diff --git a/README.md b/README.md index 72883f7..f9d97a7 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ origins and local adaptations in [Provenance and local additions](#provenance-an | CUDA | Toolkit installation, an `sm_121` GPU verification program, an exact cuBLAS GEMM diagnostic and NVIDIA container setup instructions | | Installation and recovery | Checked source inputs, a separate kernel/UKI, configuration and EFI backups, Limine hash verification and rollback tools | -The kernel recipe and P16 patches are included here. The `spark_hwmon` source, +The P16 kernel delta is included here; `scripts/build-kernel.sh` fetches the Omarchy recipe it applies to. The `spark_hwmon` source, installer and tests are fetched at an immutable commit by `scripts/prepare-spark-hwmon.sh`; `sources.json` records the upstream source pins. ACPI overrides are generated from the target machine's own firmware tables. @@ -47,7 +47,7 @@ policy, see [Update-safe P16 installation](docs/update-safe.md). | Platform / GPU | **NVIDIA RTX Spark N1X**, AArch64, GPU `10de:2e03`, CUDA compute capability **12.1** | | Firmware | BIOS **H7607BA.300**, EC **2.16** | | Base installation | Official **Omarchy ARM64 Nightly** | -| Patched kernel | Omarchy recipe **7.2.8-23** plus P16 patches, the CVE-2026-98432 fix and the i8042 key-filter gate, packaged as `linux-p16-asus-25` and producing **7.2.8-25-omarchy-p16-asus** | +| Patched kernel | Omarchy recipe **7.3-20** plus the P16 delta, packaged as `linux-p16-asus-26` and producing **7.3.0-26-omarchy-p16-asus** | | Validated NVIDIA driver | **615.78.08**, open kernel modules | The install scripts check the laptop model and BIOS. The ACPI builder checks @@ -153,16 +153,16 @@ Run as your regular user: ./scripts/build-kernel.sh ``` -The first run downloads the Linux source. Signature verification remains enabled, using an isolated GPG directory under `build/gnupg/`. Allow several tens of GB of free disk space. The build produces: +The script fetches `pkgbuilds/linux-omarchy-aarch64` at the omarchy-pkgs commit in `sources.json` into `build/kernel/`, copies the patches from `kernel/` beside it and applies `kernel/PKGBUILD.patch` with `--fuzz=0`. Then it runs `makepkg` there. Arguments go to `makepkg`, so `./scripts/build-kernel.sh --nobuild` only verifies the sources and applies the patches. The first run downloads the Linux source to `build/sources/`. Signature verification remains enabled, using an isolated GPG directory under `build/gnupg/`. Allow 60 GB of free disk space. The build produces: ```text -kernel/linux-p16-asus-25-7.2.8-25-aarch64.pkg.tar.zst -kernel/linux-p16-asus-25-headers-7.2.8-25-aarch64.pkg.tar.zst +build/kernel/linux-p16-asus-26-7.3-26-aarch64.pkg.tar.zst +build/kernel/linux-p16-asus-26-headers-7.3-26-aarch64.pkg.tar.zst ``` NVIDIA-DKMS requires the headers package. Pacman owns the installed kernel and modules; the installed headers allow DKMS builds after the source build directory has been removed. -`kernel/PKGBUILD` specifies the patch order and SHA-256/BLAKE2 checksums. Omarchy already includes the SPI-HID transport series; the remaining P16 patches add the ACPI IRQ retry, virtual GPIOs, thermal filtering and ACPI allocation fix. The combined ASUS patch already includes ARM64 WMI support, relocation to `drivers/platform/asus/` and the P16 RSOC fix. Apply it once as part of the recipe. +`kernel/PKGBUILD.patch` holds the whole P16 change to the Omarchy recipe: the package name and `pkgrel`, the release suffix, the config lines, no NVIDIA package, and the six patches with their SHA-256 and BLAKE2 checksums. Four patches are unchanged copies of [omarchy-pkgs#1958](https://github.com/omacom/omarchy-pkgs/pull/1958) at `f9a172da`: ASUS WMI on ARM64 with the P16 RSOC read and charge limit (`9100`), the MT8901 EINT-only pins (`9101`), the i8042 and fan-curve gates (`9103`) and the SPI-HID `_RST` call (`9104`). `p16-thermal.patch` keeps PSYS and PSOC out of the thermal zones, and `arm64-acpi-allocation.patch` keeps the initrd ACPI overrides inside one EFI descriptor. The scripts read the release from `build/kernel/PKGBUILD`, so they need an assembled recipe. A change to the pin or to `kernel/` takes a new `pkgrel`. ## 5. Install the kernel and system configuration @@ -219,7 +219,7 @@ python3 scripts/peripherals.py check-installed This checks file contents, not touchpad gestures or audible speaker output. -Each release is its own package, named after `pkgrel` in `kernel/PKGBUILD` (now `linux-p16-asus-25`), so earlier P16 kernels such as `linux-p16-asus-24` stay installed. Keep the old kernel and boot entry until the new kernel has booted successfully. The ACPI hook and ASUS services continue to support the older P16 kernels. +Each release is its own package, named after `pkgrel` in `kernel/PKGBUILD.patch` (now `linux-p16-asus-26`), so earlier P16 kernels such as `linux-p16-asus-24` stay installed. Keep the old kernel and boot entry until the new kernel has booted successfully. The ACPI hook and ASUS services continue to support the older P16 kernels. From the installed Omarchy system: @@ -237,15 +237,16 @@ The installer: - preserves the target machine's root/LUKS parameters and adds the validated P16 boot parameters; - installs NVIDIA DRM modesetting/fbdev configuration and blocks the conflicting legacy `nvidiafb` driver; - builds an additional unified kernel image (UKI) and verifies its kernel, ACPI tables and required modules; -- registers `linux-p16-asus-25` with Limine and verifies EFI BLAKE2b hashes; -- displays the boot menu for ten seconds while preserving the existing default entry. +- registers `linux-p16-asus-26` with Limine and verifies EFI BLAKE2b hashes; +- displays the boot menu for ten seconds while preserving the existing default entry and every existing entry. -The generated P16 UKI explicitly includes `power_wrap_drv.usb4_release=0`, -`pci=hpbussize=0x80,hpmmiosize=32M,hpmmioprefsize=32G`, -`mem_sleep_default=s2idle` and +The generated P16 UKI explicitly includes +`pci=hpbussize=0x80,hpmmiosize=32M,hpmmioprefsize=32G` and `initcall_blacklist=simpledrm_platform_driver_init`, in addition to the console -and ACPI options above. These retain USB4 resources, reserve PCI hotplug space, -select suspend-to-idle and avoid the conflicting SimpleDRM initialization. +and ACPI options above. These reserve PCI hotplug space and avoid the +conflicting SimpleDRM initialization. Omarchy's patches 1112 and 1113 keep the +USB4 resources and select suspend-to-idle by default, so the P16 UKI drops +`power_wrap_drv.usb4_release=` and `mem_sleep_default=` from the host command line. The corresponding Limine drop-ins preserve these options during later UKI rebuilds. They apply to the normal default command line; keep Omarchy's separate fallback command line for recovery. Existing `pci=` settings are replaced with @@ -268,7 +269,7 @@ sudo ./scripts/install-kernel.sh --resume /root/p16-install.XXXXXXXX Replace `XXXXXXXX` with the actual backup suffix printed when installation started. Resume validates the root-owned checkpoint, all backup files and both package checksums. It restores the original boot files before repeating installation. This also supports recovery from an interruption that prevented automatic restoration. A successfully completed installation cannot be resumed. Checkpoints created before the NVIDIA/platform or peripheral configuration additions can still be restored, but must be resumed using their original installer revision. A manually restored checkpoint can be resumed with the same package files while the boot environment still matches. -Reboot and select **`linux-p16-asus-25`** in the Limine menu. Then check: +Reboot and select **`linux-p16-asus-26`** in the Limine menu. Then check: ```bash uname -r @@ -276,7 +277,7 @@ uname -r sudo python3 scripts/verify-boot.py ``` -`uname -r` must report `7.2.8-25-omarchy-p16-asus`. Battery readings should be plausible, `nvidia-smi` should list the GPU, and the three services should have started successfully. `powerprofilesctl list` should report `nvidia_rtx_spark` and `platform_profile` as drivers. +`uname -r` must report `7.3.0-26-omarchy-p16-asus`. Battery readings should be plausible, `nvidia-smi` should list the GPU, and the three services should have started successfully. `powerprofilesctl list` should report `nvidia_rtx_spark` and `platform_profile` as drivers. ## 6. Configure a German keyboard layout @@ -303,7 +304,7 @@ powerprofilesctl set power-saver Balanced maps to ASUS Balanced, Performance to ASUS Performance, and Power Saver to ASUS Quiet. The daemon also controls the NVIDIA CPU backend. -`p16-asus-controls.service` loads the ASUS driver before power profile discovery. `p16-charge-limit.service` sets the charge limit to **80%** after battery registration. Both services are restricted to the validated ASUS P16 kernel releases (`7.2.8-14`, `7.2.8-23`, `7.2.8-24` and `7.2.8-25`). The factory fan curves remain active. +`p16-asus-controls.service` loads the ASUS driver before power profile discovery. `p16-charge-limit.service` sets the charge limit to **80%** after battery registration. Both services are restricted to the validated ASUS P16 kernel releases (`7.2.8-14`, `7.2.8-23`, `7.2.8-24`, `7.2.8-25` and `7.3.0-26`). The factory fan curves remain active. At the critical battery level, UPower powers the laptop off (`/etc/UPower/UPower.conf.d/50-p16-critical.conf`). The kernel has no hibernation, and suspend-to-idle still drains the battery, so a suspend at that level can run it flat. The installer restarts UPower and requires `GetCriticalAction` to report `PowerOff`. @@ -319,7 +320,7 @@ The monitor reads ACPI, NVIDIA, NVMe, Wi-Fi and fan interfaces. The kernel exclu ### RTX Spark power and temperature telemetry -After rebooting successfully into `7.2.8-25-omarchy-p16-asus`, install the +After rebooting successfully into `7.3.0-26-omarchy-p16-asus`, install the validated `spark_hwmon` backend. Its complete source and tests are fetched from the immutable commit in `sources.json`, version **0.3.0.rtxspark.5**: @@ -410,8 +411,8 @@ After an NVIDIA package update, ensure DKMS builds successfully for the P16 kern ```bash dkms status -sudo dkms autoinstall -k 7.2.8-25-omarchy-p16-asus -sudo depmod -a 7.2.8-25-omarchy-p16-asus +sudo dkms autoinstall -k 7.3.0-26-omarchy-p16-asus +sudo depmod -a 7.3.0-26-omarchy-p16-asus ``` Then rebuild the UKI through Omarchy's `limine-mkinitcpio` workflow and run `sudo python3 scripts/verify-boot.py` so the initramfs and root filesystem contain matching drivers. Preserve the stock kernel and its fallback entry when changing kernels. @@ -475,17 +476,17 @@ and applying calibration. The full 44-test suite passed normally and with Python assertions disabled. This did not include a fresh OS installation, an audible playback test or a physical test of the DRM candidate. -The surrounding kernel recipe and many device patches come from Omarchy and -their credited upstream authors. Our P16-specific additions and integration -include ASUS RSOC handling, the virtual-GPIO/IRQ and thermal corrections, -Limine installation/recovery, and the separately pinned `spark_hwmon` N1X +The kernel recipe and many device patches come from Omarchy and their +credited upstream authors. The ASUS WMI, MT8901 pin and SPI-HID reset patches +come from omarchy-pkgs#1958. Our P16-specific additions and integration +include the thermal correction, Limine installation/recovery, and the separately pinned `spark_hwmon` N1X backend. Original source notices are retained; see [sources.json](sources.json) and [LICENSES.md](LICENSES.md) for provenance and licenses. ## Repository layout and sources ```text -kernel/ complete Omarchy kernel recipe, configuration, signatures and P16 patches +kernel/ the P16 delta: PKGBUILD.patch and six kernel patches acpi/ ACPI builder, transformations, ACPICA source archive and MIT license config/ mkinitcpio/Limine configuration and systemd services scripts/ build, installation, keyboard, temperature and verification tools @@ -498,18 +499,13 @@ build/ local downloads and build outputs; excluded from Git - [Omarchy ARM64/N1X installation](https://github.com/omacom/omarchy-iso/blob/quattro/N1X.md) - [Nightly build and ARM64 publication](https://github.com/omacom/omarchy-iso/blob/quattro/.github/workflows/nightly-build.yml) -- [Omarchy kernel recipe](https://github.com/omacom/omarchy-pkgs/tree/9db7ac36d410aca6d571975be1a5a77677918569/pkgbuilds/linux-omarchy-aarch64) +- [Omarchy kernel recipe](https://github.com/omacom/omarchy-pkgs/tree/b4e7d40dd9aec8173dbd532479b56f585e6ebba3/pkgbuilds/linux-omarchy-aarch64) +- [ProArt P16 ASUS platform patches, omarchy-pkgs#1958](https://github.com/omacom/omarchy-pkgs/pull/1958) - [Josephine Pfeiffer's Arch Linux ARM ProArt P16 repository — ACPI, touchpad, speaker-firmware metadata and DRM candidate](https://github.com/pfeifferj/archlinuxarm-proart-p16/tree/3484cc008a9ee00b34c086c729e28e935cbc3430) (see [component provenance](#provenance-and-local-additions)) - [SPI-HID v5](https://lore.kernel.org/all/20261009-send-upstream-v5-0-384af01da3ee@chromium.org/) -The large `kernel/` file count comes from the pinned Omarchy recipe: its local -source inputs include patches, detached signatures and the ARM64 configuration. -Every bundled patch/signature is referenced by `PKGBUILD`; the three public -keys verify upstream signatures. The inherited recipe also carries patches for -other architectures. They are retained to reproduce the validated kernel base, -rather than selectively changing it for this laptop. Local kernel source trees, -packages and other build outputs are ignored by Git. Generated `.SRCINFO` -metadata is not stored; it can be recreated with `makepkg --printsrcinfo`. +`build/` holds the fetched recipe, the downloads, the kernel source tree and the packages. Git ignores it. Generated `.SRCINFO` +metadata is not stored; it can be recreated with `makepkg --printsrcinfo` in `build/kernel/`. Verify repository checksums with `sha256sum -c SHA256SUMS`. See [LICENSES.md](LICENSES.md) for licensing. diff --git a/SHA256SUMS b/SHA256SUMS index 353381f..c8c6c47 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -1,7 +1,7 @@ 54ee9ce04dec81e9fc85a4ef1fc29077019e90f9505f5fb0bdc37c49e3a6a5d8 .gitattributes e0c93ebc514dea21ed799dcfecdd647d3ce97bfbf9c8aeb220956bb4457f4006 .gitignore 20c738ce6e82e7bfcef30614c3226dbf920d9a1faabc48451571dc17eff5a329 LICENSES.md -cb8f080f6f33b7cfbb0a0666a88ee407e84a22ae0688907fe3ae04015f8e8dd8 README.md +50ec4e935bd3ae3113fa7c50e39caefd7a5b87e9d536ceb09ff447378b99dd20 README.md f904c0073e5132ca2a0640694a1236a25c64dc74c3180e8299ebb555a16ddbc9 acpi/LICENSE 14f276c97000dafdd51bc7af948d7b87aecc673df2d399ce14dbbbfb70e20c07 acpi/acpi_builder.py e66ceb26d6d514ce164fe22f5a4f7ca165cc38349d7a97f41a21f19b364647a2 acpi/acpica-unix-20260408.tar.gz @@ -15,489 +15,45 @@ d2ae26037d9d8407e12cb2432bc4c655231884c38a5fccd1cd1d7390502cdfad config/00-omar 497c10607eee04ee9a8835da1110856d2ea77fc2129c50884d1016fb7e15084d config/limine-p16-keyboard.conf 36f790b2f9a49cc52e25e4d59eb664fdacacdbaf6af33e398a4faef2450667f1 config/nvidia.conf 52eefa8921d17b19469458315c9a3957f71dc8a51e71f2ae8af3057d24988e02 config/omarchy-n1x-nvidiafb.conf -94ca70c21f4882960d737ad69694e25fd3163a509f1699a185f891214d09ace6 config/p16-acpi -0589c89034169c95f7c5702f54a2d5977d60ffefb3090cdd5435691a1d2a7198 config/p16-asus-controls.service -dc8658662c4ee66d7143ff26e4c9ecaf74637dac2edb4cb08d93b426cdf9537b config/p16-charge-limit.service +aa2c21893e77f28f09d9dfa93ed069f1b1a6ddc5c6dcc780abc80a5b4105cec7 config/p16-acpi +4c0360640792bbfce36b08758247baacb033ca686e48bdadd7f8fff6adc2ce5c config/p16-asus-controls.service +dd3fa16e6fd5cb4a9020ff617e6732d7aba0cea4cafb0ada59f59f362ea01175 config/p16-charge-limit.service 39d595392cc0f5979164aad23cbbf3058ec371dd3f16e0f796255d04f183b345 config/p16-touchpad.quirks 39ce76af7f5c039310567f335c9fcc96474491c34076f12367043090c03ab694 config/speaker-firmware.json -79bbb8acddac41113f912cb53af2fc0f4d51a753b1eca0cad6fe5f8ed5046df9 config/zz-p16-hardware-fixes.conf +3ed67c5d1b84db6ff66481659f649a00e9c78911ab8ed67626ae2e4ee81e6852 config/zz-p16-hardware-fixes.conf 1eedbb84066fe765903cd17abfce0aa3519139f66946e22490a98b64122d94bb config/zz-p16-input.conf e1ee2400583db9ea4f6fefcdff61bc6166135fd4526c3082e83f3d15daaa5b11 config/zz-p16-keyboard.conf 8e853a32441fc644a98f24747a4c100fb38e9b1d5b817bd53f835d094596b7f7 config/zz-p16-speakers.conf 4a28950812d73c4d9471b3fd9ec922114c8d97104f8174756ee33dc61a755b58 cuda/vector-add.cu -777e4bbfe44531c6504fa646ee74e95e8ff11f264a3fa281b528e25960e741ad kernel/0010-archlinux-base.patch -3e735decaaa8bb0bcb678a87d9eb8e06d18861f8d73ee042f88d1d2263c4ba0e kernel/0010-archlinux-base.patch.sig -6cf74fc3f28a751354187b6cf610c3e43cf9088b5f730b68dbb575828c3a7478 kernel/0011-kbuild-optimize-for-performance-o3.patch -a7ca00815f67be5f71a145fbb49b0f7d77317b0d43946ade1f01b686adb6b994 kernel/0011-kbuild-optimize-for-performance-o3.patch.sig -5de3a8f11e9217c9b7815f9348396e8a35f68c2d440bb4fc0746a3e1401e7ca5 kernel/0110-bore-6.8.0.patch -7b40fef2de9a017d047089f51796d609f0d12aa51cc10b55968e37753dcf5c94 kernel/0110-bore-6.8.0.patch.sig -58f21f8c48dbbb1295d488815aae50003155ec9ea5633ffbca4f0e17b18e8803 kernel/0120-tlbpull.patch -ad5711735006ad330ce686e54704baaa48f714be98f42765a0c1db71cfe5dfd6 kernel/0120-tlbpull.patch.sig -413e9994d35bc722cfe45752ab60a1bd8454443170d80987e6a5be6b7b745940 kernel/0121-smp-preempt.patch -190c811c69ad9744a76965d94b7b29d838f06db1db939af48bd4e9c6615c6c62 kernel/0121-smp-preempt.patch.sig -19cf60d05f912155ce54ad6af70b933ab63a8277785efa03695851089d87ac29 kernel/0130-sched-detach-tasks.patch -67f74877b1679c2a58528cbbd5aa4ea6915fd478408cbe52af93b2cd27dbebaa kernel/0130-sched-detach-tasks.patch.sig -d7c247f4e9f84e05b482c0294ef9053587cc50e46e29962cabcb27f97aa2277d kernel/0140-sched-always-inline.patch -da9b6c9db7c5169a838c538289a51c80313c53b26bb46e5927994ddc99f8b223 kernel/0140-sched-always-inline.patch.sig -064d5c5429b491e5b62e29cddc7b31a7cf29a4b66597428ce042a017deb2d2c4 kernel/0141-sched-urgent-fixes.patch -16fe6d7bb075a5fec04cfb50abc709f9b24635b09e16ca7e5f51f5c4b985b263 kernel/0141-sched-urgent-fixes.patch.sig -574b3e1152b16c27b281c56564044c38fc80a82a591acb41e99fbb23a658b03b kernel/0143-sched-hybrid-cluster-balancing.patch -ad3f74c82e25e28b6bbc3135acdc315637664312b830102806810d77e24cc236 kernel/0143-sched-hybrid-cluster-balancing.patch.sig -04350da18867666ef240e3a1d2d69281ad9990412154408564e2399bbc96628f kernel/0144-sched-nohz-idle-core.patch -e6b7de5cb81c24834126e0b78557065ad5253a90f50a24665c5b9bcc90a45ccf kernel/0144-sched-nohz-idle-core.patch.sig -07baad05112a47cb0aea81191502c87e496e13b4f23a6ec36ea65bb4219c35a8 kernel/0150-adios-3.2.0.patch -100cf55ea804e5ddf325a4a59dd6583d888d768cb35232de15bcc1f088eb5209 kernel/0150-adios-3.2.0.patch.sig -df870910371645a95140a3f92424db43c4e1a92bd493393e598d61c6266f1c7b kernel/0210-pm-updates.patch -a15ea95c0fe4c34ba9850e5130348a1a4d4544f7d9469b41a9b232226b11e7d3 kernel/0210-pm-updates.patch.sig -3d5550935087a7d82b527227e8f08ed98c2ffdb830b526c09e30b93137b3e607 kernel/0211-pm-fixes-1.patch -dd49af14071193e8410522514b9aae2c7ddfe30616fac8c8a9b308df3bec6abb kernel/0211-pm-fixes-1.patch.sig -2351136c78ad2dfe68e34bf9a70d377724257f6239e68bf8f501637b607af6b2 kernel/0212-pm-fixes-2.patch -d7be08b3451f83c05a290fe62dac1ff0472e945f65c033a03826fd44cf6789fe kernel/0212-pm-fixes-2.patch.sig -6c93475fc28d211ad7c15c691ea882deedeea8c0defe153cdde0a2a74488c7a0 kernel/0213-pm-fixes-3.patch -e1ffe252fa2bd6d554000e661839de53f071998c56023b81748f5054ed6aadaf kernel/0213-pm-fixes-3.patch.sig -718b40e15350049e03c0ed281b9257fca5432b8dec2e0e145e8b26507ee8892d kernel/0220-x86-amd-zen5-tlb-sizes.patch -41d8b867fc87943fca074cc8d2db739a4fbaa86ae70fa207e2023070a7d1f658 kernel/0220-x86-amd-zen5-tlb-sizes.patch.sig -b7ba949eea77e169aceb2c401d4eb83a7413aab6f15ee2a7ab1a96352f0aa12d kernel/0250-zsmalloc.patch -bfcad9d6ac59b8e9ac39f29d2bff4515234e2a2d88fe72b5891e293029e6fbc4 kernel/0250-zsmalloc.patch.sig -341424b925d506869793686e22ea8f095a34048595ebebec409c0a7bbd346ca2 kernel/0260-mglru-exec-protect.patch -d1c74a1b3b4ae43df0c3ebb0d011acc356a7e212bfc5d9957dd8035027853346 kernel/0260-mglru-exec-protect.patch.sig -7c25d0a53a115bc1f072ff0cfdd9aa88858e754ae8b15026a2582656e8bd9c43 kernel/0270-ksm-rmap-walk.patch -b7a90b78c986fe182fb45f3cb93d37c6637eb89a5d1b745b44b69d1017d14d82 kernel/0270-ksm-rmap-walk.patch.sig -336d72ab830bb33ef2a23bda1869e1fc071af64b24779281e197073ab70c851a kernel/0280-mm-updates.patch -effbb36d3e446259b9ed3d16b1538da52eb4e962faa14ec6d3be2bf20ea3583e kernel/0280-mm-updates.patch.sig -829300e576f418e64101a20d87f30f7c90798cd6e179bfb72768a83d99fa711e kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch -e8854a7e3f17c0756ae0f447cdbe9c7cfed5135cc78c5a89ee807a46bd5974fc kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch.sig -5e3b455024fab2855b590091c9d14b0d12d5363f3d4bf025b31b9aa88b65eba5 kernel/0290-zstd-bmi2-fallback-aliases.patch -fead2a422633a494bac42079fa0b46c8f795566e74fca919f96eb1d1648aa3f3 kernel/0290-zstd-bmi2-fallback-aliases.patch.sig -abd8c9326cecc9bb85db4b3dc98ddcb66306b34a6d84fb05d0805aed537e2dc4 kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch -7dc66c611e32833c20a428673f693037d62998d79f75ae4ea402b319aff4175d kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch.sig -60a9df54821cd98581e7476f8a7bb6cb0819762bdbed4d356332e41d164a8182 kernel/0292-crypto-zstd-defer-cstream-init.patch -888c1c2999f9277063d41b754eea9efaf6748942de749079fed2a281e0a28613 kernel/0292-crypto-zstd-defer-cstream-init.patch.sig -929108ae0a8eb4782cafdd89e3d4426d02d86f2c2102ed99e760e31f0bc3794a kernel/0293-crypto-zstd-defer-dstream-init.patch -8bf477dd125116179994cbf5ee8349e6d90e39b4c19d9b615c29fcd095f96ed9 kernel/0293-crypto-zstd-defer-dstream-init.patch.sig -e1226c836a9c2fb6daff109e56ba21c13fd198e109cbb181de920af04fe153e6 kernel/0295-af-alg-restrict.patch -61fdd3a9fa147f94c62cb004e1611a091a0a6da560eb3501dfaeaa89f565678f kernel/0295-af-alg-restrict.patch.sig -2cdd81f5520b935e1d99629fbd6e1cc9d1351b301396316f37946b95084f1a26 kernel/0300-btrfs.patch -0b34f8a894d71fbee7212e66be311aa4b87f6c3df9ab05b1fdf8f26bae1719d8 kernel/0300-btrfs.patch.sig -e65c2645b0d01301a91874183faed44a390b7a402d2dffd45171d210034dcc93 kernel/0301-btrfs-fixes-1.patch -6c8899a98751387b3709498ce956ef6223c8a1186a0bbf2a8cbdf15fb4bed935 kernel/0301-btrfs-fixes-1.patch.sig -d8e64b9da3beab7c33832c019da50d0977b39dc32ec1f649a7c3bc93a2fdb9a5 kernel/0302-btrfs-zstd-decompress-direct-to-page.patch -b1478f3d94b4e6198e91deb1fa872c1aa52be24692aab0468cff42af8c81e1c0 kernel/0302-btrfs-zstd-decompress-direct-to-page.patch.sig -5e2515879d58eba10c861f73318f4c4b478b8dd592680eb58961aa4065d4c3df kernel/0303-btrfs-fixes-2.patch -1a4f1533803e4b2be8a60ed553ee5af26aa900af877d7d7ac9c3a6a035e118b5 kernel/0303-btrfs-fixes-2.patch.sig -874efac3eb32970f3e06275adc072a384b89ff69e2e5b7452d6146a6e89049b0 kernel/0304-btrfs-fixes-3.patch -46a1f666177213e7cf9f65469f37b04d4c50e1417a6a014210468bb07894aa7c kernel/0304-btrfs-fixes-3.patch.sig -43aa4a11d9d48f5094b4c0e807d1d31598e861a50695bdfa52f19819b5ff5285 kernel/0310-fuse-eof-zeroing.patch -582bf8553974564993e52ca54817fe2fc02732ceb5a6f3a7e5162c35b50c2697 kernel/0310-fuse-eof-zeroing.patch.sig -2b49e4c98c5d704bee0a0e2b38051d59177161bca7b0188e6c0feb555a95fbf1 kernel/0311-fuse-perf.patch -d4c1f820378d2ff3e175fb2a5cb689183a0fbb4f4865bf5e70cee2caa9810cde kernel/0311-fuse-perf.patch.sig -e6b770d37e80509ed7ec5d8b59b4d2e5d6dba54ba659d7392de3b567f1eb6e54 kernel/0312-fuse-writethrough-uptodate.patch -99ab6f6a5eed6ca73f3ee1098bab6b2250cc6e5d97dc7434d3354265bb86329a kernel/0312-fuse-writethrough-uptodate.patch.sig -a9b3ef8aa79488d1cd813507e040e0762d4c8c5845b7f4ecc29c6cea1ade8056 kernel/0313-fuse-background-wakeup.patch -c79549638faa617b7e002f966f60184c71ebc68d3f2619a4393f182a56773b1d kernel/0313-fuse-background-wakeup.patch.sig -264d49d74eb4006c8eded08e39409045032920d76df035aebe8a1d0939d4b7b7 kernel/0320-vfs-open-consume-path-reference.patch -21dd16b05f9091fb99feeae34c8132d93a2ebf013239ab5bde0d7096b5694d3b kernel/0320-vfs-open-consume-path-reference.patch.sig -5cc215215fed4247c2d6b9732deff586331a07d54c3b00538a81921093a3a1a1 kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch -5a975a8a0f31aa76626d9b66bb5c541bd51072063fb8dbf6e61b748816cf43b7 kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch.sig -e303da14a3c8a15fd1cb45394138f03dd16e66d2ac0d1ebcd933977df937d771 kernel/0360-gpu-mem-cgroup.patch -c9b806bc2982bb96067b6d41559a1444df8de0002676357288ef427339e2d055 kernel/0360-gpu-mem-cgroup.patch.sig -1f0c958b64ba48b8dc8b5548e1ad1934b8d4903fc16fec15014759e3681ea275 kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch -fe9c82a8eccaa3698ce338d66b2dea71155e2091179d171a836a887990502617 kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch.sig -d9eb3717ba98e270b0a998f8dd90cbda072f63b6a6ea8f66763bde3ea64e591d kernel/0401-psr2-early-transport-panels.patch -ec9240fb3a265f752aabbd5880c06b2d037c3901e2f05fdcc9d15de0e5307489 kernel/0401-psr2-early-transport-panels.patch.sig -ce634014dc0131a44c3c95a8e9cb0a9de433f59d73fd99d3e3297adde65fef71 kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch -07622d3c33277df59064db2cb134e67049d0dbded8940e7fd604e3dcb13bc77e kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch.sig -d069e594d170adb016c5000d9cb7eac12c3c267a6b60c27afde7f046dba0509b kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch -5b30fc6f937d03ba869028d628f86a6323adb6d30b22edb7d5f64040174acc2c kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch.sig -78feb2e2fabccaf954fdae5b776a22cec4a3f4135fbd24f79596a5274fc0129b kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch -d9092a765c213a46d99b7087fcca900e8264cd800d03c40caf8641c913cd885f kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch.sig -f864c7daeaac0bad482bbf3853583d8a6cbbf2bf264562e397fc26355ffd5504 kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch -78d67383c43c768dac1882e129b773df4e84550f73e15b913d3bbee95dd59716 kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch.sig -c3a709af1589bd0c467565dc66ec4c01bed9c2b94314dde30c839084e594557b kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch -ab9ca0fbee3b7543124ef77a9b1b3cc361e55f28fa4f3b373b9bafe3b1e27d53 kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch.sig -1e2fddb2e0c5d184a2e8c774886cf9be2f2f292e4f05832b50e5b49c48a7bacc kernel/0411-drm-xe-display-no-stolen-framebuffers.patch -1f7733e10391a8a15d34b83ae600b6c686007e2f16beabba9d3f08b50a35cc62 kernel/0411-drm-xe-display-no-stolen-framebuffers.patch.sig -b9b8771b6a8bd7128f4344ad189e32c155abf72abd3ff646dcf5c78b08eb94c4 kernel/0420-safe-window.patch -5d9d22c0e87d801110699e832ee7e95f82c3461511e69e747d6f0f53e0da4694 kernel/0420-safe-window.patch.sig -34991cf6cec6c22bc1a55a76bc5f72b405165a2f14ef977a0446df7c18bdfbb4 kernel/0430-fbc.patch -ab43d9918acf172254e800992df9509bcf3107e725089d544cbb41b246d79fb1 kernel/0430-fbc.patch.sig -cae59282e3d1afd69f4f5dc00a180c712ef464c98b8fd7ccc9b03de944dc79b9 kernel/0440-xe3-peak-bandwidth.patch -e89fe884a8651c84d322bfd23e5de6e62ac84c738f20f30d4ecc3e5e5e328ec7 kernel/0440-xe3-peak-bandwidth.patch.sig -3b06b5285923c251b0ebaf69911875f796cf7f1d7580ec33bb218509fea313a7 kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch -9219cd52309b6a07c6147075c664ed9e9768badbe2209c3cd8e2e21d340cce17 kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch.sig -15609bef72571868fec6b8971f53b74441e5e93fbdd3c677ede963d0719cbc40 kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch -a66042b4e1eb78f0a801b0c082c77b1438d301c575728b95a8fbeabbf606088f kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch.sig -1231a6e23557936b811ce5dc184c23a7fbd268a20d582b6820c67125df8f07c0 kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch -95920fee6ec3923b970a6ddb559240082e5eec7b219cf1acbdd953b62d4befaf kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch.sig -ec12a77671afb85f8297c86fc97f8314b4f00a1630acb199af12e3550a9d4ec8 kernel/0450-amd-hdmi-vrr-allm.patch -366d8c6bead5ad696916f77ea305f38ed885c28ed6c6198881041bf0233aacc4 kernel/0450-amd-hdmi-vrr-allm.patch.sig -1b1660064a3dadf2bb3006b140d1c7016a1ad051f27e7a4d6d9f3f40d491fe9c kernel/0451-amd-vtem-tmds-links.patch -e2ad00b72f62a9454d6013a677dbf6a2d5e5fee042f514e276d2c75e8f3f9f28 kernel/0451-amd-vtem-tmds-links.patch.sig -40ac31789399a5964c4fd820d4cdc7214add91109bbcf4a614619e5d8b367441 kernel/0452-amd-hdmi-frl-default.patch -47a9bf7b7a4fe98df5b3f37ce38b76fa8f1b118505e56415e3407a2f337b3905 kernel/0452-amd-hdmi-frl-default.patch.sig -ab3b968d8bc2073e8c53478aa5d5afbadc5329a22b1486a014e5d0d84bfcf752 kernel/0453-amd-vtem-null-sink.patch -9f7f927f8ad66ec4c4ad0c35af08692429911f44a4a47bd135e5e0eb9a7ceb8d kernel/0453-amd-vtem-null-sink.patch.sig -2a2a81e647aefda80192d230cd1dbae2aeb611f66b7d6c83694b9f9f8e2befdb kernel/0454-amd-hdmi-frl-status-polling.patch -4778ae4fa84cc216cc53f91bd999e0f9b077d3fac252990cbdb6c1e4ac42d74b kernel/0454-amd-hdmi-frl-status-polling.patch.sig -2772f0733267d12f36ae2a339c9aeaf0a133a20381a6b73e0c26f2ef92996ff3 kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch -26c48606150f03d5606b7152911223172359b72d48f9fb458d99dade9bb074fa kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch.sig -3998c774884fdfc94be3da3c4c3641bd4b5aeb1878d8ef13bf0e27cd9f2e9994 kernel/0456-amd-dml-frl-compressed-cap-check.patch -79e76357944286f36a29cc645aceb0c8f8c388e3b7343664c2204f2a305bf89a kernel/0456-amd-dml-frl-compressed-cap-check.patch.sig -0d5afb79681a948a65943f557d143c15126e2497e71c5ff50ac13ed8619a67e5 kernel/0460-vesa-displayid-dsc-bpp.patch -c84a7ad7c98a9daed1c5dc7a87b6eba8a5565238cc18eeb92d1dcc7080a0afb3 kernel/0460-vesa-displayid-dsc-bpp.patch.sig -e95f8fb6d116b30c2b86d9fb51747a9f9b4e5f980c1a3b627a38940db9d0e521 kernel/0461-vesa-dsc-passthru-mode-match-fix.patch -c54c0fb6ab6f36260bfa1186cef1e21b3f3e74c63aded866d714c45ebf8c8956 kernel/0461-vesa-dsc-passthru-mode-match-fix.patch.sig -dab92dbc6eac02771c72801d94e6a53aabcf629a9cd79e85e0ce2ba44a65b06b kernel/0472-amdgpu-userq-post-reset-error.patch -aef1c58126a529e451cb180152eda3327251ec9d4f0178ed15d4b3f8cd42de5a kernel/0472-amdgpu-userq-post-reset-error.patch.sig -f55bc6366f8b9ffef744b289788a19e8604239e84c1af8b929a6922cf07d223d kernel/0474-amd-display-oled-vesa-backlight.patch -4e90fe3edec813f9379c8de9d67f62ba4cf6030d3c6fe4426e84d2b9556fe7f3 kernel/0474-amd-display-oled-vesa-backlight.patch.sig -0057dff07a3ce9c7b7085edd1f912958e01ce8f7400151d55dfb74c0c6a084e2 kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch -e76e3dd9fcf9832ff69185cfc96d534a65da5ddc9469c618555742ac0b2c62cb kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch.sig -9c4c16b9593449ce556a4d6325e5e2205cb1698f9000a967ba7df118395b1ef0 kernel/0476-amd-display-ycbcr420-only-modes.patch -22b091ebef96c94789d3511403d9c3d2b33bebb8e126610ac50e4b1633b72699 kernel/0476-amd-display-ycbcr420-only-modes.patch.sig -00afdc277c53dff0898ac86fd44ead020e007373134d7c7c333285a9f1dbf786 kernel/0477-amd-display-irq-atomic-rmw.patch -075d3d2064926d434cc41e562a2d81163a791ad0f3c2947570579dfbe2ccda37 kernel/0477-amd-display-irq-atomic-rmw.patch.sig -bed39a5e6bbb7cdac3f56a883a4684b2a63f3e8fe2f8cdcdd0b89b374b8d2a21 kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch -1f1eb9348481ca5c7049971e14a324cc34a177a84f1582ca0b689562931fbc08 kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch.sig -75d7fc371ba9b00a78af2e4b0fdb7cf79bf25a6620c983662d6b2e90cf5ce8c0 kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch -119eb6520aca62b120bf222ad792130147c65ca1ea4e830bd74b740ab22e18d4 kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch.sig -0fe32924142868879ac9417c67b0233b6ef8ddb0163183352479f5163bf7b5df kernel/0510-sound-updates.patch -965fbf8e94816ed3f074e0c392eeec630556a7bde55f7eb0858c46a3f664197e kernel/0510-sound-updates.patch.sig -7444186ad4f6d8e2b52a3729064f649b035af6eae4f4ad46b9768c006419fdbc kernel/0511-asoc-updates.patch -f40f57c8431b52db83bf2b7eb89b9e1e0a835542a167290df8d84c79a2c63663 kernel/0511-asoc-updates.patch.sig -94750a925a726ad6631d0486e7f3cb3796b3941715b188e790fa135d0aa5734d kernel/0512-sound-fixes-1.patch -47afa2ec396682fb4e617a02849d75d72e6c64d298917210439f7cc7fac87dc6 kernel/0512-sound-fixes-1.patch.sig -143193a175084d65035bcfdcc81e9dfef2e794dd56d637556db2c73b117f708f kernel/0513-asoc-fixes-1.patch -b3e07f969e15580432a99cb917a311a00a01f06dcd73e5bdf96ae585fd5f96d1 kernel/0513-asoc-fixes-1.patch.sig -f18821fa9527c7ee07a49b9c1c983a3584d5058f9734b520b5d51cb485c93f17 kernel/0514-sound-fixes-2.patch -7557dcc73a3c5f03276f3e437d61a49a30ba56fc7479ed623e7195f8cd737047 kernel/0514-sound-fixes-2.patch.sig -f7ff13ea46359217d696c6ccd49bc3d74c441ac5893d5151d95138017b0d10aa kernel/0515-xps13-sof-quirk.patch -a9ea41e94635aac733e62c62c3339d64662e58649a1b15d17492ce61a2a36cfb kernel/0515-xps13-sof-quirk.patch.sig -d17493b3579c730d27dc723447175b70d991f50253c9fd419df5e923bdf7a244 kernel/0516-rt766-stream-config-type.patch -d3c4c9dfaf9092732fed20f8df16bc876c9dd201db5ae3dc101ec116170b0865 kernel/0516-rt766-stream-config-type.patch.sig -92971bb4dbde209cf170838cfcd75d8ac9978239821d3493c28cc12623c2bb60 kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch -dc276685c943b98f97fa5e1ee881b57741e6d9df7a44ba1762f47075a7104c02 kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch.sig -7245c6e2cb5c0b0ddf800894f087770cbf8ccc6f8b3f53b9a21c704e9dfa42c2 kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch -69b2f0c3acb3d019c7611eab1ebc13edb097bae5e80d25561f3b81d72001f2c0 kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch.sig -d49629fd003900f13418c05d8c2fc37c8dea2fd8a15debb5b863008c9c46021f kernel/0522-sound-fixes-3.patch -19e9e32a011eb9fd9a08705e2a0b95e54e33508b903f55b9a4e5005011957b8d kernel/0522-sound-fixes-3.patch.sig -411fe33ab7021dcf73b02cdc80a64094a511333c52dd754e54d382fe1145de08 kernel/0523-asoc-fixes-2.patch -7f5721818a6b5ccaa495d7d7966c0b27f03c28e91266862ca8b5262a131cd30a kernel/0523-asoc-fixes-2.patch.sig -5104ee45fc11994b1cb44130811435c84fe4db532a2fa9a722c7b03dbbdc8bf1 kernel/0524-sound-fixes-4.patch -5bdb8d6277e785c8d6f981c32bf768754f3a67443543bd800ccda799bfba0819 kernel/0524-sound-fixes-4.patch.sig -f7617e3c4248e015f6f174e7c8659299d831035d0fb3c89acd1a858a202f91b9 kernel/0525-asoc-fixes-3.patch -47941d482c91f7cf4d5507bd60ddf0e924025261f10cac51ac4888eba2b80209 kernel/0525-asoc-fixes-3.patch.sig -e7dd17ccd4b417a1813c21285c738a3fdede1326d8a1445086ea1af294c3710b kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch -dd994c78ffac47449451666278afbc32df52867281cab880b08c0d4c1fa49631 kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch.sig -058aa32a18723035b18a770e1bd7f4b4f101bf5618bf0114e1874a398de42e06 kernel/0527-sound-fixes-5.patch -4da668b7e4e588fab6aabf9efc1eb5d94a0dbcbb8caf3e41404a7fc1ec700ff6 kernel/0527-sound-fixes-5.patch.sig -833c5ede23f4a014f428c64b7da550cdcd7ecc939dfeb45dce172b18417888a5 kernel/0528-asoc-fixes-4.patch -88b9db3249acf5eab3d63acda34c3af3f3d9faaef437ec2ebfe8940b05a9e882 kernel/0528-asoc-fixes-4.patch.sig -21a9196887fe8453218e4805e171b19958005f38e5d21886c58a55f8d9b86795 kernel/0541-cvs-nova-lake-acpi-id.patch -2a0d3151ba7d1e8af235dffb8d7149154183bd7b4cb962b6566a7b07749fd7b8 kernel/0541-cvs-nova-lake-acpi-id.patch.sig -29c61ec984bd342113b3c4310a3d5fddfd6d7db83847cfb26b84cc730385320a kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch -66319814411883782198ba4011b602fd8459ec88fe473f3fefe85de93017c88e kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch.sig -4b5abcc24f557e83e4d385c8304c781d6ab78fc0a3935db97e01e7d27fc617ea kernel/0543-media-laptop-cameras.patch -17bf85971ee26db82892c1087971439c9315c32d3eaf50f2c9956bb6c36978d5 kernel/0543-media-laptop-cameras.patch.sig -0dc5f0f91640715ee1744fb8cfe680de6ac1370f4df8e17d31016744f31d3638 kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch -82c1a0f61fb7be168d5111fb73075004e964fc02d7f55669dfcdb8d851e7bb58 kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch.sig -cd068c7e199f458356886eb321f759a91894bca374c71ccac242407d8b22a1f5 kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch -137effa4916e3fcf685108353746755102f324298a91c448b3070f03a36b7339 kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch.sig -618369a173be9a5a2f91fb6044931d897bbf4911586bd94a10b43a25838872a2 kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch -f7b10133bec3ad62d06233b15e3012d2de4fc8df26f28aa9608a0158a4c9476f kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch.sig -bd3535f78183d56b133986b814ec31a8c1aa933d71b3a611937e6377ee04af10 kernel/0547-int3472-imx471-vana-power-enable.patch -f96bee8435b98b8a95cb563d79c60dcd1c9b60a7f51b8e4411c1203e1affc197 kernel/0547-int3472-imx471-vana-power-enable.patch.sig -bb1e2ab62b109e434bd2c2635b5912602b8a8cc0ba24743b7bb5f691dcde2353 kernel/0548-media-cvs-sensor-node-in-bound-callback.patch -bf27739aaab9cea753f50267602e86189899b2e54510317a40cc08f7d9703dd1 kernel/0548-media-cvs-sensor-node-in-bound-callback.patch.sig -55ddb7c072f3933eef42ac48f3b32f90a5298f5cf90b4ba5b2128a197250494a kernel/0549-media-imx471-analog-gain-max-960.patch -8776888d540284db268a1f1e4f2b6d5b4f7bcfaf4808110238b610e2845bc7b2 kernel/0549-media-imx471-analog-gain-max-960.patch.sig -62e446b250e96fb65a3068bac424e1e5fe4482ad6d7ac473fa94cb8ac047c0ab kernel/0560-input-updates.patch -fdddc6aff580840a86706d34f9ad50133784dd0043b2c3ff5ab482972a6286a9 kernel/0560-input-updates.patch.sig -8b55dbedf730b0dc675793418c21b909aed5db4311248bd277d3184839d261f0 kernel/0561-input-fixes.patch -412f6575ea79d01aacf7084461d1076a692eefb2c6d12cf88322c3f0f2aa91b8 kernel/0561-input-fixes.patch.sig -5a09e7b8e10fdc61839ada49e9a33a64b240fa54847c1c0e0044518297196f0b kernel/0562-hid-fixes.patch -2a93353c997d23303e3d518767cfcc9865879e966eaec44f3b2c7492e1d5c2ed kernel/0562-hid-fixes.patch.sig -b857f4c98ff5998adab1765a06ad307f9334a8d7d9644a3de556f2b0e9cb2b4b kernel/0563-input-fixes-2.patch -c6d285a0b39e60552c7b719e54c115961ace5bb24dc992a718001965057070f7 kernel/0563-input-fixes-2.patch.sig -c28fca9ba015e96599627acf42e52737a6a846bdcbfd3d4af4147eda3109e12d kernel/0565-i2c-asue140d-touchpad-100khz.patch -d2e4b1bc8da7efb73568fe396b818c8ded9b4149db61b3b3954979dcf3bc4d6f kernel/0565-i2c-asue140d-touchpad-100khz.patch.sig -d15cdfc9b86c40a119a4f21f4fbaec72efebc67677a7386df46a61816d4c6e02 kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch -509eef16f63f027a067faf60abd184fb3b9f44e28d56ac0f1b92bc1ab8ac3f83 kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch.sig -1b070eef78ccffb3763b464f5a1b0636936f4c33b0be9b44ab116c5dcbadbebe kernel/0601-thunderbolt-updates.patch -f9c05aa2be9c655aeef3b54df33d36f30f4f429d2cc5ddf2305ebb05be61e9fc kernel/0601-thunderbolt-updates.patch.sig -eb0923de01175707151930d28b1a1a912d24bbc171248fa9f45f57a2125d077a kernel/0602-thunderbolt-fixes.patch -ce72959d09cca693d1a1addf2a376c340a039fe67202ee03bd2fb946bd43346f kernel/0602-thunderbolt-fixes.patch.sig -c076ed3752bcc2033e435043668fe007eb1ea1760597416fbb5d90bed4947bec kernel/0603-usb-updates.patch -1844e77a9971e4b04426a25b079794788ef4f903629d5b94189cd0c8a1776c5f kernel/0603-usb-updates.patch.sig -0fa9fdc6d6c85435d7b3cb38b51823f458ab273c527fcbe21b945dbd89686304 kernel/0604-xhci-fixes.patch -2587504fb8524d05f0f14ca793628ad931ea379eb39bcaff70acc13dfcc850d8 kernel/0604-xhci-fixes.patch.sig -ef66f6c32ac98a311b7437265b21a8c70746f1ea4dfbe28aff655e778d09c28b kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch -13102298f4c9fa48d1f33338b186dc154e249cec5b0cc819e13317eac58f3a56 kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch.sig -b45303b559ab8990ecb4e0281e5d529625311e795d6c3a9a52c2c27498141e18 kernel/0606-thunderbolt-fixes-2.patch -7bd91503f428e4a97bad059707cc8a0995c2794c67b5473083e7cdc2134d5624 kernel/0606-thunderbolt-fixes-2.patch.sig -1728e516153acca3c343f5184c9894fe6f1a1fbc95abe1594f544ef601db39ed kernel/0607-usb-fixes.patch -e8d5e25e85440e28053449d80a9887edc64238990d1e9bdfd01ebbb3893be940 kernel/0607-usb-fixes.patch.sig -534e68a989d36823f14a10299803f294eef39391619b4c329d78c20539d9fcd5 kernel/0620-usb-string-sanitize.patch -c8ef96b8c0826e20a374049e513c63d4dbfe7fa1d4872409dfa273c376e038ae kernel/0620-usb-string-sanitize.patch.sig -516e6ec51ca0330989128a4eb2a8f6785e5d45d930899cbbbf37b8147ddfd854 kernel/0650-wireguard-tstamp-type.patch -59388277be52be8a5259893370accd9b143565aa8b2b4bbcce31dc2d23b7acd2 kernel/0650-wireguard-tstamp-type.patch.sig -757ccc291d53030b89088802615ecf727df6f18ab2515cc0075008ebbd564e36 kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch -d444bb5a98daca624a1967c116c62dd330bc48fb75ec5f8c92569de727a773ec kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch.sig -3a271bc6b0219152047fb2b78d9e695eb791b796ea6d8233096912c77d62a5c0 kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch -8fc3d00dc4176c4bc60b4ecb1288190633275318635a0567755f1c80f19f99ec kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch.sig -fd6bf3ed3d16c788330630fdd15604836ec2a0b6a7db2b04216f756da9117bd2 kernel/0663-btintel-pcie-serialize-reset-type.patch -b399694c703f311f42356ebb5318342b5bfc163416d19a7e1aa4471630f76237 kernel/0663-btintel-pcie-serialize-reset-type.patch.sig -4d598b9e00edf7c17d915eec7c8d369fc0ea40badb7f4576cb3dedd92a685d4b kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch -405642766ee9dabc3938830c947d10b73399ff0a6ffd83b571e86be143369210 kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch.sig -98ff0d6196470c582b3e3841ef35bf82a63b57ebaef952885bd1905bcb8e627b kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch -db4cd53fdcc9040eea6145cf5733a9f31eff24f1360a13011973091e587dff9b kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch.sig -de2682af1db7f5ae8cd74da4f9020bfb7d2167f030eb15f0afb7bd46ffe49e84 kernel/0666-btintel-pcie-verify-serialize-dstate.patch -4d9598dca8c7cb773546f58a9d6d4125b033870307aa87a784c42b4a085fe783 kernel/0666-btintel-pcie-verify-serialize-dstate.patch.sig -73dc22b7f97a6cc5a5f35d6b30b9b7b12be2566160a024769550290a0e7e4029 kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch -1e40a58279640414e8f0abb580f04e34263661354b96a85086a9ebef2ed6acfb kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch.sig -f06834dfaa9e976a5778fa4fd07117a85bbff3b788c91e61d8cbc628e1b8bfb3 kernel/0668-btintel-pcie-dstate-races.patch -35819e0ffdaad449628fa61c8a9c763efeadff8b52bc25845fed7f013afa3026 kernel/0668-btintel-pcie-dstate-races.patch.sig -11884198740c5ac572cbe87086b1744ce19f0e1f856775e6edccce843ab097a3 kernel/0669-btintel-version-tlv-parse-errors.patch -3b09a341dac9f648d482cf98889380aa0d1849728bdfe9e74fdbcd5be3939cf9 kernel/0669-btintel-version-tlv-parse-errors.patch.sig -e6d848172228e98dde3a7ec679e7ea6bb0a42cca0b0105c58c8f9d6d44e33943 kernel/0670-bluetooth-fixes.patch -326a1677b5b7e84084eb4756afd35df7fc00a2b5e471aa7f920831f864bb60df kernel/0670-bluetooth-fixes.patch.sig -4e80f2d05591175d4ed0a1a144509e97260e5593472aae586c07956215d99162 kernel/0700-pci-target-speed-quirk.patch -d06e3e98854093eec6562995e12cce8fe1b05f17e2f9071a568679c8f4b1280d kernel/0700-pci-target-speed-quirk.patch.sig -1b442ad6f28c684068844ce93616690b84651e35870802b02937351bea078b4a kernel/0701-pci-amd-enhanced-atomics.patch -2e80799e1e5829f9cff56b67214ffdba9134988d9f8c37189fce54c8a547f12e kernel/0701-pci-amd-enhanced-atomics.patch.sig -9be4f91e6a4be87791d700f44c228fe599468f06a4f627b79e75718ac020db4d kernel/0702-ahci-jmb585-32bit-dma-revert.patch -14c5e4a2cd81baf1bb2ede0289f961110e14252e1e7878136fa7366f0cf64c14 kernel/0702-ahci-jmb585-32bit-dma-revert.patch.sig -ed635ed3b63cdb61614b8805aa5a9515d5b538522165be625dca89bdb7d6e801 kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch -c2acdf9b49ea4e3d0509b70ff69756eeb7a8c878ab08644afd66b93a3477fab1 kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch.sig -e28c29b9f359db85a60bfd49d2f28ba51f4d2272eb79b7d3e19ba8b3d5acdac9 kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch -728f038681a0a9ada1044e2047dde60769a02cedd3db7183246dd7b8616cd11b kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch.sig -3175c56fd2935848ce99fe10be1bc348231909f8479c3d3af911c5c7ab7f381b kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch -c5f08a4c1debdff1251ba4806780633a60631c3fe2c6b2ea9dcf366b6c3d0713 kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch.sig -30a12a616afa8fe95b969e90b42aeb240962b9fab8b8bd357ac00706abdd68c7 kernel/0711-iommu-amd-perfopt-support.patch -a6f48aac92cf814fab76ee7775603f4e451d9fef5f2cac2da4144ae60c4a3465 kernel/0711-iommu-amd-perfopt-support.patch.sig -eb0ebb8c55332dab8931c667ec84cd32c91c657d21af4504327ae05643108e1d kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch -0fa1cd683e9afaacf489ba748143db22b9caea540baf30528345b364ede4f8c9 kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch.sig -945c90d99f9a9fa47d61e471f76d17c0229ffa0fa8cda22de990a2ccc4194bb2 kernel/0740-hwmon-updates.patch -7025bf54aaba0bfaebb394b6d1373f4c12e2b76e8135ef3ec9bbbe3cfb04d516 kernel/0740-hwmon-updates.patch.sig -70ff41b2341836c27c5545a7948258f137d991c2879cbeb29f7af740c11d20e6 kernel/0741-hwmon-fixes-1.patch -0dd3de1652a3140972a373ce7ae092ea2383d7ab6f31181548f0b6c19c33cfc7 kernel/0741-hwmon-fixes-1.patch.sig -b4efd997d3f09cbf258fd0f78aca44e4c96694dc4efc5c8c9a677ea67ebf5a54 kernel/0742-hwmon-fixes-2.patch -ca38b77ebd4d448f66271522582b239facb4aafb7c4edc32a4d4c7c9371221a0 kernel/0742-hwmon-fixes-2.patch.sig -2e1e2a0eb039ce61c1612bf6c7ab5227b99df053bcd5592da7758715dd333fda kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch -1c0c31c0e0e9f747e8078a86294f8ff3d7105d55ef2604a6460ebb287e24b9b7 kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch.sig -6800dd82115ebe71d80dde0bb368fbd8563caa6c29127ffde0d6b5df81b502b0 kernel/0800-platform-updates.patch -8d815c49ba9b4c9aab5bc00253254104a6279b30d8a59cdcd7f8e00b96229398 kernel/0800-platform-updates.patch.sig -d90cc6570a47c8754e4c5d45834e0434c0a1fcabda9b8933b1fba84e3dabc083 kernel/0801-amd-pmf-util-unbind-use-after-free.patch -625645d25dbb8db7edc9e68a59cde2a1b5c0bc47e21706de19e472ffed5426ab kernel/0801-amd-pmf-util-unbind-use-after-free.patch.sig -a008c052ca657efcd4e27b8f7b819adbc9606e261aac37d41a40cf67c094cff9 kernel/0802-platform-fixes.patch -575fca2856a3f7a053dcdf1f7e772ef9052211a0e0f46e3361848d4cbc282798 kernel/0802-platform-fixes.patch.sig -57169ef893dff957cbf33f7c0dc22f2fdfcfcb3befcd62ad59e2456484423bac kernel/0803-acpi-battery-hook-api-acpi-prefix.patch -5dd4c44e0d99320dfd4a3493005d016053d12d93ca0424c11aaded0d70503b36 kernel/0803-acpi-battery-hook-api-acpi-prefix.patch.sig -01ecc1adbe715bb31153a2350ca46e1cb8a6e3fdc6899b2debeff015af2412ed kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch -1167ec38a95e763402a929e2e8fba74e87d984a2a6f8f7ac8efd92da15c5648b kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch.sig -a4331d3968fc5002534063b42bd219bddfe4a7d6b08e4cb30ed60f4366ca3c41 kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch -025262b91c6466e18aff1bbab51373cc37b92fbbc747eee91127da6b049428e1 kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch.sig -028bf538c870465e1752514725372fa9eef6b7178d9b8d1e2ecc15edc5a63cc8 kernel/0850-futex-wait-multiple.patch -a8fb7439465f4d708afcdb476ea6144519fae6bb256037cd28afa61a060d2c97 kernel/0850-futex-wait-multiple.patch.sig -a92a84405ee9845738c6b52d8f0f0eca16eb40afe0ebe0f4e9e1168597675311 kernel/0851-futex-wait-multiple-fixes.patch -fae025c651c9f531dfb4369d192052f2d513873b3ea1ef4f0f53534fcc79d8d7 kernel/0851-futex-wait-multiple-fixes.patch.sig -44a0b10a6dc83465ea86f5fba936b2bfbeffb1b3f0b2e04013bfed99ba4f6c5a kernel/0852-futex-wait-multiple-abi-fixes.patch -f5ac88866e8db220a4c5c723d2dddf0d581a5515633d7a3f8f761a7047ee0c5a kernel/0852-futex-wait-multiple-abi-fixes.patch.sig -6f01b5357af7deed3f4bccea6678b4d9e8afc83e598978f42f244241667f975d kernel/0860-module-add-module-kallsyms-on-each-addr.patch -2e3d7bfb8b56dc9d811c7ba3c737e802809b295d7f30de4805ad68af4b1a28eb kernel/0860-module-add-module-kallsyms-on-each-addr.patch.sig -0da7247035a359e2491933f9effff43ea7b29748f21a0e3080bef0018c2488e3 kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch -c5ecfa4e62ac07fda323fe4db5280aeccf78ba48b959376f9e694e1b8b38c18c kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch.sig -e0c879e7d148e23eda2ac0cdfa3260aab329f1e6c917e74687181647bfe056ff kernel/1000-n1x-mediatek-platform.patch -4fd1f0f783be1b336f92816246316372bb14f612b584b55883698b5ac6487bfa kernel/1010-n1x-ffa-ec.patch -eec36e2b086ad53b1d78c1f745c3cc833ac9e671a9dcc5cb4fa7b41b434a7b50 kernel/1011-n1x-dell-xps16-battery-status.patch -00ae8b338670e7930dae5bf021ed5ab76745df1f292539a4cd41659113ac1d1e kernel/1012-n1x-acpi-thermal-skip-power-telemetry.patch -b26351abf9c30dc2e2293d5c23c0deaf9f071c6fb5b0881f98ebbf4f30725bfd kernel/1013-n1x-dell-arm64-hotkeys.patch -f97397f95d4cdb9ed85a140b943c909f4fb2f84cd075dc06e42820854a00f06b kernel/1020-n1x-power.patch -ac4d4f5f6e552d7b783694b0b9d8a4a9c6ba7f1858d03f452619bec987ff359a kernel/1021-ACPI-processor_idle-let-LPI-states-freeze-the-tick-in-suspend-to-idle.patch -9787a31255d5b31fa3f8ae79b9825a660944b43b83588484d50d7eb9ada1faca kernel/1023-ACPI-processor_idle-let-suspend-to-idle-reach-the-NVIDIA-N1x-DRIPS-state.patch -fc8a5798be57d0b0514601fae8a592a3f9db0e44ee04eeb730142d6c1f256ab7 kernel/1024-PCI-quirks-let-the-NVIDIA-N1x-NVMe-link-reach-L1.2-so-the-SoC-can-sleep.patch -025a71916a65683a7fe672eee2fa73bd05859e9d4f0e926e1e8678ecc8e6ef7d kernel/1030-n1x-audio.patch -45f6ae0ea53e4edb40a61a49100413bd8e66a814fb95e8d1175938d76a12b4fc kernel/1031-ALSA-hda-acpi-add-runtime-PM-suspend-resume-to-the-ACPI-controller.patch -ea4526ff83f659e55b0ad0b4aaac1e8402a8a645ed82fc697b80d36565586749 kernel/1032-ASoC-cs35l56-Wait-for-firmware-timer-expiry-before-system-suspend.patch -0251766c52add0dfb792616dd93244aa242f406dd7ff8b20eec043b3fe50fa47 kernel/1034-soundwire-mediatek-close-the-interrupt-gate-before-quiescing-a-link.patch -937ea870466d793eee9844a90949864d726356a0bfba0f4ee8fb2baede0142c9 kernel/1040-n1x-gpu-iommu.patch -763c138559d7f1c831a6ea6b28a3ba3c889c58662899bcc3570d49ffc4eba31d kernel/1060-ASoC-mediatek-mt8901-give-the-card-the-ACPI-subsystem-ID.patch -aef7e8c83a90102e041b1423436c98cf685ddb85b258c3a05e7cd7581c37ffe5 kernel/1070-Revert-NVIDIA-SAUCE-usb-typec-ucsi-acpi-disable-USB4-via-vendor-_DSM-at-probe.patch -e1305e8153910700cd649d9c0ff6d9376c7f169f1254341e1bc2b82c722d1c69 kernel/1071-usb-typec-ucsi-acpi-query-the-_DSM-functions-before-using-them.patch -72ae95ec18284732f8790d29c1cf2802523b745be1d2953e3878e5ce10a4cc92 kernel/1072-soc-mediatek-power_wrap-make-the-USB4-resource-release-optional.patch -0cbab0c874dbc2acf0310cae24e5a16f2853d86218a688e29beb7394e10a61a3 kernel/1073-thunderbolt-check-for-a-PCI-NHI-before-treating-it-as-one.patch -1c259aed7ba4004fa323ac94c9f4e8af8eb833f59f4dd8c9dabd6080fbb3bb31 kernel/1074-thunderbolt-nhi-let-a-single-wired-interrupt-service-the-rings.patch -71dde7e7a457e4f5e9fa1e7b1ee6aebc97eea8e0bc05a2c05ad1befe572615b7 kernel/1075-thunderbolt-nhi-share-teardown-and-export-the-NHI-core.patch -2571bef8e0bdbfa3799e0684a4a0f72e16cbf8766777c3cd91f69983907db950 kernel/1076-soc-mediatek-power_wrap-report-whether-the-USB4-resources-are-released.patch -9ee5070e04dc2ca3a0183c0f4264a9d7585757e1c3f95d37f3ba91d6fe083529 kernel/1077-thunderbolt-add-a-driver-for-USB4-host-interfaces-described-by-ACPI.patch -c87ba519bb7df6714b49a848cc31caca6f91a3fa32805f947ef4cfc91f67f4ef kernel/1078-PCI-Keep-hotplug-bridges-below-a-switch-to-their-share-of-bus-numbers.patch -2857a276701029d46cd849ed6af9799714a2f704f20e0cdf9a53086085ff8c4d kernel/1079-thunderbolt-quirks-disable-CL-states-on-the-NVIDIA-N1x-host-router.patch -85d6b1ecfdf7403f4499e6e79949e57e9b0ee1b013fabfb7fc5f85b80ac5d495 kernel/1080-thunderbolt-keep-the-NVIDIA-N1x-routers-awake-in-system-sleep.patch -a35febcac94e24698b65d623ca937125b989537a9886dc2f616c9d035add4025 kernel/1081-thunderbolt-platform-leave-the-N1x-host-routers-powered.patch -5c24923ed9e4d16116e8067cbbd0b0074b62eeb120a86162052a165927c11732 kernel/1082-thunderbolt-retry-the-NVIDIA-N1x-DP-IN-adapters-after-a-DPRX-failure.patch -44d34d84852429497e146d5f8f19b576a5c36c8b9a9f3e7f45792f51fd7b4e6f kernel/1083-usb-typec-ucsi-retry-init-when-the-PPM-answers-early-commands-incorrectly.patch -63c3741a283dcd762de5bc975b8e97aa236328de68e8fd6623bf6d7fd125c3a2 kernel/1084-usb-typec-ucsi-allow-retries-of-ucsi_resume_work.patch -1de7b523ca7fea0dcd4a4bbd5b7afd2824880ad74748e0ea83b7a83f6c74a45d kernel/1085-thunderbolt-keep-the-tunnels-of-routers-kept-awake-in-system-sleep.patch -8117c9060df26fc93f75c77fb8adee80697b396fd485e40461276756c205e54c kernel/1086-thunderbolt-space-out-the-NVIDIA-N1x-DP-tunnel-teardowns.patch -bab1a8ba58e2407fc2fd423a64c4ba95d30f6a3fa887af32471185505de58e0e kernel/1087-PCI-ACPI-Mark-USB4-tunneled-devices-removable-on-every-ACPI-platform.patch -74ed8863892903452fe5117b7672d8fe32fcef3054386b472a435d4b0eef1b00 kernel/1088-iommu-Give-external-facing-ports-the-domain-of-untrusted-devices.patch -3e8bbf257870b8f6d376e984a22ec819a1c1e67de47b61d0ba35ed28b039e516 kernel/1089-thunderbolt-platform-report-IOMMU-DMA-protection-for-the-NVIDIA-N1x.patch -8bd7382591d136f35fee515fd634767ffa8b2ec1bb28e945fdd01fac0cc1469c kernel/1090-sspm_ci-distinguish-not-submitted-from-completion-unknown.patch -62f996f0d8a1723ce5aa2c73e09888ece981e6b46b4f37842022110067b712ba kernel/1091-PCI-harden-MediaTek-Power-Wrap-system-sleep.patch -01b9987523cb65f53481052f3160bc595bbbb55713df3094f00a851e71bf1182 kernel/1092-usb-xhci-mtk-v2-add-ACPI-power-management-support.patch -b4322ff5da350c62a870627f9f001e0a4d26757b96a4634785f3b302bb11bab8 kernel/1093-usb-xhci-add-XHCI_DELAY_BEFORE_CRS-quirk-for-MediaTek-v2.patch -fa13ddb55a1a230c185ce3f4fe3c378436bcb32d3d8e1acd10442be900f8ffb7 kernel/1094-spi-mt65xx-enable-ACPI-and-power-management.patch -c27c35588d0aafee4e5721487daf7ce58624d5be42bb53a94a9604084b1d2f83 kernel/1095-i2c-mt65xx-enable-suspend-and-resume.patch -4a9f091bfdcff9c0e280885db9b4f88a75626c391001c108f86b90e457a3097d kernel/1096-pinctrl-mt8901-sync-wake-EINT-event-mask.patch -c365369fcf8a5fb3d3d7cc501ee317dab093ded82e63a1bbe76cddee8048ebef kernel/1097-usb-xhci-plat-use-firmware-managed-USB-without-SSPM.patch -712dac6fb7af23aecadb01b2ca851a64fd88e0173fd5c992913a85bf9a4d222a kernel/1098-soc-mediatek-gate-SSPM-dependent-ACPI-paths.patch -1267ec5f1ded5fdeda1f996582b4b1f60cdfec84f5364a7f8d8e9ba1250bf363 kernel/1099-soc-mediatek-power_wrap-keep-DGX-Spark-DVFSRC-policy.patch -16cbaf601ead8539374ba4b756c5927e457f7f5e55ff1ad0b446cb8d0d2ec861 kernel/1100-HID-asus-support-the-Zenbook-A16-UX3607OA-keyboard.patch -a4475812319b7aecd6ea49216d7d45b70d76cd0a53b0838c933d73e9a625bfc0 kernel/1101-HID-asus-drive-the-0B05-4B42-keyboard-backlight-without-asus-wmi.patch -9b5940534409ec08d285fbb749c7f6ba1649825f346e7ab2a1f975b5dfbcf310 kernel/1102-HID-asus-host-controlled-Fn-lock-for-the-0B05-4B42-keyboard.patch -c7b388262ae9f8f9ec2e4f3366eb2d0cbd4d1e93f0bb563b7d3df3a17fd16e74 kernel/1103-HID-asus-disable-OOBE-mode-on-the-ProArt-P14-keyboard-too.patch -2efbd3f5d196c31c85a3733707a89cd54f8579756e30f3a16b8ac45ed76b32a6 kernel/1104-HID-asus-turn-the-keyboard-backlight-off-for-sleep-without-asus-wmi.patch -30b45a34e029aee8cd57123300a83ab1dfe473cb6c88d87ad1b3cccd891e0648 kernel/1110-tools-linux-types.h-Add-128-bit-integer-types-for-arm64-UAPI-structures.patch -61260d5828b8d5009df572d5efe50ae359879fb0fbb1bc42d9145dc1947fc8dd kernel/2000-media-iris-reset-AHB-bridge-before-enabling-HW-mode.patch -2c2eeccb8ac53d8626494fc4a5f47ab4b7271f68c5318a67fc5f5cd130763671 kernel/2001-ASoC-qcom-q6apm-lpass-dais-Reset-the-codec-DMA-channel-map-in-hw_params.patch -9f08ec0bb897a496283e8f82a9478bdf42189b739094613ddc0a378b68a12dc7 kernel/2002-power-supply-qcom_battmgr-Notify-charger-supplies-of-online-changes.patch -6fcc3b801f72f15bb9e299c1dd6e876348777e01cc9e55c3a504264109f09c50 kernel/2003-wifi-ath12k-don-t-count-a-vdev-restart-as-a-started-.patch -6df3f94e9ea59f3c2e10de77225880113c4b1808e0b3e6736346c47778be985e kernel/2004-media-iris-Fix-out-of-bounds-read-in-timestamp-metad.patch -0aa39c07310466f74fd8ac48a1d2abef2dddb07f0d9211f5b801f905c919f0de kernel/2005-Revert-media-qcom-iris-use-disable_irq-during-power-.patch -fe384e8722f5f8702186e4629c585fde64ff61085234d87787c32b4572ac13bf kernel/2006-media-qcom-iris-Wait-for-threaded-IRQ-completion-dur.patch -762ad0060990fc4efee26138a0a02b507b7fdbb0cfe02d0860cf60709db7cfa2 kernel/2100-irqchip-qcom-pdc-Restructure-version-support.patch -6ba3e86204628fb925cdde1c53b97c02b93c790c41eb57eead7de53074295a38 kernel/2101-irqchip-qcom-pdc-Move-all-static-variables-to-struct.patch -8f8eed910185f263e395388fea964ea53ed7992d5e09ea0598274d9c5f43ab7e kernel/2102-irqchip-qcom-pdc-Differentiate-between-direct-SPI-an.patch -13719af91befcba7b4fb0b276f0c34b4dcca1502e01656870c9a475e79a23e4d kernel/2103-irqchip-qcom-pdc-Configure-PDC-to-pass-through-mode.patch -1cccdfd000a6a460b9cd11988e8080ca8ce579862b0d7be25b5ef50e7da95fb6 kernel/2104-irqchip-qcom-pdc-Fix-kernel-doc-for-qcom_pdc_gic_sec.patch -48b101685fcf59783ebaee21cb9f1abd04740a88eff224220676b4dfb1ddb161 kernel/2105-arm64-dts-qcom-x1e80100-Reduce-OS-PDC-DRV-span-to-0x.patch -cc0c4a111483906b780c3d886f52954a7ffbfde26ef758eda9ec38355ee72145 kernel/2106-pinctrl-qcom-Acknowledge-IRQs-for-PDC-interrupt-cont.patch -31d9251885f2fb2946ab69400700c6ba41078d47161ddb8ecab5aef308ff250d kernel/2107-Revert-pinctrl-qcom-x1e80100-Bypass-PDC-wakeup-paren.patch -7f420c1ffe57b59204f0e3e05fabd07a7991235cd76406544e53d15a453e2569 kernel/2108-arm64-dts-qcom-x1e80100-Add-deepest-idle-state.patch -5e1621ce1e260bcda757aaeb8ff706ca474d444aedb35e80be26d393047375a1 kernel/2110-Documentation-Correction-in-HID-output_report-callba.patch -b8731b4c1b9517039b31133e905c7c856bf046b2357c0497859836959d4fe5f0 kernel/2111-HID-Add-BUS_SPI-support-and-define-HID_SPI_DEVICE-ma.patch -a26e5a13d093e91969b98b5f969c635e6bd3118c847ede42ec0f83dbdbf043a6 kernel/2112-HID-spi-hid-add-transport-driver-skeleton-for-HID-ov.patch -a5664d88d81da2aae289a4a0287f22ef4eeb71270614edbee2573fea11fcb0d8 kernel/2113-HID-spi-hid-add-spi-hid-driver-HID-layer.patch -7464f35463265edfef4106767ae906b440b1dc217869ecb64e2f2ab6bfee19db kernel/2114-HID-spi-hid-add-HID-SPI-protocol-implementation.patch -d09050a74e20ef20730febde750491b646210a5fa95254cd6dc6b1115a36846e kernel/2115-HID-spi_hid-add-spi_hid-traces.patch -81cdaf4977af84abebe9e5ed57b7e632ded834620a0c953d9df691297540e66c kernel/2116-HID-spi_hid-add-ACPI-support-for-SPI-over-HID.patch -d8e3f549e0a5705ef3877f91d7bb8b3b727f9d8d4806c955be988f7d2fe9d0db kernel/2117-HID-spi_hid-add-device-tree-support-for-SPI-over-HID.patch -a20ad7745aa84a6c90a88e639b4d697664111b363f7dbb8599d16e3c5377ce5b kernel/2118-dt-bindings-input-Document-hid-over-spi-DT-schema.patch -4c56326fa72421bec2232cb86081a9857d1f5cc37f98ba790bdbbbce563f134e kernel/2119-HID-spi-hid-add-power-management-implementation.patch -bdc0203ae6ecce9c71ef8a6ce710ea4bd214e1d51b8ea97df4e79925ddc3cfcc kernel/2120-HID-spi-hid-add-panel-follower-support.patch -9ea51488527672913fefc5b8a0255574e21950df92eda7e1c536cfdd2686268a kernel/2121-dt-bindings-media-qcom-x1e80100-camss-correct-resour.patch -f56b3be5ef56339f140ecb3a7e507a2dd64ff1205f83a9a686fd9959566b1b6a kernel/2122-dt-bindings-media-add-OV13858-and-VD55G0-sensors.patch -6b7998284b6b04234837e475a59f9ef42a28665fa5a12f05c165ac24557bd5e0 kernel/2123-media-qcom-camss-unwind-failed-stream-starts.patch -4f2a5e6d4e46fc62a6cfd7bde5af878d2dca64c32ffc7e3dd6ad4d94e37aec3b kernel/2124-media-qcom-camss-support-X1E80100-C-PHY-links.patch -de441b1e44682ef8e73d4b1d44096c4ebae241a47219422d2b679af679c2ee4c kernel/2125-Documentation-media-record-Surface-Pro-11-camera-pro.patch -1af553dccb286f4cfb6c10b83d9dd70297afaa264450e4b5f9fd4d8649737242 kernel/2126-wifi-ath12k-Add-support-for-disabling-rfkill-via-dev.patch -cc36e89df67fa385e592deb669bfcd9ecb4583a994834341429ae5526c7ee1dd kernel/2127-arm64-dts-qcom-denali-preserve-ath12k-rfkill-quirk.patch -1ae6e571ea8d34fe62e03a3037f4e25aeca10d0ff1f0e8f0afd6899ab284123c kernel/2128-dt-bindings-net-qcom-ath12k-document-disable-rfkill.patch -02392ca073bd502086fb64b6945d956b1a37aedcd852078ae6e34aa5102dd6f6 kernel/2129-media-qcom-camss-restore-observed-Denali-C-PHY-seque.patch -aa35f4819fc30e52a6e8f84994225f62357d773dfa3390aebdbbbd7011abcf38 kernel/2130-platform-surface-recheck-tablet-mode-after-resume.patch -7d4472524d43e5f6d2431dc04d4dc76f7d8103aa2a72c0b63f640eaf7a8a63b5 kernel/2131-platform-surface-resync-tablet-mode-on-KIP-connectio.patch -f55ce58adf469c617a5c2efb430ec7c66bff74de67788bf60f41572baef616a3 kernel/2132-platform-surface-retry-KIP-cover-state-while-settlin.patch -1928fdbeb36fb505484048c7bfa8341c024aeceb6c301ca3e3fc68f0b903d97b kernel/2133-power-supply-qcom_battmgr-preserve-charge-limits.patch -3fffbc51b79da923225f8a02d46372d11a1b7e596b52a8b552e79f211116415f kernel/2134-media-ov13858-retry-the-first-SCCB-write-after-power.patch -56bd013677b94ed927d8e7b595a3d2867c70cedf05d15a68c3535f9ebe54b6e6 kernel/2135-drm-msm-dp-restrict-the-EDID-read-workaround-to-EDID.patch -0bab82f32e7e1d4a4bb778f2d64639c5b2f3f0b3eeec29e331bd6f5225f2488f kernel/2136-drm-msm-dp-attach-the-AUX-i2c-adapter-to-the-connect.patch -8614832330fa120d61213bbaa103bca30156e6be381eeab69c0b31573011c553 kernel/2137-irqchip-qcom-pdc-report-the-selected-X1E-mode.patch -7ac960efaf67e64849baecab09a3c8681d05b5ac5553828c8833f8323d7c85aa kernel/2138-soc-qcom-smp2p-reset-inbound-state-only-on-restart.patch -1b28581ff79a0b94d344f356f2282da3b110a337bfbeae8ad0f768f3484d11de kernel/2139-arm64-dts-qcom-x1e80100-drop-QCE-sleep-bandwidth-vot.patch -616b4c3e1d5ca8525a461b33ab791c1b348130066d6ca35bdfafdfee1f7cd182 kernel/2140-platform-surface-aggregator_registry-add-KIP-OOB-pai.patch -3c2bec044825202e6fb70501c3d75aad5957344ff54e25151ac2bbb0b712d09d kernel/2141-Bluetooth-SMP-implement-LE-legacy-out-of-band-pairin.patch -842b67c9fcaf0fbc3f4f01a3a214ca976fe4f74010555812d7b0c6a2322d2ae7 kernel/2142-drm-msm-dpu-re-program-colour-processing-blocks-on-t.patch -401c366a2e4b4c075930b1aa05c4c1554d61cf16695011937d48f250880083c9 kernel/2143-HID-surface-hid-suspend-HID-clients-on-shutdown.patch -fb93691adec100e3a7d40941bf70388f61cd407183ed9b1d467606f7cee6d4ff kernel/2144-arm64-skip-the-EFI-reset-path-when-restarting-from-a.patch -7c76502536af653bdb9a05a35621b05a7c574be45dc5b2f532083b625a94915b kernel/2145-drm-msm-dpu-Reassert-core-clock-rate-on-runtime-resu.patch -ad4f8bbdbcffe0f6f93f6997c9a6c0b786c45499441382922418ae1e9c5dd293 kernel/2146-drm-msm-dp-use-direct-SDP-flush-for-PSR.patch -7fa05715a6251357284fa1906a98439cb6870aa11284952942d867f3f9b5bc34 kernel/2147-ASoC-qcom-x1e80100-raise-the-speaker-volume-ceiling-.patch -f9bec1e20b2ca6652dc7084e658bd7eb01e1e3a0b505537dd872d47b3bde4e16 kernel/2148-Bluetooth-hci_qca-Drop-unused-event-during-BT-on.patch -44f360cfb56db8c17b3d8b9c7b73f7abdb736f97b854c3099049d5802fd2087c kernel/2149-Bluetooth-SCO-accept-incoming-eSCO-with-Enhanced-Acc.patch -42b67f86491c6a4fa32a5d8eab96e0754ec992caea253c82de5a87e7fd177e7a kernel/2150-wifi-ath12k-avoid-sleeping-PCI-wakeup-during-panic-r.patch -02db6d8198c97f6ec4ed4a7e960fa23fc563fcfad0c63f735a6a8cfe254edc89 kernel/2151-arm64-dts-qcom-hamoa-Drop-cluster_cl5-idle-state-fro.patch -3102665d9e8276f8a9089bbb09efcab5a3e61a06907d55d11911f4a23a63fd2a kernel/2152-arm64-qcom-add-Surface-Pro-11-platform-support.patch -f23cbb753cee7c3d7289bd6018b3d5c5b1317ad5bb30118a4dea55077017cb1b kernel/2153-HID-spi-fix-G6-touch-digitizer-module-alias.patch -9bcf9b22f6968b5f36094e333761e18edc8141d273bc3c3c914ad336697cade6 kernel/2154-ASoC-wsa884x-recover-PA-faults-and-apply-SP11-2S-4-o.patch -988c4416223fde4d45738f5dcefad3b67545ea2de96ca4415f575e6d0f692254 kernel/2155-Bluetooth-hci_qca-keep-the-WCN6750-baudrate-event-dr.patch -6113d32fb448f09e3618789e6ed24ea7fd2faf597664bdf4c508c473c43f8c34 kernel/2156-drm-msm-dpu-disable-the-clocks-if-the-core-rate-rest.patch -720017482aa39321f1146daf8a2fe103e3b211b40cc0f05bea4826f40c42e112 kernel/2160-arm64-dts-qcom-x1e80100-Add-CAMCC-block-definition.patch -344c8c26038208bf75fbdfe208bcacf6a0dec216c89c5c7430d58ce2fcd85b65 kernel/2161-arm64-dts-qcom-hamoa-add-camera-subsystem-nodes.patch -7224ffe0714892ff645ffa69060dd1fa1dd604906c7d01da8a5551eb21b5b161 kernel/2162-media-i2c-add-Surface-Pro-11-camera-sensors.patch -c9a615bd90f44b65febbe1b214897d9a55bd612ff77016a65730e9a8d8000d09 kernel/2163-arm64-dts-qcom-enable-Surface-Pro-11-cameras.patch -16df73790288ccf63be5c3d3e776e7e0cbb518823fadd4dd3a1d649b99f0d27a kernel/2164-arm64-dts-qcom-denali-enable-verified-IR-illuminator.patch -995cc1dc0829f5abb61f670db8ff0193d104d0299e9538b9cda587b25b5309a5 kernel/2165-media-imx681-write-exposure-through-the-24-bit-latch.patch -c55f25ceb88488f7c3e4b0bbc986bd752095aa5c6919b6c685a1e79aa679366e kernel/2166-media-imx681-expose-analogue-gain-as-a-linear-value.patch -d381bee00bef449b1fc4553c318f15d4fbcfd068ed5c03ab4238b76d3f87cf70 kernel/2167-media-i2c-vd55g0-power-the-sensor-off-only-once-when.patch -aee3b02e6d24606dc82c89282630532147de75c3253278d8aff89ea54a4e5250 kernel/2168-media-i2c-vd55g0-register-as-a-sensor-subdevice.patch -e2ffeb741a169c226663acda8f9e119f1660d924847f06a87cba41bb12f107dc kernel/2169-arm64-dts-qcom-x1-microsoft-denali-describe-the-came.patch -5eeb64bd6546a280a30388a58c7ec71cc7c25cc338519d011bdbfca8d49d7666 kernel/2170-drm-msm-adreno-a6xx-Mark-cxpd-device_link-as-statele.patch -396401cd7d1dbf781fcb8ce7ed5374e03826bbbdde188542cb385211d76ead95 kernel/2171-drm-msm-Centralize-the-standalone-drm-device-check-f.patch -fbe4af873797bfea0efd9987a8a744cadd32c25bd12a59d080f784edefa62908 kernel/2172-drm-msm-adreno-Fix-invalid-drvdata-typecast-in-adren.patch -a56a08cfc3c2a82f9a0c408fa680aea69a463fa7674e2f12dfb9857a65e2312e kernel/2173-drm-msm-Always-use-component-model-for-standalone-GP.patch -822fc723fff0318ccd6a8094eb9bfcea6c6d4e279abfb885c15f9183c9ab40af kernel/2174-drm-msm-Attach-a-driver-to-the-GMU.patch -a4079b8965fdebdf99e2e9f62e97f6c749bcfde2abbc6d6f4e46ad94e7a6c7b9 kernel/2175-serial-qcom-geni-add-force-suspend-resume-to-system-.patch -3e1f3526e989c0d9f26f3ed81229675b1aa419be21b99584d65c595cadb3fb90 kernel/2176-soc-qcom-add-ADSP-power-limits-Modern-Standby-notifi.patch -9784af3d74269b567d1a2bb7455052b2a4ed969f9be370b0fd13ab5c34d1ad98 kernel/2177-PCI-allow-D3-for-hotplug-capable-root-ports-on-Qualc.patch -498fb0728b5e78446f0f7aa4a0fd5546df7b6a7e979eb97111a6314213019071 kernel/2178-drm-msm-keep-the-GMU-optional-and-its-lock-initialis.patch -89770095e3a2c651e52fa7fe997032c0447924b015ca636462f12dcb8ea62ce0 kernel/2179-soc-qcom-adsp-pwr-lmts-drop-an-unused-include-and-sa.patch -f23b59aec9288b499bf17b19e29a29d7307841ac31e07e7acc8748736061d06a kernel/2200-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-pm8010-camera-PMIC.patch -9ca3d621fb4da0712bc8835845ced553c46c43c47e31830c52bd0c3da4a2131b kernel/2201-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-l7b_2p8-regulator.patch -885894a3f007a6f265371e4464da3c40b41fe67ed971a8b8281feaced9ed16b2 kernel/2202-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-ov02c10-RGB-sensor.patch -fbe7f557b091b151c9f91eb1de437068fab0901608081216d8a7c687e8101ea9 kernel/2203-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-enable-camera-privacy-indicator.patch -bd77fa17f6c05b4d09a722529d08de90e7348522906eec8146ee225083c778c5 kernel/2207-arm64-dts-qcom-hamoa-Power-the-display-GDSC-while-the-camera-runs.patch -b3b19a3205ce8e981a0e92921ff5316f51fe329f81951c700d7ac3416e63790f kernel/2208-i2c-qcom-cci-Reset-the-controller-when-it-resumes.patch -5eb763f45fdef2428571d4a8988522e350c71158ef83b2f1a76d3dba9798d677 kernel/2209-i2c-qcom-cci-Suspend-the-controller-50-ms-after-the-last-transfer.patch -f81f6b5769e47716ca318ecf76ab1c0fafa0e165fa858a64251359937bffcf04 kernel/8204-mm-opportunistic-compaction.patch -a1500260be5814af10cb9aeecc97d7b12e303683ce302f9fc2971eb68907974c kernel/8204-mm-opportunistic-compaction.patch.sig -c67fee35a42866dd3c9056ff099fc504cdad9530c107d959331b5572b21af818 kernel/8205-mm-hint-uses-allocation-order.patch -6a5b1bc7b925b10a2bd0fadc02dadd83df253cd372baa29daa1e8ee2dd2365ac kernel/8205-mm-hint-uses-allocation-order.patch.sig -fdfe62019e6ef5dfba2fabecc6ee5b58400f41ef000883fed135ecaca881b40c kernel/8206-mm-carry-order-and-hint-in-one-word.patch -256e81a3b52f7c71f57ca419370f7d356daef6348206222e525512d403361bc7 kernel/8206-mm-carry-order-and-hint-in-one-word.patch.sig -07683e522d6dea3d3ce658ee80bf4317f6c3caf248259da960bc4610f4d1e807 kernel/8207-mm-classify-huge-page-allocations-as-failable.patch -9ea9e1d2577862dd2d8644ab88c66e94104d13c63f851a79985d30ed471d463c kernel/8207-mm-classify-huge-page-allocations-as-failable.patch.sig -c5279468d93e562f509a6b599a2b7ca7ee0032d3fe35314c5769fc6c9a9234ab kernel/8209-xe-shrinker-use-opportunistic-hint.patch -f4574bbc5d04d7ca6b127c034062614d1e53411734563a4a94ee7a37612edaaf kernel/8209-xe-shrinker-use-opportunistic-hint.patch.sig -c0111614ec44014cbf621eedf5a4ef302a855423bc1633ee692392950e971d0e kernel/8210-xe-shrinker-single-backup-decision.patch -637ccea824389fea561d28b09e9f35e794b0be921e7909b5ae85732eabb2aad5 kernel/8210-xe-shrinker-single-backup-decision.patch.sig -c2f916fa04d91edf926abf8fed086302fe538ba62d92450af0ddb6d3a33942f1 kernel/8211-xe-shrinker-skip-active-vm.patch -44951daa32d97ba6c3d75d516dd79f894f7cb1600865d11f12210e631878cf3d kernel/8211-xe-shrinker-skip-active-vm.patch.sig -d17774053ab07de92e18abdb0ff4d00352a02b6a97c48e28d8c875954c8eec36 kernel/8212-xe-shrinker-backup-in-kswapd-only.patch -8640c3482ebfc8a2c748f083afeb27fbf86a8462ae74d4fd912e99e945f72c45 kernel/8212-xe-shrinker-backup-in-kswapd-only.patch.sig -774f337663b215c5aa8877c06ffce95be44403fe77516c1be9ef9789e2d049e5 kernel/8213-xe-hibernation-writeback-gated.patch -9518cc394fae39e2a4c1585c300d9834c5068b8da310a0168f05bc884de16309 kernel/8213-xe-hibernation-writeback-gated.patch.sig -a99e453722576f0177f1a1fbc442b6d4af469c1cabf8657b0cdb71679aec0474 kernel/PKGBUILD +8f3ac86f72c45ca2c2562a98e1245e3f93312a6f7289f77a6d2ce6c8abfb8bc5 kernel/9100-asus-arm64-wmi-p16.patch +a8ac0e0f2fc9d1ac5b3e2caeece5184c5e98b07bfcd95216ed9810f85cc6c5dd kernel/9101-p16-virtual-gpio.patch +d94601de46ec01ba29e6235437e7e82db70a4b1cb452d283947f85b0ba777148 kernel/9103-asus-capability-aware-initialization.patch +e2aa06245ad48313149893fd62d5dfe10dfa33d08c4f8dcb63d7560d873009bd kernel/9104-spi-hid-acpi-reset-handle.patch +276c54626303e3184ece97441f1d9f6f6433ba5ea9c97a19c51d879861eddb8e kernel/PKGBUILD.patch 0ababbaed19c7108e8564916fac1b8fecc44010e7f3e4b419c34d01c66049e19 kernel/arm64-acpi-allocation.patch -2d3e0c20fc1e451e3d127462e59540fc74dce829f5244060e07c24e36027612e kernel/asus-arm64-combined.patch -509f5e01b9fdf64ee35f24c95e6ba11985c9ea875147a38549f9f8adf4792e6f kernel/config.aarch64 -3f6a2afd7b321d618a06e18b6fc0bd6c911d5b40547d22b6fa109c0077dfc5ff kernel/ipv4-free-inet_opt-ireq_opt-after-rcu.patch -1270204cc36d09cf851876d0dca7b249af0d03e3b620a8757bf1f3391974e636 kernel/keys/pgp/12D27D5D8C8E9BF1AABC7C7C7C64768D3DE334E7.asc -369874fe967723f7ee31a72014900e42b37f7f9c307391d254467aaf6ca9d85c kernel/keys/pgp/647F28654894E3BD457199BE38DBBDC86092693E.asc -9ec2257fa084e6e676e876e0c16b5e6449cf4f9670e87b5f08fd8d330a78391f kernel/keys/pgp/ABAF11C65A2970B130ABE3C479BE3E4300411886.asc 64bffcc23de4b023aa6bfe5e351eb39b3e5c4ba572122564690a5e0e9837d392 kernel/p16-thermal.patch -0e20e5854cb0613e154f18cb8ddbae52a3ae614915815ea2872dd7db6dc97018 kernel/p16-virtual-gpio.patch -6e94e341bcd221dbfec7432c12a7668b6da9eac34a1f3ba7e3d337657baa8d79 kernel/spi-acpi-irq-retry.patch 8780e78a1a737e127f25a65f6d95269bffd36158dc261114de7859b490bfc5aa licenses/GPL-2.0.txt 213e4f92de2bfb95c95fc90aa94a5378e92a7c3bdf1d2b22768da3fa9068b3b3 licenses/MIT.txt 61e87ec0907405aa0f1195d1d21aa4098d7df2c033c08de51258e33f3786b406 scripts/build-acpi.py -b58b73bef154cb7db3549036f9d6ff3406feb5e51072c71c19a6f951eff541d2 scripts/build-kernel.sh +506e14b26ae9458f766d8fb34911f26e841951aeec0efcd637394444327b2436 scripts/build-kernel.sh 8a8c12df13bcc88a42a2ebbb91ab0fcc9dc1327fc214333727d130aa59a17db3 scripts/check-cuda.sh -a17c4cc7e82c5949842868ce4d232fb231b2871368c358efac1d9e1708f61032 scripts/check-system.sh -e063e94587997c7f15a360505082456f41ed9590fffec49fa1b9338e6d9a29ae scripts/check-issue-9.sh -67eaad0f3cd3c1e70c626a5b9637e4870541b123e60ce797099e2d8e5c566581 scripts/common.sh +9085e1df170cd8e8e53e94c2118f20c97f6118b61d517e0f42131e1ef73ba6ea scripts/check-issue-9.sh +a3b0f0e5924b17e353046762fb2c8aeae7fb97e8dd58252277b473ebb595b52c scripts/check-system.sh +f57d6bb6d191c445fcbe38bdfcfcb73e5a88e043cf47636a85c39a4195e24915 scripts/common.sh b21dcdbd2ad8965fb4293d82d4dcb0aac3535b69bb60b0ef40fecfb779855b19 scripts/download-nightly.py 5be9b14df6688b1eefcb2f2fa115e764e3f5a97e172fc637fb7af2ecaee7bee4 scripts/dump-acpi.sh -b86ad1af8d54b26efd9445f018e21718052dff17e93ecb9d5402ea5b04008a46 scripts/install-kernel.sh -6e1a6a0914afa49f58a9991d78f10ba6d3ddcb59e104aa7cabe67cd48f0b11a5 scripts/install_state.py -41f72b79fb164fcabded755012d6c515ba7ec1304e5cb406f9d3924d805fcefc scripts/kernel_cmdline.py +ee482d4fc029a850314a2686587b4b040db2470b96a4f96d4a3481f50433d7dc scripts/install-kernel.sh +b60d6e5acd8f0eafd3a103b745dc16d203ff8f21f03db4cfe7b6a0a4e118f9b3 scripts/install_state.py +c934c341eae1faa3c772abea60aa2787dfe1d086f6e083d47d51a4bc2349d518 scripts/kernel_cmdline.py 5e28f9a26830d7e6038d993e61a1d623e9ed93a34b3e9aa3747d5b969cb939c3 scripts/p16-charge-limit 9d326dc959d45aa56cedcfb87470dbb38e11a46c56cb92cc030c075bfed5a557 scripts/p16-temperatures -bbb87c4d8609a68714061dd304dd74625b019310ae2ddfcda828d96a83ded15f scripts/p16_release.py +9a30c16431b1b0f1588b428009d45c98be30a92731648c8707d556b3e2294f19 scripts/p16_release.py 919015a7195f1e73b2e55777a48c9cc402db7f54f5eae285d8f3b546da45a86a scripts/peripherals.py ea4980d6c562d3d531235addc7c38c73c99d7b0a9a4766ba00039ffe3f3ad8f8 scripts/prepare-spark-hwmon.sh b66ef3f32656ed49b5e79f7a2a173109db8ef479f8c961f9a39b46951c2e0d3d scripts/restore-install.sh 76bbdcf4d09cb9add2f35a1b180041c7df9fb11769d63075cd4574fe5f24701a scripts/set-german-keyboard.py +cecaea9cca19032ae43da9eb007e51b923092e606368bce228f3776b02284588 scripts/usb4-pcie-hotplug-check 57138af3bc1128410972cbc2bdcf158f638337edb49b74b8665201751d8852f0 scripts/verify-boot.py -10d2ce1bb8f1257b31cefc37fb895f621a5daff27bd5b5be329b96d97b84c830 sources.json -ff925894ff05d4baf1c3fe9bd2d0a704694b62e5589746786e96d752a67af070 tests/test_installation.py +7b8bccf43f855801af0efa8ceedd6aa7fd08d6826708a585eb306b889a8366f5 sources.json +f253ade40b86b6052c0b082d06fa93c728077ebf245a90dfdd5402609051689f tests/test_installation.py 6e95783f69e90f41a8bb6d7353c253471dee19b4fdae341ffe0d0aa20c56278c tests/test_peripherals.py diff --git a/config/p16-acpi b/config/p16-acpi index 9a98b7c..c09e6df 100644 --- a/config/p16-acpi +++ b/config/p16-acpi @@ -1,6 +1,6 @@ #!/usr/bin/env bash build() { - [[ $KERNELVERSION == 7.2.8-14-omarchy-p16 || $KERNELVERSION == 7.2.8-14-omarchy-p16-asus || $KERNELVERSION == 7.2.8-23-omarchy-p16-asus || $KERNELVERSION == 7.2.8-24-omarchy-p16-asus || $KERNELVERSION == 7.2.8-25-omarchy-p16-asus || $KERNELVERSION == 7.2.8-23-omarchy-p16-asus-npu2 || $KERNELVERSION == 7.2.8-23-rtx-spark-npu ]] || { + [[ $KERNELVERSION == 7.2.8-14-omarchy-p16 || $KERNELVERSION == 7.2.8-14-omarchy-p16-asus || $KERNELVERSION == 7.2.8-23-omarchy-p16-asus || $KERNELVERSION == 7.2.8-24-omarchy-p16-asus || $KERNELVERSION == 7.2.8-25-omarchy-p16-asus || $KERNELVERSION == 7.3.0-26-omarchy-p16-asus || $KERNELVERSION == 7.2.8-23-omarchy-p16-asus-npu2 || $KERNELVERSION == 7.2.8-23-rtx-spark-npu ]] || { error 'P16 ACPI override requires the dedicated kernel allocation fix' return 1 } diff --git a/config/p16-asus-controls.service b/config/p16-asus-controls.service index 73b48ee..aa56336 100644 --- a/config/p16-asus-controls.service +++ b/config/p16-asus-controls.service @@ -4,6 +4,7 @@ ConditionKernelVersion=|7.2.8-14-omarchy-p16-asus ConditionKernelVersion=|7.2.8-23-omarchy-p16-asus ConditionKernelVersion=|7.2.8-24-omarchy-p16-asus ConditionKernelVersion=|7.2.8-25-omarchy-p16-asus +ConditionKernelVersion=|7.3.0-26-omarchy-p16-asus ConditionKernelVersion=|7.2.8-23-omarchy-p16-asus-npu2 ConditionKernelVersion=|7.2.8-23-rtx-spark-npu Before=power-profiles-daemon.service p16-charge-limit.service diff --git a/config/p16-charge-limit.service b/config/p16-charge-limit.service index b91005a..eebe795 100644 --- a/config/p16-charge-limit.service +++ b/config/p16-charge-limit.service @@ -6,6 +6,7 @@ ConditionKernelVersion=|7.2.8-14-omarchy-p16-asus ConditionKernelVersion=|7.2.8-23-omarchy-p16-asus ConditionKernelVersion=|7.2.8-24-omarchy-p16-asus ConditionKernelVersion=|7.2.8-25-omarchy-p16-asus +ConditionKernelVersion=|7.3.0-26-omarchy-p16-asus ConditionKernelVersion=|7.2.8-23-omarchy-p16-asus-npu2 ConditionKernelVersion=|7.2.8-23-rtx-spark-npu diff --git a/config/zz-p16-boot-menu.hook b/config/zz-p16-boot-menu.hook index 9684295..61ad91e 100644 --- a/config/zz-p16-boot-menu.hook +++ b/config/zz-p16-boot-menu.hook @@ -6,6 +6,7 @@ Target = linux-omarchy Target = linux-p16-asus-23 Target = linux-p16-asus-24 Target = linux-p16-asus-25 +Target = linux-p16-asus-26 Target = linux-p16-asus-23-npu2 Target = linux-rtx-spark-npu Target = limine diff --git a/config/zz-p16-hardware-fixes.conf b/config/zz-p16-hardware-fixes.conf index de0244b..7bda315 100644 --- a/config/zz-p16-hardware-fixes.conf +++ b/config/zz-p16-hardware-fixes.conf @@ -1,5 +1,5 @@ # Keep ACPI overrides out of stock kernels lacking the ARM64 allocation fix. -if [[ ${KERNELVERSION:-} == 7.2.8-14-omarchy-p16 || ${KERNELVERSION:-} == 7.2.8-14-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-23-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-24-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-25-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-23-omarchy-p16-asus-npu2 || ${KERNELVERSION:-} == 7.2.8-23-rtx-spark-npu ]]; then +if [[ ${KERNELVERSION:-} == 7.2.8-14-omarchy-p16 || ${KERNELVERSION:-} == 7.2.8-14-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-23-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-24-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-25-omarchy-p16-asus || ${KERNELVERSION:-} == 7.3.0-26-omarchy-p16-asus || ${KERNELVERSION:-} == 7.2.8-23-omarchy-p16-asus-npu2 || ${KERNELVERSION:-} == 7.2.8-23-rtx-spark-npu ]]; then HOOKS+=(p16-acpi) MODULES+=(spi_hid_acpi) fi diff --git a/kernel/0010-archlinux-base.patch b/kernel/0010-archlinux-base.patch deleted file mode 100644 index 497422b..0000000 --- a/kernel/0010-archlinux-base.patch +++ /dev/null @@ -1,55 +0,0 @@ -diff --git a/kernel/fork.c b/kernel/fork.c ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -127,6 +127,12 @@ - - #include - -+#ifdef CONFIG_USER_NS -+static int unprivileged_userns_clone = 1; -+#else -+#define unprivileged_userns_clone 1 -+#endif -+ - /* - * Minimum number of threads to boot the kernel - */ -@@ -2092,6 +2098,11 @@ __latent_entropy struct task_struct *copy_process( - return ERR_PTR(-EPERM); - } - -+ if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { -+ if (!capable(CAP_SYS_ADMIN)) -+ return ERR_PTR(-EPERM); -+ } -+ - /* - * Force any signals received before this point to be delivered - * before the fork happens. Collect up signals sent to multiple -@@ -3165,6 +3176,10 @@ static int check_unshare_flags(unsigned long unshare_flags) - if (!current_is_single_threaded()) - return -EINVAL; - } -+ if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ } - - return 0; - } -@@ -3400,6 +3415,15 @@ static const struct ctl_table fork_sysctl_table[] = { - .mode = 0644, - .proc_handler = sysctl_max_threads, - }, -+#ifdef CONFIG_USER_NS -+ { -+ .procname = "unprivileged_userns_clone", -+ .data = &unprivileged_userns_clone, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec, -+ }, -+#endif - }; - - static int __init init_fork_sysctl(void) diff --git a/kernel/0010-archlinux-base.patch.sig b/kernel/0010-archlinux-base.patch.sig deleted file mode 100644 index 586266d..0000000 Binary files a/kernel/0010-archlinux-base.patch.sig and /dev/null differ diff --git a/kernel/0011-kbuild-optimize-for-performance-o3.patch b/kernel/0011-kbuild-optimize-for-performance-o3.patch deleted file mode 100644 index 9506ee1..0000000 --- a/kernel/0011-kbuild-optimize-for-performance-o3.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/Makefile b/Makefile ---- a/Makefile -+++ b/Makefile -@@ -935,6 +935,9 @@ KBUILD_RUSTFLAGS += -Copt-level=2 - else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE - KBUILD_CFLAGS += -Os - KBUILD_RUSTFLAGS += -Copt-level=s -+else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3 -+KBUILD_CFLAGS += -O3 -+KBUILD_RUSTFLAGS += -Copt-level=3 - endif - - # Always set `debug-assertions` and `overflow-checks` because their default -diff --git a/init/Kconfig b/init/Kconfig ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1622,6 +1622,14 @@ config CC_OPTIMIZE_FOR_SIZE - Choosing this option will pass "-Os" to your compiler resulting - in a smaller kernel. - -+config CC_OPTIMIZE_FOR_PERFORMANCE_O3 -+ bool "Optimize harder for performance (-O3)" -+ help -+ Build with the "-O3" compiler flag: more inlining, loop -+ unrolling and vectorization than -O2, at the cost of a larger -+ kernel image and larger modules. Rust code is built at -+ opt-level 3. -+ - endchoice - - config HAVE_LD_DEAD_CODE_DATA_ELIMINATION diff --git a/kernel/0011-kbuild-optimize-for-performance-o3.patch.sig b/kernel/0011-kbuild-optimize-for-performance-o3.patch.sig deleted file mode 100644 index 48ab131..0000000 Binary files a/kernel/0011-kbuild-optimize-for-performance-o3.patch.sig and /dev/null differ diff --git a/kernel/0110-bore-6.8.0.patch b/kernel/0110-bore-6.8.0.patch deleted file mode 100644 index c126c5a..0000000 --- a/kernel/0110-bore-6.8.0.patch +++ /dev/null @@ -1,1241 +0,0 @@ -diff --git a/include/linux/sched.h b/include/linux/sched.h ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -823,6 +823,31 @@ struct kmap_ctrl { - #endif - }; - -+#ifdef CONFIG_SCHED_BORE -+#define BORE_BC_TIMESTAMP_SHIFT 16 -+ -+struct bore_bc { -+ union { -+ struct { -+ u64 timestamp: 48; -+ u64 penalty: 16; -+ }; -+ u64 value; -+ }; -+}; -+ -+struct bore_ctx { -+ u64 burst_time; -+ u16 prev_penalty; -+ u16 curr_penalty; -+ u16 penalty; -+ bool stop_update; -+ bool futex_waiting; -+ struct bore_bc subtree; -+ struct bore_bc group; -+}; -+#endif /* CONFIG_SCHED_BORE */ -+ - struct task_struct { - #ifdef CONFIG_THREAD_INFO_IN_TASK - /* -@@ -884,6 +909,9 @@ struct task_struct { - #ifdef CONFIG_SCHED_CLASS_EXT - struct sched_ext_entity scx; - #endif -+#ifdef CONFIG_SCHED_BORE -+ struct bore_ctx bore; -+#endif /* CONFIG_SCHED_BORE */ - const struct sched_class *sched_class; - - #ifdef CONFIG_SCHED_CORE -diff --git a/include/linux/sched/bore.h b/include/linux/sched/bore.h -new file mode 100644 ---- /dev/null -+++ b/include/linux/sched/bore.h -@@ -0,0 +1,49 @@ -+#ifndef _KERNEL_SCHED_BORE_H -+#define _KERNEL_SCHED_BORE_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SCHED_BORE_AUTHOR "Masahito Suzuki" -+#define SCHED_BORE_PROGNAME "BORE CPU Scheduler modification" -+ -+#define SCHED_BORE_VERSION "6.8.0" -+ -+extern u8 __read_mostly sched_bore; -+DECLARE_STATIC_KEY_TRUE(sched_bore_key); -+extern u8 __read_mostly sched_burst_inherit_type; -+extern u8 __read_mostly sched_burst_smoothness; -+extern u8 __read_mostly sched_burst_penalty_offset; -+extern uint __read_mostly sched_burst_penalty_scale; -+extern uint __read_mostly sched_burst_cache_lifetime; -+extern u8 __read_mostly sched_burst_protect_slice_lv; -+DECLARE_STATIC_KEY_TRUE(sched_burst_protect_slice_cond_key); -+DECLARE_STATIC_KEY_FALSE(sched_burst_protect_slice_prefer_key); -+ -+static inline u8 bore_score(struct task_struct *p) -+{ return p->bore.penalty >> 8; } -+ -+extern u8 effective_prio_bore(struct task_struct *p); -+extern void update_curr_bore(struct task_struct *p, u64 delta_exec); -+extern void restart_burst_bore(struct task_struct *p); -+extern void restart_burst_rescale_deadline_bore(struct task_struct *p); -+extern void task_fork_bore(struct task_struct *p, struct task_struct *parent, -+ u64 clone_flags, u64 now); -+extern void sched_init_bore(void); -+extern void reset_task_bore(struct task_struct *p); -+ -+extern int sched_bore_update_handler(const struct ctl_table *table, -+ int write, void __user *buffer, size_t *lenp, loff_t *ppos); -+extern int sched_burst_inherit_type_update_handler(const struct ctl_table *table, -+ int write, void __user *buffer, size_t *lenp, loff_t *ppos); -+extern int sched_burst_protect_slice_lv_update_handler(const struct ctl_table *table, -+ int write, void __user *buffer, size_t *lenp, loff_t *ppos); -+ -+extern void reweight_entity( -+ struct cfs_rq *cfs_rq, struct sched_entity *se, unsigned long weight); -+ -+#endif /* _KERNEL_SCHED_BORE_H */ -diff --git a/init/Kconfig b/init/Kconfig ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1480,6 +1480,23 @@ config CHECKPOINT_RESTORE - - If unsure, say N here. - -+config SCHED_BORE -+ bool "Burst-Oriented Response Enhancer" -+ default y -+ help -+ In Desktop and Mobile computing, one might prefer interactive -+ tasks to keep responsive no matter what they run in the background. -+ -+ Enabling this kernel feature modifies the scheduler to discriminate -+ tasks by their burst time (runtime since it last went sleeping or -+ yielding state) and prioritize those that run less bursty. -+ Such tasks usually include window compositor, widgets backend, -+ terminal emulator, video playback, games and so on. -+ With a little impact to scheduling fairness, it may improve -+ responsiveness especially under heavy background workload. -+ -+ If unsure, say Y here. -+ - config SCHED_AUTOGROUP - bool "Automatic process group scheduling" - select CGROUPS -diff --git a/kernel/Kconfig.hz b/kernel/Kconfig.hz ---- a/kernel/Kconfig.hz -+++ b/kernel/Kconfig.hz -@@ -57,3 +57,20 @@ config HZ - - config SCHED_HRTICK - def_bool HIGH_RES_TIMERS -+ -+config MIN_BASE_SLICE_NS -+ int "Default value for min_base_slice_ns" -+ default 2000000 -+ help -+ The BORE Scheduler automatically calculates the optimal base -+ slice for the configured HZ using the following equation: -+ -+ base_slice_ns = -+ 1000000000/HZ * DIV_ROUNDUP(min_base_slice_ns, 1000000000/HZ) -+ -+ This option sets the default lower bound limit of the base slice -+ to prevent the loss of task throughput due to overscheduling. -+ -+ Setting this value too high can cause the system to boot with -+ an unnecessarily large base slice, resulting in high scheduling -+ latency and poor system responsiveness. -diff --git a/kernel/exit.c b/kernel/exit.c ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -147,7 +147,11 @@ static void __unhash_process(struct release_task_post *post, struct task_struct - detach_pid(post->pids, p, PIDTYPE_SID); - - list_del_rcu(&p->tasks); -+#ifdef CONFIG_SCHED_BORE -+ list_del_rcu(&p->sibling); -+#else /* !CONFIG_SCHED_BORE */ - list_del_init(&p->sibling); -+#endif /* CONFIG_SCHED_BORE */ - __this_cpu_dec(process_counts); - } - list_del_rcu(&p->thread_node); -diff --git a/kernel/fork.c b/kernel/fork.c ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -120,6 +120,10 @@ - /* For dup_mmap(). */ - #include "../mm/internal.h" - -+#ifdef CONFIG_SCHED_BORE -+#include -+#endif /* CONFIG_SCHED_BORE */ -+ - #include - - #define CREATE_TRACE_POINTS -@@ -2443,6 +2447,11 @@ __latent_entropy struct task_struct *copy_process( - p->start_time = ktime_get_ns(); - p->start_boottime = ktime_get_boottime_ns(); - -+#ifdef CONFIG_SCHED_BORE -+ if (likely(p->pid)) -+ task_fork_bore(p, current, clone_flags, p->start_time); -+#endif /* CONFIG_SCHED_BORE */ -+ - /* - * Make it visible to the rest of the system, but dont wake it up yet. - * Need tasklist lock for parent etc handling! -@@ -2528,7 +2537,11 @@ __latent_entropy struct task_struct *copy_process( - p->real_parent->signal->is_child_subreaper; - if (clone_flags & CLONE_AUTOREAP) - p->signal->autoreap = 1; -+#ifdef CONFIG_SCHED_BORE -+ list_add_tail_rcu(&p->sibling, &p->real_parent->children); -+#else /* !CONFIG_SCHED_BORE */ - list_add_tail(&p->sibling, &p->real_parent->children); -+#endif /* CONFIG_SCHED_BORE */ - list_add_tail_rcu(&p->tasks, &init_task.tasks); - attach_pid(p, PIDTYPE_TGID); - attach_pid(p, PIDTYPE_PGID); -diff --git a/kernel/futex/waitwake.c b/kernel/futex/waitwake.c ---- a/kernel/futex/waitwake.c -+++ b/kernel/futex/waitwake.c -@@ -4,6 +4,9 @@ - #include - #include - #include -+#ifdef CONFIG_SCHED_BORE -+#include -+#endif /* CONFIG_SCHED_BORE */ - - #include "futex.h" - -@@ -384,7 +387,15 @@ void futex_do_wait(struct futex_q *q, struct hrtimer_sleeper *timeout) - * is no timeout, or if it has yet to expire. - */ - if (!timeout || timeout->task) -+#ifdef CONFIG_SCHED_BORE -+ { -+ current->bore.futex_waiting = true; -+#endif /* CONFIG_SCHED_BORE */ - schedule(); -+#ifdef CONFIG_SCHED_BORE -+ current->bore.futex_waiting = false; -+ } -+#endif /* CONFIG_SCHED_BORE */ - } - __set_current_state(TASK_RUNNING); - } -diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile ---- a/kernel/sched/Makefile -+++ b/kernel/sched/Makefile -@@ -40,3 +40,4 @@ obj-y += core.o - obj-y += fair.o - obj-y += build_policy.o - obj-y += build_utility.o -+obj-$(CONFIG_SCHED_BORE) += bore.o -diff --git a/kernel/sched/bore.c b/kernel/sched/bore.c -new file mode 100644 ---- /dev/null -+++ b/kernel/sched/bore.c -@@ -0,0 +1,466 @@ -+/* -+ * Burst-Oriented Response Enhancer (BORE) CPU Scheduler -+ * Copyright (C) 2021-2025 Masahito Suzuki -+ */ -+#include -+#include -+#include -+#include "sched.h" -+ -+#ifdef CONFIG_SCHED_BORE -+DEFINE_STATIC_KEY_TRUE(sched_bore_key); -+u8 __read_mostly sched_bore = 1; -+u8 __read_mostly sched_burst_inherit_type = 2; -+u8 __read_mostly sched_burst_protect_slice_lv = 1; -+u8 __read_mostly sched_burst_smoothness = 1; -+u8 __read_mostly sched_burst_penalty_offset = 24; -+uint __read_mostly sched_burst_penalty_scale = 1536; -+uint __read_mostly sched_burst_cache_lifetime = 75000000; -+static int __maybe_unused maxval_prio = 39; -+static int __maybe_unused maxval_6_bits = 63; -+static int __maybe_unused maxval_8_bits = 255; -+static int __maybe_unused maxval_12_bits = 4095; -+ -+#define MAX_BURST_PENALTY ((40U << 8) - 1) -+#define BURST_CACHE_SAMPLE_LIMIT 63 -+#define BURST_CACHE_SCAN_LIMIT (BURST_CACHE_SAMPLE_LIMIT * 2) -+ -+static u32 bore_reciprocal_lut[BURST_CACHE_SAMPLE_LIMIT + 1]; -+ -+DEFINE_STATIC_KEY_TRUE(sched_burst_inherit_key); -+DEFINE_STATIC_KEY_TRUE(sched_burst_ancestor_key); -+DEFINE_STATIC_KEY_TRUE (sched_burst_protect_slice_cond_key); -+DEFINE_STATIC_KEY_FALSE(sched_burst_protect_slice_prefer_key); -+ -+static inline u32 log2p1_u64_u32fp(u64 v, u8 fp) { -+ if (unlikely(!v)) return 0; -+ int clz = __builtin_clzll(v); -+ int exponent = 64 - clz; -+ u32 mantissa = (u32)((v << clz) << 1 >> (64 - fp)); -+ return exponent << fp | mantissa; -+} -+ -+static inline u32 calc_burst_penalty(u64 burst_time) { -+ u32 greed = log2p1_u64_u32fp(burst_time, 8), -+ tolerance = sched_burst_penalty_offset << 8; -+ s32 diff = (s32)(greed - tolerance); -+ u32 penalty = diff & ~(diff >> 31); -+ u32 scaled_penalty = penalty * sched_burst_penalty_scale >> 10; -+ s32 overflow = scaled_penalty - MAX_BURST_PENALTY; -+ return scaled_penalty - (overflow & ~(overflow >> 31)); -+} -+ -+static inline u64 rescale_slice(u64 delta, u8 old_prio, u8 new_prio) { -+ u64 unscaled, rescaled; -+ unscaled = mul_u64_u32_shr(delta , sched_prio_to_weight[old_prio], 10); -+ rescaled = mul_u64_u32_shr(unscaled, sched_prio_to_wmult [new_prio], 22); -+ return rescaled; -+} -+ -+static inline u32 binary_smooth(u32 new, u32 old) { -+ u32 is_growing = (new > old); -+ u32 increment = (new - old) * is_growing; -+ u32 shift = sched_burst_smoothness; -+ u32 smoothed = old + ((increment + (1U << shift) - 1) >> shift); -+ return (new & ~(-is_growing)) | (smoothed & (-is_growing)); -+} -+ -+static void reweight_task_by_prio(struct task_struct *p, int prio) { -+ if (task_has_idle_policy(p)) return; -+ -+ struct sched_entity *se = &p->se; -+ unsigned long weight = scale_load(sched_prio_to_weight[prio]); -+ -+ if (se->on_rq) { -+ p->bore.stop_update = true; -+ reweight_entity(cfs_rq_of(se), se, weight); -+ p->bore.stop_update = false; -+ } else -+ se->load.weight = weight; -+ se->load.inv_weight = sched_prio_to_wmult[prio]; -+} -+ -+u8 effective_prio_bore(struct task_struct *p) { -+ int prio = p->static_prio - MAX_RT_PRIO; -+ if (static_branch_likely(&sched_bore_key)) -+ prio += bore_score(p); -+ prio &= ~(prio >> 31); -+ s32 diff = prio - maxval_prio; -+ prio -= (diff & ~(diff >> 31)); -+ return (u8)prio; -+} -+ -+static void update_penalty(struct task_struct *p) { -+ struct bore_ctx *ctx = &p->bore; -+ -+ u8 prev_prio = effective_prio_bore(p); -+ -+ s32 diff = (s32)ctx->curr_penalty - (s32)ctx->prev_penalty; -+ u16 max_val = ctx->curr_penalty - (diff & (diff >> 31)); -+ u32 is_kthread = !!(p->flags & PF_KTHREAD); -+ ctx->penalty = max_val & -(s32)(!is_kthread); -+ -+ u8 new_prio = effective_prio_bore(p); -+ if (new_prio != prev_prio) -+ reweight_task_by_prio(p, new_prio); -+} -+ -+void update_curr_bore(struct task_struct *p, u64 delta_exec) { -+ struct bore_ctx *ctx = &p->bore; -+ if (ctx->stop_update) return; -+ -+ ctx->burst_time += delta_exec; -+ u32 curr_penalty = ctx->curr_penalty = calc_burst_penalty(ctx->burst_time); -+ -+ if (curr_penalty <= ctx->prev_penalty) return; -+ update_penalty(p); -+} -+ -+void restart_burst_bore(struct task_struct *p) { -+ struct bore_ctx *ctx = &p->bore; -+ u32 new_penalty = binary_smooth(ctx->curr_penalty, ctx->prev_penalty); -+ ctx->prev_penalty = new_penalty; -+ ctx->curr_penalty = 0; -+ ctx->burst_time = 0; -+ update_penalty(p); -+} -+ -+void restart_burst_rescale_deadline_bore(struct task_struct *p) { -+ struct sched_entity *se = &p->se; -+ s64 vscaled, vremain = se->deadline - se->vruntime; -+ -+ u8 old_prio = effective_prio_bore(p); -+ restart_burst_bore(p); -+ u8 new_prio = effective_prio_bore(p); -+ -+ if (old_prio > new_prio) { -+ vscaled = rescale_slice(abs(vremain), old_prio, new_prio); -+ if (unlikely(vremain < 0)) -+ vscaled = -vscaled; -+ se->deadline = se->vruntime + vscaled; -+ } -+} -+ -+static inline bool task_is_bore_eligible(struct task_struct *p) -+{return p && p->sched_class == &fair_sched_class && !p->exit_state;} -+ -+#ifndef for_each_child_task -+#define for_each_child_task(p, t) \ -+ list_for_each_entry_rcu(t, &(p)->children, sibling) -+#endif -+ -+static inline u32 count_children_upto2(struct task_struct *p) { -+ struct list_head *head = &p->children; -+ struct list_head *first = READ_ONCE(head->next); -+ struct list_head *second = READ_ONCE(first->next); -+ return (first != head) + (second != head); -+} -+ -+static inline bool burst_cache_expired(struct bore_bc *bc, u64 now) { -+ struct bore_bc bc_val = { .value = READ_ONCE(bc->value) }; -+ u64 timestamp = (u64)bc_val.timestamp << BORE_BC_TIMESTAMP_SHIFT; -+ return now - timestamp > (u64)sched_burst_cache_lifetime; -+} -+ -+static void update_burst_cache(struct bore_bc *bc, -+ struct task_struct *p, u32 count, u32 total, u64 now) { -+ u32 average = (count == 1) ? total : -+ (u32)(((u64)total * bore_reciprocal_lut[count]) >> 32); -+ -+ struct bore_bc new_bc = { -+ .penalty = max(average, p->bore.penalty), -+ .timestamp = now >> BORE_BC_TIMESTAMP_SHIFT -+ }; -+ WRITE_ONCE(bc->value, new_bc.value); -+} -+ -+static u32 inherit_from_parent(struct task_struct *parent, -+ u64 clone_flags, u64 now) { -+ struct bore_bc bc_val; -+ -+ if (clone_flags & CLONE_PARENT) -+ parent = rcu_dereference(parent->real_parent); -+ -+ struct bore_bc *bc = &parent->bore.subtree; -+ -+ if (burst_cache_expired(bc, now)) { -+ struct task_struct *child; -+ u32 count = 0, total = 0, scan_count = 0; -+ for_each_child_task(parent, child) { -+ if (count >= BURST_CACHE_SAMPLE_LIMIT) break; -+ if (scan_count++ >= BURST_CACHE_SCAN_LIMIT) break; -+ -+ if (!task_is_bore_eligible(child)) continue; -+ count++; -+ total += child->bore.penalty; -+ } -+ -+ update_burst_cache(bc, parent, count, total, now); -+ } -+ -+ bc_val.value = READ_ONCE(bc->value); -+ return (u32)bc_val.penalty; -+} -+ -+static u32 inherit_from_ancestor_hub(struct task_struct *parent, -+ u64 clone_flags, u64 now) { -+ struct bore_bc bc_val; -+ struct task_struct *ancestor = parent; -+ u32 sole_child_count = 0; -+ -+ if (clone_flags & CLONE_PARENT) { -+ ancestor = rcu_dereference(ancestor->real_parent); -+ sole_child_count = 1; -+ } -+ -+ for (struct task_struct *next; -+ (next = rcu_dereference(ancestor->real_parent)) != ancestor && -+ count_children_upto2(ancestor) <= sole_child_count; -+ ancestor = next, sole_child_count = 1) {} -+ -+ struct bore_bc *bc = &ancestor->bore.subtree; -+ -+ if (burst_cache_expired(bc, now)) { -+ struct task_struct *direct_child; -+ u32 count = 0, total = 0, scan_count = 0; -+ for_each_child_task(ancestor, direct_child) { -+ if (count >= BURST_CACHE_SAMPLE_LIMIT) break; -+ if (scan_count++ >= BURST_CACHE_SCAN_LIMIT) break; -+ -+ struct task_struct *descendant = direct_child; -+ while (count_children_upto2(descendant) == 1) { -+ struct task_struct *next_descendant = -+ list_first_or_null_rcu(&descendant->children, -+ struct task_struct, sibling); -+ if (!next_descendant) break; -+ descendant = next_descendant; -+ } -+ -+ if (!task_is_bore_eligible(descendant)) continue; -+ count++; -+ total += descendant->bore.penalty; -+ } -+ -+ update_burst_cache(bc, ancestor, count, total, now); -+ } -+ -+ bc_val.value = READ_ONCE(bc->value); -+ return (u32)bc_val.penalty; -+} -+ -+static u32 inherit_from_thread_group(struct task_struct *p, u64 now) { -+ struct bore_bc bc_val; -+ struct task_struct *leader = p->group_leader; -+ struct bore_bc *bc = &leader->bore.group; -+ -+ if (burst_cache_expired(bc, now)) { -+ struct task_struct *sibling; -+ u32 count = 0, total = 0, scan_count = 0; -+ -+ for_each_thread(leader, sibling) { -+ if (count >= BURST_CACHE_SAMPLE_LIMIT) break; -+ if (scan_count++ >= BURST_CACHE_SCAN_LIMIT) break; -+ -+ if (!task_is_bore_eligible(sibling)) continue; -+ count++; -+ total += sibling->bore.penalty; -+ } -+ -+ update_burst_cache(bc, leader, count, total, now); -+ } -+ -+ bc_val.value = READ_ONCE(bc->value); -+ return (u32)bc_val.penalty; -+} -+ -+void task_fork_bore(struct task_struct *p, -+ struct task_struct *parent, u64 clone_flags, u64 now) { -+ if (!static_branch_likely(&sched_bore_key) || !task_is_bore_eligible(p)) return; -+ -+ rcu_read_lock(); -+ struct bore_ctx *ctx = &p->bore; -+ u32 inherited_penalty; -+ if (clone_flags & CLONE_THREAD) -+ inherited_penalty = inherit_from_thread_group(parent, now); -+ else if (static_branch_likely(&sched_burst_inherit_key)) -+ inherited_penalty = static_branch_likely(&sched_burst_ancestor_key)? -+ inherit_from_ancestor_hub(parent, clone_flags, now): -+ inherit_from_parent(parent, clone_flags, now); -+ else -+ inherited_penalty = 0; -+ -+ if (ctx->prev_penalty < inherited_penalty) -+ ctx->prev_penalty = inherited_penalty; -+ ctx->curr_penalty = 0; -+ ctx->burst_time = 0; -+ ctx->stop_update = false; -+ ctx->futex_waiting = false; -+ update_penalty(p); -+ rcu_read_unlock(); -+} -+ -+void reset_task_bore(struct task_struct *p) -+{ memset(&p->bore, 0, sizeof(struct bore_ctx)); } -+ -+static void update_inherit_type(void) { -+ switch(sched_burst_inherit_type) { -+ case 1: -+ static_branch_enable(&sched_burst_inherit_key); -+ static_branch_disable(&sched_burst_ancestor_key); -+ break; -+ case 2: -+ static_branch_enable(&sched_burst_inherit_key); -+ static_branch_enable(&sched_burst_ancestor_key); -+ break; -+ default: -+ static_branch_disable(&sched_burst_inherit_key); -+ break; -+ } -+} -+ -+void __init sched_init_bore(void) { -+ printk(KERN_INFO "%s %s by %s\n", -+ SCHED_BORE_PROGNAME, SCHED_BORE_VERSION, SCHED_BORE_AUTHOR); -+ -+ for (int i = 1; i <= BURST_CACHE_SAMPLE_LIMIT; i++) -+ bore_reciprocal_lut[i] = (u32)div64_u64(0xffffffffULL + i, i); -+ -+ reset_task_bore(&init_task); -+ update_inherit_type(); -+} -+ -+static void readjust_all_task_weights(void) { -+ struct task_struct *task; -+ struct rq *rq; -+ struct rq_flags rf; -+ -+ scoped_guard(write_lock_irq, &tasklist_lock) -+ for_each_process(task) { -+ if (!task_is_bore_eligible(task)) continue; -+ rq = task_rq_lock(task, &rf); -+ update_rq_clock(rq); -+ reweight_task_by_prio(task, effective_prio_bore(task)); -+ task_rq_unlock(rq, task, &rf); -+ } -+} -+ -+int sched_bore_update_handler(const struct ctl_table *table, -+ int write, void __user *buffer, size_t *lenp, loff_t *ppos) { -+ int ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos); -+ if (ret || !write) -+ return ret; -+ -+ if (sched_bore) -+ static_branch_enable(&sched_bore_key); -+ else -+ static_branch_disable(&sched_bore_key); -+ -+ readjust_all_task_weights(); -+ -+ return 0; -+} -+ -+int sched_burst_inherit_type_update_handler(const struct ctl_table *table, -+ int write, void __user *buffer, size_t *lenp, loff_t *ppos) { -+ int ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos); -+ if (ret || !write) -+ return ret; -+ -+ update_inherit_type(); -+ -+ return 0; -+} -+ -+int sched_burst_protect_slice_lv_update_handler(const struct ctl_table *table, -+ int write, void __user *buffer, size_t *lenp, loff_t *ppos) { -+ int ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos); -+ if (ret || !write) -+ return ret; -+ -+ if (sched_burst_protect_slice_lv == 1 || -+ sched_burst_protect_slice_lv == 2) -+ static_branch_enable(&sched_burst_protect_slice_cond_key); -+ else -+ static_branch_disable(&sched_burst_protect_slice_cond_key); -+ -+ if (sched_burst_protect_slice_lv >= 2) -+ static_branch_enable(&sched_burst_protect_slice_prefer_key); -+ else -+ static_branch_disable(&sched_burst_protect_slice_prefer_key); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_SYSCTL -+static struct ctl_table sched_bore_sysctls[] = { -+ { -+ .procname = "sched_bore", -+ .data = &sched_bore, -+ .maxlen = sizeof(u8), -+ .mode = 0644, -+ .proc_handler = sched_bore_update_handler, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, -+ { -+ .procname = "sched_burst_inherit_type", -+ .data = &sched_burst_inherit_type, -+ .maxlen = sizeof(u8), -+ .mode = 0644, -+ .proc_handler = sched_burst_inherit_type_update_handler, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_TWO, -+ }, -+ { -+ .procname = "sched_burst_smoothness", -+ .data = &sched_burst_smoothness, -+ .maxlen = sizeof(u8), -+ .mode = 0644, -+ .proc_handler = proc_dou8vec_minmax, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_THREE, -+ }, -+ { -+ .procname = "sched_burst_penalty_offset", -+ .data = &sched_burst_penalty_offset, -+ .maxlen = sizeof(u8), -+ .mode = 0644, -+ .proc_handler = proc_dou8vec_minmax, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = &maxval_6_bits, -+ }, -+ { -+ .procname = "sched_burst_penalty_scale", -+ .data = &sched_burst_penalty_scale, -+ .maxlen = sizeof(uint), -+ .mode = 0644, -+ .proc_handler = proc_douintvec_minmax, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = &maxval_12_bits, -+ }, -+ { -+ .procname = "sched_burst_cache_lifetime", -+ .data = &sched_burst_cache_lifetime, -+ .maxlen = sizeof(uint), -+ .mode = 0644, -+ .proc_handler = proc_douintvec, -+ }, -+ { -+ .procname = "sched_burst_protect_slice_lv", -+ .data = &sched_burst_protect_slice_lv, -+ .maxlen = sizeof(u8), -+ .mode = 0644, -+ .proc_handler = sched_burst_protect_slice_lv_update_handler, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_THREE, -+ }, -+}; -+ -+static int __init sched_bore_sysctl_init(void) { -+ register_sysctl_init("kernel", sched_bore_sysctls); -+ return 0; -+} -+late_initcall(sched_bore_sysctl_init); -+ -+#endif // CONFIG_SYSCTL -+#endif /* CONFIG_SCHED_BORE */ -diff --git a/kernel/sched/build_utility.c b/kernel/sched/build_utility.c ---- a/kernel/sched/build_utility.c -+++ b/kernel/sched/build_utility.c -@@ -54,6 +54,10 @@ - #include "stats.h" - #include "autogroup.h" - -+#ifdef CONFIG_SCHED_BORE -+#include -+#endif /* CONFIG_SCHED_BORE */ -+ - #include "clock.c" - - #ifdef CONFIG_CGROUP_CPUACCT -diff --git a/kernel/sched/core.c b/kernel/sched/core.c ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -100,6 +100,10 @@ - #include "../smpboot.h" - #include "../locking/mutex.h" - -+#ifdef CONFIG_SCHED_BORE -+#include -+#endif /* CONFIG_SCHED_BORE */ -+ - EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_send_cpu); - EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_send_cpumask); - -@@ -1534,7 +1538,11 @@ int tg_nop(struct task_group *tg, void *data) - - void set_load_weight(struct task_struct *p, bool update_load) - { -+#ifdef CONFIG_SCHED_BORE -+ int prio = effective_prio_bore(p); -+#else /* !CONFIG_SCHED_BORE */ - int prio = p->static_prio - MAX_RT_PRIO; -+#endif /* CONFIG_SCHED_BORE */ - struct load_weight lw; - - if (task_has_idle_policy(p)) { -@@ -8989,6 +8997,10 @@ void __init sched_init(void) - BUG_ON(!sched_class_above(&ext_sched_class, &idle_sched_class)); - #endif - -+#ifdef CONFIG_SCHED_BORE -+ sched_init_bore(); -+#endif /* CONFIG_SCHED_BORE */ -+ - wait_bit_init(); - - #ifdef CONFIG_FAIR_GROUP_SCHED -diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c ---- a/kernel/sched/debug.c -+++ b/kernel/sched/debug.c -@@ -170,6 +170,53 @@ static const struct file_operations sched_feat_fops = { - .release = single_release, - }; - -+#ifdef CONFIG_SCHED_BORE -+#define DEFINE_SYSCTL_SCHED_FUNC(name, update_func) \ -+static ssize_t sched_##name##_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) \ -+{ \ -+ char buf[16]; \ -+ unsigned int value; \ -+\ -+ if (cnt > 15) \ -+ cnt = 15; \ -+\ -+ if (copy_from_user(&buf, ubuf, cnt)) \ -+ return -EFAULT; \ -+ buf[cnt] = '\0'; \ -+\ -+ if (kstrtouint(buf, 10, &value)) \ -+ return -EINVAL; \ -+\ -+ sysctl_sched_##name = value; \ -+ sched_update_##update_func(); \ -+\ -+ *ppos += cnt; \ -+ return cnt; \ -+} \ -+\ -+static int sched_##name##_show(struct seq_file *m, void *v) \ -+{ \ -+ seq_printf(m, "%d\n", sysctl_sched_##name); \ -+ return 0; \ -+} \ -+\ -+static int sched_##name##_open(struct inode *inode, struct file *filp) \ -+{ \ -+ return single_open(filp, sched_##name##_show, NULL); \ -+} \ -+\ -+static const struct file_operations sched_##name##_fops = { \ -+ .open = sched_##name##_open, \ -+ .write = sched_##name##_write, \ -+ .read = seq_read, \ -+ .llseek = seq_lseek, \ -+ .release = single_release, \ -+}; -+ -+DEFINE_SYSCTL_SCHED_FUNC(min_base_slice, min_base_slice) -+ -+#undef DEFINE_SYSCTL_SCHED_FUNC -+#else /* !CONFIG_SCHED_BORE */ - static ssize_t sched_scaling_write(struct file *filp, const char __user *ubuf, - size_t cnt, loff_t *ppos) - { -@@ -209,6 +256,7 @@ static const struct file_operations sched_scaling_fops = { - .llseek = seq_lseek, - .release = single_release, - }; -+#endif /* CONFIG_SCHED_BORE */ - - #ifdef CONFIG_SCHED_CACHE - static ssize_t -@@ -645,12 +693,19 @@ static __init int sched_init_debug(void) - debugfs_create_file("preempt", 0644, debugfs_sched, NULL, &sched_dynamic_fops); - #endif - -+#ifdef CONFIG_SCHED_BORE -+ debugfs_create_file("min_base_slice_ns", 0644, debugfs_sched, NULL, &sched_min_base_slice_fops); -+ debugfs_create_u32("base_slice_ns", 0444, debugfs_sched, &sysctl_sched_base_slice); -+#else /* !CONFIG_SCHED_BORE */ - debugfs_create_u32("base_slice_ns", 0644, debugfs_sched, &sysctl_sched_base_slice); -+#endif /* CONFIG_SCHED_BORE */ - - debugfs_create_u32("latency_warn_ms", 0644, debugfs_sched, &sysctl_resched_latency_warn_ms); - debugfs_create_u32("latency_warn_once", 0644, debugfs_sched, &sysctl_resched_latency_warn_once); - -+#if !defined(CONFIG_SCHED_BORE) - debugfs_create_file("tunable_scaling", 0644, debugfs_sched, NULL, &sched_scaling_fops); -+#endif /* CONFIG_SCHED_BORE */ - debugfs_create_u32("migration_cost_ns", 0644, debugfs_sched, &sysctl_sched_migration_cost); - debugfs_create_u32("nr_migrate", 0644, debugfs_sched, &sysctl_sched_nr_migrate); - -@@ -911,6 +966,9 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p) - SPLIT_NS(schedstat_val_or_zero(p->stats.sum_sleep_runtime)), - SPLIT_NS(schedstat_val_or_zero(p->stats.sum_block_runtime))); - -+#ifdef CONFIG_SCHED_BORE -+ SEQ_printf(m, " %2d", bore_score(p)); -+#endif /* CONFIG_SCHED_BORE */ - #ifdef CONFIG_NUMA_BALANCING - SEQ_printf(m, " %d %d", task_node(p), task_numa_group_id(p)); - #endif -@@ -1401,6 +1459,9 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns, - __PS("nr_involuntary_switches", p->nivcsw); - - P(se.load.weight); -+#ifdef CONFIG_SCHED_BORE -+ __PS("bore.score", bore_score(p)); -+#endif /* CONFIG_SCHED_BORE */ - P(se.avg.load_sum); - P(se.avg.runnable_sum); - P(se.avg.util_sum); -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -58,6 +58,10 @@ - #include "stats.h" - #include "autogroup.h" - -+#ifdef CONFIG_SCHED_BORE -+#include -+#endif /* CONFIG_SCHED_BORE */ -+ - /* - * The initial- and re-scaling of tunables is configurable - * -@@ -67,17 +71,30 @@ - * SCHED_TUNABLESCALING_LOG - scaled logarithmically, *1+ilog(ncpus) - * SCHED_TUNABLESCALING_LINEAR - scaled linear, *ncpus - * -- * (default SCHED_TUNABLESCALING_LOG = *(1+ilog(ncpus)) -+ * BORE : default SCHED_TUNABLESCALING_NONE = *1 constant -+ * EEVDF: default SCHED_TUNABLESCALING_LOG = *(1+ilog(ncpus)) - */ -+#ifdef CONFIG_SCHED_BORE -+unsigned int sysctl_sched_tunable_scaling = SCHED_TUNABLESCALING_NONE; -+#else /* !CONFIG_SCHED_BORE */ - unsigned int sysctl_sched_tunable_scaling = SCHED_TUNABLESCALING_LOG; -+#endif /* CONFIG_SCHED_BORE */ - - /* - * Minimal preemption granularity for CPU-bound tasks: - * -- * (default: 0.70 msec * (1 + ilog(ncpus)), units: nanoseconds) -+ * BORE : base_slice = minimum multiple of nsecs_per_tick >= min_base_slice -+ * (default min_base_slice = 2000000 constant, units: nanoseconds) -+ * EEVDF: default 0.70 msec * (1 + ilog(ncpus)), units: nanoseconds - */ -+#ifdef CONFIG_SCHED_BORE -+static const unsigned int nsecs_per_tick = 1000000000ULL / HZ; -+unsigned int sysctl_sched_min_base_slice = CONFIG_MIN_BASE_SLICE_NS; -+__read_mostly uint sysctl_sched_base_slice = nsecs_per_tick; -+#else /* !CONFIG_SCHED_BORE */ - unsigned int sysctl_sched_base_slice = 700000ULL; - static unsigned int normalized_sysctl_sched_base_slice = 700000ULL; -+#endif /* CONFIG_SCHED_BORE */ - - __read_mostly unsigned int sysctl_sched_migration_cost = 500000UL; - -@@ -189,6 +206,13 @@ static inline void update_load_set(struct load_weight *lw, unsigned long w) - * - * This idea comes from the SD scheduler of Con Kolivas: - */ -+#ifdef CONFIG_SCHED_BORE -+static void update_sysctl(void) { -+ sysctl_sched_base_slice = nsecs_per_tick * -+ max(1UL, DIV_ROUND_UP(sysctl_sched_min_base_slice, nsecs_per_tick)); -+} -+void sched_update_min_base_slice(void) { update_sysctl(); } -+#else /* !CONFIG_SCHED_BORE */ - static unsigned int get_update_sysctl_factor(void) - { - unsigned int cpus = min_t(unsigned int, num_online_cpus(), 8); -@@ -219,6 +243,7 @@ static void update_sysctl(void) - SET_SYSCTL(sched_base_slice); - #undef SET_SYSCTL - } -+#endif /* CONFIG_SCHED_BORE */ - - void __init sched_init_granularity(void) - { -@@ -1093,7 +1118,11 @@ struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq) - */ - static inline void set_protect_slice(struct cfs_rq *cfs_rq, struct sched_entity *se) - { -+#ifdef CONFIG_SCHED_BORE -+ u64 slice = sysctl_sched_base_slice; -+#else /* CONFIG_SCHED_BORE */ - u64 slice = normalized_sysctl_sched_base_slice; -+#endif /* CONFIG_SCHED_BORE */ - u64 vprot = se->deadline; - - if (sched_feat(RUN_TO_PARITY)) -@@ -1170,8 +1199,17 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq, bool protect) - if (curr && (!curr->on_rq || !entity_eligible(cfs_rq, curr))) - curr = NULL; - -- if (curr && protect && protect_slice(curr)) -- return curr; -+ if (curr && protect && protect_slice(curr)) { -+#ifdef CONFIG_SCHED_BORE -+ if (static_branch_likely(&sched_bore_key)) { -+ if ((static_branch_likely(&sched_burst_protect_slice_cond_key) || -+ static_branch_unlikely(&sched_burst_protect_slice_prefer_key)) && -+ (!entity_is_task(curr) || !task_of(curr)->bore.futex_waiting)) -+ return curr; -+ } else -+#endif /* CONFIG_SCHED_BORE */ -+ return curr; -+ } - - /* Pick the leftmost entity if it's eligible */ - if (se && entity_eligible(cfs_rq, se)) { -@@ -1227,6 +1265,7 @@ struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) - /************************************************************** - * Scheduling class statistics methods: - */ -+#if !defined(CONFIG_SCHED_BORE) - int sched_update_scaling(void) - { - unsigned int factor = get_update_sysctl_factor(); -@@ -1238,6 +1277,7 @@ int sched_update_scaling(void) - - return 0; - } -+#endif /* CONFIG_SCHED_BORE */ - - static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se); - -@@ -1979,6 +2019,38 @@ static void account_llc_dequeue(struct rq *rq, struct task_struct *p) {} - - #endif /* CONFIG_SCHED_CACHE */ - -+#ifdef CONFIG_SCHED_BORE -+static inline bool do_preempt_weight(struct cfs_rq *cfs_rq, -+ struct sched_entity *pse, struct sched_entity *se) -+{ -+ /* -+ * Companion to the PREEMPT_SHORT path: where that lets a shorter-slice -+ * waker cancel current's slice protection, this lets a heavier (under -+ * BORE: more interactive) waker do so. No RUN_TO_PARITY gate -- in 7.0 -+ * the slice protection (vprot) exists regardless of RUN_TO_PARITY, so -+ * the weight bypass must apply either way. -+ */ -+ if (!static_branch_likely(&sched_burst_protect_slice_cond_key)) -+ return false; -+ -+ if (static_branch_unlikely(&sched_burst_protect_slice_prefer_key) -+ ? (pse->load.weight <= se->load.weight) -+ : (pse->load.weight < se->load.weight)) -+ return false; -+ -+ if (!entity_eligible(cfs_rq, pse)) -+ return false; -+ -+ if (entity_before(pse, se)) -+ return true; -+ -+ if (!entity_eligible(cfs_rq, se)) -+ return true; -+ -+ return false; -+} -+#endif /* CONFIG_SCHED_BORE */ -+ - /* - * Used by other classes to account runtime. - */ -@@ -2014,6 +2086,11 @@ static void update_curr(struct cfs_rq *cfs_rq) - resched = update_deadline(cfs_rq, curr); - - if (entity_is_task(curr)) { -+#ifdef CONFIG_SCHED_BORE -+ struct task_struct *p = task_of(curr); -+ update_curr_bore(p, delta_exec); -+#endif /* CONFIG_SCHED_BORE */ -+ - /* - * If the fair_server is active, we need to account for the - * fair_server time whether or not the task is running on -@@ -4671,8 +4748,8 @@ rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot) - se->vprot = div64_long(se->vprot * old_weight, weight); - } - --static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, -- unsigned long weight) -+void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, -+ unsigned long weight) - { - bool curr = cfs_rq->curr == se; - bool rel_vprot = false; -@@ -5976,13 +6053,12 @@ void __setparam_fair(struct task_struct *p, const struct sched_attr *attr) - static void - place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) - { -- u64 vslice, vruntime = avg_vruntime(cfs_rq); -+ u64 vslice = 0, vruntime = avg_vruntime(cfs_rq); - bool update_zero = false; - s64 lag = 0; - - if (!se->custom_slice) - se->slice = sysctl_sched_base_slice; -- vslice = calc_delta_fair(se->slice, se); - - /* - * Due to how V is constructed as the weighted average of entities, -@@ -6094,7 +6170,18 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) - se->rel_deadline = 0; - return; - } -- -+#ifdef CONFIG_SCHED_BORE -+ if (static_branch_likely(&sched_bore_key) && -+ entity_is_task(se) && -+ task_of(se)->bore.futex_waiting) -+ goto vslice_found; -+#endif /* !CONFIG_SCHED_BORE */ -+ vslice = calc_delta_fair(se->slice, se); -+#ifdef CONFIG_SCHED_BORE -+ if (static_branch_likely(&sched_bore_key)) -+ vslice >>= !!(flags & (ENQUEUE_INITIAL | ENQUEUE_WAKEUP)); -+ else -+#endif /* CONFIG_SCHED_BORE */ - /* - * When joining the competition; the existing tasks will be, - * on average, halfway through their slice, as such start tasks -@@ -6103,6 +6190,9 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) - if (sched_feat(PLACE_DEADLINE_INITIAL) && (flags & ENQUEUE_INITIAL)) - vslice /= 2; - -+#ifdef CONFIG_SCHED_BORE -+vslice_found: -+#endif /* CONFIG_SCHED_BORE */ - /* - * EEVDF: vd_i = ve_i + r_i/w_i - */ -@@ -6113,7 +6203,7 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq); - static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq); - - static void --requeue_delayed_entity(struct sched_entity *se); -+requeue_delayed_entity(struct sched_entity *se, int flags); - - static void - enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) -@@ -7776,7 +7866,7 @@ static int choose_idle_cpu(int cpu, struct task_struct *p) - } - - static void --requeue_delayed_entity(struct sched_entity *se) -+requeue_delayed_entity(struct sched_entity *se, int flags) - { - struct cfs_rq *cfs_rq = cfs_rq_of(se); - -@@ -7794,7 +7884,13 @@ requeue_delayed_entity(struct sched_entity *se) - cfs_rq->nr_queued--; - if (se != cfs_rq->curr) - __dequeue_entity(cfs_rq, se); -- place_entity(cfs_rq, se, 0); -+#ifdef CONFIG_SCHED_BORE -+ if (static_branch_likely(&sched_bore_key)) -+ flags |= ENQUEUE_WAKEUP; -+ else -+#endif /* CONFIG_SCHED_BORE */ -+ flags = 0; -+ place_entity(cfs_rq, se, flags); - if (se != cfs_rq->curr) - __enqueue_entity(cfs_rq, se); - cfs_rq->nr_queued++; -@@ -7833,7 +7929,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) - util_est_enqueue(&rq->cfs, p); - - if (flags & ENQUEUE_DELAYED) { -- requeue_delayed_entity(se); -+ requeue_delayed_entity(se, flags); - return; - } - -@@ -7851,7 +7947,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) - for_each_sched_entity(se) { - if (se->on_rq) { - if (se->sched_delayed) -- requeue_delayed_entity(se); -+ requeue_delayed_entity(se, flags); - break; - } - cfs_rq = cfs_rq_of(se); -@@ -8054,6 +8150,15 @@ static bool dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) - if (!p->se.sched_delayed) - util_est_dequeue(&rq->cfs, p); - -+#ifdef CONFIG_SCHED_BORE -+ struct cfs_rq *cfs_rq = cfs_rq_of(&p->se); -+ struct sched_entity *se = &p->se; -+ if ((flags & DEQUEUE_SLEEP) && entity_is_task(se)) { -+ if (cfs_rq->curr == se) -+ update_curr(cfs_rq); -+ restart_burst_bore(p); -+ } -+#endif /* CONFIG_SCHED_BORE */ - if (dequeue_entities(rq, &p->se, flags) < 0) - return false; - -@@ -9860,6 +9965,18 @@ static void wakeup_preempt_fair(struct rq *rq, struct task_struct *p, int wake_f - goto pick; - } - -+#ifdef CONFIG_SCHED_BORE -+ /* -+ * Likewise, if @p is heavier than current (under BORE: more -+ * interactive), per kernel.sched_burst_protect_slice_lv, override -+ * current's slice protection to allow preemption. -+ */ -+ if (do_preempt_weight(cfs_rq, pse, se)) { -+ preempt_action = PREEMPT_WAKEUP_SHORT; -+ goto pick; -+ } -+#endif -+ - /* - * Ignore wakee preemption on WF_FORK as it is less likely that - * there is shared data as exec often follow fork. Do not -@@ -10030,16 +10147,25 @@ static void yield_task_fair(struct rq *rq) - /* - * Are we the only task in the tree? - */ -+#if !defined(CONFIG_SCHED_BORE) - if (unlikely(rq->nr_running == 1)) - return; - - clear_buddies(cfs_rq, se); -+#endif /* CONFIG_SCHED_BORE */ - - update_rq_clock(rq); - /* - * Update run-time statistics of the 'current'. - */ - update_curr(cfs_rq); -+#ifdef CONFIG_SCHED_BORE -+ restart_burst_rescale_deadline_bore(curr); -+ if (unlikely(rq->nr_running == 1)) -+ return; -+ -+ clear_buddies(cfs_rq, se); -+#endif /* CONFIG_SCHED_BORE */ - /* - * Tell update_rq_clock() that we've just updated, - * so we don't do microscopic update in schedule() -@@ -15022,6 +15148,9 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p) - WARN_ON_ONCE(p->se.sched_delayed); - - attach_task_cfs_rq(p); -+#ifdef CONFIG_SCHED_BORE -+ reset_task_bore(p); -+#endif /* CONFIG_SCHED_BORE */ - - set_task_max_allowed_capacity(p); - -diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h ---- a/kernel/sched/sched.h -+++ b/kernel/sched/sched.h -@@ -2267,7 +2267,11 @@ extern int group_balance_cpu(struct sched_group *sg); - extern void update_sched_domain_debugfs(void); - extern void dirty_sched_domain_sysctl(int cpu); - -+#ifdef CONFIG_SCHED_BORE -+extern void sched_update_min_base_slice(void); -+#else /* !CONFIG_SCHED_BORE */ - extern int sched_update_scaling(void); -+#endif /* CONFIG_SCHED_BORE */ - - static inline const struct cpumask *task_user_cpus(struct task_struct *p) - { -@@ -3112,7 +3116,12 @@ static inline void attach_one_task(struct rq *rq, struct task_struct *p) - extern __read_mostly unsigned int sysctl_sched_nr_migrate; - extern __read_mostly unsigned int sysctl_sched_migration_cost; - -+#ifdef CONFIG_SCHED_BORE -+extern unsigned int sysctl_sched_min_base_slice; -+extern __read_mostly uint sysctl_sched_base_slice; -+#else /* !CONFIG_SCHED_BORE */ - extern unsigned int sysctl_sched_base_slice; -+#endif /* CONFIG_SCHED_BORE */ - - extern int sysctl_resched_latency_warn_ms; - extern int sysctl_resched_latency_warn_once; diff --git a/kernel/0110-bore-6.8.0.patch.sig b/kernel/0110-bore-6.8.0.patch.sig deleted file mode 100644 index 1efa5e3..0000000 Binary files a/kernel/0110-bore-6.8.0.patch.sig and /dev/null differ diff --git a/kernel/0120-tlbpull.patch b/kernel/0120-tlbpull.patch deleted file mode 100644 index 14e2d46..0000000 --- a/kernel/0120-tlbpull.patch +++ /dev/null @@ -1,582 +0,0 @@ -diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h ---- a/arch/x86/include/asm/pgtable.h -+++ b/arch/x86/include/asm/pgtable.h -@@ -50,7 +50,7 @@ void ptdump_walk_user_pgd_level_checkwx(void); - extern spinlock_t pgd_lock; - extern struct list_head pgd_list; - --extern struct mm_struct *pgd_page_get_mm(struct page *page); -+struct mm_struct *pgd_page_get_mm(struct ptdesc *pt); - - extern pmdval_t early_pmd_flags; - -diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h ---- a/arch/x86/include/asm/pgtable_types.h -+++ b/arch/x86/include/asm/pgtable_types.h -@@ -512,7 +512,7 @@ static inline pgprot_t pgprot_large_2_4k(pgprot_t pgprot) - return __pgprot(protval_large_2_4k(pgprot_val(pgprot))); - } - -- -+struct ptdesc; - typedef struct page *pgtable_t; - - extern pteval_t __supported_pte_mask; -diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h ---- a/arch/x86/include/asm/tlbflush.h -+++ b/arch/x86/include/asm/tlbflush.h -@@ -4,6 +4,7 @@ - - #include - #include -+#include - #include - - #include -@@ -211,6 +212,12 @@ extern u16 invlpgb_count_max; - - extern void initialize_tlbstate_and_flush(void); - -+/* -+ * Keep stack-allocated flush_tlb_info cacheline aligned, but cap the -+ * alignment to avoid excessive stack usage on large-cacheline systems. -+ */ -+#define FLUSH_TLB_INFO_ALIGN MIN(SMP_CACHE_BYTES, 64) -+ - /* - * TLB flushing: - * -@@ -249,7 +256,7 @@ struct flush_tlb_info { - u8 stride_shift; - u8 freed_tables; - u8 trim_cpumask; --}; -+} __aligned(FLUSH_TLB_INFO_ALIGN); - - void flush_tlb_local(void); - void flush_tlb_one_user(unsigned long addr); -diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c ---- a/arch/x86/kernel/kvm.c -+++ b/arch/x86/kernel/kvm.c -@@ -663,8 +663,10 @@ static void kvm_flush_tlb_multi(const struct cpumask *cpumask, - u8 state; - int cpu; - struct kvm_steal_time *src; -- struct cpumask *flushmask = this_cpu_cpumask_var_ptr(__pv_cpu_mask); -+ struct cpumask *flushmask; - -+ guard(preempt)(); -+ flushmask = this_cpu_cpumask_var_ptr(__pv_cpu_mask); - cpumask_copy(flushmask, cpumask); - /* - * We have to call flush only on online vCPUs. And -diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c ---- a/arch/x86/mm/fault.c -+++ b/arch/x86/mm/fault.c -@@ -275,17 +275,17 @@ void arch_sync_kernel_mappings(unsigned long start, unsigned long end) - for (addr = start & PMD_MASK; - addr >= TASK_SIZE_MAX && addr < VMALLOC_END; - addr += PMD_SIZE) { -- struct page *page; -+ struct ptdesc *ptdesc; - - spin_lock(&pgd_lock); -- list_for_each_entry(page, &pgd_list, lru) { -+ list_for_each_entry(ptdesc, &pgd_list, pt_list) { - spinlock_t *pgt_lock; - - /* the pgt_lock only for Xen */ -- pgt_lock = &pgd_page_get_mm(page)->page_table_lock; -+ pgt_lock = &pgd_page_get_mm(ptdesc)->page_table_lock; - - spin_lock(pgt_lock); -- vmalloc_sync_one(page_address(page), addr); -+ vmalloc_sync_one(ptdesc_address(ptdesc), addr); - spin_unlock(pgt_lock); - } - spin_unlock(&pgd_lock); -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -136,7 +136,7 @@ static void sync_global_pgds_l5(unsigned long start, unsigned long end) - - for (addr = start; addr <= end; addr = ALIGN(addr + 1, PGDIR_SIZE)) { - const pgd_t *pgd_ref = pgd_offset_k(addr); -- struct page *page; -+ struct ptdesc *ptdesc; - - /* Check for overflow */ - if (addr < start) -@@ -146,13 +146,13 @@ static void sync_global_pgds_l5(unsigned long start, unsigned long end) - continue; - - spin_lock(&pgd_lock); -- list_for_each_entry(page, &pgd_list, lru) { -+ list_for_each_entry(ptdesc, &pgd_list, pt_list) { - pgd_t *pgd; - spinlock_t *pgt_lock; - -- pgd = (pgd_t *)page_address(page) + pgd_index(addr); -+ pgd = (pgd_t *)ptdesc_address(ptdesc) + pgd_index(addr); - /* the pgt_lock only for Xen */ -- pgt_lock = &pgd_page_get_mm(page)->page_table_lock; -+ pgt_lock = &pgd_page_get_mm(ptdesc)->page_table_lock; - spin_lock(pgt_lock); - - if (!pgd_none(*pgd_ref) && !pgd_none(*pgd)) -@@ -174,7 +174,7 @@ static void sync_global_pgds_l4(unsigned long start, unsigned long end) - for (addr = start; addr <= end; addr = ALIGN(addr + 1, PGDIR_SIZE)) { - pgd_t *pgd_ref = pgd_offset_k(addr); - const p4d_t *p4d_ref; -- struct page *page; -+ struct ptdesc *ptdesc; - - /* - * With folded p4d, pgd_none() is always false, we need to -@@ -187,15 +187,15 @@ static void sync_global_pgds_l4(unsigned long start, unsigned long end) - continue; - - spin_lock(&pgd_lock); -- list_for_each_entry(page, &pgd_list, lru) { -+ list_for_each_entry(ptdesc, &pgd_list, pt_list) { - pgd_t *pgd; - p4d_t *p4d; - spinlock_t *pgt_lock; - -- pgd = (pgd_t *)page_address(page) + pgd_index(addr); -+ pgd = (pgd_t *)ptdesc_address(ptdesc) + pgd_index(addr); - p4d = p4d_offset(pgd, addr); - /* the pgt_lock only for Xen */ -- pgt_lock = &pgd_page_get_mm(page)->page_table_lock; -+ pgt_lock = &pgd_page_get_mm(ptdesc)->page_table_lock; - spin_lock(pgt_lock); - - if (!p4d_none(*p4d_ref) && !p4d_none(*p4d)) -diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c ---- a/arch/x86/mm/pat/set_memory.c -+++ b/arch/x86/mm/pat/set_memory.c -@@ -88,9 +88,8 @@ static unsigned long direct_pages_count[PG_LEVEL_NUM]; - void update_page_count(int level, unsigned long pages) - { - /* Protect against CPA */ -- spin_lock(&pgd_lock); -+ guard(spinlock)(&pgd_lock); - direct_pages_count[level] += pages; -- spin_unlock(&pgd_lock); - } - - static void split_page_count(int level) -@@ -420,7 +419,7 @@ static void __cpa_collapse_large_pages(struct cpa_data *cpa) - int collapsed = 0; - int i; - -- spin_lock(&cpa_lock); -+ guard(spinlock)(&cpa_lock); - - if (cpa->flags & (CPA_PAGES_ARRAY | CPA_ARRAY)) { - for (i = 0; i < cpa->numpages; i++) -@@ -435,10 +434,8 @@ static void __cpa_collapse_large_pages(struct cpa_data *cpa) - collapsed += collapse_large_pages(addr, &pgtables); - } - -- if (!collapsed) { -- spin_unlock(&cpa_lock); -+ if (!collapsed) - return; -- } - - flush_tlb_all(); - -@@ -454,8 +451,6 @@ static void __cpa_collapse_large_pages(struct cpa_data *cpa) - else - pagetable_free(ptdesc); - } -- -- spin_unlock(&cpa_lock); - } - - static void cpa_collapse_large_pages(struct cpa_data *cpa) -@@ -916,24 +911,23 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) - { - /* change init_mm */ - set_pte_atomic(kpte, pte); --#ifdef CONFIG_X86_32 -- { -- struct page *page; - -- list_for_each_entry(page, &pgd_list, lru) { -+ if (IS_ENABLED(CONFIG_X86_32)) { -+ struct ptdesc *ptdesc; -+ -+ list_for_each_entry(ptdesc, &pgd_list, pt_list) { - pgd_t *pgd; - p4d_t *p4d; - pud_t *pud; - pmd_t *pmd; - -- pgd = (pgd_t *)page_address(page) + pgd_index(address); -+ pgd = (pgd_t *)ptdesc_address(ptdesc) + pgd_index(address); - p4d = p4d_offset(pgd, address); - pud = pud_offset(p4d, address); - pmd = pmd_offset(pud, address); - set_pte_atomic((pte_t *)pmd, pte); - } - } --#endif - } - - static pgprot_t pgprot_clear_protnone_bits(pgprot_t prot) -@@ -1103,16 +1097,11 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address, - static int should_split_large_page(pte_t *kpte, unsigned long address, - struct cpa_data *cpa) - { -- int do_split; -- - if (cpa->force_split) - return 1; - -- spin_lock(&pgd_lock); -- do_split = __should_split_large_page(kpte, address, cpa); -- spin_unlock(&pgd_lock); -- -- return do_split; -+ guard(spinlock)(&pgd_lock); -+ return __should_split_large_page(kpte, address, cpa); - } - - static void split_set_pte(struct cpa_data *cpa, pte_t *pte, unsigned long pfn, -@@ -1162,16 +1151,14 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, - bool nx, rw; - pte_t *tmp; - -- spin_lock(&pgd_lock); -+ guard(spinlock)(&pgd_lock); - /* - * Check for races, another CPU might have split this page - * up for us already: - */ - tmp = _lookup_address_cpa(cpa, address, &level, &nx, &rw); -- if (tmp != kpte) { -- spin_unlock(&pgd_lock); -+ if (tmp != kpte) - return 1; -- } - - paravirt_alloc_pte(&init_mm, page_to_pfn(base)); - -@@ -1204,7 +1191,6 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, - break; - - default: -- spin_unlock(&pgd_lock); - return 1; - } - -@@ -1252,7 +1238,6 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, - * just split large page entry. - */ - flush_tlb_all(); -- spin_unlock(&pgd_lock); - - return 0; - } -@@ -1327,11 +1312,11 @@ static int collapse_pmd_page(pmd_t *pmd, unsigned long addr, - list_add(&page_ptdesc(pmd_page(old_pmd))->pt_list, pgtables); - - if (IS_ENABLED(CONFIG_X86_32)) { -- struct page *page; -+ struct ptdesc *ptdesc; - - /* Update all PGD tables to use the same large page */ -- list_for_each_entry(page, &pgd_list, lru) { -- pgd_t *pgd = (pgd_t *)page_address(page) + pgd_index(addr); -+ list_for_each_entry(ptdesc, &pgd_list, pt_list) { -+ pgd_t *pgd = (pgd_t *)ptdesc_address(ptdesc) + pgd_index(addr); - p4d_t *p4d = p4d_offset(pgd, addr); - pud_t *pud = pud_offset(p4d, addr); - pmd_t *pmd = pmd_offset(pud, addr); -@@ -1405,7 +1390,7 @@ static int collapse_pud_page(pud_t *pud, unsigned long addr, - */ - static int collapse_large_pages(unsigned long addr, struct list_head *pgtables) - { -- int collapsed = 0; -+ int collapsed; - pgd_t *pgd; - p4d_t *p4d; - pud_t *pud; -@@ -1413,26 +1398,24 @@ static int collapse_large_pages(unsigned long addr, struct list_head *pgtables) - - addr &= PMD_MASK; - -- spin_lock(&pgd_lock); -+ guard(spinlock)(&pgd_lock); - pgd = pgd_offset_k(addr); - if (pgd_none(*pgd)) -- goto out; -+ return 0; - p4d = p4d_offset(pgd, addr); - if (p4d_none(*p4d)) -- goto out; -+ return 0; - pud = pud_offset(p4d, addr); - if (!pud_present(*pud) || pud_leaf(*pud)) -- goto out; -+ return 0; - pmd = pmd_offset(pud, addr); - if (!pmd_present(*pmd) || pmd_leaf(*pmd)) -- goto out; -+ return 0; - - collapsed = collapse_pmd_page(pmd, addr, pgtables); - if (collapsed) - collapsed += collapse_pud_page(pud, addr, pgtables); - --out: -- spin_unlock(&pgd_lock); - return collapsed; - } - -diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c ---- a/arch/x86/mm/pgtable.c -+++ b/arch/x86/mm/pgtable.c -@@ -74,9 +74,9 @@ static void pgd_set_mm(pgd_t *pgd, struct mm_struct *mm) - virt_to_ptdesc(pgd)->pt_mm = mm; - } - --struct mm_struct *pgd_page_get_mm(struct page *page) -+struct mm_struct *pgd_page_get_mm(struct ptdesc *pt) - { -- return page_ptdesc(page)->pt_mm; -+ return pt->pt_mm; - } - - static void pgd_ctor(struct mm_struct *mm, pgd_t *pgd) -diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c ---- a/arch/x86/mm/tlb.c -+++ b/arch/x86/mm/tlb.c -@@ -1373,35 +1373,19 @@ void flush_tlb_multi(const struct cpumask *cpumask, - */ - unsigned long tlb_single_page_flush_ceiling __read_mostly = 33; - --static DEFINE_PER_CPU_SHARED_ALIGNED(struct flush_tlb_info, flush_tlb_info); -- --#ifdef CONFIG_DEBUG_VM --static DEFINE_PER_CPU(unsigned int, flush_tlb_info_idx); --#endif -- --static struct flush_tlb_info *get_flush_tlb_info(struct mm_struct *mm, -- unsigned long start, unsigned long end, -- unsigned int stride_shift, bool freed_tables, -- u64 new_tlb_gen) -+static void init_flush_tlb_info(struct flush_tlb_info *info, -+ struct mm_struct *mm, -+ unsigned long start, unsigned long end, -+ unsigned int stride_shift, bool freed_tables, -+ u64 new_tlb_gen) - { -- struct flush_tlb_info *info = this_cpu_ptr(&flush_tlb_info); -- --#ifdef CONFIG_DEBUG_VM -- /* -- * Ensure that the following code is non-reentrant and flush_tlb_info -- * is not overwritten. This means no TLB flushing is initiated by -- * interrupt handlers and machine-check exception handlers. -- */ -- BUG_ON(this_cpu_inc_return(flush_tlb_info_idx) != 1); --#endif -- - /* - * If the number of flushes is so large that a full flush - * would be faster, do a full flush. - */ - if ((end - start) >> stride_shift > tlb_single_page_flush_ceiling) { -- start = 0; -- end = TLB_FLUSH_ALL; -+ start = 0; -+ end = TLB_FLUSH_ALL; - } - - info->start = start; -@@ -1412,32 +1396,21 @@ static struct flush_tlb_info *get_flush_tlb_info(struct mm_struct *mm, - info->new_tlb_gen = new_tlb_gen; - info->initiating_cpu = smp_processor_id(); - info->trim_cpumask = 0; -- -- return info; --} -- --static void put_flush_tlb_info(void) --{ --#ifdef CONFIG_DEBUG_VM -- /* Complete reentrancy prevention checks */ -- barrier(); -- this_cpu_dec(flush_tlb_info_idx); --#endif - } - - void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, - unsigned long end, unsigned int stride_shift, - bool freed_tables) - { -- struct flush_tlb_info *info; -+ struct flush_tlb_info info; -+ bool remote_flush = false; - int cpu = get_cpu(); - u64 new_tlb_gen; - - /* This is also a barrier that synchronizes with switch_mm(). */ - new_tlb_gen = inc_mm_tlb_gen(mm); - -- info = get_flush_tlb_info(mm, start, end, stride_shift, freed_tables, -- new_tlb_gen); -+ init_flush_tlb_info(&info, mm, start, end, stride_shift, freed_tables, new_tlb_gen); - - /* - * flush_tlb_multi() is not optimized for the common case in which only -@@ -1445,20 +1418,24 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, - * flush_tlb_func_local() directly in this case. - */ - if (mm_global_asid(mm)) { -- broadcast_tlb_flush(info); -+ broadcast_tlb_flush(&info); - } else if (cpumask_any_but(mm_cpumask(mm), cpu) < nr_cpu_ids) { -- info->trim_cpumask = should_trim_cpumask(mm); -- flush_tlb_multi(mm_cpumask(mm), info); -- consider_global_asid(mm); -+ remote_flush = true; - } else if (mm == this_cpu_read(cpu_tlbstate.loaded_mm)) { - lockdep_assert_irqs_enabled(); - local_irq_disable(); -- flush_tlb_func(info); -+ flush_tlb_func(&info); - local_irq_enable(); - } - -- put_flush_tlb_info(); - put_cpu(); -+ -+ if (remote_flush) { -+ info.trim_cpumask = should_trim_cpumask(mm); -+ flush_tlb_multi(mm_cpumask(mm), &info); -+ consider_global_asid(mm); -+ } -+ - mmu_notifier_arch_invalidate_secondary_tlbs(mm, start, end); - } - -@@ -1527,19 +1504,16 @@ static void kernel_tlb_flush_range(struct flush_tlb_info *info) - - void flush_tlb_kernel_range(unsigned long start, unsigned long end) - { -- struct flush_tlb_info *info; -+ struct flush_tlb_info info; - - guard(preempt)(); -+ init_flush_tlb_info(&info, NULL, start, end, PAGE_SHIFT, false, -+ TLB_GENERATION_INVALID); - -- info = get_flush_tlb_info(NULL, start, end, PAGE_SHIFT, false, -- TLB_GENERATION_INVALID); -- -- if (info->end == TLB_FLUSH_ALL) -- kernel_tlb_flush_all(info); -+ if (info.end == TLB_FLUSH_ALL) -+ kernel_tlb_flush_all(&info); - else -- kernel_tlb_flush_range(info); -- -- put_flush_tlb_info(); -+ kernel_tlb_flush_range(&info); - } - - /* -@@ -1707,12 +1681,12 @@ EXPORT_SYMBOL_FOR_KVM(__flush_tlb_all); - - void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch) - { -- struct flush_tlb_info *info; -- -+ struct flush_tlb_info info; -+ bool remote_flush = false; - int cpu = get_cpu(); - -- info = get_flush_tlb_info(NULL, 0, TLB_FLUSH_ALL, 0, false, -- TLB_GENERATION_INVALID); -+ init_flush_tlb_info(&info, NULL, 0, TLB_FLUSH_ALL, 0, false, -+ TLB_GENERATION_INVALID); - /* - * flush_tlb_multi() is not optimized for the common case in which only - * a local TLB flush is needed. Optimize this use-case by calling -@@ -1722,18 +1696,20 @@ void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch) - invlpgb_flush_all_nonglobals(); - batch->unmapped_pages = false; - } else if (cpumask_any_but(&batch->cpumask, cpu) < nr_cpu_ids) { -- flush_tlb_multi(&batch->cpumask, info); -+ remote_flush = true; - } else if (cpumask_test_cpu(cpu, &batch->cpumask)) { - lockdep_assert_irqs_enabled(); - local_irq_disable(); -- flush_tlb_func(info); -+ flush_tlb_func(&info); - local_irq_enable(); - } - -- cpumask_clear(&batch->cpumask); -- -- put_flush_tlb_info(); - put_cpu(); -+ -+ if (remote_flush) -+ flush_tlb_multi(&batch->cpumask, &info); -+ -+ cpumask_clear(&batch->cpumask); - } - - /* -diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c ---- a/arch/x86/xen/mmu_pv.c -+++ b/arch/x86/xen/mmu_pv.c -@@ -836,15 +836,15 @@ static void xen_pgd_pin(struct mm_struct *mm) - */ - void xen_mm_pin_all(void) - { -- struct page *page; -+ struct ptdesc *ptdesc; - - spin_lock(&init_mm.page_table_lock); - spin_lock(&pgd_lock); - -- list_for_each_entry(page, &pgd_list, lru) { -- if (!PagePinned(page)) { -- __xen_pgd_pin(&init_mm, (pgd_t *)page_address(page)); -- SetPageSavePinned(page); -+ list_for_each_entry(ptdesc, &pgd_list, pt_list) { -+ if (!PagePinned(ptdesc_page(ptdesc))) { -+ __xen_pgd_pin(&init_mm, (pgd_t *)ptdesc_address(ptdesc)); -+ SetPageSavePinned(ptdesc_page(ptdesc)); - } - } - -@@ -947,16 +947,16 @@ static void xen_pgd_unpin(struct mm_struct *mm) - */ - void xen_mm_unpin_all(void) - { -- struct page *page; -+ struct ptdesc *ptdesc; - - spin_lock(&init_mm.page_table_lock); - spin_lock(&pgd_lock); - -- list_for_each_entry(page, &pgd_list, lru) { -- if (PageSavePinned(page)) { -- BUG_ON(!PagePinned(page)); -- __xen_pgd_unpin(&init_mm, (pgd_t *)page_address(page)); -- ClearPageSavePinned(page); -+ list_for_each_entry(ptdesc, &pgd_list, pt_list) { -+ if (PageSavePinned(ptdesc_page(ptdesc))) { -+ BUG_ON(!PagePinned(ptdesc_page(ptdesc))); -+ __xen_pgd_unpin(&init_mm, (pgd_t *)ptdesc_address(ptdesc)); -+ ClearPageSavePinned(ptdesc_page(ptdesc)); - } - } - diff --git a/kernel/0120-tlbpull.patch.sig b/kernel/0120-tlbpull.patch.sig deleted file mode 100644 index 766d275..0000000 Binary files a/kernel/0120-tlbpull.patch.sig and /dev/null differ diff --git a/kernel/0121-smp-preempt.patch b/kernel/0121-smp-preempt.patch deleted file mode 100644 index 66bd67c..0000000 --- a/kernel/0121-smp-preempt.patch +++ /dev/null @@ -1,514 +0,0 @@ -diff --git a/include/linux/sched.h b/include/linux/sched.h ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -848,6 +848,17 @@ struct bore_ctx { - }; - #endif /* CONFIG_SCHED_BORE */ - -+#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPTION) -+struct task_ipi_mask { -+ union { -+ cpumask_t *ipi_mask_ptr; -+ unsigned long ipi_mask_val; -+ }; -+}; -+#else -+struct task_ipi_mask { }; -+#endif -+ - struct task_struct { - #ifdef CONFIG_THREAD_INFO_IN_TASK - /* -@@ -1387,6 +1398,7 @@ struct task_struct { - struct list_head perf_event_list; - struct perf_ctx_data __rcu *perf_ctx_data; - #endif -+ struct task_ipi_mask __private ipi_mask; - #ifdef CONFIG_DEBUG_PREEMPT - unsigned long preempt_disable_ip; - #endif -diff --git a/include/linux/smp.h b/include/linux/smp.h ---- a/include/linux/smp.h -+++ b/include/linux/smp.h -@@ -47,8 +47,7 @@ extern void __smp_call_single_queue(int cpu, struct llist_node *node); - /* total number of cpus in this system (may exceed NR_CPUS) */ - extern unsigned int total_cpus; - --int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, -- int wait); -+int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, bool wait); - - void on_each_cpu_cond_mask(smp_cond_func_t cond_func, smp_call_func_t func, - void *info, bool wait, const struct cpumask *mask); -@@ -239,6 +238,18 @@ static inline int get_boot_cpu_id(void) - - #endif /* !SMP */ - -+#if defined(CONFIG_PREEMPTION) && defined(CONFIG_SMP) -+int smp_task_ipi_mask_alloc(struct task_struct *task); -+void smp_task_ipi_mask_free(struct task_struct *task); -+#else -+static inline int smp_task_ipi_mask_alloc(struct task_struct *task) -+{ -+ return 0; -+} -+ -+static inline void smp_task_ipi_mask_free(struct task_struct *task) { } -+#endif -+ - /* - * raw_smp_processor_id() - get the current (unstable) CPU id - * -diff --git a/kernel/fork.c b/kernel/fork.c ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -547,6 +547,7 @@ void free_task(struct task_struct *tsk) - #endif - release_user_cpus_ptr(tsk); - scs_release(tsk); -+ smp_task_ipi_mask_free(tsk); - - #ifndef CONFIG_THREAD_INFO_IN_TASK - /* -@@ -945,10 +946,14 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) - #endif - account_kernel_stack(tsk, 1); - -- err = scs_prepare(tsk, node); -+ err = smp_task_ipi_mask_alloc(tsk); - if (err) - goto free_stack; - -+ err = scs_prepare(tsk, node); -+ if (err) -+ goto free_ipi_mask; -+ - #ifdef CONFIG_SECCOMP - /* - * We must handle setting up seccomp filters once we're under -@@ -1026,6 +1031,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) - #endif - return tsk; - -+free_ipi_mask: -+ smp_task_ipi_mask_free(tsk); - free_stack: - exit_task_stack_account(tsk); - free_thread_stack(tsk); -diff --git a/kernel/scftorture.c b/kernel/scftorture.c ---- a/kernel/scftorture.c -+++ b/kernel/scftorture.c -@@ -348,6 +348,8 @@ static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_ra - int ret = 0; - struct scf_check *scfcp = NULL; - struct scf_selector *scfsp = scf_sel_rand(trsp); -+ bool is_single = (scfsp->scfs_prim == SCF_PRIM_SINGLE || -+ scfsp->scfs_prim == SCF_PRIM_SINGLE_RPC); - - if (scfsp->scfs_prim == SCF_PRIM_SINGLE || scfsp->scfs_wait) { - scfcp = kmalloc_obj(*scfcp, GFP_ATOMIC); -@@ -364,8 +366,6 @@ static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_ra - } - if (use_cpus_read_lock) - cpus_read_lock(); -- else -- preempt_disable(); - switch (scfsp->scfs_prim) { - case SCF_PRIM_RESCHED: - if (IS_BUILTIN(CONFIG_SCF_TORTURE_TEST)) { -@@ -411,13 +411,10 @@ static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_ra - if (!ret) { - if (use_cpus_read_lock) - cpus_read_unlock(); -- else -- preempt_enable(); -+ - wait_for_completion(&scfcp->scfc_completion); - if (use_cpus_read_lock) - cpus_read_lock(); -- else -- preempt_disable(); - } else { - scfp->n_single_rpc_ofl++; - scf_add_to_free_list(scfcp); -@@ -452,7 +449,7 @@ static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_ra - scfcp->scfc_out = true; - } - if (scfcp && scfsp->scfs_wait) { -- if (WARN_ON_ONCE((num_online_cpus() > 1 || scfsp->scfs_prim == SCF_PRIM_SINGLE) && -+ if (WARN_ON_ONCE(((use_cpus_read_lock && num_online_cpus() > 1) || is_single) && - !scfcp->scfc_out)) { - pr_warn("%s: Memory-ordering failure, scfs_prim: %d.\n", __func__, scfsp->scfs_prim); - atomic_inc(&n_mb_out_errs); // Leak rather than trash! -@@ -463,8 +460,6 @@ static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_ra - } - if (use_cpus_read_lock) - cpus_read_unlock(); -- else -- preempt_enable(); - if (allocfail) - schedule_timeout_idle((1 + longwait) * HZ); // Let no-wait handlers complete. - else if (!(torture_random(trsp) & 0xfff)) -diff --git a/kernel/smp.c b/kernel/smp.c ---- a/kernel/smp.c -+++ b/kernel/smp.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -63,7 +64,14 @@ int smpcfd_prepare_cpu(unsigned int cpu) - free_cpumask_var(cfd->cpumask); - return -ENOMEM; - } -- cfd->csd = alloc_percpu(call_single_data_t); -+ -+ /* -+ * Allocate the per-CPU CSD the first time a CPU comes up. It is -+ * not freed when the CPU is offlined, so csd_lock_wait() can access -+ * it even when the CPU was offlined after preemption was re-enabled. -+ */ -+ if (!cfd->csd) -+ cfd->csd = alloc_percpu(call_single_data_t); - if (!cfd->csd) { - free_cpumask_var(cfd->cpumask); - free_cpumask_var(cfd->cpumask_ipi); -@@ -79,7 +87,6 @@ int smpcfd_dead_cpu(unsigned int cpu) - - free_cpumask_var(cfd->cpumask); - free_cpumask_var(cfd->cpumask_ipi); -- free_percpu(cfd->csd); - return 0; - } - -@@ -323,6 +330,8 @@ static void __csd_lock_wait(call_single_data_t *csd) - int bug_id = 0; - u64 ts0, ts1; - -+ guard(preempt)(); -+ - ts1 = ts0 = ktime_get_mono_fast_ns(); - for (;;) { - if (csd_lock_wait_toolong(csd, ts0, &ts1, &bug_id, &nmessages)) -@@ -659,17 +668,9 @@ void flush_smp_call_function_queue(void) - local_irq_restore(flags); - } - --/** -- * smp_call_function_single - Run a function on a specific CPU -- * @cpu: Specific target CPU for this function. -- * @func: The function to run. This must be fast and non-blocking. -- * @info: An arbitrary pointer to pass to the function. -- * @wait: If true, wait until function has completed on other CPUs. -- * -- * Returns: %0 on success, else a negative status code. -- */ --int smp_call_function_single(int cpu, smp_call_func_t func, void *info, -- int wait) -+static int __smp_call_function_single(int cpu, smp_call_func_t func, -+ void *info, const struct cpumask *mask, -+ bool wait) - { - call_single_data_t *csd; - call_single_data_t csd_stack = { -@@ -686,6 +687,14 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info, - */ - this_cpu = get_cpu(); - -+ if (mask) { -+ /* Try for same CPU (cheapest) */ -+ if (!cpumask_test_cpu(this_cpu, mask)) -+ cpu = sched_numa_find_nth_cpu(mask, 0, cpu_to_node(this_cpu)); -+ else -+ cpu = this_cpu; -+ } -+ - /* - * Can deadlock when called with interrupts disabled. - * We allow cpu's that are not yet online though, as no one else can -@@ -718,13 +727,32 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info, - - err = generic_exec_single(cpu, csd); - -+ /* -+ * @csd is stack-allocated when @wait is true. No concurrent access -+ * except from the IPI completion path, so we can re-enable preemption -+ * early to reduce latency. -+ */ -+ put_cpu(); -+ - if (wait) - csd_lock_wait(csd); - -- put_cpu(); -- - return err; - } -+ -+/** -+ * smp_call_function_single - Run a function on a specific CPU -+ * @cpu: Specific target CPU for this function. -+ * @func: The function to run. This must be fast and non-blocking. -+ * @info: An arbitrary pointer to pass to the function. -+ * @wait: If true, wait until function has completed on other CPUs. -+ * -+ * Returns: %0 on success, else a negative status code. -+ */ -+int smp_call_function_single(int cpu, smp_call_func_t func, void *info, bool wait) -+{ -+ return __smp_call_function_single(cpu, func, info, NULL, wait); -+} - EXPORT_SYMBOL(smp_call_function_single); - - /** -@@ -775,10 +803,10 @@ EXPORT_SYMBOL_GPL(smp_call_function_single_async); - - /** - * smp_call_function_any - Run a function on any of the given cpus -- * @mask: The mask of cpus it can run on. -- * @func: The function to run. This must be fast and non-blocking. -- * @info: An arbitrary pointer to pass to the function. -- * @wait: If true, wait until function has completed. -+ * @mask: The mask of cpus it can run on. -+ * @func: The function to run. This must be fast and non-blocking. -+ * @info: An arbitrary pointer to pass to the function. -+ * @wait: If true, wait until function has completed. - * - * Selection preference: - * 1) current cpu if in @mask -@@ -789,20 +817,54 @@ EXPORT_SYMBOL_GPL(smp_call_function_single_async); - int smp_call_function_any(const struct cpumask *mask, - smp_call_func_t func, void *info, int wait) - { -- unsigned int cpu; -- int ret; -- -- /* Try for same CPU (cheapest) */ -- cpu = get_cpu(); -- if (!cpumask_test_cpu(cpu, mask)) -- cpu = sched_numa_find_nth_cpu(mask, 0, cpu_to_node(cpu)); -- -- ret = smp_call_function_single(cpu, func, info, wait); -- put_cpu(); -- return ret; -+ return __smp_call_function_single(-1, func, info, mask, wait); - } - EXPORT_SYMBOL_GPL(smp_call_function_any); - -+static DEFINE_STATIC_KEY_FALSE(ipi_mask_inlined); -+ -+#ifdef CONFIG_PREEMPTION -+ -+int smp_task_ipi_mask_alloc(struct task_struct *task) -+{ -+ if (static_branch_unlikely(&ipi_mask_inlined)) -+ return 0; -+ -+ ACCESS_PRIVATE(task, ipi_mask).ipi_mask_ptr = -+ kmalloc(cpumask_size(), GFP_KERNEL); -+ if (!ACCESS_PRIVATE(task, ipi_mask).ipi_mask_ptr) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+void smp_task_ipi_mask_free(struct task_struct *task) -+{ -+ if (static_branch_unlikely(&ipi_mask_inlined)) -+ return; -+ -+ kfree(ACCESS_PRIVATE(task, ipi_mask).ipi_mask_ptr); -+} -+ -+static cpumask_t *smp_task_ipi_mask(struct task_struct *cur) -+{ -+ /* -+ * If cpumask_size() is smaller than or equal to the pointer -+ * size, it stashes the cpumask in the pointer itself to -+ * avoid extra memory allocations. -+ */ -+ if (static_branch_unlikely(&ipi_mask_inlined)) -+ return (cpumask_t *)&ACCESS_PRIVATE(cur, ipi_mask).ipi_mask_val; -+ -+ return ACCESS_PRIVATE(cur, ipi_mask).ipi_mask_ptr; -+} -+#else -+static cpumask_t *smp_task_ipi_mask(struct task_struct *cur) -+{ -+ return NULL; -+} -+#endif -+ - /* - * Flags to be used as scf_flags argument of smp_call_function_many_cond(). - * -@@ -817,13 +879,20 @@ static void smp_call_function_many_cond(const struct cpumask *mask, - unsigned int scf_flags, - smp_cond_func_t cond_func) - { -- int cpu, last_cpu, this_cpu = smp_processor_id(); -- struct call_function_data *cfd; -+ struct cpumask *cpumask, *task_mask; - bool wait = scf_flags & SCF_WAIT; -- int nr_cpus = 0; -+ struct call_function_data *cfd; -+ int cpu, last_cpu, this_cpu; - bool run_remote = false; -+ int nr_cpus = 0; - -- lockdep_assert_preemption_disabled(); -+ this_cpu = get_cpu(); -+ cfd = this_cpu_ptr(&cfd_data); -+ task_mask = smp_task_ipi_mask(current); -+ if (task_mask) -+ cpumask = task_mask; -+ else -+ cpumask = cfd->cpumask; - - /* - * Can deadlock when called with interrupts disabled. -@@ -845,16 +914,15 @@ static void smp_call_function_many_cond(const struct cpumask *mask, - - /* Check if we need remote execution, i.e., any CPU excluding this one. */ - if (cpumask_any_and_but(mask, cpu_online_mask, this_cpu) < nr_cpu_ids) { -- cfd = this_cpu_ptr(&cfd_data); -- cpumask_and(cfd->cpumask, mask, cpu_online_mask); -- __cpumask_clear_cpu(this_cpu, cfd->cpumask); -+ cpumask_and(cpumask, mask, cpu_online_mask); -+ __cpumask_clear_cpu(this_cpu, cpumask); - - cpumask_clear(cfd->cpumask_ipi); -- for_each_cpu(cpu, cfd->cpumask) { -+ for_each_cpu(cpu, cpumask) { - call_single_data_t *csd = per_cpu_ptr(cfd->csd, cpu); - - if (cond_func && !cond_func(cpu, info)) { -- __cpumask_clear_cpu(cpu, cfd->cpumask); -+ __cpumask_clear_cpu(cpu, cpumask); - continue; - } - -@@ -904,8 +972,18 @@ static void smp_call_function_many_cond(const struct cpumask *mask, - local_irq_restore(flags); - } - -+ /* -+ * The IPI work has been queued and dispatched. On PREEMPT kernels, -+ * tasks created through dup_task_struct() have task-local wait masks. -+ * The boot init_task can fall back to cfd->cpumask when the mask is -+ * not inlined, but other tasks still use task-local masks and cannot -+ * overwrite it. On !PREEMPT kernels, preempt_enable() cannot schedule -+ * another task, so the per-CPU mask remains protected. -+ */ -+ put_cpu(); -+ - if (run_remote && wait) { -- for_each_cpu(cpu, cfd->cpumask) { -+ for_each_cpu(cpu, cpumask) { - call_single_data_t *csd; - - csd = per_cpu_ptr(cfd->csd, cpu); -@@ -916,15 +994,14 @@ static void smp_call_function_many_cond(const struct cpumask *mask, - - /** - * smp_call_function_many() - Run a function on a set of CPUs. -- * @mask: The set of cpus to run on (only runs on online subset). -- * @func: The function to run. This must be fast and non-blocking. -- * @info: An arbitrary pointer to pass to the function. -- * @wait: If true, wait (atomically) until function has completed -- * on other CPUs. -+ * @mask: The set of cpus to run on (only runs on online subset). -+ * @func: The function to run. This must be fast and non-blocking. -+ * @info: An arbitrary pointer to pass to the function. -+ * @wait: If true, wait (atomically) until function has completed -+ * on other CPUs. - * - * You must not call this function with disabled interrupts or from a -- * hardware interrupt handler or from a bottom half handler. Preemption -- * must be disabled when calling this function. -+ * hardware interrupt handler or from a bottom half handler. - * - * @func is not called on the local CPU even if @mask contains it. Consider - * using on_each_cpu_cond_mask() instead if this is not desirable. -@@ -938,10 +1015,10 @@ EXPORT_SYMBOL(smp_call_function_many); - - /** - * smp_call_function() - Run a function on all other CPUs. -- * @func: The function to run. This must be fast and non-blocking. -- * @info: An arbitrary pointer to pass to the function. -- * @wait: If true, wait (atomically) until function has completed -- * on other CPUs. -+ * @func: The function to run. This must be fast and non-blocking. -+ * @info: An arbitrary pointer to pass to the function. -+ * @wait: If true, wait (atomically) until function has completed -+ * on other CPUs. - * - * If @wait is true, then returns once @func has returned; otherwise - * it returns just before the target cpu calls @func. -@@ -951,9 +1028,8 @@ EXPORT_SYMBOL(smp_call_function_many); - */ - void smp_call_function(smp_call_func_t func, void *info, int wait) - { -- preempt_disable(); -- smp_call_function_many(cpu_online_mask, func, info, wait); -- preempt_enable(); -+ smp_call_function_many_cond(cpu_online_mask, func, info, -+ wait ? SCF_WAIT : 0, NULL); - } - EXPORT_SYMBOL(smp_call_function); - -@@ -1019,6 +1095,9 @@ EXPORT_SYMBOL(nr_cpu_ids); - void __init setup_nr_cpu_ids(void) - { - set_nr_cpu_ids(find_last_bit(cpumask_bits(cpu_possible_mask), NR_CPUS) + 1); -+ -+ if (IS_ENABLED(CONFIG_PREEMPTION) && cpumask_size() <= sizeof(unsigned long)) -+ static_branch_enable(&ipi_mask_inlined); - } - - /* Called by boot processor to activate the rest. */ -@@ -1055,12 +1134,14 @@ void __init smp_init(void) - * @func: The function to run on all applicable CPUs. - * This must be fast and non-blocking. - * @info: An arbitrary pointer to pass to both functions. -- * @wait: If true, wait (atomically) until function has -- * completed on other CPUs. -+ * @wait: If true, wait until function has completed on other CPUs. - * @mask: The set of cpus to run on (only runs on online subset). - * -- * Preemption is disabled to protect against CPUs going offline but not online. -- * CPUs going online during the call will not be seen or sent an IPI. -+ * Target CPU selection and work queueing are done with preemption -+ * disabled. This protects against CPUs going offline, but not against -+ * CPUs coming online concurrently; newly online CPUs are not guaranteed -+ * to be seen or sent an IPI. If @wait is true, the final wait for remote -+ * completion happens after that preemption-disabled section. - * - * You must not call this function with disabled interrupts or - * from a hardware interrupt handler or from a bottom half handler. -@@ -1073,9 +1154,7 @@ void on_each_cpu_cond_mask(smp_cond_func_t cond_func, smp_call_func_t func, - if (wait) - scf_flags |= SCF_WAIT; - -- preempt_disable(); - smp_call_function_many_cond(mask, func, info, scf_flags, cond_func); -- preempt_enable(); - } - EXPORT_SYMBOL(on_each_cpu_cond_mask); - -diff --git a/kernel/up.c b/kernel/up.c ---- a/kernel/up.c -+++ b/kernel/up.c -@@ -9,8 +9,7 @@ - #include - #include - --int smp_call_function_single(int cpu, void (*func) (void *info), void *info, -- int wait) -+int smp_call_function_single(int cpu, void (*func)(void *info), void *info, bool wait) - { - unsigned long flags; - diff --git a/kernel/0121-smp-preempt.patch.sig b/kernel/0121-smp-preempt.patch.sig deleted file mode 100644 index 078bc77..0000000 Binary files a/kernel/0121-smp-preempt.patch.sig and /dev/null differ diff --git a/kernel/0130-sched-detach-tasks.patch b/kernel/0130-sched-detach-tasks.patch deleted file mode 100644 index 2e16e5f..0000000 --- a/kernel/0130-sched-detach-tasks.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -13476,12 +13476,15 @@ static int sched_balance_rq(int this_cpu, struct rq *this_rq, - * still unbalanced. ld_moved simply stays zero, so it is - * correctly treated as an imbalance. - */ -- env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running); -- - more_balance: - rq_lock_irqsave(busiest, &rf); - update_rq_clock(busiest); - -+ if (!env.loop_max) -+ env.loop_max = min(sysctl_sched_nr_migrate, busiest->cfs.h_nr_queued); -+ else -+ env.loop_max = min(env.loop_max, busiest->cfs.h_nr_queued); -+ - /* - * cur_ld_moved - load moved in current iteration - * ld_moved - cumulative load moved across iterations diff --git a/kernel/0130-sched-detach-tasks.patch.sig b/kernel/0130-sched-detach-tasks.patch.sig deleted file mode 100644 index dd5fd2d..0000000 Binary files a/kernel/0130-sched-detach-tasks.patch.sig and /dev/null differ diff --git a/kernel/0140-sched-always-inline.patch b/kernel/0140-sched-always-inline.patch deleted file mode 100644 index 745455c..0000000 --- a/kernel/0140-sched-always-inline.patch +++ /dev/null @@ -1,367 +0,0 @@ -diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h ---- a/arch/arm/include/asm/mmu_context.h -+++ b/arch/arm/include/asm/mmu_context.h -@@ -80,7 +80,7 @@ static inline void check_and_switch_context(struct mm_struct *mm, - #ifndef MODULE - #define finish_arch_post_lock_switch \ - finish_arch_post_lock_switch --static inline void finish_arch_post_lock_switch(void) -+static __always_inline void finish_arch_post_lock_switch(void) - { - struct mm_struct *mm = current->mm; - -diff --git a/arch/riscv/include/asm/sync_core.h b/arch/riscv/include/asm/sync_core.h ---- a/arch/riscv/include/asm/sync_core.h -+++ b/arch/riscv/include/asm/sync_core.h -@@ -6,7 +6,7 @@ - * RISC-V implements return to user-space through an xRET instruction, - * which is not core serializing. - */ --static inline void sync_core_before_usermode(void) -+static __always_inline void sync_core_before_usermode(void) - { - asm volatile ("fence.i" ::: "memory"); - } -diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h ---- a/arch/s390/include/asm/mmu_context.h -+++ b/arch/s390/include/asm/mmu_context.h -@@ -93,7 +93,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - } - - #define finish_arch_post_lock_switch finish_arch_post_lock_switch --static inline void finish_arch_post_lock_switch(void) -+static __always_inline void finish_arch_post_lock_switch(void) - { - struct task_struct *tsk = current; - struct mm_struct *mm = tsk->mm; -diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h ---- a/arch/sparc/include/asm/mmu_context_64.h -+++ b/arch/sparc/include/asm/mmu_context_64.h -@@ -160,7 +160,7 @@ static inline void arch_start_context_switch(struct task_struct *prev) - } - - #define finish_arch_post_lock_switch finish_arch_post_lock_switch --static inline void finish_arch_post_lock_switch(void) -+static __always_inline void finish_arch_post_lock_switch(void) - { - /* Restore the state of MCDPER register for the new process - * just switched to. -diff --git a/arch/x86/include/asm/sync_core.h b/arch/x86/include/asm/sync_core.h ---- a/arch/x86/include/asm/sync_core.h -+++ b/arch/x86/include/asm/sync_core.h -@@ -93,7 +93,7 @@ static __always_inline void sync_core(void) - * to user-mode. x86 implements return to user-space through sysexit, - * sysrel, and sysretq, which are not core serializing. - */ --static inline void sync_core_before_usermode(void) -+static __always_inline void sync_core_before_usermode(void) - { - /* With PTI, we unconditionally serialize before running user code. */ - if (static_cpu_has(X86_FEATURE_PTI)) -diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h ---- a/include/linux/perf_event.h -+++ b/include/linux/perf_event.h -@@ -1632,7 +1632,7 @@ static inline void perf_event_task_migrate(struct task_struct *task) - task->sched_migrated = 1; - } - --static inline void perf_event_task_sched_in(struct task_struct *prev, -+static __always_inline void perf_event_task_sched_in(struct task_struct *prev, - struct task_struct *task) - { - if (static_branch_unlikely(&perf_sched_events)) -diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h ---- a/include/linux/sched/mm.h -+++ b/include/linux/sched/mm.h -@@ -32,7 +32,7 @@ extern struct mm_struct *mm_alloc(void); - * See also for an in-depth explanation - * of &mm_struct.mm_count vs &mm_struct.mm_users. - */ --static inline void mmgrab(struct mm_struct *mm) -+static __always_inline void mmgrab(struct mm_struct *mm) - { - atomic_inc(&mm->mm_count); - } -@@ -44,7 +44,7 @@ static inline void smp_mb__after_mmgrab(void) - - extern void __mmdrop(struct mm_struct *mm); - --static inline void mmdrop(struct mm_struct *mm) -+static __always_inline void mmdrop(struct mm_struct *mm) - { - /* - * The implicit full barrier implied by atomic_dec_and_test() is -@@ -71,27 +71,27 @@ static inline void __mmdrop_delayed(struct rcu_head *rhp) - * Invoked from finish_task_switch(). Delegates the heavy lifting on RT - * kernels via RCU. - */ --static inline void mmdrop_sched(struct mm_struct *mm) -+static __always_inline void mmdrop_sched(struct mm_struct *mm) - { - /* Provides a full memory barrier. See mmdrop() */ - if (atomic_dec_and_test(&mm->mm_count)) - call_rcu(&mm->delayed_drop, __mmdrop_delayed); - } - #else --static inline void mmdrop_sched(struct mm_struct *mm) -+static __always_inline void mmdrop_sched(struct mm_struct *mm) - { - mmdrop(mm); - } - #endif - - /* Helpers for lazy TLB mm refcounting */ --static inline void mmgrab_lazy_tlb(struct mm_struct *mm) -+static __always_inline void mmgrab_lazy_tlb(struct mm_struct *mm) - { - if (IS_ENABLED(CONFIG_MMU_LAZY_TLB_REFCOUNT)) - mmgrab(mm); - } - --static inline void mmdrop_lazy_tlb(struct mm_struct *mm) -+static __always_inline void mmdrop_lazy_tlb(struct mm_struct *mm) - { - if (IS_ENABLED(CONFIG_MMU_LAZY_TLB_REFCOUNT)) { - mmdrop(mm); -@@ -104,7 +104,7 @@ static inline void mmdrop_lazy_tlb(struct mm_struct *mm) - } - } - --static inline void mmdrop_lazy_tlb_sched(struct mm_struct *mm) -+static __always_inline void mmdrop_lazy_tlb_sched(struct mm_struct *mm) - { - if (IS_ENABLED(CONFIG_MMU_LAZY_TLB_REFCOUNT)) - mmdrop_sched(mm); -@@ -128,12 +128,12 @@ static inline void mmdrop_lazy_tlb_sched(struct mm_struct *mm) - * See also for an in-depth explanation - * of &mm_struct.mm_count vs &mm_struct.mm_users. - */ --static inline void mmget(struct mm_struct *mm) -+static __always_inline void mmget(struct mm_struct *mm) - { - atomic_inc(&mm->mm_users); - } - --static inline bool mmget_not_zero(struct mm_struct *mm) -+static __always_inline bool mmget_not_zero(struct mm_struct *mm) - { - return atomic_inc_not_zero(&mm->mm_users); - } -@@ -532,7 +532,7 @@ enum { - #include - #endif - --static inline void membarrier_mm_sync_core_before_usermode(struct mm_struct *mm) -+static __always_inline void membarrier_mm_sync_core_before_usermode(struct mm_struct *mm) - { - /* - * The atomic_read() below prevents CSE. The following should -diff --git a/include/linux/tick.h b/include/linux/tick.h ---- a/include/linux/tick.h -+++ b/include/linux/tick.h -@@ -175,7 +175,7 @@ extern cpumask_var_t tick_nohz_full_mask; - #ifdef CONFIG_NO_HZ_FULL - extern bool tick_nohz_full_running; - --static inline bool tick_nohz_full_enabled(void) -+static __always_inline bool tick_nohz_full_enabled(void) - { - if (!context_tracking_enabled()) - return false; -@@ -299,7 +299,7 @@ static inline void __tick_nohz_task_switch(void) { } - static inline void tick_nohz_full_setup(cpumask_var_t cpumask) { } - #endif - --static inline void tick_nohz_task_switch(void) -+static __always_inline void tick_nohz_task_switch(void) - { - if (tick_nohz_full_enabled()) - __tick_nohz_task_switch(); -diff --git a/include/linux/vtime.h b/include/linux/vtime.h ---- a/include/linux/vtime.h -+++ b/include/linux/vtime.h -@@ -89,24 +89,24 @@ static __always_inline void vtime_account_guest_exit(void) - * For now vtime state is tied to context tracking. We might want to decouple - * those later if necessary. - */ --static inline bool vtime_accounting_enabled(void) -+static __always_inline bool vtime_accounting_enabled(void) - { - return context_tracking_enabled(); - } - --static inline bool vtime_accounting_enabled_cpu(int cpu) -+static __always_inline bool vtime_accounting_enabled_cpu(int cpu) - { - return vtime_generic_enabled_cpu(cpu); - } - --static inline bool vtime_accounting_enabled_this_cpu(void) -+static __always_inline bool vtime_accounting_enabled_this_cpu(void) - { - return vtime_generic_enabled_this_cpu(); - } - - extern void vtime_task_switch_generic(struct task_struct *prev); - --static inline void vtime_task_switch(struct task_struct *prev) -+static __always_inline void vtime_task_switch(struct task_struct *prev) - { - if (vtime_accounting_enabled_this_cpu()) - vtime_task_switch_generic(prev); -diff --git a/kernel/sched/core.c b/kernel/sched/core.c ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -5106,7 +5106,7 @@ static inline void prepare_task(struct task_struct *next) - WRITE_ONCE(next->on_cpu, 1); - } - --static inline void finish_task(struct task_struct *prev) -+static __always_inline void finish_task(struct task_struct *prev) - { - /* - * This must be the very last reference to @prev from this CPU. After -@@ -5150,7 +5150,7 @@ static void zap_balance_callbacks(struct rq *rq) - rq->balance_callback = found ? &balance_push_callback : NULL; - } - --static void do_balance_callbacks(struct rq *rq, struct balance_callback *head) -+static __always_inline void do_balance_callbacks(struct rq *rq, struct balance_callback *head) - { - void (*func)(struct rq *rq); - struct balance_callback *next; -@@ -5185,7 +5185,7 @@ struct balance_callback balance_push_callback = { - .func = balance_push, - }; - --static inline struct balance_callback * -+static __always_inline struct balance_callback * - __splice_balance_callbacks(struct rq *rq, bool split) - { - struct balance_callback *head = rq->balance_callback; -@@ -5259,7 +5259,7 @@ prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf - __acquire(__rq_lockp(this_rq())); - } - --static inline void finish_lock_switch(struct rq *rq) -+static __always_inline void finish_lock_switch(struct rq *rq) - __releases(__rq_lockp(rq)) - { - /* -@@ -5293,7 +5293,7 @@ static inline void kmap_local_sched_out(void) - #endif - } - --static inline void kmap_local_sched_in(void) -+static __always_inline void kmap_local_sched_in(void) - { - #ifdef CONFIG_KMAP_LOCAL - if (unlikely(current->kmap_ctrl.idx)) -@@ -5347,7 +5347,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, - * past. 'prev == current' is still correct but we need to recalculate this_rq - * because prev may have moved to another CPU. - */ --static struct rq *finish_task_switch(struct task_struct *prev) -+static __always_inline struct rq *finish_task_switch(struct task_struct *prev) - __releases(__rq_lockp(this_rq())) - { - struct rq *rq = this_rq(); -diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h ---- a/kernel/sched/sched.h -+++ b/kernel/sched/sched.h -@@ -1460,12 +1460,12 @@ static inline struct cpumask *sched_group_span(struct sched_group *sg); - - DECLARE_STATIC_KEY_FALSE(__sched_core_enabled); - --static inline bool sched_core_enabled(struct rq *rq) -+static __always_inline bool sched_core_enabled(struct rq *rq) - { - return static_branch_unlikely(&__sched_core_enabled) && rq->core_enabled; - } - --static inline bool sched_core_disabled(void) -+static __always_inline bool sched_core_disabled(void) - { - return !static_branch_unlikely(&__sched_core_enabled); - } -@@ -1474,7 +1474,7 @@ static inline bool sched_core_disabled(void) - * Be careful with this function; not for general use. The return value isn't - * stable unless you actually hold a relevant rq->__lock. - */ --static inline raw_spinlock_t *rq_lockp(struct rq *rq) -+static __always_inline raw_spinlock_t *rq_lockp(struct rq *rq) - { - if (sched_core_enabled(rq)) - return &rq->core->__lock; -@@ -1482,7 +1482,7 @@ static inline raw_spinlock_t *rq_lockp(struct rq *rq) - return &rq->__lock; - } - --static inline raw_spinlock_t *__rq_lockp(struct rq *rq) -+static __always_inline raw_spinlock_t *__rq_lockp(struct rq *rq) - __returns_ctx_lock(rq_lockp(rq)) /* alias them */ - { - if (rq->core_enabled) -@@ -1585,12 +1585,12 @@ static inline bool sched_core_disabled(void) - return true; - } - --static inline raw_spinlock_t *rq_lockp(struct rq *rq) -+static __always_inline raw_spinlock_t *rq_lockp(struct rq *rq) - { - return &rq->__lock; - } - --static inline raw_spinlock_t *__rq_lockp(struct rq *rq) -+static __always_inline raw_spinlock_t *__rq_lockp(struct rq *rq) - __returns_ctx_lock(rq_lockp(rq)) /* alias them */ - { - return &rq->__lock; -@@ -1650,33 +1650,33 @@ extern void raw_spin_rq_lock_nested(struct rq *rq, int subclass) - extern bool raw_spin_rq_trylock(struct rq *rq) - __cond_acquires(true, __rq_lockp(rq)); - --static inline void raw_spin_rq_lock(struct rq *rq) -+static __always_inline void raw_spin_rq_lock(struct rq *rq) - __acquires(__rq_lockp(rq)) - { - raw_spin_rq_lock_nested(rq, 0); - } - --static inline void raw_spin_rq_unlock(struct rq *rq) -+static __always_inline void raw_spin_rq_unlock(struct rq *rq) - __releases(__rq_lockp(rq)) - { - raw_spin_unlock(rq_lockp(rq)); - } - --static inline void raw_spin_rq_lock_irq(struct rq *rq) -+static __always_inline void raw_spin_rq_lock_irq(struct rq *rq) - __acquires(__rq_lockp(rq)) - { - local_irq_disable(); - raw_spin_rq_lock(rq); - } - --static inline void raw_spin_rq_unlock_irq(struct rq *rq) -+static __always_inline void raw_spin_rq_unlock_irq(struct rq *rq) - __releases(__rq_lockp(rq)) - { - raw_spin_rq_unlock(rq); - local_irq_enable(); - } - --static inline unsigned long _raw_spin_rq_lock_irqsave(struct rq *rq) -+static __always_inline unsigned long _raw_spin_rq_lock_irqsave(struct rq *rq) - __acquires(__rq_lockp(rq)) - { - unsigned long flags; -@@ -1687,7 +1687,7 @@ static inline unsigned long _raw_spin_rq_lock_irqsave(struct rq *rq) - return flags; - } - --static inline void raw_spin_rq_unlock_irqrestore(struct rq *rq, unsigned long flags) -+static __always_inline void raw_spin_rq_unlock_irqrestore(struct rq *rq, unsigned long flags) - __releases(__rq_lockp(rq)) - { - raw_spin_rq_unlock(rq); diff --git a/kernel/0140-sched-always-inline.patch.sig b/kernel/0140-sched-always-inline.patch.sig deleted file mode 100644 index b867df1..0000000 Binary files a/kernel/0140-sched-always-inline.patch.sig and /dev/null differ diff --git a/kernel/0141-sched-urgent-fixes.patch b/kernel/0141-sched-urgent-fixes.patch deleted file mode 100644 index cddb0d9..0000000 --- a/kernel/0141-sched-urgent-fixes.patch +++ /dev/null @@ -1,97 +0,0 @@ -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -10701,17 +10701,40 @@ static enum llc_mig can_migrate_llc(int src_cpu, int dst_cpu, - return mig_llc; - } - -+static inline bool task_misfits_asym_cpu(struct lb_env *env, struct task_struct *p) -+{ -+ /* -+ * On asymmetric CPU capacity domains, do not let cache-aware -+ * balancing pull the task onto a destination CPU that cannot -+ * accommodate it. Doing so would turn the task into a misfit on -+ * the destination, trading a cache-locality gain for a capacity -+ * loss. If the task already does not fit its source CPU, the move -+ * cannot make things worse, so let the LLC preference decide. -+ */ -+ if ((env->sd->flags & SD_ASYM_CPUCAPACITY) && p && -+ !task_fits_cpu(p, env->dst_cpu) && -+ task_fits_cpu(p, env->src_cpu)) -+ return true; -+ -+ return false; -+} -+ - /* - * Check if task p can migrate from source LLC to - * destination LLC in terms of cache aware load balance. - */ --static enum llc_mig can_migrate_llc_task(int src_cpu, int dst_cpu, -+static enum llc_mig can_migrate_llc_task(struct lb_env *env, - struct task_struct *p) - { - struct mm_struct *mm; - bool to_pref; -- int cpu; -+ int cpu, src_cpu, dst_cpu; - -+ if (task_misfits_asym_cpu(env, p)) -+ return mig_forbid; -+ -+ src_cpu = env->src_cpu; -+ dst_cpu = env->dst_cpu; - mm = p->mm; - if (!mm) - return mig_unrestricted; -@@ -10768,6 +10791,14 @@ alb_break_llc(struct lb_env *env) - unsigned long util = 0; - struct task_struct *cur; - -+ /* -+ * Migrating misfit tasks from current CPU -+ * to CPU with a better fit. -+ * Prioritize that over LLC preference. -+ */ -+ if (env->migration_type == migrate_misfit) -+ return false; -+ - if (env->src_rq->nr_running <= 1) - return true; - -@@ -10775,7 +10806,8 @@ alb_break_llc(struct lb_env *env) - if (cur && cur->sched_class == &fair_sched_class) - util = task_util(cur); - -- if (can_migrate_llc(env->src_cpu, env->dst_cpu, -+ if (task_misfits_asym_cpu(env, cur) || -+ can_migrate_llc(env->src_cpu, env->dst_cpu, - util, false) == mig_forbid) - return true; - } -@@ -10815,8 +10847,7 @@ static bool migrate_degrades_llc(struct task_struct *p, struct lb_env *env) - READ_ONCE(p->preferred_llc) != llc_id(env->dst_cpu)) - return true; - -- if (can_migrate_llc_task(env->src_cpu, -- env->dst_cpu, p) != mig_forbid) -+ if (can_migrate_llc_task(env, p) != mig_forbid) - return false; - - return true; -@@ -11879,6 +11910,15 @@ static inline bool llc_balance(struct lb_env *env, struct sg_lb_stats *sgs, - if (env->sd->flags & SD_SHARE_LLC) - return false; - -+ /* -+ * On asymmetric domains, group_misfit_task_load -+ * should be prioritized to move tasks to CPU that fit them -+ * over aggregating tasks to their preferred LLC. -+ */ -+ if ((env->sd->flags & SD_ASYM_CPUCAPACITY) && -+ sgs->group_misfit_task_load) -+ return false; -+ - /* - * Skip cache aware tagging if nr_balanced_failed is sufficiently high. - * Threshold of cache_nice_tries is set to 1 higher than nr_balance_failed diff --git a/kernel/0141-sched-urgent-fixes.patch.sig b/kernel/0141-sched-urgent-fixes.patch.sig deleted file mode 100644 index 81f23cb..0000000 Binary files a/kernel/0141-sched-urgent-fixes.patch.sig and /dev/null differ diff --git a/kernel/0143-sched-hybrid-cluster-balancing.patch b/kernel/0143-sched-hybrid-cluster-balancing.patch deleted file mode 100644 index 2131bc4..0000000 --- a/kernel/0143-sched-hybrid-cluster-balancing.patch +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/include/linux/sched/sd_flags.h b/include/linux/sched/sd_flags.h ---- a/include/linux/sched/sd_flags.h -+++ b/include/linux/sched/sd_flags.h -@@ -146,8 +146,7 @@ SD_FLAG(SD_ASYM_PACKING, SDF_NEEDS_GROUPS) - /* - * Prefer to place tasks in a sibling domain - * -- * Set up until domains start spanning NUMA nodes. Close to being a SHARED_CHILD -- * flag, but cleared below domains with SD_ASYM_CPUCAPACITY. -+ * Set up until domains start spanning NUMA nodes. - * - * NEEDS_GROUPS: Load balancing flag. - */ -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -12038,12 +12038,25 @@ static inline void update_sg_lb_stats(struct lb_env *env, - continue; - - if (sd_flags & SD_ASYM_CPUCAPACITY) { -- /* Check for a misfit task on the cpu */ -- if (sgs->group_misfit_task_load < rq->misfit_task_load) { -- sgs->group_misfit_task_load = rq->misfit_task_load; -- -+ if (rq->misfit_task_load) { -+ /* -+ * Always mark the root domain overloaded so big -+ * CPUs can pick up misfit tasks via newly idle -+ * balance. -+ */ - if (balancing_at_rd) - *sg_overloaded = 1; -+ -+ /* -+ * Only account misfit load if @dst_cpu can -+ * help; otherwise, the group may be classified -+ * as misfit_task and update_sd_pick_busiest() -+ * will skip it. -+ */ -+ if (capacity_greater(capacity_of(env->dst_cpu), -+ group->sgc->max_capacity) && -+ (sgs->group_misfit_task_load < rq->misfit_task_load)) -+ sgs->group_misfit_task_load = rq->misfit_task_load; - } - } else if (env->idle && sched_reduced_capacity(rq, env->sd)) { - /* Check for a task running on a CPU with reduced capacity */ -@@ -13156,9 +13169,24 @@ static struct rq *sched_balance_find_src_rq(struct lb_env *env, - * average load. - */ - if (env->sd->flags & SD_ASYM_CPUCAPACITY && -- !capacity_greater(capacity_of(env->dst_cpu), capacity) && -- nr_running == 1) -- continue; -+ nr_running == 1) { -+ bool cluster_equal_cap = static_branch_unlikely(&sched_cluster_active) && -+ (get_actual_cpu_capacity(env->dst_cpu) == -+ get_actual_cpu_capacity(i)); -+ bool smt_degraded_cap = sched_smt_active() && !is_core_idle(i); -+ -+ /* -+ * Busy SMT siblings reduce the capacity of CPU @i. Do -+ * not skip it in this case. -+ * -+ * CONFIG_SCHED_CLUSTER requires balancing load across -+ * clusters of identical capacity, accounting for -+ * hardware and cpufreq pressure. -+ */ -+ if (!smt_degraded_cap && !cluster_equal_cap && -+ !capacity_greater(capacity_of(env->dst_cpu), capacity)) -+ continue; -+ } - - /* - * Make sure we only pull tasks from a CPU of lower priority -diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c ---- a/kernel/sched/topology.c -+++ b/kernel/sched/topology.c -@@ -1995,10 +1995,6 @@ sd_init(struct sched_domain_topology_level *tl, - /* - * Convert topological properties into behaviour. - */ -- /* Don't attempt to spread across CPUs of different capacities. */ -- if ((sd->flags & SD_ASYM_CPUCAPACITY) && sd->child) -- sd->child->flags &= ~SD_PREFER_SIBLING; -- - if (sd->flags & SD_SHARE_CPUCAPACITY) { - sd->imbalance_pct = 110; - diff --git a/kernel/0143-sched-hybrid-cluster-balancing.patch.sig b/kernel/0143-sched-hybrid-cluster-balancing.patch.sig deleted file mode 100644 index 7ca830c..0000000 Binary files a/kernel/0143-sched-hybrid-cluster-balancing.patch.sig and /dev/null differ diff --git a/kernel/0144-sched-nohz-idle-core.patch b/kernel/0144-sched-nohz-idle-core.patch deleted file mode 100644 index 7a22780..0000000 --- a/kernel/0144-sched-nohz-idle-core.patch +++ /dev/null @@ -1,77 +0,0 @@ -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -14060,29 +14060,62 @@ static inline int on_null_domain(struct rq *rq) - */ - static inline int find_new_ilb(void) - { -- int this_cpu = smp_processor_id(); -- const struct cpumask *hk_mask; -- int ilb_cpu; -+ struct cpumask *ilb_cpus; -+ int ilb_cpu, fallback = -1; - -- hk_mask = housekeeping_cpumask(HK_TYPE_KERNEL_NOISE); -+ lockdep_assert_irqs_disabled(); - -- for_each_cpu_and(ilb_cpu, nohz.idle_cpus_mask, hk_mask) { -- if (ilb_cpu == this_cpu) -+ /* -+ * Reuse the per-CPU select_rq_mask, which is protected from concurrent -+ * use on this CPU by having interrupts disabled. -+ */ -+ ilb_cpus = this_cpu_cpumask_var_ptr(select_rq_mask); -+ cpumask_and(ilb_cpus, nohz.idle_cpus_mask, -+ housekeeping_cpumask(HK_TYPE_KERNEL_NOISE)); -+ -+ for_each_cpu(ilb_cpu, ilb_cpus) { -+ if (!idle_cpu(ilb_cpu)) { -+ /* -+ * Once an idle fallback exists, a busy CPU proves that -+ * this core cannot be fully idle. Skip its siblings. -+ */ -+ if (sched_smt_active() && fallback >= 0) -+ cpumask_andnot(ilb_cpus, ilb_cpus, cpu_smt_mask(ilb_cpu)); - continue; -+ } - -- if (idle_cpu(ilb_cpu)) -- return ilb_cpu; -+ /* -+ * Running the idle load balancer on an idle sibling of a busy -+ * SMT core can reduce the capacity available to its sibling. Prefer -+ * a CPU whose entire core is idle, but retain the first idle CPU as -+ * a fallback so idle balancing can still make progress when no fully -+ * idle core exists. -+ */ -+ if (sched_smt_active() && !is_core_idle(ilb_cpu)) { -+ if (fallback < 0) -+ fallback = ilb_cpu; -+ -+ /* -+ * The core is not idle, so there is no need to check -+ * any of its other SMT siblings. -+ */ -+ cpumask_andnot(ilb_cpus, ilb_cpus, -+ cpu_smt_mask(ilb_cpu)); -+ continue; -+ } -+ -+ return ilb_cpu; - } - -- return -1; -+ return fallback; - } - - /* - * Kick a CPU to do the NOHZ balancing, if it is time for it, via a cross-CPU - * SMP function call (IPI). - * -- * We pick the first idle CPU in the HK_TYPE_KERNEL_NOISE housekeeping set -- * (if there is one). -+ * Prefer a CPU on a fully idle core in the HK_TYPE_KERNEL_NOISE housekeeping -+ * set. Fall back to the first idle CPU when no fully idle core exists. - */ - static void kick_ilb(unsigned int flags) - { diff --git a/kernel/0144-sched-nohz-idle-core.patch.sig b/kernel/0144-sched-nohz-idle-core.patch.sig deleted file mode 100644 index d956e49..0000000 Binary files a/kernel/0144-sched-nohz-idle-core.patch.sig and /dev/null differ diff --git a/kernel/0150-adios-3.2.0.patch b/kernel/0150-adios-3.2.0.patch deleted file mode 100644 index 7d0ef21..0000000 --- a/kernel/0150-adios-3.2.0.patch +++ /dev/null @@ -1,2154 +0,0 @@ -diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched -index 27f11320b8d1..e98585dd83e0 100644 ---- a/block/Kconfig.iosched -+++ b/block/Kconfig.iosched -@@ -16,6 +16,20 @@ config MQ_IOSCHED_KYBER - synchronous writes, it will self-tune queue depths to achieve that - goal. - -+config MQ_IOSCHED_ADIOS -+ tristate "Adaptive Deadline I/O scheduler" -+ default m -+ help -+ The Adaptive Deadline I/O Scheduler (ADIOS) is a multi-queue I/O -+ scheduler with learning-based adaptive latency control. -+ -+config MQ_IOSCHED_DEFAULT_ADIOS -+ bool "Enable ADIOS I/O scheduler as default MQ I/O scheduler" -+ depends on MQ_IOSCHED_ADIOS=y -+ default n -+ help -+ Enable the ADIOS I/O scheduler as the default scheduler for MQ I/O. -+ - config IOSCHED_BFQ - tristate "BFQ I/O scheduler" - select BLK_ICQ -diff --git a/block/Makefile b/block/Makefile -index e7bd320e3d69..5523e5f62f92 100644 ---- a/block/Makefile -+++ b/block/Makefile -@@ -25,6 +25,7 @@ obj-$(CONFIG_BLK_CGROUP_IOLATENCY) += blk-iolatency.o - obj-$(CONFIG_BLK_CGROUP_IOCOST) += blk-iocost.o - obj-$(CONFIG_MQ_IOSCHED_DEADLINE) += mq-deadline.o - obj-$(CONFIG_MQ_IOSCHED_KYBER) += kyber-iosched.o -+obj-$(CONFIG_MQ_IOSCHED_ADIOS) += adios.o - bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o - obj-$(CONFIG_IOSCHED_BFQ) += bfq.o - -@@ -39,3 +40,10 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \ - blk-crypto-sysfs.o - obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o - obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o -+ -+all: -+ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules -+ -+clean: -+ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean -+ -diff --git a/block/adios.c b/block/adios.c -new file mode 100644 -index 000000000000..c7f380bb65dd ---- /dev/null -+++ b/block/adios.c -@@ -0,0 +1,2062 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Adaptive Deadline I/O Scheduler (ADIOS) -+ * Copyright (C) 2025 Masahito Suzuki -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "elevator.h" -+#include "blk.h" -+#include "blk-mq.h" -+#include "blk-mq-sched.h" -+ -+#define ADIOS_VERSION "3.2.0" -+ -+/* Request Types: -+ * -+ * Tier 0 (Highest Priority): Emergency & System Integrity Requests -+ * ----------------------------------------------------------------- -+ * - Target: Requests with the BLK_MQ_INSERT_AT_HEAD flag. -+ * - Purpose: For critical, non-negotiable operations such as device error -+ * recovery or flush sequences that must bypass all other scheduling logic. -+ * - Implementation: Placed in a dedicated, high-priority FIFO queue -+ * (`prio_queue[0]`) for immediate dispatch. -+ * -+ * Tier 1 (High Priority): I/O Barrier Guarantees -+ * --------------------------------------------------------------- -+ * - Target: Requests with the REQ_OP_FLUSH flag. -+ * - Purpose: To enforce a strict I/O barrier. When a flush request is -+ * received, the scheduler stops processing new requests from its main -+ * queues until all preceding requests have been completed. This guarantees -+ * the order of operations required by filesystems for data integrity. -+ * - Implementation: A state flag (ADIOS_STATE_BARRIER) halts -+ * insertion into the main deadline tree. The barrier request and all -+ * subsequent requests are held in a temporary `barrier_queue`. Once the -+ * main queues are drained, the barrier request and the subsequent requests -+ * are released from the pending queue back into the scheduler. -+ * -+ * Tier 2 (Medium Priority): Application Responsiveness -+ * ---------------------------------------------------- -+ * - Target: Normal synchronous requests (e.g., from standard file reads). -+ * - Purpose: To ensure correct application behavior for operations that -+ * depend on sequential I/O completion (e.g., file system mounts) and to -+ * provide low latency for interactive applications. -+ * - Implementation: The deadline for these requests is set to their start -+ * time (`rq->start_time_ns`). This effectively enforces FIFO-like behavior -+ * within the deadline-sorted red-black tree, preventing out-of-order -+ * execution of dependent synchronous operations. -+ * -+ * Tier 3 (Normal Priority): Background Throughput -+ * ----------------------------------------------- -+ * - Target: Asynchronous requests. -+ * - Purpose: To maximize disk throughput for background tasks where latency -+ * is not critical. -+ * - Implementation: These are the only requests where ADIOS's adaptive -+ * latency prediction model is used. A dynamic deadline is calculated based -+ * on the predicted I/O latency, allowing for aggressive reordering to -+ * optimize I/O efficiency. -+ * -+ * Dispatch Logic: -+ * The scheduler always dispatches requests in strict priority order: -+ * 1. prio_queue[0] (Tier 0) -+ * 2. The deadline-sorted batch queue (which naturally prioritizes Tier 2 -+ * over Tier 3 due to their calculated deadlines). -+ * 3. Barrier-pending requests are handled only after the main queues are empty. -+ */ -+ -+// Global variable to control the latency -+static u64 default_global_latency_window = 16000000ULL; -+static u64 default_global_latency_window_rotational = 22000000ULL; -+// Ratio below which batch queues should be refilled -+static u8 default_bq_refill_below_ratio = 20; -+// Maximum latency sample to input -+static u64 default_lat_model_latency_limit = 500 * NSEC_PER_MSEC; -+// Batch ordering strategy -+static u64 default_batch_order = 0; -+ -+/* Compliance Flags: -+ * 0x1: Async requests will not be reordered based on the predicted latency -+ */ -+enum adios_compliance_flags { -+ ADIOS_CF_FIXORDER = 1U << 0, -+}; -+ -+// Flags to control compliance with block layer constraints -+static u64 default_compliance_flags = 0x0; -+ -+// Dynamic thresholds for shrinkage -+static u32 default_lm_shrink_at_kreqs = 5000; -+static u32 default_lm_shrink_at_gbytes = 50; -+static u32 default_lm_shrink_resist = 2; -+ -+enum adios_optype { -+ ADIOS_READ = 0, -+ ADIOS_WRITE = 1, -+ ADIOS_DISCARD = 2, -+ ADIOS_OTHER = 3, -+ ADIOS_OPTYPES = 4, -+}; -+ -+// Latency targets for each operation type -+static u64 default_latency_target[ADIOS_OPTYPES] = { -+ [ADIOS_READ] = 2ULL * NSEC_PER_MSEC, -+ [ADIOS_WRITE] = 2000ULL * NSEC_PER_MSEC, -+ [ADIOS_DISCARD] = 8000ULL * NSEC_PER_MSEC, -+ [ADIOS_OTHER] = 0ULL * NSEC_PER_MSEC, -+}; -+ -+// Maximum batch size limits for each operation type -+static u32 default_batch_limit[ADIOS_OPTYPES] = { -+ [ADIOS_READ] = 36, -+ [ADIOS_WRITE] = 72, -+ [ADIOS_DISCARD] = 1, -+ [ADIOS_OTHER] = 1, -+}; -+ -+enum adios_batch_order { -+ ADIOS_BO_OPTYPE = 0, -+ ADIOS_BO_ELEVATOR = 1, -+}; -+ -+// Thresholds for latency model control -+#define LM_BLOCK_SIZE_THRESHOLD 4096 -+#define LM_SAMPLES_THRESHOLD 1024 -+#define LM_INTERVAL_THRESHOLD 1500 -+#define LM_OUTLIER_PERCENTILE 99 -+#define LM_LAT_BUCKET_COUNT 64 -+ -+#define ADIOS_PQ_LEVELS 2 -+#define ADIOS_DL_TYPES 2 -+#define ADIOS_BQ_PAGES 2 -+ -+static u32 default_dl_prio[ADIOS_DL_TYPES] = {8, 0}; -+ -+// Bit flags for the atomic state variable, indicating which queues have requests. -+enum adios_state_flags { -+ ADIOS_STATE_PQ_0 = 1U << 0, -+ ADIOS_STATE_PQ_1 = 1U << 1, -+ ADIOS_STATE_DL_0 = 1U << 2, -+ ADIOS_STATE_DL_1 = 1U << 3, -+ ADIOS_STATE_BQ_PAGE_0 = 1U << 4, -+ ADIOS_STATE_BQ_PAGE_1 = 1U << 5, -+ ADIOS_STATE_BARRIER = 1U << 6, -+}; -+#define ADIOS_STATE_PQ 0 -+#define ADIOS_STATE_DL 2 -+#define ADIOS_STATE_BQ 4 -+#define ADIOS_STATE_BP 6 -+ -+// Temporal granularity of the deadline tree node (dl_group) -+#define ADIOS_QUANTUM_SHIFT 20 -+ -+#define ADIOS_MAX_INSERTS_PER_LOCK 72 -+#define ADIOS_MAX_DELETES_PER_LOCK 24 -+ -+// Structure to hold latency bucket data for small requests -+struct latency_bucket_small { -+ u64 weighted_sum_latency; -+ u64 sum_of_weights; -+}; -+ -+// Structure to hold latency bucket data for large requests -+struct latency_bucket_large { -+ u64 weighted_sum_latency; -+ u64 weighted_sum_block_size; -+ u64 sum_of_weights; -+}; -+ -+// Structure to hold per-cpu buckets, improving data locality and code clarity. -+struct lm_buckets { -+ struct latency_bucket_small small_bucket[LM_LAT_BUCKET_COUNT]; -+ struct latency_bucket_large large_bucket[LM_LAT_BUCKET_COUNT]; -+}; -+ -+// Structure to hold RCU-protected latency model parameters -+struct latency_model_params { -+ u64 base; -+ u64 slope; -+ u64 small_sum_delay; -+ u64 small_count; -+ u64 large_sum_delay; -+ u64 large_sum_bsize; -+ u64 last_update_jiffies; -+ struct rcu_head rcu; -+}; -+ -+// Structure to hold the latency model context data -+struct latency_model { -+ spinlock_t update_lock; -+ struct latency_model_params __rcu *params; -+ -+ // Per-CPU buckets to avoid lock contention on the completion path -+ struct lm_buckets __percpu *pcpu_buckets; -+ // Per-CPU snapshots for delta-based aggregation (accessed under update_lock) -+ struct lm_buckets __percpu *pcpu_snapshot; -+ -+ u32 lm_shrink_at_kreqs; -+ u32 lm_shrink_at_gbytes; -+ u8 lm_shrink_resist; -+}; -+ -+struct adios_pcpu_completion { -+ u64 last_completed_time; -+ sector_t last_completed_pos; -+}; -+ -+union adios_in_flight_rqs { -+ atomic64_t atomic; -+ u64 scalar; -+ struct { -+ u64 count: 16; -+ u64 total_pred_lat: 48; -+ }; -+}; -+ -+// Adios scheduler data -+struct adios_data { -+ spinlock_t pq_lock; -+ struct list_head prio_queue[2]; -+ -+ struct rb_root_cached dl_tree[2]; -+ spinlock_t lock; -+ s64 dl_bias; -+ s32 dl_prio[2]; -+ -+ atomic_t state; -+ u8 bq_state[ADIOS_BQ_PAGES]; -+ -+ bool models_stable; -+ -+ u64 global_latency_window; -+ u64 compliance_flags; -+ u64 latency_target[ADIOS_OPTYPES]; -+ u32 batch_limit[ADIOS_OPTYPES]; -+ u32 batch_actual_max_size[ADIOS_OPTYPES]; -+ u32 batch_actual_max_total; -+ u32 async_depth; -+ u32 lat_model_latency_limit; -+ u8 bq_refill_below_ratio; -+ u8 is_rotational; -+ u8 batch_order; -+ u8 elv_direction; -+ sector_t head_pos; -+ -+ bool bq_page; -+ struct list_head batch_queue[ADIOS_BQ_PAGES][ADIOS_OPTYPES]; -+ u32 batch_count[ADIOS_BQ_PAGES][ADIOS_OPTYPES]; -+ u8 bq_batch_order[ADIOS_BQ_PAGES]; -+ spinlock_t bq_lock; -+ spinlock_t barrier_lock; -+ struct list_head barrier_queue; -+ -+ struct lm_buckets *aggr_buckets; -+ -+ struct latency_model latency_model[ADIOS_OPTYPES]; -+ struct timer_list update_timer; -+ -+ union adios_in_flight_rqs in_flight_rqs; -+ atomic64_t total_pred_lat; -+ -+ struct adios_pcpu_completion __percpu *pcpu_completion; -+ -+ struct kmem_cache *rq_data_cache; -+ mempool_t *rq_data_pool; -+ struct kmem_cache *dl_group_pool; -+ -+ struct request_queue *queue; -+}; -+ -+// List of requests with the same deadline in the deadline-sorted tree -+struct dl_group { -+ struct rb_node node; -+ struct list_head rqs; -+ u64 deadline; -+} __attribute__((aligned(64))); -+ -+// Structure to hold scheduler-specific data for each request -+struct adios_rq_data { -+ struct list_head *dl_group; -+ struct list_head dl_node; -+ -+ struct request *rq; -+ u64 deadline; -+ u64 pred_lat; -+ u32 block_size; -+ bool managed; -+} __attribute__((aligned(64))); -+ -+static const int adios_prio_to_wmult[40] = { -+ /* -20 */ 88761, 71755, 56483, 46273, 36291, -+ /* -15 */ 29154, 23254, 18705, 14949, 11916, -+ /* -10 */ 9548, 7620, 6100, 4904, 3906, -+ /* -5 */ 3121, 2501, 1991, 1586, 1277, -+ /* 0 */ 1024, 820, 655, 526, 423, -+ /* 5 */ 335, 272, 215, 172, 137, -+ /* 10 */ 110, 87, 70, 56, 45, -+ /* 15 */ 36, 29, 23, 18, 15, -+}; -+ -+static inline bool compliant(struct adios_data *ad, u32 flag) { -+ return ad->compliance_flags & flag; -+} -+ -+// Count the number of entries in aggregated small buckets -+static u64 lm_count_small_entries(struct latency_bucket_small *buckets) { -+ u64 total_weight = 0; -+ for (u8 i = 0; i < LM_LAT_BUCKET_COUNT; i++) -+ total_weight += buckets[i].sum_of_weights; -+ return total_weight; -+} -+ -+// Update the small buckets in the latency model from aggregated data -+static bool lm_update_small_buckets(struct latency_model *model, -+ struct latency_model_params *params, -+ struct latency_bucket_small *buckets, -+ u64 total_weight, bool count_all) { -+ u64 sum_latency = 0; -+ u64 sum_weight = 0; -+ u64 cumulative_weight = 0, threshold_weight = 0; -+ u8 outlier_threshold_bucket = 0; -+ u8 outlier_percentile = LM_OUTLIER_PERCENTILE; -+ u8 reduction; -+ -+ if (count_all) -+ outlier_percentile = 100; -+ -+ // Calculate the threshold weight for outlier detection -+ threshold_weight = (total_weight * outlier_percentile) / 100; -+ -+ // Identify the bucket that corresponds to the outlier threshold -+ for (u8 i = 0; i < LM_LAT_BUCKET_COUNT; i++) { -+ cumulative_weight += buckets[i].sum_of_weights; -+ if (cumulative_weight >= threshold_weight) { -+ outlier_threshold_bucket = i; -+ break; -+ } -+ } -+ -+ // Calculate the average latency, excluding outliers -+ for (u8 i = 0; i <= outlier_threshold_bucket; i++) { -+ struct latency_bucket_small *bucket = &buckets[i]; -+ if (i < outlier_threshold_bucket) { -+ sum_latency += bucket->weighted_sum_latency; -+ sum_weight += bucket->sum_of_weights; -+ } else { -+ // The threshold bucket's contribution is proportional -+ u64 remaining_weight = -+ threshold_weight - (cumulative_weight - bucket->sum_of_weights); -+ if (bucket->sum_of_weights > 0) { -+ sum_latency += div_u64(bucket->weighted_sum_latency * -+ remaining_weight, bucket->sum_of_weights); -+ sum_weight += remaining_weight; -+ } -+ } -+ } -+ -+ // Shrink the model if it reaches at the readjustment threshold -+ if (params->small_count >= 1000ULL * model->lm_shrink_at_kreqs) { -+ reduction = model->lm_shrink_resist; -+ if (params->small_count >> reduction) { -+ params->small_sum_delay -= params->small_sum_delay >> reduction; -+ params->small_count -= params->small_count >> reduction; -+ } -+ } -+ -+ if (!sum_weight) -+ return false; -+ -+ // Accumulate the average latency into the statistics -+ params->small_sum_delay += sum_latency; -+ params->small_count += sum_weight; -+ -+ return true; -+} -+ -+// Count the number of entries in aggregated large buckets -+static u64 lm_count_large_entries(struct latency_bucket_large *buckets) { -+ u64 total_weight = 0; -+ for (u8 i = 0; i < LM_LAT_BUCKET_COUNT; i++) -+ total_weight += buckets[i].sum_of_weights; -+ return total_weight; -+} -+ -+// Update the large buckets in the latency model from aggregated data -+static bool lm_update_large_buckets(struct latency_model *model, -+ struct latency_model_params *params, -+ struct latency_bucket_large *buckets, -+ u64 total_weight, bool count_all) { -+ s64 sum_latency = 0; -+ u64 sum_block_size = 0, intercept; -+ u64 cumulative_weight = 0, threshold_weight = 0; -+ u64 sum_weight = 0; -+ u8 outlier_threshold_bucket = 0; -+ u8 outlier_percentile = LM_OUTLIER_PERCENTILE; -+ u8 reduction; -+ -+ if (count_all) -+ outlier_percentile = 100; -+ -+ // Calculate the threshold weight for outlier detection -+ threshold_weight = (total_weight * outlier_percentile) / 100; -+ -+ // Identify the bucket that corresponds to the outlier threshold -+ for (u8 i = 0; i < LM_LAT_BUCKET_COUNT; i++) { -+ cumulative_weight += buckets[i].sum_of_weights; -+ if (cumulative_weight >= threshold_weight) { -+ outlier_threshold_bucket = i; -+ break; -+ } -+ } -+ -+ // Calculate the average latency and block size, excluding outliers -+ for (u8 i = 0; i <= outlier_threshold_bucket; i++) { -+ struct latency_bucket_large *bucket = &buckets[i]; -+ if (i < outlier_threshold_bucket) { -+ sum_latency += bucket->weighted_sum_latency; -+ sum_block_size += bucket->weighted_sum_block_size; -+ sum_weight += bucket->sum_of_weights; -+ } else { -+ // The threshold bucket's contribution is proportional -+ u64 remaining_weight = -+ threshold_weight - (cumulative_weight - bucket->sum_of_weights); -+ if (bucket->sum_of_weights > 0) { -+ sum_latency += div_u64(bucket->weighted_sum_latency * -+ remaining_weight, bucket->sum_of_weights); -+ sum_block_size += div_u64(bucket->weighted_sum_block_size * -+ remaining_weight, bucket->sum_of_weights); -+ sum_weight += remaining_weight; -+ } -+ } -+ } -+ -+ if (!sum_weight) -+ return false; -+ -+ // Shrink the model if it reaches at the readjustment threshold -+ if (params->large_sum_bsize >= 0x40000000ULL * model->lm_shrink_at_gbytes) { -+ reduction = model->lm_shrink_resist; -+ if (params->large_sum_bsize >> reduction) { -+ params->large_sum_delay -= params->large_sum_delay >> reduction; -+ params->large_sum_bsize -= params->large_sum_bsize >> reduction; -+ } -+ } -+ -+ // Accumulate the average delay into the statistics -+ intercept = params->base; -+ if (sum_latency > intercept) -+ sum_latency -= intercept; -+ -+ params->large_sum_delay += sum_latency; -+ params->large_sum_bsize += sum_block_size; -+ -+ return true; -+} -+ -+static void reset_buckets(struct lm_buckets *buckets) -+{ memset(buckets, 0, sizeof(*buckets)); } -+ -+static void lm_reset_pcpu_buckets(struct latency_model *model) { -+ int cpu; -+ for_each_possible_cpu(cpu) { -+ reset_buckets(per_cpu_ptr(model->pcpu_buckets, cpu)); -+ reset_buckets(per_cpu_ptr(model->pcpu_snapshot, cpu)); -+ } -+} -+ -+// Update the latency model parameters and statistics -+static void latency_model_update( -+ struct adios_data *ad, struct latency_model *model) { -+ u64 now; -+ u64 small_weight, large_weight; -+ bool time_elapsed; -+ bool small_processed = false, large_processed = false; -+ struct lm_buckets *aggr = ad->aggr_buckets; -+ struct latency_bucket_small *asb; -+ struct latency_bucket_large *alb; -+ struct lm_buckets *pcpu_b, *snap; -+ unsigned long flags; -+ int cpu; -+ struct latency_model_params *old_params, *new_params; -+ -+ spin_lock_irqsave(&model->update_lock, flags); -+ -+ old_params = rcu_dereference_protected(model->params, -+ lockdep_is_held(&model->update_lock)); -+ new_params = kmemdup(old_params, sizeof(*new_params), GFP_ATOMIC); -+ if (!new_params) { -+ spin_unlock_irqrestore(&model->update_lock, flags); -+ return; -+ } -+ -+ // Aggregate deltas from all CPUs using snapshot-delta method. -+ // Per-CPU counters increase monotonically; we compute delta = current - snapshot. -+ for_each_possible_cpu(cpu) { -+ pcpu_b = per_cpu_ptr(model->pcpu_buckets, cpu); -+ snap = per_cpu_ptr(model->pcpu_snapshot, cpu); -+ -+ for (u8 i = 0; i < LM_LAT_BUCKET_COUNT; i++) { -+ u64 sw = pcpu_b->small_bucket[i].sum_of_weights; -+ u64 sl = pcpu_b->small_bucket[i].weighted_sum_latency; -+ u64 dsw = sw - snap->small_bucket[i].sum_of_weights; -+ u64 dsl = sl - snap->small_bucket[i].weighted_sum_latency; -+ snap->small_bucket[i].sum_of_weights = sw; -+ snap->small_bucket[i].weighted_sum_latency = sl; -+ if (dsw) { -+ asb = &aggr->small_bucket[i]; -+ asb->sum_of_weights += dsw; -+ asb->weighted_sum_latency += dsl; -+ } -+ -+ u64 lw = pcpu_b->large_bucket[i].sum_of_weights; -+ u64 ll = pcpu_b->large_bucket[i].weighted_sum_latency; -+ u64 lb = pcpu_b->large_bucket[i].weighted_sum_block_size; -+ u64 dlw = lw - snap->large_bucket[i].sum_of_weights; -+ u64 dll = ll - snap->large_bucket[i].weighted_sum_latency; -+ u64 dlb = lb - snap->large_bucket[i].weighted_sum_block_size; -+ snap->large_bucket[i].sum_of_weights = lw; -+ snap->large_bucket[i].weighted_sum_latency = ll; -+ snap->large_bucket[i].weighted_sum_block_size = lb; -+ if (dlw) { -+ alb = &aggr->large_bucket[i]; -+ alb->sum_of_weights += dlw; -+ alb->weighted_sum_latency += dll; -+ alb->weighted_sum_block_size += dlb; -+ } -+ } -+ } -+ -+ // Count the number of entries in aggregated buckets -+ small_weight = lm_count_small_entries(aggr->small_bucket); -+ large_weight = lm_count_large_entries(aggr->large_bucket); -+ -+ // Whether enough time has elapsed since the last update -+ now = jiffies; -+ time_elapsed = unlikely(!new_params->base) || -+ new_params->last_update_jiffies + -+ msecs_to_jiffies(LM_INTERVAL_THRESHOLD) <= now; -+ -+ // Update small buckets -+ if (small_weight && (time_elapsed || -+ LM_SAMPLES_THRESHOLD <= small_weight || !new_params->base)) { -+ small_processed = lm_update_small_buckets(model, new_params, -+ aggr->small_bucket, small_weight, !new_params->base); -+ memset(&aggr->small_bucket[0], 0, sizeof(aggr->small_bucket)); -+ } -+ // Update large buckets -+ if (large_weight && (time_elapsed || -+ LM_SAMPLES_THRESHOLD <= large_weight || !new_params->slope)) { -+ large_processed = lm_update_large_buckets(model, new_params, -+ aggr->large_bucket, large_weight, !new_params->slope); -+ memset(&aggr->large_bucket[0], 0, sizeof(aggr->large_bucket)); -+ } -+ -+ // Update the base parameter if small bucket was processed -+ if (small_processed && likely(new_params->small_count)) -+ new_params->base = div_u64(new_params->small_sum_delay, -+ new_params->small_count); -+ -+ // Update the slope parameter if large bucket was processed -+ if (large_processed && likely(new_params->large_sum_bsize)) -+ new_params->slope = div_u64(new_params->large_sum_delay, -+ DIV_ROUND_UP_ULL(new_params->large_sum_bsize, 1024)); -+ -+ // Update last updated jiffies if update happened or time has elapsed -+ if (small_processed || large_processed || time_elapsed) -+ new_params->last_update_jiffies = now; -+ -+ rcu_assign_pointer(model->params, new_params); -+ spin_unlock_irqrestore(&model->update_lock, flags); -+ -+ kfree_rcu(old_params, rcu); -+} -+ -+// Determine the bucket index for a given measured and predicted latency -+static u8 lm_input_bucket_index(u64 measured, u64 predicted) { -+ u32 bucket_index; -+ -+ if (measured < predicted * 2) -+ bucket_index = div_u64((measured * 20), predicted); -+ else if (measured < predicted * 5) -+ bucket_index = div_u64((measured * 10), predicted) + 20; -+ else -+ bucket_index = div_u64((measured * 3), predicted) + 40; -+ -+ if (bucket_index >= LM_LAT_BUCKET_COUNT) -+ bucket_index = LM_LAT_BUCKET_COUNT - 1; -+ -+ return (u8)bucket_index; -+} -+ -+// Input latency data into the latency model -+static void latency_model_input(struct adios_data *ad, -+ struct latency_model *model, -+ u32 block_size, u64 latency, u64 pred_lat, u32 weight) { -+ unsigned long flags; -+ u8 bucket_index; -+ struct lm_buckets *buckets; -+ u64 current_base; -+ struct latency_model_params *params; -+ -+ local_irq_save(flags); -+ buckets = per_cpu_ptr(model->pcpu_buckets, __smp_processor_id()); -+ -+ rcu_read_lock(); -+ params = rcu_dereference(model->params); -+ current_base = params->base; -+ rcu_read_unlock(); -+ -+ if (block_size <= LM_BLOCK_SIZE_THRESHOLD) { -+ // Handle small requests -+ bucket_index = lm_input_bucket_index(latency, current_base ?: 1); -+ -+ buckets->small_bucket[bucket_index].sum_of_weights += weight; -+ buckets->small_bucket[bucket_index].weighted_sum_latency += -+ latency * weight; -+ -+ local_irq_restore(flags); -+ -+ if (unlikely(!current_base)) { -+ latency_model_update(ad, model); -+ return; -+ } -+ } else { -+ // Handle large requests -+ if (!current_base || !pred_lat) { -+ local_irq_restore(flags); -+ return; -+ } -+ -+ bucket_index = lm_input_bucket_index(latency, pred_lat); -+ -+ buckets->large_bucket[bucket_index].sum_of_weights += weight; -+ buckets->large_bucket[bucket_index].weighted_sum_latency += -+ latency * weight; -+ buckets->large_bucket[bucket_index].weighted_sum_block_size += -+ block_size * weight; -+ -+ local_irq_restore(flags); -+ } -+} -+ -+// Predict the latency for a given block size using the latency model -+static u64 latency_model_predict(struct latency_model *model, u32 block_size) { -+ u64 result; -+ struct latency_model_params *params; -+ -+ rcu_read_lock(); -+ params = rcu_dereference(model->params); -+ -+ result = params->base; -+ if (block_size > LM_BLOCK_SIZE_THRESHOLD) -+ result += params->slope * -+ DIV_ROUND_UP_ULL(block_size - LM_BLOCK_SIZE_THRESHOLD, 1024); -+ -+ rcu_read_unlock(); -+ -+ return result; -+} -+ -+// Determine the type of operation based on request flags -+static u8 adios_optype(struct request *rq) { -+ switch (rq->cmd_flags & REQ_OP_MASK) { -+ case REQ_OP_READ: -+ return ADIOS_READ; -+ case REQ_OP_WRITE: -+ return ADIOS_WRITE; -+ case REQ_OP_DISCARD: -+ return ADIOS_DISCARD; -+ default: -+ return ADIOS_OTHER; -+ } -+} -+ -+static inline u8 adios_optype_not_read(struct request *rq) { -+ return (rq->cmd_flags & REQ_OP_MASK) != REQ_OP_READ; -+} -+ -+// Helper function to retrieve adios_rq_data from a request -+static inline struct adios_rq_data *get_rq_data(struct request *rq) { -+ return rq->elv.priv[0]; -+} -+ -+static inline -+void set_adios_state(struct adios_data *ad, u32 shift, u32 idx, bool flag) { -+ if (flag) -+ atomic_or(1U << (idx + shift), &ad->state); -+ else -+ atomic_andnot(1U << (idx + shift), &ad->state); -+} -+ -+static inline u32 get_adios_state(struct adios_data *ad) -+{ return atomic_read(&ad->state); } -+ -+static inline u32 eval_this_adios_state(u32 state, u32 shift) -+{ return (state >> shift) & 0x3; } -+ -+static inline u32 eval_adios_state(struct adios_data *ad, u32 shift) -+{ return eval_this_adios_state(get_adios_state(ad), shift); } -+ -+// Add a request to the deadline-sorted red-black tree -+static void add_to_dl_tree( -+ struct adios_data *ad, bool dl_idx, struct request *rq) { -+ struct rb_root_cached *root = &ad->dl_tree[dl_idx]; -+ struct rb_node **link = &(root->rb_root.rb_node), *parent = NULL; -+ bool leftmost = true; -+ struct adios_rq_data *rd = get_rq_data(rq); -+ struct dl_group *dlg; -+ u64 deadline; -+ bool was_empty = RB_EMPTY_ROOT(&root->rb_root); -+ -+ /* Tier-2: Synchronous Requests -+ * - Needs to be FIFO within a same optype -+ * - Relaxed order between different optypes -+ * - basically needs to be processed in early time */ -+ rd->deadline = rq->start_time_ns; -+ -+ /* Tier-3: Aynchronous Requests -+ * - Can be reordered and delayed freely */ -+ if (!(rq->cmd_flags & REQ_SYNC)) { -+ rd->deadline += ad->latency_target[adios_optype(rq)]; -+ if (!compliant(ad, ADIOS_CF_FIXORDER)) -+ rd->deadline += rd->pred_lat; -+ } -+ -+ // Now quantize the deadline (-> dlg->deadline == RB-Tree key) -+ deadline = rd->deadline & ~((1ULL << ADIOS_QUANTUM_SHIFT) - 1); -+ -+ while (*link) { -+ dlg = rb_entry(*link, struct dl_group, node); -+ s64 diff = deadline - dlg->deadline; -+ -+ parent = *link; -+ if (diff < 0) { -+ link = &((*link)->rb_left); -+ } else if (diff > 0) { -+ link = &((*link)->rb_right); -+ leftmost = false; -+ } else { // diff == 0 -+ goto found; -+ } -+ } -+ -+ dlg = rb_entry_safe(parent, struct dl_group, node); -+ if (!dlg || dlg->deadline != deadline) { -+ dlg = kmem_cache_zalloc(ad->dl_group_pool, GFP_ATOMIC); -+ if (!dlg) -+ return; -+ dlg->deadline = deadline; -+ INIT_LIST_HEAD(&dlg->rqs); -+ rb_link_node(&dlg->node, parent, link); -+ rb_insert_color_cached(&dlg->node, root, leftmost); -+ } -+found: -+ list_add_tail(&rd->dl_node, &dlg->rqs); -+ rd->dl_group = &dlg->rqs; -+ -+ if (was_empty) -+ set_adios_state(ad, ADIOS_STATE_DL, dl_idx, true); -+} -+ -+// Remove a request from the deadline-sorted red-black tree -+static void del_from_dl_tree( -+ struct adios_data *ad, bool dl_idx, struct request *rq) { -+ struct rb_root_cached *root = &ad->dl_tree[dl_idx]; -+ struct adios_rq_data *rd = get_rq_data(rq); -+ struct dl_group *dlg = container_of(rd->dl_group, struct dl_group, rqs); -+ -+ list_del_init(&rd->dl_node); -+ if (list_empty(&dlg->rqs)) { -+ rb_erase_cached(&dlg->node, root); -+ kmem_cache_free(ad->dl_group_pool, dlg); -+ } -+ rd->dl_group = NULL; -+ -+ if (RB_EMPTY_ROOT(&ad->dl_tree[dl_idx].rb_root)) -+ set_adios_state(ad, ADIOS_STATE_DL, dl_idx, false); -+} -+ -+// Remove a request from the scheduler -+static void remove_request(struct adios_data *ad, struct request *rq) { -+ bool dl_idx = adios_optype_not_read(rq); -+ struct request_queue *q = rq->q; -+ struct adios_rq_data *rd = get_rq_data(rq); -+ -+ list_del_init(&rq->queuelist); -+ -+ // We might not be on the rbtree, if we are doing an insert merge -+ if (rd->dl_group) -+ del_from_dl_tree(ad, dl_idx, rq); -+ -+ elv_rqhash_del(q, rq); -+ if (q->last_merge == rq) -+ q->last_merge = NULL; -+} -+ -+// Convert a queue depth to the corresponding word depth for shallow allocation -+static int to_word_depth(struct blk_mq_hw_ctx *hctx, unsigned int qdepth) { -+ struct sbitmap_queue *bt = &hctx->sched_tags->bitmap_tags; -+ const unsigned int nrr = hctx->queue->nr_requests; -+ -+ return ((qdepth << bt->sb.shift) + nrr - 1) / nrr; -+} -+ -+// We limit the depth of request allocation for asynchronous and write requests -+static void adios_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data) { -+ struct adios_data *ad = data->q->elevator->elevator_data; -+ -+ // Do not throttle synchronous reads -+ if (op_is_sync(opf) && !op_is_write(opf)) -+ return; -+ -+ data->shallow_depth = to_word_depth(data->hctx, ad->async_depth); -+} -+ -+// The number of requests in the queue was notified from the block layer -+static void adios_depth_updated(struct request_queue *q) { -+ struct adios_data *ad = q->elevator->elevator_data; -+ -+ ad->async_depth = q->nr_requests; -+ blk_mq_set_min_shallow_depth(q, 1); -+} -+ -+// Handle request merging after a merge operation -+static void adios_request_merged(struct request_queue *q, struct request *req, -+ enum elv_merge type) { -+ bool dl_idx = adios_optype_not_read(req); -+ struct adios_data *ad = q->elevator->elevator_data; -+ -+ // Reposition request in the deadline-sorted tree -+ del_from_dl_tree(ad, dl_idx, req); -+ add_to_dl_tree(ad, dl_idx, req); -+} -+ -+// Handle merging of requests after one has been merged into another -+static void adios_merged_requests(struct request_queue *q, struct request *req, -+ struct request *next) { -+ struct adios_data *ad = q->elevator->elevator_data; -+ -+ lockdep_assert_held(&ad->lock); -+ -+ // kill knowledge of next, this one is a goner -+ remove_request(ad, next); -+} -+ -+// Try to merge a bio into an existing rq before associating it with an rq -+static bool adios_bio_merge(struct request_queue *q, struct bio *bio, -+ unsigned int nr_segs) { -+ unsigned long flags; -+ struct adios_data *ad = q->elevator->elevator_data; -+ struct request *free = NULL; -+ bool ret; -+ -+ if (eval_adios_state(ad, ADIOS_STATE_BP)) -+ return false; -+ -+ if (!spin_trylock_irqsave(&ad->lock, flags)) -+ return false; -+ -+ ret = blk_mq_sched_try_merge(q, bio, nr_segs, &free); -+ spin_unlock_irqrestore(&ad->lock, flags); -+ -+ if (free) -+ blk_mq_free_request(free); -+ -+ return ret; -+} -+ -+static bool merge_or_insert_to_dl_tree(struct adios_data *ad, -+ struct request *rq, struct request_queue *q, struct list_head *free) { -+ if (blk_mq_sched_try_insert_merge(q, rq, free)) -+ return true; -+ -+ bool dl_idx = adios_optype_not_read(rq); -+ add_to_dl_tree(ad, dl_idx, rq); -+ -+ if (rq_mergeable(rq)) { -+ elv_rqhash_add(q, rq); -+ if (!q->last_merge) -+ q->last_merge = rq; -+ } -+ -+ return false; -+} -+ -+static void insert_to_prio_queue(struct adios_data *ad, -+ struct request *rq, bool pq_idx) { -+ struct adios_rq_data *rd = get_rq_data(rq); -+ -+ /* We're sure that rd->managed == true */ -+ union adios_in_flight_rqs ifr = { -+ .count = 1, -+ .total_pred_lat = rd->pred_lat, -+ }; -+ atomic64_add(ifr.scalar, &ad->in_flight_rqs.atomic); -+ -+ scoped_guard(spinlock_irqsave, &ad->pq_lock) { -+ bool was_empty = list_empty(&ad->prio_queue[pq_idx]); -+ list_add_tail(&rq->queuelist, &ad->prio_queue[pq_idx]); -+ if (was_empty) -+ set_adios_state(ad, ADIOS_STATE_PQ, pq_idx, true); -+ } -+} -+ -+// Insert a request into the scheduler (after Read & Write models stabilized) -+static void insert_request_post_stability(struct blk_mq_hw_ctx *hctx, -+ struct request *rq, blk_insert_t insert_flags, struct list_head *free) { -+ struct request_queue *q = hctx->queue; -+ struct adios_data *ad = q->elevator->elevator_data; -+ struct adios_rq_data *rd = get_rq_data(rq); -+ u8 optype = adios_optype(rq); -+ bool rq_is_flush; -+ -+ rd->managed = true; -+ rd->block_size = blk_rq_bytes(rq); -+ rd->pred_lat = -+ latency_model_predict(&ad->latency_model[optype], rd->block_size); -+ if (unlikely(rd->pred_lat > ad->lat_model_latency_limit)) -+ rd->pred_lat = ad->lat_model_latency_limit; -+ -+ /* Tier-0: BLK_MQ_INSERT_AT_HEAD Requests */ -+ if (insert_flags & BLK_MQ_INSERT_AT_HEAD) { -+ insert_to_prio_queue(ad, rq, 0); -+ return; -+ } -+ -+ /* -+ * Strict Barrier Handling for REQ_OP_FLUSH: -+ * If a flush request arrives, or if the scheduler is already in a -+ * barrier-pending state, all subsequent requests are diverted to a -+ * separate barrier_queue. This ensures that no new requests are processed -+ * until all work preceding the barrier is complete. -+ */ -+ rq_is_flush = (rq->cmd_flags & REQ_OP_MASK) == REQ_OP_FLUSH; -+ if (eval_adios_state(ad, ADIOS_STATE_BP) || rq_is_flush) { -+ scoped_guard(spinlock_irqsave, &ad->barrier_lock) { -+ if (rq_is_flush) -+ set_adios_state(ad, ADIOS_STATE_BP, 0, true); -+ list_add_tail(&rq->queuelist, &ad->barrier_queue); -+ } -+ return; -+ } -+ -+ if (merge_or_insert_to_dl_tree(ad, rq, q, free)) -+ return; -+} -+ -+// Insert a request into the scheduler (before Read & Write models stabilizes) -+static void insert_request_pre_stability(struct blk_mq_hw_ctx *hctx, -+ struct request *rq, blk_insert_t insert_flags, struct list_head *free) { -+ struct adios_data *ad = hctx->queue->elevator->elevator_data; -+ struct adios_rq_data *rd = get_rq_data(rq); -+ u8 optype = adios_optype(rq); -+ u8 pq_idx = !(insert_flags & BLK_MQ_INSERT_AT_HEAD); -+ bool stable = false; -+ -+ rd->managed = true; -+ rd->block_size = blk_rq_bytes(rq); -+ rd->pred_lat = -+ latency_model_predict(&ad->latency_model[optype], rd->block_size); -+ if (unlikely(rd->pred_lat > ad->lat_model_latency_limit)) -+ rd->pred_lat = ad->lat_model_latency_limit; -+ -+ insert_to_prio_queue(ad, rq, pq_idx); -+ -+ rcu_read_lock(); -+ if (rcu_dereference(ad->latency_model[ADIOS_READ].params)->base > 0 && -+ rcu_dereference(ad->latency_model[ADIOS_WRITE].params)->base > 0) -+ stable = true; -+ rcu_read_unlock(); -+ -+ if (stable) -+ ad->models_stable = true; -+} -+ -+// Insert multiple requests into the scheduler -+static void adios_insert_requests(struct blk_mq_hw_ctx *hctx, -+ struct list_head *list, -+ blk_insert_t insert_flags) { -+ struct request_queue *q = hctx->queue; -+ struct adios_data *ad = q->elevator->elevator_data; -+ struct request *rq; -+ bool stop = false; -+ LIST_HEAD(free); -+ -+ do { -+ scoped_guard(spinlock_irqsave, &ad->lock) -+ for (int i = 0; i < ADIOS_MAX_INSERTS_PER_LOCK; i++) { -+ if (list_empty(list)) { -+ stop = true; -+ break; -+ } -+ rq = list_first_entry(list, struct request, queuelist); -+ list_del_init(&rq->queuelist); -+ if (likely(ad->models_stable)) -+ insert_request_post_stability(hctx, rq, insert_flags, &free); -+ else -+ insert_request_pre_stability(hctx, rq, insert_flags, &free); -+ }} while (!stop); -+ -+ blk_mq_free_requests(&free); -+} -+ -+// Prepare a request before it is inserted into the scheduler -+static void adios_prepare_request(struct request *rq) { -+ struct adios_data *ad = rq->q->elevator->elevator_data; -+ struct adios_rq_data *rd; -+ -+ rd = mempool_alloc(ad->rq_data_pool, GFP_ATOMIC); -+ memset(rd, 0, sizeof(*rd)); -+ rd->rq = rq; -+ rq->elv.priv[0] = rd; -+} -+ -+static struct adios_rq_data *get_dl_first_rd(struct adios_data *ad, bool idx) { -+ struct rb_root_cached *root = &ad->dl_tree[idx]; -+ struct rb_node *first = rb_first_cached(root); -+ struct dl_group *dl_group = rb_entry(first, struct dl_group, node); -+ -+ return list_first_entry(&dl_group->rqs, struct adios_rq_data, dl_node); -+} -+ -+// Comparison function for sorting requests by block address -+static int cmp_rq_pos(void *priv, -+ const struct list_head *a, const struct list_head *b) { -+ struct request *rq_a = list_entry(a, struct request, queuelist); -+ struct request *rq_b = list_entry(b, struct request, queuelist); -+ u64 pos_a = blk_rq_pos(rq_a); -+ u64 pos_b = blk_rq_pos(rq_b); -+ -+ return (int)(pos_a > pos_b) - (int)(pos_a < pos_b); -+} -+ -+#ifndef list_last_entry_or_null -+#define list_last_entry_or_null(ptr, type, member) \ -+ (!list_empty(ptr) ? list_last_entry(ptr, type, member) : NULL) -+#endif -+ -+// Update the elevator direction -+static void update_elv_direction(struct adios_data *ad) { -+ if (!ad->is_rotational) -+ return; -+ -+ bool page = ad->bq_page; -+ struct list_head *q = &ad->batch_queue[page][1]; -+ if (ad->bq_batch_order[page] < ADIOS_BO_ELEVATOR || list_empty(q)) { -+ ad->elv_direction = 0; -+ return; -+ } -+ -+ // Get first and last request positions in the queue -+ struct request *rq_a = list_first_entry(q, struct request, queuelist); -+ struct request *rq_b = list_last_entry (q, struct request, queuelist); -+ u64 pos_a = blk_rq_pos(rq_a); -+ u64 pos_b = blk_rq_pos(rq_b); -+ u64 avg_rq_pos = (pos_a + pos_b) >> 1; -+ -+ ad->elv_direction = !!(ad->head_pos > avg_rq_pos); -+} -+ -+// Fill the batch queues with requests from the deadline-sorted red-black tree -+static bool fill_batch_queues(struct adios_data *ad, u64 tpl) { -+ struct adios_rq_data *rd; -+ struct request *rq; -+ struct list_head *dest_q; -+ u8 dest_idx; -+ u64 added_lat = 0; -+ u32 optype_count[ADIOS_OPTYPES] = {0}; -+ u32 count = 0; -+ u8 optype; -+ bool page = !ad->bq_page, dl_idx, bias_idx, update_bias; -+ u32 dl_queued; -+ u8 bq_batch_order; -+ bool stop = false; -+ -+ // Reset batch queue counts for the back page -+ memset(&ad->batch_count[page], 0, sizeof(ad->batch_count[page])); -+ -+ ad->bq_batch_order[page] = -+ bq_batch_order = ad->batch_order; -+ -+ do { -+ scoped_guard(spinlock_irqsave, &ad->lock) -+ for (int i = 0; i < ADIOS_MAX_DELETES_PER_LOCK; i++) { -+ bool has_base = false; -+ -+ dl_queued = eval_adios_state(ad, ADIOS_STATE_DL); -+ // Check if there are any requests queued in the deadline tree -+ if (!dl_queued) { -+ stop = true; -+ break; -+ } -+ -+ // Reads if both queues have requests, otherwise pick the non-empty. -+ dl_idx = dl_queued >> 1; -+ -+ // Get the first request from the deadline-sorted tree -+ rd = get_dl_first_rd(ad, dl_idx); -+ -+ bias_idx = ad->dl_bias < 0; -+ // If read and write requests are queued, choose one based on bias -+ if (dl_queued == 0x3) { -+ struct adios_rq_data *trd[2] = {get_dl_first_rd(ad, 0), rd}; -+ rd = trd[bias_idx]; -+ -+ update_bias = (trd[bias_idx]->deadline > trd[!bias_idx]->deadline); -+ } else -+ update_bias = (bias_idx == dl_idx); -+ -+ rq = rd->rq; -+ optype = adios_optype(rq); -+ -+ rcu_read_lock(); -+ has_base = -+ !!rcu_dereference(ad->latency_model[optype].params)->base; -+ rcu_read_unlock(); -+ -+ // Check batch size and total predicted latency -+ if (count && (!has_base || -+ ad->batch_count[page][optype] >= ad->batch_limit[optype] || -+ (tpl + added_lat + rd->pred_lat) > ad->global_latency_window)) { -+ stop = true; -+ break; -+ } -+ -+ if (update_bias) { -+ s64 sign = ((s64)bias_idx << 1) - 1; -+ if (unlikely(!rd->pred_lat)) -+ ad->dl_bias = sign; -+ else -+ // Adjust the bias based on the predicted latency -+ ad->dl_bias += sign * (s64)((rd->pred_lat * -+ adios_prio_to_wmult[ad->dl_prio[bias_idx] + 20]) >> 10); -+ } -+ -+ remove_request(ad, rq); -+ -+ // Add request to the corresponding batch queue -+ dest_idx = (bq_batch_order == ADIOS_BO_OPTYPE || optype == ADIOS_OTHER)? -+ optype : !!(rd->deadline != rq->start_time_ns); -+ dest_q = &ad->batch_queue[page][dest_idx]; -+ list_add_tail(&rq->queuelist, dest_q); -+ ad->bq_state[page] |= 1U << dest_idx; -+ ad->batch_count[page][optype]++; -+ optype_count[optype]++; -+ added_lat += rd->pred_lat; -+ count++; -+ }} while (!stop); -+ -+ if (bq_batch_order == ADIOS_BO_ELEVATOR && ad->batch_count[page][1] > 1) -+ list_sort(NULL, &ad->batch_queue[page][1], cmp_rq_pos); -+ -+ if (count) { -+ /* We're sure that every request's rd->managed == true */ -+ union adios_in_flight_rqs ifr = { -+ .count = count, -+ .total_pred_lat = added_lat, -+ }; -+ atomic64_add(ifr.scalar, &ad->in_flight_rqs.atomic); -+ -+ set_adios_state(ad, ADIOS_STATE_BQ, page, true); -+ -+ for (optype = 0; optype < ADIOS_OPTYPES; optype++) -+ if (ad->batch_actual_max_size[optype] < optype_count[optype]) -+ ad->batch_actual_max_size[optype] = optype_count[optype]; -+ if (ad->batch_actual_max_total < count) -+ ad->batch_actual_max_total = count; -+ } -+ return count; -+} -+ -+// Flip to the next batch queue page -+static void flip_bq_page(struct adios_data *ad) { -+ ad->bq_page = !ad->bq_page; -+ update_elv_direction(ad); -+} -+ -+// Pop a request from the specified index (optype or elevator tier) -+static inline struct request *pop_bq_request( -+ struct adios_data *ad, u8 idx, bool direction) { -+ bool page = ad->bq_page; -+ struct list_head *q = &ad->batch_queue[page][idx]; -+ struct request *rq = direction ? -+ list_last_entry_or_null (q, struct request, queuelist): -+ list_first_entry_or_null(q, struct request, queuelist); -+ if (rq) { -+ list_del_init(&rq->queuelist); -+ if (list_empty(q)) -+ ad->bq_state[page] &= ~(1U << idx); -+ } -+ return rq; -+} -+ -+static struct request *pop_next_bq_request_optype(struct adios_data *ad) { -+ u32 bq_state = ad->bq_state[ad->bq_page]; -+ if (!bq_state) return NULL; -+ -+ struct request *rq; -+ u32 bq_idx = __builtin_ctz(bq_state); -+ -+ // Dispatch based on optype (FIFO within each) or single-queue elevator -+ rq = pop_bq_request(ad, bq_idx, false); -+ return rq; -+} -+ -+static struct request *pop_next_bq_request_elevator(struct adios_data *ad) { -+ u32 bq_state = ad->bq_state[ad->bq_page]; -+ if (!bq_state) return NULL; -+ -+ struct request *rq; -+ u32 bq_idx = __builtin_ctz(bq_state); -+ bool direction = (bq_idx == 1) & ad->elv_direction; -+ -+ // Tier-2 (sync) is always high priority -+ // Tier-3 (async) uses the pre-calculated elevator direction -+ rq = pop_bq_request(ad, bq_idx, direction); -+ -+ /* If batch queue for the sync requests just became empty */ -+ if (bq_idx == 0 && rq && !(bq_state & 0x1)) -+ update_elv_direction(ad); -+ -+ return rq; -+} -+ -+// Returns the state of the batch queue page -+static inline bool bq_page_has_rq(u32 bq_state, bool page) { -+ return bq_state & (1U << page); -+} -+ -+// Dispatch a request from the batch queues -+static struct request *dispatch_from_bq(struct adios_data *ad) { -+ struct request *rq; -+ -+ guard(spinlock_irqsave)(&ad->bq_lock); -+ -+ u32 state = get_adios_state(ad); -+ u32 bq_state = eval_this_adios_state(state, ADIOS_STATE_BQ); -+ u32 bq_curr_page_has_rq = bq_page_has_rq(bq_state, ad->bq_page); -+ union adios_in_flight_rqs ifr; -+ ifr.scalar = atomic64_read(&ad->in_flight_rqs.atomic); -+ u64 tpl = ifr.total_pred_lat; -+ -+ // Refill the batch queues if the back page is empty, dl_tree has work, and -+ // current page is empty or the total ongoing latency is below the threshold -+ if (!bq_page_has_rq(bq_state, !ad->bq_page) && -+ (!bq_curr_page_has_rq || (!tpl || tpl < div_u64( -+ ad->global_latency_window * ad->bq_refill_below_ratio, 100))) && -+ eval_this_adios_state(state, ADIOS_STATE_DL)) -+ fill_batch_queues(ad, tpl); -+ -+ // If current batch queue page is empty, and the other page has work, flip -+ if (!bq_curr_page_has_rq && -+ bq_page_has_rq(eval_adios_state(ad, ADIOS_STATE_BQ), !ad->bq_page)) -+ flip_bq_page(ad); -+ -+ // Use the per-page state to decide the dispatch logic, ensuring correctness -+ rq = (ad->bq_batch_order[ad->bq_page] == ADIOS_BO_ELEVATOR) ? -+ pop_next_bq_request_elevator(ad): -+ pop_next_bq_request_optype(ad); -+ -+ if (rq) { -+ bool page = ad->bq_page; -+ bool is_empty = !ad->bq_state[page]; -+ if (is_empty) -+ set_adios_state(ad, ADIOS_STATE_BQ, page, false); -+ return rq; -+ } -+ -+ return NULL; -+} -+ -+// Dispatch a request from the priority queue -+static struct request *dispatch_from_pq(struct adios_data *ad) { -+ struct request *rq = NULL; -+ -+ guard(spinlock_irqsave)(&ad->pq_lock); -+ u32 pq_state = eval_adios_state(ad, ADIOS_STATE_PQ); -+ u8 pq_idx = pq_state >> 1; -+ struct list_head *q = &ad->prio_queue[pq_idx]; -+ -+ if (unlikely(list_empty(q))) return NULL; -+ -+ rq = list_first_entry(q, struct request, queuelist); -+ list_del_init(&rq->queuelist); -+ if (list_empty(q)) { -+ set_adios_state(ad, ADIOS_STATE_PQ, pq_idx, false); -+ update_elv_direction(ad); -+ } -+ return rq; -+} -+ -+static bool release_barrier_requests(struct adios_data *ad) { -+ u32 moved_count = 0; -+ LIST_HEAD(local_list); -+ -+ scoped_guard(spinlock_irqsave, &ad->barrier_lock) { -+ if (!list_empty(&ad->barrier_queue)) { -+ struct request *trq, *next; -+ bool first_barrier_moved = false; -+ -+ list_for_each_entry_safe(trq, next, &ad->barrier_queue, queuelist) { -+ if (!first_barrier_moved) { -+ list_del_init(&trq->queuelist); -+ insert_to_prio_queue(ad, trq, 1); -+ moved_count++; -+ first_barrier_moved = true; -+ continue; -+ } -+ -+ if ((trq->cmd_flags & REQ_OP_MASK) == REQ_OP_FLUSH) -+ break; -+ -+ list_move_tail(&trq->queuelist, &local_list); -+ moved_count++; -+ } -+ -+ if (list_empty(&ad->barrier_queue)) -+ set_adios_state(ad, ADIOS_STATE_BP, 0, false); -+ } -+ } -+ -+ if (!moved_count) -+ return false; -+ -+ if (!list_empty(&local_list)) { -+ struct request *trq, *next; -+ LIST_HEAD(free_list); -+ -+ /* ad->lock is already held */ -+ list_for_each_entry_safe(trq, next, &local_list, queuelist) { -+ list_del_init(&trq->queuelist); -+ if (merge_or_insert_to_dl_tree(ad, trq, ad->queue, &free_list)) -+ continue; -+ } -+ -+ if (!list_empty(&free_list)) -+ blk_mq_free_requests(&free_list); -+ } -+ -+ return true; -+} -+ -+// Dispatch a request to the hardware queue -+static struct request *adios_dispatch_request(struct blk_mq_hw_ctx *hctx) { -+ struct adios_data *ad = hctx->queue->elevator->elevator_data; -+ struct request *rq; -+ -+retry: -+ rq = dispatch_from_pq(ad); -+ if (rq) -+ goto found; -+ -+ rq = dispatch_from_bq(ad); -+ if (rq) -+ goto found; -+ -+ /* -+ * If all active queues are empty, check if we need to process a barrier. -+ * This is the trigger to release requests that were held in barrier_queue -+ * due to a REQ_OP_FLUSH barrier. -+ */ -+ if (eval_adios_state(ad, ADIOS_STATE_BP)) { -+ bool barrier_released = false; -+ scoped_guard(spinlock_irqsave, &ad->lock) -+ barrier_released = release_barrier_requests(ad); -+ if (barrier_released) -+ goto retry; -+ } -+ -+ return NULL; -+found: -+ if (ad->is_rotational) -+ ad->head_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); -+ -+ rq->rq_flags |= RQF_STARTED; -+ return rq; -+} -+ -+// Timer callback function to periodically update latency models -+static void update_timer_callback(struct timer_list *t) { -+ struct adios_data *ad = timer_container_of(ad, t, update_timer); -+ -+ for (u8 optype = 0; optype < ADIOS_OPTYPES; optype++) -+ latency_model_update(ad, &ad->latency_model[optype]); -+} -+ -+// Handle the completion of a request -+static void adios_completed_request(struct request *rq, u64 now) { -+ struct adios_data *ad = rq->q->elevator->elevator_data; -+ struct adios_rq_data *rd = get_rq_data(rq); -+ union adios_in_flight_rqs ifr = { .scalar = 0 }; -+ -+ if (rd->managed) { -+ union adios_in_flight_rqs ifr_to_sub = { -+ .count = 1, -+ .total_pred_lat = rd->pred_lat, -+ }; -+ ifr.scalar = atomic64_sub_return( -+ ifr_to_sub.scalar, &ad->in_flight_rqs.atomic); -+ } -+ u8 optype = adios_optype(rq); -+ -+ unsigned long flags; -+ struct adios_pcpu_completion *pc; -+ -+ local_irq_save(flags); -+ pc = this_cpu_ptr(ad->pcpu_completion); -+ -+ if (optype == ADIOS_OTHER) { -+ // Non-positional commands make the head position unpredictable. -+ // Invalidate our knowledge of the last completed position. -+ if (ad->is_rotational) -+ pc->last_completed_pos = 0; -+ local_irq_restore(flags); -+ return; -+ } -+ -+ u64 lct = pc->last_completed_time ?: rq->io_start_time_ns; -+ pc->last_completed_time = (ifr.count) ? now : 0; -+ -+ if (!rq->io_start_time_ns || !rd->block_size || unlikely(now < lct)) { -+ local_irq_restore(flags); -+ return; -+ } -+ -+ u64 latency = now - lct; -+ -+ u32 weight = 1; -+ if (ad->is_rotational) { -+ sector_t current_pos = blk_rq_pos(rq); -+ // Only calculate seek distance if we have a valid last position. -+ if (pc->last_completed_pos > 0) { -+ u64 seek_distance = abs( -+ (s64)current_pos - (s64)pc->last_completed_pos); -+ if (seek_distance) -+ weight = 65 - __builtin_clzll(seek_distance); -+ } -+ // Update (or re-synchronize) our knowledge of the head position. -+ pc->last_completed_pos = current_pos + blk_rq_sectors(rq); -+ } -+ -+ local_irq_restore(flags); -+ -+ if (latency > ad->lat_model_latency_limit) -+ return; -+ -+ latency_model_input(ad, &ad->latency_model[optype], -+ rd->block_size, latency, rd->pred_lat, weight); -+ timer_reduce(&ad->update_timer, jiffies + msecs_to_jiffies(100)); -+} -+ -+// Clean up after a request is finished -+static void adios_finish_request(struct request *rq) { -+ struct adios_data *ad = rq->q->elevator->elevator_data; -+ -+ if (rq->elv.priv[0]) { -+ // Free adios_rq_data back to the memory pool -+ mempool_free(get_rq_data(rq), ad->rq_data_pool); -+ rq->elv.priv[0] = NULL; -+ } -+} -+ -+// Check if there are any requests available for dispatch -+static bool adios_has_work(struct blk_mq_hw_ctx *hctx) { -+ struct adios_data *ad = hctx->queue->elevator->elevator_data; -+ -+ return atomic_read(&ad->state) != 0; -+} -+ -+// Initialize the scheduler-specific data when initializing the request queue -+static int adios_init_sched(struct request_queue *q, struct elevator_queue *eq) { -+ struct adios_data *ad; -+ int ret = -ENOMEM; -+ u8 optype = 0; -+ -+ ad = kzalloc_node(sizeof(*ad), GFP_KERNEL, q->node); -+ if (!ad) { -+ pr_err("adios: Failed to create adios_data\n"); -+ goto put_eq; -+ } -+ -+ eq->elevator_data = ad; -+ -+ // Create a memory pool for adios_rq_data -+ ad->rq_data_cache = kmem_cache_create("adios_rq_data", -+ sizeof(struct adios_rq_data), -+ 0, SLAB_HWCACHE_ALIGN, NULL); -+ if (!ad->rq_data_cache) { -+ pr_err("adios: Failed to create rq_data_cache\n"); -+ goto free_ad; -+ } -+ -+ ad->rq_data_pool = mempool_create_slab_pool( -+ q->nr_requests, ad->rq_data_cache); -+ if (!ad->rq_data_pool) { -+ pr_err("adios: Failed to create rq_data_pool\n"); -+ goto destroy_rq_data_cache; -+ } -+ -+ /* Create a memory pool for dl_group */ -+ ad->dl_group_pool = kmem_cache_create("dl_group_pool", -+ sizeof(struct dl_group), -+ 0, SLAB_HWCACHE_ALIGN, NULL); -+ if (!ad->dl_group_pool) { -+ pr_err("adios: Failed to create dl_group_pool\n"); -+ goto destroy_rq_data_pool; -+ } -+ -+ for (int i = 0; i < ADIOS_PQ_LEVELS; i++) -+ INIT_LIST_HEAD(&ad->prio_queue[i]); -+ -+ for (u8 i = 0; i < ADIOS_DL_TYPES; i++) { -+ ad->dl_tree[i] = RB_ROOT_CACHED; -+ ad->dl_prio[i] = default_dl_prio[i]; -+ } -+ ad->dl_bias = 0; -+ -+ for (u8 page = 0; page < ADIOS_BQ_PAGES; page++) -+ for (optype = 0; optype < ADIOS_OPTYPES; optype++) -+ INIT_LIST_HEAD(&ad->batch_queue[page][optype]); -+ -+ ad->aggr_buckets = kzalloc(sizeof(*ad->aggr_buckets), GFP_KERNEL); -+ if (!ad->aggr_buckets) { -+ pr_err("adios: Failed to allocate aggregation buckets\n"); -+ goto destroy_dl_group_pool; -+ } -+ -+ ad->pcpu_completion = alloc_percpu(struct adios_pcpu_completion); -+ if (!ad->pcpu_completion) { -+ pr_err("adios: Failed to allocate per-CPU completion data\n"); -+ goto free_aggr_buckets; -+ } -+ -+ for (optype = 0; optype < ADIOS_OPTYPES; optype++) { -+ struct latency_model *model = &ad->latency_model[optype]; -+ struct latency_model_params *params; -+ -+ spin_lock_init(&model->update_lock); -+ params = kzalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ pr_err("adios: Failed to allocate latency_model_params\n"); -+ goto free_buckets; -+ } -+ params->last_update_jiffies = jiffies; -+ RCU_INIT_POINTER(model->params, params); -+ -+ model->pcpu_buckets = alloc_percpu(struct lm_buckets); -+ if (!model->pcpu_buckets) { -+ pr_err("adios: Failed to allocate per-CPU buckets\n"); -+ kfree(params); -+ goto free_buckets; -+ } -+ -+ model->pcpu_snapshot = alloc_percpu(struct lm_buckets); -+ if (!model->pcpu_snapshot) { -+ pr_err("adios: Failed to allocate per-CPU snapshot\n"); -+ free_percpu(model->pcpu_buckets); -+ kfree(params); -+ goto free_buckets; -+ } -+ -+ model->lm_shrink_at_kreqs = default_lm_shrink_at_kreqs; -+ model->lm_shrink_at_gbytes = default_lm_shrink_at_gbytes; -+ model->lm_shrink_resist = default_lm_shrink_resist; -+ } -+ -+ for (optype = 0; optype < ADIOS_OPTYPES; optype++) { -+ ad->latency_target[optype] = default_latency_target[optype]; -+ ad->batch_limit[optype] = default_batch_limit[optype]; -+ } -+ -+ eq->elevator_data = ad; -+ -+ ad->is_rotational = !!(q->limits.features & BLK_FEAT_ROTATIONAL); -+ ad->global_latency_window = (ad->is_rotational)? -+ default_global_latency_window_rotational: -+ default_global_latency_window; -+ ad->bq_refill_below_ratio = default_bq_refill_below_ratio; -+ ad->lat_model_latency_limit = default_lat_model_latency_limit; -+ ad->batch_order = default_batch_order; -+ ad->compliance_flags = default_compliance_flags; -+ -+ ad->models_stable = false; -+ -+ atomic_set(&ad->state, 0); -+ -+ spin_lock_init(&ad->lock); -+ spin_lock_init(&ad->pq_lock); -+ spin_lock_init(&ad->bq_lock); -+ spin_lock_init(&ad->barrier_lock); -+ INIT_LIST_HEAD(&ad->barrier_queue); -+ -+ timer_setup(&ad->update_timer, update_timer_callback, 0); -+ -+ /* We dispatch from request queue wide instead of hw queue */ -+ blk_queue_flag_set(QUEUE_FLAG_SQ_SCHED, q); -+ -+ ad->queue = q; -+ blk_stat_enable_accounting(q); -+ -+ q->elevator = eq; -+ adios_depth_updated(q); -+ return 0; -+ -+free_buckets: -+ pr_err("adios: Failed to allocate per-cpu buckets\n"); -+ while (optype-- > 0) { -+ struct latency_model *prev_model = &ad->latency_model[optype]; -+ kfree(rcu_access_pointer(prev_model->params)); -+ free_percpu(prev_model->pcpu_snapshot); -+ free_percpu(prev_model->pcpu_buckets); -+ } -+ free_percpu(ad->pcpu_completion); -+free_aggr_buckets: -+ kfree(ad->aggr_buckets); -+destroy_dl_group_pool: -+ kmem_cache_destroy(ad->dl_group_pool); -+destroy_rq_data_pool: -+ mempool_destroy(ad->rq_data_pool); -+destroy_rq_data_cache: -+ kmem_cache_destroy(ad->rq_data_cache); -+free_ad: -+ kfree(ad); -+put_eq: -+ kobject_put(&eq->kobj); -+ return ret; -+} -+ -+// Clean up and free resources when exiting the scheduler -+static void adios_exit_sched(struct elevator_queue *e) { -+ struct adios_data *ad = e->elevator_data; -+ -+ timer_shutdown_sync(&ad->update_timer); -+ -+ WARN_ON_ONCE(!list_empty(&ad->barrier_queue)); -+ for (int i = 0; i < 2; i++) -+ WARN_ON_ONCE(!list_empty(&ad->prio_queue[i])); -+ -+ for (u8 i = 0; i < ADIOS_OPTYPES; i++) { -+ struct latency_model *model = &ad->latency_model[i]; -+ struct latency_model_params *params = rcu_access_pointer(model->params); -+ -+ RCU_INIT_POINTER(model->params, NULL); -+ kfree_rcu(params, rcu); -+ -+ free_percpu(model->pcpu_snapshot); -+ free_percpu(model->pcpu_buckets); -+ } -+ -+ synchronize_rcu(); -+ -+ free_percpu(ad->pcpu_completion); -+ kfree(ad->aggr_buckets); -+ -+ mempool_destroy(ad->rq_data_pool); -+ kmem_cache_destroy(ad->rq_data_cache); -+ -+ if (ad->dl_group_pool) -+ kmem_cache_destroy(ad->dl_group_pool); -+ -+ blk_stat_disable_accounting(ad->queue); -+ -+ kfree(ad); -+} -+ -+static void sideload_latency_model( -+ struct latency_model *model, u64 base, u64 slope) { -+ struct latency_model_params *old_params, *new_params; -+ unsigned long flags; -+ -+ new_params = kzalloc(sizeof(*new_params), GFP_KERNEL); -+ if (!new_params) -+ return; -+ -+ spin_lock_irqsave(&model->update_lock, flags); -+ -+ old_params = rcu_dereference_protected(model->params, -+ lockdep_is_held(&model->update_lock)); -+ -+ new_params->last_update_jiffies = jiffies; -+ -+ // Initialize base and its statistics as a single sample. -+ new_params->base = base; -+ new_params->small_sum_delay = base; -+ new_params->small_count = 1; -+ -+ // Initialize slope and its statistics as a single sample. -+ new_params->slope = slope; -+ new_params->large_sum_delay = slope; -+ new_params->large_sum_bsize = 1024; /* Corresponds to 1 KiB */ -+ -+ lm_reset_pcpu_buckets(model); -+ -+ rcu_assign_pointer(model->params, new_params); -+ spin_unlock_irqrestore(&model->update_lock, flags); -+ -+ kfree_rcu(old_params, rcu); -+} -+ -+// Define sysfs attributes for operation types -+#define SYSFS_OPTYPE_DECL(name, optype) \ -+static ssize_t adios_lat_model_##name##_show( \ -+ struct elevator_queue *e, char *page) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ struct latency_model *model = &ad->latency_model[optype]; \ -+ struct latency_model_params *params; \ -+ ssize_t len = 0; \ -+ u64 base, slope; \ -+ rcu_read_lock(); \ -+ params = rcu_dereference(model->params); \ -+ base = params->base; \ -+ slope = params->slope; \ -+ rcu_read_unlock(); \ -+ len += sprintf(page, "base : %llu ns\n", base); \ -+ len += sprintf(page + len, "slope: %llu ns/KiB\n", slope); \ -+ return len; \ -+} \ -+static ssize_t adios_lat_model_##name##_store( \ -+ struct elevator_queue *e, const char *page, size_t count) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ struct latency_model *model = &ad->latency_model[optype]; \ -+ u64 base, slope; \ -+ int ret; \ -+ ret = sscanf(page, "%llu %llu", &base, &slope); \ -+ if (ret != 2) \ -+ return -EINVAL; \ -+ sideload_latency_model(model, base, slope); \ -+ reset_buckets(ad->aggr_buckets); \ -+ return count; \ -+} \ -+static ssize_t adios_lat_target_##name##_show( \ -+ struct elevator_queue *e, char *page) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ return sprintf(page, "%llu\n", ad->latency_target[optype]); \ -+} \ -+static ssize_t adios_lat_target_##name##_store( \ -+ struct elevator_queue *e, const char *page, size_t count) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ unsigned long nsec; \ -+ int ret; \ -+ ret = kstrtoul(page, 10, &nsec); \ -+ if (ret) \ -+ return ret; \ -+ sideload_latency_model(&ad->latency_model[optype], 0, 0); \ -+ ad->latency_target[optype] = nsec; \ -+ return count; \ -+} \ -+static ssize_t adios_batch_limit_##name##_show( \ -+ struct elevator_queue *e, char *page) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ return sprintf(page, "%u\n", ad->batch_limit[optype]); \ -+} \ -+static ssize_t adios_batch_limit_##name##_store( \ -+ struct elevator_queue *e, const char *page, size_t count) { \ -+ unsigned long max_batch; \ -+ int ret; \ -+ ret = kstrtoul(page, 10, &max_batch); \ -+ if (ret || max_batch == 0) \ -+ return -EINVAL; \ -+ struct adios_data *ad = e->elevator_data; \ -+ ad->batch_limit[optype] = max_batch; \ -+ return count; \ -+} -+ -+SYSFS_OPTYPE_DECL(read, ADIOS_READ); -+SYSFS_OPTYPE_DECL(write, ADIOS_WRITE); -+SYSFS_OPTYPE_DECL(discard, ADIOS_DISCARD); -+ -+// Show the maximum batch size actually achieved for each operation type -+static ssize_t adios_batch_actual_max_show( -+ struct elevator_queue *e, char *page) { -+ struct adios_data *ad = e->elevator_data; -+ u32 total_count, read_count, write_count, discard_count; -+ -+ total_count = ad->batch_actual_max_total; -+ read_count = ad->batch_actual_max_size[ADIOS_READ]; -+ write_count = ad->batch_actual_max_size[ADIOS_WRITE]; -+ discard_count = ad->batch_actual_max_size[ADIOS_DISCARD]; -+ -+ return sprintf(page, -+ "Total : %u\nDiscard: %u\nRead : %u\nWrite : %u\n", -+ total_count, discard_count, read_count, write_count); -+} -+ -+#define SYSFS_ULL_DECL(field, min_val, max_val) \ -+static ssize_t adios_##field##_show( \ -+ struct elevator_queue *e, char *page) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ return sprintf(page, "%llu\n", ad->field); \ -+} \ -+static ssize_t adios_##field##_store( \ -+ struct elevator_queue *e, const char *page, size_t count) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ unsigned long val; \ -+ int ret; \ -+ ret = kstrtoul(page, 10, &val); \ -+ if (ret || val < (min_val) || val > (max_val)) \ -+ return -EINVAL; \ -+ ad->field = val; \ -+ return count; \ -+} -+ -+SYSFS_ULL_DECL(global_latency_window, 0, ULLONG_MAX) -+SYSFS_ULL_DECL(compliance_flags, 0, ULLONG_MAX) -+ -+#define SYSFS_INT_DECL(field, min_val, max_val) \ -+static ssize_t adios_##field##_show( \ -+ struct elevator_queue *e, char *page) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ return sprintf(page, "%d\n", ad->field); \ -+} \ -+static ssize_t adios_##field##_store( \ -+ struct elevator_queue *e, const char *page, size_t count) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ int val; \ -+ int ret; \ -+ ret = kstrtoint(page, 10, &val); \ -+ if (ret || val < (min_val) || val > (max_val)) \ -+ return -EINVAL; \ -+ ad->field = val; \ -+ return count; \ -+} -+ -+SYSFS_INT_DECL(bq_refill_below_ratio, 0, 100) -+SYSFS_INT_DECL(lat_model_latency_limit, 0, 2*NSEC_PER_SEC) -+SYSFS_INT_DECL(batch_order, ADIOS_BO_OPTYPE, !!ad->is_rotational) -+ -+// Show the read priority -+static ssize_t adios_read_priority_show( -+ struct elevator_queue *e, char *page) { -+ struct adios_data *ad = e->elevator_data; -+ return sprintf(page, "%d\n", ad->dl_prio[0]); -+} -+ -+// Set the read priority -+static ssize_t adios_read_priority_store( -+ struct elevator_queue *e, const char *page, size_t count) { -+ struct adios_data *ad = e->elevator_data; -+ int prio; -+ int ret; -+ -+ ret = kstrtoint(page, 10, &prio); -+ if (ret || prio < -20 || prio > 19) -+ return -EINVAL; -+ -+ guard(spinlock_irqsave)(&ad->lock); -+ ad->dl_prio[0] = prio; -+ ad->dl_bias = 0; -+ -+ return count; -+} -+ -+// Reset batch queue statistics -+static ssize_t adios_reset_bq_stats_store( -+ struct elevator_queue *e, const char *page, size_t count) { -+ struct adios_data *ad = e->elevator_data; -+ unsigned long val; -+ int ret; -+ -+ ret = kstrtoul(page, 10, &val); -+ if (ret || val != 1) -+ return -EINVAL; -+ -+ for (u8 i = 0; i < ADIOS_OPTYPES; i++) -+ ad->batch_actual_max_size[i] = 0; -+ -+ ad->batch_actual_max_total = 0; -+ -+ return count; -+} -+ -+// Reset the latency model parameters or load them from user input -+static ssize_t adios_reset_lat_model_store( -+ struct elevator_queue *e, const char *page, size_t count) -+{ -+ struct adios_data *ad = e->elevator_data; -+ struct latency_model *model; -+ int ret; -+ -+ /* -+ * Differentiate between two modes based on input format: -+ * 1. "1": Fully reset the model (backward compatibility). -+ * 2. "R_base R_slope W_base W_slope D_base D_slope": Load values. -+ */ -+ if (!strchr(page, ' ')) { -+ // Mode 1: Full reset. -+ unsigned long val; -+ -+ ret = kstrtoul(page, 10, &val); -+ if (ret || val != 1) -+ return -EINVAL; -+ -+ for (u8 i = 0; i < ADIOS_OPTYPES; i++) { -+ model = &ad->latency_model[i]; -+ sideload_latency_model(model, 0, 0); -+ } -+ } else { -+ // Mode 2: Load initial values for all latency models. -+ u64 params[3][2]; /* 0:base, 1:slope for R, W, D */ -+ -+ ret = sscanf(page, "%llu %llu %llu %llu %llu %llu", -+ ¶ms[ADIOS_READ ][0], ¶ms[ADIOS_READ ][1], -+ ¶ms[ADIOS_WRITE ][0], ¶ms[ADIOS_WRITE ][1], -+ ¶ms[ADIOS_DISCARD][0], ¶ms[ADIOS_DISCARD][1]); -+ -+ if (ret != 6) -+ return -EINVAL; -+ -+ for (u8 i = ADIOS_READ; i <= ADIOS_DISCARD; i++) { -+ model = &ad->latency_model[i]; -+ sideload_latency_model(model, params[i][0], params[i][1]); -+ } -+ } -+ reset_buckets(ad->aggr_buckets); -+ -+ return count; -+} -+ -+// Show the ADIOS version -+static ssize_t adios_version_show(struct elevator_queue *e, char *page) { -+ return sprintf(page, "%s\n", ADIOS_VERSION); -+} -+ -+// Define sysfs attributes for dynamic thresholds -+#define SHRINK_THRESHOLD_ATTR_RW(name, model_field, min_value, max_value) \ -+static ssize_t adios_shrink_##name##_store( \ -+ struct elevator_queue *e, const char *page, size_t count) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ unsigned long val; \ -+ int ret; \ -+ ret = kstrtoul(page, 10, &val); \ -+ if (ret || val < min_value || val > max_value) \ -+ return -EINVAL; \ -+ for (u8 i = 0; i < ADIOS_OPTYPES; i++) { \ -+ struct latency_model *model = &ad->latency_model[i]; \ -+ unsigned long flags; \ -+ spin_lock_irqsave(&model->update_lock, flags); \ -+ model->model_field = val; \ -+ spin_unlock_irqrestore(&model->update_lock, flags); \ -+ } \ -+ return count; \ -+} \ -+static ssize_t adios_shrink_##name##_show( \ -+ struct elevator_queue *e, char *page) { \ -+ struct adios_data *ad = e->elevator_data; \ -+ u32 val = 0; \ -+ unsigned long flags; \ -+ struct latency_model *model = &ad->latency_model[0]; \ -+ spin_lock_irqsave(&model->update_lock, flags); \ -+ val = model->model_field; \ -+ spin_unlock_irqrestore(&model->update_lock, flags); \ -+ return sprintf(page, "%u\n", val); \ -+} -+ -+SHRINK_THRESHOLD_ATTR_RW(at_kreqs, lm_shrink_at_kreqs, 1, 100000) -+SHRINK_THRESHOLD_ATTR_RW(at_gbytes, lm_shrink_at_gbytes, 1, 1000) -+SHRINK_THRESHOLD_ATTR_RW(resist, lm_shrink_resist, 1, 3) -+ -+// Define sysfs attributes -+#define AD_ATTR(name, show_func, store_func) \ -+ __ATTR(name, 0644, show_func, store_func) -+#define AD_ATTR_RW(name) \ -+ __ATTR(name, 0644, adios_##name##_show, adios_##name##_store) -+#define AD_ATTR_RO(name) \ -+ __ATTR(name, 0444, adios_##name##_show, NULL) -+#define AD_ATTR_WO(name) \ -+ __ATTR(name, 0200, NULL, adios_##name##_store) -+ -+// Define sysfs attributes for ADIOS scheduler -+static struct elv_fs_entry adios_sched_attrs[] = { -+ AD_ATTR_RO(batch_actual_max), -+ AD_ATTR_RW(bq_refill_below_ratio), -+ AD_ATTR_RW(global_latency_window), -+ AD_ATTR_RW(lat_model_latency_limit), -+ AD_ATTR_RW(batch_order), -+ AD_ATTR_RW(compliance_flags), -+ -+ AD_ATTR_RW(batch_limit_read), -+ AD_ATTR_RW(batch_limit_write), -+ AD_ATTR_RW(batch_limit_discard), -+ -+ AD_ATTR_RW(lat_model_read), -+ AD_ATTR_RW(lat_model_write), -+ AD_ATTR_RW(lat_model_discard), -+ -+ AD_ATTR_RW(lat_target_read), -+ AD_ATTR_RW(lat_target_write), -+ AD_ATTR_RW(lat_target_discard), -+ -+ AD_ATTR_RW(shrink_at_kreqs), -+ AD_ATTR_RW(shrink_at_gbytes), -+ AD_ATTR_RW(shrink_resist), -+ -+ AD_ATTR_RW(read_priority), -+ -+ AD_ATTR_WO(reset_bq_stats), -+ AD_ATTR_WO(reset_lat_model), -+ AD_ATTR(adios_version, adios_version_show, NULL), -+ -+ __ATTR_NULL -+}; -+ -+// Define the ADIOS scheduler type -+static struct elevator_type mq_adios = { -+ .ops = { -+ .next_request = elv_rb_latter_request, -+ .former_request = elv_rb_former_request, -+ .limit_depth = adios_limit_depth, -+ .depth_updated = adios_depth_updated, -+ .request_merged = adios_request_merged, -+ .requests_merged = adios_merged_requests, -+ .bio_merge = adios_bio_merge, -+ .insert_requests = adios_insert_requests, -+ .prepare_request = adios_prepare_request, -+ .dispatch_request = adios_dispatch_request, -+ .completed_request = adios_completed_request, -+ .finish_request = adios_finish_request, -+ .has_work = adios_has_work, -+ .init_sched = adios_init_sched, -+ .exit_sched = adios_exit_sched, -+ }, -+ .elevator_attrs = adios_sched_attrs, -+ .elevator_name = "adios", -+ .elevator_owner = THIS_MODULE, -+}; -+MODULE_ALIAS("mq-adios-iosched"); -+ -+#define ADIOS_PROGNAME "Adaptive Deadline I/O Scheduler" -+#define ADIOS_AUTHOR "Masahito Suzuki" -+ -+// Initialize the ADIOS scheduler module -+static int __init adios_init(void) { -+ printk(KERN_INFO "%s %s by %s\n", -+ ADIOS_PROGNAME, ADIOS_VERSION, ADIOS_AUTHOR); -+ return elv_register(&mq_adios); -+} -+ -+// Exit the ADIOS scheduler module -+static void __exit adios_exit(void) { -+ elv_unregister(&mq_adios); -+} -+ -+module_init(adios_init); -+module_exit(adios_exit); -+ -+MODULE_AUTHOR(ADIOS_AUTHOR); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION(ADIOS_PROGNAME); -\ No newline at end of file -diff --git a/block/elevator.c b/block/elevator.c -index 2161b6eea680..72a0dc6b345f 100644 ---- a/block/elevator.c -+++ b/block/elevator.c -@@ -740,6 +740,14 @@ void elevator_set_default(struct request_queue *q) - if (q->tag_set->flags & BLK_MQ_F_NO_SCHED_BY_DEFAULT) - return; - -+#ifdef CONFIG_MQ_IOSCHED_DEFAULT_ADIOS -+ ctx.name = "adios"; -+#else // !CONFIG_MQ_IOSCHED_DEFAULT_ADIOS -+ bool is_sq = q->nr_hw_queues == 1 || blk_mq_is_shared_tags(q->tag_set->flags); -+ if (!is_sq) -+ return; -+#endif // CONFIG_MQ_IOSCHED_DEFAULT_ADIOS -+ - /* - * For single queue devices, default to using mq-deadline. If we - * have multiple queues or mq-deadline is not available, default -@@ -749,13 +757,10 @@ void elevator_set_default(struct request_queue *q) - if (!ctx.type) - return; - -- if ((q->nr_hw_queues == 1 || -- blk_mq_is_shared_tags(q->tag_set->flags))) { -- err = elevator_change(q, &ctx); -- if (err < 0) -- pr_warn("\"%s\" elevator initialization, failed %d, falling back to \"none\"\n", -- ctx.name, err); -- } -+ err = elevator_change(q, &ctx); -+ if (err < 0) -+ pr_warn("\"%s\" elevator initialization, failed %d, falling back to \"none\"\n", -+ ctx.name, err); - elevator_put(ctx.type); - } - diff --git a/kernel/0150-adios-3.2.0.patch.sig b/kernel/0150-adios-3.2.0.patch.sig deleted file mode 100644 index 1f838b7..0000000 Binary files a/kernel/0150-adios-3.2.0.patch.sig and /dev/null differ diff --git a/kernel/0210-pm-updates.patch b/kernel/0210-pm-updates.patch deleted file mode 100644 index 5110d06..0000000 --- a/kernel/0210-pm-updates.patch +++ /dev/null @@ -1,2365 +0,0 @@ -diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c ---- a/drivers/acpi/acpi_processor.c -+++ b/drivers/acpi/acpi_processor.c -@@ -994,3 +994,357 @@ end: - } - EXPORT_SYMBOL_NS_GPL(acpi_processor_evaluate_cst, "ACPI_PROCESSOR_IDLE"); - #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ -+ -+#ifdef CONFIG_ACPI_PROCESSOR_IDLE -+struct acpi_lpi_states_array { -+ unsigned int size; -+ unsigned int composite_states_size; -+ struct acpi_lpi_state *entries; -+ struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER]; -+}; -+ -+static int obj_get_integer(union acpi_object *obj, u32 *value) -+{ -+ if (obj->type != ACPI_TYPE_INTEGER) -+ return -EINVAL; -+ -+ *value = obj->integer.value; -+ return 0; -+} -+ -+#define lpi_state_debug(handle, message, state_idx) \ -+ acpi_handle_debug(handle, message " for _LPI state %u\n", state_idx) -+ -+static void process_lpi_state_package(union acpi_object *lpi_pkg, -+ struct acpi_lpi_state *lpi_state, -+ acpi_handle handle, -+ unsigned int state_idx, bool strict) -+{ -+ union acpi_object *lpi_pkg_elem, *obj; -+ -+ if (lpi_pkg->type != ACPI_TYPE_PACKAGE || lpi_pkg->package.count < 7) -+ return; -+ -+ lpi_pkg_elem = lpi_pkg->package.elements; -+ -+ /* Get the entry method first and skip the state if that fails. */ -+ obj = &lpi_pkg_elem[6]; -+ if (obj->type == ACPI_TYPE_BUFFER) { -+ struct acpi_power_register *reg; -+ -+ if (obj->buffer.length < sizeof(*reg)) { -+ lpi_state_debug(handle, "Invalid register data", state_idx); -+ return; -+ } -+ -+ reg = (struct acpi_power_register *)obj->buffer.pointer; -+ if (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) { -+ lpi_state_debug(handle, "Unsupported entry method", state_idx); -+ return; -+ } -+ -+ lpi_state->entry_method = ACPI_CSTATE_FFH; -+ lpi_state->address = reg->address; -+ } else if (obj->type == ACPI_TYPE_INTEGER) { -+ lpi_state->entry_method = ACPI_CSTATE_INTEGER; -+ lpi_state->address = obj->integer.value; -+ } else { -+ lpi_state_debug(handle, "Invalid entry method", state_idx); -+ return; -+ } -+ -+ if (obj_get_integer(&lpi_pkg_elem[0], &lpi_state->min_residency)) { -+ if (strict) { -+ lpi_state_debug(handle, "No min. residency", state_idx); -+ return; -+ } -+ -+ lpi_state_debug(handle, "Assuming 10 us min. residency", state_idx); -+ lpi_state->min_residency = 10; -+ } -+ -+ if (obj_get_integer(&lpi_pkg_elem[1], &lpi_state->wake_latency)) { -+ if (strict) { -+ lpi_state_debug(handle, "No wake latency", state_idx); -+ return; -+ } -+ -+ lpi_state_debug(handle, "Assuming 10 us wake latency", state_idx); -+ lpi_state->wake_latency = 10; -+ } -+ -+ if (obj_get_integer(&lpi_pkg_elem[2], &lpi_state->flags)) -+ lpi_state->flags = 0; -+ -+ if (obj_get_integer(&lpi_pkg_elem[3], &lpi_state->arch_flags)) -+ lpi_state->arch_flags = 0; -+ -+ if (obj_get_integer(&lpi_pkg_elem[4], &lpi_state->res_cnt_freq)) -+ lpi_state->res_cnt_freq = 1; -+ -+ if (obj_get_integer(&lpi_pkg_elem[5], &lpi_state->enable_parent_state)) -+ lpi_state->enable_parent_state = 0; -+ -+ /* Skip elements [7-8] i.e. Residency/Usage counters. */ -+ -+ /* -+ * Avoid out-of-bounds access if the size of the package is less than -+ * expected. -+ */ -+ if (lpi_pkg->package.count < 10) -+ return; -+ -+ obj = &lpi_pkg_elem[9]; -+ if (obj->type == ACPI_TYPE_STRING) -+ strscpy(lpi_state->desc, obj->string.pointer, ACPI_CX_DESC_LEN); -+} -+ -+static int acpi_processor_evaluate_lpi(acpi_handle handle, -+ struct acpi_lpi_states_array *info, -+ bool strict) -+{ -+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -+ union acpi_object *lpi_data, *lpi_pkg; -+ unsigned int lpi_pkg_count, state_idx; -+ struct acpi_lpi_state *lpi_state; -+ acpi_status status; -+ int ret = 0; -+ -+ status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer); -+ if (ACPI_FAILURE(status)) { -+ acpi_handle_debug(handle, "No _LPI, giving up\n"); -+ return -ENODEV; -+ } -+ -+ lpi_data = buffer.pointer; -+ -+ /* There must be at least 4 elements = 3 elements + 1 package */ -+ if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE || -+ lpi_data->package.count < 4) { -+ acpi_handle_debug(handle, "Not enough elements in _LPI\n"); -+ ret = -ENODATA; -+ goto end; -+ } -+ -+ lpi_pkg_count = lpi_data->package.elements[2].integer.value; -+ -+ /* Validate number of power states. */ -+ if (!lpi_pkg_count || lpi_pkg_count != lpi_data->package.count - 3) { -+ acpi_handle_debug(handle, "Invalid _LPI state count\n"); -+ ret = -ENODATA; -+ goto end; -+ } -+ -+ lpi_state = kzalloc_objs(*lpi_state, lpi_pkg_count); -+ if (!lpi_state) { -+ ret = -ENOMEM; -+ goto end; -+ } -+ -+ info->size = lpi_pkg_count; -+ info->entries = lpi_state; -+ -+ /* _LPI State packages start at index 3. */ -+ lpi_pkg = &lpi_data->package.elements[3]; -+ -+ for (state_idx = 1; state_idx <= lpi_pkg_count; state_idx++) { -+ lpi_state->index = state_idx; -+ process_lpi_state_package(lpi_pkg++, lpi_state++, handle, -+ state_idx, strict); -+ } -+ -+ acpi_handle_debug(handle, "Found %u power states\n", lpi_pkg_count); -+end: -+ kfree(buffer.pointer); -+ return ret; -+} -+ -+/** -+ * combine_lpi_states - combine local and parent LPI states to form a composite LPI state -+ * -+ * @local: local LPI state -+ * @parent: parent LPI state -+ * @result: composite LPI state -+ */ -+static bool combine_lpi_states(struct acpi_lpi_state *local, -+ struct acpi_lpi_state *parent, -+ struct acpi_lpi_state *result) -+{ -+ if (parent->entry_method == ACPI_CSTATE_INTEGER) { -+ if (!parent->address) /* 0 means autopromotable */ -+ return false; -+ result->address = local->address + parent->address; -+ } else { -+ result->address = parent->address; -+ } -+ -+ result->min_residency = max(local->min_residency, parent->min_residency); -+ result->wake_latency = local->wake_latency + parent->wake_latency; -+ result->enable_parent_state = parent->enable_parent_state; -+ result->entry_method = local->entry_method; -+ -+ result->flags = parent->flags; -+ result->arch_flags = parent->arch_flags; -+ result->index = parent->index; -+ -+ scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc); -+ return true; -+} -+ -+#define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0) -+ -+static void stash_composite_state(struct acpi_lpi_states_array *curr_level, -+ struct acpi_lpi_state *t) -+{ -+ curr_level->composite_states[curr_level->composite_states_size++] = t; -+} -+ -+static bool too_many_states(acpi_handle handle, unsigned int state_count) -+{ -+ if (state_count < ACPI_PROCESSOR_MAX_POWER) -+ return false; -+ -+ acpi_handle_info(handle, "No space for more _LPI states than %d\n", -+ ACPI_PROCESSOR_MAX_POWER); -+ return true; -+} -+ -+static unsigned int flatten_lpi_states(acpi_handle handle, -+ struct acpi_lpi_state *lpi_states, -+ unsigned int state_count, -+ struct acpi_lpi_states_array *curr, -+ struct acpi_lpi_states_array *prev) -+{ -+ struct acpi_lpi_state *parent_lpi = curr->entries; -+ unsigned int j; -+ -+ /* -+ * Combine each of the "raw" _LPI states from the current (processor -+ * container) level with all of the composite _LPI states from the -+ * previous (processor or processor container) level. -+ */ -+ for (j = 0; j < curr->size; j++, parent_lpi++) { -+ struct acpi_lpi_state *flpi; -+ int i; -+ -+ if (!(parent_lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED)) -+ continue; -+ -+ if (too_many_states(handle, state_count)) -+ break; -+ -+ flpi = &lpi_states[state_count]; -+ -+ for (i = 0; i < prev->composite_states_size; i++) { -+ struct acpi_lpi_state *local_lpi = prev->composite_states[i]; -+ -+ if (parent_lpi->index > local_lpi->enable_parent_state) -+ continue; -+ -+ if (!combine_lpi_states(local_lpi, parent_lpi, flpi)) -+ continue; -+ -+ stash_composite_state(curr, flpi); -+ state_count++; -+ flpi++; -+ -+ if (state_count >= ACPI_PROCESSOR_MAX_POWER) -+ break; -+ } -+ } -+ -+ return state_count; -+} -+ -+int acpi_processor_extract_lpi_info(acpi_handle pr_handle, -+ struct acpi_processor_power *pr_power, -+ bool strict) -+{ -+ struct acpi_lpi_states_array info[2], *prev, *curr; -+ acpi_handle handle = pr_handle; -+ unsigned int state_count = 0; -+ unsigned int i; -+ int ret; -+ -+ if (!osc_pc_lpi_support_confirmed) -+ return -EOPNOTSUPP; -+ -+ curr = &info[0]; -+ curr->composite_states_size = 0; -+ -+ ret = acpi_processor_evaluate_lpi(handle, curr, strict); -+ if (ret) -+ return ret; -+ -+ /* Copy all of the usable first-level states to power.lpi_states[]. */ -+ for (i = 0; i < curr->size; i++) { -+ struct acpi_lpi_state *lpi = &curr->entries[i]; -+ struct acpi_lpi_state *flpi; -+ -+ /* -+ * Skip states that are not enabled or have an inadequate entry -+ * method for this level. -+ */ -+ if (!(lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED) || -+ lpi->entry_method == ACPI_CSTATE_INTEGER) -+ continue; -+ -+ if (too_many_states(pr_handle, state_count)) -+ break; -+ -+ flpi = &pr_power->lpi_states[state_count++]; -+ memcpy(flpi, lpi, sizeof(*lpi)); -+ stash_composite_state(curr, flpi); -+ } -+ -+ kfree(curr->entries); -+ -+ /* -+ * If there are no _LPI states at the first level, there are no _LPI -+ * states at all. -+ */ -+ if (!state_count) -+ return -ENODATA; -+ -+ prev = curr; -+ curr = &info[1]; -+ -+ for (;;) { -+ struct acpi_lpi_states_array *tmp; -+ struct acpi_device *d; -+ -+ if (ACPI_FAILURE(acpi_get_parent(handle, &handle))) -+ break; -+ -+ d = acpi_fetch_acpi_dev(handle); -+ if (!d) -+ break; -+ -+ if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID)) -+ break; -+ -+ curr->composite_states_size = 0; -+ -+ ret = acpi_processor_evaluate_lpi(handle, curr, strict); -+ if (ret) -+ break; -+ -+ /* flatten all the LPI states in this level of hierarchy */ -+ state_count = flatten_lpi_states(pr_handle, pr_power->lpi_states, -+ state_count, curr, prev); -+ -+ kfree(curr->entries); -+ -+ tmp = prev, prev = curr, curr = tmp; -+ } -+ -+ /* reset the index after flattening */ -+ for (i = 0; i < state_count; i++) -+ pr_power->lpi_states[i].index = i; -+ -+ pr_power->count = state_count; -+ -+ return 0; -+} -+EXPORT_SYMBOL_NS_GPL(acpi_processor_extract_lpi_info, "ACPI_PROCESSOR_IDLE"); -+#endif /* CONFIG_ACPI_PROCESSOR_IDLE */ -diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c ---- a/drivers/acpi/processor_idle.c -+++ b/drivers/acpi/processor_idle.c -@@ -853,237 +853,6 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) - - #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ - --struct acpi_lpi_states_array { -- unsigned int size; -- unsigned int composite_states_size; -- struct acpi_lpi_state *entries; -- struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER]; --}; -- --static int obj_get_integer(union acpi_object *obj, u32 *value) --{ -- if (obj->type != ACPI_TYPE_INTEGER) -- return -EINVAL; -- -- *value = obj->integer.value; -- return 0; --} -- --static int acpi_processor_evaluate_lpi(acpi_handle handle, -- struct acpi_lpi_states_array *info) --{ -- acpi_status status; -- int ret = 0; -- int pkg_count, state_idx = 1, loop; -- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -- union acpi_object *lpi_data; -- struct acpi_lpi_state *lpi_state; -- -- status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer); -- if (ACPI_FAILURE(status)) { -- acpi_handle_debug(handle, "No _LPI, giving up\n"); -- return -ENODEV; -- } -- -- lpi_data = buffer.pointer; -- -- /* There must be at least 4 elements = 3 elements + 1 package */ -- if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE || -- lpi_data->package.count < 4) { -- pr_debug("not enough elements in _LPI\n"); -- ret = -ENODATA; -- goto end; -- } -- -- pkg_count = lpi_data->package.elements[2].integer.value; -- -- /* Validate number of power states. */ -- if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) { -- pr_debug("count given by _LPI is not valid\n"); -- ret = -ENODATA; -- goto end; -- } -- -- lpi_state = kzalloc_objs(*lpi_state, pkg_count); -- if (!lpi_state) { -- ret = -ENOMEM; -- goto end; -- } -- -- info->size = pkg_count; -- info->entries = lpi_state; -- -- /* LPI States start at index 3 */ -- for (loop = 3; state_idx <= pkg_count; loop++, state_idx++, lpi_state++) { -- union acpi_object *element, *pkg_elem, *obj; -- -- element = &lpi_data->package.elements[loop]; -- if (element->type != ACPI_TYPE_PACKAGE || element->package.count < 7) -- continue; -- -- pkg_elem = element->package.elements; -- -- obj = pkg_elem + 6; -- if (obj->type == ACPI_TYPE_BUFFER) { -- struct acpi_power_register *reg; -- -- if (obj->buffer.length < sizeof(*reg)) { -- acpi_handle_debug(handle, -- "Invalid register data for _LPI state %d\n", -- state_idx); -- continue; -- } -- -- reg = (struct acpi_power_register *)obj->buffer.pointer; -- if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO && -- reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) -- continue; -- -- lpi_state->address = reg->address; -- lpi_state->entry_method = -- reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE ? -- ACPI_CSTATE_FFH : ACPI_CSTATE_SYSTEMIO; -- } else if (obj->type == ACPI_TYPE_INTEGER) { -- lpi_state->entry_method = ACPI_CSTATE_INTEGER; -- lpi_state->address = obj->integer.value; -- } else { -- pr_debug("Entry method of state-%d is invalid, disable it.\n", -- state_idx); -- continue; -- } -- -- lpi_state->index = state_idx; -- if (obj_get_integer(pkg_elem + 0, &lpi_state->min_residency)) { -- pr_debug("No min. residency found, assuming 10 us\n"); -- lpi_state->min_residency = 10; -- } -- -- if (obj_get_integer(pkg_elem + 1, &lpi_state->wake_latency)) { -- pr_debug("No wakeup residency found, assuming 10 us\n"); -- lpi_state->wake_latency = 10; -- } -- -- if (obj_get_integer(pkg_elem + 2, &lpi_state->flags)) -- lpi_state->flags = 0; -- -- if (obj_get_integer(pkg_elem + 3, &lpi_state->arch_flags)) -- lpi_state->arch_flags = 0; -- -- if (obj_get_integer(pkg_elem + 4, &lpi_state->res_cnt_freq)) -- lpi_state->res_cnt_freq = 1; -- -- if (obj_get_integer(pkg_elem + 5, &lpi_state->enable_parent_state)) -- lpi_state->enable_parent_state = 0; -- -- /* Skip elements [7-8] i.e. Residency/Usage counters. */ -- -- /* -- * Avoid out-of-bounds access if the size of the package is less -- * than expected. -- */ -- if (element->package.count < 10) -- continue; -- -- obj = pkg_elem + 9; -- if (obj->type == ACPI_TYPE_STRING) -- strscpy(lpi_state->desc, obj->string.pointer, -- ACPI_CX_DESC_LEN); -- } -- -- acpi_handle_debug(handle, "Found %d power states\n", state_idx); --end: -- kfree(buffer.pointer); -- return ret; --} -- --/** -- * combine_lpi_states - combine local and parent LPI states to form a composite LPI state -- * -- * @local: local LPI state -- * @parent: parent LPI state -- * @result: composite LPI state -- */ --static bool combine_lpi_states(struct acpi_lpi_state *local, -- struct acpi_lpi_state *parent, -- struct acpi_lpi_state *result) --{ -- if (parent->entry_method == ACPI_CSTATE_INTEGER) { -- if (!parent->address) /* 0 means autopromotable */ -- return false; -- result->address = local->address + parent->address; -- } else { -- result->address = parent->address; -- } -- -- result->min_residency = max(local->min_residency, parent->min_residency); -- result->wake_latency = local->wake_latency + parent->wake_latency; -- result->enable_parent_state = parent->enable_parent_state; -- result->entry_method = local->entry_method; -- -- result->flags = parent->flags; -- result->arch_flags = parent->arch_flags; -- result->index = parent->index; -- -- scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc); -- return true; --} -- --#define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0) -- --static void stash_composite_state(struct acpi_lpi_states_array *curr_level, -- struct acpi_lpi_state *t) --{ -- curr_level->composite_states[curr_level->composite_states_size++] = t; --} -- --static unsigned int flatten_lpi_states(struct acpi_processor *pr, -- unsigned int flat_state_cnt, -- struct acpi_lpi_states_array *curr_level, -- struct acpi_lpi_states_array *prev_level) --{ -- int i, j, state_count = curr_level->size; -- struct acpi_lpi_state *p, *t = curr_level->entries; -- -- curr_level->composite_states_size = 0; -- for (j = 0; j < state_count; j++, t++) { -- struct acpi_lpi_state *flpi; -- -- if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED)) -- continue; -- -- if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) { -- pr_warn("Limiting number of LPI states to max (%d)\n", -- ACPI_PROCESSOR_MAX_POWER); -- pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n"); -- break; -- } -- -- flpi = &pr->power.lpi_states[flat_state_cnt]; -- -- if (!prev_level) { /* leaf/processor node */ -- memcpy(flpi, t, sizeof(*t)); -- stash_composite_state(curr_level, flpi); -- flat_state_cnt++; -- continue; -- } -- -- for (i = 0; i < prev_level->composite_states_size; i++) { -- p = prev_level->composite_states[i]; -- if (t->index <= p->enable_parent_state && -- combine_lpi_states(p, t, flpi)) { -- stash_composite_state(curr_level, flpi); -- flat_state_cnt++; -- flpi++; -- if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) -- break; -- } -- } -- } -- -- kfree(curr_level->entries); -- return flat_state_cnt; --} -- - int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu) - { - return -EOPNOTSUPP; -@@ -1091,64 +860,16 @@ int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu) - - static int acpi_processor_get_lpi_info(struct acpi_processor *pr) - { -- int ret, i; -- acpi_status status; -- acpi_handle handle = pr->handle, pr_ahandle; -- struct acpi_device *d = NULL; -- struct acpi_lpi_states_array info[2], *tmp, *prev, *curr; -- unsigned int state_count; -+ int ret; - - /* make sure our architecture has support */ - ret = acpi_processor_ffh_lpi_probe(pr->id); - if (ret == -EOPNOTSUPP) - return ret; - -- if (!osc_pc_lpi_support_confirmed) -- return -EOPNOTSUPP; -- -- if (!acpi_has_method(handle, "_LPI")) -- return -EINVAL; -- -- prev = &info[0]; -- curr = &info[1]; -- handle = pr->handle; -- ret = acpi_processor_evaluate_lpi(handle, prev); -+ ret = acpi_processor_extract_lpi_info(pr->handle, &pr->power, false); - if (ret) - return ret; -- state_count = flatten_lpi_states(pr, 0, prev, NULL); -- -- status = acpi_get_parent(handle, &pr_ahandle); -- while (ACPI_SUCCESS(status)) { -- d = acpi_fetch_acpi_dev(pr_ahandle); -- if (!d) -- break; -- -- handle = pr_ahandle; -- -- if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID)) -- break; -- -- /* can be optional ? */ -- if (!acpi_has_method(handle, "_LPI")) -- break; -- -- ret = acpi_processor_evaluate_lpi(handle, curr); -- if (ret) -- break; -- -- /* flatten all the LPI states in this level of hierarchy */ -- state_count = flatten_lpi_states(pr, state_count, curr, prev); -- -- tmp = prev, prev = curr, curr = tmp; -- -- status = acpi_get_parent(handle, &pr_ahandle); -- } -- -- /* reset the index after flattening */ -- for (i = 0; i < state_count; i++) -- pr->power.lpi_states[i].index = i; -- -- pr->power.count = state_count; - - /* Tell driver that _LPI is supported. */ - pr->flags.has_lpi = 1; -diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c ---- a/drivers/base/power/main.c -+++ b/drivers/base/power/main.c -@@ -41,6 +41,9 @@ - #include "../base.h" - #include "power.h" - -+#undef MODULE_PARAM_PREFIX -+#define MODULE_PARAM_PREFIX "pm." -+ - typedef int (*pm_callback_t)(struct device *); - - /* -@@ -532,6 +535,11 @@ module_param(dpm_watchdog_all_cpu_backtrace, bool, 0644); - MODULE_PARM_DESC(dpm_watchdog_all_cpu_backtrace, - "Backtrace all CPUs on DPM watchdog timeout"); - -+static bool __read_mostly dpm_watchdog_enabled = -+ IS_ENABLED(CONFIG_DPM_WATCHDOG_ENABLED); -+module_param(dpm_watchdog_enabled, bool, 0644); -+MODULE_PARM_DESC(dpm_watchdog_enabled, "Enable DPM watchdog"); -+ - static unsigned int __read_mostly dpm_watchdog_timeout = CONFIG_DPM_WATCHDOG_TIMEOUT; - static unsigned int __read_mostly dpm_watchdog_warning_timeout = - CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT; -@@ -627,6 +635,9 @@ static void dpm_watchdog_set(struct dpm_watchdog *wd, struct device *dev) - { - struct timer_list *timer = &wd->timer; - -+ if (!dpm_watchdog_enabled) -+ return; -+ - wd->dev = dev; - wd->tsk = current; - wd->fatal = dpm_watchdog_timeout == dpm_watchdog_warning_timeout; -@@ -645,6 +656,9 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) - { - struct timer_list *timer = &wd->timer; - -+ if (!dpm_watchdog_enabled) -+ return; -+ - timer_delete_sync(timer); - timer_destroy_on_stack(timer); - } -diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c ---- a/drivers/base/power/runtime.c -+++ b/drivers/base/power/runtime.c -@@ -469,9 +469,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) - if (retval == -EACCES) - retval = -EAGAIN; - -- if (retval != -EAGAIN && retval != -EBUSY) -- dev->power.runtime_error = retval; -- - return retval; - } - -@@ -751,6 +748,9 @@ static int rpm_suspend(struct device *dev, int rpmflags) - dev->power.deferred_resume = false; - wake_up_all(&dev->power.wait_queue); - -+ if (retval != -EAGAIN && retval != -EBUSY) -+ dev->power.runtime_error = retval; -+ - /* - * On transient errors, if the callback routine failed an autosuspend, - * and if the last_busy time has been updated so that there is a new -diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c ---- a/drivers/cpufreq/amd-pstate-ut.c -+++ b/drivers/cpufreq/amd-pstate-ut.c -@@ -59,6 +59,7 @@ static int amd_pstate_ut_check_freq(u32 index); - static int amd_pstate_ut_epp(u32 index); - static int amd_pstate_ut_check_driver(u32 index); - static int amd_pstate_ut_check_freq_attrs(u32 index); -+static int amd_pstate_ut_check_floor_freq(u32 index); - - static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = { - {"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid }, -@@ -68,6 +69,7 @@ static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = { - {"amd_pstate_ut_epp", amd_pstate_ut_epp }, - {"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }, - {"amd_pstate_ut_check_freq_attrs", amd_pstate_ut_check_freq_attrs }, -+ {"amd_pstate_ut_check_floor_freq", amd_pstate_ut_check_floor_freq }, - }; - - static bool test_in_list(const char *list, const char *name) -@@ -275,6 +277,7 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode) - static int amd_pstate_ut_epp(u32 index) - { - static const char * const epp_strings[] = { -+ "dynamic", - "power", - "balance_power", - "balance_performance", -@@ -282,10 +285,10 @@ static int amd_pstate_ut_epp(u32 index) - }; - char *buf __free(cleanup_page) = NULL; - struct cpufreq_policy *policy = NULL; -+ unsigned long orig_dynamic_epp = 0; - enum amd_pstate_mode orig_mode; - struct amd_cpudata *cpudata; - unsigned long orig_policy; -- bool orig_dynamic_epp; - int ret, cpu = 0; - u16 epp; - int i; -@@ -294,9 +297,11 @@ static int amd_pstate_ut_epp(u32 index) - if (!policy) - return -ENODEV; - -- cpudata = policy->driver_data; - orig_mode = amd_pstate_get_status(); -- orig_dynamic_epp = cpudata->dynamic_epp; -+ if (policy->driver_data) { -+ cpudata = policy->driver_data; -+ orig_dynamic_epp = cpudata->dynamic_epp; -+ } - - /* Drop reference before potential driver change. */ - cpufreq_cpu_put(policy); -@@ -321,16 +326,6 @@ static int amd_pstate_ut_epp(u32 index) - orig_policy = cpudata->policy; - cpudata->policy = CPUFREQ_POLICY_POWERSAVE; - -- /* -- * Disable dynamic EPP before running test. If "orig_dynamic_epp" is -- * true, the driver will do a redundant switch at the end and there -- * is no need for enabling it again at the end of the test. -- */ -- if (cpudata->dynamic_epp) { -- pr_debug("Dynamic EPP is enabled, disabling it\n"); -- amd_pstate_clear_dynamic_epp(policy); -- } -- - for (epp = 0; epp <= U8_MAX; epp++) { - u8 val; - -@@ -367,6 +362,11 @@ static int amd_pstate_ut_epp(u32 index) - if (ret < 0) - goto out; - strreplace(buf, '\n', '\0'); -+ /* -+ * "dynamic" mode reports the EPP as "dynamic(profile:X)" -+ * Trim at "(" and just compare tie the epp string. -+ */ -+ strreplace(buf, '(', '\0'); - - if (strcmp(buf, epp_strings[i])) { - pr_err("String EPP value mismatch: %s != %s\n", buf, epp_strings[i]); -@@ -380,18 +380,23 @@ static int amd_pstate_ut_epp(u32 index) - out: - if (policy) { - cpudata->policy = orig_policy; -+ /* -+ * If the driver had enabled dynamic_epp to begin with, -+ * restore it here before dropping policy reference. -+ */ -+ if (orig_dynamic_epp) { -+ int ret2; -+ -+ ret2 = store_energy_performance_preference(policy, -+ epp_strings[0], -+ strlen(epp_strings[0])); -+ if (!ret && (ret2 < 0)) -+ ret = ret2; -+ } - up_write(&policy->rwsem); - cpufreq_cpu_put(policy); - } - -- if (orig_dynamic_epp) { -- int ret2; -- -- ret2 = amd_pstate_set_mode(AMD_PSTATE_DISABLE); -- if (!ret && ret2) -- ret = ret2; -- } -- - if (orig_mode != amd_pstate_get_status()) { - int ret2; - -@@ -557,6 +562,80 @@ out: - return ret; - } - -+static int amd_pstate_ut_check_floor_freq(u32 index) -+{ -+ struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; -+ char *buf __free(cleanup_page) = NULL; -+ unsigned int orig_floor_freq; -+ unsigned int floor_freq; -+ int ret, cpu = 0; -+ -+ if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO)) -+ return -EOPNOTSUPP; -+ -+ policy = cpufreq_cpu_get(cpu); -+ if (!policy) -+ return -ENODEV; -+ -+ buf = (char *)__get_free_page(GFP_KERNEL); -+ if (!buf) -+ return -ENOMEM; -+ -+ guard(rwsem_write)(&policy->rwsem); -+ -+ if (!policy->driver_data) -+ return -ENODEV; -+ -+ /* Retrieve original floor frequency */ -+ memset(buf, 0, PAGE_SIZE); -+ ret = show_amd_pstate_floor_freq(policy, buf); -+ if (ret < 0) -+ return ret; -+ -+ ret = kstrtou32(buf, 0, &orig_floor_freq); -+ if (ret) -+ return ret; -+ -+ memset(buf, 0, PAGE_SIZE); -+ snprintf(buf, PAGE_SIZE, "%u", policy->cpuinfo.min_freq); -+ -+ /* Set floor frequency to cpuinfo.min_freq */ -+ ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf)); -+ if (ret < 0) { -+ pr_err("Failed to set floor frequency to %s\n", buf); -+ return ret; -+ } -+ -+ memset(buf, 0, PAGE_SIZE); -+ ret = show_amd_pstate_floor_freq(policy, buf); -+ if (ret < 0) -+ return ret; -+ -+ strreplace(buf, '\n', '\0'); -+ ret = kstrtou32(buf, 0, &floor_freq); -+ if (ret) -+ return ret; -+ -+ /* Confirm sysfs reflects the change correctly. */ -+ if (floor_freq != policy->cpuinfo.min_freq) { -+ pr_err("Floor frequency value mismatch: %u != %u\n", -+ floor_freq, policy->cpuinfo.min_freq); -+ return -EINVAL; -+ } -+ -+ memset(buf, 0, PAGE_SIZE); -+ snprintf(buf, PAGE_SIZE, "%u", orig_floor_freq); -+ -+ /* Restore the original value. */ -+ ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf)); -+ if (ret < 0) { -+ pr_err("Failed to restore floor frequency to %s\n", buf); -+ return ret; -+ } -+ -+ return 0; -+} -+ - static int __init amd_pstate_ut_init(void) - { - u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases); -@@ -575,10 +654,16 @@ static int __init amd_pstate_ut_init(void) - - ret = amd_pstate_ut_cases[i].func(i); - -- if (ret) -+ if (ret) { -+ /* Platform does not support the feature being tested. */ -+ if (ret == -EOPNOTSUPP) { -+ pr_err("%-4d %-20s\t skipped!\n", i+1, amd_pstate_ut_cases[i].name); -+ continue; -+ } - pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret); -- else -+ } else { - pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name); -+ } - } - - return 0; -diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c ---- a/drivers/cpufreq/amd-pstate.c -+++ b/drivers/cpufreq/amd-pstate.c -@@ -75,7 +75,7 @@ const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode) - mode = AMD_PSTATE_UNDEFINED; - return amd_pstate_mode_string[mode]; - } --EXPORT_SYMBOL_GPL(amd_pstate_get_mode_string); -+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_get_mode_string); - - struct quirk_entry { - u32 nominal_freq; -@@ -87,7 +87,6 @@ static struct cpufreq_driver amd_pstate_driver; - static struct cpufreq_driver amd_pstate_epp_driver; - static int cppc_state = AMD_PSTATE_UNDEFINED; - static bool amd_pstate_prefcore = true; --static bool dynamic_epp; - static struct quirk_entry *quirks; - - /* -@@ -106,6 +105,7 @@ static struct quirk_entry *quirks; - * 3 balance_power - * 4 power - * 5 custom (for raw EPP values) -+ * 6 dynamic (platform profile driven selection) - */ - enum energy_perf_value_index { - EPP_INDEX_DEFAULT = 0, -@@ -114,6 +114,7 @@ enum energy_perf_value_index { - EPP_INDEX_BALANCE_POWERSAVE, - EPP_INDEX_POWERSAVE, - EPP_INDEX_CUSTOM, -+ EPP_INDEX_DYNAMIC, - EPP_INDEX_MAX, - }; - -@@ -124,6 +125,7 @@ static const char * const energy_perf_strings[] = { - [EPP_INDEX_BALANCE_POWERSAVE] = "balance_power", - [EPP_INDEX_POWERSAVE] = "power", - [EPP_INDEX_CUSTOM] = "custom", -+ [EPP_INDEX_DYNAMIC] = "dynamic", - }; - static_assert(ARRAY_SIZE(energy_perf_strings) == EPP_INDEX_MAX); - -@@ -134,7 +136,7 @@ static unsigned int epp_values[] = { - [EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_BALANCE_POWERSAVE, - [EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_POWERSAVE, - }; --static_assert(ARRAY_SIZE(epp_values) == EPP_INDEX_MAX - 1); -+static_assert(ARRAY_SIZE(epp_values) == EPP_INDEX_MAX - 2); - - typedef int (*cppc_mode_transition_fn)(int); - -@@ -462,7 +464,6 @@ static int msr_init_perf(struct amd_cpudata *cpudata) - { - union perf_cached perf = READ_ONCE(cpudata->perf); - u64 cap1, numerator, cppc_req; -- u8 min_perf; - - int ret = rdmsrq_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1, - &cap1); -@@ -478,16 +479,6 @@ static int msr_init_perf(struct amd_cpudata *cpudata) - return ret; - - WRITE_ONCE(cpudata->cppc_req_cached, cppc_req); -- min_perf = FIELD_GET(AMD_CPPC_MIN_PERF_MASK, cppc_req); -- -- /* -- * Clear out the min_perf part to check if the rest of the MSR is 0, if yes, this is an -- * indication that the min_perf value is the one specified through the BIOS option -- */ -- cppc_req &= ~(AMD_CPPC_MIN_PERF_MASK); -- -- if (!cppc_req) -- perf.bios_min_perf = min_perf; - - perf.highest_perf = numerator; - perf.max_limit_perf = numerator; -@@ -495,6 +486,7 @@ static int msr_init_perf(struct amd_cpudata *cpudata) - perf.nominal_perf = FIELD_GET(AMD_CPPC_NOMINAL_PERF_MASK, cap1); - perf.lowest_nonlinear_perf = FIELD_GET(AMD_CPPC_LOWNONLIN_PERF_MASK, cap1); - perf.lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1); -+ perf.bios_min_perf = FIELD_GET(AMD_CPPC_MIN_PERF_MASK, cppc_req); - WRITE_ONCE(cpudata->perf, perf); - WRITE_ONCE(cpudata->prefcore_ranking, FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1)); - WRITE_ONCE(cpudata->floor_perf_cnt, FIELD_GET(AMD_CPPC_FLOOR_PERF_CNT_MASK, cap1)); -@@ -789,6 +781,7 @@ static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, - static void amd_pstate_adjust_perf(struct cpufreq_policy *policy, - unsigned long _min_perf, - unsigned long target_perf, -+ unsigned long _max_perf, - unsigned long capacity) - { - u8 max_perf, min_perf, des_perf, cap_perf; -@@ -1044,6 +1037,13 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) - return -EINVAL; - } - -+ if (perf.bios_min_perf) { -+ u32 bios_min_freq = perf_to_freq(perf, cpudata->nominal_freq, perf.bios_min_perf); -+ -+ pr_debug("Found Requested CPU Min Frequency of %uKHz on CPU%d\n", -+ bios_min_freq, cpudata->cpu); -+ } -+ - return 0; - } - -@@ -1192,6 +1192,24 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb, - return NOTIFY_OK; - } - -+static int amd_pstate_get_epp_from_platform_profile(struct cpufreq_policy *policy, -+ enum platform_profile_option profile) -+{ -+ switch (profile) { -+ case PLATFORM_PROFILE_PERFORMANCE: -+ return AMD_CPPC_EPP_PERFORMANCE; -+ case PLATFORM_PROFILE_BALANCED: -+ return amd_pstate_get_balanced_epp(policy); -+ case PLATFORM_PROFILE_LOW_POWER: -+ return AMD_CPPC_EPP_POWERSAVE; -+ default: -+ break; -+ } -+ -+ pr_err("Unknown Platform Profile %d\n", profile); -+ return -EOPNOTSUPP; -+} -+ - static int amd_pstate_profile_probe(void *drvdata, unsigned long *choices) - { - set_bit(PLATFORM_PROFILE_LOW_POWER, choices); -@@ -1217,31 +1235,19 @@ static int amd_pstate_profile_set(struct device *dev, - struct amd_cpudata *cpudata = dev_get_drvdata(dev); - struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu); - int ret; -+ u8 epp; - - if (!policy) - return -ENODEV; - -- switch (profile) { -- case PLATFORM_PROFILE_LOW_POWER: -- ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_POWERSAVE); -- if (ret) -- return ret; -- break; -- case PLATFORM_PROFILE_BALANCED: -- ret = amd_pstate_set_epp(policy, -- amd_pstate_get_balanced_epp(policy)); -- if (ret) -- return ret; -- break; -- case PLATFORM_PROFILE_PERFORMANCE: -- ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_PERFORMANCE); -- if (ret) -- return ret; -- break; -- default: -- pr_err("Unknown Platform Profile %d\n", profile); -- return -EOPNOTSUPP; -- } -+ ret = amd_pstate_get_epp_from_platform_profile(policy, profile); -+ if (ret < 0) -+ return ret; -+ -+ epp = (u8)ret; -+ ret = amd_pstate_set_epp(policy, epp); -+ if (ret) -+ return ret; - - cpudata->current_profile = profile; - -@@ -1267,28 +1273,20 @@ void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy) - kfree(cpudata->profile_name); - cpudata->dynamic_epp = false; - } --EXPORT_SYMBOL_GPL(amd_pstate_clear_dynamic_epp); -+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_clear_dynamic_epp); - - static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy) - { - struct amd_cpudata *cpudata = policy->driver_data; -+ u64 prev = READ_ONCE(cpudata->cppc_req_cached); - int ret; - u8 epp; - -- switch (cpudata->current_profile) { -- case PLATFORM_PROFILE_PERFORMANCE: -- epp = AMD_CPPC_EPP_PERFORMANCE; -- break; -- case PLATFORM_PROFILE_LOW_POWER: -- epp = AMD_CPPC_EPP_POWERSAVE; -- break; -- case PLATFORM_PROFILE_BALANCED: -- epp = amd_pstate_get_balanced_epp(policy); -- break; -- default: -- pr_err("Unknown Platform Profile %d\n", cpudata->current_profile); -- return -EOPNOTSUPP; -- } -+ ret = amd_pstate_get_epp_from_platform_profile(policy, cpudata->current_profile); -+ if (ret < 0) -+ return ret; -+ -+ epp = (u8)ret; - ret = amd_pstate_set_epp(policy, epp); - if (ret) - return ret; -@@ -1321,6 +1319,9 @@ static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy) - cleanup: - amd_pstate_clear_dynamic_epp(policy); - -+ epp = FIELD_GET(AMD_CPPC_EPP_PERF_MASK, prev); -+ /* Restore previous EPP if toggling Dynamic EPP failed. */ -+ amd_pstate_set_epp(policy, epp); - return ret; - } - -@@ -1391,7 +1392,7 @@ static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy, - static ssize_t show_energy_performance_available_preferences( - struct cpufreq_policy *policy, char *buf) - { -- int offset = 0, i; -+ int i, offset = 0; - struct amd_cpudata *cpudata = policy->driver_data; - - if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) -@@ -1414,11 +1415,6 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, - bool raw_epp = false; - u8 epp; - -- if (cpudata->dynamic_epp) { -- pr_debug("EPP cannot be set when dynamic EPP is enabled\n"); -- return -EBUSY; -- } -- - /* - * if the value matches a number, use that, otherwise see if - * matches an index in the energy_perf_strings array -@@ -1429,6 +1425,25 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, - ret = sysfs_match_string(energy_perf_strings, buf); - if (ret < 0 || ret == EPP_INDEX_CUSTOM) - return -EINVAL; -+ -+ if (ret == EPP_INDEX_DYNAMIC) { -+ if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) -+ return -EBUSY; -+ /* -+ * Dynamic EPP was already enabled for this CPU. -+ * Nothing to do. -+ */ -+ if (cpudata->dynamic_epp) -+ return count; -+ -+ cpudata->current_profile = PLATFORM_PROFILE_BALANCED; -+ ret = amd_pstate_set_dynamic_epp(policy); -+ if (ret) -+ return ret; -+ -+ return count; -+ } -+ - if (ret) - epp = epp_values[ret]; - else -@@ -1440,6 +1455,13 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, - return -EBUSY; - } - -+ /* -+ * Dynamic EPP was enabled previously! -+ * Switch back to the static EPP mode. -+ */ -+ if (cpudata->dynamic_epp) -+ amd_pstate_clear_dynamic_epp(policy); -+ - ret = amd_pstate_set_epp(policy, epp); - if (ret) - return ret; -@@ -1448,7 +1470,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, - - return count; - } --EXPORT_SYMBOL_GPL(store_energy_performance_preference); -+EXPORT_SYMBOL_FOR_PSTATE_UT(store_energy_performance_preference); - - ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf) - { -@@ -1457,7 +1479,7 @@ ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char * - - epp = FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached); - -- if (cpudata->raw_epp) -+ if (!cpudata->dynamic_epp && cpudata->raw_epp) - return sysfs_emit(buf, "%u\n", epp); - - switch (epp) { -@@ -1477,12 +1499,14 @@ ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char * - return -EINVAL; - } - -+ if (cpudata->dynamic_epp) -+ return sysfs_emit(buf, "dynamic(profile:%s)\n", energy_perf_strings[preference]); -+ - return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]); - } --EXPORT_SYMBOL_GPL(show_energy_performance_preference); -+EXPORT_SYMBOL_FOR_PSTATE_UT(show_energy_performance_preference); - --static ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy, -- const char *buf, size_t count) -+ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy, const char *buf, size_t count) - { - struct amd_cpudata *cpudata = policy->driver_data; - union perf_cached perf = READ_ONCE(cpudata->perf); -@@ -1505,13 +1529,15 @@ static ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy, - - return ret ?: count; - } -+EXPORT_SYMBOL_FOR_PSTATE_UT(store_amd_pstate_floor_freq); - --static ssize_t show_amd_pstate_floor_freq(struct cpufreq_policy *policy, char *buf) -+ssize_t show_amd_pstate_floor_freq(struct cpufreq_policy *policy, char *buf) - { - struct amd_cpudata *cpudata = policy->driver_data; - - return sysfs_emit(buf, "%u\n", cpudata->floor_freq); - } -+EXPORT_SYMBOL_FOR_PSTATE_UT(show_amd_pstate_floor_freq); - - static ssize_t show_amd_pstate_floor_count(struct cpufreq_policy *policy, char *buf) - { -@@ -1579,7 +1605,7 @@ struct freq_attr **amd_pstate_get_current_attrs(void) - return NULL; - return current_pstate_driver->attr; - } --EXPORT_SYMBOL_GPL(amd_pstate_get_current_attrs); -+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_get_current_attrs); - - static struct freq_attr **get_freq_attrs(void) - { -@@ -1764,7 +1790,7 @@ int amd_pstate_get_status(void) - { - return cppc_state; - } --EXPORT_SYMBOL_GPL(amd_pstate_get_status); -+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_get_status); - - int amd_pstate_update_status(const char *buf, size_t size) - { -@@ -1784,7 +1810,7 @@ int amd_pstate_update_status(const char *buf, size_t size) - - return 0; - } --EXPORT_SYMBOL_GPL(amd_pstate_update_status); -+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_update_status); - - static ssize_t status_show(struct device *dev, - struct device_attribute *attr, char *buf) -@@ -1812,50 +1838,12 @@ static ssize_t prefcore_show(struct device *dev, - return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore)); - } - --static ssize_t dynamic_epp_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- return sysfs_emit(buf, "%s\n", str_enabled_disabled(dynamic_epp)); --} -- --static ssize_t dynamic_epp_store(struct device *a, struct device_attribute *b, -- const char *buf, size_t count) --{ -- bool enabled; -- int ret; -- -- ret = kstrtobool(buf, &enabled); -- if (ret) -- return ret; -- -- guard(mutex)(&amd_pstate_driver_lock); -- -- if (cppc_state != AMD_PSTATE_ACTIVE) { -- pr_debug("dynamic_epp can only be toggled in active mode\n"); -- return -EINVAL; -- } -- -- /* Nothing to do */ -- if (dynamic_epp == enabled) -- return count; -- -- /* reinitialize with desired dynamic EPP value */ -- dynamic_epp = enabled; -- ret = amd_pstate_change_driver_mode(cppc_state); -- if (ret) -- dynamic_epp = false; -- -- return ret ? ret : count; --} -- - static DEVICE_ATTR_RW(status); - static DEVICE_ATTR_RO(prefcore); --static DEVICE_ATTR_RW(dynamic_epp); - - static struct attribute *pstate_global_attributes[] = { - &dev_attr_status.attr, - &dev_attr_prefcore.attr, -- &dev_attr_dynamic_epp.attr, - NULL - }; - -@@ -1938,12 +1926,13 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) - - policy->boost_supported = READ_ONCE(cpudata->boost_supported); - -- /* Fetch the firmware programmed default EPP value */ -+ /* Cache the firmware programmed EPP */ - default_epp = amd_pstate_get_epp(cpudata); - if (default_epp < 0) { - ret = default_epp; - goto free_cpudata1; - } -+ FIELD_MODIFY(AMD_CPPC_EPP_PERF_MASK, &cpudata->cppc_req_cached, default_epp); - - /* - * Set the policy to provide a valid fallback value in case -@@ -1961,10 +1950,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) - cpudata->current_profile = PLATFORM_PROFILE_BALANCED; - } - -- if (dynamic_epp) -- ret = amd_pstate_set_dynamic_epp(policy); -- else -- ret = amd_pstate_set_epp(policy, cpudata->epp_default_dc); -+ ret = amd_pstate_set_epp(policy, cpudata->epp_default_dc); - if (ret) - goto free_cpudata1; - -@@ -2036,6 +2022,18 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy) - if (!policy->cpuinfo.max_freq) - return -ENODEV; - -+ /* Must be a switch between PERFORMANCE and POWERSAVE */ -+ if (cpudata->policy != policy->policy) { -+ /* -+ * Disable dynamic_epp when switching -+ * out of CPUFREQ_POLICY_POWERSAVE. -+ */ -+ if (cpudata->dynamic_epp) { -+ WARN_ON_ONCE(cpudata->policy != CPUFREQ_POLICY_POWERSAVE); -+ amd_pstate_clear_dynamic_epp(policy); -+ } -+ } -+ - cpudata->policy = policy->policy; - - ret = amd_pstate_epp_update_limit(policy, true); -@@ -2363,19 +2361,8 @@ static int __init amd_prefcore_param(char *str) - return 0; - } - --static int __init amd_dynamic_epp_param(char *str) --{ -- if (!strcmp(str, "disable")) -- dynamic_epp = false; -- if (!strcmp(str, "enable")) -- dynamic_epp = true; -- -- return 0; --} -- - early_param("amd_pstate", amd_pstate_param); - early_param("amd_prefcore", amd_prefcore_param); --early_param("amd_dynamic_epp", amd_dynamic_epp_param); - - MODULE_AUTHOR("Huang Rui "); - MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver"); -diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h ---- a/drivers/cpufreq/amd-pstate.h -+++ b/drivers/cpufreq/amd-pstate.h -@@ -11,6 +11,13 @@ - #include - #include - -+#if IS_MODULE(CONFIG_X86_AMD_PSTATE_UT) -+#define EXPORT_SYMBOL_FOR_PSTATE_UT(symbol) \ -+ EXPORT_SYMBOL_FOR_MODULES(symbol, "amd-pstate-ut") -+#else -+#define EXPORT_SYMBOL_FOR_PSTATE_UT(symbol) -+#endif -+ - /********************************************************************* - * AMD P-state INTERFACE * - *********************************************************************/ -@@ -153,6 +160,8 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy, - const char *buf, size_t count); - ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf); - void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy); -+ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy, const char *buf, size_t count); -+ssize_t show_amd_pstate_floor_freq(struct cpufreq_policy *policy, char *buf); - - struct freq_attr; - -diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c ---- a/drivers/cpufreq/cpufreq.c -+++ b/drivers/cpufreq/cpufreq.c -@@ -2225,14 +2225,17 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch); - * @policy: cpufreq policy object of the target CPU. - * @min_perf: Minimum (required) performance level (units of @capacity). - * @target_perf: Target (desired) performance level (units of @capacity). -+ * @max_perf: Maximum (allowed) performance level (units of @capacity). - * @capacity: Capacity of the target CPU. - * -- * Carry out a fast performance level switch of @cpu without sleeping. -+ * Carry out a fast performance level adjustment for the CPU represented by -+ * @policy without sleeping. - * - * The driver's ->adjust_perf() callback invoked by this function must be -- * suitable for being called from within RCU-sched read-side critical sections -- * and it is expected to select a suitable performance level equal to or above -- * @min_perf and preferably equal to or below @target_perf. -+ * suitable for calling from within RCU-sched read-side critical sections and -+ * it is expected to program the processor to select suitable performance -+ * levels between @min_perf and @max_perf inclusive and preferably close to -+ * @target_perf going forward for the CPU represented by @policy. - * - * This function must not be called if policy->fast_switch_enabled is unset. - * -@@ -2244,9 +2247,10 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch); - void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy, - unsigned long min_perf, - unsigned long target_perf, -+ unsigned long max_perf, - unsigned long capacity) - { -- cpufreq_driver->adjust_perf(policy, min_perf, target_perf, capacity); -+ cpufreq_driver->adjust_perf(policy, min_perf, target_perf, max_perf, capacity); - } - - /** -diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c ---- a/drivers/cpufreq/intel_pstate.c -+++ b/drivers/cpufreq/intel_pstate.c -@@ -299,7 +299,6 @@ struct pstate_funcs { - static struct pstate_funcs pstate_funcs __read_mostly; - - static bool hwp_active __ro_after_init; --static int hwp_mode_bdw __ro_after_init; - static bool per_cpu_limits __ro_after_init; - static bool hwp_forced __ro_after_init; - static bool hwp_boost __read_mostly; -@@ -587,21 +586,14 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) - - hwp_is_hybrid = true; - -- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_pstate * scaling, -- perf_ctl_scaling); -- cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling, -- perf_ctl_scaling); -- - freq = perf_ctl_max_phys * perf_ctl_scaling; - cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq); - -- freq = cpu->pstate.min_pstate * perf_ctl_scaling; -- cpu->pstate.min_freq = freq; - /* - * Cast the min P-state value retrieved via pstate_funcs.get_min() to - * the effective range of HWP performance levels. - */ -- cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq); -+ cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, cpu->pstate.min_freq); - } - - static bool turbo_is_disabled(void) -@@ -979,12 +971,10 @@ static int hybrid_get_cost(struct device *dev, unsigned long freq, - * capacity. Similarly, P-cores start to be populated when E-cores are - * utilized above 60% of the capacity. - */ -- if (hybrid_get_cpu_type(dev->id) == INTEL_CPU_TYPE_ATOM) { -- if (hybrid_has_l3(dev->id)) /* E-core */ -- *cost += 1; -- } else { /* P-core */ -+ if (hybrid_get_cpu_type(dev->id) == INTEL_CPU_TYPE_CORE) /* P-core */ - *cost += 2; -- } -+ else if (hybrid_has_l3(dev->id)) /* E-core */ -+ *cost += 1; - - return 0; - } -@@ -1185,6 +1175,22 @@ static bool hybrid_clear_max_perf_cpu(void) - return ret; - } - -+static void intel_pstate_update_freq_limits(struct cpudata *cpu) -+{ -+ int scaling = cpu->pstate.scaling; -+ unsigned int turbo_freq = cpu->pstate.turbo_pstate * scaling; -+ unsigned int max_freq = cpu->pstate.max_pstate * scaling; -+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling; -+ -+ if (scaling != perf_ctl_scaling) { -+ turbo_freq = rounddown(turbo_freq, perf_ctl_scaling); -+ max_freq = rounddown(max_freq, perf_ctl_scaling); -+ } -+ -+ cpu->pstate.turbo_freq = turbo_freq; -+ cpu->pstate.max_freq = max_freq; -+} -+ - static void __intel_pstate_get_hwp_cap(struct cpudata *cpu) - { - u64 cap; -@@ -1197,20 +1203,8 @@ static void __intel_pstate_get_hwp_cap(struct cpudata *cpu) - - static void intel_pstate_get_hwp_cap(struct cpudata *cpu) - { -- int scaling = cpu->pstate.scaling; -- - __intel_pstate_get_hwp_cap(cpu); -- -- cpu->pstate.max_freq = cpu->pstate.max_pstate * scaling; -- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling; -- if (scaling != cpu->pstate.perf_ctl_scaling) { -- int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling; -- -- cpu->pstate.max_freq = rounddown(cpu->pstate.max_freq, -- perf_ctl_scaling); -- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_freq, -- perf_ctl_scaling); -- } -+ intel_pstate_update_freq_limits(cpu); - } - - static void hybrid_update_capacity(struct cpudata *cpu) -@@ -2299,33 +2293,16 @@ static int hwp_get_cpu_scaling(int cpu) - return intel_pstate_cppc_get_scaling(cpu); - } - --static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) --{ -- trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu); -- cpu->pstate.current_pstate = pstate; -- /* -- * Generally, there is no guarantee that this code will always run on -- * the CPU being updated, so force the register update to run on the -- * right CPU. -- */ -- wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL, -- pstate_funcs.get_val(cpu, pstate)); --} -- --static void intel_pstate_set_min_pstate(struct cpudata *cpu) --{ -- intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); --} -- - static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) - { - int perf_ctl_scaling = pstate_funcs.get_scaling(); - - cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical(cpu->cpu); - cpu->pstate.min_pstate = pstate_funcs.get_min(cpu->cpu); -+ cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling; - cpu->pstate.perf_ctl_scaling = perf_ctl_scaling; - -- if (hwp_active && !hwp_mode_bdw) { -+ if (hwp_active) { - __intel_pstate_get_hwp_cap(cpu); - - if (pstate_funcs.get_cpu_scaling) { -@@ -2345,11 +2322,7 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) - cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu); - } - -- if (cpu->pstate.scaling == perf_ctl_scaling) { -- cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling; -- cpu->pstate.max_freq = cpu->pstate.max_pstate * perf_ctl_scaling; -- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * perf_ctl_scaling; -- } -+ intel_pstate_update_freq_limits(cpu); - - if (pstate_funcs.get_aperf_mperf_shift) - cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift(); -@@ -2882,8 +2855,22 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu, - cpu->min_perf_ratio); - } - -+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) -+{ -+ trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu); -+ cpu->pstate.current_pstate = pstate; -+ /* -+ * Generally, there is no guarantee that this code will always run on -+ * the CPU being updated, so force the register update to run on the -+ * right CPU. -+ */ -+ wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL, -+ pstate_funcs.get_val(cpu, pstate)); -+} -+ - static int intel_pstate_set_policy(struct cpufreq_policy *policy) - { -+ unsigned int freq = policy->min; - struct cpudata *cpu; - - if (!policy->cpuinfo.max_freq) -@@ -2899,7 +2886,23 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) - - intel_pstate_update_perf_limits(cpu, policy->min, policy->max); - -- if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) { -+ if (hwp_active) { -+ /* -+ * The active mode only requires an update util hook if HWP -+ * boost is used and the policy is not "performance". -+ */ -+ if (hwp_boost && cpu->policy != CPUFREQ_POLICY_PERFORMANCE) { -+ intel_pstate_set_update_util_hook(policy->cpu); -+ } else { -+ intel_pstate_clear_update_util_hook(policy->cpu); -+ if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) { -+ freq = cpu->max_perf_ratio * cpu->pstate.scaling; -+ if (cpu->pstate.scaling != cpu->pstate.perf_ctl_scaling) -+ freq = rounddown(freq, cpu->pstate.perf_ctl_scaling); -+ } -+ } -+ intel_pstate_hwp_set(policy->cpu); -+ } else if (cpu->policy == CPUFREQ_POLICY_PERFORMANCE) { - int pstate = max(cpu->pstate.min_pstate, cpu->max_perf_ratio); - - /* -@@ -2908,25 +2911,17 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) - */ - intel_pstate_clear_update_util_hook(policy->cpu); - intel_pstate_set_pstate(cpu, pstate); -+ freq = pstate * cpu->pstate.scaling; - } else { - intel_pstate_set_update_util_hook(policy->cpu); - } -- -- if (hwp_active) { -- /* -- * When hwp_boost was active before and dynamically it -- * was turned off, in that case we need to clear the -- * update util hook. -- */ -- if (!hwp_boost) -- intel_pstate_clear_update_util_hook(policy->cpu); -- intel_pstate_hwp_set(policy->cpu); -- } - /* -- * policy->cur is never updated with the intel_pstate driver, but it -- * is used as a stale frequency value. So, keep it within limits. -+ * policy->cur is never updated in the intel_pstate driver, but it is -+ * used as a stale frequency value, so set it to reflect the actual -+ * requested P-state in the "performance" policy case and to the min -+ * otherwise. - */ -- policy->cur = policy->min; -+ policy->cur = freq; - - mutex_unlock(&intel_pstate_limits_lock); - -@@ -2969,6 +2964,11 @@ static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy) - return 0; - } - -+static void intel_pstate_set_min_pstate(struct cpudata *cpu) -+{ -+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); -+} -+ - static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy) - { - struct cpudata *cpu = all_cpu_data[policy->cpu]; -@@ -3242,6 +3242,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, - static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy, - unsigned long min_perf, - unsigned long target_perf, -+ unsigned long max_perf, - unsigned long capacity) - { - struct cpudata *cpu = all_cpu_data[policy->cpu]; -@@ -3272,7 +3273,13 @@ static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy, - if (min_pstate > cpu->max_perf_ratio) - min_pstate = cpu->max_perf_ratio; - -- max_pstate = min(cap_pstate, cpu->max_perf_ratio); -+ max_pstate = cap_pstate; -+ if (max_perf < capacity) -+ max_pstate = DIV_ROUND_UP(cap_pstate * max_perf, capacity); -+ -+ if (max_pstate > cpu->max_perf_ratio) -+ max_pstate = cpu->max_perf_ratio; -+ - if (max_pstate < min_pstate) - max_pstate = min_pstate; - -@@ -3679,14 +3686,14 @@ static inline bool intel_pstate_has_acpi_ppc(void) { return false; } - static inline void intel_pstate_request_control_from_smm(void) {} - #endif /* CONFIG_ACPI */ - --#define INTEL_PSTATE_HWP_BROADWELL 0x01 -+#define INTEL_PSTATE_HWP_NOT_HYBRID 0x01 - - #define X86_MATCH_HWP(vfm, hwp_mode) \ - X86_MATCH_VFM_FEATURE(vfm, X86_FEATURE_HWP, hwp_mode) - - static const struct x86_cpu_id hwp_support_ids[] __initconst = { -- X86_MATCH_HWP(INTEL_BROADWELL_X, INTEL_PSTATE_HWP_BROADWELL), -- X86_MATCH_HWP(INTEL_BROADWELL_D, INTEL_PSTATE_HWP_BROADWELL), -+ X86_MATCH_HWP(INTEL_BROADWELL_X, INTEL_PSTATE_HWP_NOT_HYBRID), -+ X86_MATCH_HWP(INTEL_BROADWELL_D, INTEL_PSTATE_HWP_NOT_HYBRID), - X86_MATCH_HWP(INTEL_ANY, 0), - {} - }; -@@ -3811,7 +3818,6 @@ static int __init intel_pstate_init(void) - - if (!no_hwp) { - hwp_active = true; -- hwp_mode_bdw = id->driver_data; - intel_pstate.attr = hwp_cpufreq_attrs; - intel_cpufreq.attr = hwp_cpufreq_attrs; - intel_cpufreq.flags |= CPUFREQ_NEED_UPDATE_LIMITS; -@@ -3819,7 +3825,8 @@ static int __init intel_pstate_init(void) - if (!default_driver) - default_driver = &intel_pstate; - -- pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling; -+ if (!id->driver_data) -+ pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling; - - goto hwp_cpu_matched; - } -diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c ---- a/drivers/idle/intel_idle.c -+++ b/drivers/idle/intel_idle.c -@@ -1780,6 +1780,7 @@ module_param_named(no_native, no_native, bool, 0444); - MODULE_PARM_DESC(no_native, "Ignore cpu specific (native) idle states in lieu of ACPI idle states"); - - static struct acpi_processor_power acpi_state_table __initdata; -+static bool acpi_lpi_available __initdata; - - /** - * intel_idle_cst_usable - Check if the _CST information can be used. -@@ -1804,18 +1805,37 @@ static bool __init intel_idle_cst_usable(void) - return true; - } - --static bool __init intel_idle_acpi_cst_extract(void) -+static bool __init intel_idle_acpi_extract_lpi_cstates(void) - { - unsigned int cpu; - -- if (no_acpi) { -- pr_debug("Not allowed to use ACPI _CST\n"); -- return false; -+ for_each_possible_cpu(cpu) { -+ struct acpi_processor *pr; -+ -+ pr = per_cpu(processors, cpu); -+ if (!pr) -+ continue; -+ -+ if (acpi_processor_extract_lpi_info(pr->handle, -+ &acpi_state_table, true)) -+ continue; -+ -+ acpi_lpi_available = true; -+ return true; - } - -- for_each_possible_cpu(cpu) { -- struct acpi_processor *pr = per_cpu(processors, cpu); -+ pr_debug("No ACPI _LPI idle states\n"); -+ return false; -+} - -+static bool __init intel_idle_acpi_extract_cst_cstates(void) -+{ -+ unsigned int cpu; -+ -+ for_each_possible_cpu(cpu) { -+ struct acpi_processor *pr; -+ -+ pr = per_cpu(processors, cpu); - if (!pr) - continue; - -@@ -1827,18 +1847,96 @@ static bool __init intel_idle_acpi_cst_extract(void) - if (!intel_idle_cst_usable()) - continue; - -- if (!acpi_processor_claim_cst_control()) -- break; -- - return true; - } - -- acpi_state_table.count = 0; - pr_debug("ACPI _CST not found or not usable\n"); - return false; - } - --static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) -+static bool __init intel_idle_acpi_extract_cstates(void) -+{ -+ if (intel_idle_acpi_extract_lpi_cstates()) -+ return true; -+ -+ if (intel_idle_acpi_extract_cst_cstates()) -+ return true; -+ -+ return false; -+} -+ -+static bool __init intel_idle_acpi_probe(void) -+{ -+ if (no_acpi) { -+ pr_debug("Not allowed to use ACPI for C-states extraction\n"); -+ return false; -+ } -+ -+ if (intel_idle_acpi_extract_cstates() && -+ acpi_processor_claim_cst_control()) -+ return true; -+ -+ acpi_state_table.count = 0; -+ return false; -+} -+ -+static void __init intel_idle_complete_state_init(struct cpuidle_state *state) -+{ -+ if (intel_idle_state_needs_timer_stop(state)) -+ state->flags |= CPUIDLE_FLAG_TIMER_STOP; -+ -+ state->enter = intel_idle; -+ state->enter_dead = intel_idle_enter_dead; -+ state->enter_s2idle = intel_idle_s2idle; -+} -+ -+static void __init intel_idle_init_cstates_acpi_lpi(struct cpuidle_driver *drv) -+{ -+ int index; -+ -+ for (index = 0; index < acpi_state_table.count; index++) { -+ struct acpi_lpi_state *lpi_state; -+ struct cpuidle_state *state; -+ -+ if (intel_idle_max_cstate_reached(index)) -+ break; -+ -+ lpi_state = &acpi_state_table.lpi_states[index]; -+ -+ state = &drv->states[drv->state_count++]; -+ -+ scnprintf(state->name, CPUIDLE_NAME_LEN, "C%d_LPI", index + 1); -+ strscpy(state->desc, lpi_state->desc, CPUIDLE_DESC_LEN); -+ state->exit_latency = lpi_state->wake_latency; -+ state->target_residency = lpi_state->min_residency; -+ state->flags = MWAIT2flg(lpi_state->address); -+ /* -+ * Assume that entering any of the idle states extracted from -+ * _LPI except for the first two will cause the TLB to be -+ * flushed and let the core call leave_mm() for them upfront -+ * to avoid unnecessary wakeups due to TLB shootdowns. -+ */ -+ if (index > 1) -+ state->flags |= CPUIDLE_FLAG_TLB_FLUSHED; -+ -+ if (disabled_states_mask & BIT(index + 1)) -+ state->flags |= CPUIDLE_FLAG_OFF; -+ -+ intel_idle_complete_state_init(state); -+ -+ pr_info("%s: MWAIT hint 0x%x\n", state->name, flg2MWAIT(state->flags)); -+ } -+ -+ /* -+ * Assume the first idle state in the table to be C1 and if any deeper -+ * idle states are exposed while X86_FEATURE_NONSTOP_TSC is unset, mark -+ * the TSC as unstable. -+ */ -+ if (index > 1 && !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) -+ mark_tsc_unstable("TSC halts in idle"); -+} -+ -+static void __init intel_idle_init_cstates_acpi_cst(struct cpuidle_driver *drv) - { - int cstate, limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count); - -@@ -1880,49 +1978,76 @@ static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) - if (disabled_states_mask & BIT(cstate)) - state->flags |= CPUIDLE_FLAG_OFF; - -- if (intel_idle_state_needs_timer_stop(state)) -- state->flags |= CPUIDLE_FLAG_TIMER_STOP; -- - if (cx->type > ACPI_STATE_C1 && !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) - mark_tsc_unstable("TSC halts in idle"); - -- state->enter = intel_idle; -- state->enter_dead = intel_idle_enter_dead; -- state->enter_s2idle = intel_idle_s2idle; -+ intel_idle_complete_state_init(state); - } - } - --static bool __init intel_idle_off_by_default(unsigned int flags, u32 mwait_hint) -+static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) - { -- int cstate, limit; -+ if (acpi_lpi_available) -+ intel_idle_init_cstates_acpi_lpi(drv); -+ else -+ intel_idle_init_cstates_acpi_cst(drv); -+} - -- /* -- * If there are no _CST C-states, do not disable any C-states by -- * default. -- */ -- if (!acpi_state_table.count) -- return false; -+static bool __init intel_idle_acpi_hint_match(unsigned int flags, u32 acpi_hint, -+ u32 table_hint) -+{ -+ if (flags & CPUIDLE_FLAG_PARTIAL_HINT_MATCH) { -+ acpi_hint &= ~MWAIT_SUBSTATE_MASK; -+ table_hint &= ~MWAIT_SUBSTATE_MASK; -+ } -+ return acpi_hint == table_hint; -+} -+ -+static bool __init intel_idle_off_by_default_lpi(unsigned int flags, u32 mwait_hint) -+{ -+ int index; -+ -+ for (index = 0; index < acpi_state_table.count; index++) { -+ u32 acpi_hint = acpi_state_table.lpi_states[index].address; -+ -+ if (intel_idle_acpi_hint_match(flags, acpi_hint, mwait_hint)) -+ return false; -+ } -+ return true; -+} -+ -+static bool __init intel_idle_off_by_default_cst(unsigned int flags, u32 mwait_hint) -+{ -+ int cstate, limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count); - -- limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count); - /* - * If limit > 0, intel_idle_cst_usable() has returned 'true', so all of - * the interesting states are ACPI_CSTATE_FFH. - */ - for (cstate = 1; cstate < limit; cstate++) { - u32 acpi_hint = acpi_state_table.states[cstate].address; -- u32 table_hint = mwait_hint; - -- if (flags & CPUIDLE_FLAG_PARTIAL_HINT_MATCH) { -- acpi_hint &= ~MWAIT_SUBSTATE_MASK; -- table_hint &= ~MWAIT_SUBSTATE_MASK; -- } -- -- if (acpi_hint == table_hint) -+ if (intel_idle_acpi_hint_match(flags, acpi_hint, mwait_hint)) - return false; - } - return true; - } - -+static bool __init intel_idle_off_by_default(unsigned int flags, u32 mwait_hint) -+{ -+ /* -+ * If there is no C-states information in the ACPI tables, do not -+ * disable any C-states by default. -+ */ -+ if (!acpi_state_table.count) -+ return false; -+ -+ if (acpi_lpi_available) -+ return intel_idle_off_by_default_lpi(flags, mwait_hint); -+ -+ return intel_idle_off_by_default_cst(flags, mwait_hint); -+} -+ - static inline bool ignore_native(void) - { - return no_native && !no_acpi; -@@ -1930,7 +2055,7 @@ static inline bool ignore_native(void) - #else /* !CONFIG_ACPI_PROCESSOR_CSTATE */ - #define force_use_acpi (false) - --static inline bool intel_idle_acpi_cst_extract(void) { return false; } -+static inline bool intel_idle_acpi_probe(void) { return false; } - static inline void intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) { } - static inline bool intel_idle_off_by_default(unsigned int flags, u32 mwait_hint) - { -@@ -2745,7 +2870,7 @@ static int __init intel_idle_init(void) - if (icpu) { - if (icpu->state_table) - cpuidle_state_table = icpu->state_table; -- else if (!intel_idle_acpi_cst_extract()) -+ else if (!intel_idle_acpi_probe()) - return -ENODEV; - - auto_demotion_disable_flags = icpu->auto_demotion_disable_flags; -@@ -2754,8 +2879,8 @@ static int __init intel_idle_init(void) - if (icpu->c1_demotion_supported) - c1_demotion_supported = true; - if (icpu->use_acpi || force_use_acpi) -- intel_idle_acpi_cst_extract(); -- } else if (!intel_idle_acpi_cst_extract()) { -+ intel_idle_acpi_probe(); -+ } else if (!intel_idle_acpi_probe()) { - return -ENODEV; - } - -diff --git a/drivers/opp/core.c b/drivers/opp/core.c ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -1581,8 +1581,6 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, - struct opp_table *opp_table, - bool getclk) - { -- int ret; -- - /* - * Return early if we don't need to get clk or we have already done it - * earlier. -@@ -1591,39 +1589,35 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, - opp_table->clks) - return opp_table; - -- /* Find clk for the device */ -- opp_table->clk = clk_get(dev, NULL); -+ /* -+ * There are few platforms which don't want the OPP core to manage -+ * device's clock settings. In such cases neither the platform -+ * provides the clks explicitly to us, nor the DT contains a valid -+ * clk entry. The OPP nodes in DT may still contain "opp-hz" property -+ * though, which we need to parse and allow the platform to find an -+ * OPP based on freq later on. -+ * -+ * This is a simple solution to take care of such corner cases, i.e. -+ * make the clk_count 1, which lets us allocate space for frequency -+ * in opp->rates and also parse the entries in DT. Use -+ * clk_get_optional() instead of clk_get() so opp_table->clk stays -+ * NULL for such devices, instead of holding an ERR_PTR(-ENOENT) that -+ * consumers must remember to special-case. -+ */ -+ opp_table->clk = clk_get_optional(dev, NULL); - -- ret = PTR_ERR_OR_ZERO(opp_table->clk); -- if (!ret) { -+ if (IS_ERR(opp_table->clk)) { -+ dev_pm_opp_put_opp_table(opp_table); -+ dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n"); -+ return ERR_CAST(opp_table->clk); -+ } -+ -+ if (opp_table->clk) - opp_table->config_clks = _opp_config_clk_single; -- opp_table->clk_count = 1; -- return opp_table; -- } - -- if (ret == -ENOENT) { -- /* -- * There are few platforms which don't want the OPP core to -- * manage device's clock settings. In such cases neither the -- * platform provides the clks explicitly to us, nor the DT -- * contains a valid clk entry. The OPP nodes in DT may still -- * contain "opp-hz" property though, which we need to parse and -- * allow the platform to find an OPP based on freq later on. -- * -- * This is a simple solution to take care of such corner cases, -- * i.e. make the clk_count 1, which lets us allocate space for -- * frequency in opp->rates and also parse the entries in DT. -- */ -- opp_table->clk_count = 1; -+ opp_table->clk_count = 1; - -- dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret); -- return opp_table; -- } -- -- dev_pm_opp_put_opp_table(opp_table); -- dev_err_probe(dev, ret, "Couldn't find clock\n"); -- -- return ERR_PTR(ret); -+ return opp_table; - } - - /* -diff --git a/include/linux/acpi.h b/include/linux/acpi.h ---- a/include/linux/acpi.h -+++ b/include/linux/acpi.h -@@ -315,6 +315,19 @@ static inline int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, - } - #endif - -+#ifdef CONFIG_ACPI_PROCESSOR_IDLE -+int acpi_processor_extract_lpi_info(acpi_handle pr_handle, -+ struct acpi_processor_power *pr_power, -+ bool strict); -+#else -+static inline int acpi_processor_extract_lpi_info(acpi_handle pr_handle, -+ struct acpi_processor_power *pr_power, -+ bool strict) -+{ -+ return -ENODEV; -+} -+#endif -+ - #ifdef CONFIG_ACPI_HOTPLUG_CPU - /* Arch dependent functions for cpu hotplug support */ - int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, -diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h ---- a/include/linux/cpufreq.h -+++ b/include/linux/cpufreq.h -@@ -379,6 +379,7 @@ struct cpufreq_driver { - void (*adjust_perf)(struct cpufreq_policy *policy, - unsigned long min_perf, - unsigned long target_perf, -+ unsigned long max_perf, - unsigned long capacity); - - /* -@@ -624,6 +625,7 @@ unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, - void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy, - unsigned long min_perf, - unsigned long target_perf, -+ unsigned long max_perf, - unsigned long capacity); - bool cpufreq_driver_has_adjust_perf(void); - int cpufreq_driver_target(struct cpufreq_policy *policy, -diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig ---- a/kernel/power/Kconfig -+++ b/kernel/power/Kconfig -@@ -268,6 +268,16 @@ config DPM_WATCHDOG - captured in pstore device for inspection in subsequent - boot session. - -+config DPM_WATCHDOG_ENABLED -+ bool "Enable DPM watchdog by default" -+ depends on DPM_WATCHDOG -+ default y -+ help -+ If you say Y here, the DPM watchdog will be enabled by default. -+ If you say N, it will be compiled in but disabled. It can be -+ enabled at boot time via the "pm.dpm_watchdog_enabled" kernel -+ parameter or at runtime via sysfs. -+ - config DPM_WATCHDOG_TIMEOUT - int "Watchdog timeout to panic in seconds" - range 1 120 -diff --git a/kernel/power/swap.c b/kernel/power/swap.c ---- a/kernel/power/swap.c -+++ b/kernel/power/swap.c -@@ -430,19 +430,22 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, - - if (!handle->cur) - return -EINVAL; -- offset = alloc_swapdev_block(root_swap); -- error = write_page(buf, offset, hb); -- if (error) -- return error; -- handle->cur->entries[handle->k++] = offset; -+ -+ /* -+ * If the current map page is full, allocate and link next one first. -+ * Delaying this until here avoids writing an empty swap map page when -+ * the image size is an exact MAP_PAGE_ENTRIES multiple. -+ */ - if (handle->k >= MAP_PAGE_ENTRIES) { - offset = alloc_swapdev_block(root_swap); - if (!offset) - return -ENOSPC; -+ - handle->cur->next_swap = offset; - error = write_page(handle->cur, handle->cur_swap, hb); - if (error) -- goto out; -+ return error; -+ - clear_page(handle->cur); - handle->cur_swap = offset; - handle->k = 0; -@@ -450,7 +453,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, - if (hb && low_free_pages() <= handle->reqd_free_pages) { - error = hib_wait_io(hb); - if (error) -- goto out; -+ return error; - /* - * Recalculate the number of required free pages, to - * make sure we never take more than half. -@@ -458,14 +461,21 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, - handle->reqd_free_pages = reqd_free_pages(); - } - } -- out: -- return error; -+ -+ offset = alloc_swapdev_block(root_swap); -+ error = write_page(buf, offset, hb); -+ if (error) -+ return error; -+ handle->cur->entries[handle->k++] = offset; -+ return 0; - } - - static int flush_swap_writer(struct swap_map_handle *handle) - { -- if (handle->cur && handle->cur_swap) -+ if (handle->cur && handle->cur_swap && handle->k) - return write_page(handle->cur, handle->cur_swap, NULL); -+ else if (handle->cur && handle->cur_swap) -+ return 0; - else - return -EINVAL; - } -@@ -739,7 +749,7 @@ static int save_compressed_image(struct swap_map_handle *handle, - - data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR_OR_NULL(data[thr].cc)) { -- pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc)); -+ pr_err("Could not allocate comp stream %pe\n", data[thr].cc); - ret = -EFAULT; - goto out_clean; - } -@@ -1243,7 +1253,7 @@ static int load_compressed_image(struct swap_map_handle *handle, - - data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR_OR_NULL(data[thr].cc)) { -- pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc)); -+ pr_err("Could not allocate comp stream %pe\n", data[thr].cc); - ret = -EFAULT; - goto out_clean; - } -diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c ---- a/kernel/sched/cpufreq_schedutil.c -+++ b/kernel/sched/cpufreq_schedutil.c -@@ -50,6 +50,7 @@ struct sugov_cpu { - - unsigned long util; - unsigned long bw_min; -+ unsigned long bw_max; - - /* The field below is for single-CPU policies only: */ - #ifdef CONFIG_NO_HZ_COMMON -@@ -243,6 +244,7 @@ static void sugov_get_util(struct sugov_cpu *sg_cpu, unsigned long boost) - util = effective_cpu_util(sg_cpu->cpu, util, &min, &max); - util = max(util, boost); - sg_cpu->bw_min = min; -+ sg_cpu->bw_max = max; - sg_cpu->util = sugov_effective_cpu_perf(sg_cpu->cpu, util, min, max); - } - -@@ -495,7 +497,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time, - sg_cpu->util = prev_util; - - cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min, -- sg_cpu->util, max_cap); -+ sg_cpu->util, sg_cpu->bw_max, max_cap); - - sg_policy->need_freq_update = false; - sg_policy->last_freq_update_time = time; -@@ -601,7 +603,7 @@ static ssize_t rate_limit_us_show(struct gov_attr_set *attr_set, char *buf) - { - struct sugov_tunables *tunables = to_sugov_tunables(attr_set); - -- return sprintf(buf, "%u\n", tunables->rate_limit_us); -+ return sysfs_emit(buf, "%u\n", tunables->rate_limit_us); - } - - static ssize_t -diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs ---- a/rust/kernel/cpufreq.rs -+++ b/rust/kernel/cpufreq.rs -@@ -797,7 +797,13 @@ pub trait Driver { - } - - /// Driver's `adjust_perf` callback. -- fn adjust_perf(_policy: &mut Policy, _min_perf: usize, _target_perf: usize, _capacity: usize) { -+ fn adjust_perf( -+ _policy: &mut Policy, -+ _min_perf: usize, -+ _target_perf: usize, -+ _max_perf: usize, -+ _capacity: usize, -+ ) { - build_error!(VTABLE_DEFAULT_ERROR) - } - -@@ -1270,12 +1276,13 @@ impl Registration { - ptr: *mut bindings::cpufreq_policy, - min_perf: c_ulong, - target_perf: c_ulong, -+ max_perf: c_ulong, - capacity: c_ulong, - ) { - // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the - // lifetime of `policy`. - let policy = unsafe { Policy::from_raw_mut(ptr) }; -- T::adjust_perf(policy, min_perf, target_perf, capacity); -+ T::adjust_perf(policy, min_perf, target_perf, max_perf, capacity); - } - - /// Driver's `get_intermediate` callback. diff --git a/kernel/0210-pm-updates.patch.sig b/kernel/0210-pm-updates.patch.sig deleted file mode 100644 index 4f4c8b3..0000000 Binary files a/kernel/0210-pm-updates.patch.sig and /dev/null differ diff --git a/kernel/0211-pm-fixes-1.patch b/kernel/0211-pm-fixes-1.patch deleted file mode 100644 index ed2d0f5..0000000 --- a/kernel/0211-pm-fixes-1.patch +++ /dev/null @@ -1,104 +0,0 @@ -diff --git a/drivers/opp/core.c b/drivers/opp/core.c ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -453,8 +453,8 @@ int dev_pm_opp_get_opp_count(struct device *dev) - _find_opp_table(dev); - - if (IS_ERR(opp_table)) { -- dev_dbg(dev, "%s: OPP table not found (%ld)\n", -- __func__, PTR_ERR(opp_table)); -+ dev_dbg(dev, "%s: OPP table not found (%pe)\n", -+ __func__, opp_table); - return PTR_ERR(opp_table); - } - -@@ -611,8 +611,8 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available, - _find_opp_table(dev); - - if (IS_ERR(opp_table)) { -- dev_err(dev, "%s: OPP table not found (%ld)\n", __func__, -- PTR_ERR(opp_table)); -+ dev_err(dev, "%s: OPP table not found (%pe)\n", __func__, -+ opp_table); - return ERR_CAST(opp_table); - } - -@@ -722,8 +722,8 @@ struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, - struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev); - - if (IS_ERR(opp_table)) { -- dev_err(dev, "%s: OPP table not found (%ld)\n", __func__, -- PTR_ERR(opp_table)); -+ dev_err(dev, "%s: OPP table not found (%pe)\n", __func__, -+ opp_table); - return ERR_CAST(opp_table); - } - -@@ -1036,8 +1036,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, - - /* Regulator not available for device */ - if (IS_ERR(reg)) { -- dev_dbg(dev, "%s: regulator not available: %ld\n", __func__, -- PTR_ERR(reg)); -+ dev_dbg(dev, "%s: regulator not available: %pe\n", __func__, -+ reg); - return 0; - } - -@@ -1448,8 +1448,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) - temp_freq = freq; - opp = _find_freq_ceil(opp_table, &temp_freq); - if (IS_ERR(opp)) { -- dev_err(dev, "%s: failed to find OPP for freq %lu (%ld)\n", -- __func__, freq, PTR_ERR(opp)); -+ dev_err(dev, "%s: failed to find OPP for freq %lu (%pe)\n", -+ __func__, freq, opp); - return PTR_ERR(opp); - } - -@@ -1581,6 +1581,8 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, - struct opp_table *opp_table, - bool getclk) - { -+ int ret; -+ - /* - * Return early if we don't need to get clk or we have already done it - * earlier. -@@ -1607,9 +1609,9 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, - opp_table->clk = clk_get_optional(dev, NULL); - - if (IS_ERR(opp_table->clk)) { -+ ret = dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n"); - dev_pm_opp_put_opp_table(opp_table); -- dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n"); -- return ERR_CAST(opp_table->clk); -+ return ERR_PTR(ret); - } - - if (opp_table->clk) -@@ -2869,8 +2871,8 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, - struct dev_pm_opp *opp __free(put_opp) = ERR_PTR(-ENODEV), *tmp_opp; - - if (IS_ERR(opp_table)) { -- dev_warn(dev, "%s: Device OPP not found (%ld)\n", __func__, -- PTR_ERR(opp_table)); -+ dev_warn(dev, "%s: Device OPP not found (%pe)\n", __func__, -+ opp_table); - return PTR_ERR(opp_table); - } - -diff --git a/drivers/opp/of.c b/drivers/opp/of.c ---- a/drivers/opp/of.c -+++ b/drivers/opp/of.c -@@ -1345,8 +1345,8 @@ int of_get_required_opp_performance_state(struct device_node *np, int index) - _find_table_of_opp_np(required_np); - - if (IS_ERR(opp_table)) { -- pr_err("%s: Failed to find required OPP table %pOF: %ld\n", -- __func__, np, PTR_ERR(opp_table)); -+ pr_err("%s: Failed to find required OPP table %pOF: %pe\n", -+ __func__, np, opp_table); - return PTR_ERR(opp_table); - } - diff --git a/kernel/0211-pm-fixes-1.patch.sig b/kernel/0211-pm-fixes-1.patch.sig deleted file mode 100644 index 3282089..0000000 Binary files a/kernel/0211-pm-fixes-1.patch.sig and /dev/null differ diff --git a/kernel/0212-pm-fixes-2.patch b/kernel/0212-pm-fixes-2.patch deleted file mode 100644 index 0e9c073..0000000 --- a/kernel/0212-pm-fixes-2.patch +++ /dev/null @@ -1,54 +0,0 @@ -diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c ---- a/kernel/power/hibernate.c -+++ b/kernel/power/hibernate.c -@@ -408,9 +408,18 @@ int hibernation_snapshot(int platform_mode) - if (error) - goto Close; - -+ error = dpm_prepare(PMSG_FREEZE); -+ if (error) -+ goto Complete; -+ -+ /* Preallocate image memory before freezing kernel threads and shutting down devices. */ -+ error = hibernate_preallocate_memory(); -+ if (error) -+ goto Complete; -+ - error = freeze_kernel_threads(); - if (error) -- goto Close; -+ goto Cleanup; - - if (hibernation_test(TEST_FREEZER)) { - -@@ -422,15 +431,6 @@ int hibernation_snapshot(int platform_mode) - goto Thaw; - } - -- error = dpm_prepare(PMSG_FREEZE); -- if (error) -- goto Complete; -- -- /* Preallocate image memory before shutting down devices. */ -- error = hibernate_preallocate_memory(); -- if (error) -- goto Complete; -- - console_suspend_all(); - pm_restrict_gfp_mask(); - -@@ -464,10 +464,12 @@ int hibernation_snapshot(int platform_mode) - platform_end(platform_mode); - return error; - -- Complete: -- dpm_complete(PMSG_RECOVER); - Thaw: - thaw_kernel_threads(); -+ Cleanup: -+ swsusp_free(); -+ Complete: -+ dpm_complete(PMSG_RECOVER); - goto Close; - } - diff --git a/kernel/0212-pm-fixes-2.patch.sig b/kernel/0212-pm-fixes-2.patch.sig deleted file mode 100644 index 679057c..0000000 Binary files a/kernel/0212-pm-fixes-2.patch.sig and /dev/null differ diff --git a/kernel/0213-pm-fixes-3.patch b/kernel/0213-pm-fixes-3.patch deleted file mode 100644 index e8c1523..0000000 --- a/kernel/0213-pm-fixes-3.patch +++ /dev/null @@ -1,61 +0,0 @@ -diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c ---- a/drivers/cpufreq/cpufreq.c -+++ b/drivers/cpufreq/cpufreq.c -@@ -2590,8 +2590,8 @@ static void cpufreq_update_pressure(struct cpufreq_policy *policy) - - cpu = cpumask_first(policy->related_cpus); - max_freq = arch_scale_freq_ref(cpu); -- if (!max_freq) -- max_freq = policy->cpuinfo.max_freq; -+ if (!max_freq && cpufreq_driver->scale_freq_ref) -+ max_freq = cpufreq_driver->scale_freq_ref(policy); - - capped_freq = policy->max; - -diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c ---- a/drivers/cpufreq/intel_pstate.c -+++ b/drivers/cpufreq/intel_pstate.c -@@ -1175,6 +1175,14 @@ static bool hybrid_clear_max_perf_cpu(void) - return ret; - } - -+static unsigned int intel_pstate_scale_freq_ref(struct cpufreq_policy *policy) -+{ -+ if (READ_ONCE(all_cpu_data[policy->cpu]->capacity_perf)) -+ return policy->cpuinfo.max_freq; -+ -+ return 0; -+} -+ - static void intel_pstate_update_freq_limits(struct cpudata *cpu) - { - int scaling = cpu->pstate.scaling; -@@ -3092,6 +3100,7 @@ static struct cpufreq_driver intel_pstate = { - .offline = intel_pstate_cpu_offline, - .online = intel_pstate_cpu_online, - .update_limits = intel_pstate_update_limits, -+ .scale_freq_ref = intel_pstate_scale_freq_ref, - .name = "intel_pstate", - }; - -@@ -3415,6 +3424,7 @@ static struct cpufreq_driver intel_cpufreq = { - .suspend = intel_cpufreq_suspend, - .resume = intel_pstate_resume, - .update_limits = intel_pstate_update_limits, -+ .scale_freq_ref = intel_pstate_scale_freq_ref, - .name = "intel_cpufreq", - }; - -diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h ---- a/include/linux/cpufreq.h -+++ b/include/linux/cpufreq.h -@@ -420,6 +420,9 @@ struct cpufreq_driver { - /* Will be called after the driver is fully initialized */ - void (*ready)(struct cpufreq_policy *policy); - -+ /* Return the capacity reference frequency for policy. */ -+ unsigned int (*scale_freq_ref)(struct cpufreq_policy *policy); -+ - struct freq_attr **attr; - - /* platform specific boost support code */ diff --git a/kernel/0213-pm-fixes-3.patch.sig b/kernel/0213-pm-fixes-3.patch.sig deleted file mode 100644 index caad5f0..0000000 Binary files a/kernel/0213-pm-fixes-3.patch.sig and /dev/null differ diff --git a/kernel/0220-x86-amd-zen5-tlb-sizes.patch b/kernel/0220-x86-amd-zen5-tlb-sizes.patch deleted file mode 100644 index 1c5c5b3..0000000 --- a/kernel/0220-x86-amd-zen5-tlb-sizes.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h ---- a/arch/x86/include/asm/cpufeatures.h -+++ b/arch/x86/include/asm/cpufeatures.h -@@ -471,6 +471,8 @@ - #define X86_FEATURE_AUTOIBRS (20*32+ 8) /* Automatic IBRS */ - #define X86_FEATURE_NO_SMM_CTL_MSR (20*32+ 9) /* SMM_CTL MSR is not present */ - -+#define X86_FEATURE_L2_TLB_SIZE_X32 (20*32+14) /* L2 TLB sizes are encoded as multiples of 32 */ -+ - #define X86_FEATURE_GP_ON_USER_CPUID (20*32+17) /* User CPUID faulting */ - - #define X86_FEATURE_PREFETCHI (20*32+20) /* Prefetch Data/Instruction to Cache Level */ -diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c ---- a/arch/x86/kernel/cpu/amd.c -+++ b/arch/x86/kernel/cpu/amd.c -@@ -1190,7 +1190,7 @@ static unsigned int amd_size_cache(struct cpuinfo_x86 *c, unsigned int size) - - static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) - { -- u32 ebx, eax, ecx, edx; -+ u32 ebx, eax, ecx, edx, shift, tmp; - u16 mask = 0xfff; - - if (c->x86 < 0xf) -@@ -1199,10 +1199,12 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) - if (c->extended_cpuid_level < 0x80000006) - return; - -+ shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5; -+ - cpuid(0x80000006, &eax, &ebx, &ecx, &edx); - -- tlb_lld_4k = (ebx >> 16) & mask; -- tlb_lli_4k = ebx & mask; -+ tlb_lld_4k = ((ebx >> 16) & mask) << shift; -+ tlb_lli_4k = (ebx & mask) << shift; - - /* - * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB -@@ -1214,16 +1216,18 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) - } - - /* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ -- if (!((eax >> 16) & mask)) -+ tmp = ((eax >> 16) & mask) << shift; -+ if (!tmp) - tlb_lld_2m = (cpuid_eax(0x80000005) >> 16) & 0xff; - else -- tlb_lld_2m = (eax >> 16) & mask; -+ tlb_lld_2m = tmp; - - /* a 4M entry uses two 2M entries */ - tlb_lld_4m = tlb_lld_2m >> 1; - - /* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */ -- if (!(eax & mask)) { -+ tmp = (eax & mask) << shift; -+ if (!tmp) { - /* Erratum 658 */ - if (c->x86 == 0x15 && c->x86_model <= 0x1f) { - tlb_lli_2m = 1024; -@@ -1231,8 +1235,9 @@ static void cpu_detect_tlb_amd(struct cpuinfo_x86 *c) - cpuid(0x80000005, &eax, &ebx, &ecx, &edx); - tlb_lli_2m = eax & 0xff; - } -- } else -- tlb_lli_2m = eax & mask; -+ } else { -+ tlb_lli_2m = tmp; -+ } - - tlb_lli_4m = tlb_lli_2m >> 1; - -diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c ---- a/arch/x86/kernel/cpu/common.c -+++ b/arch/x86/kernel/cpu/common.c -@@ -857,7 +857,7 @@ static void get_model_name(struct cpuinfo_x86 *c) - - void cpu_detect_cache_sizes(struct cpuinfo_x86 *c) - { -- unsigned int n, dummy, ebx, ecx, edx, l2size; -+ unsigned int n, dummy, ebx, ecx, edx, l2size, shift __maybe_unused; - - n = c->extended_cpuid_level; - -@@ -877,7 +877,9 @@ void cpu_detect_cache_sizes(struct cpuinfo_x86 *c) - l2size = ecx >> 16; - - #ifdef CONFIG_X86_64 -+ shift = !!cpu_has(c, X86_FEATURE_L2_TLB_SIZE_X32) * 5; - c->x86_tlbsize += ((ebx >> 16) & 0xfff) + (ebx & 0xfff); -+ c->x86_tlbsize <<= shift; - #else - /* do processor-specific cache resizing */ - if (this_cpu->legacy_cache_size) diff --git a/kernel/0220-x86-amd-zen5-tlb-sizes.patch.sig b/kernel/0220-x86-amd-zen5-tlb-sizes.patch.sig deleted file mode 100644 index 33230cf..0000000 Binary files a/kernel/0220-x86-amd-zen5-tlb-sizes.patch.sig and /dev/null differ diff --git a/kernel/0250-zsmalloc.patch b/kernel/0250-zsmalloc.patch deleted file mode 100644 index 43793e5..0000000 --- a/kernel/0250-zsmalloc.patch +++ /dev/null @@ -1,396 +0,0 @@ -diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c ---- a/mm/zsmalloc.c -+++ b/mm/zsmalloc.c -@@ -21,6 +21,10 @@ - * pool->lock - * class->lock - * zspage->lock -+ * -+ * When ZS_OBJ_CLASS_BITS > 0, zs_free() skips pool->lock; it picks -+ * the size_class from obj's encoded class_idx and serializes against -+ * page migration via class->lock. - */ - - #include -@@ -67,8 +71,8 @@ - #define MAX_POSSIBLE_PHYSMEM_BITS MAX_PHYSMEM_BITS - #else - /* -- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just -- * be PAGE_SHIFT -+ * If this definition of MAX_PHYSMEM_BITS is used, ZS_OBJ_PFN_SHIFT will -+ * just be PAGE_SHIFT - */ - #define MAX_POSSIBLE_PHYSMEM_BITS BITS_PER_LONG - #endif -@@ -88,8 +92,23 @@ - #define OBJ_TAG_BITS 1 - #define OBJ_TAG_MASK OBJ_ALLOCATED_TAG - --#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS) --#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1) -+/* -+ * obj is encoded as [PFN | class_idx | obj_idx] within an unsigned long: -+ * -+ * |<-- _PFN_BITS -->|<-- ZS_OBJ_CLASS_BITS -->|<-- ZS_OBJ_IDX_BITS -->| -+ * +-----------------+-------------------------+-----------------------+ -+ * | PFN | class_idx | obj_idx | -+ * +-----------------+-------------------------+-----------------------+ -+ * MSB ^ LSB -+ * | -+ * +-- ZS_OBJ_PFN_SHIFT -+ * -+ * Encoding class_idx into obj lets zs_free() locate the size_class -+ * without holding pool->lock; class_idx is invariant across page -+ * migration (only PFN changes), so a lockless read of the obj value -+ * always yields a valid class_idx. -+ */ -+#define ZS_OBJ_PFN_SHIFT (BITS_PER_LONG - _PFN_BITS) - - #define HUGE_BITS 1 - #define FULLNESS_BITS 4 -@@ -98,9 +117,61 @@ - - #define ZS_MAX_PAGES_PER_ZSPAGE (_AC(CONFIG_ZSMALLOC_CHAIN_SIZE, UL)) - -+/* -+ * Bits to index a page within a zspage = ceil(log2(ZS_MAX_PAGES_PER_ZSPAGE)). -+ * Computed at preprocessor time, for use in #if below. Kconfig -+ * restricts ZSMALLOC_CHAIN_SIZE to [4, 16]. -+ */ -+#if ZS_MAX_PAGES_PER_ZSPAGE <= 4 -+#define ZS_PAGES_PER_ZSPAGE_BITS 2 -+#elif ZS_MAX_PAGES_PER_ZSPAGE <= 8 -+#define ZS_PAGES_PER_ZSPAGE_BITS 3 -+#elif ZS_MAX_PAGES_PER_ZSPAGE <= 16 -+#define ZS_PAGES_PER_ZSPAGE_BITS 4 -+#else -+#error "ZSMALLOC_CHAIN_SIZE out of expected range [4,16]" -+#endif -+ -+/* -+ * Bits to index an object within a single PAGE_SIZE at the smallest -+ * possible object size: log2(PAGE_SIZE / 32) = PAGE_SHIFT - 5. -+ * 32 is the hard floor of ZS_MIN_ALLOC_SIZE. -+ */ -+#define ZS_OBJS_PER_PAGE_BITS (PAGE_SHIFT - 5) -+ -+/* -+ * Bits to index any object in the densest possible zspage. Below this, -+ * ZS_MIN_ALLOC_SIZE is auto-raised by the MAX(32, ...) formula -- still -+ * correct, but objects are coarser. -+ */ -+#define ZS_OBJS_PER_ZSPAGE_BITS \ -+ (ZS_PAGES_PER_ZSPAGE_BITS + ZS_OBJS_PER_PAGE_BITS) -+ -+/* -+ * Encode class_idx only when obj has spare bits; otherwise -+ * ZS_OBJ_CLASS_BITS folds to 0 (32-bit, or 64-bit UML/fallback). -+ */ -+#if BITS_PER_LONG >= 64 && \ -+ ZS_OBJ_PFN_SHIFT >= (CLASS_BITS + 1) + ZS_OBJS_PER_ZSPAGE_BITS -+#define ZS_OBJ_CLASS_BITS (CLASS_BITS + 1) -+#else -+#define ZS_OBJ_CLASS_BITS 0 -+#endif -+#define ZS_OBJ_CLASS_MASK ((_AC(1, UL) << ZS_OBJ_CLASS_BITS) - 1) -+ -+#define ZS_OBJ_IDX_BITS (ZS_OBJ_PFN_SHIFT - ZS_OBJ_CLASS_BITS) -+#define ZS_OBJ_IDX_MASK ((_AC(1, UL) << ZS_OBJ_IDX_BITS) - 1) -+ -+/* -+ * Belt-and-suspenders: the #if above already guarantees this when -+ * class_idx is enabled. Catches future tweaks that bypass it. -+ */ -+static_assert(ZS_OBJ_IDX_BITS >= ZS_PAGES_PER_ZSPAGE_BITS, -+ "zsmalloc: ZS_MIN_ALLOC_SIZE would exceed ZS_MAX_ALLOC_SIZE"); -+ - /* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */ - #define ZS_MIN_ALLOC_SIZE \ -- MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS)) -+ MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> ZS_OBJ_IDX_BITS)) - /* each chunk includes extra space to keep handle */ - #define ZS_MAX_ALLOC_SIZE PAGE_SIZE - -@@ -396,10 +467,13 @@ static void cache_free_zspage(struct zspage *zspage) - kmem_cache_free(zspage_cachep, zspage); - } - --/* class->lock(which owns the handle) synchronizes races */ -+/* -+ * Pairs with READ_ONCE() in handle_to_obj(): zs_free() may read the -+ * handle locklessly, so prevent store tearing here. -+ */ - static void record_obj(unsigned long handle, unsigned long obj) - { -- *(unsigned long *)handle = obj; -+ WRITE_ONCE(*(unsigned long *)handle, obj); - } - - static inline bool __maybe_unused is_first_zpdesc(struct zpdesc *zpdesc) -@@ -725,33 +799,36 @@ static struct zpdesc *get_next_zpdesc(struct zpdesc *zpdesc) - static void obj_to_location(unsigned long obj, struct zpdesc **zpdesc, - unsigned int *obj_idx) - { -- *zpdesc = pfn_zpdesc(obj >> OBJ_INDEX_BITS); -- *obj_idx = (obj & OBJ_INDEX_MASK); -+ *zpdesc = pfn_zpdesc(obj >> ZS_OBJ_PFN_SHIFT); -+ *obj_idx = (obj & ZS_OBJ_IDX_MASK); - } - - static void obj_to_zpdesc(unsigned long obj, struct zpdesc **zpdesc) - { -- *zpdesc = pfn_zpdesc(obj >> OBJ_INDEX_BITS); -+ *zpdesc = pfn_zpdesc(obj >> ZS_OBJ_PFN_SHIFT); - } - - /** -- * location_to_obj - get obj value encoded from (, ) -+ * location_to_obj - encode (, , ) into obj value - * @zpdesc: zpdesc object resides in zspage - * @obj_idx: object index -+ * @class_idx: size class index; ignored when ZS_OBJ_CLASS_BITS == 0 - */ --static unsigned long location_to_obj(struct zpdesc *zpdesc, unsigned int obj_idx) -+static unsigned long location_to_obj(struct zpdesc *zpdesc, unsigned int obj_idx, -+ unsigned int class_idx) - { - unsigned long obj; - -- obj = zpdesc_pfn(zpdesc) << OBJ_INDEX_BITS; -- obj |= obj_idx & OBJ_INDEX_MASK; -+ obj = zpdesc_pfn(zpdesc) << ZS_OBJ_PFN_SHIFT; -+ obj |= (unsigned long)(class_idx & ZS_OBJ_CLASS_MASK) << ZS_OBJ_IDX_BITS; -+ obj |= obj_idx & ZS_OBJ_IDX_MASK; - - return obj; - } - - static unsigned long handle_to_obj(unsigned long handle) - { -- return *(unsigned long *)handle; -+ return READ_ONCE(*(unsigned long *)handle); - } - - static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj, -@@ -805,13 +882,26 @@ static int trylock_zspage(struct zspage *zspage) - return 0; - } - --static void __free_zspage(struct zs_pool *pool, struct size_class *class, -- struct zspage *zspage) -+/* -+ * Three free helpers, kept apart here: -+ * -+ * __free_zspage_lockless(): bare core; walks zpdescs and returns pages -+ * to the buddy allocator. Caller owns all zpdesc locks and has -+ * removed the zspage from its class list. Used by zs_free() outside -+ * class->lock so the buddy-side work does not stall the class. -+ * -+ * __free_zspage(): __free_zspage_lockless() + per-class accounting, -+ * under class->lock. Used by async_free_zspage(), the worker for -+ * zspages whose trylock_zspage() failed. -+ * -+ * free_zspage(): full wrapper - trylock zpdescs, remove from class -+ * list, call __free_zspage(); kicks deferred free on contention. -+ * Used by compaction. -+ */ -+static inline void __free_zspage_lockless(struct zspage *zspage) - { - struct zpdesc *zpdesc, *next; - -- assert_spin_locked(&class->lock); -- - VM_BUG_ON(get_zspage_inuse(zspage)); - VM_BUG_ON(zspage->fullness != ZS_INUSE_RATIO_0); - -@@ -827,7 +917,13 @@ static void __free_zspage(struct zs_pool *pool, struct size_class *class, - } while (zpdesc != NULL); - - cache_free_zspage(zspage); -+} - -+static void __free_zspage(struct zs_pool *pool, struct size_class *class, -+ struct zspage *zspage) -+{ -+ assert_spin_locked(&class->lock); -+ __free_zspage_lockless(zspage); - class_stat_sub(class, ZS_OBJS_ALLOCATED, class->objs_per_zspage); - atomic_long_sub(class->pages_per_zspage, &pool->pages_allocated); - } -@@ -1280,7 +1376,7 @@ static unsigned long obj_malloc(struct zs_pool *pool, - kunmap_local(vaddr); - mod_zspage_inuse(zspage, 1); - -- obj = location_to_obj(m_zpdesc, obj); -+ obj = location_to_obj(m_zpdesc, obj, zspage->class); - record_obj(handle, obj); - - return obj; -@@ -1383,37 +1479,97 @@ static void obj_free(int class_size, unsigned long obj) - mod_zspage_inuse(zspage, -1); - } - -+#if (ZS_OBJ_CLASS_BITS > 0) || defined(CONFIG_COMPACTION) -+/* Folds to 0 when ZS_OBJ_CLASS_BITS == 0; no ifdef needed at callers. */ -+static unsigned int obj_to_class_idx(unsigned long obj) -+{ -+ return (obj >> ZS_OBJ_IDX_BITS) & ZS_OBJ_CLASS_MASK; -+} -+#endif -+ -+/* -+ * Resolve @handle to its zspage / size_class and acquire class->lock. -+ * -+ * When class_idx is encoded in obj (ZS_OBJ_CLASS_BITS > 0), it is -+ * invariant under page migration, so the handle can be read locklessly -+ * to pick the size_class. Once class->lock is held migration is -+ * blocked and the handle is re-read to obtain a stable PFN. -+ * -+ * Otherwise (32-bit, or 64-bit fallback paths like UML where the -+ * encoding is disabled), fall back to pool->lock for the lookup. -+ */ -+#if ZS_OBJ_CLASS_BITS > 0 -+static inline void obj_class_get_and_lock(struct zs_pool *pool, unsigned long handle, -+ unsigned long *objp, struct zspage **zspagep, -+ struct size_class **classp) -+ __acquires(&(*classp)->lock) -+{ -+ struct zpdesc *f_zpdesc; -+ unsigned long obj; -+ -+ obj = handle_to_obj(handle); -+ *classp = pool->size_class[obj_to_class_idx(obj)]; -+ spin_lock(&(*classp)->lock); -+ /* Re-read under class->lock: PFN is now stable vs migration. */ -+ obj = handle_to_obj(handle); -+ obj_to_zpdesc(obj, &f_zpdesc); -+ *zspagep = get_zspage(f_zpdesc); -+ *objp = obj; -+} -+#else -+static inline void obj_class_get_and_lock(struct zs_pool *pool, unsigned long handle, -+ unsigned long *objp, struct zspage **zspagep, -+ struct size_class **classp) -+ __acquires(&(*classp)->lock) -+{ -+ struct zpdesc *f_zpdesc; -+ unsigned long obj; -+ -+ read_lock(&pool->lock); -+ obj = handle_to_obj(handle); -+ obj_to_zpdesc(obj, &f_zpdesc); -+ *zspagep = get_zspage(f_zpdesc); -+ *classp = zspage_class(pool, *zspagep); -+ spin_lock(&(*classp)->lock); -+ read_unlock(&pool->lock); -+ *objp = obj; -+} -+#endif -+ - void zs_free(struct zs_pool *pool, unsigned long handle) - { - struct zspage *zspage; -- struct zpdesc *f_zpdesc; - unsigned long obj; - struct size_class *class; - int fullness; -+ struct zspage *zspage_to_free = NULL; - - if (IS_ERR_OR_NULL((void *)handle)) - return; - -- /* -- * The pool->lock protects the race with zpage's migration -- * so it's safe to get the page from handle. -- */ -- read_lock(&pool->lock); -- obj = handle_to_obj(handle); -- obj_to_zpdesc(obj, &f_zpdesc); -- zspage = get_zspage(f_zpdesc); -- class = zspage_class(pool, zspage); -- spin_lock(&class->lock); -- read_unlock(&pool->lock); -+ obj_class_get_and_lock(pool, handle, &obj, &zspage, &class); - - class_stat_sub(class, ZS_OBJS_INUSE, 1); - obj_free(class->size, obj); - - fullness = fix_fullness_group(class, zspage); -- if (fullness == ZS_INUSE_RATIO_0) -- free_zspage(pool, class, zspage); -+ if (fullness == ZS_INUSE_RATIO_0) { -+ if (trylock_zspage(zspage)) { -+ remove_zspage(class, zspage); -+ class_stat_sub(class, ZS_OBJS_ALLOCATED, -+ class->objs_per_zspage); -+ zspage_to_free = zspage; -+ } else { -+ kick_deferred_free(pool); -+ } -+ } - - spin_unlock(&class->lock); -+ -+ if (zspage_to_free) { -+ __free_zspage_lockless(zspage_to_free); -+ atomic_long_sub(class->pages_per_zspage, &pool->pages_allocated); -+ } - cache_free_handle(handle); - } - EXPORT_SYMBOL_GPL(zs_free); -@@ -1646,9 +1802,6 @@ static void lock_zspage(struct zspage *zspage) - } - zspage_read_unlock(zspage); - } --#endif /* CONFIG_COMPACTION */ -- --#ifdef CONFIG_COMPACTION - - static void replace_sub_page(struct size_class *class, struct zspage *zspage, - struct zpdesc *newzpdesc, struct zpdesc *oldzpdesc) -@@ -1715,8 +1868,8 @@ static int zs_page_migrate(struct page *newpage, struct page *page, - pool = zspage->pool; - - /* -- * The pool migrate_lock protects the race between zpage migration -- * and zs_free. -+ * The pool migrate_lock protects against races between zpage migration -+ * and zs_free(), but only when ZS_OBJ_CLASS_BITS does not apply. - */ - write_lock(&pool->lock); - class = zspage_class(pool, zspage); -@@ -1764,7 +1917,8 @@ static int zs_page_migrate(struct page *newpage, struct page *page, - - old_obj = handle_to_obj(handle); - obj_to_location(old_obj, &dummy, &obj_idx); -- new_obj = (unsigned long)location_to_obj(newzpdesc, obj_idx); -+ new_obj = location_to_obj(newzpdesc, obj_idx, -+ obj_to_class_idx(old_obj)); - record_obj(handle, new_obj); - } - } -@@ -1775,9 +1929,9 @@ static int zs_page_migrate(struct page *newpage, struct page *page, - * Since we complete the data copy and set up new zspage structure, - * it's okay to release migration_lock. - */ -- write_unlock(&pool->lock); -- spin_unlock(&class->lock); - zspage_write_unlock(zspage); -+ spin_unlock(&class->lock); -+ write_unlock(&pool->lock); - - zpdesc_get(newzpdesc); - if (zpdesc_zone(newzpdesc) != zpdesc_zone(zpdesc)) { -@@ -1894,8 +2048,9 @@ static unsigned long __zs_compact(struct zs_pool *pool, - unsigned long pages_freed = 0; - - /* -- * protect the race between zpage migration and zs_free -- * as well as zpage allocation/free -+ * Protect against races between zpage migration and zs_free() -+ * (only when ZS_OBJ_CLASS_BITS does not apply), as well as -+ * zpage allocation and free. - */ - write_lock(&pool->lock); - spin_lock(&class->lock); diff --git a/kernel/0250-zsmalloc.patch.sig b/kernel/0250-zsmalloc.patch.sig deleted file mode 100644 index 24e9d20..0000000 Binary files a/kernel/0250-zsmalloc.patch.sig and /dev/null differ diff --git a/kernel/0260-mglru-exec-protect.patch b/kernel/0260-mglru-exec-protect.patch deleted file mode 100644 index f3b0e56..0000000 --- a/kernel/0260-mglru-exec-protect.patch +++ /dev/null @@ -1,313 +0,0 @@ -diff --git a/include/linux/rmap.h b/include/linux/rmap.h ---- a/include/linux/rmap.h -+++ b/include/linux/rmap.h -@@ -843,7 +843,7 @@ static inline int folio_try_share_anon_rmap_pmd(struct folio *folio, - * Called from mm/vmscan.c to handle paging out - */ - int folio_referenced(struct folio *, int is_locked, -- struct mem_cgroup *memcg, vm_flags_t *vm_flags); -+ struct mem_cgroup *memcg, vma_flags_t *vma_flags); - - void try_to_migrate(struct folio *folio, enum ttu_flags flags); - void try_to_unmap(struct folio *, enum ttu_flags flags); -@@ -975,10 +975,9 @@ struct anon_vma *folio_lock_anon_vma_read(const struct folio *folio, - #define anon_vma_prepare(vma) (0) - - static inline int folio_referenced(struct folio *folio, int is_locked, -- struct mem_cgroup *memcg, -- vm_flags_t *vm_flags) -+ struct mem_cgroup *memcg, vma_flags_t *vma_flags) - { -- *vm_flags = 0; -+ vma_flags_clear_all(vma_flags); - return 0; - } - -diff --git a/mm/rmap.c b/mm/rmap.c ---- a/mm/rmap.c -+++ b/mm/rmap.c -@@ -907,7 +907,7 @@ pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address) - struct folio_referenced_arg { - int mapcount; - int referenced; -- vm_flags_t vm_flags; -+ vma_flags_t vma_flags; - struct mem_cgroup *memcg; - }; - -@@ -926,7 +926,7 @@ static bool folio_referenced_one(struct folio *folio, - address = pvmw.address; - nr = 1; - -- if (vma->vm_flags & VM_LOCKED) { -+ if (vma_test(vma, VMA_LOCKED_BIT)) { - ptes++; - pra->mapcount--; - -@@ -947,7 +947,7 @@ static bool folio_referenced_one(struct folio *folio, - /* Restore the mlock which got missed */ - mlock_vma_folio(folio, vma); - page_vma_mapped_walk_done(&pvmw); -- pra->vm_flags |= VM_LOCKED; -+ vma_flags_set(&pra->vma_flags, VMA_LOCKED_BIT); - return false; /* To break the loop */ - } - -@@ -1015,8 +1015,11 @@ static bool folio_referenced_one(struct folio *folio, - referenced++; - - if (referenced) { -+ vma_flags_t vma_flags = vma->flags; -+ - pra->referenced++; -- pra->vm_flags |= vma->vm_flags & ~VM_LOCKED; -+ vma_flags_clear(&vma_flags, VMA_LOCKED_BIT); -+ vma_flags_set_mask(&pra->vma_flags, vma_flags); - } - - if (!pra->mapcount) -@@ -1054,7 +1057,7 @@ static bool invalid_folio_referenced_vma(struct vm_area_struct *vma, void *arg) - * @folio: The folio to test. - * @is_locked: Caller holds lock on the folio. - * @memcg: target memory cgroup -- * @vm_flags: A combination of all the vma->vm_flags which referenced the folio. -+ * @vma_flags: A combination of all the vma->flags which referenced the folio. - * - * Quick test_and_clear_referenced for all mappings of a folio, - * -@@ -1062,7 +1065,7 @@ static bool invalid_folio_referenced_vma(struct vm_area_struct *vma, void *arg) - * the function bailed out due to rmap lock contention. - */ - int folio_referenced(struct folio *folio, int is_locked, -- struct mem_cgroup *memcg, vm_flags_t *vm_flags) -+ struct mem_cgroup *memcg, vma_flags_t *vma_flags) - { - bool we_locked = false; - struct folio_referenced_arg pra = { -@@ -1078,7 +1081,7 @@ int folio_referenced(struct folio *folio, int is_locked, - }; - - VM_WARN_ON_ONCE_FOLIO(folio_is_zone_device(folio), folio); -- *vm_flags = 0; -+ vma_flags_clear_all(vma_flags); - if (!pra.mapcount) - return 0; - -@@ -1092,7 +1095,7 @@ int folio_referenced(struct folio *folio, int is_locked, - } - - rmap_walk(folio, &rwc); -- *vm_flags = pra.vm_flags; -+ vma_flags_set_mask(vma_flags, pra.vma_flags); - - if (we_locked) - folio_unlock(folio); -diff --git a/mm/vmscan.c b/mm/vmscan.c ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -262,6 +262,12 @@ static bool writeback_throttling_sane(struct scan_control *sc) - } - #endif - -+static inline bool is_exec_file_folio(const struct folio *folio, -+ const vma_flags_t *vma_flags) -+{ -+ return vma_flags_test(vma_flags, VMA_EXEC_BIT) && folio_is_file_lru(folio); -+} -+ - static void set_task_reclaim_state(struct task_struct *task, - struct reclaim_state *rs) - { -@@ -830,10 +836,16 @@ enum folio_references { - * with PG_active set. In contrast, the aging (page table walk) path uses - * folio_update_gen(). - */ --static bool lru_gen_set_refs(struct folio *folio) -+static bool lru_gen_set_refs(struct folio *folio, const vma_flags_t *vma_flags) - { - /* see the comment on LRU_REFS_FLAGS */ - if (!folio_test_referenced(folio) && !folio_test_workingset(folio)) { -+ /* Activate file-backed executable folios after first usage. */ -+ if (is_exec_file_folio(folio, vma_flags)) { -+ set_mask_bits(&folio->flags.f, LRU_REFS_FLAGS, BIT(PG_workingset)); -+ return true; -+ } -+ - set_mask_bits(&folio->flags.f, LRU_REFS_MASK, BIT(PG_referenced)); - return false; - } -@@ -846,7 +858,7 @@ static bool lru_gen_set_refs(struct folio *folio) - return true; - } - #else --static bool lru_gen_set_refs(struct folio *folio) -+static bool lru_gen_set_refs(struct folio *folio, const vma_flags_t *vma_flags) - { - return false; - } -@@ -856,16 +868,16 @@ static enum folio_references folio_check_references(struct folio *folio, - struct scan_control *sc) - { - int referenced_ptes, referenced_folio; -- vm_flags_t vm_flags; -+ vma_flags_t vma_flags; - - referenced_ptes = folio_referenced(folio, 1, sc->target_mem_cgroup, -- &vm_flags); -+ &vma_flags); - - /* - * The supposedly reclaimable folio was found to be in a VM_LOCKED vma. - * Let the folio, now marked Mlocked, be moved to the unevictable list. - */ -- if (vm_flags & VM_LOCKED) -+ if (vma_flags_test(&vma_flags, VMA_LOCKED_BIT)) - return FOLIOREF_ACTIVATE; - - /* -@@ -881,7 +893,7 @@ static enum folio_references folio_check_references(struct folio *folio, - if (!referenced_ptes) - return FOLIOREF_RECLAIM; - -- return lru_gen_set_refs(folio) ? FOLIOREF_ACTIVATE : FOLIOREF_KEEP; -+ return lru_gen_set_refs(folio, &vma_flags) ? FOLIOREF_ACTIVATE : FOLIOREF_KEEP; - } - - referenced_folio = folio_test_clear_referenced(folio); -@@ -909,7 +921,7 @@ static enum folio_references folio_check_references(struct folio *folio, - /* - * Activate file-backed executable folios after first usage. - */ -- if ((vm_flags & VM_EXEC) && folio_is_file_lru(folio)) -+ if (is_exec_file_folio(folio, &vma_flags)) - return FOLIOREF_ACTIVATE; - - return FOLIOREF_KEEP; -@@ -2067,7 +2079,7 @@ static void shrink_active_list(unsigned long nr_to_scan, - { - unsigned long nr_taken; - unsigned long nr_scanned; -- vm_flags_t vm_flags; -+ vma_flags_t vma_flags; - LIST_HEAD(l_hold); /* The folios which were snipped off */ - LIST_HEAD(l_active); - LIST_HEAD(l_inactive); -@@ -2111,7 +2123,7 @@ static void shrink_active_list(unsigned long nr_to_scan, - - /* Referenced or rmap lock contention: rotate */ - if (folio_referenced(folio, 0, sc->target_mem_cgroup, -- &vm_flags) != 0) { -+ &vma_flags) != 0) { - /* - * Identify referenced, file-backed active folios and - * give them one more trip around the active list. So -@@ -2121,7 +2133,7 @@ static void shrink_active_list(unsigned long nr_to_scan, - * IO, plus JVM can create lots of anon VM_EXEC folios, - * so we ignore them here. - */ -- if ((vm_flags & VM_EXEC) && folio_is_file_lru(folio)) { -+ if (is_exec_file_folio(folio, &vma_flags)) { - nr_rotated += folio_nr_pages(folio); - list_add(&folio->lru, &l_active); - continue; -@@ -3190,14 +3202,19 @@ static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) - ******************************************************************************/ - - /* promote pages accessed through page tables */ --static int folio_update_gen(struct folio *folio, int gen) -+static int folio_update_gen(struct folio *folio, int gen, const vma_flags_t *vma_flags) - { - unsigned long new_flags, old_flags = READ_ONCE(folio->flags.f); - - VM_WARN_ON_ONCE(gen >= MAX_NR_GENS); - -- /* see the comment on LRU_REFS_FLAGS */ -- if (!folio_test_referenced(folio) && !folio_test_workingset(folio)) { -+ /* -+ * See the comment on LRU_REFS_FLAGS, and activate file-backed -+ * executable folios after first usage to avoid typical IO -+ * thrashing from reclaiming. -+ */ -+ if (!folio_test_referenced(folio) && !folio_test_workingset(folio) && -+ !is_exec_file_folio(folio, vma_flags)) { - set_mask_bits(&folio->flags.f, LRU_REFS_MASK, BIT(PG_referenced)); - return -1; - } -@@ -3430,8 +3447,8 @@ static bool suitable_to_scan(int total, int young) - return young * n >= total; - } - --static void walk_update_folio(struct lru_gen_mm_walk *walk, struct folio *folio, -- int new_gen, bool dirty) -+static void walk_update_folio(struct lru_gen_mm_walk *walk, struct vm_area_struct *vma, -+ struct folio *folio, int new_gen, bool dirty) - { - int old_gen; - -@@ -3444,10 +3461,10 @@ static void walk_update_folio(struct lru_gen_mm_walk *walk, struct folio *folio, - folio_mark_dirty(folio); - - if (walk) { -- old_gen = folio_update_gen(folio, new_gen); -+ old_gen = folio_update_gen(folio, new_gen, &vma->flags); - if (old_gen >= 0 && old_gen != new_gen) - update_batch_size(walk, folio, old_gen, new_gen); -- } else if (lru_gen_set_refs(folio)) { -+ } else if (lru_gen_set_refs(folio, &vma->flags)) { - old_gen = folio_lru_gen(folio); - if (old_gen >= 0 && old_gen != new_gen) - folio_activate(folio); -@@ -3520,7 +3537,7 @@ static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, - continue; - - if (last != folio) { -- walk_update_folio(walk, last, gen, dirty); -+ walk_update_folio(walk, args->vma, last, gen, dirty); - - last = folio; - dirty = false; -@@ -3533,7 +3550,7 @@ static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, - walk->mm_stats[MM_LEAF_YOUNG] += nr; - } - -- walk_update_folio(walk, last, gen, dirty); -+ walk_update_folio(walk, args->vma, last, gen, dirty); - last = NULL; - - if (i < PTRS_PER_PTE && get_next_vma(PMD_MASK, PAGE_SIZE, args, &start, &end)) -@@ -3611,7 +3628,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area - goto next; - - if (last != folio) { -- walk_update_folio(walk, last, gen, dirty); -+ walk_update_folio(walk, vma, last, gen, dirty); - - last = folio; - dirty = false; -@@ -3625,7 +3642,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area - i = i > MIN_LRU_BATCH ? 0 : find_next_bit(bitmap, MIN_LRU_BATCH, i) + 1; - } while (i <= MIN_LRU_BATCH); - -- walk_update_folio(walk, last, gen, dirty); -+ walk_update_folio(walk, vma, last, gen, dirty); - - lazy_mmu_mode_disable(); - spin_unlock(ptl); -@@ -4260,7 +4277,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr) - continue; - - if (last != folio) { -- walk_update_folio(walk, last, gen, dirty); -+ walk_update_folio(walk, vma, last, gen, dirty); - - last = folio; - dirty = false; -@@ -4272,7 +4289,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr) - young += nr; - } - -- walk_update_folio(walk, last, gen, dirty); -+ walk_update_folio(walk, vma, last, gen, dirty); - - lazy_mmu_mode_disable(); - diff --git a/kernel/0260-mglru-exec-protect.patch.sig b/kernel/0260-mglru-exec-protect.patch.sig deleted file mode 100644 index b84157c..0000000 Binary files a/kernel/0260-mglru-exec-protect.patch.sig and /dev/null differ diff --git a/kernel/0270-ksm-rmap-walk.patch b/kernel/0270-ksm-rmap-walk.patch deleted file mode 100644 index afe8241..0000000 --- a/kernel/0270-ksm-rmap-walk.patch +++ /dev/null @@ -1,161 +0,0 @@ -diff --git a/mm/ksm.c b/mm/ksm.c ---- a/mm/ksm.c -+++ b/mm/ksm.c -@@ -195,22 +195,28 @@ struct ksm_stable_node { - * @node: rb node of this rmap_item in the unstable tree - * @head: pointer to stable_node heading this list in the stable tree - * @hlist: link into hlist of rmap_items hanging off that stable_node -- * @age: number of scan iterations since creation -- * @remaining_skips: how many scans to skip -+ * @age: number of scan iterations since creation (unstable node) -+ * @remaining_skips: how many scans to skip (unstable node) -+ * @linear_page_index: the original page's index before merged by KSM (stable node) - */ - struct ksm_rmap_item { - struct ksm_rmap_item *rmap_list; - union { -- struct anon_vma *anon_vma; /* when stable */ -+ struct anon_vma *anon_vma; /* for reverse mapping, when stable */ - #ifdef CONFIG_NUMA - int nid; /* when node of unstable tree */ - #endif - }; - struct mm_struct *mm; - unsigned long address; /* + low bits used for flags below */ -- unsigned int oldchecksum; /* when unstable */ -- rmap_age_t age; -- rmap_age_t remaining_skips; -+ union { -+ struct { -+ unsigned int oldchecksum; -+ rmap_age_t age; -+ rmap_age_t remaining_skips; -+ }; /* when unstable */ -+ unsigned long linear_page_index; /* for reverse mapping, when stable */ -+ }; - union { - struct rb_node node; /* when node of unstable tree */ - struct { /* when listed from stable tree */ -@@ -776,6 +782,11 @@ static struct vm_area_struct *find_mergeable_vma(struct mm_struct *mm, - return vma; - } - -+/* -+ * break_cow: actively break COW, replacing the KSM page by a fresh anonymous -+ * page. This is called when rmap_item has not yet become stable, but page -+ * has been merged. -+ */ - static void break_cow(struct ksm_rmap_item *rmap_item) - { - struct mm_struct *mm = rmap_item->mm; -@@ -787,6 +798,11 @@ static void break_cow(struct ksm_rmap_item *rmap_item) - * to undo, we also need to drop a reference to the anon_vma. - */ - put_anon_vma(rmap_item->anon_vma); -+ /* -+ * Reset linear_page_index that might overlay age-related -+ * information. (it's still unstable node) -+ */ -+ rmap_item->linear_page_index = 0; - - mmap_read_lock(mm); - vma = find_mergeable_vma(mm, addr); -@@ -899,6 +915,8 @@ static void remove_node_from_stable_tree(struct ksm_stable_node *stable_node) - VM_BUG_ON(stable_node->rmap_hlist_len <= 0); - stable_node->rmap_hlist_len--; - put_anon_vma(rmap_item->anon_vma); -+ /* Reset linear_page_index that might overlay age-related information. */ -+ rmap_item->linear_page_index = 0; - rmap_item->address &= PAGE_MASK; - cond_resched(); - } -@@ -1052,6 +1070,8 @@ static void remove_rmap_item_from_tree(struct ksm_rmap_item *rmap_item) - stable_node->rmap_hlist_len--; - - put_anon_vma(rmap_item->anon_vma); -+ /* Reset linear_page_index that might overlay age-related information. */ -+ rmap_item->linear_page_index = 0; - rmap_item->head = NULL; - rmap_item->address &= PAGE_MASK; - -@@ -1598,8 +1618,15 @@ static int try_to_merge_with_ksm_page(struct ksm_rmap_item *rmap_item, - /* Unstable nid is in union with stable anon_vma: remove first */ - remove_rmap_item_from_tree(rmap_item); - -- /* Must get reference to anon_vma while still holding mmap_lock */ -+ /* -+ * We can consider the VMA only while still holding the mmap lock, -+ * so lock, so reference the anon_vma and calculate the linear -+ * page index early, before stable_tree_append(). If anything goes -+ * wrong that prevents the rmap_item from being added to the -+ * stable_tree, break_cow() will clean it up. -+ */ - rmap_item->anon_vma = vma->anon_vma; -+ rmap_item->linear_page_index = linear_page_index(vma, rmap_item->address); - get_anon_vma(vma->anon_vma); - out: - mmap_read_unlock(mm); -@@ -2458,6 +2485,13 @@ static bool should_skip_rmap_item(struct folio *folio, - if (folio_test_ksm(folio)) - return false; - -+ /* -+ * There is no age information in stable-tree nodes. We might end up -+ * here without a KSM page for example after COW. -+ */ -+ if (rmap_item->address & STABLE_FLAG) -+ return false; -+ - age = rmap_item->age; - if (age != U8_MAX) - rmap_item->age++; -@@ -3173,6 +3207,7 @@ void rmap_walk_ksm(struct folio *folio, struct rmap_walk_control *rwc) - hlist_for_each_entry(rmap_item, &stable_node->hlist, hlist) { - /* Ignore the stable/unstable/sqnr flags */ - const unsigned long addr = rmap_item->address & PAGE_MASK; -+ const unsigned long index = rmap_item->linear_page_index; - struct anon_vma *anon_vma = rmap_item->anon_vma; - struct anon_vma_chain *vmac; - struct vm_area_struct *vma; -@@ -3186,8 +3221,18 @@ void rmap_walk_ksm(struct folio *folio, struct rmap_walk_control *rwc) - anon_vma_lock_read(anon_vma); - } - -+ /* -+ * Currently, KSM folios are always small folios, so it's -+ * sufficient to search for a single page. We can simply use -+ * the linear_page_index of the original de-duplicate -+ * anonymous page that we remembered in the rmap_item while -+ * de-duplicating. Note that mremap() always de-duplicates KSM -+ * folios: so if there was mremap() in our parent or our child, -+ * we wouldn't have the KSM folio mapped in these processes -+ * anymore. -+ */ - anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root, -- 0, ULONG_MAX) { -+ index, index) { - - cond_resched(); - vma = vmac->vma; -@@ -3243,17 +3288,17 @@ void collect_procs_ksm(const struct folio *folio, const struct page *page, - rcu_read_lock(); - for_each_process(tsk) { - struct anon_vma_chain *vmac; -- unsigned long addr; -+ const unsigned long addr = rmap_item->address & PAGE_MASK; -+ const unsigned long index = rmap_item->linear_page_index; - struct task_struct *t = - task_early_kill(tsk, force_early); - if (!t) - continue; -- anon_vma_interval_tree_foreach(vmac, &av->rb_root, 0, -- ULONG_MAX) -+ anon_vma_interval_tree_foreach(vmac, &av->rb_root, index, -+ index) - { - vma = vmac->vma; - if (vma->vm_mm == t->mm) { -- addr = rmap_item->address & PAGE_MASK; - add_to_kill_ksm(t, page, vma, to_kill, - addr); - } diff --git a/kernel/0270-ksm-rmap-walk.patch.sig b/kernel/0270-ksm-rmap-walk.patch.sig deleted file mode 100644 index f6989e4..0000000 Binary files a/kernel/0270-ksm-rmap-walk.patch.sig and /dev/null differ diff --git a/kernel/0280-mm-updates.patch b/kernel/0280-mm-updates.patch deleted file mode 100644 index e0bf148..0000000 --- a/kernel/0280-mm-updates.patch +++ /dev/null @@ -1,1162 +0,0 @@ -diff --git a/drivers/block/zram/backend_842.c b/drivers/block/zram/backend_842.c ---- a/drivers/block/zram/backend_842.c -+++ b/drivers/block/zram/backend_842.c -@@ -1,5 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - -+#define pr_fmt(fmt) "842: " fmt -+ - #include - #include - #include -@@ -13,6 +15,14 @@ static void release_params_842(struct zcomp_params *params) - - static int setup_params_842(struct zcomp_params *params) - { -+ if (params->dict_sz) { -+ pr_err("dictionary is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ if (params->level != ZCOMP_PARAM_NOT_SET) { -+ pr_err("compression level is not supported\n"); -+ return -EOPNOTSUPP; -+ } - return 0; - } - -diff --git a/drivers/block/zram/backend_deflate.c b/drivers/block/zram/backend_deflate.c ---- a/drivers/block/zram/backend_deflate.c -+++ b/drivers/block/zram/backend_deflate.c -@@ -1,5 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - -+#define pr_fmt(fmt) "deflate: " fmt -+ - #include - #include - #include -@@ -22,15 +24,26 @@ static void deflate_release_params(struct zcomp_params *params) - - static int deflate_setup_params(struct zcomp_params *params) - { -- if (params->level == ZCOMP_PARAM_NOT_SET) -+ if (params->dict_sz) { -+ pr_err("dictionary is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ if (params->level == ZCOMP_PARAM_NOT_SET) { - params->level = Z_DEFAULT_COMPRESSION; -+ } else if (params->level < Z_DEFAULT_COMPRESSION || -+ params->level > Z_BEST_COMPRESSION) { -+ pr_err("invalid compression level %d\n", params->level); -+ return -EINVAL; -+ } -+ - if (params->deflate.winbits == ZCOMP_PARAM_NOT_SET) { - params->deflate.winbits = DEFLATE_DEF_WINBITS; - } else { - s32 wb = params->deflate.winbits; - - if ((wb < -15 || wb > -9) && (wb < 9 || wb > 15)) { -- pr_err("invalid deflate winbits: %d\n", wb); -+ pr_err("invalid winbits %d\n", wb); - return -EINVAL; - } - } -diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_lz4.c ---- a/drivers/block/zram/backend_lz4.c -+++ b/drivers/block/zram/backend_lz4.c -@@ -1,3 +1,7 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#define pr_fmt(fmt) "lz4: " fmt -+ - #include - #include - #include -@@ -28,8 +32,12 @@ static int lz4_setup_params(struct zcomp_params *params) - LZ4_stream_t *dict_stream; - int ret; - -- if (params->level == ZCOMP_PARAM_NOT_SET) -+ if (params->level == ZCOMP_PARAM_NOT_SET) { - params->level = LZ4_ACCELERATION_DEFAULT; -+ } else if (params->level < LZ4_ACCELERATION_DEFAULT) { -+ pr_err("invalid compression level %d\n", params->level); -+ return -EINVAL; -+ } - - if (!params->dict || !params->dict_sz) - return 0; -diff --git a/drivers/block/zram/backend_lz4hc.c b/drivers/block/zram/backend_lz4hc.c ---- a/drivers/block/zram/backend_lz4hc.c -+++ b/drivers/block/zram/backend_lz4hc.c -@@ -1,3 +1,7 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#define pr_fmt(fmt) "lz4hc: " fmt -+ - #include - #include - #include -@@ -18,8 +22,18 @@ static void lz4hc_release_params(struct zcomp_params *params) - - static int lz4hc_setup_params(struct zcomp_params *params) - { -- if (params->level == ZCOMP_PARAM_NOT_SET) -+ if (params->level == ZCOMP_PARAM_NOT_SET) { - params->level = LZ4HC_DEFAULT_CLEVEL; -+ } else if (params->level < 1 || params->level > LZ4HC_MAX_CLEVEL) { -+ /* -+ * Use < 1 rather than < LZ4HC_MIN_CLEVEL here because -+ * LZ4HC_compress_generic() only clamps levels below 1 -+ * (levels 1 and 2 are valid). LZ4HC_MIN_CLEVEL (3) is -+ * advisory and not enforced by the library. -+ */ -+ pr_err("invalid compression level %d\n", params->level); -+ return -EINVAL; -+ } - - return 0; - } -diff --git a/drivers/block/zram/backend_lzo.c b/drivers/block/zram/backend_lzo.c ---- a/drivers/block/zram/backend_lzo.c -+++ b/drivers/block/zram/backend_lzo.c -@@ -1,5 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - -+#define pr_fmt(fmt) "lzo: " fmt -+ - #include - #include - #include -@@ -12,6 +14,14 @@ static void lzo_release_params(struct zcomp_params *params) - - static int lzo_setup_params(struct zcomp_params *params) - { -+ if (params->dict_sz) { -+ pr_err("dictionary is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ if (params->level != ZCOMP_PARAM_NOT_SET) { -+ pr_err("compression level is not supported\n"); -+ return -EOPNOTSUPP; -+ } - return 0; - } - -diff --git a/drivers/block/zram/backend_lzorle.c b/drivers/block/zram/backend_lzorle.c ---- a/drivers/block/zram/backend_lzorle.c -+++ b/drivers/block/zram/backend_lzorle.c -@@ -1,5 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - -+#define pr_fmt(fmt) "lzo-rle: " fmt -+ - #include - #include - #include -@@ -12,6 +14,14 @@ static void lzorle_release_params(struct zcomp_params *params) - - static int lzorle_setup_params(struct zcomp_params *params) - { -+ if (params->dict_sz) { -+ pr_err("dictionary is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ if (params->level != ZCOMP_PARAM_NOT_SET) { -+ pr_err("compression level is not supported\n"); -+ return -EOPNOTSUPP; -+ } - return 0; - } - -diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c ---- a/drivers/block/zram/backend_zstd.c -+++ b/drivers/block/zram/backend_zstd.c -@@ -1,5 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - -+#define pr_fmt(fmt) "zstd: " fmt -+ - #include - #include - #include -@@ -58,8 +60,13 @@ static int zstd_setup_params(struct zcomp_params *params) - return -ENOMEM; - - params->drv_data = zp; -- if (params->level == ZCOMP_PARAM_NOT_SET) -+ if (params->level == ZCOMP_PARAM_NOT_SET) { - params->level = zstd_default_clevel(); -+ } else if (params->level < zstd_min_clevel() || -+ params->level > zstd_max_clevel()) { -+ pr_err("invalid compression level %d\n", params->level); -+ goto error; -+ } - - zp->cprm = zstd_get_params(params->level, PAGE_SIZE); - -@@ -85,7 +92,6 @@ static int zstd_setup_params(struct zcomp_params *params) - return 0; - - error: -- zstd_release_params(params); - return -EINVAL; - } - -@@ -161,7 +167,6 @@ static int zstd_create(struct zcomp_params *params, struct zcomp_ctx *ctx) - return 0; - - error: -- zstd_release_params(params); - zstd_destroy(ctx); - return -EINVAL; - } -diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c ---- a/drivers/block/zram/zram_drv.c -+++ b/drivers/block/zram/zram_drv.c -@@ -1664,6 +1664,17 @@ static void comp_algorithm_set(struct zram *zram, u32 prio, const char *alg) - zram->comp_algs[prio] = alg; - } - -+static void comp_params_reset(struct zram *zram, u32 prio) -+{ -+ struct zcomp_params *params = &zram->params[prio]; -+ -+ vfree(params->dict); -+ params->level = ZCOMP_PARAM_NOT_SET; -+ params->deflate.winbits = ZCOMP_PARAM_NOT_SET; -+ params->dict_sz = 0; -+ params->dict = NULL; -+} -+ - static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf) - { - const char *alg; -@@ -1684,20 +1695,10 @@ static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf) - } - - comp_algorithm_set(zram, prio, alg); -+ comp_params_reset(zram, prio); - return 0; - } - --static void comp_params_reset(struct zram *zram, u32 prio) --{ -- struct zcomp_params *params = &zram->params[prio]; -- -- vfree(params->dict); -- params->level = ZCOMP_PARAM_NOT_SET; -- params->deflate.winbits = ZCOMP_PARAM_NOT_SET; -- params->dict_sz = 0; -- params->dict = NULL; --} -- - static int comp_params_store(struct zram *zram, u32 prio, s32 level, - const char *dict_path, - struct deflate_params *deflate_params) -@@ -1712,8 +1713,16 @@ static int comp_params_store(struct zram *zram, u32 prio, s32 level, - INT_MAX, - NULL, - READING_POLICY); -- if (sz < 0) -+ if (sz < 0) { -+ pr_err("failed to load dictionary %s (err=%zd)\n", -+ dict_path, sz); -+ return sz; -+ } -+ if (sz == 0) { -+ pr_err("failed to load dictionary %s (empty file)\n", -+ dict_path); - return -EINVAL; -+ } - } - - zram->params[prio].dict_sz = sz; -diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h ---- a/include/linux/memcontrol.h -+++ b/include/linux/memcontrol.h -@@ -952,6 +952,8 @@ unsigned long memcg_page_state_output(struct mem_cgroup *memcg, int item); - bool memcg_stat_item_valid(int idx); - bool memcg_vm_event_item_valid(enum vm_event_item idx); - unsigned long lruvec_page_state(struct lruvec *lruvec, enum node_stat_item idx); -+unsigned long lruvec_page_state_monotonic(struct lruvec *lruvec, -+ enum node_stat_item idx); - unsigned long lruvec_page_state_local(struct lruvec *lruvec, - enum node_stat_item idx); - -@@ -1404,6 +1406,12 @@ static inline unsigned long lruvec_page_state(struct lruvec *lruvec, - return node_page_state(lruvec_pgdat(lruvec), idx); - } - -+static inline unsigned long lruvec_page_state_monotonic(struct lruvec *lruvec, -+ enum node_stat_item idx) -+{ -+ return node_page_state_monotonic(lruvec_pgdat(lruvec), idx); -+} -+ - static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec, - enum node_stat_item idx) - { -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -323,6 +323,8 @@ enum node_stat_item { - PGSCAN_PROACTIVE, - PGSCAN_ANON, - PGSCAN_FILE, -+ PGROTATE_ANON, -+ PGROTATE_FILE, - PGREFILL, - #ifdef CONFIG_HUGETLB_PAGE - NR_HUGETLB, -@@ -755,6 +757,12 @@ void lru_gen_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, - - #endif /* CONFIG_LRU_GEN */ - -+struct lru_cost { -+ unsigned long count; -+ unsigned long last_rotated; -+ unsigned long last_io; -+}; -+ - struct lruvec { - struct list_head lists[NR_LRU_LISTS]; - /* per lruvec lru_lock for memcg */ -@@ -763,9 +771,12 @@ struct lruvec { - * These track the cost of reclaiming one LRU - file or anon - - * over the other. As the observed cost of reclaiming one LRU - * increases, the reclaim scan balance tips toward the other. -+ * Updated and decayed at prepare_scan_control() time; cost_lock -+ * serialises that update. - */ -- unsigned long anon_cost; -- unsigned long file_cost; -+ struct lru_cost cost[ANON_AND_FILE]; -+ /* Protects cost[]. */ -+ spinlock_t cost_lock; - /* Non-resident age, driven by LRU movement */ - atomic_long_t nonresident_age; - /* Refaults at the time of last reclaim cycle */ -diff --git a/include/linux/swap.h b/include/linux/swap.h ---- a/include/linux/swap.h -+++ b/include/linux/swap.h -@@ -309,9 +309,6 @@ extern unsigned long totalreserve_pages; - - - /* linux/mm/swap.c */ --void lru_note_cost_unlock_irq(struct lruvec *lruvec, bool file, -- unsigned int nr_io, unsigned int nr_rotated); --void lru_note_cost_refault(struct folio *); - void folio_add_lru(struct folio *); - void folio_add_lru_vma(struct folio *, struct vm_area_struct *); - void mark_page_accessed(struct page *); -diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h ---- a/include/linux/vmstat.h -+++ b/include/linux/vmstat.h -@@ -20,7 +20,6 @@ struct reclaim_stat { - unsigned nr_congested; - unsigned nr_writeback; - unsigned nr_immediate; -- unsigned nr_pageout; - unsigned nr_activate[ANON_AND_FILE]; - unsigned nr_ref_keep; - unsigned nr_unmap_fail; -@@ -194,6 +193,19 @@ unsigned long global_node_page_state_pages(enum node_stat_item item) - return x; - } - -+/* -+ * Non-clamping variant of global_node_page_state() intended for callers that -+ * snapshot a monotonically-incremented counter and subtract two samples. -+ * Returns the raw wrapping value so that unsigned modular subtraction stays -+ * correct across a signed-long overflow (a real hazard on 32-bit) that the -+ * clamp in global_node_page_state() would otherwise turn into a huge spurious -+ * delta. Do NOT use for non-monotonic page-count reads. -+ */ -+static inline unsigned long global_node_page_state_monotonic(enum node_stat_item item) -+{ -+ return (unsigned long)atomic_long_read(&vm_node_stat[item]); -+} -+ - static inline unsigned long global_node_page_state(enum node_stat_item item) - { - VM_WARN_ON_ONCE(vmstat_item_in_bytes(item)); -@@ -259,11 +271,14 @@ extern unsigned long node_page_state(struct pglist_data *pgdat, - enum node_stat_item item); - extern unsigned long node_page_state_pages(struct pglist_data *pgdat, - enum node_stat_item item); -+extern unsigned long node_page_state_monotonic(struct pglist_data *pgdat, -+ enum node_stat_item item); - extern void fold_vm_numa_events(void); - #else - #define sum_zone_node_page_state(node, item) global_zone_page_state(item) - #define node_page_state(node, item) global_node_page_state(item) - #define node_page_state_pages(node, item) global_node_page_state_pages(item) -+#define node_page_state_monotonic(node, item) global_node_page_state_monotonic(item) - static inline void fold_vm_numa_events(void) - { - } -diff --git a/lib/maple_tree.c b/lib/maple_tree.c ---- a/lib/maple_tree.c -+++ b/lib/maple_tree.c -@@ -1501,14 +1501,26 @@ static inline void mas_parent_gap(struct ma_state *mas, unsigned char offset, - goto ascend; - } - -+static __always_inline void mas_update_gap_known(struct ma_state *mas, -+ unsigned long gap) -+{ -+ unsigned char pslot; -+ unsigned long p_gap; -+ -+ pslot = mte_parent_slot(mas->node); -+ p_gap = ma_gaps(mte_parent(mas->node), -+ mas_parent_type(mas, mas->node))[pslot]; -+ -+ if (p_gap != gap) -+ mas_parent_gap(mas, pslot, gap); -+} -+ - /* - * mas_update_gap() - Update a nodes gaps and propagate up if necessary. - * @mas: the maple state. - */ - static inline void mas_update_gap(struct ma_state *mas) - { -- unsigned char pslot; -- unsigned long p_gap; - unsigned long max_gap; - - if (!mt_is_alloc(mas->tree)) -@@ -1518,13 +1530,7 @@ static inline void mas_update_gap(struct ma_state *mas) - return; - - max_gap = mas_max_gap(mas); -- -- pslot = mte_parent_slot(mas->node); -- p_gap = ma_gaps(mte_parent(mas->node), -- mas_parent_type(mas, mas->node))[pslot]; -- -- if (p_gap != max_gap) -- mas_parent_gap(mas, pslot, max_gap); -+ mas_update_gap_known(mas, max_gap); - } - - /* -@@ -2081,8 +2087,8 @@ static inline void mas_wmb_replace(struct ma_state *mas, struct maple_copy *cp) - mas->node = mt_slot_locked(mas->tree, cp->slot, 0); - /* Insert the new data in the tree */ - mas_topiary_replace(mas, old_enode, cp->height); -- if (!mte_is_leaf(mas->node)) -- mas_update_gap(mas); -+ if (mt_is_alloc(mas->tree) && !mte_is_root(mas->node)) -+ mas_update_gap_known(mas, cp->gap[0]); - - mtree_range_walk(mas); - } -@@ -3125,7 +3131,7 @@ static void mas_wr_spanning_store(struct ma_wr_state *wr_mas) - static inline void mas_wr_node_store(struct ma_wr_state *wr_mas) - { - unsigned char dst_offset, offset_end; -- unsigned char copy_size, node_pivots; -+ unsigned char copy_size, node_pivots, node_slots; - struct maple_node reuse, *newnode; - unsigned long *dst_pivots; - void __rcu **dst_slots; -@@ -3138,6 +3144,7 @@ static inline void mas_wr_node_store(struct ma_wr_state *wr_mas) - in_rcu = mt_in_rcu(mas->tree); - offset_end = wr_mas->offset_end; - node_pivots = mt_pivots[wr_mas->type]; -+ node_slots = mt_slots[wr_mas->type]; - /* Assume last adds an entry */ - new_end = mas->end + 1 - offset_end + mas->offset; - if (mas->last == wr_mas->end_piv) { -@@ -3149,7 +3156,6 @@ static inline void mas_wr_node_store(struct ma_wr_state *wr_mas) - if (in_rcu) { - newnode = mas_pop_node(mas); - } else { -- memset(&reuse, 0, sizeof(struct maple_node)); - newnode = &reuse; - } - -@@ -3193,7 +3199,21 @@ static inline void mas_wr_node_store(struct ma_wr_state *wr_mas) - dst_pivots[new_end] = mas->max; - - done: -- mas_leaf_set_meta(newnode, maple_leaf_64, new_end); -+ if (!in_rcu && new_end + 2 < node_slots) { -+ unsigned char clear_from = new_end + 1; -+ -+ /* -+ * Note that the last slot is never cleared, since the metadata -+ * will be stored there or it has a value. -+ */ -+ memset(dst_slots + clear_from, 0, -+ sizeof(void __rcu *) * (node_slots - clear_from)); -+ if (clear_from < node_pivots) -+ memset(dst_pivots + clear_from, 0, -+ sizeof(unsigned long) * (node_pivots - clear_from)); -+ } -+ -+ mas_leaf_set_meta(newnode, wr_mas->type, new_end); - if (in_rcu) { - struct maple_enode *old_enode = mas->node; - -@@ -3218,7 +3238,7 @@ static inline void mas_wr_slot_store(struct ma_wr_state *wr_mas) - void __rcu **slots = wr_mas->slots; - bool gap = false; - -- gap |= !mt_slot_locked(mas->tree, slots, offset); -+ gap |= !wr_mas->content; - gap |= !mt_slot_locked(mas->tree, slots, offset + 1); - - if (wr_mas->offset_end - offset == 1) { -@@ -3661,6 +3681,9 @@ static inline enum store_type mas_wr_store_type(struct ma_wr_state *wr_mas) - { - struct ma_state *mas = wr_mas->mas; - unsigned char new_end; -+ bool appending; -+ bool one_slot; -+ bool in_rcu; - - if (unlikely(mas_is_none(mas) || mas_is_ptr(mas))) - return wr_store_root; -@@ -3680,21 +3703,30 @@ static inline enum store_type mas_wr_store_type(struct ma_wr_state *wr_mas) - return wr_new_root; - - new_end = mas_wr_new_end(wr_mas); -+ in_rcu = mt_in_rcu(mas->tree); -+ appending = mas->offset == mas->end; -+ one_slot = wr_mas->offset_end - mas->offset == 1; -+ - /* Potential spanning rebalance collapsing a node */ - if (new_end < mt_min_slots[wr_mas->type]) { - if (!mte_is_root(mas->node)) - return wr_rebalance; -+ if (!in_rcu) { -+ if (appending) -+ return wr_append; -+ else if (mas->end == new_end && one_slot) -+ return wr_slot_store; -+ } - return wr_node_store; - } - - if (new_end >= mt_slots[wr_mas->type]) - return wr_split_store; - -- if (!mt_in_rcu(mas->tree) && (mas->offset == mas->end)) -+ if (!in_rcu && appending) - return wr_append; - -- if ((new_end == mas->end) && (!mt_in_rcu(mas->tree) || -- (wr_mas->offset_end - mas->offset == 1))) -+ if (new_end == mas->end && (!in_rcu || one_slot)) - return wr_slot_store; - - return wr_node_store; -diff --git a/mm/khugepaged.c b/mm/khugepaged.c ---- a/mm/khugepaged.c -+++ b/mm/khugepaged.c -@@ -1442,10 +1442,10 @@ static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long s - - result = SCAN_SUCCEED; - out_up_write: -- if (anon_vma_locked) -- anon_vma_unlock_write(vma->anon_vma); - if (pte) - pte_unmap(pte); -+ if (anon_vma_locked) -+ anon_vma_unlock_write(vma->anon_vma); - mmap_write_unlock(mm); - out_nolock: - if (folio) -diff --git a/mm/ksm.c b/mm/ksm.c ---- a/mm/ksm.c -+++ b/mm/ksm.c -@@ -3061,10 +3061,9 @@ int __ksm_enter(struct mm_struct *mm) - - slot = &mm_slot->slot; - -+ spin_lock(&ksm_mmlist_lock); - /* Check ksm_run too? Would need tighter locking */ - needs_wakeup = list_empty(&ksm_mm_head.slot.mm_node); -- -- spin_lock(&ksm_mmlist_lock); - mm_slot_insert(mm_slots_hash, mm, slot); - /* - * When KSM_RUN_MERGE (or KSM_RUN_STOP), -diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c ---- a/mm/memcontrol-v1.c -+++ b/mm/memcontrol-v1.c -@@ -1998,8 +1998,8 @@ void memcg1_stat_format(struct mem_cgroup *memcg, struct seq_buf *s) - for_each_online_pgdat(pgdat) { - mz = memcg->nodeinfo[pgdat->node_id]; - -- anon_cost += mz->lruvec.anon_cost; -- file_cost += mz->lruvec.file_cost; -+ anon_cost += mz->lruvec.cost[WORKINGSET_ANON].count; -+ file_cost += mz->lruvec.cost[WORKINGSET_FILE].count; - } - seq_buf_printf(s, "anon_cost %lu\n", anon_cost); - seq_buf_printf(s, "file_cost %lu\n", file_cost); -diff --git a/mm/memcontrol.c b/mm/memcontrol.c ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -393,6 +393,7 @@ static const unsigned int memcg_node_stat_items[] = { - NR_SHMEM_THPS, - NR_FILE_THPS, - NR_ANON_THPS, -+ NR_VMSCAN_WRITE, - NR_VMALLOC, - NR_KERNEL_STACK_KB, - NR_PAGETABLE, -@@ -419,6 +420,8 @@ static const unsigned int memcg_node_stat_items[] = { - PGSCAN_PROACTIVE, - PGSCAN_ANON, - PGSCAN_FILE, -+ PGROTATE_ANON, -+ PGROTATE_FILE, - PGREFILL, - #ifdef CONFIG_HUGETLB_PAGE - NR_HUGETLB, -@@ -502,6 +505,42 @@ unsigned long lruvec_page_state(struct lruvec *lruvec, enum node_stat_item idx) - return x; - } - -+/** -+ * lruvec_page_state_monotonic - non-clamping lruvec stat read for delta sampling -+ * @lruvec: the LRU vector to read from -+ * @idx: the node_stat_item to read -+ * -+ * Returns the raw state[idx] value cast to unsigned long, skipping the -+ * clamp-negative-to-zero step in lruvec_page_state(). Intended for callers -+ * that snapshot a monotonically-incremented counter and subtract two -+ * samples: unsigned modular arithmetic then yields the correct delta across -+ * a signed-long wraparound (a real hazard on 32-bit) that the clamp would -+ * otherwise turn into a huge spurious delta. -+ * -+ * Do NOT use for non-monotonic page-count reads where a transient negative -+ * reading from per-CPU delta skew must present as zero. -+ * -+ * XXX: This helper (and its node/global peers) exists because some -+ * monotonically-incremented event counters are stored in -+ * enum node_stat_item. -+ */ -+unsigned long lruvec_page_state_monotonic(struct lruvec *lruvec, -+ enum node_stat_item idx) -+{ -+ struct mem_cgroup_per_node *pn; -+ int i; -+ -+ if (mem_cgroup_disabled()) -+ return node_page_state_monotonic(lruvec_pgdat(lruvec), idx); -+ -+ i = memcg_stats_index(idx); -+ if (WARN_ONCE(BAD_STAT_IDX(i), "%s: missing stat item %d\n", __func__, idx)) -+ return 0; -+ -+ pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec); -+ return (unsigned long)READ_ONCE(pn->lruvec_stats->state[i]); -+} -+ - unsigned long lruvec_page_state_local(struct lruvec *lruvec, - enum node_stat_item idx) - { -@@ -2095,7 +2134,12 @@ static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) - - stock_pages = READ_ONCE(stock->nr_pages[i]); - if (stock_pages >= nr_pages) { -- WRITE_ONCE(stock->nr_pages[i], stock_pages - nr_pages); -+ stock_pages -= nr_pages; -+ WRITE_ONCE(stock->nr_pages[i], stock_pages); -+ if (!stock_pages) { -+ css_put(&memcg->css); -+ WRITE_ONCE(stock->cached[i], NULL); -+ } - ret = true; - } - break; -diff --git a/mm/migrate_device.c b/mm/migrate_device.c ---- a/mm/migrate_device.c -+++ b/mm/migrate_device.c -@@ -872,7 +872,7 @@ static int migrate_vma_insert_huge_pmd_page(struct migrate_vma *migrate, - - if (flush) { - pte_free(vma->vm_mm, pgtable); -- flush_cache_page(vma, addr, addr + HPAGE_PMD_SIZE); -+ flush_cache_range(vma, addr, addr + HPAGE_PMD_SIZE); - pmdp_invalidate(vma, addr, pmdp); - } else { - pgtable_trans_huge_deposit(vma->vm_mm, pmdp, pgtable); -diff --git a/mm/mmzone.c b/mm/mmzone.c ---- a/mm/mmzone.c -+++ b/mm/mmzone.c -@@ -78,6 +78,7 @@ void lruvec_init(struct lruvec *lruvec) - - memset(lruvec, 0, sizeof(struct lruvec)); - spin_lock_init(&lruvec->lru_lock); -+ spin_lock_init(&lruvec->cost_lock); - zswap_lruvec_state_init(lruvec); - - for_each_lru(lru) -diff --git a/mm/mremap.c b/mm/mremap.c ---- a/mm/mremap.c -+++ b/mm/mremap.c -@@ -264,7 +264,7 @@ static int move_ptes(struct pagetable_move_control *pmc, - - for (; old_addr < old_end; old_ptep += nr_ptes, old_addr += nr_ptes * PAGE_SIZE, - new_ptep += nr_ptes, new_addr += nr_ptes * PAGE_SIZE) { -- VM_WARN_ON_ONCE(!pte_none(*new_ptep)); -+ VM_WARN_ON_ONCE(!pte_none(ptep_get(new_ptep))); - - nr_ptes = 1; - max_nr_ptes = (old_end - old_addr) >> PAGE_SHIFT; -diff --git a/mm/shmem.c b/mm/shmem.c ---- a/mm/shmem.c -+++ b/mm/shmem.c -@@ -3612,6 +3612,7 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, - struct shmem_inode_info *info = SHMEM_I(inode); - struct shmem_falloc shmem_falloc; - pgoff_t start, index, end, undo_fallocend; -+ loff_t aligned_end; - int error; - - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) -@@ -3668,8 +3669,15 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset, - goto out; - } - -+ /* Check for wraparound */ -+ if (check_add_overflow(offset + len, (loff_t)PAGE_SIZE - 1, -+ &aligned_end)) { -+ error = -EFBIG; -+ goto out; -+ } -+ - start = offset >> PAGE_SHIFT; -- end = (offset + len + PAGE_SIZE - 1) >> PAGE_SHIFT; -+ end = aligned_end >> PAGE_SHIFT; - /* Try to avoid a swapstorm if len is impossible to satisfy */ - if (sbinfo->max_blocks && end - start > sbinfo->max_blocks) { - error = -ENOSPC; -diff --git a/mm/swap.c b/mm/swap.c ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -272,73 +272,6 @@ void folio_rotate_reclaimable(struct folio *folio) - folio_batch_add_and_move(folio, lru_move_tail); - } - --void lru_note_cost_unlock_irq(struct lruvec *lruvec, bool file, -- unsigned int nr_io, unsigned int nr_rotated) -- __releases(lruvec->lru_lock) -- __releases(rcu) --{ -- unsigned long cost; -- -- /* -- * Reflect the relative cost of incurring IO and spending CPU -- * time on rotations. This doesn't attempt to make a precise -- * comparison, it just says: if reloads are about comparable -- * between the LRU lists, or rotations are overwhelmingly -- * different between them, adjust scan balance for CPU work. -- */ -- cost = nr_io * SWAP_CLUSTER_MAX + nr_rotated; -- if (!cost) { -- spin_unlock_irq(&lruvec->lru_lock); -- rcu_read_unlock(); -- return; -- } -- -- for (;;) { -- unsigned long lrusize; -- -- /* Record cost event */ -- if (file) -- lruvec->file_cost += cost; -- else -- lruvec->anon_cost += cost; -- -- /* -- * Decay previous events -- * -- * Because workloads change over time (and to avoid -- * overflow) we keep these statistics as a floating -- * average, which ends up weighing recent refaults -- * more than old ones. -- */ -- lrusize = lruvec_page_state(lruvec, NR_INACTIVE_ANON) + -- lruvec_page_state(lruvec, NR_ACTIVE_ANON) + -- lruvec_page_state(lruvec, NR_INACTIVE_FILE) + -- lruvec_page_state(lruvec, NR_ACTIVE_FILE); -- -- if (lruvec->file_cost + lruvec->anon_cost > lrusize / 4) { -- lruvec->file_cost /= 2; -- lruvec->anon_cost /= 2; -- } -- -- spin_unlock_irq(&lruvec->lru_lock); -- lruvec = parent_lruvec(lruvec); -- if (!lruvec) { -- rcu_read_unlock(); -- break; -- } -- spin_lock_irq(&lruvec->lru_lock); -- } --} -- --void lru_note_cost_refault(struct folio *folio) --{ -- struct lruvec *lruvec; -- -- lruvec = folio_lruvec_lock_irq(folio); -- lru_note_cost_unlock_irq(lruvec, folio_is_file_lru(folio), -- folio_nr_pages(folio), 0); --} -- - static void lru_activate(struct lruvec *lruvec, struct folio *folio) - { - long nr_pages = folio_nr_pages(folio); -@@ -1173,8 +1106,6 @@ void lru_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent, int - - child_lruvec = mem_cgroup_lruvec(memcg, NODE_DATA(nid)); - parent_lruvec = mem_cgroup_lruvec(parent, NODE_DATA(nid)); -- parent_lruvec->anon_cost += child_lruvec->anon_cost; -- parent_lruvec->file_cost += child_lruvec->file_cost; - - for_each_lru(lru) - lruvec_reparent_lru(child_lruvec, parent_lruvec, lru, nid); -diff --git a/mm/vma.c b/mm/vma.c ---- a/mm/vma.c -+++ b/mm/vma.c -@@ -1866,10 +1866,10 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, - bool *need_rmap_locks) - { - struct vm_area_struct *vma = *vmap; -- unsigned long vma_start = vma->vm_start; -+ unsigned long old_vma_start = vma->vm_start; - struct mm_struct *mm = vma->vm_mm; - struct vm_area_struct *new_vma; -- bool faulted_in_anon_vma = true; -+ bool can_self_merge = false; - VMA_ITERATOR(vmi, mm, addr); - VMG_VMA_STATE(vmg, &vmi, NULL, vma, addr, addr + len); - -@@ -1879,7 +1879,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, - */ - if (unlikely(vma_is_anonymous(vma) && !vma->anon_vma)) { - pgoff = addr >> PAGE_SHIFT; -- faulted_in_anon_vma = false; -+ can_self_merge = true; - } - - /* -@@ -1899,24 +1899,21 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, - new_vma = vma_merge_copied_range(&vmg); - - if (new_vma) { -- /* -- * Source vma may have been merged into new_vma -- */ -- if (unlikely(vma_start >= new_vma->vm_start && -- vma_start < new_vma->vm_end)) { -+ /* Self-merged and VMA replaced. */ -+ if (unlikely(new_vma->vm_start < old_vma_start && -+ new_vma->vm_end > old_vma_start)) { - /* -- * The only way we can get a vma_merge with -- * self during an mremap is if the vma hasn't -- * been faulted in yet and we were allowed to -- * reset the dst vma->vm_pgoff to the -- * destination address of the mremap to allow -- * the merge to happen. mremap must change the -- * vm_pgoff linearity between src and dst vmas -- * (in turn preventing a vma_merge) to be -- * safe. It is only safe to keep the vm_pgoff -- * linear if there are no pages mapped yet. -+ * The only way a VMA can both self-merge and be -+ * replaced is if the remap places the new VMA -+ * immediately prior to its old self ('next') and -+ * immediately after another VMA ('prev') causing the -+ * next to be removed and prev to be expanded to cover -+ * the entire range. -+ * -+ * This should only be possible if the page offset was -+ * updated, i.e. the VMA is unfaulted. - */ -- VM_BUG_ON_VMA(faulted_in_anon_vma, new_vma); -+ VM_WARN_ON_ONCE_VMA(!can_self_merge, new_vma); - *vmap = vma = new_vma; - } - *need_rmap_locks = (new_vma->vm_pgoff <= vma->vm_pgoff); -diff --git a/mm/vmscan.c b/mm/vmscan.c ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -669,7 +669,7 @@ static pageout_t pageout(struct folio *folio, struct address_space *mapping, - folio_clear_reclaim(folio); - - trace_mm_vmscan_write_folio(folio); -- node_stat_add_folio(folio, NR_VMSCAN_WRITE); -+ lruvec_stat_mod_folio(folio, NR_VMSCAN_WRITE, folio_nr_pages(folio)); - return PAGE_SUCCESS; - } - -@@ -1420,8 +1420,6 @@ static unsigned int shrink_folio_list(struct list_head *folio_list, - sc->nr_scanned -= (nr_pages - 1); - nr_pages = 1; - } -- stat->nr_pageout += nr_pages; -- - if (folio_test_writeback(folio)) - goto keep; - if (folio_test_dirty(folio)) -@@ -2045,10 +2043,10 @@ static unsigned long shrink_inactive_list(unsigned long nr_to_scan, - item = PGSTEAL_KSWAPD + reclaimer_offset(sc); - mod_lruvec_state(lruvec, item, nr_reclaimed); - mod_lruvec_state(lruvec, PGSTEAL_ANON + file, nr_reclaimed); -+ if (nr_scanned > nr_reclaimed) -+ mod_lruvec_state(lruvec, PGROTATE_ANON + file, -+ nr_scanned - nr_reclaimed); - -- lruvec_lock_irq(lruvec); -- lru_note_cost_unlock_irq(lruvec, file, stat.nr_pageout, -- nr_scanned - nr_reclaimed); - handle_reclaim_writeback(nr_taken, pgdat, sc, &stat); - trace_mm_vmscan_lru_shrink_inactive(pgdat->node_id, - nr_scanned, nr_reclaimed, &stat, sc->priority, file); -@@ -2154,9 +2152,9 @@ static void shrink_active_list(unsigned long nr_to_scan, - count_vm_events(PGDEACTIVATE, nr_deactivate); - count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE, nr_deactivate); - mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken); -+ if (nr_rotated) -+ mod_lruvec_state(lruvec, PGROTATE_ANON + file, nr_rotated); - -- lruvec_lock_irq(lruvec); -- lru_note_cost_unlock_irq(lruvec, file, 0, nr_rotated); - trace_mm_vmscan_lru_shrink_active(pgdat->node_id, nr_taken, nr_activate, - nr_deactivate, nr_rotated, sc->priority, file); - } -@@ -2289,8 +2287,10 @@ enum scan_balance { - - static void prepare_scan_control(pg_data_t *pgdat, struct scan_control *sc) - { -- unsigned long file; -+ struct lru_cost *anon_cost, *file_cost; - struct lruvec *target_lruvec; -+ unsigned long lrusize; -+ unsigned long file; - - if (lru_gen_enabled() && !lru_gen_switching()) - return; -@@ -2306,11 +2306,69 @@ static void prepare_scan_control(pg_data_t *pgdat, struct scan_control *sc) - - /* - * Determine the scan balance between anon and file LRUs. -+ * -+ * The cost model is based on rotations, refaults and -+ * reclaim-driven writes (anon only) on each side. -+ * -+ * These event counters are monotonic, so each reclaim cycle -+ * the delta since the last scan is extracted and incorporated -+ * into a decaying average. This ensures currency, as workloads -+ * change over time, and avoids overflow in the calculations. -+ * -+ * Use lruvec_page_state_monotonic() so unsigned subtraction -+ * yields the correct delta across a signed-long wraparound of -+ * the underlying counter (a real hazard on 32-bit that the -+ * clamp in lruvec_page_state() would otherwise turn into a huge -+ * spurious delta). - */ -- spin_lock_irq(&target_lruvec->lru_lock); -- sc->anon_cost = target_lruvec->anon_cost; -- sc->file_cost = target_lruvec->file_cost; -- spin_unlock_irq(&target_lruvec->lru_lock); -+ spin_lock(&target_lruvec->cost_lock); -+ -+ for (int f = 0; f <= 1; f++) { -+ struct lru_cost *cost = &target_lruvec->cost[f]; -+ unsigned long rotated, io, nr_rotated, nr_io; -+ -+ rotated = lruvec_page_state_monotonic(target_lruvec, -+ PGROTATE_ANON + f); -+ io = lruvec_page_state_monotonic(target_lruvec, -+ WORKINGSET_RESTORE_BASE + f); -+ if (f == WORKINGSET_ANON) -+ io += lruvec_page_state_monotonic(target_lruvec, -+ NR_VMSCAN_WRITE); -+ -+ nr_rotated = rotated - cost->last_rotated; -+ nr_io = io - cost->last_io; -+ -+ /* -+ * Reflect the relative cost of incurring IO and spending -+ * CPU time on rotations. This doesn't attempt to make a -+ * precise comparison, it just says: if reloads are about -+ * comparable between the LRU lists, or rotations are -+ * overwhelmingly different between them, adjust scan -+ * balance for CPU work. -+ */ -+ cost->count += nr_io * SWAP_CLUSTER_MAX + nr_rotated; -+ -+ cost->last_rotated = rotated; -+ cost->last_io = io; -+ } -+ -+ anon_cost = &target_lruvec->cost[WORKINGSET_ANON]; -+ file_cost = &target_lruvec->cost[WORKINGSET_FILE]; -+ -+ lrusize = lruvec_page_state(target_lruvec, NR_INACTIVE_ANON) + -+ lruvec_page_state(target_lruvec, NR_ACTIVE_ANON) + -+ lruvec_page_state(target_lruvec, NR_INACTIVE_FILE) + -+ lruvec_page_state(target_lruvec, NR_ACTIVE_FILE); -+ -+ while (anon_cost->count + file_cost->count > lrusize / 4) { -+ anon_cost->count /= 2; -+ file_cost->count /= 2; -+ } -+ -+ sc->anon_cost = anon_cost->count; -+ sc->file_cost = file_cost->count; -+ -+ spin_unlock(&target_lruvec->cost_lock); - - /* - * Target desirable inactive:active list ratios for the anon -@@ -4197,7 +4255,7 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr) - unsigned long end; - struct lru_gen_mm_walk *walk; - struct folio *last = NULL; -- int young = 1; -+ int young = nr; - pte_t *pte = pvmw->pte; - unsigned long addr = pvmw->address; - struct vm_area_struct *vma = pvmw->vma; -@@ -4819,7 +4877,8 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec, - struct reclaim_stat stat; - struct lru_gen_mm_walk *walk; - int scanned, reclaimed; -- int isolated = 0, type, type_scanned; -+ int isolated = 0, nr_isolated = 0, type, type_scanned; -+ unsigned long total_reclaimed = 0; - bool skip_retry = false; - struct mem_cgroup *memcg = lruvec_memcg(lruvec); - struct pglist_data *pgdat = lruvec_pgdat(lruvec); -@@ -4831,6 +4890,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec, - - scanned = isolate_folios(nr_to_scan, lruvec, sc, swappiness, - &list, &isolated, &type, &type_scanned); -+ nr_isolated = isolated; - - /* Scanning may have emptied the oldest gen, flush it */ - if (scanned) -@@ -4843,6 +4903,7 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec, - retry: - reclaimed = shrink_folio_list(&list, pgdat, sc, &stat, false, memcg); - sc->nr_reclaimed += reclaimed; -+ total_reclaimed += reclaimed; - /* Retry pass is only meant for clean folios without new isolation */ - if (isolated) - handle_reclaim_writeback(isolated, pgdat, sc, &stat); -@@ -4892,6 +4953,10 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec, - goto retry; - } - -+ if (nr_isolated > total_reclaimed) -+ mod_lruvec_state(lruvec, PGROTATE_ANON + type, -+ nr_isolated - total_reclaimed); -+ - return scanned; - } - -diff --git a/mm/vmstat.c b/mm/vmstat.c ---- a/mm/vmstat.c -+++ b/mm/vmstat.c -@@ -1024,6 +1024,17 @@ unsigned long node_page_state(struct pglist_data *pgdat, - - return node_page_state_pages(pgdat, item); - } -+ -+/* -+ * Non-clamping variant of node_page_state() intended for callers that -+ * snapshot a monotonically-incremented counter and subtract two samples. -+ * See global_node_page_state_monotonic() for the rationale. -+ */ -+unsigned long node_page_state_monotonic(struct pglist_data *pgdat, -+ enum node_stat_item item) -+{ -+ return (unsigned long)atomic_long_read(&pgdat->vm_stat[item]); -+} - #endif - - /* -@@ -1289,6 +1300,8 @@ const char * const vmstat_text[] = { - [I(PGSCAN_PROACTIVE)] = "pgscan_proactive", - [I(PGSCAN_ANON)] = "pgscan_anon", - [I(PGSCAN_FILE)] = "pgscan_file", -+ [I(PGROTATE_ANON)] = "pgrotate_anon", -+ [I(PGROTATE_FILE)] = "pgrotate_file", - [I(PGREFILL)] = "pgrefill", - #ifdef CONFIG_HUGETLB_PAGE - [I(NR_HUGETLB)] = "nr_hugetlb", -diff --git a/mm/workingset.c b/mm/workingset.c ---- a/mm/workingset.c -+++ b/mm/workingset.c -@@ -584,11 +584,6 @@ void workingset_refault(struct folio *folio, void *shadow) - /* Folio was active prior to eviction */ - if (workingset) { - folio_set_workingset(folio); -- /* -- * XXX: Move to folio_add_lru() when it supports new vs -- * putback -- */ -- lru_note_cost_refault(folio); - mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + file, nr); - } - out: -diff --git a/mm/zswap.c b/mm/zswap.c ---- a/mm/zswap.c -+++ b/mm/zswap.c -@@ -1217,7 +1217,7 @@ static unsigned long zswap_shrinker_count(struct shrinker *shrinker, - * Without memcg, use the zswap pool-wide metrics. - */ - if (!mem_cgroup_disabled()) { -- mem_cgroup_flush_stats(memcg); -+ mem_cgroup_flush_stats_ratelimited(memcg); - nr_backing = memcg_page_state(memcg, MEMCG_ZSWAP_B) >> PAGE_SHIFT; - nr_stored = memcg_page_state(memcg, MEMCG_ZSWAPPED); - } else { -@@ -1275,6 +1275,14 @@ static struct shrinker *zswap_alloc_shrinker(void) - return shrinker; - } - -+/* -+ * Scan up to SWAP_CLUSTER_MAX pages on each per-node zswap LRU of @memcg -+ * and write back the reclaimable ones. -+ * -+ * Return: 0 if at least one entry was written back, -EAGAIN if entries -+ * were scanned but none could be written back, or -ENOENT if @memcg has -+ * writeback disabled, is a zombie cgroup, or has empty zswap LRUs. -+ */ - static int shrink_memcg(struct mem_cgroup *memcg) - { - int nid, shrunk = 0, scanned = 0; -@@ -1290,13 +1298,14 @@ static int shrink_memcg(struct mem_cgroup *memcg) - return -ENOENT; - - for_each_node_state(nid, N_NORMAL_MEMORY) { -- unsigned long nr_to_walk = 1; -+ unsigned long nr_to_walk = SWAP_CLUSTER_MAX; - - shrunk += list_lru_walk_one(&zswap_list_lru, nid, memcg, - &shrink_memcg_cb, NULL, &nr_to_walk); -- scanned += 1 - nr_to_walk; -+ scanned += SWAP_CLUSTER_MAX - nr_to_walk; - } - -+ /* Nothing was scanned: every LRU under @memcg was empty. */ - if (!scanned) - return -ENOENT; - diff --git a/kernel/0280-mm-updates.patch.sig b/kernel/0280-mm-updates.patch.sig deleted file mode 100644 index 97d0386..0000000 Binary files a/kernel/0280-mm-updates.patch.sig and /dev/null differ diff --git a/kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch b/kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch deleted file mode 100644 index e8e9809..0000000 --- a/kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c ---- a/mm/pgtable-generic.c -+++ b/mm/pgtable-generic.c -@@ -438,12 +438,30 @@ static void kernel_pgtable_work_func(struct work_struct *work) - __pagetable_free(pt); - } - -+static void schedule_kernel_pgtable_free(void) -+{ -+ schedule_work(&kernel_pgtable_work.work); -+} -+ - void pagetable_free_kernel(struct ptdesc *pt) - { - spin_lock(&kernel_pgtable_work.lock); - list_add(&pt->pt_list, &kernel_pgtable_work.list); - spin_unlock(&kernel_pgtable_work.lock); - -- schedule_work(&kernel_pgtable_work.work); -+ /* -+ * The workqueue may not exist yet while the system is booting. -+ * kernel_pgtable_drain_early() schedules the work once it does. -+ */ -+ if (system_state != SYSTEM_BOOTING) -+ schedule_kernel_pgtable_free(); - } -+ -+static int __init kernel_pgtable_drain_early(void) -+{ -+ /* Free the kernel page tables queued while booting. */ -+ schedule_kernel_pgtable_free(); -+ return 0; -+} -+core_initcall(kernel_pgtable_drain_early); - #endif diff --git a/kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch.sig b/kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch.sig deleted file mode 100644 index d9c680c..0000000 Binary files a/kernel/0281-mm-no-deferred-kernel-page-table-free-at-boot.patch.sig and /dev/null differ diff --git a/kernel/0290-zstd-bmi2-fallback-aliases.patch b/kernel/0290-zstd-bmi2-fallback-aliases.patch deleted file mode 100644 index a14613c..0000000 --- a/kernel/0290-zstd-bmi2-fallback-aliases.patch +++ /dev/null @@ -1,97 +0,0 @@ -diff --git a/lib/zstd/common/entropy_common.c b/lib/zstd/common/entropy_common.c ---- a/lib/zstd/common/entropy_common.c -+++ b/lib/zstd/common/entropy_common.c -@@ -202,6 +202,8 @@ BMI2_TARGET_ATTRIBUTE static size_t FSE_readNCount_body_bmi2( - { - return FSE_readNCount_body(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); - } -+#else -+#define FSE_readNCount_body_bmi2 FSE_readNCount_body_default - #endif - - size_t FSE_readNCount_bmi2( -@@ -323,6 +325,8 @@ static BMI2_TARGET_ATTRIBUTE size_t HUF_readStats_body_bmi2(BYTE* huffWeight, si - { - return HUF_readStats_body(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize, 1); - } -+#else -+#define HUF_readStats_body_bmi2 HUF_readStats_body_default - #endif - - size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, -diff --git a/lib/zstd/common/fse_decompress.c b/lib/zstd/common/fse_decompress.c ---- a/lib/zstd/common/fse_decompress.c -+++ b/lib/zstd/common/fse_decompress.c -@@ -300,6 +300,8 @@ BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, siz - { - return FSE_decompress_wksp_body(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize, 1); - } -+#else -+#define FSE_decompress_wksp_body_bmi2 FSE_decompress_wksp_body_default - #endif - - size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) -diff --git a/lib/zstd/compress/zstd_compress_sequences.c b/lib/zstd/compress/zstd_compress_sequences.c ---- a/lib/zstd/compress/zstd_compress_sequences.c -+++ b/lib/zstd/compress/zstd_compress_sequences.c -@@ -415,6 +415,10 @@ ZSTD_encodeSequences_bmi2( - sequences, nbSeq, longOffsets); - } - -+#else -+ -+#define ZSTD_encodeSequences_bmi2 ZSTD_encodeSequences_default -+ - #endif - - size_t ZSTD_encodeSequences( -diff --git a/lib/zstd/decompress/huf_decompress.c b/lib/zstd/decompress/huf_decompress.c ---- a/lib/zstd/decompress/huf_decompress.c -+++ b/lib/zstd/decompress/huf_decompress.c -@@ -700,6 +700,8 @@ size_t HUF_decompress4X1_usingDTable_internal_bmi2(void* dst, size_t dstSize, vo - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X1_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); - } -+#else -+#define HUF_decompress4X1_usingDTable_internal_bmi2 HUF_decompress4X1_usingDTable_internal_default - #endif - - static -@@ -1503,6 +1505,8 @@ size_t HUF_decompress4X2_usingDTable_internal_bmi2(void* dst, size_t dstSize, vo - size_t cSrcSize, HUF_DTable const* DTable) { - return HUF_decompress4X2_usingDTable_internal_body(dst, dstSize, cSrc, cSrcSize, DTable); - } -+#else -+#define HUF_decompress4X2_usingDTable_internal_bmi2 HUF_decompress4X2_usingDTable_internal_default - #endif - - static -diff --git a/lib/zstd/decompress/zstd_decompress_block.c b/lib/zstd/decompress/zstd_decompress_block.c ---- a/lib/zstd/decompress/zstd_decompress_block.c -+++ b/lib/zstd/decompress/zstd_decompress_block.c -@@ -622,6 +622,8 @@ BMI2_TARGET_ATTRIBUTE static void ZSTD_buildFSETable_body_bmi2(ZSTD_seqSymbol* d - ZSTD_buildFSETable_body(dt, normalizedCounter, maxSymbolValue, - baseValue, nbAdditionalBits, tableLog, wksp, wkspSize); - } -+#else -+#define ZSTD_buildFSETable_body_bmi2 ZSTD_buildFSETable_body_default - #endif - - void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, -@@ -1934,6 +1936,16 @@ ZSTD_decompressSequencesLong_bmi2(ZSTD_DCtx* dctx, - } - #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ - -+#else -+ -+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG -+#define ZSTD_decompressSequences_bmi2 ZSTD_decompressSequences_default -+#define ZSTD_decompressSequencesSplitLitBuffer_bmi2 ZSTD_decompressSequencesSplitLitBuffer_default -+#endif -+#ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT -+#define ZSTD_decompressSequencesLong_bmi2 ZSTD_decompressSequencesLong_default -+#endif -+ - #endif /* DYNAMIC_BMI2 */ - - #ifndef ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG diff --git a/kernel/0290-zstd-bmi2-fallback-aliases.patch.sig b/kernel/0290-zstd-bmi2-fallback-aliases.patch.sig deleted file mode 100644 index 66df3c4..0000000 Binary files a/kernel/0290-zstd-bmi2-fallback-aliases.patch.sig and /dev/null differ diff --git a/kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch b/kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch deleted file mode 100644 index 9f0b872..0000000 --- a/kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch +++ /dev/null @@ -1,413 +0,0 @@ -diff --git a/lib/zstd/common/compiler.h b/lib/zstd/common/compiler.h ---- a/lib/zstd/common/compiler.h -+++ b/lib/zstd/common/compiler.h -@@ -14,6 +14,7 @@ - - #include - -+#include "zstd_deps.h" - #include "portability_macros.h" - - /*-******************************************************* -@@ -96,6 +97,17 @@ - */ - #define BMI2_TARGET_ATTRIBUTE TARGET_ATTRIBUTE("lzcnt,bmi,bmi2") - -+#if !DYNAMIC_BMI2 -+# define ZSTD_USE_BMI2(bmi2) 0 -+# define ZSTD_SET_BMI2(state, value) do { } while (0) -+#elif defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+# define ZSTD_USE_BMI2(bmi2) cpu_feature_enabled(X86_FEATURE_BMI2) -+# define ZSTD_SET_BMI2(state, value) do { } while (0) -+#else -+# define ZSTD_USE_BMI2(bmi2) (bmi2) -+# define ZSTD_SET_BMI2(state, value) do { (state) = (value); } while (0) -+#endif -+ - /* prefetch - * can be disabled, by declaring NO_PREFETCH build macro */ - #if ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) -diff --git a/lib/zstd/common/entropy_common.c b/lib/zstd/common/entropy_common.c ---- a/lib/zstd/common/entropy_common.c -+++ b/lib/zstd/common/entropy_common.c -@@ -16,6 +16,10 @@ - /* ************************************* - * Dependencies - ***************************************/ -+#include "zstd_deps.h" -+#if defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+#include -+#endif - #include "mem.h" - #include "error_private.h" /* ERR_*, ERROR */ - #define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */ -@@ -210,11 +214,9 @@ size_t FSE_readNCount_bmi2( - short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr, - const void* headerBuffer, size_t hbSize, int bmi2) - { --#if DYNAMIC_BMI2 -- if (bmi2) { -+ if (ZSTD_USE_BMI2(bmi2)) { - return FSE_readNCount_body_bmi2(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); - } --#endif - (void)bmi2; - return FSE_readNCount_body_default(normalizedCounter, maxSVPtr, tableLogPtr, headerBuffer, hbSize); - } -@@ -335,11 +337,9 @@ size_t HUF_readStats_wksp(BYTE* huffWeight, size_t hwSize, U32* rankStats, - void* workSpace, size_t wkspSize, - int flags) - { --#if DYNAMIC_BMI2 -- if (flags & HUF_flags_bmi2) { -+ if (ZSTD_USE_BMI2(flags & HUF_flags_bmi2)) { - return HUF_readStats_body_bmi2(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); - } --#endif - (void)flags; - return HUF_readStats_body_default(huffWeight, hwSize, rankStats, nbSymbolsPtr, tableLogPtr, src, srcSize, workSpace, wkspSize); - } -diff --git a/lib/zstd/common/fse_decompress.c b/lib/zstd/common/fse_decompress.c ---- a/lib/zstd/common/fse_decompress.c -+++ b/lib/zstd/common/fse_decompress.c -@@ -24,6 +24,9 @@ - #include "fse.h" - #include "error_private.h" - #include "zstd_deps.h" /* ZSTD_memcpy */ -+#if defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+#include -+#endif - #include "bits.h" /* ZSTD_highbit32 */ - - -@@ -306,11 +309,9 @@ BMI2_TARGET_ATTRIBUTE static size_t FSE_decompress_wksp_body_bmi2(void* dst, siz - - size_t FSE_decompress_wksp_bmi2(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, unsigned maxLog, void* workSpace, size_t wkspSize, int bmi2) - { --#if DYNAMIC_BMI2 -- if (bmi2) { -+ if (ZSTD_USE_BMI2(bmi2)) { - return FSE_decompress_wksp_body_bmi2(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); - } --#endif - (void)bmi2; - return FSE_decompress_wksp_body_default(dst, dstCapacity, cSrc, cSrcSize, maxLog, workSpace, wkspSize); - } -diff --git a/lib/zstd/common/zstd_deps.h b/lib/zstd/common/zstd_deps.h ---- a/lib/zstd/common/zstd_deps.h -+++ b/lib/zstd/common/zstd_deps.h -@@ -26,6 +26,11 @@ - #ifndef ZSTD_DEPS_COMMON - #define ZSTD_DEPS_COMMON - -+#if defined(__KERNEL__) && defined(CONFIG_X86) && \ -+ !defined(__DISABLE_EXPORTS) -+#define ZSTD_USE_KERNEL_CPU_FEATURES -+#endif -+ - #include - #include - -diff --git a/lib/zstd/compress/huf_compress.c b/lib/zstd/compress/huf_compress.c ---- a/lib/zstd/compress/huf_compress.c -+++ b/lib/zstd/compress/huf_compress.c -@@ -22,6 +22,9 @@ - * Includes - ****************************************************************/ - #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ -+#if defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+#include -+#endif - #include "../common/compiler.h" - #include "../common/bitstream.h" - #include "hist.h" -@@ -1138,9 +1141,10 @@ HUF_compress1X_usingCTable_internal(void* dst, size_t dstSize, - const void* src, size_t srcSize, - const HUF_CElt* CTable, const int flags) - { -- if (flags & HUF_flags_bmi2) { -+ if (ZSTD_USE_BMI2(flags & HUF_flags_bmi2)) { - return HUF_compress1X_usingCTable_internal_bmi2(dst, dstSize, src, srcSize, CTable); - } -+ (void)flags; - return HUF_compress1X_usingCTable_internal_default(dst, dstSize, src, srcSize, CTable); - } - -diff --git a/lib/zstd/compress/zstd_compress.c b/lib/zstd/compress/zstd_compress.c ---- a/lib/zstd/compress/zstd_compress.c -+++ b/lib/zstd/compress/zstd_compress.c -@@ -102,7 +102,7 @@ static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) - assert(cctx != NULL); - ZSTD_memset(cctx, 0, sizeof(*cctx)); - cctx->customMem = memManager; -- cctx->bmi2 = ZSTD_cpuSupportsBmi2(); -+ ZSTD_SET_BMI2(cctx->bmi2, ZSTD_cpuSupportsBmi2()); - { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); - assert(!ZSTD_isError(err)); - (void)err; -@@ -142,7 +142,7 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) - cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); - cctx->tmpWorkspace = ZSTD_cwksp_reserve_object(&cctx->workspace, TMP_WORKSPACE_SIZE); - cctx->tmpWkspSize = TMP_WORKSPACE_SIZE; -- cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); -+ ZSTD_SET_BMI2(cctx->bmi2, ZSTD_cpuid_bmi2(ZSTD_cpuid())); - return cctx; - } - -@@ -4042,7 +4042,7 @@ ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, - op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, - srcSize, - zc->tmpWorkspace, zc->tmpWkspSize /* statically allocated in resetCCtx */, -- zc->bmi2); -+ ZSTD_CCtx_get_bmi2(zc)); - FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!"); - - if (!zc->isFirstBlock && -@@ -4332,7 +4332,7 @@ ZSTD_compressBlock_internal(ZSTD_CCtx* zc, - dst, dstCapacity, - srcSize, - zc->tmpWorkspace, zc->tmpWkspSize /* statically allocated in resetCCtx */, -- zc->bmi2); -+ ZSTD_CCtx_get_bmi2(zc)); - - if (frame && - /* We don't want to emit our first block as a RLE even if it qualifies because -@@ -6796,7 +6796,7 @@ ZSTD_compressSequences_internal(ZSTD_CCtx* cctx, - op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize, - blockSize, - cctx->tmpWorkspace, cctx->tmpWkspSize /* statically allocated in resetCCtx */, -- cctx->bmi2); -+ ZSTD_CCtx_get_bmi2(cctx)); - FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); - DEBUGLOG(5, "Compressed sequences size: %zu", compressedSeqsSize); - -@@ -7321,7 +7321,7 @@ ZSTD_compressSequencesAndLiterals_internal(ZSTD_CCtx* cctx, - &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy, - &cctx->appliedParams, - cctx->tmpWorkspace, cctx->tmpWkspSize /* statically allocated in resetCCtx */, -- cctx->bmi2); -+ ZSTD_CCtx_get_bmi2(cctx)); - FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); - /* note: the spec forbids for any compressed block to be larger than maximum block size */ - if (compressedSeqsSize > cctx->blockSizeMax) compressedSeqsSize = 0; -diff --git a/lib/zstd/compress/zstd_compress_internal.h b/lib/zstd/compress/zstd_compress_internal.h ---- a/lib/zstd/compress/zstd_compress_internal.h -+++ b/lib/zstd/compress/zstd_compress_internal.h -@@ -537,6 +537,15 @@ struct ZSTD_CCtx_s { - size_t extSeqBufCapacity; - }; - -+MEM_STATIC int ZSTD_CCtx_get_bmi2(const struct ZSTD_CCtx_s *cctx) { -+#if DYNAMIC_BMI2 && !defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+ return cctx->bmi2; -+#else -+ (void)cctx; -+ return 0; -+#endif -+} -+ - typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e; - typedef enum { ZSTD_tfp_forCCtx, ZSTD_tfp_forCDict } ZSTD_tableFillPurpose_e; - -diff --git a/lib/zstd/compress/zstd_compress_sequences.c b/lib/zstd/compress/zstd_compress_sequences.c ---- a/lib/zstd/compress/zstd_compress_sequences.c -+++ b/lib/zstd/compress/zstd_compress_sequences.c -@@ -12,6 +12,10 @@ - /*-************************************* - * Dependencies - ***************************************/ -+#include "../common/zstd_deps.h" -+#if defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+#include -+#endif - #include "zstd_compress_sequences.h" - - /* -@@ -429,15 +433,13 @@ size_t ZSTD_encodeSequences( - SeqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2) - { - DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity); --#if DYNAMIC_BMI2 -- if (bmi2) { -+ if (ZSTD_USE_BMI2(bmi2)) { - return ZSTD_encodeSequences_bmi2(dst, dstCapacity, - CTable_MatchLength, mlCodeTable, - CTable_OffsetBits, ofCodeTable, - CTable_LitLength, llCodeTable, - sequences, nbSeq, longOffsets); - } --#endif - (void)bmi2; - return ZSTD_encodeSequences_default(dst, dstCapacity, - CTable_MatchLength, mlCodeTable, -diff --git a/lib/zstd/compress/zstd_compress_superblock.c b/lib/zstd/compress/zstd_compress_superblock.c ---- a/lib/zstd/compress/zstd_compress_superblock.c -+++ b/lib/zstd/compress/zstd_compress_superblock.c -@@ -684,6 +684,6 @@ size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, - &zc->appliedParams, - dst, dstCapacity, - src, srcSize, -- zc->bmi2, lastBlock, -+ ZSTD_CCtx_get_bmi2(zc), lastBlock, - zc->tmpWorkspace, zc->tmpWkspSize /* statically allocated in resetCCtx */); - } -diff --git a/lib/zstd/decompress/huf_decompress.c b/lib/zstd/decompress/huf_decompress.c ---- a/lib/zstd/decompress/huf_decompress.c -+++ b/lib/zstd/decompress/huf_decompress.c -@@ -17,6 +17,9 @@ - * Dependencies - ****************************************************************/ - #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memset */ -+#if defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+#include -+#endif - #include "../common/compiler.h" - #include "../common/bitstream.h" /* BIT_* */ - #include "../common/fse.h" /* to compress headers */ -@@ -113,9 +116,10 @@ typedef size_t (*HUF_DecompressUsingDTableFn)(void *dst, size_t dstSize, - static size_t fn(void* dst, size_t dstSize, void const* cSrc, \ - size_t cSrcSize, HUF_DTable const* DTable, int flags) \ - { \ -- if (flags & HUF_flags_bmi2) { \ -+ if (ZSTD_USE_BMI2(flags & HUF_flags_bmi2)) { \ - return fn##_bmi2(dst, dstSize, cSrc, cSrcSize, DTable); \ - } \ -+ (void)flags; \ - return fn##_default(dst, dstSize, cSrc, cSrcSize, DTable); \ - } - -@@ -899,18 +903,16 @@ static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize, - HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X1_usingDTable_internal_default; - HUF_DecompressFastLoopFn loopFn = HUF_decompress4X1_usingDTable_internal_fast_c_loop; - --#if DYNAMIC_BMI2 -- if (flags & HUF_flags_bmi2) { -+ if (ZSTD_USE_BMI2(flags & HUF_flags_bmi2)) { - fallbackFn = HUF_decompress4X1_usingDTable_internal_bmi2; - # if ZSTD_ENABLE_ASM_X86_64_BMI2 - if (!(flags & HUF_flags_disableAsm)) { - loopFn = HUF_decompress4X1_usingDTable_internal_fast_asm_loop; - } - # endif -- } else { -+ } else if (DYNAMIC_BMI2) { - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); - } --#endif - - #if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) - if (!(flags & HUF_flags_disableAsm)) { -@@ -1723,18 +1725,16 @@ static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize, - HUF_DecompressUsingDTableFn fallbackFn = HUF_decompress4X2_usingDTable_internal_default; - HUF_DecompressFastLoopFn loopFn = HUF_decompress4X2_usingDTable_internal_fast_c_loop; - --#if DYNAMIC_BMI2 -- if (flags & HUF_flags_bmi2) { -+ if (ZSTD_USE_BMI2(flags & HUF_flags_bmi2)) { - fallbackFn = HUF_decompress4X2_usingDTable_internal_bmi2; - # if ZSTD_ENABLE_ASM_X86_64_BMI2 - if (!(flags & HUF_flags_disableAsm)) { - loopFn = HUF_decompress4X2_usingDTable_internal_fast_asm_loop; - } - # endif -- } else { -+ } else if (DYNAMIC_BMI2) { - return fallbackFn(dst, dstSize, cSrc, cSrcSize, DTable); - } --#endif - - #if ZSTD_ENABLE_ASM_X86_64_BMI2 && defined(__BMI2__) - if (!(flags & HUF_flags_disableAsm)) { -diff --git a/lib/zstd/decompress/zstd_decompress.c b/lib/zstd/decompress/zstd_decompress.c ---- a/lib/zstd/decompress/zstd_decompress.c -+++ b/lib/zstd/decompress/zstd_decompress.c -@@ -259,9 +259,7 @@ static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx) - dctx->noForwardProgress = 0; - dctx->oversizedDuration = 0; - dctx->isFrameDecompression = 1; --#if DYNAMIC_BMI2 -- dctx->bmi2 = ZSTD_cpuSupportsBmi2(); --#endif -+ ZSTD_SET_BMI2(dctx->bmi2, ZSTD_cpuSupportsBmi2()); - dctx->ddictSet = NULL; - ZSTD_DCtx_resetParameters(dctx); - #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -diff --git a/lib/zstd/decompress/zstd_decompress_block.c b/lib/zstd/decompress/zstd_decompress_block.c ---- a/lib/zstd/decompress/zstd_decompress_block.c -+++ b/lib/zstd/decompress/zstd_decompress_block.c -@@ -16,6 +16,9 @@ - * Dependencies - *********************************************************/ - #include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ -+#if defined(ZSTD_USE_KERNEL_CPU_FEATURES) -+#include -+#endif - #include "../common/compiler.h" /* prefetch */ - #include "../common/cpu.h" /* bmi2 */ - #include "../common/mem.h" /* low level memory routines */ -@@ -631,13 +634,11 @@ void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, - const U32* baseValue, const U8* nbAdditionalBits, - unsigned tableLog, void* wksp, size_t wkspSize, int bmi2) - { --#if DYNAMIC_BMI2 -- if (bmi2) { -+ if (ZSTD_USE_BMI2(bmi2)) { - ZSTD_buildFSETable_body_bmi2(dt, normalizedCounter, maxSymbolValue, - baseValue, nbAdditionalBits, tableLog, wksp, wkspSize); - return; - } --#endif - (void)bmi2; - ZSTD_buildFSETable_body_default(dt, normalizedCounter, maxSymbolValue, - baseValue, nbAdditionalBits, tableLog, wksp, wkspSize); -@@ -1955,11 +1956,9 @@ ZSTD_decompressSequences(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, - const ZSTD_longOffset_e isLongOffset) - { - DEBUGLOG(5, "ZSTD_decompressSequences"); --#if DYNAMIC_BMI2 -- if (ZSTD_DCtx_get_bmi2(dctx)) { -+ if (ZSTD_USE_BMI2(ZSTD_DCtx_get_bmi2(dctx))) { - return ZSTD_decompressSequences_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } --#endif - return ZSTD_decompressSequences_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } - static size_t -@@ -1968,11 +1967,9 @@ ZSTD_decompressSequencesSplitLitBuffer(ZSTD_DCtx* dctx, void* dst, size_t maxDst - const ZSTD_longOffset_e isLongOffset) - { - DEBUGLOG(5, "ZSTD_decompressSequencesSplitLitBuffer"); --#if DYNAMIC_BMI2 -- if (ZSTD_DCtx_get_bmi2(dctx)) { -+ if (ZSTD_USE_BMI2(ZSTD_DCtx_get_bmi2(dctx))) { - return ZSTD_decompressSequencesSplitLitBuffer_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } --#endif - return ZSTD_decompressSequencesSplitLitBuffer_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } - #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_LONG */ -@@ -1991,11 +1988,9 @@ ZSTD_decompressSequencesLong(ZSTD_DCtx* dctx, - const ZSTD_longOffset_e isLongOffset) - { - DEBUGLOG(5, "ZSTD_decompressSequencesLong"); --#if DYNAMIC_BMI2 -- if (ZSTD_DCtx_get_bmi2(dctx)) { -+ if (ZSTD_USE_BMI2(ZSTD_DCtx_get_bmi2(dctx))) { - return ZSTD_decompressSequencesLong_bmi2(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } --#endif - return ZSTD_decompressSequencesLong_default(dctx, dst, maxDstSize, seqStart, seqSize, nbSeq, isLongOffset); - } - #endif /* ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT */ -diff --git a/lib/zstd/decompress/zstd_decompress_internal.h b/lib/zstd/decompress/zstd_decompress_internal.h ---- a/lib/zstd/decompress/zstd_decompress_internal.h -+++ b/lib/zstd/decompress/zstd_decompress_internal.h -@@ -204,7 +204,7 @@ struct ZSTD_DCtx_s - }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ - - MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { --#if DYNAMIC_BMI2 -+#if DYNAMIC_BMI2 && !defined(ZSTD_USE_KERNEL_CPU_FEATURES) - return dctx->bmi2; - #else - (void)dctx; diff --git a/kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch.sig b/kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch.sig deleted file mode 100644 index 9fb78f3..0000000 Binary files a/kernel/0291-zstd-bmi2-cpu-feature-dispatch.patch.sig and /dev/null differ diff --git a/kernel/0292-crypto-zstd-defer-cstream-init.patch b/kernel/0292-crypto-zstd-defer-cstream-init.patch deleted file mode 100644 index 4007e61..0000000 --- a/kernel/0292-crypto-zstd-defer-cstream-init.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/crypto/zstd.c b/crypto/zstd.c ---- a/crypto/zstd.c -+++ b/crypto/zstd.c -@@ -96,6 +96,7 @@ static int zstd_compress_one(struct acomp_req *req, struct zstd_ctx *ctx, - - static int zstd_compress(struct acomp_req *req) - { -+ bool stream_initialized = false; - struct crypto_acomp_stream *s; - unsigned int pos, scur, dcur; - unsigned int total_out = 0; -@@ -115,12 +116,6 @@ static int zstd_compress(struct acomp_req *req) - if (ret) - goto out; - -- ctx->cctx = zstd_init_cstream(&ctx->params, 0, ctx->wksp, ctx->wksp_size); -- if (!ctx->cctx) { -- ret = -EINVAL; -- goto out; -- } -- - do { - dcur = acomp_walk_next_dst(&walk); - if (!dcur) { -@@ -142,6 +137,19 @@ static int zstd_compress(struct acomp_req *req) - goto out; - } - -+ if (!stream_initialized) { -+ ctx->cctx = zstd_init_cstream(&ctx->params, 0, -+ ctx->wksp, ctx->wksp_size); -+ if (!ctx->cctx) { -+ /* Release in the reverse of the map order. */ -+ acomp_walk_done_src(&walk, 0); -+ acomp_walk_done_dst(&walk, 0); -+ ret = -EINVAL; -+ goto out; -+ } -+ stream_initialized = true; -+ } -+ - if (scur) { - inbuf.pos = 0; - inbuf.src = walk.src.virt.addr; diff --git a/kernel/0292-crypto-zstd-defer-cstream-init.patch.sig b/kernel/0292-crypto-zstd-defer-cstream-init.patch.sig deleted file mode 100644 index 38fc2a9..0000000 Binary files a/kernel/0292-crypto-zstd-defer-cstream-init.patch.sig and /dev/null differ diff --git a/kernel/0293-crypto-zstd-defer-dstream-init.patch b/kernel/0293-crypto-zstd-defer-dstream-init.patch deleted file mode 100644 index 224f1ad..0000000 --- a/kernel/0293-crypto-zstd-defer-dstream-init.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/crypto/zstd.c b/crypto/zstd.c ---- a/crypto/zstd.c -+++ b/crypto/zstd.c -@@ -215,6 +215,7 @@ static int zstd_decompress_one(struct acomp_req *req, struct zstd_ctx *ctx, - - static int zstd_decompress(struct acomp_req *req) - { -+ bool stream_initialized = false; - struct crypto_acomp_stream *s; - unsigned int total_out = 0; - unsigned int scur, dcur; -@@ -232,12 +233,6 @@ static int zstd_decompress(struct acomp_req *req) - if (ret) - goto out; - -- ctx->dctx = zstd_init_dstream(ZSTD_MAX_SIZE, ctx->wksp, ctx->wksp_size); -- if (!ctx->dctx) { -- ret = -EINVAL; -- goto out; -- } -- - do { - scur = acomp_walk_next_src(&walk); - if (scur) { -@@ -263,6 +258,19 @@ static int zstd_decompress(struct acomp_req *req) - goto out; - } - -+ if (!stream_initialized) { -+ ctx->dctx = zstd_init_dstream(ZSTD_MAX_SIZE, ctx->wksp, -+ ctx->wksp_size); -+ if (!ctx->dctx) { -+ /* Release in the reverse of the map order. */ -+ acomp_walk_done_dst(&walk, 0); -+ acomp_walk_done_src(&walk, 0); -+ ret = -EINVAL; -+ goto out; -+ } -+ stream_initialized = true; -+ } -+ - outbuf.pos = 0; - outbuf.dst = (u8 *)walk.dst.virt.addr; - outbuf.size = dcur; diff --git a/kernel/0293-crypto-zstd-defer-dstream-init.patch.sig b/kernel/0293-crypto-zstd-defer-dstream-init.patch.sig deleted file mode 100644 index 5edd1fa..0000000 Binary files a/kernel/0293-crypto-zstd-defer-dstream-init.patch.sig and /dev/null differ diff --git a/kernel/0295-af-alg-restrict.patch b/kernel/0295-af-alg-restrict.patch deleted file mode 100644 index 2700fc9..0000000 --- a/kernel/0295-af-alg-restrict.patch +++ /dev/null @@ -1,363 +0,0 @@ ---- a/crypto/af_alg.c -+++ b/crypto/af_alg.c -@@ -8,6 +8,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -22,10 +23,28 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include - -+static int af_alg_restrict = 1; -+ -+static const struct ctl_table af_alg_table[] = { -+ { -+ .procname = "af_alg_restrict", -+ .data = &af_alg_restrict, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_TWO, -+ }, -+}; -+ -+static struct ctl_table_header *af_alg_header; -+ - struct alg_type_list { - const struct af_alg_type *type; - struct list_head list; -@@ -110,6 +129,43 @@ - } - EXPORT_SYMBOL_GPL(af_alg_unregister_type); - -+static bool af_alg_capable(void) -+{ -+ return ns_capable_noaudit(&init_user_ns, CAP_NET_ADMIN) || -+ capable(CAP_SYS_ADMIN); -+} -+ -+int af_alg_check_restriction(const char *name, -+ const struct af_alg_allowlist_entry allowlist[]) -+{ -+ int level = READ_ONCE(af_alg_restrict); -+ -+ if (level == 0) -+ return 0; -+ if (level == 1) { -+ for (const struct af_alg_allowlist_entry *ent = allowlist; -+ ent->name; ent++) { -+ if (strcmp(name, ent->name) == 0) { -+ if ((ent->flags & AF_ALG_UNPRIVILEGED) || -+ af_alg_capable()) -+ return 0; -+ /* List contains at most one entry per name. */ -+ break; -+ } -+ } -+ } -+ /* -+ * Use -ENOENT (the error code for "algorithm not found") instead of -+ * -EACCES or -EPERM, for the highest chance of correctly triggering -+ * fallback code paths in userspace programs. -+ * -+ * Don't log a warning, since it would be noisy. iwd tries to bind a -+ * bunch of algorithms that it never uses. -+ */ -+ return -ENOENT; -+} -+EXPORT_SYMBOL_GPL(af_alg_check_restriction); -+ - static void alg_do_release(const struct af_alg_type *type, void *private) - { - if (!type) -@@ -506,6 +562,9 @@ - struct sock *sk; - int err; - -+ if (READ_ONCE(af_alg_restrict) == 2) -+ return -EAFNOSUPPORT; -+ - if (sock->type != SOCK_SEQPACKET) - return -ESOCKTNOSUPPORT; - if (protocol != 0) -@@ -1222,27 +1281,32 @@ - - static int __init af_alg_init(void) - { -- int err = proto_register(&alg_proto, 0); -+ int err; -+ -+ af_alg_header = register_sysctl("crypto", af_alg_table); - -+ err = proto_register(&alg_proto, 0); - if (err) -- goto out; -+ goto out_unregister_sysctl; - - err = sock_register(&alg_family); -- if (err != 0) -+ if (err) - goto out_unregister_proto; - --out: -- return err; -+ return 0; - - out_unregister_proto: - proto_unregister(&alg_proto); -- goto out; -+out_unregister_sysctl: -+ unregister_sysctl_table(af_alg_header); -+ return err; - } - - static void __exit af_alg_exit(void) - { - sock_unregister(PF_ALG); - proto_unregister(&alg_proto); -+ unregister_sysctl_table(af_alg_header); - } - - module_init(af_alg_init); ---- a/crypto/algif_aead.c -+++ b/crypto/algif_aead.c -@@ -34,6 +34,11 @@ - #include - #include - -+static const struct af_alg_allowlist_entry aead_allowlist[] = { -+ { "ccm(aes)" }, /* bluez */ -+ {}, -+}; -+ - static inline bool aead_sufficient_data(struct sock *sk) - { - struct alg_sock *ask = alg_sk(sk); -@@ -344,6 +349,12 @@ - - static void *aead_bind(const char *name) - { -+ int err; -+ -+ err = af_alg_check_restriction(name, aead_allowlist); -+ if (err) -+ return ERR_PTR(err); -+ - return crypto_alloc_aead(name, 0, AF_ALG_CRYPTOAPI_MASK); - } - ---- a/crypto/algif_hash.c -+++ b/crypto/algif_hash.c -@@ -16,6 +16,24 @@ - #include - #include - -+static const struct af_alg_allowlist_entry hash_allowlist[] = { -+ { "cmac(aes)" }, /* iwd, bluez */ -+ { "hmac(md5)" }, /* iwd */ -+ { "hmac(sha1)" }, /* iwd */ -+ { "hmac(sha224)" }, /* iwd */ -+ { "hmac(sha256)" }, /* iwd */ -+ { "hmac(sha384)" }, /* iwd */ -+ { "hmac(sha512)" }, /* iwd, sha512hmac */ -+ { "md4" }, /* iwd */ -+ { "md5" }, /* iwd */ -+ { "sha1", AF_ALG_UNPRIVILEGED }, /* iwd, iproute2 < 7.0 */ -+ { "sha224" }, /* iwd */ -+ { "sha256" }, /* iwd */ -+ { "sha384" }, /* iwd */ -+ { "sha512" }, /* iwd */ -+ {}, -+}; -+ - struct hash_ctx { - struct af_alg_sgl sgl; - -@@ -382,6 +400,12 @@ - - static void *hash_bind(const char *name) - { -+ int err; -+ -+ err = af_alg_check_restriction(name, hash_allowlist); -+ if (err) -+ return ERR_PTR(err); -+ - return crypto_alloc_ahash(name, 0, AF_ALG_CRYPTOAPI_MASK); - } - ---- a/crypto/algif_rng.c -+++ b/crypto/algif_rng.c -@@ -50,6 +50,10 @@ - MODULE_AUTHOR("Stephan Mueller "); - MODULE_DESCRIPTION("User-space interface for random number generators"); - -+static const struct af_alg_allowlist_entry rng_allowlist[] = { -+ {}, -+}; -+ - struct rng_ctx { - #define MAXSIZE 128 - unsigned int len; -@@ -201,6 +205,11 @@ - { - struct rng_parent_ctx *pctx; - struct crypto_rng *rng; -+ int err; -+ -+ err = af_alg_check_restriction(name, rng_allowlist); -+ if (err) -+ return ERR_PTR(err); - - pctx = kzalloc_obj(*pctx); - if (!pctx) ---- a/crypto/algif_skcipher.c -+++ b/crypto/algif_skcipher.c -@@ -35,6 +35,24 @@ - #include - #include - -+static const struct af_alg_allowlist_entry skcipher_allowlist[] = { -+ { "adiantum(xchacha12,aes)", AF_ALG_UNPRIVILEGED }, /* cryptsetup */ -+ { "adiantum(xchacha20,aes)", AF_ALG_UNPRIVILEGED }, /* cryptsetup */ -+ { "cbc(aes)" }, /* iwd */ -+ { "cbc(des)" }, /* iwd */ -+ { "cbc(des3_ede)" }, /* iwd */ -+ { "cbc(paes)" }, /* caam and others */ -+ { "ctr(aes)" }, /* iwd */ -+ { "ecb(aes)" }, /* iwd, bluez */ -+ { "ecb(des)" }, /* iwd */ -+ { "hctr2(aes)", AF_ALG_UNPRIVILEGED }, /* cryptsetup */ -+ { "xts(aes)", AF_ALG_UNPRIVILEGED }, /* cryptsetup benchmark */ -+ { "xts(camellia)", AF_ALG_UNPRIVILEGED }, /* cryptsetup */ -+ { "xts(serpent)", AF_ALG_UNPRIVILEGED }, /* cryptsetup */ -+ { "xts(twofish)", AF_ALG_UNPRIVILEGED }, /* cryptsetup */ -+ {}, -+}; -+ - static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, - size_t size) - { -@@ -311,6 +329,11 @@ - static void *skcipher_bind(const char *name) - { - u32 mask = AF_ALG_CRYPTOAPI_MASK; -+ int err; -+ -+ err = af_alg_check_restriction(name, skcipher_allowlist); -+ if (err) -+ return ERR_PTR(err); - - if (strcmp(name, "cbc(paes)") == 0) - mask = 0; ---- a/include/crypto/if_alg.h -+++ b/include/crypto/if_alg.h -@@ -8,6 +8,7 @@ - #ifndef _CRYPTO_IF_ALG_H - #define _CRYPTO_IF_ALG_H - -+#include - #include - #include - #include -@@ -121,7 +122,7 @@ - * @iv: IV for cipher operation - * @state: Existing state for continuing operation - * @aead_assoclen: Length of AAD for AEAD cipher operations -- * @completion: Work queue for synchronous operation -+ * @wait: For waiting for completion of async crypto ops - * @used: TX bytes sent to kernel. This variable is used to - * ensure that user space cannot cause the kernel - * to allocate too much memory in sendmsg operation. -@@ -161,9 +162,20 @@ - unsigned int inflight; - }; - -+/* Flags for af_alg_allowlist_entry::flags: */ -+#define AF_ALG_UNPRIVILEGED BIT(0) /* Unprivileged use is allowed */ -+ -+struct af_alg_allowlist_entry { -+ const char *name; -+ u32 flags; -+}; -+ - int af_alg_register_type(const struct af_alg_type *type); - int af_alg_unregister_type(const struct af_alg_type *type); - -+int af_alg_check_restriction(const char *name, -+ const struct af_alg_allowlist_entry allowlist[]); -+ - int af_alg_release(struct socket *sock); - void af_alg_release_parent(struct sock *sk); - int af_alg_accept(struct sock *sk, struct socket *newsock, -@@ -177,10 +189,11 @@ - } - - /** -- * Size of available buffer for sending data from user space to kernel. -+ * af_alg_sndbuf - Size of available buffer for sending data from user space to kernel. - * -- * @sk socket of connection to user space -- * @return number of bytes still available -+ * @sk: socket of connection to user space -+ * -+ * Returns: number of bytes still available - */ - static inline int af_alg_sndbuf(struct sock *sk) - { -@@ -192,10 +205,11 @@ - } - - /** -- * Can the send buffer still be written to? -+ * af_alg_writable - Can the send buffer still be written to? -+ * -+ * @sk: socket of connection to user space - * -- * @sk socket of connection to user space -- * @return true => writable, false => not writable -+ * Returns: true => writable, false => not writable - */ - static inline bool af_alg_writable(struct sock *sk) - { -@@ -203,10 +217,11 @@ - } - - /** -- * Size of available buffer used by kernel for the RX user space operation. -+ * af_alg_rcvbuf - Size of available buffer used by kernel for the RX user space operation. - * -- * @sk socket of connection to user space -- * @return number of bytes still available -+ * @sk: socket of connection to user space -+ * -+ * Returns: number of bytes still available - */ - static inline int af_alg_rcvbuf(struct sock *sk) - { -@@ -218,10 +233,11 @@ - } - - /** -- * Can the RX buffer still be written to? -+ * af_alg_readable - Can the RX buffer still be read from? -+ * -+ * @sk: socket of connection to user space - * -- * @sk socket of connection to user space -- * @return true => writable, false => not writable -+ * Returns: true => readable, false => not readable - */ - static inline bool af_alg_readable(struct sock *sk) - { diff --git a/kernel/0295-af-alg-restrict.patch.sig b/kernel/0295-af-alg-restrict.patch.sig deleted file mode 100644 index 94672f5..0000000 Binary files a/kernel/0295-af-alg-restrict.patch.sig and /dev/null differ diff --git a/kernel/0300-btrfs.patch b/kernel/0300-btrfs.patch deleted file mode 100644 index 837f7bc..0000000 --- a/kernel/0300-btrfs.patch +++ /dev/null @@ -1,4042 +0,0 @@ -diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c ---- a/fs/btrfs/block-group.c -+++ b/fs/btrfs/block-group.c -@@ -2630,10 +2630,9 @@ static int fill_dummy_bgs(struct btrfs_fs_info *fs_info) - - /* Fill dummy cache as FULL */ - bg->length = map->chunk_len; -- bg->flags = map->type; -+ bg->flags = map->on_disk_type; - bg->cached = BTRFS_CACHE_FINISHED; - bg->used = map->chunk_len; -- bg->flags = map->type; - bg->space_info = btrfs_find_space_info(fs_info, bg->flags); - ret = btrfs_add_block_group_cache(bg); - /* -@@ -3922,7 +3921,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans, - old_val += num_bytes; - cache->used = old_val; - cache->reserved -= num_bytes; -- cache->reclaim_mark = 0; -+ cache->reclaim_mark = false; - space_info->bytes_reserved -= num_bytes; - space_info->bytes_used += num_bytes; - space_info->disk_used += num_bytes * factor; -diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h ---- a/fs/btrfs/block-group.h -+++ b/fs/btrfs/block-group.h -@@ -263,6 +263,9 @@ struct btrfs_block_group { - - enum btrfs_block_group_size_class size_class:8; - -+ /* If set, this blockgroup is not used for allocation between two reclaim sweeps. */ -+ bool reclaim_mark; -+ - /* - * Number of extents in this block group used for swap files. - * All accesses protected by the spinlock 'lock'. -@@ -281,7 +284,6 @@ struct btrfs_block_group { - struct list_head active_bg_list; - struct work_struct zone_finish_work; - struct extent_buffer *last_eb; -- u64 reclaim_mark; - }; - - static inline u64 btrfs_block_group_end(const struct btrfs_block_group *block_group) -diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c ---- a/fs/btrfs/compression.c -+++ b/fs/btrfs/compression.c -@@ -651,9 +651,9 @@ struct heuristic_ws { - u8 *sample; - u32 sample_size; - /* Buckets store counters for each byte value */ -- struct bucket_item *bucket; -+ struct bucket_item bucket[BUCKET_SIZE]; - /* Sorting buffer */ -- struct bucket_item *bucket_b; -+ struct bucket_item bucket_b[BUCKET_SIZE]; - struct list_head list; - }; - -@@ -664,8 +664,6 @@ static void free_heuristic_ws(struct list_head *ws) - workspace = list_entry(ws, struct heuristic_ws, list); - - kvfree(workspace->sample); -- kfree(workspace->bucket); -- kfree(workspace->bucket_b); - kfree(workspace); - } - -@@ -681,14 +679,6 @@ static struct list_head *alloc_heuristic_ws(struct btrfs_fs_info *fs_info) - if (!ws->sample) - goto fail; - -- ws->bucket = kzalloc_objs(*ws->bucket, BUCKET_SIZE); -- if (!ws->bucket) -- goto fail; -- -- ws->bucket_b = kzalloc_objs(*ws->bucket_b, BUCKET_SIZE); -- if (!ws->bucket_b) -- goto fail; -- - INIT_LIST_HEAD(&ws->list); - return &ws->list; - fail: -diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c ---- a/fs/btrfs/ctree.c -+++ b/fs/btrfs/ctree.c -@@ -1460,6 +1460,7 @@ static noinline void unlock_up(struct btrfs_path *path, int level, - */ - static int - read_block_for_search(struct btrfs_root *root, struct btrfs_path *p, -+ struct btrfs_eb_prealloc *pa, - struct extent_buffer **eb_ret, int slot, - const struct btrfs_key *key) - { -@@ -1546,7 +1547,8 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p, - if (p->reada != READA_NONE) - reada_for_search(fs_info, p, parent_level, slot, key->objectid); - -- tmp = btrfs_find_create_tree_block(fs_info, blocknr, check.owner_root, check.level); -+ tmp = btrfs_find_create_tree_block(fs_info, pa, blocknr, -+ check.owner_root, check.level); - if (IS_ERR(tmp)) { - ret = PTR_ERR(tmp); - tmp = NULL; -@@ -2004,6 +2006,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, - u8 lowest_level = 0; - int min_write_lock_level; - int prev_cmp; -+ struct btrfs_eb_prealloc pa = { .supports_nowait = true }; - - if (!root) - return -EINVAL; -@@ -2058,6 +2061,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, - } - - again: -+ if (pa.needs_prealloc) { -+ ret = btrfs_init_eb_prealloc(fs_info, &pa, false); -+ if (ret) -+ goto done; -+ } - prev_cmp = -1; - b = btrfs_search_slot_get_root(root, p, write_lock_level); - if (IS_ERR(b)) { -@@ -2187,7 +2195,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, - goto done; - } - -- ret2 = read_block_for_search(root, p, &b, slot, key); -+ ret2 = read_block_for_search(root, p, &pa, &b, slot, key); - if (ret2 == -EAGAIN && !p->nowait) { - trace_btrfs_search_slot_restart(root, level, "read_block"); - goto again; -@@ -2234,6 +2242,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, - ret = ret2; - } - -+ btrfs_free_eb_prealloc(&pa); -+ - return ret; - } - ALLOW_ERROR_INJECTION(btrfs_search_slot, ERRNO); -@@ -2259,6 +2269,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key, - int level; - int lowest_unlock = 1; - u8 lowest_level = 0; -+ struct btrfs_eb_prealloc pa = { .supports_nowait = true }; - - lowest_level = p->lowest_level; - WARN_ON(p->nodes[0] != NULL); -@@ -2270,6 +2281,11 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key, - } - - again: -+ if (pa.needs_prealloc) { -+ ret = btrfs_init_eb_prealloc(fs_info, &pa, false); -+ if (ret) -+ goto done; -+ } - b = btrfs_get_old_root(root, time_seq); - if (unlikely(!b)) { - ret = -EIO; -@@ -2316,7 +2332,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key, - goto done; - } - -- ret2 = read_block_for_search(root, p, &b, slot, key); -+ ret2 = read_block_for_search(root, p, &pa, &b, slot, key); - if (ret2 == -EAGAIN && !p->nowait) - goto again; - if (ret2) { -@@ -2339,6 +2355,8 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key, - if (ret < 0) - btrfs_release_path(p); - -+ btrfs_free_eb_prealloc(&pa); -+ - return ret; - } - -@@ -4780,6 +4798,7 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, - struct extent_buffer *next; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_key key; -+ struct btrfs_eb_prealloc pa = { .supports_nowait = true }; - bool need_commit_sem = false; - u32 nritems; - int ret; -@@ -4798,6 +4817,11 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, - - btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1); - again: -+ if (pa.needs_prealloc) { -+ ret = btrfs_init_eb_prealloc(fs_info, &pa, false); -+ if (ret) -+ goto done; -+ } - level = 1; - next = NULL; - btrfs_release_path(path); -@@ -4880,7 +4904,7 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, - } - - next = c; -- ret = read_block_for_search(root, path, &next, slot, &key); -+ ret = read_block_for_search(root, path, &pa, &next, slot, &key); - if (ret == -EAGAIN && !path->nowait) - goto again; - -@@ -4923,7 +4947,7 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, - if (!level) - break; - -- ret = read_block_for_search(root, path, &next, 0, &key); -+ ret = read_block_for_search(root, path, &pa, &next, 0, &key); - if (ret == -EAGAIN && !path->nowait) - goto again; - -@@ -4956,6 +4980,8 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, - ret = ret2; - } - -+ btrfs_free_eb_prealloc(&pa); -+ - return ret; - } - -diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h ---- a/fs/btrfs/ctree.h -+++ b/fs/btrfs/ctree.h -@@ -131,7 +131,6 @@ enum { - BTRFS_ROOT_ORPHAN_ITEM_INSERTED, - BTRFS_ROOT_DEFRAG_RUNNING, - BTRFS_ROOT_FORCE_COW, -- BTRFS_ROOT_MULTI_LOG_TASKS, - BTRFS_ROOT_DIRTY, - BTRFS_ROOT_DELETING, - -@@ -196,9 +195,7 @@ struct btrfs_root { - struct list_head log_ctxs[2]; - /* Used only for log trees of subvolumes, not for the log root tree */ - atomic_t log_writers; -- atomic_t log_commit[2]; -- /* Used only for log trees of subvolumes, not for the log root tree */ -- atomic_t log_batch; -+ bool log_commit[2]; - /* - * Protected by the 'log_mutex' lock but can be read without holding - * that lock to avoid unnecessary lock contention, in which case it -@@ -216,7 +213,6 @@ struct btrfs_root { - * to access this field. - */ - int last_log_commit; -- pid_t log_start_pid; - - u64 last_trans; - -diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c ---- a/fs/btrfs/defrag.c -+++ b/fs/btrfs/defrag.c -@@ -1093,7 +1093,7 @@ static int defrag_collect_targets(struct btrfs_inode *inode, - struct defrag_target_range *tmp; - - list_for_each_entry_safe(entry, tmp, target_list, list) { -- list_del_init(&entry->list); -+ list_del(&entry->list); - kfree(entry); - } - } -@@ -1169,7 +1169,7 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len, - struct defrag_target_range *entry; - struct defrag_target_range *tmp; - LIST_HEAD(target_list); -- struct folio **folios; -+ struct folio AUTO_KFREE(*folios); - const u32 sectorsize = inode->root->fs_info->sectorsize; - u64 cur = start; - const unsigned int nr_pages = ((start + len - 1) >> PAGE_SHIFT) - -@@ -1196,10 +1196,8 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len, - * range or the extent lock. - */ - ret = btrfs_delalloc_reserve_space(inode, &data_reserved, start, len); -- if (ret < 0) { -- kfree(folios); -+ if (ret < 0) - return ret; -- } - - /* Prepare all pages */ - for (int i = 0; cur < start + len && i < nr_pages; i++) { -@@ -1234,16 +1232,12 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len, - if (ret < 0) - goto unlock_extent; - -- list_for_each_entry(entry, &target_list, list) { -+ list_for_each_entry_safe(entry, tmp, &target_list, list) { - defrag_one_locked_target(inode, entry, folios, nr_pages, &cached_state); - if (entry->start > last_defrag_end) - btrfs_delalloc_release_space(inode, data_reserved, last_defrag_end, - entry->start - last_defrag_end, true); - last_defrag_end = entry->start + entry->len; -- } -- -- list_for_each_entry_safe(entry, tmp, &target_list, list) { -- list_del_init(&entry->list); - kfree(entry); - } - unlock_extent: -@@ -1255,7 +1249,6 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len, - folio_unlock(folios[i]); - folio_put(folios[i]); - } -- kfree(folios); - btrfs_delalloc_release_extents(inode, len); - if (last_defrag_end < start + len) - btrfs_delalloc_release_space(inode, data_reserved, last_defrag_end, -@@ -1326,10 +1319,8 @@ static int defrag_one_cluster(struct btrfs_inode *inode, - inode->root->fs_info->sectorsize_bits; - } - out: -- list_for_each_entry_safe(entry, tmp, &target_list, list) { -- list_del_init(&entry->list); -+ list_for_each_entry_safe(entry, tmp, &target_list, list) - kfree(entry); -- } - if (ret >= 0) - *last_scanned_ret = max(*last_scanned_ret, start + len); - return ret; -diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c ---- a/fs/btrfs/delayed-inode.c -+++ b/fs/btrfs/delayed-inode.c -@@ -1523,10 +1523,10 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, - ret = __btrfs_add_delayed_item(delayed_node, delayed_item); - if (unlikely(ret)) { - btrfs_err(trans->fs_info, --"error adding delayed dir index item, name: %.*s, index: %llu, root: %llu, dir: %llu, dir->index_cnt: %llu, delayed_node->index_cnt: %llu, error: %d", -+"error adding delayed dir index item, name: %.*s, index: %llu, root: %llu, dir: %llu, dir->index_cnt: %llu, delayed_node->index_cnt: %llu, error: %pe", - name_len, name, index, btrfs_root_id(delayed_node->root), - delayed_node->inode_id, dir->index_cnt, -- delayed_node->index_cnt, ret); -+ delayed_node->index_cnt, ERR_PTR(ret)); - btrfs_release_delayed_item(delayed_item); - btrfs_release_dir_index_item_space(trans); - mutex_unlock(&delayed_node->mutex); -@@ -1645,8 +1645,8 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, - */ - if (ret < 0) { - btrfs_err(trans->fs_info, --"metadata reservation failed for delayed dir item deletion, index: %llu, root: %llu, inode: %llu, error: %d", -- index, btrfs_root_id(node->root), node->inode_id, ret); -+"metadata reservation failed for delayed dir item deletion, index: %llu, root: %llu, inode: %llu, error: %pe", -+ index, btrfs_root_id(node->root), node->inode_id, ERR_PTR(ret)); - btrfs_release_delayed_item(item); - goto end; - } -@@ -1655,8 +1655,8 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, - ret = __btrfs_add_delayed_item(node, item); - if (unlikely(ret)) { - btrfs_err(trans->fs_info, --"failed to add delayed dir index item, root: %llu, inode: %llu, index: %llu, error: %d", -- btrfs_root_id(node->root), node->inode_id, index, ret); -+"failed to add delayed dir index item, root: %llu, inode: %llu, index: %llu, error: %pe", -+ btrfs_root_id(node->root), node->inode_id, index, ERR_PTR(ret)); - btrfs_delayed_item_release_metadata(dir->root, item); - btrfs_release_delayed_item(item); - } -diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c ---- a/fs/btrfs/direct-io.c -+++ b/fs/btrfs/direct-io.c -@@ -14,7 +14,6 @@ - #include "ordered-data.h" - - struct btrfs_dio_data { -- ssize_t submitted; - loff_t old_isize; - struct extent_changeset *data_reserved; - struct btrfs_ordered_extent *ordered; -@@ -151,7 +150,7 @@ static struct extent_map *btrfs_create_dio_extent(struct btrfs_inode *inode, - if (type != BTRFS_ORDERED_NOCOW) { - em = btrfs_create_io_em(inode, start, file_extent, type); - if (IS_ERR(em)) -- goto out; -+ return em; - } - - ordered = btrfs_alloc_ordered_extent(inode, start, file_extent, -@@ -168,7 +167,6 @@ static struct extent_map *btrfs_create_dio_extent(struct btrfs_inode *inode, - ASSERT(!dio_data->ordered); - dio_data->ordered = ordered; - } -- out: - - return em; - } -@@ -626,78 +624,81 @@ static int btrfs_dio_iomap_end(struct inode *inode, loff_t pos, loff_t length, - { - struct iomap_iter *iter = container_of(iomap, struct iomap_iter, iomap); - struct btrfs_dio_data *dio_data = iter->private; -- size_t submitted = dio_data->submitted; - const bool write = !!(flags & IOMAP_WRITE); - int ret = 0; - -- if (!write && (iomap->type == IOMAP_HOLE)) { -- /* If reading from a hole, unlock and return */ -- btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos, -- pos + length - 1, NULL); -+ if (!write) { -+ /* -+ * Hole read, nothing is submitted, thus we have to unlock -+ * the whole range. -+ */ -+ if (iomap->type == IOMAP_HOLE) { -+ btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos, -+ pos + length - 1, NULL); -+ return 0; -+ } -+ /* -+ * Short read, needs to unlock the remaining range, and -+ * return -ENOTBLK so we can later fault in the pages and retry. -+ */ -+ if (written < length) { -+ btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos + written, -+ pos + length - 1, NULL); -+ return -ENOTBLK; -+ } -+ /* The full range is submitted, endio will do the unlock. */ - return 0; - } - -- if (submitted < length) { -- pos += submitted; -- length -= submitted; -- if (write) { -- /* -- * Got a short write and have updated the isize, need to -- * revert the isize change. -- * -- * Normally we need to update isize with extent lock hold, -- * but we're safe due to the following factors: -- * -- * - Only a single writer can be enlarging isize -- * Enlarging isize will take the exclusive inode lock. -- * -- * - Buffered readers need to wait for the OE we're holding -- * Buffered readers will lock extent and wait for OE -- * of the folio range, and since page cache is invalidated -- * the OE wait can not be skipped. -- * -- * So here we are safe to revert the isize before -- * finishing the OE, and no reader of the remaining range -- * can see the enlarged size. -- * -- * TODO: Extend the DIO_LOCKED lifespan for direct writes, -- * and only enlarge isize after a successful write. -- */ -- if (dio_data->updated_isize) { -- u64 new_isize; -+ if (written < length) { -+ /* -+ * Got a short write and have updated the i_size, need to revert -+ * the i_size change. -+ * -+ * Normally we need to update i_size with extent lock held, but -+ * we're safe due to the following factors: -+ * -+ * - Only a single writer can be enlarging i_size -+ * Enlarging i_size will take the exclusive inode lock. -+ * -+ * - Buffered readers need to wait for the OE we're holding -+ * Buffered readers will lock extent and wait for OE -+ * of the folio range, and since page cache is invalidated -+ * the OE wait cannot be skipped. -+ * -+ * So here we are safe to revert the isize before finishing the -+ * OE, and no reader of the remaining range can see the enlarged -+ * size. -+ * -+ * TODO: Extend the DIO_LOCKED lifespan for direct writes, -+ * and only enlarge isize after a successful write. -+ */ -+ if (dio_data->updated_isize) { -+ u64 new_isize; - -- if (submitted == 0) -- new_isize = dio_data->old_isize; -- else -- new_isize = max(dio_data->old_isize, pos); -- i_size_write(inode, new_isize); -- dio_data->updated_isize = false; -- } -- /* -- * We have a short write, if there is any range -- * that is submitted properly, that part will have -- * its own OE split from the original one. -- * -- * So for the OE at dio_data->ordered, it's the part -- * that is not submitted, and should be marked -- * as fully truncated. -- */ -- btrfs_mark_ordered_extent_truncated(dio_data->ordered, 0); -- btrfs_finish_ordered_extent(dio_data->ordered, -- pos, length, true); -- } else { -- btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos, -- pos + length - 1, NULL); -+ if (written == 0) -+ new_isize = dio_data->old_isize; -+ else -+ new_isize = max(dio_data->old_isize, pos + written); -+ i_size_write(inode, new_isize); -+ dio_data->updated_isize = false; - } -+ /* -+ * We have a short write, if there is any range that is submitted -+ * properly, that part will have its own OE split from the -+ * original one. -+ * -+ * So for the OE at dio_data->ordered, it's the part that is not -+ * submitted, and should be marked as fully truncated. -+ */ -+ btrfs_mark_ordered_extent_truncated(dio_data->ordered, 0); -+ btrfs_finish_ordered_extent(dio_data->ordered, -+ pos + written, length - written, true); - ret = -ENOTBLK; - } -- if (write) { -- btrfs_put_ordered_extent(dio_data->ordered); -- dio_data->ordered = NULL; -- } -- -- if (write) -- extent_changeset_free(dio_data->data_reserved); -+ btrfs_put_ordered_extent(dio_data->ordered); -+ dio_data->ordered = NULL; -+ extent_changeset_free(dio_data->data_reserved); - return ret; - } - -@@ -779,8 +780,6 @@ static void btrfs_dio_submit_io(const struct iomap_iter *iter, struct bio *bio, - dip->file_offset = file_offset; - dip->bytes = bio->bi_iter.bi_size; - -- dio_data->submitted += bio->bi_iter.bi_size; -- - /* - * Check if we are doing a partial write. If we are, we need to split - * the ordered extent to match the submitted bio. Hang on to the -@@ -824,13 +823,41 @@ static ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter, - IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, &data, done_before); - } - -+static bool need_stable_write(struct btrfs_inode *inode) -+{ -+ const u64 data_profile = btrfs_data_alloc_profile(inode->root->fs_info) & -+ BTRFS_BLOCK_GROUP_PROFILE_MASK; -+ -+ /* Data checksum requires stable buffer. */ -+ if (!(inode->flags & BTRFS_INODE_NODATASUM)) -+ return true; -+ /* -+ * Any profile with mirror/parity will require stable buffer. -+ * Otherwise the mirror may differ from each other. -+ * -+ * Thus only SINGLE and RAID0 doesn't require stable buffer. -+ */ -+ if (data_profile != 0 && data_profile != BTRFS_BLOCK_GROUP_RAID0) -+ return true; -+ return false; -+} -+ - static struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *iter, - size_t done_before) - { - struct btrfs_dio_data data = { 0 }; -+ unsigned int dio_flags = IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED; -+ -+ if (need_stable_write(BTRFS_I(file_inode(iocb->ki_filp)))) { -+ /* For now no support for BOUNCE and NOWAIT direct write. */ -+ if (iocb->ki_flags & IOCB_NOWAIT) -+ return ERR_PTR(-EAGAIN); -+ -+ dio_flags |= IOMAP_DIO_BOUNCE; -+ } - - return __iomap_dio_rw(iocb, iter, &btrfs_dio_iomap_ops, &btrfs_dio_ops, -- IOMAP_DIO_PARTIAL | IOMAP_DIO_FSBLOCK_ALIGNED, &data, done_before); -+ dio_flags, &data, done_before); - } - - static ssize_t check_direct_IO(struct btrfs_fs_info *fs_info, -@@ -859,8 +886,6 @@ ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) - ssize_t ret; - unsigned int ilock_flags = 0; - struct iomap_dio *dio; -- const u64 data_profile = btrfs_data_alloc_profile(fs_info) & -- BTRFS_BLOCK_GROUP_PROFILE_MASK; - - if (iocb->ki_flags & IOCB_NOWAIT) - ilock_flags |= BTRFS_ILOCK_TRY; -@@ -874,16 +899,6 @@ ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) - if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode) && IS_NOSEC(inode)) - ilock_flags |= BTRFS_ILOCK_SHARED; - -- /* -- * If our data profile has duplication (either extra mirrors or RAID56), -- * we can not trust the direct IO buffer, the content may change during -- * writeback and cause different contents written to different mirrors. -- * -- * Thus only RAID0 and SINGLE can go true zero-copy direct IO. -- */ -- if (data_profile != BTRFS_BLOCK_GROUP_RAID0 && data_profile != 0) -- goto buffered; -- - relock: - ret = btrfs_inode_lock(BTRFS_I(inode), ilock_flags); - if (ret < 0) -@@ -924,22 +939,6 @@ ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) - btrfs_inode_unlock(BTRFS_I(inode), ilock_flags); - goto buffered; - } -- /* -- * We can't control the folios being passed in, applications can write -- * to them while a direct IO write is in progress. This means the -- * content might change after we calculated the data checksum. -- * Therefore we can end up storing a checksum that doesn't match the -- * persisted data. -- * -- * To be extra safe and avoid false data checksum mismatch, if the -- * inode requires data checksum, just fallback to buffered IO. -- * For buffered IO we have full control of page cache and can ensure -- * no one is modifying the content during writeback. -- */ -- if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { -- btrfs_inode_unlock(BTRFS_I(inode), ilock_flags); -- goto buffered; -- } - - /* - * The iov_iter can be mapped to the same file range we are writing to. -diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c ---- a/fs/btrfs/disk-io.c -+++ b/fs/btrfs/disk-io.c -@@ -591,12 +591,13 @@ static const struct address_space_operations btree_aops = { - - struct extent_buffer *btrfs_find_create_tree_block( - struct btrfs_fs_info *fs_info, -+ struct btrfs_eb_prealloc *pa, - u64 bytenr, u64 owner_root, - int level) - { - if (btrfs_is_testing(fs_info)) - return alloc_test_extent_buffer(fs_info, bytenr); -- return alloc_extent_buffer(fs_info, bytenr, owner_root, level); -+ return alloc_extent_buffer(fs_info, pa, bytenr, owner_root, level); - } - - /* -@@ -609,12 +610,13 @@ struct extent_buffer *btrfs_find_create_tree_block( - struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr, - struct btrfs_tree_parent_check *check) - { -+ struct btrfs_eb_prealloc pa = { 0 }; - struct extent_buffer *buf = NULL; - int ret; - - ASSERT(check); - -- buf = btrfs_find_create_tree_block(fs_info, bytenr, check->owner_root, -+ buf = btrfs_find_create_tree_block(fs_info, &pa, bytenr, check->owner_root, - check->level); - if (IS_ERR(buf)) - return buf; -@@ -667,10 +669,7 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info, - init_waitqueue_head(&root->log_commit_wait[1]); - INIT_LIST_HEAD(&root->log_ctxs[0]); - INIT_LIST_HEAD(&root->log_ctxs[1]); -- atomic_set(&root->log_commit[0], 0); -- atomic_set(&root->log_commit[1], 0); - atomic_set(&root->log_writers, 0); -- atomic_set(&root->log_batch, 0); - refcount_set(&root->refs, 1); - atomic_set(&root->snapshot_force_cow, 0); - atomic_set(&root->nr_swapfiles, 0); -@@ -2053,7 +2052,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, - if (IS_ERR(log_tree_root->node)) { - ret = PTR_ERR(log_tree_root->node); - log_tree_root->node = NULL; -- btrfs_err(fs_info, "failed to read log tree with error: %d", ret); -+ btrfs_err(fs_info, "failed to read log tree with error: %pe", ERR_PTR(ret)); - btrfs_put_root(log_tree_root); - return ret; - } -@@ -2063,7 +2062,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info, - btrfs_put_root(log_tree_root); - if (unlikely(ret)) { - ASSERT(BTRFS_FS_ERROR(fs_info) != 0); -- btrfs_err(fs_info, "failed to recover log trees with error: %d", ret); -+ btrfs_err(fs_info, "failed to recover log trees with error: %pe", ERR_PTR(ret)); - return ret; - } - -@@ -2304,8 +2303,8 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info) - - return 0; - out: -- btrfs_warn(fs_info, "failed to read root (objectid=%llu): %d", -- location.objectid, ret); -+ btrfs_warn(fs_info, "failed to read root (objectid=%llu): %pe", -+ location.objectid, ERR_PTR(ret)); - return ret; - } - -@@ -2400,8 +2399,8 @@ static int validate_sys_chunk_array(const struct btrfs_fs_info *fs_info, - int btrfs_validate_super(const struct btrfs_fs_info *fs_info, - const struct btrfs_super_block *sb, int mirror_num) - { -- u64 nodesize = btrfs_super_nodesize(sb); -- u64 sectorsize = btrfs_super_sectorsize(sb); -+ const u32 nodesize = btrfs_super_nodesize(sb); -+ const u32 sectorsize = btrfs_super_sectorsize(sb); - int ret = 0; - const bool ignore_flags = btrfs_test_opt(fs_info, IGNORESUPERFLAGS); - -@@ -2443,24 +2442,24 @@ int btrfs_validate_super(const struct btrfs_fs_info *fs_info, - */ - if (unlikely(!is_power_of_2(sectorsize) || sectorsize < BTRFS_MIN_BLOCKSIZE || - sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE)) { -- btrfs_err(fs_info, "invalid sectorsize %llu", sectorsize); -+ btrfs_err(fs_info, "invalid sectorsize %u", sectorsize); - ret = -EINVAL; - } - - if (unlikely(!btrfs_supported_blocksize(sectorsize))) { - btrfs_err(fs_info, -- "sectorsize %llu not yet supported for page size %lu", -+ "sectorsize %u not yet supported for page size %lu", - sectorsize, PAGE_SIZE); - ret = -EINVAL; - } - - if (unlikely(!is_power_of_2(nodesize) || nodesize < sectorsize || - nodesize > BTRFS_MAX_METADATA_BLOCKSIZE)) { -- btrfs_err(fs_info, "invalid nodesize %llu", nodesize); -+ btrfs_err(fs_info, "invalid nodesize %u", nodesize); - ret = -EINVAL; - } - if (unlikely(nodesize != le32_to_cpu(sb->__unused_leafsize))) { -- btrfs_err(fs_info, "invalid leafsize %u, should be %llu", -+ btrfs_err(fs_info, "invalid leafsize %u, should be %u", - le32_to_cpu(sb->__unused_leafsize), nodesize); - ret = -EINVAL; - } -@@ -2910,7 +2909,6 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) - fs_info->nodesize = 4096; - fs_info->sectorsize = 4096; - fs_info->sectorsize_bits = ilog2(4096); -- fs_info->stripesize = 4096; - - /* Default compress algorithm when user does -o compress */ - fs_info->compress_type = BTRFS_COMPRESS_ZLIB; -@@ -2984,8 +2982,8 @@ static int btrfs_uuid_rescan_kthread(void *data) - ret = btrfs_uuid_tree_iterate(fs_info); - if (ret < 0) { - if (ret != -EINTR) -- btrfs_warn(fs_info, "iterating uuid_tree failed %d", -- ret); -+ btrfs_warn(fs_info, "iterating uuid_tree failed %pe", -+ ERR_PTR(ret)); - up(&fs_info->uuid_tree_rescan_sem); - return ret; - } -@@ -3088,7 +3086,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) - ret = btrfs_rebuild_free_space_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, -- "failed to rebuild free space tree: %d", ret); -+ "failed to rebuild free space tree: %pe", ERR_PTR(ret)); - return ret; - } - } -@@ -3099,7 +3097,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) - ret = btrfs_delete_free_space_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, -- "failed to disable free space tree: %d", ret); -+ "failed to disable free space tree: %pe", ERR_PTR(ret)); - return ret; - } - } -@@ -3110,7 +3108,8 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) - */ - ret = btrfs_delete_orphan_free_space_entries(fs_info); - if (ret < 0) { -- btrfs_err(fs_info, "failed to delete orphan free space tree entries: %d", ret); -+ btrfs_err(fs_info, "failed to delete orphan free space tree entries: %pe", -+ ERR_PTR(ret)); - return ret; - } - /* -@@ -3144,7 +3143,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) - ret = btrfs_recover_relocation(fs_info); - mutex_unlock(&fs_info->cleaner_mutex); - if (ret < 0) { -- btrfs_warn(fs_info, "failed to recover relocation: %d", ret); -+ btrfs_warn(fs_info, "failed to recover relocation: %pe", ERR_PTR(ret)); - return ret; - } - -@@ -3154,7 +3153,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) - ret = btrfs_create_free_space_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, -- "failed to create free space tree: %d", ret); -+ "failed to create free space tree: %pe", ERR_PTR(ret)); - return ret; - } - } -@@ -3182,7 +3181,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info) - ret = btrfs_create_uuid_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, -- "failed to create the UUID tree %d", ret); -+ "failed to create the UUID tree %pe", ERR_PTR(ret)); - return ret; - } - } -@@ -3372,7 +3371,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - { - u32 sectorsize; - u32 nodesize; -- u32 stripesize; - u64 generation; - u16 csum_type; - struct btrfs_super_block *disk_super; -@@ -3481,7 +3479,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - /* Set up fs_info before parsing mount options */ - nodesize = btrfs_super_nodesize(disk_super); - sectorsize = btrfs_super_sectorsize(disk_super); -- stripesize = sectorsize; - fs_info->dirty_metadata_batch = nodesize * (1 + ilog2(nr_cpu_ids)); - fs_info->delalloc_batch = sectorsize * 512 * (1 + ilog2(nr_cpu_ids)); - -@@ -3500,7 +3497,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - else - fs_info->block_max_order = calc_block_max_order(fs_info->sectorsize_bits); - fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size; -- fs_info->stripesize = stripesize; - fs_info->fs_devices->fs_info = fs_info; - - if (fs_info->sectorsize > PAGE_SIZE) -@@ -3566,7 +3562,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - ret = btrfs_read_sys_array(fs_info); - mutex_unlock(&fs_info->chunk_mutex); - if (ret) { -- btrfs_err(fs_info, "failed to read the system array: %d", ret); -+ btrfs_err(fs_info, "failed to read the system array: %pe", ERR_PTR(ret)); - goto fail_sb_buffer; - } - -@@ -3585,7 +3581,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - - ret = btrfs_read_chunk_tree(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to read chunk tree: %d", ret); -+ btrfs_err(fs_info, "failed to read chunk tree: %pe", ERR_PTR(ret)); - goto fail_tree_roots; - } - -@@ -3615,7 +3611,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - ret = btrfs_get_dev_zone_info_all_devices(fs_info); - if (ret) { - btrfs_err(fs_info, -- "zoned: failed to read device zone info: %d", ret); -+ "zoned: failed to read device zone info: %pe", ERR_PTR(ret)); - goto fail_block_groups; - } - -@@ -3638,72 +3634,73 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - ret = btrfs_verify_dev_extents(fs_info); - if (ret) { - btrfs_err(fs_info, -- "failed to verify dev extents against chunks: %d", -- ret); -+ "failed to verify dev extents against chunks: %pe", -+ ERR_PTR(ret)); - goto fail_block_groups; - } - ret = btrfs_recover_balance(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to recover balance: %d", ret); -+ btrfs_err(fs_info, "failed to recover balance: %pe", ERR_PTR(ret)); - goto fail_block_groups; - } - - ret = btrfs_init_dev_stats(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to init dev_stats: %d", ret); -+ btrfs_err(fs_info, "failed to init dev_stats: %pe", ERR_PTR(ret)); - goto fail_block_groups; - } - - ret = btrfs_init_dev_replace(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to init dev_replace: %d", ret); -+ btrfs_err(fs_info, "failed to init dev_replace: %pe", ERR_PTR(ret)); - goto fail_block_groups; - } - - ret = btrfs_check_zoned_mode(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to initialize zoned mode: %d", -- ret); -+ btrfs_err(fs_info, "failed to initialize zoned mode: %pe", -+ ERR_PTR(ret)); - goto fail_block_groups; - } - - ret = btrfs_sysfs_add_fsid(fs_devices); - if (ret) { -- btrfs_err(fs_info, "failed to init sysfs fsid interface: %d", -- ret); -+ btrfs_err(fs_info, "failed to init sysfs fsid interface: %pe", -+ ERR_PTR(ret)); - goto fail_block_groups; - } - - ret = btrfs_sysfs_add_mounted(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to init sysfs interface: %d", ret); -+ btrfs_err(fs_info, "failed to init sysfs interface: %pe", ERR_PTR(ret)); - goto fail_fsdev_sysfs; - } - - ret = btrfs_init_space_info(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to initialize space info: %d", ret); -+ btrfs_err(fs_info, "failed to initialize space info: %pe", ERR_PTR(ret)); - goto fail_sysfs; - } - - ret = btrfs_read_block_groups(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to read block groups: %d", ret); -+ btrfs_err(fs_info, "failed to read block groups: %pe", ERR_PTR(ret)); - goto fail_sysfs; - } - - if (btrfs_fs_incompat(fs_info, REMAP_TREE)) { - ret = btrfs_populate_fully_remapped_bgs_list(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to populate fully_remapped_bgs list: %d", ret); -+ btrfs_err(fs_info, "failed to populate fully_remapped_bgs list: %pe", -+ ERR_PTR(ret)); - goto fail_sysfs; - } - } - - ret = btrfs_init_writeback_bio_size(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to get optimum writeback size: %d", -- ret); -+ btrfs_err(fs_info, "failed to get optimum writeback size: %pe", -+ ERR_PTR(ret)); - goto fail_sysfs; - } - -@@ -3759,7 +3756,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - fs_info->fs_root = btrfs_get_fs_root(fs_info, BTRFS_FS_TREE_OBJECTID, true); - if (IS_ERR(fs_info->fs_root)) { - ret = PTR_ERR(fs_info->fs_root); -- btrfs_err(fs_info, "failed to read fs tree: %d", ret); -+ btrfs_err(fs_info, "failed to read fs tree: %pe", ERR_PTR(ret)); - fs_info->fs_root = NULL; - goto fail_qgroup; - } -@@ -3780,7 +3777,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device - btrfs_info(fs_info, "checking UUID tree"); - ret = btrfs_check_uuid_tree(fs_info); - if (ret) { -- btrfs_err(fs_info, "failed to check the UUID tree: %d", ret); -+ btrfs_err(fs_info, "failed to check the UUID tree: %pe", ERR_PTR(ret)); - close_ctree(fs_info); - return ret; - } -@@ -3896,8 +3893,8 @@ static int write_dev_supers(struct btrfs_device *device, - continue; - } else if (ret < 0) { - btrfs_err(device->fs_info, -- "couldn't get super block location for mirror %d error %d", -- i, ret); -+ "couldn't get super block location for mirror %d error %pe", -+ i, ERR_PTR(ret)); - atomic_inc(&device->sb_write_errors); - continue; - } -@@ -3915,8 +3912,8 @@ static int write_dev_supers(struct btrfs_device *device, - GFP_NOFS); - if (IS_ERR(folio)) { - btrfs_err(device->fs_info, -- "couldn't get super block page for bytenr %llu error %ld", -- bytenr, PTR_ERR(folio)); -+ "couldn't get super block page for bytenr %llu error %pe", -+ bytenr, folio); - atomic_inc(&device->sb_write_errors); - continue; - } -@@ -4398,6 +4395,21 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) - */ - flush_workqueue(fs_info->fixup_workers); - -+ /* -+ * After we entered close_ctree() autodefrag could be running and before -+ * we parked the cleaner kthread, it dirtied folios of some inode. -+ * We don't want to leave any delalloc here, it may be flushed any time -+ * after this point and result in ordered extents that create delayed -+ * iputs after flushed the ordered extent queues further below, run -+ * delayed iputs and set BTRFS_FS_STATE_NO_DELAYED_IPUT. If we are -+ * mounted with flushoncommit, then btrfs_commit_super() called below -+ * will flush delalloc and wait for ordered extents but we end up -+ * getting delayed iputs than are never run. So flush delalloc and wait -+ * for ordered extents. -+ */ -+ btrfs_start_delalloc_roots(fs_info, LONG_MAX, false); -+ btrfs_wait_ordered_roots(fs_info, U64_MAX, NULL); -+ - /* - * Handle the error fs first, as it will flush and wait for all ordered - * extents. This will generate delayed iputs, thus we want to handle -@@ -4528,7 +4540,7 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) - if (!btrfs_is_shutdown(fs_info)) { - ret = btrfs_commit_super(fs_info); - if (ret) -- btrfs_err(fs_info, "commit super block returned %d", ret); -+ btrfs_err(fs_info, "commit super block returned %pe", ERR_PTR(ret)); - } - } - -@@ -4567,6 +4579,13 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info) - free_root_pointers(fs_info, true); - btrfs_free_fs_roots(fs_info); - -+ /* -+ * Drop metadata left stranded ahead of a zone write pointer while the -+ * endio workqueues are still up, so the final iput() of the btree inode -+ * below does not hang submitting a write that can no longer complete. -+ */ -+ btrfs_zoned_release_dirty_metadata(fs_info); -+ - /* - * We must make sure there is not any read request to - * submit after we stop all workers. -@@ -5015,6 +5034,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info) - btrfs_assert_delayed_root_empty(fs_info); - btrfs_destroy_all_delalloc_inodes(fs_info); - btrfs_drop_all_logs(fs_info); -+ btrfs_zoned_release_dirty_metadata(fs_info); - btrfs_free_all_qgroup_pertrans(fs_info); - mutex_unlock(&fs_info->transaction_kthread_mutex); - -diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h ---- a/fs/btrfs/disk-io.h -+++ b/fs/btrfs/disk-io.h -@@ -15,6 +15,7 @@ - struct block_device; - struct super_block; - struct extent_buffer; -+struct btrfs_eb_prealloc; - struct btrfs_device; - struct btrfs_fs_devices; - struct btrfs_fs_info; -@@ -48,6 +49,7 @@ struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr, - struct btrfs_tree_parent_check *check); - struct extent_buffer *btrfs_find_create_tree_block( - struct btrfs_fs_info *fs_info, -+ struct btrfs_eb_prealloc *pa, - u64 bytenr, u64 owner_root, - int level); - int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info); -diff --git a/fs/btrfs/extent-io-tree.c b/fs/btrfs/extent-io-tree.c ---- a/fs/btrfs/extent-io-tree.c -+++ b/fs/btrfs/extent-io-tree.c -@@ -334,6 +334,21 @@ static inline struct extent_state *tree_search(struct extent_io_tree *tree, u64 - return tree_search_for_insert(tree, offset, NULL, NULL); - } - -+static void validate_extent_state(const struct extent_io_tree *tree, -+ const struct extent_state *state) -+{ -+ u32 blocksize; -+ -+ if (tree->owner != IO_TREE_INODE_IO) -+ return; -+ -+ blocksize = btrfs_extent_io_tree_to_fs_info(tree)->sectorsize; -+ ASSERT(IS_ALIGNED(state->start, blocksize) && -+ IS_ALIGNED(state->end + 1, blocksize), -+ "unaligned extent state, blocksize=%u start=%llu end=%llu state=0x%x", -+ blocksize, state->start, state->end, state->state); -+} -+ - #define extent_io_tree_panic(tree, state, opname, err) \ - btrfs_panic(btrfs_extent_io_tree_to_fs_info((tree)), (err), \ - "extent io tree error on %s state start %llu end %llu", \ -@@ -429,6 +444,8 @@ static struct extent_state *insert_state(struct extent_io_tree *tree, - const u64 end = state->end + 1; - const bool try_merge = !(bits & (EXTENT_LOCK_BITS | EXTENT_BOUNDARY)); - -+ validate_extent_state(tree, state); -+ - set_state_bits(tree, state, bits, changeset); - - node = &tree->state.rb_node; -@@ -481,6 +498,8 @@ static void insert_state_fast(struct extent_io_tree *tree, - struct rb_node *parent, unsigned bits, - struct extent_changeset *changeset) - { -+ validate_extent_state(tree, state); -+ - set_state_bits(tree, state, bits, changeset); - rb_link_node(&state->rb_node, parent, node); - rb_insert_color(&state->rb_node, &tree->state); -@@ -533,6 +552,8 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig, - } - } - -+ validate_extent_state(tree, orig); -+ validate_extent_state(tree, prealloc); - rb_link_node(&prealloc->rb_node, parent, node); - rb_insert_color(&prealloc->rb_node, &tree->state); - -diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c ---- a/fs/btrfs/extent-tree.c -+++ b/fs/btrfs/extent-tree.c -@@ -4757,7 +4757,7 @@ static noinline int find_free_extent(struct btrfs_root *root, - - /* Checks */ - ffe_ctl->search_start = round_up(ffe_ctl->found_offset, -- fs_info->stripesize); -+ fs_info->sectorsize); - - /* move on to the next group */ - if (ffe_ctl->search_start + ffe_ctl->num_bytes > -@@ -5260,10 +5260,11 @@ btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, - enum btrfs_lock_nesting nest) - { - struct btrfs_fs_info *fs_info = root->fs_info; -+ struct btrfs_eb_prealloc pa = { 0 }; - struct extent_buffer *buf; - u64 lockdep_owner = owner; - -- buf = btrfs_find_create_tree_block(fs_info, bytenr, owner, level); -+ buf = btrfs_find_create_tree_block(fs_info, &pa, bytenr, owner, level); - if (IS_ERR(buf)) - return buf; - -@@ -5880,8 +5881,8 @@ static int maybe_drop_reference(struct btrfs_trans_handle *trans, struct btrfs_r - ret = btrfs_qgroup_trace_subtree(trans, next, generation, level - 1); - if (ret) { - btrfs_err_rl(root->fs_info, --"error %d accounting shared subtree, quota is out of sync, rescan required", -- ret); -+"error %pe accounting shared subtree, quota is out of sync, rescan required", -+ ERR_PTR(ret)); - } - } - -@@ -5917,6 +5918,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, - struct walk_control *wc) - { - struct btrfs_fs_info *fs_info = root->fs_info; -+ struct btrfs_eb_prealloc pa = { 0 }; - u64 bytenr; - u64 generation; - u64 owner_root = 0; -@@ -5939,7 +5941,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, - - bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]); - -- next = btrfs_find_create_tree_block(fs_info, bytenr, btrfs_root_id(root), -+ next = btrfs_find_create_tree_block(fs_info, &pa, bytenr, btrfs_root_id(root), - level - 1); - if (IS_ERR(next)) - return PTR_ERR(next); -@@ -6096,8 +6098,8 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, - ret = btrfs_qgroup_trace_leaf_items(trans, eb); - if (ret) { - btrfs_err_rl(fs_info, -- "error %d accounting leaf items, quota is out of sync, rescan required", -- ret); -+ "error %pe accounting leaf items, quota is out of sync, rescan required", -+ ERR_PTR(ret)); - } - } - } -@@ -6498,8 +6500,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root, bool update_ref, bool for_reloc - ret = btrfs_qgroup_cleanup_dropped_subvolume(fs_info, rootid); - if (ret < 0) - btrfs_warn_rl(fs_info, -- "failed to cleanup qgroup 0/%llu: %d", -- rootid, ret); -+ "failed to cleanup qgroup 0/%llu: %pe", -+ rootid, ERR_PTR(ret)); - ret = 0; - } - /* -@@ -6914,8 +6916,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) - - if (bg_failed) - btrfs_warn(fs_info, -- "failed to trim %llu block group(s), first error %d", -- bg_failed, bg_ret); -+ "failed to trim %llu block group(s), first error %pe", -+ bg_failed, ERR_PTR(bg_ret)); - - if (ret == -ERESTARTSYS || ret == -EINTR) - return ret; -@@ -6925,8 +6927,8 @@ int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range) - - if (dev_failed) - btrfs_warn(fs_info, -- "failed to trim %llu device(s), first error %d", -- dev_failed, dev_ret); -+ "failed to trim %llu device(s), first error %pe", -+ dev_failed, ERR_PTR(dev_ret)); - range->len = trimmed; - if (ret == -ERESTARTSYS || ret == -EINTR) - return ret; -diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c ---- a/fs/btrfs/extent_io.c -+++ b/fs/btrfs/extent_io.c -@@ -1392,6 +1392,22 @@ static void lock_extents_for_read(struct btrfs_inode *inode, u64 start, u64 end, - } - } - -+static void assert_folio_range(const struct btrfs_inode *inode, -+ u64 start, u64 end) -+{ -+ const u32 blocksize = inode->root->fs_info->sectorsize; -+ -+ /* -+ * For btrfs page cache, a folio always contains at least one block, -+ * so the range should always be block size aligned. -+ */ -+ ASSERT(IS_ALIGNED(start, blocksize) && IS_ALIGNED(end + 1, blocksize), -+ "blocksize=%u root=%lld ino=%llu start=%llu end=%llu mapping min order=%u", -+ blocksize, btrfs_root_id(inode->root), btrfs_ino(inode), -+ start, end, -+ mapping_min_folio_order(inode->vfs_inode.i_mapping)); -+} -+ - int btrfs_read_folio(struct file *file, struct folio *folio) - { - struct inode *vfs_inode = folio->mapping->host; -@@ -1407,6 +1423,7 @@ int btrfs_read_folio(struct file *file, struct folio *folio) - struct fsverity_info *vi = NULL; - int ret; - -+ assert_folio_range(inode, start, end); - lock_extents_for_read(inode, start, end, &cached_state); - if (folio_pos(folio) < i_size_read(vfs_inode)) - vi = fsverity_get_info(vfs_inode); -@@ -1698,13 +1715,13 @@ static noinline_for_stack int writepage_delalloc(struct btrfs_inode *inode, - last_finished_delalloc_end = found_start + found_len; - if (unlikely(ret < 0)) - btrfs_err_rl(fs_info, --"failed to run delalloc range, root=%lld ino=%llu folio=%llu submit_bitmap=%*pbl start=%llu len=%u: %d", -+"failed to run delalloc range, root=%lld ino=%llu folio=%llu submit_bitmap=%*pbl start=%llu len=%u: %pe", - btrfs_root_id(inode->root), - btrfs_ino(inode), - folio_pos(folio), - blocks_per_folio, - bio_ctrl->submit_bitmap, -- found_start, found_len, ret); -+ found_start, found_len, ERR_PTR(ret)); - } else { - /* - * We've hit an error during previous delalloc range, -@@ -1914,6 +1931,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, - ASSERT(start >= folio_start, "start=%llu folio_start=%llu", start, folio_start); - ASSERT(end <= folio_end, "start=%llu len=%u folio_start=%llu folio_size=%zu", - start, len, folio_start, folio_size(folio)); -+ assert_folio_range(inode, folio_start, folio_end - 1); - - /* - * We are about to checksum and write out the data, so it must not be -@@ -2081,10 +2099,10 @@ static int extent_writepage(struct folio *folio, struct btrfs_bio_ctrl *bio_ctrl - return 0; - if (unlikely(ret < 0)) - btrfs_err_rl(fs_info, --"failed to submit blocks, root=%lld inode=%llu folio=%llu submit_bitmap=%*pbl: %d", -+"failed to submit blocks, root=%lld inode=%llu folio=%llu submit_bitmap=%*pbl: %pe", - btrfs_root_id(inode->root), btrfs_ino(inode), - folio_pos(folio), blocks_per_folio, -- bio_ctrl->submit_bitmap, ret); -+ bio_ctrl->submit_bitmap, ERR_PTR(ret)); - - bio_ctrl->wbc->nr_to_write--; - -@@ -2976,13 +2994,25 @@ void btrfs_readahead(struct readahead_control *rac) - struct extent_map *em_cached = NULL; - struct fsverity_info *vi = NULL; - -+ assert_folio_range(inode, start, end); - lock_extents_for_read(inode, start, end, &cached_state); -+ /* We don't use cached state for a bulk unlock, just free it. */ -+ btrfs_free_extent_state(cached_state); - if (start < i_size_read(vfs_inode)) - vi = fsverity_get_info(vfs_inode); -- while ((folio = readahead_folio(rac)) != NULL) -- btrfs_do_readpage(folio, &em_cached, &bio_ctrl, vi); -+ while ((folio = readahead_folio(rac)) != NULL) { -+ /* -+ * Read start and end before btrfs_do_readpage(). It unlocks the -+ * folio, so our reference might not be valid after. -+ */ -+ const u64 folio_start = folio_pos(folio); -+ const u64 folio_end = folio_start + folio_size(folio) - 1; - -- btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state); -+ btrfs_do_readpage(folio, &em_cached, &bio_ctrl, vi); -+ /* Only unlock the range we locked, even if readahead expands. */ -+ if (folio_start >= start && folio_end <= end) -+ btrfs_unlock_extent(&inode->io_tree, folio_start, folio_end, NULL); -+ } - - if (em_cached) - btrfs_free_extent_map(em_cached); -@@ -3298,12 +3328,9 @@ void btrfs_uninhibit_all_eb_writeback(struct btrfs_trans_handle *trans) - trans->inhibited_ebs_hand = 0; - } - --static struct extent_buffer *__alloc_extent_buffer(struct btrfs_fs_info *fs_info, -- u64 start) -+static void init_extent_buffer(struct btrfs_fs_info *fs_info, -+ struct extent_buffer *eb, u64 start) - { -- struct extent_buffer *eb = NULL; -- -- eb = kmem_cache_zalloc(extent_buffer_cache, GFP_NOFS|__GFP_NOFAIL); - eb->start = start; - eb->len = fs_info->nodesize; - eb->fs_info = fs_info; -@@ -3316,7 +3343,15 @@ static struct extent_buffer *__alloc_extent_buffer(struct btrfs_fs_info *fs_info - refcount_set(&eb->refs, 1); - - ASSERT(eb->len <= BTRFS_MAX_METADATA_BLOCKSIZE); -+} - -+static struct extent_buffer *__alloc_extent_buffer(struct btrfs_fs_info *fs_info, -+ u64 start) -+{ -+ struct extent_buffer *eb; -+ -+ eb = kmem_cache_zalloc(extent_buffer_cache, GFP_NOFS | __GFP_NOFAIL); -+ init_extent_buffer(fs_info, eb, start); - return eb; - } - -@@ -3613,7 +3648,7 @@ static bool check_eb_alignment(struct btrfs_fs_info *fs_info, u64 start) - * The caller needs to free the existing folios and retry using the same order. - */ - static int attach_eb_folio_to_filemap(struct extent_buffer *eb, int i, -- struct btrfs_folio_state *prealloc, -+ struct btrfs_eb_prealloc *pa, - struct extent_buffer **found_eb_ret) - { - -@@ -3635,6 +3670,7 @@ static int attach_eb_folio_to_filemap(struct extent_buffer *eb, int i, - if (!ret) - goto finish; - -+ /* ret == -EEXIST: a folio already lives at this index. */ - existing_folio = filemap_lock_folio(mapping, index + i); - /* The page cache only exists for a very short time, just retry. */ - if (IS_ERR(existing_folio)) -@@ -3643,7 +3679,27 @@ static int attach_eb_folio_to_filemap(struct extent_buffer *eb, int i, - /* For now, we should only have single-page folios for btree inode. */ - ASSERT(folio_nr_pages(existing_folio) == 1); - -+ /* -+ * TODO: Special handling for a corner case where the order of -+ * folios mismatch between the new eb and filemap. -+ * -+ * This happens when: -+ * -+ * - the new eb is using higher order folio -+ * -+ * - the filemap is still using 0-order folios for the range -+ * This can happen at the previous eb allocation, and we don't -+ * have higher order folio for the call. -+ * -+ * - the existing eb has already been freed -+ * -+ * In this case, we have to free the existing folios first, and -+ * re-allocate using the same order. -+ * Thankfully this is not going to happen yet, as we're still -+ * using 0-order folios. -+ */ - if (folio_size(existing_folio) != eb->folio_size) { -+ DEBUG_WARN("folio order mismatch between new eb and filemap"); - folio_unlock(existing_folio); - folio_put(existing_folio); - return -EAGAIN; -@@ -3674,8 +3730,10 @@ static int attach_eb_folio_to_filemap(struct extent_buffer *eb, int i, - eb->folio_size = folio_size(eb->folios[i]); - eb->folio_shift = folio_shift(eb->folios[i]); - /* Should not fail, as we have preallocated the memory. */ -- ret = attach_extent_buffer_folio(eb, eb->folios[i], prealloc); -+ ret = attach_extent_buffer_folio(eb, eb->folios[i], pa->bfs); - ASSERT(!ret); -+ /* The subpage state, if any, is now attached to the folio or freed. */ -+ pa->bfs = NULL; - /* - * To inform we have an extra eb under allocation, so that - * detach_extent_buffer_page() won't release the folio private when the -@@ -3690,13 +3748,104 @@ static int attach_eb_folio_to_filemap(struct extent_buffer *eb, int i, - return 0; - } - -+/* -+ * Allocate the extent_buffer, its folios, and btrfs_folio_state, if needed. -+ * -+ * @pa: The holder struct to do the allocation in. -+ * @nowait: Whether to do a speculative GFP_NOWAIT allocation while holding locks. -+ * -+ * Return 0 on success and a negative errno otherwise. On failure, pa->eb/bfs -+ * will be NULL. If @nowait=true, then on ENOMEM, mark @pa->needs_prealloc and -+ * return -EAGAIN to signal the caller to unlock and retry. -+ */ -+int btrfs_init_eb_prealloc(struct btrfs_fs_info *fs_info, -+ struct btrfs_eb_prealloc *pa, bool nowait) -+{ -+ gfp_t gfp = nowait ? GFP_NOWAIT : GFP_NOFS | __GFP_NOFAIL; -+ int ret; -+ -+ ASSERT(!pa->eb, "unexpected non-null eb: %p", pa->eb); -+ ASSERT(!pa->bfs, "unexpected non-null bfs: %p", pa->bfs); -+ pa->needs_prealloc = false; -+ -+ pa->eb = kmem_cache_zalloc(extent_buffer_cache, gfp); -+ if (!pa->eb) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ /* alloc_eb_folio_array() needs len; init_extent_buffer() sets it again later. */ -+ pa->eb->len = fs_info->nodesize; -+ -+ /* -+ * Preallocate folio private for subpage case, so that we won't -+ * allocate memory with i_private_lock nor page lock hold. -+ * -+ * The memory will be freed by attach_extent_buffer_page() or freed -+ * manually if we exit earlier. -+ */ -+ if (btrfs_meta_is_subpage(fs_info)) { -+ pa->bfs = btrfs_alloc_folio_state(fs_info, PAGE_SIZE, -+ BTRFS_SUBPAGE_METADATA, gfp); -+ if (IS_ERR(pa->bfs)) { -+ ret = PTR_ERR(pa->bfs); -+ pa->bfs = NULL; -+ goto free_eb; -+ } -+ } -+ -+ /* -+ * Allocate pages without attaching them. Caller is ultimately responsible -+ * for attaching the folios to the mapping with attach_eb_folio_to_filemap(). -+ */ -+ ret = alloc_eb_folio_array(pa->eb, gfp | __GFP_MOVABLE); -+ if (ret < 0) -+ goto free_bfs; -+ -+ return 0; -+ -+free_bfs: -+ btrfs_free_folio_state(pa->bfs); -+ pa->bfs = NULL; -+free_eb: -+ kmem_cache_free(extent_buffer_cache, pa->eb); -+ pa->eb = NULL; -+out: -+ if (nowait && ret == -ENOMEM) { -+ pa->needs_prealloc = true; -+ ret = -EAGAIN; -+ } -+ return ret; -+} -+ -+/* -+ * Used to cleanup a btrfs_eb_prealloc which had its contents allocated but -+ * folios not yet attached and eb/bfs consumed, and refs still 0. -+ * -+ * Safe to call on a fully used btrfs_eb_prealloc as the internal structs will -+ * be null once they are owned by the context using them. -+ */ -+void btrfs_free_eb_prealloc(struct btrfs_eb_prealloc *pa) -+{ -+ if (!pa->eb) -+ return; -+ -+ for (int i = 0; i < num_extent_pages(pa->eb); i++) { -+ if (pa->eb->folios[i]) -+ folio_put(pa->eb->folios[i]); -+ } -+ btrfs_free_folio_state(pa->bfs); -+ kmem_cache_free(extent_buffer_cache, pa->eb); -+ pa->eb = NULL; -+ pa->bfs = NULL; -+} -+ - struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, -+ struct btrfs_eb_prealloc *pa, - u64 start, u64 owner_root, int level) - { - int attached = 0; - struct extent_buffer *eb; - struct extent_buffer *existing_eb = NULL; -- struct btrfs_folio_state *prealloc = NULL; - u64 lockdep_owner = owner_root; - bool page_contig = true; - bool uptodate = true; -@@ -3720,9 +3869,14 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, - if (eb) - return eb; - -- eb = __alloc_extent_buffer(fs_info, start); -- if (!eb) -- return ERR_PTR(-ENOMEM); -+ if (!pa->eb) { -+ ret = btrfs_init_eb_prealloc(fs_info, pa, pa->supports_nowait); -+ if (ret) -+ return ERR_PTR(ret); -+ } -+ eb = pa->eb; -+ pa->eb = NULL; -+ init_extent_buffer(fs_info, eb, start); - - /* - * The reloc trees are just snapshots, so we need them to appear to be -@@ -3733,66 +3887,18 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, - - btrfs_set_buffer_lockdep_class(lockdep_owner, eb, level); - -- /* -- * Preallocate folio private for subpage case, so that we won't -- * allocate memory with i_private_lock nor page lock hold. -- * -- * The memory will be freed by attach_extent_buffer_page() or freed -- * manually if we exit earlier. -- */ -- if (btrfs_meta_is_subpage(fs_info)) { -- prealloc = btrfs_alloc_folio_state(fs_info, PAGE_SIZE, BTRFS_SUBPAGE_METADATA); -- if (IS_ERR(prealloc)) { -- ret = PTR_ERR(prealloc); -- goto out; -- } -- } -- --reallocate: -- /* -- * Allocate all pages first. These will be attached to btree_inode->i_mapping -- * below (added to LRU, served by btree_migrate_folio), so request -- * __GFP_MOVABLE so the page allocator places them in MOVABLE pageblocks. -- */ -- ret = alloc_eb_folio_array(eb, GFP_NOFS | __GFP_NOFAIL | __GFP_MOVABLE); -- if (ret < 0) { -- btrfs_free_folio_state(prealloc); -- goto out; -- } -- - /* Attach all pages to the filemap. */ - for (int i = 0; i < num_extent_folios(eb); i++) { - struct folio *folio; - -- ret = attach_eb_folio_to_filemap(eb, i, prealloc, &existing_eb); -+ ret = attach_eb_folio_to_filemap(eb, i, pa, &existing_eb); - if (ret > 0) { - ASSERT(existing_eb); - goto out; - } -- -- /* -- * TODO: Special handling for a corner case where the order of -- * folios mismatch between the new eb and filemap. -- * -- * This happens when: -- * -- * - the new eb is using higher order folio -- * -- * - the filemap is still using 0-order folios for the range -- * This can happen at the previous eb allocation, and we don't -- * have higher order folio for the call. -- * -- * - the existing eb has already been freed -- * -- * In this case, we have to free the existing folios first, and -- * re-allocate using the same order. -- * Thankfully this is not going to happen yet, as we're still -- * using 0-order folios. -- */ -- if (unlikely(ret == -EAGAIN)) { -- DEBUG_WARN("folio order mismatch between new eb and filemap"); -- goto reallocate; -- } -+ /* -EAGAIN: folio order mismatch, unreachable with 0-order folios. */ -+ if (ret < 0) -+ goto out; - attached++; - - /* -@@ -3869,6 +3975,10 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, - out: - WARN_ON(!refcount_dec_and_test(&eb->refs)); - -+ /* Attach hands off pa->bfs; free it if we bailed first. */ -+ btrfs_free_folio_state(pa->bfs); -+ pa->bfs = NULL; -+ - /* - * Any attached folios need to be detached before we unlock them. This - * is because when we're inserting our new folios into the mapping, and -@@ -4030,6 +4140,32 @@ void free_extent_buffer_stale(struct extent_buffer *eb) - release_extent_buffer(eb); - } - -+static void clear_extent_buffer_dirty(struct extent_buffer *eb) -+{ -+ struct btrfs_fs_info *fs_info = eb->fs_info; -+ -+ if (!test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) -+ return; -+ -+ buffer_tree_clear_mark(eb, PAGECACHE_TAG_DIRTY); -+ percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, -(s64)eb->len, -+ fs_info->dirty_metadata_batch); -+ -+ for (int i = 0; i < num_extent_folios(eb); i++) { -+ struct folio *folio = eb->folios[i]; -+ bool last; -+ -+ if (!folio_test_dirty(folio)) -+ continue; -+ folio_lock(folio); -+ last = btrfs_meta_folio_clear_and_test_dirty(folio, eb); -+ if (last) -+ btrfs_clear_folio_dirty_tag(folio); -+ folio_unlock(folio); -+ } -+ WARN_ON(refcount_read(&eb->refs) == 0); -+} -+ - void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans, - struct extent_buffer *eb) - { -@@ -4054,26 +4190,42 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans, - return; - } - -- if (!test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) -+ clear_extent_buffer_dirty(eb); -+} -+ -+/* -+ * On a zoned filesystem a freed tree block is kept dirty and flagged as -+ * EXTENT_BUFFER_ZONED_ZEROOUT so a later writeback zeroes it out and advances -+ * the zone write pointer. Such buffers still dirty when the filesystem is torn -+ * down can no longer be written back and are stale; if left dirty they hang the -+ * final iput() of the btree inode. Drop their dirty state, and the deferred -+ * zero-out along with it. -+ */ -+void btrfs_zoned_release_dirty_metadata(struct btrfs_fs_info *fs_info) -+{ -+ struct eb_batch batch; -+ unsigned long index = 0; -+ -+ if (!btrfs_is_zoned(fs_info)) - return; - -- buffer_tree_clear_mark(eb, PAGECACHE_TAG_DIRTY); -- percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, -(s64)eb->len, -- fs_info->dirty_metadata_batch); -+ btrfs_zoned_meta_io_lock(fs_info); -+ eb_batch_init(&batch); -+ while (buffer_tree_get_ebs_tag(fs_info, &index, ULONG_MAX, -+ PAGECACHE_TAG_DIRTY, &batch)) { -+ struct extent_buffer *eb; - -- for (int i = 0; i < num_extent_folios(eb); i++) { -- struct folio *folio = eb->folios[i]; -- bool last; -- -- if (!folio_test_dirty(folio)) -- continue; -- folio_lock(folio); -- last = btrfs_meta_folio_clear_and_test_dirty(folio, eb); -- if (last) -- btrfs_clear_folio_dirty_tag(folio); -- folio_unlock(folio); -+ while ((eb = eb_batch_next(&batch)) != NULL) { -+ btrfs_tree_lock(eb); -+ if (test_and_clear_bit(EXTENT_BUFFER_ZONED_ZEROOUT, -+ &eb->bflags)) -+ clear_extent_buffer_dirty(eb); -+ btrfs_tree_unlock(eb); -+ } -+ eb_batch_release(&batch); -+ cond_resched(); - } -- WARN_ON(refcount_read(&eb->refs) == 0); -+ btrfs_zoned_meta_io_unlock(fs_info); - } - - void set_extent_buffer_dirty(struct extent_buffer *eb) -@@ -4923,6 +5075,8 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, - .level = level, - .transid = gen - }; -+ /* Readahead is best effort so prefer to fail rather than block in reclaim. */ -+ struct btrfs_eb_prealloc pa = { .supports_nowait = true }; - struct extent_buffer *eb; - int ret; - -@@ -4931,7 +5085,7 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info, - check.has_first_key = true; - } - -- eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level); -+ eb = btrfs_find_create_tree_block(fs_info, &pa, bytenr, owner_root, level); - if (IS_ERR(eb)) - return; - -diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h ---- a/fs/btrfs/extent_io.h -+++ b/fs/btrfs/extent_io.h -@@ -119,6 +119,25 @@ struct extent_buffer { - #endif - }; - -+/* -+ * Wrapper struct for managing preallocating an extent_buffer, its folios and a -+ * btrfs_folio_state if needed. -+ * -+ * Only used to mediate allocation, do not refer to the eb directly if not -+ * returned from a successful eb allocating API. -+ * -+ * The eb folios and bfs should generally not be fully attached, except briefly -+ * before they are NULLed in the struct after successful attachment. -+ */ -+struct btrfs_eb_prealloc { -+ struct extent_buffer *eb; -+ struct btrfs_folio_state *bfs; -+ /* eb alloc may use GFP_NOWAIT; caller can drop locks and retry. */ -+ bool supports_nowait; -+ /* GFP_NOWAIT eb alloc failed; preallocate again and retry. */ -+ bool needs_prealloc; -+}; -+ - struct btrfs_eb_write_context { - struct writeback_control *wbc; - struct extent_buffer *eb; -@@ -271,7 +290,11 @@ int set_folio_extent_mapped(struct folio *folio); - void clear_folio_extent_mapped(struct folio *folio); - - struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, -+ struct btrfs_eb_prealloc *pa, - u64 start, u64 owner_root, int level); -+int btrfs_init_eb_prealloc(struct btrfs_fs_info *fs_info, -+ struct btrfs_eb_prealloc *pa, bool nowait); -+void btrfs_free_eb_prealloc(struct btrfs_eb_prealloc *pa); - struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start); - struct extent_buffer *btrfs_clone_extent_buffer(const struct extent_buffer *src); -@@ -393,6 +416,7 @@ void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end, - u32 bits_to_clear, unsigned long page_ops); - void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans, - struct extent_buffer *buf); -+void btrfs_zoned_release_dirty_metadata(struct btrfs_fs_info *fs_info); - - static inline void btrfs_clear_folio_dirty_tag(struct folio *folio) - { -diff --git a/fs/btrfs/fiemap.c b/fs/btrfs/fiemap.c ---- a/fs/btrfs/fiemap.c -+++ b/fs/btrfs/fiemap.c -@@ -641,7 +641,7 @@ static int extent_fiemap(struct btrfs_inode *inode, - u64 prev_extent_end; - u64 range_start; - u64 range_end; -- const u64 sectorsize = inode->root->fs_info->sectorsize; -+ const u32 sectorsize = inode->root->fs_info->sectorsize; - bool stopped = false; - int ret; - -diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c ---- a/fs/btrfs/file.c -+++ b/fs/btrfs/file.c -@@ -1573,8 +1573,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) - else - btrfs_inode_lock(inode, BTRFS_ILOCK_MMAP); - -- atomic_inc(&root->log_batch); -- - /* - * Before we acquired the inode's lock and the mmap lock, someone may - * have dirtied more pages in the target range. We need to make sure -@@ -1657,8 +1655,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) - if (ret) - goto out_release_extents; - -- atomic_inc(&root->log_batch); -- - if (skip_inode_logging(&ctx)) { - /* - * We've had everything committed since the last time we were -@@ -2663,8 +2659,8 @@ static int btrfs_punch_hole(struct file *file, loff_t offset, loff_t len) - - lockstart = round_up(offset, fs_info->sectorsize); - lockend = round_down(offset + len, fs_info->sectorsize) - 1; -- same_block = (BTRFS_BYTES_TO_BLKS(fs_info, offset)) -- == (BTRFS_BYTES_TO_BLKS(fs_info, offset + len - 1)); -+ same_block = (offset >> fs_info->sectorsize_bits) == -+ ((offset + len - 1) >> fs_info->sectorsize_bits); - /* - * Only do this if we are in the same block and we aren't doing the - * entire block. -@@ -2868,7 +2864,7 @@ enum { - static int btrfs_zero_range_check_range_boundary(struct btrfs_inode *inode, - u64 offset) - { -- const u64 sectorsize = inode->root->fs_info->sectorsize; -+ const u32 sectorsize = inode->root->fs_info->sectorsize; - struct extent_map *em; - int ret; - -@@ -2898,7 +2894,7 @@ static int btrfs_zero_range(struct inode *inode, - struct extent_changeset *data_reserved = NULL; - int ret; - u64 alloc_hint = 0; -- const u64 sectorsize = fs_info->sectorsize; -+ const u32 sectorsize = fs_info->sectorsize; - const u64 orig_start = offset; - const u64 orig_end = offset + len - 1; - u64 alloc_start = round_down(offset, sectorsize); -@@ -2947,8 +2943,8 @@ static int btrfs_zero_range(struct inode *inode, - } - btrfs_free_extent_map(em); - -- if (BTRFS_BYTES_TO_BLKS(fs_info, offset) == -- BTRFS_BYTES_TO_BLKS(fs_info, offset + len - 1)) { -+ if ((offset >> fs_info->sectorsize_bits) == -+ ((offset + len - 1) >> fs_info->sectorsize_bits)) { - em = btrfs_get_extent(BTRFS_I(inode), NULL, alloc_start, sectorsize); - if (IS_ERR(em)) { - ret = PTR_ERR(em); -diff --git a/fs/btrfs/fs.c b/fs/btrfs/fs.c ---- a/fs/btrfs/fs.c -+++ b/fs/btrfs/fs.c -@@ -127,20 +127,9 @@ void btrfs_csum_final(struct btrfs_csum_ctx *ctx, u8 *out) - } - - /* -- * We support the following block sizes for all systems: -- * -- * - 4K -- * This is the most common block size. For PAGE SIZE > 4K cases the subpage -- * mode is used. -- * -- * - PAGE_SIZE -- * The straightforward block size to support. -- * -- * And extra support for the following block sizes based on the kernel config: -- * -- * - MIN_BLOCKSIZE -- * This is either 4K (regular builds) or 2K (debug builds) -- * This allows testing subpage routines on x86_64. -+ * For regular builds, any block size <= page size is supported. -+ * For experimental builds, any block size between BTRFS_MIN_BLOCKSIZE -+ * and BTRFS_MAX_BLOCKSIZE (inclusive) is supported. - */ - bool __attribute_const__ btrfs_supported_blocksize(u32 blocksize) - { -@@ -148,7 +137,7 @@ bool __attribute_const__ btrfs_supported_blocksize(u32 blocksize) - ASSERT(is_power_of_2(blocksize) && blocksize >= BTRFS_MIN_BLOCKSIZE && - blocksize <= BTRFS_MAX_BLOCKSIZE); - -- if (blocksize == PAGE_SIZE || blocksize == SZ_4K || blocksize == BTRFS_MIN_BLOCKSIZE) -+ if (blocksize <= PAGE_SIZE) - return true; - #ifdef CONFIG_BTRFS_EXPERIMENTAL - /* -diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h ---- a/fs/btrfs/fs.h -+++ b/fs/btrfs/fs.h -@@ -289,7 +289,8 @@ enum { - BTRFS_MOUNT_IGNOREBADROOTS | \ - BTRFS_MOUNT_IGNOREDATACSUMS | \ - BTRFS_MOUNT_IGNOREMETACSUMS | \ -- BTRFS_MOUNT_IGNORESUPERFLAGS) -+ BTRFS_MOUNT_IGNORESUPERFLAGS | \ -+ BTRFS_MOUNT_USEBACKUPROOT) - - /* - * Compat flags that we support. If any incompat flags are set other than the -@@ -890,7 +891,6 @@ struct btrfs_fs_info { - u32 sectorsize_bits; - u32 block_min_order; - u32 block_max_order; -- u32 stripesize; - u32 writeback_bio_size; - u32 csum_size; - u32 csums_per_leaf; -@@ -1060,8 +1060,6 @@ static inline u64 btrfs_calc_metadata_size(const struct btrfs_fs_info *fs_info, - #define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r->fs_info) >> 4) - \ - sizeof(struct btrfs_item)) - --#define BTRFS_BYTES_TO_BLKS(fs_info, bytes) ((bytes) >> (fs_info)->sectorsize_bits) -- - static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info) - { - return IS_ENABLED(CONFIG_BLK_DEV_ZONED) && fs_info->zone_size > 0; -diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c ---- a/fs/btrfs/inode.c -+++ b/fs/btrfs/inode.c -@@ -250,8 +250,8 @@ static void print_data_reloc_error(const struct btrfs_inode *inode, u64 file_off - - ret = extent_from_logical(fs_info, logical, &path, &found_key, &flags); - if (ret < 0) { -- btrfs_err_rl(fs_info, "failed to lookup extent item for logical %llu: %d", -- logical, ret); -+ btrfs_err_rl(fs_info, "failed to lookup extent item for logical %llu: %pe", -+ logical, ERR_PTR(ret)); - return; - } - eb = path.nodes[0]; -@@ -869,7 +869,7 @@ static void compress_file_range(struct btrfs_work *work) - struct btrfs_inode *inode = async_chunk->inode; - struct btrfs_fs_info *fs_info = inode->root->fs_info; - struct compressed_bio *cb = NULL; -- u64 blocksize = fs_info->sectorsize; -+ const u32 blocksize = fs_info->sectorsize; - u64 start = async_chunk->start; - u64 end = async_chunk->end; - u64 actual_end; -@@ -1019,9 +1019,10 @@ static void submit_uncompressed_range(struct btrfs_inode *inode, - btrfs_folio_end_lock(inode->root->fs_info, locked_folio, - start, async_extent->ram_size); - btrfs_err_rl(inode->root->fs_info, -- "%s failed, root=%llu inode=%llu start=%llu len=%llu: %d", -+ "%s failed, root=%llu inode=%llu start=%llu len=%llu: %pe", - __func__, btrfs_root_id(inode->root), -- btrfs_ino(inode), start, async_extent->ram_size, ret); -+ btrfs_ino(inode), start, async_extent->ram_size, -+ ERR_PTR(ret)); - } - } - -@@ -1508,10 +1509,10 @@ static noinline int cow_file_range(struct btrfs_inode *inode, - end - start - cur_alloc_size + 1, NULL); - } - btrfs_err(fs_info, --"%s failed, root=%llu inode=%llu start=%llu len=%llu cur_offset=%llu cur_alloc_size=%u: %d", -+"%s failed, root=%llu inode=%llu start=%llu len=%llu cur_offset=%llu cur_alloc_size=%u: %pe", - __func__, btrfs_root_id(inode->root), - btrfs_ino(inode), orig_start, end + 1 - orig_start, -- start, cur_alloc_size, ret); -+ start, cur_alloc_size, ERR_PTR(ret)); - return ret; - } - -@@ -1962,9 +1963,9 @@ static int nocow_one_range(struct btrfs_inode *inode, struct folio *locked_folio - PAGE_UNLOCK | PAGE_START_WRITEBACK | - PAGE_END_WRITEBACK); - btrfs_err(inode->root->fs_info, -- "%s failed, root=%lld inode=%llu start=%llu len=%llu: %d", -+ "%s failed, root=%lld inode=%llu start=%llu len=%llu: %pe", - __func__, btrfs_root_id(inode->root), btrfs_ino(inode), -- file_pos, len, ret); -+ file_pos, len, ERR_PTR(ret)); - return ret; - } - -@@ -2285,10 +2286,10 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, - } - btrfs_free_path(path); - btrfs_err(fs_info, --"%s failed, root=%llu inode=%llu start=%llu len=%llu cur_offset=%llu oe_cleanup=%llu oe_cleanup_len=%llu untouched_start=%llu untouched_len=%llu: %d", -+"%s failed, root=%llu inode=%llu start=%llu len=%llu cur_offset=%llu oe_cleanup=%llu oe_cleanup_len=%llu untouched_start=%llu untouched_len=%llu: %pe", - __func__, btrfs_root_id(inode->root), btrfs_ino(inode), - start, end + 1 - start, cur_offset, oe_cleanup_start, oe_cleanup_len, -- untouched_start, untouched_len, ret); -+ untouched_start, untouched_len, ERR_PTR(ret)); - return ret; - } - -@@ -3065,7 +3066,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, - u64 qgroup_reserved) - { - struct btrfs_root *root = inode->root; -- const u64 sectorsize = root->fs_info->sectorsize; -+ const u32 sectorsize = root->fs_info->sectorsize; - BTRFS_PATH_AUTO_FREE(path); - struct extent_buffer *leaf; - struct btrfs_key ins; -@@ -3926,7 +3927,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) - - out: - if (ret) -- btrfs_err(fs_info, "could not do orphan cleanup %d", ret); -+ btrfs_err(fs_info, "could not do orphan cleanup %pe", ERR_PTR(ret)); - return ret; - } - -@@ -4229,8 +4230,8 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path - ret = btrfs_load_inode_props(inode, path); - if (ret) - btrfs_err(fs_info, -- "error loading props for ino %llu (root %llu): %d", -- btrfs_ino(inode), btrfs_root_id(root), ret); -+ "error loading props for ino %llu (root %llu): %pe", -+ btrfs_ino(inode), btrfs_root_id(root), ERR_PTR(ret)); - } - - /* -@@ -6844,8 +6845,8 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, - } - if (ret) { - btrfs_err(fs_info, -- "error inheriting props for ino %llu (root %llu): %d", -- btrfs_ino(BTRFS_I(inode)), btrfs_root_id(root), ret); -+ "error inheriting props for ino %llu (root %llu): %pe", -+ btrfs_ino(BTRFS_I(inode)), btrfs_root_id(root), ERR_PTR(ret)); - } - - /* -@@ -10224,6 +10225,8 @@ static void btrfs_free_swapfile_pins(struct inode *inode) - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; - struct btrfs_swapfile_pin *sp; - struct rb_node *node, *next; -+ u64 bg_bytes_released = 0; -+ u32 bg_nr_released = 0; - - spin_lock(&fs_info->swapfile_pins_lock); - node = rb_first(&fs_info->swapfile_pins); -@@ -10233,15 +10236,24 @@ static void btrfs_free_swapfile_pins(struct inode *inode) - if (sp->inode == inode) { - rb_erase(&sp->node, &fs_info->swapfile_pins); - if (sp->is_block_group) { -- btrfs_dec_block_group_swap_extents(sp->ptr, -+ struct btrfs_block_group *bg = sp->ptr; -+ -+ bg_bytes_released += bg->length; -+ bg_nr_released++; -+ btrfs_dec_block_group_swap_extents(bg, - sp->bg_extent_count); -- btrfs_put_block_group(sp->ptr); -+ btrfs_put_block_group(bg); - } - kfree(sp); - } - node = next; - } - spin_unlock(&fs_info->swapfile_pins_lock); -+ btrfs_info(fs_info, -+"swapfile deactivated on root %llu ino %llu, released %llu bytes from %u block group(s)", -+ btrfs_root_id(BTRFS_I(inode)->root), -+ btrfs_ino(BTRFS_I(inode)), bg_bytes_released, -+ bg_nr_released); - } - - struct btrfs_swap_info { -@@ -10319,8 +10331,10 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file, - struct btrfs_backref_share_check_ctx *backref_ctx = NULL; - struct btrfs_path *path = NULL; - int ret = 0; -+ u32 pinned_bg_nr = 0; - u64 isize; - u64 prev_extent_end = 0; -+ u64 pinned_bg_size = 0; - - /* - * Acquire the inode's mmap lock to prevent races with memory mapped -@@ -10570,6 +10584,9 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file, - ret = 0; - else - goto out; -+ } else { -+ pinned_bg_size += bg->length; -+ pinned_bg_nr++; - } - - if (bsi.block_len && -@@ -10617,6 +10634,14 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file, - if (ret) - return ret; - -+ btrfs_info(fs_info, -+"swapfile activated on root %llu ino %llu, pinned down %llu bytes from %u block group(s)", -+ btrfs_root_id(BTRFS_I(inode)->root), -+ btrfs_ino(BTRFS_I(inode)), -+ pinned_bg_size, pinned_bg_nr); -+ btrfs_warn(fs_info, -+"block groups with swapfile extents will not be scrubbed or balanced"); -+ - if (device) - sis->bdev = device->bdev; - *span = bsi.highest_ppage - bsi.lowest_ppage + 1; -diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c ---- a/fs/btrfs/ioctl.c -+++ b/fs/btrfs/ioctl.c -@@ -400,9 +400,9 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap, - - /* - * 1 for inode item -- * 2 for properties -+ * 1 for property - */ -- trans = btrfs_start_transaction(root, 3); -+ trans = btrfs_start_transaction(root, 2); - if (IS_ERR(trans)) - return PTR_ERR(trans); - -@@ -1143,13 +1143,13 @@ static noinline int btrfs_ioctl_resize(struct file *file, - } - - static noinline int __btrfs_ioctl_snap_create(struct file *file, -- struct mnt_idmap *idmap, - const char *name, unsigned long fd, bool subvol, - bool readonly, - struct btrfs_qgroup_inherit *inherit) - { - int ret; - struct qstr qname = QSTR(name); -+ struct mnt_idmap *idmap = file_mnt_idmap(file); - - if (!S_ISDIR(file_inode(file)->i_mode)) - return -ENOTDIR; -@@ -1227,8 +1227,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, - if (ret < 0) - return ret; - -- return __btrfs_ioctl_snap_create(file, file_mnt_idmap(file), -- vol_args->name, vol_args->fd, subvol, -+ return __btrfs_ioctl_snap_create(file, vol_args->name, vol_args->fd, subvol, - false, NULL); - } - -@@ -1271,8 +1270,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, - return ret; - } - -- return __btrfs_ioctl_snap_create(file, file_mnt_idmap(file), -- vol_args->name, vol_args->fd, subvol, -+ return __btrfs_ioctl_snap_create(file, vol_args->name, vol_args->fd, subvol, - readonly, inherit); - } - -@@ -1664,13 +1662,11 @@ static noinline int btrfs_ioctl_tree_search_v2(struct btrfs_root *root, - } - - /* -- * Search INODE_REFs to identify path name of 'dirid' directory -- * in a 'tree_id' tree. and sets path name to 'name'. -+ * Search for an INODE_REF in a 'root' tree which identifies the path name of -+ * 'dirid'. When found, it sets 'name' with the path name. - */ --static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, -- u64 tree_id, u64 dirid, char *name) -+static noinline int btrfs_search_path_in_tree(struct btrfs_root *root, u64 dirid, char *name) - { -- struct btrfs_root *root; - struct btrfs_key key; - char *ptr; - int ret = -1; -@@ -1692,13 +1688,6 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, - - ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX - 1]; - -- root = btrfs_get_fs_root(info, tree_id, true); -- if (IS_ERR(root)) { -- ret = PTR_ERR(root); -- root = NULL; -- goto out; -- } -- - key.objectid = dirid; - key.type = BTRFS_INODE_REF_KEY; - key.offset = (u64)-1; -@@ -1706,11 +1695,9 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, - while (1) { - ret = btrfs_search_backwards(root, &key, path); - if (ret < 0) -- goto out; -- else if (ret > 0) { -- ret = -ENOENT; -- goto out; -- } -+ return ret; -+ else if (ret > 0) -+ return -ENOENT; - - l = path->nodes[0]; - slot = path->slots[0]; -@@ -1719,10 +1706,8 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, - len = btrfs_inode_ref_name_len(l, iref); - ptr -= len + 1; - total_len += len + 1; -- if (ptr < name) { -- ret = -ENAMETOOLONG; -- goto out; -- } -+ if (ptr < name) -+ return -ENAMETOOLONG; - - *(ptr + len) = '/'; - read_extent_buffer(l, ptr, (unsigned long)(iref + 1), len); -@@ -1737,10 +1722,8 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, - } - memmove(name, ptr, total_len); - name[total_len] = '\0'; -- ret = 0; --out: -- btrfs_put_root(root); -- return ret; -+ -+ return 0; - } - - static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap, -@@ -1884,6 +1867,7 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap, - static noinline int btrfs_ioctl_ino_lookup(struct btrfs_root *root, - void __user *argp) - { -+ bool new_root = false; - struct btrfs_ioctl_ino_lookup_args AUTO_KFREE(args); - int ret = 0; - -@@ -1897,6 +1881,8 @@ static noinline int btrfs_ioctl_ino_lookup(struct btrfs_root *root, - */ - if (args->treeid == 0) - args->treeid = btrfs_root_id(root); -+ else -+ new_root = true; - - if (args->objectid == BTRFS_FIRST_FREE_OBJECTID) { - args->name[0] = 0; -@@ -1908,9 +1894,14 @@ static noinline int btrfs_ioctl_ino_lookup(struct btrfs_root *root, - goto out; - } - -- ret = btrfs_search_path_in_tree(root->fs_info, -- args->treeid, args->objectid, -- args->name); -+ if (new_root) { -+ root = btrfs_get_fs_root(root->fs_info, args->treeid, true); -+ if (IS_ERR(root)) -+ return PTR_ERR(root); -+ } -+ ret = btrfs_search_path_in_tree(root, args->objectid, args->name); -+ if (new_root) -+ btrfs_put_root(root); - - out: - if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) -@@ -2848,8 +2839,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) - else - ret = -ENOENT; - btrfs_err(fs_info, -- "could not find default diritem for dir %llu: %d", -- dir_id, ret); -+ "could not find default diritem for dir %llu: %pe", -+ dir_id, ERR_PTR(ret)); - goto out_free; - } - -@@ -3620,7 +3611,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) - { - struct inode *inode = file_inode(file); - struct btrfs_fs_info *fs_info = inode_to_fs_info(inode); -- struct btrfs_root *root = BTRFS_I(inode)->root; -+ struct btrfs_root *quota_root; - struct btrfs_ioctl_qgroup_assign_args AUTO_KFREE(sa); - struct btrfs_qgroup_list AUTO_KFREE(prealloc); - struct btrfs_trans_handle *trans; -@@ -3651,10 +3642,20 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) - } - } - -+ mutex_lock(&fs_info->qgroup_ioctl_lock); -+ quota_root = btrfs_grab_root(fs_info->quota_root); -+ mutex_unlock(&fs_info->qgroup_ioctl_lock); -+ -+ if (!quota_root) { -+ ret = -ENOTCONN; -+ goto drop_write; -+ } -+ - /* 2 BTRFS_QGROUP_RELATION_KEY items. */ -- trans = btrfs_start_transaction(root, 2); -+ trans = btrfs_start_transaction(quota_root, 2); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); -+ btrfs_put_root(quota_root); - goto drop_write; - } - -@@ -3678,6 +3679,7 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) - "qgroup status update failed after %s relation, marked as inconsistent", - sa->assign ? "adding" : "deleting"); - err = btrfs_end_transaction(trans); -+ btrfs_put_root(quota_root); - if (err && !ret) - ret = err; - -@@ -3689,7 +3691,8 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) - static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) - { - struct inode *inode = file_inode(file); -- struct btrfs_root *root = BTRFS_I(inode)->root; -+ struct btrfs_fs_info *fs_info = inode_to_fs_info(inode); -+ struct btrfs_root *quota_root; - struct btrfs_ioctl_qgroup_create_args AUTO_KFREE(sa); - struct btrfs_trans_handle *trans; - int ret; -@@ -3698,7 +3701,7 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - -- if (!btrfs_qgroup_enabled(root->fs_info)) -+ if (!btrfs_qgroup_enabled(fs_info)) - return -ENOTCONN; - - ret = mnt_want_write_file(file); -@@ -3721,13 +3724,23 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) - goto drop_write; - } - -+ mutex_lock(&fs_info->qgroup_ioctl_lock); -+ quota_root = btrfs_grab_root(fs_info->quota_root); -+ mutex_unlock(&fs_info->qgroup_ioctl_lock); -+ -+ if (!quota_root) { -+ ret = -ENOTCONN; -+ goto drop_write; -+ } -+ - /* - * 1 BTRFS_QGROUP_INFO_KEY item. - * 1 BTRFS_QGROUP_LIMIT_KEY item. - */ -- trans = btrfs_start_transaction(root, 2); -+ trans = btrfs_start_transaction(quota_root, 2); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); -+ btrfs_put_root(quota_root); - goto drop_write; - } - -@@ -3738,6 +3751,7 @@ static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) - } - - err = btrfs_end_transaction(trans); -+ btrfs_put_root(quota_root); - if (err && !ret) - ret = err; - -@@ -3750,6 +3764,8 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) - { - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; -+ struct btrfs_root *quota_root; -+ struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_ioctl_qgroup_limit_args AUTO_KFREE(sa); - struct btrfs_trans_handle *trans; - int ret; -@@ -3759,7 +3775,7 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - -- if (!btrfs_qgroup_enabled(root->fs_info)) -+ if (!btrfs_qgroup_enabled(fs_info)) - return -ENOTCONN; - - ret = mnt_want_write_file(file); -@@ -3772,10 +3788,20 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) - goto drop_write; - } - -+ mutex_lock(&fs_info->qgroup_ioctl_lock); -+ quota_root = btrfs_grab_root(fs_info->quota_root); -+ mutex_unlock(&fs_info->qgroup_ioctl_lock); -+ -+ if (!quota_root) { -+ ret = -ENOTCONN; -+ goto drop_write; -+ } -+ - /* 1 BTRFS_QGROUP_LIMIT_KEY item. */ -- trans = btrfs_start_transaction(root, 1); -+ trans = btrfs_start_transaction(quota_root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); -+ btrfs_put_root(quota_root); - goto drop_write; - } - -@@ -3788,6 +3814,7 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) - ret = btrfs_limit_qgroup(trans, qgroupid, &sa->lim); - - err = btrfs_end_transaction(trans); -+ btrfs_put_root(quota_root); - if (err && !ret) - ret = err; - -diff --git a/fs/btrfs/messages.c b/fs/btrfs/messages.c ---- a/fs/btrfs/messages.c -+++ b/fs/btrfs/messages.c -@@ -279,7 +279,6 @@ void __btrfs_panic(const struct btrfs_fs_info *fs_info, const char *function, - unsigned int line, int error, const char *fmt, ...) - { - char *s_id = ""; -- const char *errstr; - struct va_format vaf = { .fmt = fmt }; - va_list args; - -@@ -289,13 +288,12 @@ void __btrfs_panic(const struct btrfs_fs_info *fs_info, const char *function, - va_start(args, fmt); - vaf.va = &args; - -- errstr = btrfs_decode_error(error); - if (fs_info && (btrfs_test_opt(fs_info, PANIC_ON_FATAL_ERROR))) -- panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %s)\n", -- s_id, function, line, &vaf, error, errstr); -+ panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %pe)\n", -+ s_id, function, line, &vaf, error, ERR_PTR(error)); - -- btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %s)", -- function, line, &vaf, error, errstr); -+ btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %pe)", -+ function, line, &vaf, error, ERR_PTR(error)); - va_end(args); - /* Caller calls BUG() */ - } -diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c ---- a/fs/btrfs/qgroup.c -+++ b/fs/btrfs/qgroup.c -@@ -3915,8 +3915,8 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) - ret = PTR_ERR(trans); - trans = NULL; - btrfs_err(fs_info, -- "fail to start transaction for status update: %d", -- ret); -+ "fail to start transaction for status update: %pe", -+ ERR_PTR(ret)); - } - } else { - trans = NULL; -@@ -3931,7 +3931,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) - - if (ret2 < 0) { - ret = ret2; -- btrfs_err(fs_info, "fail to update qgroup status: %d", ret); -+ btrfs_err(fs_info, "fail to update qgroup status: %pe", ERR_PTR(ret)); - } - } - fs_info->qgroup_rescan_running = false; -@@ -3952,7 +3952,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) - btrfs_info(fs_info, "qgroup scan completed%s", - ret > 0 ? " (inconsistency flag cleared)" : ""); - } else { -- btrfs_err(fs_info, "qgroup scan failed with %d", ret); -+ btrfs_err(fs_info, "qgroup scan failed with %pe", ERR_PTR(ret)); - } - } - -diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c ---- a/fs/btrfs/raid56.c -+++ b/fs/btrfs/raid56.c -@@ -2997,13 +2997,11 @@ void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio) - * This is due to the fact rbio has its own page management for its cache. - */ - void raid56_parity_cache_data_folios(struct btrfs_raid_bio *rbio, -- struct folio **data_folios, u64 data_logical) -+ void *vaddr, u64 data_logical) - { - struct btrfs_fs_info *fs_info = rbio->bioc->fs_info; - const u64 offset_in_full_stripe = data_logical - - rbio->bioc->full_stripe_logical; -- unsigned int findex = 0; -- unsigned int foffset = 0; - int ret; - - /* -@@ -3026,18 +3024,10 @@ void raid56_parity_cache_data_folios(struct btrfs_raid_bio *rbio, - cur_off < offset_in_full_stripe + BTRFS_STRIPE_LEN; - cur_off += PAGE_SIZE) { - const unsigned int pindex = cur_off >> PAGE_SHIFT; -- void *kaddr; - -- kaddr = kmap_local_page(rbio->stripe_pages[pindex]); -- memcpy_from_folio(kaddr, data_folios[findex], foffset, PAGE_SIZE); -- kunmap_local(kaddr); -- -- foffset += PAGE_SIZE; -- ASSERT(foffset <= folio_size(data_folios[findex])); -- if (foffset == folio_size(data_folios[findex])) { -- findex++; -- foffset = 0; -- } -+ ASSERT(cur_off - offset_in_full_stripe + PAGE_SIZE <= BTRFS_STRIPE_LEN); -+ memcpy_to_page(rbio->stripe_pages[pindex], 0, -+ vaddr + cur_off - offset_in_full_stripe, PAGE_SIZE); - } - bitmap_set(rbio->stripe_uptodate_bitmap, - offset_in_full_stripe >> fs_info->sectorsize_bits, -diff --git a/fs/btrfs/raid56.h b/fs/btrfs/raid56.h ---- a/fs/btrfs/raid56.h -+++ b/fs/btrfs/raid56.h -@@ -283,7 +283,7 @@ struct btrfs_raid_bio *raid56_parity_alloc_scrub_rbio(struct bio *bio, - void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio); - - void raid56_parity_cache_data_folios(struct btrfs_raid_bio *rbio, -- struct folio **data_folios, u64 data_logical); -+ void *vaddr, u64 data_logical); - - int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info); - void btrfs_free_stripe_hash_table(struct btrfs_fs_info *info); -diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c ---- a/fs/btrfs/reflink.c -+++ b/fs/btrfs/reflink.c -@@ -20,30 +20,31 @@ - #define BTRFS_MAX_DEDUPE_LEN SZ_16M - - static int clone_finish_inode_update(struct btrfs_trans_handle *trans, -- struct inode *inode, -+ struct btrfs_inode *inode, - u64 endoff, - const u64 destoff, - const u64 olen, - bool no_time_update) - { -+ struct inode *vfs_inode = &inode->vfs_inode; - int ret; - -- inode_inc_iversion(inode); -- if (!no_time_update) { -- inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); -- } -+ inode_inc_iversion(vfs_inode); -+ if (!no_time_update) -+ inode_set_mtime_to_ts(vfs_inode, inode_set_ctime_current(vfs_inode)); -+ - /* - * We round up to the block size at eof when determining which - * extents to clone above, but shouldn't round up the file size. - */ - if (endoff > destoff + olen) - endoff = destoff + olen; -- if (endoff > inode->i_size) { -- i_size_write(inode, endoff); -- btrfs_inode_safe_disk_i_size_write(BTRFS_I(inode), 0); -+ if (endoff > vfs_inode->i_size) { -+ i_size_write(vfs_inode, endoff); -+ btrfs_inode_safe_disk_i_size_write(inode, 0); - } - -- ret = btrfs_update_inode(trans, BTRFS_I(inode)); -+ ret = btrfs_update_inode(trans, inode); - if (unlikely(ret)) { - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans); -@@ -392,11 +393,11 @@ static int clone_copy_inline_extent(struct btrfs_inode *inode, - * @destoff: Offset within @inode to start clone - * @no_time_update: Whether to update mtime/ctime on the target inode - */ --static int btrfs_clone(struct inode *src, struct inode *inode, -+static int btrfs_clone(struct btrfs_inode *src, struct btrfs_inode *inode, - const u64 off, const u64 olen, const u64 olen_aligned, - const u64 destoff, bool no_time_update) - { -- struct btrfs_fs_info *fs_info = inode_to_fs_info(inode); -+ struct btrfs_fs_info *fs_info = inode->root->fs_info; - BTRFS_PATH_AUTO_FREE(path); - struct extent_buffer *leaf; - struct btrfs_trans_handle *trans; -@@ -420,7 +421,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - - path->reada = READA_FORWARD; - /* Clone data */ -- key.objectid = btrfs_ino(BTRFS_I(src)); -+ key.objectid = btrfs_ino(src); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = off; - -@@ -436,8 +437,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - u64 drop_start; - - /* Note the key will change type as we walk through the tree */ -- ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, -- 0, 0); -+ ret = btrfs_search_slot(NULL, src->root, &key, path, 0, 0); - if (ret < 0) - goto out; - /* -@@ -455,7 +455,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - nritems = btrfs_header_nritems(path->nodes[0]); - process_slot: - if (path->slots[0] >= nritems) { -- ret = btrfs_next_leaf(BTRFS_I(src)->root, path); -+ ret = btrfs_next_leaf(src->root, path); - if (ret < 0) - goto out; - if (ret > 0) -@@ -466,8 +466,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - slot = path->slots[0]; - - btrfs_item_key_to_cpu(leaf, &key, slot); -- if (key.type > BTRFS_EXTENT_DATA_KEY || -- key.objectid != btrfs_ino(BTRFS_I(src))) -+ if (key.type > BTRFS_EXTENT_DATA_KEY || key.objectid != btrfs_ino(src)) - break; - - ASSERT(key.type == BTRFS_EXTENT_DATA_KEY, "key.type=%u", key.type); -@@ -514,7 +513,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - btrfs_release_path(path); - - memcpy(&new_key, &key, sizeof(new_key)); -- new_key.objectid = btrfs_ino(BTRFS_I(inode)); -+ new_key.objectid = btrfs_ino(inode); - if (off <= key.offset) - new_key.offset = key.offset + destoff - off; - else -@@ -558,7 +557,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - clone_info.extent_buf = buf; - clone_info.is_new_extent = false; - clone_info.update_times = !no_time_update; -- ret = btrfs_replace_file_extents(BTRFS_I(inode), path, -+ ret = btrfs_replace_file_extents(inode, path, - drop_start, new_key.offset + datal - 1, - &clone_info, &trans); - if (ret) -@@ -582,7 +581,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - goto out; - } - -- ret = clone_copy_inline_extent(BTRFS_I(inode), path, &new_key, -+ ret = clone_copy_inline_extent(inode, path, &new_key, - drop_start, datal, size, - comp, buf, &trans); - if (ret) -@@ -605,9 +604,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - * the checksums problem on fsync. - */ - if (extent_gen == trans->transid && disko > 0) -- BTRFS_I(src)->last_reflink_trans = trans->transid; -+ src->last_reflink_trans = trans->transid; - -- BTRFS_I(inode)->last_reflink_trans = trans->transid; -+ inode->last_reflink_trans = trans->transid; - - last_dest_end = ALIGN(new_key.offset + datal, - fs_info->sectorsize); -@@ -653,10 +652,10 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - * set by previous calls to btrfs_replace_file_extents() that - * replaced file extent items. - */ -- if (last_dest_end >= i_size_read(inode)) -- btrfs_set_inode_full_sync(BTRFS_I(inode)); -+ if (last_dest_end >= i_size_read(&inode->vfs_inode)) -+ btrfs_set_inode_full_sync(inode); - -- ret = btrfs_replace_file_extents(BTRFS_I(inode), path, -+ ret = btrfs_replace_file_extents(inode, path, - last_dest_end, destoff + len - 1, NULL, &trans); - if (ret) - goto out; -@@ -666,7 +665,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode, - } - - out: -- clear_bit(BTRFS_INODE_NO_DELALLOC_FLUSH, &BTRFS_I(inode)->runtime_flags); -+ clear_bit(BTRFS_INODE_NO_DELALLOC_FLUSH, &inode->runtime_flags); - - return ret; - } -@@ -688,10 +687,10 @@ static void btrfs_double_mmap_unlock(struct btrfs_inode *inode1, struct btrfs_in - static int btrfs_extent_same_range(struct btrfs_inode *src, u64 loff, u64 len, - struct btrfs_inode *dst, u64 dst_loff) - { -- const u64 end = dst_loff + len - 1; - struct extent_state *cached_state = NULL; - struct btrfs_fs_info *fs_info = src->root->fs_info; -- const u64 bs = fs_info->sectorsize; -+ const u32 bs = fs_info->sectorsize; -+ const u64 end = round_up(dst_loff + len, bs) - 1; - int ret; - - /* -@@ -701,8 +700,7 @@ static int btrfs_extent_same_range(struct btrfs_inode *src, u64 loff, u64 len, - * mode. - */ - btrfs_lock_extent(&dst->io_tree, dst_loff, end, &cached_state); -- ret = btrfs_clone(&src->vfs_inode, &dst->vfs_inode, loff, len, -- ALIGN(len, bs), dst_loff, true); -+ ret = btrfs_clone(src, dst, loff, len, ALIGN(len, bs), dst_loff, true); - btrfs_unlock_extent(&dst->io_tree, dst_loff, end, &cached_state); - - btrfs_btree_balance_dirty(fs_info); -@@ -710,12 +708,12 @@ static int btrfs_extent_same_range(struct btrfs_inode *src, u64 loff, u64 len, - return ret; - } - --static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, -- struct inode *dst, u64 dst_loff) -+static int btrfs_extent_same(struct btrfs_inode *src, u64 loff, u64 olen, -+ struct btrfs_inode *dst, u64 dst_loff) - { - int ret = 0; - u64 i, tail_len, chunk_count; -- struct btrfs_root *root_dst = BTRFS_I(dst)->root; -+ struct btrfs_root *root_dst = dst->root; - - spin_lock(&root_dst->root_item_lock); - if (root_dst->send_in_progress) { -@@ -733,8 +731,8 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, - chunk_count = div_u64(olen, BTRFS_MAX_DEDUPE_LEN); - - for (i = 0; i < chunk_count; i++) { -- ret = btrfs_extent_same_range(BTRFS_I(src), loff, BTRFS_MAX_DEDUPE_LEN, -- BTRFS_I(dst), dst_loff); -+ ret = btrfs_extent_same_range(src, loff, BTRFS_MAX_DEDUPE_LEN, -+ dst, dst_loff); - if (ret) - goto out; - -@@ -743,8 +741,7 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, - } - - if (tail_len > 0) -- ret = btrfs_extent_same_range(BTRFS_I(src), loff, tail_len, -- BTRFS_I(dst), dst_loff); -+ ret = btrfs_extent_same_range(src, loff, tail_len, dst, dst_loff); - out: - spin_lock(&root_dst->root_item_lock); - root_dst->dedupe_in_progress--; -@@ -757,12 +754,14 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - u64 off, u64 olen, u64 destoff) - { - struct extent_state *cached_state = NULL; -- struct inode *inode = file_inode(file); -- struct inode *src = file_inode(file_src); -- struct btrfs_fs_info *fs_info = inode_to_fs_info(inode); -+ struct btrfs_inode *inode = BTRFS_I(file_inode(file)); -+ struct btrfs_inode *src = BTRFS_I(file_inode(file_src)); -+ struct btrfs_fs_info *fs_info = inode->root->fs_info; -+ const u64 src_isize = src->vfs_inode.i_size; -+ const u64 inode_isize = inode->vfs_inode.i_size; - int ret; - u64 len = olen; -- u64 bs = fs_info->sectorsize; -+ const u32 bs = fs_info->sectorsize; - u64 end; - - /* -@@ -771,13 +770,13 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - * if the file size is not blocksize aligned. So we don't need to check - * for that case here. - */ -- if (off + len == src->i_size) -- len = ALIGN(src->i_size, bs) - off; -+ if (off + len == src_isize) -+ len = ALIGN(src_isize, bs) - off; - -- if (destoff > inode->i_size) { -- const u64 wb_start = ALIGN_DOWN(inode->i_size, bs); -+ if (destoff > inode_isize) { -+ const u64 wb_start = ALIGN_DOWN(inode_isize, bs); - -- ret = btrfs_cont_expand(BTRFS_I(inode), inode->i_size, destoff); -+ ret = btrfs_cont_expand(inode, inode_isize, destoff); - if (ret) - return ret; - /* -@@ -789,8 +788,7 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - * we found the previous extent covering eof and before we - * attempted to increment its reference count). - */ -- ret = btrfs_wait_ordered_range(BTRFS_I(inode), wb_start, -- destoff - wb_start); -+ ret = btrfs_wait_ordered_range(inode, wb_start, destoff - wb_start); - if (ret) - return ret; - } -@@ -801,10 +799,10 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - * because we have already locked the inode's i_mmap_lock in exclusive - * mode. - */ -- end = destoff + len - 1; -- btrfs_lock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state); -+ end = round_up(destoff + len, bs) - 1; -+ btrfs_lock_extent(&inode->io_tree, destoff, end, &cached_state); - ret = btrfs_clone(src, inode, off, olen, len, destoff, false); -- btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state); -+ btrfs_unlock_extent(&inode->io_tree, destoff, end, &cached_state); - if (ret < 0) - return ret; - -@@ -818,7 +816,7 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - * could come from some range other than the copied inline extent's - * destination range and we have no way to know that. - */ -- ret = btrfs_wait_ordered_range(BTRFS_I(inode), destoff, len); -+ ret = btrfs_wait_ordered_range(inode, destoff, len); - if (ret < 0) - return ret; - -@@ -826,7 +824,7 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - * Invalidate page cache so that future reads will see the cloned data - * immediately and not the previous data. - */ -- ret = filemap_invalidate_inode(inode, false, destoff, end); -+ ret = filemap_invalidate_inode(&inode->vfs_inode, false, destoff, end); - if (ret < 0) - return ret; - -@@ -841,7 +839,7 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, - { - struct btrfs_inode *inode_in = BTRFS_I(file_inode(file_in)); - struct btrfs_inode *inode_out = BTRFS_I(file_inode(file_out)); -- u64 bs = inode_out->root->fs_info->sectorsize; -+ const u32 bs = inode_out->root->fs_info->sectorsize; - u64 wb_len; - int ret; - -@@ -934,7 +932,7 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, - bool same_inode = dst_inode == src_inode; - int ret; - -- if (btrfs_is_shutdown(inode_to_fs_info(file_inode(src_file)))) -+ if (btrfs_is_shutdown(src_inode->root->fs_info)) - return -EIO; - - if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) -@@ -953,8 +951,7 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off, - goto out_unlock; - - if (remap_flags & REMAP_FILE_DEDUP) -- ret = btrfs_extent_same(&src_inode->vfs_inode, off, len, -- &dst_inode->vfs_inode, destoff); -+ ret = btrfs_extent_same(src_inode, off, len, dst_inode, destoff); - else - ret = btrfs_clone_files(dst_file, src_file, off, len, destoff); - -diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c ---- a/fs/btrfs/relocation.c -+++ b/fs/btrfs/relocation.c -@@ -339,14 +339,15 @@ static struct btrfs_backref_node *walk_down_backref( - - static bool reloc_root_is_dead(const struct btrfs_root *root) - { -- /* -- * Pair with set_bit/clear_bit in clean_dirty_subvols and -- * btrfs_update_reloc_root. We need to see the updated bit before -- * trying to access reloc_root -- */ -- smp_rmb(); - if (test_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state)) - return true; -+ /* -+ * Pairs with set_bit/clear_bit in clear_reloc_root() and -+ * btrfs_update_reloc_root(). We need to see the updated bit before -+ * trying to access root->reloc_root in our callers. -+ */ -+ smp_rmb(); -+ - return false; - } - -@@ -4151,10 +4152,10 @@ static int copy_remapped_data(struct btrfs_fs_info *fs_info, u64 old_addr, - u64 new_addr, u64 length) - { - int ret; -- u64 copy_len = min_t(u64, length, SZ_1M); -+ const u64 copy_len = min_t(u64, length, SZ_1M); - struct page **pages; - struct reloc_io_private priv; -- unsigned int nr_pages = DIV_ROUND_UP(length, PAGE_SIZE); -+ const unsigned int nr_pages = DIV_ROUND_UP(copy_len, PAGE_SIZE); - - pages = kzalloc_objs(struct page *, nr_pages, GFP_NOFS); - if (!pages) -diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c ---- a/fs/btrfs/root-tree.c -+++ b/fs/btrfs/root-tree.c -@@ -265,15 +265,15 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info) - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - btrfs_err(fs_info, -- "failed to join transaction to delete orphan item: %d", -- ret); -+ "failed to join transaction to delete orphan item: %pe", -+ ERR_PTR(ret)); - return ret; - } - ret = btrfs_del_orphan_item(trans, tree_root, root_objectid); - btrfs_end_transaction(trans); - if (ret) { - btrfs_err(fs_info, -- "failed to delete root orphan item: %d", ret); -+ "failed to delete root orphan item: %pe", ERR_PTR(ret)); - return ret; - } - continue; -diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c ---- a/fs/btrfs/scrub.c -+++ b/fs/btrfs/scrub.c -@@ -57,12 +57,6 @@ struct scrub_ctx; - - #define SCRUB_TOTAL_STRIPES (SCRUB_GROUPS_PER_SCTX * SCRUB_STRIPES_PER_GROUP) - --/* -- * The following value times PAGE_SIZE needs to be large enough to match the -- * largest node/leaf/sector size that shall be supported. -- */ --#define SCRUB_MAX_SECTORS_PER_BLOCK (BTRFS_MAX_METADATA_BLOCKSIZE / SZ_4K) -- - /* Represent one sector and its needed info to verify the content. */ - struct scrub_sector_verification { - union { -@@ -129,19 +123,17 @@ enum { - scrub_bitmap_nr_last, - }; - --#define SCRUB_STRIPE_MAX_FOLIOS (BTRFS_STRIPE_LEN / PAGE_SIZE) -- - /* - * Represent one contiguous range with a length of BTRFS_STRIPE_LEN. - */ - struct scrub_stripe { - struct scrub_ctx *sctx; - struct btrfs_block_group *bg; -- -- struct folio *folios[SCRUB_STRIPE_MAX_FOLIOS]; - struct scrub_sector_verification *sectors; -- - struct btrfs_device *dev; -+ -+ void *buffer; -+ - u64 logical; - u64 physical; - -@@ -227,6 +219,9 @@ struct scrub_ctx { - refcount_t refs; - }; - -+static_assert(BTRFS_STRIPE_LEN >= PAGE_SIZE); -+static_assert(IS_ALIGNED(BTRFS_STRIPE_LEN, PAGE_SIZE)); -+ - #define scrub_calc_start_bit(stripe, name, block_nr) \ - ({ \ - unsigned int __start_bit; \ -@@ -338,13 +333,10 @@ static void release_scrub_stripe(struct scrub_stripe *stripe) - if (!stripe) - return; - -- for (int i = 0; i < SCRUB_STRIPE_MAX_FOLIOS; i++) { -- if (stripe->folios[i]) -- folio_put(stripe->folios[i]); -- stripe->folios[i] = NULL; -- } -+ kvfree(stripe->buffer); - kfree(stripe->sectors); - kfree(stripe->csums); -+ stripe->buffer = NULL; - stripe->sectors = NULL; - stripe->csums = NULL; - stripe->sctx = NULL; -@@ -354,9 +346,6 @@ static void release_scrub_stripe(struct scrub_stripe *stripe) - static int init_scrub_stripe(struct btrfs_fs_info *fs_info, - struct scrub_stripe *stripe) - { -- const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order; -- int ret; -- - memset(stripe, 0, sizeof(*stripe)); - - stripe->nr_sectors = BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits; -@@ -367,11 +356,8 @@ static int init_scrub_stripe(struct btrfs_fs_info *fs_info, - atomic_set(&stripe->pending_io, 0); - spin_lock_init(&stripe->write_error_lock); - -- ASSERT(BTRFS_STRIPE_LEN >> min_folio_shift <= SCRUB_STRIPE_MAX_FOLIOS); -- ret = btrfs_alloc_folio_array(BTRFS_STRIPE_LEN >> min_folio_shift, -- fs_info->block_min_order, stripe->folios, -- GFP_NOFS); -- if (ret < 0) -+ stripe->buffer = kvmalloc(BTRFS_STRIPE_LEN, GFP_NOFS); -+ if (!stripe->buffer) - goto error; - - stripe->sectors = kzalloc_objs(struct scrub_sector_verification, -@@ -682,32 +668,18 @@ static int fill_writer_pointer_gap(struct scrub_ctx *sctx, u64 physical) - return ret; - } - --static void *scrub_stripe_get_kaddr(struct scrub_stripe *stripe, int sector_nr) -+/* -+ * Unlike the existing csum which is based on paddr, this version is fully on -+ * vaddr, so no extra per-page iteration needed. -+ */ -+static void scrub_calc_vaddr_csum(struct btrfs_fs_info *fs_info, -+ void *vaddr, unsigned int len, u8 *dest) - { -- struct btrfs_fs_info *fs_info = stripe->bg->fs_info; -- const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order; -- u32 offset = (sector_nr << fs_info->sectorsize_bits); -- const struct folio *folio = stripe->folios[offset >> min_folio_shift]; -+ struct btrfs_csum_ctx csum; - -- /* stripe->folios[] is allocated by us and no highmem is allowed. */ -- ASSERT(folio); -- ASSERT(!folio_test_highmem(folio)); -- return folio_address(folio) + offset_in_folio(folio, offset); --} -- --static phys_addr_t scrub_stripe_get_paddr(struct scrub_stripe *stripe, int sector_nr) --{ -- struct btrfs_fs_info *fs_info = stripe->bg->fs_info; -- const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order; -- u32 offset = (sector_nr << fs_info->sectorsize_bits); -- const struct folio *folio = stripe->folios[offset >> min_folio_shift]; -- -- /* stripe->folios[] is allocated by us and no highmem is allowed. */ -- ASSERT(folio); -- ASSERT(!folio_test_highmem(folio)); -- /* And the range must be contained inside the folio. */ -- ASSERT(offset_in_folio(folio, offset) + fs_info->sectorsize <= folio_size(folio)); -- return page_to_phys(folio_page(folio, 0)) + offset_in_folio(folio, offset); -+ btrfs_csum_init(&csum, fs_info->csum_type); -+ btrfs_csum_update(&csum, vaddr, len); -+ btrfs_csum_final(&csum, dest); - } - - static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr) -@@ -715,19 +687,10 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr - struct btrfs_fs_info *fs_info = stripe->bg->fs_info; - const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits; - const u64 logical = stripe->logical + (sector_nr << fs_info->sectorsize_bits); -- void *first_kaddr = scrub_stripe_get_kaddr(stripe, sector_nr); -- struct btrfs_header *header = first_kaddr; -- struct btrfs_csum_ctx csum; -- u8 on_disk_csum[BTRFS_CSUM_SIZE]; -+ void *first_vaddr = stripe->buffer + (sector_nr << fs_info->sectorsize_bits); -+ struct btrfs_header *header = first_vaddr; - u8 calculated_csum[BTRFS_CSUM_SIZE]; - -- /* -- * Here we don't have a good way to attach the pages (and subpages) -- * to a dummy extent buffer, thus we have to directly grab the members -- * from pages. -- */ -- memcpy(on_disk_csum, header->csum, fs_info->csum_size); -- - if (logical != btrfs_stack_header_bytenr(header)) { - scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree); - scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree); -@@ -759,23 +722,15 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr - } - - /* Now check tree block csum. */ -- btrfs_csum_init(&csum, fs_info->csum_type); -- btrfs_csum_update(&csum, first_kaddr + BTRFS_CSUM_SIZE, -- fs_info->sectorsize - BTRFS_CSUM_SIZE); -- -- for (int i = sector_nr + 1; i < sector_nr + sectors_per_tree; i++) { -- btrfs_csum_update(&csum, scrub_stripe_get_kaddr(stripe, i), -- fs_info->sectorsize); -- } -- -- btrfs_csum_final(&csum, calculated_csum); -- if (memcmp(calculated_csum, on_disk_csum, fs_info->csum_size) != 0) { -+ scrub_calc_vaddr_csum(fs_info, first_vaddr + BTRFS_CSUM_SIZE, -+ fs_info->nodesize - BTRFS_CSUM_SIZE, calculated_csum); -+ if (memcmp(calculated_csum, header->csum, fs_info->csum_size) != 0) { - scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree); - scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree); - btrfs_warn_rl(fs_info, - "scrub: tree block %llu mirror %u has bad csum, has " BTRFS_CSUM_FMT " want " BTRFS_CSUM_FMT, - logical, stripe->mirror_num, -- BTRFS_CSUM_FMT_VALUE(fs_info->csum_size, on_disk_csum), -+ BTRFS_CSUM_FMT_VALUE(fs_info->csum_size, header->csum), - BTRFS_CSUM_FMT_VALUE(fs_info->csum_size, calculated_csum)); - return; - } -@@ -801,9 +756,7 @@ static void scrub_verify_one_sector(struct scrub_stripe *stripe, int sector_nr) - struct btrfs_fs_info *fs_info = stripe->bg->fs_info; - struct scrub_sector_verification *sector = &stripe->sectors[sector_nr]; - const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits; -- phys_addr_t paddr = scrub_stripe_get_paddr(stripe, sector_nr); - u8 csum_buf[BTRFS_CSUM_SIZE]; -- int ret; - - ASSERT(sector_nr >= 0 && sector_nr < stripe->nr_sectors); - -@@ -846,8 +799,10 @@ static void scrub_verify_one_sector(struct scrub_stripe *stripe, int sector_nr) - return; - } - -- ret = btrfs_check_block_csum(fs_info, paddr, csum_buf, sector->csum); -- if (ret < 0) { -+ scrub_calc_vaddr_csum(fs_info, -+ stripe->buffer + (sector_nr << fs_info->sectorsize_bits), -+ fs_info->sectorsize, csum_buf); -+ if (memcmp(csum_buf, sector->csum, fs_info->csum_size)) { - scrub_bitmap_set_bit_csum_error(stripe, sector_nr); - scrub_bitmap_set_bit_error(stripe, sector_nr); - } else { -@@ -870,16 +825,51 @@ static void scrub_verify_one_stripe(struct scrub_stripe *stripe, unsigned long b - } - } - --static int calc_sector_number(struct scrub_stripe *stripe, struct bio_vec *first_bvec) -+static unsigned int calc_sector_number(const struct btrfs_bio *bbio) - { -- int i; -+ const struct scrub_stripe *stripe = bbio->private; -+ const struct btrfs_fs_info *fs_info = stripe->bg->fs_info; - -- for (i = 0; i < stripe->nr_sectors; i++) { -- if (scrub_stripe_get_kaddr(stripe, i) == bvec_virt(first_bvec)) -- break; -+ /* Scrub bbios all have their @file_offset set to the logical bytenr. */ -+ ASSERT(bbio->file_offset >= stripe->logical && -+ bbio->file_offset < stripe->logical + (stripe->nr_sectors << -+ fs_info->sectorsize_bits), -+ "scrub bio logical=%llu stripe logical=%llu stripe len=%u", -+ bbio->file_offset, stripe->logical, -+ stripe->nr_sectors << fs_info->sectorsize_bits); -+ return (bbio->file_offset - stripe->logical) >> fs_info->sectorsize_bits; -+} -+ -+/* -+ * Common handling of read endio. -+ * -+ * The bbio will be released, so no more access to @bbio after this function. -+ */ -+static void scrub_read_endio_common(struct btrfs_bio *bbio) -+{ -+ struct scrub_stripe *stripe = bbio->private; -+ struct btrfs_fs_info *fs_info = stripe->bg->fs_info; -+ unsigned int sector_nr = calc_sector_number(bbio); -+ const u32 bio_size = bio_get_size(&bbio->bio); -+ const u32 sectors = bio_size >> fs_info->sectorsize_bits; -+ -+ -+ /* -+ * For vmallocated space, readers need to call invalidate_kernel_vmap_range() -+ * to manage the coherency between kernel mapping and devie space mapping. -+ */ -+ if (is_vmalloc_addr(stripe->buffer)) -+ invalidate_kernel_vmap_range( -+ stripe->buffer + (sector_nr << fs_info->sectorsize_bits), -+ bio_size); -+ -+ if (bbio->bio.bi_status) { -+ scrub_bitmap_set_io_error(stripe, sector_nr, sectors); -+ scrub_bitmap_set_error(stripe, sector_nr, sectors); -+ } else { -+ scrub_bitmap_clear_io_error(stripe, sector_nr, sectors); - } -- ASSERT(i < stripe->nr_sectors); -- return i; -+ bio_put(&bbio->bio); - } - - /* -@@ -891,22 +881,9 @@ static int calc_sector_number(struct scrub_stripe *stripe, struct bio_vec *first - static void scrub_repair_read_endio(struct btrfs_bio *bbio) - { - struct scrub_stripe *stripe = bbio->private; -- struct btrfs_fs_info *fs_info = stripe->bg->fs_info; -- int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio)); -- const u32 bio_size = bio_get_size(&bbio->bio); - -- ASSERT(sector_nr < stripe->nr_sectors); -+ scrub_read_endio_common(bbio); - -- if (bbio->bio.bi_status) { -- scrub_bitmap_set_io_error(stripe, sector_nr, -- bio_size >> fs_info->sectorsize_bits); -- scrub_bitmap_set_error(stripe, sector_nr, -- bio_size >> fs_info->sectorsize_bits); -- } else { -- scrub_bitmap_clear_io_error(stripe, sector_nr, -- bio_size >> fs_info->sectorsize_bits); -- } -- bio_put(&bbio->bio); - if (atomic_dec_and_test(&stripe->pending_io)) - wake_up(&stripe->io_wait); - } -@@ -921,30 +898,35 @@ static void scrub_bio_add_sector(struct btrfs_bio *bbio, struct scrub_stripe *st - int sector_nr) - { - struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info; -- void *kaddr = scrub_stripe_get_kaddr(stripe, sector_nr); -+ const u32 offset = sector_nr << fs_info->sectorsize_bits; - int ret; - -- ret = bio_add_page(&bbio->bio, virt_to_page(kaddr), fs_info->sectorsize, -- offset_in_page(kaddr)); -- /* -- * Caller should ensure the bbio has enough size. -- * And we cannot use __bio_add_page(), which doesn't do any merge. -- * -- * Meanwhile for scrub_submit_initial_read() we fully rely on the merge -- * to create the minimal amount of bio vectors, for fs block size < page -- * size cases. -- */ -+ ASSERT(offset + fs_info->sectorsize <= BTRFS_STRIPE_LEN); -+ -+ if (is_vmalloc_addr(stripe->buffer)) { -+ ret = bio_add_vmalloc(&bbio->bio, stripe->buffer + offset, fs_info->sectorsize); -+ ASSERT(ret == true); -+ return; -+ } -+ ret = bio_add_page(&bbio->bio, virt_to_page(stripe->buffer + offset), -+ fs_info->sectorsize, offset_in_page(stripe->buffer + offset)); - ASSERT(ret == fs_info->sectorsize); - } - - static struct btrfs_bio *alloc_scrub_bbio(struct btrfs_fs_info *fs_info, -- unsigned int nr_vecs, blk_opf_t opf, -+ blk_opf_t opf, - u64 logical, - btrfs_bio_end_io_t end_io, void *private) - { - struct btrfs_bio *bbio; - -- bbio = btrfs_bio_alloc(nr_vecs, opf, BTRFS_I(fs_info->btree_inode), -+ /* -+ * Stripe->buffer is allocated by kvmalloc(), which can be pages at -+ * different physical addresses, we have to ensure the bbio is large -+ * enough to contain the full stripe. -+ */ -+ bbio = btrfs_bio_alloc(BTRFS_STRIPE_LEN >> PAGE_SHIFT, opf, -+ BTRFS_I(fs_info->btree_inode), - logical, end_io, private); - bbio->is_scrub = true; - bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT; -@@ -976,7 +958,7 @@ static void scrub_stripe_submit_repair_read(struct scrub_stripe *stripe, - } - - if (!bbio) -- bbio = alloc_scrub_bbio(fs_info, stripe->nr_sectors, REQ_OP_READ, -+ bbio = alloc_scrub_bbio(fs_info, REQ_OP_READ, - stripe->logical + (i << fs_info->sectorsize_bits), - scrub_repair_read_endio, stripe); - -@@ -1249,20 +1231,9 @@ static void scrub_stripe_read_repair_worker(struct work_struct *work) - static void scrub_read_endio(struct btrfs_bio *bbio) - { - struct scrub_stripe *stripe = bbio->private; -- int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio)); -- int num_sectors; -- const u32 bio_size = bio_get_size(&bbio->bio); - -- ASSERT(sector_nr < stripe->nr_sectors); -- num_sectors = bio_size >> stripe->bg->fs_info->sectorsize_bits; -+ scrub_read_endio_common(bbio); - -- if (bbio->bio.bi_status) { -- scrub_bitmap_set_io_error(stripe, sector_nr, num_sectors); -- scrub_bitmap_set_error(stripe, sector_nr, num_sectors); -- } else { -- scrub_bitmap_clear_io_error(stripe, sector_nr, num_sectors); -- } -- bio_put(&bbio->bio); - if (atomic_dec_and_test(&stripe->pending_io)) { - wake_up(&stripe->io_wait); - INIT_WORK(&stripe->work, scrub_stripe_read_repair_worker); -@@ -1274,7 +1245,7 @@ static void scrub_write_endio(struct btrfs_bio *bbio) - { - struct scrub_stripe *stripe = bbio->private; - struct btrfs_fs_info *fs_info = stripe->bg->fs_info; -- int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio)); -+ unsigned int sector_nr = calc_sector_number(bbio); - const u32 bio_size = bio_get_size(&bbio->bio); - - if (bbio->bio.bi_status) { -@@ -1353,7 +1324,7 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str - bbio = NULL; - } - if (!bbio) -- bbio = alloc_scrub_bbio(fs_info, stripe->nr_sectors, REQ_OP_WRITE, -+ bbio = alloc_scrub_bbio(fs_info, REQ_OP_WRITE, - stripe->logical + (sector_nr << fs_info->sectorsize_bits), - scrub_write_endio, stripe); - scrub_bio_add_sector(bbio, stripe, sector_nr); -@@ -1848,7 +1819,7 @@ static void scrub_submit_extent_sector_read(struct scrub_stripe *stripe) - continue; - } - -- bbio = alloc_scrub_bbio(fs_info, stripe->nr_sectors, REQ_OP_READ, -+ bbio = alloc_scrub_bbio(fs_info, REQ_OP_READ, - logical, scrub_read_endio, stripe); - } - -@@ -1873,7 +1844,6 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx, - { - struct btrfs_fs_info *fs_info = sctx->fs_info; - struct btrfs_bio *bbio; -- const u32 min_folio_shift = PAGE_SHIFT + fs_info->block_min_order; - unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits; - int mirror = stripe->mirror_num; - -@@ -1886,7 +1856,7 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx, - return; - } - -- bbio = alloc_scrub_bbio(fs_info, BTRFS_STRIPE_LEN >> min_folio_shift, REQ_OP_READ, -+ bbio = alloc_scrub_bbio(fs_info, REQ_OP_READ, - stripe->logical, scrub_read_endio, stripe); - /* Read the whole range inside the chunk boundary. */ - for (unsigned int cur = 0; cur < nr_sectors; cur++) -@@ -2142,7 +2112,7 @@ static int scrub_raid56_cached_parity(struct scrub_ctx *sctx, - for (int i = 0; i < data_stripes; i++) { - struct scrub_stripe *stripe = &sctx->raid56_data_stripes[i]; - -- raid56_parity_cache_data_folios(rbio, stripe->folios, -+ raid56_parity_cache_data_folios(rbio, stripe->buffer, - full_stripe_start + (i << BTRFS_STRIPE_LEN_SHIFT)); - } - raid56_parity_submit_scrub_rbio(rbio); -@@ -3095,14 +3065,6 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, - /* At mount time we have ensured nodesize is in the range of [4K, 64K]. */ - ASSERT(fs_info->nodesize <= BTRFS_STRIPE_LEN); - -- /* -- * SCRUB_MAX_SECTORS_PER_BLOCK is calculated using the largest possible -- * value (max nodesize / min sectorsize), thus nodesize should always -- * be fine. -- */ -- ASSERT(fs_info->nodesize <= -- SCRUB_MAX_SECTORS_PER_BLOCK << fs_info->sectorsize_bits); -- - /* Allocate outside of device_list_mutex */ - sctx = scrub_setup_ctx(fs_info, is_dev_replace); - if (IS_ERR(sctx)) -diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c ---- a/fs/btrfs/send.c -+++ b/fs/btrfs/send.c -@@ -130,10 +130,10 @@ static_assert(offsetof(struct backref_cache_entry, entry) == 0); - #define SEND_MAX_DIR_CREATED_CACHE_SIZE 64 - - /* -- * Max number of entries in the cache that stores directories that were already -- * created. The cache uses raw struct btrfs_lru_cache_entry entries, so it uses -- * at most 4096 bytes - sizeof(struct btrfs_lru_cache_entry) is 48 bytes, but -- * the kmalloc-64 slab is used, so we get 4096 bytes (64 bytes * 64). -+ * Maximum number of entries in the cache that stores utimes values for directories. -+ * The cache uses raw struct btrfs_lru_cache_entry entries, so it uses at most -+ * 4096 bytes - sizeof(struct btrfs_lru_cache_entry) is 48 bytes, but the -+ * kmalloc-64 slab is used, so we get 4096 bytes (64 bytes * 64). - */ - #define SEND_MAX_DIR_UTIMES_CACHE_SIZE 64 - -@@ -625,9 +625,8 @@ static void fs_path_unreverse(struct fs_path *p) - static inline bool is_current_inode_path(const struct send_ctx *sctx, - const struct fs_path *path) - { -- const struct fs_path *cur = &sctx->cur_inode_path; -- -- return (strncmp(path->start, cur->start, fs_path_len(cur)) == 0); -+ /* Paths are always nul terminated. */ -+ return (strcmp(path->start, sctx->cur_inode_path.start) == 0); - } - - static struct btrfs_path *alloc_path_for_send(void) -@@ -6033,7 +6032,7 @@ static int send_write_or_clone(struct send_ctx *sctx, - int ret = 0; - u64 offset = key->offset; - u64 end; -- u64 bs = sctx->send_root->fs_info->sectorsize; -+ const u32 bs = sctx->send_root->fs_info->sectorsize; - struct btrfs_file_extent_item *ei; - u64 disk_byte; - u64 data_offset; -@@ -8251,7 +8250,7 @@ long btrfs_ioctl_send(struct btrfs_root *send_root, const struct btrfs_ioctl_sen - } - - if (sort_clone_roots) { -- for (i = 0; i < sctx->clone_roots_cnt; i++) { -+ for (i = 0; sctx && i < sctx->clone_roots_cnt; i++) { - btrfs_root_dec_send_in_progress( - sctx->clone_roots[i].root); - btrfs_put_root(sctx->clone_roots[i].root); -diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c ---- a/fs/btrfs/space-info.c -+++ b/fs/btrfs/space-info.c -@@ -2156,7 +2156,7 @@ static bool do_reclaim_sweep(struct btrfs_space_info *space_info, int raid) - will_reclaim = true; - reclaim = true; - } -- bg->reclaim_mark++; -+ bg->reclaim_mark = true; - spin_unlock(&bg->lock); - if (reclaim) - btrfs_mark_bg_to_reclaim(bg); -diff --git a/fs/btrfs/subpage.c b/fs/btrfs/subpage.c ---- a/fs/btrfs/subpage.c -+++ b/fs/btrfs/subpage.c -@@ -59,7 +59,7 @@ int btrfs_attach_folio_state(const struct btrfs_fs_info *fs_info, - if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio)) - return 0; - -- bfs = btrfs_alloc_folio_state(fs_info, folio_size(folio), type); -+ bfs = btrfs_alloc_folio_state(fs_info, folio_size(folio), type, GFP_NOFS); - if (IS_ERR(bfs)) - return PTR_ERR(bfs); - -@@ -86,7 +86,8 @@ void btrfs_detach_folio_state(const struct btrfs_fs_info *fs_info, struct folio - } - - struct btrfs_folio_state *btrfs_alloc_folio_state(const struct btrfs_fs_info *fs_info, -- size_t fsize, enum btrfs_folio_type type) -+ size_t fsize, enum btrfs_folio_type type, -+ gfp_t gfp) - { - struct btrfs_folio_state *ret; - unsigned int real_size; -@@ -96,7 +97,7 @@ struct btrfs_folio_state *btrfs_alloc_folio_state(const struct btrfs_fs_info *fs - real_size = struct_size(ret, bitmaps, - BITS_TO_LONGS(btrfs_bitmap_nr_max * - (fsize >> fs_info->sectorsize_bits))); -- ret = kzalloc(real_size, GFP_NOFS); -+ ret = kzalloc(real_size, gfp); - if (!ret) - return ERR_PTR(-ENOMEM); - -diff --git a/fs/btrfs/subpage.h b/fs/btrfs/subpage.h ---- a/fs/btrfs/subpage.h -+++ b/fs/btrfs/subpage.h -@@ -110,7 +110,8 @@ void btrfs_detach_folio_state(const struct btrfs_fs_info *fs_info, struct folio - - /* Allocate additional data where page represents more than one sector */ - struct btrfs_folio_state *btrfs_alloc_folio_state(const struct btrfs_fs_info *fs_info, -- size_t fsize, enum btrfs_folio_type type); -+ size_t fsize, enum btrfs_folio_type type, -+ gfp_t gfp); - static inline void btrfs_free_folio_state(struct btrfs_folio_state *bfs) - { - kfree(bfs); -diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c ---- a/fs/btrfs/super.c -+++ b/fs/btrfs/super.c -@@ -129,7 +129,6 @@ enum { - - /* Rescue options */ - Opt_rescue, -- Opt_usebackuproot, - - /* Debugging options */ - Opt_enospc_debug, -@@ -249,8 +248,6 @@ static const struct fs_parameter_spec btrfs_fs_parameters[] = { - - /* Rescue options. */ - fsparam_enum("rescue", Opt_rescue, btrfs_parameter_rescue), -- /* Deprecated, with alias rescue=usebackuproot */ -- __fsparam(NULL, "usebackuproot", Opt_usebackuproot, fs_param_deprecated, NULL), - /* For compatibility only, alias for "rescue=nologreplay". */ - fsparam_flag("norecovery", Opt_norecovery), - -@@ -514,19 +511,20 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param) - btrfs_clear_opt(ctx->mount_opt, NODISCARD); - break; - case Opt_space_cache: -- if (result.negated) { -- btrfs_set_opt(ctx->mount_opt, NOSPACECACHE); -- btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE); -- btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE); -- } else { -- btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE); -- btrfs_set_opt(ctx->mount_opt, SPACE_CACHE); -- } -+ if (!result.negated) -+ btrfs_warn(NULL, -+ "v1 space cache is deprecated, falling back to no space cache"); -+ btrfs_set_opt(ctx->mount_opt, NOSPACECACHE); -+ btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE); -+ btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE); - break; - case Opt_space_cache_version: - switch (result.uint_32) { - case Opt_space_cache_v1: -- btrfs_set_opt(ctx->mount_opt, SPACE_CACHE); -+ btrfs_warn(NULL, -+ "v1 space cache is deprecated, falling back to no space cache"); -+ btrfs_set_opt(ctx->mount_opt, NOSPACECACHE); -+ btrfs_clear_opt(ctx->mount_opt, SPACE_CACHE); - btrfs_clear_opt(ctx->mount_opt, FREE_SPACE_TREE); - break; - case Opt_space_cache_v2: -@@ -560,14 +558,6 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param) - else - btrfs_set_opt(ctx->mount_opt, AUTO_DEFRAG); - break; -- case Opt_usebackuproot: -- btrfs_warn(NULL, -- "'usebackuproot' is deprecated, use 'rescue=usebackuproot' instead"); -- btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT); -- -- /* If we're loading the backup roots we can't trust the space cache. */ -- btrfs_set_opt(ctx->mount_opt, CLEAR_CACHE); -- break; - case Opt_skip_balance: - btrfs_set_opt(ctx->mount_opt, SKIP_BALANCE); - break; -@@ -620,6 +610,7 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param) - btrfs_set_opt(ctx->mount_opt, IGNORESUPERFLAGS); - btrfs_set_opt(ctx->mount_opt, IGNOREBADROOTS); - btrfs_set_opt(ctx->mount_opt, NOLOGREPLAY); -+ btrfs_set_opt(ctx->mount_opt, USEBACKUPROOT); - break; - default: - btrfs_info(NULL, "unrecognized rescue option '%s'", -@@ -668,7 +659,6 @@ static int btrfs_parse_param(struct fs_context *fc, struct fs_parameter *param) - */ - static void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info) - { -- btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT); - btrfs_clear_opt(fs_info->mount_opt, CLEAR_CACHE); - btrfs_clear_opt(fs_info->mount_opt, NOSPACECACHE); - } -@@ -692,7 +682,8 @@ bool btrfs_check_options(const struct btrfs_fs_info *info, - bool ret = true; - - if (!(flags & SB_RDONLY) && -- (check_ro_option(info, *mount_opt, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") || -+ (check_ro_option(info, *mount_opt, BTRFS_MOUNT_USEBACKUPROOT, "usebackuproot") || -+ check_ro_option(info, *mount_opt, BTRFS_MOUNT_NOLOGREPLAY, "nologreplay") || - check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREBADROOTS, "ignorebadroots") || - check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREDATACSUMS, "ignoredatacsums") || - check_ro_option(info, *mount_opt, BTRFS_MOUNT_IGNOREMETACSUMS, "ignoremetacsums") || -@@ -982,7 +973,7 @@ static int btrfs_fill_super(struct super_block *sb, - - ret = open_ctree(sb, fs_devices); - if (ret) { -- btrfs_err(fs_info, "open_ctree failed: %d", ret); -+ btrfs_err(fs_info, "open_ctree failed: %pe", ERR_PTR(ret)); - return ret; - } - -diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c ---- a/fs/btrfs/sysfs.c -+++ b/fs/btrfs/sysfs.c -@@ -1336,7 +1336,7 @@ char *btrfs_get_mod_read_policy(void) - return read_policy; - } - --/* Set perms to 0, disable /sys/module/btrfs/parameter/read_policy interface. */ -+/* Set perms to 0, disable /sys/module/btrfs/parameters/read_policy interface. */ - module_param(read_policy, charp, 0); - MODULE_PARM_DESC(read_policy, - "Global read policy: pid (default), round-robin[:], devid[:]"); -diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c ---- a/fs/btrfs/transaction.c -+++ b/fs/btrfs/transaction.c -@@ -1528,12 +1528,8 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans) - ASSERT(atomic_read(&root->log_writers) == 0, - "atomic_read(&root->log_writers)=%d", - atomic_read(&root->log_writers)); -- ASSERT(atomic_read(&root->log_commit[0]) == 0, -- "atomic_read(&root->log_commit[0])=%d", -- atomic_read(&root->log_commit[0])); -- ASSERT(atomic_read(&root->log_commit[1]) == 0, -- "atomic_read(&root->log_commit[1])=%d", -- atomic_read(&root->log_commit[1])); -+ ASSERT(!root->log_commit[0]); -+ ASSERT(!root->log_commit[1]); - - radix_tree_tag_clear(&fs_info->fs_roots_radix, - (unsigned long)btrfs_root_id(root), -@@ -1651,7 +1647,7 @@ static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, - ret = btrfs_write_and_wait_transaction(trans); - if (unlikely(ret)) { - btrfs_err(fs_info, --"error while writing out transaction during qgroup snapshot accounting: %d", ret); -+"error while writing out transaction during qgroup snapshot accounting: %pe", ERR_PTR(ret)); - return ret; - } - -@@ -2597,7 +2593,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans) - - ret = btrfs_write_and_wait_transaction(trans); - if (unlikely(ret)) { -- btrfs_err(fs_info, "error while writing out transaction: %d", ret); -+ btrfs_err(fs_info, "error while writing out transaction: %pe", ERR_PTR(ret)); - /* - * Abort before releasing tree_log_mutex, so a log sync waiting - * on it sees the fs error and skips writing super_for_commit -@@ -2764,8 +2760,8 @@ void __cold __btrfs_abort_transaction(struct btrfs_trans_handle *trans, - WRITE_ONCE(trans->transaction->aborted, error); - trace_btrfs_transaction_abort(trans); - if (first_hit) { -- btrfs_err(fs_info, "Transaction %llu aborted (error %d)", -- trans->transid, error); -+ btrfs_err(fs_info, "Transaction %llu aborted (%pe)", -+ trans->transid, ERR_PTR(error)); - if (error == -ENOSPC) - btrfs_dump_space_info_for_trans_abort(fs_info); - } -diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c ---- a/fs/btrfs/tree-log.c -+++ b/fs/btrfs/tree-log.c -@@ -221,7 +221,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, - static int link_to_fixup_dir(struct walk_control *wc, u64 objectid); - static noinline int replay_dir_deletes(struct walk_control *wc, - u64 dirid, bool del_all); --static void wait_log_commit(struct btrfs_root *root, int transid); -+static bool wait_log_commit(struct btrfs_root *root, int transid); - - /* - * tree logging is a special write ahead log used to make sure that -@@ -305,24 +305,13 @@ static int start_log_trans(struct btrfs_trans_handle *trans, - - again: - if (root->log_root) { -- int index = (root->log_transid + 1) % 2; -- - if (btrfs_need_log_full_commit(trans)) { - ret = BTRFS_LOG_FORCE_COMMIT; - goto out; - } - -- if (zoned && atomic_read(&root->log_commit[index])) { -- wait_log_commit(root, root->log_transid - 1); -+ if (zoned && wait_log_commit(root, root->log_transid - 1)) - goto again; -- } -- -- if (!root->log_start_pid) { -- clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); -- root->log_start_pid = current->pid; -- } else if (root->log_start_pid != current->pid) { -- set_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); -- } - } else { - /* - * This means fs_info->log_root_tree was already created -@@ -340,8 +329,6 @@ static int start_log_trans(struct btrfs_trans_handle *trans, - goto out; - - set_bit(BTRFS_ROOT_HAS_LOG_TREE, &root->state); -- clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); -- root->log_start_pid = current->pid; - } - - atomic_inc(&root->log_writers); -@@ -372,13 +359,9 @@ static int join_running_log_trans(struct btrfs_root *root) - mutex_lock(&root->log_mutex); - again: - if (root->log_root) { -- int index = (root->log_transid + 1) % 2; -- - ret = 0; -- if (zoned && atomic_read(&root->log_commit[index])) { -- wait_log_commit(root, root->log_transid - 1); -+ if (zoned && wait_log_commit(root, root->log_transid - 1)) - goto again; -- } - atomic_inc(&root->log_writers); - } - mutex_unlock(&root->log_mutex); -@@ -2986,6 +2969,7 @@ static noinline int walk_down_log_tree(struct btrfs_path *path, int *level, - { - struct btrfs_trans_handle *trans = wc->trans; - struct btrfs_fs_info *fs_info = wc->log->fs_info; -+ struct btrfs_eb_prealloc pa = { 0 }; - u64 bytenr; - u64 ptr_gen; - struct extent_buffer *next; -@@ -3010,7 +2994,7 @@ static noinline int walk_down_log_tree(struct btrfs_path *path, int *level, - check.has_first_key = true; - btrfs_node_key_to_cpu(cur, &check.first_key, path->slots[*level]); - -- next = btrfs_find_create_tree_block(fs_info, bytenr, -+ next = btrfs_find_create_tree_block(fs_info, &pa, bytenr, - btrfs_header_owner(cur), - *level - 1); - if (IS_ERR(next)) { -@@ -3181,10 +3165,14 @@ static int update_log_root(struct btrfs_trans_handle *trans, - return ret; - } - --static void wait_log_commit(struct btrfs_root *root, int transid) -+/* Returns true if we had to wait, false otherwise. */ -+static bool wait_log_commit(struct btrfs_root *root, int transid) - { - DEFINE_WAIT(wait); -- int index = transid % 2; -+ const int index = (transid >= 0 ? transid % 2 : -transid % 2); -+ -+ if (!root->log_commit[index]) -+ return false; - - /* - * we only allow two pending log transactions at a time, -@@ -3195,15 +3183,17 @@ static void wait_log_commit(struct btrfs_root *root, int transid) - prepare_to_wait(&root->log_commit_wait[index], - &wait, TASK_UNINTERRUPTIBLE); - -- if (!(root->log_transid_committed < transid && -- atomic_read(&root->log_commit[index]))) -- break; -- - mutex_unlock(&root->log_mutex); - schedule(); - mutex_lock(&root->log_mutex); -+ -+ if (!(root->log_transid_committed < transid && -+ root->log_commit[index])) -+ break; - } - finish_wait(&root->log_commit_wait[index], &wait); -+ -+ return true; - } - - static void wait_for_writer(struct btrfs_root *root) -@@ -3307,15 +3297,15 @@ static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root, - int btrfs_sync_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_log_ctx *ctx) - { -- int index1; -- int index2; - int mark; - int ret; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_root *log = root->log_root; - struct btrfs_root *log_root_tree = fs_info->log_root_tree; - struct btrfs_root_item new_root_item; -- int log_transid = 0; -+ int log_transid = ctx->log_transid; -+ int index1 = log_transid % 2; -+ int index2; - struct btrfs_log_ctx root_log_ctx; - struct blk_plug plug; - u64 log_root_start; -@@ -3323,41 +3313,25 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, - - mutex_lock(&root->log_mutex); - trace_btrfs_sync_log_enter(trans, root, ctx); -- log_transid = ctx->log_transid; - if (root->log_transid_committed >= log_transid) { - trace_btrfs_sync_log_exit(trans, root, ctx, ctx->log_ret); - mutex_unlock(&root->log_mutex); - return ctx->log_ret; - } - -- index1 = log_transid % 2; -- if (atomic_read(&root->log_commit[index1])) { -- wait_log_commit(root, log_transid); -+ if (wait_log_commit(root, log_transid)) { - trace_btrfs_sync_log_exit(trans, root, ctx, ctx->log_ret); - mutex_unlock(&root->log_mutex); - return ctx->log_ret; - } - ASSERT(log_transid == root->log_transid, - "log_transid=%d root->log_transid=%d", log_transid, root->log_transid); -- atomic_set(&root->log_commit[index1], 1); -+ root->log_commit[index1] = true; - - /* wait for previous tree log sync to complete */ -- if (atomic_read(&root->log_commit[(index1 + 1) % 2])) -- wait_log_commit(root, log_transid - 1); -+ wait_log_commit(root, log_transid - 1); - -- while (1) { -- int batch = atomic_read(&root->log_batch); -- /* when we're on an ssd, just kick the log commit out */ -- if (!btrfs_test_opt(fs_info, SSD) && -- test_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state)) { -- mutex_unlock(&root->log_mutex); -- schedule_timeout_uninterruptible(1); -- mutex_lock(&root->log_mutex); -- } -- wait_for_writer(root); -- if (batch == atomic_read(&root->log_batch)) -- break; -- } -+ wait_for_writer(root); - - /* bail out if we need to do a full commit */ - if (btrfs_need_log_full_commit(trans)) { -@@ -3414,7 +3388,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, - - btrfs_set_root_log_transid(root, root->log_transid + 1); - log->log_transid = root->log_transid; -- root->log_start_pid = 0; - /* - * IO has been started, blocks of the log tree have WRITTEN flag set - * in their headers. new modifications of the log will be written to -@@ -3473,7 +3446,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, - goto out; - } - -- if (atomic_read(&log_root_tree->log_commit[index2])) { -+ if (log_root_tree->log_commit[index2]) { - blk_finish_plug(&plug); - ret = btrfs_wait_tree_log_extents(log, mark); - wait_log_commit(log_root_tree, -@@ -3487,12 +3460,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, - ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid, - "root_log_ctx.log_transid=%d log_root_tree->log_transid=%d", - root_log_ctx.log_transid, log_root_tree->log_transid); -- atomic_set(&log_root_tree->log_commit[index2], 1); -+ log_root_tree->log_commit[index2] = true; - -- if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) { -- wait_log_commit(log_root_tree, -- root_log_ctx.log_transid - 1); -- } -+ wait_log_commit(log_root_tree, root_log_ctx.log_transid - 1); - - /* - * now that we've moved on to the tree of log tree roots, -@@ -3590,7 +3560,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, - - /* - * We know there can only be one task here, since we have not yet set -- * root->log_commit[index1] to 0 and any task attempting to sync the -+ * root->log_commit[index1] to false and any task attempting to sync the - * log must wait for the previous log transaction to commit if it's - * still in progress or wait for the current log transaction commit if - * someone else already started it. We use <= and not < because the -@@ -3606,7 +3576,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, - btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); - - log_root_tree->log_transid_committed++; -- atomic_set(&log_root_tree->log_commit[index2], 0); -+ log_root_tree->log_commit[index2] = false; - mutex_unlock(&log_root_tree->log_mutex); - - /* -@@ -3619,7 +3589,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, - mutex_lock(&root->log_mutex); - btrfs_remove_all_log_ctxs(root, index1, ret); - root->log_transid_committed++; -- atomic_set(&root->log_commit[index1], 0); -+ root->log_commit[index1] = false; - mutex_unlock(&root->log_mutex); - - /* -@@ -5622,6 +5592,15 @@ static int btrfs_log_holes(struct btrfs_trans_handle *trans, - if (!btrfs_fs_incompat(fs_info, NO_HOLES) || i_size == 0) - return 0; - -+ /* -+ * If there are no prealloc extents (which can be located past i_size), -+ * and disk space used is greater than or equals to i_size, then there -+ * are no holes. -+ */ -+ if (!(inode->flags & BTRFS_INODE_PREALLOC) && -+ i_size <= inode_get_bytes(&inode->vfs_inode)) -+ return 0; -+ - key.objectid = ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = 0; -diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c ---- a/fs/btrfs/verity.c -+++ b/fs/btrfs/verity.c -@@ -652,7 +652,7 @@ static int btrfs_end_enable_verity(struct file *filp, const void *desc, - rollback_ret = rollback_verity(inode); - if (rollback_ret) - btrfs_err(inode->root->fs_info, -- "failed to rollback verity items: %d", rollback_ret); -+ "failed to rollback verity items: %pe", ERR_PTR(rollback_ret)); - return ret; - } - -diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c ---- a/fs/btrfs/volumes.c -+++ b/fs/btrfs/volumes.c -@@ -740,41 +740,6 @@ const u8 *btrfs_sb_fsid_ptr(const struct btrfs_super_block *sb) - return has_metadata_uuid ? sb->metadata_uuid : sb->fsid; - } - --static bool is_same_device(struct btrfs_device *device, const char *new_path) --{ -- struct path old = { .mnt = NULL, .dentry = NULL }; -- struct path new = { .mnt = NULL, .dentry = NULL }; -- char AUTO_KFREE(old_path); -- bool is_same = false; -- int ret; -- -- if (!device->name) -- goto out; -- -- old_path = kzalloc(PATH_MAX, GFP_NOFS); -- if (!old_path) -- goto out; -- -- rcu_read_lock(); -- ret = strscpy(old_path, rcu_dereference(device->name), PATH_MAX); -- rcu_read_unlock(); -- if (ret < 0) -- goto out; -- -- ret = kern_path(old_path, LOOKUP_FOLLOW, &old); -- if (ret) -- goto out; -- ret = kern_path(new_path, LOOKUP_FOLLOW, &new); -- if (ret) -- goto out; -- if (path_equal(&old, &new)) -- is_same = true; --out: -- path_put(&old); -- path_put(&new); -- return is_same; --} -- - /* - * Add new device to list of registered devices - * -@@ -895,7 +860,7 @@ static noinline struct btrfs_device *device_list_add(const char *path, - MAJOR(path_devt), MINOR(path_devt), - current->comm, task_pid_nr(current)); - -- } else if (!device->name || !is_same_device(device, path)) { -+ } else if (!device->name || device->devt != path_devt) { - const char *old_name; - - /* -@@ -4592,7 +4557,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info) - if (ret == -ENOSPC) { - enospc_errors++; - } else if (ret == -ETXTBSY) { -- btrfs_info(fs_info, -+ btrfs_warn(fs_info, - "skipping relocation of block group %llu due to active swapfile", - found_key.offset); - ret = 0; -@@ -6053,6 +6018,19 @@ struct btrfs_chunk_map *btrfs_alloc_chunk_map(int num_stripes, gfp_t gfp) - return map; - } - -+static void set_real_chunk_type(struct btrfs_chunk_map *map) -+{ -+ map->type = map->on_disk_type; -+ if (likely((map->on_disk_type & BTRFS_BLOCK_GROUP_RAID56_MASK) == 0 || -+ nr_data_stripes(map) > 1)) -+ return; -+ if (map->on_disk_type & BTRFS_BLOCK_GROUP_RAID5) -+ map->type |= BTRFS_BLOCK_GROUP_RAID1; -+ else -+ map->type |= BTRFS_BLOCK_GROUP_RAID1C3; -+ map->type &= ~BTRFS_BLOCK_GROUP_RAID56_MASK; -+} -+ - static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans, - struct alloc_chunk_ctl *ctl, - struct btrfs_device_info *devices_info) -@@ -6071,11 +6049,10 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans, - map->start = start; - map->chunk_len = ctl->chunk_size; - map->stripe_size = ctl->stripe_size; -- map->type = type; -- map->io_align = BTRFS_STRIPE_LEN; -- map->io_width = BTRFS_STRIPE_LEN; -+ map->on_disk_type = type; - map->sub_stripes = ctl->sub_stripes; - map->num_stripes = ctl->num_stripes; -+ set_real_chunk_type(map); - - for (int i = 0; i < ctl->ndevs; i++) { - for (int j = 0; j < ctl->dev_stripes; j++) { -@@ -6254,7 +6231,7 @@ int btrfs_chunk_alloc_add_chunk_item(struct btrfs_trans_handle *trans, - btrfs_set_stack_chunk_length(chunk, bg->length); - btrfs_set_stack_chunk_owner(chunk, BTRFS_EXTENT_TREE_OBJECTID); - btrfs_set_stack_chunk_stripe_len(chunk, BTRFS_STRIPE_LEN); -- btrfs_set_stack_chunk_type(chunk, map->type); -+ btrfs_set_stack_chunk_type(chunk, map->on_disk_type); - btrfs_set_stack_chunk_num_stripes(chunk, map->num_stripes); - btrfs_set_stack_chunk_io_align(chunk, BTRFS_STRIPE_LEN); - btrfs_set_stack_chunk_io_width(chunk, BTRFS_STRIPE_LEN); -@@ -7636,9 +7613,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, - map->start = logical; - map->chunk_len = length; - map->num_stripes = num_stripes; -- map->io_width = btrfs_chunk_io_width(leaf, chunk); -- map->io_align = btrfs_chunk_io_align(leaf, chunk); -- map->type = type; -+ map->on_disk_type = type; - /* - * We can't use the sub_stripes value, as for profiles other than - * RAID10, they may have 0 as sub_stripes for filesystems created by -@@ -7649,6 +7624,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, - */ - map->sub_stripes = btrfs_raid_array[index].sub_stripes; - map->verified_stripes = 0; -+ set_real_chunk_type(map); - - if (num_stripes > 0) - map->stripe_size = btrfs_calc_stripe_length(map); -diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h ---- a/fs/btrfs/volumes.h -+++ b/fs/btrfs/volumes.h -@@ -632,9 +632,15 @@ struct btrfs_chunk_map { - u64 start; - u64 chunk_len; - u64 stripe_size; -+ /* -+ * The real type that is utilized during logical address mapping. -+ * -+ * For most profiles it matches @on_disk_type, but for single-data-RAID56, -+ * the real type will be set to RAID1/RAID1C3, to avoid unsupported -+ * operations from raid56 lib. -+ */ - u64 type; -- int io_align; -- int io_width; -+ u64 on_disk_type; - int num_stripes; - int sub_stripes; - struct btrfs_io_stripe stripes[]; -diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h ---- a/include/trace/events/btrfs.h -+++ b/include/trace/events/btrfs.h -@@ -1613,9 +1613,9 @@ TRACE_EVENT(btrfs_sync_log_enter, - __entry->log_transid_committed = - data_race(root->log_transid_committed); - __entry->log_committing = -- atomic_read(&root->log_commit[ctx->log_transid % 2]); -+ data_race(root->log_commit[ctx->log_transid % 2]); - __entry->log_committing_prev = -- atomic_read(&root->log_commit[(ctx->log_transid + 1) % 2]); -+ data_race(root->log_commit[(ctx->log_transid + 1) % 2]); - __entry->log_writers = atomic_read(&root->log_writers); - ), - diff --git a/kernel/0300-btrfs.patch.sig b/kernel/0300-btrfs.patch.sig deleted file mode 100644 index c992405..0000000 Binary files a/kernel/0300-btrfs.patch.sig and /dev/null differ diff --git a/kernel/0301-btrfs-fixes-1.patch b/kernel/0301-btrfs-fixes-1.patch deleted file mode 100644 index 8cc1ec5..0000000 --- a/kernel/0301-btrfs-fixes-1.patch +++ /dev/null @@ -1,92 +0,0 @@ -diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c ---- a/fs/btrfs/dev-replace.c -+++ b/fs/btrfs/dev-replace.c -@@ -627,7 +627,7 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, - - ret = mark_block_group_to_copy(fs_info, src_device); - if (ret) -- return ret; -+ goto leave; - - down_write(&dev_replace->rwsem); - dev_replace->replace_task = current; -diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c ---- a/fs/btrfs/ioctl.c -+++ b/fs/btrfs/ioctl.c -@@ -384,6 +384,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap, - inode_flags &= ~BTRFS_INODE_COMPRESS; - inode_flags |= BTRFS_INODE_NOCOMPRESS; - } else if (fsflags & FS_COMPR_FL) { -+ enum btrfs_compression_type comp_type; - - if (IS_SWAPFILE(&inode->vfs_inode)) - return -ETXTBSY; -@@ -391,9 +392,23 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap, - inode_flags |= BTRFS_INODE_COMPRESS; - inode_flags &= ~BTRFS_INODE_NOCOMPRESS; - -- comp = btrfs_compress_type2str(fs_info->compress_type); -- if (!comp || comp[0] == 0) -- comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB); -+ /* -+ * Keep the algorithm recorded in the compression property, -+ * otherwise changing an unrelated attribute would reset it to -+ * the mount default, since FS_IOC_SETFLAGS callers write back -+ * the whole flag set they got from FS_IOC_GETFLAGS and that -+ * includes FS_COMPR_FL for any inode carrying the property. -+ * -+ * Inodes with the compress flag set but no property keep using -+ * the mount default, so they behave as before. -+ */ -+ if (inode->prop_compress) -+ comp_type = inode->prop_compress; -+ else if (fs_info->compress_type) -+ comp_type = fs_info->compress_type; -+ else -+ comp_type = BTRFS_COMPRESS_ZLIB; -+ comp = btrfs_compress_type2str(comp_type); - } else { - inode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); - } -diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c ---- a/fs/btrfs/send.c -+++ b/fs/btrfs/send.c -@@ -6417,6 +6417,13 @@ static int process_extent(struct send_ctx *sctx, - - if (S_ISLNK(sctx->cur_inode_mode)) - return 0; -+ if (unlikely(!S_ISREG(sctx->cur_inode_mode))) { -+ btrfs_crit(sctx->send_root->fs_info, -+ "send: extent for non-regular inode %llu root %llu mode 0%llo", -+ key->objectid, btrfs_root_id(sctx->send_root), -+ sctx->cur_inode_mode & S_IFMT); -+ return -EUCLEAN; -+ } - - if (sctx->parent_root && !sctx->cur_inode_new) { - ret = is_extent_unchanged(sctx, path, key); -diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c ---- a/fs/btrfs/zoned.c -+++ b/fs/btrfs/zoned.c -@@ -2710,6 +2710,7 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng - { - struct btrfs_block_group *block_group; - u64 min_alloc_bytes; -+ int ret = 0; - - if (!btrfs_is_zoned(fs_info)) - return 0; -@@ -2729,11 +2730,11 @@ int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 leng - block_group->start + block_group->zone_capacity) - goto out; - -- do_zone_finish(block_group, true); -+ ret = do_zone_finish(block_group, true); - - out: - btrfs_put_block_group(block_group); -- return 0; -+ return ret; - } - - static void btrfs_zone_finish_endio_workfn(struct work_struct *work) diff --git a/kernel/0301-btrfs-fixes-1.patch.sig b/kernel/0301-btrfs-fixes-1.patch.sig deleted file mode 100644 index e43d3d6..0000000 Binary files a/kernel/0301-btrfs-fixes-1.patch.sig and /dev/null differ diff --git a/kernel/0302-btrfs-zstd-decompress-direct-to-page.patch b/kernel/0302-btrfs-zstd-decompress-direct-to-page.patch deleted file mode 100644 index d949f95..0000000 --- a/kernel/0302-btrfs-zstd-decompress-direct-to-page.patch +++ /dev/null @@ -1,109 +0,0 @@ -diff --git c/fs/btrfs/zstd.c i/fs/btrfs/zstd.c ---- c/fs/btrfs/zstd.c -+++ i/fs/btrfs/zstd.c -@@ -589,10 +589,48 @@ int zstd_compress_bio(struct list_head *ws, struct compressed_bio *cb) - return ret; - } - -+/* -+ * Map the destination for the next chunk of output. -+ * -+ * @decompressed is the offset of the next output byte inside the fully -+ * decompressed extent. If that offset has reached the current destination -+ * segment, its page-bounded bio_vec is kmapped so that zstd can write into the -+ * page cache directly, and the number of bytes writable there is returned. -+ * Otherwise @kaddr_ret is set to NULL and the number of bytes to skip before -+ * that segment is returned. This covers both the initial prefix and gaps in -+ * the destination bio. -+ */ -+static u32 zstd_map_dest(struct compressed_bio *cb, u32 decompressed, -+ void **kaddr_ret) -+{ -+ struct bio *orig_bio = &cb->orig_bbio->bio; -+ struct bio_vec bvec; -+ u32 bvec_offset; -+ u32 off; -+ -+ bvec = bio_iter_iovec(orig_bio, orig_bio->bi_iter); -+ /* -+ * cb->start may underflow, but subtracting that value can still give us -+ * the correct offset inside the full decompressed extent. -+ */ -+ bvec_offset = page_offset(bvec.bv_page) + bvec.bv_offset - cb->start; -+ -+ if (decompressed < bvec_offset) { -+ *kaddr_ret = NULL; -+ return bvec_offset - decompressed; -+ } -+ -+ off = decompressed - bvec_offset; -+ ASSERT(off < bvec.bv_len); -+ *kaddr_ret = bvec_kmap_local(&bvec) + off; -+ return bvec.bv_len - off; -+} -+ - int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb) - { - struct btrfs_fs_info *fs_info = cb_to_fs_info(cb); - struct workspace *workspace = list_entry(ws, struct workspace, list); -+ struct bio *orig_bio = &cb->orig_bbio->bio; - struct folio_iter fi; - size_t srclen = bio_get_size(&cb->bbio.bio); - zstd_dstream *stream; -@@ -600,7 +638,6 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb) - const unsigned int min_folio_size = btrfs_min_folio_size(fs_info); - unsigned long folio_in_index = 0; - unsigned long total_folios_in = DIV_ROUND_UP(srclen, min_folio_size); -- unsigned long buf_start; - unsigned long total_out = 0; - - bio_first_folio(&fi, &cb->bbio.bio, 0); -@@ -624,15 +661,26 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb) - workspace->in_buf.pos = 0; - workspace->in_buf.size = min_t(size_t, srclen, min_folio_size); - -- workspace->out_buf.dst = workspace->buf; -- workspace->out_buf.pos = 0; -- workspace->out_buf.size = fs_info->sectorsize; -- -- while (1) { -+ while (orig_bio->bi_iter.bi_size) { - size_t ret2; -+ void *kaddr; -+ u32 dstlen; -+ -+ dstlen = zstd_map_dest(cb, total_out, &kaddr); -+ if (kaddr) { -+ workspace->out_buf.dst = kaddr; -+ workspace->out_buf.size = dstlen; -+ } else { -+ workspace->out_buf.dst = workspace->buf; -+ workspace->out_buf.size = min_t(u32, dstlen, -+ fs_info->sectorsize); -+ } -+ workspace->out_buf.pos = 0; - - ret2 = zstd_decompress_stream(stream, &workspace->out_buf, - &workspace->in_buf); -+ if (kaddr) -+ kunmap_local(kaddr); - if (unlikely(zstd_is_error(ret2))) { - struct btrfs_inode *inode = cb->bbio.inode; - -@@ -643,14 +691,9 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb) - ret = -EIO; - goto done; - } -- buf_start = total_out; - total_out += workspace->out_buf.pos; -- workspace->out_buf.pos = 0; -- -- ret = btrfs_decompress_buf2page(workspace->out_buf.dst, -- total_out - buf_start, cb, buf_start); -- if (ret == 0) -- break; -+ if (kaddr) -+ bio_advance(orig_bio, workspace->out_buf.pos); - - if (workspace->in_buf.pos >= srclen) - break; diff --git a/kernel/0302-btrfs-zstd-decompress-direct-to-page.patch.sig b/kernel/0302-btrfs-zstd-decompress-direct-to-page.patch.sig deleted file mode 100644 index a75cf51..0000000 Binary files a/kernel/0302-btrfs-zstd-decompress-direct-to-page.patch.sig and /dev/null differ diff --git a/kernel/0303-btrfs-fixes-2.patch b/kernel/0303-btrfs-fixes-2.patch deleted file mode 100644 index 42654e7..0000000 --- a/kernel/0303-btrfs-fixes-2.patch +++ /dev/null @@ -1,97 +0,0 @@ -diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c ---- a/fs/btrfs/block-group.c -+++ b/fs/btrfs/block-group.c -@@ -3074,6 +3074,18 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran - return ERR_PTR(ret); - } - -+ /* -+ * Ensure the corresponding space_info object is created and -+ * assigned to our block group. We want our bg to be added to the rbtree -+ * with its ->space_info set. -+ * -+ * On a zoned filesystem btrfs_add_new_free_space() ends up in -+ * __btrfs_add_free_space_zoned(), which dereferences -+ * block_group->space_info, so it has to be set beforehand. -+ */ -+ cache->space_info = space_info; -+ ASSERT(cache->space_info); -+ - ret = btrfs_add_new_free_space(cache, chunk_offset, chunk_offset + size, NULL); - btrfs_free_excluded_extents(cache); - if (ret) { -@@ -3081,14 +3093,6 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran - return ERR_PTR(ret); - } - -- /* -- * Ensure the corresponding space_info object is created and -- * assigned to our block group. We want our bg to be added to the rbtree -- * with its ->space_info set. -- */ -- cache->space_info = space_info; -- ASSERT(cache->space_info); -- - ret = btrfs_add_block_group_cache(cache); - if (ret) { - btrfs_remove_free_space_cache(cache); -diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c ---- a/fs/btrfs/tree-checker.c -+++ b/fs/btrfs/tree-checker.c -@@ -1909,6 +1909,16 @@ static int check_inode_ref(struct extent_buffer *leaf, - return -EUCLEAN; - } - -+ if (unlikely(btrfs_is_fstree(btrfs_header_owner(leaf)) && -+ (key->offset < BTRFS_FIRST_FREE_OBJECTID || -+ key->offset > BTRFS_LAST_FREE_OBJECTID))) { -+ inode_ref_err(leaf, slot, -+ "invalid offset for ref key, have %llu expect [%llu, %lld]", -+ key->offset, BTRFS_FIRST_FREE_OBJECTID, -+ BTRFS_LAST_FREE_OBJECTID); -+ return -EUCLEAN; -+ } -+ - ptr = btrfs_item_ptr_offset(leaf, slot); - end = ptr + btrfs_item_size(leaf, slot); - while (ptr < end) { -@@ -1952,12 +1962,14 @@ static int check_inode_extref(struct extent_buffer *leaf, - { - unsigned long ptr = btrfs_item_ptr_offset(leaf, slot); - unsigned long end = ptr + btrfs_item_size(leaf, slot); -+ const bool is_fstree = btrfs_is_fstree(btrfs_header_owner(leaf)); - - if (unlikely(!check_prev_ino(leaf, key, slot, prev_key))) - return -EUCLEAN; - - while (ptr < end) { - struct btrfs_inode_extref *extref = (struct btrfs_inode_extref *)ptr; -+ u64 parent; - u16 namelen; - - if (unlikely(ptr + sizeof(*extref) > end)) { -@@ -1967,7 +1979,24 @@ static int check_inode_extref(struct extent_buffer *leaf, - return -EUCLEAN; - } - -+ parent = btrfs_inode_extref_parent(leaf, extref); -+ if (unlikely(is_fstree && (parent < BTRFS_FIRST_FREE_OBJECTID || -+ parent > BTRFS_LAST_FREE_OBJECTID))) { -+ inode_ref_err(leaf, slot, -+ "invalid parent for extref key, have %llu expect [%llu, %lld]", -+ parent, BTRFS_FIRST_FREE_OBJECTID, -+ BTRFS_LAST_FREE_OBJECTID); -+ return -EUCLEAN; -+ } -+ - namelen = btrfs_inode_extref_name_len(leaf, extref); -+ if (unlikely(namelen == 0 || namelen > BTRFS_NAME_LEN)) { -+ inode_ref_err(leaf, slot, -+ "invalid inode extref name length, has %u expect [1, %u]", -+ namelen, BTRFS_NAME_LEN); -+ return -EUCLEAN; -+ } -+ - if (unlikely(ptr + sizeof(*extref) + namelen > end)) { - inode_ref_err(leaf, slot, - "inode extref overflow, ptr %lu end %lu namelen %u", diff --git a/kernel/0303-btrfs-fixes-2.patch.sig b/kernel/0303-btrfs-fixes-2.patch.sig deleted file mode 100644 index 705b8ba..0000000 Binary files a/kernel/0303-btrfs-fixes-2.patch.sig and /dev/null differ diff --git a/kernel/0304-btrfs-fixes-3.patch b/kernel/0304-btrfs-fixes-3.patch deleted file mode 100644 index 7d1ab48..0000000 --- a/kernel/0304-btrfs-fixes-3.patch +++ /dev/null @@ -1,77 +0,0 @@ -diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c ---- a/fs/btrfs/tree-checker.c -+++ b/fs/btrfs/tree-checker.c -@@ -2306,7 +2306,7 @@ static int check_free_space_extent(struct extent_buffer *leaf, struct btrfs_key - - if (unlikely(btrfs_item_size(leaf, slot) != 0)) { - generic_err(leaf, slot, -- "invalid item size for free space info, has %u expect 0", -+ "invalid item size for free space extent, has %u expect 0", - btrfs_item_size(leaf, slot)); - return -EUCLEAN; - } -diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c ---- a/fs/btrfs/volumes.c -+++ b/fs/btrfs/volumes.c -@@ -740,6 +740,36 @@ const u8 *btrfs_sb_fsid_ptr(const struct btrfs_super_block *sb) - return has_metadata_uuid ? sb->metadata_uuid : sb->fsid; - } - -+static bool should_rename_device(const struct btrfs_device *dev) -+{ -+ bool ret; -+ const char *old_name; -+ -+ rcu_read_lock(); -+ old_name = rcu_dereference(dev->name); -+ /* -+ * For systems booted without an initramfs, the rootfs has the device -+ * name "/dev/root". -+ * -+ * Although using btrfs without an initramfs is not recommended (if a -+ * new device is added to the rootfs, the system can no longer boot, as -+ * there is no way to register all devices), there is still a minority -+ * of users doing this. -+ * -+ * And after the system is up, a later device scan on the real block -+ * device file will never get this device's name updated, as the -+ * device->devt is still the same. -+ * -+ * Here we add one and only one exception for "/dev/root", to allow the -+ * device name to be updated even if the new path points to the same -+ * block device. -+ */ -+ ret = (strcmp(old_name, "/dev/root") == 0); -+ rcu_read_unlock(); -+ -+ return ret; -+} -+ - /* - * Add new device to list of registered devices - * -@@ -860,7 +890,8 @@ static noinline struct btrfs_device *device_list_add(const char *path, - MAJOR(path_devt), MINOR(path_devt), - current->comm, task_pid_nr(current)); - -- } else if (!device->name || device->devt != path_devt) { -+ } else if (!device->name || device->devt != path_devt || -+ should_rename_device(device)) { - const char *old_name; - - /* -diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c ---- a/fs/btrfs/zoned.c -+++ b/fs/btrfs/zoned.c -@@ -2688,6 +2688,11 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags) - - switch (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) { - case 0: /* single */ -+ case BTRFS_BLOCK_GROUP_RAID0: -+ case BTRFS_BLOCK_GROUP_RAID1: -+ case BTRFS_BLOCK_GROUP_RAID1C3: -+ case BTRFS_BLOCK_GROUP_RAID1C4: -+ case BTRFS_BLOCK_GROUP_RAID10: - ret = (atomic_read(&zinfo->active_zones_left) >= (1 + reserved)); - break; - case BTRFS_BLOCK_GROUP_DUP: diff --git a/kernel/0304-btrfs-fixes-3.patch.sig b/kernel/0304-btrfs-fixes-3.patch.sig deleted file mode 100644 index 3e983dc..0000000 Binary files a/kernel/0304-btrfs-fixes-3.patch.sig and /dev/null differ diff --git a/kernel/0310-fuse-eof-zeroing.patch b/kernel/0310-fuse-eof-zeroing.patch deleted file mode 100644 index 38a6427..0000000 --- a/kernel/0310-fuse-eof-zeroing.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c ---- a/fs/fuse/dir.c -+++ b/fs/fuse/dir.c -@@ -2289,6 +2289,9 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry, - */ - if ((is_truncate || !is_wb) && - S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { -+ if (outarg.attr.size > oldsize) -+ truncate_pagecache_range(inode, oldsize, -+ outarg.attr.size - 1); - truncate_pagecache(inode, outarg.attr.size); - invalidate_inode_pages2(mapping); - } -diff --git a/fs/fuse/file.c b/fs/fuse/file.c ---- a/fs/fuse/file.c -+++ b/fs/fuse/file.c -@@ -1360,9 +1360,13 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii) - struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_inode *fi = get_fuse_inode(inode); - loff_t pos = iocb->ki_pos; -+ loff_t old_size = i_size_read(inode); - int err = 0; - ssize_t res = 0; - -+ if (pos > old_size) -+ truncate_pagecache_range(inode, old_size, pos - 1); -+ - if (inode->i_size < pos + iov_iter_count(ii)) - set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); - -@@ -2909,6 +2913,11 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, - - /* we could have extended the file */ - if (!(mode & FALLOC_FL_KEEP_SIZE)) { -+ loff_t oldsize = i_size_read(inode); -+ -+ if (offset + length > oldsize) -+ truncate_pagecache_range(inode, oldsize, -+ offset + length - 1); - if (fuse_write_update_attr(inode, offset + length, length)) - file_update_time(file); - } diff --git a/kernel/0310-fuse-eof-zeroing.patch.sig b/kernel/0310-fuse-eof-zeroing.patch.sig deleted file mode 100644 index 79483f9..0000000 Binary files a/kernel/0310-fuse-eof-zeroing.patch.sig and /dev/null differ diff --git a/kernel/0311-fuse-perf.patch b/kernel/0311-fuse-perf.patch deleted file mode 100644 index ca3c02a..0000000 --- a/kernel/0311-fuse-perf.patch +++ /dev/null @@ -1,104 +0,0 @@ -diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c ---- a/fs/fuse/dev.c -+++ b/fs/fuse/dev.c -@@ -213,10 +213,13 @@ EXPORT_SYMBOL_GPL(fuse_req_hash); - /* - * A new request is available, wake fiq->waitq - */ --static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq) -+static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq, bool sync) - __releases(fiq->lock) - { -- wake_up(&fiq->waitq); -+ if (sync) -+ wake_up_sync(&fiq->waitq); -+ else -+ wake_up(&fiq->waitq); - kill_fasync(&fiq->fasync, SIGIO, POLL_IN); - spin_unlock(&fiq->lock); - } -@@ -233,7 +236,7 @@ void fuse_dev_queue_forget(struct fuse_iqueue *fiq, - if (fiq->connected) { - fiq->forget_list_tail->next = forget; - fiq->forget_list_tail = forget; -- fuse_dev_wake_and_unlock(fiq); -+ fuse_dev_wake_and_unlock(fiq, false); - } else { - kfree(forget); - spin_unlock(&fiq->lock); -@@ -255,7 +258,7 @@ void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req) - list_del_init(&req->intr_entry); - spin_unlock(&fiq->lock); - } else { -- fuse_dev_wake_and_unlock(fiq); -+ fuse_dev_wake_and_unlock(fiq, false); - } - } else { - spin_unlock(&fiq->lock); -@@ -285,11 +288,13 @@ EXPORT_SYMBOL_GPL(fuse_request_assign_unique); - - static void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req) - { -+ bool sync = test_and_clear_bit(FR_SYNC_WAKEUP, &req->flags); -+ - spin_lock(&fiq->lock); - if (fiq->connected) { - fuse_request_assign_unique_locked(fiq, req); - list_add_tail(&req->list, &fiq->pending); -- fuse_dev_wake_and_unlock(fiq); -+ fuse_dev_wake_and_unlock(fiq, sync); - } else { - spin_unlock(&fiq->lock); - req->out.h.error = -ENOTCONN; -@@ -752,6 +757,11 @@ static void __fuse_request_send(struct fuse_req *req) - /* acquire extra reference, since request is still needed after - fuse_request_end() */ - __fuse_get_request(req); -+ /* -+ * This is a synchronous request: the caller will block waiting for -+ * the answer. Hint the scheduler via wake_up_sync(). -+ */ -+ set_bit(FR_SYNC_WAKEUP, &req->flags); - fuse_send_one(fiq, req); - - request_wait_answer(req); -@@ -1806,7 +1816,7 @@ void fuse_chan_resend(struct fuse_chan *fch) - } - /* iq and pq requests are both oldest to newest */ - list_splice(&to_queue, &fiq->pending); -- fuse_dev_wake_and_unlock(fiq); -+ fuse_dev_wake_and_unlock(fiq, false); - } - - /* Look up request on processing list by unique ID */ -diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h ---- a/fs/fuse/fuse_dev_i.h -+++ b/fs/fuse/fuse_dev_i.h -@@ -38,6 +38,8 @@ struct fuse_iqueue; - * @FR_PRIVATE: request is on private list - * @FR_ASYNC: request is asynchronous - * @FR_URING: request is handled through fuse-io-uring -+ * @FR_SYNC_WAKEUP: use synchronous wakeup when queueing this request to -+ * give the scheduler a hint about the waker task - */ - enum fuse_req_flag { - FR_ISREPLY, -@@ -53,6 +55,7 @@ enum fuse_req_flag { - FR_PRIVATE, - FR_ASYNC, - FR_URING, -+ FR_SYNC_WAKEUP, - }; - - /** -diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c ---- a/fs/fuse/inode.c -+++ b/fs/fuse/inode.c -@@ -1420,6 +1420,7 @@ static void process_init_reply(struct fuse_args *args, int error) - - fm->sb->s_bdi->ra_pages = - min(fm->sb->s_bdi->ra_pages, ra_pages); -+ fm->sb->s_bdi->io_pages = fc->max_pages; - fc->minor = arg->minor; - fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; - fc->max_write = max_t(unsigned, 4096, fc->max_write); diff --git a/kernel/0311-fuse-perf.patch.sig b/kernel/0311-fuse-perf.patch.sig deleted file mode 100644 index ef5fe91..0000000 Binary files a/kernel/0311-fuse-perf.patch.sig and /dev/null differ diff --git a/kernel/0312-fuse-writethrough-uptodate.patch b/kernel/0312-fuse-writethrough-uptodate.patch deleted file mode 100644 index 8aaf4c6..0000000 --- a/kernel/0312-fuse-writethrough-uptodate.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff --git a/fs/fuse/file.c b/fs/fuse/file.c ---- a/fs/fuse/file.c -+++ b/fs/fuse/file.c -@@ -1219,8 +1219,7 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia, - struct file *file = iocb->ki_filp; - struct fuse_file *ff = file->private_data; - struct fuse_mount *fm = ff->fm; -- unsigned int offset, i; -- bool short_write; -+ unsigned int i; - int err; - - for (i = 0; i < ap->num_folios; i++) -@@ -1235,24 +1234,9 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia, - if (!err && ia->write.out.size > count) - err = -EIO; - -- short_write = ia->write.out.size < count; -- offset = ap->descs[0].offset; -- count = ia->write.out.size; - for (i = 0; i < ap->num_folios; i++) { - struct folio *folio = ap->folios[i]; - -- if (err) { -- folio_clear_uptodate(folio); -- } else { -- if (count >= folio_size(folio) - offset) -- count -= folio_size(folio) - offset; -- else { -- if (short_write) -- folio_clear_uptodate(folio); -- count = 0; -- } -- offset = 0; -- } - if (ia->write.folio_locked && (i == ap->num_folios - 1)) - folio_unlock(folio); - folio_put(folio); diff --git a/kernel/0312-fuse-writethrough-uptodate.patch.sig b/kernel/0312-fuse-writethrough-uptodate.patch.sig deleted file mode 100644 index bd3d135..0000000 Binary files a/kernel/0312-fuse-writethrough-uptodate.patch.sig and /dev/null differ diff --git a/kernel/0313-fuse-background-wakeup.patch b/kernel/0313-fuse-background-wakeup.patch deleted file mode 100644 index 27fbcdc..0000000 --- a/kernel/0313-fuse-background-wakeup.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c ---- a/fs/fuse/dev.c -+++ b/fs/fuse/dev.c -@@ -406,7 +406,8 @@ void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val) - fch->max_background = val; - fch->blocked = fch->num_background >= fch->max_background; - if (!fch->blocked) -- wake_up(&fch->blocked_waitq); -+ wake_up_nr(&fch->blocked_waitq, -+ fch->max_background - fch->num_background); - spin_unlock(&fch->bg_lock); - } - diff --git a/kernel/0313-fuse-background-wakeup.patch.sig b/kernel/0313-fuse-background-wakeup.patch.sig deleted file mode 100644 index a8e53e8..0000000 Binary files a/kernel/0313-fuse-background-wakeup.patch.sig and /dev/null differ diff --git a/kernel/0320-vfs-open-consume-path-reference.patch b/kernel/0320-vfs-open-consume-path-reference.patch deleted file mode 100644 index eba1599..0000000 --- a/kernel/0320-vfs-open-consume-path-reference.patch +++ /dev/null @@ -1,119 +0,0 @@ -diff --git a/fs/internal.h b/fs/internal.h ---- a/fs/internal.h -+++ b/fs/internal.h -@@ -204,6 +204,7 @@ int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group, - int flag); - int chown_common(const struct path *path, uid_t user, gid_t group); - extern int vfs_open(const struct path *, struct file *); -+int vfs_open_consume(struct path *, struct file *); - - /* - * inode.c -diff --git a/fs/namei.c b/fs/namei.c ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -4652,6 +4652,7 @@ static const char *open_last_lookups(struct nameidata *nd, - static int do_open(struct nameidata *nd, - struct file *file, const struct open_flags *op) - { -+ struct vfsmount *mnt; - struct mnt_idmap *idmap; - int open_flag = op->open_flag; - bool do_truncate; -@@ -4693,11 +4694,17 @@ static int do_open(struct nameidata *nd, - error = mnt_want_write(nd->path.mnt); - if (error) - return error; -+ /* -+ * A dedicated reference is needed because after the call to -+ * vfs_open_consume() we no longer own the reference in nd->path.mnt -+ * while we need to undo write acess below. -+ */ -+ mnt = mntget(nd->path.mnt); - do_truncate = true; - } - error = may_open(idmap, &nd->path, acc_mode, open_flag); - if (!error && !(file->f_mode & FMODE_OPENED)) -- error = vfs_open(&nd->path, file); -+ error = vfs_open_consume(&nd->path, file); - if (!error) - error = security_file_post_open(file, op->acc_mode); - if (!error && do_truncate) -@@ -4706,8 +4713,10 @@ static int do_open(struct nameidata *nd, - WARN_ON(1); - error = -EINVAL; - } -- if (do_truncate) -- mnt_drop_write(nd->path.mnt); -+ if (do_truncate) { -+ mnt_drop_write(mnt); -+ mntput(mnt); -+ } - return error; - } - -diff --git a/fs/open.c b/fs/open.c ---- a/fs/open.c -+++ b/fs/open.c -@@ -882,6 +882,11 @@ static inline int file_get_write_access(struct file *f) - return error; - } - -+/* -+ * Populate struct file -+ * -+ * NOTE: it assumes f_path is populated and consumes the caller's reference. -+ */ - static int do_dentry_open(struct file *f, - int (*open)(struct inode *, struct file *)) - { -@@ -889,7 +894,6 @@ static int do_dentry_open(struct file *f, - struct inode *inode = f->f_path.dentry->d_inode; - int error; - -- path_get(&f->f_path); - f->f_inode = inode; - f->f_mapping = inode->i_mapping; - f->f_wb_err = filemap_sample_wb_err(f->f_mapping); -@@ -1006,6 +1010,7 @@ int finish_open(struct file *file, struct dentry *dentry, - BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */ - - file->__f_path.dentry = dentry; -+ path_get(&file->f_path); - return do_dentry_open(file, open); - } - EXPORT_SYMBOL(finish_open); -@@ -1049,6 +1054,7 @@ int vfs_open(const struct path *path, struct file *file) - int ret; - - file->__f_path = *path; -+ path_get(&file->f_path); - ret = do_dentry_open(file, NULL); - if (!ret) { - /* -@@ -1061,6 +1067,25 @@ int vfs_open(const struct path *path, struct file *file) - return ret; - } - -+/** -+ * vfs_open_consume - open the file at the given path and consume the reference -+ * @path: path to open -+ * @file: newly allocated file with f_flag initialized -+ */ -+int vfs_open_consume(struct path *path, struct file *file) -+{ -+ int ret; -+ -+ file->__f_path = *path; -+ path->mnt = NULL; -+ path->dentry = NULL; -+ ret = do_dentry_open(file, NULL); -+ if (!ret) { -+ fsnotify_open(file); -+ } -+ return ret; -+} -+ - struct file *dentry_open(const struct path *path, int flags, - const struct cred *cred) - { diff --git a/kernel/0320-vfs-open-consume-path-reference.patch.sig b/kernel/0320-vfs-open-consume-path-reference.patch.sig deleted file mode 100644 index 74dd333..0000000 Binary files a/kernel/0320-vfs-open-consume-path-reference.patch.sig and /dev/null differ diff --git a/kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch b/kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch deleted file mode 100644 index 9a8f97f..0000000 --- a/kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch +++ /dev/null @@ -1,123 +0,0 @@ -diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h -index 4590d6a3d821..dbdc2053332d 100644 ---- a/drivers/gpu/drm/drm_displayid_internal.h -+++ b/drivers/gpu/drm/drm_displayid_internal.h -@@ -67,6 +67,7 @@ struct drm_edid; - #define DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY 0x28 - #define DATA_BLOCK_2_CONTAINER_ID 0x29 - #define DATA_BLOCK_2_TYPE_10_FORMULA_TIMING 0x2a -+#define DATA_BLOCK_2_ADAPTIVE_SYNC 0x2b - #define DATA_BLOCK_2_VENDOR_SPECIFIC 0x7e - #define DATA_BLOCK_2_CTA_DISPLAY_ID 0x81 - -diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c -index df3c25bac761..354d4ff1aff7 100644 ---- a/drivers/gpu/drm/drm_edid.c -+++ b/drivers/gpu/drm/drm_edid.c -@@ -6598,6 +6598,49 @@ static void drm_get_monitor_range(struct drm_connector *connector, - info->monitor_range.min_vfreq, info->monitor_range.max_vfreq); - } - -+#define DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE 6 -+ -+static bool drm_update_displayid_adaptive_sync_range(struct drm_connector *connector, -+ const struct displayid_block *block) -+{ -+ struct drm_monitor_range_info *range = &connector->display_info.monitor_range; -+ const u8 *data = (const u8 *)(block + 1); -+ u16 best_min = 0, best_max = 0; -+ unsigned int best_span = 0; -+ int i; -+ -+ if (block->rev != 0 || block->num_bytes < DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE || -+ block->num_bytes % DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE) -+ return false; -+ -+ for (i = 0; i < block->num_bytes; i += DISPLAYID_ADAPTIVE_SYNC_DESC_SIZE) { -+ const u8 *desc = &data[i]; -+ u16 min_vfreq = desc[2]; -+ u16 max_vfreq = ((((u16)desc[4]) & 0x3) << 8) | desc[3]; -+ unsigned int span; -+ -+ max_vfreq += 1; -+ if (!min_vfreq || max_vfreq <= min_vfreq) -+ continue; -+ -+ span = max_vfreq - min_vfreq; -+ if (span <= best_span) -+ continue; -+ -+ best_min = min_vfreq; -+ best_max = max_vfreq; -+ best_span = span; -+ } -+ -+ if (best_span) { -+ range->min_vfreq = best_min; -+ range->max_vfreq = best_max; -+ return true; -+ } -+ -+ return false; -+} -+ - static void drm_parse_vesa_mso_data(struct drm_connector *connector, - const struct displayid_block *block) - { -@@ -6720,26 +6763,43 @@ static void update_displayid_info(struct drm_connector *connector, - { - struct drm_display_info *info = &connector->display_info; - const struct displayid_block *block; -+ bool adaptive_sync_range = false; -+ bool displayid_base_logged = false; - struct displayid_iter iter; - - displayid_iter_edid_begin(drm_edid, &iter); - displayid_iter_for_each(block, &iter) { -- drm_dbg_kms(connector->dev, -- "[CONNECTOR:%d:%s] DisplayID extension version 0x%02x, primary use 0x%02x\n", -- connector->base.id, connector->name, -- displayid_version(&iter), -- displayid_primary_use(&iter)); -- if (displayid_version(&iter) == DISPLAY_ID_STRUCTURE_VER_20 && -- (displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_VR || -- displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_AR)) -- info->non_desktop = true; -- - /* -- * We're only interested in the base section here, no need to -- * iterate further. -+ * Primary use is a DisplayID base section property, but later -+ * blocks may still carry useful metadata like adaptive sync ranges. - */ -- break; -+ if (!displayid_base_logged) { -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] DisplayID extension version 0x%02x, primary use 0x%02x\n", -+ connector->base.id, connector->name, -+ displayid_version(&iter), -+ displayid_primary_use(&iter)); -+ if (displayid_version(&iter) == DISPLAY_ID_STRUCTURE_VER_20 && -+ (displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_VR || -+ displayid_primary_use(&iter) == PRIMARY_USE_HEAD_MOUNTED_AR)) -+ info->non_desktop = true; -+ -+ displayid_base_logged = true; -+ } -+ -+ if (!info->monitor_range.min_vfreq && !info->monitor_range.max_vfreq && -+ block->tag == DATA_BLOCK_2_ADAPTIVE_SYNC) -+ adaptive_sync_range = -+ drm_update_displayid_adaptive_sync_range(connector, block); - } -+ -+ if (adaptive_sync_range) -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] DisplayID adaptive sync refresh rate range is %d Hz - %d Hz\n", -+ connector->base.id, connector->name, -+ info->monitor_range.min_vfreq, -+ info->monitor_range.max_vfreq); -+ - displayid_iter_end(&iter); - } - diff --git a/kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch.sig b/kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch.sig deleted file mode 100644 index a00bf83..0000000 Binary files a/kernel/0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch.sig and /dev/null differ diff --git a/kernel/0360-gpu-mem-cgroup.patch b/kernel/0360-gpu-mem-cgroup.patch deleted file mode 100644 index 278fc0c..0000000 --- a/kernel/0360-gpu-mem-cgroup.patch +++ /dev/null @@ -1,601 +0,0 @@ -diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c ---- a/drivers/gpu/drm/nouveau/nouveau_ttm.c -+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c -@@ -188,6 +188,11 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm) - - man->func = &nouveau_vram_manager; - -+ man->cg = drmm_cgroup_register_region(drm->dev, "vram", -+ drm->gem.vram_available); -+ if (IS_ERR(man->cg)) -+ return PTR_ERR(man->cg); -+ - ttm_resource_manager_init(man, &drm->ttm.bdev, - drm->gem.vram_available >> PAGE_SHIFT); - ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man); -diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c ---- a/drivers/gpu/drm/ttm/ttm_bo.c -+++ b/drivers/gpu/drm/ttm/ttm_bo.c -@@ -488,6 +488,118 @@ int ttm_bo_evict_first(struct ttm_device *bdev, struct ttm_resource_manager *man - return ret; - } - -+struct ttm_bo_alloc_state { -+ /** @charge_pool: The memory pool the resource is charged to */ -+ struct dmem_cgroup_pool_state *charge_pool; -+ /** @limit_pool: Which pool limit we should test against */ -+ struct dmem_cgroup_pool_state *limit_pool; -+ /** @in_evict: Whether we are currently evicting buffers */ -+ bool in_evict; -+ /** @may_try_low: If only unprotected BOs, i.e. BOs whose cgroup -+ * is exceeding its dmem low/min protection, should be considered for eviction -+ */ -+ bool may_try_low; -+}; -+ -+/** -+ * ttm_bo_alloc_at_place - Attempt allocating a BO's backing store in a place -+ * -+ * @bo: The buffer to allocate the backing store of -+ * @place: The place to attempt allocation in -+ * @ctx: ttm_operation_ctx associated with this allocation -+ * @force_space: If we should evict buffers to force space -+ * @res: On allocation success, the resulting struct ttm_resource. -+ * @alloc_state: Object holding allocation state such as charged cgroups. -+ * -+ * Returns: -+ * -EBUSY: No space available, but allocation should be retried with ttm_bo_evict_alloc. -+ * -ENOSPC: No space available, allocation should not be retried. -+ * -ERESTARTSYS: An interruptible sleep was interrupted by a signal. -+ * -+ */ -+static int ttm_bo_alloc_at_place(struct ttm_buffer_object *bo, -+ const struct ttm_place *place, -+ bool force_space, -+ struct ttm_resource **res, -+ struct ttm_bo_alloc_state *alloc_state) -+{ -+ bool may_evict; -+ int ret; -+ -+ may_evict = !alloc_state->in_evict && force_space && -+ place->mem_type != TTM_PL_SYSTEM; -+ if (!alloc_state->charge_pool) { -+ ret = ttm_resource_try_charge(bo, place, &alloc_state->charge_pool, -+ force_space ? &alloc_state->limit_pool -+ : NULL); -+ if (ret) { -+ /* -+ * -EAGAIN means the charge failed, which we treat -+ * like an allocation failure. Therefore, return an -+ * error code indicating the allocation failed - -+ * either -EBUSY if the allocation should be -+ * retried with eviction, or -ENOSPC if there should -+ * be no second attempt. -+ */ -+ if (!alloc_state->in_evict) -+ alloc_state->may_try_low = may_evict; -+ if (ret == -EAGAIN) -+ ret = may_evict ? -EBUSY : -ENOSPC; -+ return ret; -+ } -+ } -+ -+ /* -+ * cgroup protection plays a special role in eviction. -+ * Conceptually, protection of memory via the dmem cgroup controller -+ * entitles the protected cgroup to use a certain amount of memory. -+ * There are two types of protection - the 'low' limit is a -+ * "best-effort" protection, whereas the 'min' limit provides a hard -+ * guarantee that memory within the cgroup's allowance will not be -+ * evicted under any circumstance. -+ * -+ * To faithfully model this concept in TTM, we also need to take cgroup -+ * protection into account when allocating. When allocation in one -+ * place fails, TTM will default to trying other places first before -+ * evicting. -+ * If the allocation is covered by dmem cgroup protection, however, -+ * this prevents the allocation from using the memory it is "entitled" -+ * to. To make sure unprotected allocations cannot push new protected -+ * allocations out of places they are "entitled" to use, we should -+ * evict buffers not covered by any cgroup protection, if this -+ * allocation is covered by cgroup protection. -+ * -+ * Buffers covered by 'min' protection are a special case - the 'min' -+ * limit is a stronger guarantee than 'low', and thus buffers protected -+ * by 'low' but not 'min' should also be considered for eviction. -+ * Buffers protected by 'min' will never be considered for eviction -+ * anyway, so the regular eviction path should be triggered here. -+ * Buffers protected by 'low' but not 'min' will take a special -+ * eviction path that only evicts buffers covered by neither 'low' or -+ * 'min' protections. -+ */ -+ if (!alloc_state->in_evict) { -+ may_evict |= dmem_cgroup_below_min(NULL, alloc_state->charge_pool); -+ alloc_state->may_try_low = may_evict; -+ -+ may_evict |= dmem_cgroup_below_low(NULL, alloc_state->charge_pool); -+ } -+ -+ ret = ttm_resource_alloc(bo, place, res, alloc_state->charge_pool); -+ if (ret) { -+ if (ret == -ENOSPC && may_evict) -+ ret = -EBUSY; -+ return ret; -+ } -+ -+ /* -+ * Ownership of charge_pool has been transferred to the TTM resource, -+ * don't make the caller think we still hold a reference to it. -+ */ -+ alloc_state->charge_pool = NULL; -+ return 0; -+} -+ - /** - * struct ttm_bo_evict_walk - Parameters for the evict walk. - */ -@@ -503,22 +615,61 @@ struct ttm_bo_evict_walk { - /** @evicted: Number of successful evictions. */ - unsigned long evicted; - -- /** @limit_pool: Which pool limit we should test against */ -- struct dmem_cgroup_pool_state *limit_pool; - /** @try_low: Whether we should attempt to evict BO's with low watermark threshold */ - bool try_low; - /** @hit_low: If we cannot evict a bo when @try_low is false (first pass) */ - bool hit_low; -+ -+ /** @alloc_state: State associated with the allocation attempt. */ -+ struct ttm_bo_alloc_state *alloc_state; - }; - - static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo) - { - struct ttm_bo_evict_walk *evict_walk = - container_of(walk, typeof(*evict_walk), walk); -+ struct dmem_cgroup_pool_state *limit_pool, *ancestor = NULL; -+ bool evict_valuable; - s64 lret; - -- if (!dmem_cgroup_state_evict_valuable(evict_walk->limit_pool, bo->resource->css, -- evict_walk->try_low, &evict_walk->hit_low)) -+ /* -+ * If may_try_low is not set, then we're trying to evict unprotected -+ * buffers in favor of a protected allocation for charge_pool. Explicitly skip -+ * buffers belonging to the same cgroup here - that cgroup is definitely protected, -+ * even though dmem_cgroup_state_evict_valuable would allow the eviction because a -+ * cgroup is always allowed to evict from itself even if it is protected. -+ */ -+ if (!evict_walk->alloc_state->may_try_low && -+ bo->resource->css == evict_walk->alloc_state->charge_pool) -+ return 0; -+ -+ limit_pool = evict_walk->alloc_state->limit_pool; -+ /* -+ * If there is no explicit limit pool, find the root of the shared subtree between -+ * evictor and evictee. This is important so that recursive protection rules can -+ * apply properly: Recursive protection distributes cgroup protection afforded -+ * to a parent cgroup but not used explicitly by a child cgroup between all child -+ * cgroups (see docs of effective_protection in mm/page_counter.c). However, when -+ * direct siblings compete for memory, siblings that were explicitly protected -+ * should get prioritized over siblings that weren't. This only happens correctly -+ * when the root of the shared subtree is passed to -+ * dmem_cgroup_state_evict_valuable. Otherwise, the effective-protection -+ * calculation cannot distinguish direct siblings from unrelated subtrees and the -+ * calculated protection ends up wrong. -+ */ -+ if (!limit_pool) { -+ ancestor = dmem_cgroup_get_common_ancestor(bo->resource->css, -+ evict_walk->alloc_state->charge_pool); -+ limit_pool = ancestor; -+ } -+ -+ evict_valuable = dmem_cgroup_state_evict_valuable(limit_pool, bo->resource->css, -+ evict_walk->try_low, -+ &evict_walk->hit_low); -+ if (ancestor) -+ dmem_cgroup_pool_state_put(ancestor); -+ -+ if (!evict_valuable) - return 0; - - if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place)) -@@ -537,8 +688,10 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object * - - evict_walk->evicted++; - if (evict_walk->res) -- lret = ttm_resource_alloc(evict_walk->evictor, evict_walk->place, -- evict_walk->res, NULL); -+ lret = ttm_bo_alloc_at_place(evict_walk->evictor, -+ evict_walk->place, false, -+ evict_walk->res, -+ evict_walk->alloc_state); - if (lret == 0) - return 1; - out: -@@ -560,7 +713,7 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev, - struct ttm_operation_ctx *ctx, - struct ww_acquire_ctx *ticket, - struct ttm_resource **res, -- struct dmem_cgroup_pool_state *limit_pool) -+ struct ttm_bo_alloc_state *state) - { - struct ttm_bo_evict_walk evict_walk = { - .walk = { -@@ -573,15 +726,21 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev, - .place = place, - .evictor = evictor, - .res = res, -- .limit_pool = limit_pool, -+ .alloc_state = state, - }; - s64 lret; - -+ state->in_evict = true; -+ - evict_walk.walk.arg.trylock_only = true; - lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1); - -- /* One more attempt if we hit low limit? */ -- if (!lret && evict_walk.hit_low) { -+ /* If we failed to find enough BOs to evict, but we skipped over -+ * some BOs because they were covered by dmem low protection, retry -+ * evicting these protected BOs too, except if we're told not to -+ * consider protected BOs at all. -+ */ -+ if (!lret && evict_walk.hit_low && state->may_try_low) { - evict_walk.try_low = true; - lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1); - } -@@ -602,11 +761,13 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev, - } while (!lret && evict_walk.evicted); - - /* We hit the low limit? Try once more */ -- if (!lret && evict_walk.hit_low && !evict_walk.try_low) { -+ if (!lret && evict_walk.hit_low && !evict_walk.try_low && -+ state->may_try_low) { - evict_walk.try_low = true; - goto retry; - } - out: -+ state->in_evict = false; - if (lret < 0) - return lret; - if (lret == 0) -@@ -724,9 +885,8 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo, - - for (i = 0; i < placement->num_placement; ++i) { - const struct ttm_place *place = &placement->placement[i]; -- struct dmem_cgroup_pool_state *limit_pool = NULL; -+ struct ttm_bo_alloc_state alloc_state = {}; - struct ttm_resource_manager *man; -- bool may_evict; - - man = ttm_manager_type(bdev, place->mem_type); - if (!man || !ttm_resource_manager_used(man)) -@@ -736,25 +896,30 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo, - TTM_PL_FLAG_FALLBACK)) - continue; - -- may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM); -- ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL); -- if (ret) { -- if (ret != -ENOSPC) { -- dmem_cgroup_pool_state_put(limit_pool); -- return ret; -- } -- if (!may_evict) { -- dmem_cgroup_pool_state_put(limit_pool); -- continue; -- } -+ ret = ttm_bo_alloc_at_place(bo, place, force_space, res, -+ &alloc_state); - -+ if (ret == -ENOSPC) { -+ dmem_cgroup_uncharge(alloc_state.charge_pool, bo->base.size); -+ dmem_cgroup_pool_state_put(alloc_state.limit_pool); -+ continue; -+ } else if (ret == -EBUSY) { - ret = ttm_bo_evict_alloc(bdev, man, place, bo, ctx, -- ticket, res, limit_pool); -- dmem_cgroup_pool_state_put(limit_pool); -- if (ret == -EBUSY) -- continue; -- if (ret) -+ ticket, res, &alloc_state); -+ -+ dmem_cgroup_pool_state_put(alloc_state.limit_pool); -+ -+ if (ret) { -+ dmem_cgroup_uncharge(alloc_state.charge_pool, -+ bo->base.size); -+ if (ret == -EBUSY) -+ continue; - return ret; -+ } -+ } else if (ret) { -+ dmem_cgroup_uncharge(alloc_state.charge_pool, bo->base.size); -+ dmem_cgroup_pool_state_put(alloc_state.limit_pool); -+ return ret; - } - - ret = ttm_bo_add_pipelined_eviction_fences(bo, man, ctx->no_wait_gpu); -diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c ---- a/drivers/gpu/drm/ttm/ttm_resource.c -+++ b/drivers/gpu/drm/ttm/ttm_resource.c -@@ -386,33 +386,52 @@ void ttm_resource_fini(struct ttm_resource_manager *man, - } - EXPORT_SYMBOL(ttm_resource_fini); - -+/** -+ * ttm_resource_try_charge - charge a resource manager's cgroup pool -+ * @bo: buffer for which an allocation should be charged -+ * @place: where the allocation is attempted to be placed -+ * @ret_pool: on charge success, the pool that was charged -+ * @ret_limit_pool: on charge failure, the pool responsible for the failure -+ * -+ * Should be used to charge cgroups before attempting resource allocation. -+ * When charging succeeds, the value of ret_pool should be passed to -+ * ttm_resource_alloc. -+ * -+ * Returns: 0 on charge success, negative errno on failure. -+ */ -+int ttm_resource_try_charge(struct ttm_buffer_object *bo, -+ const struct ttm_place *place, -+ struct dmem_cgroup_pool_state **ret_pool, -+ struct dmem_cgroup_pool_state **ret_limit_pool) -+{ -+ struct ttm_resource_manager *man = -+ ttm_manager_type(bo->bdev, place->mem_type); -+ -+ if (!man->cg) { -+ *ret_pool = NULL; -+ if (ret_limit_pool) -+ *ret_limit_pool = NULL; -+ return 0; -+ } -+ -+ return dmem_cgroup_try_charge(man->cg, bo->base.size, ret_pool, -+ ret_limit_pool); -+} -+ - int ttm_resource_alloc(struct ttm_buffer_object *bo, - const struct ttm_place *place, - struct ttm_resource **res_ptr, -- struct dmem_cgroup_pool_state **ret_limit_pool) -+ struct dmem_cgroup_pool_state *charge_pool) - { - struct ttm_resource_manager *man = - ttm_manager_type(bo->bdev, place->mem_type); -- struct dmem_cgroup_pool_state *pool = NULL; - int ret; - -- if (man->cg) { -- ret = dmem_cgroup_try_charge(man->cg, bo->base.size, &pool, ret_limit_pool); -- if (ret) { -- if (ret == -EAGAIN) -- ret = -ENOSPC; -- return ret; -- } -- } -- - ret = man->func->alloc(man, bo, place, res_ptr); -- if (ret) { -- if (pool) -- dmem_cgroup_uncharge(pool, bo->base.size); -+ if (ret) - return ret; -- } - -- (*res_ptr)->css = pool; -+ (*res_ptr)->css = charge_pool; - - spin_lock(&bo->bdev->lru_lock); - ttm_resource_add_bulk_move(*res_ptr, bo); -diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h ---- a/include/drm/ttm/ttm_resource.h -+++ b/include/drm/ttm/ttm_resource.h -@@ -458,10 +458,14 @@ void ttm_resource_init(struct ttm_buffer_object *bo, - void ttm_resource_fini(struct ttm_resource_manager *man, - struct ttm_resource *res); - -+int ttm_resource_try_charge(struct ttm_buffer_object *bo, -+ const struct ttm_place *place, -+ struct dmem_cgroup_pool_state **ret_pool, -+ struct dmem_cgroup_pool_state **ret_limit_pool); - int ttm_resource_alloc(struct ttm_buffer_object *bo, - const struct ttm_place *place, - struct ttm_resource **res, -- struct dmem_cgroup_pool_state **ret_limit_pool); -+ struct dmem_cgroup_pool_state *charge_pool); - void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res); - bool ttm_resource_intersects(struct ttm_device *bdev, - struct ttm_resource *res, -diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h ---- a/include/linux/cgroup.h -+++ b/include/linux/cgroup.h -@@ -623,6 +623,27 @@ static inline struct cgroup *cgroup_ancestor(struct cgroup *cgrp, - return cgrp->ancestors[ancestor_level]; - } - -+/** -+ * cgroup_common_ancestor - find common ancestor of two cgroups -+ * @a: first cgroup to find common ancestor of -+ * @b: second cgroup to find common ancestor of -+ * -+ * Find the first cgroup that is an ancestor of both @a and @b, if it exists -+ * and return a pointer to it. If such a cgroup doesn't exist, return NULL. -+ * -+ * This function is safe to call as long as both @a and @b are accessible. -+ */ -+static inline struct cgroup *cgroup_common_ancestor(struct cgroup *a, -+ struct cgroup *b) -+{ -+ int level; -+ -+ for (level = min(a->level, b->level); level >= 0; level--) -+ if (a->ancestors[level] == b->ancestors[level]) -+ return a->ancestors[level]; -+ return NULL; -+} -+ - /** - * task_under_cgroup_hierarchy - test task's membership of cgroup ancestry - * @task: the task to be tested -diff --git a/include/linux/cgroup_dmem.h b/include/linux/cgroup_dmem.h ---- a/include/linux/cgroup_dmem.h -+++ b/include/linux/cgroup_dmem.h -@@ -24,6 +24,12 @@ void dmem_cgroup_uncharge(struct dmem_cgroup_pool_state *pool, u64 size); - bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool, - struct dmem_cgroup_pool_state *test_pool, - bool ignore_low, bool *ret_hit_low); -+bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root, -+ struct dmem_cgroup_pool_state *test); -+bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, -+ struct dmem_cgroup_pool_state *test); -+struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a, -+ struct dmem_cgroup_pool_state *b); - - void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool); - #else -@@ -59,6 +65,25 @@ bool dmem_cgroup_state_evict_valuable(struct dmem_cgroup_pool_state *limit_pool, - return true; - } - -+static inline bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root, -+ struct dmem_cgroup_pool_state *test) -+{ -+ return false; -+} -+ -+static inline bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, -+ struct dmem_cgroup_pool_state *test) -+{ -+ return false; -+} -+ -+static inline -+struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a, -+ struct dmem_cgroup_pool_state *b) -+{ -+ return NULL; -+} -+ - static inline void dmem_cgroup_pool_state_put(struct dmem_cgroup_pool_state *pool) - { } - -diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c ---- a/kernel/cgroup/dmem.c -+++ b/kernel/cgroup/dmem.c -@@ -695,6 +695,110 @@ int dmem_cgroup_try_charge(struct dmem_cgroup_region *region, u64 size, - } - EXPORT_SYMBOL_GPL(dmem_cgroup_try_charge); - -+/** -+ * dmem_cgroup_below_min() - Tests whether current usage is within min limit. -+ * -+ * @root: Root of the subtree to calculate protection for, or NULL to calculate global protection. -+ * @test: The pool to test the usage/min limit of. -+ * -+ * Return: true if usage is below min and the cgroup is protected, false otherwise. -+ */ -+bool dmem_cgroup_below_min(struct dmem_cgroup_pool_state *root, -+ struct dmem_cgroup_pool_state *test) -+{ -+ if (root == test || !pool_parent(test)) -+ return false; -+ -+ if (!root) { -+ for (root = test; pool_parent(root); root = pool_parent(root)) -+ {} -+ } -+ -+ /* -+ * In mem_cgroup_below_min(), the memcg pendant, this call is missing. -+ * mem_cgroup_below_min() gets called during traversal of the cgroup tree, where -+ * protection is already calculated as part of the traversal. dmem cgroup eviction -+ * does not traverse the cgroup tree, so we need to recalculate effective protection -+ * here. -+ */ -+ dmem_cgroup_calculate_protection(root, test); -+ return page_counter_read(&test->cnt) <= READ_ONCE(test->cnt.emin); -+} -+EXPORT_SYMBOL_GPL(dmem_cgroup_below_min); -+ -+/** -+ * dmem_cgroup_below_low() - Tests whether current usage is within low limit. -+ * -+ * @root: Root of the subtree to calculate protection for, or NULL to calculate global protection. -+ * @test: The pool to test the usage/low limit of. -+ * -+ * Return: true if usage is below low and the cgroup is protected, false otherwise. -+ */ -+bool dmem_cgroup_below_low(struct dmem_cgroup_pool_state *root, -+ struct dmem_cgroup_pool_state *test) -+{ -+ if (root == test || !pool_parent(test)) -+ return false; -+ -+ if (!root) { -+ for (root = test; pool_parent(root); root = pool_parent(root)) -+ {} -+ } -+ -+ /* -+ * In mem_cgroup_below_low(), the memcg pendant, this call is missing. -+ * mem_cgroup_below_low() gets called during traversal of the cgroup tree, where -+ * protection is already calculated as part of the traversal. dmem cgroup eviction -+ * does not traverse the cgroup tree, so we need to recalculate effective protection -+ * here. -+ */ -+ dmem_cgroup_calculate_protection(root, test); -+ return page_counter_read(&test->cnt) <= READ_ONCE(test->cnt.elow); -+} -+EXPORT_SYMBOL_GPL(dmem_cgroup_below_low); -+ -+/** -+ * dmem_cgroup_get_common_ancestor(): Find the first common ancestor of two pools. -+ * @a: First pool to find the common ancestor of. -+ * @b: First pool to find the common ancestor of. -+ * -+ * Return: The first pool that is a parent of both @a and @b, or NULL if either @a or @b are NULL, -+ * or if such a pool does not exist. A reference to the returned pool is grabbed and must be -+ * released by the caller when it is done using the pool. -+ */ -+struct dmem_cgroup_pool_state *dmem_cgroup_get_common_ancestor(struct dmem_cgroup_pool_state *a, -+ struct dmem_cgroup_pool_state *b) -+{ -+ struct cgroup *ancestor_cgroup; -+ struct cgroup_subsys_state *ancestor_css; -+ struct dmemcg_state *ancestor_dmemcs = NULL; -+ struct dmem_cgroup_pool_state *pool = NULL; -+ -+ if (!a || !b) -+ return NULL; -+ -+ ancestor_cgroup = cgroup_common_ancestor(a->cs->css.cgroup, b->cs->css.cgroup); -+ if (!ancestor_cgroup) -+ return NULL; -+ -+ rcu_read_lock(); -+ ancestor_css = cgroup_e_css(ancestor_cgroup, &dmem_cgrp_subsys); -+ if (css_tryget(ancestor_css)) -+ ancestor_dmemcs = css_to_dmemcs(ancestor_css); -+ rcu_read_unlock(); -+ -+ if (ancestor_dmemcs) { -+ pool = get_cg_pool_unlocked(css_to_dmemcs(ancestor_css), -+ a->region); -+ if (WARN_ON(IS_ERR(pool))) { -+ pool = NULL; -+ css_put(ancestor_css); -+ } -+ } -+ return pool; -+} -+EXPORT_SYMBOL_GPL(dmem_cgroup_get_common_ancestor); -+ - static int dmem_cgroup_region_capacity_show(struct seq_file *sf, void *v) - { - struct dmem_cgroup_region *region; diff --git a/kernel/0360-gpu-mem-cgroup.patch.sig b/kernel/0360-gpu-mem-cgroup.patch.sig deleted file mode 100644 index 6e989c6..0000000 Binary files a/kernel/0360-gpu-mem-cgroup.patch.sig and /dev/null differ diff --git a/kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch b/kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch deleted file mode 100644 index 32f3010..0000000 --- a/kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c -index c6963ea420cc..c38d613f15d6 100644 ---- a/drivers/gpu/drm/i915/display/intel_alpm.c -+++ b/drivers/gpu/drm/i915/display/intel_alpm.c -@@ -399,7 +399,7 @@ static void lnl_alpm_configure(struct intel_dp *intel_dp, - ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_50_SYMBOLS | - ALPM_CTL_AUX_LESS_WAKE_TIME(crtc_state->alpm_state.aux_less_wake_lines); - -- if (intel_dp->as_sdp_supported) { -+ if (intel_dp->as_sdp_supported && crtc_state->has_panel_replay) { - u32 pr_alpm_ctl = get_pr_alpm_as_sdp_transmission_time(crtc_state); - - if (crtc_state->link_off_after_as_sdp_when_pr_active) diff --git a/kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch.sig b/kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch.sig deleted file mode 100644 index 80b2f7b..0000000 Binary files a/kernel/0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch.sig and /dev/null differ diff --git a/kernel/0401-psr2-early-transport-panels.patch b/kernel/0401-psr2-early-transport-panels.patch deleted file mode 100644 index 3e88cea..0000000 --- a/kernel/0401-psr2-early-transport-panels.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c -index beaa1d626..5fdf4594c 100644 ---- a/drivers/gpu/drm/i915/display/intel_psr.c -+++ b/drivers/gpu/drm/i915/display/intel_psr.c -@@ -714,8 +714,14 @@ static void _psr_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *co - * To support PSR version 02h and PSR version 03h without - * Y-coordinate requirement panels we would need to enable - * GTC first. -+ * -+ * Early Transport (version 04h) implies Y-coordinate -+ * support. Accept it without explicit Y-coordinate -+ * requirement bit. - */ -- connector->dp.psr_caps.su_support = y_req && -+ connector->dp.psr_caps.su_support = -+ (y_req || connector->dp.psr_caps.dpcd[0] == -+ DP_PSR2_WITH_Y_COORD_ET_SUPPORTED) && - intel_alpm_aux_wake_supported(intel_dp); - drm_dbg_kms(display->drm, "PSR2 %ssupported\n", - connector->dp.psr_caps.su_support ? "" : "not "); diff --git a/kernel/0401-psr2-early-transport-panels.patch.sig b/kernel/0401-psr2-early-transport-panels.patch.sig deleted file mode 100644 index ff5430c..0000000 Binary files a/kernel/0401-psr2-early-transport-panels.patch.sig and /dev/null differ diff --git a/kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch b/kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch deleted file mode 100644 index 27e9b7d..0000000 --- a/kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch +++ /dev/null @@ -1,172 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h ---- a/drivers/gpu/drm/i915/display/intel_display_types.h -+++ b/drivers/gpu/drm/i915/display/intel_display_types.h -@@ -1780,6 +1780,7 @@ struct intel_psr { - u32 dc3co_exitline; - u32 dc3co_exit_delay; - struct delayed_work dc3co_work; -+ struct delayed_work panel_replay_reenable_work; - u8 entry_setup_frames; - - u8 io_wake_lines; -diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c ---- a/drivers/gpu/drm/i915/display/intel_psr.c -+++ b/drivers/gpu/drm/i915/display/intel_psr.c -@@ -2481,6 +2481,7 @@ void intel_psr_disable(struct intel_dp *intel_dp, - mutex_unlock(&intel_dp->psr.lock); - cancel_work_sync(&intel_dp->psr.work); - cancel_delayed_work_sync(&intel_dp->psr.dc3co_work); -+ cancel_delayed_work_sync(&intel_dp->psr.panel_replay_reenable_work); - } - - /** -@@ -2512,6 +2513,7 @@ void intel_psr_pause(struct intel_dp *intel_dp) - - cancel_work_sync(&psr->work); - cancel_delayed_work_sync(&psr->dc3co_work); -+ cancel_delayed_work_sync(&psr->panel_replay_reenable_work); - } - - /** -@@ -3545,6 +3547,17 @@ static void intel_psr_handle_irq(struct intel_dp *intel_dp) - drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); - } - -+#define PANEL_REPLAY_REENABLE_DELAY_MS 50 -+ -+static bool panel_replay_exit_on_flush_enabled(struct intel_dp *intel_dp) -+{ -+ return intel_dp_is_edp(intel_dp) && -+ intel_dp->psr.panel_replay_enabled && -+ intel_dp->psr.sel_update_enabled && -+ intel_has_dpcd_quirk(intel_dp, -+ QUIRK_PANEL_REPLAY_EXIT_ON_FLUSH); -+} -+ - static void intel_psr_work(struct work_struct *work) - { - struct intel_dp *intel_dp = -@@ -3563,6 +3576,11 @@ static void intel_psr_work(struct work_struct *work) - if (intel_dp->psr.pause_counter) - goto unlock; - -+ /* The dedicated delayed work owns re-entry while the quirk is armed. */ -+ if (panel_replay_exit_on_flush_enabled(intel_dp) && -+ delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work)) -+ goto unlock; -+ - /* - * We have to make sure PSR is ready for re-enable - * otherwise it keeps disabled until next full enable/disable cycle. -@@ -3572,6 +3590,10 @@ static void intel_psr_work(struct work_struct *work) - if (!__psr_wait_for_idle_locked(intel_dp)) - goto unlock; - -+ if (panel_replay_exit_on_flush_enabled(intel_dp) && -+ delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work)) -+ goto unlock; -+ - /* - * The delayed work can race with an invalidate hence we need to - * recheck. Since psr_flush first clears this and then reschedules we -@@ -3585,6 +3607,33 @@ static void intel_psr_work(struct work_struct *work) - mutex_unlock(&intel_dp->psr.lock); - } - -+static void panel_replay_reenable_work(struct work_struct *work) -+{ -+ struct intel_dp *intel_dp = -+ container_of(work, typeof(*intel_dp), -+ psr.panel_replay_reenable_work.work); -+ -+ mutex_lock(&intel_dp->psr.lock); -+ -+ if (!intel_dp->psr.enabled || -+ !panel_replay_exit_on_flush_enabled(intel_dp) || -+ intel_dp->psr.pause_counter || -+ READ_ONCE(intel_dp->psr.irq_aux_error)) -+ goto unlock; -+ -+ if (!__psr_wait_for_idle_locked(intel_dp)) -+ goto unlock; -+ -+ /* Recheck for activity or a newer deadline after the unlocked wait. */ -+ if (delayed_work_pending(&intel_dp->psr.panel_replay_reenable_work) || -+ intel_dp->psr.busy_frontbuffer_bits || intel_dp->psr.active) -+ goto unlock; -+ -+ intel_psr_activate(intel_dp); -+unlock: -+ mutex_unlock(&intel_dp->psr.lock); -+} -+ - static void intel_psr_configure_full_frame_update(struct intel_dp *intel_dp) - { - struct intel_display *display = to_intel_display(intel_dp); -@@ -3656,8 +3705,11 @@ void intel_psr_invalidate(struct intel_display *display, - INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe); - intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits; - -- if (pipe_frontbuffer_bits) -+ if (pipe_frontbuffer_bits) { -+ if (panel_replay_exit_on_flush_enabled(intel_dp)) -+ cancel_delayed_work(&intel_dp->psr.panel_replay_reenable_work); - _psr_invalidate_handle(intel_dp); -+ } - - mutex_unlock(&intel_dp->psr.lock); - } -@@ -3773,6 +3825,15 @@ void intel_psr_flush(struct intel_display *display, - if (intel_dp->psr.pause_counter) - goto unlock; - -+ if (pipe_frontbuffer_bits && -+ panel_replay_exit_on_flush_enabled(intel_dp)) { -+ intel_psr_exit(intel_dp); -+ mod_delayed_work(display->wq.unordered, -+ &intel_dp->psr.panel_replay_reenable_work, -+ msecs_to_jiffies(PANEL_REPLAY_REENABLE_DELAY_MS)); -+ goto unlock; -+ } -+ - if (origin == ORIGIN_FLIP || - (origin == ORIGIN_CURSOR_UPDATE && - !intel_dp->psr.psr2_sel_fetch_enabled)) { -@@ -3836,6 +3897,8 @@ void intel_psr_init(struct intel_dp *intel_dp) - - INIT_WORK(&intel_dp->psr.work, intel_psr_work); - INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, tgl_dc3co_disable_work); -+ INIT_DELAYED_WORK(&intel_dp->psr.panel_replay_reenable_work, -+ panel_replay_reenable_work); - mutex_init(&intel_dp->psr.lock); - } - -diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c ---- a/drivers/gpu/drm/i915/display/intel_quirks.c -+++ b/drivers/gpu/drm/i915/display/intel_quirks.c -@@ -94,6 +94,14 @@ static void quirk_disable_edp_panel_replay(struct intel_dp *intel_dp) - drm_info(display->drm, "Applying disable Panel Replay quirk\n"); - } - -+static void quirk_panel_replay_exit_on_flush(struct intel_dp *intel_dp) -+{ -+ struct intel_display *display = to_intel_display(intel_dp); -+ -+ intel_set_dpcd_quirk(intel_dp, QUIRK_PANEL_REPLAY_EXIT_ON_FLUSH); -+ drm_info(display->drm, "Applying Panel Replay exit on flush quirk\n"); -+} -+ - static void quirk_disable_psr2(struct intel_display *display) - { - intel_set_quirk(display, QUIRK_DISABLE_PSR2); -diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h ---- a/drivers/gpu/drm/i915/display/intel_quirks.h -+++ b/drivers/gpu/drm/i915/display/intel_quirks.h -@@ -23,6 +23,7 @@ enum intel_quirk_id { - QUIRK_EDP_LIMIT_RATE_HBR2, - QUIRK_DISABLE_EDP_PANEL_REPLAY, - QUIRK_DISABLE_PSR2, -+ QUIRK_PANEL_REPLAY_EXIT_ON_FLUSH, - }; - - void intel_init_quirks(struct intel_display *display); diff --git a/kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch.sig b/kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch.sig deleted file mode 100644 index cb36779..0000000 Binary files a/kernel/0402-drm-i915-quirk-panel-replay-exit-on-flush.patch.sig and /dev/null differ diff --git a/kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch b/kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch deleted file mode 100644 index 24c203e..0000000 --- a/kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c ---- a/drivers/gpu/drm/i915/display/intel_quirks.c -+++ b/drivers/gpu/drm/i915/display/intel_quirks.c -@@ -284,7 +284,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = { - .subsystem_vendor = 0x1028, - .subsystem_device = 0x0db9, - .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), -- .hook = quirk_disable_edp_panel_replay, -+ .hook = quirk_panel_replay_exit_on_flush, - }, - /* Dell XPS 16 DA16260 */ - { diff --git a/kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch.sig b/kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch.sig deleted file mode 100644 index a828b25..0000000 Binary files a/kernel/0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch.sig and /dev/null differ diff --git a/kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch b/kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch deleted file mode 100644 index 8eb9b65..0000000 --- a/kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c ---- a/drivers/gpu/drm/i915/display/intel_quirks.c -+++ b/drivers/gpu/drm/i915/display/intel_quirks.c -@@ -292,7 +292,7 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = { - .subsystem_vendor = 0x1028, - .subsystem_device = 0x0dba, - .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), -- .hook = quirk_disable_edp_panel_replay, -+ .hook = quirk_panel_replay_exit_on_flush, - }, - }; - diff --git a/kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch.sig b/kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch.sig deleted file mode 100644 index 0894c4b..0000000 Binary files a/kernel/0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch.sig and /dev/null differ diff --git a/kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch b/kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch deleted file mode 100644 index 1da7f71..0000000 --- a/kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c ---- a/drivers/gpu/drm/i915/display/intel_quirks.c -+++ b/drivers/gpu/drm/i915/display/intel_quirks.c -@@ -267,6 +267,9 @@ static struct intel_quirk intel_quirks[] = { - - /* Xiaomi Book Pro 14 2026 */ - { 0xb081, 0x1d72, 0x2424, quirk_disable_psr2 }, -+ -+ /* Dell XPS 13 DX13260 */ -+ { DEVICE_ID_ANY, 0x1028, 0x0e54, quirk_disable_psr2 }, - }; - - static const struct intel_dpcd_quirk intel_dpcd_quirks[] = { -@@ -294,6 +297,14 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = { - .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), - .hook = quirk_panel_replay_exit_on_flush, - }, -+ /* Dell XPS 13 DX13260 */ -+ { -+ .device = DEVICE_ID_ANY, -+ .subsystem_vendor = 0x1028, -+ .subsystem_device = 0x0e54, -+ .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), -+ .hook = quirk_disable_edp_panel_replay, -+ }, - }; - - void intel_init_quirks(struct intel_display *display) diff --git a/kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch.sig b/kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch.sig deleted file mode 100644 index 833b6bd..0000000 Binary files a/kernel/0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch.sig and /dev/null differ diff --git a/kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch b/kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch deleted file mode 100644 index 94d0d55..0000000 --- a/kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c ---- a/drivers/gpu/drm/i915/display/intel_quirks.c -+++ b/drivers/gpu/drm/i915/display/intel_quirks.c -@@ -305,6 +305,15 @@ static const struct intel_dpcd_quirk intel_dpcd_quirks[] = { - .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), - .hook = quirk_disable_edp_panel_replay, - }, -+ /* Dell XPS 13 DX13260 (Wildcat Lake), sink "Bamboo" */ -+ { -+ .device = DEVICE_ID_ANY, -+ .subsystem_vendor = 0x1028, -+ .subsystem_device = 0x0e53, -+ .sink_oui = SINK_OUI(0x00, 0x22, 0xb9), -+ .sink_device_id = SINK_DEVICE_ID(0x42, 0x61, 0x6d, 0x62, 0x6f, 0x6f), -+ .hook = quirk_panel_replay_exit_on_flush, -+ }, - }; - - void intel_init_quirks(struct intel_display *display) diff --git a/kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch.sig b/kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch.sig deleted file mode 100644 index 086a867..0000000 Binary files a/kernel/0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch.sig and /dev/null differ diff --git a/kernel/0411-drm-xe-display-no-stolen-framebuffers.patch b/kernel/0411-drm-xe-display-no-stolen-framebuffers.patch deleted file mode 100644 index c1f3ad5..0000000 --- a/kernel/0411-drm-xe-display-no-stolen-framebuffers.patch +++ /dev/null @@ -1,43 +0,0 @@ -diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.c b/drivers/gpu/drm/xe/display/xe_display_bo.c ---- a/drivers/gpu/drm/xe/display/xe_display_bo.c -+++ b/drivers/gpu/drm/xe/display/xe_display_bo.c -@@ -147,33 +147,12 @@ static struct drm_gem_object *xe_display_bo_fbdev_create(struct drm_device *drm, - struct xe_device *xe = to_xe_device(drm); - struct xe_bo *obj; - -- obj = ERR_PTR(-ENODEV); -- -- if (xe_display_bo_fbdev_prefer_stolen(xe, size)) { -- obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), -- size, -- ttm_bo_type_kernel, -- XE_BO_FLAG_FORCE_WC | -- XE_BO_FLAG_STOLEN | -- XE_BO_FLAG_GGTT, -- false); -- if (!IS_ERR(obj)) -- drm_info(&xe->drm, "Allocated fbdev into stolen\n"); -- else -- drm_info(&xe->drm, "Allocated fbdev into stolen failed: %li\n", PTR_ERR(obj)); -- } else { -- drm_info(&xe->drm, "Allocating fbdev: Stolen memory not preferred.\n"); -- } -- -- if (IS_ERR(obj)) { -- obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), size, -- ttm_bo_type_kernel, -- XE_BO_FLAG_FORCE_WC | -- XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) | -- XE_BO_FLAG_GGTT, -- false); -- } -- -+ obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), size, -+ ttm_bo_type_kernel, -+ XE_BO_FLAG_FORCE_WC | -+ XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) | -+ XE_BO_FLAG_GGTT, -+ false); - if (IS_ERR(obj)) { - drm_err(&xe->drm, "failed to allocate framebuffer (%pe)\n", obj); - return ERR_PTR(-ENOMEM); diff --git a/kernel/0411-drm-xe-display-no-stolen-framebuffers.patch.sig b/kernel/0411-drm-xe-display-no-stolen-framebuffers.patch.sig deleted file mode 100644 index 67e82c0..0000000 Binary files a/kernel/0411-drm-xe-display-no-stolen-framebuffers.patch.sig and /dev/null differ diff --git a/kernel/0420-safe-window.patch b/kernel/0420-safe-window.patch deleted file mode 100644 index 21017c7..0000000 --- a/kernel/0420-safe-window.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c ---- a/drivers/gpu/drm/i915/display/intel_display.c -+++ b/drivers/gpu/drm/i915/display/intel_display.c -@@ -2452,6 +2452,19 @@ static int intel_crtc_set_context_latency(struct intel_crtc_state *crtc_state) - set_context_latency = max(set_context_latency, - intel_psr_min_set_context_latency(crtc_state)); - -+ /* -+ * From PTL onwards, the set context latency can be in the vactive -+ * region, letting the safe window start some lines before the vblank -+ * start. With modes that have a smaller vblank region, the computed -+ * guardband is clamped to the vblank length, making the undelayed and -+ * delayed vblank coincide. If the SCL is also 0, the 'safe window' -+ * becomes effectively 0, and the DSB configured to wait for it gets -+ * stalled, since the hardware never signals the safe window. Keep the -+ * set context latency at a minimum of 1 to avoid this. -+ */ -+ if (DISPLAY_VER(display) >= 30) -+ set_context_latency = max(1, set_context_latency); -+ - return set_context_latency; - } - diff --git a/kernel/0420-safe-window.patch.sig b/kernel/0420-safe-window.patch.sig deleted file mode 100644 index 33f021c..0000000 Binary files a/kernel/0420-safe-window.patch.sig and /dev/null differ diff --git a/kernel/0430-fbc.patch b/kernel/0430-fbc.patch deleted file mode 100644 index b64db93..0000000 --- a/kernel/0430-fbc.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c ---- a/drivers/gpu/drm/i915/display/intel_fbc.c -+++ b/drivers/gpu/drm/i915/display/intel_fbc.c -@@ -59,6 +59,7 @@ - #include "intel_fbc_regs.h" - #include "intel_frontbuffer.h" - #include "intel_parent.h" -+#include "skl_universal_plane.h" - - #define for_each_fbc_id(__display, __fbc_id) \ - for ((__fbc_id) = INTEL_FBC_A; (__fbc_id) < I915_MAX_FBCS; (__fbc_id)++) \ -@@ -1305,6 +1306,9 @@ static bool intel_fbc_surface_size_ok(const struct intel_plane_state *plane_stat - struct intel_display *display = to_intel_display(plane_state); - unsigned int effective_w, effective_h, max_w, max_h; - -+ if (DISPLAY_VER(display) >= 20) -+ return true; -+ - intel_fbc_max_surface_size(display, &max_w, &max_h); - - effective_w = plane_state->view.color_plane[0].x + -@@ -1315,10 +1319,18 @@ static bool intel_fbc_surface_size_ok(const struct intel_plane_state *plane_stat - return effective_w <= max_w && effective_h <= max_h; - } - --static void intel_fbc_max_plane_size(struct intel_display *display, -+static void intel_fbc_max_plane_size(const struct intel_plane_state *plane_state, - unsigned int *w, unsigned int *h) - { -- if (DISPLAY_VER(display) >= 10) { -+ struct intel_display *display = to_intel_display(plane_state); -+ struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); -+ const struct drm_framebuffer *fb = plane_state->hw.fb; -+ unsigned int rotation = plane_state->hw.rotation; -+ -+ if (DISPLAY_VER(display) >= 20) { -+ *w = intel_plane_max_width(plane, fb, 0, rotation); -+ *h = 4096; -+ } else if (DISPLAY_VER(display) >= 10) { - *w = 5120; - *h = 4096; - } else if (DISPLAY_VER(display) >= 8 || display->platform.haswell) { -@@ -1335,10 +1347,9 @@ static void intel_fbc_max_plane_size(struct intel_display *display, - - static bool intel_fbc_plane_size_valid(const struct intel_plane_state *plane_state) - { -- struct intel_display *display = to_intel_display(plane_state); - unsigned int w, h, max_w, max_h; - -- intel_fbc_max_plane_size(display, &max_w, &max_h); -+ intel_fbc_max_plane_size(plane_state, &max_w, &max_h); - - w = drm_rect_width(&plane_state->uapi.src) >> 16; - h = drm_rect_height(&plane_state->uapi.src) >> 16; -diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c ---- a/drivers/gpu/drm/i915/display/skl_universal_plane.c -+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c -@@ -1932,10 +1932,10 @@ static int intel_plane_min_height(struct intel_plane *plane, - return 1; - } - --static int intel_plane_max_width(struct intel_plane *plane, -- const struct drm_framebuffer *fb, -- int color_plane, -- unsigned int rotation) -+int intel_plane_max_width(struct intel_plane *plane, -+ const struct drm_framebuffer *fb, -+ int color_plane, -+ unsigned int rotation) - { - if (plane->max_width) - return plane->max_width(fb, color_plane, rotation); -@@ -1943,10 +1943,10 @@ static int intel_plane_max_width(struct intel_plane *plane, - return INT_MAX; - } - --static int intel_plane_max_height(struct intel_plane *plane, -- const struct drm_framebuffer *fb, -- int color_plane, -- unsigned int rotation) -+int intel_plane_max_height(struct intel_plane *plane, -+ const struct drm_framebuffer *fb, -+ int color_plane, -+ unsigned int rotation) - { - if (plane->max_height) - return plane->max_height(fb, color_plane, rotation); -diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h ---- a/drivers/gpu/drm/i915/display/skl_universal_plane.h -+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h -@@ -8,6 +8,7 @@ - - #include - -+struct drm_framebuffer; - struct intel_crtc; - struct intel_display; - struct intel_initial_plane_config; -@@ -42,5 +43,13 @@ bool icl_is_hdr_plane(struct intel_display *display, enum plane_id plane_id); - - u32 skl_plane_aux_dist(const struct intel_plane_state *plane_state, - int color_plane); -+int intel_plane_max_width(struct intel_plane *plane, -+ const struct drm_framebuffer *fb, -+ int color_plane, -+ unsigned int rotation); -+int intel_plane_max_height(struct intel_plane *plane, -+ const struct drm_framebuffer *fb, -+ int color_plane, -+ unsigned int rotation); - - #endif diff --git a/kernel/0430-fbc.patch.sig b/kernel/0430-fbc.patch.sig deleted file mode 100644 index 7c6d7b4..0000000 Binary files a/kernel/0430-fbc.patch.sig and /dev/null differ diff --git a/kernel/0440-xe3-peak-bandwidth.patch b/kernel/0440-xe3-peak-bandwidth.patch deleted file mode 100644 index a13b165..0000000 --- a/kernel/0440-xe3-peak-bandwidth.patch +++ /dev/null @@ -1,67 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c ---- a/drivers/gpu/drm/i915/display/intel_bw.c -+++ b/drivers/gpu/drm/i915/display/intel_bw.c -@@ -52,6 +52,8 @@ - - #define DEPROGBWPCLIMIT 60 - -+#define PEAK_BW_THRESHOLD 20000 -+ - struct intel_psf_gv_point { - u8 clk; /* clock in multiples of 16.6666 MHz */ - }; -@@ -587,6 +589,33 @@ - return num_channels * (channel_width / 8) * dclk; - } - -+static void xe3_add_peakbw_threshold(struct intel_display *display) -+{ -+ u8 qgv_points = display->bw.max[0].num_qgv_points; -+ -+ if (!HAS_PEAK_BW_THRESHOLD(display)) -+ return; -+ -+ if (qgv_points >= I915_NUM_QGV_POINTS) { -+ drm_dbg_kms(display->drm, "QGV points maxed out; skipping peak bandwidth threshold.\n"); -+ return; -+ } -+ -+ if (qgv_points <= 1) -+ return; -+ -+ for (int i = 0; i < ARRAY_SIZE(display->bw.max); i++) { -+ struct intel_bw_info *bi = &display->bw.max[i]; -+ -+ bi->num_qgv_points++; -+ bi->peakbw[qgv_points] = PEAK_BW_THRESHOLD; -+ bi->deratedbw[qgv_points] = PEAK_BW_THRESHOLD; -+ } -+ -+ drm_dbg_kms(display->drm, "An extra QGV point %d added for Peak bw threshod of %d\n", -+ qgv_points, PEAK_BW_THRESHOLD); -+} -+ - static int tgl_get_bw_info(struct intel_display *display, - const struct dram_info *dram_info, - const struct intel_soc_bw_params *soc_bw_params, -@@ -684,6 +713,9 @@ - } - } - -+ /* For xe3 cases add an extra qgv point for Peak bw threshold */ -+ xe3_add_peakbw_threshold(display); -+ - /* - * In case if SAGV is disabled in BIOS, we always get 1 - * SAGV point, but we can't send PCode commands to restrict it -diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h ---- a/drivers/gpu/drm/i915/display/intel_display_device.h -+++ b/drivers/gpu/drm/i915/display/intel_display_device.h -@@ -191,6 +191,7 @@ - #define HAS_MBUS_JOINING(__display) ((__display)->platform.alderlake_p || DISPLAY_VER(__display) >= 14) - #define HAS_MSO(__display) (DISPLAY_VER(__display) >= 12) - #define HAS_OVERLAY(__display) (DISPLAY_INFO(__display)->has_overlay) -+#define HAS_PEAK_BW_THRESHOLD(__display) (DISPLAY_VER(__display) >= 30) - #define HAS_PIPEDMC(__display) (DISPLAY_VER(__display) >= 12) - #define HAS_PIXEL_NORMALIZER(__display) (DISPLAY_VER(__display) >= 35) - #define HAS_PSR(__display) (DISPLAY_INFO(__display)->has_psr) diff --git a/kernel/0440-xe3-peak-bandwidth.patch.sig b/kernel/0440-xe3-peak-bandwidth.patch.sig deleted file mode 100644 index 99d5c08..0000000 Binary files a/kernel/0440-xe3-peak-bandwidth.patch.sig and /dev/null differ diff --git a/kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch b/kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch deleted file mode 100644 index e2e1fac..0000000 --- a/kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c ---- a/drivers/gpu/drm/i915/display/intel_cursor.c -+++ b/drivers/gpu/drm/i915/display/intel_cursor.c -@@ -536,7 +536,8 @@ static void i9xx_cursor_disable_sel_fetch_arm(struct intel_dsb *dsb, - struct intel_display *display = to_intel_display(plane); - enum pipe pipe = plane->pipe; - -- if (!crtc_state->enable_psr2_sel_fetch) -+ if (!crtc_state->enable_psr2_sel_fetch && -+ !crtc_state->clear_psr2_sel_fetch) - return; - - intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), 0); -@@ -569,8 +570,10 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_dsb *dsb, - struct intel_display *display = to_intel_display(plane); - enum pipe pipe = plane->pipe; - -- if (!crtc_state->enable_psr2_sel_fetch) -+ if (!crtc_state->enable_psr2_sel_fetch) { -+ i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state); - return; -+ } - - if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) { - if (crtc_state->enable_psr2_su_region_et) { -diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h ---- a/drivers/gpu/drm/i915/display/intel_display_types.h -+++ b/drivers/gpu/drm/i915/display/intel_display_types.h -@@ -1177,6 +1177,8 @@ struct intel_crtc_state { - bool has_sel_update; - bool enable_psr2_sel_fetch; - bool enable_psr2_su_region_et; -+ /* Drop the stale selective fetch enable bits as selective fetch is turned off */ -+ bool clear_psr2_sel_fetch; - bool req_psr2_sdp_prior_scanline; - bool has_panel_replay; - bool link_off_after_as_sdp_when_pr_active; -diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c ---- a/drivers/gpu/drm/i915/display/intel_psr.c -+++ b/drivers/gpu/drm/i915/display/intel_psr.c -@@ -2941,6 +2941,8 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, - struct intel_crtc *crtc) - { - struct intel_display *display = to_intel_display(state); -+ const struct intel_crtc_state *old_crtc_state = -+ intel_atomic_get_old_crtc_state(state, crtc); - struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct intel_plane_state *new_plane_state, *old_plane_state; - struct intel_plane *plane; -@@ -2953,6 +2955,19 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, - bool full_update = false, su_area_changed; - int i, ret; - -+ /* -+ * Selective fetch is not always usable, for instance it is dropped -+ * while pipe CRC is active. The planes keep their selective fetch -+ * enable bit set in hardware over that, and a plane disabled while -+ * selective fetch is off never gets the bit cleared. Once selective -+ * fetch comes back the hardware would resume fetching for a plane that -+ * is no longer enabled and keep its DDB range reserved, so have the -+ * plane update drop the bit for every plane of the pipe as selective -+ * fetch is turned off. -+ */ -+ crtc_state->clear_psr2_sel_fetch = old_crtc_state->enable_psr2_sel_fetch && -+ !crtc_state->enable_psr2_sel_fetch; -+ - if (!crtc_state->enable_psr2_sel_fetch) - return 0; - -diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c ---- a/drivers/gpu/drm/i915/display/skl_universal_plane.c -+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c -@@ -885,7 +885,8 @@ static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb, - struct intel_display *display = to_intel_display(plane); - enum pipe pipe = plane->pipe; - -- if (!crtc_state->enable_psr2_sel_fetch) -+ if (!crtc_state->enable_psr2_sel_fetch && -+ !crtc_state->clear_psr2_sel_fetch) - return; - - intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0); -@@ -1634,10 +1635,8 @@ static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb, - struct intel_display *display = to_intel_display(plane); - enum pipe pipe = plane->pipe; - -- if (!crtc_state->enable_psr2_sel_fetch) -- return; -- -- if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) -+ if (crtc_state->enable_psr2_sel_fetch && -+ drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) - intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), - SEL_FETCH_PLANE_CTL_ENABLE); - else diff --git a/kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch.sig b/kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch.sig deleted file mode 100644 index 2a891ba..0000000 Binary files a/kernel/0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch.sig and /dev/null differ diff --git a/kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch b/kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch deleted file mode 100644 index 820d377..0000000 --- a/kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c ---- a/drivers/gpu/drm/i915/display/intel_dsb.c -+++ b/drivers/gpu/drm/i915/display/intel_dsb.c -@@ -902,9 +902,17 @@ void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, - * the hardware itself guarantees that we're SCL lines - * away from the delayed vblank, and we won't be inside - * the vmin safe window so this extra wait does nothing. -+ * -+ * Experimentally, DSB may observe a slightly stale -+ * PIPEDSL value. When the actual scanline has just reached -+ * safe_window_start, WAIT_DSL_OUT may complete immediately -+ * due to the stale value. -+ * -+ * Shift the start back by one scanline to ensure the wait -+ * window is entered reliably. - */ - intel_dsb_wait_scanline_out(state, dsb, -- intel_vrr_safe_window_start(crtc_state), -+ intel_vrr_safe_window_start(crtc_state) - 1, - intel_vrr_vmin_safe_window_end(crtc_state)); - /* - * When the push is sent during vblank it will trigger diff --git a/kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch.sig b/kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch.sig deleted file mode 100644 index f11347d..0000000 Binary files a/kernel/0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch.sig and /dev/null differ diff --git a/kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch b/kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch deleted file mode 100644 index 9efda11..0000000 --- a/kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c ---- a/drivers/gpu/drm/i915/display/intel_display_params.c -+++ b/drivers/gpu/drm/i915/display/intel_display_params.c -@@ -120,6 +120,10 @@ intel_display_param_named_unsafe(enable_psr, int, 0400, - "(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) " - "Default: -1 (use per-chip default)"); - -+intel_display_param_named_unsafe(enable_dc_balance, bool, 0400, -+ "Enable VRR DC balance (0=disabled, 1=enabled). " -+ "Default: 0 (disabled)"); -+ - intel_display_param_named_unsafe(enable_panel_replay, int, 0400, - "Enable Panel Replay (0=disabled, 1=enabled). Default: -1 (use per-chip default)"); - -diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h ---- a/drivers/gpu/drm/i915/display/intel_display_params.h -+++ b/drivers/gpu/drm/i915/display/intel_display_params.h -@@ -46,6 +46,7 @@ struct drm_printer; - param(bool, enable_dp_mst, true, 0600) \ - param(int, enable_fbc, -1, 0600) \ - param(int, enable_psr, -1, 0600) \ -+ param(bool, enable_dc_balance, false, 0600) \ - param(int, enable_panel_replay, -1, 0600) \ - param(bool, psr_safest_params, false, 0400) \ - param(bool, enable_psr2_sel_fetch, true, 0400) \ -diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c ---- a/drivers/gpu/drm/i915/display/intel_vrr.c -+++ b/drivers/gpu/drm/i915/display/intel_vrr.c -@@ -383,10 +383,12 @@ static bool intel_vrr_dc_balance_possible(const struct intel_crtc_state *crtc_st - static void - intel_vrr_dc_balance_compute_config(struct intel_crtc_state *crtc_state) - { -+ struct intel_display *display = to_intel_display(crtc_state); - int guardband_usec, adjustment_usec; - struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - -- if (!intel_vrr_dc_balance_possible(crtc_state) || !crtc_state->vrr.enable) -+ if (!intel_vrr_dc_balance_possible(crtc_state) || -+ !crtc_state->vrr.enable || !display->params.enable_dc_balance) - return; - - crtc_state->vrr.dc_balance.vmax = crtc_state->vrr.vmax; diff --git a/kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch.sig b/kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch.sig deleted file mode 100644 index 497cbb1..0000000 Binary files a/kernel/0444-drm-i915-vrr-dc-balance-off-by-default.patch.sig and /dev/null differ diff --git a/kernel/0450-amd-hdmi-vrr-allm.patch b/kernel/0450-amd-hdmi-vrr-allm.patch deleted file mode 100644 index 02991bc..0000000 --- a/kernel/0450-amd-hdmi-vrr-allm.patch +++ /dev/null @@ -1,456 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -104,6 +104,7 @@ - #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" - - #include "modules/inc/mod_freesync.h" -+#include "modules/inc/mod_info_packet.h" - #include "modules/inc/mod_power.h" - #include "modules/power/power_helpers.h" - -@@ -10088,6 +10089,9 @@ static void update_freesync_state_on_stream( - &vrr_infopacket, - pack_sdp_v1_3); - -+ if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) -+ mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket); -+ - new_crtc_state->freesync_vrr_info_changed |= - (memcmp(&new_crtc_state->vrr_infopacket, - &vrr_infopacket, -@@ -10099,6 +10103,36 @@ static void update_freesync_state_on_stream( - new_stream->vrr_infopacket = vrr_infopacket; - new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params); - -+ /* -+ * HDMI ALLM: when Gaming-VRR is active (VRR_EN=1) and the sink -+ * advertises ALLM in the SCDS, the Source shall transmit the HF-VSIF -+ * with ALLM_Mode=1 (HDMI 2.1 Section 7.6.6). -+ */ -+ if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || -+ new_stream->signal == SIGNAL_TYPE_HDMI_FRL) { -+ struct dc_info_packet hf_vsif = {0}; -+ bool sink_allm = aconn && aconn->base.display_info.hdmi.allm; -+ bool allm = sink_allm && -+ (vrr_params.state == VRR_STATE_ACTIVE_VARIABLE || -+ vrr_params.state == VRR_STATE_ACTIVE_FIXED); -+ bool allm_changed; -+ -+ if (allm) -+ mod_build_hf_vsif_infopacket(new_stream, &hf_vsif, allm, allm); -+ -+ allm_changed = memcmp(&new_stream->hfvsif_infopacket, &hf_vsif, -+ sizeof(hf_vsif)) != 0; -+ new_crtc_state->freesync_vrr_info_changed |= allm_changed; -+ new_stream->hfvsif_infopacket = hf_vsif; -+ -+ if (allm_changed) -+ drm_dbg_driver(adev_to_drm(adev), -+ "ALLM: flip on crtc=%u: sink_allm=%d vrr_state=%d -> ALLM_Mode=%d\n", -+ new_crtc_state->base.crtc->base.id, -+ sink_allm, -+ vrr_params.state, allm); -+ } -+ - if (new_crtc_state->freesync_vrr_info_changed) - drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d", - new_crtc_state->base.crtc->base.id, -@@ -10665,9 +10699,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, - } - - if (acrtc_state->stream) { -- if (acrtc_state->freesync_vrr_info_changed) -+ if (acrtc_state->freesync_vrr_info_changed) { - bundle->stream_update.vrr_infopacket = - &acrtc_state->stream->vrr_infopacket; -+ bundle->stream_update.hfvsif_infopacket = -+ &acrtc_state->stream->hfvsif_infopacket; -+ } - } - } - -@@ -12069,6 +12106,14 @@ static void get_freesync_config_for_crtc( - } - out: - new_crtc_state->freesync_config = config; -+ -+ drm_dbg_driver(new_con_state->base.connector->dev, -+ "VRR: cfg vrr_enabled=%d vrr_supported=%d fs_capable=%d vrefresh=%d min=%d max=%d state=%d\n", -+ new_crtc_state->base.vrr_enabled, -+ new_crtc_state->vrr_supported, -+ new_con_state->freesync_capable, vrefresh, -+ aconnector->min_vfreq, aconnector->max_vfreq, -+ config.state); - } - - static void reset_freesync_config_for_crtc( -@@ -14031,6 +14076,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version)) - goto update; - -+ drm_dbg_driver(adev_to_drm(adev), -+ "VRR: enter signal=%d hdmi_vrr=%d mrange[%d-%d] hdmi.vrr_cap[sup=%d min=%d max=%d]\n", -+ sink->sink_signal, connector->display_info.hdmi.vrr_cap.supported, -+ connector->display_info.monitor_range.min_vfreq, -+ connector->display_info.monitor_range.max_vfreq, -+ connector->display_info.hdmi.vrr_cap.supported, -+ connector->display_info.hdmi.vrr_cap.vrr_min, -+ connector->display_info.hdmi.vrr_cap.vrr_max); -+ - edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw() - - /* Some eDP panels only have the refresh rate range info in DisplayID */ -@@ -14056,7 +14110,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP; - } - -- } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) { -+ } else if (drm_edid && -+ (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || -+ sink->sink_signal == SIGNAL_TYPE_HDMI_FRL)) { - i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); - if (i >= 0) { - amdgpu_dm_connector->vsdb_info = vsdb_info; -@@ -14072,6 +14128,59 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; - } - } -+ -+ drm_dbg_driver(adev_to_drm(adev), -+ "VRR: amd_vsdb i=%d fs_sup=%d min=%d max=%d fs_capable=%d\n", -+ i, vsdb_info.freesync_supported, -+ vsdb_info.min_refresh_rate_hz, -+ vsdb_info.max_refresh_rate_hz, freesync_capable); -+ -+ /* -+ * If AMD VSDB didn't provide a valid FreeSync range, fall back to -+ * the HDMI 2.1 VRR capability parsed from the HF-VSDB. -+ */ -+ if (!freesync_capable && connector->display_info.hdmi.vrr_cap.supported) { -+ struct drm_hdmi_vrr_cap *vrr_cap = -+ &connector->display_info.hdmi.vrr_cap; -+ -+ drm_dbg_driver(adev_to_drm(adev), -+ "VRR: HF-VSDB fallback: hdmi_vrr=1 vrr_cap[sup=%d min=%d max=%d] mrange_max=%d\n", -+ vrr_cap->supported, vrr_cap->vrr_min, vrr_cap->vrr_max, -+ connector->display_info.monitor_range.max_vfreq); -+ -+ if (vrr_cap->supported && vrr_cap->vrr_min > 0) { -+ amdgpu_dm_connector->min_vfreq = vrr_cap->vrr_min; -+ amdgpu_dm_connector->max_vfreq = vrr_cap->vrr_max ? -+ vrr_cap->vrr_max : -+ connector->display_info.monitor_range.max_vfreq; -+ -+ /* -+ * VRRMAX = 0 in the HF-VSDB means "up to the Base -+ * Refresh Rate". If the EDID also did not provide a -+ * monitor range max, fall back to the Base Refresh -+ * Rate (the highest refresh rate of the preferred -+ * timing) so a valid VRR range is still reported to -+ * userspace. -+ */ -+ if (!amdgpu_dm_connector->max_vfreq) { -+ struct drm_display_mode *brr_mode = -+ get_highest_refresh_rate_mode(amdgpu_dm_connector, true); -+ -+ if (brr_mode) -+ amdgpu_dm_connector->max_vfreq = -+ drm_mode_vrefresh(brr_mode); -+ } -+ -+ if (amdgpu_dm_connector->max_vfreq - -+ amdgpu_dm_connector->min_vfreq > 10) -+ freesync_capable = true; -+ -+ connector->display_info.monitor_range.min_vfreq = -+ amdgpu_dm_connector->min_vfreq; -+ connector->display_info.monitor_range.max_vfreq = -+ amdgpu_dm_connector->max_vfreq; -+ } -+ } - } - - if (amdgpu_dm_connector->dc_link) -@@ -14113,6 +14222,11 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - if (dm_con_state) - dm_con_state->freesync_capable = freesync_capable; - -+ drm_dbg_driver(adev_to_drm(adev), -+ "VRR: caps result: freesync_capable=%d min_vfreq=%d max_vfreq=%d\n", -+ freesync_capable, amdgpu_dm_connector->min_vfreq, -+ amdgpu_dm_connector->max_vfreq); -+ - if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable && - amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) { - amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported = false; -diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h ---- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h -+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h -@@ -67,6 +67,10 @@ struct AS_Df_params { - struct frame_duration_op decrease; - }; - -+void mod_build_infopacket_vtem(const struct dc_stream_state *stream, -+ const struct mod_vrr_params *vrr, int fva_factor, -+ struct dc_info_packet *infopacket); -+ - void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream, - enum adaptive_sync_type asType, const struct AS_Df_params *param, - struct dc_info_packet *info_packet); -diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c ---- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c -+++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c -@@ -291,6 +291,21 @@ void set_vsc_packet_colorimetry_data( - info_packet->sb[18] = 0; - } - -+static void set_field_with_mask(unsigned char *dest, unsigned int mask, unsigned int value) -+{ -+ unsigned int shift = 0; -+ -+ if (!mask || !dest) -+ return; -+ -+ while (!((mask >> shift) & 1)) -+ shift++; -+ -+ *dest = *dest & ~mask; -+ value = value & (mask >> shift); -+ *dest = *dest | (value << shift); -+} -+ - void mod_build_vsc_infopacket(const struct dc_stream_state *stream, - struct dc_info_packet *info_packet, - enum dc_color_space cs, -@@ -644,6 +659,100 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, - info_packet->valid = true; - } - -+static void build_vtem_infopacket_data(const struct dc_stream_state *stream, -+ const struct mod_vrr_params *vrr, int fva_factor, -+ struct dc_info_packet *infopacket) -+{ -+ unsigned int field_rate_in_hz; -+ -+ /* FVA Factor setting */ -+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__FVA_FACTOR_M1, -+ (fva_factor > 0) ? (fva_factor - 1) : 0); -+ /* VRR Parameters */ -+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || -+ vrr->state == VRR_STATE_ACTIVE_FIXED) { -+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__VRR_EN, 1); -+ } else { -+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__VRR_EN, 0); -+ } -+ -+ if (vrr->state == VRR_STATE_ACTIVE_FIXED) -+ set_field_with_mask(&infopacket->sb[VTEM_MD0], MASK_VTEM_MD0__M_CONST, vrr->m_const); -+ -+ if (!stream->timing.vic) { -+ set_field_with_mask(&infopacket->sb[VTEM_MD1], MASK_VTEM_MD1__BASE_VFRONT, -+ stream->timing.v_front_porch); -+ -+ -+ /* TODO: In dal2, we check mode flags for a reduced blanking timing. -+ * Need a way to relay that information to this function. -+ * if("ReducedBlanking") -+ * { -+ * set_field_with_mask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__RB, 1; -+ * } -+ */ -+ -+ field_rate_in_hz = stream->timing.pix_clk_100hz * 100; -+ field_rate_in_hz /= stream->timing.h_total; -+ field_rate_in_hz = (field_rate_in_hz + stream->timing.v_total / 2) -+ / stream->timing.v_total; -+ -+ set_field_with_mask(&infopacket->sb[VTEM_MD2], MASK_VTEM_MD2__BASE_REFRESH_RATE_98, -+ field_rate_in_hz >> 8); -+ set_field_with_mask(&infopacket->sb[VTEM_MD3], MASK_VTEM_MD3__BASE_REFRESH_RATE_07, -+ field_rate_in_hz); -+ -+ } -+ -+ /* -+ * When no VTEM feature is enabled (neither VRR nor FVA), signal a -+ * zero-length data set (MLDS) by clearing Data_Set_Length. HDMI 2.1 -+ * 10.10.2.4 requires the Source to either stop transmitting the VTEM -+ * or set Data_Set_Length = 0 when no feature is enabled; keeping the -+ * VTEM with Data_Set_Length = 0 preserves the every-MTW cadence while -+ * staying compliant (e.g. HDMI GCTS HF1-58 step 6.2). -+ */ -+ if (vrr->state != VRR_STATE_ACTIVE_VARIABLE && -+ vrr->state != VRR_STATE_ACTIVE_FIXED && fva_factor == 0) -+ set_field_with_mask(&infopacket->sb[VTEM_PB6], -+ MASK_VTEM_PB6__DATA_SET_LENGTH_LSB, 0); -+ -+ infopacket->valid = true; -+} -+ -+static void build_infopacket_header_vtem(enum signal_type signal, -+ struct dc_info_packet *infopacket) -+{ -+ /* HEADER */ -+ -+ /* HB0, HB1, HB2 indicates PacketType VTEMPacket */ -+ infopacket->hb0 = 0x7F; -+ infopacket->hb1 = 0xC0; -+ infopacket->hb2 = 0x00; /* sequence_index */ -+ -+ set_field_with_mask(&infopacket->sb[VTEM_PB0], MASK_VTEM_PB0__VFR, 1); -+ set_field_with_mask(&infopacket->sb[VTEM_PB2], MASK_VTEM_PB2__ORGANIZATION_ID, 1); -+ set_field_with_mask(&infopacket->sb[VTEM_PB3], MASK_VTEM_PB3__DATA_SET_TAG_MSB, 0); -+ set_field_with_mask(&infopacket->sb[VTEM_PB4], MASK_VTEM_PB4__DATA_SET_TAG_LSB, 1); -+ set_field_with_mask(&infopacket->sb[VTEM_PB5], MASK_VTEM_PB5__DATA_SET_LENGTH_MSB, 0); -+ set_field_with_mask(&infopacket->sb[VTEM_PB6], MASK_VTEM_PB6__DATA_SET_LENGTH_LSB, 4); -+} -+ -+void mod_build_infopacket_vtem(const struct dc_stream_state *stream, -+ const struct mod_vrr_params *vrr, int fva_factor, -+ struct dc_info_packet *infopacket) -+{ -+ /* VTEM info packet for HdmiVrr */ -+ -+ memset(infopacket, 0, sizeof(struct dc_info_packet)); -+ -+ /* VTEM Packet is structured differently */ -+ build_infopacket_header_vtem(stream->signal, infopacket); -+ build_vtem_infopacket_data(stream, vrr, fva_factor, infopacket); -+ -+ infopacket->valid = true; -+} -+ - void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream, - enum adaptive_sync_type asType, - const struct AS_Df_params *param, -diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c ---- a/drivers/gpu/drm/drm_edid.c -+++ b/drivers/gpu/drm/drm_edid.c -@@ -6182,6 +6182,33 @@ static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector, - hdmi->y420_dc_modes = dc_mask; - } - -+static void drm_parse_hdmi_gaming_info(struct drm_hdmi_info *hdmi, const u8 *db) -+{ -+ struct drm_hdmi_vrr_cap *vrr = &hdmi->vrr_cap; -+ -+ if (cea_db_payload_len(db) < 8) -+ return; -+ -+ hdmi->fapa_start_location = db[8] & DRM_EDID_FAPA_START_LOCATION; -+ hdmi->allm = db[8] & DRM_EDID_ALLM; -+ vrr->fva = db[8] & DRM_EDID_FVA; -+ vrr->cnmvrr = db[8] & DRM_EDID_CNMVRR; -+ vrr->cinema_vrr = db[8] & DRM_EDID_CINEMA_VRR; -+ vrr->mdelta = db[8] & DRM_EDID_MDELTA; -+ -+ if (cea_db_payload_len(db) < 9) -+ return; -+ -+ vrr->vrr_min = db[9] & DRM_EDID_VRR_MIN_MASK; -+ vrr->supported = (vrr->vrr_min > 0 && vrr->vrr_min <= 48); -+ -+ if (cea_db_payload_len(db) < 10) -+ return; -+ -+ vrr->vrr_max = (db[9] & DRM_EDID_VRR_MAX_UPPER_MASK) << 2 | db[10]; -+ vrr->supported &= (vrr->vrr_max == 0 || vrr->vrr_max >= 100); -+} -+ - static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc, - const u8 *hf_scds) - { -@@ -6308,6 +6335,8 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, - - drm_parse_ycbcr420_deep_color_info(connector, hf_scds); - -+ drm_parse_hdmi_gaming_info(&connector->display_info.hdmi, hf_scds); -+ - if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11]) { - drm_parse_dsc_info(hdmi_dsc, hf_scds); - dsc_support = true; -@@ -6317,6 +6346,19 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector, - "[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n", - connector->base.id, connector->name, - max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support)); -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] FAPA in blanking: %s, ALLM support: %s, Fast Vactive support: %s\n", -+ connector->base.id, connector->name, str_yes_no(hdmi->fapa_start_location), -+ str_yes_no(hdmi->allm), str_yes_no(hdmi->vrr_cap.fva)); -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] Negative M VRR support: %s, CinemaVRR support: %s, Mdelta: %d\n", -+ connector->base.id, connector->name, str_yes_no(hdmi->vrr_cap.cnmvrr), -+ str_yes_no(hdmi->vrr_cap.cinema_vrr), hdmi->vrr_cap.mdelta); -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] VRRmin: %u, VRRmax: %u, VRR supported: %s\n", -+ connector->base.id, connector->name, hdmi->vrr_cap.vrr_min, -+ hdmi->vrr_cap.vrr_max, str_yes_no(hdmi->vrr_cap.supported)); -+ - } - - static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, -diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h ---- a/include/drm/drm_connector.h -+++ b/include/drm/drm_connector.h -@@ -254,6 +254,44 @@ struct drm_scdc { - struct drm_scrambling scrambling; - }; - -+/** -+ * struct drm_hdmi_vrr_cap - Information about VRR capabilities of a HDMI sink -+ * -+ * Describes the VRR support provided by HDMI 2.1 sink. The information is -+ * fetched fom additional HFVSDB blocks defined for HDMI 2.1. -+ */ -+struct drm_hdmi_vrr_cap { -+ /** @fva: flag for Fast VActive (Quick Frame Transport) support */ -+ bool fva; -+ -+ /** @mcnmvrr: flag for Negative M VRR support */ -+ bool cnmvrr; -+ -+ /** @mcinema_vrr: flag for Cinema VRR support */ -+ bool cinema_vrr; -+ -+ /** @mdelta: flag for limited frame-to-frame compensation support */ -+ bool mdelta; -+ -+ /** -+ * @vrr_min : minimum supported variable refresh rate in Hz. -+ * Valid values only inide 1 - 48 range -+ */ -+ u16 vrr_min; -+ -+ /** -+ * @vrr_max : maximum supported variable refresh rate in Hz (optional). -+ * Valid values are either 0 (max based on video mode) or >= 100 -+ */ -+ u16 vrr_max; -+ -+ /** -+ * @supported: flag for vrr support based on checking for VRRmin and -+ * VRRmax values having correct values. -+ */ -+ bool supported; -+}; -+ - /** - * struct drm_hdmi_dsc_cap - DSC capabilities of HDMI sink - * -@@ -330,6 +368,15 @@ struct drm_hdmi_info { - /** @max_lanes: supported by sink */ - u8 max_lanes; - -+ /** @fapa_start_location: flag for the FAPA in blanking support */ -+ bool fapa_start_location; -+ -+ /** @allm: flag for Auto Low Latency Mode support by sink */ -+ bool allm; -+ -+ /** @vrr_cap: VRR capabilities of the sink */ -+ struct drm_hdmi_vrr_cap vrr_cap; -+ - /** @dsc_cap: DSC capabilities of the sink */ - struct drm_hdmi_dsc_cap dsc_cap; - }; diff --git a/kernel/0450-amd-hdmi-vrr-allm.patch.sig b/kernel/0450-amd-hdmi-vrr-allm.patch.sig deleted file mode 100644 index 186828c..0000000 Binary files a/kernel/0450-amd-hdmi-vrr-allm.patch.sig and /dev/null differ diff --git a/kernel/0451-amd-vtem-tmds-links.patch b/kernel/0451-amd-vtem-tmds-links.patch deleted file mode 100644 index 5bc46ad..0000000 --- a/kernel/0451-amd-vtem-tmds-links.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -10089,7 +10089,10 @@ static void update_freesync_state_on_stream( - &vrr_infopacket, - pack_sdp_v1_3); - -- if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) -+ /* Per HDMI 2.1, VTEM is valid on TMDS as well as FRL */ -+ if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL || -+ (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && -+ aconn && aconn->base.display_info.hdmi.vrr_cap.supported)) - mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket); - - new_crtc_state->freesync_vrr_info_changed |= diff --git a/kernel/0451-amd-vtem-tmds-links.patch.sig b/kernel/0451-amd-vtem-tmds-links.patch.sig deleted file mode 100644 index ce4d4da..0000000 Binary files a/kernel/0451-amd-vtem-tmds-links.patch.sig and /dev/null differ diff --git a/kernel/0452-amd-hdmi-frl-default.patch b/kernel/0452-amd-hdmi-frl-default.patch deleted file mode 100644 index e392ccc..0000000 --- a/kernel/0452-amd-hdmi-frl-default.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c -index 1aed121f4ddb..081de37c2083 100644 ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c -@@ -216,8 +216,9 @@ int amdgpu_smu_pptable_id = -1; - * DISABLE_FRACTIONAL_PWM (bit 2) disabled by default - * PSR (bit 3) disabled by default - * EDP NO POWER SEQUENCING (bit 4) disabled by default -+ * FRL (bit 10) enabled by default - */ --uint amdgpu_dc_feature_mask = 2; -+uint amdgpu_dc_feature_mask = DC_MULTI_MON_PP_MCLK_SWITCH_MASK | DC_FRL_MASK; - uint amdgpu_dc_debug_mask; - uint amdgpu_dc_visual_confirm; - int amdgpu_async_gfx_ring = 1; -diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h -index 3fd38323a88b..bdd80c5e378e 100644 ---- a/drivers/gpu/drm/amd/include/amd_shared.h -+++ b/drivers/gpu/drm/amd/include/amd_shared.h -@@ -287,7 +287,7 @@ enum DC_FEATURE_MASK { - */ - DC_REPLAY_MASK = (1 << 9), - /** -- * @DC_FRL_MASK: (0x400) disabled by default -+ * @DC_FRL_MASK: (0x400) enabled by default - */ - DC_FRL_MASK = (1 << 10), - }; diff --git a/kernel/0452-amd-hdmi-frl-default.patch.sig b/kernel/0452-amd-hdmi-frl-default.patch.sig deleted file mode 100644 index c879559..0000000 Binary files a/kernel/0452-amd-hdmi-frl-default.patch.sig and /dev/null differ diff --git a/kernel/0453-amd-vtem-null-sink.patch b/kernel/0453-amd-vtem-null-sink.patch deleted file mode 100644 index 0a3c3d3..0000000 --- a/kernel/0453-amd-vtem-null-sink.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -10090,8 +10090,8 @@ static void update_freesync_state_on_stream( - pack_sdp_v1_3); - - /* Per HDMI 2.1, VTEM is valid on TMDS as well as FRL */ -- if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL || -- (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && -+ if (new_stream->signal == SIGNAL_TYPE_HDMI_FRL || -+ (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A && - aconn && aconn->base.display_info.hdmi.vrr_cap.supported)) - mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket); - diff --git a/kernel/0453-amd-vtem-null-sink.patch.sig b/kernel/0453-amd-vtem-null-sink.patch.sig deleted file mode 100644 index e8b34ac..0000000 Binary files a/kernel/0453-amd-vtem-null-sink.patch.sig and /dev/null differ diff --git a/kernel/0454-amd-hdmi-frl-status-polling.patch b/kernel/0454-amd-hdmi-frl-status-polling.patch deleted file mode 100644 index 62ada93..0000000 --- a/kernel/0454-amd-hdmi-frl-status-polling.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -2025,7 +2025,7 @@ static void hdmi_frl_status_polling_work(struct work_struct *work) - if (!dc_is_hdmi_signal(dc_link->connector_signal)) - continue; - -- if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL) -+ if (dc_link->frl_link_settings.frl_link_rate == 0) - continue; - - link_update = dc_link_frl_poll_status_flag(dc_link); diff --git a/kernel/0454-amd-hdmi-frl-status-polling.patch.sig b/kernel/0454-amd-hdmi-frl-status-polling.patch.sig deleted file mode 100644 index 0f7a5ed..0000000 Binary files a/kernel/0454-amd-hdmi-frl-status-polling.patch.sig and /dev/null differ diff --git a/kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch b/kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch deleted file mode 100644 index 26db142..0000000 --- a/kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c ---- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c -+++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c -@@ -882,7 +882,7 @@ static void verify_link_capability_non_destructive(struct dc_link *link) - else - link->verified_link_cap = dp_get_max_link_cap(link); - } else if (dc_is_hdmi_signal(link->local_sink->sink_signal)) { -- link->verified_link_cap = link->reported_link_cap; -+ link->frl_verified_link_cap = link->frl_reported_link_cap; - - if (is_hdmi_frl_in_use(link)) { - link->local_sink->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; diff --git a/kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch.sig b/kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch.sig deleted file mode 100644 index 757e147..0000000 Binary files a/kernel/0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch.sig and /dev/null differ diff --git a/kernel/0456-amd-dml-frl-compressed-cap-check.patch b/kernel/0456-amd-dml-frl-compressed-cap-check.patch deleted file mode 100644 index 4531604..0000000 --- a/kernel/0456-amd-dml-frl-compressed-cap-check.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c ---- a/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c -+++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_frl_cap_chk.c -@@ -630,17 +630,17 @@ enum frl_cap_chk_result dml1_frl_cap_chk(struct frl_cap_chk_params *params) - { - struct frl_cap_chk_intermediates inter; - --#if defined (CONFIG_DRM_AMD_DC_FP) -- if (params->compressed) -- return dml1_frl_cap_chk_compressed(params, &inter); --#endif -- - return dml1_frl_cap_chk_inter(params, &inter); - } - - enum frl_cap_chk_result dml1_frl_cap_chk_inter(struct frl_cap_chk_params *params, - struct frl_cap_chk_intermediates *inter) - { -+#if defined (CONFIG_DRM_AMD_DC_FP) -+ if (params->compressed) -+ return dml1_frl_cap_chk_compressed(params, inter); -+#endif -+ - return dml1_frl_cap_chk_uncompressed(params, inter); - } - diff --git a/kernel/0456-amd-dml-frl-compressed-cap-check.patch.sig b/kernel/0456-amd-dml-frl-compressed-cap-check.patch.sig deleted file mode 100644 index 3ebb7c2..0000000 Binary files a/kernel/0456-amd-dml-frl-compressed-cap-check.patch.sig and /dev/null differ diff --git a/kernel/0460-vesa-displayid-dsc-bpp.patch b/kernel/0460-vesa-displayid-dsc-bpp.patch deleted file mode 100644 index 7597723..0000000 --- a/kernel/0460-vesa-displayid-dsc-bpp.patch +++ /dev/null @@ -1,335 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -7116,6 +7116,11 @@ static void fill_stream_properties_from_drm_display_mode( - - stream->output_color_space = get_output_color_space(timing_out, connector_state); - stream->content_type = get_output_content_type(connector_state); -+ -+ /* DisplayID Type VII pass-through timings. */ -+ if (mode_in->dsc_passthrough_timings_support && info->dp_dsc_bpp_x16 != 0) { -+ stream->timing.dsc_fixed_bits_per_pixel_x16 = info->dp_dsc_bpp_x16; -+ } - } - - static void fill_audio_info(struct audio_info *audio_info, -@@ -7636,6 +7641,7 @@ create_stream_for_sink(struct drm_connector *connector, - struct drm_display_mode mode; - struct drm_display_mode saved_mode; - struct drm_display_mode *freesync_mode = NULL; -+ struct drm_display_mode *dsc_passthru_mode = NULL; - bool native_mode_found = false; - bool recalculate_timing = false; - bool scale = dm_state->scaling != RMX_OFF; -@@ -7727,6 +7733,16 @@ create_stream_for_sink(struct drm_connector *connector, - } - } - -+ list_for_each_entry(dsc_passthru_mode, &connector->modes, head) { -+ if (dsc_passthru_mode->hdisplay == mode.hdisplay && -+ dsc_passthru_mode->vdisplay == mode.vdisplay && -+ drm_mode_vrefresh(dsc_passthru_mode) == mode_refresh) { -+ mode.dsc_passthrough_timings_support = -+ dsc_passthru_mode->dsc_passthrough_timings_support; -+ break; -+ } -+ } -+ - if (recalculate_timing) - drm_mode_set_crtcinfo(&saved_mode, 0); - -diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h ---- a/drivers/gpu/drm/drm_displayid_internal.h -+++ b/drivers/gpu/drm/drm_displayid_internal.h -@@ -98,6 +98,7 @@ struct displayid_header { - u8 ext_count; - } __packed; - -+#define DISPLAYID_BLOCK_REV GENMASK(2, 0) - struct displayid_block { - u8 tag; - u8 rev; -@@ -126,6 +127,7 @@ struct displayid_detailed_timings_1 { - __le16 vsw; - } __packed; - -+#define DISPLAYID_BLOCK_PASSTHROUGH_TIMINGS_SUPPORT BIT(3) - struct displayid_detailed_timing_block { - struct displayid_block base; - struct displayid_detailed_timings_1 timings[]; -@@ -138,19 +140,28 @@ struct displayid_formula_timings_9 { - u8 vrefresh; - } __packed; - -+#define DISPLAYID_BLOCK_DESCRIPTOR_PAYLOAD_BYTES GENMASK(6, 4) - struct displayid_formula_timing_block { - struct displayid_block base; - struct displayid_formula_timings_9 timings[]; - } __packed; - -+#define DISPLAYID_VESA_DP_TYPE GENMASK(2, 0) - #define DISPLAYID_VESA_MSO_OVERLAP GENMASK(3, 0) - #define DISPLAYID_VESA_MSO_MODE GENMASK(6, 5) -+#define DISPLAYID_VESA_DSC_BPP_INT GENMASK(5, 0) -+#define DISPLAYID_VESA_DSC_BPP_FRACT GENMASK(3, 0) -+ -+#define DISPLAYID_VESA_DP_TYPE_EDP 0 -+#define DISPLAYID_VESA_DP_TYPE_DP 1 - - struct displayid_vesa_vendor_specific_block { - struct displayid_block base; - u8 oui[3]; - u8 data_structure_type; - u8 mso; -+ u8 dsc_bpp_int; -+ u8 dsc_bpp_fract; - } __packed; - - /* -diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c ---- a/drivers/gpu/drm/drm_edid.c -+++ b/drivers/gpu/drm/drm_edid.c -@@ -45,6 +45,7 @@ - #include - #include - #include -+#include - #include - - #include "drm_crtc_internal.h" -@@ -6683,12 +6684,13 @@ static bool drm_update_displayid_adaptive_sync_range(struct drm_connector *conne - return false; - } - --static void drm_parse_vesa_mso_data(struct drm_connector *connector, -- const struct displayid_block *block) -+static void drm_parse_vesa_specific_block(struct drm_connector *connector, -+ const struct displayid_block *block) - { - struct displayid_vesa_vendor_specific_block *vesa = - (struct displayid_vesa_vendor_specific_block *)block; - struct drm_display_info *info = &connector->display_info; -+ int dp_type; - - if (block->num_bytes < 3) { - drm_dbg_kms(connector->dev, -@@ -6700,51 +6702,73 @@ static void drm_parse_vesa_mso_data(struct drm_connector *connector, - if (oui(vesa->oui[0], vesa->oui[1], vesa->oui[2]) != VESA_IEEE_OUI) - return; - -- if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) { -+ if (block->num_bytes < 5) { - drm_dbg_kms(connector->dev, - "[CONNECTOR:%d:%s] Unexpected VESA vendor block size\n", - connector->base.id, connector->name); - return; - } - -- switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) { -- default: -- drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Reserved MSO mode value\n", -+ dp_type = FIELD_GET(DISPLAYID_VESA_DP_TYPE, vesa->data_structure_type); -+ if (dp_type > 1) { -+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Reserved dp type value\n", - connector->base.id, connector->name); -- fallthrough; -- case 0: -- info->mso_stream_count = 0; -- break; -- case 1: -- info->mso_stream_count = 2; /* 2 or 4 links */ -- break; -- case 2: -- info->mso_stream_count = 4; /* 4 links */ -- break; - } - -- if (!info->mso_stream_count) { -+ /* MSO is only supported for eDP */ -+ if (dp_type == DISPLAYID_VESA_DP_TYPE_EDP) { -+ switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) { -+ default: -+ drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Reserved MSO mode value\n", -+ connector->base.id, connector->name); -+ fallthrough; -+ case 0: -+ info->mso_stream_count = 0; -+ break; -+ case 1: -+ info->mso_stream_count = 2; /* 2 or 4 links */ -+ break; -+ case 2: -+ info->mso_stream_count = 4; /* 4 links */ -+ break; -+ } -+ } -+ -+ if (info->mso_stream_count) { -+ info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP, vesa->mso); -+ if (info->mso_pixel_overlap > 8) { -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] Reserved MSO pixel overlap value %u\n", -+ connector->base.id, connector->name, -+ info->mso_pixel_overlap); -+ info->mso_pixel_overlap = 8; -+ } -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] MSO stream count %u, pixel overlap %u\n", -+ connector->base.id, connector->name, -+ info->mso_stream_count, info->mso_pixel_overlap); -+ } else { - info->mso_pixel_overlap = 0; -+ } -+ -+ if (block->num_bytes < 7) { -+ /* DSC bpp is optional */ - return; - } - -- info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP, vesa->mso); -- if (info->mso_pixel_overlap > 8) { -- drm_dbg_kms(connector->dev, -- "[CONNECTOR:%d:%s] Reserved MSO pixel overlap value %u\n", -- connector->base.id, connector->name, -- info->mso_pixel_overlap); -- info->mso_pixel_overlap = 8; -- } -+ info->dp_dsc_bpp_x16 = FIELD_GET(DISPLAYID_VESA_DSC_BPP_INT, vesa->dsc_bpp_int) << 4 | -+ FIELD_GET(DISPLAYID_VESA_DSC_BPP_FRACT, vesa->dsc_bpp_fract); - -- drm_dbg_kms(connector->dev, -- "[CONNECTOR:%d:%s] MSO stream count %u, pixel overlap %u\n", -- connector->base.id, connector->name, -- info->mso_stream_count, info->mso_pixel_overlap); -+ if (info->dp_dsc_bpp_x16 > 0) { -+ drm_dbg_kms(connector->dev, -+ "[CONNECTOR:%d:%s] DSC bits per pixel " FXP_Q4_FMT "\n", -+ connector->base.id, connector->name, -+ FXP_Q4_ARGS(info->dp_dsc_bpp_x16)); -+ } - } - --static void drm_update_mso(struct drm_connector *connector, -- const struct drm_edid *drm_edid) -+static void drm_update_vesa_specific_block(struct drm_connector *connector, -+ const struct drm_edid *drm_edid) - { - const struct displayid_block *block; - struct displayid_iter iter; -@@ -6752,7 +6776,7 @@ static void drm_update_mso(struct drm_connector *connector, - displayid_iter_edid_begin(drm_edid, &iter); - displayid_iter_for_each(block, &iter) { - if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC) -- drm_parse_vesa_mso_data(connector, block); -+ drm_parse_vesa_specific_block(connector, block); - } - displayid_iter_end(&iter); - } -@@ -6789,6 +6813,7 @@ static void drm_reset_display_info(struct drm_connector *connector) - info->mso_stream_count = 0; - info->mso_pixel_overlap = 0; - info->max_dsc_bpp = 0; -+ info->dp_dsc_bpp_x16 = 0; - - kfree(info->vics); - info->vics = NULL; -@@ -6930,7 +6955,7 @@ static void update_display_info(struct drm_connector *connector, - if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) - info->color_formats |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422); - -- drm_update_mso(connector, drm_edid); -+ drm_update_vesa_specific_block(connector, drm_edid); - - out: - if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_NON_DESKTOP)) { -@@ -6960,8 +6985,8 @@ static void update_display_info(struct drm_connector *connector, - } - - static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev, -- const struct displayid_detailed_timings_1 *timings, -- bool type_7) -+ const struct displayid_block *block, -+ const struct displayid_detailed_timings_1 *timings) - { - struct drm_display_mode *mode; - unsigned int pixel_clock = (timings->pixel_clock[0] | -@@ -6977,11 +7002,16 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d - unsigned int vsync_width = le16_to_cpu(timings->vsw) + 1; - bool hsync_positive = le16_to_cpu(timings->hsync) & (1 << 15); - bool vsync_positive = le16_to_cpu(timings->vsync) & (1 << 15); -+ bool type_7 = block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING; - - mode = drm_mode_create(dev); - if (!mode) - return NULL; - -+ if (type_7 && FIELD_GET(DISPLAYID_BLOCK_REV, block->rev) >= 1) -+ mode->dsc_passthrough_timings_support = -+ block->rev & DISPLAYID_BLOCK_PASSTHROUGH_TIMINGS_SUPPORT; -+ - /* resolution is kHz for type VII, and 10 kHz for type I */ - mode->clock = type_7 ? pixel_clock : pixel_clock * 10; - mode->hdisplay = hactive; -@@ -7014,7 +7044,6 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, - int num_timings; - struct drm_display_mode *newmode; - int num_modes = 0; -- bool type_7 = block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING; - /* blocks must be multiple of 20 bytes length */ - if (block->num_bytes % 20) - return 0; -@@ -7023,7 +7052,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, - for (i = 0; i < num_timings; i++) { - struct displayid_detailed_timings_1 *timings = &det->timings[i]; - -- newmode = drm_mode_displayid_detailed(connector->dev, timings, type_7); -+ newmode = drm_mode_displayid_detailed(connector->dev, block, timings); - if (!newmode) - continue; - -@@ -7070,7 +7099,8 @@ static int add_displayid_formula_modes(struct drm_connector *connector, - struct drm_display_mode *newmode; - int num_modes = 0; - bool type_10 = block->tag == DATA_BLOCK_2_TYPE_10_FORMULA_TIMING; -- int timing_size = 6 + ((formula_block->base.rev & 0x70) >> 4); -+ int timing_size = 6 + -+ FIELD_GET(DISPLAYID_BLOCK_DESCRIPTOR_PAYLOAD_BYTES, formula_block->base.rev); - - /* extended blocks are not supported yet */ - if (timing_size != 6) -diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h ---- a/include/drm/drm_connector.h -+++ b/include/drm/drm_connector.h -@@ -939,6 +939,12 @@ struct drm_display_info { - */ - u32 max_dsc_bpp; - -+ /** -+ * @dp_dsc_bpp: DP Display-Stream-Compression (DSC) timing's target -+ * DSC bits per pixel in 6.4 fixed point format. 0 means undefined. -+ */ -+ u16 dp_dsc_bpp_x16; -+ - /** - * @vics: Array of vics_len VICs. Internal to EDID parsing. - */ -diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h ---- a/include/drm/drm_modes.h -+++ b/include/drm/drm_modes.h -@@ -417,6 +417,16 @@ struct drm_display_mode { - */ - enum hdmi_picture_aspect picture_aspect_ratio; - -+ /** -+ * @dsc_passthrough_timing_support: -+ * -+ * Indicates whether this mode timing descriptor is supported -+ * with specific target DSC bits per pixel only. -+ * -+ * VESA vendor-specific data block shall exist with the relevant -+ * DSC bits per pixel declaration when this flag is set to true. -+ */ -+ bool dsc_passthrough_timings_support; - }; - - /** diff --git a/kernel/0460-vesa-displayid-dsc-bpp.patch.sig b/kernel/0460-vesa-displayid-dsc-bpp.patch.sig deleted file mode 100644 index 51e6458..0000000 Binary files a/kernel/0460-vesa-displayid-dsc-bpp.patch.sig and /dev/null differ diff --git a/kernel/0461-vesa-dsc-passthru-mode-match-fix.patch b/kernel/0461-vesa-dsc-passthru-mode-match-fix.patch deleted file mode 100644 index b826d02..0000000 --- a/kernel/0461-vesa-dsc-passthru-mode-match-fix.patch +++ /dev/null @@ -1,51 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -7642,6 +7642,7 @@ create_stream_for_sink(struct drm_connector *connector, - struct drm_display_mode saved_mode; - struct drm_display_mode *freesync_mode = NULL; - struct drm_display_mode *dsc_passthru_mode = NULL; -+ unsigned int dsc_passthru_match_flags; - bool native_mode_found = false; - bool recalculate_timing = false; - bool scale = dm_state->scaling != RMX_OFF; -@@ -7708,6 +7709,22 @@ create_stream_for_sink(struct drm_connector *connector, - - mode_refresh = drm_mode_vrefresh(&mode); - -+ dsc_passthru_match_flags = DRM_MODE_MATCH_TIMINGS | -+ DRM_MODE_MATCH_CLOCK | -+ DRM_MODE_MATCH_FLAGS | -+ DRM_MODE_MATCH_3D_FLAGS; -+ if (mode.picture_aspect_ratio) -+ dsc_passthru_match_flags |= DRM_MODE_MATCH_ASPECT_RATIO; -+ -+ list_for_each_entry(dsc_passthru_mode, &connector->modes, head) { -+ if (drm_mode_match(dsc_passthru_mode, &mode, -+ dsc_passthru_match_flags)) { -+ mode.dsc_passthrough_timings_support = -+ dsc_passthru_mode->dsc_passthrough_timings_support; -+ break; -+ } -+ } -+ - if (preferred_mode == NULL) { - /* - * This may not be an error, the use case is when we have no -@@ -7733,16 +7750,6 @@ create_stream_for_sink(struct drm_connector *connector, - } - } - -- list_for_each_entry(dsc_passthru_mode, &connector->modes, head) { -- if (dsc_passthru_mode->hdisplay == mode.hdisplay && -- dsc_passthru_mode->vdisplay == mode.vdisplay && -- drm_mode_vrefresh(dsc_passthru_mode) == mode_refresh) { -- mode.dsc_passthrough_timings_support = -- dsc_passthru_mode->dsc_passthrough_timings_support; -- break; -- } -- } -- - if (recalculate_timing) - drm_mode_set_crtcinfo(&saved_mode, 0); - diff --git a/kernel/0461-vesa-dsc-passthru-mode-match-fix.patch.sig b/kernel/0461-vesa-dsc-passthru-mode-match-fix.patch.sig deleted file mode 100644 index 09c45c3..0000000 Binary files a/kernel/0461-vesa-dsc-passthru-mode-match-fix.patch.sig and /dev/null differ diff --git a/kernel/0472-amdgpu-userq-post-reset-error.patch b/kernel/0472-amdgpu-userq-post-reset-error.patch deleted file mode 100644 index 942772c..0000000 --- a/kernel/0472-amdgpu-userq-post-reset-error.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c -@@ -1426,7 +1426,7 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost) - struct amdgpu_usermode_queue *queue; - const struct amdgpu_userq_funcs *userq_funcs; - unsigned long queue_id; -- int r = 0; -+ int ret = 0, r; - - xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) { - if (queue->state == AMDGPU_USERQ_STATE_HUNG && !vram_lost) { -@@ -1435,11 +1435,12 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost) - r = userq_funcs->map(queue); - if (r) { - dev_err(adev->dev, "Failed to remap queue %ld\n", queue_id); -+ ret = r; - continue; - } - queue->state = AMDGPU_USERQ_STATE_MAPPED; - } - } - -- return r; -+ return ret; - } diff --git a/kernel/0472-amdgpu-userq-post-reset-error.patch.sig b/kernel/0472-amdgpu-userq-post-reset-error.patch.sig deleted file mode 100644 index a79ea43..0000000 Binary files a/kernel/0472-amdgpu-userq-post-reset-error.patch.sig and /dev/null differ diff --git a/kernel/0474-amd-display-oled-vesa-backlight.patch b/kernel/0474-amd-display-oled-vesa-backlight.patch deleted file mode 100644 index 035758b..0000000 --- a/kernel/0474-amd-display-oled-vesa-backlight.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -4176,8 +4176,12 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) - else if (!IS_ERR_OR_NULL(panel_backlight_quirk) && - panel_backlight_quirk->force_pwm) - caps->aux_support = false; -- if (caps->aux_support) -- aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; -+ if (caps->aux_support) { -+ if (aconnector->dc_link->dpcd_caps.panel_luminance_control) -+ aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_VESA_AUX; -+ else -+ aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; -+ } - - luminance_range = &conn_base->display_info.luminance_range; - diff --git a/kernel/0474-amd-display-oled-vesa-backlight.patch.sig b/kernel/0474-amd-display-oled-vesa-backlight.patch.sig deleted file mode 100644 index 3f0768a..0000000 Binary files a/kernel/0474-amd-display-oled-vesa-backlight.patch.sig and /dev/null differ diff --git a/kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch b/kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch deleted file mode 100644 index a58a962..0000000 --- a/kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c ---- a/drivers/gpu/drm/i915/display/intel_dp.c -+++ b/drivers/gpu/drm/i915/display/intel_dp.c -@@ -3219,11 +3219,7 @@ static bool intel_dp_needs_as_sdp(struct intel_dp *intel_dp, - if (drm_dp_is_branch(intel_dp->dpcd)) - return false; - -- if (intel_psr_needs_alpm_aux_less(intel_dp, crtc_state) && -- !intel_psr_pr_async_video_timing_supported(intel_dp)) -- return true; -- -- return intel_vrr_possible(crtc_state); -+ return crtc_state->vrr.enable; - } - - static void intel_dp_compute_as_sdp(struct intel_dp *intel_dp, diff --git a/kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch.sig b/kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch.sig deleted file mode 100644 index 3ddfad0..0000000 Binary files a/kernel/0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch.sig and /dev/null differ diff --git a/kernel/0476-amd-display-ycbcr420-only-modes.patch b/kernel/0476-amd-display-ycbcr420-only-modes.patch deleted file mode 100644 index 8d6c8a4..0000000 --- a/kernel/0476-amd-display-ycbcr420-only-modes.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -7020,16 +7020,11 @@ static void fill_stream_properties_from_drm_display_mode( - timing_out->v_border_top = 0; - timing_out->v_border_bottom = 0; - /* TODO: un-hardcode */ -- if (drm_mode_is_420_only(info, mode_in) -- && (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || -- stream->signal == SIGNAL_TYPE_HDMI_FRL) -- && aconnector -- && aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420) -- timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; -- else if (drm_mode_is_420_also(info, mode_in) -- && aconnector -- && (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420 -- || aconnector->force_yuv420_output)) -+ if (drm_mode_is_420_only(info, mode_in) || -+ (aconnector && -+ (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420 || -+ aconnector->force_yuv420_output) && -+ drm_mode_is_420_also(info, mode_in))) - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; - else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) - && aconnector diff --git a/kernel/0476-amd-display-ycbcr420-only-modes.patch.sig b/kernel/0476-amd-display-ycbcr420-only-modes.patch.sig deleted file mode 100644 index bf85c11..0000000 Binary files a/kernel/0476-amd-display-ycbcr420-only-modes.patch.sig and /dev/null differ diff --git a/kernel/0477-amd-display-irq-atomic-rmw.patch b/kernel/0477-amd-display-irq-atomic-rmw.patch deleted file mode 100644 index 1b0eb75..0000000 --- a/kernel/0477-amd-display-irq-atomic-rmw.patch +++ /dev/null @@ -1,303 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -3345,7 +3345,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, - if (acrtc && state->stream_status[i].plane_count != 0 && - amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) { - irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst; -- rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; -+ rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY; - if (rc) - drm_warn(adev_to_drm(adev), "Failed to %s pflip interrupts\n", - enable ? "enable" : "disable"); -@@ -3369,7 +3369,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, - /* During gpu-reset we disable and then enable vblank irq, so - * don't use amdgpu_irq_get/put() to avoid refcount change. - */ -- if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) -+ if (!amdgpu_dm_irq_set(adev, irq_source, enable)) - drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis"); - - } else if (acrtc && state->stream_status[i].plane_count != 0) { -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h -@@ -550,6 +550,18 @@ struct amdgpu_display_manager { - struct common_irq_params - vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1]; - -+ /** -+ * @irq_reg_lock: -+ * -+ * Serializes the read-modify-writes of the HW interrupt control -+ * registers. Several interrupt sources share one register - e.g. the -+ * enable and clear bits of both VSTARTUP (vblank) and VUPDATE_NO_LOCK -+ * live in OTG_GLOBAL_SYNC_STATUS. Therefore, enabling one source must -+ * not race with acking another. Held only across amdgpu_dm_irq_set() -+ * and amdgpu_dm_irq_ack(). -+ */ -+ spinlock_t irq_reg_lock; -+ - /** - * @dmub_trace_params: - * -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c -@@ -31,6 +31,7 @@ - #include "amdgpu_dm_psr.h" - #include "amdgpu_dm_replay.h" - #include "amdgpu_dm_crtc.h" -+#include "amdgpu_dm_irq.h" - #include "amdgpu_dm_plane.h" - #include "amdgpu_dm_trace.h" - #include "amdgpu_dm_debugfs.h" -@@ -87,7 +88,7 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable) - - irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst; - -- rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; -+ rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY; - - DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n", - acrtc->crtc_id, enable ? "en" : "dis", rc); -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c -@@ -1378,12 +1378,13 @@ void dm_helpers_free_gpu_mem( - - bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable) - { -+ struct amdgpu_device *adev = ctx->driver_context; - enum dc_irq_source irq_source; - bool ret; - - irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX; - -- ret = dc_interrupt_set(ctx->dc, irq_source, enable); -+ ret = amdgpu_dm_irq_set(adev, irq_source, enable); - - DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n", - enable ? "en" : "dis", ret); -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c -@@ -424,6 +424,7 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev) - DRM_DEBUG_KMS("DM_IRQ\n"); - - spin_lock_init(&adev->dm.irq_handler_list_table_lock); -+ spin_lock_init(&adev->dm.irq_reg_lock); - - for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) { - /* low context handler list init */ -@@ -496,7 +497,7 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev) - hnd_list_l = &adev->dm.irq_handler_list_low_tab[src]; - hnd_list_h = &adev->dm.irq_handler_list_high_tab[src]; - if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h)) -- dc_interrupt_set(adev->dm.dc, src, false); -+ amdgpu_dm_irq_set(adev, src, false); - - DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags); - -@@ -533,7 +534,7 @@ void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev) - hnd_list_l = &adev->dm.irq_handler_list_low_tab[src]; - hnd_list_h = &adev->dm.irq_handler_list_high_tab[src]; - if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h)) -- dc_interrupt_set(adev->dm.dc, src, true); -+ amdgpu_dm_irq_set(adev, src, true); - } - - DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags); -@@ -558,7 +559,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev) - hnd_list_l = &adev->dm.irq_handler_list_low_tab[src]; - hnd_list_h = &adev->dm.irq_handler_list_high_tab[src]; - if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h)) -- dc_interrupt_set(adev->dm.dc, src, true); -+ amdgpu_dm_irq_set(adev, src, true); - } - - DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags); -@@ -645,6 +646,21 @@ static void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev, - DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags); - } - -+bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src, -+ bool enable) -+{ -+ guard(spinlock_irqsave)(&adev->dm.irq_reg_lock); -+ -+ return dc_interrupt_set(adev->dm.dc, src, enable); -+} -+ -+void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src) -+{ -+ guard(spinlock_irqsave)(&adev->dm.irq_reg_lock); -+ -+ dc_interrupt_ack(adev->dm.dc, src); -+} -+ - /** - * amdgpu_dm_irq_handler - Generic DM IRQ handler - * @adev: amdgpu base driver device containing the DM device -@@ -665,7 +681,7 @@ static int amdgpu_dm_irq_handler(struct amdgpu_device *adev, - entry->src_id, - entry->src_data[0]); - -- dc_interrupt_ack(adev->dm.dc, src); -+ amdgpu_dm_irq_ack(adev, src); - - /* Call high irq work immediately */ - amdgpu_dm_irq_immediate_work(adev, src); -@@ -703,7 +719,7 @@ static int amdgpu_dm_set_hpd_irq_state(struct amdgpu_device *adev, - enum dc_irq_source src = amdgpu_dm_hpd_to_dal_irq_source(type); - bool st = (state == AMDGPU_IRQ_STATE_ENABLE); - -- dc_interrupt_set(adev->dm.dc, src, st); -+ amdgpu_dm_irq_set(adev, src, st); - return 0; - } - -@@ -737,7 +753,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev, - if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed) - dc_allow_idle_optimizations(dc, false); - -- dc_interrupt_set(adev->dm.dc, irq_source, st); -+ amdgpu_dm_irq_set(adev, irq_source, st); - return 0; - } - -@@ -791,7 +807,7 @@ static int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *adev, - enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX; - bool st = (state == AMDGPU_IRQ_STATE_ENABLE); - -- dc_interrupt_set(adev->dm.dc, irq_source, st); -+ amdgpu_dm_irq_set(adev, irq_source, st); - return 0; - } - -@@ -817,7 +833,7 @@ static int amdgpu_dm_set_dmub_trace_irq_state(struct amdgpu_device *adev, - enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX0; - bool st = (state == AMDGPU_IRQ_STATE_ENABLE); - -- dc_interrupt_set(adev->dm.dc, irq_source, st); -+ amdgpu_dm_irq_set(adev, irq_source, st); - return 0; - } - -@@ -881,9 +897,7 @@ void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev) - } - void amdgpu_dm_outbox_init(struct amdgpu_device *adev) - { -- dc_interrupt_set(adev->dm.dc, -- DC_IRQ_SOURCE_DMCUB_OUTBOX, -- true); -+ amdgpu_dm_irq_set(adev, DC_IRQ_SOURCE_DMCUB_OUTBOX, true); - } - - /** -@@ -905,7 +919,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) - - /* First, clear all hpd and hpdrx interrupts */ - for (i = DC_IRQ_SOURCE_HPD1; i <= DC_IRQ_SOURCE_HPD6RX; i++) { -- if (!dc_interrupt_set(adev->dm.dc, i, false)) -+ if (!amdgpu_dm_irq_set(adev, i, false)) - drm_err(dev, "Failed to clear hpd(rx) source=%d on init\n", - i); - } -@@ -934,7 +948,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) - * of dm. Note that only hpd interrupt types are registered with - * base driver; hpd_rx types aren't. IOW, amdgpu_irq_get/put on - * hpd_rx isn't available. DM currently controls hpd_rx -- * explicitly with dc_interrupt_set() -+ * explicitly with amdgpu_dm_irq_set() - */ - if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) { - irq_type = dc_link->irq_source_hpd - DC_IRQ_SOURCE_HPD1; -@@ -943,23 +957,21 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) - * and what bios reports as the # of connectors with hpd - * sources. Since the # of hpd source types registered - * with base driver == mode_info.num_hpd, we have to -- * fallback to dc_interrupt_set for the remaining types. -+ * fallback to amdgpu_dm_irq_set for the remaining types. - */ - if (irq_type < adev->mode_info.num_hpd) { - if (amdgpu_irq_get(adev, &adev->hpd_irq, irq_type)) - drm_err(dev, "DM_IRQ: Failed get HPD for source=%d)!\n", - dc_link->irq_source_hpd); - } else { -- dc_interrupt_set(adev->dm.dc, -- dc_link->irq_source_hpd, -- true); -+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd, -+ true); - } - } - - if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) { -- dc_interrupt_set(adev->dm.dc, -- dc_link->irq_source_hpd_rx, -- true); -+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx, -+ true); - } - } - drm_connector_list_iter_end(&iter); -@@ -1003,16 +1015,14 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev) - drm_err(dev, "DM_IRQ: Failed put HPD for source=%d!\n", - dc_link->irq_source_hpd); - } else { -- dc_interrupt_set(adev->dm.dc, -- dc_link->irq_source_hpd, -- false); -+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd, -+ false); - } - } - - if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) { -- dc_interrupt_set(adev->dm.dc, -- dc_link->irq_source_hpd_rx, -- false); -+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx, -+ false); - } - } - drm_connector_list_iter_end(&iter); -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h -@@ -81,6 +81,34 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev, - enum dc_irq_source irq_source, - void *ih_index); - -+/** -+ * amdgpu_dm_irq_set - enable or disable a DC interrupt source. -+ * -+ * @adev: AMD DRM device -+ * @src: DC interrupt source to toggle -+ * @enable: true to enable the source, false to disable it -+ * -+ * DM-wide replacement for dc_interrupt_set(). As locking is DM's -+ * responsibility, this is a thin wrapper serializes the underlying -+ * read-modify-write against the other interrupt sources sharing HW control -+ * registers with @src, so DM must never call dc_interrupt_set() directly. -+ * -+ * Returns: true if the source was toggled. -+ */ -+bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src, -+ bool enable); -+ -+/** -+ * amdgpu_dm_irq_ack - acknowledge a DC interrupt source. -+ * -+ * @adev: AMD DRM device -+ * @src: DC interrupt source to acknowledge -+ * -+ * DM-wide replacement for dc_interrupt_ack(), serialized the same way as -+ * amdgpu_dm_irq_set(). -+ */ -+void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src); -+ - void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev); - - void amdgpu_dm_outbox_init(struct amdgpu_device *adev); diff --git a/kernel/0477-amd-display-irq-atomic-rmw.patch.sig b/kernel/0477-amd-display-irq-atomic-rmw.patch.sig deleted file mode 100644 index ffb08a4..0000000 Binary files a/kernel/0477-amd-display-irq-atomic-rmw.patch.sig and /dev/null differ diff --git a/kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch b/kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch deleted file mode 100644 index dcdb282..0000000 --- a/kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -14232,6 +14232,12 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - } - } - -+ /* HDMI/PCON without an EDID FreeSync VCP code is not FreeSync-capable. */ -+ if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || -+ as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) && -+ !sink->edid_caps.freesync_vcp_code) -+ freesync_capable = false; -+ - /* Handle MCCS */ - if (do_mccs) { - dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); diff --git a/kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch.sig b/kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch.sig deleted file mode 100644 index 55dd043..0000000 Binary files a/kernel/0478-amd-freesync-vcp-code-check-hdmi-pcon.patch.sig and /dev/null differ diff --git a/kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch b/kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch deleted file mode 100644 index 13b9043..0000000 --- a/kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c -@@ -10135,20 +10135,19 @@ static void update_freesync_state_on_stream( - */ - if (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || - new_stream->signal == SIGNAL_TYPE_HDMI_FRL) { -- struct dc_info_packet hf_vsif = {0}; -+ struct dc_info_packet vsp_infopacket = {0}; - bool sink_allm = aconn && aconn->base.display_info.hdmi.allm; - bool allm = sink_allm && - (vrr_params.state == VRR_STATE_ACTIVE_VARIABLE || - vrr_params.state == VRR_STATE_ACTIVE_FIXED); - bool allm_changed; - -- if (allm) -- mod_build_hf_vsif_infopacket(new_stream, &hf_vsif, allm, allm); -+ mod_build_hf_vsif_infopacket(new_stream, &vsp_infopacket, allm, allm); - -- allm_changed = memcmp(&new_stream->hfvsif_infopacket, &hf_vsif, -- sizeof(hf_vsif)) != 0; -+ allm_changed = memcmp(&new_stream->vsp_infopacket, &vsp_infopacket, -+ sizeof(vsp_infopacket)) != 0; - new_crtc_state->freesync_vrr_info_changed |= allm_changed; -- new_stream->hfvsif_infopacket = hf_vsif; -+ new_stream->vsp_infopacket = vsp_infopacket; - - if (allm_changed) - drm_dbg_driver(adev_to_drm(adev), -@@ -10727,8 +10726,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, - if (acrtc_state->freesync_vrr_info_changed) { - bundle->stream_update.vrr_infopacket = - &acrtc_state->stream->vrr_infopacket; -- bundle->stream_update.hfvsif_infopacket = -- &acrtc_state->stream->hfvsif_infopacket; -+ bundle->stream_update.vsp_infopacket = -+ &acrtc_state->stream->vsp_infopacket; - } - } - } diff --git a/kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch.sig b/kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch.sig deleted file mode 100644 index 8cd5401..0000000 Binary files a/kernel/0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch.sig and /dev/null differ diff --git a/kernel/0510-sound-updates.patch b/kernel/0510-sound-updates.patch deleted file mode 100644 index 1368f53..0000000 --- a/kernel/0510-sound-updates.patch +++ /dev/null @@ -1,12141 +0,0 @@ -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -1757,6 +1757,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) - * by the drivers/platform/x86/serial-multi-instantiate.c driver, which - * knows which client device id to use for each resource. - */ -+ {"AWDZ8399", }, - {"BSG1160", }, - {"BSG2150", }, - {"CSC3551", }, -diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c ---- a/drivers/platform/x86/serial-multi-instantiate.c -+++ b/drivers/platform/x86/serial-multi-instantiate.c -@@ -307,6 +307,15 @@ static void smi_remove(struct platform_device *pdev) - smi_devs_unregister(smi); - } - -+static const struct smi_node aw88399_hda = { -+ .instances = { -+ { "aw88399-hda", IRQ_RESOURCE_AUTO, 0 }, -+ { "aw88399-hda", IRQ_RESOURCE_AUTO, 0 }, -+ {} -+ }, -+ .bus_type = SMI_AUTO_DETECT, -+}; -+ - static const struct smi_node bsg1160_data = { - .instances = { - { "bmc150_accel", IRQ_RESOURCE_GPIO, 0 }, -@@ -405,6 +414,7 @@ static const struct smi_node tas2781_hda = { - * drivers/acpi/scan.c: acpi_device_enumeration_by_parent(). - */ - static const struct acpi_device_id smi_acpi_ids[] = { -+ { "AWDZ8399", (unsigned long)&aw88399_hda }, - { "BSG1160", (unsigned long)&bsg1160_data }, - { "BSG2150", (unsigned long)&bsg2150_data }, - { "CSC3551", (unsigned long)&cs35l41_hda }, -diff --git a/include/sound/ac97/codec.h b/include/sound/ac97/codec.h ---- a/include/sound/ac97/codec.h -+++ b/include/sound/ac97/codec.h -@@ -33,7 +33,7 @@ struct ac97_id { - }; - - /** -- * ac97_codec_device - a ac97 codec -+ * struct ac97_codec_device - a ac97 codec - * @dev: the core device - * @vendor_id: the vendor_id of the codec, as sensed on the AC-link - * @num: the codec number, 0 is primary, 1 is first slave, etc ... -@@ -53,7 +53,7 @@ struct ac97_codec_device { - }; - - /** -- * ac97_codec_driver - a ac97 codec driver -+ * struct ac97_codec_driver - a ac97 codec driver - * @driver: the device driver structure - * @probe: the function called when a ac97_codec_device is matched - * @remove: the function called when the device is unbound/removed -diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h ---- a/include/sound/asequencer.h -+++ b/include/sound/asequencer.h -@@ -11,9 +11,6 @@ - #include - #include - --/* helper macro */ --#define snd_seq_event_bounce_ext_data(ev) ((void*)((char *)(ev)->data.ext.ptr + sizeof(struct snd_seq_event_bounce))) -- - /* - * type check macros - */ -diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h -new file mode 100644 ---- /dev/null -+++ b/include/sound/aw88399.h -@@ -0,0 +1,621 @@ -+/* SPDX-License-Identifier: GPL-2.0-only -+ * -+ * linux/sound/aw88399.h -- Platform data for AW88399 -+ * -+ * Copyright (c) 2023 AWINIC Technology CO., LTD -+ * -+ * Author: Weidong Wang -+ */ -+ -+#ifndef __SOUND_AW88399_H -+#define __SOUND_AW88399_H -+ -+#include -+#include -+ -+/* registers list */ -+#define AW88399_ID_REG (0x00) -+#define AW88399_SYSST_REG (0x01) -+#define AW88399_SYSINT_REG (0x02) -+#define AW88399_SYSINTM_REG (0x03) -+#define AW88399_SYSCTRL_REG (0x04) -+#define AW88399_SYSCTRL2_REG (0x05) -+#define AW88399_I2SCTRL1_REG (0x06) -+#define AW88399_I2SCTRL2_REG (0x07) -+#define AW88399_I2SCTRL3_REG (0x08) -+#define AW88399_DACCFG1_REG (0x09) -+#define AW88399_DACCFG2_REG (0x0A) -+#define AW88399_DACCFG3_REG (0x0B) -+#define AW88399_DACCFG4_REG (0x0C) -+#define AW88399_DACCFG5_REG (0x0D) -+#define AW88399_DACCFG6_REG (0x0E) -+#define AW88399_DACCFG7_REG (0x0F) -+#define AW88399_MPDCFG1_REG (0x10) -+#define AW88399_MPDCFG2_REG (0x11) -+#define AW88399_MPDCFG3_REG (0x12) -+#define AW88399_MPDCFG4_REG (0x13) -+#define AW88399_PWMCTRL1_REG (0x14) -+#define AW88399_PWMCTRL2_REG (0x15) -+#define AW88399_PWMCTRL3_REG (0x16) -+#define AW88399_I2SCFG1_REG (0x17) -+#define AW88399_DBGCTRL_REG (0x18) -+#define AW88399_HAGCST_REG (0x20) -+#define AW88399_VBAT_REG (0x21) -+#define AW88399_TEMP_REG (0x22) -+#define AW88399_PVDD_REG (0x23) -+#define AW88399_ISNDAT_REG (0x24) -+#define AW88399_VSNDAT_REG (0x25) -+#define AW88399_I2SINT_REG (0x26) -+#define AW88399_I2SCAPCNT_REG (0x27) -+#define AW88399_ANASTA1_REG (0x28) -+#define AW88399_ANASTA2_REG (0x29) -+#define AW88399_ANASTA3_REG (0x2A) -+#define AW88399_TESTDET_REG (0x2B) -+#define AW88399_DSMCFG1_REG (0x30) -+#define AW88399_DSMCFG2_REG (0x31) -+#define AW88399_DSMCFG3_REG (0x32) -+#define AW88399_DSMCFG4_REG (0x33) -+#define AW88399_DSMCFG5_REG (0x34) -+#define AW88399_DSMCFG6_REG (0x35) -+#define AW88399_DSMCFG7_REG (0x36) -+#define AW88399_DSMCFG8_REG (0x37) -+#define AW88399_TESTIN_REG (0x38) -+#define AW88399_TESTOUT_REG (0x39) -+#define AW88399_MEMTEST_REG (0x3A) -+#define AW88399_VSNCTRL1_REG (0x3B) -+#define AW88399_ISNCTRL1_REG (0x3C) -+#define AW88399_ISNCTRL2_REG (0x3D) -+#define AW88399_DSPMADD_REG (0x40) -+#define AW88399_DSPMDAT_REG (0x41) -+#define AW88399_WDT_REG (0x42) -+#define AW88399_ACR1_REG (0x43) -+#define AW88399_ACR2_REG (0x44) -+#define AW88399_ASR1_REG (0x45) -+#define AW88399_ASR2_REG (0x46) -+#define AW88399_DSPCFG_REG (0x47) -+#define AW88399_ASR3_REG (0x48) -+#define AW88399_ASR4_REG (0x49) -+#define AW88399_DSPVCALB_REG (0x4A) -+#define AW88399_CRCCTRL_REG (0x4B) -+#define AW88399_DSPDBG1_REG (0x4C) -+#define AW88399_DSPDBG2_REG (0x4D) -+#define AW88399_DSPDBG3_REG (0x4E) -+#define AW88399_PLLCTRL1_REG (0x50) -+#define AW88399_PLLCTRL2_REG (0x51) -+#define AW88399_PLLCTRL3_REG (0x52) -+#define AW88399_CDACTRL1_REG (0x53) -+#define AW88399_CDACTRL2_REG (0x54) -+#define AW88399_CDACTRL3_REG (0x55) -+#define AW88399_SADCCTRL1_REG (0x56) -+#define AW88399_SADCCTRL2_REG (0x57) -+#define AW88399_BOPCTRL1_REG (0x58) -+#define AW88399_BOPCTRL2_REG (0x5A) -+#define AW88399_BOPCTRL3_REG (0x5B) -+#define AW88399_BOPCTRL4_REG (0x5C) -+#define AW88399_BOPCTRL5_REG (0x5D) -+#define AW88399_BOPCTRL6_REG (0x5E) -+#define AW88399_BOPCTRL7_REG (0x5F) -+#define AW88399_BSTCTRL1_REG (0x60) -+#define AW88399_BSTCTRL2_REG (0x61) -+#define AW88399_BSTCTRL3_REG (0x62) -+#define AW88399_BSTCTRL4_REG (0x63) -+#define AW88399_BSTCTRL5_REG (0x64) -+#define AW88399_BSTCTRL6_REG (0x65) -+#define AW88399_BSTCTRL7_REG (0x66) -+#define AW88399_BSTCTRL8_REG (0x67) -+#define AW88399_BSTCTRL9_REG (0x68) -+#define AW88399_BSTCTRL10_REG (0x69) -+#define AW88399_CPCTRL_REG (0x6A) -+#define AW88399_EFWH_REG (0x6C) -+#define AW88399_EFWM2_REG (0x6D) -+#define AW88399_EFWM1_REG (0x6E) -+#define AW88399_EFWL_REG (0x6F) -+#define AW88399_TESTCTRL1_REG (0x70) -+#define AW88399_TESTCTRL2_REG (0x71) -+#define AW88399_EFCTRL1_REG (0x72) -+#define AW88399_EFCTRL2_REG (0x73) -+#define AW88399_EFRH4_REG (0x74) -+#define AW88399_EFRH3_REG (0x75) -+#define AW88399_EFRH2_REG (0x76) -+#define AW88399_EFRH1_REG (0x77) -+#define AW88399_EFRL4_REG (0x78) -+#define AW88399_EFRL3_REG (0x79) -+#define AW88399_EFRL2_REG (0x7A) -+#define AW88399_EFRL1_REG (0x7B) -+#define AW88399_TM_REG (0x7C) -+#define AW88399_TM2_REG (0x7D) -+ -+#define AW88399_REG_MAX (0x7E) -+#define AW88399_MUTE_VOL (1023) -+ -+#define AW88399_DSP_CFG_ADDR (0x9B00) -+#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68) -+#define AW88399_DSP_FW_ADDR (0x8980) -+#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40) -+#define AW88399_DSP_ROM_CHECK_DATA (0x4638) -+ -+#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000)) -+#define AW88399_CALI_RE_HBITS_SHIFT (16) -+ -+#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF)) -+#define AW88399_CALI_RE_LBITS_SHIFT (0) -+ -+#define AW88399_I2STXEN_START_BIT (9) -+#define AW88399_I2STXEN_BITS_LEN (1) -+#define AW88399_I2STXEN_MASK \ -+ (~(((1<> (shift)) -+#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000)) -+#define AW88399_CRC_CHECK_PASS_VAL (0x4) -+ -+#define AW88399_CRC_CFG_BASE_ADDR (0xD80) -+#define AW88399_CRC_FW_BASE_ADDR (0x4C0) -+#define AW88399_ACF_FILE "aw88399_acf.bin" -+#define AW88399_DEV_SYSST_CHECK_MAX (10) -+#define AW88399_CHIP_ID 0x2183 -+ -+#define AW88399_START_RETRIES (5) -+#define AW88399_START_WORK_DELAY_MS (0) -+ -+enum { -+ AW_EF_AND_CHECK = 0, -+ AW_EF_OR_CHECK, -+}; -+ -+enum { -+ AW88399_DEV_VDSEL_DAC = 0, -+ AW88399_DEV_VDSEL_VSENSE = 32, -+}; -+ -+enum { -+ AW88399_DSP_CRC_NA = 0, -+ AW88399_DSP_CRC_OK = 1, -+}; -+ -+enum { -+ AW88399_DSP_FW_UPDATE_OFF = 0, -+ AW88399_DSP_FW_UPDATE_ON = 1, -+}; -+ -+enum { -+ AW88399_FORCE_UPDATE_OFF = 0, -+ AW88399_FORCE_UPDATE_ON = 1, -+}; -+ -+enum { -+ AW88399_1000_US = 1000, -+ AW88399_2000_US = 2000, -+ AW88399_3000_US = 3000, -+ AW88399_4000_US = 4000, -+}; -+ -+enum AW88399_DEV_STATUS { -+ AW88399_DEV_PW_OFF = 0, -+ AW88399_DEV_PW_ON, -+}; -+ -+enum AW88399_DEV_FW_STATUS { -+ AW88399_DEV_FW_FAILED = 0, -+ AW88399_DEV_FW_OK, -+}; -+ -+enum AW88399_DEV_MEMCLK { -+ AW88399_DEV_MEMCLK_OSC = 0, -+ AW88399_DEV_MEMCLK_PLL = 1, -+}; -+ -+enum AW88399_DEV_DSP_CFG { -+ AW88399_DEV_DSP_WORK = 0, -+ AW88399_DEV_DSP_BYPASS = 1, -+}; -+ -+enum { -+ AW88399_NOT_RCV_MODE = 0, -+ AW88399_RCV_MODE = 1, -+}; -+ -+enum { -+ AW88399_SYNC_START = 0, -+ AW88399_ASYNC_START, -+}; -+ -+struct aw_device; -+struct aw_container; -+struct aw_cali_desc; -+struct gpio_desc; -+struct i2c_client; -+struct regmap; -+ -+struct aw88399 { -+ struct aw_device *aw_pa; -+ struct mutex lock; -+ struct gpio_desc *reset_gpio; -+ struct delayed_work start_work; -+ struct regmap *regmap; -+ struct aw_container *aw_cfg; -+ -+ unsigned int check_val; -+ unsigned int crc_init_val; -+ unsigned int vcalb_init_val; -+ unsigned int dither_st; -+ bool bsts_unreliable; -+ bool fw_needs_reload; -+}; -+ -+int aw_dev_check_syspll(struct aw_device *aw_dev); -+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable); -+int aw_dev_get_dsp_status(struct aw_device *aw_dev); -+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value); -+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc); -+int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name); -+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute); -+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel); -+void aw88399_hw_reset(struct aw88399 *aw88399); -+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap); -+extern const struct regmap_config aw88399_remap_config; -+int aw88399_request_firmware_file(struct aw88399 *aw88399); -+void aw88399_start(struct aw88399 *aw88399, bool sync_start); -+void aw88399_startup_work(struct work_struct *work); -+int aw88399_stop(struct aw_device *aw_dev); -+ -+#endif /* __SOUND_AW88399_H */ -diff --git a/include/sound/control.h b/include/sound/control.h ---- a/include/sound/control.h -+++ b/include/sound/control.h -@@ -7,6 +7,7 @@ - * Copyright (c) by Jaroslav Kysela - */ - -+#include - #include - #include - #include -@@ -167,6 +168,8 @@ snd_ctl_find_id_mixer(struct snd_card *card, const char *name) - - int snd_ctl_create(struct snd_card *card); - -+extern struct rw_semaphore snd_ioctl_rwsem; -+ - int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn); - int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn); - #ifdef CONFIG_COMPAT -diff --git a/include/sound/core.h b/include/sound/core.h ---- a/include/sound/core.h -+++ b/include/sound/core.h -@@ -108,8 +108,8 @@ struct snd_card { - char longname[80]; /* name of this soundcard */ - char irq_descr[32]; /* Interrupt description */ - char mixername[80]; /* mixer name */ -- char components[128]; /* card components delimited with -- space */ -+ char *components; /* card components, space-delimited */ -+ unsigned int components_alloc_size; /* current allocation size of components */ - struct module *module; /* top-level module */ - - void *private_data; /* private data for soundcard */ -diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h ---- a/include/sound/hda_codec.h -+++ b/include/sound/hda_codec.h -@@ -256,6 +256,7 @@ struct hda_codec { - unsigned int link_down_at_suspend:1; /* link down at runtime suspend */ - unsigned int relaxed_resume:1; /* don't resume forcibly for jack */ - unsigned int forced_resume:1; /* forced resume for jack */ -+ unsigned int acomp_requested_resume:1; /* resume requested by acomp */ - unsigned int no_stream_clean_at_suspend:1; /* do not clean streams at suspend */ - unsigned int ctl_dev_id:1; /* old control element id build behaviour */ - unsigned int eld_jack_detect:1; /* Machine jack-detection by ELD */ -diff --git a/include/sound/hda_regmap.h b/include/sound/hda_regmap.h ---- a/include/sound/hda_regmap.h -+++ b/include/sound/hda_regmap.h -@@ -69,11 +69,14 @@ void snd_hdac_regmap_sync(struct hdac_device *codec); - - /** - * snd_hdac_regmap_write - Write a verb with caching -+ * @codec: HD-audio codec base device - * @nid: codec NID -- * @reg: verb to write -+ * @verb: verb to write - * @val: value to write - * - * For writing an amp value, use snd_hdac_regmap_update_amp(). -+ * -+ * Returns: %0 if successful or a negative error code. - */ - static inline int - snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid, -@@ -85,13 +88,16 @@ snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid, - } - - /** -- * snd_hda_regmap_update - Update a verb value with caching -+ * snd_hdac_regmap_update - Update a verb value with caching -+ * @codec: HD-audio codec - * @nid: codec NID - * @verb: verb to update - * @mask: bit mask to update - * @val: value to update - * - * For updating an amp value, use snd_hdac_regmap_update_amp(). -+ * -+ * Returns: %0 if successful or a negative error code. - */ - static inline int - snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid, -@@ -104,12 +110,15 @@ snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid, - } - - /** -- * snd_hda_regmap_read - Read a verb with caching -+ * snd_hdac_regmap_read - Read a verb with caching -+ * @codec: HD-audio codec - * @nid: codec NID - * @verb: verb to read - * @val: pointer to store the value - * - * For reading an amp value, use snd_hda_regmap_get_amp(). -+ * -+ * Returns: %0 if successful or a negative error code. - */ - static inline int - snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid, -@@ -125,12 +134,12 @@ snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid, - * @codec: HD-audio codec - * @nid: NID to read the AMP value - * @ch: channel (left=0 or right=1) -- * @direction: #HDA_INPUT or #HDA_OUTPUT -- * @index: the index value (only for input direction) -- * @val: the pointer to store the value -+ * @dir: #HDA_INPUT or #HDA_OUTPUT -+ * @idx: the index value (only for input direction) - * - * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. -- * Returns the value or a negative error. -+ * -+ * Returns: the value or a negative error. - */ - static inline int - snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid, -@@ -148,13 +157,14 @@ snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid, - * @codec: HD-audio codec - * @nid: NID to read the AMP value - * @ch: channel (left=0 or right=1) -- * @direction: #HDA_INPUT or #HDA_OUTPUT -+ * @dir: #HDA_INPUT or #HDA_OUTPUT - * @idx: the index value (only for input direction) - * @mask: bit mask to set - * @val: the bits value to set - * - * Update the AMP value with a bit mask. -- * Returns 0 if the value is unchanged, 1 if changed, or a negative error. -+ * -+ * Returns: 0 if the value is unchanged, 1 if changed, or a negative error. - */ - static inline int - snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid, -@@ -169,13 +179,12 @@ snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid, - * snd_hdac_regmap_get_amp_stereo - Read stereo AMP values - * @codec: HD-audio codec - * @nid: NID to read the AMP value -- * @ch: channel (left=0 or right=1) -- * @direction: #HDA_INPUT or #HDA_OUTPUT -- * @index: the index value (only for input direction) -- * @val: the pointer to store the value -+ * @dir: #HDA_INPUT or #HDA_OUTPUT -+ * @idx: the index value (only for input direction) - * - * Read stereo AMP values. The lower byte is left, the upper byte is right. -- * Returns the value or a negative error. -+ * -+ * Returns: the value or a negative error. - */ - static inline int - snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid, -@@ -192,14 +201,15 @@ snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid, - * snd_hdac_regmap_update_amp_stereo - update the stereo AMP value - * @codec: HD-audio codec - * @nid: NID to read the AMP value -- * @direction: #HDA_INPUT or #HDA_OUTPUT -+ * @dir: #HDA_INPUT or #HDA_OUTPUT - * @idx: the index value (only for input direction) - * @mask: bit mask to set - * @val: the bits value to set - * - * Update the stereo AMP value with a bit mask. - * The lower byte is left, the upper byte is right. -- * Returns 0 if the value is unchanged, 1 if changed, or a negative error. -+ * -+ * Returns: 0 if the value is unchanged, 1 if changed, or a negative error. - */ - static inline int - snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid, -diff --git a/include/sound/pcm.h b/include/sound/pcm.h ---- a/include/sound/pcm.h -+++ b/include/sound/pcm.h -@@ -145,61 +145,60 @@ struct snd_pcm_ops { - #define SNDRV_PCM_RATE_8000_768000 (SNDRV_PCM_RATE_8000_384000|\ - SNDRV_PCM_RATE_705600|\ - SNDRV_PCM_RATE_768000) --#define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt) --#define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8) --#define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8) --#define SNDRV_PCM_FMTBIT_S16_LE _SNDRV_PCM_FMTBIT(S16_LE) --#define SNDRV_PCM_FMTBIT_S16_BE _SNDRV_PCM_FMTBIT(S16_BE) --#define SNDRV_PCM_FMTBIT_U16_LE _SNDRV_PCM_FMTBIT(U16_LE) --#define SNDRV_PCM_FMTBIT_U16_BE _SNDRV_PCM_FMTBIT(U16_BE) --#define SNDRV_PCM_FMTBIT_S24_LE _SNDRV_PCM_FMTBIT(S24_LE) --#define SNDRV_PCM_FMTBIT_S24_BE _SNDRV_PCM_FMTBIT(S24_BE) --#define SNDRV_PCM_FMTBIT_U24_LE _SNDRV_PCM_FMTBIT(U24_LE) --#define SNDRV_PCM_FMTBIT_U24_BE _SNDRV_PCM_FMTBIT(U24_BE) -+#define SNDRV_PCM_FMTBIT_S8 (1ULL << SNDRV_PCM_FORMAT_S8) -+#define SNDRV_PCM_FMTBIT_U8 (1ULL << SNDRV_PCM_FORMAT_U8) -+#define SNDRV_PCM_FMTBIT_S16_LE (1ULL << SNDRV_PCM_FORMAT_S16_LE) -+#define SNDRV_PCM_FMTBIT_S16_BE (1ULL << SNDRV_PCM_FORMAT_S16_BE) -+#define SNDRV_PCM_FMTBIT_U16_LE (1ULL << SNDRV_PCM_FORMAT_U16_LE) -+#define SNDRV_PCM_FMTBIT_U16_BE (1ULL << SNDRV_PCM_FORMAT_U16_BE) -+#define SNDRV_PCM_FMTBIT_S24_LE (1ULL << SNDRV_PCM_FORMAT_S24_LE) -+#define SNDRV_PCM_FMTBIT_S24_BE (1ULL << SNDRV_PCM_FORMAT_S24_BE) -+#define SNDRV_PCM_FMTBIT_U24_LE (1ULL << SNDRV_PCM_FORMAT_U24_LE) -+#define SNDRV_PCM_FMTBIT_U24_BE (1ULL << SNDRV_PCM_FORMAT_U24_BE) - // For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the - // available bit count in most significant bit. It's for the case of so-called 'left-justified' or - // `right-padding` sample which has less width than 32 bit. --#define SNDRV_PCM_FMTBIT_S32_LE _SNDRV_PCM_FMTBIT(S32_LE) --#define SNDRV_PCM_FMTBIT_S32_BE _SNDRV_PCM_FMTBIT(S32_BE) --#define SNDRV_PCM_FMTBIT_U32_LE _SNDRV_PCM_FMTBIT(U32_LE) --#define SNDRV_PCM_FMTBIT_U32_BE _SNDRV_PCM_FMTBIT(U32_BE) --#define SNDRV_PCM_FMTBIT_FLOAT_LE _SNDRV_PCM_FMTBIT(FLOAT_LE) --#define SNDRV_PCM_FMTBIT_FLOAT_BE _SNDRV_PCM_FMTBIT(FLOAT_BE) --#define SNDRV_PCM_FMTBIT_FLOAT64_LE _SNDRV_PCM_FMTBIT(FLOAT64_LE) --#define SNDRV_PCM_FMTBIT_FLOAT64_BE _SNDRV_PCM_FMTBIT(FLOAT64_BE) --#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_LE) --#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_BE) --#define SNDRV_PCM_FMTBIT_MU_LAW _SNDRV_PCM_FMTBIT(MU_LAW) --#define SNDRV_PCM_FMTBIT_A_LAW _SNDRV_PCM_FMTBIT(A_LAW) --#define SNDRV_PCM_FMTBIT_IMA_ADPCM _SNDRV_PCM_FMTBIT(IMA_ADPCM) --#define SNDRV_PCM_FMTBIT_MPEG _SNDRV_PCM_FMTBIT(MPEG) --#define SNDRV_PCM_FMTBIT_GSM _SNDRV_PCM_FMTBIT(GSM) --#define SNDRV_PCM_FMTBIT_S20_LE _SNDRV_PCM_FMTBIT(S20_LE) --#define SNDRV_PCM_FMTBIT_U20_LE _SNDRV_PCM_FMTBIT(U20_LE) --#define SNDRV_PCM_FMTBIT_S20_BE _SNDRV_PCM_FMTBIT(S20_BE) --#define SNDRV_PCM_FMTBIT_U20_BE _SNDRV_PCM_FMTBIT(U20_BE) --#define SNDRV_PCM_FMTBIT_SPECIAL _SNDRV_PCM_FMTBIT(SPECIAL) --#define SNDRV_PCM_FMTBIT_S24_3LE _SNDRV_PCM_FMTBIT(S24_3LE) --#define SNDRV_PCM_FMTBIT_U24_3LE _SNDRV_PCM_FMTBIT(U24_3LE) --#define SNDRV_PCM_FMTBIT_S24_3BE _SNDRV_PCM_FMTBIT(S24_3BE) --#define SNDRV_PCM_FMTBIT_U24_3BE _SNDRV_PCM_FMTBIT(U24_3BE) --#define SNDRV_PCM_FMTBIT_S20_3LE _SNDRV_PCM_FMTBIT(S20_3LE) --#define SNDRV_PCM_FMTBIT_U20_3LE _SNDRV_PCM_FMTBIT(U20_3LE) --#define SNDRV_PCM_FMTBIT_S20_3BE _SNDRV_PCM_FMTBIT(S20_3BE) --#define SNDRV_PCM_FMTBIT_U20_3BE _SNDRV_PCM_FMTBIT(U20_3BE) --#define SNDRV_PCM_FMTBIT_S18_3LE _SNDRV_PCM_FMTBIT(S18_3LE) --#define SNDRV_PCM_FMTBIT_U18_3LE _SNDRV_PCM_FMTBIT(U18_3LE) --#define SNDRV_PCM_FMTBIT_S18_3BE _SNDRV_PCM_FMTBIT(S18_3BE) --#define SNDRV_PCM_FMTBIT_U18_3BE _SNDRV_PCM_FMTBIT(U18_3BE) --#define SNDRV_PCM_FMTBIT_G723_24 _SNDRV_PCM_FMTBIT(G723_24) --#define SNDRV_PCM_FMTBIT_G723_24_1B _SNDRV_PCM_FMTBIT(G723_24_1B) --#define SNDRV_PCM_FMTBIT_G723_40 _SNDRV_PCM_FMTBIT(G723_40) --#define SNDRV_PCM_FMTBIT_G723_40_1B _SNDRV_PCM_FMTBIT(G723_40_1B) --#define SNDRV_PCM_FMTBIT_DSD_U8 _SNDRV_PCM_FMTBIT(DSD_U8) --#define SNDRV_PCM_FMTBIT_DSD_U16_LE _SNDRV_PCM_FMTBIT(DSD_U16_LE) --#define SNDRV_PCM_FMTBIT_DSD_U32_LE _SNDRV_PCM_FMTBIT(DSD_U32_LE) --#define SNDRV_PCM_FMTBIT_DSD_U16_BE _SNDRV_PCM_FMTBIT(DSD_U16_BE) --#define SNDRV_PCM_FMTBIT_DSD_U32_BE _SNDRV_PCM_FMTBIT(DSD_U32_BE) -+#define SNDRV_PCM_FMTBIT_S32_LE (1ULL << SNDRV_PCM_FORMAT_S32_LE) -+#define SNDRV_PCM_FMTBIT_S32_BE (1ULL << SNDRV_PCM_FORMAT_S32_BE) -+#define SNDRV_PCM_FMTBIT_U32_LE (1ULL << SNDRV_PCM_FORMAT_U32_LE) -+#define SNDRV_PCM_FMTBIT_U32_BE (1ULL << SNDRV_PCM_FORMAT_U32_BE) -+#define SNDRV_PCM_FMTBIT_FLOAT_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT_LE) -+#define SNDRV_PCM_FMTBIT_FLOAT_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT_BE) -+#define SNDRV_PCM_FMTBIT_FLOAT64_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_LE) -+#define SNDRV_PCM_FMTBIT_FLOAT64_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_BE) -+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) -+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE) -+#define SNDRV_PCM_FMTBIT_MU_LAW (1ULL << SNDRV_PCM_FORMAT_MU_LAW) -+#define SNDRV_PCM_FMTBIT_A_LAW (1ULL << SNDRV_PCM_FORMAT_A_LAW) -+#define SNDRV_PCM_FMTBIT_IMA_ADPCM (1ULL << SNDRV_PCM_FORMAT_IMA_ADPCM) -+#define SNDRV_PCM_FMTBIT_MPEG (1ULL << SNDRV_PCM_FORMAT_MPEG) -+#define SNDRV_PCM_FMTBIT_GSM (1ULL << SNDRV_PCM_FORMAT_GSM) -+#define SNDRV_PCM_FMTBIT_S20_LE (1ULL << SNDRV_PCM_FORMAT_S20_LE) -+#define SNDRV_PCM_FMTBIT_U20_LE (1ULL << SNDRV_PCM_FORMAT_U20_LE) -+#define SNDRV_PCM_FMTBIT_S20_BE (1ULL << SNDRV_PCM_FORMAT_S20_BE) -+#define SNDRV_PCM_FMTBIT_U20_BE (1ULL << SNDRV_PCM_FORMAT_U20_BE) -+#define SNDRV_PCM_FMTBIT_SPECIAL (1ULL << SNDRV_PCM_FORMAT_SPECIAL) -+#define SNDRV_PCM_FMTBIT_S24_3LE (1ULL << SNDRV_PCM_FORMAT_S24_3LE) -+#define SNDRV_PCM_FMTBIT_U24_3LE (1ULL << SNDRV_PCM_FORMAT_U24_3LE) -+#define SNDRV_PCM_FMTBIT_S24_3BE (1ULL << SNDRV_PCM_FORMAT_S24_3BE) -+#define SNDRV_PCM_FMTBIT_U24_3BE (1ULL << SNDRV_PCM_FORMAT_U24_3BE) -+#define SNDRV_PCM_FMTBIT_S20_3LE (1ULL << SNDRV_PCM_FORMAT_S20_3LE) -+#define SNDRV_PCM_FMTBIT_U20_3LE (1ULL << SNDRV_PCM_FORMAT_U20_3LE) -+#define SNDRV_PCM_FMTBIT_S20_3BE (1ULL << SNDRV_PCM_FORMAT_S20_3BE) -+#define SNDRV_PCM_FMTBIT_U20_3BE (1ULL << SNDRV_PCM_FORMAT_U20_3BE) -+#define SNDRV_PCM_FMTBIT_S18_3LE (1ULL << SNDRV_PCM_FORMAT_S18_3LE) -+#define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE) -+#define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE) -+#define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE) -+#define SNDRV_PCM_FMTBIT_G723_24 (1ULL << SNDRV_PCM_FORMAT_G723_24) -+#define SNDRV_PCM_FMTBIT_G723_24_1B (1ULL << SNDRV_PCM_FORMAT_G723_24_1B) -+#define SNDRV_PCM_FMTBIT_G723_40 (1ULL << SNDRV_PCM_FORMAT_G723_40) -+#define SNDRV_PCM_FMTBIT_G723_40_1B (1ULL << SNDRV_PCM_FORMAT_G723_40_1B) -+#define SNDRV_PCM_FMTBIT_DSD_U8 (1ULL << SNDRV_PCM_FORMAT_DSD_U8) -+#define SNDRV_PCM_FMTBIT_DSD_U16_LE (1ULL << SNDRV_PCM_FORMAT_DSD_U16_LE) -+#define SNDRV_PCM_FMTBIT_DSD_U32_LE (1ULL << SNDRV_PCM_FORMAT_DSD_U32_LE) -+#define SNDRV_PCM_FMTBIT_DSD_U16_BE (1ULL << SNDRV_PCM_FORMAT_DSD_U16_BE) -+#define SNDRV_PCM_FMTBIT_DSD_U32_BE (1ULL << SNDRV_PCM_FORMAT_DSD_U32_BE) - - #ifdef SNDRV_LITTLE_ENDIAN - #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE -@@ -228,11 +227,10 @@ struct snd_pcm_ops { - #define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_BE - #endif - --#define _SNDRV_PCM_SUBFMTBIT(fmt) BIT((__force int)SNDRV_PCM_SUBFORMAT_##fmt) --#define SNDRV_PCM_SUBFMTBIT_STD _SNDRV_PCM_SUBFMTBIT(STD) --#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX _SNDRV_PCM_SUBFMTBIT(MSBITS_MAX) --#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 _SNDRV_PCM_SUBFMTBIT(MSBITS_20) --#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 _SNDRV_PCM_SUBFMTBIT(MSBITS_24) -+#define SNDRV_PCM_SUBFMTBIT_STD (1U << SNDRV_PCM_SUBFORMAT_STD) -+#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX (1U << SNDRV_PCM_SUBFORMAT_MSBITS_MAX) -+#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 (1U << SNDRV_PCM_SUBFORMAT_MSBITS_20) -+#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 (1U << SNDRV_PCM_SUBFORMAT_MSBITS_24) - - struct snd_pcm_file { - struct snd_pcm_substream *substream; -@@ -1515,7 +1513,7 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, - */ - static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format) - { -- return 1ULL << (__force int) pcm_format; -+ return 1ULL << pcm_format; - } - - /** -@@ -1523,9 +1521,7 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format) - * @f: the iterator variable in snd_pcm_format_t type - */ - #define pcm_for_each_format(f) \ -- for ((f) = SNDRV_PCM_FORMAT_FIRST; \ -- (__force int)(f) <= (__force int)SNDRV_PCM_FORMAT_LAST; \ -- (f) = (__force snd_pcm_format_t)((__force int)(f) + 1)) -+ for ((f) = SNDRV_PCM_FORMAT_FIRST; (f) <= SNDRV_PCM_FORMAT_LAST; (f)++) - - /* printk helpers */ - #define pcm_err(pcm, fmt, args...) \ -diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h ---- a/include/sound/pcm_params.h -+++ b/include/sound/pcm_params.h -@@ -71,7 +71,7 @@ static inline void snd_mask_set(struct snd_mask *mask, unsigned int val) - static inline void snd_mask_set_format(struct snd_mask *mask, - snd_pcm_format_t format) - { -- snd_mask_set(mask, (__force unsigned int)format); -+ snd_mask_set(mask, format); - } - - static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val) -@@ -132,7 +132,7 @@ static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val) - static inline int snd_mask_test_format(const struct snd_mask *mask, - snd_pcm_format_t format) - { -- return snd_mask_test(mask, (__force unsigned int)format); -+ return snd_mask_test(mask, format); - } - - static inline int snd_mask_single(const struct snd_mask *mask) -@@ -302,8 +302,7 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn - */ - static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p) - { -- return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p, -- SNDRV_PCM_HW_PARAM_ACCESS)); -+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_ACCESS)); - } - - /** -@@ -312,8 +311,7 @@ static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p) - */ - static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p) - { -- return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p, -- SNDRV_PCM_HW_PARAM_FORMAT)); -+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_FORMAT)); - } - - /** -@@ -323,8 +321,7 @@ static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p) - static inline snd_pcm_subformat_t - params_subformat(const struct snd_pcm_hw_params *p) - { -- return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p, -- SNDRV_PCM_HW_PARAM_SUBFORMAT)); -+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_SUBFORMAT)); - } - - /** -diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h ---- a/include/sound/rawmidi.h -+++ b/include/sound/rawmidi.h -@@ -176,8 +176,9 @@ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream); - /* main midi functions */ - - int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info); --int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice, -- int mode, struct snd_rawmidi_file *rfile); -+int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice, -+ int mode, struct snd_rawmidi_file *rfile, -+ int depth); - int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile); - int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_params *params); -@@ -191,6 +192,15 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream, - long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream, - const unsigned char *buf, long count); - -+/* non-nested version */ -+static inline int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, -+ int subdevice, -+ int mode, -+ struct snd_rawmidi_file *rfile) -+{ -+ return snd_rawmidi_kernel_open_nested(rmidi, subdevice, mode, rfile, 0); -+} -+ - /* set up the tied devices */ - static inline void snd_rawmidi_tie_devices(struct snd_rawmidi *r1, - struct snd_rawmidi *r2) -diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h ---- a/include/sound/seq_virmidi.h -+++ b/include/sound/seq_virmidi.h -@@ -46,7 +46,6 @@ struct snd_virmidi_dev { - int client; /* created/attached client */ - int port; /* created/attached port */ - unsigned int flags; /* SNDRV_VIRMIDI_* */ -- rwlock_t filelist_lock; - struct rw_semaphore filelist_sem; - struct list_head filelist; - }; -diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h ---- a/include/uapi/sound/asequencer.h -+++ b/include/uapi/sound/asequencer.h -@@ -308,16 +308,6 @@ struct snd_seq_ump_event { - }; - }; - --/* -- * bounce event - stored as variable size data -- */ --struct snd_seq_event_bounce { -- int err; -- struct snd_seq_event event; -- /* external data follows here. */ --}; -- -- - /* system information */ - struct snd_seq_system_info { - int queues; /* maximum queues count */ -@@ -348,10 +338,10 @@ struct snd_seq_running_info { - - - /* client types */ --typedef int __bitwise snd_seq_client_type_t; --#define NO_CLIENT ((__force snd_seq_client_type_t) 0) --#define USER_CLIENT ((__force snd_seq_client_type_t) 1) --#define KERNEL_CLIENT ((__force snd_seq_client_type_t) 2) -+typedef int snd_seq_client_type_t; -+#define NO_CLIENT 0 -+#define USER_CLIENT 1 -+#define KERNEL_CLIENT 2 - - /* event filter flags */ - #define SNDRV_SEQ_FILTER_BROADCAST (1U<<0) /* accept broadcast messages */ -diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h ---- a/include/uapi/sound/asound.h -+++ b/include/uapi/sound/asound.h -@@ -169,72 +169,72 @@ enum { - SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, - }; - --typedef int __bitwise snd_pcm_access_t; --#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) /* interleaved mmap */ --#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) /* noninterleaved mmap */ --#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) /* complex mmap */ --#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) /* readi/writei */ --#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) /* readn/writen */ -+typedef int snd_pcm_access_t; -+#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED 0 /* interleaved mmap */ -+#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED 1 /* noninterleaved mmap */ -+#define SNDRV_PCM_ACCESS_MMAP_COMPLEX 2 /* complex mmap */ -+#define SNDRV_PCM_ACCESS_RW_INTERLEAVED 3 /* readi/writei */ -+#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED 4 /* readn/writen */ - #define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED - --typedef int __bitwise snd_pcm_format_t; --#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0) --#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1) --#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2) --#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3) --#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4) --#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5) --#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) /* low three bytes */ --#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */ --#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */ --#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */ -+typedef int snd_pcm_format_t; -+#define SNDRV_PCM_FORMAT_S8 0 -+#define SNDRV_PCM_FORMAT_U8 1 -+#define SNDRV_PCM_FORMAT_S16_LE 2 -+#define SNDRV_PCM_FORMAT_S16_BE 3 -+#define SNDRV_PCM_FORMAT_U16_LE 4 -+#define SNDRV_PCM_FORMAT_U16_BE 5 -+#define SNDRV_PCM_FORMAT_S24_LE 6 /* low three bytes */ -+#define SNDRV_PCM_FORMAT_S24_BE 7 /* low three bytes */ -+#define SNDRV_PCM_FORMAT_U24_LE 8 /* low three bytes */ -+#define SNDRV_PCM_FORMAT_U24_BE 9 /* low three bytes */ - /* - * For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the - * available bit count in most significant bit. It's for the case of so-called 'left-justified' or - * `right-padding` sample which has less width than 32 bit. - */ --#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10) --#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11) --#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12) --#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13) --#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ --#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ --#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ --#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ --#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) /* IEC-958 subframe, Little Endian */ --#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) /* IEC-958 subframe, Big Endian */ --#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20) --#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21) --#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) --#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) --#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) --#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */ --#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */ --#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */ --#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */ -+#define SNDRV_PCM_FORMAT_S32_LE 10 -+#define SNDRV_PCM_FORMAT_S32_BE 11 -+#define SNDRV_PCM_FORMAT_U32_LE 12 -+#define SNDRV_PCM_FORMAT_U32_BE 13 -+#define SNDRV_PCM_FORMAT_FLOAT_LE 14 /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ -+#define SNDRV_PCM_FORMAT_FLOAT_BE 15 /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ -+#define SNDRV_PCM_FORMAT_FLOAT64_LE 16 /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ -+#define SNDRV_PCM_FORMAT_FLOAT64_BE 17 /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ -+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE 18 /* IEC-958 subframe, Little Endian */ -+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE 19 /* IEC-958 subframe, Big Endian */ -+#define SNDRV_PCM_FORMAT_MU_LAW 20 -+#define SNDRV_PCM_FORMAT_A_LAW 21 -+#define SNDRV_PCM_FORMAT_IMA_ADPCM 22 -+#define SNDRV_PCM_FORMAT_MPEG 23 -+#define SNDRV_PCM_FORMAT_GSM 24 -+#define SNDRV_PCM_FORMAT_S20_LE 25 /* in four bytes, LSB justified */ -+#define SNDRV_PCM_FORMAT_S20_BE 26 /* in four bytes, LSB justified */ -+#define SNDRV_PCM_FORMAT_U20_LE 27 /* in four bytes, LSB justified */ -+#define SNDRV_PCM_FORMAT_U20_BE 28 /* in four bytes, LSB justified */ - /* gap in the numbering for a future standard linear format */ --#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) --#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */ --#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */ --#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) /* in three bytes */ --#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) /* in three bytes */ --#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) /* in three bytes */ --#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) /* in three bytes */ --#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) /* in three bytes */ --#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) /* in three bytes */ --#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) /* in three bytes */ --#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */ --#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */ --#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */ --#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */ --#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ --#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ --#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ --#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ --#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ --#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ --#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */ --#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */ -+#define SNDRV_PCM_FORMAT_SPECIAL 31 -+#define SNDRV_PCM_FORMAT_S24_3LE 32 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_S24_3BE 33 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_U24_3LE 34 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_U24_3BE 35 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_S20_3LE 36 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_S20_3BE 37 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_U20_3LE 38 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_U20_3BE 39 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_S18_3LE 40 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_S18_3BE 41 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_U18_3LE 42 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_U18_3BE 43 /* in three bytes */ -+#define SNDRV_PCM_FORMAT_G723_24 44 /* 8 samples in 3 bytes */ -+#define SNDRV_PCM_FORMAT_G723_24_1B 45 /* 1 sample in 1 byte */ -+#define SNDRV_PCM_FORMAT_G723_40 46 /* 8 Samples in 5 bytes */ -+#define SNDRV_PCM_FORMAT_G723_40_1B 47 /* 1 sample in 1 byte */ -+#define SNDRV_PCM_FORMAT_DSD_U8 48 /* DSD, 1-byte samples DSD (x8) */ -+#define SNDRV_PCM_FORMAT_DSD_U16_LE 49 /* DSD, 2-byte samples DSD (x16), little endian */ -+#define SNDRV_PCM_FORMAT_DSD_U32_LE 50 /* DSD, 4-byte samples DSD (x32), little endian */ -+#define SNDRV_PCM_FORMAT_DSD_U16_BE 51 /* DSD, 2-byte samples DSD (x16), big endian */ -+#define SNDRV_PCM_FORMAT_DSD_U32_BE 52 /* DSD, 4-byte samples DSD (x32), big endian */ - #define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE - #define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8 - -@@ -265,11 +265,11 @@ typedef int __bitwise snd_pcm_format_t; - #define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE - #endif - --typedef int __bitwise snd_pcm_subformat_t; --#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) --#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1) --#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2) --#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3) -+typedef int snd_pcm_subformat_t; -+#define SNDRV_PCM_SUBFORMAT_STD 0 -+#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX 1 -+#define SNDRV_PCM_SUBFORMAT_MSBITS_20 2 -+#define SNDRV_PCM_SUBFORMAT_MSBITS_24 3 - #define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24 - - #define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */ -@@ -303,16 +303,16 @@ typedef int __bitwise snd_pcm_subformat_t; - #define __SND_STRUCT_TIME64 - #endif - --typedef int __bitwise snd_pcm_state_t; --#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ --#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */ --#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */ --#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) /* stream is running */ --#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) /* stream reached an xrun */ --#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */ --#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) /* stream is paused */ --#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */ --#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */ -+typedef int snd_pcm_state_t; -+#define SNDRV_PCM_STATE_OPEN 0 /* stream is open */ -+#define SNDRV_PCM_STATE_SETUP 1 /* stream has a setup */ -+#define SNDRV_PCM_STATE_PREPARED 2 /* stream is ready to start */ -+#define SNDRV_PCM_STATE_RUNNING 3 /* stream is running */ -+#define SNDRV_PCM_STATE_XRUN 4 /* stream reached an xrun */ -+#define SNDRV_PCM_STATE_DRAINING 5 /* stream is draining */ -+#define SNDRV_PCM_STATE_PAUSED 6 /* stream is paused */ -+#define SNDRV_PCM_STATE_SUSPENDED 7 /* hardware is suspended */ -+#define SNDRV_PCM_STATE_DISCONNECTED 8 /* hardware is disconnected */ - #define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED - - enum { -@@ -1058,7 +1058,7 @@ struct snd_timer_tread { - * * - ****************************************************************************/ - --#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) -+#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10) - - struct snd_ctl_card_info { - int card; /* card number */ -@@ -1072,24 +1072,43 @@ struct snd_ctl_card_info { - unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */ - }; - --typedef int __bitwise snd_ctl_elem_type_t; --#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) /* invalid */ --#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) /* boolean type */ --#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) /* integer type */ --#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) /* enumerated type */ --#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) /* byte array */ --#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) /* IEC958 (S/PDIF) setup */ --#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) /* 64-bit integer type */ -+/* -+ * Card components can exceed the fixed 128 bytes in snd_ctl_card_info. -+ * Use SNDRV_CTL_IOCTL_CARD_BYTES with type SND_CTL_CARD_BTYPE_COMPONENTS -+ * to retrieve the full string. -+ */ -+ -+/* Type values for struct snd_ctl_card_bytes::type */ -+enum { -+ SND_CTL_CARD_BTYPE_COMPONENTS = 1, /* full card components string */ -+}; -+ -+struct snd_ctl_card_bytes { -+ __u32 type; /* SND_CTL_CARD_BTYPE_* */ -+ __u32 data_allocated; /* size of @data buffer in bytes */ -+ __u32 data_len; /* in/out: actual data length in bytes */ -+ __u32 reserved; /* explicit pad */ -+ __u64 data; /* user buffer (pointer stored as __u64) */ -+}; -+ -+typedef int snd_ctl_elem_type_t; -+#define SNDRV_CTL_ELEM_TYPE_NONE 0 /* invalid */ -+#define SNDRV_CTL_ELEM_TYPE_BOOLEAN 1 /* boolean type */ -+#define SNDRV_CTL_ELEM_TYPE_INTEGER 2 /* integer type */ -+#define SNDRV_CTL_ELEM_TYPE_ENUMERATED 3 /* enumerated type */ -+#define SNDRV_CTL_ELEM_TYPE_BYTES 4 /* byte array */ -+#define SNDRV_CTL_ELEM_TYPE_IEC958 5 /* IEC958 (S/PDIF) setup */ -+#define SNDRV_CTL_ELEM_TYPE_INTEGER64 6 /* 64-bit integer type */ - #define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64 - --typedef int __bitwise snd_ctl_elem_iface_t; --#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) /* global control */ --#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */ --#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */ --#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) /* PCM device */ --#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */ --#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) /* timer device */ --#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) /* sequencer client */ -+typedef int snd_ctl_elem_iface_t; -+#define SNDRV_CTL_ELEM_IFACE_CARD 0 /* global control */ -+#define SNDRV_CTL_ELEM_IFACE_HWDEP 1 /* hardware dependent device */ -+#define SNDRV_CTL_ELEM_IFACE_MIXER 2 /* virtual mixer device */ -+#define SNDRV_CTL_ELEM_IFACE_PCM 3 /* PCM device */ -+#define SNDRV_CTL_ELEM_IFACE_RAWMIDI 4 /* RawMidi device */ -+#define SNDRV_CTL_ELEM_IFACE_TIMER 5 /* timer device */ -+#define SNDRV_CTL_ELEM_IFACE_SEQUENCER 6 /* sequencer client */ - #define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER - - #define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) -@@ -1198,6 +1217,7 @@ struct snd_ctl_tlv { - - #define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) - #define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info) -+#define SNDRV_CTL_IOCTL_CARD_BYTES _IOWR('U', 0x02, struct snd_ctl_card_bytes) - #define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list) - #define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info) - #define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value) -diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h ---- a/include/uapi/sound/firewire.h -+++ b/include/uapi/sound/firewire.h -@@ -79,11 +79,12 @@ struct snd_firewire_event_motu_register_dsp_change { - * - * @type: Fixed to SNDRV_FIREWIRE_EVENT_FF400_MESSAGE. - * @message_count: The number of messages. -+ * @messages: Array of @message_count messages - * @messages.message: The messages expressing hardware knob operation. - * @messages.tstamp: The isochronous cycle at which the request subaction of asynchronous -- * transaction was sent to deliver the message. It has 16 bit unsigned integer -+ * transaction was sent to deliver the message. It has 16-bit unsigned integer - * value. The higher 3 bits of value expresses the lower three bits of second -- * field in the format of CYCLE_TIME, up to 7. The rest 13 bits expresses cycle -+ * field in the format of CYCLE_TIME, up to 7. The remaining 13 bits express cycle - * field up to 7999. - * - * The structure expresses message transmitted by Fireface 400 when operating hardware knob. -@@ -191,8 +192,9 @@ struct snd_firewire_motu_register_dsp_meter { - #define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_ALIGNED_INPUT_COUNT (SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT + 2) - - /** -- * snd_firewire_motu_register_dsp_parameter - the container for parameters of DSP controlled -- * by register access. -+ * struct snd_firewire_motu_register_dsp_parameter - the container for parameters -+ * of DSP controlled by register access. -+ * @mixer: aggregate of @mixer.source and @mixer.output - * @mixer.source.gain: The gain of source to mixer. - * @mixer.source.pan: The L/R balance of source to mixer. - * @mixer.source.flag: The flag of source to mixer, including mute, solo. -@@ -200,21 +202,25 @@ struct snd_firewire_motu_register_dsp_meter { - * Audio Express. - * @mixer.source.paired_width: The width of paired source to mixer, only for 4 pre and - * Audio Express. -+ * @mixer.output: FIXME - * @mixer.output.paired_volume: The volume of paired output from mixer. - * @mixer.output.paired_flag: The flag of paired output from mixer. -+ * @output: output parameters - * @output.main_paired_volume: The volume of paired main output. - * @output.hp_paired_volume: The volume of paired hp output. - * @output.hp_paired_assignment: The source assigned to paired hp output. -- * @output.reserved: Padding for 32 bit alignment for future extension. -+ * @output.reserved: Padding for 32-bit alignment for future extension. -+ * @line_input: line input parameters - * @line_input.boost_flag: The flags of boost for line inputs, only for 828mk2 and Traveler. - * @line_input.nominal_level_flag: The flags of nominal level for line inputs, only for 828mk2 and - * Traveler. -- * @line_input.reserved: Padding for 32 bit alignment for future extension. -+ * @line_input.reserved: Padding for 32-bit alignment for future extension. -+ * @input: input parameters - * @input.gain_and_invert: The value including gain and invert for input, only for Ultralite, 4 pre - * and Audio Express. - * @input.flag: The flag of input; e.g. jack detection, phantom power, and pad, only for Ultralite, - * 4 pre and Audio express. -- * @reserved: Padding so that the size of structure is kept to 512 byte, but for future extension. -+ * @reserved: Padding so that the size of structure is kept to 512 bytes, but for future extension. - * - * The structure expresses the set of parameters for DSP controlled by register access. - */ -@@ -272,8 +278,8 @@ struct snd_firewire_motu_register_dsp_parameter { - * controlled by command - * @data: Signal level meters. The mapping between position and signal channel is model-dependent. - * -- * The structure expresses the part of DSP status for hardware meter. The 32 bit storage is -- * estimated to include IEEE 764 32 bit single precision floating point (binary32) value. It is -+ * The structure expresses the part of DSP status for hardware meter. The 32-bit storage is -+ * estimated to include IEEE 764 32-bit single precision floating point (binary32) value. It is - * expected to be linear value (not logarithm) for audio signal level between 0.0 and +1.0. - */ - struct snd_firewire_motu_command_dsp_meter { -diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c ---- a/sound/atmel/ac97c.c -+++ b/sound/atmel/ac97c.c -@@ -693,7 +693,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct snd_card *card; - struct atmel_ac97c *chip; -- struct resource *regs; -+ void __iomem *regs; - struct clk *pclk; - static const struct snd_ac97_bus_ops ops = { - .write = atmel_ac97c_write, -@@ -702,42 +702,34 @@ static int atmel_ac97c_probe(struct platform_device *pdev) - int retval; - int irq; - -- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- if (!regs) { -- dev_dbg(&pdev->dev, "no memory resource\n"); -- return -ENXIO; -- } -+ regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); - - irq = platform_get_irq(pdev, 0); -- if (irq < 0) { -- dev_dbg(&pdev->dev, "could not get irq: %d\n", irq); -+ if (irq < 0) - return irq; -- } - -- pclk = clk_get(&pdev->dev, "ac97_clk"); -+ pclk = devm_clk_get_enabled(&pdev->dev, "ac97_clk"); - if (IS_ERR(pclk)) { - dev_dbg(&pdev->dev, "no peripheral clock\n"); - return PTR_ERR(pclk); - } -- retval = clk_prepare_enable(pclk); -- if (retval) -- goto err_prepare_enable; - -- retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, -+ retval = snd_devm_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, - SNDRV_DEFAULT_STR1, THIS_MODULE, - sizeof(struct atmel_ac97c), &card); - if (retval) { - dev_dbg(&pdev->dev, "could not create sound card device\n"); -- goto err_snd_card_new; -+ return retval; - } - - chip = get_chip(card); - -- retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip); -- if (retval) { -- dev_dbg(&pdev->dev, "unable to request irq %d\n", irq); -- goto err_request_irq; -- } -+ retval = devm_request_irq(&pdev->dev, irq, atmel_ac97c_interrupt, 0, "AC97C", chip); -+ if (retval) -+ return retval; -+ - chip->irq = irq; - - spin_lock_init(&chip->lock); -@@ -749,13 +741,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev) - chip->card = card; - chip->pclk = pclk; - chip->pdev = pdev; -- chip->regs = ioremap(regs->start, resource_size(regs)); -- -- if (!chip->regs) { -- dev_dbg(&pdev->dev, "could not remap register memory\n"); -- retval = -ENOMEM; -- goto err_ioremap; -- } -+ chip->regs = regs; - - chip->reset_pin = devm_gpiod_get_index(dev, "ac97", 2, GPIOD_OUT_HIGH); - if (IS_ERR(chip->reset_pin)) -@@ -770,25 +756,25 @@ static int atmel_ac97c_probe(struct platform_device *pdev) - retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus); - if (retval) { - dev_dbg(&pdev->dev, "could not register on ac97 bus\n"); -- goto err_ac97_bus; -+ return retval; - } - - retval = atmel_ac97c_mixer_new(chip); - if (retval) { - dev_dbg(&pdev->dev, "could not register ac97 mixer\n"); -- goto err_ac97_bus; -+ return retval; - } - - retval = atmel_ac97c_pcm_new(chip); - if (retval) { - dev_dbg(&pdev->dev, "could not register ac97 pcm device\n"); -- goto err_ac97_bus; -+ return retval; - } - - retval = snd_card_register(card); - if (retval) { - dev_dbg(&pdev->dev, "could not register sound card\n"); -- goto err_ac97_bus; -+ return retval; - } - - platform_set_drvdata(pdev, card); -@@ -797,18 +783,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev) - chip->regs, irq); - - return 0; -- --err_ac97_bus: -- iounmap(chip->regs); --err_ioremap: -- free_irq(irq, chip); --err_request_irq: -- snd_card_free(card); --err_snd_card_new: -- clk_disable_unprepare(pclk); --err_prepare_enable: -- clk_put(pclk); -- return retval; - } - - static int atmel_ac97c_suspend(struct device *pdev) -@@ -839,13 +813,6 @@ static void atmel_ac97c_remove(struct platform_device *pdev) - ac97c_writel(chip, CAMR, 0); - ac97c_writel(chip, COMR, 0); - ac97c_writel(chip, MR, 0); -- -- clk_disable_unprepare(chip->pclk); -- clk_put(chip->pclk); -- iounmap(chip->regs); -- free_irq(chip->irq, chip); -- -- snd_card_free(card); - } - - static struct platform_driver atmel_ac97c_driver = { -diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c ---- a/sound/core/compress_offload.c -+++ b/sound/core/compress_offload.c -@@ -1393,17 +1393,17 @@ static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd, - #endif - - static const struct file_operations snd_compr_file_ops = { -- .owner = THIS_MODULE, -- .open = snd_compr_open, -- .release = snd_compr_free, -- .write = snd_compr_write, -- .read = snd_compr_read, -- .unlocked_ioctl = snd_compr_ioctl, -+ .owner = THIS_MODULE, -+ .open = snd_compr_open, -+ .release = snd_compr_free, -+ .write = snd_compr_write, -+ .read = snd_compr_read, -+ .unlocked_ioctl = snd_compr_ioctl, - #ifdef CONFIG_COMPAT -- .compat_ioctl = snd_compr_ioctl_compat, -+ .compat_ioctl = snd_compr_ioctl_compat, - #endif -- .mmap = snd_compr_mmap, -- .poll = snd_compr_poll, -+ .mmap = snd_compr_mmap, -+ .poll = snd_compr_poll, - }; - - static int snd_compress_dev_register(struct snd_device *device) -diff --git a/sound/core/control.c b/sound/core/control.c ---- a/sound/core/control.c -+++ b/sound/core/control.c -@@ -38,7 +38,7 @@ struct snd_kctl_ioctl { - snd_kctl_ioctl_func_t fioctl; - }; - --static DECLARE_RWSEM(snd_ioctl_rwsem); -+DECLARE_RWSEM(snd_ioctl_rwsem); - static DECLARE_RWSEM(snd_ctl_layer_rwsem); - static LIST_HEAD(snd_control_ioctls); - #ifdef CONFIG_COMPAT -@@ -55,9 +55,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) - struct snd_ctl_file *ctl; - int i, err; - -- err = stream_open(inode, file); -- if (err < 0) -- return err; -+ stream_open(inode, file); - - card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL); - if (!card) { -@@ -65,12 +63,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file) - goto __error1; - } - err = snd_card_file_add(card, file); -- if (err < 0) { -- err = -ENODEV; -+ if (err < 0) - goto __error1; -- } - if (!try_module_get(card->module)) { -- err = -EFAULT; -+ err = -ENODEV; - goto __error2; - } - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); -@@ -876,23 +872,81 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, - { - struct snd_ctl_card_info *info __free(kfree) = - kzalloc(sizeof(*info), GFP_KERNEL); -+ ssize_t n; - - if (! info) - return -ENOMEM; -+ -+ static_assert(sizeof(info->components) >= 2); -+ - scoped_guard(rwsem_read, &snd_ioctl_rwsem) { -+ const char *components = card->components; -+ -+ if (!components) -+ components = ""; -+ - info->card = card->number; - strscpy(info->id, card->id, sizeof(info->id)); - strscpy(info->driver, card->driver, sizeof(info->driver)); - strscpy(info->name, card->shortname, sizeof(info->name)); - strscpy(info->longname, card->longname, sizeof(info->longname)); - strscpy(info->mixername, card->mixername, sizeof(info->mixername)); -- strscpy(info->components, card->components, sizeof(info->components)); -+ n = strscpy(info->components, components, sizeof(info->components)); -+ if (n < 0) // mark the truncation with '>' before NULL terminator -+ info->components[sizeof(info->components) - 2] = '>'; - } - if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) - return -EFAULT; - return 0; - } - -+static int snd_ctl_card_bytes(struct snd_card *card, -+ struct snd_ctl_card_bytes *info, -+ unsigned int __user *data_len_out) -+{ -+ unsigned int data_len; -+ -+ switch (info->type) { -+ case SND_CTL_CARD_BTYPE_COMPONENTS: -+ scoped_guard(rwsem_read, &snd_ioctl_rwsem) { -+ const char *components = card->components; -+ -+ if (!components) -+ components = ""; -+ -+ data_len = strlen(components) + 1; -+ -+ if (!info->data || info->data_allocated == 0) -+ break; -+ -+ if (info->data_allocated < data_len) -+ return -ENOMEM; -+ -+ if (copy_to_user(u64_to_user_ptr(info->data), components, data_len)) -+ return -EFAULT; -+ } -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (put_user(data_len, data_len_out)) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static int snd_ctl_card_bytes_user(struct snd_card *card, -+ struct snd_ctl_card_bytes __user *_info) -+{ -+ struct snd_ctl_card_bytes info; -+ -+ if (copy_from_user(&info, _info, sizeof(info))) -+ return -EFAULT; -+ -+ return snd_ctl_card_bytes(card, &info, &_info->data_len); -+} -+ - static int snd_ctl_elem_list(struct snd_card *card, - struct snd_ctl_elem_list *list) - { -@@ -1990,6 +2044,8 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg - return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0; - case SNDRV_CTL_IOCTL_CARD_INFO: - return snd_ctl_card_info(card, ctl, cmd, argp); -+ case SNDRV_CTL_IOCTL_CARD_BYTES: -+ return snd_ctl_card_bytes_user(card, argp); - case SNDRV_CTL_IOCTL_ELEM_LIST: - return snd_ctl_elem_list_user(card, argp); - case SNDRV_CTL_IOCTL_ELEM_INFO: -@@ -2339,16 +2395,15 @@ EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer); - * INIT PART - */ - --static const struct file_operations snd_ctl_f_ops = --{ -- .owner = THIS_MODULE, -- .read = snd_ctl_read, -- .open = snd_ctl_open, -- .release = snd_ctl_release, -- .poll = snd_ctl_poll, -- .unlocked_ioctl = snd_ctl_ioctl, -- .compat_ioctl = snd_ctl_ioctl_compat, -- .fasync = snd_ctl_fasync, -+static const struct file_operations snd_ctl_f_ops = { -+ .owner = THIS_MODULE, -+ .read = snd_ctl_read, -+ .open = snd_ctl_open, -+ .release = snd_ctl_release, -+ .poll = snd_ctl_poll, -+ .unlocked_ioctl = snd_ctl_ioctl, -+ .compat_ioctl = snd_ctl_ioctl_compat, -+ .fasync = snd_ctl_fasync, - }; - - /* call lops under rwsems; called from snd_ctl_dev_*() below() */ -diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c ---- a/sound/core/control_compat.c -+++ b/sound/core/control_compat.c -@@ -226,8 +226,8 @@ static int copy_ctl_value_from_user(struct snd_card *card, - if (type < 0) - return type; - -- if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN || -- type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) { -+ if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || -+ type == SNDRV_CTL_ELEM_TYPE_INTEGER) { - for (i = 0; i < count; i++) { - s32 __user *intp = valuep; - int val; -@@ -236,7 +236,7 @@ static int copy_ctl_value_from_user(struct snd_card *card, - data->value.integer.value[i] = val; - } - } else { -- size = get_elem_size((__force snd_ctl_elem_type_t)type, count); -+ size = get_elem_size(type, count); - if (size < 0) { - dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); - return -EINVAL; -@@ -259,8 +259,8 @@ static int copy_ctl_value_to_user(void __user *userdata, - struct snd_ctl_elem_value32 __user *data32 = userdata; - int i, size; - -- if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN || -- type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) { -+ if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || -+ type == SNDRV_CTL_ELEM_TYPE_INTEGER) { - for (i = 0; i < count; i++) { - s32 __user *intp = valuep; - int val; -@@ -269,7 +269,7 @@ static int copy_ctl_value_to_user(void __user *userdata, - return -EFAULT; - } - } else { -- size = get_elem_size((__force snd_ctl_elem_type_t)type, count); -+ size = get_elem_size(type, count); - if (copy_to_user(valuep, data->value.bytes.data, size)) - return -EFAULT; - } -@@ -417,7 +417,7 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, - break; - } - return snd_ctl_elem_add(file, data, replace); --} -+} - - enum { - SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32), -@@ -446,6 +446,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns - switch (cmd) { - case SNDRV_CTL_IOCTL_PVERSION: - case SNDRV_CTL_IOCTL_CARD_INFO: -+ case SNDRV_CTL_IOCTL_CARD_BYTES: - case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: - case SNDRV_CTL_IOCTL_POWER: - case SNDRV_CTL_IOCTL_POWER_STATE: -diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c ---- a/sound/core/hwdep.c -+++ b/sound/core/hwdep.c -@@ -87,7 +87,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) - - if (!try_module_get(hw->card->module)) { - snd_card_unref(hw->card); -- return -EFAULT; -+ return -ENODEV; - } - - init_waitqueue_entry(&wait, current); -@@ -323,18 +323,17 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, - - */ - --static const struct file_operations snd_hwdep_f_ops = --{ -- .owner = THIS_MODULE, -- .llseek = snd_hwdep_llseek, -- .read = snd_hwdep_read, -- .write = snd_hwdep_write, -- .open = snd_hwdep_open, -- .release = snd_hwdep_release, -- .poll = snd_hwdep_poll, -- .unlocked_ioctl = snd_hwdep_ioctl, -- .compat_ioctl = snd_hwdep_ioctl_compat, -- .mmap = snd_hwdep_mmap, -+static const struct file_operations snd_hwdep_f_ops = { -+ .owner = THIS_MODULE, -+ .llseek = snd_hwdep_llseek, -+ .read = snd_hwdep_read, -+ .write = snd_hwdep_write, -+ .open = snd_hwdep_open, -+ .release = snd_hwdep_release, -+ .poll = snd_hwdep_poll, -+ .unlocked_ioctl = snd_hwdep_ioctl, -+ .compat_ioctl = snd_hwdep_ioctl_compat, -+ .mmap = snd_hwdep_mmap, - }; - - static void snd_hwdep_free(struct snd_hwdep *hwdep) -diff --git a/sound/core/info.c b/sound/core/info.c ---- a/sound/core/info.c -+++ b/sound/core/info.c -@@ -78,7 +78,7 @@ static int alloc_info_private(struct snd_info_entry *entry, - if (!entry || !entry->p) - return -ENODEV; - if (!try_module_get(entry->module)) -- return -EFAULT; -+ return -ENODEV; - data = kzalloc_obj(*data); - if (!data) { - module_put(entry->module); -diff --git a/sound/core/init.c b/sound/core/init.c ---- a/sound/core/init.c -+++ b/sound/core/init.c -@@ -466,20 +466,19 @@ static int snd_disconnect_fasync(int fd, struct file *file, int on) - return -ENODEV; - } - --static const struct file_operations snd_shutdown_f_ops = --{ -- .owner = THIS_MODULE, -- .llseek = snd_disconnect_llseek, -- .read = snd_disconnect_read, -- .write = snd_disconnect_write, -- .release = snd_disconnect_release, -- .poll = snd_disconnect_poll, -- .unlocked_ioctl = snd_disconnect_ioctl, -+static const struct file_operations snd_shutdown_f_ops = { -+ .owner = THIS_MODULE, -+ .llseek = snd_disconnect_llseek, -+ .read = snd_disconnect_read, -+ .write = snd_disconnect_write, -+ .release = snd_disconnect_release, -+ .poll = snd_disconnect_poll, -+ .unlocked_ioctl = snd_disconnect_ioctl, - #ifdef CONFIG_COMPAT -- .compat_ioctl = snd_disconnect_ioctl, -+ .compat_ioctl = snd_disconnect_ioctl, - #endif -- .mmap = snd_disconnect_mmap, -- .fasync = snd_disconnect_fasync -+ .mmap = snd_disconnect_mmap, -+ .fasync = snd_disconnect_fasync - }; - - /** -@@ -592,6 +591,9 @@ static int snd_card_do_free(struct snd_card *card) - snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); - #endif - snd_device_free_all(card); -+ kfree(card->components); -+ card->components = NULL; -+ card->components_alloc_size = 0; - if (card->private_free) - card->private_free(card); - #ifdef CONFIG_SND_CTL_DEBUG -@@ -725,7 +727,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src, - int len, loops; - bool is_default = false; - char *id; -- -+ - copy_valid_id_string(card, src, nid); - id = card->id; - -@@ -1034,21 +1036,44 @@ int __init snd_card_info_init(void) - * - * Return: Zero otherwise a negative error code. - */ -- -+ - int snd_component_add(struct snd_card *card, const char *component) - { - char *ptr; - int len = strlen(component); -+ unsigned int cur_len, need_len; - -- ptr = strstr(card->components, component); -- if (ptr != NULL) { -- if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */ -- return 1; -+ guard(rwsem_write)(&snd_ioctl_rwsem); -+ -+ if (card->components) { -+ ptr = strstr(card->components, component); -+ if (ptr) { -+ if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */ -+ return 1; -+ } -+ cur_len = strlen(card->components) + 1; -+ } else { -+ cur_len = 0; - } -- if (strlen(card->components) + 1 + len + 1 > sizeof(card->components)) { -+ -+ need_len = cur_len + len + 1; -+ if (need_len > 512) { - snd_BUG(); - return -ENOMEM; - } -+ -+ if (need_len > card->components_alloc_size) { -+ unsigned int new_alloc = roundup(need_len, 32); -+ -+ ptr = krealloc(card->components, new_alloc, GFP_KERNEL); -+ if (!ptr) -+ return -ENOMEM; -+ if (!card->components) -+ ptr[0] = '\0'; -+ card->components = ptr; -+ card->components_alloc_size = new_alloc; -+ } -+ - if (card->components[0] != '\0') - strcat(card->components, " "); - strcat(card->components, component); -diff --git a/sound/core/jack.c b/sound/core/jack.c ---- a/sound/core/jack.c -+++ b/sound/core/jack.c -@@ -303,41 +303,41 @@ static ssize_t jack_type_read(struct file *file, - } - - static const struct file_operations jack_type_fops = { -- .open = simple_open, -- .read = jack_type_read, -- .llseek = default_llseek, -+ .open = simple_open, -+ .read = jack_type_read, -+ .llseek = default_llseek, - }; - #endif - - static const struct file_operations sw_inject_enable_fops = { -- .open = simple_open, -- .read = sw_inject_enable_read, -- .write = sw_inject_enable_write, -- .llseek = default_llseek, -+ .open = simple_open, -+ .read = sw_inject_enable_read, -+ .write = sw_inject_enable_write, -+ .llseek = default_llseek, - }; - - static const struct file_operations jackin_inject_fops = { -- .open = simple_open, -- .write = jackin_inject_write, -- .llseek = default_llseek, -+ .open = simple_open, -+ .write = jackin_inject_write, -+ .llseek = default_llseek, - }; - - static const struct file_operations jack_kctl_id_fops = { -- .open = simple_open, -- .read = jack_kctl_id_read, -- .llseek = default_llseek, -+ .open = simple_open, -+ .read = jack_kctl_id_read, -+ .llseek = default_llseek, - }; - - static const struct file_operations jack_kctl_mask_bits_fops = { -- .open = simple_open, -- .read = jack_kctl_mask_bits_read, -- .llseek = default_llseek, -+ .open = simple_open, -+ .read = jack_kctl_mask_bits_read, -+ .llseek = default_llseek, - }; - - static const struct file_operations jack_kctl_status_fops = { -- .open = simple_open, -- .read = jack_kctl_status_read, -- .llseek = default_llseek, -+ .open = simple_open, -+ .read = jack_kctl_status_read, -+ .llseek = default_llseek, - }; - - static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, -diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c ---- a/sound/core/oss/mixer_oss.c -+++ b/sound/core/oss/mixer_oss.c -@@ -30,9 +30,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) - struct snd_mixer_oss_file *fmixer; - int err; - -- err = nonseekable_open(inode, file); -- if (err < 0) -- return err; -+ nonseekable_open(inode, file); - - card = snd_lookup_oss_minor_data(iminor(inode), - SNDRV_OSS_DEVICE_TYPE_MIXER); -@@ -60,7 +58,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) - kfree(fmixer); - snd_card_file_remove(card, file); - snd_card_unref(card); -- return -EFAULT; -+ return -ENODEV; - } - snd_card_unref(card); - return 0; -@@ -407,13 +405,12 @@ static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd, - * REGISTRATION PART - */ - --static const struct file_operations snd_mixer_oss_f_ops = --{ -- .owner = THIS_MODULE, -- .open = snd_mixer_oss_open, -- .release = snd_mixer_oss_release, -- .unlocked_ioctl = snd_mixer_oss_ioctl, -- .compat_ioctl = snd_mixer_oss_ioctl_compat, -+static const struct file_operations snd_mixer_oss_f_ops = { -+ .owner = THIS_MODULE, -+ .open = snd_mixer_oss_open, -+ .release = snd_mixer_oss_release, -+ .unlocked_ioctl = snd_mixer_oss_ioctl, -+ .compat_ioctl = snd_mixer_oss_ioctl_compat, - }; - - /* -diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c ---- a/sound/core/oss/pcm_oss.c -+++ b/sound/core/oss/pcm_oss.c -@@ -879,11 +879,11 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) - _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0); - snd_mask_none(&mask); - if (atomic_read(&substream->mmap_count)) -- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); -+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); - else { -- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED); -+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED); - if (!direct) -- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); -+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); - } - err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask); - if (err < 0) { -@@ -909,7 +909,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) - else - sformat = snd_pcm_plug_slave_format(format, sformat_mask); - -- if ((__force int)sformat < 0 || -+ if (sformat < 0 || - !snd_mask_test_format(sformat_mask, sformat)) { - pcm_for_each_format(sformat) { - if (snd_mask_test_format(sformat_mask, sformat) && -@@ -921,7 +921,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) - goto failure; - } - format_found: -- err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0); -+ err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0); - if (err < 0) - goto failure; - -@@ -930,9 +930,9 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) - } else { - _snd_pcm_hw_params_any(params); - _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, -- (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0); -+ SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0); - _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, -- (__force int)snd_pcm_oss_format_from(runtime->oss.format), 0); -+ snd_pcm_oss_format_from(runtime->oss.format), 0); - _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, - runtime->oss.channels, 0); - _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, -@@ -1875,7 +1875,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) - format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); - for (fmt = 0; fmt < 32; ++fmt) { - if (snd_mask_test(format_mask, fmt)) { -- int f = snd_pcm_oss_format_to((__force snd_pcm_format_t)fmt); -+ int f = snd_pcm_oss_format_to(fmt); - if (f >= 0) - formats |= f; - } -@@ -2495,9 +2495,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) - int nonblock; - wait_queue_entry_t wait; - -- err = nonseekable_open(inode, file); -- if (err < 0) -- return err; -+ nonseekable_open(inode, file); - - pcm = snd_lookup_oss_minor_data(iminor(inode), - SNDRV_OSS_DEVICE_TYPE_PCM); -@@ -2509,7 +2507,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) - if (err < 0) - goto __error1; - if (!try_module_get(pcm->card->module)) { -- err = -EFAULT; -+ err = -ENODEV; - goto __error2; - } - if (snd_task_name(current, task_name, sizeof(task_name)) < 0) { -@@ -3129,17 +3127,16 @@ static inline void snd_pcm_oss_proc_done(struct snd_pcm *pcm) - * ENTRY functions - */ - --static const struct file_operations snd_pcm_oss_f_reg = --{ -- .owner = THIS_MODULE, -- .read = snd_pcm_oss_read, -- .write = snd_pcm_oss_write, -- .open = snd_pcm_oss_open, -- .release = snd_pcm_oss_release, -- .poll = snd_pcm_oss_poll, -- .unlocked_ioctl = snd_pcm_oss_ioctl, -- .compat_ioctl = snd_pcm_oss_ioctl_compat, -- .mmap = snd_pcm_oss_mmap, -+static const struct file_operations snd_pcm_oss_f_reg = { -+ .owner = THIS_MODULE, -+ .read = snd_pcm_oss_read, -+ .write = snd_pcm_oss_write, -+ .open = snd_pcm_oss_open, -+ .release = snd_pcm_oss_release, -+ .poll = snd_pcm_oss_poll, -+ .unlocked_ioctl = snd_pcm_oss_ioctl, -+ .compat_ioctl = snd_pcm_oss_ioctl_compat, -+ .mmap = snd_pcm_oss_mmap, - }; - - static void register_oss_dsp(struct snd_pcm *pcm, int index) -diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c ---- a/sound/core/oss/pcm_plugin.c -+++ b/sound/core/oss/pcm_plugin.c -@@ -272,13 +272,13 @@ static int snd_pcm_plug_formats(const struct snd_mask *mask, - SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE | - SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE); -- snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW); -+ snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW); - - if (formats.bits[0] & lower_32_bits(linfmts)) - formats.bits[0] |= lower_32_bits(linfmts); - if (formats.bits[1] & upper_32_bits(linfmts)) - formats.bits[1] |= upper_32_bits(linfmts); -- return snd_mask_test(&formats, (__force int)format); -+ return snd_mask_test(&formats, format); - } - - static const snd_pcm_format_t preferred_formats[] = { -@@ -307,20 +307,20 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, - { - int i; - -- if (snd_mask_test(format_mask, (__force int)format)) -+ if (snd_mask_test(format_mask, format)) - return format; - if (!snd_pcm_plug_formats(format_mask, format)) -- return (__force snd_pcm_format_t)-EINVAL; -+ return -EINVAL; - if (snd_pcm_format_linear(format)) { - unsigned int width = snd_pcm_format_width(format); - int unsignd = snd_pcm_format_unsigned(format) > 0; - int big = snd_pcm_format_big_endian(format) > 0; - unsigned int badness, best = -1; -- snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1; -+ snd_pcm_format_t best_format = -1; - for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) { - snd_pcm_format_t f = preferred_formats[i]; - unsigned int w; -- if (!snd_mask_test(format_mask, (__force int)f)) -+ if (!snd_mask_test(format_mask, f)) - continue; - w = snd_pcm_format_width(f); - if (w >= width) -@@ -334,21 +334,21 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, - best = badness; - } - } -- if ((__force int)best_format >= 0) -+ if (best_format >= 0) - return best_format; - else -- return (__force snd_pcm_format_t)-EINVAL; -+ return -EINVAL; - } else { - switch (format) { - case SNDRV_PCM_FORMAT_MU_LAW: - for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) { - snd_pcm_format_t format1 = preferred_formats[i]; -- if (snd_mask_test(format_mask, (__force int)format1)) -+ if (snd_mask_test(format_mask, format1)) - return format1; - } - fallthrough; - default: -- return (__force snd_pcm_format_t)-EINVAL; -+ return -EINVAL; - } - } - } -diff --git a/sound/core/pcm.c b/sound/core/pcm.c ---- a/sound/core/pcm.c -+++ b/sound/core/pcm.c -@@ -211,11 +211,9 @@ static const char * const snd_pcm_format_names[] = { - */ - const char *snd_pcm_format_name(snd_pcm_format_t format) - { -- unsigned int format_num = (__force unsigned int)format; -- -- if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num]) -+ if (format >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format]) - return "Unknown"; -- return snd_pcm_format_names[format_num]; -+ return snd_pcm_format_names[format]; - } - EXPORT_SYMBOL_GPL(snd_pcm_format_name); - -@@ -275,12 +273,12 @@ static const char *snd_pcm_stream_name(int stream) - - static const char *snd_pcm_access_name(snd_pcm_access_t access) - { -- return snd_pcm_access_names[(__force int)access]; -+ return snd_pcm_access_names[access]; - } - - static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat) - { -- return snd_pcm_subformat_names[(__force int)subformat]; -+ return snd_pcm_subformat_names[subformat]; - } - - static const char *snd_pcm_tstamp_mode_name(int mode) -@@ -290,7 +288,7 @@ static const char *snd_pcm_tstamp_mode_name(int mode) - - static const char *snd_pcm_state_name(snd_pcm_state_t state) - { -- return snd_pcm_state_names[(__force int)state]; -+ return snd_pcm_state_names[state]; - } - - #if IS_ENABLED(CONFIG_SND_PCM_OSS) -diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c ---- a/sound/core/pcm_misc.c -+++ b/sound/core/pcm_misc.c -@@ -24,15 +24,12 @@ struct pcm_format_data { - unsigned char silence[8]; /* silence data to fill */ - }; - --/* we do lots of calculations on snd_pcm_format_t; shut up sparse */ --#define INT __force int -- - static bool valid_format(snd_pcm_format_t format) - { -- return (INT)format >= 0 && (INT)format <= (INT)SNDRV_PCM_FORMAT_LAST; -+ return format >= 0 && format <= SNDRV_PCM_FORMAT_LAST; - } - --static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { -+static const struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { - [SNDRV_PCM_FORMAT_S8] = { - .width = 8, .phys = 8, .le = -1, .signd = 1, - .silence = {}, -@@ -251,7 +248,7 @@ int snd_pcm_format_signed(snd_pcm_format_t format) - int val; - if (!valid_format(format)) - return -EINVAL; -- val = pcm_formats[(INT)format].signd; -+ val = pcm_formats[format].signd; - if (val < 0) - return -EINVAL; - return val; -@@ -300,7 +297,7 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) - int val; - if (!valid_format(format)) - return -EINVAL; -- val = pcm_formats[(INT)format].le; -+ val = pcm_formats[format].le; - if (val < 0) - return -EINVAL; - return val; -@@ -337,7 +334,7 @@ int snd_pcm_format_width(snd_pcm_format_t format) - int val; - if (!valid_format(format)) - return -EINVAL; -- val = pcm_formats[(INT)format].width; -+ val = pcm_formats[format].width; - if (!val) - return -EINVAL; - return val; -@@ -356,7 +353,7 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) - int val; - if (!valid_format(format)) - return -EINVAL; -- val = pcm_formats[(INT)format].phys; -+ val = pcm_formats[format].phys; - if (!val) - return -EINVAL; - return val; -@@ -390,9 +387,9 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) - { - if (!valid_format(format)) - return NULL; -- if (! pcm_formats[(INT)format].phys) -+ if (! pcm_formats[format].phys) - return NULL; -- return pcm_formats[(INT)format].silence; -+ return pcm_formats[format].silence; - } - EXPORT_SYMBOL(snd_pcm_format_silence_64); - -@@ -416,12 +413,12 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int - return -EINVAL; - if (samples == 0) - return 0; -- width = pcm_formats[(INT)format].phys; /* physical width */ -+ width = pcm_formats[format].phys; /* physical width */ - if (!width) - return -EINVAL; -- pat = pcm_formats[(INT)format].silence; -+ pat = pcm_formats[format].silence; - /* signed or 1 byte data */ -- if (pcm_formats[(INT)format].signd == 1 || width <= 8) { -+ if (pcm_formats[format].signd == 1 || width <= 8) { - unsigned int bytes = samples * width / 8; - memset(data, *pat, bytes); - return 0; -diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c ---- a/sound/core/pcm_native.c -+++ b/sound/core/pcm_native.c -@@ -257,7 +257,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, - } - - /* macro for simplified cast */ --#define PARAM_MASK_BIT(b) (1U << (__force int)(b)) -+#define PARAM_MASK_BIT(b) (1U << (b)) - - static bool hw_support_mmap(struct snd_pcm_substream *substream) - { -@@ -489,7 +489,7 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, - params->msbits = snd_interval_value(i); - m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); - if (snd_mask_single(m)) { -- snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m); -+ snd_pcm_format_t format = snd_mask_min(m); - params->msbits = snd_pcm_format_width(format); - } - } -@@ -497,13 +497,13 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, - if (params->msbits) { - m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); - if (snd_mask_single(m)) { -- snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m); -+ snd_pcm_format_t format = snd_mask_min(m); - - if (snd_pcm_format_linear(format) && - snd_pcm_format_width(format) != params->msbits) { - m_rw = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT); - snd_mask_reset(m_rw, -- (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX); -+ SNDRV_PCM_SUBFORMAT_MSBITS_MAX); - if (snd_mask_empty(m_rw)) - return -EINVAL; - } -@@ -1252,7 +1252,7 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream) - runtime->trigger_master = NULL; - } - --#define ACTION_ARG_IGNORE (__force snd_pcm_state_t)0 -+#define ACTION_ARG_IGNORE 0 - - struct action_ops { - int (*pre_action)(struct snd_pcm_substream *substream, -@@ -1637,7 +1637,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun); - /* - * pause callbacks: pass boolean (to start pause or resume) as state argument - */ --#define pause_pushed(state) (__force bool)(state) -+#define pause_pushed(state) (bool)(state) - - static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, - snd_pcm_state_t state) -@@ -1709,14 +1709,14 @@ static const struct action_ops snd_pcm_action_pause = { - static int snd_pcm_pause(struct snd_pcm_substream *substream, bool push) - { - return snd_pcm_action(&snd_pcm_action_pause, substream, -- (__force snd_pcm_state_t)push); -+ (snd_pcm_state_t)push); - } - - static int snd_pcm_pause_lock_irq(struct snd_pcm_substream *substream, - bool push) - { - return snd_pcm_action_lock_irq(&snd_pcm_action_pause, substream, -- (__force snd_pcm_state_t)push); -+ (snd_pcm_state_t)push); - } - - #ifdef CONFIG_PM -@@ -1984,7 +1984,7 @@ static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, - snd_pcm_state_t state) - { - snd_pcm_state_t cur_state = snd_pcm_get_state(substream); -- int f_flags = (__force int)state; -+ int f_flags = state; - - if (cur_state == SNDRV_PCM_STATE_OPEN || - cur_state == SNDRV_PCM_STATE_DISCONNECTED) -@@ -2052,7 +2052,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, - - return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, - substream, -- (__force snd_pcm_state_t)f_flags); -+ (snd_pcm_state_t)f_flags); - } - - /* -@@ -2463,7 +2463,7 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, - if (bits <= 0) - continue; /* ignore invalid formats */ - if ((unsigned)bits < i->min || (unsigned)bits > i->max) -- snd_mask_reset(&m, (__force unsigned)k); -+ snd_mask_reset(&m, k); - } - return snd_mask_refine(mask, &m); - } -@@ -2545,16 +2545,16 @@ static int snd_pcm_hw_rule_subformats(struct snd_pcm_hw_params *params, - - snd_mask_none(&m); - /* All PCMs support at least the default STD subformat. */ -- snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_STD); -+ snd_mask_set(&m, SNDRV_PCM_SUBFORMAT_STD); - - pcm_for_each_format(f) { -- if (!snd_mask_test(fmask, (__force unsigned)f)) -+ if (!snd_mask_test(fmask, f)) - continue; - - if (f == SNDRV_PCM_FORMAT_S32_LE && *subformats) - m.bits[0] |= *subformats; - else if (snd_pcm_format_linear(f)) -- snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX); -+ snd_mask_set(&m, SNDRV_PCM_SUBFORMAT_MSBITS_MAX); - } - - return snd_mask_refine(sfmask, &m); -@@ -2882,9 +2882,10 @@ static int snd_pcm_open_file(struct file *file, - static int snd_pcm_playback_open(struct inode *inode, struct file *file) - { - struct snd_pcm *pcm; -- int err = nonseekable_open(inode, file); -- if (err < 0) -- return err; -+ int err; -+ -+ nonseekable_open(inode, file); -+ - pcm = snd_lookup_minor_data(iminor(inode), - SNDRV_DEVICE_TYPE_PCM_PLAYBACK); - err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); -@@ -2896,9 +2897,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) - static int snd_pcm_capture_open(struct inode *inode, struct file *file) - { - struct snd_pcm *pcm; -- int err = nonseekable_open(inode, file); -- if (err < 0) -- return err; -+ int err; -+ -+ nonseekable_open(inode, file); -+ - pcm = snd_lookup_minor_data(iminor(inode), - SNDRV_DEVICE_TYPE_PCM_CAPTURE); - err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); -@@ -2920,7 +2922,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) - if (err < 0) - goto __error1; - if (!try_module_get(pcm->card->module)) { -- err = -EFAULT; -+ err = -ENODEV; - goto __error2; - } - init_waitqueue_entry(&wait, current); -@@ -3916,6 +3918,8 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf) - if (substream == NULL) - return VM_FAULT_SIGBUS; - runtime = substream->runtime; -+ if (runtime->state == SNDRV_PCM_STATE_DISCONNECTED) -+ return VM_FAULT_SIGBUS; - offset = vmf->pgoff << PAGE_SHIFT; - dma_bytes = PAGE_ALIGN(runtime->dma_bytes); - if (offset > dma_bytes - PAGE_SIZE) -@@ -4256,29 +4260,29 @@ static unsigned long snd_pcm_get_unmapped_area(struct file *file, - - const struct file_operations snd_pcm_f_ops[2] = { - { -- .owner = THIS_MODULE, -- .write = snd_pcm_write, -- .write_iter = snd_pcm_writev, -- .open = snd_pcm_playback_open, -- .release = snd_pcm_release, -- .poll = snd_pcm_poll, -- .unlocked_ioctl = snd_pcm_ioctl, -- .compat_ioctl = snd_pcm_ioctl_compat, -- .mmap = snd_pcm_mmap, -- .fasync = snd_pcm_fasync, -- .get_unmapped_area = snd_pcm_get_unmapped_area, -+ .owner = THIS_MODULE, -+ .write = snd_pcm_write, -+ .write_iter = snd_pcm_writev, -+ .open = snd_pcm_playback_open, -+ .release = snd_pcm_release, -+ .poll = snd_pcm_poll, -+ .unlocked_ioctl = snd_pcm_ioctl, -+ .compat_ioctl = snd_pcm_ioctl_compat, -+ .mmap = snd_pcm_mmap, -+ .fasync = snd_pcm_fasync, -+ .get_unmapped_area = snd_pcm_get_unmapped_area, - }, - { -- .owner = THIS_MODULE, -- .read = snd_pcm_read, -- .read_iter = snd_pcm_readv, -- .open = snd_pcm_capture_open, -- .release = snd_pcm_release, -- .poll = snd_pcm_poll, -- .unlocked_ioctl = snd_pcm_ioctl, -- .compat_ioctl = snd_pcm_ioctl_compat, -- .mmap = snd_pcm_mmap, -- .fasync = snd_pcm_fasync, -- .get_unmapped_area = snd_pcm_get_unmapped_area, -+ .owner = THIS_MODULE, -+ .read = snd_pcm_read, -+ .read_iter = snd_pcm_readv, -+ .open = snd_pcm_capture_open, -+ .release = snd_pcm_release, -+ .poll = snd_pcm_poll, -+ .unlocked_ioctl = snd_pcm_ioctl, -+ .compat_ioctl = snd_pcm_ioctl_compat, -+ .mmap = snd_pcm_mmap, -+ .fasync = snd_pcm_fasync, -+ .get_unmapped_area = snd_pcm_get_unmapped_area, - } - }; -diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c ---- a/sound/core/rawmidi.c -+++ b/sound/core/rawmidi.c -@@ -408,9 +408,10 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, - return 0; - } - --/* called from sound/core/seq/seq_midi.c */ --int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice, -- int mode, struct snd_rawmidi_file *rfile) -+/* called from sound/core/seq/seq_midi.c and sound/core/ump.c */ -+int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice, -+ int mode, struct snd_rawmidi_file *rfile, -+ int depth) - { - int err; - -@@ -419,13 +420,14 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice, - if (!try_module_get(rmidi->card->module)) - return -ENXIO; - -- guard(mutex)(&rmidi->open_mutex); -+ mutex_lock_nested(&rmidi->open_mutex, depth); - err = rawmidi_open_priv(rmidi, subdevice, mode, rfile); - if (err < 0) - module_put(rmidi->card->module); -+ mutex_unlock(&rmidi->open_mutex); - return err; - } --EXPORT_SYMBOL(snd_rawmidi_kernel_open); -+EXPORT_SYMBOL(snd_rawmidi_kernel_open_nested); - - static int snd_rawmidi_open(struct inode *inode, struct file *file) - { -@@ -441,9 +443,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) - if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) - return -EINVAL; /* invalid combination */ - -- err = stream_open(inode, file); -- if (err < 0) -- return err; -+ stream_open(inode, file); - - if (maj == snd_major) { - rmidi = snd_lookup_minor_data(iminor(inode), -@@ -1784,14 +1784,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, - */ - - static const struct file_operations snd_rawmidi_f_ops = { -- .owner = THIS_MODULE, -- .read = snd_rawmidi_read, -- .write = snd_rawmidi_write, -- .open = snd_rawmidi_open, -- .release = snd_rawmidi_release, -- .poll = snd_rawmidi_poll, -- .unlocked_ioctl = snd_rawmidi_ioctl, -- .compat_ioctl = snd_rawmidi_ioctl_compat, -+ .owner = THIS_MODULE, -+ .read = snd_rawmidi_read, -+ .write = snd_rawmidi_write, -+ .open = snd_rawmidi_open, -+ .release = snd_rawmidi_release, -+ .poll = snd_rawmidi_poll, -+ .unlocked_ioctl = snd_rawmidi_ioctl, -+ .compat_ioctl = snd_rawmidi_ioctl_compat, - }; - - static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, -diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c ---- a/sound/core/seq/oss/seq_oss.c -+++ b/sound/core/seq/oss/seq_oss.c -@@ -206,17 +206,16 @@ odev_poll(struct file *file, poll_table * wait) - * registration of sequencer minor device - */ - --static const struct file_operations seq_oss_f_ops = --{ -- .owner = THIS_MODULE, -- .read = odev_read, -- .write = odev_write, -- .open = odev_open, -- .release = odev_release, -- .poll = odev_poll, -- .unlocked_ioctl = odev_ioctl, -- .compat_ioctl = odev_ioctl_compat, -- .llseek = noop_llseek, -+static const struct file_operations seq_oss_f_ops = { -+ .owner = THIS_MODULE, -+ .read = odev_read, -+ .write = odev_write, -+ .open = odev_open, -+ .release = odev_release, -+ .poll = odev_poll, -+ .unlocked_ioctl = odev_ioctl, -+ .compat_ioctl = odev_ioctl_compat, -+ .llseek = noop_llseek, - }; - - static int __init -diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c ---- a/sound/core/seq/seq_clientmgr.c -+++ b/sound/core/seq/seq_clientmgr.c -@@ -59,7 +59,7 @@ static DEFINE_MUTEX(register_mutex); - * client table - */ - static char clienttablock[SNDRV_SEQ_MAX_CLIENTS]; --static struct snd_seq_client *clienttab[SNDRV_SEQ_MAX_CLIENTS]; -+static struct snd_seq_client __rcu *clienttab[SNDRV_SEQ_MAX_CLIENTS]; - static struct snd_seq_usage client_usage; - - /* -@@ -95,15 +95,23 @@ static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client) - return snd_seq_total_cells(client->pool) > 0; - } - --/* return pointer to client structure for specified id */ --static struct snd_seq_client *clientptr(int clientid) -+/* return pointer to client structure for specified id; call under RCU read-lock */ -+static struct snd_seq_client *__clientptr(int clientid) - { - if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) { - pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n", - clientid); - return NULL; - } -- return clienttab[clientid]; -+ return rcu_dereference_check(clienttab[clientid], -+ lockdep_is_held(&clients_lock)); -+} -+ -+/* return pointer to client structure for specified id */ -+static struct snd_seq_client *clientptr(int clientid) -+{ -+ guard(rcu)(); -+ return __clientptr(clientid); - } - - static struct snd_seq_client *client_use_ptr(int clientid, bool load_module) -@@ -115,8 +123,8 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module) - clientid); - return NULL; - } -- scoped_guard(spinlock_irqsave, &clients_lock) { -- client = clientptr(clientid); -+ scoped_guard(rcu) { -+ client = __clientptr(clientid); - if (client) - return snd_seq_client_ref(client); - if (clienttablock[clientid]) -@@ -150,8 +158,8 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module) - snd_seq_device_load_drivers(); - } - } -- scoped_guard(spinlock_irqsave, &clients_lock) { -- client = clientptr(clientid); -+ scoped_guard(rcu) { -+ client = __clientptr(clientid); - if (client) - return snd_seq_client_ref(client); - } -@@ -212,7 +220,6 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) - } - client->type = NO_CLIENT; - snd_use_lock_init(&client->use_lock); -- rwlock_init(&client->ports_lock); - mutex_init(&client->ports_mutex); - INIT_LIST_HEAD(&client->ports_list_head); - mutex_init(&client->ioctl_mutex); -@@ -224,14 +231,17 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) - for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN; - c < SNDRV_SEQ_MAX_CLIENTS; - c++) { -- if (clienttab[c] || clienttablock[c]) -+ if (rcu_access_pointer(clienttab[c]) || clienttablock[c]) - continue; -- clienttab[client->number = c] = client; -+ client->number = c; -+ rcu_assign_pointer(clienttab[c], client); - return client; - } - } else { -- if (clienttab[client_index] == NULL && !clienttablock[client_index]) { -- clienttab[client->number = client_index] = client; -+ if (rcu_access_pointer(clienttab[client_index]) == NULL && -+ !clienttablock[client_index]) { -+ client->number = client_index; -+ rcu_assign_pointer(clienttab[client_index], client); - return client; - } - } -@@ -249,10 +259,16 @@ static int seq_free_client1(struct snd_seq_client *client) - return 0; - scoped_guard(spinlock_irq, &clients_lock) { - clienttablock[client->number] = 1; -- clienttab[client->number] = NULL; -+ rcu_assign_pointer(clienttab[client->number], NULL); - } - snd_seq_delete_all_ports(client); - snd_seq_queue_client_leave(client->number); -+ /* the client has been unpublished from the table; wait for a grace -+ * period so that lockless readers (snd_seq_client_use_ptr()) that -+ * observed the old pointer can no longer take a new use_lock -+ * reference, then drain the outstanding references before freeing -+ */ -+ synchronize_rcu(); - snd_use_lock_sync(&client->use_lock); - if (client->pool) - snd_seq_pool_delete(&client->pool); -@@ -296,11 +312,8 @@ static int snd_seq_open(struct inode *inode, struct file *file) - int c, mode; /* client id */ - struct snd_seq_client *client; - struct snd_seq_user_client *user; -- int err; - -- err = stream_open(inode, file); -- if (err < 0) -- return err; -+ stream_open(inode, file); - - scoped_guard(mutex, ®ister_mutex) { - client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS); -@@ -517,9 +530,8 @@ static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event) - * Return the error event. - * - * If the receiver client is a user client, the original event is -- * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. If -- * the original event is also variable length, the external data is -- * copied after the event record. -+ * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. The -+ * external data of a variable length event is not copied along. - * If the receiver client is a kernel client, the original event is - * quoted in SNDRV_SEQ_EVENT_KERNEL_ERROR, since this requires no extra - * kmalloc. -@@ -724,10 +736,11 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, - - /* lock list */ - if (atomic) -- read_lock(&grp->list_lock); -+ rcu_read_lock(); - else - down_read_nested(&grp->list_mutex, hop); -- list_for_each_entry(subs, &grp->list_head, src_list) { -+ hlist_for_each_entry_rcu(subs, &grp->list_head, src_list, -+ lockdep_is_held(&grp->list_mutex)) { - /* both ports ready? */ - if (atomic_read(&subs->ref_count) != 2) - continue; -@@ -748,7 +761,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client, - memcpy(event, &event_saved, saved_size); - } - if (atomic) -- read_unlock(&grp->list_lock); -+ rcu_read_unlock(); - else - up_read(&grp->list_mutex); - memcpy(event, &event_saved, saved_size); -@@ -1945,7 +1958,7 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) - { - struct snd_seq_query_subs *subs = arg; - struct snd_seq_port_subs_info *group; -- struct list_head *p; -+ struct hlist_node *p; - int i; - - struct snd_seq_client *cptr __free(snd_seq_client) = -@@ -1972,15 +1985,15 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg) - /* search for the subscriber */ - subs->num_subs = group->count; - i = 0; -- list_for_each(p, &group->list_head) { -+ hlist_for_each(p, &group->list_head) { - if (i++ == subs->index) { - /* found! */ - struct snd_seq_subscribers *s; - if (subs->type == SNDRV_SEQ_QUERY_SUBS_READ) { -- s = list_entry(p, struct snd_seq_subscribers, src_list); -+ s = hlist_entry(p, struct snd_seq_subscribers, src_list); - subs->addr = s->info.dest; - } else { -- s = list_entry(p, struct snd_seq_subscribers, dest_list); -+ s = hlist_entry(p, struct snd_seq_subscribers, dest_list); - subs->addr = s->info.sender; - } - subs->flags = s->info.flags; -@@ -2536,19 +2549,19 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer, - struct snd_seq_port_subs_info *group, - int is_src, char *msg) - { -- struct list_head *p; -+ struct hlist_node *p; - struct snd_seq_subscribers *s; - int count = 0; - - guard(rwsem_read)(&group->list_mutex); -- if (list_empty(&group->list_head)) -+ if (hlist_empty(&group->list_head)) - return; - snd_iprintf(buffer, msg); -- list_for_each(p, &group->list_head) { -+ hlist_for_each(p, &group->list_head) { - if (is_src) -- s = list_entry(p, struct snd_seq_subscribers, src_list); -+ s = hlist_entry(p, struct snd_seq_subscribers, src_list); - else -- s = list_entry(p, struct snd_seq_subscribers, dest_list); -+ s = hlist_entry(p, struct snd_seq_subscribers, dest_list); - if (count++) - snd_iprintf(buffer, ", "); - snd_iprintf(buffer, "%d:%d", -@@ -2670,16 +2683,15 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, - * REGISTRATION PART - */ - --static const struct file_operations snd_seq_f_ops = --{ -- .owner = THIS_MODULE, -- .read = snd_seq_read, -- .write = snd_seq_write, -- .open = snd_seq_open, -- .release = snd_seq_release, -- .poll = snd_seq_poll, -- .unlocked_ioctl = snd_seq_ioctl, -- .compat_ioctl = snd_seq_ioctl_compat, -+static const struct file_operations snd_seq_f_ops = { -+ .owner = THIS_MODULE, -+ .read = snd_seq_read, -+ .write = snd_seq_write, -+ .open = snd_seq_open, -+ .release = snd_seq_release, -+ .poll = snd_seq_poll, -+ .unlocked_ioctl = snd_seq_ioctl, -+ .compat_ioctl = snd_seq_ioctl_compat, - }; - - static struct device *seq_dev; -diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h ---- a/sound/core/seq/seq_clientmgr.h -+++ b/sound/core/seq/seq_clientmgr.h -@@ -49,7 +49,6 @@ struct snd_seq_client { - /* ports */ - int num_ports; /* number of ports */ - struct list_head ports_list_head; -- rwlock_t ports_lock; - struct mutex ports_mutex; - struct mutex ioctl_mutex; - int convert32; /* convert 32->64bit */ -diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c ---- a/sound/core/seq/seq_ports.c -+++ b/sound/core/seq/seq_ports.c -@@ -48,8 +48,8 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, - - if (client == NULL) - return NULL; -- guard(read_lock)(&client->ports_lock); -- list_for_each_entry(port, &client->ports_list_head, list) { -+ guard(rcu)(); -+ list_for_each_entry_rcu(port, &client->ports_list_head, list) { - if (port->addr.port == num) { - if (port->closing) - break; /* deleting now */ -@@ -71,8 +71,8 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl - - num = pinfo->addr.port; - found = NULL; -- guard(read_lock)(&client->ports_lock); -- list_for_each_entry(port, &client->ports_list_head, list) { -+ guard(rcu)(); -+ list_for_each_entry_rcu(port, &client->ports_list_head, list) { - if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) && - !check_inactive) - continue; /* skip inactive ports */ -@@ -98,10 +98,9 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl - /* initialize snd_seq_port_subs_info */ - static void port_subs_info_init(struct snd_seq_port_subs_info *grp) - { -- INIT_LIST_HEAD(&grp->list_head); -+ INIT_HLIST_HEAD(&grp->list_head); - grp->count = 0; - grp->exclusive = 0; -- rwlock_init(&grp->list_lock); - init_rwsem(&grp->list_mutex); - grp->open = NULL; - grp->close = NULL; -@@ -154,7 +153,6 @@ int snd_seq_insert_port(struct snd_seq_client *client, int port, - - num = max(port, 0); - guard(mutex)(&client->ports_mutex); -- guard(write_lock_irq)(&client->ports_lock); - struct list_head *insert_before = &client->ports_list_head; - list_for_each_entry(p, &client->ports_list_head, list) { - if (p->addr.port == port) -@@ -166,12 +164,13 @@ int snd_seq_insert_port(struct snd_seq_client *client, int port, - if (port < 0) /* auto-probe mode */ - num = p->addr.port + 1; - } -- /* insert the new port */ -- list_add_tail(&new_port->list, insert_before); -- client->num_ports++; -+ /* finish initializing the port before publishing it to RCU readers */ - new_port->addr.port = num; /* store the port number in the port */ - if (!new_port->name[0]) - sprintf(new_port->name, "port-%d", num); -+ /* insert the new port */ -+ list_add_tail_rcu(&new_port->list, insert_before); -+ client->num_ports++; - - return num; - } -@@ -202,12 +201,12 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, - bool is_src, bool ack); - - static inline struct snd_seq_subscribers * --get_subscriber(struct list_head *p, bool is_src) -+get_subscriber(struct hlist_node *p, bool is_src) - { - if (is_src) -- return list_entry(p, struct snd_seq_subscribers, src_list); -+ return hlist_entry(p, struct snd_seq_subscribers, src_list); - else -- return list_entry(p, struct snd_seq_subscribers, dest_list); -+ return hlist_entry(p, struct snd_seq_subscribers, dest_list); - } - - /* -@@ -219,9 +218,9 @@ static void clear_subscriber_list(struct snd_seq_client *client, - struct snd_seq_port_subs_info *grp, - int is_src) - { -- struct list_head *p, *n; -+ struct hlist_node *p, *n; - -- list_for_each_safe(p, n, &grp->list_head) { -+ hlist_for_each_safe(p, n, &grp->list_head) { - struct snd_seq_subscribers *subs; - - subs = get_subscriber(p, is_src); -@@ -238,13 +237,13 @@ static void clear_subscriber_list(struct snd_seq_client *client, - * remove the subscriber info - */ - if (atomic_dec_and_test(&subs->ref_count)) -- kfree(subs); -+ kfree_rcu(subs, rcu); - continue; - } - - /* ok we got the connected port */ - delete_and_unsubscribe_port(c, aport, subs, !is_src, true); -- kfree(subs); -+ kfree_rcu(subs, rcu); - } - } - -@@ -254,7 +253,13 @@ static int port_delete(struct snd_seq_client *client, - { - /* set closing flag and wait for all port access are gone */ - port->closing = 1; -- snd_use_lock_sync(&port->use_lock); -+ /* the port has already been unlinked from the client's port list; -+ * wait for a grace period so that RCU readers still traversing the -+ * list can no longer take a new use_lock reference, then drain the -+ * outstanding references before freeing -+ */ -+ synchronize_rcu(); -+ snd_use_lock_sync(&port->use_lock); - - /* clear subscribers info */ - clear_subscriber_list(client, port, &port->c_src, true); -@@ -277,11 +282,10 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port) - struct snd_seq_client_port *found = NULL, *p; - - scoped_guard(mutex, &client->ports_mutex) { -- guard(write_lock_irq)(&client->ports_lock); - list_for_each_entry(p, &client->ports_list_head, list) { - if (p->addr.port == port) { - /* ok found. delete from the list at first */ -- list_del(&p->list); -+ list_del_rcu(&p->list); - client->num_ports--; - found = p; - break; -@@ -297,26 +301,16 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port) - /* delete the all ports belonging to the given client */ - int snd_seq_delete_all_ports(struct snd_seq_client *client) - { -- struct list_head deleted_list; - struct snd_seq_client_port *port, *tmp; -- -- /* move the port list to deleted_list, and -- * clear the port list in the client data. -+ -+ /* unlink and delete each port; port_delete() waits for an RCU grace -+ * period before draining the port, so concurrent lockless readers can -+ * no longer take a new use_lock reference on it - */ - guard(mutex)(&client->ports_mutex); -- scoped_guard(write_lock_irq, &client->ports_lock) { -- if (!list_empty(&client->ports_list_head)) { -- list_add(&deleted_list, &client->ports_list_head); -- list_del_init(&client->ports_list_head); -- } else { -- INIT_LIST_HEAD(&deleted_list); -- } -- client->num_ports = 0; -- } -- -- /* remove each port in deleted_list */ -- list_for_each_entry_safe(port, tmp, &deleted_list, list) { -- list_del(&port->list); -+ list_for_each_entry_safe(port, tmp, &client->ports_list_head, list) { -+ list_del_rcu(&port->list); -+ client->num_ports--; - snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port); - port_delete(client, port); - } -@@ -499,20 +493,20 @@ static int check_and_subscribe_port(struct snd_seq_client *client, - bool is_src, bool exclusive, bool ack) - { - struct snd_seq_port_subs_info *grp; -- struct list_head *p; -+ struct hlist_node *p; - struct snd_seq_subscribers *s; - int err; - - grp = is_src ? &port->c_src : &port->c_dest; - guard(rwsem_write)(&grp->list_mutex); - if (exclusive) { -- if (!list_empty(&grp->list_head)) -+ if (!hlist_empty(&grp->list_head)) - return -EBUSY; - } else { - if (grp->exclusive) - return -EBUSY; - /* check whether already exists */ -- list_for_each(p, &grp->list_head) { -+ hlist_for_each(p, &grp->list_head) { - s = get_subscriber(p, is_src); - if (match_subs_info(&subs->info, &s->info)) - return -EBUSY; -@@ -526,11 +520,10 @@ static int check_and_subscribe_port(struct snd_seq_client *client, - } - - /* add to list */ -- guard(write_lock_irq)(&grp->list_lock); - if (is_src) -- list_add_tail(&subs->src_list, &grp->list_head); -+ hlist_add_tail_rcu(&subs->src_list, &grp->list_head); - else -- list_add_tail(&subs->dest_list, &grp->list_head); -+ hlist_add_tail_rcu(&subs->dest_list, &grp->list_head); - grp->exclusive = exclusive; - atomic_inc(&subs->ref_count); - -@@ -544,17 +537,15 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client, - bool is_src, bool ack) - { - struct snd_seq_port_subs_info *grp; -- struct list_head *list; -+ struct hlist_node *list; - bool empty; - - grp = is_src ? &port->c_src : &port->c_dest; - list = is_src ? &subs->src_list : &subs->dest_list; -- scoped_guard(write_lock_irq, &grp->list_lock) { -- empty = list_empty(list); -- if (!empty) -- list_del_init(list); -- grp->exclusive = 0; -- } -+ empty = hlist_unhashed(list); -+ if (!empty) -+ hlist_del_init_rcu(list); -+ grp->exclusive = 0; - - if (!empty) - unsubscribe_port(client, port, grp, &subs->info, ack); -@@ -590,8 +581,8 @@ int snd_seq_port_connect(struct snd_seq_client *connector, - - subs->info = *info; - atomic_set(&subs->ref_count, 0); -- INIT_LIST_HEAD(&subs->src_list); -- INIT_LIST_HEAD(&subs->dest_list); -+ INIT_HLIST_NODE(&subs->src_list); -+ INIT_HLIST_NODE(&subs->dest_list); - - exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE); - -@@ -612,7 +603,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector, - delete_and_unsubscribe_port(src_client, src_port, subs, true, - connector->number != src_client->number); - error: -- kfree(subs); -+ kfree_rcu(subs, rcu); - return err; - } - -@@ -633,7 +624,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, - */ - scoped_guard(rwsem_write, &dest->list_mutex) { - /* look for the connection */ -- list_for_each_entry(subs, &dest->list_head, dest_list) { -+ hlist_for_each_entry(subs, &dest->list_head, dest_list) { - if (match_subs_info(info, &subs->info)) { - __delete_and_unsubscribe_port(dest_client, dest_port, - subs, false, -@@ -648,7 +639,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, - - delete_and_unsubscribe_port(src_client, src_port, subs, true, - connector->number != src_client->number); -- kfree(subs); -+ kfree_rcu(subs, rcu); - return 0; - } - -@@ -662,7 +653,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, - int err = -ENOENT; - - guard(rwsem_read)(&src_grp->list_mutex); -- list_for_each_entry(s, &src_grp->list_head, src_list) { -+ hlist_for_each_entry(s, &src_grp->list_head, src_list) { - if (addr_match(dest_addr, &s->info.dest)) { - *subs = s->info; - err = 0; -diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h ---- a/sound/core/seq/seq_ports.h -+++ b/sound/core/seq/seq_ports.h -@@ -28,17 +28,17 @@ - - struct snd_seq_subscribers { - struct snd_seq_port_subscribe info; /* additional info */ -- struct list_head src_list; /* link of sources */ -- struct list_head dest_list; /* link of destinations */ -+ struct hlist_node src_list; /* link of sources */ -+ struct hlist_node dest_list; /* link of destinations */ - atomic_t ref_count; -+ struct rcu_head rcu; /* for deferred free */ - }; - - struct snd_seq_port_subs_info { -- struct list_head list_head; /* list of subscribed ports */ -+ struct hlist_head list_head; /* list of subscribed ports */ - unsigned int count; /* count of subscribers */ - unsigned int exclusive: 1; /* exclusive mode */ - struct rw_semaphore list_mutex; -- rwlock_t list_lock; - int (*open)(void *private_data, struct snd_seq_port_subscribe *info); - int (*close)(void *private_data, struct snd_seq_port_subscribe *info); - }; -diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c ---- a/sound/core/seq/seq_ump_client.c -+++ b/sound/core/seq/seq_ump_client.c -@@ -37,8 +37,11 @@ struct seq_ump_client { - struct snd_ump_endpoint *ump; /* assigned endpoint */ - int seq_client; /* sequencer client id */ - int opened[2]; /* current opens for each direction */ -- rwlock_t output_lock; /* protects out_rfile output access */ - struct snd_rawmidi_file out_rfile; /* rawmidi for output */ -+ /* RCU-protected shadow of out_rfile.output for the delivery hot path; -+ * out_rfile itself is only touched by open/close under open_mutex -+ */ -+ struct snd_rawmidi_substream __rcu *out_substream; - struct seq_ump_input_buffer input; /* input parser context */ - void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */ - struct work_struct group_notify_work; /* FB change notification */ -@@ -89,8 +92,8 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct, - unsigned char type; - int len; - -- guard(read_lock_irqsave)(&client->output_lock); -- substream = client->out_rfile.output; -+ guard(rcu)(); -+ substream = rcu_dereference(client->out_substream); - if (!substream) - return -ENODEV; - if (!snd_seq_ev_is_ump(ev)) -@@ -108,19 +111,22 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct, - static int seq_ump_client_open(struct seq_ump_client *client, int dir) - { - struct snd_ump_endpoint *ump = client->ump; -- struct snd_rawmidi_file rfile = {}; - int err; - - guard(mutex)(&ump->open_mutex); - if (dir == STR_OUT && !client->opened[dir]) { -+ /* out_rfile is only accessed under open_mutex; the delivery -+ * path reads out_substream via RCU, so open into out_rfile -+ * directly and publish the substream afterwards -+ */ - err = snd_rawmidi_kernel_open(&ump->core, 0, - SNDRV_RAWMIDI_LFLG_OUTPUT | - SNDRV_RAWMIDI_LFLG_APPEND, -- &rfile); -+ &client->out_rfile); - if (err < 0) - return err; -- scoped_guard(write_lock_irqsave, &client->output_lock) -- client->out_rfile = rfile; -+ rcu_assign_pointer(client->out_substream, -+ client->out_rfile.output); - } - client->opened[dir]++; - return 0; -@@ -130,17 +136,18 @@ static int seq_ump_client_open(struct seq_ump_client *client, int dir) - static int seq_ump_client_close(struct seq_ump_client *client, int dir) - { - struct snd_ump_endpoint *ump = client->ump; -- struct snd_rawmidi_file rfile = {}; - - guard(mutex)(&ump->open_mutex); - if (!--client->opened[dir]) { -- if (dir == STR_OUT) { -- scoped_guard(write_lock_irqsave, &client->output_lock) { -- rfile = client->out_rfile; -- client->out_rfile = (struct snd_rawmidi_file){}; -- } -- if (rfile.rmidi) -- snd_rawmidi_kernel_release(&rfile); -+ if (dir == STR_OUT && client->out_rfile.rmidi) { -+ rcu_assign_pointer(client->out_substream, NULL); -+ /* wait for a grace period so that no reader in the -+ * delivery path is still writing to the substream -+ * before it is released -+ */ -+ synchronize_rcu(); -+ snd_rawmidi_kernel_release(&client->out_rfile); -+ client->out_rfile = (struct snd_rawmidi_file){}; - } - } - return 0; -@@ -480,7 +487,6 @@ static int snd_seq_ump_probe(struct snd_seq_device *dev) - - INIT_WORK(&client->group_notify_work, handle_group_notify); - client->ump = ump; -- rwlock_init(&client->output_lock); - - client->seq_client = - snd_seq_create_kernel_client(card, ump->core.device, -diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c ---- a/sound/core/seq/seq_virmidi.c -+++ b/sound/core/seq/seq_virmidi.c -@@ -78,10 +78,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, - int len; - - if (atomic) -- read_lock(&rdev->filelist_lock); -+ rcu_read_lock(); - else - down_read(&rdev->filelist_sem); -- list_for_each_entry(vmidi, &rdev->filelist, list) { -+ list_for_each_entry_rcu(vmidi, &rdev->filelist, list, -+ lockdep_is_held(&rdev->filelist_sem)) { - if (!READ_ONCE(vmidi->trigger)) - continue; - if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { -@@ -96,7 +97,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, - } - } - if (atomic) -- read_unlock(&rdev->filelist_lock); -+ rcu_read_unlock(); - else - up_read(&rdev->filelist_sem); - -@@ -200,8 +201,7 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream) - vmidi->port = rdev->port; - runtime->private_data = vmidi; - scoped_guard(rwsem_write, &rdev->filelist_sem) { -- guard(write_lock_irq)(&rdev->filelist_lock); -- list_add_tail(&vmidi->list, &rdev->filelist); -+ list_add_tail_rcu(&vmidi->list, &rdev->filelist); - } - vmidi->rdev = rdev; - return 0; -@@ -243,9 +243,13 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) - struct snd_virmidi *vmidi = substream->runtime->private_data; - - scoped_guard(rwsem_write, &rdev->filelist_sem) { -- guard(write_lock_irq)(&rdev->filelist_lock); -- list_del(&vmidi->list); -+ list_del_rcu(&vmidi->list); - } -+ /* wait for a grace period so that lockless readers in the atomic -+ * delivery path (snd_virmidi_dev_receive_event()) are no longer -+ * traversing this entry before its parser and memory are freed -+ */ -+ synchronize_rcu(); - snd_midi_event_free(vmidi->parser); - substream->runtime->private_data = NULL; - kfree(vmidi); -@@ -508,7 +512,6 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi - rdev->device = device; - rdev->client = -1; - init_rwsem(&rdev->filelist_sem); -- rwlock_init(&rdev->filelist_lock); - INIT_LIST_HEAD(&rdev->filelist); - rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH; - rmidi->private_data = rdev; -diff --git a/sound/core/sound.c b/sound/core/sound.c ---- a/sound/core/sound.c -+++ b/sound/core/sound.c -@@ -167,11 +167,10 @@ static int snd_open(struct inode *inode, struct file *file) - return err; - } - --static const struct file_operations snd_fops = --{ -- .owner = THIS_MODULE, -- .open = snd_open, -- .llseek = noop_llseek, -+static const struct file_operations snd_fops = { -+ .owner = THIS_MODULE, -+ .open = snd_open, -+ .llseek = noop_llseek, - }; - - #ifdef CONFIG_SND_DYNAMIC_MINORS -@@ -358,7 +357,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu - struct snd_minor *mptr; - - guard(mutex)(&sound_mutex); -- for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { -+ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { - mptr = snd_minors[minor]; - if (!mptr) - continue; -@@ -395,15 +394,21 @@ int __init snd_minor_info_init(void) - - static int __init alsa_sound_init(void) - { -+ int err; -+ - snd_major = major; - snd_ecards_limit = cards_limit; -- if (register_chrdev(major, "alsa", &snd_fops)) { -+ -+ err = register_chrdev(major, "alsa", &snd_fops); -+ if (err < 0) { - pr_err("ALSA core: unable to register native major device number %d\n", major); -- return -EIO; -+ return err; - } -- if (snd_info_init() < 0) { -+ -+ err = snd_info_init(); -+ if (err < 0) { - unregister_chrdev(major, "alsa"); -- return -ENOMEM; -+ return err; - } - - #ifdef CONFIG_SND_DEBUG -diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c ---- a/sound/core/sound_kunit.c -+++ b/sound/core/sound_kunit.c -@@ -17,8 +17,8 @@ - .name = #fmt, \ - } - --#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1) --#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1 -+#define WRONG_FORMAT_1 (SNDRV_PCM_FORMAT_LAST + 1) -+#define WRONG_FORMAT_2 -1 - - #define VALID_NAME "ValidName" - #define NAME_W_SPEC_CHARS "In%v@1id name" -diff --git a/sound/core/timer.c b/sound/core/timer.c ---- a/sound/core/timer.c -+++ b/sound/core/timer.c -@@ -1546,11 +1546,8 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size) - static int snd_timer_user_open(struct inode *inode, struct file *file) - { - struct snd_timer_user *tu; -- int err; - -- err = stream_open(inode, file); -- if (err < 0) -- return err; -+ stream_open(inode, file); - - tu = kzalloc_obj(*tu); - if (tu == NULL) -@@ -2176,9 +2173,9 @@ static long snd_utimer_ioctl(struct file *file, unsigned int ioctl, unsigned lon - } - - static const struct file_operations snd_utimer_fops = { -- .llseek = noop_llseek, -- .release = snd_utimer_release, -- .unlocked_ioctl = snd_utimer_ioctl, -+ .llseek = noop_llseek, -+ .release = snd_utimer_release, -+ .unlocked_ioctl = snd_utimer_ioctl, - }; - - static int snd_utimer_start(struct snd_timer *t) -@@ -2530,16 +2527,15 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait) - #define snd_timer_user_ioctl_compat NULL - #endif - --static const struct file_operations snd_timer_f_ops = --{ -- .owner = THIS_MODULE, -- .read = snd_timer_user_read, -- .open = snd_timer_user_open, -- .release = snd_timer_user_release, -- .poll = snd_timer_user_poll, -- .unlocked_ioctl = snd_timer_user_ioctl, -- .compat_ioctl = snd_timer_user_ioctl_compat, -- .fasync = snd_timer_user_fasync, -+static const struct file_operations snd_timer_f_ops = { -+ .owner = THIS_MODULE, -+ .read = snd_timer_user_read, -+ .open = snd_timer_user_open, -+ .release = snd_timer_user_release, -+ .poll = snd_timer_user_poll, -+ .unlocked_ioctl = snd_timer_user_ioctl, -+ .compat_ioctl = snd_timer_user_ioctl_compat, -+ .fasync = snd_timer_user_fasync, - }; - - /* unregister the system timer */ -diff --git a/sound/core/ump.c b/sound/core/ump.c ---- a/sound/core/ump.c -+++ b/sound/core/ump.c -@@ -1157,10 +1157,11 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream) - return -ENODEV; - if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { - if (!ump->legacy_out_opens) { -- err = snd_rawmidi_kernel_open(&ump->core, 0, -- SNDRV_RAWMIDI_LFLG_OUTPUT | -- SNDRV_RAWMIDI_LFLG_APPEND, -- &ump->legacy_out_rfile); -+ err = snd_rawmidi_kernel_open_nested(&ump->core, 0, -+ SNDRV_RAWMIDI_LFLG_OUTPUT | -+ SNDRV_RAWMIDI_LFLG_APPEND, -+ &ump->legacy_out_rfile, -+ SINGLE_DEPTH_NESTING); - if (err < 0) - return err; - } -diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c ---- a/sound/drivers/aloop.c -+++ b/sound/drivers/aloop.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -55,7 +56,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); - module_param_array(pcm_notify, int, NULL, 0444); - MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); - module_param_array(timer_source, charp, NULL, 0444); --MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default]."); -+MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default], 'hrtimer' for high-resolution timer."); - - #define NO_PITCH 100000 - -@@ -161,8 +162,11 @@ struct loopback_pcm { - unsigned int period_size_frac; /* period size in jiffies ticks */ - unsigned int last_drift; - unsigned long last_jiffies; -- /* If jiffies timer is used */ -+ /* If jiffies / hrtimer is used */ - struct timer_list timer; -+#ifdef CONFIG_HIGH_RES_TIMERS -+ struct hrtimer hrtimer; -+#endif - - /* size of per channel buffer in case of non-interleaved access */ - unsigned int channel_buf_n; -@@ -232,6 +236,31 @@ static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm) - return 0; - } - -+#ifdef CONFIG_HIGH_RES_TIMERS -+/* call in cable->lock */ -+static int loopback_hrtimer_start(struct loopback_pcm *dpcm) -+{ -+ unsigned long tick; -+ unsigned int rate_shift = get_rate_shift(dpcm); -+ -+ if (rate_shift != dpcm->pcm_rate_shift) { -+ dpcm->pcm_rate_shift = rate_shift; -+ dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); -+ } -+ if (dpcm->period_size_frac <= dpcm->irq_pos) { -+ dpcm->irq_pos %= dpcm->period_size_frac; -+ dpcm->period_update_pending = 1; -+ } -+ tick = dpcm->period_size_frac - dpcm->irq_pos; -+ tick = DIV_ROUND_UP(tick, dpcm->pcm_bps); -+ hrtimer_start(&dpcm->hrtimer, -+ ns_to_ktime(div_u64((u64)tick * NSEC_PER_SEC, HZ)), -+ HRTIMER_MODE_REL_SOFT); -+ -+ return 0; -+} -+#endif -+ - /* call in cable->lock */ - static int loopback_snd_timer_start(struct loopback_pcm *dpcm) - { -@@ -270,6 +299,16 @@ static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm) - return 0; - } - -+#ifdef CONFIG_HIGH_RES_TIMERS -+/* call in cable->lock */ -+static inline int loopback_hrtimer_stop(struct loopback_pcm *dpcm) -+{ -+ hrtimer_try_to_cancel(&dpcm->hrtimer); -+ -+ return 0; -+} -+#endif -+ - /* call in cable->lock */ - static int loopback_snd_timer_stop(struct loopback_pcm *dpcm) - { -@@ -300,6 +339,15 @@ static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm) - return 0; - } - -+#ifdef CONFIG_HIGH_RES_TIMERS -+static inline int loopback_hrtimer_stop_sync(struct loopback_pcm *dpcm) -+{ -+ hrtimer_cancel(&dpcm->hrtimer); -+ -+ return 0; -+} -+#endif -+ - /* call in loopback->cable_lock */ - static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm) - { -@@ -734,6 +782,30 @@ static void loopback_jiffies_timer_function(struct timer_list *t) - snd_pcm_period_elapsed(dpcm->substream); - } - -+#ifdef CONFIG_HIGH_RES_TIMERS -+static enum hrtimer_restart loopback_hrtimer_function(struct hrtimer *t) -+{ -+ struct loopback_pcm *dpcm = container_of(t, struct loopback_pcm, hrtimer); -+ bool period_elapsed = false; -+ -+ scoped_guard(spinlock_irqsave, &dpcm->cable->lock) { -+ if (loopback_jiffies_timer_pos_update(dpcm->cable) & -+ (1 << dpcm->substream->stream)) { -+ loopback_hrtimer_start(dpcm); -+ if (dpcm->period_update_pending) { -+ dpcm->period_update_pending = 0; -+ period_elapsed = true; -+ } -+ } -+ } -+ -+ if (period_elapsed) -+ snd_pcm_period_elapsed(dpcm->substream); -+ -+ return HRTIMER_NORESTART; -+} -+#endif -+ - /* call in cable->lock */ - static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime, - unsigned long resolution) -@@ -907,6 +979,21 @@ static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm, - snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); - } - -+#ifdef CONFIG_HIGH_RES_TIMERS -+static void loopback_hrtimer_dpcm_info(struct loopback_pcm *dpcm, -+ struct snd_info_buffer *buffer) -+{ -+ snd_iprintf(buffer, " update_pending:\t%u\n", -+ dpcm->period_update_pending); -+ snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); -+ snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); -+ snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", -+ dpcm->last_jiffies, jiffies); -+ snd_iprintf(buffer, " timer_expires:\t%llu\n", -+ ktime_to_ns(hrtimer_get_expires(&dpcm->hrtimer))); -+} -+#endif -+ - static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm, - struct snd_info_buffer *buffer) - { -@@ -1097,6 +1184,26 @@ static const struct loopback_ops loopback_jiffies_timer_ops = { - .dpcm_info = loopback_jiffies_timer_dpcm_info, - }; - -+#ifdef CONFIG_HIGH_RES_TIMERS -+static int loopback_hrtimer_open(struct loopback_pcm *dpcm) -+{ -+ hrtimer_setup(&dpcm->hrtimer, loopback_hrtimer_function, -+ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT); -+ -+ return 0; -+} -+ -+static const struct loopback_ops loopback_hrtimer_ops = { -+ .open = loopback_hrtimer_open, -+ .start = loopback_hrtimer_start, -+ .stop = loopback_hrtimer_stop, -+ .stop_sync = loopback_hrtimer_stop_sync, -+ .close_substream = loopback_hrtimer_stop_sync, -+ .pos_update = loopback_jiffies_timer_pos_update, -+ .dpcm_info = loopback_hrtimer_dpcm_info, -+}; -+#endif -+ - static int loopback_parse_timer_id(const char *str, - struct snd_timer_id *tid) - { -@@ -1274,7 +1381,12 @@ static int loopback_open(struct snd_pcm_substream *substream) - spin_lock_init(&cable->lock); - snd_refcount_init(&cable->stop_count); - cable->hw = loopback_pcm_hardware; -- if (loopback->timer_source) -+#ifdef CONFIG_HIGH_RES_TIMERS -+ if (loopback->timer_source && !strcmp(loopback->timer_source, "hrtimer")) -+ cable->ops = &loopback_hrtimer_ops; -+ else -+#endif -+ if (loopback->timer_source && loopback->timer_source[0]) - cable->ops = &loopback_snd_timer_ops; - else - cable->ops = &loopback_jiffies_timer_ops; -@@ -1491,7 +1603,7 @@ static int loopback_format_info(struct snd_kcontrol *kcontrol, - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; -- uinfo->value.integer.max = (__force int)SNDRV_PCM_FORMAT_LAST; -+ uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; - uinfo->value.integer.step = 1; - return 0; - } -@@ -1502,7 +1614,7 @@ static int loopback_format_get(struct snd_kcontrol *kcontrol, - struct loopback *loopback = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = -- (__force int)loopback->setup[kcontrol->id.subdevice] -+ loopback->setup[kcontrol->id.subdevice] - [kcontrol->id.device].format; - return 0; - } -@@ -1556,7 +1668,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, - static int loopback_access_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) - { -- const char * const texts[] = {"Interleaved", "Non-interleaved"}; -+ static const char * const texts[] = {"Interleaved", "Non-interleaved"}; - - return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); - } -diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c ---- a/sound/drivers/dummy.c -+++ b/sound/drivers/dummy.c -@@ -100,6 +100,7 @@ struct dummy_timer_ops { - int (*prepare)(struct snd_pcm_substream *); - int (*start)(struct snd_pcm_substream *); - int (*stop)(struct snd_pcm_substream *); -+ int (*sync_stop)(struct snd_pcm_substream *); - snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); - }; - -@@ -285,6 +286,14 @@ static int dummy_systimer_stop(struct snd_pcm_substream *substream) - return 0; - } - -+static int dummy_systimer_sync_stop(struct snd_pcm_substream *substream) -+{ -+ struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; -+ -+ timer_delete_sync(&dpcm->timer); -+ return 0; -+} -+ - static int dummy_systimer_prepare(struct snd_pcm_substream *substream) - { - struct snd_pcm_runtime *runtime = substream->runtime; -@@ -341,7 +350,10 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream) - - static void dummy_systimer_free(struct snd_pcm_substream *substream) - { -- kfree(substream->runtime->private_data); -+ struct dummy_systimer_pcm *dpcm = substream->runtime->private_data; -+ -+ timer_shutdown_sync(&dpcm->timer); -+ kfree(dpcm); - } - - static const struct dummy_timer_ops dummy_systimer_ops = { -@@ -350,6 +362,7 @@ static const struct dummy_timer_ops dummy_systimer_ops = { - .prepare = dummy_systimer_prepare, - .start = dummy_systimer_start, - .stop = dummy_systimer_stop, -+ .sync_stop = dummy_systimer_sync_stop, - .pointer = dummy_systimer_pointer, - }; - -@@ -407,9 +420,12 @@ static int dummy_hrtimer_stop(struct snd_pcm_substream *substream) - return 0; - } - --static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm) -+static int dummy_hrtimer_sync_stop(struct snd_pcm_substream *substream) - { -+ struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data; -+ - hrtimer_cancel(&dpcm->timer); -+ return 0; - } - - static snd_pcm_uframes_t -@@ -435,7 +451,6 @@ static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream) - long sec; - unsigned long nsecs; - -- dummy_hrtimer_sync(dpcm); - period = runtime->period_size; - rate = runtime->rate; - sec = period / rate; -@@ -463,7 +478,7 @@ static int dummy_hrtimer_create(struct snd_pcm_substream *substream) - static void dummy_hrtimer_free(struct snd_pcm_substream *substream) - { - struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data; -- dummy_hrtimer_sync(dpcm); -+ - kfree(dpcm); - } - -@@ -473,6 +488,7 @@ static const struct dummy_timer_ops dummy_hrtimer_ops = { - .prepare = dummy_hrtimer_prepare, - .start = dummy_hrtimer_start, - .stop = dummy_hrtimer_stop, -+ .sync_stop = dummy_hrtimer_sync_stop, - .pointer = dummy_hrtimer_pointer, - }; - -@@ -495,6 +511,13 @@ static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) - return -EINVAL; - } - -+static int dummy_pcm_sync_stop(struct snd_pcm_substream *substream) -+{ -+ if (get_dummy_ops(substream)->sync_stop) -+ return get_dummy_ops(substream)->sync_stop(substream); -+ return 0; -+} -+ - static int dummy_pcm_prepare(struct snd_pcm_substream *substream) - { - return get_dummy_ops(substream)->prepare(substream); -@@ -646,6 +669,7 @@ static const struct snd_pcm_ops dummy_pcm_ops = { - .hw_params = dummy_pcm_hw_params, - .prepare = dummy_pcm_prepare, - .trigger = dummy_pcm_trigger, -+ .sync_stop = dummy_pcm_sync_stop, - .pointer = dummy_pcm_pointer, - }; - -@@ -655,6 +679,7 @@ static const struct snd_pcm_ops dummy_pcm_ops_no_buf = { - .hw_params = dummy_pcm_hw_params, - .prepare = dummy_pcm_prepare, - .trigger = dummy_pcm_trigger, -+ .sync_stop = dummy_pcm_sync_stop, - .pointer = dummy_pcm_pointer, - .copy = dummy_pcm_copy, - .fill_silence = dummy_pcm_silence, -diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c ---- a/sound/hda/codecs/ca0132.c -+++ b/sound/hda/codecs/ca0132.c -@@ -5788,7 +5788,8 @@ static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol, - uinfo->value.enumerated.items = MIC_BOOST_NUM_OF_STEPS; - if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS) - uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1; -- sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx); -+ snprintf(namestr, sizeof(namestr), "%d %s", -+ (uinfo->value.enumerated.item * 10), sfx); - strscpy(uinfo->value.enumerated.name, namestr); - return 0; - } -@@ -5840,9 +5841,9 @@ static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol, - uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX; - if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX) - uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1; -- sprintf(namestr, "%s %s", -- ae5_headphone_gain_presets[uinfo->value.enumerated.item].name, -- sfx); -+ snprintf(namestr, sizeof(namestr), "%s %s", -+ ae5_headphone_gain_presets[uinfo->value.enumerated.item].name, -+ sfx); - strscpy(uinfo->value.enumerated.name, namestr); - return 0; - } -@@ -5894,8 +5895,8 @@ static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol, - uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX; - if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX) - uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1; -- sprintf(namestr, "%s", -- ae5_filter_presets[uinfo->value.enumerated.item].name); -+ snprintf(namestr, sizeof(namestr), "%s", -+ ae5_filter_presets[uinfo->value.enumerated.item].name); - strscpy(uinfo->value.enumerated.name, namestr); - return 0; - } -@@ -6632,7 +6633,7 @@ static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid, - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type); - -- sprintf(namestr, "FX: %s %s Volume", pfx, dirstr[dir]); -+ snprintf(namestr, sizeof(namestr), "FX: %s %s Volume", pfx, dirstr[dir]); - - knew.tlv.c = NULL; - -@@ -6671,9 +6672,9 @@ static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid, - * prefix to OutFX or InFX enable controls. - */ - if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID)) -- sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]); -+ snprintf(namestr, sizeof(namestr), "FX: %s %s Switch", pfx, dirstr[dir]); - else -- sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); -+ snprintf(namestr, sizeof(namestr), "%s %s Switch", pfx, dirstr[dir]); - - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); - } -@@ -8530,10 +8531,9 @@ static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k) - - static bool ca0132_download_dsp_images(struct hda_codec *codec) - { -- bool dsp_loaded = false; - struct ca0132_spec *spec = codec->spec; - const struct dsp_image_seg *dsp_os_image; -- const struct firmware *fw_entry = NULL; -+ const struct firmware *fw_entry __free(firmware) = NULL; - /* - * Alternate firmwares for different variants. The Recon3Di apparently - * can use the default firmware, but I'll leave the option in case -@@ -8573,15 +8573,10 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) - dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); - if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) { - codec_err(codec, "ca0132 DSP load image failed\n"); -- goto exit_download; -+ return false; - } - -- dsp_loaded = dspload_wait_loaded(codec); -- --exit_download: -- release_firmware(fw_entry); -- -- return dsp_loaded; -+ return dspload_wait_loaded(codec); - } - - static void ca0132_download_dsp(struct hda_codec *codec) -@@ -9634,6 +9629,7 @@ static void ca0132_free(struct hda_codec *codec) - #endif - kfree(spec->spec_init_verbs); - kfree(codec->spec); -+ codec->spec = NULL; - } - - static void dbpro_free(struct hda_codec *codec) -@@ -9644,6 +9640,7 @@ static void dbpro_free(struct hda_codec *codec) - - kfree(spec->spec_init_verbs); - kfree(codec->spec); -+ codec->spec = NULL; - } - - static void ca0132_config(struct hda_codec *codec) -diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c ---- a/sound/hda/codecs/cm9825.c -+++ b/sound/hda/codecs/cm9825.c -@@ -15,7 +15,8 @@ - - enum { - QUIRK_CM_STD = 0x0, -- QUIRK_GENE_TWL7_SSID = 0x160dc000 -+ QUIRK_GENE_TWL7_SSID = 0x160dc000, -+ QUIRK_IBP_SSID = 0x15bd3275 - }; - - /* CM9825 Offset Definitions */ -@@ -40,13 +41,19 @@ enum { - #define CM9825_VERB_SET_GAD 0x7b4 - #define CM9825_VERB_SET_TMOD 0x7b5 - #define CM9825_VERB_SET_SNR 0x7b6 -+#define CM9825_VERB_SET_OMTP 0x7ef -+#define CM9825_VERB_READ_OMTP 0xfec - - struct cmi_spec { - struct hda_gen_spec gen; - const struct hda_verb *chip_d0_verbs; - const struct hda_verb *chip_d3_verbs; -+ const struct hda_verb *chip_playback_start_verbs; -+ const struct hda_verb *chip_playback_stop_verbs; - const struct hda_verb *chip_hp_present_verbs; - const struct hda_verb *chip_hp_remove_verbs; -+ const struct hda_verb *chip_lineout_present_verbs; -+ const struct hda_verb *chip_lineout_remove_verbs; - struct hda_codec *codec; - struct delayed_work unsol_inputs_work; - struct delayed_work unsol_lineout_work; -@@ -193,6 +200,94 @@ static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = { - {} - }; - -+/* -+ * To save power, AD/CLK is turned off. -+ */ -+static const struct hda_verb cm9825_ibp_d3_verbs[] = { -+ {0x43, CM9825_VERB_SET_D2S, 0x62}, -+ {0x43, CM9825_VERB_SET_PLL, 0x01}, -+ {0x43, CM9825_VERB_SET_NEG, 0xc2}, -+ {0x43, CM9825_VERB_SET_ADCL, 0x00}, -+ {0x43, CM9825_VERB_SET_DACL, 0x02}, -+ {0x43, CM9825_VERB_SET_VNEG, 0x50}, -+ {0x43, CM9825_VERB_SET_MBIAS, 0x00}, -+ {0x43, CM9825_VERB_SET_PDNEG, 0x04}, -+ {0x43, CM9825_VERB_SET_CDALR, 0xf6}, -+ {0x43, CM9825_VERB_SET_OTP, 0xcd}, -+ {} -+}; -+ -+/* -+ * D0 configuration: enable PLL/CLK/ADC/DAC and optimize performance -+ */ -+static const struct hda_verb cm9825_ibp_d0_verbs[] = { -+ {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, -+ {0x43, CM9825_VERB_SET_SNR, 0x38}, -+ {0x43, CM9825_VERB_SET_PLL, 0x00}, -+ {0x43, CM9825_VERB_SET_ADCL, 0x00}, -+ {0x43, CM9825_VERB_SET_DACL, 0x02}, -+ {0x43, CM9825_VERB_SET_MBIAS, 0x00}, -+ {0x43, CM9825_VERB_SET_VNEG, 0x56}, -+ {0x43, CM9825_VERB_SET_D2S, 0x62}, -+ {0x43, CM9825_VERB_SET_DACTRL, 0x00}, -+ {0x43, CM9825_VERB_SET_PDNEG, 0x0c}, -+ {0x43, CM9825_VERB_SET_CDALR, 0xf4}, -+ {0x43, CM9825_VERB_SET_OTP, 0xcd}, -+ {0x43, CM9825_VERB_SET_MTCBA, 0x61}, -+ {0x43, CM9825_VERB_SET_OCP, 0x33}, -+ {0x43, CM9825_VERB_SET_GAD, 0x07}, -+ {0x43, CM9825_VERB_SET_TMOD, 0x26}, -+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d}, -+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d}, -+ {0x43, CM9825_VERB_SET_HPF_1, 0x40}, -+ {0x43, CM9825_VERB_SET_HPF_2, 0x40}, -+ {} -+}; -+ -+/* -+ * Enable mbias, ADC. -+ */ -+static const struct hda_verb cm9825_ibp_lineout_present_verbs[] = { -+ {0x43, CM9825_VERB_SET_ADCL, 0x8c}, -+ {0x43, CM9825_VERB_SET_MBIAS, 0x10}, -+ {} -+}; -+ -+/* -+ * Disable mbias, ADC. -+ */ -+static const struct hda_verb cm9825_ibp_lineout_remove_verbs[] = { -+ {0x43, CM9825_VERB_SET_ADCL, 0x00}, -+ {0x43, CM9825_VERB_SET_MBIAS, 0x00}, -+ {} -+}; -+ -+/* -+ * Turn on the DAC (widget NID 0x43) in the playback path by writing -+ * a sequence of vendor-specific verbs. -+ */ -+static const struct hda_verb cm9825_ibp_playback_start_verbs[] = { -+ {0x43, CM9825_VERB_SET_DACL, 0xaa}, -+ {0x43, CM9825_VERB_SET_D2S, 0xf2}, -+ {0x43, CM9825_VERB_SET_VDO, 0xc4}, -+ {0x43, CM9825_VERB_SET_SNR, 0x30}, -+ {} -+}; -+ -+/* -+ * Shut down the playback path. The order differs slightly from the -+ * enable sequence, likely to avoid audible pop noise when powering -+ * down the output stage. -+ */ -+static const struct hda_verb cm9825_ibp_playback_stop_verbs[] = { -+ {0x43, CM9825_VERB_SET_VDO, 0xc0}, -+ {0x43, CM9825_VERB_SET_DACL, 0x02}, -+ {0x43, CM9825_VERB_SET_D2S, 0x62}, -+ {0x43, CM9825_VERB_SET_VDO, 0x80}, -+ {0x43, CM9825_VERB_SET_SNR, 0x38}, -+ {} -+}; -+ - static void cm9825_update_jk_plug_status(struct hda_codec *codec, hda_nid_t nid) - { - struct cmi_spec *spec = codec->spec; -@@ -232,6 +327,23 @@ static void cm9825_unsol_lineout_delayed(struct work_struct *work) - struct cmi_spec *spec = - container_of(to_delayed_work(work), struct cmi_spec, - unsol_lineout_work); -+ hda_nid_t line_out_pin = spec->gen.autocfg.line_out_pins[0]; -+ bool line_out_jack_plugin = false; -+ -+ line_out_jack_plugin = snd_hda_jack_detect(spec->codec, line_out_pin); -+ -+ codec_dbg(spec->codec, "lineout_jack_plugin %d, lineout_pin 0x%X\n", -+ (int)line_out_jack_plugin, line_out_pin); -+ -+ if (!line_out_jack_plugin) { -+ /* Jack plugout */ -+ snd_hda_sequence_write(spec->codec, -+ spec->chip_lineout_remove_verbs); -+ } else { -+ /* Jack plugin */ -+ snd_hda_sequence_write(spec->codec, -+ spec->chip_lineout_present_verbs); -+ } - - cm9825_update_jk_plug_status(spec->codec, - spec->gen.autocfg.line_out_pins[0]); -@@ -362,12 +474,10 @@ static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo, - - switch (action) { - case HDA_GEN_PCM_ACT_PREPARE: -- snd_hda_sequence_write(spec->codec, -- cm9825_gene_twl7_playback_start_verbs); -+ snd_hda_sequence_write(codec, spec->chip_playback_start_verbs); - break; - case HDA_GEN_PCM_ACT_CLEANUP: -- snd_hda_sequence_write(spec->codec, -- cm9825_gene_twl7_playback_stop_verbs); -+ snd_hda_sequence_write(codec, spec->chip_playback_stop_verbs); - break; - default: - return; -@@ -471,7 +581,8 @@ static int cm9825_resume(struct hda_codec *codec) - - if (codec->core.subsystem_id == QUIRK_CM_STD) - cm9825_cm_std_resume(codec); -- else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) { -+ else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID || -+ codec->core.subsystem_id == QUIRK_IBP_SSID) { - snd_hda_codec_init(codec); - snd_hda_sequence_write(codec, spec->chip_d0_verbs); - } -@@ -487,6 +598,7 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id) - struct cmi_spec *spec; - struct auto_pin_cfg *cfg; - int err = 0; -+ unsigned int val; - - spec = kzalloc_obj(*spec); - if (spec == NULL) -@@ -523,9 +635,33 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id) - spec->chip_d0_verbs = cm9825_gene_twl7_d0_verbs; - spec->chip_d3_verbs = cm9825_gene_twl7_d3_verbs; - spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook; -+ spec->chip_playback_start_verbs = -+ cm9825_gene_twl7_playback_start_verbs; -+ spec->chip_playback_stop_verbs = -+ cm9825_gene_twl7_playback_stop_verbs; - /* Internal fixed device, Rear, Mic-in, 3.5mm */ - snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100); - break; -+ case QUIRK_IBP_SSID: -+ snd_hda_codec_set_name(codec, "CM9825 IBP"); -+ spec->chip_d0_verbs = cm9825_ibp_d0_verbs; -+ spec->chip_d3_verbs = cm9825_ibp_d3_verbs; -+ spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook; -+ spec->chip_lineout_present_verbs = -+ cm9825_ibp_lineout_present_verbs; -+ spec->chip_lineout_remove_verbs = -+ cm9825_ibp_lineout_remove_verbs; -+ spec->chip_playback_start_verbs = -+ cm9825_ibp_playback_start_verbs; -+ spec->chip_playback_stop_verbs = cm9825_ibp_playback_stop_verbs; -+ -+ /* OMTP */ -+ val = -+ snd_hda_codec_read(codec, 0x46, 0, CM9825_VERB_READ_OMTP, -+ 0x0); -+ snd_hda_codec_write(codec, 0x46, 0, CM9825_VERB_SET_OMTP, -+ (val >> 24) & 0x7f); -+ break; - default: - err = -ENXIO; - break; -diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c ---- a/sound/hda/codecs/conexant.c -+++ b/sound/hda/codecs/conexant.c -@@ -292,6 +292,7 @@ enum { - CXT_PINCFG_TOP_SPEAKER, - CXT_FIXUP_HP_A_U, - CXT_FIXUP_ACER_SWIFT_HP, -+ CXT_FIXUP_HUAWEI_MATEBOOK_HP, - }; - - /* for hda_fixup_thinkpad_acpi() */ -@@ -451,7 +452,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec) - if (!spec->dc_enable) { - /* disable DC bias path and pin for port F */ - update_mic_pin(codec, 0x1e, 0); -- snd_hda_activate_path(codec, spec->dc_mode_path, false, false); -+ if (spec->dc_mode_path) -+ snd_hda_activate_path(codec, spec->dc_mode_path, false, false); - - /* update port B (ext mic) and C (int mic) */ - /* OLPC defers mic widget control until when capture is -@@ -487,7 +489,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec) - update_mic_pin(codec, 0x1b, 0); - /* enable DC bias path and pin */ - update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0); -- snd_hda_activate_path(codec, spec->dc_mode_path, true, false); -+ if (spec->dc_mode_path) -+ snd_hda_activate_path(codec, spec->dc_mode_path, true, false); - } - } - -@@ -1033,6 +1036,13 @@ static const struct hda_fixup cxt_fixups[] = { - { } - }, - }, -+ [CXT_FIXUP_HUAWEI_MATEBOOK_HP] = { -+ .type = HDA_FIXUP_PINS, -+ .v.pins = (const struct hda_pintbl[]) { -+ { 0x18, 0x03211020 }, /* Headphone */ -+ { } -+ }, -+ }, - }; - - static const struct hda_quirk cxt5045_fixups[] = { -@@ -1097,6 +1107,7 @@ static const struct hda_quirk cxt5066_fixups[] = { - SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), -+ SND_PCI_QUIRK(0x103c, 0x837b, "HP ProBook 440 G5", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK), - SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), -@@ -1133,6 +1144,7 @@ static const struct hda_quirk cxt5066_fixups[] = { - SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), - SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad/Ideapad", CXT_FIXUP_LENOVO_XPAD_ACPI), -+ SND_PCI_QUIRK(0x19e5, 0x3289, "Huawei Matebook", CXT_FIXUP_HUAWEI_MATEBOOK_HP), - SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), - SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), - SND_PCI_QUIRK(0x1d05, 0x3012, "MECHREVO Wujie 15X Pro", CXT_FIXUP_HEADSET_MIC), -diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c ---- a/sound/hda/codecs/generic.c -+++ b/sound/hda/codecs/generic.c -@@ -2695,30 +2695,13 @@ static const struct snd_kcontrol_new out_jack_mode_enum = { - .put = out_jack_mode_put, - }; - --static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) --{ -- struct hda_gen_spec *spec = codec->spec; -- const struct snd_kcontrol_new *kctl; -- int i; -- -- snd_array_for_each(&spec->kctls, i, kctl) { -- if (!strcmp(kctl->name, name) && kctl->index == idx) -- return true; -- } -- return false; --} -- - static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, - char *name, size_t name_len) - { - struct hda_gen_spec *spec = codec->spec; -- int idx = 0; - -- snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); -- strlcat(name, " Jack Mode", name_len); -- -- for (; find_kctl_name(codec, name, idx); idx++) -- ; -+ snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len); -+ hda_append_suffix(name, " Jack Mode", name_len); - } - - static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin) -@@ -5695,7 +5678,7 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, - break; - } - } -- strlcat(str, sfx, len); -+ hda_append_suffix(str, sfx, len); - } - - /* copy PCM stream info from @default_str, and override non-NULL entries -diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c ---- a/sound/hda/codecs/hdmi/hdmi.c -+++ b/sound/hda/codecs/hdmi/hdmi.c -@@ -2236,8 +2236,10 @@ void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) - /* skip notification during system suspend (but not in runtime PM); - * the state will be updated at resume - */ -- if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) -+ if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) { -+ codec->acomp_requested_resume = 1; - return; -+ } - - snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id); - } -@@ -2346,6 +2348,7 @@ static const struct hda_device_id snd_hda_id_generichdmi[] = { - HDA_CODEC_ID_MODEL(0x1d179f8e, "KX-7000 HDMI/DP", MODEL_GF), - HDA_CODEC_ID_MODEL(0x1d179f8f, "KX-7000 HDMI/DP", MODEL_GF), - HDA_CODEC_ID_MODEL(0x1d179f90, "KX-7000 HDMI/DP", MODEL_GF), -+ HDA_CODEC_ID_MODEL(0x4c545020, "Lisuan HDMI/DP", MODEL_GENERIC), - HDA_CODEC_ID_MODEL(0x67663d82, "Arise 82 HDMI/DP", MODEL_GF), - HDA_CODEC_ID_MODEL(0x67663d83, "Arise 83 HDMI/DP", MODEL_GF), - HDA_CODEC_ID_MODEL(0x67663d84, "Arise 84 HDMI/DP", MODEL_GF), -diff --git a/sound/hda/codecs/helpers/razer_blade16_2025.c b/sound/hda/codecs/helpers/razer_blade16_2025.c -new file mode 100644 ---- /dev/null -+++ b/sound/hda/codecs/helpers/razer_blade16_2025.c -@@ -0,0 +1,820 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Razer Blade 16 (2025) external smart-amplifier programming and fixup, -+ * to be included from the codec driver. -+ * -+ * The internal speakers are driven by an external smart amplifier whose -+ * crossover, voicing and protection live in a DSP reached over a vendor -+ * coef mailbox on NID 0x20. These tables hold the programming captured -+ * from the Windows driver, reduced to the NID-0x20 traffic this machine -+ * needs (everything else the HDA parser rebuilds). -+ * -+ * Each entry is either a plain codec coef write or a mailbox write: -+ * strobe == 0: coef[addr] = lo -+ * strobe != 0: amp[addr] = (hi << 16) | lo, with the bank selected on -+ * port 0x89 and the write committed by the strobe opcode. -+ */ -+ -+struct alc298_razer_blade16_2025_op { -+ u16 bank; /* mailbox bank (port 0x89); unused for a plain coef */ -+ u16 addr; /* mailbox register, or plain coef index */ -+ u16 hi; /* mailbox high word; unused for a plain coef */ -+ u16 lo; /* mailbox low word, or plain coef value */ -+ u16 strobe; /* mailbox commit opcode; 0 marks a plain coef write */ -+}; -+ -+/* program the external DSP at init; the amp is woken/parked separately */ -+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_init[] = { -+ { 0x0000, 0xf102, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xf103, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xc000, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xea00, 0x0000, 0x0047, 0xb031 }, -+ { 0x0000, 0xf20d, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xf212, 0x0000, 0x003e, 0xb031 }, -+ { 0x0000, 0xc001, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xc003, 0x0000, 0x0022, 0xb031 }, -+ { 0x0000, 0xc004, 0x0000, 0x0044, 0xb031 }, -+ { 0x0000, 0xc005, 0x0000, 0x0044, 0xb031 }, -+ { 0x0000, 0xc007, 0x0000, 0x0064, 0xb031 }, -+ { 0x0000, 0xc00e, 0x0000, 0x00e7, 0xb031 }, -+ { 0x0000, 0xf223, 0x0000, 0x007f, 0xb031 }, -+ { 0x0000, 0xf224, 0x0000, 0x00db, 0xb031 }, -+ { 0x0000, 0xf225, 0x0000, 0x00ee, 0xb031 }, -+ { 0x0000, 0xf226, 0x0000, 0x003f, 0xb031 }, -+ { 0x0000, 0xf227, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xf21a, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xf242, 0x0000, 0x003c, 0xb031 }, -+ { 0x0000, 0xc120, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xc125, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xc321, 0x0000, 0x000b, 0xb031 }, -+ { 0x0000, 0xc200, 0x0000, 0x00d8, 0xb031 }, -+ { 0x0000, 0xc201, 0x0000, 0x0027, 0xb031 }, -+ { 0x0000, 0xc202, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xc400, 0x0000, 0x000e, 0xb031 }, -+ { 0x0000, 0xc401, 0x0000, 0x0043, 0xb031 }, -+ { 0x0000, 0xc402, 0x0000, 0x00e0, 0xb031 }, -+ { 0x0000, 0xc403, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xc404, 0x0000, 0x004c, 0xb031 }, -+ { 0x0000, 0xc406, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xc407, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xc408, 0x0000, 0x003f, 0xb031 }, -+ { 0x0000, 0xc300, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xc125, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xdf00, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xdf5f, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xdf60, 0x0000, 0x00a7, 0xb031 }, -+ { 0x0000, 0xc203, 0x0000, 0x0084, 0xb031 }, -+ { 0x0000, 0xc206, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xf10a, 0x0000, 0x000b, 0xb031 }, -+ { 0x0000, 0xf10b, 0x0000, 0x004c, 0xb031 }, -+ { 0x0000, 0xf104, 0x0000, 0x00f4, 0xb031 }, -+ { 0x0000, 0xf105, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xf109, 0x0000, 0x00e0, 0xb031 }, -+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 }, -+ { 0x0000, 0xf104, 0x0000, 0x00f4, 0xb031 }, -+ { 0x0000, 0xf105, 0x0000, 0x0004, 0xb031 }, -+ { 0x0000, 0xf109, 0x0000, 0x0065, 0xb031 }, -+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 }, -+ { 0x0000, 0xf104, 0x0000, 0x00f7, 0xb031 }, -+ { 0x0000, 0xf105, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xf109, 0x0000, 0x0006, 0xb031 }, -+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 }, -+ { 0x0000, 0xf104, 0x0000, 0x00f7, 0xb031 }, -+ { 0x0000, 0xf105, 0x0000, 0x0031, 0xb031 }, -+ { 0x0000, 0xf109, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 }, -+ { 0x0000, 0xe706, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xe707, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xe806, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xe807, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xce04, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xce05, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xce06, 0x0000, 0x0031, 0xb031 }, -+ { 0x0000, 0xce07, 0x0000, 0x00b4, 0xb031 }, -+ { 0x0000, 0xcf04, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xcf05, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xcf06, 0x0000, 0x0031, 0xb031 }, -+ { 0x0000, 0xcf07, 0x0000, 0x00b4, 0xb031 }, -+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xc130, 0x0000, 0x0051, 0xb031 }, -+ { 0x0000, 0xe000, 0x0000, 0x00a8, 0xb031 }, -+ { 0x4100, 0x1888, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xc121, 0x0000, 0x000b, 0xb031 }, -+ { 0x0000, 0xea00, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xca00, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xca02, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xca12, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xed00, 0x0000, 0x0090, 0xb031 }, -+ { 0x0000, 0xcc2c, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc2d, 0x0000, 0x000e, 0xb031 }, -+ { 0x0000, 0xcc2e, 0x0000, 0x0076, 0xb031 }, -+ { 0x0000, 0xcc2f, 0x0000, 0x0043, 0xb031 }, -+ { 0x0000, 0xcd2c, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd2d, 0x0000, 0x000e, 0xb031 }, -+ { 0x0000, 0xcd2e, 0x0000, 0x0076, 0xb031 }, -+ { 0x0000, 0xcd2f, 0x0000, 0x0043, 0xb031 }, -+ { 0x0000, 0xcc24, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc25, 0x0000, 0x0051, 0xb031 }, -+ { 0x0000, 0xcc26, 0x0000, 0x00eb, 0xb031 }, -+ { 0x0000, 0xcc27, 0x0000, 0x0085, 0xb031 }, -+ { 0x0000, 0xcd24, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd25, 0x0000, 0x0051, 0xb031 }, -+ { 0x0000, 0xcd26, 0x0000, 0x00eb, 0xb031 }, -+ { 0x0000, 0xcd27, 0x0000, 0x0085, 0xb031 }, -+ { 0x0000, 0xcc20, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc21, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc22, 0x0000, 0x0043, 0xb031 }, -+ { 0x0000, 0xcd20, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd21, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd22, 0x0000, 0x0043, 0xb031 }, -+ { 0x0000, 0xcc16, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xcc17, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd16, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xcd17, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc29, 0x0000, 0x005d, 0xb031 }, -+ { 0x0000, 0xcc2a, 0x0000, 0x00c0, 0xb031 }, -+ { 0x0000, 0xcd29, 0x0000, 0x005d, 0xb031 }, -+ { 0x0000, 0xcd2a, 0x0000, 0x00c0, 0xb031 }, -+ { 0x0000, 0xcc31, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xcc32, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc33, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc34, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd31, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xcd32, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd33, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd34, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc36, 0x0000, 0x0079, 0xb031 }, -+ { 0x0000, 0xcc37, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xcc38, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xcc39, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xcd36, 0x0000, 0x0079, 0xb031 }, -+ { 0x0000, 0xcd37, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xcd38, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xcd39, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xcc09, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc0a, 0x0000, 0x000a, 0xb031 }, -+ { 0x0000, 0xcc0b, 0x0000, 0x007c, 0xb031 }, -+ { 0x0000, 0xcc0c, 0x0000, 0x005b, 0xb031 }, -+ { 0x0000, 0xcd09, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd0a, 0x0000, 0x000a, 0xb031 }, -+ { 0x0000, 0xcd0b, 0x0000, 0x007c, 0xb031 }, -+ { 0x0000, 0xcd0c, 0x0000, 0x005b, 0xb031 }, -+ { 0x0000, 0xcc0e, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcc0f, 0x0000, 0x0005, 0xb031 }, -+ { 0x0000, 0xcc10, 0x0000, 0x003e, 0xb031 }, -+ { 0x0000, 0xcc11, 0x0000, 0x002d, 0xb031 }, -+ { 0x0000, 0xcd0e, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcd0f, 0x0000, 0x0005, 0xb031 }, -+ { 0x0000, 0xcd10, 0x0000, 0x003e, 0xb031 }, -+ { 0x0000, 0xcd11, 0x0000, 0x002d, 0xb031 }, -+ { 0x0000, 0xccd6, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xccd7, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xcdd6, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcdd7, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xccd8, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xccd9, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xcdd8, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcdd9, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xccda, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xccdb, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xcdda, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xcddb, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xc320, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xc321, 0x0000, 0x000a, 0xb031 }, -+ { 0x0000, 0xe604, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xdb00, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xdd00, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xdc19, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xdc1a, 0x0000, 0x006a, 0xb031 }, -+ { 0x0000, 0xdc1b, 0x0000, 0x00aa, 0xb031 }, -+ { 0x0000, 0xdc1c, 0x0000, 0x00ab, 0xb031 }, -+ { 0x0000, 0xdc1d, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xdc1e, 0x0000, 0x0027, 0xb031 }, -+ { 0x0000, 0xdc1f, 0x0000, 0x0062, 0xb031 }, -+ { 0x0000, 0xdc20, 0x0000, 0x0076, 0xb031 }, -+ { 0x0000, 0xde19, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xde1a, 0x0000, 0x006a, 0xb031 }, -+ { 0x0000, 0xde1b, 0x0000, 0x00aa, 0xb031 }, -+ { 0x0000, 0xde1c, 0x0000, 0x00ab, 0xb031 }, -+ { 0x0000, 0xde1d, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xde1e, 0x0000, 0x0027, 0xb031 }, -+ { 0x0000, 0xde1f, 0x0000, 0x0062, 0xb031 }, -+ { 0x0000, 0xde20, 0x0000, 0x0076, 0xb031 }, -+ { 0x0000, 0xdb32, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xdd32, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xdb33, 0x0000, 0x000a, 0xb031 }, -+ { 0x0000, 0xdd33, 0x0000, 0x000a, 0xb031 }, -+ { 0x0000, 0xdb34, 0x0000, 0x001a, 0xb031 }, -+ { 0x0000, 0xdd34, 0x0000, 0x001a, 0xb031 }, -+ { 0x0000, 0xdb15, 0x0000, 0x00ef, 0xb031 }, -+ { 0x0000, 0xdd15, 0x0000, 0x00ef, 0xb031 }, -+ { 0x0000, 0xdb17, 0x0000, 0x003f, 0xb031 }, -+ { 0x0000, 0xdd17, 0x0000, 0x003f, 0xb031 }, -+ { 0x0000, 0xdb94, 0x0000, 0x0070, 0xb031 }, -+ { 0x0000, 0xdd94, 0x0000, 0x0070, 0xb031 }, -+ { 0x0000, 0xdb19, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xdd19, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xc203, 0x0000, 0x001c, 0xb031 }, -+ { 0x0000, 0xdb00, 0x0000, 0x004c, 0xb031 }, -+ { 0x0000, 0xdb04, 0x0000, 0x0005, 0xb031 }, -+ { 0x0000, 0xdb05, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xdd04, 0x0000, 0x0005, 0xb031 }, -+ { 0x0000, 0xdd05, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xdbbb, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xdbbc, 0x0000, 0x004c, 0xb031 }, -+ { 0x0000, 0xdbbd, 0x0000, 0x00f3, 0xb031 }, -+ { 0x0000, 0xdbbe, 0x0000, 0x00cf, 0xb031 }, -+ { 0x0000, 0xddbb, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xddbc, 0x0000, 0x004c, 0xb031 }, -+ { 0x0000, 0xddbd, 0x0000, 0x00f3, 0xb031 }, -+ { 0x0000, 0xddbe, 0x0000, 0x00cf, 0xb031 }, -+ { 0x0000, 0xdb01, 0x0000, 0x0079, 0xb031 }, -+ { 0x0000, 0xdd01, 0x0000, 0x0079, 0xb031 }, -+ { 0x0000, 0xdb08, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xdd08, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xdc52, 0x0000, 0x00ef, 0xb031 }, -+ { 0x0000, 0xde52, 0x0000, 0x00ef, 0xb031 }, -+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 }, -+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 }, -+ { 0x0000, 0xdf0a, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xdf0b, 0x0000, 0x007f, 0xb031 }, -+ { 0x0000, 0xc851, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xc951, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xdf01, 0x0000, 0x0073, 0xb031 }, -+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 }, -+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xebcb, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xeb10, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xeb11, 0x0000, 0x00bb, 0xb031 }, -+ { 0x0000, 0xeb12, 0x0000, 0x00ab, 0xb031 }, -+ { 0x0000, 0xeb13, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xeb14, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb15, 0x0000, 0x004c, 0xb031 }, -+ { 0x0000, 0xeb16, 0x0000, 0x0069, 0xb031 }, -+ { 0x0000, 0xeb21, 0x0000, 0x0011, 0xb031 }, -+ { 0x0000, 0xeb22, 0x0000, 0x00c2, 0xb031 }, -+ { 0x0000, 0xeb23, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xeb24, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xeb25, 0x0000, 0x00bd, 0xb031 }, -+ { 0x0000, 0xeb26, 0x0000, 0x0055, 0xb031 }, -+ { 0x0000, 0xeb27, 0x0000, 0x00d0, 0xb031 }, -+ { 0x0000, 0xeb28, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb29, 0x0000, 0x003c, 0xb031 }, -+ { 0x0000, 0xeb2a, 0x0000, 0x0051, 0xb031 }, -+ { 0x0000, 0xeb2b, 0x0000, 0x0018, 0xb031 }, -+ { 0x0000, 0xeb30, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xeb31, 0x0000, 0x004f, 0xb031 }, -+ { 0x0000, 0xeb32, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xeb33, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xeb34, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb35, 0x0000, 0x00bb, 0xb031 }, -+ { 0x0000, 0xeb36, 0x0000, 0x0024, 0xb031 }, -+ { 0x0000, 0xeb37, 0x0000, 0x0068, 0xb031 }, -+ { 0x0000, 0xeb40, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb41, 0x0000, 0x00f5, 0xb031 }, -+ { 0x0000, 0xeb42, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xeb43, 0x0000, 0x00e8, 0xb031 }, -+ { 0x0000, 0xeb44, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xeb45, 0x0000, 0x004f, 0xb031 }, -+ { 0x0000, 0xeb46, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xeb47, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xeb48, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb49, 0x0000, 0x00c5, 0xb031 }, -+ { 0x0000, 0xeb4a, 0x0000, 0x0032, 0xb031 }, -+ { 0x0000, 0xeb4b, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xeb50, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xeb51, 0x0000, 0x008a, 0xb031 }, -+ { 0x0000, 0xeb52, 0x0000, 0x00b4, 0xb031 }, -+ { 0x0000, 0xeb53, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xeb54, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb55, 0x0000, 0x007d, 0xb031 }, -+ { 0x0000, 0xeb56, 0x0000, 0x00d9, 0xb031 }, -+ { 0x0000, 0xeb57, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xeb60, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xeb61, 0x0000, 0x00e7, 0xb031 }, -+ { 0x0000, 0xeb62, 0x0000, 0x00b5, 0xb031 }, -+ { 0x0000, 0xeb63, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xeb64, 0x0000, 0x00fa, 0xb031 }, -+ { 0x0000, 0xeb65, 0x0000, 0x0086, 0xb031 }, -+ { 0x0000, 0xeb66, 0x0000, 0x00a8, 0xb031 }, -+ { 0x0000, 0xeb67, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xeb68, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xeb69, 0x0000, 0x009a, 0xb031 }, -+ { 0x0000, 0xeb6a, 0x0000, 0x002f, 0xb031 }, -+ { 0x0000, 0xeb6b, 0x0000, 0x0018, 0xb031 }, -+ { 0x0000, 0xebb6, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xeb70, 0x0000, 0x00f5, 0xb031 }, -+ { 0x0000, 0xeb71, 0x0000, 0x00e1, 0xb031 }, -+ { 0x0000, 0xeb72, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xeb73, 0x0000, 0x00d0, 0xb031 }, -+ { 0x0000, 0xeb74, 0x0000, 0x0006, 0xb031 }, -+ { 0x0000, 0xeb75, 0x0000, 0x0050, 0xb031 }, -+ { 0x0000, 0xeb76, 0x0000, 0x002c, 0xb031 }, -+ { 0x0000, 0xeb77, 0x0000, 0x0050, 0xb031 }, -+ { 0x0000, 0xeb80, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb81, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xeb82, 0x0000, 0x0016, 0xb031 }, -+ { 0x0000, 0xeb83, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xeb84, 0x0000, 0x00f5, 0xb031 }, -+ { 0x0000, 0xeb85, 0x0000, 0x00e1, 0xb031 }, -+ { 0x0000, 0xeb86, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xeb87, 0x0000, 0x00d0, 0xb031 }, -+ { 0x0000, 0xeb88, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xeb89, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xeb8a, 0x0000, 0x0016, 0xb031 }, -+ { 0x0000, 0xeb8b, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xebb8, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xeb90, 0x0000, 0x00fc, 0xb031 }, -+ { 0x0000, 0xeb91, 0x0000, 0x008b, 0xb031 }, -+ { 0x0000, 0xeb92, 0x0000, 0x00bd, 0xb031 }, -+ { 0x0000, 0xeb93, 0x0000, 0x0064, 0xb031 }, -+ { 0x0000, 0xeb94, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xeb95, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xeb96, 0x0000, 0x00e7, 0xb031 }, -+ { 0x0000, 0xeb97, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xeba0, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xeba1, 0x0000, 0x0091, 0xb031 }, -+ { 0x0000, 0xeba2, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xeba3, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xeba4, 0x0000, 0x00f6, 0xb031 }, -+ { 0x0000, 0xeba5, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xeba6, 0x0000, 0x0093, 0xb031 }, -+ { 0x0000, 0xeba7, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xeba8, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xeba9, 0x0000, 0x0087, 0xb031 }, -+ { 0x0000, 0xebaa, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xebab, 0x0000, 0x006c, 0xb031 }, -+ { 0x0000, 0xebc3, 0x0000, 0x00ff, 0xb031 }, -+ { 0x0000, 0xebc4, 0x0000, 0x00fc, 0xb031 }, -+ { 0x0000, 0xeb00, 0x0000, 0x0005, 0xb031 }, -+ { 0x0000, 0xeb01, 0x0000, 0x00a9, 0xb031 }, -+ { 0x0000, 0xeb02, 0x0000, 0x00df, 0xb031 }, -+ { 0x0000, 0xeb03, 0x0000, 0x007b, 0xb031 }, -+ { 0x0000, 0xeb05, 0x0000, 0x0079, 0xb031 }, -+ { 0x0000, 0xeb06, 0x0000, 0x005a, 0xb031 }, -+ { 0x0000, 0xeb07, 0x0000, 0x0004, 0xb031 }, -+ { 0x0000, 0xebc0, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xd0cb, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xd0b0, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xd010, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd011, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xd012, 0x0000, 0x0092, 0xb031 }, -+ { 0x0000, 0xd013, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd014, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xd015, 0x0000, 0x00f6, 0xb031 }, -+ { 0x0000, 0xd016, 0x0000, 0x0072, 0xb031 }, -+ { 0x0000, 0xd017, 0x0000, 0x00b0, 0xb031 }, -+ { 0x0000, 0xd020, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xd021, 0x0000, 0x00fb, 0xb031 }, -+ { 0x0000, 0xd022, 0x0000, 0x0037, 0xb031 }, -+ { 0x0000, 0xd023, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd024, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd025, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xd026, 0x0000, 0x0090, 0xb031 }, -+ { 0x0000, 0xd027, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xd028, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xd029, 0x0000, 0x00fb, 0xb031 }, -+ { 0x0000, 0xd02a, 0x0000, 0x0037, 0xb031 }, -+ { 0x0000, 0xd02b, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd0c3, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd0c4, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xd0c0, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xce6a, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xce63, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xce64, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 }, -+ { 0x0000, 0xdb04, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xdb05, 0x0000, 0x0006, 0xb031 }, -+ { 0x0000, 0xcc00, 0x0000, 0x00c1, 0xb031 }, -+ { 0x0000, 0xca02, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xca00, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xca62, 0x0000, 0x0077, 0xb031 }, -+ { 0x0000, 0xca65, 0x0000, 0x0082, 0xb031 }, -+ { 0x0000, 0xca68, 0x0000, 0x00c2, 0xb031 }, -+ { 0x0000, 0xca75, 0x0000, 0x003a, 0xb031 }, -+ { 0x0000, 0xca7b, 0x0000, 0x006f, 0xb031 }, -+ { 0x0000, 0xca00, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xca02, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xc860, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xc861, 0x0000, 0x00e5, 0xb031 }, -+ { 0x0000, 0xc862, 0x0000, 0x00eb, 0xb031 }, -+ { 0x0000, 0xc863, 0x0000, 0x00c6, 0xb031 }, -+ { 0x0000, 0xc864, 0x0000, 0x00ba, 0xb031 }, -+ { 0x0000, 0xc865, 0x0000, 0x0061, 0xb031 }, -+ { 0x0000, 0xc867, 0x0000, 0x0017, 0xb031 }, -+ { 0x0000, 0xc868, 0x0000, 0x00ed, 0xb031 }, -+ { 0x0000, 0xc869, 0x0000, 0x003c, 0xb031 }, -+ { 0x0000, 0xc86a, 0x0000, 0x008a, 0xb031 }, -+ { 0x0000, 0xc86b, 0x0000, 0x00e2, 0xb031 }, -+ { 0x0000, 0xc875, 0x0000, 0x003a, 0xb031 }, -+ { 0x0000, 0xc87b, 0x0000, 0x006f, 0xb031 }, -+ { 0x0000, 0xc836, 0x0000, 0x00f9, 0xb031 }, -+ { 0x0000, 0xc8a0, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xc833, 0x0000, 0x000b, 0xb031 }, -+ { 0x0000, 0xc834, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xc83f, 0x0000, 0x0014, 0xb031 }, -+ { 0x0000, 0xc83e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc83a, 0x0000, 0x0076, 0xb031 }, -+ { 0x0000, 0xc83b, 0x0000, 0x0089, 0xb031 }, -+ { 0x0000, 0xc830, 0x0000, 0x0013, 0xb031 }, -+ { 0x0000, 0xc826, 0x0000, 0x00d1, 0xb031 }, -+ { 0x0000, 0xc890, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xc823, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xc824, 0x0000, 0x0004, 0xb031 }, -+ { 0x0000, 0xc82f, 0x0000, 0x0018, 0xb031 }, -+ { 0x0000, 0xc82e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc820, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xc816, 0x0000, 0x00f9, 0xb031 }, -+ { 0x0000, 0xc880, 0x0000, 0x00e1, 0xb031 }, -+ { 0x0000, 0xc813, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xc814, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xc81f, 0x0000, 0x0014, 0xb031 }, -+ { 0x0000, 0xc81e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc81a, 0x0000, 0x0066, 0xb031 }, -+ { 0x0000, 0xc81b, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xc810, 0x0000, 0x000d, 0xb031 }, -+ { 0x0000, 0xc846, 0x0000, 0x00f9, 0xb031 }, -+ { 0x0000, 0xc8d0, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xc844, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xc84f, 0x0000, 0x0014, 0xb031 }, -+ { 0x0000, 0xc84e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc84a, 0x0000, 0x0026, 0xb031 }, -+ { 0x0000, 0xc84b, 0x0000, 0x0056, 0xb031 }, -+ { 0x0000, 0xc800, 0x0000, 0x00b0, 0xb031 }, -+ { 0x0000, 0xc851, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xc500, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc501, 0x0000, 0x0026, 0xb031 }, -+ { 0x0000, 0xc502, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xc503, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xc504, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xc505, 0x0000, 0x00da, 0xb031 }, -+ { 0x0000, 0xc506, 0x0000, 0x000e, 0xb031 }, -+ { 0x0000, 0xc507, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc510, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xc511, 0x0000, 0x00da, 0xb031 }, -+ { 0x0000, 0xc512, 0x0000, 0x000e, 0xb031 }, -+ { 0x0000, 0xc513, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc514, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc515, 0x0000, 0x0026, 0xb031 }, -+ { 0x0000, 0xc516, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xc517, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xc518, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xc541, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xd250, 0x0000, 0x0087, 0xb031 }, -+ { 0x0000, 0xd251, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xd264, 0x0000, 0x00c0, 0xb031 }, -+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 }, -+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xecb0, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xec10, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xec11, 0x0000, 0x00bb, 0xb031 }, -+ { 0x0000, 0xec12, 0x0000, 0x00ab, 0xb031 }, -+ { 0x0000, 0xec13, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xec14, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec15, 0x0000, 0x004c, 0xb031 }, -+ { 0x0000, 0xec16, 0x0000, 0x0069, 0xb031 }, -+ { 0x0000, 0xec21, 0x0000, 0x0011, 0xb031 }, -+ { 0x0000, 0xec22, 0x0000, 0x00c2, 0xb031 }, -+ { 0x0000, 0xec23, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xec24, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xec25, 0x0000, 0x00bd, 0xb031 }, -+ { 0x0000, 0xec26, 0x0000, 0x0055, 0xb031 }, -+ { 0x0000, 0xec27, 0x0000, 0x00d0, 0xb031 }, -+ { 0x0000, 0xec28, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec29, 0x0000, 0x003c, 0xb031 }, -+ { 0x0000, 0xec2a, 0x0000, 0x0051, 0xb031 }, -+ { 0x0000, 0xec2b, 0x0000, 0x0018, 0xb031 }, -+ { 0x0000, 0xecb2, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xec30, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xec31, 0x0000, 0x004f, 0xb031 }, -+ { 0x0000, 0xec32, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xec33, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xec34, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec35, 0x0000, 0x00bb, 0xb031 }, -+ { 0x0000, 0xec36, 0x0000, 0x0024, 0xb031 }, -+ { 0x0000, 0xec37, 0x0000, 0x0068, 0xb031 }, -+ { 0x0000, 0xec40, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec41, 0x0000, 0x00f5, 0xb031 }, -+ { 0x0000, 0xec42, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xec43, 0x0000, 0x00e8, 0xb031 }, -+ { 0x0000, 0xec44, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xec45, 0x0000, 0x004f, 0xb031 }, -+ { 0x0000, 0xec46, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xec47, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xec48, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec49, 0x0000, 0x00c5, 0xb031 }, -+ { 0x0000, 0xec4a, 0x0000, 0x0032, 0xb031 }, -+ { 0x0000, 0xec4b, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xecb4, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xec50, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xec51, 0x0000, 0x008a, 0xb031 }, -+ { 0x0000, 0xec52, 0x0000, 0x00b4, 0xb031 }, -+ { 0x0000, 0xec53, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xec54, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec55, 0x0000, 0x007d, 0xb031 }, -+ { 0x0000, 0xec56, 0x0000, 0x00d9, 0xb031 }, -+ { 0x0000, 0xec57, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xec60, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xec61, 0x0000, 0x00e7, 0xb031 }, -+ { 0x0000, 0xec62, 0x0000, 0x00b5, 0xb031 }, -+ { 0x0000, 0xec63, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xec64, 0x0000, 0x00fa, 0xb031 }, -+ { 0x0000, 0xec65, 0x0000, 0x0086, 0xb031 }, -+ { 0x0000, 0xec66, 0x0000, 0x00a8, 0xb031 }, -+ { 0x0000, 0xec67, 0x0000, 0x0040, 0xb031 }, -+ { 0x0000, 0xec68, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xec69, 0x0000, 0x009a, 0xb031 }, -+ { 0x0000, 0xec6a, 0x0000, 0x002f, 0xb031 }, -+ { 0x0000, 0xec6b, 0x0000, 0x0018, 0xb031 }, -+ { 0x0000, 0xecb6, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xec70, 0x0000, 0x00f5, 0xb031 }, -+ { 0x0000, 0xec71, 0x0000, 0x00e1, 0xb031 }, -+ { 0x0000, 0xec72, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xec73, 0x0000, 0x00d0, 0xb031 }, -+ { 0x0000, 0xec74, 0x0000, 0x0006, 0xb031 }, -+ { 0x0000, 0xec75, 0x0000, 0x0050, 0xb031 }, -+ { 0x0000, 0xec76, 0x0000, 0x002c, 0xb031 }, -+ { 0x0000, 0xec77, 0x0000, 0x0050, 0xb031 }, -+ { 0x0000, 0xec80, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec81, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xec82, 0x0000, 0x0016, 0xb031 }, -+ { 0x0000, 0xec83, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xec84, 0x0000, 0x00f5, 0xb031 }, -+ { 0x0000, 0xec85, 0x0000, 0x00e1, 0xb031 }, -+ { 0x0000, 0xec86, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xec87, 0x0000, 0x00d0, 0xb031 }, -+ { 0x0000, 0xec88, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xec89, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xec8a, 0x0000, 0x0016, 0xb031 }, -+ { 0x0000, 0xec8b, 0x0000, 0x0028, 0xb031 }, -+ { 0x0000, 0xecb8, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xec90, 0x0000, 0x00fc, 0xb031 }, -+ { 0x0000, 0xec91, 0x0000, 0x008b, 0xb031 }, -+ { 0x0000, 0xec92, 0x0000, 0x00bd, 0xb031 }, -+ { 0x0000, 0xec93, 0x0000, 0x0064, 0xb031 }, -+ { 0x0000, 0xec94, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xec95, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xec96, 0x0000, 0x00e7, 0xb031 }, -+ { 0x0000, 0xec97, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xeca0, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xeca1, 0x0000, 0x0091, 0xb031 }, -+ { 0x0000, 0xeca2, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xeca3, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xeca4, 0x0000, 0x00f6, 0xb031 }, -+ { 0x0000, 0xeca5, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xeca6, 0x0000, 0x0093, 0xb031 }, -+ { 0x0000, 0xeca7, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xeca8, 0x0000, 0x0003, 0xb031 }, -+ { 0x0000, 0xeca9, 0x0000, 0x0087, 0xb031 }, -+ { 0x0000, 0xecaa, 0x0000, 0x0099, 0xb031 }, -+ { 0x0000, 0xecab, 0x0000, 0x006c, 0xb031 }, -+ { 0x0000, 0xebc3, 0x0000, 0x00ff, 0xb031 }, -+ { 0x0000, 0xebc4, 0x0000, 0x00fc, 0xb031 }, -+ { 0x0000, 0xec00, 0x0000, 0x0005, 0xb031 }, -+ { 0x0000, 0xec01, 0x0000, 0x00a9, 0xb031 }, -+ { 0x0000, 0xec02, 0x0000, 0x00df, 0xb031 }, -+ { 0x0000, 0xec03, 0x0000, 0x007b, 0xb031 }, -+ { 0x0000, 0xec05, 0x0000, 0x0079, 0xb031 }, -+ { 0x0000, 0xec06, 0x0000, 0x005a, 0xb031 }, -+ { 0x0000, 0xec07, 0x0000, 0x0004, 0xb031 }, -+ { 0x0000, 0xebc0, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xd1b0, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xd110, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd111, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xd112, 0x0000, 0x0092, 0xb031 }, -+ { 0x0000, 0xd113, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd114, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xd115, 0x0000, 0x00f6, 0xb031 }, -+ { 0x0000, 0xd116, 0x0000, 0x0072, 0xb031 }, -+ { 0x0000, 0xd117, 0x0000, 0x00b0, 0xb031 }, -+ { 0x0000, 0xd120, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xd121, 0x0000, 0x00fb, 0xb031 }, -+ { 0x0000, 0xd122, 0x0000, 0x0037, 0xb031 }, -+ { 0x0000, 0xd123, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd124, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd125, 0x0000, 0x0009, 0xb031 }, -+ { 0x0000, 0xd126, 0x0000, 0x0090, 0xb031 }, -+ { 0x0000, 0xd127, 0x0000, 0x0020, 0xb031 }, -+ { 0x0000, 0xd128, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xd129, 0x0000, 0x00fb, 0xb031 }, -+ { 0x0000, 0xd12a, 0x0000, 0x0037, 0xb031 }, -+ { 0x0000, 0xd12b, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd0c3, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd0c4, 0x0000, 0x000c, 0xb031 }, -+ { 0x0000, 0xd0c0, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xce63, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xce64, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 }, -+ { 0x0000, 0xdd04, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xdd05, 0x0000, 0x0006, 0xb031 }, -+ { 0x0000, 0xca12, 0x0000, 0x000f, 0xb031 }, -+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xca82, 0x0000, 0x0077, 0xb031 }, -+ { 0x0000, 0xca85, 0x0000, 0x0082, 0xb031 }, -+ { 0x0000, 0xca88, 0x0000, 0x00c2, 0xb031 }, -+ { 0x0000, 0xca95, 0x0000, 0x003a, 0xb031 }, -+ { 0x0000, 0xca9b, 0x0000, 0x006f, 0xb031 }, -+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xca12, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xc960, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xc961, 0x0000, 0x00e5, 0xb031 }, -+ { 0x0000, 0xc962, 0x0000, 0x00eb, 0xb031 }, -+ { 0x0000, 0xc963, 0x0000, 0x00c6, 0xb031 }, -+ { 0x0000, 0xc964, 0x0000, 0x00ba, 0xb031 }, -+ { 0x0000, 0xc965, 0x0000, 0x0061, 0xb031 }, -+ { 0x0000, 0xc967, 0x0000, 0x0017, 0xb031 }, -+ { 0x0000, 0xc968, 0x0000, 0x00ed, 0xb031 }, -+ { 0x0000, 0xc969, 0x0000, 0x003c, 0xb031 }, -+ { 0x0000, 0xc96a, 0x0000, 0x008a, 0xb031 }, -+ { 0x0000, 0xc96b, 0x0000, 0x00e2, 0xb031 }, -+ { 0x0000, 0xc975, 0x0000, 0x003a, 0xb031 }, -+ { 0x0000, 0xc97b, 0x0000, 0x006f, 0xb031 }, -+ { 0x0000, 0xc936, 0x0000, 0x00f9, 0xb031 }, -+ { 0x0000, 0xc9a0, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xc933, 0x0000, 0x000b, 0xb031 }, -+ { 0x0000, 0xc934, 0x0000, 0x0002, 0xb031 }, -+ { 0x0000, 0xc93f, 0x0000, 0x0014, 0xb031 }, -+ { 0x0000, 0xc93e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc93a, 0x0000, 0x0076, 0xb031 }, -+ { 0x0000, 0xc93b, 0x0000, 0x0089, 0xb031 }, -+ { 0x0000, 0xc930, 0x0000, 0x0013, 0xb031 }, -+ { 0x0000, 0xc926, 0x0000, 0x00d1, 0xb031 }, -+ { 0x0000, 0xc990, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xc923, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xc924, 0x0000, 0x0004, 0xb031 }, -+ { 0x0000, 0xc92f, 0x0000, 0x0018, 0xb031 }, -+ { 0x0000, 0xc92e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc920, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xc916, 0x0000, 0x00f9, 0xb031 }, -+ { 0x0000, 0xc980, 0x0000, 0x00e1, 0xb031 }, -+ { 0x0000, 0xc913, 0x0000, 0x0000, 0xb031 }, -+ { 0x0000, 0xc914, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xc91f, 0x0000, 0x0014, 0xb031 }, -+ { 0x0000, 0xc91e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc91a, 0x0000, 0x0066, 0xb031 }, -+ { 0x0000, 0xc91b, 0x0000, 0x0078, 0xb031 }, -+ { 0x0000, 0xc910, 0x0000, 0x000d, 0xb031 }, -+ { 0x0000, 0xc946, 0x0000, 0x00f9, 0xb031 }, -+ { 0x0000, 0xc9d0, 0x0000, 0x00f1, 0xb031 }, -+ { 0x0000, 0xc944, 0x0000, 0x0001, 0xb031 }, -+ { 0x0000, 0xc94f, 0x0000, 0x0014, 0xb031 }, -+ { 0x0000, 0xc94e, 0x0000, 0x0094, 0xb031 }, -+ { 0x0000, 0xc94a, 0x0000, 0x0026, 0xb031 }, -+ { 0x0000, 0xc94b, 0x0000, 0x0056, 0xb031 }, -+ { 0x0000, 0xc951, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xc600, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc601, 0x0000, 0x0026, 0xb031 }, -+ { 0x0000, 0xc602, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xc603, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xc604, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xc605, 0x0000, 0x00da, 0xb031 }, -+ { 0x0000, 0xc606, 0x0000, 0x000e, 0xb031 }, -+ { 0x0000, 0xc607, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc610, 0x0000, 0x0007, 0xb031 }, -+ { 0x0000, 0xc611, 0x0000, 0x00da, 0xb031 }, -+ { 0x0000, 0xc612, 0x0000, 0x000e, 0xb031 }, -+ { 0x0000, 0xc613, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc614, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xc615, 0x0000, 0x0026, 0xb031 }, -+ { 0x0000, 0xc616, 0x0000, 0x004a, 0xb031 }, -+ { 0x0000, 0xc617, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xc618, 0x0000, 0x0008, 0xb031 }, -+ { 0x0000, 0xc541, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xc802, 0x0000, 0x00d2, 0xb031 }, -+ { 0x0000, 0xc902, 0x0000, 0x00d2, 0xb031 }, -+ { 0x0000, 0xc800, 0x0000, 0x00f0, 0xb031 }, -+ { 0x0000, 0xd250, 0x0000, 0x0087, 0xb031 }, -+ { 0x0000, 0xd252, 0x0000, 0x0030, 0xb031 }, -+ { 0x0000, 0xd264, 0x0000, 0x00c0, 0xb031 }, -+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 }, -+ { 0x0000, 0xdf00, 0x0000, 0x0010, 0xb031 }, -+ { 0x0000, 0xdbb5, 0x0041, 0xd27f, 0xb037 }, -+ { 0x0000, 0xddb5, 0x0040, 0x6e3b, 0xb037 }, -+ { 0x0000, 0xdb93, 0x0000, 0x009e, 0xb033 }, -+ { 0x0000, 0xdd93, 0x0000, 0x009e, 0xb033 }, -+ { 0x0000, 0xdb12, 0x0000, 0x00c0, 0xb031 }, -+ { 0x0000, 0xdd12, 0x0000, 0x00c0, 0xb031 }, -+ { 0x0000, 0xdb08, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xdd08, 0x0000, 0x0080, 0xb031 }, -+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 }, -+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 }, -+ { 0x0000, 0x0010, 0x0000, 0x0f21, 0x0000 }, -+}; -+ -+/* wake the amp (ea00=0x43, c121=0x0b, f109=0xe0) */ -+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_wake[] = { -+ { 0x0000, 0xea00, 0x0000, 0x0043, 0xb031 }, -+ { 0x0000, 0xc121, 0x0000, 0x000b, 0xb031 }, -+ { 0x0000, 0xf109, 0x0000, 0x00e0, 0xb031 }, -+}; -+ -+/* park the amp (ea00=0x47, c121=0x0a, f109=0xa0) */ -+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_sleep[] = { -+ { 0x0000, 0xea00, 0x0000, 0x0047, 0xb031 }, -+ { 0x0000, 0xc121, 0x0000, 0x000a, 0xb031 }, -+ { 0x0000, 0xf109, 0x0000, 0x00a0, 0xb031 }, -+}; -+ -+/* -+ * Razer Blade 16 (2025): Realtek ALC298 driving an external smart amp. -+ * Crossover, voicing and speaker protection live in an external DSP -+ * reached over a vendor-coef mailbox on NID 0x20; the captured DSP -+ * programming is in the tables above. NID 0x14, the BIOS-disabled -+ * tweeter pin, is re-exposed via a pin-config override so the parser -+ * drives it as a normal internal speaker (shared volume/mute, auto-mute -+ * on headphone insertion). -+ * -+ * alc298_razer_blade16_2025_apply() runs one op-table: a plain coef write -+ * (strobe == 0) goes through alc_write_coef_idx(), while a mailbox op -+ * selects a bank and streams four PROC_COEF words (addr/hi/lo/commit) -+ * into a single coef index (0x23) on NID 0x20 to reach the external DSP -+ * -- that one-index/many-words form is why it cannot be expressed as an -+ * alc_process_coef_fw() table (one value per index). -+ */ -+static void alc298_razer_blade16_2025_apply(struct hda_codec *codec, -+ const struct alc298_razer_blade16_2025_op *seq, -+ int num) -+{ -+ int i; -+ -+ for (i = 0; i < num; i++) { -+ if (!seq[i].strobe) { -+ alc_write_coef_idx(codec, seq[i].addr, seq[i].lo); -+ continue; -+ } -+ alc_write_coef_idx(codec, 0x89, seq[i].bank); -+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x23); -+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].addr); -+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].hi); -+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].lo); -+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].strobe); -+ } -+} -+ -+static void alc298_razer_blade16_2025_pcm_hook(struct hda_pcm_stream *hinfo, -+ struct hda_codec *codec, -+ struct snd_pcm_substream *substream, -+ int action) -+{ -+ /* power the external amp only while a stream is running */ -+ switch (action) { -+ case HDA_GEN_PCM_ACT_PREPARE: -+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_wake, -+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_wake)); -+ break; -+ case HDA_GEN_PCM_ACT_CLEANUP: -+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_sleep, -+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_sleep)); -+ break; -+ } -+} -+ -+static void alc298_fixup_razer_blade16_2025(struct hda_codec *codec, -+ const struct hda_fixup *fix, int action) -+{ -+ /* -+ * Pin every output to a fixed converter so the routing does not -+ * rely on the generic parser's DAC-allocation heuristics: without -+ * a fixed assignment the parser brings up only one speaker pin and -+ * leaves the other silent, and the allocation could change between -+ * kernel versions. Both speaker pins share DAC 0x03 through mixer -+ * 0x0d: that is the only converter that drives the woofer (NID -+ * 0x17) on this machine -- feeding it from DAC 0x02 or the digital -+ * converter 0x06 leaves the woofer silent. Both pins carry the -+ * same stereo stream and the external amp does the crossover. -+ * Headphone NID 0x21 keeps DAC 0x02. -+ */ -+ static const hda_nid_t preferred_pairs[] = { -+ 0x21, 0x02, -+ 0x14, 0x03, -+ 0x17, 0x03, -+ 0 -+ }; -+ struct alc_spec *spec = codec->spec; -+ -+ switch (action) { -+ case HDA_FIXUP_ACT_PRE_PROBE: -+ spec->gen.preferred_dacs = preferred_pairs; -+ break; -+ case HDA_FIXUP_ACT_PROBE: -+ spec->gen.pcm_playback_hook = alc298_razer_blade16_2025_pcm_hook; -+ break; -+ case HDA_FIXUP_ACT_INIT: -+ /* -+ * Wake the amp, program its DSP at boot and on resume, then -+ * park it. It is woken again for playback and parked -+ * afterwards from the pcm_playback_hook. -+ */ -+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_wake, -+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_wake)); -+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_init, -+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_init)); -+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_sleep, -+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_sleep)); -+ break; -+ } -+} -diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c ---- a/sound/hda/codecs/realtek/alc269.c -+++ b/sound/hda/codecs/realtek/alc269.c -@@ -296,7 +296,8 @@ static void alc282_init(struct hda_codec *codec) - msleep(100); - - /* Headphone capless set to normal mode */ -- alc_write_coef_idx(codec, 0x78, coef78); -+ if (coef78 != -1) -+ alc_write_coef_idx(codec, 0x78, coef78); - } - - static void alc282_shutup(struct hda_codec *codec) -@@ -333,7 +334,8 @@ static void alc282_shutup(struct hda_codec *codec) - - alc_auto_setup_eapd(codec, false); - alc_shutup_pins(codec); -- alc_write_coef_idx(codec, 0x78, coef78); -+ if (coef78 != -1) -+ alc_write_coef_idx(codec, 0x78, coef78); - } - - static const struct coef_fw alc283_coefs[] = { -@@ -585,15 +587,19 @@ static void alc285_hp_init(struct hda_codec *codec) - - alc_write_coefex_idx(codec, 0x58, 0x00, 0xf888); /* HP depop procedure start */ - val = alc_read_coefex_idx(codec, 0x58, 0x00); -- for (i = 0; i < 20 && val & 0x8000; i++) { -+ for (i = 0; i < 20 && val != -1 && val & 0x8000; i++) { - msleep(50); - val = alc_read_coefex_idx(codec, 0x58, 0x00); - } /* Wait for depop procedure finish */ - -- alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */ -- alc_update_coef_idx(codec, 0x38, 1<<4, coef38); -- alc_update_coef_idx(codec, 0x0d, 0x110, coef0d); -- alc_update_coef_idx(codec, 0x36, 3<<13, coef36); -+ if (val != -1) -+ alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */ -+ if (coef38 != -1) -+ alc_update_coef_idx(codec, 0x38, 1<<4, coef38); -+ if (coef0d != -1) -+ alc_update_coef_idx(codec, 0x0d, 0x110, coef0d); -+ if (coef36 != -1) -+ alc_update_coef_idx(codec, 0x36, 3<<13, coef36); - - msleep(50); - alc_update_coef_idx(codec, 0x4a, 1<<15, 0); -@@ -858,7 +864,7 @@ static void alc294_hp_init(struct hda_codec *codec) - - /* Wait for depop procedure finish */ - val = alc_read_coefex_idx(codec, 0x58, 0x01); -- for (i = 0; i < 20 && val & 0x0080; i++) { -+ for (i = 0; i < 20 && val != -1 && val & 0x0080; i++) { - msleep(50); - val = alc_read_coefex_idx(codec, 0x58, 0x01); - } -@@ -1392,6 +1398,15 @@ static void alc245_fixup_hp_gpio_led(struct hda_codec *codec, - alc_fixup_hp_gpio_led(codec, action, 0, 0x04); - } - -+static void alc245_fixup_minisforum_jack_detect(struct hda_codec *codec, -+ const struct hda_fixup *fix, -+ int action) -+{ -+ if (action == HDA_FIXUP_ACT_INIT) -+ /* Clear Reset HP JD while preserving the other coefficient bits. */ -+ alc_update_coef_idx(codec, 0x4a, BIT(15), 0); -+} -+ - /* turn on/off mic-mute LED per capture hook via VREF change */ - static int vref_micmute_led_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -@@ -2557,6 +2572,13 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec, - } - } - -+static void alc285_lenovo_dac_rename(struct hda_codec *codec, -+ const struct hda_fixup *fix, int action) -+{ -+ if (action == HDA_FIXUP_ACT_BUILD) -+ rename_ctl(codec, "Line Out Playback Volume", -+ "Headphone Playback Volume"); -+} - static void alc290_fixup_mono_speakers(struct hda_codec *codec, - const struct hda_fixup *fix, int action) - { -@@ -3262,6 +3284,36 @@ static void find_cirrus_companion_amps(struct hda_codec *cdc) - comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count); - } - -+static void aw88399_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action) -+{ -+ comp_generic_fixup(cdc, action, "i2c", "AWDZ8399", "-%s:00-aw88399-hda.%d", 2); -+} -+ -+static void alc287_fixup_legion_16iax10h_aw88399(struct hda_codec *codec, -+ const struct hda_fixup *fix, int action) -+{ -+ /* -+ * Force DAC 0x02 for the bass speaker 0x17, as the default 0x06 lacks volume controls. -+ */ -+ static const hda_nid_t conn[] = { 0x02 }; -+ struct alc_spec *spec = codec->spec; -+ -+ alc269_fixup_limit_int_mic_boost(codec, fix, action); -+ alc_fixup_headset_mode_no_hp_mic(codec, fix, action); -+ alc_fixup_headset_jack(codec, fix, action); -+ -+ switch (action) { -+ case HDA_FIXUP_ACT_PRE_PROBE: -+ spec->gen.suppress_auto_mic = 1; -+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn); -+ break; -+ case HDA_FIXUP_ACT_BUILD: -+ spec->gen.multiout.max_channels = 2; -+ spec->gen.pcm_rec[0]->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 2; -+ break; -+ } -+} -+ - static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action) - { - comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2); -@@ -3357,6 +3409,9 @@ static void alc287_fixup_acer_micmute_led(struct hda_codec *codec, - /* for alc285_fixup_ideapad_s740_coef() */ - #include "../helpers/ideapad_s740.c" - -+/* for alc298_fixup_razer_blade16_2025() */ -+#include "../helpers/razer_blade16_2025.c" -+ - static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = { - WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000), - WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000), -@@ -3939,6 +3994,7 @@ enum { - ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572, - ALC269_FIXUP_ACER_AC700, - ALC269_FIXUP_LIMIT_INT_MIC_BOOST, -+ ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST, - ALC269VB_FIXUP_ASUS_ZENBOOK, - ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, - ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE, -@@ -4007,6 +4063,7 @@ enum { - ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC295_FIXUP_DISABLE_DAC3, - ALC285_FIXUP_SPEAKER2_TO_DAC1, -+ ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1, - ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1, - ALC285_FIXUP_ASUS_HEADSET_MIC, - ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS, -@@ -4076,7 +4133,6 @@ enum { - ALC294_FIXUP_ASUS_ALLY, - ALC294_FIXUP_ASUS_ALLY_PINS, - ALC294_FIXUP_ASUS_ALLY_VERBS, -- ALC294_FIXUP_ASUS_ALLY_SPEAKER, - ALC294_FIXUP_ASUS_HPE, - ALC294_FIXUP_ASUS_COEF_1B, - ALC294_FIXUP_ASUS_GX502_HP, -@@ -4101,6 +4157,8 @@ enum { - ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, - ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS, - ALC298_FIXUP_LG_GRAM_STYLE_14, -+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS, -+ ALC298_FIXUP_RAZER_BLADE16_2025, - ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, - ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, - ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, -@@ -4118,7 +4176,6 @@ enum { - ALC269_FIXUP_LEMOTE_A190X, - ALC256_FIXUP_INTEL_NUC8_RUGGED, - ALC233_FIXUP_INTEL_NUC8_DMIC, -- ALC233_FIXUP_INTEL_NUC8_BOOST, - ALC256_FIXUP_INTEL_NUC10, - ALC255_FIXUP_XIAOMI_HEADSET_MIC, - ALC274_FIXUP_HP_MIC, -@@ -4149,6 +4206,7 @@ enum { - ALC298_FIXUP_LENOVO_C940_DUET7, - ALC287_FIXUP_LENOVO_YOGA_BOOK_9I, - ALC287_FIXUP_LENOVO_YOGA_PRO7, -+ ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK, - ALC287_FIXUP_13S_GEN2_SPEAKERS, - ALC256_FIXUP_SET_COEF_DEFAULTS, - ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, -@@ -4193,7 +4251,6 @@ enum { - ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD, - ALC2XX_FIXUP_HEADSET_MIC, - ALC289_FIXUP_DELL_CS35L41_SPI_2, -- ALC294_FIXUP_CS35L41_I2C_2, - ALC256_FIXUP_ACER_SFG16_MICMUTE_LED, - ALC256_FIXUP_HEADPHONE_AMP_VOL, - ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX, -@@ -4207,6 +4264,7 @@ enum { - ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318, - ALC256_FIXUP_CHROME_BOOK, - ALC245_FIXUP_CLEVO_NOISY_MIC, -+ ALC245_FIXUP_MINISFORUM_JACK_DETECT, - ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE, - ALC233_FIXUP_MEDION_MTL_SPK, - ALC233_FIXUP_STARLABS_STARFIGHTER, -@@ -4216,7 +4274,6 @@ enum { - ALC274_FIXUP_HP_AIO_BIND_DACS, - ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2, - ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC, -- ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1, - ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC, - ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK, - ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE, -@@ -4236,6 +4293,10 @@ enum { - ALC236_FIXUP_DELL_HP_POP_NOISE, - ALC274_FIXUP_HP_89E9_GPIO, - ALC274_FIXUP_HP_VERBS, -+ ALC287_FIXUP_AW88399_I2C_2, -+ ALC287_FIXUP_LENOVO_LEGION_AW88399, -+ ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET, -+ ALC285_LENOVO_DAC_RENAME, - }; - - /* A special fixup for Lenovo C940 and Yoga Duet 7; -@@ -4273,6 +4334,20 @@ static void alc287_fixup_lenovo_yoga_book_9i(struct hda_codec *codec, - } - - static const struct hda_fixup alc269_fixups[] = { -+ [ALC298_FIXUP_RAZER_BLADE16_2025_PINS] = { -+ .type = HDA_FIXUP_PINS, -+ .v.pins = (const struct hda_pintbl[]) { -+ { 0x14, 0x90170121 }, /* tweeter as internal speaker, seq 1 */ -+ { 0x17, 0x90170120 }, /* woofer as internal speaker, seq 0 */ -+ { } -+ }, -+ .chained = true, -+ .chain_id = ALC298_FIXUP_RAZER_BLADE16_2025, -+ }, -+ [ALC298_FIXUP_RAZER_BLADE16_2025] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc298_fixup_razer_blade16_2025, -+ }, - [ALC233_FIXUP_WUJIE_SPEAKERS] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { -@@ -4713,6 +4788,10 @@ static const struct hda_fixup alc269_fixups[] = { - .chain_id = ALC271_FIXUP_DMIC, - }, - [ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc269_fixup_limit_int_mic_boost -+ }, -+ [ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc269_fixup_limit_int_mic_boost, - .chained = true, -@@ -5088,11 +5167,7 @@ static const struct hda_fixup alc269_fixups[] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic, - .chained = true, -- .chain_id = ALC233_FIXUP_INTEL_NUC8_BOOST, -- }, -- [ALC233_FIXUP_INTEL_NUC8_BOOST] = { -- .type = HDA_FIXUP_FUNC, -- .v.func = alc269_fixup_limit_int_mic_boost -+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST, - }, - [ALC255_FIXUP_DELL_SPK_NOISE] = { - .type = HDA_FIXUP_FUNC, -@@ -5153,6 +5228,10 @@ static const struct hda_fixup alc269_fixups[] = { - [ALC285_FIXUP_SPEAKER2_TO_DAC1] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc285_fixup_speaker2_to_dac1, -+ }, -+ [ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc285_fixup_speaker2_to_dac1, - .chained = true, - .chain_id = ALC269_FIXUP_THINKPAD_ACPI - }, -@@ -5672,11 +5751,7 @@ static const struct hda_fixup alc269_fixups[] = { - { } - }, - .chained = true, -- .chain_id = ALC294_FIXUP_ASUS_ALLY_SPEAKER -- }, -- [ALC294_FIXUP_ASUS_ALLY_SPEAKER] = { -- .type = HDA_FIXUP_FUNC, -- .v.func = alc285_fixup_speaker2_to_dac1, -+ .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1 - }, - [ALC285_FIXUP_THINKPAD_X1_GEN7] = { - .type = HDA_FIXUP_FUNC, -@@ -6223,6 +6298,16 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC269_FIXUP_LENOVO_XPAD_ACPI, - }, -+ [ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc_fixup_headset_jack, -+ .chained = true, -+ /* Same as ALC285_FIXUP_THINKPAD_HEADSET_JACK, except that the -+ * mute LEDs are driven through ideapad_laptop rather than -+ * thinkpad_acpi. -+ */ -+ .chain_id = ALC287_FIXUP_LENOVO_YOGA_PRO7, -+ }, - [ALC623_FIXUP_LENOVO_THINKSTATION_P340] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_no_shutup, -@@ -6662,10 +6747,6 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC289_FIXUP_DUAL_SPK - }, -- [ALC294_FIXUP_CS35L41_I2C_2] = { -- .type = HDA_FIXUP_FUNC, -- .v.func = cs35l41_fixup_i2c_two, -- }, - [ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc256_fixup_acer_sfg16_micmute_led, -@@ -6738,6 +6819,10 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, - }, -+ [ALC245_FIXUP_MINISFORUM_JACK_DETECT] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc245_fixup_minisforum_jack_detect, -+ }, - [ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE] = { - .type = HDA_FIXUP_PINS, - .v.pins = (const struct hda_pintbl[]) { -@@ -6758,6 +6843,8 @@ static const struct hda_fixup alc269_fixups[] = { - [ALC233_FIXUP_STARLABS_STARFIGHTER] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc233_fixup_starlabs_starfighter, -+ .chained = true, -+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST, - }, - [ALC294_FIXUP_BASS_SPEAKER_15] = { - .type = HDA_FIXUP_FUNC, -@@ -6785,11 +6872,7 @@ static const struct hda_fixup alc269_fixups[] = { - { } - }, - .chained = true, -- .chain_id = ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1 -- }, -- [ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1] = { -- .type = HDA_FIXUP_FUNC, -- .v.func = alc285_fixup_speaker2_to_dac1, -+ .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1 - }, - [ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC] = { - .type = HDA_FIXUP_FUNC, -@@ -6907,6 +6990,26 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC274_FIXUP_HP_89E9_GPIO, - }, -+ [ALC287_FIXUP_AW88399_I2C_2] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = aw88399_fixup_i2c_two, -+ }, -+ [ALC287_FIXUP_LENOVO_LEGION_AW88399] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc287_fixup_legion_16iax10h_aw88399, -+ .chained = true, -+ .chain_id = ALC287_FIXUP_AW88399_I2C_2, -+ }, -+ [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc_fixup_headset_jack, -+ .chained = true, -+ .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, -+ }, -+ [ALC285_LENOVO_DAC_RENAME] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc285_lenovo_dac_rename, -+ }, - }; - - static const struct hda_quirk alc269_fixup_tbl[] = { -@@ -6960,8 +7063,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x159e, "Acer Nitro 5 AN515-46", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC), -+ SND_PCI_QUIRK(0x1025, 0x1616, "Acer Aspire A515-57", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x161f, "Acer S40-54", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), -+ SND_PCI_QUIRK(0x1025, 0x166c, "Acer Predator PH16-71", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED), -@@ -6970,6 +7075,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x1025, 0x1909, "Acer Nitro ANV16-42", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), - SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X), - SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), -@@ -7154,10 +7260,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11), - SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360), - SND_PCI_QUIRK(0x103c, 0x85f0, "HP Laptop 15-dw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), -+ SND_PCI_QUIRK(0x103c, 0x85f3, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x8603, "HP Omen 17-cb0xxx", ALC285_FIXUP_HP_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x860c, "HP ZBook 17 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT), - SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT), - SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT), -+ SND_PCI_QUIRK(0x103c, 0x864f, "HP Laptop 15-dy0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), -@@ -7268,6 +7376,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8a05, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8a06, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), -+ SND_PCI_QUIRK(0x103c, 0x8a0e, "HP Pavilion Laptop 15-eh2xxx", ALC287_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8a1b, "HP 255 15.6 inch G9 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x8a1f, "HP Laptop 14s-dr5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), -@@ -7359,10 +7468,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX), - SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX), -- SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX), - SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS), - SND_PCI_QUIRK(0x103c, 0x8c2d, "HP Victus 15-fa1xxx (MB 8C2D)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), -+ SND_PCI_QUIRK(0x103c, 0x8c3f, "HP Victus 15-fa1xxx (MB 8C3F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), -@@ -7511,6 +7621,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x8f57, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), -+ SND_PCI_QUIRK(0x103c, 0x8f7e, "HP Messi", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x8f94, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED), - SND_PCI_QUIRK(0x103c, 0x8f95, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED), - SND_PCI_QUIRK(0x1043, 0x1024, "ASUS Zephyrus G14 2025", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC), -@@ -7518,6 +7629,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), - SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), - SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), -+ SND_PCI_QUIRK(0x1043, 0x1044, "ASUS GA403UM", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x1043, 0x106f, "ASUS VivoBook X515UA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), -@@ -7525,16 +7637,15 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK), - SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), -+ SND_PCI_QUIRK(0x1043, 0x10c4, "ASUS Vivobook S14 S5406SA", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK), - SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), -- HDA_CODEC_QUIRK(0x1043, 0x1204, "ASUS Strix G16 G615JMR", ALC287_FIXUP_TXNW2781_I2C_ASUS), -- SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C), -- HDA_CODEC_QUIRK(0x1043, 0x1214, "ASUS ROG Strix G615LP", ALC287_FIXUP_TXNW2781_I2C_ASUS), -- SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C), -+ SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TXNW2781_I2C_ASUS), -+ SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TXNW2781_I2C_ASUS), - SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), -@@ -7583,7 +7694,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), - SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), -- SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE), - SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401), -@@ -7594,7 +7705,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x19f4, "ASUS UM3405GA", ALC294_FIXUP_ASUS_I2C_HEADSET_MIC), - SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), - SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC294_FIXUP_ASUS_SPI_HEADSET_MIC), -- SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1043, 0x1a8e, "ASUS G712LWS", ALC294_FIXUP_LENOVO_MIC_LOCATION), - SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B), -@@ -7623,6 +7734,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15), - SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), -+ SND_PCI_QUIRK(0x1043, 0x1e3e, "ASUS VivoBook M515DA/X515DAP", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), - SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC), -@@ -7634,8 +7746,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE), - SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RC72LA", ALC287_FIXUP_ASUS_ALLY_X), - SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2), -- HDA_CODEC_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1), -- SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1), - SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401), - SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), - SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2), -@@ -7846,7 +7957,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK), -- SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -+ SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), -@@ -7862,7 +7973,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), -- SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -+ SND_PCI_QUIRK(0x17aa, 0x225c, "Lenovo ThinkPad X1 Carbon 6th Gen", ALC285_LENOVO_DAC_RENAME), -+ SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x17aa, 0x2288, "Thinkpad X390", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK), - SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK), - SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK), -@@ -7937,7 +8049,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - HDA_CODEC_QUIRK(0x17aa, 0x386a, "Lenovo Yoga 7 16IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2), -- SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1), -+ SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1), - HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */ - HDA_CODEC_QUIRK(0x17aa, 0x38a7, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */ - SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), -@@ -7972,6 +8084,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C), -+ HDA_CODEC_QUIRK(0x17aa, 0x3926, "Legion Pro 5 16ADR10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), -+ /* Legion R9000P ADR10 shares PCI SSID 17aa:38bb with Yoga S780-14.5 Air AMD quad AAC; -+ * use codec SSID to distinguish them -+ */ -+ HDA_CODEC_QUIRK(0x17aa, 0x3927, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399), -+ HDA_CODEC_QUIRK(0x17aa, 0x3928, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399), - SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C), -@@ -7989,7 +8107,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C), -- SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C), - /* Legion 7 15ASH11 shares PCI SSID 17aa:38f9 with Thinkbook 16P Gen5; - * use codec SSID to distinguish them - */ -@@ -7999,7 +8116,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x38fc, "Lenovo Yoga Pro 7 15ASH11", ALC287_FIXUP_LENOVO_YOGA_PRO7), - SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), -- SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), -+ HDA_CODEC_QUIRK(0x17aa, 0x3906, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399), -+ HDA_CODEC_QUIRK(0x17aa, 0x3907, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399), -+ SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET), - SND_PCI_QUIRK(0x17aa, 0x3911, "Lenovo Yoga Pro 7 14IAH10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x3912, "Lenovo Xiaoxin 14 GT", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC), -@@ -8007,14 +8126,19 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x3929, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x392b, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), -+ HDA_CODEC_QUIRK(0x17aa, 0x3936, "Legion R9000P ADR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399), -+ HDA_CODEC_QUIRK(0x17aa, 0x3937, "Legion R9000P ADR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399), -+ HDA_CODEC_QUIRK(0x17aa, 0x3938, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399), -+ HDA_CODEC_QUIRK(0x17aa, 0x3939, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399), -+ SND_PCI_QUIRK(0x17aa, 0x393e, "Lenovo ThinkBook 14 G8+ IPH", ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK), - HDA_CODEC_QUIRK(0x17aa, 0x394c, "Lenovo Yoga Slim 7 14AGP11", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), - SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), -- SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -+ SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), - SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK), -- SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -+ SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK), -@@ -8027,7 +8151,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x508b, "Thinkpad X12 Gen 1", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), -- SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -+ SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), -@@ -8041,9 +8165,14 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1854, 0x0489, "LG gram 16 (16Z90R-A)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), - SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS), - SND_PCI_QUIRK(0x1854, 0x0490, "LG Gram Style 14 (14Z90RS)", ALC298_FIXUP_LG_GRAM_STYLE_14), -+ SND_PCI_QUIRK(0x1854, 0x0554, "LG gram 16 (16Z90TR)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS), - SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS), - SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC), -+ SND_PCI_QUIRK(0x1a58, 0x2023, "Razer Blade 16 (2025)", -+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS), -+ SND_PCI_QUIRK(0x1a58, 0x300e, "Razer Blade 16 (2025)", -+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS), - SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20), - SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI), - SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101), -@@ -8078,13 +8207,17 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), - SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK), - SND_PCI_QUIRK(0x1e50, 0x7007, "Positivo DN50E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -+ SND_PCI_QUIRK(0x1e50, 0x7036, "Acer Gadget E10 ETBook", ALC233_FIXUP_WUJIE_SPEAKERS), - SND_PCI_QUIRK(0x1e50, 0x7038, "Positivo DN140", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1ee7, 0x2081, "HONOR MRB-XXX M1020", ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO), -+ SND_PCI_QUIRK(0x1f4c, 0xb020, "Minisforum AI X1 Pro", -+ ALC245_FIXUP_MINISFORUM_JACK_DETECT), - SND_PCI_QUIRK(0x1f4c, 0xe001, "Minisforum V3 (SE)", ALC245_FIXUP_BASS_HP_DAC), - SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x2039, 0x0001, "Inspur S14-G1", ALC295_FIXUP_CHROME_BOOK), -+ SND_PCI_QUIRK(0x2145, 0x0001, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER), - SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13), - SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO), -@@ -8095,6 +8228,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX), - SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME), - SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK), -+ SND_PCI_QUIRK(0x2782, 0xa128, "Positivo N15RPE-S", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x2782, 0xa212, "Lunnen Ground 14", ALC269VC_FIXUP_LUNNEN_GROUND_14), - SND_PCI_QUIRK(0x7017, 0x2014, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER), - SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), -@@ -8168,6 +8302,7 @@ static const struct hda_quirk alc269_fixup_vendor_tbl[] = { - SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI), - SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED), -+ SND_PCI_QUIRK_VENDOR(0x2145, "Star Labs", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - {} - }; - -@@ -8307,6 +8442,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { - {.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"}, - {.id = ALC245_FIXUP_BASS_HP_DAC, .name = "alc245-fixup-bass-hp-dac"}, - {.id = ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, .name = "alc256-honor-mrb-xxx-m1020-audio"}, -+ {.id = ALC287_FIXUP_LENOVO_LEGION_AW88399, .name = "alc287-lenovo-legion-aw88399"}, - {} - }; - #define ALC225_STANDARD_PINS \ -@@ -8912,6 +9048,7 @@ static int alc269_probe(struct hda_codec *codec, const struct hda_device_id *id) - spec->init_hook = alc256_init; - spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ - if (codec->core.vendor_id == 0x10ec0236 && -+ codec->bus->pci && - codec->bus->pci->vendor != PCI_VENDOR_ID_AMD) - spec->en_3kpull_low = false; - break; -diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c ---- a/sound/hda/codecs/realtek/alc662.c -+++ b/sound/hda/codecs/realtek/alc662.c -@@ -325,6 +325,7 @@ enum { - ALC897_FIXUP_UNIS_H3C_X500S, - ALC897_FIXUP_HEADSET_MIC_PIN3, - ALC662_FIXUP_CSL_GPIO, -+ ALC897_FIXUP_BEELINK_SER6_AMP, - }; - - static const struct hda_fixup alc662_fixups[] = { -@@ -782,6 +783,10 @@ static const struct hda_fixup alc662_fixups[] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc662_fixup_csl_amp, - }, -+ [ALC897_FIXUP_BEELINK_SER6_AMP] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc_fixup_gpio4, -+ }, - }; - - static const struct hda_quirk alc662_fixup_tbl[] = { -@@ -853,6 +858,7 @@ static const struct hda_quirk alc662_fixup_tbl[] = { - SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), - SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB), - SND_PCI_QUIRK(0x1e63, 0x6d9a, "F+ FLAPTOP r", ALC897_FIXUP_HP_HSMIC_VERB), -+ SND_PCI_QUIRK(0x1f66, 0x0202, "Beelink SER6 Max 6900", ALC897_FIXUP_BEELINK_SER6_AMP), - - #if 0 - /* Below is a quirk table taken from the old code. -diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig ---- a/sound/hda/codecs/side-codecs/Kconfig -+++ b/sound/hda/codecs/side-codecs/Kconfig -@@ -13,6 +13,24 @@ config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST - Documentation/dev-tools/kunit/. - If in doubt, say "N". - -+config SND_HDA_SCODEC_AW88399 -+ tristate -+ select SND_HDA_GENERIC -+ -+config SND_HDA_SCODEC_AW88399_I2C -+ tristate "Build AW88399 HD-audio side codec support for I2C Bus" -+ depends on I2C -+ depends on ACPI -+ depends on SND_SOC -+ select SND_HDA_SCODEC_AW88399 -+ select SND_SOC_AW88399_LIB -+ help -+ Say Y or M here to include AW88399 I2C HD-audio side codec support -+ in snd-hda-intel driver, such as ALC287. -+ -+comment "Set to Y if you want auto-loading the side codec driver" -+ depends on SND_HDA=y && SND_HDA_SCODEC_AW88399_I2C=m -+ - config SND_HDA_SCODEC_CS35L41 - tristate - select SND_HDA_GENERIC -diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile ---- a/sound/hda/codecs/side-codecs/Makefile -+++ b/sound/hda/codecs/side-codecs/Makefile -@@ -3,6 +3,8 @@ subdir-ccflags-y += -I$(src)/../../common - - snd-hda-cirrus-scodec-y := cirrus_scodec.o - snd-hda-cirrus-scodec-test-y := cirrus_scodec_test.o -+snd-hda-scodec-aw88399-y := aw88399_hda.o -+snd-hda-scodec-aw88399-i2c-y := aw88399_hda_i2c.o - snd-hda-scodec-cs35l41-y := cs35l41_hda.o cs35l41_hda_property.o - snd-hda-scodec-cs35l41-i2c-y := cs35l41_hda_i2c.o - snd-hda-scodec-cs35l41-spi-y := cs35l41_hda_spi.o -@@ -16,6 +18,8 @@ snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o - - obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o - obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o -+obj-$(CONFIG_SND_HDA_SCODEC_AW88399) += snd-hda-scodec-aw88399.o -+obj-$(CONFIG_SND_HDA_SCODEC_AW88399_I2C) += snd-hda-scodec-aw88399-i2c.o - obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o - obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o - obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o -diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.c b/sound/hda/codecs/side-codecs/aw88399_hda.c -new file mode 100644 ---- /dev/null -+++ b/sound/hda/codecs/side-codecs/aw88399_hda.c -@@ -0,0 +1,373 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+// -+// AW88399 HDA side codec driver -+// -+// Based on cs35l41_hda.c and aw88399.c -+// -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "../generic.h" -+#include "hda_component.h" -+#include "aw88399_hda.h" -+ -+#define AW88399_HDA_I2C_BASE_ADDR 0x34 -+ -+static void aw88399_hda_playback_hook(struct device *dev, int action) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ struct aw88399 *core = aw88399->core; -+ int ret = 0; -+ -+ dev_dbg(aw88399->dev, "Playback action: %d\n", action); -+ -+ switch (action) { -+ case HDA_GEN_PCM_ACT_OPEN: -+ pm_runtime_get_sync(dev); -+ aw88399->playing = true; -+ break; -+ case HDA_GEN_PCM_ACT_PREPARE: -+ if (core) -+ aw88399_start(core, AW88399_SYNC_START); -+ break; -+ case HDA_GEN_PCM_ACT_CLEANUP: -+ if (aw88399->aw_dev) -+ ret = aw88399_stop(aw88399->aw_dev); -+ if (ret) -+ dev_err(aw88399->dev, "Failed to stop amplifier: %d\n", ret); -+ break; -+ case HDA_GEN_PCM_ACT_CLOSE: -+ if (aw88399->aw_dev) -+ aw88399_stop(aw88399->aw_dev); -+ aw88399->playing = false; -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); -+ break; -+ default: -+ dev_warn(aw88399->dev, "Unsupported action: %d\n", action); -+ break; -+ } -+} -+ -+static int aw88399_hda_bind(struct device *dev, struct device *master, void *master_data) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ struct hda_component_parent *parent = master_data; -+ struct hda_component *comp; -+ -+ comp = hda_component_from_index(parent, aw88399->index); -+ if (!comp) -+ return -EINVAL; -+ -+ if (comp->dev) -+ return -EBUSY; -+ -+ comp->dev = dev; -+ -+ strscpy(comp->name, dev_name(dev), sizeof(comp->name)); -+ -+ comp->playback_hook = aw88399_hda_playback_hook; -+ -+ dev_info(aw88399->dev, -+ "AW88399 Bound - SSID: %s, channel: %d\n", -+ aw88399->acpi_subsystem_id, aw88399->channel); -+ -+ return 0; -+} -+ -+static void aw88399_hda_unbind(struct device *dev, struct device *master, void *master_data) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ struct hda_component_parent *parent = master_data; -+ struct hda_component *comp; -+ -+ comp = hda_component_from_index(parent, aw88399->index); -+ if (comp && (comp->dev == dev)) -+ memset(comp, 0, sizeof(*comp)); -+ -+ dev_dbg(aw88399->dev, "Unbound from HDA codec\n"); -+} -+ -+static const struct component_ops aw88399_hda_comp_ops = { -+ .bind = aw88399_hda_bind, -+ .unbind = aw88399_hda_unbind, -+}; -+ -+static int aw88399_hda_index_from_i2c(struct aw88399_hda *aw88399) -+{ -+ return to_i2c_client(aw88399->dev)->addr - AW88399_HDA_I2C_BASE_ADDR; -+} -+ -+static int aw88399_hda_init(struct aw88399_hda *aw88399) -+{ -+ struct device *dev = aw88399->dev; -+ struct i2c_client *i2c = to_i2c_client(dev); -+ struct aw88399 *core; -+ int ret; -+ -+ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); -+ if (!core) -+ return -ENOMEM; -+ -+ mutex_init(&core->lock); -+ core->reset_gpio = aw88399->reset_gpio; -+ core->regmap = aw88399->regmap; -+ core->bsts_unreliable = aw88399->bsts_unreliable; -+ -+ aw88399_hw_reset(core); -+ -+ ret = aw88399_init(core, i2c, aw88399->regmap); -+ if (ret) -+ return ret; -+ -+ /* Set channel BEFORE loading firmware so ACF parser sees correct value */ -+ if (core->aw_pa) -+ aw88399_dev_set_channel(core, aw88399->channel); -+ -+ ret = aw88399_request_firmware_file(core); -+ if (ret) -+ return ret; -+ -+ aw88399->core = core; -+ aw88399->aw_dev = core->aw_pa; -+ -+ return 0; -+} -+ -+static int aw88399_swap_channels(struct aw88399_hda *aw88399) -+{ -+ /* -+ * Certain Lenovo Legion laptops have their -+ * I2C wiring reversed: 0x34 is physically the right speaker, -+ * 0x35 is the left. Swap channels to correct L/R assignment. -+ * This is a model-specific hardware wiring issue, not a driver bug. -+ */ -+ aw88399->channel = 1 - aw88399->channel; -+ dev_dbg(aw88399->dev, -+ "Channel swap applied: index %d -> channel %d\n", -+ aw88399->index, aw88399->channel); -+ return 0; -+} -+ -+static int aw88399_skip_bsts_check(struct aw88399_hda *aw88399) -+{ -+ /* -+ * BSTS (boost-finished) status bit does not reliably report on -+ * some hardware. On certain Lenovo Legion laptops, both amps -+ * report BSTS=0 (boost not finished) during normal playback -+ * despite clean audio output. Skip BSTS in the startup status -+ * check to avoid false init failures. -+ */ -+ aw88399->bsts_unreliable = true; -+ dev_dbg(aw88399->dev, "BSTS status check disabled\n"); -+ return 0; -+} -+ -+static int aw88399_apply_legion_quirks(struct aw88399_hda *aw88399) -+{ -+ aw88399_swap_channels(aw88399); -+ aw88399_skip_bsts_check(aw88399); -+ return 0; -+} -+ -+struct aw88399_prop_model { -+ const char *ssid; -+ int (*apply_prop)(struct aw88399_hda *aw88399); -+}; -+ -+static const struct aw88399_prop_model aw88399_prop_model_table[] = { -+ { "17AA3906", aw88399_apply_legion_quirks }, -+ { "17AA3907", aw88399_apply_legion_quirks }, -+ { "17AA3927", aw88399_apply_legion_quirks }, -+ { "17AA3928", aw88399_apply_legion_quirks }, -+ { "17AA3936", aw88399_apply_legion_quirks }, -+ { "17AA3937", aw88399_apply_legion_quirks }, -+ { "17AA3938", aw88399_apply_legion_quirks }, -+ { "17AA3939", aw88399_apply_legion_quirks }, -+ { } -+}; -+ -+static int aw88399_hda_acpi_probe(struct aw88399_hda *aw88399) -+{ -+ struct acpi_device *adev; -+ const char *sub; -+ const struct aw88399_prop_model *model; -+ -+ aw88399->index = aw88399_hda_index_from_i2c(aw88399); -+ aw88399->channel = aw88399->index; -+ aw88399->acpi_subsystem_id = NULL; -+ -+ adev = acpi_dev_get_first_match_dev("AWDZ8399", NULL, -1); -+ if (!adev) { -+ dev_err(aw88399->dev, "Failed to find an ACPI device for AWDZ8399\n"); -+ return -ENODEV; -+ } -+ -+ struct device *physdev __free(put_device) = -+ get_device(acpi_get_first_physical_node(adev)); -+ acpi_dev_put(adev); -+ if (!physdev) -+ return -ENODEV; -+ -+ sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); -+ if (IS_ERR_OR_NULL(sub)) -+ return 0; -+ -+ aw88399->acpi_subsystem_id = devm_kstrdup(aw88399->dev, sub, GFP_KERNEL); -+ kfree(sub); -+ if (!aw88399->acpi_subsystem_id) -+ return -ENOMEM; -+ -+ for (model = aw88399_prop_model_table; model->ssid; model++) { -+ if (!strcasecmp(model->ssid, aw88399->acpi_subsystem_id)) { -+ dev_info(aw88399->dev, -+ "Applying properties for SSID %s\n", -+ aw88399->acpi_subsystem_id); -+ return model->apply_prop(aw88399); -+ } -+ } -+ -+ return 0; -+} -+ -+int aw88399_hda_probe(struct device *dev, struct regmap *regmap) -+{ -+ struct aw88399_hda *aw88399; -+ int ret; -+ -+ aw88399 = devm_kzalloc(dev, sizeof(*aw88399), GFP_KERNEL); -+ if (!aw88399) -+ return -ENOMEM; -+ -+ if (IS_ERR(regmap)) -+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to obtain regmap\n"); -+ -+ aw88399->dev = dev; -+ aw88399->regmap = regmap; -+ dev_set_drvdata(dev, aw88399); -+ -+ aw88399->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); -+ if (IS_ERR(aw88399->reset_gpio)) -+ return dev_err_probe(dev, PTR_ERR(aw88399->reset_gpio), -+ "Failed to get reset GPIO\n"); -+ -+ ret = aw88399_hda_acpi_probe(aw88399); -+ if (ret) -+ return dev_err_probe(dev, ret, "ACPI probe failed\n"); -+ -+ ret = aw88399_hda_init(aw88399); -+ if (ret) -+ return dev_err_probe(dev, ret, "Chip initialization failed\n"); -+ -+ /* Enable runtime PM */ -+ pm_runtime_set_autosuspend_delay(dev, 3000); -+ pm_runtime_use_autosuspend(dev); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ -+ ret = component_add(dev, &aw88399_hda_comp_ops); -+ if (ret) { -+ pm_runtime_disable(dev); -+ return dev_err_probe(dev, ret, "Failed to register component\n"); -+ } -+ -+ dev_info(dev, "AW88399 HDA side codec registered successfully\n"); -+ -+ return 0; -+} -+EXPORT_SYMBOL_NS_GPL(aw88399_hda_probe, "SND_HDA_SCODEC_AW88399"); -+ -+void aw88399_hda_remove(struct device *dev) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ -+ pm_runtime_disable(dev); -+ -+ if (aw88399->aw_dev) -+ aw88399_stop(aw88399->aw_dev); -+ -+ component_del(dev, &aw88399_hda_comp_ops); -+ -+ dev_dbg(aw88399->dev, "AW88399 HDA side codec removed\n"); -+} -+EXPORT_SYMBOL_NS_GPL(aw88399_hda_remove, "SND_HDA_SCODEC_AW88399"); -+ -+static int aw88399_hda_runtime_suspend(struct device *dev) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ -+ dev_dbg(aw88399->dev, "Runtime suspend\n"); -+ -+ if (aw88399->aw_dev && aw88399->playing) -+ aw88399_stop(aw88399->aw_dev); -+ -+ return 0; -+} -+ -+static int aw88399_hda_runtime_resume(struct device *dev) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ -+ dev_dbg(aw88399->dev, "Runtime resume\n"); -+ -+ if (aw88399->core && aw88399->aw_dev && aw88399->playing) -+ aw88399_start(aw88399->core, AW88399_SYNC_START); -+ -+ return 0; -+} -+ -+static int aw88399_hda_system_suspend(struct device *dev) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ int ret; -+ -+ dev_dbg(aw88399->dev, "System suspend\n"); -+ -+ if (aw88399->aw_dev && aw88399->playing) -+ aw88399_stop(aw88399->aw_dev); -+ -+ if (aw88399->core) -+ aw88399->core->fw_needs_reload = true; -+ -+ ret = pm_runtime_force_suspend(dev); -+ if (ret) -+ dev_err(aw88399->dev, "Runtime force suspend failed: %d\n", ret); -+ -+ return ret; -+} -+ -+static int aw88399_hda_system_resume(struct device *dev) -+{ -+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev); -+ int ret; -+ -+ dev_dbg(aw88399->dev, "System resume\n"); -+ -+ if (aw88399->aw_dev) -+ aw88399_hw_reset(aw88399->core); -+ -+ ret = pm_runtime_force_resume(dev); -+ if (ret) -+ dev_err(aw88399->dev, "Runtime force resume failed: %d\n", ret); -+ -+ return ret; -+} -+ -+const struct dev_pm_ops aw88399_hda_pm_ops = { -+ RUNTIME_PM_OPS(aw88399_hda_runtime_suspend, aw88399_hda_runtime_resume, NULL) -+ SYSTEM_SLEEP_PM_OPS(aw88399_hda_system_suspend, aw88399_hda_system_resume) -+}; -+EXPORT_SYMBOL_NS_GPL(aw88399_hda_pm_ops, "SND_HDA_SCODEC_AW88399"); -+ -+MODULE_DESCRIPTION("AW88399 HDA driver"); -+MODULE_AUTHOR("Yakov Till "); -+MODULE_AUTHOR("Marco Giunta "); -+MODULE_LICENSE("GPL"); -+MODULE_FIRMWARE("aw88399_acf.bin"); -diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.h b/sound/hda/codecs/side-codecs/aw88399_hda.h -new file mode 100644 ---- /dev/null -+++ b/sound/hda/codecs/side-codecs/aw88399_hda.h -@@ -0,0 +1,36 @@ -+/* SPDX-License-Identifier: GPL-2.0-only -+ * -+ * AW88399 HDA side codec driver -+ */ -+ -+#ifndef __AW88399_HDA_H__ -+#define __AW88399_HDA_H__ -+ -+#include -+#include -+#include -+ -+struct aw88399; -+struct aw_device; -+ -+struct aw88399_hda { -+ struct device *dev; -+ struct regmap *regmap; -+ struct gpio_desc *reset_gpio; -+ struct aw_device *aw_dev; -+ struct aw88399 *core; -+ bool bsts_unreliable; -+ -+ const char *acpi_subsystem_id; -+ int index; -+ int channel; -+ -+ bool playing; -+}; -+ -+int aw88399_hda_probe(struct device *dev, struct regmap *regmap); -+void aw88399_hda_remove(struct device *dev); -+ -+extern const struct dev_pm_ops aw88399_hda_pm_ops; -+ -+#endif /* __AW88399_HDA_H__ */ -diff --git a/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c -new file mode 100644 ---- /dev/null -+++ b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c -@@ -0,0 +1,54 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+// -+// AW88399 HDA I2C driver -+// -+// Based on cs35l41_hda_i2c.c -+// -+ -+#include -+#include -+#include -+ -+#include "aw88399_hda.h" -+ -+static int aw88399_hda_i2c_probe(struct i2c_client *clt) -+{ -+ if (!strstr(dev_name(&clt->dev), "AWDZ8399")) -+ return -ENODEV; -+ -+ return aw88399_hda_probe(&clt->dev, -+ devm_regmap_init_i2c(clt, &aw88399_remap_config)); -+} -+ -+static void aw88399_hda_i2c_remove(struct i2c_client *clt) -+{ -+ aw88399_hda_remove(&clt->dev); -+} -+ -+static const struct i2c_device_id aw88399_hda_i2c_id[] = { -+ { .name = "aw88399-hda" }, -+ { } -+}; -+ -+static const struct acpi_device_id aw88399_acpi_hda_match[] = { -+ { "AWDZ8399", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, aw88399_acpi_hda_match); -+ -+static struct i2c_driver aw88399_hda_i2c_driver = { -+ .driver = { -+ .name = "aw88399-hda", -+ .acpi_match_table = aw88399_acpi_hda_match, -+ .pm = &aw88399_hda_pm_ops, -+ }, -+ .probe = aw88399_hda_i2c_probe, -+ .remove = aw88399_hda_i2c_remove, -+ .id_table = aw88399_hda_i2c_id, -+}; -+module_i2c_driver(aw88399_hda_i2c_driver); -+ -+MODULE_DESCRIPTION("HDA AW88399 I2C driver"); -+MODULE_IMPORT_NS("SND_HDA_SCODEC_AW88399"); -+MODULE_AUTHOR("Yakov Till "); -+MODULE_LICENSE("GPL"); -diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c ---- a/sound/hda/codecs/side-codecs/cs35l41_hda.c -+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c -@@ -170,6 +170,7 @@ static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41, - char *s, c; - int ret = 0; - -+ *firmware = NULL; - if (spkid > -1 && ssid && amp_name) - *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART, - dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type], -@@ -528,8 +529,8 @@ static int cs35l41_read_tuning_params(struct cs35l41_hda *cs35l41, const struct - - static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_filename) - { -- const struct firmware *tuning_param_file = NULL; -- char *tuning_param_filename = NULL; -+ const struct firmware *tuning_param_file __free(firmware) = NULL; -+ char *tuning_param_filename __free(kfree) = NULL; - int ret; - - ret = cs35l41_request_tuning_param_file(cs35l41, tuning_filename, &tuning_param_file, -@@ -548,19 +549,16 @@ static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_ - cs35l41_set_default_tuning_params(cs35l41); - } - -- release_firmware(tuning_param_file); -- kfree(tuning_param_filename); -- - return ret; - } - - static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41) - { -- const struct firmware *coeff_firmware = NULL; -- const struct firmware *wmfw_firmware = NULL; -+ const struct firmware *coeff_firmware __free(firmware) = NULL; -+ const struct firmware *wmfw_firmware __free(firmware) = NULL; - struct cs_dsp *dsp = &cs35l41->cs_dsp; -- char *coeff_filename = NULL; -- char *wmfw_filename = NULL; -+ char *coeff_filename __free(kfree) = NULL; -+ char *wmfw_filename __free(kfree) = NULL; - int ret; - - if (!cs35l41->halo_initialized) { -@@ -592,20 +590,13 @@ static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41) - - ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename, - cs35l41_hda_fw_ids[cs35l41->firmware_type]); -- if (ret) -- goto err; -+ if (ret) { -+ cs35l41_set_default_tuning_params(cs35l41); -+ return ret; -+ } - - cs35l41_hda_apply_calibration(cs35l41); -- --err: -- if (ret) -- cs35l41_set_default_tuning_params(cs35l41); -- release_firmware(wmfw_firmware); -- release_firmware(coeff_firmware); -- kfree(wmfw_filename); -- kfree(coeff_filename); -- -- return ret; -+ return 0; - } - - static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41) -@@ -1924,7 +1915,6 @@ int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, - static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) - { - struct acpi_device *adev; -- struct device *physdev; - struct spi_device *spi; - const char *sub; - int ret; -@@ -1936,7 +1926,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i - } - - cs35l41->dacpi = adev; -- physdev = get_device(acpi_get_first_physical_node(adev)); -+ struct device *physdev __free(put_device) = -+ get_device(acpi_get_first_physical_node(adev)); - if (!physdev) { - acpi_dev_put(adev); - return -ENODEV; -@@ -1954,13 +1945,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i - } - - ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id); -- if (ret) { -- put_device(physdev); -+ if (ret) - return ret; -- } - out: -- put_device(physdev); -- - cs35l41->bypass_fw = false; - if (cs35l41->control_bus == SPI) { - spi = to_spi_device(cs35l41->dev); -diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c ---- a/sound/hda/codecs/side-codecs/cs35l56_hda.c -+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c -@@ -527,18 +527,6 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56, - base_name, NULL, NULL, "bin"); - } - --static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware, -- char *wmfw_filename, -- const struct firmware *coeff_firmware, -- char *coeff_filename) --{ -- release_firmware(wmfw_firmware); -- kfree(wmfw_filename); -- -- release_firmware(coeff_firmware); -- kfree(coeff_filename); --} -- - static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56) - { - int ret; -@@ -561,10 +549,10 @@ static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56) - - static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) - { -- const struct firmware *coeff_firmware = NULL; -- const struct firmware *wmfw_firmware = NULL; -- char *coeff_filename = NULL; -- char *wmfw_filename = NULL; -+ const struct firmware *coeff_firmware __free(firmware) = NULL; -+ const struct firmware *wmfw_firmware __free(firmware) = NULL; -+ char *coeff_filename __free(kfree) = NULL; -+ char *wmfw_filename __free(kfree) = NULL; - unsigned int preloaded_fw_ver; - bool firmware_missing; - int ret; -@@ -606,14 +594,14 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) - if (firmware_missing) { - if (!wmfw_firmware) { - dev_err(cs35l56->base.dev, ".%s file required but not found\n", "wmfw"); -- goto err_fw_release; -+ return; - } else if (!coeff_firmware) { - dev_err(cs35l56->base.dev, ".%s file required but not found\n", "bin"); -- goto err_fw_release; -+ return; - } - } - -- mutex_lock(&cs35l56->base.irq_lock); -+ guard(mutex)(&cs35l56->base.irq_lock); - - /* - * If the firmware hasn't been patched it must be shutdown before -@@ -624,14 +612,14 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) - if (firmware_missing && (wmfw_firmware || coeff_firmware)) { - ret = cs35l56_firmware_shutdown(&cs35l56->base); - if (ret) -- goto err; -+ return; - } - - ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename, - coeff_firmware, coeff_filename, "misc"); - if (ret) { - dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret); -- goto err; -+ return; - } - - if (wmfw_filename) -@@ -679,11 +667,6 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56) - err_powered_up: - if (!cs35l56->base.fw_patched) - cs_dsp_power_down(&cs35l56->cs_dsp); --err: -- mutex_unlock(&cs35l56->base.irq_lock); --err_fw_release: -- cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename, -- coeff_firmware, coeff_filename); - } - - static void cs35l56_hda_dsp_work(struct work_struct *work) -diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c ---- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c -+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c -@@ -88,7 +88,6 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) - { - struct gpio_desc *speaker_id; - struct acpi_device *adev; -- struct device *physdev; - LIST_HEAD(resources); - const char *sub; - uint32_t subid; -@@ -101,7 +100,8 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) - return -ENODEV; - } - -- physdev = get_device(acpi_get_first_physical_node(adev)); -+ struct device *physdev __free(put_device) = -+ get_device(acpi_get_first_physical_node(adev)); - ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); - if (ret < 0) { - dev_err(p->dev, "Failed to get ACPI resource.\n"); -@@ -151,14 +151,12 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) - end_2563: - acpi_dev_free_resource_list(&resources); - strscpy(p->dev_name, hid, sizeof(p->dev_name)); -- put_device(physdev); - acpi_dev_put(adev); - - return 0; - - err: - dev_err(p->dev, "read acpi error, ret: %d\n", ret); -- put_device(physdev); - acpi_dev_put(adev); - - return ret; -diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c ---- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c -+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c -@@ -328,7 +328,6 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda, - { - struct tasdevice_priv *p = tas_hda->priv; - struct acpi_device *adev; -- struct device *physdev; - u32 values[HDA_MAX_COMPONENTS]; - const char *property; - size_t nval; -@@ -341,7 +340,9 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda, - } - - strscpy(p->dev_name, hid, sizeof(p->dev_name)); -- physdev = get_device(acpi_get_first_physical_node(adev)); -+ -+ struct device *physdev __free(put_device) = -+ get_device(acpi_get_first_physical_node(adev)); - acpi_dev_put(adev); - if (!physdev) - return -ENODEV; -@@ -381,13 +382,11 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda, - goto err; - } - } -- put_device(physdev); - - return 0; -+ - err: - dev_err(p->dev, "read acpi error, ret: %d\n", ret); -- put_device(physdev); -- - return ret; - } - -diff --git a/sound/hda/common/auto_parser.c b/sound/hda/common/auto_parser.c ---- a/sound/hda/common/auto_parser.c -+++ b/sound/hda/common/auto_parser.c -@@ -601,9 +601,9 @@ static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) - return -1; - } - --/* get a unique suffix or an index number */ -+/* get a unique suffix */ - static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, -- int num_pins, int *indexp) -+ int num_pins) - { - static const char * const channel_sfx[] = { - " Front", " Surround", " CLFE", " Side" -@@ -615,11 +615,8 @@ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, - return NULL; - if (num_pins == 1) - return ""; -- if (num_pins > ARRAY_SIZE(channel_sfx)) { -- if (indexp) -- *indexp = i; -+ if (num_pins > ARRAY_SIZE(channel_sfx)) - return ""; -- } - return channel_sfx[i]; - } - -@@ -638,27 +635,9 @@ static const char *check_output_pfx(struct hda_codec *codec, hda_nid_t nid) - return ""; - } - --static int get_hp_label_index(struct hda_codec *codec, hda_nid_t nid, -- const hda_nid_t *pins, int num_pins) --{ -- int i, j, idx = 0; -- -- const char *pfx = check_output_pfx(codec, nid); -- -- i = find_idx_in_nid_list(nid, pins, num_pins); -- if (i < 0) -- return -1; -- for (j = 0; j < i; j++) -- if (pfx == check_output_pfx(codec, pins[j])) -- idx++; -- -- return idx; --} -- - static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg, -- const char *name, char *label, int maxlen, -- int *indexp) -+ const char *name, char *label, int maxlen) - { - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int attr = snd_hda_get_input_pin_attr(def_conf); -@@ -671,19 +650,11 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, - - if (cfg) { - /* try to give a unique suffix if needed */ -- sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs, -- indexp); -+ sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs); -+ if (!sfx) -+ sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs); - if (!sfx) -- sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs, -- indexp); -- if (!sfx) { -- /* don't add channel suffix for Headphone controls */ -- int idx = get_hp_label_index(codec, nid, cfg->hp_pins, -- cfg->hp_outs); -- if (idx >= 0 && indexp) -- *indexp = idx; - sfx = ""; -- } - } - snprintf(label, maxlen, "%s%s%s", pfx, name, sfx); - return 1; -@@ -699,7 +670,6 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, - * @cfg: the parsed pin configuration - * @label: the string buffer to store - * @maxlen: the max length of string buffer (including termination) -- * @indexp: the pointer to return the index number (for multiple ctls) - * - * Get a label for the given pin. This function works for both input and - * output pins. When @cfg is given as non-NULL, the function tries to get -@@ -708,47 +678,33 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, - * This function tries to give a unique label string for the pin as much as - * possible. For example, when the multiple line-outs are present, it adds - * the channel suffix like "Front", "Surround", etc (only when @cfg is given). -- * If no unique name with a suffix is available and @indexp is non-NULL, the -- * index number is stored in the pointer. - */ - int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg, -- char *label, int maxlen, int *indexp) -+ char *label, int maxlen) - { - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); - const char *name = NULL; - int i; - bool hdmi; - -- if (indexp) -- *indexp = 0; - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - return 0; - - switch (get_defcfg_device(def_conf)) { - case AC_JACK_LINE_OUT: - return fill_audio_out_name(codec, nid, cfg, "Line Out", -- label, maxlen, indexp); -+ label, maxlen); - case AC_JACK_SPEAKER: - return fill_audio_out_name(codec, nid, cfg, "Speaker", -- label, maxlen, indexp); -+ label, maxlen); - case AC_JACK_HP_OUT: - return fill_audio_out_name(codec, nid, cfg, "Headphone", -- label, maxlen, indexp); -+ label, maxlen); - case AC_JACK_SPDIF_OUT: - case AC_JACK_DIG_OTHER_OUT: - hdmi = is_hdmi_cfg(def_conf); - name = hdmi ? "HDMI" : "SPDIF"; -- if (cfg && indexp) -- for (i = 0; i < cfg->dig_outs; i++) { -- hda_nid_t pin = cfg->dig_out_pins[i]; -- unsigned int c; -- if (pin == nid) -- break; -- c = snd_hda_codec_get_pincfg(codec, pin); -- if (hdmi == is_hdmi_cfg(c)) -- (*indexp)++; -- } - break; - default: - if (cfg) { -diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c ---- a/sound/hda/common/codec.c -+++ b/sound/hda/common/codec.c -@@ -39,6 +39,12 @@ static int call_exec_verb(struct hda_bus *bus, struct hda_codec *codec, - int err; - - CLASS(snd_hda_power_pm, pm)(codec); -+ if (pm.err < 0 && !bus->core.chip_init) { -+ codec_warn(codec, -+ "Failed to send cmd 0x%x ret=[%d], hda control stopped\n", -+ cmd, pm.err); -+ return pm.err; -+ } - guard(mutex)(&bus->core.cmd_mutex); - if (flags & HDA_RW_NO_RESPONSE_FALLBACK) - bus->no_response_fallback = 1; -@@ -2969,8 +2975,11 @@ static void hda_codec_pm_complete(struct device *dev) - dev->power.power_state = PMSG_RESUME; - - if (pm_runtime_suspended(dev) && (codec->jackpoll_interval || -- hda_codec_need_resume(codec) || codec->forced_resume)) -+ hda_codec_need_resume(codec) || codec->forced_resume || -+ codec->acomp_requested_resume)) { -+ codec->acomp_requested_resume = 0; - pm_request_resume(dev); -+ } - } - - static int hda_codec_pm_suspend(struct device *dev) -@@ -3372,7 +3381,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, - for (; knew->name; knew++) { - struct snd_kcontrol *kctl; - int addr = 0, idx = 0; -- if (knew->iface == (__force snd_ctl_elem_iface_t)-1) -+ if (knew->iface == -1) - continue; /* skip this codec private value */ - for (;;) { - kctl = snd_ctl_new1(knew, codec); -diff --git a/sound/hda/common/hda_auto_parser.h b/sound/hda/common/hda_auto_parser.h ---- a/sound/hda/common/hda_auto_parser.h -+++ b/sound/hda/common/hda_auto_parser.h -@@ -46,7 +46,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, - int input); - int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg, -- char *label, int maxlen, int *indexp); -+ char *label, int maxlen); - - enum { - INPUT_PIN_ATTR_UNUSED, /* pin not connected */ -diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h ---- a/sound/hda/common/hda_local.h -+++ b/sound/hda/common/hda_local.h -@@ -723,4 +723,11 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable); - #define codec_dbg(codec, fmt, args...) \ - dev_dbg(hda_codec_dev(codec), fmt, ##args) - -+/* append a suffix string safely; equivalent with strlcat() */ -+static inline void hda_append_suffix(char *str, const char *suffix, size_t size) -+{ -+ size_t len = strnlen(str, size); -+ strscpy(str + len, suffix, size - len); -+} -+ - #endif /* __SOUND_HDA_LOCAL_H */ -diff --git a/sound/hda/common/jack.c b/sound/hda/common/jack.c ---- a/sound/hda/common/jack.c -+++ b/sound/hda/common/jack.c -@@ -612,10 +612,10 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, - if (base_name) - strscpy(name, base_name, sizeof(name)); - else -- snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); -+ snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name)); - if (phantom_jack) - /* Example final name: "Internal Mic Phantom Jack" */ -- strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); -+ hda_append_suffix(name, " Phantom", sizeof(name)); - err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); - if (err < 0) - return err; -diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c ---- a/sound/hda/controllers/intel.c -+++ b/sound/hda/controllers/intel.c -@@ -100,6 +100,8 @@ enum { - #define ATIHDMI_NUM_CAPTURE 0 - #define ATIHDMI_NUM_PLAYBACK 8 - -+/* Hygon HD Audio controller */ -+#define PCI_DEVICE_ID_HYGON_18H_M05H_HDA 0x14a9 - - static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; - static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -@@ -241,6 +243,7 @@ enum { - AZX_DRIVER_ZHAOXIN, - AZX_DRIVER_ZHAOXINHDMI, - AZX_DRIVER_LOONGSON, -+ AZX_DRIVER_HYGON, - AZX_DRIVER_GENERIC, - AZX_NUM_DRIVERS, /* keep this as last entry */ - }; -@@ -360,6 +363,7 @@ static const char * const driver_short_names[] = { - [AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin", - [AZX_DRIVER_ZHAOXINHDMI] = "HDA Zhaoxin HDMI", - [AZX_DRIVER_LOONGSON] = "HDA Loongson", -+ [AZX_DRIVER_HYGON] = "HDA Hygon", - [AZX_DRIVER_GENERIC] = "HD-Audio Generic", - }; - -@@ -1926,6 +1930,10 @@ static int azx_first_init(struct azx *chip) - if (chip->driver_type == AZX_DRIVER_ZHAOXINHDMI) - bus->polling_mode = 1; - -+ if (chip->driver_type == AZX_DRIVER_HYGON && -+ chip->pci->device == PCI_DEVICE_ID_HYGON_18H_M05H_HDA) -+ bus->access_sdnctl_in_dword = 1; -+ - bus->remap_addr = pcim_iomap_region(pci, 0, "ICH HD audio"); - if (IS_ERR(bus->remap_addr)) - return PTR_ERR(bus->remap_addr); -@@ -2189,6 +2197,15 @@ static int azx_probe(struct pci_dev *pci, - dev_warn(&pci->dev, "dmic_detect option is deprecated, pass snd-intel-dspcfg.dsp_driver=1 option instead\n"); - } - -+ /* A sanity check against wild device binding; -+ * here the range 0x200 is enough for the registers used at probe, -+ * but it doesn't mean covering all HD-audio registers -+ */ -+ if (pci_resource_len(pci, 0) < 0x200) { -+ dev_err(&pci->dev, "Too small PCI BAR0\n"); -+ return -EINVAL; -+ } -+ - err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, - 0, &card); - if (err < 0) { -@@ -2381,7 +2398,7 @@ static int azx_probe_continue(struct azx *chip) - - #ifdef CONFIG_SND_HDA_PATCH_LOADER - if (patch[dev] && *patch[dev]) { -- const struct firmware *fw = NULL; -+ const struct firmware *fw __free(firmware) = NULL; - - dev_info(&pci->dev, "Applying patch firmware '%s'\n", - patch[dev]); -@@ -2390,7 +2407,6 @@ static int azx_probe_continue(struct azx *chip) - "Cannot load firmware, continue without patching\n"); - } else { - err = snd_hda_load_patch(&chip->bus, fw->size, fw->data); -- release_firmware(fw); - if (err < 0) - goto out_free; - } -@@ -2838,6 +2854,11 @@ static const struct pci_device_id azx_ids[] = { - .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL }, - { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI), - .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL }, -+ /* Hygon HDAudio */ -+ { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_HDA), -+ .driver_data = AZX_DRIVER_HYGON | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_NO_MSI }, -+ /* Lisuan HD-audio */ -+ { PCI_DEVICE(0x4c54, 0x5010), .driver_data = AZX_DRIVER_GENERIC }, - { 0, } - }; - MODULE_DEVICE_TABLE(pci, azx_ids); -diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c ---- a/sound/hda/core/controller.c -+++ b/sound/hda/core/controller.c -@@ -511,7 +511,10 @@ void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus) - { - unsigned long timeout; - -- snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); -+ if (bus->access_sdnctl_in_dword) -+ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); -+ else -+ snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); - - timeout = jiffies + msecs_to_jiffies(100); - while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout)) -@@ -576,7 +579,10 @@ static void azx_int_disable(struct hdac_bus *bus) - - /* disable interrupts in stream descriptor */ - list_for_each_entry(azx_dev, &bus->stream_list, list) -- snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0); -+ if (bus->access_sdnctl_in_dword) -+ snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_INT_MASK, 0); -+ else -+ snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0); - - /* disable SIE for all streams & disable controller CIE and GIE */ - snd_hdac_chip_writel(bus, INTCTL, 0); -@@ -682,6 +688,11 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status, - sd_status = snd_hdac_stream_readb(azx_dev, SD_STS); - snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); - handled |= 1 << azx_dev->index; -+ if (sd_status & (SD_INT_FIFO_ERR | SD_INT_DESC_ERR)) { -+ dev_warn_ratelimited(bus->dev, -+ "stream %u dma error: 0x%02x\n", -+ azx_dev->index, sd_status); -+ } - if ((!azx_dev->substream && !azx_dev->cstream) || - !azx_dev->running || !(sd_status & SD_INT_COMPLETE)) - continue; -@@ -713,7 +724,7 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus) - BDL_SIZE, &s->bdl); - num_streams++; - if (err < 0) -- return -ENOMEM; -+ goto error_bdl; - } - - if (WARN_ON(!num_streams)) -@@ -722,12 +733,24 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus) - err = snd_dma_alloc_pages(dma_type, bus->dev, - num_streams * 8, &bus->posbuf); - if (err < 0) -- return -ENOMEM; -+ goto error_bdl; - list_for_each_entry(s, &bus->stream_list, list) - s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8); - - /* single page (at least 4096 bytes) must suffice for both ringbuffes */ -- return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb); -+ err = snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb); -+ if (err < 0) -+ goto error_posbuf; -+ return 0; -+ -+error_posbuf: -+ snd_dma_free_pages(&bus->posbuf); -+error_bdl: -+ list_for_each_entry(s, &bus->stream_list, list) { -+ if (s->bdl.area) -+ snd_dma_free_pages(&s->bdl); -+ } -+ return -ENOMEM; - } - EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages); - -diff --git a/sound/hda/core/device.c b/sound/hda/core/device.c ---- a/sound/hda/core/device.c -+++ b/sound/hda/core/device.c -@@ -664,6 +664,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = { - { 0x1af4, "QEMU" }, - { 0x1fa8, "Senarytech" }, - { 0x434d, "C-Media" }, -+ { 0x4c54, "Lisuan" }, - { 0x8086, "Intel" }, - { 0x8384, "SigmaTel" }, - {} /* terminator */ -@@ -766,7 +767,7 @@ unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subfor - - params_set_format(¶ms, snd_hdac_format_normalize(format)); - snd_mask_set(hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT), -- (__force unsigned int)subformat); -+ subformat); - - bits = snd_pcm_hw_params_bits(¶ms); - if (maxbits) -diff --git a/sound/hda/core/hda_bus_type.c b/sound/hda/core/hda_bus_type.c ---- a/sound/hda/core/hda_bus_type.c -+++ b/sound/hda/core/hda_bus_type.c -@@ -39,10 +39,7 @@ EXPORT_SYMBOL_GPL(hdac_get_device_id); - - static int hdac_codec_match(struct hdac_device *dev, const struct hdac_driver *drv) - { -- if (hdac_get_device_id(dev, drv)) -- return 1; -- else -- return 0; -+ return !!hdac_get_device_id(dev, drv); - } - - static int hda_bus_match(struct device *dev, const struct device_driver *drv) -@@ -59,9 +56,7 @@ static int hda_bus_match(struct device *dev, const struct device_driver *drv) - */ - if (hdrv->match) - return hdrv->match(hdev, hdrv); -- else -- return hdac_codec_match(hdev, hdrv); -- return 1; -+ return hdac_codec_match(hdev, hdrv); - } - - static int hda_uevent(const struct device *dev, struct kobj_uevent_env *env) -diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c ---- a/sound/hda/core/stream.c -+++ b/sound/hda/core/stream.c -@@ -146,8 +146,12 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev) - stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); - else - stripe_ctl = 0; -- snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, -- stripe_ctl); -+ if (bus->access_sdnctl_in_dword) -+ snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, -+ stripe_ctl); -+ else -+ snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, -+ stripe_ctl); - } - /* set DMA start and interrupt mask */ - if (bus->access_sdnctl_in_dword) -@@ -166,11 +170,22 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_start); - */ - static void snd_hdac_stream_clear(struct hdac_stream *azx_dev) - { -- snd_hdac_stream_updateb(azx_dev, SD_CTL, -- SD_CTL_DMA_START | SD_INT_MASK, 0); -- snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ -- if (azx_dev->stripe) -- snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); -+ struct hdac_bus *bus = azx_dev->bus; -+ -+ if (bus->access_sdnctl_in_dword) { -+ snd_hdac_stream_updatel(azx_dev, SD_CTL, -+ SD_CTL_DMA_START | SD_INT_MASK, 0); -+ snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ -+ if (azx_dev->stripe) -+ snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); -+ } else { -+ snd_hdac_stream_updateb(azx_dev, SD_CTL, -+ SD_CTL_DMA_START | SD_INT_MASK, 0); -+ snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ -+ if (azx_dev->stripe) -+ snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); -+ } -+ - azx_dev->running = false; - } - -@@ -225,12 +240,16 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev) - { - unsigned char val; - int dma_run_state; -+ struct hdac_bus *bus = azx_dev->bus; - - snd_hdac_stream_clear(azx_dev); - - dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START; - -- snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); -+ if (bus->access_sdnctl_in_dword) -+ snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); -+ else -+ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET); - - /* wait for hardware to report that the stream entered reset */ - snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RESET), 3, 300); -@@ -238,7 +257,10 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev) - if (azx_dev->bus->dma_stop_delay && dma_run_state) - udelay(azx_dev->bus->dma_stop_delay); - -- snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); -+ if (bus->access_sdnctl_in_dword) -+ snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); -+ else -+ snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0); - - /* wait for hardware to report that the stream is out of reset */ - snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, !(val & SD_CTL_STREAM_RESET), 3, 300); -diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c ---- a/sound/isa/msnd/msnd_pinnacle.c -+++ b/sound/isa/msnd/msnd_pinnacle.c -@@ -367,7 +367,8 @@ static int snd_msnd_init_sma(struct snd_msnd *chip) - static int upload_dsp_code(struct snd_card *card) - { - struct snd_msnd *chip = card->private_data; -- const struct firmware *init_fw = NULL, *perm_fw = NULL; -+ const struct firmware *init_fw __free(firmware) = NULL; -+ const struct firmware *perm_fw __free(firmware) = NULL; - int err; - - outb(HPBLKSEL_0, chip->io + HP_BLKS); -@@ -375,28 +376,21 @@ static int upload_dsp_code(struct snd_card *card) - err = request_firmware(&init_fw, INITCODEFILE, card->dev); - if (err < 0) { - dev_err(card->dev, LOGNAME ": Error loading " INITCODEFILE); -- goto cleanup1; -+ return err; - } - err = request_firmware(&perm_fw, PERMCODEFILE, card->dev); - if (err < 0) { - dev_err(card->dev, LOGNAME ": Error loading " PERMCODEFILE); -- goto cleanup; -+ return err; - } - - memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size); - if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) { - dev_warn(card->dev, LOGNAME ": Error uploading to DSP\n"); -- err = -ENODEV; -- goto cleanup; -+ return -ENODEV; - } - dev_info(card->dev, LOGNAME ": DSP firmware uploaded\n"); -- err = 0; -- --cleanup: -- release_firmware(perm_fw); --cleanup1: -- release_firmware(init_fw); -- return err; -+ return 0; - } - - #ifdef MSND_CLASSIC -diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c ---- a/sound/isa/sscape.c -+++ b/sound/isa/sscape.c -@@ -526,7 +526,7 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data, - static int sscape_upload_bootblock(struct snd_card *card) - { - struct soundscape *sscape = get_card_soundscape(card); -- const struct firmware *init_fw = NULL; -+ const struct firmware *init_fw __free(firmware) = NULL; - int data = 0; - int ret; - -@@ -537,8 +537,6 @@ static int sscape_upload_bootblock(struct snd_card *card) - } - ret = upload_dma_data(sscape, init_fw->data, init_fw->size); - -- release_firmware(init_fw); -- - guard(spinlock_irqsave)(&sscape->lock); - if (ret == 0) - data = host_read_ctrl_unsafe(sscape->io_base, 100); -@@ -562,7 +560,7 @@ static int sscape_upload_bootblock(struct snd_card *card) - static int sscape_upload_microcode(struct snd_card *card, int version) - { - struct soundscape *sscape = get_card_soundscape(card); -- const struct firmware *init_fw = NULL; -+ const struct firmware *init_fw __free(firmware) = NULL; - char name[14]; - int err; - -@@ -579,8 +577,6 @@ static int sscape_upload_microcode(struct snd_card *card, int version) - dev_info(card->dev, "sscape: MIDI firmware loaded %zu KBs\n", - init_fw->size >> 10); - -- release_firmware(init_fw); -- - return err; - } - -diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c ---- a/sound/isa/wavefront/wavefront_fx.c -+++ b/sound/isa/wavefront/wavefront_fx.c -@@ -232,41 +232,32 @@ snd_wavefront_fx_start (snd_wavefront_t *dev) - { - unsigned int i; - int err; -- const struct firmware *firmware = NULL; -+ const struct firmware *firmware __free(firmware) = NULL; - - if (dev->fx_initialized) - return 0; - - err = request_firmware(&firmware, "yamaha/yss225_registers.bin", - dev->card->dev); -- if (err < 0) { -- err = -1; -- goto out; -- } -+ if (err < 0) -+ return -1; - - for (i = 0; i + 1 < firmware->size; i += 2) { - if (firmware->data[i] >= 8 && firmware->data[i] < 16) { - outb(firmware->data[i + 1], - dev->base + firmware->data[i]); - } else if (firmware->data[i] == WAIT_IDLE) { -- if (!wavefront_fx_idle(dev)) { -- err = -1; -- goto out; -- } -+ if (!wavefront_fx_idle(dev)) -+ return -1; - } else { - dev_err(dev->card->dev, - "invalid address in register data\n"); -- err = -1; -- goto out; -+ return -1; - } - } - - dev->fx_initialized = 1; -- err = 0; -- --out: -- release_firmware(firmware); -- return err; -+ return 0; - } - - MODULE_FIRMWARE("yamaha/yss225_registers.bin"); -diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c ---- a/sound/isa/wavefront/wavefront_synth.c -+++ b/sound/isa/wavefront/wavefront_synth.c -@@ -2053,7 +2053,7 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path) - const unsigned char *buf; - int len, err; - int section_cnt_downloaded = 0; -- const struct firmware *firmware; -+ const struct firmware *firmware __free(firmware) = NULL; - - err = request_firmware(&firmware, path, dev->card->dev); - if (err < 0) { -@@ -2108,11 +2108,9 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path) - section_cnt_downloaded++; - } - -- release_firmware(firmware); - return 0; - - failure: -- release_firmware(firmware); - dev_err(dev->card->dev, "firmware download failed!!!\n"); - return 1; - } -diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c ---- a/sound/pci/asihpi/asihpi.c -+++ b/sound/pci/asihpi/asihpi.c -@@ -280,7 +280,7 @@ static void print_hwparams(struct snd_pcm_substream *substream, - snd_pcm_format_width(params_format(p)) / 8); - } - --#define INVALID_FORMAT (__force snd_pcm_format_t)(-1) -+#define INVALID_FORMAT -1 - - static const snd_pcm_format_t hpi_to_alsa_formats[] = { - INVALID_FORMAT, /* INVALID */ -diff --git a/sound/pci/asihpi/hpidspcd.c b/sound/pci/asihpi/hpidspcd.c ---- a/sound/pci/asihpi/hpidspcd.c -+++ b/sound/pci/asihpi/hpidspcd.c -@@ -23,7 +23,7 @@ struct dsp_code_private { - short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, - u32 *os_error_code) - { -- const struct firmware *firmware; -+ const struct firmware *firmware __free(firmware) = NULL; - struct pci_dev *dev = os_data; - struct code_header header; - char fw_name[20]; -@@ -37,11 +37,11 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, - if (err || !firmware) { - dev_err(&dev->dev, "%d, request_firmware failed for %s\n", - err, fw_name); -- goto error1; -+ goto error; - } - if (firmware->size < sizeof(header)) { - dev_err(&dev->dev, "Header size too small %s\n", fw_name); -- goto error2; -+ goto error; - } - memcpy(&header, firmware->data, sizeof(header)); - -@@ -51,7 +51,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, - dev_err(&dev->dev, - "Invalid firmware header size %d != file %zd\n", - header.size, firmware->size); -- goto error2; -+ goto error; - } - - if (HPI_VER_MAJOR(header.version) != HPI_VER_MAJOR(HPI_VER)) { -@@ -59,7 +59,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, - dev_err(&dev->dev, - "Incompatible firmware version DSP image %X != Driver %X\n", - header.version, HPI_VER); -- goto error2; -+ goto error; - } - - if (header.version != HPI_VER) { -@@ -72,19 +72,17 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, - dsp_code->pvt = kmalloc_obj(*dsp_code->pvt); - if (!dsp_code->pvt) { - err_ret = HPI_ERROR_MEMORY_ALLOC; -- goto error2; -+ goto error; - } - - dsp_code->pvt->dev = dev; -- dsp_code->pvt->firmware = firmware; -+ dsp_code->pvt->firmware = no_free_ptr(firmware); - dsp_code->header = header; - dsp_code->block_length = header.size / sizeof(u32); - dsp_code->word_count = sizeof(header) / sizeof(u32); - return 0; - --error2: -- release_firmware(firmware); --error1: -+error: - dsp_code->block_length = 0; - return err_ret; - } -diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c ---- a/sound/pci/asihpi/hpioctl.c -+++ b/sound/pci/asihpi/hpioctl.c -@@ -385,8 +385,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, - if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) { - memlen = pci_resource_len(pci_dev, idx); - pci.ap_mem_base[idx] = -- ioremap(pci_resource_start(pci_dev, idx), -- memlen); -+ pcim_iomap(pci_dev, idx, memlen); - if (!pci.ap_mem_base[idx]) { - HPI_DEBUG_LOG(ERROR, - "ioremap failed, aborting\n"); -@@ -509,13 +508,6 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, - return 0; - - err: -- while (--idx >= 0) { -- if (pci.ap_mem_base[idx]) { -- iounmap(pci.ap_mem_base[idx]); -- pci.ap_mem_base[idx] = NULL; -- } -- } -- - if (adapter.p_buffer) { - adapter.buffer_size = 0; - vfree(adapter.p_buffer); -@@ -527,14 +519,11 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, - - void asihpi_adapter_remove(struct pci_dev *pci_dev) - { -- int idx; - struct hpi_message hm; - struct hpi_response hr; - struct hpi_adapter *pa; -- struct hpi_pci pci; - - pa = pci_get_drvdata(pci_dev); -- pci = pa->adapter->pci; - - /* Disable IRQ generation on DSP side */ - hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, -@@ -550,10 +539,6 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) - hm.adapter_index = pa->adapter->index; - hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); - -- /* unmap PCI memory space, mapped during device init. */ -- for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx) -- iounmap(pci.ap_mem_base[idx]); -- - if (pa->irq) - free_irq(pa->irq, pa); - -diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c ---- a/sound/pci/cs46xx/cs46xx_lib.c -+++ b/sound/pci/cs46xx/cs46xx_lib.c -@@ -387,7 +387,7 @@ static int load_firmware(struct snd_cs46xx *chip, - unsigned int nums, fwlen, fwsize; - const __le32 *fwdat; - struct dsp_module_desc *module = NULL; -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - char fw_path[32]; - - sprintf(fw_path, "cs46xx/%s", fw_name); -@@ -395,10 +395,8 @@ static int load_firmware(struct snd_cs46xx *chip, - if (err < 0) - return err; - fwsize = fw->size / 4; -- if (fwsize < 2) { -- err = -EINVAL; -- goto error; -- } -+ if (fwsize < 2) -+ return -EINVAL; - - err = -ENOMEM; - module = kzalloc_obj(*module); -@@ -454,14 +452,12 @@ static int load_firmware(struct snd_cs46xx *chip, - } - - *module_ret = module; -- release_firmware(fw); - return 0; - - error_inval: - err = -EINVAL; - error: - free_module_desc(module); -- release_firmware(fw); - return err; - } - -@@ -500,22 +496,18 @@ MODULE_FIRMWARE("cs46xx/ba1"); - - static int load_firmware(struct snd_cs46xx *chip) - { -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - int i, size, err; - - err = request_firmware(&fw, "cs46xx/ba1", &chip->pci->dev); - if (err < 0) - return err; -- if (fw->size != sizeof(*chip->ba1)) { -- err = -EINVAL; -- goto error; -- } -+ if (fw->size != sizeof(*chip->ba1)) -+ return -EINVAL; - - chip->ba1 = vmalloc(sizeof(*chip->ba1)); -- if (!chip->ba1) { -- err = -ENOMEM; -- goto error; -- } -+ if (!chip->ba1) -+ return -ENOMEM; - - memcpy_le32(chip->ba1, fw->data, sizeof(*chip->ba1)); - -@@ -524,11 +516,9 @@ static int load_firmware(struct snd_cs46xx *chip) - for (i = 0; i < BA1_MEMORY_COUNT; i++) - size += chip->ba1->memory[i].size; - if (size > BA1_DWORD_SIZE * 4) -- err = -EINVAL; -+ return -EINVAL; - -- error: -- release_firmware(fw); -- return err; -+ return 0; - } - - static __maybe_unused int snd_cs46xx_download_image(struct snd_cs46xx *chip) -diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c ---- a/sound/pci/emu10k1/emufx.c -+++ b/sound/pci/emu10k1/emufx.c -@@ -990,7 +990,7 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, - i < icode->gpr_list_control_count) { - memset(gctl, 0, sizeof(*gctl)); - id = &ctl->kcontrol->id; -- gctl->id.iface = (__force int)id->iface; -+ gctl->id.iface = id->iface; - strscpy(gctl->id.name, id->name, sizeof(gctl->id.name)); - gctl->id.index = id->index; - gctl->id.device = id->device; -@@ -1156,7 +1156,7 @@ static void - snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr *ctl, - const char *name, int gpr, int defval, int defval_hr) - { -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, name); - ctl->vcount = ctl->count = 1; - if (high_res_gpr_volume) { -@@ -1180,7 +1180,7 @@ static void - snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr *ctl, - const char *name, int gpr, int defval, int defval_hr) - { -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, name); - ctl->vcount = ctl->count = 2; - if (high_res_gpr_volume) { -@@ -1205,7 +1205,7 @@ static void - snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, - const char *name, int gpr, int defval) - { -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, name); - ctl->vcount = ctl->count = 1; - ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; -@@ -1218,7 +1218,7 @@ static void - snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, - const char *name, int gpr, int defval) - { -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, name); - ctl->vcount = ctl->count = 2; - ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; -@@ -1542,7 +1542,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) - * Process tone control - */ - ctl = &controls[nctl + 0]; -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, "Tone Control - Bass"); - ctl->vcount = 2; - ctl->count = 10; -@@ -1551,7 +1551,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) - ctl->value[0] = ctl->value[1] = 20; - ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; - ctl = &controls[nctl + 1]; -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, "Tone Control - Treble"); - ctl->vcount = 2; - ctl->count = 10; -@@ -2137,7 +2137,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) - * Process tone control - */ - ctl = &controls[i + 0]; -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, "Tone Control - Bass"); - ctl->vcount = 2; - ctl->count = 10; -@@ -2147,7 +2147,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) - ctl->tlv = snd_emu10k1_bass_treble_db_scale; - ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; - ctl = &controls[i + 1]; -- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; -+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strscpy(ctl->id.name, "Tone Control - Treble"); - ctl->vcount = 2; - ctl->count = 10; -diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c ---- a/sound/pci/korg1212/korg1212.c -+++ b/sound/pci/korg1212/korg1212.c -@@ -1980,7 +1980,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) - __maybe_unused unsigned ioport_size; - __maybe_unused unsigned iomem2_size; - struct snd_korg1212 *korg1212 = card->private_data; -- const struct firmware *dsp_code; -+ const struct firmware *dsp_code __free(firmware) = NULL; - - err = pcim_enable_device(pci); - if (err < 0) -@@ -2147,10 +2147,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) - - korg1212->dma_dsp = snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, - dsp_code->size); -- if (!korg1212->dma_dsp) { -- release_firmware(dsp_code); -+ if (!korg1212->dma_dsp) - return -ENOMEM; -- } - - K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n", - korg1212->dma_dsp->area, korg1212->dma_dsp->addr, dsp_code->size, -@@ -2158,8 +2156,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) - - memcpy(korg1212->dma_dsp->area, dsp_code->data, dsp_code->size); - -- release_firmware(dsp_code); -- - rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0); - - if (rc) -diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c ---- a/sound/pci/mixart/mixart_hwdep.c -+++ b/sound/pci/mixart/mixart_hwdep.c -@@ -560,12 +560,11 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr) - "miXart8.xlx", "miXart8.elf", "miXart8AES.xlx" - }; - char path[32]; -- -- const struct firmware *fw_entry; - int i, err; - - for (i = 0; i < 3; i++) { - sprintf(path, "mixart/%s", fw_files[i]); -+ const struct firmware *fw_entry __free(firmware) = NULL; - if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { - dev_err(&mgr->pci->dev, - "miXart: can't load firmware %s\n", path); -@@ -573,7 +572,6 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr) - } - /* fake hwdep dsp record */ - err = mixart_dsp_load(mgr, i, fw_entry); -- release_firmware(fw_entry); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << i; -diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c ---- a/sound/pci/pcxhr/pcxhr_hwdep.c -+++ b/sound/pci/pcxhr/pcxhr_hwdep.c -@@ -367,7 +367,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) - }; - char path[32]; - -- const struct firmware *fw_entry; - int i, err; - int fw_set = mgr->fw_file_set; - -@@ -375,6 +374,7 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) - if (!fw_files[fw_set][i]) - continue; - sprintf(path, "pcxhr/%s", fw_files[fw_set][i]); -+ const struct firmware *fw_entry __free(firmware) = NULL; - if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { - dev_err(&mgr->pci->dev, - "pcxhr: can't load firmware %s\n", -@@ -383,7 +383,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) - } - /* fake hwdep dsp record */ - err = pcxhr_dsp_load(mgr, i, fw_entry); -- release_firmware(fw_entry); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << i; -diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c ---- a/sound/pci/sis7019.c -+++ b/sound/pci/sis7019.c -@@ -1260,16 +1260,16 @@ static int sis_chip_create(struct snd_card *card, - sis->irq = -1; - sis->ioport = pci_resource_start(pci, 0); - -- rc = pcim_request_all_regions(pci, "SiS7019"); -+ rc = pcim_request_region(pci, 0, "SiS7019"); - if (rc) { -- dev_err(&pci->dev, "unable request regions\n"); -+ dev_err(&pci->dev, "unable request I/O region\n"); - return rc; - } - -- sis->ioaddr = devm_ioremap(&pci->dev, pci_resource_start(pci, 1), 0x4000); -- if (!sis->ioaddr) { -+ sis->ioaddr = pcim_iomap_region(pci, 1, "SiS7019"); -+ if (IS_ERR(sis->ioaddr)) { - dev_err(&pci->dev, "unable to remap MMIO, aborting\n"); -- return -EIO; -+ return PTR_ERR(sis->ioaddr); - } - - rc = sis_alloc_suspend(sis); -diff --git a/sound/sh/aica.c b/sound/sh/aica.c ---- a/sound/sh/aica.c -+++ b/sound/sh/aica.c -@@ -518,8 +518,9 @@ static const struct snd_kcontrol_new snd_aica_pcmvolume_control = { - static int load_aica_firmware(void) - { - int err; -- const struct firmware *fw_entry; - spu_reset(); -+ -+ const struct firmware *fw_entry __free(firmware) = NULL; - err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev); - if (unlikely(err)) - return err; -@@ -527,7 +528,6 @@ static int load_aica_firmware(void) - spu_disable(); - spu_memload(0, fw_entry->data, fw_entry->size); - spu_enable(); -- release_firmware(fw_entry); - return err; - } - -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -726,6 +726,10 @@ config SND_SOC_AW87390 - sound quality, which is a new high efficiency, low - noise, constant large volume, 6th Smart K audio amplifier. - -+config SND_SOC_AW88399_LIB -+ tristate -+ select SND_SOC_AW88395_LIB -+ - config SND_SOC_AW88399 - tristate "Soc Audio for awinic aw88399" - depends on I2C -@@ -733,6 +737,7 @@ config SND_SOC_AW88399 - select REGMAP_I2C - select GPIOLIB - select SND_SOC_AW88395_LIB -+ select SND_SOC_AW88399_LIB - help - This option enables support for aw88399 Smart PA. - The awinic AW88399 is an I2S/TDM input, high efficiency -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -55,6 +55,7 @@ snd-soc-aw88395-y := aw88395/aw88395.o - snd-soc-aw88166-y := aw88166.o - snd-soc-aw88261-y := aw88261.o - snd-soc-aw88399-y := aw88399.o -+snd-soc-aw88399-lib-y := aw88399-lib.o - snd-soc-bd28623-y := bd28623.o - snd-soc-bt-sco-y := bt-sco.o - snd-soc-chv3-codec-y := chv3-codec.o -@@ -496,6 +497,7 @@ obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o - obj-$(CONFIG_SND_SOC_AW88166) +=snd-soc-aw88166.o - obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o - obj-$(CONFIG_SND_SOC_AW88399) += snd-soc-aw88399.o -+obj-$(CONFIG_SND_SOC_AW88399_LIB) += snd-soc-aw88399-lib.o - obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o - obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o - obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o -diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/codecs/aw88399-lib.c -@@ -0,0 +1,1411 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+// -+// aw88399-lib.c -- AW88399 Common functions for ASoC and HDA audio drivers -+// -+// Copyright (c) 2023 AWINIC Technology CO., LTD -+// -+// Author: Weidong Wang -+// -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "aw88395/aw88395_device.h" -+ -+const struct regmap_config aw88399_remap_config = { -+ .val_bits = 16, -+ .reg_bits = 8, -+ .max_register = AW88399_REG_MAX, -+ .reg_format_endian = REGMAP_ENDIAN_LITTLE, -+ .val_format_endian = REGMAP_ENDIAN_BIG, -+}; -+EXPORT_SYMBOL_GPL(aw88399_remap_config); -+ -+static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) -+{ -+ int ret; -+ -+ if (pwd) -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE); -+ else -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE); -+ -+ if (ret) -+ dev_dbg(aw_dev->dev, "%s failed", __func__); -+} -+ -+static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status) -+{ -+ unsigned int reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, ®_val); -+ if (ret) -+ dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); -+ else -+ *int_status = reg_val; -+ -+ dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status); -+} -+ -+static void aw_dev_clear_int_status(struct aw_device *aw_dev) -+{ -+ u16 int_status; -+ -+ /* read int status and clear */ -+ aw_dev_get_int_status(aw_dev, &int_status); -+ /* make sure int status is clear */ -+ aw_dev_get_int_status(aw_dev, &int_status); -+ if (int_status) -+ dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status); -+} -+ -+static int aw_dev_get_iis_status(struct aw_device *aw_dev) -+{ -+ unsigned int reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); -+ if (ret) -+ return ret; -+ if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) { -+ dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int aw_dev_check_mode1_pll(struct aw_device *aw_dev) -+{ -+ int ret, i; -+ -+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -+ ret = aw_dev_get_iis_status(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "mode1 iis signal check error"); -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ } else { -+ return 0; -+ } -+ } -+ -+ return -EPERM; -+} -+ -+static int aw_dev_check_mode2_pll(struct aw_device *aw_dev) -+{ -+ unsigned int reg_val; -+ int ret, i; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ reg_val &= (~AW88399_CCO_MUX_MASK); -+ if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) { -+ dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); -+ return -EPERM; -+ } -+ -+ /* change mode2 */ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, -+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -+ ret = aw_dev_get_iis_status(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "mode2 iis signal check error"); -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ } else { -+ break; -+ } -+ } -+ -+ /* change mode1 */ -+ regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, -+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE); -+ if (ret == 0) { -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -+ ret = aw_dev_get_iis_status(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ } else { -+ break; -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+int aw_dev_check_syspll(struct aw_device *aw_dev) -+{ -+ int ret; -+ -+ ret = aw_dev_check_mode1_pll(aw_dev); -+ if (ret) { -+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); -+ ret = aw_dev_check_mode2_pll(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "mode2 check iis failed"); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(aw_dev_check_syspll); -+ -+static int aw_dev_check_sysst(struct aw88399 *aw88399) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ unsigned int check_val; -+ unsigned int reg_val; -+ int ret, i; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ if (reg_val & (~AW88399_NOISE_GATE_EN_MASK)) -+ check_val = AW88399_BIT_SYSST_NOSWS_CHECK; -+ else -+ check_val = AW88399_BIT_SYSST_SWS_CHECK; -+ -+ /* -+ * On some hardware the BSTS (boost-finished) status bit does not -+ * reliably assert even when audio output is working normally. -+ * Allow per-instance bypass when flagged by the side-codec driver. -+ */ -+ if (aw88399->bsts_unreliable) -+ check_val &= ~AW88399_BSTS_FINISHED_VALUE; -+ -+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) { -+ dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x", -+ i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK); -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ } else { -+ return 0; -+ } -+ } -+ -+ return -EPERM; -+} -+ -+static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) -+{ -+ int ret; -+ -+ if (amppd) -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE); -+ else -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE); -+ -+ if (ret) -+ dev_dbg(aw_dev->dev, "%s failed", __func__); -+} -+ -+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable) -+{ -+ int ret; -+ -+ if (is_enable) -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE); -+ else -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE); -+ -+ if (ret) -+ dev_dbg(aw_dev->dev, "%s failed\n", __func__); -+} -+EXPORT_SYMBOL_GPL(aw_dev_dsp_enable); -+ -+static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk) -+{ -+ uint16_t icalkh_val, icalkl_val, icalk_val; -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ unsigned int reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, ®_val); -+ if (ret) -+ return ret; -+ icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK); -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, ®_val); -+ if (ret) -+ return ret; -+ icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK); -+ -+ if (aw88399->check_val == AW_EF_AND_CHECK) -+ icalk_val = icalkh_val & icalkl_val; -+ else -+ icalk_val = icalkh_val | icalkl_val; -+ -+ if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK)) -+ icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG; -+ *icalk = (int16_t)icalk_val; -+ -+ return 0; -+} -+ -+static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk) -+{ -+ uint16_t vcalkh_val, vcalkl_val, vcalk_val; -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ unsigned int reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK); -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK); -+ -+ if (aw88399->check_val == AW_EF_AND_CHECK) -+ vcalk_val = vcalkh_val & vcalkl_val; -+ else -+ vcalk_val = vcalkh_val | vcalkl_val; -+ -+ if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK) -+ vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG; -+ *vcalk = (int16_t)vcalk_val; -+ -+ return 0; -+} -+ -+static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk) -+{ -+ uint16_t vcalkh_val, vcalkl_val, vcalk_val; -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ unsigned int reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, ®_val); -+ if (ret) -+ return ret; -+ vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK); -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, ®_val); -+ if (ret) -+ return ret; -+ vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK); -+ -+ if (aw88399->check_val == AW_EF_AND_CHECK) -+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) & -+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); -+ else -+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) | -+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); -+ -+ if (vcalk_val & (~AW88399_TEM4_SIGN_MASK)) -+ vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG; -+ -+ *vcalk = (int16_t)vcalk_val; -+ -+ return 0; -+} -+ -+static int aw_dev_set_vcalb(struct aw88399 *aw88399) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ unsigned int vsense_select, vsense_value; -+ int32_t ical_k, vcal_k, vcalb; -+ int16_t icalk, vcalk; -+ uint16_t reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value); -+ if (ret) -+ return ret; -+ -+ vsense_select = vsense_value & (~AW88399_VDSEL_MASK); -+ -+ ret = aw88399_dev_get_icalk(aw88399, &icalk); -+ if (ret) { -+ dev_err(aw_dev->dev, "get icalk failed\n"); -+ return ret; -+ } -+ -+ ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE; -+ -+ switch (vsense_select) { -+ case AW88399_DEV_VDSEL_VSENSE: -+ ret = aw88399_dev_get_vcalk(aw88399, &vcalk); -+ vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE; -+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR * -+ ical_k / vcal_k * aw88399->vcalb_init_val; -+ break; -+ case AW88399_DEV_VDSEL_DAC: -+ ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk); -+ vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE; -+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR / -+ AW88399_ISCAL_DAC_FACTOR * ical_k / -+ vcal_k * aw88399->vcalb_init_val; -+ break; -+ default: -+ dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); -+ ret = -EINVAL; -+ break; -+ } -+ if (ret) -+ return ret; -+ -+ vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR; -+ reg_val = (uint32_t)vcalb; -+ -+ regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val); -+ -+ return 0; -+} -+ -+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc) -+{ -+ struct aw_device *aw_dev = -+ container_of(cali_desc, struct aw_device, cali_desc); -+ uint16_t re_lbits, re_hbits; -+ u32 cali_re; -+ int ret; -+ -+ if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) || -+ (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN)) -+ return -EINVAL; -+ -+ cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + -+ aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT); -+ -+ re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT; -+ re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT; -+ -+ ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits); -+ if (ret) { -+ dev_err(aw_dev->dev, "set cali re error"); -+ return ret; -+ } -+ -+ ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits); -+ if (ret) -+ dev_err(aw_dev->dev, "set cali re error"); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(aw_dev_update_cali_re); -+ -+static int aw_dev_fw_crc_check(struct aw_device *aw_dev) -+{ -+ uint16_t check_val, fw_len_val; -+ unsigned int reg_val; -+ int ret; -+ -+ /* calculate fw_end_addr */ -+ fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR; -+ -+ /* write fw_end_addr to crc_end_addr */ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -+ ~AW88399_CRC_END_ADDR_MASK, fw_len_val); -+ if (ret) -+ return ret; -+ /* enable fw crc check */ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE); -+ -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ -+ /* read crc check result */ -+ regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; -+ -+ /* disable fw crc check */ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE); -+ if (ret) -+ return ret; -+ -+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) { -+ dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x", -+ __func__, check_val, AW88399_CRC_CHECK_PASS_VAL); -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int aw_dev_cfg_crc_check(struct aw_device *aw_dev) -+{ -+ uint16_t check_val, cfg_len_val; -+ unsigned int reg_val; -+ int ret; -+ -+ /* calculate cfg end addr */ -+ cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR; -+ -+ /* write cfg_end_addr to crc_end_addr */ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -+ ~AW88399_CRC_END_ADDR_MASK, cfg_len_val); -+ if (ret) -+ return ret; -+ -+ /* enable cfg crc check */ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE); -+ if (ret) -+ return ret; -+ -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -+ -+ /* read crc check result */ -+ ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; -+ -+ /* disable cfg crc check */ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE); -+ if (ret) -+ return ret; -+ -+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) { -+ dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x", -+ check_val, AW88399_CRC_CHECK_PASS_VAL); -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int aw_dev_hw_crc_check(struct aw88399 *aw88399) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ int ret; -+ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE); -+ if (ret) -+ return ret; -+ -+ ret = aw_dev_fw_crc_check(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "fw_crc_check failed\n"); -+ goto crc_check_failed; -+ } -+ -+ ret = aw_dev_cfg_crc_check(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "cfg_crc_check failed\n"); -+ goto crc_check_failed; -+ } -+ -+ ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val); -+ if (ret) -+ return ret; -+ -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); -+ -+ return ret; -+ -+crc_check_failed: -+ regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); -+ return ret; -+} -+ -+static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) -+{ -+ int ret; -+ -+ if (flag) -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG, -+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE); -+ else -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE); -+ -+ if (ret) -+ dev_dbg(aw_dev->dev, "%s failed", __func__); -+} -+ -+int aw_dev_get_dsp_status(struct aw_device *aw_dev) -+{ -+ unsigned int reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, ®_val); -+ if (ret) -+ return ret; -+ if (!(reg_val & (~AW88399_WDT_CNT_MASK))) -+ return -EPERM; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(aw_dev_get_dsp_status); -+ -+static int aw_dev_dsp_check(struct aw_device *aw_dev) -+{ -+ int ret, i; -+ -+ switch (aw_dev->dsp_cfg) { -+ case AW88399_DEV_DSP_BYPASS: -+ dev_dbg(aw_dev->dev, "dsp bypass"); -+ ret = 0; -+ break; -+ case AW88399_DEV_DSP_WORK: -+ aw_dev_dsp_enable(aw_dev, false); -+ aw_dev_dsp_enable(aw_dev, true); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -+ for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) { -+ ret = aw_dev_get_dsp_status(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "dsp wdt status error=%d", ret); -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ } -+ } -+ break; -+ default: -+ dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg); -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value) -+{ -+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; -+ unsigned int reg_value; -+ u16 real_value; -+ int ret; -+ -+ real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL); -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, ®_value); -+ if (ret) -+ return ret; -+ -+ dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value); -+ -+ real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK); -+ -+ ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(aw_dev_set_volume); -+ -+static void aw_dev_fade_in(struct aw_device *aw_dev) -+{ -+ struct aw_volume_desc *desc = &aw_dev->volume_desc; -+ u16 fade_in_vol = desc->ctl_volume; -+ int fade_step = aw_dev->fade_step; -+ int i; -+ -+ if (fade_step == 0 || aw_dev->fade_in_time == 0) { -+ aw_dev_set_volume(aw_dev, fade_in_vol); -+ return; -+ } -+ -+ for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { -+ aw_dev_set_volume(aw_dev, i); -+ usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); -+ } -+ -+ if (i != fade_in_vol) -+ aw_dev_set_volume(aw_dev, fade_in_vol); -+} -+ -+static void aw_dev_fade_out(struct aw_device *aw_dev) -+{ -+ struct aw_volume_desc *desc = &aw_dev->volume_desc; -+ int fade_step = aw_dev->fade_step; -+ int i; -+ -+ if (fade_step == 0 || aw_dev->fade_out_time == 0) { -+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); -+ return; -+ } -+ -+ for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) { -+ aw_dev_set_volume(aw_dev, i); -+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); -+ } -+ -+ if (i != AW88399_MUTE_VOL) { -+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); -+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); -+ } -+} -+ -+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute) -+{ -+ if (is_mute) { -+ aw_dev_fade_out(aw_dev); -+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE); -+ } else { -+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE); -+ aw_dev_fade_in(aw_dev); -+ } -+} -+EXPORT_SYMBOL_GPL(aw88399_dev_mute); -+ -+static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ -+ if (dither) -+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE); -+ else -+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE); -+} -+ -+static int aw88399_dev_start(struct aw88399 *aw88399) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ int ret; -+ -+ if (aw_dev->status == AW88399_DEV_PW_ON) { -+ dev_dbg(aw_dev->dev, "already power on"); -+ return 0; -+ } -+ -+ aw88399_dev_set_dither(aw88399, false); -+ -+ /* power on */ -+ aw_dev_pwd(aw_dev, false); -+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -+ -+ ret = aw_dev_check_syspll(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "pll check failed cannot start"); -+ goto pll_check_fail; -+ } -+ -+ /* amppd on */ -+ aw_dev_amppd(aw_dev, false); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 50); -+ -+ /* check i2s status */ -+ ret = aw_dev_check_sysst(aw88399); -+ if (ret) { -+ dev_err(aw_dev->dev, "sysst check failed"); -+ goto sysst_check_fail; -+ } -+ -+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) { -+ ret = aw_dev_hw_crc_check(aw88399); -+ if (ret) { -+ dev_err(aw_dev->dev, "dsp crc check failed"); -+ goto crc_check_fail; -+ } -+ aw_dev_dsp_enable(aw_dev, false); -+ aw_dev_set_vcalb(aw88399); -+ aw_dev_update_cali_re(&aw_dev->cali_desc); -+ -+ ret = aw_dev_dsp_check(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "dsp status check failed"); -+ goto dsp_check_fail; -+ } -+ } else { -+ dev_dbg(aw_dev->dev, "start pa with dsp bypass"); -+ } -+ -+ /* enable tx feedback */ -+ aw_dev_i2s_tx_enable(aw_dev, true); -+ -+ if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE) -+ aw88399_dev_set_dither(aw88399, true); -+ -+ /* close mute */ -+ aw88399_dev_mute(aw_dev, false); -+ /* clear inturrupt */ -+ aw_dev_clear_int_status(aw_dev); -+ aw_dev->status = AW88399_DEV_PW_ON; -+ -+ return 0; -+ -+dsp_check_fail: -+crc_check_fail: -+ aw_dev_dsp_enable(aw_dev, false); -+sysst_check_fail: -+ aw_dev_clear_int_status(aw_dev); -+ aw_dev_amppd(aw_dev, true); -+pll_check_fail: -+ aw_dev_pwd(aw_dev, true); -+ aw_dev->status = AW88399_DEV_PW_OFF; -+ -+ return ret; -+} -+ -+static int aw_dev_dsp_update_container(struct aw_device *aw_dev, -+ unsigned char *data, unsigned int len, unsigned short base) -+{ -+ u32 tmp_len; -+ int i, ret; -+ -+ ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) { -+ tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE); -+ ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG, -+ &data[i], tmp_len); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int aw_dev_get_ra(struct aw_cali_desc *cali_desc) -+{ -+ struct aw_device *aw_dev = -+ container_of(cali_desc, struct aw_device, cali_desc); -+ u32 dsp_ra; -+ int ret; -+ -+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA, -+ &dsp_ra, AW_DSP_32_DATA); -+ if (ret) { -+ dev_err(aw_dev->dev, "read ra error"); -+ return ret; -+ } -+ -+ cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra, -+ AW88399_DSP_RE_SHIFT); -+ -+ return 0; -+} -+ -+static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev, -+ unsigned char *data, unsigned int len) -+{ -+ int ret; -+ -+ dev_dbg(aw_dev->dev, "dsp config len:%d", len); -+ -+ if (!len || !data) { -+ dev_err(aw_dev->dev, "dsp config data is null or len is 0"); -+ return -EINVAL; -+ } -+ -+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR); -+ if (ret) -+ return ret; -+ -+ aw_dev->dsp_cfg_len = len; -+ -+ ret = aw_dev_get_ra(&aw_dev->cali_desc); -+ -+ return ret; -+} -+ -+static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, -+ unsigned char *data, unsigned int len) -+{ -+ int ret; -+ -+ dev_dbg(aw_dev->dev, "dsp firmware len:%d", len); -+ -+ if (!len || !data) { -+ dev_err(aw_dev->dev, "dsp firmware data is null or len is 0"); -+ return -EINVAL; -+ } -+ -+ aw_dev->dsp_fw_len = len; -+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR); -+ -+ return ret; -+} -+ -+static int aw_dev_check_sram(struct aw_device *aw_dev) -+{ -+ unsigned int reg_val; -+ -+ /* read dsp_rom_check_reg */ -+ aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, ®_val, AW_DSP_16_DATA); -+ if (reg_val != AW88399_DSP_ROM_CHECK_DATA) { -+ dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]", -+ reg_val, AW88399_DSP_ROM_CHECK_DATA); -+ return -EPERM; -+ } -+ -+ /* check dsp_cfg_base_addr */ -+ aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR, -+ AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA); -+ aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, ®_val, AW_DSP_16_DATA); -+ if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) { -+ dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", -+ reg_val, AW88399_DSP_ODD_NUM_BIT_TEST); -+ return -EPERM; -+ } -+ -+ return 0; -+} -+ -+static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag) -+{ -+ int ret; -+ -+ switch (flag) { -+ case AW88399_DEV_MEMCLK_PLL: -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -+ ~AW88399_MEM_CLKSEL_MASK, -+ AW88399_MEM_CLKSEL_DAPHCLK_VALUE); -+ if (ret) -+ dev_err(aw_dev->dev, "memclk select pll failed"); -+ break; -+ case AW88399_DEV_MEMCLK_OSC: -+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -+ ~AW88399_MEM_CLKSEL_MASK, -+ AW88399_MEM_CLKSEL_OSCCLK_VALUE); -+ if (ret) -+ dev_err(aw_dev->dev, "memclk select OSC failed"); -+ break; -+ default: -+ dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag); -+ break; -+ } -+} -+ -+static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev) -+{ -+ struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; -+ unsigned int reg_val; -+ int ret; -+ -+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, ®_val); -+ if (ret) { -+ dev_dbg(aw_dev->dev, "%s failed", __func__); -+ return; -+ } -+ if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE) -+ profctrl_desc->cur_mode = AW88399_RCV_MODE; -+ else -+ profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE; -+} -+ -+static int aw_dev_update_reg_container(struct aw88399 *aw88399, -+ unsigned char *data, unsigned int len) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; -+ u16 read_vol, reg_val; -+ int data_len, i, ret; -+ int16_t *reg_data; -+ u8 reg_addr; -+ -+ reg_data = (int16_t *)data; -+ data_len = len >> 1; -+ -+ if (data_len & 0x1) { -+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < data_len; i += 2) { -+ reg_addr = reg_data[i]; -+ reg_val = reg_data[i + 1]; -+ -+ if (reg_addr == AW88399_DSPVCALB_REG) { -+ aw88399->vcalb_init_val = reg_val; -+ continue; -+ } -+ -+ if (reg_addr == AW88399_SYSCTRL_REG) { -+ if (reg_val & (~AW88399_DSPBY_MASK)) -+ aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS; -+ else -+ aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK; -+ -+ reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK | -+ AW88399_DSPBY_MASK); -+ reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE | -+ AW88399_DSPBY_BYPASS_VALUE); -+ } -+ -+ if (reg_addr == AW88399_I2SCTRL3_REG) { -+ reg_val &= AW88399_I2STXEN_MASK; -+ reg_val |= AW88399_I2STXEN_DISABLE_VALUE; -+ } -+ -+ if (reg_addr == AW88399_SYSCTRL2_REG) { -+ read_vol = (reg_val & (~AW88399_VOL_MASK)) >> -+ AW88399_VOL_START_BIT; -+ aw_dev->volume_desc.init_volume = read_vol; -+ } -+ -+ if (reg_addr == AW88399_DBGCTRL_REG) { -+ if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE) -+ aw88399->check_val = AW_EF_OR_CHECK; -+ else -+ aw88399->check_val = AW_EF_AND_CHECK; -+ -+ aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK); -+ } -+ -+ if (reg_addr == AW88399_CRCCTRL_REG) -+ aw88399->crc_init_val = reg_val; -+ -+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); -+ if (ret) -+ return ret; -+ } -+ -+ aw_dev_pwd(aw_dev, false); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -+ -+ aw_dev_get_cur_mode_st(aw_dev); -+ -+ if (aw_dev->prof_cur != aw_dev->prof_index) -+ vol_desc->ctl_volume = 0; -+ else -+ aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); -+ -+ return 0; -+} -+ -+static int aw_dev_reg_update(struct aw88399 *aw88399, -+ unsigned char *data, unsigned int len) -+{ -+ int ret; -+ -+ if (!len || !data) { -+ dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0"); -+ return -EINVAL; -+ } -+ -+ ret = aw_dev_update_reg_container(aw88399, data, len); -+ if (ret) -+ dev_err(aw88399->aw_pa->dev, "reg update failed"); -+ -+ return ret; -+} -+ -+int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) -+{ -+ struct aw_prof_info *prof_info = &aw_dev->prof_info; -+ struct aw_prof_desc *prof_desc; -+ -+ if ((index >= aw_dev->prof_info.count) || (index < 0)) { -+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]", -+ index, aw_dev->prof_info.count); -+ return -EINVAL; -+ } -+ -+ prof_desc = &aw_dev->prof_info.prof_desc[index]; -+ -+ *prof_name = prof_info->prof_name_list[prof_desc->id]; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(aw88399_dev_get_prof_name); -+ -+static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index, -+ struct aw_prof_desc **prof_desc) -+{ -+ if ((index >= aw_dev->prof_info.count) || (index < 0)) { -+ dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", -+ __func__, index, aw_dev->prof_info.count); -+ return -EINVAL; -+ } -+ -+ *prof_desc = &aw_dev->prof_info.prof_desc[index]; -+ -+ return 0; -+} -+ -+static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ struct aw_prof_desc *prof_index_desc; -+ struct aw_sec_data_desc *sec_desc; -+ char *prof_name; -+ int ret; -+ -+ if ((aw_dev->prof_cur == aw_dev->prof_index) && -+ (force_up_en == AW88399_FORCE_UPDATE_OFF)) { -+ dev_dbg(aw_dev->dev, "scene no change, not update"); -+ return 0; -+ } -+ -+ if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) { -+ dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status); -+ return -EPERM; -+ } -+ -+ ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); -+ if (ret) -+ return ret; -+ -+ dev_dbg(aw_dev->dev, "start update %s", prof_name); -+ -+ ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); -+ if (ret) -+ return ret; -+ -+ /* update reg */ -+ sec_desc = prof_index_desc->sec_desc; -+ ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data, -+ sec_desc[AW88395_DATA_TYPE_REG].len); -+ if (ret) { -+ dev_err(aw_dev->dev, "update reg failed"); -+ return ret; -+ } -+ -+ aw88399_dev_mute(aw_dev, true); -+ -+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) -+ aw_dev_dsp_enable(aw_dev, false); -+ -+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); -+ -+ ret = aw_dev_check_sram(aw_dev); -+ if (ret) { -+ dev_err(aw_dev->dev, "check sram failed"); -+ goto error; -+ } -+ -+ if (up_dsp_fw_en) { -+ dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver); -+ ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data, -+ sec_desc[AW88395_DATA_TYPE_DSP_FW].len); -+ if (ret) { -+ dev_err(aw_dev->dev, "update dsp fw failed"); -+ goto error; -+ } -+ } -+ -+ /* update dsp config */ -+ ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data, -+ sec_desc[AW88395_DATA_TYPE_DSP_CFG].len); -+ if (ret) { -+ dev_err(aw_dev->dev, "update dsp cfg failed"); -+ goto error; -+ } -+ -+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); -+ -+ aw_dev->prof_cur = aw_dev->prof_index; -+ -+ return 0; -+ -+error: -+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); -+ return ret; -+} -+ -+static void aw88399_start_pa(struct aw88399 *aw88399) -+{ -+ int ret, i; -+ -+ for (i = 0; i < AW88399_START_RETRIES; i++) { -+ ret = aw88399_dev_start(aw88399); -+ if (ret) { -+ dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i); -+ ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true); -+ if (ret) { -+ dev_err(aw88399->aw_pa->dev, "fw update failed"); -+ continue; -+ } -+ } else { -+ dev_dbg(aw88399->aw_pa->dev, "start success\n"); -+ break; -+ } -+ } -+} -+ -+void aw88399_startup_work(struct work_struct *work) -+{ -+ struct aw88399 *aw88399 = -+ container_of(work, struct aw88399, start_work.work); -+ -+ mutex_lock(&aw88399->lock); -+ aw88399_start_pa(aw88399); -+ mutex_unlock(&aw88399->lock); -+} -+EXPORT_SYMBOL_GPL(aw88399_startup_work); -+ -+void aw88399_start(struct aw88399 *aw88399, bool sync_start) -+{ -+ int ret; -+ -+ if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK) -+ return; -+ -+ if (aw88399->aw_pa->status == AW88399_DEV_PW_ON) -+ return; -+ -+ ret = aw88399_dev_fw_update(aw88399, aw88399->fw_needs_reload ? -+ AW88399_DSP_FW_UPDATE_ON : AW88399_DSP_FW_UPDATE_OFF, true); -+ if (ret) { -+ dev_err(aw88399->aw_pa->dev, "fw update failed."); -+ return; -+ } -+ -+ aw88399->fw_needs_reload = false; -+ -+ if (sync_start == AW88399_SYNC_START) -+ aw88399_start_pa(aw88399); -+ else -+ queue_delayed_work(system_dfl_wq, -+ &aw88399->start_work, -+ AW88399_START_WORK_DELAY_MS); -+} -+EXPORT_SYMBOL_GPL(aw88399_start); -+ -+static int aw_dev_check_sysint(struct aw_device *aw_dev) -+{ -+ u16 reg_val; -+ -+ aw_dev_get_int_status(aw_dev, ®_val); -+ if (reg_val & AW88399_BIT_SYSINT_CHECK) { -+ dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+int aw88399_stop(struct aw_device *aw_dev) -+{ -+ struct aw_sec_data_desc *dsp_cfg = -+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG]; -+ struct aw_sec_data_desc *dsp_fw = -+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW]; -+ int int_st; -+ -+ if (aw_dev->status == AW88399_DEV_PW_OFF) { -+ dev_dbg(aw_dev->dev, "already power off"); -+ return 0; -+ } -+ -+ aw_dev->status = AW88399_DEV_PW_OFF; -+ -+ aw88399_dev_mute(aw_dev, true); -+ usleep_range(AW88399_4000_US, AW88399_4000_US + 100); -+ -+ aw_dev_i2s_tx_enable(aw_dev, false); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100); -+ -+ int_st = aw_dev_check_sysint(aw_dev); -+ -+ aw_dev_dsp_enable(aw_dev, false); -+ -+ aw_dev_amppd(aw_dev, true); -+ -+ if (int_st) { -+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); -+ aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len); -+ aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len); -+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); -+ } -+ -+ aw_dev_pwd(aw_dev, true); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(aw88399_stop); -+ -+static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg) -+{ -+ struct aw_device *aw_dev = aw88399->aw_pa; -+ int ret; -+ -+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); -+ if (ret) { -+ dev_err(aw_dev->dev, "aw_dev acf parse failed"); -+ return -EINVAL; -+ } -+ aw_dev->fade_in_time = AW88399_1000_US / 10; -+ aw_dev->fade_out_time = AW88399_1000_US >> 1; -+ aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id; -+ aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id; -+ -+ ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON); -+ if (ret) { -+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); -+ return ret; -+ } -+ -+ aw88399_dev_mute(aw_dev, true); -+ -+ /* close tx feedback */ -+ aw_dev_i2s_tx_enable(aw_dev, false); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100); -+ -+ /* enable amppd */ -+ aw_dev_amppd(aw_dev, true); -+ -+ /* close dsp */ -+ aw_dev_dsp_enable(aw_dev, false); -+ /* set power down */ -+ aw_dev_pwd(aw_dev, true); -+ -+ return 0; -+} -+ -+int aw88399_request_firmware_file(struct aw88399 *aw88399) -+{ -+ const struct firmware *cont = NULL; -+ int ret; -+ -+ aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED; -+ -+ ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev); -+ if (ret) { -+ dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE); -+ return ret; -+ } -+ -+ dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n", -+ AW88399_ACF_FILE, cont ? cont->size : 0); -+ -+ aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev, -+ struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL); -+ if (!aw88399->aw_cfg) { -+ release_firmware(cont); -+ return -ENOMEM; -+ } -+ aw88399->aw_cfg->len = (int)cont->size; -+ memcpy(aw88399->aw_cfg->data, cont->data, cont->size); -+ release_firmware(cont); -+ -+ ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg); -+ if (ret) { -+ dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE); -+ return ret; -+ } -+ -+ mutex_lock(&aw88399->lock); -+ /* aw device init */ -+ ret = aw88399_dev_init(aw88399, aw88399->aw_cfg); -+ if (ret) -+ dev_err(aw88399->aw_pa->dev, "dev init failed"); -+ mutex_unlock(&aw88399->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(aw88399_request_firmware_file); -+ -+void aw88399_hw_reset(struct aw88399 *aw88399) -+{ -+ if (aw88399->reset_gpio) { -+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -+ gpiod_set_value_cansleep(aw88399->reset_gpio, 0); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1); -+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -+ } -+} -+EXPORT_SYMBOL_GPL(aw88399_hw_reset); -+ -+static void aw88399_parse_channel_dt(struct aw_device *aw_dev) -+{ -+ struct device_node *np = aw_dev->dev->of_node; -+ u32 channel_value; -+ int ret; -+ -+ ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value); -+ if (ret) { -+ /* -+ * On ACPI systems, DT properties don't exist. Derive channel -+ * from I2C address: 0x34 -> channel 0 (left), 0x35 -> channel 1 (right) -+ */ -+ aw_dev->channel = aw_dev->i2c->addr - 0x34; -+ dev_dbg(aw_dev->dev, -+ "DT channel property not found, using I2C address-based channel %d (addr 0x%02x)\n", -+ aw_dev->channel, aw_dev->i2c->addr); -+ return; -+ } -+ aw_dev->channel = channel_value; -+} -+ -+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap) -+{ -+ struct aw_device *aw_dev; -+ unsigned int chip_id; -+ int ret; -+ -+ ret = regmap_read(regmap, AW88399_ID_REG, &chip_id); -+ if (ret) { -+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); -+ return ret; -+ } -+ if (chip_id != AW88399_CHIP_ID) { -+ dev_err(&i2c->dev, "unsupported device"); -+ return -ENXIO; -+ } -+ dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); -+ -+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); -+ if (!aw_dev) -+ return -ENOMEM; -+ aw88399->aw_pa = aw_dev; -+ -+ aw_dev->i2c = i2c; -+ aw_dev->dev = &i2c->dev; -+ aw_dev->regmap = regmap; -+ mutex_init(&aw_dev->dsp_lock); -+ -+ aw_dev->chip_id = chip_id; -+ aw_dev->acf = NULL; -+ aw_dev->prof_info.prof_desc = NULL; -+ aw_dev->prof_info.count = 0; -+ aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; -+ aw_dev->channel = AW88399_DEV_DEFAULT_CH; -+ aw_dev->fw_status = AW88399_DEV_FW_FAILED; -+ -+ aw_dev->fade_step = AW88399_VOLUME_STEP_DB; -+ aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE; -+ -+ aw88399_parse_channel_dt(aw_dev); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(aw88399_init); -+ -+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel) -+{ -+ aw88399->aw_pa->channel = channel; -+} -+EXPORT_SYMBOL_GPL(aw88399_dev_set_channel); -+ -+MODULE_DESCRIPTION("AW88399 common device library"); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c ---- a/sound/soc/codecs/aw88399.c -+++ b/sound/soc/codecs/aw88399.c -@@ -10,1217 +10,12 @@ - #include - #include - #include --#include --#include - #include - #include - #include - #include "aw88399.h" - #include "aw88395/aw88395_device.h" - --static const struct regmap_config aw88399_remap_config = { -- .val_bits = 16, -- .reg_bits = 8, -- .max_register = AW88399_REG_MAX, -- .reg_format_endian = REGMAP_ENDIAN_LITTLE, -- .val_format_endian = REGMAP_ENDIAN_BIG, --}; -- --static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) --{ -- int ret; -- -- if (pwd) -- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE); -- else -- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE); -- -- if (ret) -- dev_dbg(aw_dev->dev, "%s failed", __func__); --} -- --static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status) --{ -- unsigned int reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, ®_val); -- if (ret) -- dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); -- else -- *int_status = reg_val; -- -- dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status); --} -- --static void aw_dev_clear_int_status(struct aw_device *aw_dev) --{ -- u16 int_status; -- -- /* read int status and clear */ -- aw_dev_get_int_status(aw_dev, &int_status); -- /* make sure int status is clear */ -- aw_dev_get_int_status(aw_dev, &int_status); -- if (int_status) -- dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status); --} -- --static int aw_dev_get_iis_status(struct aw_device *aw_dev) --{ -- unsigned int reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); -- if (ret) -- return ret; -- if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) { -- dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val); -- return -EINVAL; -- } -- -- return 0; --} -- --static int aw_dev_check_mode1_pll(struct aw_device *aw_dev) --{ -- int ret, i; -- -- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -- ret = aw_dev_get_iis_status(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "mode1 iis signal check error"); -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- } else { -- return 0; -- } -- } -- -- return -EPERM; --} -- --static int aw_dev_check_mode2_pll(struct aw_device *aw_dev) --{ -- unsigned int reg_val; -- int ret, i; -- -- ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, ®_val); -- if (ret) -- return ret; -- -- reg_val &= (~AW88399_CCO_MUX_MASK); -- if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) { -- dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); -- return -EPERM; -- } -- -- /* change mode2 */ -- ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, -- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE); -- if (ret) -- return ret; -- -- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -- ret = aw_dev_get_iis_status(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "mode2 iis signal check error"); -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- } else { -- break; -- } -- } -- -- /* change mode1 */ -- regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG, -- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE); -- if (ret == 0) { -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -- ret = aw_dev_get_iis_status(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- } else { -- break; -- } -- } -- } -- -- return ret; --} -- --static int aw_dev_check_syspll(struct aw_device *aw_dev) --{ -- int ret; -- -- ret = aw_dev_check_mode1_pll(aw_dev); -- if (ret) { -- dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); -- ret = aw_dev_check_mode2_pll(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "mode2 check iis failed"); -- return ret; -- } -- } -- -- return 0; --} -- --static int aw_dev_check_sysst(struct aw_device *aw_dev) --{ -- unsigned int check_val; -- unsigned int reg_val; -- int ret, i; -- -- ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, ®_val); -- if (ret) -- return ret; -- -- if (reg_val & (~AW88399_NOISE_GATE_EN_MASK)) -- check_val = AW88399_BIT_SYSST_NOSWS_CHECK; -- else -- check_val = AW88399_BIT_SYSST_SWS_CHECK; -- -- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) { -- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, ®_val); -- if (ret) -- return ret; -- -- if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) { -- dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x", -- i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK); -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- } else { -- return 0; -- } -- } -- -- return -EPERM; --} -- --static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) --{ -- int ret; -- -- if (amppd) -- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE); -- else -- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE); -- -- if (ret) -- dev_dbg(aw_dev->dev, "%s failed", __func__); --} -- --static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable) --{ -- int ret; -- -- if (is_enable) -- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE); -- else -- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE); -- -- if (ret) -- dev_dbg(aw_dev->dev, "%s failed\n", __func__); --} -- --static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk) --{ -- uint16_t icalkh_val, icalkl_val, icalk_val; -- struct aw_device *aw_dev = aw88399->aw_pa; -- unsigned int reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, ®_val); -- if (ret) -- return ret; -- icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK); -- -- ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, ®_val); -- if (ret) -- return ret; -- icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK); -- -- if (aw88399->check_val == AW_EF_AND_CHECK) -- icalk_val = icalkh_val & icalkl_val; -- else -- icalk_val = icalkh_val | icalkl_val; -- -- if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK)) -- icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG; -- *icalk = (int16_t)icalk_val; -- -- return 0; --} -- --static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk) --{ -- uint16_t vcalkh_val, vcalkl_val, vcalk_val; -- struct aw_device *aw_dev = aw88399->aw_pa; -- unsigned int reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, ®_val); -- if (ret) -- return ret; -- -- vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK); -- -- ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, ®_val); -- if (ret) -- return ret; -- -- vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK); -- -- if (aw88399->check_val == AW_EF_AND_CHECK) -- vcalk_val = vcalkh_val & vcalkl_val; -- else -- vcalk_val = vcalkh_val | vcalkl_val; -- -- if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK) -- vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG; -- *vcalk = (int16_t)vcalk_val; -- -- return 0; --} -- --static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk) --{ -- uint16_t vcalkh_val, vcalkl_val, vcalk_val; -- struct aw_device *aw_dev = aw88399->aw_pa; -- unsigned int reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, ®_val); -- if (ret) -- return ret; -- vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK); -- -- ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, ®_val); -- if (ret) -- return ret; -- vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK); -- -- if (aw88399->check_val == AW_EF_AND_CHECK) -- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) & -- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); -- else -- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) | -- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT); -- -- if (vcalk_val & (~AW88399_TEM4_SIGN_MASK)) -- vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG; -- -- *vcalk = (int16_t)vcalk_val; -- -- return 0; --} -- --static int aw_dev_set_vcalb(struct aw88399 *aw88399) --{ -- struct aw_device *aw_dev = aw88399->aw_pa; -- unsigned int vsense_select, vsense_value; -- int32_t ical_k, vcal_k, vcalb; -- int16_t icalk, vcalk; -- uint16_t reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value); -- if (ret) -- return ret; -- -- vsense_select = vsense_value & (~AW88399_VDSEL_MASK); -- -- ret = aw88399_dev_get_icalk(aw88399, &icalk); -- if (ret) { -- dev_err(aw_dev->dev, "get icalk failed\n"); -- return ret; -- } -- -- ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE; -- -- switch (vsense_select) { -- case AW88399_DEV_VDSEL_VSENSE: -- ret = aw88399_dev_get_vcalk(aw88399, &vcalk); -- vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE; -- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR * -- ical_k / vcal_k * aw88399->vcalb_init_val; -- break; -- case AW88399_DEV_VDSEL_DAC: -- ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk); -- vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE; -- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR / -- AW88399_ISCAL_DAC_FACTOR * ical_k / -- vcal_k * aw88399->vcalb_init_val; -- break; -- default: -- dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); -- ret = -EINVAL; -- break; -- } -- if (ret) -- return ret; -- -- vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR; -- reg_val = (uint32_t)vcalb; -- -- regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val); -- -- return 0; --} -- --static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc) --{ -- struct aw_device *aw_dev = -- container_of(cali_desc, struct aw_device, cali_desc); -- uint16_t re_lbits, re_hbits; -- u32 cali_re; -- int ret; -- -- if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) || -- (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN)) -- return -EINVAL; -- -- cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + -- aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT); -- -- re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT; -- re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT; -- -- ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits); -- if (ret) { -- dev_err(aw_dev->dev, "set cali re error"); -- return ret; -- } -- -- ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits); -- if (ret) -- dev_err(aw_dev->dev, "set cali re error"); -- -- return ret; --} -- --static int aw_dev_fw_crc_check(struct aw_device *aw_dev) --{ -- uint16_t check_val, fw_len_val; -- unsigned int reg_val; -- int ret; -- -- /* calculate fw_end_addr */ -- fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR; -- -- /* write fw_end_addr to crc_end_addr */ -- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -- ~AW88399_CRC_END_ADDR_MASK, fw_len_val); -- if (ret) -- return ret; -- /* enable fw crc check */ -- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE); -- -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- -- /* read crc check result */ -- regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); -- if (ret) -- return ret; -- -- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; -- -- /* disable fw crc check */ -- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE); -- if (ret) -- return ret; -- -- if (check_val != AW88399_CRC_CHECK_PASS_VAL) { -- dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x", -- __func__, check_val, AW88399_CRC_CHECK_PASS_VAL); -- ret = -EINVAL; -- } -- -- return ret; --} -- --static int aw_dev_cfg_crc_check(struct aw_device *aw_dev) --{ -- uint16_t check_val, cfg_len_val; -- unsigned int reg_val; -- int ret; -- -- /* calculate cfg end addr */ -- cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR; -- -- /* write cfg_end_addr to crc_end_addr */ -- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -- ~AW88399_CRC_END_ADDR_MASK, cfg_len_val); -- if (ret) -- return ret; -- -- /* enable cfg crc check */ -- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE); -- if (ret) -- return ret; -- -- usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -- -- /* read crc check result */ -- ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, ®_val); -- if (ret) -- return ret; -- -- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT; -- -- /* disable cfg crc check */ -- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG, -- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE); -- if (ret) -- return ret; -- -- if (check_val != AW88399_CRC_CHECK_PASS_VAL) { -- dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x", -- check_val, AW88399_CRC_CHECK_PASS_VAL); -- ret = -EINVAL; -- } -- -- return ret; --} -- --static int aw_dev_hw_crc_check(struct aw88399 *aw88399) --{ -- struct aw_device *aw_dev = aw88399->aw_pa; -- int ret; -- -- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE); -- if (ret) -- return ret; -- -- ret = aw_dev_fw_crc_check(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "fw_crc_check failed\n"); -- goto crc_check_failed; -- } -- -- ret = aw_dev_cfg_crc_check(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "cfg_crc_check failed\n"); -- goto crc_check_failed; -- } -- -- ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val); -- if (ret) -- return ret; -- -- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); -- -- return ret; -- --crc_check_failed: -- regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE); -- return ret; --} -- --static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) --{ -- int ret; -- -- if (flag) -- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG, -- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE); -- else -- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG, -- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE); -- -- if (ret) -- dev_dbg(aw_dev->dev, "%s failed", __func__); --} -- --static int aw_dev_get_dsp_status(struct aw_device *aw_dev) --{ -- unsigned int reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, ®_val); -- if (ret) -- return ret; -- if (!(reg_val & (~AW88399_WDT_CNT_MASK))) -- return -EPERM; -- -- return 0; --} -- --static int aw_dev_dsp_check(struct aw_device *aw_dev) --{ -- int ret, i; -- -- switch (aw_dev->dsp_cfg) { -- case AW88399_DEV_DSP_BYPASS: -- dev_dbg(aw_dev->dev, "dsp bypass"); -- ret = 0; -- break; -- case AW88399_DEV_DSP_WORK: -- aw_dev_dsp_enable(aw_dev, false); -- aw_dev_dsp_enable(aw_dev, true); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -- for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) { -- ret = aw_dev_get_dsp_status(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "dsp wdt status error=%d", ret); -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- } -- } -- break; -- default: -- dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg); -- ret = -EINVAL; -- break; -- } -- -- return ret; --} -- --static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value) --{ -- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; -- unsigned int reg_value; -- u16 real_value; -- int ret; -- -- real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL); -- -- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, ®_value); -- if (ret) -- return ret; -- -- dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value); -- -- real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK); -- -- ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value); -- -- return ret; --} -- --static void aw_dev_fade_in(struct aw_device *aw_dev) --{ -- struct aw_volume_desc *desc = &aw_dev->volume_desc; -- u16 fade_in_vol = desc->ctl_volume; -- int fade_step = aw_dev->fade_step; -- int i; -- -- if (fade_step == 0 || aw_dev->fade_in_time == 0) { -- aw_dev_set_volume(aw_dev, fade_in_vol); -- return; -- } -- -- for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { -- aw_dev_set_volume(aw_dev, i); -- usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); -- } -- -- if (i != fade_in_vol) -- aw_dev_set_volume(aw_dev, fade_in_vol); --} -- --static void aw_dev_fade_out(struct aw_device *aw_dev) --{ -- struct aw_volume_desc *desc = &aw_dev->volume_desc; -- int fade_step = aw_dev->fade_step; -- int i; -- -- if (fade_step == 0 || aw_dev->fade_out_time == 0) { -- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); -- return; -- } -- -- for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) { -- aw_dev_set_volume(aw_dev, i); -- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); -- } -- -- if (i != AW88399_MUTE_VOL) { -- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL); -- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); -- } --} -- --static void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute) --{ -- if (is_mute) { -- aw_dev_fade_out(aw_dev); -- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE); -- } else { -- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG, -- ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE); -- aw_dev_fade_in(aw_dev); -- } --} -- --static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither) --{ -- struct aw_device *aw_dev = aw88399->aw_pa; -- -- if (dither) -- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE); -- else -- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE); --} -- --static int aw88399_dev_start(struct aw88399 *aw88399) --{ -- struct aw_device *aw_dev = aw88399->aw_pa; -- int ret; -- -- if (aw_dev->status == AW88399_DEV_PW_ON) { -- dev_dbg(aw_dev->dev, "already power on"); -- return 0; -- } -- -- aw88399_dev_set_dither(aw88399, false); -- -- /* power on */ -- aw_dev_pwd(aw_dev, false); -- usleep_range(AW88399_2000_US, AW88399_2000_US + 10); -- -- ret = aw_dev_check_syspll(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "pll check failed cannot start"); -- goto pll_check_fail; -- } -- -- /* amppd on */ -- aw_dev_amppd(aw_dev, false); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 50); -- -- /* check i2s status */ -- ret = aw_dev_check_sysst(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "sysst check failed"); -- goto sysst_check_fail; -- } -- -- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) { -- ret = aw_dev_hw_crc_check(aw88399); -- if (ret) { -- dev_err(aw_dev->dev, "dsp crc check failed"); -- goto crc_check_fail; -- } -- aw_dev_dsp_enable(aw_dev, false); -- aw_dev_set_vcalb(aw88399); -- aw_dev_update_cali_re(&aw_dev->cali_desc); -- -- ret = aw_dev_dsp_check(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "dsp status check failed"); -- goto dsp_check_fail; -- } -- } else { -- dev_dbg(aw_dev->dev, "start pa with dsp bypass"); -- } -- -- /* enable tx feedback */ -- aw_dev_i2s_tx_enable(aw_dev, true); -- -- if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE) -- aw88399_dev_set_dither(aw88399, true); -- -- /* close mute */ -- aw88399_dev_mute(aw_dev, false); -- /* clear inturrupt */ -- aw_dev_clear_int_status(aw_dev); -- aw_dev->status = AW88399_DEV_PW_ON; -- -- return 0; -- --dsp_check_fail: --crc_check_fail: -- aw_dev_dsp_enable(aw_dev, false); --sysst_check_fail: -- aw_dev_clear_int_status(aw_dev); -- aw_dev_amppd(aw_dev, true); --pll_check_fail: -- aw_dev_pwd(aw_dev, true); -- aw_dev->status = AW88399_DEV_PW_OFF; -- -- return ret; --} -- --static int aw_dev_dsp_update_container(struct aw_device *aw_dev, -- unsigned char *data, unsigned int len, unsigned short base) --{ -- u32 tmp_len; -- int i, ret; -- -- ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base); -- if (ret) -- return ret; -- -- for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) { -- tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE); -- ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG, -- &data[i], tmp_len); -- if (ret) -- return ret; -- } -- -- return 0; --} -- --static int aw_dev_get_ra(struct aw_cali_desc *cali_desc) --{ -- struct aw_device *aw_dev = -- container_of(cali_desc, struct aw_device, cali_desc); -- u32 dsp_ra; -- int ret; -- -- ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA, -- &dsp_ra, AW_DSP_32_DATA); -- if (ret) { -- dev_err(aw_dev->dev, "read ra error"); -- return ret; -- } -- -- cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra, -- AW88399_DSP_RE_SHIFT); -- -- return 0; --} -- --static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev, -- unsigned char *data, unsigned int len) --{ -- int ret; -- -- dev_dbg(aw_dev->dev, "dsp config len:%d", len); -- -- if (!len || !data) { -- dev_err(aw_dev->dev, "dsp config data is null or len is 0"); -- return -EINVAL; -- } -- -- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR); -- if (ret) -- return ret; -- -- aw_dev->dsp_cfg_len = len; -- -- ret = aw_dev_get_ra(&aw_dev->cali_desc); -- -- return ret; --} -- --static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, -- unsigned char *data, unsigned int len) --{ -- int ret; -- -- dev_dbg(aw_dev->dev, "dsp firmware len:%d", len); -- -- if (!len || !data) { -- dev_err(aw_dev->dev, "dsp firmware data is null or len is 0"); -- return -EINVAL; -- } -- -- aw_dev->dsp_fw_len = len; -- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR); -- -- return ret; --} -- --static int aw_dev_check_sram(struct aw_device *aw_dev) --{ -- unsigned int reg_val; -- -- /* read dsp_rom_check_reg */ -- aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, ®_val, AW_DSP_16_DATA); -- if (reg_val != AW88399_DSP_ROM_CHECK_DATA) { -- dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]", -- reg_val, AW88399_DSP_ROM_CHECK_DATA); -- return -EPERM; -- } -- -- /* check dsp_cfg_base_addr */ -- aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR, -- AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA); -- aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, ®_val, AW_DSP_16_DATA); -- if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) { -- dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", -- reg_val, AW88399_DSP_ODD_NUM_BIT_TEST); -- return -EPERM; -- } -- -- return 0; --} -- --static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag) --{ -- int ret; -- -- switch (flag) { -- case AW88399_DEV_MEMCLK_PLL: -- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -- ~AW88399_MEM_CLKSEL_MASK, -- AW88399_MEM_CLKSEL_DAPHCLK_VALUE); -- if (ret) -- dev_err(aw_dev->dev, "memclk select pll failed"); -- break; -- case AW88399_DEV_MEMCLK_OSC: -- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG, -- ~AW88399_MEM_CLKSEL_MASK, -- AW88399_MEM_CLKSEL_OSCCLK_VALUE); -- if (ret) -- dev_err(aw_dev->dev, "memclk select OSC failed"); -- break; -- default: -- dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag); -- break; -- } --} -- --static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev) --{ -- struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc; -- unsigned int reg_val; -- int ret; -- -- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, ®_val); -- if (ret) { -- dev_dbg(aw_dev->dev, "%s failed", __func__); -- return; -- } -- if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE) -- profctrl_desc->cur_mode = AW88399_RCV_MODE; -- else -- profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE; --} -- --static int aw_dev_update_reg_container(struct aw88399 *aw88399, -- unsigned char *data, unsigned int len) --{ -- struct aw_device *aw_dev = aw88399->aw_pa; -- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; -- u16 read_vol, reg_val; -- int data_len, i, ret; -- int16_t *reg_data; -- u8 reg_addr; -- -- reg_data = (int16_t *)data; -- data_len = len >> 1; -- -- if (data_len & 0x1) { -- dev_err(aw_dev->dev, "data len:%d unsupported", data_len); -- return -EINVAL; -- } -- -- for (i = 0; i < data_len; i += 2) { -- reg_addr = reg_data[i]; -- reg_val = reg_data[i + 1]; -- -- if (reg_addr == AW88399_DSPVCALB_REG) { -- aw88399->vcalb_init_val = reg_val; -- continue; -- } -- -- if (reg_addr == AW88399_SYSCTRL_REG) { -- if (reg_val & (~AW88399_DSPBY_MASK)) -- aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS; -- else -- aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK; -- -- reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK | -- AW88399_DSPBY_MASK); -- reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE | -- AW88399_DSPBY_BYPASS_VALUE); -- } -- -- if (reg_addr == AW88399_I2SCTRL3_REG) { -- reg_val &= AW88399_I2STXEN_MASK; -- reg_val |= AW88399_I2STXEN_DISABLE_VALUE; -- } -- -- if (reg_addr == AW88399_SYSCTRL2_REG) { -- read_vol = (reg_val & (~AW88399_VOL_MASK)) >> -- AW88399_VOL_START_BIT; -- aw_dev->volume_desc.init_volume = read_vol; -- } -- -- if (reg_addr == AW88399_DBGCTRL_REG) { -- if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE) -- aw88399->check_val = AW_EF_OR_CHECK; -- else -- aw88399->check_val = AW_EF_AND_CHECK; -- -- aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK); -- } -- -- if (reg_addr == AW88399_CRCCTRL_REG) -- aw88399->crc_init_val = reg_val; -- -- ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); -- if (ret) -- return ret; -- } -- -- aw_dev_pwd(aw_dev, false); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -- -- aw_dev_get_cur_mode_st(aw_dev); -- -- if (aw_dev->prof_cur != aw_dev->prof_index) -- vol_desc->ctl_volume = 0; -- else -- aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); -- -- return 0; --} -- --static int aw_dev_reg_update(struct aw88399 *aw88399, -- unsigned char *data, unsigned int len) --{ -- int ret; -- -- if (!len || !data) { -- dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0"); -- return -EINVAL; -- } -- -- ret = aw_dev_update_reg_container(aw88399, data, len); -- if (ret) -- dev_err(aw88399->aw_pa->dev, "reg update failed"); -- -- return ret; --} -- --static int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) --{ -- struct aw_prof_info *prof_info = &aw_dev->prof_info; -- struct aw_prof_desc *prof_desc; -- -- if ((index >= aw_dev->prof_info.count) || (index < 0)) { -- dev_err(aw_dev->dev, "index[%d] overflow count[%d]", -- index, aw_dev->prof_info.count); -- return -EINVAL; -- } -- -- prof_desc = &aw_dev->prof_info.prof_desc[index]; -- -- *prof_name = prof_info->prof_name_list[prof_desc->id]; -- -- return 0; --} -- --static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index, -- struct aw_prof_desc **prof_desc) --{ -- if ((index >= aw_dev->prof_info.count) || (index < 0)) { -- dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", -- __func__, index, aw_dev->prof_info.count); -- return -EINVAL; -- } -- -- *prof_desc = &aw_dev->prof_info.prof_desc[index]; -- -- return 0; --} -- --static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en) --{ -- struct aw_device *aw_dev = aw88399->aw_pa; -- struct aw_prof_desc *prof_index_desc; -- struct aw_sec_data_desc *sec_desc; -- char *prof_name; -- int ret; -- -- if ((aw_dev->prof_cur == aw_dev->prof_index) && -- (force_up_en == AW88399_FORCE_UPDATE_OFF)) { -- dev_dbg(aw_dev->dev, "scene no change, not update"); -- return 0; -- } -- -- if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) { -- dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status); -- return -EPERM; -- } -- -- ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); -- if (ret) -- return ret; -- -- dev_dbg(aw_dev->dev, "start update %s", prof_name); -- -- ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); -- if (ret) -- return ret; -- -- /* update reg */ -- sec_desc = prof_index_desc->sec_desc; -- ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data, -- sec_desc[AW88395_DATA_TYPE_REG].len); -- if (ret) { -- dev_err(aw_dev->dev, "update reg failed"); -- return ret; -- } -- -- aw88399_dev_mute(aw_dev, true); -- -- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) -- aw_dev_dsp_enable(aw_dev, false); -- -- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); -- -- ret = aw_dev_check_sram(aw_dev); -- if (ret) { -- dev_err(aw_dev->dev, "check sram failed"); -- goto error; -- } -- -- if (up_dsp_fw_en) { -- dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver); -- ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data, -- sec_desc[AW88395_DATA_TYPE_DSP_FW].len); -- if (ret) { -- dev_err(aw_dev->dev, "update dsp fw failed"); -- goto error; -- } -- } -- -- /* update dsp config */ -- ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data, -- sec_desc[AW88395_DATA_TYPE_DSP_CFG].len); -- if (ret) { -- dev_err(aw_dev->dev, "update dsp cfg failed"); -- goto error; -- } -- -- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); -- -- aw_dev->prof_cur = aw_dev->prof_index; -- -- return 0; -- --error: -- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); -- return ret; --} -- --static void aw88399_start_pa(struct aw88399 *aw88399) --{ -- int ret, i; -- -- for (i = 0; i < AW88399_START_RETRIES; i++) { -- ret = aw88399_dev_start(aw88399); -- if (ret) { -- dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i); -- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true); -- if (ret) { -- dev_err(aw88399->aw_pa->dev, "fw update failed"); -- continue; -- } -- } else { -- dev_dbg(aw88399->aw_pa->dev, "start success\n"); -- break; -- } -- } --} -- --static void aw88399_startup_work(struct work_struct *work) --{ -- struct aw88399 *aw88399 = -- container_of(work, struct aw88399, start_work.work); -- -- mutex_lock(&aw88399->lock); -- aw88399_start_pa(aw88399); -- mutex_unlock(&aw88399->lock); --} -- --static void aw88399_start(struct aw88399 *aw88399, bool sync_start) --{ -- int ret; -- -- if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK) -- return; -- -- if (aw88399->aw_pa->status == AW88399_DEV_PW_ON) -- return; -- -- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true); -- if (ret) { -- dev_err(aw88399->aw_pa->dev, "fw update failed."); -- return; -- } -- -- if (sync_start == AW88399_SYNC_START) -- aw88399_start_pa(aw88399); -- else -- queue_delayed_work(system_dfl_wq, -- &aw88399->start_work, -- AW88399_START_WORK_DELAY_MS); --} -- --static int aw_dev_check_sysint(struct aw_device *aw_dev) --{ -- u16 reg_val; -- -- aw_dev_get_int_status(aw_dev, ®_val); -- if (reg_val & AW88399_BIT_SYSINT_CHECK) { -- dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val); -- return -EINVAL; -- } -- -- return 0; --} -- --static int aw88399_stop(struct aw_device *aw_dev) --{ -- struct aw_sec_data_desc *dsp_cfg = -- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG]; -- struct aw_sec_data_desc *dsp_fw = -- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW]; -- int int_st; -- -- if (aw_dev->status == AW88399_DEV_PW_OFF) { -- dev_dbg(aw_dev->dev, "already power off"); -- return 0; -- } -- -- aw_dev->status = AW88399_DEV_PW_OFF; -- -- aw88399_dev_mute(aw_dev, true); -- usleep_range(AW88399_4000_US, AW88399_4000_US + 100); -- -- aw_dev_i2s_tx_enable(aw_dev, false); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 100); -- -- int_st = aw_dev_check_sysint(aw_dev); -- -- aw_dev_dsp_enable(aw_dev, false); -- -- aw_dev_amppd(aw_dev, true); -- -- if (int_st) { -- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC); -- aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len); -- aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len); -- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL); -- } -- -- aw_dev_pwd(aw_dev, true); -- -- return 0; --} -- - static struct snd_soc_dai_driver aw88399_dai[] = { - { - .name = "aw88399-aif", -@@ -1869,86 +664,6 @@ static int aw88399_calib_set(struct snd_kcontrol *kcontrol, - return 0; - } - --static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg) --{ -- struct aw_device *aw_dev = aw88399->aw_pa; -- int ret; -- -- ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); -- if (ret) { -- dev_err(aw_dev->dev, "aw_dev acf parse failed"); -- return -EINVAL; -- } -- aw_dev->fade_in_time = AW88399_1000_US / 10; -- aw_dev->fade_out_time = AW88399_1000_US >> 1; -- aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id; -- aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id; -- -- ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON); -- if (ret) { -- dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); -- return ret; -- } -- -- aw88399_dev_mute(aw_dev, true); -- -- /* close tx feedback */ -- aw_dev_i2s_tx_enable(aw_dev, false); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 100); -- -- /* enable amppd */ -- aw_dev_amppd(aw_dev, true); -- -- /* close dsp */ -- aw_dev_dsp_enable(aw_dev, false); -- /* set power down */ -- aw_dev_pwd(aw_dev, true); -- -- return 0; --} -- --static int aw88399_request_firmware_file(struct aw88399 *aw88399) --{ -- const struct firmware *cont = NULL; -- int ret; -- -- aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED; -- -- ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev); -- if (ret) { -- dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE); -- return ret; -- } -- -- dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n", -- AW88399_ACF_FILE, cont ? cont->size : 0); -- -- aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev, -- struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL); -- if (!aw88399->aw_cfg) { -- release_firmware(cont); -- return -ENOMEM; -- } -- aw88399->aw_cfg->len = (int)cont->size; -- memcpy(aw88399->aw_cfg->data, cont->data, cont->size); -- release_firmware(cont); -- -- ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg); -- if (ret) { -- dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE); -- return ret; -- } -- -- mutex_lock(&aw88399->lock); -- /* aw device init */ -- ret = aw88399_dev_init(aw88399, aw88399->aw_cfg); -- if (ret) -- dev_err(aw88399->aw_pa->dev, "dev init failed"); -- mutex_unlock(&aw88399->lock); -- -- return ret; --} -- - static const struct snd_kcontrol_new aw88399_controls[] = { - SOC_SINGLE_EXT("PCM Playback Volume", AW88399_SYSCTRL2_REG, - 6, AW88399_MUTE_VOL, 0, aw88399_volume_get, -@@ -2040,70 +755,6 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88399 = { - .num_controls = ARRAY_SIZE(aw88399_controls), - }; - --static void aw88399_hw_reset(struct aw88399 *aw88399) --{ -- if (aw88399->reset_gpio) { -- gpiod_set_value_cansleep(aw88399->reset_gpio, 1); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -- gpiod_set_value_cansleep(aw88399->reset_gpio, 0); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -- gpiod_set_value_cansleep(aw88399->reset_gpio, 1); -- usleep_range(AW88399_1000_US, AW88399_1000_US + 10); -- } --} -- --static void aw88399_parse_channel_dt(struct aw_device *aw_dev) --{ -- struct device_node *np = aw_dev->dev->of_node; -- u32 channel_value; -- -- of_property_read_u32(np, "awinic,audio-channel", &channel_value); -- aw_dev->channel = channel_value; --} -- --static int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap) --{ -- struct aw_device *aw_dev; -- unsigned int chip_id; -- int ret; -- -- ret = regmap_read(regmap, AW88399_ID_REG, &chip_id); -- if (ret) { -- dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); -- return ret; -- } -- if (chip_id != AW88399_CHIP_ID) { -- dev_err(&i2c->dev, "unsupported device"); -- return -ENXIO; -- } -- dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); -- -- aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); -- if (!aw_dev) -- return -ENOMEM; -- aw88399->aw_pa = aw_dev; -- -- aw_dev->i2c = i2c; -- aw_dev->dev = &i2c->dev; -- aw_dev->regmap = regmap; -- mutex_init(&aw_dev->dsp_lock); -- -- aw_dev->chip_id = chip_id; -- aw_dev->acf = NULL; -- aw_dev->prof_info.prof_desc = NULL; -- aw_dev->prof_info.count = 0; -- aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; -- aw_dev->channel = AW88399_DEV_DEFAULT_CH; -- aw_dev->fw_status = AW88399_DEV_FW_FAILED; -- -- aw_dev->fade_step = AW88399_VOLUME_STEP_DB; -- aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE; -- -- aw88399_parse_channel_dt(aw_dev); -- -- return 0; --} -- - static int aw88399_i2c_probe(struct i2c_client *i2c) - { - struct aw88399 *aw88399; -diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h ---- a/sound/soc/codecs/aw88399.h -+++ b/sound/soc/codecs/aw88399.h -@@ -10,512 +10,10 @@ - #ifndef __AW88399_H__ - #define __AW88399_H__ - --/* registers list */ --#define AW88399_ID_REG (0x00) --#define AW88399_SYSST_REG (0x01) --#define AW88399_SYSINT_REG (0x02) --#define AW88399_SYSINTM_REG (0x03) --#define AW88399_SYSCTRL_REG (0x04) --#define AW88399_SYSCTRL2_REG (0x05) --#define AW88399_I2SCTRL1_REG (0x06) --#define AW88399_I2SCTRL2_REG (0x07) --#define AW88399_I2SCTRL3_REG (0x08) --#define AW88399_DACCFG1_REG (0x09) --#define AW88399_DACCFG2_REG (0x0A) --#define AW88399_DACCFG3_REG (0x0B) --#define AW88399_DACCFG4_REG (0x0C) --#define AW88399_DACCFG5_REG (0x0D) --#define AW88399_DACCFG6_REG (0x0E) --#define AW88399_DACCFG7_REG (0x0F) --#define AW88399_MPDCFG1_REG (0x10) --#define AW88399_MPDCFG2_REG (0x11) --#define AW88399_MPDCFG3_REG (0x12) --#define AW88399_MPDCFG4_REG (0x13) --#define AW88399_PWMCTRL1_REG (0x14) --#define AW88399_PWMCTRL2_REG (0x15) --#define AW88399_PWMCTRL3_REG (0x16) --#define AW88399_I2SCFG1_REG (0x17) --#define AW88399_DBGCTRL_REG (0x18) --#define AW88399_HAGCST_REG (0x20) --#define AW88399_VBAT_REG (0x21) --#define AW88399_TEMP_REG (0x22) --#define AW88399_PVDD_REG (0x23) --#define AW88399_ISNDAT_REG (0x24) --#define AW88399_VSNDAT_REG (0x25) --#define AW88399_I2SINT_REG (0x26) --#define AW88399_I2SCAPCNT_REG (0x27) --#define AW88399_ANASTA1_REG (0x28) --#define AW88399_ANASTA2_REG (0x29) --#define AW88399_ANASTA3_REG (0x2A) --#define AW88399_TESTDET_REG (0x2B) --#define AW88399_DSMCFG1_REG (0x30) --#define AW88399_DSMCFG2_REG (0x31) --#define AW88399_DSMCFG3_REG (0x32) --#define AW88399_DSMCFG4_REG (0x33) --#define AW88399_DSMCFG5_REG (0x34) --#define AW88399_DSMCFG6_REG (0x35) --#define AW88399_DSMCFG7_REG (0x36) --#define AW88399_DSMCFG8_REG (0x37) --#define AW88399_TESTIN_REG (0x38) --#define AW88399_TESTOUT_REG (0x39) --#define AW88399_MEMTEST_REG (0x3A) --#define AW88399_VSNCTRL1_REG (0x3B) --#define AW88399_ISNCTRL1_REG (0x3C) --#define AW88399_ISNCTRL2_REG (0x3D) --#define AW88399_DSPMADD_REG (0x40) --#define AW88399_DSPMDAT_REG (0x41) --#define AW88399_WDT_REG (0x42) --#define AW88399_ACR1_REG (0x43) --#define AW88399_ACR2_REG (0x44) --#define AW88399_ASR1_REG (0x45) --#define AW88399_ASR2_REG (0x46) --#define AW88399_DSPCFG_REG (0x47) --#define AW88399_ASR3_REG (0x48) --#define AW88399_ASR4_REG (0x49) --#define AW88399_DSPVCALB_REG (0x4A) --#define AW88399_CRCCTRL_REG (0x4B) --#define AW88399_DSPDBG1_REG (0x4C) --#define AW88399_DSPDBG2_REG (0x4D) --#define AW88399_DSPDBG3_REG (0x4E) --#define AW88399_PLLCTRL1_REG (0x50) --#define AW88399_PLLCTRL2_REG (0x51) --#define AW88399_PLLCTRL3_REG (0x52) --#define AW88399_CDACTRL1_REG (0x53) --#define AW88399_CDACTRL2_REG (0x54) --#define AW88399_CDACTRL3_REG (0x55) --#define AW88399_SADCCTRL1_REG (0x56) --#define AW88399_SADCCTRL2_REG (0x57) --#define AW88399_BOPCTRL1_REG (0x58) --#define AW88399_BOPCTRL2_REG (0x5A) --#define AW88399_BOPCTRL3_REG (0x5B) --#define AW88399_BOPCTRL4_REG (0x5C) --#define AW88399_BOPCTRL5_REG (0x5D) --#define AW88399_BOPCTRL6_REG (0x5E) --#define AW88399_BOPCTRL7_REG (0x5F) --#define AW88399_BSTCTRL1_REG (0x60) --#define AW88399_BSTCTRL2_REG (0x61) --#define AW88399_BSTCTRL3_REG (0x62) --#define AW88399_BSTCTRL4_REG (0x63) --#define AW88399_BSTCTRL5_REG (0x64) --#define AW88399_BSTCTRL6_REG (0x65) --#define AW88399_BSTCTRL7_REG (0x66) --#define AW88399_BSTCTRL8_REG (0x67) --#define AW88399_BSTCTRL9_REG (0x68) --#define AW88399_BSTCTRL10_REG (0x69) --#define AW88399_CPCTRL_REG (0x6A) --#define AW88399_EFWH_REG (0x6C) --#define AW88399_EFWM2_REG (0x6D) --#define AW88399_EFWM1_REG (0x6E) --#define AW88399_EFWL_REG (0x6F) --#define AW88399_TESTCTRL1_REG (0x70) --#define AW88399_TESTCTRL2_REG (0x71) --#define AW88399_EFCTRL1_REG (0x72) --#define AW88399_EFCTRL2_REG (0x73) --#define AW88399_EFRH4_REG (0x74) --#define AW88399_EFRH3_REG (0x75) --#define AW88399_EFRH2_REG (0x76) --#define AW88399_EFRH1_REG (0x77) --#define AW88399_EFRL4_REG (0x78) --#define AW88399_EFRL3_REG (0x79) --#define AW88399_EFRL2_REG (0x7A) --#define AW88399_EFRL1_REG (0x7B) --#define AW88399_TM_REG (0x7C) --#define AW88399_TM2_REG (0x7D) -- --#define AW88399_REG_MAX (0x7E) --#define AW88399_MUTE_VOL (1023) -- --#define AW88399_DSP_CFG_ADDR (0x9B00) --#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68) --#define AW88399_DSP_FW_ADDR (0x8980) --#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40) --#define AW88399_DSP_ROM_CHECK_DATA (0x4638) -- --#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000)) --#define AW88399_CALI_RE_HBITS_SHIFT (16) -- --#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF)) --#define AW88399_CALI_RE_LBITS_SHIFT (0) -- --#define AW88399_I2STXEN_START_BIT (9) --#define AW88399_I2STXEN_BITS_LEN (1) --#define AW88399_I2STXEN_MASK \ -- (~(((1<> (shift)) --#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000)) --#define AW88399_CRC_CHECK_PASS_VAL (0x4) -- --#define AW88399_CRC_CFG_BASE_ADDR (0xD80) --#define AW88399_CRC_FW_BASE_ADDR (0x4C0) --#define AW88399_ACF_FILE "aw88399_acf.bin" --#define AW88399_DEV_SYSST_CHECK_MAX (10) --#define AW88399_CHIP_ID 0x2183 -+#include - - #define AW88399_I2C_NAME "aw88399" - --#define AW88399_START_RETRIES (5) --#define AW88399_START_WORK_DELAY_MS (0) -- - #define AW88399_RATES (SNDRV_PCM_RATE_8000_48000 | \ - SNDRV_PCM_RATE_96000) - #define AW88399_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ -@@ -550,80 +48,4 @@ - .put = profile_set, \ - } - --enum { -- AW_EF_AND_CHECK = 0, -- AW_EF_OR_CHECK, --}; -- --enum { -- AW88399_DEV_VDSEL_DAC = 0, -- AW88399_DEV_VDSEL_VSENSE = 32, --}; -- --enum { -- AW88399_DSP_CRC_NA = 0, -- AW88399_DSP_CRC_OK = 1, --}; -- --enum { -- AW88399_DSP_FW_UPDATE_OFF = 0, -- AW88399_DSP_FW_UPDATE_ON = 1, --}; -- --enum { -- AW88399_FORCE_UPDATE_OFF = 0, -- AW88399_FORCE_UPDATE_ON = 1, --}; -- --enum { -- AW88399_1000_US = 1000, -- AW88399_2000_US = 2000, -- AW88399_3000_US = 3000, -- AW88399_4000_US = 4000, --}; -- --enum AW88399_DEV_STATUS { -- AW88399_DEV_PW_OFF = 0, -- AW88399_DEV_PW_ON, --}; -- --enum AW88399_DEV_FW_STATUS { -- AW88399_DEV_FW_FAILED = 0, -- AW88399_DEV_FW_OK, --}; -- --enum AW88399_DEV_MEMCLK { -- AW88399_DEV_MEMCLK_OSC = 0, -- AW88399_DEV_MEMCLK_PLL = 1, --}; -- --enum AW88399_DEV_DSP_CFG { -- AW88399_DEV_DSP_WORK = 0, -- AW88399_DEV_DSP_BYPASS = 1, --}; -- --enum { -- AW88399_NOT_RCV_MODE = 0, -- AW88399_RCV_MODE = 1, --}; -- --enum { -- AW88399_SYNC_START = 0, -- AW88399_ASYNC_START, --}; -- --struct aw88399 { -- struct aw_device *aw_pa; -- struct mutex lock; -- struct gpio_desc *reset_gpio; -- struct delayed_work start_work; -- struct regmap *regmap; -- struct aw_container *aw_cfg; -- -- unsigned int check_val; -- unsigned int crc_init_val; -- unsigned int vcalb_init_val; -- unsigned int dither_st; --}; -- --#endif -+#endif /* __AW88399_H__ */ -diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c ---- a/sound/soc/codecs/tas2781-fmwlib.c -+++ b/sound/soc/codecs/tas2781-fmwlib.c -@@ -1849,16 +1849,26 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv, - } - } - if (ret == -EAGAIN) { -- if (block->nr_retry > 0) -+ if (block->nr_retry > 0) { -+ /* Give the hardware time to stabilize before -+ * next block re-transmission attempt. -+ */ -+ usleep_range(2000, 2500); - continue; -+ } - } else if (ret < 0) /*err in current device, skip it*/ - break; - - if (block->is_pchksum_present) { - ret = tasdev_block_chksum(tas_priv, block, chn); - if (ret == -EAGAIN) { -- if (block->nr_retry > 0) -+ if (block->nr_retry > 0) { -+ /* Give the bus time to recover after -+ * a checksum mismatch error. -+ */ -+ usleep_range(2000, 2500); - continue; -+ } - } else if (ret < 0) /*err in current device, skip it*/ - break; - } -diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c ---- a/sound/soc/fsl/fsl-asoc-card.c -+++ b/sound/soc/fsl/fsl-asoc-card.c -@@ -1118,7 +1118,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - } - - ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt); -- priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt; -+ priv->asrc_format = asrc_fmt; - if (ret) { - /* Fallback to old binding; translate to asrc_format */ - ret = of_property_read_u32(asrc_np, "fsl,asrc-width", -diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c ---- a/sound/soc/fsl/fsl_asrc.c -+++ b/sound/soc/fsl/fsl_asrc.c -@@ -1358,7 +1358,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) - } - - ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); -- asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; -+ asrc->asrc_format = asrc_fmt; - if (ret) { - ret = of_property_read_u32(np, "fsl,asrc-width", &width); - if (ret) { -diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c ---- a/sound/soc/fsl/fsl_asrc_m2m.c -+++ b/sound/soc/fsl/fsl_asrc_m2m.c -@@ -367,13 +367,13 @@ static int fsl_asrc_m2m_comp_set_params(struct snd_compr_stream *stream, - if (ret) - return -EINVAL; - -- if (pcm_format_to_bits((__force snd_pcm_format_t)params->codec.format) & cap.fmt_in) -- pair->sample_format[IN] = (__force snd_pcm_format_t)params->codec.format; -+ if (pcm_format_to_bits(params->codec.format) & cap.fmt_in) -+ pair->sample_format[IN] = params->codec.format; - else - return -EINVAL; - -- if (pcm_format_to_bits((__force snd_pcm_format_t)params->codec.pcm_format) & cap.fmt_out) -- pair->sample_format[OUT] = (__force snd_pcm_format_t)params->codec.pcm_format; -+ if (pcm_format_to_bits(params->codec.pcm_format) & cap.fmt_out) -+ pair->sample_format[OUT] = params->codec.pcm_format; - else - return -EINVAL; - -@@ -600,7 +600,7 @@ static int fsl_asrc_m2m_fill_codec_caps(struct fsl_asrc *asrc, - cap.rate_in, - cap.rate_in_count * sizeof(__u32)); - codec->descriptor[j].num_sample_rates = cap.rate_in_count; -- codec->descriptor[j].formats = (__force __u32)k; -+ codec->descriptor[j].formats = k; - codec->descriptor[j].pcm_formats = cap.fmt_out; - codec->descriptor[j].src.out_sample_rate_min = cap.rate_out[0]; - codec->descriptor[j].src.out_sample_rate_max = -diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c ---- a/sound/soc/fsl/fsl_easrc.c -+++ b/sound/soc/fsl/fsl_easrc.c -@@ -2227,7 +2227,7 @@ static int fsl_easrc_probe(struct platform_device *pdev) - } - - ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); -- easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; -+ easrc->asrc_format = asrc_fmt; - if (ret) { - dev_err(dev, "failed to asrc format\n"); - return ret; -diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c ---- a/sound/soc/fsl/fsl_qmc_audio.c -+++ b/sound/soc/fsl/fsl_qmc_audio.c -@@ -503,8 +503,8 @@ static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream, - return ret; - } - -- access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED | -- 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED; -+ access = 1ULL << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED | -+ 1ULL << SNDRV_PCM_ACCESS_RW_INTERLEAVED; - ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS, - access); - if (ret) { -@@ -532,8 +532,8 @@ static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substrea - return ret; - } - -- access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED | -- 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; -+ access = 1ULL << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED | -+ 1ULL << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; - ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS, - access); - if (ret) { -diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c ---- a/sound/soc/fsl/imx-card.c -+++ b/sound/soc/fsl/imx-card.c -@@ -531,7 +531,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - - mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - snd_mask_none(mask); -- snd_mask_set(mask, (__force unsigned int)data->asrc_format); -+ snd_mask_set(mask, data->asrc_format); - - return 0; - } -@@ -684,7 +684,7 @@ static int imx_card_parse_of(struct imx_card_data *data) - } - - ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt); -- data->asrc_format = (__force snd_pcm_format_t)asrc_fmt; -+ data->asrc_format = asrc_fmt; - if (ret) { - /* Fallback to old binding; translate to asrc_format */ - ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); -diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c ---- a/sound/soc/intel/avs/probes.c -+++ b/sound/soc/intel/avs/probes.c -@@ -144,7 +144,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream, - ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); - if (ret < 0) - return ret; -- bps = snd_pcm_format_physical_width((__force snd_pcm_format_t)params->codec.format); -+ bps = snd_pcm_format_physical_width(params->codec.format); - if (bps < 0) - return bps; - format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate); -diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c ---- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c -+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c -@@ -172,7 +172,7 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - { - /* fix BE i2s format to S32_LE, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); - -@@ -184,7 +184,7 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - { - /* fix BE i2s format to S24_LE, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); - -diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c ---- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c -+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c -@@ -99,7 +99,7 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - - /* fix BE i2s format to S32_LE, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); - return 0; -@@ -112,7 +112,7 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - - /* fix BE i2s format to S24_LE, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); - return 0; -diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c ---- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c -+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c -@@ -387,7 +387,7 @@ static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - - /* clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, fmt); - -diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c ---- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c -+++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c -@@ -623,7 +623,7 @@ static int mt8188_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - { - /* fix BE i2s format to 32bit, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); - -diff --git a/sound/soc/mediatek/mt8189/mt8189-nau8825.c b/sound/soc/mediatek/mt8189/mt8189-nau8825.c ---- a/sound/soc/mediatek/mt8189/mt8189-nau8825.c -+++ b/sound/soc/mediatek/mt8189/mt8189-nau8825.c -@@ -174,7 +174,7 @@ static int mt8189_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - - /* fix BE i2s format to 32bit, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); - -diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c ---- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c -+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c -@@ -382,7 +382,7 @@ static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - { - /* fix BE i2s format to S24_LE, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); - -diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c ---- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c -+++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c -@@ -387,7 +387,7 @@ static int mt8195_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - { - /* fix BE i2s format to S24_LE, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); - -@@ -650,7 +650,7 @@ static int mt8195_etdm_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - { - /* fix BE i2s format to S24_LE, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); - -diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediatek/mt8196/mt8196-nau8825.c ---- a/sound/soc/mediatek/mt8196/mt8196-nau8825.c -+++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c -@@ -180,7 +180,7 @@ static int mt8196_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - - /* fix BE i2s format to 32bit, clean param mask first */ - snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), -- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST); -+ 0, SNDRV_PCM_FORMAT_LAST); - - params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); - return 0; -diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c ---- a/sound/soc/meson/meson-codec-glue.c -+++ b/sound/soc/meson/meson-codec-glue.c -@@ -74,7 +74,7 @@ int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream, - data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params)); - data->params.rate_min = params_rate(params); - data->params.rate_max = params_rate(params); -- data->params.formats = 1ULL << (__force int) params_format(params); -+ data->params.formats = 1ULL << params_format(params); - data->params.channels_min = params_channels(params); - data->params.channels_max = params_channels(params); - data->params.sig_bits = dai->driver->playback.sig_bits; -diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c ---- a/sound/sparc/dbri.c -+++ b/sound/sparc/dbri.c -@@ -1840,6 +1840,7 @@ static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x) - int rval = D_INTR_GETRVAL(x); - #endif - -+#ifdef DBRI_DEBUG - if (channel == D_INTR_CMD) { - dprintk(D_CMD, "INTR: Command: %-5s Value:%d\n", - cmds[command], val); -@@ -1847,6 +1848,7 @@ static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x) - dprintk(D_INT, "INTR: Chan:%d Code:%d Val:%#x\n", - channel, code, rval); - } -+#endif - - switch (code) { - case D_INTR_CMDI: -diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c ---- a/sound/usb/6fire/firmware.c -+++ b/sound/usb/6fire/firmware.c -@@ -194,23 +194,20 @@ static int usb6fire_fw_ezusb_upload( - int ret; - u8 data; - struct usb_device *device = interface_to_usbdev(intf); -- const struct firmware *fw = NULL; -- struct ihex_record *rec = kmalloc_obj(struct ihex_record); -+ struct ihex_record *rec __free(kfree) = kmalloc_obj(struct ihex_record); - - if (!rec) - return -ENOMEM; - -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, fwname, &device->dev); - if (ret < 0) { -- kfree(rec); - dev_err(&intf->dev, - "error requesting ezusb firmware %s.\n", fwname); - return ret; - } - ret = usb6fire_fw_ihex_init(fw, rec); - if (ret < 0) { -- kfree(rec); -- release_firmware(fw); - dev_err(&intf->dev, - "error validating ezusb firmware %s.\n", fwname); - return ret; -@@ -219,8 +216,6 @@ static int usb6fire_fw_ezusb_upload( - data = 0x01; /* stop ezusb cpu */ - ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); - if (ret) { -- kfree(rec); -- release_firmware(fw); - dev_err(&intf->dev, - "unable to upload ezusb firmware %s: begin message.\n", - fwname); -@@ -231,8 +226,6 @@ static int usb6fire_fw_ezusb_upload( - ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address, - rec->data, rec->len); - if (ret) { -- kfree(rec); -- release_firmware(fw); - dev_err(&intf->dev, - "unable to upload ezusb firmware %s: data urb.\n", - fwname); -@@ -240,8 +233,6 @@ static int usb6fire_fw_ezusb_upload( - } - } - -- release_firmware(fw); -- kfree(rec); - if (postdata) { /* write data after firmware has been uploaded */ - ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr, - postdata, postlen); -@@ -270,19 +261,18 @@ static int usb6fire_fw_fpga_upload( - int ret; - int i; - struct usb_device *device = interface_to_usbdev(intf); -- u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL); -+ u8 *buffer __free(kfree) = kmalloc(FPGA_BUFSIZE, GFP_KERNEL); - const char *c; - const char *end; -- const struct firmware *fw; - - if (!buffer) - return -ENOMEM; - -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, fwname, &device->dev); - if (ret < 0) { - dev_err(&intf->dev, "unable to get fpga firmware %s.\n", - fwname); -- kfree(buffer); - return -EIO; - } - -@@ -291,8 +281,6 @@ static int usb6fire_fw_fpga_upload( - - ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0); - if (ret) { -- kfree(buffer); -- release_firmware(fw); - dev_err(&intf->dev, - "unable to upload fpga firmware: begin urb.\n"); - return ret; -@@ -304,15 +292,11 @@ static int usb6fire_fw_fpga_upload( - - ret = usb6fire_fw_fpga_write(device, buffer, i); - if (ret < 0) { -- release_firmware(fw); -- kfree(buffer); - dev_err(&intf->dev, - "unable to upload fpga firmware: fw urb.\n"); - return ret; - } - } -- release_firmware(fw); -- kfree(buffer); - - ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0); - if (ret) { -diff --git a/sound/usb/card.c b/sound/usb/card.c ---- a/sound/usb/card.c -+++ b/sound/usb/card.c -@@ -715,7 +715,7 @@ static void snd_usb_init_quirk_flags(int idx, struct snd_usb_audio *chip) - - /* old style option found: the position-based integer value */ - if (quirk_flags[idx] && -- !kstrtou32(quirk_flags[idx], 0, &chip->quirk_flags)) { -+ !kstrtou64(quirk_flags[idx], 0, &chip->quirk_flags)) { - snd_usb_apply_flag_dbg("module param", chip, chip->quirk_flags); - return; - } -@@ -905,6 +905,40 @@ static int try_to_register_card(struct snd_usb_audio *chip, int ifnum) - return 0; - } - -+static void usb_audio_disconnect_components(struct snd_usb_audio *chip) -+{ -+ struct snd_usb_stream *as; -+ struct snd_usb_endpoint *ep; -+ struct usb_mixer_interface *mixer; -+ struct list_head *p; -+ -+ /* release the pcm resources */ -+ list_for_each_entry(as, &chip->pcm_list, list) { -+ snd_usb_stream_disconnect(as); -+ } -+ /* release the endpoint resources */ -+ list_for_each_entry(ep, &chip->ep_list, list) { -+ snd_usb_endpoint_release(ep); -+ } -+ /* release the midi resources */ -+ list_for_each(p, &chip->midi_list) { -+ snd_usbmidi_disconnect(p); -+ } -+ snd_usb_midi_v2_disconnect_all(chip); -+ /* -+ * Nice to check quirk && quirk->shares_media_device and -+ * then call the snd_media_device_delete(). Don't have -+ * access to the quirk here. snd_media_device_delete() -+ * accesses mixer_list -+ */ -+ snd_media_device_delete(chip); -+ -+ /* release mixer resources */ -+ list_for_each_entry(mixer, &chip->mixer_list, list) { -+ snd_usb_mixer_disconnect(mixer); -+ } -+} -+ - /* - * probe the active usb device - * -@@ -1077,8 +1111,10 @@ static int usb_audio_probe(struct usb_interface *intf, - * decrement before memory is possibly returned. - */ - atomic_dec(&chip->active); -- if (!chip->num_interfaces) -+ if (!chip->num_interfaces) { -+ usb_audio_disconnect_components(chip); - snd_card_free(chip->card); -+ } - } - return err; - } -@@ -1091,48 +1127,18 @@ static bool __usb_audio_disconnect(struct usb_interface *intf, - struct snd_usb_audio *chip, - struct snd_card *card) - { -- struct list_head *p; -- - guard(mutex)(®ister_mutex); - - if (platform_ops && platform_ops->disconnect_cb) - platform_ops->disconnect_cb(chip); - - if (atomic_inc_return(&chip->shutdown) == 1) { -- struct snd_usb_stream *as; -- struct snd_usb_endpoint *ep; -- struct usb_mixer_interface *mixer; -- - /* wait until all pending tasks done; - * they are protected by snd_usb_lock_shutdown() - */ - snd_refcount_sync(&chip->usage_count); - snd_card_disconnect(card); -- /* release the pcm resources */ -- list_for_each_entry(as, &chip->pcm_list, list) { -- snd_usb_stream_disconnect(as); -- } -- /* release the endpoint resources */ -- list_for_each_entry(ep, &chip->ep_list, list) { -- snd_usb_endpoint_release(ep); -- } -- /* release the midi resources */ -- list_for_each(p, &chip->midi_list) { -- snd_usbmidi_disconnect(p); -- } -- snd_usb_midi_v2_disconnect_all(chip); -- /* -- * Nice to check quirk && quirk->shares_media_device and -- * then call the snd_media_device_delete(). Don't have -- * access to the quirk here. snd_media_device_delete() -- * accesses mixer_list -- */ -- snd_media_device_delete(chip); -- -- /* release mixer resources */ -- list_for_each_entry(mixer, &chip->mixer_list, list) { -- snd_usb_mixer_disconnect(mixer); -- } -+ usb_audio_disconnect_components(chip); - } - - if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND) -diff --git a/sound/usb/clock.c b/sound/usb/clock.c ---- a/sound/usb/clock.c -+++ b/sound/usb/clock.c -@@ -600,7 +600,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip, - static int set_sample_rate_v2v3(struct snd_usb_audio *chip, - const struct audioformat *fmt, int rate) - { -- int cur_rate, prev_rate; -+ int cur_rate, prev_rate = 0; - int clock; - - /* First, try to find a valid clock. This may trigger -@@ -625,9 +625,12 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, - return clock; - } - -- prev_rate = get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock); -- if (prev_rate == rate) -- goto validation; -+ if (!(chip->quirk_flags & QUIRK_FLAG_ALWAYS_SET_RATE)) { -+ prev_rate = get_sample_rate_v2v3(chip, fmt->iface, -+ fmt->altsetting, clock); -+ if (prev_rate == rate) -+ goto validation; -+ } - - cur_rate = snd_usb_set_sample_rate_v2v3(chip, fmt, clock, rate); - if (cur_rate < 0) { -diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c ---- a/sound/usb/endpoint.c -+++ b/sound/usb/endpoint.c -@@ -1237,7 +1237,10 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep) - /* try to use enough URBs to contain an entire ALSA buffer */ - max_urbs = min((unsigned) MAX_URBS, - MAX_QUEUE * packs_per_ms / urb_packs); -- ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods); -+ if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP) -+ ep->nurbs = MAX_URBS; -+ else -+ ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods); - } - - if (fmt->fmt_type == UAC_FORMAT_TYPE_II) -@@ -1262,6 +1265,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep) - goto out_of_memory; - u->urb->pipe = ep->pipe; - u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; -+ if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP) -+ u->urb->transfer_flags |= URB_ISO_ASAP; - u->urb->interval = 1 << ep->datainterval; - u->urb->context = u; - u->urb->complete = snd_complete_urb; -diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c ---- a/sound/usb/mixer_maps.c -+++ b/sound/usb/mixer_maps.c -@@ -505,6 +505,19 @@ static const struct usbmix_connector_map gigabyte_b450_connector_map[] = { - {} - }; - -+/* Audient iD14: FU 12 advertises Volume on only 4 of its 6 logical channels -+ * and sits on the monitor mixer branch, but it is traced through to the -+ * Speaker output terminal and gets named "Speaker Playback Volume". Userspace -+ * then adopts it as the stream's hardware volume, and any setting below 0 dB -+ * attenuates some channels but not others (20 dB imbalance at 80%). Give it a -+ * non-standard name so that it is no longer taken for the stream's master -+ * volume, while remaining reachable for anyone who wants the monitor gain. -+ */ -+static const struct usbmix_name_map audient_id14_map[] = { -+ { 12, "Monitor Mix Playback" }, /* FU, partial coverage */ -+ {} -+}; -+ - /* - * Control map entries - */ -@@ -588,6 +601,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { - .id = USB_ID(0x2573, 0x0008), - .map = maya44_map, - }, -+ { -+ /* Audient iD14 */ -+ .id = USB_ID(0x2708, 0x0008), -+ .map = audient_id14_map, -+ }, - { - /* KEF X300A */ - .id = USB_ID(0x27ac, 0x1000), -diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c ---- a/sound/usb/mixer_quirks.c -+++ b/sound/usb/mixer_quirks.c -@@ -3920,6 +3920,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) - #define SND_DJM_450_IDX 0x5 - #define SND_DJM_A9_IDX 0x6 - #define SND_DJM_V10_IDX 0x7 -+#define SND_DJM_S11_IDX 0x8 - - #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ - .name = _name, \ -@@ -4260,6 +4261,21 @@ static const struct snd_djm_ctl snd_djm_ctls_v10[] = { - // playback channels are fixed and controlled by hardware knobs on the mixer - }; - -+// DJM-S11 -+static const u16 snd_djm_opts_s11_cap1[] = { -+ 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d }; -+static const u16 snd_djm_opts_s11_cap2[] = { -+ 0x0200, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d }; -+static const u16 snd_djm_opts_s11_cap3[] = { -+ 0x0307, 0x0308, 0x0309, 0x030a, 0x030d, 0x0311, 0x0312 }; -+ -+static const struct snd_djm_ctl snd_djm_ctls_s11[] = { -+ SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), -+ SND_DJM_CTL("Input 1 Capture Switch", s11_cap1, 1, SND_DJM_WINDEX_CAP), -+ SND_DJM_CTL("Input 2 Capture Switch", s11_cap2, 1, SND_DJM_WINDEX_CAP), -+ SND_DJM_CTL("Input 3 Capture Switch", s11_cap3, 3, SND_DJM_WINDEX_CAP) -+}; -+ - static const struct snd_djm_device snd_djm_devices[] = { - [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2), - [SND_DJM_750_IDX] = SND_DJM_DEVICE(750), -@@ -4269,6 +4285,7 @@ static const struct snd_djm_device snd_djm_devices[] = { - [SND_DJM_450_IDX] = SND_DJM_DEVICE(450), - [SND_DJM_A9_IDX] = SND_DJM_DEVICE(a9), - [SND_DJM_V10_IDX] = SND_DJM_DEVICE(v10), -+ [SND_DJM_S11_IDX] = SND_DJM_DEVICE(s11), - }; - - static int snd_djm_controls_info(struct snd_kcontrol *kctl, -@@ -4573,6 +4590,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) - case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */ - err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX); - break; -+ case USB_ID(0x2b73, 0x0037): /* Pioneer DJ DJM-S11 */ -+ err = snd_djm_controls_create(mixer, SND_DJM_S11_IDX); -+ break; - case USB_ID(0x03f0, 0x0269): /* HP TB Dock G2 */ - err = hp_dock_mixer_create(mixer); - break; -diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h ---- a/sound/usb/quirks-table.h -+++ b/sound/usb/quirks-table.h -@@ -3320,6 +3320,73 @@ YAMAHA_DEVICE(0x7010, "UB99"), - } - } - }, -+{ -+ /* -+ * Pioneer DJ / AlphaTheta DJM-S11 -+ */ -+ USB_DEVICE(0x2b73, 0x0037), -+ QUIRK_DRIVER_INFO { -+ QUIRK_DATA_COMPOSITE { -+ { -+ QUIRK_DATA_STANDARD_MIXER(0) -+ }, -+ { -+ QUIRK_DATA_AUDIOFORMAT(1) { -+ .formats = SNDRV_PCM_FMTBIT_S24_3LE, -+ .channels = 14, -+ .iface = 1, -+ .altsetting = 1, -+ .altset_idx = 1, -+ .endpoint = 0x01, -+ .ep_attr = USB_ENDPOINT_XFER_ISOC | -+ USB_ENDPOINT_SYNC_ASYNC, -+ .rates = SNDRV_PCM_RATE_48000, -+ .rate_min = 48000, -+ .rate_max = 48000, -+ .nr_rates = 1, -+ .rate_table = (unsigned int[]) { 48000 }, -+ .clock = 1, -+ .fmt_type = UAC_FORMAT_TYPE_I -+ } -+ }, -+ { -+ QUIRK_DATA_AUDIOFORMAT(2) { -+ .formats = SNDRV_PCM_FMTBIT_S24_3LE, -+ .channels = 10, -+ .iface = 2, -+ .altsetting = 1, -+ .altset_idx = 1, -+ .endpoint = 0x82, -+ .ep_attr = USB_ENDPOINT_XFER_ISOC | -+ USB_ENDPOINT_SYNC_ASYNC | -+ USB_ENDPOINT_USAGE_IMPLICIT_FB, -+ .rates = SNDRV_PCM_RATE_48000, -+ .rate_min = 48000, -+ .rate_max = 48000, -+ .nr_rates = 1, -+ .rate_table = (unsigned int[]) { 48000 }, -+ .clock = 1, -+ .fmt_type = UAC_FORMAT_TYPE_I -+ } -+ }, -+ { -+ /* Audio Control (unknown purpose) */ -+ .ifnum = 3, -+ .type = QUIRK_IGNORE_INTERFACE -+ }, -+ { -+ .ifnum = 4, -+ .type = QUIRK_MIDI_STANDARD_INTERFACE -+ }, -+ { -+ /* HID */ -+ .ifnum = 5, -+ .type = QUIRK_IGNORE_INTERFACE -+ }, -+ QUIRK_COMPOSITE_END -+ } -+ } -+}, - - /* - * MacroSilicon MS2100/MS2106 based AV capture cards -diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c ---- a/sound/usb/quirks.c -+++ b/sound/usb/quirks.c -@@ -2145,7 +2145,7 @@ struct usb_string_match { - - struct usb_audio_quirk_flags_table { - u32 id; -- u32 flags; -+ u64 flags; - const struct usb_string_match *usb_string_match; - }; - -@@ -2314,7 +2314,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - DEVICE_FLG(0x0661, 0x0883, /* iBasso DC04 Ultra */ - QUIRK_FLAG_DSD_RAW), - DEVICE_FLG(0x0666, 0x0880, /* SPACETOUCH USB Audio */ -- QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY), -+ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY | -+ QUIRK_FLAG_CTL_MSG_DELAY_5M), - DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */ - QUIRK_FLAG_IGNORE_CTL_ERROR), - DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */ -@@ -2337,6 +2338,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_IGNORE_CTL_ERROR), - DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */ - QUIRK_FLAG_CTL_MSG_DELAY_1M), -+ DEVICE_FLG(0x0a73, 0x003a, /* Mackie DLZ Creator XS */ -+ QUIRK_FLAG_ALWAYS_SET_RATE), - DEVICE_FLG(0x0b05, 0x18a6, /* ASUSTek Computer, Inc. */ - QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), - DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */ -@@ -2432,6 +2435,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), - DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), -+ DEVICE_FLG(0x1e0b, 0xd01e, /* Generic USB Audio Device */ -+ QUIRK_FLAG_PLAYBACK_URB_FIXUP), - DEVICE_FLG(0x1ff7, 0x0f81, /* SC13A Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE), - DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */ -@@ -2528,6 +2533,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_ALIGN_TRANSFER), - DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */ - QUIRK_FLAG_ALIGN_TRANSFER), -+ DEVICE_FLG(0x84ef, 0x002a, /* Valeton GP-200 */ -+ QUIRK_FLAG_GENERIC_IMPLICIT_FB), - DEVICE_FLG(0x84ef, 0x0082, /* Hotone Audio Pulze Mini */ - QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL | QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL), - -@@ -2641,18 +2648,12 @@ static const char *const snd_usb_audio_quirk_flag_names[] = { - QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL), - QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY), - QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN), -+ QUIRK_STRING_ENTRY(PLAYBACK_URB_FIXUP), -+ QUIRK_STRING_ENTRY(ALWAYS_SET_RATE), - NULL - }; - --const char *snd_usb_quirk_flag_find_name(unsigned long index) --{ -- if (index >= ARRAY_SIZE(snd_usb_audio_quirk_flag_names)) -- return NULL; -- -- return snd_usb_audio_quirk_flag_names[index]; --} -- --u32 snd_usb_quirk_flags_from_name(const char *name) -+static u64 snd_usb_quirk_flags_from_name(const char *name) - { - int i; - -@@ -2661,7 +2662,7 @@ u32 snd_usb_quirk_flags_from_name(const char *name) - - for (i = 0; snd_usb_audio_quirk_flag_names[i]; i++) { - if (strcasecmp(name, snd_usb_audio_quirk_flag_names[i]) == 0) -- return BIT_U32(i); -+ return BIT_U64(i); - } - - return 0; -@@ -2719,7 +2720,7 @@ void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip, - { - u16 chip_vid = USB_ID_VENDOR(chip->usb_id); - u16 chip_pid = USB_ID_PRODUCT(chip->usb_id); -- u32 mask_flags, unmask_flags, bit; -+ u64 mask_flags, unmask_flags, bit; - char *p, *field, *flag; - bool is_unmask; - u16 vid, pid; -@@ -2773,7 +2774,7 @@ void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip, - is_unmask = false; - } - -- if (!kstrtou32(flag, 16, &bit)) { -+ if (!kstrtou64(flag, 16, &bit)) { - if (is_unmask) - unmask_flags |= bit; - else -diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h ---- a/sound/usb/quirks.h -+++ b/sound/usb/quirks.h -@@ -56,7 +56,4 @@ void snd_usb_init_quirk_flags_table(struct snd_usb_audio *chip); - void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip, - const char *str); - --const char *snd_usb_quirk_flag_find_name(unsigned long flag); --u32 snd_usb_quirk_flags_from_name(const char *name); -- - #endif /* __USBAUDIO_QUIRKS_H */ -diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h ---- a/sound/usb/usbaudio.h -+++ b/sound/usb/usbaudio.h -@@ -44,7 +44,7 @@ struct snd_usb_audio { - atomic_t active; - atomic_t shutdown; - struct snd_refcount usage_count; -- unsigned int quirk_flags; -+ u64 quirk_flags; - unsigned int need_delayed_register:1; /* warn for delayed registration */ - int num_interfaces; - int last_iface; -@@ -254,6 +254,16 @@ extern bool snd_usb_skip_validation; - * check being non-fatal and only disabling GET_CUR instead of the whole mixer. - * The current volume will then be provided by the internal cache that stores - * the last set volume -+ * QUIRK_FLAG_PLAYBACK_URB_FIXUP -+ * Set URB_ISO_ASAP flag for isochronous URBs and force nurbs to MAX_URBS. -+ * This is needed for devices that exhibit boot-time audio stuttering due -+ * to insufficient buffer depth combined with xHCI scheduling variability. -+ * The larger buffer (MAX_URBS = 12, ~64ms) absorbs system scheduling -+ * jitter during boot, while URB_ISO_ASAP ensures consistent xHCI scheduling. -+ * QUIRK_FLAG_ALWAYS_SET_RATE: -+ * Issue SET_CUR for the sample rate even when the clock already reports the -+ * requested rate. A device advertising a single rate is otherwise never sent -+ * the request at all, and some require it before streaming will start. - */ - - enum { -@@ -288,10 +298,12 @@ enum { - QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28, - QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29, - QUIRK_TYPE_MIXER_GET_CUR_BROKEN = 30, -+ QUIRK_TYPE_PLAYBACK_URB_FIXUP = 31, -+ QUIRK_TYPE_ALWAYS_SET_RATE = 32, - /* Please also edit snd_usb_audio_quirk_flag_names */ - }; - --#define QUIRK_FLAG(x) BIT_U32(QUIRK_TYPE_ ## x) -+#define QUIRK_FLAG(x) BIT_U64(QUIRK_TYPE_ ## x) - - #define QUIRK_FLAG_GET_SAMPLE_RATE QUIRK_FLAG(GET_SAMPLE_RATE) - #define QUIRK_FLAG_SHARE_MEDIA_DEVICE QUIRK_FLAG(SHARE_MEDIA_DEVICE) -@@ -324,5 +336,7 @@ enum { - #define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL) - #define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY) - #define QUIRK_FLAG_MIXER_GET_CUR_BROKEN QUIRK_FLAG(MIXER_GET_CUR_BROKEN) -+#define QUIRK_FLAG_PLAYBACK_URB_FIXUP QUIRK_FLAG(PLAYBACK_URB_FIXUP) -+#define QUIRK_FLAG_ALWAYS_SET_RATE QUIRK_FLAG(ALWAYS_SET_RATE) - - #endif /* __USBAUDIO_H */ -diff --git a/sound/usb/usx2y/us144mkii_pcm.h b/sound/usb/usx2y/us144mkii_pcm.h ---- a/sound/usb/usx2y/us144mkii_pcm.h -+++ b/sound/usb/usx2y/us144mkii_pcm.h -@@ -7,7 +7,7 @@ - #include "us144mkii.h" - - /** -- * tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM. -+ * var tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM. - * - * Defines the supported PCM formats, rates, channels, and buffer/period sizes - * for the TASCAM US-144MKII audio interface. -@@ -15,14 +15,14 @@ - extern const struct snd_pcm_hardware tascam_pcm_hw; - - /** -- * tascam_playback_ops - ALSA PCM operations for playback. -+ * var tascam_playback_ops - ALSA PCM operations for playback. - * - * This structure defines the callback functions for playback stream operations. - */ - extern const struct snd_pcm_ops tascam_playback_ops; - - /** -- * tascam_capture_ops - ALSA PCM operations for capture. -+ * var tascam_capture_ops - ALSA PCM operations for capture. - * - * This structure defines the callback functions for capture stream operations. - */ -diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c ---- a/sound/usb/usx2y/usbusx2yaudio.c -+++ b/sound/usb/usx2y/usbusx2yaudio.c -@@ -167,7 +167,6 @@ static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, i - if (!urb) - return -ENODEV; - urb->start_frame = frame + NRURBS * nr_of_packs(); // let hcd do rollover sanity checks -- urb->hcpriv = NULL; - urb->dev = subs->usx2y->dev; /* we need to set this at each time */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { diff --git a/kernel/0510-sound-updates.patch.sig b/kernel/0510-sound-updates.patch.sig deleted file mode 100644 index 95975e7..0000000 Binary files a/kernel/0510-sound-updates.patch.sig and /dev/null differ diff --git a/kernel/0511-asoc-updates.patch b/kernel/0511-asoc-updates.patch deleted file mode 100644 index 75c49b4..0000000 --- a/kernel/0511-asoc-updates.patch +++ /dev/null @@ -1,37891 +0,0 @@ -diff --git a/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c b/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c ---- a/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c -+++ b/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c -@@ -147,7 +147,7 @@ static const struct reg_default halo_register_defaults[] = { - { 0x2b805c0, 0 }, /* HALO_SCRATCH1 */ - { 0x2b805c8, 0 }, /* HALO_SCRATCH2 */ - { 0x2b805d0, 0 }, /* HALO_SCRATCH3 */ -- { 0x2b805c8, 0 }, /* HALO_SCRATCH4 */ -+ { 0x2b805d8, 0 }, /* HALO_SCRATCH4 */ - { 0x2bc1000, 0 }, /* HALO_CCM_CORE_CONTROL */ - { 0x2bc7000, 0 }, /* HALO_WDT_CONTROL */ - -diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c ---- a/drivers/soundwire/bus_type.c -+++ b/drivers/soundwire/bus_type.c -@@ -105,6 +105,9 @@ static int sdw_bus_probe(struct device *dev) - } - slave->index = ret; - -+ /* Create IRQ mapping now so the driver can get it in probe() */ -+ sdw_irq_create_mapping(slave); -+ - ret = drv->probe(slave, id); - if (ret) { - ida_free(&slave->bus->slave_ida, slave->index); -@@ -117,9 +120,6 @@ static int sdw_bus_probe(struct device *dev) - if (drv->ops && drv->ops->read_prop) - drv->ops->read_prop(slave); - -- if (slave->prop.use_domain_irq) -- sdw_irq_create_mapping(slave); -- - /* init the dynamic sysfs attributes we need */ - ret = sdw_slave_sysfs_dpn_init(slave); - if (ret < 0) -diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h ---- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h -+++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h -@@ -152,6 +152,10 @@ - #define LPI_MI2S_TX_4 146 - #define SENARY_MI2S_RX 147 - #define SENARY_MI2S_TX 148 -+#define LPI_MI2S_RX_5 149 -+#define LPI_MI2S_TX_5 150 -+#define LPI_MI2S_RX_6 151 -+#define LPI_MI2S_TX_6 152 - - #define LPASS_CLK_ID_PRI_MI2S_IBIT 1 - #define LPASS_CLK_ID_PRI_MI2S_EBIT 2 -@@ -233,11 +237,39 @@ - /* Clock ID for RX CORE MCLK2 2X MCLK */ - #define LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 70 - -+#define LAPSS_CLK_ID_QAIF_IF0_IBIT 71 -+#define LAPSS_CLK_ID_QAIF_IF0_EBIT 72 -+#define LAPSS_CLK_ID_QAIF_IF1_IBIT 73 -+#define LAPSS_CLK_ID_QAIF_IF1_EBIT 74 -+#define LAPSS_CLK_ID_QAIF_IF2_IBIT 75 -+#define LAPSS_CLK_ID_QAIF_IF2_EBIT 76 -+#define LAPSS_CLK_ID_QAIF_IF3_IBIT 77 -+#define LAPSS_CLK_ID_QAIF_IF3_EBIT 78 -+#define LAPSS_CLK_ID_QAIF_IF4_IBIT 79 -+#define LAPSS_CLK_ID_QAIF_IF4_EBIT 80 -+#define LAPSS_CLK_ID_QAIF_IF5_IBIT 81 -+#define LAPSS_CLK_ID_QAIF_IF5_EBIT 82 -+#define LAPSS_CLK_ID_QAIF_IF6_IBIT 83 -+#define LAPSS_CLK_ID_QAIF_IF6_EBIT 84 -+#define LAPSS_CLK_ID_QAIF_IF7_IBIT 85 -+#define LAPSS_CLK_ID_QAIF_IF7_EBIT 86 -+#define LAPSS_CLK_ID_QAIF_IF8_IBIT 87 -+#define LAPSS_CLK_ID_QAIF_IF8_EBIT 88 -+#define LAPSS_CLK_ID_QAIF_IF9_IBIT 89 -+#define LAPSS_CLK_ID_QAIF_IF9_EBIT 90 -+#define LAPSS_CLK_ID_QAIF_IF10_IBIT 91 -+#define LAPSS_CLK_ID_QAIF_IF10_EBIT 92 -+#define LAPSS_CLK_ID_QAIF_IF11_IBIT 93 -+#define LAPSS_CLK_ID_QAIF_IF11_EBIT 94 -+#define LAPSS_CLK_ID_QAIF_IF12_IBIT 95 -+#define LAPSS_CLK_ID_QAIF_IF12_EBIT 96 -+#define LAPSS_CLK_ID_VA_QAIF_IF0_IBIT 97 -+#define LAPSS_CLK_ID_VA_QAIF_IF0_EBIT 98 -+ - #define LPASS_HW_AVTIMER_VOTE 101 - #define LPASS_HW_MACRO_VOTE 102 - #define LPASS_HW_DCODEC_VOTE 103 -- --#define Q6AFE_MAX_CLK_ID 104 -+#define LPASS_HW_LPR_VOTE 104 - - #define LPASS_CLK_ATTRIBUTE_INVALID 0x0 - #define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1 -diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h -deleted file mode 100644 ---- a/include/linux/platform_data/omap-twl4030.h -+++ /dev/null -@@ -1,42 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ --/** -- * omap-twl4030.h - ASoC machine driver for TI SoC based boards with twl4030 -- * codec, header. -- * -- * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com -- * All rights reserved. -- * -- * Author: Peter Ujfalusi -- */ -- --#ifndef _OMAP_TWL4030_H_ --#define _OMAP_TWL4030_H_ -- --/* To select if only one channel is connected in a stereo port */ --#define OMAP_TWL4030_LEFT (1 << 0) --#define OMAP_TWL4030_RIGHT (1 << 1) -- --struct omap_tw4030_pdata { -- const char *card_name; -- /* Voice port is connected to McBSP3 */ -- bool voice_connected; -- -- /* The driver will parse the connection flags if this flag is set */ -- bool custom_routing; -- /* Flags to indicate connected audio ports. */ -- u8 has_hs; -- u8 has_hf; -- u8 has_predriv; -- u8 has_carkit; -- bool has_ear; -- -- bool has_mainmic; -- bool has_submic; -- bool has_hsmic; -- bool has_carkitmic; -- bool has_digimic0; -- bool has_digimic1; -- u8 has_linein; --}; -- --#endif /* _OMAP_TWL4030_H_ */ -diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h ---- a/include/sound/cs35l56.h -+++ b/include/sound/cs35l56.h -@@ -417,7 +417,6 @@ void cs35l56_wait_control_port_ready(void); - void cs35l56_wait_min_reset_pulse(void); - void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire); - int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); --irqreturn_t cs35l56_irq(int irq, void *data); - int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base); - int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base); - int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire); -diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h ---- a/include/sound/dmaengine_pcm.h -+++ b/include/sound/dmaengine_pcm.h -@@ -175,12 +175,6 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, - struct dmaengine_pcm { - struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; - const struct snd_dmaengine_pcm_config *config; -- struct snd_soc_component component; - unsigned int flags; - }; -- --static inline struct dmaengine_pcm *soc_component_to_pcm(struct snd_soc_component *p) --{ -- return container_of(p, struct dmaengine_pcm, component); --} - #endif -diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h ---- a/include/sound/hda-mlink.h -+++ b/include/sound/hda-mlink.h -@@ -9,6 +9,22 @@ - struct hdac_bus; - struct hdac_ext_link; - -+/** -+ * enum hda_bus_ml_link_type - mlink link type, used by SOF link DMA -+ * allocator constraints (see struct sof_intel_hda_dev). -+ * -+ * @HDA_BUS_ML_LINK_HDA: non-alt link, i.e. HDA codec or iDisp -+ * @HDA_BUS_ML_LINK_SDW: alt link, SoundWire -+ * @HDA_BUS_ML_LINK_UAOL: alt link, USB Audio Offload -+ * @HDA_BUS_ML_LINK_OTHER: alt link, SSP or DMIC -+ */ -+enum hda_bus_ml_link_type { -+ HDA_BUS_ML_LINK_HDA, -+ HDA_BUS_ML_LINK_SDW, -+ HDA_BUS_ML_LINK_UAOL, -+ HDA_BUS_ML_LINK_OTHER, -+}; -+ - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK) - - int hda_bus_ml_init(struct hdac_bus *bus); -@@ -49,11 +65,12 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num); - int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, - int channel_mask, int stream_id, int dir); - --void hda_bus_ml_put_all(struct hdac_bus *bus); - void hda_bus_ml_reset_losidv(struct hdac_bus *bus); - int hda_bus_ml_resume(struct hdac_bus *bus); - int hda_bus_ml_suspend(struct hdac_bus *bus); - -+enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink); -+ - struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus); - struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus); - struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus); -@@ -169,11 +186,13 @@ hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, - return 0; - } - --static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { } - static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { } - static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; } - static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; } - -+static inline enum hda_bus_ml_link_type -+hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) { return HDA_BUS_ML_LINK_HDA; } -+ - static inline struct hdac_ext_link * - hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) { return NULL; } - -diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h ---- a/include/sound/sdca_asoc.h -+++ b/include/sound/sdca_asoc.h -@@ -25,6 +25,8 @@ struct snd_soc_dai_driver; - struct snd_soc_dai_ops; - struct snd_soc_dapm_route; - struct snd_soc_dapm_widget; -+struct snd_soc_pcm_stream; -+struct sdca_entity; - - /* convenient macro to handle the mono volume in 7.8 fixed format representation */ - #define SDCA_SINGLE_Q78_TLV(xname, xreg, xmin, xmax, xstep, tlv_array) \ -@@ -82,6 +84,11 @@ int sdca_asoc_populate_component(struct device *dev, - struct snd_soc_dai_driver **dai_drv, int *num_dai_drv, - const struct snd_soc_dai_ops *ops); - -+int sdca_asoc_populate_rate_format(struct device *dev, -+ struct sdca_function_data *function, -+ struct sdca_entity *entity, -+ struct snd_soc_pcm_stream *stream); -+ - int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap, - struct sdca_function_data *function, - struct snd_pcm_substream *substream, -@@ -100,9 +107,9 @@ int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); --int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap, -+int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap, - int function_id, int entity_id, -- int from_ps, int to_ps, -- const struct sdca_pde_delay *pde_delays, -- int num_delays); -+ int from_ps, int to_ps, -+ const struct sdca_pde_delay *pde_delays, -+ int num_delays); - #endif // __SDCA_ASOC_H__ -diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h ---- a/include/sound/sdca_function.h -+++ b/include/sound/sdca_function.h -@@ -298,7 +298,7 @@ enum sdca_xu_controls { - }; - - /** -- * enum sdca_set_index_range - Column definitions UMP SetIndex -+ * enum sdca_fdl_set_index_range - Column definitions UMP SetIndex - */ - enum sdca_fdl_set_index_range { - SDCA_FDL_SET_INDEX_SET_NUMBER = 0, -@@ -803,6 +803,8 @@ struct sdca_control_range { - * @mode: Access mode of the Control. - * @layers: Bitmask of access layers of the Control. - * @deferrable: Indicates if the access to the Control can be deferred. -+ * @is_volatile: Indicates the Control registers are forced to be treated -+ * as volatile. - * @has_default: Indicates the Control has a default value to be written. - * @has_reset: Indicates the Control has a defined reset value. - * @has_fixed: Indicates the Control only supports a single value. -@@ -1116,7 +1118,6 @@ struct sdca_entity_ge { - - /** - * struct sdca_entity_hide - information specific to HIDE Entities -- * @hid: HID device structure - * @num_hidtx_ids: number of HIDTx Report ID - * @num_hidrx_ids: number of HIDRx Report ID - * @hidtx_ids: HIDTx Report ID -@@ -1127,11 +1128,8 @@ struct sdca_entity_ge { - * within this Device - * @max_delay: the maximum time in microseconds allowed for the Device - * to change the ownership from Device to Host -- * @hid_report_desc: HID Report Descriptor for the HIDE Entity -- * @hid_desc: HID descriptor for the HIDE Entity - */ - struct sdca_entity_hide { -- struct hid_device *hid; - unsigned int *hidtx_ids; - unsigned int *hidrx_ids; - int num_hidtx_ids; -@@ -1139,12 +1137,10 @@ struct sdca_entity_hide { - unsigned int af_number_list[SDCA_MAX_FUNCTION_COUNT]; - unsigned int hide_reside_function_num; - unsigned int max_delay; -- unsigned char *hid_report_desc; -- struct hid_descriptor hid_desc; - }; - - /** -- * enum sdca_xu_reset_machanism - SDCA FDL Resets -+ * enum sdca_xu_reset_mechanism - SDCA FDL Resets - */ - enum sdca_xu_reset_mechanism { - SDCA_XU_RESET_FUNCTION = 0x0, -@@ -1401,6 +1397,16 @@ struct sdca_fdl_data { - int num_sets; - }; - -+/** -+ * struct sdca_function_hid - information about a function's HID descriptors -+ * @report_desc: HID Report Descriptor for the HID Function -+ * @desc: HID descriptor for the HID Function -+ */ -+struct sdca_function_hid { -+ unsigned char *report_desc; -+ struct hid_descriptor desc; -+}; -+ - /** - * struct sdca_function_data - top-level information for one SDCA function - * @desc: Pointer to short descriptor from initial parsing. -@@ -1415,6 +1421,7 @@ struct sdca_fdl_data { - * @reset_max_delay: Maximum Function reset delay in microseconds, before an - * error should be reported. - * @fdl_data: FDL data for this Function, if available. -+ * @hid: HID data for this Function, if available. - */ - struct sdca_function_data { - struct sdca_function_desc *desc; -@@ -1430,6 +1437,10 @@ struct sdca_function_data { - unsigned int reset_max_delay; - - struct sdca_fdl_data fdl_data; -+ -+ union { -+ struct sdca_function_hid hid; -+ }; - }; - - static inline u32 sdca_range(struct sdca_control_range *range, -@@ -1451,8 +1462,7 @@ static inline u32 sdca_range_search(struct sdca_control_range *range, - return 0; - } - --int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, -- struct sdca_function_data *function); -+int sdca_parse_function(struct device *dev, struct sdca_function_data *function); - - const char *sdca_find_terminal_name(enum sdca_terminal_type type); - -@@ -1469,5 +1479,7 @@ struct sdca_control_range *sdca_selector_find_range(struct device *dev, - struct sdca_cluster *sdca_id_find_cluster(struct device *dev, - struct sdca_function_data *function, - const int id); -+struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function, -+ const char *entity_label); - - #endif -diff --git a/include/sound/sdca_hid.h b/include/sound/sdca_hid.h ---- a/include/sound/sdca_hid.h -+++ b/include/sound/sdca_hid.h -@@ -16,18 +16,21 @@ struct sdca_interrupt; - - #if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID) - --int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, -- struct sdca_entity *entity); -+int sdca_add_hid_device(struct sdca_interrupt *interrupt); -+void sdca_destroy_hid_device(struct sdca_interrupt *interrupt); - int sdca_hid_process_report(struct sdca_interrupt *interrupt); - - #else - --static inline int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, -- struct sdca_entity *entity) -+static inline int sdca_add_hid_device(struct sdca_interrupt *interrupt) - { - return 0; - } - -+static inline void sdca_destroy_hid_device(struct sdca_interrupt *interrupt) -+{ -+} -+ - static inline int sdca_hid_process_report(struct sdca_interrupt *interrupt) - { - return 0; -diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h ---- a/include/sound/simple_card_utils.h -+++ b/include/sound/simple_card_utils.h -@@ -181,7 +181,7 @@ void simple_util_canonicalize_platform(struct snd_soc_dai_link_component *platfo - void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, - int is_single_links); - --void simple_util_clean_reference(struct snd_soc_card *card); -+void simple_util_clean_reference(struct simple_util_priv *priv); - - void simple_util_parse_convert(struct device_node *np, char *prefix, - struct simple_util_data *data); -@@ -189,18 +189,37 @@ bool simple_util_is_convert_required(const struct simple_util_data *data); - - int simple_util_get_sample_fmt(struct simple_util_data *data); - --int simple_util_parse_routing(struct snd_soc_card *card, -- char *prefix); --int simple_util_parse_widgets(struct snd_soc_card *card, -- char *prefix); --int simple_util_parse_pin_switches(struct snd_soc_card *card, -- char *prefix); -+int simple_util_parse_property(struct simple_util_priv *priv, -+ int (*func)(struct snd_soc_card *card, const char *propname), -+ char *prefix, char *property); -+static inline int simple_util_parse_routing(struct simple_util_priv *priv, char *prefix) -+{ -+ return simple_util_parse_property(priv, snd_soc_of_parse_audio_routing, -+ prefix, "routing"); -+} -+ -+static inline int simple_util_parse_widgets(struct simple_util_priv *priv, char *prefix) -+{ -+ return simple_util_parse_property(priv, snd_soc_of_parse_audio_simple_widgets, -+ prefix, "widgets"); -+} -+ -+static inline int simple_util_parse_pin_switches(struct simple_util_priv *priv, char *prefix) -+{ -+ return simple_util_parse_property(priv, snd_soc_of_parse_pin_switches, -+ prefix, "pin-switches"); -+} -+ -+static inline int simple_util_parse_aux_devs(struct simple_util_priv *priv, char *prefix) -+{ -+ return simple_util_parse_property(priv, snd_soc_of_parse_aux_devs, -+ prefix, "aux-devs"); -+} - - int simple_util_init_jack(struct snd_soc_card *card, - struct simple_util_jack *sjack, - int is_hp, char *prefix, char *pin); --int simple_util_init_aux_jacks(struct simple_util_priv *priv, -- char *prefix); -+int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix); - int simple_util_init_priv(struct simple_util_priv *priv, - struct link_info *li); - void simple_util_remove(struct platform_device *pdev); -diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h ---- a/include/sound/soc-acpi.h -+++ b/include/sound/soc-acpi.h -@@ -57,7 +57,7 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) - #endif - - /** -- * snd_soc_acpi_mach_params: interface for machine driver configuration -+ * struct snd_soc_acpi_mach_params - interface for machine driver configuration - * - * @acpi_ipc_irq_index: used for BYT-CR detection - * @platform: string used for HDAudio codec support -@@ -93,7 +93,7 @@ struct snd_soc_acpi_mach_params { - }; - - /** -- * snd_soc_acpi_endpoint - endpoint descriptor -+ * struct snd_soc_acpi_endpoint - endpoint descriptor - * @num: endpoint number (mandatory, unique per device) - * @aggregated: 0 (independent) or 1 (logically grouped) - * @group_position: zero-based order (only when @aggregated is 1) -@@ -107,7 +107,7 @@ struct snd_soc_acpi_endpoint { - }; - - /** -- * snd_soc_acpi_adr_device - descriptor for _ADR-enumerated device -+ * struct snd_soc_acpi_adr_device - descriptor for _ADR-enumerated device - * @adr: 64 bit ACPI _ADR value - * @num_endpoints: number of endpoints for this device - * @endpoints: array of endpoints -@@ -121,7 +121,7 @@ struct snd_soc_acpi_adr_device { - }; - - /** -- * snd_soc_acpi_link_adr - ACPI-based list of _ADR enumerated devices -+ * struct snd_soc_acpi_link_adr - ACPI-based list of _ADR enumerated devices - * @mask: one bit set indicates the link this list applies to - * @num_adr: ARRAY_SIZE of devices - * @adr_d: array of devices -@@ -167,8 +167,8 @@ struct snd_soc_acpi_link_adr { - #define SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME BIT(4) - - /** -- * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are -- * related to the hardware, except for the firmware and topology file names. -+ * struct snd_soc_acpi_mach - ACPI-based machine descriptor. Most of the fields -+ * are related to the hardware, except for the firmware and topology file names. - * A platform supported by legacy and Sound Open Firmware (SOF) would expose - * all firmware/topology related fields. - * -@@ -192,6 +192,7 @@ struct snd_soc_acpi_link_adr { - * the initial selection in the snd_soc_acpi_mach table. - * @pdata: intended for platform data or machine specific-ops. This structure - * is not constant since this field may be updated at run-time -+ * @mach_params: machine driver configuration - * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @tplg_quirk_mask: quirks to select different topology files dynamically - * @get_function_tplg_files: This is an optional callback, if specified then instead of -@@ -199,11 +200,11 @@ struct snd_soc_acpi_link_adr { - * files to be loaded. - * Return value: The number of the files or negative ERRNO. 0 means that the single topology - * file should be used, no function topology split can be used on the machine. -- * @card: the pointer of the card -- * @mach: the pointer of the machine driver -- * @prefix: the prefix of the topology file name. Typically, it is the path. -- * @tplg_files: the pointer of the array of the topology file names. -- * @best_effort: ignore non supported links and try to build the card in best effort -+ * card: the pointer of the card -+ * mach: the pointer of the machine driver -+ * prefix: the prefix of the topology file name. Typically, it is the path. -+ * tplg_files: the pointer of the array of the topology file names. -+ * best_effort: ignore non supported links and try to build the card in best effort - * with supported links - */ - /* Descriptor for SST ASoC machine driver */ -diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h ---- a/include/sound/soc-component.h -+++ b/include/sound/soc-component.h -@@ -253,6 +253,9 @@ struct snd_soc_component { - void *mark_pm; - - struct dentry *debugfs_root; -+ -+ /* Component private data */ -+ void *priv; - }; - - #define for_each_component_dais(component, dai)\ -@@ -283,6 +286,14 @@ static inline int snd_soc_component_cache_sync( - return regcache_sync(component->regmap); - } - -+struct snd_soc_component *snd_soc_component_alloc(struct device *dev); -+ -+void snd_soc_component_set_name(struct snd_soc_component *component, const char *name); -+const char *snd_soc_component_name(struct snd_soc_component *component); -+ -+void snd_soc_component_set_priv(struct snd_soc_component *component, void *priv); -+void *snd_soc_component_to_priv(struct snd_soc_component *component); -+ - void snd_soc_component_set_aux(struct snd_soc_component *component, - struct snd_soc_aux_dev *aux); - int snd_soc_component_init(struct snd_soc_component *component); -diff --git a/include/sound/soc.h b/include/sound/soc.h ---- a/include/sound/soc.h -+++ b/include/sound/soc.h -@@ -447,15 +447,16 @@ static inline int snd_soc_resume(struct device *dev) - } - #endif - int snd_soc_poweroff(struct device *dev); --int snd_soc_component_initialize(struct snd_soc_component *component, -- const struct snd_soc_component_driver *driver, -- struct device *dev); --int snd_soc_add_component(struct snd_soc_component *component, -- struct snd_soc_dai_driver *dai_drv, -- int num_dai); --int snd_soc_register_component(struct device *dev, -+int snd_soc_register_component_c(struct snd_soc_component *component, - const struct snd_soc_component_driver *component_driver, - struct snd_soc_dai_driver *dai_drv, int num_dai); -+int snd_soc_register_component_d(struct device *dev, -+ const struct snd_soc_component_driver *component_driver, -+ struct snd_soc_dai_driver *dai_drv, int num_dai); -+#define snd_soc_register_component(x, ...) _Generic((x), \ -+struct device * : snd_soc_register_component_d, \ -+struct snd_soc_component * : snd_soc_register_component_c)(x, __VA_ARGS__) -+ - int devm_snd_soc_register_component(struct device *dev, - const struct snd_soc_component_driver *component_driver, - struct snd_soc_dai_driver *dai_drv, int num_dai); -diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h ---- a/include/sound/sof/dai-amd.h -+++ b/include/sound/sof/dai-amd.h -@@ -18,6 +18,7 @@ struct sof_ipc_dai_acp_params { - uint32_t fsync_rate; /* FSYNC frequency in Hz */ - uint32_t tdm_slots; - uint32_t tdm_mode; -+ uint32_t format; - } __packed; - - /* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */ -diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h ---- a/include/sound/sof/dai.h -+++ b/include/sound/sof/dai.h -@@ -90,6 +90,8 @@ enum sof_ipc_dai_type { - SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */ - SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */ - SOF_DAI_AMD_SDW, /**< AMD ACP SDW */ -+ SOF_DAI_INTEL_UAOL, /**< Intel UAOL */ -+ SOF_DAI_AMD_I2S, /**< AMD ACP I2S */ - }; - - /* general purpose DAI configuration */ -@@ -121,6 +123,7 @@ struct sof_ipc_dai_config { - struct sof_ipc_dai_mtk_afe_params afe; - struct sof_ipc_dai_micfil_params micfil; - struct sof_ipc_dai_acp_sdw_params acp_sdw; -+ struct sof_ipc_dai_acp_params acp_i2s; - }; - } __packed; - -diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h ---- a/include/sound/sof/header.h -+++ b/include/sound/sof/header.h -@@ -179,7 +179,7 @@ struct sof_ipc_compound_hdr { - uint32_t count; /**< count of 0 means end of compound sequence */ - } __packed; - --/** -+/* - * OOPS header architecture specific data. - */ - struct sof_ipc_dsp_oops_arch_hdr { -@@ -187,7 +187,7 @@ struct sof_ipc_dsp_oops_arch_hdr { - uint32_t totalsize; /* Total size of oops message */ - } __packed; - --/** -+/* - * OOPS header platform specific data. - */ - struct sof_ipc_dsp_oops_plat_hdr { -diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h ---- a/include/sound/sof/ipc4/header.h -+++ b/include/sound/sof/ipc4/header.h -@@ -187,6 +187,10 @@ enum sof_ipc4_pipeline_state { - #define SOF_IPC4_GLB_PIPE_EXT_CORE_ID_MASK GENMASK(23, 20) - #define SOF_IPC4_GLB_PIPE_EXT_CORE_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_CORE_ID_SHIFT) - -+#define SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT 29 -+#define SOF_IPC4_GLB_PIPE_PAYLOAD_MASK BIT(29) -+#define SOF_IPC4_GLB_PIPE_PAYLOAD(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT) -+ - /* pipeline set state ipc msg */ - #define SOF_IPC4_GLB_PIPE_STATE_ID_SHIFT 16 - #define SOF_IPC4_GLB_PIPE_STATE_ID_MASK GENMASK(23, 16) -@@ -536,12 +540,63 @@ enum sof_ipc4_notification_type { - SOF_IPC4_NOTIFY_TYPE_LAST, - }; - -+enum sof_ipc4_resource_type { -+ SOF_IPC4_MODULE_INSTANCE, -+ SOF_IPC4_PIPELINE, -+ SOF_IPC4_GATEWAY, -+ SOF_IPC4_EDF_TASK, -+ SOF_IPC4_INVALID_RESOURCE_TYPE, -+}; -+ -+enum sof_ipc4_event_type { -+ /* Underrun detected by the Mixer */ -+ SOF_IPC4_MIXER_UNDERRUN_DETECTED = 1, -+ /* Error caught during data processing */ -+ SOF_IPC4_PROCESS_DATA_ERROR = 3, -+ /* Underrun detected by gateway. */ -+ SOF_IPC4_GATEWAY_UNDERRUN_DETECTED = 6, -+ /* Overrun detected by gateway */ -+ SOF_IPC4_GATEWAY_OVERRUN_DETECTED, -+}; -+ -+/** -+ * struct sof_ipc4_process_data_error_event_data - process data error event payload -+ * @error_code: Error code returned by data processing function -+ */ -+struct sof_ipc4_process_data_error_event_data { -+ uint32_t error_code; -+}; -+ -+/** -+ * struct sof_ipc4_mixer_underrun_event_data - mixer underrun event payload -+ * @eos_flag: Indicates EndOfStream -+ * @data_mixed: Data processed by module (in bytes) -+ * @expected_data_mixed: Expected data to be processed (in bytes) -+ */ -+struct sof_ipc4_mixer_underrun_event_data { -+ uint32_t eos_flag; -+ uint32_t data_mixed; -+ uint32_t expected_data_mixed; -+}; -+ -+/** -+ * union sof_ipc4_resource_event_data - resource event specific payload -+ * @dws: Raw event data payload as six dwords -+ * @process_data_error: SOF_IPC4_PROCESS_DATA_ERROR payload -+ * @mixer_underrun: SOF_IPC4_MIXER_UNDERRUN_DETECTED payload -+ */ -+union sof_ipc4_resource_event_data { -+ uint32_t dws[6]; -+ struct sof_ipc4_process_data_error_event_data process_data_error; -+ struct sof_ipc4_mixer_underrun_event_data mixer_underrun; -+}; -+ - struct sof_ipc4_notify_resource_data { - uint32_t resource_type; - uint32_t resource_id; - uint32_t event_type; - uint32_t reserved; -- uint32_t data[6]; -+ union sof_ipc4_resource_event_data data; - } __packed __aligned(4); - - #define SOF_IPC4_DEBUG_DESCRIPTOR_SIZE 12 /* 3 x u32 */ -@@ -654,11 +709,81 @@ enum sof_ipc4_mod_init_ext_obj_id { - SOF_IPC4_MOD_INIT_DATA_ID_MAX = SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA, - }; - --/* DP module memory configuration data object for ext_init object array */ -+/* DP module memory configuration data object for object array */ - struct sof_ipc4_mod_init_ext_dp_memory_data { -+ u32 domain_id; /* userspace domain ID */ -+ u32 stack_bytes; /* required stack size in bytes */ -+ u32 heap_bytes; /* required heap size in bytes */ -+} __packed __aligned(4); -+ -+/* -+ * This set of macros are very similar to the set above, but these are -+ * for building payload to SOF_IPC4_GLB_CREATE_PIPELINE message. -+ * -+ * Macros for creating struct sof_ipc4_glb_pipe_payload payload with -+ * its associated data. struct sof_ipc4_glb_pipe_payload should be the -+ * first piece of payload following SOF_IPC4_GLB_CREATE_PIPELINE msg, -+ * and its existence is indicated with SOF_IPC4_GLB_PIPE_PAYLOAD bit. -+ * -+ * The macros below apply to sof_ipc4_glb_pipe_payload.word0 -+ */ -+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT 0 -+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_MASK GENMASK(23, 0) -+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT) -+ -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT 24 -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK BIT(24) -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT) -+ -+struct sof_ipc4_glb_pipe_payload { -+ u32 word0; -+ u32 rsvd1; -+ u32 rsvd2; -+} __packed __aligned(4); -+ -+/* -+ * SOF_IPC4_GLB_CREATE_PIPELINE payload may be followed by arbitrary -+ * number of object array objects. SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY-bit -+ * indicates that an array object follows struct -+ * sof_ipc4_glb_pipe_payload. -+ * -+ * The object header's SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST-bit in struct -+ * sof_ipc4_glb_pipe_ext_object indicates if the array is continued -+ * with another object. The header has also fields to identify the -+ * object, SOF_IPC4_GLB_PIPE_EXT_OBJ_ID, and to indicate the object's -+ * size in 32-bit words, SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS, not -+ * including the header itself. -+ * -+ * The macros below apply to sof_ipc4_glb_pipe_ext_object.header -+ */ -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT 0 -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK BIT(0) -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT) -+ -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT 1 -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_MASK GENMASK(15, 1) -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT) -+ -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT 16 -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_MASK GENMASK(31, 16) -+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT) -+ -+struct sof_ipc4_glb_pipe_ext_object { -+ u32 header; -+ u32 data[]; -+} __packed __aligned(4); -+ -+enum sof_ipc4_glb_pipe_ext_obj_id { -+ SOF_IPC4_GLB_PIPE_DATA_ID_INVALID = 0, -+ SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA, -+ SOF_IPC4_GLB_PIPE_DATA_ID_MAX = SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA, -+}; -+ -+/* Pipeline memory configuration data object for ext_init object array */ -+struct sof_ipc4_glb_pipe_ext_obj_memory_data { - u32 domain_id; /* userspace domain ID */ -- u32 stack_bytes; /* stack size in bytes, 0 means default size */ -- u32 heap_bytes; /* stack size in bytes, 0 means default size */ -+ u32 stack_bytes; /* stack size in bytes */ -+ u32 heap_bytes; /* heap size in bytes */ - } __packed __aligned(4); - - /** @}*/ -diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h ---- a/include/sound/tas2781-dsp.h -+++ b/include/sound/tas2781-dsp.h -@@ -201,6 +201,11 @@ struct tasdevice_rca { - int ncfgs; - struct tasdevice_config_info **cfg_info; - int profile_cfg_id; -+ /* -+ * Used among SmartAMP for PDM microphone recording or IV data -+ * capture. -+ */ -+ int capture_profile_id; - /* - * Since version 0x105, the keyword 'init' was introduced into the - * profile, which is used for chip initialization, particularly to -@@ -222,7 +227,7 @@ void tasdevice_calbin_remove(void *context); - int tasdevice_select_tuningprm_cfg(void *context, int prm, - int cfg_no, int rca_conf_no); - int tasdevice_prmg_load(void *context, int prm_no); --void tasdevice_tuning_switch(void *context, int state); -+void tasdevice_tuning_switch(void *context, int state, bool is_cap); - int tas2781_load_calibration(void *context, char *file_name, - unsigned short i); - -diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h -deleted file mode 100644 ---- a/include/sound/tlv320aic32x4.h -+++ /dev/null -@@ -1,43 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ --/* -- * tlv320aic32x4.h -- TLV320AIC32X4 Soc Audio driver platform data -- * -- * Copyright 2011 Vista Silicon S.L. -- * -- * Author: Javier Martin -- */ -- --#ifndef _AIC32X4_PDATA_H --#define _AIC32X4_PDATA_H -- --#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001 --#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002 --#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004 --#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008 --#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010 -- --#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001 --#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002 -- --/* GPIO API */ --#define AIC32X4_MFPX_DEFAULT_VALUE 0xff -- --#define AIC32X4_MFP1_DIN_DISABLED 0 --#define AIC32X4_MFP1_DIN_ENABLED 0x2 --#define AIC32X4_MFP1_GPIO_IN 0x4 -- --#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0 --#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1 -- --#define AIC32X4_MFP_GPIO_ENABLED 0x4 -- --#define AIC32X4_MFP5_GPIO_DISABLED 0x0 --#define AIC32X4_MFP5_GPIO_INPUT 0x8 --#define AIC32X4_MFP5_GPIO_OUTPUT 0xc --#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0 --#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1 -- --struct aic32x4_setup_data { -- unsigned int gpio_func[5]; --}; --#endif -diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h ---- a/include/sound/wm8904.h -+++ b/include/sound/wm8904.h -@@ -116,7 +116,7 @@ - #define WM8904_DRC_REGS 4 - #define WM8904_EQ_REGS 24 - --/** -+/* - * DRC configurations are specified with a label and a set of register - * values to write (the enable bits will be ignored). At runtime an - * enumerated control will be presented for each DRC block allowing -@@ -131,7 +131,7 @@ struct wm8904_drc_cfg { - u16 regs[WM8904_DRC_REGS]; - }; - --/** -+/* - * ReTune Mobile configurations are specified with a label, sample - * rate and set of values to write (the enable bits will be ignored). - * -diff --git a/include/uapi/sound/skl-tplg-interface.h b/include/uapi/sound/skl-tplg-interface.h -deleted file mode 100644 ---- a/include/uapi/sound/skl-tplg-interface.h -+++ /dev/null -@@ -1,168 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ --/* -- * skl-tplg-interface.h - Intel DSP FW private data interface -- * -- * Copyright (C) 2015 Intel Corp -- * Author: Jeeja KP -- * Nilofer, Samreen -- */ -- --#ifndef __HDA_TPLG_INTERFACE_H__ --#define __HDA_TPLG_INTERFACE_H__ -- --#include -- --/* -- * Default types range from 0~12. type can range from 0 to 0xff -- * SST types start at higher to avoid any overlapping in future -- */ --#define SKL_CONTROL_TYPE_BYTE_TLV 0x100 --#define SKL_CONTROL_TYPE_MIC_SELECT 0x102 --#define SKL_CONTROL_TYPE_MULTI_IO_SELECT 0x103 --#define SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC 0x104 -- --#define HDA_SST_CFG_MAX 900 /* size of copier cfg*/ --#define MAX_IN_QUEUE 8 --#define MAX_OUT_QUEUE 8 -- --#define SKL_UUID_STR_SZ 40 --/* Event types goes here */ --/* Reserve event type 0 for no event handlers */ --enum skl_event_types { -- SKL_EVENT_NONE = 0, -- SKL_MIXER_EVENT, -- SKL_MUX_EVENT, -- SKL_VMIXER_EVENT, -- SKL_PGA_EVENT --}; -- --/** -- * enum skl_ch_cfg - channel configuration -- * -- * @SKL_CH_CFG_MONO: One channel only -- * @SKL_CH_CFG_STEREO: L & R -- * @SKL_CH_CFG_2_1: L, R & LFE -- * @SKL_CH_CFG_3_0: L, C & R -- * @SKL_CH_CFG_3_1: L, C, R & LFE -- * @SKL_CH_CFG_QUATRO: L, R, Ls & Rs -- * @SKL_CH_CFG_4_0: L, C, R & Cs -- * @SKL_CH_CFG_5_0: L, C, R, Ls & Rs -- * @SKL_CH_CFG_5_1: L, C, R, Ls, Rs & LFE -- * @SKL_CH_CFG_DUAL_MONO: One channel replicated in two -- * @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ] -- * @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ] -- * @SKL_CH_CFG_INVALID: Invalid -- */ --enum skl_ch_cfg { -- SKL_CH_CFG_MONO = 0, -- SKL_CH_CFG_STEREO = 1, -- SKL_CH_CFG_2_1 = 2, -- SKL_CH_CFG_3_0 = 3, -- SKL_CH_CFG_3_1 = 4, -- SKL_CH_CFG_QUATRO = 5, -- SKL_CH_CFG_4_0 = 6, -- SKL_CH_CFG_5_0 = 7, -- SKL_CH_CFG_5_1 = 8, -- SKL_CH_CFG_DUAL_MONO = 9, -- SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10, -- SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11, -- SKL_CH_CFG_7_1 = 12, -- SKL_CH_CFG_4_CHANNEL = SKL_CH_CFG_7_1, -- SKL_CH_CFG_INVALID --}; -- --enum skl_module_type { -- SKL_MODULE_TYPE_MIXER = 0, -- SKL_MODULE_TYPE_COPIER, -- SKL_MODULE_TYPE_UPDWMIX, -- SKL_MODULE_TYPE_SRCINT, -- SKL_MODULE_TYPE_ALGO, -- SKL_MODULE_TYPE_BASE_OUTFMT, -- SKL_MODULE_TYPE_KPB, -- SKL_MODULE_TYPE_MIC_SELECT, --}; -- --enum skl_core_affinity { -- SKL_AFFINITY_CORE_0 = 0, -- SKL_AFFINITY_CORE_1, -- SKL_AFFINITY_CORE_MAX --}; -- --enum skl_pipe_conn_type { -- SKL_PIPE_CONN_TYPE_NONE = 0, -- SKL_PIPE_CONN_TYPE_FE, -- SKL_PIPE_CONN_TYPE_BE --}; -- --enum skl_hw_conn_type { -- SKL_CONN_NONE = 0, -- SKL_CONN_SOURCE = 1, -- SKL_CONN_SINK = 2 --}; -- --enum skl_dev_type { -- SKL_DEVICE_BT = 0x0, -- SKL_DEVICE_DMIC = 0x1, -- SKL_DEVICE_I2S = 0x2, -- SKL_DEVICE_SLIMBUS = 0x3, -- SKL_DEVICE_HDALINK = 0x4, -- SKL_DEVICE_HDAHOST = 0x5, -- SKL_DEVICE_NONE --}; -- --/** -- * enum skl_interleaving - interleaving style -- * -- * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN] -- * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN] -- */ --enum skl_interleaving { -- SKL_INTERLEAVING_PER_CHANNEL = 0, -- SKL_INTERLEAVING_PER_SAMPLE = 1, --}; -- --enum skl_sample_type { -- SKL_SAMPLE_TYPE_INT_MSB = 0, -- SKL_SAMPLE_TYPE_INT_LSB = 1, -- SKL_SAMPLE_TYPE_INT_SIGNED = 2, -- SKL_SAMPLE_TYPE_INT_UNSIGNED = 3, -- SKL_SAMPLE_TYPE_FLOAT = 4 --}; -- --enum module_pin_type { -- /* All pins of the module takes same PCM inputs or outputs -- * e.g. mixout -- */ -- SKL_PIN_TYPE_HOMOGENEOUS, -- /* All pins of the module takes different PCM inputs or outputs -- * e.g mux -- */ -- SKL_PIN_TYPE_HETEROGENEOUS, --}; -- --enum skl_module_param_type { -- SKL_PARAM_DEFAULT = 0, -- SKL_PARAM_INIT, -- SKL_PARAM_SET, -- SKL_PARAM_BIND --}; -- --struct skl_dfw_algo_data { -- __u32 set_params:2; -- __u32 rsvd:30; -- __u32 param_id; -- __u32 max; -- char params[]; --} __packed; -- --enum skl_tkn_dir { -- SKL_DIR_IN, -- SKL_DIR_OUT --}; -- --enum skl_tuple_type { -- SKL_TYPE_TUPLE, -- SKL_TYPE_DATA --}; -- --#endif -diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h ---- a/include/uapi/sound/snd_ar_tokens.h -+++ b/include/uapi/sound/snd_ar_tokens.h -@@ -58,7 +58,7 @@ enum ar_event_types { - #define SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX 256 - #define SND_SOC_AR_TPLG_VOL_CTL 257 - --/** -+/* - * %AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: Sub Graph Instance Id - * - * %AR_TKN_U32_SUB_GRAPH_PERF_MODE: Performance mode of subgraph -@@ -168,6 +168,60 @@ enum ar_event_types { - * LOG_WAIT = 0, - * LOG_IMMEDIATELY = 1 - * -+ * %AR_TKN_U16_MODULE_SYNC_SRC: Frame sync source -+ * AR_AUDIO_IF_SYNC_SRC_EXTERNAL = 0, -+ * AR_AUDIO_IF_SYNC_SRC_INTERNAL = 1 -+ * -+ * %AR_TKN_U16_MODULE_CTRL_DATA_OUT_ENABLE: Enable data-out tri-state control -+ * AR_AUDIO_IF_CTRL_DATA_OE_DISABLE = 0, -+ * AR_AUDIO_IF_CTRL_DATA_OE_ENABLE = 1 -+ * -+ * %AR_TKN_U32_MODULE_SLOT_MASK: Active TDM slot bitmask -+ * -+ * %AR_TKN_U16_MODULE_NSLOTS_PER_FRAME: Number of slots per TDM frame -+ * -+ * %AR_TKN_U16_MODULE_SLOT_WIDTH: Slot width in bits (16 or 32) -+ * -+ * %AR_TKN_U16_MODULE_SYNC_MODE: Frame sync mode -+ * AR_AUDIO_IF_FRAME_SYNC_MODE_SHORT = 0, -+ * AR_AUDIO_IF_FRAME_SYNC_MODE_ONE_SLOT = 1, -+ * AR_AUDIO_IF_FRAME_SYNC_MODE_LONG = 2 -+ * -+ * %AR_TKN_U16_MODULE_CTRL_INVERT_SYNC_PULSE: Invert frame sync pulse polarity -+ * AR_AUDIO_IF_SYNC_NORMAL = 0, -+ * AR_AUDIO_IF_SYNC_INVERTED = 1 -+ * -+ * %AR_TKN_U16_MODULE_CTRL_SYNC_DATA_DELAY: Data delay relative to frame sync -+ * AR_AUDIO_IF_DATA_DELAY_NONE = 0, -+ * AR_AUDIO_IF_DATA_DELAY_1_CYCLE = 1, -+ * AR_AUDIO_IF_DATA_DELAY_2_CYCLE = 2 -+ * -+ * %AR_TKN_U16_MODULE_INTF_MODE: Audio IF interface mode -+ * AR_AUDIO_IF_INTF_MODE_TDM = 0, -+ * AR_AUDIO_IF_INTF_MODE_PCM = 1, -+ * AR_AUDIO_IF_INTF_MODE_I2S = 2 -+ * -+ * %AR_TKN_U16_MODULE_QAIF_TYPE: QAIF hardware port type index -+ * AR_AUDIO_IF_QAIF = 0, -+ * AR_AUDIO_IF_QAIF_VA = 1 -+ * -+ * %AR_TKN_U32_MODULE_ACTIVE_LANE_MASK: Active lane bitmask for multi-lane -+ * -+ * %AR_TKN_U32_MODULE_FRAME_SYNC_RATE: Frame sync rate in Hz -+ * -+ * %AR_TKN_U16_MODULE_BIT_CLK_TYPE: Bit clock type -+ * AR_AUDIO_IF_BIT_CLK_INTERNAL = 0, -+ * AR_AUDIO_IF_BIT_CLK_EXTERNAL = 1, -+ * AR_AUDIO_IF_BIT_CLK_SKIP = 2 -+ * -+ * %AR_TKN_U8_MODULE_INV_INT_BIT_CLK: Invert internal bit clock -+ * AR_AUDIO_IF_CLK_NORMAL = 0, -+ * AR_AUDIO_IF_CLK_INVERTED = 1 -+ * -+ * %AR_TKN_U8_MODULE_INV_EXT_BIT_CLK: Invert external bit clock -+ * AR_AUDIO_IF_CLK_NORMAL = 0, -+ * AR_AUDIO_IF_CLK_INVERTED = 1 -+ * - * %AR_TKN_DAI_INDEX: dai index - * - */ -@@ -240,6 +294,45 @@ enum ar_event_types { - #define AR_TKN_U32_MODULE_LOG_TAP_POINT_ID 260 - #define AR_TKN_U32_MODULE_LOG_MODE 261 - -+#define AR_TKN_U16_MODULE_SYNC_SRC 262 -+#define AR_TKN_U16_MODULE_CTRL_DATA_OUT_ENABLE 263 -+#define AR_TKN_U32_MODULE_SLOT_MASK 264 -+#define AR_TKN_U16_MODULE_NSLOTS_PER_FRAME 265 -+#define AR_TKN_U16_MODULE_SLOT_WIDTH 266 -+#define AR_TKN_U16_MODULE_SYNC_MODE 267 -+#define AR_TKN_U16_MODULE_CTRL_INVERT_SYNC_PULSE 268 -+#define AR_TKN_U16_MODULE_CTRL_SYNC_DATA_DELAY 269 -+#define AR_TKN_U16_MODULE_INTF_MODE 270 -+#define AR_TKN_U16_MODULE_QAIF_TYPE 271 -+#define AR_TKN_U32_MODULE_ACTIVE_LANE_MASK 272 -+#define AR_TKN_U32_MODULE_FRAME_SYNC_RATE 273 -+#define AR_TKN_U16_MODULE_BIT_CLK_TYPE 274 -+#define AR_TKN_U8_MODULE_INV_INT_BIT_CLK 275 -+#define AR_TKN_U8_MODULE_INV_EXT_BIT_CLK 276 -+ -+#define AR_AUDIO_IF_SYNC_SRC_EXTERNAL 0 -+#define AR_AUDIO_IF_SYNC_SRC_INTERNAL 1 -+#define AR_AUDIO_IF_CTRL_DATA_OE_DISABLE 0 -+#define AR_AUDIO_IF_CTRL_DATA_OE_ENABLE 1 -+#define AR_AUDIO_IF_INTF_MODE_TDM 0 -+#define AR_AUDIO_IF_INTF_MODE_PCM 1 -+#define AR_AUDIO_IF_INTF_MODE_I2S 2 -+#define AR_AUDIO_IF_QAIF 0 -+#define AR_AUDIO_IF_QAIF_VA 1 -+#define AR_AUDIO_IF_FRAME_SYNC_MODE_SHORT 0 -+#define AR_AUDIO_IF_FRAME_SYNC_MODE_ONE_SLOT 1 -+#define AR_AUDIO_IF_FRAME_SYNC_MODE_LONG 2 -+#define AR_AUDIO_IF_SYNC_NORMAL 0 -+#define AR_AUDIO_IF_SYNC_INVERTED 1 -+#define AR_AUDIO_IF_DATA_DELAY_NONE 0 -+#define AR_AUDIO_IF_DATA_DELAY_1_CYCLE 1 -+#define AR_AUDIO_IF_DATA_DELAY_2_CYCLE 2 -+#define AR_AUDIO_IF_BIT_CLK_INTERNAL 0 -+#define AR_AUDIO_IF_BIT_CLK_EXTERNAL 1 -+#define AR_AUDIO_IF_BIT_CLK_SKIP 2 -+#define AR_AUDIO_IF_CLK_NORMAL 0 -+#define AR_AUDIO_IF_CLK_INVERTED 1 -+ - #define SND_SOC_AR_TPLG_MODULE_CFG_TYPE 0x01001006 - struct audioreach_module_priv_data { - __le32 size; /* size in bytes of the array, including all elements */ -diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h -deleted file mode 100644 ---- a/include/uapi/sound/snd_sst_tokens.h -+++ /dev/null -@@ -1,324 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ --/* -- * snd_sst_tokens.h - Intel SST tokens definition -- * -- * Copyright (C) 2016 Intel Corp -- * Author: Shreyas NC -- */ --#ifndef __SND_SST_TOKENS_H__ --#define __SND_SST_TOKENS_H__ -- --/** -- * %SKL_TKN_UUID: Module UUID -- * -- * %SKL_TKN_U8_BLOCK_TYPE: Type of the private data block.Can be: -- * tuples, bytes, short and words -- * -- * %SKL_TKN_U8_IN_PIN_TYPE: Input pin type, -- * homogenous=0, heterogenous=1 -- * -- * %SKL_TKN_U8_OUT_PIN_TYPE: Output pin type, -- * homogenous=0, heterogenous=1 -- * %SKL_TKN_U8_DYN_IN_PIN: Configure Input pin dynamically -- * if true -- * -- * %SKL_TKN_U8_DYN_OUT_PIN: Configure Output pin dynamically -- * if true -- * -- * %SKL_TKN_U8_IN_QUEUE_COUNT: Store the number of Input pins -- * -- * %SKL_TKN_U8_OUT_QUEUE_COUNT: Store the number of Output pins -- * -- * %SKL_TKN_U8_TIME_SLOT: TDM slot number -- * -- * %SKL_TKN_U8_CORE_ID: Stores module affinity value.Can take -- * the values: -- * SKL_AFFINITY_CORE_0 = 0, -- * SKL_AFFINITY_CORE_1, -- * SKL_AFFINITY_CORE_MAX -- * -- * %SKL_TKN_U8_MOD_TYPE: Module type value. -- * -- * %SKL_TKN_U8_CONN_TYPE: Module connection type can be a FE, -- * BE or NONE as defined : -- * SKL_PIPE_CONN_TYPE_NONE = 0, -- * SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA) -- * SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA) -- * -- * %SKL_TKN_U8_DEV_TYPE: Type of device to which the module is -- * connected -- * Can take the values: -- * SKL_DEVICE_BT = 0x0, -- * SKL_DEVICE_DMIC = 0x1, -- * SKL_DEVICE_I2S = 0x2, -- * SKL_DEVICE_SLIMBUS = 0x3, -- * SKL_DEVICE_HDALINK = 0x4, -- * SKL_DEVICE_HDAHOST = 0x5, -- * SKL_DEVICE_NONE -- * -- * %SKL_TKN_U8_HW_CONN_TYPE: Connection type of the HW to which the -- * module is connected -- * SKL_CONN_NONE = 0, -- * SKL_CONN_SOURCE = 1, -- * SKL_CONN_SINK = 2 -- * -- * %SKL_TKN_U16_PIN_INST_ID: Stores the pin instance id -- * -- * %SKL_TKN_U16_MOD_INST_ID: Stores the mdule instance id -- * -- * %SKL_TKN_U32_MAX_MCPS: Module max mcps value -- * -- * %SKL_TKN_U32_MEM_PAGES: Module resource pages -- * -- * %SKL_TKN_U32_OBS: Stores Output Buffer size -- * -- * %SKL_TKN_U32_IBS: Stores input buffer size -- * -- * %SKL_TKN_U32_VBUS_ID: Module VBUS_ID. PDM=0, SSP0=0, -- * SSP1=1,SSP2=2, -- * SSP3=3, SSP4=4, -- * SSP5=5, SSP6=6,INVALID -- * -- * %SKL_TKN_U32_PARAMS_FIXUP: Module Params fixup mask -- * %SKL_TKN_U32_CONVERTER: Module params converter mask -- * %SKL_TKN_U32_PIPE_ID: Stores the pipe id -- * -- * %SKL_TKN_U32_PIPE_CONN_TYPE: Type of the token to which the pipe is -- * connected to. It can be -- * SKL_PIPE_CONN_TYPE_NONE = 0, -- * SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA), -- * SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA), -- * -- * %SKL_TKN_U32_PIPE_PRIORITY: Pipe priority value -- * %SKL_TKN_U32_PIPE_MEM_PGS: Pipe resource pages -- * -- * %SKL_TKN_U32_DIR_PIN_COUNT: Value for the direction to set input/output -- * formats and the pin count. -- * The first 4 bits have the direction -- * value and the next 4 have -- * the pin count value. -- * SKL_DIR_IN = 0, SKL_DIR_OUT = 1. -- * The input and output formats -- * share the same set of tokens -- * with the distinction between input -- * and output made by reading direction -- * token. -- * -- * %SKL_TKN_U32_FMT_CH: Supported channel count -- * -- * %SKL_TKN_U32_FMT_FREQ: Supported frequency/sample rate -- * -- * %SKL_TKN_U32_FMT_BIT_DEPTH: Supported container size -- * -- * %SKL_TKN_U32_FMT_SAMPLE_SIZE:Number of samples in the container -- * -- * %SKL_TKN_U32_FMT_CH_CONFIG: Supported channel configurations for the -- * input/output. -- * -- * %SKL_TKN_U32_FMT_INTERLEAVE: Interleaving style which can be per -- * channel or per sample. The values can be : -- * SKL_INTERLEAVING_PER_CHANNEL = 0, -- * SKL_INTERLEAVING_PER_SAMPLE = 1, -- * -- * %SKL_TKN_U32_FMT_SAMPLE_TYPE: -- * Specifies the sample type. Can take the -- * values: SKL_SAMPLE_TYPE_INT_MSB = 0, -- * SKL_SAMPLE_TYPE_INT_LSB = 1, -- * SKL_SAMPLE_TYPE_INT_SIGNED = 2, -- * SKL_SAMPLE_TYPE_INT_UNSIGNED = 3, -- * SKL_SAMPLE_TYPE_FLOAT = 4 -- * -- * %SKL_TKN_U32_CH_MAP: Channel map values -- * %SKL_TKN_U32_MOD_SET_PARAMS: It can take these values: -- * SKL_PARAM_DEFAULT, SKL_PARAM_INIT, -- * SKL_PARAM_SET, SKL_PARAM_BIND -- * -- * %SKL_TKN_U32_MOD_PARAM_ID: ID of the module params -- * -- * %SKL_TKN_U32_CAPS_SET_PARAMS: -- * Set params value -- * -- * %SKL_TKN_U32_CAPS_PARAMS_ID: Params ID -- * -- * %SKL_TKN_U32_CAPS_SIZE: Caps size -- * -- * %SKL_TKN_U32_PROC_DOMAIN: Specify processing domain -- * -- * %SKL_TKN_U32_LIB_COUNT: Specifies the number of libraries -- * -- * %SKL_TKN_STR_LIB_NAME: Specifies the library name -- * -- * %SKL_TKN_U32_PMODE: Specifies the power mode for pipe -- * -- * %SKL_TKL_U32_D0I3_CAPS: Specifies the D0i3 capability for module -- * -- * %SKL_TKN_U32_DMA_BUF_SIZE: DMA buffer size in millisec -- * -- * %SKL_TKN_U32_PIPE_DIR: Specifies pipe direction. Can be -- * playback/capture. -- * -- * %SKL_TKN_U32_NUM_CONFIGS: Number of pipe configs -- * -- * %SKL_TKN_U32_PATH_MEM_PGS: Size of memory (in pages) required for pipeline -- * and its data -- * -- * %SKL_TKN_U32_PIPE_CONFIG_ID: Config id for the modules in the pipe -- * and PCM params supported by that pipe -- * config. This is used as index to fill -- * up the pipe config and module config -- * structure. -- * -- * %SKL_TKN_U32_CFG_FREQ: -- * %SKL_TKN_U8_CFG_CHAN: -- * %SKL_TKN_U8_CFG_BPS: PCM params (freq, channels, bits per sample) -- * supported for each of the pipe configs. -- * -- * %SKL_TKN_CFG_MOD_RES_ID: Module's resource index for each of the -- * pipe config -- * -- * %SKL_TKN_CFG_MOD_FMT_ID: Module's interface index for each of the -- * pipe config -- * -- * %SKL_TKN_U8_NUM_MOD: Number of modules in the manifest -- * -- * %SKL_TKN_MM_U8_MOD_IDX: Current index of the module in the manifest -- * -- * %SKL_TKN_MM_U8_NUM_RES: Number of resources for the module -- * -- * %SKL_TKN_MM_U8_NUM_INTF: Number of interfaces for the module -- * -- * %SKL_TKN_MM_U32_RES_ID: Resource index for the resource info to -- * be filled into. -- * A module can support multiple resource -- * configuration and is represnted as a -- * resource table. This index is used to -- * fill information into appropriate index. -- * -- * %SKL_TKN_MM_U32_CPS: DSP cycles per second -- * -- * %SKL_TKN_MM_U32_DMA_SIZE: Allocated buffer size for gateway DMA -- * -- * %SKL_TKN_MM_U32_CPC: DSP cycles allocated per frame -- * -- * %SKL_TKN_MM_U32_RES_PIN_ID: Resource pin index in the module -- * -- * %SKL_TKN_MM_U32_INTF_PIN_ID: Interface index in the module -- * -- * %SKL_TKN_MM_U32_PIN_BUF: Buffer size of the module pin -- * -- * %SKL_TKN_MM_U32_FMT_ID: Format index for each of the interface/ -- * format information to be filled into. -- * -- * %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats -- * %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats -- * -- * %SKL_TKN_U32_ASTATE_IDX: Table Index for the A-State entry to be filled -- * with kcps and clock source -- * -- * %SKL_TKN_U32_ASTATE_COUNT: Number of valid entries in A-State table -- * -- * %SKL_TKN_U32_ASTATE_KCPS: Specifies the core load threshold (in kilo -- * cycles per second) below which DSP is clocked -- * from source specified by clock source. -- * -- * %SKL_TKN_U32_ASTATE_CLK_SRC: Clock source for A-State entry -- * -- * %SKL_TKN_U32_FMT_CFG_IDX: Format config index -- * -- * module_id and loadable flags dont have tokens as these values will be -- * read from the DSP FW manifest -- * -- * Tokens defined can be used either in the manifest or widget private data. -- * -- * SKL_TKN_MM is used as a suffix for all tokens that represent -- * module data in the manifest. -- */ --enum SKL_TKNS { -- SKL_TKN_UUID = 1, -- SKL_TKN_U8_NUM_BLOCKS, -- SKL_TKN_U8_BLOCK_TYPE, -- SKL_TKN_U8_IN_PIN_TYPE, -- SKL_TKN_U8_OUT_PIN_TYPE, -- SKL_TKN_U8_DYN_IN_PIN, -- SKL_TKN_U8_DYN_OUT_PIN, -- SKL_TKN_U8_IN_QUEUE_COUNT, -- SKL_TKN_U8_OUT_QUEUE_COUNT, -- SKL_TKN_U8_TIME_SLOT, -- SKL_TKN_U8_CORE_ID, -- SKL_TKN_U8_MOD_TYPE, -- SKL_TKN_U8_CONN_TYPE, -- SKL_TKN_U8_DEV_TYPE, -- SKL_TKN_U8_HW_CONN_TYPE, -- SKL_TKN_U16_MOD_INST_ID, -- SKL_TKN_U16_BLOCK_SIZE, -- SKL_TKN_U32_MAX_MCPS, -- SKL_TKN_U32_MEM_PAGES, -- SKL_TKN_U32_OBS, -- SKL_TKN_U32_IBS, -- SKL_TKN_U32_VBUS_ID, -- SKL_TKN_U32_PARAMS_FIXUP, -- SKL_TKN_U32_CONVERTER, -- SKL_TKN_U32_PIPE_ID, -- SKL_TKN_U32_PIPE_CONN_TYPE, -- SKL_TKN_U32_PIPE_PRIORITY, -- SKL_TKN_U32_PIPE_MEM_PGS, -- SKL_TKN_U32_DIR_PIN_COUNT, -- SKL_TKN_U32_FMT_CH, -- SKL_TKN_U32_FMT_FREQ, -- SKL_TKN_U32_FMT_BIT_DEPTH, -- SKL_TKN_U32_FMT_SAMPLE_SIZE, -- SKL_TKN_U32_FMT_CH_CONFIG, -- SKL_TKN_U32_FMT_INTERLEAVE, -- SKL_TKN_U32_FMT_SAMPLE_TYPE, -- SKL_TKN_U32_FMT_CH_MAP, -- SKL_TKN_U32_PIN_MOD_ID, -- SKL_TKN_U32_PIN_INST_ID, -- SKL_TKN_U32_MOD_SET_PARAMS, -- SKL_TKN_U32_MOD_PARAM_ID, -- SKL_TKN_U32_CAPS_SET_PARAMS, -- SKL_TKN_U32_CAPS_PARAMS_ID, -- SKL_TKN_U32_CAPS_SIZE, -- SKL_TKN_U32_PROC_DOMAIN, -- SKL_TKN_U32_LIB_COUNT, -- SKL_TKN_STR_LIB_NAME, -- SKL_TKN_U32_PMODE, -- SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */ -- SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS, -- SKL_TKN_U32_DMA_BUF_SIZE, -- -- SKL_TKN_U32_PIPE_DIRECTION, -- SKL_TKN_U32_PIPE_CONFIG_ID, -- SKL_TKN_U32_NUM_CONFIGS, -- SKL_TKN_U32_PATH_MEM_PGS, -- -- SKL_TKN_U32_CFG_FREQ, -- SKL_TKN_U8_CFG_CHAN, -- SKL_TKN_U8_CFG_BPS, -- SKL_TKN_CFG_MOD_RES_ID, -- SKL_TKN_CFG_MOD_FMT_ID, -- SKL_TKN_U8_NUM_MOD, -- -- SKL_TKN_MM_U8_MOD_IDX, -- SKL_TKN_MM_U8_NUM_RES, -- SKL_TKN_MM_U8_NUM_INTF, -- SKL_TKN_MM_U32_RES_ID, -- SKL_TKN_MM_U32_CPS, -- SKL_TKN_MM_U32_DMA_SIZE, -- SKL_TKN_MM_U32_CPC, -- SKL_TKN_MM_U32_RES_PIN_ID, -- SKL_TKN_MM_U32_INTF_PIN_ID, -- SKL_TKN_MM_U32_PIN_BUF, -- SKL_TKN_MM_U32_FMT_ID, -- SKL_TKN_MM_U32_NUM_IN_FMT, -- SKL_TKN_MM_U32_NUM_OUT_FMT, -- -- SKL_TKN_U32_ASTATE_IDX, -- SKL_TKN_U32_ASTATE_COUNT, -- SKL_TKN_U32_ASTATE_KCPS, -- SKL_TKN_U32_ASTATE_CLK_SRC, -- -- SKL_TKN_U32_FMT_CFG_IDX = 96, -- SKL_TKN_MAX = SKL_TKN_U32_FMT_CFG_IDX, --}; -- --#endif -diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h ---- a/include/uapi/sound/sof/tokens.h -+++ b/include/uapi/sound/sof/tokens.h -@@ -111,8 +111,8 @@ - - #define SOF_TKN_COMP_SCHED_DOMAIN 418 - #define SOF_TKN_COMP_DOMAIN_ID 419 --#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 420 --#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 421 -+#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 420 -+#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 421 - - /* SSP */ - #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 -@@ -223,6 +223,7 @@ - #define SOF_TKN_AMD_ACPI2S_RATE 1700 - #define SOF_TKN_AMD_ACPI2S_CH 1701 - #define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702 -+#define SOF_TKN_AMD_ACPI2S_FORMAT 1703 - - /* MICFIL PDM */ - #define SOF_TKN_IMX_MICFIL_RATE 2000 -diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c ---- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c -+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c -@@ -171,13 +171,13 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) - case HDA_GEN_PCM_ACT_OPEN: - pm_runtime_get_sync(dev); - scoped_guard(mutex, &tas_hda->priv->codec_lock) { -- tasdevice_tuning_switch(tas_hda->priv, 0); -+ tasdevice_tuning_switch(tas_hda->priv, 0, false); - tas_hda->priv->playback_started = true; - } - break; - case HDA_GEN_PCM_ACT_CLOSE: - scoped_guard(mutex, &tas_hda->priv->codec_lock) { -- tasdevice_tuning_switch(tas_hda->priv, 1); -+ tasdevice_tuning_switch(tas_hda->priv, 1, false); - tas_hda->priv->playback_started = false; - } - -@@ -720,7 +720,7 @@ static int tas2781_runtime_suspend(struct device *dev) - * Stop the playback if it's unused. - */ - if (tas_hda->priv->playback_started) { -- tasdevice_tuning_switch(tas_hda->priv, 1); -+ tasdevice_tuning_switch(tas_hda->priv, 1, false); - tas_hda->priv->playback_started = false; - } - -@@ -750,7 +750,7 @@ static int tas2781_system_suspend(struct device *dev) - - /* Shutdown chip before system suspend */ - if (tas_hda->priv->playback_started) -- tasdevice_tuning_switch(tas_hda->priv, 1); -+ tasdevice_tuning_switch(tas_hda->priv, 1, false); - - /* - * Reset GPIO may be shared, so cannot reset here. -@@ -783,7 +783,7 @@ static int tas2781_system_resume(struct device *dev) - TASDEVICE_BIN_BLK_PRE_POWER_UP); - - if (tas_hda->priv->playback_started) -- tasdevice_tuning_switch(tas_hda->priv, 0); -+ tasdevice_tuning_switch(tas_hda->priv, 0, false); - - return 0; - } -diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c ---- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c -+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c -@@ -399,11 +399,11 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) - pm_runtime_get_sync(dev); - guard(mutex)(&tas_priv->codec_lock); - if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK) -- tasdevice_tuning_switch(tas_hda->priv, 0); -+ tasdevice_tuning_switch(tas_hda->priv, 0, false); - } else if (action == HDA_GEN_PCM_ACT_CLOSE) { - guard(mutex)(&tas_priv->codec_lock); - if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK) -- tasdevice_tuning_switch(tas_priv, 1); -+ tasdevice_tuning_switch(tas_priv, 1, false); - pm_runtime_put_autosuspend(dev); - } - } -@@ -847,7 +847,7 @@ static int tas2781_runtime_suspend(struct device *dev) - - if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK - && tas_priv->playback_started) -- tasdevice_tuning_switch(tas_priv, 1); -+ tasdevice_tuning_switch(tas_priv, 1, false); - - tas_priv->tasdevice[tas_priv->index].cur_book = -1; - tas_priv->tasdevice[tas_priv->index].cur_conf = -1; -@@ -864,7 +864,7 @@ static int tas2781_runtime_resume(struct device *dev) - - if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK - && tas_priv->playback_started) -- tasdevice_tuning_switch(tas_priv, 0); -+ tasdevice_tuning_switch(tas_priv, 0, false); - - return 0; - } -@@ -882,7 +882,7 @@ static int tas2781_system_suspend(struct device *dev) - /* Shutdown chip before system suspend */ - if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK - && tas_priv->playback_started) -- tasdevice_tuning_switch(tas_priv, 1); -+ tasdevice_tuning_switch(tas_priv, 1, false); - - return 0; - } -@@ -917,7 +917,7 @@ static int tas2781_system_resume(struct device *dev) - tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; - - if (tas_priv->playback_started) -- tasdevice_tuning_switch(tas_priv, 0); -+ tasdevice_tuning_switch(tas_priv, 0, false); - } - - return ret; -diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c ---- a/sound/soc/amd/acp-config.c -+++ b/sound/soc/amd/acp-config.c -@@ -63,6 +63,13 @@ static const struct dmi_system_id acp70_acpi_flag_override_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook 18 M1807GA"), - }, - }, -+ { -+ /* HP OmniBook X Flip 14-kc0xxx (Strix Point, ACP 7.2) */ -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"), -+ DMI_MATCH(DMI_BOARD_NAME, "8EA1"), -+ }, -+ }, - {} - }; - -@@ -379,5 +386,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[] = { - }; - EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_machines); - -+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[] = { -+ { -+ .id = "AMDI1010", -+ .drv_name = "acp7x-dsp", -+ .pdata = &acp_quirk_data, -+ .fw_filename = "sof-acp7x.ri", -+ .sof_tplg_filename = "sof-acp7x.tplg", -+ }, -+ {}, -+}; -+EXPORT_SYMBOL(snd_soc_acpi_amd_acp7x_sof_machines); -+ - MODULE_DESCRIPTION("AMD ACP Machine Configuration Module"); - MODULE_LICENSE("Dual BSD/GPL"); -diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c ---- a/sound/soc/amd/acp-pcm-dma.c -+++ b/sound/soc/amd/acp-pcm-dma.c -@@ -691,12 +691,10 @@ static irqreturn_t dma_irq_handler(int irq, void *arg) - { - u16 dscr_idx; - u32 intr_flag, ext_intr_status; -- struct audio_drv_data *irq_data; -+ struct audio_drv_data *irq_data = arg; - void __iomem *acp_mmio; -- struct device *dev = arg; - bool valid_irq = false; - -- irq_data = dev_get_drvdata(dev); - acp_mmio = irq_data->acp_mmio; - - ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT); -@@ -1291,10 +1289,10 @@ static int acp_audio_probe(struct platform_device *pdev) - - irq = platform_get_irq(pdev, 0); - if (irq < 0) -- return -ENODEV; -+ return irq; - - status = devm_request_irq(&pdev->dev, irq, dma_irq_handler, -- 0, "ACP_IRQ", &pdev->dev); -+ 0, "ACP_IRQ", audio_drv_data); - if (status) { - dev_err(&pdev->dev, "ACP IRQ request failed\n"); - return status; -diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c ---- a/sound/soc/amd/acp/acp-i2s.c -+++ b/sound/soc/amd/acp/acp-i2s.c -@@ -686,6 +686,10 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d - return 0; - } - -+static const u64 acp_i2s_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A; -+ - const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { - .startup = acp_i2s_startup, - .hw_params = acp_i2s_hwparams, -@@ -693,6 +697,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { - .trigger = acp_i2s_trigger, - .set_fmt = acp_i2s_set_fmt, - .set_tdm_slot = acp_i2s_set_tdm_slot, -+ .auto_selectable_formats = &acp_i2s_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON"); - -diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c ---- a/sound/soc/amd/acp/acp-mach-common.c -+++ b/sound/soc/amd/acp/acp-mach-common.c -@@ -938,15 +938,10 @@ static int acp_max98388_hw_params(struct snd_pcm_substream *substream, - struct snd_soc_dai *codec_dai = - snd_soc_card_get_codec_dai(card, - MAX98388_CODEC_DAI); -- int ret; - -- ret = snd_soc_dai_set_fmt(codec_dai, -- SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S | -- SND_SOC_DAIFMT_NB_NF); -- if (ret < 0) -- return ret; -- -- return ret; -+ return snd_soc_dai_set_fmt(codec_dai, -+ SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_NF); - } - - static const struct snd_soc_ops acp_max98388_ops = { -diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c ---- a/sound/soc/amd/acp/acp-pci.c -+++ b/sound/soc/amd/acp/acp-pci.c -@@ -118,17 +118,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id - if (!chip) - return -ENOMEM; - -- if (pci_enable_device(pci)) -+ if (pcim_enable_device(pci)) - return dev_err_probe(&pci->dev, -ENODEV, - "pci_enable_device failed\n"); - -- ret = pci_request_regions(pci, "AMD ACP3x audio"); -- if (ret < 0) { -- dev_err(&pci->dev, "pci_request_regions failed\n"); -- ret = -ENOMEM; -- goto disable_pci; -- } -- - pci_set_master(pci); - - chip->acp_rev = pci->revision; -@@ -161,24 +154,21 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id - break; - default: - dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); -- ret = -EINVAL; -- goto release_regions; -+ return -EINVAL; - } - chip->flag = flag; - - addr = pci_resource_start(pci, 0); -- chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); -- if (!chip->base) { -- ret = -ENOMEM; -- goto release_regions; -- } -+ chip->base = pcim_iomap_region(pci, 0, "AMD ACP3x audio"); -+ if (IS_ERR(chip->base)) -+ return PTR_ERR(chip->base); - - chip->addr = addr; - - chip->acp_hw_ops_init(chip); - ret = acp_hw_init(chip); - if (ret) -- goto release_regions; -+ goto de_init; - - ret = devm_request_irq(dev, pci->irq, irq_handler, - IRQF_SHARED, "ACP_I2S_IRQ", chip); -@@ -214,10 +204,6 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id - - de_init: - acp_hw_deinit(chip); --release_regions: -- pci_release_regions(pci); --disable_pci: -- pci_disable_device(pci); - - return ret; - }; -diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c ---- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c -+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c -@@ -531,15 +531,15 @@ static int mc_probe(struct platform_device *pdev) - dmi_check_system(soc_sdw_quirk_table); - - if (quirk_override != -1) { -- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", -+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", - soc_sdw_quirk, quirk_override); - soc_sdw_quirk = quirk_override; - } - -- log_quirks(card->dev); -+ log_quirks(&pdev->dev); - - ctx->mc_quirk = soc_sdw_quirk; -- dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk); -+ dev_dbg(&pdev->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk); - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ctx->codec_info_list_count; i++) - codec_info_list[i].amp_num = 0; -@@ -556,12 +556,12 @@ static int mc_probe(struct platform_device *pdev) - for (i = 0; i < ctx->codec_info_list_count; i++) - amp_num += codec_info_list[i].amp_num; - -- card->components = devm_kasprintf(card->dev, GFP_KERNEL, -+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, - " cfg-amp:%d", amp_num); - if (!card->components) - return -ENOMEM; - if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) { -- card->components = devm_kasprintf(card->dev, GFP_KERNEL, -+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, - "%s mic:acp-dmic cfg-mics:%d", - card->components, - 1); -@@ -570,9 +570,9 @@ static int mc_probe(struct platform_device *pdev) - } - - /* Register the card */ -- ret = devm_snd_soc_register_card(card->dev, card); -+ ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { -- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); -+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret); - asoc_sdw_mc_dailink_exit_loop(card); - return ret; - } -@@ -590,8 +590,8 @@ static void mc_remove(struct platform_device *pdev) - } - - static const struct platform_device_id mc_id_table[] = { -- { "amd_sdw", }, -- {} -+ { .name = "amd_sdw" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, mc_id_table); - -diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c ---- a/sound/soc/amd/acp/acp-sdw-sof-mach.c -+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c -@@ -314,7 +314,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) - if (!sof_aux) - return -ENOMEM; - -- ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs); -+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_devs); - if (ret < 0) - return ret; - -@@ -399,12 +399,12 @@ static int mc_probe(struct platform_device *pdev) - dmi_check_system(sof_sdw_quirk_table); - - if (quirk_override != -1) { -- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", -+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", - sof_sdw_quirk, quirk_override); - sof_sdw_quirk = quirk_override; - } - -- log_quirks(card->dev); -+ log_quirks(&pdev->dev); - - ctx->mc_quirk = sof_sdw_quirk; - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ -@@ -423,15 +423,15 @@ static int mc_probe(struct platform_device *pdev) - for (i = 0; i < ctx->codec_info_list_count; i++) - amp_num += codec_info_list[i].amp_num; - -- card->components = devm_kasprintf(card->dev, GFP_KERNEL, -+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, - " cfg-amp:%d", amp_num); - if (!card->components) - return -ENOMEM; - - /* Register the card */ -- ret = devm_snd_soc_register_card(card->dev, card); -+ ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { -- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); -+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret); - asoc_sdw_mc_dailink_exit_loop(card); - return ret; - } -@@ -449,8 +449,8 @@ static void mc_remove(struct platform_device *pdev) - } - - static const struct platform_device_id mc_id_table[] = { -- { "amd_sof_sdw", }, -- {} -+ { .name = "amd_sof_sdw" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, mc_id_table); - -diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c ---- a/sound/soc/amd/acp/acp-sof-mach.c -+++ b/sound/soc/amd/acp/acp-sof-mach.c -@@ -128,31 +128,31 @@ static int acp_sof_probe(struct platform_device *pdev) - static const struct platform_device_id board_ids[] = { - { - .name = "rt5682-rt1019", -- .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data -+ .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data, - }, - { - .name = "rt5682-max", -- .driver_data = (kernel_ulong_t)&sof_rt5682_max_data -+ .driver_data = (kernel_ulong_t)&sof_rt5682_max_data, - }, - { - .name = "rt5682s-max", -- .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data -+ .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data, - }, - { - .name = "rt5682s-rt1019", -- .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data -+ .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data, - }, - { - .name = "nau8825-max", -- .driver_data = (kernel_ulong_t)&sof_nau8825_data -+ .driver_data = (kernel_ulong_t)&sof_nau8825_data, - }, - { - .name = "rt5682s-hs-rt1019", -- .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data -+ .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data, - }, - { - .name = "nau8821-max", -- .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data -+ .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data, - }, - { } - }; -diff --git a/sound/soc/amd/acp/amd-acp70-acpi-match.c b/sound/soc/amd/acp/amd-acp70-acpi-match.c ---- a/sound/soc/amd/acp/amd-acp70-acpi-match.c -+++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c -@@ -659,6 +659,56 @@ static const struct snd_soc_acpi_link_adr acp70_rt721_l1u0_tas2783x2_l1u8b[] = { - {} - }; - -+static const struct snd_soc_acpi_adr_device rt712_vb_l1u0_adr[] = { -+ { -+ .adr = 0x000130025D071201ull, -+ /* -+ * On this platform speakers are provided by two TAS2783 amps, -+ * so the AIF2 amp path is left unused: jack + DMIC only. -+ */ -+ .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints), -+ .endpoints = jack_dmic_endpoints, -+ .name_prefix = "rt712" -+ } -+}; -+ -+/* -+ * Unique ID 0xC drives the left speaker and 0x9 the right one. The order of the -+ * entries matters as much as the endpoints: asoc_sdw_parse_sdw_endpoints() -+ * appends them to the dailink in array order and sdw_compute_slave_ports() -+ * hands out payload block offsets in that same order, so the first entry is the -+ * one that receives channel 0. -+ */ -+static const struct snd_soc_acpi_adr_device tas2783x2_l0u9c_adr[] = { -+ { -+ .adr = 0x00003C0102000001ull, -+ .num_endpoints = 1, -+ .endpoints = &spk_l_endpoint, -+ .name_prefix = "tas2783-1", -+ }, -+ { -+ .adr = 0x0000390102000001ull, -+ .num_endpoints = 1, -+ .endpoints = &spk_r_endpoint, -+ .name_prefix = "tas2783-2", -+ }, -+}; -+ -+/* HP OmniBook X Flip 14-kc0xxx (board 8EA1) */ -+static const struct snd_soc_acpi_link_adr acp70_tas2783x2_l0u9c_rt712_vb_l1u0[] = { -+ { -+ .mask = BIT(0), -+ .num_adr = ARRAY_SIZE(tas2783x2_l0u9c_adr), -+ .adr_d = tas2783x2_l0u9c_adr, -+ }, -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(rt712_vb_l1u0_adr), -+ .adr_d = rt712_vb_l1u0_adr, -+ }, -+ {} -+}; -+ - static const struct snd_soc_acpi_endpoint rt721_endpoints[] = { - { /* Jack Playback/Capture Endpoint (AIF1) */ - .num = 0, -@@ -704,6 +754,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[] = { - .links = acp70_tas2783_2, - .drv_name = "amd_sdw", - }, -+ { -+ .link_mask = BIT(0) | BIT(1), -+ .links = acp70_tas2783x2_l0u9c_rt712_vb_l1u0, -+ .machine_check = snd_soc_acpi_amd_sdca_is_device_rt712_vb, -+ .drv_name = "amd_sdw", -+ }, - { - .link_mask = BIT(0) | BIT(1), - .links = acp70_rt1320_l0_rt722_l1, -diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h ---- a/sound/soc/amd/mach-config.h -+++ b/sound/soc/amd/mach-config.h -@@ -28,6 +28,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; - extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[]; - extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[]; - extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[]; -+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[]; - - struct config_entry { - u32 flags; -diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c ---- a/sound/soc/amd/raven/acp3x-i2s.c -+++ b/sound/soc/amd/raven/acp3x-i2s.c -@@ -250,11 +250,17 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, - return ret; - } - -+static const u64 acp3x_i2s_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A; -+ - static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = { - .hw_params = acp3x_i2s_hwparams, - .trigger = acp3x_i2s_trigger, - .set_fmt = acp3x_i2s_set_fmt, - .set_tdm_slot = acp3x_i2s_set_tdm_slot, -+ .auto_selectable_formats = &acp3x_i2s_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static const struct snd_soc_component_driver acp3x_dai_component = { -diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c ---- a/sound/soc/amd/vangogh/acp5x-i2s.c -+++ b/sound/soc/amd/vangogh/acp5x-i2s.c -@@ -337,11 +337,17 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream, - return ret; - } - -+static const u64 acp5x_i2s_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A; -+ - static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = { - .hw_params = acp5x_i2s_hwparams, - .trigger = acp5x_i2s_trigger, - .set_fmt = acp5x_i2s_set_fmt, - .set_tdm_slot = acp5x_i2s_set_tdm_slot, -+ .auto_selectable_formats = &acp5x_i2s_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static const struct snd_soc_component_driver acp5x_dai_component = { -diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c ---- a/sound/soc/amd/yc/acp6x-mach.c -+++ b/sound/soc/amd/yc/acp6x-mach.c -@@ -795,12 +795,12 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { - } - }, - { -- .driver_data = &acp6x_card, -- .matches = { -- DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"), -- } -- }, -+ .driver_data = &acp6x_card, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"), -+ } -+ }, - { - .driver_data = &acp6x_card, - .matches = { -diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c ---- a/sound/soc/apple/mca.c -+++ b/sound/soc/apple/mca.c -@@ -133,12 +133,17 @@ struct mca_cluster { - struct clk *clk_parent; - struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1]; - -- bool port_started[SNDRV_PCM_STREAM_LAST + 1]; -- int port_driver; /* The cluster driving this cluster's port */ -+ bool clk_provider; -+ -+ bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1]; -+ int port_clk_driver; /* The cluster driving this cluster's port */ - - bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1]; - struct device_link *pd_link; - -+ /* In case of clock consumer FE */ -+ int syncgen_in_use; -+ - unsigned int bclk_ratio; - - /* Masks etc. picked up via the set_tdm_slot method */ -@@ -157,7 +162,7 @@ struct mca_data { - struct reset_control *rstc; - struct device_link *pd_link; - -- /* Mutex for accessing port_driver of foreign clusters */ -+ /* Mutex for accessing port_clk_driver of foreign clusters */ - struct mutex port_mutex; - - int nclusters; -@@ -220,6 +225,12 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd, - FIELD_PREP(SERDES_CONF_SYNC_SEL, 0)); - mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL, - FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1)); -+ /* -+ * ADMAC gets started right after this. This delay seems -+ * to be needed for that to be reliable, e.g. ensure the -+ * clock is stable? -+ */ -+ udelay(100); - break; - default: - break; -@@ -256,11 +267,29 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd, - return 0; - } - -+static int mca_fe_get_portmask(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_dpcm *dpcm; -+ int mask = 0; -+ -+ for_each_dpcm_be(fe, substream->stream, dpcm) { -+ int no = mca_dai_to_cluster(snd_soc_rtd_to_cpu(dpcm->be, 0))->no; -+ -+ mask |= 1 << no; -+ } -+ -+ return mask; -+} -+ - static int mca_fe_enable_clocks(struct mca_cluster *cl) - { - struct mca_data *mca = cl->host; - int ret; - -+ if (!cl->clk_provider) -+ return -EINVAL; -+ - ret = clk_prepare_enable(cl->clk_parent); - if (ret) { - dev_err(mca->dev, -@@ -311,7 +340,7 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl) - for (i = 0; i < mca->nclusters; i++) { - be_cl = &mca->clusters[i]; - -- if (be_cl->port_driver != cl->no) -+ if (be_cl->port_clk_driver != cl->no) - continue; - - for_each_pcm_streams(stream) { -@@ -323,36 +352,6 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl) - return false; - } - --static int mca_be_prepare(struct snd_pcm_substream *substream, -- struct snd_soc_dai *dai) --{ -- struct mca_cluster *cl = mca_dai_to_cluster(dai); -- struct mca_data *mca = cl->host; -- struct mca_cluster *fe_cl; -- int ret; -- -- if (cl->port_driver < 0) -- return -EINVAL; -- -- fe_cl = &mca->clusters[cl->port_driver]; -- -- /* -- * Typically the CODECs we are paired with will require clocks -- * to be present at time of unmute with the 'mute_stream' op -- * or at time of DAPM widget power-up. We need to enable clocks -- * here at the latest (frontend prepare would be too late). -- */ -- if (!mca_fe_clocks_in_use(fe_cl)) { -- ret = mca_fe_enable_clocks(fe_cl); -- if (ret < 0) -- return ret; -- } -- -- cl->clocks_in_use[substream->stream] = true; -- -- return 0; --} -- - static int mca_be_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { -@@ -360,7 +359,7 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, - struct mca_data *mca = cl->host; - struct mca_cluster *fe_cl; - -- if (cl->port_driver < 0) -+ if (cl->port_clk_driver < 0) - return -EINVAL; - - /* -@@ -368,7 +367,7 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, - * belong to the same PCM, accesses should have been - * synchronized at ASoC level. - */ -- fe_cl = &mca->clusters[cl->port_driver]; -+ fe_cl = &mca->clusters[cl->port_clk_driver]; - if (!mca_fe_clocks_in_use(fe_cl)) - return 0; /* Nothing to do */ - -@@ -380,6 +379,56 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, - return 0; - } - -+static int mca_fe_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct mca_cluster *cl = mca_dai_to_cluster(dai); -+ struct mca_data *mca = cl->host; -+ -+ if (cl->clk_provider) -+ return 0; -+ -+ /* Turn on the cluster power domain if not already in use */ -+ if (!cl->syncgen_in_use) { -+ int port = ffs(mca_fe_get_portmask(substream)); -+ -+ cl->pd_link = device_link_add(mca->dev, cl->pd_dev, -+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | -+ DL_FLAG_RPM_ACTIVE); -+ if (!cl->pd_link) { -+ dev_err(mca->dev, -+ "cluster %d: unable to prop-up power domain\n", cl->no); -+ return -EINVAL; -+ } -+ -+ mca_modify(cl, REG_SYNCGEN_MCLK_SEL, SYNCGEN_MCLK_SEL, BIT(port)); -+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, -+ SYNCGEN_STATUS_EN); -+ } -+ cl->syncgen_in_use |= 1 << substream->stream; -+ -+ return 0; -+} -+ -+static int mca_fe_hw_free(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct mca_cluster *cl = mca_dai_to_cluster(dai); -+ -+ if (cl->clk_provider) -+ return 0; -+ -+ cl->syncgen_in_use &= ~(1 << substream->stream); -+ if (cl->syncgen_in_use) -+ return 0; -+ -+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0); -+ if (cl->pd_link) -+ device_link_del(cl->pd_link); -+ -+ return 0; -+} -+ - static unsigned int mca_crop_mask(unsigned int mask, int nchans) - { - while (hweight32(mask) > nchans) -@@ -390,7 +439,7 @@ static unsigned int mca_crop_mask(unsigned int mask, int nchans) - - static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit, - unsigned int mask, int slots, int nchans, -- int slot_width, bool is_tx, int port) -+ int slot_width, bool is_tx, int portmask) - { - __iomem void *serdes_base = cl->base + serdes_unit; - u32 serdes_conf, serdes_conf_mask; -@@ -449,7 +498,7 @@ static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit, - serdes_base + REG_RX_SERDES_SLOTMASK); - writel_relaxed(~((u32)mca_crop_mask(mask, nchans)), - serdes_base + REG_RX_SERDES_SLOTMASK + 0x4); -- writel_relaxed(1 << port, -+ writel_relaxed(portmask, - serdes_base + REG_RX_SERDES_PORT); - } - -@@ -505,9 +554,18 @@ static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - u32 serdes_conf = 0; - u32 bitstart; - -- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != -- SND_SOC_DAIFMT_BP_FP) -+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { -+ case SND_SOC_DAIFMT_BP_FP: -+ cl->clk_provider = true; -+ break; -+ -+ case SND_SOC_DAIFMT_BC_FC: -+ cl->clk_provider = false; -+ break; -+ -+ default: - goto err; -+ } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: -@@ -564,24 +622,6 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) - return 0; - } - --static int mca_fe_get_port(struct snd_pcm_substream *substream) --{ -- struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); -- struct snd_soc_pcm_runtime *be; -- struct snd_soc_dpcm *dpcm; -- -- be = NULL; -- for_each_dpcm_be(fe, substream->stream, dpcm) { -- be = dpcm->be; -- break; -- } -- -- if (!be) -- return -EINVAL; -- -- return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no; --} -- - static int mca_fe_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -@@ -595,7 +635,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, - unsigned long bclk_ratio; - unsigned int tdm_slots, tdm_slot_width, tdm_mask; - u32 regval, pad; -- int ret, port, nchans_ceiled; -+ int ret, portmask, nchans_ceiled; - - if (!cl->tdm_slot_width) { - /* -@@ -644,13 +684,13 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, - tdm_mask = (1 << tdm_slots) - 1; - } - -- port = mca_fe_get_port(substream); -- if (port < 0) -- return port; -+ portmask = mca_fe_get_portmask(substream); -+ if (!portmask) -+ return -EINVAL; - - ret = mca_configure_serdes(cl, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF, - tdm_mask, tdm_slots, params_channels(params), -- tdm_slot_width, is_tx, port); -+ tdm_slot_width, is_tx, portmask); - if (ret) - return ret; - -@@ -699,6 +739,19 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, - return 0; - } - -+static const u64 mca_fe_selectable_formats[] = -+{ -+ /* pattern 1 */ -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_NB_IF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF, -+ -+ /* pattern 2 */ -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_NF -+}; -+ - static const struct snd_soc_dai_ops mca_fe_ops = { - .startup = mca_fe_startup, - .set_fmt = mca_fe_set_fmt, -@@ -706,66 +759,128 @@ static const struct snd_soc_dai_ops mca_fe_ops = { - .set_tdm_slot = mca_fe_set_tdm_slot, - .hw_params = mca_fe_hw_params, - .trigger = mca_fe_trigger, -+ .prepare = mca_fe_prepare, -+ .hw_free = mca_fe_hw_free, -+ .auto_selectable_formats = mca_fe_selectable_formats, -+ .num_auto_selectable_formats = ARRAY_SIZE(mca_fe_selectable_formats), - }; - --static bool mca_be_started(struct mca_cluster *cl) -+/* -+ * Is there a FE attached which will be feeding this port's clocks? -+ */ -+static bool mca_be_clk_started(struct mca_cluster *cl) - { - int stream; - - for_each_pcm_streams(stream) -- if (cl->port_started[stream]) -+ if (cl->port_clk_started[stream]) - return true; - return false; - } - -+static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be, -+ int stream) -+{ -+ struct snd_soc_pcm_runtime *fe = NULL; -+ struct snd_soc_dpcm *dpcm; -+ -+ for_each_dpcm_fe(be, stream, dpcm) { -+ if (fe && dpcm->fe != fe) { -+ dev_err(be->dev, "many FE per one BE unsupported\n"); -+ return NULL; -+ } -+ -+ fe = dpcm->fe; -+ } -+ -+ return fe; -+} -+ -+static int mca_be_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream); -+ struct mca_cluster *cl = mca_dai_to_cluster(dai); -+ struct mca_data *mca = cl->host; -+ struct mca_cluster *fe_cl, *fe_clk_cl; -+ int ret; -+ -+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); -+ -+ if (!fe_cl->clk_provider) -+ return 0; -+ -+ if (cl->port_clk_driver < 0) -+ return 0; -+ -+ fe_clk_cl = &mca->clusters[cl->port_clk_driver]; -+ -+ /* -+ * Typically the CODECs we are paired with will require clocks -+ * to be present at time of unmute with the 'mute_stream' op -+ * or at time of DAPM widget power-up. We need to enable clocks -+ * here at the latest (frontend prepare would be too late). -+ */ -+ if (!mca_fe_clocks_in_use(fe_clk_cl)) { -+ ret = mca_fe_enable_clocks(fe_clk_cl); -+ if (ret < 0) -+ return ret; -+ } -+ -+ cl->clocks_in_use[substream->stream] = true; -+ -+ return 0; -+} -+ - static int mca_be_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { - struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); -- struct snd_soc_pcm_runtime *fe; -+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream); - struct mca_cluster *cl = mca_dai_to_cluster(dai); - struct mca_cluster *fe_cl; - struct mca_data *mca = cl->host; -- struct snd_soc_dpcm *dpcm; -- -- fe = NULL; -- -- for_each_dpcm_fe(be, substream->stream, dpcm) { -- if (fe && dpcm->fe != fe) { -- dev_err(mca->dev, "many FE per one BE unsupported\n"); -- return -EINVAL; -- } -- -- fe = dpcm->fe; -- } - - if (!fe) - return -EINVAL; -- - fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); - -- if (mca_be_started(cl)) { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no), -+ cl->base + REG_PORT_DATA_SEL); -+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, -+ PORT_ENABLES_TX_DATA); -+ } -+ -+ if (!fe_cl->clk_provider) -+ return 0; -+ -+ if (mca_be_clk_started(cl)) { - /* - * Port is already started in the other direction. - * Make sure there isn't a conflict with another cluster -- * driving the port. -+ * driving the port clocks. - */ -- if (cl->port_driver != fe_cl->no) -+ if (cl->port_clk_driver != fe_cl->no) - return -EINVAL; - -- cl->port_started[substream->stream] = true; -+ cl->port_clk_started[substream->stream] = true; - return 0; - } - -- writel_relaxed(PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA, -- cl->base + REG_PORT_ENABLES); - writel_relaxed(FIELD_PREP(PORT_CLOCK_SEL, fe_cl->no + 1), - cl->base + REG_PORT_CLOCK_SEL); -+ - writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no), - cl->base + REG_PORT_DATA_SEL); -+ -+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS, -+ PORT_ENABLES_CLOCKS); -+ - scoped_guard(mutex, &mca->port_mutex) -- cl->port_driver = fe_cl->no; -- cl->port_started[substream->stream] = true; -+ cl->port_clk_driver = fe_cl->no; -+ cl->port_clk_started[substream->stream] = true; - - return 0; - } -@@ -773,20 +888,34 @@ static int mca_be_startup(struct snd_pcm_substream *substream, - static void mca_be_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { -+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream); - struct mca_cluster *cl = mca_dai_to_cluster(dai); -+ struct mca_cluster *fe_cl; - struct mca_data *mca = cl->host; - -- cl->port_started[substream->stream] = false; -+ if (!fe) -+ return; -+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0)); - -- if (!mca_be_started(cl)) { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0); -+ writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); -+ } -+ -+ if (!fe_cl->clk_provider) -+ return; -+ -+ cl->port_clk_started[substream->stream] = false; -+ if (!mca_be_clk_started(cl)) { - /* - * Were we the last direction to shutdown? -- * Turn off the lights. -+ * Turn off the lights (clocks). - */ -- writel_relaxed(0, cl->base + REG_PORT_ENABLES); -- writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); -+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS, 0); -+ writel_relaxed(0, cl->base + REG_PORT_CLOCK_SEL); - scoped_guard(mutex, &mca->port_mutex) -- cl->port_driver = -1; -+ cl->port_clk_driver = -1; - } - } - -@@ -1092,7 +1221,7 @@ static int apple_mca_probe(struct platform_device *pdev) - cl->host = mca; - cl->no = i; - cl->base = base + CLUSTER_STRIDE * i; -- cl->port_driver = -1; -+ cl->port_clk_driver = -1; - cl->clk_parent = of_clk_get(pdev->dev.of_node, i); - if (IS_ERR(cl->clk_parent)) { - dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n", -diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c ---- a/sound/soc/atmel/atmel-i2s.c -+++ b/sound/soc/atmel/atmel-i2s.c -@@ -540,12 +540,16 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) - return 0; - } - -+static const u64 atmel_i2s_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_I2S; -+ - static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { - .probe = atmel_i2s_dai_probe, - .prepare = atmel_i2s_prepare, - .trigger = atmel_i2s_trigger, - .hw_params = atmel_i2s_hw_params, - .set_fmt = atmel_i2s_set_dai_fmt, -+ .auto_selectable_formats = &atmel_i2s_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver atmel_i2s_dai = { -diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c ---- a/sound/soc/atmel/atmel_ssc_dai.c -+++ b/sound/soc/atmel/atmel_ssc_dai.c -@@ -825,6 +825,11 @@ static int atmel_ssc_resume(struct snd_soc_component *component) - #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S32_LE) - -+static const u64 atmel_ssc_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A; -+ - static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { - .startup = atmel_ssc_startup, - .shutdown = atmel_ssc_shutdown, -@@ -833,6 +838,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { - .hw_params = atmel_ssc_hw_params, - .set_fmt = atmel_ssc_set_dai_fmt, - .set_clkdiv = atmel_ssc_set_dai_clkdiv, -+ .auto_selectable_formats = &atmel_ssc_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver atmel_ssc_dai = { -diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c ---- a/sound/soc/atmel/atmel_wm8904.c -+++ b/sound/soc/atmel/atmel_wm8904.c -@@ -82,32 +82,33 @@ static struct snd_soc_card atmel_asoc_wm8904_card = { - - static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev) - { -- struct device_node *np = pdev->dev.of_node; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; - struct device_node *codec_np, *cpu_np; - struct snd_soc_card *card = &atmel_asoc_wm8904_card; - struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; - int ret; - - if (!np) { -- dev_err(&pdev->dev, "only device tree supported\n"); -+ dev_err(dev, "only device tree supported\n"); - return -EINVAL; - } - - ret = snd_soc_of_parse_card_name(card, "atmel,model"); - if (ret) { -- dev_err(&pdev->dev, "failed to parse card name\n"); -+ dev_err(dev, "failed to parse card name\n"); - return ret; - } - - ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing"); - if (ret) { -- dev_err(&pdev->dev, "failed to parse audio routing\n"); -+ dev_err(dev, "failed to parse audio routing\n"); - return ret; - } - - cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); - if (!cpu_np) { -- dev_err(&pdev->dev, "failed to get dai and pcm info\n"); -+ dev_err(dev, "failed to get dai and pcm info\n"); - ret = -EINVAL; - return ret; - } -@@ -117,7 +118,7 @@ static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev) - - codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); - if (!codec_np) { -- dev_err(&pdev->dev, "failed to get codec info\n"); -+ dev_err(dev, "failed to get codec info\n"); - ret = -EINVAL; - return ret; - } -diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c ---- a/sound/soc/atmel/mchp-i2s-mcc.c -+++ b/sound/soc/atmel/mchp-i2s-mcc.c -@@ -912,6 +912,13 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) - return 0; - } - -+static const u64 mchp_i2s_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_GATED | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF; -+ - static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { - .probe = mchp_i2s_mcc_dai_probe, - .set_sysclk = mchp_i2s_mcc_set_sysclk, -@@ -922,6 +929,8 @@ static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { - .hw_free = mchp_i2s_mcc_hw_free, - .set_fmt = mchp_i2s_mcc_set_dai_fmt, - .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, -+ .auto_selectable_formats = &mchp_i2s_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - #define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000 -diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c ---- a/sound/soc/atmel/mchp-pdmc.c -+++ b/sound/soc/atmel/mchp-pdmc.c -@@ -741,6 +741,8 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd, - return ret; - } - -+static const u64 mchp_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_PDM; -+ - static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { - .probe = mchp_pdmc_dai_probe, - .set_fmt = mchp_pdmc_set_fmt, -@@ -748,6 +750,8 @@ static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = { - .hw_params = mchp_pdmc_hw_params, - .trigger = mchp_pdmc_trigger, - .pcm_new = &mchp_pdmc_pcm_new, -+ .auto_selectable_formats = &mchp_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver mchp_pdmc_dai = { -diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c ---- a/sound/soc/au1x/db1200.c -+++ b/sound/soc/au1x/db1200.c -@@ -42,7 +42,7 @@ static const struct platform_device_id db1200_pids[] = { - .name = "db1550-i2s", - .driver_data = 5, - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, db1200_pids); - -diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c ---- a/sound/soc/au1x/i2sc.c -+++ b/sound/soc/au1x/i2sc.c -@@ -202,11 +202,22 @@ static int au1xi2s_startup(struct snd_pcm_substream *substream, - return 0; - } - -+static const u64 au1xi2s_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_NB_IF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF; -+ - static const struct snd_soc_dai_ops au1xi2s_dai_ops = { - .startup = au1xi2s_startup, - .trigger = au1xi2s_trigger, - .hw_params = au1xi2s_hw_params, - .set_fmt = au1xi2s_set_fmt, -+ .auto_selectable_formats = &au1xi2s_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver au1xi2s_dai_driver = { -diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c ---- a/sound/soc/au1x/psc-ac97.c -+++ b/sound/soc/au1x/psc-ac97.c -@@ -210,9 +210,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, - { - struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); - unsigned long r, ro, stat; -- int chans, t, stype = substream->stream; -- -- chans = params_channels(params); -+ int t, stype = substream->stream; - - r = ro = __raw_readl(AC97_CFG(pscdata)); - stat = __raw_readl(AC97_STAT(pscdata)); -diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c ---- a/sound/soc/au1x/psc-i2s.c -+++ b/sound/soc/au1x/psc-i2s.c -@@ -262,11 +262,22 @@ static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream, - return 0; - } - -+static const u64 au1xpsc_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_NB_IF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF; -+ - static const struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = { - .startup = au1xpsc_i2s_startup, - .trigger = au1xpsc_i2s_trigger, - .hw_params = au1xpsc_i2s_hw_params, - .set_fmt = au1xpsc_i2s_set_fmt, -+ .auto_selectable_formats = &au1xpsc_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = { -diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c ---- a/sound/soc/bcm/bcm2835-i2s.c -+++ b/sound/soc/bcm/bcm2835-i2s.c -@@ -748,6 +748,17 @@ static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) - return 0; - } - -+static const u64 bcm2835_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_B | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_NB_IF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF; -+ - static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { - .probe = bcm2835_i2s_dai_probe, - .startup = bcm2835_i2s_startup, -@@ -758,6 +769,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { - .set_fmt = bcm2835_i2s_set_dai_fmt, - .set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio, - .set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot, -+ .auto_selectable_formats = &bcm2835_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver bcm2835_i2s_dai = { -diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c ---- a/sound/soc/bcm/cygnus-ssp.c -+++ b/sound/soc/bcm/cygnus-ssp.c -@@ -1133,6 +1133,11 @@ static int cygnus_ssp_resume(struct snd_soc_component *component) - #define cygnus_ssp_resume NULL - #endif - -+static const u64 cygnus_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_B; -+ - static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = { - .startup = cygnus_ssp_startup, - .shutdown = cygnus_ssp_shutdown, -@@ -1141,6 +1146,8 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = { - .set_fmt = cygnus_ssp_set_fmt, - .set_sysclk = cygnus_ssp_set_sysclk, - .set_tdm_slot = cygnus_set_dai_tdm_slot, -+ .auto_selectable_formats = &cygnus_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = { -diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c ---- a/sound/soc/cirrus/ep93xx-i2s.c -+++ b/sound/soc/cirrus/ep93xx-i2s.c -@@ -401,6 +401,15 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component) - #define ep93xx_i2s_resume NULL - #endif - -+static const u64 ep93xx_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_NB_IF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF; -+ - static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { - .probe = ep93xx_i2s_dai_probe, - .startup = ep93xx_i2s_startup, -@@ -408,6 +417,8 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { - .hw_params = ep93xx_i2s_hw_params, - .set_sysclk = ep93xx_i2s_set_sysclk, - .set_fmt = ep93xx_i2s_set_dai_fmt, -+ .auto_selectable_formats = &ep93xx_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - #define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -238,6 +238,7 @@ config SND_SOC_ALL_CODECS - imply SND_SOC_RT715_SDCA_SDW - imply SND_SOC_RT721_SDCA_SDW - imply SND_SOC_RT722_SDCA_SDW -+ imply SND_SOC_RT766_SDCA_SDW - imply SND_SOC_RT1308_SDW - imply SND_SOC_RT1316_SDW - imply SND_SOC_RT1318 -@@ -367,6 +368,7 @@ config SND_SOC_ALL_CODECS - imply SND_SOC_WSA881X - imply SND_SOC_WSA883X - imply SND_SOC_WSA884X -+ imply SND_SOC_WSA885X - imply SND_SOC_ZL38060 - help - Normally ASoC codec drivers are only built if a machine driver which -@@ -615,8 +617,8 @@ config SND_SOC_AK4613 - depends on I2C - - config SND_SOC_AK4619 -- tristate "AKM AK4619 CODEC" -- depends on I2C -+ tristate "AKM AK4619 CODEC" -+ depends on I2C - - config SND_SOC_AK4642 - tristate "AKM AK4642 CODEC" -@@ -894,6 +896,7 @@ config SND_SOC_CS35L56_SDW - tristate "Cirrus Logic CS35L56 CODEC (SDW)" - depends on SOUNDWIRE - select REGMAP_SOUNDWIRE -+ select IRQ_DOMAIN - select SND_SOC_CS35L56 - select SND_SOC_CS35L56_SHARED - help -@@ -1206,16 +1209,16 @@ config SND_SOC_JZ4725B_CODEC - will be called snd-soc-jz4725b-codec. - - config SND_SOC_JZ4760_CODEC -- depends on MACH_INGENIC || COMPILE_TEST -- depends on OF -- select REGMAP -- tristate "Ingenic JZ4760 internal CODEC" -- help -- Enable support for the internal CODEC found in the JZ4760 SoC -- from Ingenic. -+ depends on MACH_INGENIC || COMPILE_TEST -+ depends on OF -+ select REGMAP -+ tristate "Ingenic JZ4760 internal CODEC" -+ help -+ Enable support for the internal CODEC found in the JZ4760 SoC -+ from Ingenic. - -- This driver can also be built as a module. If so, the module -- will be called snd-soc-jz4760-codec. -+ This driver can also be built as a module. If so, the module -+ will be called snd-soc-jz4760-codec. - - config SND_SOC_JZ4770_CODEC - depends on MACH_INGENIC || COMPILE_TEST -@@ -1893,7 +1896,7 @@ config SND_SOC_RT5670 - depends on I2C - - config SND_SOC_RT5677 -- tristate -+ tristate "Realtek RT5677 Codec" - depends on I2C - select REGMAP_I2C - select REGMAP_IRQ -@@ -1983,6 +1986,15 @@ config SND_SOC_RT715_SDCA_SDW - select REGMAP_SOUNDWIRE - select REGMAP_SOUNDWIRE_MBQ - -+config SND_SOC_RT766_SDCA_SDW -+ tristate "Realtek RT766 SDCA Codec - SDW" -+ depends on SOUNDWIRE -+ depends on SND_SOC_SDCA -+ select SND_SOC_SDCA_HID -+ select SND_SOC_SDCA_IRQ -+ select REGMAP_SOUNDWIRE -+ select REGMAP_SOUNDWIRE_MBQ -+ - config SND_SOC_RT9120 - tristate "Richtek RT9120 Stereo Class-D Amplifier" - depends on I2C -@@ -2302,8 +2314,8 @@ config SND_SOC_TLV320ADC3XXX - depends on I2C - depends on GPIOLIB - help -- Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 -- ADCs. -+ Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101 -+ ADCs. - - config SND_SOC_TLV320AIC23 - tristate -@@ -2776,6 +2788,16 @@ config SND_SOC_WSA884X - This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D - Smart Speaker Amplifier. - -+config SND_SOC_WSA885X -+ tristate "WSA885X Codec" -+ depends on I2C -+ select REGMAP_I2C -+ help -+ This enables support for Qualcomm WSA885X Stereo Smart Speaker -+ Amplifier. The codec driver programs the amplifier register -+ map and exposes the DAI and mixer controls used by Qualcomm -+ audio machine drivers. -+ - config SND_SOC_ZL38060 - tristate "Microsemi ZL38060 Connected Home Audio Processor" - depends on SPI_MASTER -@@ -2899,28 +2921,32 @@ config SND_SOC_TPA6130A2 - depends on I2C - - config SND_SOC_LPASS_MACRO_COMMON -- tristate -+ tristate - - config SND_SOC_LPASS_WSA_MACRO - depends on COMMON_CLK -+ depends on PM_CLK - select REGMAP_MMIO - select SND_SOC_LPASS_MACRO_COMMON - tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)" - - config SND_SOC_LPASS_VA_MACRO - depends on COMMON_CLK -+ depends on PM_CLK - select REGMAP_MMIO - select SND_SOC_LPASS_MACRO_COMMON - tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)" - - config SND_SOC_LPASS_RX_MACRO - depends on COMMON_CLK -+ depends on PM_CLK - select REGMAP_MMIO - select SND_SOC_LPASS_MACRO_COMMON - tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)" - - config SND_SOC_LPASS_TX_MACRO - depends on COMMON_CLK -+ depends on PM_CLK - select REGMAP_MMIO - select SND_SOC_LPASS_MACRO_COMMON - tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)" -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -285,6 +285,7 @@ snd-soc-rt715-y := rt715.o rt715-sdw.o - snd-soc-rt715-sdca-y := rt715-sdca.o rt715-sdca-sdw.o - snd-soc-rt721-sdca-y := rt721-sdca.o rt721-sdca-sdw.o - snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o -+snd-soc-rt766-sdca-y := rt766-sdca.o rt766-sdca-sdw.o - snd-soc-rt9120-y := rt9120.o - snd-soc-rt9123-y := rt9123.o - snd-soc-rt9123p-y := rt9123p.o -@@ -427,6 +428,7 @@ snd-soc-wm-hubs-y := wm_hubs.o - snd-soc-wsa881x-y := wsa881x.o - snd-soc-wsa883x-y := wsa883x.o - snd-soc-wsa884x-y := wsa884x.o -+snd-soc-wsa885x-y := wsa885x.o - snd-soc-zl38060-y := zl38060.o - # Amp - snd-soc-max9877-y := max9877.o -@@ -726,6 +728,7 @@ obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o - obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o - obj-$(CONFIG_SND_SOC_RT721_SDCA_SDW) += snd-soc-rt721-sdca.o - obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o -+obj-$(CONFIG_SND_SOC_RT766_SDCA_SDW) += snd-soc-rt766-sdca.o - obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o - obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o - obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o -@@ -878,6 +881,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o - obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o - obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o - obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o -+obj-$(CONFIG_SND_SOC_WSA885X) += snd-soc-wsa885x.o - obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o - - # Amp -diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c ---- a/sound/soc/codecs/ab8500-codec.c -+++ b/sound/soc/codecs/ab8500-codec.c -@@ -14,14 +14,17 @@ - * for ST-Ericsson. - */ - -+#include - #include - #include - #include - #include - #include - #include -+#include - #include - #include -+#include - #include - #include - #include -@@ -51,9 +54,32 @@ - /* Macrocell register definitions */ - #define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */ - -+/* Nr of FIR/IIR-coeff banks in ANC-block */ -+#define AB8500_NR_OF_ANC_COEFF_BANKS 2 -+ -+/* Minimum duration to keep ANC IIR Init bit high or -+low before proceeding with the configuration sequence */ -+#define AB8500_ANC_SM_DELAY 2000 -+ -+/* Sidetone states */ -+static const char * const enum_sid_state[] = { -+ "Unconfigured", -+ "Apply FIR", -+ "FIR is configured", -+}; -+enum sid_state { -+ SID_UNCONFIGURED = 0, -+ SID_APPLY_FIR = 1, -+ SID_FIR_CONFIGURED = 2, -+}; -+ - /* Private data for AB8500 device-driver */ - struct ab8500_codec_drvdata { - struct regmap *regmap; -+ struct mutex ctrl_lock; -+ -+ /* Sidetone */ -+ enum sid_state sid_status; - }; - - static inline const char *amic_micbias_str(enum amic_micbias micbias) -@@ -616,6 +642,9 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { - NULL, 0), - /* Acoustical Noise Cancellation path */ - -+ SND_SOC_DAPM_INPUT("ANC Configure Input"), -+ SND_SOC_DAPM_OUTPUT("ANC Configure Output"), -+ - SND_SOC_DAPM_MUX("ANC Source", - SND_SOC_NOPM, 0, 0, - dapm_anc_in_select), -@@ -658,6 +687,10 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = { - {"Main Supply", NULL, "Audio Power"}, - {"Main Supply", NULL, "Audio Analog Power"}, - -+ /* ANC Configure */ -+ {"ANC Configure Input", NULL, "Main Supply"}, -+ {"ANC Configure Output", NULL, "ANC Configure Input"}, -+ - /* Powerup charge pump if DA1/2 is in use */ - - {"DA_IN1", NULL, "ab8500_0p"}, -@@ -939,6 +972,75 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = { - {"MIC2 V-AMICx Enable", NULL, "V-AMIC2"}, - }; - -+/* -+ * Control-events -+ */ -+ -+static int sid_status_control_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev); -+ -+ guard(mutex)(&drvdata->ctrl_lock); -+ ucontrol->value.enumerated.item[0] = drvdata->sid_status; -+ -+ return 0; -+} -+ -+/* Write sidetone FIR-coefficients configuration sequence */ -+static int sid_status_control_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev); -+ unsigned int param, sidconf; -+ int status = 1; -+ -+ dev_dbg(component->dev, "%s: Enter\n", __func__); -+ -+ if (ucontrol->value.enumerated.item[0] != SID_APPLY_FIR) { -+ dev_err(component->dev, -+ "%s: ERROR: This control supports '%s' only!\n", -+ __func__, enum_sid_state[SID_APPLY_FIR]); -+ return -EIO; -+ } -+ -+ guard(mutex)(&drvdata->ctrl_lock); -+ -+ sidconf = snd_soc_component_read(component, AB8500_SIDFIRCONF); -+ if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { -+ if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) { -+ dev_err(component->dev, "%s: Sidetone busy while off!\n", -+ __func__); -+ status = -EPERM; -+ } else { -+ status = -EBUSY; -+ } -+ dev_dbg(component->dev, "%s: Exit\n", __func__); -+ return status; -+ } -+ -+ snd_soc_component_write(component, AB8500_SIDFIRADR, 0); -+ -+ for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) { -+ snd_soc_component_write(component, AB8500_SIDFIRCOEF1, 0); -+ snd_soc_component_write(component, AB8500_SIDFIRCOEF2, 0); -+ } -+ -+ snd_soc_component_update_bits(component, AB8500_SIDFIRADR, -+ BIT(AB8500_SIDFIRADR_FIRSIDSET), -+ BIT(AB8500_SIDFIRADR_FIRSIDSET)); -+ snd_soc_component_update_bits(component, AB8500_SIDFIRADR, -+ BIT(AB8500_SIDFIRADR_FIRSIDSET), 0); -+ -+ drvdata->sid_status = SID_FIR_CONFIGURED; -+ -+ dev_dbg(component->dev, "%s: Exit\n", __func__); -+ -+ return status; -+} -+ - /* - * Controls - Non-DAPM ASoC - */ -@@ -1222,6 +1324,9 @@ static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast, - AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT, - enum_slavemaster); - -+/* Sidetone */ -+static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state); -+ - /* ANC */ - - static struct snd_kcontrol_new ab8500_ctrls[] = { -@@ -1512,6 +1617,8 @@ static struct snd_kcontrol_new ab8500_ctrls[] = { - AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0), - - /* Sidetone */ -+ SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate, -+ sid_status_control_get, sid_status_control_put), - SOC_SINGLE_STROBE("Sidetone Reset", - AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0), - }; -@@ -2041,8 +2148,10 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np, - - static int ab8500_codec_probe(struct snd_soc_component *component) - { -+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - struct device *dev = component->dev; - struct device_node *np = dev->of_node; -+ struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); - struct ab8500_codec_platform_data codec_pdata; - int status; - -@@ -2075,6 +2184,10 @@ static int ab8500_codec_probe(struct snd_soc_component *component) - snd_soc_component_write(component, AB8500_SHORTCIRCONF, - BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); - -+ snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); -+ -+ mutex_init(&drvdata->ctrl_lock); -+ - return status; - } - -@@ -2103,6 +2216,7 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) - GFP_KERNEL); - if (!drvdata) - return -ENOMEM; -+ drvdata->sid_status = SID_UNCONFIGURED; - dev_set_drvdata(&pdev->dev, drvdata); - - drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, -diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c ---- a/sound/soc/codecs/ad1836.c -+++ b/sound/soc/codecs/ad1836.c -@@ -193,9 +193,15 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, - return 0; - } - -+static const u64 ad1836_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF; -+ - static const struct snd_soc_dai_ops ad1836_dai_ops = { - .hw_params = ad1836_hw_params, - .set_fmt = ad1836_set_dai_fmt, -+ .auto_selectable_formats = &ad1836_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - #define AD183X_DAI(_name, num_dacs, num_adcs) \ -diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c ---- a/sound/soc/codecs/ad193x.c -+++ b/sound/soc/codecs/ad193x.c -@@ -394,6 +394,14 @@ static int ad193x_startup(struct snd_pcm_substream *substream, - &constr); - } - -+static const u64 ad193x_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_NB_IF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF; -+ - static const struct snd_soc_dai_ops ad193x_dai_ops = { - .startup = ad193x_startup, - .hw_params = ad193x_hw_params, -@@ -401,6 +409,8 @@ static const struct snd_soc_dai_ops ad193x_dai_ops = { - .set_tdm_slot = ad193x_set_tdm_slot, - .set_sysclk = ad193x_set_dai_sysclk, - .set_fmt = ad193x_set_dai_fmt, -+ .auto_selectable_formats = &ad193x_selectable_formats, -+ .num_auto_selectable_formats = 1, - .no_capture_mute = 1, - }; - -diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c ---- a/sound/soc/codecs/adau7118-hw.c -+++ b/sound/soc/codecs/adau7118-hw.c -@@ -22,7 +22,7 @@ static const struct of_device_id adau7118_of_match[] = { - MODULE_DEVICE_TABLE(of, adau7118_of_match); - - static const struct platform_device_id adau7118_id[] = { -- { .name = "adau7118" }, -+ { .name = "adau7118" }, - { } - }; - MODULE_DEVICE_TABLE(platform, adau7118_id); -diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c ---- a/sound/soc/codecs/adav80x.c -+++ b/sound/soc/codecs/adav80x.c -@@ -743,11 +743,19 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, - adav80x->rate = 0; - } - -+static const u64 adav80x_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF; -+ - static const struct snd_soc_dai_ops adav80x_dai_ops = { - .set_fmt = adav80x_set_dai_fmt, - .hw_params = adav80x_hw_params, - .startup = adav80x_dai_startup, - .shutdown = adav80x_dai_shutdown, -+ .auto_selectable_formats = &adav80x_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - #define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ -diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c ---- a/sound/soc/codecs/ak4613.c -+++ b/sound/soc/codecs/ak4613.c -@@ -95,6 +95,7 @@ - * see - * AK4613_ENABLE_TDM_TEST - */ -+#include - #include - #include - #include -@@ -384,7 +385,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, - struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); - struct device *dev = component->dev; - -- mutex_lock(&priv->lock); -+ guard(mutex)(&priv->lock); - priv->cnt--; - if (priv->cnt < 0) { - dev_err(dev, "unexpected counter error\n"); -@@ -392,7 +393,6 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, - } - if (!priv->cnt) - priv->ctrl1 = 0; -- mutex_unlock(&priv->lock); - } - - static void ak4613_hw_constraints(struct ak4613_priv *priv, -@@ -507,10 +507,9 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_component *component = dai->component; - struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); - -- mutex_lock(&priv->lock); -+ guard(mutex)(&priv->lock); - ak4613_hw_constraints(priv, substream); - priv->cnt++; -- mutex_unlock(&priv->lock); - - return 0; - } -@@ -599,45 +598,47 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, - */ - ret = -EINVAL; - -- mutex_lock(&priv->lock); -- if (priv->cnt > 1) { -- /* -- * If it was already working, use current priv->ctrl1 -- */ -- ret = 0; -- } else { -- /* -- * It is not yet working, -- */ -- unsigned int channel = params_channels(params); -- u8 tdm; -+ scoped_guard(mutex, &priv->lock) { -+ if (priv->cnt > 1) { -+ /* -+ * If it was already working, use current priv->ctrl1 -+ */ -+ ret = 0; -+ } else { -+ /* -+ * It is not yet working, -+ */ -+ unsigned int channel = params_channels(params); -+ u8 tdm; - -- /* STEREO or TDM */ -- if (channel == 2) -- tdm = AK4613_CONFIG_MODE_STEREO; -- else -- tdm = AK4613_CONFIG_GET(priv, MODE); -+ /* STEREO or TDM */ -+ if (channel == 2) -+ tdm = AK4613_CONFIG_MODE_STEREO; -+ else -+ tdm = AK4613_CONFIG_GET(priv, MODE); - -- for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { -- const struct ak4613_interface *iface = ak4613_iface + i; -+ for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { -+ const struct ak4613_interface *iface = ak4613_iface + i; - -- if ((iface->fmt == fmt) && (iface->width == width)) { -- /* -- * Ctrl1 -- * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | -- * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| -- * < tdm > < iface->dif > -- */ -- priv->ctrl1 = (tdm << 6) | (iface->dif << 3); -- ret = 0; -- break; -+ if (iface->fmt == fmt && iface->width == width) { -+ /* -+ * Ctrl1 -+ * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | -+ * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| -+ * < tdm > < iface->dif > -+ */ -+ priv->ctrl1 = (tdm << 6) | (iface->dif << 3); -+ ret = 0; -+ break; -+ } - } - } - } -- mutex_unlock(&priv->lock); - -- if (ret < 0) -- goto hw_params_end; -+ if (ret < 0) { -+ dev_warn(dev, "unsupported data width/format combination\n"); -+ return ret; -+ } - - snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1); - snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2); -@@ -645,10 +646,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, - snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic); - snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc); - --hw_params_end: -- if (ret < 0) -- dev_warn(dev, "unsupported data width/format combination\n"); -- - return ret; - } - -diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c ---- a/sound/soc/codecs/arizona-jack.c -+++ b/sound/soc/codecs/arizona-jack.c -@@ -5,6 +5,7 @@ - * Copyright (C) 2012-2014 Wolfson Microelectronics plc - */ - -+#include - #include - #include - #include -@@ -707,15 +708,13 @@ static void arizona_micd_timeout_work(struct work_struct *work) - struct arizona_priv, - micd_timeout_work.work); - -- mutex_lock(&info->lock); -+ guard(mutex)(&info->lock); - - dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n"); - - info->detecting = false; - - arizona_identify_headphone(info); -- -- mutex_unlock(&info->lock); - } - - static int arizona_micd_adc_read(struct arizona_priv *info) -@@ -921,12 +920,11 @@ static void arizona_micd_detect(struct work_struct *work) - - cancel_delayed_work_sync(&info->micd_timeout_work); - -- mutex_lock(&info->lock); -+ guard(mutex)(&info->lock); - - /* If the cable was removed while measuring ignore the result */ - if (!(info->jack->status & SND_JACK_MECHANICAL)) { - dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); -- mutex_unlock(&info->lock); - return; - } - -@@ -936,7 +934,6 @@ static void arizona_micd_detect(struct work_struct *work) - arizona_button_reading(info); - - pm_runtime_mark_last_busy(arizona->dev); -- mutex_unlock(&info->lock); - } - - static irqreturn_t arizona_micdet(int irq, void *data) -@@ -948,10 +945,10 @@ static irqreturn_t arizona_micdet(int irq, void *data) - cancel_delayed_work_sync(&info->micd_detect_work); - cancel_delayed_work_sync(&info->micd_timeout_work); - -- mutex_lock(&info->lock); -- if (!info->detecting) -- debounce = 0; -- mutex_unlock(&info->lock); -+ scoped_guard(mutex, &info->lock) { -+ if (!info->detecting) -+ debounce = 0; -+ } - - if (debounce) - queue_delayed_work(system_power_efficient_wq, -@@ -969,9 +966,8 @@ static void arizona_hpdet_work(struct work_struct *work) - struct arizona_priv, - hpdet_work.work); - -- mutex_lock(&info->lock); -+ guard(mutex)(&info->lock); - arizona_start_hpdet_acc_id(info); -- mutex_unlock(&info->lock); - } - - static int arizona_hpdet_wait(struct arizona_priv *info) -@@ -1018,9 +1014,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data) - cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); - cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); - -- pm_runtime_get_sync(arizona->dev); -+ guard(pm_runtime_active_auto)(arizona->dev); - -- mutex_lock(&info->lock); -+ guard(mutex)(&info->lock); - - if (info->micd_clamp) { - mask = ARIZONA_MICD_CLAMP_STS; -@@ -1036,8 +1032,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data) - ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); - if (ret) { - dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); -- mutex_unlock(&info->lock); -- pm_runtime_put_autosuspend(arizona->dev); - return IRQ_NONE; - } - -@@ -1056,62 +1050,61 @@ static irqreturn_t arizona_jackdet(int irq, void *data) - &info->micd_timeout_work, - msecs_to_jiffies(micd_timeout)); - } -+ } else { -+ info->last_jackdet = val; - -- goto out; -- } -- info->last_jackdet = val; -+ if (info->last_jackdet == present) { -+ dev_dbg(arizona->dev, "Detected jack\n"); -+ snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); - -- if (info->last_jackdet == present) { -- dev_dbg(arizona->dev, "Detected jack\n"); -- snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); -+ info->detecting = true; -+ info->mic = false; -+ info->jack_flips = 0; - -- info->detecting = true; -- info->mic = false; -- info->jack_flips = 0; -+ if (!arizona->pdata.hpdet_acc_id) { -+ arizona_start_mic(info); -+ } else { -+ queue_delayed_work(system_power_efficient_wq, -+ &info->hpdet_work, -+ msecs_to_jiffies(HPDET_DEBOUNCE)); -+ } - -- if (!arizona->pdata.hpdet_acc_id) { -- arizona_start_mic(info); -+ if (info->micd_clamp || !arizona->pdata.jd_invert) -+ regmap_update_bits(arizona->regmap, -+ ARIZONA_JACK_DETECT_DEBOUNCE, -+ ARIZONA_MICD_CLAMP_DB | -+ ARIZONA_JD1_DB, 0); - } else { -- queue_delayed_work(system_power_efficient_wq, -- &info->hpdet_work, -- msecs_to_jiffies(HPDET_DEBOUNCE)); -- } -+ dev_dbg(arizona->dev, "Detected jack removal\n"); -+ -+ arizona_stop_mic(info); -+ -+ info->num_hpdet_res = 0; -+ for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) -+ info->hpdet_res[i] = 0; -+ info->mic = false; -+ info->hpdet_done = false; -+ info->hpdet_retried = false; -+ -+ snd_soc_jack_report(info->jack, 0, -+ ARIZONA_JACK_MASK | info->micd_button_mask); -+ -+ /* -+ * If the jack was removed during a headphone detection we -+ * need to wait for the headphone detection to finish, as -+ * it can not be aborted. We don't want to be able to start -+ * a new headphone detection from a fresh insert until this -+ * one is finished. -+ */ -+ arizona_hpdet_wait(info); - -- if (info->micd_clamp || !arizona->pdata.jd_invert) - regmap_update_bits(arizona->regmap, - ARIZONA_JACK_DETECT_DEBOUNCE, -- ARIZONA_MICD_CLAMP_DB | -- ARIZONA_JD1_DB, 0); -- } else { -- dev_dbg(arizona->dev, "Detected jack removal\n"); -- -- arizona_stop_mic(info); -- -- info->num_hpdet_res = 0; -- for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) -- info->hpdet_res[i] = 0; -- info->mic = false; -- info->hpdet_done = false; -- info->hpdet_retried = false; -- -- snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask); -- -- /* -- * If the jack was removed during a headphone detection we -- * need to wait for the headphone detection to finish, as -- * it can not be aborted. We don't want to be able to start -- * a new headphone detection from a fresh insert until this -- * one is finished. -- */ -- arizona_hpdet_wait(info); -- -- regmap_update_bits(arizona->regmap, -- ARIZONA_JACK_DETECT_DEBOUNCE, -- ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, -- ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); -+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, -+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); -+ } - } - --out: - /* Clear trig_sts to make sure DCVDD is not forced up */ - regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, - ARIZONA_MICD_CLAMP_FALL_TRIG_STS | -@@ -1119,10 +1112,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data) - ARIZONA_JD1_FALL_TRIG_STS | - ARIZONA_JD1_RISE_TRIG_STS); - -- mutex_unlock(&info->lock); -- -- pm_runtime_put_autosuspend(arizona->dev); -- - return IRQ_HANDLED; - } - -diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c ---- a/sound/soc/codecs/arizona.c -+++ b/sound/soc/codecs/arizona.c -@@ -7,6 +7,7 @@ - * Author: Mark Brown - */ - -+#include - #include - #include - #include -@@ -1158,17 +1159,16 @@ int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags) - struct arizona_priv *priv = snd_soc_component_get_drvdata(component); - int ret = 0; - -- mutex_lock(&priv->dvfs_lock); -+ guard(mutex)(&priv->dvfs_lock); - - if (!priv->dvfs_cached && !priv->dvfs_reqs) { - ret = arizona_dvfs_enable(component); - if (ret) -- goto err; -+ return ret; - } - - priv->dvfs_reqs |= flags; --err: -- mutex_unlock(&priv->dvfs_lock); -+ - return ret; - } - EXPORT_SYMBOL_GPL(arizona_dvfs_up); -@@ -1179,7 +1179,7 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags) - unsigned int old_reqs; - int ret = 0; - -- mutex_lock(&priv->dvfs_lock); -+ guard(mutex)(&priv->dvfs_lock); - - old_reqs = priv->dvfs_reqs; - priv->dvfs_reqs &= ~flags; -@@ -1187,7 +1187,6 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags) - if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs) - ret = arizona_dvfs_disable(component); - -- mutex_unlock(&priv->dvfs_lock); - return ret; - } - EXPORT_SYMBOL_GPL(arizona_dvfs_down); -@@ -1199,7 +1198,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, - struct arizona_priv *priv = snd_soc_component_get_drvdata(component); - int ret = 0; - -- mutex_lock(&priv->dvfs_lock); -+ guard(mutex)(&priv->dvfs_lock); - - switch (event) { - case SND_SOC_DAPM_POST_PMU: -@@ -1222,7 +1221,6 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, - break; - } - -- mutex_unlock(&priv->dvfs_lock); - return ret; - } - EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev); -@@ -1657,13 +1655,11 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component, - { 0x80, 0x0 }, - }; - -- mutex_lock(&arizona->dac_comp_lock); -- -- dac_comp[1].def = arizona->dac_comp_coeff; -- if (rate >= 176400) -- dac_comp[2].def = arizona->dac_comp_enabled; -- -- mutex_unlock(&arizona->dac_comp_lock); -+ scoped_guard(mutex, &arizona->dac_comp_lock) { -+ dac_comp[1].def = arizona->dac_comp_coeff; -+ if (rate >= 176400) -+ dac_comp[2].def = arizona->dac_comp_enabled; -+ } - - regmap_multi_reg_write(arizona->regmap, - dac_comp, -diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c ---- a/sound/soc/codecs/aw87390.c -+++ b/sound/soc/codecs/aw87390.c -@@ -7,6 +7,7 @@ - // Author: Weidong Wang - // - -+#include - #include - #include - #include -@@ -225,11 +226,10 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol, - struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); - int ret; - -- mutex_lock(&aw87390->lock); -+ guard(mutex)(&aw87390->lock); - ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]); - if (ret) { - dev_dbg(codec->dev, "profile index does not change\n"); -- mutex_unlock(&aw87390->lock); - return 0; - } - -@@ -238,8 +238,6 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol, - aw87390_power_on(aw87390->aw_pa); - } - -- mutex_unlock(&aw87390->lock); -- - return 1; - } - -@@ -250,7 +248,7 @@ static const struct snd_kcontrol_new aw87390_controls[] = { - - static int aw87390_request_firmware_file(struct aw87390 *aw87390) - { -- const struct firmware *cont = NULL; -+ const struct firmware *cont __free(firmware) = NULL; - int ret; - - aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED; -@@ -265,14 +263,11 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390) - - aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, - struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL); -- if (!aw87390->aw_cfg) { -- release_firmware(cont); -+ if (!aw87390->aw_cfg) - return -ENOMEM; -- } - - aw87390->aw_cfg->len = cont->size; - memcpy(aw87390->aw_cfg->data, cont->data, cont->size); -- release_firmware(cont); - - ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg); - if (ret) { -@@ -280,14 +275,12 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390) - return ret; - } - -- mutex_lock(&aw87390->lock); -+ guard(mutex)(&aw87390->lock); - - ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg); - if (ret) - dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n"); - -- mutex_unlock(&aw87390->lock); -- - return ret; - } - -diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c ---- a/sound/soc/codecs/aw88081.c -+++ b/sound/soc/codecs/aw88081.c -@@ -7,6 +7,7 @@ - // Author: Weidong Wang - // - -+#include - #include - #include - #include -@@ -763,9 +764,8 @@ static void aw88081_startup_work(struct work_struct *work) - struct aw88081 *aw88081 = - container_of(work, struct aw88081, start_work.work); - -- mutex_lock(&aw88081->lock); -+ guard(mutex)(&aw88081->lock); - aw88081_start_pa(aw88081); -- mutex_unlock(&aw88081->lock); - } - - static void aw88081_start(struct aw88081 *aw88081, bool sync_start) -@@ -942,11 +942,10 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol, - int ret; - - /* pa stop or stopping just set profile */ -- mutex_lock(&aw88081->lock); -+ guard(mutex)(&aw88081->lock); - ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]); - if (ret) { - dev_dbg(codec->dev, "profile index does not change"); -- mutex_unlock(&aw88081->lock); - return 0; - } - -@@ -955,8 +954,6 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol, - aw88081_start(aw88081, AW88081_SYNC_START); - } - -- mutex_unlock(&aw88081->lock); -- - return 1; - } - -@@ -1136,7 +1133,7 @@ static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg - - static int aw88081_request_firmware_file(struct aw88081 *aw88081) - { -- const struct firmware *cont = NULL; -+ const struct firmware *cont __free(firmware) = NULL; - struct aw_container *aw_cfg; - int ret; - -@@ -1150,26 +1147,21 @@ static int aw88081_request_firmware_file(struct aw88081 *aw88081) - AW88081_ACF_FILE, cont ? cont->size : 0); - - aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL); -- if (!aw_cfg) { -- release_firmware(cont); -+ if (!aw_cfg) - return -ENOMEM; -- } -+ - aw_cfg->len = (int)cont->size; - memcpy(aw_cfg->data, cont->data, cont->size); - - aw88081->aw_cfg = aw_cfg; - -- release_firmware(cont); -- - ret = aw88395_dev_load_acf_check(aw88081->aw_pa, aw88081->aw_cfg); - if (ret) - return ret; - -- mutex_lock(&aw88081->lock); -- ret = aw88081_dev_init(aw88081, aw88081->aw_cfg); -- mutex_unlock(&aw88081->lock); -+ guard(mutex)(&aw88081->lock); - -- return ret; -+ return aw88081_dev_init(aw88081, aw88081->aw_cfg); - } - - static int aw88081_playback_event(struct snd_soc_dapm_widget *w, -@@ -1178,7 +1170,7 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w, - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&aw88081->lock); -+ guard(mutex)(&aw88081->lock); - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - aw88081_start(aw88081, AW88081_ASYNC_START); -@@ -1189,7 +1181,6 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w, - default: - break; - } -- mutex_unlock(&aw88081->lock); - - return 0; - } -diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c ---- a/sound/soc/codecs/aw88166.c -+++ b/sound/soc/codecs/aw88166.c -@@ -7,6 +7,7 @@ - // Author: Weidong Wang - // - -+#include - #include - #include - #include -@@ -1173,9 +1174,8 @@ static void aw88166_startup_work(struct work_struct *work) - struct aw88166 *aw88166 = - container_of(work, struct aw88166, start_work.work); - -- mutex_lock(&aw88166->lock); -+ guard(mutex)(&aw88166->lock); - aw88166_start_pa(aw88166); -- mutex_unlock(&aw88166->lock); - } - - static void aw88166_start(struct aw88166 *aw88166, bool sync_start) -@@ -1413,11 +1413,10 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol, - struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); - int ret; - -- mutex_lock(&aw88166->lock); -+ guard(mutex)(&aw88166->lock); - ret = aw88166_dev_set_profile_index(aw88166->aw_pa, ucontrol->value.integer.value[0]); - if (ret) { - dev_dbg(codec->dev, "profile index does not change"); -- mutex_unlock(&aw88166->lock); - return 0; - } - -@@ -1426,8 +1425,6 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol, - aw88166_start(aw88166, AW88166_SYNC_START); - } - -- mutex_unlock(&aw88166->lock); -- - return 1; - } - -@@ -1573,7 +1570,7 @@ static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg - - static int aw88166_request_firmware_file(struct aw88166 *aw88166) - { -- const struct firmware *cont = NULL; -+ const struct firmware *cont __free(firmware) = NULL; - const char *fw_name; - int ret; - -@@ -1593,13 +1590,11 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166) - - aw88166->aw_cfg = devm_kzalloc(aw88166->aw_pa->dev, - struct_size(aw88166->aw_cfg, data, cont->size), GFP_KERNEL); -- if (!aw88166->aw_cfg) { -- release_firmware(cont); -+ if (!aw88166->aw_cfg) - return -ENOMEM; -- } -+ - aw88166->aw_cfg->len = (int)cont->size; - memcpy(aw88166->aw_cfg->data, cont->data, cont->size); -- release_firmware(cont); - - ret = aw88395_dev_load_acf_check(aw88166->aw_pa, aw88166->aw_cfg); - if (ret) { -@@ -1607,12 +1602,12 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166) - return ret; - } - -- mutex_lock(&aw88166->lock); -- /* aw device init */ -- ret = aw88166_dev_init(aw88166, aw88166->aw_cfg); -- if (ret) -- dev_err(aw88166->aw_pa->dev, "dev init failed\n"); -- mutex_unlock(&aw88166->lock); -+ scoped_guard(mutex, &aw88166->lock) { -+ /* aw device init */ -+ ret = aw88166_dev_init(aw88166, aw88166->aw_cfg); -+ if (ret) -+ dev_err(aw88166->aw_pa->dev, "dev init failed\n"); -+ } - - return ret; - } -@@ -1639,7 +1634,7 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w, - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&aw88166->lock); -+ guard(mutex)(&aw88166->lock); - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - aw88166_start(aw88166, AW88166_ASYNC_START); -@@ -1650,7 +1645,6 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w, - default: - break; - } -- mutex_unlock(&aw88166->lock); - - return 0; - } -diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c ---- a/sound/soc/codecs/aw88261.c -+++ b/sound/soc/codecs/aw88261.c -@@ -8,6 +8,7 @@ - // Author: Weidong Wang - // - -+#include - #include - #include - #include -@@ -960,11 +961,10 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol, - int ret; - - /* pa stop or stopping just set profile */ -- mutex_lock(&aw88261->lock); -+ guard(mutex)(&aw88261->lock); - ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]); - if (ret) { - dev_dbg(codec->dev, "profile index does not change"); -- mutex_unlock(&aw88261->lock); - return 0; - } - -@@ -973,8 +973,6 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol, - aw88261_start(aw88261); - } - -- mutex_unlock(&aw88261->lock); -- - return 1; - } - -@@ -1038,7 +1036,7 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w, - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&aw88261->lock); -+ guard(mutex)(&aw88261->lock); - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - aw88261_start(aw88261); -@@ -1049,7 +1047,6 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w, - default: - break; - } -- mutex_unlock(&aw88261->lock); - - return 0; - } -@@ -1152,7 +1149,7 @@ static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg - - static int aw88261_request_firmware_file(struct aw88261 *aw88261) - { -- const struct firmware *cont = NULL; -+ const struct firmware *cont __free(firmware) = NULL; - struct aw_container *aw_cfg; - const char *fw_name; - int ret; -@@ -1172,13 +1169,11 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261) - fw_name, cont ? cont->size : 0); - - aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL); -- if (!aw_cfg) { -- release_firmware(cont); -+ if (!aw_cfg) - return -ENOMEM; -- } -+ - aw_cfg->len = (int)cont->size; - memcpy(aw_cfg->data, cont->data, cont->size); -- release_firmware(cont); - - aw88261->aw_cfg = aw_cfg; - -@@ -1188,12 +1183,12 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261) - return ret; - } - -- mutex_lock(&aw88261->lock); -- /* aw device init */ -- ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); -- if (ret) -- dev_err(aw88261->aw_pa->dev, "dev init failed"); -- mutex_unlock(&aw88261->lock); -+ scoped_guard(mutex, &aw88261->lock) { -+ /* aw device init */ -+ ret = aw88261_dev_init(aw88261, aw88261->aw_cfg); -+ if (ret) -+ dev_err(aw88261->aw_pa->dev, "dev init failed"); -+ } - - return ret; - } -diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c ---- a/sound/soc/codecs/aw88395/aw88395.c -+++ b/sound/soc/codecs/aw88395/aw88395.c -@@ -8,6 +8,7 @@ - // Author: Weidong Wang - // - -+#include - #include - #include - #include -@@ -51,9 +52,8 @@ static void aw88395_startup_work(struct work_struct *work) - struct aw88395 *aw88395 = - container_of(work, struct aw88395, start_work.work); - -- mutex_lock(&aw88395->lock); -+ guard(mutex)(&aw88395->lock); - aw88395_start_pa(aw88395); -- mutex_unlock(&aw88395->lock); - } - - static void aw88395_start(struct aw88395 *aw88395, bool sync_start) -@@ -224,11 +224,10 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol, - int ret; - - /* pa stop or stopping just set profile */ -- mutex_lock(&aw88395->lock); -+ guard(mutex)(&aw88395->lock); - ret = aw88395_dev_set_profile_index(aw88395->aw_pa, ucontrol->value.integer.value[0]); - if (ret < 0) { - dev_dbg(codec->dev, "profile index does not change"); -- mutex_unlock(&aw88395->lock); - return 0; - } - -@@ -237,8 +236,6 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol, - aw88395_start(aw88395, AW88395_SYNC_START); - } - -- mutex_unlock(&aw88395->lock); -- - return 1; - } - -@@ -366,7 +363,7 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w, - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&aw88395->lock); -+ guard(mutex)(&aw88395->lock); - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - aw88395_start(aw88395, AW88395_ASYNC_START); -@@ -377,7 +374,6 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w, - default: - break; - } -- mutex_unlock(&aw88395->lock); - - return 0; - } -@@ -461,7 +457,7 @@ static void aw88395_hw_reset(struct aw88395 *aw88395) - - static int aw88395_request_firmware_file(struct aw88395 *aw88395) - { -- const struct firmware *cont = NULL; -+ const struct firmware *cont __free(firmware) = NULL; - struct aw_container *aw_cfg; - int ret; - -@@ -477,13 +473,11 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395) - AW88395_ACF_FILE, cont ? cont->size : 0); - - aw_cfg = devm_kzalloc(aw88395->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL); -- if (!aw_cfg) { -- release_firmware(cont); -+ if (!aw_cfg) - return -ENOMEM; -- } -+ - aw_cfg->len = (int)cont->size; - memcpy(aw_cfg->data, cont->data, cont->size); -- release_firmware(cont); - - aw88395->aw_cfg = aw_cfg; - -@@ -495,12 +489,12 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395) - - dev_dbg(aw88395->aw_pa->dev, "%s : bin load success\n", __func__); - -- mutex_lock(&aw88395->lock); -- /* aw device init */ -- ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg); -- if (ret < 0) -- dev_err(aw88395->aw_pa->dev, "dev init failed"); -- mutex_unlock(&aw88395->lock); -+ scoped_guard(mutex, &aw88395->lock) { -+ /* aw device init */ -+ ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg); -+ if (ret < 0) -+ dev_err(aw88395->aw_pa->dev, "dev init failed"); -+ } - - return ret; - } -diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c ---- a/sound/soc/codecs/aw88395/aw88395_device.c -+++ b/sound/soc/codecs/aw88395/aw88395_device.c -@@ -8,6 +8,7 @@ - // Author: Ben Yi - // - -+#include - #include - #include - #include -@@ -70,7 +71,7 @@ int aw_dev_dsp_write(struct aw_device *aw_dev, - u32 reg_value; - int ret; - -- mutex_lock(&aw_dev->dsp_lock); -+ guard(mutex)(&aw_dev->dsp_lock); - switch (data_type) { - case AW_DSP_16_DATA: - ret = aw_dev_dsp_write_16bit(aw_dev, dsp_addr, dsp_data); -@@ -93,7 +94,6 @@ int aw_dev_dsp_write(struct aw_device *aw_dev, - /* clear dsp chip select state*/ - if (regmap_read(aw_dev->regmap, AW88395_ID_REG, ®_value)) - dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret); -- mutex_unlock(&aw_dev->dsp_lock); - - return ret; - } -@@ -156,7 +156,7 @@ int aw_dev_dsp_read(struct aw_device *aw_dev, - u32 reg_value; - int ret; - -- mutex_lock(&aw_dev->dsp_lock); -+ guard(mutex)(&aw_dev->dsp_lock); - switch (data_type) { - case AW_DSP_16_DATA: - ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data); -@@ -179,7 +179,6 @@ int aw_dev_dsp_read(struct aw_device *aw_dev, - /* clear dsp chip select state*/ - if (regmap_read(aw_dev->regmap, AW88395_ID_REG, ®_value)) - dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret); -- mutex_unlock(&aw_dev->dsp_lock); - - return ret; - } -@@ -1110,42 +1109,36 @@ static int aw_dev_dsp_update_container(struct aw_device *aw_dev, - #ifdef AW88395_DSP_I2C_WRITES - u32 tmp_len; - -- mutex_lock(&aw_dev->dsp_lock); -+ guard(mutex)(&aw_dev->dsp_lock); - ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base); - if (ret) -- goto error_operation; -+ return ret; - - for (i = 0; i < len; i += AW88395_MAX_RAM_WRITE_BYTE_SIZE) { - tmp_len = min(len - i, AW88395_MAX_RAM_WRITE_BYTE_SIZE); - ret = regmap_raw_write(aw_dev->regmap, AW88395_DSPMDAT_REG, - &data[i], tmp_len); - if (ret) -- goto error_operation; -+ return ret; - } -- mutex_unlock(&aw_dev->dsp_lock); - #else - __be16 reg_val; - -- mutex_lock(&aw_dev->dsp_lock); -+ guard(mutex)(&aw_dev->dsp_lock); - /* i2c write */ - ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base); - if (ret) -- goto error_operation; -+ return ret; - for (i = 0; i < len; i += 2) { - reg_val = cpu_to_be16p((u16 *)(data + i)); - ret = regmap_write(aw_dev->regmap, AW88395_DSPMDAT_REG, - (u16)reg_val); - if (ret) -- goto error_operation; -+ return ret; - } -- mutex_unlock(&aw_dev->dsp_lock); - #endif - - return 0; -- --error_operation: -- mutex_unlock(&aw_dev->dsp_lock); -- return ret; - } - - static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, -@@ -1231,14 +1224,14 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) - { - unsigned int reg_val; - -- mutex_lock(&aw_dev->dsp_lock); -+ guard(mutex)(&aw_dev->dsp_lock); - /* check the odd bits of reg 0x40 */ - regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, AW88395_DSP_ODD_NUM_BIT_TEST); - regmap_read(aw_dev->regmap, AW88395_DSPMADD_REG, ®_val); - if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) { - dev_err(aw_dev->dev, "check reg 0x40 odd bit failed, read[0x%x] != write[0x%x]", - reg_val, AW88395_DSP_ODD_NUM_BIT_TEST); -- goto error; -+ return -EPERM; - } - - /* check the even bits of reg 0x40 */ -@@ -1247,7 +1240,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) - if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) { - dev_err(aw_dev->dev, "check reg 0x40 even bit failed, read[0x%x] != write[0x%x]", - reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST); -- goto error; -+ return -EPERM; - } - - /* check dsp_fw_base_addr */ -@@ -1256,7 +1249,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) - if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) { - dev_err(aw_dev->dev, "check dsp fw addr failed, read[0x%x] != write[0x%x]", - reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST); -- goto error; -+ return -EPERM; - } - - /* check dsp_cfg_base_addr */ -@@ -1265,15 +1258,10 @@ static int aw_dev_check_sram(struct aw_device *aw_dev) - if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) { - dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]", - reg_val, AW88395_DSP_ODD_NUM_BIT_TEST); -- goto error; -+ return -EPERM; - } -- mutex_unlock(&aw_dev->dsp_lock); - - return 0; -- --error: -- mutex_unlock(&aw_dev->dsp_lock); -- return -EPERM; - } - - int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool force_up_en) -diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c ---- a/sound/soc/codecs/aw88399-lib.c -+++ b/sound/soc/codecs/aw88399-lib.c -@@ -1282,7 +1282,7 @@ static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg - - int aw88399_request_firmware_file(struct aw88399 *aw88399) - { -- const struct firmware *cont = NULL; -+ const struct firmware *cont __free(firmware) = NULL; - int ret; - - aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED; -@@ -1298,13 +1298,11 @@ int aw88399_request_firmware_file(struct aw88399 *aw88399) - - aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev, - struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL); -- if (!aw88399->aw_cfg) { -- release_firmware(cont); -+ if (!aw88399->aw_cfg) - return -ENOMEM; -- } -+ - aw88399->aw_cfg->len = (int)cont->size; - memcpy(aw88399->aw_cfg->data, cont->data, cont->size); -- release_firmware(cont); - - ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg); - if (ret) { -diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c ---- a/sound/soc/codecs/aw88399.c -+++ b/sound/soc/codecs/aw88399.c -@@ -7,6 +7,7 @@ - // Author: Weidong Wang - // - -+#include - #include - #include - #include -@@ -497,11 +498,10 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol, - struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec); - int ret; - -- mutex_lock(&aw88399->lock); -+ guard(mutex)(&aw88399->lock); - ret = aw88399_dev_set_profile_index(aw88399->aw_pa, ucontrol->value.integer.value[0]); - if (ret) { - dev_dbg(codec->dev, "profile index does not change"); -- mutex_unlock(&aw88399->lock); - return 0; - } - -@@ -510,8 +510,6 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol, - aw88399_start(aw88399, AW88399_SYNC_START); - } - -- mutex_unlock(&aw88399->lock); -- - return 1; - } - -@@ -690,7 +688,7 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w, - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&aw88399->lock); -+ guard(mutex)(&aw88399->lock); - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - aw88399_start(aw88399, AW88399_ASYNC_START); -@@ -701,7 +699,6 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w, - default: - break; - } -- mutex_unlock(&aw88399->lock); - - return 0; - } -diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c ---- a/sound/soc/codecs/bt-sco.c -+++ b/sound/soc/codecs/bt-sco.c -@@ -85,13 +85,9 @@ static int bt_sco_probe(struct platform_device *pdev) - } - - static const struct platform_device_id bt_sco_driver_ids[] = { -- { -- .name = "dfbmcs320", -- }, -- { -- .name = "bt-sco", -- }, -- {}, -+ { .name = "dfbmcs320" }, -+ { .name = "bt-sco" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); - -diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c ---- a/sound/soc/codecs/cpcap.c -+++ b/sound/soc/codecs/cpcap.c -@@ -26,14 +26,6 @@ - /* Register 9 - CPCAP_REG_INTS2 --- Interrupt Sense 2 */ - #define CPCAP_BIT_PTT_S 11 /* Push To Talk */ - --/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */ --#define CPCAP_BIT_AUDIO_LOW_PWR 6 --#define CPCAP_BIT_AUD_LOWPWR_SPEED 5 --#define CPCAP_BIT_VAUDIOPRISTBY 4 --#define CPCAP_BIT_VAUDIO_MODE1 2 --#define CPCAP_BIT_VAUDIO_MODE0 1 --#define CPCAP_BIT_V_AUDIO_EN 0 -- - /* Register 513 CPCAP_REG_CC --- CODEC */ - #define CPCAP_BIT_CDC_CLK2 15 - #define CPCAP_BIT_CDC_CLK1 14 -@@ -239,7 +231,6 @@ struct cpcap_reg_info { - }; - - static const struct cpcap_reg_info cpcap_default_regs[] = { -- { CPCAP_REG_VAUDIOC, 0x003F, 0x0000 }, - { CPCAP_REG_CC, 0xFFFF, 0x0000 }, - { CPCAP_REG_CC, 0xFFFF, 0x0000 }, - { CPCAP_REG_CDI, 0xBFFF, 0x0000 }, -@@ -1265,6 +1256,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) - { -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_component *component = dai->component; - struct device *dev = component->dev; - struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); -@@ -1298,7 +1290,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream, - return err; - } - -- return 0; -+ return snd_soc_runtime_set_dai_fmt(rtd, rtd->dai_link->dai_fmt); - } - - static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, -@@ -1391,121 +1383,8 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, - return 0; - } - -- --/* -- * Configure codec for voice call if requested. -- * -- * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt() -- * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the -- * cpcap related hardware as CPU is not involved in the voice call. -- */ --static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai, -- bool voice_call) --{ -- int mask, err; -- -- /* Modem to codec VAUDIO_MODE1 */ -- mask = BIT(CPCAP_BIT_VAUDIO_MODE1); -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC, -- mask, voice_call ? mask : 0); -- if (err) -- return err; -- -- /* Clear MIC1_MUX for call */ -- mask = BIT(CPCAP_BIT_MIC1_MUX); -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, -- mask, voice_call ? 0 : mask); -- if (err) -- return err; -- -- /* Set MIC2_MUX for call */ -- mask = BIT(CPCAP_BIT_MB_ON1L) | BIT(CPCAP_BIT_MB_ON1R) | -- BIT(CPCAP_BIT_MIC2_MUX) | BIT(CPCAP_BIT_MIC2_PGA_EN); -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, -- mask, voice_call ? mask : 0); -- if (err) -- return err; -- -- /* Enable LDSP for call */ -- mask = BIT(CPCAP_BIT_A2_LDSP_L_EN) | BIT(CPCAP_BIT_A2_LDSP_R_EN); -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA, -- mask, voice_call ? mask : 0); -- if (err) -- return err; -- -- /* Enable CPCAP_BIT_PGA_CDC_EN for call */ -- mask = BIT(CPCAP_BIT_PGA_CDC_EN); -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA, -- mask, voice_call ? mask : 0); -- if (err) -- return err; -- -- /* Unmute voice for call */ -- if (dai) { -- err = snd_soc_dai_digital_mute(dai, !voice_call, -- SNDRV_PCM_STREAM_PLAYBACK); -- if (err) -- return err; -- } -- -- /* Set modem to codec mic CDC and HPF for call */ -- mask = BIT(CPCAP_BIT_MIC2_CDC_EN) | BIT(CPCAP_BIT_CDC_EN_RX) | -- BIT(CPCAP_BIT_AUDOHPF_1) | BIT(CPCAP_BIT_AUDOHPF_0) | -- BIT(CPCAP_BIT_AUDIHPF_1) | BIT(CPCAP_BIT_AUDIHPF_0); -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC, -- mask, voice_call ? mask : 0); -- if (err) -- return err; -- -- /* Enable modem to codec CDC for call*/ -- mask = BIT(CPCAP_BIT_CDC_CLK_EN); -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, -- mask, voice_call ? mask : 0); -- -- return err; --} -- --static int cpcap_voice_set_tdm_slot(struct snd_soc_dai *dai, -- unsigned int tx_mask, unsigned int rx_mask, -- int slots, int slot_width) --{ -- struct snd_soc_component *component = dai->component; -- struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); -- int err, ts_mask, mask; -- bool voice_call; -- -- /* -- * Primitive test for voice call, probably needs more checks -- * later on for 16-bit calls detected, Bluetooth headset etc. -- */ -- if (tx_mask == 0 && rx_mask == 1 && slot_width == 8) -- voice_call = true; -- else -- voice_call = false; -- -- ts_mask = 0x7 << CPCAP_BIT_MIC2_TIMESLOT0; -- ts_mask |= 0x7 << CPCAP_BIT_MIC1_RX_TIMESLOT0; -- -- mask = (tx_mask & 0x7) << CPCAP_BIT_MIC2_TIMESLOT0; -- mask |= (rx_mask & 0x7) << CPCAP_BIT_MIC1_RX_TIMESLOT0; -- -- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, -- ts_mask, mask); -- if (err) -- return err; -- -- err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, slot_width * 1000); -- if (err) -- return err; -- -- err = cpcap_voice_call(cpcap, dai, voice_call); -- if (err) -- return err; -- -- return 0; --} -- --static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute, int direction) -+static int cpcap_voice_set_mute(struct snd_soc_dai *dai, -+ int mute, int direction) - { - struct snd_soc_component *component = dai->component; - struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); -@@ -1526,7 +1405,6 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = { - .hw_params = cpcap_voice_hw_params, - .set_sysclk = cpcap_voice_set_dai_sysclk, - .set_fmt = cpcap_voice_set_dai_fmt, -- .set_tdm_slot = cpcap_voice_set_tdm_slot, - .mute_stream = cpcap_voice_set_mute, - .no_capture_mute = 1, - }; -diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c ---- a/sound/soc/codecs/cros_ec_codec.c -+++ b/sound/soc/codecs/cros_ec_codec.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -319,10 +320,18 @@ static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - (uint8_t *)&p, sizeof(p), NULL, 0); - } - -+static const u64 i2s_rx_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF; -+ - static const struct snd_soc_dai_ops i2s_rx_dai_ops = { - .hw_params = i2s_rx_hw_params, - .set_fmt = i2s_rx_set_fmt, - .set_bclk_ratio = i2s_rx_set_bclk_ratio, -+ .auto_selectable_formats = &i2s_rx_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static int i2s_rx_event(struct snd_soc_dapm_widget *w, -@@ -608,10 +617,10 @@ static void wov_copy_work(struct work_struct *w) - container_of(w, struct cros_ec_codec_priv, wov_copy_work.work); - int ret; - -- mutex_lock(&priv->wov_dma_lock); -+ guard(mutex)(&priv->wov_dma_lock); - if (!priv->wov_substream) { - dev_warn(priv->dev, "no pcm substream\n"); -- goto leave; -+ return; - } - - if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) -@@ -624,8 +633,6 @@ static void wov_copy_work(struct work_struct *w) - msecs_to_jiffies(10)); - else if (ret) - dev_err(priv->dev, "failed to read audio data\n"); --leave: -- mutex_unlock(&priv->wov_dma_lock); - } - - static int wov_enable_get(struct snd_kcontrol *kcontrol, -@@ -895,12 +902,11 @@ static int wov_pcm_hw_params(struct snd_soc_component *component, - struct cros_ec_codec_priv *priv = - snd_soc_component_get_drvdata(component); - -- mutex_lock(&priv->wov_dma_lock); -+ guard(mutex)(&priv->wov_dma_lock); - priv->wov_substream = substream; - priv->wov_rp = priv->wov_wp = 0; - priv->wov_dma_offset = 0; - priv->wov_burst_read = true; -- mutex_unlock(&priv->wov_dma_lock); - - return 0; - } -@@ -911,10 +917,10 @@ static int wov_pcm_hw_free(struct snd_soc_component *component, - struct cros_ec_codec_priv *priv = - snd_soc_component_get_drvdata(component); - -- mutex_lock(&priv->wov_dma_lock); -- wov_queue_dequeue(priv, wov_queue_size(priv)); -- priv->wov_substream = NULL; -- mutex_unlock(&priv->wov_dma_lock); -+ scoped_guard(mutex, &priv->wov_dma_lock) { -+ wov_queue_dequeue(priv, wov_queue_size(priv)); -+ priv->wov_substream = NULL; -+ } - - cancel_delayed_work_sync(&priv->wov_copy_work); - -diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c ---- a/sound/soc/codecs/cs-amp-lib.c -+++ b/sound/soc/codecs/cs-amp-lib.c -@@ -7,6 +7,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -83,10 +84,12 @@ static int cs_amp_write_cal_coeff(struct cs_dsp *dsp, - KUNIT_STATIC_STUB_REDIRECT(cs_amp_write_cal_coeff, dsp, controls, ctl_name, val); - - if (IS_REACHABLE(CONFIG_FW_CS_DSP)) { -- mutex_lock(&dsp->pwr_lock); -- cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, controls->mem_region, controls->alg_id); -- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval)); -- mutex_unlock(&dsp->pwr_lock); -+ scoped_guard(mutex, &dsp->pwr_lock) { -+ cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, -+ controls->mem_region, -+ controls->alg_id); -+ ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval)); -+ } - - if (ret < 0) { - dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret); -diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c ---- a/sound/soc/codecs/cs35l32.c -+++ b/sound/soc/codecs/cs35l32.c -@@ -538,7 +538,15 @@ static int cs35l32_runtime_resume(struct device *dev) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); - - regcache_cache_only(cs35l32->regmap, false); -- regcache_sync(cs35l32->regmap); -+ ret = regcache_sync(cs35l32->regmap); -+ if (ret) { -+ regcache_cache_only(cs35l32->regmap, true); -+ regcache_mark_dirty(cs35l32->regmap); -+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); -+ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), -+ cs35l32->supplies); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c ---- a/sound/soc/codecs/cs35l56-sdw.c -+++ b/sound/soc/codecs/cs35l56-sdw.c -@@ -231,7 +231,7 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) - * a soft reset. - */ - if (cs35l56->base.init_done) -- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); -+ cs35l56_unmask_soundwire_interrupts(cs35l56); - - out: - pm_runtime_put_autosuspend(cs35l56->base.dev); -@@ -240,47 +240,17 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral) - static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral, - struct sdw_slave_intr_status *status) - { -- struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); -- -- /* SoundWire core holds our pm_runtime when calling this function. */ -- -- dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port); -- -- if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0) -- return 0; -- - /* -- * Prevent bus manager suspending and possibly issuing a -- * bus-reset before the queued work has run. -+ * The IRQ itself was handled through the regmap_irq handler, this is -+ * just clearing up the additional Cirrus SoundWire registers that are -+ * not covered by the SoundWire framework or the IRQ handler itself. - */ -- pm_runtime_get_noresume(cs35l56->base.dev); -- -- /* -- * Mask and clear until it has been handled. -- * None of the interrupts are time-critical so use the -- * power-efficient queue. -- */ -- cs35l56_mask_soundwire_interrupts(peripheral); -- queue_work(system_power_efficient_wq, &cs35l56->sdw_irq_work); -+ sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1); -+ sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF); - - return 0; - } - --static void cs35l56_sdw_irq_work(struct work_struct *work) --{ -- struct cs35l56_private *cs35l56 = container_of(work, -- struct cs35l56_private, -- sdw_irq_work); -- -- cs35l56_irq(-1, &cs35l56->base); -- -- /* unmask interrupts */ -- if (!cs35l56->sdw_irq_no_unmask) -- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); -- -- pm_runtime_put_autosuspend(cs35l56->base.dev); --} -- - static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) - { - struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); -@@ -302,6 +272,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral) - prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT); - prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT); - prop->paging_support = true; -+ prop->use_domain_irq = true; - prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; - prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF; - -@@ -406,7 +377,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) - if (ret) - return ret; - -- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); -+ cs35l56_unmask_soundwire_interrupts(cs35l56); - - return 0; - } -@@ -418,21 +389,12 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev) - if (!cs35l56->base.init_done) - return 0; - -- cs35l56_disable_sdw_interrupts(cs35l56); -+ /* runtime_resume unmasks the interrupt */ -+ cs35l56_mask_soundwire_interrupts(cs35l56); - - return cs35l56_system_suspend(dev); - } - --static int __maybe_unused cs35l56_sdw_system_resume(struct device *dev) --{ -- struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); -- -- cs35l56->sdw_irq_no_unmask = false; -- /* runtime_resume re-enables the interrupt */ -- -- return cs35l56_system_resume(dev); --} -- - static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id) - { - struct device *dev = &peripheral->dev; -@@ -447,7 +409,6 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi - cs35l56->base.dev = dev; - cs35l56->sdw_peripheral = peripheral; - cs35l56->sdw_link_num = peripheral->bus->link_id; -- INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work); - - dev_set_drvdata(dev, cs35l56); - -@@ -457,6 +418,7 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi - regmap_config = &cs35l56_regmap_sdw; - break; - case 0x3563: -+ case 0x3562: - regmap_config = &cs35l63_regmap_sdw; - break; - default: -@@ -483,21 +445,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi - /* Start in cache-only until device is enumerated */ - regcache_cache_only(cs35l56->base.regmap, true); - -- return cs35l56_common_probe(cs35l56, -EINVAL); -+ return cs35l56_common_probe(cs35l56, peripheral->irq); - } - - static void cs35l56_sdw_remove(struct sdw_slave *peripheral) - { - struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev); - -- cs35l56_disable_sdw_interrupts(cs35l56); -+ cs35l56_mask_soundwire_interrupts(cs35l56); - - cs35l56_remove(cs35l56); - } - - static const struct dev_pm_ops cs35l56_sdw_pm = { - SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL) -- SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_sdw_system_resume) -+ SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_system_resume) - LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early) - /* NOIRQ stage not needed, SoundWire doesn't use a hard IRQ */ - }; -@@ -505,6 +467,7 @@ static const struct dev_pm_ops cs35l56_sdw_pm = { - static const struct sdw_device_id cs35l56_sdw_id[] = { - SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556), - SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557), -+ SDW_SLAVE_ENTRY(0x01FA, 0x3562, 0x3562), - SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563), - {}, - }; -diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c ---- a/sound/soc/codecs/cs35l56-shared.c -+++ b/sound/soc/codecs/cs35l56-shared.c -@@ -96,6 +96,7 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) - ARRAY_SIZE(cs35l56_patch_fw)); - break; - case 0x63: -+ case 0x62: - ret = regmap_register_patch(cs35l56_base->regmap, cs35l63_patch_fw, - ARRAY_SIZE(cs35l63_patch_fw)); - break; -@@ -389,6 +390,7 @@ static void cs35l56_set_fw_reg_table(struct cs35l56_base *cs35l56_base) - } - break; - case 0x63: -+ case 0x62: - cs35l56_base->fw_reg = &cs35l63_fw_reg; - break; - } -@@ -595,6 +597,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) - } - break; - case 0x63: -+ case 0x62: - regmap_multi_reg_write_bypassed(cs35l56_base->regmap, - cs35l63_system_reset_seq, - ARRAY_SIZE(cs35l63_system_reset_seq)); -@@ -613,26 +616,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) - } - EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, "SND_SOC_CS35L56_SHARED"); - --int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) --{ -- int ret; -- -- if (irq < 1) -- return 0; -- -- ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, -- IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, -- "cs35l56", cs35l56_base); -- if (!ret) -- cs35l56_base->irq = irq; -- else -- dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); -- -- return ret; --} --EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED"); -- --irqreturn_t cs35l56_irq(int irq, void *data) -+static irqreturn_t cs35l56_irq(int irq, void *data) - { - struct cs35l56_base *cs35l56_base = data; - unsigned int status1 = 0, status8 = 0, status20 = 0; -@@ -640,23 +624,22 @@ irqreturn_t cs35l56_irq(int irq, void *data) - unsigned int val; - int rv; - -- irqreturn_t ret = IRQ_NONE; -- - if (!cs35l56_base->init_done) - return IRQ_NONE; - -- mutex_lock(&cs35l56_base->irq_lock); -+ guard(mutex)(&cs35l56_base->irq_lock); - -- rv = pm_runtime_resume_and_get(cs35l56_base->dev); -+ PM_RUNTIME_ACQUIRE_IF_ENABLED(cs35l56_base->dev, pm); -+ rv = PM_RUNTIME_ACQUIRE_ERR(&pm); - if (rv < 0) { - dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv); -- goto err_unlock; -+ return IRQ_NONE; - } - - regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val); - if ((val & CS35L56_IRQ1_STS_MASK) == 0) { - dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n"); -- goto err; -+ return IRQ_NONE; - } - - /* Ack interrupts */ -@@ -680,7 +663,7 @@ irqreturn_t cs35l56_irq(int irq, void *data) - - /* Check to see if unmasked bits are active */ - if (!status1 && !status8 && !status20) -- goto err; -+ return IRQ_NONE; - - if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK) - dev_crit(cs35l56_base->dev, "Amp short error\n"); -@@ -688,16 +671,27 @@ irqreturn_t cs35l56_irq(int irq, void *data) - if (status8 & CS35L56_TEMP_ERR_EINT1_MASK) - dev_crit(cs35l56_base->dev, "Overtemp error\n"); - -- ret = IRQ_HANDLED; -+ return IRQ_HANDLED; -+} - --err: -- pm_runtime_put(cs35l56_base->dev); --err_unlock: -- mutex_unlock(&cs35l56_base->irq_lock); -+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) -+{ -+ int ret; -+ -+ if (irq < 1) -+ return 0; -+ -+ ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq, -+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, -+ "cs35l56", cs35l56_base); -+ if (!ret) -+ cs35l56_base->irq = irq; -+ else -+ dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret); - - return ret; - } --EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED"); -+EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED"); - - int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) - { -@@ -816,14 +810,10 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou - if (!cs35l56_base->init_done) - return 0; - -- if (!cs35l56_base->can_hibernate) -- goto out_sync; -- -- /* Must be done before releasing cache-only */ -- if (!is_soundwire) -+ /* Hibernate wake must be done before releasing cache-only */ -+ if (cs35l56_base->can_hibernate && !is_soundwire) - cs35l56_issue_wake_event(cs35l56_base); - --out_sync: - ret = cs35l56_wait_for_firmware_boot(cs35l56_base); - if (ret) { - dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret); -@@ -1470,6 +1460,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) - cs35l56_base->calibration_controls = &cs35l56_calibration_controls; - break; - case 0x35A630: -+ case 0x35A620: - cs35l56_base->calibration_controls = &cs35l63_calibration_controls; - devid = devid >> 4; - break; -diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c ---- a/sound/soc/codecs/cs35l56.c -+++ b/sound/soc/codecs/cs35l56.c -@@ -18,11 +18,9 @@ - #include - #include - #include --#include - #include - #include - #include --#include - #include - #include - #include -@@ -39,55 +37,49 @@ - #include "wm_adsp.h" - #include "cs35l56.h" - --/* -- * snd_soc_register_component() can call component_probe() on all instances -- * in a card, so deferred registration must be protected across all instances. -- */ --static DEFINE_MUTEX(cs35l56_component_register_lock); --static bool cs35l56_shutting_down; -- --void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral) -+void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56) - { - /* -+ * Mask unconditionally. -+ * - * The read of GEN_INT_STAT_1 is required as per the SoundWire spec - * for interrupt status bits to clear. - * GEN_INT_MASK_1 masks the _inputs_ to GEN_INT_STAT1. - */ -- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0); -- sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1); -- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF); -+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0); -+ sdw_read_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1); -+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF); - } - EXPORT_SYMBOL_NS_GPL(cs35l56_mask_soundwire_interrupts, "SND_SOC_CS35L56_CORE"); - --void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral) -+void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56) - { -- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ); -+ if (!cs35l56->base.irq) -+ return; -+ -+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, -+ CS35L56_SDW_INT_MASK_CODEC_IRQ); - } - EXPORT_SYMBOL_NS_GPL(cs35l56_unmask_soundwire_interrupts, "SND_SOC_CS35L56_CORE"); - --void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56) -+static void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56) - { - if (!cs35l56->sdw_peripheral) - return; - -- cs35l56->sdw_irq_no_unmask = true; -- flush_work(&cs35l56->sdw_irq_work); -- -- /* Mask interrupts and flush in case sdw_irq_work was queued again */ -- cs35l56_mask_soundwire_interrupts(cs35l56->sdw_peripheral); -- flush_work(&cs35l56->sdw_irq_work); -+ cs35l56_mask_soundwire_interrupts(cs35l56); -+ if (cs35l56->base.irq) -+ disable_irq(cs35l56->base.irq); - } --EXPORT_SYMBOL_NS_GPL(cs35l56_disable_sdw_interrupts, "SND_SOC_CS35L56_CORE"); - --void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56) -+static void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56) - { -- if (!cs35l56->sdw_peripheral) -+ if (!cs35l56->sdw_peripheral || !cs35l56->base.irq) - return; - -- cs35l56->sdw_irq_no_unmask = false; -- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral); -+ enable_irq(cs35l56->base.irq); -+ cs35l56_unmask_soundwire_interrupts(cs35l56); - } --EXPORT_SYMBOL_NS_GPL(cs35l56_enable_sdw_interrupts, "SND_SOC_CS35L56_CORE"); - - static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event); -@@ -837,11 +829,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56, bool firmware_missing - { - int ret; - -- /* -- * Disable SoundWire interrupts to prevent race with IRQ work. -- * Setting sdw_irq_no_unmask prevents the handler re-enabling -- * the SoundWire interrupt. -- */ -+ /* Disable SoundWire interrupts to prevent race with IRQ handler thread */ - cs35l56_disable_sdw_interrupts(cs35l56); - - ret = cs35l56_firmware_shutdown(&cs35l56->base); -@@ -1405,6 +1393,7 @@ static int _cs35l56_component_probe(struct snd_soc_component *component) - ARRAY_SIZE(cs35l56_controls)); - break; - case 0x63: -+ case 0x62: - ret = snd_soc_add_component_controls(component, cs35l63_controls, - ARRAY_SIZE(cs35l63_controls)); - break; -@@ -1968,11 +1957,6 @@ static void cs35l56_component_register_work(struct work_struct *work) - component_register_work); - int ret; - -- guard(mutex)(&cs35l56_component_register_lock); -- -- if (cs35l56_shutting_down) -- return; -- - PM_RUNTIME_ACQUIRE_AUTOSUSPEND(cs35l56->base.dev, pm_err); - ret = PM_RUNTIME_ACQUIRE_ERR(&pm_err); - if (ret) { -@@ -2233,37 +2217,6 @@ EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = { - }; - #endif - --static int cs35l56_reboot_notify(struct notifier_block *nb, -- unsigned long action, void *data) --{ -- guard(mutex)(&cs35l56_component_register_lock); -- cs35l56_shutting_down = true; -- -- return NOTIFY_DONE; --} -- --static struct notifier_block cs35l56_reboot_notifier = { -- .notifier_call = cs35l56_reboot_notify, --}; -- --static int __init cs35l56_modinit(void) --{ -- /* -- * Use reboot notifier to prevent race between shutdown and -- * snd_soc_register_component(). Driver shutdown() callback would -- * run too late, after device_shutdown() is already walking the -- * device list that component registration can modify. -- */ -- return register_reboot_notifier(&cs35l56_reboot_notifier); --} --module_init(cs35l56_modinit); -- --static void __exit cs35l56_modexit(void) --{ -- unregister_reboot_notifier(&cs35l56_reboot_notifier); --} --module_exit(cs35l56_modexit); -- - MODULE_DESCRIPTION("ASoC CS35L56 driver"); - MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); - MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); -diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h ---- a/sound/soc/codecs/cs35l56.h -+++ b/sound/soc/codecs/cs35l56.h -@@ -32,7 +32,6 @@ struct sdw_slave; - struct cs35l56_private { - struct wm_adsp dsp; /* must be first member */ - struct cs35l56_base base; -- struct work_struct component_register_work; - struct work_struct dsp_work; - struct workqueue_struct *dsp_wq; - struct snd_soc_component *component; -@@ -40,11 +39,8 @@ struct cs35l56_private { - struct sdw_slave *sdw_peripheral; - struct regmap *sdw_bus_regmap; - const char *fallback_fw_suffix; -- struct work_struct sdw_irq_work; -- bool sdw_irq_no_unmask; - bool soft_resetting; - bool sdw_attached; -- bool component_registered; - struct completion init_completion; - - int speaker_id; -@@ -67,10 +63,8 @@ static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_b - - extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi; - --void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral); --void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral); --void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56); --void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56); -+void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56); -+void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56); - - int cs35l56_system_suspend(struct device *dev); - int cs35l56_system_suspend_late(struct device *dev); -@@ -78,7 +72,6 @@ int cs35l56_system_suspend_no_irq(struct device *dev); - int cs35l56_system_resume_no_irq(struct device *dev); - int cs35l56_system_resume_early(struct device *dev); - int cs35l56_system_resume(struct device *dev); --irqreturn_t cs35l56_irq(int irq, void *data); - int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq); - int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq); - int cs35l56_init(struct cs35l56_private *cs35l56); -diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c ---- a/sound/soc/codecs/cs40l50-codec.c -+++ b/sound/soc/codecs/cs40l50-codec.c -@@ -288,8 +288,8 @@ static int cs40l50_codec_driver_probe(struct platform_device *pdev) - } - - static const struct platform_device_id cs40l50_id[] = { -- { "cs40l50-codec", }, -- {} -+ { .name = "cs40l50-codec" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, cs40l50_id); - -diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c ---- a/sound/soc/codecs/cs42l42-sdw.c -+++ b/sound/soc/codecs/cs42l42-sdw.c -@@ -481,10 +481,20 @@ static int cs42l42_sdw_runtime_resume(struct device *dev) - regcache_cache_only(cs42l42->regmap, false); - - /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ -- regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); -- regcache_sync(cs42l42->regmap); -+ ret = regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); -+ if (ret) -+ goto err_sync; -+ -+ ret = regcache_sync(cs42l42->regmap); -+ if (ret) -+ goto err_sync; - - return 0; -+ -+err_sync: -+ regcache_cache_only(cs42l42->regmap, true); -+ regcache_mark_dirty(cs42l42->regmap); -+ return ret; - } - - static int cs42l42_sdw_resume(struct device *dev) -diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c ---- a/sound/soc/codecs/cs42l42.c -+++ b/sound/soc/codecs/cs42l42.c -@@ -9,6 +9,7 @@ - * Author: Michael White - */ - -+#include - #include - #include - #include -@@ -565,7 +566,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ - struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); - - /* Prevent race with interrupt handler */ -- mutex_lock(&cs42l42->irq_lock); -+ guard(mutex)(&cs42l42->irq_lock); - cs42l42->jack = jk; - - if (jk) { -@@ -581,7 +582,6 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_ - break; - } - } -- mutex_unlock(&cs42l42->irq_lock); - - return 0; - } -@@ -1668,13 +1668,10 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) - unsigned int current_button_status; - unsigned int i; - -- pm_runtime_get_sync(cs42l42->dev); -- mutex_lock(&cs42l42->irq_lock); -- if (cs42l42->suspended || !cs42l42->init_done) { -- mutex_unlock(&cs42l42->irq_lock); -- pm_runtime_put_autosuspend(cs42l42->dev); -+ guard(pm_runtime_active_auto)(cs42l42->dev); -+ guard(mutex)(&cs42l42->irq_lock); -+ if (cs42l42->suspended || !cs42l42->init_done) - return IRQ_NONE; -- } - - /* Read sticky registers to clear interurpt */ - for (i = 0; i < ARRAY_SIZE(stickies); i++) { -@@ -1774,9 +1771,6 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) - } - } - -- mutex_unlock(&cs42l42->irq_lock); -- pm_runtime_put_autosuspend(cs42l42->dev); -- - return IRQ_HANDLED; - } - EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE"); -@@ -2163,23 +2157,23 @@ int cs42l42_suspend(struct device *dev) - * future interrupts. This ensures a safe disable if the interrupt - * is shared. - */ -- mutex_lock(&cs42l42->irq_lock); -- cs42l42->suspended = true; -+ scoped_guard(mutex, &cs42l42->irq_lock) { -+ cs42l42->suspended = true; - -- /* Save register values that will be overwritten by shutdown sequence */ -- for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { -- regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); -- save_regs[i] = (u8)reg; -+ /* Save register values that will be overwritten by shutdown sequence */ -+ for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) { -+ regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, ®); -+ save_regs[i] = (u8)reg; -+ } -+ -+ /* Shutdown codec */ -+ regmap_multi_reg_write(cs42l42->regmap, -+ cs42l42_shutdown_seq, -+ ARRAY_SIZE(cs42l42_shutdown_seq)); -+ -+ /* All interrupt sources are now disabled */ - } - -- /* Shutdown codec */ -- regmap_multi_reg_write(cs42l42->regmap, -- cs42l42_shutdown_seq, -- ARRAY_SIZE(cs42l42_shutdown_seq)); -- -- /* All interrupt sources are now disabled */ -- mutex_unlock(&cs42l42->irq_lock); -- - /* Wait for power-down complete */ - msleep(CS42L42_PDN_DONE_TIME_MS); - ret = regmap_read_poll_timeout(cs42l42->regmap, -@@ -2250,13 +2244,13 @@ void cs42l42_resume_restore(struct device *dev) - regcache_cache_only(cs42l42->regmap, false); - regcache_mark_dirty(cs42l42->regmap); - -- mutex_lock(&cs42l42->irq_lock); -- /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ -- regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); -- regcache_sync(cs42l42->regmap); -+ scoped_guard(mutex, &cs42l42->irq_lock) { -+ /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */ -+ regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1); -+ regcache_sync(cs42l42->regmap); - -- cs42l42->suspended = false; -- mutex_unlock(&cs42l42->irq_lock); -+ cs42l42->suspended = false; -+ } - - dev_dbg(dev, "System resumed\n"); - } -diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c ---- a/sound/soc/codecs/cs42l43-jack.c -+++ b/sound/soc/codecs/cs42l43-jack.c -@@ -6,6 +6,7 @@ - // Cirrus Logic International Semiconductor Ltd. - - #include -+#include - #include - #include - #include -@@ -67,6 +68,21 @@ static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const pro - return -EINVAL; - } - -+static void cs42l43_apply_accdet_config(struct cs42l43_codec *priv, -+ unsigned int autocontrol, -+ unsigned int pdncntl) -+{ -+ struct cs42l43 *cs42l43 = priv->core; -+ -+ regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, -+ CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | -+ CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); -+ regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, -+ CS42L43_RING_SENSE_EN_MASK, pdncntl); -+ -+ dev_dbg(priv->dev, "Successfully configured accessory detect\n"); -+} -+ - int cs42l43_set_jack(struct snd_soc_component *component, - struct snd_soc_jack *jack, void *d) - { -@@ -80,31 +96,34 @@ int cs42l43_set_jack(struct snd_soc_component *component, - - dev_dbg(priv->dev, "Configure accessory detect\n"); - -- ret = pm_runtime_resume_and_get(priv->dev); -+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); -+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm); - if (ret) { - dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret); - return ret; - } - -- mutex_lock(&priv->jack_lock); -+ guard(mutex)(&priv->jack_lock); - - priv->jack_hp = jack; - -- if (!jack) -- goto done; -+ if (!jack) { -+ cs42l43_apply_accdet_config(priv, autocontrol, pdncntl); -+ return 0; -+ } - - ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms"); - if (ret != -EINVAL) { - if (ret < 0) { - dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n", - ret); -- goto error; -+ return ret; - } - - if (ret > CS42L43_N_BUTTONS) { - ret = -EINVAL; - dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n"); -- goto error; -+ return ret; - } - - ret = device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms", -@@ -112,7 +131,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - if (ret < 0) { - dev_err(priv->dev, "Property cirrus,button-ohms malformed: %d\n", - ret); -- goto error; -+ return ret; - } - } else { - priv->buttons[0] = 70; -@@ -124,7 +143,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - ret = cs42l43_find_index(priv, "cirrus,detect-us", 50000, &priv->detect_us, - cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us)); - if (ret < 0) -- goto error; -+ return ret; - - hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT; - -@@ -134,7 +153,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms, - ARRAY_SIZE(cs42l43_accdet_ramp_ms)); - if (ret < 0) -- goto error; -+ return ret; - - hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT; - -@@ -142,7 +161,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - &priv->bias_sense_ua, cs42l43_accdet_bias_sense, - ARRAY_SIZE(cs42l43_accdet_bias_sense)); - if (ret < 0) -- goto error; -+ return ret; - - if (priv->bias_sense_ua) - autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT; -@@ -154,7 +173,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - &priv->tip_debounce_ms); - if (ret < 0 && ret != -EINVAL) { - dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret); -- goto error; -+ return ret; - } - - /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */ -@@ -170,7 +189,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - &priv->tip_fall_db_ms, cs42l43_accdet_db_ms, - ARRAY_SIZE(cs42l43_accdet_db_ms)); - if (ret < 0) -- goto error; -+ return ret; - - tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT; - -@@ -178,7 +197,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - &priv->tip_rise_db_ms, cs42l43_accdet_db_ms, - ARRAY_SIZE(cs42l43_accdet_db_ms)); - if (ret < 0) -- goto error; -+ return ret; - - tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT; - -@@ -199,7 +218,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - NULL, cs42l43_accdet_db_ms, - ARRAY_SIZE(cs42l43_accdet_db_ms)); - if (ret < 0) -- goto error; -+ return ret; - - ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT; - -@@ -207,7 +226,7 @@ int cs42l43_set_jack(struct snd_soc_component *component, - NULL, cs42l43_accdet_db_ms, - ARRAY_SIZE(cs42l43_accdet_db_ms)); - if (ret < 0) -- goto error; -+ return ret; - - ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT; - pdncntl |= CS42L43_RING_SENSE_EN_MASK; -@@ -228,23 +247,9 @@ int cs42l43_set_jack(struct snd_soc_component *component, - CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK | - CS42L43_AUTO_HSDET_TIME_MASK, hs2); - --done: -- ret = 0; -+ cs42l43_apply_accdet_config(priv, autocontrol, pdncntl); - -- regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, -- CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK | -- CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol); -- regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL, -- CS42L43_RING_SENSE_EN_MASK, pdncntl); -- -- dev_dbg(priv->dev, "Successfully configured accessory detect\n"); -- --error: -- mutex_unlock(&priv->jack_lock); -- -- pm_runtime_put_autosuspend(priv->dev); -- -- return ret; -+ return 0; - } - - static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect) -@@ -370,22 +375,22 @@ irqreturn_t cs42l43_button_press(int irq, void *data) - { - struct cs42l43_codec *priv = data; - struct cs42l43 *cs42l43 = priv->core; -- irqreturn_t iret = IRQ_NONE; - unsigned int buttons = 0; - unsigned int val = 0; - int i, ret; - -- ret = pm_runtime_resume_and_get(priv->dev); -+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); -+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm); - if (ret) { - dev_err(priv->dev, "Failed to resume for button press: %d\n", ret); -- return iret; -+ return IRQ_NONE; - } - -- mutex_lock(&priv->jack_lock); -+ guard(mutex)(&priv->jack_lock); - - if (!priv->button_detect_running) { - dev_dbg(priv->dev, "Spurious button press IRQ\n"); -- goto error; -+ return IRQ_NONE; - } - - // Wait for 2 full cycles of comb filter to ensure good reading -@@ -396,12 +401,12 @@ irqreturn_t cs42l43_button_press(int irq, void *data) - /* Bail if jack removed, the button is irrelevant and likely invalid */ - if (!cs42l43_jack_present(priv)) { - dev_dbg(priv->dev, "Button ignored due to removal\n"); -- goto error; -+ return IRQ_NONE; - } - - if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) { - dev_dbg(priv->dev, "Button ignored due to bias sense\n"); -- goto error; -+ return IRQ_NONE; - } - - val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT; -@@ -424,45 +429,32 @@ irqreturn_t cs42l43_button_press(int irq, void *data) - - snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS); - -- iret = IRQ_HANDLED; -- --error: -- mutex_unlock(&priv->jack_lock); -- -- pm_runtime_put_autosuspend(priv->dev); -- -- return iret; -+ return IRQ_HANDLED; - } - - irqreturn_t cs42l43_button_release(int irq, void *data) - { - struct cs42l43_codec *priv = data; -- irqreturn_t iret = IRQ_NONE; - int ret; - -- ret = pm_runtime_resume_and_get(priv->dev); -+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); -+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm); - if (ret) { - dev_err(priv->dev, "Failed to resume for button release: %d\n", ret); -- return iret; -+ return IRQ_NONE; - } - -- mutex_lock(&priv->jack_lock); -+ guard(mutex)(&priv->jack_lock); - -- if (priv->button_detect_running) { -- dev_dbg(priv->dev, "Button release IRQ\n"); -- -- snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); -- -- iret = IRQ_HANDLED; -- } else { -+ if (!priv->button_detect_running) { - dev_dbg(priv->dev, "Spurious button release IRQ\n"); -+ return IRQ_NONE; - } - -- mutex_unlock(&priv->jack_lock); -+ dev_dbg(priv->dev, "Button release IRQ\n"); -+ snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS); - -- pm_runtime_put_autosuspend(priv->dev); -- -- return iret; -+ return IRQ_HANDLED; - } - - void cs42l43_bias_sense_timeout(struct work_struct *work) -@@ -472,13 +464,14 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) - struct cs42l43 *cs42l43 = priv->core; - int ret; - -- ret = pm_runtime_resume_and_get(priv->dev); -+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm); -+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm); - if (ret) { - dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret); - return; - } - -- mutex_lock(&priv->jack_lock); -+ guard(mutex)(&priv->jack_lock); - - if (cs42l43_jack_present(priv) && priv->button_detect_running) { - dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n"); -@@ -491,10 +484,6 @@ void cs42l43_bias_sense_timeout(struct work_struct *work) - CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, - CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK); - } -- -- mutex_unlock(&priv->jack_lock); -- -- pm_runtime_put_autosuspend(priv->dev); - } - - static const struct reg_sequence cs42l43_3pole_patch[] = { -@@ -896,9 +885,8 @@ int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); - -- mutex_lock(&priv->jack_lock); -+ guard(mutex)(&priv->jack_lock); - ucontrol->value.integer.value[0] = priv->jack_override; -- mutex_unlock(&priv->jack_lock); - - return 0; - } -@@ -914,17 +902,13 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u - if (override >= e->items) - return -EINVAL; - -- mutex_lock(&priv->jack_lock); -+ guard(mutex)(&priv->jack_lock); - -- if (!cs42l43_jack_present(priv)) { -- mutex_unlock(&priv->jack_lock); -+ if (!cs42l43_jack_present(priv)) - return -EBUSY; -- } - -- if (override == priv->jack_override) { -- mutex_unlock(&priv->jack_lock); -+ if (override == priv->jack_override) - return 0; -- } - - priv->jack_override = override; - -@@ -984,7 +968,5 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u - cs42l43_jack_override_modes[override].report); - } - -- mutex_unlock(&priv->jack_lock); -- - return 1; - } -diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c ---- a/sound/soc/codecs/cs42l43.c -+++ b/sound/soc/codecs/cs42l43.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1207,14 +1208,12 @@ static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv) - { - struct cs42l43 *cs42l43 = priv->core; - -- mutex_lock(&priv->spk_vu_lock); -+ guard(mutex)(&priv->spk_vu_lock); - - regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, - CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK); - regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1, - CS42L43_AMP1_2_VU_MASK, 0); -- -- mutex_unlock(&priv->spk_vu_lock); - } - - static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift) -@@ -1601,7 +1600,7 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, - struct cs42l43 *cs42l43 = priv->core; - int ret; - -- mutex_lock(&cs42l43->pll_lock); -+ guard(mutex)(&cs42l43->pll_lock); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: -@@ -1626,8 +1625,6 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w, - break; - } - -- mutex_unlock(&cs42l43->pll_lock); -- - return ret; - } - -@@ -2565,13 +2562,10 @@ static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id, - { - struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component); - struct cs42l43 *cs42l43 = priv->core; -- int ret; - -- mutex_lock(&cs42l43->pll_lock); -- ret = cs42l43_set_pll(priv, src, freq); -- mutex_unlock(&cs42l43->pll_lock); -+ guard(mutex)(&cs42l43->pll_lock); - -- return ret; -+ return cs42l43_set_pll(priv, src, freq); - } - - static int cs42l43_component_probe(struct snd_soc_component *component) -@@ -2941,8 +2935,8 @@ static const struct dev_pm_ops cs42l43_codec_pm_ops = { - }; - - static const struct platform_device_id cs42l43_codec_id_table[] = { -- { "cs42l43-codec", }, -- {} -+ { .name = "cs42l43-codec" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table); - -diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c ---- a/sound/soc/codecs/cs42l84.c -+++ b/sound/soc/codecs/cs42l84.c -@@ -10,6 +10,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -281,10 +282,9 @@ static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_ - struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); - - /* Prevent race with interrupt handler */ -- mutex_lock(&cs42l84->irq_lock); -+ guard(mutex)(&cs42l84->irq_lock); - cs42l84->jack = jk; - snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET); -- mutex_unlock(&cs42l84->irq_lock); - - return 0; - } -@@ -831,7 +831,7 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) - u8 current_ring_state; - int i; - -- mutex_lock(&cs42l84->irq_lock); -+ guard(mutex)(&cs42l84->irq_lock); - /* Read sticky registers to clear interrupt */ - for (i = 0; i < ARRAY_SIZE(stickies); i++) { - regmap_read(cs42l84->regmap, irq_params_table[i].status_addr, -@@ -902,8 +902,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) - break; - } - -- mutex_unlock(&cs42l84->irq_lock); -- - return IRQ_HANDLED; - } - -@@ -919,8 +917,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data) - } - } - -- mutex_unlock(&cs42l84->irq_lock); -- - return IRQ_HANDLED; - } - -diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c ---- a/sound/soc/codecs/cs43130.c -+++ b/sound/soc/codecs/cs43130.c -@@ -6,6 +6,7 @@ - * - * Authors: Li Xu - */ -+#include - #include - #include - #include -@@ -818,26 +819,26 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, - unsigned int required_clk; - u8 dsd_speed; - -- mutex_lock(&cs43130->clk_mutex); -- if (!cs43130->clk_req) { -- /* no DAI is currently using clk */ -- if (!(CS43130_MCLK_22M % params_rate(params))) -- required_clk = CS43130_MCLK_22M; -- else -- required_clk = CS43130_MCLK_24M; -+ scoped_guard(mutex, &cs43130->clk_mutex) { -+ if (!cs43130->clk_req) { -+ /* no DAI is currently using clk */ -+ if (!(CS43130_MCLK_22M % params_rate(params))) -+ required_clk = CS43130_MCLK_22M; -+ else -+ required_clk = CS43130_MCLK_24M; - -- cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); -- if (cs43130->pll_bypass) -- cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); -- else -- cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); -+ cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); -+ if (cs43130->pll_bypass) -+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); -+ else -+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); -+ } -+ -+ cs43130->clk_req++; -+ if (cs43130->clk_req == 2) -+ cs43130_pcm_dsd_mix(true, cs43130->regmap); - } - -- cs43130->clk_req++; -- if (cs43130->clk_req == 2) -- cs43130_pcm_dsd_mix(true, cs43130->regmap); -- mutex_unlock(&cs43130->clk_mutex); -- - switch (params_rate(params)) { - case 176400: - dsd_speed = 0; -@@ -881,26 +882,26 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, - unsigned int required_clk; - u8 dsd_speed; - -- mutex_lock(&cs43130->clk_mutex); -- if (!cs43130->clk_req) { -- /* no DAI is currently using clk */ -- if (!(CS43130_MCLK_22M % params_rate(params))) -- required_clk = CS43130_MCLK_22M; -- else -- required_clk = CS43130_MCLK_24M; -+ scoped_guard(mutex, &cs43130->clk_mutex) { -+ if (!cs43130->clk_req) { -+ /* no DAI is currently using clk */ -+ if (!(CS43130_MCLK_22M % params_rate(params))) -+ required_clk = CS43130_MCLK_22M; -+ else -+ required_clk = CS43130_MCLK_24M; - -- cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); -- if (cs43130->pll_bypass) -- cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); -- else -- cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); -+ cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk); -+ if (cs43130->pll_bypass) -+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT); -+ else -+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL); -+ } -+ -+ cs43130->clk_req++; -+ if (cs43130->clk_req == 2) -+ cs43130_pcm_dsd_mix(true, cs43130->regmap); - } - -- cs43130->clk_req++; -- if (cs43130->clk_req == 2) -- cs43130_pcm_dsd_mix(true, cs43130->regmap); -- mutex_unlock(&cs43130->clk_mutex); -- - switch (dai->id) { - case CS43130_ASP_DOP_DAI: - case CS43130_XSP_DOP_DAI: -@@ -988,14 +989,13 @@ static int cs43130_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_component *component = dai->component; - struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&cs43130->clk_mutex); -+ guard(mutex)(&cs43130->clk_mutex); - cs43130->clk_req--; - if (!cs43130->clk_req) { - /* no DAI is currently using clk */ - cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO); - cs43130_pcm_dsd_mix(false, cs43130->regmap); - } -- mutex_unlock(&cs43130->clk_mutex); - - return 0; - } -diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c ---- a/sound/soc/codecs/cs4349.c -+++ b/sound/soc/codecs/cs4349.c -@@ -340,7 +340,13 @@ static int cs4349_runtime_resume(struct device *dev) - gpiod_set_value_cansleep(cs4349->reset_gpio, 1); - - regcache_cache_only(cs4349->regmap, false); -- regcache_sync(cs4349->regmap); -+ ret = regcache_sync(cs4349->regmap); -+ if (ret) { -+ regcache_cache_only(cs4349->regmap, true); -+ regcache_mark_dirty(cs4349->regmap); -+ gpiod_set_value_cansleep(cs4349->reset_gpio, 0); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c ---- a/sound/soc/codecs/cs47l15.c -+++ b/sound/soc/codecs/cs47l15.c -@@ -6,6 +6,7 @@ - // Cirrus Logic International Semiconductor Ltd. - // - -+#include - #include - #include - #include -@@ -1285,9 +1286,8 @@ static int cs47l15_component_probe(struct snd_soc_component *component) - - snd_soc_component_init_regmap(component, madera->regmap); - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = snd_soc_component_to_dapm(component); -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = snd_soc_component_to_dapm(component); - - ret = madera_init_inputs(component); - if (ret) -@@ -1317,9 +1317,8 @@ static void cs47l15_component_remove(struct snd_soc_component *component) - struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); - struct madera *madera = cs47l15->core.madera; - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = NULL; -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = NULL; - - wm_adsp2_component_remove(&cs47l15->core.adsp[0], component); - } -diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c ---- a/sound/soc/codecs/cs47l35.c -+++ b/sound/soc/codecs/cs47l35.c -@@ -6,6 +6,7 @@ - // Cirrus Logic International Semiconductor Ltd. - // - -+#include - #include - #include - #include -@@ -1566,9 +1567,8 @@ static int cs47l35_component_probe(struct snd_soc_component *component) - - snd_soc_component_init_regmap(component, madera->regmap); - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = snd_soc_component_to_dapm(component); -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = snd_soc_component_to_dapm(component); - - ret = madera_init_inputs(component); - if (ret) -@@ -1600,9 +1600,8 @@ static void cs47l35_component_remove(struct snd_soc_component *component) - struct madera *madera = cs47l35->core.madera; - int i; - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = NULL; -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = NULL; - - for (i = 0; i < CS47L35_NUM_ADSP; i++) - wm_adsp2_component_remove(&cs47l35->core.adsp[i], component); -diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c ---- a/sound/soc/codecs/cs47l85.c -+++ b/sound/soc/codecs/cs47l85.c -@@ -6,6 +6,7 @@ - // Cirrus Logic International Semiconductor Ltd. - // - -+#include - #include - #include - #include -@@ -2504,9 +2505,8 @@ static int cs47l85_component_probe(struct snd_soc_component *component) - - snd_soc_component_init_regmap(component, madera->regmap); - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = snd_soc_component_to_dapm(component); -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = snd_soc_component_to_dapm(component); - - ret = madera_init_inputs(component); - if (ret) -@@ -2537,9 +2537,8 @@ static void cs47l85_component_remove(struct snd_soc_component *component) - struct madera *madera = cs47l85->core.madera; - int i; - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = NULL; -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = NULL; - - for (i = 0; i < CS47L85_NUM_ADSP; i++) - wm_adsp2_component_remove(&cs47l85->core.adsp[i], component); -diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c ---- a/sound/soc/codecs/cs47l90.c -+++ b/sound/soc/codecs/cs47l90.c -@@ -6,6 +6,7 @@ - // Cirrus Logic International Semiconductor Ltd. - // - -+#include - #include - #include - #include -@@ -2423,9 +2424,8 @@ static int cs47l90_component_probe(struct snd_soc_component *component) - - snd_soc_component_init_regmap(component, madera->regmap); - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = snd_soc_component_to_dapm(component); -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = snd_soc_component_to_dapm(component); - - ret = madera_init_inputs(component); - if (ret) -@@ -2456,9 +2456,8 @@ static void cs47l90_component_remove(struct snd_soc_component *component) - struct madera *madera = cs47l90->core.madera; - int i; - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = NULL; -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = NULL; - - for (i = 0; i < CS47L90_NUM_ADSP; i++) - wm_adsp2_component_remove(&cs47l90->core.adsp[i], component); -diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c ---- a/sound/soc/codecs/cs47l92.c -+++ b/sound/soc/codecs/cs47l92.c -@@ -6,6 +6,7 @@ - // Cirrus Logic International Semiconductor Ltd. - // - -+#include - #include - #include - #include -@@ -1892,9 +1893,8 @@ static int cs47l92_component_probe(struct snd_soc_component *component) - - snd_soc_component_init_regmap(component, madera->regmap); - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = snd_soc_component_to_dapm(component); -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = snd_soc_component_to_dapm(component); - - ret = madera_init_inputs(component); - if (ret) -@@ -1922,9 +1922,8 @@ static void cs47l92_component_remove(struct snd_soc_component *component) - struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); - struct madera *madera = cs47l92->core.madera; - -- mutex_lock(&madera->dapm_ptr_lock); -- madera->dapm = NULL; -- mutex_unlock(&madera->dapm_ptr_lock); -+ scoped_guard(mutex, &madera->dapm_ptr_lock) -+ madera->dapm = NULL; - - wm_adsp2_component_remove(&cs47l92->core.adsp[0], component); - } -diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c ---- a/sound/soc/codecs/cs48l32.c -+++ b/sound/soc/codecs/cs48l32.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -236,15 +237,13 @@ static int cs48l32_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v - int ret; - - /* Prevent any mixer mux changes while we do this */ -- mutex_lock(&cs48l32_codec->rate_lock); -+ guard(mutex)(&cs48l32_codec->rate_lock); - - /* The write must be guarded by a number of SYSCLK cycles */ - cs48l32_spin_sysclk(cs48l32_codec); - ret = snd_soc_put_enum_double(kcontrol, ucontrol); - cs48l32_spin_sysclk(cs48l32_codec); - -- mutex_unlock(&cs48l32_codec->rate_lock); -- - return ret; - } - -@@ -2242,7 +2241,6 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai, - struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1]; - unsigned int base = dai->driver->base; - unsigned int current_asp_rate, target_asp_rate; -- bool change_rate_domain = false; - int ret; - - if (clk_id == dai_priv->clk) -@@ -2284,19 +2282,15 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai, - - if ((current_asp_rate & CS48L32_ASP_RATE_MASK) != - (target_asp_rate & CS48L32_ASP_RATE_MASK)) { -- change_rate_domain = true; -- -- mutex_lock(&cs48l32_codec->rate_lock); - /* Guard the rate change with SYSCLK cycles */ -- cs48l32_spin_sysclk(cs48l32_codec); -- } -- -- snd_soc_component_update_bits(component, base + CS48L32_ASP_CONTROL1, -- CS48L32_ASP_RATE_MASK, target_asp_rate); -- -- if (change_rate_domain) { -- cs48l32_spin_sysclk(cs48l32_codec); -- mutex_unlock(&cs48l32_codec->rate_lock); -+ scoped_guard(mutex, &cs48l32_codec->rate_lock) { -+ cs48l32_spin_sysclk(cs48l32_codec); -+ snd_soc_component_update_bits(component, -+ base + CS48L32_ASP_CONTROL1, -+ CS48L32_ASP_RATE_MASK, -+ target_asp_rate); -+ cs48l32_spin_sysclk(cs48l32_codec); -+ } - } - } - -diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c ---- a/sound/soc/codecs/cx2072x.c -+++ b/sound/soc/codecs/cx2072x.c -@@ -9,6 +9,7 @@ - // - - #include -+#include - #include - #include - #include -@@ -1408,7 +1409,7 @@ static int cx2072x_jack_status_check(void *data) - unsigned int type = 0; - int state = 0; - -- mutex_lock(&cx2072x->lock); -+ guard(mutex)(&cx2072x->lock); - - regmap_read(cx2072x->regmap, CX2072X_PORTA_PIN_SENSE, &jack); - jack = jack >> 24; -@@ -1434,8 +1435,6 @@ static int cx2072x_jack_status_check(void *data) - /* clear interrupt */ - regmap_write(cx2072x->regmap, CX2072X_UM_INTERRUPT_CRTL_E, 0x12 << 24); - -- mutex_unlock(&cx2072x->lock); -- - dev_dbg(codec->dev, "CX2072X_HSDETECT type=0x%X,Jack state = %x\n", - type, state); - return state; -diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c ---- a/sound/soc/codecs/da7213.c -+++ b/sound/soc/codecs/da7213.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -216,13 +217,10 @@ static int da7213_volsw_locked_get(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7213->ctrl_lock); -- ret = snd_soc_get_volsw(kcontrol, ucontrol); -- mutex_unlock(&da7213->ctrl_lock); -+ guard(mutex)(&da7213->ctrl_lock); - -- return ret; -+ return snd_soc_get_volsw(kcontrol, ucontrol); - } - - static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol, -@@ -230,13 +228,10 @@ static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7213->ctrl_lock); -- ret = snd_soc_put_volsw(kcontrol, ucontrol); -- mutex_unlock(&da7213->ctrl_lock); -+ guard(mutex)(&da7213->ctrl_lock); - -- return ret; -+ return snd_soc_put_volsw(kcontrol, ucontrol); - } - - static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol, -@@ -244,13 +239,10 @@ static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7213->ctrl_lock); -- ret = snd_soc_get_enum_double(kcontrol, ucontrol); -- mutex_unlock(&da7213->ctrl_lock); -+ guard(mutex)(&da7213->ctrl_lock); - -- return ret; -+ return snd_soc_get_enum_double(kcontrol, ucontrol); - } - - static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol, -@@ -258,13 +250,10 @@ static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7213->ctrl_lock); -- ret = snd_soc_put_enum_double(kcontrol, ucontrol); -- mutex_unlock(&da7213->ctrl_lock); -+ guard(mutex)(&da7213->ctrl_lock); - -- return ret; -+ return snd_soc_put_enum_double(kcontrol, ucontrol); - } - - /* ALC */ -@@ -465,9 +454,8 @@ static int da7213_tonegen_freq_get(struct snd_kcontrol *kcontrol, - __le16 val; - int ret; - -- mutex_lock(&da7213->ctrl_lock); -- ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val)); -- mutex_unlock(&da7213->ctrl_lock); -+ scoped_guard(mutex, &da7213->ctrl_lock) -+ ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val)); - - if (ret) - return ret; -@@ -499,12 +487,11 @@ static int da7213_tonegen_freq_put(struct snd_kcontrol *kcontrol, - */ - val_new = cpu_to_le16(ucontrol->value.integer.value[0]); - -- mutex_lock(&da7213->ctrl_lock); -+ guard(mutex)(&da7213->ctrl_lock); - ret = regmap_raw_read(da7213->regmap, reg, &val_old, sizeof(val_old)); - if (ret == 0 && (val_old != val_new)) - ret = regmap_raw_write(da7213->regmap, reg, - &val_new, sizeof(val_new)); -- mutex_unlock(&da7213->ctrl_lock); - - if (ret < 0) - return ret; -diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c ---- a/sound/soc/codecs/da7219.c -+++ b/sound/soc/codecs/da7219.c -@@ -8,6 +8,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -256,13 +257,10 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7219->ctrl_lock); -- ret = snd_soc_get_volsw(kcontrol, ucontrol); -- mutex_unlock(&da7219->ctrl_lock); -+ guard(mutex)(&da7219->ctrl_lock); - -- return ret; -+ return snd_soc_get_volsw(kcontrol, ucontrol); - } - - static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, -@@ -270,13 +268,10 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7219->ctrl_lock); -- ret = snd_soc_put_volsw(kcontrol, ucontrol); -- mutex_unlock(&da7219->ctrl_lock); -+ guard(mutex)(&da7219->ctrl_lock); - -- return ret; -+ return snd_soc_put_volsw(kcontrol, ucontrol); - } - - static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, -@@ -284,13 +279,10 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7219->ctrl_lock); -- ret = snd_soc_get_enum_double(kcontrol, ucontrol); -- mutex_unlock(&da7219->ctrl_lock); -+ guard(mutex)(&da7219->ctrl_lock); - -- return ret; -+ return snd_soc_get_enum_double(kcontrol, ucontrol); - } - - static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, -@@ -298,13 +290,10 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7219->ctrl_lock); -- ret = snd_soc_put_enum_double(kcontrol, ucontrol); -- mutex_unlock(&da7219->ctrl_lock); -+ guard(mutex)(&da7219->ctrl_lock); - -- return ret; -+ return snd_soc_put_enum_double(kcontrol, ucontrol); - } - - /* ALC */ -@@ -422,9 +411,8 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, - __le16 val; - int ret; - -- mutex_lock(&da7219->ctrl_lock); -- ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); -- mutex_unlock(&da7219->ctrl_lock); -+ scoped_guard(mutex, &da7219->ctrl_lock) -+ ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); - - if (ret) - return ret; -@@ -456,12 +444,11 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, - */ - val_new = cpu_to_le16(ucontrol->value.integer.value[0]); - -- mutex_lock(&da7219->ctrl_lock); -+ guard(mutex)(&da7219->ctrl_lock); - ret = regmap_raw_read(da7219->regmap, reg, &val_old, sizeof(val_old)); - if (ret == 0 && (val_old != val_new)) - ret = regmap_raw_write(da7219->regmap, reg, -- &val_new, sizeof(val_new)); -- mutex_unlock(&da7219->ctrl_lock); -+ &val_new, sizeof(val_new)); - - if (ret < 0) - return ret; -@@ -1167,15 +1154,12 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, - struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - int ret = 0; - -- mutex_lock(&da7219->pll_lock); -+ guard(mutex)(&da7219->pll_lock); - -- if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) { -- mutex_unlock(&da7219->pll_lock); -+ if (da7219->clk_src == clk_id && da7219->mclk_rate == freq) - return 0; -- } - -- if ((freq < 2000000) || (freq > 54000000)) { -- mutex_unlock(&da7219->pll_lock); -+ if (freq < 2000000 || freq > 54000000) { - dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", - freq); - return -EINVAL; -@@ -1193,7 +1177,6 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, - break; - default: - dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); -- mutex_unlock(&da7219->pll_lock); - return -EINVAL; - } - -@@ -1203,17 +1186,13 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, - freq = clk_round_rate(da7219->mclk, freq); - ret = clk_set_rate(da7219->mclk, freq); - if (ret) { -- dev_err(codec_dai->dev, "Failed to set clock rate %d\n", -- freq); -- mutex_unlock(&da7219->pll_lock); -+ dev_err(codec_dai->dev, "Failed to set clock rate %d\n", freq); - return ret; - } - } - - da7219->mclk_rate = freq; - -- mutex_unlock(&da7219->pll_lock); -- - return 0; - } - -@@ -1296,13 +1275,10 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - { - struct snd_soc_component *component = codec_dai->component; - struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&da7219->pll_lock); -- ret = da7219_set_pll(component, source, fout); -- mutex_unlock(&da7219->pll_lock); -+ guard(mutex)(&da7219->pll_lock); - -- return ret; -+ return da7219_set_pll(component, source, fout); - } - - static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) -diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c ---- a/sound/soc/codecs/es8316.c -+++ b/sound/soc/codecs/es8316.c -@@ -9,11 +9,13 @@ - - #include - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -30,6 +32,13 @@ static const unsigned int supported_mclk_lrck_ratios[] = { - 256, 384, 400, 500, 512, 768, 1024 - }; - -+static const char * const es8316_supply_names[] = { -+ "avdd", -+ "cpvdd", -+ "dvdd", -+ "pvdd", -+}; -+ - struct es8316_priv { - struct mutex lock; - struct clk *mclk; -@@ -620,15 +629,15 @@ static irqreturn_t es8316_irq(int irq, void *data) - struct snd_soc_component *comp = es8316->component; - unsigned int flags; - -- mutex_lock(&es8316->lock); -+ guard(mutex)(&es8316->lock); - - regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); - if (flags == 0x00) -- goto out; /* Powered-down / reset */ -+ return IRQ_HANDLED; /* Powered-down / reset */ - - /* Catch spurious IRQ before set_jack is called */ - if (!es8316->jack) -- goto out; -+ return IRQ_HANDLED; - - if (es8316->jd_inverted) - flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED; -@@ -681,8 +690,6 @@ static irqreturn_t es8316_irq(int irq, void *data) - } - } - --out: -- mutex_unlock(&es8316->lock); - return IRQ_HANDLED; - } - -@@ -699,18 +706,16 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component, - es8316->jd_inverted = device_property_read_bool(component->dev, - "everest,jack-detect-inverted"); - -- mutex_lock(&es8316->lock); -+ scoped_guard(mutex, &es8316->lock) { -+ es8316->jack = jack; - -- es8316->jack = jack; -+ if (es8316->jack->status & SND_JACK_MICROPHONE) -+ es8316_enable_micbias_for_mic_gnd_short_detect(component); - -- if (es8316->jack->status & SND_JACK_MICROPHONE) -- es8316_enable_micbias_for_mic_gnd_short_detect(component); -- -- snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, -- ES8316_GPIO_ENABLE_INTERRUPT, -- ES8316_GPIO_ENABLE_INTERRUPT); -- -- mutex_unlock(&es8316->lock); -+ snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, -+ ES8316_GPIO_ENABLE_INTERRUPT, -+ ES8316_GPIO_ENABLE_INTERRUPT); -+ } - - /* Enable irq and sync initial jack state */ - enable_irq(es8316->irq); -@@ -726,7 +731,7 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component) - - disable_irq(es8316->irq); - -- mutex_lock(&es8316->lock); -+ guard(mutex)(&es8316->lock); - - snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, - ES8316_GPIO_ENABLE_INTERRUPT, 0); -@@ -737,8 +742,6 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component) - } - - es8316->jack = NULL; -- -- mutex_unlock(&es8316->lock); - } - - static int es8316_set_jack(struct snd_soc_component *component, -@@ -871,6 +874,11 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client) - - i2c_set_clientdata(i2c_client, es8316); - -+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(es8316_supply_names), -+ es8316_supply_names); -+ if (ret) -+ return dev_err_probe(dev, ret, "unable to enable supplies\n"); -+ - es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); - if (IS_ERR(es8316->regmap)) - return PTR_ERR(es8316->regmap); -diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c ---- a/sound/soc/codecs/es8326.c -+++ b/sound/soc/codecs/es8326.c -@@ -6,6 +6,7 @@ - // Authors: David Yang - // - -+#include - #include - #include - #include -@@ -790,7 +791,7 @@ static void es8326_jack_button_handler(struct work_struct *work) - if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */ - return; - -- mutex_lock(&es8326->lock); -+ guard(mutex)(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HPDET_STA); - switch (iface) { - case 0x93: -@@ -845,7 +846,6 @@ static void es8326_jack_button_handler(struct work_struct *work) - } - es8326_disable_micbias(es8326->component); - } -- mutex_unlock(&es8326->lock); - } - - static void es8326_jack_detect_handler(struct work_struct *work) -@@ -855,7 +855,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) - struct snd_soc_component *comp = es8326->component; - unsigned int iface; - -- mutex_lock(&es8326->lock); -+ guard(mutex)(&es8326->lock); - iface = snd_soc_component_read(comp, ES8326_HPDET_STA); - dev_dbg(comp->dev, "gpio flag %#04x", iface); - -@@ -873,7 +873,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) - regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, - ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ? - ~es8326->jack_pol : es8326->jack_pol)); -- goto exit; -+ return; - } - - if ((iface & ES8326_HPINSERT_FLAG) == 0) { -@@ -930,7 +930,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) - queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work, - msecs_to_jiffies(400)); - es8326->hp = 1; -- goto exit; -+ return; - } - if (es8326->jack->status & SND_JACK_HEADSET) { - /* detect button */ -@@ -939,7 +939,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) - (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON)); - es8326_enable_micbias(es8326->component); - queue_delayed_work(system_dfl_wq, &es8326->button_press_work, 10); -- goto exit; -+ return; - } - if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) { - dev_dbg(comp->dev, "Headphone detected\n"); -@@ -958,8 +958,6 @@ static void es8326_jack_detect_handler(struct work_struct *work) - usleep_range(10000, 15000); - } - } --exit: -- mutex_unlock(&es8326->lock); - } - - static irqreturn_t es8326_irq(int irq, void *dev_id) -@@ -1200,13 +1198,12 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component, - { - struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&es8326->lock); -- if (es8326->jd_inverted) -- snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, -- ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); -- es8326->jack = jack; -- -- mutex_unlock(&es8326->lock); -+ scoped_guard(mutex, &es8326->lock) { -+ if (es8326->jd_inverted) -+ snd_soc_component_update_bits(component, ES8326_HPDET_TYPE, -+ ES8326_HP_DET_JACK_POL, ~es8326->jack_pol); -+ es8326->jack = jack; -+ } - es8326_irq(es8326->irq, es8326); - } - -@@ -1219,13 +1216,12 @@ static void es8326_disable_jack_detect(struct snd_soc_component *component) - return; /* Already disabled (or never enabled) */ - cancel_delayed_work_sync(&es8326->jack_detect_work); - -- mutex_lock(&es8326->lock); -+ guard(mutex)(&es8326->lock); - if (es8326->jack->status & SND_JACK_MICROPHONE) { - es8326_disable_micbias(component); - snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET); - } - es8326->jack = NULL; -- mutex_unlock(&es8326->lock); - } - - static int es8326_set_jack(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c ---- a/sound/soc/codecs/es8328.c -+++ b/sound/soc/codecs/es8328.c -@@ -405,6 +405,11 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = { - - { "Mic Bias", NULL, "Mic Bias Gen" }, - -+ { "LINPUT1", NULL, "Mic Bias" }, -+ { "RINPUT1", NULL, "Mic Bias" }, -+ { "LINPUT2", NULL, "Mic Bias" }, -+ { "RINPUT2", NULL, "Mic Bias" }, -+ - { "Left Mixer", NULL, "Left DAC" }, - { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, - { "Left Mixer", "Right Playback Switch", "Right DAC" }, -diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c ---- a/sound/soc/codecs/es8389.c -+++ b/sound/soc/codecs/es8389.c -@@ -36,6 +36,10 @@ struct es8389_private { - unsigned int sysclk; - int mastermode; - -+ u8 hpfl; -+ u8 hpfr; -+ u32 hpf_freq; -+ u32 capture_rate; - u8 mclk_src; - u8 vddd; - int version; -@@ -50,10 +54,29 @@ static const char * const es8389_core_supplies[] = { - static bool es8389_volatile_register(struct device *dev, - unsigned int reg) - { -- if ((reg <= 0xff)) -- return true; -- else -+ switch (reg) { -+ case ES8389_ADCL_VOL: -+ case ES8389_ADCR_VOL: -+ case ES8389_MIC1_GAIN: -+ case ES8389_MIC2_GAIN: -+ case ES8389_DACL_VOL: -+ case ES8389_DACR_VOL: -+ case ES8389_ALC_ON: -+ case ES8389_ALC_CTL: -+ case ES8389_ALC_TARGET: -+ case ES8389_ALC_GAIN: -+ case ES8389_ADC_MUTE: -+ case ES8389_OSR_VOL: -+ case ES8389_DAC_INV: -+ case ES8389_MIX_VOL: -+ case ES8389_DAC_MIX: -+ case ES8389_ADC_RESET: -+ case ES8389_ADC_MODE: -+ case ES8389_DMIC_EN: - return false; -+ default: -+ return true; -+ } - } - - static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0); -@@ -63,6 +86,92 @@ static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -9500, 100, 0); - static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -3200, 200, 0); - static const DECLARE_TLV_DB_SCALE(alc_max_level, -3200, 200, 0); - -+static const u32 hpf_table[10][10] = { -+ {1020, 754, 624, 559, 527, 511, 502, 498, 497, 496}, -+ {754, 495, 368, 306, 274, 259, 251, 247, 246, 244}, -+ {624, 368, 243, 182, 151, 136, 128, 124, 123, 121}, -+ {559, 306, 182, 120, 90, 75, 68, 63, 62, 60}, -+ {527, 274, 151, 90, 60, 45, 38, 33, 32, 31}, -+ {511, 259, 136, 75, 45, 30, 23, 19, 18, 17}, -+ {502, 251, 128, 68, 38, 23, 16, 13, 11, 11}, -+ {498, 247, 124, 63, 33, 19, 13, 10, 8, 8}, -+ {497, 246, 123, 62, 32, 18, 11, 8, 8, 0}, -+ {496, 244, 121, 60, 31, 17, 11, 8, 0, 0} -+}; -+ -+static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2, u32 *out) -+{ -+ int best_row = -1, best_col = -1; -+ u32 min_diff = U32_MAX; -+ u32 f, diff; -+ int i, j; -+ -+ if (target_hz > 1020) -+ return false; -+ -+ for (i = 0; i < 10; i++) { -+ for (j = i; j < 10; j++) { -+ f = hpf_table[i][j]; -+ -+ diff = (target_hz > f) ? (target_hz - f) : (f - target_hz); -+ if (diff < min_diff) { -+ min_diff = diff; -+ best_row = i; -+ best_col = j; -+ *out = f; -+ } -+ } -+ } -+ -+ *hpf1 = best_col + ES8389_HPF_OFFSET; -+ *hpf2 = best_row + ES8389_HPF_OFFSET; -+ -+ return true; -+} -+ -+static int es8389_hpf_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); -+ -+ ucontrol->value.integer.value[0] = es8389->hpf_freq; -+ return 0; -+} -+ -+static int es8389_hpf_set(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); -+ u32 freq; -+ bool hpf; -+ -+ if (es8389->hpf_freq == ucontrol->value.integer.value[0]) -+ return 0; -+ -+ if (es8389->capture_rate) { -+ freq = (ucontrol->value.integer.value[0] * 48000) / es8389->capture_rate; -+ -+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq); -+ if (!hpf) -+ return -EBUSY; -+ -+ if (es8389->hpf_freq != ucontrol->value.integer.value[0]) -+ dev_dbg(component->dev, "At the %u Hz sampling rate, %ld Hz could not be obtained." -+ "the frequency has been set to the closest value, %u Hz\n", -+ es8389->capture_rate, ucontrol->value.integer.value[0], es8389->hpf_freq); -+ -+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl); -+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr); -+ } else { -+ es8389->hpf_freq = ucontrol->value.integer.value[0]; -+ dev_dbg(component->dev, "PCM_STREAM_CAPTURE is not active.retain the input frequency\n"); -+ } -+ -+ return 1; -+} -+ - static int es8389_dmic_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) - { -@@ -143,6 +252,16 @@ static const struct soc_enum alc_ramprate = - static const struct soc_enum alc_winsize = - SOC_ENUM_SINGLE(ES8389_ALC_CTL, 0, 16, winsize); - -+static const char *const es8389_adcl_mux_txt[] = { -+ "Normal", -+ "ADC2 channel to ADC1 channel", -+}; -+ -+static const char *const es8389_adcr_mux_txt[] = { -+ "Normal", -+ "ADC1 channel to ADC2 channel", -+}; -+ - static const char *const es8389_outl_mux_txt[] = { - "Normal", - "DAC2 channel to DAC1 channel", -@@ -170,6 +289,20 @@ static const unsigned int es8389_pga_values[] = { - 1, 5, 6 - }; - -+static const struct soc_enum es8389_adcl_mux_enum = -+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 5, -+ ARRAY_SIZE(es8389_adcl_mux_txt), es8389_adcl_mux_txt); -+ -+static const struct snd_kcontrol_new es8389_adcl_mux_controls = -+ SOC_DAPM_ENUM("INPUTL MUX", es8389_adcl_mux_enum); -+ -+static const struct soc_enum es8389_adcr_mux_enum = -+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 4, -+ ARRAY_SIZE(es8389_adcr_mux_txt), es8389_adcr_mux_txt); -+ -+static const struct snd_kcontrol_new es8389_adcr_mux_controls = -+ SOC_DAPM_ENUM("INPUTR MUX", es8389_adcr_mux_enum); -+ - static const struct soc_enum es8389_outl_mux_enum = - SOC_ENUM_SINGLE(ES8389_DAC_MIX, 5, - ARRAY_SIZE(es8389_outl_mux_txt), es8389_outl_mux_txt); -@@ -240,6 +373,8 @@ static const struct snd_kcontrol_new es8389_snd_controls[] = { - SOC_DOUBLE("ADC OSR Volume ON Switch", ES8389_ADC_MUTE, 6, 7, 1, 0), - SOC_SINGLE_TLV("ADC OSR Volume", ES8389_OSR_VOL, 0, 0xFF, 0, adc_vol_tlv), - SOC_DOUBLE("ADC OUTPUT Invert Switch", ES8389_ADC_HPF2, 5, 6, 1, 0), -+ SOC_SINGLE_EXT("ADC HPF Freq Select", SND_SOC_NOPM, 0, 1020, 0, -+ es8389_hpf_get, es8389_hpf_set), - - SOC_SINGLE_TLV("DACL Playback Volume", ES8389_DACL_VOL, 0, 0xFF, 0, dac_vol_tlv), - SOC_SINGLE_TLV("DACR Playback Volume", ES8389_DACR_VOL, 0, 0xFF, 0, dac_vol_tlv), -@@ -298,6 +433,8 @@ static const struct snd_soc_dapm_widget es8389_dapm_widgets[] = { - &es8389_adc_mixer_controls[0], - ARRAY_SIZE(es8389_adc_mixer_controls)), - SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8389_dmic_mux_controls), -+ SND_SOC_DAPM_MUX("INPUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_adcl_mux_controls), -+ SND_SOC_DAPM_MUX("INPUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_adcr_mux_controls), - - SND_SOC_DAPM_MUX("OUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_outl_mux_controls), - SND_SOC_DAPM_MUX("OUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_outr_mux_controls), -@@ -311,10 +448,15 @@ static const struct snd_soc_dapm_route es8389_dapm_routes[] = { - {"ADCL", NULL, "PGAL"}, - {"ADCR", NULL, "PGAR"}, - -+ {"INPUTL MUX", "Normal", "ADCL"}, -+ {"INPUTL MUX", "ADC2 channel to ADC1 channel", "ADCR"}, -+ {"INPUTR MUX", "Normal", "ADCR"}, -+ {"INPUTR MUX", "ADC1 channel to ADC2 channel", "ADCL"}, -+ - {"ADC Mixer", "DACL ADCL Mixer", "DACL"}, - {"ADC Mixer", "DACR ADCR Mixer", "DACR"}, -- {"ADC Mixer", NULL, "ADCL"}, -- {"ADC Mixer", NULL, "ADCR"}, -+ {"ADC Mixer", NULL, "INPUTL MUX"}, -+ {"ADC Mixer", NULL, "INPUTR MUX"}, - - {"ADC MUX", "AMIC", "ADC Mixer"}, - {"ADC MUX", "DMIC", "DMIC"}, -@@ -415,52 +557,54 @@ static const struct _coeff_div coeff_div[] = { - {36, 576000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {48, 768000, 16000, 0x02, 0x57, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {50, 800000, 16000, 0x00, 0x7E, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -- {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -- {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {96, 1536000, 16000, 0x02, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {128, 2048000, 16000, 0x00, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {144, 2304000, 16000, 0x00, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {150, 2400000, 16000, 0x02, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {192, 3072000, 16000, 0x02, 0x65, 0x25, 0xE0, 0x00, 0xE1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -- {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {300, 4800000, 16000, 0x02, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {384, 6144000, 16000, 0x02, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -- {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {750, 12000000, 16000, 0x0E, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -- {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -- {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1152, 18432000, 16000, 0x08, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1200, 19200000, 16000, 0x0B, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1500, 24000000, 16000, 0x0E, 0x26, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -- {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, -+ {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {1625, 26000000, 16000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2}, - {800, 19200000, 24000, 0x07, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x1A, 0x49, 0x14, 2, 2}, - {375, 12000000, 32000, 0x0E, 0x2E, 0x05, 0xC8, 0x00, 0xC2, 0x80, 0x40, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 0}, -- {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2}, -- {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2}, -+ {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {64, 2822400, 44100, 0x00, 0x51, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {48, 2304000, 48000, 0x02, 0x55, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {50, 2400000, 48000, 0x00, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {64, 3072000, 48000, 0x00, 0x51, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {125, 6000000, 48000, 0x04, 0x6E, 0x05, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {250, 12000000, 48000, 0x04, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -- {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, -+ {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {800, 38400000, 48000, 0x18, 0x45, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2}, - {128, 11289600, 88200, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x32, 0x89, 0x25, 2, 2}, -- {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, -+ {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, - {96, 9216000, 96000, 0x02, 0x43, 0x00, 0xC0, 0x10, 0xC0, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, - {256, 24576000, 96000, 0x00, 0x40, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2}, - {128, 24576000, 192000, 0x00, 0x50, 0x00, 0xC0, 0x18, 0xC1, 0x81, 0xC0, 0x00, 0x8F, 0x7F, 0xBF, 0xC0, 0x3F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 2, 2}, -+ {64, 12288000, 192000, 0x00, 0x41, 0x00, 0xC0, 0x18, 0xC1, 0x80, 0x00, 0x00, 0x8F, 0x7F, 0xEF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 1, 0}, - }; - - static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate) -@@ -564,6 +708,8 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, - int coeff, ret; - u8 dmic_enable, state = 0; - unsigned int regv; -+ u32 freq; -+ bool hpf; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: -@@ -590,7 +736,7 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, - - if (es8389->mclk_src == ES8389_SCLK_PIN) { - regmap_update_bits(es8389->regmap, ES8389_MASTER_CLK, -- ES8389_MCLK_SOURCE, es8389->mclk_src); -+ ES8389_MCLK_MASK, ES8389_MCLK_FROM_SCLK); - es8389->sysclk = params_channels(params) * params_width(params) * params_rate(params); - } - -@@ -641,6 +787,28 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream, - dev_warn(component->dev, "Clock coefficients do not match"); - } - -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { -+ es8389->capture_rate = params_rate(params); -+ freq = (es8389->hpf_freq * 48000) / params_rate(params); -+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq); -+ if (!hpf) { -+ dev_err(component->dev, "The HPF frequency is invalid\n"); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static int es8389_pcm_hw_free(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ es8389->capture_rate = 0; -+ - return 0; - } - -@@ -721,8 +889,8 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction) - regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE, - 0x03, 0x00); - } else { -- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x0a); -- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x0a); -+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl); -+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr); - regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE, - 0x03, 0x00); - } -@@ -738,6 +906,7 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction) - - static const struct snd_soc_dai_ops es8389_ops = { - .hw_params = es8389_pcm_hw_params, -+ .hw_free = es8389_pcm_hw_free, - .set_fmt = es8389_set_dai_fmt, - .set_sysclk = es8389_set_dai_sysclk, - .set_tdm_slot = es8389_set_tdm_slot, -@@ -771,7 +940,7 @@ static void es8389_init(struct snd_soc_component *component) - - regmap_read(es8389->regmap, ES8389_MAX_REGISTER, ®); - es8389->version = reg; -- regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x00); -+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x56); - regmap_write(es8389->regmap, ES8389_RESET, 0x7E); - regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x38); - regmap_write(es8389->regmap, ES8389_ADC_HPF1, 0x64); -@@ -823,7 +992,7 @@ static void es8389_init(struct snd_soc_component *component) - regmap_write(es8389->regmap, ES8389_SCLK_DIV, 0x04); - regmap_write(es8389->regmap, ES8389_LRCK_DIV1, 0x01); - regmap_write(es8389->regmap, ES8389_LRCK_DIV2, 0x00); -- regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x00); -+ regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x10); - regmap_write(es8389->regmap, ES8389_ADC_OSR, 0x1F); - regmap_write(es8389->regmap, ES8389_ADC_DSP, 0x7F); - regmap_write(es8389->regmap, ES8389_ADC_MUTE, 0xC0); -@@ -861,13 +1030,13 @@ static int es8389_resume(struct snd_soc_component *component) - regcache_cache_only(es8389->regmap, false); - regcache_cache_bypass(es8389->regmap, true); - regmap_read(es8389->regmap, ES8389_RESET, ®v); -- regcache_cache_bypass(es8389->regmap, false); - - if (regv == 0xff) - es8389_init(component); - else - es8389_set_bias_level(component, SND_SOC_BIAS_ON); - -+ regcache_cache_bypass(es8389->regmap, false); - regcache_sync(es8389->regmap); - - return 0; -@@ -913,6 +1082,7 @@ static int es8389_probe(struct snd_soc_component *component) - return ret; - } - -+ es8389->hpf_freq = ES8389_HPF_DEFAULT; - es8389_init(component); - es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY); - -diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h ---- a/sound/soc/codecs/es8389.h -+++ b/sound/soc/codecs/es8389.h -@@ -106,6 +106,9 @@ - #define ES8389_MIC_SEL_MASK (7 << 4) - #define ES8389_MIC_DEFAULT (1 << 4) - -+#define ES8389_HPF_DEFAULT 16 -+#define ES8389_HPF_OFFSET 4 -+ - #define ES8389_MASTER_MODE_EN (1 << 0) - - #define ES8389_TDM_OFF (0 << 0) -@@ -116,9 +119,11 @@ - #define ES8389_TDM_SLOT (0x70 << 0) - #define ES8389_TDM_SHIFT 4 - --#define ES8389_MCLK_SOURCE (1 << 6) --#define ES8389_MCLK_PIN (1 << 6) --#define ES8389_SCLK_PIN (0 << 6) -+#define ES8389_MCLK_MASK (3 << 6) -+#define ES8389_MCLK_FROM_SCLK (1 << 6) -+#define ES8389_MCLK_SOURCE ES8389_MCLK_PIN -+#define ES8389_MCLK_PIN 0 -+#define ES8389_SCLK_PIN 1 - - /* ES8389_FMT */ - #define ES8389_S24_LE (0 << 5) -diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c ---- a/sound/soc/codecs/es9356.c -+++ b/sound/soc/codecs/es9356.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -19,8 +20,6 @@ - #include - #include - #include --#include --#include - #include - #include - #include -@@ -500,16 +499,19 @@ static int es9356_power_state(struct snd_soc_dai *dai, unsigned char ps, unsigne - } - - /* power state changes are not independent across functions */ -- mutex_lock(&es9356->pde_lock); -- ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps0:ps3); -- if (ret) { -- regmap_write(es9356->regmap, -- SDW_SDCA_CTL(func, pde_entity, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps?ps3:ps0); -- es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps3:ps0); -- } else -- dev_dbg(component->dev, "%s PDE is already %d\n", __func__, ps?ps0:ps3); -- -- mutex_unlock(&es9356->pde_lock); -+ scoped_guard(mutex, &es9356->pde_lock) { -+ ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps0 : ps3); -+ if (ret) { -+ regmap_write(es9356->regmap, -+ SDW_SDCA_CTL(func, pde_entity, -+ ES9356_SDCA_CTL_REQ_POWER_STATE, 0), -+ ps ? ps3 : ps0); -+ es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps3 : ps0); -+ } else { -+ dev_dbg(component->dev, "%s PDE is already %d\n", __func__, -+ ps ? ps0 : ps3); -+ } -+ } - - if (rate) - regmap_write(es9356->regmap, -@@ -671,7 +673,7 @@ static int es9356_sdca_mbq_size(struct device *dev, unsigned int reg) - } - } - --static struct regmap_sdw_mbq_cfg es9356_mbq_config = { -+static const struct regmap_sdw_mbq_cfg es9356_mbq_config = { - .mbq_size = es9356_sdca_mbq_size, - }; - -@@ -1091,9 +1093,8 @@ static int es9356_sdca_dev_system_suspend(struct device *dev) - { - struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev); - -- mutex_lock(&es9356->disable_irq_lock); -- es9356->disable_irq = true; -- mutex_unlock(&es9356->disable_irq_lock); -+ scoped_guard(mutex, &es9356->disable_irq_lock) -+ es9356->disable_irq = true; - - return es9356_sdca_dev_suspend(dev); - } -diff --git a/sound/soc/codecs/fs-amp-lib.c b/sound/soc/codecs/fs-amp-lib.c ---- a/sound/soc/codecs/fs-amp-lib.c -+++ b/sound/soc/codecs/fs-amp-lib.c -@@ -221,7 +221,7 @@ static void fs_print_firmware_info(struct fs_amp_lib *amp_lib) - - int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name) - { -- const struct firmware *cont; -+ const struct firmware *cont __free(firmware) = NULL; - struct fs_fwm_header *hdr; - int ret; - -@@ -237,7 +237,6 @@ int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name) - dev_info(amp_lib->dev, "Loading %s - size: %zu\n", name, cont->size); - - hdr = devm_kmemdup(amp_lib->dev, cont->data, cont->size, GFP_KERNEL); -- release_firmware(cont); - if (!hdr) - return -ENOMEM; - -diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c ---- a/sound/soc/codecs/fs210x.c -+++ b/sound/soc/codecs/fs210x.c -@@ -4,6 +4,7 @@ - // - // Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd. - -+#include - #include - #include - #include -@@ -771,9 +772,8 @@ static int fs210x_dai_hw_params(struct snd_pcm_substream *substream, - if (fs210x->devid == FS2105S_DEVICE_ID && fs210x->srate == 16000) - return -EOPNOTSUPP; - -- mutex_lock(&fs210x->lock); -- ret = fs210x_set_hw_params(fs210x); -- mutex_unlock(&fs210x->lock); -+ scoped_guard(mutex, &fs210x->lock) -+ ret = fs210x_set_hw_params(fs210x); - if (ret) - dev_err(fs210x->dev, "Failed to set hw params: %d\n", ret); - -@@ -790,15 +790,11 @@ static int fs210x_dai_mute(struct snd_soc_dai *dai, int mute, int stream) - - fs210x = snd_soc_component_get_drvdata(dai->component); - -- mutex_lock(&fs210x->lock); -- -- if (!fs210x->is_inited || fs210x->is_suspended) { -- mutex_unlock(&fs210x->lock); -- return 0; -+ scoped_guard(mutex, &fs210x->lock) { -+ if (!fs210x->is_inited || fs210x->is_suspended) -+ return 0; - } - -- mutex_unlock(&fs210x->lock); -- - if (mute) { - cancel_delayed_work_sync(&fs210x->fault_check_work); - cancel_delayed_work_sync(&fs210x->start_work); -@@ -817,15 +813,11 @@ static int fs210x_dai_trigger(struct snd_pcm_substream *substream, - - fs210x = snd_soc_component_get_drvdata(dai->component); - -- mutex_lock(&fs210x->lock); -- -- if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) { -- mutex_unlock(&fs210x->lock); -- return 0; -+ scoped_guard(mutex, &fs210x->lock) { -+ if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) -+ return 0; - } - -- mutex_unlock(&fs210x->lock); -- - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: -@@ -853,13 +845,11 @@ static void fs210x_start_work(struct work_struct *work) - - fs210x = container_of(work, struct fs210x_priv, start_work.work); - -- mutex_lock(&fs210x->lock); -+ guard(mutex)(&fs210x->lock); - - ret = fs210x_dev_play(fs210x); - if (ret) - dev_err(fs210x->dev, "Failed to start playing: %d\n", ret); -- -- mutex_unlock(&fs210x->lock); - } - - static void fs210x_fault_check_work(struct work_struct *work) -@@ -870,15 +860,13 @@ static void fs210x_fault_check_work(struct work_struct *work) - - fs210x = container_of(work, struct fs210x_priv, fault_check_work.work); - -- mutex_lock(&fs210x->lock); -+ scoped_guard(mutex, &fs210x->lock) { -+ if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) -+ return; - -- if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) { -- mutex_unlock(&fs210x->lock); -- return; -+ ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status); - } - -- ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status); -- mutex_unlock(&fs210x->lock); - if (ret) - return; - -@@ -991,7 +979,7 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol, - if (fs210x->scene_id < 1) - return -EINVAL; - -- mutex_lock(&fs210x->lock); -+ guard(mutex)(&fs210x->lock); - /* - * FS210x has scene(s) as below: - * init scene: id = 0 -@@ -1000,7 +988,6 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol, - */ - index = fs210x->scene_id - 1; - ucontrol->value.integer.value[0] = index; -- mutex_unlock(&fs210x->lock); - - return 0; - } -@@ -1019,7 +1006,7 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, - return -EINVAL; - } - -- mutex_lock(&fs210x->lock); -+ guard(mutex)(&fs210x->lock); - - /* - * FS210x has scene(s) as below: -@@ -1029,17 +1016,14 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, - */ - scene_id = ucontrol->value.integer.value[0] + 1; - scene_count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */ -- if (scene_id < 1 || scene_id > scene_count) { -- mutex_unlock(&fs210x->lock); -+ if (scene_id < 1 || scene_id > scene_count) - return -ERANGE; -- } - - if (scene_id != fs210x->scene_id) - is_changed = true; - - if (fs210x->is_suspended) { - fs210x->scene_id = scene_id; -- mutex_unlock(&fs210x->lock); - return is_changed; - } - -@@ -1047,8 +1031,6 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol, - if (ret) - dev_err(fs210x->dev, "Failed to set scene: %d\n", ret); - -- mutex_unlock(&fs210x->lock); -- - if (!ret && is_changed) - return 1; - -@@ -1062,12 +1044,10 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w, - struct fs210x_priv *fs210x = snd_soc_component_get_drvdata(cmpnt); - int ret = 0; - -- mutex_lock(&fs210x->lock); -+ guard(mutex)(&fs210x->lock); - -- if (fs210x->is_suspended) { -- mutex_unlock(&fs210x->lock); -+ if (fs210x->is_suspended) - return 0; -- } - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: -@@ -1088,8 +1068,6 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w, - break; - } - -- mutex_unlock(&fs210x->lock); -- - return ret; - } - -@@ -1220,11 +1198,9 @@ static int fs210x_probe(struct snd_soc_component *cmpnt) - if (ret) - return ret; - -- mutex_lock(&fs210x->lock); -- ret = fs210x_init_chip(fs210x); -- mutex_unlock(&fs210x->lock); -+ guard(mutex)(&fs210x->lock); - -- return ret; -+ return fs210x_init_chip(fs210x); - } - - static void fs210x_remove(struct snd_soc_component *cmpnt) -@@ -1251,15 +1227,15 @@ static int fs210x_suspend(struct snd_soc_component *cmpnt) - - regcache_cache_only(fs210x->regmap, true); - -- mutex_lock(&fs210x->lock); -- fs210x->cur_scene = NULL; -- fs210x->is_inited = false; -- fs210x->is_playing = false; -- fs210x->is_suspended = true; -+ scoped_guard(mutex, &fs210x->lock) { -+ fs210x->cur_scene = NULL; -+ fs210x->is_inited = false; -+ fs210x->is_playing = false; -+ fs210x->is_suspended = true; - -- gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ -- fsleep(30000); /* >= 30ms */ -- mutex_unlock(&fs210x->lock); -+ gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */ -+ fsleep(30000); /* >= 30ms */ -+ } - - cancel_delayed_work_sync(&fs210x->start_work); - cancel_delayed_work_sync(&fs210x->fault_check_work); -@@ -1288,14 +1264,11 @@ static int fs210x_resume(struct snd_soc_component *cmpnt) - return ret; - } - -- mutex_lock(&fs210x->lock); -+ guard(mutex)(&fs210x->lock); - - fs210x->is_suspended = false; -- ret = fs210x_init_chip(fs210x); - -- mutex_unlock(&fs210x->lock); -- -- return ret; -+ return fs210x_init_chip(fs210x); - } - #else - #define fs210x_suspend NULL -diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c ---- a/sound/soc/codecs/hdac_hda.c -+++ b/sound/soc/codecs/hdac_hda.c -@@ -437,7 +437,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) - - #ifdef CONFIG_SND_HDA_PATCH_LOADER - if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) { -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - - dev_info(&hdev->dev, "Applying patch firmware '%s'\n", - loadable_patch[hda_pvt->dev_index]); -@@ -451,7 +451,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) - dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret); - goto error_no_pm; - } -- release_firmware(fw); - } - } - #endif -diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c ---- a/sound/soc/codecs/hdac_hdmi.c -+++ b/sound/soc/codecs/hdac_hdmi.c -@@ -10,6 +10,7 @@ - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -+#include - #include - #include - #include -@@ -537,10 +538,11 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( - continue; - - list_for_each_entry(port, &pcm->port_list, head) { -- mutex_lock(&pcm->lock); -- ret = hdac_hdmi_query_port_connlist(hdev, -- port->pin, port); -- mutex_unlock(&pcm->lock); -+ scoped_guard(mutex, &pcm->lock) { -+ ret = hdac_hdmi_query_port_connlist(hdev, -+ port->pin, -+ port); -+ } - if (ret < 0) - continue; - -@@ -640,11 +642,11 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, - pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); - - if (pcm) { -- mutex_lock(&pcm->lock); -- pcm->chmap_set = false; -- memset(pcm->chmap, 0, sizeof(pcm->chmap)); -- pcm->channels = 0; -- mutex_unlock(&pcm->lock); -+ scoped_guard(mutex, &pcm->lock) { -+ pcm->chmap_set = false; -+ memset(pcm->chmap, 0, sizeof(pcm->chmap)); -+ pcm->channels = 0; -+ } - } - - if (dai_map->port) -@@ -922,7 +924,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, - if (port == NULL) - return -EINVAL; - -- mutex_lock(&hdmi->pin_mutex); -+ guard(mutex)(&hdmi->pin_mutex); - list_for_each_entry(pcm, &hdmi->pcm_list, head) { - if (list_empty(&pcm->port_list)) - continue; -@@ -945,12 +947,10 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, - list_add_tail(&port->head, &pcm->port_list); - if (port->eld.monitor_present && port->eld.eld_valid) { - hdac_hdmi_jack_report_sync(pcm, port, true); -- mutex_unlock(&hdmi->pin_mutex); - return ret; - } - } - } -- mutex_unlock(&hdmi->pin_mutex); - - return ret; - } -@@ -1274,67 +1274,65 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, - * In case of non MST pin, get_eld info API expectes port - * to be -1. - */ -- mutex_lock(&hdmi->pin_mutex); -- port->eld.monitor_present = false; -+ scoped_guard(mutex, &hdmi->pin_mutex) { -+ port->eld.monitor_present = false; - -- if (pin->mst_capable) -- port_id = port->id; -+ if (pin->mst_capable) -+ port_id = port->id; - -- size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id, -- &port->eld.monitor_present, -- port->eld.eld_buffer, -- ELD_MAX_SIZE); -+ size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id, -+ &port->eld.monitor_present, -+ port->eld.eld_buffer, -+ ELD_MAX_SIZE); - -- if (size > 0) { -- size = min(size, ELD_MAX_SIZE); -- if (hdac_hdmi_parse_eld(hdev, port) < 0) -- size = -EINVAL; -- } -- -- eld_valid = port->eld.eld_valid; -- -- if (size > 0) { -- port->eld.eld_valid = true; -- port->eld.eld_size = size; -- } else { -- port->eld.eld_valid = false; -- port->eld.eld_size = 0; -- } -- -- eld_changed = (eld_valid != port->eld.eld_valid); -- -- pcm = hdac_hdmi_get_pcm(hdev, port); -- -- if (!port->eld.monitor_present || !port->eld.eld_valid) { -- -- dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", -- __func__, pin->nid, port->id); -- -- /* -- * PCMs are not registered during device probe, so don't -- * report jack here. It will be done in usermode mux -- * control select. -- */ -- if (pcm) { -- hdac_hdmi_jack_report(pcm, port, false); -- schedule_work(&port->dapm_work); -+ if (size > 0) { -+ size = min(size, ELD_MAX_SIZE); -+ if (hdac_hdmi_parse_eld(hdev, port) < 0) -+ size = -EINVAL; - } - -- mutex_unlock(&hdmi->pin_mutex); -- return; -- } -+ eld_valid = port->eld.eld_valid; - -- if (port->eld.monitor_present && port->eld.eld_valid) { -- if (pcm) { -- hdac_hdmi_jack_report(pcm, port, true); -- schedule_work(&port->dapm_work); -+ if (size > 0) { -+ port->eld.eld_valid = true; -+ port->eld.eld_size = size; -+ } else { -+ port->eld.eld_valid = false; -+ port->eld.eld_size = 0; - } - -- print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, -- port->eld.eld_buffer, port->eld.eld_size, false); -+ eld_changed = (eld_valid != port->eld.eld_valid); - -+ pcm = hdac_hdmi_get_pcm(hdev, port); -+ -+ if (!port->eld.monitor_present || !port->eld.eld_valid) { -+ -+ dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n", -+ __func__, pin->nid, port->id); -+ -+ /* -+ * PCMs are not registered during device probe, so don't -+ * report jack here. It will be done in usermode mux -+ * control select. -+ */ -+ if (pcm) { -+ hdac_hdmi_jack_report(pcm, port, false); -+ schedule_work(&port->dapm_work); -+ } -+ -+ return; -+ } -+ -+ if (port->eld.monitor_present && port->eld.eld_valid) { -+ if (pcm) { -+ hdac_hdmi_jack_report(pcm, port, true); -+ schedule_work(&port->dapm_work); -+ } -+ -+ print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, -+ port->eld.eld_buffer, port->eld.eld_size, false); -+ } - } -- mutex_unlock(&hdmi->pin_mutex); - - if (eld_changed && pcm) - snd_ctl_notify(hdmi->card, -@@ -1795,13 +1793,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx, - if (list_empty(&pcm->port_list)) - return; - -- mutex_lock(&pcm->lock); -+ guard(mutex)(&pcm->lock); - pcm->chmap_set = true; - memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); - list_for_each_entry(port, &pcm->port_list, head) - if (prepared) - hdac_hdmi_setup_audio_infoframe(hdev, pcm, port); -- mutex_unlock(&pcm->lock); - } - - static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx) -@@ -1866,8 +1863,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) - snd_hdac_ext_bus_link_get(hdev->bus, hlink); - - hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL); -- if (hdmi_priv == NULL) -+ if (hdmi_priv == NULL) { -+ snd_hdac_ext_bus_link_put(hdev->bus, hlink); - return -ENOMEM; -+ } - - snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap); - hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; -@@ -1876,8 +1875,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) - hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; - hdmi_priv->hdev = hdev; - -- if (!hdac_id) -+ if (!hdac_id) { -+ snd_hdac_ext_bus_link_put(hdev->bus, hlink); - return -ENODEV; -+ } - - if (hdac_id->driver_data) - hdmi_priv->drv_data = -@@ -1902,6 +1903,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) - if (ret < 0) { - dev_err(&hdev->dev, - "Failed in parse and map nid with err: %d\n", ret); -+ snd_hdac_ext_bus_link_put(hdev->bus, hlink); -+ snd_hdac_display_power(hdev->bus, hdev->addr, false); - return ret; - } - snd_hdac_refresh_widgets(hdev); -diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c ---- a/sound/soc/codecs/hdmi-codec.c -+++ b/sound/soc/codecs/hdmi-codec.c -@@ -4,6 +4,7 @@ - * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ - * Author: Jyri Sarha - */ -+#include - #include - #include - #include -@@ -456,31 +457,30 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, - if (!((has_playback && tx) || (has_capture && !tx))) - return 0; - -- mutex_lock(&hcp->lock); -+ guard(mutex)(&hcp->lock); - if (hcp->busy) { - dev_err(dai->dev, "Only one simultaneous stream supported!\n"); -- mutex_unlock(&hcp->lock); - return -EINVAL; - } - - if (hcp->hcd.ops->audio_startup) { - ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); - if (ret) -- goto err; -+ return ret; - } - - if (tx && hcp->hcd.ops->get_eld) { - ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, - hcp->eld, sizeof(hcp->eld)); - if (ret) -- goto err; -+ return ret; - - snd_parse_eld(dai->dev, &hcp->eld_parsed, - hcp->eld, sizeof(hcp->eld)); - - ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); - if (ret) -- goto err; -+ return ret; - - /* Select chmap supported */ - hdmi_codec_eld_chmap(hcp); -@@ -488,8 +488,6 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, - - hcp->busy = true; - --err: -- mutex_unlock(&hcp->lock); - return ret; - } - -@@ -507,9 +505,8 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); - -- mutex_lock(&hcp->lock); -+ guard(mutex)(&hcp->lock); - hcp->busy = false; -- mutex_unlock(&hcp->lock); - } - - static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, -diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c ---- a/sound/soc/codecs/idt821034.c -+++ b/sound/soc/codecs/idt821034.c -@@ -7,6 +7,7 @@ - // Author: Herve Codina - - #include -+#include - #include - #include - #include -@@ -413,12 +414,12 @@ static int idt821034_kctrl_gain_get(struct snd_kcontrol *kcontrol, - - ch = IDT821034_ID_GET_CHAN(mc->reg); - -- mutex_lock(&idt821034->mutex); -- if (IDT821034_ID_IS_OUT(mc->reg)) -- val = idt821034->amps.ch[ch].amp_out.gain; -- else -- val = idt821034->amps.ch[ch].amp_in.gain; -- mutex_unlock(&idt821034->mutex); -+ scoped_guard(mutex, &idt821034->mutex) { -+ if (IDT821034_ID_IS_OUT(mc->reg)) -+ val = idt821034->amps.ch[ch].amp_out.gain; -+ else -+ val = idt821034->amps.ch[ch].amp_in.gain; -+ } - - ucontrol->value.integer.value[0] = val & mask; - if (invert) -@@ -456,7 +457,7 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol, - - ch = IDT821034_ID_GET_CHAN(mc->reg); - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - if (IDT821034_ID_IS_OUT(mc->reg)) { - amp = &idt821034->amps.ch[ch].amp_out; -@@ -466,22 +467,18 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol, - gain_type = IDT821034_GAIN_TX; - } - -- if (amp->gain == val) { -- ret = 0; -- goto end; -- } -+ if (amp->gain == val) -+ return 0; - - if (!amp->is_muted) { - ret = idt821034_set_gain_channel(idt821034, ch, gain_type, val); - if (ret) -- goto end; -+ return ret; - } - - amp->gain = val; -- ret = 1; /* The value changed */ --end: -- mutex_unlock(&idt821034->mutex); -- return ret; -+ -+ return 1; - } - - static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol, -@@ -495,11 +492,11 @@ static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol, - - ch = IDT821034_ID_GET_CHAN(id); - -- mutex_lock(&idt821034->mutex); -- is_muted = IDT821034_ID_IS_OUT(id) ? -- idt821034->amps.ch[ch].amp_out.is_muted : -- idt821034->amps.ch[ch].amp_in.is_muted; -- mutex_unlock(&idt821034->mutex); -+ scoped_guard(mutex, &idt821034->mutex) { -+ is_muted = IDT821034_ID_IS_OUT(id) ? -+ idt821034->amps.ch[ch].amp_out.is_muted : -+ idt821034->amps.ch[ch].amp_in.is_muted; -+ } - - ucontrol->value.integer.value[0] = !is_muted; - -@@ -521,7 +518,7 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol, - ch = IDT821034_ID_GET_CHAN(id); - is_mute = !ucontrol->value.integer.value[0]; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - if (IDT821034_ID_IS_OUT(id)) { - amp = &idt821034->amps.ch[ch].amp_out; -@@ -531,21 +528,17 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol, - gain_type = IDT821034_GAIN_TX; - } - -- if (amp->is_muted == is_mute) { -- ret = 0; -- goto end; -- } -+ if (amp->is_muted == is_mute) -+ return 0; - - ret = idt821034_set_gain_channel(idt821034, ch, gain_type, - is_mute ? 0 : amp->gain); - if (ret) -- goto end; -+ return ret; - - amp->is_muted = is_mute; -- ret = 1; /* The value changed */ --end: -- mutex_unlock(&idt821034->mutex); -- return ret; -+ -+ return 1; - } - - static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -300, 1300); -@@ -623,24 +616,20 @@ static int idt821034_power_event(struct snd_soc_dapm_widget *w, - struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component); - unsigned int id = w->shift; - u8 power, mask; -- int ret; - u8 ch; - - ch = IDT821034_ID_GET_CHAN(id); - mask = IDT821034_ID_IS_OUT(id) ? IDT821034_CONF_PWRUP_RX : IDT821034_CONF_PWRUP_TX; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - power = idt821034_get_channel_power(idt821034, ch); - if (SND_SOC_DAPM_EVENT_ON(event)) - power |= mask; - else - power &= ~mask; -- ret = idt821034_set_channel_power(idt821034, ch, power); - -- mutex_unlock(&idt821034->mutex); -- -- return ret; -+ return idt821034_set_channel_power(idt821034, ch, power); - } - - static const struct snd_soc_dapm_widget idt821034_dapm_widgets[] = { -@@ -717,9 +706,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai, - ch = 0; - while (mask && ch < IDT821034_NB_CHANNEL) { - if (mask & 0x1) { -- mutex_lock(&idt821034->mutex); -- ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_RX, slot); -- mutex_unlock(&idt821034->mutex); -+ scoped_guard(mutex, &idt821034->mutex) -+ ret = idt821034_set_channel_ts(idt821034, ch, -+ IDT821034_CH_RX, slot); - if (ret) { - dev_err(dai->dev, "ch%u set tx tdm slot failed (%d)\n", - ch, ret); -@@ -742,9 +731,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai, - ch = 0; - while (mask && ch < IDT821034_NB_CHANNEL) { - if (mask & 0x1) { -- mutex_lock(&idt821034->mutex); -- ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_TX, slot); -- mutex_unlock(&idt821034->mutex); -+ scoped_guard(mutex, &idt821034->mutex) -+ ret = idt821034_set_channel_ts(idt821034, ch, -+ IDT821034_CH_TX, slot); - if (ret) { - dev_err(dai->dev, "ch%u set rx tdm slot failed (%d)\n", - ch, ret); -@@ -769,9 +758,8 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - { - struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component); - u8 conf; -- int ret; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - conf = idt821034_get_codec_conf(idt821034); - -@@ -785,13 +773,10 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - default: - dev_err(dai->dev, "Unsupported DAI format 0x%x\n", - fmt & SND_SOC_DAIFMT_FORMAT_MASK); -- ret = -EINVAL; -- goto end; -+ return -EINVAL; - } -- ret = idt821034_set_codec_conf(idt821034, conf); --end: -- mutex_unlock(&idt821034->mutex); -- return ret; -+ -+ return idt821034_set_codec_conf(idt821034, conf); - } - - static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, -@@ -800,9 +785,8 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, - { - struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component); - u8 conf; -- int ret; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - conf = idt821034_get_codec_conf(idt821034); - -@@ -816,13 +800,10 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream, - default: - dev_err(dai->dev, "Unsupported PCM format 0x%x\n", - params_format(params)); -- ret = -EINVAL; -- goto end; -+ return -EINVAL; - } -- ret = idt821034_set_codec_conf(idt821034, conf); --end: -- mutex_unlock(&idt821034->mutex); -- return ret; -+ -+ return idt821034_set_codec_conf(idt821034, conf); - } - - static const unsigned int idt821034_sample_bits[] = {8}; -@@ -897,11 +878,11 @@ static int idt821034_reset_audio(struct idt821034 *idt821034) - int ret; - u8 i; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - ret = idt821034_set_codec_conf(idt821034, 0); - if (ret) -- goto end; -+ return ret; - - for (i = 0; i < IDT821034_NB_CHANNEL; i++) { - idt821034->amps.ch[i].amp_out.gain = IDT821034_GAIN_OUT_INIT_RAW; -@@ -909,24 +890,21 @@ static int idt821034_reset_audio(struct idt821034 *idt821034) - ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_RX, - idt821034->amps.ch[i].amp_out.gain); - if (ret) -- goto end; -+ return ret; - - idt821034->amps.ch[i].amp_in.gain = IDT821034_GAIN_IN_INIT_RAW; - idt821034->amps.ch[i].amp_in.is_muted = false; - ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_TX, - idt821034->amps.ch[i].amp_in.gain); - if (ret) -- goto end; -+ return ret; - - ret = idt821034_set_channel_power(idt821034, i, 0); - if (ret) -- goto end; -+ return ret; - } - -- ret = 0; --end: -- mutex_unlock(&idt821034->mutex); -- return ret; -+ return 0; - } - - static int idt821034_component_probe(struct snd_soc_component *component) -@@ -965,7 +943,7 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, - u8 slic_raw; - int ret; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - slic_raw = idt821034_get_written_slic_raw(idt821034, ch); - if (val) -@@ -974,8 +952,6 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset, - slic_raw &= ~mask; - ret = idt821034_write_slic_raw(idt821034, ch, slic_raw); - -- mutex_unlock(&idt821034->mutex); -- - if (ret) - dev_err(&idt821034->spi->dev, "set gpio %d (%u, 0x%x) failed (%d)\n", - offset, ch, mask, ret); -@@ -991,9 +967,8 @@ static int idt821034_chip_gpio_get(struct gpio_chip *c, unsigned int offset) - u8 slic_raw; - int ret; - -- mutex_lock(&idt821034->mutex); -- ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw); -- mutex_unlock(&idt821034->mutex); -+ scoped_guard(mutex, &idt821034->mutex) -+ ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw); - if (ret) { - dev_err(&idt821034->spi->dev, "get gpio %d (%u, 0x%x) failed (%d)\n", - offset, ch, mask, ret); -@@ -1015,9 +990,8 @@ static int idt821034_chip_get_direction(struct gpio_chip *c, unsigned int offset - struct idt821034 *idt821034 = gpiochip_get_data(c); - u8 slic_dir; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - slic_dir = idt821034_get_slic_conf(idt821034, ch); -- mutex_unlock(&idt821034->mutex); - - return slic_dir & mask ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; - } -@@ -1034,7 +1008,7 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs - if (mask & ~(IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN)) - return -EPERM; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - slic_conf = idt821034_get_slic_conf(idt821034, ch) | mask; - -@@ -1044,7 +1018,6 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs - offset, ch, mask, ret); - } - -- mutex_unlock(&idt821034->mutex); - return ret; - } - -@@ -1060,7 +1033,7 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off - if (ret) - return ret; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - slic_conf = idt821034_get_slic_conf(idt821034, ch) & ~mask; - -@@ -1070,7 +1043,6 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off - offset, ch, mask, ret); - } - -- mutex_unlock(&idt821034->mutex); - return ret; - } - -@@ -1079,24 +1051,22 @@ static int idt821034_reset_gpio(struct idt821034 *idt821034) - int ret; - u8 i; - -- mutex_lock(&idt821034->mutex); -+ guard(mutex)(&idt821034->mutex); - - /* IO0 and IO1 as input for all channels and output IO set to 0 */ - for (i = 0; i < IDT821034_NB_CHANNEL; i++) { - ret = idt821034_set_slic_conf(idt821034, i, - IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN); - if (ret) -- goto end; -+ return ret; - - ret = idt821034_write_slic_raw(idt821034, i, 0); - if (ret) -- goto end; -+ return ret; - - } -- ret = 0; --end: -- mutex_unlock(&idt821034->mutex); -- return ret; -+ -+ return 0; - } - - static int idt821034_gpio_init(struct idt821034 *idt821034) -diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c ---- a/sound/soc/codecs/lochnagar-sc.c -+++ b/sound/soc/codecs/lochnagar-sc.c -@@ -137,15 +137,23 @@ static int lochnagar_sc_set_usb_fmt(struct snd_soc_dai *dai, unsigned int fmt) - return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBP_CFP); - } - -+static const u64 lochnagar_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF; -+ - static const struct snd_soc_dai_ops lochnagar_sc_line_ops = { - .startup = lochnagar_sc_line_startup, - .shutdown = lochnagar_sc_line_shutdown, - .set_fmt = lochnagar_sc_set_line_fmt, -+ .auto_selectable_formats = &lochnagar_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static const struct snd_soc_dai_ops lochnagar_sc_usb_ops = { - .startup = lochnagar_sc_startup, - .set_fmt = lochnagar_sc_set_usb_fmt, -+ .auto_selectable_formats = &lochnagar_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver lochnagar_sc_dai[] = { -diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c ---- a/sound/soc/codecs/lpass-macro-common.c -+++ b/sound/soc/codecs/lpass-macro-common.c -@@ -1,6 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-only - // Copyright (c) 2022, The Linux Foundation. All rights reserved. - -+#include - #include - #include - #include -@@ -71,21 +72,16 @@ EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); - - void lpass_macro_set_codec_version(enum lpass_codec_version version) - { -- mutex_lock(&lpass_codec_mutex); -+ guard(mutex)(&lpass_codec_mutex); - lpass_codec_version = version; -- mutex_unlock(&lpass_codec_mutex); - } - EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version); - - enum lpass_codec_version lpass_macro_get_codec_version(void) - { -- enum lpass_codec_version ver; -+ guard(mutex)(&lpass_codec_mutex); - -- mutex_lock(&lpass_codec_mutex); -- ver = lpass_codec_version; -- mutex_unlock(&lpass_codec_mutex); -- -- return ver; -+ return lpass_codec_version; - } - EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version); - -diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c ---- a/sound/soc/codecs/lpass-rx-macro.c -+++ b/sound/soc/codecs/lpass-rx-macro.c -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -2030,9 +2031,10 @@ static struct snd_soc_dai_driver rx_macro_dai[] = { - }, - }; - --static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) -+static int rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) - { - struct regmap *regmap = rx->regmap; -+ int ret; - - if (mclk_enable) { - if (rx->rx_mclk_users == 0) { -@@ -2047,14 +2049,16 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) - CDC_RX_FS_MCLK_CNT_EN_MASK, - CDC_RX_FS_MCLK_CNT_ENABLE); - regcache_mark_dirty(regmap); -- regcache_sync(regmap); -+ ret = regcache_sync(regmap); -+ if (ret) -+ return ret; - } - rx->rx_mclk_users++; - } else { - if (rx->rx_mclk_users <= 0) { - dev_err(rx->dev, "%s: clock already disabled\n", __func__); - rx->rx_mclk_users = 0; -- return; -+ return 0; - } - rx->rx_mclk_users--; - if (rx->rx_mclk_users == 0) { -@@ -2068,6 +2072,8 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable) - CDC_RX_CLK_MCLK2_EN_MASK, 0x0); - } - } -+ -+ return 0; - } - - static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w, -@@ -2079,11 +2085,9 @@ static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w, - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: -- rx_macro_mclk_enable(rx, true); -- break; -+ return rx_macro_mclk_enable(rx, true); - case SND_SOC_DAPM_POST_PMD: -- rx_macro_mclk_enable(rx, false); -- break; -+ return rx_macro_mclk_enable(rx, false); - default: - dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event); - ret = -EINVAL; -@@ -3671,14 +3675,16 @@ static int swclk_gate_enable(struct clk_hw *hw) - struct rx_macro *rx = to_rx_macro(hw); - int ret; - -- ret = clk_prepare_enable(rx->mclk); -+ ret = pm_runtime_resume_and_get(rx->dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = rx_macro_mclk_enable(rx, true); - if (ret) { -- dev_err(rx->dev, "unable to prepare mclk\n"); -+ clk_disable_unprepare(rx->mclk); - return ret; - } - -- rx_macro_mclk_enable(rx, true); -- - regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, - CDC_RX_SWR_CLK_EN_MASK, 1); - -@@ -3693,7 +3699,7 @@ static void swclk_gate_disable(struct clk_hw *hw) - CDC_RX_SWR_CLK_EN_MASK, 0); - - rx_macro_mclk_enable(rx, false); -- clk_disable_unprepare(rx->mclk); -+ pm_runtime_put_autosuspend(rx->dev); - } - - static int swclk_gate_is_enabled(struct clk_hw *hw) -@@ -3864,28 +3870,31 @@ static int rx_macro_probe(struct platform_device *pdev) - rx->dev = dev; - - /* set MCLK and NPL rates */ -- clk_set_rate(rx->mclk, MCLK_FREQ); -- clk_set_rate(rx->npl, MCLK_FREQ); -- -- ret = clk_prepare_enable(rx->macro); -+ ret = clk_set_rate(rx->mclk, MCLK_FREQ); - if (ret) - return ret; - -- ret = clk_prepare_enable(rx->dcodec); -+ ret = clk_set_rate(rx->npl, MCLK_FREQ); - if (ret) -- goto err_dcodec; -+ return ret; - -- ret = clk_prepare_enable(rx->mclk); -+ ret = devm_pm_clk_create(dev); - if (ret) -- goto err_mclk; -+ return ret; - -- ret = clk_prepare_enable(rx->npl); -- if (ret) -- goto err_npl; -+ ret = of_pm_clk_add_clks(dev); -+ if (ret < 0) -+ return ret; - -- ret = clk_prepare_enable(rx->fsgen); -+ pm_runtime_set_autosuspend_delay(dev, 100); -+ pm_runtime_use_autosuspend(dev); -+ ret = devm_pm_runtime_enable(dev); - if (ret) -- goto err_fsgen; -+ return ret; -+ -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret) -+ return ret; - - /* reset swr block */ - regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, -@@ -3902,46 +3911,25 @@ static int rx_macro_probe(struct platform_device *pdev) - rx_macro_dai, - ARRAY_SIZE(rx_macro_dai)); - if (ret) -- goto err_clkout; -- -- -- pm_runtime_set_autosuspend_delay(dev, 3000); -- pm_runtime_use_autosuspend(dev); -- pm_runtime_mark_last_busy(dev); -- pm_runtime_set_active(dev); -- pm_runtime_enable(dev); -+ goto err_rpm_put; - - ret = rx_macro_register_mclk_output(rx); - if (ret) -- goto err_clkout; -+ goto err_rpm_put; -+ -+ ret = pm_runtime_put_autosuspend(dev); -+ if (ret < 0) -+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); - - return 0; - --err_clkout: -- clk_disable_unprepare(rx->fsgen); --err_fsgen: -- clk_disable_unprepare(rx->npl); --err_npl: -- clk_disable_unprepare(rx->mclk); --err_mclk: -- clk_disable_unprepare(rx->dcodec); --err_dcodec: -- clk_disable_unprepare(rx->macro); -+err_rpm_put: -+ if (pm_runtime_put_sync_suspend(dev) < 0) -+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); - - return ret; - } - --static void rx_macro_remove(struct platform_device *pdev) --{ -- struct rx_macro *rx = dev_get_drvdata(&pdev->dev); -- -- clk_disable_unprepare(rx->mclk); -- clk_disable_unprepare(rx->npl); -- clk_disable_unprepare(rx->fsgen); -- clk_disable_unprepare(rx->macro); -- clk_disable_unprepare(rx->dcodec); --} -- - static const struct of_device_id rx_macro_dt_match[] = { - { - .compatible = "qcom,sc7280-lpass-rx-macro", -@@ -3969,13 +3957,17 @@ MODULE_DEVICE_TABLE(of, rx_macro_dt_match); - static int rx_macro_runtime_suspend(struct device *dev) - { - struct rx_macro *rx = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(rx->regmap, true); -- regcache_mark_dirty(rx->regmap); - -- clk_disable_unprepare(rx->fsgen); -- clk_disable_unprepare(rx->npl); -- clk_disable_unprepare(rx->mclk); -+ ret = pm_clk_suspend(dev); -+ if (ret) { -+ regcache_cache_only(rx->regmap, false); -+ return ret; -+ } -+ -+ regcache_mark_dirty(rx->regmap); - - return 0; - } -@@ -3985,33 +3977,23 @@ static int rx_macro_runtime_resume(struct device *dev) - struct rx_macro *rx = dev_get_drvdata(dev); - int ret; - -- ret = clk_prepare_enable(rx->mclk); -+ ret = pm_clk_resume(dev); - if (ret) { -- dev_err(dev, "unable to prepare mclk\n"); -+ regcache_cache_only(rx->regmap, true); -+ regcache_mark_dirty(rx->regmap); - return ret; - } - -- ret = clk_prepare_enable(rx->npl); -- if (ret) { -- dev_err(dev, "unable to prepare mclkx2\n"); -- goto err_npl; -- } -- -- ret = clk_prepare_enable(rx->fsgen); -- if (ret) { -- dev_err(dev, "unable to prepare fsgen\n"); -- goto err_fsgen; -- } - regcache_cache_only(rx->regmap, false); -- regcache_sync(rx->regmap); -+ ret = regcache_sync(rx->regmap); -+ if (ret) { -+ regcache_cache_only(rx->regmap, true); -+ regcache_mark_dirty(rx->regmap); -+ pm_clk_suspend(dev); -+ return ret; -+ } - - return 0; --err_fsgen: -- clk_disable_unprepare(rx->npl); --err_npl: -- clk_disable_unprepare(rx->mclk); -- -- return ret; - } - - static const struct dev_pm_ops rx_macro_pm_ops = { -@@ -4026,7 +4008,6 @@ static struct platform_driver rx_macro_driver = { - .pm = pm_ptr(&rx_macro_pm_ops), - }, - .probe = rx_macro_probe, -- .remove = rx_macro_remove, - }; - - module_platform_driver(rx_macro_driver); -diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c ---- a/sound/soc/codecs/lpass-tx-macro.c -+++ b/sound/soc/codecs/lpass-tx-macro.c -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -614,6 +615,7 @@ static int tx_macro_mclk_enable(struct tx_macro *tx, - bool mclk_enable) - { - struct regmap *regmap = tx->regmap; -+ int ret; - - if (mclk_enable) { - if (tx->tx_mclk_users == 0) { -@@ -626,7 +628,9 @@ static int tx_macro_mclk_enable(struct tx_macro *tx, - CDC_TX_FS_CNT_EN_MASK, - CDC_TX_FS_CNT_ENABLE); - regcache_mark_dirty(regmap); -- regcache_sync(regmap); -+ ret = regcache_sync(regmap); -+ if (ret) -+ return ret; - } - tx->tx_mclk_users++; - } else { -@@ -739,11 +743,9 @@ static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w, - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: -- tx_macro_mclk_enable(tx, true); -- break; -+ return tx_macro_mclk_enable(tx, true); - case SND_SOC_DAPM_POST_PMD: -- tx_macro_mclk_enable(tx, false); -- break; -+ return tx_macro_mclk_enable(tx, false); - default: - break; - } -@@ -2149,17 +2151,20 @@ static int swclk_gate_enable(struct clk_hw *hw) - struct regmap *regmap = tx->regmap; - int ret; - -- ret = clk_prepare_enable(tx->mclk); -+ ret = pm_runtime_resume_and_get(tx->dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = tx_macro_mclk_enable(tx, true); - if (ret) { -- dev_err(tx->dev, "failed to enable mclk\n"); -+ pm_runtime_put_autosuspend(tx->dev); - return ret; - } - -- tx_macro_mclk_enable(tx, true); -- - regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL, - CDC_TX_SWR_CLK_EN_MASK, - CDC_TX_SWR_CLK_ENABLE); -+ - return 0; - } - -@@ -2172,7 +2177,7 @@ static void swclk_gate_disable(struct clk_hw *hw) - CDC_TX_SWR_CLK_EN_MASK, 0x0); - - tx_macro_mclk_enable(tx, false); -- clk_disable_unprepare(tx->mclk); -+ pm_runtime_put_autosuspend(tx->dev); - } - - static int swclk_gate_is_enabled(struct clk_hw *hw) -@@ -2315,28 +2320,31 @@ static int tx_macro_probe(struct platform_device *pdev) - tx->active_decimator[TX_MACRO_AIF3_CAP] = -1; - - /* set MCLK and NPL rates */ -- clk_set_rate(tx->mclk, MCLK_FREQ); -- clk_set_rate(tx->npl, MCLK_FREQ); -- -- ret = clk_prepare_enable(tx->macro); -+ ret = clk_set_rate(tx->mclk, MCLK_FREQ); - if (ret) - goto err; - -- ret = clk_prepare_enable(tx->dcodec); -+ ret = clk_set_rate(tx->npl, MCLK_FREQ); - if (ret) -- goto err_dcodec; -+ goto err; - -- ret = clk_prepare_enable(tx->mclk); -+ ret = devm_pm_clk_create(dev); - if (ret) -- goto err_mclk; -+ goto err; - -- ret = clk_prepare_enable(tx->npl); -- if (ret) -- goto err_npl; -+ ret = of_pm_clk_add_clks(dev); -+ if (ret < 0) -+ goto err; - -- ret = clk_prepare_enable(tx->fsgen); -+ pm_runtime_set_autosuspend_delay(dev, 100); -+ pm_runtime_use_autosuspend(dev); -+ ret = devm_pm_runtime_enable(dev); - if (ret) -- goto err_fsgen; -+ goto err; -+ -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret < 0) -+ goto err; - - - /* reset soundwire block */ -@@ -2356,30 +2364,21 @@ static int tx_macro_probe(struct platform_device *pdev) - tx_macro_dai, - ARRAY_SIZE(tx_macro_dai)); - if (ret) -- goto err_clkout; -- -- pm_runtime_set_autosuspend_delay(dev, 3000); -- pm_runtime_use_autosuspend(dev); -- pm_runtime_mark_last_busy(dev); -- pm_runtime_set_active(dev); -- pm_runtime_enable(dev); -+ goto err_rpm_put; - - ret = tx_macro_register_mclk_output(tx); - if (ret) -- goto err_clkout; -+ goto err_rpm_put; -+ -+ ret = pm_runtime_put_autosuspend(dev); -+ if (ret < 0) -+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); - - return 0; - --err_clkout: -- clk_disable_unprepare(tx->fsgen); --err_fsgen: -- clk_disable_unprepare(tx->npl); --err_npl: -- clk_disable_unprepare(tx->mclk); --err_mclk: -- clk_disable_unprepare(tx->dcodec); --err_dcodec: -- clk_disable_unprepare(tx->macro); -+err_rpm_put: -+ if (pm_runtime_put_sync_suspend(dev) < 0) -+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); - err: - lpass_macro_pds_exit(tx->pds); - -@@ -2390,25 +2389,23 @@ static void tx_macro_remove(struct platform_device *pdev) - { - struct tx_macro *tx = dev_get_drvdata(&pdev->dev); - -- clk_disable_unprepare(tx->macro); -- clk_disable_unprepare(tx->dcodec); -- clk_disable_unprepare(tx->mclk); -- clk_disable_unprepare(tx->npl); -- clk_disable_unprepare(tx->fsgen); -- - lpass_macro_pds_exit(tx->pds); - } - - static int tx_macro_runtime_suspend(struct device *dev) - { - struct tx_macro *tx = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(tx->regmap, true); -- regcache_mark_dirty(tx->regmap); - -- clk_disable_unprepare(tx->fsgen); -- clk_disable_unprepare(tx->npl); -- clk_disable_unprepare(tx->mclk); -+ ret = pm_clk_suspend(dev); -+ if (ret) { -+ regcache_cache_only(tx->regmap, false); -+ return ret; -+ } -+ -+ regcache_mark_dirty(tx->regmap); - - return 0; - } -@@ -2418,34 +2415,23 @@ static int tx_macro_runtime_resume(struct device *dev) - struct tx_macro *tx = dev_get_drvdata(dev); - int ret; - -- ret = clk_prepare_enable(tx->mclk); -+ ret = pm_clk_resume(dev); - if (ret) { -- dev_err(dev, "unable to prepare mclk\n"); -+ regcache_cache_only(tx->regmap, true); -+ regcache_mark_dirty(tx->regmap); - return ret; - } - -- ret = clk_prepare_enable(tx->npl); -- if (ret) { -- dev_err(dev, "unable to prepare npl\n"); -- goto err_npl; -- } -- -- ret = clk_prepare_enable(tx->fsgen); -- if (ret) { -- dev_err(dev, "unable to prepare fsgen\n"); -- goto err_fsgen; -- } -- - regcache_cache_only(tx->regmap, false); -- regcache_sync(tx->regmap); -+ ret = regcache_sync(tx->regmap); -+ if (ret) { -+ regcache_cache_only(tx->regmap, true); -+ regcache_mark_dirty(tx->regmap); -+ pm_clk_suspend(dev); -+ return ret; -+ } - - return 0; --err_fsgen: -- clk_disable_unprepare(tx->npl); --err_npl: -- clk_disable_unprepare(tx->mclk); -- -- return ret; - } - - static const struct dev_pm_ops tx_macro_pm_ops = { -diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c ---- a/sound/soc/codecs/lpass-va-macro.c -+++ b/sound/soc/codecs/lpass-va-macro.c -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1351,34 +1352,43 @@ static int fsgen_gate_enable(struct clk_hw *hw) - { - struct va_macro *va = to_va_macro(hw); - struct regmap *regmap = va->regmap; -- int ret; -+ int ret, rpm_ret; - -- if (va->has_swr_master) { -- ret = clk_prepare_enable(va->mclk); -- if (ret) -- return ret; -- } -+ ret = pm_runtime_resume_and_get(va->dev); -+ if (ret < 0) -+ return ret; - - ret = va_macro_mclk_enable(va, true); -+ if (ret) { -+ rpm_ret = pm_runtime_put_autosuspend(va->dev); -+ if (rpm_ret < 0) -+ dev_warn(va->dev, -+ "runtime PM put failed in fsgen enable unwind: %d\n", -+ rpm_ret); -+ return ret; -+ } - if (va->has_swr_master) - regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, - CDC_VA_SWR_CLK_EN_MASK, CDC_VA_SWR_CLK_ENABLE); - -- return ret; -+ return 0; - } - - static void fsgen_gate_disable(struct clk_hw *hw) - { - struct va_macro *va = to_va_macro(hw); - struct regmap *regmap = va->regmap; -+ int ret; - - if (va->has_swr_master) - regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL, - CDC_VA_SWR_CLK_EN_MASK, 0x0); - - va_macro_mclk_enable(va, false); -- if (va->has_swr_master) -- clk_disable_unprepare(va->mclk); -+ -+ ret = pm_runtime_put_autosuspend(va->dev); -+ if (ret < 0) -+ dev_warn(va->dev, "runtime PM put failed in fsgen disable: %d\n", ret); - } - - static int fsgen_gate_is_enabled(struct clk_hw *hw) -@@ -1539,6 +1549,7 @@ static int va_macro_probe(struct platform_device *pdev) - void __iomem *base; - u32 sample_rate = 0; - int ret; -+ int rpm_ret; - - va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL); - if (!va) -@@ -1594,7 +1605,9 @@ static int va_macro_probe(struct platform_device *pdev) - va->has_npl_clk = data->has_npl_clk; - - /* mclk rate */ -- clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); -+ ret = clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ); -+ if (ret) -+ goto err; - - if (va->has_npl_clk) { - va->npl = devm_clk_get(dev, "npl"); -@@ -1603,25 +1616,29 @@ static int va_macro_probe(struct platform_device *pdev) - goto err; - } - -- clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ); -+ ret = clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ); -+ if (ret) -+ goto err; - } - -- ret = clk_prepare_enable(va->macro); -+ ret = devm_pm_clk_create(dev); - if (ret) - goto err; - -- ret = clk_prepare_enable(va->dcodec); -- if (ret) -- goto err_dcodec; -+ ret = of_pm_clk_add_clks(dev); -+ if (ret < 0) -+ goto err; - -- ret = clk_prepare_enable(va->mclk); -+ pm_runtime_set_autosuspend_delay(dev, 100); -+ pm_runtime_use_autosuspend(dev); -+ ret = devm_pm_runtime_enable(dev); - if (ret) -- goto err_mclk; -+ goto err; - -- if (va->has_npl_clk) { -- ret = clk_prepare_enable(va->npl); -- if (ret) -- goto err_npl; -+ rpm_ret = pm_runtime_resume_and_get(dev); -+ if (rpm_ret < 0) { -+ ret = rpm_ret; -+ goto err; - } - - /** -@@ -1634,7 +1651,7 @@ static int va_macro_probe(struct platform_device *pdev) - /* read version from register */ - ret = va_macro_set_lpass_codec_version(va); - if (ret) -- goto err_clkout; -+ goto err_rpm_put; - } - - if (va->has_swr_master) { -@@ -1664,35 +1681,28 @@ static int va_macro_probe(struct platform_device *pdev) - va_macro_dais, - ARRAY_SIZE(va_macro_dais)); - if (ret) -- goto err_clkout; -- -- pm_runtime_set_autosuspend_delay(dev, 3000); -- pm_runtime_use_autosuspend(dev); -- pm_runtime_mark_last_busy(dev); -- pm_runtime_set_active(dev); -- pm_runtime_enable(dev); -+ goto err_rpm_put; - - ret = va_macro_register_fsgen_output(va); - if (ret) -- goto err_clkout; -+ goto err_rpm_put; - - va->fsgen = devm_clk_hw_get_clk(dev, &va->hw, "fsgen"); - if (IS_ERR(va->fsgen)) { - ret = PTR_ERR(va->fsgen); -- goto err_clkout; -+ goto err_rpm_put; - } - -+ rpm_ret = pm_runtime_put_autosuspend(dev); -+ if (rpm_ret < 0) -+ dev_warn(dev, "runtime PM put failed after probe: %d\n", rpm_ret); -+ - return 0; - --err_clkout: -- if (va->has_npl_clk) -- clk_disable_unprepare(va->npl); --err_npl: -- clk_disable_unprepare(va->mclk); --err_mclk: -- clk_disable_unprepare(va->dcodec); --err_dcodec: -- clk_disable_unprepare(va->macro); -+err_rpm_put: -+ rpm_ret = pm_runtime_put_sync_suspend(dev); -+ if (rpm_ret < 0) -+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind: %d\n", rpm_ret); - err: - lpass_macro_pds_exit(va->pds); - -@@ -1703,53 +1713,52 @@ static void va_macro_remove(struct platform_device *pdev) - { - struct va_macro *va = dev_get_drvdata(&pdev->dev); - -- if (va->has_npl_clk) -- clk_disable_unprepare(va->npl); -- -- clk_disable_unprepare(va->mclk); -- clk_disable_unprepare(va->dcodec); -- clk_disable_unprepare(va->macro); -- - lpass_macro_pds_exit(va->pds); - } - - static int va_macro_runtime_suspend(struct device *dev) - { - struct va_macro *va = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(va->regmap, true); -+ -+ ret = pm_clk_suspend(dev); -+ if (ret) { -+ regcache_cache_only(va->regmap, false); -+ return ret; -+ } -+ - regcache_mark_dirty(va->regmap); - -- if (va->has_npl_clk) -- clk_disable_unprepare(va->npl); -- -- clk_disable_unprepare(va->mclk); -- - return 0; - } - - static int va_macro_runtime_resume(struct device *dev) - { - struct va_macro *va = dev_get_drvdata(dev); -- int ret; -+ int ret, sret; - -- ret = clk_prepare_enable(va->mclk); -+ ret = pm_clk_resume(dev); - if (ret) { -- dev_err(va->dev, "unable to prepare mclk\n"); -+ regcache_cache_only(va->regmap, true); -+ regcache_mark_dirty(va->regmap); - return ret; - } - -- if (va->has_npl_clk) { -- ret = clk_prepare_enable(va->npl); -- if (ret) { -- clk_disable_unprepare(va->mclk); -- dev_err(va->dev, "unable to prepare npl\n"); -- return ret; -- } -- } -- - regcache_cache_only(va->regmap, false); -- regcache_sync(va->regmap); -+ -+ ret = regcache_sync(va->regmap); -+ if (ret) { -+ regcache_cache_only(va->regmap, true); -+ regcache_mark_dirty(va->regmap); -+ sret = pm_clk_suspend(dev); -+ if (sret) -+ dev_err(va->dev, -+ "failed to suspend clocks after regcache sync failure: %d\n", -+ sret); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c ---- a/sound/soc/codecs/lpass-wsa-macro.c -+++ b/sound/soc/codecs/lpass-wsa-macro.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -2529,15 +2530,13 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = { - static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) - { - struct regmap *regmap = wsa->regmap; -+ int ret; - - if (enable) { -- int ret; -- -- ret = clk_prepare_enable(wsa->mclk); -- if (ret) { -- dev_err(wsa->dev, "failed to enable mclk\n"); -+ ret = pm_runtime_resume_and_get(wsa->dev); -+ if (ret < 0) - return ret; -- } -+ - wsa_macro_mclk_enable(wsa, true); - - regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, -@@ -2548,7 +2547,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable) - regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, - CDC_WSA_SWR_CLK_EN_MASK, 0); - wsa_macro_mclk_enable(wsa, false); -- clk_disable_unprepare(wsa->mclk); -+ -+ ret = pm_runtime_put_autosuspend(wsa->dev); -+ if (ret < 0) -+ dev_warn(wsa->dev, "runtime PM put failed: %d\n", ret); - } - - return 0; -@@ -2656,7 +2658,7 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa) - init.num_parents = 1; - wsa->hw.init = &init; - hw = &wsa->hw; -- ret = clk_hw_register(wsa->dev, hw); -+ ret = devm_clk_hw_register(wsa->dev, hw); - if (ret) - return ret; - -@@ -2771,28 +2773,31 @@ static int wsa_macro_probe(struct platform_device *pdev) - wsa->dev = dev; - - /* set MCLK and NPL rates */ -- clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); -- clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); -- -- ret = clk_prepare_enable(wsa->macro); -+ ret = clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ); - if (ret) -- goto err; -+ return ret; - -- ret = clk_prepare_enable(wsa->dcodec); -+ ret = clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ); - if (ret) -- goto err_dcodec; -+ return ret; - -- ret = clk_prepare_enable(wsa->mclk); -+ ret = devm_pm_clk_create(dev); - if (ret) -- goto err_mclk; -+ return ret; - -- ret = clk_prepare_enable(wsa->npl); -- if (ret) -- goto err_npl; -+ ret = of_pm_clk_add_clks(dev); -+ if (ret < 0) -+ return ret; - -- ret = clk_prepare_enable(wsa->fsgen); -+ pm_runtime_set_autosuspend_delay(dev, 100); -+ pm_runtime_use_autosuspend(dev); -+ ret = devm_pm_runtime_enable(dev); - if (ret) -- goto err_fsgen; -+ return ret; -+ -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret < 0) -+ return ret; - - /* reset swr ip */ - regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL, -@@ -2809,56 +2814,37 @@ static int wsa_macro_probe(struct platform_device *pdev) - wsa_macro_dai, - ARRAY_SIZE(wsa_macro_dai)); - if (ret) -- goto err_clkout; -- -- pm_runtime_set_autosuspend_delay(dev, 3000); -- pm_runtime_use_autosuspend(dev); -- pm_runtime_mark_last_busy(dev); -- pm_runtime_set_active(dev); -- pm_runtime_enable(dev); -+ goto err_rpm_put; - - ret = wsa_macro_register_mclk_output(wsa); - if (ret) -- goto err_clkout; -+ goto err_rpm_put; -+ -+ ret = pm_runtime_put_autosuspend(dev); -+ if (ret < 0) -+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret); - - return 0; -- --err_clkout: -- clk_disable_unprepare(wsa->fsgen); --err_fsgen: -- clk_disable_unprepare(wsa->npl); --err_npl: -- clk_disable_unprepare(wsa->mclk); --err_mclk: -- clk_disable_unprepare(wsa->dcodec); --err_dcodec: -- clk_disable_unprepare(wsa->macro); --err: -+err_rpm_put: -+ if (pm_runtime_put_sync_suspend(dev) < 0) -+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n"); - return ret; -- --} -- --static void wsa_macro_remove(struct platform_device *pdev) --{ -- struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev); -- -- clk_disable_unprepare(wsa->macro); -- clk_disable_unprepare(wsa->dcodec); -- clk_disable_unprepare(wsa->mclk); -- clk_disable_unprepare(wsa->npl); -- clk_disable_unprepare(wsa->fsgen); - } - - static int wsa_macro_runtime_suspend(struct device *dev) - { - struct wsa_macro *wsa = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(wsa->regmap, true); -- regcache_mark_dirty(wsa->regmap); - -- clk_disable_unprepare(wsa->fsgen); -- clk_disable_unprepare(wsa->npl); -- clk_disable_unprepare(wsa->mclk); -+ ret = pm_clk_suspend(dev); -+ if (ret) { -+ regcache_cache_only(wsa->regmap, false); -+ return ret; -+ } -+ -+ regcache_mark_dirty(wsa->regmap); - - return 0; - } -@@ -2866,36 +2852,29 @@ static int wsa_macro_runtime_suspend(struct device *dev) - static int wsa_macro_runtime_resume(struct device *dev) - { - struct wsa_macro *wsa = dev_get_drvdata(dev); -- int ret; -+ int ret, sret; - -- ret = clk_prepare_enable(wsa->mclk); -+ ret = pm_clk_resume(dev); - if (ret) { -- dev_err(dev, "unable to prepare mclk\n"); -+ regcache_cache_only(wsa->regmap, true); -+ regcache_mark_dirty(wsa->regmap); -+ return ret; -+ } -+ regcache_cache_only(wsa->regmap, false); -+ -+ ret = regcache_sync(wsa->regmap); -+ if (ret) { -+ regcache_cache_only(wsa->regmap, true); -+ regcache_mark_dirty(wsa->regmap); -+ sret = pm_clk_suspend(dev); -+ if (sret) -+ dev_err(dev, -+ "failed to suspend clocks after regcache sync failure: %d\n", -+ sret); - return ret; - } - -- ret = clk_prepare_enable(wsa->npl); -- if (ret) { -- dev_err(dev, "unable to prepare mclkx2\n"); -- goto err_npl; -- } -- -- ret = clk_prepare_enable(wsa->fsgen); -- if (ret) { -- dev_err(dev, "unable to prepare fsgen\n"); -- goto err_fsgen; -- } -- -- regcache_cache_only(wsa->regmap, false); -- regcache_sync(wsa->regmap); -- - return 0; --err_fsgen: -- clk_disable_unprepare(wsa->npl); --err_npl: -- clk_disable_unprepare(wsa->mclk); -- -- return ret; - } - - static const struct dev_pm_ops wsa_macro_pm_ops = { -@@ -2929,7 +2908,6 @@ static struct platform_driver wsa_macro_driver = { - .pm = pm_ptr(&wsa_macro_pm_ops), - }, - .probe = wsa_macro_probe, -- .remove = wsa_macro_remove, - }; - - module_platform_driver(wsa_macro_driver); -diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c ---- a/sound/soc/codecs/madera.c -+++ b/sound/soc/codecs/madera.c -@@ -6,6 +6,7 @@ - // Cirrus Logic International Semiconductor Ltd. - // - -+#include - #include - #include - #include -@@ -513,7 +514,7 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w, - * We can't rely on the DAPM mutex for locking because we need a lock - * that can safely be called in hw_params - */ -- mutex_lock(&priv->rate_lock); -+ guard(mutex)(&priv->rate_lock); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: -@@ -532,8 +533,6 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w, - - madera_debug_dump_domain_groups(priv); - -- mutex_unlock(&priv->rate_lock); -- - return 0; - } - EXPORT_SYMBOL_GPL(madera_domain_clk_ev); -@@ -875,9 +874,8 @@ static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol, - const int adsp_num = e->shift_l; - int item; - -- mutex_lock(&priv->rate_lock); -- cached_rate = priv->adsp_rate_cache[adsp_num]; -- mutex_unlock(&priv->rate_lock); -+ scoped_guard(mutex, &priv->rate_lock) -+ cached_rate = priv->adsp_rate_cache[adsp_num]; - - item = snd_soc_enum_val_to_item(e, cached_rate); - ucontrol->value.enumerated.item[0] = item; -@@ -893,7 +891,6 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - const int adsp_num = e->shift_l; - const unsigned int item = ucontrol->value.enumerated.item[0]; -- int ret = 0; - - if (item >= e->items) - return -EINVAL; -@@ -903,22 +900,20 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol, - * maintain consistent behaviour that rate domains cannot be changed - * while in use since this is a hardware requirement - */ -- mutex_lock(&priv->rate_lock); -+ guard(mutex)(&priv->rate_lock); - - if (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].cs_dsp.base)) { - dev_warn(priv->madera->dev, - "Cannot change '%s' while in use by active audio paths\n", - kcontrol->id.name); -- ret = -EBUSY; -+ return -EBUSY; - } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) { - /* Volatile register so defer until the codec is powered up */ - priv->adsp_rate_cache[adsp_num] = e->values[item]; -- ret = 1; -+ return 1; - } - -- mutex_unlock(&priv->rate_lock); -- -- return ret; -+ return 0; - } - - static const struct soc_enum madera_adsp_rate_enum[] = { -@@ -1061,15 +1056,13 @@ int madera_rate_put(struct snd_kcontrol *kcontrol, - * Prevent the domain powering up while we're checking whether it's - * safe to change rate domain - */ -- mutex_lock(&priv->rate_lock); -+ guard(mutex)(&priv->rate_lock); - - val = snd_soc_component_read(component, e->reg); - val >>= e->shift_l; - val &= e->mask; -- if (snd_soc_enum_item_to_val(e, item) == val) { -- ret = 0; -- goto out; -- } -+ if (snd_soc_enum_item_to_val(e, item) == val) -+ return 0; - - if (!madera_can_change_grp_rate(priv, e->reg)) { - dev_warn(priv->madera->dev, -@@ -1082,8 +1075,6 @@ int madera_rate_put(struct snd_kcontrol *kcontrol, - ret = snd_soc_put_enum_double(kcontrol, ucontrol); - madera_spin_sysclk(priv); - } --out: -- mutex_unlock(&priv->rate_lock); - - return ret; - } -@@ -3041,12 +3032,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream, - if ((cur & MADERA_AIF1_RATE_MASK) == (tar & MADERA_AIF1_RATE_MASK)) - return 0; - -- mutex_lock(&priv->rate_lock); -+ guard(mutex)(&priv->rate_lock); - - if (!madera_can_change_grp_rate(priv, base + MADERA_AIF_RATE_CTRL)) { - madera_aif_warn(dai, "Cannot change rate while active\n"); -- ret = -EBUSY; -- goto out; -+ return -EBUSY; - } - - /* Guard the rate change with SYSCLK cycles */ -@@ -3055,9 +3045,6 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream, - MADERA_AIF1_RATE_MASK, tar); - madera_spin_sysclk(priv); - --out: -- mutex_unlock(&priv->rate_lock); -- - return ret; - } - -@@ -3345,6 +3332,16 @@ static int madera_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, - return 0; - } - -+static const u64 madera_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_B | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_NB_IF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_NF | -+ SND_SOC_POSSIBLE_DAIFMT_IB_IF; -+ - const struct snd_soc_dai_ops madera_dai_ops = { - .startup = &madera_startup, - .set_fmt = &madera_set_fmt, -@@ -3352,6 +3349,8 @@ const struct snd_soc_dai_ops madera_dai_ops = { - .hw_params = &madera_hw_params, - .set_sysclk = &madera_dai_set_sysclk, - .set_tristate = &madera_set_tristate, -+ .auto_selectable_formats = &madera_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - EXPORT_SYMBOL_GPL(madera_dai_ops); - -diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c ---- a/sound/soc/codecs/max98090.c -+++ b/sound/soc/codecs/max98090.c -@@ -2341,6 +2341,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data) - * - * @component: MAX98090 component - * @jack: jack to report detection events on -+ * @data: can be used if codec driver need extra data for configuring jack - * - * Enable microphone detection via IRQ on the MAX98090. If GPIOs are - * being used to bring out signals to the processor then only platform -@@ -2646,12 +2647,18 @@ static void max98090_i2c_remove(struct i2c_client *client) - static int max98090_runtime_resume(struct device *dev) - { - struct max98090_priv *max98090 = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(max98090->regmap, false); - - max98090_reset(max98090); - -- regcache_sync(max98090->regmap); -+ ret = regcache_sync(max98090->regmap); -+ if (ret < 0) { -+ regcache_cache_only(max98090->regmap, true); -+ regcache_mark_dirty(max98090->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c ---- a/sound/soc/codecs/max98095.c -+++ b/sound/soc/codecs/max98095.c -@@ -5,6 +5,7 @@ - * Copyright 2011 Maxim Integrated Products - */ - -+#include - #include - #include - #include -@@ -1532,15 +1533,17 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, - regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL); - snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0); - -- mutex_lock(&max98095->lock); -- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); -- m98095_eq_band(component, channel, 0, coef_set->band1); -- m98095_eq_band(component, channel, 1, coef_set->band2); -- m98095_eq_band(component, channel, 2, coef_set->band3); -- m98095_eq_band(component, channel, 3, coef_set->band4); -- m98095_eq_band(component, channel, 4, coef_set->band5); -- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0); -- mutex_unlock(&max98095->lock); -+ scoped_guard(mutex, &max98095->lock) { -+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, -+ M98095_SEG, M98095_SEG); -+ m98095_eq_band(component, channel, 0, coef_set->band1); -+ m98095_eq_band(component, channel, 1, coef_set->band2); -+ m98095_eq_band(component, channel, 2, coef_set->band3); -+ m98095_eq_band(component, channel, 3, coef_set->band4); -+ m98095_eq_band(component, channel, 4, coef_set->band5); -+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, -+ M98095_SEG, 0); -+ } - - /* Restore the original on/off state */ - snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave); -@@ -1683,12 +1686,14 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, - regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL); - snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0); - -- mutex_lock(&max98095->lock); -- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); -- m98095_biquad_band(component, channel, 0, coef_set->band1); -- m98095_biquad_band(component, channel, 1, coef_set->band2); -- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0); -- mutex_unlock(&max98095->lock); -+ scoped_guard(mutex, &max98095->lock) { -+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, -+ M98095_SEG, M98095_SEG); -+ m98095_biquad_band(component, channel, 0, coef_set->band1); -+ m98095_biquad_band(component, channel, 1, coef_set->band2); -+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, -+ M98095_SEG, 0); -+ } - - /* Restore the original on/off state */ - snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave); -diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c ---- a/sound/soc/codecs/max98363.c -+++ b/sound/soc/codecs/max98363.c -@@ -100,7 +100,12 @@ static int max98363_resume(struct device *dev) - return ret; - - regcache_cache_only(max98363->regmap, false); -- regcache_sync(max98363->regmap); -+ ret = regcache_sync(max98363->regmap); -+ if (ret) { -+ regcache_cache_only(max98363->regmap, true); -+ regcache_mark_dirty(max98363->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c ---- a/sound/soc/codecs/max98373-i2c.c -+++ b/sound/soc/codecs/max98373-i2c.c -@@ -488,10 +488,17 @@ static int max98373_suspend(struct device *dev) - static int max98373_resume(struct device *dev) - { - struct max98373_priv *max98373 = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(max98373->regmap, false); - max98373_reset(max98373, dev); -- regcache_sync(max98373->regmap); -+ ret = regcache_sync(max98373->regmap); -+ if (ret) { -+ regcache_cache_only(max98373->regmap, true); -+ regcache_mark_dirty(max98373->regmap); -+ return ret; -+ } -+ - return 0; - } - -diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c ---- a/sound/soc/codecs/max98373-sdw.c -+++ b/sound/soc/codecs/max98373-sdw.c -@@ -277,7 +277,12 @@ static int max98373_resume(struct device *dev) - } - - regcache_cache_only(max98373->regmap, false); -- regcache_sync(max98373->regmap); -+ ret = regcache_sync(max98373->regmap); -+ if (ret) { -+ regcache_cache_only(max98373->regmap, true); -+ regcache_mark_dirty(max98373->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c ---- a/sound/soc/codecs/max98388.c -+++ b/sound/soc/codecs/max98388.c -@@ -863,10 +863,16 @@ static int max98388_suspend(struct device *dev) - static int max98388_resume(struct device *dev) - { - struct max98388_priv *max98388 = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(max98388->regmap, false); - max98388_reset(max98388, dev); -- regcache_sync(max98388->regmap); -+ ret = regcache_sync(max98388->regmap); -+ if (ret) { -+ regcache_cache_only(max98388->regmap, true); -+ regcache_mark_dirty(max98388->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c ---- a/sound/soc/codecs/max98390.c -+++ b/sound/soc/codecs/max98390.c -@@ -788,7 +788,6 @@ static int max98390_dsm_init(struct snd_soc_component *component) - const char *vendor, *product; - struct max98390_priv *max98390 = - snd_soc_component_get_drvdata(component); -- const struct firmware *fw; - char *dsm_param; - - vendor = dmi_get_system_info(DMI_SYS_VENDOR); -@@ -805,6 +804,8 @@ static int max98390_dsm_init(struct snd_soc_component *component) - snprintf(filename, sizeof(filename), "%s", - max98390->dsm_param_name); - } -+ -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, filename, component->dev); - if (ret) { - ret = request_firmware(&fw, "dsm_param.bin", component->dev); -@@ -812,7 +813,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) - ret = request_firmware(&fw, "dsmparam.bin", - component->dev); - if (ret) -- goto err; -+ return ret; - } - } - -@@ -822,8 +823,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) - if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) { - dev_err(component->dev, - "param fw is invalid.\n"); -- ret = -EINVAL; -- goto err_alloc; -+ return -EINVAL; - } - dsm_param = (char *)fw->data; - param_start_addr = (dsm_param[0] & 0xff) | (dsm_param[1] & 0xff) << 8; -@@ -833,8 +833,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) - fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) { - dev_err(component->dev, - "param fw is invalid.\n"); -- ret = -EINVAL; -- goto err_alloc; -+ return -EINVAL; - } - regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); - dsm_param += MAX98390_DSM_PAYLOAD_OFFSET; -@@ -842,10 +841,7 @@ static int max98390_dsm_init(struct snd_soc_component *component) - dsm_param, param_size); - regmap_write(max98390->regmap, MAX98390_R23E1_DSP_GLOBAL_EN, 0x01); - --err_alloc: -- release_firmware(fw); --err: -- return ret; -+ return 0; - } - - static void max98390_init_regs(struct snd_soc_component *component) -@@ -952,11 +948,17 @@ static int max98390_suspend(struct device *dev) - static int max98390_resume(struct device *dev) - { - struct max98390_priv *max98390 = dev_get_drvdata(dev); -+ int ret; - - dev_dbg(dev, "%s:Enter\n", __func__); - - regcache_cache_only(max98390->regmap, false); -- regcache_sync(max98390->regmap); -+ ret = regcache_sync(max98390->regmap); -+ if (ret) { -+ regcache_cache_only(max98390->regmap, true); -+ regcache_mark_dirty(max98390->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c ---- a/sound/soc/codecs/max98396.c -+++ b/sound/soc/codecs/max98396.c -@@ -1600,19 +1600,37 @@ static int max98396_resume(struct device *dev) - if (max98396->pvdd) { - ret = regulator_enable(max98396->pvdd); - if (ret < 0) -- return ret; -+ goto err_core_supplies; - } - - if (max98396->vbat) { - ret = regulator_enable(max98396->vbat); - if (ret < 0) -- return ret; -+ goto err_pvdd; - } - - regcache_cache_only(max98396->regmap, false); - max98396_reset(max98396, dev); -- regcache_sync(max98396->regmap); -+ ret = regcache_sync(max98396->regmap); -+ if (ret < 0) { -+ regcache_cache_only(max98396->regmap, true); -+ regcache_mark_dirty(max98396->regmap); -+ goto err_vbat; -+ } -+ - return 0; -+ -+err_vbat: -+ if (max98396->vbat) -+ regulator_disable(max98396->vbat); -+err_pvdd: -+ if (max98396->pvdd) -+ regulator_disable(max98396->pvdd); -+err_core_supplies: -+ regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES, -+ max98396->core_supplies); -+ -+ return ret; - } - - static const struct dev_pm_ops max98396_pm = { -diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c ---- a/sound/soc/codecs/max98927.c -+++ b/sound/soc/codecs/max98927.c -@@ -742,11 +742,17 @@ static int max98927_suspend(struct device *dev) - static int max98927_resume(struct device *dev) - { - struct max98927_priv *max98927 = dev_get_drvdata(dev); -+ int ret; - - regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET, - MAX98927_SOFT_RESET); - regcache_cache_only(max98927->regmap, false); -- regcache_sync(max98927->regmap); -+ ret = regcache_sync(max98927->regmap); -+ if (ret) { -+ regcache_cache_only(max98927->regmap, true); -+ regcache_mark_dirty(max98927->regmap); -+ return ret; -+ } - return 0; - } - -diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c ---- a/sound/soc/codecs/msm8916-wcd-analog.c -+++ b/sound/soc/codecs/msm8916-wcd-analog.c -@@ -217,9 +217,11 @@ - #define CDC_A_RX_HPH_BIAS_LDO_OCP (0xf195) - #define CDC_A_RX_HPH_BIAS_CNP (0xf196) - #define CDC_A_RX_HPH_CNP_EN (0xf197) -+#define CDC_A_RX_HPH_L_TEST (0xf19A) - #define CDC_A_RX_HPH_L_PA_DAC_CTL (0xf19B) - #define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK BIT(1) - #define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET BIT(1) -+#define CDC_A_RX_HPH_R_TEST (0xf19C) - #define CDC_A_RX_HPH_R_PA_DAC_CTL (0xf19D) - #define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1) - #define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1) -@@ -232,6 +234,8 @@ - #define RX_EAR_CTL_PA_SEL_MASK BIT(7) - #define RX_EAR_CTL_PA_SEL BIT(7) - -+#define CDC_A_RX_EAR_STATUS (0xf1A1) -+ - #define CDC_A_SPKR_DAC_CTL (0xf1B0) - #define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4) - #define SPKR_DAC_CTL_DAC_RESET_NORMAL 0 -@@ -250,6 +254,7 @@ - SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \ - SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \ - SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET) -+#define CDC_A_SPKR_ANA_BIAS_SET (0xf1B3) - #define CDC_A_SPKR_OCP_CTL (0xf1B4) - #define CDC_A_SPKR_PWRSTG_CTL (0xf1B5) - #define SPKR_PWRSTG_CTL_DAC_EN_MASK BIT(0) -@@ -264,6 +269,7 @@ - - #define CDC_A_SPKR_DRV_DBG (0xf1B7) - #define CDC_A_CURRENT_LIMIT (0xf1C0) -+#define CDC_A_BYPASS_MODE (0xf1C2) - #define CDC_A_BOOST_EN_CTL (0xf1C3) - #define CDC_A_SLOPE_COMP_IP_ZERO (0xf1C4) - #define CDC_A_SEC_ACCESS (0xf1D0) -@@ -286,6 +292,11 @@ static const char * const supply_names[] = { - - #define MBHC_MAX_BUTTONS (5) - -+struct wcd_reg_seq { -+ const struct reg_default *seq; -+ int seq_size; -+}; -+ - struct pm8916_wcd_analog_priv { - u16 pmic_rev; - u16 codec_version; -@@ -696,6 +707,59 @@ static int pm8916_wcd_analog_enable_ear_pa(struct snd_soc_dapm_widget *w, - return 0; - } - -+static int pm8916_wcd_analog_enable_hphl_pa(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, -+ int event) -+{ -+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); -+ struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); -+ -+ /* This quirk is not required for revisions prior to CAJON_2_0 */ -+ if (priv->codec_version < 4) -+ return 0; -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ usleep_range(7000, 7100); -+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST, -+ 0x04, 0x04); -+ break; -+ case SND_SOC_DAPM_POST_PMD: -+ /* wait 20 ms after the digital codec has powered down */ -+ msleep(20); -+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST, -+ 0x04, 0x00); -+ break; -+ } -+ return 0; -+} -+ -+static int pm8916_wcd_analog_enable_hphr_pa(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, -+ int event) -+{ -+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); -+ struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); -+ -+ /* This quirk is not required for revisions prior to CAJON_2_0 */ -+ if (priv->codec_version < 4) -+ return 0; -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ usleep_range(7000, 7100); -+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST, -+ 0x04, 0x04); -+ break; -+ case SND_SOC_DAPM_POST_PMD: -+ msleep(20); -+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST, -+ 0x04, 0x00); -+ break; -+ } -+ return 0; -+} -+ - static const struct reg_default wcd_reg_defaults_2_0[] = { - {CDC_A_RX_COM_OCP_CTL, 0xD1}, - {CDC_A_RX_COM_OCP_COUNT, 0xFF}, -@@ -715,9 +779,69 @@ static const struct reg_default wcd_reg_defaults_2_0[] = { - {CDC_A_MASTER_BIAS_CTL, 0x30}, - }; - -+static const struct wcd_reg_seq pm8916_data = { -+ .seq = wcd_reg_defaults_2_0, -+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_2_0), -+}; -+ -+static const struct reg_default wcd_reg_defaults_pm8950[] = { -+ {CDC_A_RX_COM_OCP_CTL, 0xd1}, -+ {CDC_A_RX_COM_OCP_COUNT, 0xff}, -+ {CDC_D_SEC_ACCESS, 0xa5}, -+ {CDC_D_PERPH_RESET_CTL3, 0x0f}, -+ {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c}, -+ {CDC_A_NCP_FBCTRL, 0xa8}, -+ {CDC_A_NCP_VCTRL, 0xa4}, -+ {CDC_A_SPKR_DRV_CTL, 0x69}, -+ {CDC_A_SPKR_DRV_DBG, 0x01}, -+ {CDC_A_SEC_ACCESS, 0xa5}, -+ {CDC_A_PERPH_RESET_CTL3, 0x0f}, -+ {CDC_A_CURRENT_LIMIT, 0x82}, -+ {CDC_A_SPKR_ANA_BIAS_SET, 0x41}, -+ {CDC_A_SPKR_DAC_CTL, 0x03}, -+ {CDC_A_SPKR_OCP_CTL, 0xe1}, -+ {CDC_A_RX_HPH_BIAS_PA, 0xfa}, -+ {CDC_A_MASTER_BIAS_CTL, 0x30}, -+ {CDC_A_MICB_1_INT_RBIAS, 0x00}, -+}; -+ -+static const struct wcd_reg_seq pm8950_data = { -+ .seq = wcd_reg_defaults_pm8950, -+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8950), -+}; -+ -+static const struct reg_default wcd_reg_defaults_pm8953[] = { -+ {CDC_A_RX_COM_OCP_CTL, 0xd1}, -+ {CDC_A_RX_COM_OCP_COUNT, 0xff}, -+ {CDC_D_SEC_ACCESS, 0xa5}, -+ {CDC_D_PERPH_RESET_CTL3, 0x0f}, -+ {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c}, -+ {CDC_A_NCP_FBCTRL, 0xa8}, -+ {CDC_A_NCP_VCTRL, 0xa4}, -+ {CDC_A_SPKR_DRV_CTL, 0x69}, -+ {CDC_A_SPKR_DRV_DBG, 0x01}, -+ {CDC_A_SEC_ACCESS, 0xa5}, -+ {CDC_A_PERPH_RESET_CTL3, 0x0f}, -+ {CDC_A_CURRENT_LIMIT, 0xa2}, -+ {CDC_A_BYPASS_MODE, 0x18}, -+ {CDC_A_SPKR_ANA_BIAS_SET, 0x41}, -+ {CDC_A_SPKR_DAC_CTL, 0x03}, -+ {CDC_A_SPKR_OCP_CTL, 0xe1}, -+ {CDC_A_RX_HPH_BIAS_PA, 0xfa}, -+ {CDC_A_RX_EAR_STATUS, 0x10}, -+ {CDC_A_MASTER_BIAS_CTL, 0x30}, -+ {CDC_A_MICB_1_INT_RBIAS, 0x00}, -+}; -+ -+static const struct wcd_reg_seq pm8953_data = { -+ .seq = wcd_reg_defaults_pm8953, -+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8953), -+}; -+ - static int pm8916_wcd_analog_probe(struct snd_soc_component *component) - { - struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev); -+ const struct wcd_reg_seq *wcd_reg_init_data; - int err, reg; - - err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); -@@ -738,9 +862,11 @@ static int pm8916_wcd_analog_probe(struct snd_soc_component *component) - snd_soc_component_write(component, CDC_D_PERPH_RESET_CTL4, 0x01); - snd_soc_component_write(component, CDC_A_PERPH_RESET_CTL4, 0x01); - -- for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++) -- snd_soc_component_write(component, wcd_reg_defaults_2_0[reg].reg, -- wcd_reg_defaults_2_0[reg].def); -+ wcd_reg_init_data = of_device_get_match_data(component->dev); -+ -+ for (reg = 0; reg < wcd_reg_init_data->seq_size; reg++) -+ snd_soc_component_write(component, wcd_reg_init_data->seq[reg].reg, -+ wcd_reg_init_data->seq[reg].def); - - priv->component = component; - -@@ -883,11 +1009,15 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { - SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, &ear_mux), - SND_SOC_DAPM_SUPPLY("EAR CP", CDC_A_NCP_EN, 4, 0, NULL, 0), - -- SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0), -+ SND_SOC_DAPM_PGA_E("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0, -+ pm8916_wcd_analog_enable_hphl_pa, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux), - SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL, - 0), -- SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0), -+ SND_SOC_DAPM_PGA_E("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0, -+ pm8916_wcd_analog_enable_hphr_pa, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux), - SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL, - 0), -@@ -1259,7 +1389,9 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) - } - - static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { -- { .compatible = "qcom,pm8916-wcd-analog-codec", }, -+ { .compatible = "qcom,pm8916-wcd-analog-codec", .data = &pm8916_data }, -+ { .compatible = "qcom,pm8950-wcd-analog-codec", .data = &pm8950_data }, -+ { .compatible = "qcom,pm8953-wcd-analog-codec", .data = &pm8953_data }, - { } - }; - -diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c ---- a/sound/soc/codecs/mt6357.c -+++ b/sound/soc/codecs/mt6357.c -@@ -1834,8 +1834,8 @@ static int mt6357_platform_driver_probe(struct platform_device *pdev) - } - - static const struct platform_device_id mt6357_platform_ids[] = { -- {"mt6357-sound", 0}, -- { /* sentinel */ }, -+ { .name = "mt6357-sound" }, -+ { /* sentinel */ } - }; - MODULE_DEVICE_TABLE(platform, mt6357_platform_ids); - -diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c ---- a/sound/soc/codecs/mt6359-accdet.c -+++ b/sound/soc/codecs/mt6359-accdet.c -@@ -6,6 +6,7 @@ - // Author: Argus Lin - // - -+#include - #include - #include - #include -@@ -398,14 +399,13 @@ static void mt6359_accdet_work(struct work_struct *work) - struct mt6359_accdet *priv = - container_of(work, struct mt6359_accdet, accdet_work); - -- mutex_lock(&priv->res_lock); -+ guard(mutex)(&priv->res_lock); - priv->pre_accdet_status = priv->accdet_status; - check_jack_btn_type(priv); - - if (priv->jack_plugged && - priv->pre_accdet_status != priv->accdet_status) - mt6359_accdet_jack_report(priv); -- mutex_unlock(&priv->res_lock); - } - - static void mt6359_accdet_jd_work(struct work_struct *work) -@@ -416,7 +416,7 @@ static void mt6359_accdet_jd_work(struct work_struct *work) - struct mt6359_accdet *priv = - container_of(work, struct mt6359_accdet, jd_work); - -- mutex_lock(&priv->res_lock); -+ guard(mutex)(&priv->res_lock); - if (priv->jd_sts == M_PLUG_IN) { - priv->jack_plugged = true; - -@@ -450,7 +450,6 @@ static void mt6359_accdet_jd_work(struct work_struct *work) - - if (priv->caps & ACCDET_PMIC_EINT_IRQ) - recover_eint_setting(priv); -- mutex_unlock(&priv->res_lock); - } - - static irqreturn_t mt6359_accdet_irq(int irq, void *data) -@@ -459,7 +458,7 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) - unsigned int irq_val = 0, val = 0, value = 0; - int ret; - -- mutex_lock(&priv->res_lock); -+ guard(mutex)(&priv->res_lock); - regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val); - - if (irq_val & ACCDET_IRQ_MASK_SFT) { -@@ -474,7 +473,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) - 1000); - if (ret) { - dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); -- mutex_unlock(&priv->res_lock); - return IRQ_NONE; - } - regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, -@@ -498,7 +496,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) - if (ret) { - dev_err(priv->dev, "%s(), ret %d\n", __func__, - ret); -- mutex_unlock(&priv->res_lock); - return IRQ_NONE; - } - regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, -@@ -521,7 +518,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) - if (ret) { - dev_err(priv->dev, "%s(), ret %d\n", __func__, - ret); -- mutex_unlock(&priv->res_lock); - return IRQ_NONE; - } - regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, -@@ -540,7 +536,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data) - - queue_work(priv->jd_workqueue, &priv->jd_work); - } -- mutex_unlock(&priv->res_lock); - - return IRQ_HANDLED; - } -diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c ---- a/sound/soc/codecs/ntpfw.c -+++ b/sound/soc/codecs/ntpfw.c -@@ -89,7 +89,7 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) - { - struct device *dev = &i2c->dev; - const struct ntpfw_chunk *chunk; -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - const u8 *data; - size_t leftover; - int ret; -@@ -101,10 +101,8 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) - return ret; - } - -- if (!ntpfw_verify(dev, fw->data, fw->size, magic)) { -- ret = -EINVAL; -- goto done; -- } -+ if (!ntpfw_verify(dev, fw->data, fw->size, magic)) -+ return -EINVAL; - - data = fw->data + sizeof(struct ntpfw_header); - leftover = fw->size - sizeof(struct ntpfw_header); -@@ -112,23 +110,18 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) - while (leftover) { - chunk = (struct ntpfw_chunk *)data; - -- if (!ntpfw_verify_chunk(dev, chunk, leftover)) { -- ret = -EINVAL; -- goto done; -- } -+ if (!ntpfw_verify_chunk(dev, chunk, leftover)) -+ return -EINVAL; - - ret = ntpfw_send_chunk(i2c, chunk); - if (ret) -- goto done; -+ return ret; - - data += be16_to_cpu(chunk->length) + sizeof(*chunk); - leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk); - } - --done: -- release_firmware(fw); -- -- return ret; -+ return 0; - } - EXPORT_SYMBOL_GPL(ntpfw_load); - -diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h ---- a/sound/soc/codecs/ntpfw.h -+++ b/sound/soc/codecs/ntpfw.h -@@ -1,5 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-only */ --/** -+/* - * ntpfw.h - Firmware helper functions for Neofidelity codecs - * - * Copyright (c) 2024, SaluteDevices. All Rights Reserved. -@@ -13,10 +13,11 @@ - /** - * ntpfw_load - load firmware to amplifier over i2c interface. - * -- * @i2c Pointer to amplifier's I2C client. -- * @name Firmware file name. -- * @magic Magic number to validate firmware. -- * @return 0 or error code upon error. -+ * @i2c: Pointer to amplifier's I2C client. -+ * @name: Firmware file name. -+ * @magic: Magic number to validate firmware. -+ * -+ * Returns: 0 or error code upon error. - */ - int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic); - -diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c ---- a/sound/soc/codecs/pcm1681.c -+++ b/sound/soc/codecs/pcm1681.c -@@ -199,10 +199,17 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream, - return pcm1681_set_deemph(component); - } - -+static const u64 pcm1681_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J; -+ - static const struct snd_soc_dai_ops pcm1681_dai_ops = { - .set_fmt = pcm1681_set_dai_fmt, - .hw_params = pcm1681_hw_params, - .mute_stream = pcm1681_mute, -+ .auto_selectable_formats = &pcm1681_selectable_formats, -+ .num_auto_selectable_formats = 1, - .no_capture_mute = 1, - }; - -diff --git a/sound/soc/codecs/pcm1754.c b/sound/soc/codecs/pcm1754.c ---- a/sound/soc/codecs/pcm1754.c -+++ b/sound/soc/codecs/pcm1754.c -@@ -78,10 +78,16 @@ static int pcm1754_mute_stream(struct snd_soc_dai *dai, int mute, int stream) - return 0; - } - -+static const u64 pcm1754_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J; -+ - static const struct snd_soc_dai_ops pcm1754_dai_ops = { - .set_fmt = pcm1754_set_dai_fmt, - .hw_params = pcm1754_hw_params, - .mute_stream = pcm1754_mute_stream, -+ .auto_selectable_formats = &pcm1754_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static const struct snd_soc_dai_driver pcm1754_dai = { -diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c ---- a/sound/soc/codecs/pcm1789.c -+++ b/sound/soc/codecs/pcm1789.c -@@ -164,11 +164,18 @@ static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd, - return ret; - } - -+static const u64 pcm1789_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J; -+ - static const struct snd_soc_dai_ops pcm1789_dai_ops = { - .set_fmt = pcm1789_set_dai_fmt, - .hw_params = pcm1789_hw_params, - .mute_stream = pcm1789_mute, - .trigger = pcm1789_trigger, -+ .auto_selectable_formats = &pcm1789_selectable_formats, -+ .num_auto_selectable_formats = 1, - .no_capture_mute = 1, - }; - -diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c ---- a/sound/soc/codecs/pcm179x.c -+++ b/sound/soc/codecs/pcm179x.c -@@ -142,10 +142,16 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream, - return 0; - } - -+static const u64 pcm179x_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J; -+ - static const struct snd_soc_dai_ops pcm179x_dai_ops = { - .set_fmt = pcm179x_set_dai_fmt, - .hw_params = pcm179x_hw_params, - .mute_stream = pcm179x_mute, -+ .auto_selectable_formats = &pcm179x_selectable_formats, -+ .num_auto_selectable_formats = 1, - .no_capture_mute = 1, - }; - -diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c ---- a/sound/soc/codecs/pcm186x.c -+++ b/sound/soc/codecs/pcm186x.c -@@ -473,11 +473,20 @@ static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, - return 0; - } - -+static const u64 pcm186x_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_B | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF; -+ - static const struct snd_soc_dai_ops pcm186x_dai_ops = { - .set_sysclk = pcm186x_set_dai_sysclk, - .set_tdm_slot = pcm186x_set_tdm_slot, - .set_fmt = pcm186x_set_fmt, - .hw_params = pcm186x_hw_params, -+ .auto_selectable_formats = &pcm186x_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver pcm1863_dai = { -diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c ---- a/sound/soc/codecs/pcm3060.c -+++ b/sound/soc/codecs/pcm3060.c -@@ -164,10 +164,18 @@ static int pcm3060_hw_params(struct snd_pcm_substream *substream, - return 0; - } - -+static const u64 pcm3060_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_NB_NF; -+ - static const struct snd_soc_dai_ops pcm3060_dai_ops = { - .set_sysclk = pcm3060_set_sysclk, - .set_fmt = pcm3060_set_fmt, - .hw_params = pcm3060_hw_params, -+ .auto_selectable_formats = &pcm3060_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - #define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \ -diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c ---- a/sound/soc/codecs/pcm512x.c -+++ b/sound/soc/codecs/pcm512x.c -@@ -6,7 +6,7 @@ - * Copyright 2014 Linaro Ltd - */ - -- -+#include - #include - #include - #include -@@ -399,10 +399,9 @@ static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); - -- mutex_lock(&pcm512x->mutex); -+ guard(mutex)(&pcm512x->mutex); - ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); - ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); -- mutex_unlock(&pcm512x->mutex); - - return 0; - } -@@ -414,7 +413,7 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, - struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); - int ret, changed = 0; - -- mutex_lock(&pcm512x->mutex); -+ guard(mutex)(&pcm512x->mutex); - - if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { - pcm512x->mute ^= 0x4; -@@ -430,13 +429,10 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, - if (ret != 0) { - dev_err(component->dev, - "Failed to update digital mute: %d\n", ret); -- mutex_unlock(&pcm512x->mutex); - return ret; - } - } - -- mutex_unlock(&pcm512x->mutex); -- - return changed; - } - -@@ -1465,7 +1461,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) - int ret; - unsigned int mute_det; - -- mutex_lock(&pcm512x->mutex); -+ guard(mutex)(&pcm512x->mutex); - - if (mute) { - pcm512x->mute |= 0x1; -@@ -1475,7 +1471,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) - if (ret != 0) { - dev_err(component->dev, - "Failed to set digital mute: %d\n", ret); -- goto unlock; -+ return ret; - } - - regmap_read_poll_timeout(pcm512x->regmap, -@@ -1488,7 +1484,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) - if (ret != 0) { - dev_err(component->dev, - "Failed to update digital mute: %d\n", ret); -- goto unlock; -+ return ret; - } - - regmap_read_poll_timeout(pcm512x->regmap, -@@ -1499,18 +1495,24 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction) - 200, 10000); - } - --unlock: -- mutex_unlock(&pcm512x->mutex); -- - return ret; - } - -+static const u64 pcm512x_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_B; -+ - static const struct snd_soc_dai_ops pcm512x_dai_ops = { - .startup = pcm512x_dai_startup, - .hw_params = pcm512x_hw_params, - .set_fmt = pcm512x_set_fmt, - .mute_stream = pcm512x_mute, - .set_bclk_ratio = pcm512x_set_bclk_ratio, -+ .auto_selectable_formats = &pcm512x_selectable_formats, -+ .num_auto_selectable_formats = 1, - .no_capture_mute = 1, - }; - -diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c ---- a/sound/soc/codecs/pcm6240.c -+++ b/sound/soc/codecs/pcm6240.c -@@ -12,6 +12,7 @@ - // Author: Shenghao Ding - // - -+#include - #include - #include - #include -@@ -605,7 +606,7 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, - unsigned int reg = mc->reg; - unsigned int val; - -- mutex_lock(&pcm_dev->codec_lock); -+ guard(mutex)(&pcm_dev->codec_lock); - - if (pcm_dev->chip_id == PCM1690) { - ret = pcmdev_dev_read(pcm_dev, dev_no, PCM1690_REG_MODE_CTRL, -@@ -613,18 +614,18 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, - if (ret) { - dev_err(pcm_dev->dev, "%s: read mode err=%d\n", - __func__, ret); -- goto out; -+ return ret; - } - val &= PCM1690_REG_MODE_CTRL_DAMS_MSK; - /* Set to wide-range mode, before using vol ctrl. */ - if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) { - ucontrol->value.integer.value[0] = -25500; -- goto out; -+ return ret; - } - /* Set to fine mode, before using fine vol ctrl. */ - if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) { - ucontrol->value.integer.value[0] = -12750; -- goto out; -+ return ret; - } - } - -@@ -632,15 +633,14 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol, - if (ret) { - dev_err(pcm_dev->dev, "%s: read err=%d\n", - __func__, ret); -- goto out; -+ return ret; - } - - val = (val >> shift) & mask; - val = (val > max) ? max : val; - val = mc->invert ? max - val : val; - ucontrol->value.integer.value[0] = val; --out: -- mutex_unlock(&pcm_dev->codec_lock); -+ - return ret; - } - -@@ -678,7 +678,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol, - unsigned int val, val_mask; - unsigned int reg = mc->reg; - -- mutex_lock(&pcm_dev->codec_lock); -+ guard(mutex)(&pcm_dev->codec_lock); - val = ucontrol->value.integer.value[0] & mask; - val = (val > max) ? max : val; - val = mc->invert ? max - val : val; -@@ -702,7 +702,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol, - __func__, rc); - else - rc = 1; -- mutex_unlock(&pcm_dev->codec_lock); -+ - return rc; - } - -@@ -1577,10 +1577,10 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp) - { - struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(comp); - struct i2c_adapter *adap = pcm_dev->client->adapter; -- const struct firmware *fw_entry = NULL; -+ const struct firmware *fw_entry __free(firmware) = NULL; - int ret, i, j; - -- mutex_lock(&pcm_dev->codec_lock); -+ guard(mutex)(&pcm_dev->codec_lock); - - pcm_dev->component = comp; - -@@ -1588,7 +1588,7 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp) - for (j = 0; j < 2; j++) { - ret = pcmdev_gain_ctrl_add(pcm_dev, i, j); - if (ret < 0) -- goto out; -+ return ret; - } - } - -@@ -1621,21 +1621,17 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp) - if (ret) { - dev_err(pcm_dev->dev, "%s: request %s err = %d\n", __func__, - pcm_dev->bin_name, ret); -- goto out; -+ return ret; - } - - ret = pcmdev_regbin_ready(fw_entry, pcm_dev); - if (ret) { - dev_err(pcm_dev->dev, "%s: %s parse err = %d\n", __func__, - pcm_dev->bin_name, ret); -- goto out; -+ return ret; - } -- ret = pcmdev_profile_ctrl_add(pcm_dev); --out: -- release_firmware(fw_entry); - -- mutex_unlock(&pcm_dev->codec_lock); -- return ret; -+ return pcmdev_profile_ctrl_add(pcm_dev); - } - - -@@ -1645,9 +1641,8 @@ static void pcmdevice_comp_remove(struct snd_soc_component *codec) - - if (!pcm_dev) - return; -- mutex_lock(&pcm_dev->codec_lock); -+ guard(mutex)(&pcm_dev->codec_lock); - pcmdevice_config_info_remove(pcm_dev); -- mutex_unlock(&pcm_dev->codec_lock); - } - - static const struct snd_soc_dapm_widget pcmdevice_dapm_widgets[] = { -@@ -1890,9 +1885,9 @@ static int pcmdevice_mute(struct snd_soc_dai *dai, int mute, int stream) - else - block_type = PCMDEVICE_BIN_BLK_PRE_POWER_UP; - -- mutex_lock(&pcm_dev->codec_lock); -+ guard(mutex)(&pcm_dev->codec_lock); - pcmdevice_select_cfg_blk(pcm_dev, pcm_dev->cur_conf, block_type); -- mutex_unlock(&pcm_dev->codec_lock); -+ - return 0; - } - -diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c ---- a/sound/soc/codecs/peb2466.c -+++ b/sound/soc/codecs/peb2466.c -@@ -6,6 +6,7 @@ - // - // Author: Herve Codina - -+#include - #include - #include - #include -@@ -1537,17 +1538,14 @@ static int peb2466_fw_parse(struct snd_soc_component *component, - - static int peb2466_load_coeffs(struct snd_soc_component *component, const char *fw_name) - { -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - int ret; - - ret = request_firmware(&fw, fw_name, component->dev); - if (ret) - return ret; - -- ret = peb2466_fw_parse(component, fw->data, fw->size); -- release_firmware(fw); -- -- return ret; -+ return peb2466_fw_parse(component, fw->data, fw->size); - } - - static int peb2466_component_probe(struct snd_soc_component *component) -@@ -1704,13 +1702,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x - * So, a specific cache value is used. - */ - -- mutex_lock(&peb2466->gpio.lock); -+ guard(mutex)(&peb2466->gpio.lock); - - cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); -- if (!cache) { -- ret = -EINVAL; -- goto end; -- } -+ if (!cache) -+ return -EINVAL; - - tmp = *cache; - tmp &= ~mask; -@@ -1718,14 +1714,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x - - ret = regmap_write(peb2466->regmap, xr_reg, tmp); - if (ret) -- goto end; -+ return ret; - - *cache = tmp; -- ret = 0; - --end: -- mutex_unlock(&peb2466->gpio.lock); -- return ret; -+ return 0; - } - - static int peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, -diff --git a/sound/soc/codecs/pm4125-sdw.c b/sound/soc/codecs/pm4125-sdw.c ---- a/sound/soc/codecs/pm4125-sdw.c -+++ b/sound/soc/codecs/pm4125-sdw.c -@@ -464,10 +464,16 @@ static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev) - static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev) - { - struct pm4125_sdw_priv *priv = dev_get_drvdata(dev); -+ int ret; - - if (priv->regmap) { - regcache_cache_only(priv->regmap, false); -- regcache_sync(priv->regmap); -+ ret = regcache_sync(priv->regmap); -+ if (ret) { -+ regcache_cache_only(priv->regmap, true); -+ regcache_mark_dirty(priv->regmap); -+ return ret; -+ } - } - - return 0; -diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c ---- a/sound/soc/codecs/pm4125.c -+++ b/sound/soc/codecs/pm4125.c -@@ -5,6 +5,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1295,7 +1296,7 @@ static const struct irq_domain_ops pm4125_domain_ops = { - - static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev) - { -- pm4125->virq = irq_domain_add_linear(NULL, 1, &pm4125_domain_ops, NULL); -+ pm4125->virq = irq_domain_create_linear(NULL, 1, &pm4125_domain_ops, NULL); - if (!(pm4125->virq)) { - dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); - return -EINVAL; -diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c ---- a/sound/soc/codecs/rt1017-sdca-sdw.c -+++ b/sound/soc/codecs/rt1017-sdca-sdw.c -@@ -784,7 +784,12 @@ static int rt1017_sdca_dev_resume(struct device *dev) - } - - regcache_cache_only(rt1017->regmap, false); -- regcache_sync(rt1017->regmap); -+ ret = regcache_sync(rt1017->regmap); -+ if (ret) { -+ regcache_cache_only(rt1017->regmap, true); -+ regcache_mark_dirty(rt1017->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c ---- a/sound/soc/codecs/rt1316-sdw.c -+++ b/sound/soc/codecs/rt1316-sdw.c -@@ -756,7 +756,12 @@ static int rt1316_dev_resume(struct device *dev) - } - - regcache_cache_only(rt1316->regmap, false); -- regcache_sync(rt1316->regmap); -+ ret = regcache_sync(rt1316->regmap); -+ if (ret) { -+ regcache_cache_only(rt1316->regmap, true); -+ regcache_mark_dirty(rt1316->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c ---- a/sound/soc/codecs/rt1318-sdw.c -+++ b/sound/soc/codecs/rt1318-sdw.c -@@ -830,7 +830,12 @@ static int rt1318_dev_resume(struct device *dev) - return ret; - - regcache_cache_only(rt1318->regmap, false); -- regcache_sync(rt1318->regmap); -+ ret = regcache_sync(rt1318->regmap); -+ if (ret) { -+ regcache_cache_only(rt1318->regmap, true); -+ regcache_mark_dirty(rt1318->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c ---- a/sound/soc/codecs/rt1320-sdw.c -+++ b/sound/soc/codecs/rt1320-sdw.c -@@ -410,6 +410,402 @@ static const struct reg_sequence rt1321_blind_write[] = { - { 0x41001988, 0x03 }, - }; - -+static const struct reg_sequence rt1321_va1_blind_write[] = { -+ { 0x0000c003, 0xf0 }, -+ { 0x0000c01b, 0xfc }, -+ { 0x0000c5c3, 0xf2 }, -+ { 0x0000c5c2, 0x00 }, -+ { 0x0000c5c1, 0x10 }, -+ { 0x0000c5c0, 0x04 }, -+ { 0x0000c5c7, 0x03 }, -+ { 0x0000c5c6, 0x10 }, -+ { 0x0000c526, 0x47 }, -+ { 0x0000c5c4, 0x12 }, -+ { 0x0000c5c5, 0x60 }, -+ { 0x0000c520, 0x10 }, -+ { 0x0000c521, 0x32 }, -+ { 0x0000c5c7, 0x00 }, -+ { 0x0000c5c8, 0x03 }, -+ { 0x0000c5d3, 0x08 }, -+ { 0x0000c5d2, 0x0a }, -+ { 0x0000c5d1, 0x49 }, -+ { 0x0000c5d0, 0x0f }, -+ { 0x0000c580, 0x10 }, -+ { 0x0000c581, 0x32 }, -+ { 0x0000c582, 0x01 }, -+ { 0x0000c682, 0x60 }, -+ { 0x0000c019, 0x10 }, -+ { 0x0000c5f0, 0x01 }, -+ { 0x0000c5f7, 0x22 }, -+ { 0x0000c5f6, 0x22 }, -+ { 0x0000c057, 0x51 }, -+ { 0x0000c054, 0x55 }, -+ { 0x0000c053, 0x55 }, -+ { 0x0000c052, 0x55 }, -+ { 0x0000c051, 0x01 }, -+ { 0x0000c050, 0x15 }, -+ { 0x0000c060, 0x99 }, -+ { 0x0000c030, 0x55 }, -+ { 0x0000c061, 0x55 }, -+ { 0x0000c063, 0x55 }, -+ { 0x0000c065, 0xa5 }, -+ { 0x0000c06b, 0x0a }, -+ { 0x0000ca05, 0xd6 }, -+ { 0x0000ca06, 0x11 }, -+ { 0x0000ca07, 0x1e }, -+ { 0x0000ca25, 0xd6 }, -+ { 0x0000ca26, 0x11 }, -+ { 0x0000ca27, 0x1e }, -+ { 0x0000cd00, 0x05 }, -+ { 0x0000cd81, 0x49 }, -+ { 0x0000cd82, 0x49 }, -+ { 0x0000c604, 0x40 }, -+ { 0x0000c609, 0x40 }, -+ { 0x0000c046, 0xf7 }, -+ { 0x0000c045, 0xff }, -+ { 0x0000c044, 0xff }, -+ { 0x0000c043, 0xff }, -+ { 0x0000c042, 0xff }, -+ { 0x0000c041, 0xff }, -+ { 0x0000c040, 0xff }, -+ { 0x0000c049, 0xff }, -+ { 0x0000c028, 0x3f }, -+ { 0x0000c020, 0x3f }, -+ { 0x0000c032, 0x13 }, -+ { 0x0000c033, 0x01 }, -+ { 0x0000cc10, 0x01 }, -+ { 0x0000dc20, 0x03 }, -+ { 0x0000de03, 0x05 }, -+ { 0x0000dc00, 0x00 }, -+ { 0x0000c700, 0xf0 }, -+ { 0x0000c701, 0x13 }, -+ { 0x0000c900, 0xc3 }, -+ { 0x0000c570, 0x08 }, -+ { 0x0000c086, 0x02 }, -+ { 0x0000c085, 0x7f }, -+ { 0x0000c084, 0x00 }, -+ { 0x0000c081, 0xff }, -+ { 0x0000f084, 0x0f }, -+ { 0x0000f083, 0xff }, -+ { 0x0000f082, 0xff }, -+ { 0x0000f081, 0xff }, -+ { 0x0000f080, 0xff }, -+ { 0x20003003, 0x3f }, -+ { 0x20005818, 0x81 }, -+ { 0x20009018, 0x81 }, -+ { 0x2000301c, 0x81 }, -+ { 0x0000c003, 0xc0 }, -+ { 0x0000c047, 0x80 }, -+ { 0x0000d541, 0x80 }, -+ { 0x0000d487, 0x0b }, -+ { 0x0000d487, 0x3b }, -+ { 0x0000d486, 0xc3 }, -+ { 0x0000d470, 0x89 }, -+ { 0x0000d471, 0x3a }, -+ { 0x0000d472, 0x3d }, -+ { 0x0000d474, 0x11 }, -+ { 0x0000d475, 0x32 }, -+ { 0x0000d476, 0x64 }, -+ { 0x0000d477, 0x10 }, -+ { 0x0000d478, 0xff }, -+ { 0x0000d479, 0x20 }, -+ { 0x0000d47a, 0x10 }, -+ { 0x0000d73c, 0xb7 }, -+ { 0x0000d73d, 0xd7 }, -+ { 0x0000d73e, 0x00 }, -+ { 0x0000d73f, 0x10 }, -+ { 0x1000cd56, 0x00 }, -+ { 0x3fc2dfc0, 0x03 }, -+ { 0x3fc2dfc1, 0x00 }, -+ { 0x3fc2dfc2, 0x00 }, -+ { 0x3fc2dfc3, 0x00 }, -+ { 0x3fc2dfc4, 0x01 }, -+ { 0x3fc2dfc5, 0x00 }, -+ { 0x3fc2dfc6, 0x00 }, -+ { 0x3fc2dfc7, 0x00 }, -+ { 0x3fc2df80, 0x00 }, -+ { 0x3fc2df81, 0x00 }, -+ { 0x3fc2df82, 0x00 }, -+ { 0x3fc2df83, 0x00 }, -+ { 0x0000d541, 0x40 }, -+ { 0x0000d486, 0x43 }, -+ { 0x1000db00, 0x04 }, -+ { 0x1000db01, 0x00 }, -+ { 0x1000db02, 0x10 }, -+ { 0x1000db03, 0x00 }, -+ { 0x1000db04, 0x00 }, -+ { 0x1000db05, 0x45 }, -+ { 0x1000db06, 0x0d }, -+ { 0x1000db07, 0x01 }, -+ { 0x1000db08, 0x00 }, -+ { 0x1000db09, 0x00 }, -+ { 0x1000db0a, 0xbf }, -+ { 0x1000db0b, 0x0b }, -+ { 0x1000db0c, 0x11 }, -+ { 0x1000db0d, 0x00 }, -+ { 0x1000db0e, 0x00 }, -+ { 0x1000db0f, 0x00 }, -+ { 0x1000db10, 0x2c }, -+ { 0x1000db11, 0xfa }, -+ { 0x1000db12, 0x00 }, -+ { 0x1000db13, 0x00 }, -+ { 0x1000db14, 0x09 }, -+ { 0x0000d540, 0x21 }, -+ { 0x0000c570, 0x08 }, -+ { 0x0000d714, 0x17 }, -+ { 0x0000c5c3, 0xf2 }, -+ { 0x0000c5c8, 0x03 }, -+ { 0x20009012, 0x00 }, -+ { 0x0000dd08, 0x17 }, -+ { 0x0000dd09, 0x0e }, -+ { 0x0000dd0a, 0x17 }, -+ { 0x0000dd0b, 0x0e }, -+ { 0x0000c570, 0x08 }, -+ { 0x0000d471, 0x3a }, -+ { 0x0000db00, 0x00 }, -+ { 0x0000db01, 0x00 }, -+ { 0x0000db02, 0x73 }, -+ { 0x0000db03, 0x00 }, -+ { 0x0000db04, 0x00 }, -+ { 0x0000db05, 0x00 }, -+ { 0x0000db06, 0x00 }, -+ { 0x0000db07, 0x00 }, -+ { 0x0000db08, 0x7f }, -+ { 0x0000db09, 0x00 }, -+ { 0x0000db1a, 0x00 }, -+ { 0x0000db1b, 0x00 }, -+ { 0x0000db19, 0x00 }, -+}; -+ -+static const struct reg_sequence rt1321_va2_blind_write[] = { -+ { 0x0000c003, 0xf0 }, -+ { 0x0000c01b, 0xfc }, -+ { 0x0000c5c3, 0xf2 }, -+ { 0x0000c5c2, 0x00 }, -+ { 0x0000c5c1, 0x10 }, -+ { 0x0000c5c0, 0x04 }, -+ { 0x0000c5c7, 0x03 }, -+ { 0x0000c5c6, 0x10 }, -+ { 0x0000c526, 0x47 }, -+ { 0x0000c5c4, 0x12 }, -+ { 0x0000c5c5, 0x60 }, -+ { 0x0000c520, 0x10 }, -+ { 0x0000c521, 0x32 }, -+ { 0x0000c5c7, 0x00 }, -+ { 0x0000c5c8, 0x03 }, -+ { 0x0000c5d3, 0x08 }, -+ { 0x0000c5d2, 0x0a }, -+ { 0x0000c5d1, 0x49 }, -+ { 0x0000c5d0, 0x0f }, -+ { 0x0000c580, 0x10 }, -+ { 0x0000c581, 0x32 }, -+ { 0x0000c582, 0x01 }, -+ { 0x0000c682, 0x60 }, -+ { 0x0000c019, 0x10 }, -+ { 0x0000c5f0, 0x01 }, -+ { 0x0000c5f7, 0x22 }, -+ { 0x0000c5f6, 0x22 }, -+ { 0x0000c057, 0x51 }, -+ { 0x0000c054, 0x55 }, -+ { 0x0000c053, 0x55 }, -+ { 0x0000c052, 0x55 }, -+ { 0x0000c051, 0x01 }, -+ { 0x0000c050, 0x15 }, -+ { 0x0000c060, 0x99 }, -+ { 0x0000c030, 0x55 }, -+ { 0x0000c061, 0x55 }, -+ { 0x0000c063, 0x55 }, -+ { 0x0000c065, 0xa5 }, -+ { 0x0000c06b, 0x0a }, -+ { 0x0000ca05, 0xd6 }, -+ { 0x0000ca06, 0x11 }, -+ { 0x0000ca07, 0x1e }, -+ { 0x0000ca25, 0xd6 }, -+ { 0x0000ca26, 0x11 }, -+ { 0x0000ca27, 0x1e }, -+ { 0x0000cd00, 0x05 }, -+ { 0x0000cd81, 0x49 }, -+ { 0x0000cd82, 0x49 }, -+ { 0x0000c604, 0x40 }, -+ { 0x0000c609, 0x40 }, -+ { 0x0000c046, 0xf7 }, -+ { 0x0000c045, 0xff }, -+ { 0x0000c044, 0xff }, -+ { 0x0000c043, 0xff }, -+ { 0x0000c042, 0xff }, -+ { 0x0000c041, 0xff }, -+ { 0x0000c040, 0xff }, -+ { 0x0000c049, 0xff }, -+ { 0x0000c028, 0x3f }, -+ { 0x0000c020, 0x3f }, -+ { 0x0000c032, 0x13 }, -+ { 0x0000c033, 0x01 }, -+ { 0x0000cc10, 0x01 }, -+ { 0x0000dc20, 0x03 }, -+ { 0x0000de03, 0x05 }, -+ { 0x0000dc00, 0x00 }, -+ { 0x0000c700, 0xf0 }, -+ { 0x0000c701, 0x13 }, -+ { 0x0000c900, 0xc3 }, -+ { 0x0000c570, 0x08 }, -+ { 0x0000c086, 0x02 }, -+ { 0x0000c085, 0x7f }, -+ { 0x0000c084, 0x00 }, -+ { 0x0000c081, 0xff }, -+ { 0x0000f084, 0x0f }, -+ { 0x0000f083, 0xff }, -+ { 0x0000f082, 0xff }, -+ { 0x0000f081, 0xff }, -+ { 0x0000f080, 0xff }, -+ { 0x20003003, 0x3f }, -+ { 0x20005818, 0x81 }, -+ { 0x20009018, 0x81 }, -+ { 0x2000301c, 0x81 }, -+ { 0x0000c003, 0xc0 }, -+ { 0x0000c047, 0x80 }, -+ { 0x0000d541, 0x80 }, -+ { 0x0000d487, 0x0b }, -+ { 0x0000d487, 0x3b }, -+ { 0x0000d486, 0xc3 }, -+ { 0x0000d470, 0x89 }, -+ { 0x0000d471, 0x3a }, -+ { 0x0000d472, 0x3d }, -+ { 0x0000d474, 0x11 }, -+ { 0x0000d475, 0x32 }, -+ { 0x0000d476, 0x64 }, -+ { 0x0000d477, 0x10 }, -+ { 0x0000d478, 0xff }, -+ { 0x0000d479, 0x20 }, -+ { 0x0000d47a, 0x10 }, -+ { 0x10008000, 0x67 }, -+ { 0x10008001, 0x80 }, -+ { 0x10008002, 0x00 }, -+ { 0x10008003, 0x00 }, -+ { 0x1000cd56, 0x00 }, -+ { 0x0000d486, 0x43 }, -+ { 0x3fc2dfc3, 0x00 }, -+ { 0x3fc2dfc2, 0x00 }, -+ { 0x3fc2dfc1, 0x00 }, -+ { 0x3fc2dfc0, 0x03 }, -+ { 0x3fc2dfc7, 0x00 }, -+ { 0x3fc2dfc6, 0x00 }, -+ { 0x3fc2dfc5, 0x00 }, -+ { 0x3fc2dfc4, 0x01 }, -+ { 0x3fc2dfa3, 0x00 }, -+ { 0x3fc2dfa2, 0x00 }, -+ { 0x3fc2dfa1, 0x00 }, -+ { 0x3fc2dfa0, 0x00 }, -+ { 0x3fc2df80, 0x10 }, -+ { 0x3fc2df81, 0x20 }, -+ { 0x3fc2df82, 0x00 }, -+ { 0x3fc2df83, 0x00 }, -+ { 0x3fc2df84, 0x50 }, -+ { 0x3fc2df85, 0x19 }, -+ { 0x3fc2df86, 0x00 }, -+ { 0x3fc2df87, 0x00 }, -+ { 0x3fc2df88, 0x52 }, -+ { 0x3fc2df89, 0x23 }, -+ { 0x3fc2df8a, 0x00 }, -+ { 0x3fc2df8b, 0x00 }, -+ { 0x3fc2df8c, 0xe0 }, -+ { 0x3fc2df8d, 0x2e }, -+ { 0x3fc2df8e, 0x00 }, -+ { 0x3fc2df8f, 0x00 }, -+ { 0x3fc2df90, 0xe0 }, -+ { 0x3fc2df91, 0x2e }, -+ { 0x3fc2df92, 0x00 }, -+ { 0x3fc2df93, 0x00 }, -+ { 0x3fc2df94, 0x01 }, -+ { 0x3fc2df95, 0x08 }, -+ { 0x3fc2df96, 0x00 }, -+ { 0x3fc2df97, 0x00 }, -+ { 0x3fc2df40, 0x80 }, -+ { 0x3fc2df41, 0xbb }, -+ { 0x3fc2df42, 0x00 }, -+ { 0x3fc2df43, 0x00 }, -+ { 0x3fc2df44, 0xc0 }, -+ { 0x3fc2df45, 0x99 }, -+ { 0x3fc2df46, 0x01 }, -+ { 0x3fc2df47, 0x00 }, -+ { 0x3fc2df48, 0x00 }, -+ { 0x3fc2df49, 0x00 }, -+ { 0x3fc2df4a, 0x00 }, -+ { 0x3fc2df4b, 0x00 }, -+ { 0x3fc2df4c, 0x00 }, -+ { 0x3fc2df4d, 0x00 }, -+ { 0x3fc2df4e, 0x00 }, -+ { 0x3fc2df4f, 0x00 }, -+ { 0x3fc2df50, 0x01 }, -+ { 0x3fc2df51, 0x00 }, -+ { 0x3fc2df52, 0x00 }, -+ { 0x3fc2df53, 0x00 }, -+ { 0x3fc2df54, 0x01 }, -+ { 0x3fc2df55, 0x00 }, -+ { 0x3fc2df56, 0x00 }, -+ { 0x3fc2df57, 0x00 }, -+ { 0x3fc2df58, 0x00 }, -+ { 0x3fc2df59, 0x00 }, -+ { 0x3fc2df5a, 0x00 }, -+ { 0x3fc2df5b, 0x00 }, -+ { 0x3fc2df5c, 0x01 }, -+ { 0x3fc2df5d, 0x00 }, -+ { 0x3fc2df5e, 0x00 }, -+ { 0x3fc2df5f, 0x00 }, -+ { 0x3fc2df60, 0x00 }, -+ { 0x3fc2df61, 0x00 }, -+ { 0x3fc2df62, 0x00 }, -+ { 0x3fc2df63, 0x00 }, -+ { 0x3fc2df64, 0x00 }, -+ { 0x3fc2df65, 0x00 }, -+ { 0x3fc2df66, 0x00 }, -+ { 0x3fc2df67, 0x10 }, -+ { 0x3fc2df68, 0x01 }, -+ { 0x3fc2df69, 0x00 }, -+ { 0x3fc2df6a, 0x00 }, -+ { 0x3fc2df6b, 0x00 }, -+ { 0x3fc2df6c, 0x01 }, -+ { 0x3fc2df6d, 0x00 }, -+ { 0x3fc2df6e, 0x00 }, -+ { 0x3fc2df6f, 0x00 }, -+ { 0x3fc2df70, 0x04 }, -+ { 0x3fc2df71, 0x00 }, -+ { 0x3fc2df72, 0x00 }, -+ { 0x3fc2df73, 0x00 }, -+ { 0x3fc2df74, 0x01 }, -+ { 0x3fc2df75, 0x00 }, -+ { 0x3fc2df76, 0x00 }, -+ { 0x3fc2df77, 0x00 }, -+ { 0x1000db00, 0x04 }, -+ { 0x1000db01, 0x00 }, -+ { 0x1000db02, 0x10 }, -+ { 0x1000db03, 0x00 }, -+ { 0x1000db04, 0x00 }, -+ { 0x1000db05, 0x45 }, -+ { 0x1000db06, 0x0d }, -+ { 0x1000db07, 0x01 }, -+ { 0x1000db08, 0x00 }, -+ { 0x1000db09, 0x00 }, -+ { 0x1000db0a, 0xbf }, -+ { 0x1000db0b, 0x0b }, -+ { 0x1000db0c, 0x11 }, -+ { 0x1000db0d, 0x00 }, -+ { 0x1000db0e, 0x00 }, -+ { 0x1000db0f, 0x00 }, -+ { 0x1000db10, 0x2c }, -+ { 0x1000db11, 0xfa }, -+ { 0x1000db12, 0x00 }, -+ { 0x1000db13, 0x00 }, -+ { 0x1000db14, 0x09 }, -+ { 0x0000d540, 0x21 }, -+ { 0x0000d714, 0x17 }, -+ { 0x0000dd0b, 0x0d }, -+ { 0x0000dd0a, 0xff }, -+ { 0x0000dd09, 0x0d }, -+ { 0x0000dd08, 0xff }, -+ { 0x0000c5fb, 0x12 }, -+ { 0x0000c570, 0x08 }, -+}; -+ - static const struct reg_default rt1320_reg_defaults[] = { - { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, -@@ -440,6 +836,7 @@ static const struct reg_default rt1320_mbq_defaults[] = { - static bool rt1320_readable_register(struct device *dev, unsigned int reg) - { - switch (reg) { -+ case 0x004d: - case 0xc000 ... 0xc086: - case 0xc400 ... 0xc409: - case 0xc480 ... 0xc48f: -@@ -497,10 +894,15 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) - case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER: - case 0x1000f008: - case 0x1000f021: -- case 0x2000300f: -+ case 0x20003000 ... 0x2000300f: - case 0x2000301c: -- case 0x2000900f: -+ case 0x20003040 ... 0x20003059: -+ case 0x20005800 ... 0x2000580f: -+ case 0x20005818: -+ case 0x20005840 ... 0x20005859: -+ case 0x20009000 ... 0x2000900f: - case 0x20009018: -+ case 0x20009040 ... 0x20009059: - case 0x3fc000c0 ... 0x3fc2dfc8: - case 0x3fe00000 ... 0x3fe36fff: - /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */ -@@ -545,6 +947,7 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) - static bool rt1320_volatile_register(struct device *dev, unsigned int reg) - { - switch (reg) { -+ case 0x004d: - case 0xc000: - case 0xc003: - case 0xc081: -@@ -596,15 +999,20 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) - case 0x1000c000 ... 0x1000dfff: - case 0x1000f008: - case 0x1000f021: -- case 0x2000300f: -+ case 0x2000300e ... 0x2000300f: - case 0x2000301c: -- case 0x2000900f: -+ case 0x20003040 ... 0x20003059: -+ case 0x2000580e ... 0x2000580f: -+ case 0x20005818: -+ case 0x20005840 ... 0x20005859: -+ case 0x2000900e ... 0x2000900f: - case 0x20009018: -+ case 0x20009040 ... 0x20009059: - case 0x3fc2ab80 ... 0x3fc2ac4c: - case 0x3fc2b780: - case 0x3fc2bf80 ... 0x3fc2bf83: - case 0x3fc2bfc0 ... 0x3fc2bfc8: -- case 0x3fc2d300 ... 0x3fc2d354: -+ case 0x3fc2d300 ... 0x3fc2d3cc: - case 0x3fc2dfc0 ... 0x3fc2dfc8: - case 0x3fe2e000 ... 0x3fe2e003: - case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): -@@ -892,6 +1300,42 @@ static int rt1320_check_fw_ready(struct rt1320_sdw_priv *rt1320) - return 0; - } - -+static int rt1320_dspfw_status(struct rt1320_sdw_priv *rt1320) -+{ -+ struct device *dev = &rt1320->sdw_slave->dev; -+ unsigned int fw_status_addr, fw_ready; -+ unsigned int dspfw_run; -+ -+ switch (rt1320->dev_id) { -+ case RT1320_DEV_ID: -+ fw_status_addr = RT1320_DSPFW_STATUS_ADDR; -+ break; -+ case RT1321_DEV_ID: -+ fw_status_addr = RT1321_DSPFW_STATUS_ADDR; -+ break; -+ default: -+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -+ return -EINVAL; -+ } -+ -+ regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); -+ fw_ready &= 0x1; -+ -+ if (rt1320->dev_id == RT1321_DEV_ID) { -+ regmap_read(rt1320->regmap, 0xf01e, &dspfw_run); -+ dspfw_run &= 0x1; -+ fw_ready = (!dspfw_run && fw_ready); -+ } -+ -+ if (fw_ready) { -+ dev_dbg(dev, "%s, DSP FW was already\n", __func__); -+ return 1; -+ } -+ -+ dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__); -+ return 0; -+} -+ - static int rt1320_check_power_state_ready(struct rt1320_sdw_priv *rt1320, enum rt1320_power_state ps) - { - struct device *dev = &rt1320->sdw_slave->dev; -@@ -982,6 +1426,9 @@ static int rt1320_fw_param_protocol(struct rt1320_sdw_priv *rt1320, enum rt1320_ - if (!tempbuf) - return -ENOMEM; - -+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) -+ paramid += 0x0bff0000; -+ - paramhr.moudleid = 1; - paramhr.commandtype = cmdid; - /* 8 is "sizeof(paramid) + sizeof(paramlength)" */ -@@ -1120,45 +1567,73 @@ static void rt1320_calc_r0(struct rt1320_sdw_priv *rt1320) - l_calir0, l_calir0_lo, r_calir0, r_calir0_lo); - } - -+static int rt1320_pilot_tone_output(struct rt1320_sdw_priv *rt1320) -+{ -+ struct device *dev = &rt1320->sdw_slave->dev; -+ int l_targetpostgain, r_targetpostgain; -+ unsigned long long factor = (1 << 12); -+ int l_pilotgain[9], r_pilotgain[9]; -+ const int postgain_step = 234; -+ int targetGain; -+ -+ switch (rt1320->dev_id) { -+ case RT1320_DEV_ID: -+ targetGain = -320000; -+ break; -+ case RT1321_DEV_ID: -+ targetGain = -420000; -+ if (rt1320->version_id == RT1321_VA0) -+ targetGain = -320000; -+ break; -+ default: -+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -+ return -EINVAL; -+ } -+ -+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 70, &l_pilotgain[0], sizeof(l_pilotgain)); -+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 71, &r_pilotgain[0], sizeof(r_pilotgain)); -+ dev_dbg(dev, "%s, LR pilotgain %d, %d\n", __func__, l_pilotgain[2], r_pilotgain[2]); -+ -+ /* calculate pilot tone gain */ -+ l_pilotgain[2] = (l_pilotgain[2] * 10000) / factor; -+ r_pilotgain[2] = (r_pilotgain[2] * 10000) / factor; -+ -+ /* calculate post gain to meet target gain */ -+ l_targetpostgain = abs(targetGain - l_pilotgain[2]) / postgain_step; -+ r_targetpostgain = abs(targetGain - r_pilotgain[2]) / postgain_step; -+ l_targetpostgain = 0xfff - l_targetpostgain; -+ r_targetpostgain = 0xfff - r_targetpostgain; -+ dev_dbg(dev, "%s, LR targetpostgain=0x%x, 0x%x\n", __func__, l_targetpostgain, r_targetpostgain); -+ -+ regmap_write(rt1320->regmap, 0xdd0b, (l_targetpostgain & 0xf00) >> 8); -+ regmap_write(rt1320->regmap, 0xdd0a, l_targetpostgain & 0xff); -+ regmap_write(rt1320->regmap, 0xdd09, (r_targetpostgain & 0xf00) >> 8); -+ regmap_write(rt1320->regmap, 0xdd08, r_targetpostgain & 0xff); -+ -+ return 0; -+} -+ - static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) - { - struct device *dev = &rt1320->sdw_slave->dev; - struct rt1320_datafixpoint audfixpoint[2]; - unsigned int reg_c5fb, reg_c570, reg_cd00; -- unsigned int vol_reg[4], fw_ready; -+ unsigned int vol_reg[4]; - unsigned long long l_meanr0, r_meanr0; -- unsigned int fw_status_addr; - int l_re[5], r_re[5]; - int ret, tmp; - unsigned long long factor = (1 << 27); - unsigned short l_advancegain, r_advancegain; - unsigned int delay_s = 7; /* delay seconds for the calibration */ -+ int dspfw_status; - - if (!rt1320->component) - return; - -- switch (rt1320->dev_id) { -- case RT1320_DEV_ID: -- fw_status_addr = RT1320_DSPFW_STATUS_ADDR; -- break; -- case RT1321_DEV_ID: -- fw_status_addr = RT1321_DSPFW_STATUS_ADDR; -- break; -- default: -- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -- return; -- } -- -- /* set volume 0dB */ - regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]); - regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]); - regmap_read(rt1320->regmap, 0xdd09, &vol_reg[1]); - regmap_read(rt1320->regmap, 0xdd08, &vol_reg[0]); -- regmap_write(rt1320->regmap, 0xdd0b, 0x0f); -- regmap_write(rt1320->regmap, 0xdd0a, 0xff); -- regmap_write(rt1320->regmap, 0xdd09, 0x0f); -- regmap_write(rt1320->regmap, 0xdd08, 0xff); -- - regmap_read(rt1320->regmap, 0xc5fb, ®_c5fb); - regmap_read(rt1320->regmap, 0xc570, ®_c570); - regmap_read(rt1320->regmap, 0xcd00, ®_cd00); -@@ -1171,9 +1646,8 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) - goto _finish_; - } - -- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); -- fw_ready &= 0x1; -- if (!fw_ready) { -+ dspfw_status = rt1320_dspfw_status(rt1320); -+ if (dspfw_status <= 0) { - dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__); - goto _finish_; - } -@@ -1184,8 +1658,19 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) - goto _finish_; - } - -- if (rt1320->dev_id == RT1320_DEV_ID) -- regmap_write(rt1320->regmap, 0xc5fb, 0x00); -+ /* fine tune pilot tone output */ -+ ret = rt1320_pilot_tone_output(rt1320); -+ if (ret < 0) { -+ dev_dbg(dev, "%s, Failed to tune pilot tone output\n", __func__); -+ goto _finish_; -+ } -+ -+ if (rt1320->dev_id == RT1321_DEV_ID) { -+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00); -+ regmap_write(rt1320->regmap, 0xc5c4, 0x12); -+ } -+ -+ regmap_write(rt1320->regmap, 0xc5fb, 0x00); - regmap_write(rt1320->regmap, 0xc570, 0x0b); - regmap_write(rt1320->regmap, 0xcd00, 0xc5); - -@@ -1246,6 +1731,11 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320) - SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03); - rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03); - -+ if (rt1320->dev_id == RT1321_DEV_ID) { -+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80); -+ regmap_write(rt1320->regmap, 0xc5c4, 0x10); -+ } -+ - /* advance gain will be set when R0 load, not here */ - regmap_write(rt1320->regmap, 0xdd0b, vol_reg[3]); - regmap_write(rt1320->regmap, 0xdd0a, vol_reg[2]); -@@ -1296,7 +1786,7 @@ static int rt1320_r0_cali_put(struct snd_kcontrol *kcontrol, - static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) - { - struct sdw_slave *slave = rt1320->sdw_slave; -- const struct firmware *patch; -+ const struct firmware *patch __free(firmware) = NULL; - const char *filename; - unsigned int addr, val, min_addr, max_addr; - const unsigned char *ptr; -@@ -1312,6 +1802,9 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) - max_addr = 0x10007fff; - break; - case RT1321_DEV_ID: -+ if (rt1320->version_id == RT1321_VA2) -+ return; -+ - filename = RT1321_VA_MCU_PATCH; - min_addr = 0x10008000; - max_addr = 0x10008fff; -@@ -1347,17 +1840,15 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) - - if (addr > max_addr || addr < min_addr) { - dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr); -- goto _exit_; -+ return; - } - if (val > 0xff) { - dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val); -- goto _exit_; -+ return; - } - regmap_write(rt1320->regmap, addr, val); - } - } --_exit_: -- release_firmware(patch); - } - } - -@@ -1382,30 +1873,17 @@ static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320) - static void rt1320_t0_load(struct rt1320_sdw_priv *rt1320, unsigned int l_t0, unsigned int r_t0) - { - struct device *dev = &rt1320->sdw_slave->dev; -- unsigned int factor = (1 << 22), fw_ready; -+ unsigned int factor = (1 << 22); - int l_t0_data[38], r_t0_data[38]; -- unsigned int fw_status_addr; -- -- switch (rt1320->dev_id) { -- case RT1320_DEV_ID: -- fw_status_addr = RT1320_DSPFW_STATUS_ADDR; -- break; -- case RT1321_DEV_ID: -- fw_status_addr = RT1321_DSPFW_STATUS_ADDR; -- break; -- default: -- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -- return; -- } -+ int dspfw_status; - - regmap_write(rt1320->regmap, - SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, - RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); - rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); - -- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); -- fw_ready &= 0x1; -- if (!fw_ready) { -+ dspfw_status = rt1320_dspfw_status(rt1320); -+ if (dspfw_status <= 0) { - dev_warn(dev, "%s, DSP FW is NOT ready\n", __func__); - goto _exit_; - } -@@ -1444,7 +1922,7 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) - struct device *dev = &rt1320->sdw_slave->dev; - static const char func_tag[] = "FUNC"; - static const char xu_tag[] = "XU"; -- const struct firmware *rae_fw = NULL; -+ const struct firmware *rae_fw __free(firmware) = NULL; - unsigned int fw_offset; - unsigned char *fw_data; - unsigned char *param_data; -@@ -1483,22 +1961,46 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) - request_firmware(&rae_fw, rae_filename, dev); - if (rae_fw) { - -- /* RAE CRC clear */ -- regmap_write(rt1320->regmap, 0xe80b, 0x0f); -- -- /* RAE stop & CRC disable */ -- regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00); -- -- while (--retry) { -- regmap_read(rt1320->regmap, 0xe83f, &value); -- if (value & 0x40) -- break; -- usleep_range(1000, 1100); -- } -- if (!retry && !(value & 0x40)) { -- dev_err(dev, "%s: RAE is not ready to load\n", __func__); -- release_firmware(rae_fw); -- return -ETIMEDOUT; -+ switch (rt1320->dev_id) { -+ case RT1320_DEV_ID: -+ /* RAE CRC clear */ -+ regmap_write(rt1320->regmap, 0xe80b, 0x0f); -+ /* RAE stop & CRC disable */ -+ regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00); -+ while (--retry) { -+ regmap_read(rt1320->regmap, 0xe83f, &value); -+ if (value & 0x40) -+ break; -+ usleep_range(1000, 1100); -+ } -+ if (!retry && !(value & 0x40)) { -+ dev_err(dev, "%s: RAE is not ready to load\n", __func__); -+ return -ETIMEDOUT; -+ } -+ break; -+ case RT1321_DEV_ID: -+ /* RAE CRC clear */ -+ regmap_write(rt1320->regmap, 0x2000300e, 0xc0); -+ regmap_write(rt1320->regmap, 0x2000300f, 0x0f); -+ /* RAE stop & Phase sync & CRC disable */ -+ regmap_update_bits(rt1320->regmap, 0x20003003, 0xfe, 0x00); -+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00); -+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x00); -+ /* check whether write state is ready */ -+ while (--retry) { -+ regmap_read(rt1320->regmap, 0x20003043, &value); -+ if (value & 0x40) -+ break; -+ usleep_range(1000, 1100); -+ } -+ if (!retry && !(value & 0x40)) { -+ dev_err(dev, "%s: RAE is not ready to load\n", __func__); -+ return -ETIMEDOUT; -+ } -+ break; -+ default: -+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -+ return -EINVAL; - } - - dev_dbg(dev, "%s, rae_fw size=0x%zx\n", __func__, rae_fw->size); -@@ -1551,7 +2053,6 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) - } - - regcache_cache_bypass(rt1320->regmap, false); -- release_firmware(rae_fw); - - } else { - dev_err(dev, "%s: Failed to load %s firmware\n", __func__, rae_filename); -@@ -1559,18 +2060,34 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320) - goto _exit_; - } - -- /* RAE CRC enable */ -- regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c); -- -- /* RAE update */ -- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00); -- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80); -- -- /* RAE run */ -- regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80); -- -- regmap_read(rt1320->regmap, 0xe80b, &value); -- dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value); -+ switch (rt1320->dev_id) { -+ case RT1320_DEV_ID: -+ /* RAE CRC enable */ -+ regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c); -+ /* RAE update */ -+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00); -+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80); -+ /* RAE run */ -+ regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80); -+ regmap_read(rt1320->regmap, 0xe80b, &value); -+ dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value); -+ break; -+ case RT1321_DEV_ID: -+ /* RAE CRC enable */ -+ regmap_update_bits(rt1320->regmap, 0x20003003, 0x30, 0x30); -+ /* RAE update */ -+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x00); -+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x80); -+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x00); -+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x80); -+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x00); -+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x80); -+ /* RAE run */ -+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x01); -+ /* Phase sync eanble */ -+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80); -+ break; -+ } - - rt1320->rae_update_done = true; - -@@ -1598,32 +2115,21 @@ struct rt1320_dspfwheader { - - struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt1320->component); - struct device *dev = &rt1320->sdw_slave->dev; -- unsigned int val, i, fw_offset, fw_ready; -- unsigned int fw_status_addr; -+ unsigned int val, i, fw_offset; - struct rt1320_dspfwheader *fwheader; - struct rt1320_imageinfo *ptr_img; - struct sdw_bpt_section sec[10]; -- const struct firmware *fw = NULL; -+ const struct firmware *fw __free(firmware) = NULL; - unsigned char *fw_data; - bool dev_fw_match = false; - static const char hdr_sig[] = "AFX"; - unsigned int hdr_size = 0; - const char *dmi_vendor, *dmi_product, *dmi_sku; - int len_vendor, len_product, len_sku; -+ unsigned char boot_mode = 0; /* 0: from RAM; 1: from ROM */ -+ unsigned char has_0x3fc00000 = 0; - char filename[512]; - -- switch (rt1320->dev_id) { -- case RT1320_DEV_ID: -- fw_status_addr = RT1320_DSPFW_STATUS_ADDR; -- break; -- case RT1321_DEV_ID: -- fw_status_addr = RT1321_DSPFW_STATUS_ADDR; -- break; -- default: -- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -- return; -- } -- - dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR); - dmi_product = dmi_get_system_info(DMI_PRODUCT_NAME); - dmi_sku = dmi_get_system_info(DMI_PRODUCT_SKU); -@@ -1653,17 +2159,12 @@ struct rt1320_dspfwheader { - RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); - rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); - -- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); -- fw_ready &= 0x1; -- if (fw_ready) { -+ if (rt1320_dspfw_status(rt1320)) { - dev_dbg(dev, "%s, DSP FW was already\n", __func__); - rt1320->fw_load_done = true; - goto _exit_; - } - -- /* change to IRAM */ -- regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00); -- - request_firmware(&fw, filename, dev); - if (fw) { - fwheader = (struct rt1320_dspfwheader *)fw->data; -@@ -1672,7 +2173,6 @@ struct rt1320_dspfwheader { - - if (fwheader->sync != 0x0a1c5679) { - dev_err(dev, "%s: FW sync error\n", __func__); -- release_firmware(fw); - goto _exit_; - } - -@@ -1709,9 +2209,11 @@ struct rt1320_dspfwheader { - dev_fw_match = true; - break; - case RT1321_DEV_ID: -- if (ptr_img->addr == 0x3fc00000) -- if (fw_data[9] == '1') -+ if (ptr_img->addr == 0x3fc00000) { -+ if (fw_data[7] == '1') - dev_fw_match = true; -+ has_0x3fc00000 = 1; -+ } - break; - default: - dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -@@ -1721,6 +2223,22 @@ struct rt1320_dspfwheader { - fw_offset += ptr_img->size; - } - -+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) { -+ /* -+ * For 1321 VA2, if the FW doesn't include the section for address 0x3fc00000, -+ * it means the FW will boot from ROM and force dev_fw_match to true to download FW by BRA. -+ */ -+ if (!has_0x3fc00000) { -+ boot_mode = 1; -+ dev_fw_match = true; -+ } -+ dev_dbg(dev, "%s: Boot from %s for VA2\n", __func__, (boot_mode ? "ROM" : "RAM")); -+ } -+ -+ /* change to IRAM */ -+ if (!boot_mode) -+ regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00); -+ - if (dev_fw_match) { - dev_dbg(dev, "%s, starting BRA downloading FW..\n", __func__); - rt1320->bra_msg.dev_num = rt1320->sdw_slave->dev_num; -@@ -1732,7 +2250,6 @@ struct rt1320_dspfwheader { - } - - regcache_cache_bypass(rt1320->regmap, false); -- release_firmware(fw); - - if (!dev_fw_match) { - dev_err(dev, "%s: FW file doesn't match to device\n", __func__); -@@ -1743,24 +2260,39 @@ struct rt1320_dspfwheader { - goto _exit_; - } - -- /* run RAM code */ -- regmap_read(rt1320->regmap, 0x3fc2bfc0, &val); -- val |= 0x8; -- regmap_write(rt1320->regmap, 0x3fc2bfc0, val); -- -- /* clear frame counter */ - switch (rt1320->dev_id) { - case RT1320_DEV_ID: -+ /* run RAM code */ -+ regmap_read(rt1320->regmap, 0x3fc2bfc0, &val); -+ val |= 0x8; -+ regmap_write(rt1320->regmap, 0x3fc2bfc0, val); -+ /* clear frame counter */ - regmap_write(rt1320->regmap, 0x3fc2bfcb, 0x00); - regmap_write(rt1320->regmap, 0x3fc2bfca, 0x00); - regmap_write(rt1320->regmap, 0x3fc2bfc9, 0x00); - regmap_write(rt1320->regmap, 0x3fc2bfc8, 0x00); - break; - case RT1321_DEV_ID: -+ if (!boot_mode) { -+ /* run RAM code */ -+ regmap_read(rt1320->regmap, 0x3fc2dfc0, &val); -+ val |= 0x8; -+ regmap_write(rt1320->regmap, 0x3fc2dfc0, val); -+ } -+ /* clear frame counter */ - regmap_write(rt1320->regmap, 0x3fc2dfcb, 0x00); - regmap_write(rt1320->regmap, 0x3fc2dfca, 0x00); - regmap_write(rt1320->regmap, 0x3fc2dfc9, 0x00); - regmap_write(rt1320->regmap, 0x3fc2dfc8, 0x00); -+ /* enable handshake */ -+ regmap_write(rt1320->regmap, 0x3fc2dfc4, 0x00); -+ regmap_write(rt1320->regmap, 0xd470, 0xad); -+ /* minimum phase settings */ -+ regmap_write(rt1320->regmap, 0xc5c4, 0x10); -+ regmap_write(rt1320->regmap, 0x20003003, 0x31); -+ regmap_update_bits(rt1320->regmap, 0x20003002, 0x40, 0x00); -+ regmap_write(rt1320->regmap, 0xc5b3, 0x01); -+ regmap_write(rt1320->regmap, 0xc052, 0x11); - break; - } - -@@ -1843,14 +2375,35 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) - - static void rt1321_preset(struct rt1320_sdw_priv *rt1320) - { -+ const struct reg_sequence *blindwrite; - unsigned int i, reg, val, delay; -+ unsigned int array_size; - -- for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) { -- reg = rt1321_blind_write[i].reg; -- val = rt1321_blind_write[i].def; -- delay = rt1321_blind_write[i].delay_us; -+ switch (rt1320->version_id) { -+ case RT1321_VA0: -+ blindwrite = rt1321_blind_write; -+ array_size = ARRAY_SIZE(rt1321_blind_write); -+ break; -+ case RT1321_VA1: -+ blindwrite = rt1321_va1_blind_write; -+ array_size = ARRAY_SIZE(rt1321_va1_blind_write); -+ break; -+ case RT1321_VA2: -+ blindwrite = rt1321_va2_blind_write; -+ array_size = ARRAY_SIZE(rt1321_va2_blind_write); -+ break; -+ default: -+ dev_err(&rt1320->sdw_slave->dev, "%s: Unknown version ID %d\n", -+ __func__, rt1320->version_id); -+ return; -+ } - -- if (reg == 0x3fc2dfc3) -+ for (i = 0; i < array_size; i++) { -+ reg = blindwrite[i].reg; -+ val = blindwrite[i].def; -+ delay = blindwrite[i].delay_us; -+ -+ if (reg == 0x1000cd56) - rt1320_load_mcu_patch(rt1320); - - regmap_write(rt1320->regmap, reg, val); -@@ -1892,6 +2445,24 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) - regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val); - regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp); - rt1320->dev_id = (val << 8) | tmp; -+ -+ /* This is a workaround that reads the value twice to obtain the correct result. */ -+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val); -+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp); -+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val); -+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp); -+ val = (val << 8) | tmp; -+ -+ if (rt1320->dev_id == RT1321_DEV_ID) { -+ if (rt1320->version_id == 0x01) -+ rt1320->version_id = RT1321_VA2; -+ else if (val == RT1321_DEV_HV_VA0_ID) -+ rt1320->version_id = RT1321_VA0; -+ else if (val == RT1321_DEV_HV_VA1_ID) -+ rt1320->version_id = RT1321_VA1; -+ else -+ dev_err(dev, "%s: Unknown version ID 0x%x for RT1321\n", __func__, rt1320->version_id); -+ } - } - - regmap_read(rt1320->regmap, -@@ -2326,25 +2897,12 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); - static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320) - { - struct device *dev = regmap_get_device(rt1320->regmap); -- unsigned int fw_status_addr; -- unsigned int fw_ready; -+ int dspfw_status; - int ret = 0; - - if (!rt1320->r0_l_reg || !rt1320->r0_r_reg) - return -EINVAL; - -- switch (rt1320->dev_id) { -- case RT1320_DEV_ID: -- fw_status_addr = RT1320_DSPFW_STATUS_ADDR; -- break; -- case RT1321_DEV_ID: -- fw_status_addr = RT1321_DSPFW_STATUS_ADDR; -- break; -- default: -- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id); -- return -EINVAL; -- } -- - regmap_write(rt1320->regmap, - SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00); - ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00); -@@ -2353,9 +2911,8 @@ static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320) - goto _timeout_; - } - -- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready); -- fw_ready &= 0x1; -- if (!fw_ready) { -+ dspfw_status = rt1320_dspfw_status(rt1320); -+ if (dspfw_status <= 0) { - dev_dbg(dev, "%s, DSP FW is NOT ready\n", __func__); - goto _timeout_; - } -@@ -2458,7 +3015,7 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol, - if (!rt1320->hw_init) - return 0; - -- ret = pm_runtime_resume(component->dev); -+ ret = pm_runtime_resume_and_get(component->dev); - if (ret < 0 && ret != -EACCES) - return ret; - -@@ -2469,6 +3026,8 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol, - if (!ucontrol->value.integer.value[0]) - rt1320->fw_load_done = false; - -+ pm_runtime_mark_last_busy(component->dev); -+ pm_runtime_put_autosuspend(component->dev); - return 0; - } - -@@ -2819,6 +3378,37 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream, - return 0; - } - -+static int rt1320_bus_config(struct sdw_slave *slave, -+ struct sdw_bus_params *params) -+{ -+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev); -+ unsigned int clk_base; -+ -+ regmap_read(rt1320->regmap, 0x004d, &clk_base); -+ dev_dbg(&rt1320->sdw_slave->dev, "%s clk_base=%x", __func__, clk_base); -+ -+ switch (clk_base) { -+ case RT1320_CLK_FREQ_19_2_MHZ: -+ case RT1320_CLK_FREQ_24MHZ: -+ regmap_write(rt1320->regmap, 0xc600, 0x04); -+ regmap_write(rt1320->regmap, 0xc601, 0x83); -+ regmap_write(rt1320->regmap, 0xc602, 0x1f); -+ regmap_write(rt1320->regmap, 0xc603, 0x40); -+ break; -+ case RT1320_CLK_FREQ_24_576MHZ: -+ case RT1320_CLK_FREQ_22_5792MHZ: -+ regmap_write(rt1320->regmap, 0xc600, 0x07); -+ regmap_write(rt1320->regmap, 0xc601, 0x80); -+ regmap_write(rt1320->regmap, 0xc602, 0x0f); -+ regmap_write(rt1320->regmap, 0xc603, 0x40); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ - /* - * slave_ops: callbacks for get_clock_stop_mode, clock_stop and - * port_prep are not defined for now -@@ -2826,12 +3416,13 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream, - static const struct sdw_slave_ops rt1320_slave_ops = { - .read_prop = rt1320_read_prop, - .update_status = rt1320_update_status, -+ .bus_config = rt1320_bus_config, - }; - - static int rt1320_sdw_component_probe(struct snd_soc_component *component) - { -- int ret; - struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); -+ int ret; - - rt1320->component = component; - -@@ -3062,10 +3653,23 @@ static int rt1320_dev_resume(struct device *dev) - return ret; - - regcache_cache_only(rt1320->regmap, false); -- regcache_sync(rt1320->regmap); -+ ret = regcache_sync(rt1320->regmap); -+ if (ret) -+ goto err_sync; -+ - regcache_cache_only(rt1320->mbq_regmap, false); -- regcache_sync(rt1320->mbq_regmap); -+ ret = regcache_sync(rt1320->mbq_regmap); -+ if (ret) -+ goto err_sync; -+ - return 0; -+ -+err_sync: -+ regcache_cache_only(rt1320->regmap, true); -+ regcache_cache_only(rt1320->mbq_regmap, true); -+ regcache_mark_dirty(rt1320->regmap); -+ regcache_mark_dirty(rt1320->mbq_regmap); -+ return ret; - } - - static const struct dev_pm_ops rt1320_pm = { -diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h ---- a/sound/soc/codecs/rt1320-sdw.h -+++ b/sound/soc/codecs/rt1320-sdw.h -@@ -17,12 +17,17 @@ - - #define RT1320_DEV_ID 0x6981 - #define RT1321_DEV_ID 0x7045 -+#define RT1321_DEV_HV_VA0_ID 0x6997 -+#define RT1321_DEV_HV_VA1_ID 0x7071 - - /* imp-defined registers */ - #define RT1320_DEV_VERSION_ID_1 0xc404 - #define RT1320_DEV_ID_1 0xc405 - #define RT1320_DEV_ID_0 0xc406 - -+#define RT1320_HV_DEV_ID_0 0xf622 -+#define RT1320_HV_DEV_ID_1 0xf623 -+ - #define RT1320_POWER_STATE 0xc560 - - #define RT1321_PATCH_MAIN_VER 0x1000cffe -@@ -94,6 +99,12 @@ enum rt1320_version_id { - RT1320_VC, - }; - -+enum rt1321_version_id { -+ RT1321_VA0, -+ RT1321_VA1, -+ RT1321_VA2, -+}; -+ - #define RT1320_VER_B_ID 0x07392238 - #define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin" - #define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin" -@@ -121,6 +132,7 @@ struct rt1320_datafixpoint { - int invrs; - }; - -+/* FW parameter id 1300 */ - typedef struct FwPara_HwSwGain { - unsigned int SwAdvGain; - unsigned int SwBasGain; -@@ -163,6 +175,13 @@ enum rt1320_rw_type { - RT1320_PARAM_READ = 3, - }; - -+enum { -+ RT1320_CLK_FREQ_19_2_MHZ = 1, -+ RT1320_CLK_FREQ_24MHZ = 2, -+ RT1320_CLK_FREQ_24_576MHZ = 3, -+ RT1320_CLK_FREQ_22_5792MHZ = 4, -+}; -+ - struct rt1320_sdw_priv { - struct snd_soc_component *component; - struct regmap *regmap; -diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c ---- a/sound/soc/codecs/rt5514-spi.c -+++ b/sound/soc/codecs/rt5514-spi.c -@@ -6,6 +6,7 @@ - * Author: Oder Chiou - */ - -+#include - #include - #include - #include -@@ -79,17 +80,17 @@ static void rt5514_spi_copy_work(struct work_struct *work) - unsigned int cur_wp, remain_data; - u8 buf[8]; - -- mutex_lock(&rt5514_dsp->dma_lock); -+ guard(mutex)(&rt5514_dsp->dma_lock); - if (!rt5514_dsp->substream) { - dev_err(rt5514_dsp->dev, "No pcm substream\n"); -- goto done; -+ return; - } - - runtime = rt5514_dsp->substream->runtime; - period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); - if (!period_bytes) { - schedule_delayed_work(&rt5514_dsp->copy_work, 5); -- goto done; -+ return; - } - - if (rt5514_dsp->buf_size % period_bytes) -@@ -111,7 +112,7 @@ static void rt5514_spi_copy_work(struct work_struct *work) - - if (remain_data < period_bytes) { - schedule_delayed_work(&rt5514_dsp->copy_work, 5); -- goto done; -+ return; - } - } - -@@ -146,9 +147,6 @@ static void rt5514_spi_copy_work(struct work_struct *work) - snd_pcm_period_elapsed(rt5514_dsp->substream); - - schedule_delayed_work(&rt5514_dsp->copy_work, 5); -- --done: -- mutex_unlock(&rt5514_dsp->dma_lock); - } - - static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) -@@ -216,7 +214,7 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component, - snd_soc_component_get_drvdata(component); - u8 buf[8]; - -- mutex_lock(&rt5514_dsp->dma_lock); -+ guard(mutex)(&rt5514_dsp->dma_lock); - rt5514_dsp->substream = substream; - rt5514_dsp->dma_offset = 0; - -@@ -225,8 +223,6 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component, - if (buf[0] & RT5514_IRQ_STATUS_BIT) - rt5514_schedule_copy(rt5514_dsp); - -- mutex_unlock(&rt5514_dsp->dma_lock); -- - return 0; - } - -@@ -236,9 +232,8 @@ static int rt5514_spi_hw_free(struct snd_soc_component *component, - struct rt5514_dsp *rt5514_dsp = - snd_soc_component_get_drvdata(component); - -- mutex_lock(&rt5514_dsp->dma_lock); -- rt5514_dsp->substream = NULL; -- mutex_unlock(&rt5514_dsp->dma_lock); -+ scoped_guard(mutex, &rt5514_dsp->dma_lock) -+ rt5514_dsp->substream = NULL; - - cancel_delayed_work_sync(&rt5514_dsp->copy_work); - -diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c ---- a/sound/soc/codecs/rt5514.c -+++ b/sound/soc/codecs/rt5514.c -@@ -1073,12 +1073,18 @@ static int rt5514_set_bias_level(struct snd_soc_component *component, - * settings to make sure recording properly. - */ - if (rt5514->dsp_enabled) { -- rt5514->dsp_enabled = 0; -- regmap_multi_reg_write(rt5514->i2c_regmap, -- rt5514_i2c_patch, -- ARRAY_SIZE(rt5514_i2c_patch)); -+ ret = regmap_multi_reg_write(rt5514->i2c_regmap, -+ rt5514_i2c_patch, -+ ARRAY_SIZE(rt5514_i2c_patch)); -+ if (ret) -+ return ret; -+ - regcache_mark_dirty(rt5514->regmap); -- regcache_sync(rt5514->regmap); -+ ret = regcache_sync(rt5514->regmap); -+ if (ret) -+ return ret; -+ -+ rt5514->dsp_enabled = 0; - } - } - break; -diff --git a/sound/soc/codecs/rt5575-spi.c b/sound/soc/codecs/rt5575-spi.c ---- a/sound/soc/codecs/rt5575-spi.c -+++ b/sound/soc/codecs/rt5575-spi.c -@@ -93,7 +93,6 @@ static void rt5575_spi_burst_write(struct spi_device *spi, u32 addr, const u8 *t - int rt5575_spi_fw_load(struct spi_device *spi) - { - struct device *dev = &spi->dev; -- const struct firmware *firmware; - int i, ret; - static const char * const fw_path[] = { - "realtek/rt5575/rt5575_fw1.bin", -@@ -104,6 +103,7 @@ int rt5575_spi_fw_load(struct spi_device *spi) - static const u32 fw_addr[] = { 0x5f400000, 0x5f600000, 0x5f7fe000, 0x5f7ff000 }; - - for (i = 0; i < ARRAY_SIZE(fw_addr); i++) { -+ const struct firmware *firmware __free(firmware) = NULL; - ret = request_firmware(&firmware, fw_path[i], dev); - if (ret) { - dev_err(dev, "Request firmware failure: %d\n", ret); -@@ -111,7 +111,6 @@ int rt5575_spi_fw_load(struct spi_device *spi) - } - - rt5575_spi_burst_write(spi, fw_addr[i], firmware->data, firmware->size); -- release_firmware(firmware); - } - - return 0; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -6,6 +6,7 @@ - * Author: Bard Liao - */ - -+#include - #include - #include - #include -@@ -3323,92 +3324,89 @@ static void rt5645_jack_detect_work(struct work_struct *work) - if (!rt5645->component) - return; - -- mutex_lock(&rt5645->jd_mutex); -- -- switch (rt5645->pdata.jd_mode) { -- case 0: /* Not using rt5645 JD */ -- if (rt5645->gpiod_hp_det) { -- gpio_state = gpiod_get_value(rt5645->gpiod_hp_det); -- if (rt5645->pdata.inv_hp_pol) -- gpio_state ^= 1; -- dev_dbg(rt5645->component->dev, "gpio_state = %d\n", -- gpio_state); -- report = rt5645_jack_detect(rt5645->component, gpio_state); -- } -- snd_soc_jack_report(rt5645->hp_jack, -- report, SND_JACK_HEADPHONE); -- snd_soc_jack_report(rt5645->mic_jack, -- report, SND_JACK_MICROPHONE); -- mutex_unlock(&rt5645->jd_mutex); -- return; -- case 4: -- val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; -- break; -- default: /* read rt5645 jd1_1 status */ -- val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; -- break; -- -- } -- -- if (!val && (rt5645->jack_type == 0)) { /* jack in */ -- report = rt5645_jack_detect(rt5645->component, 1); -- } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) { -- /* for push button and jack out */ -- btn_type = 0; -- if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) { -- /* button pressed */ -- report = SND_JACK_HEADSET; -- btn_type = rt5645_button_detect(rt5645->component); -- /* rt5650 can report three kinds of button behavior, -- one click, double click and hold. However, -- currently we will report button pressed/released -- event. So all the three button behaviors are -- treated as button pressed. */ -- switch (btn_type) { -- case 0x8000: -- case 0x4000: -- case 0x2000: -- report |= SND_JACK_BTN_0; -- break; -- case 0x1000: -- case 0x0800: -- case 0x0400: -- report |= SND_JACK_BTN_1; -- break; -- case 0x0200: -- case 0x0100: -- case 0x0080: -- report |= SND_JACK_BTN_2; -- break; -- case 0x0040: -- case 0x0020: -- case 0x0010: -- report |= SND_JACK_BTN_3; -- break; -- case 0x0000: /* unpressed */ -- break; -- default: -- dev_err(rt5645->component->dev, -- "Unexpected button code 0x%04x\n", -- btn_type); -- break; -+ scoped_guard(mutex, &rt5645->jd_mutex) { -+ switch (rt5645->pdata.jd_mode) { -+ case 0: /* Not using rt5645 JD */ -+ if (rt5645->gpiod_hp_det) { -+ gpio_state = gpiod_get_value(rt5645->gpiod_hp_det); -+ if (rt5645->pdata.inv_hp_pol) -+ gpio_state ^= 1; -+ dev_dbg(rt5645->component->dev, "gpio_state = %d\n", -+ gpio_state); -+ report = rt5645_jack_detect(rt5645->component, gpio_state); - } -+ snd_soc_jack_report(rt5645->hp_jack, -+ report, SND_JACK_HEADPHONE); -+ snd_soc_jack_report(rt5645->mic_jack, -+ report, SND_JACK_MICROPHONE); -+ return; -+ case 4: -+ val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020; -+ break; -+ default: /* read rt5645 jd1_1 status */ -+ val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000; -+ break; - } -- if (btn_type == 0)/* button release */ -- report = rt5645->jack_type; -- else { -- mod_timer(&rt5645->btn_check_timer, -- msecs_to_jiffies(100)); -- } -- } else { -- /* jack out */ -- report = 0; -- snd_soc_component_update_bits(rt5645->component, -- RT5645_INT_IRQ_ST, 0x1, 0x0); -- rt5645_jack_detect(rt5645->component, 0); -- } - -- mutex_unlock(&rt5645->jd_mutex); -+ if (!val && rt5645->jack_type == 0) { /* jack in */ -+ report = rt5645_jack_detect(rt5645->component, 1); -+ } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) { -+ /* for push button and jack out */ -+ btn_type = 0; -+ if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) { -+ /* button pressed */ -+ report = SND_JACK_HEADSET; -+ btn_type = rt5645_button_detect(rt5645->component); -+ /* -+ * rt5650 can report three kinds of button behavior, -+ * one click, double click and hold. However, -+ * currently we will report button pressed/released -+ * event. So all the three button behaviors are -+ * treated as button pressed. -+ */ -+ switch (btn_type) { -+ case 0x8000: -+ case 0x4000: -+ case 0x2000: -+ report |= SND_JACK_BTN_0; -+ break; -+ case 0x1000: -+ case 0x0800: -+ case 0x0400: -+ report |= SND_JACK_BTN_1; -+ break; -+ case 0x0200: -+ case 0x0100: -+ case 0x0080: -+ report |= SND_JACK_BTN_2; -+ break; -+ case 0x0040: -+ case 0x0020: -+ case 0x0010: -+ report |= SND_JACK_BTN_3; -+ break; -+ case 0x0000: /* unpressed */ -+ break; -+ default: -+ dev_err(rt5645->component->dev, -+ "Unexpected button code 0x%04x\n", -+ btn_type); -+ break; -+ } -+ } -+ if (btn_type == 0)/* button release */ -+ report = rt5645->jack_type; -+ else -+ mod_timer(&rt5645->btn_check_timer, -+ msecs_to_jiffies(100)); -+ } else { -+ /* jack out */ -+ report = 0; -+ snd_soc_component_update_bits(rt5645->component, -+ RT5645_INT_IRQ_ST, 0x1, 0x0); -+ rt5645_jack_detect(rt5645->component, 0); -+ } -+ } - - snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE); - snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); -@@ -3522,9 +3520,15 @@ static int rt5645_suspend(struct snd_soc_component *component) - static int rt5645_resume(struct snd_soc_component *component) - { - struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); -+ int ret; - - regcache_cache_only(rt5645->regmap, false); -- regcache_sync(rt5645->regmap); -+ ret = regcache_sync(rt5645->regmap); -+ if (ret) { -+ regcache_cache_only(rt5645->regmap, true); -+ regcache_mark_dirty(rt5645->regmap); -+ return ret; -+ } - - return 0; - } -@@ -4335,9 +4339,15 @@ static int rt5645_sys_suspend(struct device *dev) - static int rt5645_sys_resume(struct device *dev) - { - struct rt5645_priv *rt5645 = dev_get_drvdata(dev); -+ int ret; - - regcache_cache_only(rt5645->regmap, false); -- regcache_sync(rt5645->regmap); -+ ret = regcache_sync(rt5645->regmap); -+ if (ret) { -+ regcache_cache_only(rt5645->regmap, true); -+ regcache_mark_dirty(rt5645->regmap); -+ return ret; -+ } - - if (rt5645->hp_jack) { - rt5645->jack_type = 0; -diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c ---- a/sound/soc/codecs/rt5665.c -+++ b/sound/soc/codecs/rt5665.c -@@ -6,6 +6,7 @@ - * Author: Bard Liao - */ - -+#include - #include - #include - #include -@@ -1208,7 +1209,7 @@ static void rt5665_jack_detect_handler(struct work_struct *work) - usleep_range(10000, 15000); - } - -- mutex_lock(&rt5665->calibrate_mutex); -+ guard(mutex)(&rt5665->calibrate_mutex); - - val = snd_soc_component_read(rt5665->component, RT5665_AJD1_CTRL) & 0x0010; - if (!val) { -@@ -1274,8 +1275,6 @@ static void rt5665_jack_detect_handler(struct work_struct *work) - schedule_delayed_work(&rt5665->jd_check_work, 0); - else - cancel_delayed_work_sync(&rt5665->jd_check_work); -- -- mutex_unlock(&rt5665->calibrate_mutex); - } - - static const char * const rt5665_clk_sync[] = { -@@ -4564,7 +4563,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) - { - int value, count; - -- mutex_lock(&rt5665->calibrate_mutex); -+ guard(mutex)(&rt5665->calibrate_mutex); - - regcache_cache_bypass(rt5665->regmap, true); - -@@ -4601,7 +4600,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) - pr_err("HP Calibration Failure\n"); - regmap_write(rt5665->regmap, RT5665_RESET, 0); - regcache_cache_bypass(rt5665->regmap, false); -- goto out_unlock; -+ rt5665->calibration_done = true; -+ return; - } - - count++; -@@ -4620,7 +4620,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) - pr_err("MONO Calibration Failure\n"); - regmap_write(rt5665->regmap, RT5665_RESET, 0); - regcache_cache_bypass(rt5665->regmap, false); -- goto out_unlock; -+ rt5665->calibration_done = true; -+ return; - } - - count++; -@@ -4635,9 +4636,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) - regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); - regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); - --out_unlock: - rt5665->calibration_done = true; -- mutex_unlock(&rt5665->calibrate_mutex); - } - - static void rt5665_calibrate_handler(struct work_struct *work) -diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c ---- a/sound/soc/codecs/rt5668.c -+++ b/sound/soc/codecs/rt5668.c -@@ -6,6 +6,7 @@ - * Author: Bard Liao - */ - -+#include - #include - #include - #include -@@ -986,7 +987,7 @@ static void rt5668_jack_detect_handler(struct work_struct *work) - return; - } - -- mutex_lock(&rt5668->calibrate_mutex); -+ guard(mutex)(&rt5668->calibrate_mutex); - - val = snd_soc_component_read(rt5668->component, RT5668_AJD1_CTRL) - & RT5668_JDH_RS_MASK; -@@ -1053,8 +1054,6 @@ static void rt5668_jack_detect_handler(struct work_struct *work) - schedule_delayed_work(&rt5668->jd_check_work, 0); - else - cancel_delayed_work_sync(&rt5668->jd_check_work); -- -- mutex_unlock(&rt5668->calibrate_mutex); - } - - static const struct snd_kcontrol_new rt5668_snd_controls[] = { -@@ -2356,7 +2355,7 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) - { - int value, count; - -- mutex_lock(&rt5668->calibrate_mutex); -+ guard(mutex)(&rt5668->calibrate_mutex); - - rt5668_reset(rt5668->regmap); - regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xa2bf); -@@ -2400,9 +2399,6 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668) - /* restore settings */ - regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0xc0c4); - regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x0000); -- -- mutex_unlock(&rt5668->calibrate_mutex); -- - } - - static int rt5668_i2c_probe(struct i2c_client *i2c) -diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c ---- a/sound/soc/codecs/rt5677-spi.c -+++ b/sound/soc/codecs/rt5677-spi.c -@@ -6,6 +6,7 @@ - * Author: Oder Chiou - */ - -+#include - #include - #include - #include -@@ -133,9 +134,8 @@ static int rt5677_spi_hw_params( - struct rt5677_dsp *rt5677_dsp = - snd_soc_component_get_drvdata(component); - -- mutex_lock(&rt5677_dsp->dma_lock); -+ guard(mutex)(&rt5677_dsp->dma_lock); - rt5677_dsp->substream = substream; -- mutex_unlock(&rt5677_dsp->dma_lock); - - return 0; - } -@@ -147,9 +147,8 @@ static int rt5677_spi_hw_free( - struct rt5677_dsp *rt5677_dsp = - snd_soc_component_get_drvdata(component); - -- mutex_lock(&rt5677_dsp->dma_lock); -+ guard(mutex)(&rt5677_dsp->dma_lock); - rt5677_dsp->substream = NULL; -- mutex_unlock(&rt5677_dsp->dma_lock); - - return 0; - } -@@ -311,17 +310,17 @@ static void rt5677_spi_copy_work(struct work_struct *work) - int ret = 0; - - /* Ensure runtime->dma_area buffer does not go away while copying. */ -- mutex_lock(&rt5677_dsp->dma_lock); -+ guard(mutex)(&rt5677_dsp->dma_lock); - if (!rt5677_dsp->substream) { - dev_err(rt5677_dsp->dev, "No pcm substream\n"); -- goto done; -+ return; - } - - runtime = rt5677_dsp->substream->runtime; - - if (rt5677_spi_mic_write_offset(&mic_write_offset)) { - dev_err(rt5677_dsp->dev, "No mic_write_offset\n"); -- goto done; -+ return; - } - - /* If this is the first time that we've asked for streaming data after -@@ -355,7 +354,7 @@ static void rt5677_spi_copy_work(struct work_struct *work) - ret = rt5677_spi_copy(rt5677_dsp, copy_bytes); - if (ret) { - dev_err(rt5677_dsp->dev, "Copy failed %d\n", ret); -- goto done; -+ return; - } - rt5677_dsp->avail_bytes += copy_bytes; - if (rt5677_dsp->avail_bytes >= period_bytes) { -@@ -367,8 +366,6 @@ static void rt5677_spi_copy_work(struct work_struct *work) - - delay = bytes_to_frames(runtime, period_bytes) / runtime->rate; - schedule_delayed_work(&rt5677_dsp->copy_work, secs_to_jiffies(delay)); --done: -- mutex_unlock(&rt5677_dsp->dma_lock); - } - - static int rt5677_spi_pcm_new(struct snd_soc_component *component, -@@ -507,10 +504,8 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) - header[3] = ((addr + offset) & 0x0000ff00) >> 8; - header[4] = ((addr + offset) & 0x000000ff) >> 0; - -- mutex_lock(&spi_mutex); -- status |= spi_sync(g_spi, &m); -- mutex_unlock(&spi_mutex); -- -+ scoped_guard(mutex, &spi_mutex) -+ status |= spi_sync(g_spi, &m); - - /* Copy data back to caller buffer */ - rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len); -@@ -564,9 +559,8 @@ int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) - offset += t.len; - t.len += RT5677_SPI_HEADER + 1; - -- mutex_lock(&spi_mutex); -- status |= spi_sync(g_spi, &m); -- mutex_unlock(&spi_mutex); -+ scoped_guard(mutex, &spi_mutex) -+ status |= spi_sync(g_spi, &m); - } - return status; - } -@@ -591,10 +585,10 @@ void rt5677_spi_hotword_detected(void) - return; - } - -- mutex_lock(&rt5677_dsp->dma_lock); -- dev_info(rt5677_dsp->dev, "Hotword detected\n"); -- rt5677_dsp->new_hotword = true; -- mutex_unlock(&rt5677_dsp->dma_lock); -+ scoped_guard(mutex, &rt5677_dsp->dma_lock) { -+ dev_info(rt5677_dsp->dev, "Hotword detected\n"); -+ rt5677_dsp->new_hotword = true; -+ } - - schedule_delayed_work(&rt5677_dsp->copy_work, 0); - } -diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c ---- a/sound/soc/codecs/rt5677.c -+++ b/sound/soc/codecs/rt5677.c -@@ -6,6 +6,8 @@ - * Author: Oder Chiou - */ - -+#include -+#include - #include - #include - #include -@@ -563,46 +565,43 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, - struct snd_soc_component *component = rt5677->component; - int ret; - -- mutex_lock(&rt5677->dsp_cmd_lock); -+ guard(mutex)(&rt5677->dsp_cmd_lock); - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, - addr >> 16); - if (ret < 0) { - dev_err(component->dev, "Failed to set addr msb value: %d\n", ret); -- goto err; -+ return ret; - } - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, - addr & 0xffff); - if (ret < 0) { - dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret); -- goto err; -+ return ret; - } - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, - value >> 16); - if (ret < 0) { - dev_err(component->dev, "Failed to set data msb value: %d\n", ret); -- goto err; -+ return ret; - } - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, - value & 0xffff); - if (ret < 0) { - dev_err(component->dev, "Failed to set data lsb value: %d\n", ret); -- goto err; -+ return ret; - } - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, - opcode); - if (ret < 0) { - dev_err(component->dev, "Failed to set op code value: %d\n", ret); -- goto err; -+ return ret; - } - --err: -- mutex_unlock(&rt5677->dsp_cmd_lock); -- - return ret; - } - -@@ -622,36 +621,33 @@ static int rt5677_dsp_mode_i2c_read_addr( - int ret; - unsigned int msb, lsb; - -- mutex_lock(&rt5677->dsp_cmd_lock); -+ guard(mutex)(&rt5677->dsp_cmd_lock); - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, - addr >> 16); - if (ret < 0) { - dev_err(component->dev, "Failed to set addr msb value: %d\n", ret); -- goto err; -+ return ret; - } - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, - addr & 0xffff); - if (ret < 0) { - dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret); -- goto err; -+ return ret; - } - - ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, - 0x0002); - if (ret < 0) { - dev_err(component->dev, "Failed to set op code value: %d\n", ret); -- goto err; -+ return ret; - } - - regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb); - regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb); - *value = (msb << 16) | lsb; - --err: -- mutex_unlock(&rt5677->dsp_cmd_lock); -- - return ret; - } - -@@ -853,11 +849,11 @@ static int rt5677_parse_and_load_dsp(struct rt5677_priv *rt5677, const u8 *buf, - - static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677) - { -- const struct firmware *fwp; - struct device *dev = rt5677->component->dev; -- int ret = 0; -+ int ret; - - /* Load dsp firmware from rt5677_elf_vad file */ -+ const struct firmware *fwp __free(firmware) = NULL; - ret = request_firmware(&fwp, "rt5677_elf_vad", dev); - if (ret) { - dev_err(dev, "Request rt5677_elf_vad failed %d\n", ret); -@@ -865,9 +861,7 @@ static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677) - } - dev_info(dev, "Requested rt5677_elf_vad (%zu)\n", fwp->size); - -- ret = rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size); -- release_firmware(fwp); -- return ret; -+ return rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size); - } - - static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on) -@@ -940,21 +934,20 @@ static void rt5677_dsp_work(struct work_struct *work) - activity = false; - - /* Don't turn off the DSP while handling irqs */ -- mutex_lock(&rt5677->irq_lock); -- /* Set DSP CPU to Stop */ -- regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, -- RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); -+ scoped_guard(mutex, &rt5677->irq_lock) { -+ /* Set DSP CPU to Stop */ -+ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, -+ RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU); - -- rt5677_set_dsp_mode(rt5677, false); -+ rt5677_set_dsp_mode(rt5677, false); - -- /* Disable and clear VAD interrupt */ -- regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); -+ /* Disable and clear VAD interrupt */ -+ regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184); - -- /* Set GPIO1 pin back to be IRQ output for jack detect */ -- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, -- RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); -- -- mutex_unlock(&rt5677->irq_lock); -+ /* Set GPIO1 pin back to be IRQ output for jack detect */ -+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, -+ RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ); -+ } - } - } - -@@ -4767,6 +4760,21 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) - return rt5677_update_gpio_bits(rt5677, offset, m, v); - } - -+static int rt5677_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) -+{ -+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip); -+ unsigned int shift = RT5677_GPIOx_DIR_SFT + (offset % 5) * 3; -+ unsigned int bank = offset / 5; -+ unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2; -+ int ret; -+ -+ ret = regmap_test_bits(rt5677->regmap, reg, BIT(shift)); -+ if (ret < 0) -+ return ret; -+ -+ return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; -+} -+ - /* - * Configures the GPIO as - * 0 - floating -@@ -4834,6 +4842,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) - static const struct gpio_chip rt5677_template_chip = { - .label = RT5677_DRV_NAME, - .owner = THIS_MODULE, -+ .get_direction = rt5677_gpio_get_direction, - .direction_output = rt5677_gpio_direction_out, - .set = rt5677_gpio_set, - .direction_input = rt5677_gpio_direction_in, -@@ -4980,11 +4989,11 @@ static int rt5677_read(void *context, unsigned int reg, unsigned int *val) - - if (rt5677->is_dsp_mode) { - if (reg > 0xff) { -- mutex_lock(&rt5677->dsp_pri_lock); -- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, -- reg & 0xff); -- rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); -- mutex_unlock(&rt5677->dsp_pri_lock); -+ scoped_guard(mutex, &rt5677->dsp_pri_lock) { -+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, -+ reg & 0xff); -+ rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); -+ } - } else { - rt5677_dsp_mode_i2c_read(rt5677, reg, val); - } -@@ -5002,12 +5011,12 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val) - - if (rt5677->is_dsp_mode) { - if (reg > 0xff) { -- mutex_lock(&rt5677->dsp_pri_lock); -- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, -- reg & 0xff); -- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, -- val); -- mutex_unlock(&rt5677->dsp_pri_lock); -+ scoped_guard(mutex, &rt5677->dsp_pri_lock) { -+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, -+ reg & 0xff); -+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, -+ val); -+ } - } else { - rt5677_dsp_mode_i2c_write(rt5677, reg, val); - } -@@ -5399,7 +5408,7 @@ static void rt5677_resume_irq_check(struct work_struct *work) - * Without this explicit check, unplug the headset right after suspend - * starts, then after resume the headset is still shown as plugged in. - */ -- mutex_lock(&rt5677->irq_lock); -+ guard(mutex)(&rt5677->irq_lock); - for (i = 0; i < RT5677_IRQ_NUM; i++) { - if (rt5677->irq_en & rt5677_irq_descs[i].enable_mask) { - virq = irq_find_mapping(rt5677->domain, i); -@@ -5407,7 +5416,6 @@ static void rt5677_resume_irq_check(struct work_struct *work) - handle_nested_irq(virq); - } - } -- mutex_unlock(&rt5677->irq_lock); - } - - static void rt5677_irq_bus_lock(struct irq_data *data) -diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c ---- a/sound/soc/codecs/rt5682-sdw.c -+++ b/sound/soc/codecs/rt5682-sdw.c -@@ -6,6 +6,7 @@ - // Author: Oder Chiou - // - -+#include - #include - #include - #include -@@ -410,7 +411,9 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) - if (rt5682->first_hw_init) { - regcache_cache_bypass(rt5682->regmap, false); - regcache_mark_dirty(rt5682->regmap); -- regcache_sync(rt5682->regmap); -+ ret = regcache_sync(rt5682->regmap); -+ if (ret) -+ goto err_sync; - - /* volatile registers */ - regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2, -@@ -472,8 +475,16 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave) - /* Mark Slave initialization complete */ - rt5682->hw_init = true; - rt5682->first_hw_init = true; -+ goto out; -+ -+err_sync: -+ regcache_cache_bypass(rt5682->regmap, false); -+ regcache_cache_only(rt5682->sdw_regmap, true); -+ regcache_cache_only(rt5682->regmap, true); -+ regcache_mark_dirty(rt5682->regmap); - - err_nodev: -+out: - pm_runtime_put_autosuspend(&slave->dev); - - dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret); -@@ -660,12 +671,11 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave, - dev_dbg(&slave->dev, - "%s control_port_stat=%x", __func__, status->control_port); - -- mutex_lock(&rt5682->disable_irq_lock); -+ guard(mutex)(&rt5682->disable_irq_lock); - if (status->control_port & 0x4 && !rt5682->disable_irq) { - mod_delayed_work(system_power_efficient_wq, - &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time)); - } -- mutex_unlock(&rt5682->disable_irq_lock); - - return 0; - } -@@ -736,11 +746,11 @@ static int rt5682_dev_system_suspend(struct device *dev) - * deferred work completes and before the parent disables - * interrupts on the link - */ -- mutex_lock(&rt5682->disable_irq_lock); -- rt5682->disable_irq = true; -- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, -- SDW_SCP_INT1_IMPL_DEF, 0); -- mutex_unlock(&rt5682->disable_irq_lock); -+ scoped_guard(mutex, &rt5682->disable_irq_lock) { -+ rt5682->disable_irq = true; -+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, -+ SDW_SCP_INT1_IMPL_DEF, 0); -+ } - - if (ret < 0) { - /* log but don't prevent suspend from happening */ -@@ -760,12 +770,12 @@ static int rt5682_dev_resume(struct device *dev) - return 0; - - if (!slave->unattach_request) { -- mutex_lock(&rt5682->disable_irq_lock); -- if (rt5682->disable_irq == true) { -- sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); -- rt5682->disable_irq = false; -+ scoped_guard(mutex, &rt5682->disable_irq_lock) { -+ if (rt5682->disable_irq) { -+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); -+ rt5682->disable_irq = false; -+ } - } -- mutex_unlock(&rt5682->disable_irq_lock); - } - - ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT); -@@ -776,7 +786,13 @@ static int rt5682_dev_resume(struct device *dev) - - regcache_cache_only(rt5682->sdw_regmap, false); - regcache_cache_only(rt5682->regmap, false); -- regcache_sync(rt5682->regmap); -+ ret = regcache_sync(rt5682->regmap); -+ if (ret) { -+ regcache_cache_only(rt5682->sdw_regmap, true); -+ regcache_cache_only(rt5682->regmap, true); -+ regcache_mark_dirty(rt5682->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c ---- a/sound/soc/codecs/rt5682.c -+++ b/sound/soc/codecs/rt5682.c -@@ -6,6 +6,7 @@ - // Author: Bard Liao - // - -+#include - #include - #include - #include -@@ -3125,7 +3126,7 @@ void rt5682_calibrate(struct rt5682_priv *rt5682) - { - int value, count; - -- mutex_lock(&rt5682->calibrate_mutex); -+ guard(mutex)(&rt5682->calibrate_mutex); - - rt5682_reset(rt5682); - regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f); -@@ -3175,8 +3176,6 @@ void rt5682_calibrate(struct rt5682_priv *rt5682) - regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); - regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0c0c); -- -- mutex_unlock(&rt5682->calibrate_mutex); - } - EXPORT_SYMBOL_GPL(rt5682_calibrate); - -diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c ---- a/sound/soc/codecs/rt5682s.c -+++ b/sound/soc/codecs/rt5682s.c -@@ -6,6 +6,7 @@ - // Author: Derek Fang - // - -+#include - #include - #include - #include -@@ -648,7 +649,7 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode - { - struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component); - -- mutex_lock(&rt5682s->sar_mutex); -+ guard(mutex)(&rt5682s->sar_mutex); - - switch (mode) { - case SAR_PWR_SAVING: -@@ -695,8 +696,6 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode - dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode); - break; - } -- -- mutex_unlock(&rt5682s->sar_mutex); - } - - static void rt5682s_enable_push_button_irq(struct snd_soc_component *component) -@@ -2534,7 +2533,7 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) - if (!rt5682s_clk_check(rt5682s)) - return -EINVAL; - -- mutex_lock(&rt5682s->wclk_mutex); -+ guard(mutex)(&rt5682s->wclk_mutex); - - snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, - RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, -@@ -2556,8 +2555,6 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw) - - rt5682s->wclk_enabled = 1; - -- mutex_unlock(&rt5682s->wclk_mutex); -- - return 0; - } - -@@ -2570,7 +2567,7 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) - if (!rt5682s_clk_check(rt5682s)) - return; - -- mutex_lock(&rt5682s->wclk_mutex); -+ guard(mutex)(&rt5682s->wclk_mutex); - - if (!rt5682s->jack_type) - snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1, -@@ -2585,8 +2582,6 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw) - rt5682s_set_pllb_power(rt5682s, 0); - - rt5682s->wclk_enabled = 0; -- -- mutex_unlock(&rt5682s->wclk_mutex); - } - - static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw, -@@ -2997,7 +2992,7 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) - { - unsigned int count, value; - -- mutex_lock(&rt5682s->calibrate_mutex); -+ guard(mutex)(&rt5682s->calibrate_mutex); - - regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xaa80); - usleep_range(15000, 20000); -@@ -3034,8 +3029,6 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s) - regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x00c0); - regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0x0800); - regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x0000); -- -- mutex_unlock(&rt5682s->calibrate_mutex); - } - - static const struct regmap_config rt5682s_regmap = { -diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c ---- a/sound/soc/codecs/rt700-sdw.c -+++ b/sound/soc/codecs/rt700-sdw.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -415,12 +416,11 @@ static int rt700_interrupt_callback(struct sdw_slave *slave, - dev_dbg(&slave->dev, - "%s control_port_stat=%x", __func__, status->control_port); - -- mutex_lock(&rt700->disable_irq_lock); -+ guard(mutex)(&rt700->disable_irq_lock); - if (status->control_port & 0x4 && !rt700->disable_irq) { - mod_delayed_work(system_power_efficient_wq, - &rt700->jack_detect_work, msecs_to_jiffies(250)); - } -- mutex_unlock(&rt700->disable_irq_lock); - - return 0; - } -@@ -499,11 +499,11 @@ static int rt700_dev_system_suspend(struct device *dev) - * deferred work completes and before the parent disables - * interrupts on the link - */ -- mutex_lock(&rt700->disable_irq_lock); -- rt700->disable_irq = true; -- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, -- SDW_SCP_INT1_IMPL_DEF, 0); -- mutex_unlock(&rt700->disable_irq_lock); -+ scoped_guard(mutex, &rt700->disable_irq_lock) { -+ rt700->disable_irq = true; -+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, -+ SDW_SCP_INT1_IMPL_DEF, 0); -+ } - - if (ret < 0) { - /* log but don't prevent suspend from happening */ -diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c ---- a/sound/soc/codecs/rt711-sdca-sdw.c -+++ b/sound/soc/codecs/rt711-sdca-sdw.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -415,13 +416,13 @@ static int rt711_sdca_dev_system_suspend(struct device *dev) - * deferred work completes and before the parent disables - * interrupts on the link - */ -- mutex_lock(&rt711_sdca->disable_irq_lock); -- rt711_sdca->disable_irq = true; -- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -- SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -- SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -- mutex_unlock(&rt711_sdca->disable_irq_lock); -+ scoped_guard(mutex, &rt711_sdca->disable_irq_lock) { -+ rt711_sdca->disable_irq = true; -+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -+ } - - if (ret1 < 0 || ret2 < 0) { - /* log but don't prevent suspend from happening */ -@@ -443,13 +444,15 @@ static int rt711_sdca_dev_resume(struct device *dev) - return 0; - - if (!slave->unattach_request) { -- mutex_lock(&rt711->disable_irq_lock); -- if (rt711->disable_irq == true) { -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); -- rt711->disable_irq = false; -+ scoped_guard(mutex, &rt711->disable_irq_lock) { -+ if (rt711->disable_irq) { -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0); -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8); -+ rt711->disable_irq = false; -+ } - } -- mutex_unlock(&rt711->disable_irq_lock); - } - - ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT); -diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c ---- a/sound/soc/codecs/rt711-sdca.c -+++ b/sound/soc/codecs/rt711-sdca.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -450,7 +451,7 @@ static void rt711_sdca_btn_check_handler(struct work_struct *work) - - static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) - { -- mutex_lock(&rt711->calibrate_mutex); -+ guard(mutex)(&rt711->calibrate_mutex); - - if (rt711->hs_jack) { - /* Enable HID1 event & set button RTC mode */ -@@ -515,8 +516,6 @@ static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) - - dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__); - } -- -- mutex_unlock(&rt711->calibrate_mutex); - } - - static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c ---- a/sound/soc/codecs/rt711-sdw.c -+++ b/sound/soc/codecs/rt711-sdw.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -422,12 +423,11 @@ static int rt711_interrupt_callback(struct sdw_slave *slave, - dev_dbg(&slave->dev, - "%s control_port_stat=%x", __func__, status->control_port); - -- mutex_lock(&rt711->disable_irq_lock); -+ guard(mutex)(&rt711->disable_irq_lock); - if (status->control_port & 0x4 && !rt711->disable_irq) { - mod_delayed_work(system_power_efficient_wq, - &rt711->jack_detect_work, msecs_to_jiffies(250)); - } -- mutex_unlock(&rt711->disable_irq_lock); - - return 0; - } -@@ -509,11 +509,11 @@ static int rt711_dev_system_suspend(struct device *dev) - * deferred work completes and before the parent disables - * interrupts on the link - */ -- mutex_lock(&rt711->disable_irq_lock); -- rt711->disable_irq = true; -- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, -- SDW_SCP_INT1_IMPL_DEF, 0); -- mutex_unlock(&rt711->disable_irq_lock); -+ scoped_guard(mutex, &rt711->disable_irq_lock) { -+ rt711->disable_irq = true; -+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, -+ SDW_SCP_INT1_IMPL_DEF, 0); -+ } - - if (ret < 0) { - /* log but don't prevent suspend from happening */ -@@ -535,12 +535,12 @@ static int rt711_dev_resume(struct device *dev) - return 0; - - if (!slave->unattach_request) { -- mutex_lock(&rt711->disable_irq_lock); -- if (rt711->disable_irq == true) { -- sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); -- rt711->disable_irq = false; -+ scoped_guard(mutex, &rt711->disable_irq_lock) { -+ if (rt711->disable_irq) { -+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); -+ rt711->disable_irq = false; -+ } - } -- mutex_unlock(&rt711->disable_irq_lock); - } - - ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT); -diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c ---- a/sound/soc/codecs/rt711.c -+++ b/sound/soc/codecs/rt711.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -89,24 +90,24 @@ static int rt711_calibration(struct rt711_priv *rt711) - struct regmap *regmap = rt711->regmap; - int ret = 0; - -- mutex_lock(&rt711->calibrate_mutex); -+ guard(mutex)(&rt711->calibrate_mutex); - regmap_write(rt711->regmap, -- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); -+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); - - dev = regmap_get_device(regmap); - - /* Calibration manual mode */ - rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, -- 0xf, 0x0); -+ 0xf, 0x0); - - /* trigger */ - rt711_index_update_bits(regmap, RT711_VENDOR_CALI, -- RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, -- RT711_DAC_DC_CALI_TRIGGER); -+ RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, -+ RT711_DAC_DC_CALI_TRIGGER); - - /* wait for calibration process */ - rt711_index_read(regmap, RT711_VENDOR_CALI, -- RT711_DAC_DC_CALI_CTL1, &val); -+ RT711_DAC_DC_CALI_CTL1, &val); - - while (val & RT711_DAC_DC_CALI_TRIGGER) { - if (loop >= 500) { -@@ -119,16 +120,15 @@ static int rt711_calibration(struct rt711_priv *rt711) - - usleep_range(10000, 11000); - rt711_index_read(regmap, RT711_VENDOR_CALI, -- RT711_DAC_DC_CALI_CTL1, &val); -+ RT711_DAC_DC_CALI_CTL1, &val); - } - - /* depop mode */ - rt711_index_update_bits(regmap, RT711_VENDOR_REG, -- RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); -+ RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); - - regmap_write(rt711->regmap, -- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); -- mutex_unlock(&rt711->calibrate_mutex); -+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - - dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret); - return ret; -@@ -362,24 +362,24 @@ static void rt711_jack_init(struct rt711_priv *rt711) - { - struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt711->component); - -- mutex_lock(&rt711->calibrate_mutex); -+ guard(mutex)(&rt711->calibrate_mutex); - /* power on */ - if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY) - regmap_write(rt711->regmap, -- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); -+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); - - if (rt711->hs_jack) { - /* unsolicited response & IRQ control */ - regmap_write(rt711->regmap, -- RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); -+ RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); - regmap_write(rt711->regmap, -- RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); -+ RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); - regmap_write(rt711->regmap, -- RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); -+ RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); - rt711_index_write(rt711->regmap, RT711_VENDOR_REG, -- 0x10, 0x2420); -+ 0x10, 0x2420); - rt711_index_write(rt711->regmap, RT711_VENDOR_REG, -- 0x19, 0x2e11); -+ 0x19, 0x2e11); - - switch (rt711->jd_src) { - case RT711_JD1: -@@ -449,8 +449,7 @@ static void rt711_jack_init(struct rt711_priv *rt711) - /* power off */ - if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY) - regmap_write(rt711->regmap, -- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); -- mutex_unlock(&rt711->calibrate_mutex); -+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - } - - static int rt711_set_jack_detect(struct snd_soc_component *component, -@@ -511,7 +510,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, - unsigned int read_ll, read_rl; - int i; - -- mutex_lock(&rt711->calibrate_mutex); -+ guard(mutex)(&rt711->calibrate_mutex); - - /* Can't use update bit function, so read the original value first */ - addr_h = mc->reg; -@@ -599,7 +598,6 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, - regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - -- mutex_unlock(&rt711->calibrate_mutex); - return 0; - } - -@@ -908,11 +906,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component, - break; - - case SND_SOC_BIAS_STANDBY: -- mutex_lock(&rt711->calibrate_mutex); -- regmap_write(rt711->regmap, -- RT711_SET_AUDIO_POWER_STATE, -- AC_PWRST_D3); -- mutex_unlock(&rt711->calibrate_mutex); -+ scoped_guard(mutex, &rt711->calibrate_mutex) { -+ regmap_write(rt711->regmap, -+ RT711_SET_AUDIO_POWER_STATE, -+ AC_PWRST_D3); -+ } - break; - - default: -diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c ---- a/sound/soc/codecs/rt712-sdca-dmic.c -+++ b/sound/soc/codecs/rt712-sdca-dmic.c -@@ -912,10 +912,23 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev) - } - - regcache_cache_only(rt712->regmap, false); -- regcache_sync(rt712->regmap); -+ ret = regcache_sync(rt712->regmap); -+ if (ret) -+ goto err_sync; -+ - regcache_cache_only(rt712->mbq_regmap, false); -- regcache_sync(rt712->mbq_regmap); -+ ret = regcache_sync(rt712->mbq_regmap); -+ if (ret) -+ goto err_sync; -+ - return 0; -+ -+err_sync: -+ regcache_cache_only(rt712->regmap, true); -+ regcache_cache_only(rt712->mbq_regmap, true); -+ regcache_mark_dirty(rt712->regmap); -+ regcache_mark_dirty(rt712->mbq_regmap); -+ return ret; - } - - static const struct dev_pm_ops rt712_sdca_dmic_pm = { -diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c ---- a/sound/soc/codecs/rt712-sdca-sdw.c -+++ b/sound/soc/codecs/rt712-sdca-sdw.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -427,13 +428,13 @@ static int rt712_sdca_dev_system_suspend(struct device *dev) - * deferred work completes and before the parent disables - * interrupts on the link - */ -- mutex_lock(&rt712_sdca->disable_irq_lock); -- rt712_sdca->disable_irq = true; -- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -- SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -- SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -- mutex_unlock(&rt712_sdca->disable_irq_lock); -+ scoped_guard(mutex, &rt712_sdca->disable_irq_lock) { -+ rt712_sdca->disable_irq = true; -+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -+ } - - if (ret1 < 0 || ret2 < 0) { - /* log but don't prevent suspend from happening */ -@@ -455,14 +456,15 @@ static int rt712_sdca_dev_resume(struct device *dev) - return 0; - - if (!slave->unattach_request) { -- mutex_lock(&rt712->disable_irq_lock); -- if (rt712->disable_irq == true) { -- -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); -- rt712->disable_irq = false; -+ scoped_guard(mutex, &rt712->disable_irq_lock) { -+ if (rt712->disable_irq) { -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0); -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8); -+ rt712->disable_irq = false; -+ } - } -- mutex_unlock(&rt712->disable_irq_lock); - } - - ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT); -@@ -472,9 +474,20 @@ static int rt712_sdca_dev_resume(struct device *dev) - } - - regcache_cache_only(rt712->regmap, false); -- regcache_sync(rt712->regmap); -+ ret = regcache_sync(rt712->regmap); -+ if (ret) { -+ regcache_cache_only(rt712->regmap, true); -+ return ret; -+ } -+ - regcache_cache_only(rt712->mbq_regmap, false); -- regcache_sync(rt712->mbq_regmap); -+ ret = regcache_sync(rt712->mbq_regmap); -+ if (ret) { -+ regcache_cache_only(rt712->mbq_regmap, true); -+ regcache_cache_only(rt712->regmap, true); -+ return ret; -+ } -+ - return 0; - } - -diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c ---- a/sound/soc/codecs/rt712-sdca.c -+++ b/sound/soc/codecs/rt712-sdca.c -@@ -7,6 +7,7 @@ - // - - #include -+#include - #include - #include - #include -@@ -403,7 +404,7 @@ static void rt712_sdca_btn_check_handler(struct work_struct *work) - - static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) - { -- mutex_lock(&rt712->calibrate_mutex); -+ guard(mutex)(&rt712->calibrate_mutex); - - if (rt712->hs_jack) { - /* Enable HID1 event & set button RTC mode */ -@@ -450,8 +451,6 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) - - dev_dbg(&rt712->slave->dev, "in %s disable\n", __func__); - } -- -- mutex_unlock(&rt712->calibrate_mutex); - } - - static int rt712_sdca_set_jack_detect(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c ---- a/sound/soc/codecs/rt721-sdca-sdw.c -+++ b/sound/soc/codecs/rt721-sdca-sdw.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -466,13 +467,13 @@ static int rt721_sdca_dev_system_suspend(struct device *dev) - * deferred work completes and before the parent disables - * interrupts on the link - */ -- mutex_lock(&rt721_sdca->disable_irq_lock); -- rt721_sdca->disable_irq = true; -- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -- SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -- SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -- mutex_unlock(&rt721_sdca->disable_irq_lock); -+ scoped_guard(mutex, &rt721_sdca->disable_irq_lock) { -+ rt721_sdca->disable_irq = true; -+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -+ } - - if (ret1 < 0 || ret2 < 0) { - /* log but don't prevent suspend from happening */ -@@ -494,13 +495,15 @@ static int rt721_sdca_dev_resume(struct device *dev) - return 0; - - if (!slave->unattach_request) { -- mutex_lock(&rt721->disable_irq_lock); -- if (rt721->disable_irq == true) { -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); -- rt721->disable_irq = false; -+ scoped_guard(mutex, &rt721->disable_irq_lock) { -+ if (rt721->disable_irq) { -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0); -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8); -+ rt721->disable_irq = false; -+ } - } -- mutex_unlock(&rt721->disable_irq_lock); - } - - ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT); -@@ -510,9 +513,20 @@ static int rt721_sdca_dev_resume(struct device *dev) - } - - regcache_cache_only(rt721->regmap, false); -- regcache_sync(rt721->regmap); -+ ret = regcache_sync(rt721->regmap); -+ if (ret) { -+ regcache_cache_only(rt721->regmap, true); -+ return ret; -+ } -+ - regcache_cache_only(rt721->mbq_regmap, false); -- regcache_sync(rt721->mbq_regmap); -+ ret = regcache_sync(rt721->mbq_regmap); -+ if (ret) { -+ regcache_cache_only(rt721->mbq_regmap, true); -+ regcache_cache_only(rt721->regmap, true); -+ return ret; -+ } -+ - return 0; - } - -diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c ---- a/sound/soc/codecs/rt721-sdca.c -+++ b/sound/soc/codecs/rt721-sdca.c -@@ -5,7 +5,7 @@ - // Copyright(c) 2024 Realtek Semiconductor Corp. - // - // -- -+#include - #include - #include - #include -@@ -289,7 +289,7 @@ static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721) - - static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) - { -- mutex_lock(&rt721->calibrate_mutex); -+ guard(mutex)(&rt721->calibrate_mutex); - if (rt721->hs_jack) { - sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0); -@@ -309,7 +309,6 @@ static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) - rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, - RT721_GE_REL_CTRL1, 0x4000, 0x4000); - } -- mutex_unlock(&rt721->calibrate_mutex); - } - - static int rt721_sdca_set_jack_detect(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c ---- a/sound/soc/codecs/rt722-sdca-sdw.c -+++ b/sound/soc/codecs/rt722-sdca-sdw.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -517,13 +518,13 @@ static int rt722_sdca_dev_system_suspend(struct device *dev) - * deferred work completes and before the parent disables - * interrupts on the link - */ -- mutex_lock(&rt722_sdca->disable_irq_lock); -- rt722_sdca->disable_irq = true; -- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -- SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -- SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -- mutex_unlock(&rt722_sdca->disable_irq_lock); -+ scoped_guard(mutex, &rt722_sdca->disable_irq_lock) { -+ rt722_sdca->disable_irq = true; -+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0); -+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0); -+ } - - if (ret1 < 0 || ret2 < 0) { - /* log but don't prevent suspend from happening */ -@@ -545,13 +546,15 @@ static int rt722_sdca_dev_resume(struct device *dev) - return 0; - - if (!slave->unattach_request) { -- mutex_lock(&rt722->disable_irq_lock); -- if (rt722->disable_irq == true) { -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); -- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); -- rt722->disable_irq = false; -+ scoped_guard(mutex, &rt722->disable_irq_lock) { -+ if (rt722->disable_irq) { -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, -+ SDW_SCP_SDCA_INTMASK_SDCA_0); -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, -+ SDW_SCP_SDCA_INTMASK_SDCA_8); -+ rt722->disable_irq = false; -+ } - } -- mutex_unlock(&rt722->disable_irq_lock); - } - - ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT); -@@ -561,7 +564,13 @@ static int rt722_sdca_dev_resume(struct device *dev) - } - - regcache_cache_only(rt722->regmap, false); -- regcache_sync(rt722->regmap); -+ ret = regcache_sync(rt722->regmap); -+ if (ret) { -+ regcache_cache_only(rt722->regmap, true); -+ regcache_mark_dirty(rt722->regmap); -+ return ret; -+ } -+ - return 0; - } - -diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c ---- a/sound/soc/codecs/rt722-sdca.c -+++ b/sound/soc/codecs/rt722-sdca.c -@@ -6,6 +6,7 @@ - // - // - -+#include - #include - #include - #include -@@ -294,7 +295,7 @@ static void rt722_sdca_btn_check_handler(struct work_struct *work) - - static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) - { -- mutex_lock(&rt722->calibrate_mutex); -+ guard(mutex)(&rt722->calibrate_mutex); - if (rt722->hs_jack) { - /* set SCP_SDCA_IntMask1[0]=1 */ - sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, -@@ -317,7 +318,6 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) - rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, - RT722_GE_RELATED_CTL2, 0x4000, 0x4000); - } -- mutex_unlock(&rt722->calibrate_mutex); - } - - static int rt722_sdca_set_jack_detect(struct snd_soc_component *component, -@@ -352,8 +352,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) - static const char func_tag[] = "FUNC"; - static const char xu_tag[] = "XU"; - const char *dmi_vendor, *dmi_product, *dmi_sku; -- char *cae_filename; -- const struct firmware *cae_fw = NULL; - unsigned int cae_st_spk, cae_st_hp, cae_st_mic; - unsigned int func, value; - unsigned int combined_val; -@@ -385,7 +383,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) - space = strchr(dmi_sku, ' '); - s_len = space ? space - dmi_sku : strlen(dmi_sku); - -- cae_filename = kasprintf(GFP_KERNEL, -+ char *cae_filename __free(kfree) = -+ kasprintf(GFP_KERNEL, - "realtek/rt722/rt722_RAE_%.*s_%.*s_%.*s.dat", - v_len, dmi_vendor, - p_len, dmi_product, -@@ -399,8 +398,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) - regmap_write(rt722->regmap, RT722_MIC_CAE_PARAM39, 0x5f); - usleep_range(50000, 60000); - -+ const struct firmware *cae_fw __free(firmware) = NULL; - request_firmware(&cae_fw, cae_filename, dev); -- kfree(cae_filename); - if (!cae_fw) { - dev_err(dev, "%s: Failed to load CAE firmware\n", __func__); - return -ENOENT; -@@ -555,7 +554,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) - regcache_cache_bypass(rt722->regmap, false); - rt722->cae_update_done = 1; - dev_dbg(dev, "%s: CAE FW update done.\n", __func__); -- release_firmware(cae_fw); - return 0; - - verify_abort: -@@ -565,7 +563,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722) - out_release: - rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG, - RT722_MISC_CTRL1, 0x8000, 0x0000); -- release_firmware(cae_fw); - dev_err(dev, "%s: CAE FW update aborted (ret=%d).\n", __func__, ret); - return ret; - } -@@ -1906,6 +1903,9 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) - rt722_sdca_amp_preset(rt722); - rt722_sdca_jack_preset(rt722); - -+ if (rt722->hs_jack && (!rt722->first_hw_init)) -+ rt722_sdca_jack_init(rt722); -+ - if (rt722->first_hw_init) { - regcache_cache_bypass(rt722->regmap, false); - regcache_mark_dirty(rt722->regmap); -diff --git a/sound/soc/codecs/rt766-sdca-sdw.c b/sound/soc/codecs/rt766-sdca-sdw.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/codecs/rt766-sdca-sdw.c -@@ -0,0 +1,339 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+// -+// rt766-sdca-sdw.c -- rt766 SDCA ALSA SoC audio driver -+// -+// Copyright(c) 2026 Realtek Semiconductor Corp. -+// -+// -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "rt766-sdca.h" -+#include "rt766-sdca-sdw.h" -+ -+#define RT766_PROBE_TIMEOUT 5000 -+ -+static bool rt766_sdca_readable_register(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4: -+ case RT766_VERSION_ID ... RT766_BOND_LATCH_ID: -+ case 0xc344 ... 0xc345: -+ case 0xc900: -+ case 0xc920: -+ case 0xd540 ... 0xd542: -+ case 0xf01e: -+ case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1: -+ case 0x310100: -+ case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END: -+ case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END: -+ case RT766_MUTE_REG(UAJ, USER_FU41, 1): -+ case RT766_MUTE_REG(UAJ, USER_FU41, 2): -+ case RT766_VOLUME_REG(UAJ, USER_FU41, 1): -+ case RT766_VOLUME_REG(UAJ, USER_FU41, 2): -+ case RT766_MUTE_REG(UAJ, USER_FU36, 1): -+ case RT766_MUTE_REG(UAJ, USER_FU36, 2): -+ case RT766_VOLUME_REG(UAJ, USER_FU36, 1): -+ case RT766_VOLUME_REG(UAJ, USER_FU36, 2): -+ case RT766_PDE_REQ_REG(UAJ, PDE47): -+ case RT766_PDE_REQ_REG(UAJ, PDE34): -+ case RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX): -+ case RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX): -+ case RT766_FUNC_STATUS_REG(UAJ): /* 0x40480000 */ -+ case RT766_PDE_ACTUAL_REG(UAJ, PDE47): /* 0x40481400 */ -+ case RT766_PDE_ACTUAL_REG(UAJ, PDE34): /* 0x40481480 */ -+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1): -+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2): -+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE): -+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE): /* 0x40600490 */ -+ case RT766_PDE_REQ_REG(MIC, PDE11): -+ case RT766_MUTE_REG(MIC, USER_FU113, 1): -+ case RT766_MUTE_REG(MIC, USER_FU113, 2): -+ case RT766_MUTE_REG(MIC, USER_FU113, 3): -+ case RT766_MUTE_REG(MIC, USER_FU113, 4): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 1): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 2): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 3): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 4): -+ case RT766_FUNC_STATUS_REG(MIC): /* 0x40880000 */ -+ case RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX): -+ case RT766_PDE_ACTUAL_REG(MIC, PDE11): /* 0x40881500 */ -+ case RT766_FUNC_STATUS_REG(HID): /* 0x40c80000 */ -+ /* 0x40c80080 - 0x40c80098 */ -+ case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ... -+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH): -+ case RT766_MUTE_REG(AMP, USER_FU21, 1): -+ case RT766_MUTE_REG(AMP, USER_FU21, 2): -+ case RT766_VOLUME_REG(AMP, USER_FU21, 1): -+ case RT766_VOLUME_REG(AMP, USER_FU21, 2): -+ case RT766_PDE_REQ_REG(AMP, PDE23): -+ case RT766_FUNC_STATUS_REG(AMP): /* 0x41080000 */ -+ case RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER): -+ case RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX): -+ case RT766_PDE_ACTUAL_REG(AMP, PDE23): /* 0x41081980 */ -+ case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool rt766_sdca_volatile_register(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4: -+ case RT766_VERSION_ID ... RT766_BOND_LATCH_ID: -+ case 0xc344 ... 0xc345: -+ case 0xc900: -+ case 0xc920: -+ case 0xd540 ... 0xd542: -+ case 0xf01e: -+ case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1: -+ case 0x310100: -+ case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END: -+ case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END: -+ case RT766_FUNC_STATUS_REG(UAJ): -+ case RT766_PDE_ACTUAL_REG(UAJ, PDE47): -+ case RT766_PDE_ACTUAL_REG(UAJ, PDE34): -+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE): -+ case RT766_FUNC_STATUS_REG(MIC): -+ case RT766_PDE_ACTUAL_REG(MIC, PDE11): -+ case RT766_FUNC_STATUS_REG(HID): -+ case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ... -+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH): -+ case RT766_FUNC_STATUS_REG(AMP): -+ case RT766_PDE_ACTUAL_REG(AMP, PDE23): -+ case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static int rt766_sdca_mbq_size(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case RT766_VOLUME_REG(UAJ, USER_FU41, 1): -+ case RT766_VOLUME_REG(UAJ, USER_FU41, 2): -+ case RT766_VOLUME_REG(UAJ, USER_FU36, 1): -+ case RT766_VOLUME_REG(UAJ, USER_FU36, 2): -+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1): -+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 1): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 2): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 3): -+ case RT766_VOLUME_REG(MIC, USER_FU113, 4): -+ case RT766_VOLUME_REG(AMP, USER_FU21, 1): -+ case RT766_VOLUME_REG(AMP, USER_FU21, 2): -+ return 2; -+ default: -+ return 1; -+ } -+} -+ -+static const struct regmap_sdw_mbq_cfg rt766_sdca_mbq_cfg = { -+ .mbq_size = rt766_sdca_mbq_size, -+}; -+ -+static const struct regmap_config rt766_sdca_regmap = { -+ .reg_bits = 32, -+ .val_bits = 16, -+ .readable_reg = rt766_sdca_readable_register, -+ .volatile_reg = rt766_sdca_volatile_register, -+ .reg_defaults = rt766_sdca_defaults, -+ .num_reg_defaults = ARRAY_SIZE(rt766_sdca_defaults), -+ .max_register = SDW_SDCA_MAX_REGISTER, -+ .cache_type = REGCACHE_MAPLE, -+ .use_single_read = true, -+ .use_single_write = true, -+}; -+ -+static int rt766_sdca_update_status(struct sdw_slave *slave, -+ enum sdw_slave_status status) -+{ -+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(&slave->dev); -+ -+ if (status == SDW_SLAVE_UNATTACHED) -+ rt766->hw_init = false; -+ -+ if (status == SDW_SLAVE_ATTACHED) { -+ if (rt766->hs_jack) { -+ /* -+ * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then -+ * if the device attached again, we will need to set the setting back. -+ * It could avoid losing the jack detection interrupt. -+ * This also could sync with the cache value as the rt766_sdca_jack_init set. -+ */ -+ sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK3, -+ SDW_SCP_SDCA_INTMASK_SDCA_16); -+ sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK4, -+ SDW_SCP_SDCA_INTMASK_SDCA_24); -+ } -+ } -+ -+ /* -+ * Perform initialization only if slave status is present and -+ * hw_init flag is false -+ */ -+ if (rt766->hw_init || status != SDW_SLAVE_ATTACHED) -+ return 0; -+ -+ /* perform I/O transfers required for Slave initialization */ -+ return rt766_sdca_io_init(&slave->dev, slave); -+} -+ -+static int rt766_sdca_read_prop(struct sdw_slave *slave) -+{ -+ struct sdw_slave_prop *prop = &slave->prop; -+ int ret; -+ -+ ret = sdw_slave_read_prop(slave); -+ if (ret < 0) -+ return ret; -+ -+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; -+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; -+ /* -+ * SDCA interrupts are routed through SoundWire domain IRQ. -+ */ -+ prop->use_domain_irq = true; -+ -+ return 0; -+} -+ -+static const struct sdw_slave_ops rt766_sdca_slave_ops = { -+ .read_prop = rt766_sdca_read_prop, -+ .update_status = rt766_sdca_update_status, -+}; -+ -+static int rt766_sdca_sdw_probe(struct sdw_slave *slave, -+ const struct sdw_device_id *id) -+{ -+ struct regmap *regmap; -+ -+ /* Regmap Initialization */ -+ regmap = devm_regmap_init_sdw_mbq_cfg(&slave->dev, slave, -+ &rt766_sdca_regmap, &rt766_sdca_mbq_cfg); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); -+ -+ return rt766_sdca_init(&slave->dev, regmap, slave); -+} -+ -+static void rt766_sdca_sdw_remove(struct sdw_slave *slave) -+{ -+ pm_runtime_disable(&slave->dev); -+} -+ -+static const struct sdw_device_id rt766_sdca_id[] = { -+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x766, 0x3, 0x1, 0), -+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x767, 0x3, 0x1, 0), -+ {}, -+}; -+MODULE_DEVICE_TABLE(sdw, rt766_sdca_id); -+ -+static int rt766_sdca_dev_suspend(struct device *dev) -+{ -+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); -+ -+ if (!rt766->hw_init) -+ return 0; -+ -+ regcache_cache_only(rt766->regmap, true); -+ return 0; -+} -+ -+static int rt766_sdca_dev_system_suspend(struct device *dev) -+{ -+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); -+ struct sdw_slave *slave = dev_to_sdw_dev(dev); -+ int ret1, ret2; -+ -+ if (!rt766->hw_init) -+ return 0; -+ -+ /* -+ * prevent new interrupts from being handled after the -+ * deferred work completes and before the parent disables -+ * interrupts on the link -+ */ -+ mutex_lock(&rt766->disable_irq_lock); -+ rt766->disable_irq = true; -+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK3, -+ SDW_SCP_SDCA_INTMASK_SDCA_16, 0); -+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK4, -+ SDW_SCP_SDCA_INTMASK_SDCA_24, 0); -+ mutex_unlock(&rt766->disable_irq_lock); -+ -+ if (ret1 < 0 || ret2 < 0) { -+ /* log but don't prevent suspend from happening */ -+ dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__); -+ } -+ -+ return rt766_sdca_dev_suspend(dev); -+} -+ -+static int rt766_sdca_dev_resume(struct device *dev) -+{ -+ struct sdw_slave *slave = dev_to_sdw_dev(dev); -+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); -+ int ret; -+ -+ if (!rt766->first_hw_init) -+ return 0; -+ -+ if (!slave->unattach_request) { -+ mutex_lock(&rt766->disable_irq_lock); -+ if (rt766->disable_irq == true) { -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK3, SDW_SCP_SDCA_INTMASK_SDCA_16); -+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK4, SDW_SCP_SDCA_INTMASK_SDCA_24); -+ rt766->disable_irq = false; -+ } -+ mutex_unlock(&rt766->disable_irq_lock); -+ goto regmap_sync; -+ } -+ -+ ret = sdw_slave_wait_for_init(slave, RT766_PROBE_TIMEOUT); -+ if (ret) { -+ sdw_show_ping_status(slave->bus, true); -+ return ret; -+ } -+ -+regmap_sync: -+ regcache_cache_only(rt766->regmap, false); -+ ret = regcache_sync(rt766->regmap); -+ if (ret) { -+ regcache_cache_only(rt766->regmap, true); -+ regcache_mark_dirty(rt766->regmap); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops rt766_sdca_pm = { -+ SYSTEM_SLEEP_PM_OPS(rt766_sdca_dev_system_suspend, rt766_sdca_dev_resume) -+ RUNTIME_PM_OPS(rt766_sdca_dev_suspend, rt766_sdca_dev_resume, NULL) -+}; -+ -+static struct sdw_driver rt766_sdca_sdw_driver = { -+ .driver = { -+ .name = "rt766-sdca", -+ .pm = pm_ptr(&rt766_sdca_pm), -+ }, -+ .probe = rt766_sdca_sdw_probe, -+ .remove = rt766_sdca_sdw_remove, -+ .ops = &rt766_sdca_slave_ops, -+ .id_table = rt766_sdca_id, -+}; -+module_sdw_driver(rt766_sdca_sdw_driver); -+ -+MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver"); -+MODULE_AUTHOR("Shuming Fan "); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("SND_SOC_SDCA"); -diff --git a/sound/soc/codecs/rt766-sdca-sdw.h b/sound/soc/codecs/rt766-sdca-sdw.h -new file mode 100644 ---- /dev/null -+++ b/sound/soc/codecs/rt766-sdca-sdw.h -@@ -0,0 +1,61 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * rt766-sdca-sdw.h -- RT766 SDCA ALSA SoC audio driver header -+ * -+ * Copyright(c) 2026 Realtek Semiconductor Corp. -+ */ -+ -+#ifndef __RT766_SDW_H__ -+#define __RT766_SDW_H__ -+ -+#include -+#include -+ -+static const struct reg_default rt766_sdca_defaults[] = { -+ /* 0x40400289 - 0x4040028a */ -+ { RT766_MUTE_REG(UAJ, USER_FU41, 1), 0x01 }, -+ { RT766_MUTE_REG(UAJ, USER_FU41, 2), 0x01 }, -+ /* 0x40400291 - 0x40400292 */ -+ { RT766_VOLUME_REG(UAJ, USER_FU41, 1), 0x0000 }, -+ { RT766_VOLUME_REG(UAJ, USER_FU41, 2), 0x0000 }, -+ /* 0x40400789 - 0x4040078a */ -+ { RT766_MUTE_REG(UAJ, USER_FU36, 1), 0x01 }, -+ { RT766_MUTE_REG(UAJ, USER_FU36, 2), 0x01 }, -+ /* 0x40400791 - 0x40400792 */ -+ { RT766_VOLUME_REG(UAJ, USER_FU36, 1), 0x0000 }, -+ { RT766_VOLUME_REG(UAJ, USER_FU36, 2), 0x0000 }, -+ { RT766_PDE_REQ_REG(UAJ, PDE47), 0x03 }, /* 0x40401408 */ -+ { RT766_PDE_REQ_REG(UAJ, PDE34), 0x03 }, /* 0x40401488 */ -+ { RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480080 */ -+ { RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480880 */ -+ /* 0x40600259 - 0x4060025a */ -+ { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1), 0xfe00 }, -+ { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2), 0xfe00 }, -+ { RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE), 0x00 }, /* 0x40600488 */ -+ -+ { RT766_PDE_REQ_REG(MIC, PDE11), 0x03 }, /* 0x40801508 */ -+ /* 0x40801809 - 0x4080180c */ -+ { RT766_MUTE_REG(MIC, USER_FU113, 1), 0x01 }, -+ { RT766_MUTE_REG(MIC, USER_FU113, 2), 0x01 }, -+ { RT766_MUTE_REG(MIC, USER_FU113, 3), 0x01 }, -+ { RT766_MUTE_REG(MIC, USER_FU113, 4), 0x01 }, -+ /* 0x40801811 - 0x40801814 */ -+ { RT766_VOLUME_REG(MIC, USER_FU113, 1), 0x0000 }, -+ { RT766_VOLUME_REG(MIC, USER_FU113, 2), 0x0000 }, -+ { RT766_VOLUME_REG(MIC, USER_FU113, 3), 0x0000 }, -+ { RT766_VOLUME_REG(MIC, USER_FU113, 4), 0x0000 }, -+ { RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40880900 */ -+ -+ /* 0x41000189 - 0x4100018a */ -+ { RT766_MUTE_REG(AMP, USER_FU21, 1), 0x01 }, -+ { RT766_MUTE_REG(AMP, USER_FU21, 2), 0x01 }, -+ /* 0x41000191 - 0x41000192 */ -+ { RT766_VOLUME_REG(AMP, USER_FU21, 1), 0x0000 }, -+ { RT766_VOLUME_REG(AMP, USER_FU21, 2), 0x0000 }, -+ { RT766_PDE_REQ_REG(AMP, PDE23), 0x03 }, /* 0x41001988 */ -+ { RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0x00 }, /* 0x41080200 */ -+ { RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x41081080 */ -+ -+}; -+ -+#endif /* __RT766_SDW_H__ */ -diff --git a/sound/soc/codecs/rt766-sdca.c b/sound/soc/codecs/rt766-sdca.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/codecs/rt766-sdca.c -@@ -0,0 +1,1378 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+// -+// rt766-sdca.c -- rt766 SDCA ALSA SoC audio driver -+// -+// Copyright(c) 2026 Realtek Semiconductor Corp. -+// -+// -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "rt766-sdca.h" -+#include "rt-sdw-common.h" -+ -+static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt) -+{ -+ struct rt766_sdca_priv *rt766 = interrupt->priv; -+ unsigned char *buf = NULL; -+ unsigned int offset, owner, length; -+ unsigned int det_mode, idx, val; -+ int ret; -+ -+ ret = regmap_read(rt766->regmap, -+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE), -+ &det_mode); -+ if (ret < 0) -+ goto io_error; -+ -+ /* get current UMP message owner */ -+ ret = regmap_read(rt766->regmap, -+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER), -+ &owner); -+ if (ret < 0) -+ goto io_error; -+ -+ /* if owner is device then there is no button event from device */ -+ if (owner == 1) -+ return 0; -+ -+ if (det_mode) { -+ /* read UMP message length */ -+ ret = regmap_read(rt766->regmap, -+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH), -+ &length); -+ if (ret < 0) -+ goto _end_btn_det_; -+ -+ /* read UMP message offset */ -+ ret = regmap_read(rt766->regmap, -+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGEOFFSET), -+ &offset); -+ if (ret < 0) -+ goto _end_btn_det_; -+ -+ buf = devm_kzalloc(&rt766->slave->dev, length, GFP_KERNEL); -+ if (!buf) { -+ dev_err(&rt766->slave->dev, "%s: alloc buf failed\n", __func__); -+ goto _end_btn_det_; -+ } -+ -+ for (idx = 0; idx < length; idx++) { -+ ret = regmap_read(rt766->regmap, -+ RT766_BUF_ADDR_HID1 + offset + idx, &val); -+ if (ret < 0) -+ goto _end_btn_det_; -+ buf[idx] = val & 0xff; -+ } -+ -+ if (rt766->hid) -+ hid_input_report(rt766->hid, HID_INPUT_REPORT, -+ buf, length, 1); -+ } -+ -+_end_btn_det_: -+ if (buf) -+ devm_kfree(&rt766->slave->dev, buf); -+ -+ /* Host is owner, so set back to device */ -+ if (owner == 0) { -+ regmap_write(rt766->regmap, -+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER), 0x01); -+ } -+ -+ return 0; -+ -+io_error: -+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); -+ return ret; -+} -+ -+static irqreturn_t rt766_sdca_irq_btn_handler(int irq, void *data) -+{ -+ struct sdca_interrupt *interrupt = data; -+ struct rt766_sdca_priv *rt766 = interrupt->priv; -+ -+ if (!rt766->hs_jack) -+ return IRQ_HANDLED; -+ -+ if (!rt766->component->card || !rt766->component->card->instantiated) -+ return IRQ_HANDLED; -+ -+ mutex_lock(&rt766->disable_irq_lock); -+ if (!rt766->disable_irq) -+ rt766_sdca_btn_detect(interrupt); -+ mutex_unlock(&rt766->disable_irq_lock); -+ return IRQ_HANDLED; -+} -+ -+static int rt766_sdca_headset_detect(struct rt766_sdca_priv *rt766) -+{ -+ unsigned int det_mode; -+ int ret; -+ -+ /* get detected_mode */ -+ ret = regmap_read(rt766->regmap, -+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE), -+ &det_mode); -+ if (ret < 0) -+ goto io_error; -+ -+ switch (det_mode) { -+ case 0x00: -+ rt766->jack_type = 0; -+ break; -+ case 0x03: -+ rt766->jack_type = SND_JACK_HEADPHONE; -+ break; -+ case 0x05: -+ rt766->jack_type = SND_JACK_HEADSET; -+ break; -+ } -+ -+ /* write selected_mode */ -+ if (det_mode) { -+ ret = regmap_write(rt766->regmap, -+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE), -+ det_mode); -+ if (ret < 0) -+ goto io_error; -+ } -+ -+ dev_dbg(&rt766->slave->dev, -+ "%s, detected_mode=0x%x\n", __func__, det_mode); -+ -+ return 0; -+ -+io_error: -+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); -+ return ret; -+} -+ -+static irqreturn_t rt766_sdca_irq_jd_handler(int irq, void *data) -+{ -+ struct sdca_interrupt *interrupt = data; -+ struct rt766_sdca_priv *rt766 = interrupt->priv; -+ -+ if (!rt766->hs_jack) -+ return IRQ_HANDLED; -+ -+ if (!rt766->component->card || !rt766->component->card->instantiated) -+ return IRQ_HANDLED; -+ -+ mutex_lock(&rt766->disable_irq_lock); -+ if (!rt766->disable_irq) -+ rt766_sdca_headset_detect(rt766); -+ mutex_unlock(&rt766->disable_irq_lock); -+ -+ dev_dbg(&rt766->slave->dev, -+ "in %s, jack_type=%d\n", __func__, rt766->jack_type); -+ -+ snd_soc_jack_report(rt766->hs_jack, rt766->jack_type, SND_JACK_HEADSET); -+ return IRQ_HANDLED; -+} -+ -+static void rt766_sdca_destroy_hid_device(struct sdca_interrupt *interrupt) -+{ -+ struct rt766_sdca_priv *rt766 = interrupt->priv; -+ -+ hid_destroy_device(rt766->hid); -+} -+ -+static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766, -+ struct sdca_function_data *function, -+ struct snd_soc_component *component, -+ struct sdca_interrupt_info *info, -+ bool enabled) -+{ -+ struct device *dev = &rt766->slave->dev; -+ struct sdca_interrupt *interrupt; -+ struct sdca_control *control; -+ struct sdca_entity *entity; -+ irq_handler_t handler; -+ int i, j, irq, ret; -+ -+ for (i = 0; i < function->num_entities; i++) { -+ entity = &function->entities[i]; -+ -+ for (j = 0; j < entity->num_controls; j++) { -+ control = &entity->controls[j]; -+ irq = control->interrupt_position; -+ -+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) { -+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE): -+ handler = rt766_sdca_irq_jd_handler; -+ break; -+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): -+ handler = rt766_sdca_irq_btn_handler; -+ break; -+ default: -+ continue; -+ } -+ -+ interrupt = &info->irqs[irq]; -+ -+ if (enabled) { -+ ret = sdca_irq_data_populate(dev, rt766->regmap, component, -+ function, entity, control, -+ interrupt); -+ if (ret) -+ return ret; -+ -+ if (handler == rt766_sdca_irq_btn_handler) { -+ ret = sdca_add_hid_device(interrupt); -+ if (ret) -+ return ret; -+ -+ interrupt->free_priv = rt766_sdca_destroy_hid_device; -+ rt766->hid = interrupt->priv; -+ } -+ -+ interrupt->priv = rt766; -+ ret = sdca_irq_request(dev, info, irq, interrupt->name, -+ handler, interrupt); -+ if (ret) { -+ dev_err(dev, "failed to request irq %s: %d\n", -+ interrupt->name, ret); -+ sdca_irq_cleanup_late(dev, function, info); -+ return ret; -+ } -+ dev_dbg(dev, "Requesting IRQ %d InterruptName=%s\n", irq, interrupt->name); -+ } else { -+ sdca_irq_cleanup_late(dev, function, info); -+ dev_dbg(dev, "Freeing IRQ %d\n", irq); -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int rt766_sdca_set_jack_detect(struct snd_soc_component *component, -+ struct snd_soc_jack *hs_jack, void *data) -+{ -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ int ret; -+ -+ if (!rt766->uaj_func_data) { -+ dev_err(&rt766->slave->dev, "The SDCA UAJ function is not supported.\n"); -+ return -EINVAL; -+ } -+ -+ rt766->hs_jack = hs_jack; -+ -+ if (!rt766->first_hw_init) -+ return 0; -+ -+ ret = pm_runtime_resume_and_get(component->dev); -+ if (ret < 0) { -+ if (ret != -EACCES) { -+ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); -+ return ret; -+ } -+ -+ /* pm_runtime not enabled yet */ -+ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); -+ return 0; -+ } -+ -+ /* disable interrupts if hs_jack is not set */ -+ if (!rt766->hs_jack) { -+ if (rt766->uaj_func_data) -+ rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data, -+ rt766->component, rt766->irq_info, false); -+ -+ if (rt766->hid_func_data) -+ rt766_sdca_irq_ctl(rt766, rt766->hid_func_data, -+ rt766->component, rt766->irq_info, false); -+ } -+ -+ pm_runtime_put_autosuspend(component->dev); -+ -+ return 0; -+} -+ -+static int rt766_sdca_set_fu_ctl(struct rt766_sdca_priv *rt766, int func_num, int fu_num) -+{ -+ unsigned int fu01_reg, fu02_reg; -+ unsigned int ch_01, ch_02; -+ unsigned int ch_mute; -+ unsigned int fu_reg; -+ int err, i; -+ -+ switch (fu_num) { -+ case RT766_SDCA_ENT_USER_FU41: -+ ch_01 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_l_mute) ? 0x01 : 0x00; -+ ch_02 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_r_mute) ? 0x01 : 0x00; -+ break; -+ case RT766_SDCA_ENT_USER_FU36: -+ ch_01 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_l_mute) ? 0x01 : 0x00; -+ ch_02 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_r_mute) ? 0x01 : 0x00; -+ break; -+ case RT766_SDCA_ENT_USER_FU21: -+ ch_01 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_l_mute) ? 0x01 : 0x00; -+ ch_02 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_r_mute) ? 0x01 : 0x00; -+ break; -+ case RT766_SDCA_ENT_USER_FU113: -+ for (i = 0; i < ARRAY_SIZE(rt766->fu113_mixer_mute); i++) { -+ ch_mute = (rt766->fu113_dapm_mute || rt766->fu113_mixer_mute[i]) ? 0x01 : 0x00; -+ fu_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1) + i; -+ err = regmap_write(rt766->regmap, fu_reg, ch_mute); -+ if (err < 0) -+ return err; -+ } -+ return 0; -+ } -+ -+ fu01_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1); -+ fu02_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 2); -+ err = regmap_write(rt766->regmap, fu01_reg, ch_01); -+ if (err < 0) -+ return err; -+ err = regmap_write(rt766->regmap, fu02_reg, ch_02); -+ if (err < 0) -+ return err; -+ -+ return 0; -+} -+ -+static int rt766_sdca_fu41_playback_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ ucontrol->value.integer.value[0] = !rt766->fu41_mixer_l_mute; -+ ucontrol->value.integer.value[1] = !rt766->fu41_mixer_r_mute; -+ return 0; -+} -+ -+static int rt766_sdca_fu41_playback_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ int err; -+ -+ if (rt766->fu41_mixer_l_mute == !ucontrol->value.integer.value[0] && -+ rt766->fu41_mixer_r_mute == !ucontrol->value.integer.value[1]) -+ return 0; -+ -+ rt766->fu41_mixer_l_mute = !ucontrol->value.integer.value[0]; -+ rt766->fu41_mixer_r_mute = !ucontrol->value.integer.value[1]; -+ -+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41); -+ if (err < 0) -+ return err; -+ -+ return 1; -+} -+ -+static int rt766_sdca_fu36_capture_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ ucontrol->value.integer.value[0] = !rt766->fu36_mixer_l_mute; -+ ucontrol->value.integer.value[1] = !rt766->fu36_mixer_r_mute; -+ return 0; -+} -+ -+static int rt766_sdca_fu36_capture_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ int err; -+ -+ if (rt766->fu36_mixer_l_mute == !ucontrol->value.integer.value[0] && -+ rt766->fu36_mixer_r_mute == !ucontrol->value.integer.value[1]) -+ return 0; -+ -+ rt766->fu36_mixer_l_mute = !ucontrol->value.integer.value[0]; -+ rt766->fu36_mixer_r_mute = !ucontrol->value.integer.value[1]; -+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36); -+ if (err < 0) -+ return err; -+ -+ return 1; -+} -+ -+static int rt766_sdca_fu21_playback_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ ucontrol->value.integer.value[0] = !rt766->fu21_mixer_l_mute; -+ ucontrol->value.integer.value[1] = !rt766->fu21_mixer_r_mute; -+ return 0; -+} -+ -+static int rt766_sdca_fu21_playback_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ int err; -+ -+ if (rt766->fu21_mixer_l_mute == !ucontrol->value.integer.value[0] && -+ rt766->fu21_mixer_r_mute == !ucontrol->value.integer.value[1]) -+ return 0; -+ -+ rt766->fu21_mixer_l_mute = !ucontrol->value.integer.value[0]; -+ rt766->fu21_mixer_r_mute = !ucontrol->value.integer.value[1]; -+ -+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21); -+ if (err < 0) -+ return err; -+ -+ return 1; -+} -+ -+static int rt766_sdca_fu113_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_to_component(w->dapm); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ rt766->fu113_dapm_mute = false; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113); -+ break; -+ case SND_SOC_DAPM_PRE_PMD: -+ rt766->fu113_dapm_mute = true; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113); -+ break; -+ } -+ return 0; -+} -+ -+static int rt766_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ struct rt_sdca_dmic_kctrl_priv *p = -+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; -+ const unsigned int interval_offset = 0xc0; -+ unsigned int regvalue, ctl, i; -+ -+ /* check all channels */ -+ for (i = 0; i < p->count; i++) { -+ regmap_read(rt766->regmap, p->reg_base + i, ®value); -+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset); -+ -+ ucontrol->value.integer.value[i] = ctl; -+ } -+ -+ return 0; -+} -+ -+static int rt766_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt_sdca_dmic_kctrl_priv *p = -+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ const unsigned int interval_offset = 0xc0; -+ unsigned int gain_val[4]; -+ unsigned int i, changed = 0; -+ unsigned int regvalue[4]; -+ int err; -+ -+ /* check all channels */ -+ for (i = 0; i < p->count; i++) { -+ regmap_read(rt766->regmap, p->reg_base + i, ®value[i]); -+ -+ gain_val[i] = ucontrol->value.integer.value[i]; -+ if (gain_val[i] > p->max) -+ gain_val[i] = p->max; -+ -+ gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset); -+ gain_val[i] &= 0xffff; -+ -+ if (regvalue[i] != gain_val[i]) -+ changed = 1; -+ } -+ -+ if (!changed) -+ return 0; -+ -+ for (i = 0; i < p->count; i++) { -+ err = regmap_write(rt766->regmap, p->reg_base + i, gain_val[i]); -+ if (err < 0) -+ dev_err(&rt766->slave->dev, "0x%08x can't be set\n", p->reg_base + i); -+ } -+ -+ return changed; -+} -+ -+static int rt766_sdca_dmic_fu113_capture_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ unsigned int i; -+ -+ for (i = 0; i < 4; i++) -+ ucontrol->value.integer.value[i] = !rt766->fu113_mixer_mute[i]; -+ return 0; -+} -+ -+static int rt766_sdca_dmic_fu113_capture_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ int err, changed = 0, i; -+ -+ for (i = 0; i < 4; i++) { -+ if (rt766->fu113_mixer_mute[i] != !ucontrol->value.integer.value[i]) -+ changed = 1; -+ rt766->fu113_mixer_mute[i] = !ucontrol->value.integer.value[i]; -+ } -+ -+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113); -+ if (err < 0) -+ return err; -+ return changed; -+} -+ -+static int rt766_sdca_fu41_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_to_component(w->dapm); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ rt766->fu41_dapm_mute = false; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41); -+ break; -+ case SND_SOC_DAPM_PRE_PMD: -+ rt766->fu41_dapm_mute = true; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41); -+ break; -+ } -+ return 0; -+} -+ -+static int rt766_sdca_pde_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event, int func_num, int pde_num, const char *pde_ent) -+{ -+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ struct sdca_function_data *func_data; -+ unsigned char ps0 = 0x0, ps3 = 0x3; -+ const struct sdca_entity *entity; -+ unsigned int pde_req_reg; -+ int from_ps, to_ps; -+ int ret; -+ -+ pde_req_reg = SDW_SDCA_CTL(func_num, pde_num, SDCA_CTL_PDE_REQUESTED_PS, 0); -+ -+ switch (func_num) { -+ case RT766_FUNC_NUM_UAJ: -+ func_data = rt766->uaj_func_data; -+ break; -+ case RT766_FUNC_NUM_AMP: -+ func_data = rt766->sa_func_data; -+ break; -+ case RT766_FUNC_NUM_MIC: -+ func_data = rt766->sm_func_data; -+ break; -+ default: -+ dev_err(component->dev, "%s: unsupported func_num %d\n", -+ __func__, func_num); -+ return -EINVAL; -+ } -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ regmap_write(rt766->regmap, pde_req_reg, ps0); -+ from_ps = ps3; -+ to_ps = ps0; -+ break; -+ case SND_SOC_DAPM_PRE_PMD: -+ regmap_write(rt766->regmap, pde_req_reg, ps3); -+ from_ps = ps0; -+ to_ps = ps3; -+ break; -+ } -+ -+ entity = sdca_find_entity_by_label(func_data, pde_ent); -+ if (!entity) { -+ dev_err(component->dev, "%s: failed to find entity %s\n", -+ __func__, pde_ent); -+ return -EINVAL; -+ } -+ -+ ret = sdca_asoc_pde_poll_actual_ps(rt766->regmap, -+ func_num, -+ pde_num, -+ from_ps, to_ps, -+ entity->pde.max_delay, -+ entity->pde.num_max_delay); -+ if (ret) -+ dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n", -+ __func__, from_ps, to_ps, ret); -+ -+ return ret; -+} -+ -+static int rt766_sdca_pde47_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ return rt766_sdca_pde_event(w, kcontrol, event, -+ RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE47, "PDE 47"); -+} -+ -+static int rt766_sdca_fu36_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_to_component(w->dapm); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ rt766->fu36_dapm_mute = false; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36); -+ break; -+ case SND_SOC_DAPM_PRE_PMD: -+ rt766->fu36_dapm_mute = true; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36); -+ break; -+ } -+ return 0; -+} -+ -+static int rt766_sdca_pde34_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ return rt766_sdca_pde_event(w, kcontrol, event, -+ RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE34, "PDE 34"); -+} -+ -+static int rt766_sdca_fu21_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_component *component = -+ snd_soc_dapm_to_component(w->dapm); -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ rt766->fu21_dapm_mute = false; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21); -+ break; -+ case SND_SOC_DAPM_PRE_PMD: -+ rt766->fu21_dapm_mute = true; -+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21); -+ break; -+ } -+ return 0; -+} -+ -+static int rt766_sdca_pde23_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ return rt766_sdca_pde_event(w, kcontrol, event, -+ RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_PDE23, "PDE 23"); -+} -+ -+static int rt766_sdca_pde11_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ return rt766_sdca_pde_event(w, kcontrol, event, -+ RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_PDE11, "PDE 11"); -+} -+ -+static int rt766_dmic_fu_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ struct rt_sdca_dmic_kctrl_priv *p = -+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; -+ -+ if (p->max == 1) -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; -+ else -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = p->count; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = p->max; -+ return 0; -+} -+ -+static const char * const rt766_rx_data_ch_select[] = { -+ "L,R", -+ "R,L", -+ "L,L", -+ "R,R", -+ "L,L+R", -+ "R,L+R", -+ "L+R,L", -+ "L+R,R", -+ "L+R,L+R", -+}; -+ -+static SOC_ENUM_SINGLE_DECL(rt766_rx_data_ch_enum, -+ RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0, -+ rt766_rx_data_ch_select); -+ -+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -9525, 75, 0); -+static const DECLARE_TLV_DB_SCALE(spk_vol_tlv, -6525, 75, 0); -+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0); -+static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, -200, 200, 0); -+ -+#define RT766_P75DB_STEP 0xC0 /* 0.75 dB in Q7.8 format */ -+#define RT766_2DB_STEP 0x200 /* 2 dB in Q7.8 format */ -+#define RT766_HP_VOL_MIN (-127) /* -95.25 dB / 0.75 dB step */ -+#define RT766_HS_VOL_MIN (-23) /* -17.25 dB / 0.75 dB step */ -+#define RT766_HS_BOOST_VOL_MIN (-1) /* -2 dB / 2 dB step */ -+#define RT766_SPK_VOL_MIN (-87) /* -65.25 dB / 0.75 dB step */ -+#define RT766_P_VOL_MAX 0 /* 0 dB / 0.75 dB step */ -+#define RT766_HS_VOL_MAX 40 /* 30 dB / 0.75 dB step */ -+#define RT766_HS_BOOST_VOL_MAX 20 /* 40 dB / 2 dB step */ -+ -+static const struct snd_kcontrol_new rt766_sdca_controls[] = { -+ SOC_DOUBLE_EXT("FU41 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0, -+ rt766_sdca_fu41_playback_get, rt766_sdca_fu41_playback_put), -+ SDCA_DOUBLE_Q78_TLV("FU41 Playback Volume", -+ RT766_VOLUME_REG(UAJ, USER_FU41, 1), -+ RT766_VOLUME_REG(UAJ, USER_FU41, 2), -+ RT766_HP_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, hp_vol_tlv), -+ SOC_DOUBLE_EXT("FU36 Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, -+ rt766_sdca_fu36_capture_get, rt766_sdca_fu36_capture_put), -+ SDCA_DOUBLE_Q78_TLV("FU36 Capture Volume", -+ RT766_VOLUME_REG(UAJ, USER_FU36, 1), -+ RT766_VOLUME_REG(UAJ, USER_FU36, 2), -+ RT766_HS_VOL_MIN, RT766_HS_VOL_MAX, RT766_P75DB_STEP, mic_vol_tlv), -+ SDCA_DOUBLE_Q78_TLV("FU33 Boost Volume", -+ RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1), -+ RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2), -+ RT766_HS_BOOST_VOL_MIN, RT766_HS_BOOST_VOL_MAX, RT766_2DB_STEP, boost_vol_tlv), -+ -+ SOC_DOUBLE_EXT("FU21 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0, -+ rt766_sdca_fu21_playback_get, rt766_sdca_fu21_playback_put), -+ SDCA_DOUBLE_Q78_TLV("FU21 Playback Volume", -+ RT766_VOLUME_REG(AMP, USER_FU21, 1), -+ RT766_VOLUME_REG(AMP, USER_FU21, 2), -+ RT766_SPK_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, spk_vol_tlv), -+ SOC_ENUM("RX Channel Select", rt766_rx_data_ch_enum), -+ -+ RT_SDCA_FU_CTRL("FU113 Capture Switch", -+ RT766_MUTE_REG(MIC, USER_FU113, 1), 1, 1, 4, rt766_dmic_fu_info, -+ rt766_sdca_dmic_fu113_capture_get, rt766_sdca_dmic_fu113_capture_put), -+ RT_SDCA_EXT_TLV("FU113 Capture Volume", -+ RT766_VOLUME_REG(MIC, USER_FU113, 1), -+ rt766_sdca_dmic_set_gain_get, rt766_sdca_dmic_set_gain_put, -+ 4, 0x3f, mic_vol_tlv, rt766_dmic_fu_info), -+}; -+ -+static const struct snd_soc_dapm_widget rt766_sdca_dapm_widgets[] = { -+ /* UAJ */ -+ SND_SOC_DAPM_OUTPUT("HP"), -+ SND_SOC_DAPM_INPUT("MIC2"), -+ SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0, -+ rt766_sdca_pde47_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0, -+ rt766_sdca_pde34_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_DAC_E("FU 41", NULL, SND_SOC_NOPM, 0, 0, -+ rt766_sdca_fu41_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0, -+ rt766_sdca_fu36_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("DP12TX", "DP12 Capture", 0, SND_SOC_NOPM, 0, 0), -+ -+ /* AMP */ -+ SND_SOC_DAPM_OUTPUT("SPOL"), -+ SND_SOC_DAPM_OUTPUT("SPOR"), -+ SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0, -+ rt766_sdca_fu21_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, -+ rt766_sdca_pde23_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), -+ -+ /* DMIC */ -+ SND_SOC_DAPM_INPUT("DMIC1"), -+ SND_SOC_DAPM_INPUT("DMIC2"), -+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, -+ rt766_sdca_pde11_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0, -+ rt766_sdca_fu113_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0), -+}; -+ -+static const struct snd_soc_dapm_route rt766_sdca_audio_map[] = { -+ { "FU 41", NULL, "DP3RX" }, -+ { "DP12TX", NULL, "FU 36" }, -+ { "FU 36", NULL, "PDE 34" }, -+ { "FU 36", NULL, "MIC2" }, -+ { "HP", NULL, "PDE 47" }, -+ { "HP", NULL, "FU 41" }, -+ -+ { "FU 21", NULL, "DP1RX" }, -+ { "FU 21", NULL, "PDE 23" }, -+ { "SPOL", NULL, "FU 21" }, -+ { "SPOR", NULL, "FU 21" }, -+ -+ {"DP8TX", NULL, "FU 113"}, -+ {"FU 113", NULL, "PDE 11"}, -+ {"FU 113", NULL, "DMIC1"}, -+ {"FU 113", NULL, "DMIC2"}, -+}; -+ -+static int rt766_sdca_probe(struct snd_soc_component *component) -+{ -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ struct device *dev = &rt766->slave->dev; -+ int ret; -+ -+ rt766->component = component; -+ -+ ret = pm_runtime_resume(component->dev); -+ if (ret < 0 && ret != -EACCES) -+ return ret; -+ -+ if (rt766->uaj_func_data) { -+ dev_dbg(dev, "%s : irq %d\n", __func__, rt766->slave->irq); -+ -+ rt766->irq_info = devm_sdca_irq_allocate(dev, rt766->regmap, rt766->slave->irq); -+ if (IS_ERR(rt766->irq_info)) -+ return PTR_ERR(rt766->irq_info); -+ -+ ret = rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data, -+ component, rt766->irq_info, true); -+ if (ret < 0) { -+ dev_err(dev, "Failed to request UAJ SDCA IRQ: %d\n", ret); -+ return ret; -+ } -+ -+ if (rt766->hid_func_data) { -+ ret = rt766_sdca_irq_ctl(rt766, rt766->hid_func_data, -+ component, rt766->irq_info, true); -+ if (ret < 0) { -+ dev_err(dev, "Failed to request HID SDCA IRQ: %d\n", ret); -+ return ret; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static void rt766_sdca_remove(struct snd_soc_component *component) -+{ -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ -+ sdca_irq_cleanup_late(component->dev, rt766->uaj_func_data, rt766->irq_info); -+ sdca_irq_cleanup_late(component->dev, rt766->hid_func_data, rt766->irq_info); -+} -+ -+static const struct snd_soc_component_driver soc_sdca_dev_rt766 = { -+ .probe = rt766_sdca_probe, -+ .remove = rt766_sdca_remove, -+ .controls = rt766_sdca_controls, -+ .num_controls = ARRAY_SIZE(rt766_sdca_controls), -+ .dapm_widgets = rt766_sdca_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(rt766_sdca_dapm_widgets), -+ .dapm_routes = rt766_sdca_audio_map, -+ .num_dapm_routes = ARRAY_SIZE(rt766_sdca_audio_map), -+ .set_jack = rt766_sdca_set_jack_detect, -+ .endianness = 1, -+}; -+ -+static int rt766_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, -+ int direction) -+{ -+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream); -+ -+ return 0; -+} -+ -+static void rt766_sdca_shutdown(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ snd_soc_dai_set_dma_data(dai, substream, NULL); -+} -+ -+static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ struct sdw_stream_config stream_config; -+ struct sdw_port_config port_config; -+ enum sdw_data_direction direction; -+ struct sdw_stream_runtime *sdw_stream; -+ unsigned int sampling_rate; -+ int retval, port; -+ -+ dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id); -+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream); -+ -+ if (!sdw_stream) -+ return -EINVAL; -+ -+ if (!rt766->slave) -+ return -EINVAL; -+ -+ /* SoundWire specific configuration */ -+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config); -+ -+ /* SoundWire specific configuration */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ direction = SDW_DATA_DIR_RX; -+ if (dai->id == RT766_AIF1) -+ port = 3; -+ else if (dai->id == RT766_AIF2) -+ port = 1; -+ else -+ return -EINVAL; -+ } else { -+ direction = SDW_DATA_DIR_TX; -+ if (dai->id == RT766_AIF1) -+ port = 12; -+ else if (dai->id == RT766_AIF3) -+ port = 8; -+ else -+ return -EINVAL; -+ } -+ -+ port_config.num = port; -+ retval = sdw_stream_add_slave(rt766->slave, &stream_config, -+ &port_config, 1, sdw_stream); -+ if (retval) { -+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__); -+ return retval; -+ } -+ -+ if (params_channels(params) > 16) { -+ dev_err(component->dev, "%s: Unsupported channels %d\n", -+ __func__, params_channels(params)); -+ return -EINVAL; -+ } -+ -+ /* sampling rate configuration */ -+ switch (params_rate(params)) { -+ case 44100: -+ sampling_rate = RT766_SDCA_RATE_44100HZ; -+ break; -+ case 48000: -+ sampling_rate = RT766_SDCA_RATE_48000HZ; -+ break; -+ case 96000: -+ sampling_rate = RT766_SDCA_RATE_96000HZ; -+ break; -+ case 192000: -+ sampling_rate = RT766_SDCA_RATE_192000HZ; -+ break; -+ default: -+ dev_err(component->dev, "%s: Rate %d is not supported\n", -+ __func__, params_rate(params)); -+ return -EINVAL; -+ } -+ -+ /* set sampling frequency */ -+ switch (dai->id) { -+ case RT766_AIF1: -+ regmap_write(rt766->regmap, -+ RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX), -+ sampling_rate); -+ regmap_write(rt766->regmap, -+ RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX), -+ sampling_rate); -+ break; -+ case RT766_AIF2: -+ regmap_write(rt766->regmap, -+ RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX), -+ sampling_rate); -+ break; -+ case RT766_AIF3: -+ regmap_write(rt766->regmap, -+ RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX), -+ sampling_rate); -+ break; -+ default: -+ dev_err(component->dev, "%s: Wrong DAI id\n", __func__); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int rt766_sdca_pcm_hw_free(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -+ struct sdw_stream_runtime *sdw_stream = -+ snd_soc_dai_get_dma_data(dai, substream); -+ -+ if (!rt766->slave) -+ return -EINVAL; -+ -+ sdw_stream_remove_slave(rt766->slave, sdw_stream); -+ return 0; -+} -+ -+#define RT766_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ -+ SNDRV_PCM_RATE_192000) -+#define RT766_DAC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) -+#define RT766_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ -+ SNDRV_PCM_FMTBIT_S32_LE) -+ -+static const struct snd_soc_dai_ops rt766_sdca_ops = { -+ .hw_params = rt766_sdca_pcm_hw_params, -+ .hw_free = rt766_sdca_pcm_hw_free, -+ .set_stream = rt766_sdca_set_sdw_stream, -+ .shutdown = rt766_sdca_shutdown, -+}; -+ -+static struct snd_soc_dai_driver rt766_sdca_dai[] = { -+ { -+ .name = "rt766-sdca-aif1", -+ .id = RT766_AIF1, -+ .playback = { -+ .stream_name = "DP3 Playback", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = RT766_STEREO_RATES, -+ .formats = RT766_DAC_FORMATS, -+ }, -+ .capture = { -+ .stream_name = "DP12 Capture", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = RT766_STEREO_RATES, -+ .formats = RT766_ADC_FORMATS, -+ }, -+ .ops = &rt766_sdca_ops, -+ .symmetric_rate = 1, -+ }, -+ { -+ .name = "rt766-sdca-aif2", -+ .id = RT766_AIF2, -+ .playback = { -+ .stream_name = "DP1 Playback", -+ .channels_min = 1, -+ .channels_max = 4, -+ .rates = RT766_STEREO_RATES, -+ .formats = RT766_DAC_FORMATS, -+ }, -+ .ops = &rt766_sdca_ops, -+ }, -+ { -+ .name = "rt766-sdca-aif3", -+ .id = RT766_AIF3, -+ .capture = { -+ .stream_name = "DP8 Capture", -+ .channels_min = 1, -+ .channels_max = 4, -+ .rates = RT766_STEREO_RATES, -+ .formats = RT766_ADC_FORMATS, -+ }, -+ .ops = &rt766_sdca_ops, -+ } -+}; -+ -+static unsigned int rt766_find_dt_rates(struct device *dev, struct sdca_function_data *function, -+ const char *label) -+{ -+ struct snd_soc_pcm_stream stream; -+ struct sdca_entity *entity; -+ int i, ret; -+ -+ for (i = 0; i < function->num_entities; i++) { -+ entity = &function->entities[i]; -+ -+ if (strcmp(entity->label, label)) -+ continue; -+ -+ /* Can't check earlier as only terminals have an iot member. */ -+ if (!entity->iot.is_dataport) -+ continue; -+ -+ ret = sdca_asoc_populate_rate_format(dev, function, entity, &stream); -+ if (ret < 0) { -+ dev_dbg(dev, "%s: failed to parse rates for entity %s\n", -+ __func__, entity->label); -+ return 0; -+ } -+ -+ dev_dbg(dev, "%s: %s supports rates 0x%08x\n", __func__, entity->label, stream.rates); -+ } -+ -+ return stream.rates; -+} -+ -+int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave) -+{ -+ struct sdca_function_data *func_data_ptr; -+ struct snd_soc_dai_driver *dai_drv; -+ struct rt766_sdca_priv *rt766; -+ unsigned int rates; -+ int ret; -+ int i; -+ -+ rt766 = devm_kzalloc(dev, sizeof(*rt766), GFP_KERNEL); -+ if (!rt766) -+ return -ENOMEM; -+ -+ dev_set_drvdata(dev, rt766); -+ rt766->slave = slave; -+ rt766->regmap = regmap; -+ -+ regcache_cache_only(rt766->regmap, true); -+ -+ ret = devm_mutex_init(dev, &rt766->disable_irq_lock); -+ if (ret < 0) { -+ dev_err(dev, "Failed to initialize mutex\n"); -+ return ret; -+ } -+ -+ /* -+ * Mark hw_init to false -+ * HW init will be performed when device reports present -+ */ -+ rt766->hw_init = false; -+ rt766->first_hw_init = false; -+ rt766->fu41_dapm_mute = true; -+ rt766->fu41_mixer_l_mute = rt766->fu41_mixer_r_mute = false; -+ rt766->fu36_dapm_mute = true; -+ rt766->fu36_mixer_l_mute = rt766->fu36_mixer_r_mute = true; -+ rt766->fu21_dapm_mute = true; -+ rt766->fu21_mixer_l_mute = rt766->fu21_mixer_r_mute = false; -+ rt766->fu113_dapm_mute = true; -+ rt766->fu113_mixer_mute[0] = rt766->fu113_mixer_mute[1] = -+ rt766->fu113_mixer_mute[2] = rt766->fu113_mixer_mute[3] = true; -+ -+ dai_drv = devm_kzalloc(dev, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai), GFP_KERNEL); -+ if (!dai_drv) { -+ dev_err(dev, "Failed to allocate memory for DAI driver\n"); -+ ret = -ENOMEM; -+ goto _sdw_init_err_; -+ } -+ memcpy(dai_drv, rt766_sdca_dai, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai)); -+ -+ /* get SDCA function data */ -+ dev_dbg(dev, "SDCA functions found: %d", slave->sdca_data.num_functions); -+ for (i = 0; i < slave->sdca_data.num_functions; i++) { -+ func_data_ptr = devm_kzalloc(dev, sizeof(*func_data_ptr), GFP_KERNEL); -+ if (!func_data_ptr) { -+ dev_err(dev, "Failed to allocate memory for function data\n"); -+ ret = -ENOMEM; -+ goto _free_dai_drv_; -+ } -+ -+ func_data_ptr->desc = &slave->sdca_data.function[i]; -+ ret = sdca_parse_function(dev, func_data_ptr); -+ if (ret) { -+ devm_kfree(dev, func_data_ptr); -+ goto _free_dai_drv_; -+ } -+ dev_dbg(dev, "Function type=%d, num_entities=%d", -+ slave->sdca_data.function[i].type, func_data_ptr->num_entities); -+ -+ switch (slave->sdca_data.function[i].type) { -+ case SDCA_FUNCTION_TYPE_UAJ: -+ rt766->uaj_func_data = func_data_ptr; -+ /* -+ * Some machines may only support a subset of the sample rates supported by the codec. -+ * Therefore, we need to parse the supported sample rates from the DisCo table and -+ * configure them in the DAI. If the DisCo table does not provide sample rate information, -+ * we will fall back to the default supported rates defined in the codec driver. -+ */ -+ rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 41"); -+ if (rates) -+ dai_drv[RT766_DAI_UAJ].playback.rates = rates; -+ -+ rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 36"); -+ if (rates) -+ dai_drv[RT766_DAI_UAJ].capture.rates = rates; -+ break; -+ case SDCA_FUNCTION_TYPE_SMART_AMP: -+ rt766->sa_func_data = func_data_ptr; -+ rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 21"); -+ if (rates) -+ dai_drv[RT766_DAI_AMP].playback.rates = rates; -+ break; -+ case SDCA_FUNCTION_TYPE_SMART_MIC: -+ rt766->sm_func_data = func_data_ptr; -+ rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 113"); -+ if (rates) -+ dai_drv[RT766_DAI_MIC].capture.rates = rates; -+ break; -+ case SDCA_FUNCTION_TYPE_HID: -+ rt766->hid_func_data = func_data_ptr; -+ break; -+ default: -+ dev_dbg(dev, "Unexpected SDCA function type found: %d", -+ slave->sdca_data.function[i].type); -+ } -+ } -+ -+ ret = devm_snd_soc_register_component(dev, -+ &soc_sdca_dev_rt766, dai_drv, ARRAY_SIZE(rt766_sdca_dai)); -+ if (ret < 0) -+ goto _free_dai_drv_; -+ -+ /* set autosuspend parameters */ -+ pm_runtime_set_autosuspend_delay(dev, 3000); -+ pm_runtime_use_autosuspend(dev); -+ -+ /* make sure the device does not suspend immediately */ -+ pm_runtime_mark_last_busy(dev); -+ -+ pm_runtime_enable(dev); -+ dev_dbg(dev, "%s\n", __func__); -+ return 0; -+ -+_free_dai_drv_: -+ if (dai_drv) -+ devm_kfree(dev, dai_drv); -+ -+_sdw_init_err_: -+ return ret; -+} -+ -+static int rt766_func_initialize(struct rt766_sdca_priv *rt766, struct sdca_function_data *func_data) -+{ -+ struct device *dev = &rt766->slave->dev; -+ unsigned int func_status_reg; -+ unsigned int func_status; -+ int ret; -+ -+ switch (func_data->desc->type) { -+ case SDCA_FUNCTION_TYPE_UAJ: -+ func_status_reg = RT766_FUNC_STATUS_REG(UAJ); -+ break; -+ case SDCA_FUNCTION_TYPE_SMART_AMP: -+ func_status_reg = RT766_FUNC_STATUS_REG(AMP); -+ break; -+ case SDCA_FUNCTION_TYPE_SMART_MIC: -+ func_status_reg = RT766_FUNC_STATUS_REG(MIC); -+ break; -+ case SDCA_FUNCTION_TYPE_HID: -+ func_status_reg = RT766_FUNC_STATUS_REG(HID); -+ break; -+ default: -+ dev_dbg(dev, "Unexpected SDCA function type found: %d", -+ func_data->desc->type); -+ return -EINVAL; -+ } -+ -+ regmap_read(rt766->regmap, func_status_reg, &func_status); -+ dev_dbg(dev, "%s, %s func_status=0x%x\n", __func__, func_data->desc->name, func_status); -+ -+ if ((func_status & SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION) || (!rt766->first_hw_init)) { -+ ret = sdca_regmap_write_init(dev, rt766->regmap, func_data); -+ if (ret) { -+ dev_err(dev, "%s initialization table update failed\n", func_data->desc->name); -+ goto _func_init_err_; -+ } -+ -+ regmap_write(rt766->regmap, func_status_reg, -+ SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION); -+ } -+ -+ return 0; -+ -+_func_init_err_: -+ dev_err(dev, "%s: %s init writes failed, err=%d", __func__, func_data->desc->name, ret); -+ return ret; -+} -+ -+int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave) -+{ -+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev); -+ unsigned int val; -+ -+ rt766->disable_irq = false; -+ -+ if (rt766->hw_init) -+ return 0; -+ -+ regcache_cache_only(rt766->regmap, false); -+ if (rt766->first_hw_init) { -+ regcache_cache_bypass(rt766->regmap, true); -+ } else { -+ /* -+ * PM runtime status is marked as 'active' only when a Slave reports as Attached -+ */ -+ -+ /* update count of parent 'active' children */ -+ pm_runtime_set_active(&slave->dev); -+ } -+ -+ pm_runtime_get_noresume(&slave->dev); -+ -+ regmap_read(rt766->regmap, RT766_BOND_LATCH_ID, &val); -+ dev_dbg(&slave->dev, "%s bond ID=0x%x (%s)\n", __func__, val, (val == 0x1) ? "RT767" : "RT766"); -+ -+ /* check function status and initialize if needed */ -+ if (rt766->uaj_func_data) -+ rt766_func_initialize(rt766, rt766->uaj_func_data); -+ if (rt766->sa_func_data) -+ rt766_func_initialize(rt766, rt766->sa_func_data); -+ if (rt766->sm_func_data) -+ rt766_func_initialize(rt766, rt766->sm_func_data); -+ if (rt766->hid_func_data) -+ rt766_func_initialize(rt766, rt766->hid_func_data); -+ -+ if (rt766->first_hw_init) { -+ regcache_cache_bypass(rt766->regmap, false); -+ regcache_mark_dirty(rt766->regmap); -+ } else { -+ rt766->first_hw_init = true; -+ } -+ -+ /* Mark Slave initialization complete */ -+ rt766->hw_init = true; -+ -+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); -+ -+ pm_runtime_put_autosuspend(&slave->dev); -+ -+ return 0; -+} -+ -+MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver"); -+MODULE_AUTHOR("Shuming Fan "); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("SND_SOC_SDCA"); -diff --git a/sound/soc/codecs/rt766-sdca.h b/sound/soc/codecs/rt766-sdca.h -new file mode 100644 ---- /dev/null -+++ b/sound/soc/codecs/rt766-sdca.h -@@ -0,0 +1,140 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * rt766-sdca.h -- RT766 SDCA ALSA SoC audio driver header -+ * -+ * Copyright(c) 2026 Realtek Semiconductor Corp. -+ */ -+ -+#ifndef __RT766_H__ -+#define __RT766_H__ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct rt766_sdca_priv { -+ struct regmap *regmap; -+ struct snd_soc_component *component; -+ struct sdw_slave *slave; -+ bool hw_init; -+ bool first_hw_init; -+ struct snd_soc_jack *hs_jack; -+ struct mutex disable_irq_lock; /* SDCA irq lock protection */ -+ bool disable_irq; -+ int jack_type; -+ bool fu41_dapm_mute; -+ bool fu41_mixer_l_mute; -+ bool fu41_mixer_r_mute; -+ bool fu113_dapm_mute; -+ bool fu113_mixer_mute[4]; -+ bool fu21_dapm_mute; -+ bool fu21_mixer_l_mute; -+ bool fu21_mixer_r_mute; -+ bool fu36_dapm_mute; -+ bool fu36_mixer_l_mute; -+ bool fu36_mixer_r_mute; -+ struct sdca_function_data *uaj_func_data; -+ struct sdca_function_data *sm_func_data; -+ struct sdca_function_data *sa_func_data; -+ struct sdca_function_data *hid_func_data; -+ struct sdca_interrupt_info *irq_info; -+ struct hid_device *hid; -+}; -+ -+/* vendor registers */ -+#define RT766_VERSION_ID 0xc404 -+#define RT766_DEV_ID1 0xc405 -+#define RT766_DEV_ID0 0xc406 -+#define RT766_BOND_LATCH_ID 0xc407 -+ -+#define RT766_HP_POWER_STATE 0x1000004 -+#define RT766_HP_FSM_CTL2_1 0x100000d -+ -+/* MCU Patch address */ -+#define RT766_MCU_PATCH_ADDR1_START 0x10010000 -+#define RT766_MCU_PATCH_ADDR1_END 0x10011fff -+#define RT766_MCU_PATCH_ADDR2_START 0x10020000 -+#define RT766_MCU_PATCH_ADDR2_END 0x10023fff -+ -+/* Buffer address for HID */ -+#define RT766_BUF_ADDR_HID1 0x44030000 -+#define RT766_BUF_ADDR_HID2 0x44030020 -+ -+/* SDCA (Channel) */ -+#define RT766_CH_1 0x01 -+#define RT766_CH_2 0x02 -+#define RT766_CH_3 0x03 -+#define RT766_CH_4 0x04 -+ -+/* RT766 SDCA Control - function number */ -+#define RT766_FUNC_NUM_UAJ 0x01 -+#define RT766_FUNC_NUM_MIC 0x02 -+#define RT766_FUNC_NUM_HID 0x03 -+#define RT766_FUNC_NUM_AMP 0x04 -+ -+/* RT766 SDCA entity */ -+#define RT766_SDCA_ENT_0 0x00 -+#define RT766_SDCA_ENT_HID101 0x01 -+#define RT766_SDCA_ENT_GE49 0x49 -+#define RT766_SDCA_ENT_USER_FU41 0x05 -+#define RT766_SDCA_ENT_USER_FU36 0x0f -+#define RT766_SDCA_ENT_USER_FU21 0x03 -+#define RT766_SDCA_ENT_USER_FU113 0x30 -+#define RT766_SDCA_ENT_PDE23 0x33 -+#define RT766_SDCA_ENT_PDE47 0x28 -+#define RT766_SDCA_ENT_PDE11 0x2a -+#define RT766_SDCA_ENT_PDE34 0x29 -+#define RT766_SDCA_ENT_CS41 0x01 -+#define RT766_SDCA_ENT_CS36 0x11 -+#define RT766_SDCA_ENT_CS113 0x12 -+#define RT766_SDCA_ENT_CS21 0x21 -+#define RT766_SDCA_ENT_PLATFORM_FU33 0x44 -+#define RT766_SDCA_ENT_PPU21 0x04 -+ -+/* sample frequency index */ -+#define RT766_SDCA_RATE_44100HZ 0x08 -+#define RT766_SDCA_RATE_48000HZ 0x09 -+#define RT766_SDCA_RATE_96000HZ 0x0b -+#define RT766_SDCA_RATE_192000HZ 0x0d -+ -+/* SDCA Register macros */ -+#define RT766_MUTE_REG(func, fu, ch) \ -+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_MUTE, RT766_CH_##ch) -+ -+#define RT766_VOLUME_REG(func, fu, ch) \ -+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_CHANNEL_VOLUME, RT766_CH_##ch) -+ -+#define RT766_GAIN_REG(func, fu, ch) \ -+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_GAIN, RT766_CH_##ch) -+ -+#define RT766_PDE_REQ_REG(func, pde) \ -+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_REQUESTED_PS, 0) -+ -+#define RT766_PDE_ACTUAL_REG(func, pde) \ -+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_ACTUAL_PS, 0) -+ -+#define RT766_FUNC_STATUS_REG(func) \ -+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_0, SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0) -+ -+#define RT766_SDCA_CTL(func, ent, ctl) \ -+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##ent, ctl, 0) -+ -+enum { -+ RT766_AIF1, -+ RT766_AIF2, -+ RT766_AIF3, -+}; -+ -+enum { -+ RT766_DAI_UAJ, -+ RT766_DAI_AMP, -+ RT766_DAI_MIC, -+}; -+ -+int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave); -+int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave); -+#endif /* __RT766_H__ */ -diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c ---- a/sound/soc/codecs/rt9120.c -+++ b/sound/soc/codecs/rt9120.c -@@ -606,12 +606,19 @@ static int rt9120_runtime_suspend(struct device *dev) - static int rt9120_runtime_resume(struct device *dev) - { - struct rt9120_data *data = dev_get_drvdata(dev); -+ int ret; - - if (data->pwdnn_gpio) { - gpiod_set_value(data->pwdnn_gpio, 1); - msleep(RT9120_CHIPON_WAITMS); - regcache_cache_only(data->regmap, false); -- regcache_sync(data->regmap); -+ ret = regcache_sync(data->regmap); -+ if (ret) { -+ regcache_cache_only(data->regmap, true); -+ regcache_mark_dirty(data->regmap); -+ gpiod_set_value(data->pwdnn_gpio, 0); -+ return ret; -+ } - } - - return 0; -diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c ---- a/sound/soc/codecs/sigmadsp.c -+++ b/sound/soc/codecs/sigmadsp.c -@@ -5,6 +5,7 @@ - * Copyright 2009-2014 Analog Devices Inc. - */ - -+#include - #include - #include - #include -@@ -135,7 +136,7 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, - uint8_t *data; - int ret = 0; - -- mutex_lock(&sigmadsp->lock); -+ guard(mutex)(&sigmadsp->lock); - - data = ucontrol->value.bytes.data; - -@@ -148,8 +149,6 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, - ctrl->cached = true; - } - -- mutex_unlock(&sigmadsp->lock); -- - return ret; - } - -@@ -160,7 +159,7 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, - struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); - int ret = 0; - -- mutex_lock(&sigmadsp->lock); -+ guard(mutex)(&sigmadsp->lock); - - if (!ctrl->cached) { - ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache, -@@ -174,8 +173,6 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, - ctrl->num_bytes); - } - -- mutex_unlock(&sigmadsp->lock); -- - return ret; - } - -@@ -487,7 +484,7 @@ static void devm_sigmadsp_release(struct device *dev, void *res) - static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) - { - const struct sigma_firmware_header *ssfw_head; -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - int ret; - u32 crc; - -@@ -495,7 +492,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) - ret = request_firmware(&fw, name, sigmadsp->dev); - if (ret) { - pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); -- goto done; -+ return ret; - } - - /* then verify the header */ -@@ -509,13 +506,13 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) - */ - if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { - dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n"); -- goto done; -+ return -EINVAL; - } - - ssfw_head = (void *)fw->data; - if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { - dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n"); -- goto done; -+ return -EINVAL; - } - - crc = crc32(0, fw->data + sizeof(*ssfw_head), -@@ -524,7 +521,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) - if (crc != le32_to_cpu(ssfw_head->crc)) { - dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", - le32_to_cpu(ssfw_head->crc), crc); -- goto done; -+ return -EINVAL; - } - - switch (ssfw_head->version) { -@@ -545,9 +542,6 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) - if (ret) - sigmadsp_firmware_release(sigmadsp); - --done: -- release_firmware(fw); -- - return ret; - } - -@@ -677,10 +671,10 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, - return; - changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active); - if (active && changed > 0) { -- mutex_lock(&sigmadsp->lock); -- if (ctrl->cached) -- sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); -- mutex_unlock(&sigmadsp->lock); -+ scoped_guard(mutex, &sigmadsp->lock) { -+ if (ctrl->cached) -+ sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); -+ } - } - } - -diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c ---- a/sound/soc/codecs/sma1303.c -+++ b/sound/soc/codecs/sma1303.c -@@ -1777,6 +1777,8 @@ static void sma1303_i2c_remove(struct i2c_client *client) - struct sma1303_priv *sma1303 = - (struct sma1303_priv *) i2c_get_clientdata(client); - -+ if (sma1303->attr_grp) -+ sysfs_remove_group(sma1303->kobj, sma1303->attr_grp); - cancel_delayed_work_sync(&sma1303->check_fault_work); - } - -diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c ---- a/sound/soc/codecs/sma1307.c -+++ b/sound/soc/codecs/sma1307.c -@@ -1690,7 +1690,7 @@ static void sma1307_check_fault_worker(struct work_struct *work) - - static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file) - { -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - int size, offset, num_mode; - int ret; - -@@ -1703,22 +1703,18 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil - return; - } else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) { - dev_err(sma1307->dev, "%s: Invalid file\n", __func__); -- release_firmware(fw); - sma1307->set.status = false; - return; - } - - int *data __free(kfree) = kzalloc(fw->size, GFP_KERNEL); - if (!data) { -- release_firmware(fw); - sma1307->set.status = false; - return; - } - size = fw->size >> 2; - memcpy(data, fw->data, fw->size); - -- release_firmware(fw); -- - /* HEADER */ - sma1307->set.header_size = SMA1307_SETTING_HEADER_SIZE; - sma1307->set.checksum = data[sma1307->set.header_size - 2]; -diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c ---- a/sound/soc/codecs/sta32x.c -+++ b/sound/soc/codecs/sta32x.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -269,9 +270,9 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, - int numcoef = kcontrol->private_value >> 16; - int index = kcontrol->private_value & 0xffff; - unsigned int cfud, val; -- int i, ret = 0; -+ int i; - -- mutex_lock(&sta32x->coeff_lock); -+ guard(mutex)(&sta32x->coeff_lock); - - /* preserve reserved bits in STA32X_CFUD */ - regmap_read(sta32x->regmap, STA32X_CFUD, &cfud); -@@ -283,24 +284,20 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, - regmap_write(sta32x->regmap, STA32X_CFUD, cfud); - - regmap_write(sta32x->regmap, STA32X_CFADDR2, index); -- if (numcoef == 1) { -+ if (numcoef == 1) - regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04); -- } else if (numcoef == 5) { -+ else if (numcoef == 5) - regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08); -- } else { -- ret = -EINVAL; -- goto exit_unlock; -- } -+ else -+ return -EINVAL; -+ - - for (i = 0; i < 3 * numcoef; i++) { - regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val); - ucontrol->value.bytes.data[i] = val; - } - --exit_unlock: -- mutex_unlock(&sta32x->coeff_lock); -- -- return ret; -+ return 0; - } - - static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, -diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c ---- a/sound/soc/codecs/sta350.c -+++ b/sound/soc/codecs/sta350.c -@@ -16,6 +16,7 @@ - - #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ - -+#include - #include - #include - #include -@@ -306,9 +307,9 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, - int numcoef = kcontrol->private_value >> 16; - int index = kcontrol->private_value & 0xffff; - unsigned int cfud, val; -- int i, ret = 0; -+ int i; - -- mutex_lock(&sta350->coeff_lock); -+ guard(mutex)(&sta350->coeff_lock); - - /* preserve reserved bits in STA350_CFUD */ - regmap_read(sta350->regmap, STA350_CFUD, &cfud); -@@ -320,24 +321,19 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, - regmap_write(sta350->regmap, STA350_CFUD, cfud); - - regmap_write(sta350->regmap, STA350_CFADDR2, index); -- if (numcoef == 1) { -+ if (numcoef == 1) - regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04); -- } else if (numcoef == 5) { -+ else if (numcoef == 5) - regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08); -- } else { -- ret = -EINVAL; -- goto exit_unlock; -- } -+ else -+ return -EINVAL; - - for (i = 0; i < 3 * numcoef; i++) { - regmap_read(sta350->regmap, STA350_B1CF1 + i, &val); - ucontrol->value.bytes.data[i] = val; - } - --exit_unlock: -- mutex_unlock(&sta350->coeff_lock); -- -- return ret; -+ return 0; - } - - static int sta350_coefficient_put(struct snd_kcontrol *kcontrol, -diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c ---- a/sound/soc/codecs/tac5xx2-sdw.c -+++ b/sound/soc/codecs/tac5xx2-sdw.c -@@ -88,6 +88,9 @@ - #define TAC_FW_FILE_HDR 20 - #define TAC_MAX_FW_CHUNKS 512 - -+#define TAC_UAJ_PREP_CONNECTED 0xff -+#define TAC_UAJ_PREP_DISCONNECTED 0xdf -+ - struct tac_fw_hdr { - u32 size; - u32 version_offset; -@@ -138,6 +141,7 @@ struct tac5xx2_prv { - bool hw_init; - bool first_hw_init_done; - u32 part_id; -+ u32 rev_id; - struct snd_soc_jack *hs_jack; - int jack_type; - /* Custom fw binary. UMP File Download is not used. */ -@@ -261,7 +265,6 @@ static const struct reg_default tac_reg_default[] = { - {TAC_REG_SDW(0, 0, 0x78), 0x0}, - {TAC_REG_SDW(0, 0, 0x7b), 0x0}, - {TAC_REG_SDW(0, 0, 0x7c), 0xd0}, -- {TAC_REG_SDW(0, 0, 0x7d), 0x0}, - {TAC_REG_SDW(0, 0, 0x7e), 0x0}, - {TAC_REG_SDW(0, 1, 0x1), 0x0}, - {TAC_REG_SDW(0, 1, 0x2), 0x0}, -@@ -507,18 +510,6 @@ static const struct regmap_config tac_regmap = { - .use_single_write = true, - }; - --/* Check if device has DSP algo that needs status monitoring */ --static bool tac_has_dsp_algo(struct tac5xx2_prv *tac_dev) --{ -- switch (tac_dev->part_id) { -- case 0x5682: -- case 0x2883: -- return true; -- default: -- return false; -- } --} -- - /* Check if device has UAJ (Universal Audio Jack) support */ - static bool tac_has_uaj_support(struct tac5xx2_prv *tac_dev) - { -@@ -800,7 +791,7 @@ static int tac_sdw_hw_params(struct snd_pcm_substream *substream, - return ret; - } - -- ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, pde_entity, -+ ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity, - SDCA_PDE_PS3, SDCA_PDE_PS0, NULL, 0); - if (ret) - dev_err(tac_dev->dev, "failed to transition func %d, pde %d from PS3 -> PS0, err=%d\n", -@@ -847,7 +838,7 @@ static int tac_sdw_pcm_hw_free(struct snd_pcm_substream *substream, - return ret; - } - -- ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, -+ ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, - pde_entity, SDCA_PDE_PS0, SDCA_PDE_PS3, - NULL, 0); - if (ret) -@@ -942,6 +933,7 @@ static int tac5xx2_sdca_button_detect(struct tac5xx2_prv *tac_dev) - static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) - { - int val, ret; -+ u8 jack_prep; - - ret = regmap_read(tac_dev->regmap, - SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35, -@@ -951,6 +943,8 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) - return ret; - } - -+ jack_prep = TAC_UAJ_PREP_CONNECTED; -+ - switch (val) { - case 4: - tac_dev->jack_type = SND_JACK_MICROPHONE; -@@ -964,6 +958,7 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) - case 0: - default: - tac_dev->jack_type = 0; -+ jack_prep = TAC_UAJ_PREP_DISCONNECTED; - break; - } - -@@ -973,26 +968,44 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) - if (ret) - dev_err(tac_dev->dev, "Failed to update the jack type to device"); - -+ /* -+ * When uaj is uplugged and booted, we end up with the channel prepare -+ * timeout error for the uaj ports. This writes allows the channel prepare -+ * to succeed when the uaj is not plugged in. -+ */ -+ if (tac_dev->rev_id >= 0x30) { -+ ret = regmap_write(tac_dev->regmap, TAC_REG_SDW(0, 3, 127), jack_prep); -+ if (ret) -+ dev_warn(tac_dev->dev, "Failed to write jack_prep register: %d\n", ret); -+ } -+ - return 0; - } - - static int tac5xx2_jack_init(struct tac5xx2_prv *tac_dev) - { -+ u32 jd_int_mask, hid_int_mask; - int ret = 0; - -+ if (tac_dev->rev_id >= 0x30) { -+ jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_12; -+ hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_17; -+ } else { -+ jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_11; -+ hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_16; -+ } -+ - if (!tac_dev->hs_jack) - goto disable_interrupts; - -- ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, -- SDW_SCP_SDCA_INTMASK_SDCA_11); -+ ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, jd_int_mask); - if (ret) { - dev_err(tac_dev->dev, - "Failed to register jack detection interrupt: %d\n", ret); - goto disable_interrupts; - } - -- ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, -- SDW_SCP_SDCA_INTMASK_SDCA_16); -+ ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, hid_int_mask); - if (ret) { - dev_err(tac_dev->dev, - "Failed to register for button detect interrupt: %d\n", ret); -@@ -1051,6 +1064,7 @@ static int tac_interrupt_callback(struct sdw_slave *slave, - unsigned int sdca_int2, sdca_int3, jack_report_mask = 0; - struct tac5xx2_prv *tac_dev = dev_get_drvdata(&slave->dev); - struct device *dev = &slave->dev; -+ u32 headset_detect_chk, hid_detect_chk; - int btn_type = 0; - int ret = 0; - -@@ -1081,14 +1095,22 @@ static int tac_interrupt_callback(struct sdw_slave *slave, - dev_dbg(dev, "SDCA_INT2: 0x%02x, SDCA_INT3: 0x%02x\n", - sdca_int2, sdca_int3); - -- if (sdca_int2 & SDW_SCP_SDCA_INT_SDCA_11) { -+ if (tac_dev->rev_id >= 0x30) { -+ headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_12; -+ hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_17; -+ } else { -+ headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_11; -+ hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_16; -+ } -+ -+ if (sdca_int2 & headset_detect_chk) { - ret = tac5xx2_sdca_headset_detect(tac_dev); - if (ret < 0) - goto clear; - jack_report_mask |= SND_JACK_HEADSET; - } - -- if (sdca_int3 & SDW_SCP_SDCA_INT_SDCA_16) { -+ if (sdca_int3 & hid_detect_chk) { - btn_type = tac5xx2_sdca_button_detect(tac_dev); - if (btn_type < 0) - btn_type = 0; -@@ -1695,6 +1717,15 @@ static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool first) - goto io_init_err; - } - -+ if (!tac_dev->rev_id) { -+ ret = regmap_read(tac_dev->regmap, TAC_REV_ID, &tac_dev->rev_id); -+ if (ret) { -+ dev_err(tac_dev->dev, "failed to rev id, err=%d\n", ret); -+ goto io_init_err; -+ } -+ dev_dbg(tac_dev->dev, "detected rev_id 0x%x", tac_dev->rev_id); -+ } -+ - if (tac_dev->fw_files && tac_dev->fw_file_cnt > 0) { - ret = tac_download_fw_to_hw(tac_dev); - if (ret) { -@@ -1940,7 +1971,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral, - "failed to allocate %s function data", - func_name); - function_data->desc = &peripheral->sdca_data.function[i]; -- ret = sdca_parse_function(dev, peripheral, function_data); -+ ret = sdca_parse_function(dev, function_data); - if (!ret) - *func_ptr = function_data; - else -@@ -1959,6 +1990,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral, - tac_dev->hw_init = false; - tac_dev->first_hw_init_done = false; - tac_dev->part_id = id->part_id; -+ tac_dev->rev_id = 0x0; - dev_set_drvdata(dev, tac_dev); - - regmap = devm_regmap_init_sdw_mbq_cfg(&peripheral->dev, peripheral, -@@ -1972,17 +2004,13 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral, - tac_dev->jack_type = 0; - init_completion(&tac_dev->fw_caching_complete); - -- if (tac_has_dsp_algo(tac_dev)) { -- tac_generate_fw_name(peripheral, tac_dev->fw_binaryname, -- sizeof(tac_dev->fw_binaryname)); -+ tac_generate_fw_name(peripheral, tac_dev->fw_binaryname, -+ sizeof(tac_dev->fw_binaryname)); - -- ret = tac_load_and_cache_firmware_async(tac_dev); -- if (ret) { -- complete_all(&tac_dev->fw_caching_complete); -- dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret); -- } -- } else { -+ ret = tac_load_and_cache_firmware_async(tac_dev); -+ if (ret) { - complete_all(&tac_dev->fw_caching_complete); -+ dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret); - } - - ret = tac_init(tac_dev); -diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c ---- a/sound/soc/codecs/tas2552.c -+++ b/sound/soc/codecs/tas2552.c -@@ -495,13 +495,21 @@ static int tas2552_runtime_suspend(struct device *dev) - static int tas2552_runtime_resume(struct device *dev) - { - struct tas2552_data *tas2552 = dev_get_drvdata(dev); -+ int ret; - - gpiod_set_value_cansleep(tas2552->enable_gpio, 1); - - tas2552_sw_shutdown(tas2552, 0); - - regcache_cache_only(tas2552->regmap, false); -- regcache_sync(tas2552->regmap); -+ ret = regcache_sync(tas2552->regmap); -+ if (ret) { -+ regcache_cache_only(tas2552->regmap, true); -+ regcache_mark_dirty(tas2552->regmap); -+ tas2552_sw_shutdown(tas2552, 1); -+ gpiod_set_value_cansleep(tas2552->enable_gpio, 0); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c ---- a/sound/soc/codecs/tas2781-comlib-i2c.c -+++ b/sound/soc/codecs/tas2781-comlib-i2c.c -@@ -6,6 +6,7 @@ - // - // Author: Shenghao Ding - -+#include - #include - #include - #include -@@ -342,7 +343,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, - /* Codec Lock Hold to ensure that codec_probe and firmware parsing and - * loading do not simultaneously execute. - */ -- mutex_lock(&tas_priv->codec_lock); -+ guard(mutex)(&tas_priv->codec_lock); - - if (tas_priv->name_prefix) - scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin", -@@ -360,8 +361,6 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, - dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n", - ret); - -- /* Codec Lock Release*/ -- mutex_unlock(&tas_priv->codec_lock); - return ret; - } - EXPORT_SYMBOL_GPL(tascodec_init); -diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c ---- a/sound/soc/codecs/tas2781-fmwlib.c -+++ b/sound/soc/codecs/tas2781-fmwlib.c -@@ -2253,7 +2253,7 @@ int tas2781_load_calibration(void *context, char *file_name, - { - struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; - struct tasdevice *tasdev = &(tas_priv->tasdevice[i]); -- const struct firmware *fw_entry = NULL; -+ const struct firmware *fw_entry __free(firmware) = NULL; - struct tasdevice_fw *tas_fmw; - struct firmware fmw; - int offset = 0; -@@ -2263,60 +2263,50 @@ int tas2781_load_calibration(void *context, char *file_name, - if (ret) { - dev_err(tas_priv->dev, "%s: Request firmware %s failed\n", - __func__, file_name); -- goto out; -+ return ret; - } - - if (!fw_entry->size) { - dev_err(tas_priv->dev, "%s: file read error: size = %lu\n", - __func__, (unsigned long)fw_entry->size); -- ret = -EINVAL; -- goto out; -+ return -EINVAL; - } - fmw.size = fw_entry->size; - fmw.data = fw_entry->data; - - tas_fmw = tasdev->cali_data_fmw = kzalloc_obj(struct tasdevice_fw); -- if (!tasdev->cali_data_fmw) { -- ret = -ENOMEM; -- goto out; -- } -+ if (!tasdev->cali_data_fmw) -+ return -ENOMEM; -+ - tas_fmw->dev = tas_priv->dev; - offset = fw_parse_header(tas_priv, tas_fmw, &fmw, offset); - if (offset == -EINVAL) { - dev_err(tas_priv->dev, "fw_parse_header EXIT!\n"); -- ret = offset; -- goto out; -+ return -EINVAL; - } - offset = fw_parse_variable_hdr_cal(tas_priv, tas_fmw, &fmw, offset); - if (offset == -EINVAL) { - dev_err(tas_priv->dev, - "%s: fw_parse_variable_header_cal EXIT!\n", __func__); -- ret = offset; -- goto out; -+ return -EINVAL; - } - offset = fw_parse_program_data(tas_priv, tas_fmw, &fmw, offset); - if (offset < 0) { - dev_err(tas_priv->dev, "fw_parse_program_data EXIT!\n"); -- ret = offset; -- goto out; -+ return offset; - } - offset = fw_parse_configuration_data(tas_priv, tas_fmw, &fmw, offset); - if (offset < 0) { - dev_err(tas_priv->dev, "fw_parse_configuration_data EXIT!\n"); -- ret = offset; -- goto out; -+ return offset; - } - offset = fw_parse_calibration_data(tas_priv, tas_fmw, &fmw, offset); - if (offset < 0) { - dev_err(tas_priv->dev, "fw_parse_calibration_data EXIT!\n"); -- ret = offset; -- goto out; -+ return offset; - } - --out: -- release_firmware(fw_entry); -- -- return ret; -+ return 0; - } - EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, "SND_SOC_TAS2781_FMWLIB"); - -@@ -2409,7 +2399,7 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw, - int tasdevice_dsp_parser(void *context) - { - struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context; -- const struct firmware *fw_entry; -+ const struct firmware *fw_entry __free(firmware) = NULL; - int ret; - - ret = request_firmware(&fw_entry, tas_priv->coef_binaryname, -@@ -2417,15 +2407,10 @@ int tasdevice_dsp_parser(void *context) - if (ret) { - dev_err(tas_priv->dev, "%s: load %s error\n", __func__, - tas_priv->coef_binaryname); -- goto out; -+ return ret; - } - -- ret = tasdevice_dspfw_ready(fw_entry, tas_priv); -- release_firmware(fw_entry); -- fw_entry = NULL; -- --out: -- return ret; -+ return tasdevice_dspfw_ready(fw_entry, tas_priv); - } - EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, "SND_SOC_TAS2781_FMWLIB"); - -@@ -2807,11 +2792,12 @@ int tasdevice_prmg_load(void *context, int prm_no) - } - EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, "SND_SOC_TAS2781_FMWLIB"); - --void tasdevice_tuning_switch(void *context, int state) -+void tasdevice_tuning_switch(void *context, int state, bool is_cap) - { - struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; - struct tasdevice_fw *tas_fmw = tas_priv->fmw; -- int profile_cfg_id = tas_priv->rcabin.profile_cfg_id; -+ int profile_cfg_id = is_cap ? tas_priv->rcabin.capture_profile_id : -+ tas_priv->rcabin.profile_cfg_id; - - /* - * Only RCA-based Playback can still work with no dsp program running -@@ -2828,7 +2814,6 @@ void tasdevice_tuning_switch(void *context, int state) - if (state == 0) { - if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) { - /* dsp mode or tuning mode */ -- profile_cfg_id = tas_priv->rcabin.profile_cfg_id; - tasdevice_select_tuningprm_cfg(tas_priv, - tas_priv->cur_prog, tas_priv->cur_conf, - profile_cfg_id); -diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c ---- a/sound/soc/codecs/tas2781-i2c.c -+++ b/sound/soc/codecs/tas2781-i2c.c -@@ -13,6 +13,7 @@ - // Author: Kevin Lu - // - -+#include - #include - #include - #include -@@ -617,6 +618,7 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol, - { - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp); -+ int i; - - guard(mutex)(&priv->codec_lock); - if (priv->chip_id == TAS2563) -@@ -624,6 +626,14 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol, - else - tas2781_calib_stop_put(priv); - -+ /* -+ * Set reloading-firmware flag after calibration, the flag will work -+ * during next playback, then set to the program id after reloading -+ * firmware. -+ */ -+ for (i = 0; i < priv->ndev; i++) -+ priv->tasdevice[i].cur_prog = -1; -+ - return 1; - } - -@@ -843,12 +853,12 @@ static int tasdevice_digital_gain_get( - unsigned char data[4]; - int ret; - -- mutex_lock(&tas_dev->codec_lock); -+ guard(mutex)(&tas_dev->codec_lock); - /* Read the primary device */ - ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); - if (ret) { - dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); -- goto out; -+ return ret; - } - - target = get_unaligned_be32(&data[0]); -@@ -868,8 +878,7 @@ static int tasdevice_digital_gain_get( - /* find out the member same as or closer to the current volume */ - ucontrol->value.integer.value[0] = - abs(target - ar_l) <= abs(target - ar_r) ? l : r; --out: -- mutex_unlock(&tas_dev->codec_lock); -+ - return 0; - } - -@@ -882,29 +891,26 @@ static int tasdevice_digital_gain_put( - struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); - struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec); - int vol = ucontrol->value.integer.value[0]; -- int status = 0, max = mc->max, rc = 1; -+ int status = 0, max = mc->max; - int i, ret; - unsigned int reg = mc->reg; - unsigned int volrd, volwr; - unsigned char data[4]; - - vol = clamp(vol, 0, max); -- mutex_lock(&tas_dev->codec_lock); -+ guard(mutex)(&tas_dev->codec_lock); - /* Read the primary device */ - ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4); - if (ret) { - dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__); -- rc = -1; -- goto out; -+ return -1; - } - - volrd = get_unaligned_be32(&data[0]); - volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]); - -- if (volrd == volwr) { -- rc = 0; -- goto out; -- } -+ if (volrd == volwr) -+ return 0; - - for (i = 0; i < tas_dev->ndev; i++) { - ret = tasdevice_dev_bulk_write(tas_dev, i, reg, -@@ -918,10 +924,9 @@ static int tasdevice_digital_gain_put( - } - - if (status) -- rc = -1; --out: -- mutex_unlock(&tas_dev->codec_lock); -- return rc; -+ return -1; -+ -+ return 1; - } - - static const struct snd_kcontrol_new tasdevice_cali_controls[] = { -@@ -995,6 +1000,57 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, - return ret; - } - -+/** -+ * tasdevice_set_capture_profile_id - Set runtime capture profile index via -+ * ALSA control -+ * @kcontrol: ALSA kcontrol handle that triggers this operation -+ * @ucontrol: User space control value carrying the new profile index -+ * -+ * This mixer control handler validates the user-provided capture profile ID -+ * against the maximum valid index parsed from the loaded DSP firmware, -+ * then updates the runtime stored capture profile ID only if the new value -+ * differs from the current active one. It will immediately return -EINVAL -+ * if the submitted profile ID falls outside the valid range, including the -+ * edge case that no valid configuration blocks are detected in firmware. -+ * -+ * No actual DSP register write is performed in this handler. The updated -+ * profile ID will be applied to the hardware when the next ALSA capture -+ * stream starts up. Caller does not need to take extra codec lock here, -+ * as the ALSA control core already guarantees serialized execution. -+ * -+ * Return: 1 if profile ID value was changed, 0 if no modification needed, -+ * -EINVAL if the input profile ID is out of valid range -+ */ -+static int tasdevice_set_capture_profile_id(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); -+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); -+ unsigned int user_prof_id = ucontrol->value.integer.value[0]; -+ unsigned int max_valid_id; -+ int ret = 0; -+ -+ /* -+ * Align valid range with the bound defined in -+ * tasdevice_info_profile() -+ */ -+ max_valid_id = tas_priv->rcabin.ncfgs - 1; -+ -+ /* -+ * Reject invalid input including zero total configuration edge -+ * case -+ */ -+ if (tas_priv->rcabin.ncfgs == 0 || user_prof_id > max_valid_id) -+ return -EINVAL; -+ -+ if (tas_priv->rcabin.capture_profile_id != user_prof_id) { -+ tas_priv->rcabin.capture_profile_id = user_prof_id; -+ ret = 1; -+ } -+ -+ return ret; -+} -+ - static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) - { -@@ -1075,6 +1131,41 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, - return 0; - } - -+/** -+ * tasdevice_get_capture_profile_id - Report current active capture profile -+ * ID to user space -+ * @kcontrol: ALSA kcontrol structure passed from ALSA core -+ * @ucontrol: User-space control element value buffer to write the result back -+ * -+ * This function ensures the returned profile ID is always clamped inside the -+ * valid range advertised by the info callback, preventing accidental invalid -+ * values from being exposed to applications even if internal driver state is -+ * temporarily inconsistent. -+ * -+ * Returns 0 on successful fill of the control value, no error conditions -+ * are defined for this getter callback. -+ */ -+static int tasdevice_get_capture_profile_id(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); -+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); -+ unsigned int max_valid_id, current_prof_id; -+ -+ max_valid_id = tas_priv->rcabin.ncfgs > 0 ? -+ (tas_priv->rcabin.ncfgs - 1U) : 0; -+ -+ /* -+ * Cast current profile id to unsigned to match type with max_valid_id, -+ * avoid signedness mismatch; -+ */ -+ current_prof_id = (unsigned int)tas_priv->rcabin.capture_profile_id; -+ /* Prevent underflow when there are no loaded capture profiles. */ -+ ucontrol->value.integer.value[0] = min(current_prof_id, max_valid_id); -+ -+ return 0; -+} -+ - static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) - { -@@ -1117,6 +1208,41 @@ static int tasdevice_create_control(struct tasdevice_priv *tas_priv) - ret = snd_soc_add_component_controls(tas_priv->codec, - prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index); - -+ mix_index = 0; -+ switch (tas_priv->chip_id) { -+ case TAS2563: -+ case TAS2568: -+ case TAS2570: -+ case TAS2572: -+ case TAS2573: -+ case TAS2574: -+ case TAS2781: -+ prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls, -+ sizeof(prof_ctrls[0]), GFP_KERNEL); -+ if (!prof_ctrls) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ /* Create a mixer item for selecting the capture profile */ -+ name = devm_kstrdup(tas_priv->dev, "Speaker Capture Profile Id", -+ GFP_KERNEL); -+ if (!name) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ prof_ctrls[mix_index].name = name; -+ prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; -+ prof_ctrls[mix_index].info = tasdevice_info_profile; -+ prof_ctrls[mix_index].get = tasdevice_get_capture_profile_id; -+ prof_ctrls[mix_index].put = tasdevice_set_capture_profile_id; -+ mix_index++; -+ -+ ret = snd_soc_add_component_controls(tas_priv->codec, -+ prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index); -+ break; -+ } -+ - out: - return ret; - } -@@ -1330,6 +1456,43 @@ static void alpa_cali_update(struct bulk_reg_val *p, - p->val_len = 4; - } - -+static int create_tas2781_cali_start_ktrl(struct tasdevice_priv -+ *priv, struct snd_kcontrol_new *cali_ctrl) -+{ -+ struct soc_bytes_ext *ext_cali_start; -+ char *cali_start_name; -+ -+ ext_cali_start = devm_kzalloc(priv->dev, -+ sizeof(*ext_cali_start), GFP_KERNEL); -+ if (!ext_cali_start) -+ return -ENOMEM; -+ -+ cali_start_name = devm_kstrdup(priv->dev, -+ "Calibration Start", GFP_KERNEL); -+ if (!cali_start_name) -+ return -ENOMEM; -+ /* -+ * package structure for tas2781 ftc start: -+ * Pkg len (1 byte) -+ * Reg id (1 byte, constant 'r') -+ * book, page, register for pilot threshold, pilot tone -+ * and sine gain (12 bytes) -+ * for (i = 0; i < Device-Sum; i++) { -+ * Device #i index_info (1 byte) -+ * Sine gain for Device #i (8 bytes) -+ * } -+ */ -+ ext_cali_start->max = 14 + priv->ndev * 9; -+ cali_ctrl->name = cali_start_name; -+ cali_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER; -+ cali_ctrl->info = snd_soc_bytes_info_ext; -+ cali_ctrl->put = tas2781_calib_start_put; -+ cali_ctrl->get = tasdev_nop_get; -+ cali_ctrl->private_value = (unsigned long)ext_cali_start; -+ -+ return 0; -+} -+ - static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) - { - struct calidata *cali_data = &priv->cali_data; -@@ -1448,37 +1611,11 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) - */ - cali_data->data[0] = 0xff; - if (priv->chip_id == TAS2781) { -- struct soc_bytes_ext *ext_cali_start; -- char *cali_start_name; -- -- ext_cali_start = devm_kzalloc(priv->dev, -- sizeof(*ext_cali_start), GFP_KERNEL); -- if (!ext_cali_start) -- return -ENOMEM; -- -- cali_start_name = devm_kstrdup(priv->dev, -- "Calibration Start", GFP_KERNEL); -- if (!cali_start_name) -- return -ENOMEM; -- /* -- * package structure for tas2781 ftc start: -- * Pkg len (1 byte) -- * Reg id (1 byte, constant 'r') -- * book, page, register for pilot threshold, pilot tone -- * and sine gain (12 bytes) -- * for (i = 0; i < Device-Sum; i++) { -- * Device #i index_info (1 byte) -- * Sine gain for Device #i (8 bytes) -- * } -- */ -- ext_cali_start->max = 14 + priv->ndev * 9; -- cali_ctrls[i].name = cali_start_name; -- cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; -- cali_ctrls[i].info = snd_soc_bytes_info_ext; -- cali_ctrls[i].put = tas2781_calib_start_put; -- cali_ctrls[i].get = tasdev_nop_get; -- cali_ctrls[i].private_value = (unsigned long)ext_cali_start; -+ rc = create_tas2781_cali_start_ktrl(priv, &cali_ctrls[i]); -+ if (rc != 0) -+ return rc; - i++; -+ - } - - return snd_soc_add_component_controls(priv->codec, cali_ctrls, -@@ -1765,13 +1902,25 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w, - struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); - int state = 0; - -- /* Codec Lock Hold */ -- mutex_lock(&tas_priv->codec_lock); -+ guard(mutex)(&tas_priv->codec_lock); - if (event == SND_SOC_DAPM_PRE_PMD) - state = 1; -- tasdevice_tuning_switch(tas_priv, state); -- /* Codec Lock Release*/ -- mutex_unlock(&tas_priv->codec_lock); -+ tasdevice_tuning_switch(tas_priv, state, false); -+ -+ return 0; -+} -+ -+static int tasdevice_capture_dapm_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm); -+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); -+ int state = 0; -+ -+ guard(mutex)(&tas_priv->codec_lock); -+ if (event == SND_SOC_DAPM_PRE_PMD) -+ state = 1; -+ tasdevice_tuning_switch(tas_priv, state, true); - - return 0; - } -@@ -1779,7 +1928,7 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w, - static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = { - SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT_E("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM, -- 0, 0, tasdevice_dapm_event, -+ 0, 0, tasdevice_capture_dapm_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event), - SND_SOC_DAPM_OUTPUT("OUT"), -diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c ---- a/sound/soc/codecs/tas2783-sdw.c -+++ b/sound/soc/codecs/tas2783-sdw.c -@@ -12,6 +12,7 @@ - // Author: Baojun Xu - // Author: Kevin Lu - -+#include - #include - #include - #include -@@ -494,6 +495,56 @@ static bool tas2783_readable_register(struct device *dev, unsigned int reg) - return tas2783_sdca_mbq_size(dev, reg) > 0; - } - -+static bool tas2783_writeable_register(struct device *dev, unsigned int reg) -+{ -+ /* -+ * The Latency Control of every Entity, together with the Power Domain -+ * actual state and the protection status, is read-only. They are -+ * listed in tas2783_reg_default[] with a placeholder value, so without -+ * this a regcache_sync() would try to write them back and the -+ * peripheral would reject the transaction, aborting the sync. -+ */ -+ switch (reg) { -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU21, 0x10, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU23, 0x10, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU26, 0x10, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x06, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x07, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS24, 0x02, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS21, 0x02, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS25, 0x02, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS26, 0x02, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS28, 0x02, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PDE23, 0x10, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_UDMPU23, 0x06, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x05, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x11, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU21, 0x06, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU26, 0x06, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT21, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT29, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT26, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT28, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT24, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT23, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT25, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT28, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MU26, 0x06, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT127, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU127, 0x10, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS127, 0x02, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x04, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x08, 0): -+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x04, 0): -+ return false; -+ -+ default: -+ return tas2783_sdca_mbq_size(dev, reg) > 0; -+ } -+} -+ - static bool tas2783_volatile_register(struct device *dev, u32 reg) - { - switch (reg) { -@@ -515,6 +566,7 @@ static const struct regmap_config tas_regmap = { - .reg_bits = 32, - .val_bits = 8, - .readable_reg = tas2783_readable_register, -+ .writeable_reg = tas2783_writeable_register, - .volatile_reg = tas2783_volatile_register, - .reg_defaults = tas2783_reg_default, - .num_reg_defaults = ARRAY_SIZE(tas2783_reg_default), -@@ -692,12 +744,12 @@ static s32 tas2783_update_calibdata(struct tas2783_prv *tas_dev) - return 0; - } - -- mutex_lock(&tas_dev->calib_lock); -- ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data, -- tas_dev->cali_data.read_sz); -- if (!ret) -- tas2783_set_calib_params_to_device(tas_dev, tmp_val); -- mutex_unlock(&tas_dev->calib_lock); -+ scoped_guard(mutex, &tas_dev->calib_lock) { -+ ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data, -+ tas_dev->cali_data.read_sz); -+ if (!ret) -+ tas2783_set_calib_params_to_device(tas_dev, tmp_val); -+ } - - return ret; - } -@@ -926,22 +978,23 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream, - dev_err(tas_dev->dev, - "clear latch failed, err=%d", ret); - -- mutex_lock(&tas_dev->pde_lock); -- /* -- * Sometimes, there is error returned during power on. -- * So added retry logic to ensure power on so that -- * port prepare succeeds -- */ -- do { -- ret = regmap_write(tas_dev->regmap, -- SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, -- TAS2783_SDCA_CTL_REQ_POW_STATE, 0), -- TAS2783_SDCA_POW_STATE_ON); -- if (!ret) -- break; -- usleep_range(2000, 2200); -- } while (retry--); -- mutex_unlock(&tas_dev->pde_lock); -+ scoped_guard(mutex, &tas_dev->pde_lock) { -+ /* -+ * Sometimes, there is error returned during power on. -+ * So added retry logic to ensure power on so that -+ * port prepare succeeds -+ */ -+ do { -+ ret = regmap_write(tas_dev->regmap, -+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, -+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0), -+ TAS2783_SDCA_POW_STATE_ON); -+ if (!ret) -+ break; -+ usleep_range(2000, 2200); -+ } while (retry--); -+ } -+ - if (ret) - return ret; - -@@ -965,7 +1018,6 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream, - static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { -- s32 ret; - struct snd_soc_component *component = dai->component; - struct tas2783_prv *tas_dev = - snd_soc_component_get_drvdata(component); -@@ -974,14 +1026,11 @@ static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream, - - sdw_stream_remove_slave(tas_dev->sdw_peripheral, sdw_stream); - -- mutex_lock(&tas_dev->pde_lock); -- ret = regmap_write(tas_dev->regmap, -- SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, -- TAS2783_SDCA_CTL_REQ_POW_STATE, 0), -- TAS2783_SDCA_POW_STATE_OFF); -- mutex_unlock(&tas_dev->pde_lock); -- -- return ret; -+ guard(mutex)(&tas_dev->pde_lock); -+ return regmap_write(tas_dev->regmap, -+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, -+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0), -+ TAS2783_SDCA_POW_STATE_OFF); - } - - static const struct snd_soc_dai_ops tas_dai_ops = { -@@ -1349,7 +1398,7 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral, - function_data->desc = &peripheral->sdca_data.function[i]; - - /* Parse the function */ -- ret = sdca_parse_function(dev, peripheral, function_data); -+ ret = sdca_parse_function(dev, function_data); - if (!ret) - tas_dev->sa_func_data = function_data; - else -diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c ---- a/sound/soc/codecs/tas5805m.c -+++ b/sound/soc/codecs/tas5805m.c -@@ -12,6 +12,7 @@ - // - // It has been simplified a little and reworked for the 5.x ALSA SoC API. - -+#include - #include - #include - #include -@@ -230,10 +231,9 @@ static int tas5805m_vol_get(struct snd_kcontrol *kcontrol, - struct tas5805m_priv *tas5805m = - snd_soc_component_get_drvdata(component); - -- mutex_lock(&tas5805m->lock); -+ guard(mutex)(&tas5805m->lock); - ucontrol->value.integer.value[0] = tas5805m->vol[0]; - ucontrol->value.integer.value[1] = tas5805m->vol[1]; -- mutex_unlock(&tas5805m->lock); - - return 0; - } -@@ -249,13 +249,12 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct tas5805m_priv *tas5805m = - snd_soc_component_get_drvdata(component); -- int ret = 0; - - if (!(volume_is_valid(ucontrol->value.integer.value[0]) && - volume_is_valid(ucontrol->value.integer.value[1]))) - return -EINVAL; - -- mutex_lock(&tas5805m->lock); -+ guard(mutex)(&tas5805m->lock); - if (tas5805m->vol[0] != ucontrol->value.integer.value[0] || - tas5805m->vol[1] != ucontrol->value.integer.value[1]) { - tas5805m->vol[0] = ucontrol->value.integer.value[0]; -@@ -265,11 +264,10 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol, - tas5805m->is_powered); - if (tas5805m->is_powered) - tas5805m_refresh(tas5805m); -- ret = 1; -+ return 1; - } -- mutex_unlock(&tas5805m->lock); - -- return ret; -+ return 0; - } - - static const struct snd_kcontrol_new tas5805m_snd_controls[] = { -@@ -332,7 +330,7 @@ static void do_work(struct work_struct *work) - - dev_dbg(&tas5805m->i2c->dev, "DSP startup\n"); - -- mutex_lock(&tas5805m->lock); -+ guard(mutex)(&tas5805m->lock); - /* We mustn't issue any I2C transactions until the I2S - * clock is stable. Furthermore, we must allow a 5ms - * delay after the first set of register writes to -@@ -345,7 +343,6 @@ static void do_work(struct work_struct *work) - - tas5805m->is_powered = true; - tas5805m_refresh(tas5805m); -- mutex_unlock(&tas5805m->lock); - } - - static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, -@@ -362,7 +359,7 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, - dev_dbg(component->dev, "DSP shutdown\n"); - cancel_work_sync(&tas5805m->work); - -- mutex_lock(&tas5805m->lock); -+ guard(mutex)(&tas5805m->lock); - if (tas5805m->is_powered) { - tas5805m->is_powered = false; - -@@ -379,7 +376,6 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w, - - regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ); - } -- mutex_unlock(&tas5805m->lock); - } - - return 0; -@@ -414,14 +410,13 @@ static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction) - struct tas5805m_priv *tas5805m = - snd_soc_component_get_drvdata(component); - -- mutex_lock(&tas5805m->lock); -+ guard(mutex)(&tas5805m->lock); - dev_dbg(component->dev, "set mute=%d (is_powered=%d)\n", - mute, tas5805m->is_powered); - - tas5805m->is_muted = mute; - if (tas5805m->is_powered) - tas5805m_refresh(tas5805m); -- mutex_unlock(&tas5805m->lock); - - return 0; - } -@@ -462,7 +457,6 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) - struct tas5805m_priv *tas5805m; - char filename[128]; - const char *config_name; -- const struct firmware *fw; - int ret; - - regmap = devm_regmap_init_i2c(i2c, &tas5805m_regmap); -@@ -507,24 +501,20 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) - - snprintf(filename, sizeof(filename), "tas5805m_dsp_%s.bin", - config_name); -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, filename, dev); - if (ret) - return ret; - - if ((fw->size < 2) || (fw->size & 1)) { - dev_err(dev, "firmware is invalid\n"); -- release_firmware(fw); - return -EINVAL; - } - - tas5805m->dsp_cfg_len = fw->size; - tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL); -- if (!tas5805m->dsp_cfg_data) { -- release_firmware(fw); -+ if (!tas5805m->dsp_cfg_data) - return -ENOMEM; -- } -- -- release_firmware(fw); - - /* Do the first part of the power-on here, while we can expect - * the I2S interface to be quiet. We must raise PDN# and then -diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c ---- a/sound/soc/codecs/tlv320aic26.c -+++ b/sound/soc/codecs/tlv320aic26.c -@@ -320,8 +320,14 @@ static int aic26_probe(struct snd_soc_component *component) - return 0; - } - -+static void aic26_remove(struct snd_soc_component *component) -+{ -+ device_remove_file(component->dev, &dev_attr_keyclick); -+} -+ - static const struct snd_soc_component_driver aic26_soc_component_dev = { - .probe = aic26_probe, -+ .remove = aic26_remove, - .controls = aic26_snd_controls, - .num_controls = ARRAY_SIZE(aic26_snd_controls), - .dapm_widgets = tlv320aic26_dapm_widgets, -diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c ---- a/sound/soc/codecs/tlv320aic31xx.c -+++ b/sound/soc/codecs/tlv320aic31xx.c -@@ -1720,18 +1720,14 @@ static int tlv320dac3100_fw_load(struct aic31xx_priv *aic31xx, - static int tlv320dac3100_load_coeffs(struct aic31xx_priv *aic31xx, - const char *fw_name) - { -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - int ret; - - ret = request_firmware(&fw, fw_name, aic31xx->dev); - if (ret) - return ret; - -- ret = tlv320dac3100_fw_load(aic31xx, fw->data, fw->size); -- -- release_firmware(fw); -- -- return ret; -+ return tlv320dac3100_fw_load(aic31xx, fw->data, fw->size); - } - - static int aic31xx_i2c_probe(struct i2c_client *i2c) -diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c ---- a/sound/soc/codecs/tlv320aic32x4-clk.c -+++ b/sound/soc/codecs/tlv320aic32x4-clk.c -@@ -1,5 +1,5 @@ --/* SPDX-License-Identifier: GPL-2.0 -- * -+// SPDX-License-Identifier: GPL-2.0 -+/* - * Clock Tree for the Texas Instruments TLV320AIC32x4 - * - * Copyright 2019 Annaliese McDermond -@@ -9,6 +9,7 @@ - - #include - #include -+#include - #include - #include - -@@ -57,7 +58,7 @@ static void clk_aic32x4_pll_unprepare(struct clk_hw *hw) - struct clk_aic32x4 *pll = to_clk_aic32x4(hw); - - regmap_update_bits(pll->regmap, AIC32X4_PLLPR, -- AIC32X4_PLLEN, 0); -+ AIC32X4_PLLEN, 0); - } - - static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw) -@@ -75,7 +76,7 @@ static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw) - } - - static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll, -- struct clk_aic32x4_pll_muldiv *settings) -+ struct clk_aic32x4_pll_muldiv *settings) - { - /* Change to use regmap_bulk_read? */ - unsigned int val; -@@ -106,19 +107,19 @@ static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll, - } - - static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll, -- struct clk_aic32x4_pll_muldiv *settings) -+ struct clk_aic32x4_pll_muldiv *settings) - { - int ret; - /* Change to use regmap_bulk_write for some if not all? */ - - ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR, -- AIC32X4_PLL_R_MASK, settings->r); -+ AIC32X4_PLL_R_MASK, settings->r); - if (ret < 0) - return ret; - - ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR, -- AIC32X4_PLL_P_MASK, -- settings->p << AIC32X4_PLL_P_SHIFT); -+ AIC32X4_PLL_P_MASK, -+ settings->p << AIC32X4_PLL_P_SHIFT); - if (ret < 0) - return ret; - -@@ -136,23 +137,21 @@ static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll, - return 0; - } - --static unsigned long clk_aic32x4_pll_calc_rate( -- struct clk_aic32x4_pll_muldiv *settings, -- unsigned long parent_rate) -+static unsigned long clk_aic32x4_pll_calc_rate(struct clk_aic32x4_pll_muldiv *settings, -+ unsigned long parent_rate) - { - u64 rate; - /* - * We scale j by 10000 to account for the decimal part of P and divide - * it back out later. - */ -- rate = (u64) parent_rate * settings->r * -- ((settings->j * 10000) + settings->d); -+ rate = (u64)parent_rate * settings->r * ((settings->j * 10000) + settings->d); - -- return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000); -+ return (unsigned long)DIV_ROUND_UP_ULL(rate, settings->p * 10000); - } - - static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, -- unsigned long rate, unsigned long parent_rate) -+ unsigned long rate, unsigned long parent_rate) - { - u64 multiplier; - -@@ -165,14 +164,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, - * of the multiplier. This is because we can't do floating point - * math in the kernel. - */ -- multiplier = (u64) rate * settings->p * 10000; -+ multiplier = (u64)rate * settings->p * 10000; - do_div(multiplier, parent_rate); - - /* - * J can't be over 64, so R can scale this. - * R can't be greater than 4. - */ -- settings->r = ((u32) multiplier / 640000) + 1; -+ settings->r = ((u32)multiplier / 640000) + 1; - if (settings->r > 4) - return -1; - do_div(multiplier, settings->r); -@@ -184,14 +183,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings, - return -1; - - /* Figure out the integer part, J, and the fractional part, D. */ -- settings->j = (u32) multiplier / 10000; -- settings->d = (u32) multiplier % 10000; -+ settings->j = (u32)multiplier / 10000; -+ settings->d = (u32)multiplier % 10000; - - return 0; - } - - static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw, -- unsigned long parent_rate) -+ unsigned long parent_rate) - { - struct clk_aic32x4 *pll = to_clk_aic32x4(hw); - struct clk_aic32x4_pll_muldiv settings; -@@ -220,8 +219,8 @@ static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw, - } - - static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, -- unsigned long rate, -- unsigned long parent_rate) -+ unsigned long rate, -+ unsigned long parent_rate) - { - struct clk_aic32x4 *pll = to_clk_aic32x4(hw); - struct clk_aic32x4_pll_muldiv settings; -@@ -236,7 +235,7 @@ static int clk_aic32x4_pll_set_rate(struct clk_hw *hw, - return ret; - - /* 10ms is the delay to wait before the clocks are stable */ -- msleep(10); -+ usleep_range(10000, 20000); - - return 0; - } -@@ -261,7 +260,6 @@ static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw) - return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT; - } - -- - static const struct clk_ops aic32x4_pll_ops = { - .prepare = clk_aic32x4_pll_prepare, - .unprepare = clk_aic32x4_pll_unprepare, -@@ -311,11 +309,11 @@ static void clk_aic32x4_div_unprepare(struct clk_hw *hw) - struct clk_aic32x4 *div = to_clk_aic32x4(hw); - - regmap_update_bits(div->regmap, div->reg, -- AIC32X4_DIVEN, 0); -+ AIC32X4_DIVEN, 0); - } - - static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate, -- unsigned long parent_rate) -+ unsigned long parent_rate) - { - struct clk_aic32x4 *div = to_clk_aic32x4(hw); - u8 divisor; -@@ -342,7 +340,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw, - } - - static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw, -- unsigned long parent_rate) -+ unsigned long parent_rate) - { - struct clk_aic32x4 *div = to_clk_aic32x4(hw); - unsigned int val; -@@ -399,7 +397,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { - { - .name = "pll", - .parent_names = -- (const char* []) { "mclk", "bclk", "gpio", "din" }, -+ (const char *[]) { "mclk", "bclk", "gpio", "din" }, - .num_parents = 4, - .ops = &aic32x4_pll_ops, - .reg = 0, -@@ -414,28 +412,28 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { - }, - { - .name = "ndac", -- .parent_names = (const char * []) { "codec_clkin" }, -+ .parent_names = (const char *[]) { "codec_clkin" }, - .num_parents = 1, - .ops = &aic32x4_div_ops, - .reg = AIC32X4_NDAC, - }, - { - .name = "mdac", -- .parent_names = (const char * []) { "ndac" }, -+ .parent_names = (const char *[]) { "ndac" }, - .num_parents = 1, - .ops = &aic32x4_div_ops, - .reg = AIC32X4_MDAC, - }, - { - .name = "nadc", -- .parent_names = (const char * []) { "codec_clkin" }, -+ .parent_names = (const char *[]) { "codec_clkin" }, - .num_parents = 1, - .ops = &aic32x4_div_ops, - .reg = AIC32X4_NADC, - }, - { - .name = "madc", -- .parent_names = (const char * []) { "nadc" }, -+ .parent_names = (const char *[]) { "nadc" }, - .num_parents = 1, - .ops = &aic32x4_div_ops, - .reg = AIC32X4_MADC, -@@ -451,7 +449,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = { - }; - - static struct clk *aic32x4_register_clk(struct device *dev, -- struct aic32x4_clkdesc *desc) -+ struct aic32x4_clkdesc *desc) - { - struct clk_init_data init; - struct clk_aic32x4 *priv; -@@ -464,8 +462,8 @@ static struct clk *aic32x4_register_clk(struct device *dev, - init.flags = 0; - - priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL); -- if (priv == NULL) -- return (struct clk *) -ENOMEM; -+ if (!priv) -+ return ERR_PTR(-ENOMEM); - - priv->dev = dev; - priv->hw.init = &init; -diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c ---- a/sound/soc/codecs/tlv320aic32x4-i2c.c -+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c -@@ -1,11 +1,10 @@ --/* SPDX-License-Identifier: GPL-2.0 -- * -+// SPDX-License-Identifier: GPL-2.0 -+/* - * Copyright 2011-2019 NW Digital Radio - * - * Author: Annaliese McDermond - * - * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. -- * - */ - - #include -@@ -16,17 +15,23 @@ - - #include "tlv320aic32x4.h" - -+static const struct regmap_config aic32x4_i2c_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = AIC32X4_REFPOWERUP, -+ .ranges = aic32x4_regmap_pages, -+ .num_ranges = 1, -+}; -+ - static int aic32x4_i2c_probe(struct i2c_client *i2c) - { - struct regmap *regmap; -- struct regmap_config config; - enum aic32x4_type type; - -- config = aic32x4_regmap_config; -- config.reg_bits = 8; -- config.val_bits = 8; -+ regmap = devm_regmap_init_i2c(i2c, &aic32x4_i2c_regmap_config); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); - -- regmap = devm_regmap_init_i2c(i2c, &config); - type = (uintptr_t)i2c_get_match_data(i2c); - - return aic32x4_probe(&i2c->dev, regmap, type); -diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c ---- a/sound/soc/codecs/tlv320aic32x4-spi.c -+++ b/sound/soc/codecs/tlv320aic32x4-spi.c -@@ -1,11 +1,10 @@ --/* SPDX-License-Identifier: GPL-2.0 -- * -+// SPDX-License-Identifier: GPL-2.0 -+/* - * Copyright 2011-2019 NW Digital Radio - * - * Author: Annaliese McDermond - * - * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. -- * - */ - - #include -@@ -16,19 +15,25 @@ - - #include "tlv320aic32x4.h" - -+static const struct regmap_config aic32x4_spi_regmap_config = { -+ .reg_bits = 7, -+ .pad_bits = 1, -+ .val_bits = 8, -+ .read_flag_mask = 0x01, -+ .max_register = AIC32X4_REFPOWERUP, -+ .ranges = aic32x4_regmap_pages, -+ .num_ranges = 1, -+}; -+ - static int aic32x4_spi_probe(struct spi_device *spi) - { - struct regmap *regmap; -- struct regmap_config config; - enum aic32x4_type type; - -- config = aic32x4_regmap_config; -- config.reg_bits = 7; -- config.pad_bits = 1; -- config.val_bits = 8; -- config.read_flag_mask = 0x01; -+ regmap = devm_regmap_init_spi(spi, &aic32x4_spi_regmap_config); -+ if (IS_ERR(regmap)) -+ return PTR_ERR(regmap); - -- regmap = devm_regmap_init_spi(spi, &config); - type = (uintptr_t)spi_get_device_match_data(spi); - - return aic32x4_probe(&spi->dev, regmap, type); -diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c ---- a/sound/soc/codecs/tlv320aic32x4.c -+++ b/sound/soc/codecs/tlv320aic32x4.c -@@ -1,7 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * linux/sound/soc/codecs/tlv320aic32x4.c -- * - * Copyright 2011 Vista Silicon S.L. - * - * Author: Javier Martin -@@ -28,7 +26,6 @@ - #include - #include - #include --#include - - #include "tlv320aic32x4.h" - -@@ -45,7 +42,8 @@ struct aic32x4_priv { - struct regulator *supply_dv; - struct regulator *supply_av; - -- struct aic32x4_setup_data *setup; -+ unsigned int gpio_func[5]; -+ - struct device *dev; - enum aic32x4_type type; - -@@ -75,7 +73,7 @@ static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w, - }; - - static int mic_bias_event(struct snd_soc_dapm_widget *w, -- struct snd_kcontrol *kcontrol, int event) -+ struct snd_kcontrol *kcontrol, int event) - { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - -@@ -83,25 +81,23 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, - case SND_SOC_DAPM_POST_PMU: - /* Change Mic Bias Registor */ - snd_soc_component_update_bits(component, AIC32X4_MICBIAS, -- AIC32x4_MICBIAS_MASK, -- AIC32X4_MICBIAS_LDOIN | -- AIC32X4_MICBIAS_2075V); -- printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__); -+ AIC32x4_MICBIAS_MASK, -+ AIC32X4_MICBIAS_LDOIN | -+ AIC32X4_MICBIAS_2075V); -+ dev_dbg(component->dev, "Mic Bias will be turned ON\n"); - break; - case SND_SOC_DAPM_PRE_PMD: - snd_soc_component_update_bits(component, AIC32X4_MICBIAS, -- AIC32x4_MICBIAS_MASK, 0); -- printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n", -- __func__); -+ AIC32x4_MICBIAS_MASK, 0); -+ dev_dbg(component->dev, "Mic Bias will be turned OFF\n"); - break; - } - - return 0; - } - -- - static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - u8 val; -@@ -114,7 +110,7 @@ static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, - }; - - static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - u8 val; -@@ -123,8 +119,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, - val = snd_soc_component_read(component, AIC32X4_DOUTCTL); - gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); - if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { -- printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n", -- __func__); -+ dev_err(component->dev, "MFP2 is not configure as a GPIO output\n"); - return -EINVAL; - } - -@@ -142,7 +137,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol, - }; - - static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - u8 val; -@@ -155,7 +150,7 @@ static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol, - }; - - static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - u8 val; -@@ -164,8 +159,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, - val = snd_soc_component_read(component, AIC32X4_MISOCTL); - gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED); - if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) { -- printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n", -- __func__); -+ dev_err(component->dev, "MFP4 is not configure as a GPIO output\n"); - return -EINVAL; - } - -@@ -183,7 +177,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol, - }; - - static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - u8 val; -@@ -195,7 +189,7 @@ static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol, - }; - - static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) -+ struct snd_ctl_elem_value *ucontrol) - { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - u8 val; -@@ -204,8 +198,7 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, - val = snd_soc_component_read(component, AIC32X4_GPIOCTL); - gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT); - if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) { -- printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n", -- __func__); -+ dev_err(component->dev, "MFP5 is not configure as a GPIO output\n"); - return -EINVAL; - } - -@@ -222,25 +215,31 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol, - return 0; - }; - --static const struct snd_kcontrol_new aic32x4_mfp1[] = { -- SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL), --}; -- --static const struct snd_kcontrol_new aic32x4_mfp2[] = { -- SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio), --}; -- --static const struct snd_kcontrol_new aic32x4_mfp3[] = { -- SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL), --}; -- --static const struct snd_kcontrol_new aic32x4_mfp4[] = { -- SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio), --}; -- --static const struct snd_kcontrol_new aic32x4_mfp5[] = { -- SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio, -- aic32x4_set_mfp5_gpio), -+static const struct { -+ unsigned int reg; -+ struct snd_kcontrol_new ctrl; -+} aic32x4_mfp_cfg[] = { -+ { -+ .reg = AIC32X4_DINCTL, -+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL), -+ }, -+ { -+ .reg = AIC32X4_DOUTCTL, -+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio), -+ }, -+ { -+ .reg = AIC32X4_SCLKCTL, -+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL), -+ }, -+ { -+ .reg = AIC32X4_MISOCTL, -+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio), -+ }, -+ { -+ .reg = AIC32X4_GPIOCTL, -+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio, -+ aic32x4_set_mfp5_gpio), -+ }, - }; - - /* 0dB min, 0.5dB steps */ -@@ -270,53 +269,42 @@ static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text); - - static const struct snd_kcontrol_new aic32x4_snd_controls[] = { - SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, -- AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), -+ AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), - SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum), - SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum), - SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, -- AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, -- tlv_driver_gain), -+ AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain), - SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, -- AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, -- tlv_driver_gain), -+ AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain), - SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, -- AIC32X4_HPRGAIN, 6, 0x01, 1), -+ AIC32X4_HPRGAIN, 6, 0x01, 1), - SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, -- AIC32X4_LORGAIN, 6, 0x01, 1), -+ AIC32X4_LORGAIN, 6, 0x01, 1), - SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum), - SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL, -- AIC32X4_RMICPGAVOL, 7, 0x01, 1), -+ AIC32X4_RMICPGAVOL, 7, 0x01, 1), - - SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0), - SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0), - - SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL, -- AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol), -+ AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol), - SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL, -- AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), -+ AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), - - SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), - - SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0), - SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0), -- SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, -- 4, 0x07, 0), -- SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, -- 0, 0x03, 0), -- SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, -- 6, 0x03, 0), -- SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, -- 1, 0x1F, 0), -- SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, -- 0, 0x7F, 0), -- SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, -- 3, 0x1F, 0), -- SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, -- 3, 0x1F, 0), -- SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, -- 0, 0x1F, 0), -- SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, -- 0, 0x0F, 0), -+ SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, 4, 0x07, 0), -+ SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, 0, 0x03, 0), -+ SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, 6, 0x03, 0), -+ SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, 1, 0x1F, 0), -+ SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, 0, 0x7F, 0), -+ SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, 3, 0x1F, 0), -+ SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, 3, 0x1F, 0), -+ SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, 0, 0x1F, 0), -+ SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, 0, 0x0F, 0), - }; - - static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { -@@ -354,21 +342,27 @@ static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_te - static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = { - SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum), - }; -+ - static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = { - SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum), - }; -+ - static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = { - SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum), - }; -+ - static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = { - SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum), - }; -+ - static const struct snd_kcontrol_new cml_to_lmixer_controls[] = { - SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum), - }; -+ - static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = { - SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum), - }; -+ - static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = { - SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum), - }; -@@ -385,21 +379,27 @@ static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_te - static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = { - SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum), - }; -+ - static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = { - SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum), - }; -+ - static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = { - SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum), - }; -+ - static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = { - SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum), - }; -+ - static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = { - SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum), - }; -+ - static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = { - SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum), - }; -+ - static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = { - SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum), - }; -@@ -428,38 +428,38 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { - - SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), - SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in1r_to_rmixer_controls), -+ in1r_to_rmixer_controls), - SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in2r_to_rmixer_controls), -+ in2r_to_rmixer_controls), - SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in3r_to_rmixer_controls), -+ in3r_to_rmixer_controls), - SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in2l_to_rmixer_controls), -+ in2l_to_rmixer_controls), - SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, -- cmr_to_rmixer_controls), -+ cmr_to_rmixer_controls), - SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, -- in1l_to_rmixer_controls), -+ in1l_to_rmixer_controls), - SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, -- in3l_to_rmixer_controls), -+ in3l_to_rmixer_controls), - - SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), - SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in1l_to_lmixer_controls), -+ in1l_to_lmixer_controls), - SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in2l_to_lmixer_controls), -+ in2l_to_lmixer_controls), - SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in3l_to_lmixer_controls), -+ in3l_to_lmixer_controls), - SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, -- in1r_to_lmixer_controls), -+ in1r_to_lmixer_controls), - SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, -- cml_to_lmixer_controls), -+ cml_to_lmixer_controls), - SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, -- in2r_to_lmixer_controls), -+ in2r_to_lmixer_controls), - SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, -- in3r_to_lmixer_controls), -+ in3r_to_lmixer_controls), - - SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event, -- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - - SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc), - -@@ -575,7 +575,7 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { - {"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"}, - }; - --static const struct regmap_range_cfg aic32x4_regmap_pages[] = { -+const struct regmap_range_cfg aic32x4_regmap_pages[] = { - { - .selector_reg = 0, - .selector_mask = 0xff, -@@ -585,13 +585,7 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = { - .range_max = AIC32X4_REFPOWERUP, - }, - }; -- --const struct regmap_config aic32x4_regmap_config = { -- .max_register = AIC32X4_REFPOWERUP, -- .ranges = aic32x4_regmap_pages, -- .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), --}; --EXPORT_SYMBOL(aic32x4_regmap_config); -+EXPORT_SYMBOL_GPL(aic32x4_regmap_pages); - - static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -@@ -624,7 +618,7 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) - case SND_SOC_DAIFMT_CBC_CFC: - break; - default: -- printk(KERN_ERR "aic32x4: invalid clock provider\n"); -+ dev_err(component->dev, "invalid clock provider\n"); - return -EINVAL; - } - -@@ -651,19 +645,20 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) - AIC32X4_IFACE1_DATATYPE_SHIFT); - break; - default: -- printk(KERN_ERR "aic32x4: invalid DAI interface format\n"); -+ dev_err(component->dev, "invalid DAI interface format\n"); - return -EINVAL; - } - - aic32x4->fmt = fmt; - - snd_soc_component_update_bits(component, AIC32X4_IFACE1, -- AIC32X4_IFACE1_DATATYPE_MASK | -- AIC32X4_IFACE1_MASTER_MASK, iface_reg_1); -+ AIC32X4_IFACE1_DATATYPE_MASK | -+ AIC32X4_IFACE1_MASTER_MASK, -+ iface_reg_1); - snd_soc_component_update_bits(component, AIC32X4_IFACE2, -- AIC32X4_DATA_OFFSET_MASK, iface_reg_2); -+ AIC32X4_DATA_OFFSET_MASK, iface_reg_2); - snd_soc_component_update_bits(component, AIC32X4_IFACE3, -- AIC32X4_BCLKINV_MASK, iface_reg_3); -+ AIC32X4_BCLKINV_MASK, iface_reg_3); - - return 0; - } -@@ -676,14 +671,13 @@ static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr) - static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr) - { - snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8); -- snd_soc_component_write(component, AIC32X4_DOSRLSB, -- (dosr & 0xff)); -+ snd_soc_component_write(component, AIC32X4_DOSRLSB, dosr & 0xff); - - return 0; - } - - static int aic32x4_set_processing_blocks(struct snd_soc_component *component, -- u8 r_block, u8 p_block) -+ u8 r_block, u8 p_block) - { - struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); - -@@ -703,6 +697,45 @@ static int aic32x4_set_processing_blocks(struct snd_soc_component *component, - return 0; - } - -+static int aic32x4_configure_rate(struct snd_soc_component *component, -+ unsigned int rate, u8 *aosr, u8 *adc_rc, -+ u8 *dac_rc, u8 *dosr_inc) -+{ -+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); -+ u8 prb_rx, prb_tx; -+ -+ if (rate <= 48000) { -+ *aosr = 128; -+ *adc_rc = 6; -+ *dac_rc = 8; -+ *dosr_inc = 8; -+ prb_rx = 1; -+ prb_tx = 1; -+ } else if (rate <= 96000) { -+ *aosr = 64; -+ *adc_rc = 6; -+ *dac_rc = 8; -+ *dosr_inc = 4; -+ prb_rx = 1; -+ prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 9; -+ } else if (rate == 192000) { -+ *aosr = 32; -+ *adc_rc = 3; -+ *dac_rc = 4; -+ *dosr_inc = 2; -+ prb_rx = 13; -+ prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 19; -+ } else { -+ dev_err(component->dev, "Sampling rate %u not supported\n", rate); -+ return -EINVAL; -+ } -+ -+ if (aic32x4->type == AIC32X4_TYPE_TAS2505) -+ prb_rx = 0; -+ -+ return aic32x4_set_processing_blocks(component, prb_rx, prb_tx); -+} -+ - static int aic32x4_setup_clocks(struct snd_soc_component *component, - unsigned int sample_rate, unsigned int channels, - unsigned int bit_depth) -@@ -717,7 +750,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, - unsigned long adc_clock_rate, dac_clock_rate; - int ret; - -- static struct clk_bulk_data clocks[] = { -+ struct clk_bulk_data clocks[] = { - { .id = "pll" }, - { .id = "nadc" }, - { .id = "madc" }, -@@ -729,37 +762,11 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, - if (ret) - return ret; - -- if (sample_rate <= 48000) { -- aosr = 128; -- adc_resource_class = 6; -- dac_resource_class = 8; -- dosr_increment = 8; -- if (aic32x4->type == AIC32X4_TYPE_TAS2505) -- aic32x4_set_processing_blocks(component, 0, 1); -- else -- aic32x4_set_processing_blocks(component, 1, 1); -- } else if (sample_rate <= 96000) { -- aosr = 64; -- adc_resource_class = 6; -- dac_resource_class = 8; -- dosr_increment = 4; -- if (aic32x4->type == AIC32X4_TYPE_TAS2505) -- aic32x4_set_processing_blocks(component, 0, 1); -- else -- aic32x4_set_processing_blocks(component, 1, 9); -- } else if (sample_rate == 192000) { -- aosr = 32; -- adc_resource_class = 3; -- dac_resource_class = 4; -- dosr_increment = 2; -- if (aic32x4->type == AIC32X4_TYPE_TAS2505) -- aic32x4_set_processing_blocks(component, 0, 1); -- else -- aic32x4_set_processing_blocks(component, 13, 19); -- } else { -- dev_err(component->dev, "Sampling rate not supported\n"); -- return -EINVAL; -- } -+ ret = aic32x4_configure_rate(component, sample_rate, &aosr, -+ &adc_resource_class, &dac_resource_class, -+ &dosr_increment); -+ if (ret) -+ return ret; - - /* PCM over I2S is always 2-channel */ - if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) -@@ -781,50 +788,39 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component, - (min_mdac * dosr * sample_rate); - for (mdac = min_mdac; mdac <= 128; ++mdac) { - for (ndac = max_ndac; ndac > 0; --ndac) { -- dac_clock_rate = ndac * mdac * dosr * -- sample_rate; -- if (dac_clock_rate == adc_clock_rate) { -- if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0) -- continue; -+ dac_clock_rate = ndac * mdac * dosr * sample_rate; -+ if (dac_clock_rate != adc_clock_rate) -+ continue; - -- clk_set_rate(clocks[0].clk, -- dac_clock_rate); -+ if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0) -+ continue; - -- clk_set_rate(clocks[1].clk, -- sample_rate * aosr * -- madc); -- clk_set_rate(clocks[2].clk, -- sample_rate * aosr); -- aic32x4_set_aosr(component, -- aosr); -+ clk_set_rate(clocks[0].clk, dac_clock_rate); - -- clk_set_rate(clocks[3].clk, -- sample_rate * dosr * -- mdac); -- clk_set_rate(clocks[4].clk, -- sample_rate * dosr); -- aic32x4_set_dosr(component, -- dosr); -+ clk_set_rate(clocks[1].clk, sample_rate * aosr * madc); -+ clk_set_rate(clocks[2].clk, sample_rate * aosr); -+ aic32x4_set_aosr(component, aosr); - -- clk_set_rate(clocks[5].clk, -- sample_rate * channels * -- bit_depth); -+ clk_set_rate(clocks[3].clk, sample_rate * dosr * mdac); -+ clk_set_rate(clocks[4].clk, sample_rate * dosr); -+ aic32x4_set_dosr(component, dosr); - -- return 0; -- } -+ clk_set_rate(clocks[5].clk, -+ sample_rate * channels * bit_depth); -+ -+ return 0; - } - } - } - } - -- dev_err(component->dev, -- "Could not set clocks to support sample rate.\n"); -+ dev_err(component->dev, "Could not set clocks to support sample rate.\n"); - return -EINVAL; - } - - static int aic32x4_hw_params(struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params, -- struct snd_soc_dai *dai) -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) - { - struct snd_soc_component *component = dai->component; - struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); -@@ -837,24 +833,20 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, - - switch (params_physical_width(params)) { - case 16: -- iface1_reg |= (AIC32X4_WORD_LEN_16BITS << -- AIC32X4_IFACE1_DATALEN_SHIFT); -+ iface1_reg |= (AIC32X4_WORD_LEN_16BITS << AIC32X4_IFACE1_DATALEN_SHIFT); - break; - case 20: -- iface1_reg |= (AIC32X4_WORD_LEN_20BITS << -- AIC32X4_IFACE1_DATALEN_SHIFT); -+ iface1_reg |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_IFACE1_DATALEN_SHIFT); - break; - case 24: -- iface1_reg |= (AIC32X4_WORD_LEN_24BITS << -- AIC32X4_IFACE1_DATALEN_SHIFT); -+ iface1_reg |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_IFACE1_DATALEN_SHIFT); - break; - case 32: -- iface1_reg |= (AIC32X4_WORD_LEN_32BITS << -- AIC32X4_IFACE1_DATALEN_SHIFT); -+ iface1_reg |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_IFACE1_DATALEN_SHIFT); - break; - } - snd_soc_component_update_bits(component, AIC32X4_IFACE1, -- AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); -+ AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); - - if (params_channels(params) == 1) { - dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; -@@ -865,7 +857,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, - dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; - } - snd_soc_component_update_bits(component, AIC32X4_DACSETUP, -- AIC32X4_DAC_CHAN_MASK, dacsetup_reg); -+ AIC32X4_DAC_CHAN_MASK, dacsetup_reg); - - return 0; - } -@@ -875,7 +867,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction) - struct snd_soc_component *component = dai->component; - - snd_soc_component_update_bits(component, AIC32X4_DACMUTE, -- AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); -+ AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); - - return 0; - } -@@ -886,7 +878,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component, - struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - int ret; - -- static struct clk_bulk_data clocks[] = { -+ struct clk_bulk_data clocks[] = { - { .id = "madc" }, - { .id = "mdac" }, - { .id = "bdiv" }, -@@ -955,44 +947,14 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component) - struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); - - /* setup GPIO functions */ -- /* MFP1 */ -- if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) { -- snd_soc_component_write(component, AIC32X4_DINCTL, -- aic32x4->setup->gpio_func[0]); -- snd_soc_add_component_controls(component, aic32x4_mfp1, -- ARRAY_SIZE(aic32x4_mfp1)); -- } -+ BUILD_BUG_ON(ARRAY_SIZE(aic32x4->gpio_func) != ARRAY_SIZE(aic32x4_mfp_cfg)); -+ for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) { -+ if (aic32x4->gpio_func[i] == AIC32X4_MFPX_DEFAULT_VALUE) -+ continue; - -- /* MFP2 */ -- if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) { -- snd_soc_component_write(component, AIC32X4_DOUTCTL, -- aic32x4->setup->gpio_func[1]); -- snd_soc_add_component_controls(component, aic32x4_mfp2, -- ARRAY_SIZE(aic32x4_mfp2)); -- } -- -- /* MFP3 */ -- if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) { -- snd_soc_component_write(component, AIC32X4_SCLKCTL, -- aic32x4->setup->gpio_func[2]); -- snd_soc_add_component_controls(component, aic32x4_mfp3, -- ARRAY_SIZE(aic32x4_mfp3)); -- } -- -- /* MFP4 */ -- if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) { -- snd_soc_component_write(component, AIC32X4_MISOCTL, -- aic32x4->setup->gpio_func[3]); -- snd_soc_add_component_controls(component, aic32x4_mfp4, -- ARRAY_SIZE(aic32x4_mfp4)); -- } -- -- /* MFP5 */ -- if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) { -- snd_soc_component_write(component, AIC32X4_GPIOCTL, -- aic32x4->setup->gpio_func[4]); -- snd_soc_add_component_controls(component, aic32x4_mfp5, -- ARRAY_SIZE(aic32x4_mfp5)); -+ snd_soc_component_write(component, aic32x4_mfp_cfg[i].reg, -+ aic32x4->gpio_func[i]); -+ snd_soc_add_component_controls(component, &aic32x4_mfp_cfg[i].ctrl, 1); - } - } - -@@ -1002,7 +964,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) - u32 tmp_reg; - int ret; - -- static struct clk_bulk_data clocks[] = { -+ struct clk_bulk_data clocks[] = { - { .id = "codec_clkin" }, - { .id = "pll" }, - { .id = "bdiv" }, -@@ -1013,8 +975,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) - if (ret) - return ret; - -- if (aic32x4->setup) -- aic32x4_setup_gpios(component); -+ aic32x4_setup_gpios(component); - - clk_set_parent(clocks[0].clk, clocks[1].clk); - clk_set_parent(clocks[2].clk, clocks[3].clk); -@@ -1022,7 +983,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component) - /* Power platform configuration */ - if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) { - snd_soc_component_write(component, AIC32X4_MICBIAS, -- AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V); -+ AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V); - } - if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE) - snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE); -@@ -1041,16 +1002,16 @@ static int aic32x4_component_probe(struct snd_soc_component *component) - /* Mic PGA routing */ - if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) - snd_soc_component_write(component, AIC32X4_LMICPGANIN, -- AIC32X4_LMICPGANIN_IN2R_10K); -+ AIC32X4_LMICPGANIN_IN2R_10K); - else - snd_soc_component_write(component, AIC32X4_LMICPGANIN, -- AIC32X4_LMICPGANIN_CM1L_10K); -+ AIC32X4_LMICPGANIN_CM1L_10K); - if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) - snd_soc_component_write(component, AIC32X4_RMICPGANIN, -- AIC32X4_RMICPGANIN_IN1L_10K); -+ AIC32X4_RMICPGANIN_IN1L_10K); - else - snd_soc_component_write(component, AIC32X4_RMICPGANIN, -- AIC32X4_RMICPGANIN_CM1R_10K); -+ AIC32X4_RMICPGANIN_CM1R_10K); - - /* - * Workaround: for an unknown reason, the ADC needs to be powered up -@@ -1058,8 +1019,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component) - * a HW BUG or some kind of behavior not documented in the datasheet. - */ - tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP); -- snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg | -- AIC32X4_LADC_EN | AIC32X4_RADC_EN); -+ snd_soc_component_write(component, AIC32X4_ADCSETUP, -+ tmp_reg | AIC32X4_LADC_EN | AIC32X4_RADC_EN); - snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg); - - /* -@@ -1102,13 +1063,13 @@ static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = { - SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum), - - SOC_SINGLE_TLV("HP Driver Gain Volume", -- AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain), -+ AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain), - SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1), - - SOC_SINGLE_TLV("Speaker Driver Playback Volume", -- TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain), -+ TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain), - SOC_SINGLE_TLV("Speaker Amplifier Playback Volume", -- TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol), -+ TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol), - - SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), - }; -@@ -1144,11 +1105,12 @@ static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = { - static struct snd_soc_dai_driver aic32x4_tas2505_dai = { - .name = "tas2505-hifi", - .playback = { -- .stream_name = "Playback", -- .channels_min = 1, -- .channels_max = 2, -- .rates = SNDRV_PCM_RATE_8000_96000, -- .formats = AIC32X4_FORMATS,}, -+ .stream_name = "Playback", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_96000, -+ .formats = AIC32X4_FORMATS, -+ }, - .ops = &aic32x4_ops, - .symmetric_rate = 1, - }; -@@ -1159,7 +1121,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) - u32 tmp_reg; - int ret; - -- static struct clk_bulk_data clocks[] = { -+ struct clk_bulk_data clocks[] = { - { .id = "codec_clkin" }, - { .id = "pll" }, - { .id = "bdiv" }, -@@ -1170,8 +1132,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) - if (ret) - return ret; - -- if (aic32x4->setup) -- aic32x4_setup_gpios(component); -+ aic32x4_setup_gpios(component); - - clk_set_parent(clocks[0].clk, clocks[1].clk); - clk_set_parent(clocks[2].clk, clocks[3].clk); -@@ -1192,7 +1153,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component) - snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg); - - /* -- * Enable the fast charging feature and ensure the needed 40ms ellapsed -+ * Enable the fast charging feature and ensure the needed 40ms elapsed - * before using the analog circuits. - */ - snd_soc_component_write(component, TAS2505_REFPOWERUP, -@@ -1218,17 +1179,10 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 = - .endianness = 1, - }; - --static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, -- struct device_node *np) -+static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np) - { -- struct aic32x4_setup_data *aic32x4_setup; - int ret; - -- aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup), -- GFP_KERNEL); -- if (!aic32x4_setup) -- return -ENOMEM; -- - ret = of_property_match_string(np, "clock-names", "mclk"); - if (ret < 0) - return -EINVAL; -@@ -1245,9 +1199,11 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, - gpiod_set_consumer_name(aic32x4->rstn_gpio, "tlv320aic32x4_rstn"); - } - -- if (of_property_read_u32_array(np, "aic32x4-gpio-func", -- aic32x4_setup->gpio_func, 5) >= 0) -- aic32x4->setup = aic32x4_setup; -+ for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) -+ aic32x4->gpio_func[i] = AIC32X4_MFPX_DEFAULT_VALUE; -+ of_property_read_u32_array(np, "aic32x4-gpio-func", -+ aic32x4->gpio_func, ARRAY_SIZE(aic32x4->gpio_func)); -+ - return 0; - } - -@@ -1266,7 +1222,7 @@ static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4) - } - - static int aic32x4_setup_regulators(struct device *dev, -- struct aic32x4_priv *aic32x4) -+ struct aic32x4_priv *aic32x4) - { - int ret = 0; - -@@ -1356,12 +1312,8 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, - struct device_node *np = dev->of_node; - int ret; - -- if (IS_ERR(regmap)) -- return PTR_ERR(regmap); -- -- aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), -- GFP_KERNEL); -- if (aic32x4 == NULL) -+ aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), GFP_KERNEL); -+ if (!aic32x4) - return -ENOMEM; - - aic32x4->dev = dev; -@@ -1405,11 +1357,13 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap, - switch (aic32x4->type) { - case AIC32X4_TYPE_TAS2505: - ret = devm_snd_soc_register_component(dev, -- &soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1); -+ &soc_component_dev_aic32x4_tas2505, -+ &aic32x4_tas2505_dai, 1); - break; - default: - ret = devm_snd_soc_register_component(dev, -- &soc_component_dev_aic32x4, &aic32x4_dai, 1); -+ &soc_component_dev_aic32x4, -+ &aic32x4_dai, 1); - } - - if (ret) { -diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h ---- a/sound/soc/codecs/tlv320aic32x4.h -+++ b/sound/soc/codecs/tlv320aic32x4.h -@@ -3,7 +3,6 @@ - * tlv320aic32x4.h - */ - -- - #ifndef _TLV320AIC32X4_H - #define _TLV320AIC32X4_H - -@@ -16,7 +15,7 @@ enum aic32x4_type { - AIC32X4_TYPE_TAS2505, - }; - --extern const struct regmap_config aic32x4_regmap_config; -+extern const struct regmap_range_cfg aic32x4_regmap_pages[]; - int aic32x4_probe(struct device *dev, struct regmap *regmap, - enum aic32x4_type type); - void aic32x4_remove(struct device *dev); -@@ -24,7 +23,7 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); - - /* tlv320aic32x4 register space (in decimal to match datasheet) */ - --#define AIC32X4_REG(page, reg) ((page * 128) + reg) -+#define AIC32X4_REG(page, reg) (((page) * 128) + (reg)) - - #define AIC32X4_PSEL AIC32X4_REG(0, 0) - -@@ -234,4 +233,31 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name); - #define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000 - #define AIC32X4_MAX_PLL_CLKIN 20000000 - -+#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001 -+#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002 -+#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004 -+#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008 -+#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010 -+ -+#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001 -+#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002 -+ -+/* GPIO API */ -+#define AIC32X4_MFPX_DEFAULT_VALUE 0xff -+ -+#define AIC32X4_MFP1_DIN_DISABLED 0 -+#define AIC32X4_MFP1_DIN_ENABLED 0x2 -+#define AIC32X4_MFP1_GPIO_IN 0x4 -+ -+#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0 -+#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1 -+ -+#define AIC32X4_MFP_GPIO_ENABLED 0x4 -+ -+#define AIC32X4_MFP5_GPIO_DISABLED 0x0 -+#define AIC32X4_MFP5_GPIO_INPUT 0x8 -+#define AIC32X4_MFP5_GPIO_OUTPUT 0xc -+#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0 -+#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1 -+ - #endif /* _TLV320AIC32X4_H */ -diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c ---- a/sound/soc/codecs/tlv320dac33.c -+++ b/sound/soc/codecs/tlv320dac33.c -@@ -7,6 +7,7 @@ - * Copyright: (C) 2009 Nokia Corporation - */ - -+#include - #include - #include - #include -@@ -236,13 +237,10 @@ static int dac33_write_locked(struct snd_soc_component *component, unsigned int - unsigned int value) - { - struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); -- int ret; - -- mutex_lock(&dac33->mutex); -- ret = dac33_write(component, reg, value); -- mutex_unlock(&dac33->mutex); -+ guard(mutex)(&dac33->mutex); - -- return ret; -+ return dac33_write(component, reg, value); - } - - #define DAC33_I2C_ADDR_AUTOINC 0x80 -@@ -365,13 +363,13 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) - struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); - int ret = 0; - -- mutex_lock(&dac33->mutex); -+ guard(mutex)(&dac33->mutex); - - /* Safety check */ - if (unlikely(power == dac33->chip_power)) { - dev_dbg(component->dev, "Trying to set the same power state: %s\n", - power ? "ON" : "OFF"); -- goto exit; -+ return ret; - } - - if (power) { -@@ -380,7 +378,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) - if (ret != 0) { - dev_err(component->dev, - "Failed to enable supplies: %d\n", ret); -- goto exit; -+ return ret; - } - - if (dac33->reset_gpiod) { -@@ -388,7 +386,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) - if (ret < 0) { - dev_err(&dac33->i2c->dev, - "Failed to set reset GPIO: %d\n", ret); -- goto exit; -+ return ret; - } - } - -@@ -400,7 +398,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) - if (ret < 0) { - dev_err(&dac33->i2c->dev, - "Failed to set reset GPIO: %d\n", ret); -- goto exit; -+ return ret; - } - } - -@@ -409,14 +407,12 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) - if (ret != 0) { - dev_err(component->dev, - "Failed to disable supplies: %d\n", ret); -- goto exit; -+ return ret; - } - - dac33->chip_power = 0; - } - --exit: -- mutex_unlock(&dac33->mutex); - return ret; - } - -@@ -659,7 +655,6 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) - { - struct snd_soc_component *component = dac33->component; - unsigned int delay; -- unsigned long flags; - - switch (dac33->fifo_mode) { - case DAC33_FIFO_MODE1: -@@ -667,10 +662,10 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) - DAC33_THRREG(dac33->nsample)); - - /* Take the timestamps */ -- spin_lock_irqsave(&dac33->lock, flags); -- dac33->t_stamp2 = ktime_to_us(ktime_get()); -- dac33->t_stamp1 = dac33->t_stamp2; -- spin_unlock_irqrestore(&dac33->lock, flags); -+ scoped_guard(spinlock_irqsave, &dac33->lock) { -+ dac33->t_stamp2 = ktime_to_us(ktime_get()); -+ dac33->t_stamp1 = dac33->t_stamp2; -+ } - - dac33_write16(component, DAC33_PREFILL_MSB, - DAC33_THRREG(dac33->alarm_threshold)); -@@ -682,11 +677,11 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) - break; - case DAC33_FIFO_MODE7: - /* Take the timestamp */ -- spin_lock_irqsave(&dac33->lock, flags); -- dac33->t_stamp1 = ktime_to_us(ktime_get()); -- /* Move back the timestamp with drain time */ -- dac33->t_stamp1 -= dac33->mode7_us_to_lthr; -- spin_unlock_irqrestore(&dac33->lock, flags); -+ scoped_guard(spinlock_irqsave, &dac33->lock) { -+ dac33->t_stamp1 = ktime_to_us(ktime_get()); -+ /* Move back the timestamp with drain time */ -+ dac33->t_stamp1 -= dac33->mode7_us_to_lthr; -+ } - - dac33_write16(component, DAC33_PREFILL_MSB, - DAC33_THRREG(DAC33_MODE7_MARGIN)); -@@ -704,14 +699,12 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) - static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33) - { - struct snd_soc_component *component = dac33->component; -- unsigned long flags; - - switch (dac33->fifo_mode) { - case DAC33_FIFO_MODE1: - /* Take the timestamp */ -- spin_lock_irqsave(&dac33->lock, flags); -- dac33->t_stamp2 = ktime_to_us(ktime_get()); -- spin_unlock_irqrestore(&dac33->lock, flags); -+ scoped_guard(spinlock_irqsave, &dac33->lock) -+ dac33->t_stamp2 = ktime_to_us(ktime_get()); - - dac33_write16(component, DAC33_NSAMPLE_MSB, - DAC33_THRREG(dac33->nsample)); -@@ -735,7 +728,7 @@ static void dac33_work(struct work_struct *work) - dac33 = container_of(work, struct tlv320dac33_priv, work); - component = dac33->component; - -- mutex_lock(&dac33->mutex); -+ guard(mutex)(&dac33->mutex); - switch (dac33->state) { - case DAC33_PREFILL: - dac33->state = DAC33_PLAYBACK; -@@ -757,18 +750,15 @@ static void dac33_work(struct work_struct *work) - dac33_write(component, DAC33_FIFO_CTRL_A, reg); - break; - } -- mutex_unlock(&dac33->mutex); - } - - static irqreturn_t dac33_interrupt_handler(int irq, void *dev) - { - struct snd_soc_component *component = dev; - struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component); -- unsigned long flags; - -- spin_lock_irqsave(&dac33->lock, flags); -- dac33->t_stamp1 = ktime_to_us(ktime_get()); -- spin_unlock_irqrestore(&dac33->lock, flags); -+ scoped_guard(spinlock_irqsave, &dac33->lock) -+ dac33->t_stamp1 = ktime_to_us(ktime_get()); - - /* Do not schedule the workqueue in Mode7 */ - if (dac33->fifo_mode != DAC33_FIFO_MODE7) -@@ -902,14 +892,13 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream, - return -EINVAL; - } - -- mutex_lock(&dac33->mutex); -+ guard(mutex)(&dac33->mutex); - - if (!dac33->chip_power) { - /* - * Chip is not powered yet. - * Do the init in the dac33_set_bias_level later. - */ -- mutex_unlock(&dac33->mutex); - return 0; - } - -@@ -1053,8 +1042,6 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream, - break; - } - -- mutex_unlock(&dac33->mutex); -- - return 0; - } - -@@ -1156,21 +1143,20 @@ static snd_pcm_sframes_t dac33_dai_delay( - unsigned int time_delta, uthr; - int samples_out, samples_in, samples; - snd_pcm_sframes_t delay = 0; -- unsigned long flags; - - switch (dac33->fifo_mode) { - case DAC33_FIFO_BYPASS: - break; - case DAC33_FIFO_MODE1: -- spin_lock_irqsave(&dac33->lock, flags); -- t0 = dac33->t_stamp1; -- t1 = dac33->t_stamp2; -- spin_unlock_irqrestore(&dac33->lock, flags); -+ scoped_guard(spinlock_irqsave, &dac33->lock) { -+ t0 = dac33->t_stamp1; -+ t1 = dac33->t_stamp2; -+ } - t_now = ktime_to_us(ktime_get()); - - /* We have not started to fill the FIFO yet, delay is 0 */ - if (!t1) -- goto out; -+ return 0; - - if (t0 > t1) { - /* -@@ -1230,23 +1216,22 @@ static snd_pcm_sframes_t dac33_dai_delay( - } - break; - case DAC33_FIFO_MODE7: -- spin_lock_irqsave(&dac33->lock, flags); -- t0 = dac33->t_stamp1; -- uthr = dac33->uthr; -- spin_unlock_irqrestore(&dac33->lock, flags); -+ scoped_guard(spinlock_irqsave, &dac33->lock) { -+ t0 = dac33->t_stamp1; -+ uthr = dac33->uthr; -+ } - t_now = ktime_to_us(ktime_get()); - - /* We have not started to fill the FIFO yet, delay is 0 */ - if (!t0) -- goto out; -+ return 0; - - if (t_now <= t0) { - /* - * Either the timestamps are messed or equal. Report - * maximum delay - */ -- delay = uthr; -- goto out; -+ return uthr; - } - - time_delta = t_now - t0; -@@ -1287,7 +1272,7 @@ static snd_pcm_sframes_t dac33_dai_delay( - dac33->fifo_mode); - break; - } --out: -+ - return delay; - } - -diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c ---- a/sound/soc/codecs/tscs42xx.c -+++ b/sound/soc/codecs/tscs42xx.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -210,25 +211,21 @@ static int power_up_audio_plls(struct snd_soc_component *component) - return ret; - } - -- mutex_lock(&tscs42xx->pll_lock); -+ guard(mutex)(&tscs42xx->pll_lock); - - ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val); - if (ret < 0) { - dev_err(component->dev, "Failed to turn PLL on (%d)\n", ret); -- goto exit; -+ return ret; - } - - if (!plls_locked(component)) { - dev_err(component->dev, "Failed to lock plls\n"); - ret = -ENOMSG; -- goto exit; -+ return ret; - } - -- ret = 0; --exit: -- mutex_unlock(&tscs42xx->pll_lock); -- -- return ret; -+ return 0; - } - - static int power_down_audio_plls(struct snd_soc_component *component) -@@ -236,28 +233,24 @@ static int power_down_audio_plls(struct snd_soc_component *component) - struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component); - int ret; - -- mutex_lock(&tscs42xx->pll_lock); -+ guard(mutex)(&tscs42xx->pll_lock); - - ret = snd_soc_component_update_bits(component, R_PLLCTL1C, - RM_PLLCTL1C_PDB_PLL1, - RV_PLLCTL1C_PDB_PLL1_DISABLE); - if (ret < 0) { - dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret); -- goto exit; -+ return ret; - } - ret = snd_soc_component_update_bits(component, R_PLLCTL1C, - RM_PLLCTL1C_PDB_PLL2, - RV_PLLCTL1C_PDB_PLL2_DISABLE); - if (ret < 0) { - dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret); -- goto exit; -+ return ret; - } - -- ret = 0; --exit: -- mutex_unlock(&tscs42xx->pll_lock); -- -- return ret; -+ return 0; - } - - static int coeff_ram_get(struct snd_kcontrol *kcontrol, -@@ -269,13 +262,11 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol, - (struct coeff_ram_ctl *)kcontrol->private_value; - struct soc_bytes_ext *params = &ctl->bytes_ext; - -- mutex_lock(&tscs42xx->coeff_ram_lock); -+ guard(mutex)(&tscs42xx->coeff_ram_lock); - - memcpy(ucontrol->value.bytes.data, - &tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max); - -- mutex_unlock(&tscs42xx->coeff_ram_lock); -- - return 0; - } - -@@ -290,14 +281,14 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, - unsigned int coeff_cnt = params->max / COEFF_SIZE; - int ret; - -- mutex_lock(&tscs42xx->coeff_ram_lock); -+ guard(mutex)(&tscs42xx->coeff_ram_lock); - - tscs42xx->coeff_ram_synced = false; - - memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], - ucontrol->value.bytes.data, params->max); - -- mutex_lock(&tscs42xx->pll_lock); -+ guard(mutex)(&tscs42xx->pll_lock); - - if (plls_locked(component)) { - ret = write_coeff_ram(component, tscs42xx->coeff_ram, -@@ -305,18 +296,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, - if (ret < 0) { - dev_err(component->dev, - "Failed to flush coeff ram cache (%d)\n", ret); -- goto exit; -+ return ret; - } - tscs42xx->coeff_ram_synced = true; - } - -- ret = 0; --exit: -- mutex_unlock(&tscs42xx->pll_lock); -- -- mutex_unlock(&tscs42xx->coeff_ram_lock); -- -- return ret; -+ return 0; - } - - /* Input L Capture Route */ -@@ -385,21 +370,17 @@ static int dac_event(struct snd_soc_dapm_widget *w, - struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component); - int ret; - -- mutex_lock(&tscs42xx->coeff_ram_lock); -+ guard(mutex)(&tscs42xx->coeff_ram_lock); - - if (!tscs42xx->coeff_ram_synced) { - ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00, - COEFF_RAM_COEFF_COUNT); - if (ret < 0) -- goto exit; -+ return ret; - tscs42xx->coeff_ram_synced = true; - } - -- ret = 0; --exit: -- mutex_unlock(&tscs42xx->coeff_ram_lock); -- -- return ret; -+ return 0; - } - - static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = { -@@ -926,12 +907,10 @@ static int setup_sample_rate(struct snd_soc_component *component, - return ret; - } - -- mutex_lock(&tscs42xx->audio_params_lock); -+ guard(mutex)(&tscs42xx->audio_params_lock); - - tscs42xx->samplerate = rate; - -- mutex_unlock(&tscs42xx->audio_params_lock); -- - return 0; - } - -@@ -1253,12 +1232,10 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai, - return ret; - } - -- mutex_lock(&tscs42xx->audio_params_lock); -+ guard(mutex)(&tscs42xx->audio_params_lock); - - tscs42xx->bclk_ratio = ratio; - -- mutex_unlock(&tscs42xx->audio_params_lock); -- - return 0; - } - -diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c ---- a/sound/soc/codecs/tscs454.c -+++ b/sound/soc/codecs/tscs454.c -@@ -4,6 +4,7 @@ - // Author: Steven Eckhoff - - #include -+#include - #include - #include - #include -@@ -329,12 +330,10 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol, - return -EINVAL; - } - -- mutex_lock(coeff_ram_lock); -- -- memcpy(ucontrol->value.bytes.data, -- &coeff_ram[ctl->addr * COEFF_SIZE], params->max); -- -- mutex_unlock(coeff_ram_lock); -+ scoped_guard(mutex, coeff_ram_lock) { -+ memcpy(ucontrol->value.bytes.data, -+ &coeff_ram[ctl->addr * COEFF_SIZE], params->max); -+ } - - return 0; - } -@@ -428,15 +427,15 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, - return -EINVAL; - } - -- mutex_lock(coeff_ram_lock); -+ guard(mutex)(coeff_ram_lock); - - *coeff_ram_synced = false; - - memcpy(&coeff_ram[ctl->addr * COEFF_SIZE], - ucontrol->value.bytes.data, params->max); - -- mutex_lock(&tscs454->pll1.lock); -- mutex_lock(&tscs454->pll2.lock); -+ guard(mutex)(&tscs454->pll1.lock); -+ guard(mutex)(&tscs454->pll2.lock); - - val = snd_soc_component_read(component, R_PLLSTAT); - if (val) { /* PLLs locked */ -@@ -446,18 +445,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol, - if (ret < 0) { - dev_err(component->dev, - "Failed to flush coeff ram cache (%d)\n", ret); -- goto exit; -+ return ret; - } - *coeff_ram_synced = true; - } - -- ret = 0; --exit: -- mutex_unlock(&tscs454->pll2.lock); -- mutex_unlock(&tscs454->pll1.lock); -- mutex_unlock(coeff_ram_lock); -- -- return ret; -+ return 0; - } - - static inline int coeff_ram_sync(struct snd_soc_component *component, -@@ -465,41 +458,35 @@ static inline int coeff_ram_sync(struct snd_soc_component *component, - { - int ret; - -- mutex_lock(&tscs454->dac_ram.lock); -- if (!tscs454->dac_ram.synced) { -- ret = write_coeff_ram(component, tscs454->dac_ram.cache, -- R_DACCRS, R_DACCRADD, R_DACCRWDL, -- 0x00, COEFF_RAM_COEFF_COUNT); -- if (ret < 0) { -- mutex_unlock(&tscs454->dac_ram.lock); -- return ret; -+ scoped_guard(mutex, &tscs454->dac_ram.lock) { -+ if (!tscs454->dac_ram.synced) { -+ ret = write_coeff_ram(component, tscs454->dac_ram.cache, -+ R_DACCRS, R_DACCRADD, R_DACCRWDL, -+ 0x00, COEFF_RAM_COEFF_COUNT); -+ if (ret < 0) -+ return ret; - } - } -- mutex_unlock(&tscs454->dac_ram.lock); - -- mutex_lock(&tscs454->spk_ram.lock); -- if (!tscs454->spk_ram.synced) { -- ret = write_coeff_ram(component, tscs454->spk_ram.cache, -- R_SPKCRS, R_SPKCRADD, R_SPKCRWDL, -- 0x00, COEFF_RAM_COEFF_COUNT); -- if (ret < 0) { -- mutex_unlock(&tscs454->spk_ram.lock); -- return ret; -+ scoped_guard(mutex, &tscs454->spk_ram.lock) { -+ if (!tscs454->spk_ram.synced) { -+ ret = write_coeff_ram(component, tscs454->spk_ram.cache, -+ R_SPKCRS, R_SPKCRADD, R_SPKCRWDL, -+ 0x00, COEFF_RAM_COEFF_COUNT); -+ if (ret < 0) -+ return ret; - } - } -- mutex_unlock(&tscs454->spk_ram.lock); - -- mutex_lock(&tscs454->sub_ram.lock); -- if (!tscs454->sub_ram.synced) { -- ret = write_coeff_ram(component, tscs454->sub_ram.cache, -- R_SUBCRS, R_SUBCRADD, R_SUBCRWDL, -- 0x00, COEFF_RAM_COEFF_COUNT); -- if (ret < 0) { -- mutex_unlock(&tscs454->sub_ram.lock); -- return ret; -+ scoped_guard(mutex, &tscs454->sub_ram.lock) { -+ if (!tscs454->sub_ram.synced) { -+ ret = write_coeff_ram(component, tscs454->sub_ram.cache, -+ R_SUBCRS, R_SUBCRADD, R_SUBCRWDL, -+ 0x00, COEFF_RAM_COEFF_COUNT); -+ if (ret < 0) -+ return ret; - } - } -- mutex_unlock(&tscs454->sub_ram.lock); - - return 0; - } -@@ -658,16 +645,14 @@ static int set_sysclk(struct snd_soc_component *component) - - static inline void reserve_pll(struct pll *pll) - { -- mutex_lock(&pll->lock); -+ guard(mutex)(&pll->lock); - pll->users++; -- mutex_unlock(&pll->lock); - } - - static inline void free_pll(struct pll *pll) - { -- mutex_lock(&pll->lock); -+ guard(mutex)(&pll->lock); - pll->users--; -- mutex_unlock(&pll->lock); - } - - static int pll_connected(struct snd_soc_dapm_widget *source, -@@ -679,15 +664,13 @@ static int pll_connected(struct snd_soc_dapm_widget *source, - int users; - - if (strstr(source->name, "PLL 1")) { -- mutex_lock(&tscs454->pll1.lock); -- users = tscs454->pll1.users; -- mutex_unlock(&tscs454->pll1.lock); -+ scoped_guard(mutex, &tscs454->pll1.lock) -+ users = tscs454->pll1.users; - dev_dbg(component->dev, "%s(): PLL 1 users = %d\n", __func__, - users); - } else { -- mutex_lock(&tscs454->pll2.lock); -- users = tscs454->pll2.users; -- mutex_unlock(&tscs454->pll2.lock); -+ scoped_guard(mutex, &tscs454->pll2.lock) -+ users = tscs454->pll2.users; - dev_dbg(component->dev, "%s(): PLL 2 users = %d\n", __func__, - users); - } -@@ -806,7 +789,7 @@ static inline int aif_free(struct snd_soc_component *component, - { - struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&tscs454->aifs_status_lock); -+ guard(mutex)(&tscs454->aifs_status_lock); - - dev_dbg(component->dev, "%s(): aif %d\n", __func__, aif->id); - -@@ -829,8 +812,6 @@ static inline int aif_free(struct snd_soc_component *component, - free_pll(tscs454->internal_rate.pll); - } - -- mutex_unlock(&tscs454->aifs_status_lock); -- - return 0; - } - -@@ -3174,7 +3155,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, - unsigned int val; - int ret; - -- mutex_lock(&tscs454->aifs_status_lock); -+ guard(mutex)(&tscs454->aifs_status_lock); - - dev_dbg(component->dev, "%s(): aif %d fs = %u\n", __func__, - aif->id, fs); -@@ -3207,14 +3188,14 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, - ret = set_aif_fs(component, aif->id, fs); - if (ret < 0) { - dev_err(component->dev, "Failed to set aif fs (%d)\n", ret); -- goto exit; -+ return ret; - } - - ret = set_aif_sample_format(component, params_format(params), aif->id); - if (ret < 0) { - dev_err(component->dev, - "Failed to set aif sample format (%d)\n", ret); -- goto exit; -+ return ret; - } - - set_aif_status_active(&tscs454->aifs_status, aif->id, -@@ -3223,11 +3204,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream, - dev_dbg(component->dev, "Set aif %d active. Streams status is 0x%x\n", - aif->id, tscs454->aifs_status.streams); - -- ret = 0; --exit: -- mutex_unlock(&tscs454->aifs_status_lock); -- -- return ret; -+ return 0; - } - - static int tscs454_hw_free(struct snd_pcm_substream *substream, -diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c ---- a/sound/soc/codecs/twl6040.c -+++ b/sound/soc/codecs/twl6040.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -273,7 +274,7 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component, - struct twl6040_data *priv = snd_soc_component_get_drvdata(component); - int status; - -- mutex_lock(&priv->mutex); -+ guard(mutex)(&priv->mutex); - - /* Sync status */ - status = twl6040_read(component, TWL6040_REG_STATUS); -@@ -281,8 +282,6 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component, - snd_soc_jack_report(jack, report, report); - else - snd_soc_jack_report(jack, 0, report); -- -- mutex_unlock(&priv->mutex); - } - - void twl6040_hs_jack_detect(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c ---- a/sound/soc/codecs/uda1342.c -+++ b/sound/soc/codecs/uda1342.c -@@ -308,9 +308,16 @@ static int uda1342_suspend(struct device *dev) - static int uda1342_resume(struct device *dev) - { - struct uda1342_priv *uda1342 = dev_get_drvdata(dev); -+ int ret; - -+ regcache_cache_only(uda1342->regmap, false); - regcache_mark_dirty(uda1342->regmap); -- regcache_sync(uda1342->regmap); -+ ret = regcache_sync(uda1342->regmap); -+ if (ret) { -+ regcache_cache_only(uda1342->regmap, true); -+ regcache_mark_dirty(uda1342->regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c ---- a/sound/soc/codecs/wcd9335.c -+++ b/sound/soc/codecs/wcd9335.c -@@ -5010,9 +5010,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) - */ - usleep_range(600, 650); - -- gpiod_set_value(wcd->reset_gpio, 1); -+ gpiod_set_value_cansleep(wcd->reset_gpio, 1); - msleep(20); -- gpiod_set_value(wcd->reset_gpio, 0); -+ gpiod_set_value_cansleep(wcd->reset_gpio, 0); - msleep(20); - - return 0; -diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c ---- a/sound/soc/codecs/wcd934x.c -+++ b/sound/soc/codecs/wcd934x.c -@@ -1265,13 +1265,10 @@ static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src) - - static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd) - { -- mutex_lock(&wcd->sysclk_mutex); -- -- if (++wcd->sysclk_users != 1) { -- mutex_unlock(&wcd->sysclk_mutex); -- return 0; -+ scoped_guard(mutex, &wcd->sysclk_mutex) { -+ if (++wcd->sysclk_users != 1) -+ return 0; - } -- mutex_unlock(&wcd->sysclk_mutex); - - regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS, - WCD934X_ANA_BIAS_EN_MASK, -@@ -1328,12 +1325,10 @@ static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd) - - static int wcd934x_disable_ana_bias_and_syclk(struct wcd934x_codec *wcd) - { -- mutex_lock(&wcd->sysclk_mutex); -- if (--wcd->sysclk_users != 0) { -- mutex_unlock(&wcd->sysclk_mutex); -- return 0; -+ scoped_guard(mutex, &wcd->sysclk_mutex) { -+ if (--wcd->sysclk_users != 0) -+ return 0; - } -- mutex_unlock(&wcd->sysclk_mutex); - - regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG, - WCD934X_EXT_CLK_BUF_EN_MASK | -@@ -2384,7 +2379,7 @@ static int wcd934x_micbias_control(struct snd_soc_component *component, - __func__, micb_num); - return -EINVAL; - } -- mutex_lock(&wcd934x->micb_lock); -+ guard(mutex)(&wcd934x->micb_lock); - - switch (req) { - case MICB_PULLUP_ENABLE: -@@ -2446,8 +2441,6 @@ static int wcd934x_micbias_control(struct snd_soc_component *component, - break; - } - -- mutex_unlock(&wcd934x->micb_lock); -- - return 0; - } - -@@ -2488,7 +2481,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - int req_volt, int micb_num) - { - struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component); -- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; -+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; - - switch (micb_num) { - case MIC_BIAS_1: -@@ -2506,7 +2499,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - default: - return -EINVAL; - } -- mutex_lock(&wcd934x->micb_lock); -+ guard(mutex)(&wcd934x->micb_lock); - /* - * If requested micbias voltage is same as current micbias - * voltage, then just return. Otherwise, adjust voltage as -@@ -2521,15 +2514,11 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - WCD934X_MICB_VAL_MASK); - - req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); -- if (req_vout_ctl < 0) { -- ret = -EINVAL; -- goto exit; -- } -+ if (req_vout_ctl < 0) -+ return -EINVAL; - -- if (cur_vout_ctl == req_vout_ctl) { -- ret = 0; -- goto exit; -- } -+ if (cur_vout_ctl == req_vout_ctl) -+ return 0; - - if (micb_en == WCD934X_MICB_ENABLE) - snd_soc_component_write_field(component, micb_reg, -@@ -2550,9 +2539,8 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - */ - usleep_range(2000, 2100); - } --exit: -- mutex_unlock(&wcd934x->micb_lock); -- return ret; -+ -+ return 0; - } - - static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, -@@ -5899,10 +5887,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev) - } - - static const struct platform_device_id wcd934x_driver_id[] = { -- { -- .name = "wcd934x-codec", -- }, -- {}, -+ { .name = "wcd934x-codec" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, wcd934x_driver_id); - -diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c ---- a/sound/soc/codecs/wcd937x-sdw.c -+++ b/sound/soc/codecs/wcd937x-sdw.c -@@ -1084,10 +1084,16 @@ static int wcd937x_sdw_runtime_suspend(struct device *dev) - static int wcd937x_sdw_runtime_resume(struct device *dev) - { - struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev); -+ int ret; - - if (wcd->regmap) { - regcache_cache_only(wcd->regmap, false); -- regcache_sync(wcd->regmap); -+ ret = regcache_sync(wcd->regmap); -+ if (ret) { -+ regcache_cache_only(wcd->regmap, true); -+ regcache_mark_dirty(wcd->regmap); -+ return ret; -+ } - } - - return 0; -diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c ---- a/sound/soc/codecs/wcd937x.c -+++ b/sound/soc/codecs/wcd937x.c -@@ -2,6 +2,7 @@ - // Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. - - #include -+#include - #include - #include - #include -@@ -1056,7 +1057,7 @@ static int wcd937x_micbias_control(struct snd_soc_component *component, - return -EINVAL; - } - -- mutex_lock(&wcd937x->micb_lock); -+ guard(mutex)(&wcd937x->micb_lock); - switch (req) { - case MICB_PULLUP_ENABLE: - wcd937x->pullup_ref[micb_index]++; -@@ -1136,7 +1137,6 @@ static int wcd937x_micbias_control(struct snd_soc_component *component, - } - break; - } -- mutex_unlock(&wcd937x->micb_lock); - - return 0; - } -@@ -1460,7 +1460,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - int req_volt, int micb_num) - { - struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component); -- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; -+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; - - switch (micb_num) { - case MIC_BIAS_1: -@@ -1475,7 +1475,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - default: - return -EINVAL; - } -- mutex_lock(&wcd937x->micb_lock); -+ guard(mutex)(&wcd937x->micb_lock); - /* - * If requested micbias voltage is same as current micbias - * voltage, then just return. Otherwise, adjust voltage as -@@ -1490,15 +1490,11 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - WCD937X_MICB_VOUT_MASK); - - req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); -- if (req_vout_ctl < 0) { -- ret = -EINVAL; -- goto exit; -- } -+ if (req_vout_ctl < 0) -+ return -EINVAL; - -- if (cur_vout_ctl == req_vout_ctl) { -- ret = 0; -- goto exit; -- } -+ if (cur_vout_ctl == req_vout_ctl) -+ return 0; - - if (micb_en == WCD937X_MICB_ENABLE) - snd_soc_component_write_field(component, micb_reg, -@@ -1519,9 +1515,8 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - */ - usleep_range(2000, 2100); - } --exit: -- mutex_unlock(&wcd937x->micb_lock); -- return ret; -+ -+ return 0; - } - - static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c ---- a/sound/soc/codecs/wcd938x-sdw.c -+++ b/sound/soc/codecs/wcd938x-sdw.c -@@ -1245,10 +1245,16 @@ static int wcd938x_sdw_runtime_suspend(struct device *dev) - static int wcd938x_sdw_runtime_resume(struct device *dev) - { - struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev); -+ int ret; - - if (wcd->regmap) { - regcache_cache_only(wcd->regmap, false); -- regcache_sync(wcd->regmap); -+ ret = regcache_sync(wcd->regmap); -+ if (ret) { -+ regcache_cache_only(wcd->regmap, true); -+ regcache_mark_dirty(wcd->regmap); -+ return ret; -+ } - } - - pm_runtime_mark_last_busy(dev); -diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c ---- a/sound/soc/codecs/wcd938x.c -+++ b/sound/soc/codecs/wcd938x.c -@@ -1,6 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0-only - // Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. - -+#include - #include - #include - #include -@@ -1976,7 +1977,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - int req_volt, int micb_num) - { - struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); -- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0; -+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en; - - switch (micb_num) { - case MIC_BIAS_1: -@@ -1994,7 +1995,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - default: - return -EINVAL; - } -- mutex_lock(&wcd938x->micb_lock); -+ guard(mutex)(&wcd938x->micb_lock); - /* - * If requested micbias voltage is same as current micbias - * voltage, then just return. Otherwise, adjust voltage as -@@ -2009,15 +2010,11 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - WCD938X_MICB_VOUT_MASK); - - req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); -- if (req_vout_ctl < 0) { -- ret = -EINVAL; -- goto exit; -- } -+ if (req_vout_ctl < 0) -+ return -EINVAL; - -- if (cur_vout_ctl == req_vout_ctl) { -- ret = 0; -- goto exit; -- } -+ if (cur_vout_ctl == req_vout_ctl) -+ return 0; - - if (micb_en == WCD938X_MICB_ENABLE) - snd_soc_component_write_field(component, micb_reg, -@@ -2038,9 +2035,8 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - */ - usleep_range(2000, 2100); - } --exit: -- mutex_unlock(&wcd938x->micb_lock); -- return ret; -+ -+ return 0; - } - - static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c ---- a/sound/soc/codecs/wcd939x-sdw.c -+++ b/sound/soc/codecs/wcd939x-sdw.c -@@ -1431,10 +1431,16 @@ static int wcd939x_sdw_runtime_suspend(struct device *dev) - static int wcd939x_sdw_runtime_resume(struct device *dev) - { - struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); -+ int ret; - - if (wcd->regmap) { - regcache_cache_only(wcd->regmap, false); -- regcache_sync(wcd->regmap); -+ ret = regcache_sync(wcd->regmap); -+ if (ret) { -+ regcache_cache_only(wcd->regmap, true); -+ regcache_mark_dirty(wcd->regmap); -+ return ret; -+ } - } - - return 0; -diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c ---- a/sound/soc/codecs/wcd939x.c -+++ b/sound/soc/codecs/wcd939x.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1923,7 +1924,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); - unsigned int micb_reg, cur_vout_ctl, micb_en; - int req_vout_ctl; -- int ret = 0; - - switch (micb_num) { - case MIC_BIAS_1: -@@ -1941,7 +1941,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - default: - return -EINVAL; - } -- mutex_lock(&wcd939x->micb_lock); -+ guard(mutex)(&wcd939x->micb_lock); - - /* - * If requested micbias voltage is same as current micbias -@@ -1957,15 +1957,11 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - WCD939X_MICB_VOUT_CTL); - - req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt); -- if (req_vout_ctl < 0) { -- ret = req_vout_ctl; -- goto exit; -- } -+ if (req_vout_ctl < 0) -+ return req_vout_ctl; - -- if (cur_vout_ctl == req_vout_ctl) { -- ret = 0; -- goto exit; -- } -+ if (cur_vout_ctl == req_vout_ctl) -+ return 0; - - dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n", - __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl), -@@ -1990,9 +1986,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, - usleep_range(2000, 2100); - } - --exit: -- mutex_unlock(&wcd939x->micb_lock); -- return ret; -+ return 0; - } - - static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, -diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c ---- a/sound/soc/codecs/wm0010.c -+++ b/sound/soc/codecs/wm0010.c -@@ -9,6 +9,7 @@ - * Scott Ling - */ - -+#include - #include - #include - #include -@@ -148,13 +149,11 @@ static const char *wm0010_state_to_str(enum wm0010_state state) - static void wm0010_halt(struct snd_soc_component *component) - { - struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component); -- unsigned long flags; - enum wm0010_state state; - - /* Fetch the wm0010 state */ -- spin_lock_irqsave(&wm0010->irq_lock, flags); -- state = wm0010->state; -- spin_unlock_irqrestore(&wm0010->irq_lock, flags); -+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock) -+ state = wm0010->state; - - switch (state) { - case WM0010_POWER_OFF: -@@ -173,9 +172,8 @@ static void wm0010_halt(struct snd_soc_component *component) - break; - } - -- spin_lock_irqsave(&wm0010->irq_lock, flags); -- wm0010->state = WM0010_POWER_OFF; -- spin_unlock_irqrestore(&wm0010->irq_lock, flags); -+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock) -+ wm0010->state = WM0010_POWER_OFF; - } - - struct wm0010_boot_xfer { -@@ -190,11 +188,9 @@ struct wm0010_boot_xfer { - static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010) - { - enum wm0010_state state; -- unsigned long flags; - -- spin_lock_irqsave(&wm0010->irq_lock, flags); -- state = wm0010->state; -- spin_unlock_irqrestore(&wm0010->irq_lock, flags); -+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock) -+ state = wm0010->state; - - dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n", - wm0010_state_to_str(state), wm0010_state_to_str(state + 1)); -@@ -337,7 +333,6 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - struct wm0010_boot_xfer *xfer; - int ret; - DECLARE_COMPLETION_ONSTACK(done); -- const struct firmware *fw; - const struct dfw_binrec *rec; - const struct dfw_inforec *inforec; - u64 *img; -@@ -346,6 +341,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - - INIT_LIST_HEAD(&xfer_list); - -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, name, component->dev); - if (ret != 0) { - dev_err(component->dev, "Failed to request application(%s): %d\n", -@@ -364,16 +360,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - /* First record should be INFO */ - if (rec->command != DFW_CMD_INFO) { - dev_err(component->dev, "First record not INFO\r\n"); -- ret = -EINVAL; -- goto abort; -+ return -EINVAL; - } - - if (inforec->info_version != INFO_VERSION) { - dev_err(component->dev, - "Unsupported version (%02d) of INFO record\r\n", - inforec->info_version); -- ret = -EINVAL; -- goto abort; -+ return -EINVAL; - } - - dev_dbg(component->dev, "Version v%02d INFO record found\r\n", -@@ -382,8 +376,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - /* Check it's a DSP file */ - if (dsp != DEVICE_ID_WM0010) { - dev_err(component->dev, "Not a WM0010 firmware file.\r\n"); -- ret = -EINVAL; -- goto abort; -+ return -EINVAL; - } - - /* Skip the info record as we don't need to send it */ -@@ -408,14 +401,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - out = kzalloc(len, GFP_KERNEL | GFP_DMA); - if (!out) { - ret = -ENOMEM; -- goto abort1; -+ goto abort; - } - xfer->t.rx_buf = out; - - img = kzalloc(len, GFP_KERNEL | GFP_DMA); - if (!img) { - ret = -ENOMEM; -- goto abort1; -+ goto abort; - } - xfer->t.tx_buf = img; - -@@ -453,13 +446,13 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - ret = spi_async(spi, &xfer->m); - if (ret != 0) { - dev_err(component->dev, "Write failed: %d\n", ret); -- goto abort1; -+ goto abort; - } - - if (wm0010->boot_failed) { - dev_dbg(component->dev, "Boot fail!\n"); - ret = -EINVAL; -- goto abort1; -+ goto abort; - } - } - -@@ -467,7 +460,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - - ret = 0; - --abort1: -+abort: - while (!list_empty(&xfer_list)) { - xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer, - list); -@@ -477,8 +470,6 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp - kfree(xfer); - } - --abort: -- release_firmware(fw); - return ret; - } - -@@ -486,14 +477,12 @@ static int wm0010_stage2_load(struct snd_soc_component *component) - { - struct spi_device *spi = to_spi_device(component->dev); - struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component); -- const struct firmware *fw; - struct spi_message m; - struct spi_transfer t; -- u32 *img; -- u8 *out; - int i; - int ret = 0; - -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, "wm0010_stage2.bin", component->dev); - if (ret != 0) { - dev_err(component->dev, "Failed to request stage2 loader: %d\n", -@@ -504,17 +493,15 @@ static int wm0010_stage2_load(struct snd_soc_component *component) - dev_dbg(component->dev, "Downloading %zu byte stage 2 loader\n", fw->size); - - /* Copy to local buffer first as vmalloc causes problems for dma */ -- img = kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA); -- if (!img) { -- ret = -ENOMEM; -- goto abort2; -- } -+ u32 *img __free(kfree) = -+ kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA); -+ if (!img) -+ return -ENOMEM; - -- out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA); -- if (!out) { -- ret = -ENOMEM; -- goto abort1; -- } -+ u8 *out __free(kfree) = -+ kzalloc(fw->size, GFP_KERNEL | GFP_DMA); -+ if (!out) -+ return -ENOMEM; - - spi_message_init(&m); - memset(&t, 0, sizeof(t)); -@@ -531,7 +518,7 @@ static int wm0010_stage2_load(struct snd_soc_component *component) - ret = spi_sync(spi, &m); - if (ret != 0) { - dev_err(component->dev, "Initial download failed: %d\n", ret); -- goto abort; -+ return ret; - } - - /* Look for errors from the boot ROM */ -@@ -540,18 +527,11 @@ static int wm0010_stage2_load(struct snd_soc_component *component) - dev_err(component->dev, "Boot ROM error: %x in %d\n", - out[i], i); - wm0010_mark_boot_failure(wm0010); -- ret = -EBUSY; -- goto abort; -+ return -EBUSY; - } - } --abort: -- kfree(out); --abort1: -- kfree(img); --abort2: -- release_firmware(fw); - -- return ret; -+ return 0; - } - - static int wm0010_boot(struct snd_soc_component *component) -@@ -734,9 +714,8 @@ static int wm0010_set_bias_level(struct snd_soc_component *component, - break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) { -- mutex_lock(&wm0010->lock); -- wm0010_halt(component); -- mutex_unlock(&wm0010->lock); -+ scoped_guard(mutex, &wm0010->lock) -+ wm0010_halt(component); - } - break; - case SND_SOC_BIAS_OFF: -@@ -832,9 +811,8 @@ static irqreturn_t wm0010_irq(int irq, void *data) - case WM0010_OUT_OF_RESET: - case WM0010_BOOTROM: - case WM0010_STAGE2: -- spin_lock(&wm0010->irq_lock); -- complete(&wm0010->boot_completion); -- spin_unlock(&wm0010->irq_lock); -+ scoped_guard(spinlock, &wm0010->irq_lock) -+ complete(&wm0010->boot_completion); - return IRQ_HANDLED; - default: - return IRQ_NONE; -diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c ---- a/sound/soc/codecs/wm2000.c -+++ b/sound/soc/codecs/wm2000.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -612,20 +613,15 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); - unsigned int anc_active = ucontrol->value.integer.value[0]; -- int ret; - - if (anc_active > 1) - return -EINVAL; - -- mutex_lock(&wm2000->lock); -+ guard(mutex)(&wm2000->lock); - - wm2000->anc_active = anc_active; - -- ret = wm2000_anc_set_mode(wm2000); -- -- mutex_unlock(&wm2000->lock); -- -- return ret; -+ return wm2000_anc_set_mode(wm2000); - } - - static int wm2000_speaker_get(struct snd_kcontrol *kcontrol, -@@ -645,20 +641,15 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); - unsigned int val = ucontrol->value.integer.value[0]; -- int ret; - - if (val > 1) - return -EINVAL; - -- mutex_lock(&wm2000->lock); -+ guard(mutex)(&wm2000->lock); - - wm2000->spk_ena = val; - -- ret = wm2000_anc_set_mode(wm2000); -- -- mutex_unlock(&wm2000->lock); -- -- return ret; -+ return wm2000_anc_set_mode(wm2000); - } - - static const struct snd_kcontrol_new wm2000_controls[] = { -@@ -676,9 +667,8 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, - { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev); -- int ret; - -- mutex_lock(&wm2000->lock); -+ guard(mutex)(&wm2000->lock); - - if (SND_SOC_DAPM_EVENT_ON(event)) - wm2000->anc_eng_ena = 1; -@@ -686,11 +676,7 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w, - if (SND_SOC_DAPM_EVENT_OFF(event)) - wm2000->anc_eng_ena = 0; - -- ret = wm2000_anc_set_mode(wm2000); -- -- mutex_unlock(&wm2000->lock); -- -- return ret; -+ return wm2000_anc_set_mode(wm2000); - } - - static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = { -@@ -810,7 +796,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c) - struct wm2000_priv *wm2000; - struct wm2000_platform_data *pdata; - const char *filename; -- const struct firmware *fw = NULL; -+ const struct firmware *fw __free(firmware) = NULL; - int ret, i; - unsigned int reg; - u16 id; -@@ -828,7 +814,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c) - ret = PTR_ERR(wm2000->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); -- goto out; -+ return ret; - } - - for (i = 0; i < WM2000_NUM_SUPPLIES; i++) -@@ -922,9 +908,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c) - - err_supplies: - regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies); -- --out: -- release_firmware(fw); - return ret; - } - -diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c ---- a/sound/soc/codecs/wm2200.c -+++ b/sound/soc/codecs/wm2200.c -@@ -2461,7 +2461,15 @@ static int wm2200_runtime_resume(struct device *dev) - } - - regcache_cache_only(wm2200->regmap, false); -- regcache_sync(wm2200->regmap); -+ ret = regcache_sync(wm2200->regmap); -+ if (ret) { -+ regcache_cache_only(wm2200->regmap, true); -+ regcache_mark_dirty(wm2200->regmap); -+ gpiod_set_value_cansleep(wm2200->ldo_ena, 0); -+ regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), -+ wm2200->core_supplies); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c ---- a/sound/soc/codecs/wm5100.c -+++ b/sound/soc/codecs/wm5100.c -@@ -2659,7 +2659,15 @@ static int wm5100_runtime_resume(struct device *dev) - } - - regcache_cache_only(wm5100->regmap, false); -- regcache_sync(wm5100->regmap); -+ ret = regcache_sync(wm5100->regmap); -+ if (ret) { -+ regcache_cache_only(wm5100->regmap, true); -+ regcache_mark_dirty(wm5100->regmap); -+ gpiod_set_value_cansleep(wm5100->ldo_ena, 0); -+ regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), -+ wm5100->core_supplies); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c ---- a/sound/soc/codecs/wm5102.c -+++ b/sound/soc/codecs/wm5102.c -@@ -7,6 +7,7 @@ - * Author: Mark Brown - */ - -+#include - #include - #include - #include -@@ -667,10 +668,9 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct arizona *arizona = dev_get_drvdata(component->dev->parent); - -- mutex_lock(&arizona->dac_comp_lock); -+ guard(mutex)(&arizona->dac_comp_lock); - put_unaligned_be16(arizona->dac_comp_coeff, - ucontrol->value.bytes.data); -- mutex_unlock(&arizona->dac_comp_lock); - - return 0; - } -@@ -681,16 +681,14 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct arizona *arizona = dev_get_drvdata(component->dev->parent); - uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data); -- int ret = 0; - -- mutex_lock(&arizona->dac_comp_lock); -+ guard(mutex)(&arizona->dac_comp_lock); - if (arizona->dac_comp_coeff != dac_comp_coeff) { - arizona->dac_comp_coeff = dac_comp_coeff; -- ret = 1; -+ return 1; - } -- mutex_unlock(&arizona->dac_comp_lock); - -- return ret; -+ return 0; - } - - static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, -@@ -699,9 +697,8 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct arizona *arizona = dev_get_drvdata(component->dev->parent); - -- mutex_lock(&arizona->dac_comp_lock); -+ guard(mutex)(&arizona->dac_comp_lock); - ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; -- mutex_unlock(&arizona->dac_comp_lock); - - return 0; - } -@@ -712,19 +709,17 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct arizona *arizona = dev_get_drvdata(component->dev->parent); - struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; -- int ret = 0; - - if (ucontrol->value.integer.value[0] > mc->max) - return -EINVAL; - -- mutex_lock(&arizona->dac_comp_lock); -+ guard(mutex)(&arizona->dac_comp_lock); - if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) { - arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; -- ret = 1; -+ return 1; - } -- mutex_unlock(&arizona->dac_comp_lock); - -- return ret; -+ return 0; - } - - static const char * const wm5102_osr_text[] = { -diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c ---- a/sound/soc/codecs/wm8731.c -+++ b/sound/soc/codecs/wm8731.c -@@ -10,6 +10,7 @@ - * Based on wm8753.c by Liam Girdwood - */ - -+#include - #include - #include - #include -@@ -110,22 +111,20 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component); - unsigned int deemph = ucontrol->value.integer.value[0]; -- int ret = 0; - - if (deemph > 1) - return -EINVAL; - -- mutex_lock(&wm8731->lock); -+ guard(mutex)(&wm8731->lock); - if (wm8731->deemph != deemph) { - wm8731->deemph = deemph; - - wm8731_set_deemph(component); - -- ret = 1; -+ return 1; - } -- mutex_unlock(&wm8731->lock); - -- return ret; -+ return 0; - } - - static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0); -diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c ---- a/sound/soc/codecs/wm8903.c -+++ b/sound/soc/codecs/wm8903.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -458,22 +459,20 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component); - unsigned int deemph = ucontrol->value.integer.value[0]; -- int ret = 0; - - if (deemph > 1) - return -EINVAL; - -- mutex_lock(&wm8903->lock); -+ guard(mutex)(&wm8903->lock); - if (wm8903->deemph != deemph) { - wm8903->deemph = deemph; - - wm8903_set_deemph(component); - -- ret = 1; -+ return 1; - } -- mutex_unlock(&wm8903->lock); - -- return ret; -+ return 0; - } - - /* ALSA can only do steps of .01dB */ -diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c ---- a/sound/soc/codecs/wm8940.c -+++ b/sound/soc/codecs/wm8940.c -@@ -333,7 +333,7 @@ static const struct snd_soc_dapm_route wm8940_dapm_routes[] = { - {"ADC", NULL, "Boost Mixer"}, - }; - --#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0); -+#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0) - - static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c ---- a/sound/soc/codecs/wm8958-dsp2.c -+++ b/sound/soc/codecs/wm8958-dsp2.c -@@ -7,6 +7,7 @@ - * Author: Mark Brown - */ - -+#include - #include - #include - #include -@@ -864,9 +865,8 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context) - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - - if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) { -- mutex_lock(&wm8994->fw_lock); -+ guard(mutex)(&wm8994->fw_lock); - wm8994->enh_eq = fw; -- mutex_unlock(&wm8994->fw_lock); - } - } - -@@ -876,9 +876,8 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - - if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) { -- mutex_lock(&wm8994->fw_lock); -+ guard(mutex)(&wm8994->fw_lock); - wm8994->mbc_vss = fw; -- mutex_unlock(&wm8994->fw_lock); - } - } - -@@ -888,9 +887,8 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - - if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) { -- mutex_lock(&wm8994->fw_lock); -+ guard(mutex)(&wm8994->fw_lock); - wm8994->mbc = fw; -- mutex_unlock(&wm8994->fw_lock); - } - } - -diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c ---- a/sound/soc/codecs/wm8962.c -+++ b/sound/soc/codecs/wm8962.c -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1564,11 +1565,10 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); - int old = wm8962->dsp2_ena; -- int ret = 0; - int dsp2_running = snd_soc_component_read(component, WM8962_DSP2_POWER_MANAGEMENT) & - WM8962_DSP2_ENA; - -- mutex_lock(&wm8962->dsp2_ena_lock); -+ guard(mutex)(&wm8962->dsp2_ena_lock); - - if (ucontrol->value.integer.value[0]) - wm8962->dsp2_ena |= 1 << shift; -@@ -1576,9 +1576,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, - wm8962->dsp2_ena &= ~(1 << shift); - - if (wm8962->dsp2_ena == old) -- goto out; -- -- ret = 1; -+ return 0; - - if (dsp2_running) { - if (wm8962->dsp2_ena) -@@ -1587,10 +1585,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, - wm8962_dsp2_stop(component); - } - --out: -- mutex_unlock(&wm8962->dsp2_ena_lock); -- -- return ret; -+ return 1; - } - - /* The VU bits for the headphones are in a different register to the mute -@@ -3937,7 +3932,9 @@ static int wm8962_runtime_resume(struct device *dev) - WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, - 0); - -- regcache_sync(wm8962->regmap); -+ ret = regcache_sync(wm8962->regmap); -+ if (ret) -+ goto cache_sync_err; - - regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, - WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA, -@@ -3955,6 +3952,11 @@ static int wm8962_runtime_resume(struct device *dev) - - return 0; - -+cache_sync_err: -+ regcache_cache_only(wm8962->regmap, true); -+ regcache_mark_dirty(wm8962->regmap); -+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), -+ wm8962->supplies); - disable_clock: - clk_disable_unprepare(wm8962->pdata.mclk); - return ret; -diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c ---- a/sound/soc/codecs/wm8994.c -+++ b/sound/soc/codecs/wm8994.c -@@ -7,6 +7,7 @@ - * Author: Mark Brown - */ - -+#include - #include - #include - #include -@@ -766,7 +767,7 @@ static void active_reference(struct snd_soc_component *component) - { - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - -- mutex_lock(&wm8994->accdet_lock); -+ guard(mutex)(&wm8994->accdet_lock); - - wm8994->active_refcount++; - -@@ -775,8 +776,6 @@ static void active_reference(struct snd_soc_component *component) - - /* If we're using jack detection go into audio mode */ - wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO); -- -- mutex_unlock(&wm8994->accdet_lock); - } - - static void active_dereference(struct snd_soc_component *component) -@@ -784,7 +783,7 @@ static void active_dereference(struct snd_soc_component *component) - struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); - u16 mode; - -- mutex_lock(&wm8994->accdet_lock); -+ guard(mutex)(&wm8994->accdet_lock); - - wm8994->active_refcount--; - -@@ -800,8 +799,6 @@ static void active_dereference(struct snd_soc_component *component) - - wm1811_jackdet_set_mode(component, mode); - } -- -- mutex_unlock(&wm8994->accdet_lock); - } - - static int clk_sys_event(struct snd_soc_dapm_widget *w, -@@ -3704,7 +3701,7 @@ static void wm8958_open_circuit_work(struct work_struct *work) - open_circuit_work.work); - struct device *dev = wm8994->wm8994->dev; - -- mutex_lock(&wm8994->accdet_lock); -+ guard(mutex)(&wm8994->accdet_lock); - - wm1811_micd_stop(wm8994->hubs.component); - -@@ -3718,8 +3715,6 @@ static void wm8958_open_circuit_work(struct work_struct *work) - snd_soc_jack_report(wm8994->micdet[0].jack, 0, - wm8994->btn_mask | - SND_JACK_HEADSET); -- -- mutex_unlock(&wm8994->accdet_lock); - } - - static void wm8958_mic_id(void *data, u16 status) -@@ -3777,7 +3772,7 @@ static void wm1811_mic_work(struct work_struct *work) - struct snd_soc_component *component = wm8994->hubs.component; - struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - -- pm_runtime_get_sync(component->dev); -+ guard(pm_runtime_active)(component->dev); - - /* If required for an external cap force MICBIAS on */ - if (control->pdata.jd_ext_cap) { -@@ -3785,7 +3780,7 @@ static void wm1811_mic_work(struct work_struct *work) - snd_soc_dapm_sync(dapm); - } - -- mutex_lock(&wm8994->accdet_lock); -+ guard(mutex)(&wm8994->accdet_lock); - - dev_dbg(component->dev, "Starting mic detection\n"); - -@@ -3803,10 +3798,6 @@ static void wm1811_mic_work(struct work_struct *work) - snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1, - WM8958_MICD_ENA, WM8958_MICD_ENA); - } -- -- mutex_unlock(&wm8994->accdet_lock); -- -- pm_runtime_put(component->dev); - } - - static irqreturn_t wm1811_jackdet_irq(int irq, void *data) -@@ -4026,15 +4017,10 @@ static void wm8958_mic_work(struct work_struct *work) - mic_complete_work.work); - struct snd_soc_component *component = wm8994->hubs.component; - -- pm_runtime_get_sync(component->dev); -- -- mutex_lock(&wm8994->accdet_lock); -+ guard(pm_runtime_active)(component->dev); -+ guard(mutex)(&wm8994->accdet_lock); - - wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status); -- -- mutex_unlock(&wm8994->accdet_lock); -- -- pm_runtime_put(component->dev); - } - - static irqreturn_t wm8958_mic_irq(int irq, void *data) -diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c ---- a/sound/soc/codecs/wm9712.c -+++ b/sound/soc/codecs/wm9712.c -@@ -6,6 +6,7 @@ - * Author: Liam Girdwood - */ - -+#include - #include - #include - #include -@@ -229,7 +230,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, - shift = mc->shift & 0xff; - mask = 1 << shift; - -- mutex_lock(&wm9712->lock); -+ guard(mutex)(&wm9712->lock); - old = wm9712->hp_mixer[mixer]; - if (ucontrol->value.integer.value[0]) - wm9712->hp_mixer[mixer] |= mask; -@@ -251,8 +252,6 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, - &update); - } - -- mutex_unlock(&wm9712->lock); -- - return change; - } - -diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c ---- a/sound/soc/codecs/wm9713.c -+++ b/sound/soc/codecs/wm9713.c -@@ -11,6 +11,7 @@ - * o Support for DAPM - */ - -+#include - #include - #include - #include -@@ -238,7 +239,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, - shift = mc->shift & 0xff; - mask = (1 << shift); - -- mutex_lock(&wm9713->lock); -+ guard(mutex)(&wm9713->lock); - old = wm9713->hp_mixer[mixer]; - if (ucontrol->value.integer.value[0]) - wm9713->hp_mixer[mixer] |= mask; -@@ -260,8 +261,6 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, - &update); - } - -- mutex_unlock(&wm9713->lock); -- - return change; - } - -diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c ---- a/sound/soc/codecs/wm_adsp.c -+++ b/sound/soc/codecs/wm_adsp.c -@@ -348,7 +348,6 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct wm_adsp *dsp = snd_soc_component_get_drvdata(component); -- int ret = 1; - - if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw) - return 0; -@@ -356,16 +355,14 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, - if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW) - return -EINVAL; - -- mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock); -+ guard(mutex)(&dsp[e->shift_l].cs_dsp.pwr_lock); - - if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list)) -- ret = -EBUSY; -+ return -EBUSY; - else - dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; - -- mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock); -- -- return ret; -+ return 1; - } - EXPORT_SYMBOL_GPL(wm_adsp_fw_put); - -@@ -450,15 +447,13 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl, - if (val == 0) - return 0; /* 0 means no event */ - -- mutex_lock(&cs_ctl->dsp->pwr_lock); -+ guard(mutex)(&cs_ctl->dsp->pwr_lock); - - if (cs_ctl->enabled) - ret = cs_dsp_coeff_write_acked_control(cs_ctl, val); - else - ret = -EPERM; - -- mutex_unlock(&cs_ctl->dsp->pwr_lock); -- - if (ret < 0) - return ret; - -@@ -486,15 +481,13 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, - struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; - int ret = 0; - -- mutex_lock(&cs_ctl->dsp->pwr_lock); -+ guard(mutex)(&cs_ctl->dsp->pwr_lock); - - ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size); - - if (!ret && copy_to_user(bytes, cs_ctl->cache, size)) - ret = -EFAULT; - -- mutex_unlock(&cs_ctl->dsp->pwr_lock); -- - return ret; - } - -@@ -694,10 +687,9 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, - struct cs_dsp_coeff_ctl *cs_ctl; - int ret; - -- mutex_lock(&dsp->cs_dsp.pwr_lock); -+ guard(mutex)(&dsp->cs_dsp.pwr_lock); - cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg); - ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); -- mutex_unlock(&dsp->cs_dsp.pwr_lock); - - if (ret < 0) - return ret; -@@ -709,14 +701,10 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); - int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, - unsigned int alg, void *buf, size_t len) - { -- int ret; -+ guard(mutex)(&dsp->cs_dsp.pwr_lock); - -- mutex_lock(&dsp->cs_dsp.pwr_lock); -- ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), -+ return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg), - 0, buf, len); -- mutex_unlock(&dsp->cs_dsp.pwr_lock); -- -- return ret; - } - EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); - -@@ -1270,38 +1258,32 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) - { - struct wm_adsp_compr *compr, *tmp; - struct snd_soc_pcm_runtime *rtd = stream->private_data; -- int ret = 0; - -- mutex_lock(&dsp->cs_dsp.pwr_lock); -+ guard(mutex)(&dsp->cs_dsp.pwr_lock); - - if (wm_adsp_fw[dsp->fw].num_caps == 0) { - adsp_err(dsp, "%s: Firmware does not support compressed API\n", - snd_soc_rtd_to_codec(rtd, 0)->name); -- ret = -ENXIO; -- goto out; -+ return -ENXIO; - } - - if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { - adsp_err(dsp, "%s: Firmware does not support stream direction\n", - snd_soc_rtd_to_codec(rtd, 0)->name); -- ret = -EINVAL; -- goto out; -+ return -EINVAL; - } - - list_for_each_entry(tmp, &dsp->compr_list, list) { - if (!strcmp(tmp->name, snd_soc_rtd_to_codec(rtd, 0)->name)) { - adsp_err(dsp, "%s: Only a single stream supported per dai\n", - snd_soc_rtd_to_codec(rtd, 0)->name); -- ret = -EBUSY; -- goto out; -+ return -EBUSY; - } - } - - compr = kzalloc_obj(*compr); -- if (!compr) { -- ret = -ENOMEM; -- goto out; -- } -+ if (!compr) -+ return -ENOMEM; - - compr->dsp = dsp; - compr->stream = stream; -@@ -1311,10 +1293,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) - - stream->runtime->private_data = compr; - --out: -- mutex_unlock(&dsp->cs_dsp.pwr_lock); -- -- return ret; -+ return 0; - } - EXPORT_SYMBOL_GPL(wm_adsp_compr_open); - -@@ -1324,7 +1303,7 @@ int wm_adsp_compr_free(struct snd_soc_component *component, - struct wm_adsp_compr *compr = stream->runtime->private_data; - struct wm_adsp *dsp = compr->dsp; - -- mutex_lock(&dsp->cs_dsp.pwr_lock); -+ guard(mutex)(&dsp->cs_dsp.pwr_lock); - - wm_adsp_compr_detach(compr); - list_del(&compr->list); -@@ -1332,8 +1311,6 @@ int wm_adsp_compr_free(struct snd_soc_component *component, - kfree(compr->raw_buf); - kfree(compr); - -- mutex_unlock(&dsp->cs_dsp.pwr_lock); -- - return 0; - } - EXPORT_SYMBOL_GPL(wm_adsp_compr_free); -@@ -1741,7 +1718,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, - - compr_dbg(compr, "Trigger: %d\n", cmd); - -- mutex_lock(&dsp->cs_dsp.pwr_lock); -+ guard(mutex)(&dsp->cs_dsp.pwr_lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: -@@ -1777,8 +1754,6 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component, - break; - } - -- mutex_unlock(&dsp->cs_dsp.pwr_lock); -- - return ret; - } - EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); -@@ -1907,21 +1882,20 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, - - compr_dbg(compr, "Pointer request\n"); - -- mutex_lock(&dsp->cs_dsp.pwr_lock); -+ guard(mutex)(&dsp->cs_dsp.pwr_lock); - - buf = compr->buf; - - if (dsp->fatal_error || !buf || buf->error) { - snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); -- ret = -EIO; -- goto out; -+ return -EIO; - } - - if (buf->avail < wm_adsp_compr_frag_words(compr)) { - ret = wm_adsp_buffer_update_avail(buf); - if (ret < 0) { - compr_err(compr, "Error reading avail: %d\n", ret); -- goto out; -+ return ret; - } - - /* -@@ -1934,14 +1908,14 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, - if (buf->error) - snd_compr_stop_error(stream, - SNDRV_PCM_STATE_XRUN); -- goto out; -+ return ret; - } - - ret = wm_adsp_buffer_reenable_irq(buf); - if (ret < 0) { - compr_err(compr, "Failed to re-enable buffer IRQ: %d\n", - ret); -- goto out; -+ return ret; - } - } - } -@@ -1950,9 +1924,6 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component, - tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE; - tstamp->sampling_rate = compr->sample_rate; - --out: -- mutex_unlock(&dsp->cs_dsp.pwr_lock); -- - return ret; - } - EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); -@@ -2063,15 +2034,13 @@ int wm_adsp_compr_copy(struct snd_soc_component *component, - struct wm_adsp *dsp = compr->dsp; - int ret; - -- mutex_lock(&dsp->cs_dsp.pwr_lock); -+ guard(mutex)(&dsp->cs_dsp.pwr_lock); - - if (stream->direction == SND_COMPRESS_CAPTURE) - ret = wm_adsp_compr_read(compr, buf, count); - else - ret = -ENOTSUPP; - -- mutex_unlock(&dsp->cs_dsp.pwr_lock); -- - return ret; - } - EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); -diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c ---- a/sound/soc/codecs/wsa881x.c -+++ b/sound/soc/codecs/wsa881x.c -@@ -1178,7 +1178,13 @@ static int wsa881x_runtime_resume(struct device *dev) - } - - regcache_cache_only(regmap, false); -- regcache_sync(regmap); -+ ret = regcache_sync(regmap); -+ if (ret) { -+ regcache_cache_only(regmap, true); -+ regcache_mark_dirty(regmap); -+ gpiod_direction_output(wsa881x->sd_n, 1); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c ---- a/sound/soc/codecs/wsa883x.c -+++ b/sound/soc/codecs/wsa883x.c -@@ -4,6 +4,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -1237,9 +1238,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, - - switch (event) { - case SND_SOC_DAPM_POST_PMU: -- mutex_lock(&wsa883x->sp_lock); -- wsa883x->pa_on = true; -- mutex_unlock(&wsa883x->sp_lock); -+ scoped_guard(mutex, &wsa883x->sp_lock) -+ wsa883x->pa_on = true; - - switch (wsa883x->dev_mode) { - case RECEIVER: -@@ -1290,9 +1290,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, - WSA883X_GLOBAL_PA_EN_MASK, 0); - snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, - WSA883X_PDM_EN_MASK, 0); -- mutex_lock(&wsa883x->sp_lock); -- wsa883x->pa_on = false; -- mutex_unlock(&wsa883x->sp_lock); -+ scoped_guard(mutex, &wsa883x->sp_lock) -+ wsa883x->pa_on = false; - break; - } - return 0; -@@ -1696,9 +1695,15 @@ static int wsa883x_runtime_suspend(struct device *dev) - static int wsa883x_runtime_resume(struct device *dev) - { - struct regmap *regmap = dev_get_regmap(dev, NULL); -+ int ret; - - regcache_cache_only(regmap, false); -- regcache_sync(regmap); -+ ret = regcache_sync(regmap); -+ if (ret) { -+ regcache_cache_only(regmap, true); -+ regcache_mark_dirty(regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c ---- a/sound/soc/codecs/wsa884x.c -+++ b/sound/soc/codecs/wsa884x.c -@@ -1701,9 +1701,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, - - switch (event) { - case SND_SOC_DAPM_POST_PMU: -- mutex_lock(&wsa884x->sp_lock); -- wsa884x->pa_on = true; -- mutex_unlock(&wsa884x->sp_lock); -+ scoped_guard(mutex, &wsa884x->sp_lock) -+ wsa884x->pa_on = true; - - wsa884x_spkr_post_pmu(component, wsa884x); - -@@ -1717,9 +1716,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, - WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, - 0x0); - -- mutex_lock(&wsa884x->sp_lock); -- wsa884x->pa_on = false; -- mutex_unlock(&wsa884x->sp_lock); -+ scoped_guard(mutex, &wsa884x->sp_lock) -+ wsa884x->pa_on = false; - break; - } - -@@ -2147,9 +2145,15 @@ static int wsa884x_runtime_suspend(struct device *dev) - static int wsa884x_runtime_resume(struct device *dev) - { - struct regmap *regmap = dev_get_regmap(dev, NULL); -+ int ret; - - regcache_cache_only(regmap, false); -- regcache_sync(regmap); -+ ret = regcache_sync(regmap); -+ if (ret) { -+ regcache_cache_only(regmap, true); -+ regcache_mark_dirty(regmap); -+ return ret; -+ } - - return 0; - } -diff --git a/sound/soc/codecs/wsa885x.c b/sound/soc/codecs/wsa885x.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/codecs/wsa885x.c -@@ -0,0 +1,1533 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -+ */ -+ -+/* WSA885X codec driver */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Control Registers - Audio Processing */ -+#define WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S 0x0000 -+#define WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK 0x0004 -+#define WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX 0x0140 -+#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID 0x0208 -+#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX 0x0240 -+#define WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER 0x0340 -+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0 0x4405 -+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1 0x4406 -+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB 0x4409 -+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB 0x6409 -+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB 0x440a -+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB 0x640a -+#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS 0x0a04 -+#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS 0x0a40 -+#define WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE 0x0b10 -+#define WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX 0x0e40 -+ -+/* Analog Top Registers - Power and Clock Control */ -+#define WSA885X_ANA_TOP_PON_CKSK_CTL_0 0x800d -+#define WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG 0x8024 -+#define WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG 0x8025 -+#define WSA885X_ANA_TOP_BG_TVP_OVRD_CTL 0x8034 -+ -+/* Analog PLL Registers */ -+#define WSA885X_ANA_PLL_DIV_CTL_0 0x8090 -+#define WSA885X_ANA_PLL_DIV_CTL_1 0x8091 -+#define WSA885X_ANA_TOP_PLL_VCO_CTL 0x8092 -+#define WSA885X_ANA_TOP_PLL_LOOPFILT_0 0x8093 -+#define WSA885X_ANA_TOP_PLL_OVRD_CTL 0x8098 -+#define WSA885X_ANA_TOP_PLL_STATUS_0 0x809a -+#define WSA885X_ANA_TOP_PLL_STATUS_1 0x809b -+ -+/* Analog Boost Control Registers */ -+#define WSA885X_ANA_TOP_BOOST_STB_CTRL2 0x805b -+#define WSA885X_ANA_TOP_BOOST_STB_CTRL3 0x805c -+#define WSA885X_ANA_TOP_BOOST_BYP_CTRL2 0x805e -+#define WSA885X_ANA_TOP_BOOST_BYP_CTRL3 0x805f -+#define WSA885X_ANA_TOP_BOOST_MISC 0x8063 -+#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2 0x8065 -+#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4 0x8067 -+ -+/* Analog IV Sense ADC Registers */ -+#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2 0x80ca -+#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3 0x80cb -+#define WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL 0x80cc -+#define WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2 0x80d0 -+ -+/* Analog Speaker Power Stage Registers */ -+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3 0x8108 -+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3 0x810b -+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3 0x810e -+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3 0x8111 -+#define WSA885X_ANA_TOP_SPK_TOP_SPARE3 0x813c -+#define WSA885X_SPK_TOP_LF_CH1_CTRL11 0x811c -+#define WSA885X_SPK_TOP_LF_CH1_TUNE1 0x811d -+#define WSA885X_SPK_TOP_LF_CH2_TUNE1 0x8129 -+#define WSA885X_SPK_TOP_LF_CH1_CTRL9 0x811a -+#define WSA885X_SPK_TOP_LF_CH2_CTRL9 0x8126 -+#define WSA885X_SPK_TOP_LF_CH2_CTRL11 0x8128 -+#define WSA885X_SPK_TOP_COMMON_CTRL2 0x8102 -+#define WSA885X_SPK_TOP_COMMON_TUNE1 0x8103 -+#define WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1 0x80ba -+#define WSA885X_DIG_CTRL0_TOP_CLK_CFG 0x8418 -+#define WSA885X_DIG_CTRL0_SDCA_COMMIT 0x8419 -+#define WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE 0x841a -+#define WSA885X_DIG_CTRL0_SYS_CLK_SEL 0x841b -+#define WSA885X_DIG_CTRL0_CDC_CLK_CTL 0x841c -+#define WSA885X_DIG_CTRL0_PA_FSM_CTL 0x8420 -+#define WSA885X_DIG_CTRL0_POWER_FSM_CTL0 0x8423 -+#define WSA885X_DIG_CTRL0_POWER_FSM_CTL1 0x8424 -+#define WSA885X_DIG_CTRL0_PA0_FSM_CTL1 0x842b -+#define WSA885X_DIG_CTRL0_PA1_FSM_CTL1 0x8435 -+#define WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL 0x8458 -+#define WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL 0x8470 -+#define WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1 0x84b4 -+#define WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1 0x84b7 -+#define WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1 0x84A0 -+#define WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1 0x84A4 -+ -+/* Digital Control 1 Registers - I2S/TDM Interface */ -+#define WSA885X_DIG_CTRL1_I2S_CTL0 0x85A0 -+#define WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX 0x85A2 -+#define WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX 0x85A3 -+#define WSA885X_DIG_CTRL1_I2S_TDM_CTL0 0x85A7 -+#define WSA885X_DIG_CTRL1_I2S_TDM_CTL1 0x85A9 -+#define WSA885X_DIG_CTRL1_I2S_TDM_CH_RX 0x85AA -+#define WSA885X_DIG_CTRL1_I2S_TDM_CH_TX 0x85AB -+#define WSA885X_DIG_CTRL1_I2S_RESET_CTL 0x85AE -+ -+/* CDC RX Path Registers - Audio Data Path */ -+#define WSA885X_CDC_RX0_RX_PATH_CFG0 0x8601 -+#define WSA885X_CDC_RX0_RX_PATH_CFG1 0x8602 -+#define WSA885X_CDC_RX0_RX_PATH_CTL 0x8606 -+#define WSA885X_RX0_RX_PATH_DSMDEM_CTL 0x8613 -+#define WSA885X_CDC_RX1_RX_PATH_CFG0 0x8621 -+#define WSA885X_CDC_RX1_RX_PATH_CFG1 0x8622 -+#define WSA885X_CDC_RX1_RX_PATH_CTL 0x8626 -+#define WSA885X_RX1_RX_PATH_DSMDEM_CTL 0x8633 -+ -+/* CDC Compander Registers - Dynamic Range Control */ -+#define WSA885X_CDC_COMPANDER0_CTL0 0x8640 -+#define WSA885X_CDC_COMPANDER0_CTL7 0x8647 -+#define WSA885X_CDC_COMPANDER1_CTL0 0x8660 -+#define WSA885X_CDC_COMPANDER1_CTL7 0x8667 -+ -+/* CDC Speaker Protection Registers - IV Sense */ -+#define WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL 0x86A1 -+#define WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL 0x86B1 -+#define WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL 0x86A9 -+#define WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL 0x86B9 -+ -+/* CDC Class-H Registers - Headroom Control */ -+#define WSA885X_CDC_CLSH_V1P8_BP_CTL1 0x86CD -+#define WSA885X_CDC_CLSH_V1P8_BP_CTL0 0x86CC -+#define WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0 0x86C7 -+#define WSA885X_CDC_CLSH_CLSH_V_HD_PA 0x86C3 -+#define WSA885X_CDC_CLSH_V1P8_BP_CTL2 0x86CE -+ -+/* Driver Constants */ -+#define WSA885X_CLK_RATE_FIXED 73728000 -+#define WSA885X_NUM_REGS 0x03 -+ -+/* Interrupt Registers */ -+#define WSA885X_INTR_STATUS0 0x8584 -+#define WSA885X_INTR_MASK0 0x8581 -+#define WSA885X_INTR_CLEAR0 0x8587 -+ -+/* Power and PA FSM Control Registers */ -+#define WSA885X_PA0_FSM_CTL0 0x842A -+#define WSA885X_PA1_FSM_CTL0 0x8434 -+ -+/* Digital Control GPIO and Interrupt Registers */ -+#define WSA885X_DIG_CTRL1_PIN_CT 0x8510 -+#define WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL 0x8518 -+#define WSA885X_DIG_CTRL1_INTR_MODE 0x8580 -+ -+#define WSA885X_I2S_CTL0_PCM_RATE_MASK GENMASK(4, 1) -+#define WSA885X_I2S_CTL0_ENABLE_MASK BIT(0) -+#define WSA885X_I2S_CTL0_PCM_RATE(v) \ -+ FIELD_PREP(WSA885X_I2S_CTL0_PCM_RATE_MASK, (v)) -+#define WSA885X_I2S_CTL0_PCM_RATE_8KHZ 0x0 -+#define WSA885X_I2S_CTL0_PCM_RATE_16KHZ 0x1 -+#define WSA885X_I2S_CTL0_PCM_RATE_32KHZ 0x2 -+#define WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ 0x3 -+#define WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ 0x4 -+#define WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ 0x5 -+#define WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ 0x6 -+#define WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK GENMASK(2, 0) -+#define WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK GENMASK(6, 4) -+#define WSA885X_I2S_CFG0_TDM_TX_SLOT0(v) \ -+ FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, (v)) -+#define WSA885X_I2S_CFG0_TDM_TX_SLOT1(v) \ -+ FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, (v)) -+#define WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK GENMASK(2, 0) -+#define WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK GENMASK(6, 4) -+#define WSA885X_I2S_CFG1_TDM_TX_SLOT2(v) \ -+ FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, (v)) -+#define WSA885X_I2S_CFG1_TDM_TX_SLOT3(v) \ -+ FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, (v)) -+#define WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK BIT(0) -+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK GENMASK(3, 2) -+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2 \ -+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 0) -+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4 \ -+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 1) -+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8 \ -+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 3) -+#define WSA885X_I2S_TDM_CH_TX_CH0_EN BIT(0) -+#define WSA885X_I2S_TDM_CH_TX_CH1_EN BIT(1) -+#define WSA885X_I2S_TDM_CH_TX_CH2_EN BIT(2) -+#define WSA885X_I2S_TDM_CH_TX_CH3_EN BIT(3) -+#define WSA885X_I2S_TDM_CH_RX_CH0_EN BIT(0) -+#define WSA885X_I2S_TDM_CH_RX_CH3_EN BIT(3) -+#define WSA885X_I2S_RESET_CTL_RESET_MASK BIT(0) -+#define WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK BIT(2) -+#define WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK BIT(3) -+#define WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK BIT(2) -+ -+#define WSA885X_I2S_TX_SLOT_ISENSE0 0x1 -+#define WSA885X_I2S_TX_SLOT_ISENSE1 0x2 -+#define WSA885X_I2S_TX_SLOT_CUR_SENSE0 0x5 -+#define WSA885X_I2S_TX_SLOT_CUR_SENSE1 0x6 -+ -+/* RX Sample Rate Index Values - Audio Playback Path */ -+#define WSA885X_RX_RATE_8000HZ 0x00 -+#define WSA885X_RX_RATE_16000HZ 0x01 -+#define WSA885X_RX_RATE_32000HZ 0x02 -+#define WSA885X_RX_RATE_44100HZ 0x03 -+#define WSA885X_RX_RATE_48000HZ 0x04 -+#define WSA885X_RX_RATE_96000HZ 0x05 -+#define WSA885X_RX_RATE_192000HZ 0x06 -+#define WSA885X_RX_RATE_384000HZ 0x07 -+ -+/* VI Sample Rate Index Values - Voltage/Current Sensing Path */ -+#define WSA885X_VI_RATE_8000HZ 0x00 -+#define WSA885X_VI_RATE_16000HZ 0x01 -+#define WSA885X_VI_RATE_44100HZ 0x02 -+#define WSA885X_VI_RATE_48000HZ 0x03 -+#define WSA885X_VI_RATE_96000HZ 0x04 -+#define WSA885X_VI_RATE_22050HZ 0x05 -+#define WSA885X_VI_RATE_24000HZ 0x06 -+#define WSA885X_VI_RATE_192000HZ 0x07 -+#define WSA885X_VI_RATE_384000HZ 0x08 -+ -+/* Channel Configuration Masks */ -+#define WSA885X_CHANNEL_STEREO 0x03 -+#define WSA885X_CHANNEL_MONO_LEFT 0x01 -+#define WSA885X_CHANNEL_MONO_RIGHT 0x02 -+ -+#define WSA885X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ -+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | \ -+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) -+ -+#define WSA885X_PLL_LOCK_BIT BIT(0) -+ -+#define WSA885X_FU21_VOL_STEPS 124 -+#define WSA885X_USAGE_MODE_MAX 8 -+static const DECLARE_TLV_DB_SCALE(wsa885x_fu21_digital_gain, -8400, 100, 0); -+ -+static bool wsa885x_is_valid_rx_slot_mask(u32 mask) -+{ -+ return mask == WSA885X_CHANNEL_MONO_LEFT || -+ mask == WSA885X_CHANNEL_MONO_RIGHT || -+ mask == WSA885X_CHANNEL_STEREO; -+} -+ -+static const char *const wsa885x_supply_name[] = { -+ "vdd-1p8", -+ "vdd-io", -+}; -+ -+enum { -+ WSA885X_BATT_1S = 1, -+ WSA885X_BATT_2S, -+}; -+ -+enum { -+ WSA885X_IRQ_INT_SAF2WAR = 0, -+ WSA885X_IRQ_INT_WAR2SAF, -+ WSA885X_IRQ_INT_DISABLE, -+ WSA885X_IRQ_INT_PA0_OCP, -+ WSA885X_IRQ_INT_PA1_OCP, -+ WSA885X_IRQ_INT_CLIP0, -+ WSA885X_IRQ_INT_CLIP1, -+ WSA885X_IRQ_INT_CLK_WD, -+ WSA885X_IRQ_INT_INTR_GPIO1_PIN, -+ WSA885X_IRQ_INT_INTR_GPIO2_PIN, -+ WSA885X_IRQ_INT_UVLO, -+ WSA885X_IRQ_INT_BOP, -+ WSA885X_IRQ_INT_PA0_FSM_ERR, -+ WSA885X_IRQ_INT_PA1_FSM_ERR, -+ WSA885X_IRQ_INT_MAIN_FSM_ERR, -+ WSA885X_IRQ_INT_PCM_DATA0_WD, -+ WSA885X_IRQ_INT_PCM_DATA1_WD, -+ WSA885X_IRQ_INT_PCM_DATA0_DC, -+ WSA885X_IRQ_INT_PCM_DATA1_DC, -+ WSA885X_IRQ_INT_PLL_UNLOCKED, -+ WSA885X_IRQ_INT_PROT_MODE_CHANGE, -+ WSA885X_IRQ_INT_PB_CLOCK_VALID, -+ WSA885X_IRQ_INT_SENSE_CLOCK_VALID, -+ WSA885X_IRQ_MAX, -+}; -+ -+struct wsa885x_priv { -+ struct i2c_client *client; -+ struct regmap *regmap; -+ struct device *dev; -+ struct snd_soc_component *component; -+ struct gpio_desc *sd_n; -+ struct reset_control *sd_reset; -+ u32 usage_mode; -+ u32 rx_slot_mask; -+ u32 batt_conf; -+ int stereo_vol_db; -+ struct mutex state_lock; /* protects mutable control state */ -+}; -+ -+struct wsa885x_reg_update { -+ unsigned int reg; -+ unsigned int mask; -+ unsigned int val; -+}; -+ -+static const struct regmap_range_cfg wsa885x_regmap_ranges[] = { -+ { -+ .range_min = 0, -+ .range_max = 0x88ff, -+ .selector_reg = 0x0, -+ .selector_mask = 0xFF, -+ .selector_shift = 0, -+ .window_start = 0, -+ .window_len = 0x100, -+ }, -+}; -+ -+static const struct reg_default wsa885x_codec_reg_defaults[] = { -+ {WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S, 0x00}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x00}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, 0x00}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, 0x00}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, 0x04}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, 0xac}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, 0xac}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, 0x03}, -+ {WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, 0x03}, -+ {WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x00}, -+ {WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x19}, -+ {WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x22}, -+ {WSA885X_ANA_PLL_DIV_CTL_0, 0x0c}, -+ {WSA885X_ANA_PLL_DIV_CTL_1, 0x50}, -+ {WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00}, -+ {WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xb4}, -+ {WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00}, -+ {WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00}, -+ {WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x03}, -+ {WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x3c}, -+ {WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc5}, -+ {WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x13}, -+ {WSA885X_ANA_TOP_BOOST_MISC, 0x79}, -+ {WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x00}, -+ {WSA885X_SPK_TOP_COMMON_CTRL2, 0x08}, -+ {WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x09}, -+ {WSA885X_SPK_TOP_LF_CH1_TUNE1, 0x00}, -+ {WSA885X_SPK_TOP_LF_CH2_TUNE1, 0x00}, -+ {WSA885X_SPK_TOP_LF_CH1_CTRL9, 0x00}, -+ {WSA885X_SPK_TOP_LF_CH2_CTRL9, 0x00}, -+ {WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x09}, -+ {WSA885X_SPK_TOP_COMMON_TUNE1, 0x03}, -+ {WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1, 0x00}, -+ {WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0e}, -+ {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x40}, -+ {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0xff}, -+ {WSA885X_ANA_TOP_PLL_STATUS_0, 0x00}, -+ {WSA885X_ANA_TOP_PLL_STATUS_1, 0x00}, -+ {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x84}, -+ {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x02}, -+ {WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x00}, -+ {WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0xe0}, -+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa4}, -+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0xc9}, -+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa4}, -+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0xc9}, -+ {WSA885X_DIG_CTRL0_TOP_CLK_CFG, 0x00}, -+ {WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x00}, -+ {WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00}, -+ {WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00}, -+ {WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00}, -+ {WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05}, -+ {WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x00}, -+ {WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x45}, -+ {WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x45}, -+ {WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x7f}, -+ {WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00}, -+ {WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01}, -+ {WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01}, -+ {WSA885X_DIG_CTRL1_I2S_CTL0, 0x06}, -+ {WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, 0x00}, -+ {WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, 0x00}, -+ {WSA885X_DIG_CTRL1_I2S_TDM_CTL0, 0x00}, -+ {WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05}, -+ {WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00}, -+ {WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00}, -+ {WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, WSA885X_I2S_TDM_CH_RX_CH3_EN}, -+ {WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89}, -+ {WSA885X_CDC_RX0_RX_PATH_CFG1, 0x64}, -+ {WSA885X_CDC_RX0_RX_PATH_CTL, 0x24}, -+ {WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01}, -+ {WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89}, -+ {WSA885X_CDC_RX1_RX_PATH_CFG1, 0x64}, -+ {WSA885X_CDC_RX1_RX_PATH_CTL, 0x04}, -+ {WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01}, -+ {WSA885X_CDC_COMPANDER0_CTL0, 0x01}, -+ {WSA885X_CDC_COMPANDER0_CTL7, 0x2a}, -+ {WSA885X_CDC_COMPANDER1_CTL0, 0x01}, -+ {WSA885X_CDC_COMPANDER1_CTL7, 0x2a}, -+ {WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14}, -+ {WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14}, -+ {WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14}, -+ {WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14}, -+ {WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50}, -+ {WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c}, -+ {WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d}, -+ {WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03}, -+ {WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05}, -+}; -+ -+static void wsa885x_multi_update_bits(struct regmap *regmap, -+ const struct wsa885x_reg_update *updates, -+ size_t num_updates) -+{ -+ size_t i; -+ -+ for (i = 0; i < num_updates; i++) -+ regmap_update_bits(regmap, updates[i].reg, -+ updates[i].mask, updates[i].val); -+} -+ -+static void wsa885x_toggle_irq_bit(struct wsa885x_priv *wsa885x, -+ unsigned int reg, unsigned int mask) -+{ -+ regmap_update_bits(wsa885x->regmap, reg, mask, 0); -+ regmap_update_bits(wsa885x->regmap, reg, mask, mask); -+} -+ -+static void wsa885x_pulse_irq_bit(struct wsa885x_priv *wsa885x, -+ unsigned int reg, unsigned int mask) -+{ -+ regmap_update_bits(wsa885x->regmap, reg, mask, 0); -+ regmap_update_bits(wsa885x->regmap, reg, mask, mask); -+ regmap_update_bits(wsa885x->regmap, reg, mask, 0); -+} -+ -+static int wsa885x_tdm_ctl0_slot_num_val(int slots, unsigned int *slot_num_val) -+{ -+ if (!slot_num_val) -+ return -EINVAL; -+ -+ switch (slots) { -+ case 2: -+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2; -+ return 0; -+ case 4: -+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4; -+ return 0; -+ case 8: -+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int wsa885x_reg_update_sequence(struct regmap *regmap, int slots) -+{ -+ static const struct reg_sequence regs[] = { -+ { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x15 }, -+ { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x11 }, -+ }; -+ unsigned int slot_num_val; -+ int ret; -+ -+ if (!regmap) -+ return -EINVAL; -+ -+ ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val); -+ if (ret) -+ return ret; -+ -+ regmap_multi_reg_write(regmap, regs, ARRAY_SIZE(regs)); -+ -+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0, -+ WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, -+ slot_num_val); -+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0, -+ WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK, -+ WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK); -+ regmap_write(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, -+ WSA885X_I2S_TDM_CH_TX_CH0_EN); -+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, -+ WSA885X_I2S_TDM_CH_TX_CH1_EN, -+ WSA885X_I2S_TDM_CH_TX_CH1_EN); -+ -+ return 0; -+} -+ -+static int wsa885x_wait_for_pll_lock(struct wsa885x_priv *wsa885x) -+{ -+ unsigned int status = 0; -+ int cnt = 0, ret = 0; -+ -+ do { -+ usleep_range(1000, 1100); -+ ret = regmap_read(wsa885x->regmap, WSA885X_ANA_TOP_PLL_STATUS_0, &status); -+ if (ret) { -+ dev_err(wsa885x->dev, "PLL status read failed: %d\n", ret); -+ return ret; -+ } -+ -+ if (status & WSA885X_PLL_LOCK_BIT) -+ return 0; -+ } while (++cnt < 20); -+ -+ dev_warn(wsa885x->dev, "PLL lock timeout after 20ms, status=0x%x\n", status); -+ return -ETIMEDOUT; -+} -+ -+static int wsa885x_2s_conf(struct wsa885x_priv *wsa885x) -+{ -+ static const struct reg_sequence regs[] = { -+ { WSA885X_SPK_TOP_COMMON_TUNE1, 0x26 }, -+ { WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x0d }, -+ { WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x0d }, -+ { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x71 }, -+ { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0xAA }, -+ }; -+ -+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); -+} -+ -+static const struct reg_sequence wsa885x_reg_init[] = { -+ { WSA885X_CDC_RX0_RX_PATH_CTL, 0x24 }, -+ { WSA885X_CDC_RX1_RX_PATH_CTL, 0x24 }, -+ { WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01 }, -+ { WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01 }, -+ { WSA885X_CDC_COMPANDER0_CTL0, 0x01 }, -+ { WSA885X_CDC_COMPANDER1_CTL0, 0x01 }, -+ { WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14 }, -+ { WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14 }, -+ { WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14 }, -+ { WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14 }, -+ { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0f }, -+ { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x4f }, -+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x02 }, -+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00 }, -+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x01 }, -+ { WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x01 }, -+ { WSA885X_CDC_RX0_RX_PATH_CFG1, 0x60 }, -+ { WSA885X_CDC_RX1_RX_PATH_CFG1, 0x60 }, -+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa5 }, -+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa5 }, -+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x85 }, -+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0c }, -+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0e }, -+ { WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x0c }, -+ { WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01 }, -+ { WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01 }, -+ { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x88 }, -+ { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89 }, -+ { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x88 }, -+ { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89 }, -+ { WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x82 }, -+ { WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x34 }, -+ { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x41 }, -+ { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0x7f }, -+ { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50 }, -+ { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c }, -+ { WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d }, -+ { WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03 }, -+ { WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05 }, -+ { WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x20 }, -+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0x45 }, -+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0x45 }, -+ { WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05 }, -+ { WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x35 }, -+ { WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x21 }, -+ { WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc7 }, -+ { WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x11 }, -+ { WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0x80 }, -+ { WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x08 }, -+ { WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x47 }, -+ { WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x47 }, -+ { WSA885X_CDC_COMPANDER0_CTL7, 0x34 }, -+ { WSA885X_CDC_COMPANDER1_CTL7, 0x34 }, -+ { WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x79 }, -+}; -+ -+static int wsa885x_hw_init(struct wsa885x_priv *wsa885x) -+{ -+ static const struct reg_sequence regs[] = { -+ { WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL, 0x2e }, -+ { WSA885X_DIG_CTRL1_INTR_MODE, 0x01 }, -+ { WSA885X_DIG_CTRL1_PIN_CT, 0x04 }, -+ }; -+ int ret; -+ -+ ret = regmap_multi_reg_write(wsa885x->regmap, wsa885x_reg_init, -+ ARRAY_SIZE(wsa885x_reg_init)); -+ if (ret) -+ return ret; -+ -+ if (wsa885x->batt_conf == WSA885X_BATT_2S) { -+ ret = wsa885x_2s_conf(wsa885x); -+ if (ret) -+ return ret; -+ } -+ -+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); -+} -+ -+static int wsa885x_unmask_interrupts(struct wsa885x_priv *wsa885x) -+{ -+ static const struct reg_sequence regs[] = { -+ { WSA885X_INTR_MASK0, 0x00 }, -+ { WSA885X_INTR_MASK0 + 1, 0x00 }, -+ { WSA885X_INTR_MASK0 + 2, 0xf8 }, -+ }; -+ -+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); -+} -+ -+static int wsa885x_wait_for_pde_state(struct wsa885x_priv *wsa885x, int ps) -+{ -+ unsigned int act_ps = 0, clock_valid = 0; -+ int rc = 0, cnt = 0; -+ -+ if (ps < 0 || ps > 3) -+ return -EINVAL; -+ -+ do { -+ usleep_range(1000, 1500); -+ rc = regmap_read(wsa885x->regmap, -+ WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, -+ &act_ps); -+ if (rc) { -+ dev_err(wsa885x->dev, "PDE state read failed: %d\n", rc); -+ return rc; -+ } -+ if (act_ps == ps) -+ return 0; -+ } while (++cnt < 5); -+ -+ if (regmap_read(wsa885x->regmap, -+ WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, -+ &clock_valid)) -+ dev_err(wsa885x->dev, -+ "PDE power state %d request failed, actual_ps %d, clock_valid read failed\n", -+ ps, act_ps); -+ else -+ dev_err(wsa885x->dev, -+ "PDE power state %d request failed, actual_ps %d, clock_valid:%d\n", -+ ps, act_ps, clock_valid); -+ -+ return -ETIMEDOUT; -+} -+ -+static void wsa885x_program_stereo_volume(struct wsa885x_priv *wsa885x, -+ int stereo_vol_db, bool commit) -+{ -+ regmap_write(wsa885x->regmap, -+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, -+ (u8)(s8)stereo_vol_db); -+ regmap_write(wsa885x->regmap, -+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00); -+ regmap_write(wsa885x->regmap, -+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, -+ (u8)(s8)stereo_vol_db); -+ regmap_write(wsa885x->regmap, -+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00); -+ -+ if (commit) -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); -+} -+ -+static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct wsa885x_priv *wsa885x; -+ u8 pcm_rate, cs21_sample_rate_idx, cs24_sample_rate_idx; -+ -+ wsa885x = snd_soc_component_get_drvdata(dai->component); -+ -+ switch (params_rate(params)) { -+ case 8000: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_8KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_8000HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_8000HZ; -+ break; -+ case 16000: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_16KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_16000HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_16000HZ; -+ break; -+ case 32000: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_32KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_32000HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ; -+ break; -+ case 44100: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_44100HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_44100HZ; -+ break; -+ case 48000: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_48000HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ; -+ break; -+ case 88200: -+ case 96000: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_96000HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_96000HZ; -+ break; -+ case 176400: -+ case 192000: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_192000HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_192000HZ; -+ break; -+ case 352800: -+ case 384000: -+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ; -+ cs21_sample_rate_idx = WSA885X_RX_RATE_384000HZ; -+ cs24_sample_rate_idx = WSA885X_VI_RATE_384000HZ; -+ break; -+ default: -+ dev_err(wsa885x->dev, "sampling rate %d is not supported\n", params_rate(params)); -+ return -EINVAL; -+ } -+ -+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0, -+ WSA885X_I2S_CTL0_PCM_RATE_MASK | -+ WSA885X_I2S_CTL0_ENABLE_MASK, -+ WSA885X_I2S_CTL0_PCM_RATE(pcm_rate) | -+ WSA885X_I2S_CTL0_ENABLE_MASK); -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00); -+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, -+ cs21_sample_rate_idx); -+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, -+ cs24_sample_rate_idx); -+ -+ mutex_lock(&wsa885x->state_lock); -+ wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); -+ mutex_unlock(&wsa885x->state_lock); -+ -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01); -+ -+ return 0; -+} -+ -+static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai, -+ unsigned int tx_slot_mask, -+ unsigned int rx_slot_mask, int slots, -+ int slot_width) -+{ -+ static const struct wsa885x_reg_update stereo_updates[] = { -+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, -+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) }, -+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, -+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_ISENSE1) }, -+ { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, -+ WSA885X_I2S_CFG1_TDM_TX_SLOT2(WSA885X_I2S_TX_SLOT_CUR_SENSE0) }, -+ { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, -+ WSA885X_I2S_CFG1_TDM_TX_SLOT3(WSA885X_I2S_TX_SLOT_CUR_SENSE1) }, -+ }; -+ static const struct wsa885x_reg_update mono_left_updates[] = { -+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, -+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) }, -+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, -+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE0) }, -+ }; -+ static const struct wsa885x_reg_update mono_right_updates[] = { -+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, -+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE1) }, -+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, -+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE1) }, -+ }; -+ struct wsa885x_priv *wsa885x; -+ unsigned int slot_num_val; -+ u32 mask; -+ int ret; -+ -+ wsa885x = snd_soc_component_get_drvdata(dai->component); -+ -+ ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val); -+ if (ret) { -+ dev_err(wsa885x->dev, "%s: unsupported slot count %d\n", -+ __func__, slots); -+ return ret; -+ } -+ -+ if (rx_slot_mask && !wsa885x_is_valid_rx_slot_mask(rx_slot_mask)) { -+ dev_err(wsa885x->dev, -+ "%s: unsupported rx_slot_mask 0x%x\n", -+ __func__, rx_slot_mask); -+ return -EINVAL; -+ } -+ -+ mutex_lock(&wsa885x->state_lock); -+ if (rx_slot_mask) -+ wsa885x->rx_slot_mask = rx_slot_mask; -+ else if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) -+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; -+ mask = wsa885x->rx_slot_mask; -+ -+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, -+ WSA885X_I2S_RESET_CTL_RESET_MASK, -+ WSA885X_I2S_RESET_CTL_RESET_MASK); -+ -+ if (mask == WSA885X_CHANNEL_STEREO) { -+ wsa885x_multi_update_bits(wsa885x->regmap, stereo_updates, -+ ARRAY_SIZE(stereo_updates)); -+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); -+ if (ret) -+ goto exit_unlock; -+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, -+ WSA885X_I2S_TDM_CH_TX_CH2_EN, -+ WSA885X_I2S_TDM_CH_TX_CH2_EN); -+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, -+ WSA885X_I2S_TDM_CH_TX_CH3_EN, -+ WSA885X_I2S_TDM_CH_TX_CH3_EN); -+ } else if (mask == WSA885X_CHANNEL_MONO_LEFT) { -+ wsa885x_multi_update_bits(wsa885x->regmap, mono_left_updates, -+ ARRAY_SIZE(mono_left_updates)); -+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); -+ if (ret) -+ goto exit_unlock; -+ } else if (mask == WSA885X_CHANNEL_MONO_RIGHT) { -+ wsa885x_multi_update_bits(wsa885x->regmap, mono_right_updates, -+ ARRAY_SIZE(mono_right_updates)); -+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots); -+ if (ret) -+ goto exit_unlock; -+ } -+ -+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0, -+ WSA885X_I2S_CTL0_ENABLE_MASK, -+ WSA885X_I2S_CTL0_ENABLE_MASK); -+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, -+ WSA885X_I2S_RESET_CTL_RESET_MASK, 0); -+ -+ ret = 0; -+ -+exit_unlock: -+ mutex_unlock(&wsa885x->state_lock); -+ -+ return ret; -+} -+ -+static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id, -+ unsigned int freq, int dir) -+{ -+ static const struct reg_sequence pll_prep[] = { -+ { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x03 }, -+ { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x04 }, -+ { WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xB4 }, -+ { WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00 }, -+ { WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00 }, -+ }; -+ static const struct reg_sequence pll_cleanup[] = { -+ { WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00 }, -+ { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 }, -+ { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 }, -+ }; -+ struct wsa885x_priv *wsa885x; -+ u32 pll_div; -+ int ret = 0; -+ -+ wsa885x = snd_soc_component_get_drvdata(dai->component); -+ -+ if (!freq) -+ return -EINVAL; -+ if (WSA885X_CLK_RATE_FIXED % freq) -+ return -EINVAL; -+ pll_div = WSA885X_CLK_RATE_FIXED / freq; -+ if (pll_div > 0xff) -+ return -EINVAL; -+ -+ regmap_multi_reg_write(wsa885x->regmap, pll_prep, ARRAY_SIZE(pll_prep)); -+ regmap_write(wsa885x->regmap, WSA885X_ANA_PLL_DIV_CTL_0, pll_div); -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x02); -+ -+ ret = wsa885x_wait_for_pll_lock(wsa885x); -+ if (ret) { -+ dev_err(wsa885x->dev, "PLL lock failed, aborting sysclk configuration\n"); -+ regmap_multi_reg_write(wsa885x->regmap, pll_cleanup, -+ ARRAY_SIZE(pll_cleanup)); -+ return ret; -+ } -+ -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00); -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x01); -+ regmap_write(wsa885x->regmap, WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00); -+ -+ return 0; -+} -+ -+static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stream) -+{ -+ static const struct reg_sequence mute_regs[] = { -+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, -+ { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03 }, -+ }; -+ static const struct reg_sequence mute_commit_regs[] = { -+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01 }, -+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01 }, -+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, -+ }; -+ static const struct reg_sequence unmute_prep_head_regs[] = { -+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, -+ }; -+ static const struct reg_sequence unmute_prep_tail_regs[] = { -+ { WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01 }, -+ { WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01 }, -+ }; -+ static const struct reg_sequence unmute_volume_regs[] = { -+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00 }, -+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00 }, -+ }; -+ static const struct reg_sequence unmute_commit_regs[] = { -+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, -+ { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x00 }, -+ }; -+ static const struct reg_sequence unmute_finish_regs[] = { -+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x00 }, -+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x00 }, -+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 }, -+ }; -+ struct wsa885x_priv *wsa885x; -+ int ret = 0, ps0 = 0, ps3 = 3; -+ -+ wsa885x = snd_soc_component_get_drvdata(dai->component); -+ -+ if (stream != SNDRV_PCM_STREAM_PLAYBACK) -+ return 0; -+ -+ mutex_lock(&wsa885x->state_lock); -+ -+ if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { -+ ret = -EINVAL; -+ goto exit_unlock; -+ } -+ -+ if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask)) -+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; -+ -+ if (mute) { -+ regmap_multi_reg_write(wsa885x->regmap, mute_regs, -+ ARRAY_SIZE(mute_regs)); -+ ret = wsa885x_wait_for_pde_state(wsa885x, ps3); -+ if (ret) { -+ dev_err(wsa885x->dev, -+ "PS3 transition failed: %d\n", ret); -+ } else { -+ regmap_multi_reg_write(wsa885x->regmap, mute_commit_regs, -+ ARRAY_SIZE(mute_commit_regs)); -+ } -+ } else { -+ regmap_multi_reg_write(wsa885x->regmap, unmute_prep_head_regs, -+ ARRAY_SIZE(unmute_prep_head_regs)); -+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, -+ wsa885x->usage_mode); -+ regmap_multi_reg_write(wsa885x->regmap, unmute_prep_tail_regs, -+ ARRAY_SIZE(unmute_prep_tail_regs)); -+ wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false); -+ regmap_multi_reg_write(wsa885x->regmap, unmute_volume_regs, -+ ARRAY_SIZE(unmute_volume_regs)); -+ regmap_multi_reg_write(wsa885x->regmap, unmute_commit_regs, -+ ARRAY_SIZE(unmute_commit_regs)); -+ ret = wsa885x_wait_for_pde_state(wsa885x, ps0); -+ if (ret) -+ goto exit_unlock; -+ -+ if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) { -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, -+ WSA885X_I2S_TDM_CH_RX_CH0_EN | -+ WSA885X_I2S_TDM_CH_RX_CH3_EN); -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x03); -+ } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) { -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, -+ WSA885X_I2S_TDM_CH_RX_CH3_EN); -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x01); -+ } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) { -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, -+ WSA885X_I2S_TDM_CH_RX_CH0_EN); -+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x02); -+ } -+ -+ regmap_multi_reg_write(wsa885x->regmap, unmute_finish_regs, -+ ARRAY_SIZE(unmute_finish_regs)); -+ } -+ -+exit_unlock: -+ mutex_unlock(&wsa885x->state_lock); -+ -+ return ret; -+} -+ -+static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ static const struct reg_sequence regs[] = { -+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 }, -+ }; -+ struct wsa885x_priv *wsa885x; -+ -+ wsa885x = snd_soc_component_get_drvdata(dai->component); -+ -+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) -+ return 0; -+ -+ mutex_lock(&wsa885x->state_lock); -+ regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs)); -+ mutex_unlock(&wsa885x->state_lock); -+ -+ return 0; -+} -+ -+static const struct snd_soc_dai_ops wsa885x_dai_ops = { -+ .hw_params = wsa885x_codec_hw_params, -+ .set_tdm_slot = wsa885x_codec_set_tdm_slot, -+ .set_sysclk = wsa885x_codec_set_sysclk, -+ .mute_stream = wsa885x_codec_mute_stream, -+ .hw_free = wsa885x_codec_hw_free, -+}; -+ -+static struct snd_soc_dai_driver wsa885x_dai[] = { -+ { -+ .name = "wsa885x_dai_drv", -+ .playback = { -+ .stream_name = "WSA885X TDM Playback", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = WSA885X_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE, -+ }, -+ .ops = &wsa885x_dai_ops, -+ }, -+}; -+ -+static void wsa885x_reset_assert(void *data) -+{ -+ struct wsa885x_priv *wsa885x = data; -+ -+ if (wsa885x->sd_reset) -+ reset_control_assert(wsa885x->sd_reset); -+ else -+ gpiod_direction_output(wsa885x->sd_n, 1); -+} -+ -+static void wsa885x_reset_deassert(struct wsa885x_priv *wsa885x) -+{ -+ if (wsa885x->sd_reset) -+ reset_control_deassert(wsa885x->sd_reset); -+ else -+ gpiod_direction_output(wsa885x->sd_n, 0); -+} -+ -+static int wsa885x_get_reset(struct device *dev, struct wsa885x_priv *wsa885x) -+{ -+ wsa885x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL); -+ if (IS_ERR(wsa885x->sd_reset)) -+ return dev_err_probe(dev, PTR_ERR(wsa885x->sd_reset), -+ "Failed to get reset\n"); -+ else if (wsa885x->sd_reset) -+ return 0; -+ -+ wsa885x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); -+ if (IS_ERR(wsa885x->sd_n)) -+ return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n), -+ "Shutdown Control GPIO not found\n"); -+ -+ return 0; -+} -+ -+static bool wsa885x_volatile_register(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case WSA885X_ANA_TOP_PLL_STATUS_0: -+ case WSA885X_ANA_TOP_PLL_STATUS_1: -+ case WSA885X_DIG_CTRL0_SDCA_COMMIT: -+ case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS: -+ case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID: -+ case WSA885X_INTR_STATUS0: -+ case WSA885X_INTR_STATUS0 + 1: -+ case WSA885X_INTR_STATUS0 + 2: -+ case WSA885X_INTR_CLEAR0: -+ case WSA885X_INTR_CLEAR0 + 1: -+ case WSA885X_INTR_CLEAR0 + 2: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool wsa885x_readable_register(struct device *dev, unsigned int reg) -+{ -+ if (reg == WSA885X_INTR_CLEAR0 || -+ reg == WSA885X_INTR_CLEAR0 + 1 || -+ reg == WSA885X_INTR_CLEAR0 + 2) -+ return false; -+ return reg <= 0x88ff; -+} -+ -+static bool wsa885x_writeable_register(struct device *dev, unsigned int reg) -+{ -+ if (reg > 0x88ff) -+ return false; -+ -+ switch (reg) { -+ case WSA885X_ANA_TOP_PLL_STATUS_0: -+ case WSA885X_ANA_TOP_PLL_STATUS_1: -+ case WSA885X_INTR_STATUS0: -+ case WSA885X_INTR_STATUS0 + 1: -+ case WSA885X_INTR_STATUS0 + 2: -+ case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS: -+ case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID: -+ return false; -+ default: -+ return true; -+ } -+} -+ -+static const struct regmap_config wsa885x_regmap_cfg = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = 0x88FF, -+ .ranges = wsa885x_regmap_ranges, -+ .num_ranges = ARRAY_SIZE(wsa885x_regmap_ranges), -+ .reg_defaults = wsa885x_codec_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(wsa885x_codec_reg_defaults), -+ .volatile_reg = wsa885x_volatile_register, -+ .writeable_reg = wsa885x_writeable_register, -+ .readable_reg = wsa885x_readable_register, -+ .cache_type = REGCACHE_MAPLE, -+ .use_single_read = true, -+ .use_single_write = true, -+}; -+ -+static int wsa885x_component_probe(struct snd_soc_component *component) -+{ -+ struct wsa885x_priv *wsa885x = -+ snd_soc_component_get_drvdata(component); -+ int ret; -+ -+ wsa885x->component = component; -+ snd_soc_component_init_regmap(component, wsa885x->regmap); -+ -+ ret = wsa885x_hw_init(wsa885x); -+ if (ret) -+ return ret; -+ -+ return wsa885x_unmask_interrupts(wsa885x); -+} -+ -+static int wsa885x_stereo_gain_offset_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); -+ int val; -+ -+ mutex_lock(&wsa885x->state_lock); -+ val = wsa885x->stereo_vol_db + 84; -+ mutex_unlock(&wsa885x->state_lock); -+ if (val < 0 || val > WSA885X_FU21_VOL_STEPS) -+ return -ERANGE; -+ -+ ucontrol->value.integer.value[0] = val; -+ return 0; -+} -+ -+static int wsa885x_stereo_gain_offset_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); -+ long val; -+ int stereo_vol_db; -+ -+ val = ucontrol->value.integer.value[0]; -+ -+ if (val < 0 || val > WSA885X_FU21_VOL_STEPS) { -+ dev_err(component->dev, "%s: Invalid range, Val: %ld\n", __func__, val); -+ return -EINVAL; -+ } -+ -+ stereo_vol_db = (int)val - 84; -+ -+ mutex_lock(&wsa885x->state_lock); -+ if (wsa885x->stereo_vol_db == stereo_vol_db) { -+ mutex_unlock(&wsa885x->state_lock); -+ return 0; -+ } -+ -+ wsa885x_program_stereo_volume(wsa885x, stereo_vol_db, true); -+ wsa885x->stereo_vol_db = stereo_vol_db; -+ mutex_unlock(&wsa885x->state_lock); -+ -+ return 1; -+} -+ -+static int wsa885x_usage_modes_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); -+ -+ mutex_lock(&wsa885x->state_lock); -+ if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) { -+ mutex_unlock(&wsa885x->state_lock); -+ return -ERANGE; -+ } -+ -+ ucontrol->value.integer.value[0] = wsa885x->usage_mode; -+ mutex_unlock(&wsa885x->state_lock); -+ -+ return 0; -+} -+ -+static int wsa885x_usage_modes_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); -+ u32 val = ucontrol->value.integer.value[0]; -+ -+ if (val > WSA885X_USAGE_MODE_MAX) -+ return -EINVAL; -+ -+ mutex_lock(&wsa885x->state_lock); -+ if (wsa885x->usage_mode == val) { -+ mutex_unlock(&wsa885x->state_lock); -+ return 0; -+ } -+ -+ wsa885x->usage_mode = val; -+ mutex_unlock(&wsa885x->state_lock); -+ -+ return 1; -+} -+ -+static int wsa885x_rx_slot_mask_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); -+ u32 mask; -+ -+ mutex_lock(&wsa885x->state_lock); -+ mask = wsa885x->rx_slot_mask; -+ mutex_unlock(&wsa885x->state_lock); -+ if (!wsa885x_is_valid_rx_slot_mask(mask)) -+ return -ERANGE; -+ -+ ucontrol->value.integer.value[0] = mask; -+ -+ return 0; -+} -+ -+static int wsa885x_rx_slot_mask_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component); -+ u32 mask = ucontrol->value.integer.value[0]; -+ -+ if (!wsa885x_is_valid_rx_slot_mask(mask)) -+ return -EINVAL; -+ -+ mutex_lock(&wsa885x->state_lock); -+ if (wsa885x->rx_slot_mask == mask) { -+ mutex_unlock(&wsa885x->state_lock); -+ return 0; -+ } -+ -+ wsa885x->rx_slot_mask = mask; -+ mutex_unlock(&wsa885x->state_lock); -+ -+ return 1; -+} -+ -+static const struct snd_kcontrol_new wsa885x_snd_controls[] = { -+ SOC_SINGLE_EXT("Usage Mode", SND_SOC_NOPM, 0, WSA885X_USAGE_MODE_MAX, 0, -+ wsa885x_usage_modes_get, -+ wsa885x_usage_modes_put), -+ -+ SOC_SINGLE_EXT_TLV("Speaker Volume", SND_SOC_NOPM, -+ 0, WSA885X_FU21_VOL_STEPS, 0, -+ wsa885x_stereo_gain_offset_get, -+ wsa885x_stereo_gain_offset_put, -+ wsa885x_fu21_digital_gain), -+ -+ SOC_SINGLE_EXT("Rx Slot Mask", SND_SOC_NOPM, 0, 3, 0, -+ wsa885x_rx_slot_mask_get, -+ wsa885x_rx_slot_mask_put), -+}; -+ -+static const struct snd_soc_component_driver wsa885x_component = { -+ .name = "wsa885x", -+ .probe = wsa885x_component_probe, -+ .controls = wsa885x_snd_controls, -+ .num_controls = ARRAY_SIZE(wsa885x_snd_controls), -+}; -+ -+static irqreturn_t wsa885x_handle_irq(int irq_idx, void *data) -+{ -+ struct wsa885x_priv *wsa885x = data; -+ -+ if (irq_idx < 0 || irq_idx >= WSA885X_IRQ_MAX) -+ return IRQ_NONE; -+ -+ switch (irq_idx) { -+ case WSA885X_IRQ_INT_SAF2WAR: -+ case WSA885X_IRQ_INT_WAR2SAF: -+ case WSA885X_IRQ_INT_DISABLE: -+ case WSA885X_IRQ_INT_INTR_GPIO1_PIN: -+ case WSA885X_IRQ_INT_INTR_GPIO2_PIN: -+ case WSA885X_IRQ_INT_PA0_OCP: -+ case WSA885X_IRQ_INT_PA1_OCP: -+ case WSA885X_IRQ_INT_CLIP0: -+ case WSA885X_IRQ_INT_CLIP1: -+ case WSA885X_IRQ_INT_CLK_WD: -+ case WSA885X_IRQ_INT_BOP: -+ case WSA885X_IRQ_INT_UVLO: -+ case WSA885X_IRQ_INT_PCM_DATA0_DC: -+ case WSA885X_IRQ_INT_PCM_DATA1_DC: -+ case WSA885X_IRQ_INT_PLL_UNLOCKED: -+ case WSA885X_IRQ_INT_PROT_MODE_CHANGE: -+ case WSA885X_IRQ_INT_PB_CLOCK_VALID: -+ case WSA885X_IRQ_INT_SENSE_CLOCK_VALID: -+ break; -+ case WSA885X_IRQ_INT_PCM_DATA0_WD: -+ case WSA885X_IRQ_INT_PCM_DATA1_WD: -+ if (irq_idx == WSA885X_IRQ_INT_PCM_DATA0_WD) -+ wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1, -+ WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK); -+ else -+ wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1, -+ WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK); -+ break; -+ case WSA885X_IRQ_INT_PA0_FSM_ERR: -+ case WSA885X_IRQ_INT_PA1_FSM_ERR: -+ case WSA885X_IRQ_INT_MAIN_FSM_ERR: -+ if (irq_idx == WSA885X_IRQ_INT_MAIN_FSM_ERR) { -+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_DIG_CTRL0_POWER_FSM_CTL0, -+ WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK); -+ } else if (irq_idx == WSA885X_IRQ_INT_PA0_FSM_ERR) { -+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA0_FSM_CTL0, -+ WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK); -+ } else if (irq_idx == WSA885X_IRQ_INT_PA1_FSM_ERR) { -+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA1_FSM_CTL0, -+ WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK); -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t wsa885x_interrupt_handler(int irq, void *data) -+{ -+ static const unsigned int status_reg[WSA885X_NUM_REGS] = { -+ WSA885X_INTR_STATUS0, -+ WSA885X_INTR_STATUS0 + 1, -+ WSA885X_INTR_STATUS0 + 2, -+ }; -+ static const unsigned int clear_reg[WSA885X_NUM_REGS] = { -+ WSA885X_INTR_CLEAR0, -+ WSA885X_INTR_CLEAR0 + 1, -+ WSA885X_INTR_CLEAR0 + 2, -+ }; -+ unsigned int status[WSA885X_NUM_REGS] = { 0 }; -+ struct wsa885x_priv *wsa885x = data; -+ irqreturn_t handled = IRQ_NONE; -+ irqreturn_t irq_ret; -+ int i, bit, ret, irq_num; -+ -+ for (i = 0; i < WSA885X_NUM_REGS; i++) { -+ ret = regmap_read(wsa885x->regmap, status_reg[i], &status[i]); -+ if (ret) { -+ dev_err(wsa885x->dev, -+ "Failed to read status_reg[%d] (0x%x): %d\n", -+ i, status_reg[i], ret); -+ status[i] = 0; -+ continue; -+ } -+ } -+ -+ for (i = 0; i < WSA885X_NUM_REGS; i++) { -+ for (bit = 0; bit < 8; bit++) { -+ if (status[i] & BIT(bit)) { -+ irq_num = i * 8 + bit; -+ regmap_write(wsa885x->regmap, clear_reg[i], BIT(bit)); -+ regmap_write(wsa885x->regmap, clear_reg[i], 0); -+ if (irq_num >= WSA885X_IRQ_MAX) { -+ dev_warn_ratelimited(wsa885x->dev, -+ "Unexpected IRQ bit %d (reg %d)\n", -+ bit, i); -+ handled = IRQ_HANDLED; -+ continue; -+ } -+ irq_ret = wsa885x_handle_irq(irq_num, wsa885x); -+ if (irq_ret == IRQ_HANDLED) -+ handled = IRQ_HANDLED; -+ } -+ } -+ } -+ return handled; -+} -+ -+static int wsa885x_register_irq(struct wsa885x_priv *wsa885x) -+{ -+ if (!wsa885x->client->irq) -+ return dev_err_probe(wsa885x->dev, -EINVAL, -+ "IRQ is not configured\n"); -+ -+ return devm_request_threaded_irq(wsa885x->dev, wsa885x->client->irq, NULL, -+ wsa885x_interrupt_handler, -+ IRQF_ONESHOT, -+ dev_name(wsa885x->dev), wsa885x); -+} -+ -+static int wsa885x_probe(struct i2c_client *client) -+{ -+ struct wsa885x_priv *wsa885x; -+ const struct snd_soc_component_driver *component_driver = &wsa885x_component; -+ const char *battery_config; -+ unsigned int i; -+ int ret; -+ struct device *dev = &client->dev; -+ -+ wsa885x = devm_kzalloc(dev, sizeof(*wsa885x), GFP_KERNEL); -+ if (!wsa885x) -+ return -ENOMEM; -+ -+ wsa885x->client = client; -+ wsa885x->dev = dev; -+ wsa885x->stereo_vol_db = -84; -+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO; -+ mutex_init(&wsa885x->state_lock); -+ wsa885x->regmap = devm_regmap_init_i2c(client, &wsa885x_regmap_cfg); -+ -+ if (IS_ERR(wsa885x->regmap)) -+ return PTR_ERR(wsa885x->regmap); -+ -+ ret = device_property_read_string(dev, "qcom,battery-config", -+ &battery_config); -+ if (ret) { -+ wsa885x->batt_conf = WSA885X_BATT_1S; -+ } else if (!strcmp(battery_config, "1s")) { -+ wsa885x->batt_conf = WSA885X_BATT_1S; -+ } else if (!strcmp(battery_config, "2s")) { -+ wsa885x->batt_conf = WSA885X_BATT_2S; -+ } else { -+ return dev_err_probe(dev, -EINVAL, -+ "Invalid battery config %s (expected 1s or 2s)\n", -+ battery_config); -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(wsa885x_supply_name); i++) { -+ ret = devm_regulator_get_enable(dev, wsa885x_supply_name[i]); -+ if (ret) -+ return dev_err_probe(dev, ret, -+ "Failed to enable regulator %s\n", -+ wsa885x_supply_name[i]); -+ } -+ -+ ret = wsa885x_get_reset(dev, wsa885x); -+ if (ret) -+ return ret; -+ -+ wsa885x_reset_deassert(wsa885x); -+ usleep_range(5000, 5500); -+ -+ ret = devm_add_action_or_reset(dev, wsa885x_reset_assert, wsa885x); -+ if (ret) -+ return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n"); -+ -+ i2c_set_clientdata(client, wsa885x); -+ -+ ret = wsa885x_register_irq(wsa885x); -+ if (ret) -+ return dev_err_probe(dev, ret, "wsa885x irq registration failed\n"); -+ -+ ret = devm_snd_soc_register_component(dev, component_driver, -+ wsa885x_dai, -+ ARRAY_SIZE(wsa885x_dai)); -+ if (ret) -+ return dev_err_probe(dev, ret, "Codec component registration failed\n"); -+ -+ return 0; -+} -+ -+static const struct of_device_id wsa885x_dt_match[] = { -+ { -+ .compatible = "qcom,wsa8855", -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, wsa885x_dt_match); -+ -+static const struct i2c_device_id wsa885x_id[] = { -+ { -+ .name = "wsa885x", -+ .driver_data = 0, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, wsa885x_id); -+ -+static struct i2c_driver wsa885x_driver = { -+ .driver = { -+ .name = "wsa885x", -+ .of_match_table = wsa885x_dt_match, -+ }, -+ .probe = wsa885x_probe, -+ .id_table = wsa885x_id, -+}; -+ -+module_i2c_driver(wsa885x_driver); -+ -+MODULE_DESCRIPTION("ASoC WSA885X Stereo Smart PA Codec Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c ---- a/sound/soc/codecs/zl38060.c -+++ b/sound/soc/codecs/zl38060.c -@@ -162,7 +162,7 @@ static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data) - static int zl38_load_firmware(struct device *dev, struct regmap *regmap) - { - const struct ihex_binrec *rec; -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - u32 addr; - u16 len; - int err; -@@ -180,7 +180,7 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap) - return err; - err = zl38_fw_enter_boot_mode(regmap); - if (err) -- goto out; -+ return err; - rec = (const struct ihex_binrec *)fw->data; - while (rec) { - addr = be32_to_cpu(rec->addr); -@@ -195,15 +195,12 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap) - err = -EINVAL; - } - if (err) -- goto out; -+ return err; - /* next ! */ - rec = ihex_next_binrec(rec); - } -- err = zl38_fw_go(regmap); - --out: -- release_firmware(fw); -- return err; -+ return zl38_fw_go(regmap); - } - - -diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c ---- a/sound/soc/dwc/dwc-i2s.c -+++ b/sound/soc/dwc/dwc-i2s.c -@@ -955,7 +955,9 @@ static int dw_i2s_probe(struct platform_device *pdev) - } - - irq = platform_get_irq_optional(pdev, 0); -- if (irq >= 0) { -+ if (irq == -EPROBE_DEFER) -+ return irq; -+ if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0, - pdev->name, dev); - if (ret < 0) { -diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c ---- a/sound/soc/fsl/fsl-asoc-card.c -+++ b/sound/soc/fsl/fsl-asoc-card.c -@@ -69,7 +69,6 @@ static const struct snd_pcm_hw_constraint_list cs42888_channel_constraints = { - - /** - * struct codec_priv - CODEC private data -- * @mclk: Main clock of the CODEC - * @mclk_freq: Clock rate of MCLK - * @free_freq: Clock rate of MCLK for hw_free() - * @mclk_id: MCLK (or main clock) id for set_sysclk() -@@ -80,7 +79,6 @@ static const struct snd_pcm_hw_constraint_list cs42888_channel_constraints = { - * to stay within PLL frequency limits - */ - struct codec_priv { -- struct clk *mclk; - unsigned long mclk_freq; - unsigned long free_freq; - u32 mclk_id; -@@ -109,12 +107,58 @@ struct cpu_priv { - u32 slot_num; - }; - -+struct fsl_asoc_card_priv; -+ -+/* -+ * struct fsl_asoc_card_pdata - per-compatible static card description -+ * @sysclk_dir: initial CPU SYSCLK direction override (0 = leave default IN) -+ * @sysclk_ratio: SYSCLK ratio on sample rate (0 = not used) -+ * @slot_width: TDM slot width (0 = not TDM) -+ * @codec_dai_name: name of the codec DAI -+ * @codec_mclk_id: MCLK id passed to set_sysclk() for the codec -+ * @codec_fll_id: FLL id; only valid when has_pll is true -+ * @codec_pll_id: PLL id; only valid when has_pll is true -+ * @codec_pll_ratio_s24: PLL output ratio for S24_LE -+ * @has_pll: codec uses PLL/FLL; codec_fll_id and codec_pll_id are valid -+ * @dai_fmt: DAI format flags -+ * @playback_only: restrict card to playback direction -+ * @capture_only: restrict card to capture direction -+ * @dapm_routes: DAPM route table override -+ * @num_dapm_routes: number of entries in dapm_routes -+ * @exclude_format: PCM format bitmask excluded (for SAI + WM8960/WM8962) -+ * @codec_init: codec-specific init run after mclk_freq is populated -+ * @probe_init: optional DT-driven init run at end of probe() (e.g. SPDIF codec discovery) -+ */ -+struct fsl_asoc_card_pdata { -+ u32 sysclk_dir[2]; -+ u32 sysclk_ratio[2]; -+ u32 slot_width; -+ const char *codec_dai_name; -+ u32 codec_mclk_id; -+ int codec_fll_id; -+ int codec_pll_id; -+ int codec_pll_ratio_s24; -+ bool has_pll; -+ bool playback_only; -+ bool capture_only; -+ u32 dai_fmt; -+ const struct snd_soc_dapm_route *dapm_routes; -+ int num_dapm_routes; -+ u64 exclude_format; -+ int (*codec_init)(struct fsl_asoc_card_priv *priv); -+ int (*probe_init)(struct device_node *codec_np[], -+ struct device_node *cpu_np, -+ const char *codec_dai_name[], -+ struct fsl_asoc_card_priv *priv); -+}; -+ - /** - * struct fsl_asoc_card_priv - Freescale Generic ASOC card private data - * @dai_link: DAI link structure including normal one and DPCM link - * @hp_jack: Headphone Jack structure - * @mic_jack: Microphone Jack structure - * @pdev: platform device pointer -+ * @pdata: pointer to the per-compatible card platform data - * @codec_priv: CODEC private data - * @cpu_priv: CPU private data - * @card: ASoC card structure -@@ -135,6 +179,7 @@ struct fsl_asoc_card_priv { - struct simple_util_jack hp_jack; - struct simple_util_jack mic_jack; - struct platform_device *pdev; -+ const struct fsl_asoc_card_pdata *pdata; - struct codec_priv codec_priv[2]; - struct cpu_priv cpu_priv; - struct snd_soc_card card; -@@ -609,6 +654,192 @@ static int fsl_asoc_card_spdif_init(struct device_node *codec_np[], - return 0; - } - -+static int fsl_asoc_card_cs42888_codec_init(struct fsl_asoc_card_priv *priv) -+{ -+ unsigned long mclk_freq = priv->codec_priv[0].mclk_freq; -+ -+ /* -+ * Set CPU sysclk frequency from codec MCLK only if not already -+ * set by the CPU DAI init (e.g. ESAI extal clock takes precedence). -+ */ -+ if (!priv->cpu_priv.sysclk_freq[TX]) -+ priv->cpu_priv.sysclk_freq[TX] = mclk_freq; -+ if (!priv->cpu_priv.sysclk_freq[RX]) -+ priv->cpu_priv.sysclk_freq[RX] = mclk_freq; -+ -+ priv->constraint_channels = &cs42888_channel_constraints; -+ if (mclk_freq % 12288000 == 0) -+ priv->constraint_rates = &cs42888_rate_48k_constraints; -+ else if (mclk_freq % 11289600 == 0) -+ priv->constraint_rates = &cs42888_rate_44k_constraints; -+ else -+ dev_warn(&priv->pdev->dev, -+ "Unknown MCLK frequency %lu, no rate constraints\n", -+ mclk_freq); -+ -+ return 0; -+} -+ -+static int fsl_asoc_card_wm8958_codec_init(struct fsl_asoc_card_priv *priv) -+{ -+ priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq; -+ return 0; -+} -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_cs42888_pdata = { -+ .codec_dai_name = "cs42888", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC, -+ .sysclk_dir = { SND_SOC_CLOCK_OUT, SND_SOC_CLOCK_OUT }, -+ .slot_width = 32, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+ .codec_init = fsl_asoc_card_cs42888_codec_init, -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_cs427x_pdata = { -+ .codec_dai_name = "cs4271-hifi", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .codec_mclk_id = CS427x_SYSCLK_MCLK, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_sgtl5000_pdata = { -+ .codec_dai_name = "sgtl5000", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .codec_mclk_id = SGTL5000_SYSCLK, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_tlv320aic32x4_pdata = { -+ .codec_dai_name = "tlv320aic32x4-hifi", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_tlv320aic31xx_pdata = { -+ .codec_dai_name = "tlv320dac31xx-hifi", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC, -+ .sysclk_dir = { SND_SOC_CLOCK_OUT, SND_SOC_CLOCK_OUT }, -+ .playback_only = true, -+ .dapm_routes = audio_map_tx, -+ .num_dapm_routes = ARRAY_SIZE(audio_map_tx), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_wm8962_pdata = { -+ .codec_dai_name = "wm8962", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .codec_mclk_id = WM8962_SYSCLK_MCLK, -+ .has_pll = true, -+ .codec_fll_id = WM8962_SYSCLK_FLL, -+ .codec_pll_id = WM8962_FLL, -+ /* -+ * WM8962 has same BCLK generation limitations as WM8960. -+ * See WM8960 section for detailed explanation. -+ */ -+ .exclude_format = SNDRV_PCM_FMTBIT_S20_3LE, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_wm8960_pdata = { -+ .codec_dai_name = "wm8960-hifi", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .has_pll = true, -+ .codec_fll_id = WM8960_SYSCLK_AUTO, -+ .codec_pll_id = WM8960_SYSCLK_AUTO, -+ /* -+ * WM8960 in master mode cannot generate exact 1.92 MHz BCLK -+ * required for S20_3LE (48kHz x 2ch x 20bit). Closest available -+ * is 2.048 MHz (SYSCLK/6), which causes right channel corruption. -+ * -+ * In SAI master mode, SAI derive BCLK from MCLK using integer -+ * dividers only. S20_3LE requires non-integer divider ratios -+ * with standard MCLK frequencies. For example, 48kHz stereo -+ * needs 1.920 MHz BCLK, which requires a divider of 6.4 from -+ * 12.288 MHz MCLK (not an integer). -+ */ -+ .exclude_format = SNDRV_PCM_FMTBIT_S20_3LE, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_ac97_pdata = { -+ .codec_dai_name = "ac97-hifi", -+ .dai_fmt = SND_SOC_DAIFMT_AC97, -+ .dapm_routes = audio_map_ac97, -+ .num_dapm_routes = ARRAY_SIZE(audio_map_ac97), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_mqs_pdata = { -+ .codec_dai_name = "fsl-mqs-dai", -+ .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC | -+ SND_SOC_DAIFMT_NB_NF, -+ .playback_only = true, -+ .dapm_routes = audio_map_tx, -+ .num_dapm_routes = ARRAY_SIZE(audio_map_tx), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_wm8524_pdata = { -+ .codec_dai_name = "wm8524-hifi", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC, -+ /* RX=0, TX=1: set TX (index 1) to CLOCK_OUT, RX stays at default IN */ -+ .sysclk_dir = { 0, SND_SOC_CLOCK_OUT }, -+ .sysclk_ratio = { 0, 256 }, -+ .slot_width = 32, -+ .playback_only = true, -+ .dapm_routes = audio_map_tx, -+ .num_dapm_routes = ARRAY_SIZE(audio_map_tx), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_si476x_pdata = { -+ .codec_dai_name = "si476x-codec", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC, -+ .dapm_routes = audio_map_rx, -+ .num_dapm_routes = ARRAY_SIZE(audio_map_rx), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_wm8958_pdata = { -+ .codec_dai_name = "wm8994-aif1", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .codec_mclk_id = WM8994_FLL_SRC_MCLK1, -+ .has_pll = true, -+ .codec_fll_id = WM8994_SYSCLK_FLL1, -+ .codec_pll_id = WM8994_FLL1, -+ .codec_init = fsl_asoc_card_wm8958_codec_init, -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_nau8822_pdata = { -+ .codec_dai_name = "nau8822-hifi", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .codec_mclk_id = NAU8822_CLK_MCLK, -+ .has_pll = true, -+ .codec_fll_id = NAU8822_CLK_PLL, -+ .codec_pll_id = NAU8822_CLK_PLL, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_wm8904_pdata = { -+ .codec_dai_name = "wm8904-hifi", -+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP, -+ .codec_mclk_id = WM8904_FLL_MCLK, -+ .has_pll = true, -+ .codec_fll_id = WM8904_CLK_FLL, -+ .codec_pll_id = WM8904_FLL_MCLK, -+ .codec_pll_ratio_s24 = 192, -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static const struct fsl_asoc_card_pdata fsl_asoc_spdif_pdata = { -+ .codec_dai_name = "spdif", -+ .dai_fmt = DAI_FMT_BASE, -+ .probe_init = fsl_asoc_card_spdif_init, -+}; -+ - static int hp_jack_event(struct notifier_block *nb, unsigned long event, - void *data) - { -@@ -643,17 +874,173 @@ static struct notifier_block mic_jack_nb = { - .notifier_call = mic_jack_event, - }; - --static int fsl_asoc_card_late_probe(struct snd_soc_card *card) -+/* -+ * fsl_asoc_card_init_cpu - configure CPU DAI-specific settings. -+ * -+ * Called from late_probe() when the CPU DAI component is guaranteed bound. -+ */ -+static int fsl_asoc_card_init_cpu(struct snd_soc_card *card, -+ struct snd_soc_pcm_runtime *rtd) - { - struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); -- struct snd_soc_pcm_runtime *rtd = list_first_entry( -- &card->rtd_list, struct snd_soc_pcm_runtime, list); -+ struct device_node *np = priv->pdev->dev.of_node; -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); -+ const char *comp_drv_name = cpu_dai->component->driver->name; -+ struct device *dev = card->dev; -+ int ret; -+ -+ if (!strcmp(comp_drv_name, "fsl-ssi")) { -+ /* Only SSI needs to configure AUDMUX */ -+ ret = fsl_asoc_card_audmux_init(np, priv); -+ if (ret) { -+ dev_err(dev, "failed to init audmux\n"); -+ return ret; -+ } -+ } else if (!strcmp(comp_drv_name, "fsl-esai")) { -+ struct clk *esai_clk = clk_get(cpu_dai->dev, "extal"); -+ -+ if (!IS_ERR(esai_clk)) { -+ priv->cpu_priv.sysclk_freq[TX] = clk_get_rate(esai_clk); -+ priv->cpu_priv.sysclk_freq[RX] = clk_get_rate(esai_clk); -+ clk_put(esai_clk); -+ } else { -+ dev_warn(dev, "failed to get ESAI extal clock: %ld\n", PTR_ERR(esai_clk)); -+ } -+ -+ priv->cpu_priv.sysclk_id[TX] = ESAI_HCKT_EXTAL; -+ priv->cpu_priv.sysclk_id[RX] = ESAI_HCKR_EXTAL; -+ } else if (!strcmp(comp_drv_name, "fsl-sai")) { -+ priv->cpu_priv.sysclk_id[TX] = FSL_SAI_CLK_MAST1; -+ priv->cpu_priv.sysclk_id[RX] = FSL_SAI_CLK_MAST1; -+ -+ if (priv->pdata->exclude_format) -+ priv->exclude_format = priv->pdata->exclude_format; -+ } -+ -+ return 0; -+} -+ -+/* -+ * fsl_asoc_card_init_codecs - read codec MCLK rates and set codec sysclk. -+ * -+ * Called from late_probe() after all components are bound. -+ */ -+static int fsl_asoc_card_init_codecs(struct snd_soc_card *card, -+ struct snd_soc_pcm_runtime *rtd) -+{ -+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); -+ const struct fsl_asoc_card_pdata *pdata = priv->pdata; - struct snd_soc_dai *codec_dai; - struct codec_priv *codec_priv; - struct device *dev = card->dev; - int codec_idx; - int ret; - -+ /* Read MCLK rate from each bound codec component */ -+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) { -+ struct clk *codec_clk = clk_get(codec_dai->component->dev, NULL); -+ -+ codec_priv = &priv->codec_priv[codec_idx]; -+ if (!IS_ERR(codec_clk)) { -+ codec_priv->mclk_freq = clk_get_rate(codec_clk); -+ clk_put(codec_clk); -+ } -+ } -+ -+ if (pdata->codec_init) { -+ ret = pdata->codec_init(priv); -+ if (ret) -+ return ret; -+ } -+ -+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) { -+ codec_priv = &priv->codec_priv[codec_idx]; -+ -+ ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, -+ codec_priv->mclk_freq, SND_SOC_CLOCK_IN); -+ if (ret && ret != -ENOTSUPP) { -+ dev_err(dev, "failed to set sysclk in %s\n", __func__); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static void fsl_asoc_card_free_jack(struct snd_soc_card *card) -+{ -+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); -+ -+ if (priv->hp_jack.gpio.desc) { -+ snd_soc_jack_notifier_unregister(&priv->hp_jack.jack, &hp_jack_nb); -+ snd_soc_jack_free_gpios(&priv->hp_jack.jack, 1, &priv->hp_jack.gpio); -+ priv->hp_jack.gpio.desc = NULL; -+ } -+ -+ if (priv->mic_jack.gpio.desc) { -+ snd_soc_jack_notifier_unregister(&priv->mic_jack.jack, &mic_jack_nb); -+ snd_soc_jack_free_gpios(&priv->mic_jack.jack, 1, &priv->mic_jack.gpio); -+ priv->mic_jack.gpio.desc = NULL; -+ } -+} -+ -+/* -+ * fsl_asoc_card_init_jack - register optional headphone and mic jacks. -+ * -+ * Called from late_probe() once per card bind cycle. -+ */ -+static int fsl_asoc_card_init_jack(struct snd_soc_card *card) -+{ -+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); -+ struct device_node *np = priv->pdev->dev.of_node; -+ int ret; -+ -+ /* -+ * Properties "hp-det-gpios" and "mic-det-gpios" are optional. -+ * simple_util_init_jack() checks for the GPIO property and -+ * does nothing if it is absent. -+ */ -+ if (of_property_present(np, "hp-det-gpios") || -+ of_property_present(np, "hp-det-gpio") /* deprecated */) { -+ ret = simple_util_init_jack(card, &priv->hp_jack, -+ 1, NULL, "Headphone Jack"); -+ if (ret) -+ return ret; -+ -+ snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb); -+ } -+ -+ if (of_property_present(np, "mic-det-gpios") || -+ of_property_present(np, "mic-det-gpio") /* deprecated */) { -+ ret = simple_util_init_jack(card, &priv->mic_jack, -+ 0, NULL, "Mic Jack"); -+ if (ret) -+ return ret; -+ -+ snd_soc_jack_notifier_register(&priv->mic_jack.jack, &mic_jack_nb); -+ } -+ -+ return 0; -+} -+ -+static int fsl_asoc_card_late_probe(struct snd_soc_card *card) -+{ -+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); -+ struct snd_soc_pcm_runtime *rtd; -+ int ret; -+ -+ /* Use the first rtd which carries the CPU+codec DAIs */ -+ rtd = list_first_entry(&card->rtd_list, -+ struct snd_soc_pcm_runtime, list); -+ -+ ret = fsl_asoc_card_init_jack(card); -+ if (ret) -+ goto jack_fail; -+ -+ ret = fsl_asoc_card_init_cpu(card, rtd); -+ if (ret) -+ goto jack_fail; -+ - if (fsl_asoc_card_is_ac97(priv)) { - #if IS_ENABLED(CONFIG_SND_AC97_CODEC) - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; -@@ -671,19 +1058,20 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card) - return 0; - } - -- for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) { -- codec_priv = &priv->codec_priv[codec_idx]; -+ ret = fsl_asoc_card_init_codecs(card, rtd); -+ if (ret) -+ goto jack_fail; - -- ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, -- codec_priv->mclk_freq, SND_SOC_CLOCK_IN); -- if (ret && ret != -ENOTSUPP) { -- dev_err(dev, "failed to set sysclk in %s\n", __func__); -- return ret; -- } -+ return 0; - -- if (!IS_ERR_OR_NULL(codec_priv->mclk)) -- clk_prepare_enable(codec_priv->mclk); -- } -+jack_fail: -+ fsl_asoc_card_free_jack(card); -+ return ret; -+} -+ -+static int fsl_asoc_card_card_remove(struct snd_soc_card *card) -+{ -+ fsl_asoc_card_free_jack(card); - - return 0; - } -@@ -697,12 +1085,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - struct platform_device *asrc_pdev = NULL; - struct device_node *bitclkprovider = NULL; - struct device_node *frameprovider = NULL; -- struct platform_device *cpu_pdev; - struct fsl_asoc_card_priv *priv; -- struct device *codec_dev[2] = { NULL, NULL }; -+ const struct fsl_asoc_card_pdata *pdata; - struct snd_soc_dai_link_component *dlc; -- const char *codec_dai_name[2]; -- const char *codec_dev_name[2]; -+ const char *codec_dai_name[2] = { NULL, NULL }; - u32 asrc_fmt = 0; - int codec_idx; - u32 width; -@@ -714,6 +1100,13 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - - priv->pdev = pdev; - -+ pdata = of_device_get_match_data(&pdev->dev); -+ if (!pdata) { -+ dev_err(&pdev->dev, "unknown Device Tree compatible\n"); -+ return -EINVAL; -+ } -+ priv->pdata = pdata; -+ - cpu_np = of_parse_phandle(np, "audio-cpu", 0); - /* Give a chance to old DT bindings */ - if (!cpu_np) -@@ -726,52 +1119,13 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - goto fail; - } - -- cpu_pdev = of_find_device_by_node(cpu_np); -- if (!cpu_pdev) { -- ret = dev_err_probe(&pdev->dev, -EPROBE_DEFER, -- "failed to find CPU DAI device\n"); -- goto fail; -- } -- - codec_np[0] = of_parse_phandle(np, "audio-codec", 0); - codec_np[1] = of_parse_phandle(np, "audio-codec", 1); - -- for (codec_idx = 0; codec_idx < 2; codec_idx++) { -- if (codec_np[codec_idx]) { -- struct platform_device *codec_pdev; -- struct i2c_client *codec_i2c; -- -- codec_i2c = of_find_i2c_device_by_node(codec_np[codec_idx]); -- if (codec_i2c) { -- codec_dev[codec_idx] = &codec_i2c->dev; -- codec_dev_name[codec_idx] = codec_i2c->name; -- } -- if (!codec_dev[codec_idx]) { -- codec_pdev = of_find_device_by_node(codec_np[codec_idx]); -- if (codec_pdev) { -- codec_dev[codec_idx] = &codec_pdev->dev; -- codec_dev_name[codec_idx] = codec_pdev->name; -- } -- } -- } -- } -- - asrc_np = of_parse_phandle(np, "audio-asrc", 0); - if (asrc_np) - asrc_pdev = of_find_device_by_node(asrc_np); - -- /* Get the MCLK rate only, and leave it controlled by CODEC drivers */ -- for (codec_idx = 0; codec_idx < 2; codec_idx++) { -- if (codec_dev[codec_idx]) { -- struct clk *codec_clk = clk_get(codec_dev[codec_idx], NULL); -- -- if (!IS_ERR(codec_clk)) { -- priv->codec_priv[codec_idx].mclk_freq = clk_get_rate(codec_clk); -- clk_put(codec_clk); -- } -- } -- } -- - /* Default sample rate and format, will be updated in hw_params() */ - priv->sample_rate = 44100; - priv->sample_format = SNDRV_PCM_FORMAT_S16_LE; -@@ -823,133 +1177,40 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - } - - /* Diversify the card configurations */ -- if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) { -- codec_dai_name[0] = "cs42888"; -- priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv[0].mclk_freq; -- priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv[0].mclk_freq; -- priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; -- priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; -- priv->cpu_priv.slot_width = 32; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; -- priv->constraint_channels = &cs42888_channel_constraints; -- if (priv->codec_priv[0].mclk_freq % 12288000 == 0) -- priv->constraint_rates = &cs42888_rate_48k_constraints; -- else if (priv->codec_priv[0].mclk_freq % 11289600 == 0) -- priv->constraint_rates = &cs42888_rate_44k_constraints; -- else -- dev_warn(&pdev->dev, "Unknown MCLK frequency %lu, no rate constraints\n", -- priv->codec_priv[0].mclk_freq); -- } else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) { -- codec_dai_name[0] = "cs4271-hifi"; -- priv->codec_priv[0].mclk_id = CS427x_SYSCLK_MCLK; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { -- codec_dai_name[0] = "sgtl5000"; -- priv->codec_priv[0].mclk_id = SGTL5000_SYSCLK; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) { -- codec_dai_name[0] = "tlv320aic32x4-hifi"; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) { -- codec_dai_name[0] = "tlv320dac31xx-hifi"; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; -+ priv->cpu_priv.sysclk_dir[TX] = pdata->sysclk_dir[TX]; -+ priv->cpu_priv.sysclk_dir[RX] = pdata->sysclk_dir[RX]; -+ priv->cpu_priv.sysclk_ratio[TX] = pdata->sysclk_ratio[TX]; -+ priv->cpu_priv.sysclk_ratio[RX] = pdata->sysclk_ratio[RX]; -+ priv->cpu_priv.slot_width = pdata->slot_width; -+ -+ codec_dai_name[0] = pdata->codec_dai_name; -+ priv->codec_priv[0].mclk_id = pdata->codec_mclk_id; -+ if (pdata->has_pll) { -+ priv->codec_priv[0].fll_id = pdata->codec_fll_id; -+ priv->codec_priv[0].pll_id = pdata->codec_pll_id; -+ } -+ if (pdata->codec_pll_ratio_s24) -+ priv->codec_priv[0].pll_ratio_s24 = pdata->codec_pll_ratio_s24; -+ -+ if (pdata->playback_only) { - priv->dai_link[1].playback_only = 1; - priv->dai_link[2].playback_only = 1; -- priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; -- priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; -- priv->card.dapm_routes = audio_map_tx; -- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); -- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { -- codec_dai_name[0] = "wm8962"; -- priv->codec_priv[0].mclk_id = WM8962_SYSCLK_MCLK; -- priv->codec_priv[0].fll_id = WM8962_SYSCLK_FLL; -- priv->codec_priv[0].pll_id = WM8962_FLL; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- /* -- * WM8962 has same BCLK generation limitations as WM8960. -- * See WM8960 section for detailed explanation. -- */ -- if (of_node_name_eq(cpu_np, "sai")) -- priv->exclude_format = SNDRV_PCM_FMTBIT_S20_3LE; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) { -- codec_dai_name[0] = "wm8960-hifi"; -- priv->codec_priv[0].fll_id = WM8960_SYSCLK_AUTO; -- priv->codec_priv[0].pll_id = WM8960_SYSCLK_AUTO; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- /* -- * WM8960 in master mode cannot generate exact 1.92 MHz BCLK -- * required for S20_3LE (48kHz × 2ch × 20bit). Closest available -- * is 2.048 MHz (SYSCLK/6), which causes right channel corruption. -- * -- * In SAI master mode, SAI derive BCLK from MCLK using integer -- * dividers only. S20_3LE requires non-integer divider ratios -- * with standard MCLK frequencies. For example, 48kHz stereo -- * needs 1.920 MHz BCLK, which requires a divider of 6.4 from -- * 12.288 MHz MCLK (not an integer). -- */ -- if (of_node_name_eq(cpu_np, "sai")) -- priv->exclude_format = SNDRV_PCM_FMTBIT_S20_3LE; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) { -- codec_dai_name[0] = "ac97-hifi"; -- priv->dai_fmt = SND_SOC_DAIFMT_AC97; -- priv->card.dapm_routes = audio_map_ac97; -- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97); -- } else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) { -- codec_dai_name[0] = "fsl-mqs-dai"; -- priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J | -- SND_SOC_DAIFMT_CBC_CFC | -- SND_SOC_DAIFMT_NB_NF; -- priv->dai_link[1].playback_only = 1; -- priv->dai_link[2].playback_only = 1; -- priv->card.dapm_routes = audio_map_tx; -- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); -- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) { -- codec_dai_name[0] = "wm8524-hifi"; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; -- priv->dai_link[1].playback_only = 1; -- priv->dai_link[2].playback_only = 1; -- priv->cpu_priv.slot_width = 32; -- priv->card.dapm_routes = audio_map_tx; -- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); -- priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; -- priv->cpu_priv.sysclk_ratio[TX] = 256; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) { -- codec_dai_name[0] = "si476x-codec"; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; -- priv->card.dapm_routes = audio_map_rx; -- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); -- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) { -- codec_dai_name[0] = "wm8994-aif1"; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- priv->codec_priv[0].mclk_id = WM8994_FLL_SRC_MCLK1; -- priv->codec_priv[0].fll_id = WM8994_SYSCLK_FLL1; -- priv->codec_priv[0].pll_id = WM8994_FLL1; -- priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq; -- priv->card.dapm_routes = NULL; -- priv->card.num_dapm_routes = 0; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-nau8822")) { -- codec_dai_name[0] = "nau8822-hifi"; -- priv->codec_priv[0].mclk_id = NAU8822_CLK_MCLK; -- priv->codec_priv[0].fll_id = NAU8822_CLK_PLL; -- priv->codec_priv[0].pll_id = NAU8822_CLK_PLL; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- if (codec_dev[0]) -- priv->codec_priv[0].mclk = devm_clk_get(codec_dev[0], NULL); -- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) { -- codec_dai_name[0] = "wm8904-hifi"; -- priv->codec_priv[0].mclk_id = WM8904_FLL_MCLK; -- priv->codec_priv[0].fll_id = WM8904_CLK_FLL; -- priv->codec_priv[0].pll_id = WM8904_FLL_MCLK; -- priv->codec_priv[0].pll_ratio_s24 = 192; -- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; -- } else if (of_device_is_compatible(np, "fsl,imx-audio-spdif")) { -- ret = fsl_asoc_card_spdif_init(codec_np, cpu_np, codec_dai_name, priv); -+ } -+ if (pdata->capture_only) { -+ priv->dai_link[1].capture_only = 1; -+ priv->dai_link[2].capture_only = 1; -+ } -+ -+ priv->dai_fmt = pdata->dai_fmt; -+ -+ priv->card.dapm_routes = pdata->dapm_routes; -+ priv->card.num_dapm_routes = pdata->num_dapm_routes; -+ -+ if (pdata->probe_init) { -+ ret = pdata->probe_init(codec_np, cpu_np, -+ codec_dai_name, priv); - if (ret) - goto asrc_fail; -- } else { -- dev_err(&pdev->dev, "unknown Device Tree compatible\n"); -- ret = -EINVAL; -- goto asrc_fail; - } - - /* -@@ -995,51 +1256,21 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - of_node_put(bitclkprovider); - of_node_put(frameprovider); - -- if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0] -- && codec_dai_name[0] != snd_soc_dummy_dlc.dai_name) { -- dev_dbg(&pdev->dev, "failed to find codec device\n"); -- ret = -EPROBE_DEFER; -- goto asrc_fail; -- } -- -- /* Common settings for corresponding Freescale CPU DAI driver */ -- if (of_node_name_eq(cpu_np, "ssi")) { -- /* Only SSI needs to configure AUDMUX */ -- ret = fsl_asoc_card_audmux_init(np, priv); -- if (ret) { -- dev_err(&pdev->dev, "failed to init audmux\n"); -- goto asrc_fail; -- } -- } else if (of_node_name_eq(cpu_np, "esai")) { -- struct clk *esai_clk = clk_get(&cpu_pdev->dev, "extal"); -- -- if (!IS_ERR(esai_clk)) { -- priv->cpu_priv.sysclk_freq[TX] = clk_get_rate(esai_clk); -- priv->cpu_priv.sysclk_freq[RX] = clk_get_rate(esai_clk); -- clk_put(esai_clk); -- } else if (PTR_ERR(esai_clk) == -EPROBE_DEFER) { -- ret = -EPROBE_DEFER; -- goto asrc_fail; -- } -- -- priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; -- priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; -- } else if (of_node_name_eq(cpu_np, "sai")) { -- priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; -- priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; -- } -- - /* Initialize sound card */ - priv->card.dev = &pdev->dev; - priv->card.owner = THIS_MODULE; - ret = snd_soc_of_parse_card_name(&priv->card, "model"); - if (ret) { -- snprintf(priv->name, sizeof(priv->name), "%s-audio", -- fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name[0]); -- priv->card.name = priv->name; -+ /* -+ * "model" is required by the DT binding. Enforce it here so -+ * the driver fails with a clear message. -+ */ -+ dev_err(&pdev->dev, "Error parsing card name: %d\n", ret); -+ goto asrc_fail; - } - priv->card.dai_link = priv->dai_link; - priv->card.late_probe = fsl_asoc_card_late_probe; -+ priv->card.remove = fsl_asoc_card_card_remove; - priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; - priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets); - -@@ -1146,39 +1377,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - goto asrc_fail; - } - -- /* -- * Properties "hp-det-gpios" and "mic-det-gpios" are optional, and -- * simple_util_init_jack() uses these properties for creating -- * Headphone Jack and Microphone Jack. -- * -- * The notifier is initialized in snd_soc_card_jack_new(), then -- * snd_soc_jack_notifier_register can be called. -- */ -- if (of_property_present(np, "hp-det-gpios") || -- of_property_present(np, "hp-det-gpio") /* deprecated */) { -- ret = simple_util_init_jack(&priv->card, &priv->hp_jack, -- 1, NULL, "Headphone Jack"); -- if (ret) -- goto asrc_fail; -- -- snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb); -- } -- -- if (of_property_present(np, "mic-det-gpios") || -- of_property_present(np, "mic-det-gpio") /* deprecated */) { -- ret = simple_util_init_jack(&priv->card, &priv->mic_jack, -- 0, NULL, "Mic Jack"); -- if (ret) -- goto asrc_fail; -- -- snd_soc_jack_notifier_register(&priv->mic_jack.jack, &mic_jack_nb); -- } -- - asrc_fail: - of_node_put(asrc_np); - of_node_put(codec_np[0]); - of_node_put(codec_np[1]); -- put_device(&cpu_pdev->dev); - fail: - of_node_put(cpu_np); - -@@ -1186,21 +1388,21 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) - } - - static const struct of_device_id fsl_asoc_card_dt_ids[] = { -- { .compatible = "fsl,imx-audio-ac97", }, -- { .compatible = "fsl,imx-audio-cs42888", }, -- { .compatible = "fsl,imx-audio-cs427x", }, -- { .compatible = "fsl,imx-audio-tlv320aic32x4", }, -- { .compatible = "fsl,imx-audio-tlv320aic31xx", }, -- { .compatible = "fsl,imx-audio-sgtl5000", }, -- { .compatible = "fsl,imx-audio-wm8962", }, -- { .compatible = "fsl,imx-audio-wm8960", }, -- { .compatible = "fsl,imx-audio-mqs", }, -- { .compatible = "fsl,imx-audio-wm8524", }, -- { .compatible = "fsl,imx-audio-si476x", }, -- { .compatible = "fsl,imx-audio-wm8958", }, -- { .compatible = "fsl,imx-audio-nau8822", }, -- { .compatible = "fsl,imx-audio-wm8904", }, -- { .compatible = "fsl,imx-audio-spdif", }, -+ { .compatible = "fsl,imx-audio-ac97", .data = &fsl_asoc_ac97_pdata }, -+ { .compatible = "fsl,imx-audio-cs42888", .data = &fsl_asoc_cs42888_pdata }, -+ { .compatible = "fsl,imx-audio-cs427x", .data = &fsl_asoc_cs427x_pdata }, -+ { .compatible = "fsl,imx-audio-tlv320aic32x4", .data = &fsl_asoc_tlv320aic32x4_pdata }, -+ { .compatible = "fsl,imx-audio-tlv320aic31xx", .data = &fsl_asoc_tlv320aic31xx_pdata }, -+ { .compatible = "fsl,imx-audio-sgtl5000", .data = &fsl_asoc_sgtl5000_pdata }, -+ { .compatible = "fsl,imx-audio-wm8962", .data = &fsl_asoc_wm8962_pdata }, -+ { .compatible = "fsl,imx-audio-wm8960", .data = &fsl_asoc_wm8960_pdata }, -+ { .compatible = "fsl,imx-audio-mqs", .data = &fsl_asoc_mqs_pdata }, -+ { .compatible = "fsl,imx-audio-wm8524", .data = &fsl_asoc_wm8524_pdata }, -+ { .compatible = "fsl,imx-audio-si476x", .data = &fsl_asoc_si476x_pdata }, -+ { .compatible = "fsl,imx-audio-wm8958", .data = &fsl_asoc_wm8958_pdata }, -+ { .compatible = "fsl,imx-audio-nau8822", .data = &fsl_asoc_nau8822_pdata }, -+ { .compatible = "fsl,imx-audio-wm8904", .data = &fsl_asoc_wm8904_pdata }, -+ { .compatible = "fsl,imx-audio-spdif", .data = &fsl_asoc_spdif_pdata }, - {} - }; - MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids); -diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c ---- a/sound/soc/fsl/fsl_asrc.c -+++ b/sound/soc/fsl/fsl_asrc.c -@@ -222,10 +222,9 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) - enum asrc_pair_index index = ASRC_INVALID_PAIR; - struct fsl_asrc *asrc = pair->asrc; - struct device *dev = &asrc->pdev->dev; -- unsigned long lock_flags; - int i, ret = 0; - -- spin_lock_irqsave(&asrc->lock, lock_flags); -+ guard(spinlock_irqsave)(&asrc->lock); - - for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { - if (asrc->pair[i] != NULL) -@@ -250,8 +249,6 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) - pair->index = index; - } - -- spin_unlock_irqrestore(&asrc->lock, lock_flags); -- - return ret; - } - -@@ -265,19 +262,16 @@ static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) - { - struct fsl_asrc *asrc = pair->asrc; - enum asrc_pair_index index = pair->index; -- unsigned long lock_flags; - - /* Make sure the pair is disabled */ - regmap_update_bits(asrc->regmap, REG_ASRCTR, - ASRCTR_ASRCEi_MASK(index), 0); - -- spin_lock_irqsave(&asrc->lock, lock_flags); -+ guard(spinlock_irqsave)(&asrc->lock); - - asrc->channel_avail += pair->channels; - asrc->pair[index] = NULL; - pair->error = 0; -- -- spin_unlock_irqrestore(&asrc->lock, lock_flags); - } - - /** -diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h ---- a/sound/soc/fsl/fsl_asrc.h -+++ b/sound/soc/fsl/fsl_asrc.h -@@ -444,7 +444,7 @@ struct dma_block { - }; - - /** -- * fsl_asrc_soc_data: soc specific data -+ * struct fsl_asrc_soc_data - soc specific data - * - * @use_edma: using edma as dma device or not - * @channel_bits: width of ASRCNCR register for each pair -@@ -457,7 +457,7 @@ struct fsl_asrc_soc_data { - }; - - /** -- * fsl_asrc_pair_priv: ASRC Pair private data -+ * struct fsl_asrc_pair_priv - ASRC Pair private data - * - * @config: configuration profile - */ -@@ -466,7 +466,7 @@ struct fsl_asrc_pair_priv { - }; - - /** -- * fsl_asrc_priv: ASRC private data -+ * struct fsl_asrc_priv - ASRC private data - * - * @asrck_clk: clock sources to driver ASRC internal logic - * @soc: soc specific data -diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c ---- a/sound/soc/fsl/fsl_asrc_dma.c -+++ b/sound/soc/fsl/fsl_asrc_dma.c -@@ -219,7 +219,9 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, - */ - component_be = snd_soc_lookup_component_nolocked(dev_be, SND_DMAENGINE_PCM_DRV_NAME); - if (component_be) { -- be_chan = soc_component_to_pcm(component_be)->chan[substream->stream]; -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component_be); -+ -+ be_chan = pcm->chan[substream->stream]; - tmp_chan = be_chan; - } - if (!tmp_chan) { -diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c ---- a/sound/soc/fsl/fsl_audmix.c -+++ b/sound/soc/fsl/fsl_audmix.c -@@ -286,7 +286,6 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) - { - struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai); -- unsigned long lock_flags; - - /* Capture stream shall not be handled */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -@@ -296,16 +295,14 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -- spin_lock_irqsave(&priv->lock, lock_flags); -- priv->tdms |= BIT(dai->driver->id); -- spin_unlock_irqrestore(&priv->lock, lock_flags); -+ scoped_guard(spinlock_irqsave, &priv->lock) -+ priv->tdms |= BIT(dai->driver->id); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -- spin_lock_irqsave(&priv->lock, lock_flags); -- priv->tdms &= ~BIT(dai->driver->id); -- spin_unlock_irqrestore(&priv->lock, lock_flags); -+ scoped_guard(spinlock_irqsave, &priv->lock) -+ priv->tdms &= ~BIT(dai->driver->id); - break; - default: - return -EINVAL; -diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c ---- a/sound/soc/fsl/fsl_dma.c -+++ b/sound/soc/fsl/fsl_dma.c -@@ -18,8 +18,6 @@ - #include - #include - #include --#include --#include - #include - #include - -@@ -824,9 +822,34 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) - struct device_node *np = pdev->dev.of_node; - struct device_node *ssi_np; - struct resource res; -+ void __iomem *channel; - const uint32_t *iprop; -+ int irq; - int ret; - -+ channel = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(channel)) -+ return PTR_ERR(channel); -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ -+ dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL); -+ if (!dma) -+ return -ENOMEM; -+ -+ dma->dai.name = DRV_NAME; -+ dma->dai.open = fsl_dma_open; -+ dma->dai.close = fsl_dma_close; -+ dma->dai.hw_params = fsl_dma_hw_params; -+ dma->dai.hw_free = fsl_dma_hw_free; -+ dma->dai.pointer = fsl_dma_pointer; -+ dma->dai.pcm_new = fsl_dma_new; -+ -+ dma->channel = channel; -+ dma->irq = irq; -+ - /* Find the SSI node that points to us. */ - ssi_np = find_ssi_node(np); - if (!ssi_np) { -@@ -842,55 +865,19 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) - return ret; - } - -- dma = kzalloc_obj(*dma); -- if (!dma) { -- of_node_put(ssi_np); -- return -ENOMEM; -- } -- -- dma->dai.name = DRV_NAME; -- dma->dai.open = fsl_dma_open; -- dma->dai.close = fsl_dma_close; -- dma->dai.hw_params = fsl_dma_hw_params; -- dma->dai.hw_free = fsl_dma_hw_free; -- dma->dai.pointer = fsl_dma_pointer; -- dma->dai.pcm_new = fsl_dma_new; -- - /* Store the SSI-specific information that we need */ - dma->ssi_stx_phys = res.start + REG_SSI_STX0; - dma->ssi_srx_phys = res.start + REG_SSI_SRX0; - - iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); -+ of_node_put(ssi_np); - if (iprop) - dma->ssi_fifo_depth = be32_to_cpup(iprop); - else - /* Older 8610 DTs didn't have the fifo-depth property */ - dma->ssi_fifo_depth = 8; - -- of_node_put(ssi_np); -- -- ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0); -- if (ret) { -- dev_err(&pdev->dev, "could not register platform\n"); -- kfree(dma); -- return ret; -- } -- -- dma->channel = of_iomap(np, 0); -- dma->irq = irq_of_parse_and_map(np, 0); -- -- dev_set_drvdata(&pdev->dev, dma); -- -- return 0; --} -- --static void fsl_soc_dma_remove(struct platform_device *pdev) --{ -- struct dma_object *dma = dev_get_drvdata(&pdev->dev); -- -- iounmap(dma->channel); -- irq_dispose_mapping(dma->irq); -- kfree(dma); -+ return devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0); - } - - static const struct of_device_id fsl_soc_dma_ids[] = { -@@ -905,7 +892,6 @@ static struct platform_driver fsl_soc_dma_driver = { - .of_match_table = fsl_soc_dma_ids, - }, - .probe = fsl_soc_dma_probe, -- .remove = fsl_soc_dma_remove, - }; - - module_platform_driver(fsl_soc_dma_driver); -diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h ---- a/sound/soc/fsl/fsl_dma.h -+++ b/sound/soc/fsl/fsl_dma.h -@@ -92,7 +92,7 @@ static inline u32 CCSR_DMA_ECLNDAR_ADDR(u64 x) - #define CCSR_DMA_ATR_SNOOP 0x00050000 - #define CCSR_DMA_ATR_ESAD_MASK 0x0000000F - --/** -+/* - * List Descriptor for extended chaining mode DMA operations. - * - * The CLSDAR register points to the first (in a linked-list) List -@@ -107,7 +107,7 @@ struct fsl_dma_list_descriptor { - u8 res[8]; /* Reserved */ - } __attribute__ ((aligned(32), packed)); - --/** -+/* - * Link Descriptor for basic and extended chaining mode DMA operations. - * - * A Link Descriptor points to a single DMA buffer. Each link descriptor -diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c ---- a/sound/soc/fsl/fsl_easrc.c -+++ b/sound/soc/fsl/fsl_easrc.c -@@ -1025,7 +1025,6 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id) - struct fsl_easrc_ctx_priv *ctx_priv; - struct fsl_asrc_pair *ctx; - struct device *dev; -- unsigned long lock_flags; - int ret; - - if (!easrc) -@@ -1053,9 +1052,8 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id) - if (ret) - return ret; - -- spin_lock_irqsave(&easrc->lock, lock_flags); -- ret = fsl_easrc_config_slot(easrc, ctx->index); -- spin_unlock_irqrestore(&easrc->lock, lock_flags); -+ scoped_guard(spinlock_irqsave, &easrc->lock) -+ ret = fsl_easrc_config_slot(easrc, ctx->index); - if (ret) - return ret; - -@@ -1301,13 +1299,12 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) - enum asrc_pair_index index = ASRC_INVALID_PAIR; - struct fsl_asrc *easrc = ctx->asrc; - struct device *dev; -- unsigned long lock_flags; - int ret = 0; - int i; - - dev = &easrc->pdev->dev; - -- spin_lock_irqsave(&easrc->lock, lock_flags); -+ guard(spinlock_irqsave)(&easrc->lock); - - for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) { - if (easrc->pair[i]) -@@ -1331,8 +1328,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) - easrc->channel_avail -= channels; - } - -- spin_unlock_irqrestore(&easrc->lock, lock_flags); -- - return ret; - } - -@@ -1343,7 +1338,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx) - */ - static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx) - { -- unsigned long lock_flags; - struct fsl_asrc *easrc; - - if (!ctx) -@@ -1351,14 +1345,12 @@ static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx) - - easrc = ctx->asrc; - -- spin_lock_irqsave(&easrc->lock, lock_flags); -+ guard(spinlock_irqsave)(&easrc->lock); - - fsl_easrc_release_slot(easrc, ctx->index); - - easrc->channel_avail += ctx->channels; - easrc->pair[ctx->index] = NULL; -- -- spin_unlock_irqrestore(&easrc->lock, lock_flags); - } - - /* -@@ -2292,15 +2284,13 @@ static int fsl_easrc_runtime_suspend(struct device *dev) - { - struct fsl_asrc *easrc = dev_get_drvdata(dev); - struct fsl_easrc_priv *easrc_priv = easrc->private; -- unsigned long lock_flags; - - regcache_cache_only(easrc->regmap, true); - - clk_disable_unprepare(easrc->mem_clk); - -- spin_lock_irqsave(&easrc->lock, lock_flags); -- easrc_priv->firmware_loaded = 0; -- spin_unlock_irqrestore(&easrc->lock, lock_flags); -+ scoped_guard(spinlock_irqsave, &easrc->lock) -+ easrc_priv->firmware_loaded = 0; - - return 0; - } -@@ -2311,7 +2301,6 @@ static int fsl_easrc_runtime_resume(struct device *dev) - struct fsl_easrc_priv *easrc_priv = easrc->private; - struct fsl_easrc_ctx_priv *ctx_priv; - struct fsl_asrc_pair *ctx; -- unsigned long lock_flags; - int ret; - int i; - -@@ -2323,13 +2312,11 @@ static int fsl_easrc_runtime_resume(struct device *dev) - regcache_mark_dirty(easrc->regmap); - regcache_sync(easrc->regmap); - -- spin_lock_irqsave(&easrc->lock, lock_flags); -- if (easrc_priv->firmware_loaded) { -- spin_unlock_irqrestore(&easrc->lock, lock_flags); -- goto skip_load; -+ scoped_guard(spinlock_irqsave, &easrc->lock) { -+ if (easrc_priv->firmware_loaded) -+ return 0; -+ easrc_priv->firmware_loaded = 1; - } -- easrc_priv->firmware_loaded = 1; -- spin_unlock_irqrestore(&easrc->lock, lock_flags); - - ret = fsl_easrc_get_firmware(easrc); - if (ret) { -@@ -2377,9 +2364,7 @@ static int fsl_easrc_runtime_resume(struct device *dev) - goto disable_mem_clk; - } - --skip_load: - return 0; -- - disable_mem_clk: - clk_disable_unprepare(easrc->mem_clk); - return ret; -diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h ---- a/sound/soc/fsl/fsl_easrc.h -+++ b/sound/soc/fsl/fsl_easrc.h -@@ -584,7 +584,7 @@ struct fsl_easrc_slot { - }; - - /** -- * fsl_easrc_ctx_priv: EASRC context private data -+ * struct fsl_easrc_ctx_priv - EASRC context private data - * - * @in_params: input parameter - * @out_params: output parameter -@@ -625,7 +625,7 @@ struct fsl_easrc_ctx_priv { - }; - - /** -- * fsl_easrc_priv: EASRC private data -+ * struct fsl_easrc_priv - EASRC private data - * - * @slot: slot setting - * @firmware_hdr: the header of firmware -diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c ---- a/sound/soc/fsl/fsl_esai.c -+++ b/sound/soc/fsl/fsl_esai.c -@@ -709,10 +709,9 @@ static void fsl_esai_hw_reset(struct work_struct *work) - { - struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work); - bool tx = true, rx = false, enabled[2]; -- unsigned long lock_flags; - u32 tfcr, rfcr; - -- spin_lock_irqsave(&esai_priv->lock, lock_flags); -+ guard(spinlock_irqsave)(&esai_priv->lock); - /* Save the registers */ - regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr); - regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr); -@@ -750,8 +749,6 @@ static void fsl_esai_hw_reset(struct work_struct *work) - fsl_esai_trigger_start(esai_priv, tx); - if (enabled[rx]) - fsl_esai_trigger_start(esai_priv, rx); -- -- spin_unlock_irqrestore(&esai_priv->lock, lock_flags); - } - - static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, -@@ -759,7 +756,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, - { - struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); - bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; -- unsigned long lock_flags; - - esai_priv->channels[tx] = substream->runtime->channels; - -@@ -767,16 +763,14 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -- spin_lock_irqsave(&esai_priv->lock, lock_flags); -- fsl_esai_trigger_start(esai_priv, tx); -- spin_unlock_irqrestore(&esai_priv->lock, lock_flags); -+ scoped_guard(spinlock_irqsave, &esai_priv->lock) -+ fsl_esai_trigger_start(esai_priv, tx); - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -- spin_lock_irqsave(&esai_priv->lock, lock_flags); -- fsl_esai_trigger_stop(esai_priv, tx); -- spin_unlock_irqrestore(&esai_priv->lock, lock_flags); -+ scoped_guard(spinlock_irqsave, &esai_priv->lock) -+ fsl_esai_trigger_stop(esai_priv, tx); - break; - default: - return -EINVAL; -diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c ---- a/sound/soc/fsl/fsl_spdif.c -+++ b/sound/soc/fsl/fsl_spdif.c -@@ -853,17 +853,15 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); - struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); - struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; -- unsigned long flags; - int ret = -EAGAIN; - -- spin_lock_irqsave(&ctrl->ctl_lock, flags); -+ guard(spinlock_irqsave)(&ctrl->ctl_lock); - if (ctrl->ready_buf) { - int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; - memcpy(&ucontrol->value.iec958.subcode[0], - &ctrl->subcode[idx], SPDIF_UBITS_SIZE); - ret = 0; - } -- spin_unlock_irqrestore(&ctrl->ctl_lock, flags); - - return ret; - } -@@ -885,17 +883,15 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, - struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); - struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); - struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; -- unsigned long flags; - int ret = -EAGAIN; - -- spin_lock_irqsave(&ctrl->ctl_lock, flags); -+ guard(spinlock_irqsave)(&ctrl->ctl_lock); - if (ctrl->ready_buf) { - int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; - memcpy(&ucontrol->value.bytes.data[0], - &ctrl->qsub[idx], SPDIF_QSUB_SIZE); - ret = 0; - } -- spin_unlock_irqrestore(&ctrl->ctl_lock, flags); - - return ret; - } -diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c ---- a/sound/soc/fsl/fsl_ssi.c -+++ b/sound/soc/fsl/fsl_ssi.c -@@ -1218,13 +1218,13 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - if (reg > 0x7f) - return; - -- mutex_lock(&fsl_ac97_data->ac97_reg_lock); -+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock); - - ret = clk_prepare_enable(fsl_ac97_data->clk); - if (ret) { - pr_err("ac97 write clk_prepare_enable failed: %d\n", - ret); -- goto ret_unlock; -+ return; - } - - lreg = reg << 12; -@@ -1238,9 +1238,6 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - udelay(100); - - clk_disable_unprepare(fsl_ac97_data->clk); -- --ret_unlock: -- mutex_unlock(&fsl_ac97_data->ac97_reg_lock); - } - - static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, -@@ -1252,12 +1249,12 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, - unsigned int lreg; - int ret; - -- mutex_lock(&fsl_ac97_data->ac97_reg_lock); -+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock); - - ret = clk_prepare_enable(fsl_ac97_data->clk); - if (ret) { - pr_err("ac97 read clk_prepare_enable failed: %d\n", ret); -- goto ret_unlock; -+ return val; - } - - lreg = (reg & 0x7f) << 12; -@@ -1272,8 +1269,6 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97, - - clk_disable_unprepare(fsl_ac97_data->clk); - --ret_unlock: -- mutex_unlock(&fsl_ac97_data->ac97_reg_lock); - return val; - } - -diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c ---- a/sound/soc/fsl/fsl_xcvr.c -+++ b/sound/soc/fsl/fsl_xcvr.c -@@ -797,10 +797,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - { - struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); - bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; -- unsigned long lock_flags; - int ret = 0; - -- spin_lock_irqsave(&xcvr->lock, lock_flags); -+ guard(spinlock_irqsave)(&xcvr->lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: -@@ -812,7 +811,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); - if (ret < 0) { - dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); -- goto release_lock; -+ return ret; - } - - if (tx) { -@@ -824,7 +823,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - FSL_XCVR_ISR_CMDC_TX_EN); - if (ret < 0) { - dev_err(dai->dev, "err updating isr %d\n", ret); -- goto release_lock; -+ return ret; - } - fallthrough; - case FSL_XCVR_MODE_SPDIF: -@@ -833,7 +832,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); - if (ret < 0) { - dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); -- goto release_lock; -+ return ret; - } - break; - } -@@ -844,14 +843,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); - if (ret < 0) { - dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); -- goto release_lock; -+ return ret; - } - - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, - FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); - if (ret < 0) { - dev_err(dai->dev, "Error while setting IER0: %d\n", ret); -- goto release_lock; -+ return ret; - } - - /* clear DPATH RESET */ -@@ -860,7 +859,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - 0); - if (ret < 0) { - dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); -- goto release_lock; -+ return ret; - } - - break; -@@ -873,14 +872,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); - if (ret < 0) { - dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); -- goto release_lock; -+ return ret; - } - - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, - FSL_XCVR_IRQ_EARC_ALL, 0); - if (ret < 0) { - dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); -- goto release_lock; -+ return ret; - } - - if (tx) { -@@ -891,7 +890,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); - if (ret < 0) { - dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); -- goto release_lock; -+ return ret; - } - if (xcvr->soc_data->spdif_only) - break; -@@ -905,7 +904,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - if (ret < 0) { - dev_err(dai->dev, - "Err updating ISR %d\n", ret); -- goto release_lock; -+ return ret; - } - break; - } -@@ -916,18 +915,16 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, - break; - } - --release_lock: -- spin_unlock_irqrestore(&xcvr->lock, lock_flags); - return ret; - } - - static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) - { - struct device *dev = &xcvr->pdev->dev; -- const struct firmware *fw; - int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET; - u32 mask, val; - -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev); - if (ret) { - dev_err(dev, "failed to request firmware.\n"); -@@ -939,7 +936,6 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) - /* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */ - if (rem > 16384) { - dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem); -- release_firmware(fw); - return -ENOMEM; - } - -@@ -950,7 +946,7 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) - if (ret < 0) { - dev_err(dev, "FW: failed to set page %d, err=%d\n", - page, ret); -- goto err_firmware; -+ return ret; - } - - off = page * size; -@@ -971,11 +967,6 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) - } - } - --err_firmware: -- release_firmware(fw); -- if (ret < 0) -- return ret; -- - /* configure watermarks */ - mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK; - val = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX); -@@ -1448,11 +1439,10 @@ static void reset_rx_work(struct work_struct *work) - { - struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst); - struct device *dev = &xcvr->pdev->dev; -- unsigned long lock_flags; - u32 ext_ctrl; - - dev_dbg(dev, "reset rx path\n"); -- spin_lock_irqsave(&xcvr->lock, lock_flags); -+ guard(spinlock_irqsave)(&xcvr->lock); - regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl); - - if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) { -@@ -1469,7 +1459,6 @@ static void reset_rx_work(struct work_struct *work) - FSL_XCVR_EXT_CTRL_RX_DPTH_RESET, - 0); - } -- spin_unlock_irqrestore(&xcvr->lock, lock_flags); - } - - static irqreturn_t irq0_isr(int irq, void *devid) -diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c ---- a/sound/soc/fsl/imx-audio-rpmsg.c -+++ b/sound/soc/fsl/imx-audio-rpmsg.c -@@ -22,7 +22,6 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len, - struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data; - struct rpmsg_info *info; - struct rpmsg_msg *msg; -- unsigned long flags; - - if (!rpmsg->rpmsg_pdev) - return 0; -@@ -37,21 +36,21 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len, - /* TYPE C is notification from M core */ - switch (r_msg->header.cmd) { - case TX_PERIOD_DONE: -- spin_lock_irqsave(&info->lock[TX], flags); -- msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; -- msg->r_msg.param.buffer_tail = -- r_msg->param.buffer_tail; -- msg->r_msg.param.buffer_tail %= info->num_period[TX]; -- spin_unlock_irqrestore(&info->lock[TX], flags); -+ scoped_guard(spinlock_irqsave, &info->lock[TX]) { -+ msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; -+ msg->r_msg.param.buffer_tail = -+ r_msg->param.buffer_tail; -+ msg->r_msg.param.buffer_tail %= info->num_period[TX]; -+ } - info->callback[TX](info->callback_param[TX]); - break; - case RX_PERIOD_DONE: -- spin_lock_irqsave(&info->lock[RX], flags); -- msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; -- msg->r_msg.param.buffer_tail = -- r_msg->param.buffer_tail; -- msg->r_msg.param.buffer_tail %= info->num_period[1]; -- spin_unlock_irqrestore(&info->lock[RX], flags); -+ scoped_guard(spinlock_irqsave, &info->lock[RX]) { -+ msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; -+ msg->r_msg.param.buffer_tail = -+ r_msg->param.buffer_tail; -+ msg->r_msg.param.buffer_tail %= info->num_period[1]; -+ } - info->callback[RX](info->callback_param[RX]); - break; - default: -diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c ---- a/sound/soc/fsl/imx-pcm-rpmsg.c -+++ b/sound/soc/fsl/imx-pcm-rpmsg.c -@@ -39,10 +39,9 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, - struct rpmsg_device *rpdev = info->rpdev; - int ret = 0; - -- mutex_lock(&info->msg_lock); -+ guard(mutex)(&info->msg_lock); - if (!rpdev) { - dev_err(info->dev, "rpmsg channel not ready\n"); -- mutex_unlock(&info->msg_lock); - return -EINVAL; - } - -@@ -55,15 +54,12 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, - sizeof(struct rpmsg_s_msg)); - if (ret) { - dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret); -- mutex_unlock(&info->msg_lock); - return ret; - } - - /* No receive msg for TYPE_C command */ -- if (msg->s_msg.header.type == MSG_TYPE_C) { -- mutex_unlock(&info->msg_lock); -+ if (msg->s_msg.header.type == MSG_TYPE_C) - return 0; -- } - - /* wait response from rpmsg */ - ret = wait_for_completion_timeout(&info->cmd_complete, -@@ -71,7 +67,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, - if (!ret) { - dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n", - msg->s_msg.header.cmd); -- mutex_unlock(&info->msg_lock); - return -ETIMEDOUT; - } - -@@ -100,8 +95,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, - dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd, - info->r_msg.param.resp); - -- mutex_unlock(&info->msg_lock); -- - return 0; - } - -@@ -109,14 +102,13 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream, - struct rpmsg_msg *msg, - struct rpmsg_info *info) - { -- unsigned long flags; - int ret = 0; - - /* - * Queue the work to workqueue. - * If the queue is full, drop the message. - */ -- spin_lock_irqsave(&info->wq_lock, flags); -+ guard(spinlock_irqsave)(&info->wq_lock); - if (info->work_write_index != info->work_read_index) { - int index = info->work_write_index; - -@@ -130,7 +122,6 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream, - info->msg_drop_count[substream->stream]++; - ret = -EPIPE; - } -- spin_unlock_irqrestore(&info->wq_lock, flags); - - return ret; - } -@@ -523,7 +514,6 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component, - snd_pcm_sframes_t avail; - struct timer_list *timer; - struct rpmsg_msg *msg; -- unsigned long flags; - int buffer_tail = 0; - int written_num; - -@@ -553,11 +543,11 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component, - msg->s_msg.param.buffer_tail = buffer_tail; - - /* The notification message is updated to latest */ -- spin_lock_irqsave(&info->lock[substream->stream], flags); -- memcpy(&info->notify[substream->stream], msg, -- sizeof(struct rpmsg_s_msg)); -- info->notify_updated[substream->stream] = true; -- spin_unlock_irqrestore(&info->lock[substream->stream], flags); -+ scoped_guard(spinlock_irqsave, &info->lock[substream->stream]) { -+ memcpy(&info->notify[substream->stream], msg, -+ sizeof(struct rpmsg_s_msg)); -+ info->notify_updated[substream->stream] = true; -+ } - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - avail = snd_pcm_playback_hw_avail(runtime); -@@ -641,7 +631,7 @@ static void imx_rpmsg_pcm_work(struct work_struct *work) - bool is_notification = false; - struct rpmsg_info *info; - struct rpmsg_msg msg; -- unsigned long flags; -+ bool updated; - - work_of_rpmsg = container_of(work, struct work_of_rpmsg, work); - info = work_of_rpmsg->info; -@@ -652,25 +642,26 @@ static void imx_rpmsg_pcm_work(struct work_struct *work) - * enough data in M core side, need to let M core know - * data is updated immediately. - */ -- spin_lock_irqsave(&info->lock[TX], flags); -- if (info->notify_updated[TX]) { -- memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg)); -- info->notify_updated[TX] = false; -- spin_unlock_irqrestore(&info->lock[TX], flags); -- info->send_message(&msg, info); -- } else { -- spin_unlock_irqrestore(&info->lock[TX], flags); -+ scoped_guard(spinlock_irqsave, &info->lock[TX]) { -+ updated = info->notify_updated[TX]; -+ if (updated) { -+ memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg)); -+ info->notify_updated[TX] = false; -+ } - } -+ if (updated) -+ info->send_message(&msg, info); - -- spin_lock_irqsave(&info->lock[RX], flags); -- if (info->notify_updated[RX]) { -- memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg)); -- info->notify_updated[RX] = false; -- spin_unlock_irqrestore(&info->lock[RX], flags); -- info->send_message(&msg, info); -- } else { -- spin_unlock_irqrestore(&info->lock[RX], flags); -+ scoped_guard(spinlock_irqsave, &info->lock[RX]) { -+ updated = info->notify_updated[RX]; -+ if (updated) { -+ memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg)); -+ info->notify_updated[RX] = false; -+ } - } -+ if (updated) -+ info->send_message(&msg, info); -+ - - /* Skip the notification message for it has been processed above */ - if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C && -@@ -682,10 +673,10 @@ static void imx_rpmsg_pcm_work(struct work_struct *work) - info->send_message(&work_of_rpmsg->msg, info); - - /* update read index */ -- spin_lock_irqsave(&info->wq_lock, flags); -- info->work_read_index++; -- info->work_read_index %= WORK_MAX_NUM; -- spin_unlock_irqrestore(&info->wq_lock, flags); -+ scoped_guard(spinlock_irqsave, &info->wq_lock) { -+ info->work_read_index++; -+ info->work_read_index %= WORK_MAX_NUM; -+ } - } - - static int imx_rpmsg_pcm_probe(struct platform_device *pdev) -@@ -819,9 +810,9 @@ static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = { - }; - - static const struct platform_device_id imx_rpmsg_pcm_id_table[] = { -- { .name = "rpmsg-audio-channel" }, -- { .name = "rpmsg-micfil-channel" }, -- { }, -+ { .name = "rpmsg-audio-channel" }, -+ { .name = "rpmsg-micfil-channel" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, imx_rpmsg_pcm_id_table); - -diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c ---- a/sound/soc/fsl/mpc5200_dma.c -+++ b/sound/soc/fsl/mpc5200_dma.c -@@ -77,18 +77,20 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream) - { - struct psc_dma_stream *s = _psc_dma_stream; - -- spin_lock(&s->psc_dma->lock); -- /* For each finished period, dequeue the completed period buffer -- * and enqueue a new one in it's place. */ -- while (bcom_buffer_done(s->bcom_task)) { -- bcom_retrieve_buffer(s->bcom_task, NULL, NULL); -+ scoped_guard(spinlock, &s->psc_dma->lock) { -+ /* -+ * For each finished period, dequeue the completed period buffer -+ * and enqueue a new one in its place -+ */ -+ while (bcom_buffer_done(s->bcom_task)) { -+ bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - -- s->period_current = (s->period_current+1) % s->runtime->periods; -- s->period_count++; -+ s->period_current = (s->period_current+1) % s->runtime->periods; -+ s->period_count++; - -- psc_dma_bcom_enqueue_next_buffer(s); -+ psc_dma_bcom_enqueue_next_buffer(s); -+ } - } -- spin_unlock(&s->psc_dma->lock); - - /* If the stream is active, then also inform the PCM middle layer - * of the period finished event. */ -@@ -116,7 +118,6 @@ static int psc_dma_trigger(struct snd_soc_component *component, - struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - u16 imr; -- unsigned long flags; - int i; - - switch (cmd) { -@@ -135,19 +136,18 @@ static int psc_dma_trigger(struct snd_soc_component *component, - /* Fill up the bestcomm bd queue and enable DMA. - * This will begin filling the PSC's fifo. - */ -- spin_lock_irqsave(&psc_dma->lock, flags); -+ scoped_guard(spinlock_irqsave, &psc_dma->lock) { -+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) -+ bcom_gen_bd_rx_reset(s->bcom_task); -+ else -+ bcom_gen_bd_tx_reset(s->bcom_task); - -- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) -- bcom_gen_bd_rx_reset(s->bcom_task); -- else -- bcom_gen_bd_tx_reset(s->bcom_task); -+ for (i = 0; i < runtime->periods; i++) -+ if (!bcom_queue_full(s->bcom_task)) -+ psc_dma_bcom_enqueue_next_buffer(s); - -- for (i = 0; i < runtime->periods; i++) -- if (!bcom_queue_full(s->bcom_task)) -- psc_dma_bcom_enqueue_next_buffer(s); -- -- bcom_enable(s->bcom_task); -- spin_unlock_irqrestore(&psc_dma->lock, flags); -+ bcom_enable(s->bcom_task); -+ } - - out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT); - -@@ -158,13 +158,13 @@ static int psc_dma_trigger(struct snd_soc_component *component, - substream->pstr->stream, s->period_count); - s->active = 0; - -- spin_lock_irqsave(&psc_dma->lock, flags); -- bcom_disable(s->bcom_task); -- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) -- bcom_gen_bd_rx_reset(s->bcom_task); -- else -- bcom_gen_bd_tx_reset(s->bcom_task); -- spin_unlock_irqrestore(&psc_dma->lock, flags); -+ scoped_guard(spinlock_irqsave, &psc_dma->lock) { -+ bcom_disable(s->bcom_task); -+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) -+ bcom_gen_bd_rx_reset(s->bcom_task); -+ else -+ bcom_gen_bd_tx_reset(s->bcom_task); -+ } - - break; - -@@ -314,35 +314,29 @@ int mpc5200_audio_dma_create(struct platform_device *op) - { - phys_addr_t fifo; - struct psc_dma *psc_dma; -- struct resource res; -+ struct resource *res; - int size, irq, rc; - const __be32 *prop; - void __iomem *regs; -- int ret; -+ -+ regs = devm_platform_get_and_ioremap_resource(op, 0, &res); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); - - /* Fetch the registers and IRQ of the PSC */ -- irq = irq_of_parse_and_map(op->dev.of_node, 0); -- if (of_address_to_resource(op->dev.of_node, 0, &res)) { -- dev_err(&op->dev, "Missing reg property\n"); -- return -ENODEV; -- } -- regs = devm_ioremap(&op->dev, res.start, resource_size(&res)); -- if (!regs) { -- dev_err(&op->dev, "Could not map registers\n"); -- return -ENODEV; -- } -+ irq = platform_get_irq(op, 0); -+ if (irq < 0) -+ return irq; - - /* Allocate and initialize the driver private data */ -- psc_dma = kzalloc_obj(*psc_dma); -+ psc_dma = devm_kzalloc(&op->dev, sizeof(*psc_dma), GFP_KERNEL); - if (!psc_dma) - return -ENOMEM; - - /* Get the PSC ID */ - prop = of_get_property(op->dev.of_node, "cell-index", &size); -- if (!prop || size < sizeof *prop) { -- ret = -ENODEV; -- goto out_free; -- } -+ if (!prop || size < sizeof *prop) -+ return -ENODEV; - - spin_lock_init(&psc_dma->lock); - mutex_init(&psc_dma->mutex); -@@ -357,7 +351,7 @@ int mpc5200_audio_dma_create(struct platform_device *op) - - /* Find the address of the fifo data registers and setup the - * DMA tasks */ -- fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32); -+ fifo = res->start + offsetof(struct mpc52xx_psc, buffer.buffer_32); - psc_dma->capture.bcom_task = - bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512); - psc_dma->playback.bcom_task = -@@ -365,8 +359,7 @@ int mpc5200_audio_dma_create(struct platform_device *op) - if (!psc_dma->capture.bcom_task || - !psc_dma->playback.bcom_task) { - dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); -- ret = -ENODEV; -- goto out_free; -+ return -ENODEV; - } - - /* Disable all interrupts and reset the PSC */ -@@ -399,16 +392,14 @@ int mpc5200_audio_dma_create(struct platform_device *op) - psc_dma->capture.irq = - bcom_get_task_irq(psc_dma->capture.bcom_task); - -- rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, -+ rc = devm_request_irq(&op->dev, psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, - "psc-dma-status", psc_dma); -- rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, -+ rc |= devm_request_irq(&op->dev, psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, - "psc-dma-capture", &psc_dma->capture); -- rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, -+ rc |= devm_request_irq(&op->dev, psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, - "psc-dma-playback", &psc_dma->playback); -- if (rc) { -- ret = -ENODEV; -- goto out_irq; -- } -+ if (rc) -+ return -ENODEV; - - /* Save what we've done so it can be found again later */ - dev_set_drvdata(&op->dev, psc_dma); -@@ -416,13 +407,6 @@ int mpc5200_audio_dma_create(struct platform_device *op) - /* Tell the ASoC OF helpers about it */ - return devm_snd_soc_register_component(&op->dev, - &mpc5200_audio_dma_component, NULL, 0); --out_irq: -- free_irq(psc_dma->irq, psc_dma); -- free_irq(psc_dma->capture.irq, &psc_dma->capture); -- free_irq(psc_dma->playback.irq, &psc_dma->playback); --out_free: -- kfree(psc_dma); -- return ret; - } - EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); - -@@ -435,12 +419,6 @@ int mpc5200_audio_dma_destroy(struct platform_device *op) - bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); - bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); - -- /* Release irqs */ -- free_irq(psc_dma->irq, psc_dma); -- free_irq(psc_dma->capture.irq, &psc_dma->capture); -- free_irq(psc_dma->playback.irq, &psc_dma->playback); -- -- kfree(psc_dma); - dev_set_drvdata(&op->dev, NULL); - - return 0; -diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c ---- a/sound/soc/fsl/mpc5200_psc_ac97.c -+++ b/sound/soc/fsl/mpc5200_psc_ac97.c -@@ -30,14 +30,13 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg) - int status; - unsigned int val; - -- mutex_lock(&psc_dma->mutex); -+ guard(mutex)(&psc_dma->mutex); - - /* Wait for command send status zero = ready */ - status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & - MPC52xx_PSC_SR_CMDSEND), 100, 0); - if (status == 0) { - pr_err("timeout on ac97 bus (rdy)\n"); -- mutex_unlock(&psc_dma->mutex); - return -ENODEV; - } - -@@ -53,19 +52,16 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg) - if (status == 0) { - pr_err("timeout on ac97 read (val) %x\n", - in_be16(&psc_dma->psc_regs->sr_csr.status)); -- mutex_unlock(&psc_dma->mutex); - return -ENODEV; - } - /* Get the data */ - val = in_be32(&psc_dma->psc_regs->ac97_data); - if (((val >> 24) & 0x7f) != reg) { - pr_err("reg echo error on ac97 read\n"); -- mutex_unlock(&psc_dma->mutex); - return -ENODEV; - } - val = (val >> 8) & 0xffff; - -- mutex_unlock(&psc_dma->mutex); - return (unsigned short) val; - } - -@@ -74,52 +70,46 @@ static void psc_ac97_write(struct snd_ac97 *ac97, - { - int status; - -- mutex_lock(&psc_dma->mutex); -+ guard(mutex)(&psc_dma->mutex); - - /* Wait for command status zero = ready */ - status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) & - MPC52xx_PSC_SR_CMDSEND), 100, 0); - if (status == 0) { - pr_err("timeout on ac97 bus (write)\n"); -- goto out; -+ return; - } - /* Write data */ - out_be32(&psc_dma->psc_regs->ac97_cmd, - ((reg & 0x7f) << 24) | (val << 8)); -- -- out: -- mutex_unlock(&psc_dma->mutex); - } - - static void psc_ac97_warm_reset(struct snd_ac97 *ac97) - { - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - -- mutex_lock(&psc_dma->mutex); -+ guard(mutex)(&psc_dma->mutex); - - out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); - udelay(3); - out_be32(®s->sicr, psc_dma->sicr); -- -- mutex_unlock(&psc_dma->mutex); - } - - static void psc_ac97_cold_reset(struct snd_ac97 *ac97) - { - struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; - -- mutex_lock(&psc_dma->mutex); -- dev_dbg(psc_dma->dev, "cold reset\n"); -+ scoped_guard(mutex, &psc_dma->mutex) { -+ dev_dbg(psc_dma->dev, "cold reset\n"); - -- mpc5200_psc_ac97_gpio_reset(psc_dma->id); -+ mpc5200_psc_ac97_gpio_reset(psc_dma->id); - -- /* Notify the PSC that a reset has occurred */ -- out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB); -+ /* Notify the PSC that a reset has occurred */ -+ out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB); - -- /* Re-enable RX and TX */ -- out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); -- -- mutex_unlock(&psc_dma->mutex); -+ /* Re-enable RX and TX */ -+ out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); -+ } - - usleep_range(1000, 2000); - psc_ac97_warm_reset(ac97); -@@ -286,7 +276,7 @@ static int psc_ac97_of_probe(struct platform_device *op) - return rc; - } - -- rc = snd_soc_register_component(&op->dev, &psc_ac97_component, -+ rc = devm_snd_soc_register_component(&op->dev, &psc_ac97_component, - psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai)); - if (rc != 0) { - dev_err(&op->dev, "Failed to register DAI\n"); -@@ -312,8 +302,6 @@ static int psc_ac97_of_probe(struct platform_device *op) - static void psc_ac97_of_remove(struct platform_device *op) - { - mpc5200_audio_dma_destroy(op); -- snd_soc_unregister_component(&op->dev); -- snd_soc_set_ac97_ops(NULL); - } - - /* Match table for of_platform binding */ -diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c ---- a/sound/soc/fsl/mpc5200_psc_i2s.c -+++ b/sound/soc/fsl/mpc5200_psc_i2s.c -@@ -79,9 +79,12 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, - * and we don't care about the frequency. Return an error if the direction - * is not SND_SOC_CLOCK_IN. - * -+ * @cpu_dai: DAI runtime data pointer - * @clk_id: reserved, should be zero - * @freq: the frequency of the given clock ID, currently ignored - * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) -+ * -+ * Returns: %0 on success or %-EINVAL on failure. - */ - static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -@@ -101,7 +104,10 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, - * This driver only supports I2S mode. Return an error if the format is - * not SND_SOC_DAIFMT_I2S. - * -+ * @cpu_dai: DAI runtime data pointer - * @format: one of SND_SOC_DAIFMT_xxx -+ * -+ * Returns: %0 on success or %-EINVAL on failure. - */ - static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) - { -@@ -119,7 +125,7 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) - */ - - /** -- * psc_i2s_dai_template: template CPU Digital Audio Interface -+ * var psc_i2s_dai_ops - template CPU Digital Audio Interface - */ - static const struct snd_soc_dai_ops psc_i2s_dai_ops = { - .hw_params = psc_i2s_hw_params, -@@ -166,7 +172,7 @@ static int psc_i2s_of_probe(struct platform_device *op) - if (rc != 0) - return rc; - -- rc = snd_soc_register_component(&op->dev, &psc_i2s_component, -+ rc = devm_snd_soc_register_component(&op->dev, &psc_i2s_component, - psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai)); - if (rc != 0) { - pr_err("Failed to register DAI\n"); -@@ -213,7 +219,6 @@ static int psc_i2s_of_probe(struct platform_device *op) - static void psc_i2s_of_remove(struct platform_device *op) - { - mpc5200_audio_dma_destroy(op); -- snd_soc_unregister_component(&op->dev); - } - - /* Match table for of_platform binding */ -diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c ---- a/sound/soc/fsl/p1022_ds.c -+++ b/sound/soc/fsl/p1022_ds.c -@@ -73,6 +73,8 @@ struct machine_data { - char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ - }; - -+#define card_to_mdata(_card) container_of(_card, struct machine_data, card) -+ - /** - * p1022_ds_machine_probe: initialize the board - * -@@ -82,8 +84,7 @@ struct machine_data { - */ - static int p1022_ds_machine_probe(struct snd_soc_card *card) - { -- struct machine_data *mdata = -- container_of(card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); -@@ -122,8 +123,7 @@ static int p1022_ds_machine_probe(struct snd_soc_card *card) - static int p1022_ds_startup(struct snd_pcm_substream *substream) - { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -- struct machine_data *mdata = -- container_of(rtd->card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(rtd->card); - struct device *dev = rtd->card->dev; - int ret = 0; - -@@ -156,8 +156,7 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream) - */ - static int p1022_ds_machine_remove(struct snd_soc_card *card) - { -- struct machine_data *mdata = -- container_of(card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); -@@ -399,8 +398,7 @@ static int p1022_ds_probe(struct platform_device *pdev) - static void p1022_ds_remove(struct platform_device *pdev) - { - struct snd_soc_card *card = platform_get_drvdata(pdev); -- struct machine_data *mdata = -- container_of(card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(card); - - snd_soc_unregister_card(card); - kfree(mdata); -diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c ---- a/sound/soc/fsl/p1022_rdk.c -+++ b/sound/soc/fsl/p1022_rdk.c -@@ -79,6 +79,8 @@ struct machine_data { - char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */ - }; - -+#define card_to_mdata(_card) container_of(_card, struct machine_data, card) -+ - /** - * p1022_rdk_machine_probe - initialize the board - * @card: ASoC card instance -@@ -91,8 +93,7 @@ struct machine_data { - */ - static int p1022_rdk_machine_probe(struct snd_soc_card *card) - { -- struct machine_data *mdata = -- container_of(card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); -@@ -134,8 +135,7 @@ static int p1022_rdk_machine_probe(struct snd_soc_card *card) - static int p1022_rdk_startup(struct snd_pcm_substream *substream) - { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -- struct machine_data *mdata = -- container_of(rtd->card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(rtd->card); - struct device *dev = rtd->card->dev; - int ret = 0; - -@@ -169,8 +169,7 @@ static int p1022_rdk_startup(struct snd_pcm_substream *substream) - */ - static int p1022_rdk_machine_remove(struct snd_soc_card *card) - { -- struct machine_data *mdata = -- container_of(card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(card); - struct ccsr_guts __iomem *guts; - - guts = ioremap(guts_phys, sizeof(struct ccsr_guts)); -@@ -361,8 +360,7 @@ static int p1022_rdk_probe(struct platform_device *pdev) - static void p1022_rdk_remove(struct platform_device *pdev) - { - struct snd_soc_card *card = platform_get_drvdata(pdev); -- struct machine_data *mdata = -- container_of(card, struct machine_data, card); -+ struct machine_data *mdata = card_to_mdata(card); - - snd_soc_unregister_card(card); - kfree(mdata); -diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c ---- a/sound/soc/generic/audio-graph-card.c -+++ b/sound/soc/generic/audio-graph-card.c -@@ -579,11 +579,11 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) - goto end; - } - -- ret = simple_util_parse_widgets(card, NULL); -+ ret = simple_util_parse_widgets(priv, NULL); - if (ret < 0) - goto end; - -- ret = simple_util_parse_routing(card, NULL); -+ ret = simple_util_parse_routing(priv, NULL); - if (ret < 0) - goto end; - -@@ -594,6 +594,7 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) - if (ret < 0) - goto err; - -+ /* Card name should be set after graph_for_each_link() */ - ret = simple_util_parse_card_name(priv, NULL); - if (ret < 0) - goto err; -@@ -603,14 +604,13 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) - simple_util_debug_info(priv); - - ret = devm_snd_soc_register_card(dev, card); -- if (ret < 0) -- goto err; -- -- return 0; - err: -- simple_util_clean_reference(card); -+ if (ret < 0) { -+ simple_util_clean_reference(priv); -+ return dev_err_probe(dev, ret, "parse error\n"); -+ } - end: -- return dev_err_probe(dev, ret, "parse error\n"); -+ return graph_ret(priv, ret); - } - EXPORT_SYMBOL_GPL(audio_graph_parse_of); - -diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c ---- a/sound/soc/generic/audio-graph-card2.c -+++ b/sound/soc/generic/audio-graph-card2.c -@@ -1303,11 +1303,11 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, - struct graph2_custom_hooks *hooks) - { - struct snd_soc_card *card = simple_priv_to_card(priv); -- int ret; -+ int ret = -ENOMEM; - - struct link_info *li __free(kfree) = kzalloc_obj(*li); - if (!li) -- return -ENOMEM; -+ goto end; - - card->probe = graph_util_card_probe; - card->owner = THIS_MODULE; -@@ -1316,31 +1316,35 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, - if ((hooks) && (hooks)->hook_pre) { - ret = (hooks)->hook_pre(priv); - if (ret < 0) -- goto err; -+ goto end; - } - - ret = graph_for_each_link(priv, hooks, li, graph_count); - if (!li->link) - ret = -EINVAL; - if (ret < 0) -- goto err; -+ goto end; - - ret = simple_util_init_priv(priv, li); - if (ret < 0) -- goto err; -+ goto end; - - priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); - if (IS_ERR(priv->pa_gpio)) { - ret = PTR_ERR(priv->pa_gpio); - dev_err(dev, "failed to get amplifier gpio: %d\n", ret); -- goto err; -+ goto end; - } - -- ret = simple_util_parse_widgets(card, NULL); -+ ret = simple_util_parse_widgets(priv, NULL); - if (ret < 0) -- goto err; -+ goto end; - -- ret = simple_util_parse_routing(card, NULL); -+ ret = simple_util_parse_routing(priv, NULL); -+ if (ret < 0) -+ goto end; -+ -+ ret = simple_util_parse_aux_devs(priv, NULL); - if (ret < 0) - goto err; - -@@ -1349,6 +1353,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, - if (ret < 0) - goto err; - -+ /* Card name should be set after graph_for_each_link() */ - ret = simple_util_parse_card_name(priv, NULL); - if (ret < 0) - goto err; -@@ -1363,15 +1368,13 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, - - simple_util_debug_info(priv); - -- ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); -- if (ret < 0) -- goto err; -- - ret = devm_snd_soc_register_card(dev, card); - err: -- if (ret < 0) -- dev_err_probe(dev, ret, "parse error\n"); -- -+ if (ret < 0) { -+ simple_util_clean_reference(priv); -+ return dev_err_probe(dev, ret, "parse error\n"); -+ } -+end: - return graph_ret(priv, ret); - } - EXPORT_SYMBOL_GPL(audio_graph2_parse_of); -diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c ---- a/sound/soc/generic/simple-card-utils.c -+++ b/sound/soc/generic/simple-card-utils.c -@@ -216,6 +216,27 @@ int simple_util_set_dailink_name(struct simple_util_priv *priv, - } - EXPORT_SYMBOL_GPL(simple_util_set_dailink_name); - -+int simple_util_parse_property(struct simple_util_priv *priv, -+ int (*func)(struct snd_soc_card *card, const char *propname), -+ char *prefix, char *property) -+{ -+ struct snd_soc_card *card = simple_priv_to_card(priv); -+ struct device_node *node = card->dev->of_node; -+ char prop[128]; -+ -+ if (!prefix) -+ prefix = ""; -+ -+ snprintf(prop, sizeof(prop), "%s%s", prefix, property); -+ -+ /* no property is not error */ -+ if (!of_property_present(node, prop)) -+ return 0; -+ -+ return func(card, prop); -+} -+EXPORT_SYMBOL_GPL(simple_util_parse_property); -+ - int simple_util_parse_card_name(struct simple_util_priv *priv, - char *prefix) - { -@@ -731,11 +752,12 @@ void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, - } - EXPORT_SYMBOL_GPL(simple_util_canonicalize_cpu); - --void simple_util_clean_reference(struct snd_soc_card *card) -+void simple_util_clean_reference(struct simple_util_priv *priv) - { - struct snd_soc_dai_link *dai_link; - struct snd_soc_dai_link_component *cpu; - struct snd_soc_dai_link_component *codec; -+ struct snd_soc_card *card = simple_priv_to_card(priv); - int i, j; - - for_each_card_prelinks(card, i, dai_link) { -@@ -747,57 +769,6 @@ void simple_util_clean_reference(struct snd_soc_card *card) - } - EXPORT_SYMBOL_GPL(simple_util_clean_reference); - --int simple_util_parse_routing(struct snd_soc_card *card, -- char *prefix) --{ -- struct device_node *node = card->dev->of_node; -- char prop[128]; -- -- if (!prefix) -- prefix = ""; -- -- snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); -- -- if (!of_property_present(node, prop)) -- return 0; -- -- return snd_soc_of_parse_audio_routing(card, prop); --} --EXPORT_SYMBOL_GPL(simple_util_parse_routing); -- --int simple_util_parse_widgets(struct snd_soc_card *card, -- char *prefix) --{ -- struct device_node *node = card->dev->of_node; -- char prop[128]; -- -- if (!prefix) -- prefix = ""; -- -- snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets"); -- -- if (of_property_present(node, prop)) -- return snd_soc_of_parse_audio_simple_widgets(card, prop); -- -- /* no widgets is not error */ -- return 0; --} --EXPORT_SYMBOL_GPL(simple_util_parse_widgets); -- --int simple_util_parse_pin_switches(struct snd_soc_card *card, -- char *prefix) --{ -- char prop[128]; -- -- if (!prefix) -- prefix = ""; -- -- snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); -- -- return snd_soc_of_parse_pin_switches(card, prop); --} --EXPORT_SYMBOL_GPL(simple_util_parse_pin_switches); -- - int simple_util_init_jack(struct snd_soc_card *card, - struct simple_util_jack *sjack, - int is_hp, char *prefix, -@@ -854,9 +825,9 @@ int simple_util_init_jack(struct snd_soc_card *card, - } - EXPORT_SYMBOL_GPL(simple_util_init_jack); - --int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix) -+int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix) - { -- struct snd_soc_card *card = simple_priv_to_card(priv); -+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component; - int found_jack_index = 0; - int type = 0; -@@ -1026,8 +997,9 @@ EXPORT_SYMBOL_GPL(simple_util_init_priv); - void simple_util_remove(struct platform_device *pdev) - { - struct snd_soc_card *card = platform_get_drvdata(pdev); -+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card); - -- simple_util_clean_reference(card); -+ simple_util_clean_reference(priv); - } - EXPORT_SYMBOL_GPL(simple_util_remove); - -diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c ---- a/sound/soc/generic/simple-card.c -+++ b/sound/soc/generic/simple-card.c -@@ -517,44 +517,6 @@ static int simple_populate_aux(struct simple_util_priv *priv) - return simple_ret(priv, ret); - } - --static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) --{ -- struct snd_soc_card *card = simple_priv_to_card(priv); -- int ret; -- -- ret = simple_util_parse_widgets(card, PREFIX); -- if (ret < 0) -- goto end; -- -- ret = simple_util_parse_routing(card, PREFIX); -- if (ret < 0) -- goto end; -- -- ret = simple_util_parse_pin_switches(card, PREFIX); -- if (ret < 0) -- goto end; -- -- /* Single/Muti DAI link(s) & New style of DT node */ -- memset(li, 0, sizeof(*li)); -- ret = simple_for_each_link(priv, li, -- simple_dai_link_of, -- simple_dai_link_of_dpcm); -- if (ret < 0) -- goto end; -- -- ret = simple_util_parse_card_name(priv, PREFIX); -- if (ret < 0) -- goto end; -- -- ret = simple_populate_aux(priv); -- if (ret < 0) -- goto end; -- -- ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); --end: -- return simple_ret(priv, ret); --} -- - static int simple_count_noml(struct simple_util_priv *priv, - struct device_node *np, - struct device_node *codec, -@@ -699,28 +661,19 @@ static int simple_soc_probe(struct snd_soc_card *card) - if (ret < 0) - goto end; - -- ret = simple_util_init_aux_jacks(priv, PREFIX); -+ ret = simple_util_init_aux_jacks(card, PREFIX); - end: - return simple_ret(priv, ret); - } - --static int simple_probe(struct platform_device *pdev) -+static int simple_parse_of(struct simple_util_priv *priv) - { -- struct simple_util_priv *priv; -- struct device *dev = &pdev->dev; -- struct snd_soc_card *card; -- int ret; -+ struct snd_soc_card *card = simple_priv_to_card(priv); -+ struct device *dev = card->dev; -+ int ret = -EINVAL; - -- /* Allocate the private data and the DAI link array */ -- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -- if (!priv) -- return -ENOMEM; -- -- card = simple_priv_to_card(priv); -- card->owner = THIS_MODULE; -- card->dev = dev; -- card->probe = simple_soc_probe; -- card->driver_name = "simple-card"; -+ if (!dev) -+ return simple_ret(priv, ret); - - ret = -ENOMEM; - struct link_info *li __free(kfree) = kzalloc_obj(*li); -@@ -739,25 +692,71 @@ static int simple_probe(struct platform_device *pdev) - if (ret < 0) - goto end; - -- ret = simple_parse_of(priv, li); -- if (ret < 0) { -- dev_err_probe(dev, ret, "parse error\n"); -+ ret = simple_util_parse_widgets(priv, PREFIX); -+ if (ret < 0) -+ goto end; -+ -+ ret = simple_util_parse_routing(priv, PREFIX); -+ if (ret < 0) -+ goto end; -+ -+ ret = simple_util_parse_pin_switches(priv, PREFIX); -+ if (ret < 0) -+ goto end; -+ -+ ret = simple_util_parse_aux_devs(priv, PREFIX); -+ if (ret < 0) -+ goto err; -+ -+ /* Single/Muti DAI link(s) & New style of DT node */ -+ memset(li, 0, sizeof(*li)); -+ ret = simple_for_each_link(priv, li, -+ simple_dai_link_of, -+ simple_dai_link_of_dpcm); -+ if (ret < 0) -+ goto err; -+ -+ /* Card name should be set after simple_for_each_link() */ -+ ret = simple_util_parse_card_name(priv, PREFIX); -+ if (ret < 0) -+ goto err; -+ -+ ret = simple_populate_aux(priv); -+ if (ret < 0) - goto err; -- } - - snd_soc_card_set_drvdata(card, priv); - - simple_util_debug_info(priv); - - ret = devm_snd_soc_register_card(dev, card); -- if (ret < 0) -- goto err; -- -- return 0; - err: -- simple_util_clean_reference(card); -+ if (ret < 0) { -+ simple_util_clean_reference(priv); -+ return dev_err_probe(dev, ret, "parse error\n"); -+ } - end: -- return dev_err_probe(dev, ret, "parse error\n"); -+ return simple_ret(priv, ret); -+} -+ -+static int simple_probe(struct platform_device *pdev) -+{ -+ struct simple_util_priv *priv; -+ struct device *dev = &pdev->dev; -+ struct snd_soc_card *card; -+ -+ /* Allocate the private data and the DAI link array */ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ card = simple_priv_to_card(priv); -+ card->owner = THIS_MODULE; -+ card->dev = dev; -+ card->probe = simple_soc_probe; -+ card->driver_name = "simple-card"; -+ -+ return simple_parse_of(priv); - } - - static const struct of_device_id simple_of_match[] = { -diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c ---- a/sound/soc/intel/atom/sst-atom-controls.c -+++ b/sound/soc/intel/atom/sst-atom-controls.c -@@ -14,6 +14,7 @@ - */ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -+#include - #include - #include - #include -@@ -73,14 +74,10 @@ static int sst_fill_and_send_cmd(struct sst_data *drv, - u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, - void *cmd_data, u16 len) - { -- int ret; -+ guard(mutex)(&drv->lock); - -- mutex_lock(&drv->lock); -- ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, -- task_id, pipe_id, cmd_data, len); -- mutex_unlock(&drv->lock); -- -- return ret; -+ return sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, -+ task_id, pipe_id, cmd_data, len); - } - - /* -@@ -167,7 +164,7 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol, - unsigned int val, mux; - u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map; - -- mutex_lock(&drv->lock); -+ guard(mutex)(&drv->lock); - val = 1 << ctl_no; - /* search which slot/channel has this bit set - there should be only one */ - for (mux = e->max; mux > 0; mux--) -@@ -175,7 +172,6 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol, - break; - - ucontrol->value.enumerated.item[0] = mux; -- mutex_unlock(&drv->lock); - - dev_dbg(c->dev, "%s - %s map = %#x\n", - is_tx ? "tx channel" : "rx slot", -@@ -235,7 +231,7 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol, - if (mux > e->max - 1) - return -EINVAL; - -- mutex_lock(&drv->lock); -+ guard(mutex)(&drv->lock); - /* first clear all registers of this bit */ - for (i = 0; i < e->max; i++) - map[i] &= ~val; -@@ -244,7 +240,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol, - /* kctl set to 'none' and we reset the bits so send IPC */ - ret = sst_check_and_send_slot_map(drv, kcontrol); - -- mutex_unlock(&drv->lock); - return ret; - } - -@@ -258,7 +253,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol, - - ret = sst_check_and_send_slot_map(drv, kcontrol); - -- mutex_unlock(&drv->lock); - return ret; - } - -@@ -354,13 +348,12 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol, - struct sst_algo_control *bc = (void *)kcontrol->private_value; - - dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name); -- mutex_lock(&drv->lock); -+ guard(mutex)(&drv->lock); - switch (bc->type) { - case SST_ALGO_PARAMS: - memcpy(bc->params, ucontrol->value.bytes.data, bc->max); - break; - default: -- mutex_unlock(&drv->lock); - dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n", - bc->type); - return -EINVAL; -@@ -368,7 +361,6 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol, - /*if pipe is enabled, need to send the algo params from here*/ - if (bc->w && bc->w->power) - ret = sst_send_algo_cmd(drv, bc); -- mutex_unlock(&drv->lock); - - return ret; - } -@@ -475,7 +467,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, - struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; - struct sst_gain_value *gv = mc->gain_val; - -- mutex_lock(&drv->lock); -+ guard(mutex)(&drv->lock); - - switch (mc->type) { - case SST_GAIN_TLV: -@@ -497,7 +489,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, - break; - - default: -- mutex_unlock(&drv->lock); - dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n", - mc->type); - return -EINVAL; -@@ -506,7 +497,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, - if (mc->w && mc->w->power) - ret = sst_send_gain_cmd(drv, gv, mc->task_id, - mc->pipe_id | mc->instance_id, mc->module_id, 0); -- mutex_unlock(&drv->lock); - - return ret; - } -@@ -521,10 +511,9 @@ static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w, - struct sst_data *drv = snd_soc_component_get_drvdata(c); - struct sst_ids *ids = w->priv; - -- mutex_lock(&drv->lock); -+ guard(mutex)(&drv->lock); - sst_find_and_send_pipe_algo(drv, w->name, ids); - sst_set_pipe_gain(ids, drv, 0); -- mutex_unlock(&drv->lock); - - return 0; - } -@@ -761,27 +750,29 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) - return ret; - } - -- mutex_lock(&drv->lock); -- if (enable) -- timer_usage++; -- else -- timer_usage--; -- -- /* -- * Send the command only if this call is the first enable or last -- * disable -- */ -- if ((enable && (timer_usage == 1)) || -- (!enable && (timer_usage == 0))) { -- ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD, -- SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd, -- sizeof(cmd.header) + cmd.header.length); -- if (ret && enable) { -+ scoped_guard(mutex, &drv->lock) { -+ if (enable) -+ timer_usage++; -+ else - timer_usage--; -- enable = false; -+ -+ /* -+ * Send the command only if this call is the first enable or last -+ * disable -+ */ -+ if ((enable && timer_usage == 1) || -+ (!enable && timer_usage == 0)) { -+ ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD, -+ SST_FLAG_BLOCKED, -+ SST_TASK_SBA, 0, &cmd, -+ sizeof(cmd.header) + -+ cmd.header.length); -+ if (ret && enable) { -+ timer_usage--; -+ enable = false; -+ } - } - } -- mutex_unlock(&drv->lock); - - if (!enable) - sst->ops->power(sst->dev, false); -diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c ---- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c -+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c -@@ -11,6 +11,7 @@ - */ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -+#include - #include - #include - #include -@@ -32,7 +33,7 @@ int sst_register_dsp(struct sst_device *dev) - return -EINVAL; - if (!try_module_get(dev->dev->driver->owner)) - return -ENODEV; -- mutex_lock(&sst_lock); -+ guard(mutex)(&sst_lock); - if (sst) { - dev_err(dev->dev, "we already have a device %s\n", sst->name); - module_put(dev->dev->driver->owner); -@@ -41,7 +42,7 @@ int sst_register_dsp(struct sst_device *dev) - } - dev_dbg(dev->dev, "registering device %s\n", dev->name); - sst = dev; -- mutex_unlock(&sst_lock); -+ - return 0; - } - EXPORT_SYMBOL_GPL(sst_register_dsp); -@@ -53,17 +54,15 @@ int sst_unregister_dsp(struct sst_device *dev) - if (dev != sst) - return -EINVAL; - -- mutex_lock(&sst_lock); -+ guard(mutex)(&sst_lock); - -- if (!sst) { -- mutex_unlock(&sst_lock); -+ if (!sst) - return -EIO; -- } - - module_put(sst->dev->driver->owner); - dev_dbg(dev->dev, "unreg %s\n", sst->name); - sst = NULL; -- mutex_unlock(&sst_lock); -+ - return 0; - } - EXPORT_SYMBOL_GPL(sst_unregister_dsp); -@@ -103,21 +102,14 @@ static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream) - void sst_set_stream_status(struct sst_runtime_stream *stream, - int state) - { -- unsigned long flags; -- spin_lock_irqsave(&stream->status_lock, flags); -+ guard(spinlock_irqsave)(&stream->status_lock); - stream->stream_status = state; -- spin_unlock_irqrestore(&stream->status_lock, flags); - } - - static inline int sst_get_stream_status(struct sst_runtime_stream *stream) - { -- int state; -- unsigned long flags; -- -- spin_lock_irqsave(&stream->status_lock, flags); -- state = stream->stream_status; -- spin_unlock_irqrestore(&stream->status_lock, flags); -- return state; -+ guard(spinlock_irqsave)(&stream->status_lock); -+ return stream->stream_status; - } - - static void sst_fill_alloc_params(struct snd_pcm_substream *substream, -@@ -244,12 +236,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, - - stream->stream_info.str_id = str_params.stream_id; - -- ret_val = stream->ops->open(sst->dev, &str_params); -- if (ret_val <= 0) -- return ret_val; -- -- -- return ret_val; -+ return stream->ops->open(sst->dev, &str_params); - } - - static void sst_period_elapsed(void *arg) -@@ -304,7 +291,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, - { - int ret_val = 0; - struct snd_pcm_runtime *runtime = substream->runtime; -- struct sst_runtime_stream *stream; -+ struct sst_runtime_stream *stream __free(kfree) = NULL; - - stream = kzalloc_obj(*stream); - if (!stream) -@@ -312,15 +299,14 @@ static int sst_media_open(struct snd_pcm_substream *substream, - spin_lock_init(&stream->status_lock); - - /* get the sst ops */ -- mutex_lock(&sst_lock); -- if (!sst || -- !try_module_get(sst->dev->driver->owner)) { -- dev_err(dai->dev, "no device available to run\n"); -- ret_val = -ENODEV; -- goto out_ops; -+ scoped_guard(mutex, &sst_lock) { -+ if (!sst || -+ !try_module_get(sst->dev->driver->owner)) { -+ dev_err(dai->dev, "no device available to run\n"); -+ return -ENODEV; -+ } -+ stream->ops = sst->ops; - } -- stream->ops = sst->ops; -- mutex_unlock(&sst_lock); - - stream->stream_info.str_id = 0; - -@@ -330,7 +316,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, - - ret_val = power_up_sst(stream); - if (ret_val < 0) -- goto out_power_up; -+ return ret_val; - - /* - * Make sure the period to be multiple of 1ms to align the -@@ -347,12 +333,14 @@ static int sst_media_open(struct snd_pcm_substream *substream, - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIODS, 2); - -- return snd_pcm_hw_constraint_integer(runtime, -- SNDRV_PCM_HW_PARAM_PERIODS); --out_ops: -- mutex_unlock(&sst_lock); --out_power_up: -- kfree(stream); -+ ret_val = snd_pcm_hw_constraint_integer(runtime, -+ SNDRV_PCM_HW_PARAM_PERIODS); -+ -+ if (ret_val < 0) -+ return ret_val; -+ -+ stream = NULL; -+ - return ret_val; - } - -diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c ---- a/sound/soc/intel/atom/sst/sst_ipc.c -+++ b/sound/soc/intel/atom/sst/sst_ipc.c -@@ -11,6 +11,7 @@ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -+#include - #include - #include - #include -@@ -180,9 +181,8 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) - union interrupt_reg_mrfld isr; - union interrupt_reg_mrfld imr; - union ipc_header_mrfld clear_ipc; -- unsigned long irq_flags; - -- spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); -+ guard(spinlock_irqsave)(&sst_drv_ctx->ipc_spin_lock); - imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX); - isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX); - -@@ -200,7 +200,6 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) - /* un mask busy interrupt */ - imr.part.busy_interrupt = 0; - sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full); -- spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); - } - - -diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c ---- a/sound/soc/intel/atom/sst/sst_pvt.c -+++ b/sound/soc/intel/atom/sst/sst_pvt.c -@@ -11,6 +11,7 @@ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -+#include - #include - #include - #include -@@ -64,9 +65,8 @@ u64 sst_shim_read64(void __iomem *addr, int offset) - void sst_set_fw_state_locked( - struct intel_sst_drv *sst_drv_ctx, int sst_state) - { -- mutex_lock(&sst_drv_ctx->sst_lock); -+ guard(mutex)(&sst_drv_ctx->sst_lock); - sst_drv_ctx->sst_state = sst_state; -- mutex_unlock(&sst_drv_ctx->sst_lock); - } - - /* -@@ -302,18 +302,17 @@ int sst_assign_pvt_id(struct intel_sst_drv *drv) - { - int local; - -- spin_lock(&drv->block_lock); -+ guard(spinlock)(&drv->block_lock); - /* find first zero index from lsb */ - local = ffz(drv->pvt_id); - dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local); - if (local >= SST_MAX_BLOCKS){ -- spin_unlock(&drv->block_lock); - dev_err(drv->dev, "PVT _ID error: no free id blocks "); - return -EINVAL; - } - /* toggle the index */ - change_bit(local, &drv->pvt_id); -- spin_unlock(&drv->block_lock); -+ - return local; - } - -diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c ---- a/sound/soc/intel/avs/apl.c -+++ b/sound/soc/intel/avs/apl.c -@@ -6,6 +6,7 @@ - // Amadeusz Slawinski - // - -+#include - #include - #include - #include -@@ -190,7 +191,7 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev) - { - struct avs_path *path; - -- spin_lock(&adev->path_list_lock); -+ guard(spinlock)(&adev->path_list_lock); - /* Any gateway without buffer allocated in LP area disqualifies D0IX. */ - list_for_each_entry(path, &adev->path_list, node) { - struct avs_path_pipeline *ppl; -@@ -210,14 +211,11 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev) - if (cfg->copier.dma_type == INVALID_OBJECT_ID) - continue; - -- if (!mod->gtw_attrs.lp_buffer_alloc) { -- spin_unlock(&adev->path_list_lock); -+ if (!mod->gtw_attrs.lp_buffer_alloc) - return false; -- } - } - } - } -- spin_unlock(&adev->path_list_lock); - - return true; - } -diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h ---- a/sound/soc/intel/avs/avs.h -+++ b/sound/soc/intel/avs/avs.h -@@ -336,14 +336,13 @@ int avs_icl_load_basefw(struct avs_dev *adev, struct firmware *fw); - /* Soc component members */ - - struct avs_soc_component { -- struct snd_soc_component base; -+ struct snd_soc_component *base; - struct avs_tplg *tplg; - - struct list_head node; - }; - --#define to_avs_soc_component(comp) \ -- container_of(comp, struct avs_soc_component, base) -+#define to_avs_soc_component(comp) snd_soc_component_to_priv(comp) - - extern const struct snd_soc_dai_ops avs_dai_fe_ops; - -diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c ---- a/sound/soc/intel/avs/boards/da7219.c -+++ b/sound/soc/intel/avs/boards/da7219.c -@@ -175,7 +175,6 @@ static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot, - if (!dl || !platform) - return -ENOMEM; - -- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); - dl->name = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); - dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); -@@ -259,10 +258,8 @@ static int avs_da7219_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_da7219_driver_ids[] = { -- { -- .name = "avs_da7219", -- }, -- {}, -+ { .name = "avs_da7219" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_da7219_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c ---- a/sound/soc/intel/avs/boards/dmic.c -+++ b/sound/soc/intel/avs/boards/dmic.c -@@ -104,10 +104,8 @@ static int avs_dmic_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_dmic_driver_ids[] = { -- { -- .name = "avs_dmic", -- }, -- {}, -+ { .name = "avs_dmic" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c ---- a/sound/soc/intel/avs/boards/es8336.c -+++ b/sound/soc/intel/avs/boards/es8336.c -@@ -309,10 +309,8 @@ static int avs_es8336_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_es8336_driver_ids[] = { -- { -- .name = "avs_es8336", -- }, -- {}, -+ { .name = "avs_es8336" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_es8336_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c ---- a/sound/soc/intel/avs/boards/hdaudio.c -+++ b/sound/soc/intel/avs/boards/hdaudio.c -@@ -231,10 +231,8 @@ static int avs_hdaudio_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_hdaudio_driver_ids[] = { -- { -- .name = "avs_hdaudio", -- }, -- {}, -+ { .name = "avs_hdaudio" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c ---- a/sound/soc/intel/avs/boards/i2s_test.c -+++ b/sound/soc/intel/avs/boards/i2s_test.c -@@ -107,10 +107,8 @@ static int avs_i2s_test_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_i2s_test_driver_ids[] = { -- { -- .name = "avs_i2s_test", -- }, -- {}, -+ { .name = "avs_i2s_test" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_i2s_test_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c ---- a/sound/soc/intel/avs/boards/max98357a.c -+++ b/sound/soc/intel/avs/boards/max98357a.c -@@ -136,10 +136,8 @@ static int avs_max98357a_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_max98357a_driver_ids[] = { -- { -- .name = "avs_max98357a", -- }, -- {}, -+ { .name = "avs_max98357a" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_max98357a_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c ---- a/sound/soc/intel/avs/boards/max98373.c -+++ b/sound/soc/intel/avs/boards/max98373.c -@@ -191,10 +191,8 @@ static int avs_max98373_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_max98373_driver_ids[] = { -- { -- .name = "avs_max98373", -- }, -- {}, -+ { .name = "avs_max98373" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_max98373_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c ---- a/sound/soc/intel/avs/boards/max98927.c -+++ b/sound/soc/intel/avs/boards/max98927.c -@@ -188,10 +188,8 @@ static int avs_max98927_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_max98927_driver_ids[] = { -- { -- .name = "avs_max98927", -- }, -- {}, -+ { .name = "avs_max98927" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_max98927_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c ---- a/sound/soc/intel/avs/boards/nau8825.c -+++ b/sound/soc/intel/avs/boards/nau8825.c -@@ -293,10 +293,8 @@ static int avs_nau8825_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_nau8825_driver_ids[] = { -- { -- .name = "avs_nau8825", -- }, -- {}, -+ { .name = "avs_nau8825" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_nau8825_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c ---- a/sound/soc/intel/avs/boards/pcm3168a.c -+++ b/sound/soc/intel/avs/boards/pcm3168a.c -@@ -132,10 +132,8 @@ static int avs_pcm3168a_probe(struct platform_device *pdev) - } - - static const struct platform_device_id avs_pcm3168a_driver_ids[] = { -- { -- .name = "avs_pcm3168a", -- }, -- {}, -+ { .name = "avs_pcm3168a" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c ---- a/sound/soc/intel/avs/boards/probe.c -+++ b/sound/soc/intel/avs/boards/probe.c -@@ -64,7 +64,7 @@ static const struct platform_device_id avs_probe_mb_driver_ids[] = { - { - .name = "avs_probe_mb", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_probe_mb_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c ---- a/sound/soc/intel/avs/boards/rt274.c -+++ b/sound/soc/intel/avs/boards/rt274.c -@@ -261,7 +261,7 @@ static const struct platform_device_id avs_rt274_driver_ids[] = { - { - .name = "avs_rt274", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_rt274_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c ---- a/sound/soc/intel/avs/boards/rt286.c -+++ b/sound/soc/intel/avs/boards/rt286.c -@@ -231,7 +231,7 @@ static const struct platform_device_id avs_rt286_driver_ids[] = { - { - .name = "avs_rt286", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_rt286_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c ---- a/sound/soc/intel/avs/boards/rt298.c -+++ b/sound/soc/intel/avs/boards/rt298.c -@@ -250,7 +250,7 @@ static const struct platform_device_id avs_rt298_driver_ids[] = { - { - .name = "avs_rt298", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_rt298_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c ---- a/sound/soc/intel/avs/boards/rt5514.c -+++ b/sound/soc/intel/avs/boards/rt5514.c -@@ -178,7 +178,7 @@ static const struct platform_device_id avs_rt5514_driver_ids[] = { - { - .name = "avs_rt5514", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_rt5514_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c ---- a/sound/soc/intel/avs/boards/rt5640.c -+++ b/sound/soc/intel/avs/boards/rt5640.c -@@ -252,7 +252,7 @@ static const struct platform_device_id avs_rt5640_driver_ids[] = { - { - .name = "avs_rt5640", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c ---- a/sound/soc/intel/avs/boards/rt5663.c -+++ b/sound/soc/intel/avs/boards/rt5663.c -@@ -249,7 +249,7 @@ static const struct platform_device_id avs_rt5663_driver_ids[] = { - { - .name = "avs_rt5663", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_rt5663_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c ---- a/sound/soc/intel/avs/boards/rt5682.c -+++ b/sound/soc/intel/avs/boards/rt5682.c -@@ -325,7 +325,7 @@ static const struct platform_device_id avs_rt5682_driver_ids[] = { - { - .name = "avs_rt5682", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_rt5682_driver_ids); - -diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c ---- a/sound/soc/intel/avs/boards/ssm4567.c -+++ b/sound/soc/intel/avs/boards/ssm4567.c -@@ -180,7 +180,7 @@ static const struct platform_device_id avs_ssm4567_driver_ids[] = { - { - .name = "avs_ssm4567", - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, avs_ssm4567_driver_ids); - -diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c ---- a/sound/soc/intel/avs/control.c -+++ b/sound/soc/intel/avs/control.c -@@ -27,7 +27,7 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i - struct avs_path_pipeline *ppl; - struct avs_path_module *mod; - -- spin_lock(&adev->path_list_lock); -+ guard(spinlock)(&adev->path_list_lock); - list_for_each_entry(path, &adev->path_list, node) { - list_for_each_entry(ppl, &path->ppl_list, node) { - list_for_each_entry(mod, &ppl->mod_list, node) { -@@ -35,14 +35,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i - - if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) || - guid_equal(type, &AVS_GAIN_MOD_UUID)) && -- mod->template->ctl_id == id) { -- spin_unlock(&adev->path_list_lock); -+ mod->template->ctl_id == id) - return mod; -- } - } - } - } -- spin_unlock(&adev->path_list_lock); - - return NULL; - } -diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c ---- a/sound/soc/intel/avs/core.c -+++ b/sound/soc/intel/avs/core.c -@@ -14,6 +14,7 @@ - // foundation of this driver - // - -+#include - #include - #include - #include -@@ -273,7 +274,7 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus) - if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream)) - ret = IRQ_HANDLED; - -- spin_lock_irq(&bus->reg_lock); -+ guard(spinlock_irq)(&bus->reg_lock); - /* Clear RIRB interrupt. */ - status = snd_hdac_chip_readb(bus, RIRBSTS); - if (status & RIRB_INT_MASK) { -@@ -283,7 +284,6 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus) - ret = IRQ_HANDLED; - } - -- spin_unlock_irq(&bus->reg_lock); - return ret; - } - -diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h ---- a/sound/soc/intel/avs/debug.h -+++ b/sound/soc/intel/avs/debug.h -@@ -9,6 +9,7 @@ - #ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H - #define __SOUND_SOC_INTEL_AVS_DEBUG_H - -+#include - #include "messages.h" - #include "registers.h" - -@@ -26,14 +27,9 @@ struct avs_dev; - - static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg) - { -- unsigned long flags; -- int ret; -+ guard(spinlock_irqsave)(&adev->trace_lock); - -- spin_lock_irqsave(&adev->trace_lock, flags); -- ret = avs_dsp_op(adev, log_buffer_status, msg); -- spin_unlock_irqrestore(&adev->trace_lock, flags); -- -- return ret; -+ return avs_dsp_op(adev, log_buffer_status, msg); - } - - struct avs_apl_log_buffer_layout { -diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c ---- a/sound/soc/intel/avs/debugfs.c -+++ b/sound/soc/intel/avs/debugfs.c -@@ -6,9 +6,9 @@ - // Amadeusz Slawinski - // - -+#include - #include - #include --#include - #include - #include - #include -@@ -236,20 +236,15 @@ static int strace_open(struct inode *inode, struct file *file) - if (!try_module_get(adev->dev->driver->owner)) - return -ENODEV; - -- if (kfifo_initialized(&adev->trace_fifo)) { -- ret = -EBUSY; -- goto err; -- } -+ if (kfifo_initialized(&adev->trace_fifo)) -+ return -EBUSY; - - ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL); - if (ret < 0) -- goto err; -+ return ret; - - file->private_data = adev; - return 0; --err: -- module_put(adev->dev->driver->owner); -- return ret; - } - - static int strace_release(struct inode *inode, struct file *file) -@@ -257,24 +252,22 @@ static int strace_release(struct inode *inode, struct file *file) - union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS); - struct avs_dev *adev = file->private_data; - unsigned long resource_mask; -- unsigned long flags, i; -+ unsigned long i; - u32 num_cores; - - resource_mask = adev->logged_resources; - num_cores = adev->hw_cfg.dsp_cores; - -- spin_lock_irqsave(&adev->trace_lock, flags); -+ scoped_guard(spinlock_irqsave, &adev->trace_lock) { -+ /* Gather any remaining logs. */ -+ for_each_set_bit(i, &resource_mask, num_cores) { -+ msg.log.core = i; -+ avs_dsp_op(adev, log_buffer_status, &msg); -+ } - -- /* Gather any remaining logs. */ -- for_each_set_bit(i, &resource_mask, num_cores) { -- msg.log.core = i; -- avs_dsp_op(adev, log_buffer_status, &msg); -+ kfifo_free(&adev->trace_fifo); - } - -- kfifo_free(&adev->trace_fifo); -- -- spin_unlock_irqrestore(&adev->trace_lock, flags); -- - module_put(adev->dev->driver->owner); - return 0; - } -diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c ---- a/sound/soc/intel/avs/ipc.c -+++ b/sound/soc/intel/avs/ipc.c -@@ -6,6 +6,7 @@ - // Amadeusz Slawinski - // - -+#include - #include - #include - #include -@@ -99,39 +100,39 @@ static void avs_dsp_recovery(struct avs_dev *adev) - unsigned int core_mask; - int ret; - -- mutex_lock(&adev->comp_list_mutex); -- /* disconnect all running streams */ -- list_for_each_entry(acomp, &adev->comp_list, node) { -- struct snd_soc_pcm_runtime *rtd; -- struct snd_soc_card *card; -+ scoped_guard(mutex, &adev->comp_list_mutex) { -+ /* disconnect all running streams */ -+ list_for_each_entry(acomp, &adev->comp_list, node) { -+ struct snd_soc_pcm_runtime *rtd; -+ struct snd_soc_card *card; - -- card = acomp->base.card; -- if (!card) -- continue; -- -- for_each_card_rtds(card, rtd) { -- struct snd_pcm *pcm; -- int dir; -- -- pcm = rtd->pcm; -- if (!pcm || rtd->dai_link->no_pcm) -+ card = acomp->base->card; -+ if (!card) - continue; - -- for_each_pcm_streams(dir) { -- struct snd_pcm_substream *substream; -+ for_each_card_rtds(card, rtd) { -+ struct snd_pcm *pcm; -+ int dir; - -- substream = pcm->streams[dir].substream; -- if (!substream || !substream->runtime) -+ pcm = rtd->pcm; -+ if (!pcm || rtd->dai_link->no_pcm) - continue; - -- /* No need for _irq() as we are in nonatomic context. */ -- snd_pcm_stream_lock(substream); -- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); -- snd_pcm_stream_unlock(substream); -+ for_each_pcm_streams(dir) { -+ struct snd_pcm_substream *substream; -+ -+ substream = pcm->streams[dir].substream; -+ if (!substream || !substream->runtime) -+ continue; -+ -+ /* No need for _irq() as we are in nonatomic context. */ -+ snd_pcm_stream_lock(substream); -+ snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); -+ snd_pcm_stream_unlock(substream); -+ } - } - } - } -- mutex_unlock(&adev->comp_list_mutex); - - /* forcibly shutdown all cores */ - core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0); -@@ -397,7 +398,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request - if (!ipc->ready) - return -EPERM; - -- mutex_lock(&ipc->msg_mutex); -+ guard(mutex)(&ipc->msg_mutex); - - spin_lock(&ipc->rx_lock); - avs_ipc_msg_init(ipc, reply); -@@ -412,7 +413,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request - /* Same treatment as on exception, just stack_dump=0. */ - avs_dsp_exception_caught(adev, &msg); - } -- goto exit; -+ return ret; - } - - ret = ipc->rx.rsp.status; -@@ -436,8 +437,6 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request - memcpy(reply->data, ipc->rx.data, reply->size); - } - --exit: -- mutex_unlock(&ipc->msg_mutex); - return ret; - } - -@@ -501,7 +500,7 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req - struct avs_ipc *ipc = adev->ipc; - int ret; - -- mutex_lock(&ipc->msg_mutex); -+ guard(mutex)(&ipc->msg_mutex); - - spin_lock(&ipc->rx_lock); - avs_ipc_msg_init(ipc, NULL); -@@ -522,8 +521,6 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req - dev_err(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n", - name, request->glb.primary, request->glb.ext.val, ret); - -- mutex_unlock(&ipc->msg_mutex); -- - return ret; - } - -diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c ---- a/sound/soc/intel/avs/loader.c -+++ b/sound/soc/intel/avs/loader.c -@@ -6,6 +6,7 @@ - // Amadeusz Slawinski - // - -+#include - #include - #include - #include -@@ -630,15 +631,15 @@ static int avs_load_firmware(struct avs_dev *adev, bool purge) - if (ret) - goto reenable_gating; - -- mutex_lock(&adev->comp_list_mutex); -- list_for_each_entry(acomp, &adev->comp_list, node) { -- struct avs_tplg *tplg = acomp->tplg; -+ scoped_guard(mutex, &adev->comp_list_mutex) { -+ list_for_each_entry(acomp, &adev->comp_list, node) { -+ struct avs_tplg *tplg = acomp->tplg; - -- ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); -- if (ret < 0) -- break; -+ ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); -+ if (ret < 0) -+ break; -+ } - } -- mutex_unlock(&adev->comp_list_mutex); - - reenable_gating: - avs_hda_l1sen_enable(adev, true); -diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c ---- a/sound/soc/intel/avs/path.c -+++ b/sound/soc/intel/avs/path.c -@@ -6,6 +6,7 @@ - // Amadeusz Slawinski - // - -+#include - #include - #include - #include -@@ -69,16 +70,13 @@ avs_path_find_path(struct avs_dev *adev, const char *name, u32 template_id) - if (!template) - return NULL; - -- spin_lock(&adev->path_list_lock); -+ guard(spinlock)(&adev->path_list_lock); - /* Only one variant of given path template may be instantiated at a time. */ - list_for_each_entry(path, &adev->path_list, node) { -- if (path->template->owner == template) { -- spin_unlock(&adev->path_list_lock); -+ if (path->template->owner == template) - return path; -- } - } - -- spin_unlock(&adev->path_list_lock); - return NULL; - } - -@@ -1300,7 +1298,7 @@ void avs_path_free(struct avs_path *path) - struct avs_path *cpath, *csave; - struct avs_dev *adev = path->owner; - -- mutex_lock(&adev->path_mutex); -+ guard(mutex)(&adev->path_mutex); - - /* Free all condpaths this path spawned. */ - list_for_each_entry_safe(cpath, csave, &path->source_list, source_node) -@@ -1309,8 +1307,6 @@ void avs_path_free(struct avs_path *path) - avs_condpath_free(path->owner, cpath); - - avs_path_free_unlocked(path); -- -- mutex_unlock(&adev->path_mutex); - } - - struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, -@@ -1329,13 +1325,13 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, - } - - /* Serialize path and its components creation. */ -- mutex_lock(&adev->path_mutex); -+ guard(mutex)(&adev->path_mutex); - /* Satisfy needs of avs_path_find_tplg(). */ -- mutex_lock(&adev->comp_list_mutex); -+ guard(mutex)(&adev->comp_list_mutex); - - path = avs_path_create_unlocked(adev, dma_id, variant); - if (IS_ERR(path)) -- goto exit; -+ return path; - - ret = avs_condpaths_walk_all(adev, path); - if (ret) { -@@ -1343,10 +1339,6 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, - path = ERR_PTR(ret); - } - --exit: -- mutex_unlock(&adev->comp_list_mutex); -- mutex_unlock(&adev->path_mutex); -- - return path; - } - -@@ -1491,15 +1483,13 @@ static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path) - { - struct avs_path *cpath; - -- mutex_lock(&adev->path_mutex); -+ guard(mutex)(&adev->path_mutex); - - /* If either source or sink stops, so do the attached conditional paths. */ - list_for_each_entry(cpath, &path->source_list, source_node) - avs_condpath_pause(adev, cpath); - list_for_each_entry(cpath, &path->sink_list, sink_node) - avs_condpath_pause(adev, cpath); -- -- mutex_unlock(&adev->path_mutex); - } - - int avs_path_pause(struct avs_path *path) -@@ -1555,7 +1545,7 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t - { - struct avs_path *cpath; - -- mutex_lock(&adev->path_mutex); -+ guard(mutex)(&adev->path_mutex); - - /* Run conditional paths only if source and sink are both running. */ - list_for_each_entry(cpath, &path->source_list, source_node) -@@ -1567,8 +1557,6 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t - if (cpath->source->state == AVS_PPL_STATE_RUNNING && - cpath->sink->state == AVS_PPL_STATE_RUNNING) - avs_condpath_run(adev, cpath, trigger); -- -- mutex_unlock(&adev->path_mutex); - } - - int avs_path_run(struct avs_path *path, int trigger) -diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c ---- a/sound/soc/intel/avs/pcm.c -+++ b/sound/soc/intel/avs/pcm.c -@@ -959,7 +959,7 @@ static const struct file_operations topology_name_fops = { - static int avs_component_load_libraries(struct avs_soc_component *acomp) - { - struct avs_tplg *tplg = acomp->tplg; -- struct avs_dev *adev = to_avs_dev(acomp->base.dev); -+ struct avs_dev *adev = to_avs_dev(acomp->base->dev); - int ret; - - if (!tplg->num_libs) -@@ -1393,25 +1393,28 @@ int avs_register_component(struct device *dev, const char *name, - struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) - { - struct avs_soc_component *acomp; -- int ret; -+ const char *comp_name; - - acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL); - if (!acomp) - return -ENOMEM; - -- acomp->base.name = devm_kstrdup(dev, name, GFP_KERNEL); -- if (!acomp->base.name) -+ acomp->base = snd_soc_component_alloc(dev); -+ if (!acomp->base) -+ return -ENOMEM; -+ -+ comp_name = devm_kstrdup(dev, name, GFP_KERNEL); -+ if (!comp_name) - return -ENOMEM; - - INIT_LIST_HEAD(&acomp->node); - - drv->use_dai_pcm_id = !obsolete_card_names; - -- ret = snd_soc_component_initialize(&acomp->base, drv, dev); -- if (ret < 0) -- return ret; -+ snd_soc_component_set_name(acomp->base, comp_name); -+ snd_soc_component_set_priv(acomp->base, acomp); - -- return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); -+ return snd_soc_register_component(acomp->base, drv, cpu_dais, num_cpu_dais); - } - - static struct snd_soc_dai_driver dmic_cpu_dais[] = { -diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c ---- a/sound/soc/intel/avs/probes.c -+++ b/sound/soc/intel/avs/probes.c -@@ -296,19 +296,19 @@ static const struct snd_soc_component_driver avs_probe_component_driver = { - int avs_register_probe_component(struct avs_dev *adev, const char *name) - { - struct snd_soc_component *component; -- int ret; -+ const char *comp_name; - -- component = devm_kzalloc(adev->dev, sizeof(*component), GFP_KERNEL); -+ component = snd_soc_component_alloc(adev->dev); - if (!component) - return -ENOMEM; - -- component->name = devm_kstrdup(adev->dev, name, GFP_KERNEL); -- if (!component->name) -+ comp_name = devm_kstrdup(adev->dev, name, GFP_KERNEL); -+ if (!comp_name) - return -ENOMEM; - -- ret = snd_soc_component_initialize(component, &avs_probe_component_driver, adev->dev); -- if (ret) -- return ret; -+ snd_soc_component_set_name(component, comp_name); - -- return snd_soc_add_component(component, probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); -+ return snd_soc_register_component(component, -+ &avs_probe_component_driver, -+ probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); - } -diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c ---- a/sound/soc/intel/avs/topology.c -+++ b/sound/soc/intel/avs/topology.c -@@ -2229,7 +2229,7 @@ struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp) - - int avs_load_topology(struct snd_soc_component *comp, const char *filename) - { -- const struct firmware *fw; -+ const struct firmware *fw __free(firmware) = NULL; - int ret; - - ret = request_firmware(&fw, filename, comp->dev); -@@ -2242,7 +2242,6 @@ int avs_load_topology(struct snd_soc_component *comp, const char *filename) - if (ret < 0) - dev_err(comp->dev, "load topology \"%s\" failed: %d\n", filename, ret); - -- release_firmware(fw); - return ret; - } - -diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c ---- a/sound/soc/intel/avs/utils.c -+++ b/sound/soc/intel/avs/utils.c -@@ -6,6 +6,7 @@ - // Amadeusz Slawinski - // - -+#include - #include - #include - #include -@@ -48,13 +49,12 @@ int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_mo - { - int idx; - -- mutex_lock(&adev->modres_mutex); -+ guard(mutex)(&adev->modres_mutex); - - idx = avs_module_entry_index(adev, uuid); - if (idx >= 0) - memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry)); - -- mutex_unlock(&adev->modres_mutex); - return (idx < 0) ? idx : 0; - } - -@@ -62,13 +62,12 @@ int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_modu - { - int idx; - -- mutex_lock(&adev->modres_mutex); -+ guard(mutex)(&adev->modres_mutex); - - idx = avs_module_id_entry_index(adev, module_id); - if (idx >= 0) - memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry)); - -- mutex_unlock(&adev->modres_mutex); - return (idx < 0) ? idx : 0; - } - -@@ -86,13 +85,12 @@ bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id) - bool ret = false; - int idx; - -- mutex_lock(&adev->modres_mutex); -+ guard(mutex)(&adev->modres_mutex); - - idx = avs_module_id_entry_index(adev, module_id); - if (idx >= 0) - ret = ida_is_empty(adev->mod_idas[idx]); - -- mutex_unlock(&adev->modres_mutex); - return ret; - } - -@@ -163,68 +161,57 @@ int avs_module_info_init(struct avs_dev *adev, bool purge) - if (ret) - return AVS_IPC_RET(ret); - -- mutex_lock(&adev->modres_mutex); -+ guard(mutex)(&adev->modres_mutex); - - ret = avs_module_ida_alloc(adev, info, purge); - if (ret < 0) { - dev_err(adev->dev, "initialize module idas failed: %d\n", ret); -- goto exit; -+ return ret; - } - - /* Refresh current information with newly received table. */ - kfree(adev->mods_info); - adev->mods_info = info; - --exit: -- mutex_unlock(&adev->modres_mutex); - return ret; - } - - void avs_module_info_free(struct avs_dev *adev) - { -- mutex_lock(&adev->modres_mutex); -+ guard(mutex)(&adev->modres_mutex); - - avs_module_ida_destroy(adev); - kfree(adev->mods_info); - adev->mods_info = NULL; -- -- mutex_unlock(&adev->modres_mutex); - } - - int avs_module_id_alloc(struct avs_dev *adev, u16 module_id) - { -- int ret, idx, max_id; -+ int idx, max_id; - -- mutex_lock(&adev->modres_mutex); -+ guard(mutex)(&adev->modres_mutex); - - idx = avs_module_id_entry_index(adev, module_id); - if (idx == -ENOENT) { - dev_err(adev->dev, "invalid module id: %d", module_id); -- ret = -EINVAL; -- goto exit; -+ return -EINVAL; - } - max_id = adev->mods_info->entries[idx].instance_max_count - 1; -- ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL); --exit: -- mutex_unlock(&adev->modres_mutex); -- return ret; -+ -+ return ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL); - } - - void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id) - { - int idx; - -- mutex_lock(&adev->modres_mutex); -+ guard(mutex)(&adev->modres_mutex); - - idx = avs_module_id_entry_index(adev, module_id); -- if (idx == -ENOENT) { -+ if (idx == -ENOENT) - dev_err(adev->dev, "invalid module id: %d", module_id); -- goto exit; -- } -- -- ida_free(adev->mod_idas[idx], instance_id); --exit: -- mutex_unlock(&adev->modres_mutex); -+ else -+ ida_free(adev->mod_idas[idx], instance_id); - } - - /* -diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c ---- a/sound/soc/intel/boards/sof_sdw.c -+++ b/sound/soc/intel/boards/sof_sdw.c -@@ -1483,12 +1483,12 @@ static int mc_probe(struct platform_device *pdev) - dmi_check_system(sof_sdw_quirk_table); - - if (quirk_override != -1) { -- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", -+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n", - sof_sdw_quirk, quirk_override); - sof_sdw_quirk = quirk_override; - } - -- log_quirks(card->dev); -+ log_quirks(&pdev->dev); - - ctx->mc_quirk = sof_sdw_quirk; - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ -@@ -1507,13 +1507,13 @@ static int mc_probe(struct platform_device *pdev) - for (i = 0; i < ctx->codec_info_list_count; i++) - amp_num += codec_info_list[i].amp_num; - -- card->components = devm_kasprintf(card->dev, GFP_KERNEL, -+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, - " cfg-amp:%d", amp_num); - if (!card->components) - return -ENOMEM; - - if (mach->mach_params.dmic_num) { -- card->components = devm_kasprintf(card->dev, GFP_KERNEL, -+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL, - "%s mic:dmic cfg-mics:%d", - card->components, - mach->mach_params.dmic_num); -@@ -1524,7 +1524,7 @@ static int mc_probe(struct platform_device *pdev) - /* Register the card */ - ret = devm_snd_soc_register_card(card->dev, card); - if (ret) { -- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); -+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret); - asoc_sdw_mc_dailink_exit_loop(card); - return ret; - } -@@ -1542,8 +1542,8 @@ static void mc_remove(struct platform_device *pdev) - } - - static const struct platform_device_id mc_id_table[] = { -- { "sof_sdw", }, -- {} -+ { .name = "sof_sdw" }, -+ { } - }; - MODULE_DEVICE_TABLE(platform, mc_id_table); - -diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h ---- a/sound/soc/intel/catpt/core.h -+++ b/sound/soc/intel/catpt/core.h -@@ -139,9 +139,7 @@ int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request, - - int catpt_first_boot_firmware(struct catpt_dev *cdev); - int catpt_boot_firmware(struct catpt_dev *cdev, bool restore); --int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan); --int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan); --int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan); -+int catpt_store_firmware_context(struct catpt_dev *cdev); - int catpt_coredump(struct catpt_dev *cdev); - - #include -diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c ---- a/sound/soc/intel/catpt/device.c -+++ b/sound/soc/intel/catpt/device.c -@@ -28,44 +28,17 @@ - static int catpt_do_suspend(struct device *dev) - { - struct catpt_dev *cdev = dev_get_drvdata(dev); -- struct dma_chan *chan; - int ret; - -- chan = catpt_dma_request_config_chan(cdev); -- if (IS_ERR(chan)) -- return PTR_ERR(chan); -- - memset(&cdev->dx_ctx, 0, sizeof(cdev->dx_ctx)); - ret = catpt_ipc_enter_dxstate(cdev, CATPT_DX_STATE_D3, &cdev->dx_ctx); -- if (ret) { -- ret = CATPT_IPC_RET(ret); -- goto release_dma_chan; -- } -- -- ret = catpt_dsp_stall(cdev, true); - if (ret) -- goto release_dma_chan; -+ return CATPT_IPC_RET(ret); - -- ret = catpt_store_memdumps(cdev, chan); -- if (ret) { -- dev_err(cdev->dev, "store memdumps failed: %d\n", ret); -- goto release_dma_chan; -- } -- -- ret = catpt_store_module_states(cdev, chan); -- if (ret) { -- dev_err(cdev->dev, "store module states failed: %d\n", ret); -- goto release_dma_chan; -- } -- -- ret = catpt_store_streams_context(cdev, chan); -- if (ret) -- dev_err(cdev->dev, "store streams ctx failed: %d\n", ret); -- --release_dma_chan: -- dma_release_channel(chan); -+ ret = catpt_store_firmware_context(cdev); - if (ret) - return ret; -+ - return catpt_dsp_power_down(cdev); - } - -diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c ---- a/sound/soc/intel/catpt/loader.c -+++ b/sound/soc/intel/catpt/loader.c -@@ -26,7 +26,7 @@ struct catpt_fw_hdr { - u32 reserved[4]; - } __packed; - --struct catpt_fw_mod_hdr { -+struct catpt_fw_module_hdr { - char signature[FW_SIGNATURE_SIZE]; - u32 mod_size; - u32 blocks; -@@ -81,7 +81,7 @@ catpt_request_region(struct resource *root, resource_size_t size) - return __request_region(root, addr, size, NULL, 0); - } - --int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) -+static int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) - { - struct catpt_stream_runtime *stream; - -@@ -108,7 +108,7 @@ int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) - return 0; - } - --int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan) -+static int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan) - { - int i; - -@@ -138,7 +138,7 @@ int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan) - return 0; - } - --int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) -+static int catpt_store_dram_data(struct catpt_dev *cdev, struct dma_chan *chan) - { - int i; - -@@ -171,6 +171,39 @@ int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) - return 0; - } - -+int catpt_store_firmware_context(struct catpt_dev *cdev) -+{ -+ struct dma_chan *chan; -+ int ret; -+ -+ chan = catpt_dma_request_config_chan(cdev); -+ if (IS_ERR(chan)) -+ return PTR_ERR(chan); -+ -+ ret = catpt_dsp_stall(cdev, true); -+ if (ret) -+ goto exit; -+ -+ ret = catpt_store_dram_data(cdev, chan); -+ if (ret) { -+ dev_err(cdev->dev, "store memdumps failed: %d\n", ret); -+ goto exit; -+ } -+ -+ ret = catpt_store_module_states(cdev, chan); -+ if (ret) { -+ dev_err(cdev->dev, "store module states failed: %d\n", ret); -+ goto exit; -+ } -+ -+ ret = catpt_store_streams_context(cdev, chan); -+ if (ret) -+ dev_err(cdev->dev, "store streams ctx failed: %d\n", ret); -+exit: -+ dma_release_channel(chan); -+ return ret; -+} -+ - static int - catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) - { -@@ -199,7 +232,7 @@ catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan) - return 0; - } - --static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) -+static int catpt_restore_dram_data(struct catpt_dev *cdev, struct dma_chan *chan) - { - int i; - -@@ -234,9 +267,9 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan) - return 0; - } - --static int catpt_restore_fwimage(struct catpt_dev *cdev, -- struct dma_chan *chan, dma_addr_t paddr, -- struct catpt_fw_block_hdr *blk) -+static int catpt_restore_dram_rodata(struct catpt_dev *cdev, -+ struct dma_chan *chan, dma_addr_t paddr, -+ struct catpt_fw_block_hdr *blk) - { - struct resource r1 = {}; - int i; -@@ -324,28 +357,26 @@ static int catpt_load_block(struct catpt_dev *cdev, - - static int catpt_restore_basefw(struct catpt_dev *cdev, - struct dma_chan *chan, dma_addr_t paddr, -- struct catpt_fw_mod_hdr *basefw) -+ struct catpt_fw_module_hdr *basefw) - { -- u32 offset = sizeof(*basefw); -+ u32 off = sizeof(*basefw); - int ret, i; - - print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, - basefw, sizeof(*basefw), false); - -- /* restore basefw image */ -+ /* Restore IRAM and .rodata for DRAM based on the firmware image. */ - for (i = 0; i < basefw->blocks; i++) { - struct catpt_fw_block_hdr *blk; - -- blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + offset); -+ blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + off); - - switch (blk->ram_type) { - case CATPT_RAM_TYPE_IRAM: -- ret = catpt_load_block(cdev, chan, paddr + offset, -- blk, false); -+ ret = catpt_load_block(cdev, chan, paddr + off, blk, false); - break; - default: -- ret = catpt_restore_fwimage(cdev, chan, paddr + offset, -- blk); -+ ret = catpt_restore_dram_rodata(cdev, chan, paddr + off, blk); - break; - } - -@@ -354,11 +385,11 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, - return ret; - } - -- offset += sizeof(*blk) + blk->size; -+ off += sizeof(*blk) + blk->size; - } - -- /* then proceed with memory dumps */ -- ret = catpt_restore_memdumps(cdev, chan); -+ /* Then proceed with DRAM .data saved before D3. */ -+ ret = catpt_restore_dram_data(cdev, chan); - if (ret) - dev_err(cdev->dev, "restore memdumps failed: %d\n", ret); - -@@ -367,9 +398,9 @@ static int catpt_restore_basefw(struct catpt_dev *cdev, - - static int catpt_restore_module(struct catpt_dev *cdev, - struct dma_chan *chan, dma_addr_t paddr, -- struct catpt_fw_mod_hdr *mod) -+ struct catpt_fw_module_hdr *mod) - { -- u32 offset = sizeof(*mod); -+ u32 off = sizeof(*mod); - int i; - - print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, -@@ -379,7 +410,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, - struct catpt_fw_block_hdr *blk; - int ret; - -- blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset); -+ blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off); - - switch (blk->ram_type) { - case CATPT_RAM_TYPE_INSTANCE: -@@ -390,7 +421,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, - ALIGN(blk->size, 4)); - break; - default: -- ret = catpt_load_block(cdev, chan, paddr + offset, -+ ret = catpt_load_block(cdev, chan, paddr + off, - blk, false); - break; - } -@@ -400,7 +431,7 @@ static int catpt_restore_module(struct catpt_dev *cdev, - return ret; - } - -- offset += sizeof(*blk) + blk->size; -+ off += sizeof(*blk) + blk->size; - } - - return 0; -@@ -408,10 +439,10 @@ static int catpt_restore_module(struct catpt_dev *cdev, - - static int catpt_load_module(struct catpt_dev *cdev, - struct dma_chan *chan, dma_addr_t paddr, -- struct catpt_fw_mod_hdr *mod) -+ struct catpt_fw_module_hdr *mod) - { - struct catpt_module_type *type; -- u32 offset = sizeof(*mod); -+ u32 off = sizeof(*mod); - int i; - - print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, -@@ -423,9 +454,9 @@ static int catpt_load_module(struct catpt_dev *cdev, - struct catpt_fw_block_hdr *blk; - int ret; - -- blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset); -+ blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off); - -- ret = catpt_load_block(cdev, chan, paddr + offset, blk, true); -+ ret = catpt_load_block(cdev, chan, paddr + off, blk, true); - if (ret) { - dev_err(cdev->dev, "load block failed: %d\n", ret); - return ret; -@@ -440,7 +471,7 @@ static int catpt_load_module(struct catpt_dev *cdev, - type->state_size = blk->size; - } - -- offset += sizeof(*blk) + blk->size; -+ off += sizeof(*blk) + blk->size; - } - - /* init module type static info */ -@@ -457,17 +488,17 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, - struct dma_chan *chan, dma_addr_t paddr, - struct catpt_fw_hdr *fw) - { -- u32 offset = sizeof(*fw); -+ u32 off = sizeof(*fw); - int i; - - print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, - fw, sizeof(*fw), false); - - for (i = 0; i < fw->modules; i++) { -- struct catpt_fw_mod_hdr *mod; -+ struct catpt_fw_module_hdr *mod; - int ret; - -- mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset); -+ mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off); - if (strncmp(fw->signature, mod->signature, - FW_SIGNATURE_SIZE)) { - dev_err(cdev->dev, "module signature mismatch\n"); -@@ -479,12 +510,10 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, - - switch (mod->module_id) { - case CATPT_MODID_BASE_FW: -- ret = catpt_restore_basefw(cdev, chan, paddr + offset, -- mod); -+ ret = catpt_restore_basefw(cdev, chan, paddr + off, mod); - break; - default: -- ret = catpt_restore_module(cdev, chan, paddr + offset, -- mod); -+ ret = catpt_restore_module(cdev, chan, paddr + off, mod); - break; - } - -@@ -493,7 +522,7 @@ static int catpt_restore_firmware(struct catpt_dev *cdev, - return ret; - } - -- offset += sizeof(*mod) + mod->mod_size; -+ off += sizeof(*mod) + mod->mod_size; - } - - return 0; -@@ -503,17 +532,17 @@ static int catpt_load_firmware(struct catpt_dev *cdev, - struct dma_chan *chan, dma_addr_t paddr, - struct catpt_fw_hdr *fw) - { -- u32 offset = sizeof(*fw); -+ u32 off = sizeof(*fw); - int i; - - print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4, - fw, sizeof(*fw), false); - - for (i = 0; i < fw->modules; i++) { -- struct catpt_fw_mod_hdr *mod; -+ struct catpt_fw_module_hdr *mod; - int ret; - -- mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset); -+ mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off); - if (strncmp(fw->signature, mod->signature, - FW_SIGNATURE_SIZE)) { - dev_err(cdev->dev, "module signature mismatch\n"); -@@ -523,44 +552,40 @@ static int catpt_load_firmware(struct catpt_dev *cdev, - if (mod->module_id > CATPT_MODID_LAST) - return -EINVAL; - -- ret = catpt_load_module(cdev, chan, paddr + offset, mod); -+ ret = catpt_load_module(cdev, chan, paddr + off, mod); - if (ret) { - dev_err(cdev->dev, "load module failed: %d\n", ret); - return ret; - } - -- offset += sizeof(*mod) + mod->mod_size; -+ off += sizeof(*mod) + mod->mod_size; - } - - return 0; - } - --static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan, -- const char *name, const char *signature, -- bool restore) -+static int catpt_request_load_firmware(struct catpt_dev *cdev, struct dma_chan *chan, -+ const char *name, bool restore) - { - struct catpt_fw_hdr *fw; -- struct firmware *img; - dma_addr_t paddr; - void *vaddr; - int ret; - -- ret = request_firmware((const struct firmware **)&img, name, cdev->dev); -+ const struct firmware *img __free(firmware) = NULL; -+ ret = request_firmware(&img, name, cdev->dev); - if (ret) - return ret; - - fw = (struct catpt_fw_hdr *)img->data; -- if (strncmp(fw->signature, signature, FW_SIGNATURE_SIZE)) { -+ if (strncmp(fw->signature, FW_SIGNATURE, FW_SIGNATURE_SIZE)) { - dev_err(cdev->dev, "firmware signature mismatch\n"); -- ret = -EINVAL; -- goto release_fw; -+ return -EINVAL; - } - - vaddr = dma_alloc_coherent(cdev->dev, img->size, &paddr, GFP_KERNEL); -- if (!vaddr) { -- ret = -ENOMEM; -- goto release_fw; -- } -+ if (!vaddr) -+ return -ENOMEM; - - memcpy(vaddr, img->data, img->size); - fw = (struct catpt_fw_hdr *)vaddr; -@@ -570,12 +595,10 @@ static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan, - ret = catpt_load_firmware(cdev, chan, paddr, fw); - - dma_free_coherent(cdev->dev, img->size, vaddr, paddr); --release_fw: -- release_firmware(img); - return ret; - } - --static int catpt_load_images(struct catpt_dev *cdev, bool restore) -+static int catpt_request_dma_load_firmware(struct catpt_dev *cdev, bool restore) - { - struct dma_chan *chan; - int ret; -@@ -584,8 +607,7 @@ static int catpt_load_images(struct catpt_dev *cdev, bool restore) - if (IS_ERR(chan)) - return PTR_ERR(chan); - -- ret = catpt_load_image(cdev, chan, cdev->spec->fw_name, -- FW_SIGNATURE, restore); -+ ret = catpt_request_load_firmware(cdev, chan, cdev->spec->fw_name, restore); - if (ret) - goto release_dma_chan; - -@@ -605,7 +627,7 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore) - - catpt_dsp_stall(cdev, true); - -- ret = catpt_load_images(cdev, restore); -+ ret = catpt_request_dma_load_firmware(cdev, restore); - if (ret) { - dev_err(cdev->dev, "load binaries failed: %d\n", ret); - return ret; -@@ -619,10 +641,10 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore) - if (!ret) { - dev_err(cdev->dev, "firmware ready timeout\n"); - return -ETIMEDOUT; -- /* Wake up does not mean FW is ready, an exception could occur. */ -- } else if (!cdev->ipc.ready) { -- return -EREMOTEIO; - } -+ /* Wake up does not mean FW is ready, an exception could occur. */ -+ if (!cdev->ipc.ready) -+ return -EREMOTEIO; - - /* update sram pg & clock once done booting */ - catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask); -diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c ---- a/sound/soc/intel/catpt/pcm.c -+++ b/sound/soc/intel/catpt/pcm.c -@@ -75,8 +75,8 @@ static struct catpt_stream_template *catpt_topology[] = { - static struct catpt_stream_template * - catpt_get_stream_template(struct snd_pcm_substream *substream) - { -- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream); -- struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0); -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - enum catpt_stream_type type; - - type = cpu_dai->driver->id; -@@ -159,11 +159,11 @@ static void catpt_stream_read_position(struct catpt_dev *cdev, - static void catpt_arrange_page_table(struct snd_pcm_substream *substream, - struct snd_dma_buffer *pgtbl) - { -- struct snd_pcm_runtime *rtm = substream->runtime; -+ struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream); - int i, pages; - -- pages = snd_sgbuf_aligned_pages(rtm->dma_bytes); -+ pages = snd_sgbuf_aligned_pages(runtime->dma_bytes); - - for (i = 0; i < pages; i++) { - u32 pfn, offset; -@@ -386,7 +386,7 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) - { -- struct snd_pcm_runtime *rtm = substream->runtime; -+ struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *dmab; - struct catpt_stream_runtime *stream; - struct catpt_audio_format afmt; -@@ -412,8 +412,8 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream, - - memset(&rinfo, 0, sizeof(rinfo)); - rinfo.page_table_addr = stream->pgtbl.addr; -- rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE); -- rinfo.size = rtm->dma_bytes; -+ rinfo.num_pages = DIV_ROUND_UP(runtime->dma_bytes, PAGE_SIZE); -+ rinfo.size = runtime->dma_bytes; - rinfo.offset = 0; - rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0)); - -@@ -544,11 +544,11 @@ void catpt_stream_update_position(struct catpt_dev *cdev, - struct catpt_notify_position *pos) - { - struct snd_pcm_substream *substream = stream->substream; -- struct snd_pcm_runtime *r = substream->runtime; -+ struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t dsppos, newpos; - int ret; - -- dsppos = bytes_to_frames(r, pos->stream_position); -+ dsppos = bytes_to_frames(runtime, pos->stream_position); - - if (!stream->prepared) - goto exit; -@@ -556,8 +556,8 @@ void catpt_stream_update_position(struct catpt_dev *cdev, - if (stream->template->type != CATPT_STRM_TYPE_RENDER) - goto exit; - -- if (dsppos >= r->buffer_size / 2) -- newpos = r->buffer_size / 2; -+ if (dsppos >= runtime->buffer_size / 2) -+ newpos = runtime->buffer_size / 2; - else - newpos = 0; - /* -@@ -565,7 +565,7 @@ void catpt_stream_update_position(struct catpt_dev *cdev, - * (buffer half consumed) update wp to allow stream progression. - */ - ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id, -- frames_to_bytes(r, newpos), -+ frames_to_bytes(runtime, newpos), - false, false); - if (ret) { - dev_err(cdev->dev, "update position for stream %d failed: %d\n", -@@ -600,11 +600,11 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = { - }; - - static int catpt_component_pcm_new(struct snd_soc_component *component, -- struct snd_soc_pcm_runtime *rtm) -+ struct snd_soc_pcm_runtime *rtd) - { - struct catpt_dev *cdev = dev_get_drvdata(component->dev); - -- snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG, -+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV_SG, - cdev->dev, - catpt_pcm_hardware.buffer_bytes_max, - catpt_pcm_hardware.buffer_bytes_max); -@@ -615,9 +615,9 @@ static int catpt_component_pcm_new(struct snd_soc_component *component, - static int catpt_component_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) - { -- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - -- if (!rtm->dai_link->no_pcm) -+ if (!rtd->dai_link->no_pcm) - snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware); - return 0; - } -@@ -626,13 +626,13 @@ static snd_pcm_uframes_t - catpt_component_pointer(struct snd_soc_component *component, - struct snd_pcm_substream *substream) - { -- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream); -- struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0); -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - struct catpt_stream_runtime *stream; - struct catpt_dev *cdev = dev_get_drvdata(component->dev); - u32 pos; - -- if (rtm->dai_link->no_pcm) -+ if (rtd->dai_link->no_pcm) - return 0; - - stream = snd_soc_dai_get_dma_data(cpu_dai, substream); -@@ -650,10 +650,10 @@ static const struct snd_soc_dai_ops catpt_fe_dai_ops = { - .trigger = catpt_dai_trigger, - }; - --static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm, -+static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *dai) - { -- struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtm, 0); -+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct catpt_ssp_device_format devfmt; - struct catpt_dev *cdev = dev_get_drvdata(dai->dev); - int ret; -@@ -871,8 +871,7 @@ static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol) - return CATPT_IPC_RET(ret); - } - --static int catpt_volume_info(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_info *uinfo) -+static int catpt_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) - { - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = CATPT_CHANNELS_MAX; -@@ -1073,18 +1072,14 @@ int catpt_arm_stream_templates(struct catpt_dev *cdev) - int catpt_register_plat_component(struct catpt_dev *cdev) - { - struct snd_soc_component *component; -- int ret; - -- component = devm_kzalloc(cdev->dev, sizeof(*component), GFP_KERNEL); -+ component = snd_soc_component_alloc(cdev->dev); - if (!component) - return -ENOMEM; - -- ret = snd_soc_component_initialize(component, &catpt_comp_driver, -- cdev->dev); -- if (ret) -- return ret; -+ snd_soc_component_set_name(component, catpt_comp_driver.name); - -- component->name = catpt_comp_driver.name; -- return snd_soc_add_component(component, dai_drivers, -- ARRAY_SIZE(dai_drivers)); -+ return snd_soc_register_component(component, -+ &catpt_comp_driver, -+ dai_drivers, ARRAY_SIZE(dai_drivers)); - } -diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c ---- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c -@@ -572,6 +572,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { - .links = arl_rt711_l0_rt1316_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(3), -@@ -600,12 +601,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { - .links = arl_rvp, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-arl-rt711.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = 0x1, /* link0 required */ - .links = arl_sdca_rvp, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-arl-rt711-l0.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(2), -diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c ---- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c -@@ -717,24 +717,28 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { - .links = lnl_3_in_1_sdca, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(2) | BIT(3), - .links = lnl_cs42l43_l0_cs35l56_l23, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(1) | BIT(2) | BIT(3), - .links = lnl_cs42l43_l2_cs35l56x6_l13, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-cs42l43-l2-cs35l56x6-l13.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(3), - .links = lnl_cs42l43_l0_cs35l56_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), -@@ -748,12 +752,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { - .links = lnl_rvp, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-rt711.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(2) | BIT(3), - .links = lnl_712_only, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-rt712-l2-rt1712-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), -@@ -766,19 +772,22 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { - .link_mask = GENMASK(2, 0), - .links = lnl_sdw_rt1318_l12_rt714_l0, - .drv_name = "sof_sdw", -- .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg" -+ .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = GENMASK(2, 0), - .links = lnl_sdw_rt1320_l12_rt714_l0, - .drv_name = "sof_sdw", -- .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg" -+ .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(1), - .links = lnl_sdw_rt713_l0_rt1318_l1, - .drv_name = "sof_sdw", -- .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg" -+ .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(1) | BIT(2), -diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c ---- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c -@@ -1321,60 +1321,70 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { - .links = tac5572_l0, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-tac5572.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), - .links = tac5672_l0, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-tac5672.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), - .links = tac5682_l0, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-tac5682.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), - .links = tas2783_link0, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-tas2783.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), - .links = tas2883_l0, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-tas2883.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = GENMASK(3, 0), - .links = mtl_rt713_l0_rt1316_l12_rt1713_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = GENMASK(3, 0), - .links = mtl_rt713_l0_rt1318_l12_rt1713_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l12-rt1713-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(1) | BIT(3), - .links = mtl_rt713_l0_rt1318_l1_rt1713_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l1-rt1713-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = GENMASK(2, 0), - .links = mtl_rt713_l0_rt1316_l12, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(3) | BIT(0), - .links = mtl_712_l0_1712_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), -@@ -1395,7 +1405,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { - .link_mask = GENMASK(2, 0), - .links = mtl_sdw_rt1318_l12_rt714_l0, - .drv_name = "sof_sdw", -- .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg" -+ .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(2) | BIT(3), -@@ -1455,12 +1466,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { - .links = mtl_3_in_1_sdca, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = 0x9, /* 2 active links required */ - .links = mtl_rt711_l0_rt1316_l3, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l3.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0), -@@ -1474,18 +1487,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { - .links = mtl_rvp, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-rt711.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(2), - .links = rt5682_link2_max98373_link0, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-sdw-rt5682-l2-max98373-l0.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(0) | BIT(2), - .links = cs42l42_link0_max98363_link2, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-mtl-sdw-cs42l42-l0-max98363-l2.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - {}, - }; -diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c ---- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c -@@ -492,7 +492,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { - .links = ptl_rt722_l0_rt1320_l23, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-rt722-l0-rt1320-l23.tplg", -- .get_function_tplg_files = sof_sdw_get_tplg_files, -+ .machine_check = snd_soc_acpi_intel_no_function_topology, - }, - { - .link_mask = BIT(1) | BIT(2), -@@ -522,14 +522,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { - .links = ptl_rvp, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-ptl-rt711.tplg", -+ .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { - .link_mask = BIT(3), - .links = ptl_sdw_rt712_vb_l3_rt1320_l3, - .drv_name = "sof_sdw", -- .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, -+ .machine_check = snd_soc_acpi_intel_rt712_vb_no_function_topology, - .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg", -- .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - {}, - }; -diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c ---- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c -+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c -@@ -53,6 +53,14 @@ bool snd_soc_acpi_intel_no_function_topology(void *arg) - } - EXPORT_SYMBOL_NS(snd_soc_acpi_intel_no_function_topology, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); - -+bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg) -+{ -+ return snd_soc_acpi_intel_sdca_is_device_rt712_vb(arg) && -+ snd_soc_acpi_intel_no_function_topology(arg); -+} -+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_rt712_vb_no_function_topology, -+ "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); -+ - MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks"); - MODULE_LICENSE("GPL"); - MODULE_IMPORT_NS("SND_SOC_SDCA"); -diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h ---- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h -+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h -@@ -11,5 +11,6 @@ - - bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg); - bool snd_soc_acpi_intel_no_function_topology(void *arg); -+bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg); - - #endif -diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c ---- a/sound/soc/intel/keembay/kmb_platform.c -+++ b/sound/soc/intel/keembay/kmb_platform.c -@@ -873,6 +873,8 @@ static int kmb_plat_dai_probe(struct platform_device *pdev) - - if (kmb_i2s->use_pio) { - irq = platform_get_irq_optional(pdev, 0); -+ if (irq == -EPROBE_DEFER) -+ return irq; - if (irq > 0) { - ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0, - pdev->name, kmb_i2s); -diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c ---- a/sound/soc/loongson/loongson_card.c -+++ b/sound/soc/loongson/loongson_card.c -@@ -2,24 +2,131 @@ - // - // Loongson ASoC Audio Machine driver - // --// Copyright (C) 2023 Loongson Technology Corporation Limited -+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited - // Author: Yingkun Meng -+// Binbin Zhou - // - -+#include -+#include - #include -+#include -+#include -+#include - #include - #include --#include --#include --#include - - static char codec_name[SND_ACPI_I2C_ID_LEN]; - - struct loongson_card_data { - struct snd_soc_card snd_card; - unsigned int mclk_fs; -+ struct gpio_desc *gpiod_hp_det; -+ struct gpio_desc *gpiod_hp_ctl; -+ struct gpio_desc *gpiod_spkr_en; -+ const struct loongson_card_config *cfg; - }; - -+struct loongson_card_config { -+ unsigned int fmt; -+ bool add_hp_jack; -+ bool add_dapm_widgets; -+ bool add_dapm_routes; -+}; -+ -+static const struct loongson_card_config ls2k1000_card_config = { -+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC, -+ .add_hp_jack = false, -+ .add_dapm_widgets = false, -+ .add_dapm_routes = false, -+}; -+ -+static const struct loongson_card_config ls2k0300_forever_pi_card_config = { -+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, -+ .add_hp_jack = false, -+ .add_dapm_widgets = false, -+ .add_dapm_routes = false, -+}; -+ -+static const struct loongson_card_config ls2k0300_dl2k0300b_card_config = { -+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, -+ .add_hp_jack = true, -+ .add_dapm_widgets = true, -+ .add_dapm_routes = true, -+}; -+ -+static int tegra_machine_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *k, int event) -+{ -+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); -+ struct loongson_card_data *priv = snd_soc_card_get_drvdata(card); -+ -+ if (!snd_soc_dapm_widget_name_cmp(w, "Speaker")) -+ gpiod_set_value_cansleep(priv->gpiod_spkr_en, -+ SND_SOC_DAPM_EVENT_ON(event)); -+ -+ if (!snd_soc_dapm_widget_name_cmp(w, "Headphone")) -+ gpiod_set_value_cansleep(priv->gpiod_hp_ctl, -+ SND_SOC_DAPM_EVENT_ON(event)); -+ -+ return 0; -+} -+ -+static const struct snd_soc_dapm_widget loongson_aosc_dapm_widgets[] = { -+ SND_SOC_DAPM_HP("Headphone", tegra_machine_event), -+ SND_SOC_DAPM_SPK("Speaker", tegra_machine_event), -+}; -+ -+/* Headphones Jack */ -+ -+static struct snd_soc_jack loongson_asoc_hp_jack; -+ -+static struct snd_soc_jack_pin loongson_asoc_hp_jack_pins[] = { -+ { -+ .pin = "Headphone", -+ .mask = SND_JACK_HEADPHONE -+ }, -+ { -+ .pin = "Speaker", -+ .mask = SND_JACK_HEADPHONE, -+ .invert = 1 -+ }, -+}; -+ -+static struct snd_soc_jack_gpio loongson_asoc_hp_jack_gpio = { -+ .name = "Headphones detection", -+ .report = SND_JACK_HEADPHONE, -+ .debounce_time = 150, -+}; -+ -+static int loongson_asoc_machine_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_card *card = rtd->card; -+ struct loongson_card_data *ls_priv = snd_soc_card_get_drvdata(card); -+ int ret = 0; -+ -+ if (!ls_priv->cfg->add_hp_jack || !ls_priv->gpiod_hp_det) -+ return 0; -+ -+ ret = snd_soc_card_jack_new_pins(card, "Headphones Jack", -+ SND_JACK_HEADPHONE, -+ &loongson_asoc_hp_jack, -+ loongson_asoc_hp_jack_pins, -+ ARRAY_SIZE(loongson_asoc_hp_jack_pins)); -+ if (ret) { -+ dev_err(rtd->dev, "Headphones Jack creation failed: %d\n", ret); -+ return ret; -+ } -+ -+ loongson_asoc_hp_jack_gpio.desc = ls_priv->gpiod_hp_det; -+ -+ ret = snd_soc_jack_add_gpios(&loongson_asoc_hp_jack, 1, &loongson_asoc_hp_jack_gpio); -+ if (ret) -+ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret); -+ -+ return ret; -+} -+ - static int loongson_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) - { -@@ -45,7 +152,7 @@ static int loongson_card_hw_params(struct snd_pcm_substream *substream, - return ret; - } - -- return 0; -+ return snd_soc_runtime_set_dai_fmt(rtd, ls_card->cfg->fmt); - } - - static const struct snd_soc_ops loongson_ops = { -@@ -61,8 +168,7 @@ static struct snd_soc_dai_link loongson_dai_links[] = { - { - .name = "Loongson Audio Port", - .stream_name = "Loongson Audio", -- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF -- | SND_SOC_DAIFMT_CBC_CFC, -+ .init = loongson_asoc_machine_init, - SND_SOC_DAILINK_REG(analog), - .ops = &loongson_ops, - }, -@@ -123,16 +229,35 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data) - - static int loongson_card_parse_of(struct loongson_card_data *data) - { -- struct device_node *cpu, *codec; - struct snd_soc_card *card = &data->snd_card; -+ struct device_node *cpu, *codec; - struct device *dev = card->dev; - int ret, i; - -+ data->gpiod_hp_det = devm_gpiod_get_optional(dev, "hp-det", GPIOD_IN); -+ if (IS_ERR(data->gpiod_hp_det)) -+ return PTR_ERR(data->gpiod_hp_det); -+ -+ data->gpiod_hp_ctl = devm_gpiod_get_optional(dev, "hp-ctl", GPIOD_OUT_LOW); -+ if (IS_ERR(data->gpiod_hp_ctl)) -+ return PTR_ERR(data->gpiod_hp_ctl); -+ -+ data->gpiod_spkr_en = devm_gpiod_get_optional(dev, "spkr-en", GPIOD_OUT_LOW); -+ if (IS_ERR(data->gpiod_spkr_en)) -+ return PTR_ERR(data->gpiod_spkr_en); -+ -+ if (data->cfg->add_dapm_routes) { -+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); -+ if (ret) -+ return ret; -+ } -+ - cpu = of_get_child_by_name(dev->of_node, "cpu"); - if (!cpu) { - dev_err(dev, "platform property missing or invalid\n"); - return -EINVAL; - } -+ - codec = of_get_child_by_name(dev->of_node, "codec"); - if (!codec) { - dev_err(dev, "audio-codec property missing or invalid\n"); -@@ -177,12 +302,22 @@ static int loongson_asoc_card_probe(struct platform_device *pdev) - if (!ls_priv) - return -ENOMEM; - -+ ls_priv->cfg = (const struct loongson_card_config *)device_get_match_data(dev); -+ if (!ls_priv->cfg) -+ return -EINVAL; -+ - card = &ls_priv->snd_card; - - card->dev = dev; - card->owner = THIS_MODULE; - card->dai_link = loongson_dai_links; - card->num_links = ARRAY_SIZE(loongson_dai_links); -+ -+ if (ls_priv->cfg->add_dapm_widgets) { -+ card->dapm_widgets = loongson_aosc_dapm_widgets; -+ card->num_dapm_widgets = ARRAY_SIZE(loongson_aosc_dapm_widgets); -+ } -+ - snd_soc_card_set_drvdata(card, ls_priv); - - ret = device_property_read_string(dev, "model", &card->name); -@@ -202,7 +337,19 @@ static int loongson_asoc_card_probe(struct platform_device *pdev) - } - - static const struct of_device_id loongson_asoc_dt_ids[] = { -- { .compatible = "loongson,ls-audio-card" }, -+ /* Loongson-2K1000/Loongson-2K2000/LS7A */ -+ { -+ .compatible = "loongson,ls-audio-card", -+ .data = &ls2k1000_card_config -+ }, -+ { -+ .compatible = "loongson,ls2k0300-forever-pi-audio-card", -+ .data = &ls2k0300_forever_pi_card_config -+ }, -+ { -+ .compatible = "loongson,ls2k0300-dl2k0300b-audio-card", -+ .data = &ls2k0300_dl2k0300b_card_config -+ }, - { /* sentinel */ }, - }; - MODULE_DEVICE_TABLE(of, loongson_asoc_dt_ids); -diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c ---- a/sound/soc/loongson/loongson_i2s_plat.c -+++ b/sound/soc/loongson/loongson_i2s_plat.c -@@ -2,7 +2,7 @@ - // - // Loongson I2S controller master mode dirver(platform device) - // --// Copyright (C) 2023-2024 Loongson Technology Corporation Limited -+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited - // - // Author: Yingkun Meng - // Binbin Zhou -@@ -21,6 +21,7 @@ - #include "loongson_i2s.h" - #include "loongson_dma.h" - -+/* Loongson-2K1000 APBDMA routing */ - #define LOONGSON_I2S_RX_DMA_OFFSET 21 - #define LOONGSON_I2S_TX_DMA_OFFSET 18 - -@@ -30,6 +31,11 @@ - #define LOONGSON_DMA3_CONF 0x3 - #define LOONGSON_DMA4_CONF 0x4 - -+struct loongson_i2s_plat_config { -+ int rev_id; -+ int (*i2s_dma_config)(struct platform_device *pdev); -+}; -+ - static int loongson_i2s_apbdma_config(struct platform_device *pdev) - { - int val; -@@ -47,8 +53,18 @@ static int loongson_i2s_apbdma_config(struct platform_device *pdev) - return 0; - } - -+static const struct loongson_i2s_plat_config ls2k0300_i2s_plat_config = { -+ .rev_id = 1, -+}; -+ -+static const struct loongson_i2s_plat_config ls2k1000_i2s_plat_config = { -+ .rev_id = 0, -+ .i2s_dma_config = loongson_i2s_apbdma_config, -+}; -+ - static int loongson_i2s_plat_probe(struct platform_device *pdev) - { -+ const struct loongson_i2s_plat_config *plat_config; - struct device *dev = &pdev->dev; - struct loongson_i2s *i2s; - struct resource *res; -@@ -59,12 +75,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev) - if (!i2s) - return -ENOMEM; - -- ret = loongson_i2s_apbdma_config(pdev); -- if (ret) -- return ret; -+ plat_config = device_get_match_data(dev); -+ if (!plat_config) -+ return -EINVAL; - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); -+ if (plat_config->i2s_dma_config) { -+ ret = plat_config->i2s_dma_config(pdev); -+ if (ret) -+ return ret; -+ } -+ -+ i2s->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(i2s->reg_base)) - return dev_err_probe(dev, PTR_ERR(i2s->reg_base), - "devm_ioremap_resource failed\n"); -@@ -87,11 +108,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev) - if (IS_ERR(i2s_clk)) - return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n"); - i2s->clk_rate = clk_get_rate(i2s_clk); -+ i2s->rev_id = plat_config->rev_id; - - dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); - dev_set_name(dev, LS_I2S_DRVNAME); - dev_set_drvdata(dev, i2s); - -+ if (i2s->rev_id == 1) { -+ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET, I2S_CTRL_RESET); -+ fsleep(200); -+ } -+ - ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component, - &loongson_i2s_dai, 1); - if (ret) -@@ -102,7 +129,8 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev) - } - - static const struct of_device_id loongson_i2s_ids[] = { -- { .compatible = "loongson,ls2k1000-i2s" }, -+ { .compatible = "loongson,ls2k0300-i2s", .data = &ls2k0300_i2s_plat_config }, -+ { .compatible = "loongson,ls2k1000-i2s", .data = &ls2k1000_i2s_plat_config }, - { /* sentinel */ }, - }; - MODULE_DEVICE_TABLE(of, loongson_i2s_ids); -diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig ---- a/sound/soc/mediatek/Kconfig -+++ b/sound/soc/mediatek/Kconfig -@@ -7,7 +7,7 @@ config SND_SOC_MEDIATEK - - config SND_SOC_MT2701 - tristate "ASoC support for Mediatek MT2701 chip" -- depends on ARCH_MEDIATEK -+ depends on ARCH_MEDIATEK || COMPILE_TEST - select SND_SOC_MEDIATEK - help - This adds ASoC driver for Mediatek MT2701 boards -diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c ---- a/sound/soc/mediatek/common/mtk-dsp-sof-common.c -+++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c -@@ -232,6 +232,7 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card, - const char *propname) - { - struct device_node *np = dev->of_node; -+ struct snd_soc_dai_link *dai_link; - struct snd_soc_dai_link *parsed_dai_link; - const char *dai_name = NULL; - int i, j, ret, num_links, parsed_num_links = 0; -@@ -254,9 +255,9 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card, - return ret; - } - dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name); -- for (j = 0; j < card->num_links; j++) { -- if (!strcmp(dai_name, card->dai_link[j].name)) { -- memcpy(&parsed_dai_link[parsed_num_links++], &card->dai_link[j], -+ for_each_card_prelinks(card, j, dai_link) { -+ if (!strcmp(dai_name, dai_link->name)) { -+ memcpy(&parsed_dai_link[parsed_num_links++], dai_link, - sizeof(struct snd_soc_dai_link)); - break; - } -diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c ---- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c -+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c -@@ -315,7 +315,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) - &mt8173_rt5650_priv.pll_from); - if (ret) { - dev_err(&pdev->dev, -- "%s snd_soc_register_card fail %d\n", -+ "%s device_property_read_u32() fail %d\n", - __func__, ret); - } - } -diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c ---- a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c -+++ b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c -@@ -385,8 +385,6 @@ static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w, - if (event == SND_SOC_DAPM_PRE_PMU) { - if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) - regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8); -- else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) -- regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0); - else - regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0); - } -diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c ---- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c -+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c -@@ -1019,7 +1019,7 @@ static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682x_card = { - .num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_routes), - }; - --static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card, -+static int mt8192_mt6359_card_set_be_link(struct device *dev, - struct snd_soc_dai_link *link, - struct device_node *node, - char *link_name) -@@ -1027,9 +1027,9 @@ static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card, - int ret; - - if (node && strcmp(link->name, link_name) == 0) { -- ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link); -+ ret = snd_soc_of_get_dai_link_codecs(dev, node, link); - if (ret < 0) { -- dev_err_probe(card->dev, ret, "get dai link codecs fail\n"); -+ dev_err_probe(dev, ret, "get dai link codecs fail\n"); - return ret; - } - } -@@ -1065,21 +1065,21 @@ static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data) - } - - for_each_card_prelinks(card, i, dai_link) { -- ret = mt8192_mt6359_card_set_be_link(card, dai_link, speaker_codec, "I2S3"); -+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, speaker_codec, "I2S3"); - if (ret) { - dev_err_probe(dev, ret, "%s set speaker_codec fail\n", - dai_link->name); - break; - } - -- ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S8"); -+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S8"); - if (ret) { - dev_err_probe(dev, ret, "%s set headset_codec fail\n", - dai_link->name); - break; - } - -- ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S9"); -+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S9"); - if (ret) { - dev_err_probe(dev, ret, "%s set headset_codec fail\n", - dai_link->name); -diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediatek/mt8196/mt8196-nau8825.c ---- a/sound/soc/mediatek/mt8196/mt8196-nau8825.c -+++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c -@@ -104,8 +104,6 @@ static const struct snd_kcontrol_new mt8196_nau8825_controls[] = { - - #define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp" - --static struct snd_soc_card mt8196_nau8825_soc_card; -- - static const struct snd_soc_dapm_widget mt8196_nau8825_card_widgets[] = { - /* SOF Uplink */ - SND_SOC_DAPM_MIXER("SOF_DMA_UL0", SND_SOC_NOPM, 0, 0, NULL, 0), -diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c ---- a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c -+++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c -@@ -2120,19 +2120,15 @@ static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev) - spin_lock_init(&afe_priv->afe_ctrl_lock); - mutex_init(&afe_priv->afe_clk_mutex); - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- afe->base_addr = devm_ioremap_resource(&pdev->dev, res); -+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(afe->base_addr)) - return PTR_ERR(afe->base_addr); - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -- if (res) { -- afe_priv->afe_sram_vir_addr = -- devm_ioremap_resource(&pdev->dev, res); -- if (!IS_ERR(afe_priv->afe_sram_vir_addr)) { -- afe_priv->afe_sram_phy_addr = res->start; -- afe_priv->afe_sram_size = resource_size(res); -- } -+ afe_priv->afe_sram_vir_addr = -+ devm_platform_get_and_ioremap_resource(pdev, 1, &res); -+ if (!IS_ERR(afe_priv->afe_sram_vir_addr)) { -+ afe_priv->afe_sram_phy_addr = res->start; -+ afe_priv->afe_sram_size = resource_size(res); - } - - /* initial audio related clock */ -diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c ---- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c -+++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c -@@ -70,7 +70,8 @@ static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = { - static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream) - { - struct snd_soc_pcm_runtime *rtd = substream->private_data; -- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); -+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); -+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv; - int ret = 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -@@ -101,7 +102,8 @@ static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream) - static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream) - { - struct snd_soc_pcm_runtime *rtd = substream->private_data; -- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card); -+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); -+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv; - int ret = 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -@@ -245,7 +247,8 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { - - static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card) - { -- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card); -+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); -+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv; - struct device *dev = card->dev; - int ret, i; - -@@ -294,7 +297,6 @@ static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool - struct mt8365_mt6357_priv *mach_priv; - int ret; - -- card->dev = dev; - ret = parse_dai_link_info(card); - if (ret) - goto err; -diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile ---- a/sound/soc/meson/Makefile -+++ b/sound/soc/meson/Makefile -@@ -4,6 +4,8 @@ snd-soc-meson-aiu-y := aiu.o - snd-soc-meson-aiu-y += aiu-acodec-ctrl.o - snd-soc-meson-aiu-y += aiu-codec-ctrl.o - snd-soc-meson-aiu-y += aiu-encoder-i2s.o -+snd-soc-meson-aiu-y += gx-formatter.o -+snd-soc-meson-aiu-y += aiu-formatter-i2s.o - snd-soc-meson-aiu-y += aiu-encoder-spdif.o - snd-soc-meson-aiu-y += aiu-fifo.o - snd-soc-meson-aiu-y += aiu-fifo-i2s.o -diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c ---- a/sound/soc/meson/aiu-encoder-i2s.c -+++ b/sound/soc/meson/aiu-encoder-i2s.c -@@ -10,14 +10,11 @@ - #include - - #include "aiu.h" -+#include "gx-formatter.h" -+#include "gx-interface.h" - --#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) --#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) --#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) - #define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11) --#define AIU_RST_SOFT_I2S_FAST BIT(0) - --#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2) - #define AIU_CLK_CTRL_I2S_DIV_EN BIT(0) - #define AIU_CLK_CTRL_I2S_DIV GENMASK(3, 2) - #define AIU_CLK_CTRL_AOCLK_INVERT BIT(6) -@@ -35,49 +32,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component, - enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0); - } - --static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component, -- struct snd_pcm_hw_params *params) --{ -- /* Always operate in split (classic interleaved) mode */ -- unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT; -- -- /* Reset required to update the pipeline */ -- snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST); -- snd_soc_component_read(component, AIU_I2S_SYNC); -- -- switch (params_physical_width(params)) { -- case 16: /* Nothing to do */ -- break; -- -- case 32: -- desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT | -- AIU_I2S_SOURCE_DESC_MODE_32BIT); -- break; -- -- default: -- return -EINVAL; -- } -- -- switch (params_channels(params)) { -- case 2: /* Nothing to do */ -- break; -- case 8: -- desc |= AIU_I2S_SOURCE_DESC_MODE_8CH; -- break; -- default: -- return -EINVAL; -- } -- -- snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC, -- AIU_I2S_SOURCE_DESC_MODE_8CH | -- AIU_I2S_SOURCE_DESC_MODE_24BIT | -- AIU_I2S_SOURCE_DESC_MODE_32BIT | -- AIU_I2S_SOURCE_DESC_MODE_SPLIT, -- desc); -- -- return 0; --} -- - static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component, - struct snd_pcm_hw_params *params, - unsigned int bs) -@@ -108,6 +62,32 @@ static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component, - return 0; - } - -+/* -+ * Return true if the given combination of channels and sample width requires -+ * the bs quirk. Return false otherwise. -+ */ -+static bool aiu_encoder_is_bs_quirk(unsigned int channels, int width) -+{ -+ return (channels == 8) && (width == 16); -+} -+ -+static int aiu_encoder_check_bs_quirk(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream); -+ -+ /* Nothing to do if the other stream doesn't exist or it's not configured yet. */ -+ if (!other_stream || !other_stream->channels) -+ return 0; -+ -+ if (aiu_encoder_is_bs_quirk(other_stream->channels, other_stream->width) != -+ aiu_encoder_is_bs_quirk(params_channels(params), params_width(params))) -+ return -EINVAL; -+ -+ return 0; -+} -+ - static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, - struct snd_pcm_hw_params *params, - unsigned int bs) -@@ -119,7 +99,7 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, - * increased by 50% to get the correct output rate. - * No idea why ! - */ -- if (params_width(params) == 16 && params_channels(params) == 8) { -+ if (aiu_encoder_is_bs_quirk(params_channels(params), params_width(params))) { - if (bs % 2) { - dev_err(component->dev, - "Cannot increase i2s divider by 50%%\n"); -@@ -141,25 +121,23 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, - return 0; - } - --static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, -- struct snd_pcm_hw_params *params) -+static int aiu_encoder_i2s_set_clocks(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) - { -+ struct snd_soc_component *component = dai->component; - struct aiu *aiu = snd_soc_component_get_drvdata(component); -+ struct gx_iface *iface = &aiu->i2s.iface; - unsigned int srate = params_rate(params); - unsigned int fs, bs; - int ret; - - /* Get the oversampling factor */ -- fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate); -+ fs = DIV_ROUND_CLOSEST(iface->mclk_rate, srate); - -- if (fs % 64) -+ if ((fs % 64) || (fs == 0)) - return -EINVAL; - -- /* Send data MSB first */ -- snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG, -- AIU_I2S_DAC_CFG_MSB_FIRST, -- AIU_I2S_DAC_CFG_MSB_FIRST); -- - /* Set bclk to lrlck ratio */ - snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL, - AIU_CODEC_DAC_LRCLK_CTRL_DIV, -@@ -168,10 +146,22 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component, - - bs = fs / 64; - -- if (aiu->platform->has_clk_ctrl_more_i2s_div) -+ if (aiu->platform->has_clk_ctrl_more_i2s_div) { -+ /* -+ * The hw rules added in startup() make this unreachable in the -+ * sequential case, but both streams may be refined concurrently -+ * before either commits its config, since only ops->hw_params -+ * runs under the card's pcm_mutex. Re-check against the committed -+ * state of the other stream, which is stable under that mutex. -+ */ -+ if (aiu_encoder_check_bs_quirk(substream, params, dai)) { -+ dev_err(dai->dev, "bclk requirements incompatible with other stream\n"); -+ return -EINVAL; -+ } - ret = aiu_encoder_i2s_set_more_div(component, params, bs); -- else -+ } else { - ret = aiu_encoder_i2s_set_legacy_div(component, params, bs); -+ } - - if (ret) - return ret; -@@ -188,23 +178,37 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) - { -+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); -+ int ret; -+ -+ ret = aiu_encoder_i2s_set_clocks(substream, params, dai); -+ if (ret) { -+ dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret); -+ return ret; -+ } -+ -+ ts->physical_width = params_physical_width(params); -+ ts->width = params_width(params); -+ ts->channels = params_channels(params); -+ -+ return 0; -+} -+ -+static int aiu_encoder_i2s_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); - struct snd_soc_component *component = dai->component; - int ret; - -- /* Disable the clock while changing the settings */ -- aiu_encoder_i2s_divider_enable(component, false); -+ if (ts->clk_enabled) -+ return 0; - -- ret = aiu_encoder_i2s_setup_desc(component, params); -- if (ret) { -- dev_err(dai->dev, "setting i2s desc failed\n"); -+ ret = clk_prepare_enable(ts->iface->mclk); -+ if (ret) - return ret; -- } - -- ret = aiu_encoder_i2s_set_clocks(component, params); -- if (ret) { -- dev_err(dai->dev, "setting i2s clocks failed\n"); -- return ret; -- } -+ ts->clk_enabled = true; - - aiu_encoder_i2s_divider_enable(component, true); - -@@ -214,9 +218,24 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream, - static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { -+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); - struct snd_soc_component *component = dai->component; - -- aiu_encoder_i2s_divider_enable(component, false); -+ /* -+ * If this is the last substream being closed then disable the i2s -+ * clock divider. -+ */ -+ if (snd_soc_dai_active(dai) <= 1) -+ aiu_encoder_i2s_divider_enable(component, 0); -+ -+ if (ts->clk_enabled) { -+ clk_disable_unprepare(ts->iface->mclk); -+ ts->clk_enabled = false; -+ } -+ -+ ts->channels = 0; -+ ts->width = 0; -+ ts->physical_width = 0; - - return 0; - } -@@ -224,6 +243,8 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream, - static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - { - struct snd_soc_component *component = dai->component; -+ struct aiu *aiu = snd_soc_component_get_drvdata(component); -+ struct gx_iface *iface = &aiu->i2s.iface; - unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK; - unsigned int val = 0; - unsigned int skew; -@@ -255,9 +276,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - skew = 0; - break; - default: -+ dev_err(dai->dev, "unsupported dai format\n"); - return -EINVAL; - } - -+ iface->fmt = fmt; -+ - val |= FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew); - snd_soc_component_update_bits(component, AIU_CLK_CTRL, - AIU_CLK_CTRL_LRCLK_INVERT | -@@ -272,6 +296,7 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) - { - struct aiu *aiu = snd_soc_component_get_drvdata(dai->component); -+ struct gx_iface *iface = &aiu->i2s.iface; - int ret; - - if (WARN_ON(clk_id != 0)) -@@ -280,11 +305,15 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, - if (dir == SND_SOC_CLOCK_IN) - return 0; - -- ret = clk_set_rate(aiu->i2s.clks[MCLK].clk, freq); -- if (ret) -- dev_err(dai->dev, "Failed to set sysclk to %uHz", freq); -+ ret = clk_set_rate(iface->mclk, freq); -+ if (ret) { -+ dev_err(dai->dev, "Failed to set sysclk to %uHz: %d", freq, ret); -+ return ret; -+ } - -- return ret; -+ iface->mclk_rate = freq; -+ -+ return 0; - } - - static const unsigned int hw_channels[] = {2, 8}; -@@ -294,10 +323,45 @@ static const struct snd_pcm_hw_constraint_list hw_channel_constraints = { - .mask = 0, - }; - -+static int aiu_encoder_i2s_pcm_hw_rule(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct gx_stream *other = rule->private; -+ struct snd_interval *ch = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); -+ /* -+ * The quirk is technically based on the significant bits whereas here -+ * we're using the physical width for simplicity. This works because -+ * S16_LE is the only format supported by this encoder that has: -+ * significant bits = physical width = 16-bits -+ */ -+ struct snd_interval *phys_width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); -+ struct snd_interval new_i; -+ -+ if (other->channels == 0) -+ return 0; -+ -+ snd_interval_any(&new_i); -+ -+ if (rule->var == SNDRV_PCM_HW_PARAM_CHANNELS) { -+ if (aiu_encoder_is_bs_quirk(other->channels, other->width)) -+ new_i.min = new_i.max = 8; -+ else if (snd_interval_single(phys_width) && phys_width->min == 16) -+ new_i.max = 2; /* Force 2ch */ -+ } else { /* SNDRV_PCM_HW_PARAM_SAMPLE_BITS */ -+ if (aiu_encoder_is_bs_quirk(other->channels, other->width)) -+ new_i.min = new_i.max = 16; -+ else if (snd_interval_single(ch) && ch->min == 8) -+ new_i.min = 17; /* Request physical width > 16 bits */ -+ } -+ -+ return snd_interval_refine(hw_param_interval(params, rule->var), &new_i); -+} -+ - static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) - { - struct aiu *aiu = snd_soc_component_get_drvdata(dai->component); -+ struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream); - int ret; - - /* Make sure the encoder gets either 2 or 8 channels */ -@@ -305,15 +369,79 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream, - SNDRV_PCM_HW_PARAM_CHANNELS, - &hw_channel_constraints); - if (ret) { -- dev_err(dai->dev, "adding channels constraints failed\n"); -+ dev_err(dai->dev, "adding channels constraints failed: %d\n", ret); - return ret; - } - -- ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks); -- if (ret) -- dev_err(dai->dev, "failed to enable i2s clocks\n"); -+ /* -+ * If DAI supports both playback and capture streams ensure the bs-quirk is -+ * handled correctly. -+ * This is only valid for GX platforms (has_clk_ctrl_more_i2s_div=true). -+ */ -+ if (aiu->platform->has_clk_ctrl_more_i2s_div && other_stream) { -+ ret = snd_pcm_hw_rule_add(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_CHANNELS, -+ aiu_encoder_i2s_pcm_hw_rule, -+ other_stream, -+ SNDRV_PCM_HW_PARAM_CHANNELS, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (ret) -+ return ret; - -- return ret; -+ ret = snd_pcm_hw_rule_add(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -+ aiu_encoder_i2s_pcm_hw_rule, -+ other_stream, -+ SNDRV_PCM_HW_PARAM_CHANNELS, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (ret) -+ return ret; -+ } -+ -+ /* -+ * Enable only clocks which are required for the interface internal -+ * logic. MCLK is enabled/disabled from the formatter and the I2S -+ * divider is enabled/disabled in "hw_params"/"hw_free", respectively. -+ */ -+ ret = clk_prepare_enable(aiu->i2s.clks[PCLK].clk); -+ if (ret) { -+ dev_err(dai->dev, "failed to enable PCLK: %d\n", ret); -+ return ret; -+ } -+ ret = clk_prepare_enable(aiu->i2s.clks[MIXER].clk); -+ if (ret) { -+ dev_err(dai->dev, "failed to enable MIXER: %d\n", ret); -+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); -+ return ret; -+ } -+ ret = clk_prepare_enable(aiu->i2s.clks[AOCLK].clk); -+ if (ret) { -+ dev_err(dai->dev, "failed to enable AOCLK: %d\n", ret); -+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk); -+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); -+ return ret; -+ } -+ -+ /* -+ * We're always operating in split mode for the playback stream. -+ * -+ * This setting arguably belong to the 'aiu-formatter', but it's kept -+ * here for backward compatibility reason. At reset the I2S encoder -+ * operates in normal mode which would only support 8ch, but by default -+ * only 2ch are enabled. If a playback stream is started without -+ * changing to split mode, then the I2S encoder doesn't consume audio -+ * samples and the playback fails. -+ * Moving this to 'aiu-formatter' would cause the split mode to be set -+ * only when the formatter is enabled, which doesn't happen at boot as -+ * the default value for "HDMI CTRL SRC" is "DISABLED". -+ */ -+ ret = snd_soc_component_update_bits(dai->component, AIU_I2S_SOURCE_DESC, -+ AIU_I2S_SOURCE_DESC_MODE_SPLIT, -+ AIU_I2S_SOURCE_DESC_MODE_SPLIT); -+ if (ret < 0) -+ dev_err(dai->dev, "failed to update AIU_I2S_SOURCE_DESC: %d", ret); -+ -+ return 0; - } - - static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream, -@@ -321,14 +449,89 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream, - { - struct aiu *aiu = snd_soc_component_get_drvdata(dai->component); - -- clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks); -+ clk_disable_unprepare(aiu->i2s.clks[AOCLK].clk); -+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk); -+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk); -+} -+ -+static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream, -+ int cmd, -+ struct snd_soc_dai *dai) -+{ -+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream); -+ int ret; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ ret = gx_stream_start(ts); -+ break; -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ case SNDRV_PCM_TRIGGER_STOP: -+ gx_stream_stop(ts); -+ ret = 0; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int aiu_encoder_i2s_remove_dai(struct snd_soc_dai *dai) -+{ -+ int stream; -+ -+ for_each_pcm_streams(stream) { -+ struct gx_stream *ts; -+ -+ ts = snd_soc_dai_dma_data_get(dai, stream); -+ if (ts) -+ gx_stream_free(ts); -+ -+ snd_soc_dai_dma_data_set(dai, stream, NULL); -+ } -+ -+ return 0; -+} -+ -+static int aiu_encoder_i2s_probe_dai(struct snd_soc_dai *dai) -+{ -+ struct aiu *aiu = snd_soc_dai_get_drvdata(dai); -+ struct gx_iface *iface = &aiu->i2s.iface; -+ int stream; -+ -+ for_each_pcm_streams(stream) { -+ struct gx_stream *ts; -+ -+ if (!snd_soc_dai_get_widget(dai, stream)) -+ continue; -+ -+ ts = gx_stream_alloc(iface); -+ if (!ts) { -+ aiu_encoder_i2s_remove_dai(dai); -+ return -ENOMEM; -+ } -+ snd_soc_dai_dma_data_set(dai, stream, ts); -+ } -+ -+ iface->mclk = aiu->i2s.clks[MCLK].clk; -+ iface->mclk_rate = clk_get_rate(iface->mclk); -+ -+ return 0; - } - - const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = { -+ .probe = aiu_encoder_i2s_probe_dai, -+ .remove = aiu_encoder_i2s_remove_dai, - .hw_params = aiu_encoder_i2s_hw_params, -+ .prepare = aiu_encoder_i2s_prepare, - .hw_free = aiu_encoder_i2s_hw_free, - .set_fmt = aiu_encoder_i2s_set_fmt, - .set_sysclk = aiu_encoder_i2s_set_sysclk, - .startup = aiu_encoder_i2s_startup, - .shutdown = aiu_encoder_i2s_shutdown, -+ .trigger = aiu_encoder_i2s_trigger, - }; -diff --git a/sound/soc/meson/aiu-formatter-i2s.c b/sound/soc/meson/aiu-formatter-i2s.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/meson/aiu-formatter-i2s.c -@@ -0,0 +1,103 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// -+// Copyright (c) 2026 BayLibre, SAS. -+// Author: Valerio Setti -+ -+#include -+#include -+#include -+ -+#include "aiu.h" -+#include "gx-formatter.h" -+ -+#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) -+#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) -+#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) -+ -+#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2) -+ -+static struct snd_soc_dai * -+aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w) -+{ -+ struct snd_soc_dapm_path *p; -+ struct snd_soc_dai *be; -+ -+ snd_soc_dapm_widget_for_each_sink_path(w, p) { -+ if (!p->connect) -+ continue; -+ -+ if (p->sink->id == snd_soc_dapm_dai_in) -+ return (struct snd_soc_dai *)p->sink->priv; -+ -+ be = aiu_formatter_i2s_get_be(p->sink); -+ if (be) -+ return be; -+ } -+ -+ return NULL; -+} -+ -+static struct gx_stream * -+aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w) -+{ -+ struct snd_soc_dai *be = aiu_formatter_i2s_get_be(w); -+ -+ if (!be) -+ return NULL; -+ -+ return snd_soc_dai_dma_data_get_playback(be); -+} -+ -+static int aiu_formatter_i2s_prepare(struct regmap *map, -+ const struct gx_formatter_hw *quirks, -+ struct gx_stream *ts) -+{ -+ /* Always operate in split (classic interleaved) mode */ -+ unsigned int desc = 0; -+ -+ /* -+ * Pipeline reset is already implemented in aiu_fifo_i2s_trigger() at -+ * trigger time. -+ */ -+ -+ switch (ts->physical_width) { -+ case 16: /* Nothing to do */ -+ break; -+ -+ case 32: -+ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT | -+ AIU_I2S_SOURCE_DESC_MODE_32BIT); -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ switch (ts->channels) { -+ case 2: /* Nothing to do */ -+ break; -+ case 8: -+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ regmap_update_bits(map, AIU_I2S_SOURCE_DESC, -+ AIU_I2S_SOURCE_DESC_MODE_8CH | -+ AIU_I2S_SOURCE_DESC_MODE_24BIT | -+ AIU_I2S_SOURCE_DESC_MODE_32BIT, -+ desc); -+ -+ /* Send data MSB first */ -+ regmap_update_bits(map, AIU_I2S_DAC_CFG, -+ AIU_I2S_DAC_CFG_MSB_FIRST, -+ AIU_I2S_DAC_CFG_MSB_FIRST); -+ -+ return 0; -+} -+ -+const struct gx_formatter_ops aiu_formatter_i2s_ops = { -+ .get_stream = aiu_formatter_i2s_get_stream, -+ .prepare = aiu_formatter_i2s_prepare, -+}; -diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c ---- a/sound/soc/meson/aiu.c -+++ b/sound/soc/meson/aiu.c -@@ -29,13 +29,22 @@ static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC, - static const struct snd_kcontrol_new aiu_spdif_encode_mux = - SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum); - --static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = { -- SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0, -- &aiu_spdif_encode_mux), -+#define AIU_WIDGET_SPDIF_SRC_SEL 0 -+#define AIU_WIDGET_I2S_FORMATTER 1 -+ -+static struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = { -+ [AIU_WIDGET_SPDIF_SRC_SEL] = -+ SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0, -+ &aiu_spdif_encode_mux), -+ [AIU_WIDGET_I2S_FORMATTER] = -+ SND_SOC_DAPM_PGA_E("I2S Formatter", SND_SOC_NOPM, 0, 0, NULL, 0, -+ gx_formatter_event, -+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)), - }; - - static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = { -- { "I2S Encoder Playback", NULL, "I2S FIFO Playback" }, -+ { "I2S Formatter", NULL, "I2S FIFO Playback" }, -+ { "I2S Encoder Playback", NULL, "I2S Formatter" }, - { "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" }, - { "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" }, - { "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" }, -@@ -145,6 +154,7 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = { - .formats = AIU_FORMATS, - }, - .ops = &aiu_encoder_i2s_dai_ops, -+ .symmetric_rate = 1, - }, - [CPU_SPDIF_ENCODER] = { - .name = "SPDIF Encoder", -@@ -172,6 +182,11 @@ static const struct regmap_config aiu_regmap_cfg = { - .max_register = 0x2ac, - }; - -+static const struct gx_formatter_driver aiu_formatter_i2s_drv = { -+ .regmap_cfg = &aiu_regmap_cfg, -+ .ops = &aiu_formatter_i2s_ops, -+}; -+ - static int aiu_clk_bulk_get(struct device *dev, - const char * const *ids, - unsigned int num, -@@ -282,6 +297,14 @@ static int aiu_probe(struct platform_device *pdev) - if (ret) - return ret; - -+ /* Allocate the aiu-formatter into its widget */ -+ ret = gx_formatter_create(dev, &aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER], -+ &aiu_formatter_i2s_drv, map); -+ if (ret) { -+ dev_err(dev, "Failed to allocate aiu formatter\n"); -+ goto err; -+ } -+ - /* Register the cpu component of the aiu */ - ret = snd_soc_register_component(dev, &aiu_cpu_component, - aiu_cpu_dai_drv, -@@ -310,12 +333,14 @@ static int aiu_probe(struct platform_device *pdev) - - return 0; - err: -+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]); - snd_soc_unregister_component(dev); - return ret; - } - - static void aiu_remove(struct platform_device *pdev) - { -+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]); - snd_soc_unregister_component(&pdev->dev); - } - -diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h ---- a/sound/soc/meson/aiu.h -+++ b/sound/soc/meson/aiu.h -@@ -7,6 +7,8 @@ - #ifndef _MESON_AIU_H - #define _MESON_AIU_H - -+#include "gx-formatter.h" -+ - struct clk; - struct clk_bulk_data; - struct device; -@@ -25,6 +27,7 @@ struct aiu_interface { - struct clk_bulk_data *clks; - unsigned int clk_num; - int irq; -+ struct gx_iface iface; - }; - - struct aiu_platform_data { -@@ -58,6 +61,7 @@ extern const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops; - extern const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops; - extern const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops; - extern const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops; -+extern const struct gx_formatter_ops aiu_formatter_i2s_ops; - - #define AIU_IEC958_BPF 0x000 - #define AIU_958_MISC 0x010 -diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c ---- a/sound/soc/meson/axg-card.c -+++ b/sound/soc/meson/axg-card.c -@@ -107,6 +107,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, - struct snd_soc_dai_link *pad; - struct snd_soc_dai_link *lb; - struct snd_soc_dai_link_component *dlc; -+ struct device *dev = card->dev; - int ret; - - /* extend links */ -@@ -117,11 +118,11 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card, - pad = &card->dai_link[*index]; - lb = &card->dai_link[*index + 1]; - -- lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name); -+ lb->name = devm_kasprintf(dev, GFP_KERNEL, "%s-lb", pad->name); - if (!lb->name) - return -ENOMEM; - -- dlc = devm_kzalloc(card->dev, sizeof(*dlc), GFP_KERNEL); -+ dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL); - if (!dlc) - return -ENOMEM; - -@@ -158,13 +159,14 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, - struct device_node *node, - struct axg_dai_link_tdm_data *be) - { -+ struct device *dev = card->dev; - char propname[32]; - u32 tx, rx; - int i; - -- be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES, -+ be->tx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES, - sizeof(*be->tx_mask), GFP_KERNEL); -- be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES, -+ be->rx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES, - sizeof(*be->rx_mask), GFP_KERNEL); - if (!be->tx_mask || !be->rx_mask) - return -ENOMEM; -@@ -191,7 +193,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, - - /* ... but the interface should at least have one direction */ - if (!tx && !rx) { -- dev_err(card->dev, "tdm link has no cpu slots\n"); -+ dev_err(dev, "tdm link has no cpu slots\n"); - return -EINVAL; - } - -@@ -207,7 +209,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, - * Error if the slots can't accommodate the largest mask or - * if it is just too big - */ -- dev_err(card->dev, "bad slot number\n"); -+ dev_err(dev, "bad slot number\n"); - return -EINVAL; - } - -@@ -222,8 +224,9 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card, - struct axg_dai_link_tdm_data *be) - { - struct axg_dai_link_tdm_mask *codec_mask; -+ struct device *dev = card->dev; - -- codec_mask = devm_kcalloc(card->dev, link->num_codecs, -+ codec_mask = devm_kcalloc(dev, link->num_codecs, - sizeof(*codec_mask), GFP_KERNEL); - if (!codec_mask) - return -ENOMEM; -@@ -249,10 +252,11 @@ static int axg_card_parse_tdm(struct snd_soc_card *card, - struct meson_card *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link *link = &card->dai_link[*index]; - struct axg_dai_link_tdm_data *be; -+ struct device *dev = card->dev; - int ret; - - /* Allocate tdm link parameters */ -- be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL); -+ be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL); - if (!be) - return -ENOMEM; - priv->link_data[*index] = be; -@@ -266,7 +270,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card, - - ret = axg_card_parse_cpu_tdm_slots(card, link, node, be); - if (ret) { -- dev_err(card->dev, "error parsing tdm link slots\n"); -+ dev_err(dev, "error parsing tdm link slots\n"); - return ret; - } - -@@ -310,9 +314,10 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, - { - struct snd_soc_dai_link *dai_link = &card->dai_link[*index]; - struct snd_soc_dai_link_component *cpu; -+ struct device *dev = card->dev; - int ret; - -- cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL); -+ cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL); - if (!cpu) - return -ENOMEM; - -diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c ---- a/sound/soc/meson/g12a-toacodec.c -+++ b/sound/soc/meson/g12a-toacodec.c -@@ -312,7 +312,7 @@ static int g12a_toacodec_probe(struct platform_device *pdev) - - ret = device_reset(dev); - if (ret) -- return ret; -+ return dev_err_probe(dev, ret, "failed to reset device\n"); - - regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(regs)) -diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c ---- a/sound/soc/meson/g12a-tohdmitx.c -+++ b/sound/soc/meson/g12a-tohdmitx.c -@@ -251,7 +251,7 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev) - - ret = device_reset(dev); - if (ret) -- return ret; -+ return dev_err_probe(dev, ret, "failed to reset device\n"); - - regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(regs)) -diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c ---- a/sound/soc/meson/gx-card.c -+++ b/sound/soc/meson/gx-card.c -@@ -48,9 +48,10 @@ static int gx_card_parse_i2s(struct snd_soc_card *card, - struct meson_card *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link *link = &card->dai_link[*index]; - struct gx_dai_link_i2s_data *be; -+ struct device *dev = card->dev; - - /* Allocate i2s link parameters */ -- be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL); -+ be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL); - if (!be) - return -ENOMEM; - priv->link_data[*index] = be; -@@ -81,9 +82,10 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np, - { - struct snd_soc_dai_link *dai_link = &card->dai_link[*index]; - struct snd_soc_dai_link_component *cpu; -+ struct device *dev = card->dev; - int ret; - -- cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL); -+ cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL); - if (!cpu) - return -ENOMEM; - -diff --git a/sound/soc/meson/gx-formatter.c b/sound/soc/meson/gx-formatter.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/meson/gx-formatter.c -@@ -0,0 +1,282 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR MIT) -+// -+// Copyright (c) 2026 BayLibre, SAS. -+// Author: Valerio Setti -+ -+#include -+#include -+#include -+#include -+ -+#include "gx-formatter.h" -+ -+struct gx_formatter { -+ struct list_head list; -+ struct gx_stream *stream; -+ const struct gx_formatter_driver *drv; -+ bool enabled; -+ struct regmap *map; -+}; -+ -+static int gx_formatter_enable(struct gx_formatter *formatter) -+{ -+ int ret; -+ -+ /* Do nothing if the formatter is already enabled */ -+ if (formatter->enabled) -+ return 0; -+ -+ /* Setup the stream parameter in the formatter */ -+ if (formatter->drv->ops->prepare) { -+ ret = formatter->drv->ops->prepare(formatter->map, -+ formatter->drv->quirks, -+ formatter->stream); -+ if (ret) -+ return ret; -+ } -+ -+ /* Finally, actually enable the formatter */ -+ if (formatter->drv->ops->enable) -+ formatter->drv->ops->enable(formatter->map); -+ -+ formatter->enabled = true; -+ -+ return 0; -+} -+ -+static void gx_formatter_disable(struct gx_formatter *formatter) -+{ -+ /* Do nothing if the formatter is already disabled */ -+ if (!formatter->enabled) -+ return; -+ -+ if (formatter->drv->ops->disable) -+ formatter->drv->ops->disable(formatter->map); -+ -+ formatter->enabled = false; -+} -+ -+static int gx_formatter_attach(struct gx_formatter *formatter) -+{ -+ struct gx_stream *ts = formatter->stream; -+ int ret = 0; -+ -+ mutex_lock(&ts->lock); -+ -+ /* Catch up if the stream is already running when we attach */ -+ if (ts->ready) { -+ ret = gx_formatter_enable(formatter); -+ if (ret) { -+ pr_err("failed to enable formatter\n"); -+ goto out; -+ } -+ } -+ -+ list_add_tail(&formatter->list, &ts->formatter_list); -+out: -+ mutex_unlock(&ts->lock); -+ return ret; -+} -+ -+static void gx_formatter_detach(struct gx_formatter *formatter) -+{ -+ struct gx_stream *ts = formatter->stream; -+ -+ if (!ts) -+ return; -+ -+ mutex_lock(&ts->lock); -+ list_del(&formatter->list); -+ mutex_unlock(&ts->lock); -+ -+ gx_formatter_disable(formatter); -+} -+ -+static int gx_formatter_power_up(struct gx_formatter *formatter, -+ struct snd_soc_dapm_widget *w) -+{ -+ struct gx_stream *ts = formatter->drv->ops->get_stream(w); -+ int ret; -+ -+ /* -+ * If we don't get a stream at this stage, it would mean that the -+ * widget is powering up but is not attached to any backend DAI. -+ * It should not happen, ever ! -+ */ -+ if (WARN_ON(!ts)) -+ return -ENODEV; -+ -+ formatter->stream = ts; -+ INIT_LIST_HEAD(&formatter->list); -+ ret = gx_formatter_attach(formatter); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static void gx_formatter_power_down(struct gx_formatter *formatter) -+{ -+ gx_formatter_detach(formatter); -+ formatter->stream = NULL; -+} -+ -+int gx_formatter_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *control, -+ int event) -+{ -+ struct snd_soc_component *c; -+ struct gx_formatter *formatter; -+ int ret = 0; -+ -+ c = snd_soc_dapm_to_component(w->dapm); -+ -+ if (w->priv) -+ formatter = w->priv; -+ else -+ formatter = snd_soc_component_get_drvdata(c); -+ -+ switch (event) { -+ case SND_SOC_DAPM_PRE_PMU: -+ ret = gx_formatter_power_up(formatter, w); -+ break; -+ -+ case SND_SOC_DAPM_PRE_PMD: -+ gx_formatter_power_down(formatter); -+ break; -+ -+ default: -+ dev_err(c->dev, "Unexpected event %d\n", event); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(gx_formatter_event); -+ -+int gx_formatter_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ const struct gx_formatter_driver *drv; -+ struct gx_formatter *formatter; -+ void __iomem *regs; -+ -+ drv = of_device_get_match_data(dev); -+ if (!drv) { -+ dev_err(dev, "failed to match device\n"); -+ return -ENODEV; -+ } -+ -+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL); -+ if (!formatter) -+ return -ENOMEM; -+ platform_set_drvdata(pdev, formatter); -+ formatter->drv = drv; -+ -+ regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(regs)) -+ return PTR_ERR(regs); -+ -+ formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg); -+ if (IS_ERR(formatter->map)) { -+ dev_err(dev, "failed to init regmap: %ld\n", -+ PTR_ERR(formatter->map)); -+ return PTR_ERR(formatter->map); -+ } -+ -+ return devm_snd_soc_register_component(dev, drv->component_drv, -+ NULL, 0); -+} -+EXPORT_SYMBOL_GPL(gx_formatter_probe); -+ -+int gx_formatter_create(struct device *dev, -+ struct snd_soc_dapm_widget *w, -+ const struct gx_formatter_driver *drv, -+ struct regmap *regmap) -+{ -+ struct gx_formatter *formatter; -+ -+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL); -+ if (!formatter) -+ return -ENOMEM; -+ -+ formatter->drv = drv; -+ formatter->map = regmap; -+ -+ w->priv = formatter; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(gx_formatter_create); -+ -+int gx_stream_start(struct gx_stream *ts) -+{ -+ struct gx_formatter *formatter; -+ int ret = 0; -+ -+ mutex_lock(&ts->lock); -+ -+ /* Start all the formatters attached to the stream */ -+ list_for_each_entry(formatter, &ts->formatter_list, list) { -+ ret = gx_formatter_enable(formatter); -+ if (ret) { -+ pr_err("failed to enable formatter\n"); -+ goto out; -+ } -+ } -+ -+ ts->ready = true; -+ -+out: -+ mutex_unlock(&ts->lock); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(gx_stream_start); -+ -+void gx_stream_stop(struct gx_stream *ts) -+{ -+ struct gx_formatter *formatter; -+ -+ mutex_lock(&ts->lock); -+ ts->ready = false; -+ -+ /* Stop all the formatters attached to the stream */ -+ list_for_each_entry(formatter, &ts->formatter_list, list) { -+ gx_formatter_disable(formatter); -+ } -+ -+ mutex_unlock(&ts->lock); -+} -+EXPORT_SYMBOL_GPL(gx_stream_stop); -+ -+struct gx_stream *gx_stream_alloc(struct gx_iface *iface) -+{ -+ struct gx_stream *ts; -+ -+ ts = kzalloc(sizeof(*ts), GFP_KERNEL); -+ if (ts) { -+ INIT_LIST_HEAD(&ts->formatter_list); -+ mutex_init(&ts->lock); -+ ts->iface = iface; -+ } -+ -+ return ts; -+} -+EXPORT_SYMBOL_GPL(gx_stream_alloc); -+ -+void gx_stream_free(struct gx_stream *ts) -+{ -+ /* -+ * If the list is not empty, it would mean that one of the formatter -+ * widget is still powered and attached to the interface while we -+ * are removing the TDM DAI. It should not be possible -+ */ -+ WARN_ON(!list_empty(&ts->formatter_list)); -+ mutex_destroy(&ts->lock); -+ kfree(ts); -+} -+EXPORT_SYMBOL_GPL(gx_stream_free); -+ -+MODULE_DESCRIPTION("Amlogic GX formatter driver"); -+MODULE_AUTHOR("Valerio Setti "); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/meson/gx-formatter.h b/sound/soc/meson/gx-formatter.h -new file mode 100644 ---- /dev/null -+++ b/sound/soc/meson/gx-formatter.h -@@ -0,0 +1,56 @@ -+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ -+/* -+ * Copyright (c) 2026 Baylibre SAS. -+ * Author: Valerio Setti -+ */ -+ -+#ifndef _MESON_GX_FORMATTER_H -+#define _MESON_GX_FORMATTER_H -+ -+#include "gx-interface.h" -+ -+struct platform_device; -+struct regmap; -+struct snd_soc_dapm_widget; -+struct snd_kcontrol; -+ -+struct gx_formatter_hw { -+ unsigned int skew_offset; -+}; -+ -+struct gx_formatter_ops { -+ struct gx_stream *(*get_stream)(struct snd_soc_dapm_widget *w); -+ void (*enable)(struct regmap *map); -+ void (*disable)(struct regmap *map); -+ int (*prepare)(struct regmap *map, -+ const struct gx_formatter_hw *quirks, -+ struct gx_stream *ts); -+}; -+ -+struct gx_formatter_driver { -+ const struct snd_soc_component_driver *component_drv; -+ const struct regmap_config *regmap_cfg; -+ const struct gx_formatter_ops *ops; -+ const struct gx_formatter_hw *quirks; -+}; -+ -+int gx_formatter_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *control, -+ int event); -+int gx_formatter_probe(struct platform_device *pdev); -+ -+int gx_formatter_create(struct device *dev, -+ struct snd_soc_dapm_widget *w, -+ const struct gx_formatter_driver *drv, -+ struct regmap *regmap); -+ -+/* -+ * Formatter data is already freed when the associated device is removed, -+ * so we just need to remove the pointer from the widget. -+ */ -+static inline void gx_formatter_free(struct snd_soc_dapm_widget *w) -+{ -+ w->priv = NULL; -+} -+ -+#endif /* _MESON_GX_FORMATTER_H */ -diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h -new file mode 100644 ---- /dev/null -+++ b/sound/soc/meson/gx-interface.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ -+/* -+ * Copyright (c) 2026 Baylibre SAS. -+ * Author: Valerio Setti -+ */ -+ -+#ifndef _MESON_GX_INTERFACE_H -+#define _MESON_GX_INTERFACE_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+struct gx_iface { -+ struct clk *mclk; -+ unsigned long mclk_rate; -+ -+ /* format is common to all the DAIs of the iface */ -+ unsigned int fmt; -+}; -+ -+struct gx_stream { -+ struct gx_iface *iface; -+ struct list_head formatter_list; -+ struct mutex lock; -+ unsigned int channels; -+ unsigned int width; -+ unsigned int physical_width; -+ bool ready; -+ -+ /* For continuous clock tracking */ -+ bool clk_enabled; -+}; -+ -+struct gx_stream *gx_stream_alloc(struct gx_iface *iface); -+void gx_stream_free(struct gx_stream *ts); -+int gx_stream_start(struct gx_stream *ts); -+void gx_stream_stop(struct gx_stream *ts); -+ -+#endif /* _MESON_GX_INTERFACE_H */ -diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c ---- a/sound/soc/meson/meson-card-utils.c -+++ b/sound/soc/meson/meson-card-utils.c -@@ -71,6 +71,7 @@ int meson_card_parse_dai(struct snd_soc_card *card, - struct device_node *node, - struct snd_soc_dai_link_component *dlc) - { -+ struct device *dev = card->dev; - int ret; - - if (!dlc || !node) -@@ -78,7 +79,7 @@ int meson_card_parse_dai(struct snd_soc_card *card, - - ret = snd_soc_of_get_dlc(node, NULL, dlc, 0); - if (ret) -- return dev_err_probe(card->dev, ret, "can't parse dai\n"); -+ return dev_err_probe(dev, ret, "can't parse dai\n"); - - return ret; - } -@@ -89,7 +90,8 @@ static int meson_card_set_link_name(struct snd_soc_card *card, - struct device_node *node, - const char *prefix) - { -- char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s", -+ struct device *dev = card->dev; -+ char *name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s", - prefix, node->full_name); - if (!name) - return -ENOMEM; -@@ -132,16 +134,17 @@ int meson_card_set_be_link(struct snd_soc_card *card, - struct device_node *node) - { - struct snd_soc_dai_link_component *codec; -+ struct device *dev = card->dev; - int ret, num_codecs; - - num_codecs = of_get_child_count(node); - if (!num_codecs) { -- dev_err(card->dev, "be link %s has no codec\n", -+ dev_err(dev, "be link %s has no codec\n", - node->full_name); - return -EINVAL; - } - -- codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL); -+ codec = devm_kcalloc(dev, num_codecs, sizeof(*codec), GFP_KERNEL); - if (!codec) - return -ENOMEM; - -@@ -158,7 +161,7 @@ int meson_card_set_be_link(struct snd_soc_card *card, - - ret = meson_card_set_link_name(card, link, node, "be"); - if (ret) -- dev_err(card->dev, "error setting %pOFn link name\n", node); -+ dev_err(dev, "error setting %pOFn link name\n", node); - - return ret; - } -@@ -189,12 +192,13 @@ EXPORT_SYMBOL_GPL(meson_card_set_fe_link); - static int meson_card_add_links(struct snd_soc_card *card) - { - struct meson_card *priv = snd_soc_card_get_drvdata(card); -- struct device_node *node = card->dev->of_node; -+ struct device *dev = card->dev; -+ struct device_node *node = dev->of_node; - int num, i, ret; - - num = of_get_child_count(node); - if (!num) { -- dev_err(card->dev, "card has no links\n"); -+ dev_err(dev, "card has no links\n"); - return -EINVAL; - } - -@@ -219,8 +223,10 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card, - int (*func)(struct snd_soc_card *c, - const char *p)) - { -+ struct device *dev = card->dev; -+ - /* If property is not provided, don't fail ... */ -- if (!of_property_present(card->dev->of_node, propname)) -+ if (!of_property_present(dev->of_node, propname)) - return 0; - - /* ... but do fail if it is provided and the parsing fails */ -diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c ---- a/sound/soc/meson/t9015.c -+++ b/sound/soc/meson/t9015.c -@@ -78,8 +78,14 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - return 0; - } - -+static const u64 t9015_dai_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J; -+ - static const struct snd_soc_dai_ops t9015_dai_ops = { - .set_fmt = t9015_dai_set_fmt, -+ .auto_selectable_formats = &t9015_dai_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver t9015_dai = { -@@ -265,10 +271,8 @@ static int t9015_probe(struct platform_device *pdev) - return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n"); - - ret = device_reset(dev); -- if (ret) { -- dev_err(dev, "reset failed\n"); -- return ret; -- } -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to reset device\n"); - - regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(regs)) { -diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c ---- a/sound/soc/mxs/mxs-saif.c -+++ b/sound/soc/mxs/mxs-saif.c -@@ -826,12 +826,9 @@ static int mxs_saif_probe(struct platform_device *pdev) - mxs_saif[saif->id] = saif; - - saif->clk = devm_clk_get(&pdev->dev, NULL); -- if (IS_ERR(saif->clk)) { -- ret = PTR_ERR(saif->clk); -- dev_err(&pdev->dev, "Cannot get the clock: %d\n", -- ret); -- return ret; -- } -+ if (IS_ERR(saif->clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(saif->clk), -+ "Cannot get the clock\n"); - - saif->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(saif->base)) -@@ -844,10 +841,8 @@ static int mxs_saif_probe(struct platform_device *pdev) - saif->dev = &pdev->dev; - ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0, - dev_name(&pdev->dev), saif); -- if (ret) { -- dev_err(&pdev->dev, "failed to request irq\n"); -+ if (ret) - return ret; -- } - - platform_set_drvdata(pdev, saif); - -@@ -860,16 +855,12 @@ static int mxs_saif_probe(struct platform_device *pdev) - - ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component, - &mxs_saif_dai, 1); -- if (ret) { -- dev_err(&pdev->dev, "register DAI failed\n"); -+ if (ret) - return ret; -- } - - ret = mxs_pcm_platform_register(&pdev->dev); -- if (ret) { -- dev_err(&pdev->dev, "register PCM failed: %d\n", ret); -+ if (ret) - return ret; -- } - - return 0; - } -diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c ---- a/sound/soc/mxs/mxs-sgtl5000.c -+++ b/sound/soc/mxs/mxs-sgtl5000.c -@@ -155,8 +155,6 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev) - - ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); - if (ret) { -- dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n", -- ret); - mxs_saif_put_mclk(0); - return ret; - } -diff --git a/sound/soc/pxa/pxa2xx-ac97-lib.c b/sound/soc/pxa/pxa2xx-ac97-lib.c ---- a/sound/soc/pxa/pxa2xx-ac97-lib.c -+++ b/sound/soc/pxa/pxa2xx-ac97-lib.c -@@ -316,10 +316,8 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev) - int irq; - - ac97_reg_base = devm_platform_ioremap_resource(dev, 0); -- if (IS_ERR(ac97_reg_base)) { -- dev_err(&dev->dev, "Missing MMIO resource\n"); -+ if (IS_ERR(ac97_reg_base)) - return PTR_ERR(ac97_reg_base); -- } - - if (cpu_is_pxa27x()) { - /* Assert reset using GPIOD_OUT_HIGH, because reset is GPIO_ACTIVE_LOW */ -diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c ---- a/sound/soc/qcom/common.c -+++ b/sound/soc/qcom/common.c -@@ -23,6 +23,161 @@ static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = { - SND_SOC_DAPM_SPK("DP7 Jack", NULL), - }; - -+static struct device_node *qcom_snd_get_link_node(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); -+ struct snd_soc_card *card = rtd->card; -+ struct of_phandle_args args; -+ int ret; -+ -+ if (!card->dev || !card->dev->of_node) -+ return NULL; -+ -+ for_each_available_child_of_node_scoped(card->dev->of_node, np) { -+ struct device_node *cpu_np __free(device_node) = -+ of_get_child_by_name(np, "cpu"); -+ -+ if (!cpu_np) -+ continue; -+ -+ ret = of_parse_phandle_with_args(cpu_np, "sound-dai", "#sound-dai-cells", 0, -+ &args); -+ if (ret) -+ continue; -+ -+ if (args.np == rtd->dai_link->cpus[0].of_node && -+ args.args_count == 1 && args.args[0] == cpu_dai->id) { -+ of_node_put(args.np); -+ return of_node_get(np); -+ } -+ -+ of_node_put(args.np); -+ } -+ -+ return NULL; -+} -+ -+static int qcom_snd_parse_tdm_slot(struct device_node *np, -+ struct qcom_snd_tdm_slot_cfg *cfg) -+{ -+ memset(cfg, 0, sizeof(*cfg)); -+ -+ return snd_soc_of_parse_tdm_slot(np, &cfg->tx_mask, &cfg->rx_mask, -+ &cfg->slots, &cfg->slot_width); -+} -+ -+static int qcom_snd_normalize_tdm_slots(struct qcom_snd_tdm_slot_cfg *cpu_cfg, -+ struct qcom_snd_tdm_slot_cfg *codec_cfg) -+{ -+ unsigned int slots; -+ unsigned int slot_width; -+ -+ if (cpu_cfg->slots && codec_cfg->slots && cpu_cfg->slots != codec_cfg->slots) -+ return -EINVAL; -+ -+ if (cpu_cfg->slot_width && codec_cfg->slot_width && -+ cpu_cfg->slot_width != codec_cfg->slot_width) -+ return -EINVAL; -+ -+ slots = cpu_cfg->slots ?: codec_cfg->slots; -+ if (!slots) -+ return 0; -+ -+ slot_width = cpu_cfg->slot_width ?: codec_cfg->slot_width; -+ if (!slot_width) -+ return -EINVAL; -+ -+ cpu_cfg->slots = slots; -+ codec_cfg->slots = slots; -+ cpu_cfg->slot_width = slot_width; -+ codec_cfg->slot_width = slot_width; -+ -+ return 0; -+} -+ -+static int qcom_snd_parse_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd, -+ struct qcom_snd_tdm_slot_cfg *cpu_cfg, -+ struct qcom_snd_tdm_slot_cfg *codec_cfg) -+{ -+ struct device_node *link_np __free(device_node) = qcom_snd_get_link_node(rtd); -+ int ret; -+ -+ if (!link_np) -+ return -EINVAL; -+ -+ struct device_node *cpu_np __free(device_node) = -+ of_get_child_by_name(link_np, "cpu"); -+ struct device_node *codec_np __free(device_node) = -+ of_get_child_by_name(link_np, "codec"); -+ if (!cpu_np || !codec_np) -+ return -EINVAL; -+ -+ ret = qcom_snd_parse_tdm_slot(cpu_np, cpu_cfg); -+ if (ret) -+ return ret; -+ -+ return qcom_snd_parse_tdm_slot(codec_np, codec_cfg); -+} -+ -+int qcom_snd_get_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd, -+ struct qcom_snd_tdm_slot_cfg *cpu_cfg, -+ struct qcom_snd_tdm_slot_cfg *codec_cfg) -+{ -+ int ret; -+ -+ ret = qcom_snd_parse_dai_tdm_slots(rtd, cpu_cfg, codec_cfg); -+ if (ret) -+ return ret; -+ -+ return qcom_snd_normalize_tdm_slots(cpu_cfg, codec_cfg); -+} -+EXPORT_SYMBOL_GPL(qcom_snd_get_dai_tdm_slots); -+ -+int qcom_snd_apply_dai_tdm_slots_cfg(struct snd_soc_pcm_runtime *rtd, -+ const struct qcom_snd_tdm_slot_cfg *cpu_cfg, -+ const struct qcom_snd_tdm_slot_cfg *codec_cfg) -+{ -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); -+ struct snd_soc_dai *codec_dai; -+ int i; -+ int ret; -+ -+ if (!cpu_cfg->slots) -+ return 0; -+ -+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, cpu_cfg->tx_mask, cpu_cfg->rx_mask, -+ cpu_cfg->slots, cpu_cfg->slot_width); -+ if (ret) -+ return ret; -+ -+ for_each_rtd_codec_dais(rtd, i, codec_dai) { -+ ret = snd_soc_dai_set_tdm_slot(codec_dai, -+ codec_cfg->tx_mask, -+ codec_cfg->rx_mask, -+ codec_cfg->slots, -+ codec_cfg->slot_width); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(qcom_snd_apply_dai_tdm_slots_cfg); -+ -+int qcom_snd_apply_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct qcom_snd_tdm_slot_cfg cpu_cfg; -+ struct qcom_snd_tdm_slot_cfg codec_cfg; -+ int ret; -+ -+ ret = qcom_snd_get_dai_tdm_slots(rtd, &cpu_cfg, &codec_cfg); -+ if (ret) -+ return ret == -EINVAL ? 0 : ret; -+ -+ return qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg); -+} -+EXPORT_SYMBOL_GPL(qcom_snd_apply_dai_tdm_slots); -+ - int qcom_snd_parse_of(struct snd_soc_card *card) - { - struct device *dev = card->dev; -@@ -91,7 +246,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) - - ret = of_property_read_string(np, "link-name", &link->name); - if (ret) { -- dev_err(card->dev, "error getting codec dai_link name\n"); -+ dev_err(dev, "error getting codec dai_link name\n"); - return ret; - } - -@@ -109,7 +264,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) - - ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); - if (ret) { -- dev_err_probe(card->dev, ret, -+ dev_err_probe(dev, ret, - "%s: error getting cpu dai name\n", link->name); - return ret; - } -@@ -126,7 +281,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) - "sound-dai", - 0); - if (!link->platforms->of_node) { -- dev_err(card->dev, "%s: platform dai not found\n", link->name); -+ dev_err(dev, "%s: platform dai not found\n", link->name); - return -EINVAL; - } - } else { -@@ -136,7 +291,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card) - if (codec) { - ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); - if (ret < 0) { -- dev_err_probe(card->dev, ret, -+ dev_err_probe(dev, ret, - "%s: codec dai not found\n", link->name); - return ret; - } -@@ -215,6 +370,7 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, - } - - switch (cpu_dai->id) { -+ case LPI_MI2S_RX_0: - case TX_CODEC_DMA_TX_0: - case TX_CODEC_DMA_TX_1: - case TX_CODEC_DMA_TX_2: -diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h ---- a/sound/soc/qcom/common.h -+++ b/sound/soc/qcom/common.h -@@ -7,9 +7,23 @@ - #include - #include - --#define LPASS_MAX_PORT (SENARY_MI2S_TX + 1) -+#define LPASS_MAX_PORT (LPI_MI2S_TX_6 + 1) -+ -+struct qcom_snd_tdm_slot_cfg { -+ unsigned int tx_mask; -+ unsigned int rx_mask; -+ unsigned int slots; -+ unsigned int slot_width; -+}; - - int qcom_snd_parse_of(struct snd_soc_card *card); -+int qcom_snd_get_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd, -+ struct qcom_snd_tdm_slot_cfg *cpu_cfg, -+ struct qcom_snd_tdm_slot_cfg *codec_cfg); -+int qcom_snd_apply_dai_tdm_slots_cfg(struct snd_soc_pcm_runtime *rtd, -+ const struct qcom_snd_tdm_slot_cfg *cpu_cfg, -+ const struct qcom_snd_tdm_slot_cfg *codec_cfg); -+int qcom_snd_apply_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd); - int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_jack *jack, bool *jack_setup); - int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, -diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c ---- a/sound/soc/qcom/qdsp6/audioreach.c -+++ b/sound/soc/qcom/qdsp6/audioreach.c -@@ -152,6 +152,13 @@ struct apm_i2s_module_intf_cfg { - - #define APM_I2S_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_i2s_module_intf_cfg), 8) - -+struct apm_audio_if_module_intf_cfg { -+ struct apm_module_param_data param_data; -+ struct param_id_audio_if_intf_cfg cfg; -+} __packed; -+ -+#define APM_AUDIO_IF_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_audio_if_module_intf_cfg), 8) -+ - struct apm_module_hw_ep_mf_cfg { - struct apm_module_param_data param_data; - struct param_id_hw_ep_mf mf; -@@ -168,6 +175,13 @@ struct apm_module_frame_size_factor_cfg { - - #define APM_FS_CFG_PSIZE ALIGN(sizeof(struct apm_module_frame_size_factor_cfg), 8) - -+struct apm_module_hw_ep_frame_duration_cfg { -+ struct apm_module_param_data param_data; -+ struct param_id_hw_ep_frame_duration frame_duration; -+} __packed; -+ -+#define APM_HW_EP_FRAME_DURATION_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_frame_duration_cfg), 8) -+ - struct apm_module_hw_ep_power_mode_cfg { - struct apm_module_param_data param_data; - struct param_id_hw_ep_power_mode_cfg power_mode; -@@ -703,6 +717,7 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, - int pm_sz = APM_HW_EP_PMODE_CFG_PSIZE; - int size = ic_sz + ep_sz + fs_sz + pm_sz; - void *p; -+ int i; - - struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); - if (IS_ERR(pkt)) -@@ -741,7 +756,12 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, - - intf_cfg->cfg.lpaif_type = module->hw_interface_type; - intf_cfg->cfg.intf_index = module->hw_interface_idx; -- intf_cfg->cfg.active_channels_mask = (1 << cfg->num_channels) - 1; -+ intf_cfg->cfg.active_channels_mask = 0; -+ /* Convert the physical channel mapping into a bit field */ -+ for (i = 0; i < AR_PCM_MAX_NUM_CHANNEL; i++) -+ if (cfg->channel_map[i]) -+ intf_cfg->cfg.active_channels_mask |= BIT(i); -+ - p += ic_sz; - - pm_cfg = p; -@@ -840,7 +860,7 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, - uint32_t num_channels = cfg->num_channels; - int payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) + - APM_MODULE_PARAM_DATA_SIZE; -- int i; -+ int i, j; - void *p; - - struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); -@@ -860,8 +880,12 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, - media_format->sample_rate = cfg->sample_rate; - media_format->bit_width = cfg->bit_width; - media_format->num_channels = cfg->num_channels; -- for (i = 0; i < num_channels; i++) -- media_format->channel_mapping[i] = cfg->channel_map[i]; -+ /* Convert the physical mapping to a logical mapping of the channels */ -+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) { -+ if (!cfg->channel_map[i]) -+ continue; -+ media_format->channel_mapping[j++] = cfg->channel_map[i]; -+ } - - return q6apm_send_cmd_sync(graph->apm, pkt, 0); - } -@@ -1042,6 +1066,81 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph, - return q6apm_send_cmd_sync(graph->apm, pkt, 0); - } - -+static int audioreach_audio_if_set_media_format(struct q6apm_graph *graph, -+ const struct audioreach_module *module, -+ const struct audioreach_module_config *cfg) -+{ -+ struct apm_module_hw_ep_frame_duration_cfg *fd_cfg; -+ struct apm_module_param_data *param_data; -+ struct apm_audio_if_module_intf_cfg *intf_cfg; -+ struct apm_module_hw_ep_mf_cfg *hw_cfg; -+ int ic_sz = APM_AUDIO_IF_INTF_CFG_PSIZE; -+ int ep_sz = APM_HW_EP_CFG_PSIZE; -+ int fd_sz = APM_HW_EP_FRAME_DURATION_PSIZE; -+ int size = ic_sz + ep_sz + fd_sz; -+ u32 slot_mask = cfg->slot_mask ? cfg->slot_mask : module->slot_mask; -+ u16 nslots_per_frame = cfg->nslots_per_frame ? -+ (u16)cfg->nslots_per_frame : module->nslots_per_frame; -+ u16 slot_width = cfg->slot_width ? (u16)cfg->slot_width : module->slot_width; -+ void *p; -+ -+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); -+ if (IS_ERR(pkt)) -+ return PTR_ERR(pkt); -+ -+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; -+ intf_cfg = p; -+ -+ param_data = &intf_cfg->param_data; -+ param_data->module_instance_id = module->instance_id; -+ param_data->error_code = 0; -+ param_data->param_id = PARAM_ID_AUDIO_IF_INTF_CFG; -+ param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE; -+ intf_cfg->cfg.qaif_type = module->qaif_type; -+ intf_cfg->cfg.intf_idx = (u16)module->hw_interface_idx; -+ intf_cfg->cfg.intf_mode = module->intf_mode; -+ intf_cfg->cfg.ctrl_data_out_enable = module->ctrl_data_out_enable; -+ intf_cfg->cfg.active_slot_mask = slot_mask; -+ intf_cfg->cfg.nslots_per_frame = nslots_per_frame; -+ intf_cfg->cfg.slot_width = slot_width; -+ intf_cfg->cfg.active_lane_mask = module->active_lane_mask; -+ intf_cfg->cfg.frame_sync_rate = module->frame_sync_rate; -+ intf_cfg->cfg.frame_sync_src = module->sync_src; -+ intf_cfg->cfg.frame_sync_mode = module->sync_mode; -+ intf_cfg->cfg.invert_frame_sync_pulse = module->ctrl_invert_sync_pulse; -+ intf_cfg->cfg.frame_sync_data_delay = module->ctrl_sync_data_delay; -+ intf_cfg->cfg.bit_clk_type = module->bit_clk_type; -+ intf_cfg->cfg.inv_int_bit_clk = module->inv_int_bit_clk; -+ intf_cfg->cfg.inv_ext_bit_clk = module->inv_ext_bit_clk; -+ -+ p += ic_sz; -+ hw_cfg = p; -+ param_data = &hw_cfg->param_data; -+ param_data->module_instance_id = module->instance_id; -+ param_data->error_code = 0; -+ param_data->param_id = PARAM_ID_HW_EP_MF_CFG; -+ param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE; -+ -+ hw_cfg->mf.sample_rate = cfg->sample_rate; -+ hw_cfg->mf.bit_width = cfg->bit_width; -+ hw_cfg->mf.num_channels = cfg->num_channels; -+ hw_cfg->mf.data_format = module->data_format; -+ -+ p += ep_sz; -+ fd_cfg = p; -+ param_data = &fd_cfg->param_data; -+ param_data->module_instance_id = module->instance_id; -+ param_data->error_code = 0; -+ param_data->param_id = PARAM_ID_HW_EP_FRAME_DURATION; -+ param_data->param_size = fd_sz - APM_MODULE_PARAM_DATA_SIZE; -+ fd_cfg->frame_duration.frame_duration_in_us = AUDIO_IF_FRAME_DURATION_US; -+ fd_cfg->frame_duration.allow_frame_duration_normalization = AUDIO_IF_FRAME_DURATION_NORMALIZATION_ENABLE; -+ fd_cfg->frame_duration.min_normalized_frame_dur_us = AUDIO_IF_FRAME_DURATION_MIN_US; -+ fd_cfg->frame_duration.max_normalized_frame_dur_us = AUDIO_IF_FRAME_DURATION_MAX_US; -+ -+ return q6apm_send_cmd_sync(graph->apm, pkt, 0); -+} -+ - static int audioreach_logging_set_media_format(struct q6apm_graph *graph, - const struct audioreach_module *module) - { -@@ -1080,6 +1179,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, - struct apm_pcm_module_media_fmt_cmd *cfg; - struct apm_module_param_data *param_data; - int payload_size; -+ int i, j; - - if (num_channels > 4) { - dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); -@@ -1113,7 +1213,12 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, - media_cfg->num_channels = mcfg->num_channels; - media_cfg->q_factor = mcfg->bit_width - 1; - media_cfg->bits_per_sample = mcfg->bit_width; -- memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); -+ /* Convert the physical mapping to a logical mapping of the channels */ -+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < mcfg->num_channels; i++) { -+ if (!mcfg->channel_map[i]) -+ continue; -+ media_cfg->channel_mapping[j++] = mcfg->channel_map[i]; -+ } - - return q6apm_send_cmd_sync(graph->apm, pkt, 0); - } -@@ -1163,6 +1268,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, - struct payload_media_fmt_pcm *cfg; - struct media_format *header; - int rc, payload_size; -+ int i, j; - void *p; - - if (num_channels > 4) { -@@ -1202,7 +1308,12 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, - cfg->q_factor = mcfg->bit_width - 1; - cfg->endianness = PCM_LITTLE_ENDIAN; - cfg->num_channels = mcfg->num_channels; -- memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); -+ /* Convert the physical mapping to a logical mapping of the channels */ -+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) { -+ if (!mcfg->channel_map[i]) -+ continue; -+ cfg->channel_mapping[j++] = mcfg->channel_map[i]; -+ } - } else { - rc = audioreach_set_compr_media_format(header, p, mcfg); - if (rc) -@@ -1279,7 +1390,7 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph, - struct apm_module_sp_vi_ex_mode_cfg *ex_cfg; - int op_sz, cm_sz, ex_sz; - struct apm_module_param_data *param_data; -- int rc, i, payload_size; -+ int rc, i, payload_size, j; - struct gpr_pkt *pkt; - void *p; - -@@ -1320,14 +1431,19 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph, - param_data->param_size = cm_sz - APM_MODULE_PARAM_DATA_SIZE; - - cm_cfg->cfg.num_channels = num_channels * 2; -- for (i = 0; i < num_channels; i++) { -+ /* Convert the physical mapping to a logical mapping of the channels */ -+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < num_channels; i++) { -+ if (!mcfg->channel_map[i]) -+ continue; - /* - * Map speakers into Vsense and then Isense of each channel. - * E.g. for PCM_CHANNEL_FL and PCM_CHANNEL_FR to: - * [1, 2, 3, 4] - */ -- cm_cfg->cfg.channel_mapping[2 * i] = (mcfg->channel_map[i] - 1) * 2 + 1; -- cm_cfg->cfg.channel_mapping[2 * i + 1] = (mcfg->channel_map[i] - 1) * 2 + 2; -+ cm_cfg->cfg.channel_mapping[2 * j] = (mcfg->channel_map[i] - 1) * 2 + 1; -+ cm_cfg->cfg.channel_mapping[2 * j + 1] = (mcfg->channel_map[i] - 1) * 2 + 2; -+ -+ ++j; - } - - p += cm_sz; -@@ -1411,6 +1527,10 @@ int audioreach_set_media_format(struct q6apm_graph *graph, - if (!rc) - rc = audioreach_module_enable(graph, module, true); - break; -+ case MODULE_ID_AUDIO_IF_SOURCE: -+ case MODULE_ID_AUDIO_IF_SINK: -+ rc = audioreach_audio_if_set_media_format(graph, module, cfg); -+ break; - - default: - rc = 0; -diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h ---- a/sound/soc/qcom/qdsp6/audioreach.h -+++ b/sound/soc/qcom/qdsp6/audioreach.h -@@ -36,6 +36,8 @@ struct q6apm_graph; - #define MODULE_ID_SPEAKER_PROTECTION 0x070010E2 - #define MODULE_ID_SPEAKER_PROTECTION_VI 0x070010E3 - #define MODULE_ID_OPUS_DEC 0x07001174 -+#define MODULE_ID_AUDIO_IF_SINK 0x0700117C -+#define MODULE_ID_AUDIO_IF_SOURCE 0x0700117D - - #define APM_CMD_GET_SPF_STATE 0x01001021 - #define APM_CMD_RSP_GET_SPF_STATE 0x02001007 -@@ -544,6 +546,74 @@ struct param_id_i2s_intf_cfg { - #define PORT_ID_I2S_OUPUT 1 - #define I2S_STACK_SIZE 2048 - -+#define PARAM_ID_AUDIO_IF_INTF_CFG 0x08001B11 -+ -+/* -+ * struct param_id_audio_if_intf_cfg - Audio interface configuration -+ * @qaif_type: Audio interface type (e.g. QAIF, QAIF_VA) -+ * @intf_idx: Interface instance index -+ * @intf_mode: Interface operating mode (TDM/PCM/I2S) -+ * @ctrl_data_out_enable: Enable sharing of data-out signal with other masters -+ * @active_slot_mask: Bitmask indicating active slots -+ * @nslots_per_frame: Number of slots per audio frame -+ * @slot_width: Width of each slot in bits -+ * @active_lane_mask: Bitmask of active data lanes -+ * @frame_sync_rate: Frame sync rate in Hz -+ * @frame_sync_src: Frame sync source selection -+ * @frame_sync_mode: Frame sync mode configuration -+ * @invert_frame_sync_pulse: Invert frame sync polarity when set -+ * @frame_sync_data_delay: Data delay from frame sync in bit clocks -+ * @bit_clk_type: Bit clock type (internal / external) -+ * @inv_int_bit_clk: Invert internal bit clock when set -+ * @inv_ext_bit_clk: Invert external bit clock when set -+ * -+ * This structure defines configuration parameters for the Qualcomm -+ * Audio Interface (QAIF) block. It is used to program interface -+ * characteristics such as slot configuration, clocking and frame -+ * synchronization behaviour. -+ */ -+struct param_id_audio_if_intf_cfg { -+ uint16_t qaif_type; -+ uint16_t intf_idx; -+ uint16_t intf_mode; -+ uint16_t ctrl_data_out_enable; -+ uint32_t active_slot_mask; -+ uint16_t nslots_per_frame; -+ uint16_t slot_width; -+ uint32_t active_lane_mask; -+ uint32_t frame_sync_rate; -+ uint16_t frame_sync_src; -+ uint16_t frame_sync_mode; -+ uint16_t invert_frame_sync_pulse; -+ uint16_t frame_sync_data_delay; -+ uint16_t bit_clk_type; -+ uint8_t inv_int_bit_clk; -+ uint8_t inv_ext_bit_clk; -+} __packed; -+ -+#define PARAM_ID_HW_EP_FRAME_DURATION 0x08001B2F -+#define AUDIO_IF_FRAME_DURATION_US 1000 -+#define AUDIO_IF_FRAME_DURATION_NORMALIZATION_ENABLE 1 -+#define AUDIO_IF_FRAME_DURATION_MIN_US 1 -+#define AUDIO_IF_FRAME_DURATION_MAX_US 100000 -+ -+/** -+ * struct param_id_hw_ep_frame_duration - Hardware endpoint frame duration -+ * @frame_duration_in_us: Frame duration in microseconds. -+ * @allow_frame_duration_normalization: Permit SPF to normalize frame duration. -+ * @min_normalized_frame_dur_us: Minimum normalized frame duration in microseconds. -+ * @max_normalized_frame_dur_us: Maximum normalized frame duration in microseconds. -+ * -+ * This structure configures the frame duration for the Audio IF hardware -+ * endpoint and, when enabled, the allowed normalization range. -+ */ -+struct param_id_hw_ep_frame_duration { -+ uint32_t frame_duration_in_us; -+ uint32_t allow_frame_duration_normalization; -+ uint32_t min_normalized_frame_dur_us; -+ uint32_t max_normalized_frame_dur_us; -+} __packed; -+ - #define PARAM_ID_DISPLAY_PORT_INTF_CFG 0x08001154 - - struct param_id_display_port_intf_cfg { -@@ -877,6 +947,23 @@ struct audioreach_module { - uint32_t data_format; - uint32_t hw_interface_type; - -+ /* Audio IF module (TDM/PCM/I2S) */ -+ u32 slot_mask; -+ u32 active_lane_mask; -+ u32 frame_sync_rate; -+ u16 qaif_type; -+ u16 sync_src; -+ u16 ctrl_data_out_enable; -+ u16 nslots_per_frame; -+ u16 slot_width; -+ u16 intf_mode; -+ u16 sync_mode; -+ u16 ctrl_invert_sync_pulse; -+ u16 ctrl_sync_data_delay; -+ u16 bit_clk_type; -+ u8 inv_int_bit_clk; -+ u8 inv_ext_bit_clk; -+ - /* PCM module specific */ - uint32_t interleave_type; - -@@ -907,6 +994,9 @@ struct audioreach_module_config { - u32 channel_allocation; - u32 sd_line_mask; - int fmt; -+ u32 slot_mask; -+ u16 nslots_per_frame; -+ u16 slot_width; - struct snd_codec codec; - u8 channel_map[AR_PCM_MAX_NUM_CHANNEL]; - }; -diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c ---- a/sound/soc/qcom/qdsp6/q6afe-dai.c -+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c -@@ -412,6 +412,8 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, - case SENARY_MI2S_RX ... SENARY_MI2S_TX: - case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: - case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: -+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: -+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6: - rc = q6afe_i2s_port_prepare(dai_data->port[dai->id], - &dai_data->port_config[dai->id].i2s_cfg); - if (rc < 0) { -@@ -665,6 +667,21 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { - - /* USB playback AFE port receives data for playback, hence use the RX port */ - {"USB Playback", NULL, "USB_RX"}, -+ -+ {"LPI RX0 MI2S Playback", NULL, "LPI_MI2S_RX_0"}, -+ {"LPI_MI2S_TX_0", NULL, "LPI TX0 MI2S Capture"}, -+ {"LPI RX1 MI2S Playback", NULL, "LPI_MI2S_RX_1"}, -+ {"LPI_MI2S_TX_1", NULL, "LPI TX1 MI2S Capture"}, -+ {"LPI RX2 MI2S Playback", NULL, "LPI_MI2S_RX_2"}, -+ {"LPI_MI2S_TX_2", NULL, "LPI TX2 MI2S Capture"}, -+ {"LPI RX3 MI2S Playback", NULL, "LPI_MI2S_RX_3"}, -+ {"LPI_MI2S_TX_3", NULL, "LPI TX3 MI2S Capture"}, -+ {"LPI RX4 MI2S Playback", NULL, "LPI_MI2S_RX_4"}, -+ {"LPI_MI2S_TX_4", NULL, "LPI TX4 MI2S Capture"}, -+ {"LPI RX5 MI2S Playback", NULL, "LPI_MI2S_RX_5"}, -+ {"LPI_MI2S_TX_5", NULL, "LPI TX5 MI2S Capture"}, -+ {"LPI RX6 MI2S Playback", NULL, "LPI_MI2S_RX_6"}, -+ {"LPI_MI2S_TX_6", NULL, "LPI TX6 MI2S Capture"}, - }; - - static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) -@@ -1011,6 +1028,35 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { - 0, SND_SOC_NOPM, 0, 0), - - SND_SOC_DAPM_AIF_IN("USB_RX", NULL, 0, SND_SOC_NOPM, 0, 0), -+ -+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_0", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_0", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_1", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_1", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_2", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_2", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_3", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_3", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_4", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_4", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_5", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_5", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_6", NULL, -+ 0, SND_SOC_NOPM, 0, 0), -+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_6", NULL, -+ 0, SND_SOC_NOPM, 0, 0), - }; - - static const struct snd_soc_component_driver q6afe_dai_component = { -@@ -1045,6 +1091,8 @@ static void of_q6afe_parse_dai_data(struct device *dev, - case SENARY_MI2S_RX ... SENARY_MI2S_TX: - case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: - case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: -+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: -+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6: - priv = &data->priv[id]; - ret = of_property_read_variable_u32_array(node, - "qcom,sd-lines", -diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c ---- a/sound/soc/qcom/qdsp6/q6afe.c -+++ b/sound/soc/qcom/qdsp6/q6afe.c -@@ -132,6 +132,20 @@ - #define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017 - #define AFE_PORT_ID_SENARY_MI2S_RX 0x1018 - #define AFE_PORT_ID_SENARY_MI2S_TX 0x1019 -+#define AFE_PORT_ID_INT0_MI2S_RX 0x102e -+#define AFE_PORT_ID_INT0_MI2S_TX 0x102f -+#define AFE_PORT_ID_INT1_MI2S_RX 0x1030 -+#define AFE_PORT_ID_INT1_MI2S_TX 0x1031 -+#define AFE_PORT_ID_INT2_MI2S_RX 0x1032 -+#define AFE_PORT_ID_INT2_MI2S_TX 0x1033 -+#define AFE_PORT_ID_INT3_MI2S_RX 0x1034 -+#define AFE_PORT_ID_INT3_MI2S_TX 0x1035 -+#define AFE_PORT_ID_INT4_MI2S_RX 0x1036 -+#define AFE_PORT_ID_INT4_MI2S_TX 0x1037 -+#define AFE_PORT_ID_INT5_MI2S_RX 0x1038 -+#define AFE_PORT_ID_INT5_MI2S_TX 0x1039 -+#define AFE_PORT_ID_INT6_MI2S_RX 0x103a -+#define AFE_PORT_ID_INT6_MI2S_TX 0x103b - - /* Start of the range of port IDs for TDM devices. */ - #define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000 -@@ -931,6 +945,34 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = { - [RX_CODEC_DMA_RX_7] = { AFE_PORT_ID_RX_CODEC_DMA_RX_7, - RX_CODEC_DMA_RX_7, 1, 1}, - [USB_RX] = { AFE_PORT_ID_USB_RX, USB_RX, 1, 1}, -+ [LPI_MI2S_RX_0] = { AFE_PORT_ID_INT0_MI2S_RX, -+ LPI_MI2S_RX_0, 1, 1}, -+ [LPI_MI2S_TX_0] = { AFE_PORT_ID_INT0_MI2S_TX, -+ LPI_MI2S_TX_0, 0, 1}, -+ [LPI_MI2S_RX_1] = { AFE_PORT_ID_INT1_MI2S_RX, -+ LPI_MI2S_RX_1, 1, 1}, -+ [LPI_MI2S_TX_1] = { AFE_PORT_ID_INT1_MI2S_TX, -+ LPI_MI2S_TX_1, 0, 1}, -+ [LPI_MI2S_RX_2] = { AFE_PORT_ID_INT2_MI2S_RX, -+ LPI_MI2S_RX_2, 1, 1}, -+ [LPI_MI2S_TX_2] = { AFE_PORT_ID_INT2_MI2S_TX, -+ LPI_MI2S_TX_2, 0, 1}, -+ [LPI_MI2S_RX_3] = { AFE_PORT_ID_INT3_MI2S_RX, -+ LPI_MI2S_RX_3, 1, 1}, -+ [LPI_MI2S_TX_3] = { AFE_PORT_ID_INT3_MI2S_TX, -+ LPI_MI2S_TX_3, 0, 1}, -+ [LPI_MI2S_RX_4] = { AFE_PORT_ID_INT4_MI2S_RX, -+ LPI_MI2S_RX_4, 1, 1}, -+ [LPI_MI2S_TX_4] = { AFE_PORT_ID_INT4_MI2S_TX, -+ LPI_MI2S_TX_4, 0, 1}, -+ [LPI_MI2S_RX_5] = { AFE_PORT_ID_INT5_MI2S_RX, -+ LPI_MI2S_RX_5, 1, 1}, -+ [LPI_MI2S_TX_5] = { AFE_PORT_ID_INT5_MI2S_TX, -+ LPI_MI2S_TX_5, 0, 1}, -+ [LPI_MI2S_RX_6] = { AFE_PORT_ID_INT6_MI2S_RX, -+ LPI_MI2S_RX_6, 1, 1}, -+ [LPI_MI2S_TX_6] = { AFE_PORT_ID_INT6_MI2S_TX, -+ LPI_MI2S_TX_6, 0, 1}, - }; - - static void q6afe_port_free(struct kref *ref) -@@ -1785,6 +1827,20 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) - case AFE_PORT_ID_QUINARY_MI2S_TX: - case AFE_PORT_ID_SENARY_MI2S_RX: - case AFE_PORT_ID_SENARY_MI2S_TX: -+ case AFE_PORT_ID_INT0_MI2S_RX: -+ case AFE_PORT_ID_INT0_MI2S_TX: -+ case AFE_PORT_ID_INT1_MI2S_RX: -+ case AFE_PORT_ID_INT1_MI2S_TX: -+ case AFE_PORT_ID_INT2_MI2S_RX: -+ case AFE_PORT_ID_INT2_MI2S_TX: -+ case AFE_PORT_ID_INT3_MI2S_RX: -+ case AFE_PORT_ID_INT3_MI2S_TX: -+ case AFE_PORT_ID_INT4_MI2S_RX: -+ case AFE_PORT_ID_INT4_MI2S_TX: -+ case AFE_PORT_ID_INT5_MI2S_RX: -+ case AFE_PORT_ID_INT5_MI2S_TX: -+ case AFE_PORT_ID_INT6_MI2S_RX: -+ case AFE_PORT_ID_INT6_MI2S_TX: - cfg_type = AFE_PARAM_ID_I2S_CONFIG; - break; - case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7: -diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c ---- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c -+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c -@@ -2,10 +2,12 @@ - // Copyright (c) 2021, Linaro Limited - - #include -+#include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -15,15 +17,54 @@ - #include "q6dsp-common.h" - #include "audioreach.h" - #include "q6apm.h" -+#include "q6prm.h" - - #define AUDIOREACH_BE_PCM_BASE 16 - -+struct q6apm_dai_priv_data { -+ struct clk *mclk; -+ struct clk *bclk; -+ bool mclk_enabled, bclk_enabled; -+}; -+ - struct q6apm_lpass_dai_data { - struct q6apm_graph *graph[APM_PORT_MAX]; - bool is_port_started[APM_PORT_MAX]; - struct audioreach_module_config module_config[APM_PORT_MAX]; -+ struct q6apm_dai_priv_data priv[APM_PORT_MAX]; - }; - -+static void q6apm_lpass_dai_disable_clocks(struct q6apm_lpass_dai_data *dai_data, int id) -+{ -+ if (dai_data->priv[id].mclk_enabled) { -+ clk_disable_unprepare(dai_data->priv[id].mclk); -+ dai_data->priv[id].mclk_enabled = false; -+ } -+ -+ if (dai_data->priv[id].bclk_enabled) { -+ clk_disable_unprepare(dai_data->priv[id].bclk); -+ dai_data->priv[id].bclk_enabled = false; -+ } -+} -+ -+static void q6apm_lpass_dai_put_clocks(struct q6apm_lpass_dai_data *dai_data) -+{ -+ int i; -+ -+ for (i = 0; i < APM_PORT_MAX; i++) { -+ q6apm_lpass_dai_disable_clocks(dai_data, i); -+ -+ if (dai_data->priv[i].mclk) { -+ clk_put(dai_data->priv[i].mclk); -+ dai_data->priv[i].mclk = NULL; -+ } -+ if (dai_data->priv[i].bclk) { -+ clk_put(dai_data->priv[i].bclk); -+ dai_data->priv[i].bclk = NULL; -+ } -+ } -+} -+ - static int q6dma_set_channel_map(struct snd_soc_dai *dai, - unsigned int tx_num, - const unsigned int *tx_ch_mask, -@@ -251,6 +292,62 @@ static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct s - return 0; - } - -+static int q6i2s_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -+{ -+ return q6apm_lpass_dai_startup(substream, dai); -+} -+ -+static void q6i2s_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -+{ -+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); -+ -+ q6apm_lpass_dai_shutdown(substream, dai); -+ q6apm_lpass_dai_disable_clocks(dai_data, dai->id); -+} -+ -+static int q6i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) -+{ -+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); -+ struct clk *sysclk = NULL; -+ bool *enabled = NULL; -+ int ret = 0; -+ -+ switch (clk_id) { -+ case LPAIF_MI2S_MCLK: -+ sysclk = dai_data->priv[dai->id].mclk; -+ enabled = &dai_data->priv[dai->id].mclk_enabled; -+ break; -+ case LPAIF_MI2S_BCLK: -+ sysclk = dai_data->priv[dai->id].bclk; -+ enabled = &dai_data->priv[dai->id].bclk_enabled; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (sysclk) { -+ ret = clk_set_rate(sysclk, freq); -+ if (ret) { -+ dev_err(dai->dev, "Error, Unable to set rate (%d) for sysclk %d\n", -+ freq, clk_id); -+ return ret; -+ } -+ -+ if (*enabled) -+ return 0; -+ -+ ret = clk_prepare_enable(sysclk); -+ if (ret) { -+ dev_err(dai->dev, "Error, Unable to prepare (%d) sysclk\n", clk_id); -+ return ret; -+ } -+ -+ *enabled = true; -+ } -+ -+ return ret; -+} -+ - static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - { - struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); -@@ -261,6 +358,53 @@ static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) - return 0; - } - -+static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai, -+ unsigned int tx_mask, -+ unsigned int rx_mask, -+ int slots, int slot_width) -+{ -+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); -+ struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; -+ unsigned int cap_mask, slot_mask; -+ -+ if (slot_width != 16 && slot_width != 32) { -+ dev_err(dai->dev, "%s: invalid slot_width %d\n", __func__, slot_width); -+ return -EINVAL; -+ } -+ -+ switch (slots) { -+ case 2: -+ case 4: -+ case 8: -+ case 16: -+ cap_mask = GENMASK(slots - 1, 0); -+ break; -+ default: -+ dev_err(dai->dev, "%s: invalid slots %d\n", __func__, slots); -+ return -EINVAL; -+ } -+ -+ switch (dai->id) { -+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: -+ slot_mask = (dai->id & 0x1) ? tx_mask : rx_mask; -+ if (slot_mask & ~cap_mask) { -+ dev_err(dai->dev, "%s: invalid slot mask 0x%x for %d slots\n", -+ __func__, slot_mask, slots); -+ return -EINVAL; -+ } -+ -+ cfg->nslots_per_frame = slots; -+ cfg->slot_width = slot_width; -+ cfg->slot_mask = slot_mask; -+ break; -+ default: -+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n", __func__, dai->id); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ - static const struct snd_soc_dai_ops q6dma_ops = { - .prepare = q6apm_lpass_dai_prepare, - .startup = q6apm_lpass_dai_startup, -@@ -272,11 +416,12 @@ static const struct snd_soc_dai_ops q6dma_ops = { - - static const struct snd_soc_dai_ops q6i2s_ops = { - .prepare = q6apm_lpass_dai_prepare, -- .startup = q6apm_lpass_dai_startup, -- .shutdown = q6apm_lpass_dai_shutdown, -+ .startup = q6i2s_dai_startup, -+ .shutdown = q6i2s_lpass_dai_shutdown, - .set_channel_map = q6dma_set_channel_map, - .hw_params = q6dma_hw_params, - .set_fmt = q6i2s_set_fmt, -+ .set_sysclk = q6i2s_set_sysclk, - .trigger = q6apm_lpass_dai_trigger, - }; - -@@ -289,6 +434,17 @@ static const struct snd_soc_dai_ops q6hdmi_ops = { - .trigger = q6apm_lpass_dai_trigger, - }; - -+static const struct snd_soc_dai_ops q6tdm_ops = { -+ .prepare = q6apm_lpass_dai_prepare, -+ .startup = q6apm_lpass_dai_startup, -+ .shutdown = q6i2s_lpass_dai_shutdown, -+ .set_tdm_slot = q6tdm_set_tdm_slot, -+ .hw_params = q6dma_hw_params, -+ .set_fmt = q6i2s_set_fmt, -+ .set_sysclk = q6i2s_set_sysclk, -+ .trigger = q6apm_lpass_dai_trigger, -+}; -+ - static const struct snd_soc_component_driver q6apm_lpass_dai_component = { - .name = "q6apm-be-dai-component", - .of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name, -@@ -297,6 +453,65 @@ static const struct snd_soc_component_driver q6apm_lpass_dai_component = { - .remove_order = SND_SOC_COMP_ORDER_FIRST, - }; - -+static int of_q6apm_parse_dai_data(struct device *dev, -+ struct q6apm_lpass_dai_data *data) -+{ -+ int ret; -+ -+ for_each_child_of_node_scoped(dev->of_node, node) { -+ struct q6apm_dai_priv_data *priv; -+ int id; -+ -+ ret = of_property_read_u32(node, "reg", &id); -+ if (ret || id < 0 || id >= APM_PORT_MAX) { -+ dev_err(dev, "valid dai id not found:%d\n", ret); -+ continue; -+ } -+ -+ switch (id) { -+ /* MI2S specific properties */ -+ case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: -+ case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: -+ case SENARY_MI2S_RX ... SENARY_MI2S_TX: -+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: -+ priv = &data->priv[id]; -+ priv->mclk = of_clk_get_by_name(node, "mclk"); -+ if (IS_ERR(priv->mclk)) { -+ int err = PTR_ERR(priv->mclk); -+ -+ priv->mclk = NULL; -+ if (err == -EPROBE_DEFER) { -+ q6apm_lpass_dai_put_clocks(data); -+ return dev_err_probe(dev, err, -+ "unable to get mi2s mclk\n"); -+ } -+ } -+ -+ priv->bclk = of_clk_get_by_name(node, "bclk"); -+ if (IS_ERR(priv->bclk)) { -+ int err = PTR_ERR(priv->bclk); -+ -+ priv->bclk = NULL; -+ if (err == -EPROBE_DEFER) { -+ q6apm_lpass_dai_put_clocks(data); -+ return dev_err_probe(dev, err, -+ "unable to get mi2s bclk\n"); -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+static void q6apm_lpass_dai_clocks_action(void *data) -+{ -+ q6apm_lpass_dai_put_clocks(data); -+} -+ - static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev) - { - struct q6dsp_audio_port_dai_driver_config cfg; -@@ -304,17 +519,26 @@ static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev) - struct snd_soc_dai_driver *dais; - struct device *dev = &pdev->dev; - int num_dais; -+ int ret; - - dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL); - if (!dai_data) - return -ENOMEM; - - dev_set_drvdata(dev, dai_data); -+ ret = of_q6apm_parse_dai_data(dev, dai_data); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action_or_reset(dev, q6apm_lpass_dai_clocks_action, dai_data); -+ if (ret) -+ return ret; - - memset(&cfg, 0, sizeof(cfg)); - cfg.q6i2s_ops = &q6i2s_ops; - cfg.q6dma_ops = &q6dma_ops; - cfg.q6hdmi_ops = &q6hdmi_ops; -+ cfg.q6tdm_ops = &q6tdm_ops; - dais = q6dsp_audio_ports_set_config(dev, &cfg, &num_dais); - - return devm_snd_soc_register_component(dev, &q6apm_lpass_dai_component, dais, num_dais); -diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c ---- a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c -+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c -@@ -12,7 +12,7 @@ - #include - #include "q6dsp-lpass-clocks.h" - --#define Q6DSP_MAX_CLK_ID 104 -+#define Q6DSP_MAX_CLK_ID 105 - #define Q6DSP_LPASS_CLK_ROOT_DEFAULT 0 - - -diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c ---- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c -+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c -@@ -553,11 +553,15 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { - Q6AFE_MI2S_RX_DAI("LPI RX2", LPI_MI2S_RX_2), - Q6AFE_MI2S_RX_DAI("LPI RX3", LPI_MI2S_RX_3), - Q6AFE_MI2S_RX_DAI("LPI RX4", LPI_MI2S_RX_4), -+ Q6AFE_MI2S_RX_DAI("LPI RX5", LPI_MI2S_RX_5), -+ Q6AFE_MI2S_RX_DAI("LPI RX6", LPI_MI2S_RX_6), - Q6AFE_MI2S_TX_DAI("LPI TX0", LPI_MI2S_TX_0), - Q6AFE_MI2S_TX_DAI("LPI TX1", LPI_MI2S_TX_1), - Q6AFE_MI2S_TX_DAI("LPI TX2", LPI_MI2S_TX_2), - Q6AFE_MI2S_TX_DAI("LPI TX3", LPI_MI2S_TX_3), - Q6AFE_MI2S_TX_DAI("LPI TX4", LPI_MI2S_TX_4), -+ Q6AFE_MI2S_TX_DAI("LPI TX5", LPI_MI2S_TX_5), -+ Q6AFE_MI2S_TX_DAI("LPI TX6", LPI_MI2S_TX_6), - Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0), - Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1), - Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2), -@@ -712,6 +716,7 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev, - case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: - case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: - case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: -+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6: - q6dsp_audio_fe_dais[i].ops = cfg->q6i2s_ops; - break; - case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: -diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c ---- a/sound/soc/qcom/qdsp6/q6prm-clocks.c -+++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c -@@ -42,6 +42,11 @@ static const struct q6dsp_clk_init q6prm_clks[] = { - Q6PRM_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT), - Q6PRM_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT), - Q6PRM_CLK(LPASS_CLK_ID_QUI_MI2S_OSR), -+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_1), -+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_2), -+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_3), -+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_4), -+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_5), - Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_MCLK), - Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK), - Q6PRM_CLK(LPASS_CLK_ID_VA_CORE_MCLK), -@@ -59,10 +64,40 @@ static const struct q6dsp_clk_init q6prm_clks[] = { - Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_MCLK), - Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK), - Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF0_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF0_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF1_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF1_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF2_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF2_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF3_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF3_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF4_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF4_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF5_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF5_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF6_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF6_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF7_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF7_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF8_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF8_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF9_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF9_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF10_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF10_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF11_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF11_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF12_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF12_EBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_VA_QAIF_IF0_IBIT), -+ Q6PRM_CLK(LAPSS_CLK_ID_VA_QAIF_IF0_EBIT), - Q6DSP_VOTE_CLK(LPASS_HW_MACRO_VOTE, Q6PRM_HW_CORE_ID_LPASS, - "LPASS_HW_MACRO"), - Q6DSP_VOTE_CLK(LPASS_HW_DCODEC_VOTE, Q6PRM_HW_CORE_ID_DCODEC, - "LPASS_HW_DCODEC"), -+ Q6DSP_VOTE_CLK(LPASS_HW_LPR_VOTE, Q6PRM_HW_LPR_VOTE, -+ "LPASS_HW_LPR_VOTE"), - }; - - static const struct q6dsp_clk_desc q6dsp_clk_q6prm __maybe_unused = { -diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c ---- a/sound/soc/qcom/qdsp6/q6prm.c -+++ b/sound/soc/qcom/qdsp6/q6prm.c -@@ -31,10 +31,16 @@ struct q6prm { - #define PARAM_ID_RSC_HW_CORE 0x08001032 - #define PARAM_ID_RSC_LPASS_CORE 0x0800102B - #define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C -+#define PARAM_ID_RSC_CPU_LPR 0x08001A6E -+ -+#define LPR_CPU_SS_SLEEP_DISABLE 0x1 - - struct prm_cmd_request_hw_core { - struct apm_module_param_data param_data; -- uint32_t hw_clk_id; -+ union { -+ u32 hw_clk_id; -+ u32 lpr_state; -+ }; - } __packed; - - struct prm_cmd_request_rsc { -@@ -62,6 +68,7 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool - struct prm_cmd_request_hw_core *req; - gpr_device_t *gdev = prm->gdev; - uint32_t opcode, rsp_opcode; -+ bool lpr_req = (hw_block_id == Q6PRM_HW_LPR_VOTE); - - if (enable) { - opcode = PRM_CMD_REQUEST_HW_RSC; -@@ -82,10 +89,13 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool - - param_data->module_instance_id = GPR_PRM_MODULE_IID; - param_data->error_code = 0; -- param_data->param_id = PARAM_ID_RSC_HW_CORE; -+ param_data->param_id = lpr_req ? PARAM_ID_RSC_CPU_LPR : PARAM_ID_RSC_HW_CORE; - param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE; - -- req->hw_clk_id = hw_block_id; -+ if (lpr_req) -+ req->lpr_state = LPR_CPU_SS_SLEEP_DISABLE; -+ else -+ req->hw_clk_id = hw_block_id; - - return q6prm_send_cmd_sync(prm, pkt, rsp_opcode); - } -diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h ---- a/sound/soc/qcom/qdsp6/q6prm.h -+++ b/sound/soc/qcom/qdsp6/q6prm.h -@@ -3,6 +3,9 @@ - #ifndef __Q6PRM_H__ - #define __Q6PRM_H__ - -+#define LPAIF_MI2S_MCLK 1 -+#define LPAIF_MI2S_BCLK 2 -+ - /* Clock ID for Primary I2S IBIT */ - #define Q6PRM_LPASS_CLK_ID_PRI_MI2S_IBIT 0x100 - /* Clock ID for Primary I2S EBIT */ -@@ -52,6 +55,17 @@ - /* Clock ID for QUINARY MI2S OSR CLK */ - #define Q6PRM_LPASS_CLK_ID_QUI_MI2S_OSR 0x116 - -+/* Clock ID for MCLK1 */ -+#define Q6PRM_LPASS_CLK_ID_MCLK_1 0x300 -+/* Clock ID for MCLK2 */ -+#define Q6PRM_LPASS_CLK_ID_MCLK_2 0x301 -+/* Clock ID for MCLK3 */ -+#define Q6PRM_LPASS_CLK_ID_MCLK_3 0x302 -+/* Clock ID for MCLK4 */ -+#define Q6PRM_LPASS_CLK_ID_MCLK_4 0x303 -+/* Clock ID for MCLK5 */ -+#define Q6PRM_LPASS_CLK_ID_MCLK_5 0x304 -+ - #define Q6PRM_LPASS_CLK_ID_WSA_CORE_MCLK 0x305 - #define Q6PRM_LPASS_CLK_ID_WSA_CORE_NPL_MCLK 0x306 - -@@ -83,10 +97,40 @@ - /* Clock ID for RX CORE MCLK2 2X MCLK */ - #define Q6PRM_LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 0x318 - -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF0_IBIT 0x500 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF0_EBIT 0x501 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF1_IBIT 0x502 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF1_EBIT 0x503 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF2_IBIT 0x504 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF2_EBIT 0x505 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF3_IBIT 0x506 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF3_EBIT 0x507 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF4_IBIT 0x508 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF4_EBIT 0x509 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF5_IBIT 0x50A -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF5_EBIT 0x50B -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF6_IBIT 0x50C -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF6_EBIT 0x50D -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF7_IBIT 0x50E -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF7_EBIT 0x50F -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF8_IBIT 0x510 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF8_EBIT 0x511 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF9_IBIT 0x512 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF9_EBIT 0x513 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF10_IBIT 0x514 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF10_EBIT 0x515 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF11_IBIT 0x516 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF11_EBIT 0x517 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF12_IBIT 0x518 -+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF12_EBIT 0x519 -+#define Q6PRM_LAPSS_CLK_ID_VA_QAIF_IF0_IBIT 0x550 -+#define Q6PRM_LAPSS_CLK_ID_VA_QAIF_IF0_EBIT 0x551 -+ - #define Q6PRM_LPASS_CLK_SRC_INTERNAL 1 - #define Q6PRM_LPASS_CLK_ROOT_DEFAULT 0 - #define Q6PRM_HW_CORE_ID_LPASS 1 - #define Q6PRM_HW_CORE_ID_DCODEC 2 -+#define Q6PRM_HW_LPR_VOTE 3 - - int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, - int clk_root, unsigned int freq); -diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c ---- a/sound/soc/qcom/qdsp6/q6routing.c -+++ b/sound/soc/qcom/qdsp6/q6routing.c -@@ -127,7 +127,14 @@ - { mix_name, "TX_CODEC_DMA_TX_2", "TX_CODEC_DMA_TX_2"}, \ - { mix_name, "TX_CODEC_DMA_TX_3", "TX_CODEC_DMA_TX_3"}, \ - { mix_name, "TX_CODEC_DMA_TX_4", "TX_CODEC_DMA_TX_4"}, \ -- { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"} -+ { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"}, \ -+ { mix_name, "LPI_MI2S_TX_0", "LPI_MI2S_TX_0" }, \ -+ { mix_name, "LPI_MI2S_TX_1", "LPI_MI2S_TX_1" }, \ -+ { mix_name, "LPI_MI2S_TX_2", "LPI_MI2S_TX_2" }, \ -+ { mix_name, "LPI_MI2S_TX_3", "LPI_MI2S_TX_3" }, \ -+ { mix_name, "LPI_MI2S_TX_4", "LPI_MI2S_TX_4" }, \ -+ { mix_name, "LPI_MI2S_TX_5", "LPI_MI2S_TX_5" }, \ -+ { mix_name, "LPI_MI2S_TX_6", "LPI_MI2S_TX_6" } - - #define Q6ROUTING_TX_MIXERS(id) \ - SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, \ -@@ -320,6 +327,27 @@ - id, 1, 0, msm_routing_get_audio_mixer, \ - msm_routing_put_audio_mixer), \ - SOC_SINGLE_EXT("TX_CODEC_DMA_TX_5", TX_CODEC_DMA_TX_5, \ -+ id, 1, 0, msm_routing_get_audio_mixer, \ -+ msm_routing_put_audio_mixer), \ -+ SOC_SINGLE_EXT("LPI_MI2S_TX_0", LPI_MI2S_TX_0, \ -+ id, 1, 0, msm_routing_get_audio_mixer, \ -+ msm_routing_put_audio_mixer), \ -+ SOC_SINGLE_EXT("LPI_MI2S_TX_1", LPI_MI2S_TX_1, \ -+ id, 1, 0, msm_routing_get_audio_mixer, \ -+ msm_routing_put_audio_mixer), \ -+ SOC_SINGLE_EXT("LPI_MI2S_TX_2", LPI_MI2S_TX_2, \ -+ id, 1, 0, msm_routing_get_audio_mixer, \ -+ msm_routing_put_audio_mixer), \ -+ SOC_SINGLE_EXT("LPI_MI2S_TX_3", LPI_MI2S_TX_3, \ -+ id, 1, 0, msm_routing_get_audio_mixer, \ -+ msm_routing_put_audio_mixer), \ -+ SOC_SINGLE_EXT("LPI_MI2S_TX_4", LPI_MI2S_TX_4, \ -+ id, 1, 0, msm_routing_get_audio_mixer, \ -+ msm_routing_put_audio_mixer), \ -+ SOC_SINGLE_EXT("LPI_MI2S_TX_5", LPI_MI2S_TX_5, \ -+ id, 1, 0, msm_routing_get_audio_mixer, \ -+ msm_routing_put_audio_mixer), \ -+ SOC_SINGLE_EXT("LPI_MI2S_TX_6", LPI_MI2S_TX_6, \ - id, 1, 0, msm_routing_get_audio_mixer, \ - msm_routing_put_audio_mixer), - -@@ -709,6 +737,26 @@ static const struct snd_kcontrol_new rxcodec_dma_rx_6_mixer_controls[] = { - static const struct snd_kcontrol_new rx_codec_dma_rx_7_mixer_controls[] = { - Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_7) }; - -+static const struct snd_kcontrol_new lpi_mi2s_rx_0_mixer_controls[] = { -+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_0) }; -+ -+static const struct snd_kcontrol_new lpi_mi2s_rx_1_mixer_controls[] = { -+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_1) }; -+ -+static const struct snd_kcontrol_new lpi_mi2s_rx_2_mixer_controls[] = { -+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_2) }; -+ -+static const struct snd_kcontrol_new lpi_mi2s_rx_3_mixer_controls[] = { -+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_3) }; -+ -+static const struct snd_kcontrol_new lpi_mi2s_rx_4_mixer_controls[] = { -+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_4) }; -+ -+static const struct snd_kcontrol_new lpi_mi2s_rx_5_mixer_controls[] = { -+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_5) }; -+ -+static const struct snd_kcontrol_new lpi_mi2s_rx_6_mixer_controls[] = { -+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_6) }; - - static const struct snd_kcontrol_new mmul1_mixer_controls[] = { - Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) }; -@@ -938,6 +986,27 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { - SND_SOC_DAPM_MIXER("USB_RX Audio Mixer", SND_SOC_NOPM, 0, 0, - usb_rx_mixer_controls, - ARRAY_SIZE(usb_rx_mixer_controls)), -+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0, -+ lpi_mi2s_rx_0_mixer_controls, -+ ARRAY_SIZE(lpi_mi2s_rx_0_mixer_controls)), -+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0, -+ lpi_mi2s_rx_1_mixer_controls, -+ ARRAY_SIZE(lpi_mi2s_rx_1_mixer_controls)), -+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0, -+ lpi_mi2s_rx_2_mixer_controls, -+ ARRAY_SIZE(lpi_mi2s_rx_2_mixer_controls)), -+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0, -+ lpi_mi2s_rx_3_mixer_controls, -+ ARRAY_SIZE(lpi_mi2s_rx_3_mixer_controls)), -+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0, -+ lpi_mi2s_rx_4_mixer_controls, -+ ARRAY_SIZE(lpi_mi2s_rx_4_mixer_controls)), -+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0, -+ lpi_mi2s_rx_5_mixer_controls, -+ ARRAY_SIZE(lpi_mi2s_rx_5_mixer_controls)), -+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0, -+ lpi_mi2s_rx_6_mixer_controls, -+ ARRAY_SIZE(lpi_mi2s_rx_6_mixer_controls)), - SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0, - mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)), - SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0, -@@ -1031,6 +1100,13 @@ static const struct snd_soc_dapm_route intercon[] = { - Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_6 Audio Mixer", "RX_CODEC_DMA_RX_6"), - Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_7 Audio Mixer", "RX_CODEC_DMA_RX_7"), - Q6ROUTING_RX_DAPM_ROUTE("USB_RX Audio Mixer", "USB_RX"), -+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_0 Audio Mixer", "LPI_MI2S_RX_0"), -+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_1 Audio Mixer", "LPI_MI2S_RX_1"), -+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_2 Audio Mixer", "LPI_MI2S_RX_2"), -+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_3 Audio Mixer", "LPI_MI2S_RX_3"), -+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_4 Audio Mixer", "LPI_MI2S_RX_4"), -+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_5 Audio Mixer", "LPI_MI2S_RX_5"), -+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_6 Audio Mixer", "LPI_MI2S_RX_6"), - Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"), - Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"), - Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"), -diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c ---- a/sound/soc/qcom/qdsp6/topology.c -+++ b/sound/soc/qcom/qdsp6/topology.c -@@ -753,6 +753,103 @@ static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, - return 0; - } - -+static int audioreach_widget_audio_if_module_load(struct audioreach_module *mod, -+ const struct snd_soc_tplg_vendor_array *mod_array) -+{ -+ const struct snd_soc_tplg_vendor_value_elem *mod_elem; -+ int tkn_count = 0; -+ u32 val; -+ -+ mod_elem = mod_array->value; -+ -+ while (tkn_count < le32_to_cpu(mod_array->num_elems)) { -+ val = le32_to_cpu(mod_elem->value); -+ switch (le32_to_cpu(mod_elem->token)) { -+ case AR_TKN_U32_MODULE_HW_IF_IDX: -+ mod->hw_interface_idx = val; -+ break; -+ case AR_TKN_U32_MODULE_FMT_DATA: -+ mod->data_format = val; -+ break; -+ case AR_TKN_U16_MODULE_SYNC_SRC: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->sync_src = (u16)val; -+ break; -+ case AR_TKN_U16_MODULE_CTRL_DATA_OUT_ENABLE: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->ctrl_data_out_enable = (u16)val; -+ break; -+ case AR_TKN_U32_MODULE_SLOT_MASK: -+ mod->slot_mask = val; -+ break; -+ case AR_TKN_U16_MODULE_NSLOTS_PER_FRAME: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->nslots_per_frame = (u16)val; -+ break; -+ case AR_TKN_U16_MODULE_SLOT_WIDTH: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->slot_width = (u16)val; -+ break; -+ case AR_TKN_U16_MODULE_INTF_MODE: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->intf_mode = (u16)val; -+ break; -+ case AR_TKN_U16_MODULE_SYNC_MODE: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->sync_mode = (u16)val; -+ break; -+ case AR_TKN_U16_MODULE_CTRL_INVERT_SYNC_PULSE: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->ctrl_invert_sync_pulse = (u16)val; -+ break; -+ case AR_TKN_U16_MODULE_CTRL_SYNC_DATA_DELAY: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->ctrl_sync_data_delay = (u16)val; -+ break; -+ case AR_TKN_U16_MODULE_QAIF_TYPE: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->qaif_type = (u16)val; -+ break; -+ case AR_TKN_U32_MODULE_ACTIVE_LANE_MASK: -+ mod->active_lane_mask = val; -+ break; -+ case AR_TKN_U32_MODULE_FRAME_SYNC_RATE: -+ mod->frame_sync_rate = val; -+ break; -+ case AR_TKN_U16_MODULE_BIT_CLK_TYPE: -+ if (val > U16_MAX) -+ return -EINVAL; -+ mod->bit_clk_type = (u16)val; -+ break; -+ case AR_TKN_U8_MODULE_INV_INT_BIT_CLK: -+ if (val > U8_MAX) -+ return -EINVAL; -+ mod->inv_int_bit_clk = (u8)val; -+ break; -+ case AR_TKN_U8_MODULE_INV_EXT_BIT_CLK: -+ if (val > U8_MAX) -+ return -EINVAL; -+ mod->inv_ext_bit_clk = (u8)val; -+ break; -+ default: -+ break; -+ } -+ tkn_count++; -+ mod_elem++; -+ } -+ -+ return 0; -+} -+ - static int audioreach_widget_dp_module_load(struct audioreach_module *mod, - const struct snd_soc_tplg_vendor_array *mod_array) - { -@@ -806,6 +903,12 @@ static int audioreach_widget_load_buffer(struct snd_soc_component *component, - case MODULE_ID_I2S_SOURCE: - audioreach_widget_i2s_module_load(mod, mod_array); - break; -+ case MODULE_ID_AUDIO_IF_SINK: -+ case MODULE_ID_AUDIO_IF_SOURCE: -+ ret = audioreach_widget_audio_if_module_load(mod, mod_array); -+ if (ret) -+ return ret; -+ break; - case MODULE_ID_DISPLAY_PORT_SINK: - audioreach_widget_dp_module_load(mod, mod_array); - break; -@@ -1313,7 +1416,6 @@ int audioreach_tplg_init(struct snd_soc_component *component) - { - struct snd_soc_card *card = component->card; - struct device *dev = component->dev; -- const struct firmware *fw; - int ret; - - /* Inline with Qualcomm UCM configs and linux-firmware path */ -@@ -1323,6 +1425,7 @@ int audioreach_tplg_init(struct snd_soc_component *component) - if (!tplg_fw_name) - return -ENOMEM; - -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, tplg_fw_name, dev); - if (ret < 0) { - dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret); -@@ -1335,8 +1438,6 @@ int audioreach_tplg_init(struct snd_soc_component *component) - dev_err(dev, "tplg component load failed: %d\n", ret); - } - -- release_firmware(fw); -- - return ret; - } - EXPORT_SYMBOL_GPL(audioreach_tplg_init); -diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c ---- a/sound/soc/qcom/sc8280xp.c -+++ b/sound/soc/qcom/sc8280xp.c -@@ -12,17 +12,157 @@ - #include - #include - #include "qdsp6/q6afe.h" -+#include "qdsp6/q6apm.h" -+#include "qdsp6/q6prm.h" -+#include "qdsp6/q6dsp-common.h" - #include "common.h" - #include "sdw.h" - -+#define I2S_MCLKFS 256 -+ -+#define I2S_MCLK_RATE(rate) \ -+ ((rate) * (I2S_MCLKFS)) -+#define I2S_BIT_RATE(rate, channels, format) \ -+ ((rate) * (channels) * (format)) -+ -+static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = { -+ SND_SOC_DAPM_HP("Headphone Jack", NULL), -+ SND_SOC_DAPM_MIC("Mic Jack", NULL), -+ SND_SOC_DAPM_SPK("DP0 Jack", NULL), -+ SND_SOC_DAPM_SPK("DP1 Jack", NULL), -+ SND_SOC_DAPM_SPK("DP2 Jack", NULL), -+ SND_SOC_DAPM_SPK("DP3 Jack", NULL), -+ SND_SOC_DAPM_SPK("DP4 Jack", NULL), -+ SND_SOC_DAPM_SPK("DP5 Jack", NULL), -+ SND_SOC_DAPM_SPK("DP6 Jack", NULL), -+ SND_SOC_DAPM_SPK("DP7 Jack", NULL), -+}; -+ -+static const struct snd_kcontrol_new max98090_controls[] = { -+ SOC_DAPM_PIN_SWITCH("Headset Mic12"), -+ SOC_DAPM_PIN_SWITCH("Headphone"), -+ SOC_DAPM_PIN_SWITCH("Headset Mic56"), -+ SOC_DAPM_PIN_SWITCH("Speaker"), -+ SOC_DAPM_PIN_SWITCH("Receiver"), -+ SOC_DAPM_PIN_SWITCH("Int Mic"), -+}; -+ -+static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { -+ SND_SOC_DAPM_HP("Headphone Jack", NULL), -+ SND_SOC_DAPM_MIC("Mic Jack", NULL), -+ SND_SOC_DAPM_HP("Headphone", NULL), -+ SND_SOC_DAPM_MIC("Headset Mic12", NULL), -+ SND_SOC_DAPM_MIC("Headset Mic56", NULL), -+ SND_SOC_DAPM_MIC("Int Mic", NULL), -+ SND_SOC_DAPM_SPK("Receiver", NULL), -+ SND_SOC_DAPM_SPK("Speaker", NULL), -+}; -+ -+struct qcom_snd_soc_common { -+ const char *driver_name; -+ const struct snd_soc_dapm_widget *dapm_widgets; -+ int num_dapm_widgets; -+ const struct snd_soc_dapm_route *dapm_routes; -+ int num_dapm_routes; -+ const struct snd_kcontrol_new *controls; -+ int num_controls; -+ unsigned int codec_dai_fmt; -+ bool codec_sysclk_set; -+ bool mi2s_mclk_enable; -+ bool mi2s_bclk_enable; -+ bool wcd_jack; -+ int (*snd_prepare)(struct snd_pcm_substream *substream); -+}; -+ - struct sc8280xp_snd_data { - bool stream_prepared[AFE_PORT_MAX]; - struct snd_soc_card *card; - struct snd_soc_jack jack; - struct snd_soc_jack dp_jack[8]; -+ const struct qcom_snd_soc_common *priv; - bool jack_setup; - }; - -+static inline int sc8280xp_get_mclk_freq(struct snd_pcm_hw_params *params) -+{ -+ int rate = params_rate(params); -+ -+ switch (rate) { -+ case 11025: -+ case 44100: -+ case 88200: -+ return I2S_MCLK_RATE(44100); -+ default: -+ break; -+ } -+ -+ return I2S_MCLK_RATE(rate); -+} -+ -+static inline int sc8280xp_get_bclk_freq(struct snd_pcm_hw_params *params) -+{ -+ return I2S_BIT_RATE(params_rate(params), -+ params_channels(params), -+ snd_pcm_format_width(params_format(params))); -+} -+ -+static int sc8280xp_tdm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); -+ struct snd_soc_dai *codec_dai; -+ struct qcom_snd_tdm_slot_cfg cpu_cfg; -+ struct qcom_snd_tdm_slot_cfg codec_cfg; -+ unsigned int bclk_freq; -+ int ret; -+ int i; -+ -+ ret = qcom_snd_get_dai_tdm_slots(rtd, &cpu_cfg, &codec_cfg); -+ if (ret) -+ return ret == -EINVAL ? 0 : ret; -+ -+ if (!cpu_cfg.slots) -+ return 0; -+ -+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); -+ if (ret) -+ return ret; -+ -+ ret = qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg); -+ if (ret) -+ return ret; -+ -+ bclk_freq = snd_soc_tdm_params_to_bclk(params, cpu_cfg.slot_width, cpu_cfg.slots, 1); -+ if (!bclk_freq) -+ return -EINVAL; -+ -+ if (data->priv->mi2s_bclk_enable) { -+ ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_MI2S_BCLK, bclk_freq, -+ SND_SOC_CLOCK_IN); -+ if (ret) { -+ dev_err(rtd->dev, "%s: failed to set cpu sysclk: %d\n", -+ __func__, ret); -+ return ret; -+ } -+ } -+ -+ if (data->priv->codec_sysclk_set) { -+ for_each_rtd_codec_dais(rtd, i, codec_dai) { -+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, bclk_freq, -+ SND_SOC_CLOCK_IN); -+ if (ret) { -+ dev_err(rtd->dev, "%s: failed to set codec sysclk on %s: %d\n", -+ __func__, codec_dai->name, ret); -+ return ret; -+ } -+ } -+ } -+ -+ return 0; -+} -+ - static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) - { - struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); -@@ -32,10 +172,6 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) - int dp_pcm_id = 0; - - switch (cpu_dai->id) { -- case PRIMARY_MI2S_RX...QUATERNARY_MI2S_TX: -- case QUINARY_MI2S_RX...QUINARY_MI2S_TX: -- snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); -- break; - case WSA_CODEC_DMA_RX_0: - case WSA_CODEC_DMA_RX_1: - /* -@@ -64,7 +200,10 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) - if (dp_jack) - return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); - -- return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); -+ if (data->priv->wcd_jack) -+ return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); -+ -+ return 0; - } - - static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, -@@ -96,12 +235,118 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - return 0; - } - -+static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); -+ struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); -+ int mclk_freq = sc8280xp_get_mclk_freq(params); -+ int bclk_freq = sc8280xp_get_bclk_freq(params); -+ int ret; -+ -+ switch (cpu_dai->id) { -+ case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: -+ case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: -+ case SENARY_MI2S_RX ... SENARY_MI2S_TX: -+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: -+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); -+ if (ret && ret != -ENOTSUPP) -+ return ret; -+ -+ if (data->priv->codec_dai_fmt) { -+ ret = snd_soc_dai_set_fmt(codec_dai, -+ data->priv->codec_dai_fmt); -+ if (ret && ret != -ENOTSUPP) -+ return ret; -+ } -+ -+ if (data->priv->mi2s_mclk_enable) { -+ ret = snd_soc_dai_set_sysclk(cpu_dai, -+ LPAIF_MI2S_MCLK, mclk_freq, -+ SND_SOC_CLOCK_OUT); -+ if (ret) -+ return ret; -+ } -+ -+ if (data->priv->mi2s_bclk_enable) { -+ ret = snd_soc_dai_set_sysclk(cpu_dai, -+ LPAIF_MI2S_BCLK, bclk_freq, -+ SND_SOC_CLOCK_OUT); -+ if (ret) -+ return ret; -+ } -+ -+ if (data->priv->codec_sysclk_set) { -+ ret = snd_soc_dai_set_sysclk(codec_dai, -+ 0, mclk_freq, -+ SND_SOC_CLOCK_IN); -+ if (ret && ret != -ENOTSUPP) -+ return ret; -+ } -+ break; -+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: -+ return sc8280xp_tdm_hw_params(substream, params); -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+/* -+ * WSA and WSA2 are handled as a single interface with the -+ * following channels mask: -+ * __________________________________________________ -+ * | Bits | 3 | 2 | 1 | 0 | -+ * --------------------------------------------------- -+ * | Line | WSA2 Ch2 | WSA2 Ch1 | WSA Ch2 | WSA Ch1 | -+ * --------------------------------------------------- -+ * -+ * The Ayaneo Pocket S2 speakers are connected only to -+ * the WSA2 interface and the WSA interface is not enabled. -+ * -+ * Set the channel mapping on the WSA2 channels only. -+ */ -+static const unsigned int ayaneo_ps2_channels_mapping[] = { -+ 0, /* WSA Ch1 */ -+ 0, /* WSA Ch2 */ -+ PCM_CHANNEL_FL, /* WSA2 Ch1 */ -+ PCM_CHANNEL_FR /* WSA2 Ch2 */ -+}; -+ -+static int ayaneo_ps2_snd_prepare(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); -+ unsigned int channels = substream->runtime->channels; -+ -+ if (cpu_dai->id != WSA_CODEC_DMA_RX_0) -+ return 0; -+ -+ if (channels != 2) -+ return -EINVAL; -+ -+ return snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, -+ ARRAY_SIZE(ayaneo_ps2_channels_mapping), -+ ayaneo_ps2_channels_mapping); -+} -+ - static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) - { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); - -+ if (data->priv->snd_prepare) { -+ int ret; -+ -+ ret = data->priv->snd_prepare(substream); -+ if (ret) -+ return ret; -+ } -+ - return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]); - } - -@@ -117,6 +362,7 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) - static const struct snd_soc_ops sc8280xp_be_ops = { - .startup = qcom_snd_sdw_startup, - .shutdown = qcom_snd_sdw_shutdown, -+ .hw_params = sc8280xp_snd_hw_params, - .hw_free = sc8280xp_snd_hw_free, - .prepare = sc8280xp_snd_prepare, - }; -@@ -145,38 +391,182 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) - card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); - if (!card) - return -ENOMEM; -- card->owner = THIS_MODULE; -+ - /* Allocate the private data */ - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - -+ data->priv = of_device_get_match_data(dev); -+ if (!data->priv) -+ return -ENODEV; -+ -+ card->owner = THIS_MODULE; - card->dev = dev; - dev_set_drvdata(dev, card); - snd_soc_card_set_drvdata(card, data); -+ card->dapm_widgets = data->priv->dapm_widgets; -+ card->num_dapm_widgets = data->priv->num_dapm_widgets; -+ card->dapm_routes = data->priv->dapm_routes; -+ card->num_dapm_routes = data->priv->num_dapm_routes; -+ card->controls = data->priv->controls; -+ card->num_controls = data->priv->num_controls; -+ - ret = qcom_snd_parse_of(card); - if (ret) - return ret; - -- card->driver_name = of_device_get_match_data(dev); -+ card->driver_name = data->priv->driver_name; - sc8280xp_add_be_ops(card); - return devm_snd_soc_register_card(dev, card); - } - -+static struct qcom_snd_soc_common ayaneo_ps2_priv_data = { -+ .driver_name = "ayaneo-ps2", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .snd_prepare = ayaneo_ps2_snd_prepare, -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common eliza_priv_data = { -+ .driver_name = "eliza", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common hawi_priv_data = { -+ .driver_name = "hawi", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .codec_sysclk_set = true, -+ .mi2s_bclk_enable = true, -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common kaanapali_priv_data = { -+ .driver_name = "kaanapali", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common qcs9100_priv_data = { -+ .driver_name = "sa8775p", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+}; -+ -+static const struct qcom_snd_soc_common qcs615_priv_data = { -+ .driver_name = "qcs615", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .codec_sysclk_set = true, -+}; -+ -+static const struct qcom_snd_soc_common qcm6490_priv_data = { -+ .driver_name = "qcm6490", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common qcs6490_priv_data = { -+ .driver_name = "qcs6490", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common qcs8275_priv_data = { -+ .driver_name = "qcs8300", -+ .dapm_widgets = max98090_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(max98090_dapm_widgets), -+ .controls = max98090_controls, -+ .num_controls = ARRAY_SIZE(max98090_controls), -+ .codec_sysclk_set = true, -+ .codec_dai_fmt = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC, -+}; -+ -+static const struct qcom_snd_soc_common sc8280xp_priv_data = { -+ .driver_name = "sc8280xp", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common sm8450_priv_data = { -+ .driver_name = "sm8450", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+ /* I2S Connected to HDMI */ -+ .mi2s_mclk_enable = true, -+ .mi2s_bclk_enable = true, -+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC | -+ SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_I2S, -+}; -+ -+static const struct qcom_snd_soc_common sm8475_priv_data = { -+ .driver_name = "sm8475", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+}; -+ -+static const struct qcom_snd_soc_common sm8550_priv_data = { -+ .driver_name = "sm8550", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+ /* I2S Connected to HDMI */ -+ .mi2s_mclk_enable = true, -+ .mi2s_bclk_enable = true, -+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC | -+ SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_I2S, -+}; -+ -+static const struct qcom_snd_soc_common sm8650_priv_data = { -+ .driver_name = "sm8650", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+ /* I2S Connected to HDMI */ -+ .mi2s_mclk_enable = true, -+ .mi2s_bclk_enable = true, -+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC | -+ SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_I2S, -+}; -+ -+static const struct qcom_snd_soc_common sm8750_priv_data = { -+ .driver_name = "sm8750", -+ .dapm_widgets = sc8280xp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), -+ .wcd_jack = true, -+}; -+ - static const struct of_device_id snd_sc8280xp_dt_match[] = { -- {.compatible = "qcom,eliza-sndcard", "eliza"}, -- {.compatible = "qcom,kaanapali-sndcard", "kaanapali"}, -- {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"}, -- {.compatible = "qcom,qcs615-sndcard", "qcs615"}, -- {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"}, -- {.compatible = "qcom,qcs8275-sndcard", "qcs8300"}, -- {.compatible = "qcom,qcs9075-sndcard", "sa8775p"}, -- {.compatible = "qcom,qcs9100-sndcard", "sa8775p"}, -- {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, -- {.compatible = "qcom,sm8450-sndcard", "sm8450"}, -- {.compatible = "qcom,sm8550-sndcard", "sm8550"}, -- {.compatible = "qcom,sm8650-sndcard", "sm8650"}, -- {.compatible = "qcom,sm8750-sndcard", "sm8750"}, -+ { .compatible = "ayaneo,pocket-s2-sndcard", .data = &ayaneo_ps2_priv_data }, -+ { .compatible = "qcom,eliza-sndcard", .data = &eliza_priv_data }, -+ { .compatible = "qcom,hawi-sndcard", .data = &hawi_priv_data }, -+ { .compatible = "qcom,kaanapali-sndcard", .data = &kaanapali_priv_data }, -+ { .compatible = "qcom,maili-sndcard", .data = &hawi_priv_data }, -+ { .compatible = "qcom,qcm6490-idp-sndcard", .data = &qcm6490_priv_data }, -+ { .compatible = "qcom,qcs615-sndcard", .data = &qcs615_priv_data }, -+ { .compatible = "qcom,qcs6490-rb3gen2-sndcard", .data = &qcs6490_priv_data }, -+ { .compatible = "qcom,qcs8275-sndcard", .data = &qcs8275_priv_data }, -+ { .compatible = "qcom,qcs9075-sndcard", .data = &qcs9100_priv_data }, -+ { .compatible = "qcom,qcs9100-sndcard", .data = &qcs9100_priv_data }, -+ { .compatible = "qcom,sc8280xp-sndcard", .data = &sc8280xp_priv_data }, -+ { .compatible = "qcom,sm8450-sndcard", .data = &sm8450_priv_data }, -+ { .compatible = "qcom,sm8475-sndcard", .data = &sm8475_priv_data }, -+ { .compatible = "qcom,sm8550-sndcard", .data = &sm8550_priv_data }, -+ { .compatible = "qcom,sm8650-sndcard", .data = &sm8650_priv_data }, -+ { .compatible = "qcom,sm8750-sndcard", .data = &sm8750_priv_data }, - {} - }; - -diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c ---- a/sound/soc/qcom/sdm845.c -+++ b/sound/soc/qcom/sdm845.c -@@ -36,7 +36,6 @@ struct sdm845_snd_data { - bool jack_setup; - bool slim_port_setup; - bool stream_prepared[AFE_PORT_MAX]; -- struct snd_soc_card *card; - uint32_t pri_mi2s_clk_count; - uint32_t sec_mi2s_clk_count; - uint32_t quat_tdm_clk_count; -@@ -564,7 +563,6 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev) - if (ret) - return ret; - -- data->card = card; - snd_soc_card_set_drvdata(card, data); - - sdm845_add_ops(card); -diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c ---- a/sound/soc/qcom/sm8250.c -+++ b/sound/soc/qcom/sm8250.c -@@ -112,6 +112,22 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) - snd_soc_dai_set_fmt(cpu_dai, fmt); - snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); - break; -+ case LPI_MI2S_RX_0: -+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; -+ snd_soc_dai_set_sysclk(cpu_dai, -+ Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT, -+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); -+ snd_soc_dai_set_fmt(cpu_dai, fmt); -+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); -+ break; -+ case LPI_MI2S_TX_3: -+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; -+ snd_soc_dai_set_sysclk(cpu_dai, -+ Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT, -+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE); -+ snd_soc_dai_set_fmt(cpu_dai, fmt); -+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); -+ break; - default: - break; - } -@@ -194,6 +210,7 @@ static const struct of_device_id snd_sm8250_dt_match[] = { - { .compatible = "qcom,qrb2210-sndcard", .data = "qcm2290" }, - { .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" }, - { .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" }, -+ { .compatible = "qcom,sdm660-sndcard", .data = "sdm660" }, - { .compatible = "qcom,sm8250-sndcard", .data = "sm8250" }, - {} - }; -diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c ---- a/sound/soc/qcom/storm.c -+++ b/sound/soc/qcom/storm.c -@@ -64,21 +64,21 @@ static struct snd_soc_dai_link storm_dai_link = { - SND_SOC_DAILINK_REG(hifi), - }; - --static int storm_parse_of(struct snd_soc_card *card) -+static int storm_parse_of(struct device *dev) - { -- struct snd_soc_dai_link *dai_link = card->dai_link; -- struct device_node *np = card->dev->of_node; -+ struct snd_soc_dai_link *dai_link = &storm_dai_link; -+ struct device_node *np = dev->of_node; - - dai_link->cpus->of_node = of_parse_phandle(np, "cpu", 0); - if (!dai_link->cpus->of_node) { -- dev_err(card->dev, "error getting cpu phandle\n"); -+ dev_err(dev, "error getting cpu phandle\n"); - return -EINVAL; - } - dai_link->platforms->of_node = dai_link->cpus->of_node; - - dai_link->codecs->of_node = of_parse_phandle(np, "codec", 0); - if (!dai_link->codecs->of_node) { -- dev_err(card->dev, "error getting codec phandle\n"); -+ dev_err(dev, "error getting codec phandle\n"); - return -EINVAL; - } - -@@ -106,7 +106,7 @@ static int storm_platform_probe(struct platform_device *pdev) - card->dai_link = &storm_dai_link; - card->num_links = 1; - -- ret = storm_parse_of(card); -+ ret = storm_parse_of(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "error resolving dai links: %d\n", ret); - return ret; -diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c ---- a/sound/soc/renesas/fsi.c -+++ b/sound/soc/renesas/fsi.c -@@ -1979,8 +1979,8 @@ static const struct of_device_id fsi_of_match[] = { - MODULE_DEVICE_TABLE(of, fsi_of_match); - - static const struct platform_device_id fsi_id_table[] = { -- { "sh_fsi", (kernel_ulong_t)&fsi1_core }, -- {}, -+ /* an array with no valid entry prevents matching on driver name */ -+ { } - }; - MODULE_DEVICE_TABLE(platform, fsi_id_table); - -@@ -1992,7 +1992,7 @@ static int fsi_probe(struct platform_device *pdev) - const struct fsi_core *core; - struct fsi_priv *fsi; - struct resource *res; -- unsigned int irq; -+ int irq; - int ret; - - memset(&info, 0, sizeof(info)); -@@ -2007,12 +2007,15 @@ static int fsi_probe(struct platform_device *pdev) - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- irq = platform_get_irq(pdev, 0); -- if (!res || (int)irq <= 0) { -+ if (!res) { - dev_err(&pdev->dev, "Not enough FSI platform resources.\n"); - return -ENODEV; - } - -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ - master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); - if (!master) - return -ENOMEM; -diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c ---- a/sound/soc/renesas/rcar/adg.c -+++ b/sound/soc/renesas/rcar/adg.c -@@ -565,7 +565,7 @@ static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv, - struct clk *clk; - - clk = clk_register_fixed_rate(dev, name, parent, 0, 0); -- if (IS_ERR_OR_NULL(clk)) { -+ if (IS_ERR(clk)) { - dev_err(dev, "create null clk error\n"); - return ERR_CAST(clk); - } -@@ -618,7 +618,7 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv) - * No "adg" is not error - */ - clk = devm_clk_get(dev, "adg"); -- if (IS_ERR_OR_NULL(clk)) -+ if (IS_ERR(clk)) - clk = rsnd_adg_null_clk_get(priv); - adg->adg = clk; - -@@ -626,9 +626,9 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv) - for (i = 0; i < clkin_size; i++) { - clk = devm_clk_get(dev, clkin_name[i]); - -- if (IS_ERR_OR_NULL(clk)) -+ if (IS_ERR(clk)) - clk = rsnd_adg_null_clk_get(priv); -- if (IS_ERR_OR_NULL(clk)) -+ if (IS_ERR(clk)) - goto err; - - adg->clkin[i] = clk; -diff --git a/sound/soc/renesas/siu_dai.c b/sound/soc/renesas/siu_dai.c ---- a/sound/soc/renesas/siu_dai.c -+++ b/sound/soc/renesas/siu_dai.c -@@ -715,7 +715,6 @@ static struct snd_soc_dai_driver siu_i2s_dai = { - - static int siu_probe(struct platform_device *pdev) - { -- const struct firmware *fw_entry; - struct resource *res, *region; - struct siu_info *info; - int ret; -@@ -726,6 +725,7 @@ static int siu_probe(struct platform_device *pdev) - siu_i2s_data = info; - info->dev = &pdev->dev; - -+ const struct firmware *fw_entry __free(firmware) = NULL; - ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev); - if (ret) - return ret; -@@ -736,8 +736,6 @@ static int siu_probe(struct platform_device *pdev) - */ - memcpy(&info->fw, fw_entry->data, fw_entry->size); - -- release_firmware(fw_entry); -- - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; -diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c ---- a/sound/soc/rockchip/rk3288_hdmi_analog.c -+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c -@@ -185,10 +185,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev) - gpiod_set_consumer_name(machine->gpio_hp_en, "hp_en"); - - ret = snd_soc_of_parse_card_name(card, "rockchip,model"); -- if (ret) { -- dev_err(card->dev, "SoC parse card name failed %d\n", ret); -+ if (ret) - return ret; -- } - - rk_dailink.codecs[0].of_node = of_parse_phandle(np, - "rockchip,audio-codec", -@@ -207,10 +205,9 @@ static int snd_rk_mc_probe(struct platform_device *pdev) - } - - ret = snd_soc_get_dai_name(&args, &rk_dailink.codecs[0].dai_name); -- if (ret) { -- dev_err(&pdev->dev, "Unable to get codec_dai_name\n"); -- return ret; -- } -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, -+ "Unable to get codec_dai_name\n"); - - rk_dailink.cpus->of_node = of_parse_phandle(np, "rockchip,i2s-controller", - 0); -@@ -223,11 +220,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev) - rk_dailink.platforms->of_node = rk_dailink.cpus->of_node; - - ret = snd_soc_of_parse_audio_routing(card, "rockchip,routing"); -- if (ret) { -- dev_err(&pdev->dev, -- "Unable to parse 'rockchip,routing' property\n"); -+ if (ret) - return ret; -- } - - snd_soc_card_set_drvdata(card, machine); - -diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c ---- a/sound/soc/rockchip/rockchip_i2s.c -+++ b/sound/soc/rockchip/rockchip_i2s.c -@@ -767,16 +767,14 @@ static int rockchip_i2s_probe(struct platform_device *pdev) - - /* try to prepare related clocks */ - i2s->hclk = devm_clk_get_enabled(&pdev->dev, "i2s_hclk"); -- if (IS_ERR(i2s->hclk)) { -- dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n"); -- return PTR_ERR(i2s->hclk); -- } -+ if (IS_ERR(i2s->hclk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->hclk), -+ "Can't retrieve i2s bus clock\n"); - - i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); -- if (IS_ERR(i2s->mclk)) { -- dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); -- return PTR_ERR(i2s->mclk); -- } -+ if (IS_ERR(i2s->mclk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->mclk), -+ "Can't retrieve i2s master clock\n"); - - regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(regs)) -@@ -792,7 +790,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev) - - i2s->bclk_ratio = 64; - i2s->pinctrl = devm_pinctrl_get(&pdev->dev); -- if (!IS_ERR(i2s->pinctrl)) { -+ if (IS_ERR(i2s->pinctrl)) { -+ if (PTR_ERR(i2s->pinctrl) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n"); -+ } else { - i2s->bclk_on = pinctrl_lookup_state(i2s->pinctrl, "bclk_on"); - if (!IS_ERR_OR_NULL(i2s->bclk_on)) { - i2s->bclk_off = pinctrl_lookup_state(i2s->pinctrl, "bclk_off"); -@@ -801,8 +803,6 @@ static int rockchip_i2s_probe(struct platform_device *pdev) - return -EINVAL; - } - } -- } else { -- dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n"); - } - - i2s_pinctrl_select_bclk_off(i2s); -@@ -831,16 +831,12 @@ static int rockchip_i2s_probe(struct platform_device *pdev) - &rockchip_i2s_component, - dai, 1); - -- if (ret) { -- dev_err(&pdev->dev, "Could not register DAI\n"); -+ if (ret) - return ret; -- } - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); -- if (ret) { -- dev_err(&pdev->dev, "Could not register PCM\n"); -+ if (ret) - return ret; -- } - - return 0; - } -diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c ---- a/sound/soc/rockchip/rockchip_i2s_tdm.c -+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c -@@ -1263,16 +1263,14 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) - i2s_tdm->tx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev, - "tx-m"); - if (IS_ERR(i2s_tdm->tx_reset)) { -- ret = PTR_ERR(i2s_tdm->tx_reset); -- return dev_err_probe(i2s_tdm->dev, ret, -+ return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->tx_reset), - "Error in tx-m reset control\n"); - } - - i2s_tdm->rx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev, - "rx-m"); - if (IS_ERR(i2s_tdm->rx_reset)) { -- ret = PTR_ERR(i2s_tdm->rx_reset); -- return dev_err_probe(i2s_tdm->dev, ret, -+ return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->rx_reset), - "Error in rx-m reset control\n"); - } - -@@ -1363,17 +1361,12 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) - ret = devm_snd_soc_register_component(&pdev->dev, - &rockchip_i2s_tdm_component, - i2s_tdm->dai, 1); -- -- if (ret) { -- dev_err(&pdev->dev, "Could not register DAI\n"); -+ if (ret) - goto err_suspend; -- } - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); -- if (ret) { -- dev_err(&pdev->dev, "Could not register PCM\n"); -+ if (ret) - goto err_suspend; -- } - - return 0; - -diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c ---- a/sound/soc/rockchip/rockchip_max98090.c -+++ b/sound/soc/rockchip/rockchip_max98090.c -@@ -428,11 +428,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev) - - /* Parse card name. */ - ret = snd_soc_of_parse_card_name(card, "rockchip,model"); -- if (ret) { -- dev_err(&pdev->dev, -- "Soc parse card name failed %d\n", ret); -+ if (ret) - return ret; -- } - - /* register the soc card */ - ret = devm_snd_soc_register_card(&pdev->dev, card); -diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c ---- a/sound/soc/rockchip/rockchip_pdm.c -+++ b/sound/soc/rockchip/rockchip_pdm.c -@@ -630,10 +630,8 @@ static int rockchip_pdm_probe(struct platform_device *pdev) - &rockchip_pdm_component, - &rockchip_pdm_dai, 1); - -- if (ret) { -- dev_err(&pdev->dev, "could not register dai: %d\n", ret); -+ if (ret) - goto err_suspend; -- } - - rockchip_pdm_rxctrl(pdm, 0); - -@@ -642,10 +640,8 @@ static int rockchip_pdm_probe(struct platform_device *pdev) - goto err_suspend; - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); -- if (ret) { -- dev_err(&pdev->dev, "could not register pcm: %d\n", ret); -+ if (ret) - goto err_suspend; -- } - - return 0; - -diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c ---- a/sound/soc/rockchip/rockchip_rt5645.c -+++ b/sound/soc/rockchip/rockchip_rt5645.c -@@ -191,11 +191,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev) - rk_dailink.platforms->of_node = rk_dailink.cpus->of_node; - - ret = snd_soc_of_parse_card_name(card, "rockchip,model"); -- if (ret) { -- dev_err(&pdev->dev, -- "Soc parse card name failed %d\n", ret); -+ if (ret) - goto put_cpu_of_node; -- } - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) { -diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c ---- a/sound/soc/rockchip/rockchip_sai.c -+++ b/sound/soc/rockchip/rockchip_sai.c -@@ -1428,12 +1428,13 @@ static int rockchip_sai_probe(struct platform_device *pdev) - "Failed to initialize regmap\n"); - - irq = platform_get_irq_optional(pdev, 0); -+ if (irq == -EPROBE_DEFER) -+ return irq; - if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, rockchip_sai_isr, - IRQF_SHARED, node->name, sai); - if (ret) -- return dev_err_probe(&pdev->dev, ret, -- "Failed to request irq %d\n", irq); -+ return ret; - } else { - dev_dbg(&pdev->dev, "Asked for an IRQ but got %d\n", irq); - } -@@ -1456,7 +1457,7 @@ static int rockchip_sai_probe(struct platform_device *pdev) - - ret = rockchip_sai_parse_paths(sai, node); - if (ret) -- return dev_err_probe(&pdev->dev, ret, "Failed to parse paths\n"); -+ return ret; - - /* - * From here on, all register accesses need to be wrapped in -@@ -1471,18 +1472,14 @@ static int rockchip_sai_probe(struct platform_device *pdev) - return dev_err_probe(&pdev->dev, ret, "Failed to resume device\n"); - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); -- if (ret) { -- dev_err(&pdev->dev, "Failed to register PCM: %d\n", ret); -+ if (ret) - goto err_runtime_suspend; -- } - - ret = devm_snd_soc_register_component(&pdev->dev, - &rockchip_sai_component, - dai, 1); -- if (ret) { -- dev_err(&pdev->dev, "Failed to register component: %d\n", ret); -+ if (ret) - goto err_runtime_suspend; -- } - - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_put(&pdev->dev); -diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c ---- a/sound/soc/rockchip/rockchip_spdif.c -+++ b/sound/soc/rockchip/rockchip_spdif.c -@@ -396,13 +396,13 @@ static int rk_spdif_probe(struct platform_device *pdev) - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); - if (ret) -- return dev_err_probe(&pdev->dev, ret, "Could not register PCM\n"); -+ return ret; - - ret = devm_snd_soc_register_component(&pdev->dev, - &rk_spdif_component, - &rk_spdif_dai, 1); - if (ret) -- return dev_err_probe(&pdev->dev, ret, "Could not register DAI\n"); -+ return ret; - - return 0; - } -diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c ---- a/sound/soc/samsung/i2s.c -+++ b/sound/soc/samsung/i2s.c -@@ -1116,15 +1116,31 @@ static const struct snd_soc_dapm_widget samsung_i2s_widgets[] = { - - static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = { - { "Playback Mixer", NULL, "Primary Playback" }, -- { "Playback Mixer", NULL, "Secondary Playback" }, -- - { "Mixer DAI TX", NULL, "Playback Mixer" }, - { "Primary Capture", NULL, "Mixer DAI RX" }, - }; - -+static const struct snd_soc_dapm_route samsung_i2s_dapm_routes_sec_play[] = { -+ { "Playback Mixer", NULL, "Secondary Playback" }, -+}; -+ -+static int samsung_i2s_component_probe(struct snd_soc_component *component) -+{ -+ struct samsung_i2s_priv *priv = snd_soc_component_get_drvdata(component); -+ -+ if (priv->quirks & QUIRK_SEC_DAI) -+ snd_soc_dapm_add_routes(snd_soc_component_to_dapm(component), -+ samsung_i2s_dapm_routes_sec_play, -+ ARRAY_SIZE(samsung_i2s_dapm_routes_sec_play)); -+ -+ return 0; -+} -+ - static const struct snd_soc_component_driver samsung_i2s_component = { - .name = "samsung-i2s", - -+ .probe = samsung_i2s_component_probe, -+ - .dapm_widgets = samsung_i2s_widgets, - .num_dapm_widgets = ARRAY_SIZE(samsung_i2s_widgets), - -@@ -1441,10 +1457,10 @@ static int samsung_i2s_probe(struct platform_device *pdev) - regs_base = res->start; - - priv->clk = devm_clk_get(&pdev->dev, "iis"); -- if (IS_ERR(priv->clk)) { -- dev_err(&pdev->dev, "Failed to get iis clock\n"); -- return PTR_ERR(priv->clk); -- } -+ if (IS_ERR(priv->clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), -+ "Failed to get iis clock\n"); -+ - - ret = clk_prepare_enable(priv->clk); - if (ret != 0) { -@@ -1650,8 +1666,7 @@ static const struct samsung_i2s_dai_data i2sv6_dai_type __maybe_unused = { - }; - - static const struct samsung_i2s_dai_data i2sv7_dai_type __maybe_unused = { -- .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | -- QUIRK_SUPPORTS_TDM, -+ .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR | QUIRK_SUPPORTS_TDM, - .pcm_rates = SNDRV_PCM_RATE_8000_192000, - .i2s_variant_regs = &i2sv7_regs, - }; -@@ -1675,7 +1690,7 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = { - .name = "samsung-i2s", - .driver_data = (kernel_ulong_t)&i2sv3_dai_type, - }, -- {}, -+ { } - }; - MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids); - -diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c ---- a/sound/soc/samsung/smdk_spdif.c -+++ b/sound/soc/samsung/smdk_spdif.c -@@ -130,12 +130,8 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, - return ret; - - /* Set S/PDIF uses internal source clock */ -- ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK, -- rclk_rate, SND_SOC_CLOCK_IN); -- if (ret < 0) -- return ret; -- -- return ret; -+ return snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK, -+ rclk_rate, SND_SOC_CLOCK_IN); - } - - static const struct snd_soc_ops smdk_spdif_ops = { -diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c ---- a/sound/soc/samsung/spdif.c -+++ b/sound/soc/samsung/spdif.c -@@ -380,8 +380,8 @@ static int spdif_probe(struct platform_device *pdev) - - spdif->pclk = devm_clk_get(&pdev->dev, "spdif"); - if (IS_ERR(spdif->pclk)) { -- dev_err(&pdev->dev, "failed to get peri-clock\n"); -- ret = -ENOENT; -+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->pclk), -+ "failed to get peri-clock\n"); - goto err0; - } - ret = clk_prepare_enable(spdif->pclk); -@@ -390,8 +390,8 @@ static int spdif_probe(struct platform_device *pdev) - - spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif"); - if (IS_ERR(spdif->sclk)) { -- dev_err(&pdev->dev, "failed to get internal source clock\n"); -- ret = -ENOENT; -+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->sclk), -+ "failed to get internal source clock\n"); - goto err1; - } - ret = clk_prepare_enable(spdif->sclk); -diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c ---- a/sound/soc/sdca/sdca_asoc.c -+++ b/sound/soc/sdca/sdca_asoc.c -@@ -364,7 +364,6 @@ static int entity_parse_ot(struct device *dev, - - /** - * sdca_asoc_pde_poll_actual_ps - Verify PDE power state reached target state -- * @dev: Pointer to the device for error logging. - * @regmap: Register map for reading ACTUAL_PS register. - * @function_id: SDCA function identifier. - * @entity_id: SDCA entity identifier for the power domain. -@@ -389,11 +388,11 @@ static int entity_parse_ot(struct device *dev, - * polling times out before reaching the target state, or a negative error code if - * a register read fails. - */ --int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap, -+int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap, - int function_id, int entity_id, -- int from_ps, int to_ps, -- const struct sdca_pde_delay *pde_delays, -- int num_delays) -+ int from_ps, int to_ps, -+ const struct sdca_pde_delay *pde_delays, -+ int num_delays) - { - static const int polls = 100; - static const int default_poll_us = 1000; -@@ -451,14 +450,14 @@ static int entity_pde_event(struct snd_soc_dapm_widget *widget, - return 0; - } - -- ret = sdca_asoc_pde_poll_actual_ps(component->dev, component->regmap, -+ ret = sdca_asoc_pde_poll_actual_ps(component->regmap, - SDW_SDCA_CTL_FUNC(widget->reg), - SDW_SDCA_CTL_ENT(widget->reg), - from, to, - entity->pde.max_delay, - entity->pde.num_max_delay); - if (ret) -- dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n", -+ dev_err(component->dev, "%s: pde transition %x -> %x failed: %d\n", - entity->label, from, to, ret); - - return ret; -@@ -1231,7 +1230,7 @@ static u64 width_find_mask(unsigned int bits) - } - } - --static int populate_rate_format(struct device *dev, -+int sdca_asoc_populate_rate_format(struct device *dev, - struct sdca_function_data *function, - struct sdca_entity *entity, - struct snd_soc_pcm_stream *stream) -@@ -1292,6 +1291,7 @@ static int populate_rate_format(struct device *dev, - - return 0; - } -+EXPORT_SYMBOL_NS(sdca_asoc_populate_rate_format, "SND_SOC_SDCA"); - - /** - * sdca_asoc_populate_dais - fill in an array of DAI drivers for a Function -@@ -1344,7 +1344,7 @@ int sdca_asoc_populate_dais(struct device *dev, struct sdca_function_data *funct - stream->channels_min = 1; - stream->channels_max = SDCA_MAX_CHANNEL_COUNT; - -- ret = populate_rate_format(dev, function, entity, stream); -+ ret = sdca_asoc_populate_rate_format(dev, function, entity, stream); - if (ret) - return ret; - -diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c ---- a/sound/soc/sdca/sdca_class_function.c -+++ b/sound/soc/sdca/sdca_class_function.c -@@ -329,7 +329,7 @@ static int class_function_probe(struct auxiliary_device *auxdev, - drv->core = core; - drv->function = &sdev->function; - -- ret = sdca_parse_function(dev, core->sdw, drv->function); -+ ret = sdca_parse_function(dev, drv->function); - if (ret) - return ret; - -diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c ---- a/sound/soc/sdca/sdca_fdl.c -+++ b/sound/soc/sdca/sdca_fdl.c -@@ -195,7 +195,6 @@ static int fdl_load_file(struct sdca_interrupt *interrupt, - { - struct device *dev = interrupt->dev; - struct sdca_fdl_data *fdl_data = &interrupt->function->fdl_data; -- const struct firmware *firmware = NULL; - struct acpi_sw_file *swf = NULL, *tmp; - struct sdca_fdl_file *fdl_file; - char *disk_filename; -@@ -230,6 +229,7 @@ static int fdl_load_file(struct sdca_interrupt *interrupt, - - dev_dbg(dev, "FDL disk filename: %s\n", disk_filename); - -+ const struct firmware *firmware __free(firmware) = NULL; - ret = firmware_request_nowarn(&firmware, disk_filename, dev); - kfree(disk_filename); - if (ret) { -@@ -258,8 +258,7 @@ static int fdl_load_file(struct sdca_interrupt *interrupt, - - if (!swf) { - dev_err(dev, "failed to locate SWF\n"); -- ret = -ENOENT; -- goto error; -+ return -ENOENT; - } - - dev_info(dev, "loading SWF: %x-%x-%x\n", -@@ -271,9 +270,6 @@ static int fdl_load_file(struct sdca_interrupt *interrupt, - SDCA_CTL_XU_FDL_MESSAGEOFFSET, fdl_file->fdl_offset, - SDCA_CTL_XU_FDL_MESSAGELENGTH, swf->data, - swf->file_length - offsetof(struct acpi_sw_file, data)); -- --error: -- release_firmware(firmware); - return ret; - } - -diff --git a/sound/soc/sdca/sdca_function_device.c b/sound/soc/sdca/sdca_function_device.c ---- a/sound/soc/sdca/sdca_function_device.c -+++ b/sound/soc/sdca/sdca_function_device.c -@@ -32,7 +32,8 @@ static void sdca_dev_release(struct device *dev) - - /* alloc, init and add link devices */ - static struct sdca_dev *sdca_dev_register(struct device *parent, -- struct sdca_function_desc *function_desc) -+ struct sdca_function_desc *function_desc, -+ struct acpi_table_swft *swft) - { - struct sdca_dev *sdev; - struct auxiliary_device *auxdev; -@@ -50,6 +51,7 @@ static struct sdca_dev *sdca_dev_register(struct device *parent, - auxdev->dev.release = sdca_dev_release; - - sdev->function.desc = function_desc; -+ sdev->function.fdl_data.swft = swft; - - rc = ida_alloc(&sdca_function_ida, GFP_KERNEL); - if (rc < 0) { -@@ -99,7 +101,8 @@ int sdca_dev_register_functions(struct sdw_slave *slave) - struct sdca_dev *func_dev; - - func_dev = sdca_dev_register(&slave->dev, -- &sdca_data->function[i]); -+ &sdca_data->function[i], -+ sdca_data->swft); - if (IS_ERR(func_dev)) { - ret = PTR_ERR(func_dev); - /* -diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c ---- a/sound/soc/sdca/sdca_functions.c -+++ b/sound/soc/sdca/sdca_functions.c -@@ -7,6 +7,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -18,7 +19,6 @@ - #include - #include - #include --#include - - /* - * Should be long enough to encompass all the MIPI DisCo properties. -@@ -1365,90 +1365,76 @@ static int find_sdca_entity_ge(struct device *dev, - return -EINVAL; - } - --static int --find_sdca_entity_hide(struct device *dev, struct sdw_slave *sdw, -- struct fwnode_handle *function_node, -- struct fwnode_handle *entity_node, struct sdca_entity *entity) -+static int find_sdca_entity_hide(struct device *dev, -+ struct fwnode_handle *entity_node, -+ struct sdca_entity *entity) - { - struct sdca_entity_hide *hide = &entity->hide; -- unsigned int delay, *af_list = hide->af_number_list; -- int nval, ret; -- unsigned char *report_desc = NULL; -+ int num_reports, ret; -+ unsigned int delay; - - ret = fwnode_property_read_u32(entity_node, -- "mipi-sdca-RxUMP-ownership-transition-max-delay", &delay); -+ "mipi-sdca-RxUMP-ownership-transition-max-delay", -+ &delay); - if (!ret) - hide->max_delay = delay; - -- nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDTx-supported-report-ids"); -- if (nval > 0) { -- hide->num_hidtx_ids = nval; -+ num_reports = fwnode_property_count_u32(entity_node, -+ "mipi-sdca-HIDTx-supported-report-ids"); -+ if (num_reports < 0 && num_reports != -EINVAL) { -+ dev_err(dev, "%pfwP: failed to read hid tx ids: %d\n", -+ entity_node, num_reports); -+ return num_reports; -+ } else if (num_reports > 0) { -+ hide->num_hidtx_ids = num_reports; - hide->hidtx_ids = devm_kcalloc(dev, hide->num_hidtx_ids, - sizeof(*hide->hidtx_ids), GFP_KERNEL); - if (!hide->hidtx_ids) - return -ENOMEM; - -- ret = fwnode_property_read_u32_array(entity_node, -- "mipi-sdca-HIDTx-supported-report-ids", -- hide->hidtx_ids, -- hide->num_hidtx_ids); -- if (ret < 0) -- return ret; -+ fwnode_property_read_u32_array(entity_node, -+ "mipi-sdca-HIDTx-supported-report-ids", -+ hide->hidtx_ids, hide->num_hidtx_ids); - } - -- nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDRx-supported-report-ids"); -- if (nval > 0) { -- hide->num_hidrx_ids = nval; -+ num_reports = fwnode_property_count_u32(entity_node, -+ "mipi-sdca-HIDRx-supported-report-ids"); -+ if (num_reports < 0 && num_reports != -EINVAL) { -+ dev_err(dev, "%pfwP: failed to read hid rx ids: %d\n", -+ entity_node, num_reports); -+ return num_reports; -+ } else if (num_reports > 0) { -+ hide->num_hidrx_ids = num_reports; - hide->hidrx_ids = devm_kcalloc(dev, hide->num_hidrx_ids, - sizeof(*hide->hidrx_ids), GFP_KERNEL); - if (!hide->hidrx_ids) - return -ENOMEM; - -- ret = fwnode_property_read_u32_array(entity_node, -- "mipi-sdca-HIDRx-supported-report-ids", -- hide->hidrx_ids, -- hide->num_hidrx_ids); -- if (ret < 0) -- return ret; -+ fwnode_property_read_u32_array(entity_node, -+ "mipi-sdca-HIDRx-supported-report-ids", -+ hide->hidrx_ids, hide->num_hidrx_ids); - } - -- nval = fwnode_property_count_u32(entity_node, "mipi-sdca-hide-related-audio-function-list"); -- if (nval <= 0) { -+ /* -+ * FIXME: This should probably link to the actual sdca_function_data pointer, -+ * but updating to do so should probably wait until we have a user. -+ */ -+ num_reports = fwnode_property_count_u32(entity_node, -+ "mipi-sdca-hide-related-audio-function-list"); -+ if (num_reports <= 0) { - dev_err(dev, "%pfwP: audio function numbers list missing: %d\n", -- entity_node, nval); -+ entity_node, num_reports); - return -EINVAL; -- } else if (nval > SDCA_MAX_FUNCTION_COUNT) { -- dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", entity_node); -+ } else if (num_reports > ARRAY_SIZE(hide->af_number_list)) { -+ dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", -+ entity_node); - return -EINVAL; - } - -- hide->hide_reside_function_num = nval; -+ hide->hide_reside_function_num = num_reports; - fwnode_property_read_u32_array(entity_node, -- "mipi-sdca-hide-related-audio-function-list", af_list, nval); -- -- nval = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor"); -- if (nval) -- fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor", -- (u8 *)&hide->hid_desc, nval); -- -- if (hide->hid_desc.bNumDescriptors) { -- nval = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor"); -- if (nval) { -- report_desc = devm_kzalloc(dev, nval, GFP_KERNEL); -- if (!report_desc) -- return -ENOMEM; -- hide->hid_report_desc = report_desc; -- fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor", -- report_desc, nval); -- -- /* add HID device */ -- ret = sdca_add_hid_device(dev, sdw, entity); -- if (ret) { -- dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret); -- return ret; -- } -- } -- } -+ "mipi-sdca-hide-related-audio-function-list", -+ hide->af_number_list, num_reports); - - return 0; - } -@@ -1475,8 +1461,7 @@ static int find_sdca_entity_xu(struct device *dev, - return 0; - } - --static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw, -- struct sdca_function_data *function, -+static int find_sdca_entity(struct device *dev, struct sdca_function_data *function, - struct fwnode_handle *function_node, - struct fwnode_handle *entity_node, - struct sdca_entity *entity) -@@ -1528,8 +1513,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw, - ret = find_sdca_entity_ge(dev, entity_node, entity); - break; - case SDCA_ENTITY_TYPE_HIDE: -- ret = find_sdca_entity_hide(dev, sdw, function_node, -- entity_node, entity); -+ ret = find_sdca_entity_hide(dev, entity_node, entity); - break; - default: - break; -@@ -1544,8 +1528,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw, - return 0; - } - --static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, -- struct fwnode_handle *function_node, -+static int find_sdca_entities(struct device *dev, struct fwnode_handle *function_node, - struct sdca_function_data *function) - { - struct sdca_entity *entities; -@@ -1596,7 +1579,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, - return -EINVAL; - } - -- ret = find_sdca_entity(dev, sdw, function, function_node, -+ ret = find_sdca_entity(dev, function, function_node, - entity_node, &entities[i]); - fwnode_handle_put(entity_node); - if (ret) -@@ -1619,7 +1602,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, - return 0; - } - --static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *function, -+struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function, - const char *entity_label) - { - struct sdca_entity *entity = NULL; -@@ -1648,6 +1631,7 @@ static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data * - - return NULL; - } -+EXPORT_SYMBOL_NS(sdca_find_entity_by_label, "SND_SOC_SDCA"); - - static struct sdca_entity *find_sdca_entity_by_id(struct sdca_function_data *function, - const int id) -@@ -1688,7 +1672,7 @@ static int find_sdca_entity_connection_iot(struct device *dev, - return ret; - } - -- clock_entity = find_sdca_entity_by_label(function, clock_label); -+ clock_entity = sdca_find_entity_by_label(function, clock_label); - if (!clock_entity) { - dev_err(dev, "%s: failed to find clock with label %s\n", - entity->label, clock_label); -@@ -1873,7 +1857,7 @@ static int find_sdca_entity_connection(struct device *dev, - return ret; - } - -- connected_entity = find_sdca_entity_by_label(function, connected_label); -+ connected_entity = sdca_find_entity_by_label(function, connected_label); - if (!connected_entity) { - dev_err(dev, "%s: failed to find entity with label %s\n", - entity->label, connected_label); -@@ -2088,8 +2072,7 @@ static int find_sdca_clusters(struct device *dev, - return 0; - } - --static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, -- struct fwnode_handle *function_node, -+static int find_sdca_filesets(struct device *dev, struct fwnode_handle *function_node, - struct sdca_function_data *function) - { - static const int mult_fileset = 3; -@@ -2171,23 +2154,65 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, - set->files = files; - } - -- function->fdl_data.swft = sdw->sdca_data.swft; - function->fdl_data.num_sets = num_sets; - function->fdl_data.sets = sets; - - return 0; - } - -+static int find_sdca_hid(struct device *dev, struct fwnode_handle *function_node, -+ struct sdca_function_data *function) -+{ -+ int num_desc; -+ -+ num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor"); -+ if (!num_desc) { -+ return 0; -+ } else if (num_desc < 0) { -+ dev_err(dev, "%pfwP: failed to read hid descriptor: %d\n", -+ function_node, num_desc); -+ return num_desc; -+ } else if (num_desc > sizeof(function->hid.desc)) { -+ dev_err(dev, "%pfwP: hid descriptor too large: %d\n", -+ function_node, num_desc); -+ return -EINVAL; -+ } -+ -+ fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor", -+ (u8 *)&function->hid.desc, num_desc); -+ -+ if (!function->hid.desc.bNumDescriptors) -+ return 0; -+ -+ num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor"); -+ if (num_desc <= 0) { -+ dev_err(dev, "%pfwP: failed to read report descriptor: %d\n", -+ function_node, num_desc); -+ -+ if (!num_desc) -+ return -EINVAL; -+ -+ return num_desc; -+ } -+ -+ function->hid.report_desc = devm_kzalloc(dev, num_desc, GFP_KERNEL); -+ if (!function->hid.report_desc) -+ return -ENOMEM; -+ -+ fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor", -+ function->hid.report_desc, num_desc); -+ -+ return 0; -+} -+ - /** - * sdca_parse_function - parse ACPI DisCo for a Function - * @dev: Pointer to device against which function data will be allocated. -- * @sdw: SoundWire slave device to be processed. - * @function: Pointer to the Function information, to be populated. - * - * Return: Returns 0 for success. - */ --int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, -- struct sdca_function_data *function) -+int sdca_parse_function(struct device *dev, struct sdca_function_data *function) - { - struct fwnode_handle *node = function->desc->node; - u32 tmp; -@@ -2213,7 +2238,7 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, - if (ret) - return ret; - -- ret = find_sdca_entities(dev, sdw, node, function); -+ ret = find_sdca_entities(dev, node, function); - if (ret) - return ret; - -@@ -2225,10 +2250,20 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, - if (ret < 0) - return ret; - -- ret = find_sdca_filesets(dev, sdw, node, function); -+ ret = find_sdca_filesets(dev, node, function); - if (ret) - return ret; - -+ switch (function->desc->type) { -+ case SDCA_FUNCTION_TYPE_HID: -+ ret = find_sdca_hid(dev, node, function); -+ if (ret) -+ return ret; -+ break; -+ default: -+ break; -+ } -+ - return 0; - } - EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); -diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c ---- a/sound/soc/sdca/sdca_hid.c -+++ b/sound/soc/sdca/sdca_hid.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -23,18 +24,18 @@ - - static int sdwhid_parse(struct hid_device *hid) - { -- struct sdca_entity *entity = hid->driver_data; -+ struct sdca_function_data *function = hid->driver_data; - unsigned int rsize; - int ret; - -- rsize = le16_to_cpu(entity->hide.hid_desc.rpt_desc.wDescriptorLength); -+ rsize = le16_to_cpu(function->hid.desc.rpt_desc.wDescriptorLength); - - if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { - dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize); - return -EINVAL; - } - -- ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize); -+ ret = hid_parse_report(hid, function->hid.report_desc, rsize); - - if (!ret) - return 0; -@@ -85,10 +86,16 @@ static const struct hid_ll_driver sdw_hid_driver = { - .raw_request = sdwhid_raw_request, - }; - --int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, -- struct sdca_entity *entity) -+/** -+ * sdca_add_hid_device - create a new SDCA HID device -+ * @interrupt: Pointer to the SDCA interrupt information structure. -+ * -+ * Return: Zero on success, and a negative error code on failure. -+ */ -+int sdca_add_hid_device(struct sdca_interrupt *interrupt) - { -- struct sdw_bus *bus = sdw->bus; -+ struct device *dev = interrupt->dev; -+ struct sdca_function_data *function = interrupt->function; - struct hid_device *hid; - int ret; - -@@ -100,16 +107,13 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, - - hid->dev.parent = dev; - hid->bus = BUS_SDW; -- hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID); -+ hid->version = le16_to_cpu(function->hid.desc.bcdHID); - -- snprintf(hid->name, sizeof(hid->name), -- "HID sdw:%01x:%01x:%04x:%04x:%02x", -- bus->controller_id, bus->link_id, sdw->id.mfg_id, -- sdw->id.part_id, sdw->id.class_id); -+ strscpy(hid->phys, dev_name(dev)); -+ snprintf(hid->name, sizeof(hid->name), "SDCA %s:%02x", -+ function->desc->name, function->desc->adr); - -- snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name); -- -- hid->driver_data = entity; -+ hid->driver_data = function; - - ret = hid_add_device(hid); - if (ret && ret != -ENODEV) { -@@ -118,12 +122,24 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, - return ret; - } - -- entity->hide.hid = hid; -+ interrupt->priv = hid; - - return 0; - } - EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA"); - -+/** -+ * sdca_destroy_hid_device - destroy the HID device -+ * @interrupt: Pointer to the SDCA interrupt information structure. -+ */ -+void sdca_destroy_hid_device(struct sdca_interrupt *interrupt) -+{ -+ struct hid_device *hid = interrupt->priv; -+ -+ hid_destroy_device(hid); -+} -+EXPORT_SYMBOL_NS(sdca_destroy_hid_device, "SND_SOC_SDCA"); -+ - /** - * sdca_hid_process_report - read a HID event from the device and report - * @interrupt: Pointer to the SDCA interrupt information structure. -@@ -133,7 +149,7 @@ EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA"); - int sdca_hid_process_report(struct sdca_interrupt *interrupt) - { - struct device *dev = interrupt->dev; -- struct hid_device *hid = interrupt->entity->hide.hid; -+ struct hid_device *hid = interrupt->priv; - void *val __free(kfree) = NULL; - int len, ret; - -diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c ---- a/sound/soc/sdca/sdca_interrupts.c -+++ b/sound/soc/sdca/sdca_interrupts.c -@@ -487,6 +487,12 @@ int sdca_irq_populate_early(struct device *dev, struct regmap *regmap, - } - break; - case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): -+ interrupt->free_priv = sdca_destroy_hid_device; -+ -+ ret = sdca_add_hid_device(interrupt); -+ if (ret) -+ return ret; -+ - interrupt->handler = hid_handler; - break; - default: -diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c ---- a/sound/soc/sdw_utils/soc_sdw_utils.c -+++ b/sound/soc/sdw_utils/soc_sdw_utils.c -@@ -834,6 +834,35 @@ struct asoc_sdw_codec_info codec_info_list[] = { - }, - .dai_num = 2, - }, -+ { -+ .vendor_id = 0x01fa, -+ .part_id = 0x3562, -+ .name_prefix = "AMP", -+ .is_amp = true, -+ .dais = { -+ { -+ .direction = {true, false}, -+ .dai_name = "cs35l56-sdw1", -+ .component_name = "cs35l56", -+ .dai_type = SOC_SDW_DAI_TYPE_AMP, -+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, -+ .init = asoc_sdw_cs_amp_init, -+ .rtd_init = asoc_sdw_cs_spk_rtd_init, -+ .controls = generic_spk_controls, -+ .num_controls = ARRAY_SIZE(generic_spk_controls), -+ .widgets = generic_spk_widgets, -+ .num_widgets = ARRAY_SIZE(generic_spk_widgets), -+ }, -+ { -+ .direction = {false, true}, -+ .dai_name = "cs35l56-sdw1c", -+ .dai_type = SOC_SDW_DAI_TYPE_AMP, -+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, -+ .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, -+ }, -+ }, -+ .dai_num = 2, -+ }, - { - .vendor_id = 0x01fa, - .part_id = 0x3563, -@@ -1789,9 +1818,7 @@ static int is_sdca_aux_dev_present(struct device *dev, - int adr_index) - { - struct sdw_slave *slave; -- struct device *sdw_dev; - const char *sdw_codec_name; -- int ret = 0; - int i; - - if (!aux_codec_name) -@@ -1801,7 +1828,8 @@ static int is_sdca_aux_dev_present(struct device *dev, - if (!sdw_codec_name) - return -ENOMEM; - -- sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); -+ struct device *sdw_dev __free(put_device) = -+ bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); - if (!sdw_dev) { - dev_err(dev, "codec %s not found\n", sdw_codec_name); - return -EINVAL; -@@ -1811,24 +1839,19 @@ static int is_sdca_aux_dev_present(struct device *dev, - - if (!slave->sdca_data.interface_revision) { - dev_warn(dev, "No SDCA properties, assuming aux '%s' present\n", aux_codec_name); -- ret = 1; -- goto put_dev; -+ return 1; - } - - for (i = 0; i < slave->sdca_data.num_functions; i++) { - const char *fname = slave->sdca_data.function[i].name; - -- if (fname && strstr(aux_codec_name, fname)) { -- ret = 1; -- goto put_dev; -- } -+ if (fname && strstr(aux_codec_name, fname)) -+ return 1; - } - - dev_dbg(dev, "SDCA function for aux '%s' NOT FOUND on slave, skipping\n", aux_codec_name); - --put_dev: -- put_device(sdw_dev); -- return ret; -+ return 0; - } - - int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, -@@ -1928,9 +1951,8 @@ static int is_sdca_endpoint_present(struct device *dev, - const struct snd_soc_acpi_endpoint *adr_end; - const struct asoc_sdw_dai_info *dai_info; - struct sdw_slave *slave; -- struct device *sdw_dev; - const char *sdw_codec_name; -- int ret, i; -+ int i; - - adr_end = &adr_dev->endpoints[end_index]; - dai_info = &codec_info->dais[adr_end->num]; -@@ -1939,7 +1961,8 @@ static int is_sdca_endpoint_present(struct device *dev, - if (!sdw_codec_name) - return -ENOMEM; - -- sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); -+ struct device *sdw_dev __free(put_device) = -+ bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name); - if (!sdw_dev) { - dev_err(dev, "codec %s not found\n", sdw_codec_name); - return -EINVAL; -@@ -1950,8 +1973,7 @@ static int is_sdca_endpoint_present(struct device *dev, - /* Make sure BIOS provides SDCA properties */ - if (!slave->sdca_data.interface_revision) { - dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n"); -- ret = 1; -- goto put_device; -+ return 1; - } - - for (i = 0; i < slave->sdca_data.num_functions; i++) { -@@ -1960,8 +1982,7 @@ static int is_sdca_endpoint_present(struct device *dev, - if (dai_type == dai_info->dai_type) { - dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n", - dai_type, slave->sdca_data.function[i].name); -- ret = 1; -- goto put_device; -+ return 1; - } - } - -@@ -1969,11 +1990,7 @@ static int is_sdca_endpoint_present(struct device *dev, - "SDCA device function for DAI type %d not supported, skip endpoint\n", - dai_info->dai_type); - -- ret = 0; -- --put_device: -- put_device(sdw_dev); -- return ret; -+ return 0; - } - - int asoc_sdw_parse_sdw_endpoints(struct device *dev, -diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c ---- a/sound/soc/soc-component.c -+++ b/sound/soc/soc-component.c -@@ -29,17 +29,42 @@ static inline int _soc_component_ret_reg_rw(struct snd_soc_component *component, - func, component->name, reg); - } - --static inline int soc_component_field_shift(struct snd_soc_component *component, -- unsigned int mask) -+struct snd_soc_component *snd_soc_component_alloc(struct device *dev) - { -- if (!mask) { -- dev_err(component->dev, "ASoC: error field mask is zero for %s\n", -- component->name); -- return 0; -- } -+ struct snd_soc_component *component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL); - -- return (ffs(mask) - 1); -+ if (!component) -+ return NULL; -+ -+ component->dev = dev; -+ -+ return component; - } -+EXPORT_SYMBOL_GPL(snd_soc_component_alloc); -+ -+void snd_soc_component_set_name(struct snd_soc_component *component, const char *name) -+{ -+ component->name = name; -+} -+EXPORT_SYMBOL_GPL(snd_soc_component_set_name); -+ -+const char *snd_soc_component_name(struct snd_soc_component *component) -+{ -+ return component->name; -+} -+EXPORT_SYMBOL_GPL(snd_soc_component_name); -+ -+void snd_soc_component_set_priv(struct snd_soc_component *component, void *priv) -+{ -+ component->priv = priv; -+} -+EXPORT_SYMBOL_GPL(snd_soc_component_set_priv); -+ -+void *snd_soc_component_to_priv(struct snd_soc_component *component) -+{ -+ return component->priv; -+} -+EXPORT_SYMBOL_GPL(snd_soc_component_to_priv); - - /* - * We might want to check substream by using list. -@@ -820,6 +845,18 @@ int snd_soc_component_update_bits_async(struct snd_soc_component *component, - } - EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async); - -+static inline int soc_component_field_shift(struct snd_soc_component *component, -+ unsigned int mask) -+{ -+ if (!mask) { -+ dev_err(component->dev, "ASoC: error field mask is zero for %s\n", -+ component->name); -+ return 0; -+ } -+ -+ return (ffs(mask) - 1); -+} -+ - /** - * snd_soc_component_read_field() - Read register field value - * @component: Component to read from -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -2707,10 +2707,11 @@ static void snd_soc_del_component_unlocked(struct snd_soc_component *component) - list_del(&component->list); - } - --int snd_soc_component_initialize(struct snd_soc_component *component, -- const struct snd_soc_component_driver *driver, -- struct device *dev) -+static int soc_component_initialize(struct snd_soc_component *component, -+ const struct snd_soc_component_driver *driver) - { -+ struct device *dev = component->dev; -+ - component->dapm = snd_soc_dapm_alloc(dev); - if (!component->dapm) - return -ENOMEM; -@@ -2730,16 +2731,14 @@ int snd_soc_component_initialize(struct snd_soc_component *component, - } - } - -- component->dev = dev; - component->driver = driver; - - return 0; - } --EXPORT_SYMBOL_GPL(snd_soc_component_initialize); - --int snd_soc_add_component(struct snd_soc_component *component, -- struct snd_soc_dai_driver *dai_drv, -- int num_dai) -+static int soc_component_add(struct snd_soc_component *component, -+ struct snd_soc_dai_driver *dai_drv, -+ int num_dai) - { - struct snd_soc_card *card, *c; - int ret; -@@ -2778,27 +2777,36 @@ int snd_soc_add_component(struct snd_soc_component *component, - - return ret; - } --EXPORT_SYMBOL_GPL(snd_soc_add_component); - --int snd_soc_register_component(struct device *dev, -+int snd_soc_register_component_c(struct snd_soc_component *component, - const struct snd_soc_component_driver *component_driver, - struct snd_soc_dai_driver *dai_drv, - int num_dai) - { -- struct snd_soc_component *component; - int ret; - -- component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL); -- if (!component) -- return -ENOMEM; -- -- ret = snd_soc_component_initialize(component, component_driver, dev); -+ ret = soc_component_initialize(component, component_driver); - if (ret < 0) - return ret; - -- return snd_soc_add_component(component, dai_drv, num_dai); -+ return soc_component_add(component, dai_drv, num_dai); - } --EXPORT_SYMBOL_GPL(snd_soc_register_component); -+EXPORT_SYMBOL_GPL(snd_soc_register_component_c); -+ -+int snd_soc_register_component_d(struct device *dev, -+ const struct snd_soc_component_driver *component_driver, -+ struct snd_soc_dai_driver *dai_drv, -+ int num_dai) -+{ -+ struct snd_soc_component *component; -+ -+ component = snd_soc_component_alloc(dev); -+ if (!component) -+ return -ENOMEM; -+ -+ return snd_soc_register_component_c(component, component_driver, dai_drv, num_dai); -+} -+EXPORT_SYMBOL_GPL(snd_soc_register_component_d); - - /** - * snd_soc_unregister_component_by_driver - Unregister component using a given driver -diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c ---- a/sound/soc/soc-dapm.c -+++ b/sound/soc/soc-dapm.c -@@ -1203,6 +1203,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, - case snd_soc_dapm_pga: - case snd_soc_dapm_effect: - case snd_soc_dapm_out_drv: -+ case snd_soc_dapm_encoder: -+ case snd_soc_dapm_decoder: - wname_in_long_name = true; - kcname_in_long_name = true; - break; -@@ -2785,6 +2787,8 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *component, - case snd_soc_dapm_pga: - case snd_soc_dapm_effect: - case snd_soc_dapm_out_drv: -+ case snd_soc_dapm_encoder: -+ case snd_soc_dapm_decoder: - case snd_soc_dapm_mixer: - case snd_soc_dapm_mixer_named_ctl: - case snd_soc_dapm_supply: -@@ -3367,6 +3371,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) - case snd_soc_dapm_pga: - case snd_soc_dapm_effect: - case snd_soc_dapm_out_drv: -+ case snd_soc_dapm_encoder: -+ case snd_soc_dapm_decoder: - dapm_new_pga(w); - break; - case snd_soc_dapm_dai_link: -diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c ---- a/sound/soc/soc-generic-dmaengine-pcm.c -+++ b/sound/soc/soc-generic-dmaengine-pcm.c -@@ -3,6 +3,7 @@ - // Copyright (C) 2013, Analog Devices Inc. - // Author: Lars-Peter Clausen - -+#include - #include - #include - #include -@@ -77,7 +78,7 @@ static int dmaengine_pcm_hw_params(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) - { -- struct dmaengine_pcm *pcm = soc_component_to_pcm(component); -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component); - struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); - struct dma_slave_config slave_config; - int ret; -@@ -99,7 +100,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component, - struct snd_pcm_substream *substream) - { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -- struct dmaengine_pcm *pcm = soc_component_to_pcm(component); -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component); - struct device *dma_dev = dmaengine_dma_dev(pcm, substream); - struct dma_chan *chan = pcm->chan[substream->stream]; - struct snd_dmaengine_dai_dma_data *dma_data; -@@ -148,7 +149,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component, - static int dmaengine_pcm_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) - { -- struct dmaengine_pcm *pcm = soc_component_to_pcm(component); -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component); - struct dma_chan *chan = pcm->chan[substream->stream]; - int ret; - -@@ -176,7 +177,7 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( - struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_substream *substream) - { -- struct dmaengine_pcm *pcm = soc_component_to_pcm(component); -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component); - struct snd_dmaengine_dai_dma_data *dma_data; - - if (rtd->dai_link->num_cpus > 1) { -@@ -219,7 +220,7 @@ static bool dmaengine_pcm_can_report_residue(struct device *dev, - static int dmaengine_pcm_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtd) - { -- struct dmaengine_pcm *pcm = soc_component_to_pcm(component); -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component); - const struct snd_dmaengine_pcm_config *config = pcm->config; - struct device *dev = component->dev; - size_t prealloc_buffer_size; -@@ -279,7 +280,7 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer( - struct snd_soc_component *component, - struct snd_pcm_substream *substream) - { -- struct dmaengine_pcm *pcm = soc_component_to_pcm(component); -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component); - - if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) - return snd_dmaengine_pcm_pointer_no_residue(substream); -@@ -293,7 +294,7 @@ static int dmaengine_copy(struct snd_soc_component *component, - struct iov_iter *iter, unsigned long bytes) - { - struct snd_pcm_runtime *runtime = substream->runtime; -- struct dmaengine_pcm *pcm = soc_component_to_pcm(component); -+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component); - int (*process)(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - unsigned long bytes) = pcm->config->process; -@@ -395,6 +396,27 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, - */ - if (PTR_ERR(chan) == -EPROBE_DEFER) - return -EPROBE_DEFER; -+ -+ bool has_fw_node = dev->of_node || is_acpi_device_node(dev->fwnode); -+ bool name_exists_in_fw = false; -+ -+ if (has_fw_node) -+ name_exists_in_fw = device_property_match_string(dev, -+ "dma-names", -+ name) >= 0; -+ -+ if (has_fw_node && name_exists_in_fw) -+ dev_warn(dev, "DTS/ACPI DMA channel '%s' request failed (%ld)\n", -+ name, PTR_ERR(chan)); -+ -+ if (has_fw_node && !name_exists_in_fw) -+ dev_warn(dev, "DTS/ACPI name '%s' not found, legacy failed (%ld)\n", -+ name, PTR_ERR(chan)); -+ -+ if (!has_fw_node) -+ dev_warn(dev, "Legacy DMA channel '%s' request failed (%ld)\n", -+ name, PTR_ERR(chan)); -+ - pcm->chan[i] = NULL; - } else { - pcm->chan[i] = chan; -@@ -406,6 +428,12 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, - if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) - pcm->chan[1] = pcm->chan[0]; - -+ if (!pcm->chan[0] && -+ !pcm->chan[1]) { -+ dev_err(dev, "no DMA channel found for either playback or capture\n"); -+ return -ENODEV; -+ } -+ - return 0; - } - -@@ -435,10 +463,15 @@ static const struct snd_dmaengine_pcm_config snd_dmaengine_pcm_default_config = - int snd_dmaengine_pcm_register(struct device *dev, - const struct snd_dmaengine_pcm_config *config, unsigned int flags) - { -+ struct snd_soc_component *component; - const struct snd_soc_component_driver *driver; - struct dmaengine_pcm *pcm; - int ret; - -+ component = snd_soc_component_alloc(dev); -+ if (!component) -+ return -ENOMEM; -+ - pcm = kzalloc_obj(*pcm); - if (!pcm) - return -ENOMEM; -@@ -449,7 +482,8 @@ int snd_dmaengine_pcm_register(struct device *dev, - pcm->flags = flags; - - if (config->name) -- pcm->component.name = config->name; -+ snd_soc_component_set_name(component, config->name); -+ snd_soc_component_set_priv(component, pcm); - - ret = dmaengine_pcm_request_chan_of(pcm, dev, config); - if (ret) -@@ -460,11 +494,7 @@ int snd_dmaengine_pcm_register(struct device *dev, - else - driver = &dmaengine_pcm_component; - -- ret = snd_soc_component_initialize(&pcm->component, driver, dev); -- if (ret) -- goto err_free_dma; -- -- ret = snd_soc_add_component(&pcm->component, NULL, 0); -+ ret = snd_soc_register_component(component, driver, NULL, 0); - if (ret) - goto err_free_dma; - -@@ -493,7 +523,7 @@ void snd_dmaengine_pcm_unregister(struct device *dev) - if (!component) - return; - -- pcm = soc_component_to_pcm(component); -+ pcm = snd_soc_component_to_priv(component); - - snd_soc_unregister_component_by_driver(dev, component->driver); - dmaengine_pcm_release_chan(pcm); -diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c ---- a/sound/soc/soc-topology-test.c -+++ b/sound/soc/soc-topology-test.c -@@ -45,15 +45,13 @@ static void snd_soc_tplg_test_exit(struct kunit *test) - struct kunit_soc_component { - struct kunit *kunit; - int expect; /* what result we expect when loading topology */ -- struct snd_soc_component comp; - struct snd_soc_card card; - struct firmware fw; - }; - - static int d_probe(struct snd_soc_component *component) - { -- struct kunit_soc_component *kunit_comp = -- container_of(component, struct kunit_soc_component, comp); -+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component); - int ret; - - ret = snd_soc_tplg_component_load(component, NULL, &kunit_comp->fw); -@@ -65,8 +63,7 @@ static int d_probe(struct snd_soc_component *component) - - static void d_remove(struct snd_soc_component *component) - { -- struct kunit_soc_component *kunit_comp = -- container_of(component, struct kunit_soc_component, comp); -+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component); - int ret; - - ret = snd_soc_tplg_component_remove(component); -@@ -214,8 +211,7 @@ static struct tplg_tmpl_002 tplg_tmpl_with_pcm = { - */ - static int d_probe_null_comp(struct snd_soc_component *component) - { -- struct kunit_soc_component *kunit_comp = -- container_of(component, struct kunit_soc_component, comp); -+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component); - int ret; - - /* instead of passing component pointer as first argument, pass NULL here */ -@@ -234,6 +230,7 @@ static const struct snd_soc_component_driver test_component_null_comp = { - static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - int ret; - - /* prepare */ -@@ -249,15 +246,17 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_comp, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component_null_comp, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -276,6 +275,7 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test) - static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - int ret; - - /* prepare */ -@@ -291,15 +291,17 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -318,8 +320,7 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test) - */ - static int d_probe_null_fw(struct snd_soc_component *component) - { -- struct kunit_soc_component *kunit_comp = -- container_of(component, struct kunit_soc_component, comp); -+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component); - int ret; - - /* instead of passing fw pointer as third argument, pass NULL here */ -@@ -338,6 +339,7 @@ static const struct snd_soc_component_driver test_component_null_fw = { - static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - int ret; - - /* prepare */ -@@ -353,15 +355,17 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_fw, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component_null_fw, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -375,6 +379,7 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test) - static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - struct tplg_tmpl_001 *data; - int size; - int ret; -@@ -401,15 +406,17 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -425,6 +432,7 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test) - static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - struct tplg_tmpl_001 *data; - int size; - int ret; -@@ -456,15 +464,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -480,6 +490,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test) - static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - struct tplg_tmpl_001 *data; - int size; - int ret; -@@ -511,15 +522,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -535,6 +548,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test) - static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - struct tplg_tmpl_001 *data; - int size; - int ret; -@@ -566,15 +580,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -590,6 +606,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test) - static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - struct tplg_tmpl_001 *data; - int size; - int ret; -@@ -622,15 +639,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - /* cleanup */ -@@ -644,6 +663,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes - static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - u8 *data; - int size; - int ret; -@@ -670,15 +690,17 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -- -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - snd_soc_unregister_component(test_dev); -@@ -693,6 +715,7 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test) - static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - u8 *data; - int size; - int ret; -@@ -720,16 +743,19 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); -+ -+ snd_soc_component_set_priv(component, kunit_comp); -+ - /* run test */ - ret = snd_soc_register_card(&kunit_comp->card); - if (ret != 0 && ret != -EPROBE_DEFER) - KUNIT_FAIL(test, "Failed to register card"); - - for (i = 0; i < 100; i++) { -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); - -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - snd_soc_unregister_component(test_dev); -@@ -745,6 +771,7 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test) - static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test) - { - struct kunit_soc_component *kunit_comp; -+ struct snd_soc_component *component; - u8 *data; - int size; - int ret; -@@ -772,11 +799,13 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test) - kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links); - kunit_comp->card.fully_routed = true; - -- /* run test */ -- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev); -- KUNIT_EXPECT_EQ(test, 0, ret); -+ component = snd_soc_component_alloc(test_dev); -+ KUNIT_ASSERT_NOT_NULL(test, component); - -- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0); -+ snd_soc_component_set_priv(component, kunit_comp); -+ -+ /* run test */ -+ ret = snd_soc_register_component(component, &test_component, NULL, 0); - KUNIT_EXPECT_EQ(test, 0, ret); - - for (i = 0; i < 100; i++) { -diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig ---- a/sound/soc/sof/amd/Kconfig -+++ b/sound/soc/sof/amd/Kconfig -@@ -104,4 +104,15 @@ config SND_SOC_SOF_AMD_ACP70 - AMD ACP7.0/ACP7.1 version based platforms. - Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms. - -+config SND_SOC_SOF_AMD_ACP7X -+ tristate "SOF support for ACP7.B/7.F platforms" -+ depends on SND_SOC_SOF_PCI -+ depends on AMD_NODE -+ select SND_SOC_SOF_AMD_COMMON -+ help -+ Select this option for SOF support on AMD ACP7.B and ACP7.F PCI -+ revision based platforms. -+ Say Y if you want to enable SOF on ACP7.B/7.F based platforms. -+ If unsure select "N". -+ - endif -diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile ---- a/sound/soc/sof/amd/Makefile -+++ b/sound/soc/sof/amd/Makefile -@@ -11,6 +11,7 @@ snd-sof-amd-rembrandt-y := pci-rmb.o rembrandt.o - snd-sof-amd-vangogh-y := pci-vangogh.o vangogh.o - snd-sof-amd-acp63-y := pci-acp63.o acp63.o - snd-sof-amd-acp70-y := pci-acp70.o acp70.o -+snd-sof-amd-acp7x-y := pci-acp7x.o acp7x.o - - obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o - obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) += snd-sof-amd-renoir.o -@@ -18,3 +19,4 @@ obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) += snd-sof-amd-rembrandt.o - obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) += snd-sof-amd-vangogh.o - obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) += snd-sof-amd-acp63.o - obj-$(CONFIG_SND_SOC_SOF_AMD_ACP70) += snd-sof-amd-acp70.o -+obj-$(CONFIG_SND_SOC_SOF_AMD_ACP7X) += snd-sof-amd-acp7x.o -diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h ---- a/sound/soc/sof/amd/acp-dsp-offset.h -+++ b/sound/soc/sof/amd/acp-dsp-offset.h -@@ -68,12 +68,14 @@ - #define ACP5X_PGFSM_BASE 0x1424 - #define ACP6X_PGFSM_BASE 0x1024 - #define ACP70_PGFSM_BASE ACP6X_PGFSM_BASE -+#define ACP7X_PGFSM_BASE ACP6X_PGFSM_BASE - #define PGFSM_CONTROL_OFFSET 0x0 - #define PGFSM_STATUS_OFFSET 0x4 - #define ACP3X_CLKMUX_SEL 0x1424 - #define ACP5X_CLKMUX_SEL 0x142C - #define ACP6X_CLKMUX_SEL 0x102C - #define ACP70_CLKMUX_SEL ACP6X_CLKMUX_SEL -+#define ACP7X_CLKMUX_SEL ACP6X_CLKMUX_SEL - - /* Registers from ACP_INTR block */ - #define ACP3X_EXT_INTR_STAT 0x1808 -@@ -86,21 +88,31 @@ - #define ACP70_EXTERNAL_INTR_CNTL ACP6X_EXTERNAL_INTR_CNTL - #define ACP70_EXT_INTR_STAT ACP6X_EXT_INTR_STAT - #define ACP70_EXT_INTR_STAT1 ACP6X_EXT_INTR_STAT1 -+#define ACP7X_EXTERNAL_INTR_ENB ACP6X_EXTERNAL_INTR_ENB -+#define ACP7X_EXTERNAL_INTR_CNTL 0x1A04 -+#define ACP7X_EXT_INTR_STAT 0x1A1C -+#define ACP7X_EXTERNAL_INTR_CNTL1 0x1A08 -+#define ACP7X_EXT_INTR_STAT1 0x1A20 - - #define ACP3X_DSP_SW_INTR_BASE 0x1814 - #define ACP5X_DSP_SW_INTR_BASE 0x1814 - #define ACP6X_DSP_SW_INTR_BASE 0x1808 - #define ACP70_DSP_SW_INTR_BASE ACP6X_DSP_SW_INTR_BASE -+#define ACP7X_DSP_SW_INTR_BASE 0x1860 - #define DSP_SW_INTR_CNTL_OFFSET 0x0 - #define DSP_SW_INTR_STAT_OFFSET 0x4 -+#define ACP7X_DSP_SW_INTR_STAT (ACP7X_DSP_SW_INTR_BASE + DSP_SW_INTR_STAT_OFFSET) - #define DSP_SW_INTR_TRIG_OFFSET 0x8 -+#define ACP7X_DSP_SW_INTR_TRIG_OFFSET 0x30 - #define ACP3X_ERROR_STATUS 0x18C4 - #define ACP6X_ERROR_STATUS 0x1A4C - #define ACP70_ERROR_STATUS ACP6X_ERROR_STATUS -+#define ACP7X_ERROR_STATUS 0x1A88 - #define ACP3X_AXI2DAGB_SEM_0 0x1880 - #define ACP5X_AXI2DAGB_SEM_0 0x1884 - #define ACP6X_AXI2DAGB_SEM_0 0x1874 - #define ACP70_AXI2DAGB_SEM_0 ACP6X_AXI2DAGB_SEM_0 -+#define ACP7X_AXI2DAGB_SEM_0 0x18F4 - - /* ACP common registers to report errors related to I2S & SoundWire interfaces */ - #define ACP3X_SW_I2S_ERROR_REASON 0x18C8 -@@ -123,6 +135,7 @@ - #define ACP_SCRATCH_REG_0 0x10000 - #define ACP6X_DSP_FUSION_RUNSTALL 0x0644 - #define ACP70_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL -+#define ACP7X_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL - - /* Cache window registers */ - #define ACP_DSP0_CACHE_OFFSET0 0x0420 -@@ -139,5 +152,9 @@ - #define ACP70_SDW1_HOST_WAKE_STAT BIT(25) - #define ACP70_SDW0_PME_STAT BIT(26) - #define ACP70_SDW1_PME_STAT BIT(27) -+#define ACP7X_DSP0_IDMA_ERROR_MASK 0x4B0 -+#define ACP7X_IDMA_ERROR_MASK 0x1FF9FF -+#define ACP7X_ZSC_DSP_CTRL 0x001014 -+#define ACP7X_PME_EN ACP70_PME_EN - - #endif -diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c ---- a/sound/soc/sof/amd/acp-ipc.c -+++ b/sound/soc/sof/amd/acp-ipc.c -@@ -32,11 +32,20 @@ static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata) - struct snd_sof_dev *sdev = adata->dev; - const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); - u32 swintr_trigger; -+ unsigned int swintr_trigger_reg_offset; - -+ switch (adata->pci_rev) { -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: -+ swintr_trigger_reg_offset = ACP7X_DSP_SW_INTR_TRIG_OFFSET; -+ break; -+ default: -+ swintr_trigger_reg_offset = DSP_SW_INTR_TRIG_OFFSET; -+ } - swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->dsp_intr_base + -- DSP_SW_INTR_TRIG_OFFSET); -+ swintr_trigger_reg_offset); - swintr_trigger |= 0x01; -- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_TRIG_OFFSET, -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + swintr_trigger_reg_offset, - swintr_trigger); - } - -diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c ---- a/sound/soc/sof/amd/acp-loader.c -+++ b/sound/soc/sof/amd/acp-loader.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - - #include "../ops.h" - #include "acp-dsp-offset.h" -@@ -173,10 +174,31 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) - - adata = sdev->pdata->hw_pdata; - -- if (adata->quirks && adata->quirks->signed_fw_image) -+ if (adata->pci_rev >= ACP7B_PCI_ID) { -+ if (adata->acp_sof_signed_firmware_image) { -+ if (adata->fw_bin_size <= ACP_IMAGE_HEADER_SIZE) { -+ dev_err(sdev->dev, "Invalid signed firmware size %u\n", -+ adata->fw_bin_size); -+ return -EINVAL; -+ } -+ size_fw = get_unaligned_le32(adata->bin_buf + -+ ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF); -+ if (!size_fw || -+ size_fw > adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE) { -+ dev_err(sdev->dev, -+ "Invalid signed firmware payload size %u (max %u)\n", -+ size_fw, adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE); -+ return -EINVAL; -+ } -+ size_fw += ACP_IMAGE_HEADER_SIZE; -+ } else { -+ size_fw = adata->fw_bin_size; -+ } -+ } else if (adata->quirks && adata->quirks->signed_fw_image) { - size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; -- else -+ } else { - size_fw = adata->fw_bin_size; -+ } - - page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT; - adata->fw_bin_page_count = page_count; -@@ -312,9 +334,14 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) - } - kfree(fw_filename); - -- ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, -- (void *)adata->fw_dbin->data, -- adata->fw_dbin->size); -+ if (adata->pci_rev >= ACP7B_PCI_ID) -+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_SRAM, 0, -+ (void *)adata->fw_dbin->data, -+ adata->fw_dbin->size); -+ else -+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, -+ (void *)adata->fw_dbin->data, -+ adata->fw_dbin->size); - return ret; - } - EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON"); -diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c ---- a/sound/soc/sof/amd/acp.c -+++ b/sound/soc/sof/amd/acp.c -@@ -12,6 +12,7 @@ - * Hardware interface for generic AMD ACP processor - */ - -+#include - #include - #include - #include -@@ -60,6 +61,8 @@ static void init_dma_descriptor(struct acp_dev_data *adata) - case ACP70_PCI_ID: - case ACP71_PCI_ID: - case ACP72_PCI_ID: -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: - acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR; - acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR; - break; -@@ -101,6 +104,8 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch, - case ACP70_PCI_ID: - case ACP71_PCI_ID: - case ACP72_PCI_ID: -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: - acp_dma_cntl_0 = ACP70_DMA_CNTL_0; - acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS; - acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0; -@@ -283,7 +288,8 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, - } - } - -- if (adata->quirks && adata->quirks->signed_fw_image) -+ if ((adata->quirks && adata->quirks->signed_fw_image) || -+ adata->acp_sof_signed_firmware_image) - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); - - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); -@@ -342,6 +348,8 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch) - case ACP70_PCI_ID: - case ACP71_PCI_ID: - case ACP72_PCI_ID: -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: - acp_dma_ch_sts = ACP70_DMA_CH_STS; - break; - default: -@@ -534,8 +542,17 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0); - /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */ -- if (adata->pci_rev >= ACP_RMB_PCI_ID) -+ switch (adata->pci_rev) { -+ case ACP_RMB_PCI_ID: -+ case ACP63_PCI_ID: -+ case ACP70_PCI_ID: -+ case ACP71_PCI_ID: -+ case ACP72_PCI_ID: - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0); -+ break; -+ default: -+ break; -+ } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); - irq_flag = 1; - } -@@ -564,6 +581,35 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) - return IRQ_NONE; - } - -+static irqreturn_t acp7x_irq_handler(int irq, void *dev_id) -+{ -+ struct snd_sof_dev *sdev = dev_id; -+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); -+ unsigned int base = desc->dsp_intr_base; -+ unsigned int val; -+ unsigned int ext_intr_stat; -+ int irq_flag = 0; -+ -+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); -+ if (val & ACP_DSP_TO_HOST_IRQ) { -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, -+ ACP_DSP_TO_HOST_IRQ); -+ return IRQ_WAKE_THREAD; -+ } -+ -+ ext_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); -+ if (ext_intr_stat & ACP_ERROR_IRQ_MASK) { -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); -+ irq_flag = 1; -+ } -+ -+ if (irq_flag) -+ return IRQ_HANDLED; -+ -+ return IRQ_NONE; -+} -+ - static int acp_power_on(struct snd_sof_dev *sdev) - { - const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); -@@ -571,6 +617,7 @@ static int acp_power_on(struct snd_sof_dev *sdev) - unsigned int base = desc->pgfsm_base; - unsigned int val; - unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask; -+ bool use_masked_status = false; - int ret; - - val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET); -@@ -595,6 +642,12 @@ static int acp_power_on(struct snd_sof_dev *sdev) - acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK; - acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK; - break; -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: -+ acp_pgfsm_status_mask = ACP7X_PGFSM_STATUS_MASK; -+ acp_pgfsm_cntl_mask = ACP7X_PGFSM_CNTL_POWER_ON_MASK; -+ use_masked_status = true; -+ break; - default: - return -EINVAL; - } -@@ -603,8 +656,17 @@ static int acp_power_on(struct snd_sof_dev *sdev) - snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET, - acp_pgfsm_cntl_mask); - -- ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val, -- !val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US); -+ if (use_masked_status) -+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, -+ base + PGFSM_STATUS_OFFSET, val, -+ !(val & acp_pgfsm_status_mask), -+ ACP_REG_POLL_INTERVAL, -+ ACP_REG_POLL_TIMEOUT_US); -+ else -+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, -+ base + PGFSM_STATUS_OFFSET, val, -+ !val, ACP_REG_POLL_INTERVAL, -+ ACP_REG_POLL_TIMEOUT_US); - if (ret < 0) - dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n"); - -@@ -703,6 +765,13 @@ static int acp_init(struct snd_sof_dev *sdev) - - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1); - break; -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0); -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_DSP0_IDMA_ERROR_MASK, -+ ACP7X_IDMA_ERROR_MASK); -+ break; - } - return 0; - } -@@ -749,6 +818,8 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) - case ACP72_PCI_ID: - enable = true; - break; -+ default: -+ break; - } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); - -@@ -990,6 +1061,194 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev) - } - EXPORT_SYMBOL_NS(amd_sof_acp_remove, "SND_SOC_SOF_AMD_COMMON"); - -+int amd_sof_acp7x_probe(struct snd_sof_dev *sdev) -+{ -+ struct pci_dev *pci = to_pci_dev(sdev->dev); -+ struct acp_dev_data *adata; -+ const struct sof_amd_acp_desc *chip; -+ const union acpi_object *obj; -+ struct acpi_device *adev; -+ unsigned int addr; -+ unsigned int irqflags; -+ int ret; -+ -+ chip = get_chip_info(sdev->pdata); -+ if (!chip) { -+ dev_err(sdev->dev, "no such device supported, chip id:%x\n", pci->device); -+ return -EIO; -+ } -+ adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), GFP_KERNEL); -+ if (!adata) -+ return -ENOMEM; -+ -+ adata->dev = sdev; -+ adata->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec", -+ PLATFORM_DEVID_NONE, NULL, 0); -+ if (IS_ERR(adata->dmic_dev)) { -+ dev_err(sdev->dev, "failed to register platform for dmic codec\n"); -+ return PTR_ERR(adata->dmic_dev); -+ } -+ -+ addr = pci_resource_start(pci, ACP_DSP_BAR); -+ sdev->bar[ACP_DSP_BAR] = devm_ioremap(sdev->dev, addr, pci_resource_len(pci, ACP_DSP_BAR)); -+ if (!sdev->bar[ACP_DSP_BAR]) { -+ dev_err(sdev->dev, "ioremap error\n"); -+ ret = -ENXIO; -+ goto unregister_dev; -+ } -+ -+ pci_set_master(pci); -+ adata->addr = addr; -+ adata->reg_range = chip->reg_end_addr - chip->reg_start_addr; -+ adata->pci_rev = pci->revision; -+ mutex_init(&adata->acp_lock); -+ sdev->pdata->hw_pdata = adata; -+ -+ ret = acp_init(sdev); -+ if (ret < 0) -+ goto unregister_dev; -+ -+ adev = ACPI_COMPANION(&pci->dev); -+ -+ sdev->ipc_irq = pci->irq; -+ irqflags = IRQF_SHARED; -+ -+ ret = request_threaded_irq(pci->irq, acp7x_irq_handler, acp_irq_thread, -+ irqflags, "AudioDSP", sdev); -+ if (ret < 0) { -+ dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq); -+ goto unregister_dev; -+ } -+ -+ if (adev) { -+ if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image", -+ ACPI_TYPE_INTEGER, &obj)) -+ adata->acp_sof_signed_firmware_image = obj->integer.value; -+ } -+ -+ sdev->dsp_box.offset = 0; -+ sdev->dsp_box.size = BOX_SIZE_512; -+ -+ sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size; -+ sdev->host_box.size = BOX_SIZE_512; -+ -+ sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; -+ sdev->debug_box.size = BOX_SIZE_1024; -+ -+ if (adata->acp_sof_signed_firmware_image) { -+ adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, -+ "sof-%s-code.bin", chip->name); -+ if (!adata->fw_code_bin) { -+ ret = -ENOMEM; -+ goto free_ipc_irq; -+ } -+ adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, -+ "sof-%s-data.bin", chip->name); -+ if (!adata->fw_data_bin) { -+ ret = -ENOMEM; -+ goto free_ipc_irq; -+ } -+ } -+ -+ adata->enable_fw_debug = enable_fw_debug; -+ acp_memory_init(sdev); -+ acp_dsp_stream_init(sdev); -+ -+ return 0; -+ -+free_ipc_irq: -+ free_irq(sdev->ipc_irq, sdev); -+unregister_dev: -+ platform_device_unregister(adata->dmic_dev); -+ return ret; -+} -+EXPORT_SYMBOL_NS(amd_sof_acp7x_probe, "SND_SOC_SOF_AMD_COMMON"); -+ -+void amd_sof_acp7x_remove(struct snd_sof_dev *sdev) -+{ -+ struct acp_dev_data *adata = sdev->pdata->hw_pdata; -+ -+ if (sdev->ipc_irq) -+ free_irq(sdev->ipc_irq, sdev); -+ -+ if (adata->dmic_dev) -+ platform_device_unregister(adata->dmic_dev); -+ -+ acp_reset(sdev); -+} -+EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON"); -+ -+int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) -+{ -+ struct acp_dev_data *acp_data; -+ int ret; -+ bool enable = false; -+ -+ acp_data = sdev->pdata->hw_pdata; -+ -+ ret = acp_reset(sdev); -+ if (ret) { -+ dev_err(sdev->dev, "ACP Reset failed\n"); -+ return ret; -+ } -+ switch (acp_data->pci_rev) { -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: -+ enable = true; -+ break; -+ default: -+ break; -+ } -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1); -+ -+ return 0; -+} -+EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend, "SND_SOC_SOF_AMD_COMMON"); -+ -+int amd_sof_acp7x_resume(struct snd_sof_dev *sdev) -+{ -+ struct acp_dev_data *acp_data; -+ int ret; -+ -+ acp_data = sdev->pdata->hw_pdata; -+ -+ ret = acp_init(sdev); -+ if (ret) { -+ dev_err(sdev->dev, "ACP Init failed\n"); -+ return ret; -+ } -+ ret = acp_memory_init(sdev); -+ if (ret) { -+ dev_err(sdev->dev, "ACP Memory init failed\n"); -+ return ret; -+ } -+ -+ switch (acp_data->pci_rev) { -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: -+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1); -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON"); -+ -+int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev) -+{ -+ return amd_sof_acp7x_suspend(sdev, 0); -+} -+EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON"); -+ -+int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev) -+{ -+ return amd_sof_acp7x_resume(sdev); -+} -+EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON"); -+ - MODULE_LICENSE("Dual BSD/GPL"); - MODULE_DESCRIPTION("AMD ACP sof driver"); - MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); -diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h ---- a/sound/soc/sof/amd/acp.h -+++ b/sound/soc/sof/amd/acp.h -@@ -76,6 +76,12 @@ - #define ACP70_PCI_ID 0x70 - #define ACP71_PCI_ID 0x71 - #define ACP72_PCI_ID 0x72 -+#define ACP7B_PCI_ID 0x7B -+#define ACP7F_PCI_ID 0x7F -+ -+#define ACP7X_PGFSM_CNTL_POWER_ON_MASK 0x7F -+#define ACP7X_PGFSM_STATUS_MASK 0xFFF -+#define ACP7X_SRAM_PTE_OFFSET ACP6X_SRAM_PTE_OFFSET - - #define HOST_BRIDGE_CZN 0x1630 - #define HOST_BRIDGE_VGH 0x1645 -@@ -107,6 +113,9 @@ - #define PROBE_STATUS_BIT BIT(31) - - #define ACP_FIRMWARE_SIGNATURE 0x100 -+#define ACP_IMAGE_HEADER_SIZE ACP_FIRMWARE_SIGNATURE -+#define ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF 0x14 -+ - #define ACP_ERROR_IRQ_MASK BIT(29) - #define ACP_SDW0_IRQ_MASK BIT(21) - #define ACP_SDW1_IRQ_MASK BIT(2) -@@ -271,6 +280,7 @@ struct acp_dev_data { - /* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */ - bool acp70_sdw1_wake_event; - unsigned int pci_rev; -+ int acp_sof_signed_firmware_image; - }; - - void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes); -@@ -344,6 +354,16 @@ int sof_acp63_ops_init(struct snd_sof_dev *sdev); - extern struct snd_sof_dsp_ops sof_acp70_ops; - int sof_acp70_ops_init(struct snd_sof_dev *sdev); - -+extern struct snd_sof_dsp_ops sof_acp7x_ops; -+int sof_acp7x_ops_init(struct snd_sof_dev *sdev); -+ -+int amd_sof_acp7x_probe(struct snd_sof_dev *sdev); -+void amd_sof_acp7x_remove(struct snd_sof_dev *sdev); -+int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state); -+int amd_sof_acp7x_resume(struct snd_sof_dev *sdev); -+int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev); -+int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev); -+ - struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev); - /* Machine configuration */ - int snd_amd_acp_find_config(struct pci_dev *pci); -diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/sof/amd/acp7x.c -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -+// -+// This file is provided under a dual BSD/GPLv2 license. When using or -+// redistributing this file, you may do so under either license. -+// -+// Copyright(c) 2025 Advanced Micro Devices, Inc. -+// -+// Authors: Vijendar Mukunda -+ -+/* -+ * Hardware interface for Audio DSP on ACP7.B/7.F platforms -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "../ops.h" -+#include "../sof-audio.h" -+#include "acp.h" -+#include "acp-dsp-offset.h" -+ -+#define I2S_TDM0_INSTANCE 0 -+#define I2S_TDM1_INSTANCE 1 -+#define I2S_TDM2_INSTANCE 2 -+#define PDM0_DMIC_INSTANCE 3 -+#define PDM1_DMIC_INSTANCE 4 -+ -+static struct snd_soc_dai_driver acp7x_sof_dai[] = { -+ [I2S_TDM0_INSTANCE] = { -+ .id = I2S_TDM0_INSTANCE, -+ .name = "acp-sof-i2s0", -+ .playback = { -+ .rates = SNDRV_PCM_RATE_8000_96000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | -+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, -+ .channels_min = 2, -+ .channels_max = 8, -+ .rate_min = 8000, -+ .rate_max = 96000, -+ }, -+ .capture = { -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | -+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, -+ /* Supporting only stereo for I2S HS controller capture */ -+ .channels_min = 2, -+ .channels_max = 2, -+ .rate_min = 8000, -+ .rate_max = 48000, -+ }, -+ }, -+ -+ [I2S_TDM1_INSTANCE] = { -+ .id = I2S_TDM1_INSTANCE, -+ .name = "acp-sof-i2s1", -+ .playback = { -+ .rates = SNDRV_PCM_RATE_8000_96000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | -+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, -+ .channels_min = 2, -+ .channels_max = 8, -+ .rate_min = 8000, -+ .rate_max = 96000, -+ }, -+ .capture = { -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | -+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, -+ /* Supporting only stereo for I2S BT controller capture */ -+ .channels_min = 2, -+ .channels_max = 2, -+ .rate_min = 8000, -+ .rate_max = 48000, -+ }, -+ }, -+ -+ [I2S_TDM2_INSTANCE] = { -+ .id = I2S_TDM2_INSTANCE, -+ .name = "acp-sof-i2s2", -+ .playback = { -+ .rates = SNDRV_PCM_RATE_8000_96000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | -+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, -+ .channels_min = 2, -+ .channels_max = 8, -+ .rate_min = 8000, -+ .rate_max = 96000, -+ }, -+ .capture = { -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | -+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, -+ /* Supporting only stereo for I2S SP controller capture */ -+ .channels_min = 2, -+ .channels_max = 2, -+ .rate_min = 8000, -+ .rate_max = 48000, -+ }, -+ }, -+ -+ [PDM0_DMIC_INSTANCE] = { -+ .id = PDM0_DMIC_INSTANCE, -+ .name = "acp-sof-dmic0", -+ .capture = { -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .formats = SNDRV_PCM_FMTBIT_S32_LE, -+ .channels_min = 2, -+ .channels_max = 4, -+ .rate_min = 8000, -+ .rate_max = 48000, -+ }, -+ }, -+ -+ [PDM1_DMIC_INSTANCE] = { -+ .id = PDM1_DMIC_INSTANCE, -+ .name = "acp-sof-dmic1", -+ .capture = { -+ .rates = SNDRV_PCM_RATE_8000_96000, -+ .formats = SNDRV_PCM_FMTBIT_S32_LE, -+ .channels_min = 2, -+ .channels_max = 4, -+ .rate_min = 8000, -+ .rate_max = 96000, -+ }, -+ }, -+}; -+ -+static int sof_acp7x_post_fw_run_delay(struct snd_sof_dev *sdev) -+{ -+ /* -+ * Resuming from suspend in some cases may cause the DSP firmware -+ * to enter an unrecoverable faulty state. Delaying a bit any host -+ * to DSP transmission right after firmware boot completion seems -+ * to resolve the issue. -+ */ -+ if (!sdev->first_boot) -+ usleep_range(100, 150); -+ -+ return 0; -+} -+ -+struct snd_sof_dsp_ops sof_acp7x_ops; -+EXPORT_SYMBOL_NS(sof_acp7x_ops, "SND_SOC_SOF_AMD_COMMON"); -+ -+int sof_acp7x_ops_init(struct snd_sof_dev *sdev) -+{ -+ struct acpi_device *adev = ACPI_COMPANION(&to_pci_dev(sdev->dev)->dev); -+ const union acpi_object *obj; -+ int acp_sof_signed_firmware_image = 0; -+ int acp_sof_post_fw_run_delay = 0; -+ -+ /* common defaults */ -+ memcpy(&sof_acp7x_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); -+ -+ sof_acp7x_ops.drv = acp7x_sof_dai; -+ sof_acp7x_ops.num_drv = ARRAY_SIZE(acp7x_sof_dai); -+ sof_acp7x_ops.probe = amd_sof_acp7x_probe; -+ sof_acp7x_ops.remove = amd_sof_acp7x_remove; -+ -+ if (adev) { -+ if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image", -+ ACPI_TYPE_INTEGER, &obj)) -+ acp_sof_signed_firmware_image = obj->integer.value; -+ -+ if (!acpi_dev_get_property(adev, "acp-sof-post_fw_run_delay", -+ ACPI_TYPE_INTEGER, &obj)) -+ acp_sof_post_fw_run_delay = obj->integer.value; -+ } -+ -+ if (acp_sof_signed_firmware_image) -+ sof_acp7x_ops.load_firmware = acp_sof_load_signed_firmware; -+ -+ if (acp_sof_post_fw_run_delay) -+ sof_acp7x_ops.post_fw_run = sof_acp7x_post_fw_run_delay; -+ -+ sof_acp7x_ops.suspend = amd_sof_acp7x_suspend; -+ sof_acp7x_ops.resume = amd_sof_acp7x_resume; -+ sof_acp7x_ops.runtime_suspend = amd_sof_acp7x_suspend_runtime; -+ sof_acp7x_ops.runtime_resume = amd_sof_acp7x_resume_runtime; -+ -+ return 0; -+} -diff --git a/sound/soc/sof/amd/pci-acp7x.c b/sound/soc/sof/amd/pci-acp7x.c -new file mode 100644 ---- /dev/null -+++ b/sound/soc/sof/amd/pci-acp7x.c -@@ -0,0 +1,116 @@ -+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -+// -+// This file is provided under a dual BSD/GPLv2 license. When using or -+// redistributing this file, you may do so under either license. -+// -+// Copyright(c) 2025 Advanced Micro Devices, Inc. All rights reserved. -+// -+// Authors: Vijendar Mukunda -+ -+/* -+ * PCI interface for ACP7.B/7.F devices -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "../ops.h" -+#include "../sof-pci-dev.h" -+#include "../../amd/mach-config.h" -+#include "acp.h" -+#include "acp-dsp-offset.h" -+ -+#define ACP7X_FUTURE_REG_ACLK_0 0x18e0 -+#define ACP7X_REG_START 0x1240000 -+#define ACP7X_REG_END 0x125C000 -+ -+static const struct sof_amd_acp_desc acp7x_chip_info = { -+ .name = "acp7x", -+ .pgfsm_base = ACP7X_PGFSM_BASE, -+ .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB, -+ .ext_intr_cntl = ACP7X_EXTERNAL_INTR_CNTL, -+ .ext_intr_stat = ACP7X_EXT_INTR_STAT, -+ .ext_intr_stat1 = ACP7X_EXT_INTR_STAT1, -+ .dsp_intr_base = ACP7X_DSP_SW_INTR_BASE, -+ .acp_error_stat = ACP7X_ERROR_STATUS, -+ .sram_pte_offset = ACP7X_SRAM_PTE_OFFSET, -+ .hw_semaphore_offset = ACP7X_AXI2DAGB_SEM_0, -+ .fusion_dsp_offset = ACP7X_DSP_FUSION_RUNSTALL, -+ .probe_reg_offset = ACP7X_FUTURE_REG_ACLK_0, -+ .reg_start_addr = ACP7X_REG_START, -+ .reg_end_addr = ACP7X_REG_END, -+}; -+ -+static const struct sof_dev_desc acp7x_desc = { -+ .machines = snd_soc_acpi_amd_acp7x_sof_machines, -+ .resindex_lpe_base = 0, -+ .resindex_pcicfg_base = -1, -+ .resindex_imr_base = -1, -+ .irqindex_host_ipc = -1, -+ .chip_info = &acp7x_chip_info, -+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), -+ .ipc_default = SOF_IPC_TYPE_3, -+ .default_fw_path = { -+ [SOF_IPC_TYPE_3] = "amd/sof", -+ }, -+ .default_tplg_path = { -+ [SOF_IPC_TYPE_3] = "amd/sof-tplg", -+ }, -+ .default_fw_filename = { -+ [SOF_IPC_TYPE_3] = "sof-acp7x.ri", -+ }, -+ .nocodec_tplg_filename = "sof-acp.tplg", -+ .ops = &sof_acp7x_ops, -+ .ops_init = sof_acp7x_ops_init, -+}; -+ -+static int acp7x_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) -+{ -+ unsigned int flag; -+ -+ switch (pci->revision) { -+ case ACP7B_PCI_ID: -+ case ACP7F_PCI_ID: -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ flag = snd_amd_acp_find_config(pci); -+ if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC) -+ return -ENODEV; -+ -+ return sof_pci_probe(pci, pci_id); -+} -+ -+static void acp7x_pci_remove(struct pci_dev *pci) -+{ -+ sof_pci_remove(pci); -+} -+ -+/* PCI IDs */ -+static const struct pci_device_id acp7x_pci_ids[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID), -+ .driver_data = (unsigned long)&acp7x_desc}, -+ { 0, } -+}; -+MODULE_DEVICE_TABLE(pci, acp7x_pci_ids); -+ -+/* pci_driver definition */ -+static struct pci_driver snd_sof_pci_amd_acp7x_driver = { -+ .name = KBUILD_MODNAME, -+ .id_table = acp7x_pci_ids, -+ .probe = acp7x_pci_probe, -+ .remove = acp7x_pci_remove, -+ .driver = { -+ .pm = pm_ptr(&sof_pci_pm), -+ }, -+}; -+module_pci_driver(snd_sof_pci_amd_acp7x_driver); -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_DESCRIPTION("ACP7X SOF Driver"); -+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); -+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); -diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c ---- a/sound/soc/sof/fw-file-profile.c -+++ b/sound/soc/sof/fw-file-profile.c -@@ -16,20 +16,19 @@ static int sof_test_firmware_file(struct device *dev, - enum sof_ipc_type *ipc_type_to_adjust) - { - enum sof_ipc_type fw_ipc_type; -- const struct firmware *fw; -- const char *fw_filename; - const u32 *magic; - int ret; - -- fw_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path, -- profile->fw_name); -+ const char *fw_filename __free(kfree) = -+ kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path, -+ profile->fw_name); - if (!fw_filename) - return -ENOMEM; - -+ const struct firmware *fw __free(firmware) = NULL; - ret = firmware_request_nowarn(&fw, fw_filename, dev); - if (ret < 0) { - dev_dbg(dev, "Failed to open firmware file: %s\n", fw_filename); -- kfree(fw_filename); - return ret; - } - -@@ -44,8 +43,7 @@ static int sof_test_firmware_file(struct device *dev, - break; - default: - dev_err(dev, "Invalid firmware magic: %#x\n", *magic); -- ret = -EINVAL; -- goto out; -+ return -EINVAL; - } - - if (ipc_type_to_adjust) { -@@ -54,13 +52,10 @@ static int sof_test_firmware_file(struct device *dev, - dev_err(dev, - "ipc type mismatch between %s and expected: %d vs %d\n", - fw_filename, fw_ipc_type, profile->ipc_type); -- ret = -EINVAL; -+ return -EINVAL; - } --out: -- release_firmware(fw); -- kfree(fw_filename); - -- return ret; -+ return 0; - } - - static int sof_test_topology_file(struct device *dev, -diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c ---- a/sound/soc/sof/intel/hda-ctrl.c -+++ b/sound/soc/sof/intel/hda-ctrl.c -@@ -186,6 +186,7 @@ EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON" - int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) - { - struct hdac_bus *bus = sof_to_bus(sdev); -+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); - struct hdac_stream *stream; - int sd_offset, ret = 0; - u32 gctl; -@@ -193,6 +194,16 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) - if (bus->chip_init) - return 0; - -+ /* -+ * The controller reset clears the ACE2+ link DMA stream allocation -+ * constraints; reset the masks to reflect this. -+ */ -+ memset(sof_hda->link_dma_active_sdw_mask, 0, -+ sizeof(sof_hda->link_dma_active_sdw_mask)); -+ memset(sof_hda->link_dma_active_multi_mask, 0, -+ sizeof(sof_hda->link_dma_active_multi_mask)); -+ sof_hda->link_dma_out_hda_used_mask = 0; -+ - hda_codec_set_codec_wakeup(sdev, true); - - hda_dsp_ctrl_misc_clock_gating(sdev, false); -@@ -223,6 +234,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec) - /* Accept unsolicited responses */ - snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); - -+ /* Perform a one-time enumeration of the Multi-Link capability */ -+ ret = hda_bus_ml_init(bus); -+ if (ret < 0) { -+ dev_err(sdev->dev, "%s: failed to enumerate multi-links\n", -+ __func__); -+ goto err; -+ } -+ - if (detect_codec) - hda_codec_detect_mask(sdev); - -diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c ---- a/sound/soc/sof/intel/hda-dai-ops.c -+++ b/sound/soc/sof/intel/hda-dai-ops.c -@@ -20,7 +20,7 @@ - /* These ops are only applicable for the HDA DAI's in their current form */ - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) - /* -- * This function checks if the host dma channel corresponding -+ * This function checks if the host DMA stream corresponding - * to the link DMA stream_tag argument is assigned to one - * of the FEs connected to the BE DAI. - */ -@@ -42,23 +42,53 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, - } - - static struct hdac_ext_stream * --hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) -+hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream, -+ enum hda_bus_ml_link_type link_type) - { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); - struct sof_intel_hda_stream *hda_stream; - const struct sof_intel_dsp_desc *chip; - struct snd_sof_dev *sdev; - struct hdac_ext_stream *res = NULL; - struct hdac_stream *hstream = NULL; -- - int stream_dir = substream->stream; -+ bool is_multi = link_type == HDA_BUS_ML_LINK_HDA || link_type == HDA_BUS_ML_LINK_UAOL; -+ bool is_play = stream_dir == SNDRV_PCM_STREAM_PLAYBACK; -+ bool is_sdw = link_type == HDA_BUS_ML_LINK_SDW; -+ bool is_hda = link_type == HDA_BUS_ML_LINK_HDA; -+ u32 concur_block_mask = 0; -+ u32 seq_block_mask = 0; -+ unsigned int stream_idx; - - if (!bus->ppcap) { - dev_err(bus->dev, "stream type not supported\n"); - return NULL; - } - -+ /* -+ * On ACE2+ the link DMA stream allocator must avoid two HW errata, -+ * see the comment on struct sof_intel_hda_dev. -+ * -+ * - Concurrent cross-direction: SoundWire conflicts with HDA, iDisp -+ * and UAOL on the same physical stream index; SSP and DMIC are safe. -+ * - Sequential playback: a stream index previously used by an HDA/iDisp -+ * link cannot drive any non-HDA/iDisp link in the same direction -+ * until the next controller reset. -+ * -+ * The masks are protected by bus->reg_lock; sample them inside the -+ * lock together with the stream walk to keep the decision atomic -+ * with concurrent allocations and releases. -+ */ - guard(spinlock_irq)(&bus->reg_lock); -+ -+ if (is_sdw) -+ concur_block_mask = sof_hda->link_dma_active_multi_mask[!stream_dir]; -+ else if (is_multi) -+ concur_block_mask = sof_hda->link_dma_active_sdw_mask[!stream_dir]; -+ if (is_play && !is_hda) -+ seq_block_mask = sof_hda->link_dma_out_hda_used_mask; -+ - list_for_each_entry(hstream, &bus->stream_list, list) { - struct hdac_ext_stream *hext_stream = - stream_to_hdac_ext_stream(hstream); -@@ -69,6 +99,12 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream - sdev = hda_stream->sdev; - chip = get_chip_info(sdev->pdata); - -+ stream_idx = hstream->stream_tag - 1; -+ -+ /* skip streams blocked by the ACE2+ allocator constraints */ -+ if ((concur_block_mask | seq_block_mask) & BIT(stream_idx)) -+ continue; -+ - /* check if link is available */ - if (!hext_stream->link_locked) { - /* -@@ -95,7 +131,7 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream - - /* - * This must be a hostless stream. -- * So reserve the host DMA channel. -+ * So reserve the host DMA stream. - */ - hda_stream->host_reserved = 1; - break; -@@ -109,6 +145,16 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream - - res->link_locked = 1; - res->link_substream = substream; -+ -+ stream_idx = res->hstream.stream_tag - 1; -+ if (is_sdw) -+ sof_hda->link_dma_active_sdw_mask[stream_dir] |= BIT(stream_idx); -+ else if (is_multi) -+ sof_hda->link_dma_active_multi_mask[stream_dir] |= BIT(stream_idx); -+ -+ /* persistent OUT HDA/iDisp shadow, cleared only on CRST# */ -+ if (is_hda && is_play) -+ sof_hda->link_dma_out_hda_used_mask |= BIT(stream_idx); - } - - return res; -@@ -143,11 +189,13 @@ static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev - - static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev, - struct snd_soc_dai *cpu_dai, -- struct snd_pcm_substream *substream) -+ struct snd_pcm_substream *substream, -+ struct hdac_ext_link *hlink) - { - struct hdac_ext_stream *hext_stream; -+ enum hda_bus_ml_link_type link_type = hda_bus_ml_link_get_type(hlink); - -- hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream); -+ hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream, link_type); - if (!hext_stream) - return NULL; - -@@ -160,6 +208,22 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai - struct snd_pcm_substream *substream) - { - struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream); -+ struct sof_intel_hda_dev *sof_hda = sdev->pdata->hw_pdata; -+ struct hdac_bus *bus = sof_to_bus(sdev); -+ int dir = substream->stream; -+ unsigned int stream_idx = hext_stream->hstream.stream_tag - 1; -+ -+ /* -+ * Drop the stream index from the per-direction active concurrency masks. -+ * The two masks are mutually exclusive for a given stream/direction -+ * (and a stream of the SSP/DMIC kind appears in neither), so a blind -+ * clear of both is safe and lets us avoid having to remember the -+ * link type at allocation time. -+ */ -+ scoped_guard(spinlock_irq, &bus->reg_lock) { -+ sof_hda->link_dma_active_sdw_mask[dir] &= ~BIT(stream_idx); -+ sof_hda->link_dma_active_multi_mask[dir] &= ~BIT(stream_idx); -+ } - - snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); - snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK); -diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c ---- a/sound/soc/sof/intel/hda-dai.c -+++ b/sound/soc/sof/intel/hda-dai.c -@@ -188,7 +188,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, - - if (!hext_stream) { - if (ops->assign_hext_stream) -- hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream); -+ hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream, hlink); - } - - if (!hext_stream) -diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c ---- a/sound/soc/sof/intel/hda-dsp.c -+++ b/sound/soc/sof/intel/hda-dsp.c -@@ -1114,11 +1114,7 @@ static int hda_dsp_s5_quirk(struct snd_sof_dev *sdev) - usleep_range(500, 1000); - - /* Restore state for shutdown, back to reset */ -- ret = hda_dsp_ctrl_link_reset(sdev, true); -- if (ret < 0) -- return ret; -- -- return ret; -+ return hda_dsp_ctrl_link_reset(sdev, true); - } - - int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev) -diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c ---- a/sound/soc/sof/intel/hda-loader.c -+++ b/sound/soc/sof/intel/hda-loader.c -@@ -216,9 +216,10 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int - EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); - - int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, -- bool persistent_buffer, struct hdac_ext_stream *hext_stream) -+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax) - { -- return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, false); -+ return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, -+ is_iccmax, false); - } - EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON"); - -@@ -302,7 +303,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) - * If the cleanup also fails, we return the initial error - */ - ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab, -- persistent_cl_buffer, iccmax_stream); -+ persistent_cl_buffer, iccmax_stream, true); - if (ret1 < 0) { - dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); - -@@ -458,7 +459,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) - * If the cleanup also fails, we return the initial error - */ - ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, -- persistent_cl_buffer, hext_stream); -+ persistent_cl_buffer, hext_stream, false); - if (ret1 < 0) { - dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); - -@@ -587,7 +588,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, - cleanup: - /* clean up even in case of error and return the first error */ - ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer, -- hext_stream); -+ hext_stream, false); - if (ret1 < 0) { - dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__); - -diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c ---- a/sound/soc/sof/intel/hda-mlink.c -+++ b/sound/soc/sof/intel/hda-mlink.c -@@ -432,6 +432,10 @@ int hda_bus_ml_init(struct hdac_bus *bus) - if (!bus->mlcap) - return 0; - -+ /* Enumeration is a one time operation, skip if already done */ -+ if (!list_empty(&bus->hlink_list)) -+ return 0; -+ - link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; - - dev_dbg(bus->dev, "HDAudio Multi-Link count: %d\n", link_count); -@@ -880,19 +884,6 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, - return 0; - } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK"); - --void hda_bus_ml_put_all(struct hdac_bus *bus) --{ -- struct hdac_ext_link *hlink; -- -- list_for_each_entry(hlink, &bus->hlink_list, list) { -- struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink); -- -- if (!h2link->alt) -- snd_hdac_ext_bus_link_put(bus, hlink); -- } --} --EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK"); -- - void hda_bus_ml_reset_losidv(struct hdac_bus *bus) - { - struct hdac_ext_link *hlink; -@@ -903,6 +894,24 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus) - } - EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK"); - -+enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) -+{ -+ struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink); -+ -+ if (!h2link->alt) -+ return HDA_BUS_ML_LINK_HDA; -+ -+ switch (h2link->elid) { -+ case AZX_REG_ML_LEPTR_ID_SDW: -+ return HDA_BUS_ML_LINK_SDW; -+ case AZX_REG_ML_LEPTR_ID_INTEL_UAOL: -+ return HDA_BUS_ML_LINK_UAOL; -+ default: -+ return HDA_BUS_ML_LINK_OTHER; -+ } -+} -+EXPORT_SYMBOL_NS(hda_bus_ml_link_get_type, "SND_SOC_SOF_HDA_MLINK"); -+ - int hda_bus_ml_resume(struct hdac_bus *bus) - { - struct hdac_ext_link *hlink; -diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c ---- a/sound/soc/sof/intel/hda-sdw-bpt.c -+++ b/sound/soc/sof/intel/hda-sdw-bpt.c -@@ -163,7 +163,7 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream - u32 mask; - int ret; - -- ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, true); -+ ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, false, true); - if (ret < 0) { - dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n", - __func__); -diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c ---- a/sound/soc/sof/intel/hda-stream.c -+++ b/sound/soc/sof/intel/hda-stream.c -@@ -198,13 +198,18 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, - - mask = (1 << hstream->index); - -+ /* Reset the spib_addr before disabling SPIB */ -+ if (!enable) -+ sof_io_write(sdev, hstream->spib_addr, 0); -+ - /* enable/disable SPIB for the stream */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR, - SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask, - enable << hstream->index); - - /* set the SPIB value */ -- sof_io_write(sdev, hstream->spib_addr, size); -+ if (enable) -+ sof_io_write(sdev, hstream->spib_addr, size); - - return 0; - } -@@ -608,6 +613,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, - return ret; - } - -+ /* Host DMA is not running */ -+ hstream->running = false; -+ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + SOF_HDA_ADSP_REG_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, -@@ -1323,16 +1331,18 @@ hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int si - EXPORT_SYMBOL_NS(hda_data_stream_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON"); - - int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab, -- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair) -+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, -+ bool is_iccmax, bool pair) - { - struct snd_sof_dev *sdev = dev_get_drvdata(dev); - struct hdac_stream *hstream = hdac_stream(hext_stream); - int sd_offset = SOF_STREAM_SD_OFFSET(hstream); - int ret = 0; - -- if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) -+ if (!is_iccmax) - ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0); -- else -+ -+ if (hstream->direction == SNDRV_PCM_STREAM_CAPTURE) - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, - SOF_HDA_SD_CTL_DMA_START, 0); - -diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c ---- a/sound/soc/sof/intel/hda.c -+++ b/sound/soc/sof/intel/hda.c -@@ -421,6 +421,20 @@ static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { } - /* pre fw run operations */ - int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) - { -+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; -+ const struct sof_intel_dsp_desc *chip = hda->desc; -+ int ret; -+ -+ /* Power down DSP if left enabled to ensure a clean boot state. */ -+ if (hda_dsp_core_is_enabled(sdev, chip->host_managed_cores_mask)) { -+ dev_dbg(sdev->dev, "DSP core enabled, power down DSP first\n"); -+ -+ ret = chip->power_down_dsp(sdev); -+ if (ret < 0) -+ dev_warn(sdev->dev, -+ "%s: failed to power down already-enabled DSP\n", __func__); -+ } -+ - /* disable clock gating and power gating */ - return hda_dsp_ctrl_clock_power_gating(sdev, false); - } -@@ -625,8 +639,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) - return ret; - } - -- hda_bus_ml_init(bus); -- - /* Skip SoundWire if it is not supported */ - if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH))) - goto skip_soundwire; -@@ -670,8 +682,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) - if (!HDA_IDISP_CODEC(bus->codec_mask)) - hda_codec_i915_display_power(sdev, false); - -- hda_bus_ml_put_all(bus); -- - return 0; - } - -diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h ---- a/sound/soc/sof/intel/hda.h -+++ b/sound/soc/sof/intel/hda.h -@@ -523,6 +523,29 @@ struct sof_intel_hda_dev { - /* the maximum number of streams (playback + capture) supported */ - u32 stream_max; - -+ /* -+ * ACE2+ link DMA stream allocation constraints (stream index = -+ * stream_tag - 1, shared between input and output directions). All -+ * masks are cleared by hda_dsp_ctrl_init_chip() on controller reset -+ * (CRST#). -+ * -+ * - Concurrent (cross-direction) constraint: a SoundWire stream and -+ * a HDA/iDisp/UAOL stream cannot share a physical stream index -+ * across directions, the resulting LLP/timestamp values are wrong. -+ * link_dma_active_sdw_mask and link_dma_active_multi_mask -+ * (indexed by SNDRV_PCM_STREAM_*) track currently allocated -+ * streams per direction in each of the conflicting groups; SSP -+ * and DMIC do not participate. Bits are cleared on stream release. -+ * -+ * - Sequential (playback only) constraint: once a HDA/iDisp link -+ * has used a playback stream index, that index cannot drive a -+ * non-HDA/iDisp link in the same direction until the next CRST#. -+ * link_dma_out_hda_used_mask records this. -+ */ -+ u32 link_dma_active_sdw_mask[SNDRV_PCM_STREAM_LAST + 1]; -+ u32 link_dma_active_multi_mask[SNDRV_PCM_STREAM_LAST + 1]; -+ u32 link_dma_out_hda_used_mask; -+ - /* PM related */ - bool l1_disabled;/* is DMI link L1 disabled? */ - -@@ -739,7 +762,7 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, - int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd); - - int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, -- bool persistent_buffer, struct hdac_ext_stream *hext_stream); -+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax); - int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); - #define HDA_CL_STREAM_FORMAT 0x40 - -@@ -911,7 +934,8 @@ hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int si - bool is_iccmax, bool pair); - - int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab, -- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair); -+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, -+ bool is_iccmax, bool pair); - - /* common dai driver */ - extern struct snd_soc_dai_driver skl_dai[]; -@@ -1030,7 +1054,8 @@ struct hda_dai_widget_dma_ops { - struct snd_pcm_substream *substream); - struct hdac_ext_stream *(*assign_hext_stream)(struct snd_sof_dev *sdev, - struct snd_soc_dai *cpu_dai, -- struct snd_pcm_substream *substream); -+ struct snd_pcm_substream *substream, -+ struct hdac_ext_link *hlink); - void (*release_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, - struct snd_pcm_substream *substream); - void (*setup_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream, -diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c ---- a/sound/soc/sof/intel/icl.c -+++ b/sound/soc/sof/intel/icl.c -@@ -9,10 +9,14 @@ - * Hardware interface for audio DSP on IceLake. - */ - --#include --#include --#include -+#include - #include -+#include -+#include -+#include -+#include -+#include -+ - #include "../ipc4-priv.h" - #include "../ops.h" - #include "hda.h" -diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c ---- a/sound/soc/sof/intel/mtl.c -+++ b/sound/soc/sof/intel/mtl.c -@@ -236,6 +236,17 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) - } - EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL"); - -+static bool mtl_dsp_is_enabled(struct snd_sof_dev *sdev) -+{ -+ int val; -+ -+ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); -+ if (val & MTL_HFDSSCS_CPA_MASK) -+ return true; -+ -+ return false; -+} -+ - /* pre fw run operations */ - static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) - { -@@ -249,6 +260,18 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) - u32 dsppwrsts; - const struct sof_intel_dsp_desc *chip; - -+ /* Power down the DSP if it is left enabled to ensure clean boot state */ -+ if (mtl_dsp_is_enabled(sdev)) { -+ dev_dbg(sdev->dev, "powering down DSP first\n"); -+ -+ ret = mtl_power_down_dsp(sdev); -+ if (ret < 0) { -+ dev_warn(sdev->dev, -+ "%s: failed to power down already-enabled DSP\n", __func__); -+ /* Continue anyway to attempt recovery */ -+ } -+ } -+ - chip = get_chip_info(sdev->pdata); - if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) { - dsppwrctl = PTL_HFPWRCTL2; -diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c ---- a/sound/soc/sof/ipc3-pcm.c -+++ b/sound/soc/sof/ipc3-pcm.c -@@ -421,6 +421,12 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, - dev_dbg(component->dev, "AMD_SDW channels_min: %d channels_max: %d\n", - channels->min, channels->max); - break; -+ case SOF_DAI_AMD_I2S: -+ rate->min = private->dai_config->acp_i2s.fsync_rate; -+ rate->max = private->dai_config->acp_i2s.fsync_rate; -+ channels->min = private->dai_config->acp_i2s.tdm_slots; -+ channels->max = private->dai_config->acp_i2s.tdm_slots; -+ break; - default: - dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type); - break; -diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c ---- a/sound/soc/sof/ipc3-topology.c -+++ b/sound/soc/sof/ipc3-topology.c -@@ -281,7 +281,10 @@ static const struct sof_topology_token acpdmic_tokens[] = { - offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)}, - }; - --/* ACPI2S */ -+/* -+ * ACPI2S tokens fill struct sof_ipc_dai_acp_params; SOF_DAI_AMD_I2S (ACPTDM -+ * on ACP7.B/7.F) reuses this tuple group rather than defining a parallel set. -+ */ - static const struct sof_topology_token acpi2s_tokens[] = { - {SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_acp_params, fsync_rate)}, -@@ -289,6 +292,8 @@ static const struct sof_topology_token acpi2s_tokens[] = { - offsetof(struct sof_ipc_dai_acp_params, tdm_slots)}, - {SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_acp_params, tdm_mode)}, -+ {SOF_TKN_AMD_ACPI2S_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, -+ offsetof(struct sof_ipc_dai_acp_params, format)}, - }; - - /* MICFIL PDM */ -@@ -1363,6 +1368,35 @@ static int sof_link_acp_sdw_load(struct snd_soc_component *scomp, struct snd_sof - return 0; - } - -+static int sof_link_acp_i2s_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, -+ struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) -+{ -+ struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; -+ struct sof_dai_private_data *private = dai->private; -+ u32 size = sizeof(*config); -+ int ret; -+ -+ /* handle master/slave and inverted clocks */ -+ sof_dai_set_format(hw_config, config); -+ -+ /* init IPC */ -+ memset(&config->acp_i2s, 0, sizeof(config->acp_i2s)); -+ config->hdr.size = size; -+ -+ ret = sof_update_ipc_object(scomp, &config->acp_i2s, SOF_ACPI2S_TOKENS, slink->tuples, -+ slink->num_tuples, size, slink->num_hw_configs); -+ if (ret < 0) -+ return ret; -+ -+ dai->number_configs = 1; -+ dai->current_config = 0; -+ private->dai_config = kmemdup(config, size, GFP_KERNEL); -+ if (!private->dai_config) -+ return -ENOMEM; -+ -+ return 0; -+} -+ - static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, - struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) - { -@@ -1692,6 +1726,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) - case SOF_DAI_AMD_SDW: - ret = sof_link_acp_sdw_load(scomp, slink, config, dai); - break; -+ case SOF_DAI_AMD_I2S: -+ ret = sof_link_acp_i2s_load(scomp, slink, config, dai); -+ break; - default: - break; - } -diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c ---- a/sound/soc/sof/ipc4-topology.c -+++ b/sound/soc/sof/ipc4-topology.c -@@ -163,11 +163,11 @@ static const struct sof_topology_token comp_ext_tokens[] = { - {SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain, - offsetof(struct snd_sof_widget, comp_domain)}, - {SOF_TKN_COMP_DOMAIN_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, -- offsetof(struct snd_sof_widget, dp_domain_id)}, -+ offsetof(struct snd_sof_widget, domain_id)}, - {SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, -- offsetof(struct snd_sof_widget, dp_heap_bytes)}, -+ offsetof(struct snd_sof_widget, heap_bytes)}, - {SOF_TKN_COMP_STACK_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, -- offsetof(struct snd_sof_widget, dp_stack_bytes)}, -+ offsetof(struct snd_sof_widget, stack_bytes)}, - }; - - static const struct sof_topology_token gain_tokens[] = { -@@ -406,6 +406,39 @@ sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index) - return NULL; - } - -+static void -+sof_ipc4_evaluate_params_change(struct sof_ipc4_available_audio_format *available_fmt) -+{ -+ struct sof_ipc4_audio_format *fmt; -+ u32 in_rate, in_channels, in_valid_bits; -+ u32 out_rate, out_channels, out_valid_bits; -+ u32 changed_params = 0; -+ int i, j; -+ -+ for (i = 0; i < available_fmt->num_input_formats; i++) { -+ fmt = &available_fmt->input_pin_fmts[i].audio_fmt; -+ in_rate = fmt->sampling_frequency; -+ in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); -+ in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); -+ -+ for (j = 0; j < available_fmt->num_output_formats; j++) { -+ fmt = &available_fmt->output_pin_fmts[j].audio_fmt; -+ out_rate = fmt->sampling_frequency; -+ out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); -+ out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); -+ -+ if (in_rate != out_rate) -+ changed_params |= BIT(SNDRV_PCM_HW_PARAM_RATE); -+ if (in_channels != out_channels) -+ changed_params |= BIT(SNDRV_PCM_HW_PARAM_CHANNELS); -+ if (in_valid_bits != out_valid_bits) -+ changed_params |= BIT(SNDRV_PCM_HW_PARAM_FORMAT); -+ } -+ } -+ -+ available_fmt->changed_params = changed_params; -+} -+ - /** - * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples - * @scomp: pointer to pointer to SOC component -@@ -497,6 +530,8 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, - available_fmt->num_output_formats); - } - -+ sof_ipc4_evaluate_params_change(available_fmt); -+ - return 0; - - err_out: -@@ -661,6 +696,9 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) - if (ret) - goto free_copier; - -+ /* Copier can only change format */ -+ available_fmt->changed_params &= BIT(SNDRV_PCM_HW_PARAM_FORMAT); -+ - /* - * This callback is used by host copier and module-to-module copier, - * and only host copier needs to set gtw_cfg. -@@ -789,6 +827,9 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) - if (ret) - goto free_copier; - -+ /* Copier can only change format */ -+ available_fmt->changed_params &= BIT(SNDRV_PCM_HW_PARAM_FORMAT); -+ - ret = sof_update_ipc_object(scomp, &node_type, - SOF_COPIER_TOKENS, swidget->tuples, - swidget->num_tuples, sizeof(node_type), 1); -@@ -1371,6 +1412,22 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget * - pipeline = pipe_widget->private; - pipeline->mem_usage += total; - -+ /* -+ * If this is not a Data Processing module instance, add the -+ * required heap sizes to the sum of all module instances belonging -+ * to the same pipeline, and find the maximum stack requirement -+ * among all module instances belonging to the same pipeline. -+ */ -+ if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) { -+ pipe_widget->heap_bytes += swidget->heap_bytes; -+ if (pipe_widget->stack_bytes < swidget->stack_bytes) -+ pipe_widget->stack_bytes = swidget->stack_bytes; -+ -+ dev_dbg(sdev->dev, "%s mem reqs to %s heap %u stack %u", -+ swidget->widget->name, pipe_widget->widget->name, -+ pipe_widget->heap_bytes, pipe_widget->stack_bytes); -+ } -+ - /* Update base_config->cpc from the module manifest */ - sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); - -@@ -1688,6 +1745,8 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) - pipe_widget = swidget->spipe->pipe_widget; - pipeline = pipe_widget->private; - pipeline->mem_usage = 0; -+ pipe_widget->heap_bytes = 0; -+ pipe_widget->stack_bytes = 0; - - if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { - if (pipeline->use_chain_dma) { -@@ -2065,10 +2124,57 @@ static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget - } - - static int --sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, -- struct snd_pcm_hw_params *fe_params, -- struct snd_sof_platform_stream_params *platform_params, -- struct snd_pcm_hw_params *pipeline_params, int dir) -+sof_ipc4_copier_module_update_params(struct snd_sof_widget *swidget, -+ struct snd_pcm_hw_params *pipeline_params) -+{ -+ struct snd_soc_component *scomp = swidget->scomp; -+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); -+ struct sof_ipc4_copier_data *copier_data; -+ struct sof_ipc4_copier *ipc4_copier; -+ -+ switch (swidget->id) { -+ case snd_soc_dapm_aif_in: -+ case snd_soc_dapm_aif_out: -+ case snd_soc_dapm_buffer: -+ ipc4_copier = swidget->private; -+ copier_data = &ipc4_copier->data; -+ break; -+ case snd_soc_dapm_dai_in: -+ case snd_soc_dapm_dai_out: -+ { -+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; -+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private; -+ struct snd_sof_dai *dai; -+ -+ if (pipeline->use_chain_dma) -+ return 0; -+ -+ dai = swidget->private; -+ -+ ipc4_copier = (struct sof_ipc4_copier *)dai->private; -+ copier_data = &ipc4_copier->data; -+ -+ break; -+ } -+ default: -+ dev_err(sdev->dev, "unsupported type %d for copier %s", -+ swidget->id, swidget->widget->name); -+ return -EINVAL; -+ } -+ -+ /* modify the input params for the next widget */ -+ return sof_ipc4_update_hw_params(sdev, pipeline_params, -+ &copier_data->out_format, -+ BIT(SNDRV_PCM_HW_PARAM_FORMAT) | -+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | -+ BIT(SNDRV_PCM_HW_PARAM_RATE)); -+} -+ -+static int -+_sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, -+ struct snd_pcm_hw_params *fe_params, -+ struct snd_sof_platform_stream_params *platform_params, -+ struct snd_pcm_hw_params *pipeline_params, int dir) - { - struct sof_ipc4_available_audio_format *available_fmt; - struct snd_soc_component *scomp = swidget->scomp; -@@ -2540,6 +2646,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, - return 0; - } - -+static int -+sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, -+ struct snd_pcm_hw_params *fe_params, -+ struct snd_sof_platform_stream_params *platform_params, -+ struct snd_pcm_hw_params *pipeline_params, int dir) -+{ -+ if (swidget->prepared) -+ return sof_ipc4_copier_module_update_params(swidget, -+ pipeline_params); -+ -+ return _sof_ipc4_prepare_copier_module(swidget, fe_params, -+ platform_params, pipeline_params, -+ dir); -+} -+ - static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, - struct snd_pcm_hw_params *fe_params, - struct snd_sof_platform_stream_params *platform_params, -@@ -2553,6 +2674,10 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; - int input_fmt_index, output_fmt_index; - -+ /* This cannot happen */ -+ if (unlikely(swidget->prepared)) -+ return 0; -+ - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, - &gain->data.base_config, - pipeline_params, -@@ -2598,6 +2723,10 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; - int input_fmt_index, output_fmt_index; - -+ /* Already prepared, nothing to do */ -+ if (swidget->prepared) -+ return 0; -+ - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, - &mixer->base_config, - pipeline_params, -@@ -2644,6 +2773,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; - int output_fmt_index, input_fmt_index; - -+ /* This cannot happen */ -+ if (unlikely(swidget->prepared)) -+ return 0; -+ - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, - &src->data.base_config, - pipeline_params, -@@ -2810,6 +2943,18 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, - int ret; - - if (available_fmt->num_input_formats) { -+ if (swidget->prepared) { -+ if (!available_fmt->num_output_formats) -+ return 0; -+ -+ /* modify the pipeline params with the output format */ -+ return sof_ipc4_update_hw_params(sdev, pipeline_params, -+ &process->output_format, -+ BIT(SNDRV_PCM_HW_PARAM_FORMAT) | -+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | -+ BIT(SNDRV_PCM_HW_PARAM_RATE)); -+ } -+ - input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, - &process->base_config, - pipeline_params, -@@ -2822,39 +2967,69 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, - if (available_fmt->num_output_formats) { - struct sof_ipc4_audio_format *in_fmt; - struct sof_ipc4_pin_format *pin_fmt; -- u32 out_ref_rate, out_ref_channels; -- int out_ref_valid_bits, out_ref_type; -+ u32 ref_rate, ref_channels; -+ int ref_valid_bits, ref_type; - - if (available_fmt->num_input_formats) { -+ /* -+ * The process module can change parameters and their operation -+ * depends on the direction: -+ * Playback: typically they have single output format. This is -+ * to 'force' the conversion from input to output. -+ * Use the input format as reference since the single -+ * format is going to be picked. -+ * Capture: typically they have multiple output formats to -+ * convert from dai (input) to FE (output) parameters. -+ * Use the input format as base and replace the param -+ * which is changed by the module with the FE parameter -+ * Reason: we can have module which changes the -+ * parameters in path, we cannot use the full -+ * FE param set for the module output lookup. -+ */ - in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; - -- out_ref_rate = in_fmt->sampling_frequency; -- out_ref_channels = -+ ref_rate = in_fmt->sampling_frequency; -+ ref_channels = - SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); -- out_ref_valid_bits = -+ ref_valid_bits = - SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); -- out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); -+ ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg); - } else { - /* for modules without input formats, use FE params as reference */ -- out_ref_rate = params_rate(fe_params); -- out_ref_channels = params_channels(fe_params); -+ ref_rate = params_rate(fe_params); -+ ref_channels = params_channels(fe_params); - ret = sof_ipc4_get_sample_type(sdev, fe_params); - if (ret < 0) - return ret; -- out_ref_type = (u32)ret; -+ ref_type = (u32)ret; - -- out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); -- if (out_ref_valid_bits < 0) -- return out_ref_valid_bits; -+ ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); -+ if (ref_valid_bits < 0) -+ return ref_valid_bits; - } - -+ if (dir == SNDRV_PCM_STREAM_CAPTURE) { -+ if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_RATE)) -+ ref_rate = params_rate(fe_params); -+ if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) -+ ref_channels = params_channels(fe_params); -+ if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) { -+ ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params); -+ if (ref_valid_bits < 0) -+ return ref_valid_bits; -+ -+ ref_type = sof_ipc4_get_sample_type(sdev, fe_params); -+ if (ref_type < 0) -+ return ref_type; -+ } -+ } - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, - &process->base_config, - available_fmt, -- out_ref_rate, -- out_ref_channels, -- out_ref_valid_bits, -- out_ref_type); -+ ref_rate, -+ ref_channels, -+ ref_valid_bits, -+ ref_type); - if (output_fmt_index < 0) - return output_fmt_index; - -@@ -2868,9 +3043,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, - /* modify the pipeline params with the output format */ - ret = sof_ipc4_update_hw_params(sdev, pipeline_params, - &process->output_format, -- BIT(SNDRV_PCM_HW_PARAM_FORMAT) | -- BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | -- BIT(SNDRV_PCM_HW_PARAM_RATE)); -+ available_fmt->changed_params); - if (ret) - return ret; - } -@@ -3085,27 +3258,47 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr - return 0; - } - --static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, -- struct snd_sof_widget *swidget, -- struct sof_ipc4_msg *msg, -- void *ipc_data, u32 ipc_size, -- void **new_data) -+static void sof_ipc4_add_init_ext_dp_memory_data(struct snd_sof_dev *sdev, -+ struct snd_sof_widget *swidget, -+ u32 *payload, u32 *ext_pos, -+ struct sof_ipc4_module_init_ext_object **hdr) -+{ -+ /* Add memory_data if comp_domain indicates DP */ -+ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { -+ struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; -+ -+ *hdr = (struct sof_ipc4_module_init_ext_object *)&payload[*ext_pos]; -+ (*hdr)->header = -+ SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | -+ SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data), -+ sizeof(u32))); -+ *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32)); -+ dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[*ext_pos]; -+ dp_mem_data->domain_id = swidget->domain_id; -+ dp_mem_data->stack_bytes = swidget->stack_bytes; -+ dp_mem_data->heap_bytes = swidget->heap_bytes; -+ *ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); -+ } -+} -+ -+static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, -+ struct snd_sof_widget *swidget, -+ struct sof_ipc4_msg *msg, -+ void *ipc_data, u32 ipc_size, -+ void **new_data) - { -- struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; - struct sof_ipc4_module_init_ext_init *ext_init; -- struct sof_ipc4_module_init_ext_object *hdr; -+ struct sof_ipc4_module_init_ext_object *hdr = NULL; - int new_size; - u32 *payload; - u32 ext_pos; - -- /* For the moment the only reason for adding init_ext_init payload is DP -- * memory data. If both stack and heap size are 0 (= use default), then -- * there is no need for init_ext_init payload. -+ /* -+ * Only DP widgets currently add init-ext objects here. Avoid allocating -+ * a max-sized payload buffer for widgets that will immediately return 0. - */ -- if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) { -- msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK; -+ if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) - return 0; -- } - - payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); - if (!payload) -@@ -3113,27 +3306,26 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, - - /* Add ext_init first and set objects array flag to 1 */ - ext_init = (struct sof_ipc4_module_init_ext_init *)payload; -- ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; - ext_pos = DIV_ROUND_UP(sizeof(*ext_init), sizeof(u32)); - - /* Add object array objects after ext_init */ - -- /* Add dp_memory_data if comp_domain indicates DP */ -- if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { -- hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; -- hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | -- SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | -- SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data), -- sizeof(u32))); -- ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32)); -- dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos]; -- dp_mem_data->domain_id = swidget->dp_domain_id; -- dp_mem_data->stack_bytes = swidget->dp_stack_bytes; -- dp_mem_data->heap_bytes = swidget->dp_heap_bytes; -- ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); -+ sof_ipc4_add_init_ext_dp_memory_data(sdev, swidget, payload, &ext_pos, &hdr); -+ -+ /* Add following object array items here */ -+ -+ if (!hdr) { -+ /* -+ * NOTE: Remove this early bail out, when struct -+ * sof_ipc4_module_init_ext_init alone has some -+ * function. -+ */ -+ kfree(payload); -+ return 0; - } - -- /* If another array object is added, remember clear previous OBJ_LAST bit */ -+ ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; -+ hdr->header |= SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK; - - /* Calculate final size and check that it fits to max payload size */ - new_size = ext_pos * sizeof(u32) + ipc_size; -@@ -3156,6 +3348,69 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, - return new_size; - } - -+static void sof_ipc4_widget_pipe_ext_obj_memory_data(struct snd_sof_dev *sdev, -+ struct snd_sof_widget *swidget, -+ u32 *payload, u32 *ext_pos, -+ struct sof_ipc4_glb_pipe_ext_object **hdr) -+{ -+ struct sof_ipc4_glb_pipe_ext_obj_memory_data *mem_data; -+ -+ *hdr = (struct sof_ipc4_glb_pipe_ext_object *)&payload[*ext_pos]; -+ (*hdr)->header = -+ SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA) | -+ SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*mem_data), -+ sizeof(u32))); -+ *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32)); -+ mem_data = (struct sof_ipc4_glb_pipe_ext_obj_memory_data *)&payload[*ext_pos]; -+ mem_data->domain_id = swidget->domain_id; -+ mem_data->stack_bytes = swidget->stack_bytes; -+ mem_data->heap_bytes = swidget->heap_bytes; -+ *ext_pos += DIV_ROUND_UP(sizeof(*mem_data), sizeof(u32)); -+ -+ dev_dbg(sdev->dev, -+ "%s; domain_id %u stack %u heap %u bytes", -+ swidget->widget->name, mem_data->domain_id, mem_data->stack_bytes, -+ mem_data->heap_bytes); -+} -+ -+static int sof_ipc4_widget_pipe_create_msg_payload(struct snd_sof_dev *sdev, -+ struct snd_sof_widget *swidget, -+ struct sof_ipc4_msg *msg, -+ void **new_data) -+{ -+ struct sof_ipc4_glb_pipe_payload *payload_hdr; -+ struct sof_ipc4_glb_pipe_ext_object *hdr = NULL; -+ u32 *payload; -+ u32 ext_pos; -+ -+ payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); -+ if (!payload) -+ return -ENOMEM; -+ -+ /* Add sof_ipc4_glb_pipe_payload and set array bit to 1 */ -+ payload_hdr = (struct sof_ipc4_glb_pipe_payload *)payload; -+ payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK; -+ ext_pos = DIV_ROUND_UP(sizeof(*payload_hdr), sizeof(u32)); -+ -+ sof_ipc4_widget_pipe_ext_obj_memory_data(sdev, swidget, payload, &ext_pos, &hdr); -+ /* Add following array objects here */ -+ -+ /* Mark end of object array */ -+ hdr->header |= SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK; -+ -+ /* Put total payload size in words to the payload header */ -+ payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(ext_pos); -+ *new_data = payload; -+ -+ /* Update msg extension bits according to the payload changes */ -+ msg->extension |= SOF_IPC4_GLB_PIPE_PAYLOAD_MASK; -+ -+ dev_dbg(sdev->dev, "%s: payload word0 %#x", swidget->widget->name, -+ payload_hdr->word0); -+ -+ return ext_pos * sizeof(int32_t); -+} -+ - static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) - { - struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; -@@ -3342,8 +3597,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget - swidget->widget->name, swidget->pipeline_id, module_id, - swidget->instance_id, swidget->core); - -- ret = sof_ipc4_widget_setup_msg_payload(sdev, swidget, msg, ipc_data, ipc_size, -- &ext_data); -+ ret = sof_ipc4_widget_mod_init_msg_payload(sdev, swidget, msg, ipc_data, ipc_size, -+ &ext_data); - if (ret < 0) - goto fail; - -@@ -3355,6 +3610,17 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget - dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n", - swidget->widget->name, swidget->pipeline_id, - swidget->instance_id, swidget->core); -+ -+ msg->extension &= ~SOF_IPC4_GLB_PIPE_PAYLOAD_MASK; -+ ret = sof_ipc4_widget_pipe_create_msg_payload(sdev, swidget, msg, -+ &ext_data); -+ if (ret < 0) -+ goto fail; -+ -+ if (ret > 0) { -+ ipc_size = ret; -+ ipc_data = ext_data; -+ } - } - - msg->data_size = ipc_size; -@@ -3412,6 +3678,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget - swidget->widget->name); - - pipeline->mem_usage = 0; -+ swidget->heap_bytes = 0; -+ swidget->stack_bytes = 0; - pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; - ida_free(&pipeline_ida, swidget->instance_id); - swidget->instance_id = -EINVAL; -diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h ---- a/sound/soc/sof/ipc4-topology.h -+++ b/sound/soc/sof/ipc4-topology.h -@@ -167,7 +167,7 @@ struct sof_ipc4_pipeline { - }; - - /** -- * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data -+ * struct ipc4_pipeline_set_state_data - multi pipeline trigger IPC data - * @count: Number of pipelines to be triggered - * @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered - */ -@@ -197,12 +197,15 @@ struct sof_ipc4_pin_format { - * @input_pin_fmts: Available input pin formats - * @num_input_formats: Number of input pin formats - * @num_output_formats: Number of output pin formats -+ * @changed_params: Mask of changed params by the module instance between it's -+ * input and output formts (rate, channels, depth) - */ - struct sof_ipc4_available_audio_format { - struct sof_ipc4_pin_format *output_pin_fmts; - struct sof_ipc4_pin_format *input_pin_fmts; - u32 num_input_formats; - u32 num_output_formats; -+ u32 changed_params; - }; - - /** -@@ -210,7 +213,7 @@ struct sof_ipc4_available_audio_format { - * @node_id: ID of Gateway Node - * @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes) - * @config_length: Length of gateway node configuration blob specified in #config_data -- * config_data: Gateway node configuration blob -+ * @config_data: Gateway node configuration blob - */ - struct sof_copier_gateway_cfg { - uint32_t node_id; -@@ -285,7 +288,9 @@ struct sof_ipc4_dma_stream_ch_map { - struct sof_ipc4_dma_config { - uint8_t dma_method; - uint8_t pre_allocated_by_host; -+ /* private: */ - uint16_t rsvd; -+ /* public: */ - uint32_t dma_channel_id; - uint32_t stream_id; - struct sof_ipc4_dma_stream_ch_map dma_stream_channel_map; -@@ -296,7 +301,7 @@ struct sof_ipc4_dma_config { - #define SOF_IPC4_GTW_DMA_CONFIG_ID 0x1000 - - /** -- * struct sof_ipc4_dma_config: DMA configuration -+ * struct sof_ipc4_dma_config_tlv - DMA configuration - * @type: set to SOF_IPC4_GTW_DMA_CONFIG_ID - * @length: sizeof(struct sof_ipc4_dma_config) + dma_config.dma_priv_config_size - * @dma_config: actual DMA configuration -@@ -321,6 +326,7 @@ struct sof_ipc4_alh_configuration_blob { - * @data: IPC copier data - * @copier_config: Copier + blob - * @ipc_config_size: Size of copier_config -+ * @ipc_config_data: Copier module config data - * @available_fmt: Available audio format - * @frame_fmt: frame format - * @msg: message structure for copier -diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c ---- a/sound/soc/sof/ipc4.c -+++ b/sound/soc/sof/ipc4.c -@@ -289,6 +289,89 @@ static void sof_ipc4_dump_payload(struct snd_sof_dev *sdev, - 16, 4, ipc_data, size, false); - } - -+static const char *sof_ipc4_resource_type_str(u32 type) -+{ -+ switch (type) { -+ case SOF_IPC4_MODULE_INSTANCE: -+ return "resource: MODULE_INSTANCE"; -+ case SOF_IPC4_PIPELINE: -+ return "resource: PIPELINE"; -+ case SOF_IPC4_GATEWAY: -+ return "resource: GATEWAY"; -+ case SOF_IPC4_EDF_TASK: -+ return "resource: EDF_TASK"; -+ case SOF_IPC4_INVALID_RESOURCE_TYPE: -+ return "Resource is invalid"; -+ default: -+ return "Unknown resource type"; -+ } -+} -+ -+static const char *sof_ipc4_resource_event_type_str(u32 event_type) -+{ -+ switch (event_type) { -+ case SOF_IPC4_MIXER_UNDERRUN_DETECTED: -+ return "event: MIXER_UNDERRUN_DETECTED"; -+ case SOF_IPC4_PROCESS_DATA_ERROR: -+ return "event: PROCESS_DATA_ERROR"; -+ case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED: -+ return "event: GATEWAY_UNDERRUN_DETECTED"; -+ case SOF_IPC4_GATEWAY_OVERRUN_DETECTED: -+ return "event: GATEWAY_OVERRUN_DETECTED"; -+ default: -+ return "Unknown event type"; -+ } -+} -+ -+static void sof_ipc4_resource_event_handler(struct snd_sof_dev *sdev, -+ struct sof_ipc4_msg *ipc4_msg) -+{ -+ struct sof_ipc4_notify_resource_data *data = ipc4_msg->data_ptr; -+ -+ /* Print event details */ -+ switch (data->event_type) { -+ case SOF_IPC4_MIXER_UNDERRUN_DETECTED: -+ dev_dbg(sdev->dev, "%s (%u): eos %u, mixed %u, expected %u\n", -+ sof_ipc4_resource_event_type_str(data->event_type), -+ data->event_type, data->data.mixer_underrun.eos_flag, -+ data->data.mixer_underrun.data_mixed, -+ data->data.mixer_underrun.expected_data_mixed); -+ break; -+ case SOF_IPC4_PROCESS_DATA_ERROR: -+ dev_dbg(sdev->dev, "%s (%u): error_code %#x\n", -+ sof_ipc4_resource_event_type_str(data->event_type), -+ data->event_type, data->data.process_data_error.error_code); -+ break; -+ case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED: -+ case SOF_IPC4_GATEWAY_OVERRUN_DETECTED: -+ dev_dbg(sdev->dev, "%s (%u)\n", -+ sof_ipc4_resource_event_type_str(data->event_type), -+ data->event_type); -+ break; -+ default: -+ dev_dbg(sdev->dev, "%s (%u): raw dws %#x %#x %#x %#x %#x %#x\n", -+ sof_ipc4_resource_event_type_str(data->event_type), -+ data->event_type, -+ data->data.dws[0], data->data.dws[1], data->data.dws[2], -+ data->data.dws[3], data->data.dws[4], data->data.dws[5]); -+ break; -+ } -+ -+ /* Print resource details */ -+ if (data->resource_type == SOF_IPC4_MODULE_INSTANCE) { -+ u32 module_id = SOF_IPC4_MOD_ID_GET(data->resource_id); -+ u32 instance_id = SOF_IPC4_MOD_INSTANCE_GET(data->resource_id); -+ -+ dev_dbg(sdev->dev, "%s (%u), module_id %u, instance_id %u\n", -+ sof_ipc4_resource_type_str(data->resource_type), -+ data->resource_type, module_id, instance_id); -+ } else if (data->resource_type != SOF_IPC4_INVALID_RESOURCE_TYPE) { -+ dev_dbg(sdev->dev, "%s (%u), id %u\n", -+ sof_ipc4_resource_type_str(data->resource_type), -+ data->resource_type, data->resource_id); -+ } -+} -+ - static int sof_ipc4_get_reply(struct snd_sof_dev *sdev) - { - struct snd_sof_ipc_msg *msg = sdev->msg; -@@ -734,6 +817,7 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) - break; - case SOF_IPC4_NOTIFY_RESOURCE_EVENT: - data_size = sizeof(struct sof_ipc4_notify_resource_data); -+ handler_func = sof_ipc4_resource_event_handler; - break; - case SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS: - sof_ipc4_mtrace_update_pos(sdev, SOF_IPC4_LOG_CORE_GET(ipc4_msg->primary)); -diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c ---- a/sound/soc/sof/nocodec.c -+++ b/sound/soc/sof/nocodec.c -@@ -21,12 +21,13 @@ static struct snd_soc_card sof_nocodec_card = { - static int sof_nocodec_bes_setup(struct device *dev, - struct snd_soc_dai_driver *drv, - struct snd_soc_dai_link *links, -- int link_num, struct snd_soc_card *card) -+ int link_num) - { -+ struct snd_soc_card *card = &sof_nocodec_card; - struct snd_soc_dai_link_component *dlc; - int i; - -- if (!drv || !links || !card) -+ if (!drv || !links) - return -EINVAL; - - /* set up BE dai_links */ -@@ -67,10 +68,10 @@ static int sof_nocodec_bes_setup(struct device *dev, - return 0; - } - --static int sof_nocodec_setup(struct device *dev, -- u32 num_dai_drivers, -- struct snd_soc_dai_driver *dai_drivers) -+static int sof_nocodec_setup(struct device *dev, struct snd_soc_acpi_mach *mach) - { -+ u32 num_dai_drivers = mach->mach_params.num_dai_drivers; -+ struct snd_soc_dai_driver *dai_drivers = mach->mach_params.dai_drivers; - struct snd_soc_dai_link *links; - - /* create dummy BE dai_links */ -@@ -78,7 +79,7 @@ static int sof_nocodec_setup(struct device *dev, - if (!links) - return -ENOMEM; - -- return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers, &sof_nocodec_card); -+ return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers); - } - - static int sof_nocodec_probe(struct platform_device *pdev) -@@ -92,8 +93,7 @@ static int sof_nocodec_probe(struct platform_device *pdev) - - snd_soc_card_set_topology_name(card, "sof"); - -- ret = sof_nocodec_setup(card->dev, mach->mach_params.num_dai_drivers, -- mach->mach_params.dai_drivers); -+ ret = sof_nocodec_setup(card->dev, mach); - if (ret < 0) - return ret; - -diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c ---- a/sound/soc/sof/pcm.c -+++ b/sound/soc/sof/pcm.c -@@ -62,7 +62,7 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) - * To avoid sending IPC before the previous IPC is handled, we - * schedule delayed work here to call the snd_pcm_period_elapsed(). - */ -- schedule_work(&spcm->stream[substream->stream].period_elapsed_work); -+ queue_work(system_highpri_wq, &spcm->stream[substream->stream].period_elapsed_work); - } - EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); - -diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c ---- a/sound/soc/sof/sof-audio.c -+++ b/sound/soc/sof/sof-audio.c -@@ -501,9 +501,8 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget - !sof_widget_in_same_direction(swidget, dir)) - return 0; - -- /* skip widgets already prepared or aggregated DAI widgets*/ -- if (!widget_ops[widget->id].ipc_prepare || swidget->prepared || -- is_aggregated_dai(swidget)) -+ /* skip widgets aggregated DAI widgets */ -+ if (!widget_ops[widget->id].ipc_prepare || is_aggregated_dai(swidget)) - goto sink_prepare; - - /* prepare the source widget */ -diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h ---- a/sound/soc/sof/sof-audio.h -+++ b/sound/soc/sof/sof-audio.h -@@ -459,10 +459,10 @@ struct snd_sof_widget { - /* Scheduling domain (enum sof_comp_domain), unset, Low Latency, or Data Processing */ - u32 comp_domain; - -- /* The values below are added to mod_init pay load if comp_domain indicates DP component */ -- u32 dp_domain_id; /* DP process userspace domain ID */ -- u32 dp_stack_bytes; /* DP process stack size requirement in bytes */ -- u32 dp_heap_bytes; /* DP process heap size requirement in bytes */ -+ /* Module instance's memory configuration. */ -+ u32 domain_id; /* Module instance's userspace domain ID */ -+ u32 stack_bytes; /* Module instance's stack size requirement */ -+ u32 heap_bytes; /* Module instance's heap size requirement */ - - struct snd_soc_dapm_widget *widget; - struct list_head list; /* list in sdev widget list */ -diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c ---- a/sound/soc/sof/topology.c -+++ b/sound/soc/sof/topology.c -@@ -309,7 +309,7 @@ static const struct sof_dai_types sof_dais[] = { - {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL}, - {"MICFIL", SOF_DAI_IMX_MICFIL}, - {"ACP_SDW", SOF_DAI_AMD_SDW}, -- -+ {"ACPTDM", SOF_DAI_AMD_I2S}, - }; - - static enum sof_ipc_dai_type find_dai(const char *name) -@@ -1108,7 +1108,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, - - full = NULL; - partial = NULL; -- list_for_each_entry(rtd, &card->rtd_list, list) { -+ for_each_card_rtds(card, rtd) { - /* does stream match DAI link ? */ - if (rtd->dai_link->stream_name) { - if (!strcmp(rtd->dai_link->stream_name, w->sname)) { -@@ -1173,7 +1173,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, - else - return; - -- list_for_each_entry(rtd, &card->rtd_list, list) { -+ for_each_card_rtds(card, rtd) { - /* does stream match DAI link ? */ - if (!rtd->dai_link->stream_name || - !strstr(rtd->dai_link->stream_name, sname)) -@@ -1949,8 +1949,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ - private->array, le32_to_cpu(private->size)); - if (ret < 0) { - dev_err(scomp->dev, "Failed tp parse common DAI link tokens\n"); -- kfree(slink); -- return ret; -+ goto free_slink; - } - - token_list = tplg_ops ? tplg_ops->token_list : NULL; -@@ -2001,6 +2000,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ - case SOF_DAI_AMD_HS: - case SOF_DAI_AMD_SP_VIRTUAL: - case SOF_DAI_AMD_HS_VIRTUAL: -+ case SOF_DAI_AMD_I2S: - token_id = SOF_ACPI2S_TOKENS; - num_tuples += token_list[SOF_ACPI2S_TOKENS].count; - break; -@@ -2019,8 +2019,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ - /* allocate memory for tuples array */ - slink->tuples = kzalloc_objs(*slink->tuples, num_tuples); - if (!slink->tuples) { -- kfree(slink); -- return -ENOMEM; -+ ret = -ENOMEM; -+ goto free_slink; - } - - if (token_list[SOF_DAI_LINK_TOKENS].tokens) { -@@ -2076,6 +2076,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ - - err: - kfree(slink->tuples); -+free_slink: - kfree(slink); - - return ret; -@@ -2511,13 +2512,12 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_sof_pdata *sof_pdata = sdev->pdata; - const char *tplg_filename_prefix = sof_pdata->tplg_filename_prefix; -- const struct firmware *fw; -- const char **tplg_files; - int tplg_cnt = 0; - int ret; - int i; - -- tplg_files = kcalloc(scomp->card->num_links, sizeof(char *), GFP_KERNEL); -+ const char **tplg_files __free(kfree) = -+ kcalloc(scomp->card->num_links, sizeof(char *), GFP_KERNEL); - if (!tplg_files) - return -ENOMEM; - -@@ -2543,10 +2543,8 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - tplg_filename_prefix, - &tplg_files, - no_fallback); -- if (tplg_cnt < 0) { -- kfree(tplg_files); -+ if (tplg_cnt < 0) - return tplg_cnt; -- } - } - - /* -@@ -2557,8 +2555,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - if (strstr(file, "dummy")) { - dev_err(scomp->dev, - "Function topology is required, please upgrade sof-firmware\n"); -- -- kfree(tplg_files); - return -EINVAL; - } - tplg_files[0] = file; -@@ -2573,6 +2569,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - if (tplg_files[0] != file) - dev_info(scomp->dev, "loading topology %d: %s\n", i, tplg_files[i]); - -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, tplg_files[i], scomp->dev); - if (ret < 0) { - /* -@@ -2591,8 +2588,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - else - ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw); - -- release_firmware(fw); -- - if (ret < 0) { - dev_err(scomp->dev, "tplg %s component load failed %d\n", - tplg_files[i], ret); -@@ -2611,6 +2606,8 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - goto out; - } - dev_info(scomp->dev, "loading feature topology %d: %s\n", i, feature_topology); -+ -+ const struct firmware *fw __free(firmware) = NULL; - ret = request_firmware(&fw, feature_topology, scomp->dev); - if (ret < 0) { - /* -@@ -2635,8 +2632,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - else - ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw); - -- release_firmware(fw); -- - if (ret < 0) { - dev_err(scomp->dev, "feature tplg %s component load failed %d\n", - feature_topologies[i], ret); -@@ -2655,8 +2650,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) - if (ret >= 0 && sdev->led_present) - ret = snd_ctl_led_request(); - -- kfree(tplg_files); -- - return ret; - } - EXPORT_SYMBOL(snd_sof_load_topology); -diff --git a/sound/soc/sophgo/cv1800b-tdm.c b/sound/soc/sophgo/cv1800b-tdm.c ---- a/sound/soc/sophgo/cv1800b-tdm.c -+++ b/sound/soc/sophgo/cv1800b-tdm.c -@@ -558,7 +558,7 @@ static const struct snd_soc_dai_ops cv1800b_i2s_dai_ops = { - .set_sysclk = cv1800b_i2s_dai_set_sysclk, - }; - --static const struct snd_soc_dai_driver cv1800b_i2s_dai_template = { -+static struct snd_soc_dai_driver cv1800b_i2s_dai_template = { - .name = "cv1800b-i2s", - .playback = { - .stream_name = "Playback", -@@ -636,7 +636,6 @@ static int cv1800b_i2s_probe(struct platform_device *pdev) - struct cv1800b_i2s *i2s; - struct resource *res; - void __iomem *regs; -- struct snd_soc_dai_driver *dai; - int ret; - - i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); -@@ -666,21 +665,14 @@ static int cv1800b_i2s_probe(struct platform_device *pdev) - platform_set_drvdata(pdev, i2s); - cv1800b_i2s_setup_tdm(i2s); - -- dai = devm_kmemdup(dev, &cv1800b_i2s_dai_template, sizeof(*dai), -- GFP_KERNEL); -- if (!dai) -- return -ENOMEM; -- -- ret = devm_snd_soc_register_component(dev, &cv1800b_i2s_component, dai, -- 1); -+ ret = devm_snd_soc_register_component(dev, &cv1800b_i2s_component, -+ &cv1800b_i2s_dai_template, 1); - if (ret) - return ret; - - ret = devm_snd_dmaengine_pcm_register(dev, &cv1800b_i2s_pcm_config, 0); -- if (ret) { -- dev_err(dev, "dmaengine_pcm_register failed: %d\n", ret); -+ if (ret) - return ret; -- } - - return 0; - } -diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c ---- a/sound/soc/spacemit/k1_i2s.c -+++ b/sound/soc/spacemit/k1_i2s.c -@@ -335,6 +335,11 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai) - return 0; - } - -+static const u64 spacemit_i2s_selectable_formats = -+ SND_SOC_POSSIBLE_DAIFMT_I2S | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_A | -+ SND_SOC_POSSIBLE_DAIFMT_DSP_B; -+ - static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { - .probe = spacemit_i2s_dai_probe, - .remove = spacemit_i2s_dai_remove, -@@ -343,6 +348,8 @@ static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = { - .set_sysclk = spacemit_i2s_set_sysclk, - .set_fmt = spacemit_i2s_set_fmt, - .trigger = spacemit_i2s_trigger, -+ .auto_selectable_formats = &spacemit_i2s_selectable_formats, -+ .num_auto_selectable_formats = 1, - }; - - static struct snd_soc_dai_driver spacemit_i2s_dai = { -@@ -459,7 +466,7 @@ static int spacemit_i2s_probe(struct platform_device *pdev) - - i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(i2s->base)) -- return dev_err_probe(i2s->dev, PTR_ERR(i2s->base), "failed to map registers\n"); -+ return PTR_ERR(i2s->base); - - i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(i2s->reset)) -@@ -476,7 +483,7 @@ static int spacemit_i2s_probe(struct platform_device *pdev) - &spacemit_i2s_component, - dai, 1); - if (ret) -- return dev_err_probe(i2s->dev, ret, "failed to register component"); -+ return ret; - - return devm_snd_dmaengine_pcm_register(&pdev->dev, &spacemit_dmaengine_pcm_config, 0); - } -diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c ---- a/sound/soc/spear/spdif_in.c -+++ b/sound/soc/spear/spdif_in.c -@@ -55,7 +55,7 @@ static int spdif_in_dai_probe(struct snd_soc_dai *dai) - struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai); - - host->dma_params_rx.filter_data = &host->dma_params; -- dai->capture_dma_data = &host->dma_params_rx; -+ snd_soc_dai_dma_data_set_capture(dai, &host->dma_params_rx); - - return 0; - } -@@ -150,12 +150,12 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd, - - static const struct snd_soc_dai_ops spdif_in_dai_ops = { - .shutdown = spdif_in_shutdown, -+ .probe = spdif_in_dai_probe, - .trigger = spdif_in_trigger, - .hw_params = spdif_in_hw_params, - }; - - static struct snd_soc_dai_driver spdif_in_dai = { -- .probe = spdif_in_dai_probe, - .capture = { - .channels_min = 2, - .channels_max = 2, -@@ -218,10 +218,8 @@ static int spdif_in_probe(struct platform_device *pdev) - - host->io_base = io_base; - host->irq = platform_get_irq(pdev, 0); -- if (host->irq < 0) { -- dev_warn(&pdev->dev, "failed to get IRQ: %d\n", host->irq); -+ if (host->irq < 0) - return host->irq; -- } - - host->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) -@@ -243,10 +241,8 @@ static int spdif_in_probe(struct platform_device *pdev) - - ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0, - "spdif-in", host); -- if (ret) { -- dev_warn(&pdev->dev, "request_irq failed\n"); -+ if (ret) - return ret; -- } - - ret = devm_snd_soc_register_component(&pdev->dev, &spdif_in_component, - &spdif_in_dai, 1); -diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c ---- a/sound/soc/spear/spdif_out.c -+++ b/sound/soc/spear/spdif_out.c -@@ -249,6 +249,7 @@ static int spdif_soc_dai_probe(struct snd_soc_dai *dai) - } - - static const struct snd_soc_dai_ops spdif_out_dai_ops = { -+ .probe = spdif_soc_dai_probe, - .mute_stream = spdif_mute, - .startup = spdif_out_startup, - .shutdown = spdif_out_shutdown, -@@ -266,7 +267,6 @@ static struct snd_soc_dai_driver spdif_out_dai = { - SNDRV_PCM_RATE_192000), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -- .probe = spdif_soc_dai_probe, - .ops = &spdif_out_dai_ops, - }; - -diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c ---- a/sound/soc/sprd/sprd-mcdt.c -+++ b/sound/soc/sprd/sprd-mcdt.c -@@ -931,10 +931,8 @@ static int sprd_mcdt_probe(struct platform_device *pdev) - - ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler, - 0, "sprd-mcdt", mcdt); -- if (ret) { -- dev_err(&pdev->dev, "Failed to request MCDT IRQ\n"); -+ if (ret) - return ret; -- } - - sprd_mcdt_init_chans(mcdt, res); - -diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c ---- a/sound/soc/sprd/sprd-pcm-dma.c -+++ b/sound/soc/sprd/sprd-pcm-dma.c -@@ -469,8 +469,6 @@ static int sprd_soc_platform_probe(struct platform_device *pdev) - - ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component, - NULL, 0); -- if (ret) -- dev_err(&pdev->dev, "could not register platform:%d\n", ret); - - return ret; - } -diff --git a/sound/soc/starfive/jh7110_pwmdac.c b/sound/soc/starfive/jh7110_pwmdac.c ---- a/sound/soc/starfive/jh7110_pwmdac.c -+++ b/sound/soc/starfive/jh7110_pwmdac.c -@@ -477,25 +477,22 @@ static int jh7110_pwmdac_probe(struct platform_device *pdev) - &jh7110_pwmdac_component, - &jh7110_pwmdac_dai, 1); - if (ret) -- return dev_err_probe(&pdev->dev, ret, "failed to register dai\n"); -+ return ret; - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); - if (ret) -- return dev_err_probe(&pdev->dev, ret, "failed to register pcm\n"); -+ return ret; - - pm_runtime_enable(dev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = jh7110_pwmdac_runtime_resume(&pdev->dev); -- if (ret) -- goto err_pm_disable; -+ if (ret) { -+ pm_runtime_disable(&pdev->dev); -+ return ret; -+ } - } - - return 0; -- --err_pm_disable: -- pm_runtime_disable(&pdev->dev); -- -- return ret; - } - - static void jh7110_pwmdac_remove(struct platform_device *pdev) -diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c ---- a/sound/soc/starfive/jh7110_tdm.c -+++ b/sound/soc/starfive/jh7110_tdm.c -@@ -559,10 +559,8 @@ static int jh7110_tdm_clk_reset_get(struct platform_device *pdev, - tdm->clks[5].id = "tdm"; - - ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks); -- if (ret) { -- dev_err(&pdev->dev, "Failed to get tdm clocks\n"); -+ if (ret) - return ret; -- } - - tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev); - if (IS_ERR(tdm->resets)) { -@@ -589,42 +587,33 @@ static int jh7110_tdm_probe(struct platform_device *pdev) - tdm->dev = &pdev->dev; - - ret = jh7110_tdm_clk_reset_get(pdev, tdm); -- if (ret) { -- dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n"); -+ if (ret) - return ret; -- } - - jh7110_tdm_init_params(tdm); - - dev_set_drvdata(&pdev->dev, tdm); - ret = devm_snd_soc_register_component(&pdev->dev, &jh7110_tdm_component, - &jh7110_tdm_dai, 1); -- if (ret) { -- dev_err(&pdev->dev, "Failed to register dai\n"); -+ if (ret) - return ret; -- } - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, - &jh7110_dmaengine_pcm_config, - SND_DMAENGINE_PCM_FLAG_COMPAT); -- if (ret) { -- dev_err(&pdev->dev, "Could not register pcm: %d\n", ret); -+ if (ret) - return ret; -- } - - pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = jh7110_tdm_runtime_resume(&pdev->dev); -- if (ret) -- goto err_pm_disable; -+ if (ret) { -+ pm_runtime_disable(&pdev->dev); -+ return ret; -+ } - } - - return 0; -- --err_pm_disable: -- pm_runtime_disable(&pdev->dev); -- -- return ret; - } - - static void jh7110_tdm_dev_remove(struct platform_device *pdev) -diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c ---- a/sound/soc/stm/stm32_adfsdm.c -+++ b/sound/soc/stm/stm32_adfsdm.c -@@ -360,11 +360,8 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) - ret = devm_snd_soc_register_component(&pdev->dev, - &stm32_adfsdm_soc_platform, - NULL, 0); -- if (ret < 0) { -- dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", -- __func__); -+ if (ret < 0) - return ret; -- } - - pm_runtime_enable(&pdev->dev); - -diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c ---- a/sound/soc/stm/stm32_i2s.c -+++ b/sound/soc/stm/stm32_i2s.c -@@ -1238,10 +1238,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, - - ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, 0, - dev_name(&pdev->dev), i2s); -- if (ret) { -- dev_err(&pdev->dev, "irq request returned %d\n", ret); -+ if (ret) - return ret; -- } - - /* Reset */ - rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); -@@ -1295,7 +1293,7 @@ static int stm32_i2s_probe(struct platform_device *pdev) - - ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0); - if (ret) -- return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n"); -+ return ret; - - ret = snd_soc_register_component(&pdev->dev, &stm32_i2s_component, - i2s->dai_drv, 1); -diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c ---- a/sound/soc/stm/stm32_sai_sub.c -+++ b/sound/soc/stm/stm32_sai_sub.c -@@ -1696,19 +1696,15 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) - - ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr, - IRQF_SHARED, dev_name(&pdev->dev), sai); -- if (ret) { -- dev_err(&pdev->dev, "IRQ request returned %d\n", ret); -+ if (ret) - goto err_unprepare_pclk; -- } - - if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) - conf = &stm32_sai_pcm_config_spdif; - - ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); -- if (ret) { -- ret = dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n"); -+ if (ret) - goto err_unprepare_pclk; -- } - - ret = snd_soc_register_component(&pdev->dev, &stm32_component, - &sai->cpu_dai_drv, 1); -diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c ---- a/sound/soc/stm/stm32_spdifrx.c -+++ b/sound/soc/stm/stm32_spdifrx.c -@@ -970,10 +970,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) - - ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, - dev_name(&pdev->dev), spdifrx); -- if (ret) { -- dev_err(&pdev->dev, "IRQ request returned %d\n", ret); -+ if (ret) - return ret; -- } - - rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) -@@ -987,7 +985,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) - pcm_config = &stm32_spdifrx_pcm_config; - ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); - if (ret) -- return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n"); -+ return ret; - - ret = snd_soc_register_component(&pdev->dev, - &stm32_spdifrx_component, -diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c ---- a/sound/soc/sunxi/sun4i-codec.c -+++ b/sound/soc/sunxi/sun4i-codec.c -@@ -22,13 +22,13 @@ - #include - - #include -+#include -+#include - #include - #include - #include - #include - #include --#include --#include - - /* Codec DAC digital controls and FIFO registers */ - #define SUN4I_CODEC_DAC_DPC (0x00) -@@ -2317,67 +2317,54 @@ static int sun4i_codec_probe(struct platform_device *pdev) - - scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base, - quirks->regmap_config); -- if (IS_ERR(scodec->regmap)) { -- dev_err(&pdev->dev, "Failed to create our regmap\n"); -- return PTR_ERR(scodec->regmap); -- } -+ if (IS_ERR(scodec->regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->regmap), -+ "Failed to create our regmap\n"); - - /* Get the clocks from the DT */ - scodec->clk_apb = devm_clk_get_enabled(&pdev->dev, "apb"); -- if (IS_ERR(scodec->clk_apb)) { -- dev_err(&pdev->dev, "Failed to get the APB clock\n"); -- return PTR_ERR(scodec->clk_apb); -- } -+ if (IS_ERR(scodec->clk_apb)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_apb), -+ "Failed to get the APB clock\n"); - - scodec->clk_module = devm_clk_get(&pdev->dev, "codec"); -- if (IS_ERR(scodec->clk_module)) { -- dev_err(&pdev->dev, "Failed to get the module clock\n"); -- return PTR_ERR(scodec->clk_module); -- } -+ if (IS_ERR(scodec->clk_module)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_module), -+ "Failed to get the module clock\n"); - - if (quirks->has_reset) { - scodec->rst = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL); -- if (IS_ERR(scodec->rst)) { -- dev_err(&pdev->dev, "Failed to get reset control\n"); -- return PTR_ERR(scodec->rst); -- } -+ if (IS_ERR(scodec->rst)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->rst), -+ "Failed to get reset control\n"); - } - - scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", - GPIOD_OUT_LOW); -- if (IS_ERR(scodec->gpio_pa)) { -- ret = PTR_ERR(scodec->gpio_pa); -- dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n"); -- return ret; -- } -+ if (IS_ERR(scodec->gpio_pa)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_pa), -+ "Failed to get pa gpio\n"); -+ - - scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); -- if (IS_ERR(scodec->gpio_hp)) { -- ret = PTR_ERR(scodec->gpio_hp); -- dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n"); -- return ret; -- } -+ if (IS_ERR(scodec->gpio_hp)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_hp), -+ "Failed to get hp-det gpio\n"); - - /* reg_field setup */ - scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, - scodec->regmap, - quirks->reg_adc_fifoc); -- if (IS_ERR(scodec->reg_adc_fifoc)) { -- ret = PTR_ERR(scodec->reg_adc_fifoc); -- dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", -- ret); -- return ret; -- } -+ if (IS_ERR(scodec->reg_adc_fifoc)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_adc_fifoc), -+ "Failed to create regmap fields\n"); - - scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev, - scodec->regmap, - quirks->reg_dac_fifoc); -- if (IS_ERR(scodec->reg_dac_fifoc)) { -- ret = PTR_ERR(scodec->reg_dac_fifoc); -- dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", -- ret); -- return ret; -- } -+ if (IS_ERR(scodec->reg_dac_fifoc)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_dac_fifoc), -+ "Failed to create regmap fields\n"); - - /* DMA configuration for TX FIFO */ - scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; -@@ -2394,39 +2381,29 @@ static int sun4i_codec_probe(struct platform_device *pdev) - - ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec, - &sun4i_codec_dai, 1); -- if (ret) { -- dev_err(&pdev->dev, "Failed to register our codec\n"); -+ if (ret) - return ret; -- } - - ret = devm_snd_soc_register_component(&pdev->dev, - &sun4i_codec_component, - &dummy_cpu_dai, 1); -- if (ret) { -- dev_err(&pdev->dev, "Failed to register our DAI\n"); -+ if (ret) - return ret; -- } - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); -- if (ret) { -- dev_err(&pdev->dev, "Failed to register against DMAEngine\n"); -+ if (ret) - return ret; -- } - - card = quirks->create_card(&pdev->dev); -- if (IS_ERR(card)) { -- ret = PTR_ERR(card); -- dev_err(&pdev->dev, "Failed to create our card\n"); -- return ret; -- } -+ if (IS_ERR(card)) -+ return PTR_ERR(card); - - snd_soc_card_set_drvdata(card, scodec); - - ret = snd_soc_register_card(card); -- if (ret) { -- dev_err_probe(&pdev->dev, ret, "Failed to register our card\n"); -- return ret; -- } -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, -+ "Failed to register our card\n"); - - return 0; - } -diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c ---- a/sound/soc/sunxi/sun4i-i2s.c -+++ b/sound/soc/sunxi/sun4i-i2s.c -@@ -1550,30 +1550,26 @@ static int sun4i_i2s_probe(struct platform_device *pdev) - } - - i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); -- if (IS_ERR(i2s->bus_clk)) { -- dev_err(&pdev->dev, "Can't get our bus clock\n"); -- return PTR_ERR(i2s->bus_clk); -- } -+ if (IS_ERR(i2s->bus_clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->bus_clk), -+ "Can't get our bus clock\n"); - - i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, - i2s->variant->sun4i_i2s_regmap); -- if (IS_ERR(i2s->regmap)) { -- dev_err(&pdev->dev, "Regmap initialisation failed\n"); -- return PTR_ERR(i2s->regmap); -- } -+ if (IS_ERR(i2s->regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), -+ "Regmap initialisation failed\n"); - - i2s->mod_clk = devm_clk_get(&pdev->dev, "mod"); -- if (IS_ERR(i2s->mod_clk)) { -- dev_err(&pdev->dev, "Can't get our mod clock\n"); -- return PTR_ERR(i2s->mod_clk); -- } -+ if (IS_ERR(i2s->mod_clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->mod_clk), -+ "Can't get our mod clock\n"); - - if (i2s->variant->has_reset) { - i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); -- if (IS_ERR(i2s->rst)) { -- dev_err(&pdev->dev, "Failed to get reset control\n"); -- return PTR_ERR(i2s->rst); -- } -+ if (IS_ERR(i2s->rst)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->rst), -+ "Failed to get reset control\n"); - } - - if (!IS_ERR(i2s->rst)) { -diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c ---- a/sound/soc/sunxi/sun4i-spdif.c -+++ b/sound/soc/sunxi/sun4i-spdif.c -@@ -684,26 +684,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev) - - host->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &sun4i_spdif_regmap_config); -- if (IS_ERR(host->regmap)) { -- dev_err(&pdev->dev, "failed to initialise regmap.\n"); -- return PTR_ERR(host->regmap); -- } -+ if (IS_ERR(host->regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(host->regmap), -+ "failed to initialise regmap.\n"); - - /* Clocks */ - host->apb_clk = devm_clk_get(&pdev->dev, "apb"); -- if (IS_ERR(host->apb_clk)) { -- dev_err(&pdev->dev, "failed to get a apb clock.\n"); -- return PTR_ERR(host->apb_clk); -- } -+ if (IS_ERR(host->apb_clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(host->apb_clk), -+ "failed to get a apb clock.\n"); - - if (quirks->tx_clk_name) - tx_clk_name = quirks->tx_clk_name; - host->spdif_clk = devm_clk_get(&pdev->dev, tx_clk_name); -- if (IS_ERR(host->spdif_clk)) { -- dev_err(&pdev->dev, "failed to get the \"%s\" clock.\n", -- tx_clk_name); -- return PTR_ERR(host->spdif_clk); -- } -+ if (IS_ERR(host->spdif_clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(host->spdif_clk), -+ "failed to get the \"%s\" clock.\n", -+ tx_clk_name); - - host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata; - host->dma_params_tx.maxburst = 8; -diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c ---- a/sound/soc/sunxi/sun50i-codec-analog.c -+++ b/sound/soc/sunxi/sun50i-codec-analog.c -@@ -551,16 +551,13 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev) - bool enable; - - base = devm_platform_ioremap_resource(pdev, 0); -- if (IS_ERR(base)) { -- dev_err(&pdev->dev, "Failed to map the registers\n"); -+ if (IS_ERR(base)) - return PTR_ERR(base); -- } - - regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); -- if (IS_ERR(regmap)) { -- dev_err(&pdev->dev, "Failed to create regmap\n"); -- return PTR_ERR(regmap); -- } -+ if (IS_ERR(regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap), -+ "Failed to create regmap\n"); - - enable = device_property_read_bool(&pdev->dev, - "allwinner,internal-bias-resistor"); -diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c ---- a/sound/soc/sunxi/sun8i-codec-analog.c -+++ b/sound/soc/sunxi/sun8i-codec-analog.c -@@ -822,16 +822,13 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev) - void __iomem *base; - - base = devm_platform_ioremap_resource(pdev, 0); -- if (IS_ERR(base)) { -- dev_err(&pdev->dev, "Failed to map the registers\n"); -+ if (IS_ERR(base)) - return PTR_ERR(base); -- } - - regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base); -- if (IS_ERR(regmap)) { -- dev_err(&pdev->dev, "Failed to create regmap\n"); -- return PTR_ERR(regmap); -- } -+ if (IS_ERR(regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap), -+ "Failed to create regmap\n"); - - return devm_snd_soc_register_component(&pdev->dev, - &sun8i_codec_analog_cmpnt_drv, -diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c ---- a/sound/soc/tegra/tegra20_das.c -+++ b/sound/soc/tegra/tegra20_das.c -@@ -167,10 +167,9 @@ static int tegra20_das_probe(struct platform_device *pdev) - - das->regmap = devm_regmap_init_mmio(&pdev->dev, regs, - &tegra20_das_regmap_config); -- if (IS_ERR(das->regmap)) { -- dev_err(&pdev->dev, "regmap init failed\n"); -- return PTR_ERR(das->regmap); -- } -+ if (IS_ERR(das->regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(das->regmap), -+ "regmap init failed\n"); - - tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_1, - TEGRA20_DAS_DAP_SEL_DAC1); -diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c ---- a/sound/soc/tegra/tegra210_adx.c -+++ b/sound/soc/tegra/tegra210_adx.c -@@ -496,16 +496,12 @@ static struct snd_kcontrol_new tegra264_adx_controls[] = { - static int tegra210_adx_component_probe(struct snd_soc_component *component) - { - struct tegra210_adx *adx = snd_soc_component_get_drvdata(component); -- int err = 0; - -- if (adx->soc_data->num_controls) { -- err = snd_soc_add_component_controls(component, adx->soc_data->controls, -- adx->soc_data->num_controls); -- if (err) -- dev_err(component->dev, "can't add ADX controls, err: %d\n", err); -- } -+ if (adx->soc_data->num_controls) -+ return snd_soc_add_component_controls(component, adx->soc_data->controls, -+ adx->soc_data->num_controls); - -- return err; -+ return 0; - } - - static const struct snd_soc_component_driver tegra210_adx_cmpnt = { -diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c ---- a/sound/soc/tegra/tegra210_amx.c -+++ b/sound/soc/tegra/tegra210_amx.c -@@ -504,16 +504,12 @@ static struct snd_kcontrol_new tegra264_amx_controls[] = { - static int tegra210_amx_component_probe(struct snd_soc_component *component) - { - struct tegra210_amx *amx = snd_soc_component_get_drvdata(component); -- int err = 0; - -- if (amx->soc_data->num_controls) { -- err = snd_soc_add_component_controls(component, amx->soc_data->controls, -- amx->soc_data->num_controls); -- if (err) -- dev_err(component->dev, "can't add AMX controls, err: %d\n", err); -- } -+ if (amx->soc_data->num_controls) -+ return snd_soc_add_component_controls(component, amx->soc_data->controls, -+ amx->soc_data->num_controls); - -- return err; -+ return 0; - } - - static const struct snd_soc_component_driver tegra210_amx_cmpnt = { -diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c ---- a/sound/soc/tegra/tegra210_i2s.c -+++ b/sound/soc/tegra/tegra210_i2s.c -@@ -1090,13 +1090,13 @@ static int tegra210_i2s_probe(struct platform_device *pdev) - "can't retrieve I2S bit clock\n"); - - /* -- * Not an error, as this clock is needed only when some other I/O -- * requires input clock from current I2S instance, which is -- * configurable from DT. -+ * This clock is optional and is only needed when another I/O uses -+ * the current I2S instance as its input clock, as configured in DT. - */ -- i2s->clk_sync_input = devm_clk_get(dev, "sync_input"); -+ i2s->clk_sync_input = devm_clk_get_optional(dev, "sync_input"); - if (IS_ERR(i2s->clk_sync_input)) -- dev_dbg(dev, "can't retrieve I2S sync input clock\n"); -+ return dev_err_probe(dev, PTR_ERR(i2s->clk_sync_input), -+ "can't retrieve I2S sync input clock\n"); - - regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(regs)) -diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c ---- a/sound/soc/ti/ams-delta.c -+++ b/sound/soc/ti/ams-delta.c -@@ -562,21 +562,21 @@ static int ams_delta_probe(struct platform_device *pdev) - - card->dev = &pdev->dev; - -- handset_mute = devm_gpiod_get(card->dev, "handset_mute", -+ handset_mute = devm_gpiod_get(&pdev->dev, "handset_mute", - GPIOD_OUT_HIGH); - if (IS_ERR(handset_mute)) - return PTR_ERR(handset_mute); - -- handsfree_mute = devm_gpiod_get(card->dev, "handsfree_mute", -+ handsfree_mute = devm_gpiod_get(&pdev->dev, "handsfree_mute", - GPIOD_OUT_HIGH); - if (IS_ERR(handsfree_mute)) - return PTR_ERR(handsfree_mute); - - ret = snd_soc_register_card(card); - if (ret) { -- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); - card->dev = NULL; -- return ret; -+ return dev_err_probe(&pdev->dev, ret, -+ "snd_soc_register_card() failed\n"); - } - return 0; - } -diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c ---- a/sound/soc/ti/davinci-evm.c -+++ b/sound/soc/ti/davinci-evm.c -@@ -245,9 +245,8 @@ static int davinci_evm_probe(struct platform_device *pdev) - - snd_soc_card_set_drvdata(&evm_soc_card, drvdata); - ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); -- - if (ret) { -- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); -+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); - goto err_put; - } - -diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c ---- a/sound/soc/ti/j721e-evm.c -+++ b/sound/soc/ti/j721e-evm.c -@@ -870,10 +870,9 @@ static int j721e_soc_probe(struct platform_device *pdev) - card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes); - card->fully_routed = 1; - -- if (snd_soc_of_parse_card_name(card, "model")) { -- dev_err(&pdev->dev, "Card name is not provided\n"); -- return -ENODEV; -- } -+ ret = snd_soc_of_parse_card_name(card, "model"); -+ if (ret) -+ return ret; - - link_cnt = 0; - conf_cnt = 0; -diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c ---- a/sound/soc/ti/omap-abe-twl6040.c -+++ b/sound/soc/ti/omap-abe-twl6040.c -@@ -234,16 +234,13 @@ static int omap_abe_probe(struct platform_device *pdev) - card->dapm_routes = audio_map; - card->num_dapm_routes = ARRAY_SIZE(audio_map); - -- if (snd_soc_of_parse_card_name(card, "ti,model")) { -- dev_err(&pdev->dev, "Card name is not provided\n"); -- return -ENODEV; -- } -+ ret = snd_soc_of_parse_card_name(card, "ti,model"); -+ if (ret) -+ return ret; - - ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); -- if (ret) { -- dev_err(&pdev->dev, "Error while parsing DAPM routing\n"); -+ if (ret) - return ret; -- } - - dai_node = of_parse_phandle(node, "ti,mcpdm", 0); - if (!dai_node) { -@@ -299,8 +296,8 @@ static int omap_abe_probe(struct platform_device *pdev) - - ret = devm_snd_soc_register_card(&pdev->dev, card); - if (ret) -- dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", -- ret); -+ dev_err_probe(&pdev->dev, ret, -+ "devm_snd_soc_register_card() failed\n"); - - return ret; - } -diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c ---- a/sound/soc/ti/omap-dmic.c -+++ b/sound/soc/ti/omap-dmic.c -@@ -465,10 +465,9 @@ static int asoc_dmic_probe(struct platform_device *pdev) - mutex_init(&dmic->mutex); - - dmic->fclk = devm_clk_get(dmic->dev, "fck"); -- if (IS_ERR(dmic->fclk)) { -- dev_err(dmic->dev, "can't get fck\n"); -- return -ENODEV; -- } -+ if (IS_ERR(dmic->fclk)) -+ return dev_err_probe(dmic->dev, PTR_ERR(dmic->fclk), -+ "can't get fck\n"); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); - if (!res) { -diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c ---- a/sound/soc/ti/omap-hdmi.c -+++ b/sound/soc/ti/omap-hdmi.c -@@ -24,8 +24,6 @@ - #define DRV_NAME "omap-hdmi-audio" - - struct hdmi_audio_data { -- struct snd_soc_card *card; -- - const struct omap_hdmi_audio_ops *ops; - struct device *dssdev; - struct snd_dmaengine_dai_dma_data dma_data; -@@ -375,12 +373,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) - card->dev = dev; - - ret = devm_snd_soc_register_card(dev, card); -- if (ret) { -- dev_err(dev, "snd_soc_register_card failed (%d)\n", ret); -- return ret; -- } -+ if (ret) -+ return dev_err_probe(dev, ret, "snd_soc_register_card() failed\n"); - -- ad->card = card; - snd_soc_card_set_drvdata(card, ad); - - dev_set_drvdata(dev, ad); -diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c ---- a/sound/soc/ti/omap-twl4030.c -+++ b/sound/soc/ti/omap-twl4030.c -@@ -17,7 +17,6 @@ - */ - - #include --#include - #include - #include - -@@ -29,6 +28,7 @@ - #include "omap-mcbsp.h" - - struct omap_twl4030 { -+ struct snd_soc_jack_gpio hs_jack_gpio; - struct snd_soc_jack hs_jack; - }; - -@@ -124,38 +124,18 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { - }, - }; - --/* Headset jack detection gpios */ --static struct snd_soc_jack_gpio hs_jack_gpios[] = { -- { -- .name = "ti,jack-det", -- .report = SND_JACK_HEADSET, -- .debounce_time = 200, -- }, --}; -- --static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm, -- int connected, char *pin) --{ -- if (!connected) -- snd_soc_dapm_disable_pin(dapm, pin); --} -- - static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) - { - struct snd_soc_card *card = rtd->card; -- struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); -- struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev); -+ - struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card); -- int ret = 0; -+ int ret; - - /* - * This is a bit of a hack, but the GPIO is optional so we - * only want to add the jack detection if the GPIO is there. - */ - if (of_property_present(card->dev->of_node, "ti,jack-det-gpio")) { -- hs_jack_gpios[0].gpiod_dev = card->dev; -- hs_jack_gpios[0].idx = 0; -- - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET, - &priv->hs_jack, hs_jack_pins, -@@ -163,36 +143,19 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd) - if (ret) - return ret; - -- ret = snd_soc_jack_add_gpios(&priv->hs_jack, -- ARRAY_SIZE(hs_jack_gpios), -- hs_jack_gpios); -+ priv->hs_jack_gpio.name = "ti,jack-det"; -+ priv->hs_jack_gpio.report = SND_JACK_HEADSET; -+ priv->hs_jack_gpio.debounce_time = 200; -+ priv->hs_jack_gpio.gpiod_dev = card->dev; -+ priv->hs_jack_gpio.idx = 0; -+ -+ ret = snd_soc_jack_add_gpios(&priv->hs_jack, 1, -+ &priv->hs_jack_gpio); - if (ret) - return ret; - } - -- /* -- * NULL pdata means we booted with DT. In this case the routing is -- * provided and the card is fully routed, no need to mark pins. -- */ -- if (!pdata || !pdata->custom_routing) -- return ret; -- -- /* Disable not connected paths if not used */ -- twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk"); -- twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk"); -- twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); -- twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk"); -- twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk"); -- -- twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic"); -- twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic"); -- twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); -- twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic"); -- twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic"); -- twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic"); -- twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In"); -- -- return ret; -+ return 0; - } - - /* Digital audio interface glue - connects codec <--> CPU */ -@@ -237,11 +200,15 @@ static struct snd_soc_card omap_twl4030_card = { - - static int omap_twl4030_probe(struct platform_device *pdev) - { -- struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev); -- struct device_node *node = pdev->dev.of_node; - struct snd_soc_card *card = &omap_twl4030_card; -+ struct device_node *node, *dai_node; - struct omap_twl4030 *priv; -- int ret = 0; -+ struct property *prop; -+ int ret; -+ -+ node = pdev->dev.of_node; -+ if (!node) -+ return -ENODEV; - - card->dev = &pdev->dev; - -@@ -249,69 +216,52 @@ static int omap_twl4030_probe(struct platform_device *pdev) - if (priv == NULL) - return -ENOMEM; - -- if (node) { -- struct device_node *dai_node; -- struct property *prop; -+ ret = snd_soc_of_parse_card_name(card, "ti,model"); -+ if (ret) -+ return ret; - -- if (snd_soc_of_parse_card_name(card, "ti,model")) { -- dev_err(&pdev->dev, "Card name is not provided\n"); -- return -ENODEV; -- } -- -- dai_node = of_parse_phandle(node, "ti,mcbsp", 0); -- if (!dai_node) { -- dev_err(&pdev->dev, "McBSP node is not provided\n"); -- return -EINVAL; -- } -- omap_twl4030_dai_links[0].cpus->dai_name = NULL; -- omap_twl4030_dai_links[0].cpus->of_node = dai_node; -- -- omap_twl4030_dai_links[0].platforms->name = NULL; -- omap_twl4030_dai_links[0].platforms->of_node = dai_node; -- -- dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0); -- if (!dai_node) { -- card->num_links = 1; -- } else { -- omap_twl4030_dai_links[1].cpus->dai_name = NULL; -- omap_twl4030_dai_links[1].cpus->of_node = dai_node; -- -- omap_twl4030_dai_links[1].platforms->name = NULL; -- omap_twl4030_dai_links[1].platforms->of_node = dai_node; -- } -- -- /* Optional: audio routing can be provided */ -- prop = of_find_property(node, "ti,audio-routing", NULL); -- if (prop) { -- ret = snd_soc_of_parse_audio_routing(card, -- "ti,audio-routing"); -- if (ret) -- return ret; -- -- card->fully_routed = 1; -- } -- } else if (pdata) { -- if (pdata->card_name) { -- card->name = pdata->card_name; -- } else { -- dev_err(&pdev->dev, "Card name is not provided\n"); -- return -ENODEV; -- } -- -- if (!pdata->voice_connected) -- card->num_links = 1; -- } else { -- dev_err(&pdev->dev, "Missing pdata\n"); -+ if (!card->name) { -+ dev_err(&pdev->dev, "Card name is not provided\n"); - return -ENODEV; - } - -+ dai_node = of_parse_phandle(node, "ti,mcbsp", 0); -+ if (!dai_node) { -+ dev_err(&pdev->dev, "McBSP node is not provided\n"); -+ return -EINVAL; -+ } -+ omap_twl4030_dai_links[0].cpus->dai_name = NULL; -+ omap_twl4030_dai_links[0].cpus->of_node = dai_node; -+ -+ omap_twl4030_dai_links[0].platforms->name = NULL; -+ omap_twl4030_dai_links[0].platforms->of_node = dai_node; -+ -+ dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0); -+ if (!dai_node) { -+ card->num_links = 1; -+ } else { -+ omap_twl4030_dai_links[1].cpus->dai_name = NULL; -+ omap_twl4030_dai_links[1].cpus->of_node = dai_node; -+ -+ omap_twl4030_dai_links[1].platforms->name = NULL; -+ omap_twl4030_dai_links[1].platforms->of_node = dai_node; -+ } -+ -+ /* Optional: audio routing can be provided */ -+ prop = of_find_property(node, "ti,audio-routing", NULL); -+ if (prop) { -+ ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing"); -+ if (ret) -+ return ret; -+ -+ card->fully_routed = 1; -+ } -+ - snd_soc_card_set_drvdata(card, priv); - ret = devm_snd_soc_register_card(&pdev->dev, card); -- if (ret) { -- dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", -- ret); -- return ret; -- } -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, -+ "devm_snd_soc_register_card() failed\n"); - - return 0; - } -diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c ---- a/sound/soc/ti/rx51.c -+++ b/sound/soc/ti/rx51.c -@@ -358,21 +358,22 @@ static struct snd_soc_card rx51_sound_card = { - static int rx51_soc_probe(struct platform_device *pdev) - { - struct rx51_audio_pdata *pdata; -- struct device_node *np = pdev->dev.of_node; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; - struct snd_soc_card *card = &rx51_sound_card; - int err; - - if (!of_machine_is_compatible("nokia,omap3-n900")) - return -ENODEV; - -- card->dev = &pdev->dev; -+ card->dev = dev; - - if (np) { - struct device_node *dai_node; - - dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0); - if (!dai_node) { -- dev_err(card->dev, "McBSP node is not provided\n"); -+ dev_err(dev, "McBSP node is not provided\n"); - return -EINVAL; - } - rx51_dai[0].cpus->dai_name = NULL; -@@ -382,7 +383,7 @@ static int rx51_soc_probe(struct platform_device *pdev) - - dai_node = of_parse_phandle(np, "nokia,audio-codec", 0); - if (!dai_node) { -- dev_err(card->dev, "Codec node is not provided\n"); -+ dev_err(dev, "Codec node is not provided\n"); - return -EINVAL; - } - rx51_dai[0].codecs->name = NULL; -@@ -390,7 +391,7 @@ static int rx51_soc_probe(struct platform_device *pdev) - - dai_node = of_parse_phandle(np, "nokia,audio-codec", 1); - if (!dai_node) { -- dev_err(card->dev, "Auxiliary Codec node is not provided\n"); -+ dev_err(dev, "Auxiliary Codec node is not provided\n"); - return -EINVAL; - } - rx51_aux_dev[0].dlc.name = NULL; -@@ -400,7 +401,7 @@ static int rx51_soc_probe(struct platform_device *pdev) - - dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0); - if (!dai_node) { -- dev_err(card->dev, "Headphone amplifier node is not provided\n"); -+ dev_err(dev, "Headphone amplifier node is not provided\n"); - return -EINVAL; - } - rx51_aux_dev[1].dlc.name = NULL; -@@ -409,40 +410,36 @@ static int rx51_soc_probe(struct platform_device *pdev) - rx51_codec_conf[1].dlc.of_node = dai_node; - } - -- pdata = devm_kzalloc(card->dev, sizeof(*pdata), GFP_KERNEL); -+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (pdata == NULL) - return -ENOMEM; - - snd_soc_card_set_drvdata(card, pdata); - -- pdata->tvout_selection_gpio = devm_gpiod_get(card->dev, -+ pdata->tvout_selection_gpio = devm_gpiod_get(dev, - "tvout-selection", - GPIOD_OUT_LOW); -- if (IS_ERR(pdata->tvout_selection_gpio)) { -- dev_err(card->dev, "could not get tvout selection gpio\n"); -- return PTR_ERR(pdata->tvout_selection_gpio); -- } -+ if (IS_ERR(pdata->tvout_selection_gpio)) -+ return dev_err_probe(dev, PTR_ERR(pdata->tvout_selection_gpio), -+ "could not get tvout selection gpio\n"); - -- pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch", -+ pdata->eci_sw_gpio = devm_gpiod_get(dev, "eci-switch", - GPIOD_OUT_HIGH); -- if (IS_ERR(pdata->eci_sw_gpio)) { -- dev_err(card->dev, "could not get eci switch gpio\n"); -- return PTR_ERR(pdata->eci_sw_gpio); -- } -+ if (IS_ERR(pdata->eci_sw_gpio)) -+ return dev_err_probe(dev, PTR_ERR(pdata->eci_sw_gpio), -+ "could not get eci switch gpio\n"); - -- pdata->speaker_amp_gpio = devm_gpiod_get(card->dev, -+ pdata->speaker_amp_gpio = devm_gpiod_get(dev, - "speaker-amplifier", - GPIOD_OUT_LOW); -- if (IS_ERR(pdata->speaker_amp_gpio)) { -- dev_err(card->dev, "could not get speaker enable gpio\n"); -- return PTR_ERR(pdata->speaker_amp_gpio); -- } -+ if (IS_ERR(pdata->speaker_amp_gpio)) -+ return dev_err_probe(dev, PTR_ERR(pdata->speaker_amp_gpio), -+ "could not get speaker enable gpio\n"); - -- err = devm_snd_soc_register_card(card->dev, card); -- if (err) { -- dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err); -- return err; -- } -+ err = devm_snd_soc_register_card(dev, card); -+ if (err) -+ return dev_err_probe(dev, err, -+ "snd_soc_register_card() failed\n"); - - return 0; - } -diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c ---- a/sound/soc/uniphier/aio-cpu.c -+++ b/sound/soc/uniphier/aio-cpu.c -@@ -795,16 +795,12 @@ int uniphier_aio_probe(struct platform_device *pdev) - ret = devm_snd_soc_register_component(dev, &uniphier_aio_component, - chip->chip_spec->dais, - chip->chip_spec->num_dais); -- if (ret) { -- dev_err(dev, "Register component failed.\n"); -+ if (ret) - goto err_out_reset; -- } - - ret = uniphier_aiodma_soc_register_platform(pdev); -- if (ret) { -- dev_err(dev, "Register platform failed.\n"); -+ if (ret) - goto err_out_reset; -- } - - return 0; - -diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h ---- a/sound/soc/uniphier/aio.h -+++ b/sound/soc/uniphier/aio.h -@@ -156,7 +156,7 @@ struct uniphier_aio_selector { - int hw; - }; - --/** -+/* - * 'SoftWare MAPping' setting of UniPhier AIO registers. - * - * We have to setup 'virtual' register maps to access 'real' registers of AIO. -diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c ---- a/sound/soc/ux500/mop500.c -+++ b/sound/soc/ux500/mop500.c -@@ -68,10 +68,11 @@ static void mop500_of_node_put(void) - of_node_put(mop500_dai_links[0].codecs->of_node); - } - --static int mop500_of_probe(struct platform_device *pdev, -- struct device_node *np) -+static int mop500_of_probe(struct snd_soc_card *card) - { -+ struct device *dev = card->dev; - struct device_node *codec_np, *msp_np[2]; -+ struct device_node *np = dev->of_node; - int i; - - msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0); -@@ -79,7 +80,7 @@ static int mop500_of_probe(struct platform_device *pdev, - codec_np = of_parse_phandle(np, "stericsson,audio-codec", 0); - - if (!(msp_np[0] && msp_np[1] && codec_np)) { -- dev_err(&pdev->dev, "Phandle missing or invalid\n"); -+ dev_err(dev, "Phandle missing or invalid\n"); - for (i = 0; i < 2; i++) - of_node_put(msp_np[i]); - of_node_put(codec_np); -@@ -95,21 +96,20 @@ static int mop500_of_probe(struct platform_device *pdev, - mop500_dai_links[i].codecs->name = NULL; - } - -- snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name"); -+ snd_soc_of_parse_card_name(card, "stericsson,card-name"); - - return 0; - } - - static int mop500_probe(struct platform_device *pdev) - { -- struct device_node *np = pdev->dev.of_node; - int ret; - - dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); - - mop500_card.dev = &pdev->dev; - -- ret = mop500_of_probe(pdev, np); -+ ret = mop500_of_probe(&mop500_card); - if (ret) - return ret; - -diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c ---- a/sound/soc/ux500/mop500_ab8500.c -+++ b/sound/soc/ux500/mop500_ab8500.c -@@ -433,5 +433,5 @@ void mop500_ab8500_remove(struct snd_soc_card *card) - clk_put(drvdata->clk_ptr_ulpclk); - clk_put(drvdata->clk_ptr_intclk); - -- snd_soc_card_set_drvdata(card, drvdata); -+ snd_soc_card_set_drvdata(card, NULL); - } -diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c ---- a/sound/soc/xilinx/xlnx_formatter_pcm.c -+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c -@@ -9,8 +9,6 @@ - #include - #include - #include --#include --#include - #include - - #include -diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c ---- a/sound/soc/xilinx/xlnx_i2s.c -+++ b/sound/soc/xilinx/xlnx_i2s.c -@@ -9,9 +9,8 @@ - - #include - #include --#include --#include - #include -+#include - #include - #include - -@@ -174,7 +173,6 @@ static int xlnx_i2s_probe(struct platform_device *pdev) - int ret; - u32 format; - struct device *dev = &pdev->dev; -- struct device_node *node = dev->of_node; - - drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL); - if (!drv_data) -@@ -184,18 +182,16 @@ static int xlnx_i2s_probe(struct platform_device *pdev) - if (IS_ERR(drv_data->base)) - return PTR_ERR(drv_data->base); - -- ret = of_property_read_u32(node, "xlnx,num-channels", &drv_data->channels); -- if (ret < 0) { -- dev_err(dev, "cannot get supported channels\n"); -- return ret; -- } -+ ret = device_property_read_u32(dev, "xlnx,num-channels", &drv_data->channels); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "cannot get supported channels\n"); -+ - drv_data->channels *= 2; - -- ret = of_property_read_u32(node, "xlnx,dwidth", &drv_data->data_width); -- if (ret < 0) { -- dev_err(dev, "cannot get data width\n"); -- return ret; -- } -+ ret = device_property_read_u32(dev, "xlnx,dwidth", &drv_data->data_width); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "cannot get data width\n"); -+ - switch (drv_data->data_width) { - case 16: - format = SNDRV_PCM_FMTBIT_S16_LE; -@@ -207,7 +203,7 @@ static int xlnx_i2s_probe(struct platform_device *pdev) - return -EINVAL; - } - -- if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) { -+ if (device_is_compatible(dev, "xlnx,i2s-transmitter-1.0")) { - drv_data->dai_drv.name = "xlnx_i2s_playback"; - drv_data->dai_drv.playback.stream_name = "Playback"; - drv_data->dai_drv.playback.formats = format; -@@ -215,7 +211,7 @@ static int xlnx_i2s_probe(struct platform_device *pdev) - drv_data->dai_drv.playback.channels_max = drv_data->channels; - drv_data->dai_drv.playback.rates = SNDRV_PCM_RATE_8000_192000; - drv_data->dai_drv.ops = &xlnx_i2s_dai_ops; -- } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) { -+ } else if (device_is_compatible(dev, "xlnx,i2s-receiver-1.0")) { - drv_data->dai_drv.name = "xlnx_i2s_capture"; - drv_data->dai_drv.capture.stream_name = "Capture"; - drv_data->dai_drv.capture.formats = format; -@@ -233,10 +229,8 @@ static int xlnx_i2s_probe(struct platform_device *pdev) - - ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component, - &drv_data->dai_drv, 1); -- if (ret) { -- dev_err(&pdev->dev, "i2s component registration failed\n"); -+ if (ret) - return ret; -- } - - dev_info(&pdev->dev, "%s DAI registered\n", drv_data->dai_drv.name); - -diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c ---- a/sound/soc/xilinx/xlnx_spdif.c -+++ b/sound/soc/xilinx/xlnx_spdif.c -@@ -10,8 +10,7 @@ - #include - #include - #include --#include --#include -+#include - #include - #include - #include -@@ -242,28 +241,24 @@ static int xlnx_spdif_probe(struct platform_device *pdev) - struct spdif_dev_data *ctx; - - struct device *dev = &pdev->dev; -- struct device_node *node = dev->of_node; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->axi_clk = devm_clk_get_enabled(dev, "s_axi_aclk"); -- if (IS_ERR(ctx->axi_clk)) { -- ret = PTR_ERR(ctx->axi_clk); -- dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret); -- return ret; -- } -+ if (IS_ERR(ctx->axi_clk)) -+ return dev_err_probe(dev, PTR_ERR(ctx->axi_clk), -+ "failed to get s_axi_aclk\n"); - - ctx->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ctx->base)) - return PTR_ERR(ctx->base); - -- ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode); -- if (ret < 0) { -- dev_err(dev, "cannot get SPDIF mode\n"); -- return ret; -- } -+ ret = device_property_read_u32(dev, "xlnx,spdif-mode", &ctx->mode); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "cannot get SPDIF mode\n"); -+ - if (ctx->mode) { - dai_drv = &xlnx_spdif_tx_dai; - } else { -@@ -274,29 +269,23 @@ static int xlnx_spdif_probe(struct platform_device *pdev) - ret = devm_request_irq(dev, ret, - xlnx_spdifrx_irq_handler, - 0, "XLNX_SPDIF_RX", ctx); -- if (ret) { -- dev_err(dev, "spdif rx irq request failed\n"); -- return -ENODEV; -- } -+ if (ret) -+ return ret; - - init_waitqueue_head(&ctx->chsts_q); - dai_drv = &xlnx_spdif_rx_dai; - } - -- ret = of_property_read_u32(node, "xlnx,aud_clk_i", &ctx->aclk); -- if (ret < 0) { -- dev_err(dev, "cannot get aud_clk_i value\n"); -- return ret; -- } -+ ret = device_property_read_u32(dev, "xlnx,aud_clk_i", &ctx->aclk); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "cannot get aud_clk_i value\n"); - - dev_set_drvdata(dev, ctx); - - ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component, - dai_drv, 1); -- if (ret) { -- dev_err(dev, "SPDIF component registration failed\n"); -+ if (ret) - return ret; -- } - - writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG); - dev_info(dev, "%s DAI registered\n", dai_drv->name); -diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c ---- a/sound/soc/xtensa/xtfpga-i2s.c -+++ b/sound/soc/xtensa/xtfpga-i2s.c -@@ -533,34 +533,25 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) - int err, irq; - - i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); -- if (!i2s) { -- err = -ENOMEM; -- goto err; -- } -+ if (!i2s) -+ return -ENOMEM; -+ - platform_set_drvdata(pdev, i2s); - i2s->dev = &pdev->dev; - dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s); - - i2s->regs = devm_platform_ioremap_resource(pdev, 0); -- if (IS_ERR(i2s->regs)) { -- err = PTR_ERR(i2s->regs); -- goto err; -- } -+ if (IS_ERR(i2s->regs)) -+ return PTR_ERR(i2s->regs); - - i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs, - &xtfpga_i2s_regmap_config); -- if (IS_ERR(i2s->regmap)) { -- dev_err(&pdev->dev, "regmap init failed\n"); -- err = PTR_ERR(i2s->regmap); -- goto err; -- } -+ if (IS_ERR(i2s->regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), "regmap init failed\n"); - - i2s->clk = devm_clk_get(&pdev->dev, NULL); -- if (IS_ERR(i2s->clk)) { -- dev_err(&pdev->dev, "couldn't get clock\n"); -- err = PTR_ERR(i2s->clk); -- goto err; -- } -+ if (IS_ERR(i2s->clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->clk), "couldn't get clock\n"); - - regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG, - (0x1 << XTFPGA_I2S_CONFIG_CHANNEL_BASE)); -@@ -568,41 +559,34 @@ static int xtfpga_i2s_probe(struct platform_device *pdev) - regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, XTFPGA_I2S_INT_UNDERRUN); - - irq = platform_get_irq(pdev, 0); -- if (irq < 0) { -- err = irq; -- goto err; -- } -+ if (irq < 0) -+ return irq; -+ - err = devm_request_threaded_irq(&pdev->dev, irq, NULL, - xtfpga_i2s_threaded_irq_handler, - IRQF_SHARED | IRQF_ONESHOT, - pdev->name, i2s); -- if (err < 0) { -- dev_err(&pdev->dev, "request_irq failed\n"); -- goto err; -- } -+ if (err < 0) -+ return err; - - err = devm_snd_soc_register_component(&pdev->dev, - &xtfpga_i2s_component, - xtfpga_i2s_dai, - ARRAY_SIZE(xtfpga_i2s_dai)); -- if (err < 0) { -- dev_err(&pdev->dev, "couldn't register component\n"); -- goto err; -- } -+ if (err < 0) -+ return err; -+ - - pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - err = xtfpga_i2s_runtime_resume(&pdev->dev); -- if (err) -- goto err_pm_disable; -+ if (err) { -+ pm_runtime_disable(&pdev->dev); -+ return err; -+ } - } -- return 0; - --err_pm_disable: -- pm_runtime_disable(&pdev->dev); --err: -- dev_err(&pdev->dev, "%s: err = %d\n", __func__, err); -- return err; -+ return 0; - } - - static void xtfpga_i2s_remove(struct platform_device *pdev) diff --git a/kernel/0511-asoc-updates.patch.sig b/kernel/0511-asoc-updates.patch.sig deleted file mode 100644 index a7f9893..0000000 Binary files a/kernel/0511-asoc-updates.patch.sig and /dev/null differ diff --git a/kernel/0512-sound-fixes-1.patch b/kernel/0512-sound-fixes-1.patch deleted file mode 100644 index 7de337b..0000000 --- a/kernel/0512-sound-fixes-1.patch +++ /dev/null @@ -1,661 +0,0 @@ -diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h ---- a/include/sound/rawmidi.h -+++ b/include/sound/rawmidi.h -@@ -179,7 +179,8 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info - int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice, - int mode, struct snd_rawmidi_file *rfile, - int depth); --int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile); -+int snd_rawmidi_kernel_release_nested(struct snd_rawmidi_file *rfile, -+ int depth); - int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_params *params); - int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, -@@ -201,6 +202,11 @@ static inline int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, - return snd_rawmidi_kernel_open_nested(rmidi, subdevice, mode, rfile, 0); - } - -+static inline int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile) -+{ -+ return snd_rawmidi_kernel_release_nested(rfile, 0); -+} -+ - /* set up the tied devices */ - static inline void snd_rawmidi_tie_devices(struct snd_rawmidi *r1, - struct snd_rawmidi *r2) -diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c ---- a/sound/aoa/soundbus/i2sbus/core.c -+++ b/sound/aoa/soundbus/i2sbus/core.c -@@ -240,6 +240,8 @@ static int i2sbus_add_dev(struct macio_dev *macio, - } - for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) { - int irq = irq_of_parse_and_map(np, i); -+ if (!irq) -+ goto err; - if (request_irq(irq, ints[i], 0, dev->rnames[i], dev)) - goto err; - dev->interrupts[i] = irq; -diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c ---- a/sound/core/rawmidi.c -+++ b/sound/core/rawmidi.c -@@ -571,7 +571,6 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) - struct snd_rawmidi *rmidi; - - rmidi = rfile->rmidi; -- guard(mutex)(&rmidi->open_mutex); - if (rfile->input) { - close_substream(rmidi, rfile->input, 1); - rfile->input = NULL; -@@ -585,7 +584,8 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) - } - - /* called from sound/core/seq/seq_midi.c */ --int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile) -+int snd_rawmidi_kernel_release_nested(struct snd_rawmidi_file *rfile, -+ int depth) - { - struct snd_rawmidi *rmidi; - -@@ -593,11 +593,13 @@ int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile) - return -ENXIO; - - rmidi = rfile->rmidi; -+ mutex_lock_nested(&rmidi->open_mutex, depth); - rawmidi_release_priv(rfile); -+ mutex_unlock(&rmidi->open_mutex); - module_put(rmidi->card->module); - return 0; - } --EXPORT_SYMBOL(snd_rawmidi_kernel_release); -+EXPORT_SYMBOL(snd_rawmidi_kernel_release_nested); - - static int snd_rawmidi_release(struct inode *inode, struct file *file) - { -@@ -607,7 +609,8 @@ static int snd_rawmidi_release(struct inode *inode, struct file *file) - - rfile = file->private_data; - rmidi = rfile->rmidi; -- rawmidi_release_priv(rfile); -+ scoped_guard(mutex, &rmidi->open_mutex) -+ rawmidi_release_priv(rfile); - kfree(rfile); - module = rmidi->card->module; - snd_card_file_remove(rmidi->card, file); -diff --git a/sound/core/ump.c b/sound/core/ump.c ---- a/sound/core/ump.c -+++ b/sound/core/ump.c -@@ -1184,7 +1184,8 @@ static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream) - ump->legacy_substreams[dir][group] = NULL; - if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { - if (!--ump->legacy_out_opens) -- snd_rawmidi_kernel_release(&ump->legacy_out_rfile); -+ snd_rawmidi_kernel_release_nested(&ump->legacy_out_rfile, -+ SINGLE_DEPTH_NESTING); - } - return 0; - } -diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c ---- a/sound/hda/codecs/conexant.c -+++ b/sound/hda/codecs/conexant.c -@@ -207,7 +207,7 @@ static void cx_remove(struct hda_codec *codec) - snd_hda_gen_remove(codec); - } - --static void cx_process_headset_plugin(struct hda_codec *codec) -+static void cx_process_headset_detect_plug_type(struct hda_codec *codec) - { - unsigned int val; - unsigned int count = 0; -@@ -223,11 +223,9 @@ static void cx_process_headset_plugin(struct hda_codec *codec) - count++; - } while (count < 3); - val = snd_hda_codec_read(codec, 0x1c, 0, 0xcb0, 0x0); -- if (val & 0x800) { -- codec_dbg(codec, "headset plugin, type is CTIA\n"); -- snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); -- } else if (val & 0x400) { -- codec_dbg(codec, "headset plugin, type is OMTP\n"); -+ if (val & 0xc00) { -+ codec_dbg(codec, "headset plugin, type is %s\n", -+ val & 0x800 ? "CTIA" : "OMTP"); - snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); - } else { - codec_dbg(codec, "headphone plugin\n"); -@@ -243,10 +241,12 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ - * Check hp&mic tag to process headset plugin & plugout. - */ - mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); -- if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ -+ if (!(mic_present & AC_PINSENSE_PRESENCE)) { /* mic plugout */ - snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); -- else -- cx_process_headset_plugin(codec); -+ } else { -+ cx_process_headset_detect_plug_type(codec); -+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24); -+ } - } - - static int cx_suspend(struct hda_codec *codec) -diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c ---- a/sound/hda/codecs/realtek/alc269.c -+++ b/sound/hda/codecs/realtek/alc269.c -@@ -1370,6 +1370,61 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, - alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10); - } - -+/* -+ * HP Laptop 15-fd0xxx (SSID 103c:8bb6) Speaker Mute LED fix -+ * -+ * The speaker mute LED is controlled via VREF100 on NID 0x1a. -+ * This pin must remain powered (D0) even during suspend, otherwise -+ * the LED state is lost and the pin defaults to Hi-Z on resume, -+ * causing the LED to stop responding to mute toggles. -+ * Windows keeps this pin powered unconditionally, so matching that -+ * behavior ensures consistent LED operation across suspend/resume. -+ * The mic-mute LED is controlled via GPIO 0 with active-low polarity. -+ */ -+static unsigned int hp_8bb6_power_filter(struct hda_codec *codec, -+ hda_nid_t nid, -+ unsigned int power_state) -+{ -+ if (nid == 0x1a) -+ return AC_PWRST_D0; -+ return snd_hda_gen_path_power_filter(codec, nid, power_state); -+} -+ -+static int hp_8bb6_speaker_mute_led_set(struct led_classdev *led_cdev, -+ enum led_brightness brightness) -+{ -+ struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent); -+ unsigned int val = (brightness == LED_OFF) ? PIN_IN : PIN_VREF100; -+ -+ snd_hda_set_pin_ctl_cache(codec, 0x1a, val); -+ return 0; -+} -+ -+static void alc236_fixup_hp_15_fd0xxx(struct hda_codec *codec, -+ const struct hda_fixup *fix, -+ int action) -+{ -+ struct alc_spec *spec = codec->spec; -+ -+ switch (action) { -+ case HDA_FIXUP_ACT_PRE_PROBE: -+ spec->micmute_led_polarity = 1; -+ alc_fixup_hp_gpio_led(codec, action, 0x00, 0x01); -+ -+ spec->mute_led_polarity = 0; -+ snd_hda_gen_add_mute_led_cdev(codec, hp_8bb6_speaker_mute_led_set); -+ -+ codec->power_filter = hp_8bb6_power_filter; -+ spec->no_shutup_pins = 1; -+ break; -+ -+ case HDA_FIXUP_ACT_INIT: -+ if (spec->gen.vmaster_mute.hook) -+ snd_hda_sync_vmaster_hook(&spec->gen.vmaster_mute); -+ break; -+ } -+} -+ - static void alc285_fixup_hp_gpio_led(struct hda_codec *codec, - const struct hda_fixup *fix, int action) - { -@@ -4089,6 +4144,7 @@ enum { - ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, - ALC225_FIXUP_S3_POP_NOISE, - ALC700_FIXUP_INTEL_REFERENCE, -+ ALC700_FIXUP_INTEL_HADES_CANYON, - ALC274_FIXUP_DELL_BIND_DACS, - ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, - ALC298_FIXUP_TPT470_DOCK_FIX, -@@ -4152,6 +4208,7 @@ enum { - ALC236_FIXUP_HP_GPIO_LED, - ALC236_FIXUP_HP_MUTE_LED, - ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, -+ ALC236_FIXUP_HP_15_FD0XXX, - ALC236_FIXUP_LENOVO_INV_DMIC, - ALC298_FIXUP_SAMSUNG_AMP, - ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, -@@ -4297,6 +4354,7 @@ enum { - ALC287_FIXUP_LENOVO_LEGION_AW88399, - ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET, - ALC285_LENOVO_DAC_RENAME, -+ ALC287_FIXUP_YOGA9_SPEAKER2_TO_DAC1, - }; - - /* A special fixup for Lenovo C940 and Yoga Duet 7; -@@ -4333,6 +4391,19 @@ static void alc287_fixup_lenovo_yoga_book_9i(struct hda_codec *codec, - __snd_hda_apply_fixup(codec, id, action, 0); - } - -+static void alc700_fixup_intel_hades_canyon(struct hda_codec *codec, -+ const struct hda_fixup *fix, -+ int action) -+{ -+ /* -+ * Windows may leave coef 0x1b bit 0x0400 cleared, causing broken -+ * analog playback after rebooting into Linux. Restore the bit -+ * during codec initialization. -+ */ -+ if (action == HDA_FIXUP_ACT_INIT) -+ alc_update_coef_idx(codec, 0x1b, 0x0400, 0x0400); -+} -+ - static const struct hda_fixup alc269_fixups[] = { - [ALC298_FIXUP_RAZER_BLADE16_2025_PINS] = { - .type = HDA_FIXUP_PINS, -@@ -5411,6 +5482,10 @@ static const struct hda_fixup alc269_fixups[] = { - {} - } - }, -+ [ALC700_FIXUP_INTEL_HADES_CANYON] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc700_fixup_intel_hades_canyon, -+ }, - [ALC274_FIXUP_DELL_BIND_DACS] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc274_fixup_bind_dacs, -@@ -5913,6 +5988,10 @@ static const struct hda_fixup alc269_fixups[] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc236_fixup_hp_mute_led_micmute_gpio, - }, -+ [ALC236_FIXUP_HP_15_FD0XXX] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc236_fixup_hp_15_fd0xxx, -+ }, - [ALC236_FIXUP_LENOVO_INV_DMIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic, -@@ -7010,6 +7089,12 @@ static const struct hda_fixup alc269_fixups[] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc285_lenovo_dac_rename, - }, -+ [ALC287_FIXUP_YOGA9_SPEAKER2_TO_DAC1] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc285_fixup_speaker2_to_dac1, -+ .chained = true, -+ .chain_id = ALC287_FIXUP_TXNW2781_I2C, -+ }, - }; - - static const struct hda_quirk alc269_fixup_tbl[] = { -@@ -7448,6 +7533,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), - SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_15_FD0XXX), - SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT), -@@ -8031,6 +8117,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x383d, "Legion Y9000X 2019", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3843, "Lenovo Yoga 9i / Yoga Book 9i", ALC287_FIXUP_LENOVO_YOGA_BOOK_9I), -+ SND_PCI_QUIRK(0x17aa, 0x3846, "Lenovo Yoga Pro 9 16IAH10", ALC287_FIXUP_YOGA9_SPEAKER2_TO_DAC1), - /* Yoga Pro 7 14IMH9 shares PCI SSID 17aa:3847 with Legion 7 16ACHG6; - * use codec SSID to distinguish them - */ -@@ -8044,14 +8131,15 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6), -+ SND_PCI_QUIRK(0x17aa, 0x3862, "Lenovo IdeaPad Slim 3 15ABR8", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - HDA_CODEC_QUIRK(0x17aa, 0x386a, "Lenovo Yoga 7 16IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1), -- HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */ - HDA_CODEC_QUIRK(0x17aa, 0x38a7, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */ -+ HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */ - SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C), - SND_PCI_QUIRK(0x17aa, 0x3874, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), -@@ -8231,6 +8319,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x2782, 0xa128, "Positivo N15RPE-S", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x2782, 0xa212, "Lunnen Ground 14", ALC269VC_FIXUP_LUNNEN_GROUND_14), - SND_PCI_QUIRK(0x7017, 0x2014, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER), -+ SND_PCI_QUIRK(0x8086, 0x2073, "Intel NUC 8 Hades Canyon", -+ ALC700_FIXUP_INTEL_HADES_CANYON), - SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), - SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), - SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), -diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c ---- a/sound/usb/mixer.c -+++ b/sound/usb/mixer.c -@@ -1237,21 +1237,27 @@ static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx) - } - - /* -- * Additional checks for sticky mixers -+ * Additional checks for sticky GET_CUR - * -- * Some devices' volume control mixers are sticky, which accept SET_CUR but -- * do absolutely nothing. -+ * Some devices' volume control mixers have sticky GET_CUR, which implies either -+ * stubbed SET_CUR or broken GET_CUR. For the former case, the mixer accepts -+ * SET_CUR but do absolutely nothing, so falling back to soft mixer is the only -+ * way to control the volume. For the latter case, the mixer has effective -+ * SET_CUR despite GET_CUR being constant, and the mixer is usable as long as we -+ * always provide mixer value from the ceche. - * - * Check the return values of GET_CUR with different SET_CUR values. Consider -- * the mixer as sticky if GET_CUR always returns a constant value. -+ * GET_CUR as sticky if GET_CUR always returns a constant value. - * -- * Some devices have effective SET_CUR despite GET_CUR being constant. Do not -- * consider the mixer as sticky if a quirk flag indicates that. -+ * Unfortunately, we can't distinguish between stubbed SET_CUR and broken -+ * GET_CUR with simple read-back tests. Disabling the mixer regardless and -+ * forcing userspace to use soft mixer instead can lead to audible distortion at -+ * low volume on some wireless headphones, probably due to their poorly- -+ * performed lossy codec. - * -- * Gate the registration of sticky mixers to prevent confusing userspace, so -- * that they won't cause ineffective volume control. However, for mixers with -- * effective SET_CUR but broken GET_CUR, the registration can continue normally -- * but further GET_CUR requests will be gated. -+ * Instead, mark GET_CUR as broken regardless and only provide mixer value from -+ * the cache. Users may opt into soft mixer in userspace audio stack if they -+ * need it. - */ - static int check_sticky_volume_control(struct usb_mixer_elem_info *cval, - int channel, int saved) -@@ -1271,24 +1277,13 @@ static int check_sticky_volume_control(struct usb_mixer_elem_info *cval, - return 0; - } - -- if (cval->head.mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_GET_CUR_BROKEN) { -- usb_audio_info(cval->head.mixer->chip, -- "%d:%d: broken mixer GET_CUR (%d/%d/%d => %d)\n", -- cval->head.id, mixer_ctrl_intf(cval->head.mixer), -- cval->min, cval->max, cval->res, saved); -- -- cval->get_cur_broken = 1; -- return -ENXIO; -- } -- -- usb_audio_err(cval->head.mixer->chip, -- "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n", -- cval->head.id, mixer_ctrl_intf(cval->head.mixer), -- cval->min, cval->max, cval->res, saved); - usb_audio_info(cval->head.mixer->chip, -- "check MIXER_GET_CUR_BROKEN if you believe the mixer is non-sticky"); -+ "%d:%d: broken mixer GET_CUR (%d/%d/%d => %d)\n", -+ cval->head.id, mixer_ctrl_intf(cval->head.mixer), -+ cval->min, cval->max, cval->res, saved); - -- return -ENODEV; -+ cval->get_cur_broken = 1; -+ return -ENXIO; - } - - /* -@@ -1385,8 +1380,6 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, - goto no_checks; - - ret = check_sticky_volume_control(cval, minchn, saved); -- if (ret == -ENODEV) -- goto sticky; - if (ret) - goto no_checks; - -@@ -1454,34 +1447,15 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, - } - } - -- return 0; -- --sticky: - /* -- * It makes no sense to restore the saved value for a sticky mixer, -- * since setting any value is a no-op. -- * -- * However, in some rare cases, SET_CUR is effective despite GET_CUR -- * always returns a constant value. These mixers are not sticky, but -- * there's no way to distinguish them. Without any additional -- * information, the best thing we can do is to set the mixer value to -- * the maximum before bailing out, so that a soft mixer can still reach -- * the maximum hardware volume if the mixer turns out to be non-sticky. -- * Meanwhile, all channels must be synchronized to prevent imbalance -- * volume. -+ * When GET_CUR is sticky, the saved value is bogus, so mixer values set -+ * by the sanity checks must be discarded through init_cur_mix_raw(). -+ * After that, we can clear the flag as per QUIRK_FLAG_MIXER_GET_CUR_OK. - */ -- if (!cval->cmask) { -- snd_usb_set_cur_mix_value(cval, 0, 0, cval->max); -- } else { -- idx = 0; -- for (i = 0; i < MAX_CHANNELS; i++) { -- if (cval->cmask & BIT(i)) { -- snd_usb_set_cur_mix_value(cval, i + 1, idx, cval->max); -- idx++; -- } -- } -- } -- return ret; -+ if (cval->head.mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_GET_CUR_OK) -+ cval->get_cur_broken = 0; -+ -+ return 0; - } - - #define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL) -diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c ---- a/sound/usb/mixer_maps.c -+++ b/sound/usb/mixer_maps.c -@@ -505,13 +505,13 @@ static const struct usbmix_connector_map gigabyte_b450_connector_map[] = { - {} - }; - --/* Audient iD14: FU 12 advertises Volume on only 4 of its 6 logical channels -- * and sits on the monitor mixer branch, but it is traced through to the -- * Speaker output terminal and gets named "Speaker Playback Volume". Userspace -- * then adopts it as the stream's hardware volume, and any setting below 0 dB -- * attenuates some channels but not others (20 dB imbalance at 80%). Give it a -- * non-standard name so that it is no longer taken for the stream's master -- * volume, while remaining reachable for anyone who wants the monitor gain. -+/* Audient iD14 MkI and MkII: FU 12 sits on the monitor mixer branch but is -+ * traced through to the Speaker output terminal, so it is named "Speaker -+ * Playback Volume". On MkII it controls only 4 of 6 playback channels. MkI -+ * testing found asymmetric attenuation within the main stereo pair. Userspace -+ * adopts this control as the stream's hardware volume, causing imbalance below -+ * 0 dB. Give it a non-standard name so that userspace no longer treats it as -+ * the stream master, while keeping the monitor gain reachable. - */ - static const struct usbmix_name_map audient_id14_map[] = { - { 12, "Monitor Mix Playback" }, /* FU, partial coverage */ -@@ -602,7 +602,12 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { - .map = maya44_map, - }, - { -- /* Audient iD14 */ -+ /* Audient iD14 MkI */ -+ .id = USB_ID(0x2708, 0x0002), -+ .map = audient_id14_map, -+ }, -+ { -+ /* Audient iD14 MkII */ - .id = USB_ID(0x2708, 0x0008), - .map = audient_id14_map, - }, -diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h ---- a/sound/usb/quirks-table.h -+++ b/sound/usb/quirks-table.h -@@ -1814,6 +1814,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), - } - } - }, -+{ -+ /* -+ * M-Audio Venom -+ * -+ * The AudioControl interface times out on every GET_CUR request, -+ * which adds around 47 seconds to the card registration and -+ * freezes the device, blocking streaming. -+ * Using an explicit composite quirk to skip the mixer entirely. -+ */ -+ USB_DEVICE_VENDOR_SPEC(0x0763, 0x2084), -+ QUIRK_DRIVER_INFO { -+ .vendor_name = "M-Audio", -+ .product_name = "Venom", -+ QUIRK_DATA_COMPOSITE { -+ { QUIRK_DATA_IGNORE(0) }, -+ { QUIRK_DATA_STANDARD_AUDIO(1) }, -+ { QUIRK_DATA_STANDARD_AUDIO(2) }, -+ { QUIRK_DATA_STANDARD_MIDI(3) }, -+ QUIRK_COMPOSITE_END -+ } -+ } -+}, - - /* Casio devices */ - { -diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c ---- a/sound/usb/quirks.c -+++ b/sound/usb/quirks.c -@@ -2215,10 +2215,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY), - DEVICE_FLG(0x03f0, 0x654a, /* HP 320 FHD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), -- DEVICE_FLG(0x040b, 0x0897, /* Weltrend Semiconductor, sold as Redragon H510-PRO Wireless headset */ -- QUIRK_FLAG_MIXER_GET_CUR_BROKEN), - DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */ - QUIRK_FLAG_IGNORE_CTL_ERROR), -+ DEVICE_FLG(0x041e, 0x324d, /* Creative Sound Blaster Play! 3 */ -+ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), - DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */ - QUIRK_FLAG_GET_SAMPLE_RATE), - DEVICE_FLG(0x045e, 0x083c, /* MS USB Link headset */ -@@ -2256,8 +2256,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - DEVICE_FLG(0x046d, 0x0a8f, /* Logitech H390 headset */ - QUIRK_FLAG_CTL_MSG_DELAY_1M | - QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), -- DEVICE_FLG(0x046d, 0x0af7, /* Logitech PRO X 2 LIGHTSPEED */ -- QUIRK_FLAG_MIXER_GET_CUR_BROKEN), -+ DEVICE_FLG(0x046d, 0x0aba, /* Logitech PRO X Wireless */ -+ QUIRK_FLAG_MIXER_GET_CUR_OK | -+ QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), - DEVICE_FLG(0x0499, 0x1506, /* Yamaha THR5 */ - QUIRK_FLAG_GENERIC_IMPLICIT_FB), - DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */ -@@ -2329,9 +2330,11 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - DEVICE_FLG(0x0763, 0x2031, /* M-Audio Fast Track C600 */ - QUIRK_FLAG_GENERIC_IMPLICIT_FB), - DEVICE_FLG(0x0763, 0x2080, /* M-Audio Fast Track Ultra */ -- QUIRK_FLAG_MIXER_GET_CUR_BROKEN | QUIRK_FLAG_GENERIC_IMPLICIT_FB), -+ QUIRK_FLAG_GENERIC_IMPLICIT_FB), - DEVICE_FLG(0x0763, 0x2081, /* M-Audio Fast Track Ultra */ -- QUIRK_FLAG_MIXER_GET_CUR_BROKEN | QUIRK_FLAG_GENERIC_IMPLICIT_FB), -+ QUIRK_FLAG_GENERIC_IMPLICIT_FB), -+ DEVICE_FLG(0x0763, 0x2084, /* M-Audio Venom */ -+ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_DISABLE_AUTOSUSPEND), - DEVICE_FLG(0x07fd, 0x000b, /* MOTU M Series 2nd hardware revision */ - QUIRK_FLAG_CTL_MSG_DELAY_1M), - DEVICE_FLG(0x08bb, 0x2702, /* LineX FM Transmitter */ -@@ -2370,8 +2373,6 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), - DEVICE_FLG(0x1038, 0x1294, /* SteelSeries Arctis Pro Wireless */ - QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), -- DEVICE_FLG(0x1038, 0x2232, /* SteelSeries Arctis Nova 5 */ -- QUIRK_FLAG_MIXER_GET_CUR_BROKEN), - DEVICE_FLG(0x1101, 0x0003, /* Audioengine D1 */ - QUIRK_FLAG_GET_SAMPLE_RATE), - DEVICE_FLG(0x12d1, 0x3a07, /* HUAWEI USB-C HEADSET */ -@@ -2379,8 +2380,6 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY), - DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ - QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), -- DEVICE_FLG(0x1377, 0x6004, /* Sennheiser MOMENTUM 3 */ -- QUIRK_FLAG_MIXER_GET_CUR_BROKEN), - DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ - QUIRK_FLAG_GET_SAMPLE_RATE), - DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */ -@@ -2393,6 +2392,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_IFB_SILENCE_ON_EMPTY), - DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */ - QUIRK_FLAG_IGNORE_CTL_ERROR), -+ DEVICE_FLG(0x152a, 0x85dd, /* SMSL USB DAC */ -+ QUIRK_FLAG_DSD_RAW | QUIRK_FLAG_DISABLE_AUTOSUSPEND | -+ QUIRK_FLAG_SKIP_IFACE_SETUP), - DEVICE_FLG(0x152a, 0x880a, /* NeuralDSP Quad Cortex */ - 0), /* Doesn't have the vendor quirk which would otherwise apply */ - DEVICE_FLG(0x1532, 0x055e, /* Razer Nommo V2 X */ -@@ -2505,8 +2507,6 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_CTL_MSG_DELAY_1M), - DEVICE_FLG(0x2d99, 0x0026, /* HECATE G2 GAMING HEADSET */ - QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE), -- DEVICE_FLG(0x2d99, 0xa024, /* Edifier MF200 */ -- QUIRK_FLAG_MIXER_GET_CUR_BROKEN), - DEVICE_FLG(0x2fc6, 0xf06b, /* MOONDROP Moonriver2 Ti */ - QUIRK_FLAG_CTL_MSG_DELAY), - DEVICE_FLG(0x2fc6, 0xf0b5, /* iBasso DC-Elite */ -@@ -2647,7 +2647,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = { - QUIRK_STRING_ENTRY(MIXER_PLAYBACK_LINEAR_VOL), - QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL), - QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY), -- QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN), -+ QUIRK_STRING_ENTRY(MIXER_GET_CUR_OK), - QUIRK_STRING_ENTRY(PLAYBACK_URB_FIXUP), - QUIRK_STRING_ENTRY(ALWAYS_SET_RATE), - NULL -diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h ---- a/sound/usb/usbaudio.h -+++ b/sound/usb/usbaudio.h -@@ -243,24 +243,18 @@ extern bool snd_usb_skip_validation; - * from snd_usb_handle_sync_urb. Instead fall through and enqueue a - * packet_info containing only size-0 packets, so the OUT ring keeps - * moving (emits silence). Needed by Behringer Flow 8 (1397:050c). -- * QUIRK_FLAG_MIXER_GET_CUR_BROKEN -- * Some mixers are sticky, which means that setting their current volume is a -- * no-op, and reading the current volume returns a constant value. The sticky -- * check disables these mixers to prevent confusing userspace. However, some -- * devices do have a tunable volume despite the reported current volume being -- * constant. As the sticky check can't distinguish between the two categories, -- * setting this flag tells that the device should fall into the second -- * category when GET_CUR returns a constant value, resulting in the sticky -- * check being non-fatal and only disabling GET_CUR instead of the whole mixer. -- * The current volume will then be provided by the internal cache that stores -- * the last set volume -+ * QUIRK_FLAG_MIXER_GET_CUR_OK -+ * On some devices, whether their GET_CUR being sticky depends on whether -+ * hotpluggable components are present. When the hotpluggable components are -+ * missing on probe, their GET_CUR behavior is classified as broken. Set the -+ * flag to prevent the heuristics from gating GET_CUR. - * QUIRK_FLAG_PLAYBACK_URB_FIXUP - * Set URB_ISO_ASAP flag for isochronous URBs and force nurbs to MAX_URBS. - * This is needed for devices that exhibit boot-time audio stuttering due - * to insufficient buffer depth combined with xHCI scheduling variability. - * The larger buffer (MAX_URBS = 12, ~64ms) absorbs system scheduling - * jitter during boot, while URB_ISO_ASAP ensures consistent xHCI scheduling. -- * QUIRK_FLAG_ALWAYS_SET_RATE: -+ * QUIRK_FLAG_ALWAYS_SET_RATE - * Issue SET_CUR for the sample rate even when the clock already reports the - * requested rate. A device advertising a single rate is otherwise never sent - * the request at all, and some require it before streaming will start. -@@ -297,10 +291,10 @@ enum { - QUIRK_TYPE_MIXER_PLAYBACK_LINEAR_VOL = 27, - QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28, - QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29, -- QUIRK_TYPE_MIXER_GET_CUR_BROKEN = 30, -+ QUIRK_TYPE_MIXER_GET_CUR_OK = 30, - QUIRK_TYPE_PLAYBACK_URB_FIXUP = 31, - QUIRK_TYPE_ALWAYS_SET_RATE = 32, --/* Please also edit snd_usb_audio_quirk_flag_names */ -+/* Please also edit snd_usb_audio_quirk_flag_names and alsa-configuration.rst */ - }; - - #define QUIRK_FLAG(x) BIT_U64(QUIRK_TYPE_ ## x) -@@ -335,7 +329,7 @@ enum { - #define QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL QUIRK_FLAG(MIXER_PLAYBACK_LINEAR_VOL) - #define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL) - #define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY) --#define QUIRK_FLAG_MIXER_GET_CUR_BROKEN QUIRK_FLAG(MIXER_GET_CUR_BROKEN) -+#define QUIRK_FLAG_MIXER_GET_CUR_OK QUIRK_FLAG(MIXER_GET_CUR_OK) - #define QUIRK_FLAG_PLAYBACK_URB_FIXUP QUIRK_FLAG(PLAYBACK_URB_FIXUP) - #define QUIRK_FLAG_ALWAYS_SET_RATE QUIRK_FLAG(ALWAYS_SET_RATE) - diff --git a/kernel/0512-sound-fixes-1.patch.sig b/kernel/0512-sound-fixes-1.patch.sig deleted file mode 100644 index 6645ee8..0000000 Binary files a/kernel/0512-sound-fixes-1.patch.sig and /dev/null differ diff --git a/kernel/0513-asoc-fixes-1.patch b/kernel/0513-asoc-fixes-1.patch deleted file mode 100644 index 49c1eb3..0000000 --- a/kernel/0513-asoc-fixes-1.patch +++ /dev/null @@ -1,871 +0,0 @@ -diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h ---- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h -+++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h -@@ -237,34 +237,34 @@ - /* Clock ID for RX CORE MCLK2 2X MCLK */ - #define LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 70 - --#define LAPSS_CLK_ID_QAIF_IF0_IBIT 71 --#define LAPSS_CLK_ID_QAIF_IF0_EBIT 72 --#define LAPSS_CLK_ID_QAIF_IF1_IBIT 73 --#define LAPSS_CLK_ID_QAIF_IF1_EBIT 74 --#define LAPSS_CLK_ID_QAIF_IF2_IBIT 75 --#define LAPSS_CLK_ID_QAIF_IF2_EBIT 76 --#define LAPSS_CLK_ID_QAIF_IF3_IBIT 77 --#define LAPSS_CLK_ID_QAIF_IF3_EBIT 78 --#define LAPSS_CLK_ID_QAIF_IF4_IBIT 79 --#define LAPSS_CLK_ID_QAIF_IF4_EBIT 80 --#define LAPSS_CLK_ID_QAIF_IF5_IBIT 81 --#define LAPSS_CLK_ID_QAIF_IF5_EBIT 82 --#define LAPSS_CLK_ID_QAIF_IF6_IBIT 83 --#define LAPSS_CLK_ID_QAIF_IF6_EBIT 84 --#define LAPSS_CLK_ID_QAIF_IF7_IBIT 85 --#define LAPSS_CLK_ID_QAIF_IF7_EBIT 86 --#define LAPSS_CLK_ID_QAIF_IF8_IBIT 87 --#define LAPSS_CLK_ID_QAIF_IF8_EBIT 88 --#define LAPSS_CLK_ID_QAIF_IF9_IBIT 89 --#define LAPSS_CLK_ID_QAIF_IF9_EBIT 90 --#define LAPSS_CLK_ID_QAIF_IF10_IBIT 91 --#define LAPSS_CLK_ID_QAIF_IF10_EBIT 92 --#define LAPSS_CLK_ID_QAIF_IF11_IBIT 93 --#define LAPSS_CLK_ID_QAIF_IF11_EBIT 94 --#define LAPSS_CLK_ID_QAIF_IF12_IBIT 95 --#define LAPSS_CLK_ID_QAIF_IF12_EBIT 96 --#define LAPSS_CLK_ID_VA_QAIF_IF0_IBIT 97 --#define LAPSS_CLK_ID_VA_QAIF_IF0_EBIT 98 -+#define LPASS_CLK_ID_QAIF_IF0_IBIT 71 -+#define LPASS_CLK_ID_QAIF_IF0_EBIT 72 -+#define LPASS_CLK_ID_QAIF_IF1_IBIT 73 -+#define LPASS_CLK_ID_QAIF_IF1_EBIT 74 -+#define LPASS_CLK_ID_QAIF_IF2_IBIT 75 -+#define LPASS_CLK_ID_QAIF_IF2_EBIT 76 -+#define LPASS_CLK_ID_QAIF_IF3_IBIT 77 -+#define LPASS_CLK_ID_QAIF_IF3_EBIT 78 -+#define LPASS_CLK_ID_QAIF_IF4_IBIT 79 -+#define LPASS_CLK_ID_QAIF_IF4_EBIT 80 -+#define LPASS_CLK_ID_QAIF_IF5_IBIT 81 -+#define LPASS_CLK_ID_QAIF_IF5_EBIT 82 -+#define LPASS_CLK_ID_QAIF_IF6_IBIT 83 -+#define LPASS_CLK_ID_QAIF_IF6_EBIT 84 -+#define LPASS_CLK_ID_QAIF_IF7_IBIT 85 -+#define LPASS_CLK_ID_QAIF_IF7_EBIT 86 -+#define LPASS_CLK_ID_QAIF_IF8_IBIT 87 -+#define LPASS_CLK_ID_QAIF_IF8_EBIT 88 -+#define LPASS_CLK_ID_QAIF_IF9_IBIT 89 -+#define LPASS_CLK_ID_QAIF_IF9_EBIT 90 -+#define LPASS_CLK_ID_QAIF_IF10_IBIT 91 -+#define LPASS_CLK_ID_QAIF_IF10_EBIT 92 -+#define LPASS_CLK_ID_QAIF_IF11_IBIT 93 -+#define LPASS_CLK_ID_QAIF_IF11_EBIT 94 -+#define LPASS_CLK_ID_QAIF_IF12_IBIT 95 -+#define LPASS_CLK_ID_QAIF_IF12_EBIT 96 -+#define LPASS_CLK_ID_VA_QAIF_IF0_IBIT 97 -+#define LPASS_CLK_ID_VA_QAIF_IF0_EBIT 98 - - #define LPASS_HW_AVTIMER_VOTE 101 - #define LPASS_HW_MACRO_VOTE 102 -diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c ---- a/sound/soc/amd/acp-config.c -+++ b/sound/soc/amd/acp-config.c -@@ -70,6 +70,13 @@ static const struct dmi_system_id acp70_acpi_flag_override_table[] = { - DMI_MATCH(DMI_BOARD_NAME, "8EA1"), - }, - }, -+ { -+ /* HP OmniBook X Flip 16-cc0xxx */ -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"), -+ DMI_MATCH(DMI_BOARD_NAME, "8EA2"), -+ }, -+ }, - {} - }; - -@@ -209,6 +216,20 @@ static const struct config_entry config_table[] = { - {} - }, - }, -+ { -+ .flags = FLAG_AMD_LEGACY, -+ .device = ACP_PCI_DEV_ID, -+ .dmi_table = (const struct dmi_system_id []) { -+ { -+ .matches = { -+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1060"), -+ }, -+ }, -+ {} -+ }, -+ }, - }; - - static int snd_amd_acp_acpi_find_config(struct pci_dev *pci) -diff --git a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c ---- a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c -+++ b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c -@@ -382,6 +382,14 @@ static const struct dmi_system_id acp3x_es83xx_dmi_table[] = { - }, - .driver_data = (void *)(ES83XX_ENABLE_DMIC), - }, -+ { -+ .matches = { -+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1060"), -+ }, -+ .driver_data = (void *)(ES83XX_ENABLE_DMIC), -+ }, - {} - }; - -diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c ---- a/sound/soc/amd/yc/acp6x-mach.c -+++ b/sound/soc/amd/yc/acp6x-mach.c -@@ -570,6 +570,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"), - } - }, -+ { -+ .driver_data = &acp6x_card, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R1 AMD"), -+ } -+ }, - { - .driver_data = &acp6x_card, - .matches = { -diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c ---- a/sound/soc/codecs/max98926.c -+++ b/sound/soc/codecs/max98926.c -@@ -360,7 +360,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, - regmap_write(max98926->regmap, - MAX98926_FORMAT, MAX98926_DAI_DLY_MASK); - regmap_update_bits(max98926->regmap, MAX98926_FORMAT, -- MAX98926_DAI_BCI_MASK, invert); -+ MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK, invert); - return 0; - } - -diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c ---- a/sound/soc/codecs/rt712-sdca.c -+++ b/sound/soc/codecs/rt712-sdca.c -@@ -1779,6 +1779,7 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712) - dev_dbg(dev, "%s jack/mic/amp func_status=0x%x, 0x%x, 0x%x\n", - __func__, jack_func_status, mic_func_status, amp_func_status); - -+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL3, 0x7778); - /* DMIC */ - if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { - rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526); -diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h ---- a/sound/soc/codecs/rt712-sdca.h -+++ b/sound/soc/codecs/rt712-sdca.h -@@ -74,6 +74,7 @@ struct rt712_dmic_kctrl_priv { - #define RT712_JD_PRODUCT_NUM 0x00 - #define RT712_ANALOG_BIAS_CTL3 0x04 - #define RT712_JD_CTL1 0x09 -+#define RT712_JD_CTL3 0x0b - #define RT712_IO_CTL 0x0c - #define RT712_LDO2_3_CTL1 0x0e - #define RT712_PARA_VERB_CTL 0x1a -diff --git a/sound/soc/codecs/rt766-sdca-sdw.c b/sound/soc/codecs/rt766-sdca-sdw.c ---- a/sound/soc/codecs/rt766-sdca-sdw.c -+++ b/sound/soc/codecs/rt766-sdca-sdw.c -@@ -233,6 +233,8 @@ static void rt766_sdca_sdw_remove(struct sdw_slave *slave) - static const struct sdw_device_id rt766_sdca_id[] = { - SDW_SLAVE_ENTRY_EXT(0x025d, 0x766, 0x3, 0x1, 0), - SDW_SLAVE_ENTRY_EXT(0x025d, 0x767, 0x3, 0x1, 0), -+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x766, 0x4, 0x1, 0), -+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x767, 0x4, 0x1, 0), - {}, - }; - MODULE_DEVICE_TABLE(sdw, rt766_sdca_id); -diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c ---- a/sound/soc/codecs/tac5xx2-sdw.c -+++ b/sound/soc/codecs/tac5xx2-sdw.c -@@ -55,6 +55,12 @@ - #define TAC_XU_BYPASS_REG(func, xu) \ - SDW_SDCA_CTL(TAC_FUNCTION_ID_##func, TAC_SDCA_ENT_##xu, \ - TAC_SDCA_CTL_XU_BYPASS, 0) -+#define TAC_VOLUME_REG(func, fu, ch) \ -+ SDW_SDCA_CTL(TAC_FUNCTION_ID_##func, TAC_SDCA_ENT_##fu, \ -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_##ch) -+#define TAC_GAIN_REG(func, fu, ch) \ -+ SDW_SDCA_CTL(TAC_FUNCTION_ID_##func, TAC_SDCA_ENT_##fu, \ -+ TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_##ch) - - /* mute registers */ - #define FU21_L_MUTE_REG TAC_MUTE_REG(SA, FU21, LEFT) -@@ -123,9 +129,9 @@ static const DECLARE_TLV_DB_SCALE(tac5xx2_dvc_tlv, -7200, 50, 0); - #define TAC_DOUBLE_Q78_TLV(name, func_id, ent_id) \ - SDCA_DOUBLE_Q78_TLV(name, \ - SDW_SDCA_CTL(TAC_FUNCTION_ID_##func_id, TAC_SDCA_ENT_##ent_id, \ -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), \ -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_LEFT), \ - SDW_SDCA_CTL(TAC_FUNCTION_ID_##func_id, TAC_SDCA_ENT_##ent_id, \ -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), \ -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT), \ - TAC_DVC_MIN, TAC_DVC_MAX, TAC_DVC_STEP, tac5xx2_dvc_tlv) - - struct tac5xx2_prv { -@@ -381,37 +387,53 @@ static const struct reg_default tac_reg_default[] = { - {TAC_REG_SDW(0, 1, 0x71), 0x5}, - {TAC_REG_SDW(0, 1, 0x72), 0x6}, - {TAC_REG_SDW(0, 1, 0x73), 0x7}, -+ /* SA */ -+ {TAC_MUTE_REG(SA, FU21, LEFT), 0x1}, -+ {TAC_MUTE_REG(SA, FU21, RIGHT), 0x1}, -+ {TAC_VOLUME_REG(SA, FU21, LEFT), 0x9c00}, -+ {TAC_VOLUME_REG(SA, FU21, RIGHT), 0x9c00}, -+ {TAC_MUTE_REG(SA, FU23, LEFT), 0x1}, -+ {TAC_MUTE_REG(SA, FU23, RIGHT), 0x1}, -+ {TAC_GAIN_REG(SA, FU23, LEFT), 0x0}, -+ {TAC_GAIN_REG(SA, FU23, RIGHT), 0x0}, -+ /* SM */ -+ {TAC_USAGE_REG(SM, IT11), 0x0}, -+ {TAC_USAGE_REG(SM, OT113), 0x0}, -+ {TAC_MUTE_REG(SM, FU113, LEFT), 0x1}, -+ {TAC_MUTE_REG(SM, FU113, RIGHT), 0x1}, -+ {TAC_GAIN_REG(SM, FU113, LEFT), 0x0}, -+ {TAC_GAIN_REG(SM, FU113, RIGHT), 0x0}, -+ {TAC_MUTE_REG(SM, FU11, LEFT), 0x1}, -+ {TAC_MUTE_REG(SM, FU11, RIGHT), 0x1}, -+ {TAC_GAIN_REG(SM, FU11, LEFT), 0x0}, -+ {TAC_GAIN_REG(SM, FU11, RIGHT), 0x0}, -+ {TAC_XU_BYPASS_REG(SM, XU12), 0x1}, -+ {SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_CS113, -+ TAC_SDCA_CTL_CS_SAMP_RATE_IDX, 0), 0x0}, -+ /* UAJ */ -+ {TAC_USAGE_REG(UAJ, IT33), 0x0}, -+ {TAC_USAGE_REG(UAJ, IT41), 0x0}, -+ {TAC_USAGE_REG(UAJ, OT36), 0x0}, -+ {TAC_USAGE_REG(UAJ, OT45), 0x0}, -+ {TAC_MUTE_REG(UAJ, FU41, LEFT), 0x1}, -+ {TAC_MUTE_REG(UAJ, FU41, RIGHT), 0x1}, -+ {TAC_VOLUME_REG(UAJ, FU41, LEFT), 0x0}, -+ {TAC_VOLUME_REG(UAJ, FU41, RIGHT), 0x0}, -+ {TAC_MUTE_REG(UAJ, FU36, RIGHT), 0x1}, -+ {SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU36, -+ TAC_SDCA_CHANNEL_VOLUME, TAC_JACK_MONO_CS), 0x0}, -+ {TAC_XU_BYPASS_REG(UAJ, XU42), 0x0}, -+ {SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_CS36, -+ TAC_SDCA_CTL_CS_SAMP_RATE_IDX, 0), 0x0}, -+ {SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_CS41, -+ TAC_SDCA_CTL_CS_SAMP_RATE_IDX, 0), 0x0}, - }; - - static const struct reg_sequence tac_spk_seq[] = { - REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU21, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_LEFT), 0), - REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU21, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), --}; -- --static const struct reg_sequence tac_sm_seq[] = { -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), --}; -- --static const struct reg_sequence tac_uaj_seq[] = { -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), -- REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU36, -- TAC_SDCA_CHANNEL_GAIN, TAC_JACK_MONO_CS), 0), -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT), 0), - }; - - static bool tac_volatile_reg(struct device *dev, unsigned int reg) -@@ -468,25 +490,25 @@ static int tac_sdca_mbq_size(struct device *dev, unsigned int reg) - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU21, - TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_LEFT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, -- TAC_SDCA_MASTER_GAIN, 0): -+ TAC_SDCA_CHANNEL_GAIN, 0): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_LEFT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_LEFT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_LEFT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, -- TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT): - case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU36, -- TAC_SDCA_CHANNEL_GAIN, TAC_JACK_MONO_CS): -+ TAC_SDCA_CHANNEL_VOLUME, TAC_JACK_MONO_CS): - return 2; - - default: -@@ -531,7 +553,7 @@ static const struct snd_kcontrol_new tac_uaj_controls[] = { - TAC_DOUBLE_Q78_TLV("UAJ Playback Volume", UAJ, FU41), - SDCA_SINGLE_Q78_TLV("UAJ Capture Volume", - SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU36, -- TAC_SDCA_CHANNEL_GAIN, TAC_JACK_MONO_CS), -+ TAC_SDCA_CHANNEL_VOLUME, TAC_JACK_MONO_CS), - TAC_DVC_MIN, TAC_DVC_MAX, TAC_DVC_STEP, tac5xx2_dvc_tlv), - }; - -@@ -1761,16 +1783,6 @@ static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool first) - goto io_init_err; - } - dev_dbg(dev, "smartmic init done\n"); -- -- if (first) { -- ret = regmap_multi_reg_write(tac_dev->regmap, tac_sm_seq, -- ARRAY_SIZE(tac_sm_seq)); -- if (ret) { -- dev_err(tac_dev->dev, -- "init writes failed, err=%d", ret); -- goto io_init_err; -- } -- } - } - - if (tac_dev->uaj_func_data) { -@@ -1783,14 +1795,6 @@ static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool first) - dev_dbg(dev, "uaj init done\n"); - - if (first) { -- ret = regmap_multi_reg_write(tac_dev->regmap, tac_uaj_seq, -- ARRAY_SIZE(tac_uaj_seq)); -- if (ret) { -- dev_err(tac_dev->dev, -- "init writes failed, err=%d", ret); -- goto io_init_err; -- } -- - if (tac_dev->hs_jack) { - ret = tac5xx2_jack_init(tac_dev); - if (ret) { -diff --git a/sound/soc/codecs/tac5xx2.h b/sound/soc/codecs/tac5xx2.h ---- a/sound/soc/codecs/tac5xx2.h -+++ b/sound/soc/codecs/tac5xx2.h -@@ -174,14 +174,13 @@ - #define TAC_SDCA_ENT_SAPU29 0x35 - - /* Control selector definitions */ --#define TAC_SDCA_MASTER_GAIN 0x0B - #define TAC_SDCA_MASTER_MUTE 0x01 - #define TAC_SDCA_CHANNEL_MUTE 0x01 --#define TAC_SDCA_CHANNEL_GAIN 0x02 -+#define TAC_SDCA_CHANNEL_VOLUME 0x02 - #define TAC_SDCA_POSTURENUMBER 0x10 - #define TAC_SDCA_REQUESTED_PS 0x01 - #define TAC_SDCA_ACTUAL_PS 0x10 --#define TAC_SDCA_CHANNEL_VOLUME 0x02 -+#define TAC_SDCA_CHANNEL_GAIN 0x0B - - /* 2. smart mic function */ - #define TAC_FUNCTION_ID_SM 0x2 -diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c ---- a/sound/soc/codecs/tas2783-sdw.c -+++ b/sound/soc/codecs/tas2783-sdw.c -@@ -1310,6 +1310,7 @@ static int tas_port_prep(struct sdw_slave *slave, struct sdw_prepare_ch *prep_ch - enum sdw_port_prep_ops pre_ops) - { - struct device *dev = &slave->dev; -+ struct tas2783_prv *tas_dev = dev_get_drvdata(dev); - struct sdw_dpn_prop *dpn_prop; - u32 addr; - int ret; -@@ -1321,6 +1322,25 @@ static int tas_port_prep(struct sdw_slave *slave, struct sdw_prepare_ch *prep_ch - addr = SDW_DPN_PREPARECTRL(prep_ch->num); - switch (pre_ops) { - case SDW_OPS_PORT_PRE_PREP: -+ /* -+ * The Function has to be powered before the port can complete -+ * channel preparation. hw_params() does that when a stream is -+ * set up, but a stream that is only re-prepared - as it is -+ * after the peripheral lost power in S0i3 - does not go -+ * through hw_params() again, and the peripheral is back at its -+ * PS3 reset default. Power it up here, where it is needed. -+ */ -+ scoped_guard(mutex, &tas_dev->pde_lock) -+ ret = regmap_write(tas_dev->regmap, -+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, -+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0), -+ TAS2783_SDCA_POW_STATE_ON); -+ if (ret) { -+ dev_err(dev, "power up failed for port %d, err=%d\n", -+ prep_ch->num, ret); -+ return ret; -+ } -+ - ret = sdw_write_no_pm(slave, addr, prep_ch->ch_mask); - if (ret) - dev_err(dev, "prep failed for port %d, err=%d\n", -diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c ---- a/sound/soc/loongson/loongson_card.c -+++ b/sound/soc/loongson/loongson_card.c -@@ -55,8 +55,8 @@ static const struct loongson_card_config ls2k0300_dl2k0300b_card_config = { - .add_dapm_routes = true, - }; - --static int tegra_machine_event(struct snd_soc_dapm_widget *w, -- struct snd_kcontrol *k, int event) -+static int loongson_asoc_machine_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *k, int event) - { - struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); - struct loongson_card_data *priv = snd_soc_card_get_drvdata(card); -@@ -72,9 +72,9 @@ static int tegra_machine_event(struct snd_soc_dapm_widget *w, - return 0; - } - --static const struct snd_soc_dapm_widget loongson_aosc_dapm_widgets[] = { -- SND_SOC_DAPM_HP("Headphone", tegra_machine_event), -- SND_SOC_DAPM_SPK("Speaker", tegra_machine_event), -+static const struct snd_soc_dapm_widget loongson_asoc_dapm_widgets[] = { -+ SND_SOC_DAPM_HP("Headphone", loongson_asoc_machine_event), -+ SND_SOC_DAPM_SPK("Speaker", loongson_asoc_machine_event), - }; - - /* Headphones Jack */ -@@ -314,8 +314,8 @@ static int loongson_asoc_card_probe(struct platform_device *pdev) - card->num_links = ARRAY_SIZE(loongson_dai_links); - - if (ls_priv->cfg->add_dapm_widgets) { -- card->dapm_widgets = loongson_aosc_dapm_widgets; -- card->num_dapm_widgets = ARRAY_SIZE(loongson_aosc_dapm_widgets); -+ card->dapm_widgets = loongson_asoc_dapm_widgets; -+ card->num_dapm_widgets = ARRAY_SIZE(loongson_asoc_dapm_widgets); - } - - snd_soc_card_set_drvdata(card, ls_priv); -diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c ---- a/sound/soc/qcom/common.c -+++ b/sound/soc/qcom/common.c -@@ -103,14 +103,14 @@ static int qcom_snd_parse_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd, - int ret; - - if (!link_np) -- return -EINVAL; -+ return -ENOENT; - - struct device_node *cpu_np __free(device_node) = - of_get_child_by_name(link_np, "cpu"); - struct device_node *codec_np __free(device_node) = - of_get_child_by_name(link_np, "codec"); - if (!cpu_np || !codec_np) -- return -EINVAL; -+ return -ENOENT; - - ret = qcom_snd_parse_tdm_slot(cpu_np, cpu_cfg); - if (ret) -@@ -172,7 +172,7 @@ int qcom_snd_apply_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd) - - ret = qcom_snd_get_dai_tdm_slots(rtd, &cpu_cfg, &codec_cfg); - if (ret) -- return ret == -EINVAL ? 0 : ret; -+ return ret == -ENOENT ? 0 : ret; - - return qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg); - } -diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c ---- a/sound/soc/qcom/qdsp6/q6apm-dai.c -+++ b/sound/soc/qcom/qdsp6/q6apm-dai.c -@@ -216,7 +216,7 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, - { - struct snd_pcm_runtime *runtime = substream->runtime; - struct q6apm_dai_rtd *prtd = runtime->private_data; -- struct audioreach_module_config cfg; -+ struct audioreach_module_config cfg = {}; - struct device *dev = component->dev; - struct q6apm_dai_data *pdata; - int ret; -@@ -814,7 +814,7 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component, - struct snd_compr_runtime *runtime = stream->runtime; - struct q6apm_dai_rtd *prtd = runtime->private_data; - struct q6apm_dai_data *pdata; -- struct audioreach_module_config cfg; -+ struct audioreach_module_config cfg = {}; - struct snd_codec *codec = ¶ms->codec; - int dir = stream->direction; - int ret; -diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c ---- a/sound/soc/qcom/qdsp6/q6prm-clocks.c -+++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c -@@ -64,34 +64,34 @@ static const struct q6dsp_clk_init q6prm_clks[] = { - Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_MCLK), - Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK), - Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF0_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF0_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF1_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF1_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF2_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF2_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF3_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF3_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF4_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF4_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF5_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF5_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF6_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF6_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF7_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF7_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF8_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF8_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF9_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF9_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF10_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF10_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF11_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF11_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF12_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF12_EBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_VA_QAIF_IF0_IBIT), -- Q6PRM_CLK(LAPSS_CLK_ID_VA_QAIF_IF0_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF0_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF0_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF1_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF1_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF2_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF2_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF3_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF3_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF4_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF4_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF5_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF5_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF6_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF6_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF7_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF7_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF8_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF8_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF9_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF9_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF10_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF10_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF11_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF11_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF12_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_QAIF_IF12_EBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_VA_QAIF_IF0_IBIT), -+ Q6PRM_CLK(LPASS_CLK_ID_VA_QAIF_IF0_EBIT), - Q6DSP_VOTE_CLK(LPASS_HW_MACRO_VOTE, Q6PRM_HW_CORE_ID_LPASS, - "LPASS_HW_MACRO"), - Q6DSP_VOTE_CLK(LPASS_HW_DCODEC_VOTE, Q6PRM_HW_CORE_ID_DCODEC, -diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h ---- a/sound/soc/qcom/qdsp6/q6prm.h -+++ b/sound/soc/qcom/qdsp6/q6prm.h -@@ -97,34 +97,34 @@ - /* Clock ID for RX CORE MCLK2 2X MCLK */ - #define Q6PRM_LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 0x318 - --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF0_IBIT 0x500 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF0_EBIT 0x501 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF1_IBIT 0x502 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF1_EBIT 0x503 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF2_IBIT 0x504 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF2_EBIT 0x505 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF3_IBIT 0x506 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF3_EBIT 0x507 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF4_IBIT 0x508 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF4_EBIT 0x509 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF5_IBIT 0x50A --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF5_EBIT 0x50B --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF6_IBIT 0x50C --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF6_EBIT 0x50D --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF7_IBIT 0x50E --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF7_EBIT 0x50F --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF8_IBIT 0x510 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF8_EBIT 0x511 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF9_IBIT 0x512 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF9_EBIT 0x513 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF10_IBIT 0x514 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF10_EBIT 0x515 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF11_IBIT 0x516 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF11_EBIT 0x517 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF12_IBIT 0x518 --#define Q6PRM_LAPSS_CLK_ID_QAIF_IF12_EBIT 0x519 --#define Q6PRM_LAPSS_CLK_ID_VA_QAIF_IF0_IBIT 0x550 --#define Q6PRM_LAPSS_CLK_ID_VA_QAIF_IF0_EBIT 0x551 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF0_IBIT 0x500 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF0_EBIT 0x501 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF1_IBIT 0x502 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF1_EBIT 0x503 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF2_IBIT 0x504 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF2_EBIT 0x505 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF3_IBIT 0x506 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF3_EBIT 0x507 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF4_IBIT 0x508 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF4_EBIT 0x509 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF5_IBIT 0x50A -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF5_EBIT 0x50B -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF6_IBIT 0x50C -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF6_EBIT 0x50D -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF7_IBIT 0x50E -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF7_EBIT 0x50F -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF8_IBIT 0x510 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF8_EBIT 0x511 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF9_IBIT 0x512 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF9_EBIT 0x513 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF10_IBIT 0x514 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF10_EBIT 0x515 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF11_IBIT 0x516 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF11_EBIT 0x517 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF12_IBIT 0x518 -+#define Q6PRM_LPASS_CLK_ID_QAIF_IF12_EBIT 0x519 -+#define Q6PRM_LPASS_CLK_ID_VA_QAIF_IF0_IBIT 0x550 -+#define Q6PRM_LPASS_CLK_ID_VA_QAIF_IF0_EBIT 0x551 - - #define Q6PRM_LPASS_CLK_SRC_INTERNAL 1 - #define Q6PRM_LPASS_CLK_ROOT_DEFAULT 0 -diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c ---- a/sound/soc/qcom/sc8280xp.c -+++ b/sound/soc/qcom/sc8280xp.c -@@ -115,33 +115,42 @@ static int sc8280xp_tdm_hw_params(struct snd_pcm_substream *substream, - struct snd_soc_dai *codec_dai; - struct qcom_snd_tdm_slot_cfg cpu_cfg; - struct qcom_snd_tdm_slot_cfg codec_cfg; -- unsigned int bclk_freq; -+ int bclk_freq; - int ret; - int i; - - ret = qcom_snd_get_dai_tdm_slots(rtd, &cpu_cfg, &codec_cfg); - if (ret) -- return ret == -EINVAL ? 0 : ret; -+ return ret == -ENOENT ? 0 : ret; - - if (!cpu_cfg.slots) - return 0; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); -- if (ret) -+ if (ret && ret != -ENOTSUPP) - return ret; - -+ if (data->priv->codec_dai_fmt) { -+ for_each_rtd_codec_dais(rtd, i, codec_dai) { -+ ret = snd_soc_dai_set_fmt(codec_dai, -+ data->priv->codec_dai_fmt); -+ if (ret && ret != -ENOTSUPP) -+ return ret; -+ } -+ } -+ - ret = qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg); - if (ret) - return ret; - - bclk_freq = snd_soc_tdm_params_to_bclk(params, cpu_cfg.slot_width, cpu_cfg.slots, 1); -- if (!bclk_freq) -+ if (bclk_freq <= 0) - return -EINVAL; - - if (data->priv->mi2s_bclk_enable) { - ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_MI2S_BCLK, bclk_freq, - SND_SOC_CLOCK_IN); -- if (ret) { -+ if (ret && ret != -ENOTSUPP) { - dev_err(rtd->dev, "%s: failed to set cpu sysclk: %d\n", - __func__, ret); - return ret; -@@ -152,7 +161,7 @@ static int sc8280xp_tdm_hw_params(struct snd_pcm_substream *substream, - for_each_rtd_codec_dais(rtd, i, codec_dai) { - ret = snd_soc_dai_set_sysclk(codec_dai, 0, bclk_freq, - SND_SOC_CLOCK_IN); -- if (ret) { -+ if (ret && ret != -ENOTSUPP) { - dev_err(rtd->dev, "%s: failed to set codec sysclk on %s: %d\n", - __func__, codec_dai->name, ret); - return ret; -diff --git a/sound/soc/sdw_utils/soc_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c ---- a/sound/soc/sdw_utils/soc_sdw_rt_amp.c -+++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c -@@ -252,11 +252,13 @@ int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai - if (ctx->amp_dev1) { - device_remove_software_node(ctx->amp_dev1); - put_device(ctx->amp_dev1); -+ ctx->amp_dev1 = NULL; - } - - if (ctx->amp_dev2) { - device_remove_software_node(ctx->amp_dev2); - put_device(ctx->amp_dev2); -+ ctx->amp_dev2 = NULL; - } - - return 0; -diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c ---- a/sound/soc/sdw_utils/soc_sdw_utils.c -+++ b/sound/soc/sdw_utils/soc_sdw_utils.c -@@ -81,6 +81,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* speaker */ - .direction = {true, false}, - .dai_name = "tac5xx2-aif1", -+ .component_name = "tac5572", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, - .init = asoc_sdw_ti_amp_init, -@@ -94,6 +95,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* mic */ - .direction = {false, true}, - .dai_name = "tac5xx2-aif2", -+ .component_name = "tac5572", - .dai_type = SOC_SDW_DAI_TYPE_MIC, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, - .rtd_init = asoc_sdw_ti_dmic_rtd_init, -@@ -102,6 +104,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* UAJ */ - .direction = {true, true}, - .dai_name = "tac5xx2-aif3", -+ .component_name = "tac5572", - .dai_type = SOC_SDW_DAI_TYPE_JACK, - .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, - .controls = generic_jack_controls, -@@ -122,6 +125,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* speaker with IV sense feedback */ - .direction = {true, true}, - .dai_name = "tac5xx2-aif1", -+ .component_name = "tac5672", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, - .init = asoc_sdw_ti_amp_init, -@@ -135,6 +139,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* mic */ - .direction = {false, true}, - .dai_name = "tac5xx2-aif2", -+ .component_name = "tac5672", - .dai_type = SOC_SDW_DAI_TYPE_MIC, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, - .rtd_init = asoc_sdw_ti_dmic_rtd_init, -@@ -143,6 +148,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* UAJ */ - .direction = {true, true}, - .dai_name = "tac5xx2-aif3", -+ .component_name = "tac5672", - .dai_type = SOC_SDW_DAI_TYPE_JACK, - .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, - .controls = generic_jack_controls, -@@ -163,6 +169,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* speaker with echo reference feedback */ - .direction = {true, true}, - .dai_name = "tac5xx2-aif1", -+ .component_name = "tac5682", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, - .init = asoc_sdw_ti_amp_init, -@@ -176,6 +183,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* mic */ - .direction = {false, true}, - .dai_name = "tac5xx2-aif2", -+ .component_name = "tac5682", - .dai_type = SOC_SDW_DAI_TYPE_MIC, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, - .rtd_init = asoc_sdw_ti_dmic_rtd_init, -@@ -184,6 +192,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* UAJ */ - .direction = {true, true}, - .dai_name = "tac5xx2-aif3", -+ .component_name = "tac5682", - .dai_type = SOC_SDW_DAI_TYPE_JACK, - .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, - .controls = generic_jack_controls, -@@ -203,6 +212,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - { - .direction = {true, false}, - .dai_name = "tac5xx2-aif1", -+ .component_name = "tas2883", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, - .init = asoc_sdw_ti_amp_init, -@@ -216,6 +226,7 @@ struct asoc_sdw_codec_info codec_info_list[] = { - /* mic */ - .direction = {false, true}, - .dai_name = "tac5xx2-aif2", -+ .component_name = "tas2883", - .dai_type = SOC_SDW_DAI_TYPE_MIC, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, - .rtd_init = asoc_sdw_ti_dmic_rtd_init, -@@ -1510,9 +1521,24 @@ int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) - } - - switch (cmd) { -+ case SNDRV_PCM_TRIGGER_RESUME: -+ /* -+ * The peripherals lose their port configuration when the -+ * controller is power-gated during system suspend, and an -+ * application that restarts the stream with -+ * SNDRV_PCM_IOCTL_RESUME - which platforms advertising -+ * SNDRV_PCM_INFO_RESUME allow - never goes through -+ * .prepare() again. Prepare the stream here so that the -+ * ports are reprogrammed before they are enabled; -+ * sdw_prepare_stream() reapplies the parameters without -+ * recomputing them when the stream is disabled. -+ */ -+ ret = sdw_prepare_stream(sdw_stream); -+ if (ret) -+ break; -+ fallthrough; - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -- case SNDRV_PCM_TRIGGER_RESUME: - ret = sdw_enable_stream(sdw_stream); - break; - -diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c ---- a/sound/soc/soc-generic-dmaengine-pcm.c -+++ b/sound/soc/soc-generic-dmaengine-pcm.c -@@ -397,24 +397,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, - if (PTR_ERR(chan) == -EPROBE_DEFER) - return -EPROBE_DEFER; - -- bool has_fw_node = dev->of_node || is_acpi_device_node(dev->fwnode); -- bool name_exists_in_fw = false; -- -- if (has_fw_node) -- name_exists_in_fw = device_property_match_string(dev, -- "dma-names", -- name) >= 0; -- -- if (has_fw_node && name_exists_in_fw) -- dev_warn(dev, "DTS/ACPI DMA channel '%s' request failed (%ld)\n", -- name, PTR_ERR(chan)); -- -- if (has_fw_node && !name_exists_in_fw) -- dev_warn(dev, "DTS/ACPI name '%s' not found, legacy failed (%ld)\n", -- name, PTR_ERR(chan)); -- -- if (!has_fw_node) -- dev_warn(dev, "Legacy DMA channel '%s' request failed (%ld)\n", -+ if (device_property_match_string(dev, "dma-names", name) >= 0) -+ dev_warn(dev, "dma-names has '%s' but request failed (%ld)\n", - name, PTR_ERR(chan)); - - pcm->chan[i] = NULL; diff --git a/kernel/0513-asoc-fixes-1.patch.sig b/kernel/0513-asoc-fixes-1.patch.sig deleted file mode 100644 index 2c6d29a..0000000 Binary files a/kernel/0513-asoc-fixes-1.patch.sig and /dev/null differ diff --git a/kernel/0514-sound-fixes-2.patch b/kernel/0514-sound-fixes-2.patch deleted file mode 100644 index 043c34e..0000000 --- a/kernel/0514-sound-fixes-2.patch +++ /dev/null @@ -1,362 +0,0 @@ -diff --git a/sound/hda/codecs/cirrus/cs420x.c b/sound/hda/codecs/cirrus/cs420x.c ---- a/sound/hda/codecs/cirrus/cs420x.c -+++ b/sound/hda/codecs/cirrus/cs420x.c -@@ -571,6 +571,7 @@ static const struct hda_model_fixup cs4208_models[] = { - - static const struct hda_quirk cs4208_fixup_tbl[] = { - SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO), -+ SND_PCI_QUIRK(0x8086, 0x7270, "MacBookAir 7,2", CS4208_MAC_AUTO), - {} /* terminator */ - }; - -@@ -583,6 +584,7 @@ static const struct hda_quirk cs4208_mac_fixup_tbl[] = { - SND_PCI_QUIRK(0x106b, 0x7800, "MacPro 6,1", CS4208_MACMINI), - SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11), - SND_PCI_QUIRK(0x106b, 0x7f00, "iMac 16,1", CS4208_MBP11), -+ SND_PCI_QUIRK(0x8086, 0x7270, "MacBookAir 7,2", CS4208_MBA6), - {} /* terminator */ - }; - -diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c ---- a/sound/hda/codecs/conexant.c -+++ b/sound/hda/codecs/conexant.c -@@ -249,6 +249,25 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ - } - } - -+#define SN6140_S3_AFG_D0_DELAY_MS 1000 -+ -+static void cx_set_power_state(struct hda_codec *codec, hda_nid_t fg, -+ unsigned int power_state) -+{ -+ snd_hda_codec_write_sync(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); -+ -+ /* -+ * SN6140 may not respond to AFG D0 immediately after S3. -+ * Wait before the D0 verb so the power-state command itself succeeds. -+ */ -+ if (codec->core.vendor_id == 0x14f11f87 && -+ power_state == AC_PWRST_D0 && -+ codec->core.dev.power.power_state.event == PM_EVENT_RESUME) -+ msleep(SN6140_S3_AFG_D0_DELAY_MS); -+ -+ snd_hda_codec_set_power_to_all(codec, fg, power_state); -+} -+ - static int cx_suspend(struct hda_codec *codec) - { - cx_auto_shutdown(codec); -@@ -1308,6 +1327,7 @@ static const struct hda_codec_ops cx_codec_ops = { - .init = cx_init, - .unsol_event = snd_hda_jack_unsol_event, - .suspend = cx_suspend, -+ .set_power_state = cx_set_power_state, - .check_power_status = snd_hda_gen_check_power_status, - .stream_pm = snd_hda_gen_stream_pm, - }; -diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c ---- a/sound/hda/codecs/realtek/alc269.c -+++ b/sound/hda/codecs/realtek/alc269.c -@@ -2379,6 +2379,33 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, - } - } - -+/* -+ * On the Acer Aspire A515-57G (and possibly other models sharing this -+ * board), if headphones are already inserted into the combo jack before -+ * the codec powers up (cold boot), the impedance-based headset-type -+ * sensing races and misclassifies the jack, driving the wrong output -+ * configuration (audible as missing center-panned/vocal content). A -+ * genuine physical unplug/replug after boot fixes it by forcing a fresh -+ * sense transient. Mirror that here on cold boot only: give the sense -+ * hardware time to settle, then force a fresh classification. -+ */ -+static void alc_fixup_headset_mode_acer_coldboot(struct hda_codec *codec, -+ const struct hda_fixup *fix, int action) -+{ -+ struct alc_spec *spec = codec->spec; -+ -+ alc_fixup_headset_mode(codec, fix, action); -+ -+ if (action == HDA_FIXUP_ACT_INIT && -+ !is_s3_resume(codec) && !is_s4_resume(codec) && -+ spec->current_headset_mode != ALC_HEADSET_MODE_UNPLUGGED) { -+ msleep(500); -+ spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN; -+ spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; -+ alc_fixup_headset_mode(codec, fix, action); -+ } -+} -+ - static void alc288_update_headset_jack_cb(struct hda_codec *codec, - struct hda_jack_callback *jack) - { -@@ -4248,6 +4275,7 @@ enum { - ALC282_FIXUP_ACER_DISABLE_LINEOUT, - ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST, - ALC256_FIXUP_ACER_HEADSET_MIC, -+ ALC256_FIXUP_ACER_COLDBOOT, - ALC285_FIXUP_IDEAPAD_S740_COEF, - ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST, - ALC295_FIXUP_ASUS_DACS, -@@ -6311,6 +6339,12 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC - }, -+ [ALC256_FIXUP_ACER_COLDBOOT] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = alc_fixup_headset_mode_acer_coldboot, -+ .chained = true, -+ .chain_id = ALC256_FIXUP_ACER_SFG16_MICMUTE_LED, -+ }, - [ALC285_FIXUP_IDEAPAD_S740_COEF] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc285_fixup_ideapad_s740_coef, -@@ -7148,13 +7182,14 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x159e, "Acer Nitro 5 AN515-46", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC), -- SND_PCI_QUIRK(0x1025, 0x1616, "Acer Aspire A515-57", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), -+ SND_PCI_QUIRK(0x1025, 0x1616, "Acer Aspire A515-57", ALC256_FIXUP_ACER_COLDBOOT), - SND_PCI_QUIRK(0x1025, 0x161f, "Acer S40-54", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x166c, "Acer Predator PH16-71", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED), -+ SND_PCI_QUIRK(0x1025, 0x1731, "Acer Predator PHN16-72", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x1758, "Acer Nitro ANV15-41", ALC245_FIXUP_ACER_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), -@@ -8100,6 +8135,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C), -+ SND_PCI_QUIRK(0x17aa, 0x380b, "Lenovo Yoga Slim 9 14ILL10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - /* Yoga Pro 9 16IMH9 and Legion 7 16ITHG6 share PCI SSID 17aa:3811 - * with Legion S7 15IMH05; use codec SSID to distinguish them - */ -@@ -8287,6 +8323,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1d05, 0x3034, "TongFang X6KK45xU", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1d05, 0x30ba, "TongFang XxAF5xxx", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS), -+ SND_PCI_QUIRK(0x1d19, 0x0006, "VAIO VJS131", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC), - SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), -diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c ---- a/sound/usb/fcp.c -+++ b/sound/usb/fcp.c -@@ -191,6 +191,10 @@ static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode, - const int max_retries = 5; - int err; - -+ CLASS(snd_usb_lock, pm)(mixer->chip); -+ if (pm.err < 0) -+ return -EIO; -+ - if (!private->urb) - return -ENODEV; - -@@ -1026,6 +1030,10 @@ static int fcp_init(struct usb_mixer_interface *mixer, - struct usb_device *dev = mixer->chip->dev; - int err; - -+ CLASS(snd_usb_lock, pm)(mixer->chip); -+ if (pm.err < 0) -+ return -EIO; -+ - err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), - FCP_USB_REQ_STEP0, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, -diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c ---- a/sound/usb/mixer_maps.c -+++ b/sound/usb/mixer_maps.c -@@ -518,6 +518,19 @@ static const struct usbmix_name_map audient_id14_map[] = { - {} - }; - -+/* -+ * Audient iD24: feature unit 12 ("Speaker Playback Volume") sits in the -+ * monitor-mixer branch and does not apply volume to all of its channels; -+ * when userspace adopts it as the master playback volume, the left main -+ * output stays at 0 dB while the right one is attenuated, producing a -+ * stereo imbalance. Rename it so that it is not picked up as the -+ * stream's master volume control. -+ */ -+static const struct usbmix_name_map audient_id24_map[] = { -+ { 12, "Monitor Mix Playback" }, /* FU, partial channel coverage */ -+ {} -+}; -+ - /* - * Control map entries - */ -@@ -611,6 +624,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { - .id = USB_ID(0x2708, 0x0008), - .map = audient_id14_map, - }, -+ { -+ /* Audient iD24 */ -+ .id = USB_ID(0x2708, 0x000d), -+ .map = audient_id24_map, -+ }, - { - /* KEF X300A */ - .id = USB_ID(0x27ac, 0x1000), -diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c ---- a/sound/usb/mixer_quirks.c -+++ b/sound/usb/mixer_quirks.c -@@ -3480,6 +3480,10 @@ static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u - struct usb_device *dev = chip->dev; - int err; - -+ CLASS(snd_usb_lock, pm)(chip); -+ if (pm.err < 0) -+ return -EIO; -+ - err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), - item, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, -@@ -3499,6 +3503,10 @@ static int snd_rme_digiface_read_status(struct snd_kcontrol *kcontrol, u32 statu - __le32 buf[4] = {}; - int err; - -+ CLASS(snd_usb_lock, pm)(chip); -+ if (pm.err < 0) -+ return -EIO; -+ - err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), - RME_DIGIFACE_READ_STATUS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, -diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c ---- a/sound/usb/mixer_s1810c.c -+++ b/sound/usb/mixer_s1810c.c -@@ -474,6 +474,10 @@ snd_s1810c_switch_get(struct snd_kcontrol *kctl, - u32 state = 0; - int ret; - -+ CLASS(snd_usb_lock, pm)(mixer->chip); -+ if (pm.err < 0) -+ return -EIO; -+ - guard(mutex)(&private->data_mutex); - ret = snd_s1810c_get_switch_state(mixer, kctl, &state); - if (ret < 0) -@@ -504,6 +508,10 @@ snd_s1810c_switch_set(struct snd_kcontrol *kctl, - u32 newval = 0; - int ret = 0; - -+ CLASS(snd_usb_lock, pm)(mixer->chip); -+ if (pm.err < 0) -+ return -EIO; -+ - guard(mutex)(&private->data_mutex); - ret = snd_s1810c_get_switch_state(mixer, kctl, &curval); - if (ret < 0) -diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c ---- a/sound/usb/mixer_scarlett.c -+++ b/sound/usb/mixer_scarlett.c -@@ -707,6 +707,10 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, - int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8); - int err; - -+ CLASS(snd_usb_lock, pm)(chip); -+ if (pm.err < 0) -+ return -EIO; -+ - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), - UAC2_CS_MEM, -diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c ---- a/sound/usb/mixer_scarlett2.c -+++ b/sound/usb/mixer_scarlett2.c -@@ -2603,9 +2603,9 @@ static int scarlett2_usb_rx(struct usb_device *dev, int interface, - } - - /* Send a proprietary format request to the Scarlett interface */ --static int scarlett2_usb( -- struct usb_mixer_interface *mixer, u32 cmd, -- void *req_data, u16 req_size, void *resp_data, u16 resp_size) -+static int scarlett2_usb_nopm(struct usb_mixer_interface *mixer, u32 cmd, -+ void *req_data, u16 req_size, -+ void *resp_data, u16 resp_size) - { - struct scarlett2_data *private = mixer->private_data; - struct usb_device *dev = mixer->chip->dev; -@@ -2713,6 +2713,18 @@ static int scarlett2_usb( - return err; - } - -+static int scarlett2_usb(struct usb_mixer_interface *mixer, u32 cmd, -+ void *req_data, u16 req_size, -+ void *resp_data, u16 resp_size) -+{ -+ CLASS(snd_usb_lock, pm)(mixer->chip); -+ if (pm.err < 0) -+ return -EIO; -+ -+ return scarlett2_usb_nopm(mixer, cmd, req_data, req_size, -+ resp_data, resp_size); -+} -+ - /* Send a USB message to get data; result placed in *buf */ - static int scarlett2_usb_get( - struct usb_mixer_interface *mixer, -@@ -3020,9 +3032,21 @@ static int scarlett2_usb_set_config_buf( - /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ - static void scarlett2_config_save(struct usb_mixer_interface *mixer) - { -- int err; -+ __le32 req = cpu_to_le32(SCARLETT2_USB_CONFIG_SAVE); -+ int err = scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, -+ &req, sizeof(req), NULL, 0); -+ -+ if (err < 0) -+ usb_audio_err(mixer->chip, "config save failed: %d\n", err); -+} -+ -+/* The USB suspend callback must not acquire another PM reference. */ -+static void scarlett2_config_save_nopm(struct usb_mixer_interface *mixer) -+{ -+ __le32 req = cpu_to_le32(SCARLETT2_USB_CONFIG_SAVE); -+ int err = scarlett2_usb_nopm(mixer, SCARLETT2_USB_DATA_CMD, -+ &req, sizeof(req), NULL, 0); - -- err = scarlett2_usb_activate_config(mixer, SCARLETT2_USB_CONFIG_SAVE); - if (err < 0) - usb_audio_err(mixer->chip, "config save failed: %d\n", err); - } -@@ -8639,7 +8663,7 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) - struct scarlett2_data *private = mixer->private_data; - - if (cancel_delayed_work_sync(&private->work)) -- scarlett2_config_save(private->mixer); -+ scarlett2_config_save_nopm(private->mixer); - - scarlett2_cleanup_urb(mixer); - } -diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c ---- a/sound/usb/mixer_us16x08.c -+++ b/sound/usb/mixer_us16x08.c -@@ -151,6 +151,9 @@ static const char *const route_names[] = { - static int snd_us16x08_recv_urb(struct snd_usb_audio *chip, - unsigned char *buf, int size) - { -+ CLASS(snd_usb_lock, pm)(chip); -+ if (pm.err < 0) -+ return -EIO; - - guard(mutex)(&chip->mutex); - snd_usb_ctl_msg(chip->dev, -@@ -165,6 +168,10 @@ static int snd_us16x08_recv_urb(struct snd_usb_audio *chip, - */ - static int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size) - { -+ CLASS(snd_usb_lock, pm)(chip); -+ if (pm.err < 0) -+ return -EIO; -+ - return snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), - SND_US16X08_URB_REQUEST, SND_US16X08_URB_REQUESTTYPE, - 0, 0, buf, size); diff --git a/kernel/0514-sound-fixes-2.patch.sig b/kernel/0514-sound-fixes-2.patch.sig deleted file mode 100644 index fce1ac9..0000000 Binary files a/kernel/0514-sound-fixes-2.patch.sig and /dev/null differ diff --git a/kernel/0515-xps13-sof-quirk.patch b/kernel/0515-xps13-sof-quirk.patch deleted file mode 100644 index 6a5a07c..0000000 --- a/kernel/0515-xps13-sof-quirk.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c ---- a/sound/soc/intel/boards/sof_sdw.c -+++ b/sound/soc/intel/boards/sof_sdw.c -@@ -845,6 +845,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { - }, - .driver_data = (void *)(SOC_SDW_PCH_DMIC), - }, -+ { -+ /* Dell XPS 13 DX13260 (Wildcat Lake), CS42L43 + 2x CS35L63 sidecar amps */ -+ .callback = sof_sdw_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0E53") -+ }, -+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), -+ }, - {} - }; - diff --git a/kernel/0515-xps13-sof-quirk.patch.sig b/kernel/0515-xps13-sof-quirk.patch.sig deleted file mode 100644 index 3ded939..0000000 Binary files a/kernel/0515-xps13-sof-quirk.patch.sig and /dev/null differ diff --git a/kernel/0516-rt766-stream-config-type.patch b/kernel/0516-rt766-stream-config-type.patch deleted file mode 100644 index 25fee81..0000000 --- a/kernel/0516-rt766-stream-config-type.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/sound/soc/codecs/rt766-sdca.c b/sound/soc/codecs/rt766-sdca.c ---- a/sound/soc/codecs/rt766-sdca.c -+++ b/sound/soc/codecs/rt766-sdca.c -@@ -936,9 +936,8 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - { - struct snd_soc_component *component = dai->component; - struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component); -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; -- enum sdw_data_direction direction; - struct sdw_stream_runtime *sdw_stream; - unsigned int sampling_rate; - int retval, port; -@@ -957,7 +956,6 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - - /* SoundWire specific configuration */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- direction = SDW_DATA_DIR_RX; - if (dai->id == RT766_AIF1) - port = 3; - else if (dai->id == RT766_AIF2) -@@ -965,7 +963,6 @@ static int rt766_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - else - return -EINVAL; - } else { -- direction = SDW_DATA_DIR_TX; - if (dai->id == RT766_AIF1) - port = 12; - else if (dai->id == RT766_AIF3) diff --git a/kernel/0516-rt766-stream-config-type.patch.sig b/kernel/0516-rt766-stream-config-type.patch.sig deleted file mode 100644 index 47fe225..0000000 Binary files a/kernel/0516-rt766-stream-config-type.patch.sig and /dev/null differ diff --git a/kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch b/kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch deleted file mode 100644 index 47dae22..0000000 --- a/kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch +++ /dev/null @@ -1,39 +0,0 @@ -diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c ---- a/sound/hda/codecs/realtek/alc269.c -+++ b/sound/hda/codecs/realtek/alc269.c -@@ -4226,6 +4226,7 @@ enum { - ALC294_FIXUP_ASUS_GU502_VERBS, - ALC294_FIXUP_ASUS_G513_PINS, - ALC285_FIXUP_ASUS_G533Z_PINS, -+ ALC285_FIXUP_ASUS_G733Z_VERBS, - ALC285_FIXUP_HP_GPIO_LED, - ALC285_FIXUP_HP_MUTE_LED, - ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED, -@@ -7129,6 +7130,19 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC287_FIXUP_TXNW2781_I2C, - }, -+ [ALC285_FIXUP_ASUS_G733Z_VERBS] = { -+ .type = HDA_FIXUP_VERBS, -+ .v.verbs = (const struct hda_verb[]) { -+ /* Enables internal speaker */ -+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, -+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, -+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, -+ {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, -+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, -+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, -+ { } -+ } -+ }, - }; - - static const struct hda_quirk alc269_fixup_tbl[] = { -@@ -7775,6 +7789,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x12a3, "Asus N7691ZM", ALC269_FIXUP_ASUS_N7601ZM), - SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x12b4, "ASUS B3405CCA / P3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2), -+ SND_PCI_QUIRK(0x1043, 0x12bf, "ASUS ROG Strix G733ZW", ALC285_FIXUP_ASUS_G733Z_VERBS), - SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), diff --git a/kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch.sig b/kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch.sig deleted file mode 100644 index edb27fd..0000000 Binary files a/kernel/0517-hda-realtek-rog-strix-g733zw-speakers.patch.sig and /dev/null differ diff --git a/kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch b/kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch deleted file mode 100644 index 0d8e619..0000000 --- a/kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c ---- a/sound/soc/amd/yc/acp6x-mach.c -+++ b/sound/soc/amd/yc/acp6x-mach.c -@@ -619,6 +619,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Swift SFA16-41"), - } - }, -+ { -+ .driver_data = &acp6x_card, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "MDU"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A314-23P"), -+ } -+ }, - { - .driver_data = &acp6x_card, - .matches = { diff --git a/kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch.sig b/kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch.sig deleted file mode 100644 index a16f394..0000000 Binary files a/kernel/0518-asoc-amd-yc-acer-aspire-a314-23p.patch.sig and /dev/null differ diff --git a/kernel/0522-sound-fixes-3.patch b/kernel/0522-sound-fixes-3.patch deleted file mode 100644 index 48c9872..0000000 --- a/kernel/0522-sound-fixes-3.patch +++ /dev/null @@ -1,432 +0,0 @@ -diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c ---- a/sound/hda/codecs/realtek/alc269.c -+++ b/sound/hda/codecs/realtek/alc269.c -@@ -7465,6 +7465,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x887c, "HP Laptop 14s-fq1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x888a, "HP ENVY x360 Convertible 15-eu0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), - SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED), -+ SND_PCI_QUIRK(0x103c, 0x8890, "HP Elite Dragonfly Max G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT), - SND_PCI_QUIRK(0x103c, 0x8895, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED), - SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), -@@ -7580,6 +7581,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), - SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), -+ SND_PCI_QUIRK(0x103c, 0x8ba9, "HP Omen 16-wd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_15_FD0XXX), -diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c ---- a/sound/pci/rme9652/hdspm.c -+++ b/sound/pci/rme9652/hdspm.c -@@ -1071,14 +1071,8 @@ struct hdspm { - - - static const struct pci_device_id snd_hdspm_ids[] = { -- { -- .vendor = PCI_VENDOR_ID_XILINX, -- .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, -- .subvendor = PCI_ANY_ID, -- .subdevice = PCI_ANY_ID, -- .class = 0, -- .class_mask = 0, -- .driver_data = 0}, -+ { PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI) }, -+ { PCI_DEVICE(0x1d18, 0x3fc6) }, /* RME HDSPe AIO PCI express audio */ - {0,} - }; - -diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c ---- a/sound/usb/hiface/pcm.c -+++ b/sound/usb/hiface/pcm.c -@@ -24,7 +24,7 @@ - struct pcm_urb { - struct hiface_chip *chip; - -- struct urb instance; -+ struct urb *instance; - struct usb_anchor submitted; - u8 *buffer; - }; -@@ -193,7 +193,7 @@ static void hiface_pcm_stream_stop(struct pcm_runtime *rt) - if (!time) - usb_kill_anchored_urbs( - &rt->out_urbs[i].submitted); -- usb_kill_urb(&rt->out_urbs[i].instance); -+ usb_kill_urb(rt->out_urbs[i].instance); - } - - rt->stream_state = STREAM_DISABLED; -@@ -215,9 +215,9 @@ static int hiface_pcm_stream_start(struct pcm_runtime *rt) - rt->stream_state = STREAM_STARTING; - for (i = 0; i < PCM_N_URBS; i++) { - memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE); -- usb_anchor_urb(&rt->out_urbs[i].instance, -+ usb_anchor_urb(rt->out_urbs[i].instance, - &rt->out_urbs[i].submitted); -- ret = usb_submit_urb(&rt->out_urbs[i].instance, -+ ret = usb_submit_urb(rt->out_urbs[i].instance, - GFP_ATOMIC); - if (ret) { - hiface_pcm_stream_stop(rt); -@@ -334,7 +334,7 @@ static void hiface_pcm_out_urb_handler(struct urb *usb_urb) - if (do_period_elapsed) - snd_pcm_period_elapsed(sub->instance); - -- ret = usb_submit_urb(&out_urb->instance, GFP_ATOMIC); -+ ret = usb_submit_urb(out_urb->instance, GFP_ATOMIC); - if (ret < 0) - goto out_fail; - -@@ -492,16 +492,18 @@ static int hiface_pcm_init_urb(struct pcm_urb *urb, - void (*handler)(struct urb *)) - { - urb->chip = chip; -- usb_init_urb(&urb->instance); -+ urb->instance = usb_alloc_urb(0, GFP_KERNEL); -+ if (!urb->instance) -+ return -ENOMEM; - - urb->buffer = kzalloc(PCM_PACKET_SIZE, GFP_KERNEL); - if (!urb->buffer) - return -ENOMEM; - -- usb_fill_bulk_urb(&urb->instance, chip->dev, -+ usb_fill_bulk_urb(urb->instance, chip->dev, - usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer, - PCM_PACKET_SIZE, handler, urb); -- if (usb_urb_ep_type_check(&urb->instance)) -+ if (usb_urb_ep_type_check(urb->instance)) - return -EINVAL; - init_usb_anchor(&urb->submitted); - -@@ -520,24 +522,26 @@ void hiface_pcm_abort(struct hiface_chip *chip) - } - } - --static void hiface_pcm_destroy(struct hiface_chip *chip) -+static void hiface_pcm_destroy(struct pcm_runtime *rt) - { -- struct pcm_runtime *rt = chip->pcm; - int i; - -- for (i = 0; i < PCM_N_URBS; i++) -- kfree(rt->out_urbs[i].buffer); -+ if (!rt) -+ return; - -- kfree(chip->pcm); -- chip->pcm = NULL; -+ if (rt->chip) -+ rt->chip->pcm = NULL; -+ -+ for (i = 0; i < PCM_N_URBS; i++) { -+ usb_free_urb(rt->out_urbs[i].instance); -+ kfree(rt->out_urbs[i].buffer); -+ } -+ kfree(rt); - } - - static void hiface_pcm_free(struct snd_pcm *pcm) - { -- struct pcm_runtime *rt = pcm->private_data; -- -- if (rt) -- hiface_pcm_destroy(rt->chip); -+ hiface_pcm_destroy(pcm->private_data); - } - - int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) -@@ -587,8 +591,6 @@ int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) - return 0; - - error: -- for (i = 0; i < PCM_N_URBS; i++) -- kfree(rt->out_urbs[i].buffer); -- kfree(rt); -+ hiface_pcm_destroy(rt); - return ret; - } -diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c ---- a/sound/usb/misc/ua101.c -+++ b/sound/usb/misc/ua101.c -@@ -109,10 +109,10 @@ struct ua101 { - unsigned int buffer_pos; - unsigned int queue_length; - struct ua101_urb { -- struct urb urb; -- struct usb_iso_packet_descriptor iso_frame_desc[1]; -+ struct urb *urb; - struct list_head ready_list; -- } *urbs[MAX_QUEUE_LENGTH]; -+ struct ua101 *ua; -+ } urbs[MAX_QUEUE_LENGTH]; - struct { - unsigned int size; - void *addr; -@@ -167,15 +167,15 @@ static void abort_usb_playback(struct ua101 *ua) - wake_up(&ua->alsa_playback_wait); - } - --static void playback_urb_complete(struct urb *usb_urb) -+static void playback_urb_complete(struct urb *urb) - { -- struct ua101_urb *urb = (struct ua101_urb *)usb_urb; -- struct ua101 *ua = urb->urb.context; -+ struct ua101_urb *ua_urb = urb->context; -+ struct ua101 *ua = ua_urb->ua; - -- if (unlikely(urb->urb.status == -ENOENT || /* unlinked */ -- urb->urb.status == -ENODEV || /* device removed */ -- urb->urb.status == -ECONNRESET || /* unlinked */ -- urb->urb.status == -ESHUTDOWN)) { /* device disabled */ -+ if (unlikely(urb->status == -ENOENT || /* unlinked */ -+ urb->status == -ENODEV || /* device removed */ -+ urb->status == -ECONNRESET || /* unlinked */ -+ urb->status == -ESHUTDOWN)) { /* device disabled */ - abort_usb_playback(ua); - abort_alsa_playback(ua); - return; -@@ -184,18 +184,19 @@ static void playback_urb_complete(struct urb *usb_urb) - if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) { - /* append URB to FIFO */ - guard(spinlock_irqsave)(&ua->lock); -- list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); -+ list_add_tail(&ua_urb->ready_list, &ua->ready_playback_urbs); - if (ua->rate_feedback_count > 0) - queue_work(system_highpri_wq, &ua->playback_work); - ua->playback.substream->runtime->delay -= -- urb->urb.iso_frame_desc[0].length / -+ urb->iso_frame_desc[0].length / - ua->playback.frame_bytes; - } - } - - static void first_playback_urb_complete(struct urb *urb) - { -- struct ua101 *ua = urb->context; -+ struct ua101_urb *ua_urb = urb->context; -+ struct ua101 *ua = ua_urb->ua; - - urb->complete = playback_urb_complete; - playback_urb_complete(urb); -@@ -248,7 +249,8 @@ static void playback_work(struct work_struct *work) - { - struct ua101 *ua = container_of(work, struct ua101, playback_work); - unsigned int frames; -- struct ua101_urb *urb; -+ struct ua101_urb *ua_urb; -+ struct urb *urb; - bool do_period_elapsed = false; - int err; - -@@ -275,23 +277,24 @@ static void playback_work(struct work_struct *work) - ua->rate_feedback_count--; - - /* take URB out of FIFO */ -- urb = list_first_entry(&ua->ready_playback_urbs, -- struct ua101_urb, ready_list); -- list_del(&urb->ready_list); -+ ua_urb = list_first_entry(&ua->ready_playback_urbs, -+ struct ua101_urb, ready_list); -+ list_del(&ua_urb->ready_list); -+ urb = ua_urb->urb; - - /* fill packet with data or silence */ -- urb->urb.iso_frame_desc[0].length = -+ urb->iso_frame_desc[0].length = - frames * ua->playback.frame_bytes; - if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) - do_period_elapsed |= copy_playback_data(&ua->playback, -- &urb->urb, -+ urb, - frames); - else -- memset(urb->urb.transfer_buffer, 0, -- urb->urb.iso_frame_desc[0].length); -+ memset(urb->transfer_buffer, 0, -+ urb->iso_frame_desc[0].length); - - /* and off you go ... */ -- err = usb_submit_urb(&urb->urb, GFP_ATOMIC); -+ err = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(err < 0)) { - abort_usb_playback(ua); - abort_alsa_playback(ua); -@@ -342,7 +345,8 @@ static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb, - - static void capture_urb_complete(struct urb *urb) - { -- struct ua101 *ua = urb->context; -+ struct ua101_urb *ua_urb = urb->context; -+ struct ua101 *ua = ua_urb->ua; - struct ua101_stream *stream = &ua->capture; - unsigned int frames, write_ptr; - bool do_period_elapsed; -@@ -413,7 +417,8 @@ static void capture_urb_complete(struct urb *urb) - - static void first_capture_urb_complete(struct urb *urb) - { -- struct ua101 *ua = urb->context; -+ struct ua101_urb *ua_urb = urb->context; -+ struct ua101 *ua = ua_urb->ua; - - urb->complete = capture_urb_complete; - capture_urb_complete(urb); -@@ -427,7 +432,7 @@ static int submit_stream_urbs(struct ua101 *ua, struct ua101_stream *stream) - unsigned int i; - - for (i = 0; i < stream->queue_length; ++i) { -- int err = usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL); -+ int err = usb_submit_urb(stream->urbs[i].urb, GFP_KERNEL); - if (err < 0) { - dev_err(&ua->dev->dev, "USB request error %d: %s\n", - err, usb_error_string(err)); -@@ -442,8 +447,8 @@ static void kill_stream_urbs(struct ua101_stream *stream) - unsigned int i; - - for (i = 0; i < stream->queue_length; ++i) -- if (stream->urbs[i]) -- usb_kill_urb(&stream->urbs[i]->urb); -+ if (stream->urbs[i].urb) -+ usb_kill_urb(stream->urbs[i].urb); - } - - static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) -@@ -508,7 +513,7 @@ static int start_usb_capture(struct ua101 *ua) - return err; - - clear_bit(CAPTURE_URB_COMPLETED, &ua->states); -- ua->capture.urbs[0]->urb.complete = first_capture_urb_complete; -+ ua->capture.urbs[0].urb->complete = first_capture_urb_complete; - ua->rate_feedback_start = 0; - ua->rate_feedback_count = 0; - -@@ -550,7 +555,7 @@ static int start_usb_playback(struct ua101 *ua) - return err; - - clear_bit(PLAYBACK_URB_COMPLETED, &ua->states); -- ua->playback.urbs[0]->urb.complete = -+ ua->playback.urbs[0].urb->complete = - first_playback_urb_complete; - scoped_guard(spinlock_irq, &ua->lock) { - INIT_LIST_HEAD(&ua->ready_playback_urbs); -@@ -580,7 +585,7 @@ static int start_usb_playback(struct ua101 *ua) - add_with_wraparound(ua, &ua->rate_feedback_start, 1); - ua->rate_feedback_count--; - } -- urb = &ua->playback.urbs[i]->urb; -+ urb = ua->playback.urbs[i].urb; - urb->iso_frame_desc[0].length = - frames * ua->playback.frame_bytes; - memset(urb->transfer_buffer, 0, -@@ -1059,7 +1064,7 @@ static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream, - void (*urb_complete)(struct urb *)) - { - unsigned max_packet_size = stream->max_packet_bytes; -- struct ua101_urb *urb; -+ struct urb *urb; - unsigned int b, u = 0; - - for (b = 0; b < ARRAY_SIZE(stream->buffers); ++b) { -@@ -1070,23 +1075,24 @@ static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream, - while (size >= max_packet_size) { - if (u >= stream->queue_length) - goto bufsize_error; -- urb = kmalloc_obj(*urb); -+ urb = usb_alloc_urb(1, GFP_KERNEL); - if (!urb) - return -ENOMEM; -- usb_init_urb(&urb->urb); -- urb->urb.dev = ua->dev; -- urb->urb.pipe = stream->usb_pipe; -- urb->urb.transfer_flags = URB_NO_TRANSFER_DMA_MAP; -- urb->urb.transfer_buffer = addr; -- urb->urb.transfer_dma = dma; -- urb->urb.transfer_buffer_length = max_packet_size; -- urb->urb.number_of_packets = 1; -- urb->urb.interval = 1; -- urb->urb.context = ua; -- urb->urb.complete = urb_complete; -- urb->urb.iso_frame_desc[0].offset = 0; -- urb->urb.iso_frame_desc[0].length = max_packet_size; -- stream->urbs[u++] = urb; -+ urb->dev = ua->dev; -+ urb->pipe = stream->usb_pipe; -+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; -+ urb->transfer_buffer = addr; -+ urb->transfer_dma = dma; -+ urb->transfer_buffer_length = max_packet_size; -+ urb->number_of_packets = 1; -+ urb->interval = 1; -+ urb->context = &stream->urbs[u]; -+ urb->complete = urb_complete; -+ urb->iso_frame_desc[0].offset = 0; -+ urb->iso_frame_desc[0].length = max_packet_size; -+ stream->urbs[u].ua = ua; -+ stream->urbs[u].urb = urb; -+ u++; - size -= max_packet_size; - addr += max_packet_size; - dma += max_packet_size; -@@ -1104,8 +1110,8 @@ static void free_stream_urbs(struct ua101_stream *stream) - unsigned int i; - - for (i = 0; i < stream->queue_length; ++i) { -- kfree(stream->urbs[i]); -- stream->urbs[i] = NULL; -+ usb_free_urb(stream->urbs[i].urb); -+ stream->urbs[i].urb = NULL; - } - } - -diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c ---- a/sound/usb/quirks.c -+++ b/sound/usb/quirks.c -@@ -849,6 +849,27 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) - return 0; - } - -+/* -+ * A post configuration device descriptor read is needed to make the CM1A -+ * operational after reenumeration. -+ */ -+static int snd_usb_cm1a_boot_quirk(struct usb_device *dev) -+{ -+ struct usb_device_descriptor *desc __free(kfree) = kmalloc_obj(*desc); -+ int err; -+ -+ if (!desc) -+ return -ENOMEM; -+ -+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, sizeof(*desc)); -+ if (err < 0) { -+ dev_err(&dev->dev, "failed to read device descriptor: %d\n", err); -+ return err; -+ } -+ -+ return 0; -+} -+ - /* - * Some sound cards from Native Instruments are in fact compliant to the USB - * audio standard of version 2 and other approved USB standards, even though -@@ -1681,6 +1702,8 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev, - switch (id) { - case USB_ID(0x07fd, 0x0008): /* MOTU M Series, 1st hardware version */ - return snd_usb_motu_m_series_boot_quirk(dev); -+ case USB_ID(0x1397, 0x1234): /* Behringer CM1A */ -+ return snd_usb_cm1a_boot_quirk(dev); - } - - return 0; -@@ -2390,6 +2413,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB), - DEVICE_FLG(0x1397, 0x050c, /* Behringer Flow 8 */ - QUIRK_FLAG_IFB_SILENCE_ON_EMPTY), -+ DEVICE_FLG(0x1397, 0x0510, /* Behringer UV1 */ -+ QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB), - DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */ - QUIRK_FLAG_IGNORE_CTL_ERROR), - DEVICE_FLG(0x152a, 0x85dd, /* SMSL USB DAC */ diff --git a/kernel/0522-sound-fixes-3.patch.sig b/kernel/0522-sound-fixes-3.patch.sig deleted file mode 100644 index 2f7746c..0000000 Binary files a/kernel/0522-sound-fixes-3.patch.sig and /dev/null differ diff --git a/kernel/0523-asoc-fixes-2.patch b/kernel/0523-asoc-fixes-2.patch deleted file mode 100644 index b65c5d4..0000000 --- a/kernel/0523-asoc-fixes-2.patch +++ /dev/null @@ -1,1040 +0,0 @@ -diff --git a/sound/hda/core/ext/controller.c b/sound/hda/core/ext/controller.c ---- a/sound/hda/core/ext/controller.c -+++ b/sound/hda/core/ext/controller.c -@@ -90,8 +90,10 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus) - - for (idx = 0; idx < link_count; idx++) { - hlink = kzalloc_obj(*hlink); -- if (!hlink) -+ if (!hlink) { -+ snd_hdac_ext_link_free_all(bus); - return -ENOMEM; -+ } - hlink->index = idx; - hlink->bus = bus; - hlink->ml_addr = bus->mlcap + AZX_ML_BASE + -diff --git a/sound/hda/core/ext/stream.c b/sound/hda/core/ext/stream.c ---- a/sound/hda/core/ext/stream.c -+++ b/sound/hda/core/ext/stream.c -@@ -102,8 +102,10 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx, - - for (i = 0; i < num_stream; i++) { - struct hdac_ext_stream *hext_stream = kzalloc_obj(*hext_stream); -- if (!hext_stream) -+ if (!hext_stream) { -+ snd_hdac_ext_stream_free_all(bus); - return -ENOMEM; -+ } - tag = ++stream_tag; - snd_hdac_ext_stream_init(bus, hext_stream, idx, dir, tag); - idx++; -@@ -111,7 +113,6 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx, - } - - return 0; -- - } - EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all); - -diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c ---- a/sound/soc/amd/yc/acp6x-mach.c -+++ b/sound/soc/amd/yc/acp6x-mach.c -@@ -388,6 +388,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Nitro ANV15-41"), - } - }, -+ { -+ .driver_data = &acp6x_card, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "RB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Nitro AN17-41"), -+ } -+ }, - { - .driver_data = &acp6x_card, - .matches = { -@@ -899,6 +906,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { - DMI_MATCH(DMI_BOARD_NAME, "TM2423"), - } - }, -+ { -+ .driver_data = &acp6x_card, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "HP 255R 15.6 inch G10 Notebook PC"), -+ } -+ }, - {} - }; - -diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c ---- a/sound/soc/codecs/ab8500-codec.c -+++ b/sound/soc/codecs/ab8500-codec.c -@@ -14,17 +14,14 @@ - * for ST-Ericsson. - */ - --#include - #include - #include - #include - #include - #include - #include --#include - #include - #include --#include - #include - #include - #include -@@ -54,32 +51,9 @@ - /* Macrocell register definitions */ - #define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */ - --/* Nr of FIR/IIR-coeff banks in ANC-block */ --#define AB8500_NR_OF_ANC_COEFF_BANKS 2 -- --/* Minimum duration to keep ANC IIR Init bit high or --low before proceeding with the configuration sequence */ --#define AB8500_ANC_SM_DELAY 2000 -- --/* Sidetone states */ --static const char * const enum_sid_state[] = { -- "Unconfigured", -- "Apply FIR", -- "FIR is configured", --}; --enum sid_state { -- SID_UNCONFIGURED = 0, -- SID_APPLY_FIR = 1, -- SID_FIR_CONFIGURED = 2, --}; -- - /* Private data for AB8500 device-driver */ - struct ab8500_codec_drvdata { - struct regmap *regmap; -- struct mutex ctrl_lock; -- -- /* Sidetone */ -- enum sid_state sid_status; - }; - - static inline const char *amic_micbias_str(enum amic_micbias micbias) -@@ -642,9 +616,6 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { - NULL, 0), - /* Acoustical Noise Cancellation path */ - -- SND_SOC_DAPM_INPUT("ANC Configure Input"), -- SND_SOC_DAPM_OUTPUT("ANC Configure Output"), -- - SND_SOC_DAPM_MUX("ANC Source", - SND_SOC_NOPM, 0, 0, - dapm_anc_in_select), -@@ -687,10 +658,6 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes[] = { - {"Main Supply", NULL, "Audio Power"}, - {"Main Supply", NULL, "Audio Analog Power"}, - -- /* ANC Configure */ -- {"ANC Configure Input", NULL, "Main Supply"}, -- {"ANC Configure Output", NULL, "ANC Configure Input"}, -- - /* Powerup charge pump if DA1/2 is in use */ - - {"DA_IN1", NULL, "ab8500_0p"}, -@@ -972,75 +939,6 @@ static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = { - {"MIC2 V-AMICx Enable", NULL, "V-AMIC2"}, - }; - --/* -- * Control-events -- */ -- --static int sid_status_control_get(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) --{ -- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev); -- -- guard(mutex)(&drvdata->ctrl_lock); -- ucontrol->value.enumerated.item[0] = drvdata->sid_status; -- -- return 0; --} -- --/* Write sidetone FIR-coefficients configuration sequence */ --static int sid_status_control_put(struct snd_kcontrol *kcontrol, -- struct snd_ctl_elem_value *ucontrol) --{ -- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev); -- unsigned int param, sidconf; -- int status = 1; -- -- dev_dbg(component->dev, "%s: Enter\n", __func__); -- -- if (ucontrol->value.enumerated.item[0] != SID_APPLY_FIR) { -- dev_err(component->dev, -- "%s: ERROR: This control supports '%s' only!\n", -- __func__, enum_sid_state[SID_APPLY_FIR]); -- return -EIO; -- } -- -- guard(mutex)(&drvdata->ctrl_lock); -- -- sidconf = snd_soc_component_read(component, AB8500_SIDFIRCONF); -- if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { -- if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) { -- dev_err(component->dev, "%s: Sidetone busy while off!\n", -- __func__); -- status = -EPERM; -- } else { -- status = -EBUSY; -- } -- dev_dbg(component->dev, "%s: Exit\n", __func__); -- return status; -- } -- -- snd_soc_component_write(component, AB8500_SIDFIRADR, 0); -- -- for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) { -- snd_soc_component_write(component, AB8500_SIDFIRCOEF1, 0); -- snd_soc_component_write(component, AB8500_SIDFIRCOEF2, 0); -- } -- -- snd_soc_component_update_bits(component, AB8500_SIDFIRADR, -- BIT(AB8500_SIDFIRADR_FIRSIDSET), -- BIT(AB8500_SIDFIRADR_FIRSIDSET)); -- snd_soc_component_update_bits(component, AB8500_SIDFIRADR, -- BIT(AB8500_SIDFIRADR_FIRSIDSET), 0); -- -- drvdata->sid_status = SID_FIR_CONFIGURED; -- -- dev_dbg(component->dev, "%s: Exit\n", __func__); -- -- return status; --} -- - /* - * Controls - Non-DAPM ASoC - */ -@@ -1324,9 +1222,6 @@ static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast, - AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT, - enum_slavemaster); - --/* Sidetone */ --static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state); -- - /* ANC */ - - static struct snd_kcontrol_new ab8500_ctrls[] = { -@@ -1617,8 +1512,6 @@ static struct snd_kcontrol_new ab8500_ctrls[] = { - AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0), - - /* Sidetone */ -- SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate, -- sid_status_control_get, sid_status_control_put), - SOC_SINGLE_STROBE("Sidetone Reset", - AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0), - }; -@@ -2148,10 +2041,8 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np, - - static int ab8500_codec_probe(struct snd_soc_component *component) - { -- struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - struct device *dev = component->dev; - struct device_node *np = dev->of_node; -- struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); - struct ab8500_codec_platform_data codec_pdata; - int status; - -@@ -2184,10 +2075,6 @@ static int ab8500_codec_probe(struct snd_soc_component *component) - snd_soc_component_write(component, AB8500_SHORTCIRCONF, - BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); - -- snd_soc_dapm_disable_pin(dapm, "ANC Configure Input"); -- -- mutex_init(&drvdata->ctrl_lock); -- - return status; - } - -@@ -2216,7 +2103,6 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) - GFP_KERNEL); - if (!drvdata) - return -ENOMEM; -- drvdata->sid_status = SID_UNCONFIGURED; - dev_set_drvdata(&pdev->dev, drvdata); - - drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, -diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c ---- a/sound/soc/codecs/cs35l56-sdw.c -+++ b/sound/soc/codecs/cs35l56-sdw.c -@@ -386,11 +386,8 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev) - { - struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); - -- if (!cs35l56->base.init_done) -- return 0; -- -- /* runtime_resume unmasks the interrupt */ -- cs35l56_mask_soundwire_interrupts(cs35l56); -+ if (cs35l56->sdw_attached) -+ cs35l56_mask_soundwire_interrupts(cs35l56); - - return cs35l56_system_suspend(dev); - } -diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c ---- a/sound/soc/codecs/cs35l56.c -+++ b/sound/soc/codecs/cs35l56.c -@@ -18,9 +18,11 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - #include - #include - #include -@@ -37,6 +39,13 @@ - #include "wm_adsp.h" - #include "cs35l56.h" - -+/* -+ * snd_soc_register_component() can call component_probe() on all instances -+ * in a card, so deferred registration must be protected across all instances. -+ */ -+static DEFINE_MUTEX(cs35l56_component_register_lock); -+static bool cs35l56_shutting_down; -+ - void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56) - { - /* -@@ -1957,6 +1966,11 @@ static void cs35l56_component_register_work(struct work_struct *work) - component_register_work); - int ret; - -+ guard(mutex)(&cs35l56_component_register_lock); -+ -+ if (cs35l56_shutting_down) -+ return; -+ - PM_RUNTIME_ACQUIRE_AUTOSUSPEND(cs35l56->base.dev, pm_err); - ret = PM_RUNTIME_ACQUIRE_ERR(&pm_err); - if (ret) { -@@ -2217,6 +2231,37 @@ EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = { - }; - #endif - -+static int cs35l56_reboot_notify(struct notifier_block *nb, -+ unsigned long action, void *data) -+{ -+ guard(mutex)(&cs35l56_component_register_lock); -+ cs35l56_shutting_down = true; -+ -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block cs35l56_reboot_notifier = { -+ .notifier_call = cs35l56_reboot_notify, -+}; -+ -+static int __init cs35l56_modinit(void) -+{ -+ /* -+ * Use reboot notifier to prevent race between shutdown and -+ * snd_soc_register_component(). Driver shutdown() callback would -+ * run too late, after device_shutdown() is already walking the -+ * device list that component registration can modify. -+ */ -+ return register_reboot_notifier(&cs35l56_reboot_notifier); -+} -+module_init(cs35l56_modinit); -+ -+static void __exit cs35l56_modexit(void) -+{ -+ unregister_reboot_notifier(&cs35l56_reboot_notifier); -+} -+module_exit(cs35l56_modexit); -+ - MODULE_DESCRIPTION("ASoC CS35L56 driver"); - MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); - MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); -diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h ---- a/sound/soc/codecs/cs35l56.h -+++ b/sound/soc/codecs/cs35l56.h -@@ -32,6 +32,7 @@ struct sdw_slave; - struct cs35l56_private { - struct wm_adsp dsp; /* must be first member */ - struct cs35l56_base base; -+ struct work_struct component_register_work; - struct work_struct dsp_work; - struct workqueue_struct *dsp_wq; - struct snd_soc_component *component; -@@ -41,6 +42,7 @@ struct cs35l56_private { - const char *fallback_fw_suffix; - bool soft_resetting; - bool sdw_attached; -+ bool component_registered; - struct completion init_completion; - - int speaker_id; -diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c ---- a/sound/soc/codecs/es8326.c -+++ b/sound/soc/codecs/es8326.c -@@ -26,6 +26,7 @@ struct es8326_priv { - struct snd_soc_component *component; - struct delayed_work jack_detect_work; - struct delayed_work button_press_work; -+ struct delayed_work capture_pop_work; - struct snd_soc_jack *jack; - int irq; - /* The lock protects the situation that an irq is generated -@@ -628,6 +629,7 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) - regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, - 0x30, 0x00); - } else { -+ cancel_delayed_work_sync(&es8326->capture_pop_work); - regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE, - 0x0F, 0x0F); - if (es8326->version > ES8326_VERSION_B) { -@@ -666,8 +668,9 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) - regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x70); - regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x00); - } -- regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE, -- 0x0F, 0x00); -+ -+ queue_delayed_work(system_dfl_wq, &es8326->capture_pop_work, -+ msecs_to_jiffies(40)); - } - } - return 0; -@@ -773,6 +776,15 @@ static void es8326_disable_micbias(struct snd_soc_component *component) - snd_soc_dapm_mutex_unlock(dapm); - } - -+static void es8326_capture_pop_handler(struct work_struct *work) -+{ -+ struct es8326_priv *es8326 = -+ container_of(work, struct es8326_priv, capture_pop_work.work); -+ -+ regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE, -+ 0x0F, 0x00); -+} -+ - /* - * For button detection, set the following in soundcard - * snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); -@@ -1140,6 +1152,7 @@ static int es8326_suspend(struct snd_soc_component *component) - struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component); - - cancel_delayed_work_sync(&es8326->jack_detect_work); -+ cancel_delayed_work_sync(&es8326->capture_pop_work); - es8326_disable_micbias(component); - es8326->calibrated = false; - regmap_write(es8326->regmap, ES8326_CLK_MUX, 0x2d); -@@ -1291,6 +1304,8 @@ static int es8326_i2c_probe(struct i2c_client *i2c) - es8326_jack_detect_handler); - INIT_DELAYED_WORK(&es8326->button_press_work, - es8326_jack_button_handler); -+ INIT_DELAYED_WORK(&es8326->capture_pop_work, -+ es8326_capture_pop_handler); - /* ES8316 is level-based while ES8326 is edge-based */ - ret = devm_request_threaded_irq(&i2c->dev, es8326->irq, NULL, es8326_irq, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, -diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c ---- a/sound/soc/codecs/es8389.c -+++ b/sound/soc/codecs/es8389.c -@@ -812,6 +812,23 @@ static int es8389_pcm_hw_free(struct snd_pcm_substream *substream, - return 0; - } - -+static void es8389_standby(struct snd_soc_component *component) -+{ -+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); -+ -+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x04); -+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x04); -+ regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xD4); -+ usleep_range(70000, 72000); -+ regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x59); -+ regmap_write(es8389->regmap, ES8389_ADC_EN, 0x00); -+ regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0x00); -+ regmap_write(es8389->regmap, ES8389_RESET, 0x3E); -+ regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x80); -+ usleep_range(8000, 8500); -+ regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x00); -+} -+ - static int es8389_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) - { -@@ -834,18 +851,7 @@ static int es8389_set_bias_level(struct snd_soc_component *component, - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: -- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x04); -- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x04); -- regmap_write(es8389->regmap, ES8389_CSM_JUMP, 0xD4); -- usleep_range(70000, 72000); -- regmap_write(es8389->regmap, ES8389_ANA_CTL1, 0x59); -- regmap_write(es8389->regmap, ES8389_ADC_EN, 0x00); -- regmap_write(es8389->regmap, ES8389_CLK_OFF1, 0x00); -- regmap_write(es8389->regmap, ES8389_RESET, 0x3E); -- regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x80); -- usleep_range(8000, 8500); -- regmap_update_bits(es8389->regmap, ES8389_DAC_INV, 0x80, 0x00); -- -+ es8389_standby(component); - clk_disable_unprepare(es8389->mclk); - break; - case SND_SOC_BIAS_OFF: -@@ -1015,7 +1021,7 @@ static int es8389_suspend(struct snd_soc_component *component) - { - struct es8389_private *es8389 = snd_soc_component_get_drvdata(component); - -- es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY); -+ es8389_standby(component); - regcache_cache_only(es8389->regmap, true); - regcache_mark_dirty(es8389->regmap); - -@@ -1084,7 +1090,7 @@ static int es8389_probe(struct snd_soc_component *component) - - es8389->hpf_freq = ES8389_HPF_DEFAULT; - es8389_init(component); -- es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY); -+ es8389_standby(component); - - return 0; - } -diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c ---- a/sound/soc/codecs/rt1318-sdw.c -+++ b/sound/soc/codecs/rt1318-sdw.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include "rt1318-sdw.h" - -@@ -564,11 +565,10 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_soc_component *component = dai->component; - struct rt1318_sdw_priv *rt1318 = - snd_soc_component_get_drvdata(component); -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; -- enum sdw_data_direction direction; - struct sdw_stream_runtime *sdw_stream; -- int retval, port, num_channels, ch_mask; -+ int retval, port; - unsigned int sampling_rate; - - dev_dbg(dai->dev, "%s %s", __func__, dai->name); -@@ -582,23 +582,13 @@ static int rt1318_sdw_hw_params(struct snd_pcm_substream *substream, - - /* SoundWire specific configuration */ - /* port 1 for playback */ -- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- direction = SDW_DATA_DIR_RX; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - port = 1; -- } else { -- direction = SDW_DATA_DIR_TX; -+ else - port = 2; -- } - -- num_channels = params_channels(params); -- ch_mask = (1 << num_channels) - 1; -- -- stream_config.frame_rate = params_rate(params); -- stream_config.ch_count = num_channels; -- stream_config.bps = snd_pcm_format_width(params_format(params)); -- stream_config.direction = direction; -- -- port_config.ch_mask = ch_mask; -+ /* SoundWire specific configuration */ -+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - port_config.num = port; - - retval = sdw_stream_add_slave(rt1318->sdw_slave, &stream_config, -diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c ---- a/sound/soc/codecs/rt1320-sdw.c -+++ b/sound/soc/codecs/rt1320-sdw.c -@@ -3246,7 +3246,7 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_soc_component *component = dai->component; - struct rt1320_sdw_priv *rt1320 = - snd_soc_component_get_drvdata(component); -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; - struct sdw_port_config dmic_port_config[2]; - struct sdw_stream_runtime *sdw_stream; -diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c ---- a/sound/soc/codecs/rt712-sdca.c -+++ b/sound/soc/codecs/rt712-sdca.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - #include - #include "rt712-sdca.h" - -@@ -1449,11 +1450,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - { - struct snd_soc_component *component = dai->component; - struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; -- enum sdw_data_direction direction; - struct sdw_stream_runtime *sdw_stream; -- int retval, port, num_channels; -+ int retval, port; - unsigned int sampling_rate; - - dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id); -@@ -1471,7 +1471,6 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - - /* SoundWire specific configuration */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- direction = SDW_DATA_DIR_RX; - if (dai->id == RT712_AIF1) - port = 1; - else if (dai->id == RT712_AIF2) -@@ -1479,7 +1478,6 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - else - return -EINVAL; - } else { -- direction = SDW_DATA_DIR_TX; - if (dai->id == RT712_AIF1) - port = 4; - else if (dai->id == RT712_AIF3) -@@ -1488,13 +1486,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - return -EINVAL; - } - -- stream_config.frame_rate = params_rate(params); -- stream_config.ch_count = params_channels(params); -- stream_config.bps = snd_pcm_format_width(params_format(params)); -- stream_config.direction = direction; -- -- num_channels = params_channels(params); -- port_config.ch_mask = GENMASK(num_channels - 1, 0); -+ /* SoundWire specific configuration */ -+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - port_config.num = port; - - retval = sdw_stream_add_slave(rt712->slave, &stream_config, -diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c ---- a/sound/soc/codecs/rt721-sdca.c -+++ b/sound/soc/codecs/rt721-sdca.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - - #include "rt721-sdca.h" -@@ -206,6 +207,7 @@ static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721) - regmap_write(rt721->regmap, - SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, - RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00); -+ regmap_write(rt721->regmap, 0x2f5d, 0x1); - } - - static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721) -@@ -1268,11 +1270,10 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - { - struct snd_soc_component *component = dai->component; - struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; -- enum sdw_data_direction direction; - struct sdw_stream_runtime *sdw_stream; -- int retval, port, num_channels; -+ int retval, port; - unsigned int sampling_rate; - - dev_dbg(dai->dev, "%s %s", __func__, dai->name); -@@ -1291,7 +1292,6 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - * RT721_AIF3 with port = 6 for digital-mic capture - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- direction = SDW_DATA_DIR_RX; - if (dai->id == RT721_AIF1) - port = 1; - else if (dai->id == RT721_AIF2) -@@ -1299,7 +1299,6 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - else - return -EINVAL; - } else { -- direction = SDW_DATA_DIR_TX; - if (dai->id == RT721_AIF1) - port = 2; - else if (dai->id == RT721_AIF3) -@@ -1307,13 +1306,9 @@ static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - else - return -EINVAL; - } -- stream_config.frame_rate = params_rate(params); -- stream_config.ch_count = params_channels(params); -- stream_config.bps = snd_pcm_format_width(params_format(params)); -- stream_config.direction = direction; - -- num_channels = params_channels(params); -- port_config.ch_mask = GENMASK(num_channels - 1, 0); -+ /* SoundWire specific configuration */ -+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - port_config.num = port; - - retval = sdw_stream_add_slave(rt721->slave, &stream_config, -diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c ---- a/sound/soc/codecs/rt722-sdca.c -+++ b/sound/soc/codecs/rt722-sdca.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - #include - - #include "rt722-sdca.h" -@@ -1442,11 +1443,10 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - { - struct snd_soc_component *component = dai->component; - struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; -- enum sdw_data_direction direction; - struct sdw_stream_runtime *sdw_stream; -- int retval, port, num_channels; -+ int retval, port; - unsigned int sampling_rate; - - dev_dbg(dai->dev, "%s %s", __func__, dai->name); -@@ -1465,7 +1465,6 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - * RT722_AIF3 with port = 6 for digital-mic capture - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- direction = SDW_DATA_DIR_RX; - if (dai->id == RT722_AIF1) - port = 1; - else if (dai->id == RT722_AIF2) -@@ -1473,7 +1472,6 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - else - return -EINVAL; - } else { -- direction = SDW_DATA_DIR_TX; - if (dai->id == RT722_AIF1) - port = 2; - else if (dai->id == RT722_AIF3) -@@ -1481,13 +1479,9 @@ static int rt722_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - else - return -EINVAL; - } -- stream_config.frame_rate = params_rate(params); -- stream_config.ch_count = params_channels(params); -- stream_config.bps = snd_pcm_format_width(params_format(params)); -- stream_config.direction = direction; - -- num_channels = params_channels(params); -- port_config.ch_mask = GENMASK(num_channels - 1, 0); -+ /* SoundWire specific configuration */ -+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - port_config.num = port; - - retval = sdw_stream_add_slave(rt722->slave, &stream_config, -diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c ---- a/sound/soc/codecs/tas2783-sdw.c -+++ b/sound/soc/codecs/tas2783-sdw.c -@@ -1001,6 +1001,31 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream, - /* SoundWire specific configuration */ - snd_sdw_params_to_config(substream, params, - &stream_config, &port_config); -+ -+ /* -+ * The two mono amps each render one channel of the stereo stream: -+ * snd_sdw_params_to_config() hands every codec the full mask for -+ * playback, which leaves the pair in mirror mode and one channel -+ * unreproduced. Claim a single channel instead, keyed off the -+ * machine-assigned component prefix rather than the SoundWire -+ * address, which is board-specific: soc_sdw_ti_amp.c names the amps -+ * tas2783-1..4. -+ * -+ * Which side an amp then renders does not follow from the bit that -+ * is set - sdw_compute_slave_ports() advances the payload offset by -+ * the popcount of ch_mask and never looks at which bit it is - but -+ * from the amp's position in the codec order of the DAI link, which -+ * on these boards matches the prefix numbering. -+ */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ params_channels(params) == 2 && component->name_prefix) { -+ const char *idx_str = strrchr(component->name_prefix, '-'); -+ unsigned long idx; -+ -+ if (idx_str && !kstrtoul(idx_str + 1, 10, &idx) && idx) -+ port_config.ch_mask = (idx & 1) ? BIT(0) : BIT(1); -+ } -+ - /* port 1 for playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - port_config.num = 1; -diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c ---- a/sound/soc/intel/avs/boards/hdaudio.c -+++ b/sound/soc/intel/avs/boards/hdaudio.c -@@ -15,6 +15,22 @@ - #include "../../../codecs/hda.h" - #include "../utils.h" - -+static int avs_link_startup(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ const struct snd_soc_pcm_stream *stream_info; -+ struct snd_soc_dai *codec_dai; -+ -+ codec_dai = snd_soc_rtd_to_codec(rtd, 0); -+ stream_info = snd_soc_dai_get_pcm_stream(codec_dai, substream->stream); -+ -+ return snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, stream_info->sig_bits); -+} -+ -+static const struct snd_soc_ops avs_link_ops = { -+ .startup = avs_link_startup, -+}; -+ - static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count, - struct snd_soc_dai_link **links) - { -@@ -43,6 +59,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int - dl[i].platforms = platform; - dl[i].num_platforms = 1; - dl[i].ignore_pmdown_time = 1; -+ dl[i].ops = &avs_link_ops; - - dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL); - dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); -diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c ---- a/sound/soc/intel/avs/core.c -+++ b/sound/soc/intel/avs/core.c -@@ -92,16 +92,28 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus) - { - unsigned int cp_streams, pb_streams; - unsigned int gcap; -+ int ret; - - gcap = snd_hdac_chip_readw(bus, GCAP); - cp_streams = (gcap >> 8) & 0x0F; - pb_streams = (gcap >> 12) & 0x0F; - bus->num_streams = cp_streams + pb_streams; - -- snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); -- snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); -+ ret = snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); -+ if (ret) -+ return ret; -+ ret = snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); -+ if (ret) -+ goto err; - -- return snd_hdac_bus_alloc_stream_pages(bus); -+ ret = snd_hdac_bus_alloc_stream_pages(bus); -+ if (ret) -+ goto err; -+ -+ return 0; -+err: -+ snd_hdac_ext_stream_free_all(bus); -+ return ret; - } - - static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) -@@ -383,6 +395,18 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct - struct device *dev = &pci->dev; - int ret; - -+ ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL); -+ if (!ipc) -+ return -ENOMEM; -+ -+ adev->modcfg_buf = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL); -+ if (!adev->modcfg_buf) -+ return -ENOMEM; -+ -+ ret = avs_ipc_init(ipc, dev); -+ if (ret < 0) -+ return ret; -+ - ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, &soc_hda_ext_bus_ops); - if (ret < 0) - return ret; -@@ -394,17 +418,6 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct - bus->mixer_assigned = -1; - mutex_init(&bus->prepare_mutex); - -- ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL); -- if (!ipc) -- return -ENOMEM; -- ret = avs_ipc_init(ipc, dev); -- if (ret < 0) -- return ret; -- -- adev->modcfg_buf = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL); -- if (!adev->modcfg_buf) -- return -ENOMEM; -- - adev->dev = dev; - adev->spec = (const struct avs_spec *)id->driver_data; - adev->ipc = ipc; -@@ -456,13 +469,14 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) - - ret = pcim_request_all_regions(pci, "AVS HDAudio"); - if (ret < 0) -- return ret; -+ goto err_request_regions; - - bus->addr = pci_resource_start(pci, 0); - bus->remap_addr = pci_ioremap_bar(pci, 0); - if (!bus->remap_addr) { - dev_err(bus->dev, "ioremap error\n"); -- return -ENXIO; -+ ret = -ENXIO; -+ goto err_request_regions; - } - - adev->dsp_ba = pci_ioremap_bar(pci, 4); -@@ -526,6 +540,8 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) - iounmap(adev->dsp_ba); - err_remap_bar4: - iounmap(bus->remap_addr); -+err_request_regions: -+ snd_hdac_ext_bus_exit(bus); - return ret; - } - -diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c ---- a/sound/soc/intel/avs/debugfs.c -+++ b/sound/soc/intel/avs/debugfs.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -236,15 +237,20 @@ static int strace_open(struct inode *inode, struct file *file) - if (!try_module_get(adev->dev->driver->owner)) - return -ENODEV; - -- if (kfifo_initialized(&adev->trace_fifo)) -- return -EBUSY; -+ if (kfifo_initialized(&adev->trace_fifo)) { -+ ret = -EBUSY; -+ goto err; -+ } - - ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL); - if (ret < 0) -- return ret; -+ goto err; - - file->private_data = adev; - return 0; -+err: -+ module_put(adev->dev->driver->owner); -+ return ret; - } - - static int strace_release(struct inode *inode, struct file *file) -diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c ---- a/sound/soc/intel/avs/ipc.c -+++ b/sound/soc/intel/avs/ipc.c -@@ -172,7 +172,7 @@ static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg - - /* Avoid deadlock as the exception may be the response to SET_D0IX. */ - if (current_work() != &ipc->d0ix_work.work) -- cancel_delayed_work_sync(&ipc->d0ix_work); -+ cancel_delayed_work(&ipc->d0ix_work); - ipc->in_d0ix = false; - /* Re-enabled on recovery completion. */ - pm_runtime_disable(adev->dev); -@@ -395,11 +395,11 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request - struct avs_ipc *ipc = adev->ipc; - int ret; - -+ guard(mutex)(&ipc->msg_mutex); -+ - if (!ipc->ready) - return -EPERM; - -- guard(mutex)(&ipc->msg_mutex); -- - spin_lock(&ipc->rx_lock); - avs_ipc_msg_init(ipc, reply); - avs_dsp_send_tx(adev, request, true); -diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig ---- a/sound/soc/intel/boards/Kconfig -+++ b/sound/soc/intel/boards/Kconfig -@@ -533,12 +533,14 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH - select SND_SOC_CS35L56_SPI - select SND_SOC_CS35L56_SDW - select SND_SOC_ES9356 -+ imply SND_SOC_TAC5XX2_SDW - select SND_SOC_DMIC - select SND_SOC_INTEL_HDA_DSP_COMMON - imply SND_SOC_SDW_MOCKUP - help - Add support for Intel SoundWire-based platforms connected to -- MAX98373, RT700, RT711, RT1308 and RT715 -+ MAX98373, RT700, RT711, RT1308, RT715, TAC5XX2_SDW family (including -+ TAC5572, TAC5682). - If unsure select "N". - - endif -diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c ---- a/sound/soc/intel/boards/sof_rt5682.c -+++ b/sound/soc/intel/boards/sof_rt5682.c -@@ -908,6 +908,14 @@ static const struct platform_device_id board_ids[] = { - SOF_SSP_PORT_BT_OFFLOAD(2) | - SOF_BT_OFFLOAD_PRESENT), - }, -+ { -+ .name = "nvl_rt5682_def", -+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | -+ SOF_SSP_PORT_CODEC(0) | -+ SOF_SSP_PORT_AMP(1) | -+ SOF_SSP_PORT_BT_OFFLOAD(2) | -+ SOF_BT_OFFLOAD_PRESENT), -+ }, - { - .name = "ptl_rt5682_c1_h02", - .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | -diff --git a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c ---- a/sound/soc/intel/common/soc-acpi-intel-nvl-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-nvl-match.c -@@ -51,10 +51,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[] = { - }, - { - .comp_ids = &nvl_rt5682_rt5682s_hp, -- .drv_name = "sof_rt5682", -- .sof_tplg_filename = "sof-nvl-rt5682", /* the tplg suffix is added at run time */ -- .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | -- SND_SOC_ACPI_TPLG_INTEL_SSP_MSB, -+ .drv_name = "nvl_rt5682_def", -+ .sof_tplg_filename = "sof-nvl", /* the tplg suffix is added at run time */ -+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | -+ SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, - }, - /* place amp/hdmi-in only boards in the end of table */ - { diff --git a/kernel/0523-asoc-fixes-2.patch.sig b/kernel/0523-asoc-fixes-2.patch.sig deleted file mode 100644 index 906bd76..0000000 Binary files a/kernel/0523-asoc-fixes-2.patch.sig and /dev/null differ diff --git a/kernel/0524-sound-fixes-4.patch b/kernel/0524-sound-fixes-4.patch deleted file mode 100644 index 39c0ebf..0000000 --- a/kernel/0524-sound-fixes-4.patch +++ /dev/null @@ -1,135 +0,0 @@ -diff --git a/sound/core/init.c b/sound/core/init.c ---- a/sound/core/init.c -+++ b/sound/core/init.c -@@ -364,7 +364,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent, - sound_debugfs_root); - #endif - #ifdef CONFIG_SND_CTL_DEBUG -- card->value_buf = kmalloc(sizeof(*card->value_buf), GFP_KERNEL); -+ card->value_buf = kmalloc_obj(*card->value_buf); - if (!card->value_buf) - return -ENOMEM; - #endif -diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c ---- a/sound/hda/codecs/realtek/alc269.c -+++ b/sound/hda/codecs/realtek/alc269.c -@@ -4304,6 +4304,7 @@ enum { - ALC287_FIXUP_LEGION_16ACHG6, - ALC287_FIXUP_CS35L41_I2C_2, - ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED, -+ ALC287_FIXUP_CS35L41_I2C_2_HP_MUTE_LEDS, - ALC287_FIXUP_CS35L41_I2C_4, - ALC245_FIXUP_CS35L41_SPI_1, - ALC245_FIXUP_CS35L41_SPI_2, -@@ -6615,6 +6616,12 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC285_FIXUP_HP_MUTE_LED, - }, -+ [ALC287_FIXUP_CS35L41_I2C_2_HP_MUTE_LEDS] = { -+ .type = HDA_FIXUP_FUNC, -+ .v.func = cs35l41_fixup_i2c_two, -+ .chained = true, -+ .chain_id = ALC245_FIXUP_HP_X360_MUTE_LEDS, -+ }, - [ALC287_FIXUP_CS35L41_I2C_4] = { - .type = HDA_FIXUP_FUNC, - .v.func = cs35l41_fixup_i2c_four, -@@ -7372,6 +7379,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8158, "HP", ALC256_FIXUP_HP_HEADSET_MIC), - SND_PCI_QUIRK(0x103c, 0x820d, "HP Pavilion 15", ALC295_FIXUP_HP_X360), - SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), -+ SND_PCI_QUIRK(0x103c, 0x8259, "HP OMEN 15-ax202nf", ALC269_FIXUP_HP_MUTE_LED_MIC3), - SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360), - SND_PCI_QUIRK(0x103c, 0x827f, "HP x360", ALC269_FIXUP_HP_MUTE_LED_MIC3), - SND_PCI_QUIRK(0x103c, 0x82bf, "HP G3 mini", ALC221_FIXUP_HP_MIC_NO_PRESENCE), -@@ -7582,6 +7590,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), - SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), - SND_PCI_QUIRK(0x103c, 0x8ba9, "HP Omen 16-wd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT), -+ SND_PCI_QUIRK(0x103c, 0x8bb1, "HP Victus 15-fa1xxx (MB 8BB1)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_15_FD0XXX), -@@ -7674,7 +7683,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8dcd, "HP Victus 15-fa2xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2), -- SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2_HP_MUTE_LEDS), - SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2), -diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c ---- a/sound/usb/endpoint.c -+++ b/sound/usb/endpoint.c -@@ -449,7 +449,9 @@ static void push_back_to_ready_list(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *ctx) - { - guard(spinlock_irqsave)(&ep->lock); -- list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); -+ /* ctx may still be linked: a stale completion racing a stop/restart. */ -+ if (list_empty(&ctx->ready_list)) -+ list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); - } - - /* -@@ -1037,6 +1039,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep) - */ - static int stop_urbs(struct snd_usb_endpoint *ep, bool force, bool keep_pending) - { -+ struct snd_urb_ctx *ctx, *n; - unsigned int i; - - if (!force && atomic_read(&ep->running)) -@@ -1046,7 +1049,9 @@ static int stop_urbs(struct snd_usb_endpoint *ep, bool force, bool keep_pending) - return 0; - - scoped_guard(spinlock_irqsave, &ep->lock) { -- INIT_LIST_HEAD(&ep->ready_playback_urbs); -+ /* Unlink each ctx; INIT_LIST_HEAD() alone would leave them looking linked. */ -+ list_for_each_entry_safe(ctx, n, &ep->ready_playback_urbs, ready_list) -+ list_del_init(&ctx->ready_list); - ep->next_packet_head = 0; - ep->next_packet_queued = 0; - } -diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c ---- a/sound/usb/implicit.c -+++ b/sound/usb/implicit.c -@@ -76,6 +76,7 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { - - /* Implicit feedback quirk table for capture: only FIXED type */ - static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { -+ IMPLICIT_FB_FIXED_DEV(0x1397, 0x0004, 0x01, 1), /* Behringer FCA1616 */ - {} /* terminator */ - }; - -diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c ---- a/sound/usb/mixer_maps.c -+++ b/sound/usb/mixer_maps.c -@@ -531,6 +531,15 @@ static const struct usbmix_name_map audient_id24_map[] = { - {} - }; - -+/* -+ * The GC553Pro returns no data for GET_CUR on its advertised mute control. -+ * SET_CUR succeeds but does not mute capture, so skip the control entirely. -+ */ -+static const struct usbmix_name_map avermedia_gc553pro_map[] = { -+ { 3, NULL, UAC_FU_MUTE }, -+ {} -+}; -+ - /* - * Control map entries - */ -@@ -577,6 +586,10 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { - .id = USB_ID(0x0763, 0x2031), - .selector_map = c400_selectors, - }, -+ { -+ .id = USB_ID(0x07ca, 0x1553), -+ .map = avermedia_gc553pro_map, -+ }, - { - .id = USB_ID(0x08bb, 0x2702), - .map = linex_map, diff --git a/kernel/0524-sound-fixes-4.patch.sig b/kernel/0524-sound-fixes-4.patch.sig deleted file mode 100644 index ef2122d..0000000 Binary files a/kernel/0524-sound-fixes-4.patch.sig and /dev/null differ diff --git a/kernel/0525-asoc-fixes-3.patch b/kernel/0525-asoc-fixes-3.patch deleted file mode 100644 index 843a983..0000000 --- a/kernel/0525-asoc-fixes-3.patch +++ /dev/null @@ -1,549 +0,0 @@ -diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h ---- a/include/sound/soc_sdw_utils.h -+++ b/include/sound/soc_sdw_utils.h -@@ -250,8 +250,6 @@ int asoc_sdw_cs_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct asoc_sdw_codec_info *info, - bool playback); --int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd, -- struct snd_soc_dai *dai); - int asoc_sdw_cs35l56_volume_limit(struct snd_soc_card *card, const char *name_prefix); - - /* MAXIM codec support */ -diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c ---- a/sound/soc/amd/acp/acp-sdw-sof-mach.c -+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c -@@ -314,7 +314,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) - if (!sof_aux) - return -ENOMEM; - -- ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_devs); -+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs); - if (ret < 0) - return ret; - -@@ -390,7 +390,7 @@ static int mc_probe(struct platform_device *pdev) - ctx->private = amd_ctx; - card = &ctx->card; - card->dev = &pdev->dev; -- card->name = "amd-soundwire"; -+ card->name = "amd-sdw"; - card->owner = THIS_MODULE; - card->late_probe = asoc_sdw_card_late_probe; - -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -524,13 +524,13 @@ config SND_SOC_ADAU1977 - tristate - - config SND_SOC_ADAU1977_SPI -- tristate -+ tristate "Analog Devices ADAU1977/ADAU1978/ADAU1979 CODEC - SPI" - depends on SPI_MASTER - select SND_SOC_ADAU1977 - select REGMAP_SPI - - config SND_SOC_ADAU1977_I2C -- tristate -+ tristate "Analog Devices ADAU1977/ADAU1978/ADAU1979 CODEC - I2C" - depends on I2C - select SND_SOC_ADAU1977 - select REGMAP_I2C -diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c ---- a/sound/soc/codecs/adau1977-i2c.c -+++ b/sound/soc/codecs/adau1977-i2c.c -@@ -34,9 +34,18 @@ static const struct i2c_device_id adau1977_i2c_ids[] = { - }; - MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); - -+static const struct of_device_id adau1977_i2c_of_match[] = { -+ { .compatible = "adi,adau1977" }, -+ { .compatible = "adi,adau1978" }, -+ { .compatible = "adi,adau1979" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, adau1977_i2c_of_match); -+ - static struct i2c_driver adau1977_i2c_driver = { - .driver = { - .name = "adau1977", -+ .of_match_table = adau1977_i2c_of_match, - }, - .probe = adau1977_i2c_probe, - .id_table = adau1977_i2c_ids, -diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c ---- a/sound/soc/codecs/adau1977-spi.c -+++ b/sound/soc/codecs/adau1977-spi.c -@@ -53,18 +53,18 @@ static const struct spi_device_id adau1977_spi_ids[] = { - }; - MODULE_DEVICE_TABLE(spi, adau1977_spi_ids); - --static const struct of_device_id adau1977_spi_of_match[] __maybe_unused = { -- { .compatible = "adi,adau1977" }, -- { .compatible = "adi,adau1978" }, -- { .compatible = "adi,adau1979" }, -- { }, -+static const struct of_device_id adau1977_spi_of_match[] = { -+ { .compatible = "adi,adau1977" }, -+ { .compatible = "adi,adau1978" }, -+ { .compatible = "adi,adau1979" }, -+ { }, - }; - MODULE_DEVICE_TABLE(of, adau1977_spi_of_match); - - static struct spi_driver adau1977_spi_driver = { - .driver = { - .name = "adau1977", -- .of_match_table = of_match_ptr(adau1977_spi_of_match), -+ .of_match_table = adau1977_spi_of_match, - }, - .probe = adau1977_spi_probe, - .id_table = adau1977_spi_ids, -diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c ---- a/sound/soc/codecs/rt712-sdca-sdw.c -+++ b/sound/soc/codecs/rt712-sdca-sdw.c -@@ -18,12 +18,16 @@ - static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg) - { - switch (reg) { -+ case 0x004d: - case 0x201a ... 0x201f: - case 0x2029 ... 0x202a: - case 0x202d ... 0x2034: - case 0x2230 ... 0x2232: - case 0x2f01 ... 0x2f0a: - case 0x2f35 ... 0x2f36: -+ case 0x2f3a: -+ case 0x2f3d: -+ case 0x2f41: - case 0x2f50: - case 0x2f54: - case 0x2f58 ... 0x2f5d: -@@ -48,6 +52,7 @@ static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg) - static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg) - { - switch (reg) { -+ case 0x004d: - case 0x201b: - case 0x201c: - case 0x201d: -@@ -56,6 +61,9 @@ static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg) - case 0x2230: - case 0x2f01: - case 0x2f35: -+ case 0x2f3a: -+ case 0x2f3d: -+ case 0x2f41: - case 0x320c: - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0): - case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... -diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c ---- a/sound/soc/codecs/rt712-sdca.c -+++ b/sound/soc/codecs/rt712-sdca.c -@@ -73,14 +73,57 @@ static int rt712_sdca_index_update_bits(struct rt712_sdca_priv *rt712, - return rt712_sdca_index_write(rt712, nid, reg, tmp); - } - -+static void rt712_sdca_clk_patch(struct rt712_sdca_priv *rt712) -+{ -+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0000); -+ regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x03); -+ usleep_range(1000, 1100); -+ regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x02); -+ usleep_range(1000, 1100); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x0080, 0x0000); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x001f, 0x0017); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF3, 0x0010, 0x0000); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF1, 0x0081, 0x0001); -+ regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x03); -+ usleep_range(1000, 1100); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF1, 0x0081, 0x0081); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x0080, 0x0080); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF2, 0x001f, 0x0000); -+ regmap_update_bits(rt712->regmap, RT712_PLL2_CONF3, 0x0010, 0x0010); -+ usleep_range(1000, 1100); -+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0081); -+} -+ -+static void rt712_sdca_clk_patch2(struct rt712_sdca_priv *rt712) -+{ -+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_REG, 0x49, 0x0800, -+ 0x0000); -+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_REG, 0x49, 0xf000, -+ 0x0000); -+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0000); -+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_ANALOG_CTL, 0x0c, 0xc000, -+ 0xc000); -+ rt712_sdca_index_update_bits(rt712, RT712_VENDOR_ANALOG_CTL, 0x00, 0xc000, -+ 0xc000); -+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0081); -+ regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x02); -+ usleep_range(1000, 1100); -+ regmap_write(rt712->regmap, RT712_SDW_ROOT_CLK, 0x03); -+ usleep_range(1000, 1100); -+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, 0x65, 0x0000); -+} -+ - static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712) - { - unsigned int val, loop_rc = 0, loop_dc = 0; - struct device *dev; - struct regmap *regmap = rt712->regmap; -+ unsigned int clk_base; - int chk_cnt = 100; - int ret = 0; - -+ regmap_read(rt712->regmap, RT712_SDW_ROOT_CLK, &clk_base); -+ - mutex_lock(&rt712->calibrate_mutex); - dev = regmap_get_device(regmap); - -@@ -109,8 +152,35 @@ static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712) - if (ret < 0) - goto _cali_fail_; - } -- if (loop_dc == chk_cnt) -- dev_err(dev, "%s, calibration time-out!\n", __func__); -+ -+ if (loop_dc == chk_cnt) { -+ if (clk_base == RT712_CLK_FREQ_24_576MHZ) { -+ rt712_sdca_clk_patch(rt712); -+ rt712_sdca_clk_patch2(rt712); -+ } -+ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100); -+ rt712_sdca_index_write(rt712, RT712_VENDOR_CALI, -+ RT712_DAC_DC_CALI_CTL1, 0x7883); -+ rt712_sdca_index_write(rt712, RT712_VENDOR_CALI, -+ RT712_DAC_DC_CALI_CTL1, 0xf893); -+ rt712_sdca_index_read(rt712, RT712_VENDOR_CALI, -+ RT712_DAC_DC_CALI_CTL1, &val); -+ -+ for (loop_dc = 0; loop_dc < chk_cnt && -+ (val & RT712_DAC_DC_CALI_TRIGGER); loop_dc++) { -+ usleep_range(10000, 11000); -+ ret = rt712_sdca_index_read(rt712, RT712_VENDOR_CALI, -+ RT712_DAC_DC_CALI_CTL1, &val); -+ -+ if (ret < 0) -+ goto _cali_fail_; -+ } -+ -+ if (loop_dc == chk_cnt) -+ dev_err(dev, "%s, calibration time-out!\n", __func__); -+ else -+ dev_dbg(dev, "%s, calibration success!\n", __func__); -+ } - - if (loop_dc == chk_cnt || loop_rc == chk_cnt) - ret = -ETIMEDOUT; -@@ -1759,9 +1829,13 @@ static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712) - - static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712) - { -- int ret = 0; - unsigned int jack_func_status, mic_func_status, amp_func_status; - struct device *dev = &rt712->slave->dev; -+ unsigned int clk_base; -+ int ret = 0; -+ -+ regmap_read(rt712->regmap, RT712_SDW_ROOT_CLK, &clk_base); -+ dev_dbg(dev, "%s clk_base=%x", __func__, clk_base); - - regmap_read(rt712->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status); -@@ -1773,6 +1847,12 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712) - __func__, jack_func_status, mic_func_status, amp_func_status); - - rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL3, 0x7778); -+ -+ if (clk_base == RT712_CLK_FREQ_24_576MHZ) { -+ rt712_sdca_clk_patch(rt712); -+ rt712_sdca_clk_patch2(rt712); -+ } -+ - /* DMIC */ - if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { - rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526); -diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h ---- a/sound/soc/codecs/rt712-sdca.h -+++ b/sound/soc/codecs/rt712-sdca.h -@@ -162,6 +162,16 @@ struct rt712_dmic_kctrl_priv { - #define RT712_EAPD_HIGH 0x2 - #define RT712_EAPD_LOW 0x0 - -+/* SDW clock root frequency */ -+#define RT712_SDW_ROOT_CLK 0x004d -+#define RT712_SDW_SCALE_CLK0 0x0062 -+#define RT712_SDW_SCALE_CLK1 0x0072 -+ -+/* PLL2 config */ -+#define RT712_PLL2_CONF1 0x2f3a -+#define RT712_PLL2_CONF2 0x2f3d -+#define RT712_PLL2_CONF3 0x2f41 -+ - /* RC Calibration register */ - #define RT712_RC_CAL 0x3201 - -@@ -254,6 +264,14 @@ enum rt712_sdca_version { - RT712_VB, - }; - -+enum { -+ RT712_CLK_FREQ_19_2_MHZ = 1, -+ RT712_CLK_FREQ_24MHZ = 2, -+ RT712_CLK_FREQ_24_576MHZ = 3, -+ RT712_CLK_FREQ_22_5792MHZ = 4, -+}; -+ -+ - int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave); - int rt712_sdca_init(struct device *dev, struct regmap *regmap, - struct regmap *mbq_regmap, struct sdw_slave *slave); -diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c ---- a/sound/soc/codecs/rt721-sdca-sdw.c -+++ b/sound/soc/codecs/rt721-sdca-sdw.c -@@ -70,6 +70,7 @@ static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int re - case 0x0310100: - case 0x2000000 ... 0x2000003: - case 0x2000013: -+ case 0x2000026: - case 0x200002c: - case 0x200003c: - case 0x2000046: -@@ -142,6 +143,7 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re - case 0x200000d: - case 0x2000019: - case 0x2000020: -+ case 0x2000026: - case 0x200002c: - case 0x2000030: - case 0x2000046: -@@ -155,6 +157,7 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re - case 0x5810039: - case 0x5b10018: - case 0x5b10019: -+ case 0x6100006: - return true; - default: - return false; -diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c ---- a/sound/soc/codecs/rt721-sdca.c -+++ b/sound/soc/codecs/rt721-sdca.c -@@ -1497,6 +1497,15 @@ int rt721_sdca_init(struct device *dev, struct regmap *regmap, - &soc_sdca_dev_rt721, rt721_sdca_dai, ARRAY_SIZE(rt721_sdca_dai)); - } - -+static void rt721_sdca_reset(struct rt721_sdca_priv *rt721) -+{ -+ rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_VENDOR_REG, -+ RT721_VD_HIDDEN_CTRL, RT721_HIDDEN_REG_SW_RESET, -+ RT721_HIDDEN_REG_SW_RESET); -+ rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, -+ RT721_HDA_LEGACY_RESET_CTL, 0x1, 0x1); -+} -+ - int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave) - { - struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); -@@ -1530,9 +1539,17 @@ int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave) - } - - pm_runtime_get_noresume(&slave->dev); -+ -+ if (!rt721->first_hw_init) -+ rt721_sdca_reset(rt721); -+ - rt721_sdca_dmic_preset(rt721); - rt721_sdca_amp_preset(rt721); - rt721_sdca_jack_preset(rt721); -+ -+ if (rt721->hs_jack && (!rt721->first_hw_init)) -+ rt721_sdca_jack_init(rt721); -+ - if (rt721->first_hw_init) { - regcache_cache_bypass(rt721->regmap, false); - regcache_mark_dirty(rt721->regmap); -diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c ---- a/sound/soc/codecs/wm_adsp.c -+++ b/sound/soc/codecs/wm_adsp.c -@@ -775,9 +775,12 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp, - s++; - } - -+ adsp_dbg(dsp, "Try '%s'\n", fw->filename); - ret = wm_adsp_firmware_request(&fw->firmware, fw->filename, cs_dsp->dev); - if (ret < 0) { -- adsp_dbg(dsp, "Failed to request '%s': %d\n", fw->filename, ret); -+ if (ret != -ENOENT) -+ adsp_dbg(dsp, "Failed to request '%s': %d\n", fw->filename, ret); -+ - kfree(fw->filename); - fw->filename = NULL; - if (ret != -ENOENT) -diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c ---- a/sound/soc/intel/boards/sof_es8336.c -+++ b/sound/soc/intel/boards/sof_es8336.c -@@ -360,6 +360,15 @@ static const struct dmi_system_id sof_es8336_quirk_table[] = { - .driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO | - SOC_ES8336_HEADSET_MIC1) - }, -+ { -+ .callback = sof_es8336_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "NDZ-WXX9"), -+ }, -+ .driver_data = (void *)(SOF_ES8336_HEADPHONE_GPIO | -+ SOC_ES8336_HEADSET_MIC1) -+ }, - {} - }; - -diff --git a/sound/soc/sdw_utils/soc_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c ---- a/sound/soc/sdw_utils/soc_sdw_cs_amp.c -+++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c -@@ -14,7 +14,6 @@ - #include - #include - --#define CS_AMP_CHANNELS_PER_AMP 4 - #define CS35L56_SPK_VOLUME_0DB 400 /* 0dB Max */ - - int asoc_sdw_cs35l56_volume_limit(struct snd_soc_card *card, const char *name_prefix) -@@ -64,51 +63,6 @@ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai - } - EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, "SND_SOC_SDW_UTILS"); - --int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) --{ -- const struct snd_soc_dai_link *dai_link = rtd->dai_link; -- const struct snd_soc_dai_link_ch_map *ch_map; -- const struct snd_soc_dai_link_component *codec_dlc; -- struct snd_soc_dai *codec_dai; -- u8 ch_slot[8] = {}; -- unsigned int amps_per_bus, ch_per_amp, mask; -- int i, ret; -- -- WARN_ON(dai_link->num_cpus > ARRAY_SIZE(ch_slot)); -- -- /* -- * CS35L56 has 4 TX channels. When the capture is aggregated the -- * same bus slots will be allocated to all the amps on a bus. Only -- * one amp on that bus can be transmitting in each slot so divide -- * the available 4 slots between all the amps on a bus. -- */ -- amps_per_bus = dai_link->num_codecs / dai_link->num_cpus; -- if ((amps_per_bus == 0) || (amps_per_bus > CS_AMP_CHANNELS_PER_AMP)) { -- dev_err(rtd->card->dev, "Illegal num_codecs:%u / num_cpus:%u\n", -- dai_link->num_codecs, dai_link->num_cpus); -- return -EINVAL; -- } -- -- ch_per_amp = CS_AMP_CHANNELS_PER_AMP / amps_per_bus; -- -- for_each_rtd_ch_maps(rtd, i, ch_map) { -- codec_dlc = snd_soc_link_to_codec(rtd->dai_link, i); -- codec_dai = snd_soc_find_dai(codec_dlc); -- mask = GENMASK(ch_per_amp - 1, 0) << ch_slot[ch_map->cpu]; -- -- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, mask, 4, 32); -- if (ret < 0) { -- dev_err(rtd->card->dev, "Failed to set TDM slot:%d\n", ret); -- return ret; -- } -- -- ch_slot[ch_map->cpu] += ch_per_amp; -- } -- -- return 0; --} --EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_feedback_rtd_init, "SND_SOC_SDW_UTILS"); -- - int asoc_sdw_cs_amp_init(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_links, - struct asoc_sdw_codec_info *info, -diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c ---- a/sound/soc/sdw_utils/soc_sdw_utils.c -+++ b/sound/soc/sdw_utils/soc_sdw_utils.c -@@ -811,7 +811,6 @@ struct asoc_sdw_codec_info codec_info_list[] = { - .dai_name = "cs35l56-sdw1c", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, -- .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, - }, - }, - .dai_num = 2, -@@ -840,7 +839,6 @@ struct asoc_sdw_codec_info codec_info_list[] = { - .dai_name = "cs35l56-sdw1c", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, -- .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, - }, - }, - .dai_num = 2, -@@ -869,7 +867,6 @@ struct asoc_sdw_codec_info codec_info_list[] = { - .dai_name = "cs35l56-sdw1c", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, -- .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, - }, - }, - .dai_num = 2, -@@ -898,7 +895,6 @@ struct asoc_sdw_codec_info codec_info_list[] = { - .dai_name = "cs35l56-sdw1c", - .dai_type = SOC_SDW_DAI_TYPE_AMP, - .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, -- .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init, - }, - }, - .dai_num = 2, -@@ -1565,7 +1561,7 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai_link_ch_map *ch_maps; - int ch = params_channels(params); -- unsigned int ch_mask; -+ unsigned int cpu_ch_mask, codec_ch_mask; - int num_codecs; - int step; - int i; -@@ -1575,8 +1571,9 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, - - /* Identical data will be sent to all codecs in playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- ch_mask = GENMASK(ch - 1, 0); -+ cpu_ch_mask = GENMASK(ch - 1, 0); - step = 0; -+ codec_ch_mask = 0; - } else { - num_codecs = rtd->dai_link->num_codecs; - -@@ -1586,17 +1583,24 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, - return -EINVAL; - } - -- ch_mask = GENMASK(ch / num_codecs - 1, 0); -- step = hweight_long(ch_mask); -+ cpu_ch_mask = GENMASK(ch / num_codecs - 1, 0); -+ step = hweight_long(cpu_ch_mask); -+ codec_ch_mask = cpu_ch_mask; - } - - /* - * The captured data will be combined from each cpu DAI if the dai - * link has more than one codec DAIs. Set codec channel mask and - * ASoC will set the corresponding channel numbers for each cpu dai. -+ * -+ * sdw_stream_add_slave() assigns different payload offsets to each -+ * codec in a capture stream, so that the same channels on each -+ * codec map to different channels on the CPU. - */ -- for_each_link_ch_maps(rtd->dai_link, i, ch_maps) -- ch_maps->cpu_ch_mask = ch_mask << (i * step); -+ for_each_link_ch_maps(rtd->dai_link, i, ch_maps) { -+ ch_maps->cpu_ch_mask = cpu_ch_mask << (i * step); -+ ch_maps->codec_ch_mask = codec_ch_mask; -+ } - - return 0; - } diff --git a/kernel/0525-asoc-fixes-3.patch.sig b/kernel/0525-asoc-fixes-3.patch.sig deleted file mode 100644 index e53ea2a..0000000 Binary files a/kernel/0525-asoc-fixes-3.patch.sig and /dev/null differ diff --git a/kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch b/kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch deleted file mode 100644 index 3b71148..0000000 --- a/kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c ---- a/sound/soc/sof/amd/acp.c -+++ b/sound/soc/sof/amd/acp.c -@@ -1197,7 +1197,8 @@ int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state) - enable = true; - break; - default: -- break; -+ dev_err(sdev->dev, "Unexpected PCI revision: 0x%x\n", acp_data->pci_rev); -+ return -EINVAL; - } - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable); - snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1); diff --git a/kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch.sig b/kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch.sig deleted file mode 100644 index bb0d2f1..0000000 Binary files a/kernel/0526-sof-amd-acp7x-suspend-unknown-revision.patch.sig and /dev/null differ diff --git a/kernel/0527-sound-fixes-5.patch b/kernel/0527-sound-fixes-5.patch deleted file mode 100644 index f9378d4..0000000 --- a/kernel/0527-sound-fixes-5.patch +++ /dev/null @@ -1,513 +0,0 @@ -diff --git a/include/sound/core.h b/include/sound/core.h ---- a/include/sound/core.h -+++ b/include/sound/core.h -@@ -340,6 +340,15 @@ static inline void snd_card_unref(struct snd_card *card) - - DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T)) - -+/* -+ * For automatic error handling at probe time, assign the card like: -+ * struct snd_card *card __free(snd_card_free) = NULL; -+ * then create and process as usual. -+ * But, don't forget to clear to NULL at successful return for avoiding -+ * the unexpected cleanup! -+ */ -+DEFINE_FREE(snd_card_free, struct snd_card *, if (_T) snd_card_free(_T)) -+ - #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) - - /* device.c */ -diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c ---- a/sound/core/seq/seq_compat.c -+++ b/sound/core/seq/seq_compat.c -@@ -44,7 +44,9 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned - return -EFAULT; - data->kernel = NULL; - -- err = snd_seq_kernel_client_ctl(client->number, cmd, data); -+ scoped_guard(mutex, &client->ioctl_mutex) { -+ err = snd_seq_kernel_client_ctl(client->number, cmd, data); -+ } - if (err < 0) - return err; - -diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c ---- a/sound/hda/codecs/realtek/alc269.c -+++ b/sound/hda/codecs/realtek/alc269.c -@@ -4025,6 +4025,7 @@ enum { - ALC269_FIXUP_SONY_VAIO, - ALC275_FIXUP_SONY_VAIO_GPIO2, - ALC269_FIXUP_DELL_M101Z, -+ ALC256_FIXUP_ASUS_PM3406CHA, - ALC269_FIXUP_SKU_IGNORE, - ALC269_FIXUP_ASUS_G73JW, - ALC269_FIXUP_ASUS_N7601ZM_PINS, -@@ -4124,6 +4125,7 @@ enum { - ALC285_FIXUP_HP_SPECTRE_X360_EB1, - ALC285_FIXUP_HP_SPECTRE_X360_DF1, - ALC285_FIXUP_HP_ENVY_X360, -+ ALC285_FIXUP_HP_ENVY_13AQ, - ALC288_FIXUP_DELL_HEADSET_MODE, - ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, - ALC288_FIXUP_DELL_XPS_13, -@@ -4199,6 +4201,7 @@ enum { - ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE, - ALC225_FIXUP_WYSE_AUTO_MUTE, - ALC225_FIXUP_WYSE_DISABLE_MIC_VREF, -+ ALC225_FIXUP_HP_AIO_SPK, - ALC286_FIXUP_ACER_AIO_HEADSET_MIC, - ALC256_FIXUP_ASUS_HEADSET_MIC, - ALC256_FIXUP_ASUS_MIC_NO_PRESENCE, -@@ -4385,6 +4388,7 @@ enum { - ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET, - ALC285_LENOVO_DAC_RENAME, - ALC287_FIXUP_YOGA9_SPEAKER2_TO_DAC1, -+ ALC256_FIXUP_IPASON_SMARTBOOK_S1, - }; - - /* A special fixup for Lenovo C940 and Yoga Duet 7; -@@ -4482,6 +4486,14 @@ static const struct hda_fixup alc269_fixups[] = { - {} - } - }, -+ [ALC256_FIXUP_ASUS_PM3406CHA] = { -+ .type = HDA_FIXUP_VERBS, -+ .v.verbs = (const struct hda_verb[]) { -+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x10 }, -+ { 0x20, AC_VERB_SET_PROC_COEF, 0x7f20 }, -+ {} -+ } -+ }, - [ALC269_FIXUP_SKU_IGNORE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_sku_ignore, -@@ -5720,6 +5732,14 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC - }, -+ [ALC225_FIXUP_HP_AIO_SPK] = { -+ .type = HDA_FIXUP_VERBS, -+ .v.verbs = (const struct hda_verb[]) { -+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x10 }, -+ { 0x20, AC_VERB_SET_PROC_COEF, 0x0220 }, -+ { } -+ }, -+ }, - [ALC286_FIXUP_ACER_AIO_HEADSET_MIC] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { -@@ -6401,6 +6421,15 @@ static const struct hda_fixup alc269_fixups[] = { - .chained = true, - .chain_id = ALC285_FIXUP_HP_GPIO_AMP_INIT, - }, -+ [ALC285_FIXUP_HP_ENVY_13AQ] = { -+ .type = HDA_FIXUP_PINS, -+ .v.pins = (const struct hda_pintbl[]) { -+ { 0x14, 0x90170150 }, /* front speakers */ -+ { } -+ }, -+ .chained = true, -+ .chain_id = ALC285_FIXUP_HP_GPIO_AMP_INIT, -+ }, - [ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc285_fixup_ideapad_s740_coef, -@@ -7088,6 +7117,8 @@ static const struct hda_fixup alc269_fixups[] = { - [ALC236_FIXUP_DELL_HP_POP_NOISE] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc285_fixup_invalidate_dacs, -+ .chained = true, -+ .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE - }, - [ALC274_FIXUP_HP_89E9_GPIO] = { - .type = HDA_FIXUP_FUNC, -@@ -7150,6 +7181,13 @@ static const struct hda_fixup alc269_fixups[] = { - { } - } - }, -+ [ALC256_FIXUP_IPASON_SMARTBOOK_S1] = { -+ .type = HDA_FIXUP_PINS, -+ .v.pins = (const struct hda_pintbl[]) { -+ { 0x1b, 0x90170110 }, /* the real internal speaker */ -+ { } -+ }, -+ }, - }; - - static const struct hda_quirk alc269_fixup_tbl[] = { -@@ -7197,6 +7235,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), -+ SND_PCI_QUIRK(0x1025, 0x151e, "Acer Nitro AN515-45", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC287_FIXUP_ACER_MICMUTE_LED), -@@ -7210,8 +7249,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED), -+ SND_PCI_QUIRK(0x1025, 0x172c, "Acer Nitro ANV16-41", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x1731, "Acer Predator PHN16-72", ALC2XX_FIXUP_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED), -+ SND_PCI_QUIRK(0x1025, 0x173b, "Acer Swift SFG16-72", ALC245_FIXUP_ACER_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x1758, "Acer Nitro ANV15-41", ALC245_FIXUP_ACER_MICMUTE_LED), - SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2), -@@ -7317,6 +7358,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), - SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), -+ SND_PCI_QUIRK(0x103c, 0x2164, "HP Pavilion 15 Notebook PC", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), -@@ -7399,9 +7441,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x854a, "HP EliteBook 830 G6", ALC285_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x854d, "HP EliteBook 840 G6", ALC285_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x856a, "HP Pavilion 15-cs1xxx", ALC295_FIXUP_HP_PAVILION_MUTE_LED_1B), -+ HDA_CODEC_QUIRK(0x103c, 0x85ba, "HP Pavilion AiO 24", ALC225_FIXUP_HP_AIO_SPK), - SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11), - SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360), - SND_PCI_QUIRK(0x103c, 0x85f0, "HP Laptop 15-dw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), -+ SND_PCI_QUIRK(0x103c, 0x85f1, "HP Laptop 15-dw1xxx", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), - SND_PCI_QUIRK(0x103c, 0x85f3, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x8603, "HP Omen 17-cb0xxx", ALC285_FIXUP_HP_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x860c, "HP ZBook 17 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT), -@@ -7409,6 +7453,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT), - SND_PCI_QUIRK(0x103c, 0x864f, "HP Laptop 15-dy0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), -+ SND_PCI_QUIRK(0x103c, 0x86ad, "HP ENVY 13-aq1xxx", ALC285_FIXUP_HP_ENVY_13AQ), - SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO), - SND_PCI_QUIRK(0x103c, 0x86c8, "HP Laptop 14s-dr1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), -@@ -7437,6 +7482,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8786, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x8787, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED), -+ SND_PCI_QUIRK(0x103c, 0x87b2, "HP Pavilion Gaming Laptop 15-ec1xxx", ALC285_FIXUP_HP_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), - SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x87cb, "HP Pavilion 15-eg0xxx", ALC287_FIXUP_HP_GPIO_LED), -@@ -7497,6 +7543,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x897d, "HP mt440 Mobile Thin Client U74", ALC236_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4), -+ SND_PCI_QUIRK(0x103c, 0x8987, "HP Pavilion 14-dv1001TU", ALC287_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x898a, "HP Pavilion 15-eg100", ALC287_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2), -@@ -7534,7 +7581,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), -- SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x103c, 0x8a31, "HP ENVY x360 2-in-1 Laptop 15-ey0xxx", ALC287_FIXUP_CS35L41_I2C_2_HP_MUTE_LEDS), - SND_PCI_QUIRK(0x103c, 0x8a34, "HP Pavilion x360 2-in-1 Laptop 14-ek0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8a36, "HP Pavilion Plus 14-eh0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8a3d, "HP Victus 15-fb0xxx (MB 8A3D)", ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT), -@@ -7595,6 +7642,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_15_FD0XXX), - SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), -+ SND_PCI_QUIRK(0x103c, 0x8bc7, "HP Pavilion 15-eh3174nw", ALC287_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8bd4, "HP Victus 16-s0xxx (MB 8BD4)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), -@@ -7617,6 +7665,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX), - SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS), - SND_PCI_QUIRK(0x103c, 0x8c2d, "HP Victus 15-fa1xxx (MB 8C2D)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), -+ SND_PCI_QUIRK(0x103c, 0x8c2f, "HP Victus 15-fb2xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8c3f, "HP Victus 15-fa1xxx (MB 8C3F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), - SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), -@@ -7726,6 +7775,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2), -+ SND_PCI_QUIRK(0x103c, 0x8e43, "HP Laptop 15-fd2xxx", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO), - SND_PCI_QUIRK(0x103c, 0x8e60, "HP OmniBook 7 Laptop 16-bh0xxx", ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), -@@ -7829,6 +7879,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK), - SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK), - SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC), -+ SND_PCI_QUIRK(0x1043, 0x1664, "ASUS ExpertBook PM3406CHA", ALC256_FIXUP_ASUS_PM3406CHA), - SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), -@@ -7931,7 +7982,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TXNW2781_I2C), - SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TXNW2781_I2C), - SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TXNW2781_I2C), -- SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TXNW2781_I2C), -+ SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TXNW2781_I2C_ASUS), - SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TXNW2781_I2C), - SND_PCI_QUIRK(0x1043, 0x3fd0, "ASUS B3605CVA", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x3ff0, "ASUS B5405CVA", ALC245_FIXUP_CS35L41_SPI_2), -@@ -7954,6 +8005,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), - SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), - SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), -+ SND_PCI_QUIRK(0x10ec, 0x111e, "Higole F9B", ALC290_FIXUP_MONO_SPEAKERS), - SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), - SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC), - SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -@@ -8179,7 +8231,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x383d, "Legion Y9000X 2019", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3843, "Lenovo Yoga 9i / Yoga Book 9i", ALC287_FIXUP_LENOVO_YOGA_BOOK_9I), -- SND_PCI_QUIRK(0x17aa, 0x3846, "Lenovo Yoga Pro 9 16IAH10", ALC287_FIXUP_YOGA9_SPEAKER2_TO_DAC1), - /* Yoga Pro 7 14IMH9 shares PCI SSID 17aa:3847 with Legion 7 16ACHG6; - * use codec SSID to distinguish them - */ -@@ -8204,6 +8255,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */ - SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C), -+ SND_PCI_QUIRK(0x17aa, 0x3871, "Lenovo ThinkBook 16p Gen 3 ARH", ALC287_FIXUP_YOGA7_14ARB7_I2C), - SND_PCI_QUIRK(0x17aa, 0x3874, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), -@@ -8254,6 +8306,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x38d5, "Yoga S990-16 Pro IMH YC Quad", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38d6, "Yoga S990-16 Pro IMH VECO Quad", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38d7, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN), -+ SND_PCI_QUIRK(0x17aa, 0x38dc, "Lenovo ThinkBook G8", ALC285_FIXUP_SPEAKER2_TO_DAC1), - SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C), - SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C), -@@ -8273,7 +8326,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x17aa, 0x3912, "Lenovo Xiaoxin 14 GT", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC), - SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TXNW2781_I2C), -- SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C), -+ SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_YOGA9_SPEAKER2_TO_DAC1), - SND_PCI_QUIRK(0x17aa, 0x3929, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x392b, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD), - HDA_CODEC_QUIRK(0x17aa, 0x3936, "Legion R9000P ADR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399), -@@ -8369,6 +8422,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x2039, 0x0001, "Inspur S14-G1", ALC295_FIXUP_CHROME_BOOK), - SND_PCI_QUIRK(0x2145, 0x0001, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER), -+ SND_PCI_QUIRK(0x2782, 0x0206, "IPASON SmartBook S1", ALC256_FIXUP_IPASON_SMARTBOOK_S1), - SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13), - SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO), -diff --git a/sound/hda/codecs/realtek/realtek.c b/sound/hda/codecs/realtek/realtek.c ---- a/sound/hda/codecs/realtek/realtek.c -+++ b/sound/hda/codecs/realtek/realtek.c -@@ -1292,6 +1292,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) - } - - switch (codec->core.vendor_id) { -+ case 0x10ec0235: - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; -@@ -1407,6 +1408,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, - }; - - switch (codec->core.vendor_id) { -+ case 0x10ec0235: - case 0x10ec0255: - alc_write_coef_idx(codec, 0x45, 0xc489); - snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); -@@ -1562,6 +1564,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) - alc_process_coef_fw(codec, coef0225); - alc_hp_enable_unmute(codec, 75); - break; -+ case 0x10ec0235: - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; -@@ -1663,6 +1666,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) - }; - - switch (codec->core.vendor_id) { -+ case 0x10ec0235: - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; -@@ -1780,6 +1784,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) - }; - - switch (codec->core.vendor_id) { -+ case 0x10ec0235: - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - break; -@@ -1881,6 +1886,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) - } - - switch (codec->core.vendor_id) { -+ case 0x10ec0235: - case 0x10ec0255: - alc_process_coef_fw(codec, coef0255); - msleep(300); -diff --git a/sound/hda/controllers/tegra.c b/sound/hda/controllers/tegra.c ---- a/sound/hda/controllers/tegra.c -+++ b/sound/hda/controllers/tegra.c -@@ -374,7 +374,8 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) - * in powers of 2, next available ratio is 16 which can be - * used as a limiting factor here. - */ -- if (of_device_is_compatible(np, "nvidia,tegra30-hda")) -+ if (of_device_is_compatible(np, "nvidia,tegra30-hda") || -+ of_device_is_compatible(np, "nvidia,tegra194-hda")) - chip->bus.core.sdo_limit = 16; - - /* codec detection */ -diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c ---- a/sound/pci/ctxfi/cthw20k2.c -+++ b/sound/pci/ctxfi/cthw20k2.c -@@ -1895,6 +1895,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) - - if (hw->model == CTSB1270) { - /* Set up the PCM4220 ADC on Titanium HD */ -+ data = hw_read_20kx(hw, GPIO_DATA); - data &= ~0x0C; - if (1 == info->msr) - data |= 0x00; /* Single Speed Mode 32-50kHz */ -@@ -1903,6 +1904,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) - else - data |= 0x04; /* Quad Speed Mode 108kHz-216kHz */ - hw_write_20kx(hw, GPIO_DATA, data); -+ usleep_range(10000, 11000); - } - - hw_adc_start(hw); -diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c ---- a/sound/pci/ice1712/ice1712.c -+++ b/sound/pci/ice1712/ice1712.c -@@ -2523,7 +2523,7 @@ static int snd_ice1712_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) - { - static int dev; -- struct snd_card *card __free(snd_card_unref) = NULL; -+ struct snd_card *card __free(snd_card_free) = NULL; - struct snd_ice1712 *ice; - int pcm_dev = 0, err; - const struct snd_ice1712_card_info * const *tbl, *c; -diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c ---- a/sound/usb/caiaq/device.c -+++ b/sound/usb/caiaq/device.c -@@ -562,6 +562,9 @@ static int snd_probe(struct usb_interface *intf, - ret = init_card(caiaqdev(card)); - if (ret < 0) { - dev_err(&usb_dev->dev, "unable to init card! (ret=%d)\n", ret); -+#ifdef CONFIG_SND_USB_CAIAQ_INPUT -+ snd_usb_caiaq_input_disconnect(caiaqdev(card)); -+#endif - snd_card_free(card); - return ret; - } -diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c ---- a/sound/usb/line6/playback.c -+++ b/sound/usb/line6/playback.c -@@ -182,6 +182,13 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) - - fsize *= bytes_per_frame; - -+ if (fsize > line6pcm->max_packet_size_out) { -+ dev_err(line6pcm->line6->ifcdev, -+ "playback packet too large: %d > %d\n", -+ fsize, line6pcm->max_packet_size_out); -+ return -EMSGSIZE; -+ } -+ - fout->offset = urb_size; - fout->length = fsize; - urb_size += fsize; -diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c ---- a/sound/usb/misc/ua101.c -+++ b/sound/usb/misc/ua101.c -@@ -1007,6 +1007,15 @@ static int detect_usb_format(struct ua101 *ua) - } - ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); - ua->playback.max_packet_bytes = usb_endpoint_maxp(epd); -+ -+ if (ua->capture.max_packet_bytes / ua->capture.frame_bytes * -+ ua->playback.frame_bytes > ua->playback.max_packet_bytes) { -+ dev_err(&ua->dev->dev, -+ "playback packet size %u too small for %u capture frames\n", -+ ua->playback.max_packet_bytes, -+ ua->capture.max_packet_bytes / ua->capture.frame_bytes); -+ return -ENXIO; -+ } - return 0; - } - -diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c ---- a/sound/usb/mixer_maps.c -+++ b/sound/usb/mixer_maps.c -@@ -749,6 +749,10 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { - .id = USB_ID(0x0db0, 0xa073), - .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map, - }, -+ { /* MSI MAG B850M MORTAR WIFI */ -+ .id = USB_ID(0x0db0, 0xcc78), -+ .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map, -+ }, - { /* MSI TRX40 */ - .id = USB_ID(0x0db0, 0x543d), - .map = trx40_mobo_map, -diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c ---- a/sound/usb/quirks.c -+++ b/sound/usb/quirks.c -@@ -1702,10 +1702,12 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev, - switch (id) { - case USB_ID(0x07fd, 0x0008): /* MOTU M Series, 1st hardware version */ - return snd_usb_motu_m_series_boot_quirk(dev); -- case USB_ID(0x1397, 0x1234): /* Behringer CM1A */ -- return snd_usb_cm1a_boot_quirk(dev); - } - -+ /* Behringer devices may need explicit device descriptor read at boot */ -+ if (USB_ID_VENDOR(id) == 0x1397) -+ return snd_usb_cm1a_boot_quirk(dev); -+ - return 0; - } - -@@ -2366,6 +2368,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_CTL_MSG_DELAY_1M), - DEVICE_FLG(0x0a73, 0x003a, /* Mackie DLZ Creator XS */ - QUIRK_FLAG_ALWAYS_SET_RATE), -+ DEVICE_FLG(0x0b05, 0x1826, /* ASUS SupremeFX Hi-Fi */ -+ QUIRK_FLAG_DISABLE_AUTOSUSPEND), -+ DEVICE_FLG(0x0b05, 0x1827, /* ASUS SupremeFX Hi-Fi */ -+ QUIRK_FLAG_DISABLE_AUTOSUSPEND), - DEVICE_FLG(0x0b05, 0x18a6, /* ASUSTek Computer, Inc. */ - QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE), - DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */ -@@ -2510,8 +2516,6 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY), - DEVICE_FLG(0x262a, 0x9302, /* ddHiFi TC44C */ - QUIRK_FLAG_DSD_RAW), -- DEVICE_FLG(0x2708, 0x0002, /* Audient iD14 */ -- QUIRK_FLAG_IGNORE_CTL_ERROR), - DEVICE_FLG(0x2772, 0x0502, /* Musical Fidelity M6s DAC */ - 0), /* for avoiding QUIRK_FLAG_DSD_RAW with vendor match */ - DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */ -@@ -2542,6 +2546,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_IGNORE_CTL_ERROR), - DEVICE_FLG(0x3255, 0x0000, /* Luxman D-10X */ - QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY), -+ DEVICE_FLG(0x32bb, 0x0004, /* HiBy FC4 */ -+ QUIRK_FLAG_DSD_RAW), - DEVICE_FLG(0x3302, 0x17c2, /* TTGK Technology USB-C Audio */ - QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY), - DEVICE_FLG(0x339b, 0x3a07, /* Synaptics HONOR USB-C HEADSET */ -@@ -2608,6 +2614,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { - QUIRK_FLAG_DSD_RAW), - VENDOR_FLG(0x2622, /* IAG Limited devices */ - QUIRK_FLAG_DSD_RAW), -+ VENDOR_FLG(0x2708, /* Audient devices */ -+ QUIRK_FLAG_IGNORE_CTL_ERROR), - VENDOR_FLG(0x2772, /* Musical Fidelity devices */ - QUIRK_FLAG_DSD_RAW), - VENDOR_FLG(0x278b, /* Rotel? */ diff --git a/kernel/0527-sound-fixes-5.patch.sig b/kernel/0527-sound-fixes-5.patch.sig deleted file mode 100644 index 04aa2c3..0000000 Binary files a/kernel/0527-sound-fixes-5.patch.sig and /dev/null differ diff --git a/kernel/0528-asoc-fixes-4.patch b/kernel/0528-asoc-fixes-4.patch deleted file mode 100644 index 2290ae4..0000000 --- a/kernel/0528-asoc-fixes-4.patch +++ /dev/null @@ -1,523 +0,0 @@ -diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c ---- a/drivers/spi/spi-cs42l43.c -+++ b/drivers/spi/spi-cs42l43.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -215,12 +216,108 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi) - return CS42L43_SPI_MAX_LENGTH; - } - -+/* -+ * Workaround needed for two speaker ID pins in one ACPI GpioIo() but -+ * the Linux-specific _DSD property only contains one pin. -+ * Create a temporary acpi_gpio_mapping pointing at both pins. -+ */ -+static const struct acpi_gpio_params cs42l43_2bit_speaker_id_from_one_gpioio_params[] = { -+ [0] = { -+ .crs_entry_index = 0, -+ .line_index = 0, -+ }, -+ [1] = { -+ .crs_entry_index = 0, -+ .line_index = 1, -+ }, -+}; -+ -+static const struct acpi_gpio_mapping cs42l43_2bit_speaker_id_from_one_gpioio_mapping[] = { -+ { -+ .name = "spk-id-quirk-gpios", -+ .data = cs42l43_2bit_speaker_id_from_one_gpioio_params, -+ .size = ARRAY_SIZE(cs42l43_2bit_speaker_id_from_one_gpioio_params), -+ }, -+ { } -+}; -+ -+static int cs42l43_get_2bit_speaker_id_from_one_gpioio(struct cs42l43_spi *priv, int *result) -+{ -+ struct fwnode_reference_args args; -+ struct acpi_device *adev; -+ struct gpio_desc *desc; -+ u32 spkid = 0; -+ int i, ret; -+ -+ /* Use the _DSD property to get the node containing the GpioIo() */ -+ ret = fwnode_property_get_reference_args(dev_fwnode(priv->dev), "spk-id-gpios", -+ NULL, 3, 0, &args); -+ if (ret) -+ return ret; -+ -+ struct fwnode_handle *fwnode __free(fwnode_handle) = args.fwnode; -+ -+ /* An acpi_gpio_mapping must be added to the node that contains the GpioIo() */ -+ adev = to_acpi_device_node(fwnode); -+ if (!adev) -+ return -EINVAL; -+ -+ ret = acpi_dev_add_driver_gpios(adev, cs42l43_2bit_speaker_id_from_one_gpioio_mapping); -+ if (ret) -+ return ret; -+ -+ /* gpiod_get_array() can't read from a mapping in a child node */ -+ for (i = 0; i < ARRAY_SIZE(cs42l43_2bit_speaker_id_from_one_gpioio_params); i++) { -+ desc = fwnode_gpiod_get_index(fwnode, "spk-id-quirk", i, GPIOD_IN, -+ dev_name(priv->dev)); -+ if (IS_ERR(desc)) { -+ ret = PTR_ERR(desc); -+ goto out; -+ } -+ -+ ret = gpiod_get_value_cansleep(desc); -+ gpiod_put(desc); -+ if (ret < 0) -+ goto out; -+ -+ spkid |= (u32)ret << i; -+ } -+ -+ dev_dbg(priv->dev, "spk-id-gpios = %u\n", spkid); -+ *result = spkid; -+ ret = 0; -+out: -+ acpi_dev_remove_driver_gpios(adev); -+ -+ return ret; -+} -+ -+static const struct dmi_system_id cs42l43_spk_id_quirks[] = { -+ { -+ .ident = "Dell XPS 13 DX13260", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0E53"), -+ }, -+ .driver_data = cs42l43_get_2bit_speaker_id_from_one_gpioio, -+ }, -+ { } -+}; -+ - static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result) - { -+ const struct dmi_system_id *dmi_id; - struct gpio_descs *descs; - u32 spkid; - int i, ret; - -+ dmi_id = dmi_first_match(cs42l43_spk_id_quirks); -+ if (dmi_id) { -+ int (*get_speaker_id)(struct cs42l43_spi *priv, int *result) = dmi_id->driver_data; -+ -+ return get_speaker_id(priv, result); -+ } -+ - descs = gpiod_get_array_optional(priv->dev, "spk-id", GPIOD_IN); - if (!descs) - return 0; -diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c ---- a/sound/soc/amd/acp-config.c -+++ b/sound/soc/amd/acp-config.c -@@ -51,6 +51,13 @@ static const struct dmi_system_id acp70_acpi_flag_override_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "83V9"), - }, - }, -+ { -+ /* Lenovo Yoga Pro 7 14ASP9 (Strix Point, ACP 7.0) */ -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "83HN"), -+ }, -+ }, - { - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC"), -@@ -63,6 +70,13 @@ static const struct dmi_system_id acp70_acpi_flag_override_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook 18 M1807GA"), - }, - }, -+ { -+ /* ASUS Zenbook S14 UM5406GA (Strix Point, ACP 7.0) */ -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Zenbook S14 UM5406GA"), -+ }, -+ }, - { - /* HP OmniBook X Flip 14-kc0xxx (Strix Point, ACP 7.2) */ - .matches = { -diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig ---- a/sound/soc/amd/acp/Kconfig -+++ b/sound/soc/amd/acp/Kconfig -@@ -181,6 +181,7 @@ config SND_SOC_AMD_LEGACY_SDW_MACH - select SND_SOC_RT715_SDW - select SND_SOC_RT715_SDCA_SDW - select SND_SOC_RT722_SDCA_SDW -+ select SND_SOC_TAS2783_SDW - help - This option enables Legacy(No DSP) sound card support for SoundWire - enabled AMD platforms along with ACP PDM controller. -diff --git a/sound/soc/amd/acp/amd-acp70-acpi-match.c b/sound/soc/amd/acp/amd-acp70-acpi-match.c ---- a/sound/soc/amd/acp/amd-acp70-acpi-match.c -+++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c -@@ -748,7 +748,27 @@ static const struct snd_soc_acpi_link_adr acp70_rt721_only[] = { - {} - }; - -+static const struct snd_soc_acpi_link_adr acp70_tas2783a_l0_rt712_vb_l1[] = { -+ { -+ .mask = BIT(0), -+ .num_adr = ARRAY_SIZE(tas2783_2_adr), -+ .adr_d = tas2783_2_adr, -+ }, -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(rt712_vb_1_group1_adr), -+ .adr_d = rt712_vb_1_group1_adr, -+ }, -+ {} -+}; -+ - struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[] = { -+ { -+ .link_mask = BIT(0) | BIT(1), -+ .links = acp70_tas2783a_l0_rt712_vb_l1, -+ .machine_check = snd_soc_acpi_amd_sdca_is_device_rt712_vb, -+ .drv_name = "amd_sdw", -+ }, - { - .link_mask = BIT(0), - .links = acp70_tas2783_2, -diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c ---- a/sound/soc/amd/yc/acp6x-mach.c -+++ b/sound/soc/amd/yc/acp6x-mach.c -@@ -248,6 +248,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "21J6"), - } - }, -+ { -+ .driver_data = &acp6x_card, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "21JN"), -+ } -+ }, - { - .driver_data = &acp6x_card, - .matches = { -@@ -381,6 +388,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "83Q3"), - } - }, -+ { -+ .driver_data = &acp6x_card, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "83UU"), -+ } -+ }, - { - .driver_data = &acp6x_card, - .matches = { -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -1989,9 +1989,7 @@ config SND_SOC_RT715_SDCA_SDW - config SND_SOC_RT766_SDCA_SDW - tristate "Realtek RT766 SDCA Codec - SDW" - depends on SOUNDWIRE -- depends on SND_SOC_SDCA -- select SND_SOC_SDCA_HID -- select SND_SOC_SDCA_IRQ -+ depends on SND_SOC_SDCA_CLASS - select REGMAP_SOUNDWIRE - select REGMAP_SOUNDWIRE_MBQ - -diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c ---- a/sound/soc/codecs/lpass-wsa-macro.c -+++ b/sound/soc/codecs/lpass-wsa-macro.c -@@ -1841,6 +1841,7 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w, - int event) - { - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); -+ unsigned int gain; - u16 gain_reg; - u16 reg; - struct wsa_macro *wsa = snd_soc_component_get_drvdata(component); -@@ -1882,6 +1883,8 @@ static int wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w, - CDC_WSA_RX_PGA_HALF_DB_MASK, - CDC_WSA_RX_PGA_HALF_DB_ENABLE); - } -+ gain = snd_soc_component_read(component, gain_reg); -+ snd_soc_component_write(component, gain_reg, gain); - wsa_macro_config_ear_spkr_gain(component, wsa, - event, gain_reg); - break; -diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c ---- a/sound/soc/codecs/max98363.c -+++ b/sound/soc/codecs/max98363.c -@@ -200,7 +200,7 @@ static int max98363_sdw_dai_hw_params(struct snd_pcm_substream *substream, - struct max98363_priv *max98363 = - snd_soc_component_get_drvdata(component); - -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; - enum sdw_data_direction direction; - struct sdw_stream_runtime *stream; -diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c ---- a/sound/soc/codecs/rt1017-sdca-sdw.c -+++ b/sound/soc/codecs/rt1017-sdca-sdw.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -573,11 +574,10 @@ static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - { - struct snd_soc_component *component = dai->component; - struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); -- struct sdw_stream_config stream_config; -+ struct sdw_stream_config stream_config = {0}; - struct sdw_port_config port_config; -- enum sdw_data_direction direction; - struct sdw_stream_runtime *sdw_stream; -- int retval, port, num_channels, ch_mask; -+ int retval, port; - unsigned int sampling_rate; - - dev_dbg(dai->dev, "%s %s", __func__, dai->name); -@@ -591,28 +591,17 @@ static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream, - - /* SoundWire specific configuration */ - /* port 1 for playback */ -- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- direction = SDW_DATA_DIR_RX; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - port = 1; -- } else { -- direction = SDW_DATA_DIR_TX; -+ else - port = 2; -- } - -- num_channels = params_channels(params); -- ch_mask = (1 << num_channels) - 1; -- -- stream_config.frame_rate = params_rate(params); -- stream_config.ch_count = num_channels; -- stream_config.bps = snd_pcm_format_width(params_format(params)); -- stream_config.direction = direction; -- -- port_config.ch_mask = ch_mask; -+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config); - port_config.num = port; - - dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n", -- params_rate(params), num_channels, snd_pcm_format_width(params_format(params)), -- direction, ch_mask, port); -+ stream_config.frame_rate, stream_config.ch_count, stream_config.bps, -+ stream_config.direction, port_config.ch_mask, port); - - retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config, - &port_config, 1, sdw_stream); -diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c ---- a/sound/soc/codecs/rt274.c -+++ b/sound/soc/codecs/rt274.c -@@ -619,9 +619,11 @@ static int rt274_hw_params(struct snd_pcm_substream *substream, - unsigned int val = 0; - int d_len_code = 0, c_len_code = 0; - -+ /* bit 14 Sample Rate Base, 0: 48kHz 1: 44.1kHz */ - switch (params_rate(params)) { -- /* bit 14 0:48K 1:44.1K */ - case 44100: -+ val |= BIT(14); -+ break; - case 48000: - break; - default: -diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c ---- a/sound/soc/codecs/rt286.c -+++ b/sound/soc/codecs/rt286.c -@@ -953,7 +953,7 @@ static int rt286_probe(struct snd_soc_component *component) - - if (rt286->i2c->irq) - schedule_delayed_work(&rt286->jack_detect_work, -- msecs_to_jiffies(50)); -+ msecs_to_jiffies(1250)); - return 0; - } - -diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c ---- a/sound/soc/codecs/wm8903.c -+++ b/sound/soc/codecs/wm8903.c -@@ -676,7 +676,7 @@ SOC_ENUM("DRC Decay Rate", drc_decay), - SOC_ENUM("DRC FF Delay", drc_ff_delay), - SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0), - SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0), --SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), -+SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_1, 6, 3, 0, drc_tlv_max), - SOC_ENUM("DRC QR Decay Rate", drc_qr_decay), - SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0), - SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0), -diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c ---- a/sound/soc/intel/boards/bytcr_rt5651.c -+++ b/sound/soc/intel/boards/bytcr_rt5651.c -@@ -410,6 +410,23 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { - BYT_RT5651_HP_LR_SWAPPED | - BYT_RT5651_MONO_SPEAKER), - }, -+ { -+ /* Chuwi Hi8 (CWI513) with a BIOS using generic DMI strings */ -+ .callback = byt_rt5651_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), -+ DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), -+ /* Above matches are too generic, add bios-date match */ -+ DMI_MATCH(DMI_BIOS_DATE, "05/21/2016"), -+ }, -+ .driver_data = (void *)(BYT_RT5651_MCLK_EN | -+ BYT_RT5651_JD1_1 | -+ BYT_RT5651_OVCD_TH_2000UA | -+ BYT_RT5651_OVCD_SF_1P0 | -+ BYT_RT5651_IN2_MAP | -+ BYT_RT5651_HP_LR_SWAPPED | -+ BYT_RT5651_MONO_SPEAKER), -+ }, - { - /* Chuwi Vi8 Plus (CWI519) */ - .callback = byt_rt5651_quirk_cb, -diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c ---- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c -+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c -@@ -745,6 +745,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { - .links = lnl_cs42l43_l0, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-lnl-cs42l43-l0.tplg", -+ .machine_check = snd_soc_acpi_intel_force_function_topology, - .get_function_tplg_files = sof_sdw_get_tplg_files, - }, - { -diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c ---- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c -+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c -@@ -53,6 +53,22 @@ bool snd_soc_acpi_intel_no_function_topology(void *arg) - } - EXPORT_SYMBOL_NS(snd_soc_acpi_intel_no_function_topology, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); - -+static const struct dmi_system_id force_function_topology_quirk_table[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "83R0"), -+ }, -+ }, -+ {} -+}; -+ -+bool snd_soc_acpi_intel_force_function_topology(void *arg) -+{ -+ return !dmi_check_system(force_function_topology_quirk_table); -+} -+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_force_function_topology, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); -+ - bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg) - { - return snd_soc_acpi_intel_sdca_is_device_rt712_vb(arg) && -diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h ---- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h -+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h -@@ -11,6 +11,7 @@ - - bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg); - bool snd_soc_acpi_intel_no_function_topology(void *arg); -+bool snd_soc_acpi_intel_force_function_topology(void *arg); - bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg); - - #endif -diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c ---- a/sound/soc/qcom/lpass-cpu.c -+++ b/sound/soc/qcom/lpass-cpu.c -@@ -1234,8 +1234,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) - } - if (drvdata->mi2s_playback_sd_mode[dai_id] == - LPAIF_I2SCTL_MODE_QUAD01) { -- variant->dai_driver[dai_id].playback.channels_min = 4; -- variant->dai_driver[dai_id].playback.channels_max = 4; -+ variant->dai_driver[i].playback.channels_min = 4; -+ variant->dai_driver[i].playback.channels_max = 4; - } - } - -diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c ---- a/sound/soc/sdca/sdca_class_function.c -+++ b/sound/soc/sdca/sdca_class_function.c -@@ -388,20 +388,27 @@ static int class_function_probe(struct auxiliary_device *auxdev, - - ret = devm_pm_runtime_enable(dev); - if (ret) -- return ret; -+ goto err_pm; - - ret = class_function_boot(drv); - if (ret) -- return ret; -+ goto err_pm; - - ret = devm_snd_soc_register_component(dev, cmp_drv, dais, num_dais); -- if (ret) -- return dev_err_probe(dev, ret, "failed to register component\n"); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to register component\n"); -+ goto err_pm; -+ } - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - - return 0; -+ -+err_pm: -+ pm_runtime_put_sync(dev); -+ -+ return ret; - } - - static void class_function_remove(struct auxiliary_device *auxdev) -@@ -490,8 +497,6 @@ static int class_function_suspend(struct device *dev) - struct class_function_drv *drv = auxiliary_get_drvdata(auxdev); - int ret; - -- drv->suspended = true; -- - /* Ensure runtime resume runs on resume */ - ret = pm_runtime_resume_and_get(dev); - if (ret) { -@@ -499,6 +504,8 @@ static int class_function_suspend(struct device *dev) - return ret; - } - -+ drv->suspended = true; -+ - sdca_irq_disable(drv->function, drv->core->irq_info); - - ret = pm_runtime_force_suspend(dev); -diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c ---- a/sound/soc/tegra/tegra186_asrc.c -+++ b/sound/soc/tegra/tegra186_asrc.c -@@ -828,7 +828,7 @@ static const struct snd_kcontrol_new tegra186_asrc_controls[] = { - tegra186_asrc_put_input_threshold), - - SOC_SINGLE_EXT("Stream6 Input Threshold", -- ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0, -+ ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 5), 0, 3, 0, - tegra186_asrc_get_input_threshold, - tegra186_asrc_put_input_threshold), - diff --git a/kernel/0528-asoc-fixes-4.patch.sig b/kernel/0528-asoc-fixes-4.patch.sig deleted file mode 100644 index e560a52..0000000 Binary files a/kernel/0528-asoc-fixes-4.patch.sig and /dev/null differ diff --git a/kernel/0541-cvs-nova-lake-acpi-id.patch b/kernel/0541-cvs-nova-lake-acpi-id.patch deleted file mode 100644 index 2e401f7..0000000 --- a/kernel/0541-cvs-nova-lake-acpi-id.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -867,6 +867,7 @@ static const char * const acpi_honor_dep_ids[] = { - "INTC10DE", /* CVS (LNL) driver must be loaded to allow camera streaming */ - "INTC10E0", /* CVS (ARL) driver must be loaded to allow camera streaming */ - "INTC10E1", /* CVS (PTL) driver must be loaded to allow camera streaming */ -+ "INTC10FA", /* CVS (NVL) driver must be loaded to allow camera streaming */ - "RSCV0001", /* RISC-V PLIC */ - "RSCV0002", /* RISC-V APLIC */ - "RSCV0005", /* RISC-V SBI MPXY MBOX */ -diff --git a/drivers/media/i2c/cvs/core.c b/drivers/media/i2c/cvs/core.c ---- a/drivers/media/i2c/cvs/core.c -+++ b/drivers/media/i2c/cvs/core.c -@@ -962,6 +962,7 @@ static const struct acpi_device_id intel_cvs_acpi_match[] = { - { "INTC10DE" }, /* LNL */ - { "INTC10E0" }, /* ARL */ - { "INTC10E1" }, /* PTL */ -+ { "INTC10FA" }, /* NVL */ - { } - }; - MODULE_DEVICE_TABLE(acpi, intel_cvs_acpi_match); -diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c ---- a/drivers/media/pci/intel/ipu-bridge.c -+++ b/drivers/media/pci/intel/ipu-bridge.c -@@ -171,6 +171,7 @@ static const struct acpi_device_id ivsc_acpi_ids[] = { - { "INTC10DE" }, /* LNL */ - { "INTC10E0" }, /* ARL */ - { "INTC10E1" }, /* PTL */ -+ { "INTC10FA" }, /* NVL */ - }; - - /* diff --git a/kernel/0541-cvs-nova-lake-acpi-id.patch.sig b/kernel/0541-cvs-nova-lake-acpi-id.patch.sig deleted file mode 100644 index 818b577..0000000 Binary files a/kernel/0541-cvs-nova-lake-acpi-id.patch.sig and /dev/null differ diff --git a/kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch b/kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch deleted file mode 100644 index 6a78d2e..0000000 --- a/kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff --git a/drivers/media/i2c/cvs/core.c b/drivers/media/i2c/cvs/core.c ---- a/drivers/media/i2c/cvs/core.c -+++ b/drivers/media/i2c/cvs/core.c -@@ -723,8 +723,6 @@ static int cvs_core_probe(struct device *dev, struct i2c_client *i2c) - } - - if (ctx->res == ICVS_FULLCAP) { -- struct gpio_desc *wake; -- - ctx->rst = devm_gpiod_get(dev, "rst", GPIOD_OUT_HIGH); - if (IS_ERR(ctx->rst)) { - ret = dev_err_probe(dev, PTR_ERR(ctx->rst), -@@ -732,14 +730,12 @@ static int cvs_core_probe(struct device *dev, struct i2c_client *i2c) - goto err_put_ipu; - } - -- wake = devm_gpiod_get(dev, "wake", GPIOD_IN); -- if (IS_ERR(wake)) { -- ret = dev_err_probe(dev, PTR_ERR(wake), -- "failed to get wake GPIO\n"); -- goto err_put_ipu; -- } -- -- ctx->irq = gpiod_to_irq(wake); -+ /* -+ * Do not request the line: another device's _CRS may list -+ * the same pin, and its driver would then fail with -EBUSY. -+ */ -+ ctx->irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), -+ "wake", 0); - if (ctx->irq < 0) { - ret = dev_err_probe(dev, ctx->irq, - "failed to get wake IRQ\n"); diff --git a/kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch.sig b/kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch.sig deleted file mode 100644 index 57011b1..0000000 Binary files a/kernel/0542-media-cvs-wake-irq-without-claiming-gpio.patch.sig and /dev/null differ diff --git a/kernel/0543-media-laptop-cameras.patch b/kernel/0543-media-laptop-cameras.patch deleted file mode 100644 index 9ffdd20..0000000 --- a/kernel/0543-media-laptop-cameras.patch +++ /dev/null @@ -1,3293 +0,0 @@ -diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig ---- a/drivers/media/i2c/Kconfig -+++ b/drivers/media/i2c/Kconfig -@@ -259,6 +259,7 @@ config VIDEO_IMX335 - - config VIDEO_IMX355 - tristate "Sony IMX355 sensor support" -+ select V4L2_CCI_I2C - help - This is a Video4Linux2 sensor driver for the Sony - IMX355 camera. -@@ -287,6 +288,16 @@ config VIDEO_IMX415 - To compile this driver as a module, choose M here: the - module will be called imx415. - -+config VIDEO_IMX471 -+ tristate "Sony IMX471 sensor support" -+ select V4L2_CCI_I2C -+ help -+ This is a Video4Linux2 sensor driver for the Sony -+ IMX471 camera. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called imx471. -+ - config VIDEO_MAX9271_LIB - tristate - -diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile ---- a/drivers/media/i2c/Makefile -+++ b/drivers/media/i2c/Makefile -@@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o - obj-$(CONFIG_VIDEO_IMX355) += imx355.o - obj-$(CONFIG_VIDEO_IMX412) += imx412.o - obj-$(CONFIG_VIDEO_IMX415) += imx415.o -+obj-$(CONFIG_VIDEO_IMX471) += imx471.o - obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o - obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o - obj-$(CONFIG_VIDEO_KS0127) += ks0127.o -diff --git a/drivers/media/i2c/cvs/core.c b/drivers/media/i2c/cvs/core.c ---- a/drivers/media/i2c/cvs/core.c -+++ b/drivers/media/i2c/cvs/core.c -@@ -31,6 +31,7 @@ - - #define PCI_DEVICE_ID_INTEL_IPU7 0x645d /* MTL / LNL */ - #define PCI_DEVICE_ID_INTEL_IPU7P5 0xb05d /* ARL / PTL */ -+#define PCI_DEVICE_ID_INTEL_IPU8 0xd719 /* NVL */ - - /* - * IPU7 PCI device IDs not covered by ipu6_pci_tbl in ipu6-pci-table.h. -@@ -39,6 +40,7 @@ - static const struct pci_device_id icvs_ipu7_tbl[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7P5) }, -+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU8) }, - { } - }; - -diff --git a/drivers/media/i2c/cvs/icvs.h b/drivers/media/i2c/cvs/icvs.h ---- a/drivers/media/i2c/cvs/icvs.h -+++ b/drivers/media/i2c/cvs/icvs.h -@@ -432,7 +432,6 @@ enum icvs_state { - * @freq_ctrl: (future) frequency control pointer - * @pads: Local media pads (sink/source) - * @nr_of_lanes: Active CSI-2 lane count -- * @link_freq: Current link frequency (Hz) - * @ipu_link: PM runtime device link (IPU consumer, CVS supplier) - * @res: Resource capability (light/full) - * @caps: Reported device protocol capabilities -@@ -458,7 +457,6 @@ struct icvs { - struct v4l2_ctrl *freq_ctrl; - struct media_pad pads[ICVS_CSI_NUM_PADS]; - u32 nr_of_lanes; -- u64 link_freq; - struct device_link *ipu_link; - enum icvs_resources res; - struct icvs_dev_capabilities caps; -diff --git a/drivers/media/i2c/cvs/v4l2.c b/drivers/media/i2c/cvs/v4l2.c ---- a/drivers/media/i2c/cvs/v4l2.c -+++ b/drivers/media/i2c/cvs/v4l2.c -@@ -46,6 +46,7 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = { - /** - * csi_set_link_cfg - Program default CSI-2 link parameters - * @ctx: CVS device context -+ * @link_freq: Link frequency (Hz) - * - * Populates a HOST_SET_MIPI_CONFIG command using current lane count and - * link frequency, then submits it to the device. -@@ -53,12 +54,12 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = { - * - * Return: 0 on success or negative errno. - */ --static int csi_set_link_cfg(struct icvs *ctx) -+static int csi_set_link_cfg(struct icvs *ctx, u64 link_freq) - { - struct icvs_cmd cmd = { - .cmd_id = cpu_to_be16(ICVS_HOST_SET_MIPI_CONFIG), - .param.conf.nr_of_lanes = ctx->nr_of_lanes, -- .param.conf.link_freq = ctx->link_freq, -+ .param.conf.link_freq = link_freq, - }; - size_t cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.conf); - -@@ -91,7 +92,7 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd, - struct v4l2_subdev *remote_sd = - media_entity_to_v4l2_subdev(ctx->remote->entity); - struct device *dev = cvs_dev(ctx); -- s64 freq; -+ s64 link_freq; - int ret; - - /* cvs_set_link_owner(ICVS_CSI_LINK_HOST) */ -@@ -99,15 +100,14 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd, - if (ret < 0) - return ret; - -- freq = v4l2_get_link_freq(ctx->remote, 0, 0); -- if (freq < 0) { -- ret = freq; -+ link_freq = v4l2_get_link_freq(ctx->remote, 0, 0); -+ if (link_freq < 0) { -+ ret = link_freq; - goto err_rpm_put; - } -- ctx->link_freq = freq; - - if (ctx->i2c_client) { -- ret = csi_set_link_cfg(ctx); -+ ret = csi_set_link_cfg(ctx, link_freq); - if (ret < 0) - goto err_rpm_put_sync; - } -@@ -345,7 +345,6 @@ static int cvs_csi_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, - if (freq < 0) - return -EINVAL; - -- ctx->link_freq = freq; - cfg->link_freq = freq; - - return 0; -diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c ---- a/drivers/media/i2c/imx355.c -+++ b/drivers/media/i2c/imx355.c -@@ -9,74 +9,97 @@ - #include - #include - #include -+#include - #include - #include - -+#include - #include - #include - #include - #include - --#define IMX355_REG_MODE_SELECT 0x0100 -+#define IMX355_REG_MODE_SELECT CCI_REG8(0x0100) - #define IMX355_MODE_STANDBY 0x00 - #define IMX355_MODE_STREAMING 0x01 - - /* Chip ID */ --#define IMX355_REG_CHIP_ID 0x0016 -+#define IMX355_REG_CHIP_ID CCI_REG16(0x0016) - #define IMX355_CHIP_ID 0x0355 - -+#define IMX355_REG_LANE_SEL CCI_REG8(0x0114) -+ -+/* PLL registers that depend on the external clock frequency */ -+#define IMX355_REG_EXTCLK_FREQ CCI_REG16(0x0136) -+#define IMX355_REG_PLL_OP_PREDIV CCI_REG8(0x030d) -+#define IMX355_REG_PLL_OP_MUL CCI_REG16(0x030e) -+#define IMX355_REG_PLL_IVT_PCK_DIV CCI_REG8(0x0301) -+#define IMX355_REG_PLL_IVT_SYSCK_DIV CCI_REG8(0x0303) -+#define IMX355_PLL_OP_PREDIV 2 -+#define IMX355_PLL_IVT_PCK_DIV 5 -+ - /* V_TIMING internal */ --#define IMX355_REG_FLL 0x0340 -+#define IMX355_REG_FLL CCI_REG16(0x0340) - #define IMX355_FLL_MAX 0xffff -+#define IMX355_VBLANK_MIN 20 -+ -+#define IMX355_REG_LLP CCI_REG16(0x0342) -+#define IMX355_LLP_MAX 0xffff -+ -+#define IMX355_REG_X_ADD_START CCI_REG16(0x0344) -+#define IMX355_REG_Y_ADD_START CCI_REG16(0x0346) -+#define IMX355_REG_X_ADD_END CCI_REG16(0x0348) -+#define IMX355_REG_Y_ADD_END CCI_REG16(0x034a) -+#define IMX355_REG_X_OUT_SIZE CCI_REG16(0x034c) -+#define IMX355_REG_Y_OUT_SIZE CCI_REG16(0x034e) - - /* Exposure control */ --#define IMX355_REG_EXPOSURE 0x0202 -+#define IMX355_REG_EXPOSURE CCI_REG16(0x0202) - #define IMX355_EXPOSURE_MIN 1 - #define IMX355_EXPOSURE_STEP 1 - #define IMX355_EXPOSURE_DEFAULT 0x0282 -+#define IMX355_EXPOSURE_OFFSET 10 - - /* Analog gain control */ --#define IMX355_REG_ANALOG_GAIN 0x0204 -+#define IMX355_REG_ANALOG_GAIN CCI_REG16(0x0204) - #define IMX355_ANA_GAIN_MIN 0 - #define IMX355_ANA_GAIN_MAX 960 - #define IMX355_ANA_GAIN_STEP 1 - #define IMX355_ANA_GAIN_DEFAULT 0 - - /* Digital gain control */ --#define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070 --#define IMX355_REG_DIG_GAIN_GLOBAL 0x020e -+#define IMX355_REG_DPGA_USE_GLOBAL_GAIN CCI_REG8(0x3070) -+#define IMX355_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e) - #define IMX355_DGTL_GAIN_MIN 256 - #define IMX355_DGTL_GAIN_MAX 4095 - #define IMX355_DGTL_GAIN_STEP 1 - #define IMX355_DGTL_GAIN_DEFAULT 256 - - /* Test Pattern Control */ --#define IMX355_REG_TEST_PATTERN 0x0600 -+#define IMX355_REG_TEST_PATTERN CCI_REG16(0x0600) - #define IMX355_TEST_PATTERN_DISABLED 0 - #define IMX355_TEST_PATTERN_SOLID_COLOR 1 - #define IMX355_TEST_PATTERN_COLOR_BARS 2 - #define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3 - #define IMX355_TEST_PATTERN_PN9 4 - -+#define IMX355_REG_REQ_LINK_BIT_RATE CCI_REG16(0x0820) -+ -+#define IMX355_REG_BINNING_MODE CCI_REG8(0x0900) -+#define IMX355_REG_BINNING_TYPE CCI_REG8(0x0901) -+#define IMX355_REG_BINNING_WEIGHTING CCI_REG8(0x0902) -+ - /* Flip Control */ --#define IMX355_REG_ORIENTATION 0x0101 -+#define IMX355_REG_ORIENTATION CCI_REG8(0x0101) - --/* default link frequency and external clock */ --#define IMX355_LINK_FREQ_DEFAULT 360000000LL --#define IMX355_EXT_CLK 19200000 --#define IMX355_LINK_FREQ_INDEX 0 -- --/* number of data lanes */ --#define IMX355_DATA_LANES 4 -- --struct imx355_reg { -- u16 address; -- u8 val; --}; -+#define IMX355_PIXEL_ARRAY_TOP 0 -+#define IMX355_PIXEL_ARRAY_LEFT 0 -+#define IMX355_PIXEL_ARRAY_WIDTH 3280 -+#define IMX355_PIXEL_ARRAY_HEIGHT 2464 - - struct imx355_reg_list { - u32 num_of_regs; -- const struct imx355_reg *regs; -+ const struct cci_reg_sequence *regs; - }; - - /* Mode : resolution and related config&values */ -@@ -85,28 +108,58 @@ struct imx355_mode { - u32 width; - /* Frame height */ - u32 height; -+ struct v4l2_rect crop; - - /* V-timing */ - u32 fll_def; -- u32 fll_min; - - /* H-timing */ - u32 llp; - -- /* index of link frequency */ -- u32 link_freq_index; -- - /* Default register values */ - struct imx355_reg_list reg_list; - }; - -+struct imx355_clk_params { -+ u32 ext_clk; -+ u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */ -+ u16 pll_op_mpy[2]; /* OP system PLL multiplier */ -+ u8 pll_op_prediv[2]; /* OP system pre PLL d */ -+}; -+ -+/* -+ * The clock tree is in single PLL mode, so PREDIV_VT and MPY_IVT do nothing. -+ * In 4 lane mode the MIPI rate is 360Mhz (720Mbit/s) and pixel rate is -+ * 288MPix/s. -+ * In 2 lane mode the MIPI rate is 444MHz (888Mbit/s) and pixel rate -+ * 177.6MPix/s with a 24MHz clock, and 441.6MHz (883.2Mbit/s) and 176.6MPix/s -+ * with a 19.2MHz clock. -+ */ -+static const struct imx355_clk_params imx355_clk_params[] = { -+ { -+ .ext_clk = 19200000, -+ .extclk_freq = 0x1333, -+ .pll_op_mpy = { 75, 92 }, -+ .pll_op_prediv = { 2, 2 } -+ }, -+ { -+ .ext_clk = 24000000, -+ .extclk_freq = 0x1800, -+ .pll_op_mpy = { 60, 111 }, -+ .pll_op_prediv = { 2, 3 } -+ }, -+}; -+ - struct imx355_hwcfg { -+ s64 link_freq_menu; - unsigned long link_freq_bitmap; -+ unsigned int num_lanes; - }; - - struct imx355 { - struct device *dev; - struct clk *clk; -+ struct regmap *regmap; - - struct v4l2_subdev sd; - struct media_pad pad; -@@ -114,24 +167,14 @@ struct imx355 { - struct v4l2_ctrl_handler ctrl_handler; - /* V4L2 Controls */ - struct v4l2_ctrl *link_freq; -- struct v4l2_ctrl *pixel_rate; - struct v4l2_ctrl *vblank; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *exposure; - struct v4l2_ctrl *vflip; - struct v4l2_ctrl *hflip; - -- /* Current mode */ -- const struct imx355_mode *cur_mode; -- - struct imx355_hwcfg *hwcfg; -- -- /* -- * Mutex for serialized access: -- * Protect sensor set pad format and start/stop streaming safely. -- * Protect access to sensor v4l2 controls. -- */ -- struct mutex mutex; -+ const struct imx355_clk_params *clk_params; - - struct gpio_desc *reset_gpio; - struct regulator_bulk_data *supplies; -@@ -143,750 +186,147 @@ static const struct regulator_bulk_data imx355_supplies[] = { - { .supply = "dovdd" }, - }; - --static const struct imx355_reg imx355_global_regs[] = { -- { 0x0136, 0x13 }, -- { 0x0137, 0x33 }, -- { 0x304e, 0x03 }, -- { 0x4348, 0x16 }, -- { 0x4350, 0x19 }, -- { 0x4408, 0x0a }, -- { 0x440c, 0x0b }, -- { 0x4411, 0x5f }, -- { 0x4412, 0x2c }, -- { 0x4623, 0x00 }, -- { 0x462c, 0x0f }, -- { 0x462d, 0x00 }, -- { 0x462e, 0x00 }, -- { 0x4684, 0x54 }, -- { 0x480a, 0x07 }, -- { 0x4908, 0x07 }, -- { 0x4909, 0x07 }, -- { 0x490d, 0x0a }, -- { 0x491e, 0x0f }, -- { 0x4921, 0x06 }, -- { 0x4923, 0x28 }, -- { 0x4924, 0x28 }, -- { 0x4925, 0x29 }, -- { 0x4926, 0x29 }, -- { 0x4927, 0x1f }, -- { 0x4928, 0x20 }, -- { 0x4929, 0x20 }, -- { 0x492a, 0x20 }, -- { 0x492c, 0x05 }, -- { 0x492d, 0x06 }, -- { 0x492e, 0x06 }, -- { 0x492f, 0x06 }, -- { 0x4930, 0x03 }, -- { 0x4931, 0x04 }, -- { 0x4932, 0x04 }, -- { 0x4933, 0x05 }, -- { 0x595e, 0x01 }, -- { 0x5963, 0x01 }, -- { 0x3030, 0x01 }, -- { 0x3031, 0x01 }, -- { 0x3045, 0x01 }, -- { 0x4010, 0x00 }, -- { 0x4011, 0x00 }, -- { 0x4012, 0x00 }, -- { 0x4013, 0x01 }, -- { 0x68a8, 0xfe }, -- { 0x68a9, 0xff }, -- { 0x6888, 0x00 }, -- { 0x6889, 0x00 }, -- { 0x68b0, 0x00 }, -- { 0x3058, 0x00 }, -- { 0x305a, 0x00 }, -+static const struct cci_reg_sequence imx355_global_regs[] = { -+ { CCI_REG8(0x304e), 0x03 }, -+ { CCI_REG8(0x4348), 0x16 }, -+ { CCI_REG8(0x4350), 0x19 }, -+ { CCI_REG8(0x4408), 0x0a }, -+ { CCI_REG8(0x440c), 0x0b }, -+ { CCI_REG8(0x4411), 0x5f }, -+ { CCI_REG8(0x4412), 0x2c }, -+ { CCI_REG8(0x4623), 0x00 }, -+ { CCI_REG8(0x462c), 0x0f }, -+ { CCI_REG8(0x462d), 0x00 }, -+ { CCI_REG8(0x462e), 0x00 }, -+ { CCI_REG8(0x4684), 0x54 }, -+ { CCI_REG8(0x480a), 0x07 }, -+ { CCI_REG8(0x4908), 0x07 }, -+ { CCI_REG8(0x4909), 0x07 }, -+ { CCI_REG8(0x490d), 0x0a }, -+ { CCI_REG8(0x491e), 0x0f }, -+ { CCI_REG8(0x4921), 0x06 }, -+ { CCI_REG8(0x4923), 0x28 }, -+ { CCI_REG8(0x4924), 0x28 }, -+ { CCI_REG8(0x4925), 0x29 }, -+ { CCI_REG8(0x4926), 0x29 }, -+ { CCI_REG8(0x4927), 0x1f }, -+ { CCI_REG8(0x4928), 0x20 }, -+ { CCI_REG8(0x4929), 0x20 }, -+ { CCI_REG8(0x492a), 0x20 }, -+ { CCI_REG8(0x492c), 0x05 }, -+ { CCI_REG8(0x492d), 0x06 }, -+ { CCI_REG8(0x492e), 0x06 }, -+ { CCI_REG8(0x492f), 0x06 }, -+ { CCI_REG8(0x4930), 0x03 }, -+ { CCI_REG8(0x4931), 0x04 }, -+ { CCI_REG8(0x4932), 0x04 }, -+ { CCI_REG8(0x4933), 0x05 }, -+ { CCI_REG8(0x595e), 0x01 }, -+ { CCI_REG8(0x5963), 0x01 }, -+ { CCI_REG8(0x3030), 0x01 }, -+ { CCI_REG8(0x3031), 0x01 }, -+ { CCI_REG8(0x3045), 0x01 }, -+ { CCI_REG8(0x4010), 0x00 }, -+ { CCI_REG8(0x4011), 0x00 }, -+ { CCI_REG8(0x4012), 0x00 }, -+ { CCI_REG8(0x4013), 0x01 }, -+ { CCI_REG8(0x68a8), 0xfe }, -+ { CCI_REG8(0x68a9), 0xff }, -+ { CCI_REG8(0x6888), 0x00 }, -+ { CCI_REG8(0x6889), 0x00 }, -+ { CCI_REG8(0x68b0), 0x00 }, -+ { CCI_REG8(0x3058), 0x00 }, -+ { CCI_REG8(0x305a), 0x00 }, -+ { CCI_REG8(0x0112), 0x0a }, -+ { CCI_REG8(0x0113), 0x0a }, -+ { IMX355_REG_PLL_IVT_PCK_DIV, IMX355_PLL_IVT_PCK_DIV }, -+ { CCI_REG8(0x0303), 0x01 }, -+ { CCI_REG8(0x0305), 0x02 }, -+ { CCI_REG8(0x0306), 0x00 }, -+ { CCI_REG8(0x0307), 0x78 }, -+ { CCI_REG8(0x030b), 0x01 }, -+ { IMX355_REG_PLL_OP_PREDIV, IMX355_PLL_OP_PREDIV }, -+ { CCI_REG8(0x0310), 0x00 }, -+ { CCI_REG8(0x0220), 0x00 }, -+ { CCI_REG8(0x0222), 0x01 }, -+ { CCI_REG8(0x3088), 0x04 }, -+ { CCI_REG8(0x6813), 0x02 }, -+ { CCI_REG8(0x6835), 0x07 }, -+ { CCI_REG8(0x6836), 0x01 }, -+ { CCI_REG8(0x6837), 0x04 }, -+ { CCI_REG8(0x684d), 0x07 }, -+ { CCI_REG8(0x684e), 0x01 }, -+ { CCI_REG8(0x684f), 0x04 }, - }; - --static const struct imx355_reg_list imx355_global_setting = { -- .num_of_regs = ARRAY_SIZE(imx355_global_regs), -- .regs = imx355_global_regs, -+static const struct cci_reg_sequence mode_3268x2448_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_3268x2448_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x0a }, -- { 0x0341, 0x37 }, -- { 0x0344, 0x00 }, -- { 0x0345, 0x08 }, -- { 0x0346, 0x00 }, -- { 0x0347, 0x08 }, -- { 0x0348, 0x0c }, -- { 0x0349, 0xcb }, -- { 0x034a, 0x09 }, -- { 0x034b, 0x97 }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x00 }, -- { 0x0901, 0x11 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x0c }, -- { 0x034d, 0xc4 }, -- { 0x034e, 0x09 }, -- { 0x034f, 0x90 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_3264x2448_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_3264x2448_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x0a }, -- { 0x0341, 0x37 }, -- { 0x0344, 0x00 }, -- { 0x0345, 0x08 }, -- { 0x0346, 0x00 }, -- { 0x0347, 0x08 }, -- { 0x0348, 0x0c }, -- { 0x0349, 0xc7 }, -- { 0x034a, 0x09 }, -- { 0x034b, 0x97 }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x00 }, -- { 0x0901, 0x11 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x0c }, -- { 0x034d, 0xc0 }, -- { 0x034e, 0x09 }, -- { 0x034f, 0x90 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_3280x2464_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_3280x2464_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x0a }, -- { 0x0341, 0x37 }, -- { 0x0344, 0x00 }, -- { 0x0345, 0x00 }, -- { 0x0346, 0x00 }, -- { 0x0347, 0x00 }, -- { 0x0348, 0x0c }, -- { 0x0349, 0xcf }, -- { 0x034a, 0x09 }, -- { 0x034b, 0x9f }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x00 }, -- { 0x0901, 0x11 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x0c }, -- { 0x034d, 0xd0 }, -- { 0x034e, 0x09 }, -- { 0x034f, 0xa0 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1940x1096_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1940x1096_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x02 }, -- { 0x0345, 0xa0 }, -- { 0x0346, 0x02 }, -- { 0x0347, 0xac }, -- { 0x0348, 0x0a }, -- { 0x0349, 0x33 }, -- { 0x034a, 0x06 }, -- { 0x034b, 0xf3 }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x00 }, -- { 0x0901, 0x11 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x07 }, -- { 0x034d, 0x94 }, -- { 0x034e, 0x04 }, -- { 0x034f, 0x48 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1936x1096_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1936x1096_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x02 }, -- { 0x0345, 0xa0 }, -- { 0x0346, 0x02 }, -- { 0x0347, 0xac }, -- { 0x0348, 0x0a }, -- { 0x0349, 0x2f }, -- { 0x034a, 0x06 }, -- { 0x034b, 0xf3 }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x00 }, -- { 0x0901, 0x11 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x07 }, -- { 0x034d, 0x90 }, -- { 0x034e, 0x04 }, -- { 0x034f, 0x48 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1924x1080_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1924x1080_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x02 }, -- { 0x0345, 0xa8 }, -- { 0x0346, 0x02 }, -- { 0x0347, 0xb4 }, -- { 0x0348, 0x0a }, -- { 0x0349, 0x2b }, -- { 0x034a, 0x06 }, -- { 0x034b, 0xeb }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x00 }, -- { 0x0901, 0x11 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x07 }, -- { 0x034d, 0x84 }, -- { 0x034e, 0x04 }, -- { 0x034f, 0x38 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1920x1080_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1920x1080_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x02 }, -- { 0x0345, 0xa8 }, -- { 0x0346, 0x02 }, -- { 0x0347, 0xb4 }, -- { 0x0348, 0x0a }, -- { 0x0349, 0x27 }, -- { 0x034a, 0x06 }, -- { 0x034b, 0xeb }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x00 }, -- { 0x0901, 0x11 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x07 }, -- { 0x034d, 0x80 }, -- { 0x034e, 0x04 }, -- { 0x034f, 0x38 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1640x1232_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1640x1232_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x07 }, -- { 0x0343, 0x2c }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x00 }, -- { 0x0345, 0x00 }, -- { 0x0346, 0x00 }, -- { 0x0347, 0x00 }, -- { 0x0348, 0x0c }, -- { 0x0349, 0xcf }, -- { 0x034a, 0x09 }, -- { 0x034b, 0x9f }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x01 }, -- { 0x0901, 0x22 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x06 }, -- { 0x034d, 0x68 }, -- { 0x034e, 0x04 }, -- { 0x034f, 0xd0 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1640x922_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1640x922_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x07 }, -- { 0x0343, 0x2c }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x00 }, -- { 0x0345, 0x00 }, -- { 0x0346, 0x01 }, -- { 0x0347, 0x30 }, -- { 0x0348, 0x0c }, -- { 0x0349, 0xcf }, -- { 0x034a, 0x08 }, -- { 0x034b, 0x63 }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x01 }, -- { 0x0901, 0x22 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x06 }, -- { 0x034d, 0x68 }, -- { 0x034e, 0x03 }, -- { 0x034f, 0x9a }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1300x736_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1300x736_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x07 }, -- { 0x0343, 0x2c }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x01 }, -- { 0x0345, 0x58 }, -- { 0x0346, 0x01 }, -- { 0x0347, 0xf0 }, -- { 0x0348, 0x0b }, -- { 0x0349, 0x7f }, -- { 0x034a, 0x07 }, -- { 0x034b, 0xaf }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x01 }, -- { 0x0901, 0x22 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x05 }, -- { 0x034d, 0x14 }, -- { 0x034e, 0x02 }, -- { 0x034f, 0xe0 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1296x736_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1296x736_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x07 }, -- { 0x0343, 0x2c }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x01 }, -- { 0x0345, 0x58 }, -- { 0x0346, 0x01 }, -- { 0x0347, 0xf0 }, -- { 0x0348, 0x0b }, -- { 0x0349, 0x77 }, -- { 0x034a, 0x07 }, -- { 0x034b, 0xaf }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x01 }, -- { 0x0901, 0x22 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x05 }, -- { 0x034d, 0x10 }, -- { 0x034e, 0x02 }, -- { 0x034f, 0xe0 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1284x720_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1284x720_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x07 }, -- { 0x0343, 0x2c }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x01 }, -- { 0x0345, 0x68 }, -- { 0x0346, 0x02 }, -- { 0x0347, 0x00 }, -- { 0x0348, 0x0b }, -- { 0x0349, 0x6f }, -- { 0x034a, 0x07 }, -- { 0x034b, 0x9f }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x01 }, -- { 0x0901, 0x22 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x05 }, -- { 0x034d, 0x04 }, -- { 0x034e, 0x02 }, -- { 0x034f, 0xd0 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_1280x720_regs[] = { -+ { CCI_REG8(0x0700), 0x00 }, -+ { CCI_REG8(0x0701), 0x10 }, - }; - --static const struct imx355_reg mode_1280x720_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x07 }, -- { 0x0343, 0x2c }, -- { 0x0340, 0x05 }, -- { 0x0341, 0x1a }, -- { 0x0344, 0x01 }, -- { 0x0345, 0x68 }, -- { 0x0346, 0x02 }, -- { 0x0347, 0x00 }, -- { 0x0348, 0x0b }, -- { 0x0349, 0x67 }, -- { 0x034a, 0x07 }, -- { 0x034b, 0x9f }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x01 }, -- { 0x0901, 0x22 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x05 }, -- { 0x034d, 0x00 }, -- { 0x034e, 0x02 }, -- { 0x034f, 0xd0 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x00 }, -- { 0x0701, 0x10 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, --}; -- --static const struct imx355_reg mode_820x616_regs[] = { -- { 0x0112, 0x0a }, -- { 0x0113, 0x0a }, -- { 0x0114, 0x03 }, -- { 0x0342, 0x0e }, -- { 0x0343, 0x58 }, -- { 0x0340, 0x02 }, -- { 0x0341, 0x8c }, -- { 0x0344, 0x00 }, -- { 0x0345, 0x00 }, -- { 0x0346, 0x00 }, -- { 0x0347, 0x00 }, -- { 0x0348, 0x0c }, -- { 0x0349, 0xcf }, -- { 0x034a, 0x09 }, -- { 0x034b, 0x9f }, -- { 0x0220, 0x00 }, -- { 0x0222, 0x01 }, -- { 0x0900, 0x01 }, -- { 0x0901, 0x44 }, -- { 0x0902, 0x00 }, -- { 0x034c, 0x03 }, -- { 0x034d, 0x34 }, -- { 0x034e, 0x02 }, -- { 0x034f, 0x68 }, -- { 0x0301, 0x05 }, -- { 0x0303, 0x01 }, -- { 0x0305, 0x02 }, -- { 0x0306, 0x00 }, -- { 0x0307, 0x78 }, -- { 0x030b, 0x01 }, -- { 0x030d, 0x02 }, -- { 0x030e, 0x00 }, -- { 0x030f, 0x4b }, -- { 0x0310, 0x00 }, -- { 0x0700, 0x02 }, -- { 0x0701, 0x78 }, -- { 0x0820, 0x0b }, -- { 0x0821, 0x40 }, -- { 0x3088, 0x04 }, -- { 0x6813, 0x02 }, -- { 0x6835, 0x07 }, -- { 0x6836, 0x01 }, -- { 0x6837, 0x04 }, -- { 0x684d, 0x07 }, -- { 0x684e, 0x01 }, -- { 0x684f, 0x04 }, -+static const struct cci_reg_sequence mode_820x616_regs[] = { -+ { CCI_REG8(0x0700), 0x02 }, -+ { CCI_REG8(0x0701), 0x78 }, - }; - - static const char * const imx355_test_pattern_menu[] = { -@@ -897,23 +337,19 @@ static const char * const imx355_test_pattern_menu[] = { - "Pseudorandom Sequence (PN9)", - }; - --/* -- * When adding more than the one below, make sure the disallowed ones will -- * actually be disabled in the LINK_FREQ control. -- */ --static const s64 link_freq_menu_items[] = { -- IMX355_LINK_FREQ_DEFAULT, --}; -- - /* Mode configs */ - static const struct imx355_mode supported_modes[] = { - { - .width = 3280, - .height = 2464, -+ .crop = { -+ .width = 3280, -+ .height = 2464, -+ .left = 0, -+ .top = 0, -+ }, - .fll_def = 2615, -- .fll_min = 2615, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), - .regs = mode_3280x2464_regs, -@@ -922,10 +358,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 3268, - .height = 2448, -+ .crop = { -+ .width = 3268, -+ .height = 2448, -+ .left = 8, -+ .top = 8, -+ }, - .fll_def = 2615, -- .fll_min = 2615, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_3268x2448_regs), - .regs = mode_3268x2448_regs, -@@ -934,10 +374,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 3264, - .height = 2448, -+ .crop = { -+ .width = 3264, -+ .height = 2448, -+ .left = 8, -+ .top = 8, -+ }, - .fll_def = 2615, -- .fll_min = 2615, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs), - .regs = mode_3264x2448_regs, -@@ -946,10 +390,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1940, - .height = 1096, -+ .crop = { -+ .width = 1940, -+ .height = 1096, -+ .left = 672, -+ .top = 684, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1940x1096_regs), - .regs = mode_1940x1096_regs, -@@ -958,10 +406,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1936, - .height = 1096, -+ .crop = { -+ .width = 1936, -+ .height = 1096, -+ .left = 672, -+ .top = 684, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs), - .regs = mode_1936x1096_regs, -@@ -970,10 +422,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1924, - .height = 1080, -+ .crop = { -+ .width = 1924, -+ .height = 1080, -+ .left = 680, -+ .top = 692, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1924x1080_regs), - .regs = mode_1924x1080_regs, -@@ -982,10 +438,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1920, - .height = 1080, -+ .crop = { -+ .width = 1920, -+ .height = 1080, -+ .left = 680, -+ .top = 692, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), - .regs = mode_1920x1080_regs, -@@ -994,10 +454,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1640, - .height = 1232, -+ .crop = { -+ .width = 3280, -+ .height = 2464, -+ .left = 0, -+ .top = 0, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 1836, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs), - .regs = mode_1640x1232_regs, -@@ -1006,10 +470,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1640, - .height = 922, -+ .crop = { -+ .width = 3280, -+ .height = 1844, -+ .left = 0, -+ .top = 304, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 1836, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1640x922_regs), - .regs = mode_1640x922_regs, -@@ -1018,10 +486,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1300, - .height = 736, -+ .crop = { -+ .width = 2600, -+ .height = 1472, -+ .left = 344, -+ .top = 496, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 1836, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1300x736_regs), - .regs = mode_1300x736_regs, -@@ -1030,10 +502,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1296, - .height = 736, -+ .crop = { -+ .width = 2592, -+ .height = 1472, -+ .left = 344, -+ .top = 496, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 1836, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1296x736_regs), - .regs = mode_1296x736_regs, -@@ -1042,10 +518,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1284, - .height = 720, -+ .crop = { -+ .width = 2568, -+ .height = 1440, -+ .left = 360, -+ .top = 512, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 1836, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1284x720_regs), - .regs = mode_1284x720_regs, -@@ -1054,10 +534,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 1280, - .height = 720, -+ .crop = { -+ .width = 2560, -+ .height = 1440, -+ .left = 360, -+ .top = 512, -+ }, - .fll_def = 1306, -- .fll_min = 1306, - .llp = 1836, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), - .regs = mode_1280x720_regs, -@@ -1066,10 +550,14 @@ static const struct imx355_mode supported_modes[] = { - { - .width = 820, - .height = 616, -+ .crop = { -+ .width = 3280, -+ .height = 2464, -+ .left = 0, -+ .top = 0, -+ }, - .fll_def = 652, -- .fll_min = 652, - .llp = 3672, -- .link_freq_index = IMX355_LINK_FREQ_INDEX, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_820x616_regs), - .regs = mode_820x616_regs, -@@ -1095,116 +583,28 @@ static u32 imx355_get_format_code(struct imx355 *imx355) - { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, }, - }; - -- lockdep_assert_held(&imx355->mutex); - code = codes[imx355->vflip->val][imx355->hflip->val]; - - return code; - } - --/* Read registers up to 4 at a time */ --static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val) --{ -- struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); -- struct i2c_msg msgs[2]; -- u8 addr_buf[2]; -- u8 data_buf[4] = { 0 }; -- int ret; -- -- if (len > 4) -- return -EINVAL; -- -- put_unaligned_be16(reg, addr_buf); -- /* Write register address */ -- msgs[0].addr = client->addr; -- msgs[0].flags = 0; -- msgs[0].len = ARRAY_SIZE(addr_buf); -- msgs[0].buf = addr_buf; -- -- /* Read data from register */ -- msgs[1].addr = client->addr; -- msgs[1].flags = I2C_M_RD; -- msgs[1].len = len; -- msgs[1].buf = &data_buf[4 - len]; -- -- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -- if (ret != ARRAY_SIZE(msgs)) -- return -EIO; -- -- *val = get_unaligned_be32(data_buf); -- -- return 0; --} -- --/* Write registers up to 4 at a time */ --static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val) --{ -- struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); -- u8 buf[6]; -- -- if (len > 4) -- return -EINVAL; -- -- put_unaligned_be16(reg, buf); -- put_unaligned_be32(val << (8 * (4 - len)), buf + 2); -- if (i2c_master_send(client, buf, len + 2) != len + 2) -- return -EIO; -- -- return 0; --} -- --/* Write a list of registers */ --static int imx355_write_regs(struct imx355 *imx355, -- const struct imx355_reg *regs, u32 len) --{ -- int ret; -- u32 i; -- -- for (i = 0; i < len; i++) { -- ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val); -- if (ret) { -- dev_err_ratelimited(imx355->dev, -- "write reg 0x%4.4x return err %d", -- regs[i].address, ret); -- -- return ret; -- } -- } -- -- return 0; --} -- --/* Open sub-device */ --static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) --{ -- struct imx355 *imx355 = to_imx355(sd); -- struct v4l2_mbus_framefmt *try_fmt = -- v4l2_subdev_state_get_format(fh->state, 0); -- -- mutex_lock(&imx355->mutex); -- -- /* Initialize try_fmt */ -- try_fmt->width = imx355->cur_mode->width; -- try_fmt->height = imx355->cur_mode->height; -- try_fmt->code = imx355_get_format_code(imx355); -- try_fmt->field = V4L2_FIELD_NONE; -- -- mutex_unlock(&imx355->mutex); -- -- return 0; --} -- - static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) - { - struct imx355 *imx355 = container_of(ctrl->handler, - struct imx355, ctrl_handler); -+ const struct v4l2_mbus_framefmt *format = NULL; -+ struct v4l2_subdev_state *state; - s64 max; - int ret; - -+ state = v4l2_subdev_get_locked_active_state(&imx355->sd); -+ format = v4l2_subdev_state_get_format(state, 0); -+ - /* Propagate change of current control to all related controls */ - switch (ctrl->id) { - case V4L2_CID_VBLANK: - /* Update max exposure while meeting expected vblanking */ -- max = imx355->cur_mode->height + ctrl->val - 10; -+ max = format->height + ctrl->val - IMX355_EXPOSURE_OFFSET; - __v4l2_ctrl_modify_range(imx355->exposure, - imx355->exposure->minimum, - max, imx355->exposure->step, max); -@@ -1221,31 +621,31 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) - switch (ctrl->id) { - case V4L2_CID_ANALOGUE_GAIN: - /* Analog gain = 1024/(1024 - ctrl->val) times */ -- ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2, -- ctrl->val); -+ ret = cci_write(imx355->regmap, IMX355_REG_ANALOG_GAIN, -+ ctrl->val, NULL); - break; - case V4L2_CID_DIGITAL_GAIN: -- ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2, -- ctrl->val); -+ ret = cci_write(imx355->regmap, IMX355_REG_DIG_GAIN_GLOBAL, -+ ctrl->val, NULL); - break; - case V4L2_CID_EXPOSURE: -- ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2, -- ctrl->val); -+ ret = cci_write(imx355->regmap, IMX355_REG_EXPOSURE, -+ ctrl->val, NULL); - break; - case V4L2_CID_VBLANK: - /* Update FLL that meets expected vertical blanking */ -- ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2, -- imx355->cur_mode->height + ctrl->val); -+ ret = cci_write(imx355->regmap, IMX355_REG_FLL, -+ format->height + ctrl->val, NULL); - break; - case V4L2_CID_TEST_PATTERN: -- ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN, -- 2, ctrl->val); -+ ret = cci_write(imx355->regmap, IMX355_REG_TEST_PATTERN, -+ ctrl->val, NULL); - break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: -- ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1, -- imx355->hflip->val | -- imx355->vflip->val << 1); -+ ret = cci_write(imx355->regmap, IMX355_REG_ORIENTATION, -+ imx355->hflip->val | imx355->vflip->val << 1, -+ NULL); - break; - default: - ret = -EINVAL; -@@ -1272,9 +672,7 @@ static int imx355_enum_mbus_code(struct v4l2_subdev *sd, - if (code->index > 0) - return -EINVAL; - -- mutex_lock(&imx355->mutex); - code->code = imx355_get_format_code(imx355); -- mutex_unlock(&imx355->mutex); - - return 0; - } -@@ -1288,12 +686,9 @@ static int imx355_enum_frame_size(struct v4l2_subdev *sd, - if (fse->index >= ARRAY_SIZE(supported_modes)) - return -EINVAL; - -- mutex_lock(&imx355->mutex); - if (fse->code != imx355_get_format_code(imx355)) { -- mutex_unlock(&imx355->mutex); - return -EINVAL; - } -- mutex_unlock(&imx355->mutex); - - fse->min_width = supported_modes[fse->index].width; - fse->max_width = fse->min_width; -@@ -1311,36 +706,10 @@ static void imx355_update_pad_format(struct imx355 *imx355, - fmt->format.height = mode->height; - fmt->format.code = imx355_get_format_code(imx355); - fmt->format.field = V4L2_FIELD_NONE; --} -- --static int imx355_do_get_pad_format(struct imx355 *imx355, -- struct v4l2_subdev_state *sd_state, -- struct v4l2_subdev_format *fmt) --{ -- struct v4l2_mbus_framefmt *framefmt; -- -- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -- framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); -- fmt->format = *framefmt; -- } else { -- imx355_update_pad_format(imx355, imx355->cur_mode, fmt); -- } -- -- return 0; --} -- --static int imx355_get_pad_format(struct v4l2_subdev *sd, -- struct v4l2_subdev_state *sd_state, -- struct v4l2_subdev_format *fmt) --{ -- struct imx355 *imx355 = to_imx355(sd); -- int ret; -- -- mutex_lock(&imx355->mutex); -- ret = imx355_do_get_pad_format(imx355, sd_state, fmt); -- mutex_unlock(&imx355->mutex); -- -- return ret; -+ fmt->format.colorspace = V4L2_COLORSPACE_RAW; -+ fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601; -+ fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; -+ fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; - } - - static int -@@ -1351,13 +720,8 @@ imx355_set_pad_format(struct v4l2_subdev *sd, - struct imx355 *imx355 = to_imx355(sd); - const struct imx355_mode *mode; - struct v4l2_mbus_framefmt *framefmt; -- s32 vblank_def; -- s32 vblank_min; -+ struct v4l2_rect *crop; - s64 h_blank; -- u64 pixel_rate; -- u32 height; -- -- mutex_lock(&imx355->mutex); - - /* - * Only one bayer order is supported. -@@ -1370,23 +734,25 @@ imx355_set_pad_format(struct v4l2_subdev *sd, - width, height, - fmt->format.width, fmt->format.height); - imx355_update_pad_format(imx355, mode, fmt); -- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -- framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); -- *framefmt = fmt->format; -- } else { -- imx355->cur_mode = mode; -- pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; -- do_div(pixel_rate, 10); -- __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate); -+ framefmt = v4l2_subdev_state_get_format(sd_state, 0); -+ -+ *framefmt = fmt->format; -+ -+ crop = v4l2_subdev_state_get_crop(sd_state, 0); -+ crop->width = mode->crop.width; -+ crop->height = mode->crop.height; -+ crop->left = mode->crop.left; -+ crop->top = mode->crop.top; -+ -+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Update limits and set FPS to default */ -- height = imx355->cur_mode->height; -- vblank_def = imx355->cur_mode->fll_def - height; -- vblank_min = imx355->cur_mode->fll_min - height; -- height = IMX355_FLL_MAX - height; -- __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1, -- vblank_def); -- __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def); -- h_blank = mode->llp - imx355->cur_mode->width; -+ __v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN, -+ IMX355_FLL_MAX - mode->height, 1, -+ mode->fll_def - mode->height); -+ __v4l2_ctrl_s_ctrl(imx355->vblank, mode->fll_def - mode->height); -+ -+ h_blank = mode->llp - mode->width; -+ - /* - * Currently hblank is not changeable. - * So FPS control is done only by vblank. -@@ -1395,7 +761,42 @@ imx355_set_pad_format(struct v4l2_subdev *sd, - h_blank, 1, h_blank); - } - -- mutex_unlock(&imx355->mutex); -+ return 0; -+} -+ -+static int imx355_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_selection *sel) -+{ -+ switch (sel->target) { -+ case V4L2_SEL_TGT_CROP: -+ sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); -+ return 0; -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ case V4L2_SEL_TGT_NATIVE_SIZE: -+ sel->r.top = IMX355_PIXEL_ARRAY_TOP; -+ sel->r.left = IMX355_PIXEL_ARRAY_LEFT; -+ sel->r.width = IMX355_PIXEL_ARRAY_WIDTH; -+ sel->r.height = IMX355_PIXEL_ARRAY_HEIGHT; -+ -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static int imx355_entity_init_state(struct v4l2_subdev *subdev, -+ struct v4l2_subdev_state *sd_state) -+{ -+ struct v4l2_subdev_format fmt = { }; -+ -+ fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; -+ fmt.format.code = MEDIA_BUS_FMT_SRGGB10_1X10; -+ fmt.format.width = supported_modes[0].width; -+ fmt.format.height = supported_modes[0].height; -+ -+ imx355_set_pad_format(subdev, sd_state, &fmt); - - return 0; - } -@@ -1403,52 +804,98 @@ imx355_set_pad_format(struct v4l2_subdev *sd, - /* Start streaming */ - static int imx355_start_streaming(struct imx355 *imx355) - { -- const struct imx355_reg_list *reg_list; -- int ret; -+ const struct v4l2_mbus_framefmt *fmt; -+ struct v4l2_subdev_state *state; -+ const struct imx355_mode *mode; -+ int lane_idx = imx355->hwcfg->num_lanes == 4 ? 0 : 1; -+ struct v4l2_rect *crop; -+ u64 link_bitrate; -+ u8 binning_mode; -+ int ret = 0; - - /* Global Setting */ -- reg_list = &imx355_global_setting; -- ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); -- if (ret) { -- dev_err(imx355->dev, "failed to set global settings"); -- return ret; -- } -+ cci_multi_reg_write(imx355->regmap, imx355_global_regs, -+ ARRAY_SIZE(imx355_global_regs), &ret); - -- /* Apply default values of current mode */ -- reg_list = &imx355->cur_mode->reg_list; -- ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); -- if (ret) { -- dev_err(imx355->dev, "failed to set mode"); -- return ret; -- } -+ /* Apply values of current mode */ -+ state = v4l2_subdev_get_locked_active_state(&imx355->sd); -+ fmt = v4l2_subdev_state_get_format(state, 0); -+ crop = v4l2_subdev_state_get_crop(state, 0); -+ mode = v4l2_find_nearest_size(supported_modes, -+ ARRAY_SIZE(supported_modes), -+ width, height, fmt->width, fmt->height); -+ cci_multi_reg_write(imx355->regmap, mode->reg_list.regs, -+ mode->reg_list.num_of_regs, &ret); -+ -+ /* Set readout crop and size registers */ -+ cci_write(imx355->regmap, IMX355_REG_X_ADD_START, crop->left, -+ &ret); -+ cci_write(imx355->regmap, IMX355_REG_Y_ADD_START, crop->top, &ret); -+ cci_write(imx355->regmap, IMX355_REG_X_ADD_END, -+ crop->width + crop->left - 1, &ret); -+ cci_write(imx355->regmap, IMX355_REG_Y_ADD_END, -+ crop->height + crop->top - 1, &ret); -+ cci_write(imx355->regmap, IMX355_REG_X_OUT_SIZE, fmt->width, &ret); -+ cci_write(imx355->regmap, IMX355_REG_Y_OUT_SIZE, fmt->height, &ret); -+ -+ binning_mode = ((crop->width / fmt->width) << 4) | -+ (crop->height / fmt->height); -+ cci_write(imx355->regmap, IMX355_REG_BINNING_MODE, -+ binning_mode == 0x11 ? 0x00 : 0x01, &ret); -+ cci_write(imx355->regmap, IMX355_REG_BINNING_TYPE, binning_mode, &ret); -+ cci_write(imx355->regmap, IMX355_REG_BINNING_WEIGHTING, 0x00, &ret); -+ -+ /* Set PLL registers for the external clock frequency */ -+ cci_write(imx355->regmap, IMX355_REG_EXTCLK_FREQ, -+ imx355->clk_params->extclk_freq, &ret); -+ cci_write(imx355->regmap, IMX355_REG_PLL_OP_MUL, -+ imx355->clk_params->pll_op_mpy[lane_idx], &ret); -+ cci_write(imx355->regmap, IMX355_REG_PLL_OP_PREDIV, -+ imx355->clk_params->pll_op_prediv[lane_idx], &ret); -+ cci_write(imx355->regmap, IMX355_REG_PLL_IVT_SYSCK_DIV, -+ lane_idx ? 2 : 1, &ret); -+ -+ /* Set MIPI configuration */ -+ cci_write(imx355->regmap, IMX355_REG_LANE_SEL, -+ imx355->hwcfg->num_lanes - 1, &ret); -+ -+ link_bitrate = imx355->link_freq->qmenu_int[imx355->link_freq->val] * -+ imx355->hwcfg->num_lanes * 2; -+ do_div(link_bitrate, 1000000); -+ cci_write(imx355->regmap, IMX355_REG_REQ_LINK_BIT_RATE, link_bitrate, -+ &ret); - - /* set digital gain control to all color mode */ -- ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1); -- if (ret) -- return ret; -+ cci_write(imx355->regmap, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, &ret); -+ -+ /* set line length */ -+ cci_write(imx355->regmap, IMX355_REG_LLP, -+ imx355->hblank->val + fmt->width, &ret); - - /* Apply customized values from user */ -- ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); -- if (ret) -- return ret; -+ if (!ret) -+ ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); - -- return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, -- 1, IMX355_MODE_STREAMING); -+ cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, IMX355_MODE_STREAMING, -+ &ret); -+ -+ return ret; - } - - /* Stop streaming */ - static int imx355_stop_streaming(struct imx355 *imx355) - { -- return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, -- 1, IMX355_MODE_STANDBY); -+ return cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, -+ IMX355_MODE_STANDBY, NULL); - } - - static int imx355_set_stream(struct v4l2_subdev *sd, int enable) - { - struct imx355 *imx355 = to_imx355(sd); -+ struct v4l2_subdev_state *state; - int ret = 0; - -- mutex_lock(&imx355->mutex); -+ state = v4l2_subdev_lock_and_get_active_state(sd); - - if (enable) { - ret = pm_runtime_resume_and_get(imx355->dev); -@@ -1464,21 +911,21 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) - goto err_rpm_put; - } else { - imx355_stop_streaming(imx355); -- pm_runtime_put(imx355->dev); -+ pm_runtime_put_autosuspend(imx355->dev); - } - - /* vflip and hflip cannot change during streaming */ - __v4l2_ctrl_grab(imx355->vflip, enable); - __v4l2_ctrl_grab(imx355->hflip, enable); - -- mutex_unlock(&imx355->mutex); -+ v4l2_subdev_unlock_state(state); - - return ret; - - err_rpm_put: -- pm_runtime_put(imx355->dev); -+ pm_runtime_put_autosuspend(imx355->dev); - err_unlock: -- mutex_unlock(&imx355->mutex); -+ v4l2_subdev_unlock_state(state); - - return ret; - } -@@ -1487,14 +934,14 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) - static int imx355_identify_module(struct imx355 *imx355) - { - int ret; -- u32 val; -+ u64 val; - -- ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val); -+ ret = cci_read(imx355->regmap, IMX355_REG_CHIP_ID, &val, NULL); - if (ret) - return ret; - - if (val != IMX355_CHIP_ID) { -- dev_err(imx355->dev, "chip id mismatch: %x!=%x", -+ dev_err(imx355->dev, "chip id mismatch: %x!=%llx", - IMX355_CHIP_ID, val); - return -EIO; - } -@@ -1512,9 +959,10 @@ static const struct v4l2_subdev_video_ops imx355_video_ops = { - - static const struct v4l2_subdev_pad_ops imx355_pad_ops = { - .enum_mbus_code = imx355_enum_mbus_code, -- .get_fmt = imx355_get_pad_format, -+ .get_fmt = v4l2_subdev_get_fmt, - .set_fmt = imx355_set_pad_format, - .enum_frame_size = imx355_enum_frame_size, -+ .get_selection = imx355_get_selection, - }; - - static const struct v4l2_subdev_ops imx355_subdev_ops = { -@@ -1528,7 +976,7 @@ static const struct media_entity_operations imx355_subdev_entity_ops = { - }; - - static const struct v4l2_subdev_internal_ops imx355_internal_ops = { -- .open = imx355_open, -+ .init_state = imx355_entity_init_state, - }; - - static int imx355_power_off(struct device *dev) -@@ -1582,13 +1030,11 @@ static int imx355_init_controls(struct imx355 *imx355) - { - struct v4l2_fwnode_device_properties props; - struct v4l2_ctrl_handler *ctrl_hdlr; -+ const struct imx355_mode *mode = &supported_modes[0]; - s64 exposure_max; - s64 vblank_def; -- s64 vblank_min; - s64 hblank; - u64 pixel_rate; -- const struct imx355_mode *mode; -- u32 max; - int ret; - - ctrl_hdlr = &imx355->ctrl_handler; -@@ -1596,40 +1042,34 @@ static int imx355_init_controls(struct imx355 *imx355) - if (ret) - return ret; - -- ctrl_hdlr->lock = &imx355->mutex; -- max = ARRAY_SIZE(link_freq_menu_items) - 1; - imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops, -- V4L2_CID_LINK_FREQ, max, 0, -- link_freq_menu_items); -+ V4L2_CID_LINK_FREQ, 0, 0, -+ &imx355->hwcfg->link_freq_menu); - if (imx355->link_freq) - imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ -- pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; -+ pixel_rate = imx355->hwcfg->link_freq_menu * 2 * imx355->hwcfg->num_lanes; - do_div(pixel_rate, 10); -- /* By default, PIXEL_RATE is read only */ -- imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, -- V4L2_CID_PIXEL_RATE, pixel_rate, -- pixel_rate, 1, pixel_rate); -+ -+ v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_PIXEL_RATE, -+ pixel_rate, pixel_rate, 1, pixel_rate); - - /* Initialize vblank/hblank/exposure parameters based on current mode */ -- mode = imx355->cur_mode; - vblank_def = mode->fll_def - mode->height; -- vblank_min = mode->fll_min - mode->height; - imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, -- V4L2_CID_VBLANK, vblank_min, -+ V4L2_CID_VBLANK, IMX355_VBLANK_MIN, - IMX355_FLL_MAX - mode->height, - 1, vblank_def); - - hblank = mode->llp - mode->width; -- imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, -- V4L2_CID_HBLANK, hblank, hblank, -- 1, hblank); -+ imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK, -+ hblank, hblank, 1, hblank); - if (imx355->hblank) - imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - /* fll >= exposure time + adjust parameter (default value is 10) */ -- exposure_max = mode->fll_def - 10; -+ exposure_max = mode->fll_def - IMX355_EXPOSURE_OFFSET; - imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_EXPOSURE, - IMX355_EXPOSURE_MIN, exposure_max, -@@ -1683,14 +1123,17 @@ static int imx355_init_controls(struct imx355 *imx355) - return ret; - } - --static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) -+static struct imx355_hwcfg *imx355_get_hwcfg(struct imx355 *imx355) - { -+ struct device *dev = imx355->dev; - struct imx355_hwcfg *cfg; - struct v4l2_fwnode_endpoint bus_cfg = { - .bus_type = V4L2_MBUS_CSI2_DPHY - }; -+ const struct imx355_clk_params *clk = imx355->clk_params; - struct fwnode_handle *ep; - struct fwnode_handle *fwnode = dev_fwnode(dev); -+ int lane_idx; - int ret; - - if (!fwnode) -@@ -1708,13 +1151,18 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) - if (!cfg) - goto out_err; - -- if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX355_DATA_LANES) -+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 && -+ bus_cfg.bus.mipi_csi2.num_data_lanes != 4) - goto out_err; - -+ cfg->num_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; -+ -+ lane_idx = cfg->num_lanes == 4 ? 0 : 1; -+ cfg->link_freq_menu = (clk->ext_clk * clk->pll_op_mpy[lane_idx]) / -+ (clk->pll_op_prediv[lane_idx] * 2); - ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, - bus_cfg.nr_of_link_frequencies, -- link_freq_menu_items, -- ARRAY_SIZE(link_freq_menu_items), -+ &cfg->link_freq_menu, 1, - &cfg->link_freq_bitmap); - if (ret) - goto out_err; -@@ -1741,7 +1189,10 @@ static int imx355_probe(struct i2c_client *client) - - imx355->dev = &client->dev; - -- mutex_init(&imx355->mutex); -+ imx355->regmap = devm_cci_regmap_init_i2c(client, 16); -+ if (IS_ERR(imx355->regmap)) -+ return dev_err_probe(imx355->dev, PTR_ERR(imx355->regmap), -+ "Unable to initialize I2C\n"); - - imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL); - if (IS_ERR(imx355->clk)) -@@ -1749,7 +1200,13 @@ static int imx355_probe(struct i2c_client *client) - "failed to get clock\n"); - - freq = clk_get_rate(imx355->clk); -- if (freq != IMX355_EXT_CLK) -+ for (unsigned int i = 0; i < ARRAY_SIZE(imx355_clk_params); i++) { -+ if (freq == imx355_clk_params[i].ext_clk) { -+ imx355->clk_params = &imx355_clk_params[i]; -+ break; -+ } -+ } -+ if (!imx355->clk_params) - return dev_err_probe(imx355->dev, -EINVAL, - "external clock %lu is not supported\n", - freq); -@@ -1760,7 +1217,7 @@ static int imx355_probe(struct i2c_client *client) - &imx355->supplies); - if (ret) { - dev_err_probe(imx355->dev, ret, "could not get regulators"); -- goto error_probe; -+ return ret; - } - - imx355->reset_gpio = devm_gpiod_get_optional(imx355->dev, "reset", -@@ -1768,22 +1225,21 @@ static int imx355_probe(struct i2c_client *client) - if (IS_ERR(imx355->reset_gpio)) { - ret = dev_err_probe(imx355->dev, PTR_ERR(imx355->reset_gpio), - "failed to get gpios"); -- goto error_probe; -+ return ret; - } - - /* Initialize subdev */ - v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); - -- imx355->hwcfg = imx355_get_hwcfg(imx355->dev); -+ imx355->hwcfg = imx355_get_hwcfg(imx355); - if (!imx355->hwcfg) { - dev_err(imx355->dev, "failed to get hwcfg"); -- ret = -ENODEV; -- goto error_probe; -+ return -ENODEV; - } - - ret = imx355_power_on(imx355->dev); - if (ret) -- goto error_probe; -+ return ret; - - /* Check module identity */ - ret = imx355_identify_module(imx355); -@@ -1792,9 +1248,6 @@ static int imx355_probe(struct i2c_client *client) - goto error_power_off; - } - -- /* Set default mode to max resolution */ -- imx355->cur_mode = &supported_modes[0]; -- - ret = imx355_init_controls(imx355); - if (ret) { - dev_err(imx355->dev, "failed to init controls: %d", ret); -@@ -1816,24 +1269,36 @@ static int imx355_probe(struct i2c_client *client) - goto error_handler_free; - } - -+ imx355->sd.state_lock = imx355->ctrl_handler.lock; -+ ret = v4l2_subdev_init_finalize(&imx355->sd); -+ if (ret < 0) { -+ dev_err_probe(imx355->dev, ret, "subdev init error\n"); -+ goto error_media_entity_free; -+ } -+ - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Enable runtime PM and turn off the device. - */ - pm_runtime_set_active(imx355->dev); - pm_runtime_enable(imx355->dev); -+ pm_runtime_set_autosuspend_delay(imx355->dev, 1000); -+ pm_runtime_use_autosuspend(imx355->dev); - - ret = v4l2_async_register_subdev_sensor(&imx355->sd); - if (ret < 0) -- goto error_media_entity_runtime_pm; -+ goto error_subdev_cleanup_runtime_pm; - - pm_runtime_idle(imx355->dev); - - return 0; - --error_media_entity_runtime_pm: -+error_subdev_cleanup_runtime_pm: - pm_runtime_disable(imx355->dev); - pm_runtime_set_suspended(imx355->dev); -+ pm_runtime_dont_use_autosuspend(imx355->dev); -+ v4l2_subdev_cleanup(&imx355->sd); -+error_media_entity_free: - media_entity_cleanup(&imx355->sd.entity); - - error_handler_free: -@@ -1842,9 +1307,6 @@ static int imx355_probe(struct i2c_client *client) - error_power_off: - imx355_power_off(imx355->dev); - --error_probe: -- mutex_destroy(&imx355->mutex); -- - return ret; - } - -@@ -1854,6 +1316,7 @@ static void imx355_remove(struct i2c_client *client) - struct imx355 *imx355 = to_imx355(sd); - - v4l2_async_unregister_subdev(sd); -+ v4l2_subdev_cleanup(sd); - media_entity_cleanup(&sd->entity); - v4l2_ctrl_handler_free(sd->ctrl_handler); - -@@ -1864,7 +1327,7 @@ static void imx355_remove(struct i2c_client *client) - pm_runtime_set_suspended(imx355->dev); - } - -- mutex_destroy(&imx355->mutex); -+ pm_runtime_dont_use_autosuspend(imx355->dev); - } - - static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { -diff --git a/drivers/media/i2c/imx471.c b/drivers/media/i2c/imx471.c -new file mode 100644 ---- /dev/null -+++ b/drivers/media/i2c/imx471.c -@@ -0,0 +1,957 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * imx471.c - imx471 sensor driver -+ * -+ * Copyright (C) 2025 Intel Corporation -+ * Copyright (C) 2026 Kate Hsuan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define IMX471_REG_MODE_SELECT CCI_REG8(0x0100) -+#define IMX471_MODE_STANDBY 0x00 -+#define IMX471_MODE_STREAMING 0x01 -+ -+/* Chip ID */ -+#define IMX471_REG_CHIP_ID CCI_REG16(0x0016) -+#define IMX471_CHIP_ID 0x0471 -+ -+/* V_TIMING internal */ -+#define IMX471_REG_FLL CCI_REG16(0x0340) -+#define IMX471_FLL_MAX 0xffff -+ -+/* Exposure control */ -+#define IMX471_REG_EXPOSURE CCI_REG16(0x0202) -+#define IMX471_EXPOSURE_MIN 1 -+#define IMX471_EXPOSURE_STEP 1 -+#define IMX471_EXPOSURE_DEFAULT 1270 -+ -+/* Default exposure margin */ -+#define IMX471_EXPOSURE_MARGIN 18 -+ -+/* Analog gain control */ -+#define IMX471_REG_ANALOG_GAIN CCI_REG16(0x0204) -+#define IMX471_ANA_GAIN_MIN 0 -+#define IMX471_ANA_GAIN_MAX 800 -+#define IMX471_ANA_GAIN_STEP 1 -+#define IMX471_ANA_GAIN_DEFAULT 0 -+ -+/* Digital gain control */ -+#define IMX471_REG_DPGA_USE_GLOBAL_GAIN CCI_REG16(0x3ff9) -+#define IMX471_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e) -+#define IMX471_DGTL_GAIN_MIN 256 -+#define IMX471_DGTL_GAIN_MAX 4095 -+#define IMX471_DGTL_GAIN_STEP 1 -+#define IMX471_DGTL_GAIN_DEFAULT 256 -+ -+/* HFLIP and VFLIP control */ -+#define IMX471_REG_ORIENTATION CCI_REG8(0x0101) -+ -+/* Test Pattern Control */ -+#define IMX471_REG_TEST_PATTERN CCI_REG8(0x0600) -+ -+/* default link frequency and external clock */ -+#define IMX471_LINK_FREQ_DEFAULT 200000000LL -+#define IMX471_EXT_CLK 19200000 -+ -+/* PLL */ -+#define IMX471_REG_VTPXCK_DIV CCI_REG8(0x0301) -+#define IMX471_REG_VTSYCK_DIV CCI_REG8(0x0303) -+#define IMX471_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305) -+#define IMX471_REG_PLL_VT_MPY CCI_REG16(0x0306) -+#define IMX471_REG_OPPXCK_DIV CCI_REG8(0x0309) -+#define IMX471_REG_OPSYCK_DIV CCI_REG8(0x030b) -+#define IMX471_REG_PLL_MULT_DRIV CCI_REG8(0x0310) -+#define IMX471_PLL_SINGLE 0 -+#define IMX471_PLL_DUAL 1 -+ -+/* IMX471 native and active pixel array size */ -+#define IMX471_NATIVE_WIDTH 4672 -+#define IMX471_NATIVE_HEIGHT 3512 -+#define IMX471_PIXEL_ARRAY_LEFT 8 -+#define IMX471_PIXEL_ARRAY_TOP 8 -+#define IMX471_PIXEL_ARRAY_WIDTH 4656 -+#define IMX471_PIXEL_ARRAY_HEIGHT 3496 -+ -+#define IMX471_REG_EXCK_FREQ CCI_REG16(0x0136) -+ -+#define IMX471_REG_CSI_DATA_FORMAT CCI_REG16(0x0112) -+#define IMX471_CSI_DATA_FORMAT_RAW10 0x0a0a -+ -+#define IMX471_REG_CSI_LANE_MODE CCI_REG8(0x0114) -+#define IMX471_CSI_2_LANE_MODE 1 -+#define IMX471_CSI_4_LANE_MODE 3 -+ -+#define IMX471_REG_X_ADD_STA CCI_REG16(0x0344) -+#define IMX471_REG_Y_ADD_STA CCI_REG16(0x0346) -+#define IMX471_REG_X_ADD_END CCI_REG16(0x0348) -+#define IMX471_REG_Y_ADD_END CCI_REG16(0x034a) -+#define IMX471_REG_X_OUTPUT_SIZE CCI_REG16(0x034c) -+#define IMX471_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e) -+#define IMX471_REG_X_EVEN_INC CCI_REG8(0x0381) -+#define IMX471_REG_X_ODD_INC CCI_REG8(0x0383) -+#define IMX471_REG_Y_EVEN_INC CCI_REG8(0x0385) -+#define IMX471_REG_Y_ODD_INC CCI_REG8(0x0387) -+ -+#define IMX471_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408) -+#define IMX471_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a) -+#define IMX471_REG_DIG_CROP_WIDTH CCI_REG16(0x040c) -+#define IMX471_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e) -+ -+/* Binning mode */ -+#define IMX471_REG_BINNING_MODE CCI_REG8(0x0900) -+#define IMX471_BINNING_NONE 0 -+#define IMX471_BINNING_ENABLE 1 -+#define IMX471_REG_BINNING_TYPE CCI_REG8(0x0901) -+#define IMX471_REG_BINNING_WEIGHTING CCI_REG8(0x0902) -+ -+#define to_imx471(_sd) container_of_const(_sd, struct imx471, sd) -+ -+static const char * const imx471_supply_name[] = { -+ "vana", -+}; -+ -+struct imx471_mode { -+ u32 width; -+ u32 height; -+ -+ /* V-timing */ -+ u32 fll_def; -+ u32 fll_min; -+ -+ /* H-timing */ -+ u32 llp; -+ -+ const struct cci_reg_sequence *default_mode_regs; -+ unsigned int default_mode_regs_length; -+}; -+ -+struct imx471 { -+ struct v4l2_subdev sd; -+ struct media_pad pad; -+ -+ struct v4l2_ctrl_handler ctrl_handler; -+ struct v4l2_ctrl *vblank; -+ struct v4l2_ctrl *hblank; -+ struct v4l2_ctrl *vflip; -+ struct v4l2_ctrl *hflip; -+ struct v4l2_ctrl *exposure; -+ -+ struct gpio_desc *reset_gpio; -+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx471_supply_name)]; -+ struct clk *img_clk; -+ -+ struct device *dev; -+ struct regmap *regmap; -+}; -+ -+static const struct cci_reg_sequence imx471_global_regs[] = { -+ { IMX471_REG_EXCK_FREQ, 0x1333 }, -+ { CCI_REG8(0x3c7e), 0x08 }, -+ { CCI_REG8(0x3c7f), 0x05 }, -+ { CCI_REG8(0x3e35), 0x00 }, -+ { CCI_REG8(0x3e36), 0x00 }, -+ { CCI_REG8(0x3e37), 0x00 }, -+ { CCI_REG8(0x3f7f), 0x01 }, -+ { CCI_REG8(0x4431), 0x04 }, -+ { CCI_REG8(0x531c), 0x01 }, -+ { CCI_REG8(0x531d), 0x02 }, -+ { CCI_REG8(0x531e), 0x04 }, -+ { CCI_REG8(0x5928), 0x00 }, -+ { CCI_REG8(0x5929), 0x2f }, -+ { CCI_REG8(0x592a), 0x00 }, -+ { CCI_REG8(0x592b), 0x85 }, -+ { CCI_REG8(0x592c), 0x00 }, -+ { CCI_REG8(0x592d), 0x32 }, -+ { CCI_REG8(0x592e), 0x00 }, -+ { CCI_REG8(0x592f), 0x88 }, -+ { CCI_REG8(0x5930), 0x00 }, -+ { CCI_REG8(0x5931), 0x3d }, -+ { CCI_REG8(0x5932), 0x00 }, -+ { CCI_REG8(0x5933), 0x93 }, -+ { CCI_REG8(0x5938), 0x00 }, -+ { CCI_REG8(0x5939), 0x24 }, -+ { CCI_REG8(0x593a), 0x00 }, -+ { CCI_REG8(0x593b), 0x7a }, -+ { CCI_REG8(0x593c), 0x00 }, -+ { CCI_REG8(0x593d), 0x24 }, -+ { CCI_REG8(0x593e), 0x00 }, -+ { CCI_REG8(0x593f), 0x7a }, -+ { CCI_REG8(0x5940), 0x00 }, -+ { CCI_REG8(0x5941), 0x2f }, -+ { CCI_REG8(0x5942), 0x00 }, -+ { CCI_REG8(0x5943), 0x85 }, -+ { CCI_REG8(0x5f0e), 0x6e }, -+ { CCI_REG8(0x5f11), 0xc6 }, -+ { CCI_REG8(0x5f17), 0x5e }, -+ { CCI_REG8(0x7990), 0x01 }, -+ { CCI_REG8(0x7993), 0x5d }, -+ { CCI_REG8(0x7994), 0x5d }, -+ { CCI_REG8(0x7995), 0xa1 }, -+ { CCI_REG8(0x799a), 0x01 }, -+ { CCI_REG8(0x799d), 0x00 }, -+ { CCI_REG8(0x8169), 0x01 }, -+ { CCI_REG8(0x8359), 0x01 }, -+ { CCI_REG8(0x9302), 0x1e }, -+ { CCI_REG8(0x9306), 0x1f }, -+ { CCI_REG8(0x930a), 0x26 }, -+ { CCI_REG8(0x930e), 0x23 }, -+ { CCI_REG8(0x9312), 0x23 }, -+ { CCI_REG8(0x9316), 0x2c }, -+ { CCI_REG8(0x9317), 0x19 }, -+ { CCI_REG8(0xb046), 0x01 }, -+ { CCI_REG8(0xb048), 0x01 }, -+}; -+ -+static const struct cci_reg_sequence mode_1928x1088_regs[] = { -+ { IMX471_REG_CSI_DATA_FORMAT, IMX471_CSI_DATA_FORMAT_RAW10 }, -+ { IMX471_REG_CSI_LANE_MODE, IMX471_CSI_4_LANE_MODE }, -+ { IMX471_REG_X_ADD_STA, 8 }, -+ { IMX471_REG_Y_ADD_STA, 408 }, -+ { IMX471_REG_X_ADD_END, 4647 }, -+ { IMX471_REG_Y_ADD_END, 3051 }, -+ { IMX471_REG_X_EVEN_INC, 1 }, -+ { IMX471_REG_X_ODD_INC, 1 }, -+ { IMX471_REG_Y_EVEN_INC, 1 }, -+ { IMX471_REG_Y_ODD_INC, 1 }, -+ { IMX471_REG_BINNING_MODE, IMX471_BINNING_ENABLE }, -+ { IMX471_REG_BINNING_TYPE, 0x22 }, -+ { IMX471_REG_BINNING_WEIGHTING, 0x08 }, -+ { IMX471_REG_DIG_CROP_X_OFFSET, 208 }, -+ { IMX471_REG_DIG_CROP_Y_OFFSET, 108 }, -+ { IMX471_REG_DIG_CROP_WIDTH, 1928 }, -+ { IMX471_REG_DIG_CROP_HEIGHT, 1088 }, -+ { IMX471_REG_X_OUTPUT_SIZE, 1928 }, -+ { IMX471_REG_Y_OUTPUT_SIZE, 1088 }, -+ { IMX471_REG_VTPXCK_DIV, 0x06 }, -+ { IMX471_REG_VTSYCK_DIV, 0x02 }, -+ { IMX471_REG_PREPLLCK_VT_DIV, 0x02 }, -+ { IMX471_REG_PLL_VT_MPY, 0x0079 }, -+ { IMX471_REG_OPSYCK_DIV, 0x01 }, -+ { CCI_REG8(0x030d), 0x02 }, -+ { CCI_REG8(0x030e), 0x00 }, -+ { CCI_REG8(0x030f), 0x53 }, -+ { IMX471_REG_PLL_MULT_DRIV, IMX471_PLL_DUAL }, -+ { CCI_REG8(0x3f4c), 0x81 }, -+ { CCI_REG8(0x3f4d), 0x81 }, -+ { CCI_REG8(0x3f78), 0x01 }, -+ { CCI_REG8(0x3f79), 0x31 }, -+ { CCI_REG8(0x3ffe), 0x00 }, -+ { CCI_REG8(0x3fff), 0x8a }, -+ { CCI_REG8(0x5f0a), 0xb6 }, -+}; -+ -+static const char * const imx471_test_pattern_menu[] = { -+ "Disabled", -+ "Solid Colour", -+ "Eight Vertical Colour Bars", -+ "Colour Bars With Fade to Grey", -+ "Pseudorandom Sequence (PN9)", -+}; -+ -+static const s64 link_freq_menu_items[] = { -+ IMX471_LINK_FREQ_DEFAULT, -+}; -+ -+/* -+ * The Bayer formats for the flipping. -+ * - no flip -+ * - h flip -+ * - v flip -+ * - h and v flips -+ */ -+static const u32 imx471_hv_flips_bayer_order[] = { -+ MEDIA_BUS_FMT_SRGGB10_1X10, -+ MEDIA_BUS_FMT_SGRBG10_1X10, -+ MEDIA_BUS_FMT_SGBRG10_1X10, -+ MEDIA_BUS_FMT_SBGGR10_1X10, -+}; -+ -+static const struct imx471_mode imx471_modes[] = { -+ { -+ .width = 1928, -+ .height = 1088, -+ .fll_def = 1308, -+ .fll_min = 1308, -+ .llp = 2328, -+ .default_mode_regs = mode_1928x1088_regs, -+ .default_mode_regs_length = ARRAY_SIZE(mode_1928x1088_regs), -+ }, -+}; -+ -+static int imx471_get_regulators(struct device *dev, struct imx471 *sensor) -+{ -+ for (unsigned int i = 0; i < ARRAY_SIZE(imx471_supply_name); i++) -+ sensor->supplies[i].supply = imx471_supply_name[i]; -+ -+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx471_supply_name), -+ sensor->supplies); -+} -+ -+static int imx471_set_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct imx471 *sensor = container_of_const(ctrl->handler, -+ struct imx471, -+ ctrl_handler); -+ struct v4l2_subdev_state *state = -+ v4l2_subdev_get_locked_active_state(&sensor->sd); -+ const struct v4l2_mbus_framefmt *format = -+ v4l2_subdev_state_get_format(state, 0); -+ int ret; -+ -+ if (ctrl->id == V4L2_CID_VBLANK) { -+ s64 exposure_max = format->height + ctrl->val - -+ IMX471_EXPOSURE_MARGIN; -+ ret = __v4l2_ctrl_modify_range(sensor->exposure, -+ sensor->exposure->minimum, -+ exposure_max, -+ sensor->exposure->step, -+ exposure_max); -+ if (ret) -+ return ret; -+ } -+ -+ if (!pm_runtime_get_if_in_use(sensor->dev)) -+ return 0; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_ANALOGUE_GAIN: -+ ret = cci_write(sensor->regmap, IMX471_REG_ANALOG_GAIN, -+ ctrl->val, NULL); -+ break; -+ case V4L2_CID_DIGITAL_GAIN: -+ ret = cci_write(sensor->regmap, IMX471_REG_DIG_GAIN_GLOBAL, -+ ctrl->val, NULL); -+ break; -+ case V4L2_CID_EXPOSURE: -+ ret = cci_write(sensor->regmap, IMX471_REG_EXPOSURE, -+ ctrl->val, NULL); -+ break; -+ case V4L2_CID_VBLANK: -+ /* Update FLL that meets expected vertical blanking */ -+ ret = cci_write(sensor->regmap, IMX471_REG_FLL, -+ format->height + ctrl->val, NULL); -+ break; -+ case V4L2_CID_TEST_PATTERN: -+ ret = cci_write(sensor->regmap, IMX471_REG_TEST_PATTERN, -+ ctrl->val, NULL); -+ break; -+ case V4L2_CID_HFLIP: -+ case V4L2_CID_VFLIP: -+ ret = cci_write(sensor->regmap, IMX471_REG_ORIENTATION, -+ sensor->hflip->val | sensor->vflip->val << 1, -+ NULL); -+ break; -+ default: -+ ret = -EINVAL; -+ dev_err(sensor->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", -+ ctrl->id, ctrl->val); -+ break; -+ } -+ -+ pm_runtime_put(sensor->dev); -+ -+ return ret; -+} -+ -+static const struct v4l2_ctrl_ops imx471_ctrl_ops = { -+ .s_ctrl = imx471_set_ctrl, -+}; -+ -+static u32 imx471_get_format_code(struct imx471 *sensor) -+{ -+ unsigned int i; -+ -+ i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0); -+ -+ return imx471_hv_flips_bayer_order[i]; -+} -+ -+static int imx471_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_mbus_code_enum *code) -+{ -+ struct imx471 *sensor = to_imx471(sd); -+ -+ if (code->index >= (ARRAY_SIZE(imx471_hv_flips_bayer_order) / 4)) -+ return -EINVAL; -+ -+ code->code = imx471_get_format_code(sensor); -+ -+ return 0; -+} -+ -+static int imx471_enum_frame_size(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_frame_size_enum *fse) -+{ -+ if (fse->index >= ARRAY_SIZE(imx471_modes)) -+ return -EINVAL; -+ -+ fse->min_width = imx471_modes[fse->index].width; -+ fse->max_width = fse->min_width; -+ fse->min_height = imx471_modes[fse->index].height; -+ fse->max_height = fse->min_height; -+ -+ return 0; -+} -+ -+static void imx471_update_pad_format(struct imx471 *sensor, -+ const struct imx471_mode *mode, -+ struct v4l2_subdev_format *fmt) -+{ -+ fmt->format.code = imx471_get_format_code(sensor); -+ fmt->format.width = mode->width; -+ fmt->format.height = mode->height; -+ fmt->format.field = V4L2_FIELD_NONE; -+} -+ -+static int imx471_set_pad_format(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_format *fmt) -+{ -+ struct imx471 *sensor = to_imx471(sd); -+ const struct imx471_mode *mode; -+ int h_blank, ret; -+ -+ mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), -+ width, height, fmt->format.width, -+ fmt->format.height); -+ -+ imx471_update_pad_format(sensor, mode, fmt); -+ -+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; -+ -+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) -+ return 0; -+ -+ if (media_entity_is_streaming(&sensor->sd.entity)) -+ return -EBUSY; -+ -+ ret = __v4l2_ctrl_modify_range(sensor->vblank, -+ mode->fll_min - mode->height, -+ IMX471_FLL_MAX - mode->height, -+ 1, -+ mode->fll_def - mode->height); -+ if (ret) -+ return ret; -+ -+ h_blank = mode->llp - mode->width; -+ /* -+ * Currently hblank is not changeable. -+ * So FPS control is done only by vblank. -+ */ -+ return __v4l2_ctrl_modify_range(sensor->hblank, h_blank, -+ h_blank, 1, h_blank); -+} -+ -+static int imx471_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_selection *sel) -+{ -+ switch (sel->target) { -+ case V4L2_SEL_TGT_CROP: -+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); -+ break; -+ -+ case V4L2_SEL_TGT_NATIVE_SIZE: -+ sel->r.top = 0; -+ sel->r.left = 0; -+ sel->r.width = IMX471_NATIVE_WIDTH; -+ sel->r.height = IMX471_NATIVE_HEIGHT; -+ return 0; -+ -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ sel->r.top = IMX471_PIXEL_ARRAY_TOP; -+ sel->r.left = IMX471_PIXEL_ARRAY_LEFT; -+ sel->r.width = IMX471_PIXEL_ARRAY_WIDTH; -+ sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT; -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static int imx471_init_state(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state) -+{ -+ struct v4l2_subdev_format fmt = { -+ .which = V4L2_SUBDEV_FORMAT_TRY, -+ .format = { -+ .code = MEDIA_BUS_FMT_SRGGB10_1X10, -+ .width = imx471_modes[0].width, -+ .height = imx471_modes[0].height, -+ }, -+ }; -+ -+ return imx471_set_pad_format(sd, sd_state, &fmt); -+} -+ -+static int imx471_identify_module(struct imx471 *sensor) -+{ -+ int ret; -+ u64 val; -+ -+ ret = cci_read(sensor->regmap, IMX471_REG_CHIP_ID, &val, NULL); -+ if (ret) -+ return dev_err_probe(sensor->dev, ret, -+ "failed to read chip id\n"); -+ -+ if (val != IMX471_CHIP_ID) -+ return dev_err_probe(sensor->dev, -EIO, -+ "chip id mismatch: %x!=%llx\n", -+ IMX471_CHIP_ID, val); -+ -+ return 0; -+} -+ -+static int imx471_power_off(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct imx471 *sensor = to_imx471(sd); -+ -+ clk_disable_unprepare(sensor->img_clk); -+ gpiod_set_value_cansleep(sensor->reset_gpio, 1); -+ -+ regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), -+ sensor->supplies); -+ -+ return 0; -+} -+ -+static int imx471_power_on(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct imx471 *sensor = to_imx471(sd); -+ int ret; -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(imx471_supply_name), -+ sensor->supplies); -+ if (ret < 0) { -+ dev_err(dev, "failed to enable regulators: %d\n", ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(sensor->img_clk); -+ if (ret < 0) { -+ regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), -+ sensor->supplies); -+ dev_err(dev, "failed to enable imaging clock: %d\n", ret); -+ return ret; -+ } -+ -+ gpiod_set_value_cansleep(sensor->reset_gpio, 0); -+ -+ usleep_range(10000, 15000); -+ -+ return 0; -+} -+ -+static int imx471_enable_stream(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *state, -+ u32 pad, u64 streams_mask) -+{ -+ struct imx471 *sensor = to_imx471(sd); -+ const struct imx471_mode *mode; -+ struct v4l2_mbus_framefmt *fmt; -+ int ret; -+ -+ ret = pm_runtime_resume_and_get(sensor->dev); -+ if (ret) -+ return ret; -+ -+ ret = imx471_identify_module(sensor); -+ if (ret) -+ goto error_powerdown; -+ -+ ret = cci_multi_reg_write(sensor->regmap, imx471_global_regs, -+ ARRAY_SIZE(imx471_global_regs), NULL); -+ if (ret) { -+ dev_err(sensor->dev, "failed to set global settings: %d\n", -+ ret); -+ goto error_powerdown; -+ } -+ -+ fmt = v4l2_subdev_state_get_format(state, 0); -+ mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), -+ width, height, fmt->width, fmt->height); -+ -+ ret = cci_multi_reg_write(sensor->regmap, mode->default_mode_regs, -+ mode->default_mode_regs_length, NULL); -+ if (ret) { -+ dev_err(sensor->dev, "failed to set mode: %d\n", ret); -+ goto error_powerdown; -+ } -+ -+ ret = cci_write(sensor->regmap, IMX471_REG_DPGA_USE_GLOBAL_GAIN, 1, -+ NULL); -+ if (ret) -+ goto error_powerdown; -+ -+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); -+ if (ret) -+ goto error_powerdown; -+ -+ ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, -+ IMX471_MODE_STREAMING, NULL); -+ if (ret) -+ goto error_powerdown; -+ -+ __v4l2_ctrl_grab(sensor->vflip, true); -+ __v4l2_ctrl_grab(sensor->hflip, true); -+ -+ return ret; -+ -+error_powerdown: -+ pm_runtime_put(sensor->dev); -+ -+ return ret; -+} -+ -+static int imx471_disable_stream(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *state, -+ u32 pad, u64 streams_mask) -+{ -+ struct imx471 *sensor = to_imx471(sd); -+ int ret; -+ -+ ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, -+ IMX471_MODE_STANDBY, NULL); -+ pm_runtime_put(sensor->dev); -+ -+ if (ret) -+ dev_err(sensor->dev, -+ "failed to disable stream with return value: %d\n", -+ ret); -+ -+ __v4l2_ctrl_grab(sensor->vflip, false); -+ __v4l2_ctrl_grab(sensor->hflip, false); -+ -+ return 0; -+} -+ -+static const struct v4l2_subdev_video_ops imx471_video_ops = { -+ .s_stream = v4l2_subdev_s_stream_helper, -+}; -+ -+static const struct v4l2_subdev_pad_ops imx471_pad_ops = { -+ .enum_mbus_code = imx471_enum_mbus_code, -+ .get_fmt = v4l2_subdev_get_fmt, -+ .set_fmt = imx471_set_pad_format, -+ .get_selection = imx471_get_selection, -+ .enum_frame_size = imx471_enum_frame_size, -+ .enable_streams = imx471_enable_stream, -+ .disable_streams = imx471_disable_stream, -+}; -+ -+static const struct v4l2_subdev_ops imx471_subdev_ops = { -+ .video = &imx471_video_ops, -+ .pad = &imx471_pad_ops, -+}; -+ -+static const struct v4l2_subdev_internal_ops imx471_internal_ops = { -+ .init_state = imx471_init_state, -+}; -+ -+static int imx471_init_controls(struct imx471 *sensor) -+{ -+ const struct imx471_mode *mode = &imx471_modes[0]; -+ struct v4l2_fwnode_device_properties props; -+ struct v4l2_ctrl_handler *ctrl_hdlr; -+ struct v4l2_ctrl *link_freq; -+ s64 exposure_max, hblank; -+ u64 pixel_rate; -+ int ret; -+ -+ ret = v4l2_fwnode_device_parse(sensor->dev, &props); -+ if (ret) { -+ dev_err(sensor->dev, "failed to parse fwnode: %d\n", ret); -+ return ret; -+ } -+ -+ ctrl_hdlr = &sensor->ctrl_handler; -+ v4l2_ctrl_handler_init(ctrl_hdlr, 12); -+ -+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx471_ctrl_ops, &props); -+ -+ link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, -+ &imx471_ctrl_ops, -+ V4L2_CID_LINK_FREQ, -+ ARRAY_SIZE(link_freq_menu_items) - 1, -+ 0, -+ link_freq_menu_items); -+ -+ /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ -+ pixel_rate = div_u64(IMX471_LINK_FREQ_DEFAULT * 2 * 4, 10); -+ -+ v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, -+ V4L2_CID_PIXEL_RATE, pixel_rate, -+ pixel_rate, 1, pixel_rate); -+ -+ sensor->vblank = v4l2_ctrl_new_std(ctrl_hdlr, -+ &imx471_ctrl_ops, -+ V4L2_CID_VBLANK, -+ mode->fll_min - mode->height, -+ IMX471_FLL_MAX - mode->height, -+ 1, -+ mode->fll_def - mode->height); -+ -+ hblank = mode->llp - mode->width; -+ sensor->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, -+ V4L2_CID_HBLANK, hblank, hblank, -+ 1, hblank); -+ -+ /* fll >= exposure time + adjust parameter (default value is 18) */ -+ exposure_max = mode->fll_def - IMX471_EXPOSURE_MARGIN; -+ sensor->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, -+ V4L2_CID_EXPOSURE, -+ IMX471_EXPOSURE_MIN, exposure_max, -+ IMX471_EXPOSURE_STEP, -+ IMX471_EXPOSURE_DEFAULT); -+ -+ v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, -+ IMX471_ANA_GAIN_MIN, IMX471_ANA_GAIN_MAX, -+ IMX471_ANA_GAIN_STEP, IMX471_ANA_GAIN_DEFAULT); -+ -+ v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_DIGITAL_GAIN, -+ IMX471_DGTL_GAIN_MIN, IMX471_DGTL_GAIN_MAX, -+ IMX471_DGTL_GAIN_STEP, IMX471_DGTL_GAIN_DEFAULT); -+ -+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx471_ctrl_ops, -+ V4L2_CID_TEST_PATTERN, -+ ARRAY_SIZE(imx471_test_pattern_menu) - 1, -+ 0, 0, imx471_test_pattern_menu); -+ -+ sensor->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 0); -+ -+ sensor->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, -+ V4L2_CID_VFLIP, 0, 1, 1, 0); -+ -+ if (ctrl_hdlr->error) { -+ dev_err(sensor->dev, "%s control init failed: %d\n", -+ __func__, ctrl_hdlr->error); -+ goto error; -+ } -+ -+ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; -+ sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; -+ -+ sensor->sd.ctrl_handler = ctrl_hdlr; -+ -+ return 0; -+ -+error: -+ v4l2_ctrl_handler_free(ctrl_hdlr); -+ -+ return ctrl_hdlr->error; -+} -+ -+static int imx471_check_hwcfg(struct imx471 *sensor) -+{ -+ struct v4l2_fwnode_endpoint bus_cfg = { -+ .bus_type = V4L2_MBUS_CSI2_DPHY, -+ }; -+ struct fwnode_handle *ep, *fwnode = dev_fwnode(sensor->dev); -+ unsigned long link_freq_bitmap; -+ struct clk *clk; -+ int ret; -+ -+ clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); -+ if (IS_ERR(clk)) -+ return dev_err_probe(sensor->dev, PTR_ERR(clk), -+ "can't get clock frequency\n"); -+ -+ if (clk_get_rate(clk) != IMX471_EXT_CLK) -+ return dev_err_probe(sensor->dev, -EINVAL, -+ "external clock %lu is not supported\n", -+ clk_get_rate(clk)); -+ -+ ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0); -+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); -+ fwnode_handle_put(ep); -+ if (ret) -+ return dev_err_probe(sensor->dev, ret, -+ "parsing endpoint failed\n"); -+ -+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { -+ ret = dev_err_probe(sensor->dev, -EINVAL, -+ "number of CSI2 data lanes %u is not supported\n", -+ bus_cfg.bus.mipi_csi2.num_data_lanes); -+ goto done_endpoint_free; -+ } -+ -+ ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies, -+ bus_cfg.nr_of_link_frequencies, -+ link_freq_menu_items, -+ ARRAY_SIZE(link_freq_menu_items), -+ &link_freq_bitmap); -+ -+done_endpoint_free: -+ v4l2_fwnode_endpoint_free(&bus_cfg); -+ -+ return ret; -+} -+ -+static int imx471_probe(struct i2c_client *client) -+{ -+ struct imx471 *sensor; -+ int ret; -+ -+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); -+ if (!sensor) -+ return dev_err_probe(&client->dev, -ENOMEM, -+ "failed to allocate memory\n"); -+ -+ sensor->dev = &client->dev; -+ -+ ret = imx471_check_hwcfg(sensor); -+ if (ret) -+ return dev_err_probe(sensor->dev, ret, -+ "failed to check hwcfg: %d\n", ret); -+ -+ ret = imx471_get_regulators(sensor->dev, sensor); -+ if (ret) -+ return dev_err_probe(sensor->dev, ret, -+ "failed to get regulators\n"); -+ -+ sensor->reset_gpio = devm_gpiod_get_optional(sensor->dev, "reset", -+ GPIOD_OUT_HIGH); -+ if (IS_ERR(sensor->reset_gpio)) -+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset_gpio), -+ "failed to get reset gpio\n"); -+ -+ sensor->img_clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); -+ if (IS_ERR(sensor->img_clk)) -+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->img_clk), -+ "failed to get imaging clock\n"); -+ -+ v4l2_i2c_subdev_init(&sensor->sd, client, &imx471_subdev_ops); -+ -+ sensor->regmap = devm_cci_regmap_init_i2c(client, 16); -+ if (IS_ERR(sensor->regmap)) -+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->regmap), -+ "failed to initialize CCI\n"); -+ -+ ret = imx471_power_on(sensor->dev); -+ if (ret) -+ return dev_err_probe(sensor->dev, ret, -+ "failed to power on\n"); -+ -+ ret = imx471_identify_module(sensor); -+ if (ret) { -+ dev_err_probe(sensor->dev, ret, "failed to find sensor: %d\n", -+ ret); -+ goto error_power_off; -+ } -+ -+ ret = imx471_init_controls(sensor); -+ if (ret) { -+ dev_err_probe(sensor->dev, ret, "failed to init controls: %d\n", -+ ret); -+ goto error_power_off; -+ } -+ -+ sensor->sd.internal_ops = &imx471_internal_ops; -+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE; -+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; -+ -+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); -+ if (ret) { -+ dev_err_probe(sensor->dev, ret, -+ "failed to init entity pads: %d\n", ret); -+ goto error_v4l2_ctrl_handler_free; -+ } -+ -+ sensor->sd.state_lock = sensor->ctrl_handler.lock; -+ ret = v4l2_subdev_init_finalize(&sensor->sd); -+ if (ret < 0) { -+ dev_err_probe(sensor->dev, ret, "failed to init subdev: %d\n", -+ ret); -+ goto error_media_entity_pm; -+ } -+ -+ pm_runtime_set_active(sensor->dev); -+ pm_runtime_enable(sensor->dev); -+ -+ ret = v4l2_async_register_subdev_sensor(&sensor->sd); -+ if (ret < 0) -+ goto error_v4l2_subdev_cleanup; -+ -+ pm_runtime_idle(sensor->dev); -+ -+ return 0; -+ -+error_v4l2_subdev_cleanup: -+ pm_runtime_disable(sensor->dev); -+ pm_runtime_set_suspended(sensor->dev); -+ v4l2_subdev_cleanup(&sensor->sd); -+ -+error_media_entity_pm: -+ media_entity_cleanup(&sensor->sd.entity); -+ -+error_v4l2_ctrl_handler_free: -+ v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); -+ -+error_power_off: -+ imx471_power_off(sensor->dev); -+ -+ return ret; -+} -+ -+static void imx471_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ -+ v4l2_async_unregister_subdev(sd); -+ v4l2_subdev_cleanup(sd); -+ media_entity_cleanup(&sd->entity); -+ v4l2_ctrl_handler_free(sd->ctrl_handler); -+ -+ pm_runtime_disable(&client->dev); -+ -+ if (!pm_runtime_status_suspended(&client->dev)) { -+ imx471_power_off(&client->dev); -+ pm_runtime_set_suspended(&client->dev); -+ } -+} -+ -+static DEFINE_RUNTIME_DEV_PM_OPS(imx471_pm_ops, imx471_power_off, -+ imx471_power_on, NULL); -+ -+static const struct acpi_device_id imx471_acpi_ids[] __maybe_unused = { -+ { "SONY471A" }, -+ { "TBE20A0" }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(acpi, imx471_acpi_ids); -+ -+static struct i2c_driver imx471_i2c_driver = { -+ .driver = { -+ .name = "imx471", -+ .acpi_match_table = ACPI_PTR(imx471_acpi_ids), -+ .pm = pm_sleep_ptr(&imx471_pm_ops), -+ }, -+ .probe = imx471_probe, -+ .remove = imx471_remove, -+}; -+module_i2c_driver(imx471_i2c_driver); -+ -+MODULE_AUTHOR("Jimmy Su "); -+MODULE_AUTHOR("Serin Yeh "); -+MODULE_AUTHOR("Kate Hsuan "); -+MODULE_DESCRIPTION("Sony imx471 sensor driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c ---- a/drivers/media/i2c/ov2740.c -+++ b/drivers/media/i2c/ov2740.c -@@ -1241,41 +1241,42 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, - return ret; - } - -+static const struct regmap_config regmap_config = { -+ .val_bits = 8, -+ .reg_bits = 16, -+ .disable_locking = true, -+}; -+ - static int ov2740_register_nvmem(struct i2c_client *client, - struct ov2740 *ov2740) - { - struct nvm_data *nvm; -- struct regmap_config regmap_config = { }; -- struct nvmem_config nvmem_config = { }; - struct regmap *regmap; - struct device *dev = ov2740->dev; -+ struct nvmem_config nvmem_config = { -+ .name = dev_name(dev), -+ .dev = dev, -+ .read_only = true, -+ .root_only = true, -+ .owner = THIS_MODULE, -+ .compat = true, -+ .base_dev = dev, -+ .reg_read = ov2740_nvmem_read, -+ .stride = 1, -+ .word_size = 1, -+ .size = CUSTOMER_USE_OTP_SIZE, -+ }; - - nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); - if (!nvm) - return -ENOMEM; - -- regmap_config.val_bits = 8; -- regmap_config.reg_bits = 16; -- regmap_config.disable_locking = true; - regmap = devm_regmap_init_i2c(client, ®map_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - nvm->regmap = regmap; -- -- nvmem_config.name = dev_name(dev); -- nvmem_config.dev = dev; -- nvmem_config.read_only = true; -- nvmem_config.root_only = true; -- nvmem_config.owner = THIS_MODULE; -- nvmem_config.compat = true; -- nvmem_config.base_dev = dev; -- nvmem_config.reg_read = ov2740_nvmem_read; -- nvmem_config.reg_write = NULL; - nvmem_config.priv = nvm; -- nvmem_config.stride = 1; -- nvmem_config.word_size = 1; -- nvmem_config.size = CUSTOMER_USE_OTP_SIZE; - - nvm->nvmem = devm_nvmem_register(dev, &nvmem_config); - if (IS_ERR(nvm->nvmem)) -diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c ---- a/drivers/media/pci/intel/ipu-bridge.c -+++ b/drivers/media/pci/intel/ipu-bridge.c -@@ -49,6 +49,8 @@ - * Please keep the list sorted by ACPI HID. - */ - static const struct ipu_sensor_config ipu_supported_sensors[] = { -+ /* Himax HM1092 */ -+ IPU_SENSOR_CONFIG("HIMX1092", 2, 180000000, 180480000), - /* Himax HM11B1 */ - IPU_SENSOR_CONFIG("HIMX11B1", 1, 384000000), - /* Himax HM2170 */ -@@ -97,6 +99,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { - IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), - /* Sony IMX471 */ - IPU_SENSOR_CONFIG("SONY471A", 1, 200000000), -+ /* Sony IMX471 (found on Lenovo X1 Carbon G14) */ -+ IPU_SENSOR_CONFIG("TBE20A0", 1, 200000000), - /* Toshiba T4KA3 */ - IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000), - }; -@@ -194,8 +198,8 @@ static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev - for (i = 0; i < ARRAY_SIZE(ivsc_acpi_ids); i++) { - const struct acpi_device_id *acpi_id = &ivsc_acpi_ids[i]; - struct acpi_device *consumer, *ivsc_adev; -- - acpi_handle handle = acpi_device_handle(ACPI_PTR(adev)); -+ - for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1) - /* camera sensor depends on IVSC in DSDT if exist */ - for_each_acpi_consumer_dev(ivsc_adev, consumer) diff --git a/kernel/0543-media-laptop-cameras.patch.sig b/kernel/0543-media-laptop-cameras.patch.sig deleted file mode 100644 index afd9deb..0000000 Binary files a/kernel/0543-media-laptop-cameras.patch.sig and /dev/null differ diff --git a/kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch b/kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch deleted file mode 100644 index abda19b..0000000 --- a/kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c ---- a/drivers/media/pci/intel/ipu-bridge.c -+++ b/drivers/media/pci/intel/ipu-bridge.c -@@ -138,6 +138,45 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = { - }, - .driver_data = "OVTI02C1", - }, -+ /* -+ * The first four characters of DMI_BOARD_NAME identify the Lenovo -+ * machine type/model. For example, a DMI_BOARD_NAME starting with -+ * "21Q6" indicates a ThinkPad X9-15. -+ * -+ * Reference: https://psref.lenovo.com/ -+ */ -+ { -+ /* Lenovo X9-14 */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_BOARD_NAME, "21QA"), -+ }, -+ .driver_data = "SONY471A", -+ }, -+ { -+ /* Lenovo X9-14 */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_BOARD_NAME, "21QB"), -+ }, -+ .driver_data = "SONY471A", -+ }, -+ { -+ /* Lenovo X9-15 */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_BOARD_NAME, "21Q6"), -+ }, -+ .driver_data = "SONY471A", -+ }, -+ { -+ /* Lenovo X9-15 */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_BOARD_NAME, "21Q7"), -+ }, -+ .driver_data = "SONY471A", -+ }, - {} /* Terminating entry */ - }; - diff --git a/kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch.sig b/kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch.sig deleted file mode 100644 index 844b9fe..0000000 Binary files a/kernel/0544-ipu-bridge-lenovo-x9-upside-down.patch.sig and /dev/null differ diff --git a/kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch b/kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch deleted file mode 100644 index 7c15eb7..0000000 --- a/kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c ---- a/drivers/media/pci/intel/ipu-bridge.c -+++ b/drivers/media/pci/intel/ipu-bridge.c -@@ -138,6 +138,13 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = { - }, - .driver_data = "OVTI02C1", - }, -+ { -+ .matches = { -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), -+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 16 (Dell 16 Premium) DA16250"), -+ }, -+ .driver_data = "OVTI02C1", -+ }, - /* - * The first four characters of DMI_BOARD_NAME identify the Lenovo - * machine type/model. For example, a DMI_BOARD_NAME starting with diff --git a/kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch.sig b/kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch.sig deleted file mode 100644 index 4e6cc4f..0000000 Binary files a/kernel/0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch.sig and /dev/null differ diff --git a/kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch b/kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch deleted file mode 100644 index a42d186..0000000 --- a/kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c ---- a/drivers/media/pci/intel/ipu-bridge.c -+++ b/drivers/media/pci/intel/ipu-bridge.c -@@ -184,6 +184,14 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = { - }, - .driver_data = "SONY471A", - }, -+ { -+ /* Samsung Galaxy Book5 Pro 360 */ -+ .matches = { -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), -+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "960QHA"), -+ }, -+ .driver_data = "OVTI02E1", -+ }, - {} /* Terminating entry */ - }; - diff --git a/kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch.sig b/kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch.sig deleted file mode 100644 index 18998fb..0000000 Binary files a/kernel/0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch.sig and /dev/null differ diff --git a/kernel/0547-int3472-imx471-vana-power-enable.patch b/kernel/0547-int3472-imx471-vana-power-enable.patch deleted file mode 100644 index db38adc..0000000 --- a/kernel/0547-int3472-imx471-vana-power-enable.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -164,6 +164,24 @@ static const struct int3472_gpio_map int3472_gpio_map[] = { - .con_id = "dvdd", - .enable_time_us = 45 * USEC_PER_MSEC, - }, -+ { /* imx471 expects "vana" as con_id for power enable */ -+ .hid = "SONY471A", -+ .type_from = INT3472_GPIO_TYPE_POWER_ENABLE, -+ .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, -+ .con_id = "vana", -+ .enable_time_us = GPIO_REGULATOR_ENABLE_TIME, -+ }, -+ { -+ /* -+ * imx471 (on Lenovo ThinkPads X1 G14) expects "vana" as con_id -+ * for power enable -+ */ -+ .hid = "TBE20A0", -+ .type_from = INT3472_GPIO_TYPE_POWER_ENABLE, -+ .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, -+ .con_id = "vana", -+ .enable_time_us = GPIO_REGULATOR_ENABLE_TIME, -+ }, - }; - - static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type, diff --git a/kernel/0547-int3472-imx471-vana-power-enable.patch.sig b/kernel/0547-int3472-imx471-vana-power-enable.patch.sig deleted file mode 100644 index fbd699c..0000000 Binary files a/kernel/0547-int3472-imx471-vana-power-enable.patch.sig and /dev/null differ diff --git a/kernel/0548-media-cvs-sensor-node-in-bound-callback.patch b/kernel/0548-media-cvs-sensor-node-in-bound-callback.patch deleted file mode 100644 index b041d90..0000000 --- a/kernel/0548-media-cvs-sensor-node-in-bound-callback.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff --git a/drivers/media/i2c/cvs/v4l2.c b/drivers/media/i2c/cvs/v4l2.c ---- a/drivers/media/i2c/cvs/v4l2.c -+++ b/drivers/media/i2c/cvs/v4l2.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -400,7 +401,7 @@ static int cvs_csi_notify_bound(struct v4l2_async_notifier *notifier, - struct v4l2_async_connection *asc) - { - struct icvs *ctx = notifier_to_csi(notifier); -- int pad; -+ int pad, ret; - - pad = media_entity_get_fwnode_pad(&sd->entity, asc->match.fwnode, - MEDIA_PAD_FL_SOURCE); -@@ -409,9 +410,13 @@ static int cvs_csi_notify_bound(struct v4l2_async_notifier *notifier, - - ctx->remote = &sd->entity.pads[pad]; - -- return media_create_pad_link(&sd->entity, pad, &ctx->subdev.entity, -- ICVS_CSI_PAD_SINK, MEDIA_LNK_FL_ENABLED | -- MEDIA_LNK_FL_IMMUTABLE); -+ ret = media_create_pad_link(&sd->entity, pad, &ctx->subdev.entity, -+ ICVS_CSI_PAD_SINK, MEDIA_LNK_FL_ENABLED | -+ MEDIA_LNK_FL_IMMUTABLE); -+ if (ret) -+ return ret; -+ -+ return v4l2_device_register_subdev_nodes(sd->v4l2_dev); - } - - /** diff --git a/kernel/0548-media-cvs-sensor-node-in-bound-callback.patch.sig b/kernel/0548-media-cvs-sensor-node-in-bound-callback.patch.sig deleted file mode 100644 index 5355a32..0000000 Binary files a/kernel/0548-media-cvs-sensor-node-in-bound-callback.patch.sig and /dev/null differ diff --git a/kernel/0549-media-imx471-analog-gain-max-960.patch b/kernel/0549-media-imx471-analog-gain-max-960.patch deleted file mode 100644 index a11c4f2..0000000 --- a/kernel/0549-media-imx471-analog-gain-max-960.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/media/i2c/imx471.c b/drivers/media/i2c/imx471.c ---- a/drivers/media/i2c/imx471.c -+++ b/drivers/media/i2c/imx471.c -@@ -41,7 +41,7 @@ - /* Analog gain control */ - #define IMX471_REG_ANALOG_GAIN CCI_REG16(0x0204) - #define IMX471_ANA_GAIN_MIN 0 --#define IMX471_ANA_GAIN_MAX 800 -+#define IMX471_ANA_GAIN_MAX 960 - #define IMX471_ANA_GAIN_STEP 1 - #define IMX471_ANA_GAIN_DEFAULT 0 - diff --git a/kernel/0549-media-imx471-analog-gain-max-960.patch.sig b/kernel/0549-media-imx471-analog-gain-max-960.patch.sig deleted file mode 100644 index bd5334b..0000000 Binary files a/kernel/0549-media-imx471-analog-gain-max-960.patch.sig and /dev/null differ diff --git a/kernel/0560-input-updates.patch b/kernel/0560-input-updates.patch deleted file mode 100644 index d8548c7..0000000 --- a/kernel/0560-input-updates.patch +++ /dev/null @@ -1,3869 +0,0 @@ -diff --git a/drivers/input/input.c b/drivers/input/input.c ---- a/drivers/input/input.c -+++ b/drivers/input/input.c -@@ -318,7 +318,7 @@ static int input_get_disposition(struct input_dev *dev, - static void input_event_dispose(struct input_dev *dev, int disposition, - unsigned int type, unsigned int code, int value) - { -- if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) -+ if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event && dev->ready) - dev->event(dev, type, code, value); - - if (disposition & INPUT_PASS_TO_HANDLERS) { -@@ -568,6 +568,75 @@ void input_release_device(struct input_handle *handle) - } - EXPORT_SYMBOL(input_release_device); - -+#define INPUT_DO_TOGGLE(dev, type, bits, on) \ -+ do { \ -+ int i; \ -+ bool active; \ -+ \ -+ if (!test_bit(EV_##type, dev->evbit)) \ -+ break; \ -+ \ -+ for_each_set_bit(i, dev->bits##bit, type##_CNT) { \ -+ active = test_bit(i, dev->bits); \ -+ if (!active && !on) \ -+ continue; \ -+ \ -+ dev->event(dev, EV_##type, i, on ? active : 0); \ -+ } \ -+ } while (0) -+ -+/* -+ * Iterate through the logical state of the input device (LEDs, sounds, -+ * auto-repeat) and explicitly push that state down to the hardware -+ * via dev->event() to match the current logical state (if activate is true), -+ * or forcibly turn off all feedback like LEDs and sounds during teardown -+ * or suspend (if activate is false). -+ * -+ * Primarily used as a state-replay mechanism after a device is opened -+ * or uninhibited, as events might have been dropped by the core while the -+ * hardware was not marked as ready. -+ */ -+static void input_dev_toggle(struct input_dev *dev, bool activate) -+{ -+ if (!dev->event || !dev->ready) -+ return; -+ -+ INPUT_DO_TOGGLE(dev, LED, led, activate); -+ INPUT_DO_TOGGLE(dev, SND, snd, activate); -+ -+ if (activate && test_bit(EV_REP, dev->evbit)) { -+ dev->event(dev, EV_REP, REP_PERIOD, dev->rep[REP_PERIOD]); -+ dev->event(dev, EV_REP, REP_DELAY, dev->rep[REP_DELAY]); -+ } -+} -+ -+static int input_start_device(struct input_dev *dev) -+{ -+ int error; -+ -+ lockdep_assert_held(&dev->mutex); -+ -+ if (dev->users++ == 0 && !dev->inhibited) { -+ if (dev->open) { -+ error = dev->open(dev); -+ if (error) { -+ dev->users--; -+ return error; -+ } -+ } -+ -+ scoped_guard(spinlock_irq, &dev->event_lock) { -+ dev->ready = true; -+ input_dev_toggle(dev, true); -+ } -+ -+ if (dev->poller) -+ input_dev_poller_start(dev->poller); -+ } -+ -+ return 0; -+} -+ - /** - * input_open_device - open input device - * @handle: handle through which device is being accessed -@@ -586,21 +655,9 @@ int input_open_device(struct input_handle *handle) - - handle->open++; - -- if (handle->handler->passive_observer) -- return 0; -- -- if (dev->users++ || dev->inhibited) { -- /* -- * Device is already opened and/or inhibited, -- * so we can exit immediately and report success. -- */ -- return 0; -- } -- -- if (dev->open) { -- error = dev->open(dev); -+ if (!handle->handler->passive_observer) { -+ error = input_start_device(dev); - if (error) { -- dev->users--; - handle->open--; - /* - * Make sure we are not delivering any more -@@ -611,8 +668,8 @@ int input_open_device(struct input_handle *handle) - } - } - -- if (dev->poller) -- input_dev_poller_start(dev->poller); -+ if (handle->open == 1 && handle->handler->start) -+ handle->handler->start(handle); - } - - return 0; -@@ -651,6 +708,12 @@ void input_close_device(struct input_handle *handle) - if (!--dev->users && !dev->inhibited) { - if (dev->poller) - input_dev_poller_stop(dev->poller); -+ -+ scoped_guard(spinlock_irq, &dev->event_lock) { -+ input_dev_toggle(dev, false); -+ dev->ready = false; -+ } -+ - if (dev->close) - dev->close(dev); - } -@@ -1702,37 +1765,6 @@ static int input_dev_uevent(const struct device *device, struct kobj_uevent_env - return 0; - } - --#define INPUT_DO_TOGGLE(dev, type, bits, on) \ -- do { \ -- int i; \ -- bool active; \ -- \ -- if (!test_bit(EV_##type, dev->evbit)) \ -- break; \ -- \ -- for_each_set_bit(i, dev->bits##bit, type##_CNT) { \ -- active = test_bit(i, dev->bits); \ -- if (!active && !on) \ -- continue; \ -- \ -- dev->event(dev, EV_##type, i, on ? active : 0); \ -- } \ -- } while (0) -- --static void input_dev_toggle(struct input_dev *dev, bool activate) --{ -- if (!dev->event) -- return; -- -- INPUT_DO_TOGGLE(dev, LED, led, activate); -- INPUT_DO_TOGGLE(dev, SND, snd, activate); -- -- if (activate && test_bit(EV_REP, dev->evbit)) { -- dev->event(dev, EV_REP, REP_PERIOD, dev->rep[REP_PERIOD]); -- dev->event(dev, EV_REP, REP_DELAY, dev->rep[REP_DELAY]); -- } --} -- - /** - * input_reset_device() - reset/restore the state of input device - * @dev: input device whose state needs to be reset -@@ -1756,52 +1788,73 @@ static int input_inhibit_device(struct input_dev *dev) - { - guard(mutex)(&dev->mutex); - -+ if (dev->going_away) -+ return -ENODEV; -+ - if (dev->inhibited) - return 0; - - if (dev->users) { -- if (dev->close) -- dev->close(dev); - if (dev->poller) - input_dev_poller_stop(dev->poller); -+ -+ scoped_guard(spinlock_irq, &dev->event_lock) { -+ input_dev_toggle(dev, false); -+ dev->ready = false; -+ } -+ -+ if (dev->close) -+ dev->close(dev); - } - - scoped_guard(spinlock_irq, &dev->event_lock) { - input_mt_release_slots(dev); - input_dev_release_keys(dev); - input_handle_event(dev, EV_SYN, SYN_REPORT, 1); -- input_dev_toggle(dev, false); -+ dev->inhibited = true; - } - -- dev->inhibited = true; -- - return 0; - } - - static int input_uninhibit_device(struct input_dev *dev) - { -+ struct input_handle *handle; - int error; - - guard(mutex)(&dev->mutex); - -+ if (dev->going_away) -+ return -ENODEV; -+ - if (!dev->inhibited) - return 0; - -+ dev->inhibited = false; -+ - if (dev->users) { - if (dev->open) { - error = dev->open(dev); -- if (error) -+ if (error) { -+ dev->inhibited = true; - return error; -+ } - } -- if (dev->poller) -- input_dev_poller_start(dev->poller); -+ scoped_guard(spinlock_irq, &dev->event_lock) -+ dev->ready = true; - } - -- dev->inhibited = false; -- - scoped_guard(spinlock_irq, &dev->event_lock) - input_dev_toggle(dev, true); - -+ if (dev->users && dev->poller) -+ input_dev_poller_start(dev->poller); -+ -+ list_for_each_entry(handle, &dev->h_list, d_node) { -+ if (handle->open && handle->handler->start) -+ handle->handler->start(handle); -+ } -+ - return 0; - } - -@@ -2655,9 +2708,6 @@ int input_register_handle(struct input_handle *handle) - */ - list_add_tail_rcu(&handle->h_node, &handler->h_list); - -- if (handler->start) -- handler->start(handle); -- - return 0; - } - EXPORT_SYMBOL(input_register_handle); -diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig ---- a/drivers/input/keyboard/Kconfig -+++ b/drivers/input/keyboard/Kconfig -@@ -119,44 +119,6 @@ config KEYBOARD_ATKBD - To compile this driver as a module, choose M here: the - module will be called atkbd. - --config KEYBOARD_ATKBD_HP_KEYCODES -- bool "Use HP keyboard scancodes" -- depends on PARISC && KEYBOARD_ATKBD -- default y -- help -- Say Y here if you have a PA-RISC machine and want to use an AT or -- PS/2 keyboard, and your keyboard uses keycodes that are specific to -- PA-RISC keyboards. -- -- Say N if you use a standard keyboard. -- --config KEYBOARD_ATKBD_RDI_KEYCODES -- bool "Use PrecisionBook keyboard scancodes" -- depends on KEYBOARD_ATKBD_HP_KEYCODES -- default n -- help -- If you have an RDI PrecisionBook, say Y here if you want to use its -- built-in keyboard (as opposed to an external keyboard). -- -- The PrecisionBook has five keys that conflict with those used by most -- AT and PS/2 keyboards. These are as follows: -- -- PrecisionBook Standard AT or PS/2 -- -- F1 F12 -- Left Ctrl Left Alt -- Caps Lock Left Ctrl -- Right Ctrl Caps Lock -- Left 102nd key (the key to the right of Left Shift) -- -- If you say N here, and use the PrecisionBook keyboard, then each key -- in the left-hand column will be interpreted as the corresponding key -- in the right-hand column. -- -- If you say Y here, and use an external keyboard, then each key in the -- right-hand column will be interpreted as the key shown in the -- left-hand column. -- - config KEYBOARD_QT1050 - tristate "Microchip AT42QT1050 Touch Sensor Chip" - depends on I2C -diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c ---- a/drivers/input/keyboard/atkbd.c -+++ b/drivers/input/keyboard/atkbd.c -@@ -73,13 +73,6 @@ MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard conne - #define ATKBD_KEYMAP_SIZE 512 - - static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { --#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES -- --/* XXX: need a more general approach */ -- --#include "hpps2atkbd.h" /* include the keyboard scancodes */ -- --#else - 0, 67, 65, 63, 61, 59, 60, 88,183, 68, 66, 64, 62, 15, 41,117, - 184, 56, 42, 93, 29, 16, 2, 0,185, 0, 44, 31, 30, 17, 3, 0, - 186, 46, 45, 32, 18, 5, 4, 95,187, 57, 47, 33, 20, 19, 6,183, -@@ -99,7 +92,6 @@ static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { - 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, - - 0, 0, 0, 65, 99, --#endif - }; - - static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { -diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c ---- a/drivers/input/keyboard/cap11xx.c -+++ b/drivers/input/keyboard/cap11xx.c -@@ -5,6 +5,8 @@ - * (c) 2014 Daniel Mack - */ - -+#include -+#include - #include - #include - #include -@@ -16,63 +18,43 @@ - #include - #include - -+#define CAP1114_REG_BUTTON_STATUS1 0x03 -+#define CAP1114_REG_BUTTON_STATUS2 0x04 -+#define CAP1114_REG_CONFIG2 0x40 -+#define CAP1114_REG_CONFIG2_VOL_UP_DOWN BIT(1) -+#define CAP1114_REG_LED_OUTPUT_CONTROL1 0x73 -+ - #define CAP11XX_REG_MAIN_CONTROL 0x00 - #define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6) - #define CAP11XX_REG_MAIN_CONTROL_GAIN_MASK (0xc0) - #define CAP11XX_REG_MAIN_CONTROL_DLSEEP BIT(4) --#define CAP11XX_REG_GENERAL_STATUS 0x02 - #define CAP11XX_REG_SENSOR_INPUT 0x03 --#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a -+#define CAP1114_REG_BUTTON_STATUS2 0x04 - #define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X)) - #define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f - #define CAP11XX_REG_SENSITIVITY_CONTROL_DELTA_SENSE_MASK 0x70 --#define CAP11XX_REG_CONFIG 0x20 --#define CAP11XX_REG_SENSOR_ENABLE 0x21 --#define CAP11XX_REG_SENSOR_CONFIG 0x22 --#define CAP11XX_REG_SENSOR_CONFIG2 0x23 --#define CAP11XX_REG_SAMPLING_CONFIG 0x24 --#define CAP11XX_REG_CALIBRATION 0x26 --#define CAP11XX_REG_INT_ENABLE 0x27 - #define CAP11XX_REG_REPEAT_RATE 0x28 - #define CAP11XX_REG_SIGNAL_GUARD_ENABLE 0x29 --#define CAP11XX_REG_MT_CONFIG 0x2a --#define CAP11XX_REG_MT_PATTERN_CONFIG 0x2b --#define CAP11XX_REG_MT_PATTERN 0x2d --#define CAP11XX_REG_RECALIB_CONFIG 0x2f - #define CAP11XX_REG_SENSOR_THRESH(X) (0x30 + (X)) --#define CAP11XX_REG_SENSOR_NOISE_THRESH 0x38 --#define CAP11XX_REG_STANDBY_CHANNEL 0x40 --#define CAP11XX_REG_STANDBY_CONFIG 0x41 --#define CAP11XX_REG_STANDBY_SENSITIVITY 0x42 --#define CAP11XX_REG_STANDBY_THRESH 0x43 - #define CAP11XX_REG_CONFIG2 0x44 - #define CAP11XX_REG_CONFIG2_ALT_POL BIT(6) --#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X)) --#define CAP11XX_REG_LED_POLARITY 0x73 - #define CAP11XX_REG_LED_OUTPUT_CONTROL 0x74 - #define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG 0x80 - #define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG2 0x81 -- --#define CAP11XX_REG_LED_DUTY_CYCLE_1 0x90 --#define CAP11XX_REG_LED_DUTY_CYCLE_2 0x91 --#define CAP11XX_REG_LED_DUTY_CYCLE_3 0x92 - #define CAP11XX_REG_LED_DUTY_CYCLE_4 0x93 - --#define CAP11XX_REG_LED_DUTY_MIN_MASK (0x0f) --#define CAP11XX_REG_LED_DUTY_MIN_MASK_SHIFT (0) - #define CAP11XX_REG_LED_DUTY_MAX_MASK (0xf0) --#define CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT (4) - #define CAP11XX_REG_LED_DUTY_MAX_VALUE (15) - --#define CAP11XX_REG_SENSOR_CALIB (0xb1 + (X)) --#define CAP11XX_REG_SENSOR_CALIB_LSB1 0xb9 --#define CAP11XX_REG_SENSOR_CALIB_LSB2 0xba - #define CAP11XX_REG_PRODUCT_ID 0xfd - #define CAP11XX_REG_MANUFACTURER_ID 0xfe - #define CAP11XX_REG_REVISION 0xff - - #define CAP11XX_MANUFACTURER_ID 0x5d - -+#define CAP11XX_T_RST_FILT_MIN_US 10000 -+#define CAP11XX_T_RST_ON_MIN_MS 400 -+ - #ifdef CONFIG_LEDS_CLASS - struct cap11xx_led { - struct cap11xx_priv *priv; -@@ -85,6 +67,7 @@ struct cap11xx_priv { - struct regmap *regmap; - struct device *dev; - struct input_dev *idev; -+ struct gpio_desc *reset_gpio; - const struct cap11xx_hw_model *model; - - struct cap11xx_led *leds; -@@ -101,47 +84,32 @@ struct cap11xx_priv { - - struct cap11xx_hw_model { - u8 product_id; -+ u8 led_output_control_reg_base; -+ u8 sensor_input_reg_base; - unsigned int num_channels; - unsigned int num_leds; -+ unsigned int num_sensor_thresholds; - bool has_gain; -+ bool has_grouped_sensors; - bool has_irq_config; -+ bool has_repeat_en; - bool has_sensitivity_control; - bool has_signal_guard; - }; - - static const struct reg_default cap11xx_reg_defaults[] = { - { CAP11XX_REG_MAIN_CONTROL, 0x00 }, -- { CAP11XX_REG_GENERAL_STATUS, 0x00 }, -- { CAP11XX_REG_SENSOR_INPUT, 0x00 }, -- { CAP11XX_REG_NOISE_FLAG_STATUS, 0x00 }, - { CAP11XX_REG_SENSITIVITY_CONTROL, 0x2f }, -- { CAP11XX_REG_CONFIG, 0x20 }, -- { CAP11XX_REG_SENSOR_ENABLE, 0x3f }, -- { CAP11XX_REG_SENSOR_CONFIG, 0xa4 }, -- { CAP11XX_REG_SENSOR_CONFIG2, 0x07 }, -- { CAP11XX_REG_SAMPLING_CONFIG, 0x39 }, -- { CAP11XX_REG_CALIBRATION, 0x00 }, -- { CAP11XX_REG_INT_ENABLE, 0x3f }, - { CAP11XX_REG_REPEAT_RATE, 0x3f }, -- { CAP11XX_REG_MT_CONFIG, 0x80 }, -- { CAP11XX_REG_MT_PATTERN_CONFIG, 0x00 }, -- { CAP11XX_REG_MT_PATTERN, 0x3f }, -- { CAP11XX_REG_RECALIB_CONFIG, 0x8a }, - { CAP11XX_REG_SENSOR_THRESH(0), 0x40 }, - { CAP11XX_REG_SENSOR_THRESH(1), 0x40 }, - { CAP11XX_REG_SENSOR_THRESH(2), 0x40 }, - { CAP11XX_REG_SENSOR_THRESH(3), 0x40 }, - { CAP11XX_REG_SENSOR_THRESH(4), 0x40 }, - { CAP11XX_REG_SENSOR_THRESH(5), 0x40 }, -- { CAP11XX_REG_SENSOR_NOISE_THRESH, 0x01 }, -- { CAP11XX_REG_STANDBY_CHANNEL, 0x00 }, -- { CAP11XX_REG_STANDBY_CONFIG, 0x39 }, -- { CAP11XX_REG_STANDBY_SENSITIVITY, 0x02 }, -- { CAP11XX_REG_STANDBY_THRESH, 0x40 }, -+ { CAP11XX_REG_SENSOR_THRESH(6), 0x40 }, -+ { CAP11XX_REG_SENSOR_THRESH(7), 0x40 }, - { CAP11XX_REG_CONFIG2, 0x40 }, -- { CAP11XX_REG_LED_POLARITY, 0x00 }, -- { CAP11XX_REG_SENSOR_CALIB_LSB1, 0x00 }, -- { CAP11XX_REG_SENSOR_CALIB_LSB2, 0x00 }, - }; - - static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg) -@@ -149,6 +117,12 @@ static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg) - switch (reg) { - case CAP11XX_REG_MAIN_CONTROL: - case CAP11XX_REG_SENSOR_INPUT: -+ /* -+ * CAP1114_REG_BUTTON_STATUS1 (CAP11XX_REG_SENSOR_INPUT) and -+ * CAP1114_REG_BUTTON_STATUS2 is volatile for the CAP1114, -+ * which supports more than 8 touch channels. -+ */ -+ case CAP1114_REG_BUTTON_STATUS2: - case CAP11XX_REG_SENOR_DELTA(0): - case CAP11XX_REG_SENOR_DELTA(1): - case CAP11XX_REG_SENOR_DELTA(2): -@@ -257,8 +231,8 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv) - } - - if (!of_property_read_u32_array(node, "microchip,input-threshold", -- priv->thresholds, priv->model->num_channels)) { -- for (i = 0; i < priv->model->num_channels; i++) { -+ priv->thresholds, priv->model->num_sensor_thresholds)) { -+ for (i = 0; i < priv->model->num_sensor_thresholds; i++) { - if (priv->thresholds[i] > 127) { - dev_err(dev, "Invalid input-threshold value %u\n", - priv->thresholds[i]); -@@ -273,10 +247,13 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv) - } - } - -- if (!of_property_read_u32_array(node, "microchip,calib-sensitivity", -- priv->calib_sensitivities, -- priv->model->num_channels)) { -- if (priv->model->has_sensitivity_control) { -+ if (of_property_present(node, "microchip,calib-sensitivity")) { -+ if (!priv->model->has_sensitivity_control) { -+ dev_warn(dev, -+ "This model doesn't support 'calib-sensitivity'\n"); -+ } else if (!of_property_read_u32_array(node, "microchip,calib-sensitivity", -+ priv->calib_sensitivities, -+ priv->model->num_channels)) { - for (i = 0; i < priv->model->num_channels; i++) { - if (!is_power_of_2(priv->calib_sensitivities[i]) || - priv->calib_sensitivities[i] > 4) { -@@ -296,32 +273,31 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv) - if (error) - return error; - } -- } else { -- dev_warn(dev, -- "This model doesn't support 'calib-sensitivity'\n"); - } - } - -- for (i = 0; i < priv->model->num_channels; i++) { -- if (!of_property_read_u32_index(node, "microchip,signal-guard", -- i, &u32_val)) { -- if (u32_val > 1) -- return -EINVAL; -- if (u32_val) -- priv->signal_guard_inputs_mask |= 0x01 << i; -- } -- } -- -- if (priv->signal_guard_inputs_mask) { -- if (priv->model->has_signal_guard) { -- error = regmap_write(priv->regmap, -- CAP11XX_REG_SIGNAL_GUARD_ENABLE, -- priv->signal_guard_inputs_mask); -- if (error) -- return error; -- } else { -+ if (of_property_present(node, "microchip,signal-guard")) { -+ if (!priv->model->has_signal_guard) { - dev_warn(dev, - "This model doesn't support 'signal-guard'\n"); -+ } else { -+ for (i = 0; i < priv->model->num_channels; i++) { -+ if (!of_property_read_u32_index(node, "microchip,signal-guard", -+ i, &u32_val)) { -+ if (u32_val > 1) -+ return -EINVAL; -+ if (u32_val) -+ priv->signal_guard_inputs_mask |= 0x01 << i; -+ } -+ } -+ -+ if (priv->signal_guard_inputs_mask) { -+ error = regmap_write(priv->regmap, -+ CAP11XX_REG_SIGNAL_GUARD_ENABLE, -+ priv->signal_guard_inputs_mask); -+ if (error) -+ return error; -+ } - } - } - -@@ -332,10 +308,23 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv) - of_property_read_u32_array(node, "linux,keycodes", - priv->keycodes, priv->model->num_channels); - -- /* Disable autorepeat. The Linux input system has its own handling. */ -- error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0); -- if (error) -- return error; -+ /* -+ * CAP1114 needs dedicated configuration to split -+ * grouped sensors into independent inputs. -+ */ -+ if (priv->model->has_grouped_sensors) { -+ error = regmap_set_bits(priv->regmap, CAP1114_REG_CONFIG2, -+ CAP1114_REG_CONFIG2_VOL_UP_DOWN); -+ if (error) -+ return error; -+ } -+ -+ if (priv->model->has_repeat_en) { -+ /* Disable autorepeat. The Linux input system has its own handling. */ -+ error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0); -+ if (error) -+ return error; -+ } - - return 0; - } -@@ -354,10 +343,25 @@ static irqreturn_t cap11xx_thread_func(int irq_num, void *data) - if (ret < 0) - goto out; - -- ret = regmap_read(priv->regmap, CAP11XX_REG_SENSOR_INPUT, &status); -+ ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base, &status); - if (ret < 0) - goto out; - -+ if (priv->model->num_channels > 8) { -+ unsigned int status2; -+ -+ ret = regmap_read(priv->regmap, priv->model->sensor_input_reg_base + 1, &status2); -+ if (ret < 0) -+ goto out; -+ -+ /* -+ * CAP1114 STATUS1 register only contains data for the first 6 channels. -+ * the remaining channels is stored in STATUS2. -+ */ -+ status &= GENMASK(5, 0); -+ status |= FIELD_PREP(GENMASK(13, 6), status2); -+ } -+ - for (i = 0; i < priv->idev->keycodemax; i++) - input_report_key(priv->idev, priv->keycodes[i], - status & (1 << i)); -@@ -407,10 +411,16 @@ static int cap11xx_led_set(struct led_classdev *cdev, - * limitation. Brightness levels per LED are either - * 0 (OFF) and 1 (ON). - */ -- return regmap_update_bits(priv->regmap, -- CAP11XX_REG_LED_OUTPUT_CONTROL, -- BIT(led->reg), -- value ? BIT(led->reg) : 0); -+ if (led->reg >= 8) -+ return regmap_update_bits(priv->regmap, -+ priv->model->led_output_control_reg_base + 1, -+ BIT(led->reg - 8), -+ value ? BIT(led->reg - 8) : 0); -+ else -+ return regmap_update_bits(priv->regmap, -+ priv->model->led_output_control_reg_base, -+ BIT(led->reg), -+ value ? BIT(led->reg) : 0); - } - - static int cap11xx_init_leds(struct device *dev, -@@ -420,6 +430,7 @@ static int cap11xx_init_leds(struct device *dev, - struct cap11xx_led *led; - int cnt = of_get_child_count(node); - int error; -+ u32 duty_val; - - if (!num_leds || !cnt) - return 0; -@@ -433,15 +444,26 @@ static int cap11xx_init_leds(struct device *dev, - - priv->leds = led; - -+ /* Set all LEDs to off */ - error = regmap_update_bits(priv->regmap, -- CAP11XX_REG_LED_OUTPUT_CONTROL, 0xff, 0); -+ priv->model->led_output_control_reg_base, -+ GENMASK(min(num_leds, 8) - 1, 0), 0); - if (error) - return error; - -+ if (num_leds > 8) { -+ error = regmap_update_bits(priv->regmap, -+ priv->model->led_output_control_reg_base + 1, -+ GENMASK(num_leds - 8 - 1, 0), 0); -+ if (error) -+ return error; -+ } -+ -+ duty_val = FIELD_PREP(CAP11XX_REG_LED_DUTY_MAX_MASK, -+ CAP11XX_REG_LED_DUTY_MAX_VALUE); -+ - error = regmap_update_bits(priv->regmap, CAP11XX_REG_LED_DUTY_CYCLE_4, -- CAP11XX_REG_LED_DUTY_MAX_MASK, -- CAP11XX_REG_LED_DUTY_MAX_VALUE << -- CAP11XX_REG_LED_DUTY_MAX_MASK_SHIFT); -+ CAP11XX_REG_LED_DUTY_MAX_MASK, duty_val); - if (error) - return error; - -@@ -510,9 +532,20 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client) - if (IS_ERR(priv->regmap)) - return PTR_ERR(priv->regmap); - -+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); -+ if (IS_ERR(priv->reset_gpio)) -+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), -+ "Failed to get 'reset' GPIO\n"); -+ -+ if (priv->reset_gpio) { -+ usleep_range(CAP11XX_T_RST_FILT_MIN_US, CAP11XX_T_RST_FILT_MIN_US * 2); -+ gpiod_set_value_cansleep(priv->reset_gpio, 0); -+ msleep(CAP11XX_T_RST_ON_MIN_MS); -+ } -+ - error = regmap_read(priv->regmap, CAP11XX_REG_PRODUCT_ID, &val); - if (error) -- return error; -+ return dev_err_probe(dev, error, "Failed to read product ID\n"); - - if (val != cap->product_id) { - dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n", -@@ -522,7 +555,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client) - - error = regmap_read(priv->regmap, CAP11XX_REG_MANUFACTURER_ID, &val); - if (error) -- return error; -+ return dev_err_probe(dev, error, "Failed to read manufacturer ID\n"); - - if (val != CAP11XX_MANUFACTURER_ID) { - dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n", -@@ -531,11 +564,8 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client) - } - - error = regmap_read(priv->regmap, CAP11XX_REG_REVISION, &rev); -- if (error < 0) -- return error; -- -- dev_info(dev, "CAP11XX detected, model %s, revision 0x%02x\n", -- id->name, rev); -+ if (error) -+ return dev_err_probe(dev, error, "Failed to read revision\n"); - - priv->model = cap; - -@@ -599,47 +629,79 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client) - } - - static const struct cap11xx_hw_model cap1106_model = { -- .product_id = 0x55, .num_channels = 6, .num_leds = 0, -+ .product_id = 0x55, -+ .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6, -+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, - .has_gain = true, - .has_irq_config = true, -+ .has_repeat_en = true, -+}; -+ -+static const struct cap11xx_hw_model cap1114_model = { -+ .product_id = 0x3a, -+ .num_channels = 14, .num_leds = 11, .num_sensor_thresholds = 8, -+ .led_output_control_reg_base = CAP1114_REG_LED_OUTPUT_CONTROL1, -+ .sensor_input_reg_base = CAP1114_REG_BUTTON_STATUS1, -+ .has_grouped_sensors = true, - }; - - static const struct cap11xx_hw_model cap1126_model = { -- .product_id = 0x53, .num_channels = 6, .num_leds = 2, -+ .product_id = 0x53, -+ .num_channels = 6, .num_leds = 2, .num_sensor_thresholds = 6, -+ .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL, -+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, - .has_gain = true, - .has_irq_config = true, -+ .has_repeat_en = true, - }; - - static const struct cap11xx_hw_model cap1188_model = { -- .product_id = 0x50, .num_channels = 8, .num_leds = 8, -+ .product_id = 0x50, -+ .num_channels = 8, .num_leds = 8, .num_sensor_thresholds = 8, -+ .led_output_control_reg_base = CAP11XX_REG_LED_OUTPUT_CONTROL, -+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, - .has_gain = true, - .has_irq_config = true, -+ .has_repeat_en = true, - }; - - static const struct cap11xx_hw_model cap1203_model = { -- .product_id = 0x6d, .num_channels = 3, .num_leds = 0, -+ .product_id = 0x6d, -+ .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3, -+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, -+ .has_repeat_en = true, - }; - - static const struct cap11xx_hw_model cap1206_model = { -- .product_id = 0x67, .num_channels = 6, .num_leds = 0, -+ .product_id = 0x67, -+ .num_channels = 6, .num_leds = 0, .num_sensor_thresholds = 6, -+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, -+ .has_repeat_en = true, - }; - - static const struct cap11xx_hw_model cap1293_model = { -- .product_id = 0x6f, .num_channels = 3, .num_leds = 0, -+ .product_id = 0x6f, -+ .num_channels = 3, .num_leds = 0, .num_sensor_thresholds = 3, -+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, - .has_gain = true, -+ .has_repeat_en = true, - .has_sensitivity_control = true, - .has_signal_guard = true, - }; - - static const struct cap11xx_hw_model cap1298_model = { -- .product_id = 0x71, .num_channels = 8, .num_leds = 0, -+ .product_id = 0x71, -+ .num_channels = 8, .num_leds = 0, .num_sensor_thresholds = 8, -+ .sensor_input_reg_base = CAP11XX_REG_SENSOR_INPUT, - .has_gain = true, -+ .has_repeat_en = true, - .has_sensitivity_control = true, - .has_signal_guard = true, - }; - - static const struct of_device_id cap11xx_dt_ids[] = { - { .compatible = "microchip,cap1106", .data = &cap1106_model }, -+ { .compatible = "microchip,cap1114", .data = &cap1114_model }, - { .compatible = "microchip,cap1126", .data = &cap1126_model }, - { .compatible = "microchip,cap1188", .data = &cap1188_model }, - { .compatible = "microchip,cap1203", .data = &cap1203_model }, -@@ -652,6 +714,7 @@ MODULE_DEVICE_TABLE(of, cap11xx_dt_ids); - - static const struct i2c_device_id cap11xx_i2c_ids[] = { - { .name = "cap1106", .driver_data = (kernel_ulong_t)&cap1106_model }, -+ { .name = "cap1114", .driver_data = (kernel_ulong_t)&cap1114_model }, - { .name = "cap1126", .driver_data = (kernel_ulong_t)&cap1126_model }, - { .name = "cap1188", .driver_data = (kernel_ulong_t)&cap1188_model }, - { .name = "cap1203", .driver_data = (kernel_ulong_t)&cap1203_model }, -diff --git a/drivers/input/keyboard/charlieplex_keypad.c b/drivers/input/keyboard/charlieplex_keypad.c ---- a/drivers/input/keyboard/charlieplex_keypad.c -+++ b/drivers/input/keyboard/charlieplex_keypad.c -@@ -77,7 +77,9 @@ static int charlieplex_keypad_scan_line(struct charlieplex_keypad *keypad, - int err; - - /* Activate only one line as output at a time. */ -- gpiod_direction_output(line_gpios->desc[oline], 1); -+ err = gpiod_direction_output(line_gpios->desc[oline], 1); -+ if (err) -+ return err; - - if (keypad->settling_time_us) - fsleep(keypad->settling_time_us); -diff --git a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h -deleted file mode 100644 ---- a/drivers/input/keyboard/hpps2atkbd.h -+++ /dev/null -@@ -1,110 +0,0 @@ --/* -- * drivers/input/keyboard/hpps2atkbd.h -- * -- * Copyright (c) 2004 Helge Deller -- * Copyright (c) 2002 Laurent Canet -- * Copyright (c) 2002 Thibaut Varene -- * Copyright (c) 2000 Xavier Debacker -- * -- * HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops -- * -- * This file is subject to the terms and conditions of the GNU General Public -- * License. See the file "COPYING" in the main directory of this archive -- * for more details. -- */ -- -- --/* Is the keyboard an RDI PrecisionBook? */ --#ifndef CONFIG_KEYBOARD_ATKBD_RDI_KEYCODES --# define CONFLICT(x,y) x --#else --# define CONFLICT(x,y) y --#endif -- --/* sadly RDI (Tadpole) decided to ship a different keyboard layout -- than HP for their PS/2 laptop keyboard which leads to conflicting -- keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook. -- HP: RDI: */ --#define C_07 CONFLICT( KEY_F12, KEY_F1 ) --#define C_11 CONFLICT( KEY_LEFTALT, KEY_LEFTCTRL ) --#define C_14 CONFLICT( KEY_LEFTCTRL, KEY_CAPSLOCK ) --#define C_58 CONFLICT( KEY_CAPSLOCK, KEY_RIGHTCTRL ) --#define C_61 CONFLICT( KEY_102ND, KEY_LEFT ) -- --/* Raw SET 2 scancode table */ -- --/* 00 */ KEY_RESERVED, KEY_F9, KEY_RESERVED, KEY_F5, KEY_F3, KEY_F1, KEY_F2, C_07, --/* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2, --/* 10 */ KEY_RESERVED, C_11, KEY_LEFTSHIFT, KEY_RESERVED, C_14, KEY_Q, KEY_1, KEY_F3, --/* 18 */ KEY_RESERVED, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4, --/* 20 */ KEY_RESERVED, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5, --/* 28 */ KEY_RESERVED, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6, --/* 30 */ KEY_RESERVED, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7, --/* 38 */ KEY_RESERVED, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8, --/* 40 */ KEY_RESERVED, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9, --/* 48 */ KEY_RESERVED, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10, --/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_APOSTROPHE,KEY_RESERVED, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ, --/* 58 */ C_58, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK, --/* 60 */ KEY_DOWN, C_61, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT, --/* 68 */ KEY_RESERVED, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP, --/* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, --/* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_102ND, --/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 90 */ KEY_RESERVED, KEY_RIGHTALT, 255, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_CAPSLOCK, KEY_RESERVED, KEY_LEFTMETA, --/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTMETA, --/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_COMPOSE, --/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPSLASH, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPENTER, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* e8 */ KEY_RESERVED, KEY_END, KEY_RESERVED, KEY_LEFT, KEY_HOME, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* f0 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_RESERVED, KEY_RIGHT, KEY_UP, KEY_RESERVED, KEY_PAUSE, --/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_PAGEDOWN, KEY_RESERVED, KEY_SYSRQ, KEY_PAGEUP, KEY_RESERVED, KEY_RESERVED, -- --/* These are offset for escaped keycodes: */ -- --/* 00 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_F7, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 08 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 10 */ KEY_RESERVED, KEY_RIGHTALT, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 18 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 20 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 28 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 30 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 38 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 40 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 48 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 58 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 60 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 68 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 70 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 78 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 90 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* e8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* f0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, --/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED -- --#undef CONFLICT --#undef C_07 --#undef C_11 --#undef C_14 --#undef C_58 --#undef C_61 -- -diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c ---- a/drivers/input/keyboard/matrix_keypad.c -+++ b/drivers/input/keyboard/matrix_keypad.c -@@ -16,7 +16,6 @@ - #include - #include - #include --#include - #include - #include - #include -diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c ---- a/drivers/input/keyboard/pmic8xxx-keypad.c -+++ b/drivers/input/keyboard/pmic8xxx-keypad.c -@@ -462,15 +462,9 @@ static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp) - - static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp) - { -- int rc; -- - kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; - -- rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); -- if (rc < 0) -- return rc; -- -- return rc; -+ return regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); - } - - static int pmic8xxx_kp_open(struct input_dev *dev) -diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c ---- a/drivers/input/keyboard/samsung-keypad.c -+++ b/drivers/input/keyboard/samsung-keypad.c -@@ -142,7 +142,7 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) - unsigned int row_state[SAMSUNG_MAX_COLS]; - bool key_down; - -- pm_runtime_get_sync(&keypad->pdev->dev); -+ guard(pm_runtime_active)(&keypad->pdev->dev); - - do { - readl(keypad->base + SAMSUNG_KEYIFSTSCLR); -@@ -158,8 +158,6 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) - - } while (key_down && !keypad->stopped); - -- pm_runtime_put(&keypad->pdev->dev); -- - return IRQ_HANDLED; - } - -@@ -167,7 +165,7 @@ static void samsung_keypad_start(struct samsung_keypad *keypad) - { - unsigned int val; - -- pm_runtime_get_sync(&keypad->pdev->dev); -+ guard(pm_runtime_active)(&keypad->pdev->dev); - - /* Tell IRQ thread that it may poll the device. */ - keypad->stopped = false; -@@ -182,14 +180,14 @@ static void samsung_keypad_start(struct samsung_keypad *keypad) - /* KEYIFCOL reg clear. */ - writel(0, keypad->base + SAMSUNG_KEYIFCOL); - -- pm_runtime_put(&keypad->pdev->dev); -+ enable_irq(keypad->irq); - } - - static void samsung_keypad_stop(struct samsung_keypad *keypad) - { - unsigned int val; - -- pm_runtime_get_sync(&keypad->pdev->dev); -+ guard(pm_runtime_active)(&keypad->pdev->dev); - - /* Signal IRQ thread to stop polling and disable the handler. */ - keypad->stopped = true; -@@ -205,14 +203,6 @@ static void samsung_keypad_stop(struct samsung_keypad *keypad) - writel(val, keypad->base + SAMSUNG_KEYIFCON); - - clk_disable(keypad->clk); -- -- /* -- * Now that chip should not generate interrupts we can safely -- * re-enable the handler. -- */ -- enable_irq(keypad->irq); -- -- pm_runtime_put(&keypad->pdev->dev); - } - - static int samsung_keypad_open(struct input_dev *input_dev) -@@ -412,7 +402,8 @@ static int samsung_keypad_probe(struct platform_device *pdev) - } - - error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL, -- samsung_keypad_irq, IRQF_ONESHOT, -+ samsung_keypad_irq, -+ IRQF_ONESHOT | IRQF_NO_AUTOEN, - dev_name(&pdev->dev), keypad); - if (error) { - dev_err(&pdev->dev, "failed to register keypad interrupt\n"); -@@ -492,15 +483,17 @@ static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, - - val = readl(keypad->base + SAMSUNG_KEYIFCON); - if (enable) { -+ enable_irq_wake(keypad->irq); - val |= SAMSUNG_KEYIFCON_WAKEUPEN; -- if (device_may_wakeup(&keypad->pdev->dev)) -- enable_irq_wake(keypad->irq); -+ writel(val, keypad->base + SAMSUNG_KEYIFCON); - } else { - val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; -- if (device_may_wakeup(&keypad->pdev->dev)) -- disable_irq_wake(keypad->irq); -+ writel(val, keypad->base + SAMSUNG_KEYIFCON); -+ disable_irq_wake(keypad->irq); -+ -+ if (!input_device_enabled(keypad->input_dev)) -+ writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); - } -- writel(val, keypad->base + SAMSUNG_KEYIFCON); - - clk_disable(keypad->clk); - } -@@ -516,7 +509,8 @@ static int samsung_keypad_suspend(struct device *dev) - if (input_device_enabled(input_dev)) - samsung_keypad_stop(keypad); - -- samsung_keypad_toggle_wakeup(keypad, true); -+ if (device_may_wakeup(dev)) -+ samsung_keypad_toggle_wakeup(keypad, true); - - return 0; - } -@@ -529,7 +523,8 @@ static int samsung_keypad_resume(struct device *dev) - - guard(mutex)(&input_dev->mutex); - -- samsung_keypad_toggle_wakeup(keypad, false); -+ if (device_may_wakeup(dev)) -+ samsung_keypad_toggle_wakeup(keypad, false); - - if (input_device_enabled(input_dev)) - samsung_keypad_start(keypad); -diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c ---- a/drivers/input/keyboard/snvs_pwrkey.c -+++ b/drivers/input/keyboard/snvs_pwrkey.c -@@ -39,6 +39,9 @@ struct pwrkey_drv_data { - int keycode; - int keystate; /* 1:pressed */ - int wakeup; -+ bool suspended; /* Track suspend state */ -+ bool pending_press; /* Key pressed during suspend, report from timer callback */ -+ spinlock_t lock; /* Protects keystate, suspended and pending_press */ - struct timer_list check_timer; - struct input_dev *input; - u8 minor_rev; -@@ -49,14 +52,38 @@ static void imx_imx_snvs_check_for_events(struct timer_list *t) - struct pwrkey_drv_data *pdata = timer_container_of(pdata, t, - check_timer); - struct input_dev *input = pdata->input; -+ bool state_changed = false; -+ bool pending_press; - u32 state; - - regmap_read(pdata->snvs, SNVS_HPSR_REG, &state); - state = state & SNVS_HPSR_BTN ? 1 : 0; - -- /* only report new event if status changed */ -- if (state ^ pdata->keystate) { -- pdata->keystate = state; -+ scoped_guard(spinlock_irqsave, &pdata->lock) { -+ pending_press = pdata->pending_press; -+ if (pending_press) { -+ pdata->pending_press = false; -+ pdata->keystate = 1; -+ } -+ /* only report new event if status changed */ -+ if (state ^ pdata->keystate) { -+ pdata->keystate = state; -+ state_changed = true; -+ } -+ } -+ -+ /* -+ * Report a press event latched during suspend. If the key is still -+ * held, state_changed will be 0 (keystate already set to 1 above), -+ * so no duplicate press is reported. If already released, -+ * state_changed will fire next to report the release. -+ */ -+ if (pending_press) { -+ input_report_key(input, pdata->keycode, 1); -+ input_sync(input); -+ } -+ -+ if (state_changed) { - input_event(input, EV_KEY, pdata->keycode, state); - input_sync(input); - pm_relax(pdata->input->dev.parent); -@@ -92,8 +119,17 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) - input_sync(input); - pm_relax(input->dev.parent); - } else { -+ /* -+ * If the key is pressed during suspend, latch it so -+ * the timer callback can report the press event in -+ * softirq context, avoiding out-of-order events. -+ */ -+ scoped_guard(spinlock_irqsave, &pdata->lock) { -+ if (pdata->suspended) -+ pdata->pending_press = true; -+ } - mod_timer(&pdata->check_timer, -- jiffies + msecs_to_jiffies(DEBOUNCE_TIME)); -+ jiffies + msecs_to_jiffies(DEBOUNCE_TIME)); - } - } - -@@ -112,6 +148,7 @@ static void imx_snvs_pwrkey_act(void *pdata) - - static int imx_snvs_pwrkey_probe(struct platform_device *pdev) - { -+ struct device *dev = &pdev->dev; - struct pwrkey_drv_data *pdata; - struct input_dev *input; - struct device_node *np; -@@ -122,37 +159,35 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) - u32 vid; - - /* Get SNVS register Page */ -- np = pdev->dev.of_node; -+ np = dev->of_node; - if (!np) -- return -ENODEV; -+ return dev_err_probe(dev, -ENODEV, "Device tree node not found\n"); - -- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); -+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap"); -- if (IS_ERR(pdata->snvs)) { -- dev_err(&pdev->dev, "Can't get snvs syscon\n"); -- return PTR_ERR(pdata->snvs); -- } -+ if (IS_ERR(pdata->snvs)) -+ return dev_err_probe(dev, PTR_ERR(pdata->snvs), "Can't get snvs syscon\n"); - - if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) { - pdata->keycode = KEY_POWER; -- dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); -+ dev_warn(dev, "KEY_POWER without setting in dts\n"); - } - -- clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); -- if (IS_ERR(clk)) { -- dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk); -- return PTR_ERR(clk); -- } -+ clk = devm_clk_get_optional_enabled(dev, NULL); -+ if (IS_ERR(clk)) -+ return dev_err_probe(dev, PTR_ERR(clk), -+ "Failed to get snvs clock (%pe)\n", clk); - - pdata->wakeup = of_property_read_bool(np, "wakeup-source"); - - pdata->irq = platform_get_irq(pdev, 0); - if (pdata->irq < 0) -- return -EINVAL; -+ return pdata->irq; - -+ spin_lock_init(&pdata->lock); - error = of_property_read_u32(np, "power-off-time-sec", &val); - if (!error) { - switch (val) { -@@ -165,9 +200,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) - bpt = (val / 5) - 1; - break; - default: -- dev_err(&pdev->dev, -- "power-off-time-sec %d out of range\n", val); -- return -EINVAL; -+ return dev_err_probe(dev, -EINVAL, -+ "power-off-time-sec %d out of range\n", val); - } - - regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_BPT_MASK, -@@ -184,11 +218,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) - - timer_setup(&pdata->check_timer, imx_imx_snvs_check_for_events, 0); - -- input = devm_input_allocate_device(&pdev->dev); -- if (!input) { -- dev_err(&pdev->dev, "failed to allocate the input device\n"); -- return -ENOMEM; -- } -+ input = devm_input_allocate_device(dev); -+ if (!input) -+ return dev_err_probe(dev, -ENOMEM, "failed to allocate the input device\n"); - - input->name = pdev->name; - input->phys = "snvs-pwrkey/input0"; -@@ -197,37 +229,57 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) - input_set_capability(input, EV_KEY, pdata->keycode); - - /* input customer action to cancel release timer */ -- error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata); -- if (error) { -- dev_err(&pdev->dev, "failed to register remove action\n"); -- return error; -- } -+ error = devm_add_action(dev, imx_snvs_pwrkey_act, pdata); -+ if (error) -+ return dev_err_probe(dev, error, "failed to register remove action\n"); - - pdata->input = input; - platform_set_drvdata(pdev, pdata); - -- error = devm_request_irq(&pdev->dev, pdata->irq, -- imx_snvs_pwrkey_interrupt, -- 0, pdev->name, pdev); -- if (error) { -- dev_err(&pdev->dev, "interrupt not available.\n"); -- return error; -- } -+ error = devm_request_irq(dev, pdata->irq, -+ imx_snvs_pwrkey_interrupt, -+ 0, pdev->name, pdev); -+ if (error) -+ return dev_err_probe(dev, error, "interrupt not available.\n"); - - error = input_register_device(input); -- if (error < 0) { -- dev_err(&pdev->dev, "failed to register input device\n"); -- return error; -- } -+ if (error < 0) -+ return dev_err_probe(dev, error, "failed to register input device\n"); - -- device_init_wakeup(&pdev->dev, pdata->wakeup); -- error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq); -+ device_init_wakeup(dev, pdata->wakeup); -+ error = dev_pm_set_wake_irq(dev, pdata->irq); - if (error) -- dev_err(&pdev->dev, "irq wake enable failed.\n"); -+ dev_err(dev, "irq wake enable failed.\n"); - - return 0; - } - -+static int imx_snvs_pwrkey_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); -+ -+ guard(spinlock_irq)(&pdata->lock); -+ pdata->suspended = true; -+ -+ return 0; -+} -+ -+static int imx_snvs_pwrkey_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); -+ -+ guard(spinlock_irq)(&pdata->lock); -+ pdata->suspended = false; -+ -+ return 0; -+} -+ -+static DEFINE_SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, -+ imx_snvs_pwrkey_suspend, -+ imx_snvs_pwrkey_resume); -+ - static const struct of_device_id imx_snvs_pwrkey_ids[] = { - { .compatible = "fsl,sec-v4.0-pwrkey" }, - { /* sentinel */ } -@@ -238,6 +290,7 @@ static struct platform_driver imx_snvs_pwrkey_driver = { - .driver = { - .name = "snvs_pwrkey", - .of_match_table = imx_snvs_pwrkey_ids, -+ .pm = pm_ptr(&imx_snvs_pwrkey_pm_ops), - }, - .probe = imx_snvs_pwrkey_probe, - }; -diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c ---- a/drivers/input/keyboard/tca8418_keypad.c -+++ b/drivers/input/keyboard/tca8418_keypad.c -@@ -254,7 +254,8 @@ static int tca8418_configure(struct tca8418_keypad *keypad_data, - return error; - - error = tca8418_write_byte(keypad_data, REG_CFG, -- CFG_INT_CFG | CFG_OVR_FLOW_IEN | CFG_KE_IEN); -+ CFG_INT_CFG | CFG_OVR_FLOW_IEN | -+ CFG_OVR_FLOW_M | CFG_KE_IEN); - - return error; - } -diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig ---- a/drivers/input/misc/Kconfig -+++ b/drivers/input/misc/Kconfig -@@ -842,6 +842,18 @@ config INPUT_IQS7222 - To compile this driver as a module, choose M here: the - module will be called iqs7222. - -+config INPUT_ISA1200_HAPTIC -+ tristate "Imagis ISA1200 haptic feedback unit" -+ depends on I2C -+ select INPUT_FF_MEMLESS -+ select REGMAP_I2C -+ help -+ Say Y to enable support for the Imagis ISA1200 haptic -+ feedback unit. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called isa1200. -+ - config INPUT_CMA3000 - tristate "VTI CMA3000 Tri-axis accelerometer" - help -diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile ---- a/drivers/input/misc/Makefile -+++ b/drivers/input/misc/Makefile -@@ -49,6 +49,7 @@ obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o - obj-$(CONFIG_INPUT_IQS269A) += iqs269a.o - obj-$(CONFIG_INPUT_IQS626A) += iqs626a.o - obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o -+obj-$(CONFIG_INPUT_ISA1200_HAPTIC) += isa1200.o - obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o - obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o - obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o -diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c ---- a/drivers/input/misc/ims-pcu.c -+++ b/drivers/input/misc/ims-pcu.c -@@ -2234,6 +2234,7 @@ static const struct usb_device_id ims_pcu_id_table[] = { - }, - { } - }; -+MODULE_DEVICE_TABLE(usb, ims_pcu_id_table); - - static const struct attribute_group *ims_pcu_sysfs_groups[] = { - &ims_pcu_attr_group, -diff --git a/drivers/input/misc/isa1200.c b/drivers/input/misc/isa1200.c -new file mode 100644 ---- /dev/null -+++ b/drivers/input/misc/isa1200.c -@@ -0,0 +1,533 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * System control (LDO regulator) -+ * -+ * LDO voltage to register mapping is linear, but it is split in two parts: -+ * 2.3V - 3.0V map to 0x08 - 0x0f; 3.1V - 3.8V map to 0x00 - 0x7 -+ */ -+ -+#define ISA1200_SCTRL 0x00 -+#define ISA1200_LDO_VOLTAGE_BASE 0x08 -+#define ISA1200_LDO_VOLTAGE_STEP 100000 -+#define ISA1200_LDO_VOLTAGE_2V3 23 -+#define ISA1200_LDO_VOLTAGE_3V1 31 -+#define ISA1200_LDO_VOLTAGE_MIN 2300000 -+#define ISA1200_LDO_VOLTAGE_MAX 3800000 -+ -+/* -+ * The output frequency is calculated with this formula: -+ * -+ * base clock frequency -+ * fout = ----------------------------------------- -+ * (128 - PWM_FREQ) * 2 * PLLDIV * PWM_PERIOD -+ * -+ * The base clock frequency is the clock frequency provided on the -+ * clock input to the chip, divided by the value in HCTRL0 -+ * -+ * PWM_FREQ is configured in register HCTRL4, it is common to set this -+ * to 0 to get only two variables to calculate. -+ * -+ * PLLDIV is configured in register HCTRL3 (bits 7..4, so 0..15) -+ * PWM_PERIOD is configured in register HCTRL6 -+ * Further the duty cycle can be configured in HCTRL5 -+ */ -+ -+/* -+ * HCTRL0 configures clock or PWM input and selects the divider for -+ * the clock input. -+ */ -+#define ISA1200_HCTRL0 0x30 -+#define ISA1200_HCTRL0_HAP_ENABLE BIT(7) -+#define ISA1200_HCTRL0_PWM_GEN_MODE BIT(4) -+#define ISA1200_HCTRL0_PWM_INPUT_MODE BIT(3) -+#define ISA1200_HCTRL0_CLKDIV_128 128 -+ -+/* -+ * HCTRL1 configures the motor type and clock sourse -+ */ -+#define ISA1200_HCTRL1 0x31 -+#define ISA1200_HCTRL1_EXT_CLOCK BIT(7) -+#define ISA1200_HCTRL1_DAC_INVERT BIT(6) -+#define ISA1200_HCTRL1_MODE(n) (((n) & 1) << 5) -+ -+/* HCTRL2 controls software reset of the chip */ -+#define ISA1200_HCTRL2 0x32 -+#define ISA1200_HCTRL2_SW_RESET BIT(0) -+ -+/* -+ * HCTRL3 controls the PLL divisor -+ * -+ * Bits [0,1] are always set to 1 (we don't know what they are -+ * used for) and bit 4 and upward control the PLL divisor. -+ */ -+#define ISA1200_HCTRL3 0x33 -+#define ISA1200_HCTRL3_DEFAULT 0x03 -+#define ISA1200_HCTRL3_PLLDIV(n) (((n) & 0xf) << 4) -+ -+/* HCTRL4 controls the PWM frequency of external channel */ -+#define ISA1200_HCTRL4 0x34 -+ -+/* HCTRL5 controls the PWM high duty cycle of internal channel */ -+#define ISA1200_HCTRL5 0x35 -+ -+/* HCTRL6 controls the PWM period of internal channel */ -+#define ISA1200_HCTRL6 0x36 -+#define ISA1200_HCTRL6_PERIOD_SCALE 100 -+ -+/* The use for these registers is unknown but they exist */ -+#define ISA1200_HCTRL7 0x37 -+#define ISA1200_HCTRL8 0x38 -+#define ISA1200_HCTRL9 0x39 -+#define ISA1200_HCTRLA 0x3a -+#define ISA1200_HCTRLB 0x3b -+#define ISA1200_HCTRLC 0x3c -+#define ISA1200_HCTRLD 0x3d -+ -+#define ISA1200_EN_PINS_MAX 2 -+ -+static const struct regulator_bulk_data isa1200_supplies[] = { -+ { .supply = "vdd" }, { .supply = "vddp" }, -+}; -+ -+struct isa1200_config { -+ u32 ldo_voltage; -+ u32 mode; -+ u32 clkdiv; -+ u32 plldiv; -+ u32 freq; -+ u32 period; -+ u32 duty; -+}; -+ -+struct isa1200 { -+ struct input_dev *input; -+ struct regmap *map; -+ -+ struct clk *clk; -+ struct pwm_device *pwm; -+ struct gpio_descs *enable_gpios; -+ struct regulator_bulk_data *supplies; -+ -+ struct work_struct play_work; -+ struct isa1200_config config; -+ -+ int level; -+ bool suspended; -+ bool active; -+}; -+ -+static const struct regmap_config isa1200_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = ISA1200_HCTRLD, -+}; -+ -+static void isa1200_start(struct isa1200 *isa) -+{ -+ struct isa1200_config *config = &isa->config; -+ struct device *dev = &isa->input->dev; -+ struct pwm_state state; -+ u8 hctrl0 = 0, hctrl1 = 0; -+ DECLARE_BITMAP(values, ISA1200_EN_PINS_MAX); -+ int err; -+ -+ if (!isa->active) { -+ err = regulator_bulk_enable(ARRAY_SIZE(isa1200_supplies), -+ isa->supplies); -+ if (err) { -+ dev_err(dev, "failed to enable supplies (%d)\n", err); -+ return; -+ } -+ -+ err = clk_prepare_enable(isa->clk); -+ if (err) { -+ dev_err(dev, "failed to enable clock (%d)\n", err); -+ regulator_bulk_disable(ARRAY_SIZE(isa1200_supplies), -+ isa->supplies); -+ return; -+ } -+ -+ bitmap_fill(values, ISA1200_EN_PINS_MAX); -+ gpiod_multi_set_value_cansleep(isa->enable_gpios, values); -+ -+ usleep_range(200, 300); -+ } -+ -+ regmap_write(isa->map, ISA1200_SCTRL, config->ldo_voltage); -+ -+ if (isa->clk) { -+ hctrl0 = ISA1200_HCTRL0_PWM_GEN_MODE; -+ hctrl1 = ISA1200_HCTRL1_EXT_CLOCK; -+ } -+ -+ if (isa->pwm) { -+ hctrl0 = ISA1200_HCTRL0_PWM_INPUT_MODE; -+ hctrl1 = 0; -+ } -+ -+ hctrl0 |= __ffs(config->clkdiv / ISA1200_HCTRL0_CLKDIV_128); -+ hctrl1 |= ISA1200_HCTRL1_DAC_INVERT; -+ hctrl1 |= ISA1200_HCTRL1_MODE(config->mode); -+ -+ regmap_write(isa->map, ISA1200_HCTRL0, hctrl0); -+ regmap_write(isa->map, ISA1200_HCTRL1, hctrl1); -+ -+ /* Make sure to de-assert software reset */ -+ regmap_write(isa->map, ISA1200_HCTRL2, 0x00); -+ -+ /* PLL divisor */ -+ regmap_write(isa->map, ISA1200_HCTRL3, -+ ISA1200_HCTRL3_PLLDIV(config->plldiv) | -+ ISA1200_HCTRL3_DEFAULT); -+ -+ /* Frequency */ -+ regmap_write(isa->map, ISA1200_HCTRL4, config->freq); -+ /* Duty cycle */ -+ regmap_write(isa->map, ISA1200_HCTRL5, config->period >> 1); -+ /* Period */ -+ regmap_write(isa->map, ISA1200_HCTRL6, config->period); -+ -+ hctrl0 |= ISA1200_HCTRL0_HAP_ENABLE; -+ regmap_write(isa->map, ISA1200_HCTRL0, hctrl0); -+ -+ if (isa->clk) -+ regmap_write(isa->map, ISA1200_HCTRL5, config->duty); -+ -+ if (isa->pwm) { -+ pwm_get_state(isa->pwm, &state); -+ state.duty_cycle = config->duty; -+ state.enabled = true; -+ pwm_apply_might_sleep(isa->pwm, &state); -+ } -+ -+ isa->active = true; -+} -+ -+static void isa1200_stop(struct isa1200 *isa) -+{ -+ struct pwm_state state; -+ DECLARE_BITMAP(values, ISA1200_EN_PINS_MAX); -+ -+ if (!isa->active) -+ return; -+ -+ if (isa->pwm) { -+ pwm_get_state(isa->pwm, &state); -+ state.duty_cycle = 0; -+ state.enabled = false; -+ pwm_apply_might_sleep(isa->pwm, &state); -+ } -+ -+ regmap_write(isa->map, ISA1200_HCTRL0, 0x00); -+ -+ bitmap_zero(values, ISA1200_EN_PINS_MAX); -+ gpiod_multi_set_value_cansleep(isa->enable_gpios, values); -+ -+ clk_disable_unprepare(isa->clk); -+ regulator_bulk_disable(ARRAY_SIZE(isa1200_supplies), -+ isa->supplies); -+ -+ isa->active = false; -+} -+ -+static void isa1200_play_work(struct work_struct *work) -+{ -+ struct isa1200 *isa = container_of(work, struct isa1200, play_work); -+ -+ if (!READ_ONCE(isa->suspended)) { -+ if (isa->level) -+ isa1200_start(isa); -+ else -+ isa1200_stop(isa); -+ } -+} -+ -+static int isa1200_vibrator_play_effect(struct input_dev *input, void *data, -+ struct ff_effect *effect) -+{ -+ struct isa1200 *isa = input_get_drvdata(input); -+ int level; -+ -+ /* -+ * TODO: we currently only support rumble. -+ * The ISA1200 can control two motors and some devices -+ * also have two motors mounted. -+ */ -+ level = effect->u.rumble.strong_magnitude; -+ if (!level) -+ level = effect->u.rumble.weak_magnitude; -+ -+ dev_dbg(&input->dev, "FF effect type %d level %d\n", -+ effect->type, level); -+ -+ if (isa->level != level) { -+ isa->level = level; -+ if (!READ_ONCE(isa->suspended)) -+ schedule_work(&isa->play_work); -+ } -+ -+ return 0; -+} -+ -+static void isa1200_vibrator_close(struct input_dev *input) -+{ -+ struct isa1200 *isa = input_get_drvdata(input); -+ -+ cancel_work_sync(&isa->play_work); -+ isa1200_stop(isa); -+ isa->level = 0; -+} -+ -+static int isa1200_of_probe(struct i2c_client *client) -+{ -+ struct isa1200 *isa = i2c_get_clientdata(client); -+ struct isa1200_config *config = &isa->config; -+ struct device *dev = &client->dev; -+ struct fwnode_handle *ldo_node; -+ int err; -+ -+ isa->clk = devm_clk_get_optional(dev, NULL); -+ if (IS_ERR(isa->clk)) -+ return dev_err_probe(dev, PTR_ERR(isa->clk), -+ "failed to get clock\n"); -+ -+ isa->pwm = devm_pwm_get(dev, NULL); -+ if (IS_ERR(isa->pwm)) { -+ err = PTR_ERR(isa->pwm); -+ if (err == -ENODEV || err == -EINVAL) -+ isa->pwm = NULL; -+ else -+ return dev_err_probe(dev, err, "getting PWM\n"); -+ } -+ -+ if (!isa->clk && !isa->pwm) -+ return dev_err_probe(dev, -EINVAL, -+ "clock or PWM are required, none were provided\n"); -+ -+ err = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(isa1200_supplies), -+ isa1200_supplies, &isa->supplies); -+ if (err) -+ return dev_err_probe(dev, err, "failed to get supplies\n"); -+ -+ isa->enable_gpios = devm_gpiod_get_array_optional(dev, "control", -+ GPIOD_OUT_LOW); -+ if (IS_ERR(isa->enable_gpios)) -+ return dev_err_probe(dev, PTR_ERR(isa->enable_gpios), -+ "failed to get enable gpios\n"); -+ -+ if (isa->enable_gpios && isa->enable_gpios->ndescs > ISA1200_EN_PINS_MAX) -+ return dev_err_probe(dev, -EINVAL, "too many enable gpios\n"); -+ -+ ldo_node = device_get_named_child_node(dev, "ldo"); -+ if (!ldo_node) -+ return dev_err_probe(dev, -ENODEV, -+ "failed to get embedded LDO node\n"); -+ -+ err = fwnode_property_read_u32(ldo_node, "regulator-min-microvolt", -+ &config->ldo_voltage); -+ fwnode_handle_put(ldo_node); -+ if (err) -+ return dev_err_probe(dev, err, -+ "failed to get ldo voltage\n"); -+ -+ config->ldo_voltage = clamp(config->ldo_voltage, -+ ISA1200_LDO_VOLTAGE_MIN, -+ ISA1200_LDO_VOLTAGE_MAX); -+ -+ config->ldo_voltage /= ISA1200_LDO_VOLTAGE_STEP; -+ if (config->ldo_voltage < ISA1200_LDO_VOLTAGE_3V1) -+ config->ldo_voltage = config->ldo_voltage - -+ ISA1200_LDO_VOLTAGE_2V3 + -+ ISA1200_LDO_VOLTAGE_BASE; -+ else -+ config->ldo_voltage -= ISA1200_LDO_VOLTAGE_3V1; -+ -+ config->mode = 0; /* LRA_MODE */ -+ device_property_read_u32(dev, "imagis,mode", &config->mode); -+ -+ config->clkdiv = ISA1200_HCTRL0_CLKDIV_128; -+ device_property_read_u32(dev, "imagis,clk-div", &config->clkdiv); -+ if (!config->clkdiv) -+ return dev_err_probe(dev, -EINVAL, "clk-div cannot be zero\n"); -+ -+ config->clkdiv = clamp(config->clkdiv, ISA1200_HCTRL0_CLKDIV_128, -+ ISA1200_HCTRL0_CLKDIV_128 << 3); -+ -+ err = device_property_read_u32(dev, "imagis,pll-div", &config->plldiv); -+ if (err || !config->plldiv) -+ config->plldiv = 1; -+ -+ config->period = 0; -+ config->freq = 0; -+ config->duty = 0; -+ -+ if (isa->clk) { -+ err = device_property_read_u32(dev, "imagis,period-ns", -+ &config->period); -+ if (err) -+ return dev_err_probe(dev, err, -+ "failed to get period\n"); -+ -+ /* -+ * TODO: The scale value is arbitrary, but it fits observations -+ * quite well, and the exact conversion method is unknown. -+ * The period property value returned above is the HCTRL6 -+ * register value set by the vendor code, multiplied by 100. -+ */ -+ config->period /= ISA1200_HCTRL6_PERIOD_SCALE; -+ config->duty = config->period >> 1; -+ } -+ -+ if (isa->pwm) { -+ struct pwm_state state; -+ -+ pwm_init_state(isa->pwm, &state); -+ -+ if (!state.period) -+ return dev_err_probe(dev, -EINVAL, -+ "PWM period cannot be zero\n"); -+ -+ config->freq = div64_u64(NANO, state.period * config->clkdiv); -+ config->duty = state.period >> 1; -+ -+ err = pwm_apply_might_sleep(isa->pwm, &state); -+ if (err) -+ return dev_err_probe(dev, err, -+ "failed to apply initial PWM state\n"); -+ } -+ -+ /* -+ * TODO: If device is using a clock, this property should return the -+ * value written to the HCTRL5 register by downstrem code. It likely -+ * needs to be converted into a meaningful duty cycle value, though -+ * unfortunately the exact conversion mechanism is unknown. If the -+ * device uses PWM, this property will return the correct duty cycle -+ * in nanoseconds. -+ */ -+ device_property_read_u32(dev, "imagis,duty-cycle-ns", &config->duty); -+ -+ return 0; -+} -+ -+static int isa1200_probe(struct i2c_client *client) -+{ -+ struct isa1200 *isa; -+ struct device *dev = &client->dev; -+ int err; -+ -+ isa = devm_kzalloc(dev, sizeof(*isa), GFP_KERNEL); -+ if (!isa) -+ return -ENOMEM; -+ -+ isa->input = devm_input_allocate_device(dev); -+ if (!isa->input) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(client, isa); -+ -+ err = isa1200_of_probe(client); -+ if (err) -+ return err; -+ -+ isa->map = devm_regmap_init_i2c(client, &isa1200_regmap_config); -+ if (IS_ERR(isa->map)) -+ return dev_err_probe(dev, PTR_ERR(isa->map), -+ "failed to initialize register map\n"); -+ -+ INIT_WORK(&isa->play_work, isa1200_play_work); -+ -+ isa->input->name = "isa1200-haptic"; -+ isa->input->id.bustype = BUS_I2C; -+ isa->input->close = isa1200_vibrator_close; -+ -+ isa->active = false; -+ -+ input_set_drvdata(isa->input, isa); -+ -+ /* TODO: this hardware can likely support more than rumble */ -+ input_set_capability(isa->input, EV_FF, FF_RUMBLE); -+ -+ err = input_ff_create_memless(isa->input, NULL, -+ isa1200_vibrator_play_effect); -+ if (err) -+ return dev_err_probe(dev, err, "failed to create FF dev\n"); -+ -+ err = input_register_device(isa->input); -+ if (err) -+ return dev_err_probe(dev, err, "failed to register input dev\n"); -+ -+ return 0; -+} -+ -+static int isa1200_suspend(struct device *dev) -+{ -+ struct isa1200 *isa = dev_get_drvdata(dev); -+ -+ guard(mutex)(&isa->input->mutex); -+ -+ if (input_device_enabled(isa->input)) { -+ WRITE_ONCE(isa->suspended, true); -+ cancel_work_sync(&isa->play_work); -+ isa1200_stop(isa); -+ } -+ -+ return 0; -+} -+ -+static int isa1200_resume(struct device *dev) -+{ -+ struct isa1200 *isa = dev_get_drvdata(dev); -+ -+ guard(mutex)(&isa->input->mutex); -+ -+ if (input_device_enabled(isa->input)) { -+ WRITE_ONCE(isa->suspended, false); -+ if (isa->level) -+ schedule_work(&isa->play_work); -+ } -+ -+ return 0; -+} -+ -+static DEFINE_SIMPLE_DEV_PM_OPS(isa1200_pm_ops, isa1200_suspend, isa1200_resume); -+ -+static const struct of_device_id isa1200_of_match[] = { -+ { .compatible = "imagis,isa1200" }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, isa1200_of_match); -+ -+static struct i2c_driver isa1200_i2c_driver = { -+ .driver = { -+ .name = "isa1200", -+ .of_match_table = isa1200_of_match, -+ .pm = pm_sleep_ptr(&isa1200_pm_ops), -+ }, -+ .probe = isa1200_probe, -+}; -+module_i2c_driver(isa1200_i2c_driver); -+ -+MODULE_AUTHOR("Linus Walleij "); -+MODULE_AUTHOR("Svyatoslav Ryhel "); -+MODULE_DESCRIPTION("Imagis ISA1200 haptic feedback unit"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h ---- a/drivers/input/mouse/elan_i2c.h -+++ b/drivers/input/mouse/elan_i2c.h -@@ -102,7 +102,8 @@ struct elan_transport_ops { - int (*prepare_fw_update)(struct i2c_client *client, u16 ic_type, - u8 iap_version, u16 fw_page_size); - int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size, -- const u8 *page, u16 checksum, int idx); -+ u16 fw_page_delay, const u8 *page, u16 checksum, -+ int idx); - int (*finish_fw_update)(struct i2c_client *client, - struct completion *reset_done); - -diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c ---- a/drivers/input/mouse/elan_i2c_core.c -+++ b/drivers/input/mouse/elan_i2c_core.c -@@ -16,27 +16,27 @@ - */ - - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - #include - #include --#include --#include --#include --#include --#include --#include --#include - #include --#include -+#include -+#include - #include - #include - #include - #include -+#include -+#include -+#include -+#include - #include - - #include "elan_i2c.h" -@@ -86,6 +86,7 @@ struct elan_tp_data { - u16 ic_type; - u16 fw_validpage_count; - u16 fw_page_size; -+ u16 fw_page_delay; - u32 fw_signature_address; - - u8 min_baseline; -@@ -127,8 +128,11 @@ static u32 elan_i2c_lookup_quirks(u16 ic_type, u16 product_id) - } - - static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, -- u32 *signature_address, u16 *page_size) -+ u32 *signature_address, u16 *page_size, -+ u16 *page_delay) - { -+ *page_delay = 30; -+ - switch (ic_type) { - case 0x00: - case 0x06: -@@ -164,6 +168,7 @@ static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, - break; - case 0x19: - *validpage_count = 2032; -+ *page_delay = 10; - break; - default: - /* unknown ic type clear value */ -@@ -179,6 +184,7 @@ static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, - if ((ic_type == 0x14 || ic_type == 0x15) && iap_version >= 2) { - *validpage_count /= 8; - *page_size = ETP_FW_PAGE_SIZE_512; -+ *page_delay = 50; - } else if (ic_type >= 0x0D && iap_version >= 1) { - *validpage_count /= 2; - *page_size = ETP_FW_PAGE_SIZE_128; -@@ -368,7 +374,8 @@ static int elan_query_device_info(struct elan_tp_data *data) - error = elan_get_fwinfo(data->ic_type, data->iap_version, - &data->fw_validpage_count, - &data->fw_signature_address, -- &data->fw_page_size); -+ &data->fw_page_size, -+ &data->fw_page_delay); - if (error) - dev_warn(&data->client->dev, - "unexpected iap version %#04x (ic type: %#04x), firmware update will not work\n", -@@ -479,14 +486,16 @@ static int elan_query_device_parameters(struct elan_tp_data *data) - ********************************************************** - */ - static int elan_write_fw_block(struct elan_tp_data *data, u16 page_size, -- const u8 *page, u16 checksum, int idx) -+ u16 page_delay, const u8 *page, u16 checksum, -+ int idx) - { - int retry = ETP_RETRY_COUNT; - int error; - - do { - error = data->ops->write_fw_block(data->client, page_size, -- page, checksum, idx); -+ page_delay, page, checksum, -+ idx); - if (!error) - return 0; - -@@ -525,7 +534,8 @@ static int __elan_update_firmware(struct elan_tp_data *data, - checksum += ((page[j + 1] << 8) | page[j]); - - error = elan_write_fw_block(data, data->fw_page_size, -- page, checksum, i); -+ data->fw_page_delay, page, checksum, -+ i); - if (error) { - dev_err(dev, "write page %d fail: %d\n", i, error); - return error; -diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c ---- a/drivers/input/mouse/elan_i2c_i2c.c -+++ b/drivers/input/mouse/elan_i2c_i2c.c -@@ -625,7 +625,8 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type, - } - - static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, -- const u8 *page, u16 checksum, int idx) -+ u16 fw_page_delay, const u8 *page, u16 checksum, -+ int idx) - { - struct device *dev = &client->dev; - u8 val[3]; -@@ -650,7 +651,7 @@ static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, - } - - /* Wait for F/W to update one page ROM data. */ -- msleep(fw_page_size == ETP_FW_PAGE_SIZE_512 ? 50 : 35); -+ msleep(fw_page_delay); - - error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); - if (error) { -diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c ---- a/drivers/input/mouse/elan_i2c_smbus.c -+++ b/drivers/input/mouse/elan_i2c_smbus.c -@@ -416,7 +416,8 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client, u16 ic_type, - - - static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size, -- const u8 *page, u16 checksum, int idx) -+ u16 fw_page_delay, const u8 *page, u16 checksum, -+ int idx) - { - struct device *dev = &client->dev; - int error; -diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c ---- a/drivers/input/mouse/focaltech.c -+++ b/drivers/input/mouse/focaltech.c -@@ -78,8 +78,8 @@ struct focaltech_finger_state { - * Absolute position (from the bottom left corner) of the - * finger. - */ -- unsigned int x; -- unsigned int y; -+ int x; -+ int y; - }; - - /* -@@ -108,7 +108,7 @@ struct focaltech_hw_state { - }; - - struct focaltech_data { -- unsigned int x_max, y_max; -+ int x_max, y_max; - struct focaltech_hw_state state; - }; - -@@ -126,17 +126,16 @@ static void focaltech_report_state(struct psmouse *psmouse) - input_mt_slot(dev, i); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); - if (active) { -- unsigned int clamped_x, clamped_y; - /* - * The touchpad might report invalid data, so we clamp - * the resulting values so that we do not confuse -- * userspace. -+ * userspace or accumulate coordinate wind-up. - */ -- clamped_x = clamp(finger->x, 0U, priv->x_max); -- clamped_y = clamp(finger->y, 0U, priv->y_max); -- input_report_abs(dev, ABS_MT_POSITION_X, clamped_x); -+ finger->x = clamp(finger->x, 0, priv->x_max); -+ finger->y = clamp(finger->y, 0, priv->y_max); -+ input_report_abs(dev, ABS_MT_POSITION_X, finger->x); - input_report_abs(dev, ABS_MT_POSITION_Y, -- priv->y_max - clamped_y); -+ priv->y_max - finger->y); - input_report_abs(dev, ABS_TOOL_WIDTH, state->width); - } - } -diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c ---- a/drivers/input/mouse/psmouse-base.c -+++ b/drivers/input/mouse/psmouse-base.c -@@ -256,9 +256,8 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta - */ - void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) - { -- serio_pause_rx(psmouse->ps2dev.serio); -+ guard(serio_pause_rx)(psmouse->ps2dev.serio); - __psmouse_set_state(psmouse, new_state); -- serio_continue_rx(psmouse->ps2dev.serio); - } - - /* -@@ -267,7 +266,15 @@ void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) - */ - static int psmouse_handle_byte(struct psmouse *psmouse) - { -- psmouse_ret_t rc = psmouse->protocol_handler(psmouse); -+ psmouse_ret_t rc; -+ -+ /* protocol_handler is NULL when device is being disconnected */ -+ if (unlikely(!psmouse->protocol_handler)) { -+ psmouse->pktcnt = 0; -+ return 0; -+ } -+ -+ rc = psmouse->protocol_handler(psmouse); - - switch (rc) { - case PSMOUSE_BAD_DATA: -@@ -484,13 +491,16 @@ static int psmouse_poll(struct psmouse *psmouse) - PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); - } - --static bool psmouse_check_pnp_id(const char *id, const char * const ids[]) -+static bool psmouse_check_pnp_id(const char *p, const char * const ids[]) - { -- int i; -+ const char * const *id; -+ size_t len; - -- for (i = 0; ids[i]; i++) -- if (!strcasecmp(id, ids[i])) -+ for (id = ids; *id; id++) { -+ len = strlen(*id); -+ if (!strncasecmp(p, *id, len) && (p[len] == ' ' || p[len] == '\0')) - return true; -+ } - - return false; - } -@@ -501,28 +511,26 @@ static bool psmouse_check_pnp_id(const char *id, const char * const ids[]) - bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) - { - struct serio *serio = psmouse->ps2dev.serio; -- char *p, *fw_id_copy, *save_ptr; -- bool found = false; -+ const char *p = serio->firmware_id; - -- if (strncmp(serio->firmware_id, "PNP: ", 5)) -+ if (!strstarts(p, "PNP: ")) - return false; - -- fw_id_copy = kstrndup(&serio->firmware_id[5], -- sizeof(serio->firmware_id) - 5, -- GFP_KERNEL); -- if (!fw_id_copy) -- return false; -+ p += 5; -+ while (*p) { -+ p = skip_spaces(p); -+ if (!*p) -+ break; - -- save_ptr = fw_id_copy; -- while ((p = strsep(&fw_id_copy, " ")) != NULL) { -- if (psmouse_check_pnp_id(p, ids)) { -- found = true; -+ if (psmouse_check_pnp_id(p, ids)) -+ return true; -+ -+ p = strchr(p, ' '); -+ if (!p) - break; -- } - } - -- kfree(save_ptr); -- return found; -+ return false; - } - - /* -@@ -1311,10 +1319,10 @@ static void psmouse_resync(struct work_struct *work) - bool failed = false, enabled = false; - int i; - -- mutex_lock(&psmouse_mutex); -+ guard(mutex)(&psmouse_mutex); - - if (psmouse->state != PSMOUSE_RESYNCING) -- goto out; -+ return; - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = psmouse_from_serio(serio->parent); -@@ -1392,8 +1400,6 @@ static void psmouse_resync(struct work_struct *work) - - if (parent) - psmouse_activate(parent); -- out: -- mutex_unlock(&psmouse_mutex); - } - - /* -@@ -1404,7 +1410,7 @@ static void psmouse_cleanup(struct serio *serio) - struct psmouse *psmouse = psmouse_from_serio(serio); - struct psmouse *parent = NULL; - -- mutex_lock(&psmouse_mutex); -+ guard(mutex)(&psmouse_mutex); - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = psmouse_from_serio(serio->parent); -@@ -1440,8 +1446,6 @@ static void psmouse_cleanup(struct serio *serio) - - psmouse_activate(parent); - } -- -- mutex_unlock(&psmouse_mutex); - } - - /* -@@ -1452,20 +1456,20 @@ static void psmouse_disconnect(struct serio *serio) - struct psmouse *psmouse = psmouse_from_serio(serio); - struct psmouse *parent = NULL; - -- mutex_lock(&psmouse_mutex); -+ disable_work_sync(&psmouse->resync_work); -+ -+ guard(mutex)(&psmouse_mutex); - - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - -- /* make sure we don't have a resync in progress */ -- mutex_unlock(&psmouse_mutex); -- disable_work_sync(&psmouse->resync_work); -- mutex_lock(&psmouse_mutex); -- - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = psmouse_from_serio(serio->parent); - psmouse_deactivate(parent); - } - -+ scoped_guard(serio_pause_rx, serio) -+ psmouse->protocol_handler = NULL; -+ - if (psmouse->disconnect) - psmouse->disconnect(psmouse); - -@@ -1484,8 +1488,6 @@ static void psmouse_disconnect(struct serio *serio) - - if (parent) - psmouse_activate(parent); -- -- mutex_unlock(&psmouse_mutex); - } - - static int psmouse_switch_protocol(struct psmouse *psmouse, -@@ -1654,14 +1656,12 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) - enum psmouse_type type; - int rc = -1; - -- mutex_lock(&psmouse_mutex); -+ lockdep_assert_held(&psmouse_mutex); - - if (fast_reconnect) { - reconnect_handler = psmouse->fast_reconnect; -- if (!reconnect_handler) { -- rc = -ENOENT; -- goto out_unlock; -- } -+ if (!reconnect_handler) -+ return -ENOENT; - } else { - reconnect_handler = psmouse->reconnect; - } -@@ -1713,18 +1713,20 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) - if (parent) - psmouse_activate(parent); - --out_unlock: -- mutex_unlock(&psmouse_mutex); - return rc; - } - - static int psmouse_reconnect(struct serio *serio) - { -+ guard(mutex)(&psmouse_mutex); -+ - return __psmouse_reconnect(serio, false); - } - - static int psmouse_fast_reconnect(struct serio *serio) - { -+ guard(mutex)(&psmouse_mutex); -+ - return __psmouse_reconnect(serio, true); - } - -diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c ---- a/drivers/input/mouse/synaptics.c -+++ b/drivers/input/mouse/synaptics.c -@@ -164,6 +164,7 @@ static const char * const topbuttonpad_pnp_ids[] = { - #ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS - static const char * const smbus_pnp_ids[] = { - /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ -+ "DLL0597", /* Dell Inspiron 3521 */ - "DLL060d", /* Dell Precision M3800 */ - "LEN0048", /* X1 Carbon 3 */ - "LEN0046", /* X250 */ -diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c ---- a/drivers/input/mouse/synaptics_i2c.c -+++ b/drivers/input/mouse/synaptics_i2c.c -@@ -261,7 +261,7 @@ static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val) - if (error) - return error; - -- return error; -+ return 0; - } - - static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg) -diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c ---- a/drivers/input/rmi4/rmi_f12.c -+++ b/drivers/input/rmi4/rmi_f12.c -@@ -155,6 +155,10 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) - offset += 4; - } - -+ /* When platform data are provided, we're done */ -+ if (sensor->x_mm && sensor->y_mm) -+ return 0; -+ - /* - * Use the Query DPM feature when the resolution query register - * exists. -@@ -171,8 +175,10 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) - } - dpm_resolution = buf[0]; - -- sensor->x_mm = sensor->max_x / dpm_resolution; -- sensor->y_mm = sensor->max_y / dpm_resolution; -+ if (!sensor->x_mm) -+ sensor->x_mm = sensor->max_x / dpm_resolution; -+ if (!sensor->y_mm) -+ sensor->y_mm = sensor->max_y / dpm_resolution; - } else { - if (rmi_register_desc_has_subpacket(item, 3)) { - rx_receivers = buf[offset]; -@@ -184,8 +190,10 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) - if (rmi_register_desc_has_subpacket(item, 4)) - offset += 1; - -- sensor->x_mm = (pitch_x * rx_receivers) >> 12; -- sensor->y_mm = (pitch_y * tx_receivers) >> 12; -+ if (!sensor->x_mm) -+ sensor->x_mm = (pitch_x * rx_receivers) >> 12; -+ if (!sensor->y_mm) -+ sensor->y_mm = (pitch_y * tx_receivers) >> 12; - } - - rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x_mm: %d y_mm: %d\n", __func__, -diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c ---- a/drivers/input/rmi4/rmi_smbus.c -+++ b/drivers/input/rmi4/rmi_smbus.c -@@ -177,13 +177,8 @@ static int smb_block_read(struct rmi_transport_dev *xport, - struct rmi_smb_xport *rmi_smb = - container_of(xport, struct rmi_smb_xport, xport); - struct i2c_client *client = rmi_smb->client; -- int retval; - -- retval = i2c_smbus_read_block_data(client, commandcode, buf); -- if (retval < 0) -- return retval; -- -- return retval; -+ return i2c_smbus_read_block_data(client, commandcode, buf); - } - - static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr, -diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig ---- a/drivers/input/serio/Kconfig -+++ b/drivers/input/serio/Kconfig -@@ -106,6 +106,33 @@ config SERIO_GSCPS2 - To compile this driver as a module, choose M here: the - module will be called gscps2. - -+config SERIO_GSCPS2_RDI_KEYCODES -+ bool "Use PrecisionBook keyboard scancodes" -+ depends on SERIO_GSCPS2 -+ default n -+ help -+ If you have an RDI PrecisionBook, say Y here if you want to use its -+ built-in keyboard (as opposed to an external keyboard). -+ -+ The PrecisionBook has five keys that conflict with those used by most -+ AT and PS/2 keyboards. These are as follows: -+ -+ PrecisionBook Standard AT or PS/2 -+ -+ F1 F12 -+ Left Ctrl Left Alt -+ Caps Lock Left Ctrl -+ Right Ctrl Caps Lock -+ Left 102nd key (the key to the right of Left Shift) -+ -+ If you say N here, and use the PrecisionBook keyboard, then each key -+ in the left-hand column will be interpreted as the corresponding key -+ in the right-hand column. -+ -+ If you say Y here, and use an external keyboard, then each key in the -+ right-hand column will be interpreted as the key shown in the -+ left-hand column. -+ - config HP_SDC - tristate "HP System Device Controller i8042 Support" - depends on (GSC || HP300) && SERIO -diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c ---- a/drivers/input/serio/gscps2.c -+++ b/drivers/input/serio/gscps2.c -@@ -22,18 +22,15 @@ - * was usable/enabled ?) - */ - --#include --#include --#include --#include -+#include - #include - #include --#include --#include -+#include - #include -+#include -+#include - - #include --#include - #include - - MODULE_AUTHOR("Laurent Canet , Thibaut Varene , Helge Deller "); -@@ -80,6 +77,116 @@ MODULE_LICENSE("GPL"); - #define GSC_ID_KEYBOARD 0 /* device ID values */ - #define GSC_ID_MOUSE 1 - -+#ifndef CONFIG_SERIO_GSCPS2_RDI_KEYCODES -+# define CONFLICT(x, y) x -+#else -+# define CONFLICT(x, y) y -+#endif -+ -+/* -+ * Sadly RDI (Tadpole) decided to ship a different keyboard layout -+ * than HP for their PS/2 laptop keyboard which leads to conflicting -+ * keycodes between a normal HP PS/2 keyboard and a RDI PrecisionBook. -+ * HP: RDI: -+ */ -+#define C_07 CONFLICT(KEY_F12, KEY_F1) -+#define C_11 CONFLICT(KEY_LEFTALT, KEY_LEFTCTRL) -+#define C_14 CONFLICT(KEY_LEFTCTRL, KEY_CAPSLOCK) -+#define C_58 CONFLICT(KEY_CAPSLOCK, KEY_RIGHTCTRL) -+#define C_61 CONFLICT(KEY_102ND, KEY_LEFT) -+ -+/* -+ * Special keycode value recognized by atkbd (ATKBD_KEY_NULL) to silently -+ * discard scancodes without generating input events or "unknown key" warnings. -+ */ -+#define KEY_NULL 255 -+ -+#define KEYMAP_ENTRY(scancode, keycode) (((scancode) << 16) | (keycode)) -+ -+static const u32 gscps2_keymap[] = { -+ KEYMAP_ENTRY(0x01, KEY_F9), KEYMAP_ENTRY(0x03, KEY_F5), -+ KEYMAP_ENTRY(0x04, KEY_F3), KEYMAP_ENTRY(0x05, KEY_F1), -+ KEYMAP_ENTRY(0x06, KEY_F2), KEYMAP_ENTRY(0x07, C_07), -+ KEYMAP_ENTRY(0x08, KEY_ESC), KEYMAP_ENTRY(0x09, KEY_F10), -+ KEYMAP_ENTRY(0x0a, KEY_F8), KEYMAP_ENTRY(0x0b, KEY_F6), -+ KEYMAP_ENTRY(0x0c, KEY_F4), KEYMAP_ENTRY(0x0d, KEY_TAB), -+ KEYMAP_ENTRY(0x0e, KEY_GRAVE), KEYMAP_ENTRY(0x0f, KEY_F2), -+ KEYMAP_ENTRY(0x11, C_11), KEYMAP_ENTRY(0x12, KEY_LEFTSHIFT), -+ KEYMAP_ENTRY(0x14, C_14), KEYMAP_ENTRY(0x15, KEY_Q), -+ KEYMAP_ENTRY(0x16, KEY_1), KEYMAP_ENTRY(0x17, KEY_F3), -+ KEYMAP_ENTRY(0x19, KEY_LEFTALT), KEYMAP_ENTRY(0x1a, KEY_Z), -+ KEYMAP_ENTRY(0x1b, KEY_S), KEYMAP_ENTRY(0x1c, KEY_A), -+ KEYMAP_ENTRY(0x1d, KEY_W), KEYMAP_ENTRY(0x1e, KEY_2), -+ KEYMAP_ENTRY(0x1f, KEY_F4), KEYMAP_ENTRY(0x21, KEY_C), -+ KEYMAP_ENTRY(0x22, KEY_X), KEYMAP_ENTRY(0x23, KEY_D), -+ KEYMAP_ENTRY(0x24, KEY_E), KEYMAP_ENTRY(0x25, KEY_4), -+ KEYMAP_ENTRY(0x26, KEY_3), KEYMAP_ENTRY(0x27, KEY_F5), -+ KEYMAP_ENTRY(0x29, KEY_SPACE), KEYMAP_ENTRY(0x2a, KEY_V), -+ KEYMAP_ENTRY(0x2b, KEY_F), KEYMAP_ENTRY(0x2c, KEY_T), -+ KEYMAP_ENTRY(0x2d, KEY_R), KEYMAP_ENTRY(0x2e, KEY_5), -+ KEYMAP_ENTRY(0x2f, KEY_F6), KEYMAP_ENTRY(0x31, KEY_N), -+ KEYMAP_ENTRY(0x32, KEY_B), KEYMAP_ENTRY(0x33, KEY_H), -+ KEYMAP_ENTRY(0x34, KEY_G), KEYMAP_ENTRY(0x35, KEY_Y), -+ KEYMAP_ENTRY(0x36, KEY_6), KEYMAP_ENTRY(0x37, KEY_F7), -+ KEYMAP_ENTRY(0x39, KEY_RIGHTALT), KEYMAP_ENTRY(0x3a, KEY_M), -+ KEYMAP_ENTRY(0x3b, KEY_J), KEYMAP_ENTRY(0x3c, KEY_U), -+ KEYMAP_ENTRY(0x3d, KEY_7), KEYMAP_ENTRY(0x3e, KEY_8), -+ KEYMAP_ENTRY(0x3f, KEY_F8), KEYMAP_ENTRY(0x41, KEY_COMMA), -+ KEYMAP_ENTRY(0x42, KEY_K), KEYMAP_ENTRY(0x43, KEY_I), -+ KEYMAP_ENTRY(0x44, KEY_O), KEYMAP_ENTRY(0x45, KEY_0), -+ KEYMAP_ENTRY(0x46, KEY_9), KEYMAP_ENTRY(0x47, KEY_F9), -+ KEYMAP_ENTRY(0x49, KEY_DOT), KEYMAP_ENTRY(0x4a, KEY_SLASH), -+ KEYMAP_ENTRY(0x4b, KEY_L), KEYMAP_ENTRY(0x4c, KEY_SEMICOLON), -+ KEYMAP_ENTRY(0x4d, KEY_P), KEYMAP_ENTRY(0x4e, KEY_MINUS), -+ KEYMAP_ENTRY(0x4f, KEY_F10), KEYMAP_ENTRY(0x52, KEY_APOSTROPHE), -+ KEYMAP_ENTRY(0x54, KEY_LEFTBRACE), KEYMAP_ENTRY(0x55, KEY_EQUAL), -+ KEYMAP_ENTRY(0x56, KEY_F11), KEYMAP_ENTRY(0x57, KEY_SYSRQ), -+ KEYMAP_ENTRY(0x58, C_58), KEYMAP_ENTRY(0x59, KEY_RIGHTSHIFT), -+ KEYMAP_ENTRY(0x5a, KEY_ENTER), KEYMAP_ENTRY(0x5b, KEY_RIGHTBRACE), -+ KEYMAP_ENTRY(0x5c, KEY_BACKSLASH), KEYMAP_ENTRY(0x5d, KEY_BACKSLASH), -+ KEYMAP_ENTRY(0x5e, KEY_F12), KEYMAP_ENTRY(0x5f, KEY_SCROLLLOCK), -+ KEYMAP_ENTRY(0x60, KEY_DOWN), KEYMAP_ENTRY(0x61, C_61), -+ KEYMAP_ENTRY(0x62, KEY_PAUSE), KEYMAP_ENTRY(0x63, KEY_UP), -+ KEYMAP_ENTRY(0x64, KEY_DELETE), KEYMAP_ENTRY(0x65, KEY_END), -+ KEYMAP_ENTRY(0x66, KEY_BACKSPACE), KEYMAP_ENTRY(0x67, KEY_INSERT), -+ KEYMAP_ENTRY(0x69, KEY_KP1), KEYMAP_ENTRY(0x6a, KEY_RIGHT), -+ KEYMAP_ENTRY(0x6b, KEY_KP4), KEYMAP_ENTRY(0x6c, KEY_KP7), -+ KEYMAP_ENTRY(0x6d, KEY_PAGEDOWN), KEYMAP_ENTRY(0x6e, KEY_HOME), -+ KEYMAP_ENTRY(0x6f, KEY_PAGEUP), KEYMAP_ENTRY(0x70, KEY_KP0), -+ KEYMAP_ENTRY(0x71, KEY_KPDOT), KEYMAP_ENTRY(0x72, KEY_KP2), -+ KEYMAP_ENTRY(0x73, KEY_KP5), KEYMAP_ENTRY(0x74, KEY_KP6), -+ KEYMAP_ENTRY(0x75, KEY_KP8), KEYMAP_ENTRY(0x76, KEY_ESC), -+ KEYMAP_ENTRY(0x77, KEY_NUMLOCK), KEYMAP_ENTRY(0x78, KEY_F11), -+ KEYMAP_ENTRY(0x79, KEY_KPPLUS), KEYMAP_ENTRY(0x7a, KEY_KP3), -+ KEYMAP_ENTRY(0x7b, KEY_KPMINUS), KEYMAP_ENTRY(0x7c, KEY_KPASTERISK), -+ KEYMAP_ENTRY(0x7d, KEY_KP9), KEYMAP_ENTRY(0x7e, KEY_SCROLLLOCK), -+ KEYMAP_ENTRY(0x7f, KEY_102ND), KEYMAP_ENTRY(0x91, KEY_RIGHTALT), -+ KEYMAP_ENTRY(0x92, KEY_NULL), KEYMAP_ENTRY(0x94, KEY_RIGHTCTRL), -+ KEYMAP_ENTRY(0x9d, KEY_CAPSLOCK), KEYMAP_ENTRY(0x9f, KEY_LEFTMETA), -+ KEYMAP_ENTRY(0xa7, KEY_RIGHTMETA), KEYMAP_ENTRY(0xaf, KEY_COMPOSE), -+ KEYMAP_ENTRY(0xca, KEY_KPSLASH), KEYMAP_ENTRY(0xda, KEY_KPENTER), -+ KEYMAP_ENTRY(0xe9, KEY_END), KEYMAP_ENTRY(0xeb, KEY_LEFT), -+ KEYMAP_ENTRY(0xec, KEY_HOME), KEYMAP_ENTRY(0xf0, KEY_INSERT), -+ KEYMAP_ENTRY(0xf1, KEY_DELETE), KEYMAP_ENTRY(0xf2, KEY_DOWN), -+ KEYMAP_ENTRY(0xf4, KEY_RIGHT), KEYMAP_ENTRY(0xf5, KEY_UP), -+ KEYMAP_ENTRY(0xf7, KEY_PAUSE), KEYMAP_ENTRY(0xfa, KEY_PAGEDOWN), -+ KEYMAP_ENTRY(0xfc, KEY_SYSRQ), KEYMAP_ENTRY(0xfd, KEY_PAGEUP), -+ -+ /* Escaped keycodes */ -+ KEYMAP_ENTRY(0x103, KEY_F7), KEYMAP_ENTRY(0x10b, KEY_LEFTMETA), -+ KEYMAP_ENTRY(0x10c, KEY_RIGHTMETA), KEYMAP_ENTRY(0x111, KEY_RIGHTALT), -+ KEYMAP_ENTRY(0x114, KEY_RIGHTCTRL), -+}; -+ -+static const struct property_entry gscps2_props[] = { -+ PROPERTY_ENTRY_U32_ARRAY("linux,keymap", gscps2_keymap), -+ { } -+}; -+ -+static const struct software_node gscps2_keyboard_node = { -+ .name = "gscps2-keyboard", -+ .properties = gscps2_props, -+}; - - static irqreturn_t gscps2_interrupt(int irq, void *dev); - -@@ -398,6 +505,17 @@ static int __init gscps2_probe(struct parisc_device *dev) - goto fail; - #endif - -+ if (ps2port->id == GSC_ID_KEYBOARD) { -+ ret = device_add_software_node(&serio->dev, -+ &gscps2_keyboard_node); -+ if (ret) { -+ dev_err(&dev->dev, -+ "failed to add software node for keyboard: %d\n", -+ ret); -+ goto fail; -+ } -+ } -+ - pr_info("serio: %s port at 0x%08lx irq %d @ %s\n", - ps2port->port->name, - hpa, -@@ -411,11 +529,16 @@ static int __init gscps2_probe(struct parisc_device *dev) - return 0; - - fail: -+ if (ps2port->id == GSC_ID_KEYBOARD) -+ device_remove_software_node(&serio->dev); -+ - free_irq(dev->irq, ps2port); - - fail_miserably: - iounmap(ps2port->addr); -+#if 0 - release_mem_region(dev->hpa.start, GSC_STATUS + 4); -+#endif - - fail_nomem: - kfree(ps2port); -@@ -434,6 +557,9 @@ static void __exit gscps2_remove(struct parisc_device *dev) - { - struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); - -+ if (ps2port->id == GSC_ID_KEYBOARD) -+ device_remove_software_node(&ps2port->port->dev); -+ - serio_unregister_port(ps2port->port); - free_irq(dev->irq, ps2port); - gscps2_flush(ps2port); -@@ -465,16 +591,25 @@ static struct parisc_driver parisc_ps2_driver __refdata = { - - static int __init gscps2_init(void) - { -- register_parisc_driver(&parisc_ps2_driver); -- return 0; -+ int error; -+ -+ error = software_node_register(&gscps2_keyboard_node); -+ if (error) -+ return error; -+ -+ error = register_parisc_driver(&parisc_ps2_driver); -+ if (error) -+ software_node_unregister(&gscps2_keyboard_node); -+ -+ return error; - } - - static void __exit gscps2_exit(void) - { - unregister_parisc_driver(&parisc_ps2_driver); -+ software_node_unregister(&gscps2_keyboard_node); - } - - - module_init(gscps2_init); - module_exit(gscps2_exit); -- -diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h ---- a/drivers/input/serio/i8042-acpipnpio.h -+++ b/drivers/input/serio/i8042-acpipnpio.h -@@ -3,6 +3,7 @@ - #define _I8042_ACPIPNPIO_H - - #include -+#include - - #ifdef CONFIG_X86 - #include -@@ -1486,17 +1487,21 @@ static char i8042_pnp_aux_name[32]; - - static void i8042_pnp_id_to_string(struct pnp_id *id, char *dst, int dst_size) - { -- strscpy(dst, "PNP:", dst_size); -+ struct seq_buf sb; -+ -+ seq_buf_init(&sb, dst, dst_size); -+ seq_buf_printf(&sb, "PNP:"); - - while (id) { -- strlcat(dst, " ", dst_size); -- strlcat(dst, id->id, dst_size); -+ seq_buf_printf(&sb, " %s", id->id); - id = id->next; - } - } - - static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *did) - { -+ const char *name = pnp_dev_name(dev); -+ - if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1) - i8042_pnp_data_reg = pnp_port_start(dev,0); - -@@ -1506,11 +1511,8 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id * - if (pnp_irq_valid(dev,0)) - i8042_pnp_kbd_irq = pnp_irq(dev, 0); - -- strscpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name)); -- if (strlen(pnp_dev_name(dev))) { -- strlcat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name)); -- strlcat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name)); -- } -+ scnprintf(i8042_pnp_kbd_name, sizeof(i8042_pnp_kbd_name), "%s%s%s", -+ did->id, strlen(name) ? ":" : "", name); - i8042_pnp_id_to_string(dev->id, i8042_kbd_firmware_id, - sizeof(i8042_kbd_firmware_id)); - i8042_kbd_fwnode = dev_fwnode(&dev->dev); -@@ -1524,6 +1526,8 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id * - - static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *did) - { -+ const char *name = pnp_dev_name(dev); -+ - if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1) - i8042_pnp_data_reg = pnp_port_start(dev,0); - -@@ -1533,11 +1537,8 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id * - if (pnp_irq_valid(dev, 0)) - i8042_pnp_aux_irq = pnp_irq(dev, 0); - -- strscpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name)); -- if (strlen(pnp_dev_name(dev))) { -- strlcat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name)); -- strlcat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name)); -- } -+ scnprintf(i8042_pnp_aux_name, sizeof(i8042_pnp_aux_name), "%s%s%s", -+ did->id, strlen(name) ? ":" : "", name); - i8042_pnp_id_to_string(dev->id, i8042_aux_firmware_id, - sizeof(i8042_aux_firmware_id)); - -diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c ---- a/drivers/input/touchscreen/elo.c -+++ b/drivers/input/touchscreen/elo.c -@@ -257,7 +257,7 @@ static int elo_command_10(struct elo *elo, unsigned char *packet) - - static int elo_setup_10(struct elo *elo) - { -- static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" }; -+ static const char * const elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" }; - struct input_dev *dev = elo->dev; - unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD }; - -@@ -273,7 +273,7 @@ static int elo_setup_10(struct elo *elo) - - dev_info(&elo->serio->dev, - "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n", -- elo_types[(packet[1] -'0') & 0x03], -+ elo_types[(packet[1] - '0') & 0x03], - packet[5], packet[4], packet[3], packet[7]); - - return 0; -diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c ---- a/drivers/input/touchscreen/inexio.c -+++ b/drivers/input/touchscreen/inexio.c -@@ -81,7 +81,9 @@ static irqreturn_t inexio_interrupt(struct serio *serio, - if (INEXIO_RESPONSE_BEGIN_BYTE&pinexio->data[0]) - inexio_process_data(pinexio); - else -- printk(KERN_DEBUG "inexio.c: unknown/unsynchronized data from device, byte %x\n",pinexio->data[0]); -+ dev_dbg(&serio->dev, -+ "unknown/unsynchronized data from device, byte %x\n", -+ pinexio->data[0]); - - return IRQ_HANDLED; - } -diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c ---- a/drivers/input/touchscreen/iqs5xx.c -+++ b/drivers/input/touchscreen/iqs5xx.c -@@ -785,7 +785,8 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client, - switch (rec_type) { - case IQS5XX_REC_TYPE_DATA: - if (rec_addr < IQS5XX_CHKSM || -- rec_addr > IQS5XX_PMAP_END) { -+ rec_addr > IQS5XX_PMAP_END || -+ rec_len > IQS5XX_PMAP_END + 1 - rec_addr) { - dev_err(&client->dev, - "Invalid address at record %u\n", - rec_num); -diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c ---- a/drivers/input/touchscreen/mms114.c -+++ b/drivers/input/touchscreen/mms114.c -@@ -4,6 +4,8 @@ - // Copyright (c) 2012 Samsung Electronics Co., Ltd. - // Author: Joonyoung Shim - -+#include -+#include - #include - #include - #include -@@ -52,21 +54,13 @@ - #define MMS114_TYPE_TOUCHSCREEN 1 - #define MMS114_TYPE_TOUCHKEY 2 - --enum mms_type { -- TYPE_MMS114 = 114, -- TYPE_MMS134S = 134, -- TYPE_MMS136 = 136, -- TYPE_MMS152 = 152, -- TYPE_MMS345L = 345, --}; -- - struct mms114_data { -+ const struct mms_chip *chip; - struct i2c_client *client; - struct input_dev *input_dev; - struct regulator *core_reg; - struct regulator *io_reg; - struct touchscreen_properties props; -- enum mms_type type; - unsigned int contact_threshold; - unsigned int moving_threshold; - -@@ -77,9 +71,23 @@ struct mms114_data { - u8 cache_mode_control; - }; - -+struct mms_chip { -+ const char *name; -+ int event_size; -+ bool has_config_regs; -+ int (*get_version)(struct mms114_data *data); -+}; -+ -+#define MMS114_FLAGS_ID_MASK GENMASK(3, 0) -+#define MMS114_FLAGS_TYPE_MASK GENMASK(6, 5) -+#define MMS114_FLAGS_PRESSED_MASK BIT(7) -+ -+#define MMS114_XY_HI_X_MASK GENMASK(3, 0) -+#define MMS114_XY_HI_Y_MASK GENMASK(7, 4) -+ - struct mms114_touch { -- u8 id:4, reserved_bit4:1, type:2, pressed:1; -- u8 x_hi:4, y_hi:4; -+ u8 flags; -+ u8 xy_hi; - u8 x_lo; - u8 y_lo; - u8 width; -@@ -87,16 +95,16 @@ struct mms114_touch { - u8 reserved[2]; - } __packed; - --static int __mms114_read_reg(struct mms114_data *data, unsigned int reg, -- unsigned int len, u8 *val) -+static int __mms114_read_reg(struct mms114_data *data, u8 reg, -+ unsigned int len, void *val) - { - struct i2c_client *client = data->client; - struct i2c_msg xfer[2]; -- u8 buf = reg & 0xff; -+ u8 buf = reg; - int error; - -- if (reg <= MMS114_MODE_CONTROL && reg + len > MMS114_MODE_CONTROL) -- BUG(); -+ if (WARN_ON(reg <= MMS114_MODE_CONTROL && reg + len > MMS114_MODE_CONTROL)) -+ return -EINVAL; - - /* Write register */ - xfer[0].addr = client->addr; -@@ -116,12 +124,12 @@ static int __mms114_read_reg(struct mms114_data *data, unsigned int reg, - "%s: i2c transfer failed (%d)\n", __func__, error); - return error < 0 ? error : -EIO; - } -- udelay(MMS114_I2C_DELAY); -+ usleep_range(MMS114_I2C_DELAY, MMS114_I2C_DELAY + 50); - - return 0; - } - --static int mms114_read_reg(struct mms114_data *data, unsigned int reg) -+static int mms114_read_reg(struct mms114_data *data, u8 reg) - { - u8 val; - int error; -@@ -133,15 +141,14 @@ static int mms114_read_reg(struct mms114_data *data, unsigned int reg) - return error < 0 ? error : val; - } - --static int mms114_write_reg(struct mms114_data *data, unsigned int reg, -- unsigned int val) -+static int mms114_write_reg(struct mms114_data *data, u8 reg, u8 val) - { - struct i2c_client *client = data->client; - u8 buf[2]; - int error; - -- buf[0] = reg & 0xff; -- buf[1] = val & 0xff; -+ buf[0] = reg; -+ buf[1] = val; - - error = i2c_master_send(client, buf, 2); - if (error != 2) { -@@ -149,7 +156,7 @@ static int mms114_write_reg(struct mms114_data *data, unsigned int reg, - "%s: i2c send failed (%d)\n", __func__, error); - return error < 0 ? error : -EIO; - } -- udelay(MMS114_I2C_DELAY); -+ usleep_range(MMS114_I2C_DELAY, MMS114_I2C_DELAY + 50); - - if (reg == MMS114_MODE_CONTROL) - data->cache_mode_control = val; -@@ -157,32 +164,119 @@ static int mms114_write_reg(struct mms114_data *data, unsigned int reg, - return 0; - } - -+static int mms114_get_version(struct mms114_data *data) -+{ -+ struct device *dev = &data->client->dev; -+ u8 buf[6]; -+ int error; -+ -+ error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf); -+ if (error) -+ return error; -+ -+ dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n", -+ buf[0], buf[1], buf[3]); -+ return 0; -+} -+ -+static int mms152_get_version(struct mms114_data *data) -+{ -+ struct device *dev = &data->client->dev; -+ u8 buf[3]; -+ int group; -+ int error; -+ -+ error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf); -+ if (error) -+ return error; -+ -+ group = i2c_smbus_read_byte_data(data->client, MMS152_COMPAT_GROUP); -+ if (group < 0) -+ return group; -+ -+ dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x, Compat group: %c\n", -+ buf[0], buf[1], buf[2], group); -+ return 0; -+} -+ -+static int mms345l_get_version(struct mms114_data *data) -+{ -+ struct device *dev = &data->client->dev; -+ u8 buf[3]; -+ int error; -+ -+ error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf); -+ if (error) -+ return error; -+ -+ dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x\n", -+ buf[0], buf[1], buf[2]); -+ return 0; -+} -+ -+static const struct mms_chip mms114_descriptor = { -+ .name = "MMS114", -+ .event_size = MMS114_EVENT_SIZE, -+ .has_config_regs = true, -+ .get_version = mms114_get_version, -+}; -+ -+static const struct mms_chip mms134s_descriptor = { -+ .name = "MMS134S", -+ .event_size = MMS136_EVENT_SIZE, -+ .has_config_regs = true, -+ .get_version = mms114_get_version, -+}; -+ -+static const struct mms_chip mms136_descriptor = { -+ .name = "MMS136", -+ .event_size = MMS136_EVENT_SIZE, -+ .has_config_regs = true, -+ .get_version = mms114_get_version, -+}; -+ -+static const struct mms_chip mms152_descriptor = { -+ .name = "MMS152", -+ .event_size = MMS114_EVENT_SIZE, -+ .has_config_regs = false, -+ .get_version = mms152_get_version, -+}; -+ -+static const struct mms_chip mms345l_descriptor = { -+ .name = "MMS345L", -+ .event_size = MMS114_EVENT_SIZE, -+ .has_config_regs = false, -+ .get_version = mms345l_get_version, -+}; -+ - static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *touch) - { - struct i2c_client *client = data->client; - struct input_dev *input_dev = data->input_dev; -- unsigned int id; -+ unsigned int id = FIELD_GET(MMS114_FLAGS_ID_MASK, touch->flags); -+ unsigned int type = FIELD_GET(MMS114_FLAGS_TYPE_MASK, touch->flags); -+ bool pressed = FIELD_GET(MMS114_FLAGS_PRESSED_MASK, touch->flags); - unsigned int x; - unsigned int y; - -- if (touch->id == 0 || touch->id > MMS114_MAX_TOUCH) { -- dev_err(&client->dev, "Wrong touch id (%d)\n", touch->id); -+ if (id == 0 || id > MMS114_MAX_TOUCH) { -+ dev_err(&client->dev, "Wrong touch id (%d)\n", id); - return; - } - -- id = touch->id - 1; -- x = touch->x_lo | touch->x_hi << 8; -- y = touch->y_lo | touch->y_hi << 8; -+ id--; -+ x = touch->x_lo | FIELD_GET(MMS114_XY_HI_X_MASK, touch->xy_hi) << 8; -+ y = touch->y_lo | FIELD_GET(MMS114_XY_HI_Y_MASK, touch->xy_hi) << 8; - - dev_dbg(&client->dev, - "id: %d, type: %d, pressed: %d, x: %d, y: %d, width: %d, strength: %d\n", -- id, touch->type, touch->pressed, -+ id, type, pressed, - x, y, touch->width, touch->strength); - - input_mt_slot(input_dev, id); -- input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, touch->pressed); -+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, pressed); - -- if (touch->pressed) { -+ if (pressed) { - touchscreen_report_pos(input_dev, &data->props, x, y, true); - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, touch->width); - input_report_abs(input_dev, ABS_MT_PRESSURE, touch->strength); -@@ -195,21 +289,23 @@ static void mms114_process_touchkey(struct mms114_data *data, - struct i2c_client *client = data->client; - struct input_dev *input_dev = data->input_dev; - unsigned int keycode_id; -+ unsigned int id = FIELD_GET(MMS114_FLAGS_ID_MASK, touch->flags); -+ bool pressed = FIELD_GET(MMS114_FLAGS_PRESSED_MASK, touch->flags); - -- if (touch->id == 0) -+ if (id == 0) - return; - -- if (touch->id > data->num_keycodes) { -+ if (id > data->num_keycodes) { - dev_err(&client->dev, "Wrong touch id for touchkey (%d)\n", -- touch->id); -+ id); - return; - } - -- keycode_id = touch->id - 1; -+ keycode_id = id - 1; - dev_dbg(&client->dev, "keycode id: %d, pressed: %d\n", keycode_id, -- touch->pressed); -+ pressed); - -- input_report_key(input_dev, data->keycodes[keycode_id], touch->pressed); -+ input_report_key(input_dev, data->keycodes[keycode_id], pressed); - } - - static irqreturn_t mms114_interrupt(int irq, void *dev_id) -@@ -218,8 +314,8 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) - struct i2c_client *client = data->client; - struct mms114_touch touch[MMS114_MAX_TOUCH]; - struct mms114_touch *t; -+ int event_size = data->chip->event_size; - int packet_size; -- int event_size; - int touch_size; - int index; - int error; -@@ -234,23 +330,17 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) - goto out; - } - -- /* MMS136 has slightly different event size */ -- if (data->type == TYPE_MMS134S || data->type == TYPE_MMS136) -- event_size = MMS136_EVENT_SIZE; -- else -- event_size = MMS114_EVENT_SIZE; -- - touch_size = packet_size / event_size; - -- error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size, -- (u8 *)touch); -- if (error < 0) -+ error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size, touch); -+ if (error) - goto out; - - for (index = 0; index < touch_size; index++) { - t = (struct mms114_touch *)((u8 *)touch + index * event_size); -+ unsigned int type = FIELD_GET(MMS114_FLAGS_TYPE_MASK, t->flags); - -- switch (t->type) { -+ switch (type) { - case MMS114_TYPE_TOUCHSCREEN: - mms114_process_mt(data, t); - break; -@@ -261,7 +351,7 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) - - default: - dev_err(&client->dev, "Wrong touch type (%d)\n", -- t->type); -+ type); - break; - } - } -@@ -290,65 +380,17 @@ static int mms114_set_active(struct mms114_data *data, bool active) - return mms114_write_reg(data, MMS114_MODE_CONTROL, val); - } - --static int mms114_get_version(struct mms114_data *data) --{ -- struct device *dev = &data->client->dev; -- u8 buf[6]; -- int group; -- int error; -- -- switch (data->type) { -- case TYPE_MMS345L: -- error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf); -- if (error) -- return error; -- -- dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x\n", -- buf[0], buf[1], buf[2]); -- break; -- -- case TYPE_MMS152: -- error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf); -- if (error) -- return error; -- -- group = i2c_smbus_read_byte_data(data->client, -- MMS152_COMPAT_GROUP); -- if (group < 0) -- return group; -- -- dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x, Compat group: %c\n", -- buf[0], buf[1], buf[2], group); -- break; -- -- case TYPE_MMS114: -- case TYPE_MMS134S: -- case TYPE_MMS136: -- error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf); -- if (error) -- return error; -- -- dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n", -- buf[0], buf[1], buf[3]); -- break; -- } -- -- return 0; --} -- - static int mms114_setup_regs(struct mms114_data *data) - { - const struct touchscreen_properties *props = &data->props; - int val; - int error; - -- error = mms114_get_version(data); -- if (error < 0) -+ error = data->chip->get_version(data); -+ if (error) - return error; - -- /* MMS114, MMS134S and MMS136 have configuration and power on registers */ -- if (data->type != TYPE_MMS114 && data->type != TYPE_MMS134S && -- data->type != TYPE_MMS136) -+ if (!data->chip->has_config_regs) - return 0; - - error = mms114_set_active(data, true); -@@ -366,21 +408,21 @@ static int mms114_setup_regs(struct mms114_data *data) - if (error < 0) - return error; - -- val = props->max_x & 0xff; -+ val = props->max_y & 0xff; - error = mms114_write_reg(data, MMS114_Y_RESOLUTION, val); - if (error < 0) - return error; - - if (data->contact_threshold) { - error = mms114_write_reg(data, MMS114_CONTACT_THRESHOLD, -- data->contact_threshold); -+ data->contact_threshold); - if (error < 0) - return error; - } - - if (data->moving_threshold) { - error = mms114_write_reg(data, MMS114_MOVING_THRESHOLD, -- data->moving_threshold); -+ data->moving_threshold); - if (error < 0) - return error; - } -@@ -466,9 +508,9 @@ static int mms114_parse_legacy_bindings(struct mms114_data *data) - } - - device_property_read_u32(dev, "contact-threshold", -- &data->contact_threshold); -+ &data->contact_threshold); - device_property_read_u32(dev, "moving-threshold", -- &data->moving_threshold); -+ &data->moving_threshold); - - if (device_property_read_bool(dev, "x-invert")) - props->invert_x = true; -@@ -484,7 +526,6 @@ static int mms114_probe(struct i2c_client *client) - { - struct mms114_data *data; - struct input_dev *input_dev; -- const void *match_data; - int error; - int i; - -@@ -504,12 +545,10 @@ static int mms114_probe(struct i2c_client *client) - data->client = client; - data->input_dev = input_dev; - -- match_data = device_get_match_data(&client->dev); -- if (!match_data) -+ data->chip = i2c_get_match_data(client); -+ if (!data->chip) - return -EINVAL; - -- data->type = (enum mms_type)match_data; -- - data->num_keycodes = device_property_count_u32(&client->dev, - "linux,keycodes"); - if (data->num_keycodes == -EINVAL) { -@@ -521,7 +560,7 @@ static int mms114_probe(struct i2c_client *client) - return data->num_keycodes; - } else if (data->num_keycodes > MMS114_MAX_TOUCHKEYS) { - dev_warn(&client->dev, -- "Found %d linux,keycodes but max is %d, ignoring the rest\n", -+ "Found %d linux,keycodes but max is %d, ignoring the rest\n", - data->num_keycodes, MMS114_MAX_TOUCHKEYS); - data->num_keycodes = MMS114_MAX_TOUCHKEYS; - } -@@ -566,8 +605,7 @@ static int mms114_probe(struct i2c_client *client) - 0, data->props.max_y, 0, 0); - } - -- if (data->type == TYPE_MMS114 || data->type == TYPE_MMS134S || -- data->type == TYPE_MMS136) { -+ if (data->chip->has_config_regs) { - /* - * The firmware handles movement and pressure fuzz, so - * don't duplicate that in software. -@@ -582,8 +620,8 @@ static int mms114_probe(struct i2c_client *client) - } - - input_dev->name = devm_kasprintf(&client->dev, GFP_KERNEL, -- "MELFAS MMS%d Touchscreen", -- data->type); -+ "MELFAS %s Touchscreen", -+ data->chip->name); - if (!input_dev->name) - return -ENOMEM; - -@@ -679,29 +717,22 @@ static int mms114_resume(struct device *dev) - static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume); - - static const struct i2c_device_id mms114_id[] = { -- { .name = "mms114" }, -+ { .name = "mms114", .driver_data = (kernel_ulong_t)&mms114_descriptor }, -+ { .name = "mms134s", .driver_data = (kernel_ulong_t)&mms134s_descriptor }, -+ { .name = "mms136", .driver_data = (kernel_ulong_t)&mms136_descriptor }, -+ { .name = "mms152", .driver_data = (kernel_ulong_t)&mms152_descriptor }, -+ { .name = "mms345l", .driver_data = (kernel_ulong_t)&mms345l_descriptor }, - { } - }; - MODULE_DEVICE_TABLE(i2c, mms114_id); - - #ifdef CONFIG_OF - static const struct of_device_id mms114_dt_match[] = { -- { -- .compatible = "melfas,mms114", -- .data = (void *)TYPE_MMS114, -- }, { -- .compatible = "melfas,mms134s", -- .data = (void *)TYPE_MMS134S, -- }, { -- .compatible = "melfas,mms136", -- .data = (void *)TYPE_MMS136, -- }, { -- .compatible = "melfas,mms152", -- .data = (void *)TYPE_MMS152, -- }, { -- .compatible = "melfas,mms345l", -- .data = (void *)TYPE_MMS345L, -- }, -+ { .compatible = "melfas,mms114", .data = &mms114_descriptor }, -+ { .compatible = "melfas,mms134s", .data = &mms134s_descriptor }, -+ { .compatible = "melfas,mms136", .data = &mms136_descriptor }, -+ { .compatible = "melfas,mms152", .data = &mms152_descriptor }, -+ { .compatible = "melfas,mms345l", .data = &mms345l_descriptor }, - { } - }; - MODULE_DEVICE_TABLE(of, mms114_dt_match); -@@ -722,4 +753,4 @@ module_i2c_driver(mms114_driver); - /* Module information */ - MODULE_AUTHOR("Joonyoung Shim "); - MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver"); --MODULE_LICENSE("GPL v2"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c ---- a/drivers/input/touchscreen/sur40.c -+++ b/drivers/input/touchscreen/sur40.c -@@ -128,8 +128,8 @@ struct sur40_image_header { - /* polling interval (ms) */ - #define POLL_INTERVAL 1 - --/* maximum number of contacts FIXME: this is a guess? */ --#define MAX_CONTACTS 64 -+/* maximum number of contacts */ -+#define MAX_CONTACTS 52 - - /* control commands */ - #define SUR40_GET_VERSION 0xb0 /* 12 bytes string */ -diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c ---- a/drivers/input/touchscreen/wacom_w8001.c -+++ b/drivers/input/touchscreen/wacom_w8001.c -@@ -417,6 +417,13 @@ static int w8001_detect(struct w8001 *w8001) - return 0; - } - -+static void w8001_append_suffix(char *dest, const char *suffix, size_t dest_sz) -+{ -+ size_t used = strnlen(dest, dest_sz); -+ -+ strscpy(dest + used, suffix, dest_sz - used); -+} -+ - static int w8001_setup_pen(struct w8001 *w8001, char *basename, - size_t basename_sz) - { -@@ -453,7 +460,7 @@ static int w8001_setup_pen(struct w8001 *w8001, char *basename, - } - - w8001->id = 0x90; -- strlcat(basename, " Penabled", basename_sz); -+ w8001_append_suffix(basename, " Penabled", basename_sz); - - return 0; - } -@@ -503,14 +510,14 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename, - case 2: - w8001->pktlen = W8001_PKTLEN_TOUCH93; - w8001->id = 0x93; -- strlcat(basename, " 1FG", basename_sz); -+ w8001_append_suffix(basename, " 1FG", basename_sz); - break; - - case 1: - case 3: - case 4: - w8001->pktlen = W8001_PKTLEN_TOUCH9A; -- strlcat(basename, " 1FG", basename_sz); -+ w8001_append_suffix(basename, " 1FG", basename_sz); - w8001->id = 0x9a; - break; - -@@ -534,7 +541,7 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename, - input_abs_set_res(dev, ABS_MT_POSITION_X, touch.panel_res); - input_abs_set_res(dev, ABS_MT_POSITION_Y, touch.panel_res); - -- strlcat(basename, " 2FG", basename_sz); -+ w8001_append_suffix(basename, " 2FG", basename_sz); - if (w8001->max_pen_x && w8001->max_pen_y) - w8001->id = 0xE3; - else -@@ -542,7 +549,7 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename, - break; - } - -- strlcat(basename, " Touchscreen", basename_sz); -+ w8001_append_suffix(basename, " Touchscreen", basename_sz); - - return 0; - } -diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c ---- a/drivers/mfd/rohm-bd71828.c -+++ b/drivers/mfd/rohm-bd71828.c -@@ -5,7 +5,8 @@ - * ROHM BD718[15/28/79] and BD72720 PMIC driver - */ - --#include -+#include -+#include - #include - #include - #include -@@ -18,6 +19,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -37,19 +39,6 @@ - }, \ - } - --static struct gpio_keys_button button = { -- .code = KEY_POWER, -- .gpio = -1, -- .type = EV_KEY, -- .wakeup = 1, --}; -- --static const struct gpio_keys_platform_data bd71828_powerkey_data = { -- .buttons = &button, -- .nbuttons = 1, -- .name = "bd71828-pwrkey", --}; -- - static const struct resource bd71815_rtc_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd70528-rtc-alm-0"), - DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd70528-rtc-alm-1"), -@@ -174,10 +163,6 @@ static struct mfd_cell bd71828_mfd_cells[] = { - .name = "bd71828-rtc", - .resources = bd71828_rtc_irqs, - .num_resources = ARRAY_SIZE(bd71828_rtc_irqs), -- }, { -- .name = "gpio-keys", -- .platform_data = &bd71828_powerkey_data, -- .pdata_size = sizeof(bd71828_powerkey_data), - }, - }; - -@@ -242,11 +227,8 @@ static const struct mfd_cell bd72720_mfd_cells[] = { - .name = "bd72720-rtc", - .resources = bd72720_rtc_irqs, - .num_resources = ARRAY_SIZE(bd72720_rtc_irqs), -- }, { -- .name = "gpio-keys", -- .platform_data = &bd71828_powerkey_data, -- .pdata_size = sizeof(bd71828_powerkey_data), - }, -+ /* Power button is registered separately */ - }; - - static const struct regmap_range bd71815_volatile_ranges[] = { -@@ -877,6 +859,84 @@ static int set_clk_mode(struct device *dev, struct regmap *regmap, - OUT32K_MODE_CMOS); - } - -+static const struct property_entry bd71828_powerkey_parent_props[] = { -+ PROPERTY_ENTRY_STRING("label", "bd71828-pwrkey"), -+ { } -+}; -+ -+static const struct property_entry bd71828_powerkey_props[] = { -+ PROPERTY_ENTRY_U32("linux,code", KEY_POWER), -+ PROPERTY_ENTRY_BOOL("wakeup-source"), -+ { } -+}; -+ -+#define GPIO_KEYS 0 /* Node corresponding to gpio-keys device itself */ -+#define PWRON_KEY 1 /* Node describing power button in gpio-keys */ -+ -+static int bd71828_i2c_register_swnodes(const struct software_node *nodes) -+{ -+ const struct software_node * const node_group[] = { -+ &nodes[GPIO_KEYS], &nodes[PWRON_KEY], NULL -+ }; -+ -+ return software_node_register_node_group(node_group); -+} -+ -+static void bd71828_i2c_unregister_swnodes(void *data) -+{ -+ const struct software_node *nodes = data; -+ const struct software_node * const node_group[] = { -+ &nodes[GPIO_KEYS], &nodes[PWRON_KEY], NULL -+ }; -+ -+ software_node_unregister_node_group(node_group); -+} -+ -+static int bd71828_i2c_register_pwrbutton(struct device *dev, int button_irq, -+ struct irq_domain *irq_domain) -+{ -+ const struct resource res[] = { -+ DEFINE_RES_IRQ_NAMED(button_irq, "bd71828-pwrkey"), -+ }; -+ struct mfd_cell gpio_keys_cell = { -+ .name = "gpio-keys", -+ .resources = res, -+ .num_resources = ARRAY_SIZE(res), -+ }; -+ struct software_node *nodes; -+ int ret; -+ -+ nodes = devm_kcalloc(dev, 2, sizeof(*nodes), GFP_KERNEL); -+ if (!nodes) -+ return -ENOMEM; -+ -+ nodes[GPIO_KEYS].name = devm_kasprintf(dev, GFP_KERNEL, "%s-power-key", dev_name(dev)); -+ if (!nodes[GPIO_KEYS].name) -+ return -ENOMEM; -+ -+ nodes[GPIO_KEYS].properties = bd71828_powerkey_parent_props; -+ -+ nodes[PWRON_KEY].parent = &nodes[GPIO_KEYS]; -+ nodes[PWRON_KEY].properties = bd71828_powerkey_props; -+ -+ ret = bd71828_i2c_register_swnodes(nodes); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action_or_reset(dev, bd71828_i2c_unregister_swnodes, nodes); -+ if (ret) -+ return ret; -+ -+ gpio_keys_cell.swnode = &nodes[GPIO_KEYS]; -+ -+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, &gpio_keys_cell, 1, -+ NULL, 0, irq_domain); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to register power-button"); -+ -+ return 0; -+} -+ - static struct i2c_client *bd71828_dev; - static void bd71828_power_off(void) - { -@@ -929,6 +989,7 @@ static struct regmap *bd72720_do_regmaps(struct i2c_client *i2c) - static int bd71828_i2c_probe(struct i2c_client *i2c) - { - struct regmap_irq_chip_data *irq_data; -+ struct irq_domain *irq_domain; - int ret; - struct regmap *regmap = NULL; - const struct regmap_config *regmap_config; -@@ -1022,23 +1083,23 @@ static int bd71828_i2c_probe(struct i2c_client *i2c) - "Failed to enable main level IRQs\n"); - } - } -- if (button_irq) { -- ret = regmap_irq_get_virq(irq_data, button_irq); -- if (ret < 0) -- return dev_err_probe(&i2c->dev, ret, -- "Failed to get the power-key IRQ\n"); -- -- button.irq = ret; -- } - - ret = set_clk_mode(&i2c->dev, regmap, clkmode_reg); - if (ret) - return ret; - -+ irq_domain = regmap_irq_get_domain(irq_data); -+ - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells, -- NULL, 0, regmap_irq_get_domain(irq_data)); -+ NULL, 0, irq_domain); - if (ret) -- return dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); -+ return dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); -+ -+ if (button_irq) { -+ ret = bd71828_i2c_register_pwrbutton(&i2c->dev, button_irq, irq_domain); -+ if (ret) -+ return ret; -+ } - - if (of_device_is_system_power_controller(i2c->dev.of_node) && - chip_type == ROHM_CHIP_TYPE_BD71828) { -diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c ---- a/drivers/mfd/rohm-bd718x7.c -+++ b/drivers/mfd/rohm-bd718x7.c -@@ -7,7 +7,8 @@ - // Datasheet for BD71837MWV available from - // https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e - --#include -+#include -+#include - #include - #include - #include -@@ -15,37 +16,16 @@ - #include - #include - #include -+#include - #include - #include - --static struct gpio_keys_button button = { -- .code = KEY_POWER, -- .gpio = -1, -- .type = EV_KEY, --}; -- --static struct gpio_keys_platform_data bd718xx_powerkey_data = { -- .buttons = &button, -- .nbuttons = 1, -- .name = "bd718xx-pwrkey", --}; -- - static struct mfd_cell bd71837_mfd_cells[] = { -- { -- .name = "gpio-keys", -- .platform_data = &bd718xx_powerkey_data, -- .pdata_size = sizeof(bd718xx_powerkey_data), -- }, - { .name = "bd71837-clk", }, - { .name = "bd71837-pmic", }, - }; - - static struct mfd_cell bd71847_mfd_cells[] = { -- { -- .name = "gpio-keys", -- .platform_data = &bd718xx_powerkey_data, -- .pdata_size = sizeof(bd718xx_powerkey_data), -- }, - { .name = "bd71847-clk", }, - { .name = "bd71847-pmic", }, - }; -@@ -125,10 +105,89 @@ static int bd718xx_init_press_duration(struct regmap *regmap, - return 0; - } - -+static const struct property_entry bd718xx_powerkey_parent_props[] = { -+ PROPERTY_ENTRY_STRING("label", "bd718xx-pwrkey"), -+ { } -+}; -+ -+static const struct property_entry bd718xx_powerkey_props[] = { -+ PROPERTY_ENTRY_U32("linux,code", KEY_POWER), -+ { } -+}; -+ -+static const struct resource bd718xx_powerkey_resources[] = { -+ DEFINE_RES_IRQ_NAMED(BD718XX_INT_PWRBTN_S, "bd718xx-pwrkey"), -+}; -+ -+#define GPIO_KEYS 0 /* Node corresponding to gpio-keys device itself */ -+#define PWRON_KEY 1 /* Node describing power button in gpio-keys */ -+ -+static int bd718xx_i2c_register_swnodes(const struct software_node *nodes) -+{ -+ const struct software_node * const node_group[] = { -+ &nodes[GPIO_KEYS], &nodes[PWRON_KEY], NULL -+ }; -+ -+ return software_node_register_node_group(node_group); -+} -+ -+static void bd718xx_i2c_unregister_swnodes(void *data) -+{ -+ const struct software_node *nodes = data; -+ const struct software_node * const node_group[] = { -+ &nodes[GPIO_KEYS], &nodes[PWRON_KEY], NULL -+ }; -+ -+ software_node_unregister_node_group(node_group); -+} -+ -+static int bd718xx_i2c_register_pwrbutton(struct device *dev, -+ struct irq_domain *irq_domain) -+{ -+ struct mfd_cell gpio_keys_cell = { -+ .name = "gpio-keys", -+ .resources = bd718xx_powerkey_resources, -+ .num_resources = ARRAY_SIZE(bd718xx_powerkey_resources), -+ }; -+ struct software_node *nodes; -+ int ret; -+ -+ nodes = devm_kcalloc(dev, 2, sizeof(*nodes), GFP_KERNEL); -+ if (!nodes) -+ return -ENOMEM; -+ -+ nodes[GPIO_KEYS].name = devm_kasprintf(dev, GFP_KERNEL, "%s-power-key", dev_name(dev)); -+ if (!nodes[GPIO_KEYS].name) -+ return -ENOMEM; -+ -+ nodes[GPIO_KEYS].properties = bd718xx_powerkey_parent_props; -+ -+ nodes[PWRON_KEY].parent = &nodes[GPIO_KEYS]; -+ nodes[PWRON_KEY].properties = bd718xx_powerkey_props; -+ -+ ret = bd718xx_i2c_register_swnodes(nodes); -+ if (ret) -+ return ret; -+ -+ ret = devm_add_action_or_reset(dev, bd718xx_i2c_unregister_swnodes, nodes); -+ if (ret) -+ return ret; -+ -+ gpio_keys_cell.swnode = &nodes[GPIO_KEYS]; -+ -+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, &gpio_keys_cell, 1, -+ NULL, 0, irq_domain); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to register power-button"); -+ -+ return 0; -+} -+ - static int bd718xx_i2c_probe(struct i2c_client *i2c) - { - struct regmap *regmap; - struct regmap_irq_chip_data *irq_data; -+ struct irq_domain *irq_domain; - int ret; - unsigned int chip_type; - struct mfd_cell *mfd; -@@ -169,20 +228,18 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c) - if (ret) - return ret; - -- ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S); -- -- if (ret < 0) -- return dev_err_probe(&i2c->dev, ret, "Failed to get the IRQ\n"); -- -- button.irq = ret; -+ irq_domain = regmap_irq_get_domain(irq_data); - - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, -- mfd, cells, NULL, 0, -- regmap_irq_get_domain(irq_data)); -+ mfd, cells, NULL, 0, irq_domain); - if (ret) -- dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); -+ return dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); - -- return ret; -+ ret = bd718xx_i2c_register_pwrbutton(&i2c->dev, irq_domain); -+ if (ret) -+ return ret; -+ -+ return 0; - } - - static const struct of_device_id bd718xx_of_match[] = { -diff --git a/include/linux/input.h b/include/linux/input.h ---- a/include/linux/input.h -+++ b/include/linux/input.h -@@ -117,7 +117,8 @@ enum input_clock_type { - * user opens device and dev->close() is called when the very - * last user closes the device - * @going_away: marks devices that are in a middle of unregistering and -- * causes input_open_device*() fail with -ENODEV. -+ * causes input_open_device() and input_inhibit/uninhibit_device() -+ * to fail with -ENODEV. - * @dev: driver model's view of this device - * @h_list: list of input handles associated with the device. When - * accessing the list dev->mutex must be held -@@ -128,11 +129,14 @@ enum input_clock_type { - * @devres_managed: indicates that devices is managed with devres framework - * and needs not be explicitly unregistered or freed. - * @timestamp: storage for a timestamp set by input_set_timestamp called -- * by a driver -+ * by a driver - * @inhibited: indicates that the input device is inhibited. If that is -- * the case then input core ignores any events generated by the device. -- * Device's close() is called when it is being inhibited and its open() -- * is called when it is being uninhibited. -+ * the case then input core ignores any events generated by the device. -+ * Device's close() is called when it is being inhibited and its open() -+ * is called when it is being uninhibited. -+ * @ready: indicates that the device has been successfully opened and is -+ * prepared to process events (like LEDs or sounds) sent from the -+ * input core. - */ - struct input_dev { - const char *name; -@@ -209,6 +213,7 @@ struct input_dev { - ktime_t timestamp[INPUT_CLK_MAX]; - - bool inhibited; -+ bool ready; - }; - #define to_input_dev(d) container_of(d, struct input_dev, dev) - -@@ -284,8 +289,9 @@ struct input_handle; - * @connect: called when attaching a handler to an input device - * @disconnect: disconnects a handler from input device - * @start: starts handler for given handle. This function is called by -- * input core right after connect() method and also when a process -- * that "grabbed" a device releases it -+ * input core when device is open and ready to process events, -+ * and also when device is uninhibited or when a process that "grabbed" -+ * a device releases it - * @passive_observer: set to %true by drivers only interested in observing - * data stream from devices if there are other users present. Such - * drivers will not result in starting underlying hardware device -diff --git a/include/linux/input/elan-i2c-ids.h b/include/linux/input/elan-i2c-ids.h ---- a/include/linux/input/elan-i2c-ids.h -+++ b/include/linux/input/elan-i2c-ids.h -@@ -18,7 +18,7 @@ - #ifndef __ELAN_I2C_IDS_H - #define __ELAN_I2C_IDS_H - --#include -+#include - - static const struct acpi_device_id elan_acpi_id[] = { - { "ELAN0000", 0 }, diff --git a/kernel/0560-input-updates.patch.sig b/kernel/0560-input-updates.patch.sig deleted file mode 100644 index 594f27d..0000000 Binary files a/kernel/0560-input-updates.patch.sig and /dev/null differ diff --git a/kernel/0561-input-fixes.patch b/kernel/0561-input-fixes.patch deleted file mode 100644 index b067aaa..0000000 --- a/kernel/0561-input-fixes.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c ---- a/drivers/input/touchscreen/tsc2007_core.c -+++ b/drivers/input/touchscreen/tsc2007_core.c -@@ -221,7 +221,6 @@ static int tsc2007_get_pendown_state_gpio(struct device *dev) - static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) - { - u32 val32; -- u64 val64; - - if (!device_property_read_u32(dev, "ti,max-rt", &val32)) - ts->max_rt = val32; -@@ -237,8 +236,8 @@ static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) - if (!device_property_read_u32(dev, "ti,fuzzz", &val32)) - ts->fuzzz = val32; - -- if (!device_property_read_u64(dev, "ti,poll-period", &val64)) -- ts->poll_period = msecs_to_jiffies(val64); -+ if (!device_property_read_u32(dev, "ti,poll-period", &val32)) -+ ts->poll_period = msecs_to_jiffies(val32); - else - ts->poll_period = msecs_to_jiffies(1); - diff --git a/kernel/0561-input-fixes.patch.sig b/kernel/0561-input-fixes.patch.sig deleted file mode 100644 index 609b474..0000000 Binary files a/kernel/0561-input-fixes.patch.sig and /dev/null differ diff --git a/kernel/0562-hid-fixes.patch b/kernel/0562-hid-fixes.patch deleted file mode 100644 index 47e03fa..0000000 --- a/kernel/0562-hid-fixes.patch +++ /dev/null @@ -1,483 +0,0 @@ -diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h ---- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h -+++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h -@@ -12,11 +12,15 @@ - - #include - #include -+#include - #include "amd_sfh_hid.h" - - #define PCI_DEVICE_ID_AMD_MP2 0x15E4 - #define PCI_DEVICE_ID_AMD_MP2_1_1 0x164A - -+/* The BAR 2 size must cover the highest register offset (0x10958) */ -+#define AMD_SFH_MIN_BAR_SIZE SZ_128K -+ - #define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4)) - #define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4)) - -diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c ---- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c -+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c -@@ -451,6 +451,16 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i - if (rc) - return rc; - -+ if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { -+ dev_err(&pdev->dev, "BAR 2 is not IORESOURCE_MEM\n"); -+ return -ENODEV; -+ } -+ -+ if (pci_resource_len(pdev, 2) < AMD_SFH_MIN_BAR_SIZE) { -+ dev_err(&pdev->dev, "BAR 2 is too small\n"); -+ return -EINVAL; -+ } -+ - rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME); - if (rc) - return rc; -diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c ---- a/drivers/hid/bpf/hid_bpf_dispatch.c -+++ b/drivers/hid/bpf/hid_bpf_dispatch.c -@@ -359,7 +359,7 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx) - - static int - __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, -- enum hid_report_type rtype) -+ enum hid_report_type rtype, bool hw_request) - { - struct hid_report_enum *report_enum; - struct hid_report *report; -@@ -388,6 +388,10 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, - - report_len = hid_report_len(report); - -+ /* unnumbered reports need to have a report ID reserved in the first byte */ -+ if (hw_request && report_enum->numbered == 0) -+ report_len += 1; -+ - if (*buf__sz > report_len) - *buf__sz = report_len; - -@@ -420,7 +424,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, - return -EDEADLOCK; - - /* check arguments */ -- ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype); -+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype, true); - if (ret) - return ret; - -@@ -480,7 +484,7 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) - return -EDEADLOCK; - - /* check arguments */ -- ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT); -+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT, true); - if (ret) - return ret; - -@@ -506,7 +510,7 @@ __hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *b - return -EDEADLOCK; - - /* check arguments */ -- ret = __hid_bpf_hw_check_params(ctx, buf, &size, type); -+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, type, false); - if (ret) - return ret; - -diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c ---- a/drivers/hid/hid-alps.c -+++ b/drivers/hid/hid-alps.c -@@ -407,6 +407,8 @@ static int u1_raw_event(struct alps_dev *hdata, u8 *data, int size) - return 1; - - case U1_SP_ABSOLUTE_REPORT_ID: -+ if (!hdata->input2) -+ return 0; - sp_x = get_unaligned_le16(data+2); - sp_y = get_unaligned_le16(data+4); - -@@ -738,7 +740,6 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) - goto exit; - } - -- data->input2 = input2; - input2->phys = input->phys; - input2->name = "DualPoint Stick"; - input2->id.bustype = BUS_I2C; -@@ -762,11 +763,12 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) - __set_bit(INPUT_PROP_POINTER, input2->propbit); - __set_bit(INPUT_PROP_POINTING_STICK, input2->propbit); - -- if (input_register_device(data->input2)) { -+ if (input_register_device(input2)) { - input_free_device(input2); - ret = -ENOENT; - goto exit; - } -+ data->input2 = input2; - } - - exit: -@@ -823,6 +825,24 @@ static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id) - return 0; - } - -+static void alps_remove(struct hid_device *hdev) -+{ -+ struct alps_dev *data = hid_get_drvdata(hdev); -+ -+ /* -+ * input2 ("DualPoint Stick") is allocated separately and is not -+ * tracked in hdev->inputs, so the default remove path -+ * (hid_hw_stop -> hidinput_disconnect) does not unregister it. -+ * -+ * Stop the device first so that no URB callback can touch input2 -+ * while it is being unregistered, then drop it explicitly. -+ */ -+ hid_hw_stop(hdev); -+ -+ if (data->input2) -+ input_unregister_device(data->input2); -+} -+ - static const struct hid_device_id alps_id[] = { - { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, - USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, -@@ -845,6 +865,7 @@ static struct hid_driver alps_driver = { - .input_configured = alps_input_configured, - .resume = pm_ptr(alps_post_resume), - .reset_resume = pm_ptr(alps_post_reset), -+ .remove = alps_remove, - }; - - module_hid_driver(alps_driver); -diff --git a/drivers/hid/hid-corsair-void.c b/drivers/hid/hid-corsair-void.c ---- a/drivers/hid/hid-corsair-void.c -+++ b/drivers/hid/hid-corsair-void.c -@@ -51,20 +51,23 @@ - /* Receiver report information: (ID 102) */ - /* -------------------------------------------------------------------------- */ - /* -- * When queried, the recevier responds with 4 bytes to describe the firmware -- * The first 2 bytes are for the receiver, the second 2 are the headset -+ * When queried, the receiver responds with 5 bytes to describe the firmware -+ * The first byte is the ID, then 2 bytes for the receiver, then 2 for the headset - * The headset firmware version will be 0 if no headset is connected - * -- * 0: Recevier firmware major version -+ * 0: Report ID -+ * 102 for the firmware packet -+ * -+ * 1: Receiver firmware major version - * Major version of the receiver's firmware - * -- * 1: Recevier firmware minor version -+ * 2: Receiver firmware minor version - * Minor version of the receiver's firmware - * -- * 2: Headset firmware major version -+ * 3: Headset firmware major version - * Major version of the headset's firmware - * -- * 3: Headset firmware minor version -+ * 4: Headset firmware minor version - * Minor version of the headset's firmware - */ - /* -------------------------------------------------------------------------- */ -diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c ---- a/drivers/hid/hid-elecom.c -+++ b/drivers/hid/hid-elecom.c -@@ -79,7 +79,7 @@ static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, - case USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB: - case USB_DEVICE_ID_ELECOM_M_XT3URBK_018F: - case USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC: -- case USB_DEVICE_ID_ELECOM_M_XT4DRBK: -+ case USB_DEVICE_ID_ELECOM_M_XT4DRBK_00FD: - /* - * Report descriptor format: - * 12: button bit count -@@ -104,6 +104,7 @@ static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, - mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); - break; - case USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C: -+ case USB_DEVICE_ID_ELECOM_M_XT4DRBK_018E: - /* - * Report descriptor format: - * 22: button bit count -@@ -148,7 +149,8 @@ static const struct hid_device_id elecom_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK_00FD) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK_018E) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT2DRBK) }, -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -472,7 +472,8 @@ - #define USB_DEVICE_ID_ELECOM_M_XT3URBK_018F 0x018f - #define USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC 0x00fc - #define USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C 0x018c --#define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd -+#define USB_DEVICE_ID_ELECOM_M_XT4DRBK_00FD 0x00fd -+#define USB_DEVICE_ID_ELECOM_M_XT4DRBK_018E 0x018e - #define USB_DEVICE_ID_ELECOM_M_DT1URBK 0x00fe - #define USB_DEVICE_ID_ELECOM_M_DT1DRBK 0x00ff - #define USB_DEVICE_ID_ELECOM_M_DT2DRBK 0x018d -@@ -759,6 +760,7 @@ - #define I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720 0x837a - #define USB_DEVICE_ID_ITE_LENOVO_YOGA900 0x8396 - #define I2C_DEVICE_ID_ITE_LENOVO_YOGA_SLIM_7X_KEYBOARD 0x8987 -+#define I2C_DEVICE_ID_ITE_LENOVO_YOGA_SLIM_7X_G11_KEYBOARD 0x83db - #define USB_DEVICE_ID_ITE8595 0x8595 - #define USB_DEVICE_ID_ITE_MEDION_E1239T 0xce50 - -@@ -1283,6 +1285,9 @@ - #define USB_DEVICE_ID_SAMSUNG_WIRELESS_UNIVERSAL_KBD 0xa006 - #define USB_DEVICE_ID_SAMSUNG_WIRELESS_MULTI_HOGP_KBD 0xa064 - -+#define USB_VENDOR_ID_SDINNOVATION 0x36ae -+#define USB_DEVICE_ID_SDINNOVATION_GAMING_KBD 0xfeab -+ - #define USB_VENDOR_ID_SEMICO 0x1a2c - #define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023 - #define USB_DEVICE_ID_SEMICO_USB_KEYKOARD2 0x0027 -diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c ---- a/drivers/hid/hid-logitech-hidpp.c -+++ b/drivers/hid/hid-logitech-hidpp.c -@@ -4656,6 +4656,8 @@ static const struct hid_device_id hidpp_devices[] = { - HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) }, - { /* Logitech G502 Lightspeed Wireless Gaming Mouse over USB */ - HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08D) }, -+ { /* Logitech G502 X Lightspeed Wireless Gaming Mouse over USB */ -+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC098) }, - { /* Logitech G703 Gaming Mouse over USB */ - HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC087) }, - { /* Logitech G703 Hero Gaming Mouse over USB */ -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -79,6 +79,7 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) - #define MT_QUIRK_YOGABOOK9I BIT(24) - #define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25) -+#define MT_QUIRK_IGNORE_FEATURE_ID_MISMATCH BIT(26) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 -@@ -235,6 +236,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); - #define MT_CLS_APPLE_TOUCHBAR 0x0114 - #define MT_CLS_YOGABOOK9I 0x0115 - #define MT_CLS_EGALAX_P80H84 0x0116 -+#define MT_CLS_ASUS_ROG_Z13_FOLIO 0x0117 - #define MT_CLS_SIS 0x0457 - - #define MT_DEFAULT_MAXCONTACT 10 -@@ -405,6 +407,16 @@ static const struct mt_class mt_classes[] = { - .quirks = MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_ASUS_CUSTOM_UP }, -+ { .name = MT_CLS_ASUS_ROG_Z13_FOLIO, -+ .quirks = MT_QUIRK_ALWAYS_VALID | -+ MT_QUIRK_IGNORE_DUPLICATES | -+ MT_QUIRK_HOVERING | -+ MT_QUIRK_CONTACT_CNT_ACCURATE | -+ MT_QUIRK_STICKY_FINGERS | -+ MT_QUIRK_WIN8_PTP_BUTTONS | -+ MT_QUIRK_CONFIDENCE | -+ MT_QUIRK_IGNORE_FEATURE_ID_MISMATCH, -+ .export_all_inputs = true }, - { .name = MT_CLS_VTL, - .quirks = MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE | -@@ -507,6 +519,7 @@ static const struct attribute_group mt_attribute_group = { - - static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) - { -+ struct mt_device *td = hid_get_drvdata(hdev); - int ret; - u32 size = hid_report_len(report); - u8 *buf; -@@ -528,8 +541,14 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) - dev_warn(&hdev->dev, "failed to fetch feature %d\n", - report->id); - } else { -- /* The report ID in the request and the response should match */ -- if (report->id != buf[0]) { -+ /* -+ * The report ID in the request and the response should match. -+ * Some firmware (e.g. the ASUS ROG Z13 Folio -+ * touchpad) returns a mismatched ID on this specific fetch; -+ * tolerate it only for devices explicitly flagged as such. -+ */ -+ if (report->id != buf[0] && -+ !(td->mtclass.quirks & MT_QUIRK_IGNORE_FEATURE_ID_MISMATCH)) { - hid_err(hdev, "Returned feature report did not match the request\n"); - goto free; - } -@@ -2726,6 +2745,12 @@ static const struct hid_device_id mt_devices[] = { - HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, - I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288) }, - -+ /* Asus ROG Flow Z13 (2025) GZ302EA keyboard-cover touchpad */ -+ { .driver_data = MT_CLS_ASUS_ROG_Z13_FOLIO, -+ HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, -+ USB_VENDOR_ID_ASUSTEK, -+ USB_DEVICE_ID_ASUSTEK_ROG_Z13_FOLIO) }, -+ - /* Generic MT device */ - { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, - -diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c ---- a/drivers/hid/hid-oxp.c -+++ b/drivers/hid/hid-oxp.c -@@ -1552,9 +1552,9 @@ static int oxp_hid_probe(struct hid_device *hdev, - - static void oxp_hid_remove(struct hid_device *hdev) - { -- cancel_delayed_work(&drvdata.oxp_rgb_queue); -- cancel_delayed_work(&drvdata.oxp_btn_queue); -- cancel_delayed_work(&drvdata.oxp_mcu_init); -+ cancel_delayed_work_sync(&drvdata.oxp_rgb_queue); -+ cancel_delayed_work_sync(&drvdata.oxp_btn_queue); -+ cancel_delayed_work_sync(&drvdata.oxp_mcu_init); - hid_hw_close(hdev); - hid_hw_stop(hdev); - } -diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c ---- a/drivers/hid/hid-quirks.c -+++ b/drivers/hid/hid-quirks.c -@@ -183,6 +183,7 @@ static const struct hid_device_id hid_quirks[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52_PRO), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X65), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_SDINNOVATION, USB_DEVICE_ID_SDINNOVATION_GAMING_KBD), HID_QUIRK_ALWAYS_POLL }, - { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS }, - { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS }, - { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET }, -@@ -422,13 +423,14 @@ static const struct hid_device_id hid_have_special_driver[] = { - #endif - #if IS_ENABLED(CONFIG_HID_ELECOM) - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, -- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_018C) }, -- { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK_00FD) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK_018E) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT2DRBK) }, -diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c ---- a/drivers/hid/hid-roccat.c -+++ b/drivers/hid/hid-roccat.c -@@ -344,8 +344,6 @@ int roccat_connect(const struct class *klass, struct hid_device *hid, int report - return temp; - } - -- mutex_unlock(&devices_lock); -- - init_waitqueue_head(&device->wait); - INIT_LIST_HEAD(&device->readers); - mutex_init(&device->readers_lock); -@@ -356,6 +354,7 @@ int roccat_connect(const struct class *klass, struct hid_device *hid, int report - device->cbuf_end = 0; - device->report_size = report_size; - -+ mutex_unlock(&devices_lock); - return minor; - } - EXPORT_SYMBOL_GPL(roccat_connect); -@@ -369,15 +368,12 @@ void roccat_disconnect(int minor) - - mutex_lock(&devices_lock); - device = devices[minor]; -- mutex_unlock(&devices_lock); - - device->exist = 0; /* TODO exist maybe not needed */ - - device_destroy(device->dev->class, MKDEV(roccat_major, minor)); - -- mutex_lock(&devices_lock); - devices[minor] = NULL; -- mutex_unlock(&devices_lock); - - if (device->open) { - hid_hw_close(device->hid); -@@ -385,6 +381,8 @@ void roccat_disconnect(int minor) - } else { - roccat_free_device(device); - } -+ -+ mutex_unlock(&devices_lock); - } - EXPORT_SYMBOL_GPL(roccat_disconnect); - -diff --git a/drivers/hid/hid-winwing.c b/drivers/hid/hid-winwing.c ---- a/drivers/hid/hid-winwing.c -+++ b/drivers/hid/hid-winwing.c -@@ -315,7 +315,8 @@ static void winwing_haptic_rumble_cb(struct work_struct *work) - static int winwing_play_effect(struct input_dev *dev, void *context, - struct ff_effect *effect) - { -- struct winwing_drv_data *data = (struct winwing_drv_data *) context; -+ struct hid_device *hdev = input_get_drvdata(dev); -+ struct winwing_drv_data *data = hid_get_drvdata(hdev); - - if (effect->type != FF_RUMBLE) - return 0; -@@ -342,7 +343,12 @@ static int winwing_init_ff(struct hid_device *hdev, struct hid_input *hidinput) - - input_set_capability(hidinput->input, EV_FF, FF_RUMBLE); - -- return input_ff_create_memless(hidinput->input, data, -+ /* -+ * input_ff_create_memless() takes ownership of the context pointer -+ * and frees it on teardown; do not hand it the devm-managed drvdata. -+ * winwing_play_effect() fetches it from the input device instead. -+ */ -+ return input_ff_create_memless(hidinput->input, NULL, - winwing_play_effect); - } - -diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c ---- a/drivers/hid/i2c-hid/i2c-hid-core.c -+++ b/drivers/hid/i2c-hid/i2c-hid-core.c -@@ -123,9 +123,11 @@ static const struct i2c_hid_quirks { - __u32 quirks; - } i2c_hid_quirks[] = { - { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288, -- I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, -+ I2C_HID_QUIRK_NO_IRQ_AFTER_RESET | I2C_HID_QUIRK_BAD_INPUT_SIZE }, - { I2C_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15, - I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, -+ { USB_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_LENOVO_YOGA_SLIM_7X_G11_KEYBOARD, -+ I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, - { I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_3118, - I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, - { USB_VENDOR_ID_ALPS_JP, HID_ANY_ID, -diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c ---- a/drivers/hid/wacom_sys.c -+++ b/drivers/hid/wacom_sys.c -@@ -113,8 +113,9 @@ static int wacom_wac_pen_serial_enforce(struct hid_device *hdev, - - /* Queue events which have invalid tool type or serial number */ - for (i = 0; i < report->maxfield; i++) { -- for (j = 0; j < report->field[i]->maxusage; j++) { -- struct hid_field *field = report->field[i]; -+ struct hid_field *field = report->field[i]; -+ -+ for (j = 0; j < field->report_count; j++) { - struct hid_usage *usage = &field->usage[j]; - unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); - unsigned int offset; diff --git a/kernel/0562-hid-fixes.patch.sig b/kernel/0562-hid-fixes.patch.sig deleted file mode 100644 index b890b57..0000000 Binary files a/kernel/0562-hid-fixes.patch.sig and /dev/null differ diff --git a/kernel/0563-input-fixes-2.patch b/kernel/0563-input-fixes-2.patch deleted file mode 100644 index 1682da2..0000000 --- a/kernel/0563-input-fixes-2.patch +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c ---- a/drivers/input/keyboard/atkbd.c -+++ b/drivers/input/keyboard/atkbd.c -@@ -1938,6 +1938,14 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { - }, - .callback = atkbd_deactivate_fixup, - }, -+ { -+ /* Lenovo IdeaPad Slim 3 15IWC11 (83RR) */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "83RR"), -+ }, -+ .callback = atkbd_deactivate_fixup, -+ }, - { - /* Xiaomi Book Pro 14 (TM2424) */ - .matches = { -diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c ---- a/drivers/input/mouse/synaptics.c -+++ b/drivers/input/mouse/synaptics.c -@@ -192,6 +192,7 @@ static const char * const smbus_pnp_ids[] = { - "LEN2054", /* E480 */ - "LEN2055", /* E580 */ - "LEN2058", /* E490 */ -+ "LEN205b", /* T490 */ - "LEN2068", /* T14 Gen 1 */ - "SYN1221", /* TUXEDO InfinityBook Pro 14 v5 */ - "SYN3003", /* HP EliteBook 850 G1 */ -@@ -1839,8 +1840,10 @@ static int synaptics_setup_intertouch(struct psmouse *psmouse, - return -ENXIO; - } - -- /* Disable intertouch on known-broken board revisions */ -- if (info->board_id == 2722) { -+ /* Disable intertouch on known-broken T440p board revisions */ -+ if (info->board_id == 2722 && -+ psmouse_matches_pnp_id(psmouse, -+ (const char * const []){"LEN0036", NULL})) { - psmouse_info(psmouse, - "Disabling intertouch for board id %u\n", - info->board_id); -diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h ---- a/drivers/input/serio/i8042-acpipnpio.h -+++ b/drivers/input/serio/i8042-acpipnpio.h -@@ -671,6 +671,15 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { - }, - .driver_data = (void *)(SERIO_QUIRK_NOAUX) - }, -+ { -+ /* Fujitsu LIFEBOOK U7410 */ -+ /* Mux mode also disturbs the EC keyboard, causing spurious ACKs */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU CLIENT COMPUTING LIMITED"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U7410"), -+ }, -+ .driver_data = (void *)(SERIO_QUIRK_NOMUX) -+ }, - { - /* Gigabyte M912 */ - .matches = { -diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c ---- a/drivers/input/touchscreen/s6sy761.c -+++ b/drivers/input/touchscreen/s6sy761.c -@@ -500,10 +500,22 @@ static int s6sy761_suspend(struct device *dev) - static int s6sy761_resume(struct device *dev) - { - struct s6sy761_data *sdata = dev_get_drvdata(dev); -+ int err; -+ -+ err = s6sy761_power_on(sdata); -+ if (err) -+ return err; - - enable_irq(sdata->client->irq); - -- return s6sy761_power_on(sdata); -+ guard(mutex)(&sdata->input->mutex); -+ -+ if (!input_device_enabled(sdata->input)) -+ return 0; -+ -+ err = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON); -+ -+ return err; - } - - static const struct dev_pm_ops s6sy761_pm_ops = { diff --git a/kernel/0563-input-fixes-2.patch.sig b/kernel/0563-input-fixes-2.patch.sig deleted file mode 100644 index 36b52ad..0000000 Binary files a/kernel/0563-input-fixes-2.patch.sig and /dev/null differ diff --git a/kernel/0565-i2c-asue140d-touchpad-100khz.patch b/kernel/0565-i2c-asue140d-touchpad-100khz.patch deleted file mode 100644 index 01748b9..0000000 --- a/kernel/0565-i2c-asue140d-touchpad-100khz.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c ---- a/drivers/i2c/i2c-core-acpi.c -+++ b/drivers/i2c/i2c-core-acpi.c -@@ -373,6 +373,7 @@ static const struct acpi_device_id i2c_acpi_force_100khz_device_ids[] = { - * the device works without issues on Windows at what is expected to be - * a 400KHz frequency. The root cause of the issue is not known. - */ -+ { "ASUE140D", 0 }, - { "DLL0945", 0 }, - { "ELAN0678", 0 }, - { "ELAN06FA", 0 }, diff --git a/kernel/0565-i2c-asue140d-touchpad-100khz.patch.sig b/kernel/0565-i2c-asue140d-touchpad-100khz.patch.sig deleted file mode 100644 index 8742aa9..0000000 Binary files a/kernel/0565-i2c-asue140d-touchpad-100khz.patch.sig and /dev/null differ diff --git a/kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch b/kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch deleted file mode 100644 index d7870a2..0000000 --- a/kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -1480,12 +1480,14 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) - return ret; - } - -- for (int r = 0; r < ARRAY_SIZE(asus_report_id_init); r++) { -- if (asus_has_report_id(hdev, asus_report_id_init[r])) { -- ret = asus_kbd_init(hdev, asus_report_id_init[r]); -- if (ret < 0) -- hid_warn(hdev, "Failed to initialize 0x%x: %d.\n", -- asus_report_id_init[r], ret); -+ if (!drvdata->tp) { -+ for (int r = 0; r < ARRAY_SIZE(asus_report_id_init); r++) { -+ if (asus_has_report_id(hdev, asus_report_id_init[r])) { -+ ret = asus_kbd_init(hdev, asus_report_id_init[r]); -+ if (ret < 0) -+ hid_warn(hdev, "Failed to initialize 0x%x: %d.\n", -+ asus_report_id_init[r], ret); -+ } - } - } - diff --git a/kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch.sig b/kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch.sig deleted file mode 100644 index 42cf5b7..0000000 Binary files a/kernel/0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch.sig and /dev/null differ diff --git a/kernel/0601-thunderbolt-updates.patch b/kernel/0601-thunderbolt-updates.patch deleted file mode 100644 index 7a0d9ca..0000000 --- a/kernel/0601-thunderbolt-updates.patch +++ /dev/null @@ -1,1131 +0,0 @@ -diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c ---- a/drivers/net/thunderbolt/main.c -+++ b/drivers/net/thunderbolt/main.c -@@ -1362,7 +1362,7 @@ static void tbnet_generate_mac(struct net_device *dev) - dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - } - --static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id) -+static int tbnet_probe(struct tb_service *svc) - { - struct tb_xdomain *xd = tb_service_parent(svc); - struct net_device *dev; -@@ -1482,7 +1482,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tbnet_pm_ops, tbnet_suspend, tbnet_resume); - - static const struct tb_service_id tbnet_ids[] = { - { TB_SERVICE("network", 1) }, -- { }, -+ { } - }; - MODULE_DEVICE_TABLE(tbsvc, tbnet_ids); - -diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c ---- a/drivers/thunderbolt/debugfs.c -+++ b/drivers/thunderbolt/debugfs.c -@@ -136,13 +136,13 @@ static void *validate_and_copy_from_user(const void __user *user_buf, - if (!access_ok(user_buf, *count)) - return ERR_PTR(-EFAULT); - -- buf = (void *)get_zeroed_page(GFP_KERNEL); -+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - nbytes = min_t(size_t, *count, PAGE_SIZE); - if (copy_from_user(buf, user_buf, nbytes)) { -- free_page((unsigned long)buf); -+ kfree(buf); - return ERR_PTR(-EFAULT); - } - -@@ -265,7 +265,7 @@ static ssize_t regs_write(struct tb_switch *sw, struct tb_port *port, - out: - pm_runtime_mark_last_busy(&sw->dev); - pm_runtime_put_autosuspend(&sw->dev); -- free_page((unsigned long)buf); -+ kfree(buf); - - return ret < 0 ? ret : count; - } -@@ -406,7 +406,7 @@ static ssize_t port_sb_regs_write(struct file *file, const char __user *user_buf - out: - pm_runtime_mark_last_busy(&sw->dev); - pm_runtime_put_autosuspend(&sw->dev); -- free_page((unsigned long)buf); -+ kfree(buf); - - return ret < 0 ? ret : count; - } -@@ -439,7 +439,7 @@ static ssize_t retimer_sb_regs_write(struct file *file, - out: - pm_runtime_mark_last_busy(&rt->dev); - pm_runtime_put_autosuspend(&rt->dev); -- free_page((unsigned long)buf); -+ kfree(buf); - - return ret < 0 ? ret : count; - } -@@ -652,7 +652,7 @@ margining_ber_level_write(struct file *file, const char __user *user_buf, - margining->ber_level = val; - - out_free: -- free_page((unsigned long)buf); -+ kfree(buf); - out_unlock: - mutex_unlock(&tb->lock); - -@@ -829,7 +829,7 @@ margining_lanes_write(struct file *file, const char __user *user_buf, - } - } - -- free_page((unsigned long)buf); -+ kfree(buf); - - if (lane == -1) - return -EINVAL; -@@ -958,7 +958,7 @@ margining_error_counter_write(struct file *file, const char __user *user_buf, - else - goto err_free; - -- free_page((unsigned long)buf); -+ kfree(buf); - - scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) { - if (!margining->software) -@@ -970,7 +970,7 @@ margining_error_counter_write(struct file *file, const char __user *user_buf, - return count; - - err_free: -- free_page((unsigned long)buf); -+ kfree(buf); - return -EINVAL; - } - -@@ -1116,7 +1116,7 @@ static ssize_t margining_mode_write(struct file *file, - mutex_unlock(&tb->lock); - - out_free: -- free_page((unsigned long)buf); -+ kfree(buf); - return ret ? ret : count; - } - -@@ -1503,7 +1503,7 @@ static ssize_t margining_test_write(struct file *file, - mutex_unlock(&tb->lock); - - out_free: -- free_page((unsigned long)buf); -+ kfree(buf); - return ret ? ret : count; - } - -@@ -1569,7 +1569,7 @@ static ssize_t margining_margin_write(struct file *file, - mutex_unlock(&tb->lock); - - out_free: -- free_page((unsigned long)buf); -+ kfree(buf); - return ret ? ret : count; - } - -@@ -1624,7 +1624,7 @@ static ssize_t margining_eye_write(struct file *file, - ret = -EINVAL; - } - -- free_page((unsigned long)buf); -+ kfree(buf); - return ret ? ret : count; - } - -@@ -1934,7 +1934,7 @@ static ssize_t counters_write(struct file *file, const char __user *user_buf, - out: - pm_runtime_mark_last_busy(&sw->dev); - pm_runtime_put_autosuspend(&sw->dev); -- free_page((unsigned long)buf); -+ kfree(buf); - - return ret < 0 ? ret : count; - } -diff --git a/drivers/thunderbolt/dma_test.c b/drivers/thunderbolt/dma_test.c ---- a/drivers/thunderbolt/dma_test.c -+++ b/drivers/thunderbolt/dma_test.c -@@ -636,7 +636,7 @@ static void dma_test_debugfs_init(struct tb_service *svc) - debugfs_create_file("test", 0200, debugfs_dir, svc, &test_fops); - } - --static int dma_test_probe(struct tb_service *svc, const struct tb_service_id *id) -+static int dma_test_probe(struct tb_service *svc) - { - struct tb_xdomain *xd = tb_service_parent(svc); - struct dma_test *dt; -@@ -689,7 +689,7 @@ static const struct dev_pm_ops dma_test_pm_ops = { - - static const struct tb_service_id dma_test_ids[] = { - { TB_SERVICE("dma_test", 1) }, -- { }, -+ { } - }; - MODULE_DEVICE_TABLE(tbsvc, dma_test_ids); - -diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -77,12 +77,10 @@ static int tb_service_probe(struct device *dev) - { - struct tb_service *svc = tb_to_service(dev); - struct tb_service_driver *driver; -- const struct tb_service_id *id; - - driver = container_of(dev->driver, struct tb_service_driver, driver); -- id = __tb_service_match(dev, &driver->driver); - -- return driver->probe(svc, id); -+ return driver->probe(svc); - } - - static void tb_service_remove(struct device *dev) -@@ -790,6 +788,21 @@ int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, - transmit_ring, receive_path, receive_ring); - } - -+static void tb_domain_reset_interface(struct tb *tb) -+{ -+ struct tb_nhi *nhi = tb->nhi; -+ -+ if (!nhi->ops->reset_interface) -+ return; -+ -+ guard(mutex)(&tb->lock); -+ -+ /* The reset clears the ring state so stop the control channel */ -+ tb_ctl_stop(tb->ctl); -+ nhi->ops->reset_interface(nhi); -+ tb_ctl_start(tb->ctl); -+} -+ - /** - * tb_domain_disconnect_xdomain_paths() - Disable DMA paths for XDomain - * @tb: Domain disabling the DMA paths -@@ -812,11 +825,20 @@ int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, - int transmit_path, int transmit_ring, - int receive_path, int receive_ring) - { -+ int ret; -+ - if (!tb->cm_ops->disconnect_xdomain_paths) - return -ENOTSUPP; - -- return tb->cm_ops->disconnect_xdomain_paths(tb, xd, transmit_path, -+ ret = tb->cm_ops->disconnect_xdomain_paths(tb, xd, transmit_path, - transmit_ring, receive_path, receive_ring); -+ if (ret) -+ return ret; -+ -+ if (tb->nhi->quirks & QUIRK_RESET_DMA_ON_TEARDOWN) -+ tb_domain_reset_interface(tb); -+ -+ return 0; - } - - static int disconnect_xdomain(struct device *dev, void *data) -diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c ---- a/drivers/thunderbolt/nhi.c -+++ b/drivers/thunderbolt/nhi.c -@@ -235,6 +235,12 @@ static void ring_write_descriptors(struct tb_ring *ring) - { - struct ring_frame *frame, *n; - struct ring_desc *descriptor; -+ u32 flags; -+ -+ flags = RING_DESC_POSTED; -+ if (!(ring->flags & RING_FLAG_NO_INTERRUPT)) -+ flags |= RING_DESC_INTERRUPT; -+ - list_for_each_entry_safe(frame, n, &ring->queue, list) { - if (ring_full(ring)) - break; -@@ -242,7 +248,7 @@ static void ring_write_descriptors(struct tb_ring *ring) - descriptor = &ring->descriptors[ring->head]; - descriptor->phys = frame->buffer_phy; - descriptor->time = 0; -- descriptor->flags = RING_DESC_POSTED | RING_DESC_INTERRUPT; -+ descriptor->flags = flags; - if (ring->is_tx) { - descriptor->length = frame->size; - descriptor->eof = frame->eof; -@@ -339,8 +345,9 @@ EXPORT_SYMBOL_GPL(__tb_ring_enqueue); - * @ring: Ring to poll - * - * This function can be called when @start_poll callback of the @ring -- * has been called. It will read one completed frame from the ring and -- * return it to the caller. -+ * has been called or the ring is created with %RING_FLAG_NO_INTERRUPT. -+ * It will read one completed frame from the ring and return it to the -+ * caller. - * - * Return: Pointer to &struct ring_frame, %NULL if there is no more - * completed frames. -@@ -538,6 +545,12 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size, - dev_dbg(nhi->dev, "allocating %s ring %d of size %d\n", - transmit ? "TX" : "RX", hop, size); - -+ if ((flags & RING_FLAG_NO_INTERRUPT) && start_poll) { -+ dev_WARN(nhi->dev, -+ "start_poll() and NO_INTERRUPT cannot be used at the same time\n"); -+ return NULL; -+ } -+ - ring = kzalloc_obj(*ring); - if (!ring) - return NULL; -@@ -568,7 +581,7 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size, - if (!ring->descriptors) - goto err_free_ring; - -- if (nhi->ops->request_ring_irq) { -+ if (!(flags & RING_FLAG_NO_INTERRUPT) && nhi->ops->request_ring_irq) { - if (nhi->ops->request_ring_irq(ring, flags & RING_FLAG_NO_SUSPEND)) - goto err_free_descs; - } -@@ -701,7 +714,8 @@ void tb_ring_start(struct tb_ring *ring) - ring_iowrite32options(ring, flags, 0); - } - -- ring_interrupt_active(ring, true); -+ if (!(ring->flags & RING_FLAG_NO_INTERRUPT)) -+ ring_interrupt_active(ring, true); - ring->running = true; - err: - spin_unlock(&ring->lock); -@@ -761,7 +775,8 @@ void tb_ring_stop(struct tb_ring *ring) - RING_TYPE(ring), ring->hop); - goto err; - } -- ring_interrupt_active(ring, false); -+ if (!(ring->flags & RING_FLAG_NO_INTERRUPT)) -+ ring_interrupt_active(ring, false); - - ring_iowrite32options(ring, 0, 0); - ring_iowrite64desc(ring, 0, 0); -@@ -1160,6 +1175,32 @@ static void nhi_reset(struct tb_nhi *nhi) - dev_warn(nhi->dev, "timeout resetting host router\n"); - } - -+/** -+ * nhi_reset_interface() - Reset the host interface -+ * @nhi: Host interface to reset -+ * -+ * Brings the registers in the memory BAR back to their default state and -+ * clears the End-to-End Flow Control state. The caller is responsible for -+ * stopping the control channel over the reset because it clears the ring -+ * state as well. -+ */ -+void nhi_reset_interface(struct tb_nhi *nhi) -+{ -+ u32 val; -+ -+ val = ioread32(nhi->iobase + REG_CAPS); -+ /* Only v1 host interfaces implement the reset */ -+ if (FIELD_GET(REG_CAPS_VERSION_MASK, val) >= REG_CAPS_VERSION_2) -+ return; -+ -+ dev_dbg(nhi->dev, "issuing host interface reset\n"); -+ -+ iowrite32(REG_HOST_INTERFACE_RESET_RST, -+ nhi->iobase + REG_HOST_INTERFACE_RESET); -+ /* Wait for tHIReset (10 ms) to complete */ -+ usleep_range(10000, 20000); -+} -+ - static struct tb *nhi_select_cm(struct tb_nhi *nhi) - { - struct tb *tb; -@@ -1235,6 +1276,8 @@ int nhi_probe(struct tb_nhi *nhi) - - dev_dbg(dev, "NHI initialized, starting thunderbolt\n"); - -+ nhi->host_reset = host_reset; -+ - res = tb_domain_add(tb, host_reset); - if (res) { - /* -diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h ---- a/drivers/thunderbolt/nhi.h -+++ b/drivers/thunderbolt/nhi.h -@@ -36,6 +36,8 @@ irqreturn_t nhi_msi(int irq, void *data); - irqreturn_t ring_msix(int irq, void *data); - int nhi_probe(struct tb_nhi *nhi); - void nhi_shutdown(struct tb_nhi *nhi); -+void nhi_reset_interface(struct tb_nhi *nhi); -+ - extern const struct dev_pm_ops nhi_pm_ops; - - /** -@@ -52,6 +54,7 @@ extern const struct dev_pm_ops nhi_pm_ops; - * @release_ring_irq: NHI specific interrupt release hook - * @is_present: Whether the device is currently present on the parent bus - * @init_interrupts: NHI specific interrupt initialization hook -+ * @reset_interface: Resets the host interface - */ - struct tb_nhi_ops { - int (*init)(struct tb_nhi *nhi); -@@ -66,6 +69,7 @@ struct tb_nhi_ops { - void (*release_ring_irq)(struct tb_ring *ring); - bool (*is_present)(struct tb_nhi *nhi); - int (*init_interrupts)(struct tb_nhi *nhi); -+ void (*reset_interface)(struct tb_nhi *nhi); - }; - - /* -@@ -116,11 +120,24 @@ struct tb_nhi_ops { - #define PCI_DEVICE_ID_INTEL_PTL_P_NHI0 0xe433 - #define PCI_DEVICE_ID_INTEL_PTL_P_NHI1 0xe434 - -+#define PCI_DEVICE_ID_AMD_1AH_M60H_NHI0 0x1120 -+#define PCI_DEVICE_ID_AMD_1AH_M60H_NHI1 0x1121 -+#define PCI_DEVICE_ID_AMD_1AH_M68H_NHI0 0x113b -+#define PCI_DEVICE_ID_AMD_1AH_M68H_NHI1 0x113c -+#define PCI_DEVICE_ID_AMD_1AH_M80H_NHI0 0x1155 -+#define PCI_DEVICE_ID_AMD_1AH_M80H_NHI1 0x1158 -+#define PCI_DEVICE_ID_AMD_1AH_M80H_NHI2 0x1159 -+#define PCI_DEVICE_ID_AMD_1AH_M24H_NHI0 0x151c -+#define PCI_DEVICE_ID_AMD_1AH_M24H_NHI1 0x151d -+#define PCI_DEVICE_ID_AMD_1AH_M70H_NHI0 0x158d -+#define PCI_DEVICE_ID_AMD_1AH_M70H_NHI1 0x158e -+ - #define PCI_CLASS_SERIAL_USB_USB4 0x0c0340 - - /* Host interface quirks */ --#define QUIRK_AUTO_CLEAR_INT BIT(0) --#define QUIRK_E2E BIT(1) -+#define QUIRK_AUTO_CLEAR_INT BIT(0) -+#define QUIRK_E2E BIT(1) -+#define QUIRK_RESET_DMA_ON_TEARDOWN BIT(2) - - /* - * Minimal number of vectors when we use MSI-X. Two for control channel -diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h ---- a/drivers/thunderbolt/nhi_regs.h -+++ b/drivers/thunderbolt/nhi_regs.h -@@ -115,6 +115,10 @@ struct ring_desc { - #define REG_CAPS_VERSION_MASK GENMASK(23, 16) - #define REG_CAPS_VERSION_2 0x40 - -+/* Host Interface Reset - resets TX/RX rings and E2E flow control counters */ -+#define REG_HOST_INTERFACE_RESET 0x39858 -+#define REG_HOST_INTERFACE_RESET_RST BIT(0) -+ - #define REG_DMA_MISC 0x39864 - #define REG_DMA_MISC_INT_AUTO_CLEAR BIT(2) - #define REG_DMA_MISC_DISABLE_AUTO_CLEAR BIT(17) -diff --git a/drivers/thunderbolt/pci.c b/drivers/thunderbolt/pci.c ---- a/drivers/thunderbolt/pci.c -+++ b/drivers/thunderbolt/pci.c -@@ -62,6 +62,27 @@ static void nhi_pci_check_quirks(struct tb_nhi_pci *nhi_pci) - nhi->quirks |= QUIRK_E2E; - break; - } -+ } else if (pdev->vendor == PCI_VENDOR_ID_AMD) { -+ switch (pdev->device) { -+ case PCI_DEVICE_ID_AMD_1AH_M60H_NHI0: -+ case PCI_DEVICE_ID_AMD_1AH_M60H_NHI1: -+ case PCI_DEVICE_ID_AMD_1AH_M68H_NHI0: -+ case PCI_DEVICE_ID_AMD_1AH_M68H_NHI1: -+ case PCI_DEVICE_ID_AMD_1AH_M80H_NHI0: -+ case PCI_DEVICE_ID_AMD_1AH_M80H_NHI1: -+ case PCI_DEVICE_ID_AMD_1AH_M80H_NHI2: -+ case PCI_DEVICE_ID_AMD_1AH_M24H_NHI0: -+ case PCI_DEVICE_ID_AMD_1AH_M24H_NHI1: -+ case PCI_DEVICE_ID_AMD_1AH_M70H_NHI0: -+ case PCI_DEVICE_ID_AMD_1AH_M70H_NHI1: -+ /* -+ * These AMD hosts may hang the Tx ring when the -+ * DMA paths are torn down so they need the host -+ * interface reset after each teardown. -+ */ -+ nhi->quirks |= QUIRK_RESET_DMA_ON_TEARDOWN; -+ break; -+ } - } - } - -@@ -112,7 +133,6 @@ static int nhi_pci_init_msi(struct tb_nhi *nhi) - { - struct tb_nhi_pci *nhi_pci = nhi_to_pci(nhi); - struct pci_dev *pdev = to_pci_dev(nhi->dev); -- struct device *dev = &pdev->dev; - int res, irq, nvec; - - ida_init(&nhi_pci->msix_ida); -@@ -139,7 +159,7 @@ static int nhi_pci_init_msi(struct tb_nhi *nhi) - res = devm_request_irq(&pdev->dev, irq, nhi_msi, - IRQF_NO_SUSPEND, "thunderbolt", nhi); - if (res) -- return dev_err_probe(dev, res, "request_irq failed, aborting\n"); -+ return res; - } - - return 0; -@@ -230,7 +250,7 @@ static void nhi_pci_ring_release_msix(struct tb_ring *ring) - ring->irq = 0; - } - --static void nhi_pci_shutdown(struct tb_nhi *nhi) -+static void nhi_pci_release_irq(struct tb_nhi *nhi) - { - struct tb_nhi_pci *nhi_pci = nhi_to_pci(nhi); - struct pci_dev *pdev = to_pci_dev(nhi->dev); -@@ -256,9 +276,10 @@ static const struct tb_nhi_ops pci_nhi_default_ops = { - .post_nvm_auth = nhi_pci_complete_dma_port, - .request_ring_irq = nhi_pci_ring_request_msix, - .release_ring_irq = nhi_pci_ring_release_msix, -- .shutdown = nhi_pci_shutdown, -+ .shutdown = nhi_pci_release_irq, - .is_present = nhi_pci_is_present, - .init_interrupts = nhi_pci_init_msi, -+ .reset_interface = nhi_reset_interface, - }; - - /* Ice Lake specific NHI operations */ -@@ -424,7 +445,7 @@ static int icl_nhi_resume(struct tb_nhi *nhi) - - static void icl_nhi_shutdown(struct tb_nhi *nhi) - { -- nhi_pci_shutdown(nhi); -+ nhi_pci_release_irq(nhi); - - icl_nhi_force_power(nhi, false); - } -@@ -442,6 +463,7 @@ static const struct tb_nhi_ops icl_nhi_ops = { - .release_ring_irq = nhi_pci_ring_release_msix, - .is_present = nhi_pci_is_present, - .init_interrupts = nhi_pci_init_msi, -+ .reset_interface = nhi_reset_interface, - }; - - static int nhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -@@ -479,11 +501,19 @@ static int nhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) - return nhi_probe(&nhi_pci->nhi); - } - --static void nhi_pci_remove(struct pci_dev *pdev) -+static void nhi_pci_do_remove(struct pci_dev *pdev, bool reset) - { - struct tb *tb = pci_get_drvdata(pdev); - struct tb_nhi *nhi = tb->nhi; - -+ /* -+ * On system shutdown/reboot force a host router reset so the -+ * connection manager asserts DPR on connected Thunderbolt 3 devices -+ * before the router tree is removed (see tb_stop()). -+ */ -+ if (reset) -+ nhi->host_reset = true; -+ - pm_runtime_get_sync(&pdev->dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_forbid(&pdev->dev); -@@ -493,6 +523,16 @@ static void nhi_pci_remove(struct pci_dev *pdev) - nhi_shutdown(nhi); - } - -+static void nhi_pci_remove(struct pci_dev *pdev) -+{ -+ nhi_pci_do_remove(pdev, false); -+} -+ -+static void nhi_pci_shutdown(struct pci_dev *pdev) -+{ -+ nhi_pci_do_remove(pdev, true); -+} -+ - static struct pci_device_id nhi_ids[] = { - /* - * We have to specify class, the TB bridges use the same device and -@@ -593,7 +633,7 @@ static struct pci_driver nhi_driver = { - .id_table = nhi_ids, - .probe = nhi_pci_probe, - .remove = nhi_pci_remove, -- .shutdown = nhi_pci_remove, -+ .shutdown = nhi_pci_shutdown, - .driver.pm = &nhi_pm_ops, - }; - -diff --git a/drivers/thunderbolt/stream.c b/drivers/thunderbolt/stream.c ---- a/drivers/thunderbolt/stream.c -+++ b/drivers/thunderbolt/stream.c -@@ -9,10 +9,12 @@ - - #define pr_fmt(fmt) "tbstream: " fmt - -+#include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -128,6 +130,7 @@ struct tbstream_ring { - * @out_hopid: Out HopID - * @ring_size: Size of the rings - * @throttling: Interrupt throttling rate in ns -+ * @busy_poll: Instead of interrupts, busy poll the rings - * @users: Number of times @cdev has been opened - * @closed: CLOSE packet was received - * @removed: Userspace removed the ConfigFS group underneath. -@@ -147,6 +150,7 @@ struct tbstream_dev { - int out_hopid; - unsigned int ring_size; - unsigned int throttling; -+ bool busy_poll; - int users; - bool closed; - bool removed; -@@ -536,10 +540,39 @@ tbstream_dev_send_data(struct tbstream_dev *sdev, struct iov_iter *from, - return tb_ring_tx(sdev->tx_ring.ring, &sf->frame); - } - -+static void -+tbstream_dev_poll_ring(struct tbstream_dev *sdev, struct tbstream_ring *ring) -+{ -+ struct ring_frame *frame; -+ -+ if (!sdev->busy_poll) -+ return; -+ -+ while ((frame = tb_ring_poll(ring->ring))) -+ frame->callback(ring->ring, frame, false); -+} -+ - static int tbstream_dev_send_close(struct tbstream_dev *sdev) - { - struct tbstream_frame *sf; - -+ if (sdev->busy_poll) { -+ /* -+ * When busy polling it's the write(2) path that -+ * advances the completions so it is possible that the -+ * ring is full at this point. Advance the ring here so -+ * that there is room for the CLOSE packet to be sent. -+ */ -+ ktime_t timeout = ktime_add_ms(ktime_get(), 500); -+ -+ do { -+ if (tbstream_ring_available(&sdev->tx_ring)) -+ break; -+ tbstream_dev_poll_ring(sdev, &sdev->tx_ring); -+ fsleep(15); -+ } while (ktime_before(ktime_get(), timeout)); -+ } -+ - sf = tbstream_dev_alloc_tx(sdev, TBSTREAM_CLOSE, NULL, SZ_256); - if (IS_ERR(sf)) - return PTR_ERR(sf); -@@ -549,12 +582,15 @@ static int tbstream_dev_send_close(struct tbstream_dev *sdev) - static int tbstream_dev_start(struct tbstream_dev *sdev) - { - struct tb_xdomain *xd = tbstream_dev_xdomain(sdev); -+ unsigned int flags = RING_FLAG_FRAME | RING_FLAG_E2E; - u16 sof_mask, eof_mask; - struct tb_ring *ring; - int ret, e2e_tx_hop; - -- ring = tb_ring_alloc_tx(xd->tb->nhi, -1, sdev->ring_size, -- RING_FLAG_FRAME | RING_FLAG_E2E); -+ if (sdev->busy_poll) -+ flags |= RING_FLAG_NO_INTERRUPT; -+ -+ ring = tb_ring_alloc_tx(xd->tb->nhi, -1, sdev->ring_size, flags); - if (!ring) - return -ENOMEM; - sdev->tx_ring.ring = ring; -@@ -567,9 +603,8 @@ static int tbstream_dev_start(struct tbstream_dev *sdev) - sof_mask = BIT(TBSTREAM_FRAME_START); - eof_mask = BIT(TBSTREAM_DATA) | BIT(TBSTREAM_CLOSE); - -- ring = tb_ring_alloc_rx(xd->tb->nhi, -1, sdev->ring_size, -- RING_FLAG_FRAME | RING_FLAG_E2E, e2e_tx_hop, -- sof_mask, eof_mask, NULL, NULL); -+ ring = tb_ring_alloc_rx(xd->tb->nhi, -1, sdev->ring_size, flags, -+ e2e_tx_hop, sof_mask, eof_mask, NULL, NULL); - if (!ring) { - ret = -ENOMEM; - goto err_free_tx_buffers; -@@ -607,15 +642,43 @@ static int tbstream_dev_start(struct tbstream_dev *sdev) - return ret; - } - -+static bool tbstream_dev_tx_drained(const struct tbstream_dev *sdev) -+{ -+ const struct tbstream_ring *ring = &sdev->tx_ring; -+ -+ /* -+ * Everything is completed when number of free TX slots is back -+ * to the maximum. -+ */ -+ return ring->prod - ring->cons == tb_ring_size(ring->ring) - 1; -+} -+ - static void tbstream_dev_stop(struct tbstream_dev *sdev) - { - struct tb_xdomain *xd; - -- /* Wait for the ring to complete any outstanding frames */ -- tb_ring_flush(sdev->tx_ring.ring, 500); -- tb_ring_stop(sdev->tx_ring.ring); -- tb_ring_flush(sdev->rx_ring.ring, 500); -- tb_ring_stop(sdev->rx_ring.ring); -+ if (sdev->busy_poll) { -+ /* -+ * When busy polling we must advance the ring ourselves -+ * to push all outstanding frames on the wire. -+ */ -+ ktime_t timeout = ktime_add_ms(ktime_get(), 500); -+ -+ do { -+ if (tbstream_dev_tx_drained(sdev)) -+ break; -+ tbstream_dev_poll_ring(sdev, &sdev->tx_ring); -+ fsleep(15); -+ } while (ktime_before(ktime_get(), timeout)); -+ -+ tb_ring_stop(sdev->tx_ring.ring); -+ tb_ring_stop(sdev->rx_ring.ring); -+ } else { -+ tb_ring_flush(sdev->tx_ring.ring, 500); -+ tb_ring_stop(sdev->tx_ring.ring); -+ tb_ring_flush(sdev->rx_ring.ring, 500); -+ tb_ring_stop(sdev->rx_ring.ring); -+ } - - xd = tbstream_dev_xdomain(sdev); - if (xd) { -@@ -633,10 +696,24 @@ static void tbstream_dev_stop(struct tbstream_dev *sdev) - sdev->tx_ring.ring = NULL; - } - -+/* Use only with read_iter/write_iter() to handle nowait */ -+static int tbstream_dev_lock(struct tbstream_dev *sdev, bool nowait) -+{ -+ if (nowait) { -+ if (!mutex_trylock(&sdev->lock)) -+ return -EAGAIN; -+ } else { -+ if (mutex_lock_interruptible(&sdev->lock)) -+ return -ERESTARTSYS; -+ } -+ return 0; -+} -+ - static ssize_t - tbstream_dev_fops_read_iter(struct kiocb *kiocb, struct iov_iter *to) - { - struct file *file = kiocb->ki_filp; -+ bool nowait = file->f_flags & O_NONBLOCK || kiocb->ki_flags & IOCB_NOWAIT; - struct tbstream_dev *sdev = to_tbstream_dev(file->private_data); - size_t nbytes; - int ret; -@@ -645,31 +722,50 @@ tbstream_dev_fops_read_iter(struct kiocb *kiocb, struct iov_iter *to) - if (ret) - return ret; - -- if (mutex_lock_interruptible(&sdev->lock)) -- return -ERESTARTSYS; -+ ret = tbstream_dev_lock(sdev, nowait); -+ if (ret) -+ return ret; - -- while (!tbstream_ring_available(&sdev->rx_ring)) { -- mutex_unlock(&sdev->lock); -- -- if (file->f_flags & O_NONBLOCK) -- return -EAGAIN; -- ret = wait_event_interruptible(sdev->wait, -- tbstream_ring_available(&sdev->rx_ring) || -- tbstream_dev_valid(sdev) != 0 || -- tbstream_dev_closed(sdev) || -- tbstream_dev_removed(sdev)); -- if (ret) -- return ret; -+ for (;;) { -+ /* When busy polling, advance any completions manually */ -+ tbstream_dev_poll_ring(sdev, &sdev->rx_ring); - - ret = tbstream_dev_valid(sdev); -+ if (ret) { -+ mutex_unlock(&sdev->lock); -+ return ret; -+ } -+ -+ if (tbstream_dev_closed(sdev) || tbstream_dev_removed(sdev)) { -+ mutex_unlock(&sdev->lock); -+ return 0; -+ } -+ -+ if (tbstream_ring_available(&sdev->rx_ring)) -+ break; -+ -+ mutex_unlock(&sdev->lock); -+ -+ if (nowait) -+ return -EAGAIN; -+ -+ if (sdev->busy_poll) { -+ if (signal_pending(current)) -+ return -ERESTARTSYS; -+ cond_resched(); -+ } else { -+ ret = wait_event_interruptible(sdev->wait, -+ tbstream_ring_available(&sdev->rx_ring) || -+ tbstream_dev_valid(sdev) != 0 || -+ tbstream_dev_closed(sdev) || -+ tbstream_dev_removed(sdev)); -+ if (ret) -+ return ret; -+ } -+ -+ ret = tbstream_dev_lock(sdev, nowait); - if (ret) - return ret; -- -- if (tbstream_dev_closed(sdev) || tbstream_dev_removed(sdev)) -- return 0; -- -- if (mutex_lock_interruptible(&sdev->lock)) -- return -ERESTARTSYS; - } - - nbytes = 0; -@@ -729,6 +825,7 @@ static ssize_t - tbstream_dev_fops_write_iter(struct kiocb *kiocb, struct iov_iter *from) - { - struct file *file = kiocb->ki_filp; -+ bool nowait = file->f_flags & O_NONBLOCK || kiocb->ki_flags & IOCB_NOWAIT; - struct tbstream_dev *sdev = to_tbstream_dev(file->private_data); - size_t nbytes; - int ret; -@@ -737,31 +834,49 @@ tbstream_dev_fops_write_iter(struct kiocb *kiocb, struct iov_iter *from) - if (ret) - return ret; - -- if (mutex_lock_interruptible(&sdev->lock)) -- return -ERESTARTSYS; -+ ret = tbstream_dev_lock(sdev, nowait); -+ if (ret) -+ return ret; - -- while (!tbstream_ring_available(&sdev->tx_ring)) { -- mutex_unlock(&sdev->lock); -- -- if (file->f_flags & O_NONBLOCK) -- return -EAGAIN; -- ret = wait_event_interruptible(sdev->wait, -- tbstream_ring_available(&sdev->tx_ring) || -- tbstream_dev_valid(sdev) != 0 || -- tbstream_dev_closed(sdev) || -- tbstream_dev_removed(sdev)); -- if (ret) -- return ret; -+ for (;;) { -+ tbstream_dev_poll_ring(sdev, &sdev->tx_ring); - - ret = tbstream_dev_valid(sdev); -+ if (ret) { -+ mutex_unlock(&sdev->lock); -+ return ret; -+ } -+ -+ if (tbstream_dev_closed(sdev) || tbstream_dev_removed(sdev)) { -+ mutex_unlock(&sdev->lock); -+ return -ENXIO; -+ } -+ -+ if (tbstream_ring_available(&sdev->tx_ring)) -+ break; -+ -+ mutex_unlock(&sdev->lock); -+ -+ if (nowait) -+ return -EAGAIN; -+ -+ if (sdev->busy_poll) { -+ if (signal_pending(current)) -+ return -ERESTARTSYS; -+ cond_resched(); -+ } else { -+ ret = wait_event_interruptible(sdev->wait, -+ tbstream_ring_available(&sdev->tx_ring) || -+ tbstream_dev_valid(sdev) != 0 || -+ tbstream_dev_closed(sdev) || -+ tbstream_dev_removed(sdev)); -+ if (ret) -+ return ret; -+ } -+ -+ ret = tbstream_dev_lock(sdev, nowait); - if (ret) - return ret; -- -- if (tbstream_dev_closed(sdev) || tbstream_dev_removed(sdev)) -- return -ENXIO; -- -- if (mutex_lock_interruptible(&sdev->lock)) -- return -ERESTARTSYS; - } - - nbytes = 0; -@@ -795,6 +910,13 @@ tbstream_dev_fops_poll(struct file *file, struct poll_table_struct *wait) - struct tbstream_dev *sdev = to_tbstream_dev(file->private_data); - __poll_t mask = 0; - -+ /* -+ * Without interrupts there is nothing that can wake us up so -+ * return failure instead. -+ */ -+ if (sdev->busy_poll) -+ return EPOLLERR; -+ - poll_wait(file, &sdev->wait, wait); - guard(mutex)(&sdev->lock); - if (tbstream_dev_valid(sdev) != 0) { -@@ -904,6 +1026,35 @@ tbstream_dev_from_group(struct config_group *group) - return container_of(group, struct tbstream_dev, group); - } - -+static ssize_t tbstream_dev_busy_poll_show(struct config_item *item, char *buf) -+{ -+ struct config_group *group = to_config_group(item); -+ struct tbstream_dev *sdev = tbstream_dev_from_group(group); -+ -+ return sysfs_emit(buf, "%u\n", sdev->busy_poll); -+} -+ -+static ssize_t -+tbstream_dev_busy_poll_store(struct config_item *item, const char *buf, -+ size_t count) -+{ -+ struct config_group *group = to_config_group(item); -+ struct tbstream_dev *sdev = tbstream_dev_from_group(group); -+ bool busy_poll; -+ int ret; -+ -+ ret = kstrtobool(buf, &busy_poll); -+ if (ret) -+ return ret; -+ -+ guard(mutex)(&sdev->lock); -+ if (sdev->users) -+ return -EBUSY; -+ sdev->busy_poll = busy_poll; -+ return count; -+} -+CONFIGFS_ATTR(tbstream_dev_, busy_poll); -+ - static ssize_t tbstream_dev_index_show(struct config_item *item, char *buf) - { - struct config_group *group = to_config_group(item); -@@ -1210,6 +1361,7 @@ tbstream_dev_throttling_store(struct config_item *item, const char *buf, - CONFIGFS_ATTR(tbstream_dev_, throttling); - - static struct configfs_attribute *tbstream_dev_attrs[] = { -+ &tbstream_dev_attr_busy_poll, - &tbstream_dev_attr_index, - &tbstream_dev_attr_in_hopid, - &tbstream_dev_attr_out_hopid, -@@ -1542,7 +1694,7 @@ static void tbstream_group_detach_stream(struct tbstream *stream) - config_group_put(&sg->group); - } - --static int tbstream_probe(struct tb_service *svc, const struct tb_service_id *id) -+static int tbstream_probe(struct tb_service *svc) - { - struct tbstream *stream; - -@@ -1632,7 +1784,7 @@ static const struct dev_pm_ops tbstream_pm_ops = { - - static const struct tb_service_id tbstream_ids[] = { - { TB_SERVICE("stream", 1) }, -- { }, -+ { } - }; - MODULE_DEVICE_TABLE(tbsvc, tbstream_ids); - -diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -682,7 +682,16 @@ int tb_port_disable(struct tb_port *port) - return __tb_port_enable(port, false); - } - --static int tb_port_reset(struct tb_port *port) -+/** -+ * tb_port_reset() - Reset the port -+ * @port: Port to reset -+ * -+ * Resets @port. For USB4 ports this issues a USB4 port reset and for -+ * legacy ports the link controller port is reset. -+ * -+ * Return: %0 on success, negative errno otherwise. -+ */ -+int tb_port_reset(struct tb_port *port) - { - if (tb_switch_is_usb4(port->sw)) - return port->cap_usb4 ? usb4_port_reset(port) : 0; -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -2941,7 +2941,9 @@ static void tb_handle_event(struct tb *tb, enum tb_cfg_pkg_type type, - static void tb_stop(struct tb *tb) - { - struct tb_cm *tcm = tb_priv(tb); -+ struct tb_nhi *nhi = tb->nhi; - struct tb_tunnel *tunnel; -+ struct tb_port *port; - struct tb_tunnel *n; - - cancel_delayed_work(&tcm->remove_work); -@@ -2956,6 +2958,25 @@ static void tb_stop(struct tb *tb) - tb_tunnel_deactivate(tunnel); - tb_tunnel_put(tunnel); - } -+ /* -+ * Signal disconnect to connected devices before the router tree is -+ * removed below. A Thunderbolt 3 device directly connected to a USB4 -+ * host otherwise never receives a disconnect indication, leaving -+ * firmware to poll the dead link for up to ~60 s which on some -+ * platforms turns the shutdown into a warm reset. Asserting -+ * PORT_CS_19.DPR drives SBTX low (USB4 spec section 6.9) so the device -+ * detects SBRX low and goes to Uninitialized Unplugged immediately. -+ */ -+ if (nhi->host_reset) { -+ tb_switch_for_each_port(tb->root_switch, port) { -+ if (!tb_port_is_null(port) || !tb_port_has_remote(port)) -+ continue; -+ if (tb_switch_is_usb4(port->remote->sw)) -+ continue; -+ if (tb_port_reset(port)) -+ tb_port_dbg(port, "downstream port reset failed, continuing\n"); -+ } -+ } - tb_switch_remove(tb->root_switch); - tb->root_switch = NULL; - tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ -diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -1103,6 +1103,7 @@ int tb_port_clear_counter(struct tb_port *port, int counter); - int tb_port_unlock(struct tb_port *port); - int tb_port_enable(struct tb_port *port); - int tb_port_disable(struct tb_port *port); -+int tb_port_reset(struct tb_port *port); - int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid); - void tb_port_release_in_hopid(struct tb_port *port, int hopid); - int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid); -diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c ---- a/drivers/thunderbolt/tunnel.c -+++ b/drivers/thunderbolt/tunnel.c -@@ -48,6 +48,9 @@ - #define TB_DP_AUX_PRIORITY 2 - #define TB_DP_AUX_WEIGHT 1 - -+/* struct tb_regs_hop::initial_credits is 7 bits wide */ -+#define TB_MAX_CREDITS 127 -+ - /* Minimum number of credits needed for PCIe path */ - #define TB_MIN_PCIE_CREDITS 6U - /* -@@ -1778,8 +1781,7 @@ static int tb_dma_reserve_credits(struct tb_path_hop *hop, unsigned int credits) - if (available < TB_MIN_DMA_CREDITS) - return -ENOSPC; - -- while (credits > available) -- credits--; -+ credits = min(credits, available); - - tb_port_dbg(port, "reserving %u credits for DMA path\n", - credits); -@@ -1908,7 +1910,7 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, - struct tb_tunnel *tunnel; - size_t npaths = 0, i = 0; - struct tb_path *path; -- int credits; -+ unsigned int credits; - - /* Ring 0 is reserved for control channel */ - if (WARN_ON(!receive_ring || !transmit_ring)) -@@ -1931,6 +1933,11 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, - tunnel->destroy = tb_dma_destroy; - - credits = min_not_zero(dma_credits, nhi->sw->max_dma_credits); -+ if (credits > TB_MAX_CREDITS) { -+ tb_tunnel_dbg(tunnel, "%u credits do not fit a hop, using %u\n", -+ credits, TB_MAX_CREDITS); -+ credits = TB_MAX_CREDITS; -+ } - - if (receive_ring > 0) { - path = tb_path_alloc(tb, dst, receive_path, nhi, receive_ring, 0, -diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -968,6 +968,9 @@ tb_xdp_schedule_request(struct tb *tb, const struct tb_xdp_header *hdr, - */ - int tb_register_service_driver(struct tb_service_driver *drv) - { -+ if (!drv->probe) -+ return -EINVAL; -+ - drv->driver.bus = &tb_bus_type; - return driver_register(&drv->driver); - } -@@ -1811,6 +1814,7 @@ static void tb_xdomain_state_work(struct work_struct *work) - tb_xdomain_failed(xd); - } else { - xd->state = XDOMAIN_STATE_ENUMERATED; -+ tb_xdomain_queue_properties_changed(xd); - } - break; - -diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h ---- a/include/linux/thunderbolt.h -+++ b/include/linux/thunderbolt.h -@@ -465,7 +465,7 @@ static inline struct tb_service *tb_to_service(struct device *dev) - */ - struct tb_service_driver { - struct device_driver driver; -- int (*probe)(struct tb_service *svc, const struct tb_service_id *id); -+ int (*probe)(struct tb_service *svc); - void (*remove)(struct tb_service *svc); - void (*shutdown)(struct tb_service *svc); - const struct tb_service_id *id_table; -@@ -514,6 +514,11 @@ void tb_service_properties_changed(struct tb_service *svc); - * @hop_count: Number of rings (end point hops) supported by NHI. - * @quirks: NHI specific quirks if any - * @domain_released: Completed when domain has been fully released -+ * @host_reset: Host router was reset on driver load, or forced on system -+ * shutdown/reboot. When set, tb_stop() asserts DPR on connected -+ * downstream ports to signal disconnect before tearing down the -+ * router tree. Only Thunderbolt 3 devices are reset; USB4 -+ * routers are skipped. - */ - struct tb_nhi { - spinlock_t lock; -@@ -528,6 +533,7 @@ struct tb_nhi { - u32 hop_count; - unsigned long quirks; - struct completion domain_released; -+ bool host_reset; - }; - - /** -@@ -592,6 +598,8 @@ struct tb_ring { - #define RING_FLAG_FRAME BIT(1) - /* Enable end-to-end flow control */ - #define RING_FLAG_E2E BIT(2) -+/* Do not enable interrupt for the ring */ -+#define RING_FLAG_NO_INTERRUPT BIT(3) - - struct ring_frame; - typedef void (*ring_cb)(struct tb_ring *, struct ring_frame *, bool canceled); diff --git a/kernel/0601-thunderbolt-updates.patch.sig b/kernel/0601-thunderbolt-updates.patch.sig deleted file mode 100644 index 89bd5ac..0000000 Binary files a/kernel/0601-thunderbolt-updates.patch.sig and /dev/null differ diff --git a/kernel/0602-thunderbolt-fixes.patch b/kernel/0602-thunderbolt-fixes.patch deleted file mode 100644 index f2e51c0..0000000 --- a/kernel/0602-thunderbolt-fixes.patch +++ /dev/null @@ -1,557 +0,0 @@ -diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c ---- a/drivers/thunderbolt/ctl.c -+++ b/drivers/thunderbolt/ctl.c -@@ -73,7 +73,6 @@ struct tb_ctl { - #define tb_ctl_dbg_once(ctl, format, arg...) \ - dev_dbg_once((ctl)->nhi->dev, format, ## arg) - --static DECLARE_WAIT_QUEUE_HEAD(tb_cfg_request_cancel_queue); - /* Serializes access to request kref_get/put */ - static DEFINE_MUTEX(tb_cfg_request_lock); - -@@ -133,41 +132,42 @@ void tb_cfg_request_put(struct tb_cfg_request *req) - static int tb_cfg_request_enqueue(struct tb_ctl *ctl, - struct tb_cfg_request *req) - { -+ tb_cfg_request_get(req); -+ - WARN_ON(test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)); - WARN_ON(req->ctl); - -- mutex_lock(&ctl->request_queue_lock); -+ guard(mutex)(&ctl->request_queue_lock); - if (!ctl->running) { -- mutex_unlock(&ctl->request_queue_lock); -+ tb_cfg_request_put(req); - return -ENOTCONN; - } - req->ctl = ctl; - list_add_tail(&req->list, &ctl->request_queue); - set_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); -- mutex_unlock(&ctl->request_queue_lock); - return 0; - } - -+static bool tb_cfg_request_is_active(struct tb_cfg_request *req) -+{ -+ return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); -+} -+ -+static bool tb_cfg_request_is_canceled(struct tb_cfg_request *req) -+{ -+ return test_bit(TB_CFG_REQUEST_CANCELED, &req->flags); -+} -+ - static void tb_cfg_request_dequeue(struct tb_cfg_request *req) - { - struct tb_ctl *ctl = req->ctl; - -- mutex_lock(&ctl->request_queue_lock); -- if (!test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)) { -- mutex_unlock(&ctl->request_queue_lock); -- return; -+ guard(mutex)(&ctl->request_queue_lock); -+ if (tb_cfg_request_is_active(req)) { -+ list_del(&req->list); -+ clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); -+ tb_cfg_request_put(req); - } -- -- list_del(&req->list); -- clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); -- if (test_bit(TB_CFG_REQUEST_CANCELED, &req->flags)) -- wake_up(&tb_cfg_request_cancel_queue); -- mutex_unlock(&ctl->request_queue_lock); --} -- --static bool tb_cfg_request_is_active(struct tb_cfg_request *req) --{ -- return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); - } - - static struct tb_cfg_request * -@@ -178,7 +178,7 @@ tb_cfg_request_find(struct tb_ctl *ctl, struct ctl_pkg *pkg) - mutex_lock(&pkg->ctl->request_queue_lock); - list_for_each_entry(iter, &pkg->ctl->request_queue, list) { - tb_cfg_request_get(iter); -- if (iter->match(iter, pkg)) { -+ if (!tb_cfg_request_is_canceled(iter) && iter->match(iter, pkg)) { - req = iter; - break; - } -@@ -512,8 +512,11 @@ static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame, - trace_tb_rx(pkg->ctl->index, frame->eof, pkg->buffer, frame->size, !req); - - if (req) { -- if (req->copy(req, pkg)) -- schedule_work(&req->work); -+ scoped_guard(mutex, &pkg->ctl->request_queue_lock) { -+ if (!tb_cfg_request_is_canceled(req) && -+ req->copy(req, pkg)) -+ schedule_work(&req->work); -+ } - tb_cfg_request_put(req); - } - -@@ -525,11 +528,10 @@ static void tb_cfg_request_work(struct work_struct *work) - { - struct tb_cfg_request *req = container_of(work, typeof(*req), work); - -- if (!test_bit(TB_CFG_REQUEST_CANCELED, &req->flags)) -+ if (!tb_cfg_request_is_canceled(req)) - req->callback(req->callback_data); - - tb_cfg_request_dequeue(req); -- tb_cfg_request_put(req); - } - - /** -@@ -555,10 +557,9 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, - INIT_WORK(&req->work, tb_cfg_request_work); - INIT_LIST_HEAD(&req->list); - -- tb_cfg_request_get(req); - ret = tb_cfg_request_enqueue(ctl, req); - if (ret) -- goto err_put; -+ return ret; - - ret = tb_ctl_tx(ctl, req->request, req->request_size, - req->request_type); -@@ -572,9 +573,6 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, - - err_dequeue: - tb_cfg_request_dequeue(req); --err_put: -- tb_cfg_request_put(req); -- - return ret; - } - -@@ -588,9 +586,10 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, - */ - void tb_cfg_request_cancel(struct tb_cfg_request *req, int err) - { -- set_bit(TB_CFG_REQUEST_CANCELED, &req->flags); -- schedule_work(&req->work); -- wait_event(tb_cfg_request_cancel_queue, !tb_cfg_request_is_active(req)); -+ scoped_guard(mutex, &req->ctl->request_queue_lock) -+ set_bit(TB_CFG_REQUEST_CANCELED, &req->flags); -+ cancel_work_sync(&req->work); -+ tb_cfg_request_dequeue(req); - req->result.err = err; - } - -diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c ---- a/drivers/thunderbolt/nhi.c -+++ b/drivers/thunderbolt/nhi.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -560,6 +561,8 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size, - INIT_LIST_HEAD(&ring->in_flight); - INIT_WORK(&ring->work, ring_work); - init_waitqueue_head(&ring->wait); -+ lockdep_register_key(&ring->lock_key); -+ lockdep_init_map(&ring->work.lockdep_map, "ring.work", &ring->lock_key, 0); - - ring->nhi = nhi; - ring->hop = hop; -@@ -599,6 +602,7 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size, - ring->size * sizeof(*ring->descriptors), - ring->descriptors, ring->descriptors_dma); - err_free_ring: -+ lockdep_unregister_key(&ring->lock_key); - kfree(ring); - - return NULL; -@@ -848,6 +852,7 @@ void tb_ring_free(struct tb_ring *ring) - * to finish before freeing the ring. - */ - flush_work(&ring->work); -+ lockdep_unregister_key(&ring->lock_key); - kfree(ring); - } - EXPORT_SYMBOL_GPL(tb_ring_free); -diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -774,6 +774,7 @@ static int tb_port_alloc_hopid(struct tb_port *port, bool in, int min_hopid, - { - int port_max_hopid; - struct ida *ida; -+ int ret; - - if (in) { - port_max_hopid = port->config.max_in_hop_id; -@@ -793,7 +794,11 @@ static int tb_port_alloc_hopid(struct tb_port *port, bool in, int min_hopid, - if (max_hopid < 0 || max_hopid > port_max_hopid) - max_hopid = port_max_hopid; - -- return ida_alloc_range(ida, min_hopid, max_hopid, GFP_KERNEL); -+ ret = ida_alloc_range(ida, min_hopid, max_hopid, GFP_KERNEL); -+ if (ret >= 0) -+ tb_switch_get(port->sw); -+ -+ return ret; - } - - /** -@@ -832,6 +837,7 @@ int tb_port_alloc_out_hopid(struct tb_port *port, int min_hopid, int max_hopid) - void tb_port_release_in_hopid(struct tb_port *port, int hopid) - { - ida_free(&port->in_hopids, hopid); -+ tb_switch_put(port->sw); - } - - /** -@@ -842,6 +848,7 @@ void tb_port_release_in_hopid(struct tb_port *port, int hopid) - void tb_port_release_out_hopid(struct tb_port *port, int hopid) - { - ida_free(&port->out_hopids, hopid); -+ tb_switch_put(port->sw); - } - - static inline bool tb_switch_is_reachable(const struct tb_switch *parent, -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -89,6 +89,7 @@ static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port, - const char *reason); - static void tb_queue_dp_bandwidth_request(struct tb *tb, u64 route, u8 port, - int retry, unsigned long delay); -+static void tb_dp_tunnel_active(struct tb_tunnel *tunnel, void *data); - - static void tb_queue_hotplug(struct tb *tb, u64 route, u8 port, bool unplug) - { -@@ -385,7 +386,8 @@ static void tb_switch_discover_tunnels(struct tb_switch *sw, - - switch (port->config.type) { - case TB_TYPE_DP_HDMI_IN: -- tunnel = tb_tunnel_discover_dp(tb, port, alloc_hopids); -+ tunnel = tb_tunnel_discover_dp(tb, port, alloc_hopids, -+ tb_dp_tunnel_active, tb); - tb_increase_tmu_accuracy(tunnel); - break; - -@@ -1910,6 +1912,18 @@ static void tb_dp_tunnel_active(struct tb_tunnel *tunnel, void *data) - struct tb *tb = data; - - mutex_lock(&tb->lock); -+ -+ /* -+ * If the DPRX read was canceled the tunnel is already being torn -+ * down by whoever canceled it. Do not touch the adapters here -+ * because the routers may be gone by now. -+ */ -+ if (tunnel->dprx_canceled) { -+ tb_tunnel_dbg(tunnel, "DPRX read canceled, not activating\n"); -+ mutex_unlock(&tb->lock); -+ return; -+ } -+ - if (tb_tunnel_is_active(tunnel)) { - int consumed_up, consumed_down, ret; - -@@ -1964,8 +1978,6 @@ static void tb_dp_tunnel_active(struct tb_tunnel *tunnel, void *data) - tb_dp_resource_unavailable(tb, in, "DPRX negotiation failed"); - } - mutex_unlock(&tb->lock); -- -- tb_domain_put(tb); - } - - static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in, -@@ -2026,8 +2038,7 @@ static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in, - available_up, available_down); - - tunnel = tb_tunnel_alloc_dp(tb, in, out, link_nr, available_up, -- available_down, tb_dp_tunnel_active, -- tb_domain_get(tb)); -+ available_down, tb_dp_tunnel_active, tb); - if (!tunnel) { - tb_port_dbg(out, "could not allocate DP tunnel\n"); - goto err_reclaim_usb; -@@ -2048,7 +2059,6 @@ static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in, - tb_tunnel_put(tunnel); - err_reclaim_usb: - tb_reclaim_usb3_bandwidth(tb, in, out); -- tb_domain_put(tb); - err_detach_group: - tb_detach_bandwidth_group(in); - err_dealloc_dp: -@@ -2950,11 +2960,12 @@ static void tb_stop(struct tb *tb) - /* tunnels are only present after everything has been initialized */ - list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) { - /* -- * DMA tunnels require the driver to be functional so we -- * tear them down. Other protocol tunnels can be left -- * intact. -+ * DMA tunnels and DP tunnels which are not yet active require -+ * the driver to be functional so we tear them down. -+ * Other protocol tunnels can be left intact. - */ -- if (tb_tunnel_is_dma(tunnel)) -+ if (tb_tunnel_is_dma(tunnel) || -+ (tb_tunnel_is_dp(tunnel) && !tb_tunnel_is_active(tunnel))) - tb_tunnel_deactivate(tunnel); - tb_tunnel_put(tunnel); - } -@@ -3274,11 +3285,11 @@ static void tb_remove_work(struct work_struct *work) - struct tb *tb = tcm_to_tb(tcm); - - mutex_lock(&tb->lock); -- if (tb->root_switch) -+ if (tb->root_switch) { - tb_free_unplugged_children(tb->root_switch); -+ tb_free_unplugged_xdomains(tb->root_switch); -+ } - mutex_unlock(&tb->lock); -- -- tb_free_unplugged_xdomains(tb->root_switch); - } - - static int tb_runtime_resume(struct tb *tb) -diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c ---- a/drivers/thunderbolt/tunnel.c -+++ b/drivers/thunderbolt/tunnel.c -@@ -510,6 +510,7 @@ struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down, - goto err_deactivate; - } - -+ tb_tunnel_set_active(tunnel, true); - tb_tunnel_dbg(tunnel, "discovered\n"); - return tunnel; - -@@ -1093,8 +1094,14 @@ static void tb_dp_dprx_work(struct work_struct *work) - struct tb_tunnel *tunnel = container_of(work, typeof(*tunnel), dprx_work.work); - struct tb *tb = tunnel->tb; - -+ /* -+ * The DPRX read can be canceled while this work is waiting for -+ * tb->lock. Check the flag only once it is held: while the lock is -+ * held the tunnel cannot be torn down under us and the adapters are -+ * safe to access. -+ */ -+ mutex_lock(&tb->lock); - if (!tunnel->dprx_canceled) { -- mutex_lock(&tb->lock); - if (tb_dp_is_usb4(tunnel->src_port->sw) && - tb_dp_wait_dprx(tunnel, TB_DPRX_WAIT_TIMEOUT)) { - if (ktime_before(ktime_get(), tunnel->dprx_timeout)) { -@@ -1106,41 +1113,42 @@ static void tb_dp_dprx_work(struct work_struct *work) - } else { - tb_tunnel_set_active(tunnel, true); - } -- mutex_unlock(&tb->lock); - } -+ mutex_unlock(&tb->lock); - -- if (tunnel->callback) -- tunnel->callback(tunnel, tunnel->callback_data); -+ tunnel->callback(tunnel, tunnel->callback_data); - tb_tunnel_put(tunnel); -+ tb_domain_put(tb); - } - - static int tb_dp_dprx_start(struct tb_tunnel *tunnel) - { - /* -- * Bump up the reference to keep the tunnel around. It will be -- * dropped in tb_dp_dprx_stop() once the tunnel is deactivated. -+ * Bump up the references to keep the tunnel and the domain around -+ * until the work has run or has been canceled. - */ - tb_tunnel_get(tunnel); -+ tb_domain_get(tunnel->tb); - - tunnel->dprx_started = true; -+ tunnel->dprx_canceled = false; -+ tunnel->dprx_timeout = dprx_timeout_to_ktime(dprx_timeout); -+ queue_delayed_work(tunnel->tb->wq, &tunnel->dprx_work, 0); - -- if (tunnel->callback) { -- tunnel->dprx_timeout = dprx_timeout_to_ktime(dprx_timeout); -- queue_delayed_work(tunnel->tb->wq, &tunnel->dprx_work, 0); -- return -EINPROGRESS; -- } -- -- return tb_dp_is_usb4(tunnel->src_port->sw) ? -- tb_dp_wait_dprx(tunnel, dprx_timeout) : 0; -+ return -EINPROGRESS; - } - - static void tb_dp_dprx_stop(struct tb_tunnel *tunnel) - { -+ struct tb *tb = tunnel->tb; -+ - if (tunnel->dprx_started) { - tunnel->dprx_started = false; - tunnel->dprx_canceled = true; -- if (cancel_delayed_work(&tunnel->dprx_work)) -+ if (cancel_delayed_work(&tunnel->dprx_work)) { - tb_tunnel_put(tunnel); -+ tb_domain_put(tb); -+ } - } - } - -@@ -1582,20 +1590,28 @@ static void tb_dp_dump(struct tb_tunnel *tunnel) - * @tb: Pointer to the domain structure - * @in: DP in adapter - * @alloc_hopid: Allocate HopIDs from visited ports -+ * @callback: Callback that is called when the DP tunnel is fully -+ * activated (or there is an error) -+ * @callback_data: Data for @callback - * - * If @in adapter is active, follows the tunnel to the DP out adapter - * and back. Returns the discovered tunnel or %NULL if there was no -- * tunnel. -+ * tunnel. See tb_tunnel_alloc_dp() for @callback. - * - * Return: Pointer to &struct tb_tunnel or %NULL if no tunnel found. - */ - struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, -- bool alloc_hopid) -+ bool alloc_hopid, -+ void (*callback)(struct tb_tunnel *, void *), -+ void *callback_data) - { - struct tb_tunnel *tunnel; - struct tb_port *port; - struct tb_path *path; - -+ if (WARN_ON(!callback)) -+ return NULL; -+ - if (!tb_dp_port_is_enabled(in)) - return NULL; - -@@ -1611,6 +1627,9 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, - tunnel->alloc_bandwidth = tb_dp_alloc_bandwidth; - tunnel->consumed_bandwidth = tb_dp_consumed_bandwidth; - tunnel->src_port = in; -+ tunnel->callback = callback; -+ tunnel->callback_data = callback_data; -+ INIT_DELAYED_WORK(&tunnel->dprx_work, tb_dp_dprx_work); - - path = tb_path_discover(in, TB_DP_VIDEO_HOPID, NULL, -1, - &tunnel->dst_port, "Video", alloc_hopid); -@@ -1656,6 +1675,7 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, - - tb_dp_dump(tunnel); - -+ tb_tunnel_set_active(tunnel, true); - tb_tunnel_dbg(tunnel, "discovered\n"); - return tunnel; - -@@ -1677,16 +1697,16 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, - * %0 if no available bandwidth. - * @max_down: Maximum available downstream bandwidth for the DP tunnel. - * %0 if no available bandwidth. -- * @callback: Optional callback that is called when the DP tunnel is -- * fully activated (or there is an error) -- * @callback_data: Optional data for @callback -+ * @callback: Callback that is called when the DP tunnel is fully -+ * activated (or there is an error) -+ * @callback_data: Data for @callback - * - * Allocates a tunnel between @in and @out that is capable of tunneling -- * Display Port traffic. If @callback is not %NULL it will be called -- * after tb_tunnel_activate() once the tunnel has been fully activated. -- * It can call tb_tunnel_is_active() to check if activation was -- * successful (or if it returns %false there was some sort of issue). -- * The @callback is called without @tb->lock held. -+ * Display Port traffic. The @callback is called after tb_tunnel_activate() -+ * once the tunnel has been fully activated. It can call -+ * tb_tunnel_is_active() to check if activation was successful (or if it -+ * returns %false there was some sort of issue). The @callback is called -+ * without @tb->lock held. - * - * Return: Pointer to @struct tb_tunnel or %NULL in case of failure. - */ -@@ -1701,7 +1721,7 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, - struct tb_path *path; - bool pm_support; - -- if (WARN_ON(!in->cap_adap || !out->cap_adap)) -+ if (WARN_ON(!in->cap_adap || !out->cap_adap || !callback)) - return NULL; - - tunnel = tb_tunnel_alloc(tb, 3, TB_TUNNEL_DP); -@@ -2288,6 +2308,7 @@ struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down, - tb_usb3_reclaim_available_bandwidth; - } - -+ tb_tunnel_set_active(tunnel, true); - tb_tunnel_dbg(tunnel, "discovered\n"); - return tunnel; - -diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h ---- a/drivers/thunderbolt/tunnel.h -+++ b/drivers/thunderbolt/tunnel.h -@@ -66,8 +66,8 @@ enum tb_tunnel_state { - * @dprx_canceled: Was DPRX capabilities read poll canceled - * @dprx_timeout: If set DPRX capabilities read poll work will timeout after this passes - * @dprx_work: Worker that is scheduled to poll completion of DPRX capabilities read -- * @callback: Optional callback called when DP tunnel is fully activated -- * @callback_data: Optional data for @callback -+ * @callback: Callback called when DP tunnel is fully activated -+ * @callback_data: Data for @callback - * @paths: All paths required by the tunnel - */ - struct tb_tunnel { -@@ -117,7 +117,9 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up, - bool tb_tunnel_reserved_pci(struct tb_port *port, int *reserved_up, - int *reserved_down); - struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, -- bool alloc_hopid); -+ bool alloc_hopid, -+ void (*callback)(struct tb_tunnel *, void *), -+ void *callback_data); - struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, - struct tb_port *out, int link_nr, - int max_up, int max_down, -diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -1814,7 +1814,6 @@ static void tb_xdomain_state_work(struct work_struct *work) - tb_xdomain_failed(xd); - } else { - xd->state = XDOMAIN_STATE_ENUMERATED; -- tb_xdomain_queue_properties_changed(xd); - } - break; - -diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h ---- a/include/linux/thunderbolt.h -+++ b/include/linux/thunderbolt.h -@@ -22,6 +22,7 @@ struct device; - #include - #include - #include -+#include - #include - #include - #include -@@ -565,6 +566,7 @@ struct tb_nhi { - * @interval_nsec: Interval counter if interrupt throttling is to be - * used with this ring (in ns) - * @wait: Used to signal that the ring may be empty now -+ * @lock_key: Lock validator class key per-ring - */ - struct tb_ring { - spinlock_t lock; -@@ -590,6 +592,7 @@ struct tb_ring { - void *poll_data; - unsigned int interval_nsec; - wait_queue_head_t wait; -+ struct lock_class_key lock_key; - }; - - /* Leave ring interrupt enabled on suspend */ diff --git a/kernel/0602-thunderbolt-fixes.patch.sig b/kernel/0602-thunderbolt-fixes.patch.sig deleted file mode 100644 index bc9e5e4..0000000 Binary files a/kernel/0602-thunderbolt-fixes.patch.sig and /dev/null differ diff --git a/kernel/0603-usb-updates.patch b/kernel/0603-usb-updates.patch deleted file mode 100644 index 171a4b4..0000000 --- a/kernel/0603-usb-updates.patch +++ /dev/null @@ -1,5629 +0,0 @@ -diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c ---- a/drivers/power/supply/power_supply_core.c -+++ b/drivers/power/supply/power_supply_core.c -@@ -477,6 +477,159 @@ struct power_supply *power_supply_get_by_name(const char *name) - } - EXPORT_SYMBOL_GPL(power_supply_get_by_name); - -+static bool power_supply_is_system_battery(struct power_supply *psy) -+{ -+ union power_supply_propval val; -+ -+ if (psy->desc->type != POWER_SUPPLY_TYPE_BATTERY) -+ return false; -+ -+ if (!power_supply_get_property_direct(psy, POWER_SUPPLY_PROP_SCOPE, -+ &val)) -+ if (val.intval == POWER_SUPPLY_SCOPE_DEVICE) -+ return false; -+ -+ return true; -+} -+ -+static int __power_supply_get_num_system_batteries(struct power_supply *epsy, -+ void *data) -+{ -+ int *count = data; -+ -+ if (power_supply_is_system_battery(epsy)) -+ (*count)++; -+ -+ return 0; -+} -+ -+static int power_supply_get_num_system_batteries(struct device *dev) -+{ -+ int ret, count = 0; -+ -+ ret = power_supply_for_each_psy(&count, -+ __power_supply_get_num_system_batteries); -+ -+ dev_dbg(dev, "%s: count: %d ret %d\n", __func__, count, ret); -+ -+ if (ret) -+ return ret; -+ -+ return count; -+} -+ -+struct psy_get_supplies_data { -+ int cnt; -+ int size; -+ struct power_supply **psys; -+}; -+ -+static int -+__power_supply_populate_system_batteries_array(struct power_supply *epsy, -+ void *_data) -+{ -+ struct psy_get_supplies_data *data = _data; -+ -+ if (power_supply_is_system_battery(epsy)) { -+ if (data->size <= data->cnt) -+ return -EOVERFLOW; -+ -+ get_device(&epsy->dev); -+ data->psys[data->cnt] = epsy; -+ atomic_inc(&epsy->use_cnt); -+ data->cnt++; -+ } -+ -+ return 0; -+} -+ -+static int -+power_supply_populate_system_batteries_array(struct device *dev, int size, -+ struct power_supply **batteries) -+{ -+ int ret; -+ -+ struct psy_get_supplies_data data = { -+ .cnt = 0, -+ .size = size, -+ .psys = batteries, -+ }; -+ -+ ret = power_supply_for_each_psy(&data, -+ __power_supply_populate_system_batteries_array); -+ -+ dev_dbg(dev, "%s Found %d batteries with array size %d ret %d\n", -+ __func__, data.cnt, data.size, ret); -+ -+ if (ret < 0 || !data.cnt) { -+ power_supply_put_system_batteries(batteries, data.cnt); -+ return ret; -+ } -+ -+ return data.cnt; -+} -+ -+/** -+ * power_supply_get_system_batteries() - Fetches references to battery type -+ * power supplies in the system. -+ * @dev: Pointer to device requesting the power supply refs. -+ * @psys: Pointer to an array of power supply refs. -+ * -+ * Helper function to get handles to battery type power supplies in the system. -+ * If acquiring a ref to a power supply fails, then the search for battery type -+ * power supplies will abort and the acquired power supply references will be -+ * released. -+ * -+ * Return: Indicates the number of battery type power supplies returned on -+ * success or a negative error code on failure. -+ * -+ * Call power_supply_put_system_batteries() after use to cleanup resources. -+ */ -+int __must_check power_supply_get_system_batteries(struct device *dev, -+ struct power_supply ***psys) -+{ -+ int ret; -+ -+ if (!psys) -+ return -EINVAL; -+ -+ ret = power_supply_get_num_system_batteries(dev); -+ if (ret <= 0) { -+ *psys = NULL; -+ return ret; -+ } -+ -+ *psys = kzalloc_objs(**psys, ret); -+ if (!*psys) -+ return -ENOMEM; -+ -+ ret = power_supply_populate_system_batteries_array(dev, ret, *psys); -+ if (ret <= 0) -+ *psys = NULL; -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(power_supply_get_system_batteries); -+ -+/** -+ * power_supply_put_system_batteries() - Cleanup resources allocated by -+ * power_supply_get_system_batteries() -+ * @psys: Array of power supply references to release and free. -+ * @count: Number of elements in the array. -+ */ -+void power_supply_put_system_batteries(struct power_supply **psys, int count) -+{ -+ int i; -+ -+ for (i = 0; i < count; i++) { -+ if (psys[i]) -+ power_supply_put(psys[i]); -+ } -+ -+ kfree(psys); -+} -+EXPORT_SYMBOL_GPL(power_supply_put_system_batteries); -+ - /** - * power_supply_put() - Drop reference obtained with power_supply_get_by_name - * @psy: Reference to put -diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c ---- a/drivers/usb/cdns3/cdns3-plat.c -+++ b/drivers/usb/cdns3/cdns3-plat.c -@@ -147,12 +147,12 @@ static int cdns3_plat_probe(struct platform_device *pdev) - cdns->usb2_phy = devm_phy_optional_get(dev, "cdns3,usb2-phy"); - if (IS_ERR(cdns->usb2_phy)) - return dev_err_probe(dev, PTR_ERR(cdns->usb2_phy), -- "Failed to get cdn3,usb2-phy\n"); -+ "Failed to get cdns3,usb2-phy\n"); - - cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy"); - if (IS_ERR(cdns->usb3_phy)) - return dev_err_probe(dev, PTR_ERR(cdns->usb3_phy), -- "Failed to get cdn3,usb3-phy\n"); -+ "Failed to get cdns3,usb3-phy\n"); - - ret = phy_init(cdns->usb2_phy); - if (ret) -diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c ---- a/drivers/usb/core/config.c -+++ b/drivers/usb/core/config.c -@@ -151,7 +151,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, - usb_endpoint_xfer_int(&ep->desc)) && - desc->bmAttributes != 0) { - dev_notice(ddev, "%s endpoint with bmAttributes = %d in config %d interface %d altsetting %d ep 0x%X: setting to zero\n", -- usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk", -+ usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Interrupt", - desc->bmAttributes, - cfgno, inum, asnum, ep->desc.bEndpointAddress); - ep->ss_ep_comp.bmAttributes = 0; -diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c ---- a/drivers/usb/core/devices.c -+++ b/drivers/usb/core/devices.c -@@ -37,6 +37,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -408,7 +409,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, - return 0; - /* allocate 2^1 pages = 8K (on i386); - * should be more than enough for one device */ -- pages_start = (char *)__get_free_pages(GFP_NOIO, 1); -+ pages_start = kmalloc(PAGE_SIZE << 1, GFP_NOIO); - if (!pages_start) - return -ENOMEM; - -@@ -479,7 +480,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, - if (length > *nbytes) - length = *nbytes; - if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) { -- free_pages((unsigned long)pages_start, 1); -+ kfree(pages_start); - return -EFAULT; - } - *nbytes -= length; -@@ -490,7 +491,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, - } else - *skip_bytes -= length; - -- free_pages((unsigned long)pages_start, 1); -+ kfree(pages_start); - - /* Now look at all of this device's children. */ - usb_hub_for_each_child(usbdev, chix, childdev) { -diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c ---- a/drivers/usb/core/devio.c -+++ b/drivers/usb/core/devio.c -@@ -2329,6 +2329,13 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl) - if (!connected(ps)) - return -ENODEV; - -+ if (ps->dev->state != USB_STATE_CONFIGURED) -+ return -EHOSTUNREACH; -+ -+ intf = usb_ifnum_to_if(ps->dev, ctl->ifno); -+ if (!intf) -+ return -EINVAL; -+ - /* alloc buffer */ - size = _IOC_SIZE(ctl->ioctl_code); - if (size > 0) { -@@ -2345,11 +2352,7 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl) - } - } - -- if (ps->dev->state != USB_STATE_CONFIGURED) -- retval = -EHOSTUNREACH; -- else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno))) -- retval = -EINVAL; -- else switch (ctl->ioctl_code) { -+ switch (ctl->ioctl_code) { - - /* disconnect kernel driver from interface */ - case USBDEVFS_DISCONNECT: -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -623,11 +623,11 @@ static int hub_ext_port_status(struct usb_hub *hub, int port1, int type, - mutex_lock(&hub->status_mutex); - ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len); - if (ret < len) { -- if (ret != -ENODEV) -- dev_err(hub->intfdev, -- "%s failed (err = %d)\n", __func__, ret); - if (ret >= 0) - ret = -EIO; -+ if (ret != -ENODEV) -+ dev_dbg(hub->intfdev, -+ "get_port_status failed: err = %d\n", ret); - } else { - *status = le16_to_cpu(hub->status->port.wPortStatus); - *change = le16_to_cpu(hub->status->port.wPortChange); -@@ -995,11 +995,11 @@ static int hub_hub_status(struct usb_hub *hub, - mutex_lock(&hub->status_mutex); - ret = get_hub_status(hub->hdev, &hub->status->hub); - if (ret < (int)sizeof(hub->status->hub)) { -- if (ret != -ENODEV) -- dev_err(hub->intfdev, -- "%s failed (err = %d)\n", __func__, ret); - if (ret >= 0) - ret = -EIO; -+ if (ret != -ENODEV) -+ dev_dbg(hub->intfdev, -+ "get_hub_status failed: err = %d\n", ret); - } else { - *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); -diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c ---- a/drivers/usb/dwc2/core_intr.c -+++ b/drivers/usb/dwc2/core_intr.c -@@ -334,9 +334,8 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) - - /** - * dwc2_wakeup_from_lpm_l1 - Exit the device from LPM L1 state -- * - * @hsotg: Programming view of DWC_otg controller -- * -+ * @remotewakeup: Whether this is a remote wakeup - */ - void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg, bool remotewakeup) - { -diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c ---- a/drivers/usb/dwc3/core.c -+++ b/drivers/usb/dwc3/core.c -@@ -2188,22 +2188,89 @@ static void dwc3_vbus_draw_work(struct work_struct *work) - ret, dwc->current_limit); - } - --static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc) -+static int dwc3_psy_notifier(struct notifier_block *nb, -+ unsigned long event, void *data) - { -- struct power_supply *usb_psy; -- const char *usb_psy_name; -+ struct dwc3 *dwc = container_of(nb, struct dwc3, psy_nb); -+ struct power_supply *psy = data; -+ unsigned long flags; -+ -+ if (dwc->usb_psy) -+ return NOTIFY_DONE; -+ -+ if (strcmp(psy->desc->name, dwc->usb_psy_name) != 0) -+ return NOTIFY_DONE; -+ -+ /* Explicitly get the reference for this psy */ -+ psy = power_supply_get_by_name(dwc->usb_psy_name); -+ if (!psy) -+ return NOTIFY_DONE; -+ -+ spin_lock_irqsave(&dwc->lock, flags); -+ /* -+ * The USB power_supply may already be set. This can happen if notifier -+ * callbacks for the USB power_supply race, or if a previous notifier -+ * callback has already successfully fetched and associated the instance. -+ * In such cases, release the newly acquired reference and ignore -+ * subsequent notifications until the notifier is unregistered. -+ */ -+ if (dwc->usb_psy) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ power_supply_put(psy); -+ return NOTIFY_DONE; -+ } -+ -+ dwc->usb_psy = psy; -+ if (dwc->current_limit != DWC3_CURRENT_UNSPECIFIED) -+ schedule_work(&dwc->vbus_draw_work); -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ -+ return NOTIFY_OK; -+} -+ -+static void dwc3_get_usb_power_supply(struct dwc3 *dwc) -+{ -+ struct power_supply *psy; -+ unsigned long flags; - int ret; - -- ret = device_property_read_string(dwc->dev, "usb-psy-name", &usb_psy_name); -+ ret = device_property_read_string(dwc->dev, "usb-psy-name", &dwc->usb_psy_name); - if (ret < 0) -- return NULL; -- -- usb_psy = power_supply_get_by_name(usb_psy_name); -- if (!usb_psy) -- return ERR_PTR(-EPROBE_DEFER); -+ return; - - INIT_WORK(&dwc->vbus_draw_work, dwc3_vbus_draw_work); -- return usb_psy; -+ -+ dwc->current_limit = DWC3_CURRENT_UNSPECIFIED; -+ dwc->psy_nb.notifier_call = dwc3_psy_notifier; -+ ret = power_supply_reg_notifier(&dwc->psy_nb); -+ if (ret) { -+ dev_err(dwc->dev, "Failed to register power supply notifier: %d\n", ret); -+ dwc->psy_nb.notifier_call = NULL; -+ return; -+ } -+ -+ psy = power_supply_get_by_name(dwc->usb_psy_name); -+ if (!psy) -+ return; -+ -+ /* Unregister the notifier now that we have the power supply */ -+ power_supply_unreg_notifier(&dwc->psy_nb); -+ dwc->psy_nb.notifier_call = NULL; -+ -+ spin_lock_irqsave(&dwc->lock, flags); -+ /* -+ * It is possible that the notifier callback ran before we reached here -+ * and successfully fetched the power supply. In that case we need to -+ * release the above reference. -+ */ -+ if (dwc->usb_psy) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ power_supply_put(psy); -+ return; -+ } -+ -+ dwc->usb_psy = psy; -+ spin_unlock_irqrestore(&dwc->lock, flags); - } - - int dwc3_core_probe(const struct dwc3_probe_data *data) -@@ -2251,9 +2318,9 @@ int dwc3_core_probe(const struct dwc3_probe_data *data) - - dwc3_get_software_properties(dwc, &data->properties); - -- dwc->usb_psy = dwc3_get_usb_power_supply(dwc); -- if (IS_ERR(dwc->usb_psy)) -- return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n"); -+ spin_lock_init(&dwc->lock); -+ -+ dwc3_get_usb_power_supply(dwc); - - if (!data->ignore_clocks_and_resets) { - dwc->reset = devm_reset_control_array_get_optional_shared(dev); -@@ -2305,7 +2372,6 @@ int dwc3_core_probe(const struct dwc3_probe_data *data) - dwc->num_usb3_ports = 1; - } - -- spin_lock_init(&dwc->lock); - mutex_init(&dwc->mutex); - - pm_runtime_get_noresume(dev); -@@ -2373,6 +2439,8 @@ int dwc3_core_probe(const struct dwc3_probe_data *data) - err_assert_reset: - reset_control_assert(dwc->reset); - err_put_psy: -+ if (dwc->psy_nb.notifier_call) -+ power_supply_unreg_notifier(&dwc->psy_nb); - if (dwc->usb_psy) - power_supply_put(dwc->usb_psy); - -@@ -2429,6 +2497,9 @@ void dwc3_core_remove(struct dwc3 *dwc) - - dwc3_free_event_buffers(dwc); - -+ if (dwc->psy_nb.notifier_call) -+ power_supply_unreg_notifier(&dwc->psy_nb); -+ - if (dwc->usb_psy) { - cancel_work_sync(&dwc->vbus_draw_work); - power_supply_put(dwc->usb_psy); -diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h ---- a/drivers/usb/dwc3/core.h -+++ b/drivers/usb/dwc3/core.h -@@ -722,7 +722,6 @@ struct dwc3_event_buffer { - * @cancelled_list: list of cancelled requests for this endpoint - * @pending_list: list of pending requests for this endpoint - * @started_list: list of started requests on this endpoint -- * @regs: pointer to first endpoint register - * @trb_pool: array of transaction buffers - * @trb_pool_dma: dma address of @trb_pool - * @trb_enqueue: enqueue 'pointer' into TRB array -@@ -1059,6 +1058,8 @@ struct dwc3_glue_ops { - * @role_switch_default_mode: default operation mode of controller while - * usb role is USB_ROLE_NONE. - * @usb_psy: pointer to power supply interface. -+ * @usb_psy_name: name of the USB power supply -+ * @psy_nb: power supply notifier block - * @vbus_draw_work: Work to set the vbus drawing limit - * @current_limit: How much current to draw from vbus, in milliAmperes. - * @usb2_phy: pointer to USB2 PHY -@@ -1251,9 +1252,13 @@ struct dwc3 { - enum usb_dr_mode role_switch_default_mode; - - struct power_supply *usb_psy; -+ const char *usb_psy_name; -+ struct notifier_block psy_nb; - struct work_struct vbus_draw_work; - unsigned int current_limit; - -+#define DWC3_CURRENT_UNSPECIFIED UINT_MAX -+ - u32 fladj; - u32 ref_clk_per; - u32 irq_gadget; -diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c ---- a/drivers/usb/dwc3/dwc3-am62.c -+++ b/drivers/usb/dwc3/dwc3-am62.c -@@ -205,7 +205,9 @@ static int dwc3_ti_init(struct dwc3_am62 *am62) - - dwc3_ti_writel(am62, USBSS_PHY_CONFIG, reg); - -- clk_prepare_enable(am62->usb2_refclk); -+ ret = clk_prepare_enable(am62->usb2_refclk); -+ if (ret) -+ return ret; - - /* Set mode valid bit to indicate role is valid */ - reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL); -@@ -361,14 +363,19 @@ static int dwc3_ti_resume_common(struct device *dev) - { - struct dwc3_am62 *am62 = dev_get_drvdata(dev); - u32 reg; -+ int ret; - - reg = dwc3_ti_readl(am62, USBSS_DEBUG_CFG); - if (reg != USBSS_DEBUG_CFG_DISABLED) { - /* lost power/context */ -- dwc3_ti_init(am62); -+ ret = dwc3_ti_init(am62); -+ if (ret) -+ return ret; - } else { - dwc3_ti_writel(am62, USBSS_DEBUG_CFG, USBSS_DEBUG_CFG_OFF); -- clk_prepare_enable(am62->usb2_refclk); -+ ret = clk_prepare_enable(am62->usb2_refclk); -+ if (ret) -+ return ret; - } - - if (device_may_wakeup(dev)) { -diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c ---- a/drivers/usb/dwc3/dwc3-qcom.c -+++ b/drivers/usb/dwc3/dwc3-qcom.c -@@ -602,7 +602,7 @@ static void dwc3_qcom_run_stop_notifier(struct dwc3 *dwc, bool is_on) - pm_runtime_mark_last_busy(qcom->dev); - } - --struct dwc3_glue_ops dwc3_qcom_glue_ops = { -+static struct dwc3_glue_ops dwc3_qcom_glue_ops = { - .pre_set_role = dwc3_qcom_set_role_notifier, - .pre_run_stop = dwc3_qcom_run_stop_notifier, - }; -diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c ---- a/drivers/usb/dwc3/dwc3-xilinx.c -+++ b/drivers/usb/dwc3/dwc3-xilinx.c -@@ -98,18 +98,10 @@ static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data) - - dwc3_xlnx_mask_phy_rst(priv_data, false); - -- /* Assert and De-assert reset */ -- ret = reset_control_assert(crst); -- if (ret < 0) { -- dev_err_probe(dev, ret, "failed to assert Reset\n"); -- return ret; -- } -- -- ret = reset_control_deassert(crst); -- if (ret < 0) { -- dev_err_probe(dev, ret, "failed to De-assert Reset\n"); -- return ret; -- } -+ /* assert and deassert reset */ -+ ret = reset_control_reset(crst); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to assert and deassert reset\n"); - - dwc3_xlnx_mask_phy_rst(priv_data, true); - dwc3_xlnx_set_coherency(priv_data, XLNX_USB2_TRAFFIC_ROUTE_CONFIG); -@@ -194,7 +186,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) - } - - if (priv_data->usb3_phy) { -- /* Set PIPE Power Present signal in FPD Power Present Register*/ -+ /* Set PIPE Power Present signal in FPD Power Present Register */ - writel(FPD_POWER_PRSNT_OPTION, priv_data->regs + XLNX_USB_FPD_POWER_PRSNT); - /* Set the PIPE Clock Select bit in FPD PIPE Clock register */ - writel(PIPE_CLK_SELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK); -diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c ---- a/drivers/usb/dwc3/gadget.c -+++ b/drivers/usb/dwc3/gadget.c -@@ -3129,15 +3129,26 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g, - static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) - { - struct dwc3 *dwc = gadget_to_dwc(g); -+ unsigned long flags; - - if (dwc->usb2_phy) - return usb_phy_set_power(dwc->usb2_phy, mA); - -- if (!dwc->usb_psy) -- return -EOPNOTSUPP; -+ spin_lock_irqsave(&dwc->lock, flags); -+ if (!dwc->usb_psy) { -+ if (!dwc->psy_nb.notifier_call) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -EOPNOTSUPP; -+ } -+ dwc->current_limit = mA; -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ dev_dbg(dwc->dev, "Stored VBUS draw: %u mA (power supply not ready)\n", mA); -+ return 0; -+ } - - dwc->current_limit = mA; - schedule_work(&dwc->vbus_draw_work); -+ spin_unlock_irqrestore(&dwc->lock, flags); - - return 0; - } -diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c ---- a/drivers/usb/dwc3/host.c -+++ b/drivers/usb/dwc3/host.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - - #include "../host/xhci-port.h" - #include "../host/xhci-ext-caps.h" -@@ -46,9 +47,9 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc) - return; - } - -- op_regs_base = HC_LENGTH(readl(xhci_regs)); -+ op_regs_base = FIELD_GET(HC_LENGTH, readl(xhci_regs)); - reg = readl(xhci_regs + XHCI_HCSPARAMS1); -- port_num = HCS_MAX_PORTS(reg); -+ port_num = FIELD_GET(HCS_MAX_PORTS, reg); - - for (i = 1; i <= port_num; i++) { - offset = op_regs_base + XHCI_PORTSC_BASE + 0x10 * (i - 1); -diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c ---- a/drivers/usb/gadget/configfs.c -+++ b/drivers/usb/gadget/configfs.c -@@ -125,11 +125,11 @@ static int usb_string_copy(const char *s, char **s_copy) - if (copy) { - str = copy; - } else { -- str = kmalloc(USB_MAX_STRING_WITH_NULL_LEN, GFP_KERNEL); -+ str = kzalloc(USB_MAX_STRING_WITH_NULL_LEN, GFP_KERNEL); - if (!str) - return -ENOMEM; - } -- strcpy(str, s); -+ memcpy(str, s, ret + 1); - if (str[ret - 1] == '\n') - str[ret - 1] = '\0'; - *s_copy = str; -diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c ---- a/drivers/usb/gadget/function/f_fs.c -+++ b/drivers/usb/gadget/function/f_fs.c -@@ -159,7 +159,9 @@ struct ffs_epfile { - struct mutex mutex; - - struct ffs_data *ffs; -- struct ffs_ep *ep; /* P: ffs->eps_lock */ -+ struct ffs_ep *ep; /* P: ffs->eps_lock */ -+ struct ffs_epfile *epfile_in; /* P: ffs->eps_lock */ -+ struct ffs_epfile *epfile_out; /* P: ffs->eps_lock */ - - /* - * Buffer for holding data from partial reads which may happen since -@@ -219,12 +221,13 @@ struct ffs_epfile { - struct ffs_buffer *read_buffer; - #define READ_BUFFER_DROP ((struct ffs_buffer *)ERR_PTR(-ESHUTDOWN)) - -- char name[5]; -+ char name[8]; - - unsigned char in; /* P: ffs->eps_lock */ - unsigned char isoc; /* P: ffs->eps_lock */ - -- unsigned char _pad; -+ u8 zlp_enabled; /* P: ffs->eps_lock */ -+ bool is_rw_proxy; - - /* Protects dmabufs */ - struct mutex dmabufs_mutex; -@@ -991,9 +994,8 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, - return ret; - } - --static struct ffs_ep *ffs_epfile_wait_ep(struct file *file) -+static struct ffs_ep *ffs_epfile_wait_ep(struct ffs_epfile *epfile, struct file *file) - { -- struct ffs_epfile *epfile = file->private_data; - struct ffs_ep *ep; - int ret; - -@@ -1020,17 +1022,22 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) - char *data = NULL; - ssize_t ret, data_len = -EINVAL; - int halt; -+ bool is_rw_proxy = epfile->is_rw_proxy; - - /* Are we still active? */ - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) - return -ENODEV; - -- ep = ffs_epfile_wait_ep(file); -+ /* Proxy to base endpoint if rw_proxy */ -+ if (is_rw_proxy) -+ epfile = io_data->read ? epfile->epfile_out : epfile->epfile_in; -+ -+ ep = ffs_epfile_wait_ep(epfile, file); - if (IS_ERR(ep)) - return PTR_ERR(ep); - - /* Do we halt? */ -- halt = (!io_data->read == !epfile->in); -+ halt = is_rw_proxy ? 0 : (!io_data->read == !epfile->in); - if (halt && epfile->isoc) - return -EINVAL; - -@@ -1127,6 +1134,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) - req->buf = data; - req->num_sgs = 0; - } -+ -+ req->zero = !io_data->read ? epfile->zlp_enabled : 0; - req->length = data_len; - - io_data->buf = data; -@@ -1178,6 +1187,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) - req->buf = data; - req->num_sgs = 0; - } -+ -+ req->zero = !io_data->read ? epfile->zlp_enabled : 0; - req->length = data_len; - - io_data->buf = data; -@@ -1666,7 +1677,7 @@ static int ffs_dmabuf_transfer(struct file *file, - - priv = attach->importer_priv; - -- ep = ffs_epfile_wait_ep(file); -+ ep = ffs_epfile_wait_ep(epfile, file); - if (IS_ERR(ep)) { - ret = PTR_ERR(ep); - goto err_attachment_put; -@@ -1732,6 +1743,7 @@ static int ffs_dmabuf_transfer(struct file *file, - - /* Now that the dma_fence is in place, queue the transfer. */ - -+ usb_req->zero = epfile->zlp_enabled; - usb_req->length = req->length; - usb_req->buf = NULL; - usb_req->sg = priv->sgt->sgl; -@@ -1779,10 +1791,14 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, - struct ffs_epfile *epfile = file->private_data; - struct ffs_ep *ep; - int ret; -+ __u32 enable_zlp = 0; - - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) - return -ENODEV; - -+ if (epfile->is_rw_proxy) -+ return -ENOTTY; -+ - switch (code) { - case FUNCTIONFS_DMABUF_ATTACH: - { -@@ -1811,12 +1827,29 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, - - return ffs_dmabuf_transfer(file, &req); - } -+ /* -+ * We handle this IOCTL before ffs_epfile_wait_ep() to allow userspace -+ * to configure ZLP behavior immediately without blocking indefinitely -+ * while waiting for the USB host to connect and enable the endpoint. -+ */ -+ case FUNCTIONFS_ENDPOINT_ENABLE_ZLP: -+ if (!epfile->in) -+ return -EINVAL; -+ -+ if (copy_from_user(&enable_zlp, (void __user *)value, sizeof(enable_zlp))) -+ return -EFAULT; -+ -+ spin_lock_irq(&epfile->ffs->eps_lock); -+ epfile->zlp_enabled = !!enable_zlp; -+ spin_unlock_irq(&epfile->ffs->eps_lock); -+ -+ return 0; - default: - break; - } - - /* Wait for endpoint to be enabled */ -- ep = ffs_epfile_wait_ep(file); -+ ep = ffs_epfile_wait_ep(epfile, file); - if (IS_ERR(ep)) - return PTR_ERR(ep); - -@@ -2214,7 +2247,7 @@ static void ffs_data_closed(struct ffs_data *ffs) - - if (epfiles) - ffs_epfiles_destroy(ffs->sb, epfiles, -- ffs->eps_count); -+ ffs->epfiles_count); - - if (ffs->setup_state == FFS_SETUP_PENDING) - __ffs_ep0_stall(ffs); -@@ -2273,7 +2306,7 @@ static void ffs_data_clear(struct ffs_data *ffs) - * copy of epfile will save us from use-after-free. - */ - if (epfiles) { -- ffs_epfiles_destroy(ffs->sb, epfiles, ffs->eps_count); -+ ffs_epfiles_destroy(ffs->sb, epfiles, ffs->epfiles_count); - ffs->epfiles = NULL; - } - -@@ -2371,11 +2404,16 @@ static void functionfs_unbind(struct ffs_data *ffs) - static int ffs_epfiles_create(struct ffs_data *ffs) - { - struct ffs_epfile *epfile, *epfiles; -- unsigned i, count; -+ unsigned int i, count, epfiles_count; - int err; - - count = ffs->eps_count; -- epfiles = kzalloc_objs(*epfiles, count); -+ epfiles_count = count; -+ if (ffs->user_flags & FUNCTIONFS_RW_PROXY_EPS) -+ epfiles_count += count / 2; -+ ffs->epfiles_count = epfiles_count; -+ -+ epfiles = kzalloc_objs(*epfiles, epfiles_count); - if (!epfiles) - return -ENOMEM; - -@@ -2398,6 +2436,32 @@ static int ffs_epfiles_create(struct ffs_data *ffs) - } - } - -+ if (ffs->user_flags & FUNCTIONFS_RW_PROXY_EPS) { -+ struct ffs_epfile *comp = epfiles + count; -+ -+ for (i = 0; i < count; i += 2, ++comp) { -+ struct ffs_epfile *ep1 = &epfiles[i]; -+ struct ffs_epfile *ep2 = &epfiles[i + 1]; -+ bool ep1_in = ffs->eps_addrmap[i + 1] & USB_ENDPOINT_DIR_MASK; -+ -+ comp->ffs = ffs; -+ comp->is_rw_proxy = true; -+ comp->epfile_in = ep1_in ? ep1 : ep2; -+ comp->epfile_out = ep1_in ? ep2 : ep1; -+ mutex_init(&comp->mutex); -+ mutex_init(&comp->dmabufs_mutex); -+ INIT_LIST_HEAD(&comp->dmabufs); -+ snprintf(comp->name, sizeof(comp->name), "%s_rw", -+ epfiles[i].name); -+ err = ffs_sb_create_file(ffs->sb, comp->name, -+ comp, &ffs_epfile_operations); -+ if (err) { -+ ffs_epfiles_destroy(ffs->sb, epfiles, count + (i / 2)); -+ return err; -+ } -+ } -+ } -+ - ffs->epfiles = epfiles; - return 0; - } -@@ -2975,7 +3039,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, - FUNCTIONFS_VIRTUAL_ADDR | - FUNCTIONFS_EVENTFD | - FUNCTIONFS_ALL_CTRL_RECIP | -- FUNCTIONFS_CONFIG0_SETUP)) { -+ FUNCTIONFS_CONFIG0_SETUP | -+ FUNCTIONFS_RW_PROXY_EPS)) { - ret = -ENOSYS; - goto error; - } -@@ -3063,6 +3128,21 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, - goto error; - } - -+ if (ffs->user_flags & FUNCTIONFS_RW_PROXY_EPS) { -+ if (ffs->eps_count % 2) { -+ ret = -EINVAL; -+ goto error; -+ } -+ -+ for (i = 1; i < ffs->eps_count; i += 2) { -+ if ((ffs->eps_addrmap[i] & USB_ENDPOINT_DIR_MASK) == -+ (ffs->eps_addrmap[i + 1] & USB_ENDPOINT_DIR_MASK)) { -+ ret = -EINVAL; -+ goto error; -+ } -+ } -+ } -+ - ffs->raw_descs_data = _data; - ffs->raw_descs = raw_descs; - ffs->raw_descs_length = data - raw_descs; -@@ -3358,7 +3438,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, - struct usb_request *req; - struct usb_ep *ep; - u8 bEndpointAddress; -- u16 wMaxPacketSize; -+ __le16 wMaxPacketSize; - - /* - * We back up bEndpointAddress because autoconfig overwrites -diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c ---- a/drivers/usb/gadget/function/f_mass_storage.c -+++ b/drivers/usb/gadget/function/f_mass_storage.c -@@ -203,7 +203,6 @@ - /*------------------------------------------------------------------------*/ - - #define FSG_DRIVER_DESC "Mass Storage Function" --#define FSG_DRIVER_VERSION "2009/09/11" - - static const char fsg_string_interface[] = "Mass Storage"; - -@@ -3516,8 +3515,6 @@ static struct usb_function_instance *fsg_alloc_inst(void) - if (rc) - goto release_common; - -- pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); -- - memset(&config, 0, sizeof(config)); - config.removable = true; - rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", -diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c ---- a/drivers/usb/gadget/function/u_audio.c -+++ b/drivers/usb/gadget/function/u_audio.c -@@ -641,15 +641,15 @@ int u_audio_start_capture(struct g_audio *audio_dev) - ret = config_ep_by_speed(gadget, &audio_dev->func, ep_fback); - if (ret < 0) { - dev_err(dev, "config_ep_by_speed in_ep_fback failed (%d)\n", ret); -- return ret; // TODO: Clean up out_ep -+ goto err_out_ep; - } - -- prm->fb_ep_enabled = true; - ret = usb_ep_enable(ep_fback); - if (ret < 0) { - dev_err(dev, "usb_ep_enable failed for in_ep_fback (%d)\n", ret); -- return ret; // TODO: Clean up out_ep -+ goto err_out_ep; - } -+ prm->fb_ep_enabled = true; - req_len = ep_fback->maxpacket; - - req_fback = usb_ep_alloc_request(ep_fback, GFP_ATOMIC); -@@ -680,6 +680,12 @@ int u_audio_start_capture(struct g_audio *audio_dev) - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - - return 0; -+ -+err_out_ep: -+ set_active(prm, false); -+ free_ep(prm, ep); -+ -+ return ret; - } - EXPORT_SYMBOL_GPL(u_audio_start_capture); - -diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h ---- a/drivers/usb/gadget/function/u_fs.h -+++ b/drivers/usb/gadget/function/u_fs.h -@@ -252,8 +252,14 @@ struct ffs_data { - - unsigned short strings_count; - unsigned short interfaces_count; -+ -+ /* -+ * eps_count tracks the number of underlying hardware endpoints. -+ * epfiles_count tracks the total number of VFS endpoint files. -+ * When companion endpoints are active, epfiles_count > eps_count. -+ */ - unsigned short eps_count; -- unsigned short _pad1; -+ unsigned short epfiles_count; - - /* filled by __ffs_data_got_strings() */ - /* ids in stringtabs are set in functionfs_bind() */ -diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c ---- a/drivers/usb/gadget/legacy/inode.c -+++ b/drivers/usb/gadget/legacy/inode.c -@@ -471,11 +471,17 @@ static void ep_user_copy_worker(struct work_struct *work) - struct kiocb *iocb = priv->iocb; - size_t ret; - -- kthread_use_mm(mm); -- ret = copy_to_iter(priv->buf, priv->actual, &priv->to); -- kthread_unuse_mm(mm); -- if (!ret) -+ if (mmget_not_zero(mm)) { -+ kthread_use_mm(mm); -+ ret = copy_to_iter(priv->buf, priv->actual, &priv->to); -+ kthread_unuse_mm(mm); -+ mmput(mm); -+ if (!ret) -+ ret = -EFAULT; -+ } else { - ret = -EFAULT; -+ } -+ mmdrop(mm); - - /* completing the iocb can drop the ctx and mm, don't touch mm after */ - iocb->ki_complete(iocb, ret); -@@ -501,6 +507,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) - * complete the aio request immediately. - */ - if (priv->to_free == NULL || unlikely(req->actual == 0)) { -+ mmdrop(priv->mm); - kfree(req->buf); - kfree(priv->to_free); - kfree(priv); -@@ -541,6 +548,7 @@ static ssize_t ep_aio(struct kiocb *iocb, - priv->epdata = epdata; - priv->actual = 0; - priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */ -+ mmgrab(priv->mm); - - /* each kiocb is coupled to one usb_request, but we can't - * allocate or submit those if the host disconnected. -@@ -570,6 +578,7 @@ static ssize_t ep_aio(struct kiocb *iocb, - - fail: - spin_unlock_irq(&epdata->dev->lock); -+ mmdrop(priv->mm); - kfree(priv->to_free); - kfree(priv); - put_ep(epdata); -diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c ---- a/drivers/usb/gadget/legacy/nokia.c -+++ b/drivers/usb/gadget/legacy/nokia.c -@@ -50,7 +50,7 @@ static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; - */ - #define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS - --#endif /* CONFIG_USB_DEBUG */ -+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - - FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); - -diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig ---- a/drivers/usb/gadget/udc/Kconfig -+++ b/drivers/usb/gadget/udc/Kconfig -@@ -90,7 +90,7 @@ config USB_BCM63XX_UDC - - config USB_FSL_USB2 - tristate "Freescale Highspeed USB DR Peripheral Controller" -- depends on FSL_SOC -+ depends on FSL_SOC || COMPILE_TEST - help - Some of Freescale PowerPC and i.MX processors have a High Speed - Dual-Role(DR) USB controller, which supports device mode. -diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c ---- a/drivers/usb/gadget/udc/fsl_qe_udc.c -+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c -@@ -1945,6 +1945,7 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value, - u16 index, u16 length) - { - u16 usb_status = 0; -+ struct usb_request *usb_req; - struct qe_req *req; - struct qe_ep *ep; - int status = 0; -@@ -1983,8 +1984,11 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value, - } - } - -- req = container_of(qe_alloc_request(&ep->ep, GFP_KERNEL), -- struct qe_req, req); -+ usb_req = qe_alloc_request(&ep->ep, GFP_KERNEL); -+ if (!usb_req) -+ goto stall; -+ -+ req = container_of(usb_req, struct qe_req, req); - req->req.length = 2; - req->req.buf = udc->statusbuf; - *(u16 *)req->req.buf = cpu_to_le16(usb_status); -diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c ---- a/drivers/usb/gadget/udc/pch_udc.c -+++ b/drivers/usb/gadget/udc/pch_udc.c -@@ -320,7 +320,6 @@ struct pch_vbus_gpio_data { - * @lock: protects all state - * @stall: stall requested - * @prot_stall: protcol stall requested -- * @registered: driver registered with system - * @suspended: driver in suspended state - * @connected: gadget driver associated - * @vbus_session: required vbus_session state -diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c ---- a/drivers/usb/host/fsl-mph-dr-of.c -+++ b/drivers/usb/host/fsl-mph-dr-of.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - - struct fsl_usb2_dev_data { - char *dr_mode; /* controller mode */ -@@ -183,7 +184,7 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) - const struct of_device_id *match; - const unsigned char *prop; - static unsigned int idx; -- int i; -+ int i, err; - - if (!of_device_is_available(np)) - return -ENODEV; -@@ -246,6 +247,10 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) - } - } - -+ err = devm_regulator_get_enable_optional(&ofdev->dev, "vbus"); -+ if (err) -+ return dev_err_probe(&ofdev->dev, err, "failed to get vbus regulator\n"); -+ - for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) { - if (!dev_data->drivers[i]) - continue; -diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c ---- a/drivers/usb/host/ohci-dbg.c -+++ b/drivers/usb/host/ohci-dbg.c -@@ -683,7 +683,7 @@ static int fill_buffer(struct debug_buffer *buf) - int ret; - - if (!buf->page) -- buf->page = (char *)get_zeroed_page(GFP_KERNEL); -+ buf->page = kzalloc(PAGE_SIZE, GFP_KERNEL); - - if (!buf->page) { - ret = -ENOMEM; -@@ -729,11 +729,8 @@ static int debug_close(struct inode *inode, struct file *file) - { - struct debug_buffer *buf = file->private_data; - -- if (buf) { -- if (buf->page) -- free_page((unsigned long)buf->page); -- kfree(buf); -- } -+ kfree(buf->page); -+ kfree(buf); - - return 0; - } -diff --git a/drivers/usb/host/xhci-caps.h b/drivers/usb/host/xhci-caps.h ---- a/drivers/usb/host/xhci-caps.h -+++ b/drivers/usb/host/xhci-caps.h -@@ -5,22 +5,23 @@ - */ - - #include -+#include - - /* hc_capbase - bitmasks */ - /* bits 7:0 - Capability Registers Length */ --#define HC_LENGTH(p) ((p) & 0xff) -+#define HC_LENGTH GENMASK(7, 0) - /* bits 15:8 - Rsvd */ - /* bits 31:16 - Host Controller Interface Version Number */ --#define HC_VERSION(p) (((p) >> 16) & 0xffff) -+#define HC_VERSION GENMASK(31, 16) - - /* HCSPARAMS1 - hcs_params1 - bitmasks */ - /* bits 7:0 - Number of Device Slots */ --#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff) --#define HCS_SLOTS_MASK 0xff --/* bits 18:8 - Number of Interrupters, max values is 1024 */ --#define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff) --/* bits 31:24, Max Ports - max value is 255 */ --#define HCS_MAX_PORTS(p) (((p) >> 24) & 0xff) -+#define HCS_SLOTS_MASK GENMASK(7, 0) -+/* bits 18:8 - Number of Interrupters, max values is 1024 */ -+#define HCS_MAX_INTRS GENMASK(18, 8) -+/* bits 23:19 - Rsvd */ -+/* bits 31:24 - Max Ports, max values is 255 */ -+#define HCS_MAX_PORTS GENMASK(31, 24) - - /* HCSPARAMS2 - hcs_params2 - bitmasks */ - /* -@@ -33,24 +34,25 @@ - * Note: 1 Frame = 8 Microframes - * xHCI specification section 5.3.4. - */ --#define HCS_IST_VALUE(p) ((p) & 0x7) -+#define HCS_IST_VALUE GENMASK(2, 0) - #define HCS_IST_UNIT BIT(3) - /* bits 7:4 - Event Ring Segment Table Max, 2^(n) */ --#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) -+#define HCS_ERST_MAX GENMASK(7, 4) - /* bits 20:8 - Rsvd */ - /* bits 25:21 - Max Scratchpad Buffers (Hi), 5 Most significant bits */ --#define HCS_MAX_SP_HI(p) (((p) >> 21) & 0x1f) -+#define HCS_MAX_SP_HI GENMASK(25, 21) - /* bit 26 - Scratchpad restore, for save/restore HW state */ - /* bits 31:27 - Max Scratchpad Buffers (Lo), 5 Least significant bits */ --#define HCS_MAX_SP_LO(p) (((p) >> 27) & 0x1f) --#define HCS_MAX_SCRATCHPAD(p) (HCS_MAX_SP_HI(p) << 5 | HCS_MAX_SP_LO(p)) -+#define HCS_MAX_SP_LO GENMASK(31, 27) -+#define HCS_MAX_SCRATCHPAD(p) (FIELD_GET(HCS_MAX_SP_HI, (p)) << 5 | \ -+ FIELD_GET(HCS_MAX_SP_LO, (p))) - - /* HCSPARAMS3 - hcs_params3 - bitmasks */ - /* bits 7:0 - U1 Device Exit Latency, Max U1 to U0 latency for the roothub ports */ --#define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff) -+#define HCS_U1_LATENCY GENMASK(7, 0) - /* bits 15:8 - Rsvd */ - /* bits 31:16 - U2 Device Exit Latency, Max U2 to U0 latency for the roothub ports */ --#define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff) -+#define HCS_U2_LATENCY GENMASK(31, 16) - - /* HCCPARAMS1 - hcc_params - bitmasks */ - /* bit 0 - 64-bit Addressing Capability */ -@@ -77,19 +79,20 @@ - /* bit 11 - Contiguous Frame ID Capability */ - #define HCC_CFC BIT(11) - /* bits 15:12 - Max size for Primary Stream Arrays, 2^(n+1) */ --#define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1)) -+#define HCC_MAX_PSA GENMASK(15, 12) -+#define GET_MAX_PSA_SIZE(p) (1 << (FIELD_GET(HCC_MAX_PSA, (p)) + 1)) - /* bits 31:16 - xHCI Extended Capabilities Pointer, from PCI base: 2^(n) */ --#define HCC_EXT_CAPS(p) (((p) >> 16) & 0xffff) -+#define HCC_EXT_CAPS GENMASK(31, 16) - - /* DBOFF - db_off - bitmasks */ - /* bits 1:0 - Rsvd */ - /* bits 31:2 - Doorbell Array Offset */ --#define DBOFF_MASK (0xfffffffc) -+#define DBOFF_MASK GENMASK(31, 2) - - /* RTSOFF - run_regs_off - bitmasks */ - /* bits 4:0 - Rsvd */ - /* bits 31:5 - Runtime Register Space Offse */ --#define RTSOFF_MASK (~0x1f) -+#define RTSOFF_MASK GENMASK(31, 5) - - /* HCCPARAMS2 - hcc_params2 - bitmasks */ - /* bit 0 - U3 Entry Capability */ -diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c ---- a/drivers/usb/host/xhci-dbgtty.c -+++ b/drivers/usb/host/xhci-dbgtty.c -@@ -665,11 +665,11 @@ int dbc_tty_init(void) - - void dbc_tty_exit(void) - { -- if (dbc_tty_driver) { -- tty_unregister_driver(dbc_tty_driver); -- tty_driver_kref_put(dbc_tty_driver); -- dbc_tty_driver = NULL; -- } -+ if (IS_ERR_OR_NULL(dbc_tty_driver)) -+ return; - -+ tty_unregister_driver(dbc_tty_driver); -+ tty_driver_kref_put(dbc_tty_driver); - idr_destroy(&dbc_tty_minors); -+ dbc_tty_driver = NULL; - } -diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c ---- a/drivers/usb/host/xhci-debugfs.c -+++ b/drivers/usb/host/xhci-debugfs.c -@@ -9,6 +9,7 @@ - - #include - #include -+#include - - #include "xhci.h" - #include "xhci-debugfs.h" -@@ -791,7 +792,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci) - xhci->debugfs_root, "reg-cap"); - - xhci_debugfs_regset(xhci, -- HC_LENGTH(readl(&xhci->cap_regs->hc_capbase)), -+ FIELD_GET(HC_LENGTH, readl(&xhci->cap_regs->hc_capbase)), - xhci_op_regs, ARRAY_SIZE(xhci_op_regs), - xhci->debugfs_root, "reg-op"); - -diff --git a/drivers/usb/host/xhci-histb.c b/drivers/usb/host/xhci-histb.c ---- a/drivers/usb/host/xhci-histb.c -+++ b/drivers/usb/host/xhci-histb.c -@@ -276,7 +276,7 @@ static int xhci_histb_probe(struct platform_device *pdev) - if (ret) - goto put_usb3_hcd; - -- if (HCC_MAX_PSA(xhci->hcc_params) >= 4) -+ if (GET_MAX_PSA_SIZE(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; - - ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); -diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c ---- a/drivers/usb/host/xhci-hub.c -+++ b/drivers/usb/host/xhci-hub.c -@@ -115,8 +115,8 @@ static int xhci_create_usb3x_bos_desc(struct xhci_hcd *xhci, char *buf, - - if ((xhci->quirks & XHCI_LPM_SUPPORT)) { - reg = readl(&xhci->cap_regs->hcs_params3); -- ss_cap->bU1devExitLat = HCS_U1_LATENCY(reg); -- ss_cap->bU2DevExitLat = cpu_to_le16(HCS_U2_LATENCY(reg)); -+ ss_cap->bU1devExitLat = FIELD_GET(HCS_U1_LATENCY, reg); -+ ss_cap->bU2DevExitLat = cpu_to_le16(FIELD_GET(HCS_U2_LATENCY, reg)); - } - - if (wLength < le16_to_cpu(bos->wTotalLength)) -@@ -1295,7 +1295,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - } - /* In spec software should not attempt to suspend - * a port unless the port reports that it is in the -- * enabled (PED = ‘1’,PLS < ‘3’) state. -+ * enabled (PED = '1',PLS < '3') state. - */ - portsc = xhci_portsc_readl(port); - if ((portsc & PORT_PE) == 0 || (portsc & PORT_RESET) || -diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c ---- a/drivers/usb/host/xhci-mem.c -+++ b/drivers/usb/host/xhci-mem.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - - #include "xhci.h" - #include "xhci-trace.h" -@@ -1001,7 +1002,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, - for (i = 0; i < 31; i++) { - dev->eps[i].ep_index = i; - dev->eps[i].vdev = dev; -- dev->eps[i].xhci = xhci; - INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list); - INIT_LIST_HEAD(&dev->eps[i].bw_endpoint_list); - } -@@ -1493,6 +1493,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, - return -ENOMEM; - - virt_dev->eps[ep_index].skip = false; -+ virt_dev->eps[ep_index].next_uframe = -1; - ep_ring = virt_dev->eps[ep_index].new_ring; - xhci_ring_init(xhci, ep_ring); - -@@ -2083,7 +2084,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, - addr, port_offset, port_count, major_revision); - /* Port count includes the current port offset */ - if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) -- /* WTF? "Valid values are ‘1’ to MaxPorts" */ -+ /* WTF? "Valid values are '1' to MaxPorts" */ - return; - - port_cap = &xhci->port_caps[xhci->num_port_caps++]; -@@ -2300,7 +2301,7 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags) - if (!segs) - segs = ERST_DEFAULT_SEGS; - -- max_segs = BIT(HCS_ERST_MAX(xhci->hcs_params2)); -+ max_segs = FIELD_GET(HCS_ERST_MAX, xhci->hcs_params2) << 2; - segs = min(segs, max_segs); - - ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); -diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c ---- a/drivers/usb/host/xhci-mtk.c -+++ b/drivers/usb/host/xhci-mtk.c -@@ -468,7 +468,7 @@ static void xhci_mtk_quirks(struct device *dev, struct xhci_hcd *xhci) - * MTK xHCI 0.96: PSA is 1 by default even if doesn't support stream, - * and it's 3 when support it. - */ -- if (xhci->hci_version < 0x100 && HCC_MAX_PSA(xhci->hcc_params) == 4) -+ if (xhci->hci_version < 0x100 && GET_MAX_PSA_SIZE(xhci->hcc_params) == 4) - xhci->quirks |= XHCI_BROKEN_STREAMS; - } - -@@ -650,7 +650,7 @@ static int xhci_mtk_probe(struct platform_device *pdev) - } - - usb3_hcd = xhci_get_usb3_hcd(xhci); -- if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 && -+ if (usb3_hcd && GET_MAX_PSA_SIZE(xhci->hcc_params) >= 4 && - !(xhci->quirks & XHCI_BROKEN_STREAMS)) - usb3_hcd->can_do_streams = 1; - -diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c ---- a/drivers/usb/host/xhci-pci.c -+++ b/drivers/usb/host/xhci-pci.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - - #include "xhci.h" - #include "xhci-trace.h" -@@ -662,7 +663,8 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id) - } - - usb3_hcd = xhci_get_usb3_hcd(xhci); -- if (usb3_hcd && !(xhci->quirks & XHCI_BROKEN_STREAMS) && HCC_MAX_PSA(xhci->hcc_params) >= 4) -+ if (usb3_hcd && !(xhci->quirks & XHCI_BROKEN_STREAMS) && -+ GET_MAX_PSA_SIZE(xhci->hcc_params) >= 4) - usb3_hcd->can_do_streams = 1; - - /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ -diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c ---- a/drivers/usb/host/xhci-plat.c -+++ b/drivers/usb/host/xhci-plat.c -@@ -340,7 +340,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - } - - usb3_hcd = xhci_get_usb3_hcd(xhci); -- if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 && -+ if (usb3_hcd && GET_MAX_PSA_SIZE(xhci->hcc_params) >= 4 && - !(xhci->quirks & XHCI_BROKEN_STREAMS)) - usb3_hcd->can_do_streams = 1; - -diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c ---- a/drivers/usb/host/xhci-ring.c -+++ b/drivers/usb/host/xhci-ring.c -@@ -57,6 +57,8 @@ - #include - #include - #include -+#include -+ - #include "xhci.h" - #include "xhci-trace.h" - -@@ -561,8 +563,8 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, - * pointer command pending because the device can choose to start any - * stream once the endpoint is on the HW schedule. - */ -- if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) || -- (ep_state & EP_HALTED) || (ep_state & EP_CLEARING_TT)) -+ if (ep_state & (EP_STOP_CMD_PENDING | SET_DEQ_PENDING | EP_HALTED | -+ EP_CLEARING_TT | EP_DROP_PENDING)) - return; - - trace_xhci_ring_ep_doorbell(slot_id, DB_VALUE(ep_index, stream_id)); -@@ -573,9 +575,8 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, - } - - /* Ring the doorbell for any rings with pending URBs */ --static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci, -- unsigned int slot_id, -- unsigned int ep_index) -+void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci, unsigned int slot_id, -+ unsigned int ep_index) - { - unsigned int stream_id; - struct xhci_virt_ep *ep; -@@ -598,13 +599,6 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci, - } - } - --void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci, -- unsigned int slot_id, -- unsigned int ep_index) --{ -- ring_doorbell_for_active_rings(xhci, slot_id, ep_index); --} -- - static struct xhci_virt_ep *xhci_get_virt_ep(struct xhci_hcd *xhci, - unsigned int slot_id, - unsigned int ep_index) -@@ -686,112 +680,100 @@ static u64 xhci_get_hw_deq(struct xhci_hcd *xhci, struct xhci_virt_device *vdev, - return le64_to_cpu(ep_ctx->deq); - } - --static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, -- unsigned int slot_id, unsigned int ep_index, -- unsigned int stream_id, struct xhci_td *td) -+/* -+ * Move the endpoint dequeue pointer to the next queued TD on ring->td_list or -+ * to enqueue if no TDs are queued (empty ring) -+ * All cancelled TDs on ring->td_list should be moved to ep->cancelled_td_list -+ * before calling this function -+ */ -+static int xhci_move_deq_to_next_td(struct xhci_hcd *xhci, -+ struct xhci_virt_ep *ep, -+ unsigned int stream_id) - { -- struct xhci_virt_device *dev = xhci->devs[slot_id]; -- struct xhci_virt_ep *ep = &dev->eps[ep_index]; -- struct xhci_ring *ep_ring; - struct xhci_command *cmd; -- struct xhci_segment *new_seg; -- union xhci_trb *new_deq; -- int new_cycle; -+ struct xhci_ring *ring; -+ struct xhci_td *td; - dma_addr_t addr; -- u64 hw_dequeue; -- bool hw_dequeue_found = false; -- bool td_last_trb_found = false; -+ int new_cycle; - u32 trb_sct = 0; -- int ret; -+ int ret = 0; - -- ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id, -- ep_index, stream_id); -- if (!ep_ring) { -+ ring = xhci_virt_ep_to_ring(xhci, ep, stream_id); -+ if (!ring) { - xhci_warn(xhci, "WARN can't find new dequeue, invalid stream ID %u\n", - stream_id); - return -ENODEV; - } - -- hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id) & TR_DEQ_PTR_MASK; -- new_seg = ep_ring->deq_seg; -- new_deq = ep_ring->dequeue; -- new_cycle = le32_to_cpu(td->end_trb->generic.field[3]) & TRB_CYCLE; -- -- /* -- * Walk the ring until both the next TRB and hw_dequeue are found (don't -- * move hw_dequeue back if it went forward due to a HW bug). Cycle state -- * is loaded from a known good TRB, track later toggles to maintain it. -- */ -- do { -- if (!hw_dequeue_found && xhci_trb_virt_to_dma(new_seg, new_deq) -- == (dma_addr_t)hw_dequeue) { -- hw_dequeue_found = true; -- if (td_last_trb_found) -- break; -- } -- if (new_deq == td->end_trb) -- td_last_trb_found = true; -- -- if (td_last_trb_found && trb_is_link(new_deq) && -- link_trb_toggles_cycle(new_deq)) -- new_cycle ^= 0x1; -- -- next_trb(&new_seg, &new_deq); -- -- /* Search wrapped around, bail out */ -- if (new_deq == ep->ring->dequeue) { -- xhci_err(xhci, "Error: Failed finding new dequeue state\n"); -- return -EINVAL; -- } -- -- } while (!hw_dequeue_found || !td_last_trb_found); -- -- /* Don't update the ring cycle state for the producer (us). */ -- addr = xhci_trb_virt_to_dma(new_seg, new_deq); -- if (addr == 0) { -- xhci_warn(xhci, "Can't find dma of new dequeue ptr\n"); -- xhci_warn(xhci, "deq seg = %p, deq ptr = %p\n", new_seg, new_deq); -- return -EINVAL; -- } -- - if ((ep->ep_state & SET_DEQ_PENDING)) { -- xhci_warn(xhci, "Set TR Deq already pending, don't submit for %pad\n", -- &addr); -+ xhci_warn(xhci, "Set TR Deq already pending\n"); - return -EBUSY; - } - - /* This function gets called from contexts where it cannot sleep */ - cmd = xhci_alloc_command(xhci, false, GFP_ATOMIC); - if (!cmd) { -- xhci_warn(xhci, "Can't alloc Set TR Deq cmd %pad\n", &addr); -+ xhci_warn(xhci, "Can't alloc Set TR Deq cmd\n"); - return -ENOMEM; - } - -+ /* -+ * Move dequeue to the beginning of next td, or to enqueue if ring is -+ * empty. Avoid moving dequeue to a link trb (empty ring) as it causes -+ * issues on some hosts. In that case advance the enqueue to next segment -+ * before moving dequeue to it -+ */ -+ -+ if (list_empty(&ring->td_list)) { -+ if (trb_is_link(ring->enqueue)) -+ inc_enq_past_link(xhci, ring, 0); -+ ep->queued_deq_seg = ring->enq_seg; -+ ep->queued_deq_ptr = ring->enqueue; -+ new_cycle = ring->cycle_state; -+ } else { -+ td = list_first_entry(&ring->td_list, struct xhci_td, td_list); -+ ep->queued_deq_seg = td->start_seg; -+ ep->queued_deq_ptr = td->start_trb; -+ new_cycle = le32_to_cpu(td->start_trb->generic.field[3]) & TRB_CYCLE; -+ } -+ -+ addr = xhci_trb_virt_to_dma(ep->queued_deq_seg, ep->queued_deq_ptr); -+ if (addr == 0) { -+ xhci_warn(xhci, "Can't find new dequeue dma of seg %p, ptr %p\n", -+ ep->queued_deq_seg, ep->queued_deq_ptr); -+ ret = -EINVAL; -+ goto err_out; -+ } -+ - if (stream_id) - trb_sct = SCT_FOR_TRB(SCT_PRI_TR); - ret = queue_command(xhci, cmd, - lower_32_bits(addr) | trb_sct | new_cycle, - upper_32_bits(addr), -- STREAM_ID_FOR_TRB(stream_id), SLOT_ID_FOR_TRB(slot_id) | -- EP_INDEX_FOR_TRB(ep_index) | TRB_TYPE(TRB_SET_DEQ), false); -- if (ret < 0) { -- xhci_free_command(xhci, cmd); -- return ret; -- } -- ep->queued_deq_seg = new_seg; -- ep->queued_deq_ptr = new_deq; -+ STREAM_ID_FOR_TRB(stream_id), SLOT_ID_FOR_TRB(ep->vdev->slot_id) | -+ EP_INDEX_FOR_TRB(ep->ep_index) | TRB_TYPE(TRB_SET_DEQ), false); -+ if (ret < 0) -+ goto err_out; - - xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, - "Set TR Deq ptr 0x%llx, cycle %u\n", addr, new_cycle); - -- /* Stop the TD queueing code from ringing the doorbell until -- * this command completes. The HC won't set the dequeue pointer -- * if the ring is running, and ringing the doorbell starts the -- * ring running. -+ /* -+ * Stop the TD queueing code from ringing the doorbell until this -+ * command completes. The HC won't set the dequeue pointer if the ring -+ * is running, and ringing the doorbell starts the ring. - */ - ep->ep_state |= SET_DEQ_PENDING; - xhci_ring_cmd_db(xhci); -+ - return 0; -+ -+err_out: -+ xhci_free_command(xhci, cmd); -+ ep->queued_deq_seg = NULL; -+ ep->queued_deq_ptr = NULL; -+ -+ return ret; - } - - /* flip_cycle means flip the cycle bit of all but the first and last TRB. -@@ -950,7 +932,7 @@ static void xhci_dequeue_td(struct xhci_hcd *xhci, struct xhci_td *td, struct xh - } - - /* Complete the cancelled URBs we unlinked from td_list. */ --static void xhci_giveback_invalidated_tds(struct xhci_virt_ep *ep) -+static void xhci_giveback_invalidated_tds(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) - { - struct xhci_ring *ring; - struct xhci_td *td, *tmp_td; -@@ -958,17 +940,17 @@ static void xhci_giveback_invalidated_tds(struct xhci_virt_ep *ep) - list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, - cancelled_td_list) { - -- ring = xhci_urb_to_transfer_ring(ep->xhci, td->urb); -+ ring = xhci_urb_to_transfer_ring(xhci, td->urb); - - if (td->cancel_status == TD_CLEARED) { -- xhci_dbg(ep->xhci, "%s: Giveback cancelled URB %p TD\n", -+ xhci_dbg(xhci, "%s: Giveback cancelled URB %p TD\n", - __func__, td->urb); -- xhci_td_cleanup(ep->xhci, td, ring, td->status); -+ xhci_td_cleanup(xhci, td, ring, td->status); - } else { -- xhci_dbg(ep->xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n", -+ xhci_dbg(xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n", - __func__, td->urb, td->cancel_status); - } -- if (ep->xhci->xhc_state & XHCI_STATE_DYING) -+ if (xhci->xhc_state & XHCI_STATE_DYING) - return; - } - } -@@ -1002,15 +984,19 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, - struct xhci_td *td, - enum xhci_ep_reset_type reset_type) - { -+ struct xhci_port *rhub_port = ep->vdev->rhub_port; - unsigned int slot_id = ep->vdev->slot_id; - int err; - - /* -- * Avoid resetting endpoint if link is inactive. Can cause host hang. -- * Device will be reset soon to recover the link so don't do anything -+ * Avoid resetting endpoint if link is inactive or device disonnected. -+ * Can cause host hang. -+ * Device will be reset to recover an inactive link, so don't do anything - */ -- if (ep->vdev->flags & VDEV_PORT_ERROR) -+ if (rhub_port->link_inactive || !rhub_port->connected) { -+ ep->ep_state |= EP_DROP_PENDING; - return -ENODEV; -+ } - - /* add td to cancelled list and let reset ep handler take care of it */ - if (reset_type == EP_HARD_RESET) { -@@ -1047,15 +1033,13 @@ static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, - * only call this when ring is not in a running state - */ - --static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) -+static int xhci_invalidate_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) - { -- struct xhci_hcd *xhci; - struct xhci_td *td = NULL; - struct xhci_td *tmp_td = NULL; - struct xhci_td *cached_td = NULL; - struct xhci_ring *ring; - u64 hw_deq; -- unsigned int slot_id = ep->vdev->slot_id; - int err; - - /* -@@ -1065,8 +1049,6 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) - if (ep->ep_state & SET_DEQ_PENDING) - return 0; - -- xhci = ep->xhci; -- - list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, cancelled_td_list) { - xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, - "Removing canceled TD starting at 0x%llx (dma) in stream %u URB %p", -@@ -1080,6 +1062,13 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) - td->urb, td->urb->stream_id); - continue; - } -+ -+ /* device disconnected or link error, ep will be dropped */ -+ if (ep->ep_state & EP_DROP_PENDING) { -+ td->cancel_status = TD_CLEARED; -+ continue; -+ } -+ - /* - * If a ring stopped on the TD we need to cancel then we have to - * move the xHC endpoint ring dequeue pointer past this TD. -@@ -1131,9 +1120,8 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) - if (!cached_td) - return 0; - -- err = xhci_move_dequeue_past_td(xhci, slot_id, ep->ep_index, -- cached_td->urb->stream_id, -- cached_td); -+ err = xhci_move_deq_to_next_td(xhci, ep, cached_td->urb->stream_id); -+ - if (err) { - /* Failed to move past cached td, just set cached TDs to no-op */ - list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, cancelled_td_list) { -@@ -1161,23 +1149,23 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) - * - * Call under xhci->lock on a stopped endpoint. - */ --void xhci_process_cancelled_tds(struct xhci_virt_ep *ep) -+void xhci_process_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) - { -- xhci_invalidate_cancelled_tds(ep); -- xhci_giveback_invalidated_tds(ep); -+ xhci_invalidate_cancelled_tds(xhci, ep); -+ xhci_giveback_invalidated_tds(xhci, ep); - } - - /* - * Returns the TD the endpoint ring halted on. - * Only call for non-running rings without streams. - */ --static struct xhci_td *find_halted_td(struct xhci_virt_ep *ep) -+static struct xhci_td *find_halted_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) - { - struct xhci_td *td; - u64 hw_deq; - - if (!list_empty(&ep->ring->td_list)) { /* Not streams compatible */ -- hw_deq = xhci_get_hw_deq(ep->xhci, ep->vdev, ep->ep_index, 0); -+ hw_deq = xhci_get_hw_deq(xhci, ep->vdev, ep->ep_index, 0); - hw_deq &= TR_DEQ_PTR_MASK; - td = list_first_entry(&ep->ring->td_list, struct xhci_td, td_list); - if (trb_in_td(td, hw_deq)) -@@ -1252,7 +1240,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, - reset_type = EP_SOFT_RESET; - } else { - reset_type = EP_HARD_RESET; -- td = find_halted_td(ep); -+ td = find_halted_td(xhci, ep); - if (td) - td->status = -EPROTO; - } -@@ -1310,13 +1298,17 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, - } - } - -+ /* link is inactive or disconnected, ep is not running and shouldn't be restarted */ -+ if (ep->vdev->rhub_port->link_inactive || !ep->vdev->rhub_port->connected) -+ ep->ep_state |= EP_DROP_PENDING; -+ - /* will queue a set TR deq if stopped on a cancelled, uncleared TD */ -- xhci_invalidate_cancelled_tds(ep); -+ xhci_invalidate_cancelled_tds(xhci, ep); - ep->ep_state &= ~EP_STOP_CMD_PENDING; - - /* Otherwise ring the doorbell(s) to restart queued transfers */ -- xhci_giveback_invalidated_tds(ep); -- ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -+ xhci_giveback_invalidated_tds(xhci, ep); -+ xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - } - - static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring) -@@ -1537,14 +1529,14 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, - /* HW cached TDs cleared from cache, give them back */ - list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, - cancelled_td_list) { -- ep_ring = xhci_urb_to_transfer_ring(ep->xhci, td->urb); -+ ep_ring = xhci_urb_to_transfer_ring(xhci, td->urb); - if (td->cancel_status == TD_CLEARING_CACHE) { - td->cancel_status = TD_CLEARED; -- xhci_dbg(ep->xhci, "%s: Giveback cancelled URB %p TD\n", -+ xhci_dbg(xhci, "%s: Giveback cancelled URB %p TD\n", - __func__, td->urb); -- xhci_td_cleanup(ep->xhci, td, ep_ring, td->status); -+ xhci_td_cleanup(xhci, td, ep_ring, td->status); - } else { -- xhci_dbg(ep->xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n", -+ xhci_dbg(xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n", - __func__, td->urb, td->cancel_status); - } - } -@@ -1555,17 +1547,17 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, - - /* Check for deferred or newly cancelled TDs */ - if (!list_empty(&ep->cancelled_td_list)) { -- xhci_dbg(ep->xhci, "%s: Pending TDs to clear, continuing with invalidation\n", -+ xhci_dbg(xhci, "%s: Pending TDs to clear, continuing with invalidation\n", - __func__); -- xhci_invalidate_cancelled_tds(ep); -+ xhci_invalidate_cancelled_tds(xhci, ep); - /* Try to restart the endpoint if all is done */ -- ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -+ xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - /* Start giving back any TDs invalidated above */ -- xhci_giveback_invalidated_tds(ep); -+ xhci_giveback_invalidated_tds(xhci, ep); - } else { - /* Restart any rings with pending URBs */ -- xhci_dbg(ep->xhci, "%s: All TDs cleared, ring doorbell\n", __func__); -- ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -+ xhci_dbg(xhci, "%s: All TDs cleared, ring doorbell\n", __func__); -+ xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - } - } - -@@ -1591,16 +1583,16 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, - "Ignoring reset ep completion code of %u", cmd_comp_code); - - /* Cleanup cancelled TDs as ep is stopped. May queue a Set TR Deq cmd */ -- xhci_invalidate_cancelled_tds(ep); -+ xhci_invalidate_cancelled_tds(xhci, ep); - - /* Clear our internal halted state */ - ep->ep_state &= ~EP_HALTED; - -- xhci_giveback_invalidated_tds(ep); -+ xhci_giveback_invalidated_tds(xhci, ep); - - /* if this was a soft reset, then restart */ - if ((le32_to_cpu(trb->generic.field[3])) & TRB_TSP) -- ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -+ xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - } - - static void xhci_handle_cmd_enable_slot(int slot_id, struct xhci_command *command, -@@ -2008,13 +2000,15 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci) - static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) - { - struct xhci_virt_device *vdev = NULL; -- struct usb_hcd *hcd; -- u32 port_id; -- u32 portsc, cmd_reg; -- unsigned int hcd_portnum; - struct xhci_bus_state *bus_state; -- bool bogus_port_status = false; - struct xhci_port *port; -+ struct usb_hcd *hcd; -+ bool bogus_port_status = false; -+ unsigned int hcd_portnum; -+ u32 cmd_reg; -+ u32 port_id; -+ u32 portsc; -+ u32 pls; - - /* Port status change events always have a successful completion code */ - if (GET_COMP_CODE(le32_to_cpu(event->generic.field[2])) != COMP_SUCCESS) -@@ -2051,6 +2045,7 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) - bus_state = &port->rhub->bus_state; - hcd_portnum = port->hcd_portnum; - portsc = xhci_portsc_readl(port); -+ pls = portsc & PORT_PLS_MASK; - - xhci_dbg(xhci, "Port change event, %d-%d, id %d, portsc: 0x%x\n", - hcd->self.busnum, hcd_portnum + 1, port_id, portsc); -@@ -2062,11 +2057,13 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) - usb_hcd_resume_root_hub(hcd); - } - -- if (vdev && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) { -- if (!(portsc & PORT_RESET)) -- vdev->flags |= VDEV_PORT_ERROR; -- } else if (vdev && portsc & PORT_RC) { -- vdev->flags &= ~VDEV_PORT_ERROR; -+ /* -+ * Tag broken links to avoid retries while hub driver sorts it out. -+ * Link status is not relible while port is in reset. -+ */ -+ if (!(portsc & PORT_RESET)) { -+ port->link_inactive = (pls == XDEV_INACTIVE); -+ port->connected = !!(portsc & PORT_CONNECT); - } - - if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) { -@@ -3978,88 +3975,102 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci, - /* Returns the Isochronous Scheduling Threshold in Microframes. 1 Frame is 8 Microframes. */ - static int xhci_ist_microframes(struct xhci_hcd *xhci) - { -- int ist = HCS_IST_VALUE(xhci->hcs_params2); -+ int ist = FIELD_GET(HCS_IST_VALUE, xhci->hcs_params2); - - if (xhci->hcs_params2 & HCS_IST_UNIT) - ist *= 8; - return ist; - } - --/* -- * Calculates Frame ID field of the isochronous TRB identifies the -- * target frame that the Interval associated with this Isochronous -- * Transfer Descriptor will start on. Refer to 4.11.2.5 in 1.1 spec. -- * -- * Returns actual frame id on success, negative value on error. -- */ --static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci, -- struct urb *urb, int index) -+ -+static bool xhci_isoc_td_uses_frame_id(struct xhci_hcd *xhci, struct urb *urb, -+ struct xhci_virt_ep *ep, int i) - { -- int start_frame, ist, ret = 0; -- int start_frame_id, end_frame_id, current_frame_id; -+ if (urb->transfer_flags & URB_ISO_ASAP) -+ return false; - -- if (urb->dev->speed == USB_SPEED_LOW || -- urb->dev->speed == USB_SPEED_FULL) -- start_frame = urb->start_frame + index * urb->interval; -- else -- start_frame = (urb->start_frame + index * urb->interval) >> 3; -+ if (xhci->hcc_params & HCC_CFC) -+ return true; - -+ /* set frame id for first TD of first URB in stream */ -+ if (ep->next_uframe == -1 && i == 0) -+ return true; -+ -+ return false; -+} -+ -+/* -+ * Check if frame is in the valid frame window, including start and end. -+ * If start > end then assume window wrapped around at a limit the frame -+ * value won't exceed. -+ */ -+static bool xhci_frame_in_range(u32 frame, u32 start, u32 end) -+{ -+ /* frame window end wrapped around */ -+ if (start > end) -+ return frame >= start || frame <= end; -+ -+ return frame >= start && frame <= end; -+} -+ -+/* -+ * Set the urb->start_frame of the URB. -+ * -+ * Returns microframe index of first TD -+ */ -+static int xhci_get_isoc_start_frame(struct xhci_hcd *xhci, struct urb *urb, -+ struct xhci_virt_ep *ep) -+{ -+ u32 curr_frame, start_uframe; -+ u32 urb_start, urb_end; -+ u32 win_start, win_end; -+ bool frame_unit; -+ int uinterval; -+ u32 mfindex; -+ int ist; -+ -+ /* check if urb uses frame units instead of microframes */ -+ frame_unit = (urb->dev->speed == USB_SPEED_FULL || -+ urb->dev->speed == USB_SPEED_LOW); -+ -+ uinterval = urb->interval; -+ if (frame_unit) -+ uinterval *= 8; -+ -+ /* get current microframe index and isoc scheduling threshold */ -+ mfindex = readl(&xhci->run_regs->microframe_index); - ist = xhci_ist_microframes(xhci); - -- /* Software shall not schedule an Isoch TD with a Frame ID value that -- * is less than the Start Frame ID or greater than the End Frame ID, -- * where: -- * -- * End Frame ID = (Current MFINDEX register value + 895 ms.) MOD 2048 -- * Start Frame ID = (Current MFINDEX register value + IST + 1) MOD 2048 -- * -- * Both the End Frame ID and Start Frame ID values are calculated -- * in microframes. When software determines the valid Frame ID value; -- * The End Frame ID value should be rounded down to the nearest Frame -- * boundary, and the Start Frame ID value should be rounded up to the -- * nearest Frame boundary. -- */ -- current_frame_id = readl(&xhci->run_regs->microframe_index); -- start_frame_id = roundup(current_frame_id + ist + 1, 8); -- end_frame_id = rounddown(current_frame_id + 895 * 8, 8); -+ /* calculate valid frame window, in frame units, see xhci 4.11.2.5 */ -+ curr_frame = MFINDEX_TO_FRAME(mfindex); -+ win_start = (curr_frame + DIV_ROUND_UP_POW2(ist, 8) + 1) % MAX_FRAMES; -+ win_end = (curr_frame + 895) % MAX_FRAMES; - -- start_frame &= 0x7ff; -- start_frame_id = (start_frame_id >> 3) & 0x7ff; -- end_frame_id = (end_frame_id >> 3) & 0x7ff; -- -- if (start_frame_id < end_frame_id) { -- if (start_frame > end_frame_id || -- start_frame < start_frame_id) -- ret = -EINVAL; -- } else if (start_frame_id > end_frame_id) { -- if ((start_frame > end_frame_id && -- start_frame < start_frame_id)) -- ret = -EINVAL; -+ /* Is this the first URB starting the whole isoc data flow? */ -+ if (ep->next_uframe < 0) { -+ /* align first URB to next interval boundary, or at last to full frame */ -+ start_uframe = mfindex + ist + XHCI_CFC_DELAY; -+ start_uframe = roundup(start_uframe, 8); -+ start_uframe = roundup(start_uframe, uinterval) % MAX_UFRAMES; - } else { -- ret = -EINVAL; -- } -+ /* URB is mid stream and expected to handle the next frame */ -+ start_uframe = ep->next_uframe; -+ urb_start = start_uframe / 8; -+ urb_end = (start_uframe + urb->number_of_packets * uinterval) / 8; -+ urb_end %= MAX_FRAMES; - -- if (index == 0) { -- if (ret == -EINVAL || start_frame == start_frame_id) { -- start_frame = start_frame_id + 1; -- if (urb->dev->speed == USB_SPEED_LOW || -- urb->dev->speed == USB_SPEED_FULL) -- urb->start_frame = start_frame; -- else -- urb->start_frame = start_frame << 3; -- ret = 0; -- } -- } -+ if (!xhci_frame_in_range(urb_start, win_start, win_end)) -+ xhci_dbg(xhci, "Ill-timed isoc URB %p for start frame %d, range %d-%d\n", -+ urb, urb_start, win_start, win_end); - -- if (ret) { -- xhci_warn(xhci, "Frame ID %d (reg %d, index %d) beyond range (%d, %d)\n", -- start_frame, current_frame_id, index, -- start_frame_id, end_frame_id); -- xhci_warn(xhci, "Ignore frame ID field, use SIA bit instead\n"); -- return ret; -+ if (!xhci_frame_in_range(urb_end, win_start, win_end)) -+ xhci_dbg(xhci, "Ill-timed isoc URB %p for end frame %d, range %d-%d\n", -+ urb, urb_start, win_start, win_end); - } -+ /* set urb->start_frame */ -+ urb->start_frame = frame_unit ? start_uframe / 8 : start_uframe; - -- return start_frame; -+ return start_uframe; - } - - /* Check if we should generate event interrupt for a TD in an isoc URB */ -@@ -4099,7 +4110,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - int i, j; - bool more_trbs_coming; - struct xhci_virt_ep *xep; -- int frame_id; -+ int uinterval = urb->interval; -+ int start_uframe; - - xep = &xhci->devs[slot_id]->eps[ep_index]; - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; -@@ -4115,6 +4127,12 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - start_cycle = ep_ring->cycle_state; - - urb_priv = urb->hcpriv; -+ -+ if (urb->dev->speed == USB_SPEED_FULL || urb->dev->speed == USB_SPEED_LOW) -+ uinterval = urb->interval * 8; -+ -+ start_uframe = xhci_get_isoc_start_frame(xhci, urb, xep); -+ - /* Queue the TRBs for each TD, even if they are zero-length */ - for (i = 0; i < num_tds; i++) { - unsigned int total_pkt_count, max_pkt; -@@ -4146,14 +4164,16 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - goto cleanup; - } - td = &urb_priv->td[i]; -- /* use SIA as default, if frame id is used overwrite it */ -- sia_frame_id = TRB_SIA; -- if (!(urb->transfer_flags & URB_ISO_ASAP) && -- (xhci->hcc_params & HCC_CFC)) { -- frame_id = xhci_get_isoc_frame_id(xhci, urb, i); -- if (frame_id >= 0) -- sia_frame_id = TRB_FRAME_ID(frame_id); -+ -+ -+ /* Choose SIA or frame ID based scheduling for this TD */ -+ if (xhci_isoc_td_uses_frame_id(xhci, urb, xep, i)) { -+ sia_frame_id = (start_uframe + i * uinterval) / 8; -+ sia_frame_id = TRB_FRAME_ID(sia_frame_id % MAX_FRAMES); -+ } else { -+ sia_frame_id = TRB_SIA; - } -+ - /* - * Set isoc specific data for the first TRB in a TD. - * Prevent HW from getting the TRBs by keeping the cycle state -@@ -4232,9 +4252,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - } - } - -- /* store the next frame id */ -- if (xhci->hcc_params & HCC_CFC) -- xep->next_frame_id = urb->start_frame + num_tds * urb->interval; -+ xep->next_uframe = (start_uframe + num_tds * uinterval) % MAX_UFRAMES; - - if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { - if (xhci->quirks & XHCI_AMD_PLL_FIX) -@@ -4281,11 +4299,9 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, - struct xhci_virt_device *xdev; - struct xhci_ring *ep_ring; - struct xhci_ep_ctx *ep_ctx; -- int start_frame; -+ struct xhci_virt_ep *xep; - int num_tds, num_trbs, i; - int ret; -- struct xhci_virt_ep *xep; -- int ist; - - xdev = xhci->devs[slot_id]; - xep = &xhci->devs[slot_id]->eps[ep_index]; -@@ -4311,38 +4327,12 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, - */ - check_interval(urb, ep_ctx); - -- /* Calculate the start frame and put it in urb->start_frame. */ -- if ((xhci->hcc_params & HCC_CFC) && !list_empty(&ep_ring->td_list)) { -- if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_RUNNING) { -- urb->start_frame = xep->next_frame_id; -- goto skip_start_over; -- } -- } -- -- start_frame = readl(&xhci->run_regs->microframe_index); -- start_frame &= 0x3fff; - /* -- * Round up to the next frame and consider the time before trb really -- * gets scheduled by hardare. -+ * Check if this starts the isoc data flow. Relies on hw setting ep ctx -+ * state after doorbell ring. Consider adding list_empty(td_list) check - */ -- ist = xhci_ist_microframes(xhci); -- start_frame += ist + XHCI_CFC_DELAY; -- start_frame = roundup(start_frame, 8); -- -- /* -- * Round up to the next ESIT (Endpoint Service Interval Time) if ESIT -- * is greate than 8 microframes. -- */ -- if (urb->dev->speed == USB_SPEED_LOW || -- urb->dev->speed == USB_SPEED_FULL) { -- start_frame = roundup(start_frame, urb->interval << 3); -- urb->start_frame = start_frame >> 3; -- } else { -- start_frame = roundup(start_frame, urb->interval); -- urb->start_frame = start_frame; -- } -- --skip_start_over: -+ if (GET_EP_CTX_STATE(ep_ctx) != EP_STATE_RUNNING) -+ xep->next_uframe = -1; - - return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); - } -diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c ---- a/drivers/usb/host/xhci-tegra.c -+++ b/drivers/usb/host/xhci-tegra.c -@@ -6,6 +6,7 @@ - * Copyright (C) 2014 Google, Inc. - */ - -+#include - #include - #include - #include -@@ -993,7 +994,7 @@ static int tegra_xusb_wait_for_falcon(struct tegra_xusb *tegra) - u32 value; - - cap_regs = tegra->regs; -- op_regs = tegra->regs + HC_LENGTH(readl(&cap_regs->hc_capbase)); -+ op_regs = tegra->regs + FIELD_GET(HC_LENGTH, readl(&cap_regs->hc_capbase)), - - ret = readl_poll_timeout(&op_regs->status, value, !(value & STS_CNR), 1000, 200000); - -@@ -1895,7 +1896,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) - goto remove_usb2; - } - -- if (HCC_MAX_PSA(xhci->hcc_params) >= 4) -+ if (GET_MAX_PSA_SIZE(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; - - err = usb_add_hcd(xhci->shared_hcd, tegra->xhci_irq, IRQF_SHARED); -diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c ---- a/drivers/usb/host/xhci.c -+++ b/drivers/usb/host/xhci.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - - #include "xhci.h" - #include "xhci-trace.h" -@@ -1664,7 +1665,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag - goto free_priv; - } - -- if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) { -+ if (xhci->devs[slot_id]->rhub_port->link_inactive) { - xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); - ret = -ENODEV; - goto free_priv; -@@ -1852,11 +1853,11 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) - } - - /* In this case no commands are pending but the endpoint is stopped */ -- if (ep->ep_state & EP_CLEARING_TT) { -+ if (ep->ep_state & (EP_CLEARING_TT | EP_DROP_PENDING)) { - /* and cancelled TDs can be given back right away */ - xhci_dbg(xhci, "Invalidating TDs instantly on slot %d ep %d in state 0x%x\n", - urb->dev->slot_id, ep_index, ep->ep_state); -- xhci_process_cancelled_tds(ep); -+ xhci_process_cancelled_tds(xhci, ep); - } else { - /* Otherwise, queue a new Stop Endpoint command */ - command = xhci_alloc_command(xhci, false, GFP_ATOMIC); -@@ -3507,7 +3508,7 @@ static void xhci_calculate_streams_entries(struct xhci_hcd *xhci, - * level page entries), but that's an optional feature for xHCI host - * controllers. xHCs must support at least 4 stream IDs. - */ -- max_streams = HCC_MAX_PSA(xhci->hcc_params); -+ max_streams = GET_MAX_PSA_SIZE(xhci->hcc_params); - if (*num_stream_ctxs > max_streams) { - xhci_dbg(xhci, "xHCI HW only supports %u stream ctx entries.\n", - max_streams); -@@ -3637,7 +3638,7 @@ static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, - - /* MaxPSASize value 0 (2 streams) means streams are not supported */ - if ((xhci->quirks & XHCI_BROKEN_STREAMS) || -- HCC_MAX_PSA(xhci->hcc_params) < 4) { -+ GET_MAX_PSA_SIZE(xhci->hcc_params) < 4) { - xhci_dbg(xhci, "xHCI controller does not support streams.\n"); - return -ENOSYS; - } -@@ -4035,7 +4036,6 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, - xhci_get_slot_state(xhci, virt_dev->out_ctx)); - xhci_dbg(xhci, "Not freeing device rings.\n"); - /* Don't treat this as an error. May change my mind later. */ -- virt_dev->flags = 0; - ret = 0; - goto command_cleanup; - case COMP_SUCCESS: -@@ -4087,10 +4087,12 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, - } - /* If necessary, update the number of active TTs on this root port */ - xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps); -- virt_dev->flags = 0; - ret = 0; - - command_cleanup: -+ for (i = 0; i < EP_CTX_PER_DEV; i++) -+ virt_dev->eps[i].ep_state &= ~EP_DROP_PENDING; -+ - xhci_free_command(xhci, reset_device_cmd); - return ret; - } -@@ -4607,7 +4609,7 @@ static int xhci_calculate_hird_besl(struct xhci_hcd *xhci, - int besl_device = 0; - u32 field; - -- u2del = HCS_U2_LATENCY(xhci->hcs_params3); -+ u2del = FIELD_GET(HCS_U2_LATENCY, xhci->hcs_params3); - field = le32_to_cpu(udev->bos->ext_cap->bmAttributes); - - if (field & USB_BESL_SUPPORT) { -@@ -5459,26 +5461,28 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) - xhci_warn(xhci, "Host controller not accessible, removed?\n"); - return -ENODEV; - } -- xhci->op_regs = hcd->regs + HC_LENGTH(hc_capbase); -+ xhci->op_regs = hcd->regs + FIELD_GET(HC_LENGTH, hc_capbase); -+ - xhci->run_regs = hcd->regs + - (readl(&xhci->cap_regs->run_regs_off) & RTSOFF_MASK); - /* Cache read-only capability registers */ - hcs_params1 = readl(&xhci->cap_regs->hcs_params1); - xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2); - xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3); -- xhci->hci_version = HC_VERSION(hc_capbase); -+ xhci->hci_version = FIELD_GET(HC_VERSION, hc_capbase); - xhci->hcc_params = readl(&xhci->cap_regs->hcc_params); - if (xhci->hci_version > 0x100) - xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); - - xhci->dma_mask_bits = 64; -- xhci->max_slots = min(HCS_MAX_SLOTS(hcs_params1), MAX_HC_SLOTS); -- xhci->max_ports = min(HCS_MAX_PORTS(hcs_params1), MAX_HC_PORTS); -+ xhci->max_slots = min(FIELD_GET(HCS_SLOTS_MASK, hcs_params1), MAX_HC_SLOTS); -+ xhci->max_ports = min(FIELD_GET(HCS_MAX_PORTS, hcs_params1), MAX_HC_PORTS); -+ - /* xhci-plat or xhci-pci might have set max_interrupters already */ - if (!xhci->max_interrupters) -- xhci->max_interrupters = min(HCS_MAX_INTRS(hcs_params1), MAX_HC_INTRS); -- else if (xhci->max_interrupters > HCS_MAX_INTRS(hcs_params1)) -- xhci->max_interrupters = HCS_MAX_INTRS(hcs_params1); -+ xhci->max_interrupters = min(FIELD_GET(HCS_MAX_INTRS, hcs_params1), MAX_HC_INTRS); -+ else if (xhci->max_interrupters > FIELD_GET(HCS_MAX_INTRS, hcs_params1)) -+ xhci->max_interrupters = FIELD_GET(HCS_MAX_INTRS, hcs_params1); - - xhci->quirks |= quirks; - -@@ -5519,7 +5523,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) - * DMA_BIT_MASK(32)) in this xhci_gen_setup(). - */ - if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) -- xhci->hcc_params &= ~BIT(0); -+ xhci->hcc_params &= ~HCC_64BIT_ADDR; - - /* - * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports -diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h ---- a/drivers/usb/host/xhci.h -+++ b/drivers/usb/host/xhci.h -@@ -290,6 +290,11 @@ struct xhci_run_regs { - struct xhci_intr_reg ir_set[1024]; - }; - -+/* Bits [13:3] of the microframe index equals the 1ms frame index */ -+#define MFINDEX_TO_FRAME(p) (((p) >> 3) & 0x7ff) -+#define MAX_FRAMES 2048 -+#define MAX_UFRAMES (MAX_FRAMES * 8) -+ - /** - * struct doorbell_array - * -@@ -677,9 +682,9 @@ struct xhci_virt_ep { - #define EP_SOFT_CLEAR_TOGGLE BIT(7) - /* usb_hub_clear_tt_buffer is in progress */ - #define EP_CLEARING_TT BIT(8) -+#define EP_DROP_PENDING BIT(9) /* port disconnect or link error, don't restart */ - /* ---- Related to URB cancellation ---- */ - struct list_head cancelled_td_list; -- struct xhci_hcd *xhci; - /* Dequeue pointer and dequeue segment for a submitted Set TR Dequeue - * command. We'll need to update the ring's dequeue segment and dequeue - * pointer after the command completes. -@@ -699,7 +704,7 @@ struct xhci_virt_ep { - struct list_head bw_endpoint_list; - unsigned long stop_time; - /* Isoch Frame ID checking storage */ -- int next_frame_id; -+ int next_uframe; - /* Use new Isoch TRB layout needed for extended TBC support */ - bool use_extended_tbc; - /* set if this endpoint is controlled via sideband access*/ -@@ -753,14 +758,6 @@ struct xhci_virt_device { - struct xhci_port *rhub_port; - struct xhci_interval_bw_table *bw_table; - struct xhci_tt_bw_info *tt_info; -- /* -- * flags for state tracking based on events and issued commands. -- * Software can not rely on states from output contexts because of -- * latency between events and xHC updating output context values. -- * See xhci 1.1 section 4.8.3 for more details -- */ -- unsigned long flags; --#define VDEV_PORT_ERROR BIT(0) /* Port error, link inactive */ - - /* The current max exit latency for the enabled USB3 link states. */ - u16 current_mel; -@@ -1480,6 +1477,8 @@ struct xhci_port { - int hcd_portnum; - struct xhci_hub *rhub; - struct xhci_port_cap *port_cap; -+ unsigned int link_inactive:1; -+ unsigned int connected:1; - unsigned int lpm_incapable:1; - unsigned long resume_timestamp; - bool rexit_active; -@@ -1961,7 +1960,7 @@ unsigned int count_trbs(u64 addr, u64 len); - unsigned int xhci_num_trbs_free(struct xhci_ring *ring); - int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, - int suspend, gfp_t gfp_flags); --void xhci_process_cancelled_tds(struct xhci_virt_ep *ep); -+void xhci_process_cancelled_tds(struct xhci_hcd *xhci, struct xhci_virt_ep *ep); - void xhci_update_erst_dequeue(struct xhci_hcd *xhci, - struct xhci_interrupter *ir, - bool clear_ehb); -diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c ---- a/drivers/usb/misc/cypress_cy7c63.c -+++ b/drivers/usb/misc/cypress_cy7c63.c -@@ -89,8 +89,11 @@ static int vendor_command(struct cypress *dev, unsigned char request, - address, data, iobuf, CYPRESS_MAX_REQSIZE, - USB_CTRL_GET_TIMEOUT); - /* we must not process garbage */ -- if (retval < 2) -+ if (retval < 2) { -+ if (retval >= 0) -+ retval = -EIO; - goto err_buf; -+ } - - /* store returned data (more READs to be added) */ - switch (request) { -@@ -175,8 +178,9 @@ static ssize_t read_port(struct device *dev, struct device_attribute *attr, - dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", port_num); - - result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0); -- - dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); -+ if (result < 0) -+ return result; - - return sprintf(buf, "%d", cyp->port[port_num]); - } -diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c ---- a/drivers/usb/misc/uss720.c -+++ b/drivers/usb/misc/uss720.c -@@ -223,6 +223,7 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha - } - printk(KERN_WARNING "get_1284_register timeout\n"); - kill_all_async_requests_priv(priv); -+ kref_put(&rq->ref_count, destroy_async); - return -EIO; - } - -diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c ---- a/drivers/usb/mtu3/mtu3_host.c -+++ b/drivers/usb/mtu3/mtu3_host.c -@@ -46,6 +46,14 @@ - #define WC1_IS_P_95 BIT(12) - #define WC1_IS_EN_P0_95 BIT(6) - -+/* mt8196 */ -+#define PERI_WK_CTRL0_8196 0x08 -+#define WC0_IS_EN_P0_96 BIT(0) -+#define WC0_IS_EN_P1_96 BIT(7) -+ -+#define PERI_WK_CTRL1_8196 0x10 -+#define WC1_IS_EN_P2_96 BIT(0) -+ - /* mt2712 etc */ - #define PERI_SSUSB_SPM_CTRL 0x0 - #define SSC_IP_SLEEP_EN BIT(4) -@@ -59,6 +67,9 @@ enum ssusb_uwk_vers { - SSUSB_UWK_V1_3, /* mt8195 IP0 */ - SSUSB_UWK_V1_5 = 105, /* mt8195 IP2 */ - SSUSB_UWK_V1_6, /* mt8195 IP3 */ -+ SSUSB_UWK_V1_7, /* mt8196 IP0 */ -+ SSUSB_UWK_V1_8, /* mt8196 IP1 */ -+ SSUSB_UWK_V1_9, /* mt8196 IP2 */ - }; - - /* -@@ -100,6 +111,21 @@ static void ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable) - msk = WC0_IS_EN_P3_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95; - val = enable ? (WC0_IS_EN_P3_95 | WC0_IS_C_95(0x1)) : 0; - break; -+ case SSUSB_UWK_V1_7: -+ reg = ssusb->uwk_reg_base + PERI_WK_CTRL0_8196; -+ msk = WC0_IS_EN_P0_96; -+ val = enable ? msk : 0; -+ break; -+ case SSUSB_UWK_V1_8: -+ reg = ssusb->uwk_reg_base + PERI_WK_CTRL0_8196; -+ msk = WC0_IS_EN_P1_96; -+ val = enable ? msk : 0; -+ break; -+ case SSUSB_UWK_V1_9: -+ reg = ssusb->uwk_reg_base + PERI_WK_CTRL1_8196; -+ msk = WC1_IS_EN_P2_96; -+ val = enable ? msk : 0; -+ break; - case SSUSB_UWK_V2: - reg = ssusb->uwk_reg_base + PERI_SSUSB_SPM_CTRL; - msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN; -diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c ---- a/drivers/usb/mtu3/mtu3_plat.c -+++ b/drivers/usb/mtu3/mtu3_plat.c -@@ -544,7 +544,8 @@ static int mtu3_suspend_common(struct device *dev, pm_message_t msg) - - ssusb_phy_power_off(ssusb); - clk_bulk_disable_unprepare(BULK_CLKS_CNT, ssusb->clks); -- ssusb_wakeup_set(ssusb, true); -+ if (device_may_wakeup(dev) && (ssusb->is_host || PMSG_IS_AUTO(msg))) -+ ssusb_wakeup_set(ssusb, true); - return 0; - - sleep_err: -diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig ---- a/drivers/usb/musb/Kconfig -+++ b/drivers/usb/musb/Kconfig -@@ -116,7 +116,6 @@ config USB_MUSB_POLARFIRE_SOC - tristate "Microchip PolarFire SoC platforms" - depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST - depends on NOP_USB_XCEIV -- select USB_MUSB_DUAL_ROLE - help - Say Y here to enable support for USB on Microchip's PolarFire SoC. - -diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c ---- a/drivers/usb/musb/musb_host.c -+++ b/drivers/usb/musb/musb_host.c -@@ -1774,7 +1774,8 @@ void musb_host_rx(struct musb *musb, u8 epnum) - status = -EPIPE; - - } else if (rx_csr & MUSB_RXCSR_H_ERROR) { -- dev_err(musb->controller, "ep%d RX three-strikes error", epnum); -+ dev_err_ratelimited(musb->controller, -+ "ep%d RX three-strikes error\n", epnum); - - /* - * The three-strikes error could only happen when the USB -@@ -1788,6 +1789,17 @@ void musb_host_rx(struct musb *musb, u8 epnum) - rx_csr &= ~MUSB_RXCSR_H_ERROR; - musb_writew(epio, MUSB_RXCSR, rx_csr); - -+ /* -+ * Unplugging a USB-Ethernet adapter while it is busy can make -+ * the controller keep re-asserting the three-strikes error for -+ * this endpoint before the disconnect is processed. That floods -+ * the log and can wedge the host port until reboot. Drop the -+ * stale pending RX interrupt on platforms that support it (e.g. -+ * AM335x/DSPS) to break the storm; the transfer is still -+ * aborted below via the fault path. -+ */ -+ musb_platform_clear_ep_rxintr(musb, epnum); -+ - } else if (rx_csr & MUSB_RXCSR_DATAERROR) { - - if (USB_ENDPOINT_XFER_ISOC != qh->type) { -diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c ---- a/drivers/usb/serial/digi_acceleport.c -+++ b/drivers/usb/serial/digi_acceleport.c -@@ -32,10 +32,6 @@ - /* so we can be sure to send the full buffer in one urb */ - #define DIGI_OUT_BUF_SIZE 8 - --/* port input buffer length -- must be >= transfer buffer length - 3 */ --/* so we can be sure to hold at least one full buffer from one urb */ --#define DIGI_IN_BUF_SIZE 64 -- - /* retry timeout while sleeping */ - #define DIGI_RETRY_TIMEOUT (HZ/10) - -@@ -176,10 +172,10 @@ - /* Structures */ - - struct digi_serial { -- spinlock_t ds_serial_lock; -+ struct mutex open_mutex; - struct usb_serial_port *ds_oob_port; /* out-of-band port */ - int ds_oob_port_num; /* index of out-of-band port */ -- int ds_device_started; -+ int open_count; - }; - - struct digi_port { -@@ -194,7 +190,6 @@ struct digi_port { - int dp_throttled; - int dp_throttle_restart; - wait_queue_head_t dp_flush_wait; -- wait_queue_head_t dp_close_wait; /* wait queue for close */ - wait_queue_head_t write_wait; - struct usb_serial_port *dp_port; - }; -@@ -227,9 +222,7 @@ static unsigned int digi_chars_in_buffer(struct tty_struct *tty); - static int digi_open(struct tty_struct *tty, struct usb_serial_port *port); - static void digi_close(struct usb_serial_port *port); - static void digi_dtr_rts(struct usb_serial_port *port, int on); --static int digi_startup_device(struct usb_serial *serial); - static int digi_startup(struct usb_serial *serial); --static void digi_disconnect(struct usb_serial *serial); - static void digi_release(struct usb_serial *serial); - static int digi_port_probe(struct usb_serial_port *port); - static void digi_port_remove(struct usb_serial_port *port); -@@ -272,7 +265,7 @@ static struct usb_serial_driver digi_acceleport_2_device = { - .dtr_rts = digi_dtr_rts, - .write = digi_write, - .write_room = digi_write_room, -- .write_bulk_callback = digi_write_bulk_callback, -+ .write_bulk_callback = digi_write_bulk_callback, - .read_bulk_callback = digi_read_bulk_callback, - .chars_in_buffer = digi_chars_in_buffer, - .throttle = digi_rx_throttle, -@@ -282,7 +275,6 @@ static struct usb_serial_driver digi_acceleport_2_device = { - .tiocmget = digi_tiocmget, - .tiocmset = digi_tiocmset, - .attach = digi_startup, -- .disconnect = digi_disconnect, - .release = digi_release, - .port_probe = digi_port_probe, - .port_remove = digi_port_remove, -@@ -301,7 +293,7 @@ static struct usb_serial_driver digi_acceleport_4_device = { - .close = digi_close, - .write = digi_write, - .write_room = digi_write_room, -- .write_bulk_callback = digi_write_bulk_callback, -+ .write_bulk_callback = digi_write_bulk_callback, - .read_bulk_callback = digi_read_bulk_callback, - .chars_in_buffer = digi_chars_in_buffer, - .throttle = digi_rx_throttle, -@@ -311,7 +303,6 @@ static struct usb_serial_driver digi_acceleport_4_device = { - .tiocmget = digi_tiocmget, - .tiocmset = digi_tiocmset, - .attach = digi_startup, -- .disconnect = digi_disconnect, - .release = digi_release, - .port_probe = digi_port_probe, - .port_remove = digi_port_remove, -@@ -335,7 +326,6 @@ static struct usb_serial_driver * const serial_drivers[] = { - * interruptible_sleep_on_timeout is deprecated and has been replaced - * with the equivalent code. - */ -- - static long cond_wait_interruptible_timeout_irqrestore( - wait_queue_head_t *q, long timeout, - spinlock_t *lock, unsigned long flags) -@@ -351,6 +341,13 @@ __releases(lock) - return timeout; - } - -+static struct usb_serial_port *digi_get_oob_port(struct usb_serial *serial) -+{ -+ struct digi_serial *serial_priv = usb_get_serial_data(serial); -+ -+ return serial_priv->ds_oob_port; -+} -+ - /* - * Digi Write OOB Command - * -@@ -361,15 +358,14 @@ __releases(lock) - * the interruptible flag is true, or a negative error - * returned by usb_submit_urb. - */ -- - static int digi_write_oob_command(struct usb_serial_port *port, - unsigned char *buf, int count, int interruptible) - { -- int ret = 0; -- int len; -- struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; -+ struct usb_serial_port *oob_port = digi_get_oob_port(port->serial); - struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); - unsigned long flags; -+ int ret = 0; -+ int len; - - dev_dbg(&port->dev, - "digi_write_oob_command: TOP: port=%d, count=%d\n", -@@ -406,10 +402,8 @@ static int digi_write_oob_command(struct usb_serial_port *port, - dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n", - __func__, ret); - return ret; -- - } - -- - /* - * Digi Write In Band Command - * -@@ -421,16 +415,15 @@ static int digi_write_oob_command(struct usb_serial_port *port, - * timeout ticks. Returns 0 if successful, or a negative - * error returned by digi_write. - */ -- - static int digi_write_inb_command(struct usb_serial_port *port, - unsigned char *buf, int count, unsigned long timeout) - { -- int ret = 0; -- int len; - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned char *data = port->write_urb->transfer_buffer; - unsigned long expire; - unsigned long flags; -+ int ret = 0; -+ int len; - - dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n", - priv->dp_port_num, count); -@@ -459,7 +452,7 @@ static int digi_write_inb_command(struct usb_serial_port *port, - /* len must be a multiple of 4 and small enough to */ - /* guarantee the write will send buffered data first, */ - /* so commands are in order with data and not split */ -- len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len); -+ len = min(count, port->bulk_out_size - 2 - priv->dp_out_buf_len); - if (len > 4) - len &= ~3; - -@@ -467,11 +460,10 @@ static int digi_write_inb_command(struct usb_serial_port *port, - if (priv->dp_out_buf_len > 0) { - data[0] = DIGI_CMD_SEND_DATA; - data[1] = priv->dp_out_buf_len; -- memcpy(data + 2, priv->dp_out_buf, -- priv->dp_out_buf_len); -+ memcpy(data + 2, priv->dp_out_buf, priv->dp_out_buf_len); - memcpy(data + 2 + priv->dp_out_buf_len, buf, len); -- port->write_urb->transfer_buffer_length -- = priv->dp_out_buf_len + 2 + len; -+ port->write_urb->transfer_buffer_length = -+ priv->dp_out_buf_len + 2 + len; - } else { - memcpy(data, buf, len); - port->write_urb->transfer_buffer_length = len; -@@ -484,7 +476,6 @@ static int digi_write_inb_command(struct usb_serial_port *port, - count -= len; - buf += len; - } -- - } - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - -@@ -495,7 +486,6 @@ static int digi_write_inb_command(struct usb_serial_port *port, - return ret; - } - -- - /* - * Digi Set Modem Signals - * -@@ -505,17 +495,15 @@ static int digi_write_inb_command(struct usb_serial_port *port, - * -EINTR if interrupted while sleeping, or a non-zero error - * returned by usb_submit_urb. - */ -- - static int digi_set_modem_signals(struct usb_serial_port *port, - unsigned int modem_signals, int interruptible) - { -- -- int ret; - struct digi_port *port_priv = usb_get_serial_port_data(port); -- struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; -+ struct usb_serial_port *oob_port = digi_get_oob_port(port->serial); - struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); - unsigned char *data = oob_port->write_urb->transfer_buffer; - unsigned long flags; -+ int ret; - - dev_dbg(&port->dev, - "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n", -@@ -573,14 +561,13 @@ static int digi_set_modem_signals(struct usb_serial_port *port, - * is only called from close, and only one process can be in close on a - * port at a time, so its ok. - */ -- - static int digi_transmit_idle(struct usb_serial_port *port, - unsigned long timeout) - { -- int ret; -- unsigned char buf[2]; - struct digi_port *priv = usb_get_serial_port_data(port); -+ unsigned char buf[2]; - unsigned long flags; -+ int ret; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - priv->dp_transmit_idle = 0; -@@ -607,16 +594,15 @@ static int digi_transmit_idle(struct usb_serial_port *port, - } - priv->dp_transmit_idle = 0; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); -+ - return 0; -- - } - -- - static void digi_rx_throttle(struct tty_struct *tty) - { -- unsigned long flags; - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); -+ unsigned long flags; - - /* stop receiving characters by not resubmitting the read urb */ - spin_lock_irqsave(&priv->dp_port_lock, flags); -@@ -625,13 +611,12 @@ static void digi_rx_throttle(struct tty_struct *tty) - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - } - -- - static void digi_rx_unthrottle(struct tty_struct *tty) - { -- int ret = 0; -- unsigned long flags; - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); -+ unsigned long flags; -+ int ret = 0; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - -@@ -651,7 +636,6 @@ static void digi_rx_unthrottle(struct tty_struct *tty) - __func__, ret, priv->dp_port_num); - } - -- - static void digi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - const struct ktermios *old_termios) -@@ -762,7 +746,6 @@ static void digi_set_termios(struct tty_struct *tty, - - /* set stop bits */ - if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { -- - if ((cflag & CSTOPB)) - arg = DIGI_STOP_BITS_2; - else -@@ -772,7 +755,6 @@ static void digi_set_termios(struct tty_struct *tty, - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; -- - } - - /* set input flow control */ -@@ -841,7 +823,6 @@ static void digi_set_termios(struct tty_struct *tty, - tty_encode_baud_rate(tty, baud, baud); - } - -- - static int digi_break_ctl(struct tty_struct *tty, int break_state) - { - struct usb_serial_port *port = tty->driver_data; -@@ -855,50 +836,48 @@ static int digi_break_ctl(struct tty_struct *tty, int break_state) - return digi_write_inb_command(port, buf, 4, 0); - } - -- - static int digi_tiocmget(struct tty_struct *tty) - { - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); -- unsigned int val; - unsigned long flags; -+ unsigned int val; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - val = priv->dp_modem_signals; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); -+ - return val; - } - -- - static int digi_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) - { - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); -- unsigned int val; - unsigned long flags; -+ unsigned int val; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - val = (priv->dp_modem_signals & ~clear) | set; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); -+ - return digi_set_modem_signals(port, val, 1); - } - -- - static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) - { -- -- int ret, data_len, new_len; - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned char *data = port->write_urb->transfer_buffer; -+ int ret, data_len, new_len; - unsigned long flags; - - dev_dbg(&port->dev, "digi_write: TOP: port=%d, count=%d\n", - priv->dp_port_num, count); - - /* copy user data (which can sleep) before getting spin lock */ -- count = min(count, port->bulk_out_size-2); -+ count = min(count, port->bulk_out_size - 2); - count = min(64, count); - - /* be sure only one write proceeds at a time */ -@@ -920,7 +899,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, - - /* allow space for any buffered data and for new data, up to */ - /* transfer buffer size - 2 (for command and length bytes) */ -- new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len); -+ new_len = min(count, port->bulk_out_size - 2 - priv->dp_out_buf_len); - data_len = new_len + priv->dp_out_buf_len; - - if (data_len == 0) { -@@ -928,7 +907,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, - return 0; - } - -- port->write_urb->transfer_buffer_length = data_len+2; -+ port->write_urb->transfer_buffer_length = data_len + 2; - - *data++ = DIGI_CMD_SEND_DATA; - *data++ = data_len; -@@ -954,39 +933,22 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, - "%s: usb_submit_urb failed, ret=%d, port=%d\n", - __func__, ret, priv->dp_port_num); - dev_dbg(&port->dev, "digi_write: returning %d\n", ret); -- return ret; - -+ return ret; - } - - static void digi_write_bulk_callback(struct urb *urb) - { -- - struct usb_serial_port *port = urb->context; -- struct usb_serial *serial; -- struct digi_port *priv; -- struct digi_serial *serial_priv; -+ struct digi_serial *serial_priv = usb_get_serial_data(port->serial); -+ struct digi_port *priv = usb_get_serial_port_data(port); -+ unsigned char *data = urb->transfer_buffer; - unsigned long flags; -- int ret = 0; -- int status = urb->status; - bool wakeup; -- -- /* port and serial sanity check */ -- if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { -- pr_err("%s: port or port->private is NULL, status=%d\n", -- __func__, status); -- return; -- } -- serial = port->serial; -- if (serial == NULL || (serial_priv = usb_get_serial_data(serial)) == NULL) { -- dev_err(&port->dev, -- "%s: serial or serial->private is NULL, status=%d\n", -- __func__, status); -- return; -- } -+ int ret = 0; - - /* handle oob callback */ - if (priv->dp_port_num == serial_priv->ds_oob_port_num) { -- dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n"); - spin_lock_irqsave(&priv->dp_port_lock, flags); - priv->dp_write_urb_in_use = 0; - wake_up_interruptible(&priv->write_wait); -@@ -999,15 +961,13 @@ static void digi_write_bulk_callback(struct urb *urb) - spin_lock_irqsave(&priv->dp_port_lock, flags); - priv->dp_write_urb_in_use = 0; - if (priv->dp_out_buf_len > 0) { -- *((unsigned char *)(port->write_urb->transfer_buffer)) -- = (unsigned char)DIGI_CMD_SEND_DATA; -- *((unsigned char *)(port->write_urb->transfer_buffer) + 1) -- = (unsigned char)priv->dp_out_buf_len; -- port->write_urb->transfer_buffer_length = -- priv->dp_out_buf_len + 2; -- memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf, -- priv->dp_out_buf_len); -- ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); -+ data[0] = DIGI_CMD_SEND_DATA; -+ data[1] = priv->dp_out_buf_len; -+ memcpy(data + 2, priv->dp_out_buf, priv->dp_out_buf_len); -+ -+ urb->transfer_buffer_length = priv->dp_out_buf_len + 2; -+ -+ ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret == 0) { - priv->dp_write_urb_in_use = 1; - priv->dp_out_buf_len = 0; -@@ -1041,8 +1001,8 @@ static unsigned int digi_write_room(struct tty_struct *tty) - - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - dev_dbg(&port->dev, "digi_write_room: port=%d, room=%u\n", priv->dp_port_num, room); -- return room; - -+ return room; - } - - static unsigned int digi_chars_in_buffer(struct tty_struct *tty) -@@ -1070,17 +1030,53 @@ static void digi_dtr_rts(struct usb_serial_port *port, int on) - digi_set_modem_signals(port, on * (TIOCM_DTR | TIOCM_RTS), 1); - } - -+static int digi_open_oob_port(struct usb_serial *serial) -+{ -+ struct digi_serial *serial_priv = usb_get_serial_data(serial); -+ struct usb_serial_port *oob_port = serial_priv->ds_oob_port; -+ int ret = 0; -+ -+ mutex_lock(&serial_priv->open_mutex); -+ -+ if (serial_priv->open_count++ == 0) { -+ ret = usb_submit_urb(oob_port->read_urb, GFP_KERNEL); -+ if (ret) { -+ dev_err(&serial->interface->dev, "failed to submit OOB read urb: %d\n", -+ ret); -+ serial_priv->open_count--; -+ } -+ } -+ -+ mutex_unlock(&serial_priv->open_mutex); -+ -+ return ret; -+} -+ -+static void digi_close_oob_port(struct usb_serial *serial) -+{ -+ struct digi_serial *serial_priv = usb_get_serial_data(serial); -+ struct usb_serial_port *oob_port = serial_priv->ds_oob_port; -+ -+ mutex_lock(&serial_priv->open_mutex); -+ -+ if (serial_priv->open_count-- == 1) { -+ usb_kill_urb(oob_port->read_urb); -+ usb_kill_urb(oob_port->write_urb); -+ } -+ -+ mutex_unlock(&serial_priv->open_mutex); -+} -+ - static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) - { -- int ret; -- unsigned char buf[32]; - struct digi_port *priv = usb_get_serial_port_data(port); - struct ktermios not_termios; -- int throttled; -+ unsigned char buf[32]; -+ int ret; - -- /* be sure the device is started up */ -- if (digi_startup_device(port->serial) != 0) -- return -ENXIO; -+ ret = digi_open_oob_port(port->serial); -+ if (ret) -+ return ret; - - /* read modem signals automatically whenever they change */ - buf[0] = DIGI_CMD_READ_INPUT_SIGNALS; -@@ -1106,32 +1102,34 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) - } - - spin_lock_irq(&priv->dp_port_lock); -- throttled = priv->dp_throttle_restart; - priv->dp_throttled = 0; - priv->dp_throttle_restart = 0; - spin_unlock_irq(&priv->dp_port_lock); - -- if (throttled) { -- ret = usb_submit_urb(port->read_urb, GFP_KERNEL); -- if (ret) { -- dev_err(&port->dev, "failed to submit read urb: %d\n", ret); -- return ret; -- } -+ ret = usb_submit_urb(port->read_urb, GFP_KERNEL); -+ if (ret) { -+ dev_err(&port->dev, "failed to submit read urb: %d\n", ret); -+ goto err_close_oob; - } - - return 0; --} - -+err_close_oob: -+ digi_close_oob_port(port->serial); -+ -+ return ret; -+} - - static void digi_close(struct usb_serial_port *port) - { -+ struct digi_port *priv = usb_get_serial_port_data(port); -+ unsigned char buf[32]; - DEFINE_WAIT(wait); - int ret; -- unsigned char buf[32]; -- struct digi_port *priv = usb_get_serial_port_data(port); -+ -+ usb_kill_urb(port->read_urb); - - mutex_lock(&port->serial->disc_mutex); -- /* if disconnected, just clear flags */ - if (port->serial->disconnected) - goto exit; - -@@ -1177,57 +1175,18 @@ static void digi_close(struct usb_serial_port *port) - TASK_INTERRUPTIBLE); - schedule_timeout(DIGI_CLOSE_TIMEOUT); - finish_wait(&priv->dp_flush_wait, &wait); -+exit: -+ mutex_unlock(&port->serial->disc_mutex); - - /* shutdown any outstanding bulk writes */ - usb_kill_urb(port->write_urb); --exit: -- spin_lock_irq(&priv->dp_port_lock); -- priv->dp_write_urb_in_use = 0; -- wake_up_interruptible(&priv->dp_close_wait); -- spin_unlock_irq(&priv->dp_port_lock); -- mutex_unlock(&port->serial->disc_mutex); --} - -- --/* -- * Digi Startup Device -- * -- * Starts reads on all ports. Must be called AFTER startup, with -- * urbs initialized. Returns 0 if successful, non-zero error otherwise. -- */ -- --static int digi_startup_device(struct usb_serial *serial) --{ -- int i, ret = 0; -- struct digi_serial *serial_priv = usb_get_serial_data(serial); -- struct usb_serial_port *port; -- -- /* be sure this happens exactly once */ -- spin_lock(&serial_priv->ds_serial_lock); -- if (serial_priv->ds_device_started) { -- spin_unlock(&serial_priv->ds_serial_lock); -- return 0; -- } -- serial_priv->ds_device_started = 1; -- spin_unlock(&serial_priv->ds_serial_lock); -- -- /* start reading from each bulk in endpoint for the device */ -- /* set USB_DISABLE_SPD flag for write bulk urbs */ -- for (i = 0; i < serial->type->num_ports + 1; i++) { -- port = serial->port[i]; -- ret = usb_submit_urb(port->read_urb, GFP_KERNEL); -- if (ret != 0) { -- dev_err(&port->dev, -- "%s: usb_submit_urb failed, ret=%d, port=%d\n", -- __func__, ret, i); -- break; -- } -- } -- return ret; -+ digi_close_oob_port(port->serial); - } - - static int digi_port_init(struct usb_serial_port *port, unsigned port_num) - { -+ struct digi_serial *serial_priv = usb_get_serial_data(port->serial); - struct digi_port *priv; - - priv = kzalloc_obj(*priv); -@@ -1235,10 +1194,13 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num) - return -ENOMEM; - - spin_lock_init(&priv->dp_port_lock); -+ -+ if (port == serial_priv->ds_oob_port) -+ lockdep_set_subclass(&priv->dp_port_lock, SINGLE_DEPTH_NESTING); -+ - priv->dp_port_num = port_num; - init_waitqueue_head(&priv->dp_transmit_idle_wait); - init_waitqueue_head(&priv->dp_flush_wait); -- init_waitqueue_head(&priv->dp_close_wait); - init_waitqueue_head(&priv->write_wait); - priv->dp_port = port; - -@@ -1275,10 +1237,13 @@ static int digi_startup(struct usb_serial *serial) - if (!serial_priv) - return -ENOMEM; - -- spin_lock_init(&serial_priv->ds_serial_lock); -+ mutex_init(&serial_priv->open_mutex); -+ - serial_priv->ds_oob_port_num = oob_port_num; - serial_priv->ds_oob_port = serial->port[oob_port_num]; - -+ usb_set_serial_data(serial, serial_priv); -+ - ret = digi_port_init(serial_priv->ds_oob_port, - serial_priv->ds_oob_port_num); - if (ret) { -@@ -1286,24 +1251,9 @@ static int digi_startup(struct usb_serial *serial) - return ret; - } - -- usb_set_serial_data(serial, serial_priv); -- - return 0; - } - -- --static void digi_disconnect(struct usb_serial *serial) --{ -- int i; -- -- /* stop reads and writes on all ports */ -- for (i = 0; i < serial->type->num_ports + 1; i++) { -- usb_kill_urb(serial->port[i]->read_urb); -- usb_kill_urb(serial->port[i]->write_urb); -- } --} -- -- - static void digi_release(struct usb_serial *serial) - { - struct digi_serial *serial_priv; -@@ -1333,30 +1283,25 @@ static void digi_port_remove(struct usb_serial_port *port) - static void digi_read_bulk_callback(struct urb *urb) - { - struct usb_serial_port *port = urb->context; -- struct digi_port *priv; -- struct digi_serial *serial_priv; -- int ret; -+ struct usb_serial *serial = port->serial; -+ struct digi_serial *serial_priv = usb_get_serial_data(serial); -+ struct digi_port *priv = usb_get_serial_port_data(port); - int status = urb->status; -- -- /* port sanity check, do not resubmit if port is not valid */ -- if (port == NULL) -- return; -- priv = usb_get_serial_port_data(port); -- if (priv == NULL) { -- dev_err(&port->dev, "%s: port->private is NULL, status=%d\n", -- __func__, status); -- return; -- } -- if (port->serial == NULL || -- (serial_priv = usb_get_serial_data(port->serial)) == NULL) { -- dev_err(&port->dev, "%s: serial is bad or serial->private " -- "is NULL, status=%d\n", __func__, status); -- return; -- } -+ int ret; - - /* do not resubmit urb if it has any status error */ -- if (status) { -- dev_err(&port->dev, -+ switch (status) { -+ case 0: -+ break; -+ case -ENOENT: -+ case -ECONNRESET: -+ case -ESHUTDOWN: -+ dev_err(&serial->interface->dev, -+ "%s: nonzero read bulk status: status=%d, port=%d\n", -+ __func__, status, priv->dp_port_num); -+ return; -+ default: -+ dev_err(&serial->interface->dev, - "%s: nonzero read bulk status: status=%d, port=%d\n", - __func__, status, priv->dp_port_num); - return; -@@ -1374,11 +1319,10 @@ static void digi_read_bulk_callback(struct urb *urb) - /* continue read */ - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret != 0 && ret != -EPERM) { -- dev_err(&port->dev, -+ dev_err(&serial->interface->dev, - "%s: failed resubmitting urb, ret=%d, port=%d\n", - __func__, ret, priv->dp_port_num); - } -- - } - - /* -@@ -1390,7 +1334,6 @@ static void digi_read_bulk_callback(struct urb *urb) - * It returns 0 if successful, 1 if successful but the port is - * throttled, and -1 if the sanity checks failed. - */ -- - static int digi_read_inb_callback(struct urb *urb) - { - struct usb_serial_port *port = urb->context; -@@ -1468,10 +1411,8 @@ static int digi_read_inb_callback(struct urb *urb) - dev_dbg(&port->dev, "%s: unknown opcode: %d\n", __func__, opcode); - - return throttled ? 1 : 0; -- - } - -- - /* - * Digi Read OOB Callback - * -@@ -1480,10 +1421,8 @@ static int digi_read_inb_callback(struct urb *urb) - * the port->serial is valid. It returns 0 if successful, and - * -1 if the sanity checks failed. - */ -- - static int digi_read_oob_callback(struct urb *urb) - { -- - struct usb_serial_port *port = urb->context; - struct usb_serial *serial = port->serial; - struct tty_struct *tty; -@@ -1491,8 +1430,8 @@ static int digi_read_oob_callback(struct urb *urb) - unsigned char *buf = urb->transfer_buffer; - int opcode, line, status, val; - unsigned long flags; -- int i; - unsigned int rts; -+ int i; - - if (urb->actual_length < 4) - return -1; -@@ -1504,7 +1443,8 @@ static int digi_read_oob_callback(struct urb *urb) - status = buf[i + 2]; - val = buf[i + 3]; - -- dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", -+ dev_dbg(&serial->interface->dev, -+ "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", - opcode, line, status, val); - - if (status != 0 || line >= serial->type->num_ports) -@@ -1562,8 +1502,8 @@ static int digi_read_oob_callback(struct urb *urb) - } - tty_kref_put(tty); - } -- return 0; - -+ return 0; - } - - module_usb_serial_driver(serial_drivers, id_table_combined); -diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c ---- a/drivers/usb/serial/keyspan_pda.c -+++ b/drivers/usb/serial/keyspan_pda.c -@@ -31,7 +31,6 @@ - struct keyspan_pda_private { - int tx_room; - struct work_struct unthrottle_work; -- struct usb_serial *serial; - struct usb_serial_port *port; - bool throttled; - bool throttle_req; -diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c ---- a/drivers/usb/serial/metro-usb.c -+++ b/drivers/usb/serial/metro-usb.c -@@ -36,6 +36,7 @@ - struct metrousb_private { - spinlock_t lock; - int throttled; -+ int throttle_req; - unsigned long control_state; - }; - -@@ -108,7 +109,7 @@ static void metrousb_read_int_callback(struct urb *urb) - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - int throttled = 0; -- int result = 0; -+ int result; - - dev_dbg(&port->dev, "%s\n", __func__); - -@@ -143,7 +144,10 @@ static void metrousb_read_int_callback(struct urb *urb) - - /* Set any port variables. */ - spin_lock_irqsave(&metro_priv->lock, flags); -- throttled = metro_priv->throttled; -+ if (metro_priv->throttle_req) { -+ metro_priv->throttled = 1; -+ throttled = 1; -+ } - spin_unlock_irqrestore(&metro_priv->lock, flags); - - if (throttled) -@@ -169,12 +173,13 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) - struct usb_serial *serial = port->serial; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - unsigned long flags; -- int result = 0; -+ int result; - - /* Set the private data information for the port. */ - spin_lock_irqsave(&metro_priv->lock, flags); - metro_priv->control_state = 0; - metro_priv->throttled = 0; -+ metro_priv->throttle_req = 0; - spin_unlock_irqrestore(&metro_priv->lock, flags); - - /* Clear the urb pipe. */ -@@ -269,7 +274,7 @@ static void metrousb_throttle(struct tty_struct *tty) - - /* Set the private information for the port to stop reading data. */ - spin_lock_irqsave(&metro_priv->lock, flags); -- metro_priv->throttled = 1; -+ metro_priv->throttle_req = 1; - spin_unlock_irqrestore(&metro_priv->lock, flags); - } - -@@ -321,19 +326,23 @@ static void metrousb_unthrottle(struct tty_struct *tty) - struct usb_serial_port *port = tty->driver_data; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - unsigned long flags; -- int result = 0; -+ int throttled; -+ int result; - - /* Set the private information for the port to resume reading data. */ - spin_lock_irqsave(&metro_priv->lock, flags); -+ throttled = metro_priv->throttled; - metro_priv->throttled = 0; -+ metro_priv->throttle_req = 0; - spin_unlock_irqrestore(&metro_priv->lock, flags); - -- /* Submit the urb to read from the port. */ -- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); -- if (result) -- dev_err(&port->dev, -- "failed submitting interrupt in urb error code=%d\n", -- result); -+ if (throttled) { -+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); -+ if (result) { -+ dev_err(&port->dev, "failed to submit interrupt in urb: %d\n", -+ result); -+ } -+ } - } - - static struct usb_serial_driver metrousb_device = { -diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c ---- a/drivers/usb/serial/pl2303.c -+++ b/drivers/usb/serial/pl2303.c -@@ -51,6 +51,7 @@ static const struct usb_device_id id_table[] = { - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GL) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GE) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GS) }, -+ { USB_DEVICE(PL2303_VENDOR_ID, PL256X_PRODUCT_ID_4P) }, - { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, - { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, - { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), -@@ -141,10 +142,15 @@ MODULE_DEVICE_TABLE(usb, id_table); - #define VENDOR_WRITE_REQUEST_TYPE 0x40 - #define VENDOR_WRITE_REQUEST 0x01 - #define VENDOR_WRITE_NREQUEST 0x80 -+#define VENDOR_WRITE_MPREQUEST 0x80 - - #define VENDOR_READ_REQUEST_TYPE 0xc0 - #define VENDOR_READ_REQUEST 0x01 - #define VENDOR_READ_NREQUEST 0x81 -+#define VENDOR_READ_MPREQUEST 0x80 -+ -+#define PL256X_RESET_REQUEST_TYPE 0x40 -+#define PL256X_RESET_REQUEST 0x96 - - #define UART_STATE_INDEX 8 - #define UART_STATE_MSR_MASK 0x8b -@@ -172,6 +178,16 @@ MODULE_DEVICE_TABLE(usb, id_table); - #define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 - #define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c - -+#define PL256X_PORT_A_FLOWCTRL_REG 0xc005 -+#define PL256X_PORT_B_FLOWCTRL_REG 0xd005 -+#define PL256X_PORT_C_FLOWCTRL_REG 0xe005 -+#define PL256X_PORT_D_FLOWCTRL_REG 0xf005 -+ -+#define PL256X_FLOWCTRL_MASK 0x43 -+#define PL256X_FLOWCTRL_XON_XOFF 0x40 -+#define PL256X_FLOWCTRL_RTS_CTS 0x03 -+#define PL256X_FLOWCTRL_NONE 0x00 -+ - static int pl2303_set_break(struct usb_serial_port *port, bool enable); - - enum pl2303_type { -@@ -181,6 +197,7 @@ enum pl2303_type { - TYPE_TB, - TYPE_HXD, - TYPE_HXN, -+ TYPE_MP, - TYPE_COUNT - }; - -@@ -196,6 +213,8 @@ struct pl2303_type_data { - struct pl2303_serial_private { - const struct pl2303_type_data *type; - unsigned long quirks; -+ u16 interface_num; -+ u16 flowctrl_reg; - }; - - struct pl2303_private { -@@ -236,8 +255,30 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { - .max_baud_rate = 12000000, - .no_divisors = true, - }, -+ [TYPE_MP] = { -+ .name = "MP", -+ .max_baud_rate = 24000000, -+ .no_divisors = true, -+ }, - }; - -+static int pl256x_uart_reset(struct usb_serial *serial) -+{ -+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial); -+ struct device *dev = &serial->interface->dev; -+ int res; -+ -+ res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), -+ PL256X_RESET_REQUEST, PL256X_RESET_REQUEST_TYPE, -+ 0, spriv->interface_num, NULL, 0, 100); -+ if (res) { -+ dev_err(dev, "failed to reset device: %d\n", res); -+ return res; -+ } -+ -+ return 0; -+} -+ - static int pl2303_vendor_read(struct usb_serial *serial, u16 value, - unsigned char buf[1]) - { -@@ -248,6 +289,8 @@ static int pl2303_vendor_read(struct usb_serial *serial, u16 value, - - if (spriv->type == &pl2303_type_data[TYPE_HXN]) - request = VENDOR_READ_NREQUEST; -+ else if (spriv->type == &pl2303_type_data[TYPE_MP]) -+ request = VENDOR_READ_MPREQUEST; - else - request = VENDOR_READ_REQUEST; - -@@ -279,6 +322,8 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) - - if (spriv->type == &pl2303_type_data[TYPE_HXN]) - request = VENDOR_WRITE_NREQUEST; -+ else if (spriv->type == &pl2303_type_data[TYPE_MP]) -+ request = VENDOR_WRITE_MPREQUEST; - else - request = VENDOR_WRITE_REQUEST; - -@@ -304,10 +349,12 @@ static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val) - if (!buf) - return -ENOMEM; - -- if (spriv->type == &pl2303_type_data[TYPE_HXN]) -+ if (spriv->type == &pl2303_type_data[TYPE_HXN] || -+ spriv->type == &pl2303_type_data[TYPE_MP]) { - ret = pl2303_vendor_read(serial, reg, buf); -- else -+ } else { - ret = pl2303_vendor_read(serial, reg | 0x80, buf); -+ } - - if (ret) - goto out_free; -@@ -458,6 +505,14 @@ static int pl2303_detect_type(struct usb_serial *serial) - case 0x905: /* GT-2AB */ - case 0x1005: /* GC-Q20 */ - return TYPE_HXN; -+ case 0x3302: /* PL2533 VC 2 Port */ -+ case 0x3304: /* PL2533 VC 4 Port */ -+ case 0x4302: /* PL2543 VC 2 Port */ -+ case 0x4304: /* PL2543 VC 4 Port */ -+ case 0x6502: /* PL2565 VC 2 Port */ -+ case 0x6504: /* PL2565 VC 4 Port */ -+ case 0x6506: /* PL2565 VC 4 Port QFN64 package */ -+ return TYPE_MP; - } - break; - } -@@ -491,6 +546,7 @@ static int pl2303_startup(struct usb_serial *serial) - struct pl2303_serial_private *spriv; - enum pl2303_type type; - unsigned char *buf; -+ unsigned int ifnum; - int ret; - - ret = pl2303_detect_type(serial); -@@ -500,20 +556,43 @@ static int pl2303_startup(struct usb_serial *serial) - type = ret; - dev_dbg(&serial->interface->dev, "device type: %s\n", pl2303_type_data[type].name); - -+ ifnum = serial->interface->altsetting->desc.bInterfaceNumber; -+ - spriv = kzalloc_obj(*spriv); - if (!spriv) - return -ENOMEM; - -+ if (type == TYPE_MP) { -+ switch (ifnum) { -+ case 0: -+ spriv->flowctrl_reg = PL256X_PORT_A_FLOWCTRL_REG; -+ break; -+ case 1: -+ spriv->flowctrl_reg = PL256X_PORT_B_FLOWCTRL_REG; -+ break; -+ case 2: -+ spriv->flowctrl_reg = PL256X_PORT_C_FLOWCTRL_REG; -+ break; -+ case 3: -+ spriv->flowctrl_reg = PL256X_PORT_D_FLOWCTRL_REG; -+ break; -+ default: -+ kfree(spriv); -+ return -ENODEV; -+ } -+ } -+ - spriv->type = &pl2303_type_data[type]; - spriv->quirks = (unsigned long)usb_get_serial_data(serial); - spriv->quirks |= spriv->type->quirks; -+ spriv->interface_num = ifnum; - - if (type == TYPE_HXD && pl2303_is_hxd_clone(serial)) - spriv->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE; - - usb_set_serial_data(serial, spriv); - -- if (type != TYPE_HXN) { -+ if (type != TYPE_HXN && type != TYPE_MP) { - buf = kmalloc(1, GFP_KERNEL); - if (!buf) { - kfree(spriv); -@@ -575,13 +654,15 @@ static void pl2303_port_remove(struct usb_serial_port *port) - static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) - { - struct usb_device *dev = port->serial->dev; -+ struct usb_serial *serial = port->serial; -+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial); - int retval; - - dev_dbg(&port->dev, "%s - %02x\n", __func__, value); - - retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, -- value, 0, NULL, 0, 100); -+ value, spriv->interface_num, NULL, 0, 100); - if (retval) - dev_err(&port->dev, "%s - failed: %d\n", __func__, retval); - -@@ -761,7 +842,7 @@ static int pl2303_get_line_request(struct usb_serial_port *port, - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, -- 0, 0, buf, 7, 100); -+ 0, spriv->interface_num, buf, 7, 100); - if (ret != 7) { - dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); - -@@ -780,11 +861,13 @@ static int pl2303_set_line_request(struct usb_serial_port *port, - unsigned char buf[7]) - { - struct usb_device *udev = port->serial->dev; -+ struct usb_serial *serial = port->serial; -+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial); - int ret; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, -- 0, 0, buf, 7, 100); -+ 0, spriv->interface_num, buf, 7, 100); - if (ret < 0) { - dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); - return ret; -@@ -939,6 +1022,9 @@ static void pl2303_set_termios(struct tty_struct *tty, - pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, - PL2303_HXN_FLOWCTRL_MASK, - PL2303_HXN_FLOWCTRL_RTS_CTS); -+ } else if (spriv->type == &pl2303_type_data[TYPE_MP]) { -+ pl2303_vendor_write(serial, spriv->flowctrl_reg, -+ PL256X_FLOWCTRL_RTS_CTS); - } else { - pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60); - } -@@ -947,6 +1033,9 @@ static void pl2303_set_termios(struct tty_struct *tty, - pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, - PL2303_HXN_FLOWCTRL_MASK, - PL2303_HXN_FLOWCTRL_XON_XOFF); -+ } else if (spriv->type == &pl2303_type_data[TYPE_MP]) { -+ pl2303_vendor_write(serial, spriv->flowctrl_reg, -+ PL256X_FLOWCTRL_XON_XOFF); - } else { - pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0); - } -@@ -955,6 +1044,9 @@ static void pl2303_set_termios(struct tty_struct *tty, - pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, - PL2303_HXN_FLOWCTRL_MASK, - PL2303_HXN_FLOWCTRL_NONE); -+ } else if (spriv->type == &pl2303_type_data[TYPE_MP]) { -+ pl2303_vendor_write(serial, spriv->flowctrl_reg, -+ PL256X_FLOWCTRL_NONE); - } else { - pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0); - } -@@ -1002,6 +1094,8 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) - pl2303_vendor_write(serial, PL2303_HXN_RESET_REG, - PL2303_HXN_RESET_UPSTREAM_PIPE | - PL2303_HXN_RESET_DOWNSTREAM_PIPE); -+ } else if (spriv->type == &pl2303_type_data[TYPE_MP]) { -+ pl256x_uart_reset(serial); - } else { - pl2303_vendor_write(serial, 8, 0); - pl2303_vendor_write(serial, 9, 0); -@@ -1112,7 +1206,7 @@ static int pl2303_set_break(struct usb_serial_port *port, bool enable) - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - BREAK_REQUEST, BREAK_REQUEST_TYPE, state, -- 0, NULL, 0, 100); -+ spriv->interface_num, NULL, 0, 100); - if (result) { - dev_err(&port->dev, "error sending break = %d\n", result); - return result; -diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h ---- a/drivers/usb/serial/pl2303.h -+++ b/drivers/usb/serial/pl2303.h -@@ -26,7 +26,7 @@ - #define PL2303_PRODUCT_ID_HCR331 0x331a - #define PL2303_PRODUCT_ID_MOTOROLA 0x0307 - #define PL2303_PRODUCT_ID_ZTEK 0xe1f1 -- -+#define PL256X_PRODUCT_ID_4P 0x2533 - - #define ATEN_VENDOR_ID 0x0557 - #define ATEN_VENDOR_ID2 0x0547 -diff --git a/drivers/usb/typec/altmodes/Kconfig b/drivers/usb/typec/altmodes/Kconfig ---- a/drivers/usb/typec/altmodes/Kconfig -+++ b/drivers/usb/typec/altmodes/Kconfig -@@ -5,6 +5,7 @@ menu "USB Type-C Alternate Mode drivers" - config TYPEC_DP_ALTMODE - tristate "DisplayPort Alternate Mode driver" - depends on DRM -+ select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF - help - DisplayPort USB Type-C Alternate Mode allows DisplayPort - displays and adapters to be attached to the USB Type-C -diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c ---- a/drivers/usb/typec/altmodes/displayport.c -+++ b/drivers/usb/typec/altmodes/displayport.c -@@ -764,6 +764,7 @@ int dp_altmode_probe(struct typec_altmode *alt) - struct typec_altmode *plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P); - struct fwnode_handle *fwnode; - struct dp_altmode *dp; -+ u32 cap = DP_CAP_CAPABILITY(alt->vdo); - - /* Port can only be DFP_U. */ - if (typec_altmode_get_data_role(alt) != TYPEC_HOST) -@@ -778,6 +779,18 @@ int dp_altmode_probe(struct typec_altmode *alt) - return -ENODEV; - } - -+ /* -+ * Make sure the DisplayPort VDO is valid (VESA DPAM v2.1a, Section -+ * 5.4.1, Table 5-6, DP Capabilities VDO). A device exposing DP on a -+ * USB-C receptacle must advertise at least one pin assignment for the -+ * capability it claims, otherwise Alt Mode can never be configured. -+ */ -+ if ((cap == DP_CAP_DFP_D && !DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo)) || -+ (cap == DP_CAP_UFP_D && !DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo))) { -+ typec_altmode_put_plug(plug); -+ return -ENODEV; -+ } -+ - dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); - if (!dp) { - typec_altmode_put_plug(plug); -@@ -790,7 +803,6 @@ int dp_altmode_probe(struct typec_altmode *alt) - dp->alt = alt; - - alt->desc = "DisplayPort"; -- typec_altmode_set_ops(alt, &dp_altmode_ops); - - if (plug) { - plug->desc = "Displayport"; -@@ -811,6 +823,10 @@ int dp_altmode_probe(struct typec_altmode *alt) - if (plug) - typec_altmode_set_drvdata(plug, dp); - -+ if ((alt->vdo & DP_CAP_RECEPTACLE) && typec_cable_altmode_unsupported(alt)) -+ return 0; -+ -+ typec_altmode_set_ops(alt, &dp_altmode_ops); - if (!alt->mode_selection) { - dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER; - schedule_work(&dp->work); -diff --git a/drivers/usb/typec/altmodes/thunderbolt.c b/drivers/usb/typec/altmodes/thunderbolt.c ---- a/drivers/usb/typec/altmodes/thunderbolt.c -+++ b/drivers/usb/typec/altmodes/thunderbolt.c -@@ -284,6 +284,10 @@ static int tbt_altmode_probe(struct typec_altmode *alt) - - alt->desc = "Thunderbolt3"; - typec_altmode_set_drvdata(alt, tbt); -+ -+ if (typec_cable_altmode_unsupported(alt)) -+ return 0; -+ - typec_altmode_set_ops(alt, &tbt_altmode_ops); - - if (!alt->mode_selection && tbt_ready(alt)) { -diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c ---- a/drivers/usb/typec/class.c -+++ b/drivers/usb/typec/class.c -@@ -1429,6 +1429,77 @@ int typec_cable_is_active(struct typec_cable *cable) - } - EXPORT_SYMBOL_GPL(typec_cable_is_active); - -+enum typec_cable_altmode_support { -+ CABLE_SUPPORT_UNKNOWN, -+ CABLE_SUPPORTED, -+ CABLE_NOT_SUPPORTED, -+}; -+ -+static enum typec_cable_altmode_support -+typec_cable_check_altmode_support(struct typec_cable *cable, -+ struct typec_altmode *alt) -+{ -+ struct typec_altmode *plug; -+ u32 speed; -+ -+ /* -+ * Check if the cable has an e-marker, supports modal operation, and the -+ * SOP' altmode nodes are created. -+ */ -+ plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P); -+ if (plug) { -+ typec_altmode_put_plug(plug); -+ return CABLE_SUPPORTED; -+ } -+ -+ /* The identity is not specified */ -+ if (!cable->identity) -+ return CABLE_SUPPORT_UNKNOWN; -+ -+ /* Non-e-marked cable */ -+ if (!cable->identity->id_header) -+ return CABLE_NOT_SUPPORTED; -+ -+ switch (PD_IDH_PTYPE(cable->identity->id_header)) { -+ case IDH_PTYPE_PCABLE: -+ speed = VDO_TYPEC_CABLE_SPEED(cable->identity->vdo[0]); -+ if (speed == CABLE_USB2_ONLY) -+ return CABLE_NOT_SUPPORTED; -+ return CABLE_SUPPORTED; -+ case IDH_PTYPE_ACABLE: -+ /* -+ * Active cables must establish an SOP' communication -+ * node. Since that check failed at the beginning of -+ * this function, this active cable does not support -+ * this specific altmode. -+ */ -+ return CABLE_NOT_SUPPORTED; -+ } -+ -+ return CABLE_SUPPORT_UNKNOWN; -+} -+ -+/** -+ * typec_cable_altmode_unsupported - Check if a cable restricts altmode -+ * @alt: The Alternate Mode to evaluate -+ * -+ * Returns true if the connected cable is incapable of handling the altmode. -+ */ -+bool typec_cable_altmode_unsupported(struct typec_altmode *alt) -+{ -+ enum typec_cable_altmode_support support = CABLE_SUPPORT_UNKNOWN; -+ struct typec_cable *cable; -+ -+ cable = typec_cable_get(typec_altmode2port(alt)); -+ if (cable) { -+ support = typec_cable_check_altmode_support(cable, alt); -+ typec_cable_put(cable); -+ } -+ -+ return support == CABLE_NOT_SUPPORTED; -+} -+EXPORT_SYMBOL_GPL(typec_cable_altmode_unsupported); -+ - /** - * typec_cable_set_identity - Report result from Discover Identity command - * @cable: The cable updated identity values -diff --git a/drivers/usb/typec/mux/tusb1046.c b/drivers/usb/typec/mux/tusb1046.c ---- a/drivers/usb/typec/mux/tusb1046.c -+++ b/drivers/usb/typec/mux/tusb1046.c -@@ -178,6 +178,7 @@ static const struct of_device_id tusb1046_match_table[] = { - {.compatible = "ti,tusb1046"}, - {}, - }; -+MODULE_DEVICE_TABLE(of, tusb1046_match_table); - - static struct i2c_driver tusb1046_driver = { - .driver = { -diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c ---- a/drivers/usb/typec/tcpm/tcpm.c -+++ b/drivers/usb/typec/tcpm/tcpm.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -212,6 +213,24 @@ static const char * const tcpm_ams_str[] = { - FOREACH_AMS(GENERATE_STRING) - }; - -+#define FOREACH_VDM_DISCOVERY(S) \ -+ S(VDM_DISCOVERY_UNKNOWN), \ -+ S(VDM_DISCOVERY_PARTNER_IDENT), \ -+ S(VDM_DISCOVERY_CABLE_IDENT), \ -+ S(VDM_DISCOVERY_PARTNER_SVIDS), \ -+ S(VDM_DISCOVERY_PARTNER_MODES), \ -+ S(VDM_DISCOVERY_CABLE_SVIDS), \ -+ S(VDM_DISCOVERY_CABLE_MODES), \ -+ S(VDM_DISCOVERY_COMPLETE) -+ -+enum vdm_discovery_states { -+ FOREACH_VDM_DISCOVERY(GENERATE_ENUM) -+}; -+ -+static const char * const vdm_discovery_state_strings[] = { -+ FOREACH_VDM_DISCOVERY(GENERATE_STRING) -+}; -+ - enum vdm_states { - VDM_STATE_ERR_BUSY = -3, - VDM_STATE_ERR_SEND = -2, -@@ -232,7 +251,9 @@ enum pd_msg_request { - PD_MSG_DATA_SINK_CAP, - PD_MSG_DATA_SOURCE_CAP, - PD_MSG_DATA_REV, -- PD_MSG_EXT_SINK_CAP_EXT -+ PD_MSG_EXT_SINK_CAP_EXT, -+ PD_MSG_DATA_BATT_STATUS, -+ PD_MSG_EXT_BATT_CAP, - }; - - enum adev_actions { -@@ -274,7 +295,7 @@ enum frs_typec_current { - #define ALTMODE_DISCOVERY_MAX (SVID_DISCOVERY_MAX * MODE_DISCOVERY_MAX) - - #define GET_SINK_CAP_RETRY_MS 100 --#define SEND_DISCOVER_RETRY_MS 100 -+#define SEND_DISCOVERY_VDM_RETRY_MS 100 - - struct pd_mode_data { - int svid_index; /* current SVID index */ -@@ -387,7 +408,15 @@ struct pd_timings { - }; - - /* Convert microwatt to watt */ --#define UW_TO_W(pow) ((pow) / 1000000) -+#define UW_TO_W(pow) (div_u64((pow), 1000000)) -+ -+/* -+ * As per USB PD Spec Rev 3.18 (Sec. 6.5.13.11), the number of fixed batteries -+ * that a port can be queried is restricted to 4. -+ */ -+#define MAX_NUM_FIXED_BATT 4 -+ -+#define BATTERY_PROPERTY_UNKNOWN 0xffff - - /* - * struct pd_identifier - Contains info about PD identifiers -@@ -483,8 +512,6 @@ struct tcpm_port { - bool vbus_source; - bool vbus_charge; - -- /* Set to true when Discover_Identity Command is expected to be sent in Ready states. */ -- bool send_discover; - bool op_vsafe5v; - - int try_role; -@@ -510,8 +537,8 @@ struct tcpm_port { - struct kthread_work vdm_state_machine; - struct hrtimer enable_frs_timer; - struct kthread_work enable_frs; -- struct hrtimer send_discover_timer; -- struct kthread_work send_discover_work; -+ struct hrtimer vdm_discovery_timer; -+ struct kthread_work vdm_discovery_work; - bool state_machine_running; - /* Set to true when VDM State Machine has following actions. */ - bool vdm_sm_running; -@@ -578,6 +605,9 @@ struct tcpm_port { - - u32 bist_request; - -+ /* VDM Discovery State to determine message sent */ -+ enum vdm_discovery_states vdm_discovery_state; -+ - /* PD state for Vendor Defined Messages */ - enum vdm_states vdm_state; - u32 vdm_retries; -@@ -641,12 +671,6 @@ struct tcpm_port { - bool potential_contaminant; - - /* SOP* Related Fields */ -- /* -- * Flag to determine if SOP' Discover Identity is available. The flag -- * is set if Discover Identity on SOP' does not immediately follow -- * Discover Identity on SOP. -- */ -- bool send_discover_prime; - /* - * tx_sop_type determines which SOP* a message is being sent on. - * For messages that are queued and not sent immediately such as in -@@ -683,6 +707,9 @@ struct tcpm_port { - - struct pd_identifier pd_ident; - struct sink_caps_ext_data sink_caps_ext; -+ struct power_supply **fixed_batt; -+ u32 fixed_batt_cnt; -+ u32 batt_request_id; - #ifdef CONFIG_DEBUG_FS - struct dentry *dentry; - struct mutex logbuffer_lock; /* log buffer access lock */ -@@ -771,6 +798,9 @@ static const char * const pd_rev[] = { - #define tcpm_wait_for_discharge(port) \ - (((port)->auto_vbus_discharge_enabled && !(port)->vbus_vsafe0v) ? PD_T_SAFE_0V : 0) - -+#define tcpm_can_send_vdm(state) \ -+ ((state == SRC_READY || state == SNK_READY || state == SRC_VDM_IDENTITY_REQUEST)) -+ - static enum tcpm_state tcpm_default_state(struct tcpm_port *port) - { - if (port->port_type == TYPEC_PORT_DRP) { -@@ -1470,6 +1500,20 @@ static int tcpm_pd_send_sink_caps(struct tcpm_port *port) - return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg); - } - -+static void tcpm_get_fixed_batt(struct tcpm_port *port) -+{ -+ int ret; -+ -+ if (!port->self_powered || port->fixed_batt_cnt > 0) -+ return; -+ -+ ret = power_supply_get_system_batteries(port->dev, &port->fixed_batt); -+ if (ret < 0) -+ tcpm_log(port, "Failed to get battery array, ret=%d", ret); -+ else -+ port->fixed_batt_cnt = ret; -+} -+ - static int tcpm_pd_send_sink_cap_ext(struct tcpm_port *port) - { - u16 operating_snk_watt = port->operating_snk_mw / 1000; -@@ -1482,6 +1526,8 @@ static int tcpm_pd_send_sink_cap_ext(struct tcpm_port *port) - if (!port->self_powered) - data->spr_op_pdp = operating_snk_watt; - -+ tcpm_get_fixed_batt(port); -+ - /* - * SPR Sink Minimum PDP indicates the minimum power required to operate - * a sink device in its lowest level of functionality without requiring -@@ -1507,6 +1553,7 @@ static int tcpm_pd_send_sink_cap_ext(struct tcpm_port *port) - skedb.load_step = data->load_step; - skedb.load_char = cpu_to_le16(data->load_char); - skedb.compliance = data->compliance; -+ skedb.batt_info = min(port->fixed_batt_cnt, MAX_NUM_FIXED_BATT); - skedb.modes = data->modes; - skedb.spr_min_pdp = data->spr_min_pdp; - skedb.spr_op_pdp = data->spr_op_pdp; -@@ -1525,6 +1572,153 @@ static int tcpm_pd_send_sink_cap_ext(struct tcpm_port *port) - port->message_id, - data_obj_cnt, - 1 /* Denotes if ext header */)); -+ -+ return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg); -+} -+ -+static u16 tcpm_charge_to_energy(int charge, int voltage) -+{ -+ u64 energy = div_u64((u64)charge * voltage, 1000000); -+ -+ /* Battery telemetry is reported in increments of 0.1Wh */ -+ return (u16)UW_TO_W(energy * 10); -+} -+ -+static int tcpm_pd_send_batt_status(struct tcpm_port *port) -+{ -+ u16 present_charge = BATTERY_PROPERTY_UNKNOWN; -+ bool batt_present = false, invalid_ref = true; -+ u32 batt_id = port->batt_request_id; -+ union power_supply_propval val; -+ struct power_supply *batt; -+ u8 charging_status = 0; -+ struct pd_message msg; -+ int ret, charge_now; -+ u32 bsdo; -+ -+ tcpm_get_fixed_batt(port); -+ memset(&msg, 0, sizeof(msg)); -+ -+ if (batt_id >= port->fixed_batt_cnt || batt_id >= MAX_NUM_FIXED_BATT) -+ goto send_status; -+ -+ invalid_ref = false; -+ batt = port->fixed_batt[batt_id]; -+ ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_PRESENT, &val); -+ if (ret) -+ tcpm_log(port, -+ "Failed to fetch power_supply_prop_present ret %d", -+ ret); -+ else -+ batt_present = val.intval > 0; -+ -+ ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_NOW, -+ &val); -+ if (!ret) { -+ charge_now = val.intval; -+ ret = power_supply_get_property(batt, -+ POWER_SUPPLY_PROP_VOLTAGE_AVG, -+ &val); -+ if (!ret) -+ present_charge = tcpm_charge_to_energy(charge_now, -+ val.intval); -+ } -+ -+ ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_STATUS, &val); -+ if (!ret) { -+ switch (val.intval) { -+ case POWER_SUPPLY_STATUS_CHARGING: -+ charging_status = BSDO_BATTERY_INFO_CHARGING; -+ break; -+ case POWER_SUPPLY_STATUS_DISCHARGING: -+ charging_status = BSDO_BATTERY_INFO_DISCHARGING; -+ break; -+ case POWER_SUPPLY_STATUS_NOT_CHARGING: -+ case POWER_SUPPLY_STATUS_FULL: -+ charging_status = BSDO_BATTERY_INFO_IDLE; -+ break; -+ default: -+ charging_status = BSDO_BATTERY_INFO_RSVD; -+ break; -+ } -+ } -+ -+send_status: -+ -+ bsdo = BSDO(present_charge, charging_status, batt_present, invalid_ref); -+ msg.payload[0] = cpu_to_le32(bsdo); -+ msg.header = PD_HEADER_LE(PD_DATA_BATT_STATUS, -+ port->pwr_role, -+ port->data_role, -+ port->negotiated_rev, -+ port->message_id, -+ 1); -+ -+ return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg); -+} -+ -+static int tcpm_pd_send_batt_cap(struct tcpm_port *port) -+{ -+ u16 design_cap = BATTERY_PROPERTY_UNKNOWN; -+ u16 charge_cap = BATTERY_PROPERTY_UNKNOWN; -+ u32 batt_id = port->batt_request_id; -+ union power_supply_propval val; -+ struct batt_cap_ext_msg bcdb; -+ struct power_supply *batt; -+ bool invalid_ref = true; -+ struct pd_message msg; -+ u8 data_obj_cnt; -+ int ret, vol; -+ -+ tcpm_get_fixed_batt(port); -+ memset(&msg, 0, sizeof(msg)); -+ -+ if (batt_id >= port->fixed_batt_cnt || batt_id >= MAX_NUM_FIXED_BATT) -+ goto send_cap; -+ -+ invalid_ref = false; -+ batt = port->fixed_batt[batt_id]; -+ ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_VOLTAGE_AVG, -+ &val); -+ if (!ret) { -+ vol = val.intval; -+ ret = power_supply_get_property(batt, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ &val); -+ if (!ret) -+ design_cap = tcpm_charge_to_energy(val.intval, vol); -+ -+ ret = power_supply_get_property(batt, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ &val); -+ if (!ret) -+ charge_cap = tcpm_charge_to_energy(val.intval, vol); -+ } -+ -+send_cap: -+ -+ /* -+ * As per the USB PD Rev3.1 v1.8 spec, if a battery VID (assigned by the -+ * USB-IF) does not exist or an invalid battery reference is made by the -+ * requestor, then set the VID field to 0xffff. If the VID field is -+ * 0xffff, set the PID field to 0. -+ */ -+ bcdb.vid = BATTERY_PROPERTY_UNKNOWN; -+ bcdb.pid = 0; -+ bcdb.batt_design_cap = cpu_to_le16(design_cap); -+ bcdb.batt_last_chg_cap = cpu_to_le16(charge_cap); -+ bcdb.batt_type = invalid_ref ? BATT_CAP_BATT_TYPE_INVALID_REF : 0; -+ memcpy(msg.ext_msg.data, &bcdb, sizeof(bcdb)); -+ msg.ext_msg.header = PD_EXT_HDR_LE(sizeof(bcdb), -+ 0, /* Denotes if request chunk */ -+ 0, /* Chunk number */ -+ 1 /* Chunked */); -+ -+ data_obj_cnt = count_chunked_data_objs(sizeof(bcdb)); -+ msg.header = PD_HEADER_EXT_LE(PD_EXT_BATT_CAP, port->pwr_role, -+ port->data_role, port->negotiated_rev, -+ port->message_id, data_obj_cnt); -+ - return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg); - } - -@@ -1559,13 +1753,19 @@ static void mod_enable_frs_delayed_work(struct tcpm_port *port, unsigned int del - } - } - --static void mod_send_discover_delayed_work(struct tcpm_port *port, unsigned int delay_ms) -+static void mod_vdm_discovery_cancel_delayed_work(struct tcpm_port *port) -+{ -+ hrtimer_cancel(&port->vdm_discovery_timer); -+ kthread_cancel_work_sync(&port->vdm_discovery_work); -+} -+ -+static void mod_vdm_discovery_delayed_work(struct tcpm_port *port, unsigned int delay_ms) - { - if (delay_ms) { -- hrtimer_start(&port->send_discover_timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); -+ hrtimer_start(&port->vdm_discovery_timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); - } else { -- hrtimer_cancel(&port->send_discover_timer); -- kthread_queue_work(port->wq, &port->send_discover_work); -+ hrtimer_cancel(&port->vdm_discovery_timer); -+ kthread_queue_work(port->wq, &port->vdm_discovery_work); - } - } - -@@ -1773,16 +1973,11 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, - WARN_ON(!mutex_is_locked(&port->lock)); - - /* If is sending discover_identity, handle received message first */ -- if (PD_VDO_SVDM(vdo_hdr) && PD_VDO_CMD(vdo_hdr) == CMD_DISCOVER_IDENT) { -- if (tx_sop_type == TCPC_TX_SOP_PRIME) -- port->send_discover_prime = true; -- else -- port->send_discover = true; -- mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS); -- } else { -+ if (PD_VDO_SVDM(vdo_hdr) && PD_VDO_CMD(vdo_hdr) == CMD_DISCOVER_IDENT) -+ mod_vdm_discovery_delayed_work(port, SEND_DISCOVERY_VDM_RETRY_MS); -+ else - /* Make sure we are not still processing a previous VDM packet */ - WARN_ON(port->vdm_state > VDM_STATE_DONE); -- } - - port->vdo_count = cnt + 1; - port->vdo_data[0] = header; -@@ -1805,8 +2000,7 @@ static void tcpm_queue_vdm_work(struct kthread_work *work) - struct tcpm_port *port = event->port; - - mutex_lock(&port->lock); -- if (port->state != SRC_READY && port->state != SNK_READY && -- port->state != SRC_VDM_IDENTITY_REQUEST) { -+ if (!tcpm_can_send_vdm(port->state)) { - tcpm_log_force(port, "dropping altmode_vdm_event"); - goto port_unlock; - } -@@ -2034,7 +2228,7 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port) - if (!port->partner) - return; - -- for (i = 0; i < modep->altmodes; i++) { -+ for (i = 0; i < modep->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) { - altmode = typec_partner_register_altmode(port->partner, - &modep->altmode_desc[i]); - if (IS_ERR(altmode)) { -@@ -2052,9 +2246,10 @@ static void tcpm_register_plug_altmodes(struct tcpm_port *port) - struct typec_altmode *altmode; - int i; - -- typec_plug_set_num_altmodes(port->plug_prime, modep->altmodes); -+ typec_plug_set_num_altmodes(port->plug_prime, -+ min(modep->altmodes, ALTMODE_DISCOVERY_MAX)); - -- for (i = 0; i < modep->altmodes; i++) { -+ for (i = 0; i < modep->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) { - altmode = typec_plug_register_altmode(port->plug_prime, - &modep->altmode_desc[i]); - if (IS_ERR(altmode)) { -@@ -2154,6 +2349,19 @@ static bool tcpm_cable_vdm_supported(struct tcpm_port *port) - tcpm_can_communicate_sop_prime(port); - } - -+static void tcpm_update_vdm_discovery_state(struct tcpm_port *port, -+ enum vdm_discovery_states new_state) -+{ -+ enum vdm_discovery_states old_state = port->vdm_discovery_state; -+ -+ if (old_state != new_state) -+ tcpm_log_force(port, "vdm discovery state changed: %s -> %s", -+ vdm_discovery_state_strings[old_state], -+ vdm_discovery_state_strings[new_state]); -+ -+ port->vdm_discovery_state = new_state; -+} -+ - static int tcpm_handle_discover_mode(struct tcpm_port *port, u32 *response, - enum tcpm_transmit_type rx_sop_type, - enum tcpm_transmit_type *response_tx_sop_type) -@@ -2171,6 +2379,7 @@ static int tcpm_handle_discover_mode(struct tcpm_port *port, u32 *response, - response[0] = VDO(svid, 1, - typec_get_negotiated_svdm_version(typec), - CMD_DISCOVER_MODES); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_PARTNER_MODES); - return 1; - } - -@@ -2179,10 +2388,12 @@ static int tcpm_handle_discover_mode(struct tcpm_port *port, u32 *response, - response[0] = VDO(USB_SID_PD, 1, - typec_get_cable_svdm_version(typec), - CMD_DISCOVER_SVID); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_PARTNER_MODES); - return 1; - } - - tcpm_register_partner_altmodes(port); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); - } else if (rx_sop_type == TCPC_TX_SOP_PRIME) { - modep = &port->mode_data_prime; - modep->svid_index++; -@@ -2193,11 +2404,13 @@ static int tcpm_handle_discover_mode(struct tcpm_port *port, u32 *response, - response[0] = VDO(svid, 1, - typec_get_cable_svdm_version(typec), - CMD_DISCOVER_MODES); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_CABLE_MODES); - return 1; - } - - tcpm_register_plug_altmodes(port); - tcpm_register_partner_altmodes(port); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); - } - - return 0; -@@ -2376,18 +2589,18 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, - typec_cable_set_svdm_version(port->cable, - svdm_version); - } -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_PARTNER_IDENT); -+ - /* 6.4.4.3.1 */ - svdm_consume_identity(port, p, cnt); - /* Attempt Vconn swap, delay SOP' discovery if necessary */ - if (tcpm_attempt_vconn_swap_discovery(port)) { -- port->send_discover_prime = true; - port->upcoming_state = VCONN_SWAP_SEND; - ret = tcpm_ams_start(port, VCONN_SWAP); - if (!ret) - return 0; - /* Cannot perform Vconn swap */ - port->upcoming_state = INVALID_STATE; -- port->send_discover_prime = false; - } - - /* -@@ -2398,7 +2611,6 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, - if (IS_ERR_OR_NULL(port->cable) && - tcpm_can_communicate_sop_prime(port)) { - *response_tx_sop_type = TCPC_TX_SOP_PRIME; -- port->send_discover_prime = true; - response[0] = VDO(USB_SID_PD, 1, - typec_get_negotiated_svdm_version(typec), - CMD_DISCOVER_IDENT); -@@ -2426,6 +2638,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, - tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); - return 0; - } -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_CABLE_IDENT); - - *response_tx_sop_type = TCPC_TX_SOP; - response[0] = VDO(USB_SID_PD, 1, -@@ -2445,16 +2658,27 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, - rlen = 1; - } else { - if (rx_sop_type == TCPC_TX_SOP) { -+ tcpm_update_vdm_discovery_state(port, -+ VDM_DISCOVERY_PARTNER_SVIDS); - if (modep->nsvids && supports_modal(port)) { - response[0] = VDO(modep->svids[0], 1, svdm_version, - CMD_DISCOVER_MODES); - rlen = 1; -+ } else { -+ tcpm_update_vdm_discovery_state(port, -+ VDM_DISCOVERY_COMPLETE); - } - } else if (rx_sop_type == TCPC_TX_SOP_PRIME) { -+ tcpm_update_vdm_discovery_state(port, -+ VDM_DISCOVERY_CABLE_SVIDS); - if (modep_prime->nsvids) { - response[0] = VDO(modep_prime->svids[0], 1, - svdm_version, CMD_DISCOVER_MODES); - rlen = 1; -+ } else { -+ tcpm_register_partner_altmodes(port); -+ tcpm_update_vdm_discovery_state(port, -+ VDM_DISCOVERY_COMPLETE); - } - } - } -@@ -2505,8 +2729,13 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, - case CMDT_RSP_NAK: - tcpm_ams_finish(port); - switch (cmd) { -+ /* -+ * The cable is not allowed to respond with NAK so this must've happened over SOP -+ */ - case CMD_DISCOVER_IDENT: - case CMD_DISCOVER_SVID: -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); -+ break; - case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15): - break; - case CMD_DISCOVER_MODES: -@@ -2686,44 +2915,6 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, - port->vdm_sm_running = false; - } - --static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd, -- const u32 *data, int count, enum tcpm_transmit_type tx_sop_type) --{ -- int svdm_version; -- u32 header; -- -- switch (tx_sop_type) { -- case TCPC_TX_SOP_PRIME: -- /* -- * If the port partner is discovered, then the port partner's -- * SVDM Version will be returned -- */ -- svdm_version = typec_get_cable_svdm_version(port->typec_port); -- if (svdm_version < 0) -- svdm_version = SVDM_VER_MAX; -- break; -- case TCPC_TX_SOP: -- svdm_version = typec_get_negotiated_svdm_version(port->typec_port); -- if (svdm_version < 0) -- return; -- break; -- default: -- svdm_version = typec_get_negotiated_svdm_version(port->typec_port); -- if (svdm_version < 0) -- return; -- break; -- } -- -- if (WARN_ON(count > VDO_MAX_SIZE - 1)) -- count = VDO_MAX_SIZE - 1; -- -- /* set VDM header with VID & CMD */ -- header = VDO(vid, ((vid & USB_SID_PD) == USB_SID_PD) ? -- 1 : (PD_VDO_CMD(cmd) <= CMD_ATTENTION), -- svdm_version, cmd); -- tcpm_queue_vdm(port, header, data, count, tx_sop_type); --} -- - static unsigned int vdm_ready_timeout(u32 vdm_hdr) - { - unsigned int timeout; -@@ -2769,8 +2960,7 @@ static void vdm_run_state_machine(struct tcpm_port *port) - * if there's traffic or we're not in PDO ready state don't send - * a VDM. - */ -- if (port->state != SRC_READY && port->state != SNK_READY && -- port->state != SRC_VDM_IDENTITY_REQUEST) { -+ if (!tcpm_can_send_vdm(port->state)) { - port->vdm_sm_running = false; - break; - } -@@ -2780,22 +2970,10 @@ static void vdm_run_state_machine(struct tcpm_port *port) - switch (PD_VDO_CMD(vdo_hdr)) { - case CMD_DISCOVER_IDENT: - res = tcpm_ams_start(port, DISCOVER_IDENTITY); -- if (res == 0) { -- switch (port->tx_sop_type) { -- case TCPC_TX_SOP_PRIME: -- port->send_discover_prime = false; -- break; -- case TCPC_TX_SOP: -- port->send_discover = false; -- break; -- default: -- port->send_discover = false; -- break; -- } -- } else if (res == -EAGAIN) { -+ if (res == -EAGAIN) { - port->vdo_data[0] = 0; -- mod_send_discover_delayed_work(port, -- SEND_DISCOVER_RETRY_MS); -+ mod_vdm_discovery_delayed_work(port, -+ SEND_DISCOVERY_VDM_RETRY_MS); - } - break; - case CMD_DISCOVER_SVID: -@@ -2853,6 +3031,7 @@ static void vdm_run_state_machine(struct tcpm_port *port) - */ - if (port->state == SRC_VDM_IDENTITY_REQUEST) { - tcpm_ams_finish(port); -+ port->vdo_data[0] = 0; - port->vdm_state = VDM_STATE_DONE; - tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); - /* -@@ -2869,6 +3048,7 @@ static void vdm_run_state_machine(struct tcpm_port *port) - tcpm_ams_finish(port); - } else { - tcpm_ams_finish(port); -+ port->vdo_data[0] = 0; - if (port->tx_sop_type == TCPC_TX_SOP) - break; - /* Handle SOP' Transmission Errors */ -@@ -2878,11 +3058,11 @@ static void vdm_run_state_machine(struct tcpm_port *port) - * discovery process on SOP only. - */ - case CMD_DISCOVER_IDENT: -- port->vdo_data[0] = 0; - response[0] = VDO(USB_SID_PD, 1, - typec_get_negotiated_svdm_version( - port->typec_port), - CMD_DISCOVER_SVID); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_CABLE_IDENT); - tcpm_queue_vdm(port, response[0], &response[1], - 0, TCPC_TX_SOP); - break; -@@ -2892,9 +3072,11 @@ static void vdm_run_state_machine(struct tcpm_port *port) - */ - case CMD_DISCOVER_SVID: - tcpm_register_partner_altmodes(port); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); - break; - case CMD_DISCOVER_MODES: - tcpm_register_partner_altmodes(port); -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); - break; - default: - break; -@@ -3807,7 +3989,8 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, - PD_MSG_CTRL_NOT_SUPP, - NONE_AMS); - } else { -- if (port->send_discover && port->negotiated_rev < PD_REV30) { -+ if (port->vdm_discovery_state == VDM_DISCOVERY_UNKNOWN && -+ port->negotiated_rev < PD_REV30) { - tcpm_queue_message(port, PD_MSG_CTRL_WAIT); - break; - } -@@ -3823,7 +4006,8 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, - PD_MSG_CTRL_NOT_SUPP, - NONE_AMS); - } else { -- if (port->send_discover && port->negotiated_rev < PD_REV30) { -+ if (port->vdm_discovery_state == VDM_DISCOVERY_UNKNOWN && -+ port->negotiated_rev < PD_REV30) { - tcpm_queue_message(port, PD_MSG_CTRL_WAIT); - break; - } -@@ -3832,7 +4016,8 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, - } - break; - case PD_CTRL_VCONN_SWAP: -- if (port->send_discover && port->negotiated_rev < PD_REV30) { -+ if (port->vdm_discovery_state == VDM_DISCOVERY_UNKNOWN && -+ port->negotiated_rev < PD_REV30) { - tcpm_queue_message(port, PD_MSG_CTRL_WAIT); - break; - } -@@ -3891,6 +4076,7 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, - { - enum pd_ext_msg_type type = pd_header_type_le(msg->header); - unsigned int data_size = pd_ext_header_data_size_le(msg->ext_msg.header); -+ const struct pd_chunked_ext_message_data *ext_msg = &msg->ext_msg; - - /* stopping VDM state machine if interrupted by other Messages */ - if (tcpm_vdm_ams(port)) { -@@ -3899,7 +4085,7 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, - mod_vdm_delayed_work(port, 0); - } - -- if (!(le16_to_cpu(msg->ext_msg.header) & PD_EXT_HDR_CHUNKED)) { -+ if (!(le16_to_cpu(ext_msg->header) & PD_EXT_HDR_CHUNKED)) { - tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); - tcpm_log(port, "Unchunked extended messages unsupported"); - return; -@@ -3924,9 +4110,25 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, - NONE_AMS, 0); - } - break; -- case PD_EXT_SOURCE_CAP_EXT: -- case PD_EXT_GET_BATT_CAP: - case PD_EXT_GET_BATT_STATUS: -+ if (data_size >= 1) { -+ port->batt_request_id = ext_msg->data[0]; -+ tcpm_pd_handle_msg(port, PD_MSG_DATA_BATT_STATUS, -+ GETTING_BATTERY_STATUS); -+ } else { -+ tcpm_set_state(port, SOFT_RESET_SEND, 0); -+ } -+ break; -+ case PD_EXT_GET_BATT_CAP: -+ if (data_size >= 1) { -+ port->batt_request_id = ext_msg->data[0]; -+ tcpm_pd_handle_msg(port, PD_MSG_EXT_BATT_CAP, -+ GETTING_BATTERY_CAPABILITIES); -+ } else { -+ tcpm_set_state(port, SOFT_RESET_SEND, 0); -+ } -+ break; -+ case PD_EXT_SOURCE_CAP_EXT: - case PD_EXT_BATT_CAP: - case PD_EXT_GET_MANUFACTURER_INFO: - case PD_EXT_MANUFACTURER_INFO: -@@ -4137,6 +4339,22 @@ static bool tcpm_send_queued_message(struct tcpm_port *port) - ret); - tcpm_ams_finish(port); - break; -+ case PD_MSG_DATA_BATT_STATUS: -+ ret = tcpm_pd_send_batt_status(port); -+ if (ret) -+ tcpm_log(port, -+ "Failed to send battery status ret=%d", -+ ret); -+ tcpm_ams_finish(port); -+ break; -+ case PD_MSG_EXT_BATT_CAP: -+ ret = tcpm_pd_send_batt_cap(port); -+ if (ret) -+ tcpm_log(port, -+ "Failed to send battery cap ret=%d", -+ ret); -+ tcpm_ams_finish(port); -+ break; - default: - break; - } -@@ -4853,8 +5071,7 @@ static int tcpm_src_attach(struct tcpm_port *port) - port->partner = NULL; - - port->attached = true; -- port->send_discover = true; -- port->send_discover_prime = false; -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_UNKNOWN); - - return 0; - -@@ -4896,11 +5113,11 @@ static void tcpm_unregister_altmodes(struct tcpm_port *port) - struct pd_mode_data *modep_prime = &port->mode_data_prime; - int i; - -- for (i = 0; i < modep->altmodes; i++) { -+ for (i = 0; i < modep->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) { - typec_unregister_altmode(port->partner_altmode[i]); - port->partner_altmode[i] = NULL; - } -- for (i = 0; i < modep_prime->altmodes; i++) { -+ for (i = 0; i < modep_prime->altmodes && i < ALTMODE_DISCOVERY_MAX; i++) { - typec_unregister_altmode(port->plug_prime_altmode[i]); - port->plug_prime_altmode[i] = NULL; - } -@@ -4931,6 +5148,8 @@ static void tcpm_reset_port(struct tcpm_port *port) - port->in_ams = false; - port->ams = NONE_AMS; - port->vdm_sm_running = false; -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_UNKNOWN); -+ mod_vdm_discovery_cancel_delayed_work(port); - tcpm_unregister_altmodes(port); - tcpm_typec_disconnect(port); - port->attached = false; -@@ -5014,8 +5233,7 @@ static int tcpm_snk_attach(struct tcpm_port *port) - port->partner = NULL; - - port->attached = true; -- port->send_discover = true; -- port->send_discover_prime = false; -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_UNKNOWN); - - return 0; - } -@@ -5422,16 +5640,11 @@ static void run_state_machine(struct tcpm_port *port) - * as well. - */ - if (port->explicit_contract) { -- if (port->send_discover_prime) { -- port->tx_sop_type = TCPC_TX_SOP_PRIME; -- } else { -- port->tx_sop_type = TCPC_TX_SOP; -+ if (port->vdm_discovery_state == VDM_DISCOVERY_UNKNOWN) - tcpm_set_initial_svdm_version(port); -- } -- mod_send_discover_delayed_work(port, 0); -+ mod_vdm_discovery_delayed_work(port, 0); - } else { -- port->send_discover = false; -- port->send_discover_prime = false; -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); - } - - /* -@@ -5814,16 +6027,11 @@ static void run_state_machine(struct tcpm_port *port) - * as well. - */ - if (port->explicit_contract) { -- if (port->send_discover_prime) { -- port->tx_sop_type = TCPC_TX_SOP_PRIME; -- } else { -- port->tx_sop_type = TCPC_TX_SOP; -+ if (port->vdm_discovery_state == VDM_DISCOVERY_UNKNOWN) - tcpm_set_initial_svdm_version(port); -- } -- mod_send_discover_delayed_work(port, 0); -+ mod_vdm_discovery_delayed_work(port, 0); - } else { -- port->send_discover = false; -- port->send_discover_prime = false; -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); - } - - power_supply_changed(port->psy); -@@ -5869,8 +6077,8 @@ static void run_state_machine(struct tcpm_port *port) - port->tcpc->set_pd_rx(port->tcpc, false); - tcpm_unregister_altmodes(port); - port->nr_sink_caps = 0; -- port->send_discover = true; -- port->send_discover_prime = false; -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_UNKNOWN); -+ mod_vdm_discovery_cancel_delayed_work(port); - if (port->pwr_role == TYPEC_SOURCE) - tcpm_set_state(port, SRC_HARD_RESET_VBUS_OFF, - PD_T_PS_HARD_RESET); -@@ -6017,25 +6225,15 @@ static void run_state_machine(struct tcpm_port *port) - /* DR_Swap states */ - case DR_SWAP_SEND: - tcpm_pd_send_control(port, PD_CTRL_DR_SWAP, TCPC_TX_SOP); -- if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20) { -- port->send_discover = true; -- port->send_discover_prime = false; -- } - tcpm_set_state_cond(port, DR_SWAP_SEND_TIMEOUT, - PD_T_SENDER_RESPONSE); - break; - case DR_SWAP_ACCEPT: - tcpm_pd_send_control(port, PD_CTRL_ACCEPT, TCPC_TX_SOP); -- if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20) { -- port->send_discover = true; -- port->send_discover_prime = false; -- } - tcpm_set_state_cond(port, DR_SWAP_CHANGE_DR, 0); - break; - case DR_SWAP_SEND_TIMEOUT: - tcpm_swap_complete(port, -ETIMEDOUT); -- port->send_discover = false; -- port->send_discover_prime = false; - tcpm_ams_finish(port); - tcpm_set_state(port, ready_state(port), 0); - break; -@@ -6047,6 +6245,8 @@ static void run_state_machine(struct tcpm_port *port) - else - tcpm_set_roles(port, true, TYPEC_STATE_USB, port->pwr_role, - TYPEC_HOST); -+ if (port->data_role == TYPEC_HOST || port->negotiated_rev > PD_REV20) -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_UNKNOWN); - tcpm_ams_finish(port); - tcpm_set_state(port, ready_state(port), 0); - break; -@@ -6330,9 +6530,7 @@ static void run_state_machine(struct tcpm_port *port) - - /* Cable states */ - case SRC_VDM_IDENTITY_REQUEST: -- port->send_discover_prime = true; -- port->tx_sop_type = TCPC_TX_SOP_PRIME; -- mod_send_discover_delayed_work(port, 0); -+ mod_vdm_discovery_delayed_work(port, 0); - port->upcoming_state = SRC_SEND_CAPABILITIES; - break; - -@@ -7052,8 +7250,8 @@ static void tcpm_enable_frs_work(struct kthread_work *work) - goto unlock; - - /* Send when the state machine is idle */ -- if (port->state != SNK_READY || port->vdm_sm_running || port->send_discover || -- port->send_discover_prime) -+ if (port->state != SNK_READY || port->vdm_sm_running || -+ port->vdm_discovery_state == VDM_DISCOVERY_UNKNOWN) - goto resched; - - port->upcoming_state = GET_SINK_CAP; -@@ -7070,29 +7268,160 @@ static void tcpm_enable_frs_work(struct kthread_work *work) - mutex_unlock(&port->lock); - } - --static void tcpm_send_discover_work(struct kthread_work *work) -+static void tcpm_vdm_discovery_work(struct kthread_work *work) - { -- struct tcpm_port *port = container_of(work, struct tcpm_port, send_discover_work); -+ struct tcpm_port *port = container_of(work, struct tcpm_port, vdm_discovery_work); -+ enum tcpm_transmit_type tx_sop_type = TCPC_TX_SOP; -+ struct typec_port *typec = port->typec_port; -+ struct pd_mode_data *modep, *modep_prime; -+ u32 msg[2] = { }; -+ int svdm_version; - - mutex_lock(&port->lock); -- /* No need to send DISCOVER_IDENTITY anymore */ -- if (!port->send_discover && !port->send_discover_prime) -- goto unlock; - -- if (port->data_role == TYPEC_DEVICE && port->negotiated_rev < PD_REV30) { -- port->send_discover = false; -- port->send_discover_prime = false; -+ tcpm_log_force(port, "%s state [%s]", __func__, -+ vdm_discovery_state_strings[port->vdm_discovery_state]); -+ -+ /* No need to perform work if Discovery process is complete */ -+ if (port->vdm_discovery_state == VDM_DISCOVERY_COMPLETE) - goto unlock; -- } - - /* Retry if the port is not idle */ -- if ((port->state != SRC_READY && port->state != SNK_READY && -- port->state != SRC_VDM_IDENTITY_REQUEST) || port->vdm_sm_running) { -- mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS); -+ if (!tcpm_can_send_vdm(port->state) || port->vdm_sm_running) { -+ mod_vdm_discovery_delayed_work(port, SEND_DISCOVERY_VDM_RETRY_MS); - goto unlock; - } - -- tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0, port->tx_sop_type); -+ modep = &port->mode_data; -+ modep_prime = &port->mode_data_prime; -+ -+ svdm_version = typec_get_negotiated_svdm_version(typec); -+ -+ switch (port->vdm_discovery_state) { -+ /* -+ * The port has not received a Discover Identity response from the port partner. -+ * -+ * 1. The port will send Discover Identity to the partner over SOP in the SRC_READY and -+ * SNK_READY states if there is an explicit contract -+ * 2. The port will send Discover Identity to the cable over SOP' in the -+ * SRC_VDM_IDENTITY_REQUEST state if capable of doing so. -+ */ -+ case VDM_DISCOVERY_UNKNOWN: -+ /* Can't send Discover Identity, VDM discovery is complete */ -+ if (port->data_role == TYPEC_DEVICE && port->negotiated_rev < PD_REV30) { -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); -+ goto unlock; -+ } -+ -+ if (port->state == SRC_VDM_IDENTITY_REQUEST) { -+ tx_sop_type = TCPC_TX_SOP_PRIME; -+ svdm_version = SVDM_VER_MAX; -+ } -+ -+ msg[0] = VDO(USB_SID_PD, 1, svdm_version, CMD_DISCOVER_IDENT); -+ break; -+ /* -+ * The port has received a Discover Identity ACK from the port partner. -+ * -+ * 1. The port will send Discover Identity to the cable over SOP' in the SRC_READY and -+ * SNK_READY states if it did not previously discover the cable but is capable of doing -+ * so. -+ * 2. The port will send Discover SVIDs to the partner over SOP in the SRC_READY and -+ * SNK_READY states otherwise. -+ */ -+ case VDM_DISCOVERY_PARTNER_IDENT: -+ if (tcpm_can_communicate_sop_prime(port) && !port->cable) { -+ tx_sop_type = TCPC_TX_SOP_PRIME; -+ msg[0] = VDO(USB_SID_PD, 1, svdm_version, CMD_DISCOVER_IDENT); -+ } else { -+ if (tcpm_can_communicate_sop_prime(port)) -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_CABLE_IDENT); -+ msg[0] = VDO(USB_SID_PD, 1, svdm_version, CMD_DISCOVER_SVID); -+ } -+ break; -+ /* -+ * The port has received a Discover Identity ACK from the cable. -+ * -+ * 1. The port will send Discover SVIDs to the partner over SOP. -+ */ -+ case VDM_DISCOVERY_CABLE_IDENT: -+ msg[0] = VDO(USB_SID_PD, 1, svdm_version, CMD_DISCOVER_SVID); -+ break; -+ /* -+ * The port has received a Discover SVIDs ACK from the partner or the last SVIDs supported -+ * by the partner. -+ * -+ * 1. The port will send Discover Modes for the first SVID over SOP if the partner supports -+ * modal operation and valid SVIDs were registered. -+ * 2. The vdm_discovery_state will move to VDM_DISCOVERY_COMPLETE otherwise. -+ */ -+ case VDM_DISCOVERY_PARTNER_SVIDS: -+ if (modep->nsvids && supports_modal(port)) { -+ msg[0] = VDO(modep->svids[0], 1, svdm_version, CMD_DISCOVER_MODES); -+ } else { -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); -+ goto unlock; -+ } -+ break; -+ /* -+ * The port has received a Discover Modes ACK from the partner for any mode. -+ * -+ * 1. The port will send Discover Modes for the next SVID that has not been discovered to -+ * the port partner over SOP. -+ * 2. The port will send Discover SVIDs over SOP' if the port can communicate over SOP' -+ * and the cable supports VDMs. -+ * 3. The vdm_discovery_state will move to VDM_DISCOVERY_COMPLETE otherwise. -+ */ -+ case VDM_DISCOVERY_PARTNER_MODES: -+ /* Not all modes have been discovered yet */ -+ if (modep->svid_index < modep->nsvids) { -+ msg[0] = VDO(modep_prime->svids[modep->svid_index], 1, svdm_version, -+ CMD_DISCOVER_MODES); -+ } else if (tcpm_can_communicate_sop_prime(port) && tcpm_cable_vdm_supported(port)) { -+ tx_sop_type = TCPC_TX_SOP_PRIME; -+ svdm_version = typec_get_cable_svdm_version(typec); -+ msg[0] = VDO(USB_SID_PD, 1, svdm_version, CMD_DISCOVER_SVID); -+ } else { -+ tcpm_update_vdm_discovery_state(port, VDM_DISCOVERY_COMPLETE); -+ goto unlock; -+ } -+ break; -+ /* -+ * The port has received a Discover SVIDs ACK from the cable over SOP'. -+ * -+ * 1. The port will send Discover Modes for the first SVID over SOP'. -+ */ -+ case VDM_DISCOVERY_CABLE_SVIDS: -+ if (modep_prime->nsvids) { -+ tx_sop_type = TCPC_TX_SOP_PRIME; -+ svdm_version = typec_get_cable_svdm_version(typec); -+ msg[0] = VDO(modep_prime->svids[0], 1, svdm_version, CMD_DISCOVER_MODES); -+ } else { -+ goto unlock; -+ } -+ break; -+ /* -+ * The port has received a Discover Modes ACK from the cable for any mode. -+ * -+ * 1. The port will send Discover Modes for the next SVID that has not been discovered to -+ * the cable over SOP'. -+ */ -+ case VDM_DISCOVERY_CABLE_MODES: -+ if (modep_prime->svid_index < modep_prime->nsvids) { -+ tx_sop_type = TCPC_TX_SOP_PRIME; -+ svdm_version = typec_get_cable_svdm_version(typec); -+ msg[0] = VDO(modep_prime->svids[modep->svid_index], 1, svdm_version, -+ CMD_DISCOVER_MODES); -+ } else { -+ goto unlock; -+ } -+ break; -+ default: -+ goto unlock; -+ } -+ -+ if (svdm_version >= 0) -+ tcpm_queue_vdm(port, msg[0], &msg[1], 0, tx_sop_type); - - unlock: - mutex_unlock(&port->lock); -@@ -8508,12 +8837,12 @@ static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer) - return HRTIMER_NORESTART; - } - --static enum hrtimer_restart send_discover_timer_handler(struct hrtimer *timer) -+static enum hrtimer_restart vdm_discovery_timer_handler(struct hrtimer *timer) - { -- struct tcpm_port *port = container_of(timer, struct tcpm_port, send_discover_timer); -+ struct tcpm_port *port = container_of(timer, struct tcpm_port, vdm_discovery_timer); - - if (port->registered) -- kthread_queue_work(port->wq, &port->send_discover_work); -+ kthread_queue_work(port->wq, &port->vdm_discovery_work); - return HRTIMER_NORESTART; - } - -@@ -8547,14 +8876,14 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) - kthread_init_work(&port->vdm_state_machine, vdm_state_machine_work); - kthread_init_work(&port->event_work, tcpm_pd_event_handler); - kthread_init_work(&port->enable_frs, tcpm_enable_frs_work); -- kthread_init_work(&port->send_discover_work, tcpm_send_discover_work); -+ kthread_init_work(&port->vdm_discovery_work, tcpm_vdm_discovery_work); - hrtimer_setup(&port->state_machine_timer, state_machine_timer_handler, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - hrtimer_setup(&port->vdm_state_machine_timer, vdm_state_machine_timer_handler, - CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrtimer_setup(&port->enable_frs_timer, enable_frs_timer_handler, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); -- hrtimer_setup(&port->send_discover_timer, send_discover_timer_handler, CLOCK_MONOTONIC, -+ hrtimer_setup(&port->vdm_discovery_timer, vdm_discovery_timer_handler, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - - spin_lock_init(&port->pd_event_lock); -@@ -8649,11 +8978,12 @@ void tcpm_unregister_port(struct tcpm_port *port) - port->registered = false; - kthread_destroy_worker(port->wq); - -- hrtimer_cancel(&port->send_discover_timer); -+ hrtimer_cancel(&port->vdm_discovery_timer); - hrtimer_cancel(&port->enable_frs_timer); - hrtimer_cancel(&port->vdm_state_machine_timer); - hrtimer_cancel(&port->state_machine_timer); - -+ power_supply_put_system_batteries(port->fixed_batt, port->fixed_batt_cnt); - tcpm_reset_port(port); - - tcpm_port_unregister_pd(port); -diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c ---- a/drivers/usb/typec/tipd/core.c -+++ b/drivers/usb/typec/tipd/core.c -@@ -129,6 +129,7 @@ enum { - TPS_MODE_BIST, - TPS_MODE_DISC, - TPS_MODE_PTCH, -+ TPS_MODE_APP1, - }; - - static const char *const modes[] = { -@@ -137,6 +138,7 @@ static const char *const modes[] = { - [TPS_MODE_BIST] = "BIST", - [TPS_MODE_DISC] = "DISC", - [TPS_MODE_PTCH] = "PTCH", -+ [TPS_MODE_APP1] = "APP1", - }; - - /* Unrecognized commands will be replaced with "!CMD" */ -@@ -158,6 +160,7 @@ struct tipd_data { - int (*init)(struct tps6598x *tps); - int (*switch_power_state)(struct tps6598x *tps, u8 target_state); - bool (*read_data_status)(struct tps6598x *tps); -+ bool (*read_power_status)(struct tps6598x *tps); - int (*reset)(struct tps6598x *tps); - int (*connect)(struct tps6598x *tps, u32 status); - }; -@@ -629,6 +632,34 @@ static bool tps6598x_read_power_status(struct tps6598x *tps) - return true; - } - -+/* -+ * TPS66993 deprecated Power_Status register (0x3F). BC1.2 is not supported -+ * and the remaining bits are redundant with STATUS register (0x1A). -+ * Synthesize pwr_status from the already-read STATUS register. -+ */ -+static bool tps66993_read_power_status(struct tps6598x *tps) -+{ -+ u16 pwr_status = 0; -+ -+ /* Same masks as TPS_POWER_STATUS_CONNECTION() / SOURCESINK() / PWROPMODE() in tps6598x.h */ -+ if (tps->status & TPS_STATUS_PLUG_PRESENT) -+ pwr_status |= FIELD_PREP(TPS_POWER_STATUS_CONNECTION_MASK, 1); -+ -+ /* SOURCESINK: 1=sink; STATUS.PortRole 1=source, opposite convention */ -+ if (!TPS_STATUS_TO_TYPEC_PORTROLE(tps->status)) -+ pwr_status |= FIELD_PREP(TPS_POWER_STATUS_SOURCESINK_MASK, 1); -+ -+ if (TPS_STATUS_VBUS_STATUS(tps->status) == TPS_STATUS_VBUS_STATUS_PD) -+ pwr_status |= FIELD_PREP(TPS_POWER_STATUS_TYPEC_CURRENT_MASK, -+ TPS_POWER_STATUS_TYPEC_CURRENT_PD); -+ -+ tps->pwr_status = pwr_status; -+ -+ tps->data->trace_power_status(pwr_status); -+ -+ return true; -+} -+ - static void tps6598x_handle_plug_event(struct tps6598x *tps, u32 status) - { - int ret; -@@ -906,7 +937,7 @@ static irqreturn_t cd321x_interrupt(int irq, void *data) - goto err_unlock; - - if (event & APPLE_CD_REG_INT_POWER_STATUS_UPDATE) { -- if (!tps6598x_read_power_status(tps)) -+ if (!tps->data->read_power_status(tps)) - goto err_unlock; - if (TPS_POWER_STATUS_PWROPMODE(tps->pwr_status) == TYPEC_PWR_MODE_PD) { - if (tps6598x_read_partner_identity(tps)) { -@@ -961,7 +992,7 @@ static irqreturn_t tps25750_interrupt(int irq, void *data) - goto err_clear_ints; - - if (event[0] & TPS_REG_INT_POWER_STATUS_UPDATE) -- if (!tps6598x_read_power_status(tps)) -+ if (!tps->data->read_power_status(tps)) - goto err_clear_ints; - - if (event[0] & TPS_REG_INT_DATA_STATUS_UPDATE) -@@ -1034,17 +1065,25 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data) - if (!tps6598x_read_status(tps, &status)) - goto err_unlock; - -+ tps->status = status; -+ - if ((event1[0] | event2[0]) & TPS_REG_INT_POWER_STATUS_UPDATE) -- if (!tps6598x_read_power_status(tps)) -+ if (!tps->data->read_power_status(tps)) - goto err_unlock; - - if ((event1[0] | event2[0]) & TPS_REG_INT_DATA_STATUS_UPDATE) - if (!tps->data->read_data_status(tps)) - goto err_unlock; - -- /* Handle plug insert or removal */ -- if ((event1[0] | event2[0]) & TPS_REG_INT_PLUG_EVENT) -+ /* -+ * Refresh power status before connect - needed for TPS66993 which -+ * synthesizes pwr_status from STATUS and never gets POWER_STATUS_UPDATE. -+ */ -+ if ((event1[0] | event2[0]) & TPS_REG_INT_PLUG_EVENT) { -+ if (!tps->data->read_power_status(tps)) -+ goto err_unlock; - tps6598x_handle_plug_event(tps, status); -+ } - - err_unlock: - mutex_unlock(&tps->lock); -@@ -1080,6 +1119,7 @@ static int tps6598x_check_mode(struct tps6598x *tps) - - switch (ret) { - case TPS_MODE_APP: -+ case TPS_MODE_APP1: - case TPS_MODE_PTCH: - return ret; - case TPS_MODE_BOOT: -@@ -1753,7 +1793,7 @@ static int tps6598x_probe(struct i2c_client *client) - struct tps6598x *tps; - struct fwnode_handle *fwnode; - u32 status; -- u32 vid; -+ u32 vid = 0; - int ret; - - data = i2c_get_match_data(client); -@@ -1781,8 +1821,11 @@ static int tps6598x_probe(struct i2c_client *client) - - if (!device_is_compatible(tps->dev, "ti,tps25750")) { - ret = tps6598x_read32(tps, TPS_REG_VID, &vid); -- if (ret < 0 || !vid) -+ if (ret < 0 || !vid) { -+ dev_err(tps->dev, "failed to read vendor ID: %d, vid: %#x\n", -+ ret, vid); - return -ENODEV; -+ } - } - - /* -@@ -1818,6 +1861,8 @@ static int tps6598x_probe(struct i2c_client *client) - goto err_clear_mask; - } - -+ tps->status = status; -+ - /* - * This fwnode has a "compatible" property, but is never populated as a - * struct device. Instead we simply parse it to read the properties. -@@ -1845,7 +1890,7 @@ static int tps6598x_probe(struct i2c_client *client) - - if (status & TPS_STATUS_PLUG_PRESENT) { - ret = -EINVAL; -- if (!tps6598x_read_power_status(tps)) -+ if (!tps->data->read_power_status(tps)) - goto err_unregister_port; - if (!tps->data->read_data_status(tps)) - goto err_unregister_port; -@@ -1860,7 +1905,7 @@ static int tps6598x_probe(struct i2c_client *client) - IRQF_SHARED | IRQF_ONESHOT, - dev_name(&client->dev), tps); - } else { -- dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n"); -+ dev_dbg(tps->dev, "no IRQ specified, using polling mode\n"); - INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work); - queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, - msecs_to_jiffies(POLL_INTERVAL)); -@@ -1987,6 +2032,7 @@ static const struct tipd_data cd321x_data = { - .trace_status = trace_tps6598x_status, - .init = cd321x_init, - .read_data_status = cd321x_read_data_status, -+ .read_power_status = tps6598x_read_power_status, - .reset = cd321x_reset, - .switch_power_state = cd321x_switch_power_state, - .connect = cd321x_connect, -@@ -2006,6 +2052,25 @@ static const struct tipd_data tps6598x_data = { - .apply_patch = tps6598x_apply_patch, - .init = tps6598x_init, - .read_data_status = tps6598x_read_data_status, -+ .read_power_status = tps6598x_read_power_status, -+ .reset = tps6598x_reset, -+ .connect = tps6598x_connect, -+}; -+ -+static const struct tipd_data tps66993_data = { -+ .irq_handler = tps6598x_interrupt, -+ .irq_mask1 = TPS_REG_INT_DATA_STATUS_UPDATE | -+ TPS_REG_INT_PLUG_EVENT, -+ .tps_struct_size = sizeof(struct tps6598x), -+ .register_port = tps6598x_register_port, -+ .unregister_port = tps6598x_unregister_port, -+ .trace_data_status = trace_tps6598x_data_status, -+ .trace_power_status = trace_tps6598x_power_status, -+ .trace_status = trace_tps6598x_status, -+ .apply_patch = tps6598x_apply_patch, -+ .init = tps6598x_init, -+ .read_data_status = tps6598x_read_data_status, -+ .read_power_status = tps66993_read_power_status, - .reset = tps6598x_reset, - .connect = tps6598x_connect, - }; -@@ -2024,12 +2089,14 @@ static const struct tipd_data tps25750_data = { - .apply_patch = tps25750_apply_patch, - .init = tps25750_init, - .read_data_status = tps6598x_read_data_status, -+ .read_power_status = tps6598x_read_power_status, - .reset = tps25750_reset, - .connect = tps6598x_connect, - }; - - static const struct of_device_id tps6598x_of_match[] = { - { .compatible = "ti,tps6598x", &tps6598x_data}, -+ { .compatible = "ti,tps66993", &tps66993_data}, - { .compatible = "apple,cd321x", &cd321x_data}, - { .compatible = "ti,tps25750", &tps25750_data}, - {} -diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h ---- a/drivers/usb/typec/tipd/tps6598x.h -+++ b/drivers/usb/typec/tipd/tps6598x.h -@@ -142,9 +142,13 @@ - #define TPS_SYSTEM_POWER_STATE_S4 0x04 - #define TPS_SYSTEM_POWER_STATE_S5 0x05 - --/* TPS_REG_POWER_STATUS bits */ --#define TPS_POWER_STATUS_CONNECTION(x) TPS_FIELD_GET(BIT(0), (x)) --#define TPS_POWER_STATUS_SOURCESINK(x) TPS_FIELD_GET(BIT(1), (x)) -+/* TPS_REG_POWER_STATUS bits (masks shared by TPS_FIELD_GET accessors and FIELD_PREP) */ -+#define TPS_POWER_STATUS_CONNECTION_MASK BIT(0) -+#define TPS_POWER_STATUS_SOURCESINK_MASK BIT(1) -+#define TPS_POWER_STATUS_CONNECTION(x) \ -+ TPS_FIELD_GET(TPS_POWER_STATUS_CONNECTION_MASK, (x)) -+#define TPS_POWER_STATUS_SOURCESINK(x) \ -+ TPS_FIELD_GET(TPS_POWER_STATUS_SOURCESINK_MASK, (x)) - #define TPS_POWER_STATUS_BC12_DET(x) TPS_FIELD_GET(BIT(2), (x)) - - #define TPS_POWER_STATUS_TYPEC_CURRENT_MASK GENMASK(3, 2) -diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c ---- a/drivers/usb/typec/ucsi/debugfs.c -+++ b/drivers/usb/typec/ucsi/debugfs.c -@@ -82,8 +82,8 @@ static int ucsi_resp_show(struct seq_file *s, void *not_used) - if (ucsi->debugfs->status) - return ucsi->debugfs->status; - -- seq_printf(s, "0x%016llx%016llx\n", ucsi->debugfs->response.high, -- ucsi->debugfs->response.low); -+ seq_printf(s, "0x%016llx%016llx%016llx\n", ucsi->debugfs->response.ext, -+ ucsi->debugfs->response.high, ucsi->debugfs->response.low); - return 0; - } - DEFINE_SHOW_ATTRIBUTE(ucsi_resp); -diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c ---- a/drivers/usb/typec/ucsi/ucsi.c -+++ b/drivers/usb/typec/ucsi/ucsi.c -@@ -1102,8 +1102,8 @@ static int ucsi_register_plug(struct ucsi_connector *con) - plug = typec_register_plug(con->cable, &desc); - if (IS_ERR(plug)) { - dev_err(con->ucsi->dev, -- "con%d: failed to register plug (%ld)\n", con->num, -- PTR_ERR(plug)); -+ "con%d: failed to register plug (%pe)\n", con->num, -+ plug); - return PTR_ERR(plug); - } - -@@ -1161,8 +1161,8 @@ static int ucsi_register_cable(struct ucsi_connector *con) - cable = typec_register_cable(con->port, &desc); - if (IS_ERR(cable)) { - dev_err(con->ucsi->dev, -- "con%d: failed to register cable (%ld)\n", con->num, -- PTR_ERR(cable)); -+ "con%d: failed to register cable (%pe)\n", con->num, -+ cable); - return PTR_ERR(cable); - } - -@@ -1291,8 +1291,8 @@ static int ucsi_register_partner(struct ucsi_connector *con) - partner = typec_register_partner(con->port, &desc); - if (IS_ERR(partner)) { - dev_err(con->ucsi->dev, -- "con%d: failed to register partner (%ld)\n", con->num, -- PTR_ERR(partner)); -+ "con%d: failed to register partner (%pe)\n", con->num, -+ partner); - return PTR_ERR(partner); - } - -@@ -2221,7 +2221,7 @@ static void ucsi_init_work(struct work_struct *work) - return; - } - -- queue_delayed_work(system_long_wq, &ucsi->work, -+ queue_delayed_work(system_dfl_long_wq, &ucsi->work, - UCSI_ROLE_SWITCH_INTERVAL); - } - } -@@ -2345,7 +2345,7 @@ int ucsi_register(struct ucsi *ucsi) - UCSI_BCD_GET_MINOR(ucsi->version), - UCSI_BCD_GET_SUBMINOR(ucsi->version)); - -- queue_delayed_work(system_long_wq, &ucsi->work, 0); -+ queue_delayed_work(system_dfl_long_wq, &ucsi->work, 0); - - ucsi_debugfs_register(ucsi); - return 0; -diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h ---- a/drivers/usb/typec/ucsi/ucsi.h -+++ b/drivers/usb/typec/ucsi/ucsi.h -@@ -466,6 +466,7 @@ struct ucsi_debugfs_entry { - struct ucsi_data { - u64 low; - u64 high; -+ u64 ext; - } response; - int status; - u8 message_out[MESSAGE_OUT_MAX_LEN]; -diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h ---- a/include/linux/power_supply.h -+++ b/include/linux/power_supply.h -@@ -806,11 +806,26 @@ extern int power_supply_reg_notifier(struct notifier_block *nb); - extern void power_supply_unreg_notifier(struct notifier_block *nb); - #if IS_ENABLED(CONFIG_POWER_SUPPLY) - extern struct power_supply *power_supply_get_by_name(const char *name); -+extern int __must_check power_supply_get_system_batteries(struct device *dev, -+ struct power_supply ***psys); -+extern void power_supply_put_system_batteries(struct power_supply **psys, int count); - extern void power_supply_put(struct power_supply *psy); - #else - static inline void power_supply_put(struct power_supply *psy) {} - static inline struct power_supply *power_supply_get_by_name(const char *name) - { return NULL; } -+static inline int __must_check power_supply_get_system_batteries(struct device *dev, -+ struct power_supply ***psys) -+{ -+ if (psys) -+ *psys = NULL; -+ return 0; -+} -+ -+static inline void power_supply_put_system_batteries(struct power_supply **psys, -+ int count) -+{ -+} - #endif - extern struct power_supply *power_supply_get_by_reference(struct fwnode_handle *fwnode, - const char *property); -diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h ---- a/include/linux/usb/pd.h -+++ b/include/linux/usb/pd.h -@@ -106,6 +106,9 @@ enum pd_ext_msg_type { - #define PD_HEADER_LE(type, pwr, data, rev, id, cnt) \ - cpu_to_le16(PD_HEADER((type), (pwr), (data), (rev), (id), (cnt), (0))) - -+#define PD_HEADER_EXT_LE(type, pwr, data, rev, id, cnt) \ -+ cpu_to_le16(PD_HEADER((type), (pwr), (data), (rev), (id), (cnt), (1))) -+ - static inline unsigned int pd_header_cnt(u16 header) - { - return (header >> PD_HEADER_CNT_SHIFT) & PD_HEADER_CNT_MASK; -@@ -219,6 +222,25 @@ static inline u8 count_chunked_data_objs(u32 size) - return ((size / 4) + (size % 4 ? 1 : 0)); - } - -+/** -+ * batt_cap_ext_msg - Battery capability extended PD message -+ * @vid: Battery Vendor ID (assigned by USB-IF) -+ * @pid: Battery Product ID (assigned by battery or device vendor) -+ * @batt_design_cap: Battery design capacity in 0.1Wh -+ * @batt_last_chg_cap: Battery last full charge capacity in 0.1Wh -+ * @batt_type: Battery Type. bit0 when set indicates invalid battery reference. -+ * Rest of the bits are reserved. -+ */ -+struct batt_cap_ext_msg { -+ __le16 vid; -+ __le16 pid; -+ __le16 batt_design_cap; -+ __le16 batt_last_chg_cap; -+ u8 batt_type; -+} __packed; -+ -+#define BATT_CAP_BATT_TYPE_INVALID_REF BIT(0) -+ - /* Sink Caps Extended Data Block Version */ - #define SKEDB_VER_1_0 1 - -@@ -724,4 +746,33 @@ void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct devi - - #endif /* CONFIG_TYPEC */ - -+/* Battery Status Data Object */ -+#define BSDO_PRESENT_CAPACITY GENMASK(31, 16) -+#define BSDO_CHG_STATUS GENMASK(11, 10) -+#define BSDO_BATTERY_PRESENT BIT(9) -+#define BSDO_INVALID_BATTERY_REFERENCE BIT(8) -+ -+/* -+ * Battery Charge Status: Battery Charging Status Values as defined in -+ * "USB PD Spec Rev3.1 Ver1.8", "Table 6-46 Battery Status Data Object (BSDO)". -+ */ -+#define BSDO_BATTERY_INFO_CHARGING 0x0 -+#define BSDO_BATTERY_INFO_DISCHARGING 0x1 -+#define BSDO_BATTERY_INFO_IDLE 0x2 -+#define BSDO_BATTERY_INFO_RSVD 0x3 -+ -+/** -+ * BSDO() - Pack data into Battery Status Data Object format. -+ * @batt_charge: Battery's present state of charge in 0.1WH increment. -+ * @chg_status: Battery charge status. -+ * @batt_present: Indicates that battery is present/attached when set else absent when unset. -+ * @invalid_ref: Indicates that an invalid battery reference was made in the Get_Battery_Status -+ * request. -+ */ -+#define BSDO(batt_charge, chg_status, batt_present, invalid_ref) \ -+ ((FIELD_PREP(BSDO_PRESENT_CAPACITY, batt_charge)) | \ -+ (FIELD_PREP(BSDO_CHG_STATUS, chg_status)) | \ -+ ((batt_present) ? BSDO_BATTERY_PRESENT : 0) | \ -+ ((invalid_ref) ? BSDO_INVALID_BATTERY_REFERENCE : 0)) -+ - #endif /* __LINUX_USB_PD_H */ -diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h ---- a/include/linux/usb/typec.h -+++ b/include/linux/usb/typec.h -@@ -337,6 +337,7 @@ void typec_unregister_cable(struct typec_cable *cable); - struct typec_cable *typec_cable_get(struct typec_port *port); - void typec_cable_put(struct typec_cable *cable); - int typec_cable_is_active(struct typec_cable *cable); -+bool typec_cable_altmode_unsupported(struct typec_altmode *alt); - - struct typec_plug *typec_register_plug(struct typec_cable *cable, - struct typec_plug_desc *desc); -diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h ---- a/include/uapi/linux/usb/functionfs.h -+++ b/include/uapi/linux/usb/functionfs.h -@@ -25,6 +25,7 @@ enum functionfs_flags { - FUNCTIONFS_EVENTFD = 32, - FUNCTIONFS_ALL_CTRL_RECIP = 64, - FUNCTIONFS_CONFIG0_SETUP = 128, -+ FUNCTIONFS_RW_PROXY_EPS = 256, - }; - - /* Descriptor of an non-audio endpoint */ -@@ -414,4 +415,27 @@ struct usb_functionfs_event { - #define FUNCTIONFS_DMABUF_TRANSFER _IOW('g', 133, \ - struct usb_ffs_dmabuf_transfer_req) - -+/* -+ * Enable or disable automatic zero-length packet (ZLP) appending for the -+ * endpoint. The argument is a pointer to a __u32: 0 to disable, non-zero to -+ * enable. -+ * -+ * When enabled, the kernel will automatically append a ZLP at the end of -+ * a transfer if the payload length is an exact multiple of the endpoint's -+ * max packet size. -+ * -+ * This is useful for compatibility with legacy protocols which require -+ * automatic ZLP appending to data written from userspace. -+ * -+ * This ioctl can only be used on IN endpoints. It can be called at any time -+ * after the FunctionFS instance is active, even before the host has connected -+ * or enabled the endpoint. -+ * -+ * Returns zero on success, or a negative errno value on error: -+ * -ENODEV: The FunctionFS instance is not active. -+ * -EINVAL: The endpoint is not an IN endpoint. -+ * -EFAULT: Invalid user space pointer for the argument. -+ */ -+#define FUNCTIONFS_ENDPOINT_ENABLE_ZLP _IOW('g', 134, __u32) -+ - #endif /* _UAPI__LINUX_FUNCTIONFS_H__ */ -diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs ---- a/rust/kernel/usb.rs -+++ b/rust/kernel/usb.rs -@@ -24,11 +24,8 @@ - }; - use core::{ - marker::PhantomData, -- mem::{ -- offset_of, -- MaybeUninit, // -- }, -- ptr::NonNull, -+ mem::offset_of, -+ ptr::NonNull, // - }; - - /// An adapter for the registration of USB drivers. -@@ -130,8 +127,7 @@ pub const fn from_id(vendor: u16, product: u16) -> Self { - match_flags: bindings::USB_DEVICE_ID_MATCH_DEVICE as u16, - idVendor: vendor, - idProduct: product, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - -@@ -143,8 +139,7 @@ pub const fn from_device_ver(vendor: u16, product: u16, bcd_lo: u16, bcd_hi: u16 - idProduct: product, - bcdDevice_lo: bcd_lo, - bcdDevice_hi: bcd_hi, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - -@@ -155,8 +150,7 @@ pub const fn from_device_info(class: u8, subclass: u8, protocol: u8) -> Self { - bDeviceClass: class, - bDeviceSubClass: subclass, - bDeviceProtocol: protocol, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - -@@ -167,8 +161,7 @@ pub const fn from_interface_info(class: u8, subclass: u8, protocol: u8) -> Self - bInterfaceClass: class, - bInterfaceSubClass: subclass, - bInterfaceProtocol: protocol, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - -@@ -180,8 +173,7 @@ pub const fn from_device_interface_class(vendor: u16, product: u16, class: u8) - - idVendor: vendor, - idProduct: product, - bInterfaceClass: class, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - -@@ -193,8 +185,7 @@ pub const fn from_device_interface_protocol(vendor: u16, product: u16, protocol: - idVendor: vendor, - idProduct: product, - bInterfaceProtocol: protocol, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - -@@ -206,8 +197,7 @@ pub const fn from_device_interface_number(vendor: u16, product: u16, number: u8) - idVendor: vendor, - idProduct: product, - bInterfaceNumber: number, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - -@@ -227,8 +217,7 @@ pub const fn from_device_and_interface_info( - bInterfaceClass: class, - bInterfaceSubClass: subclass, - bInterfaceProtocol: protocol, -- // SAFETY: It is safe to use all zeroes for the other fields of `usb_device_id`. -- ..unsafe { MaybeUninit::zeroed().assume_init() } -+ ..pin_init::zeroed() - }) - } - } -@@ -393,6 +382,7 @@ fn as_ref(&self) -> &Device { - - // SAFETY: Instances of `Interface` are always reference-counted. - unsafe impl AlwaysRefCounted for Interface { -+ #[inline] - fn inc_ref(&self) { - // SAFETY: The invariants of `Interface` guarantee that `self.as_raw()` - // returns a valid `struct usb_interface` pointer, for which we will -@@ -400,6 +390,7 @@ fn inc_ref(&self) { - unsafe { bindings::usb_get_intf(self.as_raw()) }; - } - -+ #[inline] - unsafe fn dec_ref(obj: NonNull) { - // SAFETY: The safety requirements guarantee that the refcount is non-zero. - unsafe { bindings::usb_put_intf(obj.cast().as_ptr()) } -@@ -444,6 +435,7 @@ fn as_raw(&self) -> *mut bindings::usb_device { - - // SAFETY: Instances of `Device` are always reference-counted. - unsafe impl AlwaysRefCounted for Device { -+ #[inline] - fn inc_ref(&self) { - // SAFETY: The invariants of `Device` guarantee that `self.as_raw()` - // returns a valid `struct usb_device` pointer, for which we will -@@ -451,6 +443,7 @@ fn inc_ref(&self) { - unsafe { bindings::usb_get_dev(self.as_raw()) }; - } - -+ #[inline] - unsafe fn dec_ref(obj: NonNull) { - // SAFETY: The safety requirements guarantee that the refcount is non-zero. - unsafe { bindings::usb_put_dev(obj.cast().as_ptr()) } diff --git a/kernel/0603-usb-updates.patch.sig b/kernel/0603-usb-updates.patch.sig deleted file mode 100644 index a76936f..0000000 Binary files a/kernel/0603-usb-updates.patch.sig and /dev/null differ diff --git a/kernel/0604-xhci-fixes.patch b/kernel/0604-xhci-fixes.patch deleted file mode 100644 index 8545f24..0000000 --- a/kernel/0604-xhci-fixes.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c ---- a/drivers/usb/host/xhci-mem.c -+++ b/drivers/usb/host/xhci-mem.c -@@ -2301,7 +2301,7 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags) - if (!segs) - segs = ERST_DEFAULT_SEGS; - -- max_segs = FIELD_GET(HCS_ERST_MAX, xhci->hcs_params2) << 2; -+ max_segs = BIT(FIELD_GET(HCS_ERST_MAX, xhci->hcs_params2)); - segs = min(segs, max_segs); - - ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); -diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c ---- a/drivers/usb/host/xhci-ring.c -+++ b/drivers/usb/host/xhci-ring.c -@@ -4328,11 +4328,16 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, - check_interval(urb, ep_ctx); - - /* -- * Check if this starts the isoc data flow. Relies on hw setting ep ctx -- * state after doorbell ring. Consider adding list_empty(td_list) check -+ * Schedule the URB discontiguously if all previous URBs have completed. -+ * XXX core can't tell if completions are pending but not running yet. - */ -- if (GET_EP_CTX_STATE(ep_ctx) != EP_STATE_RUNNING) -+ if (list_empty(&ep_ring->td_list) && -+ !hcd_periodic_completion_in_progress(xhci_to_hcd(xhci), urb->ep)) { -+ if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_RUNNING) -+ xhci_dbg(xhci, "Unexpected running ring at isoc stream start, uframe: %d\n", -+ xep->next_uframe); - xep->next_uframe = -1; -+ } - - return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); - } diff --git a/kernel/0604-xhci-fixes.patch.sig b/kernel/0604-xhci-fixes.patch.sig deleted file mode 100644 index 7d0570f..0000000 Binary files a/kernel/0604-xhci-fixes.patch.sig and /dev/null differ diff --git a/kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch b/kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch deleted file mode 100644 index a0b7740..0000000 --- a/kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch +++ /dev/null @@ -1,186 +0,0 @@ -diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -909,6 +909,10 @@ int tb_domain_init(void) - { - int ret; - -+ ret = tb_pci_rescan_init(); -+ if (ret) -+ return ret; -+ - tb_configfs_init(); - tb_debugfs_init(); - tb_acpi_init(); -@@ -927,6 +931,7 @@ err_xdomain: - err_acpi: - tb_acpi_exit(); - tb_debugfs_exit(); -+ tb_pci_rescan_exit(); - - return ret; - } -@@ -940,4 +945,5 @@ void tb_domain_exit(void) - tb_acpi_exit(); - tb_debugfs_exit(); - tb_configfs_exit(); -+ tb_pci_rescan_exit(); - } -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -9,7 +9,9 @@ - #include - #include - #include -+#include - #include -+#include - #include - - #include "tb.h" -@@ -18,6 +20,7 @@ - - #define TB_TIMEOUT 100 /* ms */ - #define TB_RELEASE_BW_TIMEOUT 10000 /* ms */ -+#define TB_PCI_RESCAN_DELAY 300 /* ms */ - - /* - * How many time bandwidth allocation request from graphics driver is -@@ -49,6 +52,13 @@ MODULE_PARM_DESC(asym_threshold, - "threshold (Mb/s) when to Gen 4 switch link symmetry. 0 disables. (default: " - __MODULE_STRING(TB_ASYM_THRESHOLD) ")"); - -+struct tb_pci_rescan { -+ struct delayed_work work; -+ struct kref kref; -+ struct pci_bus *bus; -+ bool stopped; -+}; -+ - /** - * struct tb_cm - Simple Thunderbolt connection manager - * @tunnel_list: List of active tunnels -@@ -67,8 +77,11 @@ struct tb_cm { - bool hotplug_active; - struct delayed_work remove_work; - struct tb_bandwidth_group groups[MAX_GROUPS]; -+ struct tb_pci_rescan *pci_rescan; - }; - -+static struct workqueue_struct *tb_pci_rescan_wq; -+ - static inline struct tb *tcm_to_tb(struct tb_cm *tcm) - { - return ((void *)tcm - sizeof(struct tb)); -@@ -2282,6 +2295,82 @@ static int tb_disconnect_pci(struct tb *tb, struct tb_switch *sw) - return 0; - } - -+static void tb_pci_rescan_release(struct kref *kref) -+{ -+ struct tb_pci_rescan *rescan = container_of(kref, typeof(*rescan), kref); -+ -+ put_device(&rescan->bus->dev); -+ kfree(rescan); -+} -+ -+static void tb_pci_rescan_work_fn(struct work_struct *work) -+{ -+ struct tb_pci_rescan *rescan = -+ container_of(to_delayed_work(work), typeof(*rescan), work); -+ -+ pci_lock_rescan_remove(); -+ if (!READ_ONCE(rescan->stopped)) -+ pci_rescan_bus(rescan->bus); -+ pci_unlock_rescan_remove(); -+ kref_put(&rescan->kref, tb_pci_rescan_release); -+} -+ -+static void tb_pci_rescan_schedule(struct tb *tb) -+{ -+ struct tb_cm *tcm = tb_priv(tb); -+ struct tb_pci_rescan *rescan = tcm->pci_rescan; -+ -+ if (!rescan) { -+ struct pci_bus *bus; -+ -+ if (!dev_is_pci(tb->nhi->dev)) -+ return; -+ bus = to_pci_dev(tb->nhi->dev)->bus; -+ if (bus->parent) -+ bus = bus->parent; -+ -+ rescan = kzalloc_obj(*rescan); -+ if (!rescan) -+ return; -+ INIT_DELAYED_WORK(&rescan->work, tb_pci_rescan_work_fn); -+ kref_init(&rescan->kref); -+ get_device(&bus->dev); -+ rescan->bus = bus; -+ tcm->pci_rescan = rescan; -+ } -+ -+ kref_get(&rescan->kref); -+ if (mod_delayed_work(tb_pci_rescan_wq, &rescan->work, -+ msecs_to_jiffies(TB_PCI_RESCAN_DELAY))) -+ kref_put(&rescan->kref, tb_pci_rescan_release); -+} -+ -+static void tb_pci_rescan_stop(struct tb_cm *tcm) -+{ -+ struct tb_pci_rescan *rescan = tcm->pci_rescan; -+ -+ if (!rescan) -+ return; -+ -+ WRITE_ONCE(rescan->stopped, true); -+ if (cancel_delayed_work(&rescan->work)) -+ kref_put(&rescan->kref, tb_pci_rescan_release); -+ kref_put(&rescan->kref, tb_pci_rescan_release); -+ tcm->pci_rescan = NULL; -+} -+ -+int tb_pci_rescan_init(void) -+{ -+ tb_pci_rescan_wq = alloc_workqueue("thunderbolt_pci_rescan", -+ WQ_FREEZABLE | WQ_UNBOUND, 0); -+ return tb_pci_rescan_wq ? 0 : -ENOMEM; -+} -+ -+void tb_pci_rescan_exit(void) -+{ -+ destroy_workqueue(tb_pci_rescan_wq); -+} -+ - static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw) - { - struct tb_port *up, *down, *port; -@@ -2323,6 +2412,7 @@ static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw) - tb_sw_warn(sw, "failed to connect xHCI\n"); - - list_add_tail(&tunnel->list, &tcm->tunnel_list); -+ tb_pci_rescan_schedule(tb); - return 0; - } - -@@ -2957,6 +3047,7 @@ static void tb_stop(struct tb *tb) - struct tb_tunnel *n; - - cancel_delayed_work(&tcm->remove_work); -+ tb_pci_rescan_stop(tcm); - /* tunnels are only present after everything has been initialized */ - list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) { - /* -diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -759,6 +759,8 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer, - - struct tb *icm_probe(struct tb_nhi *nhi); - struct tb *tb_probe(struct tb_nhi *nhi); -+int tb_pci_rescan_init(void); -+void tb_pci_rescan_exit(void); - - extern const struct device_type tb_domain_type; - extern const struct device_type tb_retimer_type; diff --git a/kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch.sig b/kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch.sig deleted file mode 100644 index 68db430..0000000 Binary files a/kernel/0605-thunderbolt-pcie-rescan-after-tunnel.patch.sig and /dev/null differ diff --git a/kernel/0606-thunderbolt-fixes-2.patch b/kernel/0606-thunderbolt-fixes-2.patch deleted file mode 100644 index 0d85afa..0000000 --- a/kernel/0606-thunderbolt-fixes-2.patch +++ /dev/null @@ -1,239 +0,0 @@ -diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c ---- a/drivers/thunderbolt/domain.c -+++ b/drivers/thunderbolt/domain.c -@@ -788,21 +788,6 @@ int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, - transmit_ring, receive_path, receive_ring); - } - --static void tb_domain_reset_interface(struct tb *tb) --{ -- struct tb_nhi *nhi = tb->nhi; -- -- if (!nhi->ops->reset_interface) -- return; -- -- guard(mutex)(&tb->lock); -- -- /* The reset clears the ring state so stop the control channel */ -- tb_ctl_stop(tb->ctl); -- nhi->ops->reset_interface(nhi); -- tb_ctl_start(tb->ctl); --} -- - /** - * tb_domain_disconnect_xdomain_paths() - Disable DMA paths for XDomain - * @tb: Domain disabling the DMA paths -@@ -825,20 +810,11 @@ int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd, - int transmit_path, int transmit_ring, - int receive_path, int receive_ring) - { -- int ret; -- - if (!tb->cm_ops->disconnect_xdomain_paths) - return -ENOTSUPP; - -- ret = tb->cm_ops->disconnect_xdomain_paths(tb, xd, transmit_path, -+ return tb->cm_ops->disconnect_xdomain_paths(tb, xd, transmit_path, - transmit_ring, receive_path, receive_ring); -- if (ret) -- return ret; -- -- if (tb->nhi->quirks & QUIRK_RESET_DMA_ON_TEARDOWN) -- tb_domain_reset_interface(tb); -- -- return 0; - } - - static int disconnect_xdomain(struct device *dev, void *data) -diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c ---- a/drivers/thunderbolt/nhi.c -+++ b/drivers/thunderbolt/nhi.c -@@ -1180,32 +1180,6 @@ static void nhi_reset(struct tb_nhi *nhi) - dev_warn(nhi->dev, "timeout resetting host router\n"); - } - --/** -- * nhi_reset_interface() - Reset the host interface -- * @nhi: Host interface to reset -- * -- * Brings the registers in the memory BAR back to their default state and -- * clears the End-to-End Flow Control state. The caller is responsible for -- * stopping the control channel over the reset because it clears the ring -- * state as well. -- */ --void nhi_reset_interface(struct tb_nhi *nhi) --{ -- u32 val; -- -- val = ioread32(nhi->iobase + REG_CAPS); -- /* Only v1 host interfaces implement the reset */ -- if (FIELD_GET(REG_CAPS_VERSION_MASK, val) >= REG_CAPS_VERSION_2) -- return; -- -- dev_dbg(nhi->dev, "issuing host interface reset\n"); -- -- iowrite32(REG_HOST_INTERFACE_RESET_RST, -- nhi->iobase + REG_HOST_INTERFACE_RESET); -- /* Wait for tHIReset (10 ms) to complete */ -- usleep_range(10000, 20000); --} -- - static struct tb *nhi_select_cm(struct tb_nhi *nhi) - { - struct tb *tb; -diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h ---- a/drivers/thunderbolt/nhi.h -+++ b/drivers/thunderbolt/nhi.h -@@ -36,8 +36,6 @@ irqreturn_t nhi_msi(int irq, void *data); - irqreturn_t ring_msix(int irq, void *data); - int nhi_probe(struct tb_nhi *nhi); - void nhi_shutdown(struct tb_nhi *nhi); --void nhi_reset_interface(struct tb_nhi *nhi); -- - extern const struct dev_pm_ops nhi_pm_ops; - - /** -@@ -54,7 +52,6 @@ extern const struct dev_pm_ops nhi_pm_ops; - * @release_ring_irq: NHI specific interrupt release hook - * @is_present: Whether the device is currently present on the parent bus - * @init_interrupts: NHI specific interrupt initialization hook -- * @reset_interface: Resets the host interface - */ - struct tb_nhi_ops { - int (*init)(struct tb_nhi *nhi); -@@ -69,7 +66,6 @@ struct tb_nhi_ops { - void (*release_ring_irq)(struct tb_ring *ring); - bool (*is_present)(struct tb_nhi *nhi); - int (*init_interrupts)(struct tb_nhi *nhi); -- void (*reset_interface)(struct tb_nhi *nhi); - }; - - /* -@@ -120,24 +116,11 @@ struct tb_nhi_ops { - #define PCI_DEVICE_ID_INTEL_PTL_P_NHI0 0xe433 - #define PCI_DEVICE_ID_INTEL_PTL_P_NHI1 0xe434 - --#define PCI_DEVICE_ID_AMD_1AH_M60H_NHI0 0x1120 --#define PCI_DEVICE_ID_AMD_1AH_M60H_NHI1 0x1121 --#define PCI_DEVICE_ID_AMD_1AH_M68H_NHI0 0x113b --#define PCI_DEVICE_ID_AMD_1AH_M68H_NHI1 0x113c --#define PCI_DEVICE_ID_AMD_1AH_M80H_NHI0 0x1155 --#define PCI_DEVICE_ID_AMD_1AH_M80H_NHI1 0x1158 --#define PCI_DEVICE_ID_AMD_1AH_M80H_NHI2 0x1159 --#define PCI_DEVICE_ID_AMD_1AH_M24H_NHI0 0x151c --#define PCI_DEVICE_ID_AMD_1AH_M24H_NHI1 0x151d --#define PCI_DEVICE_ID_AMD_1AH_M70H_NHI0 0x158d --#define PCI_DEVICE_ID_AMD_1AH_M70H_NHI1 0x158e -- - #define PCI_CLASS_SERIAL_USB_USB4 0x0c0340 - - /* Host interface quirks */ --#define QUIRK_AUTO_CLEAR_INT BIT(0) --#define QUIRK_E2E BIT(1) --#define QUIRK_RESET_DMA_ON_TEARDOWN BIT(2) -+#define QUIRK_AUTO_CLEAR_INT BIT(0) -+#define QUIRK_E2E BIT(1) - - /* - * Minimal number of vectors when we use MSI-X. Two for control channel -diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h ---- a/drivers/thunderbolt/nhi_regs.h -+++ b/drivers/thunderbolt/nhi_regs.h -@@ -115,10 +115,6 @@ struct ring_desc { - #define REG_CAPS_VERSION_MASK GENMASK(23, 16) - #define REG_CAPS_VERSION_2 0x40 - --/* Host Interface Reset - resets TX/RX rings and E2E flow control counters */ --#define REG_HOST_INTERFACE_RESET 0x39858 --#define REG_HOST_INTERFACE_RESET_RST BIT(0) -- - #define REG_DMA_MISC 0x39864 - #define REG_DMA_MISC_INT_AUTO_CLEAR BIT(2) - #define REG_DMA_MISC_DISABLE_AUTO_CLEAR BIT(17) -diff --git a/drivers/thunderbolt/pci.c b/drivers/thunderbolt/pci.c ---- a/drivers/thunderbolt/pci.c -+++ b/drivers/thunderbolt/pci.c -@@ -62,27 +62,6 @@ static void nhi_pci_check_quirks(struct tb_nhi_pci *nhi_pci) - nhi->quirks |= QUIRK_E2E; - break; - } -- } else if (pdev->vendor == PCI_VENDOR_ID_AMD) { -- switch (pdev->device) { -- case PCI_DEVICE_ID_AMD_1AH_M60H_NHI0: -- case PCI_DEVICE_ID_AMD_1AH_M60H_NHI1: -- case PCI_DEVICE_ID_AMD_1AH_M68H_NHI0: -- case PCI_DEVICE_ID_AMD_1AH_M68H_NHI1: -- case PCI_DEVICE_ID_AMD_1AH_M80H_NHI0: -- case PCI_DEVICE_ID_AMD_1AH_M80H_NHI1: -- case PCI_DEVICE_ID_AMD_1AH_M80H_NHI2: -- case PCI_DEVICE_ID_AMD_1AH_M24H_NHI0: -- case PCI_DEVICE_ID_AMD_1AH_M24H_NHI1: -- case PCI_DEVICE_ID_AMD_1AH_M70H_NHI0: -- case PCI_DEVICE_ID_AMD_1AH_M70H_NHI1: -- /* -- * These AMD hosts may hang the Tx ring when the -- * DMA paths are torn down so they need the host -- * interface reset after each teardown. -- */ -- nhi->quirks |= QUIRK_RESET_DMA_ON_TEARDOWN; -- break; -- } - } - } - -@@ -279,7 +258,6 @@ static const struct tb_nhi_ops pci_nhi_default_ops = { - .shutdown = nhi_pci_release_irq, - .is_present = nhi_pci_is_present, - .init_interrupts = nhi_pci_init_msi, -- .reset_interface = nhi_reset_interface, - }; - - /* Ice Lake specific NHI operations */ -@@ -463,7 +441,6 @@ static const struct tb_nhi_ops icl_nhi_ops = { - .release_ring_irq = nhi_pci_ring_release_msix, - .is_present = nhi_pci_is_present, - .init_interrupts = nhi_pci_init_msi, -- .reset_interface = nhi_reset_interface, - }; - - static int nhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c ---- a/drivers/thunderbolt/quirks.c -+++ b/drivers/thunderbolt/quirks.c -@@ -99,6 +99,9 @@ static const struct tb_quirk tb_quirks[] = { - quirk_usb3_maximum_bandwidth }, - { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HUB_40G_BRIDGE, 0x0000, 0x0000, - quirk_usb3_maximum_bandwidth }, -+ /* CLx is unstable on the Anker Prime TB5 dock (DROM 01ea:83b5) */ -+ { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HUB_80G_BRIDGE, 0x01ea, 0x83b5, -+ quirk_clx_disable }, - /* - * Block Runtime PM in DP redrive mode for Intel Barlow Ridge host - * controllers. -diff --git a/drivers/thunderbolt/stream.c b/drivers/thunderbolt/stream.c ---- a/drivers/thunderbolt/stream.c -+++ b/drivers/thunderbolt/stream.c -@@ -980,6 +980,9 @@ static int tbstream_dev_fops_open(struct inode *inode, struct file *file) - } - - mutex_unlock(&sdev->lock); -+ -+ /* Stream handles IOCB_NOWAIT just fine */ -+ file->f_mode |= FMODE_NOWAIT; - return 0; - - err_unlock: -diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c ---- a/drivers/thunderbolt/xdomain.c -+++ b/drivers/thunderbolt/xdomain.c -@@ -377,6 +377,10 @@ static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route, - - len += sizeof(res->hdr.xd_hdr) / 4; - len -= sizeof(*res) / 4; -+ if (len > TB_XDP_PROPERTIES_MAX_DATA_LENGTH) { -+ ret = -EINVAL; -+ goto err; -+ } - - if (res->offset != req.offset) { - ret = -EINVAL; diff --git a/kernel/0606-thunderbolt-fixes-2.patch.sig b/kernel/0606-thunderbolt-fixes-2.patch.sig deleted file mode 100644 index 4a16c2a..0000000 Binary files a/kernel/0606-thunderbolt-fixes-2.patch.sig and /dev/null differ diff --git a/kernel/0607-usb-fixes.patch b/kernel/0607-usb-fixes.patch deleted file mode 100644 index 2e3ea13..0000000 --- a/kernel/0607-usb-fixes.patch +++ /dev/null @@ -1,1673 +0,0 @@ -diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c ---- a/drivers/usb/cdns3/cdns3-gadget.c -+++ b/drivers/usb/cdns3/cdns3-gadget.c -@@ -3269,6 +3269,10 @@ static void cdns3_gadget_exit(struct cdns *cdns) - usb_del_gadget(&priv_dev->gadget); - devm_free_irq(cdns->dev, cdns->dev_irq, priv_dev); - -+ /* The works can still be queued until the IRQ is freed. */ -+ cancel_work_sync(&priv_dev->pending_status_wq); -+ cancel_work_sync(&priv_dev->aligned_buf_wq); -+ - cdns3_free_all_eps(priv_dev); - - while (!list_empty(&priv_dev->aligned_buf_list)) { -diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c ---- a/drivers/usb/cdns3/cdns3-pci-wrap.c -+++ b/drivers/usb/cdns3/cdns3-pci-wrap.c -@@ -96,6 +96,11 @@ static int cdns3_pci_probe(struct pci_dev *pdev, - - if (pci_is_enabled(func)) { - wrap = pci_get_drvdata(func); -+ if (!wrap) { -+ dev_err(&pdev->dev, -+ "second function not initialized, retrying\n"); -+ return -EPROBE_DEFER; -+ } - } else { - wrap = kzalloc_obj(*wrap); - if (!wrap) -diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c ---- a/drivers/usb/chipidea/ci_hdrc_tegra.c -+++ b/drivers/usb/chipidea/ci_hdrc_tegra.c -@@ -306,8 +306,10 @@ static int tegra_usb_probe(struct platform_device *pdev) - - pm_runtime_enable(&pdev->dev); - err = pm_runtime_resume_and_get(&pdev->dev); -- if (err) -+ if (err) { -+ pm_runtime_disable(&pdev->dev); - return err; -+ } - - if (device_property_present(&pdev->dev, "nvidia,needs-double-reset")) - usb->needs_double_reset = true; -diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c ---- a/drivers/usb/class/cdc-acm.c -+++ b/drivers/usb/class/cdc-acm.c -@@ -331,7 +331,6 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) - - spin_lock_irqsave(&acm->read_lock, flags); - acm->ctrlin = newctrl; -- acm->oldcount = acm->iocount; - - if (difference & USB_CDC_SERIAL_STATE_DSR) - acm->iocount.dsr++; -@@ -788,6 +787,9 @@ static void acm_port_shutdown(struct tty_port *port) - usb_autopm_put_interface_async(acm->control); - } - -+ if (acm->disconnected) -+ return; -+ - acm_unpoison_urbs(acm); - - if (acm->quirks & ALWAYS_POLL_CTRL) { -@@ -1027,11 +1029,16 @@ static int wait_serial_change(struct acm *acm, unsigned long arg) - DECLARE_WAITQUEUE(wait, current); - struct async_icount old, new; - -- do { -+ spin_lock_irq(&acm->read_lock); -+ old = acm->iocount; -+ spin_unlock_irq(&acm->read_lock); -+ -+ add_wait_queue(&acm->wioctl, &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ - spin_lock_irq(&acm->read_lock); -- old = acm->oldcount; - new = acm->iocount; -- acm->oldcount = new; - spin_unlock_irq(&acm->read_lock); - - if ((arg & TIOCM_DSR) && -@@ -1044,22 +1051,20 @@ static int wait_serial_change(struct acm *acm, unsigned long arg) - old.rng != new.rng) - break; - -- add_wait_queue(&acm->wioctl, &wait); -- set_current_state(TASK_INTERRUPTIBLE); -- schedule(); -- remove_wait_queue(&acm->wioctl, &wait); - if (acm->disconnected) { -- if (arg & TIOCM_CD) -- break; -- else -- rv = -ENODEV; -- } else { -- if (signal_pending(current)) -- rv = -ERESTARTSYS; -+ rv = -ENODEV; -+ break; - } -- } while (!rv); - -- -+ schedule(); -+ -+ if (signal_pending(current)) { -+ rv = -ERESTARTSYS; -+ break; -+ } -+ } -+ __set_current_state(TASK_RUNNING); -+ remove_wait_queue(&acm->wioctl, &wait); - - return rv; - } -diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h ---- a/drivers/usb/class/cdc-acm.h -+++ b/drivers/usb/class/cdc-acm.h -@@ -90,7 +90,6 @@ struct acm { - unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ - unsigned int ctrlout; /* output control lines (DTR, RTS) */ - struct async_icount iocount; /* counters for control line changes */ -- struct async_icount oldcount; /* for comparison of counter */ - wait_queue_head_t wioctl; /* for ioctl */ - unsigned int writesize; /* max packet size for the output bulk endpoint */ - unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -73,8 +73,11 @@ - /* - * Give SS hubs 200ms time after wake to train downstream links before - * assuming no port activity and allowing hub to runtime suspend back. -+ * Root hubs have no upstream hub whose wake propagation needs to be -+ * accounted for, so they need less time, use 120ms for them. - */ - #define USB_SS_PORT_U0_WAKE_TIME 200 /* ms */ -+#define USB_SS_RH_PORT_U0_WAKE_TIME 120 /* ms */ - - /* Protect struct usb_device->state and ->children members - * Note: Both are also protected by ->dev.sem, except that ->state can -@@ -1358,7 +1361,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) - - queue_delayed_work(system_power_efficient_wq, - &hub->post_resume_work, -- msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); -+ msecs_to_jiffies(hdev->parent ? -+ USB_SS_PORT_U0_WAKE_TIME : -+ USB_SS_RH_PORT_U0_WAKE_TIME)); - return; - } - -diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c ---- a/drivers/usb/core/message.c -+++ b/drivers/usb/core/message.c -@@ -1337,7 +1337,8 @@ static void remove_intf_ep_devs(struct usb_interface *intf) - * - * Disables the endpoint for URB submission and nukes all pending URBs. - * If @reset_hardware is set then also deallocates hcd/hardware state -- * for the endpoint. -+ * for the endpoint (clearing both ep_in and ep_out pointers for -+ * bidirectional non-ep0 control endpoints). - */ - void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, - bool reset_hardware) -@@ -1358,6 +1359,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, - dev->ep_in[epnum] = NULL; - } - if (ep) { -+ if (reset_hardware && epnum != 0 && -+ usb_endpoint_xfer_control(&ep->desc)) { -+ dev->ep_out[epnum] = NULL; -+ dev->ep_in[epnum] = NULL; -+ } - ep->enabled = 0; - usb_hcd_flush_endpoint(dev, ep); - if (reset_hardware) -diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c ---- a/drivers/usb/dwc2/hcd.c -+++ b/drivers/usb/dwc2/hcd.c -@@ -5082,14 +5082,13 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) - } - - cancel_work_sync(&hsotg->phy_reset_work); -- -- timer_delete(&hsotg->wkp_timer); - } - - static void dwc2_hcd_release(struct dwc2_hsotg *hsotg) - { - /* Turn off all host-specific interrupts */ - dwc2_disable_host_interrupts(hsotg); -+ timer_shutdown_sync(&hsotg->wkp_timer); - - dwc2_hcd_free(hsotg); - } -diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h ---- a/drivers/usb/dwc3/core.h -+++ b/drivers/usb/dwc3/core.h -@@ -49,6 +49,7 @@ - #define DWC3_ENDPOINTS_NUM 32 - #define DWC3_XHCI_RESOURCES_NUM 2 - #define DWC3_ISOC_MAX_RETRIES 5 -+#define DWC3_ERR_RECOVERY_MAX 3 - - #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ - #define DWC3_EVENT_BUFFERS_SIZE 4096 -@@ -841,6 +842,12 @@ enum dwc3_link_state { - DWC3_LINK_STATE_MASK = 0x0f, - }; - -+enum dwc3_err_state { -+ DWC3_ERR_NONE = 0, -+ DWC3_ERR_RECOVERY, -+ DWC3_ERR_UNRECOVERABLE, -+}; -+ - /* TRB Length, PCM and Status */ - #define DWC3_TRB_SIZE_MASK (0x00ffffff) - #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) -@@ -1004,6 +1011,7 @@ struct dwc3_glue_ops { - /** - * struct dwc3 - representation of our controller - * @drd_work: workqueue used for role swapping -+ * @err_recovery_work: workqueue used for controller error recovery - * @ep0_trb: trb which is used for the ctrl_req - * @bounce: address of bounce buffer - * @setup_buf: used while precessing STD USB requests -@@ -1013,6 +1021,7 @@ struct dwc3_glue_ops { - * @ep0_in_setup: one control transfer is completed and enter setup phase - * @lock: for synchronizing - * @mutex: for mode switching -+ * @connect_mutex: for the pull-up and err_recovery_work - * @dev: pointer to our struct device - * @sysdev: pointer to the DMA-capable device - * @xhci: pointer to our xHCI child -@@ -1079,6 +1088,9 @@ struct dwc3_glue_ops { - * @ep0_next_event: hold the next expected event - * @ep0state: state of endpoint zero - * @link_state: link state -+ * @err_state: current error recovery state. -+ * @err_recovery_count: number of consecutive error recovery attempts until -+ * confirmed healthy and reset to 0 on reset event. - * @speed: device speed (super, high, full, low) - * @hwparams: copy of hwparams registers - * @regset: debugfs pointer to regdump file -@@ -1189,6 +1201,7 @@ struct dwc3_glue_ops { - */ - struct dwc3 { - struct work_struct drd_work; -+ struct work_struct err_recovery_work; - struct dwc3_trb *ep0_trb; - void *bounce; - u8 *setup_buf; -@@ -1203,6 +1216,9 @@ struct dwc3 { - /* mode switching lock */ - struct mutex mutex; - -+ /* serializes pull-up run/stop vs error recovery */ -+ struct mutex connect_mutex; -+ - struct device *dev; - struct device *sysdev; - -@@ -1332,6 +1348,9 @@ struct dwc3 { - enum dwc3_ep0_next ep0_next_event; - enum dwc3_ep0_state ep0state; - enum dwc3_link_state link_state; -+ enum dwc3_err_state err_state; -+ -+ u32 err_recovery_count; - - u16 u2sel; - u16 u2pel; -diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c ---- a/drivers/usb/dwc3/dwc3-am62.c -+++ b/drivers/usb/dwc3/dwc3-am62.c -@@ -299,6 +299,7 @@ static int dwc3_ti_probe(struct platform_device *pdev) - - err_pm_disable: - clk_disable_unprepare(am62->usb2_refclk); -+ pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - return ret; -diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c ---- a/drivers/usb/dwc3/ep0.c -+++ b/drivers/usb/dwc3/ep0.c -@@ -200,6 +200,11 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, - int ret; - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ ret = -ESHUTDOWN; -+ goto out; -+ } -+ - if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) { - dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", - dep->name); -@@ -271,6 +276,10 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) - int ret; - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -ESHUTDOWN; -+ } - ret = __dwc3_gadget_ep0_set_halt(ep, value); - spin_unlock_irqrestore(&dwc->lock, flags); - -diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c ---- a/drivers/usb/dwc3/gadget.c -+++ b/drivers/usb/dwc3/gadget.c -@@ -1149,6 +1149,10 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, - return 0; - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -ESHUTDOWN; -+ } - ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); - spin_unlock_irqrestore(&dwc->lock, flags); - -@@ -2060,6 +2064,10 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, - int ret; - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -ESHUTDOWN; -+ } - ret = __dwc3_gadget_ep_queue(dep, req); - spin_unlock_irqrestore(&dwc->lock, flags); - -@@ -2292,6 +2300,10 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) - int ret; - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -ESHUTDOWN; -+ } - ret = __dwc3_gadget_ep_set_halt(dep, value, false); - spin_unlock_irqrestore(&dwc->lock, flags); - -@@ -2306,6 +2318,10 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) - int ret; - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -ESHUTDOWN; -+ } - dep->flags |= DWC3_EP_WEDGE; - - if (dep->number == 0 || dep->number == 1) -@@ -2437,6 +2453,10 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) - } - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -ESHUTDOWN; -+ } - if (!dwc->gadget->wakeup_armed) { - dev_err(dwc->dev, "not armed for remote wakeup\n"); - spin_unlock_irqrestore(&dwc->lock, flags); -@@ -2464,6 +2484,10 @@ static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) - } - - spin_lock_irqsave(&dwc->lock, flags); -+ if (dwc->err_state != DWC3_ERR_NONE) { -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return -ESHUTDOWN; -+ } - /* - * If the link is in U3, signal for remote wakeup and wait for the - * link to transition to U0 before sending device notification. -@@ -2833,10 +2857,13 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) - - synchronize_irq(dwc->irq_gadget); - -+ /* Serialize against dwc3_err_recovery_work() */ -+ mutex_lock(&dwc->connect_mutex); - if (!is_on) - ret = dwc3_gadget_soft_disconnect(dwc); - else - ret = dwc3_gadget_soft_connect(dwc); -+ mutex_unlock(&dwc->connect_mutex); - - pm_runtime_put(dwc->dev); - -@@ -4153,6 +4180,10 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) - - dwc->suspended = false; - -+ /* The controller is recovered. */ -+ if (dwc->err_state == DWC3_ERR_NONE) -+ dwc->err_recovery_count = 0; -+ - /* - * Ideally, dwc3_reset_gadget() would trigger the function - * drivers to stop any active transfers through ep disable. -@@ -4640,6 +4671,12 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt) - return ret; - } - -+static void dwc3_schedule_err_recovery(struct dwc3 *dwc) -+{ -+ dwc->err_state = DWC3_ERR_RECOVERY; -+ schedule_work(&dwc->err_recovery_work); -+} -+ - static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) - { - struct dwc3 *dwc = evt->dwc; -@@ -4673,9 +4710,21 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) - return IRQ_NONE; - - if (count > evt->length) { -- dev_err_ratelimited(dwc->dev, "invalid count(%u) > evt->length(%u)\n", -+ dev_err(dwc->dev, "invalid count(%u) > evt->length(%u)\n", - count, evt->length); -- return IRQ_NONE; -+ /* -+ * This is a fatal error - the driver and controller are out of -+ * sync on which event has been consumed. Reinitializing the -+ * controller is required to recover. Write the bogus count back -+ * to GEVNTCOUNT to clear the IRQ source, consistent with the -+ * stale event clearing in dwc3_event_buffers_setup(), then -+ * schedule error recovery. -+ */ -+ spin_lock(&dwc->lock); -+ dwc3_schedule_err_recovery(dwc); -+ spin_unlock(&dwc->lock); -+ dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), count); -+ return IRQ_HANDLED; - } - - evt->count = count; -@@ -4735,6 +4784,57 @@ static void dwc_gadget_release(struct device *dev) - kfree(gadget); - } - -+static void dwc3_err_recovery_work(struct work_struct *work) -+{ -+ struct dwc3 *dwc = container_of(work, struct dwc3, err_recovery_work); -+ unsigned long flags; -+ int ret; -+ -+ /* serializes against dwc3_gadget_pullup() */ -+ mutex_lock(&dwc->connect_mutex); -+ -+ ret = dwc3_gadget_soft_disconnect(dwc); -+ -+ dwc3_disconnect_gadget_sleepable(dwc); -+ -+ if (ret) -+ goto err_unrecoverable; -+ -+ if (dwc->softconnect) { -+ u32 count; -+ /* -+ * Wait irq to finish before soft_connect resets evt->lpos and -+ * the event buffer registers to avoid racing with -+ * dwc3_process_event_buf(). -+ */ -+ synchronize_irq(dwc->irq_gadget); -+ -+ spin_lock_irqsave(&dwc->lock, flags); -+ count = ++dwc->err_recovery_count; -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ -+ if (count > DWC3_ERR_RECOVERY_MAX) -+ goto err_unrecoverable; -+ -+ ret = dwc3_gadget_soft_connect(dwc); -+ if (ret) -+ goto err_unrecoverable; -+ } -+ mutex_unlock(&dwc->connect_mutex); -+ -+ spin_lock_irqsave(&dwc->lock, flags); -+ dwc->err_state = DWC3_ERR_NONE; -+ spin_unlock_irqrestore(&dwc->lock, flags); -+ return; -+ -+err_unrecoverable: -+ dev_err(dwc->dev, "Unable to recover the controller\n"); -+ mutex_unlock(&dwc->connect_mutex); -+ spin_lock_irqsave(&dwc->lock, flags); -+ dwc->err_state = DWC3_ERR_UNRECOVERABLE; -+ spin_unlock_irqrestore(&dwc->lock, flags); -+} -+ - /** - * dwc3_gadget_init - initializes gadget related registers - * @dwc: pointer to our controller context structure -@@ -4778,6 +4878,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) - } - - init_completion(&dwc->ep0_in_setup); -+ INIT_WORK(&dwc->err_recovery_work, dwc3_err_recovery_work); -+ mutex_init(&dwc->connect_mutex); - dwc->gadget = kzalloc_obj(struct usb_gadget); - if (!dwc->gadget) { - ret = -ENOMEM; -@@ -4874,6 +4976,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc) - if (!dwc->gadget) - return; - -+ cancel_work_sync(&dwc->err_recovery_work); -+ mutex_destroy(&dwc->connect_mutex); - dwc3_enable_susphy(dwc, true); - usb_del_gadget(dwc->gadget); - dwc3_gadget_free_endpoints(dwc); -diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c ---- a/drivers/usb/gadget/function/f_fs.c -+++ b/drivers/usb/gadget/function/f_fs.c -@@ -1877,8 +1877,9 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, - break; - case FUNCTIONFS_ENDPOINT_DESC: - { -+ const struct usb_endpoint_descriptor *desc; -+ struct usb_endpoint_descriptor desc1; - int desc_idx; -- struct usb_endpoint_descriptor desc1, *desc; - - switch (epfile->ffs->gadget->speed) { - case USB_SPEED_SUPER: -@@ -1892,7 +1893,17 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, - desc_idx = 0; - } - -- desc = epfile->ep->descs[desc_idx]; -+ do { -+ desc = epfile->ep->descs[desc_idx]; -+ } while (!desc && --desc_idx >= 0); -+ -+ if (!desc) -+ desc = epfile->ep->ep->desc; -+ if (!desc) { -+ ret = -EINVAL; -+ break; -+ } -+ - memcpy(&desc1, desc, desc->bLength); - - spin_unlock_irq(&epfile->ffs->eps_lock); -diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c ---- a/drivers/usb/gadget/function/f_midi2.c -+++ b/drivers/usb/gadget/function/f_midi2.c -@@ -1633,8 +1633,8 @@ struct f_midi2_usb_config { - - /* MIDI 1.0 jacks */ - unsigned char jack_in, jack_out, jack_id; -- struct usb_midi_in_jack_descriptor jack_ins[MAX_CABLES]; -- struct usb_midi_out_jack_descriptor_1 jack_outs[MAX_CABLES]; -+ struct usb_midi_in_jack_descriptor jack_ins[MAX_CABLES * 2]; -+ struct usb_midi_out_jack_descriptor_1 jack_outs[MAX_CABLES * 2]; - }; - - static int append_config(struct f_midi2_usb_config *config, void *d) -diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c ---- a/drivers/usb/gadget/function/f_uac1_legacy.c -+++ b/drivers/usb/gadget/function/f_uac1_legacy.c -@@ -797,6 +797,9 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) - - static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value) - { -+ if (cmd >= ARRAY_SIZE(con->data)) -+ return -EINVAL; -+ - con->data[cmd] = value; - - return 0; -@@ -804,6 +807,9 @@ static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value) - - static int generic_get_cmd(struct usb_audio_control *con, u8 cmd) - { -+ if (cmd >= ARRAY_SIZE(con->data)) -+ return -EINVAL; -+ - return con->data[cmd]; - } - -diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c ---- a/drivers/usb/gadget/udc/aspeed-vhub/core.c -+++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c -@@ -267,6 +267,9 @@ static void ast_vhub_remove(struct platform_device *pdev) - for (i = 0; i < vhub->max_ports; i++) - ast_vhub_del_dev(&vhub->ports[i].dev); - -+ /* Final drain; the worker takes vhub->lock, so stay outside of it */ -+ cancel_work_sync(&vhub->wake_work); -+ - spin_lock_irqsave(&vhub->lock, flags); - - /* Mask & ack all interrupts */ -@@ -328,6 +331,7 @@ static int ast_vhub_probe(struct platform_device *pdev) - return -ENOMEM; - - spin_lock_init(&vhub->lock); -+ INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); - vhub->pdev = pdev; - vhub->port_irq_mask = GENMASK(VHUB_IRQ_DEV1_BIT + vhub->max_ports - 1, - VHUB_IRQ_DEV1_BIT); -diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c ---- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c -+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c -@@ -280,7 +280,7 @@ static int ast_vhub_udc_wakeup(struct usb_gadget* gadget) - int rc = -EINVAL; - - spin_lock_irqsave(&d->vhub->lock, flags); -- if (!d->wakeup_en) -+ if (!d->wakeup_en || !d->registered) - goto err; - - DDBG(d, "Device initiated wakeup\n"); -diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c ---- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c -+++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c -@@ -558,7 +558,7 @@ void ast_vhub_device_connect(struct ast_vhub *vhub, - ast_vhub_send_host_wakeup(vhub); - } - --static void ast_vhub_wake_work(struct work_struct *work) -+void ast_vhub_wake_work(struct work_struct *work) - { - struct ast_vhub *vhub = container_of(work, - struct ast_vhub, -@@ -588,6 +588,8 @@ static void ast_vhub_wake_work(struct work_struct *work) - - void ast_vhub_hub_wake_all(struct ast_vhub *vhub) - { -+ lockdep_assert_held(&vhub->lock); -+ - /* - * A device is trying to wake the world, because this - * can recurse into the device, we break the call chain -@@ -1076,7 +1078,6 @@ static int ast_vhub_init_desc(struct ast_vhub *vhub) - int ast_vhub_init_hub(struct ast_vhub *vhub) - { - vhub->speed = USB_SPEED_UNKNOWN; -- INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); - - return ast_vhub_init_desc(vhub); - } -diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h ---- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h -+++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h -@@ -547,6 +547,7 @@ void ast_vhub_hub_suspend(struct ast_vhub *vhub); - void ast_vhub_hub_resume(struct ast_vhub *vhub); - void ast_vhub_hub_reset(struct ast_vhub *vhub); - void ast_vhub_hub_wake_all(struct ast_vhub *vhub); -+void ast_vhub_wake_work(struct work_struct *work); - - /* dev.c */ - int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx); -diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c ---- a/drivers/usb/gadget/udc/dummy_hcd.c -+++ b/drivers/usb/gadget/udc/dummy_hcd.c -@@ -343,9 +343,11 @@ static void dummy_giveback(struct dummy *dum, struct usb_ep *_ep, - { - bool fifo = req == &dum->fifo_req; - -+ ++dum->callback_usage; - spin_unlock(&dum->lock); - usb_gadget_giveback_request(_ep, &req->req); - spin_lock(&dum->lock); -+ --dum->callback_usage; - if (fifo) - dum->fifo_req_busy = 0; - } -@@ -759,11 +761,13 @@ static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req, - req->req.complete = fifo_complete; - - list_add_tail(&req->queue, &ep->queue); -+ ++dum->callback_usage; - spin_unlock(&dum->lock); - _req->actual = _req->length; - _req->status = 0; - usb_gadget_giveback_request(_ep, _req); - spin_lock(&dum->lock); -+ --dum->callback_usage; - } else - list_add_tail(&req->queue, &ep->queue); - spin_unlock_irqrestore(&dum->lock, flags); -diff --git a/drivers/usb/host/octeon-hcd.c b/drivers/usb/host/octeon-hcd.c ---- a/drivers/usb/host/octeon-hcd.c -+++ b/drivers/usb/host/octeon-hcd.c -@@ -378,8 +378,22 @@ struct octeon_hcd { - struct cvmx_usb_transaction *active_split; - struct cvmx_usb_tx_fifo periodic; - struct cvmx_usb_tx_fifo nonperiodic; -+ struct hrtimer sof_timer; - }; - -+static int cvmx_usb_poll(struct octeon_hcd *usb); -+ -+static enum hrtimer_restart octeon_usb_sof_timer(struct hrtimer *t) -+{ -+ struct octeon_hcd *usb = container_of(t, struct octeon_hcd, sof_timer); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&usb->lock, flags); -+ cvmx_usb_poll(usb); -+ spin_unlock_irqrestore(&usb->lock, flags); -+ return HRTIMER_NORESTART; -+} -+ - /* - * This macro logically sets a single field in a CSR. It does the sequence - * read, modify, and write -@@ -578,7 +592,7 @@ static int cvmx_wait_tx_rx(struct octeon_hcd *usb, int fflsh_type) - int result; - u64 address = CVMX_USBCX_GRSTCTL(usb->index); - u64 done = cvmx_get_cycle() + 100 * -- (u64)octeon_get_clock_rate / 1000000; -+ (u64)octeon_get_clock_rate() / 1000000; - union cvmx_usbcx_grstctl c; - - while (1) { -@@ -853,6 +867,14 @@ static int cvmx_usb_initialize(struct device *dev, - * USBC_GAHBCFG[PTXFEMPLVL] - * Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 - */ -+ usbcx_gahbcfg.u32 = cvmx_usb_read_csr32(usb, -+ CVMX_USBCX_GHWCFG3(usb->index)); -+ if (usbcx_gahbcfg.u32 == 0xffffffff || usbcx_gahbcfg.u32 == 0) { -+ dev_err(dev, "USB core is not responding (GHWCFG3=0x%08x)\n", -+ usbcx_gahbcfg.u32); -+ return -ENODEV; -+ } -+ - usbcx_gahbcfg.u32 = 0; - usbcx_gahbcfg.s.dmaen = !(usb->init_flags & - CVMX_USB_INITIALIZE_FLAGS_NO_DMA); -@@ -1900,6 +1922,7 @@ static void cvmx_usb_schedule(struct octeon_hcd *usb, int is_sof) - int channel; - struct cvmx_usb_pipe *pipe; - int need_sof; -+ u64 min_due; - enum cvmx_usb_transfer ttype; - - if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) { -@@ -1940,15 +1963,33 @@ static void cvmx_usb_schedule(struct octeon_hcd *usb, int is_sof) - * future that might need to be scheduled - */ - need_sof = 0; -+ min_due = ~0ull; - for (ttype = CVMX_USB_TRANSFER_CONTROL; - ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) { - list_for_each_entry(pipe, &usb->active_pipes[ttype], node) { -- if (pipe->next_tx_frame > usb->frame_number) { -- need_sof = 1; -- break; -- } -+ if (pipe->next_tx_frame > usb->frame_number && -+ pipe->next_tx_frame < min_due) -+ min_due = pipe->next_tx_frame; - } - } -+ if (min_due != ~0ull) { -+ u64 delta = min_due - usb->frame_number; -+ -+ /* -+ * frame_number is resynced from HFNUM on every poll, so a -+ * deadline that is many frames away does not need an -+ * interrupt on every SOF to count them down - sleep on the -+ * timer instead and keep SOF interrupts for deadlines within -+ * a few frames. Stay well below the 16383-frame wrap of -+ * HFNUM. One (micro)frame is 125us in high-speed mode. -+ */ -+ if (delta <= 4 || delta > 8000) -+ need_sof = 1; -+ else -+ hrtimer_start(&usb->sof_timer, -+ ns_to_ktime((delta - 2) * 125000), -+ HRTIMER_MODE_REL); -+ } - USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), - cvmx_usbcx_gintmsk, sofmsk, need_sof); - } -@@ -3638,6 +3679,8 @@ static int octeon_usb_probe(struct platform_device *pdev) - usb = (struct octeon_hcd *)hcd->hcd_priv; - - spin_lock_init(&usb->lock); -+ hrtimer_setup(&usb->sof_timer, octeon_usb_sof_timer, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); - - usb->init_flags = initialize_flags; - -@@ -3688,6 +3731,7 @@ static void octeon_usb_remove(struct platform_device *pdev) - unsigned long flags; - - usb_remove_hcd(hcd); -+ hrtimer_cancel(&usb->sof_timer); - spin_lock_irqsave(&usb->lock, flags); - status = cvmx_usb_shutdown(usb); - spin_unlock_irqrestore(&usb->lock, flags); -diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c ---- a/drivers/usb/host/ohci-da8xx.c -+++ b/drivers/usb/host/ohci-da8xx.c -@@ -447,6 +447,7 @@ static int ohci_da8xx_probe(struct platform_device *pdev) - - err_remove_hcd: - usb_remove_hcd(hcd); -+ device_wakeup_disable(hcd->self.controller); - err: - usb_put_hcd(hcd); - return error; -@@ -457,6 +458,7 @@ static void ohci_da8xx_remove(struct platform_device *pdev) - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); -+ device_wakeup_disable(hcd->self.controller); - usb_put_hcd(hcd); - } - -diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c ---- a/drivers/usb/host/ohci-s3c2410.c -+++ b/drivers/usb/host/ohci-s3c2410.c -@@ -335,6 +335,7 @@ ohci_hcd_s3c2410_remove(struct platform_device *dev) - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_remove_hcd(hcd); -+ device_wakeup_disable(hcd->self.controller); - s3c2410_stop_hc(dev); - usb_put_hcd(hcd); - } -diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c ---- a/drivers/usb/host/ohci-spear.c -+++ b/drivers/usb/host/ohci-spear.c -@@ -103,6 +103,7 @@ static void spear_ohci_hcd_drv_remove(struct platform_device *pdev) - struct spear_ohci *sohci_p = to_spear_ohci(hcd); - - usb_remove_hcd(hcd); -+ device_wakeup_disable(hcd->self.controller); - clk_disable_unprepare(sohci_p->clk); - - usb_put_hcd(hcd); -diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c ---- a/drivers/usb/host/ohci-st.c -+++ b/drivers/usb/host/ohci-st.c -@@ -235,6 +235,7 @@ static void st_ohci_platform_remove(struct platform_device *dev) - int clk; - - usb_remove_hcd(hcd); -+ device_wakeup_disable(hcd->self.controller); - - if (pdata->power_off) - pdata->power_off(dev); -diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c ---- a/drivers/usb/serial/bus.c -+++ b/drivers/usb/serial/bus.c -@@ -165,7 +165,11 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) - - void usb_serial_bus_deregister(struct usb_serial_driver *driver) - { -- free_dynids(driver); - driver_unregister(&driver->driver); -+ free_dynids(driver); - } - -+void usb_serial_bus_remove_new_id(struct usb_serial_driver *driver) -+{ -+ driver_remove_file(&driver->driver, &driver_attr_new_id); -+} -diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c ---- a/drivers/usb/serial/cp210x.c -+++ b/drivers/usb/serial/cp210x.c -@@ -223,6 +223,7 @@ static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ - { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ - { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ -+ { USB_DEVICE(0x1B1C, 0x1C02) }, /* Corsair AX1500i Power Supply */ - { USB_DEVICE(0x1B93, 0x1013) }, /* Phoenix Contact UPS Device */ - { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ - { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ -diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c ---- a/drivers/usb/serial/generic.c -+++ b/drivers/usb/serial/generic.c -@@ -266,6 +266,7 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer); - void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) - { - struct usb_serial_port *port = tty->driver_data; -+ struct tty_port *tport = &port->port; - unsigned int bps; - unsigned long period; - unsigned long expire; -@@ -285,7 +286,14 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) - __func__, jiffies_to_msecs(timeout), - jiffies_to_msecs(period)); - expire = jiffies + timeout; -- while (!port->serial->type->tx_empty(port)) { -+ for (;;) { -+ mutex_lock(&tport->mutex); -+ if (tty_io_error(tty) || port->serial->type->tx_empty(port)) { -+ mutex_unlock(&tport->mutex); -+ break; -+ } -+ mutex_unlock(&tport->mutex); -+ - schedule_timeout_interruptible(period); - if (signal_pending(current)) - break; -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -260,6 +260,7 @@ static void option_instat_callback(struct urb *urb); - #define QUECTEL_PRODUCT_EM060K_12a 0x012a - #define QUECTEL_PRODUCT_EM060K_12b 0x012b - #define QUECTEL_PRODUCT_EM060K_12c 0x012c -+#define QUECTEL_PRODUCT_RG660QB 0x013d - #define QUECTEL_PRODUCT_EG91 0x0191 - #define QUECTEL_PRODUCT_EG95 0x0195 - #define QUECTEL_PRODUCT_BG96 0x0296 -@@ -280,6 +281,7 @@ static void option_instat_callback(struct urb *urb); - #define QUECTEL_PRODUCT_EC200U 0x0901 - #define QUECTEL_PRODUCT_EG912Y 0x6001 - #define QUECTEL_PRODUCT_EC200S_CN 0x6002 -+#define QUECTEL_PRODUCT_EG060W 0x6004 - #define QUECTEL_PRODUCT_EC200A 0x6005 - #define QUECTEL_PRODUCT_EG916Q 0x6007 - #define QUECTEL_PRODUCT_EM061K_LWW 0x6008 -@@ -1268,12 +1270,15 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200A, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG060W, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG912Y, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG916Q, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG660QB, 0xff, 0xff, 0x30) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG660QB, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x30) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x40) }, -@@ -2168,6 +2173,8 @@ static const struct usb_device_id option_ids[] = { - { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) }, /* Simcom SIM7500/SIM7600 MBIM mode */ - { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff), /* Simcom SIM7500/SIM7600 RNDIS mode */ - .driver_info = RSVD(7) }, -+ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x902b, 0xff), -+ .driver_info = RSVD(4) }, - { USB_DEVICE(0x1e0e, 0x9071), /* Simcom SIM8230 RMNET mode */ - .driver_info = RSVD(3) | RSVD(4) }, - { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9078, 0xff), /* Simcom SIM8230 ECM mode */ -@@ -2429,6 +2436,13 @@ static const struct usb_device_id option_ids[] = { - .driver_info = RSVD(5) }, - { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe167, 0xff), /* Foxconn T99W640 MBIM */ - .driver_info = RSVD(3) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x01) }, /* Compal EXC-T1 */ -+ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x02) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x03) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x04) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x30) }, /* Compal EXM-G1x */ -+ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x40) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x60) }, - { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ - .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, - { USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */ -diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c ---- a/drivers/usb/serial/quatech2.c -+++ b/drivers/usb/serial/quatech2.c -@@ -52,6 +52,7 @@ - #define QT2_XMIT_FLUSH 0x05 /* no following info */ - #define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */ - -+#define MIN_BAUD_RATE 50 - #define MAX_BAUD_RATE 921600 - #define DEFAULT_BAUD_RATE 9600 - -@@ -156,7 +157,7 @@ static inline int calc_baud_divisor(int baudrate) - - static inline int qt2_set_port_config(struct usb_device *dev, - unsigned char port_number, -- u16 baudrate, u16 lcr) -+ speed_t baudrate, u16 lcr) - { - int divisor = calc_baud_divisor(baudrate); - u16 index = ((u16) (lcr << 8) | (u16) (port_number)); -@@ -257,9 +258,9 @@ static void qt2_set_termios(struct tty_struct *tty, - struct usb_device *dev = port->serial->dev; - struct qt2_port_private *port_priv; - struct ktermios *termios = &tty->termios; -- u16 baud; - unsigned int cflag = termios->c_cflag; - u16 new_lcr = 0; -+ speed_t baud; - int status; - - port_priv = usb_get_serial_port_data(port); -@@ -277,6 +278,18 @@ static void qt2_set_termios(struct tty_struct *tty, - if (!baud) - baud = 9600; - -+ if (baud < MIN_BAUD_RATE || baud > MAX_BAUD_RATE) { -+ if (old_termios) -+ baud = tty_termios_baud_rate(old_termios); -+ else -+ baud = clamp(baud, MIN_BAUD_RATE, MAX_BAUD_RATE); -+ -+ tty_encode_baud_rate(tty, baud, baud); -+ -+ if (!baud) -+ baud = 9600; -+ } -+ - status = qt2_set_port_config(dev, port_priv->device_port, baud, - new_lcr); - if (status < 0) -@@ -373,7 +386,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) - port_priv->device_port = (u8) device_port; - - if (tty) -- qt2_set_termios(tty, port, &tty->termios); -+ qt2_set_termios(tty, port, NULL); - - return 0; - -diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c ---- a/drivers/usb/serial/ssu100.c -+++ b/drivers/usb/serial/ssu100.c -@@ -32,6 +32,7 @@ - - #define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) - -+#define MIN_BAUD_RATE 50 - #define MAX_BAUD_RATE 460800 - - #define ATC_DISABLED 0x00 -@@ -217,9 +218,10 @@ static void ssu100_set_termios(struct tty_struct *tty, - { - struct usb_device *dev = port->serial->dev; - struct ktermios *termios = &tty->termios; -- u16 baud, divisor, remainder; -+ speed_t baud, remainder; - unsigned int cflag = termios->c_cflag; - u16 urb_value = 0; /* will hold the new flags */ -+ u16 divisor; - int result; - - if (cflag & PARENB) { -@@ -235,6 +237,18 @@ static void ssu100_set_termios(struct tty_struct *tty, - if (!baud) - baud = 9600; - -+ if (baud < MIN_BAUD_RATE || baud > MAX_BAUD_RATE) { -+ if (old_termios) -+ baud = tty_termios_baud_rate(old_termios); -+ else -+ baud = clamp(baud, MIN_BAUD_RATE, MAX_BAUD_RATE); -+ -+ tty_encode_baud_rate(tty, baud, baud); -+ -+ if (!baud) -+ baud = 9600; -+ } -+ - dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud); - - -@@ -310,7 +324,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) - dev_dbg(&port->dev, "%s - set uart failed\n", __func__); - - if (tty) -- ssu100_set_termios(tty, port, &tty->termios); -+ ssu100_set_termios(tty, port, NULL); - - return usb_serial_generic_open(tty, port); - } -diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c ---- a/drivers/usb/serial/usb-serial.c -+++ b/drivers/usb/serial/usb-serial.c -@@ -400,17 +400,13 @@ static unsigned int serial_chars_in_buffer(struct tty_struct *tty) - static void serial_wait_until_sent(struct tty_struct *tty, int timeout) - { - struct usb_serial_port *port = tty->driver_data; -- struct usb_serial *serial = port->serial; - - dev_dbg(&port->dev, "%s\n", __func__); - - if (!port->serial->type->wait_until_sent) - return; - -- mutex_lock(&serial->disc_mutex); -- if (!serial->disconnected) -- port->serial->type->wait_until_sent(tty, timeout); -- mutex_unlock(&serial->disc_mutex); -+ port->serial->type->wait_until_sent(tty, timeout); - } - - static void serial_throttle(struct tty_struct *tty) -@@ -438,8 +434,13 @@ static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) - struct usb_serial_port *port = tty->driver_data; - struct tty_port *tport = &port->port; - unsigned int close_delay, closing_wait; -+ int ret = 0; - - mutex_lock(&tport->mutex); -+ if (tty_io_error(tty)) { -+ ret = -EIO; -+ goto out_unlock; -+ } - - close_delay = jiffies_to_msecs(tport->close_delay) / 10; - closing_wait = tport->closing_wait; -@@ -452,10 +453,10 @@ static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) - - if (port->serial->type->get_serial) - port->serial->type->get_serial(tty, ss); -- -+out_unlock: - mutex_unlock(&tport->mutex); - -- return 0; -+ return ret; - } - - static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) -@@ -471,6 +472,10 @@ static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) - closing_wait = msecs_to_jiffies(closing_wait * 10); - - mutex_lock(&tport->mutex); -+ if (tty_io_error(tty)) { -+ ret = -EIO; -+ goto out_unlock; -+ } - - if (!capable(CAP_SYS_ADMIN)) { - if (close_delay != tport->close_delay || -@@ -498,6 +503,7 @@ static int serial_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) - { - struct usb_serial_port *port = tty->driver_data; -+ struct tty_port *tport = &port->port; - int retval = -ENOIOCTLCMD; - - dev_dbg(&port->dev, "%s - cmd 0x%04x\n", __func__, cmd); -@@ -508,8 +514,21 @@ static int serial_ioctl(struct tty_struct *tty, - retval = port->serial->type->tiocmiwait(tty, arg); - break; - default: -- if (port->serial->type->ioctl) -+ if (!port->serial->type->ioctl) -+ break; -+ -+ if (cmd == TIOCSRS485) -+ down_write(&tty->termios_rwsem); -+ -+ mutex_lock(&tport->mutex); -+ if (tty_io_error(tty)) -+ retval = -EIO; -+ else - retval = port->serial->type->ioctl(tty, cmd, arg); -+ mutex_unlock(&tport->mutex); -+ -+ if (cmd == TIOCSRS485) -+ up_write(&tty->termios_rwsem); - } - - return retval; -@@ -519,25 +538,40 @@ static void serial_set_termios(struct tty_struct *tty, - const struct ktermios *old) - { - struct usb_serial_port *port = tty->driver_data; -+ struct tty_port *tport = &port->port; - - dev_dbg(&port->dev, "%s\n", __func__); - -- if (port->serial->type->set_termios) -- port->serial->type->set_termios(tty, port, old); -- else -+ if (!port->serial->type->set_termios) { - tty_termios_copy_hw(&tty->termios, old); -+ return; -+ } -+ -+ mutex_lock(&tport->mutex); -+ if (!tty_io_error(tty)) -+ port->serial->type->set_termios(tty, port, old); -+ mutex_unlock(&tport->mutex); - } - - static int serial_break(struct tty_struct *tty, int break_state) - { - struct usb_serial_port *port = tty->driver_data; -+ struct tty_port *tport = &port->port; -+ int ret; - - dev_dbg(&port->dev, "%s\n", __func__); - -- if (port->serial->type->break_ctl) -- return port->serial->type->break_ctl(tty, break_state); -+ if (!port->serial->type->break_ctl) -+ return -ENOTTY; - -- return -ENOTTY; -+ mutex_lock(&tport->mutex); -+ if (tty_io_error(tty)) -+ ret = -EIO; -+ else -+ ret = port->serial->type->break_ctl(tty, break_state); -+ mutex_unlock(&tport->mutex); -+ -+ return ret; - } - - static int serial_proc_show(struct seq_file *m, void *v) -@@ -578,24 +612,44 @@ static int serial_proc_show(struct seq_file *m, void *v) - static int serial_tiocmget(struct tty_struct *tty) - { - struct usb_serial_port *port = tty->driver_data; -+ struct tty_port *tport = &port->port; -+ int ret; - - dev_dbg(&port->dev, "%s\n", __func__); - -- if (port->serial->type->tiocmget) -- return port->serial->type->tiocmget(tty); -- return -ENOTTY; -+ if (!port->serial->type->tiocmget) -+ return -ENOTTY; -+ -+ mutex_lock(&tport->mutex); -+ if (tty_io_error(tty)) -+ ret = -EIO; -+ else -+ ret = port->serial->type->tiocmget(tty); -+ mutex_unlock(&tport->mutex); -+ -+ return ret; - } - - static int serial_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) - { - struct usb_serial_port *port = tty->driver_data; -+ struct tty_port *tport = &port->port; -+ int ret; - - dev_dbg(&port->dev, "%s\n", __func__); - -- if (port->serial->type->tiocmset) -- return port->serial->type->tiocmset(tty, set, clear); -- return -ENOTTY; -+ if (!port->serial->type->tiocmset) -+ return -ENOTTY; -+ -+ mutex_lock(&tport->mutex); -+ if (tty_io_error(tty)) -+ ret = -EIO; -+ else -+ ret = port->serial->type->tiocmset(tty, set, clear); -+ mutex_unlock(&tport->mutex); -+ -+ return ret; - } - - static int serial_get_icount(struct tty_struct *tty, -@@ -1191,11 +1245,16 @@ static void usb_serial_disconnect(struct usb_interface *interface) - usb_serial_port_poison_urbs(port); - wake_up_interruptible(&port->port.delta_msr_wait); - cancel_work_sync(&port->work); -+ } -+ -+ if (serial->type->disconnect) -+ serial->type->disconnect(serial); -+ -+ for (i = 0; i < serial->num_ports; ++i) { -+ port = serial->port[i]; - if (device_is_registered(&port->dev)) - device_del(&port->dev); - } -- if (serial->type->disconnect) -- serial->type->disconnect(serial); - - release_sibling(serial, interface); - -@@ -1464,7 +1523,7 @@ int __usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers - { - int rc; - struct usb_driver *udriver; -- struct usb_serial_driver * const *sd; -+ struct usb_serial_driver * const *sd, * const *s; - - /* - * udriver must be registered before any of the serial drivers, -@@ -1517,9 +1576,11 @@ int __usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers - return 0; - - err_deregister_drivers: -+ for (s = serial_drivers; s < sd; ++s) -+ usb_serial_bus_remove_new_id(*s); -+ usb_deregister(udriver); - while (sd-- > serial_drivers) - usb_serial_deregister(*sd); -- usb_deregister(udriver); - err_free_driver: - kfree(udriver); - return rc; -@@ -1537,10 +1598,23 @@ EXPORT_SYMBOL_GPL(__usb_serial_register_drivers); - void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]) - { - struct usb_driver *udriver = (*serial_drivers)->usb_driver; -+ struct usb_serial_driver * const *sd; -+ -+ /* -+ * udriver must be deregistered before the serial drivers so that -+ * I/O is stopped before unbinding the ports. -+ * -+ * Remove the new_id attributes to prevent ids from being added and -+ * triggering a probe of udriver after it has been deregistered. -+ */ -+ for (sd = serial_drivers; *sd; ++sd) -+ usb_serial_bus_remove_new_id(*sd); - -- for (; *serial_drivers; ++serial_drivers) -- usb_serial_deregister(*serial_drivers); - usb_deregister(udriver); -+ -+ for (sd = serial_drivers; *sd; ++sd) -+ usb_serial_deregister(*sd); -+ - kfree(udriver); - } - EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); -diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c ---- a/drivers/usb/serial/xr_serial.c -+++ b/drivers/usb/serial/xr_serial.c -@@ -850,12 +850,9 @@ static int xr_get_rs485_config(struct tty_struct *tty, - struct usb_serial_port *port = tty->driver_data; - struct xr_data *data = usb_get_serial_port_data(port); - -- down_read(&tty->termios_rwsem); -- if (copy_to_user(argp, &data->rs485, sizeof(data->rs485))) { -- up_read(&tty->termios_rwsem); -+ /* core holds port mutex */ -+ if (copy_to_user(argp, &data->rs485, sizeof(data->rs485))) - return -EFAULT; -- } -- up_read(&tty->termios_rwsem); - - return 0; - } -@@ -871,10 +868,9 @@ static int xr_set_rs485_config(struct tty_struct *tty, - return -EFAULT; - xr_sanitize_serial_rs485(&rs485); - -- down_write(&tty->termios_rwsem); -+ /* core holds termios rwsem and port mutex */ - data->rs485 = rs485; - xr_set_flow_mode(tty, port, NULL); -- up_write(&tty->termios_rwsem); - - if (copy_to_user(argp, &rs485, sizeof(rs485))) - return -EFAULT; -diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c ---- a/drivers/usb/storage/sierra_ms.c -+++ b/drivers/usb/storage/sierra_ms.c -@@ -77,6 +77,13 @@ static int sierra_get_swoc_info(struct usb_device *udev, - sizeof(struct swoc_info), /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ - -+ /* -+ * A short IN transfer leaves the tail of swocInfo uninitialized; -+ * only a full transfer is valid. -+ */ -+ if (result != sizeof(struct swoc_info)) -+ return -EIO; -+ - swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU); - swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer); - return result; -diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c ---- a/drivers/usb/typec/anx7411.c -+++ b/drivers/usb/typec/anx7411.c -@@ -1566,8 +1566,11 @@ static void anx7411_i2c_remove(struct i2c_client *client) - anx7411_partner_unregister_altmode(plat); - anx7411_unregister_partner(plat); - -- if (plat->workqueue) -+ if (plat->workqueue) { -+ disable_irq(plat->intp_irq); -+ cancel_work_sync(&plat->work); - destroy_workqueue(plat->workqueue); -+ } - - i2c_unregister_device(plat->spi_client); - -diff --git a/drivers/usb/typec/port-mapper.c b/drivers/usb/typec/port-mapper.c ---- a/drivers/usb/typec/port-mapper.c -+++ b/drivers/usb/typec/port-mapper.c -@@ -42,6 +42,23 @@ static int usb4_port_compare(struct device *dev, void *fwnode) - return usb4_usb3_port_match(dev, fwnode); - } - -+static bool typec_has_usb4_host_interface(const struct fwnode_handle *fwnode) -+{ -+ if (!IS_REACHABLE(CONFIG_USB4)) -+ return false; -+ -+ struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = -+ fwnode_find_reference(fwnode, "usb4-host-interface", 0); -+ -+ /* -+ * The USB4 port can only appear if the host interface is enabled in -+ * the firmware and has been enumerated as a device. The latter is -+ * the same check as in usb_acpi_add_usb4_devlink(). -+ */ -+ return !IS_ERR(nhi_fwnode) && fwnode_device_is_available(nhi_fwnode) && -+ nhi_fwnode->dev; -+} -+ - static int typec_port_compare(struct device *dev, void *fwnode) - { - return device_match_fwnode(dev, fwnode); -@@ -64,11 +81,11 @@ static int typec_port_match(struct device *dev, void *data) - adev_fwnode); - - /* -- * If dev is USB 3.x port, it may have reference to the -+ * If dev is USB 3.x port, it may have reference to an available - * USB4 host interface in which case we can also link the - * Type-C port with the USB4 port. - */ -- if (fwnode_property_present(adev_fwnode, "usb4-host-interface")) -+ if (typec_has_usb4_host_interface(adev_fwnode)) - component_match_add(&arg->port->dev, &arg->match, - usb4_port_compare, adev_fwnode); - } -diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c ---- a/drivers/usb/typec/tcpm/tcpm.c -+++ b/drivers/usb/typec/tcpm/tcpm.c -@@ -1756,7 +1756,8 @@ static void mod_enable_frs_delayed_work(struct tcpm_port *port, unsigned int del - static void mod_vdm_discovery_cancel_delayed_work(struct tcpm_port *port) - { - hrtimer_cancel(&port->vdm_discovery_timer); -- kthread_cancel_work_sync(&port->vdm_discovery_work); -+ if (port->wq) -+ kthread_cancel_work_sync(&port->vdm_discovery_work); - } - - static void mod_vdm_discovery_delayed_work(struct tcpm_port *port, unsigned int delay_ms) -@@ -7113,7 +7114,7 @@ static void tcpm_pd_event_handler(struct kthread_work *work) - port->upcoming_state = FR_SWAP_SEND; - ret = tcpm_ams_start(port, FAST_ROLE_SWAP); - if (ret == -EAGAIN) -- port->upcoming_state = INVALID_STATE; -+ tcpm_set_state(port, ERROR_RECOVERY, 0); - } else { - tcpm_log(port, "Discarding FRS_SIGNAL! Not in sink ready"); - } -@@ -8977,6 +8978,7 @@ void tcpm_unregister_port(struct tcpm_port *port) - - port->registered = false; - kthread_destroy_worker(port->wq); -+ port->wq = NULL; - - hrtimer_cancel(&port->vdm_discovery_timer); - hrtimer_cancel(&port->enable_frs_timer); -diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c ---- a/drivers/usb/typec/tipd/core.c -+++ b/drivers/usb/typec/tipd/core.c -@@ -343,7 +343,7 @@ static void tps6598x_set_data_role(struct tps6598x *tps, - - static int tps6598x_connect(struct tps6598x *tps, u32 status) - { -- struct typec_partner_desc desc; -+ struct typec_partner_desc desc = { }; - enum typec_pwr_opmode mode; - int ret; - -@@ -354,7 +354,6 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) - - desc.usb_pd = mode == TYPEC_PWR_MODE_PD; - desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ -- desc.identity = NULL; - - if (desc.usb_pd) { - ret = tps6598x_read_partner_identity(tps); -@@ -850,11 +849,10 @@ static void cd321x_update_work(struct work_struct *work) - - /* Set up partner if we were previously disconnected (or changed). */ - if (!tps->partner) { -- struct typec_partner_desc desc; -+ struct typec_partner_desc desc = { }; - - desc.usb_pd = is_pd; - desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ -- desc.identity = NULL; - - if (desc.usb_pd) - desc.identity = &st.partner_identity; -@@ -1792,6 +1790,7 @@ static int tps6598x_probe(struct i2c_client *client) - const struct tipd_data *data; - struct tps6598x *tps; - struct fwnode_handle *fwnode; -+ bool patch_loaded = false; - u32 status; - u32 vid = 0; - int ret; -@@ -1847,6 +1846,7 @@ static int tps6598x_probe(struct i2c_client *client) - return ret; - - if (ret == TPS_MODE_PTCH) { -+ patch_loaded = true; - ret = tps->data->init(tps); - if (ret) - return ret; -@@ -1937,7 +1937,8 @@ static int tps6598x_probe(struct i2c_client *client) - tps6598x_write64(tps, TPS_REG_INT_MASK1, 0); - err_reset_controller: - /* Reset PD controller to remove any applied patch */ -- tps->data->reset(tps); -+ if (patch_loaded) -+ tps->data->reset(tps); - - return ret; - } -diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c ---- a/drivers/usb/typec/ucsi/displayport.c -+++ b/drivers/usb/typec/ucsi/displayport.c -@@ -71,11 +71,14 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) - if (ret < 0) { - if (ucsi->version > 0x0100) - goto err_unlock; -- cur = 0xff; - } - -- if (cur < UCSI_MAX_ALTMODES) { -- ret = dp->con->port_altmode[cur] == alt ? 0 : -EBUSY; -+ if (cur != 0xff) { -+ if (cur < UCSI_MAX_ALTMODES) -+ ret = dp->con->port_altmode[cur] == alt ? 0 : -EBUSY; -+ else -+ ret = -EINVAL; -+ - goto err_unlock; - } - -diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c ---- a/drivers/usb/typec/ucsi/ucsi.c -+++ b/drivers/usb/typec/ucsi/ucsi.c -@@ -1801,10 +1801,21 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) - { - struct fwnode_handle *fwnode; - int i = 1; -+ int ret; -+ u32 port; - -- device_for_each_child_node(con->ucsi->dev, fwnode) -- if (i++ == con->num) -- return fwnode; -+ device_for_each_child_node(con->ucsi->dev, fwnode) { -+ ret = fwnode_property_read_u32(fwnode, "reg", &port); -+ if (ret < 0) { -+ if (i == con->num) -+ return fwnode; -+ } else { -+ if (port == con->num - 1) -+ return fwnode; -+ } -+ -+ i++; -+ } - return NULL; - } - -diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c ---- a/drivers/usb/typec/ucsi/ucsi_acpi.c -+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c -@@ -121,6 +121,33 @@ static const struct ucsi_operations ucsi_acpi_ops = { - .async_control = ucsi_acpi_async_control - }; - -+static int ucsi_acer_read_version(struct ucsi *ucsi, u16 *version) -+{ -+ struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); -+ int ret; -+ -+ ret = ucsi_acpi_read_version(ucsi, version); -+ if (ret) -+ return ret; -+ -+ if (!*version) { -+ dev_warn(ua->dev, "UCSI version is zero, assuming 1.2\n"); -+ *version = UCSI_VERSION_1_2; -+ } -+ -+ return 0; -+} -+ -+static const struct ucsi_operations ucsi_acer_ops = { -+ .read_version = ucsi_acer_read_version, -+ .read_cci = ucsi_acpi_read_cci, -+ .poll_cci = ucsi_acpi_poll_cci, -+ .read_message_in = ucsi_acpi_read_message_in, -+ .write_message_out = ucsi_acpi_write_message_out, -+ .sync_control = ucsi_sync_control_common, -+ .async_control = ucsi_acpi_async_control -+}; -+ - static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, - void *val, size_t len, void *msg_out, - size_t msg_out_size) -@@ -162,6 +189,13 @@ static const struct ucsi_operations ucsi_gram_ops = { - }; - - static const struct dmi_system_id ucsi_acpi_quirks[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Nitro ANV15-41"), -+ }, -+ .driver_data = (void *)&ucsi_acer_ops, -+ }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), -diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c ---- a/drivers/usb/typec/ucsi/ucsi_glink.c -+++ b/drivers/usb/typec/ucsi/ucsi_glink.c -@@ -362,6 +362,10 @@ static void pmic_glink_ucsi_destroy(void *data) - { - struct pmic_glink_ucsi *ucsi = data; - -+ /* Drain the work items before ucsi_destroy() frees the ucsi instance */ -+ cancel_work_sync(&ucsi->notify_work); -+ cancel_work_sync(&ucsi->register_work); -+ - /* Protect to make sure we're not in a middle of a transaction from a glink callback */ - mutex_lock(&ucsi->lock); - ucsi_destroy(ucsi->ucsi); -@@ -467,8 +471,15 @@ static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) - { - struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev); - -- /* Unregister first to stop having read & writes */ -- ucsi_unregister(ucsi->ucsi); -+ /* Callbacks can queue work until devres releases the client */ -+ disable_work_sync(&ucsi->notify_work); -+ disable_work_sync(&ucsi->register_work); -+ -+ /* register_work may have unregistered the instance already */ -+ if (ucsi->ucsi_registered) { -+ ucsi->ucsi_registered = false; -+ ucsi_unregister(ucsi->ucsi); -+ } - } - - static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = { -diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h ---- a/include/linux/usb/serial.h -+++ b/include/linux/usb/serial.h -@@ -381,6 +381,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, - - int usb_serial_bus_register(struct usb_serial_driver *device); - void usb_serial_bus_deregister(struct usb_serial_driver *device); -+void usb_serial_bus_remove_new_id(struct usb_serial_driver *driver); - - extern const struct bus_type usb_serial_bus_type; - extern struct tty_driver *usb_serial_tty_driver; diff --git a/kernel/0607-usb-fixes.patch.sig b/kernel/0607-usb-fixes.patch.sig deleted file mode 100644 index 182c484..0000000 Binary files a/kernel/0607-usb-fixes.patch.sig and /dev/null differ diff --git a/kernel/0620-usb-string-sanitize.patch b/kernel/0620-usb-string-sanitize.patch deleted file mode 100644 index d2ac981..0000000 --- a/kernel/0620-usb-string-sanitize.patch +++ /dev/null @@ -1,29 +0,0 @@ -diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c ---- a/drivers/usb/core/message.c -+++ b/drivers/usb/core/message.c -@@ -1052,6 +1052,25 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) - UTF16_LITTLE_ENDIAN, buf, size); - buf[err] = 0; - -+ /* -+ * Some devices report string descriptors with a declared length -+ * greater than the actual serial, leaving uninitialized firmware -+ * memory (often including C0 control characters) appended to the -+ * returned string. Truncate at the first control character so -+ * callers get a clean, well-formed string. -+ */ -+ { -+ int i; -+ for (i = 0; i < err; i++) { -+ unsigned char c = buf[i]; -+ if (c < 0x20 || c == 0x7f) { -+ buf[i] = 0; -+ err = i; -+ break; -+ } -+ } -+ } -+ - if (tbuf[1] != USB_DT_STRING) - dev_dbg(&dev->dev, - "wrong descriptor type %02x for string %d (\"%s\")\n", diff --git a/kernel/0620-usb-string-sanitize.patch.sig b/kernel/0620-usb-string-sanitize.patch.sig deleted file mode 100644 index 9ed271f..0000000 Binary files a/kernel/0620-usb-string-sanitize.patch.sig and /dev/null differ diff --git a/kernel/0650-wireguard-tstamp-type.patch b/kernel/0650-wireguard-tstamp-type.patch deleted file mode 100644 index 87743c9..0000000 --- a/kernel/0650-wireguard-tstamp-type.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/drivers/net/wireguard/queueing.h b/drivers/net/wireguard/queueing.h ---- a/drivers/net/wireguard/queueing.h -+++ b/drivers/net/wireguard/queueing.h -@@ -78,12 +78,14 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating) - u8 l4_hash = skb->l4_hash; - u8 sw_hash = skb->sw_hash; - u32 hash = skb->hash; -+ u8 tstamp_type = skb->tstamp_type; - skb_scrub_packet(skb, true); - memset(&skb->headers, 0, sizeof(skb->headers)); - if (encapsulating) { - skb->l4_hash = l4_hash; - skb->sw_hash = sw_hash; - skb->hash = hash; -+ skb->tstamp_type = tstamp_type; - } - skb->queue_mapping = 0; - skb->nohdr = 0; diff --git a/kernel/0650-wireguard-tstamp-type.patch.sig b/kernel/0650-wireguard-tstamp-type.patch.sig deleted file mode 100644 index fa5148e..0000000 Binary files a/kernel/0650-wireguard-tstamp-type.patch.sig and /dev/null differ diff --git a/kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch b/kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch deleted file mode 100644 index 3b51649..0000000 --- a/kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -819,6 +819,8 @@ static const struct usb_device_id quirks_table[] = { - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x13d3, 0x3613), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH }, -+ { USB_DEVICE(0x13d3, 0x3625), .driver_info = BTUSB_MEDIATEK | -+ BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x13d3, 0x3627), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK | diff --git a/kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch.sig b/kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch.sig deleted file mode 100644 index 61318b8..0000000 Binary files a/kernel/0660-btusb-mediatek-mt7922-13d3-3625.patch.sig and /dev/null differ diff --git a/kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch b/kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch deleted file mode 100644 index d3b514c..0000000 --- a/kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c ---- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c -+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c -@@ -516,6 +516,10 @@ iwl_mld_mac80211_tx(struct ieee80211_hw *hw, - u32 link_id = u32_get_bits(info->control.flags, - IEEE80211_TX_CTRL_MLO_LINK); - -+ if (unlikely(test_bit(STATUS_FW_ERROR, &mld->trans->status))) { -+ ieee80211_free_txskb(hw, skb); -+ return; -+ } - /* In AP mode, mgmt frames are sent on the bcast station, - * so the FW can't translate the MLD addr to the link addr. Do it here - */ -diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c ---- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c -+++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c -@@ -987,6 +987,9 @@ void iwl_mld_tx_from_txq(struct iwl_mld *mld, struct ieee80211_txq *txq) - struct sk_buff *skb = NULL; - u8 zero_addr[ETH_ALEN] = {}; - -+ if (unlikely(test_bit(STATUS_FW_ERROR, &mld->trans->status))) -+ return; -+ - /* - * Don't transmit during firmware restart. The firmware is dead, - * so iwl_trans_tx() would return -EIO for each frame. Avoid the diff --git a/kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch.sig b/kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch.sig deleted file mode 100644 index 645c20d..0000000 Binary files a/kernel/0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch.sig and /dev/null differ diff --git a/kernel/0663-btintel-pcie-serialize-reset-type.patch b/kernel/0663-btintel-pcie-serialize-reset-type.patch deleted file mode 100644 index 2464f58..0000000 --- a/kernel/0663-btintel-pcie-serialize-reset-type.patch +++ /dev/null @@ -1,145 +0,0 @@ -diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c ---- a/drivers/bluetooth/btintel_pcie.c -+++ b/drivers/bluetooth/btintel_pcie.c -@@ -2499,8 +2499,6 @@ static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev, - } - } - --static void btintel_pcie_reset(struct hci_dev *hdev); -- - static int btintel_pcie_acpi_reset_method(struct btintel_pcie_data *data) - { - union acpi_object *obj, argv4; -@@ -2693,56 +2691,86 @@ static void btintel_pcie_reset_work(struct work_struct *wk) - pci_unlock_rescan_remove(); - } - --static void btintel_pcie_reset(struct hci_dev *hdev) -+/* Schedule a device reset of the requested type. -+ * -+ * BTINTEL_PCIE_RECOVERY_IN_PROGRESS serializes all reset requesters -+ * (sysfs reset attribute, hci_cmd_timeout(), hw_error, resume error -+ * path, etc.) so that: -+ * -+ * - dev_data->reset_type is written by exactly one caller (the -+ * thread that wins test_and_set_bit), eliminating the race where -+ * a second hw_error could clobber an already-scheduled reset's -+ * type; -+ * - the write happens AFTER the bit is set, so reset_work observes -+ * it through schedule_work()'s memory ordering; -+ * - losers return without touching reset_type or scheduling the -+ * work, so concurrent triggers are silently coalesced into the -+ * in-flight one (whose recovery will reinitialize the device -+ * regardless of the dropped trigger's variant). -+ * -+ * The bit is cleared only by .remove() / re-probe via fresh devm -+ * allocation, which is the intended one-shot semantics: a reset -+ * tears down and re-probes 'data', so there is no "in-flight" -+ * reset to follow up after device_reprobe() succeeds. -+ */ -+static void btintel_pcie_request_reset(struct btintel_pcie_data *data, -+ enum btintel_pcie_reset_type type) - { -- struct btintel_pcie_data *data; -- -- data = hci_get_drvdata(hdev); -- - if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags)) - return; - - if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags)) - return; - -+ data->reset_type = type; -+ - pci_dev_get(data->pdev); - schedule_work(&data->reset_work); - } - -+static void btintel_pcie_hci_reset(struct hci_dev *hdev) -+{ -+ struct btintel_pcie_data *data = hci_get_drvdata(hdev); -+ -+ btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR); -+} -+ - static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code) - { -- struct btintel_pcie_dev_recovery *data; -+ struct btintel_pcie_dev_recovery *rec; - struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev); - struct pci_dev *pdev = dev_data->pdev; -+ enum btintel_pcie_reset_type type; - time64_t retry_window; - -+ if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &dev_data->flags)) -+ return; -+ - btintel_pcie_dump_debug_registers(hdev); - -- data = btintel_pcie_get_recovery(pdev, &hdev->dev); -- if (!data) -+ rec = btintel_pcie_get_recovery(pdev, &hdev->dev); -+ if (!rec) - return; - -- if (code == 0x13) -- dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_PLDR; -- else -- dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR; -+ type = (code == 0x13) ? BTINTEL_PCIE_IOSF_PRR_PLDR -+ : BTINTEL_PCIE_IOSF_PRR_FLR; - - bt_dev_err(hdev, "Encountered exception err:0x%x triggering: %s", code, -- dev_data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR"); -- retry_window = ktime_get_boottime_seconds() - data->last_error; -+ type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR"); -+ retry_window = ktime_get_boottime_seconds() - rec->last_error; - - if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS && -- data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) { -+ rec->count >= BTINTEL_PCIE_FLR_MAX_RETRY) { - bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d", -- BTINTEL_PCIE_FLR_MAX_RETRY, data->count); -+ BTINTEL_PCIE_FLR_MAX_RETRY, rec->count); - bt_dev_dbg(hdev, "Boot time: %lld seconds", - ktime_get_boottime_seconds()); - bt_dev_dbg(hdev, "last error at: %lld seconds", -- data->last_error); -+ rec->last_error); - return; - } - btintel_pcie_inc_recovery_count(pdev, &hdev->dev); -- btintel_pcie_reset(hdev); -+ btintel_pcie_request_reset(dev_data, type); - } - - static bool btintel_pcie_wakeup(struct hci_dev *hdev) -@@ -2832,7 +2860,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) - hdev->hw_error = btintel_pcie_hw_error; - hdev->set_diag = btintel_set_diag; - hdev->set_bdaddr = btintel_set_bdaddr; -- hdev->reset = btintel_pcie_reset; -+ hdev->reset = btintel_pcie_hci_reset; - hdev->wakeup = btintel_pcie_wakeup; - hdev->hci_drv = &btintel_pcie_hci_drv; - -@@ -3124,8 +3152,7 @@ static int btintel_pcie_resume(struct device *dev) - if (data->pm_sx_event == PM_EVENT_FREEZE || - data->pm_sx_event == PM_EVENT_HIBERNATE) { - set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags); -- data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR; -- btintel_pcie_reset(data->hdev); -+ btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR); - return 0; - } - -@@ -3156,7 +3183,7 @@ static int btintel_pcie_resume(struct device *dev) - queue_work(data->coredump_workqueue, &data->coredump_work); - } - set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags); -- btintel_pcie_reset(data->hdev); -+ btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR); - } - return err; - } diff --git a/kernel/0663-btintel-pcie-serialize-reset-type.patch.sig b/kernel/0663-btintel-pcie-serialize-reset-type.patch.sig deleted file mode 100644 index 6469de5..0000000 Binary files a/kernel/0663-btintel-pcie-serialize-reset-type.patch.sig and /dev/null differ diff --git a/kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch b/kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch deleted file mode 100644 index 54219c0..0000000 --- a/kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c ---- a/drivers/bluetooth/btintel_pcie.c -+++ b/drivers/bluetooth/btintel_pcie.c -@@ -3069,10 +3069,12 @@ static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate) - BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES, - BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0); - -- /* A hardware bug may cause the alive interrupt to be missed. -- * Check if the controller reached the expected state and retry -- * the operation only if it hasn't. -+ /* A hardware bug may cause the alive interrupt to be missed. Refresh -+ * boot_stage_cache from hardware, since only the interrupt handler -+ * updates it. Finally retry only if the state check still fails. - */ -+ data->boot_stage_cache = btintel_pcie_rd_reg32(data, -+ BTINTEL_PCIE_CSR_BOOT_STAGE_REG); - if (dxstate == BTINTEL_PCIE_STATE_D0) { - if (btintel_pcie_in_d0(data)) - return 0; -diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h ---- a/drivers/bluetooth/btintel_pcie.h -+++ b/drivers/bluetooth/btintel_pcie.h -@@ -50,6 +50,7 @@ - #define BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_HALTED (BIT(14)) - #define BTINTEL_PCIE_CSR_BOOT_STAGE_MAC_ACCESS_ON (BIT(16)) - #define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE (BIT(23)) -+/* Reflects live D-state. Updated by hardware on every D-state transition. */ - #define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY (BIT(24)) - - /* Registers for MSI-X */ diff --git a/kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch.sig b/kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch.sig deleted file mode 100644 index 216c5d1..0000000 Binary files a/kernel/0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch.sig and /dev/null differ diff --git a/kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch b/kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch deleted file mode 100644 index 2ec0e80..0000000 --- a/kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch +++ /dev/null @@ -1,145 +0,0 @@ -diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c ---- a/drivers/bluetooth/btintel_pcie.c -+++ b/drivers/bluetooth/btintel_pcie.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -3046,7 +3047,8 @@ static void btintel_pcie_coredump(struct device *dev) - - static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate) - { -- int retry = 0, status; -+ int retry = 0; -+ long status; - u32 dx_intr_timeout_ms = 200; - - do { -@@ -3098,18 +3100,23 @@ static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg) - - data = pci_get_drvdata(pdev); - -- dxstate = (mesg.event == PM_EVENT_SUSPEND ? -- BTINTEL_PCIE_STATE_D3_HOT : BTINTEL_PCIE_STATE_D3_COLD); -- -- data->pm_sx_event = mesg.event; -+ /* S0ix (s2idle) uses D3_HOT; S3, freeze and hibernate use D3_COLD. */ -+ if (mesg.event == PM_EVENT_SUSPEND && -+ pm_suspend_target_state == PM_SUSPEND_TO_IDLE) -+ dxstate = BTINTEL_PCIE_STATE_D3_HOT; -+ else -+ dxstate = BTINTEL_PCIE_STATE_D3_COLD; - - start = ktime_get(); - - /* Refer: 6.4.11.7 -> Platform power management */ - err = btintel_pcie_set_dxstate(data, dxstate); - -- if (err) -+ if (err) { -+ bt_dev_err(data->hdev, "Failed to set dxstate:%u (%d)", -+ dxstate, err); - return err; -+ } - - bt_dev_dbg(data->hdev, - "device entered into d3 state from d0 in %lld us", -@@ -3132,7 +3139,7 @@ static int btintel_pcie_freeze(struct device *dev) - return btintel_pcie_suspend_late(dev, PMSG_FREEZE); - } - --static int btintel_pcie_resume(struct device *dev) -+static int btintel_pcie_resume_event(struct device *dev, pm_message_t mesg) - { - struct pci_dev *pdev = to_pci_dev(dev); - struct btintel_pcie_data *data; -@@ -3140,19 +3147,15 @@ static int btintel_pcie_resume(struct device *dev) - int err; - - data = pci_get_drvdata(pdev); -- data->gp0_received = false; - - start = ktime_get(); - -- /* When the system enters S4 (hibernate) mode, bluetooth device loses -- * power, which results in the erasure of its loaded firmware. -- * Consequently, function level reset (flr) is required on system -- * resume to bring the controller back into an operational state by -- * initiating a new firmware download. -+ /* S3 and S4 may cut power, erasing the firmware. Force FLR to recover -+ * instead of a normal D0 transition. - */ -- -- if (data->pm_sx_event == PM_EVENT_FREEZE || -- data->pm_sx_event == PM_EVENT_HIBERNATE) { -+ if (mesg.event == PM_EVENT_RESTORE || -+ (mesg.event == PM_EVENT_RESUME && -+ pm_suspend_target_state == PM_SUSPEND_MEM)) { - set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags); - btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR); - return 0; -@@ -3161,7 +3164,9 @@ static int btintel_pcie_resume(struct device *dev) - /* Refer: 6.4.11.7 -> Platform power management */ - err = btintel_pcie_set_dxstate(data, BTINTEL_PCIE_STATE_D0); - -- if (err == 0) { -+ if (err) { -+ bt_dev_err(data->hdev, "Failed to set D0 state (%d)", err); -+ } else { - bt_dev_dbg(data->hdev, - "device entered into d0 state from d3 in %lld us", - ktime_to_us(ktime_get() - start)); -@@ -3190,13 +3195,28 @@ static int btintel_pcie_resume(struct device *dev) - return err; - } - -+static int btintel_pcie_resume(struct device *dev) -+{ -+ return btintel_pcie_resume_event(dev, PMSG_RESUME); -+} -+ -+static int btintel_pcie_restore(struct device *dev) -+{ -+ return btintel_pcie_resume_event(dev, PMSG_RESTORE); -+} -+ -+static int btintel_pcie_thaw(struct device *dev) -+{ -+ return btintel_pcie_resume_event(dev, PMSG_THAW); -+} -+ - static const struct dev_pm_ops btintel_pcie_pm_ops = { - .suspend = btintel_pcie_suspend, - .resume = btintel_pcie_resume, - .freeze = btintel_pcie_freeze, -- .thaw = btintel_pcie_resume, -+ .thaw = btintel_pcie_thaw, - .poweroff = btintel_pcie_hibernate, -- .restore = btintel_pcie_resume, -+ .restore = btintel_pcie_restore, - }; - - static struct pci_driver btintel_pcie_driver = { -diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h ---- a/drivers/bluetooth/btintel_pcie.h -+++ b/drivers/bluetooth/btintel_pcie.h -@@ -478,7 +478,6 @@ struct btintel_pcie_dump_header { - * @txq: TX Queue struct - * @rxq: RX Queue struct - * @alive_intr_ctxt: Alive interrupt context -- * @pm_sx_event: PM event on which system got suspended - */ - struct btintel_pcie_data { - struct pci_dev *pdev; -@@ -533,7 +532,6 @@ struct btintel_pcie_data { - enum btintel_pcie_reset_type reset_type; - struct btintel_pcie_dbgc dbgc; - struct btintel_pcie_dump_header dmp_hdr; -- u8 pm_sx_event; - u32 debug_evt_addr; - u32 debug_evt_size; - }; diff --git a/kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch.sig b/kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch.sig deleted file mode 100644 index ee77a45..0000000 Binary files a/kernel/0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch.sig and /dev/null differ diff --git a/kernel/0666-btintel-pcie-verify-serialize-dstate.patch b/kernel/0666-btintel-pcie-verify-serialize-dstate.patch deleted file mode 100644 index b1305d3..0000000 --- a/kernel/0666-btintel-pcie-verify-serialize-dstate.patch +++ /dev/null @@ -1,113 +0,0 @@ -diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c ---- a/drivers/bluetooth/btintel_pcie.c -+++ b/drivers/bluetooth/btintel_pcie.c -@@ -1012,6 +1012,10 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) - submit_rx = false; - signal_waitq = false; - -+ /* Serialize the alive_intr_ctxt claim against set_dxstate()'s -+ * register-based fallback, which can run concurrently. -+ */ -+ spin_lock(&data->irq_lock); - switch (data->alive_intr_ctxt) { - case BTINTEL_PCIE_ROM: - data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL; -@@ -1067,6 +1071,7 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) - data->alive_intr_ctxt); - break; - } -+ spin_unlock(&data->irq_lock); - - if (submit_rx) { - btintel_pcie_reset_ia(data); -@@ -3047,7 +3052,7 @@ static void btintel_pcie_coredump(struct device *dev) - - static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate) - { -- int retry = 0; -+ int retry = 0, err; - long status; - u32 dx_intr_timeout_ms = 200; - -@@ -3059,30 +3064,66 @@ static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate) - status = wait_event_timeout(data->gp0_wait_q, data->gp0_received, - msecs_to_jiffies(dx_intr_timeout_ms)); - -- if (status) -- return 0; -+ if (!status) { -+ bt_dev_warn(data->hdev, -+ "Timeout (%u ms) on alive interrupt for D%d entry, retry count %d", -+ dx_intr_timeout_ms, dxstate, retry); - -- bt_dev_warn(data->hdev, -- "Timeout (%u ms) on alive interrupt for D%d entry, retry count %d", -- dx_intr_timeout_ms, dxstate, retry); -+ /* clear gp0 cause */ -+ btintel_pcie_clr_reg_bits(data, -+ BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES, -+ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0); -+ } - -- /* clear gp0 cause */ -- btintel_pcie_clr_reg_bits(data, -- BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES, -- BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0); -- -- /* A hardware bug may cause the alive interrupt to be missed. Refresh -- * boot_stage_cache from hardware, since only the interrupt handler -- * updates it. Finally retry only if the state check still fails. -+ /* gp0_received is set at the top of the handler, before the switch on -+ * alive_intr_ctxt. Error and lockdown are filtered out above it, but a -+ * matched case can still complete without doing anything - D3 breaks -+ * unchanged while the controller has not reached D0 - and a hardware -+ * bug may drop the interrupt outright. Either way the flag says a gp0 -+ * was handled, not that the transition completed, and only the register -+ * knows. Refresh the cache here and retry only if the state check still -+ * fails. - */ - data->boot_stage_cache = btintel_pcie_rd_reg32(data, - BTINTEL_PCIE_CSR_BOOT_STAGE_REG); - if (dxstate == BTINTEL_PCIE_STATE_D0) { -- if (btintel_pcie_in_d0(data)) -+ if (btintel_pcie_in_d0(data)) { -+ bool armed; -+ -+ /* Claim the transition under irq_lock so a -+ * concurrent gp0 handler run cannot also arm RX. -+ */ -+ spin_lock(&data->irq_lock); -+ armed = data->alive_intr_ctxt == BTINTEL_PCIE_D0; -+ if (!armed) -+ data->alive_intr_ctxt = BTINTEL_PCIE_D0; -+ spin_unlock(&data->irq_lock); -+ -+ if (armed) -+ return 0; -+ -+ /* Do what the handler's D3 -> D0 branch -+ * would have done, unless it already has. -+ */ -+ btintel_pcie_reset_ia(data); -+ err = btintel_pcie_start_rx(data); -+ if (err) -+ return err; -+ - return 0; -+ } - } else { -- if (btintel_pcie_in_d3(data)) -+ if (btintel_pcie_in_d3(data)) { -+ /* Do what the handler's D0 -> D3 branch -+ * would have done, unless it already has. -+ */ -+ spin_lock(&data->irq_lock); -+ if (data->alive_intr_ctxt != BTINTEL_PCIE_D3) -+ data->alive_intr_ctxt = BTINTEL_PCIE_D3; -+ spin_unlock(&data->irq_lock); -+ - return 0; -+ } - } - - } while (++retry < BTINTEL_PCIE_DX_TRANSITION_MAX_RETRIES); diff --git a/kernel/0666-btintel-pcie-verify-serialize-dstate.patch.sig b/kernel/0666-btintel-pcie-verify-serialize-dstate.patch.sig deleted file mode 100644 index 11d5690..0000000 Binary files a/kernel/0666-btintel-pcie-verify-serialize-dstate.patch.sig and /dev/null differ diff --git a/kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch b/kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch deleted file mode 100644 index 9927412..0000000 --- a/kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c ---- a/drivers/bluetooth/btintel_pcie.c -+++ b/drivers/bluetooth/btintel_pcie.c -@@ -3069,10 +3069,12 @@ static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate) - "Timeout (%u ms) on alive interrupt for D%d entry, retry count %d", - dx_intr_timeout_ms, dxstate, retry); - -- /* clear gp0 cause */ -- btintel_pcie_clr_reg_bits(data, -- BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES, -- BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0); -+ /* MSIX_HW_INT_CAUSES is W1C. Write only GP0 so other -+ * pending causes are not acknowledged here. -+ */ -+ btintel_pcie_wr_reg32(data, -+ BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES, -+ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0); - } - - /* gp0_received is set at the top of the handler, before the switch on diff --git a/kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch.sig b/kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch.sig deleted file mode 100644 index 0b81f4e..0000000 Binary files a/kernel/0667-btintel-pcie-gp0-cause-w1c-write.patch.sig and /dev/null differ diff --git a/kernel/0668-btintel-pcie-dstate-races.patch b/kernel/0668-btintel-pcie-dstate-races.patch deleted file mode 100644 index d25c602..0000000 --- a/kernel/0668-btintel-pcie-dstate-races.patch +++ /dev/null @@ -1,86 +0,0 @@ -diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c ---- a/drivers/bluetooth/btintel_pcie.c -+++ b/drivers/bluetooth/btintel_pcie.c -@@ -1016,6 +1016,8 @@ static void btintel_pcie_msix_gp0_handle - * register-based fallback, which can run concurrently. - */ - spin_lock(&data->irq_lock); -+ data->boot_stage_cache = btintel_pcie_rd_reg32(data, -+ BTINTEL_PCIE_CSR_BOOT_STAGE_REG); - switch (data->alive_intr_ctxt) { - case BTINTEL_PCIE_ROM: - data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL; -@@ -1071,12 +1073,12 @@ static void btintel_pcie_msix_gp0_handle - data->alive_intr_ctxt); - break; - } -- spin_unlock(&data->irq_lock); - - if (submit_rx) { - btintel_pcie_reset_ia(data); - btintel_pcie_start_rx(data); - } -+ spin_unlock(&data->irq_lock); - - if (signal_waitq) { - bt_dev_dbg(data->hdev, "wake up gp0 wait_q"); -@@ -3086,40 +3088,34 @@ static int btintel_pcie_set_dxstate(stru - * knows. Refresh the cache here and retry only if the state check still - * fails. - */ -+ spin_lock(&data->irq_lock); - data->boot_stage_cache = btintel_pcie_rd_reg32(data, - BTINTEL_PCIE_CSR_BOOT_STAGE_REG); - if (dxstate == BTINTEL_PCIE_STATE_D0) { - if (btintel_pcie_in_d0(data)) { -- bool armed; -+ err = 0; - - /* Claim the transition under irq_lock so a - * concurrent gp0 handler run cannot also arm RX. - */ -- spin_lock(&data->irq_lock); -- armed = data->alive_intr_ctxt == BTINTEL_PCIE_D0; -- if (!armed) -+ if (data->alive_intr_ctxt != BTINTEL_PCIE_D0) { - data->alive_intr_ctxt = BTINTEL_PCIE_D0; -- spin_unlock(&data->irq_lock); - -- if (armed) -- return 0; -- -- /* Do what the handler's D3 -> D0 branch -- * would have done, unless it already has. -- */ -- btintel_pcie_reset_ia(data); -- err = btintel_pcie_start_rx(data); -- if (err) -- return err; -+ /* Do what the handler's D3 -> D0 branch -+ * would have done, unless it already has. -+ */ -+ btintel_pcie_reset_ia(data); -+ err = btintel_pcie_start_rx(data); -+ } -+ spin_unlock(&data->irq_lock); - -- return 0; -+ return err; - } - } else { - if (btintel_pcie_in_d3(data)) { - /* Do what the handler's D0 -> D3 branch - * would have done, unless it already has. - */ -- spin_lock(&data->irq_lock); - if (data->alive_intr_ctxt != BTINTEL_PCIE_D3) - data->alive_intr_ctxt = BTINTEL_PCIE_D3; - spin_unlock(&data->irq_lock); -@@ -3127,6 +3123,7 @@ static int btintel_pcie_set_dxstate(stru - return 0; - } - } -+ spin_unlock(&data->irq_lock); - - } while (++retry < BTINTEL_PCIE_DX_TRANSITION_MAX_RETRIES); - diff --git a/kernel/0668-btintel-pcie-dstate-races.patch.sig b/kernel/0668-btintel-pcie-dstate-races.patch.sig deleted file mode 100644 index f910b39..0000000 Binary files a/kernel/0668-btintel-pcie-dstate-races.patch.sig and /dev/null differ diff --git a/kernel/0669-btintel-version-tlv-parse-errors.patch b/kernel/0669-btintel-version-tlv-parse-errors.patch deleted file mode 100644 index 164dbb6..0000000 --- a/kernel/0669-btintel-version-tlv-parse-errors.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c ---- a/drivers/bluetooth/btintel.c -+++ b/drivers/bluetooth/btintel.c -@@ -720,6 +720,7 @@ static int btintel_read_version_tlv(struct hci_dev *hdev, - { - struct sk_buff *skb; - const u8 param[1] = { 0xFF }; -+ int err; - - if (!version) - return -EINVAL; -@@ -738,10 +739,10 @@ static int btintel_read_version_tlv(struct hci_dev *hdev, - return -EIO; - } - -- btintel_parse_version_tlv(hdev, version, skb); -+ err = btintel_parse_version_tlv(hdev, version, skb); - - kfree_skb(skb); -- return 0; -+ return err; - } - - /* ------- REGMAP IBT SUPPORT ------- */ diff --git a/kernel/0669-btintel-version-tlv-parse-errors.patch.sig b/kernel/0669-btintel-version-tlv-parse-errors.patch.sig deleted file mode 100644 index b8e7e45..0000000 Binary files a/kernel/0669-btintel-version-tlv-parse-errors.patch.sig and /dev/null differ diff --git a/kernel/0670-bluetooth-fixes.patch b/kernel/0670-bluetooth-fixes.patch deleted file mode 100644 index 14623cd..0000000 --- a/kernel/0670-bluetooth-fixes.patch +++ /dev/null @@ -1,485 +0,0 @@ -diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c ---- a/drivers/bluetooth/btintel.c -+++ b/drivers/bluetooth/btintel.c -@@ -288,7 +288,8 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) - goto unlock; - } - -- bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1)); -+ bt_dev_err(hdev, "Exception info %.*s", (int)(skb->len - 1), -+ (char *)(skb->data + 1)); - - kfree_skb(skb); - -@@ -407,8 +408,16 @@ int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name) - /* DDC file contains one or more DDC structure which has - * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). - */ -- while (fw->size > fw_ptr - fw->data) { -- u8 cmd_plen = fw_ptr[0] + sizeof(u8); -+ while (fw->size > (size_t)(fw_ptr - fw->data)) { -+ size_t remaining = fw->size - (fw_ptr - fw->data); -+ unsigned int cmd_plen = fw_ptr[0] + 1U; -+ -+ if (cmd_plen < 3 || cmd_plen > U8_MAX || cmd_plen > remaining) { -+ bt_dev_err(hdev, "Malformed DDC record (plen=%u, remaining=%zu)", -+ cmd_plen, remaining); -+ release_firmware(fw); -+ return -EINVAL; -+ } - - skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr, - HCI_INIT_TIMEOUT); -diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c ---- a/drivers/bluetooth/btintel_pcie.c -+++ b/drivers/bluetooth/btintel_pcie.c -@@ -1200,7 +1200,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data, - { - int ret; - u8 pkt_type; -- u16 plen; -+ u32 plen; - u32 pcie_pkt_type; - void *pdata; - struct hci_dev *hdev = data->hdev; -@@ -2149,6 +2149,16 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, - if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags)) - return -ENODEV; - -+ /* Account for the 4-byte PCIe type header prepended before the -+ * DMA copy. Written as a subtraction to avoid wrap-around on -+ * attacker-controlled skb->len. -+ */ -+ if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) { -+ bt_dev_err(hdev, "Packet too large: %u > %u", skb->len, -+ BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN); -+ return -EMSGSIZE; -+ } -+ - /* Due to the fw limitation, the type header of the packet should be - * 4 bytes unlike 1 byte for UART. In UART, the firmware can read - * the first byte to get the packet type and redirect the rest of data -diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h ---- a/include/net/bluetooth/hci_core.h -+++ b/include/net/bluetooth/hci_core.h -@@ -62,7 +62,7 @@ struct inquiry_entry { - NAME_PENDING, - NAME_KNOWN, - } name_state; -- __u32 timestamp; -+ unsigned long timestamp; - struct inquiry_data data; - }; - -@@ -78,7 +78,7 @@ struct discovery_state { - struct list_head all; /* All devices found during inquiry */ - struct list_head unknown; /* Name state not known */ - struct list_head resolve; /* Name needs to be resolved */ -- __u32 timestamp; -+ unsigned long timestamp; - bdaddr_t last_adv_addr; - u8 last_adv_addr_type; - s8 last_adv_rssi; -@@ -561,6 +561,7 @@ struct hci_dev { - struct list_head link_keys; - struct list_head long_term_keys; - struct list_head identity_resolving_keys; -+ struct mutex remote_oob_lock; - struct list_head remote_oob_data; - struct list_head le_accept_list; - struct list_head le_resolv_list; -diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -302,11 +302,13 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) - cp.tx_bandwidth = cpu_to_le32(0x00001f40); - cp.rx_bandwidth = cpu_to_le32(0x00001f40); - -+ hci_dev_lock(hdev); -+ - switch (conn->codec.id) { - case BT_CODEC_MSBC: - if (!find_next_esco_param(conn, esco_param_msbc, - ARRAY_SIZE(esco_param_msbc))) -- return -EINVAL; -+ goto unlock; - - param = &esco_param_msbc[conn->attempt - 1]; - cp.tx_coding_format.id = 0x05; -@@ -332,7 +334,7 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) - case BT_CODEC_TRANSPARENT: - if (!find_next_esco_param(conn, esco_param_msbc, - ARRAY_SIZE(esco_param_msbc))) -- return -EINVAL; -+ goto unlock; - - param = &esco_param_msbc[conn->attempt - 1]; - cp.tx_coding_format.id = 0x03; -@@ -359,11 +361,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) - if (conn->parent && lmp_esco_capable(conn->parent)) { - if (!find_next_esco_param(conn, esco_param_cvsd, - ARRAY_SIZE(esco_param_cvsd))) -- return -EINVAL; -+ goto unlock; - param = &esco_param_cvsd[conn->attempt - 1]; - } else { - if (conn->attempt > ARRAY_SIZE(sco_param_cvsd)) -- return -EINVAL; -+ goto unlock; - param = &sco_param_cvsd[conn->attempt - 1]; - } - cp.tx_coding_format.id = 2; -@@ -386,9 +388,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) - cp.out_transport_unit_size = 16; - break; - default: -- return -EINVAL; -+ goto unlock; - } - -+ hci_dev_unlock(hdev); -+ - cp.retrans_effort = param->retrans_effort; - cp.pkt_type = __cpu_to_le16(param->pkt_type); - cp.max_latency = __cpu_to_le16(param->max_latency); -@@ -397,6 +401,10 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) - return -EIO; - - return 0; -+ -+unlock: -+ hci_dev_unlock(hdev); -+ return -EINVAL; - } - - static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle) -diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c ---- a/net/bluetooth/hci_core.c -+++ b/net/bluetooth/hci_core.c -@@ -1486,8 +1486,10 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, - - BT_DBG("%s removing %pMR (%u)", hdev->name, bdaddr, bdaddr_type); - -+ mutex_lock(&hdev->remote_oob_lock); - list_del(&data->list); - kfree(data); -+ mutex_unlock(&hdev->remote_oob_lock); - - return 0; - } -@@ -1496,10 +1498,12 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev) - { - struct oob_data *data, *n; - -+ mutex_lock(&hdev->remote_oob_lock); - list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) { - list_del(&data->list); - kfree(data); - } -+ mutex_unlock(&hdev->remote_oob_lock); - } - - int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, -@@ -1508,11 +1512,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, - { - struct oob_data *data; - -+ mutex_lock(&hdev->remote_oob_lock); - data = hci_find_remote_oob_data(hdev, bdaddr, bdaddr_type); - if (!data) { - data = kmalloc_obj(*data); -- if (!data) -+ if (!data) { -+ mutex_unlock(&hdev->remote_oob_lock); - return -ENOMEM; -+ } - - bacpy(&data->bdaddr, bdaddr); - data->bdaddr_type = bdaddr_type; -@@ -1545,6 +1552,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, - - BT_DBG("%s for %pMR", hdev->name, bdaddr); - -+ mutex_unlock(&hdev->remote_oob_lock); -+ - return 0; - } - -@@ -2482,6 +2491,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) - mutex_init(&hdev->lock); - mutex_init(&hdev->req_lock); - mutex_init(&hdev->mgmt_pending_lock); -+ mutex_init(&hdev->remote_oob_lock); - - ida_init(&hdev->unset_handle_ida); - -@@ -2554,8 +2564,10 @@ int hci_register_dev(struct hci_dev *hdev) - return id; - - error = dev_set_name(&hdev->dev, "hci%u", id); -- if (error) -+ if (error) { -+ ida_free(&hci_index_ida, id); - return error; -+ } - - hdev->name = dev_name(&hdev->dev); - hdev->id = id; -@@ -3323,6 +3335,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue, - - skb_shinfo(skb)->frag_list = NULL; - -+ spin_lock_bh(&queue->lock); -+ - __skb_queue_tail(queue, skb); - - do { -@@ -3337,6 +3351,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue, - - __skb_queue_tail(queue, skb); - } while (list); -+ -+ spin_unlock_bh(&queue->lock); - } - - bt_dev_dbg(hdev, "hcon %p queued %d", conn, skb_queue_len(queue)); -@@ -3400,9 +3416,6 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, - struct hci_conn *conn = NULL, *c; - unsigned int num = 0, min = ~0; - -- /* We don't have to lock device here. Connections are always -- * added and removed with TX task disabled. */ -- - rcu_read_lock(); - - list_for_each_entry_rcu(c, &h->list, list) { -@@ -3607,13 +3620,15 @@ static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type) - } - - /* Schedule SCO */ --static void hci_sched_sco(struct hci_dev *hdev, __u8 type) -+static void __hci_sched_sco(struct hci_dev *hdev, __u8 type) - { - struct hci_conn *conn; - struct sk_buff *skb; - int quote, *cnt; - unsigned int pkts = hdev->sco_pkts; - -+ lockdep_assert_held(&hdev->lock); -+ - bt_dev_dbg(hdev, "type %u", type); - - if (!hci_conn_num(hdev, type) || !pkts) -@@ -3648,6 +3663,13 @@ static void hci_sched_sco(struct hci_dev *hdev, __u8 type) - queue_work(hdev->workqueue, &hdev->tx_work); - } - -+static void hci_sched_sco(struct hci_dev *hdev, __u8 type) -+{ -+ hci_dev_lock(hdev); -+ __hci_sched_sco(hdev, type); -+ hci_dev_unlock(hdev); -+} -+ - static void hci_sched_acl_pkt(struct hci_dev *hdev) - { - unsigned int cnt = hdev->acl_cnt; -@@ -3657,6 +3679,8 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) - - __check_timeout(hdev, cnt, ACL_LINK); - -+ hci_dev_lock(hdev); -+ - while (hdev->acl_cnt && - (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { - u32 priority = (skb_peek(&chan->data_q))->priority; -@@ -3681,13 +3705,15 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) - chan->conn->sent++; - - /* Send pending SCO packets right away */ -- hci_sched_sco(hdev, SCO_LINK); -- hci_sched_sco(hdev, ESCO_LINK); -+ __hci_sched_sco(hdev, SCO_LINK); -+ __hci_sched_sco(hdev, ESCO_LINK); - } - } - - if (cnt != hdev->acl_cnt) - hci_prio_recalculate(hdev, ACL_LINK); -+ -+ hci_dev_unlock(hdev); - } - - static void hci_sched_acl(struct hci_dev *hdev) -@@ -3716,6 +3742,8 @@ static void hci_sched_le(struct hci_dev *hdev) - - __check_timeout(hdev, *cnt, LE_LINK); - -+ hci_dev_lock(hdev); -+ - tmp = *cnt; - while (*cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) { - u32 priority = (skb_peek(&chan->data_q))->priority; -@@ -3737,13 +3765,15 @@ static void hci_sched_le(struct hci_dev *hdev) - chan->conn->sent++; - - /* Send pending SCO packets right away */ -- hci_sched_sco(hdev, SCO_LINK); -- hci_sched_sco(hdev, ESCO_LINK); -+ __hci_sched_sco(hdev, SCO_LINK); -+ __hci_sched_sco(hdev, ESCO_LINK); - } - } - - if (*cnt != tmp) - hci_prio_recalculate(hdev, LE_LINK); -+ -+ hci_dev_unlock(hdev); - } - - /* Schedule iso */ -@@ -3762,6 +3792,8 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type) - - __check_timeout(hdev, *cnt, type); - -+ hci_dev_lock(hdev); -+ - while (*cnt && (conn = hci_low_sent(hdev, type, "e))) { - while (quote-- && (skb = skb_dequeue(&conn->data_q))) { - BT_DBG("skb %p len %d", skb, skb->len); -@@ -3775,6 +3807,8 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type) - (*cnt)--; - } - } -+ -+ hci_dev_unlock(hdev); - } - - static void hci_tx_work(struct work_struct *work) -diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c ---- a/net/bluetooth/hci_debugfs.c -+++ b/net/bluetooth/hci_debugfs.c -@@ -364,7 +364,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) - - list_for_each_entry(e, &cache->all, all) { - struct inquiry_data *data = &e->data; -- seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", -+ seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %lu\n", - &data->bdaddr, - data->pscan_rep_mode, data->pscan_period_mode, - data->pscan_mode, data->dev_class[2], -diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c ---- a/net/bluetooth/hci_sync.c -+++ b/net/bluetooth/hci_sync.c -@@ -312,6 +312,10 @@ static void hci_cmd_sync_work(struct work_struct *work) - while (1) { - struct hci_cmd_sync_work_entry *entry; - -+ /* Leave the backlog to hci_cmd_sync_clear() */ -+ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) -+ break; -+ - mutex_lock(&hdev->cmd_sync_work_lock); - entry = list_first_entry_or_null(&hdev->cmd_sync_work_list, - struct hci_cmd_sync_work_entry, -@@ -658,6 +662,8 @@ void hci_cmd_sync_clear(struct hci_dev *hdev) - { - struct hci_cmd_sync_work_entry *entry, *tmp; - -+ /* cmd_work is disabled, the pending request can only time out */ -+ hci_cmd_sync_cancel_sync(hdev, ENODEV); - cancel_work_sync(&hdev->cmd_sync_work); - cancel_work_sync(&hdev->reenable_adv_work); - -@@ -5678,6 +5684,7 @@ int hci_stop_discovery_sync(struct hci_dev *hdev) - { - struct discovery_state *d = &hdev->discovery; - struct inquiry_entry *e; -+ bdaddr_t addr; - int err; - - bt_dev_dbg(hdev, "state %u", hdev->discovery.state); -@@ -5713,15 +5720,21 @@ int hci_stop_discovery_sync(struct hci_dev *hdev) - return 0; - - if (d->state == DISCOVERY_RESOLVING || d->state == DISCOVERY_STOPPING) { -+ hci_dev_lock(hdev); - e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, - NAME_PENDING); -- if (!e) -+ if (!e) { -+ hci_dev_unlock(hdev); - return 0; -+ } -+ -+ bacpy(&addr, &e->data.bdaddr); -+ hci_dev_unlock(hdev); - - /* Ignore cancel errors since it should interfere with stopping - * of the discovery. - */ -- hci_remote_name_cancel_sync(hdev, &e->data.bdaddr); -+ hci_remote_name_cancel_sync(hdev, &addr); - } - - return 0; -@@ -7151,6 +7164,7 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) - bacpy(&cp.bdaddr, &conn->dst); - cp.pscan_rep_mode = 0x02; - -+ hci_dev_lock(hdev); - ie = hci_inquiry_cache_lookup(hdev, &conn->dst); - if (ie) { - if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { -@@ -7162,6 +7176,7 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) - - memcpy(conn->dev_class, ie->data.dev_class, 3); - } -+ hci_dev_unlock(hdev); - - cp.pkt_type = cpu_to_le16(conn->pkt_type); - if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) -diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c ---- a/net/bluetooth/rfcomm/tty.c -+++ b/net/bluetooth/rfcomm/tty.c -@@ -462,7 +462,7 @@ static int __rfcomm_release_dev(void __user *arg) - /* Shut down TTY synchronously before freeing rfcomm_dev */ - tty_port_tty_vhangup(&dev->port); - -- if (!test_bit(RFCOMM_TTY_OWNED, &dev->status)) -+ if (!test_and_set_bit(RFCOMM_TTY_OWNED, &dev->status)) - tty_port_put(&dev->port); - - tty_port_put(&dev->port); -@@ -724,10 +724,9 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) - * when the last process closes the tty. The behaviour is expected by - * userspace. - */ -- if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { -- set_bit(RFCOMM_TTY_OWNED, &dev->status); -+ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && -+ !test_and_set_bit(RFCOMM_TTY_OWNED, &dev->status)) - tty_port_put(&dev->port); -- } - - return 0; - } -diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c ---- a/net/bluetooth/smp.c -+++ b/net/bluetooth/smp.c -@@ -661,6 +661,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, - else - bdaddr_type = BDADDR_LE_RANDOM; - -+ mutex_lock(&hdev->remote_oob_lock); - oob_data = hci_find_remote_oob_data(hdev, &hcon->dst, - bdaddr_type); - if (oob_data && oob_data->present) { -@@ -671,6 +672,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, - SMP_DBG("OOB Remote Confirmation: %16phN", smp->pcnf); - SMP_DBG("OOB Remote Random: %16phN", smp->rr); - } -+ mutex_unlock(&hdev->remote_oob_lock); - - } else { - authreq &= ~SMP_AUTH_SC; diff --git a/kernel/0670-bluetooth-fixes.patch.sig b/kernel/0670-bluetooth-fixes.patch.sig deleted file mode 100644 index a680e2e..0000000 Binary files a/kernel/0670-bluetooth-fixes.patch.sig and /dev/null differ diff --git a/kernel/0700-pci-target-speed-quirk.patch b/kernel/0700-pci-target-speed-quirk.patch deleted file mode 100644 index 1102b3f..0000000 --- a/kernel/0700-pci-target-speed-quirk.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -108,7 +108,11 @@ int pcie_failed_link_retrain(struct pci_dev *dev) - - pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); - pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2); -- if (!(lnksta & PCI_EXP_LNKSTA_DLLLA) && pcie_lbms_seen(dev, lnksta)) { -+ if (lnksta & PCI_EXP_LNKSTA_DLLLA) { -+ ; -+ } else if (PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2) == PCIE_SPEED_2_5GT) { -+ return ret; -+ } else if (pcie_lbms_seen(dev, lnksta)) { - pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n"); - ret = pcie_set_target_speed(dev, PCIE_SPEED_2_5GT, false); - if (ret) diff --git a/kernel/0700-pci-target-speed-quirk.patch.sig b/kernel/0700-pci-target-speed-quirk.patch.sig deleted file mode 100644 index 897fa75..0000000 Binary files a/kernel/0700-pci-target-speed-quirk.patch.sig and /dev/null differ diff --git a/kernel/0701-pci-amd-enhanced-atomics.patch b/kernel/0701-pci-amd-enhanced-atomics.patch deleted file mode 100644 index c76cb96..0000000 --- a/kernel/0701-pci-amd-enhanced-atomics.patch +++ /dev/null @@ -1,109 +0,0 @@ -diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c ---- a/arch/x86/pci/fixup.c -+++ b/arch/x86/pci/fixup.c -@@ -886,6 +886,105 @@ static void quirk_clear_strap_no_soft_reset_dev2_f0(struct pci_dev *dev) - } - } - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15b8, quirk_clear_strap_no_soft_reset_dev2_f0); -+ -+/* -+ * Enhanced atomic operations can cause corruption with 64-bit IOVA -+ * on these devices. -+ */ -+#define RX_ENH_ATOMIC_EN BIT(8) -+ -+static const u32 nbio_7_7_pcie_smn_addrs[] = { -+ 0x111401d0, -+ 0x111411d0, -+ 0x111421d0, -+ 0x111431d0, -+ 0x111441d0, -+ 0x112401d0, -+ 0x112411d0, -+ 0x112421d0, -+ 0x112431d0, -+ 0x112441d0, -+ 0x112451d0, -+ 0x113401d0, -+ 0x114401d0, -+}; -+ -+static const u32 nbio_7_11_pcie_smn_addrs[] = { -+ 0x112401d0, -+ 0x112411d0, -+ 0x112421d0, -+ 0x112431d0, -+ 0x112441d0, -+ 0x112451d0, -+ 0x113401d0, -+ 0x113411d0, -+ 0x113421d0, -+ 0x113431d0, -+ 0x113441d0, -+ 0x113451d0, -+}; -+ -+static void quirk_amd_nbio_enhanced_atomic(struct pci_dev *host_bridge, -+ const u32 *smn_addrs, -+ size_t nr_smn_addrs) -+{ -+ bool changed = false; -+ size_t i; -+ u32 data; -+ int ret; -+ -+ for (i = 0; i < nr_smn_addrs; i++) { -+ ret = amd_smn_read(0, smn_addrs[i], &data); -+ if (ret) -+ continue; -+ if (!(data & RX_ENH_ATOMIC_EN)) -+ continue; -+ data = data & ~RX_ENH_ATOMIC_EN; -+ ret = amd_smn_write(0, smn_addrs[i], data); -+ if (ret) -+ continue; -+ if (changed) -+ continue; -+ ret = amd_smn_read(0, smn_addrs[i], &data); -+ if (ret) -+ continue; -+ if (data & RX_ENH_ATOMIC_EN) -+ continue; -+ changed = true; -+ } -+ -+ if (changed) -+ pci_info(host_bridge, "enhanced atomics disabled\n"); -+} -+ -+static void quirk_amd_nbio_7_7_disable_enhanced_atomic(struct pci_dev *dev) -+{ -+ quirk_amd_nbio_enhanced_atomic(dev, nbio_7_7_pcie_smn_addrs, -+ ARRAY_SIZE(nbio_7_7_pcie_smn_addrs)); -+} -+ -+static void quirk_amd_nbio_7_11_disable_enhanced_atomic(struct pci_dev *dev) -+{ -+ quirk_amd_nbio_enhanced_atomic(dev, nbio_7_11_pcie_smn_addrs, -+ ARRAY_SIZE(nbio_7_11_pcie_smn_addrs)); -+} -+ -+/* Phoenix, Hawk Point (NBIO 7.7) */ -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x14E8, -+ quirk_amd_nbio_7_7_disable_enhanced_atomic); -+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x14E8, -+ quirk_amd_nbio_7_7_disable_enhanced_atomic); -+ -+/* Strix, Krackan, Strix Halo (NBIO 7.11) */ -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1507, -+ quirk_amd_nbio_7_11_disable_enhanced_atomic); -+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1507, -+ quirk_amd_nbio_7_11_disable_enhanced_atomic); -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1122, -+ quirk_amd_nbio_7_11_disable_enhanced_atomic); -+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1122, -+ quirk_amd_nbio_7_11_disable_enhanced_atomic); -+ - #endif - - /* diff --git a/kernel/0701-pci-amd-enhanced-atomics.patch.sig b/kernel/0701-pci-amd-enhanced-atomics.patch.sig deleted file mode 100644 index f5360e4..0000000 Binary files a/kernel/0701-pci-amd-enhanced-atomics.patch.sig and /dev/null differ diff --git a/kernel/0702-ahci-jmb585-32bit-dma-revert.patch b/kernel/0702-ahci-jmb585-32bit-dma-revert.patch deleted file mode 100644 index 9794028..0000000 --- a/kernel/0702-ahci-jmb585-32bit-dma-revert.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c ---- a/drivers/ata/ahci.c -+++ b/drivers/ata/ahci.c -@@ -68,7 +68,6 @@ enum board_ids { - /* board IDs for specific chipsets in alphabetical order */ - board_ahci_al, - board_ahci_avn, -- board_ahci_jmb585, - board_ahci_mcp65, - board_ahci_mcp77, - board_ahci_mcp89, -@@ -213,15 +212,6 @@ static const struct ata_port_info ahci_port_info[] = { - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_avn_ops, - }, -- /* JMicron JMB582/585: 64-bit DMA is broken, force 32-bit */ -- [board_ahci_jmb585] = { -- AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR | -- AHCI_HFLAG_32BIT_ONLY), -- .flags = AHCI_FLAG_COMMON, -- .pio_mask = ATA_PIO4, -- .udma_mask = ATA_UDMA6, -- .port_ops = &ahci_ops, -- }, - [board_ahci_mcp65] = { - AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | - AHCI_HFLAG_YES_NCQ), -@@ -954,14 +944,6 @@ static const struct pci_device_id ahci_pci_tbl[] = { - /* Elkhart Lake AHCI */ - PCI_VDEVICE(INTEL, 0x4b63), - .driver_data = board_ahci_pcs_quirk, -- }, { -- /* JMicron JMB582/585: force 32-bit DMA (broken 64-bit implementation) */ -- PCI_VDEVICE(JMICRON, 0x0582), -- .driver_data = board_ahci_jmb585, -- -- }, { -- PCI_VDEVICE(JMICRON, 0x0585), -- .driver_data = board_ahci_jmb585, - }, { - /* JMicron 360/1/3/5/6, match class to avoid IDE function */ - PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID), diff --git a/kernel/0702-ahci-jmb585-32bit-dma-revert.patch.sig b/kernel/0702-ahci-jmb585-32bit-dma-revert.patch.sig deleted file mode 100644 index b59d6ba..0000000 Binary files a/kernel/0702-ahci-jmb585-32bit-dma-revert.patch.sig and /dev/null differ diff --git a/kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch b/kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch deleted file mode 100644 index 0fe6c04..0000000 --- a/kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch +++ /dev/null @@ -1,297 +0,0 @@ -diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c ---- a/drivers/pci/controller/vmd.c -+++ b/drivers/pci/controller/vmd.c -@@ -37,6 +37,12 @@ - #define MB2_SHADOW_OFFSET 0x2000 - #define MB2_SHADOW_SIZE 16 - -+/* DMR BAR4 register offsets */ -+#define SHADOW_MEMBAR1_28C1 0x2818 /* MEMBAR1 physical address */ -+#define SHADOW_MEMBAR2_28C1 0x2820 /* MEMBAR2 physical address */ -+#define BASE_ID_REG_28C1 0x2840 -+#define MEMBAR2_OFFSET_28C1 0x30d0 -+ - enum vmd_features { - /* - * Device may contain registers which hint the physical location of the -@@ -77,6 +83,15 @@ enum vmd_features { - * proper power management of the SoC. - */ - VMD_FEAT_BIOS_PM_QUIRK = (1 << 5), -+ -+ /* -+ * Newer VMD with device ID 0x28C1 has unique settings compared to its -+ * predecessor where BIOS enumerates the entire VMD device tree and -+ * stores respective configurations including bus start range and -+ * shadow registers in VMD MMIO space in VMD BAR4/BAR5, otherwise -+ * referred to as MEMBAR2 or MSI-X BAR. -+ */ -+ VMD_FEAT_USE_BIOS_INFO = (1 << 6), - }; - - #define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */ -@@ -142,6 +157,7 @@ struct vmd_dev { - u8 first_vec; - char *name; - int instance; -+ unsigned long features; - }; - - static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus) -@@ -366,6 +382,9 @@ static void vmd_set_msi_remapping(struct vmd_dev *vmd, bool enable) - { - u16 reg; - -+ if (!!(vmd->features & VMD_FEAT_USE_BIOS_INFO)) -+ return; -+ - pci_read_config_word(vmd->dev, PCI_REG_VMCONFIG, ®); - reg = enable ? (reg & ~VMCONFIG_MSI_REMAP) : - (reg | VMCONFIG_MSI_REMAP); -@@ -389,11 +408,22 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd) - } - } - -+static unsigned int vmd_bus_to_ecam(struct vmd_dev *vmd, unsigned int busnr) -+{ -+ if (!!(vmd->features & VMD_FEAT_USE_BIOS_INFO)) -+ return busnr; -+ -+ return busnr - vmd->busn_start; -+} -+ - static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, - unsigned int devfn, int reg, int len) - { -- unsigned int busnr_ecam = bus->number - vmd->busn_start; -- u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg); -+ unsigned int busnr_ecam; -+ u32 offset; -+ -+ busnr_ecam = vmd_bus_to_ecam(vmd, bus->number); -+ offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg); - - if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR])) - return NULL; -@@ -518,22 +548,37 @@ static inline void vmd_acpi_begin(void) { } - static inline void vmd_acpi_end(void) { } - #endif /* CONFIG_ACPI */ - -+static resource_size_t vmd_cfgbar_ecam_space(struct vmd_dev *vmd) -+{ -+ resource_size_t cfgbar_buses; -+ unsigned int ecam_start; -+ -+ cfgbar_buses = resource_size(&vmd->dev->resource[VMD_CFGBAR]) >> 20; -+ ecam_start = vmd_bus_to_ecam(vmd, vmd->resources[0].start); -+ if (ecam_start >= cfgbar_buses) -+ return 0; -+ -+ return cfgbar_buses - ecam_start; -+} - static void vmd_domain_reset(struct vmd_dev *vmd) - { - u16 bus, max_buses = resource_size(&vmd->resources[0]); - u8 dev, functions, fn, hdr_type; -+ unsigned int ecam_bus; - char __iomem *base; - -+ max_buses = min_t(u16, max_buses, vmd_cfgbar_ecam_space(vmd)); - for (bus = 0; bus < max_buses; bus++) { -+ ecam_bus = vmd_bus_to_ecam(vmd, vmd->resources[0].start + bus); - for (dev = 0; dev < 32; dev++) { -- base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus, -+ base = vmd->cfgbar + PCIE_ECAM_OFFSET(ecam_bus, - PCI_DEVFN(dev, 0), 0); - - hdr_type = readb(base + PCI_HEADER_TYPE); - - functions = (hdr_type & PCI_HEADER_TYPE_MFD) ? 8 : 1; - for (fn = 0; fn < functions; fn++) { -- base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus, -+ base = vmd->cfgbar + PCIE_ECAM_OFFSET(ecam_bus, - PCI_DEVFN(dev, fn), 0); - - hdr_type = readb(base + PCI_HEADER_TYPE) & -@@ -661,6 +706,46 @@ static int vmd_get_bus_number_start(struct vmd_dev *vmd) - return 0; - } - -+static int vmd_get_bus_info_from_bar4(struct vmd_dev *vmd, -+ resource_size_t *offset1, -+ resource_size_t *offset2) -+{ -+ u64 phys1, phys2, bar4_2840; -+ void __iomem *bar4; -+ u32 base_id; -+ u8 base_bus; -+ -+ bar4 = pci_ioremap_bar(vmd->dev, 4); -+ if (!bar4) -+ return -ENOMEM; -+ -+ /* Read shadow registers for MEMBAR1 and MEMBAR2 physical addresses */ -+ phys1 = readq(bar4 + SHADOW_MEMBAR1_28C1); -+ phys2 = readq(bar4 + SHADOW_MEMBAR2_28C1); -+ -+ /* -+ * Read and set bus start number from Base ID register. 24-bit Base ID -+ * register is part of 64-bit shadowed reqid hide range register and -+ * holds segment, bus, device and function. -+ */ -+ bar4_2840 = readq(bar4 + BASE_ID_REG_28C1); -+ base_id = bar4_2840 & 0xFFFFFF; -+ base_bus = base_id >> 8; -+ vmd->busn_start = base_bus; -+ -+ /* Calculate offsets like vmd_get_phys_offsets() does */ -+ if (phys1) -+ *offset1 = vmd->dev->resource[VMD_MEMBAR1].start - -+ (phys1 & PCI_BASE_ADDRESS_MEM_MASK); -+ if (phys2) -+ *offset2 = vmd->dev->resource[VMD_MEMBAR2].start - -+ (phys2 & PCI_BASE_ADDRESS_MEM_MASK); -+ -+ pci_iounmap(vmd->dev, bar4); -+ -+ return 0; -+} -+ - static irqreturn_t vmd_irq(int irq, void *data) - { - struct vmd_irq_list *irqs = data; -@@ -711,6 +796,52 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd) - return 0; - } - -+static int vmd_prepare_offsets_and_bus(struct vmd_dev *vmd, -+ unsigned long features, -+ resource_size_t *membar2_offset, -+ resource_size_t *offset1, -+ resource_size_t *offset2) -+{ -+ int ret; -+ -+ /* -+ * Shadow registers may exist in certain VMD device IDs which allow -+ * guests to correctly assign host physical addresses to the root ports -+ * and child devices. These registers will either return the host value -+ * or 0, depending on an enable bit in the VMD device. -+ * -+ * For certain VMD devices (i.e. 0x28C1), BIOS places device info -+ * in BAR4 shadow registers to determine the base bus number and memory -+ * offsets. -+ */ -+ if (features & VMD_FEAT_USE_BIOS_INFO) { -+ *membar2_offset = MEMBAR2_OFFSET_28C1; -+ ret = vmd_get_bus_info_from_bar4(vmd, offset1, offset2); -+ if (ret) -+ return ret; -+ } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) { -+ *membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE; -+ ret = vmd_get_phys_offsets(vmd, true, offset1, offset2); -+ if (ret) -+ return ret; -+ } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) { -+ ret = vmd_get_phys_offsets(vmd, false, offset1, offset2); -+ if (ret) -+ return ret; -+ } -+ -+ /* -+ * Certain VMD devices may have a root port configuration option which -+ * limits the bus range to between 0-127, 128-255, or 224-255. -+ */ -+ if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) { -+ ret = vmd_get_bus_number_start(vmd); -+ if (ret) -+ return ret; -+ } -+ return 0; -+} -+ - /* - * Since VMD is an aperture to regular PCIe root ports, only allow it to - * control features that the OS is allowed to control on the physical PCI bus. -@@ -780,42 +911,24 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) - LIST_HEAD(resources); - resource_size_t offset[2] = {0}; - resource_size_t membar2_offset = 0x2000; -+ resource_size_t busn_end; - struct pci_bus *child; - struct pci_dev *dev; - int ret; - -- /* -- * Shadow registers may exist in certain VMD device ids which allow -- * guests to correctly assign host physical addresses to the root ports -- * and child devices. These registers will either return the host value -- * or 0, depending on an enable bit in the VMD device. -- */ -- if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) { -- membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE; -- ret = vmd_get_phys_offsets(vmd, true, &offset[0], &offset[1]); -- if (ret) -- return ret; -- } else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) { -- ret = vmd_get_phys_offsets(vmd, false, &offset[0], &offset[1]); -- if (ret) -- return ret; -- } -- -- /* -- * Certain VMD devices may have a root port configuration option which -- * limits the bus range to between 0-127, 128-255, or 224-255 -- */ -- if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) { -- ret = vmd_get_bus_number_start(vmd); -- if (ret) -- return ret; -- } -+ ret = vmd_prepare_offsets_and_bus(vmd, features, &membar2_offset, -+ &offset[0], &offset[1]); -+ if (ret) -+ return ret; - -+ /* Do not let resource[0] end go out of bounds */ - res = &vmd->dev->resource[VMD_CFGBAR]; -+ busn_end = vmd->busn_start + (resource_size(res) >> 20) - 1; -+ busn_end = min_t(resource_size_t, busn_end, 0xff); - vmd->resources[0] = (struct resource) { - .name = "VMD CFGBAR", - .start = vmd->busn_start, -- .end = vmd->busn_start + (resource_size(res) >> 20) - 1, -+ .end = busn_end, - .flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED, - }; - -@@ -998,6 +1111,7 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) - - vmd->dev = dev; - vmd->sysdata.domain = PCI_DOMAIN_NR_NOT_SET; -+ vmd->features = features; - vmd->instance = ida_alloc(&vmd_instance_ida, GFP_KERNEL); - if (vmd->instance < 0) - return vmd->instance; -@@ -1114,6 +1228,10 @@ static const struct pci_device_id vmd_ids[] = { - .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW | - VMD_FEAT_HAS_BUS_RESTRICTIONS | - VMD_FEAT_CAN_BYPASS_MSI_REMAP,}, -+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_28C1), -+ .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW | -+ VMD_FEAT_CAN_BYPASS_MSI_REMAP | -+ VMD_FEAT_USE_BIOS_INFO,}, - {PCI_VDEVICE(INTEL, 0x467f), - .driver_data = VMD_FEATS_CLIENT,}, - {PCI_VDEVICE(INTEL, 0x4c3d), -diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h ---- a/include/linux/pci_ids.h -+++ b/include/linux/pci_ids.h -@@ -2892,6 +2892,7 @@ - #define PCI_DEVICE_ID_INTEL_HDA_ICH8 0x284b - #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 - #define PCI_DEVICE_ID_INTEL_VMD_28C0 0x28c0 -+#define PCI_DEVICE_ID_INTEL_VMD_28C1 0x28c1 - #define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 - #define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 - #define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 diff --git a/kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch.sig b/kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch.sig deleted file mode 100644 index 5969dea..0000000 Binary files a/kernel/0703-pci-vmd-scan-bios-enumerated-devices.patch.sig and /dev/null differ diff --git a/kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch b/kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch deleted file mode 100644 index 22be8d3..0000000 --- a/kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch +++ /dev/null @@ -1,120 +0,0 @@ -diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c ---- a/drivers/pci/controller/vmd.c -+++ b/drivers/pci/controller/vmd.c -@@ -92,6 +92,22 @@ enum vmd_features { - * referred to as MEMBAR2 or MSI-X BAR. - */ - VMD_FEAT_USE_BIOS_INFO = (1 << 6), -+ -+ /* -+ * Meteor Lake VMD (device ID 0x7d0b) is affected by erratum MTL016: -+ * the VMD may signal its MSI before the posted writes that carry the -+ * child device's DMA data have landed in memory. The demuxed handler -+ * then runs against a not-yet-coherent completion queue and misses the -+ * completion entirely, so the I/O is only recovered when the block -+ * layer timeout fires and polls the queue ("timeout, completion -+ * polled"). Intel's documented workaround is to issue a dummy read -+ * to the MSI initiator (the child device) before handling the -+ * interrupt: the read completion cannot pass the device's earlier -+ * posted writes, so it pulls them into memory per PCIe ordering -+ * rules. A read that terminates at the VMD itself does not order -+ * against the child's writes and is not sufficient (measured). -+ */ -+ VMD_FEAT_INTERRUPT_QUIRK = (1 << 7), - }; - - #define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */ -@@ -114,6 +130,9 @@ static DEFINE_RAW_SPINLOCK(list_lock); - * @irq: back pointer to parent. - * @enabled: true if driver enabled IRQ - * @virq: the virtual IRQ value provided to the requesting driver. -+ * @flush_addr: config space address of the initiating device, read before -+ * demuxing to flush its posted writes (MTL016); NULL if the -+ * VMD is not affected. - * - * Every MSI/MSI-X IRQ requested for a device in a VMD domain will be mapped to - * a VMD IRQ using this structure. -@@ -123,8 +142,14 @@ struct vmd_irq { - struct vmd_irq_list *irq; - bool enabled; - unsigned int virq; -+ void __iomem *flush_addr; - }; - -+struct vmd_dev; -+ -+static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, -+ unsigned int devfn, int reg, int len); -+ - /** - * struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector - * @irq_list: the list of irq's the VMD one demuxes to. -@@ -132,12 +157,15 @@ struct vmd_irq { - * @count: number of child IRQs assigned to this vector; used to track - * sharing. - * @virq: The underlying VMD Linux interrupt number -+ * @vmd: back pointer to the owning VMD device; serializes the MTL016 -+ * flush read against other config space access. - */ - struct vmd_irq_list { - struct list_head irq_list; - struct srcu_struct srcu; - unsigned int count; - unsigned int virq; -+ struct vmd_dev *vmd; - }; - - struct vmd_dev { -@@ -295,6 +323,13 @@ static int vmd_msi_alloc(struct irq_domain *domain, unsigned int virq, - INIT_LIST_HEAD(&vmdirq->node); - vmdirq->irq = vmd_next_irq(vmd, desc); - vmdirq->virq = virq + i; -+ if (vmd->features & VMD_FEAT_INTERRUPT_QUIRK) { -+ struct pci_dev *pdev = msi_desc_to_pci_dev(desc); -+ -+ vmdirq->flush_addr = vmd_cfg_addr(vmd, pdev->bus, -+ pdev->devfn, -+ PCI_VENDOR_ID, 2); -+ } - - irq_domain_set_info(domain, virq + i, vmdirq->irq->virq, - &vmd_msi_controller, vmdirq, -@@ -753,8 +788,20 @@ static irqreturn_t vmd_irq(int irq, void *data) - int idx; - - idx = srcu_read_lock(&irqs->srcu); -- list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) -+ list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) { -+ /* -+ * MTL016: the MSI may have outrun the initiating device's -+ * posted writes (e.g. its NVMe completion entry). A read -+ * that completes at the initiator flushes them, so the -+ * demuxed handler observes a coherent completion queue. -+ * The value is discarded; only the ordering matters. -+ */ -+ if (vmdirq->flush_addr) { -+ guard(raw_spinlock)(&irqs->vmd->cfg_lock); -+ readw(vmdirq->flush_addr); -+ } - generic_handle_irq(vmdirq->virq); -+ } - srcu_read_unlock(&irqs->srcu, idx); - - return IRQ_HANDLED; -@@ -785,6 +832,7 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd) - return err; - - INIT_LIST_HEAD(&vmd->irqs[i].irq_list); -+ vmd->irqs[i].vmd = vmd; - vmd->irqs[i].virq = pci_irq_vector(dev, i); - err = devm_request_irq(&dev->dev, vmd->irqs[i].virq, - vmd_irq, IRQF_NO_THREAD, -@@ -1239,7 +1287,7 @@ static const struct pci_device_id vmd_ids[] = { - {PCI_VDEVICE(INTEL, 0xa77f), - .driver_data = VMD_FEATS_CLIENT,}, - {PCI_VDEVICE(INTEL, 0x7d0b), -- .driver_data = VMD_FEATS_CLIENT,}, -+ .driver_data = VMD_FEATS_CLIENT | VMD_FEAT_INTERRUPT_QUIRK,}, - {PCI_VDEVICE(INTEL, 0xad0b), - .driver_data = VMD_FEATS_CLIENT,}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B), diff --git a/kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch.sig b/kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch.sig deleted file mode 100644 index 63aecd3..0000000 Binary files a/kernel/0704-pci-vmd-meteor-lake-mtl016-flush.patch.sig and /dev/null differ diff --git a/kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch b/kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch deleted file mode 100644 index 49806cf..0000000 --- a/kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -4370,6 +4370,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON, - DECLARE_PCI_FIXUP_HEADER(0x1c28, /* Lite-On */ - 0x0122, /* Plextor M6E (Marvell 88SS9183)*/ - quirk_dma_func1_alias); -+/* Toshiba AHCI SSD controller in MacBookAir6,1 and MacBookAir7,1 */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x010b, -+ quirk_dma_func1_alias); - - /* - * Some devices DMA with the wrong devfn, not just the wrong function. diff --git a/kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch.sig b/kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch.sig deleted file mode 100644 index 678cdb3..0000000 Binary files a/kernel/0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch.sig and /dev/null differ diff --git a/kernel/0711-iommu-amd-perfopt-support.patch b/kernel/0711-iommu-amd-perfopt-support.patch deleted file mode 100644 index 4b13fed..0000000 --- a/kernel/0711-iommu-amd-perfopt-support.patch +++ /dev/null @@ -1,413 +0,0 @@ -diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h ---- a/drivers/iommu/amd/amd_iommu.h -+++ b/drivers/iommu/amd/amd_iommu.h -@@ -48,6 +48,9 @@ extern u8 amd_iommu_hpt_vasize; - extern unsigned long amd_iommu_pgsize_bitmap; - extern bool amd_iommu_hatdis; - -+int amd_iommu_perfopt_clear(struct amd_iommu *iommu); -+int amd_iommu_perfopt_restore(struct amd_iommu *iommu); -+ - /* Protection domain ops */ - void amd_iommu_init_identity_domain(void); - struct protection_domain *protection_domain_alloc(void); -diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h ---- a/drivers/iommu/amd/amd_iommu_types.h -+++ b/drivers/iommu/amd/amd_iommu_types.h -@@ -65,6 +65,7 @@ - #define MMIO_MSI_ADDR_LO_OFFSET 0x015C - #define MMIO_MSI_ADDR_HI_OFFSET 0x0160 - #define MMIO_MSI_DATA_OFFSET 0x0164 -+#define MMIO_PERF_OPT_OFFSET 0x016C - #define MMIO_INTCAPXT_EVT_OFFSET 0x0170 - #define MMIO_INTCAPXT_PPR_OFFSET 0x0178 - #define MMIO_INTCAPXT_GALOG_OFFSET 0x0180 -@@ -99,6 +100,8 @@ - #define FEATURE_GLX GENMASK_ULL(15, 14) - #define FEATURE_GAM_VAPIC BIT_ULL(21) - #define FEATURE_PASMAX GENMASK_ULL(36, 32) -+#define FEATURE_PERF_OPT BIT_ULL(45) -+#define PERF_OPT_EN BIT(13) - #define FEATURE_GIOSUP BIT_ULL(48) - #define FEATURE_HASUP BIT_ULL(49) - #define FEATURE_EPHSUP BIT_ULL(50) -@@ -663,6 +666,9 @@ struct amd_iommu { - /* Extended features 2 */ - u64 features2; - -+ /* Devices requesting PerfOpt; the shared PERF_OPT_EN bit is on while >0. Protected by @lock. */ -+ int perfopt_refcount; -+ - /* PCI device id of the IOMMU device */ - u16 devid; - -@@ -824,6 +830,7 @@ struct iommu_dev_data { - u8 ppr :1; /* Enable device PPR support */ - bool use_vapic; /* Enable device to use vapic mode */ - bool defer_attach; -+ bool perfopt; - - struct ratelimit_state rs; /* Ratelimit IOPF messages */ - }; -diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c ---- a/drivers/iommu/amd/init.c -+++ b/drivers/iommu/amd/init.c -@@ -1945,6 +1945,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h, - if (!iommu->mmio_base) - return -ENOMEM; - -+ if (amd_iommu_perfopt_clear(iommu)) -+ pr_err("IOMMU%d: failed to clear PerfOpt\n", iommu->index); -+ - return init_iommu_from_acpi(iommu, h); - } - -@@ -3035,10 +3038,46 @@ static void enable_iommus_vapic(void) - #endif - } - -+static int clear_perfopt_all(void) -+{ -+ struct amd_iommu *iommu; -+ int err, ret = 0; -+ -+ for_each_iommu(iommu) { -+ err = amd_iommu_perfopt_clear(iommu); -+ if (err) -+ ret = err; -+ } -+ -+ return ret; -+} -+ -+static int restore_perfopt_all(void) -+{ -+ struct amd_iommu *iommu; -+ int err, ret = 0; -+ -+ for_each_iommu(iommu) { -+ err = amd_iommu_perfopt_restore(iommu); -+ if (err) -+ ret = err; -+ } -+ -+ return ret; -+} -+ - static void disable_iommus(void) - { - struct amd_iommu *iommu; - -+ /* -+ * PerfOpt is an optional performance bit, so a failure to clear it must -+ * not skip the mandatory disable below. This also runs from the void -+ * amd_iommu_disable() shutdown/kexec path, which cannot report an error. -+ */ -+ if (clear_perfopt_all()) -+ pr_err("Failed to clear PerfOpt while disabling IOMMUs\n"); -+ - for_each_iommu(iommu) - iommu_disable(iommu); - -@@ -3064,6 +3103,10 @@ static void amd_iommu_resume(void *data) - for_each_iommu(iommu) - early_enable_iommu(iommu); - -+ /* early_enable_iommu() cleared PERF_OPT_EN; re-assert it from the refcount. */ -+ if (restore_perfopt_all()) -+ pr_err("Failed to restore PerfOpt after IOMMU resume\n"); -+ - iommu_enable_event_buffer(); - amd_iommu_enable_interrupts(); - } -diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c ---- a/drivers/iommu/amd/iommu.c -+++ b/drivers/iommu/amd/iommu.c -@@ -2352,6 +2352,9 @@ static int attach_device(struct device *dev, - if (ret) - goto out; - -+ if (dev_data->perfopt) -+ goto skip_caps; -+ - /* Setup GCR3 table */ - if (pdom_is_sva_capable(domain)) { - ret = init_gcr3_table(dev_data, domain); -@@ -2376,6 +2379,7 @@ static int attach_device(struct device *dev, - pdev_enable_cap_ats(pdev); - } - -+skip_caps: - /* Update data structures */ - dev_data->domain = domain; - spin_lock_irqsave(&domain->lock, flags); -@@ -2444,6 +2448,192 @@ static void detach_device(struct device *dev) - mutex_unlock(&dev_data->mutex); - } - -+/* Program the per-IOMMU PerfOpt enable bit. Caller must hold iommu->lock. */ -+static int __perfopt_write(struct amd_iommu *iommu, bool enable) -+{ -+ u32 old, val, readback; -+ -+ if (!(readq(iommu->mmio_base + MMIO_EXT_FEATURES) & FEATURE_PERF_OPT)) -+ return enable ? -ENODEV : 0; -+ -+ old = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET); -+ if (old == U32_MAX) -+ return -EIO; -+ -+ val = enable ? old | PERF_OPT_EN : old & ~PERF_OPT_EN; -+ if (val != old) -+ writel(val, iommu->mmio_base + MMIO_PERF_OPT_OFFSET); -+ readback = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET); -+ if (readback == U32_MAX || -+ (readback & PERF_OPT_EN) != (val & PERF_OPT_EN)) -+ return -EIO; -+ return 0; -+} -+ -+/* -+ * PERF_OPT_EN is a single bit shared by every device behind @iommu, so it is -+ * reference counted: armed on the first requesting device, cleared on the last. -+ */ -+static int perfopt_get(struct amd_iommu *iommu) -+{ -+ unsigned long flags; -+ int ret = 0; -+ -+ if (!iommu->mmio_base) -+ return 0; -+ -+ raw_spin_lock_irqsave(&iommu->lock, flags); -+ if (iommu->perfopt_refcount == 0) { -+ ret = __perfopt_write(iommu, true); -+ if (ret) -+ goto out; -+ } -+ iommu->perfopt_refcount++; -+out: -+ raw_spin_unlock_irqrestore(&iommu->lock, flags); -+ return ret; -+} -+ -+static int perfopt_put(struct amd_iommu *iommu) -+{ -+ unsigned long flags; -+ int ret = 0; -+ -+ if (!iommu->mmio_base) -+ return 0; -+ -+ raw_spin_lock_irqsave(&iommu->lock, flags); -+ if (iommu->perfopt_refcount > 0 && --iommu->perfopt_refcount == 0) -+ ret = __perfopt_write(iommu, false); -+ raw_spin_unlock_irqrestore(&iommu->lock, flags); -+ return ret; -+} -+ -+/* -+ * Force PERF_OPT_EN off without touching the refcount (used on init, shutdown, -+ * and suspend). The count is preserved so amd_iommu_perfopt_restore() can -+ * re-arm on resume. -+ */ -+int amd_iommu_perfopt_clear(struct amd_iommu *iommu) -+{ -+ unsigned long flags; -+ int ret; -+ -+ if (!iommu->mmio_base) -+ return 0; -+ -+ raw_spin_lock_irqsave(&iommu->lock, flags); -+ ret = __perfopt_write(iommu, false); -+ raw_spin_unlock_irqrestore(&iommu->lock, flags); -+ return ret; -+} -+ -+/* -+ * Re-assert PERF_OPT_EN from the refcount after the hardware was reprogrammed on -+ * resume, so devices armed before suspend keep the optimization without each -+ * consumer driver re-arming. -+ */ -+int amd_iommu_perfopt_restore(struct amd_iommu *iommu) -+{ -+ unsigned long flags; -+ int ret; -+ -+ if (!iommu->mmio_base) -+ return 0; -+ -+ raw_spin_lock_irqsave(&iommu->lock, flags); -+ ret = __perfopt_write(iommu, iommu->perfopt_refcount > 0); -+ raw_spin_unlock_irqrestore(&iommu->lock, flags); -+ return ret; -+} -+ -+int amd_iommu_enable_perfopt(struct pci_dev *pdev) -+{ -+ struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); -+ struct amd_iommu *iommu = rlookup_amd_iommu(&pdev->dev); -+ struct protection_domain *domain; -+ int ret; -+ -+ if (!iommu || !dev_data) -+ return -ENODEV; -+ -+ if (!(iommu->features & FEATURE_PERF_OPT)) -+ return -ENODEV; -+ -+ domain = dev_data->domain; -+ if (!domain) -+ return -ENODEV; -+ -+ /* Already armed for this device (e.g. re-entry on resume). */ -+ if (dev_data->perfopt) -+ return 0; -+ -+ /* -+ * The bit is only architecturally valid while the device is untranslated: -+ * identity domain with ATS/PRI/PASID off. The identity domain is -+ * SVA-capable so attach_device() enabled ATS/PRI/PASID and built a GCR3 -+ * table. Re-home the device onto the same identity domain with -+ * perfopt set, so the attach_device() skip_caps path leaves -+ * ATS/PRI/PASID off and no GCR3 table. This follows the detach/attach -+ * pattern used by amd_iommu_attach_device(). -+ * -+ * Locking: this and amd_iommu_disable_perfopt() run only from the -+ * consumer driver's bind/unbind path. group->mutex is not exposed to -+ * drivers, but a device bound to its native driver cannot have its domain -+ * changed concurrently by the core (VFIO ownership is mutually exclusive; -+ * sysfs domain changes require an unused group), so the detach/attach pair -+ * is serialized without it. -+ */ -+ dev_data->perfopt = true; -+ detach_device(&pdev->dev); -+ ret = attach_device(&pdev->dev, domain); -+ if (ret) -+ goto err_restore; -+ -+ ret = perfopt_get(iommu); -+ if (ret) -+ goto err_rearm; -+ -+ dev_info_once(&pdev->dev, "PerfOpt armed on IOMMU%d\n", iommu->index); -+ return 0; -+ -+err_rearm: -+ detach_device(&pdev->dev); -+err_restore: -+ dev_data->perfopt = false; -+ if (attach_device(&pdev->dev, domain)) -+ pci_err(pdev, "failed to restore state after PerfOpt setup; device left detached\n"); -+ dev_err_once(&pdev->dev, "PerfOpt failed to arm on IOMMU%d (%d)\n", -+ iommu->index, ret); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(amd_iommu_enable_perfopt); -+ -+void amd_iommu_disable_perfopt(struct pci_dev *pdev) -+{ -+ struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev); -+ struct amd_iommu *iommu = rlookup_amd_iommu(&pdev->dev); -+ struct protection_domain *domain; -+ -+ if (!iommu || !dev_data || !dev_data->perfopt || !dev_data->domain) -+ return; -+ -+ if (WARN_ON(perfopt_put(iommu))) -+ pci_err(pdev, "failed to clear PerfOpt\n"); -+ -+ /* -+ * Restore ATS/PRI/PASID (and thus SVA) by re-homing the device onto its -+ * identity domain with the flag cleared, so a later bind without PerfOpt -+ * sees a normally-capable device. See the locking note in -+ * amd_iommu_enable_perfopt(). -+ */ -+ domain = dev_data->domain; -+ dev_data->perfopt = false; -+ detach_device(&pdev->dev); -+ if (attach_device(&pdev->dev, domain)) -+ pci_err(pdev, "failed to restore caps after PerfOpt disable\n"); -+} -+EXPORT_SYMBOL_GPL(amd_iommu_disable_perfopt); - static struct iommu_device *amd_iommu_probe_device(struct device *dev) - { - struct iommu_device *iommu_dev; -@@ -2511,6 +2701,14 @@ static struct iommu_device *amd_iommu_probe_device(struct device *dev) - static void amd_iommu_release_device(struct device *dev) - { - struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); -+ struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); -+ -+ if (dev_data->perfopt) { -+ if (WARN_ON(perfopt_put(iommu))) -+ dev_err(dev, "IOMMU%d: failed to clear PerfOpt on release\n", -+ iommu->index); -+ dev_data->perfopt = false; -+ } - - WARN_ON(dev_data->domain); - -@@ -2885,6 +3083,19 @@ static int blocked_domain_attach_device(struct iommu_domain *domain, - struct iommu_domain *old) - { - struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); -+ struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); -+ -+ /* -+ * blocked_domain is also the .release_domain, so this is the normal -+ * teardown path: drop the reference and clear the flag here too, and -+ * don't fail teardown if the WARN-guarded write doesn't stick. -+ */ -+ if (dev_data->perfopt) { -+ if (WARN_ON(perfopt_put(iommu))) -+ dev_err(dev, "IOMMU%d: failed to clear PerfOpt for blocked domain\n", -+ iommu->index); -+ dev_data->perfopt = false; -+ } - - if (dev_data->domain) - detach_device(dev); -@@ -2953,6 +3164,9 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct device *dev, - struct amd_iommu *iommu = get_amd_iommu_from_dev(dev); - int ret; - -+ if (dev_data->perfopt && !pdom_is_in_pt_mode(domain)) -+ return -EBUSY; -+ - /* - * Skip attach device to domain if new domain is same as - * devices current domain -diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h ---- a/include/linux/amd-iommu.h -+++ b/include/linux/amd-iommu.h -@@ -11,11 +11,11 @@ - #include - - struct amd_iommu; -+struct pci_dev; - - #ifdef CONFIG_AMD_IOMMU - - struct task_struct; --struct pci_dev; - - extern void amd_iommu_detect(void); - -@@ -76,4 +76,15 @@ static inline int amd_iommu_snp_disable(void) { return 0; } - static inline bool amd_iommu_sev_tio_supported(void) { return false; } - #endif - -+#ifdef CONFIG_AMD_IOMMU -+int amd_iommu_enable_perfopt(struct pci_dev *pdev); -+void amd_iommu_disable_perfopt(struct pci_dev *pdev); -+#else -+static inline int amd_iommu_enable_perfopt(struct pci_dev *pdev) -+{ -+ return 0; -+} -+static inline void amd_iommu_disable_perfopt(struct pci_dev *pdev) { } -+#endif -+ - #endif /* _ASM_X86_AMD_IOMMU_H */ diff --git a/kernel/0711-iommu-amd-perfopt-support.patch.sig b/kernel/0711-iommu-amd-perfopt-support.patch.sig deleted file mode 100644 index c4b7be2..0000000 Binary files a/kernel/0711-iommu-amd-perfopt-support.patch.sig and /dev/null differ diff --git a/kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch b/kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch deleted file mode 100644 index 5c74198..0000000 --- a/kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch +++ /dev/null @@ -1,128 +0,0 @@ -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h -@@ -160,6 +160,7 @@ struct amdgpu_watchdog_timer { - * Modules parameters. - */ - extern int amdgpu_modeset; -+extern int amdgpu_iommu_perfopt; - extern unsigned int amdgpu_vram_limit; - extern int amdgpu_vis_vram_limit; - extern int amdgpu_gart_size; -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -3842,6 +3843,28 @@ amdgpu_device_should_register_switcheroo(struct amdgpu_device *adev, bool px) - apple_gmux_detect(NULL, NULL))); - } - -+static inline bool amdgpu_device_identity(struct amdgpu_device *adev) -+{ -+ struct pci_dev *pdev = adev->pdev; -+ struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev); -+ -+ if (!domain) -+ return false; -+ -+ return domain->type == IOMMU_DOMAIN_IDENTITY; -+} -+ -+static bool amdgpu_device_use_perfopt(struct amdgpu_device *adev) -+{ -+ if (amdgpu_iommu_perfopt == 0) -+ return false; -+ -+ if (!(adev->flags & AMD_IS_APU)) -+ return false; -+ -+ return amdgpu_device_identity(adev); -+} -+ - /** - * amdgpu_device_init - initialize the driver - * -@@ -4048,6 +4071,16 @@ int amdgpu_device_init(struct amdgpu_device *adev, - if (r) - return r; - -+ if (amdgpu_device_use_perfopt(adev)) { -+ int perfopt_ret = amd_iommu_enable_perfopt(pdev); -+ -+ /* Optional optimization; a failure to arm it must not abort probe. */ -+ if (perfopt_ret) -+ dev_warn(adev->dev, -+ "Failed to enable IOMMU PerfOpt (%d); continuing without it\n", -+ perfopt_ret); -+ } -+ - /* - * No need to remove conflicting FBs for non-display class devices. - * This prevents the sysfb from being freed accidently. -@@ -4416,6 +4449,9 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) - - amdgpu_gart_dummy_page_fini(adev); - -+ if (amdgpu_device_use_perfopt(adev)) -+ amd_iommu_disable_perfopt(adev->pdev); -+ - if (pci_dev_is_disconnected(adev->pdev)) - amdgpu_device_unmap_mmio(adev); - -@@ -4779,6 +4815,20 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients) - if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) - return 0; - -+ if (amdgpu_device_use_perfopt(adev)) { -+ int perfopt_ret = amd_iommu_enable_perfopt(adev->pdev); -+ -+ /* -+ * Must not return on failure: a bare return would leak the -+ * SR-IOV VF exclusive-mode acquisition taken above (released -+ * via the exit: path). -+ */ -+ if (perfopt_ret) -+ dev_warn(adev->dev, -+ "Failed to enable IOMMU PerfOpt (%d); continuing without it\n", -+ perfopt_ret); -+ } -+ - if (adev->in_s0ix) - amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D0Entry); - -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c -@@ -185,6 +185,7 @@ char *amdgpu_disable_cu; - char *amdgpu_virtual_display; - int amdgpu_enforce_isolation = -1; - int amdgpu_modeset = -1; -+int amdgpu_iommu_perfopt = -1; - - /* Specifies the default granularity for SVM, used in buffer - * migration and restoration of backing memory when handling -@@ -393,6 +394,17 @@ module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444); - MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)"); - module_param_named(aspm, amdgpu_aspm, int, 0444); - -+/** -+ * DOC: iommu_perfopt (int) -+ * Control the AMD IOMMU PerfOpt DMA-latency optimization -+ * (0 = disable; -1 = enable on supported devices). -+ * This arms the IOMMU PerfOpt control (IOMMU spec, MMIO Offset 016Ch, EFR PerfOptSup / PerfOptEn) -+ * Arming it disables ATS, PRI, PASID and SVA for the GPU and removes IOMMU DMA containment for it, -+ * trading isolation for lower DMA latency. -+ */ -+MODULE_PARM_DESC(iommu_perfopt, "Control IOMMU PerfOpt DMA-latency optimization (-1 = enable on supported devices, 0 = disable)"); -+module_param_named(iommu_perfopt, amdgpu_iommu_perfopt, int, 0444); -+ - /** - * DOC: runpm (int) - * Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down diff --git a/kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch.sig b/kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch.sig deleted file mode 100644 index 8d77e46..0000000 Binary files a/kernel/0712-drm-amdgpu-perfopt-in-identity-domain.patch.sig and /dev/null differ diff --git a/kernel/0740-hwmon-updates.patch b/kernel/0740-hwmon-updates.patch deleted file mode 100644 index a66a783..0000000 --- a/kernel/0740-hwmon-updates.patch +++ /dev/null @@ -1,7419 +0,0 @@ -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -224,6 +224,7 @@ config SENSORS_ADT7462 - config SENSORS_ADT7470 - tristate "Analog Devices ADT7470" - depends on I2C -+ depends on PWM || PWM=n - select REGMAP_I2C - help - If you say yes here you get support for the Analog Devices -@@ -292,11 +293,11 @@ config SENSORS_ASC7621 - will be called asc7621. - - config SENSORS_ASUS_ROG_RYUJIN -- tristate "ASUS ROG RYUJIN II 360 hardware monitoring driver" -+ tristate "ASUS ROG RYUJIN hardware monitoring driver" - depends on HID - help - If you say yes here you get support for the fans and sensors of -- the ASUS ROG RYUJIN II 360 AIO CPU liquid cooler. -+ supported ASUS ROG RYUJIN II and III AIO CPU liquid coolers. - - This driver can also be built as a module. If so, the module - will be called asus_rog_ryujin. -@@ -335,6 +336,17 @@ config SENSORS_K10TEMP - This driver can also be built as a module. If so, the module - will be called k10temp. - -+config SENSORS_KB9002 -+ tristate "Kandou KB9002 PCIe retimer" -+ depends on I2C -+ help -+ If you say yes here you get support for the integrated -+ temperature sensor and firmware version readout on Kandou -+ KB9002 PCIe 5.0 retimers, accessed over SMBus. -+ -+ This driver can also be built as a module. If so, the module -+ will be called kb9002. -+ - config SENSORS_KBATT - tristate "KEBA battery controller support" - depends on KEBA_CP500 -@@ -403,7 +415,6 @@ config SENSORS_ARCTIC_FAN_CONTROLLER - config SENSORS_ARM_SCMI - tristate "ARM SCMI Sensors" - depends on ARM_SCMI_PROTOCOL -- depends on THERMAL || !THERMAL_OF - help - This driver provides support for temperature, voltage, current - and power sensors available on SCMI based platforms. The actual -@@ -415,7 +426,6 @@ config SENSORS_ARM_SCMI - config SENSORS_ARM_SCPI - tristate "ARM SCPI Sensors" - depends on ARM_SCPI_PROTOCOL -- depends on THERMAL || !THERMAL_OF - help - This driver provides support for temperature, voltage, current - and power sensors available on ARM Ltd's SCP based platforms. The -@@ -435,7 +445,6 @@ config SENSORS_ASB100 - config SENSORS_ASPEED - tristate "ASPEED AST2400/AST2500 PWM and Fan tach driver" - depends on ARCH_ASPEED || COMPILE_TEST -- depends on THERMAL || THERMAL=n - select REGMAP - help - This driver provides support for ASPEED AST2400/AST2500 PWM -@@ -506,8 +515,8 @@ config SENSORS_CORSAIR_PSU - If you say yes here you get support for Corsair PSUs with a HID - interface. - Currently this driver supports the (RM/HX)550i, (RM/HX)650i, -- (RM/HX)750i, (RM/HX)850i, (RM/HX)1000i and HX1200i power supplies -- by Corsair. -+ (RM/HX)750i, (RM/HX)850i, (RM/HX)1000i, HX1200i and HX1500i power -+ supplies by Corsair. - - This driver can also be built as a module. If so, the module - will be called corsair-psu. -@@ -788,7 +797,6 @@ config SENSORS_G762 - config SENSORS_GPIO_FAN - tristate "GPIO fan" - depends on GPIOLIB || COMPILE_TEST -- depends on THERMAL || THERMAL=n - help - If you say yes here you get support for fans connected to GPIO lines. - -@@ -802,7 +810,7 @@ config SENSORS_GXP_FAN_CTRL - If you say yes here you get support for GXP fan control functionality. - - The GXP controls fan function via the CPLD through the use of PWM -- registers. This driver reports status and pwm setting of the fans. -+ registers. This driver enables pwm setting of the fans. - - config SENSORS_HIH6130 - tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor" -@@ -942,6 +950,19 @@ config SENSORS_JC42 - This driver can also be built as a module. If so, the module - will be called jc42. - -+config SENSORS_POLARFIRE_SOC_TVS -+ tristate "PolarFire SoC (MPFS) temperature and voltage sensor" -+ depends on POLARFIRE_SOC_SYSCONS || COMPILE_TEST -+ depends on MFD_SYSCON -+ help -+ This driver adds support for the PolarFire SoC (MPFS) Temperature and -+ Voltage Sensor. -+ -+ To compile this driver as a module, choose M here. the -+ module will be called tvs-mpfs. -+ -+ If unsure, say N. -+ - config SENSORS_POWERZ - tristate "ChargerLAB POWER-Z USB-C tester" - depends on USB -@@ -1357,7 +1378,6 @@ config SENSORS_MAX6639 - config SENSORS_MAX6650 - tristate "Maxim MAX6650 sensor chip" - depends on I2C -- depends on THERMAL || THERMAL=n - help - If you say yes here you get support for the MAX6650 / MAX6651 - sensor chips. -@@ -1732,7 +1752,6 @@ config SENSORS_PC87427 - config SENSORS_NTC_THERMISTOR - tristate "NTC thermistor support" - depends on IIO -- depends on THERMAL || !THERMAL_OF - help - This driver supports NTC thermistors sensor reading and its - interpretation. The driver can also monitor the temperature and -@@ -1933,7 +1952,6 @@ config SENSORS_PT5161L - config SENSORS_PWM_FAN - tristate "PWM fan" - depends on PWM || COMPILE_TEST -- depends on THERMAL || THERMAL=n - help - If you say yes here you get support for fans connected to PWM lines. - The driver uses the generic PWM interface, thus it will work on a -@@ -1945,7 +1963,6 @@ config SENSORS_PWM_FAN - config SENSORS_QNAP_MCU_HWMON - tristate "QNAP MCU hardware monitoring" - depends on MFD_QNAP_MCU -- depends on THERMAL || THERMAL=n - help - Say yes here to enable support for fan and temperature sensor - connected to a QNAP MCU, as found in a number of QNAP network -@@ -2010,8 +2027,9 @@ config SENSORS_SHT3x - depends on I2C - select CRC8 - help -- If you say yes here you get support for the Sensiron SHT30, SHT31 and -- SHT85 humidity and temperature sensors. -+ If you say yes here you get support for the Sensiron SHT30, SHT31, -+ SHT85 and the compatible GXCAS GXHT30 humidity and temperature -+ sensors. - - This driver can also be built as a module. If so, the module - will be called sht3x. -@@ -2070,6 +2088,17 @@ config SENSORS_DME1737 - This driver can also be built as a module. If so, the module - will be called dme1737. - -+config SENSORS_EIC7700_PVT -+ tristate "Eswin EIC7700 Voltage, Temperature sensor driver" -+ depends on ARCH_ESWIN || COMPILE_TEST -+ select POLYNOMIAL -+ help -+ If you say yes here you get support for Eswin EIC7700 PVT sensor -+ embedded into the SoC. -+ -+ This driver can also be built as a module. If so, the module will be -+ called eic7700-pvt. -+ - config SENSORS_EMC1403 - tristate "SMSC EMC1403/23 thermal sensor" - depends on I2C -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -72,6 +72,7 @@ obj-$(CONFIG_SENSORS_DME1737) += dme1737.o - obj-$(CONFIG_SENSORS_DRIVETEMP) += drivetemp.o - obj-$(CONFIG_SENSORS_DS620) += ds620.o - obj-$(CONFIG_SENSORS_DS1621) += ds1621.o -+obj-$(CONFIG_SENSORS_EIC7700_PVT) += eic7700-pvt.o - obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o - obj-$(CONFIG_SENSORS_EMC1812) += emc1812.o - obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o -@@ -112,6 +113,7 @@ obj-$(CONFIG_SENSORS_IT87) += it87.o - obj-$(CONFIG_SENSORS_JC42) += jc42.o - obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o - obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o -+obj-$(CONFIG_SENSORS_KB9002) += kb9002.o - obj-$(CONFIG_SENSORS_KBATT) += kbatt.o - obj-$(CONFIG_SENSORS_KFAN) += kfan.o - obj-$(CONFIG_SENSORS_LAN966X) += lan966x-hwmon.o -@@ -197,6 +199,7 @@ obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o - obj-$(CONFIG_SENSORS_PC87360) += pc87360.o - obj-$(CONFIG_SENSORS_PC87427) += pc87427.o - obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o -+obj-$(CONFIG_SENSORS_POLARFIRE_SOC_TVS) += tvs-mpfs.o - obj-$(CONFIG_SENSORS_POWERZ) += powerz.o - obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o - obj-$(CONFIG_SENSORS_PROM21_XHCI) += prom21-xhci.o -diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c ---- a/drivers/hwmon/acpi_power_meter.c -+++ b/drivers/hwmon/acpi_power_meter.c -@@ -21,8 +21,6 @@ - #include - - #define ACPI_POWER_METER_NAME "power_meter" --#define ACPI_POWER_METER_DEVICE_NAME "Power Meter" --#define ACPI_POWER_METER_CLASS "pwr_meter_resource" - - #define NUM_SENSORS 17 - -@@ -877,7 +875,7 @@ static void acpi_power_meter_notify(acpi_handle handle, u32 event, void *data) - break; - } - -- acpi_bus_generate_netlink_event(ACPI_POWER_METER_CLASS, -+ acpi_bus_generate_netlink_event("pwr_meter_resource", - dev_name(&resource->acpi_dev->dev), - event, 0); - } -@@ -899,8 +897,6 @@ static int acpi_power_meter_probe(struct platform_device *pdev) - resource->sensors_valid = 0; - resource->acpi_dev = device; - mutex_init(&resource->lock); -- strscpy(acpi_device_name(device), ACPI_POWER_METER_DEVICE_NAME); -- strscpy(acpi_device_class(device), ACPI_POWER_METER_CLASS); - - platform_set_drvdata(pdev, resource); - -diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c ---- a/drivers/hwmon/adt7470.c -+++ b/drivers/hwmon/adt7470.c -@@ -22,6 +22,9 @@ - #include - #include - #include -+#include -+#include -+#include - - /* Addresses to scan */ - static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; -@@ -100,6 +103,7 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; - #define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2)) - - #define ADT7470_PWM_COUNT 4 -+#define ADT7470_PWM_MAX 255 - #define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x)) - #define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x)) - #define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x)) -@@ -163,6 +167,7 @@ struct adt7470_data { - char limits_valid; - unsigned long sensors_last_updated; /* In jiffies */ - unsigned long limits_last_updated; /* In jiffies */ -+ bool use_pwm_framework; - - int num_temp_sensors; /* -1 = probe */ - int temperatures_probed; -@@ -850,7 +855,7 @@ static int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val - - switch (attr) { - case hwmon_pwm_input: -- val = clamp_val(val, 0, 255); -+ val = clamp_val(val, 0, ADT7470_PWM_MAX); - mutex_lock(&data->lock); - err = regmap_write(data->regmap, ADT7470_REG_PWM(channel), - val); -@@ -886,6 +891,133 @@ static int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val - return err; - } - -+struct adt7470_pwm_wfhw { -+ u8 val; -+}; -+ -+static int adt7470_pwm_round_waveform_tohw(struct pwm_chip *chip, -+ struct pwm_device *pwm, -+ const struct pwm_waveform *wf, -+ void *_wfhw) -+{ -+ struct adt7470_data *data = pwmchip_get_drvdata(chip); -+ struct adt7470_pwm_wfhw *wfhw = _wfhw; -+ u64 actual_period; -+ -+ if (wf->duty_length_ns == 0) { -+ wfhw->val = 0; -+ return 0; -+ } -+ -+ /* -+ * The PWM frequency (period) is a single chip-wide setting shared by -+ * all 4 channels, so it cannot be changed on a per-pwm_device basis -+ * through this API. The duty cycle is rounded against the currently -+ * configured hardware period rather than the period requested in -+ * @wf; round_waveform_fromhw() reports the actual resulting -+ * waveform back so the core/consumer can detect a mismatch. -+ */ -+ actual_period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, data->pwm_freq); -+ -+ if (actual_period > wf->period_length_ns) -+ /* period too short */ -+ return 1; -+ -+ if (wf->duty_length_ns >= actual_period) { -+ wfhw->val = ADT7470_PWM_MAX; -+ } else { -+ wfhw->val = mul_u64_u64_div_u64(wf->duty_length_ns, -+ ADT7470_PWM_MAX, -+ actual_period); -+ } -+ -+ return 0; -+} -+ -+static int adt7470_pwm_round_waveform_fromhw(struct pwm_chip *chip, -+ struct pwm_device *pwm, -+ const void *_wfhw, -+ struct pwm_waveform *wf) -+{ -+ struct adt7470_data *data = pwmchip_get_drvdata(chip); -+ const struct adt7470_pwm_wfhw *wfhw = _wfhw; -+ -+ wf->period_length_ns = DIV_ROUND_UP_ULL(NSEC_PER_SEC, data->pwm_freq); -+ wf->duty_offset_ns = 0; -+ wf->duty_length_ns = DIV_ROUND_UP_ULL((u64)wfhw->val * wf->period_length_ns, -+ ADT7470_PWM_MAX); -+ return 0; -+} -+ -+static int adt7470_pwm_read_waveform(struct pwm_chip *chip, -+ struct pwm_device *pwm, -+ void *_wfhw) -+{ -+ struct adt7470_data *data = pwmchip_get_drvdata(chip); -+ struct device *dev = regmap_get_device(data->regmap); -+ struct adt7470_pwm_wfhw *wfhw = _wfhw; -+ -+ data = adt7470_update_device(dev); -+ if (IS_ERR(data)) -+ return PTR_ERR(data); -+ -+ /* -+ * No lock needed: like the other hwmon_ops read callbacks in this -+ * driver (e.g. adt7470_pwm_read()), this only does a single byte -+ * read from the cache populated by adt7470_update_device(). -+ */ -+ wfhw->val = data->pwm[pwm->hwpwm]; -+ -+ return 0; -+} -+ -+static int adt7470_pwm_write_waveform(struct pwm_chip *chip, -+ struct pwm_device *pwm, -+ const void *_wfhw) -+{ -+ struct adt7470_data *data = pwmchip_get_drvdata(chip); -+ const struct adt7470_pwm_wfhw *wfhw = _wfhw; -+ unsigned int pwm_auto_reg_mask; -+ int err; -+ -+ if (pwm->hwpwm % 2) -+ pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK; -+ else -+ pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK; -+ -+ guard(mutex)(&data->lock); -+ -+ if (data->pwm[pwm->hwpwm] == wfhw->val && -+ data->pwm_automatic[pwm->hwpwm] == 0) -+ return 0; -+ -+ /* Put the PWM channel in manual mode before updating it. */ -+ err = regmap_update_bits(data->regmap, -+ ADT7470_REG_PWM_CFG(pwm->hwpwm), -+ pwm_auto_reg_mask, 0); -+ if (err < 0) -+ return err; -+ -+ data->pwm_automatic[pwm->hwpwm] = 0; -+ -+ err = regmap_write(data->regmap, -+ ADT7470_REG_PWM(pwm->hwpwm), wfhw->val); -+ if (err < 0) -+ return err; -+ -+ data->pwm[pwm->hwpwm] = wfhw->val; -+ -+ return 0; -+} -+ -+static const struct pwm_ops adt7470_pwm_ops = { -+ .sizeof_wfhw = sizeof(struct adt7470_pwm_wfhw), -+ .round_waveform_tohw = adt7470_pwm_round_waveform_tohw, -+ .round_waveform_fromhw = adt7470_pwm_round_waveform_fromhw, -+ .read_waveform = adt7470_pwm_read_waveform, -+ .write_waveform = adt7470_pwm_write_waveform, -+}; -+ - static ssize_t pwm_max_show(struct device *dev, - struct device_attribute *devattr, char *buf) - { -@@ -910,7 +1042,7 @@ static ssize_t pwm_max_store(struct device *dev, - if (kstrtol(buf, 10, &temp)) - return -EINVAL; - -- temp = clamp_val(temp, 0, 255); -+ temp = clamp_val(temp, 0, ADT7470_PWM_MAX); - - mutex_lock(&data->lock); - data->pwm_max[attr->index] = temp; -@@ -945,7 +1077,7 @@ static ssize_t pwm_min_store(struct device *dev, - if (kstrtol(buf, 10, &temp)) - return -EINVAL; - -- temp = clamp_val(temp, 0, 255); -+ temp = clamp_val(temp, 0, ADT7470_PWM_MAX); - - mutex_lock(&data->lock); - data->pwm_min[attr->index] = temp; -@@ -1106,6 +1238,10 @@ static struct attribute *adt7470_attrs[] = { - &dev_attr_alarm_mask.attr, - &dev_attr_num_temp_sensors.attr, - &dev_attr_auto_update_interval.attr, -+ NULL -+}; -+ -+static struct attribute *adt7470_pwm_attrs[] = { - &sensor_dev_attr_force_pwm_max.dev_attr.attr, - &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, - &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, -@@ -1130,7 +1266,32 @@ static struct attribute *adt7470_attrs[] = { - NULL - }; - --ATTRIBUTE_GROUPS(adt7470); -+static const struct attribute_group adt7470_group = { -+ .attrs = adt7470_attrs, -+}; -+ -+static umode_t adt7470_pwm_is_visible(struct kobject *kobj, -+ struct attribute *attr, int index) -+{ -+ struct device *dev = kobj_to_dev(kobj); -+ struct adt7470_data *data = dev_get_drvdata(dev); -+ -+ if (data->use_pwm_framework) -+ return 0; -+ -+ return attr->mode; -+} -+ -+static const struct attribute_group adt7470_pwm_group = { -+ .attrs = adt7470_pwm_attrs, -+ .is_visible = adt7470_pwm_is_visible, -+}; -+ -+static const struct attribute_group *adt7470_groups[] = { -+ &adt7470_group, -+ &adt7470_pwm_group, -+ NULL, -+}; - - static int adt7470_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, - int channel, long *val) -@@ -1165,6 +1326,7 @@ static int adt7470_write(struct device *dev, enum hwmon_sensor_types type, u32 a - static umode_t adt7470_is_visible(const void *_data, enum hwmon_sensor_types type, - u32 attr, int channel) - { -+ const struct adt7470_data *data = _data; - umode_t mode = 0; - - switch (type) { -@@ -1197,6 +1359,14 @@ static umode_t adt7470_is_visible(const void *_data, enum hwmon_sensor_types typ - } - break; - case hwmon_pwm: -+ /* Hide all pwm attributes if this device is exposed to the PWM -+ * framework -+ */ -+ if (data->use_pwm_framework) { -+ mode = 0; -+ break; -+ } -+ - switch (attr) { - case hwmon_pwm_input: - case hwmon_pwm_enable: -@@ -1226,6 +1396,8 @@ static const struct hwmon_ops adt7470_hwmon_ops = { - }; - - static const struct hwmon_channel_info * const adt7470_info[] = { -+ HWMON_CHANNEL_INFO(chip, -+ HWMON_C_REGISTER_TZ), - HWMON_CHANNEL_INFO(temp, - HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, - HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, -@@ -1327,6 +1499,29 @@ static int adt7470_probe(struct i2c_client *client) - - data->pwm_freq = (u32)freq_val; - -+ data->use_pwm_framework = false; -+ -+ if (device_property_present(dev, "#pwm-cells")) { -+ if (IS_REACHABLE(CONFIG_PWM)) { -+ struct pwm_chip *chip; -+ -+ chip = devm_pwmchip_alloc(dev, ADT7470_PWM_COUNT, 0); -+ if (IS_ERR(chip)) -+ return PTR_ERR(chip); -+ -+ chip->ops = &adt7470_pwm_ops; -+ pwmchip_set_drvdata(chip, data); -+ -+ err = devm_pwmchip_add(dev, chip); -+ if (err) -+ return dev_err_probe(dev, err, "failed to register PWM chip\n"); -+ -+ data->use_pwm_framework = true; -+ } else { -+ dev_warn(dev, "#pwm-cells present but CONFIG_PWM disabled. HWMON PWM attributes not hidden.\n"); -+ } -+ } -+ - /* Register sysfs hooks */ - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, - &adt7470_chip_info, -diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c ---- a/drivers/hwmon/applesmc.c -+++ b/drivers/hwmon/applesmc.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - /* data port used by Apple SMC */ - #define APPLESMC_DATA_PORT 0x300 -@@ -133,6 +134,7 @@ static struct applesmc_registers { - bool init_complete; /* true when fully initialized */ - struct applesmc_entry *cache; /* cached key entries */ - const char **index; /* temperature key index */ -+ char fan_positions[10][17]; /* cached fan position labels */ - } smcreg = { - .mutex = __MUTEX_INITIALIZER(smcreg.mutex), - }; -@@ -143,8 +145,8 @@ static s16 rest_x; - static s16 rest_y; - static u8 backlight_state[2]; - --static struct device *hwmon_dev; - static struct input_dev *applesmc_idev; -+static struct device *hwmon_dev; - - /* - * Last index written to key_at_index sysfs file, and value to use for all other -@@ -372,7 +374,8 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(int index) - __be32 be; - int ret = 0; - -- if (cache->valid) -+ /* Pairs with smp_store_release() to ensure cache contents are visible */ -+ if (smp_load_acquire(&cache->valid)) - return cache; - - mutex_lock(&smcreg.mutex); -@@ -391,7 +394,8 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(int index) - cache->len = info[0]; - memcpy(cache->type, &info[1], 4); - cache->flags = info[5]; -- cache->valid = true; -+ /* Pairs with smp_load_acquire() to commit cache contents before setting valid */ -+ smp_store_release(&cache->valid, true); - - out: - mutex_unlock(&smcreg.mutex); -@@ -566,7 +570,7 @@ static int applesmc_init_smcreg_try(void) - { - struct applesmc_registers *s = &smcreg; - bool left_light_sensor = false, right_light_sensor = false; -- unsigned int count; -+ unsigned int count, i; - u8 tmp[1]; - int ret; - -@@ -597,6 +601,16 @@ static int applesmc_init_smcreg_try(void) - if (s->fan_count > 10) - s->fan_count = 10; - -+ for (i = 0; i < s->fan_count; i++) { -+ char newkey[5]; -+ -+ scnprintf(newkey, sizeof(newkey), FAN_ID_FMT, i); -+ ret = applesmc_read_key(newkey, s->fan_positions[i], 16); -+ s->fan_positions[i][16] = 0; -+ if (ret) -+ scnprintf(s->fan_positions[i], 17, " Fan %d", i); -+ } -+ - ret = applesmc_get_lower_bound(&s->temp_begin, "T"); - if (ret) - return ret; -@@ -808,33 +822,6 @@ static ssize_t applesmc_light_show(struct device *dev, - return sysfs_emit(sysfsbuf, "(%d,%d)\n", left, right); - } - --/* Displays sensor key as label */ --static ssize_t applesmc_show_sensor_label(struct device *dev, -- struct device_attribute *devattr, char *sysfsbuf) --{ -- const char *key = smcreg.index[to_index(devattr)]; -- -- return sysfs_emit(sysfsbuf, "%s\n", key); --} -- --/* Displays degree Celsius * 1000 */ --static ssize_t applesmc_show_temperature(struct device *dev, -- struct device_attribute *devattr, char *sysfsbuf) --{ -- const char *key = smcreg.index[to_index(devattr)]; -- int ret; -- s16 value; -- int temp; -- -- ret = applesmc_read_s16(key, &value); -- if (ret) -- return ret; -- -- temp = 250 * (value >> 6); -- -- return sysfs_emit(sysfsbuf, "%d\n", temp); --} -- - static ssize_t applesmc_show_fan_speed(struct device *dev, - struct device_attribute *attr, char *sysfsbuf) - { -@@ -854,99 +841,6 @@ static ssize_t applesmc_show_fan_speed(struct device *dev, - return sysfs_emit(sysfsbuf, "%u\n", speed); - } - --static ssize_t applesmc_store_fan_speed(struct device *dev, -- struct device_attribute *attr, -- const char *sysfsbuf, size_t count) --{ -- int ret; -- unsigned long speed; -- char newkey[5]; -- u8 buffer[2]; -- -- if (kstrtoul(sysfsbuf, 10, &speed) < 0 || speed >= 0x4000) -- return -EINVAL; /* Bigger than a 14-bit value */ -- -- scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)], -- to_index(attr)); -- -- buffer[0] = (speed >> 6) & 0xff; -- buffer[1] = (speed << 2) & 0xff; -- ret = applesmc_write_key(newkey, buffer, 2); -- -- if (ret) -- return ret; -- else -- return count; --} -- --static ssize_t applesmc_show_fan_manual(struct device *dev, -- struct device_attribute *attr, char *sysfsbuf) --{ -- int ret; -- u16 manual = 0; -- u8 buffer[2]; -- -- ret = applesmc_read_key(FANS_MANUAL, buffer, 2); -- if (ret) -- return ret; -- -- manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01; -- return sysfs_emit(sysfsbuf, "%d\n", manual); --} -- --static ssize_t applesmc_store_fan_manual(struct device *dev, -- struct device_attribute *attr, -- const char *sysfsbuf, size_t count) --{ -- int ret; -- u8 buffer[2]; -- unsigned long input; -- u16 val; -- -- if (kstrtoul(sysfsbuf, 10, &input) < 0) -- return -EINVAL; -- -- ret = applesmc_read_key(FANS_MANUAL, buffer, 2); -- if (ret) -- goto out; -- -- val = (buffer[0] << 8 | buffer[1]); -- -- if (input) -- val = val | (0x01 << to_index(attr)); -- else -- val = val & ~(0x01 << to_index(attr)); -- -- buffer[0] = (val >> 8) & 0xFF; -- buffer[1] = val & 0xFF; -- -- ret = applesmc_write_key(FANS_MANUAL, buffer, 2); -- --out: -- if (ret) -- return ret; -- else -- return count; --} -- --static ssize_t applesmc_show_fan_position(struct device *dev, -- struct device_attribute *attr, char *sysfsbuf) --{ -- int ret; -- char newkey[5]; -- u8 buffer[17]; -- -- scnprintf(newkey, sizeof(newkey), FAN_ID_FMT, to_index(attr)); -- -- ret = applesmc_read_key(newkey, buffer, 16); -- buffer[16] = 0; -- -- if (ret) -- return ret; -- -- return sysfs_emit(sysfsbuf, "%s\n", buffer + 4); --} -- - static ssize_t applesmc_calibrate_show(struct device *dev, - struct device_attribute *attr, char *sysfsbuf) - { -@@ -1094,22 +988,7 @@ static struct applesmc_node_group light_sensor_group[] = { - { } - }; - --static struct applesmc_node_group fan_group[] = { -- { "fan%d_label", applesmc_show_fan_position }, -- { "fan%d_input", applesmc_show_fan_speed, NULL, 0 }, -- { "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 }, -- { "fan%d_max", applesmc_show_fan_speed, NULL, 2 }, -- { "fan%d_safe", applesmc_show_fan_speed, NULL, 3 }, -- { "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 }, -- { "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual }, -- { } --}; - --static struct applesmc_node_group temp_group[] = { -- { "temp%d_label", applesmc_show_sensor_label }, -- { "temp%d_input", applesmc_show_temperature }, -- { } --}; - - /* Module stuff */ - -@@ -1312,8 +1191,238 @@ static const struct dmi_system_id applesmc_whitelist[] __initconst = { - }; - MODULE_DEVICE_TABLE(dmi, applesmc_whitelist); - -+static struct applesmc_dev_attr *fan_safe_attrs; -+static struct attribute **fan_safe_attr_list; -+static struct attribute_group fan_safe_group; -+static const struct attribute_group *applesmc_extra_groups[2]; -+ -+static u32 *applesmc_temp_config; -+static u32 *applesmc_fan_config; -+static u32 *applesmc_pwm_config; -+static struct hwmon_channel_info *applesmc_info_temp; -+static struct hwmon_channel_info *applesmc_info_fan; -+static struct hwmon_channel_info *applesmc_info_pwm; -+static const struct hwmon_channel_info **applesmc_info_arr; -+static struct hwmon_chip_info *applesmc_chip; -+ -+static void applesmc_free_hwmon(void) -+{ -+ kfree(applesmc_temp_config); -+ kfree(applesmc_fan_config); -+ kfree(applesmc_pwm_config); -+ kfree(applesmc_info_temp); -+ kfree(applesmc_info_fan); -+ kfree(applesmc_info_pwm); -+ kfree(applesmc_info_arr); -+ kfree(applesmc_chip); -+ kfree(fan_safe_attrs); -+ kfree(fan_safe_attr_list); -+} -+ -+static umode_t applesmc_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ switch (type) { -+ case hwmon_temp: -+ if (attr == hwmon_temp_input || attr == hwmon_temp_label) -+ return 0444; -+ break; -+ case hwmon_fan: -+ switch (attr) { -+ case hwmon_fan_input: -+ case hwmon_fan_label: -+ case hwmon_fan_max: -+ return 0444; -+ case hwmon_fan_min: -+ case hwmon_fan_target: -+ return 0644; -+ default: -+ break; -+ } -+ break; -+ case hwmon_pwm: -+ if (attr == hwmon_pwm_enable) -+ return 0644; -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static int applesmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long *val) -+{ -+ int ret; -+ -+ switch (type) { -+ case hwmon_temp: -+ if (attr == hwmon_temp_input) { -+ const char *key = smcreg.index[channel]; -+ s16 value; -+ -+ ret = applesmc_read_s16(key, &value); -+ if (ret) -+ return ret; -+ *val = 250 * (value >> 6); -+ return 0; -+ } -+ break; -+ case hwmon_fan: -+ switch (attr) { -+ case hwmon_fan_input: { -+ char key[5]; -+ u8 buffer[2]; -+ -+ scnprintf(key, sizeof(key), "F%dAc", channel); -+ ret = applesmc_read_key(key, buffer, 2); -+ if (ret) -+ return ret; -+ *val = ((buffer[0] << 8 | buffer[1]) >> 2); -+ return 0; -+ } -+ case hwmon_fan_min: { -+ char key[5]; -+ u8 buffer[2]; -+ -+ scnprintf(key, sizeof(key), "F%dMn", channel); -+ ret = applesmc_read_key(key, buffer, 2); -+ if (ret) -+ return ret; -+ *val = ((buffer[0] << 8 | buffer[1]) >> 2); -+ return 0; -+ } -+ case hwmon_fan_max: { -+ char key[5]; -+ u8 buffer[2]; -+ -+ scnprintf(key, sizeof(key), "F%dMx", channel); -+ ret = applesmc_read_key(key, buffer, 2); -+ if (ret) -+ return ret; -+ *val = ((buffer[0] << 8 | buffer[1]) >> 2); -+ return 0; -+ } -+ case hwmon_fan_target: { -+ char key[5]; -+ u8 buffer[2]; -+ -+ scnprintf(key, sizeof(key), "F%dTg", channel); -+ ret = applesmc_read_key(key, buffer, 2); -+ if (ret) -+ return ret; -+ *val = ((buffer[0] << 8 | buffer[1]) >> 2); -+ return 0; -+ } -+ default: -+ break; -+ } -+ break; -+ case hwmon_pwm: -+ if (attr == hwmon_pwm_enable) { -+ u8 buffer[2]; -+ -+ ret = applesmc_read_key(FANS_MANUAL, buffer, 2); -+ if (ret) -+ return ret; -+ *val = (((buffer[0] << 8 | buffer[1]) >> channel) & 0x01) ? 1 : 2; -+ return 0; -+ } -+ break; -+ default: -+ break; -+ } -+ return -EOPNOTSUPP; -+} -+ -+static int applesmc_hwmon_write(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long val) -+{ -+ int ret; -+ -+ switch (type) { -+ case hwmon_fan: -+ if (attr == hwmon_fan_min || attr == hwmon_fan_target) { -+ char key[5]; -+ u8 buffer[2]; -+ const char *fmt = (attr == hwmon_fan_min) ? "F%dMn" : "F%dTg"; -+ -+ if (val < 0 || val >= 0x4000) -+ return -EINVAL; -+ scnprintf(key, sizeof(key), fmt, channel); -+ buffer[0] = (val >> 6) & 0xff; -+ buffer[1] = (val << 2) & 0xff; -+ return applesmc_write_key(key, buffer, 2); -+ } -+ break; -+ case hwmon_pwm: -+ if (attr == hwmon_pwm_enable) { -+ u8 buffer[2]; -+ u16 manual_val; -+ const struct applesmc_entry *entry; -+ -+ if (val != 1 && val != 2) -+ return -EINVAL; -+ -+ entry = applesmc_get_entry_by_key(FANS_MANUAL); -+ if (IS_ERR(entry)) -+ return PTR_ERR(entry); -+ -+ mutex_lock(&smcreg.mutex); -+ ret = read_smc(APPLESMC_READ_CMD, entry->key, buffer, 2); -+ if (ret) -+ goto out_unlock; -+ manual_val = (buffer[0] << 8 | buffer[1]); -+ if (val == 1) -+ manual_val |= (0x01 << channel); -+ else -+ manual_val &= ~(0x01 << channel); -+ buffer[0] = (manual_val >> 8) & 0xff; -+ buffer[1] = manual_val & 0xff; -+ ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buffer, 2); -+out_unlock: -+ mutex_unlock(&smcreg.mutex); -+ return ret; -+ } -+ break; -+ default: -+ break; -+ } -+ return -EOPNOTSUPP; -+} -+ -+static int applesmc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, const char **str) -+{ -+ switch (type) { -+ case hwmon_temp: -+ if (attr == hwmon_temp_label) { -+ *str = smcreg.index[channel]; -+ return 0; -+ } -+ break; -+ case hwmon_fan: -+ if (attr == hwmon_fan_label) { -+ *str = smcreg.fan_positions[channel] + 4; -+ return 0; -+ } -+ break; -+ default: -+ break; -+ } -+ return -EOPNOTSUPP; -+} -+ -+static const struct hwmon_ops applesmc_hwmon_ops = { -+ .is_visible = applesmc_hwmon_is_visible, -+ .read = applesmc_hwmon_read, -+ .write = applesmc_hwmon_write, -+ .read_string = applesmc_hwmon_read_string, -+}; -+ - static int __init applesmc_init(void) - { -+ int i; - int ret; - - if (!dmi_check_system(applesmc_whitelist)) { -@@ -1348,17 +1457,97 @@ static int __init applesmc_init(void) - if (ret) - goto out_smcreg; - -- ret = applesmc_create_nodes(fan_group, smcreg.fan_count); -- if (ret) -+ /* allocate hwmon channel configs */ -+ applesmc_temp_config = kcalloc(smcreg.index_count + 1, -+ sizeof(*applesmc_temp_config), GFP_KERNEL); -+ applesmc_fan_config = kcalloc(smcreg.fan_count + 1, -+ sizeof(*applesmc_fan_config), GFP_KERNEL); -+ applesmc_pwm_config = kcalloc(smcreg.fan_count + 1, -+ sizeof(*applesmc_pwm_config), GFP_KERNEL); -+ if (!applesmc_temp_config || !applesmc_fan_config || !applesmc_pwm_config) { -+ ret = -ENOMEM; - goto out_info; -+ } - -- ret = applesmc_create_nodes(temp_group, smcreg.index_count); -- if (ret) -- goto out_fans; -+ for (i = 0; i < smcreg.index_count; i++) -+ applesmc_temp_config[i] = HWMON_T_INPUT | HWMON_T_LABEL; -+ applesmc_temp_config[smcreg.index_count] = 0; -+ -+ for (i = 0; i < smcreg.fan_count; i++) { -+ applesmc_fan_config[i] = HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | -+ HWMON_F_MAX | HWMON_F_TARGET; -+ applesmc_pwm_config[i] = HWMON_PWM_ENABLE; -+ } -+ applesmc_fan_config[smcreg.fan_count] = 0; -+ applesmc_pwm_config[smcreg.fan_count] = 0; -+ -+ applesmc_info_temp = kzalloc_obj(*applesmc_info_temp, GFP_KERNEL); -+ applesmc_info_fan = kzalloc_obj(*applesmc_info_fan, GFP_KERNEL); -+ applesmc_info_pwm = kzalloc_obj(*applesmc_info_pwm, GFP_KERNEL); -+ if (!applesmc_info_temp || !applesmc_info_fan || !applesmc_info_pwm) { -+ ret = -ENOMEM; -+ goto out_info; -+ } -+ -+ applesmc_info_temp->type = hwmon_temp; -+ applesmc_info_temp->config = applesmc_temp_config; -+ -+ applesmc_info_fan->type = hwmon_fan; -+ applesmc_info_fan->config = applesmc_fan_config; -+ -+ applesmc_info_pwm->type = hwmon_pwm; -+ applesmc_info_pwm->config = applesmc_pwm_config; -+ -+ applesmc_info_arr = kcalloc(4, sizeof(*applesmc_info_arr), GFP_KERNEL); -+ if (!applesmc_info_arr) { -+ ret = -ENOMEM; -+ goto out_info; -+ } -+ -+ applesmc_info_arr[0] = applesmc_info_temp; -+ applesmc_info_arr[1] = applesmc_info_fan; -+ applesmc_info_arr[2] = applesmc_info_pwm; -+ applesmc_info_arr[3] = NULL; -+ -+ applesmc_chip = kzalloc_obj(*applesmc_chip, GFP_KERNEL); -+ if (!applesmc_chip) { -+ ret = -ENOMEM; -+ goto out_info; -+ } -+ -+ applesmc_chip->ops = &applesmc_hwmon_ops; -+ applesmc_chip->info = applesmc_info_arr; -+ -+ /* Create non-standard fanX_safe attributes group */ -+ fan_safe_attrs = kcalloc(smcreg.fan_count, -+ sizeof(*fan_safe_attrs), GFP_KERNEL); -+ fan_safe_attr_list = kcalloc(smcreg.fan_count + 1, -+ sizeof(*fan_safe_attr_list), GFP_KERNEL); -+ if (!fan_safe_attrs || !fan_safe_attr_list) { -+ ret = -ENOMEM; -+ goto out_info; -+ } -+ -+ for (i = 0; i < smcreg.fan_count; i++) { -+ struct applesmc_dev_attr *node = &fan_safe_attrs[i]; -+ -+ scnprintf(node->name, sizeof(node->name), "fan%d_safe", i + 1); -+ node->sda.index = (3 << 16) | (i & 0xffff); /* Option 3 (safe speed) */ -+ node->sda.dev_attr.show = applesmc_show_fan_speed; -+ node->sda.dev_attr.store = NULL; -+ sysfs_attr_init(&node->sda.dev_attr.attr); -+ node->sda.dev_attr.attr.name = node->name; -+ node->sda.dev_attr.attr.mode = 0444; -+ fan_safe_attr_list[i] = &node->sda.dev_attr.attr; -+ } -+ fan_safe_attr_list[smcreg.fan_count] = NULL; -+ fan_safe_group.attrs = fan_safe_attr_list; -+ applesmc_extra_groups[0] = &fan_safe_group; -+ applesmc_extra_groups[1] = NULL; - - ret = applesmc_create_accelerometer(); - if (ret) -- goto out_temperature; -+ goto out_info; - - ret = applesmc_create_light_sensor(); - if (ret) -@@ -1368,7 +1557,8 @@ static int __init applesmc_init(void) - if (ret) - goto out_light_sysfs; - -- hwmon_dev = hwmon_device_register(&pdev->dev); -+ hwmon_dev = hwmon_device_register_with_info(&pdev->dev, "applesmc", NULL, -+ applesmc_chip, applesmc_extra_groups); - if (IS_ERR(hwmon_dev)) { - ret = PTR_ERR(hwmon_dev); - goto out_light_ledclass; -@@ -1382,11 +1572,8 @@ static int __init applesmc_init(void) - applesmc_release_light_sensor(); - out_accelerometer: - applesmc_release_accelerometer(); --out_temperature: -- applesmc_destroy_nodes(temp_group); --out_fans: -- applesmc_destroy_nodes(fan_group); - out_info: -+ applesmc_free_hwmon(); - applesmc_destroy_nodes(info_group); - out_smcreg: - applesmc_destroy_smcreg(); -@@ -1407,13 +1594,12 @@ static void __exit applesmc_exit(void) - applesmc_release_key_backlight(); - applesmc_release_light_sensor(); - applesmc_release_accelerometer(); -- applesmc_destroy_nodes(temp_group); -- applesmc_destroy_nodes(fan_group); - applesmc_destroy_nodes(info_group); - applesmc_destroy_smcreg(); - platform_device_unregister(pdev); - platform_driver_unregister(&applesmc_driver); - release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS); -+ applesmc_free_hwmon(); - } - - module_init(applesmc_init); -diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c ---- a/drivers/hwmon/asus-ec-sensors.c -+++ b/drivers/hwmon/asus-ec-sensors.c -@@ -185,6 +185,20 @@ enum ec_sensors { - #define SENSOR_TEMP_SENSOR_EXTRA_2 BIT(ec_sensor_temp_sensor_extra_2) - #define SENSOR_TEMP_SENSOR_EXTRA_3 BIT(ec_sensor_temp_sensor_extra_3) - -+/* -+ * The values for temperature sensor readings without physical sensors connected. -+ * The value varies across generations and is seemingly defined by the EC chip -+ * used in the given board. -+ */ -+static const s32 temperature_blank_values[] = {-62, -60, -40}; -+ -+static const s32 environment_temp_sensors = -+ SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_T_SENSOR_ALT1 | -+ SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT | -+ SENSOR_TEMP_WATER_BLOCK_IN | SENSOR_TEMP_WATER_BLOCK_OUT | -+ SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 | -+ SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3; -+ - enum board_family { - family_unknown, - family_amd_400_series, -@@ -386,6 +400,8 @@ static const struct ec_sensor_info sensors_family_intel_600[] = { - [ec_sensor_temp_t_sensor] = - EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d), - [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e), -+ [ec_sensor_fan_cpu_opt] = -+ EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), - [ec_sensor_fan_water_flow] = - EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xbe), - [ec_sensor_temp_water_in] = -@@ -487,6 +503,14 @@ static const struct ec_board_info board_info_crosshair_x670e_hero = { - .family = family_amd_600_series, - }; - -+static const struct ec_board_info board_info_crosshair_x870e_hero = { -+ .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | -+ SENSOR_TEMP_MB | SENSOR_TEMP_VRM | -+ SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT, -+ .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, -+ .family = family_amd_800_series, -+}; -+ - static const struct ec_board_info board_info_maximus_vi_hero = { - .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | - SENSOR_TEMP_T_SENSOR | -@@ -527,6 +551,14 @@ static const struct ec_board_info board_info_maximus_z790_extreme = { - .family = family_intel_700_series, - }; - -+static const struct ec_board_info board_info_maximus_z790_hero = { -+ .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | -+ SENSOR_SET_TEMP_WATER | SENSOR_FAN_WATER_FLOW | -+ SENSOR_FAN_CPU_OPT, -+ .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, -+ .family = family_intel_700_series, -+}; -+ - static const struct ec_board_info board_info_prime_x470_pro = { - .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | - SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | -@@ -590,6 +622,13 @@ static const struct ec_board_info board_info_pro_art_x870E_creator_wifi = { - .family = family_amd_800_series, - }; - -+static const struct ec_board_info board_info_pro_art_z690_creator_wifi = { -+ .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | -+ SENSOR_FAN_CPU_OPT, -+ .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PC00_LPCB_SIO1_MUT0, -+ .family = family_intel_600_series, -+}; -+ - static const struct ec_board_info board_info_pro_ws_trx50_sage_wifi = { - /* Board also has a nct6798 */ - .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_VRME | -@@ -743,7 +782,7 @@ static const struct ec_board_info board_info_strix_x870_i_gaming_wifi = { - - static const struct ec_board_info board_info_strix_x870e_e_gaming_wifi = { - .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | -- SENSOR_TEMP_MB | SENSOR_TEMP_VRM | -+ SENSOR_TEMP_MB | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR | - SENSOR_FAN_CPU_OPT, - .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, - .family = family_amd_800_series, -@@ -859,6 +898,8 @@ static const struct dmi_system_id dmi_table[] = { - &board_info_pro_art_x670E_creator_wifi), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI", - &board_info_pro_art_x870E_creator_wifi), -+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt Z690-CREATOR WIFI", -+ &board_info_pro_art_z690_creator_wifi), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS TRX50-SAGE WIFI", - &board_info_pro_ws_trx50_sage_wifi), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS TRX50-SAGE WIFI A", -@@ -883,6 +924,8 @@ static const struct dmi_system_id dmi_table[] = { - &board_info_crosshair_x670e_gene), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO", - &board_info_crosshair_x670e_hero), -+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X870E HERO", -+ &board_info_crosshair_x870e_hero), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO", - &board_info_maximus_xi_hero), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)", -@@ -893,6 +936,8 @@ static const struct dmi_system_id dmi_table[] = { - &board_info_maximus_z690_formula), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS Z790 EXTREME", - &board_info_maximus_z790_extreme), -+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS Z790 HERO", -+ &board_info_maximus_z790_hero), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-E GAMING", - &board_info_strix_b550_e_gaming), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-I GAMING", -@@ -927,8 +972,12 @@ static const struct dmi_system_id dmi_table[] = { - &board_info_strix_x870_i_gaming_wifi), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-E GAMING WIFI", - &board_info_strix_x870e_e_gaming_wifi), -+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-E GAMING WIFI7 R2", -+ &board_info_strix_x870e_e_gaming_wifi), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-H GAMING WIFI7", - &board_info_strix_x870e_h_gaming_wifi7), -+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-E GAMING", -+ &board_info_strix_z390_f_gaming), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING", - &board_info_strix_z390_f_gaming), - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z490-F GAMING", -@@ -955,6 +1004,7 @@ static const struct dmi_system_id dmi_table[] = { - }; - - struct ec_sensor { -+ /* this is ec_sensors enum value */ - unsigned int info_index; - s32 cached_value; - }; -@@ -1047,6 +1097,12 @@ get_sensor_info(const struct ec_sensors_data *state, int index) - return state->sensors_info + state->sensors[index].info_index; - } - -+static enum ec_sensors -+get_ec_sensor_type(const struct ec_sensors_data *state, int index) -+{ -+ return state->sensors[index].info_index; -+} -+ - static int find_ec_sensor_index(const struct ec_sensors_data *ec, - enum hwmon_sensor_types type, int channel) - { -@@ -1290,6 +1346,17 @@ static int get_cached_value_or_update(const struct device *dev, - return 0; - } - -+static bool is_blank_temperature_value(s32 value) -+{ -+ size_t i; -+ -+ for (i = 0; i < ARRAY_SIZE(temperature_blank_values); ++i) { -+ if (value == temperature_blank_values[i]) -+ return true; -+ } -+ return false; -+} -+ - /* - * Now follow the functions that implement the hwmon interface - */ -@@ -1297,6 +1364,8 @@ static int get_cached_value_or_update(const struct device *dev, - static int asus_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *val) - { -+ const struct ec_sensor_info *sensor_info; -+ enum ec_sensors ec_sensor; - int ret; - s32 value = 0; - -@@ -1308,12 +1377,19 @@ static int asus_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, - } - - ret = get_cached_value_or_update(dev, sidx, state, &value); -- if (!ret) { -- *val = scale_sensor_value(value, -- get_sensor_info(state, sidx)->type); -- } -+ if (ret) -+ return ret; - -- return ret; -+ sensor_info = get_sensor_info(state, sidx); -+ if (sensor_info->type == hwmon_temp) { -+ ec_sensor = get_ec_sensor_type(state, sidx); -+ if ((environment_temp_sensors & BIT(ec_sensor)) && -+ is_blank_temperature_value(value)) -+ return -ENODATA; -+ } -+ *val = scale_sensor_value(value, sensor_info->type); -+ -+ return 0; - } - - static int asus_ec_hwmon_read_string(struct device *dev, -diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c ---- a/drivers/hwmon/asus_rog_ryujin.c -+++ b/drivers/hwmon/asus_rog_ryujin.c -@@ -1,6 +1,6 @@ - // SPDX-License-Identifier: GPL-2.0+ - /* -- * hwmon driver for Asus ROG Ryujin II 360 AIO cooler. -+ * hwmon driver for Asus ROG Ryujin AIO coolers. - * - * Copyright 2024 Aleksa Savic - */ -@@ -17,6 +17,9 @@ - - #define USB_VENDOR_ID_ASUS_ROG 0x0b05 - #define USB_PRODUCT_ID_RYUJIN_AIO 0x1988 /* ASUS ROG RYUJIN II 360 */ -+#define USB_PRODUCT_ID_RYUJIN_III_EXTREME 0x1bcb -+#define USB_PRODUCT_ID_RYUJIN_III_EVA 0x1ade -+#define USB_PRODUCT_ID_RYUJIN_III_WHITE 0x1ada - - struct rog_ryujin_device_info { - u8 temp_offset; -@@ -34,6 +37,14 @@ static const struct rog_ryujin_device_info rog_ryujin_ii_360_info = { - .has_controller = true, - }; - -+static const struct rog_ryujin_device_info rog_ryujin_iii_info = { -+ .temp_offset = 5, -+ .pump_speed_offset = 7, -+ .fan_speed_offset = 10, -+ .duty_channel = 1, -+ .has_controller = false, -+}; -+ - #define STATUS_VALIDITY 1500 /* ms */ - #define MAX_REPORT_LENGTH 65 - -@@ -173,7 +184,6 @@ static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd - static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length, - struct completion *status_completion) - { -- unsigned long flags; - int ret; - - /* -@@ -181,9 +191,9 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i - * completion. Reinit is done because hidraw could have triggered - * the raw event parsing and marked the passed in completion as done. - */ -- spin_lock_irqsave(&priv->status_report_request_lock, flags); -+ spin_lock_bh(&priv->status_report_request_lock); - reinit_completion(status_completion); -- spin_unlock_irqrestore(&priv->status_report_request_lock, flags); -+ spin_unlock_bh(&priv->status_report_request_lock); - - /* Send command for getting data */ - ret = rog_ryujin_write_expanded(priv, cmd, cmd_length); -@@ -411,18 +421,15 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - int size) - { - struct rog_ryujin_data *priv = hid_get_drvdata(hdev); -- unsigned long flags; - - if (size < 2 || data[0] != RYUJIN_CMD_PREFIX) - return 0; - -- spin_lock_irqsave(&priv->status_report_request_lock, flags); -- - if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) { - if (size <= priv->info->temp_offset + 1 || - size <= priv->info->pump_speed_offset + 1 || - size <= priv->info->fan_speed_offset + 1) -- goto unlock; -+ return 0; - - /* Received coolant temp and speeds of pump and internal fan */ - priv->temp_input[0] = data[priv->info->temp_offset] * 1000 + -@@ -436,7 +443,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->cooler_status_received); - } else if (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) { - if (size <= RYUJIN_CONTROLLER_SPEED_3 + 1) -- goto unlock; -+ return 0; - - /* Received speeds of four fans attached to the controller */ - priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1); -@@ -448,7 +455,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->controller_status_received); - } else if (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) { - if (size <= RYUJIN_INTERNAL_FAN_DUTY) -- goto unlock; -+ return 0; - - /* Received report for pump and internal fan duties (in %) */ - if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) { -@@ -467,7 +474,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - * We're expecting a report, so parse it. - */ - goto read_cooler_duty; -- goto unlock; -+ return 0; - } - read_cooler_duty: - priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]); -@@ -477,7 +484,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->cooler_duty_received); - } else if (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) { - if (size <= RYUJIN_CONTROLLER_DUTY) -- goto unlock; -+ return 0; - - /* Received report for controller duty for fans (in PWM) */ - if (data[RYUJIN_CONTROLLER_DUTY] == 0) { -@@ -496,7 +503,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - * We're expecting a report, so parse it. - */ - goto read_controller_duty; -- goto unlock; -+ return 0; - } - read_controller_duty: - priv->duty_input[2] = data[RYUJIN_CONTROLLER_DUTY]; -@@ -505,8 +512,6 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->controller_duty_received); - } - --unlock: -- spin_unlock_irqrestore(&priv->status_report_request_lock, flags); - return 0; - } - -@@ -596,6 +601,12 @@ static void rog_ryujin_remove(struct hid_device *hdev) - static const struct hid_device_id rog_ryujin_table[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_AIO), - .driver_data = (kernel_ulong_t)&rog_ryujin_ii_360_info }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_III_EXTREME), -+ .driver_data = (kernel_ulong_t)&rog_ryujin_iii_info }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_III_EVA), -+ .driver_data = (kernel_ulong_t)&rog_ryujin_iii_info }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_III_WHITE), -+ .driver_data = (kernel_ulong_t)&rog_ryujin_iii_info }, - { } - }; - -@@ -625,4 +636,4 @@ module_exit(rog_ryujin_exit); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Aleksa Savic "); --MODULE_DESCRIPTION("Hwmon driver for Asus ROG Ryujin II 360 AIO cooler"); -+MODULE_DESCRIPTION("Hwmon driver for Asus ROG Ryujin AIO coolers"); -diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c ---- a/drivers/hwmon/axi-fan-control.c -+++ b/drivers/hwmon/axi-fan-control.c -@@ -508,8 +508,7 @@ static int axi_fan_control_probe(struct platform_device *pdev) - IRQF_ONESHOT | IRQF_TRIGGER_HIGH, - NULL, ctl); - if (ret) -- return dev_err_probe(&pdev->dev, ret, -- "failed to request an irq\n"); -+ return ret; - - return 0; - } -diff --git a/drivers/hwmon/chipcap2.c b/drivers/hwmon/chipcap2.c ---- a/drivers/hwmon/chipcap2.c -+++ b/drivers/hwmon/chipcap2.c -@@ -22,6 +22,8 @@ - #include - #include - #include -+#include -+#include - - #define CC2_START_CM 0xA0 - #define CC2_START_NOM 0x80 -@@ -83,6 +85,7 @@ struct cc2_data { - struct i2c_client *client; - struct regulator *regulator; - const char *name; -+ const char *label; - int irq_ready; - int irq_low; - int irq_high; -@@ -444,6 +447,8 @@ static umode_t cc2_is_visible(const void *data, enum hwmon_sensor_types type, - switch (attr) { - case hwmon_humidity_input: - return 0444; -+ case hwmon_humidity_label: -+ return cc2->label ? 0444 : 0; - case hwmon_humidity_min_alarm: - return cc2->rh_alarm.low_alarm_visible ? 0444 : 0; - case hwmon_humidity_max_alarm: -@@ -461,6 +466,8 @@ static umode_t cc2_is_visible(const void *data, enum hwmon_sensor_types type, - switch (attr) { - case hwmon_temp_input: - return 0444; -+ case hwmon_temp_label: -+ return cc2->label ? 0444 : 0; - default: - return 0; - } -@@ -547,6 +554,16 @@ static int cc2_humidity_max_alarm_status(struct cc2_data *data, long *val) - return 0; - } - -+static int cc2_read_string(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, const char **str) -+{ -+ struct cc2_data *data = dev_get_drvdata(dev); -+ -+ *str = data->label; -+ -+ return 0; -+} -+ - static int cc2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, - int channel, long *val) - { -@@ -665,8 +682,9 @@ static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev) - } - - static const struct hwmon_channel_info *cc2_info[] = { -- HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), -- HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT | HWMON_H_MIN | HWMON_H_MAX | -+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), -+ HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT | HWMON_H_LABEL | -+ HWMON_H_MIN | HWMON_H_MAX | - HWMON_H_MIN_HYST | HWMON_H_MAX_HYST | - HWMON_H_MIN_ALARM | HWMON_H_MAX_ALARM), - NULL -@@ -675,6 +693,7 @@ static const struct hwmon_channel_info *cc2_info[] = { - static const struct hwmon_ops cc2_hwmon_ops = { - .is_visible = cc2_is_visible, - .read = cc2_read, -+ .read_string = cc2_read_string, - .write = cc2_write, - }; - -@@ -705,6 +724,8 @@ static int cc2_probe(struct i2c_client *client) - return dev_err_probe(dev, PTR_ERR(data->regulator), - "Failed to get regulator\n"); - -+ device_property_read_string(dev, "label", &data->label); -+ - ret = cc2_request_ready_irq(data, dev); - if (ret) - return dev_err_probe(dev, ret, "Failed to request ready irq\n"); -diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c ---- a/drivers/hwmon/coretemp.c -+++ b/drivers/hwmon/coretemp.c -@@ -68,7 +68,7 @@ enum coretemp_attr_index { - * This value is passed as "id" field to rdmsr/wrmsr functions. - * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS, - * from where the temperature values should be read. -- * @attr_size: Total number of pre-core attrs displayed in the sysfs. -+ * @attr_size: Number of sysfs attributes in this temperature data group. - */ - struct temp_data { - int temp; -diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c ---- a/drivers/hwmon/corsair-psu.c -+++ b/drivers/hwmon/corsair-psu.c -@@ -884,7 +884,7 @@ static const struct hid_device_id corsairpsu_idtable[] = { - { HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */ - { HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */ - { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */ -- { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Legacy and Series 2023 */ -+ { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Legacy, Series 2023 and 2025 */ - { HID_USB_DEVICE(0x1b1c, 0x1c23) }, /* Corsair HX1200i Series 2023 */ - { HID_USB_DEVICE(0x1b1c, 0x1c27) }, /* Corsair HX1200i Series 2025 */ - { }, -diff --git a/drivers/hwmon/cros_ec_hwmon.c b/drivers/hwmon/cros_ec_hwmon.c ---- a/drivers/hwmon/cros_ec_hwmon.c -+++ b/drivers/hwmon/cros_ec_hwmon.c -@@ -148,9 +148,17 @@ static bool cros_ec_hwmon_is_error_temp(u8 temp) - temp == EC_TEMP_SENSOR_NOT_CALIBRATED; - } - -+/* This differs slightly from the variant in units.h to avoid rounding inconsistencies. */ -+#define CROS_EC_HWMON_ABSOLUTE_ZERO_MILLICELSIUS (-273000) -+ -+static long cros_ec_hwmon_kelvin_to_millicelsius(long t) -+{ -+ return t * MILLIDEGREE_PER_DEGREE + CROS_EC_HWMON_ABSOLUTE_ZERO_MILLICELSIUS; -+} -+ - static long cros_ec_hwmon_temp_to_millicelsius(u8 temp) - { -- return kelvin_to_millicelsius((((long)temp) + EC_TEMP_SENSOR_OFFSET)); -+ return cros_ec_hwmon_kelvin_to_millicelsius((((long)temp) + EC_TEMP_SENSOR_OFFSET)); - } - - static bool cros_ec_hwmon_attr_is_temp_threshold(u32 attr) -@@ -228,8 +236,13 @@ static int cros_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type, - ret = cros_ec_hwmon_read_temp_threshold(priv->cros_ec, channel, - cros_ec_hwmon_attr_to_thres(attr), - &threshold); -- if (ret == 0) -- *val = kelvin_to_millicelsius(threshold); -+ if (ret == 0) { -+ /* Limit to sensible, non-overflowing values. */ -+ if (threshold > 255 + 273) -+ *val = 255000; -+ else -+ *val = cros_ec_hwmon_kelvin_to_millicelsius(threshold); -+ } - } - } - -diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c ---- a/drivers/hwmon/da9055-hwmon.c -+++ b/drivers/hwmon/da9055-hwmon.c -@@ -256,11 +256,8 @@ static int da9055_hwmon_probe(struct platform_device *pdev) - NULL, da9055_auxadc_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "adc-irq", hwmon); -- if (ret != 0) { -- dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n", -- ret); -+ if (ret != 0) - return ret; -- } - - hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9055", - hwmon, -diff --git a/drivers/hwmon/eic7700-pvt.c b/drivers/hwmon/eic7700-pvt.c -new file mode 100644 ---- /dev/null -+++ b/drivers/hwmon/eic7700-pvt.c -@@ -0,0 +1,509 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * ESWIN EIC7700 Voltage, Temperature sensor driver -+ * -+ * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd. -+ * -+ * Authors: -+ * Yulin Lu -+ * Huan He -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "eic7700-pvt.h" -+ -+static const struct pvt_sensor_info pvt_info[] = { -+ PVT_SENSOR_INFO(0, "Temperature", hwmon_temp, TEMP), -+ PVT_SENSOR_INFO(0, "Voltage", hwmon_in, VOLT), -+}; -+ -+static const char * const pvt_clk_names[PVT_CLK_NUM] = {"enable", "apb"}; -+ -+/* -+ * The original translation formulae of the temperature (in degrees of Celsius) -+ * to PVT data and vice-versa are following: -+ * N = 6.0818e-8*(T^4) +1.2873e-5*(T^3) + 7.2244e-3*(T^2) + 3.6484*(T^1) + -+ * 1.6198e2, -+ * T = -1.8439e-11*(N^4) + 8.0705e-8*(N^3) + -1.8501e-4*(N^2) + -+ * 3.2843e-1*(N^1) - 4.8690e1, -+ * where T = [-40, 125]C and N = [27, 771]. -+ * They must be accordingly altered to be suitable for the integer arithmetics. -+ * The technique is called 'factor redistribution', which just makes sure the -+ * multiplications and divisions are made so to have a result of the operations -+ * within the integer numbers limit. In addition we need to translate the -+ * formulae to accept millidegrees of Celsius. Here what they look like after -+ * the alterations: -+ * N = (60818e-20*(T^4) + 12873e-14*(T^3) + 72244e-9*(T^2) + 36484e-3*T + -+ * 16198e2) / 1e4, -+ * T = -18439e-12*(N^4) + 80705e-9*(N^3) - 185010e-6*(N^2) + 328430e-3*N - -+ * 48690, -+ * where T = [-40000, 125000] mC and N = [27, 771]. -+ */ -+static const struct polynomial poly_N_to_temp = { -+ .total_divider = 1, -+ .terms = { -+ {4, -18439, 1000, 1}, -+ {3, 80705, 1000, 1}, -+ {2, -185010, 1000, 1}, -+ {1, 328430, 1000, 1}, -+ {0, -48690, 1, 1} -+ } -+}; -+ -+/* -+ * Similar alterations are performed for the voltage conversion equations. -+ * The original formulae are: -+ * N = 1.3905e3*V - 5.7685e2, -+ * V = (N + 5.7685e2) / 1.3905e3, -+ * where V = [0.72, 0.88] V and N = [424, 646]. -+ * After the optimization they looks as follows: -+ * N = (13905e-3*V - 5768.5) / 10, -+ * V = (N * 10^5 / 13905 + 57685 * 10^3 / 13905) / 10. -+ * where V = [720, 880] mV and N = [424, 646]. -+ */ -+static const struct polynomial poly_N_to_volt = { -+ .total_divider = 10, -+ .terms = { -+ {1, 100000, 13905, 1}, -+ {0, 57685000, 1, 13905} -+ } -+}; -+ -+static inline u32 eic7700_pvt_update(void __iomem *reg, u32 mask, u32 data) -+{ -+ u32 old; -+ -+ old = readl_relaxed(reg); -+ writel((old & ~mask) | (data & mask), reg); -+ -+ return old & mask; -+} -+ -+static inline void eic7700_pvt_set_mode(struct pvt_hwmon *pvt, u32 mode) -+{ -+ u32 old; -+ -+ mode = FIELD_PREP(PVT_MODE_MASK, mode); -+ -+ old = eic7700_pvt_update(pvt->regs + PVT_ENA, PVT_ENA_EN, 0); -+ eic7700_pvt_update(pvt->regs + PVT_MODE, PVT_MODE_MASK, mode); -+ eic7700_pvt_update(pvt->regs + PVT_ENA, PVT_ENA_EN, old); -+} -+ -+static inline void eic7700_pvt_set_trim(struct pvt_hwmon *pvt, u32 val) -+{ -+ u32 old; -+ -+ old = eic7700_pvt_update(pvt->regs + PVT_ENA, PVT_ENA_EN, 0); -+ writel(val, pvt->regs + PVT_TRIM); -+ eic7700_pvt_update(pvt->regs + PVT_ENA, PVT_ENA_EN, old); -+} -+ -+static irqreturn_t eic7700_pvt_hard_isr(int irq, void *data) -+{ -+ struct pvt_hwmon *pvt = data; -+ u32 stat, val; -+ int active; -+ -+ if (IS_ENABLED(CONFIG_PM)) { -+ active = pm_runtime_get_if_active(pvt->dev); -+ if (active <= 0) -+ return IRQ_NONE; -+ } -+ -+ stat = readl(pvt->regs + PVT_INT); -+ if (!(stat & PVT_INT_STAT)) { -+ if (IS_ENABLED(CONFIG_PM)) -+ pm_runtime_put(pvt->dev); -+ return IRQ_NONE; -+ } -+ -+ eic7700_pvt_update(pvt->regs + PVT_INT, PVT_INT_CLR, PVT_INT_CLR); -+ /* -+ * Read the data, update the cache and notify a waiter of this event. -+ */ -+ val = readl(pvt->regs + PVT_DATA); -+ WRITE_ONCE(pvt->data_cache, FIELD_GET(PVT_DATA_OUT, val)); -+ complete(&pvt->conversion); -+ -+ if (IS_ENABLED(CONFIG_PM)) -+ pm_runtime_put(pvt->dev); -+ -+ return IRQ_HANDLED; -+} -+ -+static int eic7700_pvt_read_data(struct pvt_hwmon *pvt, -+ enum pvt_sensor_type type, long *val) -+{ -+ unsigned long timeout; -+ u32 data; -+ int ret; -+ -+ /* -+ * Wait for PVT conversion to complete and update the data cache. The -+ * data read procedure is following: set the requested PVT sensor mode, -+ * enable conversion, wait until conversion is finished, then disable -+ * conversion and IRQ, and read the cached data. -+ */ -+ reinit_completion(&pvt->conversion); -+ -+ eic7700_pvt_set_mode(pvt, pvt_info[type].mode); -+ eic7700_pvt_update(pvt->regs + PVT_ENA, PVT_ENA_EN, PVT_ENA_EN); -+ -+ /* -+ * Wait with timeout since in case if the sensor is suddenly powered -+ * down the request won't be completed and the caller will hang up on -+ * this procedure until the power is back up again. Multiply the -+ * timeout by the factor of two to prevent a false timeout. -+ */ -+ timeout = 2 * usecs_to_jiffies(ktime_to_us(pvt->timeout)); -+ ret = wait_for_completion_timeout(&pvt->conversion, timeout); -+ -+ eic7700_pvt_update(pvt->regs + PVT_ENA, PVT_ENA_EN, 0); -+ eic7700_pvt_update(pvt->regs + PVT_INT, PVT_INT_CLR, PVT_INT_CLR); -+ -+ if (!ret) -+ synchronize_irq(pvt->irq); -+ -+ data = READ_ONCE(pvt->data_cache); -+ -+ if (!ret) -+ return -ETIMEDOUT; -+ -+ if (type == PVT_TEMP) -+ *val = polynomial_calc(&poly_N_to_temp, data); -+ else -+ *val = polynomial_calc(&poly_N_to_volt, data); -+ -+ return 0; -+} -+ -+static const struct hwmon_channel_info *pvt_channel_info[] = { -+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), -+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), -+ HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL), -+ NULL -+}; -+ -+static umode_t eic7700_pvt_hwmon_is_visible(const void *data, -+ enum hwmon_sensor_types type, -+ u32 attr, int ch) -+{ -+ switch (type) { -+ case hwmon_temp: -+ switch (attr) { -+ case hwmon_temp_input: -+ case hwmon_temp_label: -+ return 0444; -+ } -+ break; -+ case hwmon_in: -+ switch (attr) { -+ case hwmon_in_input: -+ case hwmon_in_label: -+ return 0444; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int eic7700_pvt_hwmon_read(struct device *dev, -+ enum hwmon_sensor_types type, u32 attr, -+ int ch, long *val) -+{ -+ struct pvt_hwmon *pvt = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = pm_runtime_get_sync(pvt->dev); -+ if (ret < 0) { -+ dev_err(pvt->dev, "Failed to resume PVT device: %d\n", ret); -+ pm_runtime_put_noidle(pvt->dev); -+ return ret; -+ } -+ -+ switch (type) { -+ case hwmon_temp: -+ switch (attr) { -+ case hwmon_temp_input: -+ ret = eic7700_pvt_read_data(pvt, ch, val); -+ break; -+ default: -+ ret = -EOPNOTSUPP; -+ } -+ break; -+ case hwmon_in: -+ if (attr == hwmon_in_input) -+ ret = eic7700_pvt_read_data(pvt, PVT_VOLT + ch, val); -+ else -+ ret = -EOPNOTSUPP; -+ break; -+ default: -+ ret = -EOPNOTSUPP; -+ } -+ -+ pm_runtime_mark_last_busy(pvt->dev); -+ pm_runtime_put_autosuspend(pvt->dev); -+ return ret; -+} -+ -+static int eic7700_pvt_hwmon_read_string(struct device *dev, -+ enum hwmon_sensor_types type, u32 attr, -+ int ch, const char **str) -+{ -+ switch (type) { -+ case hwmon_temp: -+ if (attr == hwmon_temp_label) { -+ *str = pvt_info[ch].label; -+ return 0; -+ } -+ break; -+ case hwmon_in: -+ if (attr == hwmon_in_label) { -+ *str = pvt_info[PVT_VOLT + ch].label; -+ return 0; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return -EOPNOTSUPP; -+} -+ -+static const struct hwmon_ops pvt_hwmon_ops = { -+ .is_visible = eic7700_pvt_hwmon_is_visible, -+ .read = eic7700_pvt_hwmon_read, -+ .read_string = eic7700_pvt_hwmon_read_string -+}; -+ -+static const struct hwmon_chip_info pvt_hwmon_info = { -+ .ops = &pvt_hwmon_ops, -+ .info = pvt_channel_info -+}; -+ -+static struct pvt_hwmon *eic7700_pvt_create_data(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct pvt_hwmon *pvt; -+ -+ pvt = devm_kzalloc(dev, sizeof(*pvt), GFP_KERNEL); -+ if (!pvt) -+ return ERR_PTR(-ENOMEM); -+ -+ pvt->dev = dev; -+ init_completion(&pvt->conversion); -+ -+ return pvt; -+} -+ -+static int eic7700_pvt_init_iface(struct pvt_hwmon *pvt) -+{ -+ /* -+ * Make sure controller are disabled so not to accidentally have ISR -+ * executed before the driver data is fully initialized. Clear the IRQ -+ * status as well. -+ */ -+ eic7700_pvt_update(pvt->regs + PVT_ENA, PVT_ENA_EN, 0); -+ eic7700_pvt_update(pvt->regs + PVT_INT, PVT_INT_CLR, PVT_INT_CLR); -+ readl(pvt->regs + PVT_INT); -+ readl(pvt->regs + PVT_DATA); -+ -+ /* Setup default sensor mode and temperature trim. */ -+ eic7700_pvt_set_mode(pvt, pvt_info[PVT_TEMP].mode); -+ -+ /* -+ * Max conversion latency (~333 µs) derived from PVT spec: -+ * maximum sampling rate = 3000 samples/sec. -+ */ -+ pvt->timeout = ns_to_ktime(PVT_TOUT_MIN); -+ -+ eic7700_pvt_set_trim(pvt, PVT_TRIM_DEF); -+ -+ return 0; -+} -+ -+static int eic7700_pvt_request_irq(struct pvt_hwmon *pvt) -+{ -+ struct platform_device *pdev = to_platform_device(pvt->dev); -+ int ret; -+ -+ pvt->irq = platform_get_irq(pdev, 0); -+ if (pvt->irq < 0) -+ return pvt->irq; -+ -+ ret = devm_request_threaded_irq(pvt->dev, pvt->irq, -+ eic7700_pvt_hard_isr, NULL, -+ IRQF_TRIGGER_HIGH, "pvt", pvt); -+ if (ret) { -+ dev_err(pvt->dev, "Couldn't request PVT IRQ\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int eic7700_pvt_create_hwmon(struct pvt_hwmon *pvt) -+{ -+ pvt->hwmon = devm_hwmon_device_register_with_info(pvt->dev, "pvt", -+ pvt, &pvt_hwmon_info, -+ NULL); -+ if (IS_ERR(pvt->hwmon)) { -+ dev_err(pvt->dev, "Couldn't create hwmon device\n"); -+ return PTR_ERR(pvt->hwmon); -+ } -+ -+ return 0; -+} -+ -+static void eic7700_pvt_disable_pm_runtime(void *data) -+{ -+ struct pvt_hwmon *pvt = data; -+ -+ pm_runtime_dont_use_autosuspend(pvt->dev); -+ pm_runtime_disable(pvt->dev); -+ -+ if (!pm_runtime_status_suspended(pvt->dev)) { -+ clk_bulk_disable_unprepare(PVT_CLK_NUM, pvt->clks); -+ pm_runtime_set_suspended(pvt->dev); -+ } -+} -+ -+static int eic7700_pvt_probe(struct platform_device *pdev) -+{ -+ struct reset_control *rst; -+ struct pvt_hwmon *pvt; -+ int i, ret; -+ -+ pvt = eic7700_pvt_create_data(pdev); -+ if (IS_ERR(pvt)) -+ return PTR_ERR(pvt); -+ -+ platform_set_drvdata(pdev, pvt); -+ -+ pvt->regs = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(pvt->regs)) -+ return PTR_ERR(pvt->regs); -+ -+ for (i = 0; i < PVT_CLK_NUM; i++) -+ pvt->clks[i].id = pvt_clk_names[i]; -+ -+ ret = devm_clk_bulk_get(&pdev->dev, PVT_CLK_NUM, pvt->clks); -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, -+ "Couldn't get clock descriptors\n"); -+ -+ rst = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL); -+ if (IS_ERR(rst)) -+ return dev_err_probe(pvt->dev, PTR_ERR(rst), -+ "Couldn't get reset control\n"); -+ -+ ret = clk_bulk_prepare_enable(PVT_CLK_NUM, pvt->clks); -+ if (ret) -+ return dev_err_probe(pvt->dev, ret, -+ "Failed to enable clocks\n"); -+ -+ ret = eic7700_pvt_init_iface(pvt); -+ if (ret) { -+ clk_bulk_disable_unprepare(PVT_CLK_NUM, pvt->clks); -+ return ret; -+ } -+ -+ if (IS_ENABLED(CONFIG_PM)) -+ clk_bulk_disable_unprepare(PVT_CLK_NUM, pvt->clks); -+ -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_set_autosuspend_delay(&pdev->dev, 3000); -+ pm_runtime_use_autosuspend(&pdev->dev); -+ pm_runtime_get_noresume(&pdev->dev); -+ -+ ret = devm_add_action_or_reset(pvt->dev, eic7700_pvt_disable_pm_runtime, -+ pvt); -+ if (ret) { -+ pm_runtime_put_noidle(&pdev->dev); -+ return dev_err_probe(&pdev->dev, ret, -+ "Can't register PM cleanup\n"); -+ } -+ -+ ret = eic7700_pvt_request_irq(pvt); -+ if (ret) -+ goto err_put_pm_runtime; -+ -+ ret = eic7700_pvt_create_hwmon(pvt); -+ if (ret) -+ goto err_put_pm_runtime; -+ -+ pm_runtime_put_autosuspend(&pdev->dev); -+ -+ return 0; -+ -+err_put_pm_runtime: -+ pm_runtime_put_noidle(&pdev->dev); -+ return ret; -+} -+ -+static int __maybe_unused eic7700_pvt_runtime_resume(struct device *dev) -+{ -+ struct pvt_hwmon *pvt = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_bulk_prepare_enable(PVT_CLK_NUM, pvt->clks); -+ if (ret) { -+ dev_err(dev, "Failed to enable clocks: %d\n", ret); -+ return ret; -+ } -+ -+ eic7700_pvt_set_trim(pvt, PVT_TRIM_DEF); -+ -+ return 0; -+} -+ -+static int __maybe_unused eic7700_pvt_runtime_suspend(struct device *dev) -+{ -+ struct pvt_hwmon *pvt = dev_get_drvdata(dev); -+ -+ clk_bulk_disable_unprepare(PVT_CLK_NUM, pvt->clks); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops eic7700_pvt_pm_ops = { -+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) -+ RUNTIME_PM_OPS(eic7700_pvt_runtime_suspend, eic7700_pvt_runtime_resume, -+ NULL) -+}; -+ -+static const struct of_device_id pvt_of_match[] = { -+ { .compatible = "eswin,eic7700-pvt"}, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, pvt_of_match); -+ -+static struct platform_driver pvt_driver = { -+ .probe = eic7700_pvt_probe, -+ .driver = { -+ .name = "eic7700-pvt", -+ .of_match_table = pvt_of_match, -+ .pm = pm_ptr(&eic7700_pvt_pm_ops), -+ }, -+}; -+module_platform_driver(pvt_driver); -+ -+MODULE_AUTHOR("Yulin Lu "); -+MODULE_AUTHOR("Huan He "); -+MODULE_DESCRIPTION("Eswin eic7700 PVT driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hwmon/eic7700-pvt.h b/drivers/hwmon/eic7700-pvt.h -new file mode 100644 ---- /dev/null -+++ b/drivers/hwmon/eic7700-pvt.h -@@ -0,0 +1,99 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * ESWIN EIC7700 Voltage, Temperature sensor driver -+ * -+ * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd. -+ */ -+#ifndef __HWMON_EIC7700_PVT_H__ -+#define __HWMON_EIC7700_PVT_H__ -+ -+#include -+#include -+#include -+#include -+ -+/* ESWIN EIC7700 PVT registers and their bitfields */ -+#define PVT_TRIM 0x04 -+#define PVT_MODE 0x08 -+#define PVT_MODE_MASK GENMASK(2, 0) -+#define PVT_CTRL_MODE_TEMP 0x0 -+#define PVT_CTRL_MODE_VOLT 0x4 -+#define PVT_ENA 0x0c -+#define PVT_ENA_EN BIT(0) -+#define PVT_INT 0x10 -+#define PVT_INT_STAT BIT(0) -+#define PVT_INT_CLR BIT(1) -+#define PVT_DATA 0x14 -+#define PVT_DATA_OUT GENMASK(9, 0) -+ -+/* -+ * PVT sensors-related limits and default values -+ * @PVT_TEMP_CHS: Number of temperature hwmon channels. -+ * @PVT_VOLT_CHS: Number of voltage hwmon channels. -+ * @PVT_TRIM_DEF: Default temperature sensor trim value (set a proper value -+ * when one is determined for ESWIN EIC7700 SoC). -+ * @PVT_TOUT_MIN: Minimal timeout between samples in nanoseconds. -+ */ -+#define PVT_TEMP_CHS 1 -+#define PVT_VOLT_CHS 1 -+#define PVT_TRIM_DEF 0 -+#define PVT_TOUT_MIN (NSEC_PER_SEC / 3000) -+ -+/* -+ * enum pvt_sensor_type - ESWIN EIC7700 PVT sensor types (correspond to each PVT -+ * sampling mode) -+ * @PVT_TEMP: PVT Temperature sensor. -+ * @PVT_VOLT: PVT Voltage sensor. -+ */ -+enum pvt_sensor_type { -+ PVT_TEMP = 0, -+ PVT_VOLT -+}; -+ -+#define PVT_CLK_NUM 2 -+ -+/* -+ * struct pvt_sensor_info - ESWIN EIC7700 PVT sensor informational structure -+ * @channel: Sensor channel ID. -+ * @label: hwmon sensor label. -+ * @mode: PVT mode corresponding to the channel. -+ * @type: Sensor type. -+ */ -+struct pvt_sensor_info { -+ int channel; -+ const char *label; -+ u32 mode; -+ enum hwmon_sensor_types type; -+}; -+ -+#define PVT_SENSOR_INFO(_ch, _label, _type, _mode) \ -+ { \ -+ .channel = _ch, \ -+ .label = _label, \ -+ .mode = PVT_CTRL_MODE_ ##_mode, \ -+ .type = _type, \ -+ } -+ -+/* -+ * struct pvt_hwmon - Eswin EIC7700 PVT private data -+ * @dev: device structure of the PVT platform device. -+ * @hwmon: hwmon device structure. -+ * @regs: pointer to the Eswin EIC7700 PVT registers region. -+ * @irq: PVT events IRQ number. -+ * @clks: PVT clock descriptors. -+ * @data_cache: data cache in raw format. -+ * @conversion: data conversion completion. -+ * @timeout: conversion timeout. -+ */ -+struct pvt_hwmon { -+ struct device *dev; -+ struct device *hwmon; -+ void __iomem *regs; -+ int irq; -+ struct clk_bulk_data clks[PVT_CLK_NUM]; -+ u32 data_cache; -+ struct completion conversion; -+ ktime_t timeout; -+}; -+ -+#endif /* __HWMON_EIC7700_PVT_H__ */ -diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c ---- a/drivers/hwmon/emc1403.c -+++ b/drivers/hwmon/emc1403.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - #include - - #define THERMAL_PID_REG 0xfd -@@ -654,14 +655,20 @@ static int emc1403_probe(struct i2c_client *client) - { - struct thermal_data *data; - struct device *hwmon_dev; -- const struct i2c_device_id *id = i2c_match_id(emc1403_idtable, client); -+ int ret; -+ -+ ret = devm_regulator_get_enable(&client->dev, "vdd"); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, -+ "Failed to enable regulator\n"); - - data = devm_kzalloc(&client->dev, sizeof(struct thermal_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - -- data->chip = id->driver_data; -+ data->chip = (uintptr_t)i2c_get_match_data(client); -+ - data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config); - if (IS_ERR(data->regmap)) - return PTR_ERR(data->regmap); -@@ -677,10 +684,20 @@ static const unsigned short emc1403_address_list[] = { - 0x18, 0x1c, 0x29, 0x3c, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END - }; - -+static const struct of_device_id emc1403_of_match[] = { -+ { .compatible = "smsc,emc1402", .data = (void *)emc1402 }, -+ { .compatible = "smsc,emc1403", .data = (void *)emc1403 }, -+ { .compatible = "smsc,emc1404", .data = (void *)emc1404 }, -+ { .compatible = "smsc,emc1428", .data = (void *)emc1428 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, emc1403_of_match); -+ - static struct i2c_driver sensor_emc1403 = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "emc1403", -+ .of_match_table = emc1403_of_match, - }, - .detect = emc1403_detect, - .probe = emc1403_probe, -diff --git a/drivers/hwmon/gxp-fan-ctrl.c b/drivers/hwmon/gxp-fan-ctrl.c ---- a/drivers/hwmon/gxp-fan-ctrl.c -+++ b/drivers/hwmon/gxp-fan-ctrl.c -@@ -1,59 +1,16 @@ - // SPDX-License-Identifier: GPL-2.0-only --/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */ -+/* Copyright (C) 2023 Hewlett-Packard Enterprise Development Company, L.P. */ - --#include - #include - #include - #include - #include - #include - --#define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */ --#define OFS_FAN_FAIL 2 /* Is 2 bytes after base */ --#define OFS_SEVSTAT 0 /* Is 0 because fn2 base will be set at SEVSTAT */ --#define POWER_BIT 24 -- - struct gxp_fan_ctrl_drvdata { - void __iomem *base; -- void __iomem *plreg; -- void __iomem *fn2; - }; - --static bool fan_installed(struct device *dev, int fan) --{ -- struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); -- u8 val; -- -- val = readb(drvdata->plreg + OFS_FAN_INST); -- -- return !!(val & BIT(fan)); --} -- --static long fan_failed(struct device *dev, int fan) --{ -- struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); -- u8 val; -- -- val = readb(drvdata->plreg + OFS_FAN_FAIL); -- -- return !!(val & BIT(fan)); --} -- --static long fan_enabled(struct device *dev, int fan) --{ -- struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); -- u32 val; -- -- /* -- * Check the power status as if the platform is off the value -- * reported for the PWM will be incorrect. Report fan as -- * disabled. -- */ -- val = readl(drvdata->fn2 + OFS_SEVSTAT); -- -- return !!((val & BIT(POWER_BIT)) && fan_installed(dev, fan)); --} -- - static int gxp_pwm_write(struct device *dev, u32 attr, int channel, long val) - { - struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); -@@ -80,37 +37,11 @@ static int gxp_fan_ctrl_write(struct device *dev, enum hwmon_sensor_types type, - } - } - --static int gxp_fan_read(struct device *dev, u32 attr, int channel, long *val) --{ -- switch (attr) { -- case hwmon_fan_enable: -- *val = fan_enabled(dev, channel); -- return 0; -- case hwmon_fan_fault: -- *val = fan_failed(dev, channel); -- return 0; -- default: -- return -EOPNOTSUPP; -- } --} -- - static int gxp_pwm_read(struct device *dev, u32 attr, int channel, long *val) - { - struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); -- u32 reg; - -- /* -- * Check the power status of the platform. If the platform is off -- * the value reported for the PWM will be incorrect. In this case -- * report a PWM of zero. -- */ -- -- reg = readl(drvdata->fn2 + OFS_SEVSTAT); -- -- if (reg & BIT(POWER_BIT)) -- *val = fan_installed(dev, channel) ? readb(drvdata->base + channel) : 0; -- else -- *val = 0; -+ *val = readb(drvdata->base + channel); - - return 0; - } -@@ -119,8 +50,6 @@ static int gxp_fan_ctrl_read(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *val) - { - switch (type) { -- case hwmon_fan: -- return gxp_fan_read(dev, attr, channel, val); - case hwmon_pwm: - return gxp_pwm_read(dev, attr, channel, val); - default: -@@ -135,16 +64,6 @@ static umode_t gxp_fan_ctrl_is_visible(const void *_data, - umode_t mode = 0; - - switch (type) { -- case hwmon_fan: -- switch (attr) { -- case hwmon_fan_enable: -- case hwmon_fan_fault: -- mode = 0444; -- break; -- default: -- break; -- } -- break; - case hwmon_pwm: - switch (attr) { - case hwmon_pwm_input: -@@ -168,15 +87,6 @@ static const struct hwmon_ops gxp_fan_ctrl_ops = { - }; - - static const struct hwmon_channel_info * const gxp_fan_ctrl_info[] = { -- HWMON_CHANNEL_INFO(fan, -- HWMON_F_FAULT | HWMON_F_ENABLE, -- HWMON_F_FAULT | HWMON_F_ENABLE, -- HWMON_F_FAULT | HWMON_F_ENABLE, -- HWMON_F_FAULT | HWMON_F_ENABLE, -- HWMON_F_FAULT | HWMON_F_ENABLE, -- HWMON_F_FAULT | HWMON_F_ENABLE, -- HWMON_F_FAULT | HWMON_F_ENABLE, -- HWMON_F_FAULT | HWMON_F_ENABLE), - HWMON_CHANNEL_INFO(pwm, - HWMON_PWM_INPUT, - HWMON_PWM_INPUT, -@@ -211,18 +121,6 @@ static int gxp_fan_ctrl_probe(struct platform_device *pdev) - return dev_err_probe(dev, PTR_ERR(drvdata->base), - "failed to map base\n"); - -- drvdata->plreg = devm_platform_ioremap_resource_byname(pdev, -- "pl"); -- if (IS_ERR(drvdata->plreg)) -- return dev_err_probe(dev, PTR_ERR(drvdata->plreg), -- "failed to map plreg\n"); -- -- drvdata->fn2 = devm_platform_ioremap_resource_byname(pdev, -- "fn2"); -- if (IS_ERR(drvdata->fn2)) -- return dev_err_probe(dev, PTR_ERR(drvdata->fn2), -- "failed to map fn2\n"); -- - hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, - "hpe_gxp_fan_ctrl", - drvdata, -diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c ---- a/drivers/hwmon/hwmon.c -+++ b/drivers/hwmon/hwmon.c -@@ -57,8 +57,8 @@ struct hwmon_device_attribute { - }; - - #define to_hwmon_attr(d) \ -- container_of(d, struct hwmon_device_attribute, dev_attr) --#define to_dev_attr(a) container_of(a, struct device_attribute, attr) -+ container_of_const(d, struct hwmon_device_attribute, dev_attr) -+#define to_dev_attr(a) container_of_const(a, struct device_attribute, attr) - - /* - * Thermal zone information -@@ -71,27 +71,27 @@ struct hwmon_thermal_data { - }; - - static ssize_t --name_show(struct device *dev, struct device_attribute *attr, char *buf) -+name_show(struct device *dev, const struct device_attribute *attr, char *buf) - { - return sysfs_emit(buf, "%s\n", to_hwmon_device(dev)->name); - } --static DEVICE_ATTR_RO(name); -+static const DEVICE_ATTR_RO(name); - - static ssize_t --label_show(struct device *dev, struct device_attribute *attr, char *buf) -+label_show(struct device *dev, const struct device_attribute *attr, char *buf) - { - return sysfs_emit(buf, "%s\n", to_hwmon_device(dev)->label); - } --static DEVICE_ATTR_RO(label); -+static const DEVICE_ATTR_RO(label); - --static struct attribute *hwmon_dev_attrs[] = { -+static const struct attribute *const hwmon_dev_attrs[] = { - &dev_attr_name.attr, - &dev_attr_label.attr, - NULL - }; - - static umode_t hwmon_dev_attr_is_visible(struct kobject *kobj, -- struct attribute *attr, int n) -+ const struct attribute *attr, int n) - { - struct device *dev = kobj_to_dev(kobj); - struct hwmon_device *hdev = to_hwmon_device(dev); -@@ -106,8 +106,8 @@ static umode_t hwmon_dev_attr_is_visible(struct kobject *kobj, - } - - static const struct attribute_group hwmon_dev_attr_group = { -- .attrs = hwmon_dev_attrs, -- .is_visible = hwmon_dev_attr_is_visible, -+ .attrs_const = hwmon_dev_attrs, -+ .is_visible_const = hwmon_dev_attr_is_visible, - }; - - static const struct attribute_group *hwmon_dev_attr_groups[] = { -@@ -115,13 +115,13 @@ static const struct attribute_group *hwmon_dev_attr_groups[] = { - NULL - }; - --static void hwmon_free_attrs(struct attribute **attrs) -+static void hwmon_free_attrs(const struct attribute *const *attrs) - { - int i; - - for (i = 0; attrs[i]; i++) { -- struct device_attribute *dattr = to_dev_attr(attrs[i]); -- struct hwmon_device_attribute *hattr = to_hwmon_attr(dattr); -+ const struct device_attribute *dattr = to_dev_attr(attrs[i]); -+ const struct hwmon_device_attribute *hattr = to_hwmon_attr(dattr); - - kfree(hattr); - } -@@ -132,8 +132,8 @@ static void hwmon_dev_release(struct device *dev) - { - struct hwmon_device *hwdev = to_hwmon_device(dev); - -- if (hwdev->group.attrs) -- hwmon_free_attrs(hwdev->group.attrs); -+ if (hwdev->group.attrs_const) -+ hwmon_free_attrs(hwdev->group.attrs_const); - kfree(hwdev->groups); - kfree(hwdev->label); - kfree(hwdev); -@@ -341,7 +341,7 @@ static int hwmon_match_device(struct device *dev, const void *data) - return dev->class == &hwmon_class; - } - --static ssize_t pec_show(struct device *dev, struct device_attribute *dummy, -+static ssize_t pec_show(struct device *dev, const struct device_attribute *dummy, - char *buf) - { - struct i2c_client *client = to_i2c_client(dev); -@@ -349,7 +349,7 @@ static ssize_t pec_show(struct device *dev, struct device_attribute *dummy, - return sysfs_emit(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC)); - } - --static ssize_t pec_store(struct device *dev, struct device_attribute *devattr, -+static ssize_t pec_store(struct device *dev, const struct device_attribute *devattr, - const char *buf, size_t count) - { - struct i2c_client *client = to_i2c_client(dev); -@@ -389,7 +389,7 @@ static ssize_t pec_store(struct device *dev, struct device_attribute *devattr, - return err; - } - --static DEVICE_ATTR_RW(pec); -+static const DEVICE_ATTR_RW(pec); - - static void hwmon_remove_pec(void *dev) - { -@@ -424,9 +424,9 @@ static int hwmon_pec_register(struct device *hdev) - /* sysfs attribute management */ - - static ssize_t hwmon_attr_show(struct device *dev, -- struct device_attribute *devattr, char *buf) -+ const struct device_attribute *devattr, char *buf) - { -- struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); -+ const struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); - struct hwmon_device *hwdev = to_hwmon_device(dev); - s64 val64; - long val; -@@ -449,10 +449,10 @@ static ssize_t hwmon_attr_show(struct device *dev, - } - - static ssize_t hwmon_attr_show_string(struct device *dev, -- struct device_attribute *devattr, -+ const struct device_attribute *devattr, - char *buf) - { -- struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); -+ const struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); - struct hwmon_device *hwdev = to_hwmon_device(dev); - enum hwmon_sensor_types type = hattr->type; - const char *s; -@@ -472,10 +472,10 @@ static ssize_t hwmon_attr_show_string(struct device *dev, - } - - static ssize_t hwmon_attr_store(struct device *dev, -- struct device_attribute *devattr, -+ const struct device_attribute *devattr, - const char *buf, size_t count) - { -- struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); -+ const struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); - struct hwmon_device *hwdev = to_hwmon_device(dev); - long val; - int ret; -@@ -509,12 +509,12 @@ static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) - (type == hwmon_fan && attr == hwmon_fan_label); - } - --static struct attribute *hwmon_genattr(const void *drvdata, -- enum hwmon_sensor_types type, -- u32 attr, -- int index, -- const char *template, -- const struct hwmon_ops *ops) -+static const struct attribute *hwmon_genattr(const void *drvdata, -+ enum hwmon_sensor_types type, -+ u32 attr, -+ int index, -+ const char *template, -+ const struct hwmon_ops *ops) - { - struct hwmon_device_attribute *hattr; - struct device_attribute *dattr; -@@ -551,8 +551,8 @@ static struct attribute *hwmon_genattr(const void *drvdata, - hattr->ops = ops; - - dattr = &hattr->dev_attr; -- dattr->show = is_string ? hwmon_attr_show_string : hwmon_attr_show; -- dattr->store = hwmon_attr_store; -+ dattr->show_const = is_string ? hwmon_attr_show_string : hwmon_attr_show; -+ dattr->store_const = hwmon_attr_store; - - a = &dattr->attr; - sysfs_attr_init(a); -@@ -830,7 +830,7 @@ static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) - } - - static int hwmon_genattrs(const void *drvdata, -- struct attribute **attrs, -+ const struct attribute **attrs, - const struct hwmon_ops *ops, - const struct hwmon_channel_info *info) - { -@@ -849,7 +849,7 @@ static int hwmon_genattrs(const void *drvdata, - u32 attr; - - while (attr_mask) { -- struct attribute *a; -+ const struct attribute *a; - - attr = __ffs(attr_mask); - attr_mask &= ~BIT(attr); -@@ -868,11 +868,11 @@ static int hwmon_genattrs(const void *drvdata, - return aindex; - } - --static struct attribute ** -+static const struct attribute ** - __hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip) - { - int ret, i, aindex = 0, nattrs = 0; -- struct attribute **attrs; -+ const struct attribute **attrs; - - for (i = 0; chip->info[i]; i++) - nattrs += hwmon_num_channel_attrs(chip->info[i]); -@@ -927,7 +927,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, - hdev = &hwdev->dev; - - if (chip) { -- struct attribute **attrs; -+ const struct attribute **attrs; - int ngroups = 2; /* terminating NULL plus &hwdev->groups */ - - if (groups) -@@ -946,7 +946,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, - goto free_hwmon; - } - -- hwdev->group.attrs = attrs; -+ hwdev->group.attrs_const = attrs; - ngroups = 0; - hwdev->groups[ngroups++] = &hwdev->group; - -diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c ---- a/drivers/hwmon/ina2xx.c -+++ b/drivers/hwmon/ina2xx.c -@@ -124,6 +124,7 @@ static const struct regmap_config ina2xx_regmap_config = { - enum ina2xx_ids { - ina219, - ina226, -+ ina232, - ina234, - ina260, - sy24655 -@@ -210,6 +211,20 @@ static const struct ina2xx_config ina2xx_config[] = { - .current_shift = 4, - .has_update_interval = true, - }, -+ [ina232] = { -+ .config_default = INA226_CONFIG_DEFAULT, -+ .calibration_value = 2048, -+ .shunt_div = 400, -+ .shunt_voltage_shift = 0, -+ .bus_voltage_shift = 0, -+ .bus_voltage_lsb = 1600, -+ .power_lsb_factor = 32, -+ .has_alerts = true, -+ .has_ishunt = false, -+ .has_power_average = false, -+ .current_shift = 0, -+ .has_update_interval = true, -+ }, - [ina260] = { - .config_default = INA260_CONFIG_DEFAULT, - .shunt_div = 400, -@@ -1123,6 +1138,7 @@ static const struct i2c_device_id ina2xx_id[] = { - { .name = "ina226", .driver_data = ina226 }, - { .name = "ina230", .driver_data = ina226 }, - { .name = "ina231", .driver_data = ina226 }, -+ { .name = "ina232", .driver_data = ina232 }, - { .name = "ina234", .driver_data = ina234 }, - { .name = "ina260", .driver_data = ina260 }, - { .name = "sy24655", .driver_data = sy24655 }, -@@ -1155,6 +1171,10 @@ static const struct of_device_id __maybe_unused ina2xx_of_match[] = { - .compatible = "ti,ina231", - .data = (void *)ina226 - }, -+ { -+ .compatible = "ti,ina232", -+ .data = (void *)ina232 -+ }, - { - .compatible = "ti,ina234", - .data = (void *)ina234 -diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c ---- a/drivers/hwmon/k10temp.c -+++ b/drivers/hwmon/k10temp.c -@@ -207,6 +207,10 @@ static const char *k10temp_temp_label[] = { - "Tccd10", - "Tccd11", - "Tccd12", -+ "Tccd13", -+ "Tccd14", -+ "Tccd15", -+ "Tccd16", - }; - - static int k10temp_read_labels(struct device *dev, -@@ -243,7 +247,7 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel, - if (*val < 0 && !data->disp_negative) - *val = 0; - break; -- case 2 ... 13: /* Tccd{1-12} */ -+ case 2 ... 17: /* Tccd{1-16} */ - ret = read_ccd_temp_reg(data, channel - 2, ®val); - - if (ret) -@@ -384,6 +388,10 @@ static const struct hwmon_channel_info * const k10temp_info[] = { - HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, -+ HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL), - NULL - }; -@@ -515,6 +523,10 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) - } - } else if (boot_cpu_data.x86 == 0x1a) { - switch (boot_cpu_data.x86_model) { -+ case 0x00 ... 0x2f: /* Zen5 Turin */ -+ data->ccd_offset = 0x1F0; -+ k10temp_get_ccd_support(data, 16); -+ break; - case 0x40 ... 0x4f: /* Zen5 Ryzen Desktop */ - data->ccd_offset = 0x308; - k10temp_get_ccd_support(data, 8); -diff --git a/drivers/hwmon/kb9002.c b/drivers/hwmon/kb9002.c -new file mode 100644 ---- /dev/null -+++ b/drivers/hwmon/kb9002.c -@@ -0,0 +1,460 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Kandou KB9002 PCIe 5.0 retimer hwmon driver. -+ * -+ * The retimer exposes a system management bus (SMBus 3.0 with PEC) -+ * target for firmware-managed status registers. This driver assumes -+ * the chip is strapped to SMBus mode and exports the aggregated -+ * maximum die temperature as hwmon temp1_input (millidegrees Celsius) -+ * plus the firmware version and boot status under debugfs. -+ * -+ * The raw-I2C path (kb9002_i2c_read/write, used only at probe to switch -+ * the host interface) carries the 32-bit register address and data -+ * big-endian. The SMBus path (kb9002_fw_read/kb9002_smbus_hw_read) -+ * carries the register address and returned data little-endian. -+ * -+ * Datasheet: Kandou KB9002 PCIe retimer (KA-015171-PD). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define KB9002_DEV_NAME "kb9002" -+ -+/* -+ * SMBus read command codes. Each read is a two-phase PEC-protected -+ * transaction: prime writes the target address, data reads it back with -+ * the register contents. FW reads use a 16-bit address, HW reads 32-bit. -+ */ -+#define KB9002_CC_FW_READ_PRIME 0x82 -+#define KB9002_CC_FW_READ_DATA 0x81 -+#define KB9002_CC_HW_READ_PRIME 0x8a -+#define KB9002_CC_HW_READ_DATA 0x89 -+ -+/* Firmware register offsets (16-bit). */ -+#define KB9002_FW_REG_VID 0x0004 -+#define KB9002_FW_REG_FW_VERSION 0x0500 -+#define KB9002_FW_REG_TEMP_MAXIMUM 0x0550 -+ -+#define KB9002_VID_MASK GENMASK(31, 16) -+#define KB9002_VID_KANDOU 0x1e6f -+ -+/* Firmware boot status: 0xe8 in the top byte means init completed OK. */ -+#define KB9002_HW_REG_FW_BOOT_STATUS 0xe0090008 -+#define KB9002_FW_BOOT_STATUS_OK_MSB 0xe8 -+ -+/* -+ * Hardware registers reached over raw I2C (32-bit addressing). The -+ * host-interface bit selects SMBus (set) vs raw-I2C target; parts -+ * strapped to raw I2C need it set before SMBus access works. -+ */ -+#define KB9002_HW_REG_REVID 0x00480004 -+#define KB9002_HW_REG_HOST_IF 0x00480008 -+#define KB9002_HOST_IF_SMBUS BIT(1) -+ -+#define KB9002_REVID_MASK GENMASK(7, 0) -+#define KB9002_REVID_B0 0x10 -+#define KB9002_REVID_B1 0x11 -+ -+/* Retries to drain a stray leading 0xff from the raw-I2C FIFO. */ -+#define KB9002_REVID_READ_RETRIES 16 -+ -+/* Temperature: 32-bit Q16.16 absolute Kelvin. */ -+#define KB9002_TEMP_FRAC_BITS 16 -+#define KB9002_ABS_ZERO_MILLI_C (-273150) -+ -+/* Firmware takes up to ~2s to respond after a host-interface change. */ -+#define KB9002_FW_READY_POLL_US (25 * USEC_PER_MSEC) -+#define KB9002_FW_READY_TIMEOUT_US (2 * USEC_PER_SEC) -+ -+struct kb9002_data { -+ struct i2c_client *client; -+ struct device *hwmon_dev; -+}; -+ -+/* Raw-I2C read: write the 32-bit BE address, then read 4 BE data bytes. */ -+static int kb9002_i2c_read(struct i2c_client *client, u32 reg, u32 *val) -+{ -+ u8 addr[4]; -+ u8 rbuf[4]; -+ struct i2c_msg msgs[2] = { -+ { -+ .addr = client->addr, -+ .flags = 0, -+ .len = sizeof(addr), -+ .buf = addr, -+ }, -+ { -+ .addr = client->addr, -+ .flags = I2C_M_RD, -+ .len = sizeof(rbuf), -+ .buf = rbuf, -+ }, -+ }; -+ int ret; -+ -+ put_unaligned_be32(reg, addr); -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret < 0) -+ return ret; -+ if (ret != ARRAY_SIZE(msgs)) -+ return -EIO; -+ -+ *val = get_unaligned_be32(rbuf); -+ return 0; -+} -+ -+/* Raw-I2C write: 4 BE address bytes followed by 4 BE data bytes. */ -+static int kb9002_i2c_write(struct i2c_client *client, u32 reg, u32 val) -+{ -+ u8 buf[8]; -+ struct i2c_msg msg = { -+ .addr = client->addr, -+ .flags = 0, -+ .len = sizeof(buf), -+ .buf = buf, -+ }; -+ int ret; -+ -+ put_unaligned_be32(reg, &buf[0]); -+ put_unaligned_be32(val, &buf[4]); -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ if (ret < 0) -+ return ret; -+ if (ret != 1) -+ return -EIO; -+ -+ return 0; -+} -+ -+/* -+ * Read the silicon revision ID. A fresh FIFO may start with a stray -+ * 0xff that shifts the result, so drain one byte between retries until -+ * the top byte is no longer 0xff. -+ */ -+static int kb9002_read_revid(struct i2c_client *client, u32 *revid) -+{ -+ u8 dummy; -+ int ret; -+ int i; -+ -+ for (i = 0; i < KB9002_REVID_READ_RETRIES; i++) { -+ ret = kb9002_i2c_read(client, KB9002_HW_REG_REVID, revid); -+ if (ret) -+ return ret; -+ if ((*revid >> 24) != 0xff) -+ return 0; -+ /* Drain one byte from the chip to re-align the I2C FIFO. */ -+ i2c_master_recv(client, &dummy, 1); -+ } -+ -+ return -EIO; -+} -+ -+/* -+ * Read a 32-bit firmware register over SMBus: block-write the 16-bit LE -+ * address, then block-read the echoed address plus 4 LE data bytes. -+ */ -+static int kb9002_fw_read(struct kb9002_data *data, u16 reg, u32 *val) -+{ -+ struct i2c_client *client = data->client; -+ u8 addr[2]; -+ u8 rbuf[I2C_SMBUS_BLOCK_MAX]; -+ int ret; -+ -+ put_unaligned_le16(reg, addr); -+ -+ ret = i2c_smbus_write_block_data(client, KB9002_CC_FW_READ_PRIME, -+ sizeof(addr), addr); -+ if (ret < 0) -+ return ret; -+ -+ ret = i2c_smbus_read_block_data(client, KB9002_CC_FW_READ_DATA, rbuf); -+ if (ret < 0) -+ return ret; -+ if (ret < (int)(sizeof(addr) + sizeof(*val))) -+ return -EIO; -+ -+ *val = get_unaligned_le32(&rbuf[sizeof(addr)]); -+ return 0; -+} -+ -+/* Like kb9002_fw_read but for a hardware register (32-bit LE address). */ -+static int kb9002_smbus_hw_read(struct kb9002_data *data, u32 reg, u32 *val) -+{ -+ struct i2c_client *client = data->client; -+ u8 addr[4]; -+ u8 rbuf[I2C_SMBUS_BLOCK_MAX]; -+ int ret; -+ -+ put_unaligned_le32(reg, addr); -+ -+ ret = i2c_smbus_write_block_data(client, KB9002_CC_HW_READ_PRIME, -+ sizeof(addr), addr); -+ if (ret < 0) -+ return ret; -+ -+ ret = i2c_smbus_read_block_data(client, KB9002_CC_HW_READ_DATA, rbuf); -+ if (ret < 0) -+ return ret; -+ if (ret < (int)(sizeof(addr) + sizeof(*val))) -+ return -EIO; -+ -+ *val = get_unaligned_le32(&rbuf[sizeof(addr)]); -+ return 0; -+} -+ -+/* -+ * Switch the host interface from raw-I2C to SMBus and wait for firmware -+ * to come back up. Called only when SMBus access failed in probe, i.e. -+ * the chip is strapped to raw-I2C mode. Confirms the revision, sets the -+ * SMBus-mode bit, then polls until firmware responds again. -+ */ -+static int kb9002_enable_smbus_target(struct kb9002_data *data) -+{ -+ struct i2c_client *client = data->client; -+ u32 revid; -+ u32 val; -+ int op_ret; -+ int ret; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) -+ return dev_err_probe(&client->dev, -ENODEV, -+ "raw I2C required to switch to SMBus mode\n"); -+ -+ ret = kb9002_read_revid(client, &revid); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, -+ "revision ID read failed\n"); -+ -+ switch (FIELD_GET(KB9002_REVID_MASK, revid)) { -+ case KB9002_REVID_B0: -+ case KB9002_REVID_B1: -+ break; -+ default: -+ return dev_err_probe(&client->dev, -ENODEV, -+ "unsupported revision ID 0x%08x\n", revid); -+ } -+ -+ ret = kb9002_i2c_read(client, KB9002_HW_REG_HOST_IF, &val); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, -+ "host interface read failed\n"); -+ -+ val |= KB9002_HOST_IF_SMBUS; -+ -+ ret = kb9002_i2c_write(client, KB9002_HW_REG_HOST_IF, val); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, -+ "host interface write failed\n"); -+ -+ /* Wait until firmware re-initialisation completes. */ -+ ret = read_poll_timeout(kb9002_fw_read, op_ret, op_ret == 0, -+ KB9002_FW_READY_POLL_US, -+ KB9002_FW_READY_TIMEOUT_US, true, -+ data, KB9002_FW_REG_VID, &val); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, -+ "firmware not responding over SMBus\n"); -+ -+ return 0; -+} -+ -+/* Convert Q16.16 absolute Kelvin to millidegrees Celsius. */ -+static long kb9002_temp_to_milli_c(u32 raw) -+{ -+ s64 milli_k = ((s64)raw * 1000) >> KB9002_TEMP_FRAC_BITS; -+ -+ return (long)milli_k + KB9002_ABS_ZERO_MILLI_C; -+} -+ -+static int kb9002_read_temp(struct kb9002_data *data, long *val) -+{ -+ u32 raw; -+ int ret; -+ -+ ret = kb9002_fw_read(data, KB9002_FW_REG_TEMP_MAXIMUM, &raw); -+ if (ret) -+ return ret; -+ -+ *val = kb9002_temp_to_milli_c(raw); -+ return 0; -+} -+ -+static umode_t kb9002_is_visible(const void *drvdata, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ return 0444; -+} -+ -+static int kb9002_read(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long *val) -+{ -+ struct kb9002_data *data = dev_get_drvdata(dev); -+ -+ if (type == hwmon_temp && attr == hwmon_temp_input) -+ return kb9002_read_temp(data, val); -+ -+ return -EOPNOTSUPP; -+} -+ -+static const struct hwmon_ops kb9002_hwmon_ops = { -+ .is_visible = kb9002_is_visible, -+ .read = kb9002_read, -+}; -+ -+static const struct hwmon_channel_info * const kb9002_hwmon_info[] = { -+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), -+ NULL, -+}; -+ -+static const struct hwmon_chip_info kb9002_chip_info = { -+ .ops = &kb9002_hwmon_ops, -+ .info = kb9002_hwmon_info, -+}; -+ -+static int kb9002_fw_version_show(struct seq_file *s, void *unused) -+{ -+ struct kb9002_data *data = s->private; -+ u32 ver; -+ int ret; -+ -+ guard(hwmon_lock)(data->hwmon_dev); -+ -+ ret = kb9002_fw_read(data, KB9002_FW_REG_FW_VERSION, &ver); -+ if (ret) -+ return ret; -+ -+ seq_printf(s, "%u.%02u.%02u.%u\n", -+ (ver >> 24) & 0xff, (ver >> 16) & 0xff, -+ (ver >> 8) & 0xff, (ver >> 0) & 0xff); -+ return 0; -+} -+DEFINE_SHOW_ATTRIBUTE(kb9002_fw_version); -+ -+static int kb9002_fw_load_status_show(struct seq_file *s, void *unused) -+{ -+ struct kb9002_data *data = s->private; -+ u32 status; -+ int ret; -+ -+ guard(hwmon_lock)(data->hwmon_dev); -+ -+ ret = kb9002_smbus_hw_read(data, KB9002_HW_REG_FW_BOOT_STATUS, &status); -+ if (ret) -+ return ret; -+ -+ seq_printf(s, "%s\n", -+ (status >> 24) == KB9002_FW_BOOT_STATUS_OK_MSB ? -+ "normal" : "abnormal"); -+ return 0; -+} -+DEFINE_SHOW_ATTRIBUTE(kb9002_fw_load_status); -+ -+static void kb9002_debugfs_init(struct kb9002_data *data) -+{ -+ struct dentry *dir = data->client->debugfs; -+ -+ debugfs_create_file("fw_ver", 0444, dir, data, -+ &kb9002_fw_version_fops); -+ debugfs_create_file("fw_load_status", 0444, dir, data, -+ &kb9002_fw_load_status_fops); -+} -+ -+static int kb9002_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct kb9002_data *data; -+ struct device *hwmon_dev; -+ u32 vid; -+ int ret; -+ -+ if (!i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_BLOCK_DATA | -+ I2C_FUNC_SMBUS_PEC)) -+ return -ENODEV; -+ -+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->client = client; -+ -+ /* All firmware register accesses are PEC-protected. */ -+ client->flags |= I2C_CLIENT_PEC; -+ -+ i2c_set_clientdata(client, data); -+ -+ /* -+ * Try SMBus first. If the chip is strapped to raw-I2C mode it -+ * will not respond to SMBus framing, so fall back to switching -+ * the host interface over raw I2C and retry. -+ */ -+ ret = kb9002_fw_read(data, KB9002_FW_REG_VID, &vid); -+ if (ret) { -+ dev_dbg(dev, "SMBus probe failed (%d), trying raw-I2C host-interface switch\n", -+ ret); -+ ret = kb9002_enable_smbus_target(data); -+ if (ret) -+ return ret; -+ ret = kb9002_fw_read(data, KB9002_FW_REG_VID, &vid); -+ if (ret) -+ return dev_err_probe(dev, ret, -+ "VID read failed after host-interface switch\n"); -+ } -+ if (FIELD_GET(KB9002_VID_MASK, vid) != KB9002_VID_KANDOU) -+ return dev_err_probe(dev, -ENODEV, -+ "unexpected VID 0x%08x\n", vid); -+ -+ hwmon_dev = devm_hwmon_device_register_with_info(dev, KB9002_DEV_NAME, -+ data, -+ &kb9002_chip_info, -+ NULL); -+ if (IS_ERR(hwmon_dev)) -+ return PTR_ERR(hwmon_dev); -+ -+ data->hwmon_dev = hwmon_dev; -+ kb9002_debugfs_init(data); -+ return 0; -+} -+ -+static const struct i2c_device_id kb9002_id[] = { -+ { .name = KB9002_DEV_NAME }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, kb9002_id); -+ -+static const struct of_device_id kb9002_of_match[] = { -+ { .compatible = "kandou,kb9002" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, kb9002_of_match); -+ -+static struct i2c_driver kb9002_driver = { -+ .driver = { -+ .name = KB9002_DEV_NAME, -+ .of_match_table = kb9002_of_match, -+ }, -+ .probe = kb9002_probe, -+ .id_table = kb9002_id, -+}; -+module_i2c_driver(kb9002_driver); -+ -+MODULE_AUTHOR("Andy Chung "); -+MODULE_DESCRIPTION("Kandou KB9002 PCIe retimer hwmon driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c ---- a/drivers/hwmon/lm90.c -+++ b/drivers/hwmon/lm90.c -@@ -101,6 +101,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -108,7 +109,7 @@ - #include - #include - #include --#include -+#include - #include - #include - #include -@@ -295,7 +296,7 @@ static const struct i2c_device_id lm90_id[] = { - }; - MODULE_DEVICE_TABLE(i2c, lm90_id); - --static const struct of_device_id __maybe_unused lm90_of_match[] = { -+static const struct of_device_id lm90_of_match[] = { - { - .compatible = "adi,adm1032", - .data = (void *)adm1032 -@@ -2602,7 +2603,6 @@ static void lm90_stop_work(void *_data) - - static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) - { -- struct device_node *np = client->dev.of_node; - int config, convrate; - - if (data->flags & LM90_HAVE_CONVRATE) { -@@ -2626,7 +2626,7 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data) - - /* Check Temperature Range Select */ - if (data->flags & LM90_HAVE_EXTENDED_TEMP) { -- if (of_property_read_bool(np, "ti,extended-range-enable")) -+ if (device_property_read_bool(&client->dev, "ti,extended-range-enable")) - config |= 0x04; - if (!(config & 0x04)) - data->flags &= ~LM90_HAVE_EXTENDED_TEMP; -@@ -2692,36 +2692,41 @@ static irqreturn_t lm90_irq_thread(int irq, void *dev_id) - return IRQ_NONE; - } - --static int lm90_probe_channel_from_dt(struct i2c_client *client, -- struct device_node *child, -- struct lm90_data *data) -+static int lm90_probe_channel(struct i2c_client *client, -+ struct fwnode_handle *child, -+ struct lm90_data *data) - { - u32 id; - s32 val; - int err; - struct device *dev = &client->dev; - -- err = of_property_read_u32(child, "reg", &id); -+ err = fwnode_property_read_u32(child, "reg", &id); - if (err) { -- dev_err(dev, "missing reg property of %pOFn\n", child); -+ dev_err(dev, "missing reg property of %pfw\n", child); - return err; - } - - if (id >= MAX_CHANNELS) { -- dev_err(dev, "invalid reg property value %d in %pOFn\n", id, child); -+ dev_err(dev, "invalid reg property value %d in %pfw\n", id, child); - return -EINVAL; - } - -- err = of_property_read_string(child, "label", &data->channel_label[id]); -+ err = fwnode_property_read_string(child, "label", &data->channel_label[id]); - if (err == -ENODATA || err == -EILSEQ) { -- dev_err(dev, "invalid label property in %pOFn\n", child); -+ dev_err(dev, "invalid label property in %pfw\n", child); - return err; - } - - if (data->channel_label[id]) - data->channel_config[id] |= HWMON_T_LABEL; - -- err = of_property_read_s32(child, "temperature-offset-millicelsius", &val); -+ /* -+ * fwnode_property_read_u32() has no signed equivalent. -+ * temperature-offset-millicelsius is signed, so read and reinterpret it as s32 to -+ * preserve negative offsets values (same behavior as the old of_property_read_s32()). -+ */ -+ err = fwnode_property_read_u32(child, "temperature-offset-millicelsius", (u32 *)&val); - if (!err) { - if (id == 0) { - dev_err(dev, "temperature-offset-millicelsius can't be set for internal channel\n"); -@@ -2739,18 +2744,17 @@ static int lm90_probe_channel_from_dt(struct i2c_client *client, - return 0; - } - --static int lm90_parse_dt_channel_info(struct i2c_client *client, -- struct lm90_data *data) -+static int lm90_parse_channel_info(struct i2c_client *client, -+ struct lm90_data *data) - { - int err; - struct device *dev = &client->dev; -- const struct device_node *np = dev->of_node; - -- for_each_child_of_node_scoped(np, child) { -- if (strcmp(child->name, "channel")) -+ device_for_each_child_node_scoped(dev, child) { -+ if (!fwnode_name_eq(child, "channel")) - continue; - -- err = lm90_probe_channel_from_dt(client, child, data); -+ err = lm90_probe_channel(client, child, data); - if (err) - return err; - } -@@ -2887,12 +2891,10 @@ static int lm90_probe(struct i2c_client *client) - /* Set maximum conversion rate */ - data->max_convrate = lm90_params[data->kind].max_convrate; - -- /* Parse device-tree channel information */ -- if (client->dev.of_node) { -- err = lm90_parse_dt_channel_info(client, data); -- if (err) -- return err; -- } -+ /* Parse channel information */ -+ err = lm90_parse_channel_info(client, data); -+ if (err) -+ return err; - - /* Initialize the LM90 chip */ - err = lm90_init_client(client, data); -@@ -2918,10 +2920,8 @@ static int lm90_probe(struct i2c_client *client) - err = devm_request_threaded_irq(dev, client->irq, - NULL, lm90_irq_thread, - IRQF_ONESHOT, "lm90", client); -- if (err < 0) { -- dev_err(dev, "cannot request IRQ %d\n", client->irq); -+ if (err < 0) - return err; -- } - } - - return 0; -@@ -2985,7 +2985,7 @@ static struct i2c_driver lm90_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm90", -- .of_match_table = of_match_ptr(lm90_of_match), -+ .of_match_table = lm90_of_match, - .pm = pm_sleep_ptr(&lm90_pm_ops), - }, - .probe = lm90_probe, -diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c ---- a/drivers/hwmon/nct6775-core.c -+++ b/drivers/hwmon/nct6775-core.c -@@ -33,6 +33,7 @@ - * (0xd451) - * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3 - * (0xd429) -+ * nct5585d 14 7 7 2+6 0xd428 0xc1 0x5ca3 - * nct6796d-s 18 7 7 6+2 0xd801 0xc1 0x5ca3 - * nct6799d-r 18 7 7 6+2 0xd802 0xc1 0x5ca3 - * -diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c ---- a/drivers/hwmon/nct6775-platform.c -+++ b/drivers/hwmon/nct6775-platform.c -@@ -34,7 +34,7 @@ static const char * const nct6775_sio_names[] __initconst = { - [nct6795] = "NCT6795D", - [nct6796] = "NCT6796D", - [nct6797] = "NCT6797D", -- [nct6798] = "NCT6798D", -+ [nct6798] = "NCT6798D/NCT5585D", - [nct6799] = "NCT6796D-S/NCT6799D-R", - }; - -diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c ---- a/drivers/hwmon/npcm750-pwm-fan.c -+++ b/drivers/hwmon/npcm750-pwm-fan.c -@@ -996,10 +996,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev) - sprintf(name, "NPCM7XX-FAN-MD%d", i); - ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr, - 0, name, (void *)data); -- if (ret) { -- dev_err(dev, "register IRQ fan%d failed\n", i); -+ if (ret) - return ret; -- } - } - - for_each_child_of_node_scoped(np, child) { -diff --git a/drivers/hwmon/nzxt-kraken3.c b/drivers/hwmon/nzxt-kraken3.c ---- a/drivers/hwmon/nzxt-kraken3.c -+++ b/drivers/hwmon/nzxt-kraken3.c -@@ -1,6 +1,7 @@ - // SPDX-License-Identifier: GPL-2.0+ - /* -- * hwmon driver for NZXT Kraken X53/X63/X73, Z53/Z63/Z73 and 2023/2023 Elite all in one coolers. -+ * hwmon driver for NZXT Kraken X53/X63/X73, Z53/Z63/Z73, 2023/2023 Elite, and -+ * 2024 Elite all in one coolers. - * X53 and Z53 in code refer to all models in their respective series (shortened for brevity). - * 2023 models use the Z53 code paths. - * -@@ -25,6 +26,7 @@ - #define USB_PRODUCT_ID_Z53 0x3008 - #define USB_PRODUCT_ID_KRAKEN2023 0x300E - #define USB_PRODUCT_ID_KRAKEN2023_ELITE 0x300C -+#define USB_PRODUCT_ID_KRAKEN2024_ELITE 0x3012 - - enum kinds { X53, Z53, KRAKEN2023 } __packed; - enum pwm_enable { off, manual, curve } __packed; -@@ -927,6 +929,10 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id - priv->kind = KRAKEN2023; - device_name = "kraken2023elite"; - break; -+ case USB_PRODUCT_ID_KRAKEN2024_ELITE: -+ priv->kind = KRAKEN2023; -+ device_name = "kraken2024elite"; -+ break; - default: - ret = -ENODEV; - goto fail_and_close; -@@ -994,6 +1000,7 @@ static const struct hid_device_id kraken3_table[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_Z53) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_KRAKEN2023) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_KRAKEN2023_ELITE) }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_KRAKEN2024_ELITE) }, - { } - }; - -diff --git a/drivers/hwmon/peci/common.h b/drivers/hwmon/peci/common.h ---- a/drivers/hwmon/peci/common.h -+++ b/drivers/hwmon/peci/common.h -@@ -31,7 +31,7 @@ struct peci_sensor_data { - - /** - * peci_sensor_need_update() - check whether sensor update is needed or not -- * @sensor: pointer to sensor data struct -+ * @state: pointer to sensor state struct - * - * Return: true if update is needed, false if not. - */ -@@ -44,7 +44,7 @@ static inline bool peci_sensor_need_update(struct peci_sensor_state *state) - - /** - * peci_sensor_mark_updated() - mark the sensor is updated -- * @sensor: pointer to sensor data struct -+ * @state: pointer to sensor state struct - */ - static inline void peci_sensor_mark_updated(struct peci_sensor_state *state) - { -diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig ---- a/drivers/hwmon/pmbus/Kconfig -+++ b/drivers/hwmon/pmbus/Kconfig -@@ -52,8 +52,8 @@ config SENSORS_ADM1275 - help - If you say yes here you get hardware monitoring support for Analog - Devices ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, -- ADM1293, ADM1294 and SQ24905C Hot-Swap Controller and -- Digital Power Monitors. -+ ADM1293, ADM1294, ROHM BD12780, ROHM BD12790, and SQ24905C -+ Hot-Swap Controller and Digital Power Monitors. - - This driver can also be built as a module. If so, the module will - be called adm1275. -@@ -394,10 +394,10 @@ config SENSORS_MAX20751 - be called max20751. - - config SENSORS_MAX20830 -- tristate "Analog Devices MAX20830" -+ tristate "Analog Devices MAX20830 and compatibles" - help - If you say yes here you get hardware monitoring support for Analog -- Devices MAX20830. -+ Devices MAX20830, MAX20830C, and MAX20840C. - - This driver can also be built as a module. If so, the module will - be called max20830. -@@ -434,8 +434,9 @@ config SENSORS_MAX34440 - tristate "Maxim MAX34440 and compatibles" - help - If you say yes here you get hardware monitoring support for Maxim -- MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461. -- Other compatible are ADPM12160, and ADPM12200. -+ MAX34440, MAX34441, MAX34446, MAX34451, MAX34452, MAX34460, and -+ MAX34461. Other compatible devices are ADPM12160, ADPM12200, and -+ ADPM12250. - - This driver can also be built as a module. If so, the module will - be called max34440. -@@ -607,6 +608,15 @@ config SENSORS_MPQ7932 - This driver can also be built as a module. If so, the module will - be called mpq7932. - -+config SENSORS_MPQ82D00 -+ tristate "MPS MPQ82D00" -+ help -+ If you say yes here you get hardware monitoring functionality support -+ for power management IC MPS MPQ82D00. -+ -+ This driver can also be built as a module. If so, the module will -+ be called mpq82d00. -+ - config SENSORS_MPQ8785 - tristate "MPS MPQ8785" - help -@@ -616,6 +626,37 @@ config SENSORS_MPQ8785 - This driver can also be built as a module. If so, the module will - be called mpq8785. - -+config SENSORS_MPQ8646 -+ tristate "MPS MPQ8646" -+ depends on REGULATOR || !REGULATOR -+ depends on NVMEM || !NVMEM -+ help -+ If you say yes here you get hardware monitoring support for the -+ Monolithic Power Systems MPQ8646. -+ -+ This driver can also be built as a module. If so, the module -+ will be called mpq8646. -+ -+config SENSORS_MPQ8646_DEBUG_UNSAFE -+ bool "MPQ8646 unsafe write/provisioning debugfs (DANGEROUS)" -+ depends on SENSORS_MPQ8646 && DEBUG_FS -+ default n -+ help -+ Expose additional WRITE-able debugfs files in the client's -+ pmbus debugfs directory, -+ /sys/kernel/debug/i2c/i2c-/-/ -+ -+ These are provisioning and bring-up aids. On many designs the -+ MPQ8646 powers the SoC core rail, so a wrong write can brown out -+ or permanently mis-provision the board. -+ -+ WARNING: Wrong register writes can and likely will physically -+ damage or destroy the chip and/or the board. -+ -+ It shall never be set in a production, shipping, or default configuration. -+ -+ If unsure, say N. -+ - config SENSORS_PIM4328 - tristate "Flex PIM4328 and compatibles" - help -@@ -677,6 +718,25 @@ config SENSORS_STEF48H28 - This driver can also be built as a module. If so, the module will - be called stef48h28. - -+config SENSORS_SQ24860 -+ tristate "Silergy SQ24860" -+ help -+ If you say yes here you get hardware monitoring support for Silergy -+ SQ24860 eFuse. -+ -+ This driver can also be built as a module. If so, the module will -+ be called sq24860. -+ -+config SENSORS_SQ24860_REGULATOR -+ bool "Regulator support for SQ24860" -+ depends on SENSORS_SQ24860 && REGULATOR -+ default SENSORS_SQ24860 -+ help -+ If you say yes here you get regulator support for Silergy SQ24860. -+ The regulator is registered through the PMBus regulator framework and -+ can be used to control the output exposed by the device. -+ This option is only useful if regulator framework support is needed. -+ - config SENSORS_STPDDC60 - tristate "ST STPDDC60" - help -@@ -767,6 +827,15 @@ config SENSORS_UCD9200 - This driver can also be built as a module. If so, the module will - be called ucd9200. - -+config SENSORS_VT7505 -+ tristate "Analog Devices MAX16545, MAX16550 and Volterra VT7505" -+ help -+ If you say yes here you get hardware monitoring support for Analog -+ Devices MAX16545, MAX16550 and Volterra VT7505 PMBus controllers. -+ -+ This driver can also be built as a module. If so, the module will -+ be called vt7505. -+ - config SENSORS_XDP710 - tristate "Infineon XDP710 family" - help -@@ -803,6 +872,16 @@ config SENSORS_XDPE1A2G7B - This driver can also be built as a module. If so, the module will - be called xdpe1a2g7b. - -+config SENSORS_XDPE1A2G7B_REGULATOR -+ bool "Regulator support for XDPE1A2G7B and compatibles" -+ depends on SENSORS_XDPE1A2G7B && REGULATOR -+ help -+ If you say yes here you get regulator support for Infineon -+ XDPE1A2G5B and XDPE1A2G7B multi-phase digital controllers. -+ -+ This enables the controllers to be used as regulator devices, -+ providing voltage control through the regulator framework. -+ - config SENSORS_XDPE122 - tristate "Infineon XDPE122 family" - help -diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile ---- a/drivers/hwmon/pmbus/Makefile -+++ b/drivers/hwmon/pmbus/Makefile -@@ -59,12 +59,15 @@ obj-$(CONFIG_SENSORS_MP5990) += mp5990.o - obj-$(CONFIG_SENSORS_MP9941) += mp9941.o - obj-$(CONFIG_SENSORS_MP9945) += mp9945.o - obj-$(CONFIG_SENSORS_MPQ7932) += mpq7932.o -+obj-$(CONFIG_SENSORS_MPQ82D00) += mpq82d00.o - obj-$(CONFIG_SENSORS_MPQ8785) += mpq8785.o -+obj-$(CONFIG_SENSORS_MPQ8646) += mpq8646.o - obj-$(CONFIG_SENSORS_PLI1209BC) += pli1209bc.o - obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o - obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o - obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o - obj-$(CONFIG_SENSORS_STEF48H28) += stef48h28.o -+obj-$(CONFIG_SENSORS_SQ24860) += sq24860.o - obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o - obj-$(CONFIG_SENSORS_TDA38640) += tda38640.o - obj-$(CONFIG_SENSORS_TPS25990) += tps25990.o -@@ -73,6 +76,7 @@ obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o - obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o - obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o - obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o -+obj-$(CONFIG_SENSORS_VT7505) += vt7505.o - obj-$(CONFIG_SENSORS_XDP710) += xdp710.o - obj-$(CONFIG_SENSORS_XDP720) += xdp720.o - obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o -diff --git a/drivers/hwmon/pmbus/acbel-fsg032.c b/drivers/hwmon/pmbus/acbel-fsg032.c ---- a/drivers/hwmon/pmbus/acbel-fsg032.c -+++ b/drivers/hwmon/pmbus/acbel-fsg032.c -@@ -52,6 +52,7 @@ static const struct i2c_device_id acbel_fsg032_id[] = { - { .name = "acbel_fsg032" }, - { } - }; -+MODULE_DEVICE_TABLE(i2c, acbel_fsg032_id); - - static struct pmbus_driver_info acbel_fsg032_info = { - .pages = 1, -diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c ---- a/drivers/hwmon/pmbus/adm1275.c -+++ b/drivers/hwmon/pmbus/adm1275.c -@@ -19,7 +19,7 @@ - #include "pmbus.h" - - enum chips { adm1075, adm1272, adm1273, adm1275, adm1276, adm1278, adm1281, -- adm1293, adm1294, sq24905c }; -+ adm1293, adm1294, bd12780, bd12790, sq24905c }; - - #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) - #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) -@@ -47,6 +47,8 @@ enum chips { adm1075, adm1272, adm1273, adm1275, adm1276, adm1278, adm1281, - #define ADM1278_VOUT_EN BIT(1) - - #define ADM1278_PMON_DEFCONFIG (ADM1278_VOUT_EN | ADM1278_TEMP1_EN | ADM1278_TSFILT) -+/* The BD127[89]0 data sheets mark TSFILT bit as reserved. */ -+#define BD12780_PMON_DEFCONFIG (ADM1278_VOUT_EN | ADM1278_TEMP1_EN) - - #define ADM1293_IRANGE_25 0 - #define ADM1293_IRANGE_50 BIT(6) -@@ -134,6 +136,30 @@ static const struct coefficients adm1272_coefficients[] = { - - }; - -+/* -+ * BD12790 coefficients derived from preliminary datasheet, Table 1 (p.18) -+ * and the PMBus direct-format relationship X = (Y * 10^(-R) - b) / m. -+ * -+ * Voltage: V[V] = 14.77e-3 * code (60V) / 24.62e-3 * code (100V) -+ * -> m = 6770, R=-2 / m = 4062, R=-2 -+ * Current: code = I[A] * RS * 132802.1 + 2048 (15mV) / * 66401.06 + 2048 (30mV) -+ * -> m = 1328, b = 2048 * 10^(-R) = 20480, R=-1 / m = 664, same b and R -+ * Power: code = k * RS * PIN, k = 35119.94 / 17559.97 / 21071.44 / 10535.72 -+ * -> m = round(k * 10^(-3-R)), R=-2 for 60V/15mV, R=-3 for the other three -+ * Temperature: code = 4.2 * T + 3188 -> m = 42, b = 3188 * 10 = 31880, R=-1 -+ */ -+static const struct coefficients bd12790_coefficients[] = { -+ [0] = { 6770, 0, -2 }, /* voltage, vrange 60V */ -+ [1] = { 4062, 0, -2 }, /* voltage, vrange 100V */ -+ [2] = { 1328, 20480, -1 }, /* current, vsense range 15mV */ -+ [3] = { 664, 20480, -1 }, /* current, vsense range 30mV */ -+ [4] = { 3512, 0, -2 }, /* power, vrange 60V, irange 15mV */ -+ [5] = { 21071, 0, -3 }, /* power, vrange 100V, irange 15mV */ -+ [6] = { 17560, 0, -3 }, /* power, vrange 60V, irange 30mV */ -+ [7] = { 10536, 0, -3 }, /* power, vrange 100V, irange 30mV */ -+ [8] = { 42, 31880, -1 }, /* temperature */ -+}; -+ - static const struct coefficients adm1275_coefficients[] = { - [0] = { 19199, 0, -2 }, /* voltage, vrange set */ - [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ -@@ -487,6 +513,8 @@ static const struct i2c_device_id adm1275_id[] = { - { .name = "adm1281", .driver_data = adm1281 }, - { .name = "adm1293", .driver_data = adm1293 }, - { .name = "adm1294", .driver_data = adm1294 }, -+ { .name = "bd12780", .driver_data = bd12780 }, -+ { .name = "bd12790", .driver_data = bd12790 }, - { .name = "mc09c", .driver_data = sq24905c }, - { } - }; -@@ -494,12 +522,13 @@ MODULE_DEVICE_TABLE(i2c, adm1275_id); - - /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ - static int adm1275_enable_vout_temp(struct adm1275_data *data, -- struct i2c_client *client, int config) -+ struct i2c_client *client, int config, -+ u16 defconfig) - { - int ret; - -- if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) { -- config |= ADM1278_PMON_DEFCONFIG; -+ if ((config & defconfig) != defconfig) { -+ config |= defconfig; - ret = adm1275_write_pmon_config(data, client, config); - if (ret < 0) { - dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n"); -@@ -524,23 +553,19 @@ static int adm1275_probe(struct i2c_client *client) - u32 shunt; - u32 avg; - -- if (!i2c_check_functionality(client->adapter, -- I2C_FUNC_SMBUS_READ_BYTE_DATA -- | I2C_FUNC_SMBUS_BLOCK_DATA)) -- return -ENODEV; -- -- ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); -+ ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_MFR_ID, block_buffer); - if (ret < 0) { - dev_err(&client->dev, "Failed to read Manufacturer ID\n"); - return ret; - } - if ((ret != 3 || strncmp(block_buffer, "ADI", 3)) && -- (ret != 2 || strncmp(block_buffer, "SY", 2))) { -+ (ret != 2 || strncmp(block_buffer, "SY", 2)) && -+ (ret != 4 || strncmp(block_buffer, "ROHM", 4))) { - dev_err(&client->dev, "Unsupported Manufacturer ID\n"); - return -ENODEV; - } - -- ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); -+ ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_MFR_MODEL, block_buffer); - if (ret < 0) { - dev_err(&client->dev, "Failed to read Manufacturer Model\n"); - return ret; -@@ -562,6 +587,7 @@ static int adm1275_probe(struct i2c_client *client) - if (mid->driver_data == adm1272 || mid->driver_data == adm1273 || - mid->driver_data == adm1278 || mid->driver_data == adm1281 || - mid->driver_data == adm1293 || mid->driver_data == adm1294 || -+ mid->driver_data == bd12780 || mid->driver_data == bd12790 || - mid->driver_data == sq24905c) - config_read_fn = i2c_smbus_read_word_data; - else -@@ -642,6 +668,7 @@ static int adm1275_probe(struct i2c_client *client) - data->have_power_sampling = true; - - coefficients = adm1272_coefficients; -+ - vindex = (config & ADM1275_VRANGE) ? 1 : 0; - cindex = (config & ADM1272_IRANGE) ? 3 : 2; - /* pindex depends on the combination of the above */ -@@ -666,7 +693,53 @@ static int adm1275_probe(struct i2c_client *client) - PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | - PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - -- ret = adm1275_enable_vout_temp(data, client, config); -+ ret = adm1275_enable_vout_temp(data, client, config, -+ ADM1278_PMON_DEFCONFIG); -+ if (ret) -+ return ret; -+ -+ if (config & ADM1278_VIN_EN) -+ info->func[0] |= PMBUS_HAVE_VIN; -+ break; -+ -+ /* -+ * The BD12790 is almost identical to the adm1272. Only the defconfig -+ * and coefficients have minor differences. -+ */ -+ case bd12790: -+ data->have_vout = true; -+ data->have_pin_max = true; -+ data->have_temp_max = true; -+ data->have_power_sampling = true; -+ -+ coefficients = bd12790_coefficients; -+ -+ vindex = (config & ADM1275_VRANGE) ? 1 : 0; -+ cindex = (config & ADM1272_IRANGE) ? 3 : 2; -+ /* pindex depends on the combination of the above */ -+ switch (config & (ADM1275_VRANGE | ADM1272_IRANGE)) { -+ case 0: -+ default: -+ pindex = 4; -+ break; -+ case ADM1275_VRANGE: -+ pindex = 5; -+ break; -+ case ADM1272_IRANGE: -+ pindex = 6; -+ break; -+ case ADM1275_VRANGE | ADM1272_IRANGE: -+ pindex = 7; -+ break; -+ } -+ tindex = 8; -+ -+ info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | -+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; -+ -+ ret = adm1275_enable_vout_temp(data, client, config, -+ BD12780_PMON_DEFCONFIG); - if (ret) - return ret; - -@@ -728,13 +801,45 @@ static int adm1275_probe(struct i2c_client *client) - PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | - PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - -- ret = adm1275_enable_vout_temp(data, client, config); -+ ret = adm1275_enable_vout_temp(data, client, config, -+ ADM1278_PMON_DEFCONFIG); - if (ret) - return ret; - - if (config & ADM1278_VIN_EN) - info->func[0] |= PMBUS_HAVE_VIN; - break; -+ -+ /* -+ * The BD12780 is almost functionally identical with the adm1278 above. -+ * Only differences visible to the driver are lack of TSFILT bits and -+ * different identification register contents. -+ */ -+ case bd12780: -+ data->have_vout = true; -+ data->have_pin_max = true; -+ data->have_temp_max = true; -+ data->have_power_sampling = true; -+ -+ coefficients = adm1278_coefficients; -+ vindex = 0; -+ cindex = 1; -+ pindex = 2; -+ tindex = 3; -+ -+ info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | -+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; -+ -+ ret = adm1275_enable_vout_temp(data, client, config, -+ BD12780_PMON_DEFCONFIG); -+ if (ret) -+ return ret; -+ -+ if (config & ADM1278_VIN_EN) -+ info->func[0] |= PMBUS_HAVE_VIN; -+ -+ break; - case adm1293: - case adm1294: - data->have_iout_min = true; -@@ -870,9 +975,27 @@ static int adm1275_probe(struct i2c_client *client) - return pmbus_do_probe(client, info); - } - -+static const struct of_device_id adm1275_of_match[] = { -+ { .compatible = "adi,adm1075", }, -+ { .compatible = "adi,adm1272", }, -+ { .compatible = "adi,adm1273", }, -+ { .compatible = "adi,adm1275", }, -+ { .compatible = "adi,adm1276", }, -+ { .compatible = "adi,adm1278", }, -+ { .compatible = "adi,adm1281", }, -+ { .compatible = "adi,adm1293", }, -+ { .compatible = "adi,adm1294", }, -+ { .compatible = "rohm,bd12780", }, -+ { .compatible = "rohm,bd12790", }, -+ { .compatible = "silergy,mc09c", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, adm1275_of_match); -+ - static struct i2c_driver adm1275_driver = { - .driver = { - .name = "adm1275", -+ .of_match_table = adm1275_of_match, - }, - .probe = adm1275_probe, - .id_table = adm1275_id, -diff --git a/drivers/hwmon/pmbus/ir36021.c b/drivers/hwmon/pmbus/ir36021.c ---- a/drivers/hwmon/pmbus/ir36021.c -+++ b/drivers/hwmon/pmbus/ir36021.c -@@ -31,21 +31,13 @@ static int ir36021_probe(struct i2c_client *client) - u8 buf[I2C_SMBUS_BLOCK_MAX]; - int ret; - -- if (!i2c_check_functionality(client->adapter, -- I2C_FUNC_SMBUS_READ_BYTE_DATA -- | I2C_FUNC_SMBUS_READ_WORD_DATA -- | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) -- return -ENODEV; -- -- ret = i2c_smbus_read_i2c_block_data(client, PMBUS_MFR_MODEL, 2, buf); -- if (ret < 0) { -- dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n"); -- return ret; -- } -- if (ret != 2 || buf[0] != 0x01 || buf[1] != 0x2d) { -- dev_err(&client->dev, "MFR_MODEL unrecognised\n"); -- return -ENODEV; -- } -+ ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_MFR_MODEL, buf); -+ if (ret < 0) -+ return dev_err_probe(&client->dev, ret, -+ "Failed to read PMBUS_MFR_MODEL\n"); -+ if (ret != 1 || buf[0] != 0x2d) -+ return dev_err_probe(&client->dev, -ENODEV, -+ "MFR_MODEL unrecognised\n"); - - return pmbus_do_probe(client, &ir36021_info); - } -diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c ---- a/drivers/hwmon/pmbus/lm25066.c -+++ b/drivers/hwmon/pmbus/lm25066.c -@@ -35,6 +35,7 @@ enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i }; - #define LM25066_READ_AVG_PIN 0xdf - - #define LM25066_DEV_SETUP_CL BIT(4) /* Current limit */ -+#define LM25066_DEV_SETUP_CL_CFG BIT(2) /* Current limit configuration */ - - #define LM25066_SAMPLES_FOR_AVG_MAX 4096 - -@@ -485,6 +486,42 @@ static int lm25066_probe(struct i2c_client *client) - - data->id = (enum chips)(unsigned long)i2c_get_match_data(client); - -+ if (data->id != lm25056) { -+ int config_new = config; -+ const char *cl_setting; -+ int ret; -+ -+ if (!of_property_read_string(client->dev.of_node, -+ "ti,current-range", &cl_setting)) { -+ config_new |= LM25066_DEV_SETUP_CL_CFG; -+ if (strcmp(cl_setting, "high") == 0) { -+ if (data->id == lm25066) -+ config_new |= LM25066_DEV_SETUP_CL; -+ else -+ config_new &= ~LM25066_DEV_SETUP_CL; -+ } else if (strcmp(cl_setting, "low") == 0) { -+ if (data->id == lm25066) -+ config_new &= ~LM25066_DEV_SETUP_CL; -+ else -+ config_new |= LM25066_DEV_SETUP_CL; -+ } else { -+ dev_err(&client->dev, -+ "invalid current-range setting: %s\n", -+ cl_setting); -+ return -EINVAL; -+ } -+ } -+ -+ if (config_new != config) { -+ ret = i2c_smbus_write_byte_data(client, -+ LM25066_DEVICE_SETUP, -+ config_new); -+ if (ret < 0) -+ return ret; -+ config = config_new; -+ } -+ } -+ - info = &data->info; - - info->pages = 1; -diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c ---- a/drivers/hwmon/pmbus/ltc2978.c -+++ b/drivers/hwmon/pmbus/ltc2978.c -@@ -611,17 +611,13 @@ static int ltc2978_get_id(struct i2c_client *client) - u8 buf[I2C_SMBUS_BLOCK_MAX]; - int ret; - -- if (!i2c_check_functionality(client->adapter, -- I2C_FUNC_SMBUS_READ_BLOCK_DATA)) -- return -ENODEV; -- -- ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); -+ ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_MFR_ID, buf); - if (ret < 0) - return ret; - if (ret < 3 || (strncmp(buf, "LTC", 3) && strncmp(buf, "ADI", 3))) - return -ENODEV; - -- ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); -+ ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_MFR_MODEL, buf); - if (ret < 0) - return ret; - for (id = <c2978_id[0]; strlen(id->name); id++) { -@@ -637,16 +633,17 @@ static int ltc2978_get_id(struct i2c_client *client) - u8 buf[I2C_SMBUS_BLOCK_MAX]; - int ret; - -- ret = i2c_smbus_read_i2c_block_data(client, PMBUS_IC_DEVICE_ID, -- sizeof(buf), buf); -+ ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_IC_DEVICE_ID, -+ buf); - if (ret < 0) - return ret; - -- if (!strncmp(buf + 1, "LT7170", 6) || -- !strncmp(buf + 1, "LT7170-1", 8)) -+ if (ret < 6) -+ return -ENODEV; -+ -+ if (!strncmp(buf, "LT7170", 6)) - return lt7170; -- if (!strncmp(buf + 1, "LT7171", 6) || -- !strncmp(buf + 1, "LT7171-1", 8)) -+ if (!strncmp(buf, "LT7171", 6)) - return lt7171; - - return -ENODEV; -diff --git a/drivers/hwmon/pmbus/max20830.c b/drivers/hwmon/pmbus/max20830.c ---- a/drivers/hwmon/pmbus/max20830.c -+++ b/drivers/hwmon/pmbus/max20830.c -@@ -7,12 +7,69 @@ - - #include - #include -+#include - #include - #include - #include "pmbus.h" - - #define MAX20830_IC_DEVICE_ID_LENGTH 9 - -+struct max20830_data { -+ struct pmbus_driver_info info; -+ u32 vout_rfb1; -+ u32 vout_rfb2; -+}; -+ -+static const char * const supported_chip_ids[] = { -+ "MAX20830", -+ "MAX20830C", -+ "MAX20840C", -+}; -+ -+/* -+ * MAX20830 only supports READ_VOUT for VOUT monitoring. -+ * -+ * Limit registers (VOUT_OV_WARN_LIMIT, VOUT_OV_FAULT_LIMIT, etc.) are not -+ * supported by this driver and return -ENODATA. This means sysfs attributes -+ * like in1_max, in1_crit, etc. will not be available. Only in1_input (the -+ * scaled output voltage) is supported. -+ * -+ * MAX20830 uses an external resistor divider for voltage sensing: -+ * - VOUT_COMMAND and VOUT_MAX set the reference voltage at the feedback pin -+ * - READ_VOUT reports the feedback voltage, which needs to be scaled for actual -+ * output voltage -+ * -+ * Scaling formula: vout_actual = vout_fb × (1 + RFB1 / RFB2) -+ * -+ * If regulator support is added in the future, some adjustments are needed to -+ * ensure correct feedback voltages are set. -+ */ -+static int max20830_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client); -+ const struct max20830_data *data = container_of(info, struct max20830_data, info); -+ int ret; -+ u64 temp; -+ -+ switch (reg) { -+ case PMBUS_READ_VOUT: -+ ret = pmbus_read_word_data(client, page, phase, reg); -+ if (ret < 0) -+ return ret; -+ -+ /* Apply voltage divider scaling if resistors are non-zero */ -+ if (data->vout_rfb1 && data->vout_rfb2) { -+ temp = (u64)data->vout_rfb1 + (u64)data->vout_rfb2; -+ temp = DIV_ROUND_CLOSEST_ULL((u64)ret * temp, data->vout_rfb2); -+ ret = clamp_val(temp, 0, 0xFFFF); -+ } -+ return ret; -+ default: -+ return -ENODATA; -+ } -+} -+ - static struct pmbus_driver_info max20830_info = { - .pages = 1, - .format[PSC_VOLTAGE_IN] = linear, -@@ -23,61 +80,53 @@ static struct pmbus_driver_info max20830_info = { - PMBUS_HAVE_TEMP | - PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | - PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, -+ .read_word_data = max20830_read_word_data, -+ .have_pmbus_revision = true, -+ .pmbus_revision = PMBUS_REV_13, - }; - - static int max20830_probe(struct i2c_client *client) - { - u8 buf[I2C_SMBUS_BLOCK_MAX + 1] = {}; -- int ret; -+ struct max20830_data *data; -+ int i, ret; - -- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA) && -- !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) -- return -ENODEV; -+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; - -- /* -- * Use i2c_smbus_read_block_data() if supported, otherwise fall back -- * to i2c_smbus_read_i2c_block_data() to support I2C controllers -- * which do not support SMBus block reads. -- */ -- if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { -- /* Reads 9 Data bytes from MAX20830 */ -- ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); -- if (ret < 0) -- return dev_err_probe(&client->dev, ret, -- "Failed to read IC_DEVICE_ID\n"); -- } else { -- /* Reads 1 length byte + 9 Data bytes from MAX20830 */ -- ret = i2c_smbus_read_i2c_block_data(client, PMBUS_IC_DEVICE_ID, -- MAX20830_IC_DEVICE_ID_LENGTH + 1, -- buf); -- if (ret < 0) -- return dev_err_probe(&client->dev, ret, -- "Failed to read IC_DEVICE_ID\n"); -- /* -- * Moves data forward, removing the length byte, this is to -- * match the format of i2c_smbus_read_block_data(). -- * Also adjust return value to reflect length byte removal. -- */ -- memmove(buf, buf + 1, MAX20830_IC_DEVICE_ID_LENGTH); -- ret = ret - 1; -- } -+ data->info = max20830_info; - -- /* -- * MAX20830 IC_DEVICE_ID sends string data "MAX20830\0". -- * Return value should at least be 9 bytes of data. -- */ -+ /* Read optional voltage divider resistor values */ -+ device_property_read_u32(&client->dev, "adi,vout-rfb1-ohms", &data->vout_rfb1); -+ device_property_read_u32(&client->dev, "adi,vout-rfb2-ohms", &data->vout_rfb2); -+ -+ ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_IC_DEVICE_ID, buf); -+ if (ret < 0) -+ return dev_err_probe(&client->dev, ret, -+ "Failed to read IC_DEVICE_ID\n"); -+ -+ /* Verify we read the expected number of bytes */ - if (ret < MAX20830_IC_DEVICE_ID_LENGTH) - return dev_err_probe(&client->dev, -ENODEV, -- "IC_DEVICE_ID too short: expected at least 9 bytes, got %d\n", -- ret); -+ "IC_DEVICE_ID too short: expected %d bytes, got %d\n", -+ MAX20830_IC_DEVICE_ID_LENGTH, ret); - -- /* 9 bytes of data, buf[0]-buf[7] = "MAX20830", buf[8] = '\0' */ -- buf[MAX20830_IC_DEVICE_ID_LENGTH - 1] = '\0'; -- if (strncmp(buf, "MAX20830", MAX20830_IC_DEVICE_ID_LENGTH - 1)) -+ /* Null-terminate the string */ -+ buf[ret] = '\0'; -+ -+ /* Verify the device ID matches what we expect */ -+ for (i = 0; i < ARRAY_SIZE(supported_chip_ids); i++) { -+ if (!strcmp(buf, supported_chip_ids[i])) -+ break; -+ } -+ -+ /* No match found - unsupported device */ -+ if (i == ARRAY_SIZE(supported_chip_ids)) - return dev_err_probe(&client->dev, -ENODEV, -- "Unsupported device: '%s'\n", buf); -+ "Unsupported device: '%*pE'\n", ret, buf); - -- return pmbus_do_probe(client, &max20830_info); -+ return pmbus_do_probe(client, &data->info); - } - - static const struct i2c_device_id max20830_id[] = { -diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c ---- a/drivers/hwmon/pmbus/max34440.c -+++ b/drivers/hwmon/pmbus/max34440.c -@@ -23,6 +23,7 @@ enum chips { - max34441, - max34446, - max34451, -+ max34452, - max34460, - max34461, - }; -@@ -59,6 +60,7 @@ enum chips { - #define MAX34440_IOUT_OC_FAULT_LIMIT 0x4A - - #define MAX34451ETNA6_MFR_REV 0x0012 -+#define MAX34451ETNA8_MFR_REV 0x0014 - - #define MAX34451_MFR_CHANNEL_CONFIG 0xe4 - #define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK 0x3f -@@ -105,16 +107,21 @@ static int max34440_read_word_data(struct i2c_client *client, int page, - case PMBUS_UT_FAULT_LIMIT: - case PMBUS_MFR_MAX_TEMP_1: - /* -- * MAX34451/ADPM family do not support VIN/IIN limit registers, -- * manufacturer-specific min/max registers, or undercurrent/ -- * undertemperature fault limits. Accessing these triggers CML -- * error and asserts ALERT. -+ * MAX34451/MAX34452/ADPM family do not support VIN/IIN limit -+ * registers, manufacturer-specific min/max registers, or -+ * undercurrent/undertemperature fault limits. Accessing these -+ * triggers CML error and asserts ALERT. - */ -- if (data->id == max34451 || data->id == adpm12160 || -- data->id == adpm12200 || data->id == adpm12250) -+ if (data->id == max34451 || data->id == max34452 || -+ data->id == adpm12160 || data->id == adpm12200 || -+ data->id == adpm12250) - return -ENXIO; - ret = -ENODATA; - break; -+ case PMBUS_VOUT_OV_WARN_LIMIT: -+ if (data->id == max34452) -+ return -ENXIO; -+ return -ENODATA; - case PMBUS_VIRT_READ_VOUT_MIN: - ret = pmbus_read_word_data(client, page, phase, - MAX34440_MFR_VOUT_MIN); -@@ -125,8 +132,8 @@ static int max34440_read_word_data(struct i2c_client *client, int page, - break; - case PMBUS_VIRT_READ_IOUT_AVG: - if (data->id != max34446 && data->id != max34451 && -- data->id != adpm12160 && data->id != adpm12200 && -- data->id != adpm12250) -+ data->id != max34452 && data->id != adpm12160 && -+ data->id != adpm12200 && data->id != adpm12250) - return -ENXIO; - ret = pmbus_read_word_data(client, page, phase, - MAX34446_MFR_IOUT_AVG); -@@ -191,6 +198,10 @@ static int max34440_write_word_data(struct i2c_client *client, int page, - ret = pmbus_write_word_data(client, page, data->iout_oc_warn_limit, - word); - break; -+ case PMBUS_VOUT_OV_WARN_LIMIT: -+ if (data->id == max34452) -+ return -ENXIO; -+ return -ENODATA; - case PMBUS_VIRT_RESET_POUT_HISTORY: - ret = pmbus_write_word_data(client, page, - MAX34446_MFR_POUT_PEAK, 0); -@@ -211,8 +222,8 @@ static int max34440_write_word_data(struct i2c_client *client, int page, - ret = pmbus_write_word_data(client, page, - MAX34440_MFR_IOUT_PEAK, 0); - if (!ret && (data->id == max34446 || data->id == max34451 || -- data->id == adpm12160 || data->id == adpm12200 || -- data->id == adpm12250)) -+ data->id == max34452 || data->id == adpm12160 || -+ data->id == adpm12200 || data->id == adpm12250)) - ret = pmbus_write_word_data(client, page, - MAX34446_MFR_IOUT_AVG, 0); - -@@ -280,12 +291,13 @@ static int max34451_read_byte_data(struct i2c_client *client, int page, int reg) - case PMBUS_STATUS_BYTE: - case PMBUS_STATUS_OTHER: - /* -- * MAX34451/ADPM family do not support STATUS_BYTE or -+ * MAX34451/MAX34452/ADPM family do not support STATUS_BYTE or - * STATUS_OTHER registers. Accessing them triggers CML - * error and asserts ALERT. - */ -- if (data->id == max34451 || data->id == adpm12160 || -- data->id == adpm12200 || data->id == adpm12250) -+ if (data->id == max34451 || data->id == max34452 || -+ data->id == adpm12160 || data->id == adpm12200 || -+ data->id == adpm12250) - return -ENXIO; - return -ENODATA; - default: -@@ -303,12 +315,13 @@ static int max34451_write_byte_data(struct i2c_client *client, int page, - case PMBUS_STATUS_BYTE: - case PMBUS_STATUS_OTHER: - /* -- * MAX34451/ADPM family do not support STATUS_BYTE or -+ * MAX34451/MAX34452/ADPM family do not support STATUS_BYTE or - * STATUS_OTHER registers. Writing to them triggers CML - * error and asserts ALERT. - */ -- if (data->id == max34451 || data->id == adpm12160 || -- data->id == adpm12200 || data->id == adpm12250) -+ if (data->id == max34451 || data->id == max34452 || -+ data->id == adpm12160 || data->id == adpm12200 || -+ data->id == adpm12250) - return -ENXIO; - return -ENODATA; - default: -@@ -339,16 +352,28 @@ static int max34451_set_supported_funcs(struct i2c_client *client, - if (rv < 0) - return rv; - -- if (rv >= MAX34451ETNA6_MFR_REV) { -+ if (data->id == max34451 && rv >= MAX34451ETNA6_MFR_REV) { - max34451_na6 = true; - data->info.format[PSC_VOLTAGE_IN] = direct; - data->info.format[PSC_CURRENT_IN] = direct; -- data->info.m[PSC_VOLTAGE_IN] = 1; -+ - data->info.b[PSC_VOLTAGE_IN] = 0; -- data->info.R[PSC_VOLTAGE_IN] = 3; -- data->info.m[PSC_CURRENT_IN] = 1; - data->info.b[PSC_CURRENT_IN] = 0; -- data->info.R[PSC_CURRENT_IN] = 2; -+ if (rv >= MAX34451ETNA8_MFR_REV) { -+ data->info.m[PSC_VOLTAGE_IN] = 125; -+ data->info.R[PSC_VOLTAGE_IN] = 0; -+ data->info.m[PSC_VOLTAGE_OUT] = 125; -+ data->info.R[PSC_VOLTAGE_OUT] = 0; -+ data->info.m[PSC_CURRENT_IN] = 250; -+ data->info.R[PSC_CURRENT_IN] = -1; -+ data->info.m[PSC_CURRENT_OUT] = 250; -+ data->info.R[PSC_CURRENT_OUT] = -1; -+ } else { -+ data->info.m[PSC_VOLTAGE_IN] = 1; -+ data->info.R[PSC_VOLTAGE_IN] = 3; -+ data->info.m[PSC_CURRENT_IN] = 1; -+ data->info.R[PSC_CURRENT_IN] = 2; -+ } - data->iout_oc_fault_limit = PMBUS_IOUT_OC_FAULT_LIMIT; - data->iout_oc_warn_limit = PMBUS_IOUT_OC_WARN_LIMIT; - } -@@ -665,6 +690,32 @@ static struct pmbus_driver_info max34440_info[] = { - .write_word_data = max34440_write_word_data, - .page_change_delay = MAX34440_PAGE_CHANGE_DELAY, - }, -+ [max34452] = { -+ .pages = 21, -+ .format[PSC_VOLTAGE_OUT] = direct, -+ .format[PSC_TEMPERATURE] = direct, -+ .format[PSC_CURRENT_OUT] = direct, -+ .m[PSC_VOLTAGE_OUT] = 1, -+ .b[PSC_VOLTAGE_OUT] = 0, -+ .R[PSC_VOLTAGE_OUT] = 3, -+ .m[PSC_CURRENT_OUT] = 1, -+ .b[PSC_CURRENT_OUT] = 0, -+ .R[PSC_CURRENT_OUT] = 2, -+ .m[PSC_TEMPERATURE] = 1, -+ .b[PSC_TEMPERATURE] = 0, -+ .R[PSC_TEMPERATURE] = 2, -+ /* func 0-15 is set dynamically before probing */ -+ .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, -+ .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, -+ .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, -+ .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, -+ .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, -+ .read_byte_data = max34451_read_byte_data, -+ .read_word_data = max34440_read_word_data, -+ .write_byte_data = max34451_write_byte_data, -+ .write_word_data = max34440_write_word_data, -+ .page_change_delay = MAX34440_PAGE_CHANGE_DELAY, -+ }, - [max34460] = { - .pages = 18, - .format[PSC_VOLTAGE_OUT] = direct, -@@ -748,7 +799,7 @@ static int max34440_probe(struct i2c_client *client) - data->iout_oc_fault_limit = MAX34440_IOUT_OC_FAULT_LIMIT; - data->iout_oc_warn_limit = MAX34440_IOUT_OC_WARN_LIMIT; - -- if (data->id == max34451) { -+ if (data->id == max34451 || data->id == max34452) { - rv = max34451_set_supported_funcs(client, data); - if (rv) - return rv; -@@ -769,6 +820,7 @@ static const struct i2c_device_id max34440_id[] = { - { .name = "max34441", .driver_data = max34441 }, - { .name = "max34446", .driver_data = max34446 }, - { .name = "max34451", .driver_data = max34451 }, -+ { .name = "max34452", .driver_data = max34452 }, - { .name = "max34460", .driver_data = max34460 }, - { .name = "max34461", .driver_data = max34461 }, - { } -diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c ---- a/drivers/hwmon/pmbus/mp2975.c -+++ b/drivers/hwmon/pmbus/mp2975.c -@@ -176,7 +176,6 @@ mp2975_vid2direct(int vrf, int val) - static u16 mp2975_data2reg_linear11(s64 val) - { - s16 exponent = 0, mantissa; -- bool negative = false; - - /* simple case */ - if (val == 0) -@@ -196,10 +195,6 @@ static u16 mp2975_data2reg_linear11(s64 val) - /* Convert mantissa from milli-units to units */ - mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); - -- /* restore sign */ -- if (negative) -- mantissa = -mantissa; -- - /* Convert to 5 bit exponent, 11 bit mantissa */ - return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); - } -diff --git a/drivers/hwmon/pmbus/mpq82d00.c b/drivers/hwmon/pmbus/mpq82d00.c -new file mode 100644 ---- /dev/null -+++ b/drivers/hwmon/pmbus/mpq82d00.c -@@ -0,0 +1,249 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Hardware monitoring driver for MPS Synchronous Step-Down Converter(MPQ82D00) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pmbus.h" -+ -+#define MPQ82D00_VOUT_DIV 64 -+ -+#define MPQ82D00_PAGE_NUM 1 -+ -+#define MPQ82D00_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \ -+ PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP | \ -+ PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | \ -+ PMBUS_HAVE_STATUS_VOUT | \ -+ PMBUS_HAVE_STATUS_IOUT | \ -+ PMBUS_HAVE_STATUS_TEMP | \ -+ PMBUS_HAVE_STATUS_INPUT) -+ -+struct mpq82d00_data { -+ struct pmbus_driver_info info; -+ int vout_scale; -+}; -+ -+#define to_mpq82d00_data(x) container_of(x, struct mpq82d00_data, info) -+ -+static u16 mpq82d00_linear_exp_transfer(u16 word, u16 expect_exponent) -+{ -+ s16 exponent, mantissa, target_exponent; -+ -+ exponent = ((s16)word) >> 11; -+ mantissa = ((s16)((word & 0x7ff) << 5)) >> 5; -+ target_exponent = (s16)((expect_exponent & 0x1f) << 11) >> 11; -+ -+ /* -+ * The MPQ82D00 does not support negtive limit value, if a negtive -+ * limit value is written, the limit value will become to 0. And -+ * the maximum positive limit value is limitted to 0x3FF. -+ */ -+ if (mantissa < 0) { -+ mantissa = 0; -+ } else { -+ if (exponent > target_exponent) { -+ mantissa = (1023 >> (exponent - target_exponent)) >= mantissa ? -+ mantissa << (exponent - target_exponent) : -+ 0x3FF; -+ } else { -+ mantissa = clamp_val(mantissa >> (target_exponent - exponent), -+ 0, 0x3FF); -+ } -+ } -+ -+ return mantissa | ((expect_exponent << 11) & 0xf800); -+} -+ -+static int mpq82d00_read_byte_data(struct i2c_client *client, int page, int reg) -+{ -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_VOUT_MODE: -+ /* -+ * The MPQ82D00 does not follow standard PMBus protocol completely, -+ * and the calculation of vout in this driver is based on direct -+ * format. As a result, the format of vout is enforced to direct. -+ */ -+ ret = PB_VOUT_MODE_DIRECT; -+ break; -+ default: -+ /* -+ * These registers are not explicitly handled by the driver, -+ * as a result, return -ENODATA directly. -+ */ -+ ret = -ENODATA; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int mpq82d00_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client); -+ struct mpq82d00_data *data = to_mpq82d00_data(info); -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_STATUS_WORD: -+ case PMBUS_READ_VIN: -+ case PMBUS_READ_IOUT: -+ case PMBUS_READ_POUT: -+ case PMBUS_READ_PIN: -+ case PMBUS_READ_TEMPERATURE_1: -+ case PMBUS_IOUT_OC_FAULT_LIMIT: -+ case PMBUS_OT_FAULT_LIMIT: -+ /* -+ * These registers are not explicitly handled by the driver, -+ * as a result, return -ENODATA directly. -+ */ -+ ret = -ENODATA; -+ break; -+ case PMBUS_READ_VOUT: -+ ret = pmbus_read_word_data(client, page, phase, reg); -+ if (ret < 0) -+ return ret; -+ -+ ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * data->vout_scale, -+ MPQ82D00_VOUT_DIV); -+ break; -+ default: -+ /* -+ * The MPQ82D00 do not support other telemetry and limit -+ * value reading, so, return -EINVAL directly. -+ */ -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int mpq82d00_write_word_data(struct i2c_client *client, int page, int reg, -+ u16 word) -+{ -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_OT_FAULT_LIMIT: -+ /* -+ * The PMBUS_OT_FAULT_LIMIT of MPQ82D00 is linear11 format, -+ * and the exponent is a constant value(5'b00000), so the -+ * exponent of word parameter should be converted to 5'b00000. -+ */ -+ ret = pmbus_write_word_data(client, page, reg, -+ mpq82d00_linear_exp_transfer(word, 0x00)); -+ break; -+ case PMBUS_IOUT_OC_FAULT_LIMIT: -+ /* -+ * The PMBUS_IOUT_OC_FAULT_LIMIT of MPQ82D00 is linear11 format, -+ * and the exponent is a constant value(5'b11100), so the -+ * exponent of word parameter should be converted to 5'b11100. -+ */ -+ ret = pmbus_write_word_data(client, page, reg, -+ mpq82d00_linear_exp_transfer(word, 0x1C)); -+ break; -+ default: -+ /* -+ * The MPQ82D00 do not support other limit value configuration, -+ * so, return -EINVAL directly. -+ */ -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int mpq82d00_identify(struct i2c_client *client, struct pmbus_driver_info *info) -+{ -+ struct mpq82d00_data *data = to_mpq82d00_data(info); -+ int ret; -+ -+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); -+ if (ret < 0) -+ return ret; -+ -+ ret = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE); -+ if (ret < 0) -+ return ret; -+ -+ /* -+ * The MPQ82D00 supports three vout mode. If PMBUS_VOUT_MODE -+ * bit5 is 1, the vout scale is 5mv/LSB.If PMBUS_VOUT_MODE bit5 -+ * is 0, it is linear mode, the vout scale is 1.953125mv/LSB. -+ */ -+ if (FIELD_GET(GENMASK(5, 5), ret)) -+ data->vout_scale = 320; -+ else -+ data->vout_scale = 125; -+ -+ return 0; -+} -+ -+static struct pmbus_driver_info mpq82d00_info = { -+ .pages = MPQ82D00_PAGE_NUM, -+ .format[PSC_VOLTAGE_IN] = linear, -+ .format[PSC_CURRENT_OUT] = linear, -+ .format[PSC_TEMPERATURE] = linear, -+ .format[PSC_VOLTAGE_OUT] = direct, -+ .format[PSC_POWER] = linear, -+ -+ .m[PSC_VOLTAGE_OUT] = 1, -+ .R[PSC_VOLTAGE_OUT] = 3, -+ .b[PSC_VOLTAGE_OUT] = 0, -+ -+ .func[0] = MPQ82D00_RAIL1_FUNC, -+ .read_word_data = mpq82d00_read_word_data, -+ .read_byte_data = mpq82d00_read_byte_data, -+ .write_word_data = mpq82d00_write_word_data, -+ .identify = mpq82d00_identify, -+}; -+ -+static int mpq82d00_probe(struct i2c_client *client) -+{ -+ struct mpq82d00_data *data; -+ -+ data = devm_kzalloc(&client->dev, sizeof(struct mpq82d00_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ memcpy(&data->info, &mpq82d00_info, sizeof(mpq82d00_info)); -+ -+ return pmbus_do_probe(client, &data->info); -+} -+ -+static const struct i2c_device_id mpq82d00_id[] = { -+ {.name = "mpq82d00"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, mpq82d00_id); -+ -+static const struct of_device_id __maybe_unused mpq82d00_of_match[] = { -+ {.compatible = "mps,mpq82d00"}, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, mpq82d00_of_match); -+ -+static struct i2c_driver mpq82d00_driver = { -+ .driver = { -+ .name = "mpq82d00", -+ .of_match_table = mpq82d00_of_match, -+ }, -+ .probe = mpq82d00_probe, -+ .id_table = mpq82d00_id, -+}; -+ -+module_i2c_driver(mpq82d00_driver); -+ -+MODULE_AUTHOR("Wensheng Wang -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pmbus.h" -+ -+/* Default cadence for the in-driver alarm-poll fallback (ms) */ -+#define MPQ8646_ALARM_POLL_MS_DEFAULT 1000 -+ -+/* MPS vendor-extended command codes (NOT in PMBus 1.3 Part II) */ -+#define MPS_CLEAR_LAST_FAULT 0x08 -+#define MPS_MFR_CFG_EXT 0xF5 -+#define MPS_MFR_CFG_EXT_CLR_LAST_EN BIT(6) -+#define MPS_PROTECTION_LAST 0xFB -+ -+/* -+ * PMBus 1.3 NVM commit / revert commands. MPS equivalent of -+ * STORE_ALL (15h) and RESTORE_ALL (16h). -+ */ -+#define PMBUS_STORE_USER_ALL 0x15 -+#define PMBUS_RESTORE_USER_ALL 0x16 -+ -+/* PMBus 1.3 timing / UVLO command codes */ -+#define PMBUS_VIN_ON 0x35 -+#define PMBUS_VIN_OFF 0x36 -+#define PMBUS_TON_DELAY 0x60 -+#define PMBUS_TON_RISE 0x61 -+#define PMBUS_TOFF_DELAY 0x64 -+#define PMBUS_TOFF_FALL 0x65 -+ -+/* MPS vendor-extended observability / identity registers */ -+#define MPS_MFR_CONFIG_ID 0xC0 -+#define MPS_MFR_CONFIG_CODE_REV 0xC1 -+#define MPS_MFR_PRODUCT_REV_USER 0xC2 -+#define MPS_MFR_SILICON_REV 0xC3 -+#define MPS_MFR_RETRY_TIMES 0xF4 -+#define MPS_MFR_VBOOT_CFG 0xFC -+ -+/* -+ * MPS_MFR_PMBUS_LOCK (EEh): 16-bit WORD whose low two bits gate -+ * subsequent PMBus writes -+ * bits[1:0] = 00 -- unlocked (POR default) -+ * 01 -- lock all writes EXCEPT VOUT_COMMAND (0x21) -+ * so the operator can still DVFS the rail -+ * 11 -- lock all writes -+ * A negative-going PG edge resets these bits to 00, the lock -+ * is operationally reversible without a full chip POR. -+ */ -+#define MPS_MFR_PMBUS_LOCK 0xEE -+ -+/* -+ * Retry parameters for the MFR_CFG_EXT gate-close write after -+ * CLEAR_LAST_FAULT. Bench-observed NVM-busy NACK window on this -+ * silicon is about 1 ms; the datasheet does not have information. -+ */ -+#define MPQ8646_NVM_RETRY_MAX 5 -+#define MPQ8646_NVM_RETRY_DELAY_US_MIN 2000 -+#define MPQ8646_NVM_RETRY_DELAY_US_MAX 4000 -+ -+#define MPQ8646_DEBUG(client, fmt, ...) \ -+ dev_dbg(&(client)->dev, fmt, ##__VA_ARGS__) -+ -+/* -+ * Maximum legal value for VOUT_SCALE_LOOP (0x29) on the MPQ8646 silicon -+ * The chip uses an 11-bit VOUT feedback-divider scale register. -+ */ -+#define MPQ8646_VOUT_SCALE_LOOP_MAX GENMASK(10, 0) -+ -+/* Forward declaration */ -+struct mpq8646_dbg_reg_ctx; -+ -+/* Per-instance state */ -+struct mpq8646_priv { -+ struct pmbus_driver_info info; /* must be first, container_of target */ -+ struct i2c_client *client; -+ -+ /* Serialises CLEAR_LAST_FAULT sequences and PROTECTION_LAST reads */ -+ struct mutex mps_lock; -+ -+ /* Set alarm_poll_interval_ms = 0 to disable. */ -+ struct delayed_work alarm_poll_work; -+ u32 alarm_poll_interval_ms; -+ -+#ifdef CONFIG_DEBUG_FS -+ /* the only debugfs file that can re-arm the poll worker */ -+ struct dentry *dbg_poll; -+ struct mpq8646_dbg_reg_ctx *dbg_reg_ctx; -+#endif -+}; -+ -+static inline struct mpq8646_priv *mpq8646_priv_from_client(struct i2c_client *client) -+{ -+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client); -+ -+ return container_of(info, struct mpq8646_priv, info); -+} -+ -+/* -+ * VID-mode m/b/R coefficients, same values as the mpq8785 driver for -+ * the MPS VID encoding. Per the PMBus Direct formula used by -+ * pmbus_core, X = (Y * 10^-R - b) / m, so m=64 / b=0 / R=1 yields -+ * 1.5625 mV per LSB. -+ */ -+#define MPQ8646_VID_M 64 -+#define MPQ8646_VID_B 0 -+#define MPQ8646_VID_R 1 -+ -+static int mpq8646_identify(struct i2c_client *client, -+ struct pmbus_driver_info *info) -+{ -+ int vout_mode; -+ -+ vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); -+ if (vout_mode < 0) -+ return vout_mode; -+ -+ switch (vout_mode & PB_VOUT_MODE_MODE_MASK) { -+ case PB_VOUT_MODE_LINEAR: -+ info->format[PSC_VOLTAGE_OUT] = linear; -+ break; -+ case PB_VOUT_MODE_VID: -+ case PB_VOUT_MODE_DIRECT: -+ info->format[PSC_VOLTAGE_OUT] = direct; -+ info->m[PSC_VOLTAGE_OUT] = MPQ8646_VID_M; -+ info->b[PSC_VOLTAGE_OUT] = MPQ8646_VID_B; -+ info->R[PSC_VOLTAGE_OUT] = MPQ8646_VID_R; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ return 0; -+}; -+ -+static int mpq8646_read_byte_data(struct i2c_client *client, int page, int reg) -+{ -+ int ret; -+ -+ MPQ8646_DEBUG(client, "read_byte_data page=%d reg=0x%02x\n", page, reg); -+ -+ switch (reg) { -+ case PMBUS_VOUT_MODE: -+ ret = pmbus_read_byte_data(client, page, reg); -+ MPQ8646_DEBUG(client, " VOUT_MODE raw=0x%02x ret=%d\n", ret, ret); -+ if (ret < 0) -+ return ret; -+ -+ if ((ret & PB_VOUT_MODE_MODE_MASK) == PB_VOUT_MODE_VID) -+ return PB_VOUT_MODE_DIRECT; -+ -+ return ret; -+ case PMBUS_STATUS_BYTE: -+ case PMBUS_STATUS_CML: -+ case PMBUS_STATUS_OTHER: -+ case PMBUS_STATUS_MFR_SPECIFIC: -+ case PMBUS_STATUS_FAN_12: -+ case PMBUS_STATUS_FAN_34: -+ return -ENXIO; -+ case PMBUS_MFR_LOCATION: -+ case PMBUS_MFR_DATE: -+ case PMBUS_MFR_SERIAL: -+ case PMBUS_IC_DEVICE_ID: -+ case PMBUS_IC_DEVICE_REV: -+ MPQ8646_DEBUG(client, " unsupported mfr-info reg 0x%02x -> ENXIO\n", reg); -+ return -ENXIO; -+ default: -+ return -ENODATA; -+ } -+} -+ -+/* -+ * Reference: ltc2978.c::ltc2978_write_word_data which uses the -+ * same virtual-register channel for its real chip-side peak reset. -+ */ -+static int mpq8646_write_word_data(struct i2c_client *client, int page, -+ int reg, u16 word) -+{ -+ struct mpq8646_priv *priv = mpq8646_priv_from_client(client); -+ int rc; -+ -+ switch (reg) { -+ case PMBUS_VIRT_RESET_VIN_HISTORY: -+ case PMBUS_VIRT_RESET_VOUT_HISTORY: -+ case PMBUS_VIRT_RESET_IOUT_HISTORY: -+ case PMBUS_VIRT_RESET_TEMP_HISTORY: -+ MPQ8646_DEBUG(client, "reset_history virt reg=0x%04x -> CLEAR_FAULTS\n", -+ reg); -+ rc = i2c_smbus_write_byte(priv->client, PMBUS_CLEAR_FAULTS); -+ if (rc < 0) -+ MPQ8646_DEBUG(client, " CLEAR_FAULTS rc=%d\n", rc); -+ return rc < 0 ? rc : 0; -+ default: -+ return -ENODATA; /* let pmbus_core do the direct write */ -+ } -+} -+ -+static int mpq8646_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ int rc; -+ -+ MPQ8646_DEBUG(client, "read_word_data page=%d phase=%d reg=0x%02x\n", -+ page, phase, reg); -+ -+ switch (reg) { -+ case PMBUS_READ_VIN: -+ case PMBUS_READ_VOUT: -+ case PMBUS_READ_IOUT: -+ case PMBUS_READ_TEMPERATURE_1: -+ case PMBUS_STATUS_WORD: -+ case PMBUS_VOUT_OV_FAULT_LIMIT: -+ case PMBUS_VOUT_OV_WARN_LIMIT: -+ case PMBUS_VOUT_UV_WARN_LIMIT: -+ case PMBUS_VOUT_UV_FAULT_LIMIT: -+ case PMBUS_IOUT_OC_FAULT_LIMIT: -+ case PMBUS_IOUT_OC_WARN_LIMIT: -+ case PMBUS_OT_FAULT_LIMIT: -+ case PMBUS_OT_WARN_LIMIT: -+ case PMBUS_VIN_OV_FAULT_LIMIT: -+ case PMBUS_VIN_OV_WARN_LIMIT: -+ case PMBUS_VIN_UV_WARN_LIMIT: -+ case PMBUS_VIN_UV_FAULT_LIMIT: -+ case PMBUS_MFR_VIN_MAX: -+ case PMBUS_MFR_VOUT_MAX: -+ case PMBUS_MFR_IOUT_MAX: -+ case PMBUS_MFR_MAX_TEMP_1: -+ break; -+ case PMBUS_VIRT_RESET_VIN_HISTORY: -+ case PMBUS_VIRT_RESET_VOUT_HISTORY: -+ case PMBUS_VIRT_RESET_IOUT_HISTORY: -+ case PMBUS_VIRT_RESET_TEMP_HISTORY: -+ return 0; -+ default: -+ return -ENODATA; -+ } -+ -+ rc = i2c_smbus_read_word_data(client, reg); -+ -+ MPQ8646_DEBUG(client, " reg=0x%02x rc=%d\n", reg, rc); -+ return rc; -+} -+ -+static struct pmbus_driver_info mpq8646_info = { -+ .pages = 1, -+ .format[PSC_VOLTAGE_IN] = direct, -+ .format[PSC_CURRENT_OUT] = direct, -+ .format[PSC_TEMPERATURE] = direct, -+ .m[PSC_VOLTAGE_IN] = 4, -+ .b[PSC_VOLTAGE_IN] = 0, -+ .R[PSC_VOLTAGE_IN] = 1, -+ .m[PSC_CURRENT_OUT] = 16, -+ .b[PSC_CURRENT_OUT] = 0, -+ .R[PSC_CURRENT_OUT] = 0, -+ .m[PSC_TEMPERATURE] = 1, -+ .b[PSC_TEMPERATURE] = 0, -+ .R[PSC_TEMPERATURE] = 0, -+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | -+ PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP | -+ PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP, -+}; -+ -+#if IS_ENABLED(CONFIG_REGULATOR) -+static const struct regulator_desc mpq8646_reg_desc[] = { -+ PMBUS_REGULATOR("vout", 0), -+}; -+#endif /* CONFIG_REGULATOR */ -+ -+#if IS_ENABLED(CONFIG_NVMEM) -+/* -+ * Expose using -+ * /sys/bus/nvmem/devices//nvmem -+ * -+ * Layout (16 bytes): -+ * offset 0..1 PROTECTION_LAST (0xFB) word, LE -- NVM -+ * offset 2..3 MFR_RETRY_TIMES (0xF4) word, LE -- NVM -+ * offset 4..5 MFR_CONFIG_ID (0xC0) word, LE -- NVM -+ * offset 6..7 MFR_VBOOT_CFG (0xFC) word, LE -- NVM -+ * offset 8 MFR_SILICON_REV (0xC3) byte -- NVM -+ * offset 9..15 reserved (zero-fill, leaves room for additions) -+ */ -+#define MPQ8646_NVMEM_SIZE 16 -+ -+struct mpq8646_nvmem_entry { -+ unsigned int off; -+ u8 reg; -+ bool is_word; -+}; -+ -+static const struct mpq8646_nvmem_entry mpq8646_nvmem_map[] = { -+ { 0, MPS_PROTECTION_LAST, true }, -+ { 2, MPS_MFR_RETRY_TIMES, true }, -+ { 4, MPS_MFR_CONFIG_ID, true }, -+ { 6, MPS_MFR_VBOOT_CFG, true }, -+ { 8, MPS_MFR_SILICON_REV, false }, -+}; -+ -+static int mpq8646_nvmem_read(void *data, unsigned int offset, void *val, -+ size_t bytes) -+{ -+ struct mpq8646_priv *priv = data; -+ u8 *out = val; -+ size_t i; -+ -+ if (offset >= MPQ8646_NVMEM_SIZE) -+ return -EINVAL; -+ if (offset + bytes > MPQ8646_NVMEM_SIZE) -+ bytes = MPQ8646_NVMEM_SIZE - offset; -+ -+ memset(out, 0, bytes); -+ -+ guard(mutex)(&priv->mps_lock); -+ for (i = 0; i < ARRAY_SIZE(mpq8646_nvmem_map); i++) { -+ const struct mpq8646_nvmem_entry *e = &mpq8646_nvmem_map[i]; -+ unsigned int e_start = e->off; -+ unsigned int e_end = e_start + (e->is_word ? 2 : 1); -+ u8 raw[2]; -+ int rc; -+ unsigned int j; -+ -+ if (e_end <= offset || e_start >= offset + bytes) -+ continue; /* outside requested slice */ -+ -+ if (e->is_word) -+ rc = i2c_smbus_read_word_data(priv->client, e->reg); -+ else -+ rc = i2c_smbus_read_byte_data(priv->client, e->reg); -+ if (rc < 0) -+ continue; /* leave the zero-fill in place */ -+ -+ raw[0] = rc & 0xff; -+ raw[1] = (rc >> 8) & 0xff; -+ -+ for (j = 0; j < e_end - e_start; j++) { -+ unsigned int abs = e_start + j; -+ -+ if (abs >= offset && abs < offset + bytes) -+ out[abs - offset] = raw[j]; -+ } -+ } -+ return 0; -+} -+#endif /* CONFIG_NVMEM */ -+ -+static const struct i2c_device_id mpq8646_id[] = { -+ { .name = "mpq8646" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(i2c, mpq8646_id); -+ -+static const struct of_device_id __maybe_unused mpq8646_of_match[] = { -+ { .compatible = "mps,mpq8646" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, mpq8646_of_match); -+ -+static struct pmbus_platform_data mpq8646_no_pec_pdata = { -+ .flags = PMBUS_NO_CAPABILITY, -+}; -+ -+#ifdef CONFIG_DEBUG_FS -+/* -+ * Read-only decode cases in the client's pmbus debugfs directory: -+ * the MPS-specific STATUS_WORD and PROTECTION_LAST bit decode plus the -+ * identity/timing registers. -+ */ -+ -+struct mpq_status_bit { -+ u16 mask; -+ const char *name; -+}; -+ -+static const struct mpq_status_bit mpq8646_status_word_bits[] = { -+ { PB_STATUS_VOUT, "VOUT" }, -+ { PB_STATUS_IOUT_POUT, "IOUT_POUT" }, -+ { PB_STATUS_INPUT, "INPUT" }, -+ { PB_STATUS_WORD_MFR, "NVM_SUMMARY" }, -+ { PB_STATUS_POWER_GOOD_N, "POWER_GOOD#" }, -+ { PB_STATUS_FANS, "FANS" }, -+ { PB_STATUS_OTHER, "OTHER" }, -+ { PB_STATUS_UNKNOWN, "WATCH_DOG" }, -+ { PB_STATUS_BUSY, "BUSY" }, -+ { PB_STATUS_OFF, "OFF" }, -+ { PB_STATUS_VOUT_OV, "VOUT_OV_FAULT" }, -+ { PB_STATUS_IOUT_OC, "IOUT_OC_FAULT" }, -+ { PB_STATUS_VIN_UV, "VIN_UV_FAULT" }, -+ { PB_STATUS_TEMPERATURE, "TEMP" }, -+ { PB_STATUS_CML, "CML" }, -+ { PB_STATUS_NONE_ABOVE, "DRMOS_FAULT" }, -+ { /* sentinel */ } -+}; -+ -+/* PROTECTION_LAST (0xFB) bit names, it survives chip POR */ -+static const struct mpq_status_bit mpq8646_protection_last_bits[] = { -+ { BIT(15), "INIT_FAULT" }, -+ { BIT(14), "NVM_CRC_ERROR" }, -+ { BIT(13), "NVM_FAULT" }, -+ { BIT(12), "OC_PHASE_FAULT" }, -+ { BIT(11), "OTP_SELF_FAULT" }, -+ { BIT(9), "SWITCH_PRD_FAULT" }, -+ { BIT(8), "VIN_OV_FAULT" }, -+ { BIT(7), "VOUT_OV_FAULT" }, -+ { BIT(6), "VOUT_UV_FAULT" }, -+ { BIT(5), "OC_TOT_FAULT" }, -+ { BIT(4), "VIN_UVLO_FAULT" }, -+ { BIT(3), "DRMOS_OTP" }, -+ { /* sentinel */ } -+}; -+ -+static void mpq8646_print_bits(struct seq_file *s, u16 v, -+ const struct mpq_status_bit *tab) -+{ -+ const struct mpq_status_bit *t; -+ bool first = true; -+ -+ seq_printf(s, "0x%04x", v); -+ if (!v) { -+ seq_puts(s, " [clean]\n"); -+ return; -+ } -+ seq_puts(s, " ["); -+ for (t = tab; t->mask; t++) { -+ if (v & t->mask) { -+ if (!first) -+ seq_putc(s, ' '); -+ seq_puts(s, t->name); -+ first = false; -+ } -+ } -+ seq_puts(s, "]\n"); -+} -+ -+static int mpq8646_dbg_status_decoded_show(struct seq_file *s, void *unused) -+{ -+ struct mpq8646_priv *priv = s->private; -+ int rc; -+ -+ scoped_guard(pmbus_lock, priv->client) -+ rc = i2c_smbus_read_word_data(priv->client, PMBUS_STATUS_WORD); -+ if (rc < 0) { -+ seq_printf(s, "ERROR: STATUS_WORD read failed (%d)\n", rc); -+ return 0; -+ } -+ seq_puts(s, "STATUS_WORD: "); -+ mpq8646_print_bits(s, (u16)rc, mpq8646_status_word_bits); -+ seq_puts(s, "(MPS extensions: bit12=NVM_SUMMARY, bit8=WATCH_DOG, bit0=DRMOS_FAULT)\n"); -+ return 0; -+} -+DEFINE_SHOW_ATTRIBUTE(mpq8646_dbg_status_decoded); -+ -+static int mpq8646_dbg_protection_last_show(struct seq_file *s, void *unused) -+{ -+ struct mpq8646_priv *priv = s->private; -+ int rc; -+ -+ guard(pmbus_lock)(priv->client); -+ scoped_guard(mutex, &priv->mps_lock) -+ rc = i2c_smbus_read_word_data(priv->client, MPS_PROTECTION_LAST); -+ -+ if (rc < 0) { -+ seq_printf(s, "ERROR: PROTECTION_LAST read failed (%d)\n", rc); -+ return 0; -+ } -+ seq_puts(s, "PROTECTION_LAST: "); -+ mpq8646_print_bits(s, (u16)rc, mpq8646_protection_last_bits); -+ seq_puts(s, "(NVM-backed, survives chip POR)\n"); -+ return 0; -+} -+DEFINE_SHOW_ATTRIBUTE(mpq8646_dbg_protection_last); -+ -+struct mpq8646_dbg_reg { -+ u8 reg; -+ bool is_word; -+ const char *name; -+}; -+ -+static const struct mpq8646_dbg_reg mpq8646_dbg_regs[] = { -+ /* MPS vendor extensions (read-only identity / observability) */ -+ { MPS_MFR_CONFIG_ID, true, "mfr_config_id" }, -+ { MPS_MFR_CONFIG_CODE_REV, true, "mfr_config_code_rev" }, -+ { MPS_MFR_SILICON_REV, false, "mfr_silicon_rev" }, -+ { MPS_MFR_RETRY_TIMES, true, "mfr_retry_times" }, -+ { MPS_MFR_VBOOT_CFG, true, "mfr_vboot_cfg" }, -+ /* PMBus 1.3 standard timing / UVLO (read-only introspection) */ -+ { PMBUS_VIN_ON, true, "vin_on" }, -+ { PMBUS_VIN_OFF, true, "vin_off" }, -+ { PMBUS_TON_DELAY, true, "ton_delay" }, -+ { PMBUS_TON_RISE, true, "ton_rise" }, -+ { PMBUS_TOFF_DELAY, true, "toff_delay" }, -+ { PMBUS_TOFF_FALL, true, "toff_fall" }, -+}; -+ -+struct mpq8646_dbg_reg_ctx { -+ struct mpq8646_priv *priv; -+ const struct mpq8646_dbg_reg *desc; -+}; -+ -+static int mpq8646_dbg_reg_show(struct seq_file *s, void *unused) -+{ -+ struct mpq8646_dbg_reg_ctx *ctx = s->private; -+ int rc; -+ -+ guard(pmbus_lock)(ctx->priv->client); -+ if (ctx->desc->is_word) -+ rc = i2c_smbus_read_word_data(ctx->priv->client, -+ ctx->desc->reg); -+ else -+ rc = i2c_smbus_read_byte_data(ctx->priv->client, -+ ctx->desc->reg); -+ -+ if (rc < 0) { -+ seq_printf(s, "ERROR: reg 0x%02x (%s) read failed (%d)\n", -+ ctx->desc->reg, ctx->desc->name, rc); -+ return 0; -+ } -+ seq_printf(s, "0x%0*x\n", ctx->desc->is_word ? 4 : 2, rc); -+ return 0; -+} -+DEFINE_SHOW_ATTRIBUTE(mpq8646_dbg_reg); -+ -+#ifdef CONFIG_SENSORS_MPQ8646_DEBUG_UNSAFE -+/* -+ * Write/provisioning data, disabled by default: NVM commit and -+ * revert, the CLEAR_LAST_FAULT sequences and a small set of named -+ * writable registers. -+ */ -+ -+static void mpq8646_unsafe_banner(struct mpq8646_priv *priv) -+{ -+ dev_warn(&priv->client->dev, -+ "**********************************************************\n" -+ "** WARNING WARNING WARNING WARNING WARNING WARNING **\n" -+ "** **\n" -+ "** The MPQ8646 provisioning debugfs writes are enabled. **\n" -+ "** Wrong register writes can and likely will physically **\n" -+ "** damage or destroy the chip and/or the board. **\n" -+ "** **\n" -+ "** If you see this message and you are not debugging **\n" -+ "** the kernel, report this immediately to your system **\n" -+ "** administrator! **\n" -+ "** **\n" -+ "** WARNING WARNING WARNING WARNING WARNING WARNING **\n" -+ "**********************************************************\n"); -+} -+ -+static int mpq8646_dbg_clear_protection_last(void *data, u64 val) -+{ -+ struct mpq8646_priv *priv = data; -+ int rc; -+ -+ if (!val) -+ return 0; -+ -+ guard(pmbus_lock)(priv->client); -+ scoped_guard(mutex, &priv->mps_lock) -+ rc = i2c_smbus_write_byte(priv->client, MPS_CLEAR_LAST_FAULT); -+ if (rc < 0) -+ dev_warn(&priv->client->dev, -+ "clear_protection_last: CLEAR_LAST_FAULT write failed (%d)\n", -+ rc); -+ return rc; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(mpq8646_dbg_clear_protection_last_fops, -+ NULL, mpq8646_dbg_clear_protection_last, "%llu\n"); -+ -+static int mpq8646_dbg_clear_protection_last_force(void *data, u64 val) -+{ -+ struct mpq8646_priv *priv = data; -+ int rc, ret; -+ int wp_orig, cfg_orig; -+ -+ if (!val) -+ return 0; -+ -+ guard(pmbus_lock)(priv->client); -+ guard(mutex)(&priv->mps_lock); -+ -+ wp_orig = i2c_smbus_read_byte_data(priv->client, PMBUS_WRITE_PROTECT); -+ if (wp_orig < 0) { -+ dev_warn(&priv->client->dev, -+ "clear_protection_last_force: WRITE_PROTECT read failed (%d), aborting\n", -+ wp_orig); -+ return wp_orig; -+ } -+ cfg_orig = i2c_smbus_read_word_data(priv->client, MPS_MFR_CFG_EXT); -+ if (cfg_orig < 0) { -+ dev_warn(&priv->client->dev, -+ "clear_protection_last_force: MFR_CFG_EXT read failed (%d), aborting\n", -+ cfg_orig); -+ return cfg_orig; -+ } -+ -+ if (wp_orig != 0) { -+ rc = i2c_smbus_write_byte_data(priv->client, -+ PMBUS_WRITE_PROTECT, 0); -+ if (rc < 0) { -+ dev_warn(&priv->client->dev, -+ "clear_protection_last_force: WP clear failed (%d), aborting\n", -+ rc); -+ return rc; -+ } -+ } -+ -+ ret = i2c_smbus_write_word_data(priv->client, MPS_MFR_CFG_EXT, -+ (u16)cfg_orig | MPS_MFR_CFG_EXT_CLR_LAST_EN); -+ if (ret < 0) { -+ dev_warn(&priv->client->dev, -+ "clear_protection_last_force: gate open failed (%d)\n", -+ ret); -+ } else { -+ ret = i2c_smbus_write_byte(priv->client, MPS_CLEAR_LAST_FAULT); -+ if (ret < 0) -+ dev_warn(&priv->client->dev, -+ "clear_protection_last_force: CLEAR_LAST_FAULT failed (%d) even with gate open\n", -+ ret); -+ -+ for (int attempt = 0; attempt < MPQ8646_NVM_RETRY_MAX; attempt++) { -+ rc = i2c_smbus_write_word_data(priv->client, -+ MPS_MFR_CFG_EXT, -+ (u16)cfg_orig); -+ if (rc >= 0) -+ break; -+ usleep_range(MPQ8646_NVM_RETRY_DELAY_US_MIN, -+ MPQ8646_NVM_RETRY_DELAY_US_MAX); -+ } -+ if (rc < 0) { -+ dev_warn(&priv->client->dev, -+ "clear_protection_last_force: MFR_CFG_EXT restore failed after retries (%d): gate may stay open until POR\n", -+ rc); -+ if (ret == 0) -+ ret = rc; -+ } -+ } -+ -+ if (wp_orig != 0) { -+ rc = i2c_smbus_write_byte_data(priv->client, -+ PMBUS_WRITE_PROTECT, -+ (u8)wp_orig); -+ if (rc < 0) { -+ dev_warn(&priv->client->dev, -+ "clear_protection_last_force: WP restore failed (%d)\n", -+ rc); -+ if (ret == 0) -+ ret = rc; -+ } -+ } -+ return ret; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(mpq8646_dbg_clear_protection_last_force_fops, -+ NULL, mpq8646_dbg_clear_protection_last_force, "%llu\n"); -+ -+static int mpq8646_dbg_store_all(void *data, u64 val) -+{ -+ struct mpq8646_priv *priv = data; -+ int rc; -+ -+ if (!val) -+ return 0; -+ -+ guard(pmbus_lock)(priv->client); -+ scoped_guard(mutex, &priv->mps_lock) -+ rc = i2c_smbus_write_byte(priv->client, PMBUS_STORE_USER_ALL); -+ if (rc < 0) -+ dev_warn(&priv->client->dev, -+ "store_all: STORE_USER_ALL (0x15) write failed (%d)\n", -+ rc); -+ return rc; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(mpq8646_dbg_store_all_fops, -+ NULL, mpq8646_dbg_store_all, "%llu\n"); -+ -+static int mpq8646_dbg_restore_all(void *data, u64 val) -+{ -+ struct mpq8646_priv *priv = data; -+ int rc; -+ -+ if (!val) -+ return 0; -+ -+ guard(pmbus_lock)(priv->client); -+ scoped_guard(mutex, &priv->mps_lock) -+ rc = i2c_smbus_write_byte(priv->client, PMBUS_RESTORE_USER_ALL); -+ if (rc < 0) -+ dev_warn(&priv->client->dev, -+ "restore_all: RESTORE_USER_ALL (0x16) write failed (%d)\n", -+ rc); -+ return rc; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(mpq8646_dbg_restore_all_fops, -+ NULL, mpq8646_dbg_restore_all, "%llu\n"); -+ -+static const struct mpq8646_dbg_reg mpq8646_dbg_regs_unsafe[] = { -+ /* PMBus 1.3 control / margin */ -+ { PMBUS_ON_OFF_CONFIG, false, "on_off_config" }, -+ { PMBUS_VOUT_MARGIN_HIGH, true, "vout_margin_high" }, -+ { PMBUS_VOUT_MARGIN_LOW, true, "vout_margin_low" }, -+ /* MPS PMBus-level write-protect */ -+ { MPS_MFR_PMBUS_LOCK, true, "mfr_pmbus_lock" }, -+ /* MPS user-writable product revision */ -+ { MPS_MFR_PRODUCT_REV_USER, true, "mfr_product_rev_user" }, -+}; -+ -+static int mpq8646_dbg_reg_get(void *data, u64 *val) -+{ -+ struct mpq8646_dbg_reg_ctx *ctx = data; -+ int rc; -+ -+ guard(pmbus_lock)(ctx->priv->client); -+ if (ctx->desc->is_word) -+ rc = i2c_smbus_read_word_data(ctx->priv->client, -+ ctx->desc->reg); -+ else -+ rc = i2c_smbus_read_byte_data(ctx->priv->client, -+ ctx->desc->reg); -+ if (rc < 0) -+ return rc; -+ *val = rc; -+ return 0; -+} -+ -+static int mpq8646_dbg_reg_set(void *data, u64 val) -+{ -+ struct mpq8646_dbg_reg_ctx *ctx = data; -+ int rc; -+ -+ guard(pmbus_lock)(ctx->priv->client); -+ if (ctx->desc->is_word) -+ rc = i2c_smbus_write_word_data(ctx->priv->client, -+ ctx->desc->reg, (u16)val); -+ else -+ rc = i2c_smbus_write_byte_data(ctx->priv->client, -+ ctx->desc->reg, (u8)val); -+ return rc < 0 ? rc : 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(mpq8646_dbg_reg_rw_fops, -+ mpq8646_dbg_reg_get, mpq8646_dbg_reg_set, "0x%llx\n"); -+ -+static void mpq8646_debugfs_register_unsafe(struct mpq8646_priv *priv, -+ struct dentry *root) -+{ -+ struct mpq8646_dbg_reg_ctx *ctx; -+ size_t i; -+ -+ mpq8646_unsafe_banner(priv); -+ -+ debugfs_create_file_unsafe("clear_protection_last", 0200, root, priv, -+ &mpq8646_dbg_clear_protection_last_fops); -+ debugfs_create_file_unsafe("clear_protection_last_force", 0200, root, -+ priv, -+ &mpq8646_dbg_clear_protection_last_force_fops); -+ debugfs_create_file_unsafe("store_all", 0200, root, priv, -+ &mpq8646_dbg_store_all_fops); -+ debugfs_create_file_unsafe("restore_all", 0200, root, priv, -+ &mpq8646_dbg_restore_all_fops); -+ -+ ctx = devm_kcalloc(&priv->client->dev, -+ ARRAY_SIZE(mpq8646_dbg_regs_unsafe), -+ sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) -+ return; -+ for (i = 0; i < ARRAY_SIZE(mpq8646_dbg_regs_unsafe); i++) { -+ ctx[i].priv = priv; -+ ctx[i].desc = &mpq8646_dbg_regs_unsafe[i]; -+ debugfs_create_file_unsafe(mpq8646_dbg_regs_unsafe[i].name, -+ 0600, root, &ctx[i], -+ &mpq8646_dbg_reg_rw_fops); -+ } -+} -+#else -+static inline void mpq8646_debugfs_register_unsafe(struct mpq8646_priv *priv, -+ struct dentry *root) {} -+#endif /* CONFIG_SENSORS_MPQ8646_DEBUG_UNSAFE */ -+ -+static int mpq8646_dbg_poll_interval_get(void *data, u64 *val) -+{ -+ struct mpq8646_priv *priv = data; -+ -+ *val = priv->alarm_poll_interval_ms; -+ return 0; -+} -+ -+static int mpq8646_dbg_poll_interval_set(void *data, u64 val) -+{ -+ struct mpq8646_priv *priv = data; -+ bool was_off = !priv->alarm_poll_interval_ms; -+ -+ priv->alarm_poll_interval_ms = (u32)val; -+ -+ if (val && was_off && !priv->client->irq) -+ schedule_delayed_work(&priv->alarm_poll_work, -+ msecs_to_jiffies((u32)val)); -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(mpq8646_dbg_poll_interval_fops, -+ mpq8646_dbg_poll_interval_get, -+ mpq8646_dbg_poll_interval_set, "%llu\n"); -+ -+static void mpq8646_debugfs_register(struct mpq8646_priv *priv) -+{ -+ struct dentry *root; -+ size_t i; -+ -+ root = pmbus_get_debugfs_dir(priv->client); -+ if (!root) -+ return; -+ -+ /* MPS extensions: status decode + NVM-backed PROTECTION_LAST */ -+ debugfs_create_file("status_decoded", 0400, root, priv, -+ &mpq8646_dbg_status_decoded_fops); -+ debugfs_create_file("protection_last", 0400, root, priv, -+ &mpq8646_dbg_protection_last_fops); -+ priv->dbg_poll = -+ debugfs_create_file_unsafe("alarm_poll_interval_ms", 0600, -+ root, priv, -+ &mpq8646_dbg_poll_interval_fops); -+ -+ priv->dbg_reg_ctx = devm_kcalloc(&priv->client->dev, -+ ARRAY_SIZE(mpq8646_dbg_regs), -+ sizeof(*priv->dbg_reg_ctx), -+ GFP_KERNEL); -+ if (!priv->dbg_reg_ctx) -+ return; -+ for (i = 0; i < ARRAY_SIZE(mpq8646_dbg_regs); i++) { -+ priv->dbg_reg_ctx[i].priv = priv; -+ priv->dbg_reg_ctx[i].desc = &mpq8646_dbg_regs[i]; -+ debugfs_create_file(mpq8646_dbg_regs[i].name, 0400, -+ root, &priv->dbg_reg_ctx[i], -+ &mpq8646_dbg_reg_fops); -+ } -+ -+ mpq8646_debugfs_register_unsafe(priv, root); -+} -+ -+static void mpq8646_debugfs_unregister(struct mpq8646_priv *priv) -+{ -+ debugfs_remove(priv->dbg_poll); -+} -+#else -+static inline void mpq8646_debugfs_register(struct mpq8646_priv *priv) {} -+static inline void mpq8646_debugfs_unregister(struct mpq8646_priv *priv) {} -+#endif /* CONFIG_DEBUG_FS */ -+ -+static void mpq8646_alarm_poll_work(struct work_struct *work) -+{ -+ struct mpq8646_priv *priv = container_of(to_delayed_work(work), -+ struct mpq8646_priv, -+ alarm_poll_work); -+ -+ if (priv->client->irq) -+ return; /* SMBALERT# wired; polling not needed */ -+ -+ if (!priv->alarm_poll_interval_ms) -+ return; /* polling disabled; don't re-arm */ -+ -+ pmbus_check_and_notify_faults(priv->client); -+ -+ schedule_delayed_work(&priv->alarm_poll_work, -+ msecs_to_jiffies(priv->alarm_poll_interval_ms)); -+} -+ -+static int mpq8646_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct pmbus_driver_info *info; -+ struct mpq8646_priv *priv; -+ u32 voltage_scale; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ priv->client = client; -+ mutex_init(&priv->mps_lock); -+ memcpy(&priv->info, &mpq8646_info, sizeof(priv->info)); -+ info = &priv->info; -+ -+ info->identify = mpq8646_identify; -+ info->read_byte_data = mpq8646_read_byte_data; -+ info->read_word_data = mpq8646_read_word_data; -+ info->write_word_data = mpq8646_write_word_data; -+ dev->platform_data = &mpq8646_no_pec_pdata; -+ -+#if IS_ENABLED(CONFIG_REGULATOR) -+ info->reg_desc = mpq8646_reg_desc; -+ info->num_regulators = ARRAY_SIZE(mpq8646_reg_desc); -+#endif -+ -+ INIT_DELAYED_WORK(&priv->alarm_poll_work, mpq8646_alarm_poll_work); -+ priv->alarm_poll_interval_ms = MPQ8646_ALARM_POLL_MS_DEFAULT; -+ -+ if (!device_property_read_u32(dev, "mps,vout-fb-divider-ratio-permille", -+ &voltage_scale)) { -+ if (voltage_scale > MPQ8646_VOUT_SCALE_LOOP_MAX) -+ return -EINVAL; -+ -+ ret = i2c_smbus_write_word_data(client, PMBUS_VOUT_SCALE_LOOP, -+ voltage_scale); -+ if (ret) -+ return ret; -+ } -+ -+ ret = pmbus_do_probe(client, info); -+ if (ret) -+ return ret; -+ -+ mpq8646_debugfs_register(priv); -+ -+ if (!client->irq) -+ schedule_delayed_work(&priv->alarm_poll_work, -+ msecs_to_jiffies(priv->alarm_poll_interval_ms)); -+ -+#if IS_ENABLED(CONFIG_NVMEM) -+ { -+ struct nvmem_config cfg = { -+ .dev = &client->dev, -+ .name = dev_name(&client->dev), -+ .owner = THIS_MODULE, -+ .read_only = true, -+ .root_only = true, -+ .word_size = 1, -+ .stride = 1, -+ .size = MPQ8646_NVMEM_SIZE, -+ .reg_read = mpq8646_nvmem_read, -+ .priv = priv, -+ }; -+ struct nvmem_device *nv = devm_nvmem_register(&client->dev, &cfg); -+ -+ if (IS_ERR(nv)) -+ dev_warn(&client->dev, -+ "nvmem snapshot register failed (%pe)\n", -+ nv); -+ } -+#endif -+ return 0; -+}; -+ -+static void mpq8646_remove(struct i2c_client *client) -+{ -+ struct mpq8646_priv *priv = mpq8646_priv_from_client(client); -+ -+ mpq8646_debugfs_unregister(priv); -+ cancel_delayed_work_sync(&priv->alarm_poll_work); -+} -+ -+static struct i2c_driver mpq8646_driver = { -+ .driver = { -+ .name = "mpq8646", -+ .of_match_table = of_match_ptr(mpq8646_of_match), -+ }, -+ .probe = mpq8646_probe, -+ .remove = mpq8646_remove, -+ .id_table = mpq8646_id, -+}; -+ -+module_i2c_driver(mpq8646_driver); -+ -+MODULE_AUTHOR("Vincent Jardin "); -+MODULE_DESCRIPTION("PMBus driver for MPS MPQ8646 (extended observability)"); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("PMBUS"); -diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h ---- a/drivers/hwmon/pmbus/pmbus.h -+++ b/drivers/hwmon/pmbus/pmbus.h -@@ -421,10 +421,12 @@ enum pmbus_data_format { linear = 0, ieee754, direct, vid }; - enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv, nvidia195mv }; - - /* PMBus revision identifiers */ --#define PMBUS_REV_10 0x00 /* PMBus revision 1.0 */ --#define PMBUS_REV_11 0x11 /* PMBus revision 1.1 */ --#define PMBUS_REV_12 0x22 /* PMBus revision 1.2 */ --#define PMBUS_REV_13 0x33 /* PMBus revision 1.3 */ -+#define PMBUS_REV_10 0x00 /* PMBus revision 1.0 */ -+#define PMBUS_REV_11 0x11 /* PMBus revision 1.1 */ -+#define PMBUS_REV_12 0x22 /* PMBus revision 1.2 */ -+#define PMBUS_REV_13 0x33 /* PMBus revision 1.3 */ -+#define PMBUS_REV_131 0x44 /* PMBus revision 1.3.1 */ -+#define PMBUS_REV_14 0x55 /* PMBus revision 1.4 */ - - /* Operation type flags for pmbus_update_ts */ - #define PMBUS_OP_WRITE BIT(0) -@@ -489,6 +491,16 @@ struct pmbus_driver_info { - int access_delay; /* in microseconds */ - int write_delay; /* in microseconds */ - int page_change_delay; /* in microseconds */ -+ -+ /* -+ * Some chips do not support the PMBUS_REVISION command. -+ * Drivers for such chips can report the supported PMBus revision here. -+ * -+ * Drivers must set have_pmbus_revision to true and provide the -+ * supported PMBus version in pmbus_revision. -+ */ -+ bool have_pmbus_revision; /* true if pmbus_revision is valid */ -+ u8 pmbus_revision; /* PMBus revision */ - }; - - /* Regulator ops */ -@@ -550,6 +562,7 @@ void pmbus_set_update(struct i2c_client *client, u8 reg, bool update); - void pmbus_wait(struct i2c_client *client); - void pmbus_update_ts(struct i2c_client *client, int op); - int pmbus_set_page(struct i2c_client *client, int page, int phase); -+int pmbus_read_smbus_i2c_block_data(struct i2c_client *client, u8 reg, char *data_buf); - int pmbus_read_word_data(struct i2c_client *client, int page, int phase, - u8 reg); - int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, -@@ -561,6 +574,7 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, - int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, - u8 mask, u8 value); - void pmbus_clear_faults(struct i2c_client *client); -+void pmbus_check_and_notify_faults(struct i2c_client *client); - bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); - bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); - int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); -diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c ---- a/drivers/hwmon/pmbus/pmbus_core.c -+++ b/drivers/hwmon/pmbus/pmbus_core.c -@@ -96,7 +96,8 @@ struct pmbus_data { - - u32 flags; /* from platform data */ - -- u8 revision; /* The PMBus revision the device is compliant with */ -+ bool have_pmbus_revision; -+ u8 revision; /* The PMBus revision the device is compliant with */ - - int exponent[PMBUS_PAGES]; - /* linear mode: exponent for output voltages */ -@@ -181,7 +182,12 @@ EXPORT_SYMBOL_NS_GPL(pmbus_set_update, "PMBUS"); - void pmbus_wait(struct i2c_client *client) - { - struct pmbus_data *data = i2c_get_clientdata(client); -- s64 delay = ktime_us_delta(data->next_access_backoff, ktime_get()); -+ s64 delay; -+ -+ if (!data) -+ return; -+ -+ delay = ktime_us_delta(data->next_access_backoff, ktime_get()); - - if (delay > 0) - fsleep(delay); -@@ -192,8 +198,14 @@ EXPORT_SYMBOL_NS_GPL(pmbus_wait, "PMBUS"); - void pmbus_update_ts(struct i2c_client *client, int op) - { - struct pmbus_data *data = i2c_get_clientdata(client); -- const struct pmbus_driver_info *info = data->info; -- int delay = info->access_delay; -+ const struct pmbus_driver_info *info; -+ int delay; -+ -+ if (!data) -+ return; -+ -+ info = data->info; -+ delay = info->access_delay; - - if (op & PMBUS_OP_WRITE) - delay = max(delay, info->write_delay); -@@ -517,6 +529,81 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, - } - EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, "PMBUS"); - -+/** -+ * pmbus_read_smbus_i2c_block_data() - Read SMBus/I2C block data -+ * @client: Handle to slave device -+ * @reg: Byte interpreted by slave -+ * @data_buf: Byte array into which data will be read -+ * Return: Negative errno or number of bytes read -+ * -+ * PMBus internal function to read a SMBus block from a PMBus chip. -+ * -+ * PMBus chips report various properties using SMBus block read operations. -+ * However, not all I2C controllers support this operation. -+ * -+ * Execute SMBus block read if supported. If not supported, but SMBus I2C block -+ * read is supported, use it instead. Note that at most 31 data bytes can be -+ * read from the device if i2c_smbus_read_i2c_block_data() is used to read the -+ * data. This is a SMBUs protocol limit which can not be avoided. -+ * -+ * Return -EOPNOTSUPP if neither I2C_FUNC_SMBUS_READ_BLOCK_DATA nor -+ * I2C_FUNC_SMBUS_READ_I2C_BLOCK is supported. -+ * -+ * Callers must hold pmbus_lock or execute calls from the probe function. -+ */ -+int pmbus_read_smbus_i2c_block_data(struct i2c_client *client, u8 reg, char *data_buf) -+{ -+ u8 buf[I2C_SMBUS_BLOCK_MAX]; -+ int blen, len, ret; -+ -+ if (i2c_check_functionality(client->adapter, -+ I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { -+ pmbus_wait(client); -+ ret = i2c_smbus_read_block_data(client, reg, data_buf); -+ pmbus_update_ts(client, 0); -+ return ret; -+ } -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { -+ dev_err_once(&client->dev, "I2C adapter does not support I2C_FUNC_SMBUS_READ_I2C_BLOCK\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ /* -+ * If the returned data is valid SMBus block data, the first byte -+ * must be the data length. -+ * -+ * i2c_smbus_read_i2c_block_data() may return an error if the chip -+ * sends NACK before the number of requested bytes is received. -+ * Handle this by reading the data length first, then reading the -+ * entire message up to I2C_SMBUS_BLOCK_MAX bytes. This ensures -+ * that requested number of bytes never exceeds the number of -+ * bytes sent by the chip. -+ */ -+ pmbus_wait(client); -+ ret = i2c_smbus_read_i2c_block_data(client, reg, 1, buf); -+ pmbus_update_ts(client, 0); -+ if (ret < 0) -+ return ret; -+ -+ len = buf[0]; -+ if (len == 0) -+ return 0; -+ blen = len; -+ if (len >= I2C_SMBUS_BLOCK_MAX) -+ len = I2C_SMBUS_BLOCK_MAX - 1; -+ pmbus_wait(client); -+ ret = i2c_smbus_read_i2c_block_data(client, reg, len + 1, buf); -+ pmbus_update_ts(client, 0); -+ if (ret < 0) -+ return ret; -+ if (buf[0] != blen) -+ return -EIO; -+ memcpy(data_buf, buf + 1, len); -+ return len; -+} -+EXPORT_SYMBOL_NS_GPL(pmbus_read_smbus_i2c_block_data, "PMBUS"); -+ - static int pmbus_read_block_data(struct i2c_client *client, int page, u8 reg, - char *data_buf) - { -@@ -526,11 +613,7 @@ static int pmbus_read_block_data(struct i2c_client *client, int page, u8 reg, - if (rv < 0) - return rv; - -- pmbus_wait(client); -- rv = i2c_smbus_read_block_data(client, reg, data_buf); -- pmbus_update_ts(client, 0); -- -- return rv; -+ return pmbus_read_smbus_i2c_block_data(client, reg, data_buf); - } - - static struct pmbus_sensor *pmbus_find_sensor(struct pmbus_data *data, int page, -@@ -2849,9 +2932,16 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, - if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) - pmbus_init_wp(client, data); - -- ret = i2c_smbus_read_byte_data(client, PMBUS_REVISION); -- if (ret >= 0) -- data->revision = ret; -+ if (info->have_pmbus_revision) { -+ data->have_pmbus_revision = true; -+ data->revision = info->pmbus_revision; -+ } else { -+ ret = i2c_smbus_read_byte_data(client, PMBUS_REVISION); -+ if (ret >= 0) { -+ data->have_pmbus_revision = true; -+ data->revision = ret; -+ } -+ } - - if (data->info->pages) - pmbus_clear_faults(client); -@@ -3455,10 +3545,9 @@ static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, - return ret; - } - --static irqreturn_t pmbus_fault_handler(int irq, void *pdata) -+void pmbus_check_and_notify_faults(struct i2c_client *client) - { -- struct pmbus_data *data = pdata; -- struct i2c_client *client = to_i2c_client(data->dev); -+ struct pmbus_data *data = i2c_get_clientdata(client); - int i, status, event; - - guard(pmbus_lock)(client); -@@ -3471,6 +3560,15 @@ static irqreturn_t pmbus_fault_handler(int irq, void *pdata) - } - - pmbus_clear_faults(client); -+} -+EXPORT_SYMBOL_NS_GPL(pmbus_check_and_notify_faults, "PMBUS"); -+ -+static irqreturn_t pmbus_fault_handler(int irq, void *pdata) -+{ -+ struct pmbus_data *data = pdata; -+ struct i2c_client *client = to_i2c_client(data->dev); -+ -+ pmbus_check_and_notify_faults(client); - - return IRQ_HANDLED; - } -@@ -3514,10 +3612,8 @@ static int pmbus_irq_setup(struct i2c_client *client, struct pmbus_data *data) - /* Register notifiers */ - err = devm_request_threaded_irq(dev, client->irq, NULL, pmbus_fault_handler, - IRQF_ONESHOT, "pmbus-irq", data); -- if (err) { -- dev_err(dev, "failed to request an irq %d\n", err); -+ if (err) - return err; -- } - - return 0; - } -@@ -3543,6 +3639,17 @@ static int pmbus_debugfs_get(void *data, u64 *val) - DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops, pmbus_debugfs_get, NULL, - "0x%02llx\n"); - -+static int pmbus_debugfs_get_revision(void *data, u64 *val) -+{ -+ struct pmbus_data *pdata = data; -+ -+ *val = pdata->revision; -+ -+ return 0; -+} -+DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_revision_ops, pmbus_debugfs_get_revision, NULL, -+ "0x%02llx\n"); -+ - static int pmbus_debugfs_get_status(void *data, u64 *val) - { - struct pmbus_debugfs_entry *entry = data; -@@ -3698,14 +3805,9 @@ static void pmbus_init_debugfs(struct i2c_client *client, - &entries[idx++], - &pmbus_debugfs_ops); - } -- if (pmbus_check_byte_register(client, 0, PMBUS_REVISION)) { -- entries[idx].client = client; -- entries[idx].page = 0; -- entries[idx].reg = PMBUS_REVISION; -- debugfs_create_file("pmbus_revision", 0444, debugfs, -- &entries[idx++], -- &pmbus_debugfs_ops); -- } -+ if (data->have_pmbus_revision) -+ debugfs_create_file("pmbus_revision", 0444, debugfs, data, -+ &pmbus_debugfs_revision_ops); - - for (i = 0; i < ARRAY_SIZE(pmbus_debugfs_block_data); i++) { - const struct pmbus_debugfs_data *d = &pmbus_debugfs_block_data[i]; -diff --git a/drivers/hwmon/pmbus/sq24860.c b/drivers/hwmon/pmbus/sq24860.c -new file mode 100644 ---- /dev/null -+++ b/drivers/hwmon/pmbus/sq24860.c -@@ -0,0 +1,430 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Author: Ziming Zhu -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pmbus.h" -+ -+#define SQ24860_IIN_CAL_GAIN 0x38 -+#define SQ24860_READ_VAUX 0xd0 -+#define SQ24860_READ_VIN_MIN 0xd1 -+#define SQ24860_READ_VIN_PEAK 0xd2 -+#define SQ24860_READ_IIN_PEAK 0xd4 -+#define SQ24860_READ_PIN_PEAK 0xd5 -+#define SQ24860_READ_TEMP_AVG 0xd6 -+#define SQ24860_READ_TEMP_PEAK 0xd7 -+#define SQ24860_READ_VOUT_MIN 0xda -+#define SQ24860_READ_VIN_AVG 0xdc -+#define SQ24860_READ_VOUT_AVG 0xdd -+#define SQ24860_READ_IIN_AVG 0xde -+#define SQ24860_READ_PIN_AVG 0xdf -+#define SQ24860_VIREF 0xe0 -+#define SQ24860_PK_MIN_AVG 0xea -+#define PK_MIN_AVG_RST_PEAK BIT(7) -+#define PK_MIN_AVG_RST_AVG BIT(6) -+#define PK_MIN_AVG_RST_MIN BIT(5) -+#define PK_MIN_AVG_AVG_CNT GENMASK(2, 0) -+#define SQ24860_MFR_WRITE_PROTECT 0xf8 -+#define SQ24860_UNLOCKED BIT(7) -+ -+#define SQ24860_8B_SHIFT 2 -+#define SQ24860_IIN_OCF_NUM 1000000 -+#define SQ24860_IIN_OCF_DIV 129278 -+#define SQ24860_IIN_OCF_OFF 165 -+ -+#define PK_MIN_AVG_RST_MASK (PK_MIN_AVG_RST_PEAK | \ -+ PK_MIN_AVG_RST_AVG | \ -+ PK_MIN_AVG_RST_MIN) -+#define SQ24860_MAX_SAMPLES BIT(FIELD_MAX(PK_MIN_AVG_AVG_CNT)) -+/* -+ * Arbitrary default Rimon value: 1.6kOhm -+ */ -+#define SQ24860_DEFAULT_RIMON 1600000000 -+#define SQ24860_GIMON 18180 -+ -+#define SQ24860_VAUX_DIV 20 -+ -+static int sq24860_write_iin_cal_gain(struct i2c_client *client, u32 rimon) -+{ -+ u64 temp = 6400ULL * 1000000000ULL * 1000ULL; -+ u64 denom; -+ u64 word; -+ -+ if (!rimon) -+ return -EINVAL; -+ -+ denom = (u64)rimon * SQ24860_GIMON; -+ word = div64_u64(temp, denom); -+ if (!word || word > U16_MAX) -+ return -EINVAL; -+ -+ return i2c_smbus_write_word_data(client, SQ24860_IIN_CAL_GAIN, -+ (u16)word); -+} -+ -+static int sq24860_mfr_write_protect_set(struct i2c_client *client, -+ u8 protect) -+{ -+ u8 val; -+ -+ switch (protect) { -+ case 0: -+ val = 0xa2; -+ break; -+ case PB_WP_ALL: -+ val = 0x0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return pmbus_write_byte_data(client, -1, SQ24860_MFR_WRITE_PROTECT, -+ val); -+} -+ -+static int sq24860_mfr_write_protect_get(struct i2c_client *client) -+{ -+ int ret = pmbus_read_byte_data(client, -1, SQ24860_MFR_WRITE_PROTECT); -+ -+ if (ret < 0) -+ return ret; -+ -+ return (ret & SQ24860_UNLOCKED) ? 0 : PB_WP_ALL; -+} -+ -+static int sq24860_read_word_data(struct i2c_client *client, -+ int page, int phase, int reg) -+{ -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_VIRT_READ_VIN_MAX: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_VIN_PEAK); -+ break; -+ -+ case PMBUS_VIRT_READ_VIN_MIN: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_VIN_MIN); -+ break; -+ -+ case PMBUS_VIRT_READ_VIN_AVG: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_VIN_AVG); -+ break; -+ -+ case PMBUS_VIRT_READ_VOUT_MIN: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_VOUT_MIN); -+ break; -+ -+ case PMBUS_VIRT_READ_VOUT_AVG: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_VOUT_AVG); -+ break; -+ -+ case PMBUS_VIRT_READ_IIN_AVG: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_IIN_AVG); -+ break; -+ -+ case PMBUS_VIRT_READ_IIN_MAX: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_IIN_PEAK); -+ break; -+ -+ case PMBUS_VIRT_READ_TEMP_AVG: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_TEMP_AVG); -+ break; -+ -+ case PMBUS_VIRT_READ_TEMP_MAX: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_TEMP_PEAK); -+ break; -+ -+ case PMBUS_VIRT_READ_PIN_AVG: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_PIN_AVG); -+ break; -+ -+ case PMBUS_VIRT_READ_PIN_MAX: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_PIN_PEAK); -+ break; -+ -+ case PMBUS_VIRT_READ_VMON: -+ ret = pmbus_read_word_data(client, page, phase, -+ SQ24860_READ_VAUX); -+ if (ret < 0) -+ break; -+ ret = DIV_ROUND_CLOSEST(ret, SQ24860_VAUX_DIV); -+ break; -+ -+ case PMBUS_VIN_UV_WARN_LIMIT: -+ case PMBUS_VIN_UV_FAULT_LIMIT: -+ case PMBUS_VIN_OV_WARN_LIMIT: -+ case PMBUS_VIN_OV_FAULT_LIMIT: -+ case PMBUS_VOUT_UV_WARN_LIMIT: -+ case PMBUS_IIN_OC_WARN_LIMIT: -+ case PMBUS_OT_WARN_LIMIT: -+ case PMBUS_OT_FAULT_LIMIT: -+ case PMBUS_PIN_OP_WARN_LIMIT: -+ /* -+ * These registers provide an 8 bits value instead of a -+ * 10bits one. Just shifting twice the register value is -+ * enough to make the sensor type conversion work, even -+ * if the datasheet provides different m, b and R for -+ * those. -+ */ -+ ret = pmbus_read_word_data(client, page, phase, reg); -+ if (ret < 0) -+ break; -+ ret <<= SQ24860_8B_SHIFT; -+ break; -+ -+ case PMBUS_IIN_OC_FAULT_LIMIT: -+ /* -+ * VIREF directly sets the over-current limit at which the eFuse -+ * will turn the FET off and trigger a fault. Expose it through -+ * this generic property instead of a manufacturer specific one. -+ */ -+ ret = pmbus_read_byte_data(client, page, SQ24860_VIREF); -+ if (ret < 0) -+ break; -+ ret = DIV_ROUND_CLOSEST(ret * SQ24860_IIN_OCF_NUM, -+ SQ24860_IIN_OCF_DIV); -+ ret += SQ24860_IIN_OCF_OFF; -+ break; -+ -+ case PMBUS_VIRT_SAMPLES: -+ ret = pmbus_read_byte_data(client, page, SQ24860_PK_MIN_AVG); -+ if (ret < 0) -+ break; -+ ret = BIT(FIELD_GET(PK_MIN_AVG_AVG_CNT, ret)); -+ break; -+ -+ case PMBUS_VIRT_RESET_TEMP_HISTORY: -+ case PMBUS_VIRT_RESET_VIN_HISTORY: -+ case PMBUS_VIRT_RESET_IIN_HISTORY: -+ case PMBUS_VIRT_RESET_PIN_HISTORY: -+ case PMBUS_VIRT_RESET_VOUT_HISTORY: -+ ret = 0; -+ break; -+ -+ default: -+ ret = -ENODATA; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int sq24860_write_word_data(struct i2c_client *client, -+ int page, int reg, u16 value) -+{ -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_VIN_UV_WARN_LIMIT: -+ case PMBUS_VIN_UV_FAULT_LIMIT: -+ case PMBUS_VIN_OV_WARN_LIMIT: -+ case PMBUS_VIN_OV_FAULT_LIMIT: -+ case PMBUS_VOUT_UV_WARN_LIMIT: -+ case PMBUS_IIN_OC_WARN_LIMIT: -+ case PMBUS_OT_WARN_LIMIT: -+ case PMBUS_OT_FAULT_LIMIT: -+ case PMBUS_PIN_OP_WARN_LIMIT: -+ value = max_t(s16, (s16)value, 0); -+ value >>= SQ24860_8B_SHIFT; -+ value = clamp_val(value, 0, 0xff); -+ ret = pmbus_write_word_data(client, page, reg, value); -+ break; -+ -+ case PMBUS_IIN_OC_FAULT_LIMIT: -+ value = max_t(s16, (s16)value, SQ24860_IIN_OCF_OFF); -+ value -= SQ24860_IIN_OCF_OFF; -+ value = DIV_ROUND_CLOSEST(((unsigned int)value) * SQ24860_IIN_OCF_DIV, -+ SQ24860_IIN_OCF_NUM); -+ value = clamp_val(value, 0, 0x3f); -+ ret = pmbus_write_byte_data(client, page, SQ24860_VIREF, value); -+ break; -+ -+ case PMBUS_VIRT_SAMPLES: -+ value = clamp_val(value, 1, SQ24860_MAX_SAMPLES); -+ value = ilog2(value); -+ ret = pmbus_update_byte_data(client, page, SQ24860_PK_MIN_AVG, -+ PK_MIN_AVG_AVG_CNT, -+ FIELD_PREP(PK_MIN_AVG_AVG_CNT, value)); -+ break; -+ -+ case PMBUS_VIRT_RESET_TEMP_HISTORY: -+ case PMBUS_VIRT_RESET_VIN_HISTORY: -+ case PMBUS_VIRT_RESET_IIN_HISTORY: -+ case PMBUS_VIRT_RESET_PIN_HISTORY: -+ case PMBUS_VIRT_RESET_VOUT_HISTORY: -+ /* -+ * SQ24860 has history resets based on MIN/AVG/PEAK instead of per -+ * sensor type. Exposing this quirk in hwmon is not desirable so -+ * reset MIN, AVG and PEAK together. Even is there effectively only -+ * one reset, which resets everything, expose the 5 entries so -+ * userspace is not required map a sensor type to another to trigger -+ * a reset -+ */ -+ ret = pmbus_update_byte_data(client, 0, SQ24860_PK_MIN_AVG, -+ PK_MIN_AVG_RST_MASK, -+ PK_MIN_AVG_RST_MASK); -+ break; -+ -+ default: -+ ret = -ENODATA; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int sq24860_read_byte_data(struct i2c_client *client, -+ int page, int reg) -+{ -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_WRITE_PROTECT: -+ ret = sq24860_mfr_write_protect_get(client); -+ break; -+ -+ default: -+ ret = -ENODATA; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int sq24860_write_byte_data(struct i2c_client *client, -+ int page, int reg, u8 byte) -+{ -+ int ret; -+ -+ switch (reg) { -+ case PMBUS_WRITE_PROTECT: -+ ret = sq24860_mfr_write_protect_set(client, byte); -+ break; -+ -+ default: -+ ret = -ENODATA; -+ break; -+ } -+ -+ return ret; -+} -+ -+#if IS_ENABLED(CONFIG_SENSORS_SQ24860_REGULATOR) -+static const struct regulator_desc sq24860_reg_desc[] = { -+ PMBUS_REGULATOR_ONE_NODE("vout"), -+}; -+#endif -+ -+static const struct pmbus_driver_info sq24860_base_info = { -+ .pages = 1, -+ .format[PSC_VOLTAGE_IN] = direct, -+ .m[PSC_VOLTAGE_IN] = 64, -+ .b[PSC_VOLTAGE_IN] = 0, -+ .R[PSC_VOLTAGE_IN] = 0, -+ .format[PSC_VOLTAGE_OUT] = direct, -+ .m[PSC_VOLTAGE_OUT] = 64, -+ .b[PSC_VOLTAGE_OUT] = 0, -+ .R[PSC_VOLTAGE_OUT] = 0, -+ .format[PSC_TEMPERATURE] = direct, -+ .m[PSC_TEMPERATURE] = 1, -+ .b[PSC_TEMPERATURE] = 0, -+ .R[PSC_TEMPERATURE] = 0, -+ /* -+ * Current and power measurements depend on the calibration gain -+ * programmed from the board-specific IMON resistor value. -+ */ -+ .format[PSC_CURRENT_IN] = direct, -+ .m[PSC_CURRENT_IN] = 16, -+ .b[PSC_CURRENT_IN] = 0, -+ .R[PSC_CURRENT_IN] = 0, -+ .format[PSC_POWER] = direct, -+ .m[PSC_POWER] = 2, -+ .b[PSC_POWER] = 0, -+ .R[PSC_POWER] = 0, -+ .func[0] = PMBUS_HAVE_VIN | -+ PMBUS_HAVE_VOUT | -+ PMBUS_HAVE_VMON | -+ PMBUS_HAVE_IIN | -+ PMBUS_HAVE_PIN | -+ PMBUS_HAVE_TEMP | -+ PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_STATUS_INPUT | -+ PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_SAMPLES, -+ .read_word_data = sq24860_read_word_data, -+ .write_word_data = sq24860_write_word_data, -+ .read_byte_data = sq24860_read_byte_data, -+ .write_byte_data = sq24860_write_byte_data, -+ -+#if IS_ENABLED(CONFIG_SENSORS_SQ24860_REGULATOR) -+ .reg_desc = sq24860_reg_desc, -+ .num_regulators = ARRAY_SIZE(sq24860_reg_desc), -+#endif -+}; -+ -+static const struct i2c_device_id sq24860_i2c_id[] = { -+ { "sq24860" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, sq24860_i2c_id); -+ -+static const struct of_device_id sq24860_of_match[] = { -+ { .compatible = "silergy,sq24860" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, sq24860_of_match); -+ -+static int sq24860_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct pmbus_driver_info *info; -+ u32 rimon; -+ int ret; -+ -+ if (device_property_read_u32(dev, "silergy,rimon-micro-ohms", &rimon)) -+ rimon = SQ24860_DEFAULT_RIMON; -+ ret = sq24860_write_iin_cal_gain(client, rimon); -+ if (ret < 0) -+ return dev_err_probe(&client->dev, ret, -+ "Failed to set gain\n"); -+ info = devm_kmemdup(dev, &sq24860_base_info, sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ return pmbus_do_probe(client, info); -+} -+ -+static struct i2c_driver sq24860_driver = { -+ .driver = { -+ .name = "sq24860", -+ .of_match_table = sq24860_of_match, -+ }, -+ .probe = sq24860_probe, -+ .id_table = sq24860_i2c_id, -+}; -+module_i2c_driver(sq24860_driver); -+ -+MODULE_AUTHOR("Ziming Zhu "); -+MODULE_DESCRIPTION("PMBUS driver for SQ24860 eFuse"); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("PMBUS"); -diff --git a/drivers/hwmon/pmbus/vt7505.c b/drivers/hwmon/pmbus/vt7505.c -new file mode 100644 ---- /dev/null -+++ b/drivers/hwmon/pmbus/vt7505.c -@@ -0,0 +1,287 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Hardware monitoring driver for Analog Devices MAX16545/MAX16550 and -+ * Volterra VT7505 PMBus controllers. -+ * -+ * Copyright 2026 Hewlett Packard Enterprise Development LP -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pmbus.h" -+ -+#define VT7505_MFR_CONFIG 0xd0 -+#define VT7505_CFG_OCP_S_FILT_MASK GENMASK(15, 14) -+ -+#define VT7505_MFR_PEAK_VIN 0xd1 -+#define VT7505_MFR_PEAK_IOUT 0xd2 -+#define VT7505_MFR_PEAK_PIN 0xd3 -+#define VT7505_MFR_PEAK_TEMP 0xd4 -+#define VT7505_MFR_CLEAR_PEAKS 0xd5 -+#define VT7505_MFR_PEAK_VOUT 0xfd -+ -+#define VT7505_RLOAD_DEFAULT 4750 -+/* Largest RLOAD for which coeff * rload / 1000 still fits in s32. */ -+#define VT7505_RLOAD_MAX 283383959U -+ -+struct vt7505_chip_data { -+ int temp_m; -+ int temp_b; -+ bool has_ocp_filter; -+}; -+ -+static const struct vt7505_chip_data max16545_data = { -+ .temp_m = 205, -+ .temp_b = 6545, -+}; -+ -+static const struct vt7505_chip_data max16550_data = { -+ .temp_m = 199, -+ .temp_b = 7046, -+ .has_ocp_filter = true, -+}; -+ -+static const struct vt7505_chip_data vt7505_data = { -+ .temp_m = 205, -+ .temp_b = 6545, -+ .has_ocp_filter = true, -+}; -+ -+static int vt7505_read_word_data(struct i2c_client *client, int page, -+ int phase, int reg) -+{ -+ switch (reg) { -+ case PMBUS_VIRT_READ_VIN_MAX: -+ return pmbus_read_word_data(client, page, phase, -+ VT7505_MFR_PEAK_VIN); -+ case PMBUS_VIRT_READ_IOUT_MAX: -+ return pmbus_read_word_data(client, page, phase, -+ VT7505_MFR_PEAK_IOUT); -+ case PMBUS_VIRT_READ_PIN_MAX: -+ return pmbus_read_word_data(client, page, phase, -+ VT7505_MFR_PEAK_PIN); -+ case PMBUS_VIRT_READ_TEMP_MAX: -+ return pmbus_read_word_data(client, page, phase, -+ VT7505_MFR_PEAK_TEMP); -+ case PMBUS_VIRT_READ_VOUT_MAX: -+ return pmbus_read_word_data(client, page, phase, -+ VT7505_MFR_PEAK_VOUT); -+ case PMBUS_VIRT_RESET_VIN_HISTORY: -+ case PMBUS_VIRT_RESET_IOUT_HISTORY: -+ case PMBUS_VIRT_RESET_PIN_HISTORY: -+ case PMBUS_VIRT_RESET_TEMP_HISTORY: -+ case PMBUS_VIRT_RESET_VOUT_HISTORY: -+ return 0; -+ default: -+ return -ENODATA; -+ } -+} -+ -+static int vt7505_write_word_data(struct i2c_client *client, int page, -+ int reg, u16 word) -+{ -+ switch (reg) { -+ /* -+ * A single reset command clears all peak values. CLEAR_PEAKS is a -+ * send-byte command; the device NAKs a word or byte-data write to it. -+ */ -+ case PMBUS_VIRT_RESET_VIN_HISTORY: -+ case PMBUS_VIRT_RESET_IOUT_HISTORY: -+ case PMBUS_VIRT_RESET_PIN_HISTORY: -+ case PMBUS_VIRT_RESET_TEMP_HISTORY: -+ case PMBUS_VIRT_RESET_VOUT_HISTORY: -+ return pmbus_write_byte(client, page, -+ VT7505_MFR_CLEAR_PEAKS); -+ default: -+ return -ENODATA; -+ } -+} -+ -+/* -+ * None of these controllers implement the standard PMBus WRITE_PROTECT -+ * (0x10) register, so tell the core not to access it. -+ */ -+static struct pmbus_platform_data vt7505_pdata = { -+ .flags = PMBUS_NO_WRITE_PROTECT, -+}; -+ -+static int vt7505_set_ocp_filter(struct i2c_client *client) -+{ -+ u32 ocp_us; -+ u8 field; -+ int ret; -+ u16 word; -+ -+ if (of_property_read_u32(client->dev.of_node, "adi,ocp-severe-filter-us", -+ &ocp_us)) -+ return 0; -+ -+ switch (ocp_us) { -+ case 0: -+ field = 0; -+ break; -+ case 1: -+ field = 1; -+ break; -+ case 2: -+ field = 2; -+ break; -+ case 10: -+ field = 3; -+ break; -+ default: -+ return dev_err_probe(&client->dev, -EINVAL, -+ "invalid adi,ocp-severe-filter-us value %u\n", -+ ocp_us); -+ } -+ -+ ret = i2c_smbus_read_word_data(client, VT7505_MFR_CONFIG); -+ if (ret < 0) -+ return dev_err_probe(&client->dev, ret, -+ "failed to read MFR_CONFIG\n"); -+ -+ word = ret & ~VT7505_CFG_OCP_S_FILT_MASK; -+ word |= FIELD_PREP(VT7505_CFG_OCP_S_FILT_MASK, field); -+ -+ ret = i2c_smbus_write_word_data(client, VT7505_MFR_CONFIG, word); -+ if (ret < 0) -+ return dev_err_probe(&client->dev, ret, -+ "failed to write MFR_CONFIG\n"); -+ -+ return 0; -+} -+ -+static void vt7505_set_m(int *m, u32 rload) -+{ -+ u64 val = (u64)*m * rload; -+ -+ /* rload is range-checked in probe, so the result fits in int. */ -+ *m = DIV_ROUND_CLOSEST_ULL(val, 1000); -+} -+ -+static int vt7505_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ const struct vt7505_chip_data *chip; -+ struct pmbus_driver_info *info; -+ u32 rload; -+ int ret; -+ -+ chip = i2c_get_match_data(client); -+ if (!chip) -+ return -ENODEV; -+ -+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ dev->platform_data = &vt7505_pdata; -+ -+ /* -+ * The m coefficient used in the direct-format current and power -+ * calculations depends on RLOAD, the external current-report resistor -+ * connected between the ILOAD pin and ground. Use the default value if -+ * none is specified. -+ */ -+ if (of_property_read_u32(dev->of_node, "adi,rload-ohms", &rload)) -+ rload = VT7505_RLOAD_DEFAULT; -+ -+ if (!rload || rload > VT7505_RLOAD_MAX) -+ return dev_err_probe(dev, -EINVAL, -+ "adi,rload-ohms must be 1-%u\n", -+ VT7505_RLOAD_MAX); -+ -+ info->pages = 1; -+ info->read_word_data = vt7505_read_word_data; -+ info->write_word_data = vt7505_write_word_data; -+ -+ info->format[PSC_VOLTAGE_IN] = direct; -+ info->format[PSC_VOLTAGE_OUT] = direct; -+ info->format[PSC_CURRENT_IN] = direct; -+ info->format[PSC_CURRENT_OUT] = direct; -+ info->format[PSC_POWER] = direct; -+ info->format[PSC_TEMPERATURE] = direct; -+ -+ /* -+ * Direct data format coefficients from the device datasheet ("PMBus -+ * Equation Parameters"). The current and power m coefficients scale -+ * with RLOAD; vt7505_set_m() applies the 1/1000 factor below, giving -+ * m = 3.824 * RLOAD for current and 0.895 * RLOAD for power. The -+ * temperature coefficients are chip specific (see the chip data). -+ */ -+ info->m[PSC_VOLTAGE_IN] = 7578; -+ info->R[PSC_VOLTAGE_IN] = -2; -+ info->m[PSC_VOLTAGE_OUT] = 7578; -+ info->R[PSC_VOLTAGE_OUT] = -2; -+ info->m[PSC_CURRENT_IN] = 3824; -+ info->b[PSC_CURRENT_IN] = -4300; -+ info->R[PSC_CURRENT_IN] = -3; -+ info->m[PSC_CURRENT_OUT] = 3824; -+ info->b[PSC_CURRENT_OUT] = -4300; -+ info->R[PSC_CURRENT_OUT] = -3; -+ info->m[PSC_POWER] = 895; -+ info->b[PSC_POWER] = -9100; -+ info->R[PSC_POWER] = -2; -+ -+ vt7505_set_m(&info->m[PSC_CURRENT_IN], rload); -+ vt7505_set_m(&info->m[PSC_CURRENT_OUT], rload); -+ vt7505_set_m(&info->m[PSC_POWER], rload); -+ -+ info->m[PSC_TEMPERATURE] = chip->temp_m; -+ info->b[PSC_TEMPERATURE] = chip->temp_b; -+ info->R[PSC_TEMPERATURE] = -2; -+ -+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | -+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | -+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | -+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | -+ PMBUS_HAVE_IIN | PMBUS_HAVE_PIN; -+ -+ /* -+ * The severe OCP deglitch filter is programmable on the MAX16550 and -+ * the VT7505, but fixed on the MAX16545. -+ */ -+ if (chip->has_ocp_filter) { -+ ret = vt7505_set_ocp_filter(client); -+ if (ret) -+ return ret; -+ } -+ -+ return pmbus_do_probe(client, info); -+} -+ -+static const struct i2c_device_id vt7505_id[] = { -+ { .name = "max16545", .driver_data = (kernel_ulong_t)&max16545_data }, -+ { .name = "max16550", .driver_data = (kernel_ulong_t)&max16550_data }, -+ { .name = "vt7505", .driver_data = (kernel_ulong_t)&vt7505_data }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, vt7505_id); -+ -+static const struct of_device_id vt7505_of_match[] = { -+ { .compatible = "adi,max16545", .data = &max16545_data }, -+ { .compatible = "adi,max16550", .data = &max16550_data }, -+ { .compatible = "adi,vt7505", .data = &vt7505_data }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, vt7505_of_match); -+ -+static struct i2c_driver vt7505_driver = { -+ .driver = { -+ .name = "vt7505", -+ .of_match_table = vt7505_of_match, -+ }, -+ .probe = vt7505_probe, -+ .id_table = vt7505_id, -+}; -+module_i2c_driver(vt7505_driver); -+ -+MODULE_AUTHOR("Georgi Vlaev "); -+MODULE_DESCRIPTION("PMBus driver for Analog Devices MAX16545/MAX16550 and Volterra VT7505"); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("PMBUS"); -diff --git a/drivers/hwmon/pmbus/xdpe1a2g7b.c b/drivers/hwmon/pmbus/xdpe1a2g7b.c ---- a/drivers/hwmon/pmbus/xdpe1a2g7b.c -+++ b/drivers/hwmon/pmbus/xdpe1a2g7b.c -@@ -57,6 +57,13 @@ static int xdpe1a2g7b_identify(struct i2c_client *client, - return 0; - } - -+#if IS_ENABLED(CONFIG_SENSORS_XDPE1A2G7B_REGULATOR) -+static const struct regulator_desc xdpe1a2g7b_reg_desc[] = { -+ PMBUS_REGULATOR("vout", 0), -+ PMBUS_REGULATOR("vout", 1), -+}; -+#endif -+ - static struct pmbus_driver_info xdpe1a2g7b_info = { - .pages = XDPE1A2G7B_PAGE_NUM, - .identify = xdpe1a2g7b_identify, -@@ -72,6 +79,10 @@ static struct pmbus_driver_info xdpe1a2g7b_info = { - .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | - PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | - PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_STATUS_INPUT, -+#if IS_ENABLED(CONFIG_SENSORS_XDPE1A2G7B_REGULATOR) -+ .num_regulators = XDPE1A2G7B_PAGE_NUM, -+ .reg_desc = xdpe1a2g7b_reg_desc, -+#endif - }; - - static int xdpe1a2g7b_probe(struct i2c_client *client) -diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c ---- a/drivers/hwmon/pwm-fan.c -+++ b/drivers/hwmon/pwm-fan.c -@@ -634,12 +634,8 @@ static int pwm_fan_probe(struct platform_device *pdev) - if (tach->irq > 0) { - ret = devm_request_irq(dev, tach->irq, pulse_handler, - IRQF_NO_THREAD, pdev->name, tach); -- if (ret) { -- dev_err(dev, -- "Failed to request interrupt: %d\n", -- ret); -+ if (ret) - return ret; -- } - } - - if (!ctx->pulses_per_revolution[i]) { -diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c ---- a/drivers/hwmon/sht15.c -+++ b/drivers/hwmon/sht15.c -@@ -981,10 +981,8 @@ static int sht15_probe(struct platform_device *pdev) - IRQF_TRIGGER_FALLING, - "sht15 data", - data); -- if (ret) { -- dev_err(&pdev->dev, "failed to get irq for data line\n"); -+ if (ret) - goto err_release_reg; -- } - disable_irq_nosync(gpiod_to_irq(data->data)); - ret = sht15_connection_reset(data); - if (ret) -diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c ---- a/drivers/hwmon/sht3x.c -+++ b/drivers/hwmon/sht3x.c -@@ -62,7 +62,7 @@ static const unsigned char sht3x_cmd_read_serial_number[] = { 0x37, 0x80 }; - #define SHT3X_MAX_HUMIDITY 100000 - - enum sht3x_chips { -- sht3x, -+ sht3x = 1, - sts3x, - }; - -@@ -940,8 +940,19 @@ static const struct i2c_device_id sht3x_ids[] = { - - MODULE_DEVICE_TABLE(i2c, sht3x_ids); - -+static const struct of_device_id sht3x_of_match[] = { -+ { .compatible = "sensirion,sht30", .data = (void *)(uintptr_t)sht3x }, -+ { .compatible = "sensirion,sts30", .data = (void *)(uintptr_t)sts3x }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(of, sht3x_of_match); -+ - static struct i2c_driver sht3x_i2c_driver = { -- .driver.name = "sht3x", -+ .driver = { -+ .name = "sht3x", -+ .of_match_table = sht3x_of_match, -+ }, - .probe = sht3x_probe, - .id_table = sht3x_ids, - }; -diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c ---- a/drivers/hwmon/tmp102.c -+++ b/drivers/hwmon/tmp102.c -@@ -396,6 +396,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tmp102_dev_pm_ops, tmp102_suspend, tmp102_resume - - static const struct i2c_device_id tmp102_id[] = { - { .name = "tmp102" }, -+ { .name = "tmp110" }, -+ { .name = "tmp113" }, - { } - }; - MODULE_DEVICE_TABLE(i2c, tmp102_id); -diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c ---- a/drivers/hwmon/tmp401.c -+++ b/drivers/hwmon/tmp401.c -@@ -695,7 +695,7 @@ static int tmp401_probe(struct i2c_client *client) - info->type = hwmon_chip; - info->config = data->chip_channel_config; - -- data->chip_channel_config[0] = HWMON_C_UPDATE_INTERVAL; -+ data->chip_channel_config[0] = HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL; - - info = &data->temp_info; - info->type = hwmon_temp; -diff --git a/drivers/hwmon/tvs-mpfs.c b/drivers/hwmon/tvs-mpfs.c -new file mode 100644 ---- /dev/null -+++ b/drivers/hwmon/tvs-mpfs.c -@@ -0,0 +1,390 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Author: Lars Randers -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MPFS_TVS_CTRL 0x08 -+#define MPFS_TVS_OUTPUT0 0x24 -+#define MPFS_TVS_OUTPUT1 0x28 -+ -+#define MPFS_TVS_CTRL_TEMP_VALID BIT(19) -+#define MPFS_TVS_CTRL_V2P5_VALID BIT(18) -+#define MPFS_TVS_CTRL_V1P8_VALID BIT(17) -+#define MPFS_TVS_CTRL_V1P05_VALID BIT(16) -+ -+#define MPFS_TVS_CTRL_TEMP_ENABLE BIT(3) -+#define MPFS_TVS_CTRL_V2P5_ENABLE BIT(2) -+#define MPFS_TVS_CTRL_V1P8_ENABLE BIT(1) -+#define MPFS_TVS_CTRL_V1P05_ENABLE BIT(0) -+#define MPFS_TVS_CTRL_ENABLE_ALL GENMASK(3, 0) -+ -+/* -+ * For all of these the value in millivolts is stored in 16 bits, with an upper -+ * sign bit and a lower 3 bits of decimal. These masks discard the sign bit and -+ * decimal places, because if Linux is running these voltages cannot be negative -+ * and so avoid having to convert to two's complement. -+ */ -+#define MPFS_OUTPUT0_V1P8_MASK GENMASK(30, 19) -+#define MPFS_OUTPUT0_V1P05_MASK GENMASK(14, 3) -+#define MPFS_OUTPUT1_V2P5_MASK GENMASK(14, 3) -+ -+/* -+ * The register map claims that the temperature is stored in bits 31:16, but -+ * application note "AN4682: PolarFire FPGA Temperature and Voltage Sensor" -+ * says that 31 is reserved. Temperature is in kelvin, so what's probably a -+ * sign bit has no value anyway. -+ */ -+#define MPFS_OUTPUT1_TEMP_MASK GENMASK(30, 16) -+ -+#define MPFS_TVS_INTERVAL_MASK GENMASK(15, 8) -+#define MPFS_TVS_INTERVAL_OFFSET 8 -+/* The interval register is in increments of 32 us */ -+#define MPFS_TVS_INTERVAL_SCALE 32 -+/* with 254 usable increments of 32 us available, 8 ms is the integer limit */ -+#define MPFS_TVS_INTERVAL_MAX_MS 8 -+ -+/* 273.1875 in 11.4 fixed-point notation */ -+#define MPFS_TVS_K_TO_C 0x1113 -+ -+enum mpfs_tvs_sensors { -+ SENSOR_V1P05 = 0, -+ SENSOR_V1P8, -+ SENSOR_V2P5, -+}; -+ -+static const char * const mpfs_tvs_voltage_labels[] = { "1P05", "1P8", "2P5" }; -+ -+struct mpfs_tvs { -+ struct regmap *regmap; -+}; -+ -+static int mpfs_tvs_voltage_read(struct mpfs_tvs *data, u32 attr, -+ int channel, long *val) -+{ -+ u32 tmp, control; -+ -+ if (attr != hwmon_in_input && attr != hwmon_in_enable) -+ return -EOPNOTSUPP; -+ -+ regmap_read(data->regmap, MPFS_TVS_CTRL, &control); -+ -+ switch (channel) { -+ case SENSOR_V2P5: -+ if (attr == hwmon_in_enable) { -+ *val = FIELD_GET(MPFS_TVS_CTRL_V2P5_ENABLE, control); -+ break; -+ } -+ -+ if (!(control & MPFS_TVS_CTRL_V2P5_VALID)) -+ return -ENODATA; -+ -+ regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp); -+ *val = FIELD_GET(MPFS_OUTPUT1_V2P5_MASK, tmp); -+ break; -+ case SENSOR_V1P8: -+ if (attr == hwmon_in_enable) { -+ *val = FIELD_GET(MPFS_TVS_CTRL_V1P8_ENABLE, control); -+ break; -+ } -+ -+ if (!(control & MPFS_TVS_CTRL_V1P8_VALID)) -+ return -ENODATA; -+ -+ regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp); -+ *val = FIELD_GET(MPFS_OUTPUT0_V1P8_MASK, tmp); -+ break; -+ case SENSOR_V1P05: -+ if (attr == hwmon_in_enable) { -+ *val = FIELD_GET(MPFS_TVS_CTRL_V1P05_ENABLE, control); -+ break; -+ } -+ -+ if (!(control & MPFS_TVS_CTRL_V1P05_VALID)) -+ return -ENODATA; -+ -+ regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp); -+ *val = FIELD_GET(MPFS_OUTPUT0_V1P05_MASK, tmp); -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static int mpfs_tvs_voltage_write(struct mpfs_tvs *data, u32 attr, -+ int channel, long val) -+{ -+ u32 tmp; -+ -+ if (attr != hwmon_in_enable) -+ return -EOPNOTSUPP; -+ -+ if (val > 1 || val < 0) -+ return -EINVAL; -+ -+ switch (channel) { -+ case SENSOR_V2P5: -+ tmp = FIELD_PREP(MPFS_TVS_CTRL_V2P5_ENABLE, val); -+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL, -+ MPFS_TVS_CTRL_V2P5_ENABLE, tmp); -+ break; -+ case SENSOR_V1P8: -+ tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P8_ENABLE, val); -+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL, -+ MPFS_TVS_CTRL_V1P8_ENABLE, tmp); -+ break; -+ case SENSOR_V1P05: -+ tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P05_ENABLE, val); -+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL, -+ MPFS_TVS_CTRL_V1P05_ENABLE, tmp); -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static int mpfs_tvs_temp_read(struct mpfs_tvs *data, u32 attr, long *val) -+{ -+ u32 tmp, control; -+ -+ if (attr != hwmon_temp_input && attr != hwmon_temp_enable) -+ return -EOPNOTSUPP; -+ -+ regmap_read(data->regmap, MPFS_TVS_CTRL, &control); -+ -+ if (attr == hwmon_temp_enable) { -+ *val = FIELD_GET(MPFS_TVS_CTRL_TEMP_ENABLE, control); -+ return 0; -+ } -+ -+ if (!(control & MPFS_TVS_CTRL_TEMP_VALID)) -+ return -ENODATA; -+ -+ regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp); -+ *val = FIELD_GET(MPFS_OUTPUT1_TEMP_MASK, tmp); -+ *val -= MPFS_TVS_K_TO_C; -+ *val = (1000 * *val) >> 4; /* fixed point (11.4) to millidegrees */ -+ -+ return 0; -+} -+ -+static int mpfs_tvs_temp_write(struct mpfs_tvs *data, u32 attr, long val) -+{ -+ u32 tmp; -+ -+ if (attr != hwmon_temp_enable) -+ return -EOPNOTSUPP; -+ -+ if (val > 1 || val < 0) -+ return -EINVAL; -+ -+ tmp = FIELD_PREP(MPFS_TVS_CTRL_TEMP_ENABLE, val); -+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL, -+ MPFS_TVS_CTRL_TEMP_ENABLE, tmp); -+ -+ return 0; -+} -+ -+static int mpfs_tvs_interval_read(struct mpfs_tvs *data, u32 attr, long *val) -+{ -+ u32 tmp; -+ -+ if (attr != hwmon_chip_update_interval) -+ return -EOPNOTSUPP; -+ -+ regmap_read(data->regmap, MPFS_TVS_CTRL, &tmp); -+ *val = FIELD_GET(MPFS_TVS_INTERVAL_MASK, tmp); -+ *val *= MPFS_TVS_INTERVAL_SCALE; -+ *val = roundup(*val, 1000); -+ *val /= 1000; -+ -+ return 0; -+} -+ -+static int mpfs_tvs_interval_write(struct mpfs_tvs *data, u32 attr, long val) -+{ -+ long temp = val; -+ -+ if (attr != hwmon_chip_update_interval) -+ return -EOPNOTSUPP; -+ -+ temp = clamp(temp, 0, MPFS_TVS_INTERVAL_MAX_MS); -+ -+ temp *= 1000; -+ temp /= MPFS_TVS_INTERVAL_SCALE; -+ -+ temp <<= MPFS_TVS_INTERVAL_OFFSET; -+ regmap_update_bits(data->regmap, MPFS_TVS_CTRL, -+ MPFS_TVS_INTERVAL_MASK, temp); -+ -+ return 0; -+} -+ -+static umode_t mpfs_tvs_is_visible(const void *data, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ if (type == hwmon_chip && attr == hwmon_chip_update_interval) -+ return 0644; -+ -+ if (type == hwmon_temp) { -+ switch (attr) { -+ case hwmon_temp_enable: -+ return 0644; -+ case hwmon_temp_input: -+ case hwmon_temp_label: -+ return 0444; -+ default: -+ return 0; -+ } -+ } -+ -+ if (type == hwmon_in) { -+ switch (attr) { -+ case hwmon_in_enable: -+ return 0644; -+ case hwmon_in_input: -+ case hwmon_in_label: -+ return 0444; -+ default: -+ return 0; -+ } -+ } -+ -+ return 0; -+} -+ -+static int mpfs_tvs_read(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long *val) -+{ -+ struct mpfs_tvs *data = dev_get_drvdata(dev); -+ -+ switch (type) { -+ case hwmon_temp: -+ return mpfs_tvs_temp_read(data, attr, val); -+ case hwmon_in: -+ return mpfs_tvs_voltage_read(data, attr, channel, val); -+ case hwmon_chip: -+ return mpfs_tvs_interval_read(data, attr, val); -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static int mpfs_tvs_write(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long val) -+{ -+ struct mpfs_tvs *data = dev_get_drvdata(dev); -+ -+ switch (type) { -+ case hwmon_temp: -+ return mpfs_tvs_temp_write(data, attr, val); -+ case hwmon_in: -+ return mpfs_tvs_voltage_write(data, attr, channel, val); -+ case hwmon_chip: -+ return mpfs_tvs_interval_write(data, attr, val); -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static int mpfs_tvs_read_labels(struct device *dev, -+ enum hwmon_sensor_types type, -+ u32 attr, int channel, -+ const char **str) -+{ -+ switch (type) { -+ case hwmon_temp: -+ *str = "Die Temp"; -+ return 0; -+ case hwmon_in: -+ *str = mpfs_tvs_voltage_labels[channel]; -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static const struct hwmon_ops mpfs_tvs_ops = { -+ .is_visible = mpfs_tvs_is_visible, -+ .read_string = mpfs_tvs_read_labels, -+ .read = mpfs_tvs_read, -+ .write = mpfs_tvs_write, -+}; -+ -+static const struct hwmon_channel_info *mpfs_tvs_info[] = { -+ HWMON_CHANNEL_INFO(chip, -+ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), -+ HWMON_CHANNEL_INFO(temp, -+ HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_ENABLE), -+ HWMON_CHANNEL_INFO(in, -+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE, -+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE, -+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE), -+ NULL -+}; -+ -+static const struct hwmon_chip_info mpfs_tvs_chip_info = { -+ .ops = &mpfs_tvs_ops, -+ .info = mpfs_tvs_info, -+}; -+ -+static int mpfs_tvs_probe(struct platform_device *pdev) -+{ -+ struct device *hwmon_dev; -+ struct mpfs_tvs *data; -+ -+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->regmap = device_node_to_regmap(pdev->dev.parent->of_node); -+ if (IS_ERR(data->regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(data->regmap), -+ "Failed to find syscon regmap\n"); -+ -+ /* -+ * It's an MMIO regmap with no resources, there's nothing that can fail -+ * and return an error -+ */ -+ regmap_write(data->regmap, MPFS_TVS_CTRL, MPFS_TVS_CTRL_ENABLE_ALL); -+ -+ hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "mpfs_tvs", -+ data, -+ &mpfs_tvs_chip_info, -+ NULL); -+ if (IS_ERR(hwmon_dev)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(hwmon_dev), -+ "hwmon device registration failed.\n"); -+ -+ return 0; -+} -+ -+static struct platform_driver mpfs_tvs_driver = { -+ .probe = mpfs_tvs_probe, -+ .driver = { -+ .name = "mpfs-tvs", -+ }, -+}; -+module_platform_driver(mpfs_tvs_driver); -+ -+MODULE_AUTHOR("Lars Randers "); -+MODULE_DESCRIPTION("PolarFire SoC temperature & voltage sensor driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c ---- a/drivers/hwmon/xgene-hwmon.c -+++ b/drivers/hwmon/xgene-hwmon.c -@@ -133,10 +133,6 @@ static int xgene_hwmon_pcc_rd(struct xgene_hwmon_dev *ctx, u32 *msg) - init_completion(&ctx->rd_complete); - ctx->resp_pending = true; - -- /* Write signature for subspace */ -- WRITE_ONCE(generic_comm_base->signature, -- cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx)); -- - /* Write to the shared command region */ - WRITE_ONCE(generic_comm_base->command, - cpu_to_le16(MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR)); -diff --git a/drivers/hwmon/yogafan.c b/drivers/hwmon/yogafan.c ---- a/drivers/hwmon/yogafan.c -+++ b/drivers/hwmon/yogafan.c -@@ -53,6 +53,7 @@ struct yoga_fan_data { - }; - - /* Specific configurations mapped via DMI */ -+ - static const struct yogafan_config yoga_8bit_fans_cfg = { - .multiplier = 100, - .fan_count = 1, -@@ -71,6 +72,24 @@ static const struct yogafan_config legion_16bit_dual_cfg = { - .paths = { "\\_SB.PCI0.LPC0.EC0.FANS", "\\_SB.PCI0.LPC0.EC0.FA2S" } - }; - -+static const struct yogafan_config loq_15iax9_8bit_dual_cfg = { -+ .multiplier = 100, -+ .fan_count = 2, -+ .paths = { "\\_SB.PC00.LPCB.EC0.FA1S", "\\_SB.PC00.LPCB.EC0.FA2S" } -+}; -+ -+static const struct yogafan_config xiaoxin_8bit_dual_cfg = { -+ .multiplier = 100, -+ .fan_count = 2, -+ .paths = { "\\_SB.PCI0.LPC0.EC0.FANS", "\\_SB.PCI0.LPC0.EC0.FA2S" } -+}; -+ -+static const struct yogafan_config yoga_pro_7_14iah10_cfg = { -+ .multiplier = 100, -+ .fan_count = 1, -+ .paths = { "\\_SB.PC00.LPCB.EC0.FANS", NULL } -+}; -+ - static void apply_rllag_filter(struct yoga_fan_data *data, int idx, long raw_rpm) - { - ktime_t now = ktime_get_boottime(); -@@ -170,6 +189,54 @@ static const struct hwmon_chip_info yoga_fan_chip_info = { - }; - - static const struct dmi_system_id yogafan_quirks[] = { -+ { -+ .ident = "Lenovo LOQ 15IAX9", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "LOQ 15IAX9"), -+ }, -+ .driver_data = (void *)&loq_15iax9_8bit_dual_cfg, -+ }, -+ { -+ .ident = "Lenovo XiaoXin Pro 13ARE 2020", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "XiaoXinPro-13ARE 2020"), -+ }, -+ .driver_data = (void *)&xiaoxin_8bit_dual_cfg, -+ }, -+ { -+ .ident = "Lenovo IdeaPad 3 15ALC6", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "IdeaPad 3 15ALC6"), -+ }, -+ .driver_data = (void *)&ideapad_8bit_fan0_cfg, -+ }, -+ { -+ .ident = "Lenovo Legion Pro 7 16AFR10H", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Legion Pro 7 16AFR10H"), -+ }, -+ .driver_data = (void *)&xiaoxin_8bit_dual_cfg, -+ }, -+ { -+ .ident = "Lenovo Yoga Pro 7 14IAH10", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Yoga Pro 7 14IAH10"), -+ }, -+ .driver_data = (void *)&yoga_pro_7_14iah10_cfg, -+ }, -+ { -+ .ident = "Lenovo Yoga 7 16ARP8", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Yoga 7 16ARP8"), -+ }, -+ .driver_data = (void *)&xiaoxin_8bit_dual_cfg, -+ }, - { - .ident = "Lenovo Yoga", - .matches = { -diff --git a/include/linux/hwmon-sysfs.h b/include/linux/hwmon-sysfs.h ---- a/include/linux/hwmon-sysfs.h -+++ b/include/linux/hwmon-sysfs.h -@@ -15,10 +15,10 @@ struct sensor_device_attribute{ - int index; - }; - #define to_sensor_dev_attr(_dev_attr) \ -- container_of(_dev_attr, struct sensor_device_attribute, dev_attr) -+ container_of_const(_dev_attr, struct sensor_device_attribute, dev_attr) - --#define SENSOR_ATTR(_name, _mode, _show, _store, _index) \ -- { .dev_attr = __ATTR(_name, _mode, _show, _store), \ -+#define SENSOR_ATTR(_name, _mode, _show, _store, _index) \ -+ { .dev_attr = __DEVICE_ATTR(_name, _mode, _show, _store), \ - .index = _index } - - #define SENSOR_ATTR_RO(_name, _func, _index) \ -@@ -49,11 +49,11 @@ struct sensor_device_attribute_2 { - u8 nr; - }; - #define to_sensor_dev_attr_2(_dev_attr) \ -- container_of(_dev_attr, struct sensor_device_attribute_2, dev_attr) -+ container_of_const(_dev_attr, struct sensor_device_attribute_2, dev_attr) - --#define SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index) \ -- { .dev_attr = __ATTR(_name, _mode, _show, _store), \ -- .index = _index, \ -+#define SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index) \ -+ { .dev_attr = __DEVICE_ATTR(_name, _mode, _show, _store), \ -+ .index = _index, \ - .nr = _nr } - - #define SENSOR_ATTR_2_RO(_name, _func, _nr, _index) \ diff --git a/kernel/0740-hwmon-updates.patch.sig b/kernel/0740-hwmon-updates.patch.sig deleted file mode 100644 index 00d8812..0000000 Binary files a/kernel/0740-hwmon-updates.patch.sig and /dev/null differ diff --git a/kernel/0741-hwmon-fixes-1.patch b/kernel/0741-hwmon-fixes-1.patch deleted file mode 100644 index 15533e0..0000000 --- a/kernel/0741-hwmon-fixes-1.patch +++ /dev/null @@ -1,179 +0,0 @@ -diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c ---- a/drivers/hwmon/applesmc.c -+++ b/drivers/hwmon/applesmc.c -@@ -1481,9 +1481,9 @@ static int __init applesmc_init(void) - applesmc_fan_config[smcreg.fan_count] = 0; - applesmc_pwm_config[smcreg.fan_count] = 0; - -- applesmc_info_temp = kzalloc_obj(*applesmc_info_temp, GFP_KERNEL); -- applesmc_info_fan = kzalloc_obj(*applesmc_info_fan, GFP_KERNEL); -- applesmc_info_pwm = kzalloc_obj(*applesmc_info_pwm, GFP_KERNEL); -+ applesmc_info_temp = kzalloc_obj(*applesmc_info_temp); -+ applesmc_info_fan = kzalloc_obj(*applesmc_info_fan); -+ applesmc_info_pwm = kzalloc_obj(*applesmc_info_pwm); - if (!applesmc_info_temp || !applesmc_info_fan || !applesmc_info_pwm) { - ret = -ENOMEM; - goto out_info; -@@ -1498,7 +1498,7 @@ static int __init applesmc_init(void) - applesmc_info_pwm->type = hwmon_pwm; - applesmc_info_pwm->config = applesmc_pwm_config; - -- applesmc_info_arr = kcalloc(4, sizeof(*applesmc_info_arr), GFP_KERNEL); -+ applesmc_info_arr = kzalloc_objs(*applesmc_info_arr, 4); - if (!applesmc_info_arr) { - ret = -ENOMEM; - goto out_info; -@@ -1509,7 +1509,7 @@ static int __init applesmc_init(void) - applesmc_info_arr[2] = applesmc_info_pwm; - applesmc_info_arr[3] = NULL; - -- applesmc_chip = kzalloc_obj(*applesmc_chip, GFP_KERNEL); -+ applesmc_chip = kzalloc_obj(*applesmc_chip); - if (!applesmc_chip) { - ret = -ENOMEM; - goto out_info; -@@ -1519,10 +1519,9 @@ static int __init applesmc_init(void) - applesmc_chip->info = applesmc_info_arr; - - /* Create non-standard fanX_safe attributes group */ -- fan_safe_attrs = kcalloc(smcreg.fan_count, -- sizeof(*fan_safe_attrs), GFP_KERNEL); -- fan_safe_attr_list = kcalloc(smcreg.fan_count + 1, -- sizeof(*fan_safe_attr_list), GFP_KERNEL); -+ fan_safe_attrs = kzalloc_objs(*fan_safe_attrs, smcreg.fan_count); -+ fan_safe_attr_list = kzalloc_objs(*fan_safe_attr_list, -+ smcreg.fan_count + 1); - if (!fan_safe_attrs || !fan_safe_attr_list) { - ret = -ENOMEM; - goto out_info; -diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c ---- a/drivers/hwmon/asus_rog_ryujin.c -+++ b/drivers/hwmon/asus_rog_ryujin.c -@@ -184,6 +184,7 @@ static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd - static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length, - struct completion *status_completion) - { -+ unsigned long flags; - int ret; - - /* -@@ -191,9 +192,9 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i - * completion. Reinit is done because hidraw could have triggered - * the raw event parsing and marked the passed in completion as done. - */ -- spin_lock_bh(&priv->status_report_request_lock); -+ spin_lock_irqsave(&priv->status_report_request_lock, flags); - reinit_completion(status_completion); -- spin_unlock_bh(&priv->status_report_request_lock); -+ spin_unlock_irqrestore(&priv->status_report_request_lock, flags); - - /* Send command for getting data */ - ret = rog_ryujin_write_expanded(priv, cmd, cmd_length); -@@ -421,15 +422,18 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - int size) - { - struct rog_ryujin_data *priv = hid_get_drvdata(hdev); -+ unsigned long flags; - - if (size < 2 || data[0] != RYUJIN_CMD_PREFIX) - return 0; - -+ spin_lock_irqsave(&priv->status_report_request_lock, flags); -+ - if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) { - if (size <= priv->info->temp_offset + 1 || - size <= priv->info->pump_speed_offset + 1 || - size <= priv->info->fan_speed_offset + 1) -- return 0; -+ goto unlock; - - /* Received coolant temp and speeds of pump and internal fan */ - priv->temp_input[0] = data[priv->info->temp_offset] * 1000 + -@@ -443,7 +447,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->cooler_status_received); - } else if (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) { - if (size <= RYUJIN_CONTROLLER_SPEED_3 + 1) -- return 0; -+ goto unlock; - - /* Received speeds of four fans attached to the controller */ - priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1); -@@ -455,7 +459,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->controller_status_received); - } else if (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) { - if (size <= RYUJIN_INTERNAL_FAN_DUTY) -- return 0; -+ goto unlock; - - /* Received report for pump and internal fan duties (in %) */ - if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) { -@@ -474,7 +478,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - * We're expecting a report, so parse it. - */ - goto read_cooler_duty; -- return 0; -+ goto unlock; - } - read_cooler_duty: - priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]); -@@ -484,7 +488,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->cooler_duty_received); - } else if (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) { - if (size <= RYUJIN_CONTROLLER_DUTY) -- return 0; -+ goto unlock; - - /* Received report for controller duty for fans (in PWM) */ - if (data[RYUJIN_CONTROLLER_DUTY] == 0) { -@@ -503,7 +507,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - * We're expecting a report, so parse it. - */ - goto read_controller_duty; -- return 0; -+ goto unlock; - } - read_controller_duty: - priv->duty_input[2] = data[RYUJIN_CONTROLLER_DUTY]; -@@ -512,6 +516,8 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo - complete_all(&priv->controller_duty_received); - } - -+unlock: -+ spin_unlock_irqrestore(&priv->status_report_request_lock, flags); - return 0; - } - -diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c ---- a/drivers/hwmon/hwmon.c -+++ b/drivers/hwmon/hwmon.c -@@ -318,6 +318,11 @@ static int hwmon_attr_base(enum hwmon_sensor_types type) - return 1; - } - -+static bool is_hwmon_device(struct device *dev) -+{ -+ return dev->class == &hwmon_class; -+} -+ - #if IS_REACHABLE(CONFIG_I2C) - - /* -@@ -338,7 +343,7 @@ static int hwmon_attr_base(enum hwmon_sensor_types type) - - static int hwmon_match_device(struct device *dev, const void *data) - { -- return dev->class == &hwmon_class; -+ return is_hwmon_device(dev); - } - - static ssize_t pec_show(struct device *dev, const struct device_attribute *dummy, -@@ -781,6 +786,9 @@ int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type, - const char *template; - int base; - -+ if (WARN(!is_hwmon_device(dev), "%s is not a hardware monitoring device\n", -+ dev_name(dev))) -+ return -EINVAL; - if (type >= ARRAY_SIZE(__templates)) - return -EINVAL; - if (attr >= __templates_size[type]) diff --git a/kernel/0741-hwmon-fixes-1.patch.sig b/kernel/0741-hwmon-fixes-1.patch.sig deleted file mode 100644 index 76f3485..0000000 Binary files a/kernel/0741-hwmon-fixes-1.patch.sig and /dev/null differ diff --git a/kernel/0742-hwmon-fixes-2.patch b/kernel/0742-hwmon-fixes-2.patch deleted file mode 100644 index 9552822..0000000 --- a/kernel/0742-hwmon-fixes-2.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c ---- a/drivers/hwmon/k10temp.c -+++ b/drivers/hwmon/k10temp.c -@@ -523,7 +523,7 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) - } - } else if (boot_cpu_data.x86 == 0x1a) { - switch (boot_cpu_data.x86_model) { -- case 0x00 ... 0x2f: /* Zen5 Turin */ -+ case 0x00 ... 0x1f: /* Zen5 Turin */ - data->ccd_offset = 0x1F0; - k10temp_get_ccd_support(data, 16); - break; diff --git a/kernel/0742-hwmon-fixes-2.patch.sig b/kernel/0742-hwmon-fixes-2.patch.sig deleted file mode 100644 index dcf7ede..0000000 Binary files a/kernel/0742-hwmon-fixes-2.patch.sig and /dev/null differ diff --git a/kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch b/kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch deleted file mode 100644 index da85b37..0000000 --- a/kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c ---- a/drivers/acpi/power.c -+++ b/drivers/acpi/power.c -@@ -1121,6 +1121,19 @@ static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "ZERO"), - } - -+ }, -+ { -+ /* -+ * Acer Swift 3 SF314-56G with NVIDIA MX250 suffers from the -+ * same ACPI power resource regression as the Thunderobot ZERO. -+ * The power resource controlling the dGPU is incorrectly turned off -+ * during initialization, causing the GPU to fall off the bus (D3cold). -+ */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Swift SF314-56G"), -+ } -+ - }, - {} - }; diff --git a/kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch.sig b/kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch.sig deleted file mode 100644 index 281de72..0000000 Binary files a/kernel/0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch.sig and /dev/null differ diff --git a/kernel/0800-platform-updates.patch b/kernel/0800-platform-updates.patch deleted file mode 100644 index c6018e3..0000000 --- a/kernel/0800-platform-updates.patch +++ /dev/null @@ -1,8290 +0,0 @@ -diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h ---- a/arch/x86/include/uapi/asm/amd_hsmp.h -+++ b/arch/x86/include/uapi/asm/amd_hsmp.h -@@ -53,9 +53,21 @@ enum hsmp_message_ids { - HSMP_SET_XGMI_PSTATE_RANGE, /* 26h Set xGMI P-state range */ - HSMP_CPU_RAIL_ISO_FREQ_POLICY, /* 27h Get/Set Cpu Iso frequency policy */ - HSMP_DFC_ENABLE_CTRL, /* 28h Enable/Disable DF C-state */ -+ HSMP_PC6_ENABLE, /* 29h Get/Set PC6 enable/disable status */ -+ HSMP_CC6_ENABLE, /* 2Ah Get/Set CC6 enable/disable status */ - HSMP_GET_RAPL_UNITS = 0x30, /* 30h Get scaling factor for energy */ - HSMP_GET_RAPL_CORE_COUNTER, /* 31h Get core energy counter value */ - HSMP_GET_RAPL_PACKAGE_COUNTER, /* 32h Get package energy counter value */ -+ HSMP_DIMM_SB_RD, /* 33h Get DIMM sideband data */ -+ HSMP_READ_CCD_POWER, /* 34h Get average CCD power */ -+ HSMP_READ_TDELTA, /* 35h Get thermal behaviour */ -+ HSMP_GET_SVI3_VR_CTRL_TEMP, /* 36h Get SVI3 VR controller rail temp */ -+ HSMP_GET_ENABLED_HSMP_CMDS, /* 37h Get supported HSMP commands */ -+ HSMP_SET_GET_FLOOR_LIMIT, /* 38h Get/Set core floor frequency limit */ -+ HSMP_DIMM_SB_WR, /* 39h Set DIMM sideband data */ -+ HSMP_SDPS_LIMIT, /* 3Ah Get/Set SDPS limit */ -+ HSMP_PQOS_TRAFFIC_PRIORITY, /* 3Bh Get/Set traffic priority */ -+ HSMP_PQOS_FLOATING_BW, /* 3Ch Get/Set max floating bandwidth */ - HSMP_MSG_ID_MAX, - }; - -@@ -170,16 +182,27 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] - {0, 1, HSMP_GET}, - - /* -- * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0 -- * input: args[0] = min link width[15:8] + max link width[7:0] -+ * HSMP_SET_XGMI_LINK_WIDTH, num_args = 1, response_sz = 0/1 -+ * input: args[0] = set/get XGMI Link width[31] (0 = set, 1 = get) + -+ * min link width[15:8] + max link width[7:0] -+ * Link width encoding: 0 = x4, 1 = x8, 2 = x16. -+ * On SET, max must be >= min. On GET, [15:0] are reserved. -+ * output: args[0] = reserved[31:16] + min link width[15:8] + -+ * max link width[7:0] - */ -- {1, 0, HSMP_SET}, -+ {1, 1, HSMP_SET_GET}, - - /* -- * HSMP_SET_DF_PSTATE, num_args = 1, response_sz = 0 -- * input: args[0] = df pstate[7:0] -+ * HSMP_SET_DF_PSTATE (APBDisable), num_args = 1, response_sz = 0/1 -+ * input: args[0] = set APB_DISABLE / get APB state[31] -+ * (0 = set & lock DF P-state, 1 = get) + -+ * reserved[30:8] + -+ * DF P-state[7:0] (0..2; reserved on GET) -+ * output: args[0] = reserved[31:9] + -+ * APB state[8] (1 = disabled, 0 = enabled) + -+ * locked DF P-state[7:0] if [8] = 1, else reserved - */ -- {1, 0, HSMP_SET}, -+ {1, 1, HSMP_SET_GET}, - - /* HSMP_SET_AUTO_DF_PSTATE, num_args = 0, response_sz = 0 */ - {0, 0, HSMP_SET}, -@@ -305,16 +328,32 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] - {1, 1, HSMP_SET}, - - /* -- * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0 -- * input: args[0] = power efficiency mode[2:0] -+ * HSMP_SET_POWER_MODE (PwrEfficiencyModeSelection), -+ * num_args = 1, response_sz = 1 -+ * input: args[0] = set/get policy[31] (0 = set, 1 = get) + -+ * high util point[30:24] + -+ * low util point[23:17] + -+ * PPT limit[16:5] + -+ * reserved[4:3] + mode selection[2:0] -+ * [30:5] are valid only when [2:0] is a balanced core mode -+ * (4 or 5). [2:0] is reserved when getting (bit[31] = 1). -+ * output: args[0] same layout, [31] reserved, [2:0] = arbitrated -+ * current efficiency mode. - */ - {1, 1, HSMP_SET_GET}, - - /* -- * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0 -- * input: args[0] = min df pstate[15:8] + max df pstate[7:0] -+ * HSMP_SET_PSTATE_MAX_MIN (DfPstateRange), num_args = 1, response_sz = 0/1 -+ * input: args[0] = set/get DF P-state range[31] (0 = set, 1 = get) + -+ * reserved[30:16] + -+ * min DF P-state[15:8] + max DF P-state[7:0] -+ * DF P-state encoding: 0 = DFP0 (high performance), -+ * 1 = DFP1, 2 = DFP2 (low performance). -+ * [15:0] are reserved when getting (args[0] bit[31] = 1). -+ * output: args[0] = reserved[31:16] + min DF P-state[15:8] + -+ * max DF P-state[7:0] - */ -- {1, 0, HSMP_SET}, -+ {1, 1, HSMP_SET_GET}, - - /* - * HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1 -@@ -328,11 +367,12 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] - {0, 0, HSMP_GET}, - - /* -- * HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 2 -+ * HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 3 - * output: args[0] = lower 32 bits of the address - * output: args[1] = upper 32 bits of the address -+ * output: args[2] = DRAM region size in bytes - */ -- {0, 2, HSMP_GET}, -+ {0, 3, HSMP_GET}, - - /* - * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0 -@@ -355,9 +395,31 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] - */ - {1, 1, HSMP_SET_GET}, - -- /* RESERVED(0x29-0x2f) */ -- {0, 0, HSMP_RSVD}, -- {0, 0, HSMP_RSVD}, -+ /* -+ * HSMP_PC6_ENABLE (Pc6Enable), num_args = 1, response_sz = 0/1 -+ * input: args[0] = set/get PC6 control[31] (0 = set, 1 = get) + -+ * reserved[30:1] + -+ * enable PC6[0] (0 = disable, 1 = enable; -+ * reserved on GET) -+ * output: args[0] = reserved[31:1] + current PC6 control[0] -+ * (last value configured via HSMP or APML) -+ */ -+ {1, 1, HSMP_SET_GET}, -+ -+ /* -+ * HSMP_CC6_ENABLE (CC6Enable), num_args = 1, response_sz = 0/1 -+ * Configures CC6 enable for all cores; changing the setting does -+ * not by itself transition cores in or out of CC6. -+ * input: args[0] = set/get CC6 control[31] (0 = set, 1 = get) + -+ * reserved[30:1] + -+ * enable CC6[0] (0 = disable, 1 = enable; -+ * reserved on GET) -+ * output: args[0] = reserved[31:1] + current CC6 control[0] -+ * (last value configured via HSMP or APML) -+ */ -+ {1, 1, HSMP_SET_GET}, -+ -+ /* RESERVED(0x2B-0x2F) */ - {0, 0, HSMP_RSVD}, - {0, 0, HSMP_RSVD}, - {0, 0, HSMP_RSVD}, -@@ -385,6 +447,89 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] - */ - {0, 2, HSMP_GET}, - -+ /* -+ * HSMP_DIMM_SB_RD, num_args = 1, response_sz = 1 -+ * input: args[0] = reg space[23] + reg offset[22:12] + -+ * device LID[11:8] + DIMM address[7:0] -+ * output: args[0] = read data byte[3:0] -+ */ -+ {1, 1, HSMP_GET}, -+ -+ /* -+ * HSMP_READ_CCD_POWER, num_args = 1, response_sz = 1 -+ * input: args[0] = apic id of core[15:0] -+ * output: args[0] = CCD power(mWatts)[31:0] -+ */ -+ {1, 1, HSMP_GET}, -+ -+ /* -+ * HSMP_READ_TDELTA, num_args = 0, response_sz = 1 -+ * output: args[0] = thermal behaviour[31:0] -+ */ -+ {0, 1, HSMP_GET}, -+ -+ /* -+ * HSMP_GET_SVI3_VR_CTRL_TEMP, num_args = 1, response_sz = 1 -+ * input: args[0] = SVI3 rail index[3:1] + read temperature[0] -+ * output: args[0] = SVI3 rail index[30:28] + -+ * rail temperature in degree C[27:0] -+ */ -+ {1, 1, HSMP_GET}, -+ -+ /* -+ * HSMP_GET_ENABLED_HSMP_CMDS, num_args = 1, response_sz = 3 -+ * input: args[0] = HSMP command mask[0] -+ * output: status of HSMP command = args[0], args[1], args[2] -+ */ -+ {1, 3, HSMP_GET}, -+ -+ /* -+ * HSMP_SET_GET_FLOOR_LIMIT, num_args = 1, response_sz = 1 -+ * input: args[0] = op[31:30] + reserved[29:28] + -+ * apic id[27:16] + floor frequency MHz[15:0] -+ * op encoding: 00 = set per-core floor, -+ * 01 = set all-cores floor (apic id reserved), -+ * 10 = get per-core floor, -+ * 11 = get per-core effective floor. -+ * Floor frequency field is reserved on GET (bit[31] = 1). -+ * output: args[0] = floor frequency MHz[15:0] -+ * (effective for op 11, configured for op 10; -+ * reserved on SET) -+ */ -+ {1, 1, HSMP_SET_GET}, -+ -+ /* -+ * HSMP_DIMM_SB_WR, num_args = 1, response_sz = 0 -+ * input: args[0] = write data[31:24] + reg space[23] + -+ * reg offset[22:12] + device LID[11:8] + -+ * DIMM address[7:0] -+ */ -+ {1, 0, HSMP_SET}, -+ -+ /* -+ * HSMP_SDPS_LIMIT, num_args = 1, response_sz = 1 -+ * input: args[0] = set/get SDPS limit[31] (0 = set, 1 = get) + -+ * SDPS limit[30:0] -+ * output: args[0] = SDPS limit[30:0] -+ */ -+ {1, 1, HSMP_SET_GET}, -+ -+ /* -+ * HSMP_PQOS_TRAFFIC_PRIORITY, num_args = 1, response_sz = 1 -+ * input: args[0] = op[31:30] + priority sel[27:26] + -+ * priority val[21:20] + input[19:0] -+ * output: args[0] = supported priorities or priority val[1:0] -+ */ -+ {1, 1, HSMP_SET_GET}, -+ -+ /* -+ * HSMP_PQOS_FLOATING_BW, num_args = 1, response_sz = 2 -+ * input: args[0] = op[31] + sub-op[30:29] + params[28:0] -+ * output: args[0] = discovery bits or floating/global memory BW (Gbps) -+ * output: args[1] = reserved or config (drop adj, sampling delay, -+ * hysteresis) -+ */ -+ {1, 2, HSMP_SET_GET}, - }; - - /* Metrics table (supported only with proto version 6) */ -@@ -467,6 +612,39 @@ struct hsmp_metric_table { - __u32 gfxclk_frequency[8]; - }; - -+/** -+ * struct hsmp_telemetry_data - Request descriptor for HSMP telemetry IOCTL -+ * @buf: Input. Userspace pointer (encoded as __u64 to keep the layout -+ * stable between 32-bit and 64-bit callers) to the destination -+ * buffer that receives the metric table. -+ * @size: Input. Size in bytes of the buffer pointed to by @buf, and the -+ * number of bytes copied out on success. Must be non-zero and no -+ * larger than the metric table size firmware reports for this -+ * socket; a larger value is rejected with -EINVAL rather than -+ * short-written. A smaller value returns the leading @size bytes -+ * of the snapshot. The kernel does not write this field back. -+ * @sock_ind: Input. Socket index from which the metric table is read. -+ * @reserved: Reserved for future use. Callers should set this to zero; -+ * future kernels may begin interpreting the field, so passing -+ * a non-zero value today is not forwards compatible. -+ * -+ * Placing @buf first lets all fields fall on their natural alignment under -+ * the surrounding #pragma pack(4), so the struct is a tight 16 bytes with -+ * the same wire layout on 32-bit and 64-bit userspace. -+ * -+ * The metric table layout depends on the HSMP protocol version reported by -+ * firmware, which userspace can read from the protocol_version sysfs -+ * attribute. Protocol version 6 uses struct hsmp_metric_table, so callers on -+ * that version pass sizeof(struct hsmp_metric_table). Later version metrics -+ * table layout is documented in the Public PPR. -+ */ -+struct hsmp_telemetry_data { -+ __u64 buf; -+ __u32 size; -+ __u16 sock_ind; -+ __u16 reserved; -+}; -+ - /* Reset to default packing */ - #pragma pack() - -@@ -474,4 +652,16 @@ struct hsmp_metric_table { - #define HSMP_BASE_IOCTL_NR 0xF8 - #define HSMP_IOCTL_CMD _IOWR(HSMP_BASE_IOCTL_NR, 0, struct hsmp_message) - -+/* -+ * Fetch the firmware metric (telemetry) table for a given socket via the -+ * HSMP character device. This avoids the PAGE_SIZE limitation of the -+ * sysfs binary attribute path for tables larger than one page (such as the -+ * ~13 KB table used by HSMP protocol version 7). -+ * -+ * The direction is _IOW because the kernel only reads the request struct; -+ * the table itself is written to the buffer that @buf points at. -+ */ -+#define HSMP_IOCTL_GET_TELEMETRY_DATA \ -+ _IOW(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data) -+ - #endif /*_ASM_X86_AMD_HSMP_H_*/ -diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c ---- a/arch/x86/platform/olpc/olpc-xo15-sci.c -+++ b/arch/x86/platform/olpc/olpc-xo15-sci.c -@@ -18,8 +18,6 @@ - - #define DRV_NAME "olpc-xo15-sci" - #define PFX DRV_NAME ": " --#define XO15_SCI_CLASS DRV_NAME --#define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI" - - static unsigned long xo15_sci_gpe; - static bool lid_wake_on_close; -@@ -148,9 +146,6 @@ static int xo15_sci_probe(struct platform_device *pdev) - if (!device) - return -ENODEV; - -- strscpy(acpi_device_name(device), XO15_SCI_DEVICE_NAME); -- strscpy(acpi_device_class(device), XO15_SCI_CLASS); -- - /* Get GPE bit assignment (EC events). */ - status = acpi_evaluate_integer(device->handle, "_GPE", NULL, &tmp); - if (ACPI_FAILURE(status)) -diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c ---- a/drivers/char/sonypi.c -+++ b/drivers/char/sonypi.c -@@ -1125,8 +1125,6 @@ static int sonypi_acpi_probe(struct platform_device *pdev) - return -ENODEV; - - sonypi_acpi_device = device; -- strscpy(acpi_device_name(device), "Sony laptop hotkeys"); -- strscpy(acpi_device_class(device), "sony/hotkey"); - return 0; - } - -diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c ---- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c -+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c -@@ -7,6 +7,7 @@ - * - * Author: Basavaraj Natikar - */ -+#include - #include - #include - #include -@@ -102,20 +103,20 @@ static int amd_sfh_mode_info(u32 *platform_type, u32 *laptop_placement) - *platform_type = mode.op_mode.devicemode; - - if (mode.op_mode.ontablestate == 1) { -- *laptop_placement = ON_TABLE; -+ *laptop_placement = AMD_PMF_ON_TABLE; - } else if (mode.op_mode.ontablestate == 2) { -- *laptop_placement = ON_LAP_MOTION; -+ *laptop_placement = AMD_PMF_ON_LAP_MOTION; - } else if (mode.op_mode.inbagstate == 1) { -- *laptop_placement = IN_BAG; -+ *laptop_placement = AMD_PMF_IN_BAG; - } else if (mode.op_mode.outbagstate == 1) { -- *laptop_placement = OUT_OF_BAG; -+ *laptop_placement = AMD_PMF_OUT_OF_BAG; - } else if (mode.op_mode.ontablestate == 0 || mode.op_mode.inbagstate == 0 || - mode.op_mode.outbagstate == 0) { -- *laptop_placement = LP_UNKNOWN; -+ *laptop_placement = AMD_PMF_LP_UNKNOWN; - pr_warn_once("Unknown laptop placement\n"); - } else if (mode.op_mode.ontablestate == 3 || mode.op_mode.inbagstate == 3 || - mode.op_mode.outbagstate == 3) { -- *laptop_placement = LP_UNDEFINED; -+ *laptop_placement = AMD_PMF_LP_UNDEFINED; - pr_warn_once("Undefined laptop placement\n"); - } - -diff --git a/drivers/platform/surface/surface_aggregator_hub.c b/drivers/platform/surface/surface_aggregator_hub.c ---- a/drivers/platform/surface/surface_aggregator_hub.c -+++ b/drivers/platform/surface/surface_aggregator_hub.c -@@ -348,8 +348,13 @@ static const struct ssam_hub_desc kip_hub = { - /* -- Driver registration. -------------------------------------------------- */ - - static const struct ssam_device_id ssam_hub_match[] = { -- { SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub }, -- { SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub }, -+ { -+ SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_KIP, 0x00), -+ .driver_data = (unsigned long)&kip_hub, -+ }, { -+ SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_BAS, 0x00), -+ .driver_data = (unsigned long)&base_hub, -+ }, - { } - }; - MODULE_DEVICE_TABLE(ssam, ssam_hub_match); -diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c ---- a/drivers/platform/surface/surface_aggregator_tabletsw.c -+++ b/drivers/platform/surface/surface_aggregator_tabletsw.c -@@ -622,8 +622,13 @@ static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = { - /* -- Driver registration. -------------------------------------------------- */ - - static const struct ssam_device_id ssam_tablet_sw_match[] = { -- { SSAM_SDEV(KIP, SAM, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc }, -- { SSAM_SDEV(POS, SAM, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc }, -+ { -+ SSAM_SDEV(KIP, SAM, 0x00, 0x01), -+ .driver_data = (unsigned long)&ssam_kip_sw_desc, -+ }, { -+ SSAM_SDEV(POS, SAM, 0x00, 0x01), -+ .driver_data = (unsigned long)&ssam_pos_sw_desc, -+ }, - { }, - }; - MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match); -diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c ---- a/drivers/platform/surface/surfacepro3_button.c -+++ b/drivers/platform/surface/surfacepro3_button.c -@@ -20,7 +20,6 @@ - #define SURFACE_PRO3_BUTTON_HID "MSHW0028" - #define SURFACE_PRO4_BUTTON_HID "MSHW0040" - #define SURFACE_BUTTON_OBJ_NAME "VGBI" --#define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons" - - #define MSHW0040_DSM_REVISION 0x01 - #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision -@@ -212,11 +211,10 @@ static int surface_button_probe(struct platform_device *pdev) - goto err_free_button; - } - -- strscpy(acpi_device_name(device), SURFACE_BUTTON_DEVICE_NAME); - snprintf(button->phys, sizeof(button->phys), "%s/buttons", - acpi_device_hid(device)); - -- input->name = acpi_device_name(device); -+ input->name = "Surface Pro 3/4 Buttons"; - input->phys = button->phys; - input->id.bustype = BUS_HOST; - input->dev.parent = &pdev->dev; -@@ -239,8 +237,8 @@ static int surface_button_probe(struct platform_device *pdev) - goto err_free_button; - } - -- dev_info(&pdev->dev, "%s [%s]\n", acpi_device_name(device), -- acpi_device_bid(device)); -+ dev_info(&pdev->dev, "%s [%s]\n", input->name, acpi_device_bid(device)); -+ - return 0; - - err_free_input: -diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig ---- a/drivers/platform/x86/Kconfig -+++ b/drivers/platform/x86/Kconfig -@@ -802,7 +802,6 @@ config LG_LAPTOP - tristate "LG Laptop Extras" - depends on ACPI - depends on ACPI_BATTERY -- depends on ACPI_WMI - depends on INPUT - select INPUT_SPARSEKMAP - select NEW_LEDS -diff --git a/drivers/platform/x86/amd/Kconfig b/drivers/platform/x86/amd/Kconfig ---- a/drivers/platform/x86/amd/Kconfig -+++ b/drivers/platform/x86/amd/Kconfig -@@ -34,6 +34,17 @@ config AMD_WBRF - This mechanism will only be activated on platforms that advertise a - need for it. - -+config AMD_HALO_LED -+ tristate "AMD Halo Box RGB LED Driver" -+ depends on ACPI_WMI && LEDS_CLASS_MULTICOLOR -+ help -+ This driver provides RGB LED control for AMD Halo Box devices -+ through the LED multicolor subsystem. The Halo Box light bar can -+ be controlled via sysfs to display any RGB color combination. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called amd_halo_led. -+ - config AMD_ISP_PLATFORM - tristate "AMD ISP4 platform driver" - depends on I2C && X86_64 && ACPI -diff --git a/drivers/platform/x86/amd/Makefile b/drivers/platform/x86/amd/Makefile ---- a/drivers/platform/x86/amd/Makefile -+++ b/drivers/platform/x86/amd/Makefile -@@ -10,5 +10,6 @@ obj-$(CONFIG_AMD_PMC) += pmc/ - obj-$(CONFIG_AMD_HSMP) += hsmp/ - obj-$(CONFIG_AMD_PMF) += pmf/ - obj-$(CONFIG_AMD_WBRF) += wbrf.o -+obj-$(CONFIG_AMD_HALO_LED) += amd_halo_led.o - obj-$(CONFIG_AMD_ISP_PLATFORM) += amd_isp4.o - obj-$(CONFIG_AMD_HFI) += hfi/ -diff --git a/drivers/platform/x86/amd/amd_halo_led.c b/drivers/platform/x86/amd/amd_halo_led.c -new file mode 100644 ---- /dev/null -+++ b/drivers/platform/x86/amd/amd_halo_led.c -@@ -0,0 +1,315 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * AMD Halo Box RGB LED Driver -+ * -+ * Copyright (C) 2026 Advanced Micro Devices, Inc. -+ * -+ * This driver provides RGB LED control for AMD Halo Box devices through -+ * the LED multicolor subsystem. The Halo Box light bar can be controlled -+ * via sysfs to display any RGB color combination. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define AMD_HALO_GUID "081E747B-E028-4232-AF24-EAAEAB2B1E86" -+ -+/* WMI method IDs from MOF */ -+enum { -+ AMD_HALO_WMI_TURN_OFF = 0x04, -+ AMD_HALO_WMI_RGB = 0x07, -+}; -+ -+/* Arg0 of the AMD_HALO_WMI_RGB Method */ -+enum { -+ AMD_HALO_RGB_CMD_GET = 0x0, -+ AMD_HALO_RGB_CMD_SET = 0x1, -+}; -+ -+/* Status codes from spec */ -+#define AMD_HALO_STATUS_SUCCESS 0x0000 -+#define AMD_HALO_STATUS_INVALID_PARAM 0xFFFD -+ -+/* Brightness uses 0-100 range */ -+#define AMD_HALO_MAX_HW_BRIGHTNESS 100 -+ -+/** -+ * struct amd_halo_led_data - Driver private data -+ * @wdev: WMI device pointer -+ * @led_mc: LED multicolor class device -+ * @subled_info: RGB channel information -+ * @lock: Mutex to protect WMI calls -+ */ -+struct amd_halo_led_data { -+ struct wmi_device *wdev; -+ struct led_classdev_mc led_mc; -+ struct mc_subled subled_info[3]; -+ struct mutex lock; -+}; -+ -+struct amd_halo_wmi_args { -+ __le32 arg0; -+ __le32 arg1; -+}; -+ -+struct amd_halo_wmi_args_rgb { -+ __le32 cmd; -+ __le32 red; -+ __le32 green; -+ __le32 blue; -+}; -+ -+struct amd_halo_wmi_output_rgb { -+ __le16 status; -+ u8 red; -+ u8 green; -+ u8 blue; -+} __packed; -+ -+static inline int wmi_status_to_err(u16 status) -+{ -+ switch (status) { -+ case AMD_HALO_STATUS_SUCCESS: -+ return 0; -+ case AMD_HALO_STATUS_INVALID_PARAM: -+ return -EINVAL; -+ default: -+ return -EIO; -+ } -+} -+ -+static int __amd_halo_wmi_call(struct wmi_device *wdev, -+ u32 method_id, void *data, size_t length) -+{ -+ struct wmi_buffer input = { -+ .length = length, -+ .data = data, -+ }; -+ struct wmi_buffer output = { }; -+ int ret; -+ -+ /* Return buffer per spec: Bytes[0:1] = Status (little-endian) */ -+ ret = wmidev_invoke_method(wdev, 0, method_id, -+ &input, &output, sizeof(__le16)); -+ if (ret) -+ return ret; -+ -+ __le16 *result_status __free(kfree) = output.data; -+ -+ return wmi_status_to_err(le16_to_cpu(*result_status)); -+} -+ -+/** -+ * amd_halo_wmi_turn_off - Turn off all LED channels -+ * @wdev: WMI device pointer -+ * -+ * Return: 0 on success, negative error code on failure -+ */ -+static int amd_halo_wmi_turn_off(struct wmi_device *wdev) -+{ -+ struct amd_halo_wmi_args args = { }; -+ -+ return __amd_halo_wmi_call(wdev, AMD_HALO_WMI_TURN_OFF, &args, sizeof(args)); -+} -+ -+/** -+ * amd_halo_wmi_set_rgb - Set all RGB channels atomically -+ * @wdev: WMI device pointer -+ * @r: brightness for red channel (0 - 100) -+ * @g: brightness for green channel (0 - 100) -+ * @b: brightness for blue channel (0 - 100) -+ * -+ * Return: 0 on success, negative error code on failure -+ */ -+static int amd_halo_wmi_set_rgb(struct wmi_device *wdev, u32 r, u32 g, u32 b) -+{ -+ struct amd_halo_wmi_args_rgb args = { -+ .cmd = cpu_to_le32(AMD_HALO_RGB_CMD_SET), -+ .red = cpu_to_le32(r), -+ .green = cpu_to_le32(g), -+ .blue = cpu_to_le32(b), -+ }; -+ -+ if (r > AMD_HALO_MAX_HW_BRIGHTNESS || -+ g > AMD_HALO_MAX_HW_BRIGHTNESS || -+ b > AMD_HALO_MAX_HW_BRIGHTNESS) { -+ return -EINVAL; -+ } -+ -+ return __amd_halo_wmi_call(wdev, AMD_HALO_WMI_RGB, &args, sizeof(args)); -+} -+ -+/** -+ * amd_halo_wmi_get_rgb - Get RGB values -+ * @wdev: WMI device pointer -+ * @r: output buffer for red value -+ * @g: output buffer for green value -+ * @b: output buffer for blue value -+ * -+ * Return: 0 on success, negative error code on failure -+ */ -+static int amd_halo_wmi_get_rgb(struct wmi_device *wdev, u8 *r, u8 *g, u8 *b) -+{ -+ struct amd_halo_wmi_args_rgb args = { -+ .cmd = cpu_to_le32(AMD_HALO_RGB_CMD_GET), -+ }; -+ struct wmi_buffer input = { -+ .length = sizeof(args), -+ .data = &args, -+ }; -+ struct wmi_buffer output = { }; -+ int ret; -+ -+ ret = wmidev_invoke_method(wdev, 0, AMD_HALO_WMI_RGB, -+ &input, &output, sizeof(struct amd_halo_wmi_output_rgb)); -+ if (ret) -+ return ret; -+ -+ struct amd_halo_wmi_output_rgb *data __free(kfree) = output.data; -+ -+ ret = wmi_status_to_err(le16_to_cpu(data->status)); -+ if (ret) -+ return ret; -+ -+ if (data->red > AMD_HALO_MAX_HW_BRIGHTNESS || -+ data->green > AMD_HALO_MAX_HW_BRIGHTNESS || -+ data->blue > AMD_HALO_MAX_HW_BRIGHTNESS) { -+ return -EPROTO; -+ } -+ -+ *r = data->red; -+ *g = data->green; -+ *b = data->blue; -+ -+ return 0; -+} -+ -+/** -+ * amd_halo_brightness_set - Set LED brightness -+ * @cdev: LED class device -+ * @brightness: Brightness value -+ * -+ * Return: 0 on success, negative error code on failure -+ */ -+static int amd_halo_brightness_set(struct led_classdev *cdev, -+ enum led_brightness brightness) -+{ -+ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); -+ struct amd_halo_led_data *data = container_of(mc_cdev, -+ struct amd_halo_led_data, -+ led_mc); -+ u32 red_hw, green_hw, blue_hw; -+ int ret; -+ -+ guard(mutex)(&data->lock); -+ -+ led_mc_calc_color_components(mc_cdev, brightness); -+ -+ if (brightness == 0) -+ return amd_halo_wmi_turn_off(data->wdev); -+ -+ red_hw = mc_cdev->subled_info[0].brightness; -+ green_hw = mc_cdev->subled_info[1].brightness; -+ blue_hw = mc_cdev->subled_info[2].brightness; -+ -+ ret = amd_halo_wmi_set_rgb(data->wdev, red_hw, green_hw, blue_hw); -+ if (ret) -+ goto out; -+ -+ return 0; -+ -+out: -+ /* -+ * Consider the light bar non-functional if AMD_HALO_WMI_RGB failed. -+ * Attempt to turn the LED off completely as clean-up. -+ */ -+ if (amd_halo_wmi_turn_off(data->wdev)) -+ dev_warn_ratelimited(&data->wdev->dev, "Failed to turn LED off on cleanup\n"); -+ -+ return ret; -+} -+ -+static int amd_halo_probe(struct wmi_device *wdev, const void *context) -+{ -+ struct led_init_data led_init_data = { -+ .devicename = "amd_halo", -+ .default_label = "multicolor:" LED_FUNCTION_STATUS, -+ .devname_mandatory = true, -+ }; -+ struct amd_halo_led_data *data; -+ u8 r, g, b; -+ int ret; -+ -+ data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ ret = devm_mutex_init(&wdev->dev, &data->lock); -+ if (ret) -+ return ret; -+ -+ data->wdev = wdev; -+ dev_set_drvdata(&wdev->dev, data); -+ -+ data->subled_info[0].color_index = LED_COLOR_ID_RED; -+ data->subled_info[1].color_index = LED_COLOR_ID_GREEN; -+ data->subled_info[2].color_index = LED_COLOR_ID_BLUE; -+ -+ data->led_mc.led_cdev.brightness = AMD_HALO_MAX_HW_BRIGHTNESS; -+ data->led_mc.led_cdev.max_brightness = AMD_HALO_MAX_HW_BRIGHTNESS; -+ data->led_mc.led_cdev.brightness_set_blocking = amd_halo_brightness_set; -+ data->led_mc.led_cdev.flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN; -+ data->led_mc.num_colors = ARRAY_SIZE(data->subled_info); -+ data->led_mc.subled_info = data->subled_info; -+ -+ ret = amd_halo_wmi_get_rgb(wdev, &r, &g, &b); -+ if (ret) -+ return ret; -+ -+ data->subled_info[0].intensity = r; -+ data->subled_info[1].intensity = g; -+ data->subled_info[2].intensity = b; -+ -+ ret = devm_led_classdev_multicolor_register_ext(&wdev->dev, &data->led_mc, -+ &led_init_data); -+ if (ret) -+ return dev_err_probe(&wdev->dev, ret, -+ "Failed to register multicolor LED\n"); -+ return 0; -+} -+ -+static const struct wmi_device_id amd_halo_id_table[] = { -+ { .guid_string = AMD_HALO_GUID }, -+ { } -+}; -+MODULE_DEVICE_TABLE(wmi, amd_halo_id_table); -+ -+static struct wmi_driver amd_halo_driver = { -+ .driver = { -+ .name = "amd_halo_led", -+ }, -+ .id_table = amd_halo_id_table, -+ .probe = amd_halo_probe, -+ .no_singleton = true, -+}; -+ -+module_wmi_driver(amd_halo_driver); -+ -+MODULE_AUTHOR("Mario Limonciello (AMD) "); -+MODULE_AUTHOR("Yo-Jung Leo Lin (AMD) "); -+MODULE_DESCRIPTION("AMD Halo Box RGB LED Control Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c ---- a/drivers/platform/x86/amd/hsmp/acpi.c -+++ b/drivers/platform/x86/amd/hsmp/acpi.c -@@ -15,12 +15,18 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - #include -+#include - #include - #include -+#include -+#include -+#include - #include - #include - #include -@@ -38,6 +44,17 @@ - - static struct hsmp_plat_device *hsmp_pdev; - -+/* -+ * Tracks the ACPI socket platform devices that share the socket array and the -+ * /dev/hsmp misc device. The first probe initializes it, each further probe -+ * takes a reference and every remove (or probe failure) drops one; the last -+ * put frees the shared state via hsmp_acpi_sock_release(). All get/put run -+ * under hsmp_sock_rwsem held for write, so the counting is already serialized -+ * and the atomic in kref is not strictly needed; kref is used for the clearer -+ * get/put interface and its release callback. -+ */ -+static struct kref hsmp_acpi_sock_kref; -+ - struct hsmp_sys_attr { - struct device_attribute dattr; - u32 msg_id; -@@ -77,6 +94,8 @@ static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind) - * bytes to integer. - */ - uid = acpi_device_uid(ACPI_COMPANION(dev)); -+ if (!uid || strlen(uid) < 3) -+ return -EINVAL; - - return kstrtou16(uid + 2, 10, sock_ind); - } -@@ -104,7 +123,7 @@ static acpi_status hsmp_resource(struct acpi_resource *res, void *data) - return AE_OK; - } - --static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) -+static int hsmp_read_acpi_dsd(struct device *dev, struct hsmp_socket *sock) - { - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *guid, *mailbox_package; -@@ -113,10 +132,10 @@ static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) - int ret = 0; - int j; - -- status = acpi_evaluate_object_typed(ACPI_HANDLE(sock->dev), "_DSD", NULL, -+ status = acpi_evaluate_object_typed(ACPI_HANDLE(dev), "_DSD", NULL, - &buf, ACPI_TYPE_PACKAGE); - if (ACPI_FAILURE(status)) { -- dev_err(sock->dev, "Failed to read mailbox reg offsets from DSD table, err: %s\n", -+ dev_err(dev, "Failed to read mailbox reg offsets from DSD table, err: %s\n", - acpi_format_exception(status)); - return -ENODEV; - } -@@ -139,7 +158,7 @@ static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) - guid = &dsd->package.elements[0]; - mailbox_package = &dsd->package.elements[1]; - if (!is_acpi_hsmp_uuid(guid) || mailbox_package->type != ACPI_TYPE_PACKAGE) { -- dev_err(sock->dev, "Invalid hsmp _DSD table data\n"); -+ dev_err(dev, "Invalid hsmp _DSD table data\n"); - ret = -EINVAL; - goto free_buf; - } -@@ -148,12 +167,18 @@ static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) - union acpi_object *msgobj, *msgstr, *msgint; - - msgobj = &mailbox_package->package.elements[j]; -- msgstr = &msgobj->package.elements[0]; -- msgint = &msgobj->package.elements[1]; - - /* package should have 1 string and 1 integer object */ - if (msgobj->type != ACPI_TYPE_PACKAGE || -- msgstr->type != ACPI_TYPE_STRING || -+ msgobj->package.count < 2) { -+ ret = -EINVAL; -+ goto free_buf; -+ } -+ -+ msgstr = &msgobj->package.elements[0]; -+ msgint = &msgobj->package.elements[1]; -+ -+ if (msgstr->type != ACPI_TYPE_STRING || - msgint->type != ACPI_TYPE_INTEGER) { - ret = -EINVAL; - goto free_buf; -@@ -183,14 +208,14 @@ static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) - return ret; - } - --static int hsmp_read_acpi_crs(struct hsmp_socket *sock) -+static int hsmp_read_acpi_crs(struct device *dev, struct hsmp_socket *sock) - { - acpi_status status; - -- status = acpi_walk_resources(ACPI_HANDLE(sock->dev), METHOD_NAME__CRS, -+ status = acpi_walk_resources(ACPI_HANDLE(dev), METHOD_NAME__CRS, - hsmp_resource, sock); - if (ACPI_FAILURE(status)) { -- dev_err(sock->dev, "Failed to look up MP1 base address from CRS method, err: %s\n", -+ dev_err(dev, "Failed to look up MP1 base address from CRS method, err: %s\n", - acpi_format_exception(status)); - return -EINVAL; - } -@@ -198,10 +223,10 @@ static int hsmp_read_acpi_crs(struct hsmp_socket *sock) - return -EINVAL; - - /* The mapped region should be un-cached */ -- sock->virt_base_addr = devm_ioremap_uc(sock->dev, sock->mbinfo.base_addr, -+ sock->virt_base_addr = devm_ioremap_uc(dev, sock->mbinfo.base_addr, - sock->mbinfo.size); - if (!sock->virt_base_addr) { -- dev_err(sock->dev, "Failed to ioremap MP1 base address\n"); -+ dev_err(dev, "Failed to ioremap MP1 base address\n"); - return -ENOMEM; - } - -@@ -215,7 +240,6 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind) - int ret; - - sock->sock_ind = sock_ind; -- sock->dev = dev; - sock->amd_hsmp_rdwr = amd_hsmp_acpi_rdwr; - - sema_init(&sock->hsmp_sem, 1); -@@ -223,12 +247,27 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind) - dev_set_drvdata(dev, sock); - - /* Read MP1 base address from CRS method */ -- ret = hsmp_read_acpi_crs(sock); -+ ret = hsmp_read_acpi_crs(dev, sock); - if (ret) - return ret; - - /* Read mailbox offsets from DSD table */ -- return hsmp_read_acpi_dsd(sock); -+ ret = hsmp_read_acpi_dsd(dev, sock); -+ if (ret) -+ return ret; -+ -+ /* -+ * Publish sock->dev last. hsmp_send_message() uses it (via -+ * smp_load_acquire()) as the readiness gate for the lock-free data -+ * plane, so it must become visible only after virt_base_addr, the -+ * mailbox offsets and the semaphore are fully initialized. On a -+ * multi-socket system socket 0 exposes /dev/hsmp before later sockets -+ * finish probing, so without this an ioctl aimed at a socket still in -+ * bring-up could pass the gate and dereference a NULL virt_base_addr. -+ */ -+ smp_store_release(&sock->dev, dev); -+ -+ return 0; - } - - static ssize_t hsmp_metric_tbl_acpi_read(struct file *filp, struct kobject *kobj, -@@ -238,13 +277,31 @@ static ssize_t hsmp_metric_tbl_acpi_read(struct file *filp, struct kobject *kobj - struct device *dev = container_of(kobj, struct device, kobj); - struct hsmp_socket *sock = dev_get_drvdata(dev); - -+ /* -+ * metrics_bin is a sysfs binary attribute and is capped at PAGE_SIZE. -+ * It can therefore only carry the protocol version 6 metric table -+ * (struct hsmp_metric_table). The larger tables defined from protocol -+ * version 7 onwards do not fit; userspace on those systems must read -+ * the snapshot through HSMP_IOCTL_GET_TELEMETRY_DATA on /dev/hsmp. -+ * Surface the unsupported case here as -EOPNOTSUPP rather than -+ * silently truncating the snapshot. -+ */ -+ if (hsmp_pdev->proto_ver != HSMP_PROTO_VER6) -+ return -EOPNOTSUPP; -+ - return hsmp_metric_tbl_read(sock, buf, count); - } - - static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, - const struct bin_attribute *battr, int id) - { -- if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) -+ /* -+ * Keep metrics_bin visible on protocol version 7 and later as well, -+ * so that userspace which expects the file to exist gets a clear -+ * -EOPNOTSUPP from the read handler instead of -ENOENT, and is -+ * pointed at HSMP_IOCTL_GET_TELEMETRY_DATA as the supported path. -+ */ -+ if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) - return battr->attr.mode; - - return 0; -@@ -459,11 +516,20 @@ static ssize_t hsmp_freq_limit_source_show(struct device *dev, struct device_att - return len; - } - -+/* -+ * Bring up one ACPI HSMP socket: parse its ACPI table, run the mailbox -+ * handshake and register its sysfs/hwmon interfaces. -+ * -+ * Called with hsmp_sock_rwsem held for write by hsmp_acpi_probe(), so the -+ * per-socket bring-up cannot race a concurrent probe or remove. -+ */ - static int init_acpi(struct device *dev) - { - u16 sock_ind; - int ret; - -+ lockdep_assert_held_write(&hsmp_sock_rwsem); -+ - ret = hsmp_get_uid(dev, &sock_ind); - if (ret) - return ret; -@@ -491,7 +557,7 @@ static int init_acpi(struct device *dev) - return ret; - } - -- if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) { -+ if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) { - ret = hsmp_get_tbl_dram_base(sock_ind); - if (ret) - dev_info(dev, "Failed to init metric table\n"); -@@ -576,6 +642,60 @@ static const struct acpi_device_id amd_hsmp_acpi_ids[] = { - }; - MODULE_DEVICE_TABLE(acpi, amd_hsmp_acpi_ids); - -+/* -+ * kref release: tear down the shared ACPI socket state once the last socket -+ * drops its reference. Deregister /dev/hsmp if it was registered, unmap any -+ * metric-table DRAM, destroy the per-socket mutexes and free the socket array. -+ * -+ * Runs from kref_put() with hsmp_sock_rwsem held for write, since the remove -+ * and probe-failure paths both drop their reference under that lock. The write -+ * lock has drained any in-flight hsmp_send_message(), so unmapping the mailbox -+ * and freeing the array cannot race the data plane. -+ */ -+static void hsmp_acpi_sock_release(struct kref *kref) -+{ -+ lockdep_assert_held_write(&hsmp_sock_rwsem); -+ -+ if (!IS_ERR_OR_NULL(hsmp_pdev->mdev.this_device)) -+ hsmp_misc_deregister(); -+ hsmp_unmap_metric_tbls(hsmp_pdev); -+ hsmp_destroy_metric_read_locks(hsmp_pdev); -+ kfree(hsmp_pdev->sock); -+ hsmp_pdev->sock = NULL; -+ hsmp_pdev->num_sockets = 0; -+ hsmp_pdev->proto_ver = 0; -+} -+ -+/** -+ * hsmp_acpi_probe_failure_cleanup() - Undo a failed ACPI socket probe. -+ * @dev: ACPI companion device whose probe failed. -+ * -+ * This device already took a reference on entry to hsmp_acpi_probe(), so clear -+ * its sock->dev and drop that reference; the shared state is released if it was -+ * the last one. -+ * -+ * Clearing sock->dev matters on multi-socket systems: when a non-first socket -+ * fails, the array stays alive (owned by an already-probed socket) and -+ * remove() is never called for this device, yet devres unmaps its mailbox once -+ * probe() returns. Without clearing dev, a later message to this index would -+ * pass every gate in hsmp_send_message() and reach the unmapped mailbox. -+ * -+ * sock is NULL if probe failed before hsmp_parse_acpi_table() set the drvdata. -+ * -+ * Called from hsmp_acpi_probe(), which already holds hsmp_sock_rwsem for write. -+ */ -+static void hsmp_acpi_probe_failure_cleanup(struct device *dev) -+{ -+ struct hsmp_socket *sock = dev_get_drvdata(dev); -+ -+ lockdep_assert_held_write(&hsmp_sock_rwsem); -+ -+ if (sock) -+ sock->dev = NULL; -+ -+ kref_put(&hsmp_acpi_sock_kref, hsmp_acpi_sock_release); -+} -+ - static int hsmp_acpi_probe(struct platform_device *pdev) - { - int ret; -@@ -584,34 +704,61 @@ static int hsmp_acpi_probe(struct platform_device *pdev) - if (!hsmp_pdev) - return -ENOMEM; - -- if (!hsmp_pdev->is_probed) { -+ /* -+ * Multiple ACPI socket devices probe in parallel, but the one-time -+ * socket-array allocation and /dev/hsmp registration below must run -+ * exactly once. Hold the socket rwsem for write across the whole -+ * bring-up so it cannot race a concurrent probe or remove, and so the -+ * probe-failure teardown drains the data plane. -+ */ -+ guard(rwsem_write)(&hsmp_sock_rwsem); -+ -+ if (!hsmp_pdev->sock) { - hsmp_pdev->num_sockets = topology_max_packages(); - if (!hsmp_pdev->num_sockets) { - dev_err(&pdev->dev, "No CPU sockets detected\n"); - return -ENODEV; - } - -- hsmp_pdev->sock = devm_kcalloc(&pdev->dev, hsmp_pdev->num_sockets, -- sizeof(*hsmp_pdev->sock), -- GFP_KERNEL); -+ hsmp_pdev->sock = kcalloc(hsmp_pdev->num_sockets, -+ sizeof(*hsmp_pdev->sock), -+ GFP_KERNEL); - if (!hsmp_pdev->sock) - return -ENOMEM; -+ -+ hsmp_init_metric_read_locks(hsmp_pdev); -+ kref_init(&hsmp_acpi_sock_kref); -+ } else { -+ kref_get(&hsmp_acpi_sock_kref); - } - -+ /* -+ * This socket now holds a reference (kref_init on the first socket, -+ * kref_get afterwards). Every failure path below drops it via -+ * hsmp_acpi_probe_failure_cleanup(), and a successful probe hands it to -+ * hsmp_acpi_remove(). -+ */ - ret = init_acpi(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Failed to initialize HSMP interface.\n"); -+ hsmp_acpi_probe_failure_cleanup(&pdev->dev); - return ret; - } - -- if (!hsmp_pdev->is_probed) { -- ret = hsmp_misc_register(&pdev->dev); -+ if (IS_ERR_OR_NULL(hsmp_pdev->mdev.this_device)) { -+ /* -+ * Register /dev/hsmp unparented. It is a singleton shared by all -+ * ACPI sockets and outlives all but the last of them, so -+ * parenting it to this socket's device would leave a dangling -+ * parent once that socket is unbound. -+ */ -+ ret = hsmp_misc_register(NULL); - if (ret) { - dev_err(&pdev->dev, "Failed to register misc device\n"); -+ hsmp_acpi_probe_failure_cleanup(&pdev->dev); - return ret; - } -- hsmp_pdev->is_probed = true; -- dev_dbg(&pdev->dev, "AMD HSMP ACPI is probed successfully\n"); -+ dev_dbg(&pdev->dev, "AMD HSMP ACPI misc device registered\n"); - } - - return 0; -@@ -619,14 +766,26 @@ static int hsmp_acpi_probe(struct platform_device *pdev) - - static void hsmp_acpi_remove(struct platform_device *pdev) - { -+ struct hsmp_socket *sock = dev_get_drvdata(&pdev->dev); -+ - /* -- * We register only one misc_device even on multi-socket system. -- * So, deregister should happen only once. -+ * Serialize the kref_put() and any release it triggers against a -+ * concurrent probe, and drain the data plane for the whole -+ * teardown: this covers the per-socket unbind, whose mailbox devres -+ * unmaps once we return, and the last unbind that frees the socket -+ * array in hsmp_acpi_sock_release(). - */ -- if (hsmp_pdev->is_probed) { -- hsmp_misc_deregister(); -- hsmp_pdev->is_probed = false; -- } -+ guard(rwsem_write)(&hsmp_sock_rwsem); -+ -+ /* -+ * Clear this socket's dev so hsmp_send_message() rejects it before -+ * devres unmaps the mailbox. On a non-final unbind the socket array -+ * stays alive, so without this a later message to this index would -+ * reach an unmapped iomem region. -+ */ -+ sock->dev = NULL; -+ -+ kref_put(&hsmp_acpi_sock_kref, hsmp_acpi_sock_release); - } - - static struct platform_driver amd_hsmp_driver = { -diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c ---- a/drivers/platform/x86/amd/hsmp/hsmp.c -+++ b/drivers/platform/x86/amd/hsmp/hsmp.c -@@ -10,10 +10,17 @@ - #include - - #include -+#include - #include - #include -+#include -+#include -+#include -+#include - #include -+#include - #include -+#include - - #include "hsmp.h" - -@@ -40,6 +47,17 @@ - - static struct hsmp_plat_device hsmp_pdev; - -+/* -+ * Gates the AMD HSMP data plane against socket bring-up and teardown. -+ * -+ * hsmp_send_message() takes it for read, so open /dev/hsmp fds and hwmon reads -+ * run concurrently. Probe and remove take it for write: probe brings sockets -+ * up (running the mailbox handshake via hsmp_send_message_locked()) and remove -+ * tears them down, both excluding and draining the data plane. -+ */ -+DECLARE_RWSEM(hsmp_sock_rwsem); -+EXPORT_SYMBOL_NS_GPL(hsmp_sock_rwsem, "AMD_HSMP"); -+ - /* - * Send a message to the HSMP port via PCI-e config space registers - * or by writing to MMIO space. -@@ -182,29 +200,33 @@ static int validate_message(struct hsmp_message *msg) - return -EINVAL; - - /* -- * Some older HSMP SET messages are updated to add GET in the same message. -- * In these messages, GET returns the current value and SET also returns -- * the successfully set value. To support this GET and SET in same message -- * while maintaining backward compatibility for the HSMP users, -- * hsmp_msg_desc_table[] indicates only maximum allowed response_sz. -+ * As the HSMP protocol evolves, newer platforms may define more -+ * response arguments for existing messages. Use an upper-bound -+ * check so that older userspace callers requesting fewer response -+ * words than what the current hsmp_msg_desc_table[] defines are -+ * still accepted, while rejecting requests that exceed the -+ * hardware capability. - */ -- if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET) { -- if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz) -- return -EINVAL; -- } else { -- /* only HSMP_SET or HSMP_GET messages go through this strict check */ -- if (msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) -- return -EINVAL; -- } -+ if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz) -+ return -EINVAL; -+ - return 0; - } - --int hsmp_send_message(struct hsmp_message *msg) -+/* -+ * Core message send. The caller must hold hsmp_sock_rwsem: the data plane -+ * takes it for read so many messages run concurrently, while the probe-time -+ * senders run under the write lock taken by probe. Holding it here serializes -+ * every message against socket teardown, which also holds it for write. -+ */ -+static int hsmp_send_message_locked(struct hsmp_message *msg) - { - struct hsmp_socket *sock; - unsigned int sock_ind; - int ret; - -+ lockdep_assert_held(&hsmp_sock_rwsem); -+ - if (!msg) - return -EINVAL; - ret = validate_message(msg); -@@ -223,6 +245,20 @@ int hsmp_send_message(struct hsmp_message *msg) - sock_ind = array_index_nospec(msg->sock_ind, hsmp_pdev.num_sockets); - sock = &hsmp_pdev.sock[sock_ind]; - -+ /* -+ * A slot exists for every possible socket, but it is only usable once -+ * that socket has actually been probed. Reject messages aimed at a -+ * socket that was never brought up or is still in bring-up, so we never -+ * operate on a zero-initialized semaphore or an unmapped mailbox. A -+ * non-NULL dev also guarantees virt_base_addr, the mailbox offsets and -+ * the semaphore are visible. -+ * -+ * Held under hsmp_sock_rwsem; pairs with smp_store_release(&sock->dev) -+ * in hsmp_parse_acpi_table(). -+ */ -+ if (!smp_load_acquire(&sock->dev)) -+ return -ENODEV; -+ - ret = down_interruptible(&sock->hsmp_sem); - if (ret < 0) - return ret; -@@ -233,6 +269,19 @@ int hsmp_send_message(struct hsmp_message *msg) - - return ret; - } -+ -+int hsmp_send_message(struct hsmp_message *msg) -+{ -+ /* -+ * Data-plane entry point: open /dev/hsmp fds and hwmon sysfs reads issue -+ * messages from here. Take hsmp_sock_rwsem for read so messages run -+ * concurrently with each other but are drained and kept out while -+ * probe/remove hold it for write to tear a socket down. -+ */ -+ guard(rwsem_read)(&hsmp_sock_rwsem); -+ -+ return hsmp_send_message_locked(msg); -+} - EXPORT_SYMBOL_NS_GPL(hsmp_send_message, "AMD_HSMP"); - - int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 num_args) -@@ -273,7 +322,7 @@ int hsmp_test(u16 sock_ind, u32 value) - msg.args[0] = value; - msg.sock_ind = sock_ind; - -- ret = hsmp_send_message(&msg); -+ ret = hsmp_send_message_locked(&msg); - if (ret) - return ret; - -@@ -301,7 +350,7 @@ static bool is_get_msg(struct hsmp_message *msg) - return false; - } - --long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -+static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) - { - int __user *arguser = (int __user *)arg; - struct hsmp_message msg = { 0 }; -@@ -370,11 +419,139 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) - return 0; - } - --ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size) -+static ssize_t hsmp_metric_tbl_read_locked(struct hsmp_socket *sock, char *buf, -+ size_t size); -+ -+/* -+ * Fetch the firmware metric (telemetry) table for the requested socket and -+ * copy it to the userspace buffer described by the request. -+ * -+ * The metric table size is variable across HSMP protocol versions and on -+ * Family 1Ah Model 50h-5Fh exceeds PAGE_SIZE. The request carries the buffer -+ * size, which may be anything up to the size firmware reported for this -+ * socket's table. -+ */ -+static long hsmp_ioctl_get_telemetry(struct file *fp, unsigned long arg) -+{ -+ void *kbuf __free(kvfree) = NULL; -+ void __user *arguser = (void __user *)arg; -+ struct hsmp_telemetry_data req; -+ struct hsmp_socket *sock; -+ void __user *user_buf; -+ size_t tbl_size; -+ unsigned int sock_ind; -+ int ret; -+ -+ /* Telemetry data is read-only; require read access on the fd. */ -+ if (!(fp->f_mode & FMODE_READ)) -+ return -EPERM; -+ -+ if (copy_from_user(&req, arguser, sizeof(req))) -+ return -EFAULT; -+ -+ /* -+ * Reserved fields must be zero so future kernels can safely -+ * repurpose them without breaking already-deployed userspace. -+ */ -+ if (req.reserved) -+ return -EINVAL; -+ -+ user_buf = u64_to_user_ptr(req.buf); -+ -+ /* -+ * /dev/hsmp is a singleton character device that outlives an individual -+ * socket unbind, so an ioctl on an already-open fd can run concurrently -+ * with socket teardown. Hold hsmp_sock_rwsem for read across the socket -+ * lookup, the checks on its metric-table state and the read itself: -+ * probe and remove take the same lock for write, so they cannot free the -+ * socket array, unmap the table or destroy the per-socket mutex while -+ * this runs. -+ * -+ * The lock is dropped before the copy_to_user() below. Faulting in the -+ * destination can block indefinitely on a userfaultfd-backed buffer, -+ * which would leave a socket unbind waiting for the write lock. -+ */ -+ scoped_guard(rwsem_read, &hsmp_sock_rwsem) { -+ if (!hsmp_pdev.sock || req.sock_ind >= hsmp_pdev.num_sockets) -+ return -ENODEV; -+ -+ /* -+ * Sanitize the user-controlled socket index against speculative -+ * execution. The bounds check above retires the out-of-range -+ * case with -ENODEV, but a mispredicted branch can still let the -+ * CPU speculatively use sock_ind as an index into -+ * hsmp_pdev.sock[] and pull arbitrary kernel memory into the -+ * cache (Spectre v1, CVE-2017-5753). array_index_nospec() turns -+ * the bounds check into a data-flow clamp so the speculative -+ * load is in-range too. -+ */ -+ sock_ind = array_index_nospec(req.sock_ind, hsmp_pdev.num_sockets); -+ sock = &hsmp_pdev.sock[sock_ind]; -+ if (!sock->metric_tbl_addr) -+ return -ENODEV; -+ -+ tbl_size = sock->metric_tbl_size; -+ if (!tbl_size) -+ return -ENODEV; -+ -+ /* -+ * A request shorter than the firmware table is served with the -+ * leading @size bytes of the snapshot, so userspace built -+ * against an older table layout keeps working on firmware that -+ * grew the table. Asking for more than firmware provides is -+ * rejected rather than short-written, so a caller can never -+ * mistake a partial copy for a full one. -+ */ -+ if (!req.size || req.size > tbl_size) -+ return -EINVAL; -+ -+ /* -+ * The bounce buffer is overwritten in full by memcpy_fromio() -+ * inside hsmp_metric_tbl_read_locked(); use kvmalloc() to avoid -+ * the zeroing cost of kvzalloc() on the ~13 KB allocation done -+ * on every ioctl call. -+ */ -+ kbuf = kvmalloc(tbl_size, GFP_KERNEL); -+ if (!kbuf) -+ return -ENOMEM; -+ -+ ret = hsmp_metric_tbl_read_locked(sock, kbuf, tbl_size); -+ } -+ -+ if (ret < 0) -+ return ret; -+ -+ if (copy_to_user(user_buf, kbuf, req.size)) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -+{ -+ switch (cmd) { -+ case HSMP_IOCTL_CMD: -+ return hsmp_ioctl_msg(fp, arg); -+ case HSMP_IOCTL_GET_TELEMETRY_DATA: -+ return hsmp_ioctl_get_telemetry(fp, arg); -+ default: -+ return -ENOTTY; -+ } -+} -+ -+/* -+ * Caller must hold hsmp_sock_rwsem. It keeps @sock, its metric-table mapping -+ * and its metric_read_lock alive: probe and remove take the same lock for -+ * write while they bring sockets up and tear them down. -+ */ -+static ssize_t hsmp_metric_tbl_read_locked(struct hsmp_socket *sock, char *buf, -+ size_t size) - { - struct hsmp_message msg = { 0 }; - int ret; - -+ lockdep_assert_held(&hsmp_sock_rwsem); -+ - if (!sock || !buf) - return -EINVAL; - -@@ -383,8 +560,7 @@ ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size) - return -ENOMEM; - } - -- /* Do not support lseek(), also don't allow more than the size of metric table */ -- if (size != sizeof(struct hsmp_metric_table)) { -+ if (size != sock->metric_tbl_size) { - dev_err(sock->dev, "Wrong buffer size\n"); - return -EINVAL; - } -@@ -392,27 +568,77 @@ ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size) - msg.msg_id = HSMP_GET_METRIC_TABLE; - msg.sock_ind = sock->sock_ind; - -- ret = hsmp_send_message(&msg); -+ /* -+ * HSMP_GET_METRIC_TABLE makes firmware refill this socket's shared -+ * metric DRAM region, which is then copied out below. Hold the -+ * per-socket lock across the fill-and-copy so concurrent readers of the -+ * same socket cannot return a torn snapshot. -+ */ -+ guard(mutex)(&sock->metric_read_lock); -+ -+ ret = hsmp_send_message_locked(&msg); - if (ret) - return ret; - memcpy_fromio(buf, sock->metric_tbl_addr, size); - - return size; - } -+ -+ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size) -+{ -+ guard(rwsem_read)(&hsmp_sock_rwsem); -+ -+ return hsmp_metric_tbl_read_locked(sock, buf, size); -+} - EXPORT_SYMBOL_NS_GPL(hsmp_metric_tbl_read, "AMD_HSMP"); - -+void hsmp_init_metric_read_locks(struct hsmp_plat_device *pdev) -+{ -+ u16 i; -+ -+ for (i = 0; i < pdev->num_sockets; i++) -+ mutex_init(&pdev->sock[i].metric_read_lock); -+} -+EXPORT_SYMBOL_NS_GPL(hsmp_init_metric_read_locks, "AMD_HSMP"); -+ -+void hsmp_destroy_metric_read_locks(struct hsmp_plat_device *pdev) -+{ -+ u16 i; -+ -+ for (i = 0; i < pdev->num_sockets; i++) -+ mutex_destroy(&pdev->sock[i].metric_read_lock); -+} -+EXPORT_SYMBOL_NS_GPL(hsmp_destroy_metric_read_locks, "AMD_HSMP"); -+ -+void hsmp_unmap_metric_tbls(struct hsmp_plat_device *pdev) -+{ -+ struct hsmp_socket *sock; -+ u16 i; -+ -+ for (i = 0; i < pdev->num_sockets; i++) { -+ sock = &pdev->sock[i]; -+ if (sock->metric_tbl_addr) { -+ iounmap(sock->metric_tbl_addr); -+ sock->metric_tbl_addr = NULL; -+ } -+ sock->metric_tbl_size = 0; -+ } -+} -+EXPORT_SYMBOL_NS_GPL(hsmp_unmap_metric_tbls, "AMD_HSMP"); -+ - int hsmp_get_tbl_dram_base(u16 sock_ind) - { - struct hsmp_socket *sock = &hsmp_pdev.sock[sock_ind]; - struct hsmp_message msg = { 0 }; - phys_addr_t dram_addr; -+ size_t tbl_size; - int ret; - - msg.sock_ind = sock_ind; - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz; - msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR; - -- ret = hsmp_send_message(&msg); -+ ret = hsmp_send_message_locked(&msg); - if (ret) - return ret; - -@@ -425,12 +651,33 @@ int hsmp_get_tbl_dram_base(u16 sock_ind) - dev_err(sock->dev, "Invalid DRAM address for metric table\n"); - return -ENOMEM; - } -- sock->metric_tbl_addr = devm_ioremap(sock->dev, dram_addr, -- sizeof(struct hsmp_metric_table)); -+ /* -+ * The ACPI socket array is shared across sockets and outlives a -+ * per-socket unbind, so metric_tbl_addr may hold a mapping from an -+ * earlier bind of this socket. Unmap it before remapping so an -+ * unbind/rebind cycle does not leak a metric-table mapping. This runs -+ * during probe before the metric sysfs attribute is exposed, so no -+ * reader can be using it. -+ */ -+ if (sock->metric_tbl_addr) { -+ iounmap(sock->metric_tbl_addr); -+ sock->metric_tbl_addr = NULL; -+ } -+ sock->metric_tbl_size = 0; -+ -+ /* SMU returns table size from Family 1Ah Model 50h and forward */ -+ if (msg.args[2]) -+ tbl_size = msg.args[2]; -+ else -+ tbl_size = sizeof(struct hsmp_metric_table); -+ -+ sock->metric_tbl_addr = ioremap(dram_addr, tbl_size); - if (!sock->metric_tbl_addr) { - dev_err(sock->dev, "Failed to ioremap metric table addr\n"); - return -ENOMEM; - } -+ sock->metric_tbl_size = tbl_size; -+ - return 0; - } - EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP"); -@@ -444,7 +691,7 @@ int hsmp_cache_proto_ver(u16 sock_ind) - msg.sock_ind = sock_ind; - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; - -- ret = hsmp_send_message(&msg); -+ ret = hsmp_send_message_locked(&msg); - if (!ret) - hsmp_pdev.proto_ver = msg.args[0]; - -@@ -463,6 +710,14 @@ int hsmp_misc_register(struct device *dev) - hsmp_pdev.mdev.name = HSMP_CDEV_NAME; - hsmp_pdev.mdev.minor = MISC_DYNAMIC_MINOR; - hsmp_pdev.mdev.fops = &hsmp_fops; -+ /* -+ * The caller chooses the parent. The platform driver has a single -+ * device whose lifetime matches /dev/hsmp and parents it there. The -+ * ACPI driver passes NULL: its /dev/hsmp is a singleton shared by -+ * per-socket devices that can be unbound individually and out of order, -+ * so parenting it to one would leave it attached to an already-removed -+ * device. -+ */ - hsmp_pdev.mdev.parent = dev; - hsmp_pdev.mdev.nodename = HSMP_DEVNODE_NAME; - hsmp_pdev.mdev.mode = 0644; -@@ -474,6 +729,7 @@ EXPORT_SYMBOL_NS_GPL(hsmp_misc_register, "AMD_HSMP"); - void hsmp_misc_deregister(void) - { - misc_deregister(&hsmp_pdev.mdev); -+ hsmp_pdev.mdev.this_device = NULL; - } - EXPORT_SYMBOL_NS_GPL(hsmp_misc_deregister, "AMD_HSMP"); - -diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h ---- a/drivers/platform/x86/amd/hsmp/hsmp.h -+++ b/drivers/platform/x86/amd/hsmp/hsmp.h -@@ -15,9 +15,12 @@ - #include - #include - #include -+#include - #include -+#include - #include - #include -+#include - - #define HSMP_METRICS_TABLE_NAME "metrics_bin" - -@@ -27,7 +30,7 @@ - #define HSMP_DEVNODE_NAME "hsmp" - #define ACPI_HSMP_DEVICE_HID "AMDI0097" - --#define DRIVER_VERSION "2.5" -+#define DRIVER_VERSION "2.6" - - struct hsmp_mbaddr_info { - u32 base_addr; -@@ -41,8 +44,12 @@ struct hsmp_socket { - struct bin_attribute hsmp_attr; - struct hsmp_mbaddr_info mbinfo; - void __iomem *metric_tbl_addr; -+ /* Size of the region mapped at @metric_tbl_addr, as reported by SMU */ -+ size_t metric_tbl_size; - void __iomem *virt_base_addr; - struct semaphore hsmp_sem; -+ /* Serializes HSMP_GET_METRIC_TABLE fill-and-copy for this socket */ -+ struct mutex metric_read_lock; - char name[HSMP_ATTR_GRP_NAME_SIZE]; - struct device *dev; - u16 sock_ind; -@@ -54,7 +61,6 @@ struct hsmp_plat_device { - struct hsmp_socket *sock; - u32 proto_ver; - u16 num_sockets; -- bool is_probed; - }; - - int hsmp_cache_proto_ver(u16 sock_ind); -@@ -63,6 +69,9 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); - void hsmp_misc_deregister(void); - int hsmp_misc_register(struct device *dev); - int hsmp_get_tbl_dram_base(u16 sock_ind); -+void hsmp_unmap_metric_tbls(struct hsmp_plat_device *pdev); -+void hsmp_init_metric_read_locks(struct hsmp_plat_device *pdev); -+void hsmp_destroy_metric_read_locks(struct hsmp_plat_device *pdev); - ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size); - struct hsmp_plat_device *get_hsmp_pdev(void); - #if IS_ENABLED(CONFIG_HWMON) -@@ -71,4 +80,10 @@ int hsmp_create_sensor(struct device *dev, u16 sock_ind); - static inline int hsmp_create_sensor(struct device *dev, u16 sock_ind) { return 0; } - #endif - int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 num_args); -+ -+/* -+ * Gates the HSMP data plane: hsmp_send_message() takes it for read; probe and -+ * remove take it for write to bring sockets up and tear them down. -+ */ -+extern struct rw_semaphore hsmp_sock_rwsem; - #endif /* HSMP_H */ -diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c ---- a/drivers/platform/x86/amd/hsmp/plat.c -+++ b/drivers/platform/x86/amd/hsmp/plat.c -@@ -13,12 +13,14 @@ - - #include - #include -+#include - #include - #include - #include - #include - #include - #include -+#include - #include - - #include -@@ -201,6 +203,25 @@ static int init_platform_device(struct device *dev) - return 0; - } - -+/* -+ * The socket array is devm-managed and freed by the driver core, but the -+ * metric-table DRAM regions are mapped with plain ioremap() during probe and -+ * the per-socket mutexes need an explicit mutex_destroy(), neither of which -+ * devres covers. -+ * -+ * Take the data-plane rwsem for write to drain any in-flight -+ * hsmp_send_message(), unmap the metric tables, destroy the mutexes and drop -+ * the global socket pointer, all before devres frees the array. Registered as -+ * a devres action so it runs on both remove and probe failure. -+ */ -+static void hsmp_pltdrv_release(void *data) -+{ -+ guard(rwsem_write)(&hsmp_sock_rwsem); -+ hsmp_unmap_metric_tbls(hsmp_pdev); -+ hsmp_destroy_metric_read_locks(hsmp_pdev); -+ hsmp_pdev->sock = NULL; -+} -+ - static int hsmp_pltdrv_probe(struct platform_device *pdev) - { - int ret; -@@ -211,7 +232,22 @@ static int hsmp_pltdrv_probe(struct platform_device *pdev) - if (!hsmp_pdev->sock) - return -ENOMEM; - -- ret = init_platform_device(&pdev->dev); -+ hsmp_init_metric_read_locks(hsmp_pdev); -+ -+ ret = devm_add_action_or_reset(&pdev->dev, hsmp_pltdrv_release, NULL); -+ if (ret) -+ return ret; -+ -+ /* -+ * init_platform_device() runs the mailbox handshake via the probe-only -+ * senders, which issue messages through hsmp_send_message_locked() and -+ * so require hsmp_sock_rwsem held. Hold it for write, matching probe's -+ * role as a socket bring-up path. The lock is not held across -+ * devm_add_action_or_reset() above so the release action, which also -+ * takes it for write, does not deadlock if that registration fails. -+ */ -+ scoped_guard(rwsem_write, &hsmp_sock_rwsem) -+ ret = init_platform_device(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Failed to init HSMP mailbox\n"); - return ret; -diff --git a/drivers/platform/x86/amd/pmc/mp1_stb.c b/drivers/platform/x86/amd/pmc/mp1_stb.c ---- a/drivers/platform/x86/amd/pmc/mp1_stb.c -+++ b/drivers/platform/x86/amd/pmc/mp1_stb.c -@@ -299,10 +299,7 @@ int amd_stb_s2d_init(struct amd_pmc_dev *dev) - if (!enable_stb) - return 0; - -- if (amd_is_stb_supported(dev)) { -- debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, -- &amd_stb_debugfs_fops_v2); -- } else { -+ if (!amd_is_stb_supported(dev)) { - debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, - &amd_stb_debugfs_fops); - return 0; -@@ -342,8 +339,18 @@ int amd_stb_s2d_init(struct amd_pmc_dev *dev) - } - - dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, dev->dram_size); -- if (!dev->stb_virt_addr) -+ if (!dev->stb_virt_addr) { - ret = -ENOMEM; -+ goto out; -+ } -+ -+ /* -+ * Only expose stb_read once the buffer is mapped; otherwise a read -+ * faults on a NULL dev->stb_virt_addr, now that a failed STB init no -+ * longer aborts probe. -+ */ -+ debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, -+ &amd_stb_debugfs_fops_v2); - - out: - /* Restore the default message port for subsequent SMU operations */ -diff --git a/drivers/platform/x86/amd/pmc/pmc-quirks.c b/drivers/platform/x86/amd/pmc/pmc-quirks.c ---- a/drivers/platform/x86/amd/pmc/pmc-quirks.c -+++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c -@@ -71,6 +71,14 @@ static const struct dmi_system_id fwbug_list[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "20XK"), - } - }, -+ { -+ .ident = "T14 Gen2 AMD", -+ .driver_data = &quirk_s2idle_spurious_8042, -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "20XL"), -+ } -+ }, - { - .ident = "T14 Gen1 AMD", - .driver_data = &quirk_s2idle_spurious_8042, -diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c ---- a/drivers/platform/x86/amd/pmc/pmc.c -+++ b/drivers/platform/x86/amd/pmc/pmc.c -@@ -939,19 +939,22 @@ static int amd_pmc_probe(struct platform_device *pdev) - } - - amd_pmc_dbgfs_register(dev); -+ -+ /* -+ * STB is an optional debug facility (enable_stb); a failure to set it -+ * up must not stop the rest of the driver - most importantly the s0i3 -+ * LPS0 handler - from working, so treat it as non-fatal. -+ */ - err = amd_stb_s2d_init(dev); - if (err) -- goto err_dbgfs_unregister; -+ dev_warn(dev->dev, "STB initialization failed (%d), continuing without STB support\n", -+ err); - - if (IS_ENABLED(CONFIG_AMD_MP2_STB)) - amd_mp2_stb_init(dev); - pm_report_max_hw_sleep(U64_MAX); - return 0; - --err_dbgfs_unregister: -- amd_pmc_dbgfs_unregister(dev); -- if (IS_ENABLED(CONFIG_SUSPEND)) -- acpi_unregister_lps0_dev(&amd_pmc_s2idle_dev_ops); - err_pci_dev_put: - pci_dev_put(rdev); - return err; -diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig ---- a/drivers/platform/x86/amd/pmf/Kconfig -+++ b/drivers/platform/x86/amd/pmf/Kconfig -@@ -30,3 +30,13 @@ config AMD_PMF_DEBUG - in the PMF config store. - - Say Y here to enable more debug logs and Say N here if you are not sure. -+ -+config AMD_PMF_UTIL_SUPPORT -+ bool "AMD PMF Util layer support" -+ depends on AMD_PMF -+ help -+ Enabling this option provides a character device for userspace to capture -+ PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic -+ Power Slider AC/DC) along with PMF metrics from the AMD PMF driver. -+ -+ Say Y here to enable it and Say N here if you are not sure. -diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile ---- a/drivers/platform/x86/amd/pmf/Makefile -+++ b/drivers/platform/x86/amd/pmf/Makefile -@@ -7,4 +7,6 @@ - obj-$(CONFIG_AMD_PMF) += amd-pmf.o - amd-pmf-y := core.o acpi.o sps.o \ - auto-mode.o cnqf.o \ -- tee-if.o spc.o -+ tee-if.o spc.o metrics.o -+# Build util.c only when AMD_PMF_UTIL_SUPPORT is enabled -+amd-pmf-$(CONFIG_AMD_PMF_UTIL_SUPPORT) += util.o -diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c ---- a/drivers/platform/x86/amd/pmf/core.c -+++ b/drivers/platform/x86/amd/pmf/core.c -@@ -11,13 +11,13 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include - #include --#include - #include - #include "pmf.h" - -@@ -26,6 +26,13 @@ - #define AMD_PMF_REGISTER_RESPONSE 0xA78 - #define AMD_PMF_REGISTER_ARGUMENT 0xA58 - -+/* PMF-SMU communication registers for 1AH_M80H */ -+#define AMD_PMF_REGISTER_MESSAGE_V2 0xA04 -+#define AMD_PMF_REGISTER_RESPONSE_V2 0xA08 -+#define AMD_PMF_REGISTER_ARGUMENT0_V2 0xA0C -+#define AMD_PMF_REGISTER_ARGUMENT1_V2 0xAAC -+#define AMD_PMF_REGISTER_ARGUMENT2_V2 0xAB0 -+ - /* Base address of SMU for mapping physical address to virtual address */ - #define AMD_PMF_MAPPING_SIZE 0x01000 - #define AMD_PMF_BASE_ADDR_OFFSET 0x10000 -@@ -48,7 +55,7 @@ - #define DELAY_MAX_US 3000 - - /* override Metrics Table sample size time (in ms) */ --static int metrics_table_loop_ms = 1000; -+int metrics_table_loop_ms = 1000; - module_param(metrics_table_loop_ms, int, 0644); - MODULE_PARM_DESC(metrics_table_loop_ms, "Metrics Table sample size time (default = 1000ms)"); - -@@ -61,7 +68,15 @@ static bool smart_pc_support = true; - module_param(smart_pc_support, bool, 0444); - MODULE_PARM_DESC(smart_pc_support, "Smart PC Support (default = true)"); - --static struct device *pmf_device; -+static bool amd_pmf_supports_accumulator_metrics(struct amd_pmf_dev *pdev) -+{ -+ switch (pdev->cpu_id) { -+ case PCI_DEVICE_ID_AMD_1AH_M80H_ROOT: -+ return true; -+ default: -+ return false; -+ } -+} - - static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data) - { -@@ -131,37 +146,6 @@ int amd_pmf_get_power_source(void) - return POWER_SOURCE_DC; - } - --static void amd_pmf_get_metrics(struct work_struct *work) --{ -- struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, work_buffer.work); -- ktime_t time_elapsed_ms; -- int socket_power; -- -- guard(mutex)(&dev->update_mutex); -- -- /* Transfer table contents */ -- memset(dev->buf, 0, sizeof(dev->m_table)); -- amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL); -- memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table)); -- -- time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time; -- /* Calculate the avg SoC power consumption */ -- socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power; -- -- if (dev->amt_enabled) { -- /* Apply the Auto Mode transition */ -- amd_pmf_trans_automode(dev, socket_power, time_elapsed_ms); -- } -- -- if (dev->cnqf_enabled) { -- /* Apply the CnQF transition */ -- amd_pmf_trans_cnqf(dev, socket_power, time_elapsed_ms); -- } -- -- dev->start_time = ktime_to_ms(ktime_get()); -- schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms)); --} -- - static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset) - { - return ioread32(dev->regbase + reg_offset); -@@ -176,13 +160,19 @@ static void __maybe_unused amd_pmf_dump_registers(struct amd_pmf_dev *dev) - { - u32 value; - -- value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_RESPONSE); -+ value = amd_pmf_reg_read(dev, dev->smu_regs->resp_reg); - dev_dbg(dev->dev, "AMD_PMF_REGISTER_RESPONSE:%x\n", value); - -- value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT); -+ value = amd_pmf_reg_read(dev, dev->smu_regs->arg_reg[0]); - dev_dbg(dev->dev, "AMD_PMF_REGISTER_ARGUMENT:%d\n", value); -+ if (amd_pmf_supports_accumulator_metrics(dev)) { -+ value = amd_pmf_reg_read(dev, dev->smu_regs->arg_reg[1]); -+ dev_dbg(dev->dev, "AMD_PMF_REGISTER_ARGUMENT1:%d\n", value); -+ value = amd_pmf_reg_read(dev, dev->smu_regs->arg_reg[2]); -+ dev_dbg(dev->dev, "AMD_PMF_REGISTER_ARGUMENT2:%d\n", value); -+ } - -- value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_MESSAGE); -+ value = amd_pmf_reg_read(dev, dev->smu_regs->msg_reg); - dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value); - } - -@@ -208,7 +198,7 @@ int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 - guard(mutex)(&dev->lock); - - /* Wait until we get a valid response */ -- rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE, -+ rc = readx_poll_timeout(ioread32, dev->regbase + dev->smu_regs->resp_reg, - val, val != 0, PMF_MSG_DELAY_MIN_US, - PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); - if (rc) { -@@ -217,16 +207,16 @@ int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 - } - - /* Write zero to response register */ -- amd_pmf_reg_write(dev, AMD_PMF_REGISTER_RESPONSE, 0); -+ amd_pmf_reg_write(dev, dev->smu_regs->resp_reg, 0); - - /* Write argument into argument register */ -- amd_pmf_reg_write(dev, AMD_PMF_REGISTER_ARGUMENT, arg); -+ amd_pmf_reg_write(dev, dev->smu_regs->arg_reg[0], arg); - - /* Write message ID to message ID register */ -- amd_pmf_reg_write(dev, AMD_PMF_REGISTER_MESSAGE, message); -+ amd_pmf_reg_write(dev, dev->smu_regs->msg_reg, message); - - /* Wait until we get a valid response */ -- rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE, -+ rc = readx_poll_timeout(ioread32, dev->regbase + dev->smu_regs->resp_reg, - val, val != 0, PMF_MSG_DELAY_MIN_US, - PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); - if (rc) { -@@ -239,7 +229,14 @@ int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 - if (get) { - /* PMFW may take longer time to return back the data */ - usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US); -- *data = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT); -+ *data = amd_pmf_reg_read(dev, dev->smu_regs->arg_reg[0]); -+ if (amd_pmf_supports_accumulator_metrics(dev) && -+ message == GET_1AH_M80H_METRICS_TABLE_DRAM_ADDR) { -+ dev->dram_addr.hi = amd_pmf_reg_read(dev, -+ dev->smu_regs->arg_reg[1]); -+ dev->dram_addr.size = amd_pmf_reg_read(dev, -+ dev->smu_regs->arg_reg[2]); -+ } - } - break; - case AMD_PMF_RESULT_CMD_REJECT_BUSY: -@@ -262,132 +259,32 @@ int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 - return rc; - } - --static const struct pci_device_id pmf_pci_ids[] = { -- { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RMB) }, -- { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) }, -- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, -- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, -- { } -+/* RMB, PS, 1AH_M20H and 1AH_M60H share the same v1 SMU mailbox registers */ -+static const struct amd_pmf_smu_regs amd_pmf_smu_regs_v1 = { -+ .msg_reg = AMD_PMF_REGISTER_MESSAGE, -+ .resp_reg = AMD_PMF_REGISTER_RESPONSE, -+ .arg_reg = { AMD_PMF_REGISTER_ARGUMENT, 0, 0 }, - }; - --int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer) --{ -- u64 phys_addr; -- u32 hi, low; -+/* 1AH_M80H uses an extended mailbox with three argument registers */ -+static const struct amd_pmf_smu_regs amd_pmf_smu_regs_v2 = { -+ .msg_reg = AMD_PMF_REGISTER_MESSAGE_V2, -+ .resp_reg = AMD_PMF_REGISTER_RESPONSE_V2, -+ .arg_reg = { -+ AMD_PMF_REGISTER_ARGUMENT0_V2, -+ AMD_PMF_REGISTER_ARGUMENT1_V2, -+ AMD_PMF_REGISTER_ARGUMENT2_V2, -+ }, -+}; - -- /* Get Metrics Table Address */ -- if (alloc_buffer) { -- switch (dev->cpu_id) { -- case AMD_CPU_ID_PS: -- case AMD_CPU_ID_RMB: -- dev->mtable_size = sizeof(dev->m_table); -- break; -- case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: -- case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: -- dev->mtable_size = sizeof(dev->m_table_v2); -- break; -- default: -- dev_err(dev->dev, "Invalid CPU id: 0x%x", dev->cpu_id); -- } -- -- dev->buf = devm_kzalloc(dev->dev, dev->mtable_size, GFP_KERNEL); -- if (!dev->buf) -- return -ENOMEM; -- } -- -- phys_addr = virt_to_phys(dev->buf); -- hi = phys_addr >> 32; -- low = phys_addr & GENMASK(31, 0); -- -- amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, SET_CMD, hi, NULL); -- amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, SET_CMD, low, NULL); -- -- return 0; --} -- --int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) --{ -- int ret; -- -- INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics); -- -- ret = amd_pmf_set_dram_addr(dev, true); -- if (ret) -- return ret; -- -- /* -- * Start collecting the metrics data after a small delay -- * or else, we might end up getting stale values from PMFW. -- */ -- schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms * 3)); -- -- return 0; --} -- --static int is_npu_metrics_supported(struct amd_pmf_dev *pdev) --{ -- switch (pdev->cpu_id) { -- case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: -- case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: -- return 0; -- default: -- return -EOPNOTSUPP; -- } --} -- --static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct amd_pmf_npu_metrics *data) --{ -- int ret, i; -- -- guard(mutex)(&dev->metrics_mutex); -- -- ret = is_npu_metrics_supported(dev); -- if (ret) -- return ret; -- -- ret = amd_pmf_set_dram_addr(dev, true); -- if (ret) -- return ret; -- -- memset(dev->buf, 0, dev->mtable_size); -- -- /* Send SMU command to get NPU metrics */ -- ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL); -- if (ret) { -- dev_err(dev->dev, "SMU command failed to get NPU metrics: %d\n", ret); -- return ret; -- } -- -- memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size); -- -- data->npuclk_freq = dev->m_table_v2.npuclk_freq; -- for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++) -- data->npu_busy[i] = dev->m_table_v2.npu_busy[i]; -- data->npu_power = dev->m_table_v2.npu_power; -- data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq; -- data->npu_reads = dev->m_table_v2.npu_reads; -- data->npu_writes = dev->m_table_v2.npu_writes; -- -- return 0; --} -- --int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info) --{ -- struct amd_pmf_dev *pdev; -- -- if (!info) -- return -EINVAL; -- -- if (!pmf_device) -- return -ENODEV; -- -- pdev = dev_get_drvdata(pmf_device); -- if (!pdev) -- return -ENODEV; -- -- return amd_pmf_get_smu_metrics(pdev, info); --} --EXPORT_SYMBOL_NS_GPL(amd_pmf_get_npu_data, "AMD_PMF"); -+static const struct pci_device_id pmf_pci_ids[] = { -+ { PCI_DEVICE_DATA(AMD, CPU_ID_RMB, &amd_pmf_smu_regs_v1) }, -+ { PCI_DEVICE_DATA(AMD, CPU_ID_PS, &amd_pmf_smu_regs_v1) }, -+ { PCI_DEVICE_DATA(AMD, 1AH_M20H_ROOT, &amd_pmf_smu_regs_v1) }, -+ { PCI_DEVICE_DATA(AMD, 1AH_M60H_ROOT, &amd_pmf_smu_regs_v1) }, -+ { PCI_DEVICE_DATA(AMD, 1AH_M80H_ROOT, &amd_pmf_smu_regs_v2) }, -+ { } -+}; - - static int amd_pmf_reinit_ta(struct amd_pmf_dev *pdev) - { -@@ -536,6 +433,19 @@ static void amd_pmf_deinit_features(struct amd_pmf_dev *dev) - } - } - -+static int amd_pmf_get_smu_mb_offset(struct amd_pmf_dev *pdev, struct pci_dev *rdev) -+{ -+ const struct pci_device_id *id; -+ -+ id = pci_match_id(pmf_pci_ids, rdev); -+ if (!id) -+ return -ENODEV; -+ -+ pdev->smu_regs = (const struct amd_pmf_smu_regs *)id->driver_data; -+ -+ return 0; -+} -+ - static const struct acpi_device_id amd_pmf_acpi_ids[] = { - {"AMDI0100", 0x100}, - {"AMDI0102", 0}, -@@ -543,6 +453,7 @@ static const struct acpi_device_id amd_pmf_acpi_ids[] = { - {"AMDI0105", 0}, - {"AMDI0107", 0}, - {"AMDI0108", 0}, -+ {"AMDI0109", 0}, - { } - }; - MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids); -@@ -624,6 +535,17 @@ static int amd_pmf_probe(struct platform_device *pdev) - if (err) - return err; - -+ /* Populate smu_regs with SoC-specific SMU mailbox register offsets */ -+ err = amd_pmf_get_smu_mb_offset(dev, rdev); -+ if (err) -+ return err; -+ -+ if (amd_pmf_supports_accumulator_metrics(dev)) { -+ err = amd_pmf_get_tbl_dram_addr(dev); -+ if (err) -+ return err; -+ } -+ - apmf_acpi_init(dev); - platform_set_drvdata(pdev, dev); - amd_pmf_dbgfs_register(dev); -@@ -632,7 +554,11 @@ static int amd_pmf_probe(struct platform_device *pdev) - if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2)) - amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD); - -- pmf_device = dev->dev; -+ amd_pmf_set_device(dev->dev); -+ -+ err = amd_pmf_cdev_register(dev); -+ if (err) -+ dev_warn(dev->dev, "failed to register util interface: %d\n", err); - - dev_info(dev->dev, "registered PMF device successfully\n"); - -@@ -643,6 +569,7 @@ static void amd_pmf_remove(struct platform_device *pdev) - { - struct amd_pmf_dev *dev = platform_get_drvdata(pdev); - -+ amd_pmf_cdev_unregister(); - amd_pmf_deinit_features(dev); - if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2)) - amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD); -diff --git a/drivers/platform/x86/amd/pmf/metrics.c b/drivers/platform/x86/amd/pmf/metrics.c -new file mode 100644 ---- /dev/null -+++ b/drivers/platform/x86/amd/pmf/metrics.c -@@ -0,0 +1,330 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * AMD Platform Management Framework Driver - Metrics Support -+ * -+ * Copyright (c) 2026, Advanced Micro Devices, Inc. -+ * All Rights Reserved. -+ * -+ * Authors: Shyam Sundar S K -+ * Patil Rajesh Reddy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pmf.h" -+ -+static struct device *pmf_device; -+ -+static u16 amd_pmf_q10_acc_to_mW(u64 avg_acc) -+{ -+ u64 val = DIV_U64_ROUND_CLOSEST(avg_acc, 1024) * MILLIWATT_PER_WATT; -+ -+ return min_t(u16, val, U16_MAX); -+} -+ -+static u16 amd_pmf_q10_acc_to_int(u64 avg_acc) -+{ -+ u64 val = DIV_U64_ROUND_CLOSEST(avg_acc, 1024); -+ -+ return min_t(u16, val, U16_MAX); -+} -+ -+static u64 amd_pmf_avg_acc_metric(u32 curr_counter, u32 prev_counter, -+ u64 curr_value, u64 prev_value) -+{ -+ u32 counter_diff; -+ u64 val_diff; -+ -+ /* Check for counter reset */ -+ if (curr_counter <= prev_counter) -+ return 0; -+ -+ counter_diff = curr_counter - prev_counter; -+ -+ if (curr_value < prev_value) -+ return 0; -+ -+ val_diff = curr_value - prev_value; -+ -+ return DIV_U64_ROUND_CLOSEST(val_diff, counter_diff); -+} -+ -+int amd_pmf_get_tbl_dram_addr(struct amd_pmf_dev *dev) -+{ -+ int ret; -+ -+ ret = amd_pmf_send_cmd(dev, GET_1AH_M80H_METRICS_TABLE_DRAM_ADDR, GET_CMD, -+ ARG_NONE, &dev->dram_addr.lo); -+ if (ret) { -+ dev_err(dev->dev, "Failed to get DRAM address: %d\n", ret); -+ return ret; -+ } -+ -+ dev->metrics_table_phys = ((u64)dev->dram_addr.hi << 32) | dev->dram_addr.lo; -+ dev->mtable_size = dev->dram_addr.size; -+ -+ if (dev->mtable_size != sizeof(dev->mtable_v3)) { -+ dev_err(dev->dev, "Metrics table size mismatch: got %u, expected %zu\n", -+ dev->dram_addr.size, sizeof(dev->mtable_v3)); -+ return -EINVAL; -+ } -+ -+ dev->metrics_table_virt = devm_ioremap(dev->dev, dev->metrics_table_phys, dev->mtable_size); -+ if (!dev->metrics_table_virt) { -+ dev_err(dev->dev, "Failed to map DRAM address for PMF metrics table\n"); -+ dev->metrics_table_phys = 0; -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static int amd_pmf_get_metrics_table_log_sample(struct amd_pmf_dev *dev) -+{ -+ int ret; -+ -+ if (!dev->metrics_table_virt) { -+ dev_err(dev->dev, "Metrics DRAM not mapped\n"); -+ return -EINVAL; -+ } -+ -+ /* Send command to PMFW to update metrics table log sample */ -+ ret = amd_pmf_send_cmd(dev, GET_1AH_M80H_METRICS_TABLE_LOG_SAMPLE, SET_CMD, ARG_NONE, NULL); -+ if (ret) { -+ dev_err(dev->dev, "Failed to request metrics log sample: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void amd_pmf_get_metrics(struct work_struct *work) -+{ -+ struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, work_buffer.work); -+ ktime_t time_elapsed_ms; -+ int socket_power; -+ -+ guard(mutex)(&dev->update_mutex); -+ -+ /* Transfer table contents */ -+ memset(dev->buf, 0, sizeof(dev->m_table)); -+ amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL); -+ memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table)); -+ -+ time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time; -+ /* Calculate the avg SoC power consumption */ -+ socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power; -+ -+ if (dev->amt_enabled) { -+ /* Apply the Auto Mode transition */ -+ amd_pmf_trans_automode(dev, socket_power, time_elapsed_ms); -+ } -+ -+ if (dev->cnqf_enabled) { -+ /* Apply the CnQF transition */ -+ amd_pmf_trans_cnqf(dev, socket_power, time_elapsed_ms); -+ } -+ -+ dev->start_time = ktime_to_ms(ktime_get()); -+ schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms)); -+} -+ -+int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer) -+{ -+ u64 phys_addr; -+ u32 hi, low; -+ -+ /* Get Metrics Table Address */ -+ if (alloc_buffer) { -+ switch (dev->cpu_id) { -+ case AMD_CPU_ID_PS: -+ case AMD_CPU_ID_RMB: -+ dev->mtable_size = sizeof(dev->m_table); -+ break; -+ case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: -+ case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: -+ dev->mtable_size = sizeof(dev->m_table_v2); -+ break; -+ default: -+ dev_err(dev->dev, "Invalid CPU id: 0x%x\n", dev->cpu_id); -+ } -+ -+ dev->buf = devm_kzalloc(dev->dev, dev->mtable_size, GFP_KERNEL); -+ if (!dev->buf) -+ return -ENOMEM; -+ } -+ -+ phys_addr = virt_to_phys(dev->buf); -+ hi = upper_32_bits(phys_addr); -+ low = lower_32_bits(phys_addr); -+ -+ amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, SET_CMD, hi, NULL); -+ amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, SET_CMD, low, NULL); -+ -+ return 0; -+} -+ -+int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev) -+{ -+ int ret; -+ -+ INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics); -+ -+ ret = amd_pmf_set_dram_addr(dev, true); -+ if (ret) -+ return ret; -+ -+ /* -+ * Start collecting the metrics data after a small delay -+ * or else, we might end up getting stale values from PMFW. -+ */ -+ schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms * 3)); -+ -+ return 0; -+} -+ -+void amd_pmf_set_device(struct device *p_device) -+{ -+ pmf_device = p_device; -+} -+ -+static int is_npu_metrics_supported(struct amd_pmf_dev *pdev) -+{ -+ switch (pdev->cpu_id) { -+ case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: -+ case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: -+ case PCI_DEVICE_ID_AMD_1AH_M80H_ROOT: -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+static void amd_pmf_calculate_acc_npu_metrics(struct amd_pmf_dev *dev, -+ struct amd_pmf_npu_metrics *data) -+{ -+ struct amd_pmf_metrics_iod *curr, *prev; -+ u64 val; -+ int i; -+ -+ curr = &dev->mtable_v3.iod; -+ prev = &dev->prev_metrics.iod; -+ -+ val = amd_pmf_avg_acc_metric(curr->counter_acc, prev->counter_acc, -+ curr->npu_temp_acc, prev->npu_temp_acc); -+ data->npu_temp = amd_pmf_q10_acc_to_int(val); -+ val = amd_pmf_avg_acc_metric(curr->counter_acc, prev->counter_acc, -+ curr->npu_power_acc, prev->npu_power_acc); -+ data->npu_power = amd_pmf_q10_acc_to_mW(val); -+ val = amd_pmf_avg_acc_metric(curr->counter_acc, prev->counter_acc, -+ curr->npuhclk_freq_eff_acc, -+ prev->npuhclk_freq_eff_acc); -+ data->mpnpuclk_freq = amd_pmf_q10_acc_to_int(val); -+ val = amd_pmf_avg_acc_metric(curr->counter_acc, prev->counter_acc, -+ curr->aieclk_freq_eff_acc, -+ prev->aieclk_freq_eff_acc); -+ data->npuclk_freq = amd_pmf_q10_acc_to_int(val); -+ -+ for (i = 0; i < ARRAY_SIZE(curr->npu_busy_acc); i++) { -+ val = amd_pmf_avg_acc_metric(curr->counter_acc, prev->counter_acc, -+ curr->npu_busy_acc[i], -+ prev->npu_busy_acc[i]); -+ data->npu_busy[i] = amd_pmf_q10_acc_to_int(val); -+ } -+} -+ -+static int amd_pmf_get_smu_metrics(struct amd_pmf_dev *dev, struct amd_pmf_npu_metrics *data) -+{ -+ int ret, i; -+ -+ guard(mutex)(&dev->metrics_mutex); -+ -+ ret = is_npu_metrics_supported(dev); -+ if (ret) -+ return ret; -+ -+ memset(data, 0, sizeof(*data)); -+ -+ switch (dev->cpu_id) { -+ case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: -+ case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: -+ ret = amd_pmf_set_dram_addr(dev, true); -+ if (ret) -+ return ret; -+ -+ memset(dev->buf, 0, dev->mtable_size); -+ -+ /* Send SMU command to get NPU metrics */ -+ ret = amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL); -+ if (ret) { -+ dev_err(dev->dev, "SMU command failed to get NPU metrics: %d\n", ret); -+ return ret; -+ } -+ -+ memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size); -+ -+ data->npuclk_freq = dev->m_table_v2.npuclk_freq; -+ for (i = 0; i < ARRAY_SIZE(data->npu_busy); i++) -+ data->npu_busy[i] = dev->m_table_v2.npu_busy[i]; -+ data->npu_power = dev->m_table_v2.npu_power; -+ data->mpnpuclk_freq = dev->m_table_v2.mpnpuclk_freq; -+ data->npu_reads = dev->m_table_v2.npu_reads; -+ data->npu_writes = dev->m_table_v2.npu_writes; -+ break; -+ case PCI_DEVICE_ID_AMD_1AH_M80H_ROOT: -+ ret = amd_pmf_get_metrics_table_log_sample(dev); -+ if (ret) -+ return ret; -+ -+ memcpy_fromio(&dev->mtable_v3, dev->metrics_table_virt, sizeof(dev->mtable_v3)); -+ -+ /* -+ * Ignore the first sample, as previous metrics is uninitialized (zero) -+ * Metrics are calculated as: -+ * metrics = current_metrics - previous_metrics -+ * Skipping the initial sample ensures accurate delta calculations. -+ */ -+ if (!dev->npu_metrics_have_prev) { -+ memcpy(&dev->prev_metrics, &dev->mtable_v3, sizeof(dev->mtable_v3)); -+ dev->npu_metrics_have_prev = true; -+ return 0; -+ } -+ -+ amd_pmf_calculate_acc_npu_metrics(dev, data); -+ memcpy(&dev->prev_metrics, &dev->mtable_v3, sizeof(dev->mtable_v3)); -+ break; -+ } -+ -+ return 0; -+} -+ -+int amd_pmf_get_npu_data(struct amd_pmf_npu_metrics *info) -+{ -+ struct amd_pmf_dev *pdev; -+ -+ if (!info) -+ return -EINVAL; -+ -+ if (!pmf_device) -+ return -ENODEV; -+ -+ pdev = dev_get_drvdata(pmf_device); -+ if (!pdev) -+ return -ENODEV; -+ -+ return amd_pmf_get_smu_metrics(pdev, info); -+} -+EXPORT_SYMBOL_NS_GPL(amd_pmf_get_npu_data, "AMD_PMF"); -diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h ---- a/drivers/platform/x86/amd/pmf/pmf.h -+++ b/drivers/platform/x86/amd/pmf/pmf.h -@@ -14,10 +14,13 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include - #include -+#include - - #define POLICY_BUF_MAX_SZ 0x4b000 - #define POLICY_SIGN_COOKIE 0x31535024 -@@ -28,6 +31,11 @@ - #define AMD_CPU_ID_PS 0x14e8 - #define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507 - #define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122 -+#define PCI_DEVICE_ID_AMD_1AH_M80H_ROOT 0x115b -+ -+/* Aliases required by PCI_DEVICE_DATA() macro naming convention */ -+#define PCI_DEVICE_ID_AMD_CPU_ID_RMB AMD_CPU_ID_RMB -+#define PCI_DEVICE_ID_AMD_CPU_ID_PS AMD_CPU_ID_PS - - struct cookie_header { - u32 sign; -@@ -70,6 +78,10 @@ struct cookie_header { - #define SET_PMF_PPT 0x25 - #define SET_PMF_PPT_APU_ONLY 0x26 - -+/* Message IDs for 1AH_M80H platform */ -+#define GET_1AH_M80H_METRICS_TABLE_LOG_SAMPLE 0x0E -+#define GET_1AH_M80H_METRICS_TABLE_DRAM_ADDR 0x0F -+ - /* OS slider update notification */ - #define DC_BEST_PERF 0 - #define DC_BETTER_PERF 1 -@@ -130,6 +142,14 @@ struct cookie_header { - #define GET_CMD true - - #define METRICS_TABLE_ID 7 -+#define BIOS_OUTPUT_MAX 10 -+ -+extern int metrics_table_loop_ms; -+ -+#define AMD_PMF_METRIC_CORE_TYPE_MAX 4 -+#define AMD_PMF_METRIC_CCX_MAX 4 -+#define AMD_PMF_NUM_CLK_DPM_LEVELS 8 -+#define AMD_PMF_NUM_MAX_CORES 12 - - typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data); - -@@ -242,6 +262,199 @@ struct apmf_fan_idx { - u32 fan_ctl_idx; - } __packed; - -+struct amd_pmf_metrics_iod { -+ u32 counter_acc; -+ /* Set Voltage */ -+ u64 vddcr_set_voltage; -+ u64 vddcr_soc_set_voltage; -+ u64 vddcr_npu_set_voltage; -+ u64 vddcr_lp_set_voltage; -+ u64 vddcr_gfx_set_voltage; -+ u64 vdd_misc_set_voltage; -+ /* Telemetry Voltages */ -+ u64 vddcr_telemetry_voltage; -+ u64 vddcr_soc_telemetry_voltage; -+ u64 vddcr_npu_telemetry_voltage; -+ u64 vddcr_lp_telemetry_voltage; -+ u64 vddcr_gfx_telemetry_voltage; -+ u64 vdd_misc_telemetry_voltage; -+ /* Telemetry Powers */ -+ u64 vddcr_telemetry_power; -+ u64 vddcr_soc_telemetry_power; -+ u64 vddcr_npu_telemetry_power; -+ u64 vddcr_lp_telemetry_power; -+ u64 vddcr_gfx_telemetry_power; -+ u64 vdd_misc_telemetry_power; -+ /* Throttlers - Fast PPT */ -+ u32 fppt_fused_limit; -+ u32 fppt_max_irm_limit; -+ u32 fppt_max_pbo_limit; -+ u32 fppt_limit; -+ u64 fppt_value_acc; -+ u32 fppt_residency_acc; -+ /* Throttlers - Slow PPT */ -+ u32 sppt_fused_limit; -+ u32 sppt_max_irm_limit; -+ u32 sppt_max_pbo_limit; -+ u32 sppt_limit; -+ u64 sppt_value_acc; -+ u32 sppt_residency_acc; -+ /* Throttlers - STAPM */ -+ u32 spl_fused_limit; -+ u32 spl_max_irm_limit; -+ u32 spl_max_pbo_limit; -+ u32 spl_limit; -+ u64 spl_value_acc; -+ u32 spl_residency_acc; -+ /* Throttlers - TDC VDDCR */ -+ u32 tdc_vddcr_fused_limit; -+ u32 tdc_vddcr_max_irm_limit; -+ u32 tdc_vddcr_max_pbo_limit; -+ u32 tdc_vddcr_limit; -+ u64 tdc_vddcr_value_acc; -+ u32 tdc_vddcr_residency_acc; -+ /* Throttlers - TDC VDDCR_SOC */ -+ u32 tdc_vddcr_soc_fused_limit; -+ u32 tdc_vddcr_soc_max_irm_limit; -+ u32 tdc_vddcr_soc_max_pbo_limit; -+ u32 tdc_vddcr_soc_limit; -+ u64 tdc_vddcr_soc_value_acc; -+ u32 tdc_vddcr_soc_residency_acc; -+ /* Throttlers - TDC VDDCR_NPU */ -+ u32 tdc_vddcr_npu_fused_limit; -+ u32 tdc_vddcr_npu_max_irm_limit; -+ u32 tdc_vddcr_npu_max_pbo_limit; -+ u32 tdc_vddcr_npu_limit; -+ u64 tdc_vddcr_npu_value_acc; -+ u32 tdc_vddcr_npu_residency_acc; -+ /* Throttlers - TDC VDDCR_LP */ -+ u32 tdc_vddcr_lp_fused_limit; -+ u32 tdc_vddcr_lp_max_irm_limit; -+ u32 tdc_vddcr_lp_max_pbo_limit; -+ u32 tdc_vddcr_lp_limit; -+ u64 tdc_vddcr_lp_value_acc; -+ u32 tdc_vddcr_lp_residency_acc; -+ /* Throttlers - TDC VDDCR_GFX */ -+ u32 tdc_vddcr_gfx_fused_limit; -+ u32 tdc_vddcr_gfx_max_irm_limit; -+ u32 tdc_vddcr_gfx_max_pbo_limit; -+ u32 tdc_vddcr_gfx_limit; -+ u64 tdc_vddcr_gfx_value_acc; -+ u32 tdc_vddcr_gfx_residency_acc; -+ /* Throttlers - EDC VDDCR */ -+ u32 edc_vddcr_fused_limit; -+ u32 edc_vddcr_max_irm_limit; -+ u32 edc_vddcr_max_pbo_limit; -+ u32 edc_vddcr_limit; -+ /* Throttlers - Thermal */ -+ u32 thm_fused_limit; -+ u32 thm_limit; -+ u64 thm_value_acc; -+ u32 thm_residency_acc; -+ u32 prochot_residency_acc; -+ u64 gfx_temp_acc; -+ u64 soc_temp_acc; -+ u32 p3t_fused_limit; -+ u64 p3t_value_acc; -+ /* Power */ -+ u64 system_power_acc; -+ u64 apu_power_acc; -+ u64 dgpu_power_acc; -+ u64 npu_power_acc; -+ /* Frequencies */ -+ u64 fclk_freq_eff_acc; -+ u64 memclk_freq_eff_acc; -+ u64 lclk_freq_eff_acc; -+ u64 gfxclk_freq_eff_acc; -+ u64 socclk_freq_eff_acc; -+ u64 vclk_freq_eff_acc; -+ u64 vpeclk_freq_eff_acc; -+ u64 aieclk_freq_eff_acc; -+ u64 npuhclk_freq_eff_acc; -+ /* Bandwidth */ -+ u64 dram_read_bandwidth; -+ u64 dram_write_bandwidth; -+ /* Activity Monitors */ -+ u64 gfx_busy_acc; -+ u64 vcn_busy_acc; -+ u64 npu_busy_acc[3]; -+ /* STT Limits */ -+ u32 stt_min_limit; -+ u64 stt_apu_hotspot_temp_acc; -+ u64 stt_hs2_hotspot_temp_acc; -+ u32 stt_apu_temp_limit; -+ u64 stt_apu_skin_temp_acc; -+ /* Residencies */ -+ u64 cpuoff_residency_ccx0; -+ u64 cpuoff_residency_ccx1; -+ u64 cpuoff_residency_ccx2; -+ u64 cpuoff_residency_ccx3; -+ /* DF-pstates */ -+ u32 fclk_freq_table[AMD_PMF_NUM_CLK_DPM_LEVELS]; -+ u32 uclk_freq_table[AMD_PMF_NUM_CLK_DPM_LEVELS]; -+ u32 ddr_rate_table[AMD_PMF_NUM_CLK_DPM_LEVELS]; -+ u8 dfpstate_source[AMD_PMF_NUM_CLK_DPM_LEVELS]; -+ /* System */ -+ u8 gfx_disabled; -+ u8 spare2[3]; -+ u32 gfxclk_fmax; -+ u8 cclk_core_fuse_enable[AMD_PMF_METRIC_CORE_TYPE_MAX][AMD_PMF_NUM_MAX_CORES]; -+ u8 cclk_core_enabled[AMD_PMF_METRIC_CORE_TYPE_MAX][AMD_PMF_NUM_MAX_CORES]; -+ u32 cclk_fmax[AMD_PMF_METRIC_CORE_TYPE_MAX][AMD_PMF_NUM_MAX_CORES]; -+ /* Overclock Capable */ -+ u8 cpu_precise_and_direct_oc_capable; -+ u8 gfx_precise_and_direct_oc_capable; -+ u8 pbo_basic_oc_capable; -+ u8 pbo_advanced_oc_capable; -+ u8 pbo_nitro_oc_capable; -+ u8 memory_and_fabric_oc_capable; -+ u8 misc_oc_capable; -+ u8 extreme_cold_oc_capable; -+ u8 down_config_control_capable; -+ u8 spare0[3]; -+ /* Overclock Status */ -+ u32 fit_limit_scalar; -+ u8 ln2_enabled; -+ u8 cpu_precise_and_direct_oc_enabled; -+ u8 gfx_precise_and_direct_oc_enabled; -+ u8 spare1[2]; -+ /* Voltage Guardband in PSM count */ -+ s8 psm_guardband[5][5][3]; -+ s32 core_power_limit_offset; -+ u32 max_freq_offset[5]; -+ u64 npu_temp_acc; -+ u64 dfpstate_residency_acc[AMD_PMF_NUM_CLK_DPM_LEVELS]; -+ u32 cclk_fboost; -+ /* PMF */ -+ u32 pmf_fast_apu_ppt_limit; -+ u64 pmf_fast_apu_ppt_value_acc; -+ u32 pmf_fast_apu_ppt_residency_acc; -+ u32 pmf_slow_apu_ppt_limit; -+ u64 pmf_slow_apu_ppt_value_acc; -+ u32 pmf_slow_apu_ppt_residency_acc; -+ u32 pmf_fast_spm_limit; -+ u64 pmf_fast_spm_value_acc; -+ u32 pmf_fast_spm_residency_acc; -+ u32 pmf_slow_spm_limit; -+ u64 pmf_slow_spm_value_acc; -+ u32 pmf_slow_spm_residency_acc; -+ u32 spare3[5]; -+} __packed __aligned(4); -+ -+struct amd_pmf_metrics_ccx { -+ u64 core_c0[AMD_PMF_NUM_MAX_CORES]; -+ u64 core_cc6[AMD_PMF_NUM_MAX_CORES]; -+ u64 core_freq[AMD_PMF_NUM_MAX_CORES]; -+ u64 core_freqeff[AMD_PMF_NUM_MAX_CORES]; -+ u64 core_temp[AMD_PMF_NUM_MAX_CORES]; -+ u64 core_power[AMD_PMF_NUM_MAX_CORES]; -+} __packed __aligned(4); -+ -+struct amd_pmf_metrics_v3 { -+ struct amd_pmf_metrics_iod iod; -+ struct amd_pmf_metrics_ccx ccx[AMD_PMF_METRIC_CCX_MAX]; -+} __packed __aligned(4); -+ - struct smu_pmf_metrics_v2 { - u16 core_frequency[16]; /* MHz */ - u16 core_power[16]; /* mW */ -@@ -391,6 +604,19 @@ struct pmf_cbi_ring_buffer { - int tail; - }; - -+/* SoC-specific SMU mailbox register offsets */ -+struct amd_pmf_smu_regs { -+ u32 msg_reg; -+ u32 resp_reg; -+ u32 arg_reg[3]; -+}; -+ -+struct amd_pmf_arg_data { -+ u32 lo; -+ u32 hi; -+ u32 size; -+}; -+ - struct amd_pmf_dev { - void __iomem *regbase; - void __iomem *smu_virt_addr; -@@ -442,6 +668,14 @@ struct amd_pmf_dev { - struct pmf_cbi_ring_buffer cbi_buf; - struct mutex cbi_mutex; /* Protects ring buffer access */ - struct mutex metrics_mutex; -+ u32 bios_output[BIOS_OUTPUT_MAX]; -+ const struct amd_pmf_smu_regs *smu_regs; -+ void __iomem *metrics_table_virt; /* Mapped DRAM virtual address for metrics table */ -+ phys_addr_t metrics_table_phys; /* DRAM physical address for metrics table */ -+ struct amd_pmf_metrics_v3 mtable_v3; /* IOD and CCX */ -+ struct amd_pmf_arg_data dram_addr; -+ struct amd_pmf_metrics_v3 prev_metrics; /* Previous metrics for delta calculation */ -+ bool npu_metrics_have_prev; - }; - - struct apmf_sps_prop_granular_v2 { -@@ -680,14 +914,6 @@ enum system_state { - SYSTEM_STATE_MAX, - }; - --enum ta_slider { -- TA_BEST_BATTERY, -- TA_BETTER_BATTERY, -- TA_BETTER_PERFORMANCE, -- TA_BEST_PERFORMANCE, -- TA_MAX, --}; -- - struct amd_pmf_pb_bitmap { - const char *name; - u32 bit_mask; -@@ -719,20 +945,6 @@ static const struct amd_pmf_pb_bitmap custom_bios_inputs_v1[] __used = { - {"NOTIFY_CUSTOM_BIOS_INPUT10", BIT(16)}, - }; - --enum platform_type { -- PTYPE_UNKNOWN = 0, -- LID_CLOSE, -- CLAMSHELL, -- FLAT, -- TENT, -- STAND, -- TABLET, -- BOOK, -- PRESENTATION, -- PULL_FWD, -- PTYPE_INVALID = 0xf, --}; -- - /* Command ids for TA communication */ - enum ta_pmf_command { - TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE, -@@ -871,6 +1083,10 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer); - int amd_pmf_notify_sbios_heartbeat_event_v2(struct amd_pmf_dev *dev, u8 flag); - u32 fixp_q88_fromint(u32 val); - int is_apmf_bios_input_notifications_supported(struct amd_pmf_dev *pdev); -+void amd_pmf_set_device(struct device *p_device); -+ -+/* Metrics layer */ -+int amd_pmf_get_tbl_dram_addr(struct amd_pmf_dev *dev); - - /* SPS Layer */ - int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf); -@@ -923,9 +1139,19 @@ int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq - void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in); - void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in); - int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev); -+u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index); - - int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid); - void amd_pmf_tee_deinit(struct amd_pmf_dev *dev); - int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev); - -+/* Util Layer */ -+#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT) -+int amd_pmf_cdev_register(struct amd_pmf_dev *dev); -+void amd_pmf_cdev_unregister(void); -+#else -+static inline int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; } -+static inline void amd_pmf_cdev_unregister(void) {} -+#endif -+ - #endif /* PMF_H */ -diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c ---- a/drivers/platform/x86/amd/pmf/spc.c -+++ b/drivers/platform/x86/amd/pmf/spc.c -@@ -10,6 +10,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -17,61 +18,7 @@ - #include "pmf.h" - - #ifdef CONFIG_AMD_PMF_DEBUG --static const char *platform_type_as_str(u16 platform_type) --{ -- switch (platform_type) { -- case CLAMSHELL: -- return "CLAMSHELL"; -- case FLAT: -- return "FLAT"; -- case TENT: -- return "TENT"; -- case STAND: -- return "STAND"; -- case TABLET: -- return "TABLET"; -- case BOOK: -- return "BOOK"; -- case PRESENTATION: -- return "PRESENTATION"; -- case PULL_FWD: -- return "PULL_FWD"; -- default: -- return "UNKNOWN"; -- } --} -- --static const char *laptop_placement_as_str(u16 device_state) --{ -- switch (device_state) { -- case ON_TABLE: -- return "ON_TABLE"; -- case ON_LAP_MOTION: -- return "ON_LAP_MOTION"; -- case IN_BAG: -- return "IN_BAG"; -- case OUT_OF_BAG: -- return "OUT_OF_BAG"; -- default: -- return "UNKNOWN"; -- } --} -- --static const char *ta_slider_as_str(unsigned int state) --{ -- switch (state) { -- case TA_BEST_PERFORMANCE: -- return "PERFORMANCE"; -- case TA_BETTER_PERFORMANCE: -- return "BALANCED"; -- case TA_BEST_BATTERY: -- return "POWER_SAVER"; -- default: -- return "Unknown TA Slider State"; -- } --} -- --static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index) -+u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index) - { - switch (index) { - case 0 ... 1: -@@ -82,13 +29,15 @@ static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int - return 0; - } - } -+EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs); - - void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) - { - int i; - - dev_dbg(dev->dev, "==== TA inputs START ====\n"); -- dev_dbg(dev->dev, "Slider State: %s\n", ta_slider_as_str(in->ev_info.power_slider)); -+ dev_dbg(dev->dev, "Slider State: %s\n", -+ amd_pmf_get_slider_position(in->ev_info.power_slider)); - dev_dbg(dev->dev, "Power Source: %s\n", amd_pmf_source_as_str(in->ev_info.power_source)); - dev_dbg(dev->dev, "Battery Percentage: %u\n", in->ev_info.bat_percentage); - dev_dbg(dev->dev, "Designed Battery Capacity: %u\n", in->ev_info.bat_design); -@@ -102,9 +51,10 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table * - dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open"); - dev_dbg(dev->dev, "User Presence: %s\n", in->ev_info.user_present ? "Present" : "Away"); - dev_dbg(dev->dev, "Ambient Light: %d\n", in->ev_info.ambient_light); -- dev_dbg(dev->dev, "Platform type: %s\n", platform_type_as_str(in->ev_info.platform_type)); -+ dev_dbg(dev->dev, "Platform type: %s\n", -+ amd_pmf_get_platform_type(in->ev_info.platform_type)); - dev_dbg(dev->dev, "Laptop placement: %s\n", -- laptop_placement_as_str(in->ev_info.device_state)); -+ amd_pmf_get_laptop_placement(in->ev_info.device_state)); - for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) - dev_dbg(dev->dev, "Custom BIOS input%d: %u\n", i + 1, - amd_pmf_get_ta_custom_bios_inputs(in, i)); -@@ -287,14 +237,14 @@ static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_ - switch (dev->current_profile) { - case PLATFORM_PROFILE_PERFORMANCE: - case PLATFORM_PROFILE_BALANCED_PERFORMANCE: -- val = TA_BEST_PERFORMANCE; -+ val = AMD_PMF_TA_BEST_PERFORMANCE; - break; - case PLATFORM_PROFILE_BALANCED: -- val = TA_BETTER_PERFORMANCE; -+ val = AMD_PMF_TA_BETTER_PERFORMANCE; - break; - case PLATFORM_PROFILE_LOW_POWER: - case PLATFORM_PROFILE_QUIET: -- val = TA_BEST_BATTERY; -+ val = AMD_PMF_TA_BEST_BATTERY; - break; - default: - dev_err(dev->dev, "Unknown Platform Profile.\n"); -diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c ---- a/drivers/platform/x86/amd/pmf/tee-if.c -+++ b/drivers/platform/x86/amd/pmf/tee-if.c -@@ -8,7 +8,9 @@ - * Author: Shyam Sundar S K - */ - -+#include - #include -+#include - #include - #include - #include "pmf.h" -@@ -97,11 +99,18 @@ static int amd_pmf_get_bios_output_idx(u32 action_idx) - - static void amd_pmf_update_bios_output(struct amd_pmf_dev *pdev, struct ta_pmf_action *action) - { -- u32 bios_idx; -+ int bios_idx; -+ int ret; - - bios_idx = amd_pmf_get_bios_output_idx(action->action_index); -+ if (bios_idx < 0 || bios_idx >= ARRAY_SIZE(pdev->bios_output)) { -+ dev_warn(pdev->dev, "BIOS output index %d out of bounds\n", bios_idx); -+ return; -+ } - -- amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx); -+ ret = amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx); -+ if (!ret) -+ pdev->bios_output[bios_idx] = action->value; - } - - static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out) -diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c -new file mode 100644 ---- /dev/null -+++ b/drivers/platform/x86/amd/pmf/util.c -@@ -0,0 +1,153 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * AMD Platform Management Framework Util Layer -+ * -+ * Copyright (c) 2026, Advanced Micro Devices, Inc. -+ * All Rights Reserved. -+ * -+ * Authors: Shyam Sundar S K -+ * Sanket Goswami -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "pmf.h" -+ -+static struct amd_pmf_dev *pmf_dev_handle; -+static DEFINE_MUTEX(pmf_util_lock); -+ -+static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info) -+{ -+ struct ta_pmf_shared_memory *ta_sm = NULL; -+ struct ta_pmf_enact_table *in = NULL; -+ int idx; -+ -+ if (!pdev || !info) -+ return -EINVAL; -+ -+ if (!pdev->shbuf) -+ return -EINVAL; -+ -+ ta_sm = pdev->shbuf; -+ in = &ta_sm->pmf_input.enact_table; -+ -+ /* Set size */ -+ info->size = sizeof(*info); -+ -+ /* PMF Feature support flags */ -+ if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE)) -+ info->features_supported |= AMD_PMF_FEAT_AUTO_MODE; -+ if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) -+ info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER; -+ if (pdev->smart_pc_enabled) -+ info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER; -+ if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC)) -+ info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC; -+ if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC)) -+ info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC; -+ -+ /* Device States */ -+ info->platform_type = in->ev_info.platform_type; -+ info->laptop_placement = in->ev_info.device_state; -+ info->lid_state = in->ev_info.lid_state; -+ info->user_presence = in->ev_info.user_present; -+ info->slider_position = in->ev_info.power_slider; -+ -+ /* Thermal and Power Metrics */ -+ info->power_source = in->ev_info.power_source; -+ info->skin_temp = in->ev_info.skin_temperature; -+ info->gfx_busy = in->ev_info.gfx_busy; -+ info->ambient_light = in->ev_info.ambient_light; -+ info->avg_c0_residency = in->ev_info.avg_c0residency; -+ info->max_c0_residency = in->ev_info.max_c0residency; -+ info->socket_power = in->ev_info.socket_power; -+ -+ /* Custom BIOS input parameters */ -+ for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++) -+ info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx); -+ -+ /* BIOS output parameters */ -+ for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++) -+ info->bios_output[idx] = pdev->bios_output[idx]; -+ -+ return 0; -+} -+ -+static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ struct amd_pmf_dev *pdev = filp->private_data; -+ void __user *argp = (void __user *)arg; -+ struct amd_pmf_info info = {}; -+ size_t copy_size; -+ __u64 user_size; -+ int ret; -+ -+ if (cmd != IOCTL_AMD_PMF_POPULATE_DATA) -+ return -ENOTTY; -+ -+ /* First read just the size field from userspace */ -+ if (copy_from_user(&user_size, argp, sizeof(user_size))) -+ return -EFAULT; -+ -+ guard(mutex)(&pmf_util_lock); -+ ret = amd_pmf_populate_data(pdev, &info); -+ if (ret) -+ return ret; -+ -+ copy_size = min_t(size_t, user_size, sizeof(info)); -+ -+ /* Set actual size being copied */ -+ info.size = copy_size; -+ -+ if (copy_to_user(argp, &info, copy_size)) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static int amd_pmf_open(struct inode *inode, struct file *filp) -+{ -+ guard(mutex)(&pmf_util_lock); -+ if (!pmf_dev_handle) -+ return -ENODEV; -+ -+ filp->private_data = pmf_dev_handle; -+ return 0; -+} -+ -+static const struct file_operations pmf_if_ops = { -+ .owner = THIS_MODULE, -+ .open = amd_pmf_open, -+ .unlocked_ioctl = amd_pmf_set_ioctl, -+}; -+ -+static struct miscdevice amd_pmf_util_if = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "amdpmf_interface", -+ .fops = &pmf_if_ops, -+}; -+ -+int amd_pmf_cdev_register(struct amd_pmf_dev *dev) -+{ -+ int ret; -+ -+ guard(mutex)(&pmf_util_lock); -+ pmf_dev_handle = dev; -+ ret = misc_register(&amd_pmf_util_if); -+ if (ret) -+ pmf_dev_handle = NULL; -+ -+ return ret; -+} -+ -+void amd_pmf_cdev_unregister(void) -+{ -+ guard(mutex)(&pmf_util_lock); -+ if (pmf_dev_handle) -+ misc_deregister(&amd_pmf_util_if); -+ pmf_dev_handle = NULL; -+} -diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c ---- a/drivers/platform/x86/asus-armoury.c -+++ b/drivers/platform/x86/asus-armoury.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -93,6 +94,8 @@ struct asus_armoury_priv { - - u32 mini_led_dev_id; - u32 gpu_mux_dev_id; -+ -+ bool requires_fan_curve; - }; - - static struct asus_armoury_priv asus_armoury = { -@@ -216,6 +219,22 @@ static int armoury_set_devstate(struct kobj_attribute *attr, - u32 result; - int err; - -+ /* On some models, PPT changes require an active fan curve */ -+ if (asus_armoury.requires_fan_curve) { -+ switch (dev_id) { -+ case ASUS_WMI_DEVID_PPT_PL1_SPL: -+ case ASUS_WMI_DEVID_PPT_PL2_SPPT: -+ case ASUS_WMI_DEVID_PPT_PL3_FPPT: -+ case ASUS_WMI_DEVID_PPT_APU_SPPT: -+ case ASUS_WMI_DEVID_PPT_PLAT_SPPT: -+ if (!asus_wmi_custom_fan_curve_is_enabled()) { -+ pr_warn_once("PPT change requires an active fan curve on this model. Enable a custom fan curve first.\n"); -+ return -EBUSY; -+ } -+ break; -+ } -+ } -+ - /* - * Prevent developers from bricking devices or issuing dangerous - * commands that can be difficult or impossible to recover from. -@@ -989,10 +1008,11 @@ static int asus_fw_attr_add(void) - /* Init / exit ****************************************************************/ - - /* Set up the min/max and defaults for ROG tunables */ --static void init_rog_tunables(void) -+static int init_rog_tunables(void) - { - const struct power_limits *ac_limits, *dc_limits; -- struct rog_tunables *ac_rog_tunables = NULL, *dc_rog_tunables = NULL; -+ struct rog_tunables *ac_rog_tunables __free(kfree) = NULL; -+ struct rog_tunables *dc_rog_tunables __free(kfree) = NULL; - const struct power_data *power_data; - const struct dmi_system_id *dmi_id; - -@@ -1000,24 +1020,25 @@ static void init_rog_tunables(void) - dmi_id = dmi_first_match(power_limits); - if (!dmi_id) { - pr_warn("No matching power limits found for this system\n"); -- return; -+ return 0; - } - - /* Get the power data for this system */ - power_data = dmi_id->driver_data; - if (!power_data) { - pr_info("No power data available for this system\n"); -- return; -+ return 0; - } - -+ asus_armoury.requires_fan_curve = power_data->requires_fan_curve; -+ - /* Initialize AC power tunables */ - ac_limits = power_data->ac_data; - if (ac_limits) { -- ac_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); -+ ac_rog_tunables = kzalloc_obj(*ac_rog_tunables); - if (!ac_rog_tunables) -- goto err_nomem; -+ return -ENOMEM; - -- asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables; - ac_rog_tunables->power_limits = ac_limits; - - /* Set initial AC values */ -@@ -1060,13 +1081,10 @@ static void init_rog_tunables(void) - /* Initialize DC power tunables */ - dc_limits = power_data->dc_data; - if (dc_limits) { -- dc_rog_tunables = kzalloc_obj(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); -- if (!dc_rog_tunables) { -- kfree(ac_rog_tunables); -- goto err_nomem; -- } -+ dc_rog_tunables = kzalloc_obj(*dc_rog_tunables); -+ if (!dc_rog_tunables) -+ return -ENOMEM; - -- asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables; - dc_rog_tunables->power_limits = dc_limits; - - /* Set initial DC values */ -@@ -1106,15 +1124,16 @@ static void init_rog_tunables(void) - pr_debug("No DC PPT limits defined\n"); - } - -- return; -+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = no_free_ptr(ac_rog_tunables); -+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = no_free_ptr(dc_rog_tunables); - --err_nomem: -- pr_err("Failed to allocate memory for tunables\n"); -+ return 0; - } - - static int __init asus_fw_init(void) - { - char *wmi_uid; -+ int err; - - wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); - if (!wmi_uid) -@@ -1127,10 +1146,21 @@ static int __init asus_fw_init(void) - if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) - return -ENODEV; - -- init_rog_tunables(); -+ err = init_rog_tunables(); -+ if (err) -+ return err; - - /* Must always be last step to ensure data is available */ -- return asus_fw_attr_add(); -+ err = asus_fw_attr_add(); -+ if (err) -+ goto err_free_tunables; -+ -+ return 0; -+ -+err_free_tunables: -+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); -+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); -+ return err; - } - - static void __exit asus_fw_exit(void) -diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h ---- a/drivers/platform/x86/asus-armoury.h -+++ b/drivers/platform/x86/asus-armoury.h -@@ -369,6 +369,38 @@ static const struct dmi_system_id power_limits[] = { - }, - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA401KM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .nv_dynamic_boost_max = 15, -+ .nv_dynamic_boost_min = 5, -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .nv_tgp_max = 95, -+ .nv_tgp_min = 55, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ }, -+ .dc_data = &(struct power_limits) { -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl2_sppt_max = 44, -+ .ppt_pl2_sppt_min = 31, -+ .ppt_pl3_fppt_max = 65, -+ .ppt_pl3_fppt_min = 45, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, - { - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "FA401UM"), -@@ -754,6 +786,40 @@ static const struct dmi_system_id power_limits[] = { - }, - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA608WV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .nv_dynamic_boost_max = 25, -+ .nv_dynamic_boost_min = 5, -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .nv_tgp_max = 115, -+ .nv_tgp_min = 55, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl2_sppt_max = 90, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl3_fppt_max = 90, -+ .ppt_pl3_fppt_min = 35, -+ }, -+ .dc_data = &(struct power_limits) { -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, - { - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "FA617NS"), -@@ -909,6 +975,32 @@ static const struct dmi_system_id power_limits[] = { - .requires_fan_curve = true, - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FX517ZR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, - { - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "FX607VU"), -@@ -2079,6 +2171,35 @@ static const struct dmi_system_id power_limits[] = { - .requires_fan_curve = true, - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G635LX"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 140, -+ .ppt_pl1_spl_max = 175, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 80, -+ .nv_tgp_max = 150, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, - { - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "G713PV"), -@@ -2322,6 +2443,35 @@ static const struct dmi_system_id power_limits[] = { - }, - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "HN7306EA"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 35, -+ .ppt_pl1_spl_def = 60, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 40, -+ .ppt_pl2_sppt_def = 70, -+ .ppt_pl2_sppt_max = 95, -+ .ppt_pl3_fppt_min = 50, -+ .ppt_pl3_fppt_def = 85, -+ .ppt_pl3_fppt_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 35, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 60, -+ .ppt_pl2_sppt_min = 40, -+ .ppt_pl2_sppt_def = 55, -+ .ppt_pl2_sppt_max = 70, -+ .ppt_pl3_fppt_min = 50, -+ .ppt_pl3_fppt_def = 65, -+ .ppt_pl3_fppt_max = 85, -+ }, -+ }, -+ }, - { - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "RC71"), -diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c ---- a/drivers/platform/x86/asus-laptop.c -+++ b/drivers/platform/x86/asus-laptop.c -@@ -42,8 +42,6 @@ - #define ASUS_LAPTOP_VERSION "0.42" - - #define ASUS_LAPTOP_NAME "Asus Laptop Support" --#define ASUS_LAPTOP_CLASS "hotkey" --#define ASUS_LAPTOP_DEVICE_NAME "Hotkey" - #define ASUS_LAPTOP_FILE KBUILD_MODNAME - #define ASUS_LAPTOP_PREFIX "\\_SB.ATKD." - -@@ -1524,9 +1522,8 @@ static void asus_acpi_notify(acpi_handle handle, u32 event, void *data) - - /* TODO Find a better way to handle events count. */ - count = asus->event_count[event % 128]++; -- acpi_bus_generate_netlink_event(asus->device->pnp.device_class, -- dev_name(&asus->device->dev), event, -- count); -+ acpi_bus_generate_netlink_event("hotkey", dev_name(&asus->device->dev), -+ event, count); - - if (event >= ATKD_BRNUP_MIN && event <= ATKD_BRNUP_MAX) - event = ATKD_BRNUP; -@@ -1840,8 +1837,6 @@ static int asus_acpi_probe(struct platform_device *pdev) - if (!asus) - return -ENOMEM; - asus->handle = device->handle; -- strscpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME); -- strscpy(acpi_device_class(device), ASUS_LAPTOP_CLASS); - asus->device = device; - - asus_dmi_check(); -diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c ---- a/drivers/platform/x86/asus-nb-wmi.c -+++ b/drivers/platform/x86/asus-nb-wmi.c -@@ -632,6 +632,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { - { KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */ - { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ - { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ -+ { KE_KEY, 0x8B, { KEY_PROG3 } }, /* ProArt key (PX13/HN7306) */ - { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */ - { KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */ - { KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */ -diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c ---- a/drivers/platform/x86/asus-wmi.c -+++ b/drivers/platform/x86/asus-wmi.c -@@ -4073,6 +4073,30 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) - return 0; - } - -+/* -+ * Returns true if at least one custom fan curve is active -+ * -+ * Used by asus-armoury to check if PPT writes will be accepted by the BIOS -+ * on models that require an active fan curve for TDP changes. -+ */ -+bool asus_wmi_custom_fan_curve_is_enabled(void) -+{ -+ struct fan_curve_data *curves; -+ struct asus_wmi *asus; -+ -+ guard(spinlock_irqsave)(&asus_ref.lock); -+ asus = asus_ref.asus; -+ if (!asus) -+ return false; -+ -+ curves = asus->custom_fan_curves; -+ -+ return (asus->cpu_fan_curve_available && curves[FAN_CURVE_DEV_CPU].enabled) || -+ (asus->gpu_fan_curve_available && curves[FAN_CURVE_DEV_GPU].enabled) || -+ (asus->mid_fan_curve_available && curves[FAN_CURVE_DEV_MID].enabled); -+} -+EXPORT_SYMBOL_NS_GPL(asus_wmi_custom_fan_curve_is_enabled, "ASUS_WMI"); -+ - /* Throttle thermal policy ****************************************************/ - static int throttle_thermal_policy_write(struct asus_wmi *asus) - { -diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c ---- a/drivers/platform/x86/dell/dell-smbios-base.c -+++ b/drivers/platform/x86/dell/dell-smbios-base.c -@@ -40,7 +40,7 @@ struct smbios_device { - struct list_head list; - struct device *device; - int priority; -- int (*call_fn)(struct calling_interface_buffer *arg); -+ smbios_callback_fn_t call_fn; - }; - - struct smbios_call { -@@ -146,7 +146,7 @@ int dell_smbios_error(int value) - } - EXPORT_SYMBOL_GPL(dell_smbios_error); - --int dell_smbios_register_device(struct device *d, int priority, void *call_fn) -+int dell_smbios_register_device(struct device *d, int priority, smbios_callback_fn_t call_fn) - { - struct smbios_device *priv; - -@@ -312,7 +312,7 @@ int dell_smbios_call(struct calling_interface_buffer *buffer) - goto out_smbios_call; - } - -- ret = selected->call_fn(buffer); -+ ret = selected->call_fn(selected->device, buffer); - - out_smbios_call: - mutex_unlock(&smbios_mutex); -diff --git a/drivers/platform/x86/dell/dell-smbios-smm.c b/drivers/platform/x86/dell/dell-smbios-smm.c ---- a/drivers/platform/x86/dell/dell-smbios-smm.c -+++ b/drivers/platform/x86/dell/dell-smbios-smm.c -@@ -49,7 +49,7 @@ static void find_cmd_address(const struct dmi_header *dm, void *dummy) - } - } - --static int dell_smbios_smm_call(struct calling_interface_buffer *input) -+static int dell_smbios_smm_call(struct device *dev, struct calling_interface_buffer *input) - { - struct smi_cmd command; - size_t size; -@@ -70,7 +70,7 @@ static int dell_smbios_smm_call(struct calling_interface_buffer *input) - } - - /* When enabled this indicates that SMM won't work */ --static bool test_wsmt_enabled(void) -+static bool test_wsmt_enabled(struct device *dev) - { - struct calling_interface_token *wsmt; - -@@ -88,7 +88,7 @@ static bool test_wsmt_enabled(void) - memset(buffer, 0, sizeof(struct calling_interface_buffer)); - buffer->input[0] = wsmt->location; - buffer->output[0] = 99; -- dell_smbios_smm_call(buffer); -+ dell_smbios_smm_call(dev, buffer); - if (buffer->output[0] == 99) - return true; - -@@ -109,7 +109,7 @@ int init_dell_smbios_smm(void) - - dmi_walk(find_cmd_address, NULL); - -- if (test_wsmt_enabled()) { -+ if (test_wsmt_enabled(&platform_device->dev)) { - pr_debug("Disabling due to WSMT enabled\n"); - ret = -ENODEV; - goto fail_wsmt; -diff --git a/drivers/platform/x86/dell/dell-smbios-wmi.c b/drivers/platform/x86/dell/dell-smbios-wmi.c ---- a/drivers/platform/x86/dell/dell-smbios-wmi.c -+++ b/drivers/platform/x86/dell/dell-smbios-wmi.c -@@ -6,21 +6,20 @@ - */ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -+#include - #include - #include - #include --#include - #include - #include - #include -+#include - #include - #include - #include - #include "dell-smbios.h" - #include "dell-wmi-descriptor.h" - --static DEFINE_MUTEX(call_mutex); --static DEFINE_MUTEX(list_mutex); - static int wmi_supported; - - struct misc_bios_flags_structure { -@@ -32,21 +31,16 @@ struct misc_bios_flags_structure { - #define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" - - struct wmi_smbios_priv { -+ struct mutex call_lock; /* Protects the content of the SMBIOS buffer */ - struct dell_wmi_smbios_buffer *buf; -- struct list_head list; - struct wmi_device *wdev; - struct device *child; - u64 req_buf_size; - struct miscdevice char_dev; - }; --static LIST_HEAD(wmi_list); - --static inline struct wmi_smbios_priv *get_first_smbios_priv(void) --{ -- return list_first_entry_or_null(&wmi_list, -- struct wmi_smbios_priv, -- list); --} -+static DECLARE_RWSEM(chardev_lock); /* Protects chardev_priv */ -+static struct wmi_smbios_priv *chardev_priv; - - static int run_smbios_call(struct wmi_device *wdev) - { -@@ -80,50 +74,36 @@ static int run_smbios_call(struct wmi_device *wdev) - return 0; - } - --static int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) -+static int dell_smbios_wmi_call(struct device *dev, struct calling_interface_buffer *buffer) - { -- struct wmi_smbios_priv *priv; -+ struct wmi_smbios_priv *priv = dev_get_drvdata(dev); - size_t difference; - size_t size; - int ret; - -- mutex_lock(&call_mutex); -- priv = get_first_smbios_priv(); -- if (!priv) { -- ret = -ENODEV; -- goto out_wmi_call; -- } -- - size = sizeof(struct calling_interface_buffer); - difference = priv->req_buf_size - sizeof(u64) - size; - -+ guard(mutex)(&priv->call_lock); -+ - memset(&priv->buf->ext, 0, difference); - memcpy(&priv->buf->std, buffer, size); - ret = run_smbios_call(priv->wdev); - memcpy(buffer, &priv->buf->std, size); --out_wmi_call: -- mutex_unlock(&call_mutex); - - return ret; - } - --static int dell_smbios_wmi_open(struct inode *inode, struct file *filp) --{ -- struct wmi_smbios_priv *priv; -- -- priv = container_of(filp->private_data, struct wmi_smbios_priv, char_dev); -- filp->private_data = priv; -- -- return nonseekable_open(inode, filp); --} -- - static ssize_t dell_smbios_wmi_read(struct file *filp, char __user *buffer, size_t length, - loff_t *offset) - { -- struct wmi_smbios_priv *priv = filp->private_data; -+ guard(rwsem_read)(&chardev_lock); - -- return simple_read_from_buffer(buffer, length, offset, &priv->req_buf_size, -- sizeof(priv->req_buf_size)); -+ if (!chardev_priv) -+ return -ENODEV; -+ -+ return simple_read_from_buffer(buffer, length, offset, &chardev_priv->req_buf_size, -+ sizeof(chardev_priv->req_buf_size)); - } - - static long dell_smbios_wmi_do_ioctl(struct wmi_smbios_priv *priv, -@@ -167,22 +147,22 @@ static long dell_smbios_wmi_do_ioctl(struct wmi_smbios_priv *priv, - static long dell_smbios_wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { - struct dell_wmi_smbios_buffer __user *input = (struct dell_wmi_smbios_buffer __user *)arg; -- struct wmi_smbios_priv *priv = filp->private_data; -- long ret; - - if (cmd != DELL_WMI_SMBIOS_CMD) - return -ENOIOCTLCMD; - -- mutex_lock(&call_mutex); -- ret = dell_smbios_wmi_do_ioctl(priv, input); -- mutex_unlock(&call_mutex); -+ guard(rwsem_read)(&chardev_lock); - -- return ret; -+ if (!chardev_priv) -+ return -ENODEV; -+ -+ guard(mutex)(&chardev_priv->call_lock); -+ -+ return dell_smbios_wmi_do_ioctl(chardev_priv, input); - } - - static const struct file_operations dell_smbios_wmi_fops = { - .owner = THIS_MODULE, -- .open = dell_smbios_wmi_open, - .read = dell_smbios_wmi_read, - .unlocked_ioctl = dell_smbios_wmi_ioctl, - .compat_ioctl = compat_ptr_ioctl, -@@ -195,10 +175,29 @@ static void dell_smbios_wmi_unregister_chardev(void *data) - misc_deregister(char_dev); - } - -+static void dell_smbios_wmi_clear_chardev(void *data) -+{ -+ guard(rwsem_write)(&chardev_lock); -+ -+ chardev_priv = NULL; -+} -+ - static int dell_smbios_wmi_register_chardev(struct wmi_smbios_priv *priv) - { - int ret; - -+ scoped_guard(rwsem_write, &chardev_lock) { -+ /* We can only have a single chardev at a time */ -+ if (chardev_priv) -+ return -EBUSY; -+ -+ chardev_priv = priv; -+ } -+ -+ ret = devm_add_action_or_reset(&priv->wdev->dev, dell_smbios_wmi_clear_chardev, NULL); -+ if (ret < 0) -+ return ret; -+ - priv->char_dev.minor = MISC_DYNAMIC_MINOR; - priv->char_dev.name = "wmi/dell-smbios"; - priv->char_dev.fops = &dell_smbios_wmi_fops; -@@ -254,31 +253,20 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context) - if (!priv->buf) - return -ENOMEM; - -+ ret = devm_mutex_init(&wdev->dev, &priv->call_lock); -+ if (ret) -+ return ret; -+ - ret = dell_smbios_wmi_register_chardev(priv); - if (ret) - return ret; - -- ret = dell_smbios_register_device(&wdev->dev, 1, &dell_smbios_wmi_call); -- if (ret) -- return ret; -- -- mutex_lock(&list_mutex); -- list_add_tail(&priv->list, &wmi_list); -- mutex_unlock(&list_mutex); -- -- return 0; -+ return dell_smbios_register_device(&wdev->dev, 1, &dell_smbios_wmi_call); - } - - static void dell_smbios_wmi_remove(struct wmi_device *wdev) - { -- struct wmi_smbios_priv *priv = dev_get_drvdata(&wdev->dev); -- -- mutex_lock(&call_mutex); -- mutex_lock(&list_mutex); -- list_del(&priv->list); -- mutex_unlock(&list_mutex); - dell_smbios_unregister_device(&wdev->dev); -- mutex_unlock(&call_mutex); - } - - static const struct wmi_device_id dell_smbios_wmi_id_table[] = { -@@ -316,6 +304,7 @@ static struct wmi_driver dell_smbios_wmi_driver = { - .probe = dell_smbios_wmi_probe, - .remove = dell_smbios_wmi_remove, - .id_table = dell_smbios_wmi_id_table, -+ .no_singleton = true, - }; - - int init_dell_smbios_wmi(void) -diff --git a/drivers/platform/x86/dell/dell-smbios.h b/drivers/platform/x86/dell/dell-smbios.h ---- a/drivers/platform/x86/dell/dell-smbios.h -+++ b/drivers/platform/x86/dell/dell-smbios.h -@@ -47,6 +47,8 @@ - - struct notifier_block; - -+typedef int (*smbios_callback_fn_t)(struct device *dev, struct calling_interface_buffer *buffer); -+ - struct calling_interface_token { - u16 tokenID; - u16 location; -@@ -64,7 +66,7 @@ struct calling_interface_structure { - struct calling_interface_token tokens[]; - } __packed; - --int dell_smbios_register_device(struct device *d, int priority, void *call_fn); -+int dell_smbios_register_device(struct device *d, int priority, smbios_callback_fn_t call_fn); - void dell_smbios_unregister_device(struct device *d); - - int dell_smbios_error(int value); -diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c ---- a/drivers/platform/x86/dell/dell-wmi-ddv.c -+++ b/drivers/platform/x86/dell/dell-wmi-ddv.c -@@ -196,40 +196,30 @@ static int dell_wmi_ddv_query_integer(struct wmi_device *wdev, enum dell_ddv_met - static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_method method, - u32 arg, struct dell_wmi_buffer **result) - { -- struct dell_wmi_buffer *buffer; - struct wmi_buffer output; - size_t buffer_size; - int ret; - -- ret = dell_wmi_ddv_query(wdev, method, arg, &output, sizeof(*buffer)); -+ ret = dell_wmi_ddv_query(wdev, method, arg, &output, sizeof(struct dell_wmi_buffer)); - if (ret < 0) - return ret; - -- buffer = output.data; -- if (!le32_to_cpu(buffer->raw_size)) { -- ret = -ENODATA; -+ struct dell_wmi_buffer *buffer __free(kfree) = output.data; - -- goto err_free; -- } -+ if (!le32_to_cpu(buffer->raw_size)) -+ return -ENODATA; - - buffer_size = struct_size(buffer, raw_data, le32_to_cpu(buffer->raw_size)); - if (buffer_size > output.length) { - dev_warn(&wdev->dev, - FW_WARN "Dell WMI buffer size (%zu) exceeds WMI buffer size (%zu)\n", - buffer_size, output.length); -- ret = -EMSGSIZE; -- -- goto err_free; -+ return -EMSGSIZE; - } - -- *result = buffer; -+ *result = no_free_ptr(buffer); - - return 0; -- --err_free: -- kfree(output.data); -- -- return ret; - } - - static ssize_t dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method, -diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c ---- a/drivers/platform/x86/eeepc-laptop.c -+++ b/drivers/platform/x86/eeepc-laptop.c -@@ -34,8 +34,6 @@ - #define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver" - #define EEEPC_LAPTOP_FILE "eeepc" - --#define EEEPC_ACPI_CLASS "hotkey" --#define EEEPC_ACPI_DEVICE_NAME "Hotkey" - #define EEEPC_ACPI_HID "ASUS010" - - MODULE_AUTHOR("Corentin Chary, Eric Cooper"); -@@ -1214,8 +1212,7 @@ static void eeepc_acpi_notify(acpi_handle handle, u32 event, void *data) - if (event > ACPI_MAX_SYS_NOTIFY) - return; - count = eeepc->event_count[event % 128]++; -- acpi_bus_generate_netlink_event(device->pnp.device_class, -- dev_name(&device->dev), event, -+ acpi_bus_generate_netlink_event("hotkey", dev_name(&device->dev), event, - count); - - /* Brightness events are special */ -@@ -1376,8 +1373,6 @@ static int eeepc_acpi_probe(struct platform_device *pdev) - if (!eeepc) - return -ENOMEM; - eeepc->handle = device->handle; -- strscpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); -- strscpy(acpi_device_class(device), EEEPC_ACPI_CLASS); - eeepc->device = device; - - platform_set_drvdata(pdev, eeepc); -diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c ---- a/drivers/platform/x86/fujitsu-laptop.c -+++ b/drivers/platform/x86/fujitsu-laptop.c -@@ -56,7 +56,6 @@ - - #define FUJITSU_LCD_N_LEVELS 8 - --#define ACPI_FUJITSU_CLASS "fujitsu" - #define ACPI_FUJITSU_BL_HID "FUJ02B1" - #define ACPI_FUJITSU_BL_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver" - #define ACPI_FUJITSU_BL_DEVICE_NAME "Fujitsu FUJ02B1" -@@ -466,7 +465,7 @@ static int acpi_fujitsu_bl_input_setup(struct device *dev) - snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0", - acpi_device_hid(device)); - -- priv->input->name = acpi_device_name(device); -+ priv->input->name = ACPI_FUJITSU_BL_DEVICE_NAME; - priv->input->phys = priv->phys; - priv->input->id.bustype = BUS_HOST; - priv->input->id.product = 0x06; -@@ -546,13 +545,11 @@ static int acpi_fujitsu_bl_probe(struct platform_device *pdev) - return -ENOMEM; - - fujitsu_bl = priv; -- strscpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME); -- strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); - - platform_set_drvdata(pdev, priv); - -- pr_info("ACPI: %s [%s]\n", -- acpi_device_name(device), acpi_device_bid(device)); -+ pr_info("ACPI: %s [%s]\n", ACPI_FUJITSU_BL_DEVICE_NAME, -+ acpi_device_bid(device)); - - if (get_max_brightness(&pdev->dev) <= 0) - priv->max_brightness = FUJITSU_LCD_N_LEVELS; -@@ -681,7 +678,7 @@ static int acpi_fujitsu_laptop_input_setup(struct device *dev) - snprintf(priv->phys, sizeof(priv->phys), "%s/input0", - acpi_device_hid(device)); - -- priv->input->name = acpi_device_name(device); -+ priv->input->name = ACPI_FUJITSU_LAPTOP_DEVICE_NAME; - priv->input->phys = priv->phys; - priv->input->id.bustype = BUS_HOST; - -@@ -1012,9 +1009,6 @@ static int acpi_fujitsu_laptop_probe(struct platform_device *pdev) - WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended."); - fext = &pdev->dev; - -- strscpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME); -- strscpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); -- - platform_set_drvdata(pdev, priv); - - /* kfifo */ -@@ -1024,8 +1018,8 @@ static int acpi_fujitsu_laptop_probe(struct platform_device *pdev) - if (ret) - return ret; - -- pr_info("ACPI: %s [%s]\n", -- acpi_device_name(device), acpi_device_bid(device)); -+ pr_info("ACPI: %s [%s]\n", ACPI_FUJITSU_LAPTOP_DEVICE_NAME, -+ acpi_device_bid(device)); - - while (call_fext_func(fext, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && - i++ < MAX_HOTKEY_RINGBUFFER_SIZE) -diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c ---- a/drivers/platform/x86/fujitsu-tablet.c -+++ b/drivers/platform/x86/fujitsu-tablet.c -@@ -22,8 +22,6 @@ - - #define MODULENAME "fujitsu-tablet" - --#define ACPI_FUJITSU_CLASS "fujitsu" -- - #define INVERT_TABLET_MODE_BIT 0x01 - #define INVERT_DOCK_STATE_BIT 0x02 - #define FORCE_TABLET_MODE_IF_UNDOCK 0x04 -@@ -160,6 +158,7 @@ static struct { - struct fujitsu_config config; - unsigned long prev_keymask; - -+ char name[17]; - char phys[21]; - - int irq; -@@ -458,14 +457,10 @@ static int acpi_fujitsu_probe(struct platform_device *pdev) - if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base) - return -ENODEV; - -- sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev)); -- sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS); -+ scnprintf(fujitsu.name, sizeof(fujitsu.name), "Fujitsu %s", acpi_device_hid(adev)); -+ scnprintf(fujitsu.phys, sizeof(fujitsu.phys), "%s/input0", acpi_device_hid(adev)); - -- snprintf(fujitsu.phys, sizeof(fujitsu.phys), -- "%s/input0", acpi_device_hid(adev)); -- -- error = input_fujitsu_setup(&pdev->dev, -- acpi_device_name(adev), fujitsu.phys); -+ error = input_fujitsu_setup(&pdev->dev, fujitsu.name, fujitsu.phys); - if (error) - return error; - -diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c ---- a/drivers/platform/x86/hp/hp-wmi.c -+++ b/drivers/platform/x86/hp/hp-wmi.c -@@ -14,6 +14,8 @@ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - - #include -+#include -+#include - #include - #include - #include -@@ -23,6 +25,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -58,6 +61,12 @@ enum hp_ec_offsets { - #define HP_FAN_SPEED_AUTOMATIC 0x00 - #define HP_POWER_LIMIT_DEFAULT 0x00 - #define HP_POWER_LIMIT_NO_CHANGE 0xFF -+#define HPWMI_MUX_MODE_UMA BIT(0) -+#define HPWMI_MUX_MODE_HYBRID BIT(1) -+#define HPWMI_MUX_MODE_DISCRETE BIT(2) -+#define HPWMI_MUX_MODE_OPTIMUS BIT(3) -+#define HPWMI_MUX_MODE_MASK GENMASK(6, 0) -+#define HPWMI_MUX_LEGACY_MASK (HPWMI_MUX_MODE_HYBRID | HPWMI_MUX_MODE_DISCRETE) - - #define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required - -@@ -133,24 +142,41 @@ static const struct thermal_profile_params omen_v1_no_ec_thermal_params = { - .ec_tp_offset = HP_NO_THERMAL_PROFILE_OFFSET, - }; - -+struct hp_wmi_fan_profile_params { -+ int (*get_fan_speed)(int fan); -+ bool fan_table; -+}; -+ - struct hp_wmi_board_params { - const struct thermal_profile_params *thermal_profile; -+ const struct hp_wmi_fan_profile_params *fan_profile; -+}; -+ -+static int hp_wmi_get_fan_speed_victus_s(int fan); -+ -+static const struct hp_wmi_fan_profile_params victus_s_fan_profile_params = { -+ .get_fan_speed = hp_wmi_get_fan_speed_victus_s, -+ .fan_table = true, - }; - - static const struct hp_wmi_board_params victus_s_board_params = { - .thermal_profile = &victus_s_thermal_params, -+ .fan_profile = &victus_s_fan_profile_params, - }; - - static const struct hp_wmi_board_params omen_v1_board_params = { - .thermal_profile = &omen_v1_thermal_params, -+ .fan_profile = &victus_s_fan_profile_params, - }; - - static const struct hp_wmi_board_params omen_v1_legacy_board_params = { - .thermal_profile = &omen_v1_legacy_thermal_params, -+ .fan_profile = &victus_s_fan_profile_params, - }; - - static const struct hp_wmi_board_params omen_v1_no_ec_board_params = { - .thermal_profile = &omen_v1_no_ec_thermal_params, -+ .fan_profile = &victus_s_fan_profile_params, - }; - - static const struct hp_wmi_board_params *active_board_params; -@@ -181,7 +207,7 @@ static const char * const omen_thermal_profile_boards[] = { - "886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6", - "88F7", "88FD", "88FE", "88FF", - "8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB", -- "8A15", "8A42", -+ "8A15", "8A42", "8A43", - "8BAD", - "8C58", - "8E41", -@@ -217,6 +243,10 @@ static const struct dmi_system_id hp_wmi_feature_boards[] __initconst = { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8902") }, - .driver_data = (void *)&omen_v1_legacy_board_params, - }, -+ { -+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A3D") }, -+ .driver_data = (void *)&victus_s_board_params, -+ }, - { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A44") }, - .driver_data = (void *)&omen_v1_legacy_board_params, -@@ -225,6 +255,14 @@ static const struct dmi_system_id hp_wmi_feature_boards[] __initconst = { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A4D") }, - .driver_data = (void *)&omen_v1_legacy_board_params, - }, -+ { -+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BAA") }, -+ .driver_data = (void *)&omen_v1_board_params, -+ }, -+ { -+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BA9") }, -+ .driver_data = (void *)&omen_v1_board_params, -+ }, - { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BAB") }, - .driver_data = (void *)&omen_v1_board_params, -@@ -233,6 +271,10 @@ static const struct dmi_system_id hp_wmi_feature_boards[] __initconst = { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8B2F") }, - .driver_data = (void *)&victus_s_board_params, - }, -+ { -+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BB3") }, -+ .driver_data = (void *)&omen_v1_no_ec_board_params, -+ }, - { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BBE") }, - .driver_data = (void *)&victus_s_board_params, -@@ -289,6 +331,10 @@ static const struct dmi_system_id hp_wmi_feature_boards[] __initconst = { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D87") }, - .driver_data = (void *)&omen_v1_no_ec_board_params, - }, -+ { -+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8D88") }, -+ .driver_data = (void *)&omen_v1_no_ec_board_params, -+ }, - { - .matches = { DMI_MATCH(DMI_BOARD_NAME, "8DD6") }, - .driver_data = (void *)&omen_v1_no_ec_board_params, -@@ -360,6 +406,7 @@ enum hp_wmi_commandtype { - HPWMI_POSTCODEERROR_QUERY = 0x2a, - HPWMI_SYSTEM_DEVICE_MODE = 0x40, - HPWMI_THERMAL_PROFILE_QUERY = 0x4c, -+ HPWMI_GRAPHICS_MUX_QUERY = 0x52, - }; - - struct victus_power_limits { -@@ -528,9 +575,9 @@ struct hp_wmi_hwmon_priv { - struct mutex lock; /* protects mode, pwm */ - u8 min_rpm; - u8 max_rpm; -- int gpu_delta; - u8 mode; -- u8 pwm; -+ u8 cpu_pwm; -+ u8 gpu_pwm; - struct delayed_work keep_alive_dwork; - }; - -@@ -857,24 +904,20 @@ static int hp_wmi_fan_speed_max_set(int enabled) - return enabled; - } - --static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv, u8 speed) -+static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv) - { - u8 fan_speed[2]; -- int gpu_speed, ret; -+ int ret; - -- fan_speed[CPU_FAN] = speed; -- fan_speed[GPU_FAN] = speed; -+ if (priv->cpu_pwm == HP_FAN_SPEED_AUTOMATIC) -+ fan_speed[CPU_FAN] = HP_FAN_SPEED_AUTOMATIC; -+ else -+ fan_speed[CPU_FAN] = pwm_to_rpm(priv->cpu_pwm, priv); - -- /* -- * GPU fan speed is always a little higher than CPU fan speed, we fetch -- * this delta value from the fan table during hwmon init. -- * Exception: Speed is set to HP_FAN_SPEED_AUTOMATIC, to revert to -- * automatic mode. -- */ -- if (speed != HP_FAN_SPEED_AUTOMATIC) { -- gpu_speed = speed + priv->gpu_delta; -- fan_speed[GPU_FAN] = clamp_val(gpu_speed, 0, U8_MAX); -- } -+ if (priv->gpu_pwm == HP_FAN_SPEED_AUTOMATIC) -+ fan_speed[GPU_FAN] = HP_FAN_SPEED_AUTOMATIC; -+ else -+ fan_speed[GPU_FAN] = pwm_to_rpm(priv->gpu_pwm, priv); - - ret = hp_wmi_get_fan_count_userdefine_trigger(); - if (ret < 0) -@@ -891,7 +934,9 @@ static int hp_wmi_fan_speed_set(struct hp_wmi_hwmon_priv *priv, u8 speed) - - static int hp_wmi_fan_speed_reset(struct hp_wmi_hwmon_priv *priv) - { -- return hp_wmi_fan_speed_set(priv, HP_FAN_SPEED_AUTOMATIC); -+ priv->cpu_pwm = HP_FAN_SPEED_AUTOMATIC; -+ priv->gpu_pwm = HP_FAN_SPEED_AUTOMATIC; -+ return hp_wmi_fan_speed_set(priv); - } - - static int hp_wmi_fan_speed_max_reset(struct hp_wmi_hwmon_priv *priv) -@@ -1152,12 +1197,134 @@ static int camera_shutter_input_setup(void) - return err; - } - -+static const u8 mux_bitmask_map[] = { -+ [0] = HPWMI_MUX_MODE_HYBRID, -+ [1] = HPWMI_MUX_MODE_DISCRETE, -+ [2] = HPWMI_MUX_MODE_OPTIMUS, -+ [3] = HPWMI_MUX_MODE_UMA, -+}; -+ -+static int hp_wmi_get_mux_supported_modes(u8 *supported) -+{ -+ u8 legacy_buffer[4] = {}; -+ u8 buffer[128] = {}; -+ u32 req_packet = 0; -+ int ret; -+ -+ if (!supported) -+ return -EINVAL; -+ -+ /* Try modern BIOS design data query (128-byte buffer) */ -+ ret = hp_wmi_perform_query(HPWMI_GET_SYSTEM_DESIGN_DATA, HPWMI_GM, -+ buffer, zero_if_sup(req_packet), sizeof(buffer)); -+ if (ret == 0) { -+ *supported = buffer[7]; -+ return 0; -+ } -+ -+ /* -+ * (Fallback): Legacy BIOS behavior based on Omen Gaming Hub. -+ * If the modern query is not supported, check if the MUX query endpoint -+ * responds to a read request. If it succeeds, the hardware has MUX -+ * capability but lacks the mode map, defaulting to Hybrid + Discrete. -+ */ -+ ret = hp_wmi_perform_query(HPWMI_GRAPHICS_MUX_QUERY, HPWMI_READ, -+ legacy_buffer, sizeof(legacy_buffer), 0); -+ if (ret < 0) -+ return ret; -+ if (ret > 0) -+ return -EINVAL; -+ -+ *supported = HPWMI_MUX_LEGACY_MASK; -+ return 0; -+} -+ -+static int hp_wmi_get_mux_mode(u8 *mode) -+{ -+ u8 buffer[4] = {}; -+ int ret; -+ -+ if (!mode) -+ return -EINVAL; -+ -+ ret = hp_wmi_perform_query(HPWMI_GRAPHICS_MUX_QUERY, HPWMI_READ, -+ buffer, sizeof(buffer), sizeof(buffer)); -+ if (ret < 0) -+ return ret; -+ if (ret > 0) -+ return -EINVAL; -+ -+ /* Mask the highest bit, which might be used as a BIOS status flag */ -+ *mode = buffer[0] & HPWMI_MUX_MODE_MASK; -+ return 0; -+} -+ -+static int hp_wmi_set_mux_mode(u8 mode) -+{ -+ u8 buffer[4] = { mode, 0x00, 0x00, 0x00 }; -+ int ret; -+ -+ ret = hp_wmi_perform_query(HPWMI_GRAPHICS_MUX_QUERY, HPWMI_WRITE, -+ buffer, sizeof(buffer), sizeof(buffer)); -+ if (ret < 0) -+ return ret; -+ if (ret > 0) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static ssize_t gpu_mux_mode_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ u8 mode; -+ int ret; -+ -+ ret = hp_wmi_get_mux_mode(&mode); -+ if (ret) -+ return ret; -+ -+ return sysfs_emit(buf, "%u\n", mode); -+} -+ -+static ssize_t gpu_mux_mode_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, -+ size_t count) -+{ -+ u32 requested; -+ u8 supported; -+ int ret; -+ -+ ret = kstrtou32(buf, 0, &requested); -+ if (ret) -+ return ret; -+ if (requested >= ARRAY_SIZE(mux_bitmask_map)) -+ return -EINVAL; -+ -+ ret = hp_wmi_get_mux_supported_modes(&supported); -+ if (ret) -+ return ret; -+ -+ /* Verify if the requested mode is allowed by the hardware mask */ -+ if (!(supported & mux_bitmask_map[requested])) -+ return -EOPNOTSUPP; -+ -+ ret = hp_wmi_set_mux_mode(requested); -+ if (ret) -+ return ret; -+ -+ return count; -+} -+ - static DEVICE_ATTR_RO(display); - static DEVICE_ATTR_RO(hddtemp); - static DEVICE_ATTR_RW(als); - static DEVICE_ATTR_RO(dock); - static DEVICE_ATTR_RO(tablet); - static DEVICE_ATTR_RW(postcode); -+static DEVICE_ATTR_RW(gpu_mux_mode); - - static struct attribute *hp_wmi_attrs[] = { - &dev_attr_display.attr, -@@ -1166,6 +1333,7 @@ static struct attribute *hp_wmi_attrs[] = { - &dev_attr_dock.attr, - &dev_attr_tablet.attr, - &dev_attr_postcode.attr, -+ &dev_attr_gpu_mux_mode.attr, - NULL, - }; - ATTRIBUTE_GROUPS(hp_wmi); -@@ -1817,6 +1985,38 @@ static bool is_victus_s_thermal_profile(void) - return is_victus_s_board; - } - -+static const struct hp_wmi_fan_profile_params *hp_wmi_fan_profile(void) -+{ -+ if (!active_board_params) -+ return NULL; -+ -+ return active_board_params->fan_profile; -+} -+ -+static bool hp_wmi_fan_control_supported(void) -+{ -+ const struct hp_wmi_fan_profile_params *params = hp_wmi_fan_profile(); -+ -+ return params && params->get_fan_speed; -+} -+ -+static bool hp_wmi_fan_table_supported(void) -+{ -+ const struct hp_wmi_fan_profile_params *params = hp_wmi_fan_profile(); -+ -+ return params && params->fan_table; -+} -+ -+static int hp_wmi_get_active_fan_speed(int fan) -+{ -+ const struct hp_wmi_fan_profile_params *params = hp_wmi_fan_profile(); -+ -+ if (!params || !params->get_fan_speed) -+ return -EOPNOTSUPP; -+ -+ return params->get_fan_speed(fan); -+} -+ - static int victus_s_gpu_thermal_profile_get(bool *ctgp_enable, - bool *ppab_enable, - u8 *dstate, -@@ -2436,7 +2636,7 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) - - switch (priv->mode) { - case PWM_MODE_MAX: -- if (is_victus_s_thermal_profile()) { -+ if (hp_wmi_fan_control_supported()) { - ret = hp_wmi_get_fan_count_userdefine_trigger(); - if (ret < 0) - return ret; -@@ -2448,16 +2648,16 @@ static int hp_wmi_apply_fan_settings(struct hp_wmi_hwmon_priv *priv) - secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); - return 0; - case PWM_MODE_MANUAL: -- if (!is_victus_s_thermal_profile()) -+ if (!hp_wmi_fan_control_supported()) - return -EOPNOTSUPP; -- ret = hp_wmi_fan_speed_set(priv, pwm_to_rpm(priv->pwm, priv)); -+ ret = hp_wmi_fan_speed_set(priv); - if (ret < 0) - return ret; - mod_delayed_work(system_dfl_wq, &priv->keep_alive_dwork, - secs_to_jiffies(KEEP_ALIVE_DELAY_SECS)); - return 0; - case PWM_MODE_AUTO: -- if (is_victus_s_thermal_profile()) { -+ if (hp_wmi_fan_control_supported()) { - ret = hp_wmi_get_fan_count_userdefine_trigger(); - if (ret < 0) - return ret; -@@ -2481,12 +2681,12 @@ static umode_t hp_wmi_hwmon_is_visible(const void *data, - { - switch (type) { - case hwmon_pwm: -- if (attr == hwmon_pwm_input && !is_victus_s_thermal_profile()) -+ if (attr == hwmon_pwm_input && !hp_wmi_fan_control_supported()) - return 0; - return 0644; - case hwmon_fan: -- if (is_victus_s_thermal_profile()) { -- if (hp_wmi_get_fan_speed_victus_s(channel) >= 0) -+ if (hp_wmi_fan_control_supported()) { -+ if (hp_wmi_get_active_fan_speed(channel) >= 0) - return 0444; - } else { - if (hp_wmi_get_fan_speed(channel) >= 0) -@@ -2510,8 +2710,8 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, - priv = dev_get_drvdata(dev); - switch (type) { - case hwmon_fan: -- if (is_victus_s_thermal_profile()) -- ret = hp_wmi_get_fan_speed_victus_s(channel); -+ if (hp_wmi_fan_control_supported()) -+ ret = hp_wmi_get_active_fan_speed(channel); - else - ret = hp_wmi_get_fan_speed(channel); - if (ret < 0) -@@ -2520,10 +2720,10 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, - return 0; - case hwmon_pwm: - if (attr == hwmon_pwm_input) { -- if (!is_victus_s_thermal_profile()) -+ if (!hp_wmi_fan_control_supported()) - return -EOPNOTSUPP; - -- rpm = hp_wmi_get_fan_speed_victus_s(channel); -+ rpm = hp_wmi_get_active_fan_speed(channel); - if (rpm < 0) - return rpm; - *val = rpm_to_pwm(rpm / 100, priv); -@@ -2550,14 +2750,15 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long val) - { - struct hp_wmi_hwmon_priv *priv; -- int rpm; -+ int cpu_rpm, gpu_rpm; - - priv = dev_get_drvdata(dev); - guard(mutex)(&priv->lock); - switch (type) { - case hwmon_pwm: - if (attr == hwmon_pwm_input) { -- if (!is_victus_s_thermal_profile()) -+ int rpm; -+ if (!hp_wmi_fan_control_supported()) - return -EOPNOTSUPP; - /* PWM input is invalid when not in manual mode */ - if (priv->mode != PWM_MODE_MANUAL) -@@ -2566,7 +2767,10 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, - /* ensure PWM input is within valid fan speeds */ - rpm = pwm_to_rpm(val, priv); - rpm = clamp_val(rpm, priv->min_rpm, priv->max_rpm); -- priv->pwm = rpm_to_pwm(rpm, priv); -+ if (channel == CPU_FAN) -+ priv->cpu_pwm = rpm_to_pwm(rpm, priv); -+ else if (channel == GPU_FAN) -+ priv->gpu_pwm = rpm_to_pwm(rpm, priv); - return hp_wmi_apply_fan_settings(priv); - } - switch (val) { -@@ -2574,16 +2778,20 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, - priv->mode = PWM_MODE_MAX; - return hp_wmi_apply_fan_settings(priv); - case PWM_MODE_MANUAL: -- if (!is_victus_s_thermal_profile()) -+ if (!hp_wmi_fan_control_supported()) - return -EOPNOTSUPP; - /* - * When switching to manual mode, set fan speed to - * current RPM values to ensure a smooth transition. - */ -- rpm = hp_wmi_get_fan_speed_victus_s(channel); -- if (rpm < 0) -- return rpm; -- priv->pwm = rpm_to_pwm(rpm / 100, priv); -+ cpu_rpm = hp_wmi_get_active_fan_speed(CPU_FAN); -+ if (cpu_rpm < 0) -+ return cpu_rpm; -+ gpu_rpm = hp_wmi_get_active_fan_speed(GPU_FAN); -+ if (gpu_rpm < 0) -+ return gpu_rpm; -+ priv->cpu_pwm = rpm_to_pwm(cpu_rpm / 100, priv); -+ priv->gpu_pwm = rpm_to_pwm(gpu_rpm / 100, priv); - priv->mode = PWM_MODE_MANUAL; - return hp_wmi_apply_fan_settings(priv); - case PWM_MODE_AUTO: -@@ -2599,7 +2807,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, - - static const struct hwmon_channel_info * const info[] = { - HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT), -- HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE | HWMON_PWM_INPUT), -+ HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE | HWMON_PWM_INPUT, HWMON_PWM_INPUT), - NULL - }; - -@@ -2640,14 +2848,14 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) - struct victus_s_fan_table *fan_table; - u8 min_rpm, max_rpm; - u8 cpu_rpm, gpu_rpm, noise_db; -- int gpu_delta, i, num_entries, ret; -+ int i, num_entries, ret; - size_t header_size, entry_size; - - /* Default behaviour on hwmon init is automatic mode */ - priv->mode = PWM_MODE_AUTO; - -- /* Bypass all non-Victus S devices */ -- if (!is_victus_s_thermal_profile()) -+ /* Bypass devices without fan control support. */ -+ if (!hp_wmi_fan_table_supported()) - return 0; - - ret = hp_wmi_perform_query(HPWMI_VICTUS_S_GET_FAN_TABLE_QUERY, -@@ -2686,10 +2894,8 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) - if (min_rpm == U8_MAX || max_rpm == 0) - return -EINVAL; - -- gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm; - priv->min_rpm = min_rpm; - priv->max_rpm = max_rpm; -- priv->gpu_delta = gpu_delta; - - return 0; - } -diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c ---- a/drivers/platform/x86/huawei-wmi.c -+++ b/drivers/platform/x86/huawei-wmi.c -@@ -6,6 +6,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -527,11 +528,104 @@ static void huawei_wmi_battery_exit(struct device *dev) - - /* Fn lock */ - -+/* GFRS byte[1] / SFRS byte[2] (FRSR) fn-lock state values */ -+#define FN_LOCK_ACPI_OFF 1 -+#define FN_LOCK_ACPI_ON 2 -+#define FN_LOCK_ACPI_STAT_OK 0 -+ -+/* -+ * Newer Huawei models (e.g. HUAWEI FLMH-XX / MateBook 14 2024) use direct -+ * ACPI methods \GFRS / \SFRS (Get/Set Fn key Reversal Status) to control -+ * Fn-lock via EC registers 0x6B (read) and 0x6C (write). -+ * -+ * GFRS response buffer layout: -+ * byte[0] = STAT (FN_LOCK_ACPI_STAT_OK = success) -+ * byte[1] = FN_LOCK_ACPI_OFF (fn-lock off) or FN_LOCK_ACPI_ON (fn-lock on) -+ * -+ * SFRS argument layout (CreateByteField(Arg0, 0x02, FRSR)): -+ * Value is read from byte[2] of the integer argument, so it must be -+ * passed as (value << 16): -+ * (FN_LOCK_ACPI_OFF << 16) = fn-lock off (writes 0x55 to EC 0x6C) -+ * (FN_LOCK_ACPI_ON << 16) = fn-lock on (writes 0x5A to EC 0x6C) -+ */ -+ -+static int huawei_acpi_fn_lock_get(int *on) -+{ -+ union acpi_object acpi_arg; -+ struct acpi_object_list arg_list = { .count = 1, .pointer = &acpi_arg }; -+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ -+ acpi_arg.type = ACPI_TYPE_INTEGER; -+ acpi_arg.integer.value = 0; -+ -+ status = acpi_evaluate_object(NULL, "\\GFRS", &arg_list, &output); -+ if (ACPI_FAILURE(status)) -+ return -EIO; -+ -+ union acpi_object *obj __free(kfree) = output.pointer; -+ if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 2) -+ return -ENODATA; -+ -+ /* byte[0] = STAT, byte[1] = fn-lock state */ -+ if (obj->buffer.pointer[0] != FN_LOCK_ACPI_STAT_OK) -+ return -EIO; -+ -+ switch (obj->buffer.pointer[1]) { -+ case FN_LOCK_ACPI_OFF: -+ if (on) -+ *on = 0; -+ break; -+ case FN_LOCK_ACPI_ON: -+ if (on) -+ *on = 1; -+ break; -+ default: -+ return -ENODATA; -+ } -+ -+ return 0; -+} -+ -+static int huawei_acpi_fn_lock_set(int on) -+{ -+ union acpi_object acpi_arg; -+ struct acpi_object_list arg_list = { .count = 1, .pointer = &acpi_arg }; -+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ -+ /* -+ * SFRS reads byte[2] of its argument via CreateByteField(Arg0, 0x02). -+ * on=0 → FRSR=FN_LOCK_ACPI_OFF → EC gets 0x55 (fn-lock off) -+ * on=1 → FRSR=FN_LOCK_ACPI_ON → EC gets 0x5A (fn-lock on) -+ */ -+ acpi_arg.type = ACPI_TYPE_INTEGER; -+ acpi_arg.integer.value = (on ? FN_LOCK_ACPI_ON : FN_LOCK_ACPI_OFF) << 16; -+ -+ status = acpi_evaluate_object(NULL, "\\SFRS", &arg_list, &output); -+ if (ACPI_FAILURE(status)) -+ return -EIO; -+ -+ union acpi_object *obj __free(kfree) = output.pointer; -+ if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) -+ return -ENODATA; -+ -+ if (obj->buffer.pointer[0] != FN_LOCK_ACPI_STAT_OK) -+ return -EIO; -+ -+ return 0; -+} -+ - static int huawei_wmi_fn_lock_get(int *on) - { - u8 ret[0x100] = { 0 }; - int err, i; - -+ /* Newer models: use direct ACPI \GFRS method */ -+ if (acpi_has_method(NULL, "\\GFRS")) -+ return huawei_acpi_fn_lock_get(on); -+ -+ /* WMI fallback */ - err = huawei_wmi_cmd(FN_LOCK_GET, ret, 0x100); - if (err) - return err; -@@ -550,6 +644,11 @@ static int huawei_wmi_fn_lock_set(int on) - { - union hwmi_arg arg; - -+ /* Newer models: use direct ACPI \SFRS method */ -+ if (acpi_has_method(NULL, "\\SFRS")) -+ return huawei_acpi_fn_lock_set(on); -+ -+ /* WMI fallback */ - arg.cmd = FN_LOCK_SET; - arg.args[2] = on + 1; // 0 undefined, 1 off, 2 on. - -diff --git a/drivers/platform/x86/intel/int1092/intel_sar.c b/drivers/platform/x86/intel/int1092/intel_sar.c ---- a/drivers/platform/x86/intel/int1092/intel_sar.c -+++ b/drivers/platform/x86/intel/int1092/intel_sar.c -@@ -91,10 +91,10 @@ static acpi_status parse_package(struct wwan_sar_context *context, union acpi_ob - item->package.count <= data->total_dev_mode) - return AE_ERROR; - -- data->device_mode_info = devm_kmalloc_array(&context->sar_device->dev, -- data->total_dev_mode, -- sizeof(*data->device_mode_info), -- GFP_KERNEL); -+ data->device_mode_info = devm_kcalloc(&context->sar_device->dev, -+ data->total_dev_mode, -+ sizeof(*data->device_mode_info), -+ GFP_KERNEL); - if (!data->device_mode_info) - return AE_ERROR; - -diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c ---- a/drivers/platform/x86/intel/pmc/core.c -+++ b/drivers/platform/x86/intel/pmc/core.c -@@ -1583,7 +1583,7 @@ int pmc_core_pmt_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc, struct tel - { - const u8 *lpm_indices; - int num_maps, mode_offset = 0; -- int ret, lpm_size; -+ int ret = 0, lpm_size; - u8 mode; - - lpm_indices = pmc->map->lpm_reg_index; -diff --git a/drivers/platform/x86/lenovo/Kconfig b/drivers/platform/x86/lenovo/Kconfig ---- a/drivers/platform/x86/lenovo/Kconfig -+++ b/drivers/platform/x86/lenovo/Kconfig -@@ -43,6 +43,20 @@ config LENOVO_WMI_CAMERA - To compile this driver as a module, choose M here: the module - will be called lenovo-wmi-camera. - -+config LENOVO_YB9_KBDOCK -+ tristate "Lenovo Yoga Book 9 keyboard dock detection" -+ depends on ACPI_WMI -+ depends on DMI -+ depends on INPUT -+ help -+ Say Y here to enable keyboard dock detection on the Lenovo Yoga Book 9 -+ 14IAH10. The detachable Bluetooth keyboard magnetically attaches to -+ either screen; this driver reports SW_TABLET_MODE input events based -+ on the attachment state and exposes the raw position in sysfs. -+ -+ To compile this driver as a module, choose M here: the module will be -+ called lenovo-yb9-kbdock. -+ - config LENOVO_YMC - tristate "Lenovo Yoga Tablet Mode Control" - depends on ACPI_WMI -diff --git a/drivers/platform/x86/lenovo/Makefile b/drivers/platform/x86/lenovo/Makefile ---- a/drivers/platform/x86/lenovo/Makefile -+++ b/drivers/platform/x86/lenovo/Makefile -@@ -8,6 +8,7 @@ obj-$(CONFIG_THINKPAD_LMI) += think-lmi.o - obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o - - lenovo-target-$(CONFIG_LENOVO_WMI_HOTKEY_UTILITIES) += wmi-hotkey-utilities.o -+lenovo-target-$(CONFIG_LENOVO_YB9_KBDOCK) += yb9-kbdock.o - lenovo-target-$(CONFIG_LENOVO_YMC) += ymc.o - lenovo-target-$(CONFIG_YOGABOOK) += yogabook.o - lenovo-target-$(CONFIG_YT2_1380) += yoga-tab2-pro-1380-fastcharger.o -diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c ---- a/drivers/platform/x86/lenovo/ideapad-laptop.c -+++ b/drivers/platform/x86/lenovo/ideapad-laptop.c -@@ -2564,8 +2564,8 @@ module_init(ideapad_laptop_init) - - static void __exit ideapad_laptop_exit(void) - { -- ideapad_wmi_driver_unregister(); - platform_driver_unregister(&ideapad_acpi_driver); -+ ideapad_wmi_driver_unregister(); - } - module_exit(ideapad_laptop_exit) - -diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c ---- a/drivers/platform/x86/lenovo/thinkpad_acpi.c -+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -67,6 +68,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -186,6 +188,7 @@ enum tpacpi_hkey_event_t { - TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */ - TP_HKEY_EV_CAMERASHUTTER_TOGGLE = 0x131b, /* Toggle Camera Shutter */ - TP_HKEY_EV_DOUBLETAP_TOGGLE = 0x131c, /* Toggle trackpoint doubletap on/off */ -+ TP_HKEY_EV_USB_C_SECURITY = 0x131e, /* USB C Security (Fn+U, Fn+S) */ - TP_HKEY_EV_PROFILE_TOGGLE = 0x131f, /* Toggle platform profile in 2024 systems */ - TP_HKEY_EV_PROFILE_TOGGLE2 = 0x1401, /* Toggle platform profile in 2025 + systems */ - -@@ -309,6 +312,7 @@ struct tp_acpi_drv_struct { - - struct ibm_struct { - char *name; -+ acpi_device_class device_class; - - int (*read) (struct seq_file *); - int (*write) (char *); -@@ -374,6 +378,8 @@ static struct { - u32 has_adaptive_kbd:1; - u32 kbd_lang:1; - u32 trackpoint_doubletap_enable:1; -+ u32 usbc_security_supported:1; -+ bool usbc_security_enabled; - struct quirk_entry *quirks; - } tp_features; - -@@ -838,9 +844,8 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm) - } - - ibm->acpi->device->driver_data = ibm; -- scnprintf(acpi_device_class(ibm->acpi->device), -- sizeof(acpi_device_class(ibm->acpi->device)), -- "%s/%s", TPACPI_ACPI_EVENT_PREFIX, ibm->name); -+ scnprintf(ibm->device_class, sizeof(ibm->device_class), "%s/%s", -+ TPACPI_ACPI_EVENT_PREFIX, ibm->name); - - status = acpi_install_notify_handler(*ibm->acpi->handle, - ibm->acpi->type, dispatch_acpi_notify, ibm); -@@ -3869,7 +3874,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) - pr_err("unknown HKEY notification event %d\n", event); - /* forward it to userspace, maybe it knows how to handle it */ - acpi_bus_generate_netlink_event( -- ibm->acpi->device->pnp.device_class, -+ ibm->device_class, - dev_name(&ibm->acpi->device->dev), - event, 0); - return; -@@ -3949,7 +3954,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) - /* netlink events */ - if (send_acpi_ev) { - acpi_bus_generate_netlink_event( -- ibm->acpi->device->pnp.device_class, -+ ibm->device_class, - dev_name(&ibm->acpi->device->dev), - event, hkey); - } -@@ -8840,6 +8845,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = { - TPACPI_Q_LNV3('R', '0', 'T', TPACPI_FAN_NS), /* 11e Gen5 GL */ - TPACPI_Q_LNV3('R', '1', 'D', TPACPI_FAN_NS), /* 11e Gen5 GL-R */ - TPACPI_Q_LNV3('R', '0', 'V', TPACPI_FAN_NS), /* 11e Gen5 KL-Y */ -+ TPACPI_Q_LNV('H', '3', TPACPI_FAN_NS), /* Edge E330 */ - TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */ - TPACPI_Q_LNV3('R', '0', 'Q', TPACPI_FAN_DECRPM),/* L480 */ - TPACPI_Q_LNV('8', 'F', TPACPI_FAN_TPR), /* ThinkPad x120e */ -@@ -11285,6 +11291,114 @@ static struct ibm_struct hwdd_driver_data = { - .name = "hwdd", - }; - -+/************************************************************************* -+ * USB-C Security subdriver -+ * -+ * HKEY.USCS(0) is a read-only ACPI method; its argument is ignored. -+ * It always returns: -+ * bit 16 - USB-C security capability present on this SKU or not -+ * bit 0 - USB-C Security state (enable or disable) -+ * -+ * Hotkey -+ * ------ -+ * 0x131e (Fn+U, Fn+S): firmware toggles USBS before firing the event. -+ * The driver reads back the new state and notifies the sysfs attribute. -+ */ -+ -+/* USCS() return word bit layout */ -+#define USCS_CAP_BIT BIT(16) /* capability: feature present on SKU */ -+#define USCS_STATUS_BIT BIT(0) /* current security state */ -+ -+/* Protects USCS() ACPI method calls in usbc_security_query() */ -+static DEFINE_MUTEX(usbc_security_mutex); -+ -+/** -+ * usbc_security_query - read current USB-C security state via USCS() -+ * @enabled: out - true when security is ON (data connections blocked) -+ * -+ * Returns: -+ * 0 success, @enabled contains the current state -+ * -EIO ACPI evaluation failed -+ * -ENODEV capability bit absent; feature not present on this SKU* -+ */ -+static int usbc_security_query(bool *enabled) -+{ -+ int status; -+ -+ guard(mutex)(&usbc_security_mutex); -+ if (!acpi_evalf(hkey_handle, &status, "USCS", "dd", 0)) -+ return -EIO; -+ -+ if (!(status & USCS_CAP_BIT)) { -+ pr_debug("USCS cap bit absent (raw=0x%x)\n", status); -+ return -ENODEV; -+ } -+ -+ *enabled = status & USCS_STATUS_BIT; -+ return 0; -+} -+ -+/* sysfs: /sys/devices/platform/thinkpad_acpi/usb_c_security ---------- */ -+static ssize_t usb_c_security_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "%s\n", -+ str_enabled_disabled(tp_features.usbc_security_enabled)); -+} -+ -+static DEVICE_ATTR_RO(usb_c_security); -+ -+static struct attribute *usbc_security_attributes[] = { -+ &dev_attr_usb_c_security.attr, -+ NULL, -+}; -+ -+static umode_t usbc_security_attr_is_visible(struct kobject *kobj, -+ struct attribute *attr, int n) -+{ -+ return tp_features.usbc_security_supported ? attr->mode : 0; -+} -+ -+static const struct attribute_group usbc_security_attr_group = { -+ .is_visible = usbc_security_attr_is_visible, -+ .attrs = usbc_security_attributes, -+}; -+ -+static int tpacpi_usbc_security_init(struct ibm_init_struct *iibm) -+{ -+ int err; -+ -+ if (!acpi_has_method(hkey_handle, "USCS")) -+ return -ENODEV; -+ -+ err = usbc_security_query(&tp_features.usbc_security_enabled); -+ if (err == -ENODEV) -+ return 0; -+ if (err) -+ return err; -+ -+ tp_features.usbc_security_supported = true; -+ return 0; -+} -+ -+/* tpacpi_usbc_security_hotkey - handle Fn+U Fn+S hotkey (0x131e) */ -+static bool tpacpi_usbc_security_hotkey(void) -+{ -+ if (!tp_features.usbc_security_supported) -+ return false; -+ -+ if (usbc_security_query(&tp_features.usbc_security_enabled)) -+ return false; -+ -+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "usb_c_security"); -+ return true; -+} -+ -+static struct ibm_struct usbc_security_driver_data = { -+ .name = "usbc_security", -+}; -+ - /* --------------------------------------------------------------------- */ - - static struct attribute *tpacpi_driver_attributes[] = { -@@ -11345,6 +11459,7 @@ static const struct attribute_group *tpacpi_groups[] = { - &dprc_attr_group, - &auxmac_attr_group, - &hwdd_attr_group, -+ &usbc_security_attr_group, - NULL, - }; - -@@ -11499,6 +11614,8 @@ static bool tpacpi_driver_event(const unsigned int hkey_event) - case TP_HKEY_EV_PROFILE_TOGGLE2: - platform_profile_cycle(); - return true; -+ case TP_HKEY_EV_USB_C_SECURITY: -+ return tpacpi_usbc_security_hotkey(); - } - - return false; -@@ -11964,6 +12081,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { - .init = tpacpi_hwdd_init, - .data = &hwdd_driver_data, - }, -+ { -+ .init = tpacpi_usbc_security_init, -+ .data = &usbc_security_driver_data, -+ }, - }; - - static int __init set_ibm_param(const char *val, const struct kernel_param *kp) -diff --git a/drivers/platform/x86/lenovo/yb9-kbdock.c b/drivers/platform/x86/lenovo/yb9-kbdock.c -new file mode 100644 ---- /dev/null -+++ b/drivers/platform/x86/lenovo/yb9-kbdock.c -@@ -0,0 +1,323 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Lenovo Yoga Book 9 keyboard-dock detection -+ * -+ * The Yoga Book 9 ships with a detachable Bluetooth keyboard that magnetically -+ * attaches to the bottom screen in one of two positions. The EC tracks -+ * attachment state in a 2-bit field called BKBD and signals changes via WMI -+ * event 0xEB on the WM10 ACPI device (_UID "GMZN"). -+ * -+ * BKBD values: -+ * 0 = keyboard detached -+ * 1 = keyboard docked on the top half of the bottom screen -+ * 2 = keyboard docked on the bottom half of the bottom screen -+ * 3 = reserved / not observed -+ * -+ * Two WMI interfaces are used (documented in embedded BMOF, WQDD, 20705 bytes): -+ * -+ * LENOVO_BTKBD_EVENT (event GUID, 806BD2A2-...) -+ * WmiDataId(1) uint32 Status — _WED(0xEB) returns EC.BKBD directly. -+ * The notify callback receives BKBD as an integer; no separate query needed. -+ * -+ * LENOVO_FEATURE_STATUS_DATA (block GUID, E7F300FA-...) -+ * WmiDataId(1) uint32 IDs = 0x00060000 (feature selector) -+ * WmiDataId(2) uint32 Status = BKBD value -+ * Used on probe and resume to read initial state. -+ * -+ * The event driver (LENOVO_BTKBD_EVENT) fires a notifier chain on each WMI -+ * event. The block driver (LENOVO_FEATURE_STATUS_DATA) owns the input_dev -+ * and registers a notifier_block to receive those events, eliminating the -+ * need for shared global state or a mutex. -+ * -+ * SW_TABLET_MODE=1 is reported when the keyboard is detached; -+ * SW_TABLET_MODE=0 when docked in either position (keyboard present). -+ * The raw BKBD value is exposed via the sysfs attribute "keyboard_position". -+ * -+ * Copyright (C) 2026 Dave Carey -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define YB9_KBDOCK_EVENT_GUID "806BD2A2-177B-481D-BFB5-3BA0BB4A2285" -+#define YB9_KBDOCK_QUERY_GUID "E7F300FA-21CD-4003-ADAC-2696135982E6" -+ -+/* BKBD encoding */ -+#define BKBD_DETACHED 0 -+ -+/* LENOVO_FEATURE_STATUS_DATA feature selector */ -+#define YB9_FEATURE_STATUS_ID 0x00060000u -+ -+/* -+ * LENOVO_FEATURE_STATUS_DATA: 8-byte buffer {uint32 IDs, uint32 Status}. -+ * IDs is always 0x00060000; Status holds the BKBD value (0–3). -+ */ -+struct lenovo_feature_status { -+ __le32 id; -+ __le32 status; -+} __packed; -+ -+/* ------------------------------------------------------------------ -+ * Notifier chain — event driver fires it, block driver listens -+ * ------------------------------------------------------------------ */ -+ -+static BLOCKING_NOTIFIER_HEAD(yb9_kbdock_chain_head); -+ -+static void devm_yb9_kbdock_unregister_notifier(void *data) -+{ -+ struct notifier_block *nb = data; -+ -+ blocking_notifier_chain_unregister(&yb9_kbdock_chain_head, nb); -+} -+ -+static int devm_yb9_kbdock_register_notifier(struct device *dev, -+ struct notifier_block *nb) -+{ -+ int ret; -+ -+ ret = blocking_notifier_chain_register(&yb9_kbdock_chain_head, nb); -+ if (ret < 0) -+ return ret; -+ -+ return devm_add_action_or_reset(dev, devm_yb9_kbdock_unregister_notifier, nb); -+} -+ -+/* ------------------------------------------------------------------ -+ * Block WMI driver — LENOVO_FEATURE_STATUS_DATA -+ * (owns input_dev, sysfs, PM resume) -+ * ------------------------------------------------------------------ */ -+ -+struct yb9_kbdock_data { -+ struct wmi_device *wdev; -+ struct input_dev *input_dev; -+ struct notifier_block nb; -+ spinlock_t lock; /* protects input_report_switch + input_sync */ -+}; -+ -+static int yb9_kbdock_query(struct yb9_kbdock_data *d, u32 *bkbd) -+{ -+ struct wmi_buffer out; -+ int ret; -+ -+ ret = wmidev_query_block(d->wdev, 0, &out, -+ sizeof(struct lenovo_feature_status)); -+ if (ret) -+ return ret; -+ -+ struct lenovo_feature_status *fs __free(kfree) = out.data; -+ -+ if (le32_to_cpu(fs->id) != YB9_FEATURE_STATUS_ID) -+ return -EIO; -+ -+ *bkbd = le32_to_cpu(fs->status); -+ return 0; -+} -+ -+static void yb9_kbdock_report(struct yb9_kbdock_data *d, u32 bkbd) -+{ -+ int tablet = (bkbd == BKBD_DETACHED) ? 1 : 0; -+ -+ spin_lock(&d->lock); -+ input_report_switch(d->input_dev, SW_TABLET_MODE, tablet); -+ input_sync(d->input_dev); -+ spin_unlock(&d->lock); -+ dev_dbg(&d->wdev->dev, "BKBD=%u SW_TABLET_MODE=%d\n", bkbd, tablet); -+} -+ -+static int yb9_kbdock_sync(struct yb9_kbdock_data *d) -+{ -+ u32 bkbd; -+ int ret; -+ -+ ret = yb9_kbdock_query(d, &bkbd); -+ if (ret) -+ return ret; -+ -+ yb9_kbdock_report(d, bkbd); -+ return 0; -+} -+ -+static int yb9_kbdock_nb_call(struct notifier_block *nb, -+ unsigned long bkbd, void *unused) -+{ -+ struct yb9_kbdock_data *d = -+ container_of(nb, struct yb9_kbdock_data, nb); -+ -+ yb9_kbdock_report(d, bkbd); -+ return NOTIFY_DONE; -+} -+ -+static ssize_t keyboard_position_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct yb9_kbdock_data *d = dev_get_drvdata(dev); -+ u32 bkbd; -+ int ret; -+ -+ ret = yb9_kbdock_query(d, &bkbd); -+ if (ret) -+ return ret; -+ return sysfs_emit(buf, "%u\n", bkbd); -+} -+static DEVICE_ATTR_RO(keyboard_position); -+ -+static const struct attribute * const yb9_kbdock_attrs[] = { -+ &dev_attr_keyboard_position.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(yb9_kbdock); -+ -+static int yb9_kbdock_resume(struct device *dev) -+{ -+ struct yb9_kbdock_data *d = dev_get_drvdata(dev); -+ -+ return yb9_kbdock_sync(d); -+} -+static DEFINE_SIMPLE_DEV_PM_OPS(yb9_kbdock_pm_ops, NULL, yb9_kbdock_resume); -+ -+static int yb9_kbdock_block_probe(struct wmi_device *wdev, const void *ctx) -+{ -+ struct yb9_kbdock_data *d; -+ struct input_dev *input_dev; -+ int ret; -+ -+ d = devm_kzalloc(&wdev->dev, sizeof(*d), GFP_KERNEL); -+ if (!d) -+ return -ENOMEM; -+ -+ d->wdev = wdev; -+ spin_lock_init(&d->lock); -+ -+ input_dev = devm_input_allocate_device(&wdev->dev); -+ if (!input_dev) -+ return -ENOMEM; -+ -+ input_dev->name = "Lenovo Yoga Book 9 keyboard dock switch"; -+ input_dev->phys = YB9_KBDOCK_QUERY_GUID "/input0"; -+ input_dev->id.bustype = BUS_HOST; -+ input_set_capability(input_dev, EV_SW, SW_TABLET_MODE); -+ -+ ret = input_register_device(input_dev); -+ if (ret) -+ return ret; -+ -+ d->input_dev = input_dev; -+ d->nb.notifier_call = yb9_kbdock_nb_call; -+ -+ ret = devm_yb9_kbdock_register_notifier(&wdev->dev, &d->nb); -+ if (ret) -+ return ret; -+ -+ dev_set_drvdata(&wdev->dev, d); -+ return yb9_kbdock_sync(d); -+} -+ -+static const struct wmi_device_id yb9_kbdock_block_id_table[] = { -+ { .guid_string = YB9_KBDOCK_QUERY_GUID }, -+ { } -+}; -+ -+static struct wmi_driver yb9_kbdock_block_driver = { -+ .driver = { -+ .name = "lenovo-yb9-kbdock", -+ .dev_groups = yb9_kbdock_groups, -+ .pm = pm_sleep_ptr(&yb9_kbdock_pm_ops), -+ }, -+ .id_table = yb9_kbdock_block_id_table, -+ .no_singleton = true, -+ .probe = yb9_kbdock_block_probe, -+}; -+ -+/* ------------------------------------------------------------------ -+ * Event WMI driver — LENOVO_BTKBD_EVENT -+ * (fires the notifier chain on each WMI event) -+ * ------------------------------------------------------------------ */ -+ -+static void yb9_kbdock_notify_new(struct wmi_device *wdev, -+ const struct wmi_buffer *data) -+{ -+ /* -+ * _WED(0xEB) returns EC.BKBD directly as a 32-bit integer -+ * (LENOVO_BTKBD_EVENT WmiDataId(1) uint32 Status). -+ * Short-buffer guard is handled by .min_event_size below. -+ */ -+ u32 bkbd = le32_to_cpu(*(const __le32 *)data->data); -+ -+ blocking_notifier_call_chain(&yb9_kbdock_chain_head, bkbd, NULL); -+} -+ -+static const struct wmi_device_id yb9_kbdock_event_id_table[] = { -+ { .guid_string = YB9_KBDOCK_EVENT_GUID }, -+ { } -+}; -+MODULE_DEVICE_TABLE(wmi, yb9_kbdock_event_id_table); -+ -+static struct wmi_driver yb9_kbdock_event_driver = { -+ .driver = { -+ .name = "lenovo-yb9-kbdock-event", -+ }, -+ .id_table = yb9_kbdock_event_id_table, -+ .no_singleton = true, -+ .notify_new = yb9_kbdock_notify_new, -+ .min_event_size = sizeof(__le32), -+}; -+ -+/* ------------------------------------------------------------------ -+ * Module init / exit -+ * ------------------------------------------------------------------ */ -+ -+static const struct dmi_system_id yb9_kbdock_dmi_table[] __initconst = { -+ { -+ /* Lenovo Yoga Book 9 14IAH10 */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "83KJ"), -+ }, -+ }, -+ { } -+}; -+ -+static int __init yb9_kbdock_init(void) -+{ -+ int ret; -+ -+ if (!dmi_check_system(yb9_kbdock_dmi_table)) -+ return -ENODEV; -+ -+ ret = wmi_driver_register(&yb9_kbdock_event_driver); -+ if (ret) -+ return ret; -+ -+ ret = wmi_driver_register(&yb9_kbdock_block_driver); -+ if (ret) { -+ wmi_driver_unregister(&yb9_kbdock_event_driver); -+ return ret; -+ } -+ -+ return 0; -+} -+module_init(yb9_kbdock_init); -+ -+static void __exit yb9_kbdock_exit(void) -+{ -+ wmi_driver_unregister(&yb9_kbdock_block_driver); -+ wmi_driver_unregister(&yb9_kbdock_event_driver); -+} -+module_exit(yb9_kbdock_exit); -+ -+MODULE_AUTHOR("Dave Carey "); -+MODULE_DESCRIPTION("Lenovo Yoga Book 9 keyboard dock detection"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/x86/lenovo/ymc.c b/drivers/platform/x86/lenovo/ymc.c ---- a/drivers/platform/x86/lenovo/ymc.c -+++ b/drivers/platform/x86/lenovo/ymc.c -@@ -28,6 +28,22 @@ static bool force; - module_param(force, bool, 0444); - MODULE_PARM_DESC(force, "Force loading on boards without a convertible DMI chassis-type"); - -+static const struct dmi_system_id lenovo_ymc_nosupport_dmi_table[] = { -+ { -+ /* -+ * Yoga Book 9 14IAH10: SW_TABLET_MODE is reported by the -+ * yb9-kbdock driver. Suppress lenovo-ymc on this machine to -+ * avoid userspace seeing two input nodes that both advertise -+ * the SW_TABLET_MODE capability. -+ */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "83KJ"), -+ }, -+ }, -+ { } -+}; -+ - static const struct dmi_system_id allowed_chasis_types_dmi_table[] = { - { - .matches = { -@@ -107,6 +123,9 @@ static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx) - struct input_dev *input_dev; - int err; - -+ if (dmi_check_system(lenovo_ymc_nosupport_dmi_table)) -+ return -ENODEV; -+ - if (!dmi_check_system(allowed_chasis_types_dmi_table)) { - if (force) - dev_info(&wdev->dev, "Force loading Lenovo YMC support\n"); -diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c ---- a/drivers/platform/x86/lg-laptop.c -+++ b/drivers/platform/x86/lg-laptop.c -@@ -8,8 +8,11 @@ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - - #include -+#include - #include - #include -+#include -+#include - #include - #include - #include -@@ -17,10 +20,12 @@ - #include - #include - #include -+#include - #include - #include - #include - #include -+#include - - #include - -@@ -57,13 +62,18 @@ MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages"); - #define LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR 0x3E8 - #define LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR 0x5E8 - --#define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248" --#define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2" --#define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6" --#define WMI_EVENT_GUID3 "911BAD44-7DF8-4FBB-9319-BABA1C4B293B" --#define WMI_METHOD_WMAB "C3A72B38-D3EF-42D3-8CBB-D5A57049F66D" --#define WMI_METHOD_WMBB "2B4F501A-BD3C-4394-8DCF-00A7D2BC8210" --#define WMI_EVENT_GUID WMI_EVENT_GUID0 -+#define LG_NOTIFY_TABLET_MODE_OFF 0x50 -+#define LG_NOTIFY_TABLET_MODE_ON 0x51 -+#define LG_NOTIFY_HOTKEY 0x80 -+#define LG_NOTIFY_THERMAL 0x81 -+#define LG_NOTIFY_MISC 0x82 -+ -+#define LG_OREP_READ_EC 0 -+#define LG_OREP_WRITE_EC 1 -+#define LG_OREP_DEBUG 2 -+#define LG_OREP_UPDATE_SYSTEM_STATE 3 -+#define LG_OREP_INTERCEPT_WMI_EVENTS 4 -+#define LG_OREP_WAKE_ON_LAN 6 - - #define SB_GGOV_METHOD "\\_SB.GGOV" - #define GOV_TLED 0x2020008 -@@ -78,26 +88,29 @@ MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages"); - #define WMBB_USB_CHARGE 0x10B - #define WMBB_BATT_LIMIT 0x10C - -+#define KBD_LED_BRIGHTNESS_MASK GENMASK(4, 0) -+#define KBD_LED_BRIGHTNESS_OFF 0x0 -+#define KBD_LED_BRIGHTNESS_HALF 0x2 -+#define KBD_LED_BRIGHTNESS_FULL 0x4 -+#define KBD_LED_MODE_MASK GENMASK(6, 5) -+#define KBD_LED_MODE_OFF 0x0 -+#define KBD_LED_MODE_ON 0x1 -+#define KBD_LED_STATUS BIT(7) -+#define KBD_LED_MAGIC_MASK GENMASK(15, 8) -+/* Exact purpose is unknown, maybe some sort of brightness limit? */ -+#define KBD_LED_MAGIC 0x05 -+ - #define FAN_MODE_LOWER GENMASK(1, 0) - #define FAN_MODE_UPPER GENMASK(5, 4) - - #define PLATFORM_NAME "lg-laptop" - --MODULE_ALIAS("wmi:" WMI_EVENT_GUID0); --MODULE_ALIAS("wmi:" WMI_EVENT_GUID1); --MODULE_ALIAS("wmi:" WMI_EVENT_GUID2); --MODULE_ALIAS("wmi:" WMI_EVENT_GUID3); --MODULE_ALIAS("wmi:" WMI_METHOD_WMAB); --MODULE_ALIAS("wmi:" WMI_METHOD_WMBB); -+struct lg_wmab_buffer_result { -+ __le32 value; -+ __le32 status; -+} __packed; - - static struct platform_device *pf_device; --static struct input_dev *wmi_input_dev; -- --static u32 inited; --#define INIT_INPUT_WMI_0 0x01 --#define INIT_INPUT_WMI_2 0x02 --#define INIT_INPUT_ACPI 0x04 --#define INIT_SPARSE_KEYMAP 0x80 - - static int battery_limit_use_wmbb; - static bool kbd_backlight_available; -@@ -105,16 +118,65 @@ static struct led_classdev kbd_backlight; - static enum led_brightness get_kbd_backlight_level(struct device *dev); - - static const struct key_entry wmi_keymap[] = { -- {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */ -- {KE_KEY, 0x74, {KEY_F21} }, /* Touchpad toggle (F5) */ -- {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */ -- {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing -- * this key both sends an event and -- * changes backlight level. -- */ -+ /* Placeholder value send by multiple hotkeys handled by ACPI */ -+ { KE_IGNORE, 0x0, { KEY_UNKNOWN }}, -+ /* LG control panel */ -+ { KE_KEY, 0x70, { KEY_F15 }}, -+ /* Touchpad toggle */ -+ { KE_KEY, 0x74, { KEY_F21 }}, -+ /* Mute Audio, already handled by ACPI */ -+ { KE_IGNORE, 0x78, { KEY_MUTE }}, -+ /* Read mode */ -+ { KE_KEY, 0xf020000, { KEY_F14 }}, -+ /* Open settings */ -+ { KE_KEY, 0xf070002, { KEY_CONFIG }}, -+ /* Keyboard backlight - pressing this key both sends an event and changes backlight level */ -+ { KE_KEY, 0x10000000, { KEY_F16 }}, -+ /* Hotkey combination pressed */ -+ { KE_IGNORE, 0x30010000, { KEY_UNKNOWN }}, -+ /* Hotkey combination released */ -+ { KE_IGNORE, 0x30010001, { KEY_UNKNOWN }}, -+ /* Change fan mode */ -+ { KE_KEY, 0x30010051, { KEY_PERFORMANCE }}, -+ /* Disable camera */ -+ { KE_KEY, 0x40020000, { KEY_CAMERA_ACCESS_TOGGLE }}, -+ /* Mute microphone */ -+ { KE_KEY, 0x40020001, { KEY_MICMUTE }}, -+ /* Fn-Lock */ -+ { KE_KEY, 0x40030001, { KEY_FN_ESC }}, - {KE_END, 0} - }; - -+static int lg_laptop_execute_orep(acpi_handle handle, u64 command, u64 value, -+ unsigned long long *result) -+{ -+ union acpi_object objs[] = { -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = command, -+ }, -+ }, -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = value, -+ }, -+ } -+ }; -+ struct acpi_object_list args = { -+ .count = ARRAY_SIZE(objs), -+ .pointer = objs, -+ }; -+ acpi_status status; -+ -+ status = acpi_evaluate_integer(handle, "OREP", &args, result); -+ if (ACPI_FAILURE(status)) -+ return -EIO; -+ -+ return 0; -+} -+ - static int ggov(u32 arg0) - { - union acpi_object args[1]; -@@ -155,30 +217,97 @@ static int ggov(u32 arg0) - return res; - } - --static union acpi_object *lg_wmab(struct device *dev, u32 method, u32 arg1, u32 arg2) -+static int lg_wmab_get(struct device *dev, u32 method, u32 *result) - { -- union acpi_object args[3]; -- acpi_status status; -- struct acpi_object_list arg; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -+ union acpi_object in[] = { -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = method, -+ }, -+ }, -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = WM_GET, -+ }, -+ }, -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = 0, -+ }, -+ }, -+ }; -+ struct lg_wmab_buffer_result *buffer_result; -+ struct acpi_object_list input = { -+ .count = ARRAY_SIZE(in), -+ .pointer = in, -+ }; -+ acpi_status status; - -- args[0].type = ACPI_TYPE_INTEGER; -- args[0].integer.value = method; -- args[1].type = ACPI_TYPE_INTEGER; -- args[1].integer.value = arg1; -- args[2].type = ACPI_TYPE_INTEGER; -- args[2].integer.value = arg2; -+ status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &input, &buffer); -+ if (ACPI_FAILURE(status)) -+ return -EIO; - -- arg.count = 3; -- arg.pointer = args; -+ union acpi_object *obj __free(kfree) = buffer.pointer; - -- status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &arg, &buffer); -- if (ACPI_FAILURE(status)) { -- dev_err(dev, "WMAB: call failed.\n"); -- return NULL; -+ if (!obj) -+ return -ENODATA; -+ -+ switch (obj->type) { -+ case ACPI_TYPE_INTEGER: -+ *result = obj->integer.value; -+ return 0; -+ case ACPI_TYPE_BUFFER: -+ if (obj->buffer.length != sizeof(*buffer_result)) -+ return -EPROTO; -+ -+ buffer_result = (struct lg_wmab_buffer_result *)obj->buffer.pointer; -+ if (get_unaligned_le32(&buffer_result->status)) -+ return -EIO; -+ -+ *result = get_unaligned_le32(&buffer_result->value); -+ return 0; -+ default: -+ return -EPROTO; - } -+} - -- return buffer.pointer; -+static int lg_wmab_set(struct device *dev, u32 method, u32 arg) -+{ -+ union acpi_object in[] = { -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = method, -+ }, -+ }, -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = WM_SET, -+ }, -+ }, -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = arg, -+ }, -+ }, -+ }; -+ struct acpi_object_list input = { -+ .count = ARRAY_SIZE(in), -+ .pointer = in, -+ }; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &input, NULL); -+ if (ACPI_FAILURE(status)) -+ return -EIO; -+ -+ return 0; - } - - static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u32 arg2) -@@ -212,76 +341,11 @@ static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u - return (union acpi_object *)buffer.pointer; - } - --static void wmi_notify(union acpi_object *obj, void *context) --{ -- long data = (long)context; -- unsigned int brightness; -- -- pr_debug("event guid %li\n", data); -- if (!obj) -- return; -- -- if (obj->type == ACPI_TYPE_INTEGER) { -- int eventcode = obj->integer.value; -- struct key_entry *key; -- -- if (eventcode == 0x10000000) { -- if (kbd_backlight_available) { -- brightness = get_kbd_backlight_level(kbd_backlight.dev->parent); -- led_classdev_notify_brightness_hw_changed(&kbd_backlight, -- brightness); -- } -- } else { -- key = sparse_keymap_entry_from_scancode( -- wmi_input_dev, eventcode); -- if (key && key->type == KE_KEY) -- sparse_keymap_report_entry(wmi_input_dev, -- key, 1, true); -- } -- } -- -- pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type, -- obj->integer.value); --} -- --static void wmi_input_setup(void) --{ -- acpi_status status; -- -- wmi_input_dev = input_allocate_device(); -- if (wmi_input_dev) { -- wmi_input_dev->name = "LG WMI hotkeys"; -- wmi_input_dev->phys = "wmi/input0"; -- wmi_input_dev->id.bustype = BUS_HOST; -- -- if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) || -- input_register_device(wmi_input_dev)) { -- pr_info("Cannot initialize input device"); -- input_free_device(wmi_input_dev); -- return; -- } -- -- inited |= INIT_SPARSE_KEYMAP; -- status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify, -- (void *)0); -- if (ACPI_SUCCESS(status)) -- inited |= INIT_INPUT_WMI_0; -- -- status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify, -- (void *)2); -- if (ACPI_SUCCESS(status)) -- inited |= INIT_INPUT_WMI_2; -- } else { -- pr_info("Cannot allocate input device"); -- } --} -- - static ssize_t fan_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) - { - unsigned long value; -- union acpi_object *r; - int ret; - - ret = kstrtoul(buffer, 10, &value); -@@ -290,10 +354,10 @@ static ssize_t fan_mode_store(struct device *dev, - if (value >= 3) - return -EINVAL; - -- r = lg_wmab(dev, WM_FAN_MODE, WM_SET, -- FIELD_PREP(FAN_MODE_LOWER, value) | -- FIELD_PREP(FAN_MODE_UPPER, value)); -- kfree(r); -+ ret = lg_wmab_set(dev, WM_FAN_MODE, FIELD_PREP(FAN_MODE_LOWER, value) | -+ FIELD_PREP(FAN_MODE_UPPER, value)); -+ if (ret < 0) -+ return ret; - - return count; - } -@@ -301,22 +365,14 @@ static ssize_t fan_mode_store(struct device *dev, - static ssize_t fan_mode_show(struct device *dev, - struct device_attribute *attr, char *buffer) - { -- unsigned int mode; -- union acpi_object *r; -+ u32 mode; -+ int ret; - -- r = lg_wmab(dev, WM_FAN_MODE, WM_GET, 0); -- if (!r) -- return -EIO; -+ ret = lg_wmab_get(dev, WM_FAN_MODE, &mode); -+ if (ret < 0) -+ return ret; - -- if (r->type != ACPI_TYPE_INTEGER) { -- kfree(r); -- return -EIO; -- } -- -- mode = FIELD_GET(FAN_MODE_LOWER, r->integer.value); -- kfree(r); -- -- return sysfs_emit(buffer, "%d\n", mode); -+ return sysfs_emit(buffer, "%lu\n", FIELD_GET(FAN_MODE_LOWER, mode)); - } - - static ssize_t usb_charge_store(struct device *dev, -@@ -366,41 +422,30 @@ static ssize_t reader_mode_store(struct device *dev, - const char *buffer, size_t count) - { - bool value; -- union acpi_object *r; - int ret; - - ret = kstrtobool(buffer, &value); - if (ret) - return ret; - -- r = lg_wmab(dev, WM_READER_MODE, WM_SET, value); -- if (!r) -- return -EIO; -+ ret = lg_wmab_set(dev, WM_READER_MODE, value); -+ if (ret < 0) -+ return ret; - -- kfree(r); - return count; - } - - static ssize_t reader_mode_show(struct device *dev, - struct device_attribute *attr, char *buffer) - { -- unsigned int status; -- union acpi_object *r; -+ u32 status; -+ int ret; - -- r = lg_wmab(dev, WM_READER_MODE, WM_GET, 0); -- if (!r) -- return -EIO; -+ ret = lg_wmab_get(dev, WM_READER_MODE, &status); -+ if (ret < 0) -+ return ret; - -- if (r->type != ACPI_TYPE_INTEGER) { -- kfree(r); -- return -EIO; -- } -- -- status = !!r->integer.value; -- -- kfree(r); -- -- return sysfs_emit(buffer, "%d\n", status); -+ return sysfs_emit(buffer, "%d\n", !!status); - } - - static ssize_t fn_lock_store(struct device *dev, -@@ -408,40 +453,30 @@ static ssize_t fn_lock_store(struct device *dev, - const char *buffer, size_t count) - { - bool value; -- union acpi_object *r; - int ret; - - ret = kstrtobool(buffer, &value); - if (ret) - return ret; - -- r = lg_wmab(dev, WM_FN_LOCK, WM_SET, value); -- if (!r) -- return -EIO; -+ ret = lg_wmab_set(dev, WM_FN_LOCK, value); -+ if (ret < 0) -+ return ret; - -- kfree(r); - return count; - } - - static ssize_t fn_lock_show(struct device *dev, - struct device_attribute *attr, char *buffer) - { -- unsigned int status; -- union acpi_object *r; -+ u32 status; -+ int ret; - -- r = lg_wmab(dev, WM_FN_LOCK, WM_GET, 0); -- if (!r) -- return -EIO; -+ ret = lg_wmab_get(dev, WM_FN_LOCK, &status); -+ if (ret < 0) -+ return ret; - -- if (r->type != ACPI_TYPE_BUFFER) { -- kfree(r); -- return -EIO; -- } -- -- status = !!r->buffer.pointer[0]; -- kfree(r); -- -- return sysfs_emit(buffer, "%d\n", status); -+ return sysfs_emit(buffer, "%d\n", !!status); - } - - static ssize_t charge_control_end_threshold_store(struct device *dev, -@@ -458,14 +493,18 @@ static ssize_t charge_control_end_threshold_store(struct device *dev, - if (value == 100 || value == 80) { - union acpi_object *r; - -- if (battery_limit_use_wmbb) -+ if (battery_limit_use_wmbb) { - r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_SET, value); -- else -- r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_SET, value); -- if (!r) -- return -EIO; -+ if (!r) -+ return -EIO; -+ -+ kfree(r); -+ } else { -+ ret = lg_wmab_set(&pf_device->dev, WM_BATT_LIMIT, value); -+ if (ret < 0) -+ return ret; -+ } - -- kfree(r); - return count; - } - -@@ -476,8 +515,9 @@ static ssize_t charge_control_end_threshold_show(struct device *device, - struct device_attribute *attr, - char *buf) - { -- unsigned int status; - union acpi_object *r; -+ u32 status; -+ int ret; - - if (battery_limit_use_wmbb) { - r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_GET, 0); -@@ -490,19 +530,13 @@ static ssize_t charge_control_end_threshold_show(struct device *device, - } - - status = r->buffer.pointer[0x10]; -+ kfree(r); - } else { -- r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_GET, 0); -- if (!r) -- return -EIO; -- -- if (r->type != ACPI_TYPE_INTEGER) { -- kfree(r); -- return -EIO; -- } -- -- status = r->integer.value; -+ ret = lg_wmab_get(&pf_device->dev, WM_BATT_LIMIT, &status); -+ if (ret < 0) -+ return ret; - } -- kfree(r); -+ - if (status != 80 && status != 100) - status = 0; - -@@ -568,10 +602,7 @@ static const struct attribute_group dev_attribute_group = { - static void tpad_led_set(struct led_classdev *cdev, - enum led_brightness brightness) - { -- union acpi_object *r; -- -- r = lg_wmab(cdev->dev->parent, WM_TLED, WM_SET, brightness > LED_OFF); -- kfree(r); -+ lg_wmab_set(cdev->dev->parent, WM_TLED, brightness > LED_OFF); - } - - static enum led_brightness tpad_led_get(struct led_classdev *cdev) -@@ -584,47 +615,50 @@ static LED_DEVICE(tpad_led, 1, 0); - static void kbd_backlight_set(struct led_classdev *cdev, - enum led_brightness brightness) - { -- u32 val; -- union acpi_object *r; -+ /* Must always be written */ -+ u32 value = KBD_LED_STATUS; -+ u32 mode, bright; - -- val = 0x22; -- if (brightness <= LED_OFF) -- val = 0; -- if (brightness >= LED_FULL) -- val = 0x24; -- r = lg_wmab(cdev->dev->parent, WM_KEY_LIGHT, WM_SET, val); -- kfree(r); -+ if (brightness <= LED_OFF) { -+ mode = KBD_LED_MODE_OFF; -+ bright = KBD_LED_BRIGHTNESS_OFF; -+ } else { -+ mode = KBD_LED_MODE_ON; -+ if (brightness >= LED_FULL) -+ bright = KBD_LED_BRIGHTNESS_FULL; -+ else -+ bright = KBD_LED_BRIGHTNESS_HALF; -+ } -+ -+ value |= FIELD_PREP(KBD_LED_BRIGHTNESS_MASK, bright); -+ value |= FIELD_PREP(KBD_LED_MODE_MASK, mode); -+ -+ lg_wmab_set(cdev->dev->parent, WM_KEY_LIGHT, value); - } - - static enum led_brightness get_kbd_backlight_level(struct device *dev) - { -- union acpi_object *r; -- int val; -+ u32 value; -+ int ret; - -- r = lg_wmab(dev, WM_KEY_LIGHT, WM_GET, 0); -- -- if (!r) -+ ret = lg_wmab_get(dev, WM_KEY_LIGHT, &value); -+ if (ret < 0) - return LED_OFF; - -- if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) { -- kfree(r); -+ if (FIELD_GET(KBD_LED_MAGIC_MASK, value) != KBD_LED_MAGIC) - return LED_OFF; -- } - -- switch (r->buffer.pointer[0] & 0x27) { -- case 0x24: -- val = LED_FULL; -- break; -- case 0x22: -- val = LED_HALF; -- break; -+ if (FIELD_GET(KBD_LED_MODE_MASK, value) == KBD_LED_MODE_OFF) -+ return LED_OFF; -+ -+ switch (FIELD_GET(KBD_LED_BRIGHTNESS_MASK, value)) { -+ case KBD_LED_BRIGHTNESS_FULL: -+ return LED_FULL; -+ case KBD_LED_BRIGHTNESS_HALF: -+ return LED_HALF; - default: -- val = LED_OFF; -+ return LED_OFF; - } -- -- kfree(r); -- -- return val; - } - - static enum led_brightness kbd_backlight_get(struct led_classdev *cdev) -@@ -634,26 +668,163 @@ static enum led_brightness kbd_backlight_get(struct led_classdev *cdev) - - static LED_DEVICE(kbd_backlight, 255, LED_BRIGHT_HW_CHANGED); - --static void wmi_input_destroy(void) --{ -- if (inited & INIT_INPUT_WMI_2) -- wmi_remove_notify_handler(WMI_EVENT_GUID2); -- -- if (inited & INIT_INPUT_WMI_0) -- wmi_remove_notify_handler(WMI_EVENT_GUID0); -- -- if (inited & INIT_SPARSE_KEYMAP) -- input_unregister_device(wmi_input_dev); -- -- inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP); --} -- - static struct platform_driver pf_driver = { - .driver = { - .name = PLATFORM_NAME, - } - }; - -+static int lg_laptop_get_event_data(acpi_handle handle, u32 value, u32 *data) -+{ -+ union acpi_object objs[] = { -+ { -+ .integer = { -+ .type = ACPI_TYPE_INTEGER, -+ .value = value, -+ }, -+ } -+ }; -+ struct acpi_object_list args = { -+ .count = ARRAY_SIZE(objs), -+ .pointer = objs, -+ }; -+ unsigned long long result; -+ acpi_status status; -+ -+ status = acpi_evaluate_integer(handle, "_WED", &args, &result); -+ if (ACPI_FAILURE(status)) -+ return -EIO; -+ -+ if (result > U32_MAX) -+ return -EPROTO; -+ -+ *data = result; -+ -+ return 0; -+} -+ -+static void lg_laptop_handle_input_event(struct input_dev *input_dev, u32 value, u32 data) -+{ -+ unsigned int kbd_brightness; -+ -+ switch (value) { -+ case LG_NOTIFY_HOTKEY: -+ sparse_keymap_report_event(input_dev, data, 1, true); -+ break; -+ case LG_NOTIFY_THERMAL: -+ /* Currently not supported */ -+ break; -+ case LG_NOTIFY_MISC: -+ switch (data) { -+ case 0x10000000: -+ if (!kbd_backlight_available) -+ break; -+ -+ kbd_brightness = get_kbd_backlight_level(kbd_backlight.dev->parent); -+ led_classdev_notify_brightness_hw_changed(&kbd_backlight, kbd_brightness); -+ break; -+ default: -+ sparse_keymap_report_event(input_dev, data, 1, true); -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void lg_laptop_notify_handler(acpi_handle handle, u32 value, void *context) -+{ -+ struct input_dev *input_dev = context; -+ u32 data; -+ int ret; -+ -+ switch (value) { -+ case LG_NOTIFY_TABLET_MODE_OFF: -+ case LG_NOTIFY_TABLET_MODE_ON: -+ /* Already handled by intel-hid */ -+ return; -+ case LG_NOTIFY_HOTKEY: -+ case LG_NOTIFY_THERMAL: -+ case LG_NOTIFY_MISC: -+ ret = lg_laptop_get_event_data(handle, value, &data); -+ if (ret < 0) { -+ dev_notice(input_dev->dev.parent, "Failed to get event data: %d\n", ret); -+ return; -+ } -+ -+ dev_dbg(input_dev->dev.parent, "Received event %u (%u)\n", value, data); -+ -+ lg_laptop_handle_input_event(input_dev, value, data); -+ return; -+ default: -+ dev_notice(input_dev->dev.parent, "Received unknown event %u\n", value); -+ } -+}; -+ -+static void lg_laptop_remove_notify_handler(void *context) -+{ -+ acpi_handle handle = context; -+ -+ acpi_remove_notify_handler(handle, ACPI_ALL_NOTIFY, lg_laptop_notify_handler); -+} -+ -+static void lg_laptop_reenable_wmi_events(void *context) -+{ -+ acpi_handle handle = context; -+ unsigned long long dummy; -+ -+ lg_laptop_execute_orep(handle, LG_OREP_INTERCEPT_WMI_EVENTS, 0, &dummy); -+} -+ -+static int lg_laptop_input_init(struct device *dev, acpi_handle handle) -+{ -+ struct input_dev *input_dev; -+ unsigned long long result; -+ acpi_status status; -+ int ret; -+ -+ if (!acpi_has_method(handle, "_WED")) -+ return 0; -+ -+ input_dev = devm_input_allocate_device(dev); -+ if (!input_dev) -+ return -ENOMEM; -+ -+ input_dev->name = "LG WMI hotkeys"; -+ input_dev->phys = "wmi/input0"; -+ input_dev->id.bustype = BUS_HOST; -+ ret = sparse_keymap_setup(input_dev, wmi_keymap, NULL); -+ if (ret < 0) -+ return ret; -+ -+ ret = input_register_device(input_dev); -+ if (ret < 0) -+ return ret; -+ -+ status = acpi_install_notify_handler(handle, ACPI_ALL_NOTIFY, lg_laptop_notify_handler, -+ input_dev); -+ if (ACPI_FAILURE(status)) -+ return -EIO; -+ -+ ret = devm_add_action_or_reset(dev, lg_laptop_remove_notify_handler, handle); -+ if (ret < 0) -+ return ret; -+ -+ if (acpi_has_method(handle, "OREP")) { -+ ret = lg_laptop_execute_orep(handle, LG_OREP_INTERCEPT_WMI_EVENTS, 1, &result); -+ if (ret < 0) -+ return ret; -+ if (result) -+ return -EIO; -+ -+ ret = devm_add_action_or_reset(dev, lg_laptop_reenable_wmi_events, handle); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ - static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physical_address address, - size_t size, u64 value) - { -@@ -865,10 +1036,6 @@ static int acpi_probe(struct platform_device *pdev) - if (year >= 2019) - battery_limit_use_wmbb = 1; - -- ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group); -- if (ret) -- goto out_platform_device; -- - /* LEDs are optional */ - ret = devm_led_classdev_register(&pdev->dev, &kbd_backlight); - if (ret < 0) -@@ -878,7 +1045,14 @@ static int acpi_probe(struct platform_device *pdev) - - devm_led_classdev_register(&pdev->dev, &tpad_led); - -- wmi_input_setup(); -+ ret = lg_laptop_input_init(&pdev->dev, device->handle); -+ if (ret < 0) -+ goto out_platform_device; -+ -+ ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group); -+ if (ret) -+ goto out_platform_device; -+ - battery_hook_register(&battery_hook); - - return 0; -@@ -895,7 +1069,6 @@ static void acpi_remove(struct platform_device *pdev) - sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group); - - battery_hook_unregister(&battery_hook); -- wmi_input_destroy(); - platform_device_unregister(pf_device); - pf_device = NULL; - platform_driver_unregister(&pf_driver); -diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c ---- a/drivers/platform/x86/msi-ec.c -+++ b/drivers/platform/x86/msi-ec.c -@@ -1055,6 +1055,7 @@ static struct msi_ec_conf CONF12 __initdata = { - - static const char * const ALLOWED_FW_13[] __initconst = { - "1594EMS1.109", // MSI Prestige 16 Studio A13VE -+ "17L1EMS1.107", // MSI Katana GF76 11UEK - NULL - }; - -@@ -1130,6 +1131,86 @@ static struct msi_ec_conf CONF13 __initdata = { - }, - }; - -+static const char * const ALLOWED_FW_14[] __initconst = { -+ "1824EMS1.108", // Raider 18 HX AI A2XWJG (MS-1824) -+ "182LIMS1.108", // Vector A18 HX A9WHG -+ "182LIMS1.111", // MSI Raider A18 HX A9WJG / Vector A18 HX A9WHG -+ "182KIMS1.113", // Raider A18 HX A7VIG -+ NULL -+}; -+ -+static struct msi_ec_conf CONF14 __initdata = { -+ .allowed_fw = ALLOWED_FW_14, -+ .charge_control = { -+ .address = 0xd7, -+ .offset_start = 0x8a, -+ .offset_end = 0x80, -+ .range_min = 0x8a, -+ .range_max = 0xe4, -+ }, -+ .webcam = { -+ .address = 0x2e, -+ .block_address = 0x2f, -+ .bit = 1, -+ }, -+ .fn_win_swap = { -+ .address = 0xe8, -+ .bit = 4, -+ }, -+ .cooler_boost = { -+ .address = 0x98, -+ .bit = 7, -+ }, -+ .shift_mode = { -+ .address = 0xd2, -+ .modes = { -+ { SM_ECO_NAME, 0xc2 }, -+ { SM_COMFORT_NAME, 0xc1 }, -+ { SM_TURBO_NAME, 0xc4 }, -+ MSI_EC_MODE_NULL -+ }, -+ }, -+ .super_battery = { -+ .address = 0xeb, -+ .mask = 0x0f, -+ }, -+ .fan_mode = { -+ .address = 0xd4, -+ .modes = { -+ { FM_AUTO_NAME, 0x0d }, -+ { FM_SILENT_NAME, 0x1d }, -+ { FM_ADVANCED_NAME, 0x8d }, -+ MSI_EC_MODE_NULL -+ }, -+ }, -+ .cpu = { -+ .rt_temp_address = 0x68, -+ .rt_fan_speed_address = 0x71, -+ .rt_fan_speed_base_min = 0x00, -+ .rt_fan_speed_base_max = 0x96, -+ .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, -+ .bs_fan_speed_base_min = 0x00, -+ .bs_fan_speed_base_max = 0x0f, -+ }, -+ .gpu = { -+ .rt_temp_address = 0x80, -+ .rt_fan_speed_address = 0x89, -+ }, -+ .leds = { -+ .micmute_led_address = 0x2c, -+ .mute_led_address = 0x2d, -+ .bit = 1, -+ }, -+ .kbd_bl = { -+ .bl_mode_address = MSI_EC_ADDR_UNSUPP, -+ .bl_modes = { 0x00, 0x08 }, -+ .max_mode = 1, -+ .bl_state_address = MSI_EC_ADDR_UNSUPP, -+ .state_base_value = 0x80, -+ .max_state = 3, -+ }, -+}; -+ - static struct msi_ec_conf *CONFIGS[] __initdata = { - &CONF0, - &CONF1, -@@ -1145,6 +1226,7 @@ static struct msi_ec_conf *CONFIGS[] __initdata = { - &CONF11, - &CONF12, - &CONF13, -+ &CONF14, - NULL - }; - -diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c ---- a/drivers/platform/x86/msi-wmi.c -+++ b/drivers/platform/x86/msi-wmi.c -@@ -46,6 +46,12 @@ enum msi_scancodes { - WIND_KEY_WLAN = 0x5f, /* Fn+F11 Wi-Fi toggle */ - WIND_KEY_TURBO, /* Fn+F10 turbo mode toggle */ - WIND_KEY_ECO = 0x69, /* Fn+F10 ECO mode toggle */ -+ /* MSI Claw keys */ -+ CLAW_KEY_VOLUMEDOWN = 0x21, -+ CLAW_KEY_CENTER = 0x29, /* MSI M-Center main menu */ -+ CLAW_KEY_QUICK_LONG = 0x2a, /* MSI M-Center quick access long hold */ -+ CLAW_KEY_VOLUMEUP = 0x32, -+ CLAW_KEY_QUICK_SHORT = 0x58, /* MSI M-Center quick access short press */ - }; - static struct key_entry msi_wmi_keymap[] = { - { KE_KEY, MSI_KEY_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, -@@ -69,6 +75,15 @@ static struct key_entry msi_wmi_keymap[] = { - { KE_KEY, WIND_KEY_TURBO, {KEY_PROG1} }, - { KE_KEY, WIND_KEY_ECO, {KEY_PROG2} }, - -+ /* These are MSI Claw keys, used for MSI M-Center in Windows */ -+ { KE_KEY, CLAW_KEY_CENTER, {KEY_F15} }, -+ -+ /* These MSI Claw keys work without WMI. Ignore them to avoid double keycodes */ -+ { KE_IGNORE, CLAW_KEY_QUICK_SHORT }, -+ { KE_IGNORE, CLAW_KEY_QUICK_LONG }, -+ { KE_IGNORE, CLAW_KEY_VOLUMEUP }, -+ { KE_IGNORE, CLAW_KEY_VOLUMEDOWN }, -+ - { KE_END, 0 } - }; - -@@ -172,44 +187,62 @@ static const struct backlight_ops msi_backlight_ops = { - - static void msi_wmi_notify(union acpi_object *obj, void *context) - { -- struct key_entry *key; -+ struct key_entry *key = NULL; -+ int eventcode = 0; - -- if (obj && obj->type == ACPI_TYPE_INTEGER) { -- int eventcode = obj->integer.value; -+ if (!obj) -+ return; -+ -+ switch (obj->type) { -+ case ACPI_TYPE_INTEGER: -+ eventcode = obj->integer.value; - pr_debug("Eventcode: 0x%x\n", eventcode); -- key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev, -- eventcode); -- if (!key) { -- pr_info("Unknown key pressed - %x\n", eventcode); -+ break; -+ case ACPI_TYPE_BUFFER: -+ /* Field returns u8[2] here, but is u32 by spec. Allow "oversized" buffers. */ -+ if (obj->buffer.length < 2) -+ return; -+ -+ /* pointer[0] is key ID, pointer[1] is active state. We don't get release -+ * events, so ignore the active state and treat as autorelease. -+ */ -+ eventcode = obj->buffer.pointer[0]; -+ pr_debug("Eventcode: 0x%x\n", eventcode); -+ break; -+ default: -+ pr_info("Unknown event received\n"); -+ return; -+ } -+ -+ key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev, eventcode); -+ -+ if (!key) { -+ pr_info("Unknown key pressed - 0x%x\n", eventcode); -+ return; -+ } -+ -+ if (event_wmi->quirk_last_pressed) { -+ ktime_t cur = ktime_get_real(); -+ ktime_t diff = ktime_sub(cur, last_pressed); -+ /* Ignore event if any event happened in a 50 ms -+ * timeframe -> Key press may result in 10-20 GPEs -+ */ -+ if (ktime_to_us(diff) < 1000 * 50) { -+ pr_debug("Suppressed key event 0x%X - Last press was %lld us ago\n", -+ key->code, ktime_to_us(diff)); - return; - } -+ last_pressed = cur; -+ } - -- if (event_wmi->quirk_last_pressed) { -- ktime_t cur = ktime_get_real(); -- ktime_t diff = ktime_sub(cur, last_pressed); -- /* Ignore event if any event happened in a 50 ms -- timeframe -> Key press may result in 10-20 GPEs */ -- if (ktime_to_us(diff) < 1000 * 50) { -- pr_debug("Suppressed key event 0x%X - " -- "Last press was %lld us ago\n", -- key->code, ktime_to_us(diff)); -- return; -- } -- last_pressed = cur; -- } -+ /* Brightness is served via acpi video driver */ -+ if (key->type == KE_KEY && -+ (backlight || (key->code == MSI_KEY_BRIGHTNESSUP || -+ key->code == MSI_KEY_BRIGHTNESSDOWN))) -+ return; - -- if (key->type == KE_KEY && -- /* Brightness is served via acpi video driver */ -- (backlight || -- (key->code != MSI_KEY_BRIGHTNESSUP && -- key->code != MSI_KEY_BRIGHTNESSDOWN))) { -- pr_debug("Send key: 0x%X - Input layer keycode: %d\n", -- key->code, key->keycode); -- sparse_keymap_report_entry(msi_wmi_input_dev, key, 1, -- true); -- } -- } else -- pr_info("Unknown event received\n"); -+ pr_debug("Send key: 0x%X - Input layer keycode: %d\n", key->code, key->keycode); -+ sparse_keymap_report_entry(msi_wmi_input_dev, key, 1, true); - } - - static int __init msi_wmi_backlight_setup(void) -diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c ---- a/drivers/platform/x86/oxpec.c -+++ b/drivers/platform/x86/oxpec.c -@@ -289,6 +289,13 @@ static const struct dmi_system_id dmi_table[] = { - }, - .driver_data = (void *)oxp_x1, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), -+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X2Mini PRO"), -+ }, -+ .driver_data = (void *)oxp_fly, -+ }, - {}, - }; - -diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c ---- a/drivers/platform/x86/panasonic-laptop.c -+++ b/drivers/platform/x86/panasonic-laptop.c -@@ -159,8 +159,6 @@ MODULE_LICENSE("GPL"); - #define ECO_MODE_ON 0x80 - - #define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support" --#define ACPI_PCC_DEVICE_NAME "Hotkey" --#define ACPI_PCC_CLASS "pcc" - - #define ACPI_PCC_INPUT_PHYS "panasonic/hkey0" - -@@ -1026,8 +1024,6 @@ static int acpi_pcc_hotkey_probe(struct platform_device *pdev) - pcc->device = device; - pcc->handle = device->handle; - device->driver_data = pcc; -- strscpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME); -- strscpy(acpi_device_class(device), ACPI_PCC_CLASS); - - result = acpi_pcc_init_input(pcc); - if (result) { -diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c ---- a/drivers/platform/x86/redmi-wmi.c -+++ b/drivers/platform/x86/redmi-wmi.c -@@ -29,24 +29,24 @@ static const struct key_entry redmi_wmi_keymap[] = { - {KE_KEY, 0x00011801, {KEY_ASSISTANT}}, - {KE_KEY, 0x00011901, {KEY_ASSISTANT}}, - -- /* Keyboard backlight */ -- {KE_IGNORE, 0x00000501, {}}, -- {KE_IGNORE, 0x00800501, {}}, -- {KE_IGNORE, 0x00050501, {}}, -- {KE_IGNORE, 0x000a0501, {}}, -+ /* Keyboard backlight: Off / Auto / Low / High (new state in byte 2) */ -+ {KE_KEY, 0x00000501, {KEY_KBDILLUMTOGGLE}}, -+ {KE_KEY, 0x00800501, {KEY_KBDILLUMTOGGLE}}, -+ {KE_KEY, 0x00050501, {KEY_KBDILLUMTOGGLE}}, -+ {KE_KEY, 0x000a0501, {KEY_KBDILLUMTOGGLE}}, - - /* Xiaomi G Command Center */ - {KE_KEY, 0x00010a01, {KEY_VENDOR}}, - -- /* OEM preset power mode */ -- {KE_IGNORE, 0x00011601, {}}, -- {KE_IGNORE, 0x00021601, {}}, -- {KE_IGNORE, 0x00031601, {}}, -- {KE_IGNORE, 0x00041601, {}}, -+ /* OEM preset power mode: 1=Balanced 2=Silent 3=Turbo 4=Full speed */ -+ {KE_KEY, 0x00011601, {KEY_PERFORMANCE}}, -+ {KE_KEY, 0x00021601, {KEY_PERFORMANCE}}, -+ {KE_KEY, 0x00031601, {KEY_PERFORMANCE}}, -+ {KE_KEY, 0x00041601, {KEY_PERFORMANCE}}, - -- /* Fn Lock state */ -- {KE_IGNORE, 0x00000701, {}}, -- {KE_IGNORE, 0x00010701, {}}, -+ /* Fn Lock state: 1=on 0=off */ -+ {KE_KEY, 0x00000701, {KEY_FN_ESC}}, -+ {KE_KEY, 0x00010701, {KEY_FN_ESC}}, - - /* Fn+`/1/2/3/4 */ - {KE_KEY, 0x00011101, {KEY_F13}}, -diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c ---- a/drivers/platform/x86/samsung-galaxybook.c -+++ b/drivers/platform/x86/samsung-galaxybook.c -@@ -1438,6 +1438,7 @@ static const struct acpi_device_id galaxybook_device_ids[] = { - { "SAM0428" }, - { "SAM0429" }, - { "SAM0430" }, -+ { "SAMB430" }, - {} - }; - MODULE_DEVICE_TABLE(acpi, galaxybook_device_ids); -diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c ---- a/drivers/platform/x86/sony-laptop.c -+++ b/drivers/platform/x86/sony-laptop.c -@@ -1264,7 +1264,7 @@ static void sony_nc_notify(acpi_handle ah, u32 event, void *data) - ev_type = HOTKEY; - sony_laptop_report_input_event(real_ev); - } -- acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class, -+ acpi_bus_generate_netlink_event("sony/hotkey", - dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev); - } - -@@ -3157,8 +3157,6 @@ static int sony_nc_probe(struct platform_device *pdev) - return -ENODEV; - - sony_nc_acpi_device = device; -- strscpy(acpi_device_class(device), "sony/hotkey"); -- - sony_nc_acpi_handle = device->handle; - - /* read device status */ -@@ -4523,7 +4521,6 @@ static int sony_pic_probe(struct platform_device *pdev) - return -ENODEV; - - spic_dev.acpi_dev = device; -- strscpy(acpi_device_class(device), "sony/hotkey"); - sony_pic_detect_device_type(&spic_dev); - mutex_init(&spic_dev.lock); - -diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c ---- a/drivers/platform/x86/topstar-laptop.c -+++ b/drivers/platform/x86/topstar-laptop.c -@@ -299,8 +299,6 @@ static int topstar_acpi_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, topstar); - -- strscpy(acpi_device_name(device), "Topstar TPSACPI"); -- strscpy(acpi_device_class(device), TOPSTAR_LAPTOP_CLASS); - topstar->device = device; - - err = topstar_acpi_init(topstar); -diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c ---- a/drivers/platform/x86/toshiba_acpi.c -+++ b/drivers/platform/x86/toshiba_acpi.c -@@ -2505,8 +2505,7 @@ static void toshiba_acpi_kbd_bl_work(struct work_struct *work) - LED_FULL : LED_OFF); - - /* Emulate the keyboard backlight event */ -- acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class, -- dev_name(&toshiba_acpi->acpi_dev->dev), -+ acpi_bus_generate_netlink_event("", dev_name(&toshiba_acpi->acpi_dev->dev), - 0x92, 0); - } - -@@ -3250,8 +3249,7 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *data) - break; - } - -- acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, -- dev_name(&acpi_dev->dev), -+ acpi_bus_generate_netlink_event("", dev_name(&acpi_dev->dev), - event, (event == 0x80) ? - dev->last_key_event : 0); - } -diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c ---- a/drivers/platform/x86/toshiba_bluetooth.c -+++ b/drivers/platform/x86/toshiba_bluetooth.c -@@ -252,10 +252,8 @@ static int toshiba_bt_rfkill_probe(struct platform_device *pdev) - platform_set_drvdata(pdev, bt_dev); - - result = toshiba_bluetooth_sync_status(bt_dev); -- if (result) { -- kfree(bt_dev); -- return result; -- } -+ if (result) -+ goto err_free_bt_dev; - - bt_dev->rfk = rfkill_alloc("Toshiba Bluetooth", - &pdev->dev, -diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c ---- a/drivers/platform/x86/toshiba_haps.c -+++ b/drivers/platform/x86/toshiba_haps.c -@@ -136,9 +136,7 @@ static void toshiba_haps_notify(acpi_handle handle, u32 event, void *data) - - pr_debug("Received event: 0x%x\n", event); - -- acpi_bus_generate_netlink_event(device->pnp.device_class, -- dev_name(&device->dev), -- event, 0); -+ acpi_bus_generate_netlink_event("", dev_name(&device->dev), event, 0); - } - - static void toshiba_haps_remove(struct platform_device *pdev) -diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c ---- a/drivers/platform/x86/uniwill/uniwill-acpi.c -+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c -@@ -95,6 +95,9 @@ - - #define EC_ADDR_MAIN_FAN_RPM_2 0x0465 - -+#define EC_ADDR_SCREEN_STATUS 0x0466 -+#define SCREEN_SUSPENDED BIT(6) -+ - #define EC_ADDR_SECOND_FAN_RPM_1 0x046C - - #define EC_ADDR_SECOND_FAN_RPM_2 0x046D -@@ -109,9 +112,35 @@ - - #define EC_ADDR_BAT_CYCLE_COUNT_2 0x04A7 - -+#define EC_ADDR_OEM_9 0x0726 -+#define AC_AUTO_BOOT_ENABLE BIT(3) -+ - #define EC_ADDR_PROJECT_ID 0x0740 -+#define PROJECT_ID_NONE 0x00 -+#define PROJECT_ID_GI 0x01 -+#define PROJECT_ID_GJ 0x02 -+#define PROJECT_ID_GK 0x03 -+#define PROJECT_ID_GICN 0x04 -+#define PROJECT_ID_GJCN 0x05 -+#define PROJECT_ID_GK5CN_X 0x06 -+#define PROJECT_ID_GK7CN_S 0x07 -+#define PROJECT_ID_GK7CPCS_GK5CQ7Z 0x08 -+#define PROJECT_ID_PF 0x09 -+#define PROJECT_ID_GK5CP_4X_5X_6X 0x0A -+#define PROJECT_ID_IDP 0x0B -+#define PROJECT_ID_IDY_6Y 0x0C -+#define PROJECT_ID_IDY_7Y 0x0D -+#define PROJECT_ID_PF4MU_PF4MN_PF5MU 0x0E -+#define PROJECT_ID_CML_GAMING 0x0F -+#define PROJECT_ID_GK7NXXR 0x10 -+#define PROJECT_ID_GM5MU1Y 0x11 - #define PROJECT_ID_PH4TRX1 0x12 -+#define PROJECT_ID_PH4TUX1 0x13 -+#define PROJECT_ID_PH4TQX1 0x14 - #define PROJECT_ID_PH6TRX1 0x15 -+#define PROJECT_ID_PH6TQXX 0x16 -+#define PROJECT_ID_PHXAXXX 0x17 -+#define PROJECT_ID_PHXPXXX 0x18 - - #define EC_ADDR_AP_OEM 0x0741 - #define ENABLE_MANUAL_CTRL BIT(0) -@@ -214,6 +243,7 @@ - #define FAN_TABLE_OFFICE_MODE BIT(2) - #define FAN_V3 BIT(3) - #define DEFAULT_MODE BIT(4) -+#define ENABLE_CHINA_MODE BIT(6) - - #define EC_ADDR_PL1_SETTING 0x0783 - -@@ -225,11 +255,12 @@ - #define FAN_CURVE_LENGTH 5 - - #define EC_ADDR_KBD_STATUS 0x078C --#define KBD_WHITE_ONLY BIT(0) // ~single color --#define KBD_SINGLE_COLOR_OFF BIT(1) -+/* Unreliable on some models, use the device descriptor instead. */ -+#define KBD_WHITE_ONLY BIT(0) -+#define KBD_POWER_OFF BIT(1) - #define KBD_TURBO_LEVEL_MASK GENMASK(3, 2) - #define KBD_APPLY BIT(4) --#define KBD_BRIGHTNESS GENMASK(7, 5) -+#define KBD_BRIGHTNESS_MASK GENMASK(7, 5) - - #define EC_ADDR_FAN_CTRL 0x078E - #define FAN3P5 BIT(1) -@@ -318,7 +349,9 @@ - #define FAN_TABLE_LENGTH 16 - - #define LED_CHANNELS 3 --#define LED_MAX_BRIGHTNESS 200 -+ -+#define KBD_LED_CHANNELS 3 -+#define KBD_LED_MAX_INTENSITY 50 - - #define UNIWILL_FEATURE_FN_LOCK BIT(0) - #define UNIWILL_FEATURE_SUPER_KEY BIT(1) -@@ -333,6 +366,9 @@ - #define UNIWILL_FEATURE_SECONDARY_FAN BIT(9) - #define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL BIT(10) - #define UNIWILL_FEATURE_USB_C_POWER_PRIORITY BIT(11) -+#define UNIWILL_FEATURE_KEYBOARD_BACKLIGHT BIT(12) -+#define UNIWILL_FEATURE_AC_AUTO_BOOT BIT(13) -+#define UNIWILL_FEATURE_USB_POWERSHARE BIT(14) - - enum usb_c_power_priority_options { - USB_C_POWER_PRIORITY_CHARGING = 0, -@@ -344,6 +380,7 @@ struct uniwill_data { - acpi_handle handle; - struct regmap *regmap; - unsigned int features; -+ u8 project_id; - struct acpi_battery_hook hook; - struct mutex battery_lock; /* Protects the list of currently registered batteries */ - union { -@@ -357,11 +394,25 @@ struct uniwill_data { - bool last_fn_lock_state; - bool last_super_key_enable_state; - bool last_touchpad_toggle_enable_state; -+ bool last_usb_powershare_high_state; - struct mutex super_key_lock; /* Protects the toggling of the super key lock state */ - struct list_head batteries; - struct mutex led_lock; /* Protects writes to the lightbar registers */ -+ u8 lightbar_max_brightness; - struct led_classdev_mc led_mc_cdev; - struct mc_subled led_mc_subled_info[LED_CHANNELS]; -+ bool kbd_led_single_color; -+ u8 kbd_led_max_brightness; -+ unsigned int last_kbd_status; -+ union { -+ struct { -+ /* Protects writes to the RGB keyboard backlight registers */ -+ struct mutex kbd_rgb_led_lock; -+ struct led_classdev_mc kbd_led_mc_cdev; -+ struct mc_subled kbd_led_mc_subled_info[KBD_LED_CHANNELS]; -+ }; -+ struct led_classdev kbd_led_cdev; -+ }; - struct mutex input_lock; /* Protects input sequence during notify */ - struct input_dev *input_device; - struct notifier_block nb; -@@ -376,6 +427,9 @@ struct uniwill_battery_entry { - - struct uniwill_device_descriptor { - unsigned int features; -+ bool kbd_led_single_color; -+ u8 kbd_led_max_brightness; -+ u8 lightbar_max_brightness; - /* Executed during driver probing */ - int (*probe)(struct uniwill_data *data); - }; -@@ -427,6 +481,9 @@ static const struct key_entry uniwill_keymap[] = { - { KE_KEY, UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }}, - { KE_KEY, UNIWILL_OSD_KBDILLUMUP, { KEY_KBDILLUMUP }}, - -+ /* Reported when the EC changed the keyboard backlight brightness */ -+ { KE_IGNORE, UNIWILL_OSD_BACKLIGHT_LEVEL_CHANGE, { KEY_UNKNOWN }}, -+ - /* Reported when the user wants to toggle the microphone mute status */ - { KE_KEY, UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }}, - -@@ -435,11 +492,6 @@ static const struct key_entry uniwill_keymap[] = { - - /* Reported when the user wants to toggle the brightness of the keyboard */ - { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }}, -- { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }}, -- { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }}, -- { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }}, -- { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }}, -- { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }}, - - /* FIXME: find out the exact meaning of those events */ - { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }}, -@@ -448,6 +500,9 @@ static const struct key_entry uniwill_keymap[] = { - /* Reported when the user wants to toggle the benchmark mode status */ - { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN }}, - -+ /* Reported when the screen is enabled/disabled during resume/suspend */ -+ { KE_IGNORE, UNIWILL_OSD_SCREEN_STATE_CHANGED, { KEY_UNKNOWN }}, -+ - /* Reported when the user wants to toggle the webcam */ - { KE_IGNORE, UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }}, - -@@ -540,6 +595,7 @@ static const struct regmap_bus uniwill_ec_bus = { - static bool uniwill_writeable_reg(struct device *dev, unsigned int reg) - { - switch (reg) { -+ case EC_ADDR_OEM_9: - case EC_ADDR_AP_OEM: - case EC_ADDR_LIGHTBAR_AC_CTRL: - case EC_ADDR_LIGHTBAR_AC_RED: -@@ -547,6 +603,11 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg) - case EC_ADDR_LIGHTBAR_AC_BLUE: - case EC_ADDR_BIOS_OEM: - case EC_ADDR_TRIGGER: -+ case EC_ADDR_RGB_RED: -+ case EC_ADDR_RGB_GREEN: -+ case EC_ADDR_RGB_BLUE: -+ case EC_ADDR_BIOS_OEM_2: -+ case EC_ADDR_KBD_STATUS: - case EC_ADDR_OEM_4: - case EC_ADDR_CHARGE_CTRL: - case EC_ADDR_LIGHTBAR_BAT_CTRL: -@@ -574,6 +635,7 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg) - case EC_ADDR_SECOND_FAN_RPM_1: - case EC_ADDR_SECOND_FAN_RPM_2: - case EC_ADDR_BAT_ALERT: -+ case EC_ADDR_OEM_9: - case EC_ADDR_PROJECT_ID: - case EC_ADDR_AP_OEM: - case EC_ADDR_LIGHTBAR_AC_CTRL: -@@ -583,8 +645,14 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg) - case EC_ADDR_BIOS_OEM: - case EC_ADDR_PWM_1: - case EC_ADDR_PWM_2: -+ case EC_ADDR_SUPPORT_2: - case EC_ADDR_TRIGGER: - case EC_ADDR_SWITCH_STATUS: -+ case EC_ADDR_RGB_RED: -+ case EC_ADDR_RGB_GREEN: -+ case EC_ADDR_RGB_BLUE: -+ case EC_ADDR_BIOS_OEM_2: -+ case EC_ADDR_KBD_STATUS: - case EC_ADDR_OEM_4: - case EC_ADDR_CHARGE_CTRL: - case EC_ADDR_LIGHTBAR_BAT_CTRL: -@@ -616,8 +684,10 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg) - case EC_ADDR_BIOS_OEM: - case EC_ADDR_PWM_1: - case EC_ADDR_PWM_2: -+ case EC_ADDR_SUPPORT_2: - case EC_ADDR_TRIGGER: - case EC_ADDR_SWITCH_STATUS: -+ case EC_ADDR_KBD_STATUS: - case EC_ADDR_OEM_4: - case EC_ADDR_CHARGE_CTRL: - case EC_ADDR_USB_C_POWER_PRIORITY: -@@ -1077,6 +1147,109 @@ static int usb_c_power_priority_init(struct uniwill_data *data) - return 0; - } - -+static ssize_t ac_auto_boot_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct uniwill_data *data = dev_get_drvdata(dev); -+ unsigned int regval; -+ bool enable; -+ int ret; -+ -+ ret = kstrtobool(buf, &enable); -+ if (ret < 0) -+ return ret; -+ -+ if (enable) -+ regval = AC_AUTO_BOOT_ENABLE; -+ else -+ regval = 0; -+ -+ ret = regmap_update_bits(data->regmap, EC_ADDR_OEM_9, AC_AUTO_BOOT_ENABLE, regval); -+ if (ret < 0) -+ return ret; -+ -+ return count; -+} -+ -+static ssize_t ac_auto_boot_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ struct uniwill_data *data = dev_get_drvdata(dev); -+ unsigned int regval; -+ int ret; -+ -+ ret = regmap_read(data->regmap, EC_ADDR_OEM_9, ®val); -+ if (ret < 0) -+ return ret; -+ -+ return sysfs_emit(buf, "%d\n", !!(regval & AC_AUTO_BOOT_ENABLE)); -+} -+ -+static DEVICE_ATTR_RW(ac_auto_boot); -+ -+static int uniwill_write_usb_powershare_high(struct uniwill_data *data, bool status) -+{ -+ unsigned int value; -+ -+ if (status) -+ value = TRIGGER_USB_CHARGING; -+ else -+ value = 0; -+ -+ /* -+ * Normaly this RMW-sequence could also trigger the super key toggle, -+ * but the EC seems to take care that those bits are always read as 0. -+ */ -+ return regmap_update_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_USB_CHARGING, value); -+} -+ -+static ssize_t usb_powershare_high_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct uniwill_data *data = dev_get_drvdata(dev); -+ bool enable; -+ int ret; -+ -+ ret = kstrtobool(buf, &enable); -+ if (ret < 0) -+ return ret; -+ -+ ret = uniwill_write_usb_powershare_high(data, enable); -+ if (ret < 0) -+ return ret; -+ -+ return count; -+} -+ -+static int uniwill_read_usb_powershare_high(struct uniwill_data *data, bool *status) -+{ -+ unsigned int value; -+ int ret; -+ -+ ret = regmap_read(data->regmap, EC_ADDR_TRIGGER, &value); -+ if (ret < 0) -+ return ret; -+ -+ *status = !!(value & TRIGGER_USB_CHARGING); -+ -+ return 0; -+} -+ -+static ssize_t usb_powershare_high_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct uniwill_data *data = dev_get_drvdata(dev); -+ bool status; -+ int ret; -+ -+ ret = uniwill_read_usb_powershare_high(data, &status); -+ if (ret < 0) -+ return ret; -+ -+ return sysfs_emit(buf, "%d\n", status); -+} -+ -+static DEVICE_ATTR_RW(usb_powershare_high); -+ - static struct attribute *uniwill_attrs[] = { - /* Keyboard-related */ - &dev_attr_fn_lock.attr, -@@ -1088,6 +1261,8 @@ static struct attribute *uniwill_attrs[] = { - /* Power-management-related */ - &dev_attr_ctgp_offset.attr, - &dev_attr_usb_c_power_priority.attr, -+ &dev_attr_ac_auto_boot.attr, -+ &dev_attr_usb_powershare_high.attr, - NULL - }; - -@@ -1127,6 +1302,16 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a - return attr->mode; - } - -+ if (attr == &dev_attr_ac_auto_boot.attr) { -+ if (uniwill_device_supports(data, UNIWILL_FEATURE_AC_AUTO_BOOT)) -+ return attr->mode; -+ } -+ -+ if (attr == &dev_attr_usb_powershare_high.attr) { -+ if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_POWERSHARE)) -+ return attr->mode; -+ } -+ - return 0; - } - -@@ -1332,7 +1517,7 @@ static int uniwill_led_brightness_set(struct led_classdev *led_cdev, enum led_br - - for (int i = 0; i < LED_CHANNELS; i++) { - /* Prevent the brightness values from overflowing */ -- value = min(LED_MAX_BRIGHTNESS, data->led_mc_subled_info[i].brightness); -+ value = min(data->lightbar_max_brightness, data->led_mc_subled_info[i].brightness); - ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value); - if (ret < 0) - return ret; -@@ -1401,14 +1586,14 @@ static int uniwill_led_init(struct uniwill_data *data) - return ret; - - data->led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI; -- data->led_mc_cdev.led_cdev.max_brightness = LED_MAX_BRIGHTNESS; -+ data->led_mc_cdev.led_cdev.max_brightness = data->lightbar_max_brightness; - data->led_mc_cdev.led_cdev.flags = LED_REJECT_NAME_CONFLICT; - data->led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_led_brightness_set; - - if (value & LIGHTBAR_S0_OFF) - data->led_mc_cdev.led_cdev.brightness = 0; - else -- data->led_mc_cdev.led_cdev.brightness = LED_MAX_BRIGHTNESS; -+ data->led_mc_cdev.led_cdev.brightness = data->lightbar_max_brightness; - - for (int i = 0; i < LED_CHANNELS; i++) { - data->led_mc_subled_info[i].color_index = color_indices[i]; -@@ -1421,7 +1606,7 @@ static int uniwill_led_init(struct uniwill_data *data) - * Make sure that the initial intensity value is not greater than - * the maximum brightness. - */ -- value = min(LED_MAX_BRIGHTNESS, value); -+ value = min(data->lightbar_max_brightness, value); - ret = regmap_write(data->regmap, uniwill_led_channel_to_ac_reg[i], value); - if (ret < 0) - return ret; -@@ -1441,6 +1626,246 @@ static int uniwill_led_init(struct uniwill_data *data) - &init_data); - } - -+static int uniwill_notify_kbd_led(struct uniwill_data *data, int brightness) -+{ -+ struct led_classdev *led_cdev; -+ int ret; -+ -+ if (data->kbd_led_single_color) -+ led_cdev = &data->kbd_led_cdev; -+ else -+ led_cdev = &data->kbd_led_mc_cdev.led_cdev; -+ -+ guard(mutex)(&led_cdev->led_access); -+ -+ /* Sync the LED brightness with the actual hardware state */ -+ ret = led_update_brightness(led_cdev); -+ if (ret < 0) -+ return ret; -+ -+ led_classdev_notify_brightness_hw_changed(led_cdev, brightness); -+ -+ return 0; -+} -+ -+#define KBD_LED_MASK (KBD_BRIGHTNESS_MASK | KBD_APPLY | KBD_POWER_OFF) -+ -+static int uniwill_kbd_led_write_brightness(struct uniwill_data *data, int brightness) -+{ -+ /* KBD_POWER_OFF is always implicitly cleared */ -+ unsigned int regval = FIELD_PREP(KBD_BRIGHTNESS_MASK, brightness) | KBD_APPLY; -+ -+ /* We must ensure that the "apply" bit is always written */ -+ return regmap_write_bits(data->regmap, EC_ADDR_KBD_STATUS, KBD_LED_MASK, regval); -+} -+ -+static int uniwill_kbd_led_read_brightness(struct uniwill_data *data) -+{ -+ unsigned int regval; -+ int ret; -+ -+ ret = regmap_read(data->regmap, EC_ADDR_KBD_STATUS, ®val); -+ if (ret < 0) -+ return ret; -+ -+ return min(FIELD_GET(KBD_BRIGHTNESS_MASK, regval), data->kbd_led_max_brightness); -+} -+ -+static int uniwill_kbd_led_brightness_set(struct led_classdev *led_cdev, -+ enum led_brightness brightness) -+{ -+ struct uniwill_data *data = container_of(led_cdev, struct uniwill_data, kbd_led_cdev); -+ -+ return uniwill_kbd_led_write_brightness(data, brightness); -+} -+ -+static enum led_brightness uniwill_kbd_led_brightness_get(struct led_classdev *led_cdev) -+{ -+ struct uniwill_data *data = container_of(led_cdev, struct uniwill_data, kbd_led_cdev); -+ -+ return uniwill_kbd_led_read_brightness(data); -+} -+ -+static const unsigned int uniwill_kbd_led_channel_to_reg[KBD_LED_CHANNELS] = { -+ EC_ADDR_RGB_RED, -+ EC_ADDR_RGB_GREEN, -+ EC_ADDR_RGB_BLUE, -+}; -+ -+static int uniwill_kbd_led_mc_brightness_set(struct led_classdev *led_cdev, -+ enum led_brightness brightness) -+{ -+ struct led_classdev_mc *led_mc_cdev = lcdev_to_mccdev(led_cdev); -+ struct uniwill_data *data = container_of(led_mc_cdev, struct uniwill_data, kbd_led_mc_cdev); -+ unsigned int min_intensity = 0; -+ unsigned int regval; -+ int ret; -+ -+ guard(mutex)(&data->kbd_rgb_led_lock); -+ -+ /* -+ * The EC interprets a RGB value of 0x000000 as a command to restore -+ * the device-specfic default RGB value. Work around this by writing -+ * a RGB value of 0x010101 (faint white) instead. -+ */ -+ if (data->kbd_led_mc_subled_info[0].intensity == 0 && -+ data->kbd_led_mc_subled_info[1].intensity == 0 && -+ data->kbd_led_mc_subled_info[2].intensity == 0) -+ min_intensity = 1; -+ -+ for (int i = 0; i < KBD_LED_CHANNELS; i++) { -+ regval = max(data->kbd_led_mc_subled_info[i].intensity, min_intensity); -+ ret = regmap_write(data->regmap, uniwill_kbd_led_channel_to_reg[i], regval); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, RGB_APPLY_COLOR, RGB_APPLY_COLOR); -+ if (ret < 0) -+ return ret; -+ -+ return uniwill_kbd_led_write_brightness(data, brightness); -+} -+ -+static enum led_brightness uniwill_kbd_led_mc_brightness_get(struct led_classdev *led_cdev) -+{ -+ struct led_classdev_mc *led_mc_cdev = lcdev_to_mccdev(led_cdev); -+ struct uniwill_data *data = container_of(led_mc_cdev, struct uniwill_data, kbd_led_mc_cdev); -+ -+ return uniwill_kbd_led_read_brightness(data); -+} -+ -+static int uniwill_white_kbd_led_init(struct uniwill_data *data) -+{ -+ struct led_init_data init_data = { -+ .default_label = "white:" LED_FUNCTION_KBD_BACKLIGHT, -+ .devicename = DRIVER_NAME, -+ .devname_mandatory = true, -+ }; -+ -+ data->kbd_led_cdev.max_brightness = data->kbd_led_max_brightness; -+ data->kbd_led_cdev.color = LED_COLOR_ID_WHITE; -+ data->kbd_led_cdev.flags = LED_BRIGHT_HW_CHANGED | LED_REJECT_NAME_CONFLICT; -+ data->kbd_led_cdev.brightness_set_blocking = uniwill_kbd_led_brightness_set; -+ data->kbd_led_cdev.brightness_get = uniwill_kbd_led_brightness_get; -+ -+ return devm_led_classdev_register_ext(data->dev, &data->kbd_led_cdev, &init_data); -+} -+ -+static int uniwill_rgb_kbd_led_init(struct uniwill_data *data) -+{ -+ unsigned int color_indices[KBD_LED_CHANNELS] = { -+ LED_COLOR_ID_RED, -+ LED_COLOR_ID_GREEN, -+ LED_COLOR_ID_BLUE, -+ }; -+ struct led_init_data init_data = { -+ .default_label = "multicolor:" LED_FUNCTION_KBD_BACKLIGHT, -+ .devicename = DRIVER_NAME, -+ .devname_mandatory = true, -+ }; -+ bool intensity_all_zeros = true; -+ bool needs_trigger = false; -+ unsigned int regval; -+ int ret; -+ -+ for (int i = 0; i < KBD_LED_CHANNELS; i++) { -+ data->kbd_led_mc_subled_info[i].color_index = color_indices[i]; -+ -+ ret = regmap_read(data->regmap, uniwill_kbd_led_channel_to_reg[i], ®val); -+ if (ret < 0) -+ return ret; -+ -+ /* -+ * Make sure that the initial intensity value is not greater than -+ * the maximum intensity. -+ */ -+ if (regval > KBD_LED_MAX_INTENSITY) { -+ regval = KBD_LED_MAX_INTENSITY; -+ ret = regmap_write(data->regmap, uniwill_kbd_led_channel_to_reg[i], regval); -+ if (ret < 0) -+ return ret; -+ -+ needs_trigger = true; -+ } -+ -+ if (regval) -+ intensity_all_zeros = false; -+ -+ data->kbd_led_mc_subled_info[i].intensity = regval; -+ data->kbd_led_mc_subled_info[i].max_intensity = KBD_LED_MAX_INTENSITY; -+ data->kbd_led_mc_subled_info[i].channel = i; -+ } -+ -+ /* See uniwill_kbd_led_mc_brightness_set() for an explaination. */ -+ if (intensity_all_zeros) { -+ for (int i = 0; i < KBD_LED_CHANNELS; i++) { -+ data->kbd_led_mc_subled_info[i].intensity = 1; -+ ret = regmap_write(data->regmap, uniwill_kbd_led_channel_to_reg[i], 1); -+ if (ret < 0) -+ return ret; -+ } -+ -+ needs_trigger = true; -+ } -+ -+ if (needs_trigger) { -+ ret = regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, RGB_APPLY_COLOR, -+ RGB_APPLY_COLOR); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = devm_mutex_init(data->dev, &data->kbd_rgb_led_lock); -+ if (ret < 0) -+ return ret; -+ -+ data->kbd_led_mc_cdev.led_cdev.max_brightness = data->kbd_led_max_brightness; -+ data->kbd_led_mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI; -+ data->kbd_led_mc_cdev.led_cdev.flags = LED_BRIGHT_HW_CHANGED | LED_REJECT_NAME_CONFLICT; -+ data->kbd_led_mc_cdev.led_cdev.brightness_set_blocking = uniwill_kbd_led_mc_brightness_set; -+ data->kbd_led_mc_cdev.led_cdev.brightness_get = uniwill_kbd_led_mc_brightness_get; -+ data->kbd_led_mc_cdev.subled_info = data->kbd_led_mc_subled_info; -+ data->kbd_led_mc_cdev.num_colors = KBD_LED_CHANNELS; -+ -+ return devm_led_classdev_multicolor_register_ext(data->dev, &data->kbd_led_mc_cdev, -+ &init_data); -+} -+ -+static int uniwill_kbd_led_init(struct uniwill_data *data) -+{ -+ unsigned int regval; -+ int ret; -+ -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return 0; -+ -+ ret = regmap_read(data->regmap, EC_ADDR_SUPPORT_2, ®val); -+ if (ret < 0) -+ return ret; -+ -+ if (!(regval & CHINA_MODE)) { -+ ret = regmap_set_bits(data->regmap, EC_ADDR_BIOS_OEM_2, ENABLE_CHINA_MODE); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = regmap_read(data->regmap, EC_ADDR_KBD_STATUS, ®val); -+ if (ret < 0) -+ return ret; -+ -+ regval |= KBD_APPLY; -+ regval &= ~KBD_POWER_OFF; -+ ret = regmap_write(data->regmap, EC_ADDR_KBD_STATUS, regval); -+ if (ret < 0) -+ return ret; -+ -+ if (data->kbd_led_single_color) -+ return uniwill_white_kbd_led_init(data); -+ -+ return uniwill_rgb_kbd_led_init(data); -+} -+ - static unsigned int uniwill_sanitize_battery_threshold(unsigned int value) - { - /* 0 means "charging threshold not active" */ -@@ -1789,6 +2214,31 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action - sysfs_notify(&data->dev->kobj, NULL, "fn_lock"); - - return NOTIFY_OK; -+ case UNIWILL_OSD_KB_LED_LEVEL0: -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return NOTIFY_DONE; -+ -+ return notifier_from_errno(uniwill_notify_kbd_led(data, 0)); -+ case UNIWILL_OSD_KB_LED_LEVEL1: -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return NOTIFY_DONE; -+ -+ return notifier_from_errno(uniwill_notify_kbd_led(data, 1)); -+ case UNIWILL_OSD_KB_LED_LEVEL2: -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return NOTIFY_DONE; -+ -+ return notifier_from_errno(uniwill_notify_kbd_led(data, 2)); -+ case UNIWILL_OSD_KB_LED_LEVEL3: -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return NOTIFY_DONE; -+ -+ return notifier_from_errno(uniwill_notify_kbd_led(data, 3)); -+ case UNIWILL_OSD_KB_LED_LEVEL4: -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return NOTIFY_DONE; -+ -+ return notifier_from_errno(uniwill_notify_kbd_led(data, 4)); - default: - mutex_lock(&data->input_lock); - sparse_keymap_report_event(data->input_device, action, 1, true); -@@ -1842,6 +2292,7 @@ static int uniwill_ec_init(struct uniwill_data *data) - if (ret < 0) - return ret; - -+ data->project_id = value; - dev_dbg(data->dev, "Project ID: %u\n", value); - - ret = regmap_set_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL); -@@ -1885,6 +2336,9 @@ static int uniwill_probe(struct platform_device *pdev) - return ret; - - data->features = device_descriptor.features; -+ data->kbd_led_single_color = device_descriptor.kbd_led_single_color; -+ data->kbd_led_max_brightness = device_descriptor.kbd_led_max_brightness; -+ data->lightbar_max_brightness = device_descriptor.lightbar_max_brightness; - - /* - * Some devices might need to perform some device-specific initialization steps -@@ -1905,6 +2359,10 @@ static int uniwill_probe(struct platform_device *pdev) - if (ret < 0) - return ret; - -+ ret = uniwill_kbd_led_init(data); -+ if (ret < 0) -+ return ret; -+ - ret = uniwill_hwmon_init(data); - if (ret < 0) - return ret; -@@ -1976,6 +2434,43 @@ static int uniwill_suspend_battery(struct uniwill_data *data) - return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl); - } - -+static int uniwill_suspend_kbd_led(struct uniwill_data *data) -+{ -+ unsigned int regval; -+ int ret; -+ -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return 0; -+ -+ ret = regmap_read(data->regmap, EC_ADDR_KBD_STATUS, ®val); -+ if (ret < 0) -+ return ret; -+ -+ /* -+ * Save the current keyboard backlight settings in order to restore them -+ * during resume. We cannot use the regmap code for that since this register -+ * needs to be declared as volatile because the brightness can be changed -+ * by the EC. -+ */ -+ data->last_kbd_status = regval; -+ FIELD_MODIFY(KBD_BRIGHTNESS_MASK, ®val, 0); -+ regval |= KBD_APPLY | KBD_POWER_OFF; -+ -+ return regmap_write(data->regmap, EC_ADDR_KBD_STATUS, regval); -+} -+ -+static int uniwill_suspend_usb_powershare(struct uniwill_data *data) -+{ -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_POWERSHARE)) -+ return 0; -+ -+ /* -+ * EC_ADDR_TRIGGER is marked as volatile, so we have to restore it -+ * ourselves. -+ */ -+ return uniwill_read_usb_powershare_high(data, &data->last_usb_powershare_high_state); -+} -+ - static int uniwill_suspend_nvidia_ctgp(struct uniwill_data *data) - { - if (!uniwill_device_supports(data, UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)) -@@ -2006,6 +2501,14 @@ static int uniwill_suspend(struct device *dev) - if (ret < 0) - return ret; - -+ ret = uniwill_suspend_kbd_led(data); -+ if (ret < 0) -+ return ret; -+ -+ ret = uniwill_suspend_usb_powershare(data); -+ if (ret < 0) -+ return ret; -+ - ret = uniwill_suspend_nvidia_ctgp(data); - if (ret < 0) - return ret; -@@ -2052,6 +2555,31 @@ static int uniwill_resume_battery(struct uniwill_data *data) - return 0; - } - -+static int uniwill_resume_kbd_led(struct uniwill_data *data) -+{ -+ int ret; -+ -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_KEYBOARD_BACKLIGHT)) -+ return 0; -+ -+ ret = regmap_write(data->regmap, EC_ADDR_KBD_STATUS, data->last_kbd_status | KBD_APPLY); -+ if (ret < 0) -+ return ret; -+ -+ if (data->kbd_led_single_color) -+ return 0; -+ -+ return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, RGB_APPLY_COLOR, RGB_APPLY_COLOR); -+} -+ -+static int uniwill_resume_usb_powershare(struct uniwill_data *data) -+{ -+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_POWERSHARE)) -+ return 0; -+ -+ return uniwill_write_usb_powershare_high(data, data->last_usb_powershare_high_state); -+} -+ - static int uniwill_resume_nvidia_ctgp(struct uniwill_data *data) - { - if (!uniwill_device_supports(data, UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)) -@@ -2096,6 +2624,14 @@ static int uniwill_resume(struct device *dev) - if (ret < 0) - return ret; - -+ ret = uniwill_resume_kbd_led(data); -+ if (ret < 0) -+ return ret; -+ -+ ret = uniwill_resume_usb_powershare(data); -+ if (ret < 0) -+ return ret; -+ - ret = uniwill_resume_nvidia_ctgp(data); - if (ret < 0) - return ret; -@@ -2126,13 +2662,30 @@ static struct platform_driver uniwill_driver = { - .shutdown = uniwill_shutdown, - }; - -+static struct uniwill_device_descriptor machenike_l16p_descriptor __initdata = { -+ .features = UNIWILL_FEATURE_FN_LOCK | -+ UNIWILL_FEATURE_SUPER_KEY | -+ UNIWILL_FEATURE_CPU_TEMP | -+ UNIWILL_FEATURE_GPU_TEMP | -+ UNIWILL_FEATURE_PRIMARY_FAN | -+ UNIWILL_FEATURE_SECONDARY_FAN | -+ UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL | -+ UNIWILL_FEATURE_KEYBOARD_BACKLIGHT | -+ UNIWILL_FEATURE_AC_AUTO_BOOT | -+ UNIWILL_FEATURE_USB_POWERSHARE, -+ .kbd_led_single_color = false, -+ .kbd_led_max_brightness = 4, -+}; -+ - static struct uniwill_device_descriptor lapqc71a_lapqc71b_descriptor __initdata = { - .features = UNIWILL_FEATURE_SUPER_KEY | -+ UNIWILL_FEATURE_LIGHTBAR | - UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT | - UNIWILL_FEATURE_CPU_TEMP | - UNIWILL_FEATURE_GPU_TEMP | - UNIWILL_FEATURE_PRIMARY_FAN | - UNIWILL_FEATURE_SECONDARY_FAN, -+ .lightbar_max_brightness = 36, - }; - - static struct uniwill_device_descriptor lapac71h_descriptor __initdata = { -@@ -2156,6 +2709,7 @@ static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = { - UNIWILL_FEATURE_GPU_TEMP | - UNIWILL_FEATURE_PRIMARY_FAN | - UNIWILL_FEATURE_SECONDARY_FAN, -+ .lightbar_max_brightness = 200, - }; - - /* -@@ -2198,15 +2752,6 @@ static struct uniwill_device_descriptor tux_featureset_2_nvidia_descriptor __ini - UNIWILL_FEATURE_USB_C_POWER_PRIORITY, - }; - --static struct uniwill_device_descriptor tux_featureset_3_descriptor __initdata = { -- .features = UNIWILL_FEATURE_FN_LOCK | -- UNIWILL_FEATURE_SUPER_KEY | -- UNIWILL_FEATURE_BATTERY_CHARGE_MODES | -- UNIWILL_FEATURE_CPU_TEMP | -- UNIWILL_FEATURE_PRIMARY_FAN | -- UNIWILL_FEATURE_SECONDARY_FAN, --}; -- - static struct uniwill_device_descriptor tux_featureset_3_nvidia_descriptor __initdata = { - .features = UNIWILL_FEATURE_FN_LOCK | - UNIWILL_FEATURE_SUPER_KEY | -@@ -2218,6 +2763,30 @@ static struct uniwill_device_descriptor tux_featureset_3_nvidia_descriptor __ini - UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL, - }; - -+static struct uniwill_device_descriptor tux_featureset_4_descriptor __initdata = { -+ .features = UNIWILL_FEATURE_FN_LOCK | -+ UNIWILL_FEATURE_SUPER_KEY | -+ UNIWILL_FEATURE_BATTERY_CHARGE_MODES | -+ UNIWILL_FEATURE_CPU_TEMP | -+ UNIWILL_FEATURE_PRIMARY_FAN | -+ UNIWILL_FEATURE_SECONDARY_FAN | -+ UNIWILL_FEATURE_AC_AUTO_BOOT | -+ UNIWILL_FEATURE_USB_POWERSHARE, -+}; -+ -+static struct uniwill_device_descriptor tux_featureset_4_nvidia_descriptor __initdata = { -+ .features = UNIWILL_FEATURE_FN_LOCK | -+ UNIWILL_FEATURE_SUPER_KEY | -+ UNIWILL_FEATURE_BATTERY_CHARGE_MODES | -+ UNIWILL_FEATURE_CPU_TEMP | -+ UNIWILL_FEATURE_GPU_TEMP | -+ UNIWILL_FEATURE_PRIMARY_FAN | -+ UNIWILL_FEATURE_SECONDARY_FAN | -+ UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL | -+ UNIWILL_FEATURE_AC_AUTO_BOOT | -+ UNIWILL_FEATURE_USB_POWERSHARE, -+}; -+ - static int phxtxx1_probe(struct uniwill_data *data) - { - unsigned int value; -@@ -2277,7 +2846,37 @@ static struct uniwill_device_descriptor pf5pu1g_descriptor __initdata = { - UNIWILL_FEATURE_PRIMARY_FAN, - }; - -+static struct uniwill_device_descriptor x4sp4nal_descriptor __initdata = { -+ .features = UNIWILL_FEATURE_FN_LOCK | -+ UNIWILL_FEATURE_SUPER_KEY | -+ UNIWILL_FEATURE_BATTERY_CHARGE_MODES | -+ UNIWILL_FEATURE_CPU_TEMP | -+ UNIWILL_FEATURE_PRIMARY_FAN | -+ UNIWILL_FEATURE_SECONDARY_FAN | -+ UNIWILL_FEATURE_KEYBOARD_BACKLIGHT | -+ UNIWILL_FEATURE_AC_AUTO_BOOT | -+ UNIWILL_FEATURE_USB_POWERSHARE, -+ .kbd_led_single_color = true, -+ .kbd_led_max_brightness = 2, -+}; -+ - static const struct dmi_system_id uniwill_dmi_table[] __initconst = { -+ { -+ .ident = "AiStone X4SP4NAL", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "AiStone"), -+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "X4SP4NAL"), -+ }, -+ .driver_data = &x4sp4nal_descriptor, -+ }, -+ { -+ .ident = "MACHENIKE L16 Pro", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "MACHENIKE"), -+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "L16P"), -+ }, -+ .driver_data = &machenike_l16p_descriptor, -+ }, - { - .ident = "XMG FUSION 15 (L19)", - .matches = { -@@ -2310,6 +2909,13 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - }, - .driver_data = &lapqc71a_lapqc71b_descriptor, - }, -+ { -+ .ident = "Avell A60 MUV", -+ .matches = { -+ DMI_MATCH(DMI_PRODUCT_NAME, "A60 MUV"), -+ }, -+ .driver_data = &lapqc71a_lapqc71b_descriptor, -+ }, - { - .ident = "Intel NUC x15", - .matches = { -@@ -2388,7 +2994,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"), - }, -- .driver_data = &tux_featureset_3_descriptor, -+ .driver_data = &tux_featureset_4_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9", -@@ -2396,7 +3002,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"), - }, -- .driver_data = &tux_featureset_3_descriptor, -+ .driver_data = &tux_featureset_4_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD", -@@ -2404,7 +3010,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"), - }, -- .driver_data = &tux_featureset_3_descriptor, -+ .driver_data = &tux_featureset_4_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD", -@@ -2412,7 +3018,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"), - }, -- .driver_data = &tux_featureset_3_descriptor, -+ .driver_data = &tux_featureset_4_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel", -@@ -2420,7 +3026,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"), - }, -- .driver_data = &tux_featureset_3_descriptor, -+ .driver_data = &tux_featureset_4_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Max 15 Gen10 AMD", -@@ -2428,7 +3034,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD", -@@ -2436,7 +3042,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6HP45xU"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Max 16 Gen10 AMD", -@@ -2444,7 +3050,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Max 15 Gen10 Intel", -@@ -2452,7 +3058,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X5AR45xS"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO InfinityBook Max 16 Gen10 Intel", -@@ -2460,7 +3066,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR55xU"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Polaris 15 Gen1 AMD", -@@ -2620,7 +3226,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6", -@@ -2628,7 +3234,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6", -@@ -2636,7 +3242,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6", -@@ -2644,7 +3250,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6", -@@ -2652,7 +3258,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Stellaris 16 Gen7 AMD", -@@ -2660,7 +3266,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Stellaris 16 Gen7 Intel", -@@ -2668,7 +3274,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Stellaris 16 Gen7 Intel", -@@ -2676,7 +3282,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { - DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"), - }, -- .driver_data = &tux_featureset_3_nvidia_descriptor, -+ .driver_data = &tux_featureset_4_nvidia_descriptor, - }, - { - .ident = "TUXEDO Book BA15 Gen10 AMD", -@@ -2745,6 +3351,12 @@ static int __init uniwill_init(void) - if (force) { - /* Assume that the device supports all features except the charge limit */ - device_descriptor.features = UINT_MAX & ~UNIWILL_FEATURE_BATTERY_CHARGE_LIMIT; -+ /* Some models only have a (white) single color keyboard backlight */ -+ device_descriptor.kbd_led_single_color = false; -+ /* Some models only support 3 brightness levels */ -+ device_descriptor.kbd_led_max_brightness = 4; -+ /* Some models only support 36 brightness levels per color component */ -+ device_descriptor.lightbar_max_brightness = 200; - pr_warn("Enabling potentially unsupported features\n"); - } - -diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h ---- a/drivers/platform/x86/uniwill/uniwill-wmi.h -+++ b/drivers/platform/x86/uniwill/uniwill-wmi.h -@@ -113,6 +113,8 @@ - - #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0 - -+#define UNIWILL_OSD_SCREEN_STATE_CHANGED 0xCC -+ - #define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF - - #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0 -diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c ---- a/drivers/platform/x86/xo15-ebook.c -+++ b/drivers/platform/x86/xo15-ebook.c -@@ -19,13 +19,10 @@ - - #define MODULE_NAME "xo15-ebook" - --#define XO15_EBOOK_CLASS MODULE_NAME - #define XO15_EBOOK_TYPE_UNKNOWN 0x00 - #define XO15_EBOOK_NOTIFY_STATUS 0x80 - --#define XO15_EBOOK_SUBCLASS "ebook" - #define XO15_EBOOK_HID "XO15EBK" --#define XO15_EBOOK_DEVICE_NAME "EBook Switch" - - MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver"); - MODULE_LICENSE("GPL"); -@@ -105,12 +102,9 @@ static int ebook_switch_probe(struct platform_device *pdev) - if (!id) - return dev_err_probe(dev, -ENODEV, "Unsupported hid\n"); - -- strscpy(acpi_device_name(device), XO15_EBOOK_DEVICE_NAME); -- strscpy(acpi_device_class(device), XO15_EBOOK_CLASS "/" XO15_EBOOK_SUBCLASS); -- - snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id); - -- input->name = acpi_device_name(device); -+ input->name = "EBook Switch"; - input->phys = button->phys; - input->id.bustype = BUS_HOST; - -diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c ---- a/drivers/power/supply/surface_battery.c -+++ b/drivers/power/supply/surface_battery.c -@@ -852,9 +852,14 @@ static const struct spwr_psy_properties spwr_psy_props_bat2_sb3 = { - }; - - static const struct ssam_device_id surface_battery_match[] = { -- { SSAM_SDEV(BAT, SAM, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1 }, -- { SSAM_SDEV(BAT, KIP, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 }, -- { }, -+ { -+ SSAM_SDEV(BAT, SAM, 0x01, 0x00), -+ .driver_data = (unsigned long)&spwr_psy_props_bat1, -+ }, { -+ SSAM_SDEV(BAT, KIP, 0x01, 0x00), -+ .driver_data = (unsigned long)&spwr_psy_props_bat2_sb3, -+ }, -+ { } - }; - MODULE_DEVICE_TABLE(ssam, surface_battery_match); - -diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c ---- a/drivers/power/supply/surface_charger.c -+++ b/drivers/power/supply/surface_charger.c -@@ -260,8 +260,11 @@ static const struct spwr_psy_properties spwr_psy_props_adp1 = { - }; - - static const struct ssam_device_id surface_ac_match[] = { -- { SSAM_SDEV(BAT, SAM, 0x01, 0x01), (unsigned long)&spwr_psy_props_adp1 }, -- { }, -+ { -+ SSAM_SDEV(BAT, SAM, 0x01, 0x01), -+ .driver_data = (unsigned long)&spwr_psy_props_adp1, -+ }, -+ { } - }; - MODULE_DEVICE_TABLE(ssam, surface_ac_match); - -diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h ---- a/include/linux/amd-pmf-io.h -+++ b/include/linux/amd-pmf-io.h -@@ -52,15 +52,6 @@ struct amd_sfh_info { - u32 laptop_placement; - }; - --enum laptop_placement { -- LP_UNKNOWN = 0, -- ON_TABLE, -- ON_LAP_MOTION, -- IN_BAG, -- OUT_OF_BAG, -- LP_UNDEFINED, --}; -- - /** - * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver - * @npuclk_freq: NPU clock frequency [MHz] -@@ -69,6 +60,7 @@ enum laptop_placement { - * @mpnpuclk_freq: MPNPU [MHz] - * @npu_reads: NPU read bandwidth [MB/sec] - * @npu_writes: NPU write bandwidth [MB/sec] -+ * @npu_temp: NPU temperature [C] - */ - struct amd_pmf_npu_metrics { - u16 npuclk_freq; -@@ -77,6 +69,7 @@ struct amd_pmf_npu_metrics { - u16 mpnpuclk_freq; - u16 npu_reads; - u16 npu_writes; -+ u16 npu_temp; - }; - - int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op); -diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h ---- a/include/linux/platform_data/x86/asus-wmi.h -+++ b/include/linux/platform_data/x86/asus-wmi.h -@@ -203,6 +203,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); - int asus_hid_register_listener(struct asus_hid_listener *cdev); - void asus_hid_unregister_listener(struct asus_hid_listener *cdev); - int asus_hid_event(enum asus_hid_event event); -+bool asus_wmi_custom_fan_curve_is_enabled(void); - #else - static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) - { -@@ -234,6 +235,10 @@ static inline int asus_hid_event(enum asus_hid_event event) - { - return -ENODEV; - } -+static inline bool asus_wmi_custom_fan_curve_is_enabled(void) -+{ -+ return false; -+} - #endif - - #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ -diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h -new file mode 100644 ---- /dev/null -+++ b/include/uapi/linux/amd-pmf.h -@@ -0,0 +1,204 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ -+/* -+ * AMD Platform Management Framework (PMF) UAPI Header -+ * -+ * Copyright (c) 2026, Advanced Micro Devices, Inc. -+ * All Rights Reserved. -+ * -+ * This file defines the user-space API for interacting with the AMD PMF -+ * driver. It provides ioctl interfaces to query platform-specific metrics -+ * such as power source, slider position, platform type, laptop placement, -+ * and various BIOS input/output parameters. -+ */ -+ -+#ifndef _UAPI_LINUX_AMD_PMF_H -+#define _UAPI_LINUX_AMD_PMF_H -+ -+#include -+#include -+#include -+ -+/** -+ * AMD_PMF_IOC_MAGIC - Magic number for AMD PMF ioctl commands -+ * -+ * This magic number uniquely identifies AMD PMF ioctl operations. -+ */ -+#define AMD_PMF_IOC_MAGIC 'p' -+ -+/** -+ * IOCTL_AMD_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data -+ * -+ * This ioctl command is used to populate the amd_pmf_info structure -+ * with the requested PMF metrics information. -+ */ -+#define IOCTL_AMD_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, __u64) -+ -+#define AMD_PMF_BIOS_PARAMS_MAX 10 -+ -+/* AMD PMF feature flags - bitmask indicating supported features */ -+#define AMD_PMF_FEAT_AUTO_MODE BIT(0) -+#define AMD_PMF_FEAT_STATIC_POWER_SLIDER BIT(1) -+#define AMD_PMF_FEAT_POLICY_BUILDER BIT(2) -+#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC BIT(3) -+#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC BIT(4) -+ -+/** -+ * enum amd_pmf_laptop_placement - Describes the physical placement of the laptop -+ * @AMD_PMF_LP_UNKNOWN: Placement cannot be determined -+ * @AMD_PMF_ON_TABLE: Laptop is placed on a stable surface like a table or desk -+ * @AMD_PMF_ON_LAP_MOTION: Laptop is on a lap with detected motion -+ * @AMD_PMF_IN_BAG: Laptop is detected to be inside a bag or case -+ * @AMD_PMF_OUT_OF_BAG: Laptop has been removed from bag or case -+ * @AMD_PMF_LP_UNDEFINED: Placement state is undefined -+ * -+ * This enumeration represents the physical placement state of the laptop -+ * as detected by platform sensors. Used for adaptive power management -+ * and thermal policies. -+ */ -+enum amd_pmf_laptop_placement { -+ AMD_PMF_LP_UNKNOWN, -+ AMD_PMF_ON_TABLE, -+ AMD_PMF_ON_LAP_MOTION, -+ AMD_PMF_IN_BAG, -+ AMD_PMF_OUT_OF_BAG, -+ AMD_PMF_LP_UNDEFINED, -+}; -+ -+/** -+ * enum amd_pmf_ta_slider - Trusted Application power slider positions -+ * @AMD_PMF_TA_BEST_BATTERY: Maximum battery savings, minimal performance -+ * @AMD_PMF_TA_BETTER_BATTERY: Balanced towards battery life -+ * @AMD_PMF_TA_BETTER_PERFORMANCE: Balanced towards performance -+ * @AMD_PMF_TA_BEST_PERFORMANCE: Maximum performance, higher power consumption -+ * @AMD_PMF_TA_MAX: Sentinel value indicating maximum enum value -+ * -+ * This enumeration defines the power slider positions used by the -+ * AMD PMF Trusted Application for dynamic power management decisions. -+ * These correspond to the Windows power slider UI positions. -+ */ -+enum amd_pmf_ta_slider { -+ AMD_PMF_TA_BEST_BATTERY, -+ AMD_PMF_TA_BETTER_BATTERY, -+ AMD_PMF_TA_BETTER_PERFORMANCE, -+ AMD_PMF_TA_BEST_PERFORMANCE, -+ AMD_PMF_TA_MAX, -+}; -+ -+/** -+ * enum amd_pmf_platform_type - Describes the physical form factor orientation -+ * @AMD_PMF_PTYPE_UNKNOWN: Platform type cannot be determined -+ * @AMD_PMF_LID_CLOSE: Laptop lid is closed -+ * @AMD_PMF_CLAMSHELL: Traditional laptop mode with keyboard and screen -+ * @AMD_PMF_FLAT: Device is lying flat on a surface -+ * @AMD_PMF_TENT: Device is in tent mode (keyboard folded back, standing) -+ * @AMD_PMF_STAND: Device is propped up in stand orientation -+ * @AMD_PMF_TABLET: Device is in tablet mode with keyboard hidden -+ * @AMD_PMF_BOOK: Device is in book reading orientation -+ * @AMD_PMF_PRESENTATION: Device is in presentation mode -+ * @AMD_PMF_PULL_FWD: Screen is pulled forward towards user -+ * @AMD_PMF_PTYPE_INVALID: Invalid platform type marker -+ * -+ * This enumeration describes the current physical orientation or form -+ * factor of convertible/2-in-1 devices. Used for optimizing power and -+ * thermal management based on device posture. -+ */ -+enum amd_pmf_platform_type { -+ AMD_PMF_PTYPE_UNKNOWN, -+ AMD_PMF_LID_CLOSE, -+ AMD_PMF_CLAMSHELL, -+ AMD_PMF_FLAT, -+ AMD_PMF_TENT, -+ AMD_PMF_STAND, -+ AMD_PMF_TABLET, -+ AMD_PMF_BOOK, -+ AMD_PMF_PRESENTATION, -+ AMD_PMF_PULL_FWD, -+ AMD_PMF_PTYPE_INVALID = 0xf, -+}; -+ -+static inline const char *amd_pmf_get_platform_type(unsigned int platform_type) -+{ -+ switch (platform_type) { -+ case AMD_PMF_CLAMSHELL: -+ return "CLAMSHELL"; -+ case AMD_PMF_LID_CLOSE: -+ return "LID_CLOSE"; -+ case AMD_PMF_FLAT: -+ return "FLAT"; -+ case AMD_PMF_TENT: -+ return "TENT"; -+ case AMD_PMF_STAND: -+ return "STAND"; -+ case AMD_PMF_TABLET: -+ return "TABLET"; -+ case AMD_PMF_BOOK: -+ return "BOOK"; -+ case AMD_PMF_PRESENTATION: -+ return "PRESENTATION"; -+ case AMD_PMF_PULL_FWD: -+ return "PULL_FWD"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+static inline const char *amd_pmf_get_laptop_placement(unsigned int device_state) -+{ -+ switch (device_state) { -+ case AMD_PMF_ON_TABLE: -+ return "ON_TABLE"; -+ case AMD_PMF_ON_LAP_MOTION: -+ return "ON_LAP_MOTION"; -+ case AMD_PMF_IN_BAG: -+ return "IN_BAG"; -+ case AMD_PMF_OUT_OF_BAG: -+ return "OUT_OF_BAG"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+static inline const char *amd_pmf_get_slider_position(unsigned int state) -+{ -+ switch (state) { -+ case AMD_PMF_TA_BEST_PERFORMANCE: -+ return "PERFORMANCE"; -+ case AMD_PMF_TA_BETTER_PERFORMANCE: -+ return "BALANCED"; -+ case AMD_PMF_TA_BEST_BATTERY: -+ return "POWER_SAVER"; -+ case AMD_PMF_TA_BETTER_BATTERY: -+ return "BALANCED_BATTERY"; -+ default: -+ return "Unknown TA Slider State"; -+ } -+} -+ -+struct amd_pmf_info { -+ __u64 size; -+ -+ /* Feature info */ -+ __u32 features_supported; -+ -+ /* Power and state info */ -+ __u32 platform_type; -+ __u32 power_source; -+ __u32 laptop_placement; -+ __u32 lid_state; -+ __u32 user_presence; -+ __u32 slider_position; -+ -+ /* Thermal and power metrics */ -+ __s32 skin_temp; -+ __u32 gfx_busy; -+ __s32 ambient_light; -+ __u32 avg_c0_residency; -+ __u32 max_c0_residency; -+ __u32 socket_power; -+ -+ /* BIOS parameters */ -+ __u32 bios_input[AMD_PMF_BIOS_PARAMS_MAX]; -+ __u32 bios_output[AMD_PMF_BIOS_PARAMS_MAX]; -+}; -+ -+#endif /* _UAPI_LINUX_AMD_PMF_H */ diff --git a/kernel/0800-platform-updates.patch.sig b/kernel/0800-platform-updates.patch.sig deleted file mode 100644 index 58371ed..0000000 Binary files a/kernel/0800-platform-updates.patch.sig and /dev/null differ diff --git a/kernel/0801-amd-pmf-util-unbind-use-after-free.patch b/kernel/0801-amd-pmf-util-unbind-use-after-free.patch deleted file mode 100644 index 029ebd2..0000000 --- a/kernel/0801-amd-pmf-util-unbind-use-after-free.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c -index 1111111..2222222 100644 ---- a/drivers/platform/x86/amd/pmf/util.c -+++ b/drivers/platform/x86/amd/pmf/util.c -@@ -79,9 +79,9 @@ static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info * - - static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { -- struct amd_pmf_dev *pdev = filp->private_data; - void __user *argp = (void __user *)arg; - struct amd_pmf_info info = {}; -+ struct amd_pmf_dev *pdev; - size_t copy_size; - __u64 user_size; - int ret; -@@ -94,6 +94,10 @@ static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long - return -EFAULT; - - guard(mutex)(&pmf_util_lock); -+ pdev = pmf_dev_handle; -+ if (!pdev) -+ return -ENODEV; -+ - ret = amd_pmf_populate_data(pdev, &info); - if (ret) - return ret; -@@ -115,7 +119,6 @@ static int amd_pmf_open(struct inode *inode, struct file *filp) - if (!pmf_dev_handle) - return -ENODEV; - -- filp->private_data = pmf_dev_handle; - return 0; - } - diff --git a/kernel/0801-amd-pmf-util-unbind-use-after-free.patch.sig b/kernel/0801-amd-pmf-util-unbind-use-after-free.patch.sig deleted file mode 100644 index 91d6150..0000000 Binary files a/kernel/0801-amd-pmf-util-unbind-use-after-free.patch.sig and /dev/null differ diff --git a/kernel/0802-platform-fixes.patch b/kernel/0802-platform-fixes.patch deleted file mode 100644 index b7d82cc..0000000 --- a/kernel/0802-platform-fixes.patch +++ /dev/null @@ -1,240 +0,0 @@ -diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c ---- a/drivers/platform/x86/amd/pmf/spc.c -+++ b/drivers/platform/x86/amd/pmf/spc.c -@@ -17,7 +17,6 @@ - #include - #include "pmf.h" - --#ifdef CONFIG_AMD_PMF_DEBUG - u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index) - { - switch (index) { -@@ -31,6 +30,7 @@ u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index) - } - EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs); - -+#ifdef CONFIG_AMD_PMF_DEBUG - void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) - { - int i; -diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c ---- a/drivers/platform/x86/x86-android-tablets/core.c -+++ b/drivers/platform/x86/x86-android-tablets/core.c -@@ -156,7 +156,6 @@ static struct platform_device **pdevs; - static struct serdev_device **serdevs; - static const struct software_node **gpio_button_swnodes; - static const struct software_node **swnode_group; --static const struct software_node **gpiochip_node_group; - static void (*exit_handler)(void); - - static __init struct i2c_adapter * -@@ -362,6 +361,15 @@ static const struct software_node *cherryview_gpiochip_node_group[] = { - NULL - }; - -+const struct software_node crystalcove_gpiochip_node = { -+ .name = "INT33FD:00", -+}; -+ -+static const struct software_node *crystalcove_gpiochip_node_group[] = { -+ &crystalcove_gpiochip_node, -+ NULL -+}; -+ - static void gpio_secondary_unset(void *data) - { - struct device *dev = data; -@@ -377,27 +385,28 @@ static void gpio_secondary_unregister_node_group(void *data) - software_node_unregister_node_group(nodes); - } - --static int gpio_secondary_fwnode_init(struct device *parent) -+static int gpio_secondary_fwnode_init(struct device *parent, -+ const struct software_node * const *node_group) - { - const struct software_node *const *swnode; - struct fwnode_handle *fwnode; - struct device *phys_dev; - int ret; - -- if (!gpiochip_node_group) -+ if (!node_group) - return 0; - -- ret = software_node_register_node_group(gpiochip_node_group); -+ ret = software_node_register_node_group(node_group); - if (ret) - return ret; - - ret = devm_add_action_or_reset(parent, - gpio_secondary_unregister_node_group, -- gpiochip_node_group); -+ (void *)node_group); - if (ret) - return ret; - -- for (swnode = gpiochip_node_group; *swnode; swnode++) { -+ for (swnode = node_group; *swnode; swnode++) { - struct device *dev __free(put_device) = - acpi_bus_find_device_by_name((*swnode)->name); - if (!dev) -@@ -460,6 +469,7 @@ static void x86_android_tablet_remove(struct platform_device *pdev) - - static __init int x86_android_tablet_probe(struct platform_device *pdev) - { -+ const struct software_node * const *gpiochip_node_group; - const struct x86_dev_info *dev_info; - const struct dmi_system_id *id; - int i, ret = 0; -@@ -491,12 +501,20 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) - break; - } - -- ret = gpio_secondary_fwnode_init(&pdev->dev); -+ ret = gpio_secondary_fwnode_init(&pdev->dev, gpiochip_node_group); - if (ret) { - x86_android_tablet_remove(pdev); - return ret; - } - -+ if (dev_info->has_crystalcove) { -+ ret = gpio_secondary_fwnode_init(&pdev->dev, crystalcove_gpiochip_node_group); -+ if (ret) { -+ x86_android_tablet_remove(pdev); -+ return ret; -+ } -+ } -+ - ret = software_node_register_node_group(dev_info->swnode_group); - if (ret) { - x86_android_tablet_remove(pdev); -diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c ---- a/drivers/platform/x86/x86-android-tablets/lenovo.c -+++ b/drivers/platform/x86/x86-android-tablets/lenovo.c -@@ -61,13 +61,6 @@ static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata = { - .initial_brightness = 128, - }; - --static const struct software_node arizona_gpiochip_node = { -- .name = "arizona", --}; -- --static const struct software_node crystalcove_gpiochip_node = { -- .name = "gpio_crystalcove", --}; - - /* Lenovo Yoga Book X90F / X90L's Android factory image has everything hardcoded */ - -@@ -416,15 +409,17 @@ static const struct platform_device_info lenovo_yoga_tab2_830_1050_pdevs[] __ini - - #define LENOVO_YOGA_TAB2_830_1050_CODEC_NAME "spi-10WM5102:00" - -+static const struct software_node lenovo_yoga_tab2_830_1050_wm5102; -+ - static const struct property_entry lenovo_yoga_tab2_830_1050_wm1502_props[] = { - PROPERTY_ENTRY_GPIO("reset-gpios", - &crystalcove_gpiochip_node, 3, GPIO_ACTIVE_HIGH), - PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios", - &baytrail_gpiochip_nodes[1], 23, GPIO_ACTIVE_HIGH), - PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios", -- &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH), -+ &lenovo_yoga_tab2_830_1050_wm5102, 2, GPIO_ACTIVE_HIGH), - PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", -- &arizona_gpiochip_node, 4, GPIO_ACTIVE_LOW), -+ &lenovo_yoga_tab2_830_1050_wm5102, 4, GPIO_ACTIVE_LOW), - { } - }; - -@@ -432,14 +427,6 @@ static const struct software_node lenovo_yoga_tab2_830_1050_wm5102 = { - .properties = lenovo_yoga_tab2_830_1050_wm1502_props, - }; - --static const struct software_node *lenovo_yoga_tab2_830_1050_swnodes[] = { -- &crystalcove_gpiochip_node, -- &arizona_gpiochip_node, -- &lenovo_yoga_tab2_830_1050_wm5102, -- &generic_lipo_hv_4v35_battery_node, -- NULL --}; -- - static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev); - static void lenovo_yoga_tab2_830_1050_exit(void); - -@@ -455,8 +442,9 @@ const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { - .pdev_info = lenovo_yoga_tab2_830_1050_pdevs, - .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), - .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, -- .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, -+ .swnode_group = generic_lipo_hv_4v35_battery_swnodes, - .modules = lenovo_yoga_tab2_modules, -+ .has_crystalcove = true, - .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, - .init = lenovo_yoga_tab2_830_1050_init, - .exit = lenovo_yoga_tab2_830_1050_exit, -@@ -800,8 +788,9 @@ const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { - .pdev_info = lenovo_yoga_tab2_1380_pdevs, - .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), - .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, -- .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, -+ .swnode_group = generic_lipo_hv_4v35_battery_swnodes, - .modules = lenovo_yoga_tab2_modules, -+ .has_crystalcove = true, - .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, - .init = lenovo_yoga_tab2_1380_init, - .exit = lenovo_yoga_tab2_830_1050_exit, -@@ -985,13 +974,15 @@ static struct arizona_pdata lenovo_yt3_wm5102_pdata = { - }, - }; - -+static const struct software_node lenovo_yt3_wm5102; -+ - static const struct property_entry lenovo_yt3_wm1502_props[] = { - PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios", - &cherryview_gpiochip_nodes[0], 75, GPIO_ACTIVE_HIGH), - PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios", - &cherryview_gpiochip_nodes[0], 81, GPIO_ACTIVE_HIGH), - PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 82, GPIO_ACTIVE_HIGH), -- PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH), -+ PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", &lenovo_yt3_wm5102, 2, GPIO_ACTIVE_HIGH), - { } - }; - -@@ -1000,11 +991,6 @@ static const struct software_node lenovo_yt3_wm5102 = { - .name = "wm5102", - }; - --static const struct software_node *lenovo_yt3_swnodes[] = { -- &arizona_gpiochip_node, -- &lenovo_yt3_wm5102, -- NULL --}; - - static const struct x86_spi_dev_info lenovo_yt3_spi_devs[] __initconst = { - { -@@ -1072,7 +1058,6 @@ const struct x86_dev_info lenovo_yt3_info __initconst = { - .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients), - .spi_dev_info = lenovo_yt3_spi_devs, - .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs), -- .swnode_group = lenovo_yt3_swnodes, - .modules = lenovo_yt3_modules, - .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, - .init = lenovo_yt3_init, -diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h ---- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h -+++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h -@@ -96,6 +96,7 @@ struct x86_dev_info { - int (*init)(struct device *dev); - void (*exit)(void); - bool use_pci; -+ bool has_crystalcove; - enum x86_gpiochip_type gpiochip_type; - }; - -@@ -107,6 +108,7 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data); - /* Software nodes representing GPIO chips used by various tablets */ - extern const struct software_node baytrail_gpiochip_nodes[]; - extern const struct software_node cherryview_gpiochip_nodes[]; -+extern const struct software_node crystalcove_gpiochip_node; - - /* - * Extern declarations of x86_dev_info structs so there can be a single diff --git a/kernel/0802-platform-fixes.patch.sig b/kernel/0802-platform-fixes.patch.sig deleted file mode 100644 index 3e19e33..0000000 Binary files a/kernel/0802-platform-fixes.patch.sig and /dev/null differ diff --git a/kernel/0803-acpi-battery-hook-api-acpi-prefix.patch b/kernel/0803-acpi-battery-hook-api-acpi-prefix.patch deleted file mode 100644 index c3246f0..0000000 --- a/kernel/0803-acpi-battery-hook-api-acpi-prefix.patch +++ /dev/null @@ -1,412 +0,0 @@ -diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c ---- a/drivers/acpi/battery.c -+++ b/drivers/acpi/battery.c -@@ -736,7 +736,7 @@ static LIST_HEAD(acpi_battery_list); - static LIST_HEAD(battery_hook_list); - static DEFINE_MUTEX(hook_mutex); - --static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) -+static void acpi_battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) - { - struct acpi_battery *battery; - -@@ -753,7 +753,7 @@ static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) - pr_info("hook unregistered: %s\n", hook->name); - } - --void battery_hook_unregister(struct acpi_battery_hook *hook) -+void acpi_battery_hook_unregister(struct acpi_battery_hook *hook) - { - mutex_lock(&hook_mutex); - /* -@@ -762,13 +762,13 @@ void battery_hook_unregister(struct acpi_battery_hook *hook) - * adding a new battery. - */ - if (!list_empty(&hook->list)) -- battery_hook_unregister_unlocked(hook); -+ acpi_battery_hook_unregister_unlocked(hook); - - mutex_unlock(&hook_mutex); - } --EXPORT_SYMBOL_GPL(battery_hook_unregister); -+EXPORT_SYMBOL_GPL(acpi_battery_hook_unregister); - --void battery_hook_register(struct acpi_battery_hook *hook) -+void acpi_battery_hook_register(struct acpi_battery_hook *hook) - { - struct acpi_battery *battery; - -@@ -789,7 +789,7 @@ void battery_hook_register(struct acpi_battery_hook *hook) - * hooks. - */ - pr_err("hook failed to load: %s", hook->name); -- battery_hook_unregister_unlocked(hook); -+ acpi_battery_hook_unregister_unlocked(hook); - goto end; - } - -@@ -799,22 +799,22 @@ void battery_hook_register(struct acpi_battery_hook *hook) - end: - mutex_unlock(&hook_mutex); - } --EXPORT_SYMBOL_GPL(battery_hook_register); -+EXPORT_SYMBOL_GPL(acpi_battery_hook_register); - --static void devm_battery_hook_unregister(void *data) -+static void devm_acpi_battery_hook_unregister(void *data) - { - struct acpi_battery_hook *hook = data; - -- battery_hook_unregister(hook); -+ acpi_battery_hook_unregister(hook); - } - --int devm_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook) -+int devm_acpi_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook) - { -- battery_hook_register(hook); -+ acpi_battery_hook_register(hook); - -- return devm_add_action_or_reset(dev, devm_battery_hook_unregister, hook); -+ return devm_add_action_or_reset(dev, devm_acpi_battery_hook_unregister, hook); - } --EXPORT_SYMBOL_GPL(devm_battery_hook_register); -+EXPORT_SYMBOL_GPL(devm_acpi_battery_hook_register); - - /* - * This function gets called right after the battery sysfs -@@ -843,7 +843,7 @@ static void battery_hook_add_battery(struct acpi_battery *battery) - */ - pr_err("error in hook, unloading: %s", - hook_node->name); -- battery_hook_unregister_unlocked(hook_node); -+ acpi_battery_hook_unregister_unlocked(hook_node); - } - } - mutex_unlock(&hook_mutex); -@@ -876,7 +876,7 @@ static void __exit battery_hook_exit(void) - * need to remove the hooks. - */ - list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) { -- battery_hook_unregister(hook); -+ acpi_battery_hook_unregister(hook); - } - mutex_destroy(&hook_mutex); - } -diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c ---- a/drivers/platform/x86/asus-wmi.c -+++ b/drivers/platform/x86/asus-wmi.c -@@ -1681,14 +1681,14 @@ static void asus_wmi_battery_init(struct asus_wmi *asus) - asus->battery_rsoc_available = false; - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_RSOC)) { - asus->battery_rsoc_available = true; -- battery_hook_register(&battery_hook); -+ acpi_battery_hook_register(&battery_hook); - } - } - - static void asus_wmi_battery_exit(struct asus_wmi *asus) - { - if (asus->battery_rsoc_available) -- battery_hook_unregister(&battery_hook); -+ acpi_battery_hook_unregister(&battery_hook); - } - - /* LEDs ***********************************************************************/ -diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c ---- a/drivers/platform/x86/ayaneo-ec.c -+++ b/drivers/platform/x86/ayaneo-ec.c -@@ -493,7 +493,7 @@ static int ayaneo_ec_probe(struct platform_device *pdev) - data->battery_hook.add_battery = ayaneo_add_battery; - data->battery_hook.remove_battery = ayaneo_remove_battery; - data->battery_hook.name = "Ayaneo Battery"; -- ret = devm_battery_hook_register(&pdev->dev, &data->battery_hook); -+ ret = devm_acpi_battery_hook_register(&pdev->dev, &data->battery_hook); - if (ret) - return ret; - } -diff --git a/drivers/platform/x86/dell/dell-laptop.c b/drivers/platform/x86/dell/dell-laptop.c ---- a/drivers/platform/x86/dell/dell-laptop.c -+++ b/drivers/platform/x86/dell/dell-laptop.c -@@ -2446,13 +2446,13 @@ static void __init dell_battery_init(struct device *dev) - battery_supported_modes = battery_get_supported_modes(); - - if (battery_supported_modes != 0) -- battery_hook_register(&dell_battery_hook); -+ acpi_battery_hook_register(&dell_battery_hook); - } - - static void dell_battery_exit(void) - { - if (battery_supported_modes != 0) -- battery_hook_unregister(&dell_battery_hook); -+ acpi_battery_hook_unregister(&dell_battery_hook); - } - - static int __init dell_init(void) -diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c ---- a/drivers/platform/x86/dell/dell-wmi-ddv.c -+++ b/drivers/platform/x86/dell/dell-wmi-ddv.c -@@ -972,7 +972,7 @@ static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) - data->eppid_attr.attr.mode = 0444; - data->eppid_attr.show = eppid_show; - -- return devm_battery_hook_register(&data->wdev->dev, &data->hook); -+ return devm_acpi_battery_hook_register(&data->wdev->dev, &data->hook); - } - - static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method) -diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c ---- a/drivers/platform/x86/fujitsu-laptop.c -+++ b/drivers/platform/x86/fujitsu-laptop.c -@@ -267,7 +267,7 @@ static int fujitsu_battery_charge_control_add(struct device *dev) - return -ENODEV; - - priv->charge_control_supported = true; -- battery_hook_register(&battery_hook); -+ acpi_battery_hook_register(&battery_hook); - - return 0; - } -@@ -277,7 +277,7 @@ static void fujitsu_battery_charge_control_remove(struct device *dev) - struct fujitsu_laptop *priv = dev_get_drvdata(dev); - - if (priv->charge_control_supported) -- battery_hook_unregister(&battery_hook); -+ acpi_battery_hook_unregister(&battery_hook); - } - - /* Hardware access for LCD brightness control */ -diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c ---- a/drivers/platform/x86/huawei-wmi.c -+++ b/drivers/platform/x86/huawei-wmi.c -@@ -512,7 +512,7 @@ static void huawei_wmi_battery_setup(struct device *dev) - return; - } - -- battery_hook_register(&huawei_wmi_battery_hook); -+ acpi_battery_hook_register(&huawei_wmi_battery_hook); - device_create_file(dev, &dev_attr_charge_control_thresholds); - } - -@@ -521,7 +521,7 @@ static void huawei_wmi_battery_exit(struct device *dev) - struct huawei_wmi *huawei = dev_get_drvdata(dev); - - if (huawei->battery_available) { -- battery_hook_unregister(&huawei_wmi_battery_hook); -+ acpi_battery_hook_unregister(&huawei_wmi_battery_hook); - device_remove_file(dev, &dev_attr_charge_control_thresholds); - } - } -diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c ---- a/drivers/platform/x86/lenovo/ideapad-laptop.c -+++ b/drivers/platform/x86/lenovo/ideapad-laptop.c -@@ -2197,8 +2197,8 @@ static int ideapad_check_features(struct ideapad_private *priv) - priv->battery_hook.remove_battery = ideapad_battery_remove; - priv->battery_hook.name = "Ideapad Battery Extension"; - -- err = devm_battery_hook_register(&priv->platform_device->dev, -- &priv->battery_hook); -+ err = devm_acpi_battery_hook_register(&priv->platform_device->dev, -+ &priv->battery_hook); - if (err) - return err; - } -diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c ---- a/drivers/platform/x86/lenovo/thinkpad_acpi.c -+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c -@@ -10021,13 +10021,13 @@ static int __init tpacpi_battery_init(struct ibm_init_struct *ibm) - battery_quirk_table, - ARRAY_SIZE(battery_quirk_table)); - -- battery_hook_register(&battery_hook); -+ acpi_battery_hook_register(&battery_hook); - return 0; - } - - static void tpacpi_battery_exit(void) - { -- battery_hook_unregister(&battery_hook); -+ acpi_battery_hook_unregister(&battery_hook); - } - - static struct ibm_struct battery_driver_data = { -diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c ---- a/drivers/platform/x86/lenovo/wmi-other.c -+++ b/drivers/platform/x86/lenovo/wmi-other.c -@@ -946,7 +946,7 @@ static void lwmi_om_psy_ext_init(struct lwmi_om_priv *priv) - priv->battery_hook.name = "Lenovo WMI Other Battery Extension"; - priv->bh_registered = true; - -- battery_hook_register(&priv->battery_hook); -+ acpi_battery_hook_register(&priv->battery_hook); - } - - /** -@@ -960,7 +960,7 @@ static void lwmi_om_psy_remove(struct lwmi_om_priv *priv) - if (!priv->bh_registered) - return; - -- battery_hook_unregister(&priv->battery_hook); -+ acpi_battery_hook_unregister(&priv->battery_hook); - priv->bh_registered = false; - } - -diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c ---- a/drivers/platform/x86/lg-laptop.c -+++ b/drivers/platform/x86/lg-laptop.c -@@ -1053,7 +1053,7 @@ static int acpi_probe(struct platform_device *pdev) - if (ret) - goto out_platform_device; - -- battery_hook_register(&battery_hook); -+ acpi_battery_hook_register(&battery_hook); - - return 0; - -@@ -1068,7 +1068,7 @@ static void acpi_remove(struct platform_device *pdev) - { - sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group); - -- battery_hook_unregister(&battery_hook); -+ acpi_battery_hook_unregister(&battery_hook); - platform_device_unregister(pf_device); - pf_device = NULL; - platform_driver_unregister(&pf_driver); -diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c ---- a/drivers/platform/x86/msi-ec.c -+++ b/drivers/platform/x86/msi-ec.c -@@ -1428,13 +1428,13 @@ static int __init msi_ec_init(void) - if (result < 0) - return result; - -- battery_hook_register(&battery_hook); -+ acpi_battery_hook_register(&battery_hook); - return 0; - } - - static void __exit msi_ec_exit(void) - { -- battery_hook_unregister(&battery_hook); -+ acpi_battery_hook_unregister(&battery_hook); - } - - MODULE_LICENSE("GPL"); -diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c ---- a/drivers/platform/x86/oxpec.c -+++ b/drivers/platform/x86/oxpec.c -@@ -956,7 +956,7 @@ static int oxp_platform_probe(struct platform_device *pdev) - return PTR_ERR(hwdev); - - if (oxp_psy_ext_supported()) { -- ret = devm_battery_hook_register(dev, &battery_hook); -+ ret = devm_acpi_battery_hook_register(dev, &battery_hook); - if (ret) - return ret; - } -diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c ---- a/drivers/platform/x86/samsung-galaxybook.c -+++ b/drivers/platform/x86/samsung-galaxybook.c -@@ -549,7 +549,8 @@ static int galaxybook_battery_threshold_init(struct samsung_galaxybook *galaxybo - galaxybook->battery_hook.remove_battery = galaxybook_battery_remove; - galaxybook->battery_hook.name = "Samsung Galaxy Book Battery Extension"; - -- return devm_battery_hook_register(&galaxybook->platform->dev, &galaxybook->battery_hook); -+ return devm_acpi_battery_hook_register(&galaxybook->platform->dev, -+ &galaxybook->battery_hook); - } - - /* -diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c ---- a/drivers/platform/x86/samsung-laptop.c -+++ b/drivers/platform/x86/samsung-laptop.c -@@ -1142,8 +1142,8 @@ static int __init samsung_battery_hook_init(struct samsung_laptop *samsung) - samsung->battery_hook.add_battery = samsung_battery_add; - samsung->battery_hook.remove_battery = samsung_battery_remove; - samsung->battery_hook.name = "Samsung Battery Extension"; -- retval = devm_battery_hook_register(&samsung->platform_device->dev, -- &samsung->battery_hook); -+ retval = devm_acpi_battery_hook_register(&samsung->platform_device->dev, -+ &samsung->battery_hook); - } - - return retval; -diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c ---- a/drivers/platform/x86/system76_acpi.c -+++ b/drivers/platform/x86/system76_acpi.c -@@ -288,12 +288,12 @@ static struct acpi_battery_hook system76_battery_hook = { - - static void system76_battery_init(void) - { -- battery_hook_register(&system76_battery_hook); -+ acpi_battery_hook_register(&system76_battery_hook); - } - - static void system76_battery_exit(void) - { -- battery_hook_unregister(&system76_battery_hook); -+ acpi_battery_hook_unregister(&system76_battery_hook); - } - - // Get the airplane mode LED brightness -diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c ---- a/drivers/platform/x86/toshiba_acpi.c -+++ b/drivers/platform/x86/toshiba_acpi.c -@@ -3301,7 +3301,7 @@ static void toshiba_acpi_remove(struct platform_device *pdev) - } - - if (dev->battery_charge_mode_supported) -- battery_hook_unregister(&battery_hook); -+ acpi_battery_hook_unregister(&battery_hook); - - if (toshiba_acpi) - toshiba_acpi = NULL; -@@ -3566,7 +3566,7 @@ static int toshiba_acpi_probe(struct platform_device *pdev) - * set, this must be done after toshiba_acpi is assigned. - */ - if (dev->battery_charge_mode_supported) -- battery_hook_register(&battery_hook); -+ acpi_battery_hook_register(&battery_hook); - - return 0; - -diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c ---- a/drivers/platform/x86/uniwill/uniwill-acpi.c -+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c -@@ -2165,7 +2165,7 @@ static int uniwill_battery_init(struct uniwill_data *data) - data->hook.add_battery = uniwill_add_battery; - data->hook.remove_battery = uniwill_remove_battery; - -- return devm_battery_hook_register(data->dev, &data->hook); -+ return devm_acpi_battery_hook_register(data->dev, &data->hook); - } - - static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action, void *dummy) -diff --git a/drivers/power/supply/cros_charge-control.c b/drivers/power/supply/cros_charge-control.c ---- a/drivers/power/supply/cros_charge-control.c -+++ b/drivers/power/supply/cros_charge-control.c -@@ -315,7 +315,7 @@ static int cros_chctl_probe(struct platform_device *pdev) - if (ret < 0) - return ret; - -- return devm_battery_hook_register(dev, &priv->battery_hook); -+ return devm_acpi_battery_hook_register(dev, &priv->battery_hook); - } - - static const struct platform_device_id cros_chctl_id[] = { -diff --git a/include/acpi/battery.h b/include/acpi/battery.h ---- a/include/acpi/battery.h -+++ b/include/acpi/battery.h -@@ -18,8 +18,9 @@ struct acpi_battery_hook { - struct list_head list; - }; - --void battery_hook_register(struct acpi_battery_hook *hook); --void battery_hook_unregister(struct acpi_battery_hook *hook); --int devm_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook); -+void acpi_battery_hook_register(struct acpi_battery_hook *hook); -+void acpi_battery_hook_unregister(struct acpi_battery_hook *hook); -+int devm_acpi_battery_hook_register(struct device *dev, -+ struct acpi_battery_hook *hook); - - #endif diff --git a/kernel/0803-acpi-battery-hook-api-acpi-prefix.patch.sig b/kernel/0803-acpi-battery-hook-api-acpi-prefix.patch.sig deleted file mode 100644 index 5a6282a..0000000 Binary files a/kernel/0803-acpi-battery-hook-api-acpi-prefix.patch.sig and /dev/null differ diff --git a/kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch b/kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch deleted file mode 100644 index a50095e..0000000 --- a/kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch +++ /dev/null @@ -1,472 +0,0 @@ -diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig ---- a/drivers/acpi/Kconfig -+++ b/drivers/acpi/Kconfig -@@ -171,8 +171,12 @@ config ACPI_AC - To compile this driver as a module, choose M here: - the module will be called ac. - -+config ACPI_BATTERY_HOOKS -+ tristate -+ - config ACPI_BATTERY - tristate "Battery" -+ select ACPI_BATTERY_HOOKS - select POWER_SUPPLY - default y - help -@@ -445,6 +449,7 @@ config ACPI_HOTPLUG_IOAPIC - config ACPI_SBS - tristate "Smart Battery System" - depends on X86 && ACPI_EC -+ select ACPI_BATTERY_HOOKS - select POWER_SUPPLY - help - This driver supports the Smart Battery System, another -diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile ---- a/drivers/acpi/Makefile -+++ b/drivers/acpi/Makefile -@@ -97,6 +97,7 @@ obj-$(CONFIG_ACPI_NHLT) += nhlt.o - obj-$(CONFIG_ACPI_NUMA) += numa/ - obj-$(CONFIG_ACPI) += acpi_memhotplug.o - obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o -+obj-$(CONFIG_ACPI_BATTERY_HOOKS) += battery_hooks.o - obj-$(CONFIG_ACPI_BATTERY) += battery.o - obj-$(CONFIG_ACPI_SBS) += sbshc.o - obj-$(CONFIG_ACPI_SBS) += sbs.o -diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c ---- a/drivers/acpi/battery.c -+++ b/drivers/acpi/battery.c -@@ -48,6 +48,7 @@ MODULE_AUTHOR("Paul Diefenbaugh"); - MODULE_AUTHOR("Alexey Starikovskiy "); - MODULE_DESCRIPTION("ACPI Battery Driver"); - MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("ACPI_BATTERY_HOOKS"); - - static int battery_bix_broken_package; - static int battery_notification_delay_ms; -@@ -97,7 +98,7 @@ struct acpi_battery { - struct acpi_device *device; - struct device *phys_dev; - struct notifier_block pm_nb; -- struct list_head list; -+ struct acpi_battery_hooks_list_entry hooks_list_entry; - unsigned long flags; - - struct mutex property_lock; /* Protects properties below. */ -@@ -723,164 +724,6 @@ static struct attribute *acpi_battery_attrs[] = { - }; - ATTRIBUTE_GROUPS(acpi_battery); - --/* -- * The Battery Hooking API -- * -- * This API is used inside other drivers that need to expose -- * platform-specific behaviour within the generic driver in a -- * generic way. -- * -- */ -- --static LIST_HEAD(acpi_battery_list); --static LIST_HEAD(battery_hook_list); --static DEFINE_MUTEX(hook_mutex); -- --static void acpi_battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) --{ -- struct acpi_battery *battery; -- -- /* -- * In order to remove a hook, we first need to -- * de-register all the batteries that are registered. -- */ -- list_for_each_entry(battery, &acpi_battery_list, list) { -- if (!hook->remove_battery(battery->bat, hook)) -- power_supply_changed(battery->bat); -- } -- list_del_init(&hook->list); -- -- pr_info("hook unregistered: %s\n", hook->name); --} -- --void acpi_battery_hook_unregister(struct acpi_battery_hook *hook) --{ -- mutex_lock(&hook_mutex); -- /* -- * Ignore already unregistered battery hooks. This might happen -- * if a battery hook was previously unloaded due to an error when -- * adding a new battery. -- */ -- if (!list_empty(&hook->list)) -- acpi_battery_hook_unregister_unlocked(hook); -- -- mutex_unlock(&hook_mutex); --} --EXPORT_SYMBOL_GPL(acpi_battery_hook_unregister); -- --void acpi_battery_hook_register(struct acpi_battery_hook *hook) --{ -- struct acpi_battery *battery; -- -- mutex_lock(&hook_mutex); -- list_add(&hook->list, &battery_hook_list); -- /* -- * Now that the driver is registered, we need -- * to notify the hook that a battery is available -- * for each battery, so that the driver may add -- * its attributes. -- */ -- list_for_each_entry(battery, &acpi_battery_list, list) { -- if (hook->add_battery(battery->bat, hook)) { -- /* -- * If a add-battery returns non-zero, -- * the registration of the hook has failed, -- * and we will not add it to the list of loaded -- * hooks. -- */ -- pr_err("hook failed to load: %s", hook->name); -- acpi_battery_hook_unregister_unlocked(hook); -- goto end; -- } -- -- power_supply_changed(battery->bat); -- } -- pr_info("new hook: %s\n", hook->name); --end: -- mutex_unlock(&hook_mutex); --} --EXPORT_SYMBOL_GPL(acpi_battery_hook_register); -- --static void devm_acpi_battery_hook_unregister(void *data) --{ -- struct acpi_battery_hook *hook = data; -- -- acpi_battery_hook_unregister(hook); --} -- --int devm_acpi_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook) --{ -- acpi_battery_hook_register(hook); -- -- return devm_add_action_or_reset(dev, devm_acpi_battery_hook_unregister, hook); --} --EXPORT_SYMBOL_GPL(devm_acpi_battery_hook_register); -- --/* -- * This function gets called right after the battery sysfs -- * attributes have been added, so that the drivers that -- * define custom sysfs attributes can add their own. -- */ --static void battery_hook_add_battery(struct acpi_battery *battery) --{ -- struct acpi_battery_hook *hook_node, *tmp; -- -- mutex_lock(&hook_mutex); -- INIT_LIST_HEAD(&battery->list); -- list_add(&battery->list, &acpi_battery_list); -- /* -- * Since we added a new battery to the list, we need to -- * iterate over the hooks and call add_battery for each -- * hook that was registered. This usually happens -- * when a battery gets hotplugged or initialized -- * during the battery module initialization. -- */ -- list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) { -- if (hook_node->add_battery(battery->bat, hook_node)) { -- /* -- * The notification of the hook has failed, to -- * prevent further errors we will unload the hook. -- */ -- pr_err("error in hook, unloading: %s", -- hook_node->name); -- acpi_battery_hook_unregister_unlocked(hook_node); -- } -- } -- mutex_unlock(&hook_mutex); --} -- --static void battery_hook_remove_battery(struct acpi_battery *battery) --{ -- struct acpi_battery_hook *hook; -- -- mutex_lock(&hook_mutex); -- /* -- * Before removing the hook, we need to remove all -- * custom attributes from the battery. -- */ -- list_for_each_entry(hook, &battery_hook_list, list) { -- hook->remove_battery(battery->bat, hook); -- } -- /* Then, just remove the battery from the list */ -- list_del(&battery->list); -- mutex_unlock(&hook_mutex); --} -- --static void __exit battery_hook_exit(void) --{ -- struct acpi_battery_hook *hook; -- struct acpi_battery_hook *ptr; -- /* -- * At this point, the acpi_bus_unregister_driver() -- * has called remove for all batteries. We just -- * need to remove the hooks. -- */ -- list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) { -- acpi_battery_hook_unregister(hook); -- } -- mutex_destroy(&hook_mutex); --} -- - static int sysfs_add_battery(struct acpi_battery *battery) - { - struct power_supply_config psy_cfg = { -@@ -936,7 +779,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) - battery->bat = NULL; - return result; - } -- battery_hook_add_battery(battery); -+ acpi_battery_add_hooks(&battery->hooks_list_entry, battery->bat); - return 0; - } - -@@ -945,7 +788,7 @@ static void sysfs_remove_battery(struct acpi_battery *battery) - if (!battery->bat) - return; - -- battery_hook_remove_battery(battery); -+ acpi_battery_remove_hooks(&battery->hooks_list_entry); - power_supply_unregister(battery->bat); - battery->bat = NULL; - } -@@ -1391,7 +1234,6 @@ static int __init acpi_battery_init(void) - static void __exit acpi_battery_exit(void) - { - platform_driver_unregister(&acpi_battery_driver); -- battery_hook_exit(); - } - - module_init(acpi_battery_init); -diff --git a/drivers/acpi/battery_hooks.c b/drivers/acpi/battery_hooks.c -new file mode 100644 ---- /dev/null -+++ b/drivers/acpi/battery_hooks.c -@@ -0,0 +1,159 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * ACPI Battery Hooks -+ * -+ * Provides helpers for registering and unregistering battery hooks for -+ * drivers that use platform-specific extensions to ACPI-enumerated -+ * batteries (both ACPI Control Method batteries and Smart Battery System -+ * batteries). -+ */ -+ -+#define pr_fmt(fmt) "ACPI: battery: " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static LIST_HEAD(acpi_battery_list); -+static LIST_HEAD(battery_hook_list); -+static DEFINE_MUTEX(hook_mutex); -+ -+static void acpi_battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) -+{ -+ struct acpi_battery_hooks_list_entry *entry; -+ -+ /* -+ * In order to remove a hook, we first need to -+ * de-register all the batteries that are registered. -+ */ -+ list_for_each_entry(entry, &acpi_battery_list, list_entry) { -+ if (!hook->remove_battery(entry->battery, hook)) -+ power_supply_changed(entry->battery); -+ } -+ list_del_init(&hook->list); -+ -+ pr_info("hook unregistered: %s\n", hook->name); -+} -+ -+void acpi_battery_hook_unregister(struct acpi_battery_hook *hook) -+{ -+ guard(mutex)(&hook_mutex); -+ -+ /* -+ * Ignore already unregistered battery hooks. This might happen -+ * if a battery hook was previously unloaded due to an error when -+ * adding a new battery. -+ */ -+ if (!list_empty(&hook->list)) -+ acpi_battery_hook_unregister_unlocked(hook); -+} -+EXPORT_SYMBOL_GPL(acpi_battery_hook_unregister); -+ -+void acpi_battery_hook_register(struct acpi_battery_hook *hook) -+{ -+ struct acpi_battery_hooks_list_entry *entry; -+ -+ guard(mutex)(&hook_mutex); -+ -+ list_add(&hook->list, &battery_hook_list); -+ /* -+ * Now that the driver is registered, we need -+ * to notify the hook that a battery is available -+ * for each battery, so that the driver may add -+ * its attributes. -+ */ -+ list_for_each_entry(entry, &acpi_battery_list, list_entry) { -+ if (hook->add_battery(entry->battery, hook)) { -+ /* -+ * If a add-battery returns non-zero, -+ * the registration of the hook has failed, -+ * and we will not add it to the list of loaded -+ * hooks. -+ */ -+ pr_err("hook failed to load: %s\n", hook->name); -+ acpi_battery_hook_unregister_unlocked(hook); -+ return; -+ } -+ -+ power_supply_changed(entry->battery); -+ } -+ pr_info("new hook: %s\n", hook->name); -+} -+EXPORT_SYMBOL_GPL(acpi_battery_hook_register); -+ -+static void devm_acpi_battery_hook_unregister(void *data) -+{ -+ struct acpi_battery_hook *hook = data; -+ -+ acpi_battery_hook_unregister(hook); -+} -+ -+int devm_acpi_battery_hook_register(struct device *dev, -+ struct acpi_battery_hook *hook) -+{ -+ acpi_battery_hook_register(hook); -+ -+ return devm_add_action_or_reset(dev, devm_acpi_battery_hook_unregister, hook); -+} -+EXPORT_SYMBOL_GPL(devm_acpi_battery_hook_register); -+ -+/* -+ * This function gets called right after the battery sysfs -+ * attributes have been added, so that the drivers that -+ * define custom sysfs attributes can add their own. -+ */ -+void acpi_battery_add_hooks(struct acpi_battery_hooks_list_entry *entry, -+ struct power_supply *battery) -+{ -+ struct acpi_battery_hook *hook_node, *tmp; -+ -+ entry->battery = battery; -+ -+ guard(mutex)(&hook_mutex); -+ -+ list_add(&entry->list_entry, &acpi_battery_list); -+ /* -+ * Since we added a new battery to the list, we need to -+ * iterate over the hooks and call add_battery for each -+ * hook that was registered. This usually happens -+ * when a battery gets hotplugged or initialized -+ * during the battery module initialization. -+ */ -+ list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) { -+ if (hook_node->add_battery(entry->battery, hook_node)) { -+ /* -+ * The notification of the hook has failed, to -+ * prevent further errors we will unload the hook. -+ */ -+ pr_err("error in hook, unloading: %s\n", hook_node->name); -+ acpi_battery_hook_unregister_unlocked(hook_node); -+ } -+ } -+} -+EXPORT_SYMBOL_NS_GPL(acpi_battery_add_hooks, "ACPI_BATTERY_HOOKS"); -+ -+void acpi_battery_remove_hooks(struct acpi_battery_hooks_list_entry *entry) -+{ -+ struct acpi_battery_hook *hook; -+ -+ guard(mutex)(&hook_mutex); -+ /* -+ * Before removing the hook, we need to remove all -+ * custom attributes from the battery. -+ */ -+ list_for_each_entry(hook, &battery_hook_list, list) -+ hook->remove_battery(entry->battery, hook); -+ -+ /* Then, just remove the battery from the list */ -+ list_del(&entry->list_entry); -+ entry->battery = NULL; -+} -+EXPORT_SYMBOL_NS_GPL(acpi_battery_remove_hooks, "ACPI_BATTERY_HOOKS"); -+ -+MODULE_DESCRIPTION("ACPI battery hooks"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c ---- a/drivers/acpi/sbs.c -+++ b/drivers/acpi/sbs.c -@@ -36,6 +36,7 @@ - MODULE_AUTHOR("Alexey Starikovskiy "); - MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); - MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("ACPI_BATTERY_HOOKS"); - - static unsigned int cache_time = 1000; - module_param(cache_time, uint, 0644); -@@ -54,6 +55,7 @@ struct acpi_battery { - struct power_supply *bat; - struct power_supply_desc bat_desc; - struct acpi_sbs *sbs; -+ struct acpi_battery_hooks_list_entry hooks_list_entry; - unsigned long update_time; - char name[8]; - char manufacturer_name[ACPI_SBS_BLOCK_MAX]; -@@ -555,6 +557,8 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) - goto end; - } - -+ acpi_battery_add_hooks(&battery->hooks_list_entry, battery->bat); -+ - end: - pr_info("%s [%s]: Battery Slot [%s] (battery %s)\n", - ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), -@@ -566,8 +570,10 @@ static void acpi_battery_remove(struct acpi_sbs *sbs, int id) - { - struct acpi_battery *battery = &sbs->battery[id]; - -- if (battery->bat) -+ if (battery->bat) { -+ acpi_battery_remove_hooks(&battery->hooks_list_entry); - power_supply_unregister(battery->bat); -+ } - } - - static int acpi_charger_add(struct acpi_sbs *sbs) -diff --git a/include/acpi/battery.h b/include/acpi/battery.h ---- a/include/acpi/battery.h -+++ b/include/acpi/battery.h -@@ -18,9 +18,18 @@ struct acpi_battery_hook { - struct list_head list; - }; - -+struct acpi_battery_hooks_list_entry { -+ struct list_head list_entry; -+ struct power_supply *battery; -+}; -+ - void acpi_battery_hook_register(struct acpi_battery_hook *hook); - void acpi_battery_hook_unregister(struct acpi_battery_hook *hook); - int devm_acpi_battery_hook_register(struct device *dev, - struct acpi_battery_hook *hook); - -+void acpi_battery_add_hooks(struct acpi_battery_hooks_list_entry *entry, -+ struct power_supply *battery); -+void acpi_battery_remove_hooks(struct acpi_battery_hooks_list_entry *entry); -+ - #endif diff --git a/kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch.sig b/kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch.sig deleted file mode 100644 index 7b62083..0000000 Binary files a/kernel/0804-acpi-battery-unified-hooks-acpi-sbs.patch.sig and /dev/null differ diff --git a/kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch b/kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch deleted file mode 100644 index 9b45c66..0000000 --- a/kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch +++ /dev/null @@ -1,209 +0,0 @@ -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -380,6 +380,7 @@ config SENSORS_FAM15H_POWER - config SENSORS_APPLESMC - tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" - depends on INPUT && X86 -+ depends on POWER_SUPPLY || POWER_SUPPLY=n - select NEW_LEDS - select LEDS_CLASS - help -diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c ---- a/drivers/hwmon/applesmc.c -+++ b/drivers/hwmon/applesmc.c -@@ -33,6 +33,8 @@ - #include - #include - #include -+#include -+#include - #include - - /* data port used by Apple SMC */ -@@ -76,6 +78,20 @@ - - #define TEMP_SENSOR_TYPE "sp78" - -+/* -+ * BCLM caps charging at a percentage. BFCL only sets when the charging LED -+ * switches from orange to green. -+ */ -+#define BATTERY_CHARGE_LIMIT_KEY "BCLM" /* r/w ui8 */ -+#define BATTERY_CHARGE_LIMIT_LED_KEY "BFCL" /* r/w ui8 */ -+ -+/* -+ * Points kept between BCLM and BFCL so the LED turns green before charging -+ * stops. Measured on a MacBookAir6,2, where a margin of 1 only just ties; -+ * 3 leaves headroom for other models. -+ */ -+#define APPLESMC_BATTERY_CHARGE_LIMIT_LED_MARGIN 3 -+ - /* List of keys used to read/write fan speeds */ - static const char *const fan_speed_fmt[] = { - "F%dAc", /* actual speed */ -@@ -131,6 +147,8 @@ static struct applesmc_registers { - int num_light_sensors; /* number of light sensors */ - bool has_accelerometer; /* has motion sensor */ - bool has_key_backlight; /* has keyboard backlight */ -+ bool has_battery_charge_limit; /* has BCLM battery charge limit */ -+ bool has_battery_charge_limit_led; /* has BFCL MagSafe LED charge limit */ - bool init_complete; /* true when fully initialized */ - struct applesmc_entry *cache; /* cached key entries */ - const char **index; /* temperature key index */ -@@ -633,6 +651,12 @@ static int applesmc_init_smcreg_try(void) - if (ret) - return ret; - ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight); -+ if (ret) -+ return ret; -+ ret = applesmc_has_key(BATTERY_CHARGE_LIMIT_KEY, &s->has_battery_charge_limit); -+ if (ret) -+ return ret; -+ ret = applesmc_has_key(BATTERY_CHARGE_LIMIT_LED_KEY, &s->has_battery_charge_limit_led); - if (ret) - return ret; - -@@ -724,6 +748,120 @@ static struct platform_driver applesmc_driver = { - }, - }; - -+static DEFINE_MUTEX(applesmc_bat_lock); -+ -+static int applesmc_bat_get_property(struct power_supply *psy, -+ const struct power_supply_ext *ext, -+ void *data, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ u8 limit; -+ int ret; -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: -+ scoped_guard(mutex, &applesmc_bat_lock) -+ ret = applesmc_read_key(BATTERY_CHARGE_LIMIT_KEY, &limit, 1); -+ if (ret) -+ return ret; -+ val->intval = limit; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int applesmc_bat_set_property(struct power_supply *psy, -+ const struct power_supply_ext *ext, -+ void *data, -+ enum power_supply_property psp, -+ const union power_supply_propval *val) -+{ -+ u8 limit, led_limit, readback; -+ int ret; -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: -+ /* 20 is known to work and 10 is not accepted; the floor is unknown. */ -+ if (val->intval < 20 || val->intval > 100) -+ return -EINVAL; -+ -+ limit = val->intval; -+ /* At 100% charging is never cut short, so no margin is needed. */ -+ led_limit = limit < 100 ? -+ limit - APPLESMC_BATTERY_CHARGE_LIMIT_LED_MARGIN : limit; -+ -+ scoped_guard(mutex, &applesmc_bat_lock) { -+ ret = applesmc_write_key(BATTERY_CHARGE_LIMIT_KEY, &limit, 1); -+ if (ret) -+ return ret; -+ -+ /* -+ * The SMC silently ignores values it does not accept and -+ * still reports success, so read the limit back. -+ */ -+ ret = applesmc_read_key(BATTERY_CHARGE_LIMIT_KEY, &readback, 1); -+ if (ret) -+ return ret; -+ if (readback != limit) -+ return -EINVAL; -+ -+ if (smcreg.has_battery_charge_limit_led) { -+ ret = applesmc_write_key(BATTERY_CHARGE_LIMIT_LED_KEY, -+ &led_limit, 1); -+ /* BCLM is already applied, so this is not an error. */ -+ if (ret) -+ pr_warn("failed to update MagSafe LED threshold (BFCL): %d\n", -+ ret); -+ } -+ } -+ -+ power_supply_changed(psy); -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int applesmc_bat_property_is_writeable(struct power_supply *psy, -+ const struct power_supply_ext *ext, -+ void *data, -+ enum power_supply_property psp) -+{ -+ return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD; -+} -+ -+static const enum power_supply_property applesmc_bat_props[] = { -+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, -+}; -+ -+static const struct power_supply_ext applesmc_bat_ext = { -+ .name = "applesmc-charge-control", -+ .properties = applesmc_bat_props, -+ .num_properties = ARRAY_SIZE(applesmc_bat_props), -+ .get_property = applesmc_bat_get_property, -+ .set_property = applesmc_bat_set_property, -+ .property_is_writeable = applesmc_bat_property_is_writeable, -+}; -+ -+static int applesmc_bat_add(struct power_supply *battery, struct acpi_battery_hook *hook) -+{ -+ return power_supply_register_extension(battery, &applesmc_bat_ext, &pdev->dev, NULL); -+} -+ -+static int applesmc_bat_remove(struct power_supply *battery, struct acpi_battery_hook *hook) -+{ -+ power_supply_unregister_extension(battery, &applesmc_bat_ext); -+ return 0; -+} -+ -+static struct acpi_battery_hook applesmc_bat_hook = { -+ .name = "Apple SMC Battery Charge Control", -+ .add_battery = applesmc_bat_add, -+ .remove_battery = applesmc_bat_remove, -+}; -+ - /* - * applesmc_calibrate - Set our "resting" values. Callers must - * hold applesmc_lock. -@@ -1563,6 +1701,10 @@ static int __init applesmc_init(void) - goto out_light_ledclass; - } - -+ if (smcreg.has_battery_charge_limit && -+ IS_REACHABLE(CONFIG_ACPI_BATTERY_HOOKS)) -+ acpi_battery_hook_register(&applesmc_bat_hook); -+ - return 0; - - out_light_ledclass: -@@ -1589,6 +1731,10 @@ static int __init applesmc_init(void) - - static void __exit applesmc_exit(void) - { -+ if (smcreg.has_battery_charge_limit && -+ IS_REACHABLE(CONFIG_ACPI_BATTERY_HOOKS)) -+ acpi_battery_hook_unregister(&applesmc_bat_hook); -+ - hwmon_device_unregister(hwmon_dev); - applesmc_release_key_backlight(); - applesmc_release_light_sensor(); diff --git a/kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch.sig b/kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch.sig deleted file mode 100644 index 73eabc0..0000000 Binary files a/kernel/0805-hwmon-applesmc-charge-control-end-threshold.patch.sig and /dev/null differ diff --git a/kernel/0850-futex-wait-multiple.patch b/kernel/0850-futex-wait-multiple.patch deleted file mode 100644 index d4ab07f..0000000 --- a/kernel/0850-futex-wait-multiple.patch +++ /dev/null @@ -1,142 +0,0 @@ -diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h ---- a/include/uapi/linux/futex.h -+++ b/include/uapi/linux/futex.h -@@ -22,6 +22,7 @@ - #define FUTEX_WAIT_REQUEUE_PI 11 - #define FUTEX_CMP_REQUEUE_PI 12 - #define FUTEX_LOCK_PI2 13 -+#define FUTEX_WAIT_MULTIPLE 31 - - #define FUTEX_PRIVATE_FLAG 128 - #define FUTEX_CLOCK_REALTIME 256 -@@ -126,6 +127,18 @@ struct futex_waitv { - __u32 __reserved; - }; - -+/** -+ * struct futex_wait_block - Block of futexes to be waited for -+ * @uaddr: User address of the futex -+ * @val: Futex value expected by userspace -+ * @bitset: Bitset for the optional bitmasked wakeup -+ */ -+struct futex_wait_block { -+ __u32 __user *uaddr; -+ __u32 val; -+ __u32 bitset; -+}; -+ - /* - * Support for robust futexes: the kernel cleans up held futexes at - * thread exit time. -diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c ---- a/kernel/futex/syscalls.c -+++ b/kernel/futex/syscalls.c -@@ -169,6 +169,7 @@ static __always_inline bool futex_cmd_has_timeout(u32 cmd) - case FUTEX_LOCK_PI2: - case FUTEX_WAIT_BITSET: - case FUTEX_WAIT_REQUEUE_PI: -+ case FUTEX_WAIT_MULTIPLE: - return true; - } - return false; -@@ -181,13 +182,79 @@ futex_init_timeout(u32 cmd, u32 op, struct timespec64 *ts, ktime_t *t) - return -EINVAL; - - *t = timespec64_to_ktime(*ts); -- if (cmd == FUTEX_WAIT) -+ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE) - *t = ktime_add_safe(ktime_get(), *t); - else if (cmd != FUTEX_LOCK_PI && !(op & FUTEX_CLOCK_REALTIME)) - *t = timens_ktime_to_host(CLOCK_MONOTONIC, *t); - return 0; - } - -+/** -+ * futex_read_wait_block - Read an array of futex_wait_block from userspace -+ * @uaddr: Userspace address of the block -+ * @count: Number of blocks to be read -+ * -+ * This function creates and allocate an array of futex_q (we zero it to -+ * initialize the fields) and then, for each futex_wait_block element from -+ * userspace, fill a futex_q element with proper values. -+ */ -+inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count) -+{ -+ unsigned int i; -+ struct futex_vector *futexv; -+ struct futex_wait_block fwb; -+ struct futex_wait_block __user *entry = -+ (struct futex_wait_block __user *)uaddr; -+ -+ if (!count || count > FUTEX_WAITV_MAX) -+ return ERR_PTR(-EINVAL); -+ -+ futexv = kcalloc(count, sizeof(*futexv), GFP_KERNEL); -+ if (!futexv) -+ return ERR_PTR(-ENOMEM); -+ -+ for (i = 0; i < count; i++) { -+ if (copy_from_user(&fwb, &entry[i], sizeof(fwb))) { -+ kfree(futexv); -+ return ERR_PTR(-EFAULT); -+ } -+ -+ futexv[i].w.flags = FUTEX_32; -+ futexv[i].w.val = fwb.val; -+ futexv[i].w.uaddr = (uintptr_t) (fwb.uaddr); -+ futexv[i].q = futex_q_init; -+ } -+ -+ return futexv; -+} -+ -+int futex_wait_multiple(struct futex_vector *vs, unsigned int count, -+ struct hrtimer_sleeper *to); -+ -+int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count) -+{ -+ int ret; -+ struct futex_vector *vs; -+ struct hrtimer_sleeper *to = NULL, timeout; -+ -+ to = futex_setup_timer(abs_time, &timeout, 0, 0); -+ -+ vs = futex_read_wait_block(uaddr, count); -+ -+ if (IS_ERR(vs)) -+ return PTR_ERR(vs); -+ -+ ret = futex_wait_multiple(vs, count, abs_time ? to : NULL); -+ kfree(vs); -+ -+ if (to) { -+ hrtimer_cancel(&to->timer); -+ destroy_hrtimer_on_stack(&to->timer); -+ } -+ -+ return ret; -+} -+ - SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, - const struct __kernel_timespec __user *, utime, - u32 __user *, uaddr2, u32, val3) -@@ -207,6 +274,9 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, - tp = &t; - } - -+ if (cmd == FUTEX_WAIT_MULTIPLE) -+ return futex_opcode_31(tp, uaddr, val); -+ - return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3); - } - -@@ -521,6 +591,9 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val, - tp = &t; - } - -+ if (cmd == FUTEX_WAIT_MULTIPLE) -+ return futex_opcode_31(tp, uaddr, val); -+ - return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3); - } - #endif /* CONFIG_COMPAT_32BIT_TIME */ diff --git a/kernel/0850-futex-wait-multiple.patch.sig b/kernel/0850-futex-wait-multiple.patch.sig deleted file mode 100644 index b8c1df3..0000000 Binary files a/kernel/0850-futex-wait-multiple.patch.sig and /dev/null differ diff --git a/kernel/0851-futex-wait-multiple-fixes.patch b/kernel/0851-futex-wait-multiple-fixes.patch deleted file mode 100644 index 671934a..0000000 --- a/kernel/0851-futex-wait-multiple-fixes.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c ---- a/kernel/futex/syscalls.c -+++ b/kernel/futex/syscalls.c -@@ -198,7 +198,7 @@ - * initialize the fields) and then, for each futex_wait_block element from - * userspace, fill a futex_q element with proper values. - */ --inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count) -+static inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count) - { - unsigned int i; - struct futex_vector *futexv; -@@ -231,19 +231,18 @@ - int futex_wait_multiple(struct futex_vector *vs, unsigned int count, - struct hrtimer_sleeper *to); - --int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count) -+static int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count) - { - int ret; - struct futex_vector *vs; - struct hrtimer_sleeper *to = NULL, timeout; - -- to = futex_setup_timer(abs_time, &timeout, 0, 0); -- - vs = futex_read_wait_block(uaddr, count); -- - if (IS_ERR(vs)) - return PTR_ERR(vs); - -+ to = futex_setup_timer(abs_time, &timeout, 0, 0); -+ - ret = futex_wait_multiple(vs, count, abs_time ? to : NULL); - kfree(vs); - diff --git a/kernel/0851-futex-wait-multiple-fixes.patch.sig b/kernel/0851-futex-wait-multiple-fixes.patch.sig deleted file mode 100644 index f32092d..0000000 Binary files a/kernel/0851-futex-wait-multiple-fixes.patch.sig and /dev/null differ diff --git a/kernel/0852-futex-wait-multiple-abi-fixes.patch b/kernel/0852-futex-wait-multiple-abi-fixes.patch deleted file mode 100644 index b0d6ba3..0000000 --- a/kernel/0852-futex-wait-multiple-abi-fixes.patch +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h ---- a/include/uapi/linux/futex.h -+++ b/include/uapi/linux/futex.h -@@ -134,7 +134,7 @@ - * @bitset: Bitset for the optional bitmasked wakeup - */ - struct futex_wait_block { -- __u32 __user *uaddr; -+ __aligned_u64 uaddr; - __u32 val; - __u32 bitset; - }; -diff --git a/kernel/futex/syscalls.c b/kernel/futex/syscalls.c ---- a/kernel/futex/syscalls.c -+++ b/kernel/futex/syscalls.c -@@ -198,7 +198,8 @@ - * initialize the fields) and then, for each futex_wait_block element from - * userspace, fill a futex_q element with proper values. - */ --static inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count) -+static inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count, -+ unsigned int flags) - { - unsigned int i; - struct futex_vector *futexv; -@@ -219,10 +220,17 @@ - return ERR_PTR(-EFAULT); - } - -- futexv[i].w.flags = FUTEX_32; -+ if (!fwb.bitset) { -+ kfree(futexv); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ futexv[i].w.flags = flags; - futexv[i].w.val = fwb.val; -- futexv[i].w.uaddr = (uintptr_t) (fwb.uaddr); -+ futexv[i].w.uaddr = fwb.uaddr; - futexv[i].q = futex_q_init; -+ futexv[i].q.bitset = fwb.bitset; -+ futexv[i].q.wake = futex_wake_mark; - } - - return futexv; -@@ -231,17 +239,21 @@ - int futex_wait_multiple(struct futex_vector *vs, unsigned int count, - struct hrtimer_sleeper *to); - --static int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count) -+static int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count, int op) - { - int ret; - struct futex_vector *vs; - struct hrtimer_sleeper *to = NULL, timeout; -+ unsigned int flags = futex_to_flags(op); -+ -+ if (flags & FLAGS_CLOCKRT) -+ return -ENOSYS; - -- vs = futex_read_wait_block(uaddr, count); -+ vs = futex_read_wait_block(uaddr, count, flags); - if (IS_ERR(vs)) - return PTR_ERR(vs); - -- to = futex_setup_timer(abs_time, &timeout, 0, 0); -+ to = futex_setup_timer(abs_time, &timeout, flags, current->timer_slack_ns); - - ret = futex_wait_multiple(vs, count, abs_time ? to : NULL); - kfree(vs); -@@ -274,7 +286,7 @@ - } - - if (cmd == FUTEX_WAIT_MULTIPLE) -- return futex_opcode_31(tp, uaddr, val); -+ return futex_opcode_31(tp, uaddr, val, op); - - return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3); - } -@@ -591,7 +603,7 @@ - } - - if (cmd == FUTEX_WAIT_MULTIPLE) -- return futex_opcode_31(tp, uaddr, val); -+ return futex_opcode_31(tp, uaddr, val, op); - - return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3); - } diff --git a/kernel/0852-futex-wait-multiple-abi-fixes.patch.sig b/kernel/0852-futex-wait-multiple-abi-fixes.patch.sig deleted file mode 100644 index 4a42013..0000000 Binary files a/kernel/0852-futex-wait-multiple-abi-fixes.patch.sig and /dev/null differ diff --git a/kernel/0860-module-add-module-kallsyms-on-each-addr.patch b/kernel/0860-module-add-module-kallsyms-on-each-addr.patch deleted file mode 100644 index ebd6e0d..0000000 --- a/kernel/0860-module-add-module-kallsyms-on-each-addr.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/include/linux/module.h b/include/linux/module.h ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -975,6 +975,10 @@ unsigned long module_kallsyms_lookup_name(const char *name); - - unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name); - -+void module_kallsyms_on_each_addr(struct module *mod, -+ void (*fn)(void *, unsigned long), -+ void *data); -+ - #else /* CONFIG_MODULES && CONFIG_KALLSYMS */ - - static inline int module_kallsyms_on_each_symbol(const char *modname, -@@ -1018,6 +1022,12 @@ static inline unsigned long find_kallsyms_symbol_value(struct module *mod, - return 0; - } - -+static inline void module_kallsyms_on_each_addr(struct module *mod, -+ void (*fn)(void *, unsigned long), -+ void *data) -+{ -+} -+ - #endif /* CONFIG_MODULES && CONFIG_KALLSYMS */ - - /* Define __free(module_put) macro for struct module *. */ -diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c ---- a/kernel/module/kallsyms.c -+++ b/kernel/module/kallsyms.c -@@ -246,6 +246,18 @@ static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned - return kallsyms->strtab + kallsyms->symtab[symnum].st_name; - } - -+/* -+ * Whether find_kallsyms_symbol() may resolve an address to symbol @symnum. -+ * Unnamed symbols are ignored: they're uninformative and inserted at a whim. -+ */ -+static bool is_lookup_symbol(struct mod_kallsyms *kallsyms, unsigned int symnum) -+{ -+ const char *name = kallsyms_symbol_name(kallsyms, symnum); -+ -+ return kallsyms->symtab[symnum].st_shndx != SHN_UNDEF && -+ *name != '\0' && !is_mapping_symbol(name); -+} -+ - /* - * Given a module and address, find the corresponding symbol and return its name - * while providing its size and offset if needed. -@@ -286,15 +298,7 @@ static const char *find_kallsyms_symbol(struct module *mod, - const Elf_Sym *sym = &kallsyms->symtab[i]; - unsigned long thisval = kallsyms_symbol_value(sym); - -- if (sym->st_shndx == SHN_UNDEF) -- continue; -- -- /* -- * We ignore unnamed symbols: they're uninformative -- * and inserted at a whim. -- */ -- if (*kallsyms_symbol_name(kallsyms, i) == '\0' || -- is_mapping_symbol(kallsyms_symbol_name(kallsyms, i))) -+ if (!is_lookup_symbol(kallsyms, i)) - continue; - - if (thisval <= addr && thisval > bestval) { -@@ -458,6 +462,28 @@ unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name) - return __find_kallsyms_symbol_value(mod, name); - } - -+/* -+ * Call @fn with the address of each symbol of @mod that find_kallsyms_symbol() -+ * may resolve an address to. Unlike module_kallsyms_on_each_symbol(), this -+ * also works while @mod is still being loaded. -+ */ -+void module_kallsyms_on_each_addr(struct module *mod, -+ void (*fn)(void *, unsigned long), -+ void *data) -+{ -+ struct mod_kallsyms *kallsyms; -+ unsigned int i; -+ -+ guard(rcu)(); -+ kallsyms = rcu_dereference(mod->kallsyms); -+ -+ /* ELF starts real symbols at 1. */ -+ for (i = 1; i < kallsyms->num_symtab; i++) { -+ if (is_lookup_symbol(kallsyms, i)) -+ fn(data, kallsyms_symbol_value(&kallsyms->symtab[i])); -+ } -+} -+ - int module_kallsyms_on_each_symbol(const char *modname, - int (*fn)(void *, const char *, unsigned long), - void *data) diff --git a/kernel/0860-module-add-module-kallsyms-on-each-addr.patch.sig b/kernel/0860-module-add-module-kallsyms-on-each-addr.patch.sig deleted file mode 100644 index f0c502a..0000000 Binary files a/kernel/0860-module-add-module-kallsyms-on-each-addr.patch.sig and /dev/null differ diff --git a/kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch b/kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch deleted file mode 100644 index 82b00bb..0000000 --- a/kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch +++ /dev/null @@ -1,113 +0,0 @@ -diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c ---- a/kernel/trace/ftrace.c -+++ b/kernel/trace/ftrace.c -@@ -4445,11 +4445,6 @@ static int print_rec(struct seq_file *m, unsigned long ip) - return ret == NULL ? -1 : 0; - } - #else --static inline int test_for_valid_rec(struct dyn_ftrace *rec) --{ -- return 1; --} -- - static inline int print_rec(struct seq_file *m, unsigned long ip) - { - seq_printf(m, "%ps", (void *)ip); -@@ -7611,6 +7606,73 @@ static void test_is_sorted(unsigned long *start, unsigned long count) - } - #endif - -+#ifdef FTRACE_MCOUNT_MAX_OFFSET -+struct ftrace_mod_locs { -+ unsigned long *start; -+ unsigned long count; -+ unsigned long *valid; -+}; -+ -+/* Mark the locations that lie at most FTRACE_MCOUNT_MAX_OFFSET after @addr. */ -+static void ftrace_mark_valid_locs(void *data, unsigned long addr) -+{ -+ struct ftrace_mod_locs *locs = data; -+ unsigned long lo = 0, hi = locs->count, mid, ip; -+ -+ /* -+ * ftrace_call_adjust() moves a location forward by at most -+ * FTRACE_MCOUNT_MAX_OFFSET, so start looking that far before @addr. -+ */ -+ while (lo < hi) { -+ mid = lo + (hi - lo) / 2; -+ if (locs->start[mid] + FTRACE_MCOUNT_MAX_OFFSET < addr) -+ lo = mid + 1; -+ else -+ hi = mid; -+ } -+ -+ for (; lo < locs->count; lo++) { -+ if (locs->start[lo] > addr + FTRACE_MCOUNT_MAX_OFFSET) -+ break; -+ ip = ftrace_call_adjust(locs->start[lo]); -+ if (ip >= addr && ip - addr <= FTRACE_MCOUNT_MAX_OFFSET) -+ __set_bit(lo, locs->valid); -+ } -+} -+ -+/* -+ * A weak function overridden within its module keeps its mcount location but -+ * has no symbol. Zero such locations before they become records, as sorttable -+ * does for vmlinux: keep only those with a symbol at most -+ * FTRACE_MCOUNT_MAX_OFFSET before them. -+ */ -+static int ftrace_zero_weak_locs(struct module *mod, unsigned long *start, -+ unsigned long count) -+{ -+ struct ftrace_mod_locs locs = { .start = start, .count = count }; -+ unsigned long i; -+ -+ locs.valid = bitmap_zalloc(count, GFP_KERNEL); -+ if (!locs.valid) -+ return -ENOMEM; -+ -+ module_kallsyms_on_each_addr(mod, ftrace_mark_valid_locs, &locs); -+ -+ for_each_clear_bit(i, locs.valid, count) -+ start[i] = 0; -+ -+ bitmap_free(locs.valid); -+ return 0; -+} -+#else -+static inline int ftrace_zero_weak_locs(struct module *mod, -+ unsigned long *start, -+ unsigned long count) -+{ -+ return 0; -+} -+#endif -+ - static int ftrace_process_locs(struct module *mod, - unsigned long *start, - unsigned long *end) -@@ -7644,6 +7706,9 @@ static int ftrace_process_locs(struct module *mod, - test_is_sorted(start, count); - } - -+ if (mod && ftrace_zero_weak_locs(mod, start, count)) -+ return -ENOMEM; -+ - start_pg = ftrace_allocate_pages(count, &pages); - if (!start_pg) - return -ENOMEM; -@@ -8049,13 +8114,6 @@ void ftrace_module_enable(struct module *mod) - - cond_resched(); - -- /* Weak functions should still be ignored */ -- if (!test_for_valid_rec(rec)) { -- /* Clear all other flags. Should not be enabled anyway */ -- rec->flags = FTRACE_FL_DISABLED; -- continue; -- } -- - cnt = 0; - - /* diff --git a/kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch.sig b/kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch.sig deleted file mode 100644 index d2d6943..0000000 Binary files a/kernel/0861-ftrace-drop-weak-function-locations-of-modules.patch.sig and /dev/null differ diff --git a/kernel/1000-n1x-mediatek-platform.patch b/kernel/1000-n1x-mediatek-platform.patch deleted file mode 100644 index a1d9841..0000000 --- a/kernel/1000-n1x-mediatek-platform.patch +++ /dev/null @@ -1,8705 +0,0 @@ -From 2a2ab2ce09b8961cc968720e40fb6ed86565a57b Mon Sep 17 00:00:00 2001 -From: Us Chien -Date: Sat, 12 Apr 2025 15:25:35 +0800 -Subject: [PATCH] NVIDIA: SAUCE: MEDIATEK: usb: host: xhci-plat: support usb3 - bulks stream low power - -BugLink: https://bugs.launchpad.net/bugs/2107509 - -Add a quirk to avoid U1 and U2 low power state operations -during bulk stream transfers. - -Change-Id: Iaff484625eca6708713d0c2acaeddfc1103ac7d2 -Signed-off-by: Us Chien -Signed-off-by: Yenchia Chen -Signed-off-by: Terje Bergstrom -Acked-by: Brad Figg -Acked-by: Matt Ochs -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off-by: Brad Figg -(cherry picked from commit 07399e87163635f78a35627866097a5cf6b6494a noble:linux-nvidia-6.11) -Signed-off-by: Jacob Martin -(backported from commit e521e80f789101cbf5041ee8d5606b9262b8250f) -[maskedarray: changed the XHCI_NVIDIA_MT8901_HOST quirk bit value -to 51] -Signed-off-by: Abdur Rahman - -(cherry picked from commit 08ca4af323903e5341d555fc8c947491263eec85 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/usb/host/xhci-plat.c | 3 +++ - drivers/usb/host/xhci.c | 5 +++++ - drivers/usb/host/xhci.h | 1 + - 3 files changed, 9 insertions(+) - -diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c -index 074d9c7316..771836ab20 100644 ---- a/drivers/usb/host/xhci-plat.c -+++ b/drivers/usb/host/xhci-plat.c -@@ -277,6 +277,9 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - if (device_property_read_bool(tmpdev, "xhci-skip-phy-init-quirk")) - xhci->quirks |= XHCI_SKIP_PHY_INIT; - -+ if (device_property_read_bool(tmpdev, "xhci-nvidia-mediatek-host")) -+ xhci->quirks |= XHCI_NVIDIA_MT8901_HOST; -+ - device_property_read_u32(tmpdev, "imod-interval-ns", - &xhci->imod_interval); - device_property_read_u16(tmpdev, "num-hc-interrupters", -diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c -index 5c759ad281..181d4f0cce 100644 ---- a/drivers/usb/host/xhci.c -+++ b/drivers/usb/host/xhci.c -@@ -3735,6 +3735,11 @@ static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, - if (ret < 0) - goto cleanup; - -+ if (xhci->quirks & XHCI_NVIDIA_MT8901_HOST) { -+ xhci_hub_control(hcd, SetPortFeature, USB_PORT_FEAT_U1_TIMEOUT, 0, NULL, 0); -+ xhci_hub_control(hcd, SetPortFeature, USB_PORT_FEAT_U2_TIMEOUT, 0, NULL, 0); -+ } -+ - spin_lock_irqsave(&xhci->lock, flags); - for (i = 0; i < num_eps; i++) { - ep_index = xhci_get_endpoint_index(&eps[i]->desc); -diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h -index 708e3ccc5d..3915f33529 100644 ---- a/drivers/usb/host/xhci.h -+++ b/drivers/usb/host/xhci.h -@@ -1648,6 +1648,7 @@ struct xhci_hcd { - #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48) - #define XHCI_ETRON_HOST BIT_ULL(49) - #define XHCI_LIMIT_ENDPOINT_INTERVAL_9 BIT_ULL(50) -+#define XHCI_NVIDIA_MT8901_HOST BIT_ULL(51) - - unsigned int num_active_eps; - unsigned int limit_active_eps; -From 32cdf0983f839ae48c81fe78926645352c4990e7 Mon Sep 17 00:00:00 2001 -From: Jonas Chen -Date: Mon, 21 Apr 2025 17:17:38 +0800 -Subject: [PATCH] NVIDIA: SAUCE: MEDIATEK: pinctrl: mediatek: Add gpio-range - record in pinctrl driver - -BugLink: https://bugs.launchpad.net/bugs/2117784 - -Kernel GPIO subsystem mapping hardware pin number to a different -range of gpio number. Add gpio-range structure to hold -the mapped gpio range in pinctrl driver. That enables the kernel -to search a range of mapped gpio range against a pinctrl device. - -Signed-off-by: Jonas Chen -Signed-off-by: Yenchia Chen -Signed-off-by: Abhishek Sahu -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Acked-by: nvmochs -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 1049985ca252 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit c113e8d8f903eccbe4fa0c075af1aadd5f4fe014 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h | 1 + - drivers/pinctrl/mediatek/pinctrl-paris.c | 15 ++++++++++++++- - 2 files changed, 15 insertions(+), 1 deletion(-) - -diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -index fa7c0ed493..df8dce1474 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -@@ -302,6 +302,7 @@ struct mtk_pinctrl { - spinlock_t lock; - /* identify rsel setting by si unit or rsel define in dts node */ - bool rsel_si_unit; -+ struct pinctrl_gpio_range range; - }; - - void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set); -diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c -index 23f04b24fd..fe437326a5 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-paris.c -+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c -@@ -3,7 +3,7 @@ - * MediaTek Pinctrl Paris Driver, which implement the vendor per-pin - * bindings for MediaTek SoC. - * -- * Copyright (C) 2018 MediaTek Inc. -+ * Copyright (C) 2018-2025 MediaTek Inc. - * Author: Sean Wang - * Zhiyong Tao - * Hongzhou.Yang -@@ -938,6 +938,15 @@ static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, - return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); - } - -+static void mtk_pinctrl_gpio_range_init(struct mtk_pinctrl *hw, struct gpio_chip *chip) -+{ -+ hw->range.name = "mtk_pinctrl_gpio_range"; -+ hw->range.id = 0; -+ hw->range.pin_base = 0; -+ hw->range.base = chip->base; -+ hw->range.npins = hw->soc->npins; -+} -+ - static int mtk_build_gpiochip(struct mtk_pinctrl *hw) - { - struct gpio_chip *chip = &hw->chip; -@@ -961,6 +970,8 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw) - if (ret < 0) - return ret; - -+ mtk_pinctrl_gpio_range_init(hw, chip); -+ - return 0; - } - -@@ -1079,6 +1090,8 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev) - if (err) - return dev_err_probe(dev, err, "Failed to add gpio_chip\n"); - -+ pinctrl_add_gpio_range(hw->pctrl, &hw->range); -+ - platform_set_drvdata(pdev, hw); - - return 0; -From 527ed14163f305522b0bbad08ba4e823f774d95a Mon Sep 17 00:00:00 2001 -From: Jonas Chen -Date: Tue, 22 Apr 2025 09:18:17 +0800 -Subject: [PATCH] NVIDIA: SAUCE: MEDIATEK: pinctrl: mediatek: Add acpi support - -BugLink: https://bugs.launchpad.net/bugs/2117784 - -Add acpi support in the shared part of pinctrl driver. Parsing -hardware base addresses and irq naumber to initialize eint -accroding to the acpi table data. - -Signed-off-by: Jonas Chen -Signed-off-by: Yenchia Chen -Signed-off-by: Abhishek Sahu -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Acked-by: nvmochs -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg -(backported from commit cdce65d91ea9 noble:linux-nvidia-6.14) -[maskedarray: context adjusted due to commit 86dee87: "pinctrl: -mediatek: Fix the invalid conditions"] -Signed-off-by: Abdur Rahman - -(cherry picked from commit 84076e8dd9e065d3ab6ce59aec774a14c7f8ff32 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 26 +++++++++++++++---- - drivers/pinctrl/mediatek/pinctrl-paris.c | 11 +++++--- - 2 files changed, 29 insertions(+), 8 deletions(-) - -diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -index 4918d38abf..fc71f9b267 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -@@ -1,6 +1,6 @@ - // SPDX-License-Identifier: GPL-2.0 - /* -- * Copyright (C) 2018 MediaTek Inc. -+ * Copyright (C) 2018-2025 MediaTek Inc. - * - * Author: Sean Wang - * -@@ -369,18 +369,30 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) - { - struct device_node *np = pdev->dev.of_node; - int ret, i, j, count_reg_names; -+ struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev); -+ struct resource *res; - - if (!IS_ENABLED(CONFIG_EINT_MTK)) - return 0; - -- if (!of_property_read_bool(np, "interrupt-controller")) -+ if (is_of_node(fwnode) && !of_property_read_bool(np, "interrupt-controller")) - return -ENODEV; - - hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL); - if (!hw->eint) - return -ENOMEM; - -- count_reg_names = of_property_count_strings(np, "reg-names"); -+ if (is_of_node(fwnode)) { -+ count_reg_names = of_property_count_strings(np, "reg-names"); -+ } else { -+ count_reg_names = 0; -+ for (i = 0; i < pdev->num_resources; i++) { -+ struct resource *r = &pdev->resource[i]; -+ -+ if (resource_type(r) == IORESOURCE_MEM) -+ count_reg_names++; -+ } -+ } - if (count_reg_names < 0) - return -EINVAL; - -@@ -396,14 +408,18 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) - } - - for (i = hw->soc->nbase_names, j = 0; i < count_reg_names; i++, j++) { -- hw->eint->base[j] = of_iomap(np, i); -+ res = platform_get_resource(pdev, IORESOURCE_MEM, i); -+ hw->eint->base[j] = is_of_node(fwnode) ? of_iomap(np, i) : -+ ioremap(res->start, resource_size(res)); - if (IS_ERR(hw->eint->base[j])) { - ret = PTR_ERR(hw->eint->base[j]); - goto err_free_eint; - } - } - -- hw->eint->irq = irq_of_parse_and_map(np, 0); -+ hw->eint->irq = is_of_node(fwnode) -+ ? irq_of_parse_and_map(np, 0) -+ : platform_get_irq(pdev, 0); - if (!hw->eint->irq) { - ret = -EINVAL; - goto err_free_eint; -diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c -index fe437326a5..b4422c981b 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-paris.c -+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c -@@ -1010,6 +1010,7 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev) - struct device *dev = &pdev->dev; - struct pinctrl_pin_desc *pins; - struct mtk_pinctrl *hw; -+ struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev); - int err, i; - - hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); -@@ -1034,16 +1035,20 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev) - return -ENOMEM; - - for (i = 0; i < hw->soc->nbase_names; i++) { -- hw->base[i] = devm_platform_ioremap_resource_byname(pdev, -- hw->soc->base_names[i]); -+ hw->base[i] = is_of_node(fwnode) -+ ? devm_platform_ioremap_resource_byname(pdev, hw->soc->base_names[i]) -+ : devm_platform_get_and_ioremap_resource(pdev, i, NULL); - if (IS_ERR(hw->base[i])) - return PTR_ERR(hw->base[i]); - } - - hw->nbase = hw->soc->nbase_names; - -- hw->rsel_si_unit = of_property_read_bool(hw->dev->of_node, -+ if (is_of_node(fwnode)) -+ hw->rsel_si_unit = of_property_read_bool(hw->dev->of_node, - "mediatek,rsel-resistance-in-si-unit"); -+ else -+ hw->rsel_si_unit = false; - - spin_lock_init(&hw->lock); - -From 6283cec8f949b6c424e866f70a4a71621133594b Mon Sep 17 00:00:00 2001 -From: Jonas Chen -Date: Tue, 22 Apr 2025 09:30:44 +0800 -Subject: [PATCH] NVIDIA: SAUCE: MEDIATEK: pinctrl: mt8901: Add pinctrl driver - -BugLink: https://bugs.launchpad.net/bugs/2117784 - -Add mt8901 pinctrl, gpio and eint driver implementation. - -Signed-off-by: Jonas Chen -Signed-off-by: Yenchia Chen -Signed-off-by: Abhishek Sahu -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Acked-by: nvmochs -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off-by: Brad Figg -(backported from commit 1fc7a586c54c noble:linux-nvidia-6.14) -[maskedarray: context adjusted for missing commit a3fe132: "pinctrl: -mediatek: Add pinctrl driver for mt8189"] -Signed-off-by: Abdur Rahman -(backported from commit 81bfb0635b75667abd430efc1d2ea50813b0fdf5 noble:linux-nvidia-6.17) -[jacobmartin: context adjusted for new pinctrl-mt8901 driver from -upstream] -Signed-off-by: Jacob Martin ---- - drivers/pinctrl/mediatek/Kconfig | 12 + - drivers/pinctrl/mediatek/Makefile | 1 + - drivers/pinctrl/mediatek/mtk-eint.c | 4 + - drivers/pinctrl/mediatek/mtk-eint.h | 1 + - drivers/pinctrl/mediatek/pinctrl-mt8901.c | 1460 +++++++++++ - drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h | 2130 +++++++++++++++++ - 6 files changed, 3608 insertions(+) - create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt8901.c - create mode 100644 drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h - -diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig -index 97980cc28b..e66e7f8d1f 100644 ---- a/drivers/pinctrl/mediatek/Kconfig -+++ b/drivers/pinctrl/mediatek/Kconfig -@@ -266,6 +266,18 @@ config PINCTRL_MT8189 - In MTK platform, we support virtual gpio and use it to - map specific eint which doesn't have real gpio pin. - -+config PINCTRL_MT8901 -+ bool "MediaTek MT8901 pin control" -+ depends on ACPI -+ depends on ARM64 || COMPILE_TEST -+ default ARM64 && ARCH_MEDIATEK -+ select PINCTRL_MTK_PARIS -+ help -+ Say yes here to support pin controller and gpio driver -+ on MediaTek MT8901 SoC. -+ In MTK platform, we support virtual gpio and use it to -+ map specific eint which doesn't have real gpio pin. -+ - config PINCTRL_MT8192 - bool "MediaTek MT8192 pin control" - depends on OF -diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile -index 6dc17b0c23..77f87d3525 100644 ---- a/drivers/pinctrl/mediatek/Makefile -+++ b/drivers/pinctrl/mediatek/Makefile -@@ -42,3 +42,4 @@ obj-$(CONFIG_PINCTRL_MT8196) += pinctrl-mt8196.o - obj-$(CONFIG_PINCTRL_MT8365) += pinctrl-mt8365.o - obj-$(CONFIG_PINCTRL_MT8516) += pinctrl-mt8516.o - obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o -+obj-$(CONFIG_PINCTRL_MT8901) += pinctrl-mt8901.o -diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c -index 47ac92ea98..61c4ac2545 100644 ---- a/drivers/pinctrl/mediatek/mtk-eint.c -+++ b/drivers/pinctrl/mediatek/mtk-eint.c -@@ -71,6 +71,10 @@ const unsigned int debounce_time_mt6878[] = { - }; - EXPORT_SYMBOL_GPL(debounce_time_mt6878); - -+const unsigned int debounce_time_mt8901[] = { -+ 156, 313, 625, 1250, 20000, 40000, 80000, 160000, 320000, 640000, 0}; -+EXPORT_SYMBOL_GPL(debounce_time_mt8901); -+ - static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint, - unsigned int eint_num, - unsigned int offset) -diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h -index 3cdd6f6310..1b185f660a 100644 ---- a/drivers/pinctrl/mediatek/mtk-eint.h -+++ b/drivers/pinctrl/mediatek/mtk-eint.h -@@ -53,6 +53,7 @@ extern const unsigned int debounce_time_mt2701[]; - extern const unsigned int debounce_time_mt6765[]; - extern const unsigned int debounce_time_mt6795[]; - extern const unsigned int debounce_time_mt6878[]; -+extern const unsigned int debounce_time_mt8901[]; - - struct mtk_eint; - -diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8901.c b/drivers/pinctrl/mediatek/pinctrl-mt8901.c -new file mode 100644 -index 0000000000..623cd0cd58 ---- /dev/null -+++ b/drivers/pinctrl/mediatek/pinctrl-mt8901.c -@@ -0,0 +1,1460 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2025 MediaTek Inc. -+ * -+ */ -+ -+#include -+#include -+#include "pinctrl-mtk-mt8901.h" -+#include "pinctrl-paris.h" -+ -+#define PIN_FIELD_BASE(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits) \ -+ PIN_FIELD_CALC(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits, 32, 0) -+#define PINS_FIELD_BASE(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits) \ -+ PIN_FIELD_CALC(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits, 32, 1) -+ -+static const struct mtk_pin_field_calc mt8901_pin_mode_range[] = { -+ PIN_FIELD(0, 181, 0x0300, 0x10, 0, 4), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_dir_range[] = { -+ PIN_FIELD(0, 181, 0x0000, 0x10, 0, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_di_range[] = { -+ PIN_FIELD(0, 181, 0x0200, 0x10, 0, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_do_range[] = { -+ PIN_FIELD(0, 181, 0x0100, 0x10, 0, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_smt_range[] = { -+ PIN_FIELD_BASE(0, 0, 8, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(1, 1, 8, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(2, 2, 8, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(3, 3, 8, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(4, 4, 8, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(5, 5, 8, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(6, 6, 8, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(7, 7, 8, 0x00c0, 0x10, 7, 1), -+ PIN_FIELD_BASE(8, 8, 2, 0x0120, 0x10, 13, 1), -+ PIN_FIELD_BASE(9, 9, 2, 0x0120, 0x10, 14, 1), -+ PIN_FIELD_BASE(10, 10, 2, 0x0120, 0x10, 15, 1), -+ PIN_FIELD_BASE(11, 11, 2, 0x0120, 0x10, 16, 1), -+ PIN_FIELD_BASE(12, 12, 1, 0x0140, 0x10, 17, 1), -+ PIN_FIELD_BASE(13, 13, 1, 0x0140, 0x10, 18, 1), -+ PIN_FIELD_BASE(14, 14, 1, 0x0140, 0x10, 14, 1), -+ PIN_FIELD_BASE(15, 15, 1, 0x0140, 0x10, 16, 1), -+ PIN_FIELD_BASE(16, 16, 1, 0x0140, 0x10, 19, 1), -+ PIN_FIELD_BASE(17, 17, 1, 0x0140, 0x10, 20, 1), -+ PIN_FIELD_BASE(18, 18, 1, 0x0140, 0x10, 21, 1), -+ PIN_FIELD_BASE(19, 19, 1, 0x0140, 0x10, 27, 1), -+ PIN_FIELD_BASE(20, 20, 1, 0x0140, 0x10, 28, 1), -+ PIN_FIELD_BASE(21, 21, 1, 0x0140, 0x10, 26, 1), -+ PIN_FIELD_BASE(22, 22, 1, 0x0140, 0x10, 25, 1), -+ PIN_FIELD_BASE(23, 23, 1, 0x0140, 0x10, 0, 1), -+ PIN_FIELD_BASE(24, 24, 1, 0x0140, 0x10, 1, 1), -+ PIN_FIELD_BASE(25, 25, 1, 0x0140, 0x10, 2, 1), -+ PIN_FIELD_BASE(26, 26, 1, 0x0140, 0x10, 3, 1), -+ PIN_FIELD_BASE(27, 27, 1, 0x0140, 0x10, 4, 1), -+ PIN_FIELD_BASE(28, 28, 1, 0x0140, 0x10, 5, 1), -+ PIN_FIELD_BASE(29, 29, 1, 0x0140, 0x10, 6, 1), -+ PIN_FIELD_BASE(30, 30, 1, 0x0140, 0x10, 7, 1), -+ PIN_FIELD_BASE(31, 31, 1, 0x0140, 0x10, 8, 1), -+ PIN_FIELD_BASE(32, 32, 9, 0x0100, 0x10, 0, 1), -+ PIN_FIELD_BASE(33, 33, 1, 0x0140, 0x10, 9, 1), -+ PIN_FIELD_BASE(34, 34, 1, 0x0140, 0x10, 10, 1), -+ PIN_FIELD_BASE(35, 35, 1, 0x0140, 0x10, 11, 1), -+ PIN_FIELD_BASE(36, 36, 9, 0x0100, 0x10, 8, 1), -+ PIN_FIELD_BASE(37, 37, 2, 0x0120, 0x10, 17, 1), -+ PIN_FIELD_BASE(38, 38, 2, 0x0120, 0x10, 18, 1), -+ PIN_FIELD_BASE(39, 39, 1, 0x0140, 0x10, 12, 1), -+ PIN_FIELD_BASE(40, 40, 2, 0x0120, 0x10, 1, 1), -+ PIN_FIELD_BASE(41, 41, 2, 0x0120, 0x10, 2, 1), -+ PIN_FIELD_BASE(42, 42, 2, 0x0120, 0x10, 3, 1), -+ PIN_FIELD_BASE(43, 43, 2, 0x0120, 0x10, 4, 1), -+ PIN_FIELD_BASE(44, 44, 2, 0x0120, 0x10, 5, 1), -+ PIN_FIELD_BASE(45, 45, 2, 0x0120, 0x10, 6, 1), -+ PIN_FIELD_BASE(46, 46, 1, 0x0140, 0x10, 13, 1), -+ PIN_FIELD_BASE(47, 47, 1, 0x0140, 0x10, 15, 1), -+ PIN_FIELD_BASE(48, 48, 2, 0x0120, 0x10, 7, 1), -+ PIN_FIELD_BASE(49, 49, 2, 0x0120, 0x10, 8, 1), -+ PIN_FIELD_BASE(50, 50, 2, 0x0120, 0x10, 9, 1), -+ PIN_FIELD_BASE(51, 51, 2, 0x0120, 0x10, 10, 1), -+ PIN_FIELD_BASE(52, 52, 2, 0x0120, 0x10, 11, 1), -+ PIN_FIELD_BASE(53, 53, 2, 0x0120, 0x10, 12, 1), -+ PIN_FIELD_BASE(54, 54, 5, 0x0120, 0x10, 10, 1), -+ PIN_FIELD_BASE(55, 55, 5, 0x0120, 0x10, 11, 1), -+ PIN_FIELD_BASE(56, 56, 1, 0x0140, 0x10, 22, 1), -+ PIN_FIELD_BASE(57, 57, 1, 0x0140, 0x10, 23, 1), -+ PIN_FIELD_BASE(58, 58, 1, 0x0140, 0x10, 24, 1), -+ PIN_FIELD_BASE(59, 59, 2, 0x0120, 0x10, 0, 1), -+ PIN_FIELD_BASE(60, 60, 9, 0x0100, 0x10, 1, 1), -+ PIN_FIELD_BASE(61, 61, 9, 0x0100, 0x10, 2, 1), -+ PIN_FIELD_BASE(62, 62, 9, 0x0100, 0x10, 3, 1), -+ PIN_FIELD_BASE(63, 63, 9, 0x0100, 0x10, 4, 1), -+ PIN_FIELD_BASE(64, 64, 9, 0x0100, 0x10, 5, 1), -+ PIN_FIELD_BASE(65, 65, 9, 0x0100, 0x10, 6, 1), -+ PIN_FIELD_BASE(66, 66, 5, 0x0120, 0x10, 0, 1), -+ PIN_FIELD_BASE(67, 67, 5, 0x0120, 0x10, 1, 1), -+ PIN_FIELD_BASE(68, 68, 9, 0x0100, 0x10, 7, 1), -+ PIN_FIELD_BASE(69, 69, 7, 0x0110, 0x10, 0, 1), -+ PIN_FIELD_BASE(70, 70, 7, 0x0110, 0x10, 1, 1), -+ PIN_FIELD_BASE(71, 71, 7, 0x0110, 0x10, 2, 1), -+ PIN_FIELD_BASE(72, 72, 7, 0x0110, 0x10, 3, 1), -+ PIN_FIELD_BASE(73, 73, 7, 0x0110, 0x10, 4, 1), -+ PIN_FIELD_BASE(74, 74, 7, 0x0110, 0x10, 5, 1), -+ PIN_FIELD_BASE(75, 75, 7, 0x0110, 0x10, 6, 1), -+ PIN_FIELD_BASE(76, 76, 7, 0x0110, 0x10, 7, 1), -+ PIN_FIELD_BASE(77, 77, 7, 0x0110, 0x10, 8, 1), -+ PIN_FIELD_BASE(78, 78, 7, 0x0110, 0x10, 9, 1), -+ PIN_FIELD_BASE(79, 79, 7, 0x0110, 0x10, 10, 1), -+ PIN_FIELD_BASE(80, 80, 7, 0x0110, 0x10, 11, 1), -+ PIN_FIELD_BASE(81, 81, 7, 0x0110, 0x10, 12, 1), -+ PIN_FIELD_BASE(82, 82, 7, 0x0110, 0x10, 13, 1), -+ PIN_FIELD_BASE(83, 83, 7, 0x0110, 0x10, 14, 1), -+ PIN_FIELD_BASE(84, 84, 7, 0x0110, 0x10, 15, 1), -+ PIN_FIELD_BASE(85, 85, 7, 0x0110, 0x10, 16, 1), -+ PIN_FIELD_BASE(86, 86, 7, 0x0110, 0x10, 17, 1), -+ PIN_FIELD_BASE(87, 87, 7, 0x0110, 0x10, 18, 1), -+ PIN_FIELD_BASE(88, 88, 7, 0x0110, 0x10, 19, 1), -+ PIN_FIELD_BASE(89, 89, 7, 0x0110, 0x10, 20, 1), -+ PIN_FIELD_BASE(90, 90, 7, 0x0110, 0x10, 21, 1), -+ PIN_FIELD_BASE(91, 91, 7, 0x0110, 0x10, 22, 1), -+ PIN_FIELD_BASE(92, 92, 3, 0x0130, 0x10, 16, 1), -+ PIN_FIELD_BASE(93, 93, 3, 0x0130, 0x10, 17, 1), -+ PIN_FIELD_BASE(94, 94, 3, 0x0130, 0x10, 18, 1), -+ PIN_FIELD_BASE(95, 95, 3, 0x0130, 0x10, 19, 1), -+ PIN_FIELD_BASE(96, 96, 3, 0x0130, 0x10, 20, 1), -+ PIN_FIELD_BASE(97, 97, 3, 0x0130, 0x10, 21, 1), -+ PIN_FIELD_BASE(98, 98, 3, 0x0130, 0x10, 22, 1), -+ PIN_FIELD_BASE(99, 99, 3, 0x0130, 0x10, 23, 1), -+ PIN_FIELD_BASE(100, 100, 3, 0x0130, 0x10, 24, 1), -+ PIN_FIELD_BASE(101, 101, 3, 0x0130, 0x10, 25, 1), -+ PIN_FIELD_BASE(102, 102, 3, 0x0130, 0x10, 26, 1), -+ PIN_FIELD_BASE(103, 103, 3, 0x0130, 0x10, 27, 1), -+ PIN_FIELD_BASE(104, 104, 3, 0x0130, 0x10, 28, 1), -+ PIN_FIELD_BASE(105, 105, 3, 0x0130, 0x10, 29, 1), -+ PIN_FIELD_BASE(106, 106, 8, 0x00c0, 0x10, 8, 1), -+ PIN_FIELD_BASE(107, 107, 8, 0x00c0, 0x10, 9, 1), -+ PIN_FIELD_BASE(108, 108, 8, 0x00c0, 0x10, 10, 1), -+ PIN_FIELD_BASE(109, 109, 8, 0x00c0, 0x10, 11, 1), -+ PIN_FIELD_BASE(110, 110, 8, 0x00c0, 0x10, 12, 1), -+ PIN_FIELD_BASE(111, 111, 8, 0x00c0, 0x10, 13, 1), -+ PIN_FIELD_BASE(112, 112, 5, 0x0120, 0x10, 15, 1), -+ PIN_FIELD_BASE(113, 113, 5, 0x0120, 0x10, 16, 1), -+ PIN_FIELD_BASE(114, 114, 5, 0x0120, 0x10, 17, 1), -+ PIN_FIELD_BASE(115, 115, 5, 0x0120, 0x10, 18, 1), -+ PIN_FIELD_BASE(116, 116, 5, 0x0120, 0x10, 19, 1), -+ PIN_FIELD_BASE(117, 117, 4, 0x0110, 0x10, 8, 1), -+ PIN_FIELD_BASE(118, 118, 4, 0x0110, 0x10, 9, 1), -+ PIN_FIELD_BASE(119, 119, 4, 0x0110, 0x10, 10, 1), -+ PIN_FIELD_BASE(120, 120, 4, 0x0110, 0x10, 11, 1), -+ PIN_FIELD_BASE(121, 121, 4, 0x0110, 0x10, 12, 1), -+ PIN_FIELD_BASE(122, 122, 4, 0x0110, 0x10, 13, 1), -+ PIN_FIELD_BASE(123, 123, 4, 0x0110, 0x10, 14, 1), -+ PIN_FIELD_BASE(124, 124, 4, 0x0110, 0x10, 15, 1), -+ PIN_FIELD_BASE(125, 125, 4, 0x0110, 0x10, 16, 1), -+ PIN_FIELD_BASE(126, 126, 5, 0x0120, 0x10, 6, 1), -+ PIN_FIELD_BASE(127, 127, 5, 0x0120, 0x10, 7, 1), -+ PIN_FIELD_BASE(128, 128, 5, 0x0120, 0x10, 8, 1), -+ PIN_FIELD_BASE(129, 129, 5, 0x0120, 0x10, 9, 1), -+ PIN_FIELD_BASE(130, 130, 4, 0x0110, 0x10, 17, 1), -+ PIN_FIELD_BASE(131, 131, 4, 0x0110, 0x10, 18, 1), -+ PIN_FIELD_BASE(132, 132, 4, 0x0110, 0x10, 19, 1), -+ PIN_FIELD_BASE(133, 133, 4, 0x0110, 0x10, 20, 1), -+ PIN_FIELD_BASE(134, 134, 3, 0x0130, 0x10, 0, 1), -+ PIN_FIELD_BASE(135, 135, 3, 0x0130, 0x10, 1, 1), -+ PIN_FIELD_BASE(136, 136, 3, 0x0130, 0x10, 2, 1), -+ PIN_FIELD_BASE(137, 137, 3, 0x0130, 0x10, 3, 1), -+ PIN_FIELD_BASE(138, 138, 3, 0x0130, 0x10, 4, 1), -+ PIN_FIELD_BASE(139, 139, 3, 0x0130, 0x10, 5, 1), -+ PIN_FIELD_BASE(140, 140, 3, 0x0130, 0x10, 6, 1), -+ PIN_FIELD_BASE(141, 141, 3, 0x0130, 0x10, 7, 1), -+ PIN_FIELD_BASE(142, 142, 3, 0x0130, 0x10, 8, 1), -+ PIN_FIELD_BASE(143, 143, 3, 0x0130, 0x10, 9, 1), -+ PIN_FIELD_BASE(144, 144, 3, 0x0130, 0x10, 10, 1), -+ PIN_FIELD_BASE(145, 145, 3, 0x0130, 0x10, 11, 1), -+ PIN_FIELD_BASE(146, 146, 3, 0x0130, 0x10, 12, 1), -+ PIN_FIELD_BASE(147, 147, 3, 0x0130, 0x10, 13, 1), -+ PIN_FIELD_BASE(148, 148, 3, 0x0130, 0x10, 14, 1), -+ PIN_FIELD_BASE(149, 149, 3, 0x0130, 0x10, 15, 1), -+ PIN_FIELD_BASE(150, 150, 4, 0x0110, 0x10, 21, 1), -+ PIN_FIELD_BASE(151, 151, 4, 0x0110, 0x10, 26, 1), -+ PIN_FIELD_BASE(152, 152, 4, 0x0110, 0x10, 25, 1), -+ PIN_FIELD_BASE(153, 153, 4, 0x0110, 0x10, 24, 1), -+ PIN_FIELD_BASE(154, 154, 4, 0x0110, 0x10, 22, 1), -+ PIN_FIELD_BASE(155, 155, 4, 0x0110, 0x10, 23, 1), -+ PIN_FIELD_BASE(156, 156, 4, 0x0110, 0x10, 0, 1), -+ PIN_FIELD_BASE(157, 157, 4, 0x0110, 0x10, 1, 1), -+ PIN_FIELD_BASE(158, 158, 4, 0x0110, 0x10, 2, 1), -+ PIN_FIELD_BASE(159, 159, 4, 0x0110, 0x10, 3, 1), -+ PIN_FIELD_BASE(160, 160, 4, 0x0110, 0x10, 4, 1), -+ PIN_FIELD_BASE(161, 161, 4, 0x0110, 0x10, 5, 1), -+ PIN_FIELD_BASE(162, 162, 4, 0x0110, 0x10, 6, 1), -+ PIN_FIELD_BASE(163, 163, 4, 0x0110, 0x10, 7, 1), -+ PIN_FIELD_BASE(164, 164, 5, 0x0120, 0x10, 12, 1), -+ PIN_FIELD_BASE(165, 165, 5, 0x0120, 0x10, 3, 1), -+ PIN_FIELD_BASE(166, 166, 5, 0x0120, 0x10, 4, 1), -+ PIN_FIELD_BASE(167, 167, 5, 0x0120, 0x10, 2, 1), -+ PIN_FIELD_BASE(168, 168, 5, 0x0120, 0x10, 13, 1), -+ PIN_FIELD_BASE(169, 169, 5, 0x0120, 0x10, 14, 1), -+ PIN_FIELD_BASE(170, 170, 5, 0x0120, 0x10, 5, 1), -+ PIN_FIELD_BASE(171, 171, 6, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(172, 172, 6, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(173, 173, 6, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(174, 174, 6, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(175, 175, 6, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(176, 176, 6, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(177, 177, 6, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(178, 178, 6, 0x00c0, 0x10, 7, 1), -+ PIN_FIELD_BASE(179, 179, 6, 0x00c0, 0x10, 8, 1), -+ PIN_FIELD_BASE(180, 180, 6, 0x00c0, 0x10, 9, 1), -+ PIN_FIELD_BASE(181, 181, 10, 0x0080, 0x10, 0, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_ies_range[] = { -+ PIN_FIELD_BASE(0, 0, 8, 0x0050, 0x10, 0, 1), -+ PIN_FIELD_BASE(1, 1, 8, 0x0050, 0x10, 1, 1), -+ PIN_FIELD_BASE(2, 2, 8, 0x0050, 0x10, 2, 1), -+ PIN_FIELD_BASE(3, 3, 8, 0x0050, 0x10, 3, 1), -+ PIN_FIELD_BASE(4, 4, 8, 0x0050, 0x10, 4, 1), -+ PIN_FIELD_BASE(5, 5, 8, 0x0050, 0x10, 5, 1), -+ PIN_FIELD_BASE(6, 6, 8, 0x0050, 0x10, 6, 1), -+ PIN_FIELD_BASE(7, 7, 8, 0x0050, 0x10, 7, 1), -+ PIN_FIELD_BASE(8, 8, 2, 0x0070, 0x10, 13, 1), -+ PIN_FIELD_BASE(9, 9, 2, 0x0070, 0x10, 14, 1), -+ PIN_FIELD_BASE(10, 10, 2, 0x0070, 0x10, 15, 1), -+ PIN_FIELD_BASE(11, 11, 2, 0x0070, 0x10, 16, 1), -+ PIN_FIELD_BASE(12, 12, 1, 0x0080, 0x10, 17, 1), -+ PIN_FIELD_BASE(13, 13, 1, 0x0080, 0x10, 18, 1), -+ PIN_FIELD_BASE(14, 14, 1, 0x0080, 0x10, 14, 1), -+ PIN_FIELD_BASE(15, 15, 1, 0x0080, 0x10, 16, 1), -+ PIN_FIELD_BASE(16, 16, 1, 0x0080, 0x10, 19, 1), -+ PIN_FIELD_BASE(17, 17, 1, 0x0080, 0x10, 20, 1), -+ PIN_FIELD_BASE(18, 18, 1, 0x0080, 0x10, 21, 1), -+ PIN_FIELD_BASE(19, 19, 1, 0x0080, 0x10, 27, 1), -+ PIN_FIELD_BASE(20, 20, 1, 0x0080, 0x10, 28, 1), -+ PIN_FIELD_BASE(21, 21, 1, 0x0080, 0x10, 26, 1), -+ PIN_FIELD_BASE(22, 22, 1, 0x0080, 0x10, 25, 1), -+ PIN_FIELD_BASE(23, 23, 1, 0x0080, 0x10, 0, 1), -+ PIN_FIELD_BASE(24, 24, 1, 0x0080, 0x10, 1, 1), -+ PIN_FIELD_BASE(25, 25, 1, 0x0080, 0x10, 2, 1), -+ PIN_FIELD_BASE(26, 26, 1, 0x0080, 0x10, 3, 1), -+ PIN_FIELD_BASE(27, 27, 1, 0x0080, 0x10, 4, 1), -+ PIN_FIELD_BASE(28, 28, 1, 0x0080, 0x10, 5, 1), -+ PIN_FIELD_BASE(29, 29, 1, 0x0080, 0x10, 6, 1), -+ PIN_FIELD_BASE(30, 30, 1, 0x0080, 0x10, 7, 1), -+ PIN_FIELD_BASE(31, 31, 1, 0x0080, 0x10, 8, 1), -+ PIN_FIELD_BASE(32, 32, 9, 0x0060, 0x10, 0, 1), -+ PIN_FIELD_BASE(33, 33, 1, 0x0080, 0x10, 9, 1), -+ PIN_FIELD_BASE(34, 34, 1, 0x0080, 0x10, 10, 1), -+ PIN_FIELD_BASE(35, 35, 1, 0x0080, 0x10, 11, 1), -+ PIN_FIELD_BASE(36, 36, 9, 0x0060, 0x10, 8, 1), -+ PIN_FIELD_BASE(37, 37, 2, 0x0070, 0x10, 17, 1), -+ PIN_FIELD_BASE(38, 38, 2, 0x0070, 0x10, 18, 1), -+ PIN_FIELD_BASE(39, 39, 1, 0x0080, 0x10, 12, 1), -+ PIN_FIELD_BASE(40, 40, 2, 0x0070, 0x10, 1, 1), -+ PIN_FIELD_BASE(41, 41, 2, 0x0070, 0x10, 2, 1), -+ PIN_FIELD_BASE(42, 42, 2, 0x0070, 0x10, 3, 1), -+ PIN_FIELD_BASE(43, 43, 2, 0x0070, 0x10, 4, 1), -+ PIN_FIELD_BASE(44, 44, 2, 0x0070, 0x10, 5, 1), -+ PIN_FIELD_BASE(45, 45, 2, 0x0070, 0x10, 6, 1), -+ PIN_FIELD_BASE(46, 46, 1, 0x0080, 0x10, 13, 1), -+ PIN_FIELD_BASE(47, 47, 1, 0x0080, 0x10, 15, 1), -+ PIN_FIELD_BASE(48, 48, 2, 0x0070, 0x10, 7, 1), -+ PIN_FIELD_BASE(49, 49, 2, 0x0070, 0x10, 8, 1), -+ PIN_FIELD_BASE(50, 50, 2, 0x0070, 0x10, 9, 1), -+ PIN_FIELD_BASE(51, 51, 2, 0x0070, 0x10, 10, 1), -+ PIN_FIELD_BASE(52, 52, 2, 0x0070, 0x10, 11, 1), -+ PIN_FIELD_BASE(53, 53, 2, 0x0070, 0x10, 12, 1), -+ PIN_FIELD_BASE(54, 54, 5, 0x0060, 0x10, 10, 1), -+ PIN_FIELD_BASE(55, 55, 5, 0x0060, 0x10, 11, 1), -+ PIN_FIELD_BASE(56, 56, 1, 0x0080, 0x10, 22, 1), -+ PIN_FIELD_BASE(57, 57, 1, 0x0080, 0x10, 23, 1), -+ PIN_FIELD_BASE(58, 58, 1, 0x0080, 0x10, 24, 1), -+ PIN_FIELD_BASE(59, 59, 2, 0x0070, 0x10, 0, 1), -+ PIN_FIELD_BASE(60, 60, 9, 0x0060, 0x10, 1, 1), -+ PIN_FIELD_BASE(61, 61, 9, 0x0060, 0x10, 2, 1), -+ PIN_FIELD_BASE(62, 62, 9, 0x0060, 0x10, 3, 1), -+ PIN_FIELD_BASE(63, 63, 9, 0x0060, 0x10, 4, 1), -+ PIN_FIELD_BASE(64, 64, 9, 0x0060, 0x10, 5, 1), -+ PIN_FIELD_BASE(65, 65, 9, 0x0060, 0x10, 6, 1), -+ PIN_FIELD_BASE(66, 66, 5, 0x0060, 0x10, 0, 1), -+ PIN_FIELD_BASE(67, 67, 5, 0x0060, 0x10, 1, 1), -+ PIN_FIELD_BASE(68, 68, 9, 0x0060, 0x10, 7, 1), -+ PIN_FIELD_BASE(69, 69, 7, 0x0070, 0x10, 0, 1), -+ PIN_FIELD_BASE(70, 70, 7, 0x0070, 0x10, 1, 1), -+ PIN_FIELD_BASE(71, 71, 7, 0x0070, 0x10, 2, 1), -+ PIN_FIELD_BASE(72, 72, 7, 0x0070, 0x10, 3, 1), -+ PIN_FIELD_BASE(73, 73, 7, 0x0070, 0x10, 4, 1), -+ PIN_FIELD_BASE(74, 74, 7, 0x0070, 0x10, 5, 1), -+ PIN_FIELD_BASE(75, 75, 7, 0x0070, 0x10, 6, 1), -+ PIN_FIELD_BASE(76, 76, 7, 0x0070, 0x10, 7, 1), -+ PIN_FIELD_BASE(77, 77, 7, 0x0070, 0x10, 8, 1), -+ PIN_FIELD_BASE(78, 78, 7, 0x0070, 0x10, 9, 1), -+ PIN_FIELD_BASE(79, 79, 7, 0x0070, 0x10, 10, 1), -+ PIN_FIELD_BASE(80, 80, 7, 0x0070, 0x10, 11, 1), -+ PIN_FIELD_BASE(81, 81, 7, 0x0070, 0x10, 12, 1), -+ PIN_FIELD_BASE(82, 82, 7, 0x0070, 0x10, 13, 1), -+ PIN_FIELD_BASE(83, 83, 7, 0x0070, 0x10, 14, 1), -+ PIN_FIELD_BASE(84, 84, 7, 0x0070, 0x10, 15, 1), -+ PIN_FIELD_BASE(85, 85, 7, 0x0070, 0x10, 16, 1), -+ PIN_FIELD_BASE(86, 86, 7, 0x0070, 0x10, 17, 1), -+ PIN_FIELD_BASE(87, 87, 7, 0x0070, 0x10, 18, 1), -+ PIN_FIELD_BASE(88, 88, 7, 0x0070, 0x10, 19, 1), -+ PIN_FIELD_BASE(89, 89, 7, 0x0070, 0x10, 20, 1), -+ PIN_FIELD_BASE(90, 90, 7, 0x0070, 0x10, 21, 1), -+ PIN_FIELD_BASE(91, 91, 7, 0x0070, 0x10, 22, 1), -+ PIN_FIELD_BASE(92, 92, 3, 0x0080, 0x10, 16, 1), -+ PIN_FIELD_BASE(93, 93, 3, 0x0080, 0x10, 17, 1), -+ PIN_FIELD_BASE(94, 94, 3, 0x0080, 0x10, 18, 1), -+ PIN_FIELD_BASE(95, 95, 3, 0x0080, 0x10, 19, 1), -+ PIN_FIELD_BASE(96, 96, 3, 0x0080, 0x10, 20, 1), -+ PIN_FIELD_BASE(97, 97, 3, 0x0080, 0x10, 21, 1), -+ PIN_FIELD_BASE(98, 98, 3, 0x0080, 0x10, 22, 1), -+ PIN_FIELD_BASE(99, 99, 3, 0x0080, 0x10, 23, 1), -+ PIN_FIELD_BASE(100, 100, 3, 0x0080, 0x10, 24, 1), -+ PIN_FIELD_BASE(101, 101, 3, 0x0080, 0x10, 25, 1), -+ PIN_FIELD_BASE(102, 102, 3, 0x0080, 0x10, 26, 1), -+ PIN_FIELD_BASE(103, 103, 3, 0x0080, 0x10, 27, 1), -+ PIN_FIELD_BASE(104, 104, 3, 0x0080, 0x10, 28, 1), -+ PIN_FIELD_BASE(105, 105, 3, 0x0080, 0x10, 29, 1), -+ PIN_FIELD_BASE(106, 106, 8, 0x0050, 0x10, 8, 1), -+ PIN_FIELD_BASE(107, 107, 8, 0x0050, 0x10, 9, 1), -+ PIN_FIELD_BASE(108, 108, 8, 0x0050, 0x10, 10, 1), -+ PIN_FIELD_BASE(109, 109, 8, 0x0050, 0x10, 11, 1), -+ PIN_FIELD_BASE(110, 110, 8, 0x0050, 0x10, 12, 1), -+ PIN_FIELD_BASE(111, 111, 8, 0x0050, 0x10, 13, 1), -+ PIN_FIELD_BASE(112, 112, 5, 0x0060, 0x10, 15, 1), -+ PIN_FIELD_BASE(113, 113, 5, 0x0060, 0x10, 16, 1), -+ PIN_FIELD_BASE(114, 114, 5, 0x0060, 0x10, 17, 1), -+ PIN_FIELD_BASE(115, 115, 5, 0x0060, 0x10, 18, 1), -+ PIN_FIELD_BASE(116, 116, 5, 0x0060, 0x10, 19, 1), -+ PIN_FIELD_BASE(117, 117, 4, 0x0060, 0x10, 8, 1), -+ PIN_FIELD_BASE(118, 118, 4, 0x0060, 0x10, 9, 1), -+ PIN_FIELD_BASE(119, 119, 4, 0x0060, 0x10, 10, 1), -+ PIN_FIELD_BASE(120, 120, 4, 0x0060, 0x10, 11, 1), -+ PIN_FIELD_BASE(121, 121, 4, 0x0060, 0x10, 12, 1), -+ PIN_FIELD_BASE(122, 122, 4, 0x0060, 0x10, 13, 1), -+ PIN_FIELD_BASE(123, 123, 4, 0x0060, 0x10, 14, 1), -+ PIN_FIELD_BASE(124, 124, 4, 0x0060, 0x10, 15, 1), -+ PIN_FIELD_BASE(125, 125, 4, 0x0060, 0x10, 16, 1), -+ PIN_FIELD_BASE(126, 126, 5, 0x0060, 0x10, 6, 1), -+ PIN_FIELD_BASE(127, 127, 5, 0x0060, 0x10, 7, 1), -+ PIN_FIELD_BASE(128, 128, 5, 0x0060, 0x10, 8, 1), -+ PIN_FIELD_BASE(129, 129, 5, 0x0060, 0x10, 9, 1), -+ PIN_FIELD_BASE(130, 130, 4, 0x0060, 0x10, 17, 1), -+ PIN_FIELD_BASE(131, 131, 4, 0x0060, 0x10, 18, 1), -+ PIN_FIELD_BASE(132, 132, 4, 0x0060, 0x10, 19, 1), -+ PIN_FIELD_BASE(133, 133, 4, 0x0060, 0x10, 20, 1), -+ PIN_FIELD_BASE(134, 134, 3, 0x0080, 0x10, 0, 1), -+ PIN_FIELD_BASE(135, 135, 3, 0x0080, 0x10, 1, 1), -+ PIN_FIELD_BASE(136, 136, 3, 0x0080, 0x10, 2, 1), -+ PIN_FIELD_BASE(137, 137, 3, 0x0080, 0x10, 3, 1), -+ PIN_FIELD_BASE(138, 138, 3, 0x0080, 0x10, 4, 1), -+ PIN_FIELD_BASE(139, 139, 3, 0x0080, 0x10, 5, 1), -+ PIN_FIELD_BASE(140, 140, 3, 0x0080, 0x10, 6, 1), -+ PIN_FIELD_BASE(141, 141, 3, 0x0080, 0x10, 7, 1), -+ PIN_FIELD_BASE(142, 142, 3, 0x0080, 0x10, 8, 1), -+ PIN_FIELD_BASE(143, 143, 3, 0x0080, 0x10, 9, 1), -+ PIN_FIELD_BASE(144, 144, 3, 0x0080, 0x10, 10, 1), -+ PIN_FIELD_BASE(145, 145, 3, 0x0080, 0x10, 11, 1), -+ PIN_FIELD_BASE(146, 146, 3, 0x0080, 0x10, 12, 1), -+ PIN_FIELD_BASE(147, 147, 3, 0x0080, 0x10, 13, 1), -+ PIN_FIELD_BASE(148, 148, 3, 0x0080, 0x10, 14, 1), -+ PIN_FIELD_BASE(149, 149, 3, 0x0080, 0x10, 15, 1), -+ PIN_FIELD_BASE(150, 150, 4, 0x0060, 0x10, 21, 1), -+ PIN_FIELD_BASE(151, 151, 4, 0x0060, 0x10, 26, 1), -+ PIN_FIELD_BASE(152, 152, 4, 0x0060, 0x10, 25, 1), -+ PIN_FIELD_BASE(153, 153, 4, 0x0060, 0x10, 24, 1), -+ PIN_FIELD_BASE(154, 154, 4, 0x0060, 0x10, 22, 1), -+ PIN_FIELD_BASE(155, 155, 4, 0x0060, 0x10, 23, 1), -+ PIN_FIELD_BASE(156, 156, 4, 0x0060, 0x10, 0, 1), -+ PIN_FIELD_BASE(157, 157, 4, 0x0060, 0x10, 1, 1), -+ PIN_FIELD_BASE(158, 158, 4, 0x0060, 0x10, 2, 1), -+ PIN_FIELD_BASE(159, 159, 4, 0x0060, 0x10, 3, 1), -+ PIN_FIELD_BASE(160, 160, 4, 0x0060, 0x10, 4, 1), -+ PIN_FIELD_BASE(161, 161, 4, 0x0060, 0x10, 5, 1), -+ PIN_FIELD_BASE(162, 162, 4, 0x0060, 0x10, 6, 1), -+ PIN_FIELD_BASE(163, 163, 4, 0x0060, 0x10, 7, 1), -+ PIN_FIELD_BASE(164, 164, 5, 0x0060, 0x10, 12, 1), -+ PIN_FIELD_BASE(165, 165, 5, 0x0060, 0x10, 3, 1), -+ PIN_FIELD_BASE(166, 166, 5, 0x0060, 0x10, 4, 1), -+ PIN_FIELD_BASE(167, 167, 5, 0x0060, 0x10, 2, 1), -+ PIN_FIELD_BASE(168, 168, 5, 0x0060, 0x10, 13, 1), -+ PIN_FIELD_BASE(169, 169, 5, 0x0060, 0x10, 14, 1), -+ PIN_FIELD_BASE(170, 170, 5, 0x0060, 0x10, 5, 1), -+ PIN_FIELD_BASE(171, 171, 6, 0x0050, 0x10, 0, 1), -+ PIN_FIELD_BASE(172, 172, 6, 0x0050, 0x10, 1, 1), -+ PIN_FIELD_BASE(173, 173, 6, 0x0050, 0x10, 2, 1), -+ PIN_FIELD_BASE(174, 174, 6, 0x0050, 0x10, 3, 1), -+ PIN_FIELD_BASE(175, 175, 6, 0x0050, 0x10, 4, 1), -+ PIN_FIELD_BASE(176, 176, 6, 0x0050, 0x10, 5, 1), -+ PIN_FIELD_BASE(177, 177, 6, 0x0050, 0x10, 6, 1), -+ PIN_FIELD_BASE(178, 178, 6, 0x0050, 0x10, 7, 1), -+ PIN_FIELD_BASE(179, 179, 6, 0x0050, 0x10, 8, 1), -+ PIN_FIELD_BASE(180, 180, 6, 0x0050, 0x10, 9, 1), -+ PIN_FIELD_BASE(181, 181, 10, 0x0020, 0x10, 0, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_pupd_range[] = { -+ PIN_FIELD_BASE(0, 0, 8, 0x0080, 0x10, 0, 1), -+ PIN_FIELD_BASE(1, 1, 8, 0x0080, 0x10, 1, 1), -+ PIN_FIELD_BASE(2, 2, 8, 0x0080, 0x10, 2, 1), -+ PIN_FIELD_BASE(3, 3, 8, 0x0080, 0x10, 3, 1), -+ PIN_FIELD_BASE(4, 4, 8, 0x0080, 0x10, 4, 1), -+ PIN_FIELD_BASE(5, 5, 8, 0x0080, 0x10, 5, 1), -+ PIN_FIELD_BASE(6, 6, 8, 0x0080, 0x10, 6, 1), -+ PIN_FIELD_BASE(7, 7, 8, 0x0080, 0x10, 7, 1), -+ PIN_FIELD_BASE(14, 14, 1, 0x00c0, 0x10, 14, 1), -+ PIN_FIELD_BASE(15, 15, 1, 0x00c0, 0x10, 16, 1), -+ PIN_FIELD_BASE(16, 16, 1, 0x00c0, 0x10, 17, 1), -+ PIN_FIELD_BASE(19, 19, 1, 0x00c0, 0x10, 21, 1), -+ PIN_FIELD_BASE(20, 20, 1, 0x00c0, 0x10, 22, 1), -+ PIN_FIELD_BASE(21, 21, 1, 0x00c0, 0x10, 20, 1), -+ PIN_FIELD_BASE(22, 22, 1, 0x00c0, 0x10, 19, 1), -+ PIN_FIELD_BASE(23, 23, 1, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(24, 24, 1, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(25, 25, 1, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(26, 26, 1, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(27, 27, 1, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(28, 28, 1, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(29, 29, 1, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(30, 30, 1, 0x00c0, 0x10, 7, 1), -+ PIN_FIELD_BASE(31, 31, 1, 0x00c0, 0x10, 8, 1), -+ PIN_FIELD_BASE(32, 32, 9, 0x00a0, 0x10, 0, 1), -+ PIN_FIELD_BASE(33, 33, 1, 0x00c0, 0x10, 9, 1), -+ PIN_FIELD_BASE(34, 34, 1, 0x00c0, 0x10, 10, 1), -+ PIN_FIELD_BASE(35, 35, 1, 0x00c0, 0x10, 11, 1), -+ PIN_FIELD_BASE(36, 36, 9, 0x00a0, 0x10, 6, 1), -+ PIN_FIELD_BASE(37, 37, 2, 0x00b0, 0x10, 10, 1), -+ PIN_FIELD_BASE(38, 38, 2, 0x00b0, 0x10, 11, 1), -+ PIN_FIELD_BASE(39, 39, 1, 0x00c0, 0x10, 12, 1), -+ PIN_FIELD_BASE(40, 40, 2, 0x00b0, 0x10, 0, 1), -+ PIN_FIELD_BASE(41, 41, 2, 0x00b0, 0x10, 1, 1), -+ PIN_FIELD_BASE(42, 42, 2, 0x00b0, 0x10, 2, 1), -+ PIN_FIELD_BASE(43, 43, 2, 0x00b0, 0x10, 3, 1), -+ PIN_FIELD_BASE(44, 44, 2, 0x00b0, 0x10, 4, 1), -+ PIN_FIELD_BASE(45, 45, 2, 0x00b0, 0x10, 5, 1), -+ PIN_FIELD_BASE(46, 46, 1, 0x00c0, 0x10, 13, 1), -+ PIN_FIELD_BASE(47, 47, 1, 0x00c0, 0x10, 15, 1), -+ PIN_FIELD_BASE(48, 48, 2, 0x00b0, 0x10, 6, 1), -+ PIN_FIELD_BASE(49, 49, 2, 0x00b0, 0x10, 7, 1), -+ PIN_FIELD_BASE(50, 50, 2, 0x00b0, 0x10, 8, 1), -+ PIN_FIELD_BASE(51, 51, 2, 0x00b0, 0x10, 9, 1), -+ PIN_FIELD_BASE(58, 58, 1, 0x00c0, 0x10, 18, 1), -+ PIN_FIELD_BASE(62, 62, 9, 0x00a0, 0x10, 1, 1), -+ PIN_FIELD_BASE(63, 63, 9, 0x00a0, 0x10, 2, 1), -+ PIN_FIELD_BASE(64, 64, 9, 0x00a0, 0x10, 3, 1), -+ PIN_FIELD_BASE(65, 65, 9, 0x00a0, 0x10, 4, 1), -+ PIN_FIELD_BASE(68, 68, 9, 0x00a0, 0x10, 5, 1), -+ PIN_FIELD_BASE(74, 74, 7, 0x00b0, 0x10, 0, 1), -+ PIN_FIELD_BASE(75, 75, 7, 0x00b0, 0x10, 1, 1), -+ PIN_FIELD_BASE(76, 76, 7, 0x00b0, 0x10, 2, 1), -+ PIN_FIELD_BASE(77, 77, 7, 0x00b0, 0x10, 3, 1), -+ PIN_FIELD_BASE(78, 78, 7, 0x00b0, 0x10, 4, 1), -+ PIN_FIELD_BASE(79, 79, 7, 0x00b0, 0x10, 5, 1), -+ PIN_FIELD_BASE(80, 80, 7, 0x00b0, 0x10, 6, 1), -+ PIN_FIELD_BASE(81, 81, 7, 0x00b0, 0x10, 7, 1), -+ PIN_FIELD_BASE(82, 82, 7, 0x00b0, 0x10, 8, 1), -+ PIN_FIELD_BASE(83, 83, 7, 0x00b0, 0x10, 9, 1), -+ PIN_FIELD_BASE(84, 84, 7, 0x00b0, 0x10, 10, 1), -+ PIN_FIELD_BASE(85, 85, 7, 0x00b0, 0x10, 11, 1), -+ PIN_FIELD_BASE(86, 86, 7, 0x00b0, 0x10, 12, 1), -+ PIN_FIELD_BASE(87, 87, 7, 0x00b0, 0x10, 13, 1), -+ PIN_FIELD_BASE(90, 90, 7, 0x00b0, 0x10, 14, 1), -+ PIN_FIELD_BASE(91, 91, 7, 0x00b0, 0x10, 15, 1), -+ PIN_FIELD_BASE(94, 94, 3, 0x00c0, 0x10, 12, 1), -+ PIN_FIELD_BASE(95, 95, 3, 0x00c0, 0x10, 13, 1), -+ PIN_FIELD_BASE(96, 96, 3, 0x00c0, 0x10, 14, 1), -+ PIN_FIELD_BASE(97, 97, 3, 0x00c0, 0x10, 15, 1), -+ PIN_FIELD_BASE(98, 98, 3, 0x00c0, 0x10, 16, 1), -+ PIN_FIELD_BASE(99, 99, 3, 0x00c0, 0x10, 17, 1), -+ PIN_FIELD_BASE(100, 100, 3, 0x00c0, 0x10, 18, 1), -+ PIN_FIELD_BASE(101, 101, 3, 0x00c0, 0x10, 19, 1), -+ PIN_FIELD_BASE(102, 102, 3, 0x00c0, 0x10, 20, 1), -+ PIN_FIELD_BASE(103, 103, 3, 0x00c0, 0x10, 21, 1), -+ PIN_FIELD_BASE(104, 104, 3, 0x00c0, 0x10, 22, 1), -+ PIN_FIELD_BASE(105, 105, 3, 0x00c0, 0x10, 23, 1), -+ PIN_FIELD_BASE(106, 106, 8, 0x0080, 0x10, 8, 1), -+ PIN_FIELD_BASE(107, 107, 8, 0x0080, 0x10, 9, 1), -+ PIN_FIELD_BASE(108, 108, 8, 0x0080, 0x10, 10, 1), -+ PIN_FIELD_BASE(109, 109, 8, 0x0080, 0x10, 11, 1), -+ PIN_FIELD_BASE(110, 110, 8, 0x0080, 0x10, 12, 1), -+ PIN_FIELD_BASE(111, 111, 8, 0x0080, 0x10, 13, 1), -+ PIN_FIELD_BASE(112, 112, 5, 0x00a0, 0x10, 5, 1), -+ PIN_FIELD_BASE(113, 113, 5, 0x00a0, 0x10, 6, 1), -+ PIN_FIELD_BASE(114, 114, 5, 0x00a0, 0x10, 7, 1), -+ PIN_FIELD_BASE(115, 115, 5, 0x00a0, 0x10, 8, 1), -+ PIN_FIELD_BASE(116, 116, 5, 0x00a0, 0x10, 9, 1), -+ PIN_FIELD_BASE(125, 125, 4, 0x00a0, 0x10, 8, 1), -+ PIN_FIELD_BASE(130, 130, 4, 0x00a0, 0x10, 9, 1), -+ PIN_FIELD_BASE(131, 131, 4, 0x00a0, 0x10, 10, 1), -+ PIN_FIELD_BASE(132, 132, 4, 0x00a0, 0x10, 11, 1), -+ PIN_FIELD_BASE(133, 133, 4, 0x00a0, 0x10, 12, 1), -+ PIN_FIELD_BASE(138, 138, 3, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(139, 139, 3, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(140, 140, 3, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(141, 141, 3, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(142, 142, 3, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(143, 143, 3, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(144, 144, 3, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(145, 145, 3, 0x00c0, 0x10, 7, 1), -+ PIN_FIELD_BASE(146, 146, 3, 0x00c0, 0x10, 8, 1), -+ PIN_FIELD_BASE(147, 147, 3, 0x00c0, 0x10, 9, 1), -+ PIN_FIELD_BASE(148, 148, 3, 0x00c0, 0x10, 10, 1), -+ PIN_FIELD_BASE(149, 149, 3, 0x00c0, 0x10, 11, 1), -+ PIN_FIELD_BASE(150, 150, 4, 0x00a0, 0x10, 13, 1), -+ PIN_FIELD_BASE(151, 151, 4, 0x00a0, 0x10, 18, 1), -+ PIN_FIELD_BASE(152, 152, 4, 0x00a0, 0x10, 17, 1), -+ PIN_FIELD_BASE(153, 153, 4, 0x00a0, 0x10, 16, 1), -+ PIN_FIELD_BASE(154, 154, 4, 0x00a0, 0x10, 14, 1), -+ PIN_FIELD_BASE(155, 155, 4, 0x00a0, 0x10, 15, 1), -+ PIN_FIELD_BASE(156, 156, 4, 0x00a0, 0x10, 0, 1), -+ PIN_FIELD_BASE(157, 157, 4, 0x00a0, 0x10, 1, 1), -+ PIN_FIELD_BASE(158, 158, 4, 0x00a0, 0x10, 2, 1), -+ PIN_FIELD_BASE(159, 159, 4, 0x00a0, 0x10, 3, 1), -+ PIN_FIELD_BASE(160, 160, 4, 0x00a0, 0x10, 4, 1), -+ PIN_FIELD_BASE(161, 161, 4, 0x00a0, 0x10, 5, 1), -+ PIN_FIELD_BASE(162, 162, 4, 0x00a0, 0x10, 6, 1), -+ PIN_FIELD_BASE(163, 163, 4, 0x00a0, 0x10, 7, 1), -+ PIN_FIELD_BASE(164, 164, 5, 0x00a0, 0x10, 2, 1), -+ PIN_FIELD_BASE(167, 167, 5, 0x00a0, 0x10, 0, 1), -+ PIN_FIELD_BASE(168, 168, 5, 0x00a0, 0x10, 3, 1), -+ PIN_FIELD_BASE(169, 169, 5, 0x00a0, 0x10, 4, 1), -+ PIN_FIELD_BASE(170, 170, 5, 0x00a0, 0x10, 1, 1), -+ PIN_FIELD_BASE(171, 171, 6, 0x0080, 0x10, 0, 1), -+ PIN_FIELD_BASE(172, 172, 6, 0x0080, 0x10, 1, 1), -+ PIN_FIELD_BASE(173, 173, 6, 0x0080, 0x10, 2, 1), -+ PIN_FIELD_BASE(174, 174, 6, 0x0080, 0x10, 3, 1), -+ PIN_FIELD_BASE(175, 175, 6, 0x0080, 0x10, 4, 1), -+ PIN_FIELD_BASE(176, 176, 6, 0x0080, 0x10, 5, 1), -+ PIN_FIELD_BASE(177, 177, 6, 0x0080, 0x10, 6, 1), -+ PIN_FIELD_BASE(178, 178, 6, 0x0080, 0x10, 7, 1), -+ PIN_FIELD_BASE(179, 179, 6, 0x0080, 0x10, 8, 1), -+ PIN_FIELD_BASE(180, 180, 6, 0x0080, 0x10, 9, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_r0_range[] = { -+ PIN_FIELD_BASE(0, 0, 8, 0x0090, 0x10, 0, 1), -+ PIN_FIELD_BASE(1, 1, 8, 0x0090, 0x10, 1, 1), -+ PIN_FIELD_BASE(2, 2, 8, 0x0090, 0x10, 2, 1), -+ PIN_FIELD_BASE(3, 3, 8, 0x0090, 0x10, 3, 1), -+ PIN_FIELD_BASE(4, 4, 8, 0x0090, 0x10, 4, 1), -+ PIN_FIELD_BASE(5, 5, 8, 0x0090, 0x10, 5, 1), -+ PIN_FIELD_BASE(6, 6, 8, 0x0090, 0x10, 6, 1), -+ PIN_FIELD_BASE(7, 7, 8, 0x0090, 0x10, 7, 1), -+ PIN_FIELD_BASE(14, 14, 1, 0x00e0, 0x10, 14, 1), -+ PIN_FIELD_BASE(15, 15, 1, 0x00e0, 0x10, 16, 1), -+ PIN_FIELD_BASE(16, 16, 1, 0x00e0, 0x10, 17, 1), -+ PIN_FIELD_BASE(19, 19, 1, 0x00e0, 0x10, 21, 1), -+ PIN_FIELD_BASE(20, 20, 1, 0x00e0, 0x10, 22, 1), -+ PIN_FIELD_BASE(21, 21, 1, 0x00e0, 0x10, 20, 1), -+ PIN_FIELD_BASE(22, 22, 1, 0x00e0, 0x10, 19, 1), -+ PIN_FIELD_BASE(23, 23, 1, 0x00e0, 0x10, 0, 1), -+ PIN_FIELD_BASE(24, 24, 1, 0x00e0, 0x10, 1, 1), -+ PIN_FIELD_BASE(25, 25, 1, 0x00e0, 0x10, 2, 1), -+ PIN_FIELD_BASE(26, 26, 1, 0x00e0, 0x10, 3, 1), -+ PIN_FIELD_BASE(27, 27, 1, 0x00e0, 0x10, 4, 1), -+ PIN_FIELD_BASE(28, 28, 1, 0x00e0, 0x10, 5, 1), -+ PIN_FIELD_BASE(29, 29, 1, 0x00e0, 0x10, 6, 1), -+ PIN_FIELD_BASE(30, 30, 1, 0x00e0, 0x10, 7, 1), -+ PIN_FIELD_BASE(31, 31, 1, 0x00e0, 0x10, 8, 1), -+ PIN_FIELD_BASE(32, 32, 9, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(33, 33, 1, 0x00e0, 0x10, 9, 1), -+ PIN_FIELD_BASE(34, 34, 1, 0x00e0, 0x10, 10, 1), -+ PIN_FIELD_BASE(35, 35, 1, 0x00e0, 0x10, 11, 1), -+ PIN_FIELD_BASE(36, 36, 9, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(37, 37, 2, 0x00d0, 0x10, 10, 1), -+ PIN_FIELD_BASE(38, 38, 2, 0x00d0, 0x10, 11, 1), -+ PIN_FIELD_BASE(39, 39, 1, 0x00e0, 0x10, 12, 1), -+ PIN_FIELD_BASE(40, 40, 2, 0x00d0, 0x10, 0, 1), -+ PIN_FIELD_BASE(41, 41, 2, 0x00d0, 0x10, 1, 1), -+ PIN_FIELD_BASE(42, 42, 2, 0x00d0, 0x10, 2, 1), -+ PIN_FIELD_BASE(43, 43, 2, 0x00d0, 0x10, 3, 1), -+ PIN_FIELD_BASE(44, 44, 2, 0x00d0, 0x10, 4, 1), -+ PIN_FIELD_BASE(45, 45, 2, 0x00d0, 0x10, 5, 1), -+ PIN_FIELD_BASE(46, 46, 1, 0x00e0, 0x10, 13, 1), -+ PIN_FIELD_BASE(47, 47, 1, 0x00e0, 0x10, 15, 1), -+ PIN_FIELD_BASE(48, 48, 2, 0x00d0, 0x10, 6, 1), -+ PIN_FIELD_BASE(49, 49, 2, 0x00d0, 0x10, 7, 1), -+ PIN_FIELD_BASE(50, 50, 2, 0x00d0, 0x10, 8, 1), -+ PIN_FIELD_BASE(51, 51, 2, 0x00d0, 0x10, 9, 1), -+ PIN_FIELD_BASE(58, 58, 1, 0x00e0, 0x10, 18, 1), -+ PIN_FIELD_BASE(62, 62, 9, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(63, 63, 9, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(64, 64, 9, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(65, 65, 9, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(68, 68, 9, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(74, 74, 7, 0x00d0, 0x10, 0, 1), -+ PIN_FIELD_BASE(75, 75, 7, 0x00d0, 0x10, 1, 1), -+ PIN_FIELD_BASE(76, 76, 7, 0x00d0, 0x10, 2, 1), -+ PIN_FIELD_BASE(77, 77, 7, 0x00d0, 0x10, 3, 1), -+ PIN_FIELD_BASE(78, 78, 7, 0x00d0, 0x10, 4, 1), -+ PIN_FIELD_BASE(79, 79, 7, 0x00d0, 0x10, 5, 1), -+ PIN_FIELD_BASE(80, 80, 7, 0x00d0, 0x10, 6, 1), -+ PIN_FIELD_BASE(81, 81, 7, 0x00d0, 0x10, 7, 1), -+ PIN_FIELD_BASE(82, 82, 7, 0x00d0, 0x10, 8, 1), -+ PIN_FIELD_BASE(83, 83, 7, 0x00d0, 0x10, 9, 1), -+ PIN_FIELD_BASE(84, 84, 7, 0x00d0, 0x10, 10, 1), -+ PIN_FIELD_BASE(85, 85, 7, 0x00d0, 0x10, 11, 1), -+ PIN_FIELD_BASE(86, 86, 7, 0x00d0, 0x10, 12, 1), -+ PIN_FIELD_BASE(87, 87, 7, 0x00d0, 0x10, 13, 1), -+ PIN_FIELD_BASE(90, 90, 7, 0x00d0, 0x10, 14, 1), -+ PIN_FIELD_BASE(91, 91, 7, 0x00d0, 0x10, 15, 1), -+ PIN_FIELD_BASE(94, 94, 3, 0x00e0, 0x10, 12, 1), -+ PIN_FIELD_BASE(95, 95, 3, 0x00e0, 0x10, 13, 1), -+ PIN_FIELD_BASE(96, 96, 3, 0x00e0, 0x10, 14, 1), -+ PIN_FIELD_BASE(97, 97, 3, 0x00e0, 0x10, 15, 1), -+ PIN_FIELD_BASE(98, 98, 3, 0x00e0, 0x10, 16, 1), -+ PIN_FIELD_BASE(99, 99, 3, 0x00e0, 0x10, 17, 1), -+ PIN_FIELD_BASE(100, 100, 3, 0x00e0, 0x10, 18, 1), -+ PIN_FIELD_BASE(101, 101, 3, 0x00e0, 0x10, 19, 1), -+ PIN_FIELD_BASE(102, 102, 3, 0x00e0, 0x10, 20, 1), -+ PIN_FIELD_BASE(103, 103, 3, 0x00e0, 0x10, 21, 1), -+ PIN_FIELD_BASE(104, 104, 3, 0x00e0, 0x10, 22, 1), -+ PIN_FIELD_BASE(105, 105, 3, 0x00e0, 0x10, 23, 1), -+ PIN_FIELD_BASE(106, 106, 8, 0x0090, 0x10, 8, 1), -+ PIN_FIELD_BASE(107, 107, 8, 0x0090, 0x10, 9, 1), -+ PIN_FIELD_BASE(108, 108, 8, 0x0090, 0x10, 10, 1), -+ PIN_FIELD_BASE(109, 109, 8, 0x0090, 0x10, 11, 1), -+ PIN_FIELD_BASE(110, 110, 8, 0x0090, 0x10, 12, 1), -+ PIN_FIELD_BASE(111, 111, 8, 0x0090, 0x10, 13, 1), -+ PIN_FIELD_BASE(112, 112, 5, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(113, 113, 5, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(114, 114, 5, 0x00c0, 0x10, 7, 1), -+ PIN_FIELD_BASE(115, 115, 5, 0x00c0, 0x10, 8, 1), -+ PIN_FIELD_BASE(116, 116, 5, 0x00c0, 0x10, 9, 1), -+ PIN_FIELD_BASE(125, 125, 4, 0x00c0, 0x10, 8, 1), -+ PIN_FIELD_BASE(130, 130, 4, 0x00c0, 0x10, 9, 1), -+ PIN_FIELD_BASE(131, 131, 4, 0x00c0, 0x10, 10, 1), -+ PIN_FIELD_BASE(132, 132, 4, 0x00c0, 0x10, 11, 1), -+ PIN_FIELD_BASE(133, 133, 4, 0x00c0, 0x10, 12, 1), -+ PIN_FIELD_BASE(138, 138, 3, 0x00e0, 0x10, 0, 1), -+ PIN_FIELD_BASE(139, 139, 3, 0x00e0, 0x10, 1, 1), -+ PIN_FIELD_BASE(140, 140, 3, 0x00e0, 0x10, 2, 1), -+ PIN_FIELD_BASE(141, 141, 3, 0x00e0, 0x10, 3, 1), -+ PIN_FIELD_BASE(142, 142, 3, 0x00e0, 0x10, 4, 1), -+ PIN_FIELD_BASE(143, 143, 3, 0x00e0, 0x10, 5, 1), -+ PIN_FIELD_BASE(144, 144, 3, 0x00e0, 0x10, 6, 1), -+ PIN_FIELD_BASE(145, 145, 3, 0x00e0, 0x10, 7, 1), -+ PIN_FIELD_BASE(146, 146, 3, 0x00e0, 0x10, 8, 1), -+ PIN_FIELD_BASE(147, 147, 3, 0x00e0, 0x10, 9, 1), -+ PIN_FIELD_BASE(148, 148, 3, 0x00e0, 0x10, 10, 1), -+ PIN_FIELD_BASE(149, 149, 3, 0x00e0, 0x10, 11, 1), -+ PIN_FIELD_BASE(150, 150, 4, 0x00c0, 0x10, 13, 1), -+ PIN_FIELD_BASE(151, 151, 4, 0x00c0, 0x10, 18, 1), -+ PIN_FIELD_BASE(152, 152, 4, 0x00c0, 0x10, 17, 1), -+ PIN_FIELD_BASE(153, 153, 4, 0x00c0, 0x10, 16, 1), -+ PIN_FIELD_BASE(154, 154, 4, 0x00c0, 0x10, 14, 1), -+ PIN_FIELD_BASE(155, 155, 4, 0x00c0, 0x10, 15, 1), -+ PIN_FIELD_BASE(156, 156, 4, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(157, 157, 4, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(158, 158, 4, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(159, 159, 4, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(160, 160, 4, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(161, 161, 4, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(162, 162, 4, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(163, 163, 4, 0x00c0, 0x10, 7, 1), -+ PIN_FIELD_BASE(164, 164, 5, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(167, 167, 5, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(168, 168, 5, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(169, 169, 5, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(170, 170, 5, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(171, 171, 6, 0x0090, 0x10, 0, 1), -+ PIN_FIELD_BASE(172, 172, 6, 0x0090, 0x10, 1, 1), -+ PIN_FIELD_BASE(173, 173, 6, 0x0090, 0x10, 2, 1), -+ PIN_FIELD_BASE(174, 174, 6, 0x0090, 0x10, 3, 1), -+ PIN_FIELD_BASE(175, 175, 6, 0x0090, 0x10, 4, 1), -+ PIN_FIELD_BASE(176, 176, 6, 0x0090, 0x10, 5, 1), -+ PIN_FIELD_BASE(177, 177, 6, 0x0090, 0x10, 6, 1), -+ PIN_FIELD_BASE(178, 178, 6, 0x0090, 0x10, 7, 1), -+ PIN_FIELD_BASE(179, 179, 6, 0x0090, 0x10, 8, 1), -+ PIN_FIELD_BASE(180, 180, 6, 0x0090, 0x10, 9, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_r1_range[] = { -+ PIN_FIELD_BASE(0, 0, 8, 0x00a0, 0x10, 0, 1), -+ PIN_FIELD_BASE(1, 1, 8, 0x00a0, 0x10, 1, 1), -+ PIN_FIELD_BASE(2, 2, 8, 0x00a0, 0x10, 2, 1), -+ PIN_FIELD_BASE(3, 3, 8, 0x00a0, 0x10, 3, 1), -+ PIN_FIELD_BASE(4, 4, 8, 0x00a0, 0x10, 4, 1), -+ PIN_FIELD_BASE(5, 5, 8, 0x00a0, 0x10, 5, 1), -+ PIN_FIELD_BASE(6, 6, 8, 0x00a0, 0x10, 6, 1), -+ PIN_FIELD_BASE(7, 7, 8, 0x00a0, 0x10, 7, 1), -+ PIN_FIELD_BASE(14, 14, 1, 0x00f0, 0x10, 14, 1), -+ PIN_FIELD_BASE(15, 15, 1, 0x00f0, 0x10, 16, 1), -+ PIN_FIELD_BASE(16, 16, 1, 0x00f0, 0x10, 17, 1), -+ PIN_FIELD_BASE(19, 19, 1, 0x00f0, 0x10, 21, 1), -+ PIN_FIELD_BASE(20, 20, 1, 0x00f0, 0x10, 22, 1), -+ PIN_FIELD_BASE(21, 21, 1, 0x00f0, 0x10, 20, 1), -+ PIN_FIELD_BASE(22, 22, 1, 0x00f0, 0x10, 19, 1), -+ PIN_FIELD_BASE(23, 23, 1, 0x00f0, 0x10, 0, 1), -+ PIN_FIELD_BASE(24, 24, 1, 0x00f0, 0x10, 1, 1), -+ PIN_FIELD_BASE(25, 25, 1, 0x00f0, 0x10, 2, 1), -+ PIN_FIELD_BASE(26, 26, 1, 0x00f0, 0x10, 3, 1), -+ PIN_FIELD_BASE(27, 27, 1, 0x00f0, 0x10, 4, 1), -+ PIN_FIELD_BASE(28, 28, 1, 0x00f0, 0x10, 5, 1), -+ PIN_FIELD_BASE(29, 29, 1, 0x00f0, 0x10, 6, 1), -+ PIN_FIELD_BASE(30, 30, 1, 0x00f0, 0x10, 7, 1), -+ PIN_FIELD_BASE(31, 31, 1, 0x00f0, 0x10, 8, 1), -+ PIN_FIELD_BASE(32, 32, 9, 0x00d0, 0x10, 0, 1), -+ PIN_FIELD_BASE(33, 33, 1, 0x00f0, 0x10, 9, 1), -+ PIN_FIELD_BASE(34, 34, 1, 0x00f0, 0x10, 10, 1), -+ PIN_FIELD_BASE(35, 35, 1, 0x00f0, 0x10, 11, 1), -+ PIN_FIELD_BASE(36, 36, 9, 0x00d0, 0x10, 6, 1), -+ PIN_FIELD_BASE(37, 37, 2, 0x00e0, 0x10, 10, 1), -+ PIN_FIELD_BASE(38, 38, 2, 0x00e0, 0x10, 11, 1), -+ PIN_FIELD_BASE(39, 39, 1, 0x00f0, 0x10, 12, 1), -+ PIN_FIELD_BASE(40, 40, 2, 0x00e0, 0x10, 0, 1), -+ PIN_FIELD_BASE(41, 41, 2, 0x00e0, 0x10, 1, 1), -+ PIN_FIELD_BASE(42, 42, 2, 0x00e0, 0x10, 2, 1), -+ PIN_FIELD_BASE(43, 43, 2, 0x00e0, 0x10, 3, 1), -+ PIN_FIELD_BASE(44, 44, 2, 0x00e0, 0x10, 4, 1), -+ PIN_FIELD_BASE(45, 45, 2, 0x00e0, 0x10, 5, 1), -+ PIN_FIELD_BASE(46, 46, 1, 0x00f0, 0x10, 13, 1), -+ PIN_FIELD_BASE(47, 47, 1, 0x00f0, 0x10, 15, 1), -+ PIN_FIELD_BASE(48, 48, 2, 0x00e0, 0x10, 6, 1), -+ PIN_FIELD_BASE(49, 49, 2, 0x00e0, 0x10, 7, 1), -+ PIN_FIELD_BASE(50, 50, 2, 0x00e0, 0x10, 8, 1), -+ PIN_FIELD_BASE(51, 51, 2, 0x00e0, 0x10, 9, 1), -+ PIN_FIELD_BASE(58, 58, 1, 0x00f0, 0x10, 18, 1), -+ PIN_FIELD_BASE(62, 62, 9, 0x00d0, 0x10, 1, 1), -+ PIN_FIELD_BASE(63, 63, 9, 0x00d0, 0x10, 2, 1), -+ PIN_FIELD_BASE(64, 64, 9, 0x00d0, 0x10, 3, 1), -+ PIN_FIELD_BASE(65, 65, 9, 0x00d0, 0x10, 4, 1), -+ PIN_FIELD_BASE(68, 68, 9, 0x00d0, 0x10, 5, 1), -+ PIN_FIELD_BASE(74, 74, 7, 0x00e0, 0x10, 0, 1), -+ PIN_FIELD_BASE(75, 75, 7, 0x00e0, 0x10, 1, 1), -+ PIN_FIELD_BASE(76, 76, 7, 0x00e0, 0x10, 2, 1), -+ PIN_FIELD_BASE(77, 77, 7, 0x00e0, 0x10, 3, 1), -+ PIN_FIELD_BASE(78, 78, 7, 0x00e0, 0x10, 4, 1), -+ PIN_FIELD_BASE(79, 79, 7, 0x00e0, 0x10, 5, 1), -+ PIN_FIELD_BASE(80, 80, 7, 0x00e0, 0x10, 6, 1), -+ PIN_FIELD_BASE(81, 81, 7, 0x00e0, 0x10, 7, 1), -+ PIN_FIELD_BASE(82, 82, 7, 0x00e0, 0x10, 8, 1), -+ PIN_FIELD_BASE(83, 83, 7, 0x00e0, 0x10, 9, 1), -+ PIN_FIELD_BASE(84, 84, 7, 0x00e0, 0x10, 10, 1), -+ PIN_FIELD_BASE(85, 85, 7, 0x00e0, 0x10, 11, 1), -+ PIN_FIELD_BASE(86, 86, 7, 0x00e0, 0x10, 12, 1), -+ PIN_FIELD_BASE(87, 87, 7, 0x00e0, 0x10, 13, 1), -+ PIN_FIELD_BASE(90, 90, 7, 0x00e0, 0x10, 14, 1), -+ PIN_FIELD_BASE(91, 91, 7, 0x00e0, 0x10, 15, 1), -+ PIN_FIELD_BASE(94, 94, 3, 0x00f0, 0x10, 12, 1), -+ PIN_FIELD_BASE(95, 95, 3, 0x00f0, 0x10, 13, 1), -+ PIN_FIELD_BASE(96, 96, 3, 0x00f0, 0x10, 14, 1), -+ PIN_FIELD_BASE(97, 97, 3, 0x00f0, 0x10, 15, 1), -+ PIN_FIELD_BASE(98, 98, 3, 0x00f0, 0x10, 16, 1), -+ PIN_FIELD_BASE(99, 99, 3, 0x00f0, 0x10, 17, 1), -+ PIN_FIELD_BASE(100, 100, 3, 0x00f0, 0x10, 18, 1), -+ PIN_FIELD_BASE(101, 101, 3, 0x00f0, 0x10, 19, 1), -+ PIN_FIELD_BASE(102, 102, 3, 0x00f0, 0x10, 20, 1), -+ PIN_FIELD_BASE(103, 103, 3, 0x00f0, 0x10, 21, 1), -+ PIN_FIELD_BASE(104, 104, 3, 0x00f0, 0x10, 22, 1), -+ PIN_FIELD_BASE(105, 105, 3, 0x00f0, 0x10, 23, 1), -+ PIN_FIELD_BASE(106, 106, 8, 0x00a0, 0x10, 8, 1), -+ PIN_FIELD_BASE(107, 107, 8, 0x00a0, 0x10, 9, 1), -+ PIN_FIELD_BASE(108, 108, 8, 0x00a0, 0x10, 10, 1), -+ PIN_FIELD_BASE(109, 109, 8, 0x00a0, 0x10, 11, 1), -+ PIN_FIELD_BASE(110, 110, 8, 0x00a0, 0x10, 12, 1), -+ PIN_FIELD_BASE(111, 111, 8, 0x00a0, 0x10, 13, 1), -+ PIN_FIELD_BASE(112, 112, 5, 0x00d0, 0x10, 5, 1), -+ PIN_FIELD_BASE(113, 113, 5, 0x00d0, 0x10, 6, 1), -+ PIN_FIELD_BASE(114, 114, 5, 0x00d0, 0x10, 7, 1), -+ PIN_FIELD_BASE(115, 115, 5, 0x00d0, 0x10, 8, 1), -+ PIN_FIELD_BASE(116, 116, 5, 0x00d0, 0x10, 9, 1), -+ PIN_FIELD_BASE(125, 125, 4, 0x00d0, 0x10, 8, 1), -+ PIN_FIELD_BASE(130, 130, 4, 0x00d0, 0x10, 9, 1), -+ PIN_FIELD_BASE(131, 131, 4, 0x00d0, 0x10, 10, 1), -+ PIN_FIELD_BASE(132, 132, 4, 0x00d0, 0x10, 11, 1), -+ PIN_FIELD_BASE(133, 133, 4, 0x00d0, 0x10, 12, 1), -+ PIN_FIELD_BASE(138, 138, 3, 0x00f0, 0x10, 0, 1), -+ PIN_FIELD_BASE(139, 139, 3, 0x00f0, 0x10, 1, 1), -+ PIN_FIELD_BASE(140, 140, 3, 0x00f0, 0x10, 2, 1), -+ PIN_FIELD_BASE(141, 141, 3, 0x00f0, 0x10, 3, 1), -+ PIN_FIELD_BASE(142, 142, 3, 0x00f0, 0x10, 4, 1), -+ PIN_FIELD_BASE(143, 143, 3, 0x00f0, 0x10, 5, 1), -+ PIN_FIELD_BASE(144, 144, 3, 0x00f0, 0x10, 6, 1), -+ PIN_FIELD_BASE(145, 145, 3, 0x00f0, 0x10, 7, 1), -+ PIN_FIELD_BASE(146, 146, 3, 0x00f0, 0x10, 8, 1), -+ PIN_FIELD_BASE(147, 147, 3, 0x00f0, 0x10, 9, 1), -+ PIN_FIELD_BASE(148, 148, 3, 0x00f0, 0x10, 10, 1), -+ PIN_FIELD_BASE(149, 149, 3, 0x00f0, 0x10, 11, 1), -+ PIN_FIELD_BASE(150, 150, 4, 0x00d0, 0x10, 13, 1), -+ PIN_FIELD_BASE(151, 151, 4, 0x00d0, 0x10, 18, 1), -+ PIN_FIELD_BASE(152, 152, 4, 0x00d0, 0x10, 17, 1), -+ PIN_FIELD_BASE(153, 153, 4, 0x00d0, 0x10, 16, 1), -+ PIN_FIELD_BASE(154, 154, 4, 0x00d0, 0x10, 14, 1), -+ PIN_FIELD_BASE(155, 155, 4, 0x00d0, 0x10, 15, 1), -+ PIN_FIELD_BASE(156, 156, 4, 0x00d0, 0x10, 0, 1), -+ PIN_FIELD_BASE(157, 157, 4, 0x00d0, 0x10, 1, 1), -+ PIN_FIELD_BASE(158, 158, 4, 0x00d0, 0x10, 2, 1), -+ PIN_FIELD_BASE(159, 159, 4, 0x00d0, 0x10, 3, 1), -+ PIN_FIELD_BASE(160, 160, 4, 0x00d0, 0x10, 4, 1), -+ PIN_FIELD_BASE(161, 161, 4, 0x00d0, 0x10, 5, 1), -+ PIN_FIELD_BASE(162, 162, 4, 0x00d0, 0x10, 6, 1), -+ PIN_FIELD_BASE(163, 163, 4, 0x00d0, 0x10, 7, 1), -+ PIN_FIELD_BASE(164, 164, 5, 0x00d0, 0x10, 2, 1), -+ PIN_FIELD_BASE(167, 167, 5, 0x00d0, 0x10, 0, 1), -+ PIN_FIELD_BASE(168, 168, 5, 0x00d0, 0x10, 3, 1), -+ PIN_FIELD_BASE(169, 169, 5, 0x00d0, 0x10, 4, 1), -+ PIN_FIELD_BASE(170, 170, 5, 0x00d0, 0x10, 1, 1), -+ PIN_FIELD_BASE(171, 171, 6, 0x00a0, 0x10, 0, 1), -+ PIN_FIELD_BASE(172, 172, 6, 0x00a0, 0x10, 1, 1), -+ PIN_FIELD_BASE(173, 173, 6, 0x00a0, 0x10, 2, 1), -+ PIN_FIELD_BASE(174, 174, 6, 0x00a0, 0x10, 3, 1), -+ PIN_FIELD_BASE(175, 175, 6, 0x00a0, 0x10, 4, 1), -+ PIN_FIELD_BASE(176, 176, 6, 0x00a0, 0x10, 5, 1), -+ PIN_FIELD_BASE(177, 177, 6, 0x00a0, 0x10, 6, 1), -+ PIN_FIELD_BASE(178, 178, 6, 0x00a0, 0x10, 7, 1), -+ PIN_FIELD_BASE(179, 179, 6, 0x00a0, 0x10, 8, 1), -+ PIN_FIELD_BASE(180, 180, 6, 0x00a0, 0x10, 9, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_pu_range[] = { -+ PIN_FIELD_BASE(8, 8, 2, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(9, 9, 2, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(10, 10, 2, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(11, 11, 2, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(12, 12, 1, 0x00d0, 0x10, 0, 1), -+ PIN_FIELD_BASE(13, 13, 1, 0x00d0, 0x10, 1, 1), -+ PIN_FIELD_BASE(17, 17, 1, 0x00d0, 0x10, 2, 1), -+ PIN_FIELD_BASE(18, 18, 1, 0x00d0, 0x10, 3, 1), -+ PIN_FIELD_BASE(52, 52, 2, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(53, 53, 2, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(54, 54, 5, 0x00b0, 0x10, 8, 1), -+ PIN_FIELD_BASE(55, 55, 5, 0x00b0, 0x10, 9, 1), -+ PIN_FIELD_BASE(56, 56, 1, 0x00d0, 0x10, 4, 1), -+ PIN_FIELD_BASE(57, 57, 1, 0x00d0, 0x10, 5, 1), -+ PIN_FIELD_BASE(59, 59, 2, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(60, 60, 9, 0x00b0, 0x10, 0, 1), -+ PIN_FIELD_BASE(61, 61, 9, 0x00b0, 0x10, 1, 1), -+ PIN_FIELD_BASE(66, 66, 5, 0x00b0, 0x10, 0, 1), -+ PIN_FIELD_BASE(67, 67, 5, 0x00b0, 0x10, 1, 1), -+ PIN_FIELD_BASE(69, 69, 7, 0x00c0, 0x10, 0, 1), -+ PIN_FIELD_BASE(70, 70, 7, 0x00c0, 0x10, 1, 1), -+ PIN_FIELD_BASE(71, 71, 7, 0x00c0, 0x10, 2, 1), -+ PIN_FIELD_BASE(72, 72, 7, 0x00c0, 0x10, 3, 1), -+ PIN_FIELD_BASE(73, 73, 7, 0x00c0, 0x10, 4, 1), -+ PIN_FIELD_BASE(88, 88, 7, 0x00c0, 0x10, 5, 1), -+ PIN_FIELD_BASE(89, 89, 7, 0x00c0, 0x10, 6, 1), -+ PIN_FIELD_BASE(92, 92, 3, 0x00d0, 0x10, 4, 1), -+ PIN_FIELD_BASE(93, 93, 3, 0x00d0, 0x10, 5, 1), -+ PIN_FIELD_BASE(117, 117, 4, 0x00b0, 0x10, 0, 1), -+ PIN_FIELD_BASE(118, 118, 4, 0x00b0, 0x10, 1, 1), -+ PIN_FIELD_BASE(119, 119, 4, 0x00b0, 0x10, 2, 1), -+ PIN_FIELD_BASE(120, 120, 4, 0x00b0, 0x10, 3, 1), -+ PIN_FIELD_BASE(121, 121, 4, 0x00b0, 0x10, 4, 1), -+ PIN_FIELD_BASE(122, 122, 4, 0x00b0, 0x10, 5, 1), -+ PIN_FIELD_BASE(123, 123, 4, 0x00b0, 0x10, 6, 1), -+ PIN_FIELD_BASE(124, 124, 4, 0x00b0, 0x10, 7, 1), -+ PIN_FIELD_BASE(126, 126, 5, 0x00b0, 0x10, 4, 1), -+ PIN_FIELD_BASE(127, 127, 5, 0x00b0, 0x10, 5, 1), -+ PIN_FIELD_BASE(128, 128, 5, 0x00b0, 0x10, 6, 1), -+ PIN_FIELD_BASE(129, 129, 5, 0x00b0, 0x10, 7, 1), -+ PIN_FIELD_BASE(134, 134, 3, 0x00d0, 0x10, 0, 1), -+ PIN_FIELD_BASE(135, 135, 3, 0x00d0, 0x10, 1, 1), -+ PIN_FIELD_BASE(136, 136, 3, 0x00d0, 0x10, 2, 1), -+ PIN_FIELD_BASE(137, 137, 3, 0x00d0, 0x10, 3, 1), -+ PIN_FIELD_BASE(165, 165, 5, 0x00b0, 0x10, 2, 1), -+ PIN_FIELD_BASE(166, 166, 5, 0x00b0, 0x10, 3, 1), -+ PIN_FIELD_BASE(181, 181, 10, 0x0060, 0x10, 0, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_pd_range[] = { -+ PIN_FIELD_BASE(8, 8, 2, 0x00a0, 0x10, 3, 1), -+ PIN_FIELD_BASE(9, 9, 2, 0x00a0, 0x10, 4, 1), -+ PIN_FIELD_BASE(10, 10, 2, 0x00a0, 0x10, 5, 1), -+ PIN_FIELD_BASE(11, 11, 2, 0x00a0, 0x10, 6, 1), -+ PIN_FIELD_BASE(12, 12, 1, 0x00b0, 0x10, 0, 1), -+ PIN_FIELD_BASE(13, 13, 1, 0x00b0, 0x10, 1, 1), -+ PIN_FIELD_BASE(17, 17, 1, 0x00b0, 0x10, 2, 1), -+ PIN_FIELD_BASE(18, 18, 1, 0x00b0, 0x10, 3, 1), -+ PIN_FIELD_BASE(52, 52, 2, 0x00a0, 0x10, 1, 1), -+ PIN_FIELD_BASE(53, 53, 2, 0x00a0, 0x10, 2, 1), -+ PIN_FIELD_BASE(54, 54, 5, 0x0090, 0x10, 8, 1), -+ PIN_FIELD_BASE(55, 55, 5, 0x0090, 0x10, 9, 1), -+ PIN_FIELD_BASE(56, 56, 1, 0x00b0, 0x10, 4, 1), -+ PIN_FIELD_BASE(57, 57, 1, 0x00b0, 0x10, 5, 1), -+ PIN_FIELD_BASE(59, 59, 2, 0x00a0, 0x10, 0, 1), -+ PIN_FIELD_BASE(60, 60, 9, 0x0090, 0x10, 0, 1), -+ PIN_FIELD_BASE(61, 61, 9, 0x0090, 0x10, 1, 1), -+ PIN_FIELD_BASE(66, 66, 5, 0x0090, 0x10, 0, 1), -+ PIN_FIELD_BASE(67, 67, 5, 0x0090, 0x10, 1, 1), -+ PIN_FIELD_BASE(69, 69, 7, 0x00a0, 0x10, 0, 1), -+ PIN_FIELD_BASE(70, 70, 7, 0x00a0, 0x10, 1, 1), -+ PIN_FIELD_BASE(71, 71, 7, 0x00a0, 0x10, 2, 1), -+ PIN_FIELD_BASE(72, 72, 7, 0x00a0, 0x10, 3, 1), -+ PIN_FIELD_BASE(73, 73, 7, 0x00a0, 0x10, 4, 1), -+ PIN_FIELD_BASE(88, 88, 7, 0x00a0, 0x10, 5, 1), -+ PIN_FIELD_BASE(89, 89, 7, 0x00a0, 0x10, 6, 1), -+ PIN_FIELD_BASE(92, 92, 3, 0x00b0, 0x10, 4, 1), -+ PIN_FIELD_BASE(93, 93, 3, 0x00b0, 0x10, 5, 1), -+ PIN_FIELD_BASE(117, 117, 4, 0x0090, 0x10, 0, 1), -+ PIN_FIELD_BASE(118, 118, 4, 0x0090, 0x10, 1, 1), -+ PIN_FIELD_BASE(119, 119, 4, 0x0090, 0x10, 2, 1), -+ PIN_FIELD_BASE(120, 120, 4, 0x0090, 0x10, 3, 1), -+ PIN_FIELD_BASE(121, 121, 4, 0x0090, 0x10, 4, 1), -+ PIN_FIELD_BASE(122, 122, 4, 0x0090, 0x10, 5, 1), -+ PIN_FIELD_BASE(123, 123, 4, 0x0090, 0x10, 6, 1), -+ PIN_FIELD_BASE(124, 124, 4, 0x0090, 0x10, 7, 1), -+ PIN_FIELD_BASE(126, 126, 5, 0x0090, 0x10, 4, 1), -+ PIN_FIELD_BASE(127, 127, 5, 0x0090, 0x10, 5, 1), -+ PIN_FIELD_BASE(128, 128, 5, 0x0090, 0x10, 6, 1), -+ PIN_FIELD_BASE(129, 129, 5, 0x0090, 0x10, 7, 1), -+ PIN_FIELD_BASE(134, 134, 3, 0x00b0, 0x10, 0, 1), -+ PIN_FIELD_BASE(135, 135, 3, 0x00b0, 0x10, 1, 1), -+ PIN_FIELD_BASE(136, 136, 3, 0x00b0, 0x10, 2, 1), -+ PIN_FIELD_BASE(137, 137, 3, 0x00b0, 0x10, 3, 1), -+ PIN_FIELD_BASE(165, 165, 5, 0x0090, 0x10, 2, 1), -+ PIN_FIELD_BASE(166, 166, 5, 0x0090, 0x10, 3, 1), -+ PIN_FIELD_BASE(181, 181, 10, 0x0050, 0x10, 0, 1), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_drv_range[] = { -+ PIN_FIELD_BASE(0, 0, 8, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(1, 1, 8, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(2, 2, 8, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(3, 3, 8, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(4, 4, 8, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(5, 5, 8, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(6, 6, 8, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(7, 7, 8, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(8, 8, 2, 0x0010, 0x10, 9, 3), -+ PIN_FIELD_BASE(9, 9, 2, 0x0010, 0x10, 12, 3), -+ PIN_FIELD_BASE(10, 10, 2, 0x0010, 0x10, 15, 3), -+ PIN_FIELD_BASE(11, 11, 2, 0x0010, 0x10, 18, 3), -+ PIN_FIELD_BASE(12, 12, 1, 0x0010, 0x10, 21, 3), -+ PIN_FIELD_BASE(13, 13, 1, 0x0010, 0x10, 24, 3), -+ PIN_FIELD_BASE(14, 14, 1, 0x0010, 0x10, 9, 3), -+ PIN_FIELD_BASE(15, 15, 1, 0x0010, 0x10, 15, 3), -+ PIN_FIELD_BASE(16, 16, 1, 0x0010, 0x10, 27, 3), -+ PIN_FIELD_BASE(17, 17, 1, 0x0020, 0x10, 0, 3), -+ PIN_FIELD_BASE(18, 18, 1, 0x0020, 0x10, 3, 3), -+ PIN_FIELD_BASE(19, 19, 1, 0x0020, 0x10, 21, 3), -+ PIN_FIELD_BASE(20, 20, 1, 0x0020, 0x10, 24, 3), -+ PIN_FIELD_BASE(21, 21, 1, 0x0020, 0x10, 18, 3), -+ PIN_FIELD_BASE(22, 22, 1, 0x0020, 0x10, 15, 3), -+ PIN_FIELD_BASE(23, 23, 1, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(24, 24, 1, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(25, 25, 1, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(26, 26, 1, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(27, 27, 1, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(28, 28, 1, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(29, 29, 1, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(30, 30, 1, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(31, 31, 1, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(32, 32, 9, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(33, 33, 1, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(34, 34, 1, 0x0010, 0x10, 0, 3), -+ PIN_FIELD_BASE(35, 35, 1, 0x0010, 0x10, 3, 3), -+ PIN_FIELD_BASE(36, 36, 9, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(37, 37, 2, 0x0010, 0x10, 21, 3), -+ PIN_FIELD_BASE(38, 38, 2, 0x0010, 0x10, 24, 3), -+ PIN_FIELD_BASE(39, 39, 1, 0x0010, 0x10, 6, 3), -+ PIN_FIELD_BASE(40, 40, 2, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(41, 41, 2, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(42, 42, 2, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(43, 43, 2, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(44, 44, 2, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(45, 45, 2, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(46, 46, 1, 0x0010, 0x10, 12, 3), -+ PIN_FIELD_BASE(47, 47, 1, 0x0010, 0x10, 18, 3), -+ PIN_FIELD_BASE(48, 48, 2, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(49, 49, 2, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(50, 50, 2, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(51, 51, 2, 0x0010, 0x10, 0, 3), -+ PIN_FIELD_BASE(52, 52, 2, 0x0010, 0x10, 3, 3), -+ PIN_FIELD_BASE(53, 53, 2, 0x0010, 0x10, 6, 3), -+ PIN_FIELD_BASE(54, 54, 5, 0x0010, 0x10, 0, 3), -+ PIN_FIELD_BASE(55, 55, 5, 0x0010, 0x10, 3, 3), -+ PIN_FIELD_BASE(56, 56, 1, 0x0020, 0x10, 6, 3), -+ PIN_FIELD_BASE(57, 57, 1, 0x0020, 0x10, 9, 3), -+ PIN_FIELD_BASE(58, 58, 1, 0x0020, 0x10, 12, 3), -+ PIN_FIELD_BASE(59, 59, 2, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(60, 60, 9, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(61, 61, 9, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(62, 62, 9, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(63, 63, 9, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(64, 64, 9, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(65, 65, 9, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(66, 66, 5, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(67, 67, 5, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(68, 68, 9, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(69, 69, 7, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(70, 70, 7, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(71, 71, 7, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(72, 72, 7, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(73, 73, 7, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(74, 74, 7, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(75, 75, 7, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(76, 76, 7, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(77, 77, 7, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(78, 78, 7, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(79, 79, 7, 0x0010, 0x10, 0, 3), -+ PIN_FIELD_BASE(80, 80, 7, 0x0010, 0x10, 3, 3), -+ PIN_FIELD_BASE(81, 81, 7, 0x0010, 0x10, 6, 3), -+ PIN_FIELD_BASE(82, 82, 7, 0x0010, 0x10, 9, 3), -+ PIN_FIELD_BASE(83, 83, 7, 0x0010, 0x10, 12, 3), -+ PIN_FIELD_BASE(84, 84, 7, 0x0010, 0x10, 15, 3), -+ PIN_FIELD_BASE(85, 85, 7, 0x0010, 0x10, 18, 3), -+ PIN_FIELD_BASE(86, 86, 7, 0x0010, 0x10, 21, 3), -+ PIN_FIELD_BASE(87, 87, 7, 0x0010, 0x10, 24, 3), -+ PIN_FIELD_BASE(88, 88, 7, 0x0010, 0x10, 27, 3), -+ PIN_FIELD_BASE(89, 89, 7, 0x0020, 0x10, 0, 3), -+ PIN_FIELD_BASE(90, 90, 7, 0x0020, 0x10, 3, 3), -+ PIN_FIELD_BASE(91, 91, 7, 0x0020, 0x10, 6, 3), -+ PIN_FIELD_BASE(92, 92, 3, 0x0010, 0x10, 18, 3), -+ PIN_FIELD_BASE(93, 93, 3, 0x0010, 0x10, 21, 3), -+ PIN_FIELD_BASE(94, 94, 3, 0x0010, 0x10, 24, 3), -+ PIN_FIELD_BASE(95, 95, 3, 0x0010, 0x10, 27, 3), -+ PIN_FIELD_BASE(96, 96, 3, 0x0020, 0x10, 0, 3), -+ PIN_FIELD_BASE(97, 97, 3, 0x0020, 0x10, 3, 3), -+ PIN_FIELD_BASE(98, 98, 3, 0x0020, 0x10, 6, 3), -+ PIN_FIELD_BASE(99, 99, 3, 0x0020, 0x10, 9, 3), -+ PIN_FIELD_BASE(100, 100, 3, 0x0020, 0x10, 12, 3), -+ PIN_FIELD_BASE(101, 101, 3, 0x0020, 0x10, 15, 3), -+ PIN_FIELD_BASE(102, 102, 3, 0x0020, 0x10, 18, 3), -+ PIN_FIELD_BASE(103, 103, 3, 0x0020, 0x10, 21, 3), -+ PIN_FIELD_BASE(104, 104, 3, 0x0020, 0x10, 24, 3), -+ PIN_FIELD_BASE(105, 105, 3, 0x0020, 0x10, 27, 3), -+ PIN_FIELD_BASE(106, 106, 8, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(107, 107, 8, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(108, 108, 8, 0x0010, 0x10, 0, 3), -+ PIN_FIELD_BASE(109, 109, 8, 0x0010, 0x10, 3, 3), -+ PIN_FIELD_BASE(110, 110, 8, 0x0010, 0x10, 6, 3), -+ PIN_FIELD_BASE(111, 111, 8, 0x0010, 0x10, 9, 3), -+ PIN_FIELD_BASE(112, 112, 5, 0x0010, 0x10, 15, 3), -+ PIN_FIELD_BASE(113, 113, 5, 0x0010, 0x10, 18, 3), -+ PIN_FIELD_BASE(114, 114, 5, 0x0010, 0x10, 21, 3), -+ PIN_FIELD_BASE(115, 115, 5, 0x0010, 0x10, 24, 3), -+ PIN_FIELD_BASE(116, 116, 5, 0x0010, 0x10, 27, 3), -+ PIN_FIELD_BASE(117, 117, 4, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(118, 118, 4, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(119, 119, 4, 0x0010, 0x10, 0, 3), -+ PIN_FIELD_BASE(120, 120, 4, 0x0010, 0x10, 3, 3), -+ PIN_FIELD_BASE(121, 121, 4, 0x0010, 0x10, 6, 3), -+ PIN_FIELD_BASE(122, 122, 4, 0x0010, 0x10, 9, 3), -+ PIN_FIELD_BASE(123, 123, 4, 0x0010, 0x10, 12, 3), -+ PIN_FIELD_BASE(124, 124, 4, 0x0010, 0x10, 15, 3), -+ PIN_FIELD_BASE(125, 125, 4, 0x0010, 0x10, 18, 3), -+ PIN_FIELD_BASE(126, 126, 5, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(127, 127, 5, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(128, 128, 5, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(129, 129, 5, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(130, 130, 4, 0x0010, 0x10, 21, 3), -+ PIN_FIELD_BASE(131, 131, 4, 0x0010, 0x10, 24, 3), -+ PIN_FIELD_BASE(132, 132, 4, 0x0010, 0x10, 27, 3), -+ PIN_FIELD_BASE(133, 133, 4, 0x0020, 0x10, 0, 3), -+ PIN_FIELD_BASE(134, 134, 3, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(135, 135, 3, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(136, 136, 3, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(137, 137, 3, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(138, 138, 3, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(139, 139, 3, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(140, 140, 3, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(141, 141, 3, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(142, 142, 3, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(143, 143, 3, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(144, 144, 3, 0x0010, 0x10, 0, 3), -+ PIN_FIELD_BASE(145, 145, 3, 0x0010, 0x10, 3, 3), -+ PIN_FIELD_BASE(146, 146, 3, 0x0010, 0x10, 6, 3), -+ PIN_FIELD_BASE(147, 147, 3, 0x0010, 0x10, 9, 3), -+ PIN_FIELD_BASE(148, 148, 3, 0x0010, 0x10, 12, 3), -+ PIN_FIELD_BASE(149, 149, 3, 0x0010, 0x10, 15, 3), -+ PIN_FIELD_BASE(150, 150, 4, 0x0020, 0x10, 3, 3), -+ PIN_FIELD_BASE(151, 151, 4, 0x0020, 0x10, 18, 3), -+ PIN_FIELD_BASE(152, 152, 4, 0x0020, 0x10, 15, 3), -+ PIN_FIELD_BASE(153, 153, 4, 0x0020, 0x10, 12, 3), -+ PIN_FIELD_BASE(154, 154, 4, 0x0020, 0x10, 6, 3), -+ PIN_FIELD_BASE(155, 155, 4, 0x0020, 0x10, 9, 3), -+ PIN_FIELD_BASE(156, 156, 4, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(157, 157, 4, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(158, 158, 4, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(159, 159, 4, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(160, 160, 4, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(161, 161, 4, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(162, 162, 4, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(163, 163, 4, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(164, 164, 5, 0x0010, 0x10, 6, 3), -+ PIN_FIELD_BASE(165, 165, 5, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(166, 166, 5, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(167, 167, 5, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(168, 168, 5, 0x0010, 0x10, 9, 3), -+ PIN_FIELD_BASE(169, 169, 5, 0x0010, 0x10, 12, 3), -+ PIN_FIELD_BASE(170, 170, 5, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(171, 171, 6, 0x0000, 0x10, 0, 3), -+ PIN_FIELD_BASE(172, 172, 6, 0x0000, 0x10, 3, 3), -+ PIN_FIELD_BASE(173, 173, 6, 0x0000, 0x10, 6, 3), -+ PIN_FIELD_BASE(174, 174, 6, 0x0000, 0x10, 9, 3), -+ PIN_FIELD_BASE(175, 175, 6, 0x0000, 0x10, 12, 3), -+ PIN_FIELD_BASE(176, 176, 6, 0x0000, 0x10, 15, 3), -+ PIN_FIELD_BASE(177, 177, 6, 0x0000, 0x10, 18, 3), -+ PIN_FIELD_BASE(178, 178, 6, 0x0000, 0x10, 21, 3), -+ PIN_FIELD_BASE(179, 179, 6, 0x0000, 0x10, 24, 3), -+ PIN_FIELD_BASE(180, 180, 6, 0x0000, 0x10, 27, 3), -+ PIN_FIELD_BASE(181, 181, 10, 0x0000, 0x10, 0, 3), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_drv_adv_range[] = { -+ PIN_FIELD_BASE(8, 8, 2, 0x0030, 0x10, 6, 3), -+ PIN_FIELD_BASE(9, 9, 2, 0x0030, 0x10, 9, 3), -+ PIN_FIELD_BASE(10, 10, 2, 0x0030, 0x10, 12, 3), -+ PIN_FIELD_BASE(11, 11, 2, 0x0030, 0x10, 15, 3), -+ PIN_FIELD_BASE(12, 12, 1, 0x0040, 0x10, 0, 3), -+ PIN_FIELD_BASE(13, 13, 1, 0x0040, 0x10, 3, 3), -+ PIN_FIELD_BASE(17, 17, 1, 0x0040, 0x10, 6, 3), -+ PIN_FIELD_BASE(18, 18, 1, 0x0040, 0x10, 9, 3), -+ PIN_FIELD_BASE(52, 52, 2, 0x0030, 0x10, 0, 3), -+ PIN_FIELD_BASE(53, 53, 2, 0x0030, 0x10, 3, 3), -+ PIN_FIELD_BASE(54, 54, 5, 0x0030, 0x10, 24, 3), -+ PIN_FIELD_BASE(55, 55, 5, 0x0030, 0x10, 27, 3), -+ PIN_FIELD_BASE(56, 56, 1, 0x0040, 0x10, 12, 3), -+ PIN_FIELD_BASE(57, 57, 1, 0x0040, 0x10, 15, 3), -+ PIN_FIELD_BASE(60, 60, 9, 0x0020, 0x10, 0, 3), -+ PIN_FIELD_BASE(61, 61, 9, 0x0020, 0x10, 3, 3), -+ PIN_FIELD_BASE(66, 66, 5, 0x0030, 0x10, 0, 3), -+ PIN_FIELD_BASE(67, 67, 5, 0x0030, 0x10, 3, 3), -+ PIN_FIELD_BASE(70, 70, 7, 0x0030, 0x10, 0, 3), -+ PIN_FIELD_BASE(71, 71, 7, 0x0030, 0x10, 3, 3), -+ PIN_FIELD_BASE(72, 72, 7, 0x0030, 0x10, 6, 3), -+ PIN_FIELD_BASE(73, 73, 7, 0x0030, 0x10, 9, 3), -+ PIN_FIELD_BASE(88, 88, 7, 0x0030, 0x10, 12, 3), -+ PIN_FIELD_BASE(89, 89, 7, 0x0030, 0x10, 15, 3), -+ PIN_FIELD_BASE(92, 92, 3, 0x0040, 0x10, 12, 3), -+ PIN_FIELD_BASE(93, 93, 3, 0x0040, 0x10, 15, 3), -+ PIN_FIELD_BASE(117, 117, 4, 0x0030, 0x10, 0, 3), -+ PIN_FIELD_BASE(118, 118, 4, 0x0030, 0x10, 3, 3), -+ PIN_FIELD_BASE(119, 119, 4, 0x0030, 0x10, 6, 3), -+ PIN_FIELD_BASE(120, 120, 4, 0x0030, 0x10, 9, 3), -+ PIN_FIELD_BASE(121, 121, 4, 0x0030, 0x10, 12, 3), -+ PIN_FIELD_BASE(122, 122, 4, 0x0030, 0x10, 15, 3), -+ PIN_FIELD_BASE(123, 123, 4, 0x0030, 0x10, 18, 3), -+ PIN_FIELD_BASE(124, 124, 4, 0x0030, 0x10, 21, 3), -+ PIN_FIELD_BASE(126, 126, 5, 0x0030, 0x10, 12, 3), -+ PIN_FIELD_BASE(127, 127, 5, 0x0030, 0x10, 15, 3), -+ PIN_FIELD_BASE(128, 128, 5, 0x0030, 0x10, 18, 3), -+ PIN_FIELD_BASE(129, 129, 5, 0x0030, 0x10, 21, 3), -+ PIN_FIELD_BASE(134, 134, 3, 0x0040, 0x10, 0, 3), -+ PIN_FIELD_BASE(135, 135, 3, 0x0040, 0x10, 3, 3), -+ PIN_FIELD_BASE(136, 136, 3, 0x0040, 0x10, 6, 3), -+ PIN_FIELD_BASE(137, 137, 3, 0x0040, 0x10, 9, 3), -+ PIN_FIELD_BASE(165, 165, 5, 0x0030, 0x10, 6, 3), -+ PIN_FIELD_BASE(166, 166, 5, 0x0030, 0x10, 9, 3), -+}; -+ -+static const struct mtk_pin_field_calc mt8901_pin_rsel_range[] = { -+ PIN_FIELD_BASE(8, 8, 2, 0x0110, 0x10, 6, 3), -+ PIN_FIELD_BASE(9, 9, 2, 0x0110, 0x10, 9, 3), -+ PIN_FIELD_BASE(10, 10, 2, 0x0110, 0x10, 12, 3), -+ PIN_FIELD_BASE(11, 11, 2, 0x0110, 0x10, 15, 3), -+ PIN_FIELD_BASE(12, 12, 1, 0x0130, 0x10, 0, 1), -+ PIN_FIELD_BASE(13, 13, 1, 0x0130, 0x10, 1, 1), -+ PIN_FIELD_BASE(17, 17, 1, 0x0130, 0x10, 2, 1), -+ PIN_FIELD_BASE(18, 18, 1, 0x0130, 0x10, 3, 1), -+ PIN_FIELD_BASE(52, 52, 2, 0x0110, 0x10, 0, 3), -+ PIN_FIELD_BASE(53, 53, 2, 0x0110, 0x10, 3, 3), -+ PIN_FIELD_BASE(54, 54, 5, 0x0110, 0x10, 12, 3), -+ PIN_FIELD_BASE(55, 55, 5, 0x0110, 0x10, 15, 3), -+ PIN_FIELD_BASE(56, 56, 1, 0x0130, 0x10, 4, 1), -+ PIN_FIELD_BASE(57, 57, 1, 0x0130, 0x10, 5, 1), -+ PIN_FIELD_BASE(60, 60, 9, 0x00f0, 0x10, 0, 3), -+ PIN_FIELD_BASE(61, 61, 9, 0x00f0, 0x10, 3, 3), -+ PIN_FIELD_BASE(66, 66, 5, 0x0110, 0x10, 0, 1), -+ PIN_FIELD_BASE(67, 67, 5, 0x0110, 0x10, 1, 1), -+ PIN_FIELD_BASE(70, 70, 7, 0x0100, 0x10, 0, 3), -+ PIN_FIELD_BASE(71, 71, 7, 0x0100, 0x10, 3, 3), -+ PIN_FIELD_BASE(72, 72, 7, 0x0100, 0x10, 6, 3), -+ PIN_FIELD_BASE(73, 73, 7, 0x0100, 0x10, 9, 3), -+ PIN_FIELD_BASE(88, 88, 7, 0x0100, 0x10, 12, 3), -+ PIN_FIELD_BASE(89, 89, 7, 0x0100, 0x10, 15, 3), -+ PIN_FIELD_BASE(92, 92, 3, 0x0120, 0x10, 12, 3), -+ PIN_FIELD_BASE(93, 93, 3, 0x0120, 0x10, 15, 3), -+ PIN_FIELD_BASE(117, 117, 4, 0x0100, 0x10, 0, 3), -+ PIN_FIELD_BASE(118, 118, 4, 0x0100, 0x10, 3, 3), -+ PIN_FIELD_BASE(119, 119, 4, 0x0100, 0x10, 6, 3), -+ PIN_FIELD_BASE(120, 120, 4, 0x0100, 0x10, 9, 3), -+ PIN_FIELD_BASE(121, 121, 4, 0x0100, 0x10, 12, 3), -+ PIN_FIELD_BASE(122, 122, 4, 0x0100, 0x10, 15, 3), -+ PIN_FIELD_BASE(123, 123, 4, 0x0100, 0x10, 18, 3), -+ PIN_FIELD_BASE(124, 124, 4, 0x0100, 0x10, 21, 3), -+ PIN_FIELD_BASE(126, 126, 5, 0x0110, 0x10, 8, 1), -+ PIN_FIELD_BASE(127, 127, 5, 0x0110, 0x10, 9, 1), -+ PIN_FIELD_BASE(128, 128, 5, 0x0110, 0x10, 10, 1), -+ PIN_FIELD_BASE(129, 129, 5, 0x0110, 0x10, 11, 1), -+ PIN_FIELD_BASE(134, 134, 3, 0x0120, 0x10, 0, 3), -+ PIN_FIELD_BASE(135, 135, 3, 0x0120, 0x10, 3, 3), -+ PIN_FIELD_BASE(136, 136, 3, 0x0120, 0x10, 6, 3), -+ PIN_FIELD_BASE(137, 137, 3, 0x0120, 0x10, 9, 3), -+ PIN_FIELD_BASE(165, 165, 5, 0x0110, 0x10, 2, 3), -+ PIN_FIELD_BASE(166, 166, 5, 0x0110, 0x10, 5, 3), -+}; -+ -+static const struct mtk_pin_rsel mt8901_pin_rsel_val_range[] = { -+ 0 -+}; -+ -+static const unsigned int mt8901_pull_type[] = { -+ MTK_PULL_PUPD_R1R0_TYPE, /*0*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*1*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*2*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*3*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*4*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*5*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*6*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*7*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*8*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*9*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*10*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*11*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*12*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*13*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*14*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*15*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*16*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*17*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*18*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*19*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*20*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*21*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*22*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*23*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*24*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*25*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*26*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*27*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*28*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*29*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*30*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*31*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*32*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*33*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*34*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*35*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*36*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*37*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*38*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*39*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*40*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*41*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*42*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*43*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*44*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*45*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*46*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*47*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*48*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*49*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*50*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*51*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*52*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*53*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*54*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*55*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*56*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*57*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*58*/ -+ MTK_PULL_PU_PD_TYPE, /*59*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*60*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*61*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*62*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*63*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*64*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*65*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*66*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*67*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*68*/ -+ MTK_PULL_PU_PD_TYPE, /*69*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*70*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*71*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*72*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*73*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*74*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*75*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*76*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*77*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*78*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*79*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*80*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*81*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*82*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*83*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*84*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*85*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*86*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*87*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*88*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*89*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*90*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*91*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*92*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*93*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*94*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*95*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*96*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*97*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*98*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*99*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*100*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*101*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*102*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*103*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*104*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*105*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*106*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*107*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*108*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*109*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*110*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*111*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*112*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*113*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*114*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*115*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*116*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*117*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*118*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*119*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*120*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*121*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*122*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*123*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*124*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*125*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*126*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*127*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*128*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*129*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*130*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*131*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*132*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*133*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*134*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*135*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*136*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*137*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*138*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*139*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*140*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*141*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*142*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*143*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*144*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*145*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*146*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*147*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*148*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*149*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*150*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*151*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*152*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*153*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*154*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*155*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*156*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*157*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*158*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*159*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*160*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*161*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*162*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*163*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*164*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*165*/ -+ MTK_PULL_PU_PD_RSEL_TYPE, /*166*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*167*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*168*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*169*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*170*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*171*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*172*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*173*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*174*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*175*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*176*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*177*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*178*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*179*/ -+ MTK_PULL_PUPD_R1R0_TYPE, /*180*/ -+ MTK_PULL_PU_PD_TYPE, /*181*/ -+}; -+ -+static const struct mtk_pin_reg_calc mt8901_reg_cals[PINCTRL_PIN_REG_MAX] = { -+ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt8901_pin_mode_range), -+ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8901_pin_dir_range), -+ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8901_pin_di_range), -+ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8901_pin_do_range), -+ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8901_pin_smt_range), -+ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8901_pin_ies_range), -+ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt8901_pin_pupd_range), -+ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt8901_pin_r0_range), -+ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt8901_pin_r1_range), -+ [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt8901_pin_pu_range), -+ [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt8901_pin_pd_range), -+ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt8901_pin_drv_range), -+ [PINCTRL_PIN_REG_DRV_ADV] = MTK_RANGE(mt8901_pin_drv_adv_range), -+ [PINCTRL_PIN_REG_RSEL] = MTK_RANGE(mt8901_pin_rsel_range), -+}; -+ -+static const char * const mt8901_pinctrl_register_base_name[] = { -+ "iocfg0", "iocfg_lt2", "iocfg_lt3", "iocfg_rt1", "iocfg_rt2", "iocfg_rt3", -+ "iocfg_tr", "iocfg_rt0", "iocfg_lt1", "iocfg_lb", "iocfg_rb", -+}; -+ -+static const struct mtk_eint_hw mt8901_eint_hw = { -+ .port_mask = 0xf, -+ .ports = 7, -+ .ap_num = 209, -+ .db_cnt = 32, -+ .db_time = debounce_time_mt8901, -+}; -+ -+static const struct mtk_pin_soc mt8901_data = { -+ .reg_cal = mt8901_reg_cals, -+ .pins = mtk_pins_mt8901, -+ .npins = ARRAY_SIZE(mtk_pins_mt8901), -+ .ngrps = ARRAY_SIZE(mtk_pins_mt8901), -+ .eint_hw = &mt8901_eint_hw, -+ .eint_pin = eint_pins_mt8901, -+ .nfuncs = 8, -+ .gpio_m = 0, -+ .base_names = mt8901_pinctrl_register_base_name, -+ .nbase_names = ARRAY_SIZE(mt8901_pinctrl_register_base_name), -+ .pull_type = mt8901_pull_type, -+ .pin_rsel = mt8901_pin_rsel_val_range, -+ .npin_rsel = ARRAY_SIZE(mt8901_pin_rsel_val_range), /*numsel*/ -+ .bias_set_combo = mtk_pinconf_bias_set_combo, -+ .bias_get_combo = mtk_pinconf_bias_get_combo, -+ .drive_set = mtk_pinconf_drive_set_rev1, -+ .drive_get = mtk_pinconf_drive_get_rev1, -+ .adv_drive_set = mtk_pinconf_adv_drive_set_raw, -+ .adv_drive_get = mtk_pinconf_adv_drive_get_raw, -+}; -+ -+static const struct acpi_device_id mt8901_pinctrl_acpi_match[] = { -+ {"NVDA9221", (kernel_ulong_t)&mt8901_data }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, mt8901_pinctrl_acpi_match); -+ -+static struct platform_driver mt8901_pinctrl_driver = { -+ .driver = { -+ .name = "mt8901-pinctrl", -+ .acpi_match_table = ACPI_PTR(mt8901_pinctrl_acpi_match), -+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops) -+ }, -+ .probe = mtk_paris_pinctrl_probe, -+}; -+ -+static int __init mt8901_pinctrl_init(void) -+{ -+ return platform_driver_register(&mt8901_pinctrl_driver); -+} -+ -+arch_initcall(mt8901_pinctrl_init); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("MediaTek MT8901 Pinctrl Driver"); -diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h -new file mode 100644 -index 0000000000..fc64fc6ff5 ---- /dev/null -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h -@@ -0,0 +1,2130 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2025 MediaTek Inc. -+ * -+ */ -+ -+#ifndef __PINCTRL_MTK_MT8901_H -+#define __PINCTRL_MTK_MT8901_H -+ -+#include "pinctrl-paris.h" -+ -+#define INVALID_BASE 0xFF -+ -+static const struct mtk_pin_desc mtk_pins_mt8901[] = { -+ MTK_PIN( -+ 0, "GPIO0", -+ MTK_EINT_FUNCTION(0, 0), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B:GPIO0"), -+ MTK_FUNCTION(1, "O:ESPI_SCK") -+ ), -+ MTK_PIN( -+ 1, "GPIO1", -+ MTK_EINT_FUNCTION(0, 1), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO1"), -+ MTK_FUNCTION(1, "B1_ESPI_IO0") -+ ), -+ MTK_PIN( -+ 2, "GPIO2", -+ MTK_EINT_FUNCTION(0, 2), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO2"), -+ MTK_FUNCTION(1, "B1_ESPI_IO1") -+ ), -+ MTK_PIN( -+ 3, "GPIO3", -+ MTK_EINT_FUNCTION(0, 3), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO3"), -+ MTK_FUNCTION(1, "B1_ESPI_IO2") -+ ), -+ MTK_PIN( -+ 4, "GPIO4", -+ MTK_EINT_FUNCTION(0, 4), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO4"), -+ MTK_FUNCTION(1, "B1_ESPI_IO3") -+ ), -+ MTK_PIN( -+ 5, "GPIO5", -+ MTK_EINT_FUNCTION(0, 5), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO5"), -+ MTK_FUNCTION(1, "O_ESPI_CSN") -+ ), -+ MTK_PIN( -+ 6, "GPIO6", -+ MTK_EINT_FUNCTION(0, 6), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO6"), -+ MTK_FUNCTION(1, "O_ESPI_RESET_O"), -+ MTK_FUNCTION(2, "I1_ESPI_RESET_I") -+ ), -+ MTK_PIN( -+ 7, "GPIO7", -+ MTK_EINT_FUNCTION(0, 7), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO7"), -+ MTK_FUNCTION(1, "I1_ESPI_ALERT") -+ ), -+ MTK_PIN( -+ 8, "GPIO8", -+ MTK_EINT_FUNCTION(0, 8), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO8"), -+ MTK_FUNCTION(1, "B1_I2C_SCL3"), -+ MTK_FUNCTION(2, "B1_DISP_SCL2"), -+ MTK_FUNCTION(4, "O_PMSR_SMAP"), -+ MTK_FUNCTION(6, "O_MD32_0_TXD"), -+ MTK_FUNCTION(7, "O_MD32_1_TXD") -+ ), -+ MTK_PIN( -+ 9, "GPIO9", -+ MTK_EINT_FUNCTION(0, 9), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO9"), -+ MTK_FUNCTION(1, "B1_I2C_SDA3"), -+ MTK_FUNCTION(2, "B1_DISP_SDA2"), -+ MTK_FUNCTION(4, "O_PMSR_SMAP_MAX"), -+ MTK_FUNCTION(6, "I1_MD32_0_RXD"), -+ MTK_FUNCTION(7, "I1_MD32_1_RXD") -+ ), -+ MTK_PIN( -+ 10, "GPIO10", -+ MTK_EINT_FUNCTION(0, 10), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO10"), -+ MTK_FUNCTION(1, "B1_I2C_SCL4"), -+ MTK_FUNCTION(2, "B1_DISP_SCL2"), -+ MTK_FUNCTION(4, "O_PMSR_SMAP_MAX_W"), -+ MTK_FUNCTION(6, "O_MD32_0_GPIO0"), -+ MTK_FUNCTION(7, "O_MD32_1_GPIO0") -+ ), -+ MTK_PIN( -+ 11, "GPIO11", -+ MTK_EINT_FUNCTION(0, 11), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO11"), -+ MTK_FUNCTION(1, "B1_I2C_SDA4"), -+ MTK_FUNCTION(2, "B1_DISP_SDA2") -+ ), -+ MTK_PIN( -+ 12, "GPIO12", -+ MTK_EINT_FUNCTION(0, 12), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO12"), -+ MTK_FUNCTION(1, "B0_SPMI_M_SCL"), -+ MTK_FUNCTION(2, "B0_TP_GPIO31_AO") -+ ), -+ MTK_PIN( -+ 13, "GPIO13", -+ MTK_EINT_FUNCTION(0, 13), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO13"), -+ MTK_FUNCTION(1, "B0_SPMI_M_SDA"), -+ MTK_FUNCTION(2, "B0_TP_GPIO6_AO") -+ ), -+ MTK_PIN( -+ 14, "GPIO14", -+ MTK_EINT_FUNCTION(0, 14), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO14"), -+ MTK_FUNCTION(1, "I0_DPAUX_HPD_IN_2"), -+ MTK_FUNCTION(7, "O_DBG_MON_A0") -+ ), -+ MTK_PIN( -+ 15, "GPIO15", -+ MTK_EINT_FUNCTION(0, 15), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO15"), -+ MTK_FUNCTION(1, "I0_DPAUX_HPD_IN_3"), -+ MTK_FUNCTION(2, "B0_TP_GPIO25_AO"), -+ MTK_FUNCTION(7, "O_DBG_MON_A1") -+ ), -+ MTK_PIN( -+ 16, "GPIO16", -+ MTK_EINT_FUNCTION(0, 16), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO16"), -+ MTK_FUNCTION(1, "O_USB4_L_TCPC_RESET"), -+ MTK_FUNCTION(7, "O_DBG_MON_A18") -+ ), -+ MTK_PIN( -+ 17, "GPIO17", -+ MTK_EINT_FUNCTION(0, 17), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO17"), -+ MTK_FUNCTION(1, "B0_SPMI_P_SCL") -+ ), -+ MTK_PIN( -+ 18, "GPIO18", -+ MTK_EINT_FUNCTION(0, 18), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO18"), -+ MTK_FUNCTION(1, "B0_SPMI_P_SDA") -+ ), -+ MTK_PIN( -+ 19, "GPIO19", -+ MTK_EINT_FUNCTION(0, 19), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO19"), -+ MTK_FUNCTION(1, "B0_TP_GPIO29_AO") -+ ), -+ MTK_PIN( -+ 20, "GPIO20", -+ MTK_EINT_FUNCTION(0, 20), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO20"), -+ MTK_FUNCTION(1, "B0_TP_GPIO30_AO") -+ ), -+ MTK_PIN( -+ 21, "GPIO21", -+ MTK_EINT_FUNCTION(0, 21), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO21"), -+ MTK_FUNCTION(1, "B1_PROCHOT") -+ ), -+ MTK_PIN( -+ 22, "GPIO22", -+ MTK_EINT_FUNCTION(0, 22), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO22"), -+ MTK_FUNCTION(1, "I0_RTC32K_CK") -+ ), -+ MTK_PIN( -+ 23, "GPIO23", -+ MTK_EINT_FUNCTION(0, 23), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO23"), -+ MTK_FUNCTION(1, "B0_TP_GPIO0_AO") -+ ), -+ MTK_PIN( -+ 24, "GPIO24", -+ MTK_EINT_FUNCTION(0, 24), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO24"), -+ MTK_FUNCTION(2, "B0_TP_GPIO1_AO"), -+ MTK_FUNCTION(3, "O_CMMCLK1"), -+ MTK_FUNCTION(4, "O_SROOT_GPIO_O"), -+ MTK_FUNCTION(5, "O_MD32_10_TXD"), -+ MTK_FUNCTION(6, "O_MD32_11_TXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_A3") -+ ), -+ MTK_PIN( -+ 25, "GPIO25", -+ MTK_EINT_FUNCTION(0, 25), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO25"), -+ MTK_FUNCTION(1, "B0_TP_GPIO2_AO"), -+ MTK_FUNCTION(2, "I0_VBUSVALID_0P"), -+ MTK_FUNCTION(4, "I0_SROOT_GPIO_I"), -+ MTK_FUNCTION(5, "I1_MD32_10_RXD"), -+ MTK_FUNCTION(6, "I1_MD32_11_RXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_A4") -+ ), -+ MTK_PIN( -+ 26, "GPIO26", -+ MTK_EINT_FUNCTION(0, 26), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO26"), -+ MTK_FUNCTION(1, "B0_TP_GPIO3_AO"), -+ MTK_FUNCTION(5, "O_MD32_12_TXD"), -+ MTK_FUNCTION(6, "O_MD32_13_TXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_A5") -+ ), -+ MTK_PIN( -+ 27, "GPIO27", -+ MTK_EINT_FUNCTION(0, 27), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO27"), -+ MTK_FUNCTION(1, "B0_TP_GPIO4_AO"), -+ MTK_FUNCTION(5, "I1_MD32_12_RXD"), -+ MTK_FUNCTION(6, "I1_MD32_13_RXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_A6") -+ ), -+ MTK_PIN( -+ 28, "GPIO28", -+ MTK_EINT_FUNCTION(0, 28), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO28"), -+ MTK_FUNCTION(1, "B0_TP_GPIO5_AO"), -+ MTK_FUNCTION(5, "O_MD32_12_GPIO0"), -+ MTK_FUNCTION(6, "O_MD32_13_GPIO0"), -+ MTK_FUNCTION(7, "O_DBG_MON_A7") -+ ), -+ MTK_PIN( -+ 29, "GPIO29", -+ MTK_EINT_FUNCTION(0, 29), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO29"), -+ MTK_FUNCTION(1, "B1_THERMTRIP") -+ ), -+ MTK_PIN( -+ 30, "GPIO30", -+ MTK_EINT_FUNCTION(0, 30), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO30"), -+ MTK_FUNCTION(1, "B0_TP_GPIO7_AO"), -+ MTK_FUNCTION(2, "O_CMMCLK0"), -+ MTK_FUNCTION(4, "I0_CLUSTER0_SLV_CPUEB_JTAG_TRSTN"), -+ MTK_FUNCTION(5, "I0_CLUSTER1_SLV_CPUEB_JTAG_TRSTN"), -+ MTK_FUNCTION(6, "I0_OSROOT_GPIO_I"), -+ MTK_FUNCTION(7, "O_DBG_MON_A8") -+ ), -+ MTK_PIN( -+ 31, "GPIO31", -+ MTK_EINT_FUNCTION(0, 31), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO31"), -+ MTK_FUNCTION(1, "B0_TP_GPIO8_AO"), -+ MTK_FUNCTION(2, "O_CMMCLK1"), -+ MTK_FUNCTION(4, "I1_CLUSTER0_SLV_CPUEB_JTAG_TMS"), -+ MTK_FUNCTION(5, "I1_CLUSTER1_SLV_CPUEB_JTAG_TMS"), -+ MTK_FUNCTION(6, "O_OSROOT_GPIO_O"), -+ MTK_FUNCTION(7, "O_DBG_MON_A9") -+ ), -+ MTK_PIN( -+ 32, "GPIO32", -+ MTK_EINT_FUNCTION(0, 32), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO32"), -+ MTK_FUNCTION(1, "B0_TP_GPIO9_AO"), -+ MTK_FUNCTION(5, "O_SROOT_UTX"), -+ MTK_FUNCTION(6, "I1_TP_UCTS1_VLP"), -+ MTK_FUNCTION(7, "O_DBG_MON_A10") -+ ), -+ MTK_PIN( -+ 33, "GPIO33", -+ MTK_EINT_FUNCTION(0, 33), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO33"), -+ MTK_FUNCTION(1, "B0_TP_GPIO10_AO"), -+ MTK_FUNCTION(2, "O_CMMCLK2"), -+ MTK_FUNCTION(3, "I0_VBUSVALID_1P"), -+ MTK_FUNCTION(4, "I1_CLUSTER0_SLV_CPUEB_JTAG_TCK"), -+ MTK_FUNCTION(5, "I1_CLUSTER1_SLV_CPUEB_JTAG_TCK"), -+ MTK_FUNCTION(6, "I0_SROOT_TCK"), -+ MTK_FUNCTION(7, "I0_OSROOT_TCK") -+ ), -+ MTK_PIN( -+ 34, "GPIO34", -+ MTK_EINT_FUNCTION(0, 34), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO34"), -+ MTK_FUNCTION(1, "B0_TP_GPIO11_AO"), -+ MTK_FUNCTION(2, "O_CMMCLK4"), -+ MTK_FUNCTION(3, "I0_VBUSVALID_3P"), -+ MTK_FUNCTION(4, "I1_CLUSTER0_SLV_CPUEB_JTAG_TDI"), -+ MTK_FUNCTION(5, "I1_CLUSTER1_SLV_CPUEB_JTAG_TDI"), -+ MTK_FUNCTION(6, "I0_SROOT_TDI"), -+ MTK_FUNCTION(7, "I0_OSROOT_TDI") -+ ), -+ MTK_PIN( -+ 35, "GPIO35", -+ MTK_EINT_FUNCTION(0, 35), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO35"), -+ MTK_FUNCTION(1, "B0_TP_GPIO12_AO"), -+ MTK_FUNCTION(2, "O_SCP_PWM_1_VLP"), -+ MTK_FUNCTION(4, "O_CLUSTER0_SLV_CPUEB_JTAG_TDO"), -+ MTK_FUNCTION(5, "O_CLUSTER1_SLV_CPUEB_JTAG_TDO"), -+ MTK_FUNCTION(6, "O_SROOT_TDO"), -+ MTK_FUNCTION(7, "O_OSROOT_TDO") -+ ), -+ MTK_PIN( -+ 36, "GPIO36", -+ MTK_EINT_FUNCTION(0, 36), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO36"), -+ MTK_FUNCTION(1, "B0_TP_GPIO22_AO"), -+ MTK_FUNCTION(5, "I1_SROOT_URX"), -+ MTK_FUNCTION(6, "O_TP_URTS1_VLP"), -+ MTK_FUNCTION(7, "O_DBG_MON_A31") -+ ), -+ MTK_PIN( -+ 37, "GPIO37", -+ MTK_EINT_FUNCTION(0, 37), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO37"), -+ MTK_FUNCTION(1, "B0_TP_GPIO23_AO"), -+ MTK_FUNCTION(2, "O_CMMCLK3"), -+ MTK_FUNCTION(4, "O_SCP_PWM_2_VLP"), -+ MTK_FUNCTION(6, "O_MD32_5_GPIO0"), -+ MTK_FUNCTION(7, "O_DBG_MON_A11") -+ ), -+ MTK_PIN( -+ 38, "GPIO38", -+ MTK_EINT_FUNCTION(0, 38), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO38"), -+ MTK_FUNCTION(1, "B0_TP_GPIO24_AO"), -+ MTK_FUNCTION(2, "O_SCP_VREQ_VAO") -+ ), -+ MTK_PIN( -+ 39, "GPIO39", -+ MTK_EINT_FUNCTION(0, 39), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO39"), -+ MTK_FUNCTION(1, "B0_TP_GPIO13_AO"), -+ MTK_FUNCTION(2, "O_SCP_PWM_2_VLP"), -+ MTK_FUNCTION(3, "O_CMMCLK0"), -+ MTK_FUNCTION(4, "I0_VBUSVALID_2P"), -+ MTK_FUNCTION(5, "O_MD32_10_GPIO0"), -+ MTK_FUNCTION(6, "I0_SROOT_TMS"), -+ MTK_FUNCTION(7, "I0_OSROOT_TMS") -+ ), -+ MTK_PIN( -+ 40, "GPIO40", -+ MTK_EINT_FUNCTION(0, 40), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO40"), -+ MTK_FUNCTION(1, "B0_TP_GPIO14_AO"), -+ MTK_FUNCTION(2, "I0_VBUSVALID_1P"), -+ MTK_FUNCTION(3, "O_URTS2"), -+ MTK_FUNCTION(4, "O_TP_URTS2_VLP"), -+ MTK_FUNCTION(5, "O_SPMI_P_TRIG_FLAG"), -+ MTK_FUNCTION(6, "I1_MD32_5_RXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_A13") -+ ), -+ MTK_PIN( -+ 41, "GPIO41", -+ MTK_EINT_FUNCTION(0, 41), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO41"), -+ MTK_FUNCTION(1, "B0_TP_GPIO15_AO"), -+ MTK_FUNCTION(2, "I0_VBUSVALID_0P"), -+ MTK_FUNCTION(3, "I1_UCTS2"), -+ MTK_FUNCTION(4, "I1_TP_UCTS2_VLP"), -+ MTK_FUNCTION(5, "O_SPMI_S_TRIG_FLAG"), -+ MTK_FUNCTION(6, "O_MD32_5_TXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_A12") -+ ), -+ MTK_PIN( -+ 42, "GPIO42", -+ MTK_EINT_FUNCTION(0, 42), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO42"), -+ MTK_FUNCTION(1, "B0_TP_GPIO16_AO"), -+ MTK_FUNCTION(2, "O_CMMCLK3"), -+ MTK_FUNCTION(3, "O_UTXD2"), -+ MTK_FUNCTION(4, "O_TP_UTXD2_VLP"), -+ MTK_FUNCTION(5, "O_SPMI_M_TRIG_FLAG"), -+ MTK_FUNCTION(6, "I0_SROOT_NTRST"), -+ MTK_FUNCTION(7, "I0_OSROOT_NTRST") -+ ), -+ MTK_PIN( -+ 43, "GPIO43", -+ MTK_EINT_FUNCTION(0, 43), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO43"), -+ MTK_FUNCTION(1, "B0_TP_GPIO17_AO"), -+ MTK_FUNCTION(2, "O_CMMCLK4"), -+ MTK_FUNCTION(3, "I1_URXD2"), -+ MTK_FUNCTION(4, "I1_TP_URXD2_VLP"), -+ MTK_FUNCTION(5, "O_MD32_4_TXD"), -+ MTK_FUNCTION(6, "O_MD32PCM_UTXD_AO_VLP") -+ ), -+ MTK_PIN( -+ 44, "GPIO44", -+ MTK_EINT_FUNCTION(0, 44), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO44"), -+ MTK_FUNCTION(1, "B0_TP_GPIO18_AO"), -+ MTK_FUNCTION(2, "I1_TP_UCTS2_VLP"), -+ MTK_FUNCTION(3, "I1_UCTS2"), -+ MTK_FUNCTION(5, "I1_MD32_4_RXD"), -+ MTK_FUNCTION(6, "I1_MD32PCM_URXD_AO_VLP") -+ ), -+ MTK_PIN( -+ 45, "GPIO45", -+ MTK_EINT_FUNCTION(0, 45), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO45"), -+ MTK_FUNCTION(1, "B0_TP_GPIO19_AO"), -+ MTK_FUNCTION(2, "O_TP_URTS2_VLP"), -+ MTK_FUNCTION(3, "O_URTS2"), -+ MTK_FUNCTION(5, "O_MD32_4_GPIO0"), -+ MTK_FUNCTION(6, "O_MD32_11_GPIO0") -+ ), -+ MTK_PIN( -+ 46, "GPIO46", -+ MTK_EINT_FUNCTION(0, 46), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO46"), -+ MTK_FUNCTION(1, "B0_TP_GPIO20_AO"), -+ MTK_FUNCTION(2, "I0_VBUSVALID_2P"), -+ MTK_FUNCTION(3, "O_SCP_VREQ_VAO"), -+ MTK_FUNCTION(4, "O_SCP_PWM_1_VLP"), -+ MTK_FUNCTION(5, "O_SROOT_GPIO_O"), -+ MTK_FUNCTION(6, "O_OSROOT_GPIO_O") -+ ), -+ MTK_PIN( -+ 47, "GPIO47", -+ MTK_EINT_FUNCTION(0, 47), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO47"), -+ MTK_FUNCTION(1, "B0_TP_GPIO21_AO"), -+ MTK_FUNCTION(2, "I0_VBUSVALID_3P"), -+ MTK_FUNCTION(3, "O_CMMCLK2"), -+ MTK_FUNCTION(5, "I0_SROOT_GPIO_I"), -+ MTK_FUNCTION(6, "I0_OSROOT_GPIO_I"), -+ MTK_FUNCTION(7, "O_DBG_MON_A2") -+ ), -+ MTK_PIN( -+ 48, "GPIO48", -+ MTK_EINT_FUNCTION(0, 48), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO48"), -+ MTK_FUNCTION(1, "O_UTXD0"), -+ MTK_FUNCTION(2, "O_TP_UTXD1_VLP"), -+ MTK_FUNCTION(6, "O_ADSP_UTXD0"), -+ MTK_FUNCTION(7, "O_DBG_MON_A19") -+ ), -+ MTK_PIN( -+ 49, "GPIO49", -+ MTK_EINT_FUNCTION(0, 49), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO49"), -+ MTK_FUNCTION(1, "I1_URXD0"), -+ MTK_FUNCTION(2, "I1_TP_URXD1_VLP"), -+ MTK_FUNCTION(6, "I1_ADSP_URXD0"), -+ MTK_FUNCTION(7, "O_DBG_MON_A20") -+ ), -+ MTK_PIN( -+ 50, "GPIO50", -+ MTK_EINT_FUNCTION(0, 50), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO50"), -+ MTK_FUNCTION(1, "O_TP_UTXD2_VLP"), -+ MTK_FUNCTION(2, "O_UTXD2"), -+ MTK_FUNCTION(4, "B0_TP_GPIO26_AO"), -+ MTK_FUNCTION(5, "O_TP_UTXD1_VLP"), -+ MTK_FUNCTION(7, "O_SROOT_UTX") -+ ), -+ MTK_PIN( -+ 51, "GPIO51", -+ MTK_EINT_FUNCTION(0, 51), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO51"), -+ MTK_FUNCTION(1, "I1_TP_URXD2_VLP"), -+ MTK_FUNCTION(2, "I1_URXD2"), -+ MTK_FUNCTION(4, "B0_TP_GPIO27_AO"), -+ MTK_FUNCTION(5, "I1_TP_URXD1_VLP"), -+ MTK_FUNCTION(7, "I1_SROOT_URX") -+ ), -+ MTK_PIN( -+ 52, "GPIO52", -+ MTK_EINT_FUNCTION(0, 52), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO52"), -+ MTK_FUNCTION(1, "B1_USB4_L_PD_SCL"), -+ MTK_FUNCTION(7, "O_ADSP_UTXD0") -+ ), -+ MTK_PIN( -+ 53, "GPIO53", -+ MTK_EINT_FUNCTION(0, 53), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO53"), -+ MTK_FUNCTION(1, "B1_USB4_L_PD_SDA"), -+ MTK_FUNCTION(5, "O_MD32_7_TXD"), -+ MTK_FUNCTION(6, "O_MD32_6_TXD"), -+ MTK_FUNCTION(7, "I1_ADSP_URXD0") -+ ), -+ MTK_PIN( -+ 54, "GPIO54", -+ MTK_EINT_FUNCTION(0, 54), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO54"), -+ MTK_FUNCTION(1, "B1_USB4_R_PD_SCL"), -+ MTK_FUNCTION(4, "I1_CKM_SCL"), -+ MTK_FUNCTION(5, "I1_MD32_7_RXD"), -+ MTK_FUNCTION(6, "I1_USB4_L_PAR_SCL"), -+ MTK_FUNCTION(7, "O_PBUD_CTRL_UTXD_AO_VLP") -+ ), -+ MTK_PIN( -+ 55, "GPIO55", -+ MTK_EINT_FUNCTION(0, 55), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO55"), -+ MTK_FUNCTION(1, "B1_USB4_R_PD_SDA"), -+ MTK_FUNCTION(4, "B1_CKM_SDA"), -+ MTK_FUNCTION(5, "O_MD32_7_GPIO0"), -+ MTK_FUNCTION(6, "B1_USB4_L_PAR_SDA"), -+ MTK_FUNCTION(7, "I1_PBUD_CTRL_URXD_AO_VLP") -+ ), -+ MTK_PIN( -+ 56, "GPIO56", -+ MTK_EINT_FUNCTION(0, 56), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO56"), -+ MTK_FUNCTION(1, "B0_SPMI_S_SCL") -+ ), -+ MTK_PIN( -+ 57, "GPIO57", -+ MTK_EINT_FUNCTION(0, 57), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO57"), -+ MTK_FUNCTION(1, "B0_SPMI_S_SDA") -+ ), -+ MTK_PIN( -+ 58, "GPIO58", -+ MTK_EINT_FUNCTION(0, 58), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO58"), -+ MTK_FUNCTION(1, "O_WATCHDOG") -+ ), -+ MTK_PIN( -+ 59, "GPIO59", -+ MTK_EINT_FUNCTION(0, 59), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO59"), -+ MTK_FUNCTION(1, "B0_PAD_RESET_DRAM_0") -+ ), -+ MTK_PIN( -+ 60, "GPIO60", -+ MTK_EINT_FUNCTION(0, 60), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO60"), -+ MTK_FUNCTION(1, "B1_I2C_SCL0"), -+ MTK_FUNCTION(5, "O_MD32_2_TXD"), -+ MTK_FUNCTION(6, "O_MD32_3_TXD") -+ ), -+ MTK_PIN( -+ 61, "GPIO61", -+ MTK_EINT_FUNCTION(0, 61), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO61"), -+ MTK_FUNCTION(1, "B1_I2C_SDA0"), -+ MTK_FUNCTION(5, "I1_MD32_2_RXD"), -+ MTK_FUNCTION(6, "I1_MD32_3_RXD") -+ ), -+ MTK_PIN( -+ 62, "GPIO62", -+ MTK_EINT_FUNCTION(0, 62), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO62"), -+ MTK_FUNCTION(1, "I0_DMIC0_DAT"), -+ MTK_FUNCTION(6, "O_TP_UTXD1_VLP"), -+ MTK_FUNCTION(7, "O_DBG_MON_B0") -+ ), -+ MTK_PIN( -+ 63, "GPIO63", -+ MTK_EINT_FUNCTION(0, 63), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO63"), -+ MTK_FUNCTION(1, "O_DMIC0_CLK"), -+ MTK_FUNCTION(6, "I1_TP_URXD1_VLP"), -+ MTK_FUNCTION(7, "O_DBG_MON_B1") -+ ), -+ MTK_PIN( -+ 64, "GPIO64", -+ MTK_EINT_FUNCTION(0, 64), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO64"), -+ MTK_FUNCTION(1, "I0_DMIC1_DAT"), -+ MTK_FUNCTION(5, "O_MD32_2_GPIO0"), -+ MTK_FUNCTION(6, "O_MD32_3_GPIO0"), -+ MTK_FUNCTION(7, "O_DBG_MON_B2") -+ ), -+ MTK_PIN( -+ 65, "GPIO65", -+ MTK_EINT_FUNCTION(0, 65), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO65"), -+ MTK_FUNCTION(1, "O_DMIC1_CLK"), -+ MTK_FUNCTION(7, "O_DBG_MON_B3") -+ ), -+ MTK_PIN( -+ 66, "GPIO66", -+ MTK_EINT_FUNCTION(0, 66), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO66"), -+ MTK_FUNCTION(1, "O_SOUNDWIRE0_CK"), -+ MTK_FUNCTION(3, "I1_TP_UCTS0_VLP"), -+ MTK_FUNCTION(4, "O_SPI_HID_IRQ_S_MON0"), -+ MTK_FUNCTION(7, "O_VADSP_UTXD0") -+ ), -+ MTK_PIN( -+ 67, "GPIO67", -+ MTK_EINT_FUNCTION(0, 67), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO67"), -+ MTK_FUNCTION(1, "B0_SOUNDWIRE0_D0"), -+ MTK_FUNCTION(3, "O_TP_URTS0_VLP"), -+ MTK_FUNCTION(7, "I1_VADSP_URXD0") -+ ), -+ MTK_PIN( -+ 68, "GPIO68", -+ MTK_EINT_FUNCTION(0, 68), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO68"), -+ MTK_FUNCTION(1, "O_SCP_PWM_0_VLP"), -+ MTK_FUNCTION(2, "O_PWM_VLP"), -+ MTK_FUNCTION(3, "B0_TP_GPIO28_AO") -+ ), -+ MTK_PIN( -+ 69, "GPIO69", -+ MTK_EINT_FUNCTION(0, 69), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO69"), -+ MTK_FUNCTION(1, "B0_PAD_RESET_DRAM_8") -+ ), -+ MTK_PIN( -+ 70, "GPIO70", -+ MTK_EINT_FUNCTION(0, 70), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO70"), -+ MTK_FUNCTION(1, "B1_SCP_SCL0"), -+ MTK_FUNCTION(4, "I0_VADSP_JTAG0_TCK"), -+ MTK_FUNCTION(5, "I1_PCIE4_USB3_PAR_SCL"), -+ MTK_FUNCTION(6, "I1_SCP_JTAG0_TCK_VLP"), -+ MTK_FUNCTION(7, "B1_SROOT_SCL") -+ ), -+ MTK_PIN( -+ 71, "GPIO71", -+ MTK_EINT_FUNCTION(0, 71), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO71"), -+ MTK_FUNCTION(1, "B1_SCP_SDA0"), -+ MTK_FUNCTION(4, "I1_VADSP_JTAG0_TMS"), -+ MTK_FUNCTION(5, "B1_PCIE4_USB3_PAR_SDA"), -+ MTK_FUNCTION(6, "B1_SCP_JTAG0_TMS_VLP"), -+ MTK_FUNCTION(7, "B1_SROOT_SDA") -+ ), -+ MTK_PIN( -+ 72, "GPIO72", -+ MTK_EINT_FUNCTION(0, 72), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO72"), -+ MTK_FUNCTION(1, "B1_SCP_SCL2"), -+ MTK_FUNCTION(2, "B1_I3C_HCI_AO_SCL"), -+ MTK_FUNCTION(4, "I1_VADSP_JTAG0_TDI"), -+ MTK_FUNCTION(5, "I1_PCIE5_PAR_SCL"), -+ MTK_FUNCTION(6, "I1_SCP_JTAG0_TDI_VLP"), -+ MTK_FUNCTION(7, "O_OSROOT_UTX") -+ ), -+ MTK_PIN( -+ 73, "GPIO73", -+ MTK_EINT_FUNCTION(0, 73), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO73"), -+ MTK_FUNCTION(1, "B1_SCP_SDA2"), -+ MTK_FUNCTION(2, "B1_I3C_HCI_AO_SDA"), -+ MTK_FUNCTION(4, "O_VADSP_JTAG0_TDO"), -+ MTK_FUNCTION(5, "B1_PCIE5_PAR_SDA"), -+ MTK_FUNCTION(6, "O_SCP_JTAG0_TDO_VLP"), -+ MTK_FUNCTION(7, "I1_OSROOT_URX") -+ ), -+ MTK_PIN( -+ 74, "GPIO74", -+ MTK_EINT_FUNCTION(0, 74), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO74"), -+ MTK_FUNCTION(1, "I0_SCP_SPIS0_SCL"), -+ MTK_FUNCTION(2, "O_SPI2_CLK"), -+ MTK_FUNCTION(3, "O_SCP_SPIM0_CK"), -+ MTK_FUNCTION(4, "I1_SPM_JTAG_TCK_VLP"), -+ MTK_FUNCTION(5, "I1_SSPM_JTAG_TCK_VLP"), -+ MTK_FUNCTION(6, "I1_PBUD_CTRL_JTAG_TCK_VLP"), -+ MTK_FUNCTION(7, "I0_OSROOT_TCK") -+ ), -+ MTK_PIN( -+ 75, "GPIO75", -+ MTK_EINT_FUNCTION(0, 75), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO75"), -+ MTK_FUNCTION(1, "B0_SCP_SPIS0_SIO0"), -+ MTK_FUNCTION(2, "B0_SPI2_MI"), -+ MTK_FUNCTION(3, "B0_SCP_SPIM0_SIO0"), -+ MTK_FUNCTION(4, "I1_SPM_JTAG_TDI_VLP"), -+ MTK_FUNCTION(5, "I1_SSPM_JTAG_TDI_VLP"), -+ MTK_FUNCTION(6, "I1_PBUD_CTRL_JTAG_TDI_VLP"), -+ MTK_FUNCTION(7, "I0_OSROOT_TDI") -+ ), -+ MTK_PIN( -+ 76, "GPIO76", -+ MTK_EINT_FUNCTION(0, 76), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO76"), -+ MTK_FUNCTION(1, "B0_SCP_SPIS0_SIO1"), -+ MTK_FUNCTION(2, "B0_SPI2_MO"), -+ MTK_FUNCTION(3, "B0_SCP_SPIM0_SIO1"), -+ MTK_FUNCTION(4, "B1_SPM_JTAG_TDO_VLP"), -+ MTK_FUNCTION(5, "O_SSPM_JTAG_TDO_VLP"), -+ MTK_FUNCTION(6, "O_PBUD_CTRL_JTAG_TDO_VLP"), -+ MTK_FUNCTION(7, "O_OSROOT_TDO") -+ ), -+ MTK_PIN( -+ 77, "GPIO77", -+ MTK_EINT_FUNCTION(0, 77), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO77"), -+ MTK_FUNCTION(1, "B0_SCP_SPIS0_SIO2"), -+ MTK_FUNCTION(2, "B0_SPI2_WP"), -+ MTK_FUNCTION(3, "B0_SCP_SPIM0_SIO2"), -+ MTK_FUNCTION(4, "I1_SPM_JTAG_TMS_VLP"), -+ MTK_FUNCTION(5, "I1_SSPM_JTAG_TMS_VLP"), -+ MTK_FUNCTION(6, "I1_PBUD_CTRL_JTAG_TMS_VLP"), -+ MTK_FUNCTION(7, "I0_OSROOT_TMS") -+ ), -+ MTK_PIN( -+ 78, "GPIO78", -+ MTK_EINT_FUNCTION(0, 78), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO78"), -+ MTK_FUNCTION(1, "B0_SCP_SPIS0_SIO3"), -+ MTK_FUNCTION(2, "B0_SPI2_HOLD"), -+ MTK_FUNCTION(3, "B0_SCP_SPIM0_SIO3"), -+ MTK_FUNCTION(4, "I0_SPM_JTAG_TRSTN_VLP"), -+ MTK_FUNCTION(5, "I0_SSPM_JTAG_TRSTN_VLP"), -+ MTK_FUNCTION(6, "I0_PBUD_CTRL_JTAG_TRSTN_VLP"), -+ MTK_FUNCTION(7, "I0_OSROOT_NTRST") -+ ), -+ MTK_PIN( -+ 79, "GPIO79", -+ MTK_EINT_FUNCTION(0, 79), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO79"), -+ MTK_FUNCTION(1, "I1_SCP_SPIS0_CS"), -+ MTK_FUNCTION(2, "O_SPI2_CSB"), -+ MTK_FUNCTION(3, "O_SCP_SPIM0_CS"), -+ MTK_FUNCTION(4, "I1_VADSP_JTAG0_TRSTN"), -+ MTK_FUNCTION(6, "I0_SCP_JTAG0_TRSTN_VLP") -+ ), -+ MTK_PIN( -+ 80, "GPIO80", -+ MTK_EINT_FUNCTION(0, 80), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO80"), -+ MTK_FUNCTION(1, "O_SPI0_CLK"), -+ MTK_FUNCTION(2, "B0_SPI0_OSROOT_CLK"), -+ MTK_FUNCTION(4, "I1_SSPM_JTAG_TCK_VLP"), -+ MTK_FUNCTION(5, "I0_VADSP_JTAG0_TCK"), -+ MTK_FUNCTION(6, "I1_SPM_JTAG_TCK_VLP"), -+ MTK_FUNCTION(7, "I1_SCP_JTAG0_TCK_VLP") -+ ), -+ MTK_PIN( -+ 81, "GPIO81", -+ MTK_EINT_FUNCTION(0, 81), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO81"), -+ MTK_FUNCTION(1, "B0_SPI0_MI"), -+ MTK_FUNCTION(2, "I0_SPI0_OSROOT_MI"), -+ MTK_FUNCTION(4, "I1_SSPM_JTAG_TDI_VLP"), -+ MTK_FUNCTION(5, "I1_VADSP_JTAG0_TDI"), -+ MTK_FUNCTION(6, "I1_SPM_JTAG_TDI_VLP"), -+ MTK_FUNCTION(7, "I1_SCP_JTAG0_TDI_VLP") -+ ), -+ MTK_PIN( -+ 82, "GPIO82", -+ MTK_EINT_FUNCTION(0, 82), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO82"), -+ MTK_FUNCTION(1, "B0_SPI0_MO"), -+ MTK_FUNCTION(2, "O_SPI0_OSROOT_MO"), -+ MTK_FUNCTION(4, "O_SSPM_JTAG_TDO_VLP"), -+ MTK_FUNCTION(5, "O_VADSP_JTAG0_TDO"), -+ MTK_FUNCTION(6, "B1_SPM_JTAG_TDO_VLP"), -+ MTK_FUNCTION(7, "O_SCP_JTAG0_TDO_VLP") -+ ), -+ MTK_PIN( -+ 83, "GPIO83", -+ MTK_EINT_FUNCTION(0, 83), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO83"), -+ MTK_FUNCTION(1, "O_SPI0_CSB0"), -+ MTK_FUNCTION(2, "O_SPI0_OSROOT_CSB"), -+ MTK_FUNCTION(4, "I1_SSPM_JTAG_TMS_VLP"), -+ MTK_FUNCTION(5, "I1_VADSP_JTAG0_TMS"), -+ MTK_FUNCTION(6, "I1_SPM_JTAG_TMS_VLP"), -+ MTK_FUNCTION(7, "B1_SCP_JTAG0_TMS_VLP") -+ ), -+ MTK_PIN( -+ 84, "GPIO84", -+ MTK_EINT_FUNCTION(0, 84), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO84"), -+ MTK_FUNCTION(1, "O_SPI0_CSB1"), -+ MTK_FUNCTION(4, "I0_SSPM_JTAG_TRSTN_VLP"), -+ MTK_FUNCTION(5, "I1_VADSP_JTAG0_TRSTN"), -+ MTK_FUNCTION(6, "I0_SPM_JTAG_TRSTN_VLP"), -+ MTK_FUNCTION(7, "I0_SCP_JTAG0_TRSTN_VLP") -+ ), -+ MTK_PIN( -+ 85, "GPIO85", -+ MTK_EINT_FUNCTION(0, 85), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO85"), -+ MTK_FUNCTION(1, "O_DISP_PWM"), -+ MTK_FUNCTION(4, "B1_U4CP_JTAG_TMS"), -+ MTK_FUNCTION(5, "I0_CLUSTER0_UDI_TDI_1"), -+ MTK_FUNCTION(6, "I0_CLUSTER1_UDI_TDI_1"), -+ MTK_FUNCTION(7, "O_DBG_MON_A21") -+ ), -+ MTK_PIN( -+ 86, "GPIO86", -+ MTK_EINT_FUNCTION(0, 86), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO86"), -+ MTK_FUNCTION(1, "O_DISP_BL_EN"), -+ MTK_FUNCTION(4, "I1_U4CP_JTAG_TDI"), -+ MTK_FUNCTION(5, "O_CLUSTER0_UDI_TDO_1"), -+ MTK_FUNCTION(6, "O_CLUSTER1_UDI_TDO_1"), -+ MTK_FUNCTION(7, "O_DBG_MON_A22") -+ ), -+ MTK_PIN( -+ 87, "GPIO87", -+ MTK_EINT_FUNCTION(0, 87), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO87"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N_1"), -+ MTK_FUNCTION(4, "O_U4CP_JTAG_TDO"), -+ MTK_FUNCTION(5, "I0_CLUSTER0_UDI_TDI_2"), -+ MTK_FUNCTION(6, "I0_CLUSTER1_UDI_TDI_2"), -+ MTK_FUNCTION(7, "O_DBG_MON_A23") -+ ), -+ MTK_PIN( -+ 88, "GPIO88", -+ MTK_EINT_FUNCTION(0, 88), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO88"), -+ MTK_FUNCTION(1, "B1_DISP_SCL1"), -+ MTK_FUNCTION(4, "I1_U4CP_JTAG_TCK"), -+ MTK_FUNCTION(5, "I1_EDP0_SCL"), -+ MTK_FUNCTION(6, "I1_HDMITX_DBG_I2C_SCL") -+ ), -+ MTK_PIN( -+ 89, "GPIO89", -+ MTK_EINT_FUNCTION(0, 89), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO89"), -+ MTK_FUNCTION(1, "B1_DISP_SDA1"), -+ MTK_FUNCTION(4, "I0_U4CP_JTAG_TRSTN"), -+ MTK_FUNCTION(5, "B1_EDP0_SDA"), -+ MTK_FUNCTION(6, "B1_HDMITX_DBG_I2C_SDA") -+ ), -+ MTK_PIN( -+ 90, "GPIO90", -+ MTK_EINT_FUNCTION(0, 90), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO90"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N2"), -+ MTK_FUNCTION(4, "O_CLKM0_C"), -+ MTK_FUNCTION(5, "O_CLUSTER0_UDI_TDO_2"), -+ MTK_FUNCTION(6, "O_CLUSTER1_UDI_TDO_2"), -+ MTK_FUNCTION(7, "O_DBG_MON_A24") -+ ), -+ MTK_PIN( -+ 91, "GPIO91", -+ MTK_EINT_FUNCTION(0, 91), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO91"), -+ MTK_FUNCTION(1, "I0_DPAUX_HPD_IN_4"), -+ MTK_FUNCTION(4, "O_CLKM1_C"), -+ MTK_FUNCTION(5, "I0_CLUSTER0_UDI_TDI_3"), -+ MTK_FUNCTION(6, "I0_CLUSTER1_UDI_TDI_3"), -+ MTK_FUNCTION(7, "O_DBG_MON_A25") -+ ), -+ MTK_PIN( -+ 92, "GPIO92", -+ MTK_EINT_FUNCTION(0, 92), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO92"), -+ MTK_FUNCTION(1, "B1_I2C_SCL5"), -+ MTK_FUNCTION(2, "O_TP_UTXD0_VLP"), -+ MTK_FUNCTION(3, "O_SSPM_UTXD_AO_VLP"), -+ MTK_FUNCTION(4, "O_TSFDC_FOUT"), -+ MTK_FUNCTION(5, "O_CLUSTER0_UDI_TDO_3"), -+ MTK_FUNCTION(6, "O_CLUSTER1_UDI_TDO_3"), -+ MTK_FUNCTION(7, "O_DBG_MON_A26") -+ ), -+ MTK_PIN( -+ 93, "GPIO93", -+ MTK_EINT_FUNCTION(0, 93), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO93"), -+ MTK_FUNCTION(1, "B1_I2C_SDA5"), -+ MTK_FUNCTION(2, "I1_TP_URXD0_VLP"), -+ MTK_FUNCTION(3, "I1_SSPM_URXD_AO_VLP"), -+ MTK_FUNCTION(4, "O_TSFDC_SDO"), -+ MTK_FUNCTION(5, "I0_CLUSTER0_UDI_TDI_4"), -+ MTK_FUNCTION(6, "I0_CLUSTER1_UDI_TDI_4"), -+ MTK_FUNCTION(7, "O_DBG_MON_A27") -+ ), -+ MTK_PIN( -+ 94, "GPIO94", -+ MTK_EINT_FUNCTION(0, 94), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO94"), -+ MTK_FUNCTION(1, "O_CMFLASH0"), -+ MTK_FUNCTION(4, "I0_TSFDC_26M"), -+ MTK_FUNCTION(5, "O_CLUSTER0_UDI_TDO_4"), -+ MTK_FUNCTION(6, "O_CLUSTER1_UDI_TDO_4"), -+ MTK_FUNCTION(7, "O_DBG_MON_A28") -+ ), -+ MTK_PIN( -+ 95, "GPIO95", -+ MTK_EINT_FUNCTION(0, 95), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO95"), -+ MTK_FUNCTION(1, "O_CMFLASH1"), -+ MTK_FUNCTION(4, "I0_TSFDC_SCF"), -+ MTK_FUNCTION(5, "I0_CLUSTER0_UDI_TDI_5"), -+ MTK_FUNCTION(6, "I0_CLUSTER1_UDI_TDI_5"), -+ MTK_FUNCTION(7, "O_DBG_MON_A29") -+ ), -+ MTK_PIN( -+ 96, "GPIO96", -+ MTK_EINT_FUNCTION(0, 96), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO96"), -+ MTK_FUNCTION(1, "O_CMVREF0"), -+ MTK_FUNCTION(2, "O_CMFLASH1"), -+ MTK_FUNCTION(4, "I0_TSFDC_SCK"), -+ MTK_FUNCTION(5, "O_CLUSTER0_UDI_TDO_5"), -+ MTK_FUNCTION(6, "O_CLUSTER1_UDI_TDO_5"), -+ MTK_FUNCTION(7, "O_DBG_MON_A30") -+ ), -+ MTK_PIN( -+ 97, "GPIO97", -+ MTK_EINT_FUNCTION(0, 97), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO97"), -+ MTK_FUNCTION(1, "O_CMVREF1"), -+ MTK_FUNCTION(2, "O_CMFLASH0"), -+ MTK_FUNCTION(4, "I0_TSFDC_SDI"), -+ MTK_FUNCTION(5, "I0_CLUSTER0_UDI_TDI_6"), -+ MTK_FUNCTION(6, "I0_CLUSTER1_UDI_TDI_6"), -+ MTK_FUNCTION(7, "O_U4CP_UTXD") -+ ), -+ MTK_PIN( -+ 98, "GPIO98", -+ MTK_EINT_FUNCTION(0, 98), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO98"), -+ MTK_FUNCTION(2, "O_CMFLASH2"), -+ MTK_FUNCTION(4, "I0_RG_TSFDC_LDO_EN"), -+ MTK_FUNCTION(5, "O_CLUSTER0_UDI_TDO_6"), -+ MTK_FUNCTION(6, "O_CLUSTER1_UDI_TDO_6"), -+ MTK_FUNCTION(7, "I1_U4CP_URXD") -+ ), -+ MTK_PIN( -+ 99, "GPIO99", -+ MTK_EINT_FUNCTION(0, 99), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO99"), -+ MTK_FUNCTION(1, "I0_MCU_M_PMIC_POC_I"), -+ MTK_FUNCTION(4, "I0_DA_TSFDC_LDO_MODE"), -+ MTK_FUNCTION(5, "I0_CLUSTER0_UDI_TDI_7"), -+ MTK_FUNCTION(6, "I0_CLUSTER1_UDI_TDI_7"), -+ MTK_FUNCTION(7, "O_U4CP_URTS") -+ ), -+ MTK_PIN( -+ 100, "GPIO100", -+ MTK_EINT_FUNCTION(0, 100), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO100"), -+ MTK_FUNCTION(1, "I0_MCU_B_PMIC_POC_I"), -+ MTK_FUNCTION(4, "I0_RG_TSFDC_LDO_REFSEL1"), -+ MTK_FUNCTION(5, "O_CLUSTER0_UDI_TDO_7"), -+ MTK_FUNCTION(6, "O_CLUSTER1_UDI_TDO_7"), -+ MTK_FUNCTION(7, "I1_U4CP_UCTS") -+ ), -+ MTK_PIN( -+ 101, "GPIO101", -+ MTK_EINT_FUNCTION(0, 101), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO101"), -+ MTK_FUNCTION(1, "O_CMFLASH2"), -+ MTK_FUNCTION(2, "O_CMVREF1"), -+ MTK_FUNCTION(3, "I1_UCTS0"), -+ MTK_FUNCTION(4, "I0_RG_TSFDC_LDO_REFSEL0"), -+ MTK_FUNCTION(5, "I1_U4CP_JTAG_TCK"), -+ MTK_FUNCTION(6, "I1_PBUD_CTRL_JTAG_TCK_VCORE"), -+ MTK_FUNCTION(7, "O_CLKM0_A") -+ ), -+ MTK_PIN( -+ 102, "GPIO102", -+ MTK_EINT_FUNCTION(0, 102), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO102"), -+ MTK_FUNCTION(1, "O_CMFLASH3"), -+ MTK_FUNCTION(2, "O_CMVREF0"), -+ MTK_FUNCTION(3, "O_URTS0"), -+ MTK_FUNCTION(4, "O_TSFDC_BG_COMP"), -+ MTK_FUNCTION(5, "B1_U4CP_JTAG_TMS"), -+ MTK_FUNCTION(6, "I1_PBUD_CTRL_JTAG_TMS_VCORE"), -+ MTK_FUNCTION(7, "O_CLKM1_A") -+ ), -+ MTK_PIN( -+ 103, "GPIO103", -+ MTK_EINT_FUNCTION(0, 103), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO103"), -+ MTK_FUNCTION(1, "O_CMVREF2"), -+ MTK_FUNCTION(2, "O_UTXD0"), -+ MTK_FUNCTION(4, "O_CLKM2_B"), -+ MTK_FUNCTION(5, "I1_U4CP_JTAG_TDI"), -+ MTK_FUNCTION(6, "I1_PBUD_CTRL_JTAG_TDI_VCORE"), -+ MTK_FUNCTION(7, "O_CLKM2_A") -+ ), -+ MTK_PIN( -+ 104, "GPIO104", -+ MTK_EINT_FUNCTION(0, 104), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO104"), -+ MTK_FUNCTION(1, "O_CMVREF3"), -+ MTK_FUNCTION(2, "I1_URXD0"), -+ MTK_FUNCTION(4, "O_CLKM3_B"), -+ MTK_FUNCTION(5, "O_U4CP_JTAG_TDO"), -+ MTK_FUNCTION(6, "O_PBUD_CTRL_JTAG_TDO_VCORE"), -+ MTK_FUNCTION(7, "O_CLKM3_A") -+ ), -+ MTK_PIN( -+ 105, "GPIO105", -+ MTK_EINT_FUNCTION(0, 105), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO105"), -+ MTK_FUNCTION(2, "O_CMFLASH3"), -+ MTK_FUNCTION(4, "O_CLKM0_B"), -+ MTK_FUNCTION(5, "I0_U4CP_JTAG_TRSTN"), -+ MTK_FUNCTION(6, "I0_PBUD_CTRL_JTAG_TRSTN_VCORE"), -+ MTK_FUNCTION(7, "O_PMSR_SMAP") -+ ), -+ MTK_PIN( -+ 106, "GPIO106", -+ MTK_EINT_FUNCTION(0, 106), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO106"), -+ MTK_FUNCTION(1, "B0_SPINOR_CK") -+ ), -+ MTK_PIN( -+ 107, "GPIO107", -+ MTK_EINT_FUNCTION(0, 107), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO107"), -+ MTK_FUNCTION(1, "B0_SPINOR_IO0") -+ ), -+ MTK_PIN( -+ 108, "GPIO108", -+ MTK_EINT_FUNCTION(0, 108), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO108"), -+ MTK_FUNCTION(1, "B0_SPINOR_IO1") -+ ), -+ MTK_PIN( -+ 109, "GPIO109", -+ MTK_EINT_FUNCTION(0, 109), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO109"), -+ MTK_FUNCTION(1, "B0_SPINOR_IO2") -+ ), -+ MTK_PIN( -+ 110, "GPIO110", -+ MTK_EINT_FUNCTION(0, 110), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO110"), -+ MTK_FUNCTION(1, "B0_SPINOR_IO3") -+ ), -+ MTK_PIN( -+ 111, "GPIO111", -+ MTK_EINT_FUNCTION(0, 111), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO111"), -+ MTK_FUNCTION(1, "B1_SPINOR_CS") -+ ), -+ MTK_PIN( -+ 112, "GPIO112", -+ MTK_EINT_FUNCTION(0, 112), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO112"), -+ MTK_FUNCTION(1, "O_SPI1_CLK"), -+ MTK_FUNCTION(5, "I1_HFRP_JTAG1_TCK") -+ ), -+ MTK_PIN( -+ 113, "GPIO113", -+ MTK_EINT_FUNCTION(0, 113), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO113"), -+ MTK_FUNCTION(1, "B0_SPI1_MI"), -+ MTK_FUNCTION(5, "I1_HFRP_JTAG1_TMS") -+ ), -+ MTK_PIN( -+ 114, "GPIO114", -+ MTK_EINT_FUNCTION(0, 114), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO114"), -+ MTK_FUNCTION(1, "B0_SPI1_MO"), -+ MTK_FUNCTION(5, "I1_HFRP_JTAG1_TDI") -+ ), -+ MTK_PIN( -+ 115, "GPIO115", -+ MTK_EINT_FUNCTION(0, 115), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO115"), -+ MTK_FUNCTION(1, "O_SPI1_CSB0"), -+ MTK_FUNCTION(5, "O_HFRP_JTAG1_TDO") -+ ), -+ MTK_PIN( -+ 116, "GPIO116", -+ MTK_EINT_FUNCTION(0, 116), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO116"), -+ MTK_FUNCTION(1, "O_SPI1_CSB1"), -+ MTK_FUNCTION(5, "I0_HFRP_JTAG1_TRSTN") -+ ), -+ MTK_PIN( -+ 117, "GPIO117", -+ MTK_EINT_FUNCTION(0, 117), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO117"), -+ MTK_FUNCTION(1, "B1_I2C_SCL1"), -+ MTK_FUNCTION(2, "B1_OSROOT_SCL"), -+ MTK_FUNCTION(4, "O_SPI_CS_S_MON0"), -+ MTK_FUNCTION(5, "I1_USB4_L_PAR_SCL"), -+ MTK_FUNCTION(6, "I1_CKM_SCL"), -+ MTK_FUNCTION(7, "I1_USB4_R_PAR_SCL") -+ ), -+ MTK_PIN( -+ 118, "GPIO118", -+ MTK_EINT_FUNCTION(0, 118), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO118"), -+ MTK_FUNCTION(1, "B1_I2C_SDA1"), -+ MTK_FUNCTION(2, "B1_OSROOT_SDA"), -+ MTK_FUNCTION(4, "O_SPI_SCL_S_MON0"), -+ MTK_FUNCTION(5, "B1_USB4_L_PAR_SDA"), -+ MTK_FUNCTION(6, "B1_CKM_SDA"), -+ MTK_FUNCTION(7, "B1_USB4_R_PAR_SDA") -+ ), -+ MTK_PIN( -+ 119, "GPIO119", -+ MTK_EINT_FUNCTION(0, 119), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO119"), -+ MTK_FUNCTION(1, "B1_I2C_SCL2"), -+ MTK_FUNCTION(4, "I1_HDMITX_DBG_I2C_SCL"), -+ MTK_FUNCTION(5, "O_CLUSTER0_MBISTREADEN_TRIGGER"), -+ MTK_FUNCTION(6, "O_CLUSTER1_MBISTREADEN_TRIGGER"), -+ MTK_FUNCTION(7, "O_PMSR_SMAP_MAX") -+ ), -+ MTK_PIN( -+ 120, "GPIO120", -+ MTK_EINT_FUNCTION(0, 120), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO120"), -+ MTK_FUNCTION(1, "B1_I2C_SDA2+J130_S133"), -+ MTK_FUNCTION(4, "B1_HDMITX_DBG_I2C_SDA"), -+ MTK_FUNCTION(5, "O_CLUSTER0_MBISTWRITEEN_TRIGGER"), -+ MTK_FUNCTION(6, "O_CLUSTER1_MBISTWRITEEN_TRIGGER"), -+ MTK_FUNCTION(7, "O_PMSR_SMAP_MAX_W") -+ ), -+ MTK_PIN( -+ 121, "GPIO121", -+ MTK_EINT_FUNCTION(0, 121), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO121"), -+ MTK_FUNCTION(1, "B1_I3C_SCL0"), -+ MTK_FUNCTION(2, "B1_I3C_HCI_0_AO_SCL"), -+ MTK_FUNCTION(4, "I1_PCIE5_PAR_SCL"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST0"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST0"), -+ MTK_FUNCTION(7, "I1_USB4_R_PAR_SCL") -+ ), -+ MTK_PIN( -+ 122, "GPIO122", -+ MTK_EINT_FUNCTION(0, 122), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO122"), -+ MTK_FUNCTION(1, "B1_I3C_SDA0"), -+ MTK_FUNCTION(2, "B1_I3C_HCI_0_AO_SDA"), -+ MTK_FUNCTION(4, "B1_PCIE5_PAR_SDA"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST1"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST1"), -+ MTK_FUNCTION(7, "B1_USB4_R_PAR_SDA") -+ ), -+ MTK_PIN( -+ 123, "GPIO123", -+ MTK_EINT_FUNCTION(0, 123), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO123"), -+ MTK_FUNCTION(1, "B1_I3C_SCL1"), -+ MTK_FUNCTION(2, "B1_I3C_HCI_1_AO_SCL"), -+ MTK_FUNCTION(4, "I1_PCIE4_USB3_PAR_SCL"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST2"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST2"), -+ MTK_FUNCTION(7, "O_VADSP_UTXD0") -+ ), -+ MTK_PIN( -+ 124, "GPIO124", -+ MTK_EINT_FUNCTION(0, 124), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO124"), -+ MTK_FUNCTION(1, "B1_I3C_SDA1"), -+ MTK_FUNCTION(2, "B1_I3C_HCI_1_AO_SDA"), -+ MTK_FUNCTION(4, "B1_PCIE4_USB3_PAR_SDA"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST3"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST3"), -+ MTK_FUNCTION(7, "I1_VADSP_URXD0") -+ ), -+ MTK_PIN( -+ 125, "GPIO125", -+ MTK_EINT_FUNCTION(0, 125), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO125"), -+ MTK_FUNCTION(1, "O_I2SIN_1_MCK"), -+ MTK_FUNCTION(4, "I0_TSFDC_SCK"), -+ MTK_FUNCTION(6, "O_CLKM2_C") -+ ), -+ MTK_PIN( -+ 126, "GPIO126", -+ MTK_EINT_FUNCTION(0, 126), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO126"), -+ MTK_FUNCTION(1, "O_SOUNDWIRE1_CK"), -+ MTK_FUNCTION(2, "O_I2SIN_1_BCK"), -+ MTK_FUNCTION(4, "O_CLUSTER0_AD_ILDO_DTEST4"), -+ MTK_FUNCTION(5, "O_CLUSTER1_AD_ILDO_DTEST4"), -+ MTK_FUNCTION(6, "I0_ADSP_JTAG0_TCK"), -+ MTK_FUNCTION(7, "I1_HFRP_JTAG0_TCK") -+ ), -+ MTK_PIN( -+ 127, "GPIO127", -+ MTK_EINT_FUNCTION(0, 127), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO127"), -+ MTK_FUNCTION(1, "B0_SOUNDWIRE1_D0"), -+ MTK_FUNCTION(2, "O_I2SOUT1_DO"), -+ MTK_FUNCTION(4, "O_CLUSTER0_AD_ILDO_DTEST5"), -+ MTK_FUNCTION(5, "O_CLUSTER1_AD_ILDO_DTEST5"), -+ MTK_FUNCTION(6, "I1_ADSP_JTAG0_TMS"), -+ MTK_FUNCTION(7, "B1_HFRP_JTAG0_TMS") -+ ), -+ MTK_PIN( -+ 128, "GPIO128", -+ MTK_EINT_FUNCTION(0, 128), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO128"), -+ MTK_FUNCTION(1, "B0_SOUNDWIRE1_D1"), -+ MTK_FUNCTION(2, "I0_I2SIN_1_DI"), -+ MTK_FUNCTION(4, "O_CLUSTER0_AD_ILDO_DTEST6"), -+ MTK_FUNCTION(5, "O_CLUSTER1_AD_ILDO_DTEST6"), -+ MTK_FUNCTION(6, "I1_ADSP_JTAG0_TDI"), -+ MTK_FUNCTION(7, "I1_HFRP_JTAG0_TDI") -+ ), -+ MTK_PIN( -+ 129, "GPIO129", -+ MTK_EINT_FUNCTION(0, 129), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO129"), -+ MTK_FUNCTION(1, "B0_SOUNDWIRE1_D2"), -+ MTK_FUNCTION(2, "O_I2SIN_1_LRCK"), -+ MTK_FUNCTION(4, "O_CLUSTER0_AD_ILDO_DTEST7"), -+ MTK_FUNCTION(5, "O_CLUSTER1_AD_ILDO_DTEST7"), -+ MTK_FUNCTION(6, "O_ADSP_JTAG0_TDO"), -+ MTK_FUNCTION(7, "O_HFRP_JTAG0_TDO") -+ ), -+ MTK_PIN( -+ 130, "GPIO130", -+ MTK_EINT_FUNCTION(0, 130), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO130"), -+ MTK_FUNCTION(1, "B0_I2SIN0_BCK"), -+ MTK_FUNCTION(3, "O_DISP_CLKM0"), -+ MTK_FUNCTION(4, "I0_TSFDC_26M"), -+ MTK_FUNCTION(5, "I0_RG_TSFDC_LDO_EN"), -+ MTK_FUNCTION(6, "O_CCU0_URTS"), -+ MTK_FUNCTION(7, "O_DBG_MON_B4") -+ ), -+ MTK_PIN( -+ 131, "GPIO131", -+ MTK_EINT_FUNCTION(0, 131), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO131"), -+ MTK_FUNCTION(1, "I0_I2SIN0_DI"), -+ MTK_FUNCTION(3, "O_DISP_CLKM1"), -+ MTK_FUNCTION(4, "O_TSFDC_FOUT"), -+ MTK_FUNCTION(5, "I0_DA_TSFDC_LDO_MODE"), -+ MTK_FUNCTION(6, "I1_CCU0_UCTS"), -+ MTK_FUNCTION(7, "O_DBG_MON_B5") -+ ), -+ MTK_PIN( -+ 132, "GPIO132", -+ MTK_EINT_FUNCTION(0, 132), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO132"), -+ MTK_FUNCTION(1, "O_I2SOUT0_DO"), -+ MTK_FUNCTION(3, "O_DISP_CLKM2"), -+ MTK_FUNCTION(4, "O_TSFDC_SDO"), -+ MTK_FUNCTION(5, "I0_RG_TSFDC_LDO_REFSEL1"), -+ MTK_FUNCTION(6, "O_CCU1_URTS"), -+ MTK_FUNCTION(7, "O_DBG_MON_B6") -+ ), -+ MTK_PIN( -+ 133, "GPIO133", -+ MTK_EINT_FUNCTION(0, 133), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO133"), -+ MTK_FUNCTION(1, "B0_I2SIN0_LRCK"), -+ MTK_FUNCTION(3, "O_DISP_CLKM3"), -+ MTK_FUNCTION(4, "I0_TSFDC_SCF"), -+ MTK_FUNCTION(5, "I0_RG_TSFDC_LDO_REFSEL0"), -+ MTK_FUNCTION(6, "I1_CCU1_UCTS"), -+ MTK_FUNCTION(7, "O_DBG_MON_B7") -+ ), -+ MTK_PIN( -+ 134, "GPIO134", -+ MTK_EINT_FUNCTION(0, 134), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO134"), -+ MTK_FUNCTION(1, "B1_SCP_SCL1"), -+ MTK_FUNCTION(2, "B1_VADSP_SCL0"), -+ MTK_FUNCTION(3, "B1_SROOT_SCL"), -+ MTK_FUNCTION(4, "O_SSPM_UTXD_AO_VLP"), -+ MTK_FUNCTION(5, "O_SPI_HID_IRQ_S_MON0"), -+ MTK_FUNCTION(6, "I1_ADSP_JTAG0_TRSTN"), -+ MTK_FUNCTION(7, "O_DBG_MON_B8") -+ ), -+ MTK_PIN( -+ 135, "GPIO135", -+ MTK_EINT_FUNCTION(0, 135), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO135"), -+ MTK_FUNCTION(1, "B1_SCP_SDA1"), -+ MTK_FUNCTION(2, "B1_VADSP_SDA0"), -+ MTK_FUNCTION(3, "B1_SROOT_SDA"), -+ MTK_FUNCTION(4, "I1_SSPM_URXD_AO_VLP"), -+ MTK_FUNCTION(7, "O_DBG_MON_B9") -+ ), -+ MTK_PIN( -+ 136, "GPIO136", -+ MTK_EINT_FUNCTION(0, 136), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO136"), -+ MTK_FUNCTION(1, "O_CMVREF2"), -+ MTK_FUNCTION(2, "B1_SCP_SCL3"), -+ MTK_FUNCTION(3, "B1_VADSP_SCL0"), -+ MTK_FUNCTION(4, "B1_SCP_SCL1"), -+ MTK_FUNCTION(5, "I1_MD32_8_RXD"), -+ MTK_FUNCTION(6, "I1_MD32_9_RXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B10") -+ ), -+ MTK_PIN( -+ 137, "GPIO137", -+ MTK_EINT_FUNCTION(0, 137), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO137"), -+ MTK_FUNCTION(1, "O_CMVREF3"), -+ MTK_FUNCTION(2, "B1_SCP_SDA3"), -+ MTK_FUNCTION(3, "B1_VADSP_SDA0"), -+ MTK_FUNCTION(4, "B1_SCP_SDA1"), -+ MTK_FUNCTION(5, "O_MD32_8_GPIO0"), -+ MTK_FUNCTION(6, "O_MD32_9_GPIO0"), -+ MTK_FUNCTION(7, "O_DBG_MON_B11") -+ ), -+ MTK_PIN( -+ 138, "GPIO138", -+ MTK_EINT_FUNCTION(0, 138), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO138"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N3"), -+ MTK_FUNCTION(2, "I0_DISP_LSPII"), -+ MTK_FUNCTION(4, "O_CLKM1_B"), -+ MTK_FUNCTION(5, "O_MD32_8_TXD"), -+ MTK_FUNCTION(6, "O_MD32_9_TXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B12") -+ ), -+ MTK_PIN( -+ 139, "GPIO139", -+ MTK_EINT_FUNCTION(0, 139), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO139"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N4"), -+ MTK_FUNCTION(2, "O_DISP_HSYNC0"), -+ MTK_FUNCTION(3, "O_DISP_HSYNC1"), -+ MTK_FUNCTION(4, "O_CLKM0_A"), -+ MTK_FUNCTION(5, "O_CLKM0_B"), -+ MTK_FUNCTION(6, "O_CLKM0_C"), -+ MTK_FUNCTION(7, "O_DBG_MON_B13") -+ ), -+ MTK_PIN( -+ 140, "GPIO140", -+ MTK_EINT_FUNCTION(0, 140), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO140"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N5"), -+ MTK_FUNCTION(2, "O_DISP_VSYNC0"), -+ MTK_FUNCTION(3, "O_DISP_VSYNC1"), -+ MTK_FUNCTION(4, "O_CLKM1_A"), -+ MTK_FUNCTION(5, "O_CLKM1_B"), -+ MTK_FUNCTION(6, "O_CLKM1_C"), -+ MTK_FUNCTION(7, "O_DBG_MON_A14") -+ ), -+ MTK_PIN( -+ 141, "GPIO141", -+ MTK_EINT_FUNCTION(0, 141), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO141"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N6"), -+ MTK_FUNCTION(2, "O_DISP_HSYNC2"), -+ MTK_FUNCTION(3, "O_DISP_HSYNC3"), -+ MTK_FUNCTION(4, "O_CLKM2_A"), -+ MTK_FUNCTION(5, "O_CLKM2_B"), -+ MTK_FUNCTION(6, "O_CLKM2_C"), -+ MTK_FUNCTION(7, "O_DBG_MON_A15") -+ ), -+ MTK_PIN( -+ 142, "GPIO142", -+ MTK_EINT_FUNCTION(0, 142), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO142"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N7"), -+ MTK_FUNCTION(2, "O_DISP_VSYNC2"), -+ MTK_FUNCTION(3, "O_DISP_VSYNC3"), -+ MTK_FUNCTION(4, "O_CLKM3_A"), -+ MTK_FUNCTION(5, "O_CLKM3_B"), -+ MTK_FUNCTION(6, "O_CLKM3_C"), -+ MTK_FUNCTION(7, "O_DBG_MON_A16") -+ ), -+ MTK_PIN( -+ 143, "GPIO143", -+ MTK_EINT_FUNCTION(0, 143), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO143"), -+ MTK_FUNCTION(1, "I0_MCU_M_PMIC_POC_I"), -+ MTK_FUNCTION(2, "I0_JTCK_SEL1"), -+ MTK_FUNCTION(3, "O_JTAGAP_JTCK"), -+ MTK_FUNCTION(4, "I0_ADSP_JTAG1_TCK"), -+ MTK_FUNCTION(5, "I0_ADSP_JTAG0_TCK"), -+ MTK_FUNCTION(6, "I0_CLUSTER0_UDI_TCK"), -+ MTK_FUNCTION(7, "I0_CLUSTER1_UDI_TCK") -+ ), -+ MTK_PIN( -+ 144, "GPIO144", -+ MTK_EINT_FUNCTION(0, 144), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO144"), -+ MTK_FUNCTION(1, "I0_MCU_B_PMIC_POC_I"), -+ MTK_FUNCTION(2, "B1_JTMS_SEL1"), -+ MTK_FUNCTION(3, "O_JTAGAP_JTMS"), -+ MTK_FUNCTION(4, "I1_ADSP_JTAG1_TMS"), -+ MTK_FUNCTION(5, "I1_ADSP_JTAG0_TMS"), -+ MTK_FUNCTION(6, "I0_CLUSTER0_UDI_TMS"), -+ MTK_FUNCTION(7, "I0_CLUSTER1_UDI_TMS") -+ ), -+ MTK_PIN( -+ 145, "GPIO145", -+ MTK_EINT_FUNCTION(0, 145), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO145"), -+ MTK_FUNCTION(1, "I1_UCTS0"), -+ MTK_FUNCTION(2, "I1_JTDI_SEL1"), -+ MTK_FUNCTION(3, "O_JTAGAP_JTDI"), -+ MTK_FUNCTION(4, "I1_ADSP_JTAG1_TDI"), -+ MTK_FUNCTION(5, "I1_ADSP_JTAG0_TDI"), -+ MTK_FUNCTION(6, "I0_CLUSTER0_UDI_TDI_0"), -+ MTK_FUNCTION(7, "I0_CLUSTER1_UDI_TDI_0") -+ ), -+ MTK_PIN( -+ 146, "GPIO146", -+ MTK_EINT_FUNCTION(0, 146), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO146"), -+ MTK_FUNCTION(1, "O_URTS0"), -+ MTK_FUNCTION(2, "O_JTDO_SEL1"), -+ MTK_FUNCTION(3, "I0_JTAGAP_JTDO"), -+ MTK_FUNCTION(4, "O_ADSP_JTAG1_TDO"), -+ MTK_FUNCTION(5, "O_ADSP_JTAG0_TDO"), -+ MTK_FUNCTION(6, "O_CLUSTER0_UDI_TDO_0"), -+ MTK_FUNCTION(7, "O_CLUSTER1_UDI_TDO_0") -+ ), -+ MTK_PIN( -+ 147, "GPIO147", -+ MTK_EINT_FUNCTION(0, 147), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO147"), -+ MTK_FUNCTION(2, "I1_JTRSTn_SEL1"), -+ MTK_FUNCTION(3, "O_JTAGAP_JTRSTn"), -+ MTK_FUNCTION(4, "I1_ADSP_JTAG1_TRSTN"), -+ MTK_FUNCTION(5, "I1_ADSP_JTAG0_TRSTN"), -+ MTK_FUNCTION(6, "I0_CLUSTER0_UDI_NTRST"), -+ MTK_FUNCTION(7, "I0_CLUSTER1_UDI_NTRST") -+ ), -+ MTK_PIN( -+ 148, "GPIO148", -+ MTK_EINT_FUNCTION(0, 148), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO148"), -+ MTK_FUNCTION(1, "O_SRCLKENA0") -+ ), -+ MTK_PIN( -+ 149, "GPIO149", -+ MTK_EINT_FUNCTION(0, 149), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO149"), -+ MTK_FUNCTION(1, "O_SRCLKENA1") -+ ), -+ MTK_PIN( -+ 150, "GPIO150", -+ MTK_EINT_FUNCTION(0, 150), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO150"), -+ MTK_FUNCTION(2, "O_NVJTAG_SEL"), -+ MTK_FUNCTION(4, "I0_TSFDC_SDI"), -+ MTK_FUNCTION(5, "O_TSFDC_BG_COMP"), -+ MTK_FUNCTION(6, "O_CLKM3_C"), -+ MTK_FUNCTION(7, "I0_HFRP_JTAG0_TRSTN") -+ ), -+ MTK_PIN( -+ 151, "GPIO151", -+ MTK_EINT_FUNCTION(0, 151), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO151"), -+ MTK_FUNCTION(1, "I1_JTRSTn_SEL1"), -+ MTK_FUNCTION(2, "O_JTAGAP_JTRSTn"), -+ MTK_FUNCTION(6, "I0_HFRP_JTAG1_TRSTN"), -+ MTK_FUNCTION(7, "I1_ADSP_JTAG1_TRSTN") -+ ), -+ MTK_PIN( -+ 152, "GPIO152", -+ MTK_EINT_FUNCTION(0, 152), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO152"), -+ MTK_FUNCTION(1, "B1_JTMS_SEL1"), -+ MTK_FUNCTION(2, "O_JTAGAP_JTMS"), -+ MTK_FUNCTION(6, "I1_HFRP_JTAG1_TMS"), -+ MTK_FUNCTION(7, "I1_ADSP_JTAG1_TMS") -+ ), -+ MTK_PIN( -+ 153, "GPIO153", -+ MTK_EINT_FUNCTION(0, 153), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO153"), -+ MTK_FUNCTION(1, "O_JTDO_SEL1"), -+ MTK_FUNCTION(2, "I0_JTAGAP_JTDO"), -+ MTK_FUNCTION(6, "O_HFRP_JTAG1_TDO"), -+ MTK_FUNCTION(7, "O_ADSP_JTAG1_TDO") -+ ), -+ MTK_PIN( -+ 154, "GPIO154", -+ MTK_EINT_FUNCTION(0, 154), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO154"), -+ MTK_FUNCTION(1, "I0_JTCK_SEL1"), -+ MTK_FUNCTION(2, "O_JTAGAP_JTCK"), -+ MTK_FUNCTION(6, "I1_HFRP_JTAG1_TCK"), -+ MTK_FUNCTION(7, "I0_ADSP_JTAG1_TCK") -+ ), -+ MTK_PIN( -+ 155, "GPIO155", -+ MTK_EINT_FUNCTION(0, 155), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO155"), -+ MTK_FUNCTION(1, "I1_JTDI_SEL1"), -+ MTK_FUNCTION(2, "O_JTAGAP_JTDI"), -+ MTK_FUNCTION(6, "I1_HFRP_JTAG1_TDI"), -+ MTK_FUNCTION(7, "I1_ADSP_JTAG1_TDI") -+ ), -+ MTK_PIN( -+ 156, "GPIO156", -+ MTK_EINT_FUNCTION(0, 156), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO156"), -+ MTK_FUNCTION(1, "O_TP_UTXD0_VLP"), -+ MTK_FUNCTION(2, "O_UTXD3"), -+ MTK_FUNCTION(3, "O_VADSP_UTXD1"), -+ MTK_FUNCTION(4, "O_SPI_SIO0_S_MON0"), -+ MTK_FUNCTION(5, "O_ADSP_UTXD1"), -+ MTK_FUNCTION(6, "I0_SROOT_TCK"), -+ MTK_FUNCTION(7, "O_OSROOT_UTX") -+ ), -+ MTK_PIN( -+ 157, "GPIO157", -+ MTK_EINT_FUNCTION(0, 157), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO157"), -+ MTK_FUNCTION(1, "I1_TP_URXD0_VLP"), -+ MTK_FUNCTION(2, "I1_URXD3"), -+ MTK_FUNCTION(3, "I1_VADSP_URXD1"), -+ MTK_FUNCTION(4, "O_SPI_SIO1_S_MON0"), -+ MTK_FUNCTION(5, "I1_ADSP_URXD1"), -+ MTK_FUNCTION(6, "I0_SROOT_TDI"), -+ MTK_FUNCTION(7, "I1_OSROOT_URX") -+ ), -+ MTK_PIN( -+ 158, "GPIO158", -+ MTK_EINT_FUNCTION(0, 158), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO158"), -+ MTK_FUNCTION(1, "O_TP_URTS0_VLP"), -+ MTK_FUNCTION(2, "O_URTS3"), -+ MTK_FUNCTION(3, "O_VADSP_URTS1"), -+ MTK_FUNCTION(4, "O_SPI_SIO2_S_MON0"), -+ MTK_FUNCTION(5, "O_ADSP_URTX1"), -+ MTK_FUNCTION(6, "O_SROOT_TDO"), -+ MTK_FUNCTION(7, "O_PBUD_CTRL_UTXD_AO_VLP") -+ ), -+ MTK_PIN( -+ 159, "GPIO159", -+ MTK_EINT_FUNCTION(0, 159), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO159"), -+ MTK_FUNCTION(1, "I1_TP_UCTS0_VLP"), -+ MTK_FUNCTION(2, "I1_UCTS3"), -+ MTK_FUNCTION(3, "I1_VADSP_UCTS1"), -+ MTK_FUNCTION(4, "O_SPI_SIO3_S_MON0"), -+ MTK_FUNCTION(5, "I1_ADSP_UCTS1"), -+ MTK_FUNCTION(6, "I0_SROOT_TMS"), -+ MTK_FUNCTION(7, "I1_PBUD_CTRL_URXD_AO_VLP") -+ ), -+ MTK_PIN( -+ 160, "GPIO160", -+ MTK_EINT_FUNCTION(0, 160), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO160"), -+ MTK_FUNCTION(1, "O_UTXD1"), -+ MTK_FUNCTION(2, "O_ADSP_UTXD1"), -+ MTK_FUNCTION(3, "O_HFRP_UTXD1"), -+ MTK_FUNCTION(4, "O_CCU1_UTXD"), -+ MTK_FUNCTION(5, "O_PBUD_CTRL_UTXD_AO_VCORE"), -+ MTK_FUNCTION(6, "O_U4CP_UTXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B14") -+ ), -+ MTK_PIN( -+ 161, "GPIO161", -+ MTK_EINT_FUNCTION(0, 161), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO161"), -+ MTK_FUNCTION(1, "I1_URXD1"), -+ MTK_FUNCTION(2, "I1_ADSP_URXD1"), -+ MTK_FUNCTION(3, "I1_HFRP_URXD1"), -+ MTK_FUNCTION(4, "I1_CCU1_URXD"), -+ MTK_FUNCTION(5, "I1_PBUD_CTRL_URXD_AO_VCORE"), -+ MTK_FUNCTION(6, "I1_U4CP_URXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B15") -+ ), -+ MTK_PIN( -+ 162, "GPIO162", -+ MTK_EINT_FUNCTION(0, 162), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO162"), -+ MTK_FUNCTION(1, "O_URTS1"), -+ MTK_FUNCTION(2, "O_ADSP_URTX1"), -+ MTK_FUNCTION(3, "O_HFRP_URTS1"), -+ MTK_FUNCTION(4, "O_CCU0_UTXD"), -+ MTK_FUNCTION(5, "O_PBUD_CTRL_UTXD_AO_VCORE"), -+ MTK_FUNCTION(6, "O_U4CP_URTS"), -+ MTK_FUNCTION(7, "O_DBG_MON_B16") -+ ), -+ MTK_PIN( -+ 163, "GPIO163", -+ MTK_EINT_FUNCTION(0, 163), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO163"), -+ MTK_FUNCTION(1, "I1_UCTS1"), -+ MTK_FUNCTION(2, "I1_ADSP_UCTS1"), -+ MTK_FUNCTION(3, "I1_HFRP_UCTS1"), -+ MTK_FUNCTION(4, "I1_CCU0_URXD"), -+ MTK_FUNCTION(5, "I1_PBUD_CTRL_URXD_AO_VCORE"), -+ MTK_FUNCTION(6, "I1_U4CP_UCTS"), -+ MTK_FUNCTION(7, "O_DBG_MON_B17") -+ ), -+ MTK_PIN( -+ 164, "GPIO164", -+ MTK_EINT_FUNCTION(0, 164), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO164"), -+ MTK_FUNCTION(1, "O_HDMITX_DC_CTRL"), -+ MTK_FUNCTION(6, "I0_SROOT_NTRST"), -+ MTK_FUNCTION(7, "O_DBG_MON_B18") -+ ), -+ MTK_PIN( -+ 165, "GPIO165", -+ MTK_EINT_FUNCTION(0, 165), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO165"), -+ MTK_FUNCTION(1, "B1_DISP_SCL0"), -+ MTK_FUNCTION(4, "I1_EDP0_SCL"), -+ MTK_FUNCTION(5, "O_CCU0_URTS"), -+ MTK_FUNCTION(6, "O_CCU1_URTS"), -+ MTK_FUNCTION(7, "I1_MD32_6_RXD") -+ ), -+ MTK_PIN( -+ 166, "GPIO166", -+ MTK_EINT_FUNCTION(0, 166), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO166"), -+ MTK_FUNCTION(1, "B1_DISP_SDA0"), -+ MTK_FUNCTION(4, "B1_EDP0_SDA"), -+ MTK_FUNCTION(5, "I1_CCU0_UCTS"), -+ MTK_FUNCTION(6, "I1_CCU1_UCTS"), -+ MTK_FUNCTION(7, "O_MD32_6_GPIO0") -+ ), -+ MTK_PIN( -+ 167, "GPIO167", -+ MTK_EINT_FUNCTION(0, 167), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO167"), -+ MTK_FUNCTION(1, "B0_DISP_GPIO_N0"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST0"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST0"), -+ MTK_FUNCTION(7, "O_DBG_MON_B19") -+ ), -+ MTK_PIN( -+ 168, "GPIO168", -+ MTK_EINT_FUNCTION(0, 168), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO168"), -+ MTK_FUNCTION(1, "I0_DPAUX_HPD_IN_0"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST1"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST1"), -+ MTK_FUNCTION(7, "O_DBG_MON_B20") -+ ), -+ MTK_PIN( -+ 169, "GPIO169", -+ MTK_EINT_FUNCTION(0, 169), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO169"), -+ MTK_FUNCTION(1, "I0_DPAUX_HPD_IN_1"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST3"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST3"), -+ MTK_FUNCTION(7, "O_DBG_MON_B21") -+ ), -+ MTK_PIN( -+ 170, "GPIO170", -+ MTK_EINT_FUNCTION(0, 170), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO170"), -+ MTK_FUNCTION(1, "O_USB4_R_TCPC_RESET"), -+ MTK_FUNCTION(5, "O_CLUSTER0_AD_ILDO_DTEST2"), -+ MTK_FUNCTION(6, "O_CLUSTER1_AD_ILDO_DTEST2"), -+ MTK_FUNCTION(7, "O_DBG_MON_A17") -+ ), -+ MTK_PIN( -+ 171, "GPIO171", -+ MTK_EINT_FUNCTION(0, 171), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO171"), -+ MTK_FUNCTION(1, "O_PCIE_PERSTN"), -+ MTK_FUNCTION(4, "O_MD32_14_GPIO0"), -+ MTK_FUNCTION(7, "O_DBG_MON_B22") -+ ), -+ MTK_PIN( -+ 172, "GPIO172", -+ MTK_EINT_FUNCTION(0, 172), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO172"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_0P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_0P"), -+ MTK_FUNCTION(5, "O_HFRP_UTXD1"), -+ MTK_FUNCTION(6, "O_CCU0_UTXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B23") -+ ), -+ MTK_PIN( -+ 173, "GPIO173", -+ MTK_EINT_FUNCTION(0, 173), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO173"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_1P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_1P"), -+ MTK_FUNCTION(5, "I1_HFRP_URXD1"), -+ MTK_FUNCTION(6, "I1_CCU0_URXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B24") -+ ), -+ MTK_PIN( -+ 174, "GPIO174", -+ MTK_EINT_FUNCTION(0, 174), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO174"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_2P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_2P"), -+ MTK_FUNCTION(4, "O_MD32PCM_UTXD_AO_VLP"), -+ MTK_FUNCTION(5, "O_HFRP_URTS1"), -+ MTK_FUNCTION(6, "O_CCU1_UTXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B25") -+ ), -+ MTK_PIN( -+ 175, "GPIO175", -+ MTK_EINT_FUNCTION(0, 175), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO175"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_3P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_3P"), -+ MTK_FUNCTION(4, "I1_MD32PCM_URXD_AO_VLP"), -+ MTK_FUNCTION(5, "I1_HFRP_UCTS1"), -+ MTK_FUNCTION(6, "I1_CCU1_URXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B26") -+ ), -+ MTK_PIN( -+ 176, "GPIO176", -+ MTK_EINT_FUNCTION(0, 176), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO176"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_4P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_4P"), -+ MTK_FUNCTION(4, "O_MD32_14_TXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B27") -+ ), -+ MTK_PIN( -+ 177, "GPIO177", -+ MTK_EINT_FUNCTION(0, 177), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO177"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_5P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_5P"), -+ MTK_FUNCTION(4, "I1_MD32_14_RXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B28") -+ ), -+ MTK_PIN( -+ 178, "GPIO178", -+ MTK_EINT_FUNCTION(0, 178), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO178"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_6P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_6P"), -+ MTK_FUNCTION(4, "O_MD32_15_TXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B29") -+ ), -+ MTK_PIN( -+ 179, "GPIO179", -+ MTK_EINT_FUNCTION(0, 179), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO179"), -+ MTK_FUNCTION(1, "B1_PCIE_CLKREQN_7P"), -+ MTK_FUNCTION(2, "I1_PCIE_PRSNT_7P"), -+ MTK_FUNCTION(4, "I1_MD32_15_RXD"), -+ MTK_FUNCTION(7, "O_DBG_MON_B30") -+ ), -+ MTK_PIN( -+ 180, "GPIO180", -+ MTK_EINT_FUNCTION(0, 180), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO180"), -+ MTK_FUNCTION(1, "I1_PCIE_WAKEN"), -+ MTK_FUNCTION(4, "O_MD32_15_GPIO0"), -+ MTK_FUNCTION(7, "O_DBG_MON_B31") -+ ), -+ MTK_PIN( -+ 181, "GPIO181", -+ MTK_EINT_FUNCTION(0, 181), -+ DRV_GRP4, -+ MTK_FUNCTION(0, "B_GPIO181"), -+ MTK_FUNCTION(1, "O_GPU_PWRGOOD") -+ ), -+}; -+ -+static struct mtk_eint_pin eint_pins_mt8901[] = { -+ MTK_EINT_PIN(0, 0, 16, 0), -+ MTK_EINT_PIN(1, 0, 17, 0), -+ MTK_EINT_PIN(2, 0, 18, 0), -+ MTK_EINT_PIN(3, 0, 19, 0), -+ MTK_EINT_PIN(4, 0, 20, 0), -+ MTK_EINT_PIN(5, 0, 21, 0), -+ MTK_EINT_PIN(6, 0, 22, 0), -+ MTK_EINT_PIN(7, 0, 23, 0), -+ MTK_EINT_PIN(8, 0, 24, 0), -+ MTK_EINT_PIN(9, 0, 25, 0), -+ MTK_EINT_PIN(10, 0, 26, 0), -+ MTK_EINT_PIN(11, 0, 27, 0), -+ MTK_EINT_PIN(12, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(13, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(14, 0, 28, 0), -+ MTK_EINT_PIN(15, 0, 29, 0), -+ MTK_EINT_PIN(16, 0, 30, 0), -+ MTK_EINT_PIN(17, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(18, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(19, 0, 31, 0), -+ MTK_EINT_PIN(20, 0, 0, 1), -+ MTK_EINT_PIN(21, 0, 1, 1), -+ MTK_EINT_PIN(22, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(23, 0, 2, 1), -+ MTK_EINT_PIN(24, 0, 3, 1), -+ MTK_EINT_PIN(25, 0, 4, 1), -+ MTK_EINT_PIN(26, 0, 5, 1), -+ MTK_EINT_PIN(27, 0, 6, 1), -+ MTK_EINT_PIN(28, 0, 7, 1), -+ MTK_EINT_PIN(29, 0, 8, 1), -+ MTK_EINT_PIN(30, 0, 9, 1), -+ MTK_EINT_PIN(31, 0, 10, 1), -+ MTK_EINT_PIN(32, 1, 0, 1), -+ MTK_EINT_PIN(33, 0, 32, 0), -+ MTK_EINT_PIN(34, 0, 33, 0), -+ MTK_EINT_PIN(35, 0, 34, 0), -+ MTK_EINT_PIN(36, 1, 1, 1), -+ MTK_EINT_PIN(37, 0, 11, 1), -+ MTK_EINT_PIN(38, 0, 12, 1), -+ MTK_EINT_PIN(39, 0, 35, 0), -+ MTK_EINT_PIN(40, 0, 36, 0), -+ MTK_EINT_PIN(41, 0, 37, 0), -+ MTK_EINT_PIN(42, 0, 13, 1), -+ MTK_EINT_PIN(43, 0, 14, 1), -+ MTK_EINT_PIN(44, 0, 38, 0), -+ MTK_EINT_PIN(45, 0, 39, 0), -+ MTK_EINT_PIN(46, 0, 40, 0), -+ MTK_EINT_PIN(47, 0, 15, 1), -+ MTK_EINT_PIN(48, 0, 41, 0), -+ MTK_EINT_PIN(49, 0, 42, 0), -+ MTK_EINT_PIN(50, 0, 43, 0), -+ MTK_EINT_PIN(51, 0, 44, 0), -+ MTK_EINT_PIN(52, 0, 45, 0), -+ MTK_EINT_PIN(53, 0, 46, 0), -+ MTK_EINT_PIN(54, 2, 13, 0), -+ MTK_EINT_PIN(55, 2, 14, 0), -+ MTK_EINT_PIN(56, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(57, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(58, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(59, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(60, 1, 3, 0), -+ MTK_EINT_PIN(61, 1, 4, 0), -+ MTK_EINT_PIN(62, 1, 5, 0), -+ MTK_EINT_PIN(63, 1, 6, 0), -+ MTK_EINT_PIN(64, 1, 7, 0), -+ MTK_EINT_PIN(65, 1, 8, 0), -+ MTK_EINT_PIN(66, 2, 15, 0), -+ MTK_EINT_PIN(67, 2, 16, 0), -+ MTK_EINT_PIN(68, 1, 2, 1), -+ MTK_EINT_PIN(69, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(70, 2, 17, 0), -+ MTK_EINT_PIN(71, 2, 18, 0), -+ MTK_EINT_PIN(72, 2, 19, 0), -+ MTK_EINT_PIN(73, 2, 20, 0), -+ MTK_EINT_PIN(74, 2, 21, 0), -+ MTK_EINT_PIN(75, 2, 22, 0), -+ MTK_EINT_PIN(76, 2, 23, 0), -+ MTK_EINT_PIN(77, 2, 24, 0), -+ MTK_EINT_PIN(78, 2, 25, 0), -+ MTK_EINT_PIN(79, 2, 26, 0), -+ MTK_EINT_PIN(80, 2, 27, 0), -+ MTK_EINT_PIN(81, 2, 28, 0), -+ MTK_EINT_PIN(82, 2, 29, 1), -+ MTK_EINT_PIN(83, 2, 30, 1), -+ MTK_EINT_PIN(84, 2, 31, 1), -+ MTK_EINT_PIN(85, 2, 32, 1), -+ MTK_EINT_PIN(86, 2, 33, 0), -+ MTK_EINT_PIN(87, 2, 34, 0), -+ MTK_EINT_PIN(88, 2, 35, 0), -+ MTK_EINT_PIN(89, 2, 36, 0), -+ MTK_EINT_PIN(90, 2, 37, 0), -+ MTK_EINT_PIN(91, 2, 38, 0), -+ MTK_EINT_PIN(92, 2, 39, 0), -+ MTK_EINT_PIN(93, 2, 40, 0), -+ MTK_EINT_PIN(94, 2, 0, 1), -+ MTK_EINT_PIN(95, 2, 1, 1), -+ MTK_EINT_PIN(96, 2, 2, 1), -+ MTK_EINT_PIN(97, 2, 3, 1), -+ MTK_EINT_PIN(98, 2, 41, 0), -+ MTK_EINT_PIN(99, 2, 4, 1), -+ MTK_EINT_PIN(100, 2, 5, 1), -+ MTK_EINT_PIN(101, 2, 6, 1), -+ MTK_EINT_PIN(102, 2, 7, 1), -+ MTK_EINT_PIN(103, 2, 8, 1), -+ MTK_EINT_PIN(104, 2, 9, 1), -+ MTK_EINT_PIN(105, 2, 10, 1), -+ MTK_EINT_PIN(106, 0, 47, 0), -+ MTK_EINT_PIN(107, 0, 48, 0), -+ MTK_EINT_PIN(108, 0, 49, 0), -+ MTK_EINT_PIN(109, 0, 50, 0), -+ MTK_EINT_PIN(110, 0, 51, 0), -+ MTK_EINT_PIN(111, 0, 52, 0), -+ MTK_EINT_PIN(112, 2, 42, 0), -+ MTK_EINT_PIN(113, 2, 43, 0), -+ MTK_EINT_PIN(114, 2, 44, 0), -+ MTK_EINT_PIN(115, 2, 45, 0), -+ MTK_EINT_PIN(116, 2, 46, 0), -+ MTK_EINT_PIN(117, 2, 47, 0), -+ MTK_EINT_PIN(118, 2, 48, 0), -+ MTK_EINT_PIN(119, 2, 49, 0), -+ MTK_EINT_PIN(120, 2, 50, 0), -+ MTK_EINT_PIN(121, 2, 51, 0), -+ MTK_EINT_PIN(122, 2, 52, 0), -+ MTK_EINT_PIN(123, 2, 53, 0), -+ MTK_EINT_PIN(124, 2, 54, 0), -+ MTK_EINT_PIN(125, 2, 55, 0), -+ MTK_EINT_PIN(126, 2, 56, 0), -+ MTK_EINT_PIN(127, 2, 57, 0), -+ MTK_EINT_PIN(128, 2, 58, 0), -+ MTK_EINT_PIN(129, 2, 59, 0), -+ MTK_EINT_PIN(130, 2, 60, 0), -+ MTK_EINT_PIN(131, 2, 61, 0), -+ MTK_EINT_PIN(132, 2, 62, 0), -+ MTK_EINT_PIN(133, 2, 63, 0), -+ MTK_EINT_PIN(134, 2, 64, 0), -+ MTK_EINT_PIN(135, 2, 65, 0), -+ MTK_EINT_PIN(136, 2, 66, 0), -+ MTK_EINT_PIN(137, 2, 67, 0), -+ MTK_EINT_PIN(138, 2, 11, 1), -+ MTK_EINT_PIN(139, 2, 12, 1), -+ MTK_EINT_PIN(140, 2, 68, 0), -+ MTK_EINT_PIN(141, 2, 69, 0), -+ MTK_EINT_PIN(142, 2, 70, 0), -+ MTK_EINT_PIN(143, 2, 71, 0), -+ MTK_EINT_PIN(144, 2, 72, 0), -+ MTK_EINT_PIN(145, 2, 73, 0), -+ MTK_EINT_PIN(146, 2, 74, 0), -+ MTK_EINT_PIN(147, 2, 75, 0), -+ MTK_EINT_PIN(148, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(149, INVALID_BASE, 0, 0), -+ MTK_EINT_PIN(150, 2, 76, 0), -+ MTK_EINT_PIN(151, 2, 77, 0), -+ MTK_EINT_PIN(152, 2, 78, 0), -+ MTK_EINT_PIN(153, 2, 79, 0), -+ MTK_EINT_PIN(154, 2, 80, 0), -+ MTK_EINT_PIN(155, 2, 81, 0), -+ MTK_EINT_PIN(156, 2, 82, 0), -+ MTK_EINT_PIN(157, 2, 83, 0), -+ MTK_EINT_PIN(158, 2, 84, 0), -+ MTK_EINT_PIN(159, 2, 85, 0), -+ MTK_EINT_PIN(160, 2, 86, 0), -+ MTK_EINT_PIN(161, 2, 87, 0), -+ MTK_EINT_PIN(162, 2, 88, 0), -+ MTK_EINT_PIN(163, 2, 89, 0), -+ MTK_EINT_PIN(164, 2, 90, 0), -+ MTK_EINT_PIN(165, 2, 91, 0), -+ MTK_EINT_PIN(166, 2, 92, 0), -+ MTK_EINT_PIN(167, 2, 93, 0), -+ MTK_EINT_PIN(168, 2, 94, 0), -+ MTK_EINT_PIN(169, 2, 95, 0), -+ MTK_EINT_PIN(170, 2, 96, 0), -+ MTK_EINT_PIN(171, 2, 97, 0), -+ MTK_EINT_PIN(172, 2, 98, 0), -+ MTK_EINT_PIN(173, 2, 99, 0), -+ MTK_EINT_PIN(174, 2, 100, 0), -+ MTK_EINT_PIN(175, 2, 101, 0), -+ MTK_EINT_PIN(176, 2, 102, 0), -+ MTK_EINT_PIN(177, 2, 103, 0), -+ MTK_EINT_PIN(178, 2, 104, 0), -+ MTK_EINT_PIN(179, 2, 105, 0), -+ MTK_EINT_PIN(180, 2, 106, 0), -+ MTK_EINT_PIN(181, 3, 0, 0), -+ MTK_EINT_PIN(182, 3, 1, 0), -+ MTK_EINT_PIN(183, 3, 2, 0), -+ MTK_EINT_PIN(184, 3, 3, 0), -+ MTK_EINT_PIN(185, 3, 4, 0), -+ MTK_EINT_PIN(186, 3, 5, 0), -+ MTK_EINT_PIN(187, 3, 6, 0), -+ MTK_EINT_PIN(188, 3, 7, 0), -+ MTK_EINT_PIN(189, 3, 8, 0), -+ MTK_EINT_PIN(190, 3, 9, 0), -+ MTK_EINT_PIN(191, 3, 10, 0), -+ MTK_EINT_PIN(192, 3, 11, 0), -+ MTK_EINT_PIN(193, 3, 12, 0), -+ MTK_EINT_PIN(194, 3, 13, 0), -+ MTK_EINT_PIN(195, 3, 14, 0), -+ MTK_EINT_PIN(196, 3, 15, 0), -+ MTK_EINT_PIN(197, 3, 16, 0), -+ MTK_EINT_PIN(198, 3, 17, 0), -+ MTK_EINT_PIN(199, 3, 18, 0), -+ MTK_EINT_PIN(200, 3, 19, 0), -+ MTK_EINT_PIN(201, 3, 20, 0), -+ MTK_EINT_PIN(202, 3, 21, 0), -+ MTK_EINT_PIN(203, 3, 22, 0), -+ MTK_EINT_PIN(204, 3, 23, 0), -+ MTK_EINT_PIN(205, 3, 24, 0), -+ MTK_EINT_PIN(206, 3, 25, 0), -+ MTK_EINT_PIN(207, 3, 26, 0), -+ MTK_EINT_PIN(208, 3, 27, 0), -+}; -+ -+#endif /* __PINCTRL__MTK_MT8901_H */ -From e3bbb822c93750583080da20a0c24e3610d22033 Mon Sep 17 00:00:00 2001 -From: Us Chien -Date: Mon, 26 May 2025 17:46:21 +0800 -Subject: [PATCH] NVIDIA: SAUCE: MEDIATEK: usb: host: xhci-hub: fix MT89xx SoCs - return PORTLI value - -BugLink: https://bugs.launchpad.net/bugs/2125126 - -For DIGITS GB10, USB SuperSpeed Plus Gen2x1 device enumeration speed is -being shown as Gen2x2 in the dmesg log. - - usb 4-1: new SuperSpeed Plus Gen 2x2 USB device number 2 using xhci-hcd - -The USB3 link lanes count is recorded in the read-only -TLC and RLC fields of the PORTLI register. In MT89xx SoCs (used by GB10), -the lane count can be wrongly set to 2 instead of 1 for USB Gen2x1 -devices due to HW Bug. As per Table 7-13 in USB xHCI revision 1.2 -specification, the value 0x5 is for SuperSpeedPlus Gen2x1. - -This patch adds a SW WAR to read the port speed in PORTSC register. -If port speed value is 0x5, then the lane count can be updated to 1. - -Signed-off-by: Us Chien -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Kai-Heng Feng -Acked-by: Matthew R. Ochs -Acked-by: Jacob Martin -Acked-by: Abdur Rahman -Signed-off--by: Brad Figg - -(cherry picked from commit b5b3a58605e6 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit c65499578d0c4af75076eea7d9a44ba8476d34a7 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/usb/host/xhci-hub.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c -index b0264bd857..c2c2b74fb9 100644 ---- a/drivers/usb/host/xhci-hub.c -+++ b/drivers/usb/host/xhci-hub.c -@@ -1266,6 +1266,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - } - port_li = readl(&port->port_reg->portli); - status = xhci_get_ext_port_status(portsc, port_li); -+ -+ /* -+ * In MT8901 USB host controller, the lane count can be wrongly set -+ * to 2 instead of 1 for USB Gen2x1 devices due to a HW Bug. As a SW -+ * WAR, check if port speed is 0x5 (SuperSpeedPlus Gen2x1) in -+ * PORTSC register and update the lane count as 1. -+ */ -+ if ((xhci->quirks & XHCI_NVIDIA_MT8901_HOST) && -+ DEV_SUPERSPEEDPLUS(portsc)) -+ status &= ~0xff00; -+ - put_unaligned_le32(status, &buf[4]); - } - break; -From 06b0ddc88b7d74e64edcee03157627314252df42 Mon Sep 17 00:00:00 2001 -From: Housong Zhang -Date: Mon, 27 Jul 2026 11:33:03 +0530 -Subject: [PATCH] NVIDIA: SAUCE: i2c: mediatek: Add ACPI/MT8901 support and - firmware-managed clocks - -BugLink: https://bugs.launchpad.net/bugs/2163407 - -On MT8901-based platforms the I2C controllers are described through -ACPI (HID NVDA0200) rather than device tree. The upstream i2c-mt65xx -driver is DT-only: no acpi_match_table, no propagation of the ACPI -fwnode to the i2c_adapter device, and clock/timing properties read -through of_property_read_*() helpers that don't operate on ACPI nodes. -Compounding that, on these platforms firmware keeps the controller's -"main" and "dma" clocks running and does not expose them via the -Linux clk framework, so devm_clk_get() returns -ENOENT for both. - -Consequently the driver does not bind on ACPI systems: no i2c_adapter -is created, HID-over-I2C never enumerates child devices, and the -internal I2C keyboard stays silent. - -Wire up ACPI and accept firmware-managed clocks: - -* Add mt8901_compat (v3 register layout, default_parent_rate=124.8 MHz - as a stand-in for clk_get_rate() when no clock provider is exposed) - and an acpi_match_table entry NVDA0200 -> mt8901_compat. - -* Replace of_device_get_match_data() with device_get_match_data() in - probe (with a NULL-match check), and switch mtk_i2c_parse_dt() to - the fwnode-aware device_property_read_*() helpers so DT and ACPI - share the same probe path. - -* Call device_set_node(&adap->dev, dev_fwnode(&pdev->dev)) so the - ACPI fwnode reaches the i2c_adapter device; without it, - has_acpi_companion() on the adapter returns 0 and - i2c_acpi_register_devices() exits early, leaving HID children - unenumerated. - -* Gate devm_clk_get() for "main"/"dma" on has_acpi_companion() - use - devm_clk_get_optional() in the ACPI branch so absent clocks are - accepted, and substitute i2c->dev_comp->default_parent_rate when - mtk_i2c_set_speed() has no clock handle to query. - -Signed-off-by: Housong Zhang -Signed-off-by: Kiran Maddaraki -Acked-by: Jamie Nguyen -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/i2c/busses/i2c-mt65xx.c | 100 +++++++++++++++++++++++++++----- - 1 file changed, 85 insertions(+), 15 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c -index 307925fb78..ac6df7b999 100644 ---- a/drivers/i2c/busses/i2c-mt65xx.c -+++ b/drivers/i2c/busses/i2c-mt65xx.c -@@ -4,6 +4,7 @@ - * Author: Xudong Chen - */ - -+#include - #include - #include - #include -@@ -270,6 +271,14 @@ struct mtk_i2c_compatible { - unsigned char ltiming_adjust: 1; - unsigned char apdma_sync: 1; - unsigned char max_dma_support; -+ /* -+ * Parent clock rate to use when the platform does not expose a -+ * Linux clock provider for the I2C source clock (e.g. firmware- -+ * managed clocks under ACPI). Left zero on SoCs whose firmware -+ * exposes clocks through the clk framework; in that case the -+ * driver continues to call clk_get_rate() on a mandatory clock. -+ */ -+ unsigned int default_parent_rate; - }; - - struct mtk_i2c_ac_timing { -@@ -523,6 +532,26 @@ static const struct mtk_i2c_compatible mt8192_compat = { - .max_dma_support = 36, - }; - -+static const struct mtk_i2c_compatible mt8901_compat = { -+ .regs = mt_i2c_regs_v3, -+ .pmic_i2c = 0, -+ .dcm = 0, -+ .auto_restart = 1, -+ .aux_len_reg = 1, -+ .timing_adjust = 1, -+ .dma_sync = 0, -+ .ltiming_adjust = 1, -+ .apdma_sync = 1, -+ .max_dma_support = 40, -+ /* -+ * MT8901 I2C on firmware-managed platforms: the IP is clocked off -+ * a 124.8 MHz parent that is not exposed via clk_get_rate(). This -+ * value mirrors the rate the SoC input clock is programmed to by -+ * the boot loader. -+ */ -+ .default_parent_rate = 124800000, -+}; -+ - static const struct of_device_id mtk_i2c_of_match[] = { - { .compatible = "mediatek,mt2712-i2c", .data = &mt2712_compat }, - { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat }, -@@ -540,6 +569,14 @@ static const struct of_device_id mtk_i2c_of_match[] = { - }; - MODULE_DEVICE_TABLE(of, mtk_i2c_of_match); - -+#ifdef CONFIG_ACPI -+static const struct acpi_device_id mtk_i2c_acpi_match[] = { -+ { "NVDA0200", (kernel_ulong_t)&mt8901_compat }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, mtk_i2c_acpi_match); -+#endif -+ - static u16 mtk_i2c_readw(struct mtk_i2c *i2c, enum I2C_REGS_OFFSET reg) - { - return readw(i2c->base + i2c->dev_comp->regs[reg]); -@@ -1358,24 +1395,31 @@ static const struct i2c_algorithm mtk_i2c_algorithm = { - .functionality = mtk_i2c_functionality, - }; - --static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c) -+static int mtk_i2c_parse_fw(struct mtk_i2c *i2c) - { - int ret; - -- ret = of_property_read_u32(np, "clock-frequency", &i2c->speed_hz); -+ ret = device_property_read_u32(i2c->dev, "clock-frequency", -+ &i2c->speed_hz); - if (ret < 0) - i2c->speed_hz = I2C_MAX_STANDARD_MODE_FREQ; - -- ret = of_property_read_u32(np, "clock-div", &i2c->clk_src_div); -- if (ret < 0) -- return ret; -+ ret = device_property_read_u32(i2c->dev, "clock-div", -+ &i2c->clk_src_div); -+ if (ret < 0) { -+ if (has_acpi_companion(i2c->dev)) -+ i2c->clk_src_div = 1; -+ else -+ return ret; -+ } - - if (i2c->clk_src_div == 0) - return -EINVAL; - -- i2c->have_pmic = of_property_read_bool(np, "mediatek,have-pmic"); -- i2c->use_push_pull = -- of_property_read_bool(np, "mediatek,use-push-pull"); -+ i2c->have_pmic = device_property_read_bool(i2c->dev, -+ "mediatek,have-pmic"); -+ i2c->use_push_pull = device_property_read_bool(i2c->dev, -+ "mediatek,use-push-pull"); - - i2c_parse_fw_timings(i2c->dev, &i2c->timing_info, true); - -@@ -1387,6 +1431,7 @@ static int mtk_i2c_probe(struct platform_device *pdev) - int ret = 0; - struct mtk_i2c *i2c; - int i, irq, speed_clk; -+ unsigned int parent_rate; - - i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) -@@ -1406,10 +1451,12 @@ static int mtk_i2c_probe(struct platform_device *pdev) - - init_completion(&i2c->msg_complete); - -- i2c->dev_comp = of_device_get_match_data(&pdev->dev); -- i2c->adap.dev.of_node = pdev->dev.of_node; -+ i2c->dev_comp = device_get_match_data(&pdev->dev); -+ if (!i2c->dev_comp) -+ return -ENODEV; - i2c->dev = &pdev->dev; - i2c->adap.dev.parent = &pdev->dev; -+ device_set_node(&i2c->adap.dev, dev_fwnode(&pdev->dev)); - i2c->adap.owner = THIS_MODULE; - i2c->adap.algo = &mtk_i2c_algorithm; - i2c->adap.quirks = i2c->dev_comp->quirks; -@@ -1423,7 +1470,7 @@ static int mtk_i2c_probe(struct platform_device *pdev) - return PTR_ERR(i2c->adap.bus_regulator); - } - -- ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c); -+ ret = mtk_i2c_parse_fw(i2c); - if (ret) - return -EINVAL; - -@@ -1434,14 +1481,33 @@ static int mtk_i2c_probe(struct platform_device *pdev) - for (i = 0; i < I2C_MT65XX_CLK_MAX; i++) - i2c->clocks[i].id = i2c_mt65xx_clk_ids[i]; - -- /* Get clocks one by one, some may be optional */ -- i2c->clocks[I2C_MT65XX_CLK_MAIN].clk = devm_clk_get(&pdev->dev, "main"); -+ /* -+ * On DT-described platforms the "main" and "dma" clocks are -+ * mandatory and probe must fail loudly if they are missing or -+ * misconfigured. On platforms where firmware manages the I2C -+ * clocks and does not expose them via the clk framework (the -+ * ACPI case), there is no Linux clock provider to query; in -+ * that case fall through to devm_clk_get_optional() and rely -+ * on the per-compat default_parent_rate below to drive -+ * mtk_i2c_set_speed(). -+ */ -+ if (has_acpi_companion(&pdev->dev)) { -+ i2c->clocks[I2C_MT65XX_CLK_MAIN].clk = -+ devm_clk_get_optional(&pdev->dev, "main"); -+ i2c->clocks[I2C_MT65XX_CLK_DMA].clk = -+ devm_clk_get_optional(&pdev->dev, "dma"); -+ } else { -+ i2c->clocks[I2C_MT65XX_CLK_MAIN].clk = -+ devm_clk_get(&pdev->dev, "main"); -+ i2c->clocks[I2C_MT65XX_CLK_DMA].clk = -+ devm_clk_get(&pdev->dev, "dma"); -+ } -+ - if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_MAIN].clk)) { - dev_err(&pdev->dev, "cannot get main clock\n"); - return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_MAIN].clk); - } - -- i2c->clocks[I2C_MT65XX_CLK_DMA].clk = devm_clk_get(&pdev->dev, "dma"); - if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_DMA].clk)) { - dev_err(&pdev->dev, "cannot get dma clock\n"); - return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_DMA].clk); -@@ -1469,7 +1535,10 @@ static int mtk_i2c_probe(struct platform_device *pdev) - - strscpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name)); - -- mtk_i2c_set_speed(i2c, clk_get_rate(i2c->clocks[speed_clk].clk)); -+ parent_rate = i2c->clocks[speed_clk].clk -+ ? clk_get_rate(i2c->clocks[speed_clk].clk) -+ : i2c->dev_comp->default_parent_rate; -+ mtk_i2c_set_speed(i2c, parent_rate); - - if (i2c->dev_comp->max_dma_support > 32) { - ret = dma_set_mask(&pdev->dev, -@@ -1563,6 +1632,7 @@ static struct platform_driver mtk_i2c_driver = { - .name = I2C_DRV_NAME, - .pm = pm_sleep_ptr(&mtk_i2c_pm), - .of_match_table = mtk_i2c_of_match, -+ .acpi_match_table = ACPI_PTR(mtk_i2c_acpi_match), - }, - }; - -From 8799a0ed1132f83663a7f2770595bff4e1943624 Mon Sep 17 00:00:00 2001 -From: Kiran Maddaraki -Date: Thu, 6 Aug 2026 15:46:01 +0530 -Subject: [PATCH] NVIDIA: SAUCE: gpiolib: acpi: route - acpi_dev_gpio_irq_wake_get_by() debounce through the warn-only wrapper - -BugLink: https://bugs.launchpad.net/bugs/2163407 - -Mainline commit e4a77f9c85a5 ("gpiolib: acpi: Make set debounce errors -non fatal") introduced acpi_gpio_set_debounce_timeout() and converted -two of the three ACPI call sites that program a debounce timeout to -use it. The wrapper downgrades a set_config(PIN_CONFIG_INPUT_DEBOUNCE) -failure to a dev_warn() so that GPIO controllers which reject that -config (e.g. the MediaTek EINT block used behind pinctrl-paris, which -returns -EINVAL for any debounce request on an edge-triggered pin) -do not fail the whole GpioInt lookup. - -The third call site in acpi_dev_gpio_irq_wake_get_by() was not -converted by that commit and still returns the raw -EINVAL from -gpio_set_debounce_timeout(). On ACPI systems whose _CRS declares a -GpioInt with any DebounceTimeout on an edge-triggered pinctrl backend, -that error propagates through acpi_dev_gpio_irq_get() and its -callers, and the affected consumer (e.g. i2c_hid_acpi) fails to -bind - no HID children enumerate. - -Route this call site through the same warn-only wrapper so all three -ACPI debounce paths behave consistently. - -Fixes: 8dcb7a15a585 ("gpiolib: acpi: Take into account debounce settings") -Signed-off-by: Kiran Maddaraki -Acked-by: Jamie Nguyen -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/gpio/gpiolib-acpi-core.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-core.c -index 220f0ac420..a8673d6813 100644 ---- a/drivers/gpio/gpiolib-acpi-core.c -+++ b/drivers/gpio/gpiolib-acpi-core.c -@@ -1057,10 +1057,7 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *con_id, - if (ret < 0) - return ret; - -- /* ACPI uses hundredths of milliseconds units */ -- ret = gpio_set_debounce_timeout(desc, info.debounce * 10); -- if (ret) -- return ret; -+ acpi_gpio_set_debounce_timeout(desc, info.debounce); - - irq_flags = acpi_dev_get_irq_type(info.triggering, - info.polarity); -From 7cc0bbcbf8d9dde57669c83d0b02d82389dab4ff Mon Sep 17 00:00:00 2001 -From: Ankit Pant -Date: Thu, 9 Jul 2026 18:21:28 +0800 -Subject: [PATCH] NVIDIA: SAUCE: pinctrl: mt8901: Enable ACPI wake-event EINT - support - -BugLink: https://bugs.launchpad.net/bugs/2167299 - -On MT8901-based ACPI platforms some EINT wake sources belong to pins -that are owned by firmware and have no Linux consumer driver. Two -things are missing for such a pin to wake the SoC from system sleep. - -First, the EINT block only forwards a wake event to the SPM when the -pin's bit in the EINT event mask is cleared. Nothing in the driver -programs that register, so the event never reaches the SPM. - -Second, the ACPI GPIO interrupts declared in the controller's _AEI -are never requested after the pinctrl driver probes. Without that -request there is no IRQ consumer for the pin, so nothing calls -enable_irq_wake() on it, its bit in wake_mask stays clear, and -mtk_eint_do_suspend() masks the interrupt for the duration of -suspend. The SPM cannot see the event from a masked EINT. - -Add a wake-event pin list to mtk_eint so the SoC driver can declare -the pins whose event mask must be cleared, and clear it on init and -on resume so the setting survives suspend/resume. Declare EINT 20 for -MT8901. Call acpi_gpiochip_request_interrupts() once the GPIO chip has -been added so gpiolib-acpi requests the _AEI interrupts and, for the -wake-capable ones, calls enable_irq_wake(). That sets the pin's bit -in wake_mask through the normal irq_set_wake path, so the EINT stays -unmasked across suspend without any driver touching wake_mask directly. - -Signed-off-by: Ankit Pant -Signed-off-by: Kiran Maddaraki -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg - -[omarchy: 7.2.6 brought 88292b7103d2 ("pinctrl: mediatek: free EINT - resources on unbind"), so mtk_eint_do_init() now ends with - devm_add_action_or_reset(); the event unmask and the debug message go - before it] ---- - drivers/gpio/gpiolib-acpi.h | 9 ---- - drivers/pinctrl/mediatek/mtk-eint.c | 50 +++++++++++++++++++ - drivers/pinctrl/mediatek/mtk-eint.h | 9 ++++ - drivers/pinctrl/mediatek/pinctrl-mt8901.c | 4 ++ - .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 2 + - .../pinctrl/mediatek/pinctrl-mtk-common-v2.h | 4 +- - drivers/pinctrl/mediatek/pinctrl-paris.c | 20 ++++++++ - include/linux/gpio/driver.h | 8 +++ - 8 files changed, 96 insertions(+), 10 deletions(-) - -diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h -index a90267470..e4c18cbc8 100644 ---- a/drivers/gpio/gpiolib-acpi.h -+++ b/drivers/gpio/gpiolib-acpi.h -@@ -24,9 +24,6 @@ struct gpio_device; - void acpi_gpiochip_add(struct gpio_chip *chip); - void acpi_gpiochip_remove(struct gpio_chip *chip); - --void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); --void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); -- - struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode, - const char *con_id, - unsigned int idx, -@@ -38,12 +35,6 @@ int acpi_gpio_count(const struct fwnode_handle *fwnode, const char *con_id); - static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } - static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } - --static inline void --acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } -- --static inline void --acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } -- - static inline struct gpio_desc * - acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id, - unsigned int idx, enum gpiod_flags *dflags, -diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c -index e6a085255..1045597ad 100644 ---- a/drivers/pinctrl/mediatek/mtk-eint.c -+++ b/drivers/pinctrl/mediatek/mtk-eint.c -@@ -51,6 +51,9 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = { - .dbnc_ctrl = 0x500, - .dbnc_set = 0x600, - .dbnc_clr = 0x700, -+ .event = 0x800, -+ .event_set = 0x840, -+ .event_clr = 0x880, - }; - - const unsigned int debounce_time_mt2701[] = { -@@ -165,6 +168,47 @@ static void mtk_eint_unmask(struct irq_data *d) - mtk_eint_flip_edge(eint, d->hwirq); - } - -+/* -+ * Clear the event_clr bit for a single EINT so its wake-event is not -+ * suppressed. Mirrors mtk_eint_unmask() addressing: register is banked -+ * per instance and word-indexed by (idx / 32). -+ */ -+static void mtk_eint_event_unmask_one(struct mtk_eint *eint, -+ unsigned int eint_num) -+{ -+ unsigned int idx, inst; -+ unsigned int mask; -+ void __iomem *reg; -+ -+ if (eint_num >= eint->hw->ap_num) -+ return; -+ -+ idx = eint->pins[eint_num].index; -+ inst = eint->pins[eint_num].instance; -+ -+ if (inst >= eint->nbase) -+ return; -+ -+ mask = BIT(idx & 0x1f); -+ reg = mtk_eint_get_offset(eint, eint_num, eint->regs->event_clr); -+ writel(mask, reg); -+} -+ -+/* -+ * Clear the event mask of every pin in the SoC's eint_event_unmask list so -+ * their wake events reach the SPM after init and resume. -+ */ -+static void mtk_eint_apply_event_unmask(struct mtk_eint *eint) -+{ -+ unsigned int i; -+ -+ if (!eint->event_pins || !eint->num_event_pins) -+ return; -+ -+ for (i = 0; i < eint->num_event_pins; i++) -+ mtk_eint_event_unmask_one(eint, eint->event_pins[i]); -+} -+ - static unsigned int mtk_eint_get_mask(struct mtk_eint *eint, - unsigned int eint_num) - { -@@ -440,6 +484,7 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend); - int mtk_eint_do_resume(struct mtk_eint *eint) - { - mtk_eint_chip_write_mask(eint, eint->cur_mask); -+ mtk_eint_apply_event_unmask(eint); - - return 0; - } -@@ -628,6 +673,11 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin) - irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler, - eint); - -+ mtk_eint_apply_event_unmask(eint); -+ -+ dev_dbg(eint->dev, "%s completed, %u EINTs registered\n", -+ __func__, eint->hw->ap_num); -+ - return devm_add_action_or_reset(eint->dev, mtk_eint_teardown, eint); - - err_eint: -diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h -index 1b185f660..cbcca2830 100644 ---- a/drivers/pinctrl/mediatek/mtk-eint.h -+++ b/drivers/pinctrl/mediatek/mtk-eint.h -@@ -31,6 +31,9 @@ struct mtk_eint_regs { - unsigned int dbnc_ctrl; - unsigned int dbnc_set; - unsigned int dbnc_clr; -+ unsigned int event; -+ unsigned int event_set; -+ unsigned int event_clr; - }; - - struct mtk_eint_hw { -@@ -84,6 +87,12 @@ struct mtk_eint { - struct mtk_eint_pin *pins; - u16 num_db_time; - -+ /* Wake-event pin list: bits to clear in event_clr after init/resume -+ * so wake sources are not suppressed. -+ */ -+ const unsigned int *event_pins; -+ unsigned int num_event_pins; -+ - /* Used to fit into various pinctrl device */ - void *pctl; - const struct mtk_eint_xt *gpio_xlate; -diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8901.c b/drivers/pinctrl/mediatek/pinctrl-mt8901.c -index 623cd0cd5..09f3ec336 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mt8901.c -+++ b/drivers/pinctrl/mediatek/pinctrl-mt8901.c -@@ -1412,6 +1412,8 @@ static const struct mtk_eint_hw mt8901_eint_hw = { - .db_time = debounce_time_mt8901, - }; - -+static const unsigned int mt8901_eint_event_unmask[] = {20}; -+ - static const struct mtk_pin_soc mt8901_data = { - .reg_cal = mt8901_reg_cals, - .pins = mtk_pins_mt8901, -@@ -1432,6 +1434,8 @@ static const struct mtk_pin_soc mt8901_data = { - .drive_get = mtk_pinconf_drive_get_rev1, - .adv_drive_set = mtk_pinconf_adv_drive_set_raw, - .adv_drive_get = mtk_pinconf_adv_drive_get_raw, -+ .eint_event_unmask = mt8901_eint_event_unmask, -+ .num_eint_event_unmask = ARRAY_SIZE(mt8901_eint_event_unmask), - }; - - static const struct acpi_device_id mt8901_pinctrl_acpi_match[] = { -diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -index fc71f9b26..b246e4960 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -@@ -434,6 +434,8 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) - hw->eint->hw = hw->soc->eint_hw; - hw->eint->pctl = hw; - hw->eint->gpio_xlate = &mtk_eint_xt; -+ hw->eint->event_pins = hw->soc->eint_event_unmask; -+ hw->eint->num_event_pins = hw->soc->num_eint_event_unmask; - - ret = mtk_eint_do_init(hw->eint, hw->soc->eint_pin); - if (ret) -diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -index df8dce147..bf71a12b8 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -@@ -283,7 +283,9 @@ struct mtk_pin_soc { - const struct mtk_pin_desc *desc, u32 arg); - int (*adv_drive_get)(struct mtk_pinctrl *hw, - const struct mtk_pin_desc *desc, u32 *val); -- -+ /* EINTs whose event mask must be cleared so they can wake the SPM */ -+ const unsigned int *eint_event_unmask; -+ const unsigned int num_eint_event_unmask; - /* Specific driver data */ - void *driver_data; - }; -diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c -index 517801d4f..7da602170 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-paris.c -+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c -@@ -975,6 +975,13 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw) - return 0; - } - -+static void mtk_pinctrl_acpi_free_interrupts(void *data) -+{ -+ struct gpio_chip *chip = data; -+ -+ acpi_gpiochip_free_interrupts(chip); -+} -+ - static int mtk_pctrl_build_state(struct platform_device *pdev) - { - struct mtk_pinctrl *hw = platform_get_drvdata(pdev); -@@ -1096,6 +1103,19 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev) - return dev_err_probe(dev, err, "Failed to add gpio_chip\n"); - - pinctrl_add_gpio_range(hw->pctrl, &hw->range); -+ if (hw->eint) { -+ acpi_gpiochip_request_interrupts(&hw->chip); -+ -+ err = devm_add_action_or_reset(dev, -+ mtk_pinctrl_acpi_free_interrupts, -+ &hw->chip); -+ if (err) { -+ pinctrl_remove_gpio_range(hw->pctrl, &hw->range); -+ gpiochip_remove(&hw->chip); -+ return dev_err_probe(dev, err, -+ "Failed to add ACPI GPIO cleanup\n"); -+ } -+ } - - platform_set_drvdata(pdev, hw); - -diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h -index 17511434e..be3ab142d 100644 ---- a/include/linux/gpio/driver.h -+++ b/include/linux/gpio/driver.h -@@ -630,6 +630,14 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, - void *data, struct lock_class_key *lock_key, - struct lock_class_key *request_key); - -+#ifdef CONFIG_GPIO_ACPI -+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); -+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); -+#else -+static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } -+static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } -+#endif -+ - struct gpio_device *gpio_device_find(const void *data, - int (*match)(struct gpio_chip *gc, - const void *data)); --- -2.56.0 - -From 0ffc59d9b95596e7cfd10514718de638ddfaec85 Mon Sep 17 00:00:00 2001 -From: "shubham.paralikar" -Date: Wed, 8 Jul 2026 15:19:19 +0800 -Subject: [PATCH] NVIDIA: SAUCE: pinctrl: mediatek: Add bus-hold bias and - program-by-GPIO helper - -BugLink: https://bugs.launchpad.net/bugs/2167299 - -The MediaTek pinctrl bias code only knows pull-up and pull-down. The -pad "bus keeper" mode, with both PU and PD enabled, cannot be -requested or read back, yet the MT8901 SoundWire pads need it: the -ACPI _CRS for the SoundWire controller carries PinFunction() vendor -encodings that ask for bus-keeper on the data lines, and without it -codec enumeration fails unless the pad registers are written by hand. - -Add MTK_BUS_HOLD as a third pull mode in the PU/PD bias path and wire -PIN_CONFIG_BIAS_BUS_HOLD through the pinctrl-paris get/set handlers. -The generic bias-bus-hold property carries no argument, so the set -handler always requests MTK_ENABLE for it. Bus-hold is only -expressible through the PU/PD bits. The PULLSEL/PULLEN and R1R0 bias -paths reject it, and on pins that also have RSEL the RSEL step is -skipped so the request is served by PU/PD and the existing RSEL value -is retained. The bias getters report PU=1, PD=1 back as MTK_BUS_HOLD. - -Register every mtk_pinctrl instance in a global list at probe and -export mtk_pinctrl_program_bias_by_gpio() through -, so a client driver that parses -PinFunction() vendor encodings from its own _CRS can apply pad bias -by absolute SoC GPIO number without going through pinctrl states. -The instance is unregistered via a devm action so it leaves the list -before devm frees it, and it is registered before the gpiochip is -added so that a failure to install that action has nothing non-devm -to unwind. MediaTek pin numbers are zero-based per controller, so the -helper refuses with -EINVAL if more than one registered controller -could own the requested pin instead of programming whichever probed -first. Every supported platform registers a single pinctrl instance, -so this cannot trigger today. The helper returns -EPROBE_DEFER while -no controller has registered, so a consumer that probes before -pinctrl is retried by the driver core instead of treating the missing -controller as a firmware error. - -The helper bypasses the pinctrl core and therefore the core's -per-controller mutex that serialises normal pinconf operations. The -PU/PD setter writes the two bits as separate register updates, so a -helper call could interleave with a concurrent mtk_pinconf_set() on -the same pin and leave the pad in a state neither caller asked for -while both report success. Add a per-controller pinconf_lock mutex -taken by mtk_pinconf_set(), mtk_pinconf_get() and the helper so the -two paths exclude each other. - -Signed-off-by: shubham.paralikar -Signed-off-by: Kiran Maddaraki -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 171 +++++++++++++++++- - .../pinctrl/mediatek/pinctrl-mtk-common-v2.h | 20 ++ - drivers/pinctrl/mediatek/pinctrl-paris.c | 37 +++- - include/linux/soc/mediatek/mtk-pinctrl.h | 40 ++++ - 4 files changed, 260 insertions(+), 8 deletions(-) - create mode 100644 include/linux/soc/mediatek/mtk-pinctrl.h - -diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -index b246e49608..8d499ad9e2 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - - #include "mtk-eint.h" - #include "pinctrl-mtk-common-v2.h" -@@ -626,10 +627,15 @@ static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, - if (arg == MTK_DISABLE) { - pu = 0; - pd = 0; -- } else if ((arg == MTK_ENABLE) && pullup) { -+ } else if (arg == MTK_ENABLE && pullup == MTK_BUS_HOLD) { -+ if (pd_only) -+ return -EINVAL; /* Bus-hold needs both PU and PD. */ -+ pu = 1; -+ pd = 1; -+ } else if ((arg == MTK_ENABLE) && pullup == 1) { - pu = 1; - pd = 0; -- } else if ((arg == MTK_ENABLE) && !pullup) { -+ } else if ((arg == MTK_ENABLE) && pullup == 0) { - pu = 0; - pd = 1; - } else { -@@ -651,6 +657,12 @@ static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw, - { - int err, enable; - -+ /* Bus-hold is not supported for the PULLSEL/PULLEN path; reject explicitly */ -+ if (pullup == MTK_BUS_HOLD) { -+ err = -EINVAL; -+ goto out; -+ } -+ - if (arg == MTK_DISABLE) - enable = 0; - else if (arg == MTK_ENABLE) -@@ -676,6 +688,12 @@ static int mtk_pinconf_bias_set_pupd_r1_r0(struct mtk_pinctrl *hw, - { - int err, r0, r1; - -+ /* Bus-hold is not supported for R1R0 path; reject explicitly */ -+ if (pullup == MTK_BUS_HOLD) { -+ err = -EINVAL; -+ goto out; -+ } -+ - if ((arg == MTK_DISABLE) || (arg == MTK_PUPD_SET_R1R0_00)) { - pullup = 0; - r0 = 0; -@@ -796,10 +814,18 @@ int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, - else - try_all_type = MTK_PULL_TYPE_MASK; - -+ /* -+ * Explicitly handle bus-hold for RSEL type: skip the RSEL path when -+ * MTK_BUS_HOLD is requested. -+ */ - if (try_all_type & MTK_PULL_RSEL_TYPE) { -- err = mtk_pinconf_bias_set_pu_pd_rsel(hw, desc, pullup, arg); -- if (!err) -- return 0; -+ if (pullup == MTK_BUS_HOLD) { -+ /* Bus-hold not supported for RSEL */ -+ } else { -+ err = mtk_pinconf_bias_set_pu_pd_rsel(hw, desc, pullup, arg); -+ if (!err) -+ return 0; -+ } - } - - if (try_all_type & MTK_PULL_PD_TYPE) { -@@ -831,6 +857,128 @@ int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, - } - EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_combo); - -+/* -+ * Registry of active mtk_pinctrl instances so that client drivers -+ * (see mtk_pinctrl_program_bias_by_gpio) can resolve an absolute SoC -+ * pin number to the owning controller without having a device handle. -+ * Number of live controllers per system is small (typically 1-2), so a -+ * flat list guarded by a mutex is sufficient. -+ */ -+static LIST_HEAD(mtk_pinctrl_instances); -+static DEFINE_MUTEX(mtk_pinctrl_instances_lock); -+ -+void mtk_pinctrl_register_instance(struct mtk_pinctrl *hw) -+{ -+ mutex_lock(&mtk_pinctrl_instances_lock); -+ list_add_tail(&hw->instance_node, &mtk_pinctrl_instances); -+ mutex_unlock(&mtk_pinctrl_instances_lock); -+} -+EXPORT_SYMBOL_GPL(mtk_pinctrl_register_instance); -+ -+void mtk_pinctrl_unregister_instance(struct mtk_pinctrl *hw) -+{ -+ mutex_lock(&mtk_pinctrl_instances_lock); -+ list_del(&hw->instance_node); -+ mutex_unlock(&mtk_pinctrl_instances_lock); -+} -+EXPORT_SYMBOL_GPL(mtk_pinctrl_unregister_instance); -+ -+/* -+ * Translate the public API's constants to the pinctrl-internal ones. -+ * Kept explicit rather than assumed-equal so the two can evolve -+ * independently (client drivers do not include pinctrl-mtk-common-v2.h). -+ */ -+static int mtk_pinctrl_public_pullup_to_internal(u32 pub, u32 *out) -+{ -+ switch (pub) { -+ case MTK_PIN_PULLDOWN: -+ *out = MTK_PULLDOWN; -+ return 0; -+ case MTK_PIN_PULLUP: -+ *out = MTK_PULLUP; -+ return 0; -+ case MTK_PIN_BUS_HOLD: -+ *out = MTK_BUS_HOLD; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int mtk_pinctrl_public_arg_to_internal(u32 pub, u32 *out) -+{ -+ switch (pub) { -+ case MTK_PIN_ENABLE: -+ *out = MTK_ENABLE; -+ return 0; -+ case MTK_PIN_DISABLE: -+ *out = MTK_DISABLE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+int mtk_pinctrl_program_bias_by_gpio(unsigned int gpio, u32 pullup, u32 arg) -+{ -+ struct mtk_pinctrl *hw, *owner = NULL; -+ const struct mtk_pin_desc *desc; -+ u32 int_pullup, int_arg; -+ int err; -+ -+ err = mtk_pinctrl_public_pullup_to_internal(pullup, &int_pullup); -+ if (err) -+ return err; -+ err = mtk_pinctrl_public_arg_to_internal(arg, &int_arg); -+ if (err) -+ return err; -+ -+ mutex_lock(&mtk_pinctrl_instances_lock); -+ -+ /* -+ * Pin numbers are zero-based per controller, so refuse rather than -+ * guess if more than one registered instance covers @gpio. -+ */ -+ list_for_each_entry(hw, &mtk_pinctrl_instances, instance_node) { -+ if (gpio >= hw->soc->npins) -+ continue; -+ -+ if (hw->soc->pins[gpio].number != gpio) -+ continue; -+ -+ if (owner) { -+ dev_warn_once(hw->dev, -+ "pin %u also owned by %s, refusing ambiguous bias request\n", -+ gpio, dev_name(owner->dev)); -+ err = -EINVAL; -+ goto out; -+ } -+ owner = hw; -+ } -+ -+ if (!owner) { -+ /* No controller yet is a probe-order problem, not a bad pin. */ -+ err = list_empty(&mtk_pinctrl_instances) ? -EPROBE_DEFER : -ENODEV; -+ goto out; -+ } -+ -+ if (!owner->soc->bias_set_combo) { -+ err = -EOPNOTSUPP; -+ goto out; -+ } -+ -+ desc = &owner->soc->pins[gpio]; -+ mutex_lock(&owner->pinconf_lock); -+ err = owner->soc->bias_set_combo(owner, desc, int_pullup, int_arg); -+ mutex_unlock(&owner->pinconf_lock); -+ -+out: -+ mutex_unlock(&mtk_pinctrl_instances_lock); -+ -+ return err; -+} -+EXPORT_SYMBOL_GPL(mtk_pinctrl_program_bias_by_gpio); -+ - static int mtk_rsel_get_si_unit(struct mtk_pinctrl *hw, - const struct mtk_pin_desc *desc, - u32 pullup, u32 rsel_val, u32 *si_unit) -@@ -889,6 +1037,13 @@ static int mtk_pinconf_bias_get_pu_pd_rsel(struct mtk_pinctrl *hw, - mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable); - else - *enable = rsel + MTK_PULL_SET_RSEL_000; -+ } else if (pu == 1 && pd == 1) { -+ /* Keeper (bus-hold) reports pull-up resistance via up-RSEL lookup */ -+ *pullup = MTK_BUS_HOLD; -+ if (hw->rsel_si_unit) -+ mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable); -+ else -+ *enable = rsel + MTK_PULL_SET_RSEL_000; - } else { - err = -EINVAL; - goto out; -@@ -921,8 +1076,12 @@ static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw, - } else if (pu == 0 && pd == 1) { - *pullup = 0; - *enable = MTK_ENABLE; -- } else -+ } else if (pu == 1 && pd == 1) { -+ *pullup = MTK_BUS_HOLD; -+ *enable = MTK_ENABLE; -+ } else { - err = -EINVAL; -+ } - - out: - return err; -diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -index bf71a12b8a..5bb062c62b 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h -@@ -10,11 +10,14 @@ - #define __PINCTRL_MTK_COMMON_V2_H - - #include -+#include - - #define MTK_INPUT 0 - #define MTK_OUTPUT 1 - #define MTK_DISABLE 0 - #define MTK_ENABLE 1 -+#define MTK_BUS_HOLD 2 -+/* 0 = pull-down, 1 = pull-up, 2 = bus-hold (keeper: PU and PD both on) */ - #define MTK_PULLDOWN 0 - #define MTK_PULLUP 1 - #define MTK_PULL_PU_PD_TYPE BIT(0) -@@ -305,6 +308,14 @@ struct mtk_pinctrl { - /* identify rsel setting by si unit or rsel define in dts node */ - bool rsel_si_unit; - struct pinctrl_gpio_range range; -+ /* Registry node, see mtk_pinctrl_register_instance in common-v2.c */ -+ struct list_head instance_node; -+ /* -+ * Serialises pinconf_set/get (called under the pinctrl core's -+ * pctldev mutex) against mtk_pinctrl_program_bias_by_gpio(), -+ * which bypasses the core. PU and PD are written separately. -+ */ -+ struct mutex pinconf_lock; - }; - - void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set); -@@ -343,6 +354,15 @@ int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw, - const struct mtk_pin_desc *desc, - u32 *pullup, u32 *enable); - -+/* -+ * Internal registration hooks for the cross-driver bias helper. -+ * The public API (mtk_pinctrl_program_bias_by_gpio()) lives in -+ * . Only mtk_paris_pinctrl_probe() -+ * should call these. -+ */ -+void mtk_pinctrl_register_instance(struct mtk_pinctrl *hw); -+void mtk_pinctrl_unregister_instance(struct mtk_pinctrl *hw); -+ - int mtk_pinconf_drive_set(struct mtk_pinctrl *hw, - const struct mtk_pin_desc *desc, u32 arg); - int mtk_pinconf_drive_get(struct mtk_pinctrl *hw, -diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c -index c3f0196d2e..7ffa3b652a 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-paris.c -+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c -@@ -139,10 +139,12 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, - - desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; - -+ mutex_lock(&hw->pinconf_lock); - switch (param) { - case PIN_CONFIG_BIAS_DISABLE: - case PIN_CONFIG_BIAS_PULL_UP: - case PIN_CONFIG_BIAS_PULL_DOWN: -+ case PIN_CONFIG_BIAS_BUS_HOLD: - if (!hw->soc->bias_get_combo) - break; - err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); -@@ -154,10 +156,13 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, - if (ret != MTK_DISABLE) - err = -EINVAL; - } else if (param == PIN_CONFIG_BIAS_PULL_UP) { -- if (!pullup || ret == MTK_DISABLE) -+ if (pullup != 1 || ret == MTK_DISABLE) - err = -EINVAL; - } else if (param == PIN_CONFIG_BIAS_PULL_DOWN) { -- if (pullup || ret == MTK_DISABLE) -+ if (pullup != 0 || ret == MTK_DISABLE) -+ err = -EINVAL; -+ } else if (param == PIN_CONFIG_BIAS_BUS_HOLD) { -+ if (pullup != MTK_BUS_HOLD || ret == MTK_DISABLE) - err = -EINVAL; - } - break; -@@ -248,6 +253,7 @@ static int mtk_pinconf_get(struct pinctrl_dev *pctldev, - err = hw->soc->adv_drive_get(hw, desc, &ret); - break; - } -+ mutex_unlock(&hw->pinconf_lock); - - if (!err) - *config = pinconf_to_config_packed(param, ret); -@@ -268,6 +274,7 @@ static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - - desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; - -+ mutex_lock(&hw->pinconf_lock); - switch ((u32)param) { - case PIN_CONFIG_BIAS_DISABLE: - if (!hw->soc->bias_set_combo) -@@ -284,6 +291,13 @@ static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - break; - err = hw->soc->bias_set_combo(hw, desc, 0, arg); - break; -+ case PIN_CONFIG_BIAS_BUS_HOLD: -+ if (!hw->soc->bias_set_combo) -+ break; -+ /* bias-bus-hold takes no argument; its presence means enable. */ -+ err = hw->soc->bias_set_combo(hw, desc, MTK_BUS_HOLD, -+ MTK_ENABLE); -+ break; - case PIN_CONFIG_INPUT_ENABLE: - /* regard all non-zero value as enable */ - err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, !!arg); -@@ -346,6 +360,7 @@ static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - err = hw->soc->adv_drive_set(hw, desc, arg); - break; - } -+ mutex_unlock(&hw->pinconf_lock); - - return err; - } -@@ -1012,6 +1027,11 @@ static int mtk_pctrl_build_state(struct platform_device *pdev) - return 0; - } - -+static void mtk_paris_unregister_instance(void *data) -+{ -+ mtk_pinctrl_unregister_instance(data); -+} -+ - int mtk_paris_pinctrl_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -1058,6 +1078,7 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev) - hw->rsel_si_unit = false; - - spin_lock_init(&hw->lock); -+ mutex_init(&hw->pinconf_lock); - - err = mtk_pctrl_build_state(pdev); - if (err) -@@ -1097,6 +1118,18 @@ int mtk_paris_pinctrl_probe(struct platform_device *pdev) - dev_warn(&pdev->dev, - "Failed to add EINT, but pinctrl still can work\n"); - -+ /* -+ * Publish the instance for mtk_pinctrl_program_bias_by_gpio() before -+ * the gpiochip is added: the helper only needs the regmaps and SoC -+ * table, and a failure to install the devm unregister action then -+ * has nothing non-devm to unwind. -+ */ -+ mtk_pinctrl_register_instance(hw); -+ -+ err = devm_add_action_or_reset(dev, mtk_paris_unregister_instance, hw); -+ if (err) -+ return err; -+ - /* Build gpiochip should be after pinctrl_enable is done */ - err = mtk_build_gpiochip(hw); - if (err) -diff --git a/include/linux/soc/mediatek/mtk-pinctrl.h b/include/linux/soc/mediatek/mtk-pinctrl.h -new file mode 100644 -index 0000000000..644d61d3ae ---- /dev/null -+++ b/include/linux/soc/mediatek/mtk-pinctrl.h -@@ -0,0 +1,40 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ * -+ * Cross-driver interface into MediaTek pinctrl for programming pad -+ * bias by absolute SoC GPIO number, for drivers that receive pad -+ * configuration through their own ACPI resources rather than pinctrl -+ * states. -+ */ -+#ifndef __LINUX_SOC_MEDIATEK_MTK_PINCTRL_H -+#define __LINUX_SOC_MEDIATEK_MTK_PINCTRL_H -+ -+#include -+ -+/* Pull-mode values accepted by mtk_pinctrl_program_bias_by_gpio(). */ -+#define MTK_PIN_PULLDOWN 0 -+#define MTK_PIN_PULLUP 1 -+#define MTK_PIN_BUS_HOLD 2 -+ -+/* Enable/disable values accepted by mtk_pinctrl_program_bias_by_gpio(). */ -+#define MTK_PIN_DISABLE 0 -+#define MTK_PIN_ENABLE 1 -+ -+/** -+ * mtk_pinctrl_program_bias_by_gpio - program pad bias by absolute GPIO -+ * @gpio: absolute SoC pin number (matches the ACPI PinFunction -+ * pin_table entry). -+ * @pullup: one of MTK_PIN_PULLDOWN, MTK_PIN_PULLUP, MTK_PIN_BUS_HOLD. -+ * @arg: MTK_PIN_ENABLE to apply, MTK_PIN_DISABLE to release. -+ * -+ * Returns 0 on success, -EPROBE_DEFER if no mtk_pinctrl instance has -+ * registered yet, -EINVAL if @pullup or @arg is not one of the values -+ * listed above or if more than one registered mtk_pinctrl owns @gpio, -+ * -ENODEV if no registered mtk_pinctrl owns @gpio, -EOPNOTSUPP if the -+ * owning controller has no bias_set_combo, or a negative error code from -+ * the underlying bias operation. -+ */ -+int mtk_pinctrl_program_bias_by_gpio(unsigned int gpio, u32 pullup, u32 arg); -+ -+#endif /* __LINUX_SOC_MEDIATEK_MTK_PINCTRL_H */ -From 7b06fb07108d39116d5f6cbe88dd870265d7d506 Mon Sep 17 00:00:00 2001 -From: "mayuresh.wani" -Date: Thu, 3 Sep 2026 22:49:30 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: add SSPM control interface - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Add the SSPM control interface: the SCMI mailbox transport used to -talk to the MediaTek System Services Power Manager microcontroller. -The transport carries SCMI messages through a shared SRAM message -area with doorbell registers, one mailbox pair for the SET and GET -channels, with interrupts requested by resource index from the ACPI -device that describes the mailbox window. - -Folded review fixes: the SET completion is correlated with the command -in flight. sspm_ci_set() publishes the SCMI header it sent before -ringing the doorbell and clears it on completion or timeout; the SET -mailbox handler reads the echoed reply header back from the slot before -handing the slot to firmware and only completes the wait when message -id, protocol and token match. A late acknowledgment from a timed-out -transaction is dropped as stale (counted, dev_dbg) instead of completing -the next command. Firmware that echoes token 0 rather than the sender's -token is tolerated until the first real echo is seen, logged once; the -sender never uses token 0 itself, so only a nonzero token match counts -as evidence of echo and a no-echo firmware stays on the compatibility -path for every transaction. After -a timeout the next command first waits a bounded time for the late reply -so it is dropped as stale before the shared slot is rewritten, which -covers the no-echo firmware case and a late interrupt reading the next -command's header back from the slot. - -Signed-off-by: mayuresh.wani -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - drivers/soc/mediatek/Kconfig | 9 + - drivers/soc/mediatek/Makefile | 1 + - drivers/soc/mediatek/sspm_ci/Makefile | 9 + - drivers/soc/mediatek/sspm_ci/sspm_ci.c | 501 +++++++++++++++++++++++++ - drivers/soc/mediatek/sspm_ci/sspm_ci.h | 13 + - 5 files changed, 533 insertions(+) - create mode 100644 drivers/soc/mediatek/sspm_ci/Makefile - create mode 100644 drivers/soc/mediatek/sspm_ci/sspm_ci.c - create mode 100644 drivers/soc/mediatek/sspm_ci/sspm_ci.h - -diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig -index d7293977f0..e545399def 100644 ---- a/drivers/soc/mediatek/Kconfig -+++ b/drivers/soc/mediatek/Kconfig -@@ -89,4 +89,13 @@ config MTK_SOCINFO - information about the SoC to the userspace including the - manufacturer name, marketing name and soc name. - -+config MTK_SSPM_CI -+ bool "MediaTek SSPM control interface" -+ depends on ACPI && ARM64 -+ help -+ Say yes here to enable the MediaTek SSPM control interface used -+ by platform firmware communication helpers. -+ -+ If unsure, say N. -+ - endmenu -diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile -index 0665573e3c..cbeb8291f5 100644 ---- a/drivers/soc/mediatek/Makefile -+++ b/drivers/soc/mediatek/Makefile -@@ -9,3 +9,4 @@ obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o - obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o - obj-$(CONFIG_MTK_SVS) += mtk-svs.o - obj-$(CONFIG_MTK_SOCINFO) += mtk-socinfo.o -+obj-$(CONFIG_MTK_SSPM_CI) += sspm_ci/ -diff --git a/drivers/soc/mediatek/sspm_ci/Makefile b/drivers/soc/mediatek/sspm_ci/Makefile -new file mode 100644 -index 0000000000..5d47409a21 ---- /dev/null -+++ b/drivers/soc/mediatek/sspm_ci/Makefile -@@ -0,0 +1,9 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# Copyright (C) 2026 MediaTek Inc. -+# -+LOCAL_CHIP_NAME := -+ -+obj-$(CONFIG_MTK_SSPM_CI) += sspm_ci.o -+ -+ccflags-y += -Werror -Wall -+ccflags-y += -I$(src)/ -diff --git a/drivers/soc/mediatek/sspm_ci/sspm_ci.c b/drivers/soc/mediatek/sspm_ci/sspm_ci.c -new file mode 100644 -index 0000000000..7aa947b3f9 ---- /dev/null -+++ b/drivers/soc/mediatek/sspm_ci/sspm_ci.c -@@ -0,0 +1,501 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2026 MediaTek Inc. -+ * -+ * MediaTek SSPM control interface driver -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sspm_ci.h" -+ -+/* MBOX */ -+#define MBOX_BOX(id, ofs) (sspm_mbox_iomap + (id * 0x10000) + ofs) -+#define MBOX_IN_SET(id) (sspm_mbox_iomap + (id * 0x10000) + 0x1000) -+#define MBOX_OUT_CLR(id) (sspm_mbox_iomap + (id * 0x10000) + 0x1004) -+ -+/* SCMI */ -+#define SCMI_MESSAGE_HEADER_MESSAGE_ID_POS 0 -+#define SCMI_MESSAGE_HEADER_MESSAGE_TYPE_POS 8 -+#define SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS 10 -+#define SCMI_MESSAGE_HEADER_TOKEN_POS 18 -+ -+#define SCMI_NOTIFY_RECV_LEN 20 -+#define SCMI_PAYLOAD_OFFSET 7 -+ -+#define SCMI_MESSAGE_HEADER_MESSAGE_ID_MASK \ -+ ((0xFF) << SCMI_MESSAGE_HEADER_MESSAGE_ID_POS) -+#define SCMI_MESSAGE_HEADER_MESSAGE_TYPE_MASK \ -+ ((0x3) << SCMI_MESSAGE_HEADER_MESSAGE_TYPE_POS) -+#define SCMI_MESSAGE_HEADER_PROTOCOL_ID_MASK \ -+ ((0xFF) << SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS) -+#define SCMI_MESSAGE_HEADER_TOKEN_MASK \ -+ ((0x3FF) << SCMI_MESSAGE_HEADER_TOKEN_POS) -+ -+/* MISC */ -+#define SSPM_MBOX_NUM (2) -+/* Last mailbox's doorbell words (MBOX_IN_SET/MBOX_OUT_CLR) must fit the window. */ -+#define SSPM_MBOX_MMIO_SPAN (((SSPM_MBOX_NUM - 1) * 0x10000) + 0x1008) -+#define SSPM_CI_SET_ID (0) -+#define SSPM_CI_GET_ID (1) -+ -+#define SSPM_CI_MAGIC (0x01) -+ -+/* 10000 iterations × mdelay(1) = 10 seconds max wait for SSPM firmware ack */ -+#define SSPM_CI_MAX_POLL_COUNT (10000) -+ -+#define IRQ_NAME_LEN (32) -+ -+enum scmi_tinysys_protocol_cmd { -+ TINYSYS_COMMON_SET = 0x3, -+ TINYSYS_COMMON_GET = 0x4, -+ TINYSYS_POWER_STATE_NOTIFY = 0x5, -+ TINYSYS_SLBC_CTRL = 0x6, -+}; -+ -+enum scmi_mtk_protocol { -+ SCMI_PROTOCOL_TINYSYS = 0x80, -+}; -+ -+enum scmi_message_type { -+ SCMI_MESSAGE_TYPE_COMMAND = 0, -+ SCMI_MESSAGE_TYPE_DELAYED_RESPONSE = 2, -+ SCMI_MESSAGE_TYPE_NOTIFICATION = 3, -+}; -+ -+struct scmi_tinysys_common_set_state { -+ u32 reserv; -+ u32 feature_id; -+ u32 p1; -+ u32 p2; -+ u32 p3; -+ u32 p4; -+ u32 p5; -+}; -+ -+struct scmi_msg_t { -+ u32 reserved0; -+ u32 status; -+ u64 reserved1; -+ u32 flags; -+ u32 length; -+ u32 message_header; -+ u32 payload[7]; -+}; -+ -+struct ap_data { -+ unsigned int irq_mbox[SSPM_MBOX_NUM]; -+ char irq_name[SSPM_MBOX_NUM][IRQ_NAME_LEN]; -+}; -+ -+static void __iomem *sspm_mbox_iomap; -+ -+static struct ap_data apmcu = { -+ .irq_mbox = {SSPM_CI_SET_ID, -+ SSPM_CI_GET_ID}, -+ .irq_name = {"SSPM_CI_SET", -+ "SSPM_CI_GET"}, -+}; -+ -+static struct device *__dev; -+static DEFINE_MUTEX(_hw_rsc); -+/* -+ * SET completion state, all under _hw_rsc except for the handler's reads -+ * and its single store to _hw_ack. -+ * -+ * _inflight_hdr is the SCMI header of the command currently waiting for -+ * its ack (0 while nothing is in flight or after a timeout, which no reply -+ * header can equal). The SET mailbox handler reads the reply header back -+ * from the slot and completes the wait only when message id, protocol and -+ * token match it, so a late ack from a timed-out transaction cannot be -+ * consumed by the next command. -+ */ -+static int _hw_ack; -+static u32 _inflight_hdr; -+/* Set once a reply echoed our token; until then a token-0 echo is accepted. */ -+static bool _token_echo_seen; -+static unsigned int _stale_acks; -+/* -+ * Set by a SET timeout: the next sspm_ci_set() first gives the late reply a -+ * bounded window to arrive (and be dropped as stale) before it rewrites the -+ * shared slot and publishes a new header. Without this, a firmware that does -+ * not echo tokens could have that late reply complete the next command, and -+ * a late interrupt could read the next command's header back from the slot. -+ */ -+static bool _drain_needed; -+#define SSPM_CI_DRAIN_MS 100 -+ -+/* -+ * Per-transaction sequence number placed in the SCMI message header token -+ * field. Incremented under _hw_rsc for every sspm_ci_set() so consecutive -+ * transactions carry distinct tokens (a hardcoded 0 made all messages -+ * indistinguishable). Packed as a u8 into the header token field. Token 0 -+ * is never sent: a reply carrying token 0 is then unambiguously a firmware -+ * that does not echo the sender's token, see sspm_ci_ack_matches(). -+ */ -+static u8 _scmi_token = 1; -+ -+static u8 sspm_ci_next_token(void) -+{ -+ u8 token = _scmi_token++; -+ -+ if (!_scmi_token) -+ _scmi_token = 1; -+ return token; -+} -+ -+static void sspm_ci_clear_globals(void *data) -+{ -+ mutex_lock(&_hw_rsc); -+ sspm_mbox_iomap = NULL; -+ __dev = NULL; -+ mutex_unlock(&_hw_rsc); -+ WRITE_ONCE(_inflight_hdr, 0); -+ _token_echo_seen = false; -+ _stale_acks = 0; -+ _drain_needed = false; -+ _scmi_token = 1; -+} -+ -+/* -+ * After a timed-out SET, wait a bounded time for its late reply so the -+ * handler drops it as stale (nothing is in flight) before the slot is reused. -+ * Called with _hw_rsc held. Returns early as soon as a stale ack was seen. -+ */ -+static void sspm_ci_drain_late_ack(void) -+{ -+ unsigned int stale = READ_ONCE(_stale_acks); -+ unsigned int ms; -+ -+ if (!_drain_needed) -+ return; -+ _drain_needed = false; -+ -+ for (ms = 0; ms < SSPM_CI_DRAIN_MS; ms++) { -+ if (READ_ONCE(_stale_acks) != stale) { -+ dev_dbg(__dev, "late SET ack drained after %u ms\n", ms); -+ return; -+ } -+ mdelay(1); -+ } -+} -+ -+static ssize_t sspm_alive_show(struct device *kobj, -+ struct device_attribute *attr, char *buf) -+{ -+ int ret; -+ -+ ret = sspm_ci_set(7, -+ 0xDEAD, 0, 0, 0, 0); -+ -+ return snprintf(buf, PAGE_SIZE, "%s\n", ret ? "Dead" : "Alive"); -+} -+DEVICE_ATTR_RO(sspm_alive); -+ -+static uint32_t pack_message_header(u8 message_id, u8 message_type, u8 protocol_id, u8 token) -+{ -+ return ((((message_id) << SCMI_MESSAGE_HEADER_MESSAGE_ID_POS) & -+ SCMI_MESSAGE_HEADER_MESSAGE_ID_MASK) | -+ (((message_type) << SCMI_MESSAGE_HEADER_MESSAGE_TYPE_POS) & -+ SCMI_MESSAGE_HEADER_MESSAGE_TYPE_MASK) | -+ (((protocol_id) << SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS) & -+ SCMI_MESSAGE_HEADER_PROTOCOL_ID_MASK) | -+ (((token) << SCMI_MESSAGE_HEADER_TOKEN_POS) & -+ SCMI_MESSAGE_HEADER_TOKEN_MASK)); -+} -+ -+int sspm_ci_set(u32 feature_id, -+ u32 p1, u32 p2, u32 p3, u32 p4, u32 p5) -+{ -+ struct scmi_msg_t scmi_tx = {}; -+ u8 protocol_id, message_type; -+ u8 token, message_id; -+ u32 message_header; -+ u32 count = 0; -+ -+ if (!sspm_mbox_iomap) -+ return -ENODEV; -+ -+ scmi_tx.payload[0] = 0; -+ scmi_tx.payload[1] = feature_id; -+ scmi_tx.payload[2] = p1; -+ scmi_tx.payload[3] = p2; -+ scmi_tx.payload[4] = p3; -+ scmi_tx.payload[5] = p4; -+ scmi_tx.payload[6] = p5; -+ scmi_tx.length = sizeof(struct scmi_tinysys_common_set_state) + sizeof(message_header); -+ message_id = TINYSYS_COMMON_SET; -+ protocol_id = SCMI_PROTOCOL_TINYSYS; -+ message_type = SCMI_MESSAGE_TYPE_COMMAND; -+ scmi_tx.status = 0; -+ scmi_tx.flags = 0x1; -+ -+ mutex_lock(&_hw_rsc); -+ -+ if (!sspm_mbox_iomap) { -+ mutex_unlock(&_hw_rsc); -+ return -ENODEV; -+ } -+ -+ /* -+ * Assign a fresh sequence token per transaction (under _hw_rsc so the -+ * counter is not raced). Distinct tokens let firmware/response tracing -+ * tell consecutive commands apart; the previous hardcoded 0 did not. -+ */ -+ token = sspm_ci_next_token(); -+ message_header = pack_message_header(message_id, message_type, -+ protocol_id, token); -+ scmi_tx.message_header = message_header; -+ sspm_ci_drain_late_ack(); -+ while (readl((void __iomem *)MBOX_IN_SET(SSPM_CI_SET_ID))) { -+ count++; -+ if (count > SSPM_CI_MAX_POLL_COUNT) { -+ mutex_unlock(&_hw_rsc); -+ dev_err(__dev, "scmi timeout\n"); -+ return -ETIMEDOUT; -+ } -+ mdelay(1); -+ } -+ memcpy_toio(MBOX_BOX(SSPM_CI_SET_ID, 0x0), &scmi_tx, sizeof(scmi_tx)); -+ /* -+ * Clear any stale ack a previous timed-out transaction may have left -+ * behind (e.g. a late IRQ that set _hw_ack after that call returned), -+ * immediately before triggering this send so the ack wait below cannot -+ * complete prematurely. Clearing here rather than before the (up-to-10s) -+ * mailbox-free poll above narrows the window in which a late ack from a -+ * timed-out transaction could be mistaken for this one to just the send -+ * trigger; the handler then matches the echoed reply header against -+ * _inflight_hdr, so a stale ack cannot complete this wait. -+ */ -+ WRITE_ONCE(_hw_ack, 0); -+ /* -+ * Publish the header the handler must see echoed before ringing the -+ * doorbell, so the completion is tied to this transaction only. -+ */ -+ WRITE_ONCE(_inflight_hdr, message_header); -+ writel(SSPM_CI_MAGIC, (void __iomem *)MBOX_IN_SET(SSPM_CI_SET_ID)); -+ /* Wait sspm-side ack. */ -+ count = 0; -+ while (READ_ONCE(_hw_ack) == 0) { -+ count++; -+ if (count > SSPM_CI_MAX_POLL_COUNT) { -+ /* -+ * Nothing in flight any more: a reply that arrives late -+ * for this header is dropped by the handler as stale -+ * instead of completing the next command. -+ */ -+ WRITE_ONCE(_inflight_hdr, 0); -+ _drain_needed = true; -+ mutex_unlock(&_hw_rsc); -+ dev_err(__dev, "scmi timeout (hdr %#x)\n", message_header); -+ return -ETIMEDOUT; -+ } -+ mdelay(1); -+ }; -+ WRITE_ONCE(_hw_ack, 0); -+ WRITE_ONCE(_inflight_hdr, 0); -+ mutex_unlock(&_hw_rsc); -+ -+ dev_dbg(__dev, "[%s] fid:%u p1:%u p2:%u p3:%u p4:%u p5:%u\n", -+ __func__, feature_id, p1, p2, p3, p4, p5); -+ return 0; -+} -+EXPORT_SYMBOL(sspm_ci_set); -+ -+#define SCMI_MESSAGE_HEADER_CORRELATE_MASK \ -+ (SCMI_MESSAGE_HEADER_MESSAGE_ID_MASK | \ -+ SCMI_MESSAGE_HEADER_PROTOCOL_ID_MASK | \ -+ SCMI_MESSAGE_HEADER_TOKEN_MASK) -+ -+/* Reply header lives at the same slot offset as the command header. */ -+#define MBOX_MSG_HDR_OFS (offsetof(struct scmi_msg_t, message_header)) -+ -+/* -+ * Decide whether the reply header read back from the SET mailbox completes -+ * the command in flight. Message id, protocol and token must all match. -+ * Firmware that does not echo the token (legacy, always replies with token -+ * 0) is tolerated until the first real token echo is seen; after that a -+ * mismatch is a stale ack. Because the sender never uses token 0, only a -+ * match on a nonzero token counts as evidence of echo: a token-0 reply can -+ * never take the exact-match branch, so a no-echo firmware stays on the -+ * compatibility path for every transaction instead of only the first. -+ */ -+static bool sspm_ci_ack_matches(u32 reply_hdr, u32 expect_hdr) -+{ -+ u32 m = SCMI_MESSAGE_HEADER_CORRELATE_MASK; -+ -+ if (!expect_hdr) -+ return false; -+ if ((reply_hdr & m) == (expect_hdr & m)) { -+ if (expect_hdr & SCMI_MESSAGE_HEADER_TOKEN_MASK) -+ _token_echo_seen = true; -+ return true; -+ } -+ if (!_token_echo_seen && -+ !(reply_hdr & SCMI_MESSAGE_HEADER_TOKEN_MASK) && -+ (reply_hdr & (m & ~SCMI_MESSAGE_HEADER_TOKEN_MASK)) == -+ (expect_hdr & (m & ~SCMI_MESSAGE_HEADER_TOKEN_MASK))) { -+ dev_info_once(__dev, -+ "firmware does not echo the SCMI token; ack correlation limited to message id and protocol\n"); -+ return true; -+ } -+ return false; -+} -+ -+static irqreturn_t _mbox_handler_(int irq, void *data) -+{ -+ unsigned int id = *((unsigned int *)data); -+ u32 reply_hdr = 0, expect_hdr = 0; -+ -+ if (id == SSPM_CI_SET_ID) { -+ /* Read the echoed header before the slot is handed back. */ -+ reply_hdr = readl((void __iomem *)MBOX_BOX(id, MBOX_MSG_HDR_OFS)); -+ expect_hdr = READ_ONCE(_inflight_hdr); -+ } -+ -+ writel(SSPM_CI_MAGIC, (void __iomem *)MBOX_OUT_CLR(id)); -+ /* -+ * The word at +0x4 is the mailbox ownership (mem_free) flag of the -+ * vendor transport, not an SCMI return status: TINYSYS SET carries no -+ * status word and the reference driver clears this flag the same way -+ * to hand the slot back to the sender. Firmware results, where a -+ * command has any, are returned in the reply payload of GET. -+ */ -+ writel(0x0, (void __iomem *)MBOX_BOX(id, 0x4)); -+ -+ /* -+ * Only the SET mailbox completes an sspm_ci_set() ack wait. The GET -+ * mailbox shares this handler but carries unsolicited firmware -+ * notifications; acking on it would let a GET interrupt complete an -+ * in-flight SET transaction early (before firmware consumed the SET -+ * message), so the ack is gated to the SET id. -+ */ -+ if (id == SSPM_CI_SET_ID) { -+ if (sspm_ci_ack_matches(reply_hdr, expect_hdr)) { -+ WRITE_ONCE(_hw_ack, 1); -+ } else { -+ WRITE_ONCE(_stale_acks, _stale_acks + 1); -+ dev_dbg(__dev, "stale SET ack dropped: reply hdr %#x, in flight %#x (%u total)\n", -+ reply_hdr, expect_hdr, _stale_acks); -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int sspm_ci_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ void __iomem *base; -+ int id = 0, irq = 0, ret = 0; -+ struct ap_data *data = &apmcu; -+ struct resource *res; -+ -+ /* -+ * Use devm_ioremap() rather than devm_platform_ioremap_resource(): -+ * the latter reserves the region via request_mem_region(), which fails -+ * with -EBUSY here because the ACPI core has already claimed the _CRS -+ * memory resource (see /proc/iomem "NVDA8400:00"). devm_ioremap() maps -+ * without exclusive reservation while still being devres-managed. -+ */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) -+ return -ENODEV; -+ if (resource_size(res) < SSPM_MBOX_MMIO_SPAN) -+ return dev_err_probe(dev, -EINVAL, -+ "mailbox window too small (%pa, need %#x)\n", -+ &res->end, SSPM_MBOX_MMIO_SPAN); -+ base = devm_ioremap(dev, res->start, resource_size(res)); -+ if (!base) -+ return -ENOMEM; -+ -+ /* -+ * The mailbox state is a single instance by design (one SSPM per -+ * SoC); refuse a second matching device instead of letting it take -+ * over the mapping while the first one's interrupts are live. -+ */ -+ mutex_lock(&_hw_rsc); -+ if (sspm_mbox_iomap) { -+ mutex_unlock(&_hw_rsc); -+ return dev_err_probe(dev, -EBUSY, -+ "SSPM mailbox already bound to %s\n", -+ dev_name(__dev)); -+ } -+ sspm_mbox_iomap = base; -+ __dev = dev; -+ mutex_unlock(&_hw_rsc); -+ -+ ret = devm_add_action_or_reset(dev, sspm_ci_clear_globals, NULL); -+ if (ret) -+ return ret; -+ -+ for (id = 0; id < SSPM_MBOX_NUM; id++) { -+ /* Get mbox device information. */ -+ irq = platform_get_irq(pdev, data->irq_mbox[id]); -+ if (irq < 0) { -+ dev_err(dev, "platform_get_irq(%d) fail.\n", id); -+ return irq; -+ } -+ -+ /* Register mbox handler. */ -+ ret = devm_request_irq(dev, irq, _mbox_handler_, -+ IRQF_TRIGGER_NONE | IRQF_NO_SUSPEND, data->irq_name[id], -+ &data->irq_mbox[id]); -+ if (ret) { -+ dev_err(dev, "request_irq(%s) fail=%d.\n", data->irq_name[id], ret); -+ return ret; -+ } -+ dev_info(dev, "%s IRQ = %d.\n", data->irq_name[id], irq); -+ } -+ -+ return 0; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) -+static void sspm_ci_remove(struct platform_device *pdev) -+#else -+static int sspm_ci_remove(struct platform_device *pdev) -+#endif -+{ -+ /* -+ * Resources are devm-managed. Probe registration order makes teardown: -+ * IRQs -> clear globals -> unmap MMIO. -+ */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 14, 0) -+ return 0; -+#endif -+} -+ -+static const struct acpi_device_id sspm_ci_acpi_match[] = { -+ {"MTKW8400", 0, 0, 0}, -+ {"NVDA8400", 0, 0, 0}, -+ {}, -+}; -+MODULE_DEVICE_TABLE(acpi, sspm_ci_acpi_match); -+ -+static struct platform_driver sspm_ci_driver = { -+ .probe = sspm_ci_probe, -+ .remove = sspm_ci_remove, -+ .driver = { -+ .name = "SSPM_CI", -+ .acpi_match_table = ACPI_PTR(sspm_ci_acpi_match), -+ }, -+}; -+ -+static int __init sspm_ci_init(void) -+{ -+ return platform_driver_register(&sspm_ci_driver); -+} -+ -+subsys_initcall(sspm_ci_init); -+ -+MODULE_DESCRIPTION("MediaTek SSPM control interface driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/soc/mediatek/sspm_ci/sspm_ci.h b/drivers/soc/mediatek/sspm_ci/sspm_ci.h -new file mode 100644 -index 0000000000..9df540f70a ---- /dev/null -+++ b/drivers/soc/mediatek/sspm_ci/sspm_ci.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2026 MediaTek Inc. -+ * -+ * MediaTek SSPM control interface driver -+ */ -+ -+#ifndef _SSPM_CI_H_ -+#define _SSPM_CI_H_ -+ -+int sspm_ci_set(u32 feature_id, -+ u32 p1, u32 p2, u32 p3, u32 p4, u32 p5); -+#endif /* _SSPM_CI_H_ */ -From db9971802e9d9ccd3dc74cd41081f87f5fc4d441 Mon Sep 17 00:00:00 2001 -From: "mayuresh.wani" -Date: Thu, 3 Sep 2026 22:49:30 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: add power_wrap device power - control driver - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Add the power_wrap driver: ACPI-driven device power control through -the SSPM control interface. Kernel clients and the ACPI power flows -use it to request device power, clock and mode changes from the SSPM -firmware, which reference counts the requests across operating system -components. - -The public client header is introduced directly at -include/linux/soc/mediatek/mtk-pwrap.h so in-tree consumers outside -drivers/soc can include it without relative paths. - -Signed-off-by: mayuresh.wani -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - drivers/soc/mediatek/Kconfig | 9 + - drivers/soc/mediatek/Makefile | 1 + - drivers/soc/mediatek/power_wrap/Makefile | 9 + - drivers/soc/mediatek/power_wrap/acpiutil.c | 429 +++++++++++++++++ - .../soc/mediatek/power_wrap/inc/power_wrap.h | 151 ++++++ - .../soc/mediatek/power_wrap/inc/pwrap_scmi.h | 81 ++++ - drivers/soc/mediatek/power_wrap/power_wrap.c | 446 ++++++++++++++++++ - include/linux/soc/mediatek/mtk-pwrap.h | 73 +++ - 8 files changed, 1199 insertions(+) - create mode 100644 drivers/soc/mediatek/power_wrap/Makefile - create mode 100644 drivers/soc/mediatek/power_wrap/acpiutil.c - create mode 100644 drivers/soc/mediatek/power_wrap/inc/power_wrap.h - create mode 100644 drivers/soc/mediatek/power_wrap/inc/pwrap_scmi.h - create mode 100644 drivers/soc/mediatek/power_wrap/power_wrap.c - create mode 100644 include/linux/soc/mediatek/mtk-pwrap.h - -diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig -index e545399def..b20141abb9 100644 ---- a/drivers/soc/mediatek/Kconfig -+++ b/drivers/soc/mediatek/Kconfig -@@ -96,6 +96,15 @@ config MTK_SSPM_CI - Say yes here to enable the MediaTek SSPM control interface used - by platform firmware communication helpers. - -+ If unsure, say N. -+config MTK_POWER_WRAP -+ bool "MediaTek Power Wrap ACPI device-control support" -+ depends on ACPI && ARM64 -+ depends on MTK_SSPM_CI -+ help -+ Say yes here to enable MediaTek Power Wrap support for ACPI based -+ device power-control flows. -+ - If unsure, say N. - - endmenu -diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile -index cbeb8291f5..91d8b58d9f 100644 ---- a/drivers/soc/mediatek/Makefile -+++ b/drivers/soc/mediatek/Makefile -@@ -10,3 +10,4 @@ obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o - obj-$(CONFIG_MTK_SVS) += mtk-svs.o - obj-$(CONFIG_MTK_SOCINFO) += mtk-socinfo.o - obj-$(CONFIG_MTK_SSPM_CI) += sspm_ci/ -+obj-$(CONFIG_MTK_POWER_WRAP) += power_wrap/ -diff --git a/drivers/soc/mediatek/power_wrap/Makefile b/drivers/soc/mediatek/power_wrap/Makefile -new file mode 100644 -index 0000000000..3a551b55b3 ---- /dev/null -+++ b/drivers/soc/mediatek/power_wrap/Makefile -@@ -0,0 +1,9 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+# Composite name power_wrap_drv avoids colliding with the source file power_wrap.o -+obj-y += power_wrap_drv.o -+power_wrap_drv-y += power_wrap.o -+power_wrap_drv-y += acpiutil.o -+ -+ccflags-y += -Wall -+ccflags-y += -I$(src)/inc -diff --git a/drivers/soc/mediatek/power_wrap/acpiutil.c b/drivers/soc/mediatek/power_wrap/acpiutil.c -new file mode 100644 -index 0000000000..bcfdd8967d ---- /dev/null -+++ b/drivers/soc/mediatek/power_wrap/acpiutil.c -@@ -0,0 +1,429 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ * -+ * acpiutil.c - ACPI utility functions for power_wrap driver -+ * -+ * This module builds the device-control (DPM) table from the PEPD -+ * device's ACPI _DSM method (UUID 64B66B51), including the per-device -+ * SCMI dev_id fetched via GDSC(). -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "power_wrap.h" -+ -+/* ACPI NameSeg is always exactly 4 characters, trailing-padded with '_' */ -+#define PWRAP_ACPI_NAMESEG_LEN 4 -+ -+/* ============================================================ -+ * DPM UUID (64B66B51) - Device-control config from ACPI -+ * ============================================================ -+ * -+ * Builds the device-control table at probe by parsing the DPMT package -+ * returned by UUID 64B66B51 function 1 (Case 1 in Cpu.asl). -+ * -+ * Note: the DPMT package does NOT carry the per-device SCMI dev_id; that -+ * lives in a separate ASL method, GDSC(path), which writes the global -+ * SRTP package. So for CTRL_BY_SCMI devices we make a second ACPI call to -+ * GDSC() to obtain dev_id. -+ */ -+ -+/* GDSC return package (SRTP) layout - see Cpu.asl Name(SRTP, ...) */ -+enum pwrap_gdsc_srtp_idx { -+ GDSC_SRTP_FEAT_ID = 0, /* SCMI feature id (0x0D; 0xFFFFFFFF = unsupported) */ -+ GDSC_SRTP_DEV_ID, /* SCMI device id (the per-device value we need) */ -+ GDSC_SRTP_PREPARE, /* Package(4): prepare action payloads */ -+ GDSC_SRTP_DSTATE, /* Package(4): d-state action payloads */ -+ GDSC_SRTP_FSTATE, /* Package(4): f-state action payloads */ -+ GDSC_SRTP_REQ, /* Package(4): request action payloads */ -+ GDSC_SRTP_ABANDON, /* Package(4): abandon action payloads */ -+ GDSC_SRTP_COUNT, -+}; -+ -+#define GDSC_FEAT_ID_UNSUPPORTED 0xFFFFFFFFU -+ -+/* -+ * pwrap_acpi_normalize_path() - Pad ACPI NameSegs to 4 chars with '_' -+ * -+ * ACPI NameSegs are fixed at 4 bytes; names shorter than 4 chars are -+ * trailing-padded with '_' (ACPI spec 19.2.2 / 5.3). The kernel's -+ * acpi_get_name(ACPI_FULL_PATHNAME) - used to key device lookups - emits -+ * the padded form ("\_SB_.PCI0.RP0_"), but the _DSM string literals are -+ * written unpadded ("\_SB.PCI0.RP0"). Normalizing makes the two agree. -+ * -+ * Leading root '\' and parent '^' prefix chars are copied verbatim; each -+ * '.'-separated NameSeg is then padded to 4 chars. -+ */ -+int pwrap_acpi_normalize_path(const char *in, char *out, size_t out_sz) -+{ -+ size_t o = 0; -+ const char *p = in; -+ -+ if (!in || !out || out_sz == 0) -+ return -EINVAL; -+ -+ /* Copy leading root/parent prefix ('\' and any '^') verbatim. */ -+ while (*p == '\\' || *p == '^') { -+ if (o + 1 >= out_sz) -+ return -ENOSPC; -+ out[o++] = *p++; -+ } -+ -+ /* Process each '.'-separated NameSeg, padding short ones to 4. */ -+ while (*p) { -+ size_t seg_len = strcspn(p, "."); -+ size_t pad = (seg_len < PWRAP_ACPI_NAMESEG_LEN) ? -+ (PWRAP_ACPI_NAMESEG_LEN - seg_len) : 0; -+ -+ if (o + seg_len + pad + 1 >= out_sz) -+ return -ENOSPC; -+ -+ memcpy(&out[o], p, seg_len); -+ o += seg_len; -+ while (pad--) -+ out[o++] = '_'; -+ -+ p += seg_len; -+ if (*p == '.') { -+ out[o++] = '.'; -+ p++; -+ } -+ } -+ -+ out[o] = '\0'; -+ return 0; -+} -+ -+/* -+ * pwrap_acpi_fetch_scmi_dev_id() - Get per-device SCMI dev_id via GDSC() -+ * @dev: PEPD ACPI device -+ * @raw_path: UNPADDED device path as it appears in the _DSM literal -+ * (GDSC's ASL ElseIf compares against unpadded names) -+ * @dev_id_out: receives the SCMI device id on success -+ * -+ * Evaluates \_SB.PEPD.GDSC(raw_path), which returns the SRTP package -+ * {feat_id, dev_id, <5 action payload packages>}. We only consume dev_id; -+ * feat_id and the action IDs are invariant and supplied by SCMI_CONFIG_INIT(). -+ * -+ * Return: 0 on success, -ENODEV if the firmware reports the path as -+ * unsupported (feat_id == 0xFFFFFFFF), negative errno otherwise. -+ */ -+static int pwrap_acpi_fetch_scmi_dev_id(struct device *dev, -+ const char *raw_path, u32 *dev_id_out) -+{ -+ acpi_handle handle = ACPI_HANDLE(dev); -+ struct acpi_object_list args; -+ union acpi_object arg, *pkg, *feat, *devid; -+ struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ int ret = 0; -+ -+ arg.type = ACPI_TYPE_STRING; -+ arg.string.pointer = (char *)raw_path; -+ arg.string.length = strlen(raw_path); -+ args.count = 1; -+ args.pointer = &arg; -+ -+ status = acpi_evaluate_object(handle, "GDSC", &args, &out); -+ if (ACPI_FAILURE(status)) { -+ dev_warn(dev, "GDSC(%s) evaluation failed: %s\n", -+ raw_path, acpi_format_exception(status)); -+ return -EIO; -+ } -+ -+ pkg = out.pointer; -+ if (!pkg || pkg->type != ACPI_TYPE_PACKAGE || -+ pkg->package.count < GDSC_SRTP_COUNT) { -+ dev_warn(dev, "GDSC(%s): unexpected return (type/count)\n", -+ raw_path); -+ ret = -EINVAL; -+ goto out_free; -+ } -+ -+ feat = &pkg->package.elements[GDSC_SRTP_FEAT_ID]; -+ devid = &pkg->package.elements[GDSC_SRTP_DEV_ID]; -+ if (feat->type != ACPI_TYPE_INTEGER || -+ devid->type != ACPI_TYPE_INTEGER) { -+ dev_warn(dev, "GDSC(%s): feat_id/dev_id not integers\n", -+ raw_path); -+ ret = -EINVAL; -+ goto out_free; -+ } -+ -+ if ((u32)feat->integer.value == GDSC_FEAT_ID_UNSUPPORTED) { -+ dev_warn(dev, "GDSC(%s): firmware reports path unsupported\n", -+ raw_path); -+ ret = -ENODEV; -+ goto out_free; -+ } -+ -+ *dev_id_out = (u32)devid->integer.value; -+ -+out_free: -+ ACPI_FREE(out.pointer); -+ return ret; -+} -+ -+/* -+ * pwrap_parse_constraints() - Flatten the constraints sub-package -+ * -+ * ASL forms (Cpu.asl Case 1): -+ * Package(0x3){enable, device_state, comp_count} -+ * Package(0x4){enable, device_state, comp_count, Package(){comp_states...}} -+ * -+ * Maps onto pwrap_idle_constraints.values[] = {enable, device_state, -+ * comp_count, comp_states[0..comp_count-1]}. -+ */ -+static void pwrap_parse_constraints(struct device *dev, -+ union acpi_object *pkg, -+ struct pwrap_idle_constraints *c) -+{ -+ u32 i, n; -+ -+ memset(c, 0, sizeof(*c)); -+ -+ if (!pkg || pkg->type != ACPI_TYPE_PACKAGE) -+ return; -+ -+ n = pkg->package.count; -+ if (n > PWRAP_IDLE_CONSTRAINT_SCALARS && -+ pkg->package.elements[PWRAP_IDLE_CONSTRAINT_SCALARS].type == ACPI_TYPE_PACKAGE) { -+ /* 4-element form: scalars + nested comp_states package */ -+ union acpi_object *comp = -+ &pkg->package.elements[PWRAP_IDLE_CONSTRAINT_SCALARS]; -+ u32 j; -+ -+ for (i = 0; i < PWRAP_IDLE_CONSTRAINT_SCALARS; i++) { -+ union acpi_object *e = &pkg->package.elements[i]; -+ -+ if (e->type == ACPI_TYPE_INTEGER) -+ c->values[i] = e->integer.value; -+ } -+ for (j = 0; j < comp->package.count && -+ (PWRAP_IDLE_CONSTRAINT_SCALARS + j) < -+ (PWRAP_MAX_COMP_NUM + PWRAP_IDLE_CONSTRAINT_SCALARS); j++) { -+ union acpi_object *e = &comp->package.elements[j]; -+ -+ if (e->type == ACPI_TYPE_INTEGER) -+ c->values[PWRAP_IDLE_CONSTRAINT_SCALARS + j] = -+ e->integer.value; -+ } -+ } else { -+ /* Flat form: copy each integer scalar in order */ -+ for (i = 0; i < n && -+ i < (PWRAP_MAX_COMP_NUM + PWRAP_IDLE_CONSTRAINT_SCALARS); i++) { -+ union acpi_object *e = &pkg->package.elements[i]; -+ -+ if (e->type == ACPI_TYPE_INTEGER) -+ c->values[i] = e->integer.value; -+ } -+ } -+ -+ /* Clamp comp_count to the number of entries actually written into -+ * comp_states[]. Firmware may report a larger value than PWRAP_MAX_COMP_NUM -+ * but the parse loops above cap writes at that limit. Without this clamp, -+ * consumers iterating comp_states[] up to comp_count would read beyond the -+ * array bounds into adjacent struct fields. -+ */ -+ if (c->comp_count > PWRAP_MAX_COMP_NUM) -+ c->comp_count = PWRAP_MAX_COMP_NUM; -+} -+ -+/* -+ * pwrap_parse_dev_package() - Parse one DPMT device package into a config -+ * -+ * Package layout (DPM_DEV_* enum): {path, type, constraints, control_type}. -+ * On success @cfg->device_path / @cfg->device_type are kstrdup'd (freed by -+ * pwrap_acpi_dpm_config_free()). -+ */ -+static int pwrap_parse_dev_package(struct device *dev, -+ union acpi_object *pkg, -+ struct pwrap_dev_config *cfg) -+{ -+ union acpi_object *path_obj, *type_obj, *ctrl_obj; -+ char norm_path[PWRAP_DEV_PATH_MAX]; -+ const char *raw_path; -+ u64 control_type; -+ int ret; -+ -+ if (pkg->type != ACPI_TYPE_PACKAGE || -+ pkg->package.count < DPM_DEV_PKG_COUNT) { -+ dev_warn(dev, "DPMT device package: bad type/count\n"); -+ return -EINVAL; -+ } -+ -+ path_obj = &pkg->package.elements[DPM_DEV_PATH]; -+ type_obj = &pkg->package.elements[DPM_DEV_TYPE]; -+ ctrl_obj = &pkg->package.elements[DPM_DEV_CONTROL_TYPE]; -+ -+ if (path_obj->type != ACPI_TYPE_STRING || !path_obj->string.pointer || -+ ctrl_obj->type != ACPI_TYPE_INTEGER) { -+ dev_warn(dev, "DPMT device package: bad path/control_type\n"); -+ return -EINVAL; -+ } -+ raw_path = path_obj->string.pointer; -+ -+ /* Normalize the (unpadded) _DSM path into the padded lookup key. */ -+ ret = pwrap_acpi_normalize_path(raw_path, norm_path, sizeof(norm_path)); -+ if (ret) { -+ dev_warn(dev, "DPMT: cannot normalize path \"%s\": %d\n", -+ raw_path, ret); -+ return ret; -+ } -+ -+ cfg->device_path = kstrdup(norm_path, GFP_KERNEL); -+ if (!cfg->device_path) -+ return -ENOMEM; -+ -+ if (type_obj->type == ACPI_TYPE_STRING && type_obj->string.pointer) { -+ cfg->device_type = kstrdup(type_obj->string.pointer, GFP_KERNEL); -+ if (!cfg->device_type) { -+ kfree(cfg->device_path); -+ cfg->device_path = NULL; -+ return -ENOMEM; -+ } -+ } -+ -+ pwrap_parse_constraints(dev, &pkg->package.elements[DPM_DEV_CONSTRAINTS], -+ &cfg->constraints); -+ -+ control_type = ctrl_obj->integer.value; -+ switch (control_type) { -+ case CTRL_NONE: -+ cfg->control_type = CTRL_NONE; -+ break; -+ case CTRL_BY_PWRAP: -+ cfg->control_type = CTRL_BY_PWRAP; -+ break; -+ case CTRL_BY_SCMI: -+ cfg->control_type = CTRL_BY_SCMI; -+ break; -+ default: -+ dev_warn(dev, "DPMT: \"%s\" unknown control_type %llu -> NONE\n", -+ norm_path, control_type); -+ cfg->control_type = CTRL_NONE; -+ break; -+ } -+ -+ /* -+ * SCMI devices need the per-device dev_id, which is not in the DPMT. -+ * Seed the invariant SCMI payload (feat_id + action IDs) the same way -+ * the static table does, then fetch dev_id from GDSC() using the RAW -+ * (unpadded) path the ASL compares against. -+ */ -+ if (cfg->control_type == CTRL_BY_SCMI) { -+ struct pwrap_scmi_config seed = SCMI_CONFIG_INIT(0); -+ u32 dev_id = 0; -+ -+ cfg->scmi_config = seed; -+ -+ ret = pwrap_acpi_fetch_scmi_dev_id(dev, raw_path, &dev_id); -+ if (ret) { -+ dev_warn(dev, "DPMT: \"%s\" SCMI but no dev_id (%d); " -+ "demoting to CTRL_NONE\n", norm_path, ret); -+ cfg->control_type = CTRL_NONE; -+ } else { -+ cfg->scmi_config.dev_id = dev_id; -+ dev_info(dev, "DPMT: \"%s\" SCMI dev_id=0x%x\n", -+ norm_path, dev_id); -+ } -+ } -+ -+ return 0; -+} -+ -+int pwrap_acpi_fetch_dpm_config(struct device *dev, -+ struct pwrap_dev_ctrl *ctrl) -+{ -+ acpi_handle handle = ACPI_HANDLE(dev); -+ union acpi_object *obj, *rev_obj, *cnt_obj; -+ u64 count; -+ u32 i; -+ int ret = 0; -+ -+ if (!dev || !ctrl) -+ return -EINVAL; -+ -+ obj = acpi_evaluate_dsm(handle, &pwrap_dsm_dpm_uuid, -+ DSM_DPM_REV_0, DSM_DPM_GET_DEV_CTRL_INFO, NULL); -+ if (!obj) { -+ dev_err(dev, "Failed to evaluate DPM _DSM func %d\n", -+ DSM_DPM_GET_DEV_CTRL_INFO); -+ return -EINVAL; -+ } -+ -+ if (obj->type != ACPI_TYPE_PACKAGE || -+ obj->package.count <= DSM_DPM_DPMT_DCFG) { -+ dev_err(dev, "DPMT: expected package with devices, got type %d count %d\n", -+ obj->type, obj->type == ACPI_TYPE_PACKAGE ? -+ obj->package.count : -1); -+ ret = -EINVAL; -+ goto out_free; -+ } -+ -+ rev_obj = &obj->package.elements[DSM_DPM_DPMT_REV]; -+ cnt_obj = &obj->package.elements[DSM_DPM_DPMT_COUNT]; -+ if (rev_obj->type != ACPI_TYPE_INTEGER || -+ cnt_obj->type != ACPI_TYPE_INTEGER) { -+ dev_err(dev, "DPMT: revision/count not integers\n"); -+ ret = -EINVAL; -+ goto out_free; -+ } -+ -+ count = cnt_obj->integer.value; -+ if (count != obj->package.count - DSM_DPM_DPMT_DCFG) { -+ dev_err(dev, "DPMT: count %llu != package devices %u\n", -+ count, obj->package.count - DSM_DPM_DPMT_DCFG); -+ ret = -EINVAL; -+ goto out_free; -+ } -+ -+ ctrl->configs = kcalloc(count, sizeof(*ctrl->configs), GFP_KERNEL); -+ if (!ctrl->configs) { -+ ret = -ENOMEM; -+ goto out_free; -+ } -+ ctrl->revision = rev_obj->integer.value; -+ ctrl->count = count; -+ -+ dev_info(dev, "DPM config from ACPI: revision=%llu, %llu devices\n", -+ ctrl->revision, count); -+ -+ for (i = 0; i < count; i++) { -+ union acpi_object *pkg = -+ &obj->package.elements[DSM_DPM_DPMT_DCFG + i]; -+ -+ ret = pwrap_parse_dev_package(dev, pkg, &ctrl->configs[i]); -+ if (ret) { -+ dev_err(dev, "DPMT: failed to parse device %u: %d\n", -+ i, ret); -+ pwrap_acpi_dpm_config_free(ctrl); -+ goto out_free; -+ } -+ } -+ -+out_free: -+ ACPI_FREE(obj); -+ return ret; -+} -+ -+void pwrap_acpi_dpm_config_free(struct pwrap_dev_ctrl *ctrl) -+{ -+ u64 i; -+ -+ if (!ctrl || !ctrl->configs) -+ return; -+ -+ for (i = 0; i < ctrl->count; i++) { -+ kfree(ctrl->configs[i].device_path); -+ kfree(ctrl->configs[i].device_type); -+ } -+ kfree(ctrl->configs); -+ ctrl->configs = NULL; -+ ctrl->count = 0; -+ ctrl->revision = 0; -+} -diff --git a/drivers/soc/mediatek/power_wrap/inc/power_wrap.h b/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -new file mode 100644 -index 0000000000..0553ce658c ---- /dev/null -+++ b/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -@@ -0,0 +1,151 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ */ -+#ifndef __MTK_PWRAP_H__ -+#define __MTK_PWRAP_H__ -+ -+#include -+#include -+ -+#include "pwrap_scmi.h" -+#include -+ -+#define PWRAP_MAX_COMP_NUM 20 -+/* Number of scalar constraint fields before the comp_states array */ -+#define PWRAP_IDLE_CONSTRAINT_SCALARS 3 -+ -+/* -+ * Max length of a normalized ACPI device path string. -+ * The longest path on MT8901 is "\_SB_.PCI2.RP0_.NVM_" (20 chars); -+ * 64 leaves ample headroom for deeper hierarchies. -+ */ -+#define PWRAP_DEV_PATH_MAX 64 -+ -+extern const guid_t pwrap_dsm_dpm_uuid; -+ -+enum pwrap_control_type { -+ CTRL_NONE = 0, -+ CTRL_BY_PWRAP = 1, -+ CTRL_BY_SCMI = 2, -+}; -+ -+enum pwrap_dsm_dpm_func_rev { -+ DSM_DPM_REV_0 = 0, -+}; -+ -+enum pwrap_dsm_dpm_func_idx { -+ DSM_DPM_GET_SUPPORT_FUNC = 0, -+ DSM_DPM_GET_DEV_CTRL_INFO, -+}; -+ -+enum pwrap_dsm_dpm_dpmt_idx { -+ DSM_DPM_DPMT_REV = 0, -+ DSM_DPM_DPMT_COUNT, -+ DSM_DPM_DPMT_DCFG, -+}; -+ -+/* -+ * Field layout of one device package inside the DPMT (DSM_DPM_DPMT_DCFG+). -+ * ASL (Cpu.asl, UUID 64B66B51, Case 1): -+ * Package(){ "", "", Package(){constraints}, } -+ */ -+enum pwrap_dpm_dev_pkg_idx { -+ DPM_DEV_PATH = 0, -+ DPM_DEV_TYPE, -+ DPM_DEV_CONSTRAINTS, -+ DPM_DEV_CONTROL_TYPE, -+ DPM_DEV_PKG_COUNT, -+}; -+ -+struct pwrap_idle_constraints { -+ union { -+ struct { -+ u64 enable; -+ u64 device_state; -+ u64 comp_count; -+ u64 comp_states[PWRAP_MAX_COMP_NUM]; -+ }; -+ u64 values[PWRAP_MAX_COMP_NUM + 3]; -+ }; -+}; -+ -+/* Device configuration data structure */ -+struct pwrap_dev_config { -+ char *device_path; -+ char *device_type; -+ struct pwrap_idle_constraints constraints; -+ enum pwrap_control_type control_type; -+ struct pwrap_scmi_config scmi_config; -+}; -+ -+/* Device control structure */ -+struct pwrap_dev_ctrl { -+ u64 revision; -+ u64 count; -+ struct pwrap_dev_config *configs; -+}; -+ -+struct mtk_pwrap_device { -+ const char *name; -+ unsigned int dev_id; -+}; -+ -+/* Driver private data */ -+struct pwrap_driver_data { -+ struct device *dev; -+ //struct pwrap_dev_ctrl dev_ctrl; -+ struct platform_device *pdev; -+ struct acpi_buffer acpi_path; -+}; -+ -+/* Getter for static pwrap_dev_ctrl */ -+struct pwrap_dev_ctrl *pwrap_get_dev_ctrl(void); -+void *pwrap_query_dev_config(const char *dev_path); -+ -+/* ============================================================ -+ * DPM device-control config from ACPI (UUID 64B66B51) -+ * ============================================================ -+ * -+ * Implemented in acpiutil.c. Declared here because they operate on -+ * struct pwrap_dev_ctrl / pwrap_scmi_config, which are defined above. -+ */ -+ -+/** -+ * pwrap_acpi_normalize_path() - Pad ACPI NameSegs to 4 chars with '_' -+ * @in: source path as written in the _DSM literal (e.g. "\\_SB.DSP1") -+ * @out: destination buffer of size @out_sz (>= PWRAP_DEV_PATH_MAX) -+ * @out_sz: size of @out -+ * -+ * ACPI NameSegs are fixed 4 bytes, short names trailing-padded with '_' -+ * (ACPI spec 19.2.2 / 5.3). acpi_get_name(ACPI_FULL_PATHNAME) emits the -+ * padded form, but _DSM string literals are unpadded. Normalizing makes -+ * the fetched path match the keys used by pwrap_query_dev_config(). -+ * -+ * Return: 0 on success, -EINVAL on bad input, -ENOSPC if too long. -+ */ -+int pwrap_acpi_normalize_path(const char *in, char *out, size_t out_sz); -+ -+/** -+ * pwrap_acpi_fetch_dpm_config() - Populate pwrap_dev_ctrl from DPM _DSM -+ * @dev: PEPD ACPI device -+ * @ctrl: device-control table to fill (configs[] is kalloc'd here) -+ * -+ * Evaluates UUID 64B66B51 function 1 (DPMT), parses every device package -+ * (path/type/constraints/control_type), normalizes the path, and for -+ * CTRL_BY_SCMI devices fetches the per-device SCMI dev_id via GDSC(). -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ -+int pwrap_acpi_fetch_dpm_config(struct device *dev, -+ struct pwrap_dev_ctrl *ctrl); -+ -+/** -+ * pwrap_acpi_dpm_config_free() - Free a pwrap_dev_ctrl built from ACPI -+ * @ctrl: table previously filled by pwrap_acpi_fetch_dpm_config() -+ * -+ * Frees each kstrdup'd device_path/device_type and the configs[] array. -+ */ -+void pwrap_acpi_dpm_config_free(struct pwrap_dev_ctrl *ctrl); -+ -+#endif -diff --git a/drivers/soc/mediatek/power_wrap/inc/pwrap_scmi.h b/drivers/soc/mediatek/power_wrap/inc/pwrap_scmi.h -new file mode 100644 -index 0000000000..fe924e8e34 ---- /dev/null -+++ b/drivers/soc/mediatek/power_wrap/inc/pwrap_scmi.h -@@ -0,0 +1,81 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ */ -+#ifndef __MTK_PWRAP_SCMI_H__ -+#define __MTK_PWRAP_SCMI_H__ -+ -+#include -+#include -+ -+#ifdef CONFIG_MTK_SSPM_CI -+int sspm_ci_set(u32 feature_id, -+ u32 p1, u32 p2, u32 p3, u32 p4, u32 p5); -+#else -+static inline int sspm_ci_set(u32 feature_id, -+ u32 p1, u32 p2, u32 p3, u32 p4, u32 p5) -+{ -+ return -ENODEV; -+} -+#endif /* CONFIG_MTK_SSPM_CI */ -+ -+#define PWRAP_SCMI_DEV_ACT_ID(_a) ((_a) & (U8_MAX << 24)) -+#define PWRAP_SCMI_DEV_STATE(_s) (((u8) (_s) & U8_MAX) << 16) -+#define PWRAP_SCMI_DEV_DRIV_CMPLT(_c) (((u8) (_c) & U8_MAX) << 8) -+#define PWRAP_SCMI_SYS_TRANS(_t) ((u8) (_t) & U8_MAX) -+ -+#define PWRAP_SCMI_DEV_ACT_PAYLOAD(_a, _s, _c, _t) \ -+ (PWRAP_SCMI_DEV_ACT_ID(_a) | PWRAP_SCMI_DEV_STATE(_s) | \ -+ PWRAP_SCMI_DEV_DRIV_CMPLT(_c) | PWRAP_SCMI_SYS_TRANS(_t)) -+ -+#define PWRAP_SCMI_COM_ACT_ID(_a) ((_a) & (U8_MAX << 24)) -+#define PWRAP_SCMI_COM_IDX(_c) (((u8) (_c) & U8_MAX) << 16) -+#define PWRAP_SCMI_COM_STATE(_s) (((u8) (_s) & U8_MAX) << 8) -+#define PWRAP_COM_DRIV_NOTIFIED(_d) ((u8) (_d) & U8_MAX) -+ -+#define PWRAP_SCMI_COM_ACT_PAYLOAD(_a, _c, _s, _d) \ -+ (PWRAP_SCMI_COM_ACT_ID(_a) | PWRAP_SCMI_COM_IDX(_c) | \ -+ PWRAP_SCMI_COM_STATE(_s) | PWRAP_COM_DRIV_NOTIFIED(_d)) -+ -+#define SCMI_PROBE_ACTION_ID 0x01000000 -+#define SCMI_DEV_STATE_ACTION_ID 0x02000000 -+#define SCMI_COM_IDLE_ACTION_ID 0x03000000 -+#define SCMI_DEV_REQUEST_ACTION_ID 0x04000000 -+#define SCMI_DEV_ABANDON_ACTION_ID 0x05000000 -+ -+#define SCMI_CONFIG_INIT(_dev) { \ -+ .feat_id = 0x0D, \ -+ .dev_id = _dev, \ -+ .data = { \ -+ [SCMI_DEV_PROBE] = {SCMI_PROBE_ACTION_ID}, \ -+ [SCMI_DEV_STATE] = {SCMI_DEV_STATE_ACTION_ID}, \ -+ [SCMI_COM_IDLE] = {SCMI_COM_IDLE_ACTION_ID}, \ -+ [SCMI_DEV_REQUEST] = {SCMI_DEV_REQUEST_ACTION_ID}, \ -+ [SCMI_DEV_ADANDON] = {SCMI_DEV_ABANDON_ACTION_ID}, \ -+ } \ -+ } -+ -+enum mtk_pwrap_scmi_notify { -+ SCMI_DEV_PROBE = 0, -+ SCMI_DEV_STATE, -+ SCMI_COM_IDLE, -+ SCMI_DEV_REQUEST, -+ SCMI_DEV_ADANDON, -+ SCMI_NOTIFY_NUMBER, -+}; -+ -+enum mtk_pwrap_scmi_data { -+ SCMI_DATA_00 = 0, -+ SCMI_DATA_01, -+ SCMI_DATA_02, -+ SCMI_DATA_03, -+ SCMI_DATA_NUMBER, -+}; -+ -+struct pwrap_scmi_config { -+ u32 feat_id; -+ u32 dev_id; -+ u32 data[SCMI_NOTIFY_NUMBER][SCMI_DATA_NUMBER]; -+}; -+ -+#endif -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -new file mode 100644 -index 0000000000..84bed7d377 ---- /dev/null -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -0,0 +1,446 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "power_wrap.h" -+ -+/* -+ * ACPI _DSM UUID for DPM -+ * (64B66B51-38F7-3391-C689-4FA2109179AB) -+ */ -+const guid_t pwrap_dsm_dpm_uuid = GUID_INIT( -+ 0x64b66b51, 0x38f7, 0x3391, -+ 0xc6, 0x89, 0x4f, 0xa2, 0x10, 0x91, 0x79, 0xab -+); -+ -+enum mtk_pwrap_type { -+ NVDA6210, -+}; -+ -+enum acpi_crs_mem_res { -+ /* ACPI memory resource data type */ -+ ACPI_CRS_MEM_RES0 = 0, -+ ACPI_CRS_MEM_RES1, -+ ACPI_CRS_MEM_RES_NUM, -+}; -+ -+enum acpi_crs_irq_res { -+ /* ACPI interrupt resource data type */ -+ ACPI_CRS_IRQ_RES0 = 0, -+ ACPI_CRS_IRQ_RES1, -+ ACPI_CRS_IRQ_RES_NUM, -+}; -+ -+static struct pwrap_dev_ctrl dev_ctrl; -+ -+/* Getter for static pwrap_dev_ctrl */ -+struct pwrap_dev_ctrl *pwrap_get_dev_ctrl(void) -+{ -+ return &dev_ctrl; -+} -+ -+/* -+ * Query dev_config by device path. -+ * Return pointer to struct pwrap_dev_config as void*, NULL otherwise. -+ */ -+void *pwrap_query_dev_config(const char *dev_path) -+{ -+ struct pwrap_dev_ctrl *ctrl = pwrap_get_dev_ctrl(); -+ -+ if (!dev_path) -+ return NULL; -+ -+ //pr_info("%s: search dev_path \"%s\"\n", -+ // __func__, dev_path); -+ -+ if (!ctrl || !ctrl->configs) -+ return NULL; -+ -+ for (int i = 0; i < ctrl->count; ++i) { -+ char *cfg_path = ctrl->configs[i].device_path; -+ //pr_info("%s: device configs[%d] path %s\n", -+ // __func__, i, ctrl->configs[i].device_path); -+ if (cfg_path && strcmp(dev_path, cfg_path) == 0) -+ return (void *) &ctrl->configs[i]; -+ } -+ return NULL; -+} -+ -+/* -+ * Common SCMI dispatch helper. -+ * Logs the raw payload, then calls sspm_ci_set() with the provided composite -+ * word as DATA_00 and the remaining three data words from the action slot. -+ * Returns the sspm_ci_set() return value, or -EINVAL if control_type is not -+ * CTRL_BY_SCMI. -+ */ -+static int pwrap_scmi_dispatch(struct pwrap_dev_config *cfg, -+ u8 action_idx, u32 composite, -+ const char *action_name) -+{ -+ if (cfg->control_type != CTRL_BY_SCMI) { -+ pr_warn("%s: control type 0x%x is not scmi for dev %s\n", -+ action_name, cfg->control_type, cfg->device_path); -+ return -EINVAL; -+ } -+ -+ pr_debug("%s: scmi payload: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", -+ action_name, -+ cfg->scmi_config.feat_id, -+ cfg->scmi_config.dev_id, -+ composite, -+ cfg->scmi_config.data[action_idx][SCMI_DATA_01], -+ cfg->scmi_config.data[action_idx][SCMI_DATA_02], -+ cfg->scmi_config.data[action_idx][SCMI_DATA_03]); -+ -+ return sspm_ci_set(cfg->scmi_config.feat_id, -+ cfg->scmi_config.dev_id, -+ composite, -+ cfg->scmi_config.data[action_idx][SCMI_DATA_01], -+ cfg->scmi_config.data[action_idx][SCMI_DATA_02], -+ cfg->scmi_config.data[action_idx][SCMI_DATA_03]); -+} -+ -+int mtk_pwrap_dev_request(void *dev_cfg) -+{ -+ struct pwrap_dev_config *cfg = (struct pwrap_dev_config *)dev_cfg; -+ -+ if (!cfg) -+ return -ENODEV; -+ return pwrap_scmi_dispatch(cfg, SCMI_DEV_REQUEST, -+ cfg->scmi_config.data[SCMI_DEV_REQUEST][SCMI_DATA_00], -+ __func__); -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_dev_request); -+ -+int mtk_pwrap_dev_remove(void *dev_cfg) -+{ -+ struct pwrap_dev_config *cfg = (struct pwrap_dev_config *)dev_cfg; -+ -+ if (!cfg) -+ return -ENODEV; -+ return pwrap_scmi_dispatch(cfg, SCMI_DEV_ADANDON, -+ cfg->scmi_config.data[SCMI_DEV_ADANDON][SCMI_DATA_00], -+ __func__); -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_dev_remove); -+ -+int mtk_pwrap_dev_suspend(void *dev_cfg, u8 sys_trans) -+{ -+ struct pwrap_dev_config *cfg = (struct pwrap_dev_config *)dev_cfg; -+ u32 composite; -+ -+ if (!cfg) -+ return -ENODEV; -+ composite = PWRAP_SCMI_DEV_ACT_PAYLOAD( -+ cfg->scmi_config.data[SCMI_DEV_STATE][SCMI_DATA_00], DEV_STA_D3, 1, sys_trans); -+ return pwrap_scmi_dispatch(cfg, SCMI_DEV_STATE, composite, __func__); -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_dev_suspend); -+ -+int mtk_pwrap_dev_resume(void *dev_cfg, u8 sys_trans) -+{ -+ struct pwrap_dev_config *cfg = (struct pwrap_dev_config *)dev_cfg; -+ u32 composite; -+ -+ if (!cfg) -+ return -ENODEV; -+ composite = PWRAP_SCMI_DEV_ACT_PAYLOAD( -+ cfg->scmi_config.data[SCMI_DEV_STATE][SCMI_DATA_00], DEV_STA_D0, 0, sys_trans); -+ return pwrap_scmi_dispatch(cfg, SCMI_DEV_STATE, composite, __func__); -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_dev_resume); -+ -+int mtk_pwrap_com_idle(void *dev_cfg, u8 com_idx) -+{ -+ struct pwrap_dev_config *cfg = (struct pwrap_dev_config *)dev_cfg; -+ u32 composite; -+ -+ if (!cfg) -+ return -ENODEV; -+ composite = PWRAP_SCMI_DEV_ACT_PAYLOAD( -+ cfg->scmi_config.data[SCMI_COM_IDLE][SCMI_DATA_00], com_idx, COM_STA_L1, 1); -+ return pwrap_scmi_dispatch(cfg, SCMI_COM_IDLE, composite, __func__); -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_com_idle); -+ -+int mtk_pwrap_com_active(void *dev_cfg, u8 com_idx) -+{ -+ struct pwrap_dev_config *cfg = (struct pwrap_dev_config *)dev_cfg; -+ u32 composite; -+ -+ if (!cfg) -+ return -ENODEV; -+ composite = PWRAP_SCMI_DEV_ACT_PAYLOAD( -+ cfg->scmi_config.data[SCMI_COM_IDLE][SCMI_DATA_00], com_idx, COM_STA_L0, 0); -+ return pwrap_scmi_dispatch(cfg, SCMI_COM_IDLE, composite, __func__); -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_com_active); -+ -+/* -+ * Probe dev_config by ACPI path, with SCMI log if needed. -+ * Return pointer to struct pwrap_dev_config as void*, NULL otherwise. -+ */ -+void *mtk_pwrap_dev_probe(const char *acpi_path) -+{ -+ int ret = 0; -+ struct pwrap_dev_config *cfg = -+ (struct pwrap_dev_config *) pwrap_query_dev_config(acpi_path); -+ -+ if (!cfg) -+ return NULL; -+ -+ pr_info("%s: Device found at path %s\n", __func__, cfg->device_path); -+ -+ if (cfg->control_type == CTRL_BY_SCMI) { -+ pr_info("%s: control type is scmi, payload: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", -+ __func__, -+ cfg->scmi_config.feat_id, -+ cfg->scmi_config.dev_id, -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_00], -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_01], -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_02], -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_03]); -+ -+ ret = sspm_ci_set( -+ cfg->scmi_config.feat_id, -+ cfg->scmi_config.dev_id, -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_00], -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_01], -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_02], -+ cfg->scmi_config.data[SCMI_DEV_PROBE][SCMI_DATA_03]); -+ -+ if (ret) { -+ pr_warn("%s: scmi ret = %d for device \"%s\"\n", -+ __func__, ret, acpi_path); -+ cfg = NULL; -+ } -+ } -+ return (void *) cfg; -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_dev_probe); -+ -+static int pwrap_config_resource(struct platform_device *pdev, kernel_ulong_t driver_data) -+{ -+ enum mtk_pwrap_type type; -+ struct resource *res; -+ int irq; -+ -+ if (!pdev) -+ return -ENODEV; -+ -+ type = (enum mtk_pwrap_type)driver_data; -+ switch (type) { -+ case NVDA6210: -+ res = platform_get_resource(pdev, IORESOURCE_MEM, ACPI_CRS_MEM_RES0); -+ if (!res) { -+ dev_err(&pdev->dev, "no memory resource for index: 0x%x\n", -+ ACPI_CRS_MEM_RES0); -+ return -ENOMEM; -+ } -+ dev_info(&pdev->dev, "ACPI MEM index 0x%x: start = 0x%llx, size = 0x%llx\n", -+ ACPI_CRS_MEM_RES0, -+ (unsigned long long)res->start, -+ (unsigned long long)resource_size(res)); -+ -+ irq = platform_get_irq(pdev, ACPI_CRS_IRQ_RES0); -+ if (irq < 0) { -+ dev_err(&pdev->dev, "no IRQ resource for index: 0x%x, error: %d\n", -+ ACPI_CRS_IRQ_RES0, irq); -+ return irq; -+ } -+ dev_info(&pdev->dev, "ACPI IRQ index 0x%x: number = %d\n", -+ ACPI_CRS_IRQ_RES0, irq); -+ break; -+ default: -+ dev_err(&pdev->dev, "not support memory resource for type: 0x%x\n", type); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int pwrap_acpi_config_init(struct device *dev) -+{ -+ struct pwrap_dev_ctrl *ctrl = pwrap_get_dev_ctrl(); -+ int err; -+ -+ if (!dev) -+ return -ENODEV; -+ -+ if (!ctrl) -+ return -EINVAL; -+ -+ dev_info(dev, "Config dev ctrl info from ACPI data\n"); -+ -+ /* -+ * Parse the full DPMT (UUID 64B66B51, func 1) into ctrl: device path, -+ * type, constraints, control_type, and - for SCMI devices - the -+ * per-device dev_id via GDSC(). Implemented in acpiutil.c. -+ */ -+ err = pwrap_acpi_fetch_dpm_config(dev, ctrl); -+ if (err) { -+ dev_err(dev, "Failed to fetch DPM config from ACPI: %d\n", err); -+ memset(ctrl, 0, sizeof(struct pwrap_dev_ctrl)); -+ } -+ -+ return err; -+} -+ -+static void pwrap_free_acpi_path(void *pointer) -+{ -+ ACPI_FREE(pointer); -+} -+ -+/** -+ * pwrap_probe_init_resources() - Set up drvdata, ACPI path, and device configs -+ * @priv: driver private data (pdev/dev already set by caller) -+ * @adev: ACPI companion device -+ * @id: matched ACPI device id (carries driver_data for resource config) -+ * -+ * Resolves the ACPI device path, configures the platform resources (MEM/IRQ), -+ * initializes the device control config from ACPI _DSM, and then runs the -+ * initial SCMI device probe against the populated -+ * config table. The device config init is non-fatal (logged as a warning); -+ * ACPI path resolution and resource config failures are fatal. -+ * -+ * Return: 0 on success, negative errno on a fatal resource/ACPI failure. -+ */ -+static int pwrap_probe_init_resources(struct pwrap_driver_data *priv, -+ struct acpi_device *adev, -+ const struct acpi_device_id *id) -+{ -+ struct platform_device *pdev = priv->pdev; -+ struct device *dev = priv->dev; -+ acpi_status status; -+ int ret; -+ -+ priv->acpi_path.length = ACPI_ALLOCATE_BUFFER; -+ priv->acpi_path.pointer = NULL; -+ status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &priv->acpi_path); -+ if (ACPI_FAILURE(status)) { -+ dev_err(&pdev->dev, "Failed to get ACPI device path\n"); -+ return -EINVAL; -+ } -+ ret = devm_add_action_or_reset(dev, pwrap_free_acpi_path, -+ priv->acpi_path.pointer); -+ if (ret) -+ return ret; -+ -+ ret = pwrap_config_resource(pdev, id->driver_data); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to setup resource for type: 0x%x with error: 0x%x\n", -+ (enum mtk_pwrap_type)id->driver_data, ret); -+ return ret; -+ } -+ -+ ret = pwrap_acpi_config_init(dev); -+ if (ret) -+ dev_warn(&pdev->dev, -+ "Device config init failed: %d (SCMI device control disabled)\n", -+ ret); -+ -+ /* -+ * Run the initial SCMI device probe only after the device-config table -+ * has been populated by pwrap_acpi_config_init(); otherwise the lookup -+ * walks an empty table and the boot-time SCMI probe is silently skipped. -+ */ -+ if (!mtk_pwrap_dev_probe((char *)priv->acpi_path.pointer)) -+ dev_err(&pdev->dev, "Not find device config data\n"); -+ -+ return 0; -+} -+ -+static int mtk_pwrap_probe(struct platform_device *pdev) -+{ -+ const struct acpi_device_id *id; -+ struct device *dev = &pdev->dev; -+ struct acpi_device *adev = ACPI_COMPANION(dev); -+ int ret; -+ struct pwrap_driver_data *priv; -+ -+ if (!adev) -+ return -ENODEV; -+ -+ id = acpi_match_device(dev->driver->acpi_match_table, dev); -+ if (!id) -+ return -ENODEV; -+ -+ dev_info(&pdev->dev, "device probe for \"%s\"\n", id->id); -+ -+ /* -+ * dev_ctrl is one static table shared with every consumer; a second -+ * matching device would replace it underneath them, so refuse it. -+ */ -+ if (pwrap_get_dev_ctrl()->configs) -+ return dev_err_probe(dev, -EBUSY, -+ "power_wrap already bound, single instance only\n"); -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, priv); -+ priv->pdev = pdev; -+ priv->dev = dev; -+ -+ /* Resolve ACPI path, configure resources, init device configs */ -+ ret = pwrap_probe_init_resources(priv, adev, id); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+#ifdef CONFIG_ACPI -+static const struct acpi_device_id mtk_pwrap_acpi_ids[] = { -+ { .id = "NVDA6210", .driver_data = NVDA6210 }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(acpi, mtk_pwrap_acpi_ids); -+#endif /* CONFIG_ACPI */ -+ -+static struct platform_driver mtk_pwrap_driver = { -+ .driver = { -+ .name = "mtk_pwrap", -+#ifdef CONFIG_ACPI -+ .acpi_match_table = mtk_pwrap_acpi_ids, -+#endif /* CONFIG_ACPI */ -+ /* -+ * mtk_pwrap_dev_probe() hands consumers raw pointers into the -+ * dev_ctrl configs[] table. The driver is built in, the ACPI -+ * device is never hot-removed and there is no remove callback, -+ * so the table lives for the lifetime of the kernel and those -+ * pointers stay valid. Suppress the sysfs bind/unbind -+ * attributes so userspace cannot rebind the driver either. -+ */ -+ .suppress_bind_attrs = true, -+ }, -+ .probe = mtk_pwrap_probe, -+}; -+ -+static int __init power_wrap_init(void) -+{ -+ int ret = 0; -+ -+ ret = platform_driver_register(&mtk_pwrap_driver); -+ -+ pr_info("%s driver register: %d\n", __func__, ret); -+ -+ return ret; -+} -+ -+/* -+ * This driver is built-in (obj-y) and bound for the lifetime of the system; -+ * it provides no module_exit() and no platform remove callback. -+ */ -+subsys_initcall(power_wrap_init); -+MODULE_LICENSE("GPL"); -diff --git a/include/linux/soc/mediatek/mtk-pwrap.h b/include/linux/soc/mediatek/mtk-pwrap.h -new file mode 100644 -index 0000000000..e884a461a7 ---- /dev/null -+++ b/include/linux/soc/mediatek/mtk-pwrap.h -@@ -0,0 +1,73 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ */ -+#ifndef __MTK_PWRAP_PUBLIC_H__ -+#define __MTK_PWRAP_PUBLIC_H__ -+ -+#include -+#include -+ -+enum mtk_pwrap_dev_state { -+ DEV_STA_UNKNOWN = 0, -+ DEV_STA_D0, -+ DEV_STA_D1, -+ DEV_STA_D2, -+ DEV_STA_D3, -+ DEV_STA_MAX -+}; -+ -+enum mtk_pwrap_com_state { -+ COM_STA_L0 = 0, -+ COM_STA_L1, -+ COM_STA_L2, -+ COM_STA_L3, -+ COM_STA_MAX -+}; -+ -+#ifdef CONFIG_MTK_POWER_WRAP -+int mtk_pwrap_dev_request(void *dev_ctrl); -+int mtk_pwrap_dev_remove(void *dev_ctrl); -+int mtk_pwrap_dev_suspend(void *dev_ctrl, u8 sys_trans); -+int mtk_pwrap_dev_resume(void *dev_ctrl, u8 sys_trans); -+int mtk_pwrap_com_idle(void *dev_ctrl, u8 com_idx); -+int mtk_pwrap_com_active(void *dev_ctrl, u8 com_idx); -+void *mtk_pwrap_dev_probe(const char *acpi_path); -+#else -+static inline int mtk_pwrap_dev_request(void *dev_ctrl) -+{ -+ return -ENODEV; -+} -+ -+static inline int mtk_pwrap_dev_remove(void *dev_ctrl) -+{ -+ return -ENODEV; -+} -+ -+static inline int mtk_pwrap_dev_suspend(void *dev_ctrl, u8 sys_trans) -+{ -+ return -ENODEV; -+} -+ -+static inline int mtk_pwrap_dev_resume(void *dev_ctrl, u8 sys_trans) -+{ -+ return -ENODEV; -+} -+ -+static inline int mtk_pwrap_com_idle(void *dev_ctrl, u8 com_idx) -+{ -+ return -ENODEV; -+} -+ -+static inline int mtk_pwrap_com_active(void *dev_ctrl, u8 com_idx) -+{ -+ return -ENODEV; -+} -+ -+static inline void *mtk_pwrap_dev_probe(const char *acpi_path) -+{ -+ return NULL; -+} -+#endif /* CONFIG_MTK_POWER_WRAP */ -+ -+#endif -From dd0cc8c04e7b0bd3a918484bb51fb6e4d03bd810 Mon Sep 17 00:00:00 2001 -From: "mayuresh.wani" -Date: Thu, 3 Sep 2026 22:49:31 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: power_wrap: add sysfs debug - interface - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Add a sysfs interface to the power_wrap driver for inspecting and -exercising device power control requests from userspace. This is a -debug and validation aid; the functional path is the in-kernel client -API and the ACPI flows. - -Signed-off-by: mayuresh.wani -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - drivers/soc/mediatek/power_wrap/Makefile | 1 + - .../soc/mediatek/power_wrap/inc/power_wrap.h | 3 + - drivers/soc/mediatek/power_wrap/power_wrap.c | 10 + - .../mediatek/power_wrap/power_wrap_sysfs.c | 433 ++++++++++++++++++ - 4 files changed, 447 insertions(+) - create mode 100644 drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c - -diff --git a/drivers/soc/mediatek/power_wrap/Makefile b/drivers/soc/mediatek/power_wrap/Makefile -index 3a551b55b3..0765daf225 100644 ---- a/drivers/soc/mediatek/power_wrap/Makefile -+++ b/drivers/soc/mediatek/power_wrap/Makefile -@@ -3,6 +3,7 @@ - # Composite name power_wrap_drv avoids colliding with the source file power_wrap.o - obj-y += power_wrap_drv.o - power_wrap_drv-y += power_wrap.o -+power_wrap_drv-y += power_wrap_sysfs.o - power_wrap_drv-y += acpiutil.o - - ccflags-y += -Wall -diff --git a/drivers/soc/mediatek/power_wrap/inc/power_wrap.h b/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -index 0553ce658c..ee0181dab1 100644 ---- a/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -+++ b/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -@@ -99,6 +99,9 @@ struct pwrap_driver_data { - struct acpi_buffer acpi_path; - }; - -+/* Create the sysfs debug/test nodes (non-fatal; group is devm-managed) */ -+int pwrap_create_sys_files(struct platform_device *pdev); -+ - /* Getter for static pwrap_dev_ctrl */ - struct pwrap_dev_ctrl *pwrap_get_dev_ctrl(void); - void *pwrap_query_dev_config(const char *dev_path); -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index 84bed7d377..fc38f14efb 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -397,6 +397,16 @@ static int mtk_pwrap_probe(struct platform_device *pdev) - if (ret) - return ret; - -+ /* -+ * The sysfs nodes are debug/test hooks. Their creation must not fail -+ * probe or disable the driver, so log a warning and continue if the -+ * attribute group could not be added. -+ */ -+ ret = pwrap_create_sys_files(pdev); -+ if (ret) -+ dev_warn(&pdev->dev, -+ "failed to create sysfs nodes: %d (continuing)\n", ret); -+ - return 0; - } - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c b/drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c -new file mode 100644 -index 0000000000..b8d196f4ac ---- /dev/null -+++ b/drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c -@@ -0,0 +1,433 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ * -+ * power_wrap_sysfs.c - sysfs interface for the power_wrap driver -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "power_wrap.h" -+ -+#define SYSFS_BUF_SIZE 128 -+ -+/* -+ * search_path caches the last path written via pwrap_dev_config_query_store() -+ * for the paired _show() to look up. It is shared state, so serialize all -+ * store/show access under search_path_lock to prevent a concurrent writer from -+ * tearing the string a reader is parsing. -+ */ -+static char search_path[SYSFS_BUF_SIZE]; -+static DEFINE_MUTEX(search_path_lock); -+ -+/** -+ * pwrap_sysfs_get_cfg() - Parse an ACPI path from a sysfs write and look it up -+ * @buf: sysfs write buffer (NOT NUL-terminated; @count valid bytes) -+ * @count: number of bytes written -+ * @path: caller-provided output buffer of size SYSFS_BUF_SIZE -+ * @out_cfg: receives the matching struct pwrap_dev_config pointer on success -+ * -+ * Copies @count bytes into @path, NUL-terminates, strips a trailing newline, -+ * logs the parsed path, and looks up the device config via -+ * pwrap_query_dev_config(). -+ * -+ * Return: 0 and sets *@out_cfg on success, -EINVAL if the input exceeds the -+ * buffer, -ENODEV if no device config matches the path. -+ */ -+static int pwrap_sysfs_get_cfg(const char *buf, size_t count, char *path, -+ void **out_cfg) -+{ -+ char norm[SYSFS_BUF_SIZE]; -+ -+ if (count >= SYSFS_BUF_SIZE) -+ return -EINVAL; -+ -+ memcpy(path, buf, count); -+ path[count] = '\0'; -+ if (count > 0 && path[count - 1] == '\n') -+ path[count - 1] = '\0'; -+ -+ pr_info("power_wrap sysfs: user input acpi device path = %s\n", path); -+ -+ /* -+ * Device configs are stored under padded ACPI paths (\_SB_.USB0); -+ * accept the unpadded spelling users type (\_SB.USB0) too. -+ */ -+ if (pwrap_acpi_normalize_path(path, norm, sizeof(norm))) -+ return -EINVAL; -+ -+ *out_cfg = pwrap_query_dev_config(norm); -+ if (!*out_cfg) { -+ pr_warn("power_wrap sysfs: no device config for path %s\n", path); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static ssize_t pwrap_dev_probe_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ int len = 0; -+ struct pwrap_dev_ctrl *ctrl = pwrap_get_dev_ctrl(); -+ -+ if (!ctrl) { -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "pwrap_dev_ctrl not available\n"); -+ return len; -+ } -+ -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "revision = %llu\ncount = %llu\n", ctrl->revision, ctrl->count); -+ -+ if (ctrl->count > 0 && ctrl->configs) { -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "Device List:\n"); -+ for (int i = 0; i < ctrl->count && len < PAGE_SIZE - 1; ++i) { -+ const char *path = ctrl->configs[i].device_path ? -+ ctrl->configs[i].device_path : "(null)"; -+ int type = ctrl->configs[i].control_type; -+ -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " [%d] device_path = %s, control_type = %d", i, path, type); -+ switch (type) { -+ case CTRL_NONE: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (CTRL_NONE)"); -+ break; -+ case CTRL_BY_PWRAP: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (CTRL_BY_PWRAP)"); -+ break; -+ case CTRL_BY_SCMI: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (CTRL_BY_SCMI)"); -+ break; -+ default: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (UNKNOWN)"); -+ break; -+ } -+ len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); -+ if (len >= PAGE_SIZE - 1) { -+ len += scnprintf(buf + len, PAGE_SIZE - len, "[truncated]\n"); -+ break; -+ } -+ } -+ } -+ -+ return len; -+} -+ -+static ssize_t pwrap_dev_probe_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char acpi_path[SYSFS_BUF_SIZE]; -+ char norm[SYSFS_BUF_SIZE]; -+ void *dev_cfg; -+ -+ if (count >= SYSFS_BUF_SIZE) -+ return -EINVAL; -+ -+ memcpy(acpi_path, buf, count); -+ acpi_path[count] = '\0'; -+ if (count > 0 && acpi_path[count - 1] == '\n') -+ acpi_path[count - 1] = '\0'; -+ -+ pr_info("power_wrap sysfs: user input acpi device path = %s\n", acpi_path); -+ -+ /* The config table holds padded paths (\_SB_.USB0); accept the unpadded form too. */ -+ if (pwrap_acpi_normalize_path(acpi_path, norm, sizeof(norm))) -+ return -EINVAL; -+ -+ dev_cfg = mtk_pwrap_dev_probe(norm); -+ if (!dev_cfg) { -+ pr_warn("power_wrap sysfs: device probe failed for path %s\n", -+ acpi_path); -+ return -ENODEV; -+ } -+ -+ return count; -+} -+DEVICE_ATTR_RW(pwrap_dev_probe); -+ -+static ssize_t pwrap_dev_remove_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char acpi_path[SYSFS_BUF_SIZE]; -+ void *dev_cfg; -+ int err; -+ -+ err = pwrap_sysfs_get_cfg(buf, count, acpi_path, &dev_cfg); -+ if (err) -+ return err; -+ -+ err = mtk_pwrap_dev_remove(dev_cfg); -+ if (err) -+ return err; -+ -+ return count; -+} -+DEVICE_ATTR_WO(pwrap_dev_remove); -+ -+static ssize_t pwrap_dev_request_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char acpi_path[SYSFS_BUF_SIZE]; -+ void *dev_cfg; -+ int err; -+ -+ err = pwrap_sysfs_get_cfg(buf, count, acpi_path, &dev_cfg); -+ if (err) -+ return err; -+ -+ err = mtk_pwrap_dev_request(dev_cfg); -+ if (err) -+ return err; -+ -+ return count; -+} -+DEVICE_ATTR_WO(pwrap_dev_request); -+ -+static ssize_t pwrap_dev_suspend_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char acpi_path[SYSFS_BUF_SIZE]; -+ void *dev_cfg; -+ int err; -+ -+ err = pwrap_sysfs_get_cfg(buf, count, acpi_path, &dev_cfg); -+ if (err) -+ return err; -+ -+ err = mtk_pwrap_dev_suspend(dev_cfg, 0); -+ if (err) -+ return err; -+ -+ return count; -+} -+DEVICE_ATTR_WO(pwrap_dev_suspend); -+ -+static ssize_t pwrap_dev_resume_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char acpi_path[SYSFS_BUF_SIZE]; -+ void *dev_cfg; -+ int err; -+ -+ err = pwrap_sysfs_get_cfg(buf, count, acpi_path, &dev_cfg); -+ if (err) -+ return err; -+ -+ err = mtk_pwrap_dev_resume(dev_cfg, 0); -+ if (err) -+ return err; -+ -+ return count; -+} -+DEVICE_ATTR_WO(pwrap_dev_resume); -+ -+static ssize_t pwrap_com_idle_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char acpi_path[SYSFS_BUF_SIZE]; -+ void *dev_cfg; -+ int err; -+ -+ err = pwrap_sysfs_get_cfg(buf, count, acpi_path, &dev_cfg); -+ if (err) -+ return err; -+ -+ err = mtk_pwrap_com_idle(dev_cfg, 0); -+ if (err) -+ return err; -+ -+ return count; -+} -+DEVICE_ATTR_WO(pwrap_com_idle); -+ -+static ssize_t pwrap_com_active_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char acpi_path[SYSFS_BUF_SIZE]; -+ void *dev_cfg; -+ int err; -+ -+ err = pwrap_sysfs_get_cfg(buf, count, acpi_path, &dev_cfg); -+ if (err) -+ return err; -+ -+ err = mtk_pwrap_com_active(dev_cfg, 0); -+ if (err) -+ return err; -+ -+ return count; -+} -+DEVICE_ATTR_WO(pwrap_com_active); -+ -+static ssize_t pwrap_dev_config_query_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct pwrap_dev_config *dev_cfg; -+ int len = 0; -+ int i, j; -+ -+ mutex_lock(&search_path_lock); -+ -+ if (search_path[0] == '\0') { -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "No device path set for search\n"); -+ mutex_unlock(&search_path_lock); -+ return len; -+ } -+ -+ dev_cfg = (struct pwrap_dev_config *) pwrap_query_dev_config(search_path); -+ mutex_unlock(&search_path_lock); -+ if (!dev_cfg) -+ return -ENODEV; -+ -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "device_path = %s\n", dev_cfg->device_path ? dev_cfg->device_path : "(null)"); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "device_type = %s\n", dev_cfg->device_type ? dev_cfg->device_type : "(null)"); -+ -+ // constraints -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "constraints:\n"); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " enable = %llu\n", dev_cfg->constraints.enable); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " device_state = %llu\n", dev_cfg->constraints.device_state); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " comp_count = %llu\n", dev_cfg->constraints.comp_count); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " comp_states = ["); -+ for (i = 0; i < dev_cfg->constraints.comp_count; i++) { -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "%llu%s", dev_cfg->constraints.comp_states[i], -+ (i < dev_cfg->constraints.comp_count - 1) ? ", " : ""); -+ } -+ len += scnprintf(buf + len, PAGE_SIZE - len, "]\n"); -+ -+ // control_type -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "control_type = %d", dev_cfg->control_type); -+ switch (dev_cfg->control_type) { -+ case CTRL_NONE: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (CTRL_NONE)\n"); -+ break; -+ case CTRL_BY_PWRAP: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (CTRL_BY_PWRAP)\n"); -+ break; -+ case CTRL_BY_SCMI: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (CTRL_BY_SCMI)\n"); -+ break; -+ default: -+ len += scnprintf(buf + len, PAGE_SIZE - len, " (UNKNOWN)\n"); -+ break; -+ } -+ -+ // scmi_config -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "scmi_config:\n"); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " feat_id = 0x%x\n", dev_cfg->scmi_config.feat_id); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " dev_id = 0x%x\n", dev_cfg->scmi_config.dev_id); -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ " data = [\n"); -+ for (i = 0; i < SCMI_NOTIFY_NUMBER; i++) { -+ len += scnprintf(buf + len, PAGE_SIZE - len, " ["); -+ for (j = 0; j < SCMI_DATA_NUMBER; j++) { -+ len += scnprintf(buf + len, PAGE_SIZE - len, -+ "0x%x%s", dev_cfg->scmi_config.data[i][j], -+ (j < SCMI_DATA_NUMBER - 1) ? ", " : ""); -+ } -+ len += scnprintf(buf + len, PAGE_SIZE - len, "]\n"); -+ } -+ len += scnprintf(buf + len, PAGE_SIZE - len, " ]\n"); -+ -+ return len; -+} -+ -+static ssize_t pwrap_dev_config_query_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char raw[SYSFS_BUF_SIZE]; -+ -+ if (count >= SYSFS_BUF_SIZE) -+ return -EINVAL; -+ -+ memcpy(raw, buf, count); -+ raw[count] = '\0'; -+ if (count > 0 && raw[count - 1] == '\n') -+ raw[count - 1] = '\0'; -+ -+ mutex_lock(&search_path_lock); -+ -+ /* Store the padded form so the lookup in _show() matches the table. */ -+ if (pwrap_acpi_normalize_path(raw, search_path, sizeof(search_path))) { -+ search_path[0] = '\0'; -+ mutex_unlock(&search_path_lock); -+ return -EINVAL; -+ } -+ -+ pr_info("power_wrap sysfs: user input acpi device path = %s\n", -+ search_path); -+ -+ mutex_unlock(&search_path_lock); -+ -+ return count; -+} -+DEVICE_ATTR_RW(pwrap_dev_config_query); -+ -+static struct attribute *pwrap_attrs[] = { -+ &dev_attr_pwrap_dev_probe.attr, -+ &dev_attr_pwrap_dev_remove.attr, -+ &dev_attr_pwrap_dev_request.attr, -+ &dev_attr_pwrap_dev_suspend.attr, -+ &dev_attr_pwrap_dev_resume.attr, -+ &dev_attr_pwrap_com_idle.attr, -+ &dev_attr_pwrap_com_active.attr, -+ &dev_attr_pwrap_dev_config_query.attr, -+ NULL, -+}; -+ -+static const struct attribute_group pwrap_group = { -+ .attrs = pwrap_attrs, -+}; -+ -+/** -+ * pwrap_create_sys_files() - Create the sysfs debug/test nodes -+ * @pdev: the power_wrap platform device -+ * -+ * Registers all nodes as one atomic attribute group: creation is -+ * all-or-nothing, so there is never a partial sysfs ABI. The group is -+ * devm-managed and removed automatically on unbind. -+ * -+ * These are debug/test nodes, so a creation failure must NOT fail probe or -+ * disable the driver - the SCMI device-control path stays functional either -+ * way. The caller logs and ignores the return value. -+ * -+ * Return: 0 on success, negative errno if the group could not be added. -+ */ -+int pwrap_create_sys_files(struct platform_device *pdev) -+{ -+ if (!pdev) -+ return -EINVAL; -+ -+ return devm_device_add_group(&pdev->dev, &pwrap_group); -+} -From 86f77d36229c2174d44654af1483a50569f9d6a8 Mon Sep 17 00:00:00 2001 -From: "mayuresh.wani" -Date: Thu, 3 Sep 2026 22:49:31 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: power_wrap: add client power - control API - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Add mtk_send_power_control_req(), the in-kernel client entry point -for pushing a power control command to the SSPM. Kernel drivers that -manage SSPM-controlled resources (for example the audio clock tree and -the audio DSP) fill a request descriptor and submit it through this -interface instead of open coding the SCMI exchange. - -Signed-off-by: mayuresh.wani -Signed-off-by: Kaushal Rajeev Butala -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - drivers/soc/mediatek/power_wrap/power_wrap.c | 94 ++++++++++++++++++++ - include/linux/soc/mediatek/mtk-pwrap.h | 48 ++++++++++ - 2 files changed, 142 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index fc38f14efb..14c85c929d 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -121,6 +121,100 @@ int mtk_pwrap_dev_request(void *dev_cfg) - } - EXPORT_SYMBOL_GPL(mtk_pwrap_dev_request); - -+/** -+ * mtk_send_power_control_req() - Send a client power control request to SSPM -+ * @pwrctlreq: caller-allocated and -filled request descriptor -+ * -+ * Entry point for other drivers that need to push a power control command to -+ * SSPM over the SCMI interface. The caller allocates and fills @pwrctlreq -+ * (including @dev and an @InBuffer pointing to a struct power_cntl_scmi_data). -+ * -+ * The flow is: -+ * 1. Validate @pwrctlreq and its buffers. -+ * 2. Resolve @dev's ACPI full pathname and use it to look up the matching -+ * struct pwrap_dev_config (which carries the per-device scmi_config with -+ * feat_id/dev_id and the SCMI_DEV_REQUEST data words). -+ * 3. Interpret @InBuffer as struct power_cntl_scmi_data. -+ * 4. OR the caller's requestId/customdata into the configured request data -+ * words and issue sspm_ci_set(). -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ -+int mtk_send_power_control_req(struct _power_cntrl_request *pwrctlreq) -+{ -+ struct power_cntl_scmi_data *scmidata; -+ struct pwrap_scmi_config *scmicfg; -+ struct pwrap_dev_config *cfg; -+ struct acpi_device *adev; -+ struct acpi_buffer path = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ int ret; -+ -+ if (!pwrctlreq || !pwrctlreq->dev) -+ return -EINVAL; -+ -+ if (!pwrctlreq->InBuffer || -+ pwrctlreq->InBufferSize < sizeof(struct power_cntl_scmi_data)) { -+ dev_err(pwrctlreq->dev, "%s: invalid input buffer\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* Extract the ACPI companion and its full pathname from dev. */ -+ adev = ACPI_COMPANION(pwrctlreq->dev); -+ if (!adev) { -+ dev_err(pwrctlreq->dev, "%s: no ACPI companion\n", __func__); -+ return -ENODEV; -+ } -+ -+ status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &path); -+ if (ACPI_FAILURE(status)) { -+ dev_err(pwrctlreq->dev, "%s: failed to get ACPI path\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* Use the ACPI path to fetch the per-device config / scmi_config. */ -+ cfg = pwrap_query_dev_config((char *)path.pointer); -+ if (!cfg) { -+ dev_err(pwrctlreq->dev, "%s: no dev config for \"%s\"\n", -+ __func__, (char *)path.pointer); -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ if (cfg->control_type != CTRL_BY_SCMI) { -+ dev_warn(pwrctlreq->dev, "%s: control type 0x%x is not scmi for dev %s\n", -+ __func__, cfg->control_type, cfg->device_path); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ scmicfg = &cfg->scmi_config; -+ -+ /* Interpret the caller's input buffer as SCMI request payload data. */ -+ scmidata = (struct power_cntl_scmi_data *)pwrctlreq->InBuffer; -+ -+ dev_dbg(pwrctlreq->dev, -+ "%s: scmi payload: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", __func__, -+ scmicfg->feat_id, scmicfg->dev_id, -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_00] | scmidata->requestId, -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_01] | scmidata->customdata[SCMI_DATA_00], -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_02] | scmidata->customdata[SCMI_DATA_01], -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_03] | scmidata->customdata[SCMI_DATA_02]); -+ -+ ret = sspm_ci_set(scmicfg->feat_id, scmicfg->dev_id, -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_00] | scmidata->requestId, -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_01] | scmidata->customdata[SCMI_DATA_00], -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_02] | scmidata->customdata[SCMI_DATA_01], -+ scmicfg->data[SCMI_DEV_REQUEST][SCMI_DATA_03] | scmidata->customdata[SCMI_DATA_02]); -+ -+ pwrctlreq->BytesReturned = 0; -+ -+out: -+ ACPI_FREE(path.pointer); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(mtk_send_power_control_req); -+ - int mtk_pwrap_dev_remove(void *dev_cfg) - { - struct pwrap_dev_config *cfg = (struct pwrap_dev_config *)dev_cfg; -diff --git a/include/linux/soc/mediatek/mtk-pwrap.h b/include/linux/soc/mediatek/mtk-pwrap.h -index e884a461a7..16d98e387c 100644 ---- a/include/linux/soc/mediatek/mtk-pwrap.h -+++ b/include/linux/soc/mediatek/mtk-pwrap.h -@@ -8,6 +8,48 @@ - #include - #include - -+struct device; -+ -+/* -+ * Number of caller-supplied custom data words carried in a power control -+ * request. These are OR'd into scmi_config.data[SCMI_DEV_REQUEST][SCMI_DATA_01..03] -+ * before being handed to sspm_ci_set(), so the count matches the three -+ * trailing data words of the SCMI_DEV_REQUEST action slot. -+ */ -+#define POWER_WRAP_SCMI_DATA_MAX_INDEX 3 -+ -+/* -+ * Power control request descriptor. -+ * -+ * A client driver that wants to send a power control command to SSPM -+ * allocates and fills one of these, then passes it to -+ * mtk_send_power_control_req(). @dev identifies the target device (used to -+ * resolve its ACPI path and, from there, its per-device SCMI config). -+ * @InBuffer must point to a struct power_cntl_scmi_data. -+ * -+ * The Out* / BytesReturned fields mirror the Windows IOCTL-style buffer -+ * contract this driver is ported from; they are reserved for future use. -+ */ -+struct _power_cntrl_request { -+ struct device *dev; -+ void *InBuffer; -+ size_t InBufferSize; -+ void *OutBuffer; -+ size_t OutBufferSize; -+ size_t BytesReturned; -+}; -+ -+/* -+ * Payload the client places in _power_cntrl_request.InBuffer. -+ * -+ * @requestId - OR'd into the SCMI_DATA_00 word (action id) of the request. -+ * @customdata[] - OR'd into the SCMI_DATA_01..03 words of the request. -+ */ -+struct power_cntl_scmi_data { -+ u8 requestId; -+ u32 customdata[POWER_WRAP_SCMI_DATA_MAX_INDEX]; -+}; -+ - enum mtk_pwrap_dev_state { - DEV_STA_UNKNOWN = 0, - DEV_STA_D0, -@@ -26,6 +68,7 @@ enum mtk_pwrap_com_state { - }; - - #ifdef CONFIG_MTK_POWER_WRAP -+int mtk_send_power_control_req(struct _power_cntrl_request *pwrctlreq); - int mtk_pwrap_dev_request(void *dev_ctrl); - int mtk_pwrap_dev_remove(void *dev_ctrl); - int mtk_pwrap_dev_suspend(void *dev_ctrl, u8 sys_trans); -@@ -34,6 +77,11 @@ int mtk_pwrap_com_idle(void *dev_ctrl, u8 com_idx); - int mtk_pwrap_com_active(void *dev_ctrl, u8 com_idx); - void *mtk_pwrap_dev_probe(const char *acpi_path); - #else -+static inline int mtk_send_power_control_req(struct _power_cntrl_request *pwrctlreq) -+{ -+ return -ENODEV; -+} -+ - static inline int mtk_pwrap_dev_request(void *dev_ctrl) - { - return -ENODEV; -From 21d6c9a57c16e9c74340fd903fcc8aec50c77f46 Mon Sep 17 00:00:00 2001 -From: "mayuresh.wani" -Date: Thu, 3 Sep 2026 22:49:31 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: power_wrap: expose client - requests in sysfs - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Extend the sysfs debug interface to cover the client power control -request path, so validation can issue and observe client requests -without a kernel consumer. - -Signed-off-by: mayuresh.wani -Signed-off-by: Kaushal Rajeev Butala -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - .../mediatek/power_wrap/power_wrap_sysfs.c | 172 ++++++++++++++++++ - 1 file changed, 172 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c b/drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c -index b8d196f4ac..9ea5ba69e6 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap_sysfs.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -394,6 +395,176 @@ static ssize_t pwrap_dev_config_query_store(struct device *dev, - } - DEVICE_ATTR_RW(pwrap_dev_config_query); - -+/* -+ * pwrap_power_ctrl_req_store - Exercise the mtk_send_power_control_req() client API -+ * -+ * Test/debug trigger for the public power control request entry point that -+ * external consumer drivers (e.g. xhci-mtk-v2) call. It drives the real API -+ * path end to end: resolve an ACPI path to its acpi_device, find its bound -+ * physical device, and hand that to mtk_send_power_control_req() (whose -+ * ACPI_COMPANION() then resolves it back to the ACPI node), which looks up -+ * the per-device CTRL_BY_SCMI config and issues sspm_ci_set(). This lets the -+ * client API be validated without needing the consumer driver to suspend. -+ * -+ * Input: " [requestId] [customdata0] [customdata1] [customdata2]" -+ * requestId/customdata are optional hex values (default 0). requestId -+ * is OR'd into the SCMI_DATA_00 (action) word; customdata into the -+ * three following words, exactly as a real client request would be. -+ * -+ * Usage: -+ * echo '\_SB.USB0 0x02' > /sys/bus/platform/devices//pwrap_power_ctrl_req -+ * echo '\_SB.USB0 0x1 0 0 0' > /sys/bus/platform/devices//pwrap_power_ctrl_req -+ */ -+/* -+ * acpi_get_first_physical_node() drops adev->physical_node_lock before it -+ * returns, so the struct device it points to can be unbound from the ACPI -+ * node and released before the caller gets to take a reference. Walk the -+ * physical node list here instead and take the reference while the lock is -+ * held, so the pointer handed back is always one the caller owns. -+ */ -+static struct device *pwrap_get_first_physical_node(struct acpi_device *adev) -+{ -+ struct acpi_device_physical_node *node; -+ struct device *dev = NULL; -+ -+ mutex_lock(&adev->physical_node_lock); -+ node = list_first_entry_or_null(&adev->physical_node_list, -+ struct acpi_device_physical_node, node); -+ if (node) -+ dev = get_device(node->dev); -+ mutex_unlock(&adev->physical_node_lock); -+ -+ return dev; -+} -+ -+static ssize_t pwrap_power_ctrl_req_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char kbuf[SYSFS_BUF_SIZE]; -+ char path[SYSFS_BUF_SIZE]; -+ u8 reqid = 0; -+ u32 cdata[POWER_WRAP_SCMI_DATA_MAX_INDEX] = { 0 }; -+ struct power_cntl_scmi_data scmidata; -+ struct _power_cntrl_request req; -+ struct acpi_device *adev; -+ struct device *phys_dev; -+ acpi_handle handle; -+ acpi_status status; -+ char *p, *tok; -+ int i, ret; -+ -+ if (count >= SYSFS_BUF_SIZE) -+ return -EINVAL; -+ -+ memcpy(kbuf, buf, count); -+ kbuf[count] = '\0'; -+ -+ /* -+ * Strict tokenized parse of " [reqId] [c0] [c1] [c2]". -+ * The path is mandatory; reqId and the customdata words are optional -+ * hex values. Any unparseable field or extra trailing token is -+ * rejected so malformed input is never silently accepted. reqId is -+ * parsed with kstrtou8() so a value > 0xff is an error rather than -+ * being silently truncated to a u8. -+ */ -+ p = kbuf; -+ -+ /* Mandatory first token: the ACPI path. */ -+ do { -+ tok = strsep(&p, " \t\n"); -+ } while (tok && *tok == '\0'); -+ if (!tok || *tok == '\0') -+ return -EINVAL; -+ if (strscpy(path, tok, sizeof(path)) < 0) -+ return -EINVAL; -+ -+ /* Optional numeric tokens: reqId, then up to 3 customdata words. */ -+ for (i = 0; i <= POWER_WRAP_SCMI_DATA_MAX_INDEX; i++) { -+ do { -+ tok = strsep(&p, " \t\n"); -+ } while (tok && *tok == '\0'); -+ if (!tok) -+ break; -+ -+ if (i == 0) { -+ if (kstrtou8(tok, 16, &reqid)) -+ return -EINVAL; -+ } else if (kstrtou32(tok, 16, &cdata[i - 1])) { -+ return -EINVAL; -+ } -+ } -+ -+ /* Reject any leftover tokens beyond the expected fields. */ -+ while (p) { -+ tok = strsep(&p, " \t\n"); -+ if (tok && *tok != '\0') -+ return -EINVAL; -+ } -+ -+ /* Resolve the ACPI path to a device we can hand to the client API. */ -+ status = acpi_get_handle(NULL, path, &handle); -+ if (ACPI_FAILURE(status)) { -+ pr_warn("power_wrap sysfs: cannot resolve ACPI path %s\n", path); -+ return -ENODEV; -+ } -+ -+ adev = acpi_get_acpi_dev(handle); -+ if (!adev) { -+ pr_warn("power_wrap sysfs: no acpi_device for %s\n", path); -+ return -ENODEV; -+ } -+ -+ /* -+ * mtk_send_power_control_req() resolves the ACPI companion via -+ * ACPI_COMPANION(dev), which reads dev->fwnode. An acpi_device's own -+ * embedded struct device does NOT have its fwnode set back to the ACPI -+ * node, so &adev->dev would yield a NULL companion. The bound physical -+ * device (e.g. the xhci-plat platform_device for \_SB.USB0) is the one -+ * whose dev->fwnode is the ACPI companion — and it's exactly the dev a -+ * real consumer driver passes. Use it. -+ * -+ * The reference on the physical device is taken under the ACPI -+ * device's physical_node_lock (see pwrap_get_first_physical_node()) -+ * before the acpi_device reference acquired by acpi_get_acpi_dev() is -+ * dropped. -+ */ -+ phys_dev = pwrap_get_first_physical_node(adev); -+ acpi_dev_put(adev); -+ -+ if (!phys_dev) { -+ pr_warn("power_wrap sysfs: no bound physical device for %s (driver not bound?)\n", -+ path); -+ return -ENODEV; -+ } -+ -+ scmidata.requestId = reqid; -+ scmidata.customdata[0] = cdata[0]; -+ scmidata.customdata[1] = cdata[1]; -+ scmidata.customdata[2] = cdata[2]; -+ -+ req.dev = phys_dev; -+ req.InBuffer = &scmidata; -+ req.InBufferSize = sizeof(scmidata); -+ req.OutBuffer = NULL; -+ req.OutBufferSize = 0; -+ req.BytesReturned = 0; -+ -+ pr_info("power_wrap sysfs: power_ctrl_req path=%s reqId=0x%x custom=[0x%x,0x%x,0x%x]\n", -+ path, reqid, cdata[0], cdata[1], cdata[2]); -+ -+ ret = mtk_send_power_control_req(&req); -+ put_device(phys_dev); -+ -+ if (ret) { -+ pr_warn("power_wrap sysfs: power_ctrl_req failed: %d\n", ret); -+ return ret; -+ } -+ -+ return count; -+} -+DEVICE_ATTR_WO(pwrap_power_ctrl_req); -+ - static struct attribute *pwrap_attrs[] = { - &dev_attr_pwrap_dev_probe.attr, - &dev_attr_pwrap_dev_remove.attr, -@@ -403,6 +574,7 @@ static struct attribute *pwrap_attrs[] = { - &dev_attr_pwrap_com_idle.attr, - &dev_attr_pwrap_com_active.attr, - &dev_attr_pwrap_dev_config_query.attr, -+ &dev_attr_pwrap_power_ctrl_req.attr, - NULL, - }; - -From 4220c95d19b50abfdaf5da281843c999279ef40b Mon Sep 17 00:00:00 2001 -From: "mayuresh.wani" -Date: Thu, 3 Sep 2026 22:49:32 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: power_wrap: enable DVFSRC via - SPM SYSRAM flag - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Set the SPM SYSRAM flag that enables DVFSRC so dynamic voltage and -frequency scaling resource control is active when the driver has -initialized. - -Signed-off-by: mayuresh.wani -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - .../soc/mediatek/power_wrap/inc/power_wrap.h | 2 + - drivers/soc/mediatek/power_wrap/power_wrap.c | 80 +++++++++++++++++++ - 2 files changed, 82 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/inc/power_wrap.h b/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -index ee0181dab1..a2b64a4c79 100644 ---- a/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -+++ b/drivers/soc/mediatek/power_wrap/inc/power_wrap.h -@@ -97,6 +97,8 @@ struct pwrap_driver_data { - //struct pwrap_dev_ctrl dev_ctrl; - struct platform_device *pdev; - struct acpi_buffer acpi_path; -+ /* Platform id from the PLID method, 0 when unavailable */ -+ unsigned long long plid; - }; - - /* Create the sysfs debug/test nodes (non-fatal; group is devm-managed) */ -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index 14c85c929d..c7a7f6b6fd 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -42,6 +42,29 @@ enum acpi_crs_irq_res { - - static struct pwrap_dev_ctrl dev_ctrl; - -+/* -+ * DVFSRC enable flag in SPM SYSRAM. -+ * -+ * The Windows PEP driver (ppmnotify.c, PepPpmLpiSupported()) writes a DVFSRC -+ * enable flag into SPM SYSRAM so the firmware enables DVFSRC for the -+ * suspend/resume low-power flow. On Windows the address/length/value are -+ * seeded into the registry by nvpep.inx (AddReg) and read back at runtime; -+ * they are fixed platform constants, so we hardcode them here. -+ * -+ * Windows source values (nvpep.inx): -+ * HKR,Parameters\DVFSRC,Offset,%REG_DWORD%,0x12FC00 -+ * HKR,Parameters\DVFSRC,Length,%REG_DWORD%,0x4 -+ * HKR,Parameters\DVFSRC,Value, %REG_DWORD%,0x1 -+ * -+ * 0x12FC00 is an absolute physical address (not an offset into any base): -+ * Windows maps it directly via MmMapIoSpaceEx(), so the Linux equivalent is -+ * ioremap(0x12FC00, 4) + writel(0x1). -+ */ -+#define PWRAP_PLID_MT8901 0x2 /* SOC_MT8901 */ -+#define PWRAP_DVFSRC_FLAG_ADDR 0x12FC00 -+#define PWRAP_DVFSRC_FLAG_LEN 0x4 -+#define PWRAP_DVFSRC_FLAG_VAL 0x1 -+ - /* Getter for static pwrap_dev_ctrl */ - struct pwrap_dev_ctrl *pwrap_get_dev_ctrl(void) - { -@@ -453,6 +476,44 @@ static int pwrap_probe_init_resources(struct pwrap_driver_data *priv, - return 0; - } - -+/** -+ * pwrap_write_dvfsrc_flag() - Enable DVFSRC via the SPM SYSRAM flag -+ * @dev: device (used for logging) -+ * -+ * Writes the DVFSRC enable flag into SPM SYSRAM so the firmware enables -+ * DVFSRC for the suspend/resume low-power flow. The flag address, length, -+ * and value are fixed platform constants (see PWRAP_DVFSRC_FLAG_* above). -+ * -+ * The flag is written once at probe. This mirrors the initial write done by -+ * the Windows PEP driver in PepPpmLpiSupported() (ppmnotify.c). SYSRAM -+ * contents are assumed to persist across the platform sleep states used on -+ * this target, so no resume-time re-write is performed. -+ * -+ * Failure to map the SYSRAM region is non-fatal: the driver continues so the -+ * SCMI device-control path stays functional. -+ */ -+static void pwrap_write_dvfsrc_flag(struct device *dev) -+{ -+ void __iomem *vaddr; -+ -+ vaddr = ioremap(PWRAP_DVFSRC_FLAG_ADDR, PWRAP_DVFSRC_FLAG_LEN); -+ if (!vaddr) { -+ dev_warn(dev, -+ "DVFSRC: failed to map SYSRAM flag at 0x%x (DVFSRC not enabled)\n", -+ PWRAP_DVFSRC_FLAG_ADDR); -+ return; -+ } -+ -+ writel(PWRAP_DVFSRC_FLAG_VAL, vaddr); -+ -+ dev_info(dev, -+ "DVFSRC: enabled via SYSRAM flag phys=0x%x len=0x%x val=0x%x\n", -+ PWRAP_DVFSRC_FLAG_ADDR, PWRAP_DVFSRC_FLAG_LEN, -+ PWRAP_DVFSRC_FLAG_VAL); -+ -+ iounmap(vaddr); -+} -+ - static int mtk_pwrap_probe(struct platform_device *pdev) - { - const struct acpi_device_id *id; -@@ -491,6 +552,25 @@ static int mtk_pwrap_probe(struct platform_device *pdev) - if (ret) - return ret; - -+ /* -+ * The register writes below are MT8901 platform constants: gate them -+ * on the PLID platform id so another SoC exposing this HID is left -+ * untouched. -+ */ -+ if (ACPI_FAILURE(acpi_evaluate_integer(adev->handle, "PLID", NULL, -+ &priv->plid))) -+ priv->plid = 0; -+ -+ /* -+ * Enable DVFSRC by writing the SPM SYSRAM flag. Ported from the -+ * Windows PEP driver (PepPpmLpiSupported() in ppmnotify.c). Non-fatal. -+ */ -+ if (priv->plid == PWRAP_PLID_MT8901) -+ pwrap_write_dvfsrc_flag(dev); -+ else -+ dev_info(dev, "platform id 0x%llx is not MT8901, DVFSRC flag not written\n", -+ priv->plid); -+ - /* - * The sysfs nodes are debug/test hooks. Their creation must not fail - * probe or disable the driver, so log a warning and continue if the -From 51fbbd671b255760bff31592f21f68e1cfc056e3 Mon Sep 17 00:00:00 2001 -From: "sanket.diwate" -Date: Thu, 3 Sep 2026 22:49:32 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: power_wrap: request AC_BESTPERF - mode during boot - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Request the AC_BESTPERF performance mode from the SSPM during boot -so the platform boots in the best performance mode on AC power, -matching the intended out of box behavior. - -Signed-off-by: sanket.diwate -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - drivers/soc/mediatek/power_wrap/power_wrap.c | 59 ++++++++++++++++++++ - 1 file changed, 59 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index c7a7f6b6fd..fb32e887cb 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -64,6 +64,21 @@ static struct pwrap_dev_ctrl dev_ctrl; - #define PWRAP_DVFSRC_FLAG_ADDR 0x12FC00 - #define PWRAP_DVFSRC_FLAG_LEN 0x4 - #define PWRAP_DVFSRC_FLAG_VAL 0x1 -+/* -+ * BestPerf performance setting register. -+ * -+ * A single 32-bit MMIO register that selects the SoC performance profile. -+ * Writing PWRAP_BEST_PERF_VAL puts the platform into its highest-performance -+ * operating point. The address/length/value are fixed platform constants, so -+ * they are hardcoded here. -+ * -+ * ioremap(ADDR, LEN) maps the register and writel(VAL) performs one 32-bit -+ * write; LEN is the size of the mapped window (4 bytes = one 32-bit register), -+ * NOT the value being written. -+ */ -+#define PWRAP_PERF_SETTING_ADDR 0x1C871E00 -+#define PWRAP_PERF_SETTING_LEN 0x4 -+#define PWRAP_BEST_PERF_VAL 0x4 - - /* Getter for static pwrap_dev_ctrl */ - struct pwrap_dev_ctrl *pwrap_get_dev_ctrl(void) -@@ -514,6 +529,41 @@ static void pwrap_write_dvfsrc_flag(struct device *dev) - iounmap(vaddr); - } - -+/** -+ * pwrap_write_bestperf_flag() - Select the highest SoC performance profile -+ * @dev: device (used for logging) -+ * -+ * Writes PWRAP_BEST_PERF_VAL to the BestPerf setting register so the platform -+ * comes up in its highest-performance operating point. The register address, -+ * length, and value are fixed platform constants (see PWRAP_PERF_SETTING_* -+ * above). -+ * -+ * -+ * Failure to map the register is non-fatal: the driver continues so the SCMI -+ * device-control path stays functional. -+ */ -+static void pwrap_write_bestperf_flag(struct device *dev) -+{ -+ void __iomem *vaddr; -+ -+ vaddr = ioremap(PWRAP_PERF_SETTING_ADDR, PWRAP_PERF_SETTING_LEN); -+ if (!vaddr) { -+ dev_warn(dev, -+ "Perf: failed to map physical address 0x%x\n", -+ PWRAP_PERF_SETTING_ADDR); -+ return; -+ } -+ -+ writel(PWRAP_BEST_PERF_VAL, vaddr); -+ -+ dev_info(dev, -+ "BestPerf Mode enabled via address phys=0x%x len=0x%x val=0x%x\n", -+ PWRAP_PERF_SETTING_ADDR, PWRAP_PERF_SETTING_LEN, -+ PWRAP_BEST_PERF_VAL); -+ -+ iounmap(vaddr); -+} -+ - static int mtk_pwrap_probe(struct platform_device *pdev) - { - const struct acpi_device_id *id; -@@ -571,6 +621,15 @@ static int mtk_pwrap_probe(struct platform_device *pdev) - dev_info(dev, "platform id 0x%llx is not MT8901, DVFSRC flag not written\n", - priv->plid); - -+ /* -+ * Set performance mode to BestPerf setting by default on driver probe -+ */ -+ if (priv->plid == PWRAP_PLID_MT8901) -+ pwrap_write_bestperf_flag(dev); -+ else -+ dev_info(dev, "platform id 0x%llx is not MT8901, BestPerf not requested\n", -+ priv->plid); -+ - /* - * The sysfs nodes are debug/test hooks. Their creation must not fail - * probe or disable the driver, so log a warning and continue if the -From 8eaa0bedf0ed8ab53b1c6f7afd11c0d1cbf2fa5c Mon Sep 17 00:00:00 2001 -From: "mayuresh.wani" -Date: Thu, 3 Sep 2026 22:49:32 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soc: mediatek: power_wrap: release usb4 - resources via SSPM - -BugLink: https://bugs.launchpad.net/bugs/2167298 - -Release the usb4 resources through the SSPM so the platform can -enter its deepest sleep states when usb4 is idle. - -Signed-off-by: mayuresh.wani -Signed-off-by: David Cemin -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Signed-off-by: Brad Figg ---- - drivers/soc/mediatek/power_wrap/power_wrap.c | 271 +++++++++++++++++++ - 1 file changed, 271 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index fb32e887cb..5db9077b56 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -7,6 +7,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -64,6 +66,75 @@ static struct pwrap_dev_ctrl dev_ctrl; - #define PWRAP_DVFSRC_FLAG_ADDR 0x12FC00 - #define PWRAP_DVFSRC_FLAG_LEN 0x4 - #define PWRAP_DVFSRC_FLAG_VAL 0x1 -+ -+/* -+ * USB4 resource-release hook. -+ * -+ * The bootloader leaves the USB4 hardware resources powered on when USB4 is -+ * not used. A single SCMI trigger to the SSPM (feature id 15, no params) tells -+ * the firmware to release them. This was previously a standalone one-call -+ * driver (usb4_hook.c / CONFIG_MTK_USB4_HOOK); it is folded into power_wrap -+ * here to avoid the overhead of a separate driver for a single API call. -+ * -+ * The release must run after the xHCI driver that owns the USB4 domain has -+ * probed: issued earlier, xHCI re-powers the domain and blocks the deepest -+ * suspend state. The xHCI driver can be a module that loads long after -+ * power_wrap (which is built in), so ordering by initcall level is not -+ * enough. Instead probe collects the xHCI controllers present in the ACPI -+ * namespace (PNP0D10/PNP0D15 platform devices) that have no driver yet and -+ * listens on the platform bus for their BUS_NOTIFY_BOUND_DRIVER events; the -+ * release is issued once the last of them has bound (immediately if none is -+ * pending). Controllers that never bind keep the release pending, which is -+ * the same outcome as before this driver existed, and a late_initcall logs -+ * that state once so it is visible in dmesg. -+ * -+ * The release is restricted to MT8901. The feature-id 15 trigger encodes -+ * an MT8901 USB4 resource-layout assumption, so gating on the platform id lets -+ * other platforms (e.g. MT8992) boot and be tested without reverting this -+ * change. The platform id is read from the PLID method on the power_wrap ACPI -+ * device (NVDA6210), mirroring the Windows PEP driver's AcpiGetPlatformId(); -+ * the value matches the PEP PLAT_IDENTIFIER enum (SOC_MT8901 == 0x2). -+ */ -+#define PWRAP_USB4_HOOK_FEATURE_ID 15 /* SSPM SCMI_USB4_HOOK */ -+ -+/* xHCI-compliant USB controllers as enumerated through ACPI. */ -+static const struct acpi_device_id pwrap_usb4_xhci_ids[] = { -+ { "PNP0D10", }, -+ { "PNP0D15", }, -+ { } -+}; -+ -+/* -+ * USB4-release state: the power_wrap device and the xHCI controllers still to -+ * bind, tracked by identity (with a device reference each). -+ * -+ * Lock order: the driver core sends BUS_NOTIFY_BOUND_DRIVER with the bound -+ * device's lock held and the notifier then takes pwrap_usb4_lock, so -+ * pwrap_usb4_lock is never held while a device lock is taken. The collection -+ * pass therefore runs without pwrap_usb4_lock: it takes each controller's -+ * device lock to read device_is_bound(), as the driver core requires, and -+ * only afterwards takes pwrap_usb4_lock to commit the list. A controller -+ * that binds between the notifier registration and that commit is recorded -+ * by the notifier in pwrap_usb4_early_bound[] and dropped from the list at -+ * commit time, so it is neither missed nor counted twice. -+ */ -+#define PWRAP_USB4_MAX_XHCI 8 -+static DEFINE_MUTEX(pwrap_usb4_lock); -+static struct device *pwrap_usb4_dev; -+static struct device *pwrap_usb4_pending[PWRAP_USB4_MAX_XHCI]; -+static unsigned int pwrap_usb4_npending; -+static struct device *pwrap_usb4_early_bound[PWRAP_USB4_MAX_XHCI]; -+static unsigned int pwrap_usb4_nearly; -+static bool pwrap_usb4_tracking; -+static bool pwrap_usb4_done; -+static struct notifier_block pwrap_usb4_nb; -+ -+/* Controllers found unbound by the collection pass, before commit. */ -+struct pwrap_usb4_scan { -+ struct device *dev[PWRAP_USB4_MAX_XHCI]; -+ unsigned int n; -+}; -+ - /* - * BestPerf performance setting register. - * -@@ -564,6 +635,203 @@ static void pwrap_write_bestperf_flag(struct device *dev) - iounmap(vaddr); - } - -+/* -+ * pwrap_release_usb4_resources() - release USB4 hardware resources via SSPM -+ * -+ * Sends a single SCMI trigger (feature id 15, no params) telling the firmware -+ * to release the USB4 resources the bootloader leaves powered on. Called with -+ * pwrap_usb4_lock held, once, when the last xHCI controller has bound (see -+ * the USB4 hook note above). Best-effort: a release failure is logged but not -+ * escalated, and the hook is not re-armed. -+ */ -+static void pwrap_release_usb4_resources(struct device *dev) -+{ -+ int ret; -+ -+ lockdep_assert_held(&pwrap_usb4_lock); -+ -+ if (pwrap_usb4_done) -+ return; -+ pwrap_usb4_done = true; -+ -+ ret = sspm_ci_set(PWRAP_USB4_HOOK_FEATURE_ID, 0, 0, 0, 0, 0); -+ if (ret) -+ dev_err(dev, "USB4: sspm_ci_set failed to release resources (%d)\n", -+ ret); -+ else -+ dev_info(dev, "USB4: SSPM released usb4 resources\n"); -+} -+ -+static bool pwrap_usb4_is_xhci(struct device *dev) -+{ -+ return dev->bus == &platform_bus_type && -+ acpi_match_device(pwrap_usb4_xhci_ids, dev); -+} -+ -+/* -+ * Collects the xHCI controllers that have no driver bound yet. Runs without -+ * pwrap_usb4_lock and takes each device's lock for device_is_bound(), as the -+ * driver core requires (see the lock order note above). -+ */ -+static int pwrap_usb4_collect_unbound(struct device *dev, void *data) -+{ -+ struct pwrap_usb4_scan *scan = data; -+ bool bound; -+ -+ if (!pwrap_usb4_is_xhci(dev)) -+ return 0; -+ -+ device_lock(dev); -+ bound = device_is_bound(dev); -+ device_unlock(dev); -+ if (bound) -+ return 0; -+ -+ if (scan->n >= PWRAP_USB4_MAX_XHCI) { -+ dev_warn(pwrap_usb4_dev, -+ "USB4: more than %u xHCI controllers, not waiting for %s\n", -+ PWRAP_USB4_MAX_XHCI, dev_name(dev)); -+ return 0; -+ } -+ -+ scan->dev[scan->n++] = get_device(dev); -+ -+ return 0; -+} -+ -+/* Drops @dev from an array of device references; true if it was there. */ -+static bool pwrap_usb4_remove(struct device **arr, unsigned int *n, -+ struct device *dev) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < *n; i++) { -+ if (arr[i] != dev) -+ continue; -+ put_device(dev); -+ arr[i] = arr[--(*n)]; -+ arr[*n] = NULL; -+ return true; -+ } -+ -+ return false; -+} -+ -+static int pwrap_usb4_bus_notify(struct notifier_block *nb, -+ unsigned long action, void *data) -+{ -+ struct device *dev = data; -+ -+ if (action != BUS_NOTIFY_BOUND_DRIVER || !pwrap_usb4_is_xhci(dev)) -+ return NOTIFY_DONE; -+ -+ mutex_lock(&pwrap_usb4_lock); -+ if (pwrap_usb4_done) { -+ /* Nothing left to do. */ -+ } else if (!pwrap_usb4_tracking) { -+ /* -+ * Bound while the collection pass is still running: remember -+ * it so the commit can drop it from whatever the pass found. -+ */ -+ if (pwrap_usb4_nearly < PWRAP_USB4_MAX_XHCI) -+ pwrap_usb4_early_bound[pwrap_usb4_nearly++] = get_device(dev); -+ else -+ dev_warn(pwrap_usb4_dev, -+ "USB4: early bind of %s not recorded, release may wait on it\n", -+ dev_name(dev)); -+ } else if (pwrap_usb4_remove(pwrap_usb4_pending, &pwrap_usb4_npending, -+ dev)) { -+ dev_dbg(pwrap_usb4_dev, "USB4: xHCI %s bound, %u pending\n", -+ dev_name(dev), pwrap_usb4_npending); -+ if (!pwrap_usb4_npending) -+ pwrap_release_usb4_resources(pwrap_usb4_dev); -+ } -+ mutex_unlock(&pwrap_usb4_lock); -+ -+ return NOTIFY_OK; -+} -+ -+/* -+ * pwrap_usb4_arm_release() - arm the USB4 release for when xHCI has bound -+ * @dev: the power_wrap device -+ * -+ * Restricted to MT8901 via the PLID platform id: on any other platform, or if -+ * PLID is not available, nothing is armed so the platform is unaffected. -+ * Three steps, none of them holding pwrap_usb4_lock together with a device -+ * lock: register the notifier; collect the unbound controllers under their -+ * device locks; then, under pwrap_usb4_lock, drop the ones the notifier saw -+ * bind in the meantime and commit the rest. The notifier stays registered: -+ * the driver is built in and never removed, and a completed release makes -+ * it a no-op. -+ */ -+static void pwrap_usb4_arm_release(struct device *dev) -+{ -+ struct pwrap_usb4_scan scan = { .n = 0 }; -+ unsigned long long plid; -+ acpi_status status; -+ unsigned int i; -+ int ret; -+ -+ status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PLID", NULL, &plid); -+ if (ACPI_FAILURE(status)) { -+ dev_info(dev, "USB4: PLID unavailable (%s), skipping release\n", -+ acpi_format_exception(status)); -+ return; -+ } -+ -+ if (plid != PWRAP_PLID_MT8901) { -+ dev_info(dev, "USB4: platform id 0x%llx is not MT8901, skipping release\n", -+ plid); -+ return; -+ } -+ -+ mutex_lock(&pwrap_usb4_lock); -+ pwrap_usb4_dev = dev; -+ pwrap_usb4_nb.notifier_call = pwrap_usb4_bus_notify; -+ ret = bus_register_notifier(&platform_bus_type, &pwrap_usb4_nb); -+ mutex_unlock(&pwrap_usb4_lock); -+ if (ret) { -+ dev_err(dev, "USB4: cannot register bus notifier (%d), release not armed\n", -+ ret); -+ return; -+ } -+ -+ bus_for_each_dev(&platform_bus_type, NULL, &scan, -+ pwrap_usb4_collect_unbound); -+ -+ mutex_lock(&pwrap_usb4_lock); -+ for (i = 0; i < scan.n; i++) { -+ if (pwrap_usb4_remove(pwrap_usb4_early_bound, &pwrap_usb4_nearly, -+ scan.dev[i])) -+ put_device(scan.dev[i]); /* bound during the pass */ -+ else -+ pwrap_usb4_pending[pwrap_usb4_npending++] = scan.dev[i]; -+ } -+ while (pwrap_usb4_nearly) -+ put_device(pwrap_usb4_early_bound[--pwrap_usb4_nearly]); -+ pwrap_usb4_tracking = true; -+ -+ if (pwrap_usb4_npending) -+ dev_info(dev, "USB4: release armed, waiting for %u xHCI controller(s) to bind\n", -+ pwrap_usb4_npending); -+ else -+ pwrap_release_usb4_resources(dev); -+ mutex_unlock(&pwrap_usb4_lock); -+} -+ -+/* Make a release that is still waiting on xHCI visible once boot settles. */ -+static int __init pwrap_usb4_report_pending(void) -+{ -+ mutex_lock(&pwrap_usb4_lock); -+ if (pwrap_usb4_tracking && !pwrap_usb4_done) -+ dev_info(pwrap_usb4_dev, "USB4: release still waiting for %u xHCI controller(s)\n", -+ pwrap_usb4_npending); -+ mutex_unlock(&pwrap_usb4_lock); -+ -+ return 0; -+} -+late_initcall(pwrap_usb4_report_pending); -+ - static int mtk_pwrap_probe(struct platform_device *pdev) - { - const struct acpi_device_id *id; -@@ -640,6 +908,9 @@ static int mtk_pwrap_probe(struct platform_device *pdev) - dev_warn(&pdev->dev, - "failed to create sysfs nodes: %d (continuing)\n", ret); - -+ /* Release the USB4 resources once xHCI has bound (see the hook note). */ -+ pwrap_usb4_arm_release(dev); -+ - return 0; - } - -From 78ec5c1301aafe05f53d2ea7162f19838a1cfbba Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Tue, 25 Aug 2026 09:11:50 +0000 -Subject: [PATCH] NVIDIA: SAUCE: usb: typec: ucsi: acpi: disable USB4 via - vendor _DSM at probe - -BugLink: https://bugs.launchpad.net/bugs/2167862 - -On some GB10 OEM platforms the firmware brings up USB4. DGX OS does -not currently plan to support USB4, so it must be disabled from the OS -side on these platforms. Disabling USB4 at the firmware level also lets -any connected USB4 device fall back to USB3 so it remains usable. - -The OEM firmware exposes an NVIDIA vendor _DSM on the UCSI device -(UUID 58ee92f1-76ca-48da-92f0-d548e83e80ea, rev 0) with three -functions: 0 = query supported-functions bitmap, 1 = enable USB4, -2 = disable USB4. The method returns a Buffer(1) whose byte 0 is -0x01 on success and 0x00 on failure. - -Invoke the disable function (index 2) from a -ucsi_acpi_apply_vendor_quirks() helper, called both at ucsi_acpi -probe time (before ucsi_register()) and on resume (before -ucsi_resume()). The EC does not persist the USB4-disable state -across suspend, so the quirk has to be reapplied on every resume. - -The call is gated on acpi_check_dsm() so hardware without this -vendor DSM is unaffected, and is best-effort: probe and resume -never fail on a DSM error. - -If USB4 support is planned for DGX Spark in the future, this change -can be removed. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/usb/typec/ucsi/ucsi_acpi.c | 52 ++++++++++++++++++++++++++++++ - 1 file changed, 52 insertions(+) - -diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c -index 18286d3e9c..0fdb33c3b0 100644 ---- a/drivers/usb/typec/ucsi/ucsi_acpi.c -+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c -@@ -173,6 +173,54 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = { - { } - }; - -+/* -+ * NVIDIA vendor extension for GB10 platforms: the firmware exposes an EC -+ * control path to disable USB4 through a vendor _DSM on the UCSI device. -+ * The presence check via acpi_check_dsm() gates it so non-GB10 -+ * UCSI hardware is unaffected. -+ */ -+static void ucsi_acpi_nvidia_disable_usb4_gb10(struct ucsi_acpi *ua) -+{ -+ static const guid_t nvidia_usb4_dsm_guid = -+ GUID_INIT(0x58ee92f1, 0x76ca, 0x48da, -+ 0x92, 0xf0, 0xd5, 0x48, 0xe8, 0x3e, 0x80, 0xea); -+ const u32 rev = 0; -+ const u32 fn_disable = 2; -+ acpi_handle handle = ACPI_HANDLE(ua->dev); -+ union acpi_object *out; -+ -+ if (!acpi_check_dsm(handle, &nvidia_usb4_dsm_guid, rev, -+ 1u << fn_disable)) -+ return; -+ -+ out = acpi_evaluate_dsm(handle, &nvidia_usb4_dsm_guid, rev, -+ fn_disable, NULL); -+ if (!out) { -+ dev_warn(ua->dev, "NVIDIA USB4 disable _DSM: evaluation failed\n"); -+ return; -+ } -+ -+ if (out->type == ACPI_TYPE_BUFFER && out->buffer.length >= 1) -+ dev_info(ua->dev, "NVIDIA USB4 disable _DSM: returned 0x%02x (%s)\n", -+ out->buffer.pointer[0], -+ out->buffer.pointer[0] == 1 ? "success" : "failure"); -+ else -+ dev_warn(ua->dev, "NVIDIA USB4 disable _DSM: unexpected return type=%d len=%u\n", -+ out->type, -+ out->type == ACPI_TYPE_BUFFER ? out->buffer.length : 0); -+ -+ ACPI_FREE(out); -+} -+ -+/* -+ * Vendor-specific quirks that must run before UCSI async work is queued, -+ * on both cold probe and resume. -+ */ -+static void ucsi_acpi_apply_vendor_quirks(struct ucsi_acpi *ua) -+{ -+ ucsi_acpi_nvidia_disable_usb4_gb10(ua); -+} -+ - static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) - { - struct ucsi_acpi *ua = data; -@@ -238,6 +286,8 @@ static int ucsi_acpi_probe(struct platform_device *pdev) - return -ENODEV; - } - -+ ucsi_acpi_apply_vendor_quirks(ua); -+ - ret = ucsi_register(ua->ucsi); - if (ret) { - acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), -@@ -274,6 +324,8 @@ static int ucsi_acpi_resume(struct device *dev) - { - struct ucsi_acpi *ua = dev_get_drvdata(dev); - -+ ucsi_acpi_apply_vendor_quirks(ua); -+ - return ucsi_resume(ua->ucsi); - } - diff --git a/kernel/1010-n1x-ffa-ec.patch b/kernel/1010-n1x-ffa-ec.patch deleted file mode 100644 index 81406e4..0000000 --- a/kernel/1010-n1x-ffa-ec.patch +++ /dev/null @@ -1,4085 +0,0 @@ -From 584258f7a69415d2ee04aceee1c56edf4d605720 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 7 May 2025 06:19:42 +0000 -Subject: [PATCH] NVIDIA: SAUCE: Add support for custom ARM FFH offset handler -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -BugLink: https://bugs.launchpad.net/bugs/2114230 - -The FFH (Functional Fixed Hardware) operation region is maintained by -ARM in https://developer.arm.com/documentation/den0048/latest/ - -OperationRegion (RegionName, RegionSpace, Offset, Length) - -For ARM FFH, Offset is used to identify the functionality offered by -this FFH address space. It must be set to one of the following values: - -- 0x0 to indicate usage of 32-bit calling convention -- 0x1 to indicate usage of 64-bit calling convention. -- All other values are reserved. - -For GB10 and other similar SOC’s, to communicate with embedded controller, -a new specification is being defined. It is currently in draft stage and -maintained in - -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/README.md -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md - -Offset 4 section: - -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#operation-region-definition - -This specification internally uses offset 0x4 which is not defined in -published ARM specification. So, when ACPI request comes with offset 0x4, -then it will fail due to missing support. This commit adds support for -custom offset handler. A new EC interface driver will be added in -subsequent patches which will registers it callback function. -When FFH operation region will be executed with offsets other -than 0x0 and 0x1, then it will be forwarded to custom handler. - -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 89b7d0384a9c noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit df76ec3fc884563f2d73013be08371e870a246d9 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/acpi/arm64/ffh.c | 32 ++++++++++++++++++++++++++++++++ - include/linux/acpi.h | 16 ++++++++++++++++ - 2 files changed, 48 insertions(+) - -diff --git a/drivers/acpi/arm64/ffh.c b/drivers/acpi/arm64/ffh.c -index 04380bab19..8bce1070d3 100644 ---- a/drivers/acpi/arm64/ffh.c -+++ b/drivers/acpi/arm64/ffh.c -@@ -19,6 +19,9 @@ struct acpi_ffh_data { - struct arm_smccc_1_2_regs *res); - }; - -+static int (*ffh_custom_handler)(struct acpi_ffh_info *info, -+ acpi_integer *value, void *region_context); -+ - int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt) - { - enum arm_smccc_conduit conduit; -@@ -99,9 +102,38 @@ int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_contex - ffh_ctxt->invoke_ffh64_fn(r, r); - memcpy(value, r, ffh_ctxt->info.length); - } -+ } else if (ffh_custom_handler) { -+ int err = ffh_custom_handler(&ffh_ctxt->info, value, -+ region_context); -+ if (err) { -+ pr_err("ARM FFH custom offset handler returned error=%d\n", -+ err); -+ ret = AE_ERROR; -+ } - } else { - ret = AE_ERROR; - } - - return ret; - } -+ -+int acpi_arm64_ffh_update_custom_offset_handler( -+ int (*handler)(struct acpi_ffh_info *info, acpi_integer *value, -+ void *region_context)) -+{ -+ if (!handler) { -+ pr_debug("ARM FFH custom offset handler unregistered\n"); -+ ffh_custom_handler = NULL; -+ return 0; -+ } -+ -+ if (ffh_custom_handler) -+ pr_debug("ARM FFH custom offset handler updated\n"); -+ else -+ pr_debug("ARM FFH custom offset handler registered\n"); -+ -+ ffh_custom_handler = handler; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(acpi_arm64_ffh_update_custom_offset_handler); -diff --git a/include/linux/acpi.h b/include/linux/acpi.h -index 60ab50cb89..4ca43f5566 100644 ---- a/include/linux/acpi.h -+++ b/include/linux/acpi.h -@@ -1630,10 +1630,26 @@ extern int acpi_ffh_address_space_arch_setup(void *handler_ctxt, - void **region_ctxt); - extern int acpi_ffh_address_space_arch_handler(acpi_integer *value, - void *region_context); -+int acpi_ffh_address_space_arch_update_custom_offset_handler( -+ int (*handler)(struct acpi_ffh_info *info, acpi_integer *value, -+ void *region_context)); - #else - static inline void acpi_init_ffh(void) { } - #endif - -+#if defined(CONFIG_ACPI_FFH) && defined(CONFIG_ARM64) -+int acpi_arm64_ffh_update_custom_offset_handler( -+ int (*handler)(struct acpi_ffh_info *info, acpi_integer *value, -+ void *region_context)); -+#else -+static inline int acpi_arm64_ffh_update_custom_offset_handler( -+ int (*handler)(struct acpi_ffh_info *info, acpi_integer *value, -+ void *region_context)) -+{ -+ return -EOPNOTSUPP; -+} -+#endif -+ - #ifdef CONFIG_ACPI - extern void acpi_device_notify(struct device *dev); - extern void acpi_device_notify_remove(struct device *dev); -From bcb9f47e5b74f0640f8c993702995edfd252c916 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 7 May 2025 07:32:22 +0000 -Subject: [PATCH] NVIDIA: SAUCE: Add nvidia ffa driver for EC communication - -BugLink: https://bugs.launchpad.net/bugs/2114230 - -Please refer - -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md -for details regarding FFA device details for secure EC -services communication. - -The HID 'MSFT000C' is reserved for FFA devices. -This HID is documented in - -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#hid-definition - -This commit adds a platform driver which binds with FFA device. -In its probe routine, it executes the AVAL method to check -if FFA can be used for secure EC services communication. - -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 555e41e166a4 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit bdd6ed09666656b94b7d75c56f3c7d9254e6c53f noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/platform/arm64/Kconfig | 13 ++++ - drivers/platform/arm64/Makefile | 1 + - drivers/platform/arm64/nvidia-ffa-ec.c | 92 ++++++++++++++++++++++++++ - 3 files changed, 106 insertions(+) - create mode 100644 drivers/platform/arm64/nvidia-ffa-ec.c - -diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig -index e32e01b2a9..690699b02e 100644 ---- a/drivers/platform/arm64/Kconfig -+++ b/drivers/platform/arm64/Kconfig -@@ -103,4 +103,17 @@ config EC_QCOM_HAMOA - - This driver currently supports Hamoa/Purwa/Glymur reference devices. - -+config NVIDIA_FFA_EC -+ tristate "NVIDIA FFA EC services driver" -+ depends on ARM_FFA_TRANSPORT || COMPILE_TEST -+ depends on ACPI -+ depends on ACPI_FFH -+ help -+ Enable NVIDIA FFA EC services. -+ For GB10 and other similar SOC’s, to communicate with embedded controller, a new -+ specification is being defined. It is currently in draft stage and maintained in -+ https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md -+ -+ Say M or Y here to include this support. -+ - endif # ARM64_PLATFORM_DEVICES -diff --git a/drivers/platform/arm64/Makefile b/drivers/platform/arm64/Makefile -index 7681be4a46..265d356a9e 100644 ---- a/drivers/platform/arm64/Makefile -+++ b/drivers/platform/arm64/Makefile -@@ -10,3 +10,4 @@ obj-$(CONFIG_EC_HUAWEI_GAOKUN) += huawei-gaokun-ec.o - obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o - obj-$(CONFIG_EC_LENOVO_THINKPAD_T14S) += lenovo-thinkpad-t14s.o - obj-$(CONFIG_EC_QCOM_HAMOA) += qcom-hamoa-ec.o -+obj-$(CONFIG_NVIDIA_FFA_EC) += nvidia-ffa-ec.o -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -new file mode 100644 -index 0000000000..22dd49a135 ---- /dev/null -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -0,0 +1,92 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#define DRV_NAME "nvidia-ffa-ec" -+ -+/* platform device for FFA ACPI device (HID MSFT000C) */ -+static struct platform_device *ffa_pdev; -+ -+static const struct acpi_device_id nvidia_ffa_device_ids[] = { -+ /* -+ * Please refer -+ * https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#hid-definition -+ * where MSFT000C is documented. -+ * -+ * The _HID 'MSFT000C' is reserved for FFA device which uses -+ * FFA interface for secure EC communication. -+ */ -+ {"MSFT000C", 0}, -+ {"", 0}, -+}; -+ -+MODULE_DEVICE_TABLE(acpi, nvidia_ffa_device_ids); -+ -+static int nvidia_ffa_probe(struct platform_device *pdev) -+{ -+ struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); -+ acpi_status status; -+ unsigned long long data = 0; -+ -+ if (ffa_pdev) { -+ dev_err(&pdev->dev, "FFA device already registered\n"); -+ return -EINVAL; -+ } -+ -+ if (!adev) { -+ dev_err(&pdev->dev, "No ACPI companion found\n"); -+ return -ENODEV; -+ } -+ -+ status = acpi_evaluate_integer(adev->handle, "AVAL", NULL, &data); -+ if (ACPI_FAILURE(status)) { -+ dev_err(&pdev->dev, "Failed to execute AVAL method\n"); -+ return -ENODEV; -+ } -+ -+ if (data != 1) { -+ dev_err(&pdev->dev, "FFA not available\n"); -+ return -ENODEV; -+ } -+ -+ ffa_pdev = pdev; -+ -+ return 0; -+} -+ -+static void nvidia_ffa_remove(struct platform_device *pdev) -+{ -+ ffa_pdev = NULL; -+} -+ -+static struct platform_driver nvidia_ffa_driver = { -+ .probe = nvidia_ffa_probe, -+ .remove = nvidia_ffa_remove, -+ .driver = { -+ .name = "nvidia-ffa", -+ .acpi_match_table = nvidia_ffa_device_ids, -+ }, -+}; -+ -+static int __init nvidia_ffa_init(void) -+{ -+ return platform_driver_register(&nvidia_ffa_driver); -+} -+module_init(nvidia_ffa_init); -+ -+static void __exit nvidia_ffa_exit(void) -+{ -+ platform_driver_unregister(&nvidia_ffa_driver); -+} -+module_exit(nvidia_ffa_exit); -+ -+MODULE_SOFTDEP("pre: arm-ffa"); -+MODULE_AUTHOR("NVIDIA CORPORATION"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("NVIDIA FFA EC services driver"); -From 888fd00cfc4dc1dccb2e53e05333fc393a687fbb Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 7 May 2025 08:12:27 +0000 -Subject: [PATCH] NVIDIA: SAUCE: Add ffa driver for each secure EC service -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -BugLink: https://bugs.launchpad.net/bugs/2114230 - -Please refer -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md -for details regarding FFA device details for secure -EC services communication. - -Each secure EC service is identified by separate UUID. -When generic FFA module loads (ffa_module), then it gets the list of -partitions. Each EC service is a FFA partition and ffa_module creates -a device for each partition. These devices will be added in -arm_ffa bus type. The device will be named as arm-ffa-. -For binding with these devices, a driver needs to be registered in -arm_ffa bus type. This driver uses structure ‘struct ffa_driver’ where -it uses UUID as ID table. The binding of the driver to device -happens on basis of UUID. - -The secure EC services FFA driver is dependent upon main FFA -device to be created (which uses ACPI ID MSFT000C), so -ffa_driver_register()/ffa_driver_unregister() is invoked from -nvidia_ffa_probe()/nvidia_ffa_remove(). - -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 9613a5c07163 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit 5ede0e8d753f77d7a792351102f800dda882032f noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 109 +++++++++++++++++++++++++ - 1 file changed, 109 insertions(+) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 22dd49a135..537e7a51bd 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -7,12 +7,111 @@ - #include - #include - #include -+#include -+#include - - #define DRV_NAME "nvidia-ffa-ec" - - /* platform device for FFA ACPI device (HID MSFT000C) */ - static struct platform_device *ffa_pdev; - -+static const uuid_t nvidia_ec_managment_service_uuid = -+ UUID_INIT(0x330c1273, 0xfde5, 0x4757, 0x98, 0x19, 0x5b, 0x65, 0x39, 0x03, 0x75, 0x02); -+ -+static const uuid_t nvidia_ec_power_service_uuid = -+ UUID_INIT(0x7157addf, 0x2fbe, 0x4c63, 0xae, 0x95, 0xef, 0xac, 0x16, 0xe3, 0xb0, 0x1c); -+ -+static const uuid_t nvidia_ec_battery_service_uuid = -+ UUID_INIT(0x25cb5207, 0xac36, 0x427d, 0xaa, 0xef, 0x3a, 0xa7, 0x88, 0x77, 0xd2, 0x7e); -+ -+static const uuid_t nvidia_ec_thermal_service_uuid = -+ UUID_INIT(0x31f56da7, 0x593c, 0x4d72, 0xa4, 0xb3, 0x8f, 0xc7, 0x17, 0x1a, 0xc0, 0x73); -+ -+static const uuid_t nvidia_ec_fan_service_uuid = -+ UUID_INIT(0x7697530c, 0xd079, 0x4ec1, 0xa4, 0xc4, 0xcf, 0x0d, 0x2b, 0xdc, 0x93, 0xfa); -+ -+static const uuid_t nvidia_ec_ucsi_service_uuid = -+ UUID_INIT(0x65467f50, 0x827f, 0x4e4f, 0x87, 0x70, 0xdb, 0xf4, 0xc3, 0xf7, 0x7f, 0x45); -+ -+static const uuid_t nvidia_ec_input_service_uuid = -+ UUID_INIT(0xe3168a99, 0x4a57, 0x4a2b, 0x8c, 0x5e, 0x11, 0xbc, 0xfe, 0xc7, 0x34, 0x06); -+ -+static const uuid_t nvidia_ec_time_alarm_service_uuid = -+ UUID_INIT(0x23ea63ed, 0xb593, 0x46ea, 0xb0, 0x27, 0x89, 0x24, 0xdf, 0x88, 0xe9, 0x2f); -+ -+/* EC service FFA device structure */ -+struct nvidia_ec_ffa_device { -+ struct ffa_device *ffa_dev; -+ struct list_head list; -+}; -+ -+/* List to contain all EC services FFA device */ -+static LIST_HEAD(nvidia_ec_ffa_dev_head); -+ -+/* Lock to serialize EC services FFA device list access */ -+static DEFINE_MUTEX(nvidia_ffa_lock); -+ -+static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) -+{ -+ struct nvidia_ec_ffa_device *nvidia_ec_ffa_dev; -+ -+ if (!ffa_pdev) { -+ dev_err(&ffa_dev->dev, "nvidia ffa device not available\n"); -+ return -ENODEV; -+ } -+ -+ nvidia_ec_ffa_dev = devm_kmalloc(&ffa_dev->dev, -+ sizeof(*nvidia_ec_ffa_dev), -+ GFP_KERNEL); -+ if (!nvidia_ec_ffa_dev) { -+ dev_err(&ffa_dev->dev, "Failed to allocate memory\n"); -+ return -ENOMEM; -+ } -+ -+ nvidia_ec_ffa_dev->ffa_dev = ffa_dev; -+ INIT_LIST_HEAD(&nvidia_ec_ffa_dev->list); -+ -+ mutex_lock(&nvidia_ffa_lock); -+ list_add(&nvidia_ec_ffa_dev->list, &nvidia_ec_ffa_dev_head); -+ mutex_unlock(&nvidia_ffa_lock); -+ -+ return 0; -+} -+ -+static void nvidia_ffa_ec_service_remove(struct ffa_device *ffa_dev) -+{ -+ struct nvidia_ec_ffa_device *cur, *tmp; -+ -+ mutex_lock(&nvidia_ffa_lock); -+ list_for_each_entry_safe(cur, tmp, &nvidia_ec_ffa_dev_head, list) { -+ if (cur->ffa_dev == ffa_dev) { -+ list_del(&cur->list); -+ devm_kfree(&ffa_dev->dev, cur); -+ break; -+ } -+ } -+ mutex_unlock(&nvidia_ffa_lock); -+} -+ -+static const struct ffa_device_id nvidia_ffa_ec_service_ids[] = { -+ { nvidia_ec_managment_service_uuid }, -+ { nvidia_ec_power_service_uuid }, -+ { nvidia_ec_battery_service_uuid }, -+ { nvidia_ec_thermal_service_uuid }, -+ { nvidia_ec_fan_service_uuid }, -+ { nvidia_ec_ucsi_service_uuid }, -+ { nvidia_ec_input_service_uuid }, -+ { nvidia_ec_time_alarm_service_uuid }, -+ {} -+}; -+ -+static struct ffa_driver nvidia_ffa_ec_service_driver = { -+ .name = DRV_NAME, -+ .probe = nvidia_ffa_ec_service_probe, -+ .remove = nvidia_ffa_ec_service_remove, -+ .id_table = nvidia_ffa_ec_service_ids, -+}; -+ - static const struct acpi_device_id nvidia_ffa_device_ids[] = { - /* - * Please refer -@@ -33,6 +132,7 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); - acpi_status status; - unsigned long long data = 0; -+ int ret; - - if (ffa_pdev) { - dev_err(&pdev->dev, "FFA device already registered\n"); -@@ -57,11 +157,20 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - - ffa_pdev = pdev; - -+ ret = ffa_driver_register(&nvidia_ffa_ec_service_driver, THIS_MODULE, DRV_NAME); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "Failed to register ec service driver error=%d\n", ret); -+ ffa_pdev = NULL; -+ return ret; -+ } -+ - return 0; - } - - static void nvidia_ffa_remove(struct platform_device *pdev) - { -+ ffa_driver_unregister(&nvidia_ffa_ec_service_driver); - ffa_pdev = NULL; - } - -From 26f30be7bdecbd0505a5242b533845e5c39b727f Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 7 May 2025 09:06:47 +0000 -Subject: [PATCH] NVIDIA: SAUCE: Add support for EC secure service - communication - -BugLink: https://bugs.launchpad.net/bugs/2114230 - -Please refer - -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md - -for details regarding FFA device details for secure EC -services communication. - -When ACPI interpreter runs code with FFH operation region offset 4, -then this data is meant for EC secure services. The FFH buffer has -data in FFA_REQ_PACKET format. In this packet, it has UUID for EC -service and then the service specific raw data. This commit adds -a custom FFH offset handler. When request comes with custom offset -then it will be handled by nvdia FFA EC driver. Inside the custom -ffh callback, it extracts the UUID and gets the ffa_device for it. -Then it fills raw data in ffa_send_direct_data2 and -invoke sync_send_receive2() routine for that ffa_device. -Once it gets the response back, then it fill data in -FFA_RESP_PACKET format and ACPI interpreter passes that data to -upper layer. - -NOTE: In the above document, the FFA_REQ_PACKET and FFA_RESP_PACKET -uses different format. But in latest firmware code, the ACPI implementation -is done using same format for both request and response -(follows the FFA_REQ_PACKET format). The status bit will be updated -in the response (0 for success and 1 for failure). - -This mixed endian is documented in -https://cdrdv2-public.intel.com/772722/asl-tutorial-v20190625.pdf - - In addition to Concatenate, there are several useful macros that generate - buffers from strings. For example, the ToUUID macro takes a string of the - form aabbccdd-eeff-gghh-iijj-kkllmmnnoopp where aa through pp represent - one byte values encoded with hexadecimal characters. This string gets - converted to a 16-byte buffer that looks like the following: - Buffer() - { - dd, cc, bb, aa, - ff, ee, - hh, gg, - ii, jj, kk, ll, mm, nn, oo, pp - } - - This mixture of little endian and big-endian encoding UUID is called - a mixed-endian format. The use of strings and the ToUUID macro is a - convenient way to avoid having to manually encode the mixed-endian - format. There are many other macros that provide similar - conveniences, such as EISAID. In kernel, it is represented with guid_t. - -Inside nvidia_ffh_handler(), we need to covert buffer of 16 -bytes from FFA UUID to AML UUID format. nvidia_get_uuid_from_aml_buf() -converts the AML UUID buffer into FFA UUID format. - -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 40ca7bcc7774 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit 613505b042bcdd9ac64a33690d9b175f596b0828 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 115 +++++++++++++++++++++++++ - 1 file changed, 115 insertions(+) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 537e7a51bd..4181addad8 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -51,6 +51,113 @@ static LIST_HEAD(nvidia_ec_ffa_dev_head); - /* Lock to serialize EC services FFA device list access */ - static DEFINE_MUTEX(nvidia_ffa_lock); - -+/* EC secure services FFA packet structure sent via ACPI */ -+struct nvidia_ec_ffa_packet { -+ u8 status; -+ u8 length; -+ u8 uuid[UUID_SIZE]; -+ u8 rawdata[]; -+} __packed; -+ -+/* -+ * ACPI ASL code uses ToUUID() macro which encodes it in mixed-endian format. -+ * Convert the AML UUID buffer into FFA UUID format. -+ */ -+static uuid_t nvidia_get_uuid_from_aml_buf(const u8 *buf) -+{ -+ return (uuid_t) {{ buf[3], buf[2], buf[1], buf[0], -+ buf[5], buf[4], buf[7], buf[6], -+ buf[8], buf[9], buf[10], buf[11], -+ buf[12], buf[13], buf[14], buf[15] }}; -+} -+ -+/* -+ * Handler function for FFH operation region offset 4. -+ * When ACPI interpreter runs code with FFH operation region offset 4, -+ * then this data is meant for EC secure services. The FFH buffer has -+ * data in 'struct nvidia_ec_ffa_packet' format. In this packet, it has UUID -+ * for EC secure service and then the service specific raw data. -+ * -+ * 1. Extract the UUID from this packet and get ffa_device for it. -+ * 2. Fill raw data in 'struct ffa_send_direct_data2' and -+ * invoke sync_send_receive2() routine for the ffa_device. -+ * 3. From response, fill the data in 'struct ffa_send_direct_data2' -+ * and return. -+ */ -+static int nvidia_ffh_handler(struct acpi_ffh_info *info, acpi_integer *value, void *region_context) -+{ -+ struct ffa_send_direct_data2 ffa_data = { 0 }; -+ struct nvidia_ec_ffa_packet *ffa_packet = (struct nvidia_ec_ffa_packet *)value; -+ struct nvidia_ec_ffa_device *cur, *ec_dev = NULL; -+ int ret; -+ uuid_t uuid; -+ -+ /* Only offset 4 is supported */ -+ if (info->offset != 4) -+ return -EOPNOTSUPP; -+ -+ /* Length should not be less than header length */ -+ if (info->length < offsetof(struct nvidia_ec_ffa_packet, rawdata)) -+ return -EINVAL; -+ -+ /* Length should not be less than actual packet length */ -+ if (info->length < -+ ffa_packet->length + offsetof(struct nvidia_ec_ffa_packet, rawdata)) { -+ ffa_packet->status = 1; -+ return -EINVAL; -+ } -+ -+ /* Packet length should not greater than FFA supported data length */ -+ if (ffa_packet->length > sizeof(ffa_data.data)) { -+ ffa_packet->status = 1; -+ return -EINVAL; -+ } -+ -+ /* Convert AML UUID to FFA UUID */ -+ uuid = nvidia_get_uuid_from_aml_buf((u8 *)ffa_packet->uuid); -+ -+ mutex_lock(&nvidia_ffa_lock); -+ /* Get nvidia_ec_ffa_device for the current UUID */ -+ list_for_each_entry(cur, &nvidia_ec_ffa_dev_head, list) { -+ if (uuid_equal(&uuid, &cur->ffa_dev->uuid)) { -+ ec_dev = cur; -+ break; -+ } -+ } -+ mutex_unlock(&nvidia_ffa_lock); -+ -+ if (!ec_dev) { -+ ffa_packet->status = 1; -+ return -EINVAL; -+ } -+ -+ /* Copy the ACPI FFH packet data into FFA data */ -+ memcpy(ffa_data.data, ffa_packet->rawdata, ffa_packet->length); -+ -+ if (!ec_dev->ffa_dev->ops || -+ !ec_dev->ffa_dev->ops->msg_ops || -+ !ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2) { -+ return -EINVAL; -+ } -+ -+ ret = ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2(ec_dev->ffa_dev, -+ &ffa_data); -+ if (ret) { -+ dev_err(&ec_dev->ffa_dev->dev, -+ "Failed to send FFA messages error=%d\n", ret); -+ ffa_packet->status = 1; -+ return ret; -+ } -+ -+ /* Set the status as success */ -+ ffa_packet->status = 0; -+ -+ /* Copy the ACPI FFA data back into ACPI FFH packet */ -+ memcpy(ffa_packet->rawdata, ffa_data.data, ffa_packet->length); -+ -+ return 0; -+} -+ - static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - { - struct nvidia_ec_ffa_device *nvidia_ec_ffa_dev; -@@ -155,6 +262,13 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - return -ENODEV; - } - -+ ret = acpi_arm64_ffh_update_custom_offset_handler(nvidia_ffh_handler); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "Failed to register custom offset handler error=%d\n", ret); -+ return ret; -+ } -+ - ffa_pdev = pdev; - - ret = ffa_driver_register(&nvidia_ffa_ec_service_driver, THIS_MODULE, DRV_NAME); -@@ -172,6 +286,7 @@ static void nvidia_ffa_remove(struct platform_device *pdev) - { - ffa_driver_unregister(&nvidia_ffa_ec_service_driver); - ffa_pdev = NULL; -+ acpi_arm64_ffh_update_custom_offset_handler(NULL); - } - - static struct platform_driver nvidia_ffa_driver = { -From f4420af725d30e05d06c17e759d89db57d103034 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 7 May 2025 09:22:14 +0000 -Subject: [PATCH] NVIDIA: SAUCE: Rescan acpi devices that uses secure EC - communication - -BugLink: https://bugs.launchpad.net/bugs/2114230 - -- During boot time, ACPI probe happens first. It calls _STA method for - each added device. - -- Inside _STA method for device managed by EC, it uses FFH offset 4. - -- The request will fail since there is no custom handler registered - for offset 0x4 and device will be disabled. - -- If rescan happens on acpi bus, then device _STA method will be - called again. - -This commit adds support to get acpi id from UUID and -invokes acpi_bus_scan(). - -NOTE: nvidia_get_acpi_id_from_uuid() returns ACPI ID only -for few services. We don't have a corresponding driver available -for all the services in the current code. For few services only, -its node uses generic ACPI ID and has driver available. -For rest of the service, the driver is not yet available, -or the published spec is not updated with full ACPI sample code. -Once we have driver available for that, then we can add -those ACPI IDs in this list. - -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 971a25e19691 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit e4ec4146cc8afe52290d15148ecbff121d06a140 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 42 ++++++++++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 4181addad8..b47a99a5d4 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -71,6 +71,35 @@ static uuid_t nvidia_get_uuid_from_aml_buf(const u8 *buf) - buf[12], buf[13], buf[14], buf[15] }}; - } - -+static int nvidia_ffa_rescan_acpi_device(struct device *dev, void *data) -+{ -+ struct acpi_device *adev = to_acpi_device(dev); -+ -+ if (acpi_dev_hid_uid_match(adev, data, NULL)) { -+ acpi_bus_scan(adev->handle); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static const char *nvidia_get_acpi_id_from_uuid(uuid_t *uuid) -+{ -+ if (uuid_equal(uuid, &nvidia_ec_battery_service_uuid)) -+ return "PNP0C0A"; -+ -+ if (uuid_equal(uuid, &nvidia_ec_time_alarm_service_uuid)) -+ return "ACPI000E"; -+ -+ if (uuid_equal(uuid, &nvidia_ec_fan_service_uuid)) -+ return "PNP0C0B"; -+ -+ if (uuid_equal(uuid, &nvidia_ec_ucsi_service_uuid)) -+ return "PNP0CA0"; -+ -+ return NULL; -+} -+ - /* - * Handler function for FFH operation region offset 4. - * When ACPI interpreter runs code with FFH operation region offset 4, -@@ -161,6 +190,7 @@ static int nvidia_ffh_handler(struct acpi_ffh_info *info, acpi_integer *value, v - static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - { - struct nvidia_ec_ffa_device *nvidia_ec_ffa_dev; -+ const char *acpi_id = NULL; - - if (!ffa_pdev) { - dev_err(&ffa_dev->dev, "nvidia ffa device not available\n"); -@@ -182,6 +212,18 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - list_add(&nvidia_ec_ffa_dev->list, &nvidia_ec_ffa_dev_head); - mutex_unlock(&nvidia_ffa_lock); - -+ /* -+ * When acpi subsystem probe all ACPI devices, then it execute _STA -+ * method for each device. The _STA method fails at that time since -+ * custom FFA driver won't be ready. Get ACPI ID from UUID and -+ * rescan the device again. -+ */ -+ acpi_id = nvidia_get_acpi_id_from_uuid(&ffa_dev->uuid); -+ if (acpi_id) { -+ acpi_bus_for_each_dev(nvidia_ffa_rescan_acpi_device, -+ (void *)acpi_id); -+ } -+ - return 0; - } - -From 355dffae11c1a83245503aea6d8642d4df785be3 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Thu, 8 May 2025 20:26:27 +0000 -Subject: [PATCH] NVIDIA: SAUCE: Add support for notifications from secure EC - services - -BugLink: https://bugs.launchpad.net/bugs/2114230 - -Please refer -https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md -for details regarding FFA device details for secure -EC services communication. - -1. We need to get virtual IDs which a EC service supports. - In the FFA node, the _DSD object contains this information. - If we look the sample from above document, - - Name(_DSD, Package() { - ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), //Device Prop UUID - Package() { - Package(2) { - "arm-arml0002-ffa-ntf-bind", - Package() { - 1, // Revision - 2, // Count of following packages - Package () { - ToUUID("330c1273-fde5-4757-9819-5b6539037502"), // Service1 UUID - Package () { - 0x01, //Cookie1 (UINT32) - 0x07, //Cookie2 - } - }, - Package () { - ToUUID("b510b3a3-59f6-4054-ba7a-ff2eb1eac765"), // Service2 UUID - Package () { - 0x01, //Cookie1 - 0x03, //Cookie2 - } - } - } - } - } - }) // _DSD() - - Then it uses a nexted package structure. - nvidia_ffa_fill_notification_map() added in this commit parses the _DSD - object and fill the notification id map for that service. - -2. Once the virtual ID is get then it needs to map to - physical ID by invoking function 1 in the notify service. - -3. The UUID for notification service is - B510B3A3-59F6-4054-BA7A-FF2EB1EAC765. - An FFA device will be created for this notification service - by ffa_module. This notify service needs to be probed first. - To make that happen, a separate ffa_driver instance is created - and it is getting registered first. - -4. We can do 1:1 mapping between virtual ID and hardware ID. - -5. We need to invoke notify_request() with hardware notification ID. - It registers callback function for notification. - -6. Once notification comes then we need to evaluate _DSM method - with virtual ID (which will be mapped same as hardware ID). - -7. The function 2 in the notify service should destroy the mapping. - But it is nither implemented in the firmware not its documentation - is available. A TODO comment is added in - nvidia_ffa_notification_destroy(). - - Also, if we unload and reload the modules, the existing mapping - still exists. In nvidia_ffa_notification_setup(), ignore the error - for this case. When firmware is updated, then the error will be - returned. - -8. The notification service FFA device is needed by each EC secure - services FFA device to get virtual notification list. Now following - device dependency chain is created. - - FFA device <- notification service FFA device <- EC secure services FFA device - - To satisfy this, call driver registration in its dependent driver probe routine. - Similarly, do the driver registration in its dependent driver removed routine. - -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 1287a1d24fd0 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit 605dde1a0254e9eebe7ab4142891430a71f4da39 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 473 ++++++++++++++++++++++++- - 1 file changed, 468 insertions(+), 5 deletions(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index b47a99a5d4..78068f1237 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -15,6 +15,12 @@ - /* platform device for FFA ACPI device (HID MSFT000C) */ - static struct platform_device *ffa_pdev; - -+/* FFA device for EC notification service */ -+static struct ffa_device *notify_ffa_dev; -+ -+static const uuid_t nvidia_ec_notify_service_uuid = -+ UUID_INIT(0xb510b3a3, 0x59f6, 0x4054, 0xba, 0x7a, 0xff, 0x2e, 0xb1, 0xea, 0xc7, 0x65); -+ - static const uuid_t nvidia_ec_managment_service_uuid = - UUID_INIT(0x330c1273, 0xfde5, 0x4757, 0x98, 0x19, 0x5b, 0x65, 0x39, 0x03, 0x75, 0x02); - -@@ -39,9 +45,19 @@ static const uuid_t nvidia_ec_input_service_uuid = - static const uuid_t nvidia_ec_time_alarm_service_uuid = - UUID_INIT(0x23ea63ed, 0xb593, 0x46ea, 0xb0, 0x27, 0x89, 0x24, 0xdf, 0x88, 0xe9, 0x2f); - -+static const guid_t nvidia_notify_bind_guid = -+ GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c, 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01); -+ -+static const guid_t nvidia_notify_dsm_guid = -+ GUID_INIT(0x7681541e, 0x8827, 0x4239, 0x8d, 0x9d, 0x36, 0xbe, 0x7f, 0xe1, 0x25, 0x42); -+ -+#define NVIDIA_FFA_MAX_NOTIFICATIONS 64 -+ - /* EC service FFA device structure */ - struct nvidia_ec_ffa_device { - struct ffa_device *ffa_dev; -+ u8 notification_count; -+ u8 notification_id[NVIDIA_FFA_MAX_NOTIFICATIONS]; - struct list_head list; - }; - -@@ -71,6 +87,27 @@ static uuid_t nvidia_get_uuid_from_aml_buf(const u8 *buf) - buf[12], buf[13], buf[14], buf[15] }}; - } - -+/* -+ * ACPI ASL code uses ToUUID() macro which encodes it in mixed-endian format. -+ * Convert UUID buffer to AML UUID. -+ */ -+static void nvidia_uuid_to_aml_uuid_buf(const uuid_t *uuid, u8 *buf) -+{ -+ const u8 *src = (u8 *)uuid; -+ -+ buf[0] = src[3]; -+ buf[1] = src[2]; -+ buf[2] = src[1]; -+ buf[3] = src[0]; -+ -+ buf[4] = src[5]; -+ buf[5] = src[4]; -+ buf[6] = src[7]; -+ buf[7] = src[6]; -+ -+ memcpy(buf + 8, src + 8, 8); -+} -+ - static int nvidia_ffa_rescan_acpi_device(struct device *dev, void *data) - { - struct acpi_device *adev = to_acpi_device(dev); -@@ -100,6 +137,380 @@ static const char *nvidia_get_acpi_id_from_uuid(uuid_t *uuid) - return NULL; - } - -+/* -+ * Fill the virtual notification IDs array supported by the current FFA device. -+ * ACPI _DSD object contains notification mapping. It uses nexted package -+ * acpi object. -+ * -+ * From the example given in -+ * https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#register-notification -+ * -+ * pkg1 Name(_DSD, Package() { -+ * pkg1_guid ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), // Device Prop UUID -+ * pkg2 Package() { -+ * pkg3 Package(2) { -+ * pkg3_prop "arm-arml0002-ffa-ntf-bind", -+ * pkg4 Package() { -+ * pkg4_rev 1, // Revision -+ * pkg4_count 1, // Count of following packages -+ * pkg5 Package () { -+ * pkg5_uuid ToUUID("330c1273-fde5-4757-9819-5b6539037502"), // Service1 UUID -+ * pkg6 Package () { -+ * pkg6_notify_id[] 0x01, // Cookie1 (UINT32) -+ * 0x07, // Cookie2 -+ * } -+ * }, -+ * } -+ * } -+ * } -+ * }) // _DSD() -+ * -+ * The variable names in this function are according to above. -+ */ -+static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_dev) -+{ -+ struct acpi_device *adev = ACPI_COMPANION(&ffa_pdev->dev); -+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -+ union acpi_object *pkg1, *pkg1_guid; -+ union acpi_object *pkg2; -+ union acpi_object *pkg3, *pkg3_prop; -+ union acpi_object *pkg4, *pkg4_rev, *pkg4_count; -+ acpi_status status; -+ int i; -+ -+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, -+ &output, ACPI_TYPE_PACKAGE); -+ if (ACPI_FAILURE(status)) { -+ dev_err(&ffa_pdev->dev, "ACPI _DSD object not found\n"); -+ return -ENODEV; -+ } -+ -+ pkg1 = output.pointer; -+ -+ /* -+ * _DSD returns a Package() with one or more pairs of elements. -+ * The first element of each pair is a Universal Unique Identifier (UUID). -+ * The second element of each pair is another Package() Data Structure. -+ * -+ * The _DSD for FFA device will have only one pair of elements so -+ * pkg1 elements count should be 2. -+ */ -+ if (pkg1->package.count != 2) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ pkg1_guid = &pkg1->package.elements[0]; -+ pkg2 = &pkg1->package.elements[1]; -+ if (pkg1_guid->type != ACPI_TYPE_BUFFER || -+ pkg1_guid->buffer.length != UUID_SIZE || -+ pkg2->type != ACPI_TYPE_PACKAGE) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ /* Check if GUID macthes with notify device prop GUID */ -+ if (!guid_equal((guid_t *)pkg1_guid->buffer.pointer, -+ &nvidia_notify_bind_guid)) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ /* pkg3 should conatin 1 element with package type */ -+ if (pkg2->package.count != 1) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ pkg3 = &pkg2->package.elements[0]; -+ if (pkg3->type != ACPI_TYPE_PACKAGE) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ pkg3_prop = &pkg3->package.elements[0]; -+ if (pkg3_prop->type != ACPI_TYPE_STRING || -+ strncmp(pkg3_prop->string.pointer, -+ "arm-arml0002-ffa-ntf-bind", -+ pkg3_prop->string.length)) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ pkg4 = &pkg3->package.elements[1]; -+ /* -+ * pkg4 should have minimum 3 elements (revision, count and minimum -+ * one notification map package) -+ */ -+ if (pkg4->type != ACPI_TYPE_PACKAGE || -+ pkg4->package.count < 3) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ pkg4_rev = &pkg4->package.elements[0]; -+ pkg4_count = &pkg4->package.elements[1]; -+ -+ /* Check if revision is 1 */ -+ if (pkg4_rev->type != ACPI_TYPE_INTEGER || -+ pkg4_rev->integer.value != 1) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ /* -+ * The pkg4_count represents the count of following packages. -+ * pkg4_count + 1 (for revision) + 1 (for pkg4_count itself) should -+ * match total number of elements in pkg4. -+ */ -+ if (pkg4_count->type != ACPI_TYPE_INTEGER || -+ (pkg4_count->integer.value + 2) != pkg4->package.count) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ /* -+ * Traverse the array of notification map packages. -+ * Each notification map package contains 2 elements, UUID -+ * and notification ID array package. Check if there is a notification -+ * map for the FFA device by comparing UUID and update the -+ * notification_id[] and notification_count. -+ */ -+ for (i = 2; i < pkg4->package.count; i++) { -+ union acpi_object *pkg5_uuid, *pkg5 = &pkg4->package.elements[2]; -+ union acpi_object *pkg6; -+ uuid_t uuid; -+ int j; -+ -+ if (pkg5->type != ACPI_TYPE_PACKAGE && -+ pkg5->package.count != 2) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ pkg5_uuid = &pkg5->package.elements[0]; -+ pkg6 = &pkg5->package.elements[1]; -+ if (pkg5_uuid->type != ACPI_TYPE_BUFFER || -+ pkg5_uuid->buffer.length != UUID_SIZE || -+ pkg6->type != ACPI_TYPE_PACKAGE) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ uuid = nvidia_get_uuid_from_aml_buf(pkg5_uuid->buffer.pointer); -+ if (!uuid_equal(&uuid, &ec_ffa_dev->ffa_dev->uuid)) -+ continue; -+ -+ for (j = 0; j < pkg6->package.count; j++) { -+ union acpi_object *pkg6_notify_id = &pkg6->package.elements[j]; -+ -+ if (pkg6_notify_id->type != ACPI_TYPE_INTEGER) { -+ kfree(output.pointer); -+ return -EINVAL; -+ } -+ -+ ec_ffa_dev->notification_id[j] = pkg6_notify_id->integer.value; -+ } -+ -+ ec_ffa_dev->notification_count = pkg6->package.count; -+ kfree(output.pointer); -+ return 0; -+ } -+ -+ kfree(output.pointer); -+ return 0; -+} -+ -+/* -+ * Notification EC service callback. -+ * Get the ffa device from callback data and invoke notification _DSM with -+ * notify_id. -+ * -+ * The details regarding _DSM is documented in -+ * https://github.com/OpenDevicePartnership/documentation/tree/main/bookshelf/Shelf%204%20Specifications#notification-events -+ */ -+static void nvidia_ffa_ec_service_notif_callback(int notify_id, void *cb_data) -+{ -+ struct acpi_device *adev = ACPI_COMPANION(&ffa_pdev->dev); -+ struct ffa_device *ffa_dev = (struct ffa_device *)cb_data; -+ union acpi_object args[2], input_pkg; -+ union acpi_object *output; -+ u8 uuid[UUID_SIZE]; -+ -+ nvidia_uuid_to_aml_uuid_buf(&ffa_dev->uuid, uuid); -+ -+ args[0].type = ACPI_TYPE_BUFFER; -+ args[0].buffer.length = sizeof(uuid); -+ args[0].buffer.pointer = uuid; -+ -+ args[1].type = ACPI_TYPE_INTEGER; -+ args[1].integer.value = notify_id; -+ -+ input_pkg.type = ACPI_TYPE_PACKAGE; -+ input_pkg.package.count = 2; -+ input_pkg.package.elements = args; -+ -+ output = acpi_evaluate_dsm(adev->handle, &nvidia_notify_dsm_guid, -+ 1, 1, &input_pkg); -+ if (!output) -+ dev_err(&ffa_pdev->dev, "Failed to execute notify\n"); -+ else -+ ACPI_FREE(output); -+} -+ -+/* -+ * Create notification setup for the notification_id. -+ * -+ * The details regarding notification setup is documented in -+ * https://github.com/OpenDevicePartnership/documentation/tree/main/bookshelf/Shelf%204%20Specifications#register-notification -+ * -+ * This function setup 1:1 mapping between hardware notification ID and -+ * virtual notification ID. -+ */ -+static int nvidia_ffa_notification_setup(struct nvidia_ec_ffa_device *ec_ffa_dev, -+ u8 notification_id) -+{ -+ struct ffa_send_direct_data2 ffa_data = { 0 }; -+ u8 *uuid = (u8 *)&ec_ffa_dev->ffa_dev->uuid; -+ int ret; -+ -+ /* X4 register, function 1 */ -+ ffa_data.data[0] = 1; -+ -+ BUILD_BUG_ON(UUID_SIZE != 16); -+ BUILD_BUG_ON(sizeof(ffa_data.data[1]) < 8); -+ -+ /* X5 and X6 registers contain UUID */ -+ memcpy(&ffa_data.data[1], uuid, 8); -+ memcpy(&ffa_data.data[2], uuid + 8, 8); -+ -+ /* X7 register, the number of notification mappings */ -+ ffa_data.data[3] = 1; -+ -+ /* X7 register, notification ID and notification bitmap bit number */ -+ ffa_data.data[4] = ((u64)notification_id << 32) | notification_id; -+ -+ if (!notify_ffa_dev->ops || -+ !notify_ffa_dev->ops->msg_ops || -+ !notify_ffa_dev->ops->msg_ops->sync_send_receive2) { -+ return -EINVAL; -+ } -+ -+ ret = notify_ffa_dev->ops->msg_ops->sync_send_receive2(notify_ffa_dev, -+ &ffa_data); -+ if (ret) { -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "Failed to send NOTIFY_SETUP id=%d error=%d\n", -+ notification_id, ret); -+ return ret; -+ } -+ -+ if (ffa_data.data[0]) { -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "NOTIFY_SETUP returned failure id=%d error=%ld\n", -+ notification_id, ffa_data.data[0]); -+ -+ /* -+ * TODO: destroy operation is not yet implemented in the firmware -+ * So, if driver is reloaded, then the previous notification -+ * still exists and failure will be returned. Once destroy -+ * is implemented in firmware, update code here to return error -+ */ -+ } -+ -+ return 0; -+} -+ -+/* Destroy notification setup for the notification_id */ -+static void nvidia_ffa_notification_destroy(struct nvidia_ec_ffa_device *ec_ffa_dev, -+ u8 notification_id) -+{ -+ /* -+ * TODO: destroy operation is not yet implemented in the firmware. -+ * Once implemented in firmware, update code here. -+ */ -+} -+ -+/* -+ * Create notifications for the FFA device. -+ * -+ * 1. Get notification map array for FFA device. -+ * 2. For each notification, setup notification with notify service and -+ * then invoke notify_request method to enable notification for FFA device. -+ */ -+static int nvidia_ffa_create_notifications(struct nvidia_ec_ffa_device *ec_ffa_dev) -+{ -+ int i, ret = 0; -+ -+ if (!ec_ffa_dev->ffa_dev->ops || -+ !ec_ffa_dev->ffa_dev->ops->notifier_ops || -+ !ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_request || -+ !ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_relinquish) { -+ return -EOPNOTSUPP; -+ } -+ -+ ret = nvidia_ffa_fill_notification_map(ec_ffa_dev); -+ if (ret) { -+ dev_err(&ffa_pdev->dev, "Error in filling notification map error=%d\n", ret); -+ return ret; -+ } -+ -+ for (i = 0; i < ec_ffa_dev->notification_count; i++) { -+ ret = nvidia_ffa_notification_setup(ec_ffa_dev, -+ ec_ffa_dev->notification_id[i]); -+ if (ret) { -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "Failed to setup notification id=%d error=%d\n", -+ ec_ffa_dev->notification_id[i], ret); -+ break; -+ } -+ -+ ret = ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_request( -+ ec_ffa_dev->ffa_dev, false, -+ nvidia_ffa_ec_service_notif_callback, -+ ec_ffa_dev->ffa_dev, ec_ffa_dev->notification_id[i]); -+ if (ret) { -+ nvidia_ffa_notification_destroy(ec_ffa_dev, -+ ec_ffa_dev->notification_id[i]); -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "Failed to request notification id=%d error=%d\n", -+ ec_ffa_dev->notification_id[i], ret); -+ break; -+ } -+ } -+ -+ /* Remove already setup notification in case of error */ -+ if (ret) { -+ int j; -+ -+ for (j = 0; j < i; j++) { -+ ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_relinquish( -+ ec_ffa_dev->ffa_dev, -+ ec_ffa_dev->notification_id[j]); -+ nvidia_ffa_notification_destroy(ec_ffa_dev, -+ ec_ffa_dev->notification_id[j]); -+ } -+ -+ ec_ffa_dev->notification_count = 0; -+ } -+ -+ return ret; -+} -+ -+/* Remove notifications for the FFA device. */ -+static void nvidia_ffa_remove_notifications(struct nvidia_ec_ffa_device *ec_ffa_dev) -+{ -+ int i; -+ -+ for (i = 0; i < ec_ffa_dev->notification_count; i++) { -+ ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_relinquish( -+ ec_ffa_dev->ffa_dev, -+ ec_ffa_dev->notification_id[i]); -+ nvidia_ffa_notification_destroy(ec_ffa_dev, -+ ec_ffa_dev->notification_id[i]); -+ } -+} -+ - /* - * Handler function for FFH operation region offset 4. - * When ACPI interpreter runs code with FFH operation region offset 4, -@@ -191,9 +602,10 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - { - struct nvidia_ec_ffa_device *nvidia_ec_ffa_dev; - const char *acpi_id = NULL; -+ int ret; - -- if (!ffa_pdev) { -- dev_err(&ffa_dev->dev, "nvidia ffa device not available\n"); -+ if (!ffa_pdev || !notify_ffa_dev) { -+ dev_err(&ffa_dev->dev, "nvidia ffa or notify device not available\n"); - return -ENODEV; - } - -@@ -208,6 +620,15 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - nvidia_ec_ffa_dev->ffa_dev = ffa_dev; - INIT_LIST_HEAD(&nvidia_ec_ffa_dev->list); - -+ ret = nvidia_ffa_create_notifications(nvidia_ec_ffa_dev); -+ if (ret) { -+ dev_info(&ffa_dev->dev, -+ "Failed to create ffa notifications error=%d\n", -+ ret); -+ devm_kfree(&ffa_dev->dev, nvidia_ec_ffa_dev); -+ return ret; -+ } -+ - mutex_lock(&nvidia_ffa_lock); - list_add(&nvidia_ec_ffa_dev->list, &nvidia_ec_ffa_dev_head); - mutex_unlock(&nvidia_ffa_lock); -@@ -235,6 +656,7 @@ static void nvidia_ffa_ec_service_remove(struct ffa_device *ffa_dev) - list_for_each_entry_safe(cur, tmp, &nvidia_ec_ffa_dev_head, list) { - if (cur->ffa_dev == ffa_dev) { - list_del(&cur->list); -+ nvidia_ffa_remove_notifications(cur); - devm_kfree(&ffa_dev->dev, cur); - break; - } -@@ -261,6 +683,46 @@ static struct ffa_driver nvidia_ffa_ec_service_driver = { - .id_table = nvidia_ffa_ec_service_ids, - }; - -+static int nvidia_ffa_notify_service_probe(struct ffa_device *ffa_dev) -+{ -+ int ret; -+ -+ if (!ffa_pdev) { -+ dev_err(&ffa_dev->dev, "nvidia ffa device not available\n"); -+ return -ENODEV; -+ } -+ -+ notify_ffa_dev = ffa_dev; -+ -+ ret = ffa_driver_register(&nvidia_ffa_ec_service_driver, THIS_MODULE, DRV_NAME); -+ if (ret) { -+ dev_err(&ffa_dev->dev, -+ "Failed to register ec service driver error=%d\n", ret); -+ notify_ffa_dev = NULL; -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void nvidia_ffa_notify_service_remove(struct ffa_device *ffa_dev) -+{ -+ ffa_driver_unregister(&nvidia_ffa_ec_service_driver); -+ notify_ffa_dev = NULL; -+} -+ -+static const struct ffa_device_id nvidia_ffa_notify_service_ids[] = { -+ { nvidia_ec_notify_service_uuid }, -+ {} -+}; -+ -+static struct ffa_driver nvidia_ffa_notify_service_driver = { -+ .name = "nvidia-ffa-notify", -+ .probe = nvidia_ffa_notify_service_probe, -+ .remove = nvidia_ffa_notify_service_remove, -+ .id_table = nvidia_ffa_notify_service_ids, -+}; -+ - static const struct acpi_device_id nvidia_ffa_device_ids[] = { - /* - * Please refer -@@ -313,10 +775,11 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - - ffa_pdev = pdev; - -- ret = ffa_driver_register(&nvidia_ffa_ec_service_driver, THIS_MODULE, DRV_NAME); -+ ret = ffa_driver_register(&nvidia_ffa_notify_service_driver, THIS_MODULE, DRV_NAME); - if (ret) { - dev_err(&pdev->dev, -- "Failed to register ec service driver error=%d\n", ret); -+ "Failed to register notify service driver error=%d\n", ret); -+ acpi_arm64_ffh_update_custom_offset_handler(NULL); - ffa_pdev = NULL; - return ret; - } -@@ -326,7 +789,7 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - - static void nvidia_ffa_remove(struct platform_device *pdev) - { -- ffa_driver_unregister(&nvidia_ffa_ec_service_driver); -+ ffa_driver_unregister(&nvidia_ffa_notify_service_driver); - ffa_pdev = NULL; - acpi_arm64_ffh_update_custom_offset_handler(NULL); - } -From 8f45d9ed088f0af91b93a034212fa324c3a8012d Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Tue, 22 Jul 2025 13:45:33 +0000 -Subject: [PATCH] NVIDIA: SAUCE: Fix FFH data response length - -BugLink: https://bugs.launchpad.net/bugs/2118357 - -commit d0038ee1df2b ("NVIDIA: SAUCE: Add support for EC -secure service communication") added nvidia_ffh_handler() -function. While copying the data back into ACPI FFH packet, -it uses the request length. The response data can be larger -than request length. The response length can't be fetched in the -linux FFH handler function. We can copy all the bytes from -ffa_data.data. The ACPI AML code will only use the required -number bytes from this. - -Normally we don't need response length to be known. -The ACPI table are not using that. It is parsing response -data directly. In the latest revision of spec, the length -field itself has been removed - -https://github.com/OpenDevicePartnership/documentation/blob/b23acb09f7cf03a5c3167509533f396d547e6291/guide_book/src/specs/ec_interface/secure-ec-services-overview.md#operation-region-definition - -For DIGITS GB10, it is using older revision of spec and the launch is -planned with older revision of spec. When we move to latest revision, -then we need to copy all data bytes for both request and response. - -The info->length is corresponding to FFH buffer length in ACPI table. -Following is the code in ACPI table - - Name (_HID, "MSFT000C") // _HID: Hardware ID - OperationRegion (AFFH, FFixedHW, 0x04, 0x90) - -info->length will be 0x90 (144) bytes. -ffa_packet->length in the older revision is valid data bytes -(https://github.com/OpenDevicePartnership/documentation/blob/45ad9b30be0f40e229deed2fef7a60d0b0b591f5/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md) - -struct nvidia_ec_ffa_packet *ffa_packet = (struct nvidia_ec_ffa_packet *)value; - -This value buffer length should be info->length. -We are taking minimum of sizeof(ffa_data.data) = 112 and -(info->length = 144) - (offsetof(struct nvidia_ec_ffa_packet, rawdata) = 18) = 126, -so ffh_copy_len will be 112 for the current DIGITS ACPI implementation. - -In the latest revision, this length mismatch is also fixed. Raw data will -start at offset 32, so there both will come as 112. - -Fixes: d0038ee1df2b ("NVIDIA: SAUCE: Add support for EC secure service communication") -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Matthew R. Ochs -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg - -(cherry picked from commit 141bd5652ecc noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit 0477ce56148b65bbaa946135a4791fe7d89b7e8d noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 78068f1237..d9e8b7fdda 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -530,6 +530,7 @@ static int nvidia_ffh_handler(struct acpi_ffh_info *info, acpi_integer *value, v - struct nvidia_ec_ffa_packet *ffa_packet = (struct nvidia_ec_ffa_packet *)value; - struct nvidia_ec_ffa_device *cur, *ec_dev = NULL; - int ret; -+ unsigned int ffh_copy_len; - uuid_t uuid; - - /* Only offset 4 is supported */ -@@ -592,9 +593,16 @@ static int nvidia_ffh_handler(struct acpi_ffh_info *info, acpi_integer *value, v - /* Set the status as success */ - ffa_packet->status = 0; - -- /* Copy the ACPI FFA data back into ACPI FFH packet */ -- memcpy(ffa_packet->rawdata, ffa_data.data, ffa_packet->length); -+ /* -+ * Copy the ACPI FFA data back into ACPI FFH packet. -+ * -+ * ACPI FFH packet raw data length can't be fetched here, so copy -+ * all bytes from ffa_data.data -+ */ -+ ffh_copy_len = min(sizeof(ffa_data.data), -+ info->length - offsetof(struct nvidia_ec_ffa_packet, rawdata)); - -+ memcpy(ffa_packet->rawdata, ffa_data.data, ffh_copy_len); - return 0; - } - -From a420ff149b1380f1e2f77ef38be31b1058d5de82 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Mon, 15 Sep 2025 17:23:32 +0530 -Subject: [PATCH] NVIDIA: SAUCE: Fix FFA notification count initialization - -BugLink: https://bugs.launchpad.net/bugs/2123861 - -In nvidia_ffa_create_notifications(), it invokes -nvidia_ffa_fill_notification_map(), which fills the virtual notification -IDs array supported by the current FFA device. This function updates -notification_count after traversing the notification array in the _DSD -method. For FFA devices without an entry in the _DSD method, -notification_count is assumed to be zero initialized. - -However, nvidia_ffa_ec_service_probe() uses kmalloc() instead of kzalloc(), -so notification_count may contain random values. This causes FFA device -probe failures. - -This patch fixes this by using kzalloc() to zero initialize the -nvidia_ec_ffa_device structure. - -Fixes: ae8718738ca8 ("NVIDIA: SAUCE: Add support for notifications from secure EC services") -Signed-off-by: Abhishek Sahu -Acked-by: Matthew R. Ochs -Acked-by: Nirmoy Das -Acked-by: Carol L Soto -Acked-by: Jacob Martin -Acked-by: Abdur Rahman -Signed-off--by: Brad Figg - -(cherry picked from commit 518a89b25556 noble:linux-nvidia-6.14) -Signed-off-by: Abdur Rahman - -(cherry picked from commit bf0587bed38496ce0affa41f55a51c140a4ef3e0 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index d9e8b7fdda..7a259ba649 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -617,7 +617,7 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - return -ENODEV; - } - -- nvidia_ec_ffa_dev = devm_kmalloc(&ffa_dev->dev, -+ nvidia_ec_ffa_dev = devm_kzalloc(&ffa_dev->dev, - sizeof(*nvidia_ec_ffa_dev), - GFP_KERNEL); - if (!nvidia_ec_ffa_dev) { -From af2eb5b1e50e6861d7ce48460b90a726a3a0e877 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 3 Jun 2026 12:16:12 +0000 -Subject: [PATCH] NVIDIA: SAUCE: platform/arm64: nvidia-ffa-ec: add ARML0002 / - DEN0077A v1.3 ALP5 support - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -Background -========== -When DGX Spark launched, the ARM FF-A EC services specification was -still a draft maintained in the OpenDevicePartnership documentation -repository. The initial deployed firmware tracks that draft and -identifies its FF-A bridge with the ACPI HID MSFT000C. The pinned -draft is preserved at - - https://github.com/OpenDevicePartnership/documentation/blob/0f7b6bad77a3eb07b66b66d0e3af718db2ec1c24/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md - -Since then ARM has published DEN0077A v1.3 ALP5. FF-A itself is now -the "Arm Firmware Framework for Arm A-profile" v1.3 ALP5 (DEN0077A), -the FFH operation-region interface it rides on is the "Arm Functional -Fixed Hardware Specification" (DEN0048D), and the EC secure-services -layer has moved into a companion repository at - - https://github.com/OpenDevicePartnership/odp-embedded-controller/blob/a018ff0ca21ac95c84b3d3559bda0d11962a0344/docs/src/specs/ec_interface/secure-ec-services-overview.md - -Platforms that ship the v1.3 ALP5 stack identify their FF-A bridge -with the ACPI HID ARML0002. - -Extend the driver to support the v1.3 ALP5 stack (ACPI HID ARML0002) -in addition to the existing draft-spec support (ACPI HID MSFT000C). -The two specs share most of the driver machinery but differ in packet -layout, FFH operation-region offset, notification encoding, and -inter-partition setup. - -Key changes in this patch: - - * Add a boolean ffa_ec_legacy_spec that is populated from the ACPI - device-ID match at probe time: - MSFT000C -> true (legacy draft spec) - ARML0002 -> false (DEN0077A v1.3 ALP5) - All spec-dependent branches key off this flag. - - * New packet structure for ARML0002 (144 bytes = 18 x 8-byte - registers X0..X17) alongside the existing 18-byte MSFT000C packet. - Fields: - u64 status bytes 0..7 driver-side status: AML writes 0; - FFH handler sets 1 on error - u64 recvid bytes 8..15 receiver endpoint ID, populated by - the FFA framework path - u8 uuid[16] bytes 16..31 service UUID - u8 rawdata bytes 32+ payload mapped to X4..X17 - - * Two FFH operation-region handlers, dispatched on info->offset: - 0x02 -> nvidia_ffh_handler_arml0002() (DEN0077A v1.3 ALP5), - operation-region defined by ARM DEN0048D "Arm Functional - Fixed Hardware Specification (FFH)" v1.3 section 2.3 - 0x04 -> nvidia_ffh_handler_msft000c() (draft), operation-region - defined by the OpenDevicePartnership secure-ec-services - draft, not by DEN0048D - Both delegate to a shared nvidia_ffh_do_ffa_send() helper that - performs UUID lookup, FFA send, and response copy. For MSFT000C, - the response copy uses ffh_copy_len = min(rawdata_buflen, - sizeof_field(struct ffa_send_direct_data2, data)) so the full - response register file is copied back and legacy consumers do not - see stale bytes past pkt->length. - - * Notification map property parsing handles both revisions: - MSFT000C: pkg4_rev = 1 - ARML0002: pkg4_rev = 0x00010000 (packed v1.0 per DEN0077A v1.3 - section 18.8.2) - - * ARML0002 notification registration uses the inter-partition - setup protocol (UUID e474d87e-...) per DEN0077A v1.3 section 18.7 - with FFA_MSG_SEND_DIRECT_REQ2 and the encoded 64-bit notification - tuple (cookie << 32 | (notif_id & 0x1FF) << 23 | per_vCPU_flag). - - * Consolidate MSFT000C notify and ARML0002 setup handling into a - single nvidia_ffa_control_service_driver whose id_table lists both - UUIDs; the FFA framework matches whichever the platform exposes. - The shared probe stores it in control_ffa_dev and guards against - duplicate registration by returning -EBUSY instead of silently - overwriting the global pointer. - - * Accept either FF-A Device Properties GUID as the outer _DSD - identifier. DEN0077A v1.3 renamed the identifier between drafts: - - ALP3 and earlier: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 - (classic ACPI 6.x Device Properties GUID) - ALP4 and later: c08c3233-b316-4723-a9d7-e21b7ac0fb6a - (FF-A specific Device Properties GUID) - - Firmware in the field ships either one depending on which draft of - the spec the BIOS was locked against; accepting both keeps a single - Linux driver working across revisions. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 521 +++++++++++++++++-------- - 1 file changed, 361 insertions(+), 160 deletions(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 7a259ba649..24cb53bdd2 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -1,9 +1,10 @@ - // SPDX-License-Identifier: GPL-2.0-only - /* -- * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved -+ * Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved - */ - - #include -+#include - #include - #include - #include -@@ -12,15 +13,37 @@ - - #define DRV_NAME "nvidia-ffa-ec" - --/* platform device for FFA ACPI device (HID MSFT000C) */ -+/* -+ * Spec version selected at probe time: -+ * true - MSFT000C, OpenDevicePartnership legacy draft spec -+ * (https://github.com/OpenDevicePartnership/documentation/blob/0f7b6bad77a3eb07b66b66d0e3af718db2ec1c24/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md) -+ * false - ARML0002, ARM DEN0077A v1.3 spec -+ * (https://support.arm.com/documentation/den0077) -+ */ -+static bool ffa_ec_legacy_spec; -+ -+/* platform device for FFA ACPI device */ - static struct platform_device *ffa_pdev; - --/* FFA device for EC notification service */ --static struct ffa_device *notify_ffa_dev; -+/* -+ * FFA device for the control-plane service used to register EC -+ * notifications. A given platform's FF-A bridge only exposes one of the -+ * two possible UUIDs: -+ * -+ * MSFT000C: EC notification service UUID -+ * (b510b3a3-59f6-4054-ba7a-ff2eb1eac765) -+ * ARML0002: inter-partition setup protocol UUID -+ * (e474d87e-5731-4044-a727-cb3e8cf3c8df) -+ */ -+static struct ffa_device *control_ffa_dev; - - static const uuid_t nvidia_ec_notify_service_uuid = - UUID_INIT(0xb510b3a3, 0x59f6, 0x4054, 0xba, 0x7a, 0xff, 0x2e, 0xb1, 0xea, 0xc7, 0x65); - -+/* Inter-partition setup protocol UUID (DEN0077A v1.3 section 18.7) */ -+static const uuid_t nvidia_ec_interpartition_setup_uuid = -+ UUID_INIT(0xe474d87e, 0x5731, 0x4044, 0xa7, 0x27, 0xcb, 0x3e, 0x8c, 0xf3, 0xc8, 0xdf); -+ - static const uuid_t nvidia_ec_managment_service_uuid = - UUID_INIT(0x330c1273, 0xfde5, 0x4757, 0x98, 0x19, 0x5b, 0x65, 0x39, 0x03, 0x75, 0x02); - -@@ -45,14 +68,43 @@ static const uuid_t nvidia_ec_input_service_uuid = - static const uuid_t nvidia_ec_time_alarm_service_uuid = - UUID_INIT(0x23ea63ed, 0xb593, 0x46ea, 0xb0, 0x27, 0x89, 0x24, 0xdf, 0x88, 0xe9, 0x2f); - --static const guid_t nvidia_notify_bind_guid = -+/* -+ * Outer UUID identifying the payload as "Device Properties" in the ACPI -+ * _DSD returned by the FFA bridge. DEN0077A v1.3 changed this GUID -+ * between drafts: -+ * -+ * ALP3 and earlier: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 -+ * ALP4 and later: c08c3233-b316-4723-a9d7-e21b7ac0fb6a -+ */ -+static const guid_t nvidia_notify_bind_guid_legacy = - GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c, 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01); - -+static const guid_t nvidia_notify_bind_guid = -+ GUID_INIT(0xc08c3233, 0xb316, 0x4723, 0xa9, 0xd7, 0xe2, 0x1b, 0x7a, 0xc0, 0xfb, 0x6a); -+ - static const guid_t nvidia_notify_dsm_guid = - GUID_INIT(0x7681541e, 0x8827, 0x4239, 0x8d, 0x9d, 0x36, 0xbe, 0x7f, 0xe1, 0x25, 0x42); - - #define NVIDIA_FFA_MAX_NOTIFICATIONS 64 - -+/* Revision values for the "arm-arml0002-ffa-ntf-bind" property package */ -+#define NVIDIA_FFA_NTF_BIND_REV_MSFT000C 1 -+#define NVIDIA_FFA_NTF_BIND_REV_ARML0002 0x00010000 -+ -+/* -+ * Notification tuple encoding for ARML0002 (DEN0077A v1.3 section 18.7.1, -+ * Table 18.25): -+ * bits[63:32] = cookie (u32) -+ * bits[31:23] = notification ID (9-bit field, LSB at bit 23) -+ * bits[22:1] = Reserved (MBZ) -+ * bit[0] = per-vCPU flag (0 = global) -+ */ -+#define NVIDIA_EC_NOTIF_TUPLE(cookie, id) \ -+ (((u64)(cookie) << 32) | (((u64)(id) & 0x1FF) << 23)) -+ -+/* Message info field: bits[2:0] = 0b010 means notification registration */ -+#define NVIDIA_EC_INTERPARTITION_MSG_NOTIF_REG 0x2 -+ - /* EC service FFA device structure */ - struct nvidia_ec_ffa_device { - struct ffa_device *ffa_dev; -@@ -67,14 +119,40 @@ static LIST_HEAD(nvidia_ec_ffa_dev_head); - /* Lock to serialize EC services FFA device list access */ - static DEFINE_MUTEX(nvidia_ffa_lock); - --/* EC secure services FFA packet structure sent via ACPI */ --struct nvidia_ec_ffa_packet { -+/* -+ * EC secure services FFA packet structure — MSFT000C (FFH offset 4). -+ * https://github.com/OpenDevicePartnership/documentation/blob/0f7b6bad77a3eb07b66b66d0e3af718db2ec1c24/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#operation-region-definition -+ * -+ * Byte layout: -+ * [0] u8 status — zero on input; 1 on error output -+ * [1] u8 length — payload byte count -+ * [2..17] u8 uuid[16] -+ * [18+] u8 rawdata[] -+ */ -+struct nvidia_ec_ffa_packet_msft000c { - u8 status; - u8 length; - u8 uuid[UUID_SIZE]; - u8 rawdata[]; - } __packed; - -+/* -+ * EC secure services FFA packet structure — ARML0002 (FFH offset 2). -+ * Layout per the OpenDevicePartnership odp-embedded-controller -+ * secure-ec-services-overview spec (Operation Region Definition). -+ * -+ * [0..7] u64 status — AML writes 0; FFH handler sets 1 on error -+ * [8..15] u64 recvid — receiver endpoint ID, not touched by handler -+ * [16..31] u8 uuid[16] — target service UUID -+ * [32+] u8 rawdata[] — payload copied to/from X4..X17 -+ */ -+struct nvidia_ec_ffa_packet_arml0002 { -+ u64 status; -+ u64 recvid; -+ u8 uuid[UUID_SIZE]; -+ u8 rawdata[]; -+} __packed; -+ - /* - * ACPI ASL code uses ToUUID() macro which encodes it in mixed-endian format. - * Convert the AML UUID buffer into FFA UUID format. -@@ -139,25 +217,28 @@ static const char *nvidia_get_acpi_id_from_uuid(uuid_t *uuid) - - /* - * Fill the virtual notification IDs array supported by the current FFA device. -- * ACPI _DSD object contains notification mapping. It uses nexted package -- * acpi object. -+ * ACPI _DSD object contains notification mapping via nested packages. - * -- * From the example given in -- * https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#register-notification -+ * Both MSFT000C and ARML0002 use the same property key -+ * "arm-arml0002-ffa-ntf-bind" and the same nested package structure, but -+ * differ in the revision field: -+ * MSFT000C: pkg4_rev = 1 -+ * ARML0002: pkg4_rev = 0x00010000 -+ * -+ * From the example given in DEN0077A v1.3 section 18.8.2: - * - * pkg1 Name(_DSD, Package() { -- * pkg1_guid ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), // Device Prop UUID -+ * pkg1_guid ToUUID("c08c3233-b316-4723-a9d7-e21b7ac0fb6a"), - * pkg2 Package() { - * pkg3 Package(2) { - * pkg3_prop "arm-arml0002-ffa-ntf-bind", - * pkg4 Package() { -- * pkg4_rev 1, // Revision -- * pkg4_count 1, // Count of following packages -+ * pkg4_rev 0x00010000, // Revision (v1.0) -+ * pkg4_count 1, // Count of following packages - * pkg5 Package () { -- * pkg5_uuid ToUUID("330c1273-fde5-4757-9819-5b6539037502"), // Service1 UUID -+ * pkg5_uuid ToUUID("...service UUID..."), - * pkg6 Package () { -- * pkg6_notify_id[] 0x01, // Cookie1 (UINT32) -- * 0x07, // Cookie2 -+ * pkg6_notify_id[] 0x01, // Cookie1 (UINT32) - * } - * }, - * } -@@ -165,7 +246,7 @@ static const char *nvidia_get_acpi_id_from_uuid(uuid_t *uuid) - * } - * }) // _DSD() - * -- * The variable names in this function are according to above. -+ * Local variable names below follow the pkgN_* labels in the diagram above. - */ - static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_dev) - { -@@ -189,11 +270,8 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - - /* - * _DSD returns a Package() with one or more pairs of elements. -- * The first element of each pair is a Universal Unique Identifier (UUID). -- * The second element of each pair is another Package() Data Structure. -- * -- * The _DSD for FFA device will have only one pair of elements so -- * pkg1 elements count should be 2. -+ * The first element of each pair is a UUID, the second is a Package(). -+ * The FFA device _DSD has only one such pair so count must be 2. - */ - if (pkg1->package.count != 2) { - kfree(output.pointer); -@@ -209,14 +287,16 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - return -EINVAL; - } - -- /* Check if GUID macthes with notify device prop GUID */ -+ /* Check if GUID matches with notify device prop GUID */ - if (!guid_equal((guid_t *)pkg1_guid->buffer.pointer, -- &nvidia_notify_bind_guid)) { -+ &nvidia_notify_bind_guid) && -+ !guid_equal((guid_t *)pkg1_guid->buffer.pointer, -+ &nvidia_notify_bind_guid_legacy)) { - kfree(output.pointer); - return -EINVAL; - } - -- /* pkg3 should conatin 1 element with package type */ -+ /* pkg2 should contain 1 element with package type */ - if (pkg2->package.count != 1) { - kfree(output.pointer); - return -EINVAL; -@@ -239,8 +319,8 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - - pkg4 = &pkg3->package.elements[1]; - /* -- * pkg4 should have minimum 3 elements (revision, count and minimum -- * one notification map package) -+ * pkg4 must have at least 3 elements: revision, count, and one -+ * notification map package. - */ - if (pkg4->type != ACPI_TYPE_PACKAGE || - pkg4->package.count < 3) { -@@ -251,17 +331,17 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - pkg4_rev = &pkg4->package.elements[0]; - pkg4_count = &pkg4->package.elements[1]; - -- /* Check if revision is 1 */ -+ /* Accept both revision values */ - if (pkg4_rev->type != ACPI_TYPE_INTEGER || -- pkg4_rev->integer.value != 1) { -+ (pkg4_rev->integer.value != NVIDIA_FFA_NTF_BIND_REV_MSFT000C && -+ pkg4_rev->integer.value != NVIDIA_FFA_NTF_BIND_REV_ARML0002)) { - kfree(output.pointer); - return -EINVAL; - } - - /* -- * The pkg4_count represents the count of following packages. -- * pkg4_count + 1 (for revision) + 1 (for pkg4_count itself) should -- * match total number of elements in pkg4. -+ * pkg4_count + 1 (revision) + 1 (count itself) must equal total -+ * elements in pkg4. - */ - if (pkg4_count->type != ACPI_TYPE_INTEGER || - (pkg4_count->integer.value + 2) != pkg4->package.count) { -@@ -270,25 +350,23 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - } - - /* -- * Traverse the array of notification map packages. -- * Each notification map package contains 2 elements, UUID -- * and notification ID array package. Check if there is a notification -- * map for the FFA device by comparing UUID and update the -- * notification_id[] and notification_count. -+ * Traverse the array of notification map packages. Each entry has a -+ * UUID and a package of cookie integers. Match UUID against the FFA -+ * device and populate notification_id[]. - */ - for (i = 2; i < pkg4->package.count; i++) { -- union acpi_object *pkg5_uuid, *pkg5 = &pkg4->package.elements[2]; -+ union acpi_object *pkg5_uuid, *pkg5 = &pkg4->package.elements[i]; - union acpi_object *pkg6; - uuid_t uuid; - int j; - -- if (pkg5->type != ACPI_TYPE_PACKAGE && -+ if (pkg5->type != ACPI_TYPE_PACKAGE || - pkg5->package.count != 2) { - kfree(output.pointer); - return -EINVAL; - } - -- pkg5_uuid = &pkg5->package.elements[0]; -+ pkg5_uuid = &pkg5->package.elements[0]; - pkg6 = &pkg5->package.elements[1]; - if (pkg5_uuid->type != ACPI_TYPE_BUFFER || - pkg5_uuid->buffer.length != UUID_SIZE || -@@ -325,9 +403,6 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - * Notification EC service callback. - * Get the ffa device from callback data and invoke notification _DSM with - * notify_id. -- * -- * The details regarding _DSM is documented in -- * https://github.com/OpenDevicePartnership/documentation/tree/main/bookshelf/Shelf%204%20Specifications#notification-events - */ - static void nvidia_ffa_ec_service_notif_callback(int notify_id, void *cb_data) - { -@@ -359,44 +434,40 @@ static void nvidia_ffa_ec_service_notif_callback(int notify_id, void *cb_data) - } - - /* -- * Create notification setup for the notification_id. -+ * MSFT000C notification setup. - * - * The details regarding notification setup is documented in -- * https://github.com/OpenDevicePartnership/documentation/tree/main/bookshelf/Shelf%204%20Specifications#register-notification -- * -- * This function setup 1:1 mapping between hardware notification ID and -- * virtual notification ID. -+ * https://github.com/OpenDevicePartnership/documentation/blob/0f7b6bad77a3eb07b66b66d0e3af718db2ec1c24/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#register-notification - */ --static int nvidia_ffa_notification_setup(struct nvidia_ec_ffa_device *ec_ffa_dev, -- u8 notification_id) -+static int nvidia_ffa_notification_setup_msft000c(struct nvidia_ec_ffa_device *ec_ffa_dev, -+ u8 notification_id) - { - struct ffa_send_direct_data2 ffa_data = { 0 }; - u8 *uuid = (u8 *)&ec_ffa_dev->ffa_dev->uuid; - int ret; - -- /* X4 register, function 1 */ -- ffa_data.data[0] = 1; -- - BUILD_BUG_ON(UUID_SIZE != 16); - BUILD_BUG_ON(sizeof(ffa_data.data[1]) < 8); - -- /* X5 and X6 registers contain UUID */ -+ /* X4: function 1 (NOTIFY_SETUP) */ -+ ffa_data.data[0] = 1; -+ -+ /* X5, X6: EC service UUID */ - memcpy(&ffa_data.data[1], uuid, 8); - memcpy(&ffa_data.data[2], uuid + 8, 8); - -- /* X7 register, the number of notification mappings */ -+ /* X7: number of notification mappings */ - ffa_data.data[3] = 1; - -- /* X7 register, notification ID and notification bitmap bit number */ -+ /* X8: notification ID used as both cookie and bitmap bit number */ - ffa_data.data[4] = ((u64)notification_id << 32) | notification_id; - -- if (!notify_ffa_dev->ops || -- !notify_ffa_dev->ops->msg_ops || -- !notify_ffa_dev->ops->msg_ops->sync_send_receive2) { -+ if (!control_ffa_dev->ops || -+ !control_ffa_dev->ops->msg_ops || -+ !control_ffa_dev->ops->msg_ops->sync_send_receive2) - return -EINVAL; -- } - -- ret = notify_ffa_dev->ops->msg_ops->sync_send_receive2(notify_ffa_dev, -+ ret = control_ffa_dev->ops->msg_ops->sync_send_receive2(control_ffa_dev, - &ffa_data); - if (ret) { - dev_err(&ec_ffa_dev->ffa_dev->dev, -@@ -421,6 +492,72 @@ static int nvidia_ffa_notification_setup(struct nvidia_ec_ffa_device *ec_ffa_dev - return 0; - } - -+/* -+ * ARML0002 notification setup (DEN0077A v1.3 section 18.7.1, Table 18.25). -+ * Uses the inter-partition setup protocol UUID. -+ */ -+static int nvidia_ffa_notification_setup_arml0002(struct nvidia_ec_ffa_device *ec_ffa_dev, -+ u8 notification_id) -+{ -+ struct ffa_send_direct_data2 ffa_data = { 0 }; -+ u8 *svc_uuid = (u8 *)&ec_ffa_dev->ffa_dev->uuid; -+ int ret; -+ -+ BUILD_BUG_ON(UUID_SIZE != 16); -+ BUILD_BUG_ON(sizeof(ffa_data.data[1]) < 8); -+ -+ /* Sender UUID: not applicable for OS-side caller, left as zero */ -+ -+ /* X7, X8: receiver (EC) service UUID */ -+ memcpy(&ffa_data.data[3], svc_uuid, 8); -+ memcpy(&ffa_data.data[4], svc_uuid + 8, 8); -+ -+ /* X9: notification registration request */ -+ ffa_data.data[5] = NVIDIA_EC_INTERPARTITION_MSG_NOTIF_REG; -+ -+ /* X10: one tuple */ -+ ffa_data.data[6] = 1; -+ -+ /* X11: tuple — cookie = notification_id, bitmap position = notification_id */ -+ ffa_data.data[7] = NVIDIA_EC_NOTIF_TUPLE(notification_id, notification_id); -+ -+ if (!control_ffa_dev->ops || -+ !control_ffa_dev->ops->msg_ops || -+ !control_ffa_dev->ops->msg_ops->sync_send_receive2) -+ return -EINVAL; -+ -+ ret = control_ffa_dev->ops->msg_ops->sync_send_receive2(control_ffa_dev, -+ &ffa_data); -+ if (ret) { -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "Failed to send NOTIFY_SETUP id=%d error=%d\n", -+ notification_id, ret); -+ return ret; -+ } -+ -+ /* -+ * DEN0077A v1.3 ALP5 Table 18.26: the inter-partition setup response -+ * carries the protocol return status in X10[7:0]. -+ */ -+ if (ffa_data.data[6] & 0xff) { -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "NOTIFY_SETUP returned failure id=%d status=0x%02lx\n", -+ notification_id, ffa_data.data[6] & 0xff); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int nvidia_ffa_notification_setup(struct nvidia_ec_ffa_device *ec_ffa_dev, -+ u8 notification_id) -+{ -+ if (!ffa_ec_legacy_spec) -+ return nvidia_ffa_notification_setup_arml0002(ec_ffa_dev, notification_id); -+ -+ return nvidia_ffa_notification_setup_msft000c(ec_ffa_dev, notification_id); -+} -+ - /* Destroy notification setup for the notification_id */ - static void nvidia_ffa_notification_destroy(struct nvidia_ec_ffa_device *ec_ffa_dev, - u8 notification_id) -@@ -435,8 +572,8 @@ static void nvidia_ffa_notification_destroy(struct nvidia_ec_ffa_device *ec_ffa_ - * Create notifications for the FFA device. - * - * 1. Get notification map array for FFA device. -- * 2. For each notification, setup notification with notify service and -- * then invoke notify_request method to enable notification for FFA device. -+ * 2. For each notification, setup notification with the control service and -+ * then invoke notify_request to enable notification for the FFA device. - */ - static int nvidia_ffa_create_notifications(struct nvidia_ec_ffa_device *ec_ffa_dev) - { -@@ -512,98 +649,146 @@ static void nvidia_ffa_remove_notifications(struct nvidia_ec_ffa_device *ec_ffa_ - } - - /* -- * Handler function for FFH operation region offset 4. -- * When ACPI interpreter runs code with FFH operation region offset 4, -- * then this data is meant for EC secure services. The FFH buffer has -- * data in 'struct nvidia_ec_ffa_packet' format. In this packet, it has UUID -- * for EC secure service and then the service specific raw data. -+ * Common FFA send path shared by both FFH handlers. - * -- * 1. Extract the UUID from this packet and get ffa_device for it. -- * 2. Fill raw data in 'struct ffa_send_direct_data2' and -- * invoke sync_send_receive2() routine for the ffa_device. -- * 3. From response, fill the data in 'struct ffa_send_direct_data2' -- * and return. -+ * Looks up the EC device by UUID, copies input_len bytes from rawdata into -+ * the FFA data registers, sends FFA_MSG_SEND_DIRECT_REQ2, then copies -+ * output_len bytes of the response back into rawdata. -+ * -+ * Returns 0 on success, negative error code on failure. - */ --static int nvidia_ffh_handler(struct acpi_ffh_info *info, acpi_integer *value, void *region_context) -+static int nvidia_ffh_do_ffa_send(uuid_t uuid, u8 *rawdata, -+ unsigned int input_len, unsigned int output_len) - { - struct ffa_send_direct_data2 ffa_data = { 0 }; -- struct nvidia_ec_ffa_packet *ffa_packet = (struct nvidia_ec_ffa_packet *)value; -- struct nvidia_ec_ffa_device *cur, *ec_dev = NULL; -+ struct nvidia_ec_ffa_device *cur, *ec_dev = NULL; - int ret; -- unsigned int ffh_copy_len; -- uuid_t uuid; - -- /* Only offset 4 is supported */ -- if (info->offset != 4) -- return -EOPNOTSUPP; -+ /* -+ * Hold nvidia_ffa_lock across the whole lookup + send so ec_dev -+ * cannot be freed by a concurrent nvidia_ffa_ec_service_remove() -+ * while its ->ffa_dev is still being dereferenced here. -+ */ -+ guard(mutex)(&nvidia_ffa_lock); - -- /* Length should not be less than header length */ -- if (info->length < offsetof(struct nvidia_ec_ffa_packet, rawdata)) -- return -EINVAL; -- -- /* Length should not be less than actual packet length */ -- if (info->length < -- ffa_packet->length + offsetof(struct nvidia_ec_ffa_packet, rawdata)) { -- ffa_packet->status = 1; -- return -EINVAL; -- } -- -- /* Packet length should not greater than FFA supported data length */ -- if (ffa_packet->length > sizeof(ffa_data.data)) { -- ffa_packet->status = 1; -- return -EINVAL; -- } -- -- /* Convert AML UUID to FFA UUID */ -- uuid = nvidia_get_uuid_from_aml_buf((u8 *)ffa_packet->uuid); -- -- mutex_lock(&nvidia_ffa_lock); -- /* Get nvidia_ec_ffa_device for the current UUID */ - list_for_each_entry(cur, &nvidia_ec_ffa_dev_head, list) { - if (uuid_equal(&uuid, &cur->ffa_dev->uuid)) { - ec_dev = cur; - break; - } - } -- mutex_unlock(&nvidia_ffa_lock); - -- if (!ec_dev) { -- ffa_packet->status = 1; -- return -EINVAL; -- } -- -- /* Copy the ACPI FFH packet data into FFA data */ -- memcpy(ffa_data.data, ffa_packet->rawdata, ffa_packet->length); -+ if (!ec_dev) -+ return -ENODEV; - - if (!ec_dev->ffa_dev->ops || - !ec_dev->ffa_dev->ops->msg_ops || -- !ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2) { -+ !ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2) - return -EINVAL; -- } - -- ret = ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2(ec_dev->ffa_dev, -- &ffa_data); -+ memcpy(ffa_data.data, rawdata, input_len); -+ -+ ret = ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2(ec_dev->ffa_dev, &ffa_data); - if (ret) { - dev_err(&ec_dev->ffa_dev->dev, - "Failed to send FFA messages error=%d\n", ret); -- ffa_packet->status = 1; - return ret; - } - -- /* Set the status as success */ -- ffa_packet->status = 0; -+ memcpy(rawdata, ffa_data.data, output_len); -+ return 0; -+} -+ -+/* FFH handler — MSFT000C (FFH offset 4) */ -+static int nvidia_ffh_handler_msft000c(struct acpi_ffh_info *info, acpi_integer *value) -+{ -+ struct nvidia_ec_ffa_packet_msft000c *pkt = (struct nvidia_ec_ffa_packet_msft000c *)value; -+ unsigned int rawdata_buflen, ffh_copy_len; -+ uuid_t uuid; -+ int ret; -+ -+ /* Buffer must fit at least the fixed header */ -+ if (info->length < offsetof(struct nvidia_ec_ffa_packet_msft000c, rawdata)) -+ return -EINVAL; -+ -+ rawdata_buflen = info->length - offsetof(struct nvidia_ec_ffa_packet_msft000c, rawdata); -+ -+ /* Buffer must fit header + declared payload */ -+ if (rawdata_buflen < pkt->length) { -+ pkt->status = 1; -+ return -EINVAL; -+ } -+ -+ /* Payload must fit in the 14 FFA data registers (112 bytes) */ -+ if (pkt->length > sizeof_field(struct ffa_send_direct_data2, data)) { -+ pkt->status = 1; -+ return -EINVAL; -+ } - - /* -- * Copy the ACPI FFA data back into ACPI FFH packet. -- * -- * ACPI FFH packet raw data length can't be fetched here, so copy -- * all bytes from ffa_data.data -+ * MSFT000C responses can be larger than the request, and the FFH -+ * region does not carry a response length. Send pkt->length bytes to -+ * the SP, and copy back as much of the response register file as the -+ * AML buffer can hold, bounded by the 14 FFA data registers (112 -+ * bytes). - */ -- ffh_copy_len = min(sizeof(ffa_data.data), -- info->length - offsetof(struct nvidia_ec_ffa_packet, rawdata)); -+ ffh_copy_len = min(rawdata_buflen, -+ sizeof_field(struct ffa_send_direct_data2, data)); - -- memcpy(ffa_packet->rawdata, ffa_data.data, ffh_copy_len); -- return 0; -+ uuid = nvidia_get_uuid_from_aml_buf(pkt->uuid); -+ ret = nvidia_ffh_do_ffa_send(uuid, pkt->rawdata, pkt->length, -+ ffh_copy_len); -+ pkt->status = ret ? 1 : 0; -+ return ret; -+} -+ -+/* FFH handler — ARML0002 (FFH offset 2) */ -+static int nvidia_ffh_handler_arml0002(struct acpi_ffh_info *info, acpi_integer *value) -+{ -+ struct nvidia_ec_ffa_packet_arml0002 *pkt = (struct nvidia_ec_ffa_packet_arml0002 *)value; -+ unsigned int payload_len; -+ uuid_t uuid; -+ int ret; -+ -+ /* Buffer must fit the fixed header */ -+ if (info->length < offsetof(struct nvidia_ec_ffa_packet_arml0002, rawdata)) -+ return -EINVAL; -+ -+ payload_len = info->length - offsetof(struct nvidia_ec_ffa_packet_arml0002, rawdata); -+ -+ /* Payload must fit in the 14 FFA data registers (112 bytes) */ -+ if (payload_len > sizeof_field(struct ffa_send_direct_data2, data)) { -+ pkt->status = 1; -+ return -EINVAL; -+ } -+ -+ uuid = nvidia_get_uuid_from_aml_buf(pkt->uuid); -+ ret = nvidia_ffh_do_ffa_send(uuid, pkt->rawdata, payload_len, payload_len); -+ pkt->status = ret ? 1 : 0; -+ return ret; -+} -+ -+/* -+ * Dispatch to the correct FFH handler based on the spec version and FFH -+ * operation-region offset. The offset selects the FFA packet layout the -+ * SPMC expects: -+ * ARML0002: offset 2 — struct nvidia_ec_ffa_packet_arml0002 -+ * operation-region defined by ARM DEN0048D "Arm Functional -+ * Fixed Hardware Specification (FFH)" v1.3 section 2.3 -+ * MSFT000C: offset 4 — struct nvidia_ec_ffa_packet_msft000c -+ * operation-region defined by the OpenDevicePartnership -+ * draft (secure-ec-services-overview.md) -+ */ -+static int nvidia_ffh_handler(struct acpi_ffh_info *info, acpi_integer *value, -+ void *region_context) -+{ -+ if (!ffa_ec_legacy_spec && info->offset == 2) -+ return nvidia_ffh_handler_arml0002(info, value); -+ -+ if (ffa_ec_legacy_spec && info->offset == 4) -+ return nvidia_ffh_handler_msft000c(info, value); -+ -+ return -EOPNOTSUPP; - } - - static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) -@@ -612,8 +797,8 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - const char *acpi_id = NULL; - int ret; - -- if (!ffa_pdev || !notify_ffa_dev) { -- dev_err(&ffa_dev->dev, "nvidia ffa or notify device not available\n"); -+ if (!ffa_pdev || !control_ffa_dev) { -+ dev_err(&ffa_dev->dev, "nvidia ffa or control device not available\n"); - return -ENODEV; - } - -@@ -630,9 +815,8 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - - ret = nvidia_ffa_create_notifications(nvidia_ec_ffa_dev); - if (ret) { -- dev_info(&ffa_dev->dev, -- "Failed to create ffa notifications error=%d\n", -- ret); -+ dev_err(&ffa_dev->dev, -+ "Failed to create ffa notifications error=%d\n", ret); - devm_kfree(&ffa_dev->dev, nvidia_ec_ffa_dev); - return ret; - } -@@ -642,16 +826,15 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - mutex_unlock(&nvidia_ffa_lock); - - /* -- * When acpi subsystem probe all ACPI devices, then it execute _STA -+ * When acpi subsystem probes all ACPI devices, it executes _STA - * method for each device. The _STA method fails at that time since -- * custom FFA driver won't be ready. Get ACPI ID from UUID and -+ * the custom FFA driver won't be ready. Get ACPI ID from UUID and - * rescan the device again. - */ - acpi_id = nvidia_get_acpi_id_from_uuid(&ffa_dev->uuid); -- if (acpi_id) { -+ if (acpi_id) - acpi_bus_for_each_dev(nvidia_ffa_rescan_acpi_device, - (void *)acpi_id); -- } - - return 0; - } -@@ -691,7 +874,17 @@ static struct ffa_driver nvidia_ffa_ec_service_driver = { - .id_table = nvidia_ffa_ec_service_ids, - }; - --static int nvidia_ffa_notify_service_probe(struct ffa_device *ffa_dev) -+/* -+ * Unified control-plane service driver. -+ * -+ * The id_table lists both control-plane UUIDs; a given platform's FF-A -+ * bridge only exposes one of them (chosen by the ACPI HID that also -+ * seeds ffa_ec_legacy_spec at parent probe time): -+ * -+ * Whichever device the framework matches, the probe stores it in -+ * control_ffa_dev and registers the shared EC service driver. -+ */ -+static int nvidia_ffa_control_service_probe(struct ffa_device *ffa_dev) - { - int ret; - -@@ -700,47 +893,46 @@ static int nvidia_ffa_notify_service_probe(struct ffa_device *ffa_dev) - return -ENODEV; - } - -- notify_ffa_dev = ffa_dev; -+ if (control_ffa_dev) { -+ dev_err(&ffa_dev->dev, "control FFA device already registered\n"); -+ return -EBUSY; -+ } -+ -+ control_ffa_dev = ffa_dev; - - ret = ffa_driver_register(&nvidia_ffa_ec_service_driver, THIS_MODULE, DRV_NAME); - if (ret) { - dev_err(&ffa_dev->dev, - "Failed to register ec service driver error=%d\n", ret); -- notify_ffa_dev = NULL; -+ control_ffa_dev = NULL; - return ret; - } - - return 0; - } - --static void nvidia_ffa_notify_service_remove(struct ffa_device *ffa_dev) -+static void nvidia_ffa_control_service_remove(struct ffa_device *ffa_dev) - { - ffa_driver_unregister(&nvidia_ffa_ec_service_driver); -- notify_ffa_dev = NULL; -+ control_ffa_dev = NULL; - } - --static const struct ffa_device_id nvidia_ffa_notify_service_ids[] = { -- { nvidia_ec_notify_service_uuid }, -+static const struct ffa_device_id nvidia_ffa_control_service_ids[] = { -+ { nvidia_ec_notify_service_uuid }, /* MSFT000C */ -+ { nvidia_ec_interpartition_setup_uuid }, /* ARML0002 */ - {} - }; - --static struct ffa_driver nvidia_ffa_notify_service_driver = { -- .name = "nvidia-ffa-notify", -- .probe = nvidia_ffa_notify_service_probe, -- .remove = nvidia_ffa_notify_service_remove, -- .id_table = nvidia_ffa_notify_service_ids, -+static struct ffa_driver nvidia_ffa_control_service_driver = { -+ .name = "nvidia-ffa-control", -+ .probe = nvidia_ffa_control_service_probe, -+ .remove = nvidia_ffa_control_service_remove, -+ .id_table = nvidia_ffa_control_service_ids, - }; - - static const struct acpi_device_id nvidia_ffa_device_ids[] = { -- /* -- * Please refer -- * https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#hid-definition -- * where MSFT000C is documented. -- * -- * The _HID 'MSFT000C' is reserved for FFA device which uses -- * FFA interface for secure EC communication. -- */ -- {"MSFT000C", 0}, -+ {"MSFT000C", true}, -+ {"ARML0002", false}, - {"", 0}, - }; - -@@ -748,6 +940,7 @@ MODULE_DEVICE_TABLE(acpi, nvidia_ffa_device_ids); - - static int nvidia_ffa_probe(struct platform_device *pdev) - { -+ const struct acpi_device_id *acpi_id; - struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); - acpi_status status; - unsigned long long data = 0; -@@ -763,6 +956,13 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - return -ENODEV; - } - -+ acpi_id = acpi_match_device(nvidia_ffa_device_ids, &pdev->dev); -+ if (!acpi_id) { -+ dev_err(&pdev->dev, "No matching ACPI device ID\n"); -+ return -ENODEV; -+ } -+ ffa_ec_legacy_spec = acpi_id->driver_data; -+ - status = acpi_evaluate_integer(adev->handle, "AVAL", NULL, &data); - if (ACPI_FAILURE(status)) { - dev_err(&pdev->dev, "Failed to execute AVAL method\n"); -@@ -783,10 +983,11 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - - ffa_pdev = pdev; - -- ret = ffa_driver_register(&nvidia_ffa_notify_service_driver, THIS_MODULE, DRV_NAME); -+ ret = ffa_driver_register(&nvidia_ffa_control_service_driver, -+ THIS_MODULE, DRV_NAME); - if (ret) { - dev_err(&pdev->dev, -- "Failed to register notify service driver error=%d\n", ret); -+ "Failed to register control service driver error=%d\n", ret); - acpi_arm64_ffh_update_custom_offset_handler(NULL); - ffa_pdev = NULL; - return ret; -@@ -797,7 +998,7 @@ static int nvidia_ffa_probe(struct platform_device *pdev) - - static void nvidia_ffa_remove(struct platform_device *pdev) - { -- ffa_driver_unregister(&nvidia_ffa_notify_service_driver); -+ ffa_driver_unregister(&nvidia_ffa_control_service_driver); - ffa_pdev = NULL; - acpi_arm64_ffh_update_custom_offset_handler(NULL); - } -From 0ba2a3343a6df6f151436ee009a1cf96ae4fc2f8 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 3 Jun 2026 12:10:12 +0000 -Subject: [PATCH] NVIDIA: SAUCE: ACPI / firmware / platform: probe ARM FF-A - early before consumer enumeration - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -Several ACPI consumer devices on ARM platforms declare _DEP on the FF-A -bridge device (HID ARML0002 for the DEN0077A v1.3 ALP5 spec or MSFT000C -for the OpenDevicePartnership draft spec) and call into \_SB.FFA0.FFAC -and \_SB.FFA0.AVAL() from their _STA / _DSM methods during ACPI device -enumeration. If the FF-A core driver or the NVIDIA EC vendor driver are -not bound at that point, the FFH operation-region handler is not yet -installed, every FFAC store hits AE_NOT_EXIST, and the consumer method -aborts, leaving those devices in a permanently broken state. - -Four coordinated changes make the FF-A stack available before consumer -ACPI devices are enumerated: - -1. drivers/acpi/scan.c - In acpi_scan_init(), before the full namespace scan - (acpi_bus_scan(ACPI_ROOT_OBJECT)), walk the namespace for both - ARML0002 and MSFT000C and enumerate those devices first using - acpi_get_devices(). A new helper acpi_scan_one_handle_cb() bridges - the acpi_get_devices callback into acpi_bus_scan(); it logs any - acpi_bus_scan() failure with acpi_handle_warn() so a silent - enumeration miss is visible. - - Because the callback runs before acpi_bus_scan(ACPI_ROOT_OBJECT) - has created the \_SB hierarchy, invoking acpi_bus_scan() directly - on the bridge handle would register the device with a NULL / root - parent. acpi_init_device_object() only sets device->dev.parent at - creation, so the later full acpi_bus_scan() would reuse the same - struct acpi_device and never re-parent it, leaving the bridge - outside the standard \_SB hierarchy for the life of the boot. - - Add a small helper acpi_scan_ensure_ancestors() that walks from the - bridge handle up to the ACPI root collecting ancestor handles and - calls acpi_bus_check_add() on each one top-down, so \_SB (and any - intermediate scope such as \_SB.FFA0) has a real struct acpi_device - before acpi_bus_scan() creates the bridge itself. - -2. drivers/firmware/arm_ffa/bus.c - Move the FF-A bus registration from subsys_initcall (level 4) to - arch_initcall (level 3) so the bus exists before any driver - registers FFA devices on it. - -3. drivers/firmware/arm_ffa/driver.c - Move the FF-A core driver initialization from module_init - (device_initcall, level 6) to arch_initcall (level 3) so the FFA - partition list and FFA devices are populated before acpi_init runs - at subsys_initcall (level 4). - -4. drivers/platform/arm64/nvidia-ffa-ec.c - Move the NVIDIA EC vendor driver registration from module_init - (device_initcall, level 6) to arch_initcall (level 3) for the same - reason. NVIDIA_FFA_EC is switched from tristate to bool (with - depends on ARM_FFA_TRANSPORT=y) so that arch_initcall really runs - at level 3 -- for a module it would only be a load-time - initializer, not a level-3 built-in initializer, so with - CONFIG_NVIDIA_FFA_EC=m or CONFIG_ARM_FFA_TRANSPORT=m the early ACPI - scan would enumerate the bridge while the FFH handler is absent. - -With these changes, when acpi_scan_init() enumerates ARML0002 / -MSFT000C early, the FF-A bus + core + NVIDIA EC vendor driver are -already in place, the FFH custom-offset handler is installed, and -subsequent enumeration of consumer ACPI devices succeeds on the first -invocation of their _STA / _DSM methods. - -Note on upstream direction. An earlier upstream change, -commit 0e0546eabcd6 ("firmware: arm_ffa: Change initcall level of -ffa_init() to rootfs_initcall"), moved ffa_init() to rootfs_initcall -to work around an IMA / TPM boot-ordering issue. That workaround was -withdrawn by commit cc7e8f21b9f0 ("Revert "firmware: arm_ffa: Change -initcall level of ffa_init() to rootfs_initcall"") once IMA started -retrying its TPM lookup at late_initcall_sync, and ffa_init() went -back to module_init upstream by design. Our concern here is -different: the FFH region handler must be installed before consumer -ACPI devices under \_SB.FFA0 have their _STA / _DSM evaluated during -the initial acpi_bus_scan(). Neither module_init (level 6) nor -rootfs_initcall (level 5) runs before acpi_init (subsys_initcall, -level 4), so we move ffa_init() (and the -FF-A bus + our vendor driver) to arch_initcall (level 3), the earliest -level at which the transport, bus, and vendor driver can all be -present before namespace enumeration. This is a SAUCE change contained -to the downstream tree; a future upstream submission of this driver in -a vendor-neutral form is expected to have a different approach. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/acpi/scan.c | 72 ++++++++++++++++++++++++++ - drivers/firmware/arm_ffa/bus.c | 2 +- - drivers/firmware/arm_ffa/driver.c | 3 +- - drivers/platform/arm64/Kconfig | 6 +-- - drivers/platform/arm64/nvidia-ffa-ec.c | 2 +- - 5 files changed, 78 insertions(+), 7 deletions(-) - -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 6e47d160ef..e3aa2232ad 100644 ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -2820,6 +2820,70 @@ static void __init acpi_get_spcr_uart_addr(void) - - static bool acpi_scan_initialized; - -+/* -+ * Maximum ACPI scope depth for which pre-created ancestor -+ * struct acpi_devices are supported when early-enumerating a device -+ * before the full acpi_bus_scan(ACPI_ROOT_OBJECT). -+ */ -+#define ACPI_SCAN_EARLY_ANCESTOR_MAX 8 -+ -+/* -+ * Ensure a struct acpi_device exists for every ancestor scope of -+ * @handle up to the ACPI root. -+ * -+ * Walk from @handle up collecting ancestor handles, then -+ * acpi_bus_check_add() each one top-down so every level has a real -+ * struct acpi_device before @handle itself is scanned. -+ */ -+static acpi_status __init acpi_scan_ensure_ancestors(acpi_handle handle) -+{ -+ acpi_handle chain[ACPI_SCAN_EARLY_ANCESTOR_MAX]; -+ acpi_handle cur = handle; -+ int n = 0; -+ -+ while (ACPI_SUCCESS(acpi_get_parent(cur, &cur))) { -+ if (cur == ACPI_ROOT_OBJECT) -+ break; -+ if (n >= ARRAY_SIZE(chain)) -+ return AE_LIMIT; -+ chain[n++] = cur; -+ } -+ -+ while (--n >= 0) { -+ struct acpi_device *adev = NULL; -+ acpi_status status; -+ -+ if (acpi_fetch_acpi_dev(chain[n])) -+ continue; -+ status = acpi_bus_check_add(chain[n], true, &adev); -+ if (ACPI_FAILURE(status)) -+ return status; -+ } -+ -+ return AE_OK; -+} -+ -+static acpi_status __init acpi_scan_one_handle_cb(acpi_handle handle, u32 level, -+ void *context, void **ret) -+{ -+ acpi_status status; -+ int err; -+ -+ status = acpi_scan_ensure_ancestors(handle); -+ if (ACPI_FAILURE(status)) { -+ acpi_handle_warn(handle, -+ "early ACPI ancestor scan failed: %d; skipping early bus scan\n", -+ status); -+ return AE_OK; -+ } -+ -+ err = acpi_bus_scan(handle); -+ if (err) -+ acpi_handle_warn(handle, "early ACPI bus scan failed: %d\n", err); -+ -+ return AE_OK; -+} -+ - void __init acpi_scan_init(void) - { - acpi_status status; -@@ -2867,6 +2931,14 @@ void __init acpi_scan_init(void) - * hotplug/hotunplug operations. - */ - mutex_lock(&acpi_scan_lock); -+ -+ /* -+ * Enumerate the ARM FF-A EC bridge devices before the full namespace scan -+ * so that they are available early for ACPI consumers that depend on them. -+ */ -+ acpi_get_devices("ARML0002", acpi_scan_one_handle_cb, NULL, NULL); -+ acpi_get_devices("MSFT000C", acpi_scan_one_handle_cb, NULL, NULL); -+ - /* - * Enumerate devices in the ACPI namespace. - */ -diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c -index 4df5c3b3fe..8879bc159b 100644 ---- a/drivers/firmware/arm_ffa/bus.c -+++ b/drivers/firmware/arm_ffa/bus.c -@@ -249,7 +249,7 @@ static int __init arm_ffa_bus_init(void) - { - return bus_register(&ffa_bus_type); - } --subsys_initcall(arm_ffa_bus_init); -+arch_initcall(arm_ffa_bus_init); - - static void __exit arm_ffa_bus_exit(void) - { -diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c -index 8654b3365c..6701526283 100644 ---- a/drivers/firmware/arm_ffa/driver.c -+++ b/drivers/firmware/arm_ffa/driver.c -@@ -2207,7 +2207,6 @@ static int ffa_probe(struct platform_device *pdev) - drv_info = NULL; - return ret; - } -- - static void ffa_remove(struct platform_device *pdev) - { - struct ffa_drv_info *info = platform_get_drvdata(pdev); -@@ -2246,7 +2245,7 @@ static int __init ffa_init(void) - - return ret; - } --module_init(ffa_init); -+arch_initcall(ffa_init); - - static void __exit ffa_exit(void) - { -diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig -index 690699b02e..857f2c41ef 100644 ---- a/drivers/platform/arm64/Kconfig -+++ b/drivers/platform/arm64/Kconfig -@@ -104,8 +104,8 @@ config EC_QCOM_HAMOA - This driver currently supports Hamoa/Purwa/Glymur reference devices. - - config NVIDIA_FFA_EC -- tristate "NVIDIA FFA EC services driver" -- depends on ARM_FFA_TRANSPORT || COMPILE_TEST -+ bool "NVIDIA FFA EC services driver" -+ depends on ARM_FFA_TRANSPORT=y || COMPILE_TEST - depends on ACPI - depends on ACPI_FFH - help -@@ -114,6 +114,6 @@ config NVIDIA_FFA_EC - specification is being defined. It is currently in draft stage and maintained in - https://github.com/OpenDevicePartnership/documentation/blob/main/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md - -- Say M or Y here to include this support. -+ Say Y here to include this support. - - endif # ARM64_PLATFORM_DEVICES -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 24cb53bdd2..a0c81193e2 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -1016,7 +1016,7 @@ static int __init nvidia_ffa_init(void) - { - return platform_driver_register(&nvidia_ffa_driver); - } --module_init(nvidia_ffa_init); -+arch_initcall(nvidia_ffa_init); - - static void __exit nvidia_ffa_exit(void) - { -From 68785c70d88b29aed82cc8bd482ab2bc30cbc64b Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 3 Jun 2026 11:24:06 +0000 -Subject: [PATCH] NVIDIA: SAUCE: ACPI: scan: add FF-A bridge HIDs to - acpi_ignore_dep_ids[] - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -ARM FF-A EC service consumers declare _DEP on the FF-A bridge device, -with HID ARML0002 for the DEN0077A v1.3 ALP5 spec, or MSFT000C for the -OpenDevicePartnership draft spec. Without ignoring these HIDs the -consumers accumulate dep_unmet >= 1 forever and never probe, for two -reasons: - -1. The FF-A bridge driver is a plain platform driver, not an ACPI - scan-handler. Only ACPI scan-handlers are hooked into the - enumeration loop's acpi_dev_clear_dependencies() path, so when the - bridge driver successfully probes nothing decrements the dep_unmet - counter on its consumers. - -2. The companion patch in this series moves the FF-A bus, core, and - NVIDIA EC vendor drivers to arch_initcall and enumerates the - ARML0002 / MSFT000C platform devices before the namespace scan. At - that point no consumer ACPI device has been scanned yet, so even - an explicit acpi_dev_clear_dependencies() call from the bridge - would walk an empty consumer list. The dep entries on the consumers - are created later, during acpi_scan_add_dep(), with no remaining - opportunity to clear them. - -The clean fix is to skip the _DEP entry creation entirely. Add both -HIDs to acpi_ignore_dep_ids[] so the FF-A bridge dep is not tracked, -and consumers can probe as soon as their other dependencies (if any) -are satisfied. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/acpi/scan.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index e3aa2232ad..2119bd4f79 100644 ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -849,6 +849,8 @@ static const char * const acpi_ignore_dep_ids[] = { - "PNP0D80", /* Windows-compatible System Power Management Controller */ - "INT33BD", /* Intel Baytrail Mailbox Device */ - "LATT2021", /* Lattice FW Update Client Driver */ -+ "ARML0002", /* ARM FF-A EC services bridge (DEN0077A) */ -+ "MSFT000C", /* OpenDevicePartnership FF-A EC services bridge */ - NULL - }; - -From ced827c6d804cee55f491f70af1079d0a5846c7a Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 27 May 2026 07:17:14 +0000 -Subject: [PATCH] NVIDIA: SAUCE: ACPI: battery: clear consumer dependencies - after successful probe - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -Some platforms declare _DEP on a battery device for unrelated -consumers. On those systems the consumer driver's probe keeps -returning -EPROBE_DEFER because adev->dep_unmet for the consumer -never drops to zero. - -acpi_dev_clear_dependencies() walks the consumer list and decrements -each consumer's dep_unmet counter. The ACPI core invokes it -automatically for ACPI scan handlers via acpi_scan_attach_handler(), -but a provider that ships as a platform_driver has to call it -explicitly from its probe path -- there is no acpi_scan_handler and -no .attach where the core could do it on the provider's behalf. This -battery driver is registered as a platform_driver whose -acpi_battery_probe() does not do that today, so a successful battery -probe currently leaves consumer dependencies pending forever. - -Call acpi_dev_clear_dependencies() at the end of acpi_battery_probe() -when initialization has succeeded, so any device that legitimately -depends on the battery can finish enumerating. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/acpi/battery.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - -diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c -index f8fa0d9a1f..ee11ca65e8 100644 ---- a/drivers/acpi/battery.c -+++ b/drivers/acpi/battery.c -@@ -1337,7 +1337,20 @@ static int acpi_battery_probe(struct platform_device *pdev) - return result; - - battery->pm_nb.notifier_call = battery_notify; -- return register_pm_notifier(&battery->pm_nb); -+ result = register_pm_notifier(&battery->pm_nb); -+ if (result) -+ return result; -+ -+ /* -+ * Some platforms declare _DEP on a battery device for unrelated -+ * consumers. This driver is registered as a platform_driver whose -+ * .probe path does not auto-clear consumer dep_unmet counters on -+ * success, so do it explicitly here to allow those consumers to -+ * probe once the battery is up. -+ */ -+ acpi_dev_clear_dependencies(device); -+ -+ return 0; - } - - static void acpi_battery_remove(struct platform_device *pdev) -From 66ab6b34a01eaffffed58298a5a5662f96d1d5b2 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 3 Jun 2026 12:35:46 +0000 -Subject: [PATCH] NVIDIA: SAUCE: platform/arm64: nvidia-ffa-ec: map AML cookies - to physical FFA notification IDs - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -The previous implementation conflated the AML cookie value (read from -the ACPI _DSD "arm-arml0002-ffa-ntf-bind" property) with the physical -FFA notification ID (the 0..63 bitmap position registered with the FFA -framework via notify_request). - -This worked accidentally on GB10 platforms where every AML cookie -value happened to be < 64, but it is wrong in general: - - * AML cookies are u32 values defined by firmware and can exceed the - FFA framework's 6-bit notification ID space. - * Two services that happen to use the same low cookie value would - collide in the FFA framework, causing one of the notify_request - calls to fail. - * When a notification fires, the FFA framework only knows the - physical notification ID; the AML _DSM Function 1 (notify) expects - the cookie that was declared in _DSD. - -Decouple the two: - - * Introduce struct nvidia_ec_notification { u32 cookie; u8 notif_id; } - and replace the bare u8 notification_id[] array with an array of - these pairs. - - * Add a global DECLARE_BITMAP(nvidia_ffa_notif_id_map, - NVIDIA_FFA_MAX_NOTIFICATIONS) used to hand out physical - notification IDs for ARML0002 across all EC services. A free bit - is picked with find_first_zero_bit() and set with set_bit() under - nvidia_ffa_lock; the bit is released with clear_bit() at every - notify_relinquish() site (create-time rollback and remove) so - repeated probe/remove cycles do not exhaust the 0..63 range. - - For MSFT000C the older draft-spec firmware rejects NOTIFY_SETUP - when the upper and lower halves of X8 differ, so the cookie itself - is used as the physical notif_id and the bitmap is bypassed; the - AML-declared cookie must fit in the FFA framework's 6-bit - notification ID space. - - * In nvidia_ffa_create_notifications(): for ARML0002 allocate the - next free physical notif_id from the bitmap under the lock; for - MSFT000C set notif_id = cookie. Store both the cookie (from _DSD) - and the assigned notif_id in the device's notifications[] array, - and pass both to the setup helpers. - - * Update nvidia_ffa_notification_setup_msft000c() and - nvidia_ffa_notification_setup_arml0002() to encode cookie in the - upper 32 bits and physical notif_id in the lower bits of the - notification-setup register field (X8 for MSFT000C, X11 for - ARML0002 with the spec's bits[31:23] placement). - -Refcount the per-service state so lookup + use in the FFH send helper -and the notification callback can straddle nvidia_ffa_lock safely. -The mutex is dropped before both slow paths, but for different reasons: - - * acpi_evaluate_dsm() (invoked from the notification callback) runs - AML that stores into FFAC, which triggers our own FFH region - handler on the same CPU and re-enters nvidia_ffh_do_ffa_send(). - Holding nvidia_ffa_lock across acpi_evaluate_dsm() would deadlock - the caller against itself on the non-recursive mutex. - - * sync_send_receive2() (invoked from nvidia_ffh_do_ffa_send() for - the FFA_MSG_SEND_DIRECT_REQ2 fastcall) does not touch ACPI, but - it can block for an unbounded time inside - ffa_msg_send_wait_for_completion() on the FFA_INTERRUPT / FFA_RUN - loop while the SP runs. Holding a driver-global mutex across that - loop would stall the notification kworker (and every other FFH - consumer) for arbitrarily long, and would risk cross-thread - deadlock against callbacks that themselves take nvidia_ffa_lock - from acpi_evaluate_dsm(). - -So this patch drops the mutex before entering -the slow path and uses a kref to keep ec_ffa_dev alive across it. - -Instead: - - * Add struct kref refcnt to nvidia_ec_ffa_device with a kfree-based - release, and allocate with kzalloc/kfree instead of devm_kzalloc - so the lifetime is decoupled from the ffa_device devm resource - ordering. - - * kref_init at probe before publishing on the global list; drop this - reference in nvidia_ffa_ec_service_remove() after list_del, and in - the probe-failure unwind path after list_del. - - * nvidia_ffh_do_ffa_send(): kref_get inside the list walk under - nvidia_ffa_lock, drop the mutex, do the FFA send, and kref_put at - return via a common out_put label. This closes the UAF window - where nvidia_ffa_ec_service_remove() could free ec_dev between - the mutex drop and the sync_send_receive2() dereference. Pin the - underlying struct ffa_device with get_device() under the same lock - and put_device() at out_put ahead of the kref_put -- the driver's - kref only keeps nvidia_ec_ffa_device alive; without the device - reference the framework could release the ffa_device out from under - ec_dev->ffa_dev after .remove returns, and sync_send_receive2() - would then dereference freed memory. - - * Pass ffa_dev as the notify_request cb_data. The FF-A core drains - its own object lifetime -- ffa_notifications_cleanup() calls - destroy_workqueue() on the pcpu notification workqueue before - ffa_partitions_cleanup() frees ffa_devices -- so a callback the - framework snapshotted before we relinquished always sees a valid - ffa_dev. In nvidia_ffa_ec_service_notif_callback(), resolve - ffa_dev to nvidia_ec_ffa_device by list walk under - nvidia_ffa_lock, which is also held around list_del in both the - remove path and the probe-failure unwind path, so the walk either - finds a live entry (pinned via kref for the _DSM duration) or - finds nothing. On lookup miss (removal or unwind has already run - for this service) skip the _DSM invocation rather than fabricate - a cookie for firmware. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 296 +++++++++++++++++++------ - 1 file changed, 227 insertions(+), 69 deletions(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index a0c81193e2..d91e8f9c30 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -4,12 +4,13 @@ - */ - - #include --#include - #include - #include - #include - #include -+#include - #include -+#include - - #define DRV_NAME "nvidia-ffa-ec" - -@@ -105,20 +106,53 @@ static const guid_t nvidia_notify_dsm_guid = - /* Message info field: bits[2:0] = 0b010 means notification registration */ - #define NVIDIA_EC_INTERPARTITION_MSG_NOTIF_REG 0x2 - -+/* -+ * Per-notification mapping: a cookie from ACPI _DSD paired with the -+ * physical notification ID (0-63) registered with the FFA framework. -+ * -+ * For ARML0002 notif_id is allocated from the global bitmap -+ * nvidia_ffa_notif_id_map. For the legacy MSFT000C path notif_id is -+ * derived directly from the AML cookie (which must already fit in the -+ * 6-bit notification ID space), and the bitmap is bypassed. -+ */ -+struct nvidia_ec_notification { -+ u32 cookie; /* cookie value from ACPI _DSD property */ -+ u8 notif_id; /* physical notification ID (0-63) */ -+}; -+ - /* EC service FFA device structure */ - struct nvidia_ec_ffa_device { - struct ffa_device *ffa_dev; -+ struct kref refcnt; - u8 notification_count; -- u8 notification_id[NVIDIA_FFA_MAX_NOTIFICATIONS]; -+ struct nvidia_ec_notification notifications[NVIDIA_FFA_MAX_NOTIFICATIONS]; - struct list_head list; - }; - -+static void nvidia_ec_ffa_device_release(struct kref *kref) -+{ -+ struct nvidia_ec_ffa_device *ec_ffa_dev = -+ container_of(kref, struct nvidia_ec_ffa_device, refcnt); -+ -+ kfree(ec_ffa_dev); -+} -+ - /* List to contain all EC services FFA device */ - static LIST_HEAD(nvidia_ec_ffa_dev_head); - - /* Lock to serialize EC services FFA device list access */ - static DEFINE_MUTEX(nvidia_ffa_lock); - -+/* -+ * Bitmap of allocated physical notification IDs (0-63), shared across -+ * all ARML0002 EC services. Allocation uses find_first_zero_bit() -+ * followed by set_bit() and must run under nvidia_ffa_lock so the -+ * find-then-set pair is atomic against concurrent allocators. Release -+ * uses clear_bit(), which is atomic on its own and runs without -+ * nvidia_ffa_lock. -+ */ -+static DECLARE_BITMAP(nvidia_ffa_notif_id_map, NVIDIA_FFA_MAX_NOTIFICATIONS); -+ - /* - * EC secure services FFA packet structure — MSFT000C (FFH offset 4). - * https://github.com/OpenDevicePartnership/documentation/blob/0f7b6bad77a3eb07b66b66d0e3af718db2ec1c24/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#operation-region-definition -@@ -352,7 +386,7 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - /* - * Traverse the array of notification map packages. Each entry has a - * UUID and a package of cookie integers. Match UUID against the FFA -- * device and populate notification_id[]. -+ * device and populate notifications[].cookie. - */ - for (i = 2; i < pkg4->package.count; i++) { - union acpi_object *pkg5_uuid, *pkg5 = &pkg4->package.elements[i]; -@@ -379,6 +413,16 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - if (!uuid_equal(&uuid, &ec_ffa_dev->ffa_dev->uuid)) - continue; - -+ /* -+ * Reject firmware _DSD that declares more cookies than the -+ * fixed-size notifications[] array can hold, before storing -+ * any of them. -+ */ -+ if (pkg6->package.count > NVIDIA_FFA_MAX_NOTIFICATIONS) { -+ kfree(output.pointer); -+ return -E2BIG; -+ } -+ - for (j = 0; j < pkg6->package.count; j++) { - union acpi_object *pkg6_notify_id = &pkg6->package.elements[j]; - -@@ -387,7 +431,14 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - return -EINVAL; - } - -- ec_ffa_dev->notification_id[j] = pkg6_notify_id->integer.value; -+ /* Cookie is u32 in _DSD; reject out-of-range firmware values. */ -+ if (pkg6_notify_id->integer.value > U32_MAX) { -+ kfree(output.pointer); -+ return -ERANGE; -+ } -+ -+ ec_ffa_dev->notifications[j].cookie = -+ (u32)pkg6_notify_id->integer.value; - } - - ec_ffa_dev->notification_count = pkg6->package.count; -@@ -401,25 +452,67 @@ static int nvidia_ffa_fill_notification_map(struct nvidia_ec_ffa_device *ec_ffa_ - - /* - * Notification EC service callback. -- * Get the ffa device from callback data and invoke notification _DSM with -- * notify_id. -+ * -+ * notify_id is the physical notification ID (bit position, 0-63) registered -+ * with notify_request. cb_data is the ffa_device * passed to notify_request; -+ * its lifetime is drained by the FF-A core (ffa_notifications_cleanup() -+ * flushes the pcpu notification workqueue before ffa_partitions_cleanup() -+ * frees ffa_devices), so it is safe to dereference here. -+ * -+ * Resolve cb_data to our per-service nvidia_ec_ffa_device under -+ * nvidia_ffa_lock, which is also held around list_del in both the remove -+ * and probe-failure-unwind paths (the final kref_put runs outside the -+ * mutex). The list walk either finds a live entry, in which case a kref -+ * is taken for the _DSM duration, or finds nothing because list_del has -+ * already run. On lookup miss skip the _DSM invocation entirely rather -+ * than fabricate a cookie for firmware. - */ - static void nvidia_ffa_ec_service_notif_callback(int notify_id, void *cb_data) - { -- struct acpi_device *adev = ACPI_COMPANION(&ffa_pdev->dev); -- struct ffa_device *ffa_dev = (struct ffa_device *)cb_data; -+ struct acpi_device *adev; -+ struct ffa_device *ffa_dev = cb_data; -+ struct nvidia_ec_ffa_device *cur, *ec_ffa_dev = NULL; - union acpi_object args[2], input_pkg; -- union acpi_object *output; -+ union acpi_object *output; -+ u32 cookie = 0; - u8 uuid[UUID_SIZE]; -+ int i; - -- nvidia_uuid_to_aml_uuid_buf(&ffa_dev->uuid, uuid); -+ if (!ffa_pdev) -+ return; -+ -+ adev = ACPI_COMPANION(&ffa_pdev->dev); -+ if (!adev) -+ return; -+ -+ mutex_lock(&nvidia_ffa_lock); -+ list_for_each_entry(cur, &nvidia_ec_ffa_dev_head, list) { -+ if (cur->ffa_dev != ffa_dev) -+ continue; -+ -+ for (i = 0; i < cur->notification_count; i++) { -+ if (cur->notifications[i].notif_id != (u8)notify_id) -+ continue; -+ cookie = cur->notifications[i].cookie; -+ ec_ffa_dev = cur; -+ kref_get(&ec_ffa_dev->refcnt); -+ break; -+ } -+ break; -+ } -+ mutex_unlock(&nvidia_ffa_lock); -+ -+ if (!ec_ffa_dev) -+ return; -+ -+ nvidia_uuid_to_aml_uuid_buf(&ec_ffa_dev->ffa_dev->uuid, uuid); - - args[0].type = ACPI_TYPE_BUFFER; - args[0].buffer.length = sizeof(uuid); - args[0].buffer.pointer = uuid; - - args[1].type = ACPI_TYPE_INTEGER; -- args[1].integer.value = notify_id; -+ args[1].integer.value = cookie; - - input_pkg.type = ACPI_TYPE_PACKAGE; - input_pkg.package.count = 2; -@@ -431,6 +524,8 @@ static void nvidia_ffa_ec_service_notif_callback(int notify_id, void *cb_data) - dev_err(&ffa_pdev->dev, "Failed to execute notify\n"); - else - ACPI_FREE(output); -+ -+ kref_put(&ec_ffa_dev->refcnt, nvidia_ec_ffa_device_release); - } - - /* -@@ -440,7 +535,7 @@ static void nvidia_ffa_ec_service_notif_callback(int notify_id, void *cb_data) - * https://github.com/OpenDevicePartnership/documentation/blob/0f7b6bad77a3eb07b66b66d0e3af718db2ec1c24/bookshelf/Shelf%204%20Specifications/EC%20Interface/src/secure-ec-services-overview.md#register-notification - */ - static int nvidia_ffa_notification_setup_msft000c(struct nvidia_ec_ffa_device *ec_ffa_dev, -- u8 notification_id) -+ u32 cookie, u8 notif_id) - { - struct ffa_send_direct_data2 ffa_data = { 0 }; - u8 *uuid = (u8 *)&ec_ffa_dev->ffa_dev->uuid; -@@ -459,8 +554,8 @@ static int nvidia_ffa_notification_setup_msft000c(struct nvidia_ec_ffa_device *e - /* X7: number of notification mappings */ - ffa_data.data[3] = 1; - -- /* X8: notification ID used as both cookie and bitmap bit number */ -- ffa_data.data[4] = ((u64)notification_id << 32) | notification_id; -+ /* X8: cookie in upper 32 bits, physical notification ID in lower 32 bits */ -+ ffa_data.data[4] = ((u64)cookie << 32) | notif_id; - - if (!control_ffa_dev->ops || - !control_ffa_dev->ops->msg_ops || -@@ -471,15 +566,15 @@ static int nvidia_ffa_notification_setup_msft000c(struct nvidia_ec_ffa_device *e - &ffa_data); - if (ret) { - dev_err(&ec_ffa_dev->ffa_dev->dev, -- "Failed to send NOTIFY_SETUP id=%d error=%d\n", -- notification_id, ret); -+ "Failed to send NOTIFY_SETUP cookie=%u notif_id=%u error=%d\n", -+ cookie, notif_id, ret); - return ret; - } - - if (ffa_data.data[0]) { - dev_err(&ec_ffa_dev->ffa_dev->dev, -- "NOTIFY_SETUP returned failure id=%d error=%ld\n", -- notification_id, ffa_data.data[0]); -+ "NOTIFY_SETUP returned failure cookie=%u notif_id=%u error=%ld\n", -+ cookie, notif_id, ffa_data.data[0]); - - /* - * TODO: destroy operation is not yet implemented in the firmware -@@ -497,7 +592,7 @@ static int nvidia_ffa_notification_setup_msft000c(struct nvidia_ec_ffa_device *e - * Uses the inter-partition setup protocol UUID. - */ - static int nvidia_ffa_notification_setup_arml0002(struct nvidia_ec_ffa_device *ec_ffa_dev, -- u8 notification_id) -+ u32 cookie, u8 notif_id) - { - struct ffa_send_direct_data2 ffa_data = { 0 }; - u8 *svc_uuid = (u8 *)&ec_ffa_dev->ffa_dev->uuid; -@@ -518,8 +613,8 @@ static int nvidia_ffa_notification_setup_arml0002(struct nvidia_ec_ffa_device *e - /* X10: one tuple */ - ffa_data.data[6] = 1; - -- /* X11: tuple — cookie = notification_id, bitmap position = notification_id */ -- ffa_data.data[7] = NVIDIA_EC_NOTIF_TUPLE(notification_id, notification_id); -+ /* X11: cookie in upper 32 bits, physical notification ID in bits[31:23] */ -+ ffa_data.data[7] = NVIDIA_EC_NOTIF_TUPLE(cookie, notif_id); - - if (!control_ffa_dev->ops || - !control_ffa_dev->ops->msg_ops || -@@ -530,8 +625,8 @@ static int nvidia_ffa_notification_setup_arml0002(struct nvidia_ec_ffa_device *e - &ffa_data); - if (ret) { - dev_err(&ec_ffa_dev->ffa_dev->dev, -- "Failed to send NOTIFY_SETUP id=%d error=%d\n", -- notification_id, ret); -+ "Failed to send NOTIFY_SETUP cookie=%u notif_id=%u error=%d\n", -+ cookie, notif_id, ret); - return ret; - } - -@@ -541,8 +636,8 @@ static int nvidia_ffa_notification_setup_arml0002(struct nvidia_ec_ffa_device *e - */ - if (ffa_data.data[6] & 0xff) { - dev_err(&ec_ffa_dev->ffa_dev->dev, -- "NOTIFY_SETUP returned failure id=%d status=0x%02lx\n", -- notification_id, ffa_data.data[6] & 0xff); -+ "NOTIFY_SETUP returned failure cookie=%u notif_id=%u status=0x%02lx\n", -+ cookie, notif_id, ffa_data.data[6] & 0xff); - return -EIO; - } - -@@ -550,17 +645,17 @@ static int nvidia_ffa_notification_setup_arml0002(struct nvidia_ec_ffa_device *e - } - - static int nvidia_ffa_notification_setup(struct nvidia_ec_ffa_device *ec_ffa_dev, -- u8 notification_id) -+ u32 cookie, u8 notif_id) - { - if (!ffa_ec_legacy_spec) -- return nvidia_ffa_notification_setup_arml0002(ec_ffa_dev, notification_id); -+ return nvidia_ffa_notification_setup_arml0002(ec_ffa_dev, cookie, notif_id); - -- return nvidia_ffa_notification_setup_msft000c(ec_ffa_dev, notification_id); -+ return nvidia_ffa_notification_setup_msft000c(ec_ffa_dev, cookie, notif_id); - } - --/* Destroy notification setup for the notification_id */ -+/* Destroy notification setup for the given physical notification ID */ - static void nvidia_ffa_notification_destroy(struct nvidia_ec_ffa_device *ec_ffa_dev, -- u8 notification_id) -+ u8 notif_id) - { - /* - * TODO: destroy operation is not yet implemented in the firmware. -@@ -593,39 +688,85 @@ static int nvidia_ffa_create_notifications(struct nvidia_ec_ffa_device *ec_ffa_d - } - - for (i = 0; i < ec_ffa_dev->notification_count; i++) { -- ret = nvidia_ffa_notification_setup(ec_ffa_dev, -- ec_ffa_dev->notification_id[i]); -+ struct nvidia_ec_notification *n = &ec_ffa_dev->notifications[i]; -+ -+ if (ffa_ec_legacy_spec) { -+ /* -+ * MSFT000C (draft spec) firmware predates the -+ * cookie/notif_id split and rejects NOTIFY_SETUP when -+ * the two halves of X8 differ. Use the cookie itself -+ * as the physical notification ID; the AML-declared -+ * cookie must fit in the FFA framework's 6-bit -+ * notification ID space. -+ */ -+ if (n->cookie >= NVIDIA_FFA_MAX_NOTIFICATIONS) { -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "MSFT000C cookie=%u exceeds notification ID range\n", -+ n->cookie); -+ ret = -EINVAL; -+ break; -+ } -+ n->notif_id = (u8)n->cookie; -+ } else { -+ /* -+ * ARML0002: allocate a free physical notification ID -+ * from the global bitmap. -+ */ -+ unsigned int id; -+ -+ mutex_lock(&nvidia_ffa_lock); -+ id = find_first_zero_bit(nvidia_ffa_notif_id_map, -+ NVIDIA_FFA_MAX_NOTIFICATIONS); -+ if (id >= NVIDIA_FFA_MAX_NOTIFICATIONS) { -+ mutex_unlock(&nvidia_ffa_lock); -+ dev_err(&ec_ffa_dev->ffa_dev->dev, -+ "No free notification IDs (cookie=%u)\n", -+ n->cookie); -+ ret = -ENOSPC; -+ break; -+ } -+ set_bit(id, nvidia_ffa_notif_id_map); -+ n->notif_id = (u8)id; -+ mutex_unlock(&nvidia_ffa_lock); -+ } -+ -+ ret = nvidia_ffa_notification_setup(ec_ffa_dev, n->cookie, n->notif_id); - if (ret) { - dev_err(&ec_ffa_dev->ffa_dev->dev, -- "Failed to setup notification id=%d error=%d\n", -- ec_ffa_dev->notification_id[i], ret); -+ "Failed to setup notification cookie=%u notif_id=%u error=%d\n", -+ n->cookie, n->notif_id, ret); -+ if (!ffa_ec_legacy_spec) -+ clear_bit(n->notif_id, nvidia_ffa_notif_id_map); - break; - } - - ret = ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_request( - ec_ffa_dev->ffa_dev, false, - nvidia_ffa_ec_service_notif_callback, -- ec_ffa_dev->ffa_dev, ec_ffa_dev->notification_id[i]); -+ ec_ffa_dev->ffa_dev, n->notif_id); - if (ret) { -- nvidia_ffa_notification_destroy(ec_ffa_dev, -- ec_ffa_dev->notification_id[i]); -+ nvidia_ffa_notification_destroy(ec_ffa_dev, n->notif_id); -+ if (!ffa_ec_legacy_spec) -+ clear_bit(n->notif_id, nvidia_ffa_notif_id_map); - dev_err(&ec_ffa_dev->ffa_dev->dev, -- "Failed to request notification id=%d error=%d\n", -- ec_ffa_dev->notification_id[i], ret); -+ "Failed to request notification cookie=%u notif_id=%u error=%d\n", -+ n->cookie, n->notif_id, ret); - break; - } - } - -- /* Remove already setup notification in case of error */ -+ /* Remove already setup notifications in case of error */ - if (ret) { - int j; - - for (j = 0; j < i; j++) { -+ struct nvidia_ec_notification *n = &ec_ffa_dev->notifications[j]; -+ - ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_relinquish( -- ec_ffa_dev->ffa_dev, -- ec_ffa_dev->notification_id[j]); -- nvidia_ffa_notification_destroy(ec_ffa_dev, -- ec_ffa_dev->notification_id[j]); -+ ec_ffa_dev->ffa_dev, n->notif_id); -+ if (!ffa_ec_legacy_spec) -+ clear_bit(n->notif_id, nvidia_ffa_notif_id_map); -+ nvidia_ffa_notification_destroy(ec_ffa_dev, n->notif_id); - } - - ec_ffa_dev->notification_count = 0; -@@ -640,11 +781,13 @@ static void nvidia_ffa_remove_notifications(struct nvidia_ec_ffa_device *ec_ffa_ - int i; - - for (i = 0; i < ec_ffa_dev->notification_count; i++) { -+ struct nvidia_ec_notification *n = &ec_ffa_dev->notifications[i]; -+ - ec_ffa_dev->ffa_dev->ops->notifier_ops->notify_relinquish( -- ec_ffa_dev->ffa_dev, -- ec_ffa_dev->notification_id[i]); -- nvidia_ffa_notification_destroy(ec_ffa_dev, -- ec_ffa_dev->notification_id[i]); -+ ec_ffa_dev->ffa_dev, n->notif_id); -+ if (!ffa_ec_legacy_spec) -+ clear_bit(n->notif_id, nvidia_ffa_notif_id_map); -+ nvidia_ffa_notification_destroy(ec_ffa_dev, n->notif_id); - } - } - -@@ -664,27 +807,26 @@ static int nvidia_ffh_do_ffa_send(uuid_t uuid, u8 *rawdata, - struct nvidia_ec_ffa_device *cur, *ec_dev = NULL; - int ret; - -- /* -- * Hold nvidia_ffa_lock across the whole lookup + send so ec_dev -- * cannot be freed by a concurrent nvidia_ffa_ec_service_remove() -- * while its ->ffa_dev is still being dereferenced here. -- */ -- guard(mutex)(&nvidia_ffa_lock); -- -+ mutex_lock(&nvidia_ffa_lock); - list_for_each_entry(cur, &nvidia_ec_ffa_dev_head, list) { - if (uuid_equal(&uuid, &cur->ffa_dev->uuid)) { - ec_dev = cur; -+ kref_get(&ec_dev->refcnt); -+ get_device(&ec_dev->ffa_dev->dev); - break; - } - } -+ mutex_unlock(&nvidia_ffa_lock); - - if (!ec_dev) - return -ENODEV; - - if (!ec_dev->ffa_dev->ops || - !ec_dev->ffa_dev->ops->msg_ops || -- !ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2) -- return -EINVAL; -+ !ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2) { -+ ret = -EINVAL; -+ goto out_put; -+ } - - memcpy(ffa_data.data, rawdata, input_len); - -@@ -692,11 +834,16 @@ static int nvidia_ffh_do_ffa_send(uuid_t uuid, u8 *rawdata, - if (ret) { - dev_err(&ec_dev->ffa_dev->dev, - "Failed to send FFA messages error=%d\n", ret); -- return ret; -+ goto out_put; - } - - memcpy(rawdata, ffa_data.data, output_len); -- return 0; -+ ret = 0; -+ -+out_put: -+ put_device(&ec_dev->ffa_dev->dev); -+ kref_put(&ec_dev->refcnt, nvidia_ec_ffa_device_release); -+ return ret; - } - - /* FFH handler — MSFT000C (FFH offset 4) */ -@@ -802,29 +949,39 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - return -ENODEV; - } - -- nvidia_ec_ffa_dev = devm_kzalloc(&ffa_dev->dev, -- sizeof(*nvidia_ec_ffa_dev), -- GFP_KERNEL); -+ nvidia_ec_ffa_dev = kzalloc(sizeof(*nvidia_ec_ffa_dev), GFP_KERNEL); - if (!nvidia_ec_ffa_dev) { - dev_err(&ffa_dev->dev, "Failed to allocate memory\n"); - return -ENOMEM; - } - - nvidia_ec_ffa_dev->ffa_dev = ffa_dev; -+ kref_init(&nvidia_ec_ffa_dev->refcnt); - INIT_LIST_HEAD(&nvidia_ec_ffa_dev->list); - -+ /* -+ * Publish nvidia_ec_ffa_dev on the global list before -+ * notify_request() is issued from nvidia_ffa_create_notifications(). -+ * The framework can start dispatching the callback as soon as -+ * notify_request() returns; the callback walks -+ * nvidia_ec_ffa_dev_head under nvidia_ffa_lock, so the entry must -+ * already be visible by then. -+ */ -+ mutex_lock(&nvidia_ffa_lock); -+ list_add(&nvidia_ec_ffa_dev->list, &nvidia_ec_ffa_dev_head); -+ mutex_unlock(&nvidia_ffa_lock); -+ - ret = nvidia_ffa_create_notifications(nvidia_ec_ffa_dev); - if (ret) { - dev_err(&ffa_dev->dev, - "Failed to create ffa notifications error=%d\n", ret); -- devm_kfree(&ffa_dev->dev, nvidia_ec_ffa_dev); -+ mutex_lock(&nvidia_ffa_lock); -+ list_del(&nvidia_ec_ffa_dev->list); -+ mutex_unlock(&nvidia_ffa_lock); -+ kref_put(&nvidia_ec_ffa_dev->refcnt, nvidia_ec_ffa_device_release); - return ret; - } - -- mutex_lock(&nvidia_ffa_lock); -- list_add(&nvidia_ec_ffa_dev->list, &nvidia_ec_ffa_dev_head); -- mutex_unlock(&nvidia_ffa_lock); -- - /* - * When acpi subsystem probes all ACPI devices, it executes _STA - * method for each device. The _STA method fails at that time since -@@ -848,8 +1005,9 @@ static void nvidia_ffa_ec_service_remove(struct ffa_device *ffa_dev) - if (cur->ffa_dev == ffa_dev) { - list_del(&cur->list); - nvidia_ffa_remove_notifications(cur); -- devm_kfree(&ffa_dev->dev, cur); -- break; -+ mutex_unlock(&nvidia_ffa_lock); -+ kref_put(&cur->refcnt, nvidia_ec_ffa_device_release); -+ return; - } - } - mutex_unlock(&nvidia_ffa_lock); -From 4d98669d707095853aac42ec6c478e2bac34ca7b Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 3 Jun 2026 12:37:37 +0000 -Subject: [PATCH] NVIDIA: SAUCE: platform/arm64: nvidia-ffa-ec: remove ACPI - rescan workaround - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -The driver previously walked the ACPI bus after each EC service FFA -device probe to rescan consumer ACPI devices. This was needed because -the FFH operation-region handler became available only after the FFA -core driver was bound, by which time consumer ACPI devices' _STA / _DSM -methods (called during the initial acpi_init() namespace scan) had -already failed against \_SB.FFA0.FFAC. - -With the FF-A bus, FF-A core driver, and NVIDIA FFA EC vendor driver -all moved to arch_initcall, and with acpi_scan_init() now explicitly -enumerating the ARML0002 and MSFT000C platform devices first via -acpi_get_devices() before the rest of the namespace scan, the FFH -handler is installed before any consumer ACPI method runs. The -rescan walk is no longer needed. - -Remove: - - nvidia_ffa_rescan_acpi_device() - - nvidia_get_acpi_id_from_uuid() - - the acpi_bus_for_each_dev() call site and the local acpi_id - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 40 -------------------------- - 1 file changed, 40 deletions(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index d91e8f9c30..a8cd7b2456 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -220,35 +220,6 @@ static void nvidia_uuid_to_aml_uuid_buf(const uuid_t *uuid, u8 *buf) - memcpy(buf + 8, src + 8, 8); - } - --static int nvidia_ffa_rescan_acpi_device(struct device *dev, void *data) --{ -- struct acpi_device *adev = to_acpi_device(dev); -- -- if (acpi_dev_hid_uid_match(adev, data, NULL)) { -- acpi_bus_scan(adev->handle); -- return 1; -- } -- -- return 0; --} -- --static const char *nvidia_get_acpi_id_from_uuid(uuid_t *uuid) --{ -- if (uuid_equal(uuid, &nvidia_ec_battery_service_uuid)) -- return "PNP0C0A"; -- -- if (uuid_equal(uuid, &nvidia_ec_time_alarm_service_uuid)) -- return "ACPI000E"; -- -- if (uuid_equal(uuid, &nvidia_ec_fan_service_uuid)) -- return "PNP0C0B"; -- -- if (uuid_equal(uuid, &nvidia_ec_ucsi_service_uuid)) -- return "PNP0CA0"; -- -- return NULL; --} -- - /* - * Fill the virtual notification IDs array supported by the current FFA device. - * ACPI _DSD object contains notification mapping via nested packages. -@@ -941,7 +912,6 @@ static int nvidia_ffh_handler(struct acpi_ffh_info *info, acpi_integer *value, - static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - { - struct nvidia_ec_ffa_device *nvidia_ec_ffa_dev; -- const char *acpi_id = NULL; - int ret; - - if (!ffa_pdev || !control_ffa_dev) { -@@ -982,16 +952,6 @@ static int nvidia_ffa_ec_service_probe(struct ffa_device *ffa_dev) - return ret; - } - -- /* -- * When acpi subsystem probes all ACPI devices, it executes _STA -- * method for each device. The _STA method fails at that time since -- * the custom FFA driver won't be ready. Get ACPI ID from UUID and -- * rescan the device again. -- */ -- acpi_id = nvidia_get_acpi_id_from_uuid(&ffa_dev->uuid); -- if (acpi_id) -- acpi_bus_for_each_dev(nvidia_ffa_rescan_acpi_device, -- (void *)acpi_id); - - return 0; - } -From 922b1fd6d072da2d7d8a5dab3a6c59d4c63e418a Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Thu, 4 Jun 2026 11:14:58 +0000 -Subject: [PATCH] NVIDIA: SAUCE: platform/arm64: nvidia-ffa-ec: inline UUIDs in - ffa_device_id tables - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -Each per-service uuid_t constant was used exactly once -- as the -initializer for its slot in an ffa_device_id[] table -- so the -named-constant indirection adds no value and makes adding a new -service a two-step edit. Drop the ten `static const uuid_t -nvidia_ec_*_uuid = UUID_INIT(...)` declarations and put UUID_INIT() -inline in the two id_table arrays (nvidia_ffa_ec_service_ids and -nvidia_ffa_control_service_ids), matching the convention already -used by drivers/tee/optee/ffa_abi.c. - -Each table entry now carries a brief comment naming the service it -maps to, so the table itself is self-describing. Adding a new EC -service becomes a single-table edit. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 71 +++++++++++--------------- - 1 file changed, 30 insertions(+), 41 deletions(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index a8cd7b2456..8a7639b240 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -38,37 +38,6 @@ static struct platform_device *ffa_pdev; - */ - static struct ffa_device *control_ffa_dev; - --static const uuid_t nvidia_ec_notify_service_uuid = -- UUID_INIT(0xb510b3a3, 0x59f6, 0x4054, 0xba, 0x7a, 0xff, 0x2e, 0xb1, 0xea, 0xc7, 0x65); -- --/* Inter-partition setup protocol UUID (DEN0077A v1.3 section 18.7) */ --static const uuid_t nvidia_ec_interpartition_setup_uuid = -- UUID_INIT(0xe474d87e, 0x5731, 0x4044, 0xa7, 0x27, 0xcb, 0x3e, 0x8c, 0xf3, 0xc8, 0xdf); -- --static const uuid_t nvidia_ec_managment_service_uuid = -- UUID_INIT(0x330c1273, 0xfde5, 0x4757, 0x98, 0x19, 0x5b, 0x65, 0x39, 0x03, 0x75, 0x02); -- --static const uuid_t nvidia_ec_power_service_uuid = -- UUID_INIT(0x7157addf, 0x2fbe, 0x4c63, 0xae, 0x95, 0xef, 0xac, 0x16, 0xe3, 0xb0, 0x1c); -- --static const uuid_t nvidia_ec_battery_service_uuid = -- UUID_INIT(0x25cb5207, 0xac36, 0x427d, 0xaa, 0xef, 0x3a, 0xa7, 0x88, 0x77, 0xd2, 0x7e); -- --static const uuid_t nvidia_ec_thermal_service_uuid = -- UUID_INIT(0x31f56da7, 0x593c, 0x4d72, 0xa4, 0xb3, 0x8f, 0xc7, 0x17, 0x1a, 0xc0, 0x73); -- --static const uuid_t nvidia_ec_fan_service_uuid = -- UUID_INIT(0x7697530c, 0xd079, 0x4ec1, 0xa4, 0xc4, 0xcf, 0x0d, 0x2b, 0xdc, 0x93, 0xfa); -- --static const uuid_t nvidia_ec_ucsi_service_uuid = -- UUID_INIT(0x65467f50, 0x827f, 0x4e4f, 0x87, 0x70, 0xdb, 0xf4, 0xc3, 0xf7, 0x7f, 0x45); -- --static const uuid_t nvidia_ec_input_service_uuid = -- UUID_INIT(0xe3168a99, 0x4a57, 0x4a2b, 0x8c, 0x5e, 0x11, 0xbc, 0xfe, 0xc7, 0x34, 0x06); -- --static const uuid_t nvidia_ec_time_alarm_service_uuid = -- UUID_INIT(0x23ea63ed, 0xb593, 0x46ea, 0xb0, 0x27, 0x89, 0x24, 0xdf, 0x88, 0xe9, 0x2f); -- - /* - * Outer UUID identifying the payload as "Device Properties" in the ACPI - * _DSD returned by the FFA bridge. DEN0077A v1.3 changed this GUID -@@ -974,14 +943,30 @@ static void nvidia_ffa_ec_service_remove(struct ffa_device *ffa_dev) - } - - static const struct ffa_device_id nvidia_ffa_ec_service_ids[] = { -- { nvidia_ec_managment_service_uuid }, -- { nvidia_ec_power_service_uuid }, -- { nvidia_ec_battery_service_uuid }, -- { nvidia_ec_thermal_service_uuid }, -- { nvidia_ec_fan_service_uuid }, -- { nvidia_ec_ucsi_service_uuid }, -- { nvidia_ec_input_service_uuid }, -- { nvidia_ec_time_alarm_service_uuid }, -+ /* management */ -+ { UUID_INIT(0x330c1273, 0xfde5, 0x4757, -+ 0x98, 0x19, 0x5b, 0x65, 0x39, 0x03, 0x75, 0x02) }, -+ /* power */ -+ { UUID_INIT(0x7157addf, 0x2fbe, 0x4c63, -+ 0xae, 0x95, 0xef, 0xac, 0x16, 0xe3, 0xb0, 0x1c) }, -+ /* battery */ -+ { UUID_INIT(0x25cb5207, 0xac36, 0x427d, -+ 0xaa, 0xef, 0x3a, 0xa7, 0x88, 0x77, 0xd2, 0x7e) }, -+ /* thermal */ -+ { UUID_INIT(0x31f56da7, 0x593c, 0x4d72, -+ 0xa4, 0xb3, 0x8f, 0xc7, 0x17, 0x1a, 0xc0, 0x73) }, -+ /* fan */ -+ { UUID_INIT(0x7697530c, 0xd079, 0x4ec1, -+ 0xa4, 0xc4, 0xcf, 0x0d, 0x2b, 0xdc, 0x93, 0xfa) }, -+ /* ucsi */ -+ { UUID_INIT(0x65467f50, 0x827f, 0x4e4f, -+ 0x87, 0x70, 0xdb, 0xf4, 0xc3, 0xf7, 0x7f, 0x45) }, -+ /* input */ -+ { UUID_INIT(0xe3168a99, 0x4a57, 0x4a2b, -+ 0x8c, 0x5e, 0x11, 0xbc, 0xfe, 0xc7, 0x34, 0x06) }, -+ /* time/alarm */ -+ { UUID_INIT(0x23ea63ed, 0xb593, 0x46ea, -+ 0xb0, 0x27, 0x89, 0x24, 0xdf, 0x88, 0xe9, 0x2f) }, - {} - }; - -@@ -1036,8 +1021,12 @@ static void nvidia_ffa_control_service_remove(struct ffa_device *ffa_dev) - } - - static const struct ffa_device_id nvidia_ffa_control_service_ids[] = { -- { nvidia_ec_notify_service_uuid }, /* MSFT000C */ -- { nvidia_ec_interpartition_setup_uuid }, /* ARML0002 */ -+ /* MSFT000C notify service */ -+ { UUID_INIT(0xb510b3a3, 0x59f6, 0x4054, -+ 0xba, 0x7a, 0xff, 0x2e, 0xb1, 0xea, 0xc7, 0x65) }, -+ /* ARML0002 inter-partition setup (DEN0077A v1.3 section 18.7) */ -+ { UUID_INIT(0xe474d87e, 0x5731, 0x4044, -+ 0xa7, 0x27, 0xcb, 0x3e, 0x8c, 0xf3, 0xc8, 0xdf) }, - {} - }; - -From e6c600c37d6122687bc8ef5a907a05c1a8a13fe2 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Thu, 4 Jun 2026 11:53:40 +0000 -Subject: [PATCH] NVIDIA: SAUCE: platform/arm64: nvidia-ffa-ec: add OEM and - standard FFA service UUIDs - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -ACPI tables collected from GB10 platforms issue FFA -requests through the FFAC channel for service UUIDs not yet listed in -nvidia_ffa_ec_service_ids[]. Without a matching entry the FFA bus -framework does not create a per-service device for those partitions, -so the FFH handler cannot route the AML packet to the correct FFA -endpoint and the AML method aborts. - -Add the standard ACPI Physical Presence service UUID -(3dddfaa6-361b-4eb4-a424-8d10089d1653, defined as -UUID_PHYSICAL_PRESENCE in include/acpi/acuuid.h) and seven OEM-specific -service UUIDs observed across GB10 platforms. The OEM entries cover -platform-defined services such as vendor management, EC RAM access, -WMI BIOS attributes, SMBIOS extensions, and other custom services. - -The OEM entries are grouped under a single "custom UUIDs used by OEM -platforms" comment because their FF-A service definitions are -platform-defined and not published in a public spec. The Physical -Presence entry is a standard ACPI service and is called out separately. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 8a7639b240..7975a90d38 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -967,6 +967,26 @@ static const struct ffa_device_id nvidia_ffa_ec_service_ids[] = { - /* time/alarm */ - { UUID_INIT(0x23ea63ed, 0xb593, 0x46ea, - 0xb0, 0x27, 0x89, 0x24, 0xdf, 0x88, 0xe9, 0x2f) }, -+ -+ /* Physical Presence (UUID_PHYSICAL_PRESENCE, include/acpi/acuuid.h) */ -+ { UUID_INIT(0x3dddfaa6, 0x361b, 0x4eb4, -+ 0xa4, 0x24, 0x8d, 0x10, 0x08, 0x9d, 0x16, 0x53) }, -+ -+ /* Custom UUIDs used by OEM platforms. */ -+ { UUID_INIT(0xa3e7f7cf, 0x66ca, 0x43b9, -+ 0x9b, 0x6e, 0x99, 0x47, 0xb8, 0xe2, 0xa5, 0x11) }, -+ { UUID_INIT(0x884a63a0, 0x3285, 0x4120, -+ 0x83, 0xaa, 0xee, 0xc0, 0x08, 0xa0, 0xa5, 0x46) }, -+ { UUID_INIT(0x378daedc, 0xf06b, 0x4446, -+ 0x83, 0x14, 0x40, 0xab, 0x93, 0x3c, 0x87, 0xa3) }, -+ { UUID_INIT(0x3592e053, 0xe409, 0x4ce0, -+ 0xa0, 0x89, 0x97, 0xbd, 0x53, 0x37, 0x1c, 0x88) }, -+ { UUID_INIT(0x8a61cc5c, 0x2bbb, 0x4e29, -+ 0xa0, 0x2e, 0x02, 0x17, 0xe3, 0xf2, 0x42, 0x5a) }, -+ { UUID_INIT(0xde5dca60, 0x9fec, 0x47fb, -+ 0x85, 0x68, 0xdf, 0xf1, 0xf5, 0x42, 0x13, 0x83) }, -+ { UUID_INIT(0x73cc07ac, 0xd184, 0x4b5a, -+ 0x89, 0x07, 0x83, 0x7c, 0x5b, 0x0a, 0xe1, 0x2b) }, - {} - }; - -From 61725d0ec05975a5b2ca9b0cdc95e768453d4b0c Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 3 Jun 2026 12:38:37 +0000 -Subject: [PATCH] NVIDIA: SAUCE: platform/arm64: nvidia-ffa-ec: retry FFA send - on transient failures - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -Some Secure Partition implementations return FFA_RET_BUSY when a -previous FFA request is still in flight. The FFA framework maps this -to -EBUSY. This has been observed on GB10 platforms during early ACPI -enumeration when an SP-originated notification arrives while the -kernel is servicing a back-to-back AML FFH write, causing the second -write to fail. - -AML cannot retry within a single FFAC field write (the handler must -return success or the whole method aborts), so do the retry here in -the unified FFH send helper: retry sync_send_receive2() on -EBUSY -with a short backoff until NVIDIA_FFA_SEND_TIMEOUT_MS elapses, then -return the last -EBUSY to the caller and let the existing failure log -fire once. - -FFA_RET_RETRY / FFA_RET_NOT_READY (both mapped to -EAGAIN) are not -retried. Those indications mean the SP is not yet initialised, which -does not apply here: nvidia-ffa-ec is the first driver to talk to the -EC SP on these platforms, so a not-ready result is not going to clear -on its own and retrying would burn the full timeout on every FFH -access while the SP stays not-ready. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 24 +++++++++++++++++++++++- - 1 file changed, 23 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 7975a90d38..c22e835b84 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -57,6 +58,9 @@ static const guid_t nvidia_notify_dsm_guid = - - #define NVIDIA_FFA_MAX_NOTIFICATIONS 64 - -+/* Timeout for retrying transient failures from sync_send_receive2() */ -+#define NVIDIA_FFA_SEND_TIMEOUT_MS 10 -+ - /* Revision values for the "arm-arml0002-ffa-ntf-bind" property package */ - #define NVIDIA_FFA_NTF_BIND_REV_MSFT000C 1 - #define NVIDIA_FFA_NTF_BIND_REV_ARML0002 0x00010000 -@@ -745,6 +749,7 @@ static int nvidia_ffh_do_ffa_send(uuid_t uuid, u8 *rawdata, - { - struct ffa_send_direct_data2 ffa_data = { 0 }; - struct nvidia_ec_ffa_device *cur, *ec_dev = NULL; -+ ktime_t deadline; - int ret; - - mutex_lock(&nvidia_ffa_lock); -@@ -770,7 +775,24 @@ static int nvidia_ffh_do_ffa_send(uuid_t uuid, u8 *rawdata, - - memcpy(ffa_data.data, rawdata, input_len); - -- ret = ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2(ec_dev->ffa_dev, &ffa_data); -+ /* -+ * Some SP implementations return a transient failure when a previous -+ * FFA request is still in flight. Retry with a short backoff until -+ * NVIDIA_FFA_SEND_TIMEOUT_MS has elapsed. -+ */ -+ deadline = ktime_add_ms(ktime_get(), NVIDIA_FFA_SEND_TIMEOUT_MS); -+ while (true) { -+ ret = ec_dev->ffa_dev->ops->msg_ops->sync_send_receive2(ec_dev->ffa_dev, -+ &ffa_data); -+ if (ret != -EBUSY) -+ break; -+ -+ if (ktime_after(ktime_get(), deadline)) -+ break; -+ -+ usleep_range(500, 1000); -+ } -+ - if (ret) { - dev_err(&ec_dev->ffa_dev->dev, - "Failed to send FFA messages error=%d\n", ret); -From c9ba5f6c1e0dc495c52c206a626c85728dd06a41 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Wed, 9 Sep 2026 10:14:47 +0000 -Subject: [PATCH] NVIDIA: SAUCE: platform/arm64: nvidia-ffa-ec: suppress driver - bind/unbind - -BugLink: https://bugs.launchpad.net/bugs/2167300 - -The FF-A bridge and its EC subunits are a single firmware fixture on -the systems this driver targets: - - * They expose the ACPI FFH region handler that consumer ACPI devices - depend on for the life of the system. - * There is no way to re-create the FFH region or the EC secure - services once torn down. - * The driver is built-in only (NVIDIA_FFA_EC is bool, depends on - ARM_FFA_TRANSPORT=y), so module removal is not possible. - -There are two live-runtime ways for the .remove callbacks of the three -in-tree drivers (nvidia_ffa_driver, nvidia_ffa_ec_service_driver, -nvidia_ffa_control_service_driver) to fire: - - * sysfs bind/unbind of one of these drivers themselves, via - /sys/bus/{platform,arm_ffa}/drivers//{bind,unbind}. This is - an admin-triggered debug/test path that has no legitimate use for a - firmware fixture the whole platform depends on. - - * sysfs unbind of the upstream ARM FF-A core platform driver at - /sys/bus/platform/drivers/arm-ffa/unbind. ffa_remove() cleans up - notifications and unregisters every ffa_device, cascading .remove - into our two arm_ffa-bus drivers (nvidia_ffa_ec_service_driver and - nvidia_ffa_control_service_driver). It does not invoke - nvidia_ffa_remove() -- that is the separate NVIDIA platform_driver - callback, and the FFH region handler is installed and torn down - there. After the arm-ffa core is unbound the FFH region handler - therefore stays installed, but the EC service list has been - emptied, so any subsequent FFH access returns -ENODEV rather than - reaching a live SP. We cannot suppress the arm-ffa-core bind attr - from here; the FF-A core does not set suppress_bind_attrs and that - is upstream policy, not ours to change. - -Set driver.suppress_bind_attrs = true on all three of our drivers to -remove sysfs unbind of this driver as an admin-triggerable teardown -path. The arm-ffa-core unbind path is unaffected, but it drains its -own notification workqueue (destroy_workqueue() in -ffa_notifications_cleanup()) before invoking our .remove callbacks -- -by the time our .remove runs on that path, no callback can still be -in flight, so it cannot trigger the teardown races that the earlier -patches contain. Those races require .remove to run while the FF-A -notification workqueue is still dispatching, and the sysfs unbind of -our own driver is now the only path that would leave that window -open. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index c22e835b84..92834fd332 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -1017,6 +1017,9 @@ static struct ffa_driver nvidia_ffa_ec_service_driver = { - .probe = nvidia_ffa_ec_service_probe, - .remove = nvidia_ffa_ec_service_remove, - .id_table = nvidia_ffa_ec_service_ids, -+ .driver = { -+ .suppress_bind_attrs = true, -+ }, - }; - - /* -@@ -1077,6 +1080,9 @@ static struct ffa_driver nvidia_ffa_control_service_driver = { - .probe = nvidia_ffa_control_service_probe, - .remove = nvidia_ffa_control_service_remove, - .id_table = nvidia_ffa_control_service_ids, -+ .driver = { -+ .suppress_bind_attrs = true, -+ }, - }; - - static const struct acpi_device_id nvidia_ffa_device_ids[] = { -@@ -1158,6 +1164,7 @@ static struct platform_driver nvidia_ffa_driver = { - .driver = { - .name = "nvidia-ffa", - .acpi_match_table = nvidia_ffa_device_ids, -+ .suppress_bind_attrs = true, - }, - }; - diff --git a/kernel/1011-n1x-dell-xps16-battery-status.patch b/kernel/1011-n1x-dell-xps16-battery-status.patch deleted file mode 100644 index f021bbb..0000000 --- a/kernel/1011-n1x-dell-xps16-battery-status.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 8955f10e469f89319fa5bc72f2c9263213690b41 Mon Sep 17 00:00:00 2001 -From: Spencer Bull -Date: Fri, 2 Oct 2026 18:22:12 -0500 -Subject: [PATCH] platform/arm64: nvidia-ffa-ec: answer the Dell XPS 16 battery - status from EC RAM - -The Dell XPS 16 (DX16263) firmware answers the EC battery service's -GetBst with an all-zero payload, so _BST reports the battery empty at -0 V and the battery never shows a charge. - -The same service reads and writes EC RAM, where the firmware's unused -EGBS method finds the live battery status. When GetBst returns nothing -on this machine, fill the reply from there, in the layout _BST expects. ---- - drivers/platform/arm64/nvidia-ffa-ec.c | 101 +++++++++++++++++++++++++ - 1 file changed, 101 insertions(+) - -diff --git a/drivers/platform/arm64/nvidia-ffa-ec.c b/drivers/platform/arm64/nvidia-ffa-ec.c -index 92834fd..f3556b7 100644 ---- a/drivers/platform/arm64/nvidia-ffa-ec.c -+++ b/drivers/platform/arm64/nvidia-ffa-ec.c -@@ -9,9 +9,12 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include -+#include - - #define DRV_NAME "nvidia-ffa-ec" - -@@ -808,6 +811,100 @@ out_put: - return ret; - } - -+/* -+ * Dell's N1x firmware answers the battery service's GetBst (command 2) with -+ * an all-zero payload: the EC behind the service does not implement it, so -+ * _BST reports an empty battery at 0 V. The live battery status is in the EC -+ * RAM that the same service exposes through its byte read and write commands, -+ * where the firmware's own, unused EGBS method reads it: select the battery -+ * at 0x03, then the state at 0x10, the rate at 0x12, the remaining capacity at -+ * 0x16 and the voltage at 0x14. Answer GetBst from there, in the layout _BST -+ * expects, whenever the service returns nothing. -+ */ -+static const uuid_t nvidia_ec_battery_uuid = -+ UUID_INIT(0x25cb5207, 0xac36, 0x427d, -+ 0xaa, 0xef, 0x3a, 0xa7, 0x88, 0x77, 0xd2, 0x7e); -+ -+#define NVIDIA_EC_BAT_GET_BST 0x02 -+#define NVIDIA_EC_BST_LEN 20 -+#define NVIDIA_EC_RAM_READ 0xf0 -+#define NVIDIA_EC_RAM_WRITE 0xf1 -+#define NVIDIA_EC_RAM_BAT_SELECT 0x03 -+#define NVIDIA_EC_RAM_BAT_STATE 0x10 -+#define NVIDIA_EC_RAM_BAT_RATE 0x12 -+#define NVIDIA_EC_RAM_BAT_VOLTAGE 0x14 -+#define NVIDIA_EC_RAM_BAT_CAPACITY 0x16 -+ -+static const struct dmi_system_id nvidia_ec_bst_from_ram_dmi[] = { -+ { -+ /* Dell XPS 16 (NVIDIA N1x) */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS 16 DX16263"), -+ }, -+ }, -+ { } -+}; -+ -+/* One EC RAM byte access, as the firmware's ECRB and ECWB methods do it. */ -+static int nvidia_ec_ram_access(uuid_t uuid, u8 cmd, u8 index, u8 *data) -+{ -+ u8 buf[8] = { cmd, 0, 0, 0, index, *data }; -+ int ret; -+ -+ ret = nvidia_ffh_do_ffa_send(uuid, buf, sizeof(buf), sizeof(buf)); -+ if (ret) -+ return ret; -+ -+ if (get_unaligned_le32(buf)) -+ return -EIO; -+ -+ *data = buf[5]; -+ return 0; -+} -+ -+static int nvidia_ec_ram_read16(uuid_t uuid, u8 index, u16 *val) -+{ -+ u8 lo = 0, hi = 0; -+ int ret; -+ -+ ret = nvidia_ec_ram_access(uuid, NVIDIA_EC_RAM_READ, index, &lo); -+ if (!ret) -+ ret = nvidia_ec_ram_access(uuid, NVIDIA_EC_RAM_READ, index + 1, &hi); -+ -+ *val = lo | hi << 8; -+ return ret; -+} -+ -+static void nvidia_ec_bst_from_ram(uuid_t uuid, u8 *rawdata) -+{ -+ u16 rate, capacity, voltage; -+ u8 battery = 1, state = 0; -+ -+ if (nvidia_ec_ram_access(uuid, NVIDIA_EC_RAM_WRITE, NVIDIA_EC_RAM_BAT_SELECT, &battery) || -+ nvidia_ec_ram_access(uuid, NVIDIA_EC_RAM_READ, NVIDIA_EC_RAM_BAT_STATE, &state) || -+ nvidia_ec_ram_read16(uuid, NVIDIA_EC_RAM_BAT_RATE, &rate) || -+ nvidia_ec_ram_read16(uuid, NVIDIA_EC_RAM_BAT_CAPACITY, &capacity) || -+ nvidia_ec_ram_read16(uuid, NVIDIA_EC_RAM_BAT_VOLTAGE, &voltage)) -+ return; -+ -+ /* State, present rate, remaining capacity, present voltage, status. */ -+ put_unaligned_le32(state, rawdata); -+ put_unaligned_le32(rate, rawdata + 4); -+ put_unaligned_le32(capacity, rawdata + 8); -+ put_unaligned_le32(voltage, rawdata + 12); -+ put_unaligned_le32(0, rawdata + 16); -+} -+ -+static bool nvidia_ec_is_get_bst(const uuid_t *uuid, const u8 *rawdata, -+ unsigned int len) -+{ -+ return len >= NVIDIA_EC_BST_LEN && -+ uuid_equal(uuid, &nvidia_ec_battery_uuid) && -+ get_unaligned_le32(rawdata) == NVIDIA_EC_BAT_GET_BST && -+ dmi_check_system(nvidia_ec_bst_from_ram_dmi); -+} -+ - /* FFH handler — MSFT000C (FFH offset 4) */ - static int nvidia_ffh_handler_msft000c(struct acpi_ffh_info *info, acpi_integer *value) - { -@@ -856,6 +953,7 @@ static int nvidia_ffh_handler_arml0002(struct acpi_ffh_info *info, acpi_integer - { - struct nvidia_ec_ffa_packet_arml0002 *pkt = (struct nvidia_ec_ffa_packet_arml0002 *)value; - unsigned int payload_len; -+ bool get_bst; - uuid_t uuid; - int ret; - -@@ -872,7 +970,10 @@ static int nvidia_ffh_handler_arml0002(struct acpi_ffh_info *info, acpi_integer - } - - uuid = nvidia_get_uuid_from_aml_buf(pkt->uuid); -+ get_bst = nvidia_ec_is_get_bst(&uuid, pkt->rawdata, payload_len); - ret = nvidia_ffh_do_ffa_send(uuid, pkt->rawdata, payload_len, payload_len); -+ if (!ret && get_bst && !memchr_inv(pkt->rawdata, 0, NVIDIA_EC_BST_LEN)) -+ nvidia_ec_bst_from_ram(uuid, pkt->rawdata); - pkt->status = ret ? 1 : 0; - return ret; - } diff --git a/kernel/1012-n1x-acpi-thermal-skip-power-telemetry.patch b/kernel/1012-n1x-acpi-thermal-skip-power-telemetry.patch deleted file mode 100644 index 9580fbd..0000000 --- a/kernel/1012-n1x-acpi-thermal-skip-power-telemetry.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 164d589ddab89fdfc8539fdab8a425ca32c66e9d Mon Sep 17 00:00:00 2001 -From: Spencer Bull -Date: Sun, 4 Oct 2026 01:20:06 -0500 -Subject: [PATCH] ACPI: thermal: skip the Dell XPS 16 N1x power telemetry zones - -The Dell XPS 16 DX16263 (NVIDIA N1x) publishes its system and SoC power -readings as the thermal zones PSYS and PSOC. Their _TMP returns -milliwatts, which reads as hundreds of degrees in every temperature -monitor. They have no trip points, so do not register them as thermal -zones on that machine. ---- - drivers/acpi/thermal.c | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c -index dd7666c..aaa0956 100644 ---- a/drivers/acpi/thermal.c -+++ b/drivers/acpi/thermal.c -@@ -781,6 +781,32 @@ static void acpi_thermal_zone_free(void *data) - kfree(tz); - } - -+/* -+ * The Dell XPS 16 DX16263 (NVIDIA N1x) publishes its system and SoC power -+ * telemetry as thermal zones PSYS and PSOC, whose _TMP returns milliwatts: they -+ * read as hundreds of degrees and have no trip points. Do not register them as -+ * thermal zones there. -+ */ -+static const struct dmi_system_id acpi_thermal_power_telemetry_dmi[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS 16 DX16263"), -+ }, -+ }, -+ { } -+}; -+ -+static bool acpi_thermal_is_power_telemetry(struct acpi_device *device) -+{ -+ const char *name = acpi_device_bid(device); -+ -+ if (strcmp(name, "PSYS") && strcmp(name, "PSOC")) -+ return false; -+ -+ return dmi_check_system(acpi_thermal_power_telemetry_dmi); -+} -+ - static int acpi_thermal_probe(struct platform_device *pdev) - { - struct thermal_trip trip_table[ACPI_THERMAL_MAX_NR_TRIPS] = { 0 }; -@@ -797,6 +823,9 @@ static int acpi_thermal_probe(struct platform_device *pdev) - if (!device) - return -ENODEV; - -+ if (acpi_thermal_is_power_telemetry(device)) -+ return -ENODEV; -+ - tz = kzalloc_obj(struct acpi_thermal); - if (!tz) - return -ENOMEM; diff --git a/kernel/1013-n1x-dell-arm64-hotkeys.patch b/kernel/1013-n1x-dell-arm64-hotkeys.patch deleted file mode 100644 index 9419622..0000000 --- a/kernel/1013-n1x-dell-arm64-hotkeys.patch +++ /dev/null @@ -1,472 +0,0 @@ -From 11d657d4e3fbb4e2044de10b4f25400d661bf2b4 Mon Sep 17 00:00:00 2001 -From: Spencer Bull -Date: Sat, 3 Oct 2026 17:39:36 -0500 -Subject: [PATCH] platform/arm64: add a driver for Dell WMI hotkeys - -Dell laptops report some hotkeys, such as mic mute, as WMI events: the -EC raises a notification, the firmware calls Notify(AMW0, 0xD0), and -_WED(0xD0) returns the event words. On x86 dell-wmi handles them through -the ACPI-WMI core, which only builds on x86, so the mic mute key on the -Arm64 Dell XPS 16 (DX16263, NVIDIA N1x) does nothing. - -Bind to the WMI device that declares Dell's event GUID, enable the event -with WED0 as the WMI core would, evaluate _WED on its notification and -report the keys through a sparse keymap, using dell-wmi's codes. Speaker -mute and brightness also come from the keyboard on this machine, so only -mic mute is reported. - -On the XPS 16 the notification never arrives: none of the EC's FF-A -notifications do on BIOS 1.2.0. The EC still queues each event in its -RAM, so on that machine poll the queue every 250 ms and read it out the -way the firmware's EC0A does. Reading the queue length hands the event -out, so the event is read in full right away rather than through _WED, -whose buffer would replay the previous event. - -Its mic-mute LED can only be toggled (MTLD 0x676, as _WED does), the EC -does not report its state, and it stays lit across a reboot. Track it, -expose it as platform::micmute so it follows the mute state rather than -the key, and turn it off at shutdown so each boot starts in step. ---- - drivers/platform/arm64/Kconfig | 17 + - drivers/platform/arm64/Makefile | 1 + - drivers/platform/arm64/dell-arm64-hotkeys.c | 391 ++++++++++++++++++++ - 3 files changed, 409 insertions(+) - create mode 100644 drivers/platform/arm64/dell-arm64-hotkeys.c - -diff --git a/drivers/platform/arm64/Kconfig b/drivers/platform/arm64/Kconfig -index 857f2c41e..7d882af9e 100644 ---- a/drivers/platform/arm64/Kconfig -+++ b/drivers/platform/arm64/Kconfig -@@ -16,6 +16,23 @@ menuconfig ARM64_PLATFORM_DEVICES - - if ARM64_PLATFORM_DEVICES - -+config DELL_ARM64_HOTKEYS -+ tristate "Dell WMI hotkeys on Arm64 laptops" -+ depends on ACPI -+ depends on INPUT -+ depends on !ACPI_WMI -+ select INPUT_SPARSEKMAP -+ select NEW_LEDS -+ select LEDS_CLASS -+ help -+ Report the hotkeys that Dell laptops send as WMI events, such as -+ mic mute, on Arm64 laptops like the Dell XPS 16 (DX16263), and -+ drive the XPS 16's mic-mute LED. On x86 the dell-wmi and -+ dell-laptop drivers handle these. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called dell-arm64-hotkeys. -+ - config EC_ACER_ASPIRE1 - tristate "Acer Aspire 1 Embedded Controller driver" - depends on ARCH_QCOM || COMPILE_TEST -diff --git a/drivers/platform/arm64/Makefile b/drivers/platform/arm64/Makefile -index 265d356a9..848bb289e 100644 ---- a/drivers/platform/arm64/Makefile -+++ b/drivers/platform/arm64/Makefile -@@ -5,6 +5,7 @@ - # This dir should only include drivers for EC-like devices. - # - -+obj-$(CONFIG_DELL_ARM64_HOTKEYS) += dell-arm64-hotkeys.o - obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o - obj-$(CONFIG_EC_HUAWEI_GAOKUN) += huawei-gaokun-ec.o - obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o -diff --git a/drivers/platform/arm64/dell-arm64-hotkeys.c b/drivers/platform/arm64/dell-arm64-hotkeys.c -new file mode 100644 -index 000000000..b87dd8927 ---- /dev/null -+++ b/drivers/platform/arm64/dell-arm64-hotkeys.c -@@ -0,0 +1,391 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Dell hotkey events on Arm64 laptops -+ * -+ * Dell laptops report some hotkeys, such as mic mute, as WMI events: the -+ * EC raises a notification, the firmware calls Notify(AMW0, 0xD0), and -+ * _WED(0xD0) returns the event as 16-bit words (length, type, codes). On -+ * x86, dell-wmi handles these through the ACPI-WMI core, which is x86 -+ * only. Arm64 Dell laptops such as the XPS 16 DX16263 (NVIDIA N1x) have -+ * the same firmware interface, so this driver handles that one event: -+ * it binds to the WMI device that declares Dell's event GUID, evaluates -+ * _WED and reports the keys. -+ * -+ * The XPS 16 DX16263's EC never raises the notification (its FF-A -+ * notifications do not arrive at all on BIOS 1.2.0), but it still queues -+ * each event in EC RAM. On that machine the driver reads the queue the way -+ * the firmware's _WED does. Its mic-mute LED can only be toggled, and the -+ * EC keeps it lit across reboots, so the driver tracks it, exposes it as a -+ * platform::micmute LED that follows the mute state rather than the key, -+ * and turns it off at shutdown. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DELL_EVENT_NOTIFY 0xd0 -+#define WDG_FLAG_EVENT BIT(3) -+ -+#define DELL_POLL_MS 250 -+ -+/* Dell WMI event GUID, 9DBB5994-A997-11DA-B012-B622A1EF5492 */ -+static const guid_t dell_event_guid = -+ GUID_INIT(0x9dbb5994, 0xa997, 0x11da, -+ 0xb0, 0x12, 0xb6, 0x22, 0xa1, 0xef, 0x54, 0x92); -+ -+/* One entry of the _WDG table, as in the ACPI-WMI core */ -+struct wdg_entry { -+ guid_t guid; -+ u8 notify_id; -+ u8 reserved; -+ u8 instance_count; -+ u8 flags; -+} __packed; -+ -+/* -+ * Type 0x0010 codes, from dell-wmi. Speaker mute and brightness also come -+ * from the keyboard on these machines, so their events are only -+ * notifications here. -+ */ -+static const struct key_entry dell_arm64_keymap[] = { -+ { KE_IGNORE, 0x00100000, { KEY_RESERVED } }, /* Fn-lock off */ -+ { KE_IGNORE, 0x00100001, { KEY_RESERVED } }, /* Fn-lock on */ -+ { KE_IGNORE, 0x0010003f, { KEY_RESERVED } }, /* Keyboard backlight changed */ -+ { KE_IGNORE, 0x00100057, { KEY_BRIGHTNESSDOWN } }, -+ { KE_IGNORE, 0x00100058, { KEY_BRIGHTNESSUP } }, -+ { KE_IGNORE, 0x00100109, { KEY_MUTE } }, -+ { KE_KEY, 0x00100150, { KEY_MICMUTE } }, -+ { KE_IGNORE, 0x00100151, { KEY_RESERVED } }, /* Fn-lock */ -+ { KE_IGNORE, 0x00100152, { KEY_KBDILLUMTOGGLE } }, -+ { KE_END, 0 } -+}; -+ -+/* -+ * An EC that queues WMI events in its RAM without notifying: reading the -+ * length register hands out the queued event, which is then read a byte -+ * at a time from the data register (the firmware's EC0A). The keys' LEDs -+ * are toggled by passing an ID to MTLD, as _WED does for the speaker mute -+ * (0x0109) and mic mute (0x0150) keys. The EC answers but never with the -+ * LED's state, so the state cannot be read back. -+ */ -+struct dell_arm64_quirks { -+ u8 queue_len_reg; -+ u8 queue_data_reg; -+ u32 mute_toggle; -+ u32 micmute_toggle; -+}; -+ -+static const struct dell_arm64_quirks dell_xps16_dx16263_quirks = { -+ .queue_len_reg = 0x2b, -+ .queue_data_reg = 0x2c, -+ .mute_toggle = 0x0781, -+ .micmute_toggle = 0x0676, -+}; -+ -+static const struct dmi_system_id dell_arm64_quirk_ids[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS 16 DX16263"), -+ }, -+ .driver_data = (void *)&dell_xps16_dx16263_quirks, -+ }, -+ { } -+}; -+ -+struct dell_arm64_hotkeys { -+ struct device *dev; -+ struct input_dev *input; -+ acpi_handle handle; -+ const struct dell_arm64_quirks *quirks; -+ struct delayed_work poll; -+ struct led_classdev micmute; -+ /* Serializes the mic-mute LED's toggles with micmute_lit */ -+ struct mutex led_lock; -+ bool micmute_lit; -+}; -+ -+static bool dell_arm64_has_event(acpi_handle handle) -+{ -+ struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; -+ const struct wdg_entry *entry; -+ union acpi_object *obj; -+ bool found = false; -+ size_t i, count; -+ -+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_WDG", NULL, &out))) -+ return false; -+ -+ obj = out.pointer; -+ if (obj && obj->type == ACPI_TYPE_BUFFER) { -+ entry = (const struct wdg_entry *)obj->buffer.pointer; -+ count = obj->buffer.length / sizeof(*entry); -+ for (i = 0; i < count; i++) { -+ if (guid_equal(&entry[i].guid, &dell_event_guid) && -+ entry[i].flags & WDG_FLAG_EVENT && -+ entry[i].notify_id == DELL_EVENT_NOTIFY) { -+ found = true; -+ break; -+ } -+ } -+ } -+ -+ kfree(out.pointer); -+ return found; -+} -+ -+static void dell_arm64_report(struct dell_arm64_hotkeys *priv, u16 type, u16 code) -+{ -+ const struct key_entry *key; -+ -+ key = sparse_keymap_entry_from_scancode(priv->input, (type << 16) | code); -+ if (!key) { -+ dev_info_ratelimited(priv->dev, "Unknown event type 0x%04x code 0x%04x\n", -+ type, code); -+ return; -+ } -+ -+ if (key->type == KE_KEY) -+ sparse_keymap_report_entry(priv->input, key, 1, true); -+} -+ -+/* Report the first entry of a Dell WMI event buffer (16-bit words). */ -+static void dell_arm64_process(struct dell_arm64_hotkeys *priv, const u8 *buf, -+ size_t size, bool set_leds) -+{ -+ size_t count = size / 2, len, i; -+ u16 type, code; -+ -+ /* -+ * The firmware copies the event into a fixed buffer without clearing -+ * it, so anything after the first entry can be left over from an -+ * earlier event. Read only the first entry, as the firmware does. -+ */ -+ if (count < 2 || !get_unaligned_le16(buf)) -+ return; -+ -+ len = min_t(size_t, get_unaligned_le16(buf) + 1, count); -+ type = get_unaligned_le16(buf + 2); -+ switch (type) { -+ case 0x0000: /* One key or event */ -+ if (len > 2) -+ dell_arm64_report(priv, type, get_unaligned_le16(buf + 4)); -+ break; -+ case 0x0010: /* Sequence of keys */ -+ case 0x0011: /* Sequence of events */ -+ for (i = 2; i < len; i++) { -+ code = get_unaligned_le16(buf + 2 * i); -+ dell_arm64_report(priv, type, code); -+ if (type != 0x0010 || !priv->quirks) -+ continue; -+ /* As _WED does; the mic-mute LED follows the mute state instead. */ -+ if (set_leds && code == 0x0109) -+ acpi_execute_simple_method(NULL, "\\_SB.MTLD", -+ priv->quirks->mute_toggle); -+ /* _WED toggled the mic-mute LED itself. */ -+ if (!set_leds && code == 0x0150) { -+ guard(mutex)(&priv->led_lock); -+ priv->micmute_lit = !priv->micmute_lit; -+ } -+ } -+ break; -+ default: -+ dev_dbg(priv->dev, "Ignored event type 0x%04x\n", type); -+ break; -+ } -+} -+ -+static void dell_arm64_read_event(struct dell_arm64_hotkeys *priv) -+{ -+ struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; -+ union acpi_object arg = { -+ .integer = { .type = ACPI_TYPE_INTEGER, .value = DELL_EVENT_NOTIFY }, -+ }; -+ struct acpi_object_list args = { .count = 1, .pointer = &arg }; -+ union acpi_object *obj; -+ -+ if (ACPI_FAILURE(acpi_evaluate_object(priv->handle, "_WED", &args, &out))) { -+ dev_warn_ratelimited(priv->dev, "Failed to read the event\n"); -+ return; -+ } -+ -+ /* _WED toggles the LEDs itself. */ -+ obj = out.pointer; -+ if (obj && obj->type == ACPI_TYPE_BUFFER) -+ dell_arm64_process(priv, obj->buffer.pointer, obj->buffer.length, false); -+ -+ kfree(out.pointer); -+} -+ -+static void dell_arm64_notify(acpi_handle handle, u32 event, void *data) -+{ -+ if (event == DELL_EVENT_NOTIFY) -+ dell_arm64_read_event(data); -+} -+ -+static bool dell_arm64_ec_read(u8 reg, u8 *val) -+{ -+ union acpi_object arg = { -+ .integer = { .type = ACPI_TYPE_INTEGER, .value = reg }, -+ }; -+ struct acpi_object_list args = { .count = 1, .pointer = &arg }; -+ unsigned long long data; -+ -+ if (ACPI_FAILURE(acpi_evaluate_integer(NULL, "\\_SB.ECRB", &args, &data))) -+ return false; -+ -+ *val = data; -+ return true; -+} -+ -+static void dell_arm64_poll(struct work_struct *work) -+{ -+ struct dell_arm64_hotkeys *priv = -+ container_of(to_delayed_work(work), struct dell_arm64_hotkeys, poll); -+ u8 buf[128] = { }, len, i, val; -+ -+ if (dell_arm64_ec_read(priv->quirks->queue_len_reg, &len) && len) { -+ dev_dbg(priv->dev, "EC queued a %u-byte event\n", len); -+ /* The length is only read once: the event must be read out now. */ -+ for (i = 0; i < len; i++) -+ if (dell_arm64_ec_read(priv->quirks->queue_data_reg, &val) && -+ i < sizeof(buf)) -+ buf[i] = val; -+ dell_arm64_process(priv, buf, min_t(size_t, len, sizeof(buf)), true); -+ } -+ -+ queue_delayed_work(system_freezable_wq, &priv->poll, -+ msecs_to_jiffies(DELL_POLL_MS)); -+} -+ -+static int dell_arm64_micmute_set(struct led_classdev *cdev, -+ enum led_brightness brightness) -+{ -+ struct dell_arm64_hotkeys *priv = -+ container_of(cdev, struct dell_arm64_hotkeys, micmute); -+ -+ guard(mutex)(&priv->led_lock); -+ if (!!brightness == priv->micmute_lit) -+ return 0; -+ -+ if (ACPI_FAILURE(acpi_execute_simple_method(NULL, "\\_SB.MTLD", -+ priv->quirks->micmute_toggle))) -+ return -EIO; -+ -+ priv->micmute_lit = !!brightness; -+ return 0; -+} -+ -+static void dell_arm64_stop(void *data) -+{ -+ struct dell_arm64_hotkeys *priv = data; -+ -+ if (priv->quirks) { -+ cancel_delayed_work_sync(&priv->poll); -+ dell_arm64_micmute_set(&priv->micmute, LED_OFF); -+ } -+ acpi_execute_simple_method(priv->handle, "WED0", 0); -+} -+ -+/* The EC keeps the LED lit across a reboot; leave it off for the next boot. */ -+static void dell_arm64_hotkeys_shutdown(struct platform_device *pdev) -+{ -+ struct dell_arm64_hotkeys *priv = platform_get_drvdata(pdev); -+ -+ if (priv && priv->quirks) -+ dell_arm64_micmute_set(&priv->micmute, LED_OFF); -+} -+ -+static int dell_arm64_hotkeys_probe(struct platform_device *pdev) -+{ -+ const struct dmi_system_id *dmi_id; -+ struct dell_arm64_hotkeys *priv; -+ acpi_handle handle = ACPI_HANDLE(&pdev->dev); -+ int ret; -+ -+ if (!handle || !dell_arm64_has_event(handle) || -+ !acpi_has_method(handle, "_WED")) -+ return -ENODEV; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ priv->dev = &pdev->dev; -+ priv->handle = handle; -+ platform_set_drvdata(pdev, priv); -+ -+ ret = devm_mutex_init(&pdev->dev, &priv->led_lock); -+ if (ret) -+ return ret; -+ -+ priv->input = devm_input_allocate_device(&pdev->dev); -+ if (!priv->input) -+ return -ENOMEM; -+ -+ priv->input->name = "Dell WMI hotkeys"; -+ priv->input->phys = "wmi/input0"; -+ priv->input->id.bustype = BUS_HOST; -+ -+ ret = sparse_keymap_setup(priv->input, dell_arm64_keymap, NULL); -+ if (ret) -+ return ret; -+ -+ ret = input_register_device(priv->input); -+ if (ret) -+ return ret; -+ -+ ret = devm_acpi_install_notify_handler(&pdev->dev, ACPI_DEVICE_NOTIFY, -+ dell_arm64_notify, priv); -+ if (ret) -+ return ret; -+ -+ /* Enable the event, as the ACPI-WMI core does with WExx. */ -+ acpi_execute_simple_method(handle, "WED0", 1); -+ -+ dmi_id = dmi_first_match(dell_arm64_quirk_ids); -+ if (dmi_id && acpi_has_method(NULL, "\\_SB.ECRB") && -+ acpi_has_method(NULL, "\\_SB.MTLD")) { -+ priv->quirks = dmi_id->driver_data; -+ INIT_DELAYED_WORK(&priv->poll, dell_arm64_poll); -+ queue_delayed_work(system_freezable_wq, &priv->poll, 0); -+ } -+ -+ ret = devm_add_action_or_reset(&pdev->dev, dell_arm64_stop, priv); -+ if (ret || !priv->quirks) -+ return ret; -+ -+ /* Shutdown turns the LED off, so a boot starts with it off. */ -+ priv->micmute.name = "platform::micmute"; -+ priv->micmute.max_brightness = 1; -+ priv->micmute.brightness_set_blocking = dell_arm64_micmute_set; -+ -+ return devm_led_classdev_register(&pdev->dev, &priv->micmute); -+} -+ -+static const struct acpi_device_id dell_arm64_hotkeys_ids[] = { -+ { "PNP0C14" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, dell_arm64_hotkeys_ids); -+ -+static struct platform_driver dell_arm64_hotkeys_driver = { -+ .driver = { -+ .name = "dell-arm64-hotkeys", -+ .acpi_match_table = dell_arm64_hotkeys_ids, -+ }, -+ .probe = dell_arm64_hotkeys_probe, -+ .shutdown = dell_arm64_hotkeys_shutdown, -+}; -+module_platform_driver(dell_arm64_hotkeys_driver); -+ -+MODULE_DESCRIPTION("Dell hotkey events on Arm64 laptops"); -+MODULE_LICENSE("GPL"); diff --git a/kernel/1020-n1x-power.patch b/kernel/1020-n1x-power.patch deleted file mode 100644 index ee754d2..0000000 --- a/kernel/1020-n1x-power.patch +++ /dev/null @@ -1,1718 +0,0 @@ -From b63ed28368443febe7da63d9bc567272dd8dad98 Mon Sep 17 00:00:00 2001 -From: Shanker Donthineni -Date: Mon, 12 Aug 2024 22:39:25 -0500 -Subject: [PATCH] NVIDIA: SAUCE: irqchip/gic-v3: Allow unused SGIs for - drivers/modules - -BugLink: https://bugs.launchpad.net/bugs/2114230 - -The commit 897e9e60c016 ("firmware: arm_ffa: Initial support for scheduler -receiver interrupt") adds support for SGI interrupts in the FFA driver. -However, the validation for SGIs in the GICv3 is too strict, causing the -driver probe to fail. - -This patch relaxes the SGI validation check, allowing callers to use SGIs -if the requested SGI number is greater than or equal to MAX_IPI, which -fixes the TFA driver probe failure. - -This issue is observed on NVIDIA server platform with FFA-v1.1. - - PTP clock support registered - EDAC MC: Ver: 3.0.0 - ARM FF-A: Driver version 1.1 - ARM FF-A: Firmware version 1.1 found - GICv3: [Firmware Bug]: Illegal GSI8 translation request - ARM FF-A: Failed to create IRQ mapping! - ARM FF-A: Notification setup failed -61, not enabled - ARM FF-A: Failed to register driver sched callback -95 - scmi_core: SCMI protocol bus registered - -This patch was sent in arm mailing list for upstream but it got -rejected. - -https://patchwork.kernel.org/project/linux-arm-kernel/patch/20240813033925.925947-1-sdonthineni@nvidia.com/ - -The proper fix requires some kind of mechanism by which a -SGI can be requested by module but that needs discussion with arm and -it will take time. This patch will break only if MAX_IPI value gets -changed. This patch adds a BUILD_BUG_ON() to catch that situation. -Once proper solution is concluded then this patch will be reverted. - -Signed-off-by: Shanker Donthineni -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Noah Wager -Acked-by: Jacob Martin -Signed-off--by: Brad Figg -(backported from commit fd136cf979db) -[maskedarray: removed enum ipi_msg_type definition as it appears in -upstream commit "irqchip/gic-v5: Add GICv5 LPI/IPI support"] -Signed-off-by: Abdur Rahman - -(cherry picked from commit df84d5ddd125e925e912c8af1c76a71d3beb1de6 noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/irqchip/irq-gic-v3.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c -index 99444a1b2f..0750219ddb 100644 ---- a/drivers/irqchip/irq-gic-v3.c -+++ b/drivers/irqchip/irq-gic-v3.c -@@ -1642,7 +1642,13 @@ static int gic_irq_domain_translate(struct irq_domain *d, - if(fwspec->param_count != 2) - return -EINVAL; - -- if (fwspec->param[0] < 16) { -+ /* -+ * Below check was added on assumption that MAX_IPI -+ * value will not be greater than 8. -+ */ -+ BUILD_BUG_ON(MAX_IPI > 8); -+ -+ if (fwspec->param[0] < MAX_IPI) { - pr_err(FW_BUG "Illegal GSI%d translation request\n", - fwspec->param[0]); - return -EINVAL; -From 0f52a324593fcf0655a694ac2171fc0894ac1b59 Mon Sep 17 00:00:00 2001 -From: Andy Ritger -Date: Tue, 20 May 2025 17:11:58 -0700 -Subject: [PATCH] NVIDIA: SAUCE: iommu/io-pgtable-arm: backport contiguous bit - support - -BugLink: https://bugs.launchpad.net/bugs/2112600 - -iommu/io-pgtable-arm: Support contiguous bit in translation tables - -The contiguous bit in translation table entries can be used as a hint to -SMMU that a group of adjacent translation table entries have consistent -attributes and point to a contiguous and properly aligned output address -range. This enables SMMU to predict the properties of the remaining -translation table entries in the same group without accessing them. It -also allows an SMMU implementation to make more efficient use of its TLB -by using a single TLB entry to cover all translation table entries in -the same group. - -In the case of 4KB granule size, there are 16 translation table entries -in one group. - -This change sets the contiguous bit for such groups of entries that are -completely covered by a single call to map_pages. As it stands, the code -wouldn't set the contiguous bit if a group of adjacent descriptors is -completed by separate calls to map_pages. - -Signed-off-by: Daniel Mentz -Link: https://lore.kernel.org/linux-iommu/20250430231924.1481493-1-danielmentz@google.com/ -[aritger: For the backport: updated the __arm_lpae_init_pte() callsite in -arm_lpae_split_blk_unmap() (arm_lpae_split_blk_unmap() is no longer -present at top of tree where the original commit was written).] -Signed-off-by: Andy Ritger -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Abdur Rahman -Acked-by: Noah Wager -Signed-off--by: Brad Figg -(backported from commit 990fa55beac8efffb7a94b26be553d52c232b9f1 linux-nvidia-6.11) -[kobak: arm_lpae_split_blk_unmap is removed since https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=33729a5fc0caf7a97d20507acbeee6b012e7e519 -iommu/io-pgtable-arm: Remove split on unmap behavior so modify as per functions] -Signed-off-by: Koba Ko -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Jacob Martin -Acked-by: Abdur Rahman -Signed-off-by: Ian May - -(cherry picked from commit c601e605745ea9f16834da6e24049b92b759b78f noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/iommu/io-pgtable-arm.c | 52 ++++++++++++++++++++++++++++++++-- - 1 file changed, 49 insertions(+), 3 deletions(-) - -diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c -index 476c0e2563..aaf2813f2c 100644 ---- a/drivers/iommu/io-pgtable-arm.c -+++ b/drivers/iommu/io-pgtable-arm.c -@@ -75,6 +75,7 @@ - - #define ARM_LPAE_PTE_NSTABLE (((arm_lpae_iopte)1) << 63) - #define ARM_LPAE_PTE_XN (((arm_lpae_iopte)3) << 53) -+#define ARM_LPAE_PTE_CONT (((arm_lpae_iopte)1) << 52) - #define ARM_LPAE_PTE_DBM (((arm_lpae_iopte)1) << 51) - #define ARM_LPAE_PTE_AF (((arm_lpae_iopte)1) << 10) - #define ARM_LPAE_PTE_SH_NS (((arm_lpae_iopte)0) << 8) -@@ -354,6 +355,27 @@ static void __arm_lpae_sync_pte(arm_lpae_iopte *ptep, int num_entries, - sizeof(*ptep) * num_entries, DMA_TO_DEVICE); - } - -+static int arm_lpae_cont_ptes(int lvl, struct arm_lpae_io_pgtable *data) -+{ -+ switch (ARM_LPAE_GRANULE(data)) { -+ case SZ_4K: -+ if (lvl >= 1) -+ return 16; -+ break; -+ case SZ_16K: -+ if (lvl == 2) -+ return 32; -+ else if (lvl == 3) -+ return 128; -+ break; -+ case SZ_64K: -+ if (lvl >= 2) -+ return 32; -+ break; -+ } -+ return 1; -+} -+ - static void __arm_lpae_clear_pte(arm_lpae_iopte *ptep, struct io_pgtable_cfg *cfg, int num_entries) - { - for (int i = 0; i < num_entries; i++) -@@ -363,13 +385,35 @@ static void __arm_lpae_clear_pte(arm_lpae_iopte *ptep, struct io_pgtable_cfg *cf - __arm_lpae_sync_pte(ptep, num_entries, cfg); - } - -+static bool arm_lpae_use_contpte(struct arm_lpae_io_pgtable *data, -+ unsigned long iova, phys_addr_t paddr, -+ int lvl, int num_entries, int i) -+{ -+ size_t sz = ARM_LPAE_BLOCK_SIZE(lvl, data); -+ int cont_ptes = arm_lpae_cont_ptes(lvl, data); -+ int contmask = cont_ptes - 1; -+ int contpte_addr_mask = sz * cont_ptes - 1; -+ int map_idx_start, tbl_idx; -+ -+ if ((paddr & contpte_addr_mask) != (iova & contpte_addr_mask)) -+ return false; -+ -+ map_idx_start = ARM_LPAE_LVL_IDX(iova, lvl, data); -+ tbl_idx = map_idx_start + i; -+ if (((tbl_idx & contmask) <= i) && -+ (tbl_idx < ((map_idx_start + num_entries) & ~contmask))) -+ return true; -+ -+ return false; -+} -+ - static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, - struct iommu_iotlb_gather *gather, - unsigned long iova, size_t size, size_t pgcount, - int lvl, arm_lpae_iopte *ptep); - - static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, -- phys_addr_t paddr, arm_lpae_iopte prot, -+ unsigned long iova, phys_addr_t paddr, arm_lpae_iopte prot, - int lvl, int num_entries, arm_lpae_iopte *ptep) - { - arm_lpae_iopte pte = prot; -@@ -383,7 +427,9 @@ static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, - pte |= ARM_LPAE_PTE_TYPE_BLOCK; - - for (i = 0; i < num_entries; i++) -- ptep[i] = pte | paddr_to_iopte(paddr + i * sz, data); -+ ptep[i] = pte | paddr_to_iopte(paddr + i * sz, data) | -+ (arm_lpae_use_contpte(data, iova, paddr, lvl, num_entries, i) ? -+ ARM_LPAE_PTE_CONT : 0); - - if (!cfg->coherent_walk) - __arm_lpae_sync_pte(ptep, num_entries, cfg); -@@ -417,7 +463,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, - } - } - -- __arm_lpae_init_pte(data, paddr, prot, lvl, num_entries, ptep); -+ __arm_lpae_init_pte(data, iova, paddr, prot, lvl, num_entries, ptep); - return 0; - } - -From 6a70ab5401ec8f4f69e2c9a9cc1313e7f4762ff7 Mon Sep 17 00:00:00 2001 -From: Sumit Gupta -Date: Sat, 25 Apr 2026 01:48:14 +0530 -Subject: [PATCH] NVIDIA: SAUCE: cpufreq: CPPC: add autonomous mode boot - parameter support - -BugLink: https://bugs.launchpad.net/bugs/2131705 - -Add a kernel boot parameter 'cppc_cpufreq.auto_sel_mode' to enable -CPPC autonomous performance selection on all CPUs at system startup. -When autonomous mode is enabled, the hardware automatically adjusts -CPU performance based on workload demands using Energy Performance -Preference (EPP) hints. - -When auto_sel_mode=1: -- Configure all CPUs for autonomous operation on first init -- Set EPP to performance preference (0x0) -- Use HW min/max_perf when available; otherwise initialize from caps -- Clamp desired_perf to bounds before enabling autonomous mode -- Hardware controls frequency instead of the OS governor - -The boot parameter is applied only during first policy initialization. -Skip applying it on CPU hotplug to preserve runtime sysfs configuration. - -This patch depends on patch [2] ("cpufreq: Set policy->min and max -as real QoS constraints") so that the policy->min/max set in -cppc_cpufreq_cpu_init() are not overridden by cpufreq_set_policy() -during init. - -Reviewed-by: Randy Dunlap -Signed-off-by: Sumit Gupta -(backported from https://lore.kernel.org/lkml/20260424201814.230071-1-sumitg@nvidia.com/) -[jamien: hunk #2 (cppc_set_enable() insertion in cppc_cpufreq_cpu_init) -rebased onto Pierre's v2 series, which replaced the local min/max vars -with direct policy->min assignment; insertion point and code are -unchanged.] -Signed-off-by: Jamie Nguyen -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - .../admin-guide/kernel-parameters.txt | 13 +++ - drivers/cpufreq/cppc_cpufreq.c | 89 +++++++++++++++++-- - 2 files changed, 97 insertions(+), 5 deletions(-) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index e8ff36982d..0363f7c18f 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -1019,6 +1019,19 @@ Kernel parameters - policy to use. This governor must be registered in the - kernel before the cpufreq driver probes. - -+ cppc_cpufreq.auto_sel_mode= -+ [CPU_FREQ] Enable ACPI CPPC autonomous performance -+ selection. When enabled, hardware automatically adjusts -+ CPU frequency on all CPUs based on workload demands. -+ In Autonomous mode, Energy Performance Preference (EPP) -+ hints guide hardware toward performance (0x0) or energy -+ efficiency (0xff). -+ Requires ACPI CPPC autonomous selection register support. -+ Format: -+ Default: 0 (disabled) -+ 0: use cpufreq governors -+ 1: enable if supported by hardware -+ - cpu_init_udelay=N - [X86,EARLY] Delay for N microsec between assert and de-assert - of APIC INIT to start processors. This delay occurs -diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c -index 8089384435..bc0c56a9a6 100644 ---- a/drivers/cpufreq/cppc_cpufreq.c -+++ b/drivers/cpufreq/cppc_cpufreq.c -@@ -28,6 +28,9 @@ - - static struct cpufreq_driver cppc_cpufreq_driver; - -+/* Autonomous Selection boot parameter */ -+static bool auto_sel_mode; -+ - #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE - static enum { - FIE_UNSET = -1, -@@ -668,6 +671,14 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) - caps = &cpu_data->perf_caps; - policy->driver_data = cpu_data; - -+ /* -+ * Enable CPPC for both OS-driven and autonomous modes. -+ * The Enable register is optional - some platforms may not support it -+ */ -+ ret = cppc_set_enable(cpu, true); -+ if (ret && ret != -EOPNOTSUPP) -+ pr_warn("Failed to enable CPPC for CPU%d (%d)\n", cpu, ret); -+ - /* - * Set min to lowest nonlinear perf to avoid any efficiency penalty (see - * Section 8.4.7.1.1.5 of ACPI 6.1 spec) -@@ -720,11 +731,71 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) - policy->cur = cppc_perf_to_khz(caps, caps->highest_perf); - cpu_data->perf_ctrls.desired_perf = caps->highest_perf; - -- ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); -- if (ret) { -- pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", -- caps->highest_perf, cpu, ret); -- goto out; -+ /* -+ * Enable autonomous mode on first init if boot param is set. -+ * Check last_governor to detect first init and skip if auto_sel -+ * is already enabled. -+ */ -+ if (auto_sel_mode && policy->last_governor[0] == '\0' && -+ !cpu_data->perf_ctrls.auto_sel) { -+ /* Init min/max_perf from caps if not already set by HW. */ -+ if (!cpu_data->perf_ctrls.min_perf) -+ cpu_data->perf_ctrls.min_perf = caps->lowest_nonlinear_perf; -+ if (!cpu_data->perf_ctrls.max_perf) -+ cpu_data->perf_ctrls.max_perf = policy->boost_enabled ? -+ caps->highest_perf : caps->nominal_perf; -+ -+ cpu_data->perf_ctrls.desired_perf = -+ clamp_t(u32, cpu_data->perf_ctrls.desired_perf, -+ cpu_data->perf_ctrls.min_perf, -+ cpu_data->perf_ctrls.max_perf); -+ -+ policy->cur = cppc_perf_to_khz(caps, -+ cpu_data->perf_ctrls.desired_perf); -+ -+ /* EPP is optional - some platforms may not support it */ -+ ret = cppc_set_epp(cpu, CPPC_EPP_PERFORMANCE_PREF); -+ if (ret && ret != -EOPNOTSUPP) -+ pr_warn("Failed to set EPP for CPU%d (%d)\n", cpu, ret); -+ else if (!ret) -+ cpu_data->perf_ctrls.energy_perf = CPPC_EPP_PERFORMANCE_PREF; -+ -+ /* Program min/max/desired into CPPC regs before enabling auto_sel. */ -+ ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); -+ if (ret) { -+ pr_debug("Err setting perf for autonomous mode CPU:%d ret:%d\n", -+ cpu, ret); -+ goto out; -+ } -+ -+ ret = cppc_set_auto_sel(cpu, true); -+ if (ret && ret != -EOPNOTSUPP) { -+ pr_warn("Failed autonomous config for CPU%d (%d)\n", -+ cpu, ret); -+ goto out; -+ } -+ if (!ret) -+ cpu_data->perf_ctrls.auto_sel = true; -+ } -+ -+ if (cpu_data->perf_ctrls.auto_sel) { -+ /* Sync policy limits from HW when autonomous mode is active */ -+ policy->min = cppc_perf_to_khz(caps, -+ cpu_data->perf_ctrls.min_perf ?: -+ caps->lowest_nonlinear_perf); -+ policy->max = cppc_perf_to_khz(caps, -+ cpu_data->perf_ctrls.max_perf ?: -+ (policy->boost_enabled ? -+ caps->highest_perf : -+ caps->nominal_perf)); -+ } else { -+ /* Normal mode: governors control frequency */ -+ ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); -+ if (ret) { -+ pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n", -+ caps->highest_perf, cpu, ret); -+ goto out; -+ } - } - - cppc_cpufreq_cpu_fie_init(policy); -@@ -1071,10 +1142,18 @@ static int __init cppc_cpufreq_init(void) - - static void __exit cppc_cpufreq_exit(void) - { -+ unsigned int cpu; -+ -+ for_each_present_cpu(cpu) -+ cppc_set_auto_sel(cpu, false); -+ - cpufreq_unregister_driver(&cppc_cpufreq_driver); - cppc_freq_invariance_exit(); - } - -+module_param(auto_sel_mode, bool, 0444); -+MODULE_PARM_DESC(auto_sel_mode, "Enable CPPC autonomous performance selection at boot"); -+ - module_exit(cppc_cpufreq_exit); - MODULE_AUTHOR("Ashwin Chaugule"); - MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec"); -From 001906837272abbc8d210ffb79a415280705ca3e Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Wed, 26 Aug 2026 20:04:48 -0700 -Subject: [PATCH] NVIDIA: SAUCE: watchdog: sbsa_gwdt: stop the watchdog across - the whole system-sleep transition - -BugLink: https://bugs.launchpad.net/bugs/2166302 - -The driver stops a running watchdog in its own device suspend callback -and restarts it in its resume callback. That leaves the watchdog armed, -with nobody refreshing it, for the entire early part of suspend entry: -userspace freeze, kernel thread freeze, and every device suspend -callback that runs before this device's own. The same window exists at -the tail end of resume. - -When the watchdog is running from boot (early_enable=1, previously -force_enable=1 downstream; 10 s default timeout) and any device stalls -its suspend callback past the timeout, the watchdog resets the system -in the middle of suspend entry. On an arm64 laptop platform this fired -on about 7% of suspend attempts in a randomized stress run (9 resets in -124 suspends; the serial console shows the board dropping into the boot -ROM mid-entry with the watchdog reset status set in NONRST_REG2). Two -elimination runs confirm the mechanism: the identical stress matrix -with the parameter off produced zero resets in 118 suspends, and with -the first version of this change (notifier plus the original device -callbacks) applied and the watchdog force-enabled, zero resets in 198 -suspends across four runs (the baseline rate predicts about 14). - -Stop the watchdog from a PM notifier at the *_PREPARE events, before -tasks are frozen and device callbacks run, and restart it at the -PM_POST_* events, after everything has resumed. The driver state -(hw_armed, sleeping) lives under a lock shared with the watchdog ops: -ops->stop clears hw_armed and stops the hardware, so a userspace stop -or magic close after thaw wins over the PM_POST_* restart; ops->start -sets hw_armed but leaves the hardware stopped while sleeping is set, so -a start during the transition is deferred to PM_POST_* instead of -arming hardware nobody can refresh. The transition is recorded at -*_PREPARE whether or not the watchdog was armed at that point. - -The sleep notifier is registered once, at driver init, before the -platform driver, so a probe that runs while the driver is loaded finds -a transition already recorded, whatever its interleaving with -*_PREPARE: the transition flag is global, and the probe adopts the -firmware WCS state into hw_armed, applies the flag (stopping a -firmware-started watchdog at once) and joins the instance list in one -critical section. A built-in driver therefore has no probe window at -all. What remains is the driver being loaded after PM_SUSPEND_PREPARE -has run. For that, when pm_suspend_in_progress() reports a suspend -already past task freezing, the probe records the transition itself, -under the lock, and the PM_POST_SUSPEND that always follows arms the -hardware again (the hibernation counterpart is not used: it stays true -past PM_POST_HIBERNATION and would record a transition nobody ends). -The device ->prepare callback, which the PM core runs after waiting -for outstanding probes and before any device suspend callback, applies -the same idempotent stop as the final guard for a module inserted -between *_PREPARE and the end of task freezing, or during hibernation -entry; that is the remaining exposure, and it ends before any device -suspend callback runs. No device callback re-arms the hardware: -PM_POST_* is the only restart point. A probe that fails, or an unbind, -removes the instance from the list and re-applies hw_armed to the -hardware, so a firmware-started watchdog stopped by *_PREPARE is left -as found (armed) instead of silently disabled. - -Validation: the first version (notifier plus the original device -callbacks) is the one behind the 198-suspend elimination run above. The -v4 state machine (this locking and deferral, without the probe-time -adoption, the driver-init notifier and the ->prepare fallback, which a -suspend loop does not exercise) ran a further 120 suspends (60 s2idle, -60 S3, randomized order, watchdog force-enabled from boot, console -recorded through every entry) with zero resets, where the baseline rate -predicts 8 to 9. This version is compile tested (arm64, W=1, checkpatch -clean in strict mode). - -This is also upstream-relevant as a companion to the early_enable -parameter: the armed-during-entry window exists for any system running -the SBSA watchdog from boot. - -(backported from https://lore.kernel.org/r/20260912182107.1156221-1-dcemin@nvidia.com) -[dcemin: v8 of the posted v1, see the version paragraph above for the delta] -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/watchdog/sbsa_gwdt.c | 264 ++++++++++++++++++++++++++++++----- - 1 file changed, 231 insertions(+), 33 deletions(-) - -diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c -index e04d42cc77..a2548822b1 100644 ---- a/drivers/watchdog/sbsa_gwdt.c -+++ b/drivers/watchdog/sbsa_gwdt.c -@@ -43,9 +43,13 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -87,6 +91,10 @@ - * indicate whether to adjust wdd->timeout to avoid a race with WS0 - * @refresh_base: Virtual address of the watchdog refresh frame - * @control_base: Virtual address of the watchdog control frame -+ * @node: Entry in the list of instances the sleep notifier owns -+ * @hw_armed: The watchdog is logically running (started by firmware, -+ * early_enable or userspace); the hardware follows it except -+ * while a system sleep transition is in progress - */ - struct sbsa_gwdt { - struct watchdog_device wdd; -@@ -95,8 +103,20 @@ struct sbsa_gwdt { - bool need_ws0_race_workaround; - void __iomem *refresh_base; - void __iomem *control_base; -+ struct list_head node; -+ bool hw_armed; - }; - -+/* -+ * System sleep state shared by all instances. The notifier recording a -+ * transition is registered once, at driver init, before any device can be -+ * probed, so a probe at any later point finds the transition already -+ * recorded instead of racing its own registration against *_PREPARE. -+ */ -+static LIST_HEAD(sbsa_gwdt_list); -+static DEFINE_SPINLOCK(sbsa_gwdt_lock); /* list, sleeping, hw_armed */ -+static bool sbsa_gwdt_sleeping; -+ - #define DEFAULT_TIMEOUT 10 /* seconds */ - - static unsigned int timeout; -@@ -244,12 +264,33 @@ static void sbsa_gwdt_get_version(struct watchdog_device *wdd) - !action && (impl == SBSA_GWDT_IMPL_MEDIATEK); - } - -+static void sbsa_gwdt_hw_start(struct sbsa_gwdt *gwdt) -+{ -+ /* writing WCS will cause an explicit watchdog refresh */ -+ writel(SBSA_GWDT_WCS_EN, gwdt->control_base + SBSA_GWDT_WCS); -+} -+ -+static void sbsa_gwdt_hw_stop(struct sbsa_gwdt *gwdt) -+{ -+ /* Simply write 0 to WCS to clean WCS_EN bit */ -+ writel(0, gwdt->control_base + SBSA_GWDT_WCS); -+} -+ - static int sbsa_gwdt_start(struct watchdog_device *wdd) - { - struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd); -+ unsigned long flags; - -- /* writing WCS will cause an explicit watchdog refresh */ -- writel(SBSA_GWDT_WCS_EN, gwdt->control_base + SBSA_GWDT_WCS); -+ spin_lock_irqsave(&sbsa_gwdt_lock, flags); -+ gwdt->hw_armed = true; -+ /* -+ * While a system sleep transition is in progress nobody can refresh -+ * the watchdog: leave the hardware stopped and let the PM_POST_* -+ * notifier arm it once everything has resumed. -+ */ -+ if (!sbsa_gwdt_sleeping) -+ sbsa_gwdt_hw_start(gwdt); -+ spin_unlock_irqrestore(&sbsa_gwdt_lock, flags); - - return 0; - } -@@ -257,9 +298,12 @@ static int sbsa_gwdt_start(struct watchdog_device *wdd) - static int sbsa_gwdt_stop(struct watchdog_device *wdd) - { - struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd); -+ unsigned long flags; - -- /* Simply write 0 to WCS to clean WCS_EN bit */ -- writel(0, gwdt->control_base + SBSA_GWDT_WCS); -+ spin_lock_irqsave(&sbsa_gwdt_lock, flags); -+ gwdt->hw_armed = false; -+ sbsa_gwdt_hw_stop(gwdt); -+ spin_unlock_irqrestore(&sbsa_gwdt_lock, flags); - - return 0; - } -@@ -288,12 +332,133 @@ static const struct watchdog_ops sbsa_gwdt_ops = { - .get_timeleft = sbsa_gwdt_get_timeleft, - }; - -+/* -+ * Per-device suspend/resume callbacks alone would stop the watchdog only -+ * once this device itself is suspended, one of the last steps of suspend -+ * entry, and restart it during device resume, before tasks are thawed. A -+ * watchdog running from boot (early_enable) would therefore be armed, with -+ * nobody refreshing it, through task freezing and every other device's -+ * suspend callback on the way down, and again from device resume until -+ * userspace runs on the way up; anything stalling past the timeout in -+ * either window resets the system. -+ * -+ * Own the transition from a PM notifier instead: stop at the *_PREPARE -+ * events, before anything is frozen, and restart at PM_POST_*, after -+ * everything has resumed. The state (hw_armed per instance, one sleeping -+ * flag) is kept under a lock shared with the watchdog ops so that a -+ * userspace stop or magic close after thaw cannot race the restart, and a -+ * start requested while the transition is in progress is deferred to -+ * PM_POST_*. The transition is recorded at *_PREPARE whether or not the -+ * watchdog was armed at that moment, so a start between *_PREPARE and -+ * task freezing is deferred as well instead of arming hardware nobody -+ * refreshes. -+ * -+ * The notifier is registered at driver init, so a probe that runs while -+ * the driver is loaded finds a transition already recorded, whatever its -+ * interleaving with *_PREPARE, and applies it when it adopts the hardware -+ * state. What remains is the driver being loaded after PM_SUSPEND_PREPARE -+ * has run: the probe then checks for a suspend already past task freezing -+ * and stops the hardware itself, and the device ->prepare callback, which -+ * the PM core runs after waiting for outstanding probes and before any -+ * device suspend callback, applies the same stop. Neither has a resume -+ * counterpart: PM_POST_* is the only place that re-arms the hardware. -+ */ -+static void sbsa_gwdt_sleep_stop(void) -+{ -+ struct sbsa_gwdt *gwdt; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sbsa_gwdt_lock, flags); -+ /* -+ * Idempotent on purpose: the *_PREPARE notifier and the device -+ * ->prepare callback both land here, and a probe that adopted a -+ * firmware-armed watchdog after *_PREPARE relies on a later call -+ * actually stopping the hardware. -+ */ -+ sbsa_gwdt_sleeping = true; -+ list_for_each_entry(gwdt, &sbsa_gwdt_list, node) -+ if (gwdt->hw_armed) -+ sbsa_gwdt_hw_stop(gwdt); -+ spin_unlock_irqrestore(&sbsa_gwdt_lock, flags); -+} -+ -+static void sbsa_gwdt_sleep_restart(void) -+{ -+ struct sbsa_gwdt *gwdt; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sbsa_gwdt_lock, flags); -+ if (sbsa_gwdt_sleeping) { -+ sbsa_gwdt_sleeping = false; -+ list_for_each_entry(gwdt, &sbsa_gwdt_list, node) -+ if (gwdt->hw_armed) -+ sbsa_gwdt_hw_start(gwdt); -+ } -+ spin_unlock_irqrestore(&sbsa_gwdt_lock, flags); -+} -+ -+static int sbsa_gwdt_pm_notify(struct notifier_block *nb, unsigned long mode, -+ void *data) -+{ -+ switch (mode) { -+ case PM_SUSPEND_PREPARE: -+ case PM_HIBERNATION_PREPARE: -+ case PM_RESTORE_PREPARE: -+ sbsa_gwdt_sleep_stop(); -+ break; -+ case PM_POST_SUSPEND: -+ case PM_POST_HIBERNATION: -+ case PM_POST_RESTORE: -+ sbsa_gwdt_sleep_restart(); -+ break; -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block sbsa_gwdt_pm_nb = { -+ .notifier_call = sbsa_gwdt_pm_notify, -+}; -+ -+static void sbsa_gwdt_remove_instance(void *data) -+{ -+ struct sbsa_gwdt *gwdt = data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sbsa_gwdt_lock, flags); -+ list_del(&gwdt->node); -+ /* -+ * PM_POST_* no longer applies to this instance. If a transition -+ * stopped the hardware, put it back into the state the last start or -+ * stop asked for, so a probe that fails while the system heads into -+ * sleep does not leave a firmware-started watchdog silently disabled; -+ * without a driver such a watchdog is armed and unrefreshed whether -+ * or not a transition is in progress, exactly as a probe failure -+ * outside a transition leaves it. -+ */ -+ if (sbsa_gwdt_sleeping && gwdt->hw_armed) -+ sbsa_gwdt_hw_start(gwdt); -+ spin_unlock_irqrestore(&sbsa_gwdt_lock, flags); -+} -+ -+static int sbsa_gwdt_prepare(struct device *dev) -+{ -+ sbsa_gwdt_sleep_stop(); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops sbsa_gwdt_pm_ops = { -+ .prepare = pm_sleep_ptr(sbsa_gwdt_prepare), -+}; -+ - static int sbsa_gwdt_probe(struct platform_device *pdev) - { - void __iomem *rf_base, *cf_base; - struct device *dev = &pdev->dev; - struct watchdog_device *wdd; - struct sbsa_gwdt *gwdt; -+ unsigned long flags; - int ret, irq; - u32 status; - -@@ -318,6 +483,34 @@ static int sbsa_gwdt_probe(struct platform_device *pdev) - gwdt->clk = arch_timer_get_cntfrq(); - gwdt->refresh_base = rf_base; - gwdt->control_base = cf_base; -+ status = readl(cf_base + SBSA_GWDT_WCS); -+ -+ /* -+ * Adopt the firmware state and join the list under the lock: a -+ * transition the notifier has already recorded applies to this -+ * instance at once, and a *_PREPARE landing after this point finds -+ * hw_armed set. pm_suspend_in_progress() covers the driver being -+ * loaded after PM_SUSPEND_PREPARE ran: it is true from the end of -+ * task freezing until the devices have resumed, and PM_POST_SUSPEND -+ * always follows its clearing, so a transition seen here is one the -+ * notifier will see the end of; read under the lock, a PM_POST_SUSPEND -+ * racing it finds the flag set. The hibernation counterpart stays -+ * true past PM_POST_HIBERNATION and would record a transition nobody -+ * ends, so that case, like the interval between *_PREPARE and the end -+ * of task freezing, relies on the device ->prepare callback instead. -+ */ -+ spin_lock_irqsave(&sbsa_gwdt_lock, flags); -+ gwdt->hw_armed = !!(status & SBSA_GWDT_WCS_EN); -+ if (pm_suspend_in_progress()) -+ sbsa_gwdt_sleeping = true; -+ if (sbsa_gwdt_sleeping && gwdt->hw_armed) -+ sbsa_gwdt_hw_stop(gwdt); -+ list_add(&gwdt->node, &sbsa_gwdt_list); -+ spin_unlock_irqrestore(&sbsa_gwdt_lock, flags); -+ -+ ret = devm_add_action_or_reset(dev, sbsa_gwdt_remove_instance, gwdt); -+ if (ret) -+ return ret; - - wdd = &gwdt->wdd; - wdd->parent = dev; -@@ -342,11 +535,15 @@ static int sbsa_gwdt_probe(struct platform_device *pdev) - wdd->min_timeout = 3; - } - -- status = readl(cf_base + SBSA_GWDT_WCS); - if (status & SBSA_GWDT_WCS_WS1) { - dev_warn(dev, "System reset by WDT.\n"); - wdd->bootstatus |= WDIOF_CARDRESET; - } -+ /* -+ * hw_armed already reflects WCS_EN (adopted above, under the lock); -+ * a transition recorded before or since has stopped the hardware -+ * and PM_POST_* re-arms it. -+ */ - if (status & SBSA_GWDT_WCS_EN) - set_bit(WDOG_HW_RUNNING, &wdd->status); - -@@ -398,32 +595,6 @@ static int sbsa_gwdt_probe(struct platform_device *pdev) - return 0; - } - --/* Disable watchdog if it is active during suspend */ --static int __maybe_unused sbsa_gwdt_suspend(struct device *dev) --{ -- struct sbsa_gwdt *gwdt = dev_get_drvdata(dev); -- -- if (watchdog_hw_running(&gwdt->wdd)) -- sbsa_gwdt_stop(&gwdt->wdd); -- -- return 0; --} -- --/* Enable watchdog if necessary */ --static int __maybe_unused sbsa_gwdt_resume(struct device *dev) --{ -- struct sbsa_gwdt *gwdt = dev_get_drvdata(dev); -- -- if (watchdog_hw_running(&gwdt->wdd)) -- sbsa_gwdt_start(&gwdt->wdd); -- -- return 0; --} -- --static const struct dev_pm_ops sbsa_gwdt_pm_ops = { -- SET_SYSTEM_SLEEP_PM_OPS(sbsa_gwdt_suspend, sbsa_gwdt_resume) --}; -- - static const struct of_device_id sbsa_gwdt_of_match[] = { - { .compatible = "arm,sbsa-gwdt", }, - {}, -@@ -439,14 +610,41 @@ MODULE_DEVICE_TABLE(platform, sbsa_gwdt_pdev_match); - static struct platform_driver sbsa_gwdt_driver = { - .driver = { - .name = DRV_NAME, -- .pm = &sbsa_gwdt_pm_ops, -+ .pm = pm_sleep_ptr(&sbsa_gwdt_pm_ops), - .of_match_table = sbsa_gwdt_of_match, - }, - .probe = sbsa_gwdt_probe, - .id_table = sbsa_gwdt_pdev_match, - }; - --module_platform_driver(sbsa_gwdt_driver); -+static int __init sbsa_gwdt_init(void) -+{ -+ int ret; -+ -+ /* -+ * Register the sleep notifier before any device can be probed, so -+ * that every transition from here on is recorded before a probe -+ * adopts a running watchdog. Its failure is fatal: without it a -+ * running watchdog would survive into system sleep unrefreshed. -+ */ -+ ret = register_pm_notifier(&sbsa_gwdt_pm_nb); -+ if (ret) -+ return ret; -+ -+ ret = platform_driver_register(&sbsa_gwdt_driver); -+ if (ret) -+ unregister_pm_notifier(&sbsa_gwdt_pm_nb); -+ -+ return ret; -+} -+module_init(sbsa_gwdt_init); -+ -+static void __exit sbsa_gwdt_exit(void) -+{ -+ platform_driver_unregister(&sbsa_gwdt_driver); -+ unregister_pm_notifier(&sbsa_gwdt_pm_nb); -+} -+module_exit(sbsa_gwdt_exit); - - MODULE_DESCRIPTION("SBSA Generic Watchdog Driver"); - MODULE_AUTHOR("Fu Wei "); -From e95f46e4c0e86d36c5c195e5707c4c649c90c955 Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Sat, 6 Jun 2026 08:51:52 -0700 -Subject: [PATCH] NVIDIA: SAUCE: pmdomain: Store cached power-down state index - as an unsigned int - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -genpd caches the state index selected by the governor so the next -power-down decision can reuse it while constraints remain unchanged. - -The cache currently stores the index in a bool, truncating every index -above 1. Use unsigned int to match generic_pm_domain.state_idx and preserve -the complete selected index. Domains that only select state 0 or 1 are -unchanged. - -Fixes: e94999688e3a ("PM / Domains: Add genpd governor for CPUs") -Signed-off-by: Bharat Dintakurti -Signed-off-by: Ishan Shah -Reviewed-by: Ishan Shah -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - include/linux/pm_domain.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h -index f925614aeb..103e74486e 100644 ---- a/include/linux/pm_domain.h -+++ b/include/linux/pm_domain.h -@@ -171,7 +171,7 @@ struct genpd_governor_data { - ktime_t last_enter; - bool reflect_residency; - bool cached_power_down_ok; -- bool cached_power_down_state_idx; -+ unsigned int cached_power_down_state_idx; - }; - - struct genpd_power_state { -From f2f87aa6aa27401510455298e9fcbea2df78bc35 Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Mon, 29 Jun 2026 21:36:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: sched: idle: Treat wakeup no-constraint as - unbounded - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -The CPU wakeup latency QoS no-constraint value is a sentinel, not a finite -latency budget. When entering s2idle, use U64_MAX for cpuidle state -selection if no CPU wakeup latency constraint is active. - -This preserves finite constraints while avoiding rejection of states with -firmware-provided latency values larger than S32_MAX usec. - -Signed-off-by: Bharat Dintakurti -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - kernel/sched/idle.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c -index 052435f4d3..056245ae17 100644 ---- a/kernel/sched/idle.c -+++ b/kernel/sched/idle.c -@@ -7,6 +7,7 @@ - * tasks which are handled in sched/fair.c ) - */ - #include -+#include - #include - #include - #include "sched.h" -@@ -214,8 +215,14 @@ static void cpuidle_idle_call(bool stop_tick) - u64 max_latency_ns; - - if (idle_should_enter_s2idle()) { -- max_latency_ns = cpu_wakeup_latency_qos_limit() * -- NSEC_PER_USEC; -+ s32 latency_limit_us = cpu_wakeup_latency_qos_limit(); -+ -+ if (latency_limit_us == -+ PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) -+ max_latency_ns = U64_MAX; -+ else -+ max_latency_ns = (u64)latency_limit_us * -+ NSEC_PER_USEC; - - entered_state = call_cpuidle_s2idle(drv, dev, - max_latency_ns); -From b6667ee782222e44e85d9f3f662d3bc9900d4852 Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Tue, 1 Sep 2026 22:48:30 +0000 -Subject: [PATCH] NVIDIA: SAUCE: pmdomain: Treat unconstrained CPU wake latency - as unlimited - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -cpu_system_power_down_ok() converts the CPU resume-latency QoS value to -nanoseconds before comparing it with genpd state latency. However, -PM_QOS_RESUME_LATENCY_NO_CONSTRAINT is a sentinel rather than a finite -microsecond limit. Treating it as an ordinary value can reject a valid -state whose combined latency is larger than the converted sentinel. - -Detect the sentinel before conversion and allow any state latency when no -constraint is present. Continue enforcing zero and finite latency requests -normally. - -Fixes: 8e7de6dc4209 ("pmdomain: Respect the CPU system wakeup QoS limit for s2idle") -Signed-off-by: Bharat Dintakurti -Signed-off-by: Ishan Shah -Reviewed-by: Ishan Shah -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/pmdomain/governor.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/drivers/pmdomain/governor.c b/drivers/pmdomain/governor.c -index 96737abbb4..fc86190ca8 100644 ---- a/drivers/pmdomain/governor.c -+++ b/drivers/pmdomain/governor.c -@@ -427,8 +427,10 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd) - - static bool cpu_system_power_down_ok(struct dev_pm_domain *pd) - { -- s64 constraint_ns = cpu_wakeup_latency_qos_limit() * NSEC_PER_USEC; - struct generic_pm_domain *genpd = pd_to_genpd(pd); -+ s32 constraint_us = cpu_wakeup_latency_qos_limit(); -+ bool no_constraint; -+ s64 constraint_ns; - int state_idx = genpd->state_count - 1; - - if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN)) { -@@ -436,12 +438,17 @@ static bool cpu_system_power_down_ok(struct dev_pm_domain *pd) - return true; - } - -+ no_constraint = constraint_us == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; -+ constraint_ns = no_constraint ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS : -+ (s64)constraint_us * NSEC_PER_USEC; -+ - /* Find the deepest state for the latency constraint. */ - while (state_idx >= 0) { - s64 latency_ns = genpd->states[state_idx].power_off_latency_ns + - genpd->states[state_idx].power_on_latency_ns; - -- if (latency_ns <= constraint_ns) { -+ /* The no-constraint value is a sentinel, not a latency budget. */ -+ if (no_constraint || latency_ns <= constraint_ns) { - genpd->state_idx = state_idx; - return true; - } -From e67b10d0eb72bb9885b8b6d953c12b7db7e31ec7 Mon Sep 17 00:00:00 2001 -From: Ishan Shah -Date: Fri, 4 Sep 2026 21:11:55 +0000 -Subject: [PATCH] NVIDIA: SAUCE: pmdomain: Correct rejected idle-state - accounting - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -pm_genpd_inc_rejected() accepts the state index whose asynchronous -power-off attempt failed, but updates the domain current state index -instead. The current index may have changed before the correction runs, -causing the wrong usage and rejected counters to be adjusted. - -The helper also leaves usage_s2idle incremented when a suspend-to-idle -entry fails. Accept the entry context from callers, use the supplied index, -and undo the s2idle counter when genpd incremented it. Reject an -out-of-range index before accessing the state table. - -Fixes: 9861f21ff16b ("pmdomain: core: Add genpd helper to correct the usage/rejected counters") -Signed-off-by: Ishan Shah -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/cpuidle/cpuidle-psci.c | 2 +- - drivers/pmdomain/core.c | 14 +++++++++++--- - include/linux/pm_domain.h | 4 ++-- - 3 files changed, 14 insertions(+), 6 deletions(-) - -diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c -index b250d0dde7..009bbedcd9 100644 ---- a/drivers/cpuidle/cpuidle-psci.c -+++ b/drivers/cpuidle/cpuidle-psci.c -@@ -99,7 +99,7 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev, - - /* Correct domain-idlestate statistics if we failed to enter. */ - if (ret == -1 && ds->state) -- pm_genpd_inc_rejected(ds->pd, ds->state_idx); -+ pm_genpd_inc_rejected(ds->pd, ds->state_idx, s2idle); - - /* Clear the domain state to start fresh when back from idle. */ - psci_clear_domain_state(); -diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c -index 842c4169e2..51ed2b4a8e 100644 ---- a/drivers/pmdomain/core.c -+++ b/drivers/pmdomain/core.c -@@ -803,6 +803,7 @@ EXPORT_SYMBOL_GPL(dev_pm_genpd_is_on); - * - * @genpd: The PM domain the idle-state belongs to. - * @state_idx: The index of the idle-state that failed. -+ * @s2idle: Whether the failed attempt was made for suspend-to-idle. - * - * In some special cases the ->power_off() callback is asynchronously powering - * off the PM domain, leading to that it may return zero to indicate success, -@@ -814,11 +815,18 @@ EXPORT_SYMBOL_GPL(dev_pm_genpd_is_on); - * while this routine is getting called. - */ - void pm_genpd_inc_rejected(struct generic_pm_domain *genpd, -- unsigned int state_idx) -+ unsigned int state_idx, bool s2idle) - { - genpd_lock(genpd); -- genpd->states[genpd->state_idx].rejected++; -- genpd->states[genpd->state_idx].usage--; -+ if (WARN_ON_ONCE(state_idx >= genpd->state_count)) -+ goto out; -+ -+ genpd->states[state_idx].rejected++; -+ genpd->states[state_idx].usage--; -+ if (s2idle && genpd->gov && genpd->gov->system_power_down_ok) -+ genpd->states[state_idx].usage_s2idle--; -+ -+out: - genpd_unlock(genpd); - } - EXPORT_SYMBOL_GPL(pm_genpd_inc_rejected); -diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h -index 103e74486e..0208d6c85d 100644 ---- a/include/linux/pm_domain.h -+++ b/include/linux/pm_domain.h -@@ -319,7 +319,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd, - struct dev_power_governor *gov, bool is_off); - int pm_genpd_remove(struct generic_pm_domain *genpd); - void pm_genpd_inc_rejected(struct generic_pm_domain *genpd, -- unsigned int state_idx); -+ unsigned int state_idx, bool s2idle); - struct device *dev_to_genpd_dev(struct device *dev); - int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state); - int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb); -@@ -373,7 +373,7 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd) - } - - static inline void pm_genpd_inc_rejected(struct generic_pm_domain *genpd, -- unsigned int state_idx) -+ unsigned int state_idx, bool s2idle) - { } - - static inline struct device *dev_to_genpd_dev(struct device *dev) -From cc2be96ae537fdd0eb6211a0fa3065b5e1444e61 Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Tue, 15 Sep 2026 18:04:27 +0000 -Subject: [PATCH] NVIDIA: SAUCE: pmdomain: Distinguish s2idle state usage - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -Synchronous genpd power-off is used for more than suspend-to-idle. -System-sleep and PREEMPT_RT CPU-hotplug paths also use -dev_pm_genpd_suspend(), so inferring the accounting context from the -presence of a system_power_down_ok() callback classifies those transitions -as s2idle. - -Add an explicit s2idle variant of the suspend helper and propagate that -context through synchronous parent power-off. Keep the existing helper as -the non-s2idle path, update the PSCI and RISC-V SBI s2idle callers, and use -the same explicit context when correcting a rejected selection. - -Co-developed-by: Ishan Shah -Signed-off-by: Ishan Shah -Signed-off-by: Bharat Dintakurti -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/cpuidle/cpuidle-psci.c | 2 +- - drivers/cpuidle/cpuidle-riscv-sbi.c | 2 +- - drivers/pmdomain/core.c | 41 ++++++++++++++++++----------- - include/linux/pm_domain.h | 2 ++ - 4 files changed, 29 insertions(+), 18 deletions(-) - -diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c -index 009bbedcd9..1562a5b09d 100644 ---- a/drivers/cpuidle/cpuidle-psci.c -+++ b/drivers/cpuidle/cpuidle-psci.c -@@ -78,7 +78,7 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev, - - /* Do runtime PM to manage a hierarchical CPU toplogy. */ - if (s2idle) -- dev_pm_genpd_suspend(pd_dev); -+ dev_pm_genpd_suspend_s2idle(pd_dev); - else - pm_runtime_put_sync_suspend(pd_dev); - -diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c -index a13e90bb43..a84085a285 100644 ---- a/drivers/cpuidle/cpuidle-riscv-sbi.c -+++ b/drivers/cpuidle/cpuidle-riscv-sbi.c -@@ -104,7 +104,7 @@ static __cpuidle int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, - - /* Do runtime PM to manage a hierarchical CPU toplogy. */ - if (s2idle) -- dev_pm_genpd_suspend(pd_dev); -+ dev_pm_genpd_suspend_s2idle(pd_dev); - else - pm_runtime_put_sync_suspend(pd_dev); - -diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c -index 51ed2b4a8e..230c7f34a1 100644 ---- a/drivers/pmdomain/core.c -+++ b/drivers/pmdomain/core.c -@@ -823,7 +823,7 @@ void pm_genpd_inc_rejected(struct generic_pm_domain *genpd, - - genpd->states[state_idx].rejected++; - genpd->states[state_idx].usage--; -- if (s2idle && genpd->gov && genpd->gov->system_power_down_ok) -+ if (s2idle) - genpd->states[state_idx].usage_s2idle--; - - out: -@@ -1400,6 +1400,7 @@ late_initcall_sync(genpd_power_off_unused); - * genpd_sync_power_off - Synchronously power off a PM domain and its parents. - * @genpd: PM domain to power off, if possible. - * @use_lock: use the lock. -+ * @s2idle: account successful state selection as suspend-to-idle. - * @depth: nesting count for lockdep. - * - * Check if the given PM domain can be powered off (during system suspend or -@@ -1410,7 +1411,7 @@ late_initcall_sync(genpd_power_off_unused); - * these cases the lock must be held. - */ - static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, -- unsigned int depth) -+ bool s2idle, unsigned int depth) - { - struct gpd_link *link; - -@@ -1442,11 +1443,7 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, - } else { - genpd->states[genpd->state_idx].usage++; - -- /* -- * The ->system_power_down_ok() callback is currently used only -- * for s2idle. Use it to know when to update the usage counter. -- */ -- if (genpd->gov && genpd->gov->system_power_down_ok) -+ if (s2idle) - genpd->states[genpd->state_idx].usage_s2idle++; - } - -@@ -1458,7 +1455,8 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, - if (use_lock) - genpd_lock_nested(link->parent, depth + 1); - -- genpd_sync_power_off(link->parent, use_lock, depth + 1); -+ genpd_sync_power_off(link->parent, use_lock, s2idle, -+ depth + 1); - - if (use_lock) - genpd_unlock(link->parent); -@@ -1576,7 +1574,7 @@ static int genpd_finish_suspend(struct device *dev, - - genpd_lock(genpd); - genpd->suspended_count++; -- genpd_sync_power_off(genpd, true, 0); -+ genpd_sync_power_off(genpd, true, false, 0); - genpd_unlock(genpd); - - return 0; -@@ -1742,7 +1740,7 @@ static void genpd_complete(struct device *dev) - genpd_unlock(genpd); - } - --static void genpd_switch_state(struct device *dev, bool suspend) -+static void genpd_switch_state(struct device *dev, bool suspend, bool s2idle) - { - struct generic_pm_domain *genpd; - bool use_lock; -@@ -1758,7 +1756,7 @@ static void genpd_switch_state(struct device *dev, bool suspend) - - if (suspend) { - genpd->suspended_count++; -- genpd_sync_power_off(genpd, use_lock, 0); -+ genpd_sync_power_off(genpd, use_lock, s2idle, 0); - } else { - genpd_sync_power_on(genpd, use_lock, 0); - genpd->suspended_count--; -@@ -1773,16 +1771,27 @@ static void genpd_switch_state(struct device *dev, bool suspend) - * @dev: The device that is attached to the genpd, that can be suspended. - * - * This routine should typically be called for a device that needs to be -- * suspended during the syscore suspend phase. It may also be called during -- * suspend-to-idle to suspend a corresponding CPU device that is attached to a -- * genpd. -+ * suspended during the syscore suspend phase. - */ - void dev_pm_genpd_suspend(struct device *dev) - { -- genpd_switch_state(dev, true); -+ genpd_switch_state(dev, true, false); - } - EXPORT_SYMBOL_GPL(dev_pm_genpd_suspend); - -+/** -+ * dev_pm_genpd_suspend_s2idle - Suspend the genpd for @dev during s2idle -+ * @dev: The device that is attached to the genpd, that can be suspended. -+ * -+ * This is equivalent to dev_pm_genpd_suspend(), but records successful domain -+ * state selections as suspend-to-idle entries. -+ */ -+void dev_pm_genpd_suspend_s2idle(struct device *dev) -+{ -+ genpd_switch_state(dev, true, true); -+} -+EXPORT_SYMBOL_GPL(dev_pm_genpd_suspend_s2idle); -+ - /** - * dev_pm_genpd_resume - Synchronously try to resume the genpd for @dev - * @dev: The device that is attached to the genpd, which needs to be resumed. -@@ -1793,7 +1802,7 @@ EXPORT_SYMBOL_GPL(dev_pm_genpd_suspend); - */ - void dev_pm_genpd_resume(struct device *dev) - { -- genpd_switch_state(dev, false); -+ genpd_switch_state(dev, false, false); - } - EXPORT_SYMBOL_GPL(dev_pm_genpd_resume); - -diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h -index 0208d6c85d..4ac6005610 100644 ---- a/include/linux/pm_domain.h -+++ b/include/linux/pm_domain.h -@@ -434,9 +434,11 @@ static inline bool dev_pm_genpd_is_on(struct device *dev) - - #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP - void dev_pm_genpd_suspend(struct device *dev); -+void dev_pm_genpd_suspend_s2idle(struct device *dev); - void dev_pm_genpd_resume(struct device *dev); - #else - static inline void dev_pm_genpd_suspend(struct device *dev) {} -+static inline void dev_pm_genpd_suspend_s2idle(struct device *dev) {} - static inline void dev_pm_genpd_resume(struct device *dev) {} - #endif - -From 5231c8fe672a6e8e7cde1b6cced64c2ba5917c14 Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Tue, 15 Sep 2026 18:05:26 +0000 -Subject: [PATCH] NVIDIA: SAUCE: cpuidle: psci: Correct rejected states for the - full domain path - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -Each successful genpd power-off callback replaces the single per-CPU PSCI -domain-state record. In a multilevel topology, firmware rejection can -therefore correct the usage and rejected counters for only the final -selected domain. - -Count the attached domain paths during CPU initialization and preallocate -enough per-CPU storage for every selection. Collect each selected domain -only while preparing a cpuidle firmware entry, use the final record for the -composite PSCI state, and correct every recorded domain if firmware rejects -it. Propagate an exhausted record array back through the genpd power-off -callback. - -Keeping collection scoped to the cpuidle transaction also prevents syscore -and CPU-hotplug genpd transitions from accumulating irrelevant state. - -Co-developed-by: Ishan Shah -Signed-off-by: Ishan Shah -Signed-off-by: Bharat Dintakurti -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/cpuidle/cpuidle-psci-domain.c | 4 +- - drivers/cpuidle/cpuidle-psci.c | 92 +++++++++++++++++++++++---- - drivers/cpuidle/cpuidle-psci.h | 4 +- - 3 files changed, 84 insertions(+), 16 deletions(-) - -diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c -index b9e4ad7d43..c4984718f1 100644 ---- a/drivers/cpuidle/cpuidle-psci-domain.c -+++ b/drivers/cpuidle/cpuidle-psci-domain.c -@@ -39,9 +39,7 @@ static int psci_pd_power_off(struct generic_pm_domain *pd) - - /* OSI mode is enabled, set the corresponding domain state. */ - pd_state = state->data; -- psci_set_domain_state(pd, pd->state_idx, *pd_state); -- -- return 0; -+ return psci_set_domain_state(pd, pd->state_idx, *pd_state); - } - - static int psci_pd_init(struct device_node *np, bool use_osi) -diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c -index 1562a5b09d..3d45edf749 100644 ---- a/drivers/cpuidle/cpuidle-psci.c -+++ b/drivers/cpuidle/cpuidle-psci.c -@@ -34,6 +34,10 @@ - struct psci_cpuidle_data { - u32 *psci_states; - struct device *dev; -+ struct psci_cpuidle_domain_state *domain_states; -+ unsigned int domain_state_count; -+ unsigned int domain_state_capacity; -+ bool collect_domain_states; - }; - - struct psci_cpuidle_domain_state { -@@ -43,22 +47,32 @@ struct psci_cpuidle_domain_state { - }; - - static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data); --static DEFINE_PER_CPU(struct psci_cpuidle_domain_state, psci_domain_state); - static bool psci_cpuidle_use_syscore; - --void psci_set_domain_state(struct generic_pm_domain *pd, unsigned int state_idx, -- u32 state) -+int psci_set_domain_state(struct generic_pm_domain *pd, unsigned int state_idx, -+ u32 state) - { -- struct psci_cpuidle_domain_state *ds = this_cpu_ptr(&psci_domain_state); -+ struct psci_cpuidle_data *data = this_cpu_ptr(&psci_cpuidle_data); -+ struct psci_cpuidle_domain_state *ds; - -+ if (!data->collect_domain_states) -+ return 0; -+ if (data->domain_state_count >= data->domain_state_capacity) -+ return -ENOSPC; -+ -+ ds = &data->domain_states[data->domain_state_count++]; - ds->pd = pd; - ds->state_idx = state_idx; - ds->state = state; -+ return 0; - } - - static inline void psci_clear_domain_state(void) - { -- __this_cpu_write(psci_domain_state.state, 0); -+ struct psci_cpuidle_data *data = this_cpu_ptr(&psci_cpuidle_data); -+ -+ data->domain_state_count = 0; -+ data->collect_domain_states = false; - } - - static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev, -@@ -69,22 +83,27 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev, - u32 *states = data->psci_states; - struct device *pd_dev = data->dev; - struct psci_cpuidle_domain_state *ds; -+ unsigned int i; - u32 state = states[idx]; - int ret; - -+ psci_clear_domain_state(); - ret = cpu_pm_enter(); - if (ret) - return -1; - - /* Do runtime PM to manage a hierarchical CPU toplogy. */ -+ data->collect_domain_states = true; - if (s2idle) - dev_pm_genpd_suspend_s2idle(pd_dev); - else - pm_runtime_put_sync_suspend(pd_dev); -+ data->collect_domain_states = false; - -- ds = this_cpu_ptr(&psci_domain_state); -- if (ds->state) -+ if (data->domain_state_count) { -+ ds = &data->domain_states[data->domain_state_count - 1]; - state = ds->state; -+ } - - trace_psci_domain_idle_enter(dev->cpu, state, s2idle); - ret = psci_cpu_suspend_enter(state) ? -1 : idx; -@@ -98,8 +117,12 @@ static __cpuidle int __psci_enter_domain_idle_state(struct cpuidle_device *dev, - cpu_pm_exit(); - - /* Correct domain-idlestate statistics if we failed to enter. */ -- if (ret == -1 && ds->state) -- pm_genpd_inc_rejected(ds->pd, ds->state_idx, s2idle); -+ if (ret == -1) { -+ for (i = 0; i < data->domain_state_count; i++) { -+ ds = &data->domain_states[i]; -+ pm_genpd_inc_rejected(ds->pd, ds->state_idx, s2idle); -+ } -+ } - - /* Clear the domain state to start fresh when back from idle. */ - psci_clear_domain_state(); -@@ -246,10 +269,29 @@ int psci_dt_parse_state_node(struct device_node *np, u32 *state) - return 0; - } - --static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv, -+static unsigned int psci_pd_count_domains(struct generic_pm_domain *pd) -+{ -+ struct gpd_link *link; -+ unsigned int child_count; -+ unsigned int count = 1; -+ -+ list_for_each_entry(link, &pd->child_links, child_node) { -+ child_count = psci_pd_count_domains(link->parent); -+ if (!child_count || check_add_overflow(count, child_count, &count)) -+ return 0; -+ } -+ -+ return count; -+} -+ -+static int psci_dt_cpu_init_topology(struct device *dev, -+ struct cpuidle_driver *drv, - struct psci_cpuidle_data *data, - unsigned int state_count, int cpu) - { -+ struct generic_pm_domain *pd; -+ unsigned int domain_count; -+ - /* Currently limit the hierarchical topology to be used in OSI mode. */ - if (!psci_has_osi_support()) - return 0; -@@ -257,6 +299,29 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv, - data->dev = dt_idle_attach_cpu(cpu, "psci"); - if (IS_ERR_OR_NULL(data->dev)) - return PTR_ERR_OR_ZERO(data->dev); -+ if (!data->dev->pm_domain) { -+ dt_idle_detach_cpu(data->dev); -+ data->dev = NULL; -+ return -ENODEV; -+ } -+ -+ pd = pd_to_genpd(data->dev->pm_domain); -+ domain_count = psci_pd_count_domains(pd); -+ if (!domain_count) { -+ dt_idle_detach_cpu(data->dev); -+ data->dev = NULL; -+ return -EOVERFLOW; -+ } -+ -+ data->domain_states = -+ devm_kcalloc(dev, domain_count, sizeof(*data->domain_states), -+ GFP_KERNEL); -+ if (!data->domain_states) { -+ dt_idle_detach_cpu(data->dev); -+ data->dev = NULL; -+ return -ENOMEM; -+ } -+ data->domain_state_capacity = domain_count; - - psci_cpuidle_use_syscore = true; - -@@ -306,7 +371,7 @@ static int psci_dt_cpu_init_idle(struct device *dev, struct cpuidle_driver *drv, - return -ENODEV; - - /* Initialize optional data, used for the hierarchical topology. */ -- ret = psci_dt_cpu_init_topology(drv, data, state_count, cpu); -+ ret = psci_dt_cpu_init_topology(dev, drv, data, state_count, cpu); - if (ret < 0) - return ret; - -@@ -344,6 +409,11 @@ static void psci_cpu_deinit_idle(int cpu) - struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu); - - dt_idle_detach_cpu(data->dev); -+ data->dev = NULL; -+ data->domain_states = NULL; -+ data->domain_state_count = 0; -+ data->domain_state_capacity = 0; -+ data->collect_domain_states = false; - psci_cpuidle_use_syscore = false; - } - -diff --git a/drivers/cpuidle/cpuidle-psci.h b/drivers/cpuidle/cpuidle-psci.h -index d29cbd796c..caf181247d 100644 ---- a/drivers/cpuidle/cpuidle-psci.h -+++ b/drivers/cpuidle/cpuidle-psci.h -@@ -6,8 +6,8 @@ - struct device_node; - struct generic_pm_domain; - --void psci_set_domain_state(struct generic_pm_domain *pd, unsigned int state_idx, -- u32 state); -+int psci_set_domain_state(struct generic_pm_domain *pd, unsigned int state_idx, -+ u32 state); - int psci_dt_parse_state_node(struct device_node *np, u32 *state); - - #endif /* __CPUIDLE_PSCI_H */ -From 3c63503ce65b63d31001a13d9fd460182b635a7d Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Tue, 1 Sep 2026 22:49:24 +0000 -Subject: [PATCH] NVIDIA: SAUCE: ACPI: processor_idle: Clear freed cpuidle - device pointers - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -acpi_processor_power_init() publishes each allocated cpuidle device through -the per-CPU acpi_cpuidle_device pointer. The normal processor power-exit -path and the global power-state refresh path unregister and free that -device without clearing the published pointer. - -If reinitialization fails before installing a replacement, the per-CPU slot -continues to reference freed memory. A repeated or adjacent lifecycle -operation can then consume the dangling pointer. - -Clear the owner slot immediately after unregistering the device and before -freeing it in both paths. - -Fixes: e18afcb7b2a12 ("ACPI: processor_idle: Fix memory leak in acpi_processor_power_exit()") -Fixes: 07cba0de5598 ("ACPI: processor: idle: Reset cpuidle on C-state list changes") -Signed-off-by: Bharat Dintakurti -Signed-off-by: Ishan Shah -Reviewed-by: Ishan Shah -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/acpi/processor_idle.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c -index 4482cf28f5..49c9f51e84 100644 ---- a/drivers/acpi/processor_idle.c -+++ b/drivers/acpi/processor_idle.c -@@ -1319,6 +1319,7 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr) - continue; - - cpuidle_unregister_device_no_lock(dev); -+ per_cpu(acpi_cpuidle_device, cpu) = NULL; - kfree(dev); - _pr->flags.power = 0; - } -@@ -1461,6 +1462,7 @@ void acpi_processor_power_exit(struct acpi_processor *pr) - - if (pr->flags.power) { - cpuidle_unregister_device(dev); -+ per_cpu(acpi_cpuidle_device, pr->id) = NULL; - kfree(dev); - } - -From 8fb13cd71cb76faab1332bafebc3eb4152d2ede3 Mon Sep 17 00:00:00 2001 -From: Ishan Shah -Date: Mon, 14 Sep 2026 22:53:27 +0000 -Subject: [PATCH] NVIDIA: SAUCE: ACPI: processor_idle: Serialize idle-state - rebuilds - -BugLink: https://bugs.launchpad.net/bugs/2167301 - -A power-state notification rebuilds the shared ACPI idle driver and every -cpuidle device. The cpuidle lock protects individual registration -operations, but it is released between device teardown, driver replacement, -and device recreation. - -Concurrent CPU0 notifications can therefore interleave complete rebuild -transactions and lose or free each other's objects. Serialize the -system-wide transaction with a dedicated mutex. Recheck the processor -state after taking the mutex because another rebuild may have completed -while the notification waited. - -Signed-off-by: Ishan Shah -Assisted-by: OpenAI-Codex:gpt-5.6 -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/acpi/processor_idle.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - -diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c -index 49c9f51e84..42e0e08372 100644 ---- a/drivers/acpi/processor_idle.c -+++ b/drivers/acpi/processor_idle.c -@@ -50,6 +50,7 @@ static unsigned int latency_factor __read_mostly = 2; - module_param(latency_factor, uint, 0644); - - static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device); -+static DEFINE_MUTEX(acpi_idle_rebuild_lock); - - static struct cpuidle_driver acpi_idle_driver = { - .name = "acpi_idle", -@@ -1291,14 +1292,20 @@ int acpi_processor_hotplug(struct acpi_processor *pr) - int acpi_processor_power_state_has_changed(struct acpi_processor *pr) - { - int cpu; -+ int ret = 0; - struct acpi_processor *_pr; - struct cpuidle_device *dev; - - if (disabled_by_idle_boot_param()) - return 0; -+ if (pr->id != 0) -+ return 0; - -- if (!pr->flags.power_setup_done) -- return -ENODEV; -+ mutex_lock(&acpi_idle_rebuild_lock); -+ if (!pr->flags.power_setup_done) { -+ ret = -ENODEV; -+ goto out; -+ } - - /* - * FIXME: Design the ACPI notification to make it once per -@@ -1306,7 +1313,7 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr) - * to make the code that updates C-States be called once. - */ - -- if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) { -+ if (cpuidle_get_driver() == &acpi_idle_driver) { - /* Protect against cpu-hotplug */ - cpus_read_lock(); - -@@ -1347,7 +1354,9 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr) - cpus_read_unlock(); - } - -- return 0; -+out: -+ mutex_unlock(&acpi_idle_rebuild_lock); -+ return ret; - } - - void acpi_processor_register_idle_driver(void) diff --git a/kernel/1021-ACPI-processor_idle-let-LPI-states-freeze-the-tick-in-suspend-to-idle.patch b/kernel/1021-ACPI-processor_idle-let-LPI-states-freeze-the-tick-in-suspend-to-idle.patch deleted file mode 100644 index a1e93fe..0000000 --- a/kernel/1021-ACPI-processor_idle-let-LPI-states-freeze-the-tick-in-suspend-to-idle.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 741a1f042172ff499fdec3571dd3e5a84ee7c050 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Wed, 7 Oct 2026 20:24:35 -0400 -Subject: [PATCH] ACPI: processor_idle: let LPI states freeze the tick in - suspend-to-idle - -The LPI states get no ->enter_s2idle callback, so on ACPI arm64 systems -suspend-to-idle never finds a state to enter with the tick frozen and -falls back to plain idle. timekeeping_suspend() never runs, and -CLOCK_MONOTONIC keeps advancing for as long as the system sleeps. - -systemd measures service watchdogs on CLOCK_MONOTONIC and relies on it -stopping in suspend. On the NVIDIA N1x (ASUS ProArt P14), any sleep -longer than three minutes made systemd kill systemd-logind, -systemd-journald and boltd for missed watchdog pings the moment it -thawed. The restarted logind dropped the graphical session, and -NetworkManager, put to sleep through the killed logind's -PrepareForSleep, never woke up again, leaving the laptop with no -network after resume. - -FFH LPI entry (PSCI CPU_SUSPEND on arm64) returns with interrupts still -disabled and FFH states already carry CPUIDLE_FLAG_RCU_IDLE for the -context tracking it does itself, which is what enter_s2idle_proper() -expects. Use the same entry for ->enter_s2idle on those states. The -hardware state does not change: s2idle already picked the deepest state -by exit latency through cpuidle_find_deepest_state(), and -find_deepest_state() picks the same one now. Only the tick and -timekeeping are frozen on top of it. ---- - drivers/acpi/processor_idle.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c -index 42e0e08..b27971d 100644 ---- a/drivers/acpi/processor_idle.c -+++ b/drivers/acpi/processor_idle.c -@@ -1194,9 +1194,18 @@ static void acpi_processor_setup_lpi_states(struct acpi_processor *pr) - state->exit_latency = lpi->wake_latency; - state->target_residency = lpi->min_residency; - state->flags |= arch_get_idle_state_flags(lpi->arch_flags); -- if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH) -- state->flags |= CPUIDLE_FLAG_RCU_IDLE; - state->enter = acpi_idle_lpi_enter; -+ if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH) { -+ state->flags |= CPUIDLE_FLAG_RCU_IDLE; -+ /* -+ * FFH entry returns with interrupts still disabled, so -+ * the state can also be entered for suspend-to-idle -+ * with the tick frozen. Without ->enter_s2idle, s2idle -+ * keeps timekeeping running and CLOCK_MONOTONIC -+ * advances for as long as the system sleeps. -+ */ -+ state->enter_s2idle = acpi_idle_lpi_enter; -+ } - drv->safe_state_index = i; - } - --- -2.56.0 - diff --git a/kernel/1023-ACPI-processor_idle-let-suspend-to-idle-reach-the-NVIDIA-N1x-DRIPS-state.patch b/kernel/1023-ACPI-processor_idle-let-suspend-to-idle-reach-the-NVIDIA-N1x-DRIPS-state.patch deleted file mode 100644 index c5b51e2..0000000 --- a/kernel/1023-ACPI-processor_idle-let-suspend-to-idle-reach-the-NVIDIA-N1x-DRIPS-state.patch +++ /dev/null @@ -1,73 +0,0 @@ -From: Ryan Hughes -Date: Mon, 12 Oct 2026 02:45:00 -0400 -Subject: [PATCH] ACPI: processor_idle: let suspend-to-idle reach the NVIDIA - N1x DRIPS state - -The N1x's _LPI reports its platform states, the deepest being -Standby-DRIPS, with a minimum residency of 0xFFFFFFFF and the cluster or -package state's exit latency (DRIPS: 966 us against the package state's -967 us) until \_SB.PEPD.ELST(1) sets MPEL. Suspend-to-idle picks the -deepest state by strictly increasing exit latency, so it stops at the -package state and the SoC never reaches DRIPS. - -Calling ELST(1) the way Windows' platform extension does is not an option: -Windows only enters DRIPS once every device constraint is met, while -Linux's idle governors pick it as soon as its 1.4 ms residency fits, with -devices running, and the system hangs at boot. - -Keep the residency, so the governors never choose these states, and add -DRIPS's wake latency (0x19D2 us) to their exit latency so that -suspend-to-idle reaches DRIPS. ---- - drivers/acpi/processor_idle.c | 26 ++++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - ---- a/drivers/acpi/processor_idle.c -+++ b/drivers/acpi/processor_idle.c -@@ -910,16 +910,25 @@ - return -EINVAL; - } - -+/* -+ * The NVIDIA N1x's DRIPS wake latency, from its _LPI with \_SB.PEPD.MPEL set -+ * (Standby-DRIPS: 0x19D2 us). -+ */ -+#define ACPI_N1X_DRIPS_WAKE_LATENCY_US 6610 -+ - static void acpi_processor_setup_lpi_states(struct acpi_processor *pr) - { - int i; - struct acpi_lpi_state *lpi; - struct cpuidle_state *state; - struct cpuidle_driver *drv = &acpi_idle_driver; -+ bool n1x; - - if (!pr->flags.has_lpi) - return; - -+ n1x = acpi_dev_present("NVDA6210", NULL, -1); -+ - for (i = 0; i < pr->power.count && i < CPUIDLE_STATE_MAX; i++) { - lpi = &pr->power.lpi_states[i]; - -@@ -928,6 +937,20 @@ - strscpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN); - state->exit_latency = lpi->wake_latency; - state->target_residency = lpi->min_residency; -+ /* -+ * The N1x reports its platform states, the deepest of them being -+ * DRIPS, with a minimum residency of 0xFFFFFFFF and the cluster or -+ * package state's exit latency, unless \_SB.PEPD.ELST(1) has set -+ * MPEL. Windows' platform extension calls ELST(1), but only enters -+ * DRIPS once every device constraint is met; with the real values -+ * Linux's idle governors pick DRIPS while devices are running and -+ * the system hangs at boot. Keep the residency, so the governors -+ * never choose these states, and add DRIPS's wake latency, so that -+ * suspend-to-idle, which takes the deepest state by exit latency, -+ * reaches DRIPS instead of stopping at the package state. -+ */ -+ if (n1x && lpi->min_residency == U32_MAX) -+ state->exit_latency += ACPI_N1X_DRIPS_WAKE_LATENCY_US; - state->flags |= arch_get_idle_state_flags(lpi->arch_flags); - state->enter = acpi_idle_lpi_enter; - if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH) { diff --git a/kernel/1024-PCI-quirks-let-the-NVIDIA-N1x-NVMe-link-reach-L1.2-so-the-SoC-can-sleep.patch b/kernel/1024-PCI-quirks-let-the-NVIDIA-N1x-NVMe-link-reach-L1.2-so-the-SoC-can-sleep.patch deleted file mode 100644 index fcfa978..0000000 --- a/kernel/1024-PCI-quirks-let-the-NVIDIA-N1x-NVMe-link-reach-L1.2-so-the-SoC-can-sleep.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Ryan Hughes -Date: Mon, 12 Oct 2026 10:20:00 -0400 -Subject: [PATCH] PCI: quirks: let the NVIDIA N1x NVMe link reach L1.2 so the - SoC can sleep - -The N1x firmware leaves ASPM off on every PCIe link. In suspend-to-idle -the NVMe drive goes to D3hot (its port has StorageD3Enable), but with -PCI-PM L1.2 off the link sits in plain L1 with CLKREQ# asserted. The -SoC's power manager then records a PCIe wake about every 60 ms and never -gets past its shallowest platform idle level (MCUSYS off), so the laptop -draws 6-15 W asleep. - -Allow ASPM L1 and PCI-PM L1.1/L1.2 on the NVMe link through -pci_enable_link_state(). The SoC then stays in DRIPS (PPS4, DRAM in -self-refresh) for the whole suspend: 0.77 W over a 7.3 h night on the -ASUS ProArt P14, woken only by the lid. ASPM L1.1/L1.2 while the drive is -active and clock power management stay off, as the firmware has them. - -The platform is recognised by its platform extension device, NVDA6210. ---- - drivers/pci/quirks.c | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -5891,6 +5891,30 @@ - DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, - PCI_BASE_CLASS_DISPLAY, 16, quirk_nvidia_hda); - -+#ifdef CONFIG_ACPI -+/* -+ * The NVIDIA N1x firmware leaves ASPM off on every PCIe link. In -+ * suspend-to-idle the NVMe drive goes to D3hot, but with PCI-PM L1.2 off its -+ * link sits in plain L1 with CLKREQ# asserted, and the SoC's power manager -+ * is woken by PCIe about every 60 ms, never getting past the shallowest -+ * platform idle level. With PCI-PM L1.1/L1.2 allowed, the SoC stays in its -+ * deepest state for the whole suspend and sleeps at under 1 W instead of -+ * 6-15 W. The platform is recognised by its PEP device, NVDA6210. -+ */ -+static void quirk_n1x_nvme_l1ss(struct pci_dev *pdev) -+{ -+ if (!acpi_dev_present("NVDA6210", NULL, -1)) -+ return; -+ -+ if (!pci_enable_link_state(pdev, PCIE_LINK_STATE_L1 | -+ PCIE_LINK_STATE_L1_1_PCIPM | -+ PCIE_LINK_STATE_L1_2_PCIPM)) -+ pci_info(pdev, "N1x: allowing ASPM L1 and PCI-PM L1.1/L1.2\n"); -+} -+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, -+ PCI_CLASS_STORAGE_EXPRESS, 0, quirk_n1x_nvme_l1ss); -+#endif -+ - /* - * Some IDT switches incorrectly flag an ACS Source Validation error on - * completions for config read requests even though PCIe r7.0, sec diff --git a/kernel/1030-n1x-audio.patch b/kernel/1030-n1x-audio.patch deleted file mode 100644 index 5ab75ec..0000000 --- a/kernel/1030-n1x-audio.patch +++ /dev/null @@ -1,21521 +0,0 @@ -From 594f3b411a3facb307bebd129217a5e4ec5bb98b Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Tue, 15 Sep 2026 10:19:47 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ALSA: hda/acpi: use pm_ptr() for the PM ops - -BugLink: https://bugs.launchpad.net/bugs/2167235 - -Wrap hda_acpi_pm in pm_ptr() so that the dev_pm_ops structure and the -suspend/resume callbacks it points to are discarded by the compiler when -CONFIG_PM is disabled, instead of being kept alive by the .pm pointer. -The callbacks are already declared through SYSTEM_SLEEP_PM_OPS() and -RUNTIME_PM_OPS(), which only fill the structure under CONFIG_PM_SLEEP -and CONFIG_PM; pm_ptr() completes that pattern and brings the driver in -line with the other HDA controller drivers (intel.c, tegra.c and -cix-ipbloq.c all use pm_ptr()). - -No functional change on a CONFIG_PM=y kernel. Follow-up to -commit a41da0bb086e ("ALSA: hda/acpi: add runtime PM suspend/resume to -the ACPI controller"), which is cherry-picked as the previous commit; -this cleanup is not part of that upstream commit and is being sent -upstream separately. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - sound/hda/controllers/acpi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/sound/hda/controllers/acpi.c b/sound/hda/controllers/acpi.c -index 505cc97e0e..774d3c75c9 100644 ---- a/sound/hda/controllers/acpi.c -+++ b/sound/hda/controllers/acpi.c -@@ -312,7 +312,7 @@ MODULE_DEVICE_TABLE(acpi, hda_acpi_match); - static struct platform_driver hda_acpi_platform_driver = { - .driver = { - .name = KBUILD_MODNAME, -- .pm = &hda_acpi_pm, -+ .pm = pm_ptr(&hda_acpi_pm), - .acpi_match_table = hda_acpi_match, - }, - .probe = hda_acpi_probe, -From a68bb471e973f62296ecda162b8f59546965d52d Mon Sep 17 00:00:00 2001 -From: Kaushal Rajeev Butala -Date: Wed, 2 Sep 2026 21:18:14 +0530 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: sdw_utils: clear stale RT711 device - reference - -BugLink: https://bugs.launchpad.net/bugs/2166188 - -asoc_sdw_rt711_exit() drops the reference held in ctx->headset_codec_dev, -but leaves the pointer populated. If the card cleanup path reaches the exit -hook more than once after a failed or deferred probe, a later invocation -can reuse the stale pointer and call put_device() again. - -Clear the pointer after put_device() so repeated cleanup becomes a no-op. -This avoids refcount underflow and possible oopses when later probe, -driver bind, or suspend paths walk the SoundWire bus after the device -reference was released. - -This is similar to commit 046173b98de3 ("ASoC: sdw_utils: fix double -put_device() on aggregated amps"). - -Signed-off-by: David Cemin -Signed-off-by: Kaushal Rajeev Butala -Acked-by: Matthew R. Ochs -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - sound/soc/sdw_utils/soc_sdw_rt711.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/sound/soc/sdw_utils/soc_sdw_rt711.c b/sound/soc/sdw_utils/soc_sdw_rt711.c -index 3a3a66b4b7..4707190e16 100644 ---- a/sound/soc/sdw_utils/soc_sdw_rt711.c -+++ b/sound/soc/sdw_utils/soc_sdw_rt711.c -@@ -124,6 +124,7 @@ int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_ - - device_remove_software_node(ctx->headset_codec_dev); - put_device(ctx->headset_codec_dev); -+ ctx->headset_codec_dev = NULL; - - return 0; - } -From b6cd09217f285d66994097b7b09e69c6b87fe73e Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:06 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add MediaTek SoundWire - manager - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Add the MediaTek mt8901 SoundWire manager driver. The manager wraps a -Cadence SoundWire master IP behind MediaTek link and interconnect glue: -ACPI probe and link enumeration, PDI allocation against the fixed AFE -interconnect grid, interrupt handling, and stream/port configuration -for the SoundWire codecs on the platform. - -Folded review fixes from the bring-up: compare device 0 status against -the SLAVESTAT field encoding rather than the raw register value, track -the previous PDI across port contiguity checks, reset the group sync -state on every hw_params instead of leaking it across streams, and -return the correct error code when a core register map fails. - -Signed-off-by: Trevor Wu -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/Kconfig | 10 + - drivers/soundwire/Makefile | 4 + - drivers/soundwire/mtk-sdw-common.h | 74 +++ - drivers/soundwire/mtk-sdw-core.c | 895 +++++++++++++++++++++++++++ - drivers/soundwire/mtk-sdw-core.h | 234 +++++++ - drivers/soundwire/mtk-sdw-top.c | 301 +++++++++ - drivers/soundwire/mtk-sdw-top.h | 105 ++++ - drivers/soundwire/mtk-sdw.c | 945 +++++++++++++++++++++++++++++ - drivers/soundwire/mtk-sdw.h | 85 +++ - 9 files changed, 2653 insertions(+) - create mode 100644 drivers/soundwire/mtk-sdw-common.h - create mode 100644 drivers/soundwire/mtk-sdw-core.c - create mode 100644 drivers/soundwire/mtk-sdw-core.h - create mode 100644 drivers/soundwire/mtk-sdw-top.c - create mode 100644 drivers/soundwire/mtk-sdw-top.h - create mode 100644 drivers/soundwire/mtk-sdw.c - create mode 100644 drivers/soundwire/mtk-sdw.h - -diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig -index 196a7daaab..ab9c011987 100644 ---- a/drivers/soundwire/Kconfig -+++ b/drivers/soundwire/Kconfig -@@ -57,6 +57,16 @@ config SOUNDWIRE_QCOM - enable this config option to get the SoundWire support for that - device - -+config SOUNDWIRE_MTK -+ tristate "MediaTek SoundWire Master driver" -+ select SOUNDWIRE_GENERIC_ALLOCATION -+ depends on SND_SOC && ACPI -+ help -+ SoundWire MediaTek Master driver. -+ If you have an MediaTek platform which has a SoundWire Master then -+ enable this config option to get the SoundWire support for that -+ device. -+ - config SOUNDWIRE_GENERIC_ALLOCATION - tristate - -diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile -index e80a2c2cf3..2e173c2791 100644 ---- a/drivers/soundwire/Makefile -+++ b/drivers/soundwire/Makefile -@@ -36,3 +36,7 @@ obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o - #Qualcomm driver - soundwire-qcom-y := qcom.o - obj-$(CONFIG_SOUNDWIRE_QCOM) += soundwire-qcom.o -+ -+#MediaTek driver -+soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o -+obj-$(CONFIG_SOUNDWIRE_MTK) += soundwire-mtk.o -diff --git a/drivers/soundwire/mtk-sdw-common.h b/drivers/soundwire/mtk-sdw-common.h -new file mode 100644 -index 0000000000..30e3645abe ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw-common.h -@@ -0,0 +1,74 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master — shared driver structure. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_COMMON_H -+#define __MTK_SDW_COMMON_H -+ -+#include "mtk-sdw-core.h" -+ -+struct mtk_sdw; -+struct mtk_sdw_top_cfg; -+struct mtk_sdw_top_pdi_params; -+ -+enum mtk_sdw_hw_ver { -+ MTK_SDW_HW_VER_MT8195 = 0, /* first chip */ -+ MTK_SDW_HW_VER_MT8901, /* second chip */ -+ MTK_SDW_HW_VER_MT8971, -+ MTK_SDW_HW_VER_MAX, -+}; -+ -+#define SDW_MAX_HWIP_NUM (2) -+#define SDW_PDI_CONFIG_NUM (8) -+#define MTK_SDW_MAX_GROUP_SYNC 4 -+#define MTK_SDW_MAX_DP 16 -+ -+struct mtk_sdw_link { -+ struct mtk_sdw_core core; -+ struct mtk_sdw *master; -+ int ip_idx; -+ int irq; -+ u32 src_base; -+ u32 src_num; -+ u32 sink_base; -+ u32 sink_num; -+}; -+ -+struct mtk_sdw_dai { -+ struct mtk_sdw_link *link; -+ unsigned int port_num; -+ struct sdw_stream_runtime *sruntime; -+ unsigned int pdi_count; -+ struct mtk_sdw_pdi_params pdi_params[SDW_PDI_CONFIG_NUM]; -+ struct mtk_sdw_top_pdi_params *top_pdi_params; -+ bool use_group_sync; -+ unsigned int group_sync_id; -+ bool need_enable_delay; -+}; -+ -+struct mtk_sdw { -+ struct device *dev; -+ void __iomem *base; /* full AFE MMIO */ -+ struct mtk_sdw_link links[SDW_MAX_HWIP_NUM]; -+ int num_links; -+ u32 controller_en_list; -+ const struct mtk_sdw_top_cfg *top_cfg; -+ void __iomem *top_pdi; /* base + top_cfg->pdi_base */ -+ void __iomem *top_con; /* base + top_cfg->con_base */ -+ u32 hw_ver; -+ /* group_lock: serializes group_refcnt[] group-sync allocation */ -+ struct mutex group_lock; -+ int group_refcnt[MTK_SDW_MAX_GROUP_SYNC]; -+ u32 tzd_delay; -+ bool tzd_inverse; -+ u32 phy_delay; -+ u32 phy_double_delay; -+ struct mtk_sdw_dai *dais; -+ int num_dais; -+ u16 dp_pdi_mask[MTK_SDW_MAX_DP]; -+}; -+ -+#endif /* __MTK_SDW_COMMON_H */ -diff --git a/drivers/soundwire/mtk-sdw-core.c b/drivers/soundwire/mtk-sdw-core.c -new file mode 100644 -index 0000000000..48b8346a80 ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw-core.c -@@ -0,0 +1,895 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire master — STABLE controller core. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "bus.h" -+#include "mtk-sdw-core.h" -+#include "mtk-sdw.h" -+ -+/* ---- register helpers ---- */ -+static u32 core_readl(struct mtk_sdw_core *core, u32 off) -+{ -+ return readl(core->regs + off); -+} -+ -+static void core_writel(struct mtk_sdw_core *core, u32 off, u32 val) -+{ -+ writel(val, core->regs + off); -+} -+ -+static void core_updatel(struct mtk_sdw_core *core, u32 off, u32 mask, u32 val) -+{ -+ u32 tmp = core_readl(core, off); -+ -+ core_writel(core, off, (tmp & ~mask) | (val & mask)); -+} -+ -+static u32 core_get_slave_status(struct mtk_sdw_core *core, u32 dev_addr) -+{ -+ u32 slave_stat = 0; -+ -+ if (dev_addr > SDW_MAX_DEVICES) { -+ dev_err(core->dev, "Unexpected device id %u\n", dev_addr); -+ return slave_stat; -+ } -+ slave_stat = core_readl(core, MCP_SLAVESTAT); -+ slave_stat = MCP_SLAVESTAT_STATUS(slave_stat, dev_addr); -+ -+ return slave_stat; -+} -+ -+#define CORE_CMD_TIMEOUT_US 50000 -+#define CORE_CMD_POLL_US 10 -+ -+static int core_send_cmd(struct mtk_sdw_core *core, u32 cmd, u8 *rdata) -+{ -+ u32 resp; -+ int ret; -+ -+ core_writel(core, MCP_COMMAND(0), cmd); -+ -+ ret = readl_poll_timeout(core->regs + MCP_STAT, resp, -+ resp & MCP_STAT_RX_NE, -+ CORE_CMD_POLL_US, CORE_CMD_TIMEOUT_US); -+ if (ret) { -+ dev_err(core->dev, "cmd 0x%08x timeout\n", cmd); -+ return SDW_CMD_TIMEOUT; -+ } -+ -+ resp = core_readl(core, MCP_COMMAND(0)); -+ if (FIELD_GET(MCP_RESP_NAK, resp)) -+ return SDW_CMD_FAIL; -+ if (!FIELD_GET(MCP_RESP_ACK, resp)) -+ return SDW_CMD_IGNORED; -+ if (rdata) -+ *rdata = FIELD_GET(MCP_RESP_RDATA, resp); -+ -+ return SDW_CMD_OK; -+} -+ -+static enum sdw_command_response -+mtk_program_scp_addr(struct mtk_sdw_core *core, struct sdw_msg *msg) -+{ -+ int ret; -+ u32 p1 = FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -+ FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -+ FIELD_PREP(MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE1) | -+ FIELD_PREP(MCP_CMD_REG_DATA, msg->addr_page1); -+ u32 p2 = FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -+ FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -+ FIELD_PREP(MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE2) | -+ FIELD_PREP(MCP_CMD_REG_DATA, msg->addr_page2); -+ -+ ret = core_send_cmd(core, p1, NULL); -+ if (ret == SDW_CMD_OK) -+ ret = core_send_cmd(core, p2, NULL); -+ -+ return ret; -+} -+ -+static int mtk_core_prep_msg(struct mtk_sdw_core *core, struct sdw_msg *msg) -+{ -+ int ret; -+ -+ if (msg->page) { -+ ret = mtk_program_scp_addr(core, msg); -+ if (ret) { -+ msg->len = 0; -+ return ret; -+ } -+ } -+ -+ switch (msg->flags) { -+ case SDW_MSG_FLAG_READ: -+ case SDW_MSG_FLAG_WRITE: -+ break; -+ default: -+ dev_err(core->dev, "Invalid msg cmd: %d\n", msg->flags); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* ======================================================================= -+ * sdw_master_ops -+ * ======================================================================= -+ */ -+static enum sdw_command_response -+mtk_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ int i, ret = 0; -+ -+ ret = mtk_core_prep_msg(core, msg); -+ if (ret) -+ return SDW_CMD_FAIL_OTHER; -+ -+ for (i = 0; i < msg->len; i++) { -+ u32 cmd = FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -+ FIELD_PREP(MCP_CMD_REG_ADDR, msg->addr + i) | -+ FIELD_PREP(MCP_CMD_SSP_TAG, msg->ssp_sync); -+ -+ if (msg->flags == SDW_MSG_FLAG_READ) { -+ cmd |= FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_READ); -+ ret = core_send_cmd(core, cmd, &msg->buf[i]); -+ } else { -+ cmd |= FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -+ FIELD_PREP(MCP_CMD_REG_DATA, msg->buf[i]); -+ ret = core_send_cmd(core, cmd, NULL); -+ } -+ if (ret) -+ break; -+ } -+ -+ return ret; -+} -+ -+static u32 mtk_sdw_read_ping_status(struct sdw_bus *bus) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ -+ return core_readl(core, MCP_SLAVESTAT); -+} -+ -+static bool mipi_fwnode_property_read_bool(const struct fwnode_handle *fwnode, -+ const char *propname) -+{ -+ int ret; -+ u8 val; -+ -+ if (!fwnode_property_present(fwnode, propname)) -+ return false; -+ ret = fwnode_property_read_u8_array(fwnode, propname, &val, 1); -+ if (ret < 0) -+ return false; -+ return !!val; -+} -+ -+static int mtk_sdw_read_prop(struct sdw_bus *bus) -+{ -+ struct sdw_master_prop *prop = &bus->prop; -+ struct fwnode_handle *link; -+ char name[40]; -+ int nval; -+ int ret; -+ int i; -+ int id = 0; -+ -+ snprintf(name, sizeof(name), "mipi-sdw-%d-sw-interface-revision", -+ bus->link_id); -+ -+ device_property_read_u32(bus->dev, name, &prop->revision); -+ -+ /* Find master handle */ -+ snprintf(name, sizeof(name), -+ "mipi-sdw-%d-link-%d-subproperties", bus->link_id, id); -+ -+ link = device_get_named_child_node(bus->dev, name); -+ if (!link) { -+ dev_err(bus->dev, "Master node %s not found\n", name); -+ return -EIO; -+ } -+ -+ for (i = SDW_CLK_STOP_MODE0; i <= SDW_CLK_STOP_MODE1; i++) { -+ snprintf(name, sizeof(name), -+ "mipi-sdw-clock-stop-mode%d-supported", i); -+ if (mipi_fwnode_property_read_bool(link, name)) -+ prop->clk_stop_modes |= BIT(i); -+ } -+ -+ fwnode_property_read_u32(link, -+ "mipi-sdw-max-clock-frequency", -+ &prop->max_clk_freq); -+ -+ nval = fwnode_property_count_u32(link, -+ "mipi-sdw-clock-frequencies-supported"); -+ if (nval > 0) { -+ prop->num_clk_freq = nval; -+ prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq, -+ sizeof(*prop->clk_freq), -+ GFP_KERNEL); -+ if (!prop->clk_freq) { -+ fwnode_handle_put(link); -+ return -ENOMEM; -+ } -+ -+ ret = fwnode_property_read_u32_array(link, -+ "mipi-sdw-clock-frequencies-supported", -+ prop->clk_freq, -+ prop->num_clk_freq); -+ if (ret < 0) { -+ fwnode_handle_put(link); -+ return ret; -+ } -+ } -+ -+ /* -+ * Check the frequencies supported. If FW doesn't provide max -+ * freq, then populate here by checking values. -+ */ -+ if (!prop->max_clk_freq && prop->clk_freq) { -+ prop->max_clk_freq = prop->clk_freq[0]; -+ for (i = 1; i < prop->num_clk_freq; i++) { -+ if (prop->clk_freq[i] > prop->max_clk_freq) -+ prop->max_clk_freq = prop->clk_freq[i]; -+ } -+ } -+ -+ fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate", -+ &prop->default_frame_rate); -+ -+ fwnode_property_read_u32(link, "mipi-sdw-default-frame-row-size", -+ &prop->default_row); -+ -+ fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size", -+ &prop->default_col); -+ -+ fwnode_handle_put(link); -+ -+ /* -+ * sdw_bus_master_add() derives the bus data-rate limits from these -+ * right after read_prop returns, so the fallbacks must be in place -+ * here rather than after the master is added. -+ */ -+ if (!prop->max_clk_freq) -+ prop->max_clk_freq = SDW_DEFAULT_MAX_BUS_CLK_FREQ; -+ if (!prop->default_frame_rate) -+ prop->default_frame_rate = SDW_DEFAULT_FRAME_RATE; -+ if (!prop->default_row) -+ prop->default_row = SDW_DEFAULT_FRAME_SHAPE_ROW; -+ if (!prop->default_col) -+ prop->default_col = SDW_DEFAULT_FRAME_SHAPE_COL; -+ -+ return 0; -+} -+ -+static int mtk_sdw_set_bus_conf(struct sdw_bus *bus, -+ struct sdw_bus_params *params) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ struct sdw_master_prop *prop = &bus->prop; -+ u8 next = params->next_bank ? 1 : 0; -+ u32 mclkd; -+ -+ /* curr_dr_freq is the *double* rate; halve it to get the bus clock. */ -+ if (params->curr_dr_freq && prop->mclk_freq) { -+ mclkd = (prop->mclk_freq / params->curr_dr_freq); -+ if (mclkd > 0) -+ mclkd--; -+ core_updatel(core, MCP_CLOCKCTRL(next), MCP_CLOCKCTRL_MCLKD, -+ FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -+ core->curr_clk_freq = params->curr_dr_freq / 2; -+ } -+ return 0; -+} -+ -+/* ======================================================================= -+ * Port ops -+ * ======================================================================= -+ */ -+ -+/* Source: word length, flow mode, data mode */ -+static int mtk_sdw_dpn_set_port_params(struct sdw_bus *bus, -+ struct sdw_port_params *params, -+ unsigned int bank) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ unsigned int p = params->num; -+ u32 cfg; -+ -+ cfg = core_readl(core, MCP_DPN_CONFIG(p, bank)); -+ -+ /* Bits per sample: encoded as (bps - 1). */ -+ u32p_replace_bits(&cfg, params->bps - 1, MCP_DPN_CONFIG_WL); -+ /* Port flow mode (isochronous=0 / async=1).*/ -+ u32p_replace_bits(&cfg, params->flow_mode, MCP_DPN_CONFIG_PFM); -+ /* Test/normal data mode. */ -+ u32p_replace_bits(&cfg, params->data_mode, MCP_DPN_CONFIG_PDM); -+ -+ core_writel(core, MCP_DPN_CONFIG(p, bank), cfg); -+ return 0; -+} -+ -+/* sample interval, block offsets, h-ctrl, BGC/BPM */ -+static int -+mtk_sdw_dpn_set_port_transport_params(struct sdw_bus *bus, -+ struct sdw_transport_params *params, -+ enum sdw_reg_bank bank) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ unsigned int p = params->port_num; -+ u8 bk = (bank == SDW_BANK1) ? 1 : 0; -+ u32 cfg, offsetctrl, hctrl; -+ -+ /* BGC and BPM live in DPN_CONFIG alongside WL/PFM/PDM. */ -+ cfg = core_readl(core, MCP_DPN_CONFIG(p, bk)); -+ u32p_replace_bits(&cfg, params->blk_grp_ctrl, MCP_DPN_CONFIG_BGC); -+ u32p_replace_bits(&cfg, params->blk_pkg_mode, MCP_DPN_CONFIG_BPM); -+ core_writel(core, MCP_DPN_CONFIG(p, bk), cfg); -+ -+ /* Sample interval: encoded as (interval - 1). */ -+ core_writel(core, MCP_DPN_SAMPLECTRL(p, bk), -+ FIELD_PREP(MCP_DPN_SAMPLECTRL_INTERVAL, -+ params->sample_interval - 1)); -+ -+ /* Block offsets 1 and 2. */ -+ offsetctrl = FIELD_PREP(MCP_DPN_OFFSETCTRL_OFFSET1, params->offset1) | -+ FIELD_PREP(MCP_DPN_OFFSETCTRL_OFFSET2, params->offset2); -+ core_writel(core, MCP_DPN_OFFSETCTRL(p, bk), offsetctrl); -+ -+ /* Horizontal start/stop and lane control. */ -+ hctrl = FIELD_PREP(MCP_DPN_HCTRL_HSTART, params->hstart) | -+ FIELD_PREP(MCP_DPN_HCTRL_HSTOP, params->hstop) | -+ FIELD_PREP(MCP_DPN_HCTRL_LANECTRL, params->lane_ctrl); -+ core_writel(core, MCP_DPN_HCTRL(p, bk), hctrl); -+ -+ return 0; -+} -+ -+static int mtk_sdw_dpn_port_enable_ch(struct sdw_bus *bus, -+ struct sdw_enable_ch *enable_ch, -+ unsigned int bank) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ unsigned int p = enable_ch->port_num; -+ u32 val = 0; -+ -+ if (enable_ch->enable) -+ val = FIELD_PREP(MCP_DPN_CHANNELEN_EN, enable_ch->ch_mask); -+ -+ core_writel(core, MCP_DPN_CHANNELEN(p, bank), val); -+ return 0; -+} -+ -+void mtk_sdw_core_dump_dpn_regs(struct mtk_sdw_core *core, unsigned int port, -+ const char *tag) -+{ -+ struct sdw_bus *bus = &core->bus; -+ int bk; -+ -+ dev_dbg(core->dev, -+ "%s: port %u curr_bank=%d next_bank=%d\n", -+ tag, port, bus->params.curr_bank, bus->params.next_bank); -+ -+ for (bk = 0; bk < 2; bk++) { -+ u32 config = core_readl(core, MCP_DPN_CONFIG(port, bk)); -+ u32 channelen = core_readl(core, MCP_DPN_CHANNELEN(port, bk)); -+ u32 samplectrl = core_readl(core, MCP_DPN_SAMPLECTRL(port, bk)); -+ u32 offsetctrl = core_readl(core, MCP_DPN_OFFSETCTRL(port, bk)); -+ u32 hctrl = core_readl(core, MCP_DPN_HCTRL(port, bk)); -+ -+ dev_dbg(core->dev, -+ "%s: port %u bank%d:\n" -+ "CONFIG=0x%08x (wl=%lu pfm=%lu pdm=%lu bgc=%lu bpm=%lu)\n" -+ "CHANNELEN=0x%08x\n" -+ "SAMPLECTRL=0x%08x (interval=%lu)\n" -+ "OFFSETCTRL=0x%08x (off1=%lu off2=%lu)\n" -+ "HCTRL=0x%08x (hstart=%lu hstop=%lu lane=%lu)\n", -+ tag, port, bk, config, -+ FIELD_GET(MCP_DPN_CONFIG_WL, config) + 1, -+ FIELD_GET(MCP_DPN_CONFIG_PFM, config), -+ FIELD_GET(MCP_DPN_CONFIG_PDM, config), -+ FIELD_GET(MCP_DPN_CONFIG_BGC, config), -+ FIELD_GET(MCP_DPN_CONFIG_BPM, config), -+ channelen, samplectrl, -+ FIELD_GET(MCP_DPN_SAMPLECTRL_INTERVAL, samplectrl) + 1, -+ offsetctrl, -+ FIELD_GET(MCP_DPN_OFFSETCTRL_OFFSET1, offsetctrl), -+ FIELD_GET(MCP_DPN_OFFSETCTRL_OFFSET2, offsetctrl), -+ hctrl, -+ FIELD_GET(MCP_DPN_HCTRL_HSTART, hctrl), -+ FIELD_GET(MCP_DPN_HCTRL_HSTOP, hctrl), -+ FIELD_GET(MCP_DPN_HCTRL_LANECTRL, hctrl)); -+ } -+} -+EXPORT_SYMBOL_GPL(mtk_sdw_core_dump_dpn_regs); -+ -+const struct sdw_master_port_ops mtk_sdw_core_port_ops = { -+ .dpn_set_port_params = mtk_sdw_dpn_set_port_params, -+ .dpn_set_port_transport_params = mtk_sdw_dpn_set_port_transport_params, -+ .dpn_port_enable_ch = mtk_sdw_dpn_port_enable_ch, -+}; -+ -+const struct sdw_master_ops mtk_sdw_core_ops = { -+ .read_prop = mtk_sdw_read_prop, -+ .read_ping_status = mtk_sdw_read_ping_status, -+ .xfer_msg = mtk_sdw_xfer_msg, -+ .set_bus_conf = mtk_sdw_set_bus_conf, -+}; -+ -+static int mtk_do_config_update(struct mtk_sdw_core *core) -+{ -+ u32 val; -+ int ret; -+ -+ core_updatel(core, MCP_CONFIGUPDATE, MCP_CONFIGUPDATE_CU, -+ MCP_CONFIGUPDATE_CU); -+ ret = readl_poll_timeout(core->regs + MCP_CONFIGUPDATE, val, -+ !(val & MCP_CONFIGUPDATE_CU), 100, 2000); -+ if (ret) { -+ dev_err(core->dev, "config update timeout\n"); -+ return ret; -+ } -+ return 0; -+} -+ -+static int mtk_init_clock_ctrl(struct mtk_sdw_core *core) -+{ -+ struct sdw_bus *bus = &core->bus; -+ struct sdw_master_prop *prop = &bus->prop; -+ int c; -+ int r; -+ u32 val; -+ -+ dev_dbg(core->dev, "mclk %d max %d row %d col %d\n", -+ prop->mclk_freq, -+ prop->max_clk_freq, -+ prop->default_row, -+ prop->default_col); -+ -+ /* Set clock divider */ -+ if (bus->params.curr_dr_freq && prop->mclk_freq) { -+ u32 mclkd = (prop->mclk_freq / bus->params.curr_dr_freq); -+ -+ if (mclkd > 0) -+ mclkd--; -+ core_updatel(core, MCP_CLOCKCTRL_B0, MCP_CLOCKCTRL_MCLKD, -+ FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -+ core_updatel(core, MCP_CLOCKCTRL_B1, MCP_CLOCKCTRL_MCLKD, -+ FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -+ } -+ -+ r = sdw_find_row_index(prop->default_row); -+ c = sdw_find_col_index(prop->default_col); -+ val = FIELD_PREP(MCP_FRAMESHAPE_NC, c) | -+ FIELD_PREP(MCP_FRAMESHAPE_NR, r); -+ -+ core_updatel(core, MCP_FRAMESHAPEINIT, -+ (MCP_FRAMESHAPE_NC | MCP_FRAMESHAPE_NR), val); -+ -+ if (prop->default_frame_rate % SDW_GSYNC_HZ) { -+ dev_warn(core->dev, -+ "[%u] FrameRate:%u not aligned with GSYNC:%d", -+ bus->link_id, prop->default_frame_rate, SDW_GSYNC_HZ); -+ } -+ -+ val = prop->default_frame_rate / SDW_GSYNC_HZ; -+ val = FIELD_PREP(MCP_SSP_CTRL_SSP_INTERVAL, val); -+ -+ core_updatel(core, MCP_SSP_CTRL_B0, MCP_SSP_CTRL_SSP_INTERVAL, val); -+ core_updatel(core, MCP_SSP_CTRL_B1, MCP_SSP_CTRL_SSP_INTERVAL, val); -+ -+ return 0; -+} -+ -+static int mtk_init_control_setting(struct mtk_sdw_core *core) -+{ -+ u32 val; -+ u32 mask; -+ -+ mask = MCP_CONTROL_RST_DELAY | MCP_CONTROL_CMD_RST | -+ MCP_CONTROL_CMD_ACCEPT_MODE; -+ -+ val = FIELD_PREP(MCP_CONTROL_RST_DELAY, 1) | MCP_CONTROL_CMD_RST; -+ -+ core_updatel(core, MCP_CONTROL, mask, val); -+ -+ return mtk_do_config_update(core); -+} -+ -+static int mtk_init_config_setting(struct mtk_sdw_core *core) -+{ -+ u32 val; -+ u32 mask; -+ -+ mask = MCP_CONFIG_MCR | MCP_CONFIG_OP_MODE; -+ -+ val = FIELD_PREP(MCP_CONFIG_MCR, SDW_DEFAULT_MAX_CMD_RETRY) | -+ FIELD_PREP(MCP_CONFIG_OP_MODE, MCP_OP_MODE_NORMAL); -+ -+ core_updatel(core, MCP_CONFIG, mask, val); -+ -+ return mtk_do_config_update(core); -+} -+ -+static void mtk_sdw_enable_master_irq(struct mtk_sdw_core *core, bool enable) -+{ -+ core_updatel(core, MCP_INTMASK, (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP), -+ enable ? (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP) : 0); -+} -+ -+void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) -+{ -+ if (enable) { -+ core_writel(core, MCP_SLAVEINTMASK0, MCP_SLAVE_INTMASK0_MASK); -+ core_writel(core, MCP_SLAVEINTMASK1, MCP_SLAVE_INTMASK1_MASK); -+ } else { -+ core_writel(core, MCP_SLAVEINTMASK0, 0); -+ core_writel(core, MCP_SLAVEINTMASK1, 0); -+ } -+ -+ mtk_sdw_enable_slave_irq(core, enable); -+ -+ mtk_sdw_enable_master_irq(core, enable); -+ -+ core->interrupt_enabled = enable; -+ -+ if (!enable) -+ cancel_work_sync(&core->work); -+ -+ core_updatel(core, MCP_INTMASK, MCP_INT_IRQ, -+ enable ? MCP_INT_IRQ : 0); -+} -+ -+void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable) -+{ -+ core_updatel(core, MCP_INTMASK, MCP_INT_SLV_MASK, -+ enable ? MCP_INT_SLV_MASK : 0); -+} -+ -+/* -+ * slave IRQ handling -+ */ -+static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, -+ u64 slave_intstat) -+{ -+ enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; -+ bool need_handle_slave = false; -+ u32 intstat; -+ u32 val; -+ int i, set_status; -+ -+ memset(status, 0, sizeof(status)); -+ -+ for (i = 0; i <= SDW_MAX_DEVICES; i++) { -+ intstat = MCP_SLAVEINTSTAT_STATUS(slave_intstat, i); -+ -+ set_status = 0; -+ -+ if (intstat) { -+ need_handle_slave = true; -+ -+ if (intstat & MCP_SLAVEINTSTAT_RESERVED) { -+ status[i] = SDW_SLAVE_RESERVED; -+ set_status++; -+ } -+ -+ if (intstat & MCP_SLAVEINTSTAT_ALERT) { -+ status[i] = SDW_SLAVE_ALERT; -+ set_status++; -+ } -+ -+ if (intstat & MCP_SLAVEINTSTAT_ATTACHED) { -+ status[i] = SDW_SLAVE_ATTACHED; -+ set_status++; -+ } -+ -+ if (intstat & MCP_SLAVEINTSTAT_NOT_PRESENT) { -+ status[i] = SDW_SLAVE_UNATTACHED; -+ set_status++; -+ } -+ } -+ -+ if (set_status != 1) { -+ val = core_get_slave_status(core, i); -+ -+ switch (val) { -+ case 0: -+ status[i] = SDW_SLAVE_UNATTACHED; -+ break; -+ case 1: -+ status[i] = SDW_SLAVE_ATTACHED; -+ break; -+ case 2: -+ status[i] = SDW_SLAVE_ALERT; -+ break; -+ case 3: -+ default: -+ status[i] = SDW_SLAVE_RESERVED; -+ break; -+ } -+ } -+ } -+ -+ if (need_handle_slave) -+ return sdw_handle_slave_status(&core->bus, status); -+ -+ return 0; -+} -+ -+static void mtk_sdw_slave_status_work(struct work_struct *work) -+{ -+ struct mtk_sdw_core *core = -+ container_of(work, struct mtk_sdw_core, work); -+ u32 stat0; -+ u32 stat1; -+ u32 dev0_stat; -+ int retries = 0; -+ u64 slv_intstat; -+ -+ core_writel(core, MCP_INTSTAT, MCP_INT_SLV_MASK); -+ -+ stat0 = core_readl(core, MCP_SLAVEINTSTAT0); -+ stat1 = core_readl(core, MCP_SLAVEINTSTAT1); -+ -+ core_writel(core, MCP_SLAVEINTSTAT0, stat0); -+ core_writel(core, MCP_SLAVEINTSTAT1, stat1); -+ dev_dbg_ratelimited(core->dev, "Slave intstat0: 0x%x, intstat1 0x%x\n", -+ stat0, stat1); -+ -+ slv_intstat = ((u64)stat1 << 32) | stat0; -+ -+ do { -+ mtk_sdw_update_slave_status(core, slv_intstat); -+ -+ dev0_stat = core_get_slave_status(core, 0); -+ -+ if (dev0_stat == MCP_SLAVESTAT_ATTACHED) { -+ slv_intstat = MCP_SLAVEINTSTAT_ATTACHED; -+ dev_info(core->dev, -+ "[%u] slave attached Dev0Stat:0x%x Retries:%d", -+ core->bus.link_id, dev0_stat, retries); -+ } else { -+ break; -+ } -+ -+ } while (retries++ < SDW_MAX_DEVICES); -+ -+ mtk_sdw_enable_slave_irq(core, true); -+} -+ -+static void mtk_sdw_handle_master_dp_interrupt(struct mtk_sdw_core *core) -+{ -+ u32 portintstatus = core_readl(core, MCP_PORTINTSTAT); -+ u32 pdistatus = core_readl(core, MCP_PDISTAT); -+ struct sdw_bus *bus = &core->bus; -+ -+ dev_info(core->dev, "[%u]PortIntStatus:0x%x PdiStatus:0x%x\n", -+ bus->link_id, portintstatus, pdistatus); -+ -+ if (portintstatus) -+ core_writel(core, MCP_PORTINTSTAT, portintstatus); -+ -+ if (pdistatus) -+ core_writel(core, MCP_PDISTAT, pdistatus); -+} -+ -+static void mtk_sdw_recalc_block_offset(struct sdw_port_runtime *p_rt) -+{ -+ struct sdw_transport_params *tp = &p_rt->transport_params; -+ int offset; -+ -+ offset = (tp->offset2 << 8) + tp->offset1; -+ offset -= 1; -+ -+ tp->offset1 = offset & 0xFF; -+ tp->offset2 = offset >> 8; -+} -+ -+static int mtk_sdw_compute_params(struct sdw_bus *bus, -+ struct sdw_stream_runtime *stream) -+{ -+ struct sdw_master_runtime *m_rt; -+ struct sdw_slave_runtime *s_rt; -+ struct sdw_port_runtime *p_rt; -+ int ret; -+ -+ ret = sdw_compute_params(bus, stream); -+ if (ret) -+ return ret; -+ -+ /* block offset should begin from 0 */ -+ list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { -+ list_for_each_entry(p_rt, &m_rt->port_list, port_node) -+ mtk_sdw_recalc_block_offset(p_rt); -+ -+ list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) -+ list_for_each_entry(p_rt, &s_rt->port_list, port_node) -+ mtk_sdw_recalc_block_offset(p_rt); -+ } -+ -+ return 0; -+} -+ -+int mtk_sdw_core_init(struct mtk_sdw_core *core) -+{ -+ core->bus.ops = &mtk_sdw_core_ops; -+ core->bus.port_ops = &mtk_sdw_core_port_ops; -+ core->bus.compute_params = mtk_sdw_compute_params; -+ -+ INIT_WORK(&core->work, mtk_sdw_slave_status_work); -+ return 0; -+} -+ -+int mtk_sdw_core_hw_init(struct mtk_sdw_core *core) -+{ -+ int ret; -+ -+ ret = mtk_init_clock_ctrl(core); -+ if (ret) -+ return ret; -+ -+ ret = mtk_init_control_setting(core); -+ if (ret) -+ return ret; -+ -+ ret = mtk_init_config_setting(core); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+irqreturn_t mtk_sdw_core_irq(int irq, void *data) -+{ -+ struct mtk_sdw_core *core = data; -+ struct sdw_bus *bus = &core->bus; -+ u32 intstat = core_readl(core, MCP_INTSTAT); -+ u32 clearstat; -+ -+ if (!(intstat & MCP_INT_IRQ)) { -+ dev_warn(core->dev, -+ "[%u]interrupt request not enabled IntStatus:0x%x", -+ bus->link_id, intstat); -+ return IRQ_NONE; -+ } -+ -+ clearstat = intstat; -+ -+ if (intstat & MCP_INT_WAKEUP) -+ dev_err(core->dev, "[%u]wakeup IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ -+ if (intstat & MCP_INT_SLV_MASK) { -+ if (intstat & MCP_INT_SLV_RESERVED) { -+ dev_info(core->dev, "[%u]slave reserved int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ -+ if (intstat & MCP_INT_SLV_ALERT) { -+ dev_info(core->dev, -+ "[%u]slave alert int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ -+ if (intstat & MCP_INT_SLV_ATTACHED) { -+ dev_info(core->dev, -+ "[%u]slave attached int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ -+ if (intstat & MCP_INT_SLV_NOT_ATTACH) { -+ dev_info(core->dev, -+ "[%u]slave not attached int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ if (core->interrupt_enabled) { -+ schedule_work(&core->work); -+ mtk_sdw_enable_slave_irq(core, false); -+ clearstat &= ~MCP_INT_SLV_MASK; -+ } -+ } -+ if (intstat & MCP_INT_DP_INT) { -+ dev_info(core->dev, "[%u]dp int IntStatus:0x%x\n", bus->link_id, -+ intstat); -+ -+ mtk_sdw_handle_master_dp_interrupt(core); -+ } -+ -+ if (intstat & (MCP_INT_CTL_BUS_CLASH)) -+ dev_err(core->dev, "[%u]control bus clash 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & (MCP_INT_DATA_BUS_CLASH)) -+ dev_err(core->dev, "[%u]data bus clash 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & MCP_INT_PARITY_ERR) -+ dev_err(core->dev, "[%u]parity error 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & MCP_INT_CMD_ERR) -+ dev_err(core->dev, "[%u]command error 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & MCP_INT_RXWL) -+ dev_info(core->dev, "[%u]rw wl 0x%x\n", bus->link_id, intstat); -+ -+ dev_info(core->dev, "[%u]ClearStatus 0x%x, IntStatus 0x%x\n", -+ bus->link_id, clearstat, intstat); -+ -+ core_writel(core, MCP_INTSTAT, clearstat); -+ -+ return IRQ_HANDLED; -+} -+ -+void mtk_sdw_configure_pdi_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *params) -+{ -+ u32 offset; -+ u32 val; -+ u32 mask; -+ -+ offset = MCP_PDIN_CONFIG(params->pdi_num); -+ -+ mask = MCP_PDIN_CONFIG_SOFTRST | MCP_PDIN_CONFIG_CHANNELMASK | -+ MCP_PDIN_CONFIG_PORTNUM; -+ -+ val = MCP_PDIN_CONFIG_SOFTRST | -+ FIELD_PREP(MCP_PDIN_CONFIG_CHANNELMASK, params->ch_mask) | -+ FIELD_PREP(MCP_PDIN_CONFIG_PORTNUM, params->port_num); -+ -+ core_updatel(core, offset, mask, val); -+} -+ -+void mtk_sdw_clear_pdi_settings(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *pdi) -+{ -+ u32 offset; -+ u32 val; -+ u32 mask; -+ -+ offset = MCP_PDIN_CONFIG(pdi->pdi_num); -+ -+ /* clear pdi fifo */ -+ mask = MCP_PDIN_CONFIG_SOFTRST; -+ val = MCP_PDIN_CONFIG_SOFTRST; -+ core_updatel(core, offset, mask, val); -+ -+ /* clear pdi channel mask */ -+ mask = MCP_PDIN_CONFIG_CHANNELMASK; -+ val = FIELD_PREP(MCP_PDIN_CONFIG_CHANNELMASK, 0); -+ core_updatel(core, offset, mask, val); -+} -+ -+void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_port_params *params, u32 dir) -+{ -+ u32 offset; -+ u32 val = 0; -+ u32 mask; -+ -+ offset = MCP_DPN_PORTCTRL(params->port_num); -+ mask = MCP_DPN_PORTCTRL_DIR | MCP_DPN_PORTCTRL_BPT_EN | -+ MCP_DPN_PORTCTRL_BPT_TYPE; -+ if (dir == SDW_DATA_DIR_RX) -+ val |= MCP_DPN_PORTCTRL_DIR; -+ -+ if (params->port_num == 0) /* bpt rx? */ -+ val |= FIELD_PREP(MCP_DPN_PORTCTRL_BPT_EN, params->bpt_en) | -+ FIELD_PREP(MCP_DPN_PORTCTRL_BPT_TYPE, -+ params->bpt_payload_type); -+ -+ core_updatel(core, offset, mask, val); -+} -diff --git a/drivers/soundwire/mtk-sdw-core.h b/drivers/soundwire/mtk-sdw-core.h -new file mode 100644 -index 0000000000..4708a10865 ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw-core.h -@@ -0,0 +1,234 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master — STABLE controller core. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_CORE_H -+#define __MTK_SDW_CORE_H -+ -+#include -+ -+#define SDW_GSYNC_HZ (8000) -+#define SDW_DEFAULT_MAX_CMD_RETRY (5) -+/* ======================================================================= -+ * MCP (Master Control Port) registers -+ * ======================================================================= -+ */ -+#define MCP_DP_SIZE 128 -+#define MCP_PDI_SIZE 16 -+ -+#define MCP_CONFIG 0x0000 -+#define MCP_CONTROL 0x0004 -+#define MCP_CMDCTRL 0x0008 -+#define MCP_SSPSTAT 0x000c -+#define MCP_FRAMESHAPE 0x0010 -+#define MCP_FRAMESHAPEINIT 0x0014 -+#define MCP_CONFIGUPDATE 0x0018 -+#define MCP_PHYCTRL 0x001c -+#define MCP_SSP_CTRL_B0 0x0020 -+#define MCP_SSP_CTRL_B1 0x0028 -+#define MCP_CLOCKCTRL_B0 0x0030 -+#define MCP_CLOCKCTRL_B1 0x0038 -+#define MCP_STAT 0x0040 -+#define MCP_INTSTAT 0x0044 -+#define MCP_INTMASK 0x0048 -+#define MCP_INTSET 0x004c -+#define MCP_SLAVESTAT 0x0050 -+#define MCP_SLAVEINTSTAT0 0x0054 -+#define MCP_SLAVEINTSTAT1 0x0058 -+#define MCP_SLAVEINTMASK0 0x005c -+#define MCP_SLAVEINTMASK1 0x0060 -+#define MCP_PORTINTSTAT 0x0064 -+#define MCP_PDISTAT 0x006c -+#define MCP_FIFOLEVEL 0x0078 -+#define MCP_FIFOSTAT 0x007c -+#define MCP_COMMAND(n) (0x0080 + (n) * 4) -+ -+#define MCP_DPN_CONFIG_B0(n) (0x0100 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_CHANNELEN_B0(n) (0x0104 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_SAMPLECTRL_B0(n) (0x0108 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_OFFSETCTRL_B0(n) (0x010c + (n) * MCP_DP_SIZE) -+#define MCP_DPN_HCTRL_B0(n) (0x0110 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_CONFIG_B1(n) (0x0118 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_CHANNELEN_B1(n) (0x011c + (n) * MCP_DP_SIZE) -+#define MCP_DPN_SAMPLECTRL_B1(n) (0x0120 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_OFFSETCTRL_B1(n) (0x0124 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_HCTRL_B1(n) (0x0128 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_PORTCTRL(n) (0x0130 + ((n) & 0xf) * MCP_DP_SIZE) -+#define MCP_PDIN_CONFIG(n) (0x1100 + ((n) & 0xf) * MCP_PDI_SIZE) -+ -+/* Bank selectors: each takes (port, bank) / (bank) */ -+#define MCP_DPN_CONFIG(n, b) \ -+ ((b) ? MCP_DPN_CONFIG_B1(n) : MCP_DPN_CONFIG_B0(n)) -+#define MCP_DPN_CHANNELEN(n, b) \ -+ ((b) ? MCP_DPN_CHANNELEN_B1(n) : MCP_DPN_CHANNELEN_B0(n)) -+#define MCP_DPN_SAMPLECTRL(n, b) \ -+ ((b) ? MCP_DPN_SAMPLECTRL_B1(n) : MCP_DPN_SAMPLECTRL_B0(n)) -+#define MCP_DPN_OFFSETCTRL(n, b) \ -+ ((b) ? MCP_DPN_OFFSETCTRL_B1(n) : MCP_DPN_OFFSETCTRL_B0(n)) -+#define MCP_DPN_HCTRL(n, b) \ -+ ((b) ? MCP_DPN_HCTRL_B1(n) : MCP_DPN_HCTRL_B0(n)) -+#define MCP_CLOCKCTRL(b) ((b) ? MCP_CLOCKCTRL_B1 : MCP_CLOCKCTRL_B0) -+ -+/* MCP_CONFIG */ -+#define MCP_CONFIG_OP_MODE GENMASK(2, 0) -+#define MCP_CONFIG_MCR GENMASK(27, 24) -+#define MCP_OP_MODE_NORMAL 0 -+ -+/* MCP_CONTROL */ -+#define MCP_CONTROL_CMD_ACCEPT_MODE BIT(1) -+#define MCP_CONTROL_CLOCK_STOP_CLR BIT(2) -+#define MCP_CONTROL_HW_BUS_RST BIT(4) -+#define MCP_CONTROL_SOFT_RST BIT(6) -+#define MCP_CONTROL_CMD_RST BIT(7) -+#define MCP_CONTROL_RST_DELAY GENMASK(10, 8) -+ -+/* MCP_FRAMESHAPE(INIT) */ -+#define MCP_FRAMESHAPE_NC GENMASK(2, 0) /* columns index */ -+#define MCP_FRAMESHAPE_NR GENMASK(7, 3) /* rows, encoded (rows/2-1) */ -+ -+/* MCP_CONFIGUPDATE */ -+#define MCP_CONFIGUPDATE_CU BIT(0) -+ -+/* MCP_SSP_CTRL */ -+#define MCP_SSP_CTRL_SSP_INTERVAL GENMASK(7, 0) -+ -+/* MCP_CLOCKCTRL */ -+#define MCP_CLOCKCTRL_MCLKD GENMASK(7, 0) -+ -+/* MCP_STAT */ -+#define MCP_STAT_RX_NE BIT(3) -+#define MCP_STAT_CLK_STOP BIT(16) -+ -+/* MCP_INTMASK / MCP_INTSTAT */ -+#define MCP_INT_RXWL BIT(2) -+#define MCP_INT_RXNE BIT(3) -+#define MCP_INT_CMD_ERR BIT(7) -+#define MCP_INT_PARITY_ERR BIT(8) -+#define MCP_INT_DATA_BUS_CLASH BIT(9) -+#define MCP_INT_CTL_BUS_CLASH BIT(10) -+#define MCP_INT_DP_INT BIT(11) -+#define MCP_INT_SLV_NOT_ATTACH BIT(12) -+#define MCP_INT_SLV_ATTACHED BIT(13) -+#define MCP_INT_SLV_ALERT BIT(14) -+#define MCP_INT_SLV_RESERVED BIT(15) -+#define MCP_INT_WAKEUP BIT(16) -+#define MCP_INT_IRQ BIT(31) -+#define MCP_INT_SLV_MASK (MCP_INT_SLV_RESERVED | \ -+ MCP_INT_SLV_ALERT | \ -+ MCP_INT_SLV_ATTACHED | \ -+ MCP_INT_SLV_NOT_ATTACH) -+#define MCP_INT_MST_ERR_MASK (MCP_INT_RXWL | \ -+ MCP_INT_PARITY_ERR | \ -+ MCP_INT_DATA_BUS_CLASH | \ -+ MCP_INT_CTL_BUS_CLASH) -+ -+/* MCP_SLAVESTAT: 2 bits/slave; MCP_SLAVEINTSTAT: 4 bits/slave */ -+#define MCP_SLAVESTAT_STATUS(x, n) (((x) >> ((n) * 2)) & 0x3) -+#define MCP_SLAVESTAT_UNATTACHED 0x0 -+#define MCP_SLAVESTAT_ATTACHED 0x1 -+#define MCP_SLAVESTAT_ALERT 0x2 -+#define MCP_SLAVEINTSTAT_STATUS(x, n) (((x) >> ((n) * 4)) & 0xf) -+#define MCP_SLAVEINTSTAT_NOT_PRESENT BIT(0) -+#define MCP_SLAVEINTSTAT_ATTACHED BIT(1) -+#define MCP_SLAVEINTSTAT_ALERT BIT(2) -+#define MCP_SLAVEINTSTAT_RESERVED BIT(3) -+ -+/* MCP_SLAVEINTMASK */ -+#define MCP_SLAVE_INTMASK0_MASK GENMASK(31, 0) -+#define MCP_SLAVE_INTMASK1_MASK GENMASK(15, 0) -+ -+/* MCP command word. CONFIRMED: dev_addr is 4-bit [27:24]. */ -+#define MCP_CMD_READ 0x2 -+#define MCP_CMD_WRITE 0x3 -+#define MCP_CMD_SSP_TAG BIT(31) -+#define MCP_CMD_FIELD GENMASK(30, 28) -+#define MCP_CMD_DEV_ADDR GENMASK(27, 24) -+#define MCP_CMD_REG_ADDR GENMASK(23, 8) -+#define MCP_CMD_REG_DATA GENMASK(7, 0) -+ -+/* MCP command response. CONFIRMED. */ -+#define MCP_RESP_ACK BIT(0) -+#define MCP_RESP_NAK BIT(1) -+#define MCP_RESP_RDATA GENMASK(15, 8) -+ -+/* Per-port transport fields (used by streaming) */ -+#define MCP_DPN_CONFIG_PFM GENMASK(1, 0) /* port flow mode */ -+#define MCP_DPN_CONFIG_PDM GENMASK(3, 2) /* port data mode */ -+/* word length, encoded (wl-1) */ -+#define MCP_DPN_CONFIG_WL GENMASK(12, 8) -+#define MCP_DPN_CONFIG_BGC GENMASK(17, 16) /* block group control */ -+#define MCP_DPN_CONFIG_BPM BIT(18) /* block packing mode */ -+#define MCP_DPN_CHANNELEN_EN GENMASK(7, 0) -+#define MCP_DPN_SAMPLECTRL_INTERVAL GENMASK(15, 0) /* encoded (interval-1) */ -+#define MCP_DPN_OFFSETCTRL_OFFSET1 GENMASK(7, 0) -+#define MCP_DPN_OFFSETCTRL_OFFSET2 GENMASK(15, 8) -+#define MCP_DPN_HCTRL_HSTOP GENMASK(3, 0) -+#define MCP_DPN_HCTRL_HSTART GENMASK(7, 4) -+#define MCP_DPN_HCTRL_LANECTRL GENMASK(10, 8) /* data lane select */ -+ -+#define MCP_DPN_PORTCTRL_BPT_TYPE GENMASK(23, 22) -+#define MCP_DPN_PORTCTRL_BPT_EN BIT(16) -+#define MCP_DPN_PORTCTRL_DIR BIT(7) -+ -+#define MCP_PDIN_CONFIG_SOFTRST BIT(24) -+#define MCP_PDIN_CONFIG_CHANNELMASK GENMASK(15, 8) -+#define MCP_PDIN_CONFIG_PORTNUM GENMASK(4, 0) -+ -+/* ======================================================================= -+ * Core object -+ * ======================================================================= -+ */ -+struct mtk_sdw_core { -+ struct sdw_bus bus; -+ struct device *dev; -+ void __iomem *regs; -+ unsigned int curr_clk_freq; -+ bool interrupt_enabled; -+ u16 attached_slaves; -+ void *priv; -+ struct work_struct work; -+}; -+ -+struct mtk_sdw_pdi_params { -+ u32 pdi_num; -+ u32 port_num; -+ u32 ch_mask; -+}; -+ -+struct mtk_sdw_port_params { -+ u32 port_num; -+ u32 bpt_payload_type; -+ bool bpt_en; -+}; -+ -+static inline struct mtk_sdw_core *bus_to_core(struct sdw_bus *bus) -+{ -+ return container_of(bus, struct mtk_sdw_core, bus); -+} -+ -+/* ======================================================================= -+ * Core API — called by the glue -+ * ======================================================================= -+ */ -+extern const struct sdw_master_ops mtk_sdw_core_ops; -+extern const struct sdw_master_port_ops mtk_sdw_core_port_ops; -+ -+int mtk_sdw_core_init(struct mtk_sdw_core *core); -+int mtk_sdw_core_hw_init(struct mtk_sdw_core *core); -+void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable); -+void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable); -+irqreturn_t mtk_sdw_core_irq(int irq, void *data); -+void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_port_params *params, u32 dir); -+ -+void mtk_sdw_configure_pdi_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *params); -+void mtk_sdw_clear_pdi_settings(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *pdi); -+void mtk_sdw_core_dump_dpn_regs(struct mtk_sdw_core *core, unsigned int port, -+ const char *tag); -+ -+#endif /* __MTK_SDW_CORE_H */ -diff --git a/drivers/soundwire/mtk-sdw-top.c b/drivers/soundwire/mtk-sdw-top.c -new file mode 100644 -index 0000000000..edc412f4e1 ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw-top.c -@@ -0,0 +1,301 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire master — AFE TOP control -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "mtk-sdw-top.h" -+ -+static const struct mtk_sdw_top_cfg mtk_sdw_top_cfgs[MTK_SDW_TOP_VER_MAX] = { -+ [MTK_SDW_TOP_VER_0] = { -+ .name = "hw_8901", -+ .reg = { -+ .tzd_delay_reg = SDW_TOP_CON0, -+ .tzd_delay_sel = GENMASK(5, 3), -+ .tzd_inverse = BIT(2), -+ .tzd_delay_en = BIT(1), -+ .phy_delay_reg = SDW_TOP_CON1, -+ .phy_delay_sel = GENMASK(3, 1), -+ .phy_double_delay_sel = GENMASK(6, 4), -+ }, -+ }, -+}; -+ -+static u32 topcon_readl(struct mtk_sdw *mst, u32 off) -+{ -+ return readl(mst->top_con + off); -+} -+ -+static void topcon_writel(struct mtk_sdw *mst, u32 off, u32 val) -+{ -+ writel(val, mst->top_con + off); -+} -+ -+static void topcon_updatel(struct mtk_sdw *mst, u32 off, u32 mask, u32 val) -+{ -+ u32 tmp = topcon_readl(mst, off); -+ -+ topcon_writel(mst, off, (tmp & ~mask) | (val & mask)); -+} -+ -+static u32 toppdi_readl(struct mtk_sdw *mst, u32 off) -+{ -+ return readl(mst->top_pdi + off); -+} -+ -+static void toppdi_writel(struct mtk_sdw *mst, u32 off, u32 val) -+{ -+ writel(val, mst->top_pdi + off); -+} -+ -+static void toppdi_updatel(struct mtk_sdw *mst, u32 off, u32 mask, u32 val) -+{ -+ u32 tmp = toppdi_readl(mst, off); -+ -+ toppdi_writel(mst, off, (tmp & ~mask) | (val & mask)); -+} -+ -+static inline u32 mtk_field_prep(u32 mask, u32 val) -+{ -+ if (!mask) -+ return 0; -+ return (val << __bf_shf(mask)) & mask; -+} -+ -+int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver) -+{ -+ int ver_id; -+ -+ switch (hw_ver) { -+ case MTK_SDW_HW_VER_MT8901: -+ case MTK_SDW_HW_VER_MT8971: -+ ver_id = MTK_SDW_TOP_VER_0; -+ break; -+ default: -+ dev_err(mst->dev, "unsupported hw-ver %d\n", hw_ver); -+ return -EINVAL; -+ } -+ -+ mst->top_cfg = &mtk_sdw_top_cfgs[ver_id]; -+ dev_info(mst->dev, "AFE TOP variant: %s (hw-ver %u)\n", -+ mst->top_cfg->name, mst->hw_ver); -+ return 0; -+} -+ -+void mtk_sdw_top_init_settings(struct mtk_sdw *mst) -+{ -+ topcon_updatel(mst, SDW_TOP_CON0, SDW_TOP_CON0_GSYNC_DIR_CTRL, -+ SDW_TOP_CON0_GSYNC_DIR_CTRL); -+} -+ -+void mtk_sdw_top_configure_delays(struct mtk_sdw *mst) -+{ -+ u32 val = 0; -+ u32 mask; -+ const struct mtk_sdw_top_reg *top_reg = &mst->top_cfg->reg; -+ -+ mask = top_reg->tzd_delay_sel | top_reg->tzd_inverse | -+ top_reg->tzd_delay_en; -+ val |= mtk_field_prep(top_reg->tzd_delay_sel, mst->tzd_delay - 1); -+ if (mst->tzd_inverse) -+ val |= top_reg->tzd_inverse; -+ if (mst->tzd_delay) -+ val |= top_reg->tzd_delay_en; -+ topcon_updatel(mst, top_reg->tzd_delay_reg, mask, val); -+ -+ val = 0; -+ mask = top_reg->phy_delay_sel | top_reg->phy_double_delay_sel; -+ val |= mtk_field_prep(top_reg->phy_delay_sel, mst->phy_delay); -+ val |= mtk_field_prep(top_reg->phy_double_delay_sel, -+ mst->phy_double_delay); -+ -+ topcon_updatel(mst, top_reg->phy_delay_reg, mask, val); -+} -+ -+void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, -+ struct mtk_sdw_top_pdi_params *param) -+{ -+ u32 val = 0; -+ u32 mask = 0; -+ -+ mask |= SDW_TOP_PDI_GROUP_SYNC; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_SLAVE_MODE, param->slave_mode); -+ mask |= SDW_TOP_PDI_SLAVE_MODE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_BRA_SLAVE, param->bra_slave); -+ mask |= SDW_TOP_PDI_BRA_SLAVE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_BRA_EOP, param->bra_eop); -+ mask |= SDW_TOP_PDI_BRA_EOP; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_BRA_MODE, param->bra_mode); -+ mask |= SDW_TOP_PDI_BRA_MODE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_DMIC_1XEN, param->dmic_1xen); -+ mask |= SDW_TOP_PDI_DMIC_1XEN; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_PDM_ONE_WIRE, param->pdm_one_wire); -+ mask |= SDW_TOP_PDI_PDM_ONE_WIRE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_PDM_MODE, param->pdm_mode); -+ mask |= SDW_TOP_PDI_PDM_MODE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_HD_SEL, param->hd_sel); -+ mask |= SDW_TOP_PDI_HD_SEL; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_CLOCK, param->clock); -+ mask |= SDW_TOP_PDI_CLOCK; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_PDM2PCM, param->pdm2pcm); -+ mask |= SDW_TOP_PDI_PDM2PCM; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_IP_SEL, param->sdw_ip_sel); -+ mask |= SDW_TOP_PDI_IP_SEL; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_DOMAIN, param->domain); -+ mask |= SDW_TOP_PDI_DOMAIN; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_FS, param->fs); -+ mask |= SDW_TOP_PDI_FS; -+ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), mask, val); -+} -+ -+static void mtk_sdw_top_enable_pdi_engen(struct mtk_sdw *mst, u32 pdi, -+ bool enable) -+{ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_EN, -+ enable ? SDW_TOP_PDI_EN : 0); -+} -+ -+static void mtk_sdw_top_enable_group_sync(struct mtk_sdw *mst, u32 pdi, -+ bool enable) -+{ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_GROUP_SYNC_ON, -+ enable ? SDW_TOP_PDI_GROUP_SYNC_ON : 0); -+} -+ -+static void mtk_sdw_top_config_group_sync(struct mtk_sdw *mst, u32 pdi, -+ u32 group) -+{ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_GROUP_SYNC, -+ FIELD_PREP(SDW_TOP_PDI_GROUP_SYNC, group)); -+} -+ -+int mtk_sdw_top_group_sync_config_get(struct mtk_sdw *mst, u8 id, u32 *cfg) -+{ -+ if (id > MTK_SDW_MAX_GROUP_SYNC) -+ return -EINVAL; -+ else if (id == GROUP_SYNC_NONE) -+ *cfg = 0; -+ else -+ *cfg = BIT(id - 1); -+ -+ return 0; -+} -+ -+int mtk_sdw_top_group_sync_acquire(struct mtk_sdw *mst, bool is_tx) -+{ -+ u8 min_id = is_tx ? TOP_GROUP_SYNC_TX_MIN_ID : TOP_GROUP_SYNC_RX_MIN_ID; -+ u8 max_id = is_tx ? TOP_GROUP_SYNC_TX_MAX_ID : TOP_GROUP_SYNC_RX_MAX_ID; -+ int best = -1; -+ int best_refcnt = INT_MAX; -+ int i, idx; -+ -+ guard(mutex)(&mst->group_lock); -+ -+ for (i = 0; i < MTK_SDW_MAX_GROUP_SYNC; i++) { -+ idx = is_tx ? i : (MTK_SDW_MAX_GROUP_SYNC - 1 - i); -+ -+ if (idx < min_id - 1 || idx > max_id - 1) -+ continue; -+ if (mst->group_refcnt[idx] < best_refcnt) { -+ best = idx; -+ best_refcnt = mst->group_refcnt[idx]; -+ } -+ } -+ if (best < 0) -+ return -EINVAL; -+ -+ mst->group_refcnt[best]++; -+ return best + 1; /* 1-based id */ -+} -+ -+void mtk_sdw_top_group_sync_release(struct mtk_sdw *mst, u8 id) -+{ -+ if (id == 0 || id > MTK_SDW_MAX_GROUP_SYNC) -+ return; -+ -+ guard(mutex)(&mst->group_lock); -+ -+ if (mst->group_refcnt[id - 1] <= 0) { -+ dev_err(mst->dev, "unexpected refcnt %d\n", -+ mst->group_refcnt[id - 1]); -+ return; -+ } -+ mst->group_refcnt[id - 1]--; -+} -+ -+int mtk_sdw_top_enable_stream(struct mtk_sdw *mst, int dai_id) -+{ -+ struct mtk_sdw_dai *mdai = &mst->dais[dai_id]; -+ int i; -+ u32 pdi_num, group_sync; -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_pdi_engen(mst, pdi_num, true); -+ } -+ -+ if (mdai->need_enable_delay) -+ usleep_range(1000, 1100); -+ -+ if (mdai->use_group_sync) { -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ group_sync = mdai->top_pdi_params[i].group_sync; -+ mtk_sdw_top_config_group_sync(mst, pdi_num, group_sync); -+ } -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_group_sync(mst, pdi_num, true); -+ } -+ } -+ -+ return 0; -+} -+ -+int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id) -+{ -+ struct mtk_sdw_dai *mdai = &mst->dais[dai_id]; -+ int i; -+ u32 pdi_num; -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_pdi_engen(mst, pdi_num, false); -+ } -+ -+ if (mdai->use_group_sync) { -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_group_sync(mst, pdi_num, false); -+ } -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_config_group_sync(mst, pdi_num, 0); -+ } -+ } -+ -+ return 0; -+} -diff --git a/drivers/soundwire/mtk-sdw-top.h b/drivers/soundwire/mtk-sdw-top.h -new file mode 100644 -index 0000000000..f12c090d60 ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw-top.h -@@ -0,0 +1,105 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master — AFE TOP control. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_TOP_H -+#define __MTK_SDW_TOP_H -+ -+#include "mtk-sdw-common.h" -+ -+enum mtk_sdw_group_sync_sel { -+ GROUP_SYNC_NONE = 0, -+ GROUP_1_SYNC, -+ GROUP_2_SYNC, -+ GROUP_3_SYNC, -+ GROUP_4_SYNC, -+}; -+ -+enum mtk_sdw_top_ver { -+ MTK_SDW_TOP_VER_0 = 0, -+ MTK_SDW_TOP_VER_MAX, -+}; -+ -+/* ---- AFE TOP registers (offsets that DON'T vary stay as #defines) ---- -+ */ -+#define SDW_TOP_PDIN_CON0(n) ((n) * 4) /* rel. top_pdi */ -+#define SDW_TOP_PDI_EN BIT(0) -+#define SDW_TOP_PDI_FS GENMASK(5, 1) -+#define SDW_TOP_PDI_DOMAIN GENMASK(8, 6) -+#define SDW_TOP_PDI_IP_SEL BIT(9) -+#define SDW_TOP_PDI_PDM2PCM BIT(10) -+#define SDW_TOP_PDI_CLOCK BIT(11) -+#define SDW_TOP_PDI_HD_SEL BIT(12) -+#define SDW_TOP_PDI_PDM_MODE BIT(13) -+#define SDW_TOP_PDI_PDM_ONE_WIRE BIT(14) -+#define SDW_TOP_PDI_DMIC_1XEN BIT(16) -+#define SDW_TOP_PDI_BRA_MODE BIT(17) -+#define SDW_TOP_PDI_BRA_EOP BIT(18) -+#define SDW_TOP_PDI_BRA_SLAVE BIT(19) -+#define SDW_TOP_PDI_SLAVE_MODE GENMASK(21, 20) -+#define SDW_TOP_PDI_GROUP_SYNC_ON BIT(22) -+#define SDW_TOP_PDI_GROUP_SYNC GENMASK(26, 23) -+ -+#define SDW_TOP_CON0 0x0000 /* rel. top_con */ -+#define SDW_TOP_CON0_GSYNC_DIR_CTRL BIT(7) -+ -+#define SDW_TOP_CON1 0x0004 -+ -+#define TOP_GROUP_SYNC_TX_MIN_ID 1 -+#define TOP_GROUP_SYNC_TX_MAX_ID 2 -+#define TOP_GROUP_SYNC_RX_MIN_ID 1 -+#define TOP_GROUP_SYNC_RX_MAX_ID 4 -+ -+struct mtk_sdw_top_pdi_params { -+ u32 group_sync; -+ u32 slave_mode; -+ u32 bra_slave; -+ u32 bra_eop; -+ u32 bra_mode; -+ u32 dmic_1xen; -+ u32 pdm_one_wire; -+ u32 pdm_mode; -+ u32 hd_sel; -+ u32 clock; -+ u32 pdm2pcm; -+ u32 sdw_ip_sel; -+ u32 domain; -+ u32 fs; -+}; -+ -+struct mtk_sdw_top_reg { -+ u32 tzd_delay_reg; -+ u32 tzd_delay_sel; -+ u32 tzd_inverse; -+ u32 tzd_delay_en; -+ u32 phy_delay_reg; -+ u32 phy_delay_sel; -+ u32 phy_double_delay_sel; -+}; -+ -+struct mtk_sdw_top_cfg { -+ const char *name; -+ struct mtk_sdw_top_reg reg; -+ /* -+ * u32 features; -+ * can be added for a bitfield if new features are supported -+ * in the future. -+ * -+ */ -+}; -+ -+int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver); -+void mtk_sdw_top_init_settings(struct mtk_sdw *mst); -+void mtk_sdw_top_configure_delays(struct mtk_sdw *mst); -+void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, -+ struct mtk_sdw_top_pdi_params *param); -+int mtk_sdw_top_group_sync_config_get(struct mtk_sdw *mst, u8 id, u32 *cfg); -+int mtk_sdw_top_group_sync_acquire(struct mtk_sdw *mst, bool is_tx); -+void mtk_sdw_top_group_sync_release(struct mtk_sdw *mst, u8 id); -+int mtk_sdw_top_enable_stream(struct mtk_sdw *mst, int dai_id); -+int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id); -+ -+#endif /* __MTK_SDW_TOP_H */ -diff --git a/drivers/soundwire/mtk-sdw.c b/drivers/soundwire/mtk-sdw.c -new file mode 100644 -index 0000000000..784250dc72 ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw.c -@@ -0,0 +1,945 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire master driver -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "mtk-sdw.h" -+#include "mtk-sdw-top.h" -+ -+static int mtk_sdw_parse_dp_allocation(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_link *link = &mst->links[idx]; -+ struct fwnode_handle *node; -+ char key[40]; -+ u32 dp[4]; -+ int ret; -+ -+ snprintf(key, sizeof(key), "acpi-scd-%d-subproperties", idx); -+ node = device_get_named_child_node(mst->dev, key); -+ if (!node) -+ return dev_err_probe(mst->dev, -ENODEV, -+ "link %d: missing %s node\n", idx, key); -+ -+ ret = fwnode_property_read_u32_array(node, "acpi-scd-dp-allocation", dp, -+ ARRAY_SIZE(dp)); -+ fwnode_handle_put(node); -+ if (ret) -+ return dev_err_probe(mst->dev, ret, -+ "link %d: bad acpi-scd-dp-allocation\n", -+ idx); -+ -+ /* -+ * { source_base, source_num, sink_base, sink_num }: every DP the -+ * firmware hands out indexes dp_pdi_mask[] and names a DP widget, -+ * so both ranges must fit in the MTK_SDW_MAX_DP ports of the -+ * manager. Check base first so the count test cannot underflow. -+ */ -+ if (dp[0] > MTK_SDW_MAX_DP || dp[1] > MTK_SDW_MAX_DP - dp[0] || -+ dp[2] > MTK_SDW_MAX_DP || dp[3] > MTK_SDW_MAX_DP - dp[2]) -+ return dev_err_probe(mst->dev, -EINVAL, -+ "link %d: DP allocation src %u+%u sink %u+%u exceeds %u ports\n", -+ idx, dp[0], dp[1], dp[2], dp[3], -+ MTK_SDW_MAX_DP); -+ -+ link->src_base = dp[0]; -+ link->src_num = dp[1]; -+ link->sink_base = dp[2]; -+ link->sink_num = dp[3]; -+ -+ dev_dbg(mst->dev, "link %d DP alloc: src %u..%u, sink %u..%u\n", idx, -+ link->src_base, link->src_base + link->src_num - 1, -+ link->sink_base, link->sink_base + link->sink_num - 1); -+ return 0; -+} -+ -+/* ======================================================================= -+ * ASoC DAI layer (ALSA <-> SoundWire stream binding) -+ * ======================================================================= -+ */ -+ -+static int mtk_sdw_set_sdw_stream(struct snd_soc_dai *dai, void *stream, -+ int direction) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ -+ mst->dais[dai->id].sruntime = stream; -+ return 0; -+} -+ -+static void *mtk_sdw_get_sdw_stream(struct snd_soc_dai *dai, int direction) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ -+ return mst->dais[dai->id].sruntime; -+} -+ -+static unsigned int derive_afe_fs_timing(unsigned int rate) -+{ -+ unsigned int fs = 0; -+ -+ switch (rate) { -+ case RATE_384000: -+ fs = MT8901_FS_384K; -+ break; -+ case RATE_352800: -+ fs = MT8901_FS_352D8K; -+ break; -+ case RATE_192000: -+ fs = MT8901_FS_192K; -+ break; -+ case RATE_176400: -+ fs = MT8901_FS_176D4K; -+ break; -+ case RATE_96000: -+ fs = MT8901_FS_96K; -+ break; -+ case RATE_88200: -+ fs = MT8901_FS_88D2K; -+ break; -+ case RATE_48000: -+ fs = MT8901_FS_48K; -+ break; -+ case RATE_44100: -+ fs = MT8901_FS_44D1K; -+ break; -+ case RATE_32000: -+ fs = MT8901_FS_32K; -+ break; -+ case RATE_24000: -+ fs = MT8901_FS_24K; -+ break; -+ case RATE_22050: -+ fs = MT8901_FS_22D05K; -+ break; -+ case RATE_16000: -+ fs = MT8901_FS_16K; -+ break; -+ case RATE_12000: -+ fs = MT8901_FS_12K; -+ break; -+ case RATE_8000: -+ fs = MT8901_FS_8K; -+ break; -+ default: -+ break; -+ } -+ -+ return fs; -+} -+ -+static void mtk_sdw_dai_release_params(struct mtk_sdw *mst, -+ struct mtk_sdw_dai *mdai) -+{ -+ int i; -+ -+ for (i = 0; i < mdai->pdi_count; i++) -+ mtk_sdw_clear_pdi_settings(&mdai->link->core, -+ &mdai->pdi_params[i]); -+ mdai->pdi_count = 0; -+ -+ if (mdai->group_sync_id > 0) { -+ mtk_sdw_top_group_sync_release(mst, mdai->group_sync_id); -+ mdai->group_sync_id = 0; -+ } -+ mdai->use_group_sync = false; -+ -+ if (mdai->top_pdi_params) { -+ devm_kfree(mst->dev, mdai->top_pdi_params); -+ mdai->top_pdi_params = NULL; -+ } -+} -+ -+static int mtk_sdw_dai_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -+ struct sdw_stream_config sconfig = { 0 }; -+ struct sdw_port_config pconfig = { 0 }; -+ struct mtk_sdw_port_params mtk_port_param = { 0 }; -+ struct mtk_sdw_top_pdi_params *top_params; -+ int dir, ret, i; -+ unsigned long pdis; -+ unsigned int pdi; -+ unsigned int channels = params_channels(params); -+ unsigned int rate = params_rate(params); -+ unsigned int pdi_count; -+ unsigned int ch_per_pdi = SDW_DEFAULT_CH_PER_PDI; -+ unsigned int tmp = 0; -+ unsigned int group_sync_config = 0; -+ unsigned int pdi_begin; -+ unsigned int last_pdi; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ dir = SDW_DATA_DIR_RX; -+ else -+ dir = SDW_DATA_DIR_TX; -+ -+ /* port_num is inside MTK_SDW_MAX_DP: validated when the DP allocation was parsed */ -+ pdis = mst->dp_pdi_mask[mdai->port_num]; -+ for_each_set_bit(pdi, &pdis, MTK_SDW_MAX_DP) { -+ dev_dbg(dai->dev, "DP%u <- PDI%u\n", mdai->port_num, pdi); -+ if (tmp++) { -+ if (pdi != last_pdi + 1) { -+ dev_dbg(dai->dev, "unexpected last PDI %u, PDI%u\n", -+ last_pdi, pdi); -+ return -EINVAL; -+ } -+ } else { -+ pdi_begin = pdi; -+ } -+ last_pdi = pdi; -+ } -+ -+ pdi_count = (channels + ch_per_pdi - 1) / ch_per_pdi; -+ if (tmp != pdi_count) { -+ dev_err(dai->dev, "DP%u pdi mask 0x%lx doesn't match channel %u\n", -+ mdai->port_num, pdis, channels); -+ return -EINVAL; -+ } -+ -+ /* -+ * ALSA allows HW_PARAMS again from SETUP or PREPARED without an -+ * intervening HW_FREE: drop the previous call's group sync -+ * reference and PDI state so nothing leaks or is released twice. -+ */ -+ mtk_sdw_dai_release_params(mst, mdai); -+ -+ if (pdi_count > 1) { -+ mdai->use_group_sync = true; -+ -+ ret = mtk_sdw_top_group_sync_acquire(mst, -+ dir == SDW_DATA_DIR_TX); -+ if (ret < 0) -+ return ret; -+ mdai->group_sync_id = ret; -+ -+ ret = mtk_sdw_top_group_sync_config_get(mst, -+ mdai->group_sync_id, -+ &group_sync_config); -+ if (ret < 0) { -+ mtk_sdw_top_group_sync_release(mst, -+ mdai->group_sync_id); -+ mdai->group_sync_id = 0; -+ return ret; -+ } -+ } -+ -+ /* update pdi_params */ -+ mdai->top_pdi_params = devm_kcalloc(mst->dev, pdi_count, -+ sizeof(*mdai->top_pdi_params), -+ GFP_KERNEL); -+ if (!mdai->top_pdi_params) { -+ ret = -ENOMEM; -+ goto err_release; -+ } -+ mdai->pdi_count = pdi_count; -+ mdai->need_enable_delay = TRUE; -+ for (i = 0; i < pdi_count; i++) { -+ mdai->pdi_params[i].pdi_num = pdi_begin++; -+ mdai->pdi_params[i].port_num = mdai->port_num; -+ mdai->pdi_params[i].ch_mask = (1 << (i * ch_per_pdi)) | -+ (1 << (i * ch_per_pdi + 1)); -+ -+ top_params = &mdai->top_pdi_params[i]; -+ top_params->group_sync = group_sync_config; -+ //top_params->slave_mode = 0; -+ top_params->bra_slave = 0; //ToDo : BRA -+ top_params->bra_mode = 0; //ToDo : BRA -+ top_params->bra_eop = (top_params->bra_mode != 0) ? 1 : 0; -+ top_params->dmic_1xen = 0; -+ top_params->pdm_one_wire = 0; -+ top_params->pdm_mode = 0; -+ //top_params->hd_sel = 0; -+ top_params->clock = IS_48K_RATE_DOMAIN(rate) ? 1 : 0; -+ top_params->pdm2pcm = 0; -+ top_params->sdw_ip_sel = mdai->link->ip_idx; -+ /* ToDo: SpecifyPdiMode for BRA */ -+ top_params->domain = MT8901_APLL_CLK_DOMAIN; -+ /* ToDo: SpecifyPdiFs for BRA */ -+ top_params->fs = derive_afe_fs_timing(rate); -+ -+ if (top_params->bra_mode != 0 && top_params->bra_slave != 0) -+ mdai->need_enable_delay = FALSE; -+ } -+ -+ pconfig.num = mdai->port_num; -+ pconfig.ch_mask = GENMASK(channels - 1, 0); -+ -+ sconfig.frame_rate = rate; -+ sconfig.ch_count = channels; -+ sconfig.bps = snd_pcm_format_width(params_format(params)); -+ sconfig.direction = dir; -+ sconfig.type = SDW_STREAM_PCM; -+ -+ mtk_port_param.port_num = pconfig.num; -+ mtk_port_param.bpt_payload_type = 0; -+ mtk_port_param.bpt_en = true; -+ mtk_sdw_configure_port_params(&mdai->link->core, &mtk_port_param, dir); -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ top_params = &mdai->top_pdi_params[i]; -+ mtk_sdw_top_configure_pdi(mst, mdai->pdi_params[i].pdi_num, -+ top_params); -+ mtk_sdw_configure_pdi_params(&mdai->link->core, -+ &mdai->pdi_params[i]); -+ } -+ -+ ret = sdw_stream_add_master(&mdai->link->core.bus, &sconfig, &pconfig, -+ 1, mdai->sruntime); -+ if (ret) -+ goto err_release; -+ -+ return 0; -+ -+err_release: -+ mtk_sdw_dai_release_params(mst, mdai); -+ return ret; -+} -+ -+static int mtk_sdw_dai_hw_free(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -+ int ret; -+ -+ ret = sdw_stream_remove_master(&mdai->link->core.bus, mdai->sruntime); -+ if (ret < 0) -+ dev_err(dai->dev, "remove manager from stream %s failed: %d\n", -+ mdai->sruntime->name, ret); -+ -+ mtk_sdw_dai_release_params(mst, mdai); -+ return ret; -+} -+ -+/* configure top stream here, it can be called before dai_link ops */ -+static int mtk_sdw_dai_trigger(struct snd_pcm_substream *substream, int cmd, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -+ -+ mtk_sdw_core_dump_dpn_regs(&mdai->link->core, mdai->port_num, -+ "trigger"); -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ return mtk_sdw_top_enable_stream(mst, dai->id); -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ return mtk_sdw_top_disable_stream(mst, dai->id); -+ default: -+ return -EINVAL; -+ } -+} -+ -+static const struct snd_soc_dai_ops mtk_sdw_dai_ops = { -+ .hw_params = mtk_sdw_dai_hw_params, -+ .hw_free = mtk_sdw_dai_hw_free, -+ .trigger = mtk_sdw_dai_trigger, -+ .set_stream = mtk_sdw_set_sdw_stream, -+ .get_stream = mtk_sdw_get_sdw_stream, -+}; -+ -+/* ======================================================================= -+ * DAPM: PDI <-> DP routing -+ * ======================================================================= -+ */ -+ -+/* Playback DEMUX target DPs (item 0 == "None"). */ -+static const char * const mtk_sdw_playback_dp_texts[] = { -+ "None", "DP2", "DP3", "DP4", "DP5", "DP6", -+}; -+ -+/* Capture MUX source DPs (item 0 == "None"). */ -+static const char * const mtk_sdw_capture_dp_texts[] = { -+ "None", "DP7", "DP8", "DP9", "DP10", -+ "DP11", "DP12", "DP13", "DP14", "DP15", -+}; -+ -+static int mtk_sdw_pdi_route_put(struct snd_kcontrol *kc, -+ struct snd_ctl_elem_value *uc) -+{ -+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kc); -+ struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm); -+ struct mtk_sdw *mst = snd_soc_component_get_drvdata(comp); -+ struct soc_enum *e = (struct soc_enum *)kc->private_value; -+ unsigned int item = uc->value.enumerated.item[0]; -+ unsigned int pdi, dp, d; -+ -+ if (sscanf(kc->id.name, "PDI%u", &pdi) != 1) -+ return -EINVAL; -+ if (pdi >= BITS_PER_TYPE(mst->dp_pdi_mask[0])) -+ return -EINVAL; -+ if (item >= e->items) -+ return -EINVAL; -+ -+ for (d = 0; d < MTK_SDW_MAX_DP; d++) -+ mst->dp_pdi_mask[d] &= ~BIT(pdi); -+ -+ if (item && sscanf(e->texts[item], "DP%u", &dp) == 1 && -+ dp < MTK_SDW_MAX_DP) -+ mst->dp_pdi_mask[dp] |= BIT(pdi); -+ -+ return snd_soc_dapm_put_enum_double(kc, uc); -+} -+ -+/* Playback: PGA(PDIn) -> DEMUX(PDIn) -> one of DP2..DP6. */ -+#define MTK_SDW_PLAYBACK_PDI(pdi) \ -+static SOC_ENUM_SINGLE_VIRT_DECL(mtk_sdw_pdi##pdi##_enum, \ -+ mtk_sdw_playback_dp_texts); \ -+static const struct snd_kcontrol_new mtk_sdw_pdi##pdi##_demux = \ -+ SOC_DAPM_ENUM_EXT("PDI" #pdi " Demux Select", \ -+ mtk_sdw_pdi##pdi##_enum, \ -+ snd_soc_dapm_get_enum_double, \ -+ mtk_sdw_pdi_route_put) -+ -+/* Capture: one of DP7..DP15 -> MUX(PDIn) -> PGA(PDIn). */ -+#define MTK_SDW_CAPTURE_PDI(pdi) \ -+static SOC_ENUM_SINGLE_VIRT_DECL(mtk_sdw_pdi##pdi##_enum, \ -+ mtk_sdw_capture_dp_texts); \ -+static const struct snd_kcontrol_new mtk_sdw_pdi##pdi##_mux = \ -+ SOC_DAPM_ENUM_EXT("PDI" #pdi " Mux Select", \ -+ mtk_sdw_pdi##pdi##_enum, \ -+ snd_soc_dapm_get_enum_double, \ -+ mtk_sdw_pdi_route_put) -+ -+MTK_SDW_PLAYBACK_PDI(2); -+MTK_SDW_PLAYBACK_PDI(3); -+MTK_SDW_PLAYBACK_PDI(4); -+MTK_SDW_PLAYBACK_PDI(5); -+MTK_SDW_PLAYBACK_PDI(6); -+ -+MTK_SDW_CAPTURE_PDI(7); -+MTK_SDW_CAPTURE_PDI(8); -+MTK_SDW_CAPTURE_PDI(9); -+MTK_SDW_CAPTURE_PDI(10); -+MTK_SDW_CAPTURE_PDI(11); -+MTK_SDW_CAPTURE_PDI(12); -+MTK_SDW_CAPTURE_PDI(13); -+MTK_SDW_CAPTURE_PDI(14); -+MTK_SDW_CAPTURE_PDI(15); -+ -+/* PDI node + its selector. */ -+#define MTK_SDW_PDI_PGA(pdi) \ -+ SND_SOC_DAPM_PGA("PDI" #pdi, SND_SOC_NOPM, 0, 0, NULL, 0) -+#define MTK_SDW_PLAYBACK_PDI_DEMUX(pdi) \ -+ SND_SOC_DAPM_DEMUX("PDI" #pdi " Demux", SND_SOC_NOPM, 0, 0, \ -+ &mtk_sdw_pdi##pdi##_demux) -+#define MTK_SDW_CAPTURE_PDI_MUX(pdi) \ -+ SND_SOC_DAPM_MUX("PDI" #pdi " Mux", SND_SOC_NOPM, 0, 0, \ -+ &mtk_sdw_pdi##pdi##_mux) -+ -+/* DP node. */ -+#define MTK_SDW_DP_WIDGET(dp) \ -+ SND_SOC_DAPM_PGA("DP" #dp, SND_SOC_NOPM, 0, 0, NULL, 0) -+ -+static const struct snd_soc_dapm_widget mtk_sdw_dapm_widgets[] = { -+ /* BRA PDIs, no DP connection */ -+ SND_SOC_DAPM_PGA("PDI0", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_PGA("PDI1", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_PGA("PDI16", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_PGA("PDI17", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* Playback PDIs + demuxes */ -+ MTK_SDW_PDI_PGA(2), MTK_SDW_PLAYBACK_PDI_DEMUX(2), -+ MTK_SDW_PDI_PGA(3), MTK_SDW_PLAYBACK_PDI_DEMUX(3), -+ MTK_SDW_PDI_PGA(4), MTK_SDW_PLAYBACK_PDI_DEMUX(4), -+ MTK_SDW_PDI_PGA(5), MTK_SDW_PLAYBACK_PDI_DEMUX(5), -+ MTK_SDW_PDI_PGA(6), MTK_SDW_PLAYBACK_PDI_DEMUX(6), -+ /* Capture PDIs + muxes */ -+ MTK_SDW_PDI_PGA(7), MTK_SDW_CAPTURE_PDI_MUX(7), -+ MTK_SDW_PDI_PGA(8), MTK_SDW_CAPTURE_PDI_MUX(8), -+ MTK_SDW_PDI_PGA(9), MTK_SDW_CAPTURE_PDI_MUX(9), -+ MTK_SDW_PDI_PGA(10), MTK_SDW_CAPTURE_PDI_MUX(10), -+ MTK_SDW_PDI_PGA(11), MTK_SDW_CAPTURE_PDI_MUX(11), -+ MTK_SDW_PDI_PGA(12), MTK_SDW_CAPTURE_PDI_MUX(12), -+ MTK_SDW_PDI_PGA(13), MTK_SDW_CAPTURE_PDI_MUX(13), -+ MTK_SDW_PDI_PGA(14), MTK_SDW_CAPTURE_PDI_MUX(14), -+ MTK_SDW_PDI_PGA(15), MTK_SDW_CAPTURE_PDI_MUX(15), -+ /* DP nodes */ -+ MTK_SDW_DP_WIDGET(2), MTK_SDW_DP_WIDGET(3), MTK_SDW_DP_WIDGET(4), -+ MTK_SDW_DP_WIDGET(5), MTK_SDW_DP_WIDGET(6), MTK_SDW_DP_WIDGET(7), -+ MTK_SDW_DP_WIDGET(8), MTK_SDW_DP_WIDGET(9), MTK_SDW_DP_WIDGET(10), -+ MTK_SDW_DP_WIDGET(11), MTK_SDW_DP_WIDGET(12), MTK_SDW_DP_WIDGET(13), -+ MTK_SDW_DP_WIDGET(14), MTK_SDW_DP_WIDGET(15), -+}; -+ -+/* -+ * Playback edge: PDIn -> PDIn Demux -> DPx (active when demux selects "DPx"). -+ */ -+#define MTK_SDW_PLAYBACK_DEMUX_OUT(pdi, dp) \ -+ { "DP" #dp, "DP" #dp, "PDI" #pdi " Demux" } -+#define MTK_SDW_PLAYBACK_PDI_LINK(pdi) \ -+ { "PDI" #pdi " Demux", NULL, "PDI" #pdi } -+ -+/* Capture edge: DPx -> PDIn Mux -> PDIn (active when mux selects "DPx"). */ -+#define MTK_SDW_CAPTURE_MUX_IN(pdi, dp) \ -+ { "PDI" #pdi " Mux", "DP" #dp, "DP" #dp } -+#define MTK_SDW_CAPTURE_PDI_LINK(pdi) \ -+ { "PDI" #pdi, NULL, "PDI" #pdi " Mux" } -+ -+static const struct snd_soc_dapm_route mtk_sdw_dapm_routes[] = { -+ /* Playback: PDI2..PDI6 -> DP2..DP6 */ -+ MTK_SDW_PLAYBACK_PDI_LINK(2), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(2, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(2, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(2, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(2, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(2, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(3, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(3, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(3, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(3, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(3, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(4), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(4, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(4, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(4, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(4, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(4, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(5, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(5, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(5, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(5, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(5, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(6), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(6, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(6, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(6, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(6, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(6, 6), -+ /* Capture: DP7..DP15 -> PDI7..PDI15 */ -+ MTK_SDW_CAPTURE_MUX_IN(7, 7), MTK_SDW_CAPTURE_MUX_IN(7, 8), -+ MTK_SDW_CAPTURE_MUX_IN(7, 9), MTK_SDW_CAPTURE_MUX_IN(7, 10), -+ MTK_SDW_CAPTURE_MUX_IN(7, 11), MTK_SDW_CAPTURE_MUX_IN(7, 12), -+ MTK_SDW_CAPTURE_MUX_IN(7, 13), MTK_SDW_CAPTURE_MUX_IN(7, 14), -+ MTK_SDW_CAPTURE_MUX_IN(7, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(7), -+ MTK_SDW_CAPTURE_MUX_IN(8, 7), MTK_SDW_CAPTURE_MUX_IN(8, 8), -+ MTK_SDW_CAPTURE_MUX_IN(8, 9), MTK_SDW_CAPTURE_MUX_IN(8, 10), -+ MTK_SDW_CAPTURE_MUX_IN(8, 11), MTK_SDW_CAPTURE_MUX_IN(8, 12), -+ MTK_SDW_CAPTURE_MUX_IN(8, 13), MTK_SDW_CAPTURE_MUX_IN(8, 14), -+ MTK_SDW_CAPTURE_MUX_IN(8, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(8), -+ MTK_SDW_CAPTURE_MUX_IN(9, 7), MTK_SDW_CAPTURE_MUX_IN(9, 8), -+ MTK_SDW_CAPTURE_MUX_IN(9, 9), MTK_SDW_CAPTURE_MUX_IN(9, 10), -+ MTK_SDW_CAPTURE_MUX_IN(9, 11), MTK_SDW_CAPTURE_MUX_IN(9, 12), -+ MTK_SDW_CAPTURE_MUX_IN(9, 13), MTK_SDW_CAPTURE_MUX_IN(9, 14), -+ MTK_SDW_CAPTURE_MUX_IN(9, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(9), -+ MTK_SDW_CAPTURE_MUX_IN(10, 7), MTK_SDW_CAPTURE_MUX_IN(10, 8), -+ MTK_SDW_CAPTURE_MUX_IN(10, 9), MTK_SDW_CAPTURE_MUX_IN(10, 10), -+ MTK_SDW_CAPTURE_MUX_IN(10, 11), MTK_SDW_CAPTURE_MUX_IN(10, 12), -+ MTK_SDW_CAPTURE_MUX_IN(10, 13), MTK_SDW_CAPTURE_MUX_IN(10, 14), -+ MTK_SDW_CAPTURE_MUX_IN(10, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(10), -+ MTK_SDW_CAPTURE_MUX_IN(11, 7), MTK_SDW_CAPTURE_MUX_IN(11, 8), -+ MTK_SDW_CAPTURE_MUX_IN(11, 9), MTK_SDW_CAPTURE_MUX_IN(11, 10), -+ MTK_SDW_CAPTURE_MUX_IN(11, 11), MTK_SDW_CAPTURE_MUX_IN(11, 12), -+ MTK_SDW_CAPTURE_MUX_IN(11, 13), MTK_SDW_CAPTURE_MUX_IN(11, 14), -+ MTK_SDW_CAPTURE_MUX_IN(11, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(11), -+ MTK_SDW_CAPTURE_MUX_IN(12, 7), MTK_SDW_CAPTURE_MUX_IN(12, 8), -+ MTK_SDW_CAPTURE_MUX_IN(12, 9), MTK_SDW_CAPTURE_MUX_IN(12, 10), -+ MTK_SDW_CAPTURE_MUX_IN(12, 11), MTK_SDW_CAPTURE_MUX_IN(12, 12), -+ MTK_SDW_CAPTURE_MUX_IN(12, 13), MTK_SDW_CAPTURE_MUX_IN(12, 14), -+ MTK_SDW_CAPTURE_MUX_IN(12, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(12), -+ MTK_SDW_CAPTURE_MUX_IN(13, 7), MTK_SDW_CAPTURE_MUX_IN(13, 8), -+ MTK_SDW_CAPTURE_MUX_IN(13, 9), MTK_SDW_CAPTURE_MUX_IN(13, 10), -+ MTK_SDW_CAPTURE_MUX_IN(13, 11), MTK_SDW_CAPTURE_MUX_IN(13, 12), -+ MTK_SDW_CAPTURE_MUX_IN(13, 13), MTK_SDW_CAPTURE_MUX_IN(13, 14), -+ MTK_SDW_CAPTURE_MUX_IN(13, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(13), -+ MTK_SDW_CAPTURE_MUX_IN(14, 7), MTK_SDW_CAPTURE_MUX_IN(14, 8), -+ MTK_SDW_CAPTURE_MUX_IN(14, 9), MTK_SDW_CAPTURE_MUX_IN(14, 10), -+ MTK_SDW_CAPTURE_MUX_IN(14, 11), MTK_SDW_CAPTURE_MUX_IN(14, 12), -+ MTK_SDW_CAPTURE_MUX_IN(14, 13), MTK_SDW_CAPTURE_MUX_IN(14, 14), -+ MTK_SDW_CAPTURE_MUX_IN(14, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(14), -+ MTK_SDW_CAPTURE_MUX_IN(15, 7), MTK_SDW_CAPTURE_MUX_IN(15, 8), -+ MTK_SDW_CAPTURE_MUX_IN(15, 9), MTK_SDW_CAPTURE_MUX_IN(15, 10), -+ MTK_SDW_CAPTURE_MUX_IN(15, 11), MTK_SDW_CAPTURE_MUX_IN(15, 12), -+ MTK_SDW_CAPTURE_MUX_IN(15, 13), MTK_SDW_CAPTURE_MUX_IN(15, 14), -+ MTK_SDW_CAPTURE_MUX_IN(15, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(15), -+}; -+ -+static int mtk_sdw_add_dai_routes(struct snd_soc_component *comp) -+{ -+ struct mtk_sdw *mst = snd_soc_component_get_drvdata(comp); -+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp); -+ int i, p, ret; -+ -+ for (i = 0; i < mst->num_links; i++) { -+ struct mtk_sdw_link *link = &mst->links[i]; -+ int offset; -+ -+ offset = 0; -+ for (p = 0; p < link->src_num; p++, offset++) { -+ char dai[32], dp[8]; -+ struct snd_soc_dapm_route r = { dai, NULL, dp }; -+ -+ snprintf(dai, sizeof(dai), "SDW%d_Playback%u", -+ link->ip_idx, offset); -+ snprintf(dp, sizeof(dp), "DP%u", link->src_base + p); -+ ret = snd_soc_dapm_add_routes(dapm, &r, 1); -+ if (ret) -+ return ret; -+ } -+ -+ offset = 0; -+ for (p = 0; p < link->sink_num; p++, offset++) { -+ char dai[32], dp[8]; -+ struct snd_soc_dapm_route r = { dp, NULL, dai }; -+ -+ snprintf(dai, sizeof(dai), "SDW%d_Capture%u", -+ link->ip_idx, offset); -+ snprintf(dp, sizeof(dp), "DP%u", link->sink_base + p); -+ ret = snd_soc_dapm_add_routes(dapm, &r, 1); -+ if (ret) -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int mtk_sdw_component_probe(struct snd_soc_component *comp) -+{ -+ return mtk_sdw_add_dai_routes(comp); -+} -+ -+static const struct snd_soc_component_driver mtk_sdw_component = { -+ .name = "mtk-soundwire", -+ .probe = mtk_sdw_component_probe, -+ .dapm_widgets = mtk_sdw_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(mtk_sdw_dapm_widgets), -+ .dapm_routes = mtk_sdw_dapm_routes, -+ .num_dapm_routes = ARRAY_SIZE(mtk_sdw_dapm_routes), -+}; -+ -+static int mtk_sdw_init_dai(struct mtk_sdw *mst, struct snd_soc_dai_driver *drv, -+ int idx, struct mtk_sdw_link *link, -+ unsigned int port, int offset, bool playback) -+{ -+ struct snd_soc_pcm_stream *stream; -+ -+ drv->id = idx; -+ drv->ops = &mtk_sdw_dai_ops; -+ -+ if (playback) { -+ drv->name = devm_kasprintf(mst->dev, GFP_KERNEL, -+ "SDW%d_Playback%u", -+ link->ip_idx, offset); -+ if (!drv->name) -+ return -ENOMEM; -+ -+ stream = &drv->playback; -+ } else { -+ drv->name = devm_kasprintf(mst->dev, GFP_KERNEL, -+ "SDW%d_Capture%u", -+ link->ip_idx, offset); -+ if (!drv->name) -+ return -ENOMEM; -+ -+ stream = &drv->capture; -+ } -+ -+ stream->channels_min = 2; -+ stream->channels_max = 8; -+ stream->rates = SNDRV_PCM_RATE_48000; -+ stream->rates = SNDRV_PCM_RATE_8000_384000; -+ stream->formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE; -+ -+ stream->stream_name = drv->name; -+ -+ mst->dais[idx].link = link; -+ mst->dais[idx].port_num = port; -+ -+ return 0; -+} -+ -+static int mtk_sdw_register_dais(struct mtk_sdw *mst) -+{ -+ struct snd_soc_dai_driver *drvs; -+ struct device *dev = mst->dev; -+ int i, p, idx = 0, num = 0, ret; -+ -+ for (i = 0; i < mst->num_links; i++) -+ num += mst->links[i].src_num + mst->links[i].sink_num; -+ if (!num) -+ return dev_err_probe(dev, -EINVAL, "no data ports allocated\n"); -+ -+ mst->dais = devm_kcalloc(dev, num, sizeof(*mst->dais), GFP_KERNEL); -+ if (!mst->dais) -+ return -ENOMEM; -+ -+ drvs = devm_kcalloc(dev, num, sizeof(*drvs), GFP_KERNEL); -+ if (!drvs) -+ return -ENOMEM; -+ -+ for (i = 0; i < mst->num_links; i++) { -+ struct mtk_sdw_link *link = &mst->links[i]; -+ int offset; -+ -+ offset = 0; -+ /* Source ports -> playback DAIs */ -+ for (p = 0; p < link->src_num; p++, idx++, offset++) { -+ ret = mtk_sdw_init_dai(mst, &drvs[idx], idx, link, -+ link->src_base + p, offset, -+ true); -+ if (ret) -+ return ret; -+ } -+ -+ offset = 0; -+ /* Sink ports -> capture DAIs */ -+ for (p = 0; p < link->sink_num; p++, idx++, offset++) { -+ ret = mtk_sdw_init_dai(mst, &drvs[idx], idx, link, -+ link->sink_base + p, offset, -+ false); -+ if (ret) -+ return ret; -+ } -+ } -+ mst->num_dais = num; -+ -+ return devm_snd_soc_register_component(dev, &mtk_sdw_component, drvs, -+ num); -+} -+ -+/* ======================================================================= -+ * Per-IP bring-up -+ * ======================================================================= -+ */ -+ -+static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_link *link = &mst->links[idx]; -+ struct mtk_sdw_core *core = &link->core; -+ int ret; -+ -+ link->master = mst; -+ link->ip_idx = idx; -+ -+ core->dev = mst->dev; -+ core->priv = link; -+ -+ core->bus.link_id = idx; -+ core->bus.prop.mclk_freq = SDW_DEFAULT_MCLK_CLK_FREQ; -+ -+ core->bus.dev = mst->dev; -+ ret = sdw_bus_master_add(&core->bus, mst->dev, mst->dev->fwnode); -+ if (ret) { -+ dev_err(mst->dev, "IP%d: bus_master_add failed: %d\n", -+ idx, ret); -+ return ret; -+ } -+ -+ ret = mtk_sdw_core_hw_init(core); -+ if (ret) { -+ sdw_bus_master_delete(&core->bus); -+ return ret; -+ } -+ -+ mtk_sdw_enable_irq(core, true); -+ dev_info(mst->dev, "IP%d: SoundWire bus ready\n", idx); -+ return 0; -+} -+ -+static void mtk_sdw_link_deinit(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_core *core = &mst->links[idx].core; -+ -+ mtk_sdw_enable_irq(core, false); -+ sdw_bus_master_delete(&core->bus); -+} -+ -+static void mtk_init_sdw_master(struct mtk_sdw *mst) -+{ -+ int i; -+ -+ mst->tzd_delay = 3; -+ mst->tzd_inverse = 0; -+ mst->phy_delay = 2; -+ mst->phy_double_delay = 0; -+ mst->num_links = SDW_MAX_HWIP_NUM; -+ -+ for (i = 0; i < SDW_MAX_HWIP_NUM; i++) -+ mst->controller_en_list |= (1UL << i); -+} -+ -+static int mtk_sdw_probe_controller(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct mtk_sdw *mst; -+ u32 hw_ver = MTK_SDW_HW_VER_MT8901; -+ u32 mmio[2]; -+ int i, ret; -+ -+ mst = devm_kzalloc(dev, sizeof(*mst), GFP_KERNEL); -+ if (!mst) -+ return -ENOMEM; -+ -+ mtk_init_sdw_master(mst); -+ -+ mst->dev = dev; -+ mutex_init(&mst->group_lock); -+ platform_set_drvdata(pdev, mst); -+ -+ ret = device_property_read_u32_array(dev, "afe-base", mmio, 2); -+ if (ret) -+ return dev_err_probe(dev, ret, -+ "missing/invalid afe-base property\n"); -+ dev_info(dev, "address %x, size %d\n", mmio[0], mmio[1]); -+ -+ mst->base = devm_ioremap(dev, mmio[0], mmio[1]); -+ if (!mst->base) -+ return -ENOMEM; -+ mst->top_pdi = mst->base + AFE_SDW_TOP_PDI_REG_BASE; -+ mst->top_con = mst->base + AFE_SDW_TOP_CON_REG_BASE; -+ -+ device_property_read_u32(dev, "acpi-scd-hw-ver", &hw_ver); -+ if (hw_ver >= MTK_SDW_HW_VER_MAX) -+ return dev_err_probe(dev, -EINVAL, -+ "unknown acpi-scd-hw-ver %u\n", hw_ver); -+ -+ mst->hw_ver = hw_ver; -+ -+ ret = mtk_sdw_top_config_select(mst, mst->hw_ver); -+ if (ret) -+ return ret; -+ -+ /* Timing delays from ACPI _DSD. */ -+ device_property_read_u32(dev, "acpi-scd-tzd-delay", &mst->tzd_delay); -+ device_property_read_u32(dev, "acpi-scd-phy-delay", &mst->phy_delay); -+ device_property_read_u32(dev, "acpi-scd-phy-double-delay", -+ &mst->phy_double_delay); -+ -+ if (mst->tzd_delay <= mst->phy_delay) { -+ dev_err(dev, "invalid delay, tzd %u - phy %u", mst->tzd_delay, -+ mst->phy_delay); -+ return -EINVAL; -+ } -+ -+ mtk_sdw_top_init_settings(mst); -+ mtk_sdw_top_configure_delays(mst); -+ -+ for (i = 0; i < mst->num_links; i++) { -+ int irq = platform_get_irq(pdev, i); -+ struct mtk_sdw_core *core = &mst->links[i].core; -+ -+ if (irq < 0) { -+ ret = irq; -+ goto err; -+ } -+ mst->links[i].irq = irq; -+ mst->links[i].ip_idx = i; -+ -+ ret = mtk_sdw_parse_dp_allocation(mst, i); -+ if (ret) -+ goto err; -+ -+ core->regs = devm_platform_ioremap_resource(pdev, i); -+ if (IS_ERR(core->regs)) { -+ ret = PTR_ERR(core->regs); -+ goto err; -+ } -+ -+ /* -+ * The line is shared and MCP_INTMASK holds whatever POST left, -+ * so the handler can run as soon as it is registered: the lock -+ * and work items it uses must exist first. -+ */ -+ ret = mtk_sdw_core_init(core); -+ if (ret) -+ goto err; -+ -+ ret = devm_request_irq(dev, irq, mtk_sdw_core_irq, IRQF_SHARED, -+ dev_name(dev), core); -+ if (ret) { -+ dev_err(dev, "IP%d: request_irq failed: %d\n", i, ret); -+ goto err; -+ } -+ -+ ret = mtk_sdw_link_init(mst, i); -+ if (ret) -+ goto err; -+ } -+ -+ ret = mtk_sdw_register_dais(mst); -+ if (ret) { -+ dev_err(dev, "failed to register DAIs: %d\n", ret); -+ goto err; -+ } -+ -+ dev_info(dev, "MediaTek SoundWire ready, %d link(s), %d DAI(s)\n", -+ mst->num_links, mst->num_dais); -+ -+ return 0; -+ -+err: -+ while (--i >= 0) -+ mtk_sdw_link_deinit(mst, i); -+ -+ return ret; -+} -+ -+static int mtk_sdw_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ int ret; -+ -+ ret = mtk_sdw_probe_controller(pdev); -+ if (ret) { -+ dev_err(dev, "failed to probe_controller %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void mtk_sdw_remove(struct platform_device *pdev) -+{ -+ struct mtk_sdw *mst = platform_get_drvdata(pdev); -+ int i; -+ -+ for (i = mst->num_links - 1; i >= 0; i--) -+ mtk_sdw_link_deinit(mst, i); -+} -+ -+static const struct acpi_device_id mtk_sdw_acpi_match[] = { -+ { "NVDA9100", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, mtk_sdw_acpi_match); -+ -+static struct platform_driver mtk_sdw_driver = { -+ .probe = mtk_sdw_probe, -+ .remove = mtk_sdw_remove, -+ .driver = { -+ .name = "mtk-soundwire", -+ .acpi_match_table = mtk_sdw_acpi_match, -+ }, -+}; -+module_platform_driver(mtk_sdw_driver); -+ -+MODULE_DESCRIPTION("MediaTek SoundWire master"); -+MODULE_AUTHOR("Trevor Wu "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/soundwire/mtk-sdw.h b/drivers/soundwire/mtk-sdw.h -new file mode 100644 -index 0000000000..2c91eb609b ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw.h -@@ -0,0 +1,85 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master driver header. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_H -+#define __MTK_SDW_H -+ -+#include "mtk-sdw-common.h" -+ -+enum mt8901_afe_clk_domain { -+ MT8901_HOPPING_CLK_DOMAIN = 0, -+ MT8901_APLL_CLK_DOMAIN = 1, -+}; -+ -+enum mtk_sdw_sample_rate { -+ RATE_384000 = 384000, -+ RATE_352800 = 352800, -+ RATE_192000 = 192000, -+ RATE_176400 = 176400, -+ RATE_96000 = 96000, -+ RATE_88200 = 88200, -+ RATE_48000 = 48000, -+ RATE_44100 = 44100, -+ RATE_32000 = 32000, -+ RATE_29400 = 29400, -+ RATE_24000 = 24000, -+ RATE_22050 = 22050, -+ RATE_16000 = 16000, -+ RATE_14700 = 14700, -+ RATE_12000 = 12000, -+ RATE_11025 = 11025, -+ RATE_8000 = 8000, -+ RATE_7350 = 7350, -+}; -+ -+enum mt8901_afe_fs_mode { -+ MT8901_FS_8K = 0, -+ MT8901_FS_11D025K = 1, -+ MT8901_FS_12K = 2, -+ MT8901_FS_16K = 4, -+ MT8901_FS_22D05K = 5, -+ MT8901_FS_24K = 6, -+ MT8901_FS_32K = 8, -+ MT8901_FS_44D1K = 9, -+ MT8901_FS_48K = 10, -+ MT8901_FS_88D2K = 13, -+ MT8901_FS_96K = 14, -+ MT8901_FS_176D4K = 17, -+ MT8901_FS_192K = 18, -+ MT8901_FS_352D8K = 21, -+ MT8901_FS_384K = 22, -+ MT8901_ETDM_OUT0_HOPPING_DOMAIN = 4, -+ MT8901_ETDM_OUT5_HOPPING_DOMAIN = 9, -+ MT8901_ETDM_IN0_HOPPING_DOMAIN = 12, -+ MT8901_ETDM_IN5_HOPPING_DOMAIN = 17, -+ MT8901_FS_TOP_PDI_IP0_PDI0 = 24, -+ MT8901_FS_TOP_PDI_IP1_PDI0 = 25, -+ MT8901_FS_TOP_PDI_IP0_PDI1 = 26, -+ MT8901_FS_TOP_PDI_IP1_PDI1 = 27, -+}; -+ -+#define IS_48K_RATE_DOMAIN(x) (((x) % 8000) == 0) -+ -+#define SDW_DEFAULT_CH_PER_PDI 2 -+ -+#define AFE_SDW_TOP_PDI_REG_BASE (0x9000) -+#define AFE_SDW_TOP_CON_REG_BASE (0x9048) -+ -+#define SDW_DEFAULT_MAX_BUS_CLK_FREQ (6144000) -+#define SDW_DEFAULT_MCLK_CLK_FREQ (24576000) -+#define SDW_DEFAULT_FRAME_RATE (24000) -+#define SDW_DEFAULT_FRAME_SHAPE_ROW (64) -+#define SDW_DEFAULT_FRAME_SHAPE_COL (8) -+ -+#define MTK_SDW_DP_SOURCE_BASE 2 /* DP2.. (master source / playback) */ -+#define MTK_SDW_DP_SOURCE_NUM 5 -+#define MTK_SDW_DP_SINK_BASE 7 /* DP7.. (master sink / capture) */ -+#define MTK_SDW_DP_SINK_NUM 9 -+#define MTK_SDW_MAX_DAIS \ -+ ((MTK_SDW_DP_SOURCE_NUM) + (MTK_SDW_DP_SINK_NUM)) /* BRA not included */ -+ -+#endif /* __MTK_SDW_H */ -From 05ed22db50e16d80e603b9adddf35d59ce2bb31b Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:06 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: register machine platform - device - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -ALSA needs a machine driver to bind the platform DAIs and the -SoundWire codecs into a sound card. Register a machine platform device -from the SoundWire manager, carrying the codec topology discovered -during enumeration, so a matching machine driver can complete the card -registration. - -Signed-off-by: Trevor Wu -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/Kconfig | 1 + - drivers/soundwire/Makefile | 2 +- - drivers/soundwire/mtk-sdw-common.h | 1 + - drivers/soundwire/mtk-sdw-mach.c | 167 +++++++++++++++++++++++++++++ - drivers/soundwire/mtk-sdw-mach.h | 20 ++++ - drivers/soundwire/mtk-sdw.c | 39 ++++++- - 6 files changed, 228 insertions(+), 2 deletions(-) - create mode 100644 drivers/soundwire/mtk-sdw-mach.c - create mode 100644 drivers/soundwire/mtk-sdw-mach.h - -diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig -index ab9c011987..9e96cf1bca 100644 ---- a/drivers/soundwire/Kconfig -+++ b/drivers/soundwire/Kconfig -@@ -61,6 +61,7 @@ config SOUNDWIRE_MTK - tristate "MediaTek SoundWire Master driver" - select SOUNDWIRE_GENERIC_ALLOCATION - depends on SND_SOC && ACPI -+ select SND_SOC_ACPI - help - SoundWire MediaTek Master driver. - If you have an MediaTek platform which has a SoundWire Master then -diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile -index 2e173c2791..063de2b271 100644 ---- a/drivers/soundwire/Makefile -+++ b/drivers/soundwire/Makefile -@@ -38,5 +38,5 @@ soundwire-qcom-y := qcom.o - obj-$(CONFIG_SOUNDWIRE_QCOM) += soundwire-qcom.o - - #MediaTek driver --soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o -+soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o mtk-sdw-mach.o - obj-$(CONFIG_SOUNDWIRE_MTK) += soundwire-mtk.o -diff --git a/drivers/soundwire/mtk-sdw-common.h b/drivers/soundwire/mtk-sdw-common.h -index 30e3645abe..32912b1272 100644 ---- a/drivers/soundwire/mtk-sdw-common.h -+++ b/drivers/soundwire/mtk-sdw-common.h -@@ -69,6 +69,7 @@ struct mtk_sdw { - struct mtk_sdw_dai *dais; - int num_dais; - u16 dp_pdi_mask[MTK_SDW_MAX_DP]; -+ struct platform_device *mach_dev; - }; - - #endif /* __MTK_SDW_COMMON_H */ -diff --git a/drivers/soundwire/mtk-sdw-mach.c b/drivers/soundwire/mtk-sdw-mach.c -new file mode 100644 -index 0000000000..582482b43e ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw-mach.c -@@ -0,0 +1,167 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire audio machine selection (codec-combination tables). -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#include -+#include -+#include -+#include "mtk-sdw-mach.h" -+ -+static const struct snd_soc_acpi_endpoint rt1320_endpoints[] = { -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 0, -+ .group_id = 1, -+ }, -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 1, -+ .group_id = 1, -+ }, -+}; -+ -+static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { -+ { -+ .num = 0, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+ { -+ .num = 2, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+}; -+ -+/* -+ * Config 0: SDW0 = RT1320 (amp), SDW1 = RT712 (jack codec). -+ */ -+static const struct snd_soc_acpi_adr_device rt1320_l0_adr[] = { -+ { -+ .adr = 0x000030025D132001ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[0], -+ .name_prefix = "rt1320-1", -+ }, -+ { -+ .adr = 0x000032025D132001ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[1], -+ .name_prefix = "rt1320-2", -+ }, -+}; -+ -+static const struct snd_soc_acpi_adr_device rt712_l1_adr[] = { -+ { -+ .adr = 0x000130025D071201ull, -+ .num_endpoints = ARRAY_SIZE(rt712_endpoints), -+ .endpoints = rt712_endpoints, -+ .name_prefix = "rt712", -+ }, -+}; -+ -+static const struct snd_soc_acpi_link_adr mtk_sdw_rt1320_l0_rt712_l1[] = { -+ { -+ .mask = BIT(0), -+ .num_adr = ARRAY_SIZE(rt1320_l0_adr), -+ .adr_d = rt1320_l0_adr, -+ }, -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(rt712_l1_adr), -+ .adr_d = rt712_l1_adr, -+ }, -+ {} -+}; -+ -+static struct snd_soc_acpi_mach mtk_sdw_machines[] = { -+ { -+ .link_mask = BIT(0) | BIT(1), -+ .links = mtk_sdw_rt1320_l0_rt712_l1, -+ .drv_name = "mtk_sdw_mc", -+ }, -+ {} -+}; -+ -+static void mtk_sdw_log_peripheral(struct device *dev, -+ struct sdw_slave *slave) -+{ -+ dev_info(dev, -+ "[%d] class=0x%02x mfg=0x%04x part=0x%04x uniq=0x%x ver=0x%x\n", -+ slave->bus->link_id, slave->id.class_id, slave->id.mfg_id, -+ slave->id.part_id, slave->id.unique_id, slave->id.sdw_version); -+} -+ -+static struct sdw_peripherals *mtk_sdw_get_peripherals(struct mtk_sdw *mst) -+{ -+ struct sdw_peripherals *peripherals; -+ struct sdw_slave *slave; -+ struct sdw_bus *bus; -+ int max_peripherals_num; -+ int i, idx = 0; -+ -+ max_peripherals_num = mst->num_links * SDW_MAX_DEVICES; -+ -+ peripherals = kmalloc_flex(*peripherals, array, max_peripherals_num, -+ GFP_KERNEL); -+ if (!peripherals) -+ return NULL; -+ -+ for (i = 0; i < mst->num_links; i++) { -+ bus = &mst->links[i].core.bus; -+ mutex_lock(&bus->bus_lock); -+ list_for_each_entry(slave, &bus->slaves, node) { -+ if (idx >= max_peripherals_num) { -+ dev_warn(mst->dev, "slave count exceeds capacity, truncating"); -+ break; -+ } -+ peripherals->array[idx++] = slave; -+ mtk_sdw_log_peripheral(mst->dev, slave); -+ } -+ mutex_unlock(&bus->bus_lock); -+ } -+ peripherals->num_peripherals = idx; -+ -+ return peripherals; -+} -+ -+struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst) -+{ -+ struct sdw_peripherals *peripherals; -+ struct snd_soc_acpi_mach *mach; -+ const struct snd_soc_acpi_link_adr *link; -+ -+ peripherals = mtk_sdw_get_peripherals(mst); -+ if (!peripherals) -+ return NULL; -+ -+ if (!peripherals->num_peripherals) { -+ dev_dbg(mst->dev, "no SoundWire peripherals enumerated\n"); -+ kfree(peripherals); -+ return NULL; -+ } -+ -+ for (mach = mtk_sdw_machines; mach->link_mask; mach++) { -+ for (link = mach->links; link && link->num_adr; link++) { -+ if (!snd_soc_acpi_sdw_link_slaves_found(mst->dev, link, -+ peripherals)) -+ break; -+ } -+ if (link && !link->num_adr) { -+ mach->mach_params.links = mach->links; -+ mach->mach_params.link_mask = mach->link_mask; -+ kfree(peripherals); -+ return mach; -+ } -+ } -+ dev_dbg(mst->dev, "no SoundWire machine matched\n"); -+ kfree(peripherals); -+ return NULL; -+} -diff --git a/drivers/soundwire/mtk-sdw-mach.h b/drivers/soundwire/mtk-sdw-mach.h -new file mode 100644 -index 0000000000..158aae2652 ---- /dev/null -+++ b/drivers/soundwire/mtk-sdw-mach.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire audio machine selection (codec-combination tables). -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_MACH_H -+#define __MTK_SDW_MACH_H -+ -+#include "mtk-sdw-common.h" -+ -+struct snd_soc_acpi_mach; -+ -+/* mtk-sdw-mach.c: match enumerated SoundWire peripherals against the codec- -+ * combination tables; returns the machine row to spawn, or NULL. -+ */ -+struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst); -+ -+#endif /* __MTK_SDW_MACH_H */ -diff --git a/drivers/soundwire/mtk-sdw.c b/drivers/soundwire/mtk-sdw.c -index 784250dc72..09329088cd 100644 ---- a/drivers/soundwire/mtk-sdw.c -+++ b/drivers/soundwire/mtk-sdw.c -@@ -19,6 +19,7 @@ - #include - #include - #include "mtk-sdw.h" -+#include "mtk-sdw-mach.h" - #include "mtk-sdw-top.h" - - static int mtk_sdw_parse_dp_allocation(struct mtk_sdw *mst, int idx) -@@ -785,6 +786,29 @@ static void mtk_init_sdw_master(struct mtk_sdw *mst) - mst->controller_en_list |= (1UL << i); - } - -+static int mtk_sdw_register_machine(struct mtk_sdw *mst) -+{ -+ struct snd_soc_acpi_mach *mach; -+ -+ mach = mtk_sdw_machine_select(mst); -+ if (!mach) { -+ dev_info(mst->dev, "no card from this controller\n"); -+ return 0; /* no card from this controller; not an error */ -+ } -+ -+ mst->mach_dev = platform_device_register_data(mst->dev, mach->drv_name, -+ PLATFORM_DEVID_NONE, -+ mach, sizeof(*mach)); -+ if (IS_ERR(mst->mach_dev)) { -+ dev_err(mst->dev, "failed to register machine %s\n", -+ mach->drv_name); -+ return PTR_ERR(mst->mach_dev); -+ } -+ -+ dev_info(mst->dev, "registered SoundWire machine %s\n", mach->drv_name); -+ return 0; -+} -+ - static int mtk_sdw_probe_controller(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -904,7 +928,8 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - static int mtk_sdw_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -- int ret; -+ struct mtk_sdw *mst; -+ int i, ret; - - ret = mtk_sdw_probe_controller(pdev); - if (ret) { -@@ -912,6 +937,16 @@ static int mtk_sdw_probe(struct platform_device *pdev) - return ret; - } - -+ mst = platform_get_drvdata(pdev); -+ -+ ret = mtk_sdw_register_machine(mst); -+ if (ret) { -+ for (i = mst->num_links - 1; i >= 0; i--) -+ mtk_sdw_link_deinit(mst, i); -+ -+ return ret; -+ } -+ - return 0; - } - -@@ -920,6 +955,8 @@ static void mtk_sdw_remove(struct platform_device *pdev) - struct mtk_sdw *mst = platform_get_drvdata(pdev); - int i; - -+ if (mst->mach_dev) -+ platform_device_unregister(mst->mach_dev); - for (i = mst->num_links - 1; i >= 0; i--) - mtk_sdw_link_deinit(mst, i); - } -From ea1913669f55a08b1343935c3939013818f987b6 Mon Sep 17 00:00:00 2001 -From: mtk34643 -Date: Thu, 3 Sep 2026 17:45:07 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: mt8901: add audio platform - driver - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Add the mt8901 AFE platform driver: memory interfaces, the AFE -interconnect, DAI definitions and the platform component used by the -machine driver. - -Folded review fixes from the bring-up: request the AFE interrupt only -after the regmap is set up so the handler cannot run against an -uninitialized map, and limit VUL_CM2 to the 16 channels that are -physically wired. - -Signed-off-by: mtk34643 -Signed-off-by: Trevor Wu -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - sound/soc/mediatek/Kconfig | 11 + - sound/soc/mediatek/Makefile | 1 + - sound/soc/mediatek/common/mtk-afe-fe-dai.c | 6 + - sound/soc/mediatek/common/mtk-base-afe.h | 15 + - sound/soc/mediatek/mt8901/Makefile | 8 + - sound/soc/mediatek/mt8901/mt8901-afe-clk.c | 46 + - sound/soc/mediatek/mt8901/mt8901-afe-clk.h | 18 + - sound/soc/mediatek/mt8901/mt8901-afe-common.h | 99 + - sound/soc/mediatek/mt8901/mt8901-afe-pcm.c | 1976 +++++++++++++++ - .../mediatek/mt8901/mt8901-dai-soundwire.c | 213 ++ - sound/soc/mediatek/mt8901/mt8901-reg.h | 2188 +++++++++++++++++ - 11 files changed, 4581 insertions(+) - create mode 100644 sound/soc/mediatek/mt8901/Makefile - create mode 100644 sound/soc/mediatek/mt8901/mt8901-afe-clk.c - create mode 100644 sound/soc/mediatek/mt8901/mt8901-afe-clk.h - create mode 100644 sound/soc/mediatek/mt8901/mt8901-afe-common.h - create mode 100644 sound/soc/mediatek/mt8901/mt8901-afe-pcm.c - create mode 100644 sound/soc/mediatek/mt8901/mt8901-dai-soundwire.c - create mode 100644 sound/soc/mediatek/mt8901/mt8901-reg.h - -diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig -index 224746e766..80306dd20e 100644 ---- a/sound/soc/mediatek/Kconfig -+++ b/sound/soc/mediatek/Kconfig -@@ -393,4 +393,15 @@ config SND_SOC_MT8196_NAU8825 - Select Y if you have such device. - If unsure select "N". - -+config SND_SOC_MT8901 -+ tristate "ASoC support for MediaTek MT8901 chip" -+ depends on ARCH_MEDIATEK && ACPI -+ depends on MTK_POWER_WRAP -+ select SND_SOC_MEDIATEK -+ help -+ This adds ASoC platform driver support for MediaTek MT8901 chip -+ that can be used with other codecs. -+ Select Y if you have such device. -+ If unsure select "N". -+ - endmenu -diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile -index a6815a3c59..e46b9d62e4 100644 ---- a/sound/soc/mediatek/Makefile -+++ b/sound/soc/mediatek/Makefile -@@ -12,3 +12,4 @@ obj-$(CONFIG_SND_SOC_MT8195) += mt8195/ - obj-$(CONFIG_SND_SOC_MT8365) += mt8365/ - obj-$(CONFIG_SND_SOC_MT8189) += mt8189/ - obj-$(CONFIG_SND_SOC_MT8196) += mt8196/ -+obj-$(CONFIG_SND_SOC_MT8901) += mt8901/ -diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c -index 2a20fa5dba..7d9dc46531 100644 ---- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c -+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c -@@ -455,6 +455,12 @@ int mtk_memif_set_channel(struct mtk_base_afe *afe, - struct mtk_base_afe_memif *memif = &afe->memif[id]; - unsigned int mono; - -+ if (memif->data->ch_num_reg > 0) { -+ mtk_regmap_update_bits(afe->regmap, memif->data->ch_num_reg, -+ memif->data->ch_num_maskbit, channel, -+ memif->data->ch_num_shift); -+ } -+ - if (memif->data->mono_shift < 0) - return 0; - -diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h -index a406f2e3e7..0161e5164a 100644 ---- a/sound/soc/mediatek/common/mtk-base-afe.h -+++ b/sound/soc/mediatek/common/mtk-base-afe.h -@@ -72,6 +72,16 @@ struct mtk_base_memif_data { - int minlen_reg; - int minlen_mask; - int minlen_shift; -+ int maxlen_reg; -+ int maxlen_mask; -+ int maxlen_shift; -+ int domain_reg; -+ int domain_shift; -+ int domain_mask; -+ /* one hart mode */ -+ int one_heart_mode_sel_reg; -+ int one_heart_mode_shift; -+ int one_heart_mode_mask_shift; - }; - - struct mtk_base_irq_data { -@@ -87,6 +97,11 @@ struct mtk_base_irq_data { - int irq_clr_reg; - int irq_clr_shift; - int irq_status_shift; -+ int irq_domain_reg; -+ int irq_domain_shift; -+ int irq_domain_maskbit; -+ int irq_mask_reg; -+ int irq_mask_shift; - }; - - struct device; -diff --git a/sound/soc/mediatek/mt8901/Makefile b/sound/soc/mediatek/mt8901/Makefile -new file mode 100644 -index 0000000000..8b4f9b54f6 ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+snd-soc-mt8901-afe-y := \ -+ mt8901-afe-clk.o \ -+ mt8901-afe-pcm.o \ -+ mt8901-dai-soundwire.o -+ -+obj-$(CONFIG_SND_SOC_MT8901) += snd-soc-mt8901-afe.o -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-clk.c b/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -new file mode 100644 -index 0000000000..44aa2b1ba2 ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -@@ -0,0 +1,46 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * mt8901-afe-clk.c -- MediaTek 8901 afe clock ctrl -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#include "mt8901-afe-common.h" -+#include "mt8901-afe-clk.h" -+#include "mt8901-reg.h" -+ -+static int mt8901_afe_enable_afe_on(struct mtk_base_afe *afe) -+{ -+ unsigned int mask; -+ -+ mask = AUDIO_ENGEN_CON0_APLL2_MASK | -+ AUDIO_ENGEN_CON0_APLL1_MASK | -+ AUDIO_ENGEN_CON0_26M_MASK; -+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, mask, mask); -+ return 0; -+} -+ -+static int mt8901_afe_disable_afe_on(struct mtk_base_afe *afe) -+{ -+ unsigned int mask; -+ -+ mask = AUDIO_ENGEN_CON0_APLL2_MASK | -+ AUDIO_ENGEN_CON0_APLL1_MASK | -+ AUDIO_ENGEN_CON0_26M_MASK; -+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, mask, 0x0); -+ return 0; -+} -+ -+int mt8901_afe_enable_main_clock(struct mtk_base_afe *afe) -+{ -+ mt8901_afe_enable_afe_on(afe); -+ return 0; -+} -+ -+int mt8901_afe_disable_main_clock(struct mtk_base_afe *afe) -+{ -+ mt8901_afe_disable_afe_on(afe); -+ return 0; -+} -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-clk.h b/sound/soc/mediatek/mt8901/mt8901-afe-clk.h -new file mode 100644 -index 0000000000..6099dcd680 ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-clk.h -@@ -0,0 +1,18 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * mt8901-afe-clk.h -- MediaTek 8901 afe clock ctrl definition -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#ifndef _MT8901_AFE_CLK_H_ -+#define _MT8901_AFE_CLK_H_ -+ -+struct mtk_base_afe; -+ -+int mt8901_afe_enable_main_clock(struct mtk_base_afe *afe); -+int mt8901_afe_disable_main_clock(struct mtk_base_afe *afe); -+ -+#endif -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-common.h b/sound/soc/mediatek/mt8901/mt8901-afe-common.h -new file mode 100644 -index 0000000000..975059dcdb ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-common.h -@@ -0,0 +1,99 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * mt8901-afe-common.h -- MediaTek 8901 audio driver definitions -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+#ifndef _MT_8901_AFE_COMMON_H_ -+#define _MT_8901_AFE_COMMON_H_ -+ -+#include -+#include -+#include -+#include "../common/mtk-base-afe.h" -+ -+enum { -+ MT8901_DAI_START, -+ MT8901_AFE_MEMIF_START = MT8901_DAI_START, -+ MT8901_AFE_MEMIF_DL0 = MT8901_AFE_MEMIF_START, -+ MT8901_AFE_MEMIF_DL1, -+ MT8901_AFE_MEMIF_DL2, -+ MT8901_AFE_MEMIF_DL3, -+ MT8901_AFE_MEMIF_DL4, -+ MT8901_AFE_MEMIF_DL5, -+ MT8901_AFE_MEMIF_DL_24CH_0, -+ MT8901_AFE_MEMIF_UL_START, -+ MT8901_AFE_MEMIF_UL0 = MT8901_AFE_MEMIF_UL_START, -+ MT8901_AFE_MEMIF_UL1, -+ MT8901_AFE_MEMIF_UL2, -+ MT8901_AFE_MEMIF_UL3, -+ MT8901_AFE_MEMIF_UL4, -+ MT8901_AFE_MEMIF_UL5, -+ MT8901_AFE_MEMIF_VUL_CM0, -+ MT8901_AFE_MEMIF_VUL_CM1, -+ MT8901_AFE_MEMIF_VUL_CM2, -+ MT8901_AFE_MEMIF_END, -+ MT8901_AFE_MEMIF_NUM = (MT8901_AFE_MEMIF_END - MT8901_AFE_MEMIF_START), -+ MT8901_DAI_END = MT8901_AFE_MEMIF_END, -+ MT8901_DAI_NUM = (MT8901_DAI_END - MT8901_DAI_START), -+}; -+ -+enum { -+ MT8901_AFE_IRQ_0 = 0, -+ MT8901_AFE_IRQ_1, -+ MT8901_AFE_IRQ_2, -+ MT8901_AFE_IRQ_3, -+ MT8901_AFE_IRQ_4, -+ MT8901_AFE_IRQ_5, -+ MT8901_AFE_IRQ_6, -+ MT8901_AFE_IRQ_7, -+ MT8901_AFE_IRQ_8, -+ MT8901_AFE_IRQ_9, -+ MT8901_AFE_IRQ_10, -+ MT8901_AFE_IRQ_11, -+ MT8901_AFE_IRQ_12, -+ MT8901_AFE_IRQ_13, -+ MT8901_AFE_IRQ_14, -+ MT8901_AFE_IRQ_15, -+ MT8901_AFE_IRQ_16, -+ MT8901_AFE_IRQ_17, -+ MT8901_AFE_IRQ_18, -+ MT8901_AFE_IRQ_19, -+ MT8901_AFE_IRQ_20, -+ MT8901_AFE_IRQ_21, -+ MT8901_AFE_IRQ_NUM, -+}; -+ -+enum { -+ MT8901_DOMAIN_HOPPING = 0, -+ MT8901_DOMAIN_APLL, -+}; -+ -+struct mtk_dai_memif_irq_priv { -+ unsigned int asys_timing_sel; -+}; -+ -+struct mt8901_afe_private { -+ u32 hw_ver; /* acpi-asd-hw-ver from _DSD */ -+ struct mtk_dai_memif_irq_priv irq_priv[MT8901_AFE_IRQ_NUM]; -+ -+ /* dai */ -+ void *dai_priv[MT8901_DAI_NUM]; -+}; -+ -+int mt8901_afe_fs_timing(struct device *dev, unsigned int rate); -+/* dai register */ -+int mt8901_dai_soundwire_register(struct mtk_base_afe *afe); -+ -+#define MT8901_SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put, id) \ -+{ \ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ -+ .info = snd_soc_info_enum_double, \ -+ .get = xhandler_get, .put = xhandler_put, \ -+ .device = id, \ -+ .private_value = (unsigned long)&(xenum), \ -+} -+ -+#endif -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -new file mode 100644 -index 0000000000..72d4c34c1a ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -@@ -0,0 +1,1976 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek ALSA SoC AFE platform driver for 8901 -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "mt8901-afe-common.h" -+#include "mt8901-afe-clk.h" -+#include "mt8901-reg.h" -+#include "../common/mtk-afe-platform-driver.h" -+#include "../common/mtk-afe-fe-dai.h" -+ -+#define MICROSECONDS_PER_SECOND (1000000UL) -+#define STEREO_CH 2 -+#define CLK_RATE_26M 26000000 -+#define CM_UPDATE_CNT_OFFSET 10 -+ -+/* hardware constants */ -+#define MT8901_DMA_ADDR_BITS 33 //ToDo: check 40bits -+#define MT8901_MEMIF_MINLEN 64 -+#define MT8901_MEMIF_MAXLEN 64 -+#define MT8901_CM0_MAX_CH 8 -+#define MT8901_CM1_MAX_CH 16 -+/* CM2 exposes 16 wired inputs (O064-O079 <- I170-I185), not the HW max 32 */ -+#define MT8901_CM2_MAX_CH 16 -+#define MT8901_MEMIF_BUFFER_BYTES_ALIGN (0x10) -+ -+/* experience values */ -+#define IO_INTF_DELAY_IN_SAMPLES 3 -+#define SERIAL_TO_PARALLEL_DELAY_IN_SAMPLES 1 -+#define CHANNEL_MERGE_DELAY_IN_SAMPLES 1 -+#define INTERCONN_DELAY_IN_SAMPLES 1 -+ -+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ -+ SNDRV_PCM_RATE_88200 |\ -+ SNDRV_PCM_RATE_96000 |\ -+ SNDRV_PCM_RATE_176400 |\ -+ SNDRV_PCM_RATE_192000 |\ -+ SNDRV_PCM_RATE_352800 |\ -+ SNDRV_PCM_RATE_384000) -+ -+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ -+ SNDRV_PCM_FMTBIT_S24_LE |\ -+ SNDRV_PCM_FMTBIT_S32_LE) -+ -+struct mtk_dai_memif_priv { -+ unsigned int fs_timing; -+ unsigned int domain; -+ unsigned int minlen; -+ unsigned int maxlen; -+}; -+ -+static const struct snd_pcm_hardware mt8901_afe_hardware = { -+ .info = SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_MMAP_VALID | -+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE, -+ .period_bytes_min = 64, -+ .period_bytes_max = 256 * 1024, -+ .periods_min = 2, -+ .periods_max = 256, -+ .buffer_bytes_max = 256 * 2 * 1024, -+}; -+ -+struct mt8901_afe_rate { -+ unsigned int rate; -+ unsigned int reg_value; -+}; -+ -+static const struct mt8901_afe_rate mt8901_afe_rates[] = { -+ { .rate = 8000, .reg_value = 0, }, -+ { .rate = 11025, .reg_value = 1, }, -+ { .rate = 12000, .reg_value = 2, }, -+ { .rate = 16000, .reg_value = 4, }, -+ { .rate = 22050, .reg_value = 5, }, -+ { .rate = 24000, .reg_value = 6, }, -+ { .rate = 32000, .reg_value = 8, }, -+ { .rate = 44100, .reg_value = 9, }, -+ { .rate = 48000, .reg_value = 10, }, -+ { .rate = 88200, .reg_value = 13, }, -+ { .rate = 96000, .reg_value = 14, }, -+ { .rate = 176400, .reg_value = 17, }, -+ { .rate = 192000, .reg_value = 18, }, -+ { .rate = 352800, .reg_value = 21, }, -+ { .rate = 384000, .reg_value = 22, }, -+}; -+ -+int mt8901_afe_fs_timing(struct device *dev, unsigned int rate) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_afe_rates); i++) -+ if (mt8901_afe_rates[i].rate == rate) -+ return mt8901_afe_rates[i].reg_value; -+ -+ dev_err(dev, "rate %u invalid!!!\n", rate); -+ -+ return -EINVAL; -+} -+ -+static int mt8901_memif_fs(struct snd_pcm_substream *substream, -+ unsigned int rate) -+{ -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct snd_soc_component *component = NULL; -+ struct mtk_base_afe *afe = NULL; -+ -+ component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); -+ if (!component) -+ return -EINVAL; -+ -+ afe = snd_soc_component_get_drvdata(component); -+ if (!afe) -+ return -EINVAL; -+ -+ return mt8901_afe_fs_timing(afe->dev, rate); -+} -+ -+static int mt8901_irq_fs(struct snd_pcm_substream *substream, -+ unsigned int rate) -+{ -+ return mt8901_memif_fs(substream, rate); -+} -+ -+enum { -+ MT8901_AFE_CM0, -+ MT8901_AFE_CM1, -+ MT8901_AFE_CM2, -+ MT8901_AFE_CM_NUM, -+}; -+ -+struct mt8901_afe_channel_merge { -+ int id; -+ int reg; -+ unsigned int sel_shift; -+ unsigned int sel_maskbit; -+ unsigned int sel_default; -+ unsigned int ch_num_shift; -+ unsigned int ch_num_maskbit; -+ unsigned int en_shift; -+ unsigned int en_maskbit; -+ unsigned int update_cnt_shift; -+ unsigned int update_cnt_maskbit; -+ unsigned int update_cnt_default; -+ unsigned int domain_shift; -+ unsigned int domain_maskbit; -+ unsigned int fs_shift; -+ unsigned int fs_maskbit; -+ unsigned int output_mux_shift; -+ unsigned int output_mux_maskbit; -+}; -+ -+static const struct mt8901_afe_channel_merge -+ mt8901_afe_cm[MT8901_AFE_CM_NUM] = { -+ [MT8901_AFE_CM0] = { -+ .id = MT8901_AFE_CM0, -+ .reg = AFE_CM0_CON0, -+ .sel_shift = 31, -+ .sel_maskbit = 0x1, -+ .sel_default = 0, -+ .ch_num_shift = 2, -+ .ch_num_maskbit = 0x1f, -+ .en_shift = 0, -+ .en_maskbit = 0x1, -+ .update_cnt_shift = 16, -+ .update_cnt_maskbit = 0x7fff, -+ .update_cnt_default = 0x6, -+ .domain_shift = 13, -+ .domain_maskbit = 0x7, -+ .fs_shift = 8, -+ .fs_maskbit = 0x1f, -+ .output_mux_shift = 7, -+ .output_mux_maskbit = 0x1, -+ }, -+ [MT8901_AFE_CM1] = { -+ .id = MT8901_AFE_CM1, -+ .reg = AFE_CM1_CON0, -+ .sel_shift = 31, -+ .sel_maskbit = 0x1, -+ .sel_default = 0, -+ .ch_num_shift = 2, -+ .ch_num_maskbit = 0x1f, -+ .en_shift = 0, -+ .en_maskbit = 0x1, -+ .update_cnt_shift = 16, -+ .update_cnt_maskbit = 0x7fff, -+ .update_cnt_default = 0x6, -+ .domain_shift = 13, -+ .domain_maskbit = 0x7, -+ .fs_shift = 8, -+ .fs_maskbit = 0x1f, -+ .output_mux_shift = 7, -+ .output_mux_maskbit = 0x1, -+ }, -+ [MT8901_AFE_CM2] = { -+ .id = MT8901_AFE_CM2, -+ .reg = AFE_CM2_CON0, -+ .sel_shift = 31, -+ .sel_maskbit = 0x1, -+ .sel_default = 0, -+ .ch_num_shift = 2, -+ .ch_num_maskbit = 0x1f, -+ .en_shift = 0, -+ .en_maskbit = 0x1, -+ .update_cnt_shift = 16, -+ .update_cnt_maskbit = 0x7fff, -+ .update_cnt_default = 0x6, -+ .domain_shift = 13, -+ .domain_maskbit = 0x7, -+ .fs_shift = 8, -+ .fs_maskbit = 0x1f, -+ .output_mux_shift = 7, -+ .output_mux_maskbit = 0x1, -+ }, -+}; -+ -+static int mt8901_afe_memif_is_ul(int id) -+{ -+ if (id >= MT8901_AFE_MEMIF_UL_START && id < MT8901_AFE_MEMIF_END) -+ return 1; -+ else -+ return 0; -+} -+ -+static const struct mt8901_afe_channel_merge * -+ mt8901_afe_found_cm(struct snd_soc_dai *dai) -+{ -+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); -+ int id = -EINVAL; -+ -+ if (mt8901_afe_memif_is_ul(dai->id) == 0) -+ return NULL; -+ -+ switch (dai->id) { -+ case MT8901_AFE_MEMIF_VUL_CM0: -+ id = MT8901_AFE_CM0; -+ break; -+ case MT8901_AFE_MEMIF_VUL_CM1: -+ id = MT8901_AFE_CM1; -+ break; -+ case MT8901_AFE_MEMIF_VUL_CM2: -+ id = MT8901_AFE_CM2; -+ break; -+ default: -+ break; -+ } -+ -+ if (id < 0) { -+ dev_dbg(afe->dev, "%s, memif %d cannot find CM!\n", -+ __func__, dai->id); -+ return NULL; -+ } -+ -+ return &mt8901_afe_cm[id]; -+} -+ -+static unsigned int mt8901_afe_cm_derive_update_cnt(unsigned int rate, -+ unsigned int channels) -+{ -+ unsigned int cnt; -+ -+ if (!rate || !channels) -+ return 0; -+ -+ /* ((26M/fs) - 10) / ceil(ch/2) - 1 */ -+ cnt = CLK_RATE_26M / rate; -+ if (cnt <= CM_UPDATE_CNT_OFFSET) -+ return 0; -+ -+ cnt = (cnt - CM_UPDATE_CNT_OFFSET) / ((channels + 1) / 2); -+ if (cnt <= 1) -+ return 0; -+ -+ return cnt - 1; -+} -+ -+static int mt8901_afe_config_cm(struct mtk_base_afe *afe, -+ const struct mt8901_afe_channel_merge *cm, -+ unsigned int channels, unsigned int rate, -+ unsigned int domain) -+{ -+ unsigned int update_cnt; -+ int fs_index; -+ -+ if (!cm) -+ return -EINVAL; -+ -+ fs_index = mt8901_afe_fs_timing(afe->dev, rate); -+ if (fs_index < 0) -+ return fs_index; -+ -+ regmap_update_bits(afe->regmap, -+ cm->reg, -+ cm->sel_maskbit << cm->sel_shift, -+ cm->sel_default << cm->sel_shift); -+ -+ regmap_update_bits(afe->regmap, -+ cm->reg, -+ cm->ch_num_maskbit << cm->ch_num_shift, -+ (channels - 1) << cm->ch_num_shift); -+ -+ update_cnt = mt8901_afe_cm_derive_update_cnt(rate, channels); -+ regmap_update_bits(afe->regmap, -+ cm->reg, -+ cm->update_cnt_maskbit << cm->update_cnt_shift, -+ update_cnt << cm->update_cnt_shift); -+ -+ regmap_update_bits(afe->regmap, -+ cm->reg, -+ cm->domain_maskbit << cm->domain_shift, -+ domain << cm->domain_shift); -+ -+ regmap_update_bits(afe->regmap, -+ cm->reg, -+ cm->fs_maskbit << cm->fs_shift, -+ (unsigned int)fs_index << cm->fs_shift); -+ -+ return 0; -+} -+ -+static int mt8901_afe_enable_cm(struct mtk_base_afe *afe, -+ const struct mt8901_afe_channel_merge *cm, -+ bool enable) -+{ -+ if (!cm) -+ return -EINVAL; -+ -+ regmap_update_bits(afe->regmap, -+ cm->reg, -+ cm->en_maskbit << cm->en_shift, -+ enable << cm->en_shift); -+ -+ return 0; -+} -+ -+struct mt8901_afe_memif_minlen { -+ unsigned int len; -+ unsigned int reg_value; -+}; -+ -+static const struct mt8901_afe_memif_minlen mt8901_memif_minlen[] = { -+ { .len = 0, .reg_value = 0, }, -+ { .len = 16, .reg_value = 1, }, -+ { .len = 32, .reg_value = 2, }, -+ { .len = 64, .reg_value = 3, }, -+}; -+ -+static int mt8901_memif_set_minlen(struct mtk_base_afe *afe, -+ int id, unsigned int len) -+{ -+ int i, value = 0; -+ struct mtk_base_afe_memif *memif = &afe->memif[id]; -+ const struct mtk_base_memif_data *data = memif->data; -+ -+ if (data->minlen_reg < 0) -+ return 0; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_memif_minlen); i++) -+ if (mt8901_memif_minlen[i].len == len) -+ value = mt8901_memif_minlen[i].reg_value; -+ -+ regmap_update_bits(afe->regmap, data->minlen_reg, -+ data->minlen_mask << data->minlen_shift, -+ value << data->minlen_shift); -+ return 0; -+} -+ -+struct mt8901_afe_memif_maxlen { -+ unsigned int len; -+ unsigned int reg_value; -+}; -+ -+static const struct mt8901_afe_memif_maxlen mt8901_memif_maxlen[] = { -+ { .len = 4, .reg_value = 0, }, -+ { .len = 16, .reg_value = 1, }, -+ { .len = 32, .reg_value = 2, }, -+ { .len = 64, .reg_value = 3, }, -+}; -+ -+static int mt8901_memif_set_maxlen(struct mtk_base_afe *afe, -+ int id, unsigned int len) -+{ -+ int i, value = 0; -+ struct mtk_base_afe_memif *memif = &afe->memif[id]; -+ const struct mtk_base_memif_data *data = memif->data; -+ -+ if (data->maxlen_reg < 0) -+ return 0; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_memif_maxlen); i++) -+ if (mt8901_memif_maxlen[i].len == len) -+ value = mt8901_memif_maxlen[i].reg_value; -+ -+ regmap_update_bits(afe->regmap, data->maxlen_reg, -+ data->maxlen_mask << data->maxlen_shift, -+ value << data->maxlen_shift); -+ -+ return 0; -+} -+ -+static int mt8901_memif_set_domain(struct mtk_base_afe *afe, -+ int id, unsigned int domain) -+{ -+ struct mtk_base_afe_memif *memif = &afe->memif[id]; -+ const struct mtk_base_memif_data *data = memif->data; -+ -+ if (data->domain_reg >= 0) -+ regmap_update_bits(afe->regmap, data->domain_reg, -+ data->domain_mask << data->domain_shift, -+ domain << data->domain_shift); -+ -+ return 0; -+} -+ -+static void mt8901_afe_irq_clear(struct mtk_base_afe *afe, -+ const struct mtk_base_irq_data *irq_data) -+{ -+ unsigned int val = 0; -+ -+ regmap_read(afe->regmap, irq_data->irq_clr_reg, &val); -+ regmap_update_bits(afe->regmap, irq_data->irq_clr_reg, -+ BIT(irq_data->irq_clr_shift), -+ ~val & BIT(irq_data->irq_clr_shift)); -+} -+ -+static void mt8901_afe_irq_enable(struct mtk_base_afe *afe, -+ const struct mtk_base_irq_data *irq_data) -+{ -+ if (irq_data->irq_mask_reg >= 0) -+ regmap_set_bits(afe->regmap, irq_data->irq_mask_reg, -+ BIT(irq_data->irq_mask_shift)); -+ -+ if (irq_data->irq_en_reg >= 0) -+ regmap_set_bits(afe->regmap, irq_data->irq_en_reg, -+ BIT(irq_data->irq_en_shift)); -+} -+ -+static void mt8901_afe_irq_disable(struct mtk_base_afe *afe, -+ const struct mtk_base_irq_data *irq_data) -+{ -+ if (irq_data->irq_en_reg >= 0) -+ regmap_clear_bits(afe->regmap, irq_data->irq_en_reg, -+ BIT(irq_data->irq_en_shift)); -+ -+ /* clear pending IRQ */ -+ mt8901_afe_irq_clear(afe, irq_data); -+ -+ if (irq_data->irq_mask_reg >= 0) -+ regmap_clear_bits(afe->regmap, irq_data->irq_mask_reg, -+ BIT(irq_data->irq_mask_shift)); -+} -+ -+static void mt8901_afe_irq_configure(struct mtk_base_afe *afe, int id, -+ int fs, unsigned int domain, -+ unsigned int counter) -+{ -+ struct mtk_base_afe_memif *memif = &afe->memif[id]; -+ struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; -+ const struct mtk_base_irq_data *irq_data = irqs->irq_data; -+ int msk, shift; -+ -+ /* set irq counter */ -+ msk = irq_data->irq_cnt_maskbit; -+ shift = irq_data->irq_cnt_shift; -+ regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, -+ msk << shift, counter << shift); -+ -+ if (irq_data->irq_fs_reg >= 0) { -+ msk = irq_data->irq_fs_maskbit; -+ shift = irq_data->irq_fs_shift; -+ regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, -+ msk << shift, fs << shift); -+ } -+ -+ if (irq_data->irq_domain_reg >= 0) { -+ msk = irq_data->irq_domain_maskbit; -+ shift = irq_data->irq_domain_shift; -+ regmap_update_bits(afe->regmap, irq_data->irq_domain_reg, -+ msk << shift, domain << shift); -+ } -+} -+ -+static unsigned long mt8901_get_prefetch_delay(struct mtk_base_afe *afe, -+ int id, unsigned int minlen, -+ unsigned int rate, -+ unsigned int channel, -+ unsigned int bitwidth) -+{ -+ unsigned long delay_us = 0; -+ unsigned long pbuf_delay; -+ -+ if (rate == 0 || channel == 0 || bitwidth == 0) { -+ dev_warn(afe->dev, -+ "%s(), unexpected parameter rate %u, ch %u, bit %u\n", -+ __func__, rate, channel, bitwidth); -+ return 0; -+ } -+ -+ delay_us = IO_INTF_DELAY_IN_SAMPLES + -+ SERIAL_TO_PARALLEL_DELAY_IN_SAMPLES + -+ CHANNEL_MERGE_DELAY_IN_SAMPLES + -+ INTERCONN_DELAY_IN_SAMPLES; -+ -+ pbuf_delay = minlen * BITS_PER_BYTE / (channel * bitwidth); -+ delay_us += pbuf_delay; -+ delay_us = delay_us * MICROSECONDS_PER_SECOND / rate; -+ -+ return delay_us; -+} -+ -+static int mt8901_afe_fe_startup(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int ret; -+ -+ ret = mtk_afe_fe_startup(substream, dai); -+ -+ snd_pcm_hw_constraint_step(runtime, 0, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ MT8901_MEMIF_BUFFER_BYTES_ALIGN); -+ -+ return ret; -+} -+ -+static int mt8901_afe_fe_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id; -+ const struct mt8901_afe_channel_merge *cm = mt8901_afe_found_cm(dai); -+ struct mtk_dai_memif_priv *memif_priv = afe_priv->dai_priv[id]; -+ unsigned int channels = params_channels(params); -+ unsigned int rate = params_rate(params); -+ unsigned int domain = memif_priv->domain; -+ -+ mt8901_afe_config_cm(afe, cm, channels, rate, domain); -+ -+ mt8901_memif_set_domain(afe, id, domain); -+ -+ mt8901_memif_set_minlen(afe, id, memif_priv->minlen); -+ -+ mt8901_memif_set_maxlen(afe, id, memif_priv->maxlen); -+ -+ return mtk_afe_fe_hw_params(substream, params, dai); -+} -+ -+static int mt8901_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); -+ const struct mt8901_afe_channel_merge *cm = mt8901_afe_found_cm(dai); -+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); -+ struct snd_pcm_runtime * const runtime = substream->runtime; -+ int id = snd_soc_rtd_to_cpu(rtd, 0)->id; -+ struct mtk_base_afe_memif *memif = &afe->memif[id]; -+ struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; -+ const struct mtk_base_irq_data *irq_data = irqs->irq_data; -+ unsigned int counter = runtime->period_size; -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ struct mtk_dai_memif_priv *memif_priv = afe_priv->dai_priv[id]; -+ int fs; -+ int ret; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ ret = mtk_memif_set_enable(afe, id); -+ if (ret) { -+ dev_err(afe->dev, -+ "%s(), error, id %d, memif enable, ret %d\n", -+ __func__, id, ret); -+ return ret; -+ } -+ -+ mt8901_afe_enable_cm(afe, cm, true); -+ -+ /* set irq fs */ -+ fs = afe->irq_fs(substream, runtime->rate); -+ if (fs < 0) -+ return -EINVAL; -+ -+ mt8901_afe_irq_configure(afe, id, fs, memif_priv->domain, -+ counter); -+ -+ /* delay for uplink */ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { -+ unsigned long prefetch_delay = -+ mt8901_get_prefetch_delay(afe, id, -+ memif_priv->minlen, -+ runtime->rate, -+ runtime->channels, -+ runtime->sample_bits); -+ -+ udelay(prefetch_delay); -+ } -+ -+ /* enable interrupt */ -+ mt8901_afe_irq_enable(afe, irq_data); -+ return 0; -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ mt8901_afe_enable_cm(afe, cm, false); -+ -+ ret = mtk_memif_set_disable(afe, id); -+ if (ret) -+ dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n", -+ __func__, id, ret); -+ -+ /* disable interrupt */ -+ mt8901_afe_irq_disable(afe, irq_data); -+ return ret; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static const struct snd_soc_dai_ops mt8901_afe_fe_dai_ops = { -+ .startup = mt8901_afe_fe_startup, -+ .shutdown = mtk_afe_fe_shutdown, -+ .hw_params = mt8901_afe_fe_hw_params, -+ .hw_free = mtk_afe_fe_hw_free, -+ .prepare = mtk_afe_fe_prepare, -+ .trigger = mt8901_afe_fe_trigger, -+}; -+ -+static struct snd_soc_dai_driver mt8901_memif_dai_driver[] = { -+ /* FE DAIs: memory intefaces to CPU */ -+ { -+ .name = "DL0", -+ .id = MT8901_AFE_MEMIF_DL0, -+ .playback = { -+ .stream_name = "DL0", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "DL1", -+ .id = MT8901_AFE_MEMIF_DL1, -+ .playback = { -+ .stream_name = "DL1", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "DL2", -+ .id = MT8901_AFE_MEMIF_DL2, -+ .playback = { -+ .stream_name = "DL2", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "DL3", -+ .id = MT8901_AFE_MEMIF_DL3, -+ .playback = { -+ .stream_name = "DL3", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "DL4", -+ .id = MT8901_AFE_MEMIF_DL4, -+ .playback = { -+ .stream_name = "DL4", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "DL5", -+ .id = MT8901_AFE_MEMIF_DL5, -+ .playback = { -+ .stream_name = "DL5", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "DL_24CH", -+ .id = MT8901_AFE_MEMIF_DL_24CH_0, -+ .playback = { -+ .stream_name = "DL_24CH", -+ .channels_min = 1, -+ .channels_max = MT8901_CM0_MAX_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "UL0", -+ .id = MT8901_AFE_MEMIF_UL0, -+ .capture = { -+ .stream_name = "UL0", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "UL1", -+ .id = MT8901_AFE_MEMIF_UL1, -+ .capture = { -+ .stream_name = "UL1", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "UL2", -+ .id = MT8901_AFE_MEMIF_UL2, -+ .capture = { -+ .stream_name = "UL2", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "UL3", -+ .id = MT8901_AFE_MEMIF_UL3, -+ .capture = { -+ .stream_name = "UL3", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "UL4", -+ .id = MT8901_AFE_MEMIF_UL4, -+ .capture = { -+ .stream_name = "UL4", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "UL5", -+ .id = MT8901_AFE_MEMIF_UL5, -+ .capture = { -+ .stream_name = "UL5", -+ .channels_min = 1, -+ .channels_max = STEREO_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "VUL_CM0", -+ .id = MT8901_AFE_MEMIF_VUL_CM0, -+ .capture = { -+ .stream_name = "VUL_CM0", -+ .channels_min = 1, -+ .channels_max = MT8901_CM0_MAX_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "VUL_CM1", -+ .id = MT8901_AFE_MEMIF_VUL_CM1, -+ .capture = { -+ .stream_name = "VUL_CM1", -+ .channels_min = 1, -+ .channels_max = MT8901_CM1_MAX_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+ { -+ .name = "VUL_CM2", -+ .id = MT8901_AFE_MEMIF_VUL_CM2, -+ .capture = { -+ .stream_name = "VUL_CM2", -+ .channels_min = 1, -+ .channels_max = MT8901_CM2_MAX_CH, -+ .rates = MTK_PCM_RATES, -+ .formats = MTK_PCM_FORMATS, -+ }, -+ .ops = &mt8901_afe_fe_dai_ops, -+ }, -+}; -+ -+/* -+ * VUL_2CH_0: Mic 2CH -+ * first-fit: PDI8 (I170/I171); contention: PDI12 (I178/I179), -+ * PDI13 (I180/I181) -+ */ -+static const struct snd_kcontrol_new o018_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I170 Switch", AFE_CONN018_5, 10, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I178 Switch", AFE_CONN018_5, 18, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I180 Switch", AFE_CONN018_5, 20, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o019_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I171 Switch", AFE_CONN019_5, 11, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I179 Switch", AFE_CONN019_5, 19, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I181 Switch", AFE_CONN019_5, 21, 1, 0), -+}; -+ -+/* -+ * VUL_2CH_1: HeadsetMic 2CH -+ * first-fit: PDI7 (I168/I169); contention: PDI12~14 (I178~I183) -+ */ -+static const struct snd_kcontrol_new o020_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I168 Switch", AFE_CONN020_5, 8, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I178 Switch", AFE_CONN020_5, 18, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I180 Switch", AFE_CONN020_5, 20, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I182 Switch", AFE_CONN020_5, 22, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o021_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I169 Switch", AFE_CONN021_5, 9, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I179 Switch", AFE_CONN021_5, 19, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I181 Switch", AFE_CONN021_5, 21, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I183 Switch", AFE_CONN021_5, 23, 1, 0), -+}; -+ -+/* VUL_2CH_4: BRA RX SDW0 — I186/I187 exclusive non-SDCA path */ -+static const struct snd_kcontrol_new o026_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I186 Switch", AFE_CONN026_5, 26, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o027_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I187 Switch", AFE_CONN027_5, 27, 1, 0), -+}; -+ -+/* VUL_2CH_5: BRA RX SDW1 — I166/I167 exclusive non-SDCA path */ -+static const struct snd_kcontrol_new o028_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I166 Switch", AFE_CONN028_5, 6, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o029_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I167 Switch", AFE_CONN029_5, 7, 1, 0), -+}; -+ -+/* -+ * VUL_CM2: Mic >2CH, max 16CH (PDI8~PDI15, I170~I185). -+ * O064~O079 each connect to one I port (no contention fallback in CM path). -+ */ -+static const struct snd_kcontrol_new o064_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I170 Switch", AFE_CONN064_5, 10, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o065_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I171 Switch", AFE_CONN065_5, 11, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o066_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I172 Switch", AFE_CONN066_5, 12, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o067_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I173 Switch", AFE_CONN067_5, 13, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o068_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I174 Switch", AFE_CONN068_5, 14, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o069_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I175 Switch", AFE_CONN069_5, 15, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o070_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I176 Switch", AFE_CONN070_5, 16, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o071_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I177 Switch", AFE_CONN071_5, 17, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o072_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I178 Switch", AFE_CONN072_5, 18, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o073_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I179 Switch", AFE_CONN073_5, 19, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o074_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I180 Switch", AFE_CONN074_5, 20, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o075_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I181 Switch", AFE_CONN075_5, 21, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o076_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I182 Switch", AFE_CONN076_5, 22, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o077_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I183 Switch", AFE_CONN077_5, 23, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o078_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I184 Switch", AFE_CONN078_5, 24, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new o079_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I185 Switch", AFE_CONN079_5, 25, 1, 0), -+}; -+ -+static const char * const mt8901_afe_domain_sel_text[] = { -+ "hopping", "apll", -+}; -+ -+static const unsigned int mt8901_afe_domain_sel_values[] = { -+ MT8901_DOMAIN_HOPPING, MT8901_DOMAIN_APLL, -+}; -+ -+static int mt8901_memif_domain_sel_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ unsigned int dai_id = kcontrol->id.device; -+ struct mtk_dai_memif_priv *priv = afe_priv->dai_priv[dai_id]; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_afe_domain_sel_values); i++) { -+ if (mt8901_afe_domain_sel_values[i] == priv->domain) { -+ ucontrol->value.enumerated.item[0] = i; -+ return 0; -+ } -+ } -+ return -EINVAL; -+} -+ -+static int mt8901_memif_domain_sel_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); -+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ unsigned int dai_id = kcontrol->id.device; -+ struct mtk_dai_memif_priv *priv = afe_priv->dai_priv[dai_id]; -+ unsigned long idx = ucontrol->value.enumerated.item[0]; -+ unsigned int reg_val; -+ -+ if (idx >= ARRAY_SIZE(mt8901_afe_domain_sel_values)) -+ return -EINVAL; -+ reg_val = mt8901_afe_domain_sel_values[idx]; -+ if (reg_val == priv->domain) -+ return 0; -+ priv->domain = reg_val; -+ return 1; -+} -+ -+static SOC_ENUM_SINGLE_EXT_DECL(mt8901_domain_sel_enum, -+ mt8901_afe_domain_sel_text); -+ -+static const struct snd_kcontrol_new mt8901_memif_controls[] = { -+ MT8901_SOC_ENUM_EXT("DL0_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_DL0), -+ MT8901_SOC_ENUM_EXT("DL1_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_DL1), -+ MT8901_SOC_ENUM_EXT("DL2_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_DL2), -+ MT8901_SOC_ENUM_EXT("DL3_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_DL3), -+ MT8901_SOC_ENUM_EXT("DL4_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_DL4), -+ MT8901_SOC_ENUM_EXT("DL5_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_DL5), -+ MT8901_SOC_ENUM_EXT("DL_24CH_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_DL_24CH_0), -+ MT8901_SOC_ENUM_EXT("UL0_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_UL0), -+ MT8901_SOC_ENUM_EXT("UL1_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_UL1), -+ MT8901_SOC_ENUM_EXT("UL2_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_UL2), -+ MT8901_SOC_ENUM_EXT("UL3_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_UL3), -+ MT8901_SOC_ENUM_EXT("UL4_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_UL4), -+ MT8901_SOC_ENUM_EXT("UL5_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_UL5), -+ MT8901_SOC_ENUM_EXT("VUL_CM0_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_VUL_CM0), -+ MT8901_SOC_ENUM_EXT("VUL_CM1_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_VUL_CM1), -+ MT8901_SOC_ENUM_EXT("VUL_CM2_Domain_Sel", mt8901_domain_sel_enum, -+ mt8901_memif_domain_sel_get, -+ mt8901_memif_domain_sel_put, -+ MT8901_AFE_MEMIF_VUL_CM2), -+}; -+ -+static const struct snd_soc_dapm_widget mt8901_memif_widgets[] = { -+ /* DL0 */ -+ SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* DL1 */ -+ SND_SOC_DAPM_MIXER("I034", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I035", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* DL4 */ -+ SND_SOC_DAPM_MIXER("I040", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I041", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* DL5 */ -+ SND_SOC_DAPM_MIXER("I042", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I043", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* DL_24CH */ -+ SND_SOC_DAPM_MIXER("I054", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I055", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I056", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I057", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I058", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I059", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I060", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I061", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* UL0 */ -+ SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0, -+ o018_mix, ARRAY_SIZE(o018_mix)), -+ SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0, -+ o019_mix, ARRAY_SIZE(o019_mix)), -+ -+ /* UL1 */ -+ SND_SOC_DAPM_MIXER("O020", SND_SOC_NOPM, 0, 0, -+ o020_mix, ARRAY_SIZE(o020_mix)), -+ SND_SOC_DAPM_MIXER("O021", SND_SOC_NOPM, 0, 0, -+ o021_mix, ARRAY_SIZE(o021_mix)), -+ -+ /* UL4 */ -+ SND_SOC_DAPM_MIXER("O026", SND_SOC_NOPM, 0, 0, -+ o026_mix, ARRAY_SIZE(o026_mix)), -+ SND_SOC_DAPM_MIXER("O027", SND_SOC_NOPM, 0, 0, -+ o027_mix, ARRAY_SIZE(o027_mix)), -+ -+ /* UL5 */ -+ SND_SOC_DAPM_MIXER("O028", SND_SOC_NOPM, 0, 0, -+ o028_mix, ARRAY_SIZE(o028_mix)), -+ SND_SOC_DAPM_MIXER("O029", SND_SOC_NOPM, 0, 0, -+ o029_mix, ARRAY_SIZE(o029_mix)), -+ -+ /* VUL_CM2: O64~O79 (SCD0 UL pool PDI8~PDI15, max 16ch) */ -+ SND_SOC_DAPM_MIXER("O064", SND_SOC_NOPM, 0, 0, -+ o064_mix, ARRAY_SIZE(o064_mix)), -+ SND_SOC_DAPM_MIXER("O065", SND_SOC_NOPM, 0, 0, -+ o065_mix, ARRAY_SIZE(o065_mix)), -+ SND_SOC_DAPM_MIXER("O066", SND_SOC_NOPM, 0, 0, -+ o066_mix, ARRAY_SIZE(o066_mix)), -+ SND_SOC_DAPM_MIXER("O067", SND_SOC_NOPM, 0, 0, -+ o067_mix, ARRAY_SIZE(o067_mix)), -+ SND_SOC_DAPM_MIXER("O068", SND_SOC_NOPM, 0, 0, -+ o068_mix, ARRAY_SIZE(o068_mix)), -+ SND_SOC_DAPM_MIXER("O069", SND_SOC_NOPM, 0, 0, -+ o069_mix, ARRAY_SIZE(o069_mix)), -+ SND_SOC_DAPM_MIXER("O070", SND_SOC_NOPM, 0, 0, -+ o070_mix, ARRAY_SIZE(o070_mix)), -+ SND_SOC_DAPM_MIXER("O071", SND_SOC_NOPM, 0, 0, -+ o071_mix, ARRAY_SIZE(o071_mix)), -+ SND_SOC_DAPM_MIXER("O072", SND_SOC_NOPM, 0, 0, -+ o072_mix, ARRAY_SIZE(o072_mix)), -+ SND_SOC_DAPM_MIXER("O073", SND_SOC_NOPM, 0, 0, -+ o073_mix, ARRAY_SIZE(o073_mix)), -+ SND_SOC_DAPM_MIXER("O074", SND_SOC_NOPM, 0, 0, -+ o074_mix, ARRAY_SIZE(o074_mix)), -+ SND_SOC_DAPM_MIXER("O075", SND_SOC_NOPM, 0, 0, -+ o075_mix, ARRAY_SIZE(o075_mix)), -+ SND_SOC_DAPM_MIXER("O076", SND_SOC_NOPM, 0, 0, -+ o076_mix, ARRAY_SIZE(o076_mix)), -+ SND_SOC_DAPM_MIXER("O077", SND_SOC_NOPM, 0, 0, -+ o077_mix, ARRAY_SIZE(o077_mix)), -+ SND_SOC_DAPM_MIXER("O078", SND_SOC_NOPM, 0, 0, -+ o078_mix, ARRAY_SIZE(o078_mix)), -+ SND_SOC_DAPM_MIXER("O079", SND_SOC_NOPM, 0, 0, -+ o079_mix, ARRAY_SIZE(o079_mix)), -+}; -+ -+static const struct snd_soc_dapm_route mt8901_memif_routes[] = { -+ {"I032", NULL, "DL0"}, -+ {"I033", NULL, "DL0"}, -+ -+ {"I034", NULL, "DL1"}, -+ {"I035", NULL, "DL1"}, -+ -+ {"I040", NULL, "DL4"}, -+ {"I041", NULL, "DL4"}, -+ -+ {"I042", NULL, "DL5"}, -+ {"I043", NULL, "DL5"}, -+ -+ {"I054", NULL, "DL_24CH"}, -+ {"I055", NULL, "DL_24CH"}, -+ {"I056", NULL, "DL_24CH"}, -+ {"I057", NULL, "DL_24CH"}, -+ {"I058", NULL, "DL_24CH"}, -+ {"I059", NULL, "DL_24CH"}, -+ {"I060", NULL, "DL_24CH"}, -+ {"I061", NULL, "DL_24CH"}, -+ -+ {"UL0", NULL, "O018"}, -+ {"UL0", NULL, "O019"}, -+ -+ {"UL1", NULL, "O020"}, -+ {"UL1", NULL, "O021"}, -+ -+ {"UL4", NULL, "O026"}, -+ {"UL4", NULL, "O027"}, -+ -+ {"UL5", NULL, "O028"}, -+ {"UL5", NULL, "O029"}, -+ -+ {"VUL_CM2", NULL, "O064"}, -+ {"VUL_CM2", NULL, "O065"}, -+ {"VUL_CM2", NULL, "O066"}, -+ {"VUL_CM2", NULL, "O067"}, -+ {"VUL_CM2", NULL, "O068"}, -+ {"VUL_CM2", NULL, "O069"}, -+ {"VUL_CM2", NULL, "O070"}, -+ {"VUL_CM2", NULL, "O071"}, -+ {"VUL_CM2", NULL, "O072"}, -+ {"VUL_CM2", NULL, "O073"}, -+ {"VUL_CM2", NULL, "O074"}, -+ {"VUL_CM2", NULL, "O075"}, -+ {"VUL_CM2", NULL, "O076"}, -+ {"VUL_CM2", NULL, "O077"}, -+ {"VUL_CM2", NULL, "O078"}, -+ {"VUL_CM2", NULL, "O079"}, -+ -+ /* UL5: BRA RX SDW1 — I166/I167 exclusive */ -+ {"O028", "I166 Switch", "I166"}, -+ {"O029", "I167 Switch", "I167"}, -+ -+ /* UL1: HeadsetMic 2CH — I168/I169 first-fit (PDI7), -+ * I178~I183 contention (PDI12~14) -+ */ -+ {"O020", "I168 Switch", "I168"}, -+ {"O020", "I178 Switch", "I178"}, -+ {"O020", "I180 Switch", "I180"}, -+ {"O020", "I182 Switch", "I182"}, -+ {"O021", "I169 Switch", "I169"}, -+ {"O021", "I179 Switch", "I179"}, -+ {"O021", "I181 Switch", "I181"}, -+ {"O021", "I183 Switch", "I183"}, -+ -+ /* UL0: Mic 2CH — I170/I171 first-fit (PDI8), -+ * I178~I181 contention (PDI12/13) -+ */ -+ {"O018", "I170 Switch", "I170"}, -+ {"O018", "I178 Switch", "I178"}, -+ {"O018", "I180 Switch", "I180"}, -+ {"O019", "I171 Switch", "I171"}, -+ {"O019", "I179 Switch", "I179"}, -+ {"O019", "I181 Switch", "I181"}, -+ -+ /* VUL_CM2: Mic >2CH — I170~I185 (PDI8~PDI15, max 16CH) */ -+ {"O064", "I170 Switch", "I170"}, -+ {"O065", "I171 Switch", "I171"}, -+ {"O066", "I172 Switch", "I172"}, -+ {"O067", "I173 Switch", "I173"}, -+ {"O068", "I174 Switch", "I174"}, -+ {"O069", "I175 Switch", "I175"}, -+ {"O070", "I176 Switch", "I176"}, -+ {"O071", "I177 Switch", "I177"}, -+ {"O072", "I178 Switch", "I178"}, -+ {"O073", "I179 Switch", "I179"}, -+ {"O074", "I180 Switch", "I180"}, -+ {"O075", "I181 Switch", "I181"}, -+ {"O076", "I182 Switch", "I182"}, -+ {"O077", "I183 Switch", "I183"}, -+ {"O078", "I184 Switch", "I184"}, -+ {"O079", "I185 Switch", "I185"}, -+ -+ /* UL4: BRA RX SDW0 — I186/I187 exclusive */ -+ {"O026", "I186 Switch", "I186"}, -+ {"O027", "I187 Switch", "I187"}, -+}; -+ -+#define MT8901_MEMIF_DL(n) \ -+[MT8901_AFE_MEMIF_DL##n] = { \ -+ .name = "DL" #n, \ -+ .id = MT8901_AFE_MEMIF_DL##n, \ -+ .reg_ofs_base = AFE_DL##n##_BASE, \ -+ .reg_ofs_cur = AFE_DL##n##_CUR, \ -+ .reg_ofs_end = AFE_DL##n##_END, \ -+ .reg_ofs_base_msb = AFE_DL##n##_BASE_MSB, \ -+ .reg_ofs_cur_msb = AFE_DL##n##_CUR_MSB, \ -+ .reg_ofs_end_msb = AFE_DL##n##_END_MSB, \ -+ .fs_reg = AFE_DL##n##_CON0, \ -+ .fs_shift = DL_SEL_FS_SFT, \ -+ .fs_maskbit = DL_SEL_FS_MASK, \ -+ .mono_reg = AFE_DL##n##_CON0, \ -+ .mono_shift = DL_MONO_SFT, \ -+ .enable_reg = AFE_DL##n##_CON0, \ -+ .enable_shift = DL_ON_SFT, \ -+ .hd_reg = AFE_DL##n##_CON0, \ -+ .hd_shift = DL_HD_MODE_SFT, \ -+ .hd_align_reg = AFE_DL##n##_CON0, \ -+ .hd_align_mshift = 2, \ -+ .pbuf_reg = AFE_DL##n##_CON0, \ -+ .pbuf_shift = DL_PBUF_SIZE_SFT, \ -+ .pbuf_mask = GENMASK(1, 0), \ -+ .minlen_reg = AFE_DL##n##_CON0, \ -+ .minlen_shift = DL_MINLEN_SFT, \ -+ .minlen_mask = GENMASK(1, 0), \ -+ .ch_num_reg = -1, \ -+ .ch_num_shift = 0, \ -+ .ch_num_maskbit = 0, \ -+ .maxlen_reg = AFE_DL##n##_CON0, \ -+ .maxlen_shift = DL_MAXLEN_SFT, \ -+ .maxlen_mask = GENMASK(1, 0), \ -+ .domain_reg = AFE_DL##n##_CON0, \ -+ .domain_shift = DL_SEL_DOMAIN_SFT, \ -+ .domain_mask = DL_SEL_DOMAIN_MASK, \ -+ .one_heart_mode_sel_reg = AFE_DL##n##_CON0, \ -+ .one_heart_mode_shift = DL_ONE_HEART_SEL_SFT, \ -+ .one_heart_mode_mask_shift = DL_ONE_HEART_SEL_MASK_SFT, \ -+} -+ -+/* MT8901_MEMIF_UL(n) is the same idea for ULn (n = 0..5). */ -+#define MT8901_MEMIF_UL(n) \ -+[MT8901_AFE_MEMIF_UL##n] = { \ -+ .name = "UL" #n, \ -+ .id = MT8901_AFE_MEMIF_UL##n, \ -+ .reg_ofs_base = AFE_VUL##n##_BASE, \ -+ .reg_ofs_cur = AFE_VUL##n##_CUR, \ -+ .reg_ofs_end = AFE_VUL##n##_END, \ -+ .reg_ofs_base_msb = AFE_VUL##n##_BASE_MSB, \ -+ .reg_ofs_cur_msb = AFE_VUL##n##_CUR_MSB, \ -+ .reg_ofs_end_msb = AFE_VUL##n##_END_MSB, \ -+ .fs_reg = AFE_VUL##n##_CON0, \ -+ .fs_shift = VUL_SEL_FS_SFT, \ -+ .fs_maskbit = VUL_SEL_FS_MASK, \ -+ .mono_reg = AFE_VUL##n##_CON0, \ -+ .mono_shift = VUL_MONO_SFT, \ -+ .enable_reg = AFE_VUL##n##_CON0, \ -+ .enable_shift = VUL_ON_SFT, \ -+ .hd_reg = AFE_VUL##n##_CON0, \ -+ .hd_shift = VUL_HD_MODE_SFT, \ -+ .hd_align_reg = AFE_VUL##n##_CON0, \ -+ .hd_align_mshift = VUL_HALIGN_SFT, \ -+ .minlen_reg = AFE_VUL##n##_CON0, \ -+ .minlen_shift = UL_MINLEN_SFT, \ -+ .minlen_mask = GENMASK(1, 0), \ -+ .ch_num_reg = -1, \ -+ .ch_num_shift = 0, \ -+ .ch_num_maskbit = 0, \ -+ .maxlen_reg = AFE_VUL##n##_CON0, \ -+ .maxlen_shift = UL_MAXLEN_SFT, \ -+ .maxlen_mask = GENMASK(1, 0), \ -+ .domain_reg = AFE_VUL##n##_CON0, \ -+ .domain_shift = VUL_SEL_DOMAIN_SFT, \ -+ .domain_mask = VUL_SEL_DOMAIN_MASK, \ -+} -+ -+#define MT8901_MEMIF_VUL_CM(n) \ -+[MT8901_AFE_MEMIF_VUL_CM##n] = { \ -+ .name = "VUL_CM" #n, \ -+ .id = MT8901_AFE_MEMIF_VUL_CM##n, \ -+ .reg_ofs_base = AFE_VUL_CM##n##_BASE, \ -+ .reg_ofs_cur = AFE_VUL_CM##n##_CUR, \ -+ .reg_ofs_end = AFE_VUL_CM##n##_END, \ -+ .reg_ofs_base_msb = AFE_VUL_CM##n##_BASE_MSB, \ -+ .reg_ofs_cur_msb = AFE_VUL_CM##n##_CUR_MSB, \ -+ .reg_ofs_end_msb = AFE_VUL_CM##n##_END_MSB, \ -+ .fs_reg = -1, \ -+ .fs_shift = 0, \ -+ .fs_maskbit = 0, \ -+ .mono_reg = -1, \ -+ .mono_shift = 0, \ -+ .int_odd_flag_reg = AFE_VUL_CM##n##_CON0, \ -+ .int_odd_flag_shift = 0, \ -+ .enable_reg = AFE_VUL_CM##n##_CON0, \ -+ .enable_shift = 28, \ -+ .hd_reg = AFE_VUL_CM##n##_CON0, \ -+ .hd_shift = 4, \ -+ .hd_align_reg = AFE_VUL_CM##n##_CON0, \ -+ .hd_align_mshift = 7, \ -+ .agent_disable_reg = -1, \ -+ .agent_disable_shift = 0, \ -+ .ch_num_reg = -1, \ -+ .ch_num_shift = 0, \ -+ .ch_num_maskbit = 0, \ -+ .msb_reg = -1, \ -+ .msb_shift = 0, \ -+ .msb_end_reg = -1, \ -+ .msb_end_shift = 0, \ -+ .minlen_reg = AFE_VUL_CM##n##_CON0, \ -+ .minlen_shift = UL_CM_MINLEN_SFT, \ -+ .minlen_mask = GENMASK(1, 0), \ -+ .maxlen_reg = AFE_VUL_CM##n##_CON0, \ -+ .maxlen_shift = UL_CM_MAXLEN_SFT, \ -+ .maxlen_mask = GENMASK(1, 0), \ -+} -+ -+static const struct mtk_base_memif_data memif_data[MT8901_AFE_MEMIF_NUM] = { -+ MT8901_MEMIF_DL(0), -+ MT8901_MEMIF_DL(1), -+ MT8901_MEMIF_DL(2), -+ MT8901_MEMIF_DL(3), -+ MT8901_MEMIF_DL(4), -+ MT8901_MEMIF_DL(5), -+ [MT8901_AFE_MEMIF_DL_24CH_0] = { -+ .name = "DL_24CH", -+ .id = MT8901_AFE_MEMIF_DL_24CH_0, -+ .reg_ofs_base = AFE_DL_24CH_BASE, -+ .reg_ofs_cur = AFE_DL_24CH_CUR, -+ .reg_ofs_end = AFE_DL_24CH_END, -+ .reg_ofs_base_msb = AFE_DL_24CH_BASE_MSB, -+ .reg_ofs_cur_msb = AFE_DL_24CH_CUR_MSB, -+ .reg_ofs_end_msb = AFE_DL_24CH_END_MSB, -+ .fs_reg = AFE_DL_24CH_CON0, -+ .fs_shift = DL_SEL_FS_SFT, -+ .fs_maskbit = DL_SEL_FS_MASK, -+ .mono_reg = -1, -+ .mono_shift = 0, -+ .enable_reg = AFE_DL_24CH_CON0, -+ .enable_shift = 31, -+ .hd_reg = AFE_DL_24CH_CON0, -+ .hd_shift = DL_HD_MODE_SFT, -+ .hd_align_reg = AFE_DL_24CH_CON0, -+ .hd_align_mshift = 2, -+ .ch_num_reg = AFE_DL_24CH_CON0, -+ .ch_num_shift = 24, -+ .ch_num_maskbit = GENMASK(5, 0), -+ .pbuf_reg = AFE_DL_24CH_CON0, -+ .pbuf_shift = DL_PBUF_SIZE_SFT, -+ .pbuf_mask = GENMASK(1, 0), -+ .minlen_reg = AFE_DL_24CH_CON0, -+ .minlen_shift = DL_MINLEN_SFT, -+ .minlen_mask = GENMASK(1, 0), -+ .maxlen_reg = AFE_DL_24CH_CON0, -+ .maxlen_shift = DL_MAXLEN_SFT, -+ .maxlen_mask = GENMASK(1, 0), -+ .domain_reg = AFE_DL_24CH_CON0, -+ .domain_shift = DL_SEL_DOMAIN_SFT, -+ .domain_mask = DL_SEL_DOMAIN_MASK, -+ .one_heart_mode_sel_reg = AFE_DL_24CH_CON0, -+ .one_heart_mode_shift = DL_ONE_HEART_SEL_SFT, -+ .one_heart_mode_mask_shift = DL_ONE_HEART_SEL_MASK_SFT, -+ }, -+ MT8901_MEMIF_UL(0), -+ MT8901_MEMIF_UL(1), -+ MT8901_MEMIF_UL(2), -+ MT8901_MEMIF_UL(3), -+ MT8901_MEMIF_UL(4), -+ MT8901_MEMIF_UL(5), -+ -+ MT8901_MEMIF_VUL_CM(0), -+ MT8901_MEMIF_VUL_CM(1), -+ MT8901_MEMIF_VUL_CM(2), -+}; -+ -+#define MT8901_AFE_IRQ(n) \ -+[MT8901_AFE_IRQ_##n] = { \ -+ .id = MT8901_AFE_IRQ_##n, \ -+ .irq_cnt_reg = AFE_IRQ##n##_MCU_CFG1, \ -+ .irq_cnt_shift = 0, \ -+ .irq_cnt_maskbit = GENMASK(23, 0), \ -+ .irq_fs_reg = AFE_IRQ##n##_MCU_CFG0, \ -+ .irq_fs_shift = 4, \ -+ .irq_fs_maskbit = GENMASK(4, 0), \ -+ .irq_en_reg = AFE_IRQ##n##_MCU_CFG0, \ -+ .irq_en_shift = 0, \ -+ .irq_clr_reg = AFE_IRQ##n##_MCU_CFG1, \ -+ .irq_clr_shift = 31, \ -+ .irq_status_shift = n, \ -+ .irq_domain_reg = AFE_IRQ##n##_MCU_CFG0, \ -+ .irq_domain_shift = 9, \ -+ .irq_domain_maskbit = 0x7, \ -+ .irq_mask_reg = AFE_IRQ_MCU_EN, \ -+ .irq_mask_shift = n, \ -+} -+ -+static const struct mtk_base_irq_data irq_data[MT8901_AFE_IRQ_NUM] = { -+ MT8901_AFE_IRQ(0), -+ MT8901_AFE_IRQ(1), -+ MT8901_AFE_IRQ(2), -+ MT8901_AFE_IRQ(3), -+ MT8901_AFE_IRQ(4), -+ MT8901_AFE_IRQ(5), -+ MT8901_AFE_IRQ(6), -+ MT8901_AFE_IRQ(7), -+ MT8901_AFE_IRQ(8), -+ MT8901_AFE_IRQ(9), -+ MT8901_AFE_IRQ(10), -+ MT8901_AFE_IRQ(11), -+ MT8901_AFE_IRQ(12), -+ MT8901_AFE_IRQ(13), -+ MT8901_AFE_IRQ(14), -+ MT8901_AFE_IRQ(15), -+ MT8901_AFE_IRQ(16), -+ MT8901_AFE_IRQ(17), -+ MT8901_AFE_IRQ(18), -+ MT8901_AFE_IRQ(19), -+ MT8901_AFE_IRQ(20), -+ MT8901_AFE_IRQ(21), -+}; -+ -+static const int mt8901_afe_memif_const_irqs[MT8901_AFE_MEMIF_NUM] = { -+ [MT8901_AFE_MEMIF_DL0] = MT8901_AFE_IRQ_0, -+ [MT8901_AFE_MEMIF_DL1] = MT8901_AFE_IRQ_1, -+ [MT8901_AFE_MEMIF_DL2] = MT8901_AFE_IRQ_2, -+ [MT8901_AFE_MEMIF_DL3] = MT8901_AFE_IRQ_3, -+ [MT8901_AFE_MEMIF_DL4] = MT8901_AFE_IRQ_4, -+ [MT8901_AFE_MEMIF_DL5] = MT8901_AFE_IRQ_5, -+ [MT8901_AFE_MEMIF_DL_24CH_0] = MT8901_AFE_IRQ_6, -+ [MT8901_AFE_MEMIF_UL0] = MT8901_AFE_IRQ_7, -+ [MT8901_AFE_MEMIF_UL1] = MT8901_AFE_IRQ_8, -+ [MT8901_AFE_MEMIF_UL2] = MT8901_AFE_IRQ_9, -+ [MT8901_AFE_MEMIF_UL3] = MT8901_AFE_IRQ_10, -+ [MT8901_AFE_MEMIF_UL4] = MT8901_AFE_IRQ_11, -+ [MT8901_AFE_MEMIF_UL5] = MT8901_AFE_IRQ_12, -+ [MT8901_AFE_MEMIF_VUL_CM0] = MT8901_AFE_IRQ_13, -+ [MT8901_AFE_MEMIF_VUL_CM1] = MT8901_AFE_IRQ_14, -+ [MT8901_AFE_MEMIF_VUL_CM2] = MT8901_AFE_IRQ_15, -+}; -+ -+static bool mt8901_is_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ /* registers with read-only bits cannot be cached */ -+ switch (reg) { -+ /* AUDIO_TOP: contains RO status bits */ -+ case AUDIO_TOP_CON0: -+ case AUDIO_TOP_CON1: -+ case AUDIO_TOP_CON3: -+ case AUDIO_TOP_CON4: -+ case AUDIO_TOP_CON5: -+ /* CM monitor */ -+ case AFE_CM0_MON: -+ case AFE_CM1_MON: -+ case AFE_CM2_MON: -+ /* DL current pointer and monitor registers */ -+ case AFE_DL0_CUR_MSB: -+ case AFE_DL0_CUR: -+ case AFE_DL0_RCH_MON: -+ case AFE_DL0_LCH_MON: -+ case AFE_DL0_MON0: -+ case AFE_DL1_CUR_MSB: -+ case AFE_DL1_CUR: -+ case AFE_DL1_RCH_MON: -+ case AFE_DL1_LCH_MON: -+ case AFE_DL1_MON0: -+ case AFE_DL2_CUR_MSB: -+ case AFE_DL2_CUR: -+ case AFE_DL2_RCH_MON: -+ case AFE_DL2_LCH_MON: -+ case AFE_DL2_MON0: -+ case AFE_DL3_CUR_MSB: -+ case AFE_DL3_CUR: -+ case AFE_DL3_RCH_MON: -+ case AFE_DL3_LCH_MON: -+ case AFE_DL3_MON0: -+ case AFE_DL4_CUR_MSB: -+ case AFE_DL4_CUR: -+ case AFE_DL4_RCH_MON: -+ case AFE_DL4_LCH_MON: -+ case AFE_DL4_MON0: -+ case AFE_DL5_CUR_MSB: -+ case AFE_DL5_CUR: -+ case AFE_DL5_RCH_MON: -+ case AFE_DL5_LCH_MON: -+ case AFE_DL5_MON0: -+ case AFE_DL_24CH_CUR_MSB: -+ case AFE_DL_24CH_CUR: -+ case AFE_DL_24CH_MON0: -+ /* VUL current pointer and monitor registers */ -+ case AFE_VUL0_CUR_MSB: -+ case AFE_VUL0_CUR: -+ case AFE_VUL0_RCH_MON: -+ case AFE_VUL0_LCH_MON: -+ case AFE_VUL0_MON0: -+ case AFE_VUL1_CUR_MSB: -+ case AFE_VUL1_CUR: -+ case AFE_VUL1_RCH_MON: -+ case AFE_VUL1_LCH_MON: -+ case AFE_VUL1_MON0: -+ case AFE_VUL2_CUR_MSB: -+ case AFE_VUL2_CUR: -+ case AFE_VUL2_RCH_MON: -+ case AFE_VUL2_LCH_MON: -+ case AFE_VUL2_MON0: -+ case AFE_VUL3_CUR_MSB: -+ case AFE_VUL3_CUR: -+ case AFE_VUL3_RCH_MON: -+ case AFE_VUL3_LCH_MON: -+ case AFE_VUL3_MON0: -+ case AFE_VUL4_CUR_MSB: -+ case AFE_VUL4_CUR: -+ case AFE_VUL4_RCH_MON: -+ case AFE_VUL4_LCH_MON: -+ case AFE_VUL4_MON0: -+ case AFE_VUL5_CUR_MSB: -+ case AFE_VUL5_CUR: -+ case AFE_VUL5_RCH_MON: -+ case AFE_VUL5_LCH_MON: -+ case AFE_VUL5_MON0: -+ case AFE_VUL8_CUR_MSB: -+ case AFE_VUL8_CUR: -+ case AFE_VUL8_RCH_MON: -+ case AFE_VUL8_LCH_MON: -+ case AFE_VUL8_MON0: -+ case AFE_VUL9_CUR_MSB: -+ case AFE_VUL9_CUR: -+ case AFE_VUL9_RCH_MON: -+ case AFE_VUL9_LCH_MON: -+ case AFE_VUL9_MON0: -+ case AFE_VUL10_CUR_MSB: -+ case AFE_VUL10_CUR: -+ case AFE_VUL10_RCH_MON: -+ case AFE_VUL10_LCH_MON: -+ case AFE_VUL10_MON0: -+ /* VUL_CM current pointer (MON0 not defined in reg.h) */ -+ case AFE_VUL_CM0_CUR_MSB: -+ case AFE_VUL_CM0_CUR: -+ case AFE_VUL_CM1_CUR_MSB: -+ case AFE_VUL_CM1_CUR: -+ case AFE_VUL_CM2_CUR_MSB: -+ case AFE_VUL_CM2_CUR: -+ /* IRQ status and monitor registers */ -+ case AFE_IRQ_MCU_STATUS: -+ case AFE_CUSTOM_IRQ_MCU_STATUS: -+ case AFE_IRQ0_CNT_MON: -+ case AFE_IRQ1_CNT_MON: -+ case AFE_IRQ2_CNT_MON: -+ case AFE_IRQ3_CNT_MON: -+ case AFE_IRQ4_CNT_MON: -+ case AFE_IRQ5_CNT_MON: -+ case AFE_IRQ6_CNT_MON: -+ case AFE_IRQ7_CNT_MON: -+ case AFE_IRQ8_CNT_MON: -+ case AFE_IRQ9_CNT_MON: -+ case AFE_IRQ10_CNT_MON: -+ case AFE_IRQ11_CNT_MON: -+ case AFE_IRQ12_CNT_MON: -+ case AFE_IRQ13_CNT_MON: -+ case AFE_IRQ14_CNT_MON: -+ case AFE_IRQ15_CNT_MON: -+ case AFE_IRQ16_CNT_MON: -+ case AFE_IRQ17_CNT_MON: -+ case AFE_IRQ18_CNT_MON: -+ case AFE_IRQ19_CNT_MON: -+ case AFE_IRQ20_CNT_MON: -+ case AFE_IRQ21_CNT_MON: -+ case AFE_IRQ22_CNT_MON: -+ case AFE_IRQ23_CNT_MON: -+ case AFE_IRQ24_CNT_MON: -+ case AFE_IRQ25_CNT_MON: -+ case AFE_IRQ26_CNT_MON: -+ case AFE_IRQ_MCU_MON3: -+ case AFE_IRQ_MCU_MON0: -+ case AFE_IRQ_MCU_MON1: -+ case AFE_IRQ_MCU_MON2: -+ /* GASRC ratio/status monitor registers */ -+ case AFE_GASRC0_NEW_CON8: -+ case AFE_GASRC0_NEW_CON9: -+ case AFE_GASRC0_NEW_CON12: -+ case AFE_GASRC0_NEW_IP_VERSION: -+ case AFE_GASRC1_NEW_CON8: -+ case AFE_GASRC1_NEW_CON9: -+ case AFE_GASRC1_NEW_CON12: -+ case AFE_GASRC1_NEW_IP_VERSION: -+ case AFE_GASRC2_NEW_CON8: -+ case AFE_GASRC2_NEW_CON9: -+ case AFE_GASRC2_NEW_CON12: -+ case AFE_GASRC2_NEW_IP_VERSION: -+ case AFE_GASRC3_NEW_CON8: -+ case AFE_GASRC3_NEW_CON9: -+ case AFE_GASRC3_NEW_CON12: -+ case AFE_GASRC3_NEW_IP_VERSION: -+ case AFE_GASRC4_NEW_CON8: -+ case AFE_GASRC4_NEW_CON9: -+ case AFE_GASRC4_NEW_CON12: -+ case AFE_GASRC4_NEW_IP_VERSION: -+ case AFE_GASRC5_NEW_CON8: -+ case AFE_GASRC5_NEW_CON9: -+ case AFE_GASRC5_NEW_CON12: -+ case AFE_GASRC5_NEW_IP_VERSION: -+ case AFE_GASRC6_NEW_CON8: -+ case AFE_GASRC6_NEW_CON9: -+ case AFE_GASRC6_NEW_CON12: -+ case AFE_GASRC6_NEW_IP_VERSION: -+ case AFE_GASRC7_NEW_CON8: -+ case AFE_GASRC7_NEW_CON9: -+ case AFE_GASRC7_NEW_CON12: -+ case AFE_GASRC7_NEW_IP_VERSION: -+ case AFE_GASRC8_NEW_CON8: -+ case AFE_GASRC8_NEW_CON9: -+ case AFE_GASRC8_NEW_CON12: -+ case AFE_GASRC8_NEW_IP_VERSION: -+ case AFE_GASRC9_NEW_CON8: -+ case AFE_GASRC9_NEW_CON9: -+ case AFE_GASRC9_NEW_CON12: -+ case AFE_GASRC9_NEW_IP_VERSION: -+ case AFE_GASRC10_NEW_CON8: -+ case AFE_GASRC10_NEW_CON9: -+ case AFE_GASRC10_NEW_CON12: -+ case AFE_GASRC10_NEW_IP_VERSION: -+ case AFE_GASRC11_NEW_CON8: -+ case AFE_GASRC11_NEW_CON9: -+ case AFE_GASRC11_NEW_CON12: -+ case AFE_GASRC11_NEW_IP_VERSION: -+ return true; -+ default: -+ return false; -+ }; -+} -+ -+static const struct regmap_config mt8901_afe_regmap_config = { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .volatile_reg = mt8901_is_volatile_reg, -+ .max_register = AFE_MAX_REGISTER, -+ .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1), -+ .cache_type = REGCACHE_FLAT, -+}; -+ -+static irqreturn_t mt8901_afe_irq_handler(int irq_id, void *dev_id) -+{ -+ struct mtk_base_afe *afe = dev_id; -+ unsigned int val = 0; -+ unsigned int mcu_irq_en = 0; -+ int i = 0; -+ int ret = 0; -+ -+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &val); -+ if (ret) { -+ dev_err(afe->dev, "%s irq status err\n", __func__); -+ goto err_irq; -+ } -+ -+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_irq_en); -+ if (ret) { -+ dev_err(afe->dev, "%s read irq en err\n", __func__); -+ goto err_irq; -+ } -+ -+ /* only handle MCU-enabled IRQs */ -+ val &= mcu_irq_en; -+ -+ for (i = 0; i < MT8901_AFE_MEMIF_NUM; i++) { -+ struct mtk_base_afe_memif *memif = &afe->memif[i]; -+ struct mtk_base_irq_data const *irq_data; -+ -+ if (memif->irq_usage < 0) -+ continue; -+ -+ irq_data = afe->irqs[memif->irq_usage].irq_data; -+ -+ if (!(val & BIT(irq_data->irq_status_shift))) -+ continue; -+ -+ /* clear IRQ by writing bit 31 of each IRQ's CFG1 register */ -+ mt8901_afe_irq_clear(afe, irq_data); -+ -+ snd_pcm_period_elapsed(memif->substream); -+ } -+ -+ return IRQ_HANDLED; -+ -+err_irq: -+ /* clear all enabled IRQs on error */ -+ for (i = 0; i < MT8901_AFE_IRQ_NUM; i++) -+ mt8901_afe_irq_clear(afe, &irq_data[i]); -+ -+ return IRQ_HANDLED; -+} -+ -+static int init_memif_priv_data(struct mtk_base_afe *afe) -+{ -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ struct mtk_dai_memif_priv *memif_priv; -+ int i; -+ -+ for (i = MT8901_AFE_MEMIF_START; i < MT8901_AFE_MEMIF_END; i++) { -+ memif_priv = devm_kzalloc(afe->dev, -+ sizeof(struct mtk_dai_memif_priv), -+ GFP_KERNEL); -+ if (!memif_priv) -+ return -ENOMEM; -+ -+ memif_priv->domain = MT8901_DOMAIN_APLL; -+ /* burst mode: minlen = 64-byte, maxlen = 64-byte burst */ -+ memif_priv->minlen = MT8901_MEMIF_MINLEN; -+ memif_priv->maxlen = MT8901_MEMIF_MAXLEN; -+ afe_priv->dai_priv[i] = memif_priv; -+ } -+ -+ return 0; -+} -+ -+static int mt8901_dai_memif_register(struct mtk_base_afe *afe) -+{ -+ struct mtk_base_afe_dai *dai; -+ -+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); -+ if (!dai) -+ return -ENOMEM; -+ -+ list_add(&dai->list, &afe->sub_dais); -+ -+ dai->dai_drivers = mt8901_memif_dai_driver; -+ dai->num_dai_drivers = ARRAY_SIZE(mt8901_memif_dai_driver); -+ -+ dai->dapm_widgets = mt8901_memif_widgets; -+ dai->num_dapm_widgets = ARRAY_SIZE(mt8901_memif_widgets); -+ dai->dapm_routes = mt8901_memif_routes; -+ dai->num_dapm_routes = ARRAY_SIZE(mt8901_memif_routes); -+ dai->controls = mt8901_memif_controls; -+ dai->num_controls = ARRAY_SIZE(mt8901_memif_controls); -+ return init_memif_priv_data(afe); -+} -+ -+typedef int (*dai_register_cb)(struct mtk_base_afe *); -+static const dai_register_cb dai_register_cbs[] = { -+ mt8901_dai_soundwire_register, -+ mt8901_dai_memif_register, -+}; -+ -+static int mt8901_afe_init_regs(struct mtk_base_afe *afe) -+{ -+ /* -+ * Route only the sources a memif can own (IRQ 0 to 15) to the MCU. -+ * The handler acknowledges through the memif mapping, so an enabled -+ * source without a memif would retrigger forever. Per-stream gating -+ * is the CFG0 enable bit driven by the trigger callbacks. -+ */ -+ static const struct reg_sequence init_regs[] = { -+ { AFE_IRQ_MCU_EN, GENMASK(MT8901_AFE_MEMIF_NUM - 1, 0) }, -+ { AFE_APLL1_TUNER_CFG, 0x332 }, -+ { AFE_APLL2_TUNER_CFG, 0x374 }, -+ { AFE_MEMIF_CON0, 0x9 }, -+ }; -+ int i; -+ -+ /* Firmware may leave sources asserted; clear them all before routing. */ -+ for (i = 0; i < MT8901_AFE_IRQ_NUM; i++) -+ mt8901_afe_irq_clear(afe, &irq_data[i]); -+ -+ return regmap_multi_reg_write(afe->regmap, -+ init_regs, ARRAY_SIZE(init_regs)); -+} -+ -+static int mt8901_afe_pcm_dev_probe(struct platform_device *pdev) -+{ -+ struct mtk_base_afe *afe; -+ struct mt8901_afe_private *afe_priv; -+ struct device *dev = &pdev->dev; -+ int i, irq_id, ret; -+ -+ ret = dma_set_mask_and_coherent(dev, -+ DMA_BIT_MASK(MT8901_DMA_ADDR_BITS)); -+ if (ret) -+ return ret; -+ -+ afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL); -+ if (!afe) -+ return -ENOMEM; -+ -+ afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv), -+ GFP_KERNEL); -+ if (!afe->platform_priv) -+ return -ENOMEM; -+ -+ afe_priv = afe->platform_priv; -+ afe->dev = &pdev->dev; -+ -+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(afe->base_addr)) -+ return dev_err_probe(dev, PTR_ERR(afe->base_addr), -+ "AFE base_addr not found\n"); -+ -+ mutex_init(&afe->irq_alloc_lock); -+ -+ /* irq initialize */ -+ afe->irqs_size = MT8901_AFE_IRQ_NUM; -+ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), -+ GFP_KERNEL); -+ if (!afe->irqs) -+ return -ENOMEM; -+ -+ for (i = 0; i < afe->irqs_size; i++) -+ afe->irqs[i].irq_data = &irq_data[i]; -+ -+ /* init memif */ -+ afe->memif_size = MT8901_AFE_MEMIF_NUM; -+ afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), -+ GFP_KERNEL); -+ if (!afe->memif) -+ return -ENOMEM; -+ -+ for (i = 0; i < afe->memif_size; i++) { -+ afe->memif[i].data = &memif_data[i]; -+ afe->memif[i].irq_usage = mt8901_afe_memif_const_irqs[i]; -+ afe->memif[i].const_irq = 1; -+ afe->irqs[afe->memif[i].irq_usage].irq_occupyed = true; -+ } -+ -+ irq_id = platform_get_irq(pdev, 0); -+ if (irq_id < 0) -+ return dev_err_probe(dev, irq_id, "no irq found"); -+ -+ /* init sub_dais */ -+ INIT_LIST_HEAD(&afe->sub_dais); -+ -+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { -+ ret = dai_register_cbs[i](afe); -+ if (ret) -+ return dev_err_probe(dev, ret, -+ "dai register i %d fail\n", i); -+ } -+ -+ /* init dai_driver and component_driver */ -+ ret = mtk_afe_combine_sub_dai(afe); -+ if (ret) -+ return dev_err_probe(dev, ret, -+ "mtk_afe_combine_sub_dai fail\n"); -+ -+ afe->mtk_afe_hardware = &mt8901_afe_hardware; -+ afe->memif_fs = mt8901_memif_fs; -+ afe->irq_fs = mt8901_irq_fs; -+ afe->memif_32bit_supported = 1; -+ -+ platform_set_drvdata(pdev, afe); -+ -+ device_property_read_u32(dev, "acpi-asd-hw-ver", &afe_priv->hw_ver); -+ -+ dev_info(dev, "acpi-asd-hw-ver = %u\n", afe_priv->hw_ver); -+ -+ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, -+ &mt8901_afe_regmap_config); -+ if (IS_ERR(afe->regmap)) { -+ ret = PTR_ERR(afe->regmap); -+ return ret; -+ } -+ -+ /* always on clock */ -+ mt8901_afe_enable_main_clock(afe); -+ -+ ret = mt8901_afe_init_regs(afe); -+ if (ret) { -+ dev_err(dev, "afe init regs failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * Request the IRQ only once the regmap exists and the IRQ enable -+ * state has been initialized: the handler dereferences afe->regmap -+ * unconditionally and firmware (UEFI POST audio) may leave interrupt -+ * state asserted, so an earlier request can fire into a half-set-up -+ * driver. -+ */ -+ ret = devm_request_threaded_irq(dev, irq_id, NULL, -+ mt8901_afe_irq_handler, -+ IRQF_ONESHOT, -+ "AFE_ISR_Handle", (void *)afe); -+ if (ret) { -+ mt8901_afe_disable_main_clock(afe); -+ return dev_err_probe(dev, ret, -+ "could not request_irq for AFE_ISR_Handle\n"); -+ } -+ -+ /* register component after regcache is in cache-only mode */ -+ ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform, -+ afe->dai_drivers, -+ afe->num_dai_drivers); -+ if (ret) -+ return dev_err_probe(dev, ret, "err_platform\n"); -+ -+ return 0; -+} -+ -+/* ACPI match: ASD0 device in Audio.asl (_HID = "NVDA9022") */ -+static const struct acpi_device_id mt8901_afe_acpi_match[] = { -+ { "NVDA9022", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, mt8901_afe_acpi_match); -+ -+static struct platform_driver mt8901_afe_pcm_driver = { -+ .driver = { -+ .name = "mt8901-audio", -+ .acpi_match_table = ACPI_PTR(mt8901_afe_acpi_match), -+ }, -+ .probe = mt8901_afe_pcm_dev_probe, -+}; -+ -+module_platform_driver(mt8901_afe_pcm_driver); -+ -+MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA 8901"); -+MODULE_AUTHOR("Weiyi Hsieh "); -+MODULE_AUTHOR("Trevor Wu "); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/mediatek/mt8901/mt8901-dai-soundwire.c b/sound/soc/mediatek/mt8901/mt8901-dai-soundwire.c -new file mode 100644 -index 0000000000..8c69141547 ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/mt8901-dai-soundwire.c -@@ -0,0 +1,213 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek MT8901 SoundWire DAI driver -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#include "mt8901-afe-common.h" -+#include "mt8901-reg.h" -+ -+/* BRA TX SDW1: DL5 I042/I043 -> O148/O149 */ -+static const struct snd_kcontrol_new mtk_dai_sndw_o148_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I042 Switch", AFE_CONN148_1, 10, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new mtk_dai_sndw_o149_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I043 Switch", AFE_CONN149_1, 11, 1, 0), -+}; -+ -+/* SCD0 DL: O150/O151 <- DL0 I032/I033 (2CH), DL_24CH I054/I055 (>2CH) */ -+static const struct snd_kcontrol_new mtk_dai_sndw_o150_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN150_1, 0, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I054 Switch", AFE_CONN150_1, 22, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new mtk_dai_sndw_o151_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN151_1, 1, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I055 Switch", AFE_CONN151_1, 23, 1, 0), -+}; -+ -+/* PDI3 mix: O152/O153 <- DL0 I032/I033 (2CH aggr), DL_24CH I056/I057 (>2CH) */ -+static const struct snd_kcontrol_new mtk_dai_sndw_o152_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I032 Switch", AFE_CONN152_1, 0, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I056 Switch", AFE_CONN152_1, 24, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new mtk_dai_sndw_o153_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I033 Switch", AFE_CONN153_1, 1, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I057 Switch", AFE_CONN153_1, 25, 1, 0), -+}; -+ -+/* PDI4 mix: O154/O155 <- DL_24CH I058/I059 (>2CH ch5~6) */ -+static const struct snd_kcontrol_new mtk_dai_sndw_o154_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I058 Switch", AFE_CONN154_1, 26, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new mtk_dai_sndw_o155_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I059 Switch", AFE_CONN155_1, 27, 1, 0), -+}; -+ -+/* PDI5 mix: O156/O157 <- DL1 I034/I035 (HP/HSO first-fit), -+ * DL_24CH I060/I061 (>2CH ch7~8) -+ */ -+static const struct snd_kcontrol_new mtk_dai_sndw_o156_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN156_1, 2, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I060 Switch", AFE_CONN156_1, 28, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new mtk_dai_sndw_o157_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN157_1, 3, 1, 0), -+ SOC_DAPM_SINGLE_AUTODISABLE("I061 Switch", AFE_CONN157_1, 29, 1, 0), -+}; -+ -+/* PDI6 mix: O158/O159 <- DL1 I034/I035 (Headphone/HeadsetOutput contention) */ -+static const struct snd_kcontrol_new mtk_dai_sndw_o158_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I034 Switch", AFE_CONN158_1, 2, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new mtk_dai_sndw_o159_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I035 Switch", AFE_CONN159_1, 3, 1, 0), -+}; -+ -+/* BRA TX SDW0: O160/O161 <- DL4 I040/I041 */ -+static const struct snd_kcontrol_new mtk_dai_sndw_o160_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I040 Switch", AFE_CONN160_1, 8, 1, 0), -+}; -+ -+static const struct snd_kcontrol_new mtk_dai_sndw_o161_mix[] = { -+ SOC_DAPM_SINGLE_AUTODISABLE("I041 Switch", AFE_CONN161_1, 9, 1, 0), -+}; -+ -+static const struct snd_soc_dapm_widget mtk_dai_soundwire_widgets[] = { -+ /* BRA TX SDW1: O148/O149 */ -+ SND_SOC_DAPM_MIXER("O148", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o148_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o148_mix)), -+ SND_SOC_DAPM_MIXER("O149", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o149_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o149_mix)), -+ -+ /* TX O port widgets: O150~O161 */ -+ SND_SOC_DAPM_MIXER("O150", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o150_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o150_mix)), -+ SND_SOC_DAPM_MIXER("O151", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o151_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o151_mix)), -+ SND_SOC_DAPM_MIXER("O152", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o152_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o152_mix)), -+ SND_SOC_DAPM_MIXER("O153", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o153_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o153_mix)), -+ SND_SOC_DAPM_MIXER("O154", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o154_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o154_mix)), -+ SND_SOC_DAPM_MIXER("O155", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o155_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o155_mix)), -+ SND_SOC_DAPM_MIXER("O156", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o156_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o156_mix)), -+ SND_SOC_DAPM_MIXER("O157", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o157_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o157_mix)), -+ SND_SOC_DAPM_MIXER("O158", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o158_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o158_mix)), -+ SND_SOC_DAPM_MIXER("O159", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o159_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o159_mix)), -+ SND_SOC_DAPM_MIXER("O160", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o160_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o160_mix)), -+ SND_SOC_DAPM_MIXER("O161", SND_SOC_NOPM, 0, 0, -+ mtk_dai_sndw_o161_mix, -+ ARRAY_SIZE(mtk_dai_sndw_o161_mix)), -+ -+ /* RX I port widgets */ -+ /* SNDW1 exclusive: I166/I167 */ -+ SND_SOC_DAPM_MIXER("I166", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I167", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* Shared PDI7~PDI15: I168~I185 */ -+ SND_SOC_DAPM_MIXER("I168", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I169", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I170", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I171", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I172", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I173", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I174", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I175", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I176", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I177", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I178", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I179", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I180", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I181", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I182", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I183", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I184", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I185", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* SNDW0 exclusive: I186/I187 */ -+ SND_SOC_DAPM_MIXER("I186", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_MIXER("I187", SND_SOC_NOPM, 0, 0, NULL, 0), -+}; -+ -+static const struct snd_soc_dapm_route mtk_dai_sndw_routes[] = { -+ /* BRA TX SDW1: DL5 -> O148/O149 */ -+ {"O148", "I042 Switch", "I042"}, -+ {"O149", "I043 Switch", "I043"}, -+ -+ /* Speaker 2CH: DL0 -> PDI2 */ -+ {"O150", "I032 Switch", "I032"}, -+ {"O151", "I033 Switch", "I033"}, -+ -+ /* Speaker 2CH aggregation: DL0 -> PDI3 */ -+ {"O152", "I032 Switch", "I032"}, -+ {"O153", "I033 Switch", "I033"}, -+ -+ /* Speaker >2CH max 8CH: DL_24CH -> PDI2~PDI5 (O150~O157) */ -+ {"O150", "I054 Switch", "I054"}, -+ {"O151", "I055 Switch", "I055"}, -+ {"O152", "I056 Switch", "I056"}, -+ {"O153", "I057 Switch", "I057"}, -+ {"O154", "I058 Switch", "I058"}, -+ {"O155", "I059 Switch", "I059"}, -+ {"O156", "I060 Switch", "I060"}, -+ {"O157", "I061 Switch", "I061"}, -+ -+ /* BRA TX SDW0: DL4 -> O160/O161 */ -+ {"O160", "I040 Switch", "I040"}, -+ {"O161", "I041 Switch", "I041"}, -+ -+ /* Headphone/HeadsetOutput: DL1 -> PDI5 (first-fit) */ -+ {"O156", "I034 Switch", "I034"}, -+ {"O157", "I035 Switch", "I035"}, -+ -+ /* Headphone/HeadsetOutput: DL1 -> PDI6 (contention) */ -+ {"O158", "I034 Switch", "I034"}, -+ {"O159", "I035 Switch", "I035"}, -+}; -+ -+int mt8901_dai_soundwire_register(struct mtk_base_afe *afe) -+{ -+ struct mtk_base_afe_dai *dai; -+ -+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); -+ if (!dai) -+ return -ENOMEM; -+ -+ list_add(&dai->list, &afe->sub_dais); -+ -+ dai->dapm_widgets = mtk_dai_soundwire_widgets; -+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_soundwire_widgets); -+ dai->dapm_routes = mtk_dai_sndw_routes; -+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_sndw_routes); -+ -+ return 0; -+} -diff --git a/sound/soc/mediatek/mt8901/mt8901-reg.h b/sound/soc/mediatek/mt8901/mt8901-reg.h -new file mode 100644 -index 0000000000..70ff5f0a55 ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/mt8901-reg.h -@@ -0,0 +1,2188 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * mt8901-reg.h -- MediaTek 8901 audio driver reg definition -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#ifndef _MT8901_REG_H_ -+#define _MT8901_REG_H_ -+ -+#define AUDIO_TOP_CON0 (0x0000) -+#define AUDIO_TOP_CON1 (0x0004) -+#define AUDIO_TOP_CON2 (0x0008) -+#define AUDIO_TOP_CON3 (0x000c) -+#define AUDIO_TOP_CON4 (0x0010) -+#define AUDIO_ENGEN_CON0 (0x0014) -+#define AUDIO_ENGEN_CON0_USER1 (0x0018) -+#define AUDIO_ENGEN_CON0_USER2 (0x001c) -+#define AFE_SINEGEN_CON0 (0x0020) -+#define AFE_SINEGEN_CON1 (0x0024) -+#define AFE_SINEGEN_CON2 (0x0028) -+#define AFE_SINEGEN_CON3 (0x002c) -+#define AFE_APLL1_TUNER_CFG (0x0030) -+#define AFE_APLL1_TUNER_MON0 (0x0034) -+#define AFE_APLL2_TUNER_CFG (0x0038) -+#define AFE_APLL2_TUNER_MON0 (0x003c) -+#define AFE_SPM_CONTROL_REQ (0x0060) -+#define AFE_SPM_CONTROL_ACK (0x0064) -+#define AUD_TOP_CFG_VCORE_RG (0x0068) -+#define AUDIO_TOP_IP_VERSION (0x006c) -+#define AUDIO_TOP_CON5 (0x0070) -+#define AUDIO_ENGEN_CON0_MON (0x007c) -+#define AUD_TOP_CFG_VLP_RG (0x0098) -+#define AUD_TOP_MON_RG (0x009c) -+#define AFE_CM0_CON0 (0x0ba0) -+#define AFE_CM0_MON (0x0ba4) -+#define AFE_CM0_IP_VERSION (0x0ba8) -+#define AFE_CM1_CON0 (0x0bb0) -+#define AFE_CM1_MON (0x0bb4) -+#define AFE_CM1_IP_VERSION (0x0bb8) -+#define AFE_CM2_CON0 (0x0bc0) -+#define AFE_CM2_MON (0x0bc4) -+#define AFE_CM2_IP_VERSION (0x0bc8) -+#define AFE_ADDA_UL0_SRC_CON0 (0x0bd0) -+#define AFE_ADDA_UL0_SRC_CON1 (0x0bd4) -+#define AFE_ADDA_UL0_SRC_CON2 (0x0bd8) -+#define AFE_ADDA_UL0_SRC_DEBUG (0x0bdc) -+#define AFE_ADDA_UL0_SRC_DEBUG_MON0 (0x0be0) -+#define AFE_ADDA_UL0_SRC_MON0 (0x0be4) -+#define AFE_ADDA_UL0_SRC_MON1 (0x0be8) -+#define AFE_ADDA_UL0_IIR_COEF_02_01 (0x0bec) -+#define AFE_ADDA_UL0_IIR_COEF_04_03 (0x0bf0) -+#define AFE_ADDA_UL0_IIR_COEF_06_05 (0x0bf4) -+#define AFE_ADDA_UL0_IIR_COEF_08_07 (0x0bf8) -+#define AFE_ADDA_UL0_IIR_COEF_10_09 (0x0bfc) -+#define AFE_ADDA_UL0_ULCF_CFG_02_01 (0x0c00) -+#define AFE_ADDA_UL0_ULCF_CFG_04_03 (0x0c04) -+#define AFE_ADDA_UL0_ULCF_CFG_06_05 (0x0c08) -+#define AFE_ADDA_UL0_ULCF_CFG_08_07 (0x0c0c) -+#define AFE_ADDA_UL0_ULCF_CFG_10_09 (0x0c10) -+#define AFE_ADDA_UL0_ULCF_CFG_12_11 (0x0c14) -+#define AFE_ADDA_UL0_ULCF_CFG_14_13 (0x0c18) -+#define AFE_ADDA_UL0_ULCF_CFG_16_15 (0x0c1c) -+#define AFE_ADDA_UL0_ULCF_CFG_18_17 (0x0c20) -+#define AFE_ADDA_UL0_ULCF_CFG_20_19 (0x0c24) -+#define AFE_ADDA_UL0_ULCF_CFG_22_21 (0x0c28) -+#define AFE_ADDA_UL0_ULCF_CFG_24_23 (0x0c2c) -+#define AFE_ADDA_UL0_ULCF_CFG_26_25 (0x0c30) -+#define AFE_ADDA_UL0_ULCF_CFG_28_27 (0x0c34) -+#define AFE_ADDA_UL0_ULCF_CFG_30_29 (0x0c38) -+#define AFE_ADDA_UL0_ULCF_CFG_32_31 (0x0c3c) -+#define AFE_ADDA_UL0_IP_VERSION (0x0c4c) -+#define AFE_ADDA_UL1_SRC_CON0 (0x0c50) -+#define AFE_ADDA_UL1_SRC_CON1 (0x0c54) -+#define AFE_ADDA_UL1_SRC_CON2 (0x0c58) -+#define AFE_ADDA_UL1_SRC_DEBUG (0x0c5c) -+#define AFE_ADDA_UL1_SRC_DEBUG_MON0 (0x0c60) -+#define AFE_ADDA_UL1_SRC_MON0 (0x0c64) -+#define AFE_ADDA_UL1_SRC_MON1 (0x0c68) -+#define AFE_ADDA_UL1_IIR_COEF_02_01 (0x0c6c) -+#define AFE_ADDA_UL1_IIR_COEF_04_03 (0x0c70) -+#define AFE_ADDA_UL1_IIR_COEF_06_05 (0x0c74) -+#define AFE_ADDA_UL1_IIR_COEF_08_07 (0x0c78) -+#define AFE_ADDA_UL1_IIR_COEF_10_09 (0x0c7c) -+#define AFE_ADDA_UL1_ULCF_CFG_02_01 (0x0c80) -+#define AFE_ADDA_UL1_ULCF_CFG_04_03 (0x0c84) -+#define AFE_ADDA_UL1_ULCF_CFG_06_05 (0x0c88) -+#define AFE_ADDA_UL1_ULCF_CFG_08_07 (0x0c8c) -+#define AFE_ADDA_UL1_ULCF_CFG_10_09 (0x0c90) -+#define AFE_ADDA_UL1_ULCF_CFG_12_11 (0x0c94) -+#define AFE_ADDA_UL1_ULCF_CFG_14_13 (0x0c98) -+#define AFE_ADDA_UL1_ULCF_CFG_16_15 (0x0c9c) -+#define AFE_ADDA_UL1_ULCF_CFG_18_17 (0x0ca0) -+#define AFE_ADDA_UL1_ULCF_CFG_20_19 (0x0ca4) -+#define AFE_ADDA_UL1_ULCF_CFG_22_21 (0x0ca8) -+#define AFE_ADDA_UL1_ULCF_CFG_24_23 (0x0cac) -+#define AFE_ADDA_UL1_ULCF_CFG_26_25 (0x0cb0) -+#define AFE_ADDA_UL1_ULCF_CFG_28_27 (0x0cb4) -+#define AFE_ADDA_UL1_ULCF_CFG_30_29 (0x0cb8) -+#define AFE_ADDA_UL1_ULCF_CFG_32_31 (0x0cbc) -+#define AFE_ADDA_UL1_IP_VERSION (0x0ccc) -+#define AFE_ADDA_ULSRC_PHASE_CLK_CON0 (0x0f00) -+#define AFE_ADDA_ULSRC_PHASE_CLK_CON1 (0x0f04) -+#define AFE_ADDA_ULSRC_PHASE_CLK_CON2 (0x0f08) -+#define AFE_ADDA_ULSRC_PHASE_CLK_CON3 (0x0f0c) -+#define AFE_ADDA_ULSRC_PHASE_CLK_CON4 (0x0f10) -+#define AFE_ADDA_ULSRC_PHASE_ENGEN_CON0 (0x0f14) -+#define AFE_ADDA_ULSRC_PHASE_ENGEN_CON1 (0x0f18) -+#define AFE_ADDA_ULSRC_PHASE_RST_CON0 (0x0f1c) -+#define ETDM_IN0_CON0 (0x1300) -+#define ETDM_IN0_CON1 (0x1304) -+#define ETDM_IN0_CON2 (0x1308) -+#define ETDM_IN0_CON3 (0x130c) -+#define ETDM_IN0_CON4 (0x1310) -+#define ETDM_IN0_CON5 (0x1314) -+#define ETDM_IN0_CON6 (0x1318) -+#define ETDM_IN0_CON7 (0x131c) -+#define ETDM_IN0_CON8 (0x1320) -+#define ETDM_IN0_CON9 (0x1324) -+#define ETDM_IN0_MON (0x1328) -+#define ETDM_IN5_CON0 (0x13f0) -+#define ETDM_IN5_CON1 (0x13f4) -+#define ETDM_IN5_CON2 (0x13f8) -+#define ETDM_IN5_CON3 (0x13fc) -+#define ETDM_IN5_CON4 (0x1400) -+#define ETDM_IN5_CON5 (0x1404) -+#define ETDM_IN5_CON6 (0x1408) -+#define ETDM_IN5_CON7 (0x140c) -+#define ETDM_IN5_CON8 (0x1410) -+#define ETDM_IN5_CON9 (0x1414) -+#define ETDM_IN5_MON (0x1418) -+#define ETDM_OUT0_CON0 (0x1480) -+#define ETDM_OUT0_CON1 (0x1484) -+#define ETDM_OUT0_CON2 (0x1488) -+#define ETDM_OUT0_CON3 (0x148c) -+#define ETDM_OUT0_CON4 (0x1490) -+#define ETDM_OUT0_CON5 (0x1494) -+#define ETDM_OUT0_CON6 (0x1498) -+#define ETDM_OUT0_CON7 (0x149c) -+#define ETDM_OUT0_CON8 (0x14a0) -+#define ETDM_OUT0_CON9 (0x14a4) -+#define ETDM_OUT0_MON (0x14a8) -+#define ETDM_OUT5_CON0 (0x15c0) -+#define ETDM_OUT5_CON1 (0x15c4) -+#define ETDM_OUT5_CON2 (0x15c8) -+#define ETDM_OUT5_CON3 (0x15cc) -+#define ETDM_OUT5_CON4 (0x15d0) -+#define ETDM_OUT5_CON5 (0x15d4) -+#define ETDM_OUT5_CON6 (0x15d8) -+#define ETDM_OUT5_CON7 (0x15dc) -+#define ETDM_OUT5_CON8 (0x15e0) -+#define ETDM_OUT5_CON9 (0x15e4) -+#define ETDM_OUT5_MON (0x15e8) -+#define ETDM_0_3_COWORK_CON0 (0x1680) -+#define ETDM_0_3_COWORK_CON1 (0x1684) -+#define ETDM_0_3_COWORK_CON2 (0x1688) -+#define ETDM_0_3_COWORK_CON3 (0x168c) -+#define ETDM_4_7_COWORK_CON0 (0x1690) -+#define ETDM_4_7_COWORK_CON1 (0x1694) -+#define ETDM_4_7_COWORK_CON2 (0x1698) -+#define ETDM_4_7_COWORK_CON3 (0x169c) -+#define ETDM_IP_VERSION (0x1c4c) -+#define AFE_CONN000_0 (0x2080) -+#define AFE_CONN004_0 (0x2100) -+#define AFE_CONN004_1 (0x2104) -+#define AFE_CONN004_2 (0x2108) -+#define AFE_CONN004_3 (0x210c) -+#define AFE_CONN004_4 (0x2110) -+#define AFE_CONN004_5 (0x2114) -+#define AFE_CONN004_6 (0x2118) -+#define AFE_CONN004_7 (0x211c) -+#define AFE_CONN005_0 (0x2120) -+#define AFE_CONN005_1 (0x2124) -+#define AFE_CONN005_2 (0x2128) -+#define AFE_CONN005_3 (0x212c) -+#define AFE_CONN005_4 (0x2130) -+#define AFE_CONN005_5 (0x2134) -+#define AFE_CONN005_6 (0x2138) -+#define AFE_CONN005_7 (0x213c) -+#define AFE_CONN006_0 (0x2140) -+#define AFE_CONN006_1 (0x2144) -+#define AFE_CONN006_2 (0x2148) -+#define AFE_CONN006_3 (0x214c) -+#define AFE_CONN006_4 (0x2150) -+#define AFE_CONN006_5 (0x2154) -+#define AFE_CONN006_6 (0x2158) -+#define AFE_CONN006_7 (0x215c) -+#define AFE_CONN007_0 (0x2160) -+#define AFE_CONN007_1 (0x2164) -+#define AFE_CONN007_2 (0x2168) -+#define AFE_CONN007_3 (0x216c) -+#define AFE_CONN007_4 (0x2170) -+#define AFE_CONN007_5 (0x2174) -+#define AFE_CONN007_6 (0x2178) -+#define AFE_CONN007_7 (0x217c) -+#define AFE_CONN008_0 (0x2180) -+#define AFE_CONN008_1 (0x2184) -+#define AFE_CONN008_2 (0x2188) -+#define AFE_CONN008_3 (0x218c) -+#define AFE_CONN008_4 (0x2190) -+#define AFE_CONN008_5 (0x2194) -+#define AFE_CONN008_6 (0x2198) -+#define AFE_CONN008_7 (0x219c) -+#define AFE_CONN009_0 (0x21a0) -+#define AFE_CONN009_1 (0x21a4) -+#define AFE_CONN009_2 (0x21a8) -+#define AFE_CONN009_3 (0x21ac) -+#define AFE_CONN009_4 (0x21b0) -+#define AFE_CONN009_5 (0x21b4) -+#define AFE_CONN009_6 (0x21b8) -+#define AFE_CONN009_7 (0x21bc) -+#define AFE_CONN010_0 (0x21c0) -+#define AFE_CONN010_1 (0x21c4) -+#define AFE_CONN010_2 (0x21c8) -+#define AFE_CONN010_3 (0x21cc) -+#define AFE_CONN010_4 (0x21d0) -+#define AFE_CONN010_5 (0x21d4) -+#define AFE_CONN010_6 (0x21d8) -+#define AFE_CONN010_7 (0x21dc) -+#define AFE_CONN011_0 (0x21e0) -+#define AFE_CONN011_1 (0x21e4) -+#define AFE_CONN011_2 (0x21e8) -+#define AFE_CONN011_3 (0x21ec) -+#define AFE_CONN011_4 (0x21f0) -+#define AFE_CONN011_5 (0x21f4) -+#define AFE_CONN011_6 (0x21f8) -+#define AFE_CONN011_7 (0x21fc) -+#define AFE_CONN012_0 (0x2200) -+#define AFE_CONN012_1 (0x2204) -+#define AFE_CONN012_2 (0x2208) -+#define AFE_CONN012_3 (0x220c) -+#define AFE_CONN012_4 (0x2210) -+#define AFE_CONN012_5 (0x2214) -+#define AFE_CONN012_6 (0x2218) -+#define AFE_CONN012_7 (0x221c) -+#define AFE_CONN013_0 (0x2220) -+#define AFE_CONN013_1 (0x2224) -+#define AFE_CONN013_2 (0x2228) -+#define AFE_CONN013_3 (0x222c) -+#define AFE_CONN013_4 (0x2230) -+#define AFE_CONN013_5 (0x2234) -+#define AFE_CONN013_6 (0x2238) -+#define AFE_CONN013_7 (0x223c) -+#define AFE_CONN014_0 (0x2240) -+#define AFE_CONN014_1 (0x2244) -+#define AFE_CONN014_2 (0x2248) -+#define AFE_CONN014_3 (0x224c) -+#define AFE_CONN014_4 (0x2250) -+#define AFE_CONN014_5 (0x2254) -+#define AFE_CONN014_6 (0x2258) -+#define AFE_CONN014_7 (0x225c) -+#define AFE_CONN015_0 (0x2260) -+#define AFE_CONN015_1 (0x2264) -+#define AFE_CONN015_2 (0x2268) -+#define AFE_CONN015_3 (0x226c) -+#define AFE_CONN015_4 (0x2270) -+#define AFE_CONN015_5 (0x2274) -+#define AFE_CONN015_6 (0x2278) -+#define AFE_CONN015_7 (0x227c) -+#define AFE_CONN016_0 (0x2280) -+#define AFE_CONN016_1 (0x2284) -+#define AFE_CONN016_2 (0x2288) -+#define AFE_CONN016_3 (0x228c) -+#define AFE_CONN016_4 (0x2290) -+#define AFE_CONN016_5 (0x2294) -+#define AFE_CONN016_6 (0x2298) -+#define AFE_CONN016_7 (0x229c) -+#define AFE_CONN017_0 (0x22a0) -+#define AFE_CONN017_1 (0x22a4) -+#define AFE_CONN017_2 (0x22a8) -+#define AFE_CONN017_3 (0x22ac) -+#define AFE_CONN017_4 (0x22b0) -+#define AFE_CONN017_5 (0x22b4) -+#define AFE_CONN017_6 (0x22b8) -+#define AFE_CONN017_7 (0x22bc) -+#define AFE_CONN018_0 (0x22c0) -+#define AFE_CONN018_1 (0x22c4) -+#define AFE_CONN018_2 (0x22c8) -+#define AFE_CONN018_3 (0x22cc) -+#define AFE_CONN018_4 (0x22d0) -+#define AFE_CONN018_5 (0x22d4) -+#define AFE_CONN018_6 (0x22d8) -+#define AFE_CONN018_7 (0x22dc) -+#define AFE_CONN019_0 (0x22e0) -+#define AFE_CONN019_1 (0x22e4) -+#define AFE_CONN019_2 (0x22e8) -+#define AFE_CONN019_3 (0x22ec) -+#define AFE_CONN019_4 (0x22f0) -+#define AFE_CONN019_5 (0x22f4) -+#define AFE_CONN019_6 (0x22f8) -+#define AFE_CONN019_7 (0x22fc) -+#define AFE_CONN020_0 (0x2300) -+#define AFE_CONN020_1 (0x2304) -+#define AFE_CONN020_2 (0x2308) -+#define AFE_CONN020_3 (0x230c) -+#define AFE_CONN020_4 (0x2310) -+#define AFE_CONN020_5 (0x2314) -+#define AFE_CONN020_6 (0x2318) -+#define AFE_CONN020_7 (0x231c) -+#define AFE_CONN021_0 (0x2320) -+#define AFE_CONN021_1 (0x2324) -+#define AFE_CONN021_2 (0x2328) -+#define AFE_CONN021_3 (0x232c) -+#define AFE_CONN021_4 (0x2330) -+#define AFE_CONN021_5 (0x2334) -+#define AFE_CONN021_6 (0x2338) -+#define AFE_CONN021_7 (0x233c) -+#define AFE_CONN022_0 (0x2340) -+#define AFE_CONN022_1 (0x2344) -+#define AFE_CONN022_2 (0x2348) -+#define AFE_CONN022_3 (0x234c) -+#define AFE_CONN022_4 (0x2350) -+#define AFE_CONN022_5 (0x2354) -+#define AFE_CONN022_6 (0x2358) -+#define AFE_CONN022_7 (0x235c) -+#define AFE_CONN023_0 (0x2360) -+#define AFE_CONN023_1 (0x2364) -+#define AFE_CONN023_2 (0x2368) -+#define AFE_CONN023_3 (0x236c) -+#define AFE_CONN023_4 (0x2370) -+#define AFE_CONN023_5 (0x2374) -+#define AFE_CONN023_6 (0x2378) -+#define AFE_CONN023_7 (0x237c) -+#define AFE_CONN024_0 (0x2380) -+#define AFE_CONN024_1 (0x2384) -+#define AFE_CONN024_2 (0x2388) -+#define AFE_CONN024_3 (0x238c) -+#define AFE_CONN024_4 (0x2390) -+#define AFE_CONN024_5 (0x2394) -+#define AFE_CONN024_6 (0x2398) -+#define AFE_CONN024_7 (0x239c) -+#define AFE_CONN025_0 (0x23a0) -+#define AFE_CONN025_1 (0x23a4) -+#define AFE_CONN025_2 (0x23a8) -+#define AFE_CONN025_3 (0x23ac) -+#define AFE_CONN025_4 (0x23b0) -+#define AFE_CONN025_5 (0x23b4) -+#define AFE_CONN025_6 (0x23b8) -+#define AFE_CONN025_7 (0x23bc) -+#define AFE_CONN026_0 (0x23c0) -+#define AFE_CONN026_1 (0x23c4) -+#define AFE_CONN026_2 (0x23c8) -+#define AFE_CONN026_3 (0x23cc) -+#define AFE_CONN026_4 (0x23d0) -+#define AFE_CONN026_5 (0x23d4) -+#define AFE_CONN026_6 (0x23d8) -+#define AFE_CONN026_7 (0x23dc) -+#define AFE_CONN027_0 (0x23e0) -+#define AFE_CONN027_1 (0x23e4) -+#define AFE_CONN027_2 (0x23e8) -+#define AFE_CONN027_3 (0x23ec) -+#define AFE_CONN027_4 (0x23f0) -+#define AFE_CONN027_5 (0x23f4) -+#define AFE_CONN027_6 (0x23f8) -+#define AFE_CONN027_7 (0x23fc) -+#define AFE_CONN028_0 (0x2400) -+#define AFE_CONN028_1 (0x2404) -+#define AFE_CONN028_2 (0x2408) -+#define AFE_CONN028_3 (0x240c) -+#define AFE_CONN028_4 (0x2410) -+#define AFE_CONN028_5 (0x2414) -+#define AFE_CONN028_6 (0x2418) -+#define AFE_CONN028_7 (0x241c) -+#define AFE_CONN029_0 (0x2420) -+#define AFE_CONN029_1 (0x2424) -+#define AFE_CONN029_2 (0x2428) -+#define AFE_CONN029_3 (0x242c) -+#define AFE_CONN029_4 (0x2430) -+#define AFE_CONN029_5 (0x2434) -+#define AFE_CONN029_6 (0x2438) -+#define AFE_CONN029_7 (0x243c) -+#define AFE_CONN034_0 (0x24c0) -+#define AFE_CONN034_1 (0x24c4) -+#define AFE_CONN034_2 (0x24c8) -+#define AFE_CONN034_3 (0x24cc) -+#define AFE_CONN034_4 (0x24d0) -+#define AFE_CONN034_5 (0x24d4) -+#define AFE_CONN034_6 (0x24d8) -+#define AFE_CONN034_7 (0x24dc) -+#define AFE_CONN035_0 (0x24e0) -+#define AFE_CONN035_1 (0x24e4) -+#define AFE_CONN035_2 (0x24e8) -+#define AFE_CONN035_3 (0x24ec) -+#define AFE_CONN035_4 (0x24f0) -+#define AFE_CONN035_5 (0x24f4) -+#define AFE_CONN035_6 (0x24f8) -+#define AFE_CONN035_7 (0x24fc) -+#define AFE_CONN036_0 (0x2500) -+#define AFE_CONN036_1 (0x2504) -+#define AFE_CONN036_2 (0x2508) -+#define AFE_CONN036_3 (0x250c) -+#define AFE_CONN036_4 (0x2510) -+#define AFE_CONN036_5 (0x2514) -+#define AFE_CONN036_6 (0x2518) -+#define AFE_CONN036_7 (0x251c) -+#define AFE_CONN037_0 (0x2520) -+#define AFE_CONN037_1 (0x2524) -+#define AFE_CONN037_2 (0x2528) -+#define AFE_CONN037_3 (0x252c) -+#define AFE_CONN037_4 (0x2530) -+#define AFE_CONN037_5 (0x2534) -+#define AFE_CONN037_6 (0x2538) -+#define AFE_CONN037_7 (0x253c) -+#define AFE_CONN038_0 (0x2540) -+#define AFE_CONN038_1 (0x2544) -+#define AFE_CONN038_2 (0x2548) -+#define AFE_CONN038_3 (0x254c) -+#define AFE_CONN038_4 (0x2550) -+#define AFE_CONN038_5 (0x2554) -+#define AFE_CONN038_6 (0x2558) -+#define AFE_CONN038_7 (0x255c) -+#define AFE_CONN039_0 (0x2560) -+#define AFE_CONN039_1 (0x2564) -+#define AFE_CONN039_2 (0x2568) -+#define AFE_CONN039_3 (0x256c) -+#define AFE_CONN039_4 (0x2570) -+#define AFE_CONN039_5 (0x2574) -+#define AFE_CONN039_6 (0x2578) -+#define AFE_CONN039_7 (0x257c) -+#define AFE_CONN040_0 (0x2580) -+#define AFE_CONN040_1 (0x2584) -+#define AFE_CONN040_2 (0x2588) -+#define AFE_CONN040_3 (0x258c) -+#define AFE_CONN040_4 (0x2590) -+#define AFE_CONN040_5 (0x2594) -+#define AFE_CONN040_6 (0x2598) -+#define AFE_CONN040_7 (0x259c) -+#define AFE_CONN041_0 (0x25a0) -+#define AFE_CONN041_1 (0x25a4) -+#define AFE_CONN041_2 (0x25a8) -+#define AFE_CONN041_3 (0x25ac) -+#define AFE_CONN041_4 (0x25b0) -+#define AFE_CONN041_5 (0x25b4) -+#define AFE_CONN041_6 (0x25b8) -+#define AFE_CONN041_7 (0x25bc) -+#define AFE_CONN042_0 (0x25c0) -+#define AFE_CONN042_1 (0x25c4) -+#define AFE_CONN042_2 (0x25c8) -+#define AFE_CONN042_3 (0x25cc) -+#define AFE_CONN042_4 (0x25d0) -+#define AFE_CONN042_5 (0x25d4) -+#define AFE_CONN042_6 (0x25d8) -+#define AFE_CONN042_7 (0x25dc) -+#define AFE_CONN043_0 (0x25e0) -+#define AFE_CONN043_1 (0x25e4) -+#define AFE_CONN043_2 (0x25e8) -+#define AFE_CONN043_3 (0x25ec) -+#define AFE_CONN043_4 (0x25f0) -+#define AFE_CONN043_5 (0x25f4) -+#define AFE_CONN043_6 (0x25f8) -+#define AFE_CONN043_7 (0x25fc) -+#define AFE_CONN044_0 (0x2600) -+#define AFE_CONN044_1 (0x2604) -+#define AFE_CONN044_2 (0x2608) -+#define AFE_CONN044_3 (0x260c) -+#define AFE_CONN044_4 (0x2610) -+#define AFE_CONN044_5 (0x2614) -+#define AFE_CONN044_6 (0x2618) -+#define AFE_CONN044_7 (0x261c) -+#define AFE_CONN045_0 (0x2620) -+#define AFE_CONN045_1 (0x2624) -+#define AFE_CONN045_2 (0x2628) -+#define AFE_CONN045_3 (0x262c) -+#define AFE_CONN045_4 (0x2630) -+#define AFE_CONN045_5 (0x2634) -+#define AFE_CONN045_6 (0x2638) -+#define AFE_CONN045_7 (0x263c) -+#define AFE_CONN046_0 (0x2640) -+#define AFE_CONN046_1 (0x2644) -+#define AFE_CONN046_2 (0x2648) -+#define AFE_CONN046_3 (0x264c) -+#define AFE_CONN046_4 (0x2650) -+#define AFE_CONN046_5 (0x2654) -+#define AFE_CONN046_6 (0x2658) -+#define AFE_CONN046_7 (0x265c) -+#define AFE_CONN047_0 (0x2660) -+#define AFE_CONN047_1 (0x2664) -+#define AFE_CONN047_2 (0x2668) -+#define AFE_CONN047_3 (0x266c) -+#define AFE_CONN047_4 (0x2670) -+#define AFE_CONN047_5 (0x2674) -+#define AFE_CONN047_6 (0x2678) -+#define AFE_CONN047_7 (0x267c) -+#define AFE_CONN048_0 (0x2680) -+#define AFE_CONN048_1 (0x2684) -+#define AFE_CONN048_2 (0x2688) -+#define AFE_CONN048_3 (0x268c) -+#define AFE_CONN048_4 (0x2690) -+#define AFE_CONN048_5 (0x2694) -+#define AFE_CONN048_6 (0x2698) -+#define AFE_CONN048_7 (0x269c) -+#define AFE_CONN049_0 (0x26a0) -+#define AFE_CONN049_1 (0x26a4) -+#define AFE_CONN049_2 (0x26a8) -+#define AFE_CONN049_3 (0x26ac) -+#define AFE_CONN049_4 (0x26b0) -+#define AFE_CONN049_5 (0x26b4) -+#define AFE_CONN049_6 (0x26b8) -+#define AFE_CONN049_7 (0x26bc) -+#define AFE_CONN050_0 (0x26c0) -+#define AFE_CONN050_1 (0x26c4) -+#define AFE_CONN050_2 (0x26c8) -+#define AFE_CONN050_3 (0x26cc) -+#define AFE_CONN050_4 (0x26d0) -+#define AFE_CONN050_5 (0x26d4) -+#define AFE_CONN050_6 (0x26d8) -+#define AFE_CONN050_7 (0x26dc) -+#define AFE_CONN051_0 (0x26e0) -+#define AFE_CONN051_1 (0x26e4) -+#define AFE_CONN051_2 (0x26e8) -+#define AFE_CONN051_3 (0x26ec) -+#define AFE_CONN051_4 (0x26f0) -+#define AFE_CONN051_5 (0x26f4) -+#define AFE_CONN051_6 (0x26f8) -+#define AFE_CONN051_7 (0x26fc) -+#define AFE_CONN052_0 (0x2700) -+#define AFE_CONN052_1 (0x2704) -+#define AFE_CONN052_2 (0x2708) -+#define AFE_CONN052_3 (0x270c) -+#define AFE_CONN052_4 (0x2710) -+#define AFE_CONN052_5 (0x2714) -+#define AFE_CONN052_6 (0x2718) -+#define AFE_CONN052_7 (0x271c) -+#define AFE_CONN053_0 (0x2720) -+#define AFE_CONN053_1 (0x2724) -+#define AFE_CONN053_2 (0x2728) -+#define AFE_CONN053_3 (0x272c) -+#define AFE_CONN053_4 (0x2730) -+#define AFE_CONN053_5 (0x2734) -+#define AFE_CONN053_6 (0x2738) -+#define AFE_CONN053_7 (0x273c) -+#define AFE_CONN054_0 (0x2740) -+#define AFE_CONN054_1 (0x2744) -+#define AFE_CONN054_2 (0x2748) -+#define AFE_CONN054_3 (0x274c) -+#define AFE_CONN054_4 (0x2750) -+#define AFE_CONN054_5 (0x2754) -+#define AFE_CONN054_6 (0x2758) -+#define AFE_CONN054_7 (0x275c) -+#define AFE_CONN055_0 (0x2760) -+#define AFE_CONN055_1 (0x2764) -+#define AFE_CONN055_2 (0x2768) -+#define AFE_CONN055_3 (0x276c) -+#define AFE_CONN055_4 (0x2770) -+#define AFE_CONN055_5 (0x2774) -+#define AFE_CONN055_6 (0x2778) -+#define AFE_CONN055_7 (0x277c) -+#define AFE_CONN056_0 (0x2780) -+#define AFE_CONN056_1 (0x2784) -+#define AFE_CONN056_2 (0x2788) -+#define AFE_CONN056_3 (0x278c) -+#define AFE_CONN056_4 (0x2790) -+#define AFE_CONN056_5 (0x2794) -+#define AFE_CONN056_6 (0x2798) -+#define AFE_CONN056_7 (0x279c) -+#define AFE_CONN057_0 (0x27a0) -+#define AFE_CONN057_1 (0x27a4) -+#define AFE_CONN057_2 (0x27a8) -+#define AFE_CONN057_3 (0x27ac) -+#define AFE_CONN057_4 (0x27b0) -+#define AFE_CONN057_5 (0x27b4) -+#define AFE_CONN057_6 (0x27b8) -+#define AFE_CONN057_7 (0x27bc) -+#define AFE_CONN058_0 (0x27c0) -+#define AFE_CONN058_1 (0x27c4) -+#define AFE_CONN058_2 (0x27c8) -+#define AFE_CONN058_3 (0x27cc) -+#define AFE_CONN058_4 (0x27d0) -+#define AFE_CONN058_5 (0x27d4) -+#define AFE_CONN058_6 (0x27d8) -+#define AFE_CONN058_7 (0x27dc) -+#define AFE_CONN059_0 (0x27e0) -+#define AFE_CONN059_1 (0x27e4) -+#define AFE_CONN059_2 (0x27e8) -+#define AFE_CONN059_3 (0x27ec) -+#define AFE_CONN059_4 (0x27f0) -+#define AFE_CONN059_5 (0x27f4) -+#define AFE_CONN059_6 (0x27f8) -+#define AFE_CONN059_7 (0x27fc) -+#define AFE_CONN060_0 (0x2800) -+#define AFE_CONN060_1 (0x2804) -+#define AFE_CONN060_2 (0x2808) -+#define AFE_CONN060_3 (0x280c) -+#define AFE_CONN060_4 (0x2810) -+#define AFE_CONN060_5 (0x2814) -+#define AFE_CONN060_6 (0x2818) -+#define AFE_CONN060_7 (0x281c) -+#define AFE_CONN061_0 (0x2820) -+#define AFE_CONN061_1 (0x2824) -+#define AFE_CONN061_2 (0x2828) -+#define AFE_CONN061_3 (0x282c) -+#define AFE_CONN061_4 (0x2830) -+#define AFE_CONN061_5 (0x2834) -+#define AFE_CONN061_6 (0x2838) -+#define AFE_CONN061_7 (0x283c) -+#define AFE_CONN062_0 (0x2840) -+#define AFE_CONN062_1 (0x2844) -+#define AFE_CONN062_2 (0x2848) -+#define AFE_CONN062_3 (0x284c) -+#define AFE_CONN062_4 (0x2850) -+#define AFE_CONN062_5 (0x2854) -+#define AFE_CONN062_6 (0x2858) -+#define AFE_CONN062_7 (0x285c) -+#define AFE_CONN063_0 (0x2860) -+#define AFE_CONN063_1 (0x2864) -+#define AFE_CONN063_2 (0x2868) -+#define AFE_CONN063_3 (0x286c) -+#define AFE_CONN063_4 (0x2870) -+#define AFE_CONN063_5 (0x2874) -+#define AFE_CONN063_6 (0x2878) -+#define AFE_CONN063_7 (0x287c) -+#define AFE_CONN064_0 (0x2880) -+#define AFE_CONN064_1 (0x2884) -+#define AFE_CONN064_2 (0x2888) -+#define AFE_CONN064_3 (0x288c) -+#define AFE_CONN064_4 (0x2890) -+#define AFE_CONN064_5 (0x2894) -+#define AFE_CONN064_6 (0x2898) -+#define AFE_CONN064_7 (0x289c) -+#define AFE_CONN065_0 (0x28a0) -+#define AFE_CONN065_1 (0x28a4) -+#define AFE_CONN065_2 (0x28a8) -+#define AFE_CONN065_3 (0x28ac) -+#define AFE_CONN065_4 (0x28b0) -+#define AFE_CONN065_5 (0x28b4) -+#define AFE_CONN065_6 (0x28b8) -+#define AFE_CONN065_7 (0x28bc) -+#define AFE_CONN066_0 (0x28c0) -+#define AFE_CONN066_1 (0x28c4) -+#define AFE_CONN066_2 (0x28c8) -+#define AFE_CONN066_3 (0x28cc) -+#define AFE_CONN066_4 (0x28d0) -+#define AFE_CONN066_5 (0x28d4) -+#define AFE_CONN066_6 (0x28d8) -+#define AFE_CONN066_7 (0x28dc) -+#define AFE_CONN067_0 (0x28e0) -+#define AFE_CONN067_1 (0x28e4) -+#define AFE_CONN067_2 (0x28e8) -+#define AFE_CONN067_3 (0x28ec) -+#define AFE_CONN067_4 (0x28f0) -+#define AFE_CONN067_5 (0x28f4) -+#define AFE_CONN067_6 (0x28f8) -+#define AFE_CONN067_7 (0x28fc) -+#define AFE_CONN068_0 (0x2900) -+#define AFE_CONN068_1 (0x2904) -+#define AFE_CONN068_2 (0x2908) -+#define AFE_CONN068_3 (0x290c) -+#define AFE_CONN068_4 (0x2910) -+#define AFE_CONN068_5 (0x2914) -+#define AFE_CONN068_6 (0x2918) -+#define AFE_CONN068_7 (0x291c) -+#define AFE_CONN069_0 (0x2920) -+#define AFE_CONN069_1 (0x2924) -+#define AFE_CONN069_2 (0x2928) -+#define AFE_CONN069_3 (0x292c) -+#define AFE_CONN069_4 (0x2930) -+#define AFE_CONN069_5 (0x2934) -+#define AFE_CONN069_6 (0x2938) -+#define AFE_CONN069_7 (0x293c) -+#define AFE_CONN070_0 (0x2940) -+#define AFE_CONN070_1 (0x2944) -+#define AFE_CONN070_2 (0x2948) -+#define AFE_CONN070_3 (0x294c) -+#define AFE_CONN070_4 (0x2950) -+#define AFE_CONN070_5 (0x2954) -+#define AFE_CONN070_6 (0x2958) -+#define AFE_CONN070_7 (0x295c) -+#define AFE_CONN071_0 (0x2960) -+#define AFE_CONN071_1 (0x2964) -+#define AFE_CONN071_2 (0x2968) -+#define AFE_CONN071_3 (0x296c) -+#define AFE_CONN071_4 (0x2970) -+#define AFE_CONN071_5 (0x2974) -+#define AFE_CONN071_6 (0x2978) -+#define AFE_CONN071_7 (0x297c) -+#define AFE_CONN072_0 (0x2980) -+#define AFE_CONN072_1 (0x2984) -+#define AFE_CONN072_2 (0x2988) -+#define AFE_CONN072_3 (0x298c) -+#define AFE_CONN072_4 (0x2990) -+#define AFE_CONN072_5 (0x2994) -+#define AFE_CONN072_6 (0x2998) -+#define AFE_CONN072_7 (0x299c) -+#define AFE_CONN073_0 (0x29a0) -+#define AFE_CONN073_1 (0x29a4) -+#define AFE_CONN073_2 (0x29a8) -+#define AFE_CONN073_3 (0x29ac) -+#define AFE_CONN073_4 (0x29b0) -+#define AFE_CONN073_5 (0x29b4) -+#define AFE_CONN073_6 (0x29b8) -+#define AFE_CONN073_7 (0x29bc) -+#define AFE_CONN074_0 (0x29c0) -+#define AFE_CONN074_1 (0x29c4) -+#define AFE_CONN074_2 (0x29c8) -+#define AFE_CONN074_3 (0x29cc) -+#define AFE_CONN074_4 (0x29d0) -+#define AFE_CONN074_5 (0x29d4) -+#define AFE_CONN074_6 (0x29d8) -+#define AFE_CONN074_7 (0x29dc) -+#define AFE_CONN075_0 (0x29e0) -+#define AFE_CONN075_1 (0x29e4) -+#define AFE_CONN075_2 (0x29e8) -+#define AFE_CONN075_3 (0x29ec) -+#define AFE_CONN075_4 (0x29f0) -+#define AFE_CONN075_5 (0x29f4) -+#define AFE_CONN075_6 (0x29f8) -+#define AFE_CONN075_7 (0x29fc) -+#define AFE_CONN076_0 (0x2a00) -+#define AFE_CONN076_1 (0x2a04) -+#define AFE_CONN076_2 (0x2a08) -+#define AFE_CONN076_3 (0x2a0c) -+#define AFE_CONN076_4 (0x2a10) -+#define AFE_CONN076_5 (0x2a14) -+#define AFE_CONN076_6 (0x2a18) -+#define AFE_CONN076_7 (0x2a1c) -+#define AFE_CONN077_0 (0x2a20) -+#define AFE_CONN077_1 (0x2a24) -+#define AFE_CONN077_2 (0x2a28) -+#define AFE_CONN077_3 (0x2a2c) -+#define AFE_CONN077_4 (0x2a30) -+#define AFE_CONN077_5 (0x2a34) -+#define AFE_CONN077_6 (0x2a38) -+#define AFE_CONN077_7 (0x2a3c) -+#define AFE_CONN078_0 (0x2a40) -+#define AFE_CONN078_1 (0x2a44) -+#define AFE_CONN078_2 (0x2a48) -+#define AFE_CONN078_3 (0x2a4c) -+#define AFE_CONN078_4 (0x2a50) -+#define AFE_CONN078_5 (0x2a54) -+#define AFE_CONN078_6 (0x2a58) -+#define AFE_CONN078_7 (0x2a5c) -+#define AFE_CONN079_0 (0x2a60) -+#define AFE_CONN079_1 (0x2a64) -+#define AFE_CONN079_2 (0x2a68) -+#define AFE_CONN079_3 (0x2a6c) -+#define AFE_CONN079_4 (0x2a70) -+#define AFE_CONN079_5 (0x2a74) -+#define AFE_CONN079_6 (0x2a78) -+#define AFE_CONN079_7 (0x2a7c) -+#define AFE_CONN080_0 (0x2a80) -+#define AFE_CONN080_1 (0x2a84) -+#define AFE_CONN080_2 (0x2a88) -+#define AFE_CONN080_3 (0x2a8c) -+#define AFE_CONN080_4 (0x2a90) -+#define AFE_CONN080_5 (0x2a94) -+#define AFE_CONN080_6 (0x2a98) -+#define AFE_CONN080_7 (0x2a9c) -+#define AFE_CONN081_0 (0x2aa0) -+#define AFE_CONN081_1 (0x2aa4) -+#define AFE_CONN081_2 (0x2aa8) -+#define AFE_CONN081_3 (0x2aac) -+#define AFE_CONN081_4 (0x2ab0) -+#define AFE_CONN081_5 (0x2ab4) -+#define AFE_CONN081_6 (0x2ab8) -+#define AFE_CONN081_7 (0x2abc) -+#define AFE_CONN082_0 (0x2ac0) -+#define AFE_CONN082_1 (0x2ac4) -+#define AFE_CONN082_2 (0x2ac8) -+#define AFE_CONN082_3 (0x2acc) -+#define AFE_CONN082_4 (0x2ad0) -+#define AFE_CONN082_5 (0x2ad4) -+#define AFE_CONN082_6 (0x2ad8) -+#define AFE_CONN082_7 (0x2adc) -+#define AFE_CONN083_0 (0x2ae0) -+#define AFE_CONN083_1 (0x2ae4) -+#define AFE_CONN083_2 (0x2ae8) -+#define AFE_CONN083_3 (0x2aec) -+#define AFE_CONN083_4 (0x2af0) -+#define AFE_CONN083_5 (0x2af4) -+#define AFE_CONN083_6 (0x2af8) -+#define AFE_CONN083_7 (0x2afc) -+#define AFE_CONN084_0 (0x2b00) -+#define AFE_CONN084_1 (0x2b04) -+#define AFE_CONN084_2 (0x2b08) -+#define AFE_CONN084_3 (0x2b0c) -+#define AFE_CONN084_4 (0x2b10) -+#define AFE_CONN084_5 (0x2b14) -+#define AFE_CONN084_6 (0x2b18) -+#define AFE_CONN084_7 (0x2b1c) -+#define AFE_CONN085_0 (0x2b20) -+#define AFE_CONN085_1 (0x2b24) -+#define AFE_CONN085_2 (0x2b28) -+#define AFE_CONN085_3 (0x2b2c) -+#define AFE_CONN085_4 (0x2b30) -+#define AFE_CONN085_5 (0x2b34) -+#define AFE_CONN085_6 (0x2b38) -+#define AFE_CONN085_7 (0x2b3c) -+#define AFE_CONN086_0 (0x2b40) -+#define AFE_CONN086_1 (0x2b44) -+#define AFE_CONN086_2 (0x2b48) -+#define AFE_CONN086_3 (0x2b4c) -+#define AFE_CONN086_4 (0x2b50) -+#define AFE_CONN086_5 (0x2b54) -+#define AFE_CONN086_6 (0x2b58) -+#define AFE_CONN086_7 (0x2b5c) -+#define AFE_CONN087_0 (0x2b60) -+#define AFE_CONN087_1 (0x2b64) -+#define AFE_CONN087_2 (0x2b68) -+#define AFE_CONN087_3 (0x2b6c) -+#define AFE_CONN087_4 (0x2b70) -+#define AFE_CONN087_5 (0x2b74) -+#define AFE_CONN087_6 (0x2b78) -+#define AFE_CONN087_7 (0x2b7c) -+#define AFE_CONN088_0 (0x2b80) -+#define AFE_CONN088_1 (0x2b84) -+#define AFE_CONN088_2 (0x2b88) -+#define AFE_CONN088_3 (0x2b8c) -+#define AFE_CONN088_4 (0x2b90) -+#define AFE_CONN088_5 (0x2b94) -+#define AFE_CONN088_6 (0x2b98) -+#define AFE_CONN088_7 (0x2b9c) -+#define AFE_CONN089_0 (0x2ba0) -+#define AFE_CONN089_1 (0x2ba4) -+#define AFE_CONN089_2 (0x2ba8) -+#define AFE_CONN089_3 (0x2bac) -+#define AFE_CONN089_4 (0x2bb0) -+#define AFE_CONN089_5 (0x2bb4) -+#define AFE_CONN089_6 (0x2bb8) -+#define AFE_CONN089_7 (0x2bbc) -+#define AFE_CONN090_0 (0x2bc0) -+#define AFE_CONN090_1 (0x2bc4) -+#define AFE_CONN090_2 (0x2bc8) -+#define AFE_CONN090_3 (0x2bcc) -+#define AFE_CONN090_4 (0x2bd0) -+#define AFE_CONN090_5 (0x2bd4) -+#define AFE_CONN090_6 (0x2bd8) -+#define AFE_CONN090_7 (0x2bdc) -+#define AFE_CONN091_0 (0x2be0) -+#define AFE_CONN091_1 (0x2be4) -+#define AFE_CONN091_2 (0x2be8) -+#define AFE_CONN091_3 (0x2bec) -+#define AFE_CONN091_4 (0x2bf0) -+#define AFE_CONN091_5 (0x2bf4) -+#define AFE_CONN091_6 (0x2bf8) -+#define AFE_CONN091_7 (0x2bfc) -+#define AFE_CONN092_0 (0x2c00) -+#define AFE_CONN092_1 (0x2c04) -+#define AFE_CONN092_2 (0x2c08) -+#define AFE_CONN092_3 (0x2c0c) -+#define AFE_CONN092_4 (0x2c10) -+#define AFE_CONN092_5 (0x2c14) -+#define AFE_CONN092_6 (0x2c18) -+#define AFE_CONN092_7 (0x2c1c) -+#define AFE_CONN093_0 (0x2c20) -+#define AFE_CONN093_1 (0x2c24) -+#define AFE_CONN093_2 (0x2c28) -+#define AFE_CONN093_3 (0x2c2c) -+#define AFE_CONN093_4 (0x2c30) -+#define AFE_CONN093_5 (0x2c34) -+#define AFE_CONN093_6 (0x2c38) -+#define AFE_CONN093_7 (0x2c3c) -+#define AFE_CONN094_0 (0x2c40) -+#define AFE_CONN094_1 (0x2c44) -+#define AFE_CONN094_2 (0x2c48) -+#define AFE_CONN094_3 (0x2c4c) -+#define AFE_CONN094_4 (0x2c50) -+#define AFE_CONN094_5 (0x2c54) -+#define AFE_CONN094_6 (0x2c58) -+#define AFE_CONN094_7 (0x2c5c) -+#define AFE_CONN095_0 (0x2c60) -+#define AFE_CONN095_1 (0x2c64) -+#define AFE_CONN095_2 (0x2c68) -+#define AFE_CONN095_3 (0x2c6c) -+#define AFE_CONN095_4 (0x2c70) -+#define AFE_CONN095_5 (0x2c74) -+#define AFE_CONN095_6 (0x2c78) -+#define AFE_CONN095_7 (0x2c7c) -+#define AFE_CONN108_0 (0x2e00) -+#define AFE_CONN108_1 (0x2e04) -+#define AFE_CONN108_2 (0x2e08) -+#define AFE_CONN108_3 (0x2e0c) -+#define AFE_CONN108_4 (0x2e10) -+#define AFE_CONN108_5 (0x2e14) -+#define AFE_CONN108_6 (0x2e18) -+#define AFE_CONN108_7 (0x2e1c) -+#define AFE_CONN109_0 (0x2e20) -+#define AFE_CONN109_1 (0x2e24) -+#define AFE_CONN109_2 (0x2e28) -+#define AFE_CONN109_3 (0x2e2c) -+#define AFE_CONN109_4 (0x2e30) -+#define AFE_CONN109_5 (0x2e34) -+#define AFE_CONN109_6 (0x2e38) -+#define AFE_CONN109_7 (0x2e3c) -+#define AFE_CONN124_0 (0x3000) -+#define AFE_CONN124_1 (0x3004) -+#define AFE_CONN124_2 (0x3008) -+#define AFE_CONN124_3 (0x300c) -+#define AFE_CONN124_4 (0x3010) -+#define AFE_CONN124_5 (0x3014) -+#define AFE_CONN124_6 (0x3018) -+#define AFE_CONN124_7 (0x301c) -+#define AFE_CONN125_0 (0x3020) -+#define AFE_CONN125_1 (0x3024) -+#define AFE_CONN125_2 (0x3028) -+#define AFE_CONN125_3 (0x302c) -+#define AFE_CONN125_4 (0x3030) -+#define AFE_CONN125_5 (0x3034) -+#define AFE_CONN125_6 (0x3038) -+#define AFE_CONN125_7 (0x303c) -+#define AFE_CONN126_0 (0x3040) -+#define AFE_CONN126_1 (0x3044) -+#define AFE_CONN126_2 (0x3048) -+#define AFE_CONN126_3 (0x304c) -+#define AFE_CONN126_4 (0x3050) -+#define AFE_CONN126_5 (0x3054) -+#define AFE_CONN126_6 (0x3058) -+#define AFE_CONN126_7 (0x305c) -+#define AFE_CONN127_0 (0x3060) -+#define AFE_CONN127_1 (0x3064) -+#define AFE_CONN127_2 (0x3068) -+#define AFE_CONN127_3 (0x306c) -+#define AFE_CONN127_4 (0x3070) -+#define AFE_CONN127_5 (0x3074) -+#define AFE_CONN127_6 (0x3078) -+#define AFE_CONN127_7 (0x307c) -+#define AFE_CONN128_0 (0x3080) -+#define AFE_CONN128_1 (0x3084) -+#define AFE_CONN128_2 (0x3088) -+#define AFE_CONN128_3 (0x308c) -+#define AFE_CONN128_4 (0x3090) -+#define AFE_CONN128_5 (0x3094) -+#define AFE_CONN128_6 (0x3098) -+#define AFE_CONN128_7 (0x309c) -+#define AFE_CONN129_0 (0x30a0) -+#define AFE_CONN129_1 (0x30a4) -+#define AFE_CONN129_2 (0x30a8) -+#define AFE_CONN129_3 (0x30ac) -+#define AFE_CONN129_4 (0x30b0) -+#define AFE_CONN129_5 (0x30b4) -+#define AFE_CONN129_6 (0x30b8) -+#define AFE_CONN129_7 (0x30bc) -+#define AFE_CONN130_0 (0x30c0) -+#define AFE_CONN130_1 (0x30c4) -+#define AFE_CONN130_2 (0x30c8) -+#define AFE_CONN130_3 (0x30cc) -+#define AFE_CONN130_4 (0x30d0) -+#define AFE_CONN130_5 (0x30d4) -+#define AFE_CONN130_6 (0x30d8) -+#define AFE_CONN130_7 (0x30dc) -+#define AFE_CONN131_0 (0x30e0) -+#define AFE_CONN131_1 (0x30e4) -+#define AFE_CONN131_2 (0x30e8) -+#define AFE_CONN131_3 (0x30ec) -+#define AFE_CONN131_4 (0x30f0) -+#define AFE_CONN131_5 (0x30f4) -+#define AFE_CONN131_6 (0x30f8) -+#define AFE_CONN131_7 (0x30fc) -+#define AFE_CONN148_0 (0x3300) -+#define AFE_CONN148_1 (0x3304) -+#define AFE_CONN148_2 (0x3308) -+#define AFE_CONN148_3 (0x330c) -+#define AFE_CONN148_4 (0x3310) -+#define AFE_CONN148_5 (0x3314) -+#define AFE_CONN148_6 (0x3318) -+#define AFE_CONN148_7 (0x331c) -+#define AFE_CONN149_0 (0x3320) -+#define AFE_CONN149_1 (0x3324) -+#define AFE_CONN149_2 (0x3328) -+#define AFE_CONN149_3 (0x332c) -+#define AFE_CONN149_4 (0x3330) -+#define AFE_CONN149_5 (0x3334) -+#define AFE_CONN149_6 (0x3338) -+#define AFE_CONN149_7 (0x333c) -+#define AFE_CONN150_0 (0x3340) -+#define AFE_CONN150_1 (0x3344) -+#define AFE_CONN150_2 (0x3348) -+#define AFE_CONN150_3 (0x334c) -+#define AFE_CONN150_4 (0x3350) -+#define AFE_CONN150_5 (0x3354) -+#define AFE_CONN150_6 (0x3358) -+#define AFE_CONN150_7 (0x335c) -+#define AFE_CONN151_0 (0x3360) -+#define AFE_CONN151_1 (0x3364) -+#define AFE_CONN151_2 (0x3368) -+#define AFE_CONN151_3 (0x336c) -+#define AFE_CONN151_4 (0x3370) -+#define AFE_CONN151_5 (0x3374) -+#define AFE_CONN151_6 (0x3378) -+#define AFE_CONN151_7 (0x337c) -+#define AFE_CONN152_0 (0x3380) -+#define AFE_CONN152_1 (0x3384) -+#define AFE_CONN152_2 (0x3388) -+#define AFE_CONN152_3 (0x338c) -+#define AFE_CONN152_4 (0x3390) -+#define AFE_CONN152_5 (0x3394) -+#define AFE_CONN152_6 (0x3398) -+#define AFE_CONN152_7 (0x339c) -+#define AFE_CONN153_0 (0x33a0) -+#define AFE_CONN153_1 (0x33a4) -+#define AFE_CONN153_2 (0x33a8) -+#define AFE_CONN153_3 (0x33ac) -+#define AFE_CONN153_4 (0x33b0) -+#define AFE_CONN153_5 (0x33b4) -+#define AFE_CONN153_6 (0x33b8) -+#define AFE_CONN153_7 (0x33bc) -+#define AFE_CONN154_0 (0x33c0) -+#define AFE_CONN154_1 (0x33c4) -+#define AFE_CONN154_2 (0x33c8) -+#define AFE_CONN154_3 (0x33cc) -+#define AFE_CONN154_4 (0x33d0) -+#define AFE_CONN154_5 (0x33d4) -+#define AFE_CONN154_6 (0x33d8) -+#define AFE_CONN154_7 (0x33dc) -+#define AFE_CONN155_0 (0x33e0) -+#define AFE_CONN155_1 (0x33e4) -+#define AFE_CONN155_2 (0x33e8) -+#define AFE_CONN155_3 (0x33ec) -+#define AFE_CONN155_4 (0x33f0) -+#define AFE_CONN155_5 (0x33f4) -+#define AFE_CONN155_6 (0x33f8) -+#define AFE_CONN155_7 (0x33fc) -+#define AFE_CONN156_0 (0x3400) -+#define AFE_CONN156_1 (0x3404) -+#define AFE_CONN156_2 (0x3408) -+#define AFE_CONN156_3 (0x340c) -+#define AFE_CONN156_4 (0x3410) -+#define AFE_CONN156_5 (0x3414) -+#define AFE_CONN156_6 (0x3418) -+#define AFE_CONN156_7 (0x341c) -+#define AFE_CONN157_0 (0x3420) -+#define AFE_CONN157_1 (0x3424) -+#define AFE_CONN157_2 (0x3428) -+#define AFE_CONN157_3 (0x342c) -+#define AFE_CONN157_4 (0x3430) -+#define AFE_CONN157_5 (0x3434) -+#define AFE_CONN157_6 (0x3438) -+#define AFE_CONN157_7 (0x343c) -+#define AFE_CONN158_0 (0x3440) -+#define AFE_CONN158_1 (0x3444) -+#define AFE_CONN158_2 (0x3448) -+#define AFE_CONN158_3 (0x344c) -+#define AFE_CONN158_4 (0x3450) -+#define AFE_CONN158_5 (0x3454) -+#define AFE_CONN158_6 (0x3458) -+#define AFE_CONN158_7 (0x345c) -+#define AFE_CONN159_0 (0x3460) -+#define AFE_CONN159_1 (0x3464) -+#define AFE_CONN159_2 (0x3468) -+#define AFE_CONN159_3 (0x346c) -+#define AFE_CONN159_4 (0x3470) -+#define AFE_CONN159_5 (0x3474) -+#define AFE_CONN159_6 (0x3478) -+#define AFE_CONN159_7 (0x347c) -+#define AFE_CONN160_0 (0x3480) -+#define AFE_CONN160_1 (0x3484) -+#define AFE_CONN160_2 (0x3488) -+#define AFE_CONN160_3 (0x348c) -+#define AFE_CONN160_4 (0x3490) -+#define AFE_CONN160_5 (0x3494) -+#define AFE_CONN160_6 (0x3498) -+#define AFE_CONN160_7 (0x349c) -+#define AFE_CONN161_0 (0x34a0) -+#define AFE_CONN161_1 (0x34a4) -+#define AFE_CONN161_2 (0x34a8) -+#define AFE_CONN161_3 (0x34ac) -+#define AFE_CONN161_4 (0x34b0) -+#define AFE_CONN161_5 (0x34b4) -+#define AFE_CONN161_6 (0x34b8) -+#define AFE_CONN161_7 (0x34bc) -+#define AFE_CONN180_0 (0x3700) -+#define AFE_CONN180_1 (0x3704) -+#define AFE_CONN180_2 (0x3708) -+#define AFE_CONN180_3 (0x370c) -+#define AFE_CONN180_4 (0x3710) -+#define AFE_CONN180_5 (0x3714) -+#define AFE_CONN180_6 (0x3718) -+#define AFE_CONN180_7 (0x371c) -+#define AFE_CONN181_0 (0x3720) -+#define AFE_CONN181_1 (0x3724) -+#define AFE_CONN181_2 (0x3728) -+#define AFE_CONN181_3 (0x372c) -+#define AFE_CONN181_4 (0x3730) -+#define AFE_CONN181_5 (0x3734) -+#define AFE_CONN181_6 (0x3738) -+#define AFE_CONN181_7 (0x373c) -+#define AFE_CONN182_0 (0x3740) -+#define AFE_CONN182_1 (0x3744) -+#define AFE_CONN182_2 (0x3748) -+#define AFE_CONN182_3 (0x374c) -+#define AFE_CONN182_4 (0x3750) -+#define AFE_CONN182_5 (0x3754) -+#define AFE_CONN182_6 (0x3758) -+#define AFE_CONN182_7 (0x375c) -+#define AFE_CONN183_0 (0x3760) -+#define AFE_CONN183_1 (0x3764) -+#define AFE_CONN183_2 (0x3768) -+#define AFE_CONN183_3 (0x376c) -+#define AFE_CONN183_4 (0x3770) -+#define AFE_CONN183_5 (0x3774) -+#define AFE_CONN183_6 (0x3778) -+#define AFE_CONN183_7 (0x377c) -+#define AFE_CONN184_0 (0x3780) -+#define AFE_CONN184_1 (0x3784) -+#define AFE_CONN184_2 (0x3788) -+#define AFE_CONN184_3 (0x378c) -+#define AFE_CONN184_4 (0x3790) -+#define AFE_CONN184_5 (0x3794) -+#define AFE_CONN184_6 (0x3798) -+#define AFE_CONN184_7 (0x379c) -+#define AFE_CONN185_0 (0x37a0) -+#define AFE_CONN185_1 (0x37a4) -+#define AFE_CONN185_2 (0x37a8) -+#define AFE_CONN185_3 (0x37ac) -+#define AFE_CONN185_4 (0x37b0) -+#define AFE_CONN185_5 (0x37b4) -+#define AFE_CONN185_6 (0x37b8) -+#define AFE_CONN185_7 (0x37bc) -+#define AFE_CONN186_0 (0x37c0) -+#define AFE_CONN186_1 (0x37c4) -+#define AFE_CONN186_2 (0x37c8) -+#define AFE_CONN186_3 (0x37cc) -+#define AFE_CONN186_4 (0x37d0) -+#define AFE_CONN186_5 (0x37d4) -+#define AFE_CONN186_6 (0x37d8) -+#define AFE_CONN186_7 (0x37dc) -+#define AFE_CONN187_0 (0x37e0) -+#define AFE_CONN187_1 (0x37e4) -+#define AFE_CONN187_2 (0x37e8) -+#define AFE_CONN187_3 (0x37ec) -+#define AFE_CONN187_4 (0x37f0) -+#define AFE_CONN187_5 (0x37f4) -+#define AFE_CONN187_6 (0x37f8) -+#define AFE_CONN187_7 (0x37fc) -+#define AFE_CONN188_0 (0x3800) -+#define AFE_CONN188_1 (0x3804) -+#define AFE_CONN188_2 (0x3808) -+#define AFE_CONN188_3 (0x380c) -+#define AFE_CONN188_4 (0x3810) -+#define AFE_CONN188_5 (0x3814) -+#define AFE_CONN188_6 (0x3818) -+#define AFE_CONN188_7 (0x381c) -+#define AFE_CONN189_0 (0x3820) -+#define AFE_CONN189_1 (0x3824) -+#define AFE_CONN189_2 (0x3828) -+#define AFE_CONN189_3 (0x382c) -+#define AFE_CONN189_4 (0x3830) -+#define AFE_CONN189_5 (0x3834) -+#define AFE_CONN189_6 (0x3838) -+#define AFE_CONN189_7 (0x383c) -+#define AFE_CONN190_0 (0x3840) -+#define AFE_CONN190_1 (0x3844) -+#define AFE_CONN190_2 (0x3848) -+#define AFE_CONN190_3 (0x384c) -+#define AFE_CONN190_4 (0x3850) -+#define AFE_CONN190_5 (0x3854) -+#define AFE_CONN190_6 (0x3858) -+#define AFE_CONN190_7 (0x385c) -+#define AFE_CONN191_0 (0x3860) -+#define AFE_CONN191_1 (0x3864) -+#define AFE_CONN191_2 (0x3868) -+#define AFE_CONN191_3 (0x386c) -+#define AFE_CONN191_4 (0x3870) -+#define AFE_CONN191_5 (0x3874) -+#define AFE_CONN191_6 (0x3878) -+#define AFE_CONN191_7 (0x387c) -+#define AFE_CONN192_0 (0x3880) -+#define AFE_CONN192_1 (0x3884) -+#define AFE_CONN192_2 (0x3888) -+#define AFE_CONN192_3 (0x388c) -+#define AFE_CONN192_4 (0x3890) -+#define AFE_CONN192_5 (0x3894) -+#define AFE_CONN192_6 (0x3898) -+#define AFE_CONN192_7 (0x389c) -+#define AFE_CONN193_0 (0x38a0) -+#define AFE_CONN193_1 (0x38a4) -+#define AFE_CONN193_2 (0x38a8) -+#define AFE_CONN193_3 (0x38ac) -+#define AFE_CONN193_4 (0x38b0) -+#define AFE_CONN193_5 (0x38b4) -+#define AFE_CONN193_6 (0x38b8) -+#define AFE_CONN193_7 (0x38bc) -+#define AFE_CONN194_0 (0x38c0) -+#define AFE_CONN194_1 (0x38c4) -+#define AFE_CONN194_2 (0x38c8) -+#define AFE_CONN194_3 (0x38cc) -+#define AFE_CONN194_4 (0x38d0) -+#define AFE_CONN194_5 (0x38d4) -+#define AFE_CONN194_6 (0x38d8) -+#define AFE_CONN194_7 (0x38dc) -+#define AFE_CONN195_0 (0x38e0) -+#define AFE_CONN195_1 (0x38e4) -+#define AFE_CONN195_2 (0x38e8) -+#define AFE_CONN195_3 (0x38ec) -+#define AFE_CONN195_4 (0x38f0) -+#define AFE_CONN195_5 (0x38f4) -+#define AFE_CONN195_6 (0x38f8) -+#define AFE_CONN195_7 (0x38fc) -+#define AFE_MEMIF_CON0 (0x4400) -+#define AFE_MEMIF_ONE_HEART (0x4420) -+#define AFE_DL0_BASE_MSB (0x4440) -+#define AFE_DL0_BASE (0x4444) -+#define AFE_DL0_CUR_MSB (0x4448) -+#define AFE_DL0_CUR (0x444c) -+#define AFE_DL0_END_MSB (0x4450) -+#define AFE_DL0_END (0x4454) -+#define AFE_DL0_RCH_MON (0x4458) -+#define AFE_DL0_LCH_MON (0x445c) -+#define AFE_DL0_CON0 (0x4460) -+#define AFE_DL0_MON0 (0x4464) -+#define AFE_DL0_MEM_UP_MSB (0x4468) -+#define AFE_DL0_MEM_UP (0x446c) -+#define AFE_DL1_BASE_MSB (0x4470) -+#define AFE_DL1_BASE (0x4474) -+#define AFE_DL1_CUR_MSB (0x4478) -+#define AFE_DL1_CUR (0x447c) -+#define AFE_DL1_END_MSB (0x4480) -+#define AFE_DL1_END (0x4484) -+#define AFE_DL1_RCH_MON (0x4488) -+#define AFE_DL1_LCH_MON (0x448c) -+#define AFE_DL1_CON0 (0x4490) -+#define AFE_DL1_MON0 (0x4494) -+#define AFE_DL1_MEM_UP_MSB (0x4498) -+#define AFE_DL1_MEM_UP (0x449c) -+#define AFE_DL2_BASE_MSB (0x44a0) -+#define AFE_DL2_BASE (0x44a4) -+#define AFE_DL2_CUR_MSB (0x44a8) -+#define AFE_DL2_CUR (0x44ac) -+#define AFE_DL2_END_MSB (0x44b0) -+#define AFE_DL2_END (0x44b4) -+#define AFE_DL2_RCH_MON (0x44b8) -+#define AFE_DL2_LCH_MON (0x44bc) -+#define AFE_DL2_CON0 (0x44c0) -+#define AFE_DL2_MON0 (0x44c4) -+#define AFE_DL2_MEM_UP_MSB (0x44c8) -+#define AFE_DL2_MEM_UP (0x44cc) -+#define AFE_DL3_BASE_MSB (0x44d0) -+#define AFE_DL3_BASE (0x44d4) -+#define AFE_DL3_CUR_MSB (0x44d8) -+#define AFE_DL3_CUR (0x44dc) -+#define AFE_DL3_END_MSB (0x44e0) -+#define AFE_DL3_END (0x44e4) -+#define AFE_DL3_RCH_MON (0x44e8) -+#define AFE_DL3_LCH_MON (0x44ec) -+#define AFE_DL3_CON0 (0x44f0) -+#define AFE_DL3_MON0 (0x44f4) -+#define AFE_DL3_MEM_UP_MSB (0x44f8) -+#define AFE_DL3_MEM_UP (0x44fc) -+#define AFE_DL4_BASE_MSB (0x4500) -+#define AFE_DL4_BASE (0x4504) -+#define AFE_DL4_CUR_MSB (0x4508) -+#define AFE_DL4_CUR (0x450c) -+#define AFE_DL4_END_MSB (0x4510) -+#define AFE_DL4_END (0x4514) -+#define AFE_DL4_RCH_MON (0x4518) -+#define AFE_DL4_LCH_MON (0x451c) -+#define AFE_DL4_CON0 (0x4520) -+#define AFE_DL4_MON0 (0x4524) -+#define AFE_DL4_MEM_UP_MSB (0x4528) -+#define AFE_DL4_MEM_UP (0x452c) -+#define AFE_DL5_BASE_MSB (0x4530) -+#define AFE_DL5_BASE (0x4534) -+#define AFE_DL5_CUR_MSB (0x4538) -+#define AFE_DL5_CUR (0x453c) -+#define AFE_DL5_END_MSB (0x4540) -+#define AFE_DL5_END (0x4544) -+#define AFE_DL5_RCH_MON (0x4548) -+#define AFE_DL5_LCH_MON (0x454c) -+#define AFE_DL5_CON0 (0x4550) -+#define AFE_DL5_MON0 (0x4554) -+#define AFE_DL5_MEM_UP_MSB (0x4558) -+#define AFE_DL5_MEM_UP (0x455c) -+#define AFE_DL_24CH_BASE_MSB (0x4620) -+#define AFE_DL_24CH_BASE (0x4624) -+#define AFE_DL_24CH_CUR_MSB (0x4628) -+#define AFE_DL_24CH_CUR (0x462c) -+#define AFE_DL_24CH_END_MSB (0x4630) -+#define AFE_DL_24CH_END (0x4634) -+#define AFE_DL_24CH_CON0 (0x4640) -+#define AFE_DL_24CH_MON0 (0x4644) -+#define AFE_DL_24CH_MEM_UP_MSB (0x4648) -+#define AFE_DL_24CH_MEM_UP (0x464c) -+#define AFE_VUL0_BASE_MSB (0x4d60) -+#define AFE_VUL0_BASE (0x4d64) -+#define AFE_VUL0_CUR_MSB (0x4d68) -+#define AFE_VUL0_CUR (0x4d6c) -+#define AFE_VUL0_END_MSB (0x4d70) -+#define AFE_VUL0_END (0x4d74) -+#define AFE_VUL0_RCH_MON (0x4d78) -+#define AFE_VUL0_LCH_MON (0x4d7c) -+#define AFE_VUL0_CON0 (0x4d80) -+#define AFE_VUL0_MON0 (0x4d84) -+#define AFE_VUL1_BASE_MSB (0x4d90) -+#define AFE_VUL1_BASE (0x4d94) -+#define AFE_VUL1_CUR_MSB (0x4d98) -+#define AFE_VUL1_CUR (0x4d9c) -+#define AFE_VUL1_END_MSB (0x4da0) -+#define AFE_VUL1_END (0x4da4) -+#define AFE_VUL1_RCH_MON (0x4da8) -+#define AFE_VUL1_LCH_MON (0x4dac) -+#define AFE_VUL1_CON0 (0x4db0) -+#define AFE_VUL1_MON0 (0x4db4) -+#define AFE_VUL2_BASE_MSB (0x4dc0) -+#define AFE_VUL2_BASE (0x4dc4) -+#define AFE_VUL2_CUR_MSB (0x4dc8) -+#define AFE_VUL2_CUR (0x4dcc) -+#define AFE_VUL2_END_MSB (0x4dd0) -+#define AFE_VUL2_END (0x4dd4) -+#define AFE_VUL2_RCH_MON (0x4dd8) -+#define AFE_VUL2_LCH_MON (0x4ddc) -+#define AFE_VUL2_CON0 (0x4de0) -+#define AFE_VUL2_MON0 (0x4de4) -+#define AFE_VUL3_BASE_MSB (0x4df0) -+#define AFE_VUL3_BASE (0x4df4) -+#define AFE_VUL3_CUR_MSB (0x4df8) -+#define AFE_VUL3_CUR (0x4dfc) -+#define AFE_VUL3_END_MSB (0x4e00) -+#define AFE_VUL3_END (0x4e04) -+#define AFE_VUL3_RCH_MON (0x4e08) -+#define AFE_VUL3_LCH_MON (0x4e0c) -+#define AFE_VUL3_CON0 (0x4e10) -+#define AFE_VUL3_MON0 (0x4e14) -+#define AFE_VUL4_BASE_MSB (0x4e20) -+#define AFE_VUL4_BASE (0x4e24) -+#define AFE_VUL4_CUR_MSB (0x4e28) -+#define AFE_VUL4_CUR (0x4e2c) -+#define AFE_VUL4_END_MSB (0x4e30) -+#define AFE_VUL4_END (0x4e34) -+#define AFE_VUL4_RCH_MON (0x4e38) -+#define AFE_VUL4_LCH_MON (0x4e3c) -+#define AFE_VUL4_CON0 (0x4e40) -+#define AFE_VUL4_MON0 (0x4e44) -+#define AFE_VUL5_BASE_MSB (0x4e50) -+#define AFE_VUL5_BASE (0x4e54) -+#define AFE_VUL5_CUR_MSB (0x4e58) -+#define AFE_VUL5_CUR (0x4e5c) -+#define AFE_VUL5_END_MSB (0x4e60) -+#define AFE_VUL5_END (0x4e64) -+#define AFE_VUL5_RCH_MON (0x4e68) -+#define AFE_VUL5_LCH_MON (0x4e6c) -+#define AFE_VUL5_CON0 (0x4e70) -+#define AFE_VUL5_MON0 (0x4e74) -+#define AFE_VUL8_BASE_MSB (0x4ee0) -+#define AFE_VUL8_BASE (0x4ee4) -+#define AFE_VUL8_CUR_MSB (0x4ee8) -+#define AFE_VUL8_CUR (0x4eec) -+#define AFE_VUL8_END_MSB (0x4ef0) -+#define AFE_VUL8_END (0x4ef4) -+#define AFE_VUL8_RCH_MON (0x4ef8) -+#define AFE_VUL8_LCH_MON (0x4efc) -+#define AFE_VUL8_CON0 (0x4f00) -+#define AFE_VUL8_MON0 (0x4f04) -+#define AFE_VUL9_BASE_MSB (0x4f10) -+#define AFE_VUL9_BASE (0x4f14) -+#define AFE_VUL9_CUR_MSB (0x4f18) -+#define AFE_VUL9_CUR (0x4f1c) -+#define AFE_VUL9_END_MSB (0x4f20) -+#define AFE_VUL9_END (0x4f24) -+#define AFE_VUL9_RCH_MON (0x4f28) -+#define AFE_VUL9_LCH_MON (0x4f2c) -+#define AFE_VUL9_CON0 (0x4f30) -+#define AFE_VUL9_MON0 (0x4f34) -+#define AFE_VUL10_BASE_MSB (0x4f40) -+#define AFE_VUL10_BASE (0x4f44) -+#define AFE_VUL10_CUR_MSB (0x4f48) -+#define AFE_VUL10_CUR (0x4f4c) -+#define AFE_VUL10_END_MSB (0x4f50) -+#define AFE_VUL10_END (0x4f54) -+#define AFE_VUL10_RCH_MON (0x4f58) -+#define AFE_VUL10_LCH_MON (0x4f5c) -+#define AFE_VUL10_CON0 (0x4f60) -+#define AFE_VUL10_MON0 (0x4f64) -+#define AFE_VUL_CM0_BASE_MSB (0x51c0) -+#define AFE_VUL_CM0_BASE (0x51c4) -+#define AFE_VUL_CM0_CUR_MSB (0x51c8) -+#define AFE_VUL_CM0_CUR (0x51cc) -+#define AFE_VUL_CM0_END_MSB (0x51d0) -+#define AFE_VUL_CM0_END (0x51d4) -+#define AFE_VUL_CM0_CON0 (0x51d8) -+#define AFE_VUL_CM1_BASE_MSB (0x51e0) -+#define AFE_VUL_CM1_BASE (0x51e4) -+#define AFE_VUL_CM1_CUR_MSB (0x51e8) -+#define AFE_VUL_CM1_CUR (0x51ec) -+#define AFE_VUL_CM1_END_MSB (0x51f0) -+#define AFE_VUL_CM1_END (0x51f4) -+#define AFE_VUL_CM1_CON0 (0x51f8) -+#define AFE_VUL_CM2_BASE_MSB (0x5200) -+#define AFE_VUL_CM2_BASE (0x5204) -+#define AFE_VUL_CM2_CUR_MSB (0x5208) -+#define AFE_VUL_CM2_CUR (0x520c) -+#define AFE_VUL_CM2_END_MSB (0x5210) -+#define AFE_VUL_CM2_END (0x5214) -+#define AFE_VUL_CM2_CON0 (0x5218) -+#define AFE_GASRC0_NEW_CON0 (0x7840) -+#define AFE_GASRC0_NEW_CON1 (0x7844) -+#define AFE_GASRC0_NEW_CON2 (0x7848) -+#define AFE_GASRC0_NEW_CON3 (0x784c) -+#define AFE_GASRC0_NEW_CON4 (0x7850) -+#define AFE_GASRC0_NEW_CON5 (0x7854) -+#define AFE_GASRC0_NEW_CON6 (0x7858) -+#define AFE_GASRC0_NEW_CON7 (0x785c) -+#define AFE_GASRC0_NEW_CON8 (0x7860) -+#define AFE_GASRC0_NEW_CON9 (0x7864) -+#define AFE_GASRC0_NEW_CON10 (0x7868) -+#define AFE_GASRC0_NEW_CON11 (0x786c) -+#define AFE_GASRC0_NEW_CON12 (0x7870) -+#define AFE_GASRC0_NEW_CON13 (0x7874) -+#define AFE_GASRC0_NEW_CON14 (0x7878) -+#define AFE_GASRC0_NEW_IP_VERSION (0x787c) -+#define AFE_GASRC1_NEW_CON0 (0x7880) -+#define AFE_GASRC1_NEW_CON1 (0x7884) -+#define AFE_GASRC1_NEW_CON2 (0x7888) -+#define AFE_GASRC1_NEW_CON3 (0x788c) -+#define AFE_GASRC1_NEW_CON4 (0x7890) -+#define AFE_GASRC1_NEW_CON5 (0x7894) -+#define AFE_GASRC1_NEW_CON6 (0x7898) -+#define AFE_GASRC1_NEW_CON7 (0x789c) -+#define AFE_GASRC1_NEW_CON8 (0x78a0) -+#define AFE_GASRC1_NEW_CON9 (0x78a4) -+#define AFE_GASRC1_NEW_CON10 (0x78a8) -+#define AFE_GASRC1_NEW_CON11 (0x78ac) -+#define AFE_GASRC1_NEW_CON12 (0x78b0) -+#define AFE_GASRC1_NEW_CON13 (0x78b4) -+#define AFE_GASRC1_NEW_CON14 (0x78b8) -+#define AFE_GASRC1_NEW_IP_VERSION (0x78bc) -+#define AFE_GASRC2_NEW_CON0 (0x78c0) -+#define AFE_GASRC2_NEW_CON1 (0x78c4) -+#define AFE_GASRC2_NEW_CON2 (0x78c8) -+#define AFE_GASRC2_NEW_CON3 (0x78cc) -+#define AFE_GASRC2_NEW_CON4 (0x78d0) -+#define AFE_GASRC2_NEW_CON5 (0x78d4) -+#define AFE_GASRC2_NEW_CON6 (0x78d8) -+#define AFE_GASRC2_NEW_CON7 (0x78dc) -+#define AFE_GASRC2_NEW_CON8 (0x78e0) -+#define AFE_GASRC2_NEW_CON9 (0x78e4) -+#define AFE_GASRC2_NEW_CON10 (0x78e8) -+#define AFE_GASRC2_NEW_CON11 (0x78ec) -+#define AFE_GASRC2_NEW_CON12 (0x78f0) -+#define AFE_GASRC2_NEW_CON13 (0x78f4) -+#define AFE_GASRC2_NEW_CON14 (0x78f8) -+#define AFE_GASRC2_NEW_IP_VERSION (0x78fc) -+#define AFE_GASRC3_NEW_CON0 (0x7900) -+#define AFE_GASRC3_NEW_CON1 (0x7904) -+#define AFE_GASRC3_NEW_CON2 (0x7908) -+#define AFE_GASRC3_NEW_CON3 (0x790c) -+#define AFE_GASRC3_NEW_CON4 (0x7910) -+#define AFE_GASRC3_NEW_CON5 (0x7914) -+#define AFE_GASRC3_NEW_CON6 (0x7918) -+#define AFE_GASRC3_NEW_CON7 (0x791c) -+#define AFE_GASRC3_NEW_CON8 (0x7920) -+#define AFE_GASRC3_NEW_CON9 (0x7924) -+#define AFE_GASRC3_NEW_CON10 (0x7928) -+#define AFE_GASRC3_NEW_CON11 (0x792c) -+#define AFE_GASRC3_NEW_CON12 (0x7930) -+#define AFE_GASRC3_NEW_CON13 (0x7934) -+#define AFE_GASRC3_NEW_CON14 (0x7938) -+#define AFE_GASRC3_NEW_IP_VERSION (0x793c) -+#define AFE_GASRC4_NEW_CON0 (0x7940) -+#define AFE_GASRC4_NEW_CON1 (0x7944) -+#define AFE_GASRC4_NEW_CON2 (0x7948) -+#define AFE_GASRC4_NEW_CON3 (0x794c) -+#define AFE_GASRC4_NEW_CON4 (0x7950) -+#define AFE_GASRC4_NEW_CON5 (0x7954) -+#define AFE_GASRC4_NEW_CON6 (0x7958) -+#define AFE_GASRC4_NEW_CON7 (0x795c) -+#define AFE_GASRC4_NEW_CON8 (0x7960) -+#define AFE_GASRC4_NEW_CON9 (0x7964) -+#define AFE_GASRC4_NEW_CON10 (0x7968) -+#define AFE_GASRC4_NEW_CON11 (0x796c) -+#define AFE_GASRC4_NEW_CON12 (0x7970) -+#define AFE_GASRC4_NEW_CON13 (0x7974) -+#define AFE_GASRC4_NEW_CON14 (0x7978) -+#define AFE_GASRC4_NEW_IP_VERSION (0x797c) -+#define AFE_GASRC5_NEW_CON0 (0x7980) -+#define AFE_GASRC5_NEW_CON1 (0x7984) -+#define AFE_GASRC5_NEW_CON2 (0x7988) -+#define AFE_GASRC5_NEW_CON3 (0x798c) -+#define AFE_GASRC5_NEW_CON4 (0x7990) -+#define AFE_GASRC5_NEW_CON5 (0x7994) -+#define AFE_GASRC5_NEW_CON6 (0x7998) -+#define AFE_GASRC5_NEW_CON7 (0x799c) -+#define AFE_GASRC5_NEW_CON8 (0x79a0) -+#define AFE_GASRC5_NEW_CON9 (0x79a4) -+#define AFE_GASRC5_NEW_CON10 (0x79a8) -+#define AFE_GASRC5_NEW_CON11 (0x79ac) -+#define AFE_GASRC5_NEW_CON12 (0x79b0) -+#define AFE_GASRC5_NEW_CON13 (0x79b4) -+#define AFE_GASRC5_NEW_CON14 (0x79b8) -+#define AFE_GASRC5_NEW_IP_VERSION (0x79bc) -+#define AFE_GASRC6_NEW_CON0 (0x79c0) -+#define AFE_GASRC6_NEW_CON1 (0x79c4) -+#define AFE_GASRC6_NEW_CON2 (0x79c8) -+#define AFE_GASRC6_NEW_CON3 (0x79cc) -+#define AFE_GASRC6_NEW_CON4 (0x79d0) -+#define AFE_GASRC6_NEW_CON5 (0x79d4) -+#define AFE_GASRC6_NEW_CON6 (0x79d8) -+#define AFE_GASRC6_NEW_CON7 (0x79dc) -+#define AFE_GASRC6_NEW_CON8 (0x79e0) -+#define AFE_GASRC6_NEW_CON9 (0x79e4) -+#define AFE_GASRC6_NEW_CON10 (0x79e8) -+#define AFE_GASRC6_NEW_CON11 (0x79ec) -+#define AFE_GASRC6_NEW_CON12 (0x79f0) -+#define AFE_GASRC6_NEW_CON13 (0x79f4) -+#define AFE_GASRC6_NEW_CON14 (0x79f8) -+#define AFE_GASRC6_NEW_IP_VERSION (0x79fc) -+#define AFE_GASRC7_NEW_CON0 (0x7a00) -+#define AFE_GASRC7_NEW_CON1 (0x7a04) -+#define AFE_GASRC7_NEW_CON2 (0x7a08) -+#define AFE_GASRC7_NEW_CON3 (0x7a0c) -+#define AFE_GASRC7_NEW_CON4 (0x7a10) -+#define AFE_GASRC7_NEW_CON5 (0x7a14) -+#define AFE_GASRC7_NEW_CON6 (0x7a18) -+#define AFE_GASRC7_NEW_CON7 (0x7a1c) -+#define AFE_GASRC7_NEW_CON8 (0x7a20) -+#define AFE_GASRC7_NEW_CON9 (0x7a24) -+#define AFE_GASRC7_NEW_CON10 (0x7a28) -+#define AFE_GASRC7_NEW_CON11 (0x7a2c) -+#define AFE_GASRC7_NEW_CON12 (0x7a30) -+#define AFE_GASRC7_NEW_CON13 (0x7a34) -+#define AFE_GASRC7_NEW_CON14 (0x7a38) -+#define AFE_GASRC7_NEW_IP_VERSION (0x7a3c) -+#define AFE_GASRC8_NEW_CON0 (0x7a40) -+#define AFE_GASRC8_NEW_CON1 (0x7a44) -+#define AFE_GASRC8_NEW_CON2 (0x7a48) -+#define AFE_GASRC8_NEW_CON3 (0x7a4c) -+#define AFE_GASRC8_NEW_CON4 (0x7a50) -+#define AFE_GASRC8_NEW_CON5 (0x7a54) -+#define AFE_GASRC8_NEW_CON6 (0x7a58) -+#define AFE_GASRC8_NEW_CON7 (0x7a5c) -+#define AFE_GASRC8_NEW_CON8 (0x7a60) -+#define AFE_GASRC8_NEW_CON9 (0x7a64) -+#define AFE_GASRC8_NEW_CON10 (0x7a68) -+#define AFE_GASRC8_NEW_CON11 (0x7a6c) -+#define AFE_GASRC8_NEW_CON12 (0x7a70) -+#define AFE_GASRC8_NEW_CON13 (0x7a74) -+#define AFE_GASRC8_NEW_CON14 (0x7a78) -+#define AFE_GASRC8_NEW_IP_VERSION (0x7a7c) -+#define AFE_GASRC9_NEW_CON0 (0x7a80) -+#define AFE_GASRC9_NEW_CON1 (0x7a84) -+#define AFE_GASRC9_NEW_CON2 (0x7a88) -+#define AFE_GASRC9_NEW_CON3 (0x7a8c) -+#define AFE_GASRC9_NEW_CON4 (0x7a90) -+#define AFE_GASRC9_NEW_CON5 (0x7a94) -+#define AFE_GASRC9_NEW_CON6 (0x7a98) -+#define AFE_GASRC9_NEW_CON7 (0x7a9c) -+#define AFE_GASRC9_NEW_CON8 (0x7aa0) -+#define AFE_GASRC9_NEW_CON9 (0x7aa4) -+#define AFE_GASRC9_NEW_CON10 (0x7aa8) -+#define AFE_GASRC9_NEW_CON11 (0x7aac) -+#define AFE_GASRC9_NEW_CON12 (0x7ab0) -+#define AFE_GASRC9_NEW_CON13 (0x7ab4) -+#define AFE_GASRC9_NEW_CON14 (0x7ab8) -+#define AFE_GASRC9_NEW_IP_VERSION (0x7abc) -+#define AFE_GASRC10_NEW_CON0 (0x7ac0) -+#define AFE_GASRC10_NEW_CON1 (0x7ac4) -+#define AFE_GASRC10_NEW_CON2 (0x7ac8) -+#define AFE_GASRC10_NEW_CON3 (0x7acc) -+#define AFE_GASRC10_NEW_CON4 (0x7ad0) -+#define AFE_GASRC10_NEW_CON5 (0x7ad4) -+#define AFE_GASRC10_NEW_CON6 (0x7ad8) -+#define AFE_GASRC10_NEW_CON7 (0x7adc) -+#define AFE_GASRC10_NEW_CON8 (0x7ae0) -+#define AFE_GASRC10_NEW_CON9 (0x7ae4) -+#define AFE_GASRC10_NEW_CON10 (0x7ae8) -+#define AFE_GASRC10_NEW_CON11 (0x7aec) -+#define AFE_GASRC10_NEW_CON12 (0x7af0) -+#define AFE_GASRC10_NEW_CON13 (0x7af4) -+#define AFE_GASRC10_NEW_CON14 (0x7af8) -+#define AFE_GASRC10_NEW_IP_VERSION (0x7afc) -+#define AFE_GASRC11_NEW_CON0 (0x7b00) -+#define AFE_GASRC11_NEW_CON1 (0x7b04) -+#define AFE_GASRC11_NEW_CON2 (0x7b08) -+#define AFE_GASRC11_NEW_CON3 (0x7b0c) -+#define AFE_GASRC11_NEW_CON4 (0x7b10) -+#define AFE_GASRC11_NEW_CON5 (0x7b14) -+#define AFE_GASRC11_NEW_CON6 (0x7b18) -+#define AFE_GASRC11_NEW_CON7 (0x7b1c) -+#define AFE_GASRC11_NEW_CON8 (0x7b20) -+#define AFE_GASRC11_NEW_CON9 (0x7b24) -+#define AFE_GASRC11_NEW_CON10 (0x7b28) -+#define AFE_GASRC11_NEW_CON11 (0x7b2c) -+#define AFE_GASRC11_NEW_CON12 (0x7b30) -+#define AFE_GASRC11_NEW_CON13 (0x7b34) -+#define AFE_GASRC11_NEW_CON14 (0x7b38) -+#define AFE_GASRC11_NEW_IP_VERSION (0x7b3c) -+#define AFE_GAIN_DL0_CON0 (0x9800) -+#define AFE_GAIN_DL0_CON1_R (0x9804) -+#define AFE_GAIN_DL0_CON1_L (0x9808) -+#define AFE_GAIN_DL0_CON2 (0x980c) -+#define AFE_GAIN_DL0_CON3 (0x9810) -+#define AFE_GAIN_DL0_CUR_R (0x9814) -+#define AFE_GAIN_DL0_CUR_L (0x9818) -+#define AFE_GAIN_DL1_CON0 (0x981c) -+#define AFE_GAIN_DL1_CON1_R (0x9820) -+#define AFE_GAIN_DL1_CON1_L (0x9824) -+#define AFE_GAIN_DL1_CON2 (0x9828) -+#define AFE_GAIN_DL1_CON3 (0x982c) -+#define AFE_GAIN_DL1_CUR_R (0x9830) -+#define AFE_GAIN_DL1_CUR_L (0x9834) -+#define AFE_GAIN_DL2_CON0 (0x9838) -+#define AFE_GAIN_DL2_CON1_R (0x983c) -+#define AFE_GAIN_DL2_CON1_L (0x9840) -+#define AFE_GAIN_DL2_CON2 (0x9844) -+#define AFE_GAIN_DL2_CON3 (0x9848) -+#define AFE_GAIN_DL2_CUR_R (0x984c) -+#define AFE_GAIN_DL2_CUR_L (0x9850) -+#define AFE_GAIN_DL3_CON0 (0x9854) -+#define AFE_GAIN_DL3_CON1_R (0x9858) -+#define AFE_GAIN_DL3_CON1_L (0x985c) -+#define AFE_GAIN_DL3_CON2 (0x9860) -+#define AFE_GAIN_DL3_CON3 (0x9864) -+#define AFE_GAIN_DL3_CUR_R (0x9868) -+#define AFE_GAIN_DL3_CUR_L (0x986c) -+#define AFE_GAIN_DL4_CON0 (0x9870) -+#define AFE_GAIN_DL4_CON1_R (0x9874) -+#define AFE_GAIN_DL4_CON1_L (0x9878) -+#define AFE_GAIN_DL4_CON2 (0x987c) -+#define AFE_GAIN_DL4_CON3 (0x9880) -+#define AFE_GAIN_DL4_CUR_R (0x9884) -+#define AFE_GAIN_DL4_CUR_L (0x9888) -+#define AFE_GAIN_DL5_CON0 (0x988c) -+#define AFE_GAIN_DL5_CON1_R (0x9890) -+#define AFE_GAIN_DL5_CON1_L (0x9894) -+#define AFE_GAIN_DL5_CON2 (0x9898) -+#define AFE_GAIN_DL5_CON3 (0x989c) -+#define AFE_GAIN_DL5_CUR_R (0x98a0) -+#define AFE_GAIN_DL5_CUR_L (0x98a4) -+#define AFE_GAIN_DL_24CH_CON0 (0x9910) -+#define AFE_GAIN_DL_24CH_CON1 (0x9914) -+#define AFE_GAIN_DL_24CH_CON2 (0x9918) -+#define AFE_GAIN_DL_24CH_CON3 (0x991c) -+#define AFE_GAIN_DL_24CH_CUR (0x9920) -+#define AFE_GAIN_DL_SYNC_CON0 (0x9924) -+#define AFE_GAIN_DL_PAUSE_CON0 (0x9928) -+#define AFE_GAIN_DL_PAUSE_CON1 (0x992c) -+#define AFE_GAIN_VUL_PAUSE_CON0 (0x9930) -+#define AFE_GAIN_DL_BYPASS_CON0 (0x9934) -+#define AFE_GAIN_DL_VUL_WRAP_IP_VERSION (0x9938) -+#define AFE_IRQ_MCU_EN (0x9d00) -+#define AFE_IRQ_MCU_DSP_EN (0x9d04) -+#define AFE_IRQ_MCU_DSP2_EN (0x9d08) -+#define AFE_IRQ_MCU_SCP_EN (0x9d0c) -+#define AFE_CUSTOM_IRQ_MCU_EN (0x9d10) -+#define AFE_CUSTOM_IRQ_MCU_DSP_EN (0x9d14) -+#define AFE_CUSTOM_IRQ_MCU_DSP2_EN (0x9d18) -+#define AFE_CUSTOM_IRQ_MCU_SCP_EN (0x9d1c) -+#define AFE_IRQ_MCU_STATUS (0x9d20) -+#define AFE_CUSTOM_IRQ_MCU_STATUS (0x9d24) -+#define AFE_IRQ0_MCU_CFG0 (0x9d40) -+#define AFE_IRQ0_MCU_CFG1 (0x9d44) -+#define AFE_IRQ1_MCU_CFG0 (0x9d48) -+#define AFE_IRQ1_MCU_CFG1 (0x9d4c) -+#define AFE_IRQ2_MCU_CFG0 (0x9d50) -+#define AFE_IRQ2_MCU_CFG1 (0x9d54) -+#define AFE_IRQ3_MCU_CFG0 (0x9d58) -+#define AFE_IRQ3_MCU_CFG1 (0x9d5c) -+#define AFE_IRQ4_MCU_CFG0 (0x9d60) -+#define AFE_IRQ4_MCU_CFG1 (0x9d64) -+#define AFE_IRQ5_MCU_CFG0 (0x9d68) -+#define AFE_IRQ5_MCU_CFG1 (0x9d6c) -+#define AFE_IRQ6_MCU_CFG0 (0x9d70) -+#define AFE_IRQ6_MCU_CFG1 (0x9d74) -+#define AFE_IRQ7_MCU_CFG0 (0x9d78) -+#define AFE_IRQ7_MCU_CFG1 (0x9d7c) -+#define AFE_IRQ8_MCU_CFG0 (0x9d80) -+#define AFE_IRQ8_MCU_CFG1 (0x9d84) -+#define AFE_IRQ9_MCU_CFG0 (0x9d88) -+#define AFE_IRQ9_MCU_CFG1 (0x9d8c) -+#define AFE_IRQ10_MCU_CFG0 (0x9d90) -+#define AFE_IRQ10_MCU_CFG1 (0x9d94) -+#define AFE_IRQ11_MCU_CFG0 (0x9d98) -+#define AFE_IRQ11_MCU_CFG1 (0x9d9c) -+#define AFE_IRQ12_MCU_CFG0 (0x9da0) -+#define AFE_IRQ12_MCU_CFG1 (0x9da4) -+#define AFE_IRQ13_MCU_CFG0 (0x9da8) -+#define AFE_IRQ13_MCU_CFG1 (0x9dac) -+#define AFE_IRQ14_MCU_CFG0 (0x9db0) -+#define AFE_IRQ14_MCU_CFG1 (0x9db4) -+#define AFE_IRQ15_MCU_CFG0 (0x9db8) -+#define AFE_IRQ15_MCU_CFG1 (0x9dbc) -+#define AFE_IRQ16_MCU_CFG0 (0x9dc0) -+#define AFE_IRQ16_MCU_CFG1 (0x9dc4) -+#define AFE_IRQ17_MCU_CFG0 (0x9dc8) -+#define AFE_IRQ17_MCU_CFG1 (0x9dcc) -+#define AFE_IRQ18_MCU_CFG0 (0x9dd0) -+#define AFE_IRQ18_MCU_CFG1 (0x9dd4) -+#define AFE_IRQ19_MCU_CFG0 (0x9dd8) -+#define AFE_IRQ19_MCU_CFG1 (0x9ddc) -+#define AFE_IRQ20_MCU_CFG0 (0x9de0) -+#define AFE_IRQ20_MCU_CFG1 (0x9de4) -+#define AFE_IRQ21_MCU_CFG0 (0x9de8) -+#define AFE_IRQ21_MCU_CFG1 (0x9dec) -+#define AFE_IRQ22_MCU_CFG0 (0x9df0) -+#define AFE_IRQ22_MCU_CFG1 (0x9df4) -+#define AFE_IRQ23_MCU_CFG0 (0x9df8) -+#define AFE_IRQ23_MCU_CFG1 (0x9dfc) -+#define AFE_IRQ24_MCU_CFG0 (0x9e00) -+#define AFE_IRQ24_MCU_CFG1 (0x9e04) -+#define AFE_IRQ25_MCU_CFG0 (0x9e08) -+#define AFE_IRQ25_MCU_CFG1 (0x9e0c) -+#define AFE_IRQ26_MCU_CFG0 (0x9e10) -+#define AFE_IRQ26_MCU_CFG1 (0x9e14) -+#define AFE_CUSTOM_IRQ22_MCU_CFG0 (0x9ec8) -+#define AFE_CUSTOM_IRQ22_MCU_CFG1 (0x9ecc) -+#define AFE_CUSTOM_IRQ23_MCU_CFG0 (0x9ed0) -+#define AFE_CUSTOM_IRQ23_MCU_CFG1 (0x9ed4) -+#define AFE_IRQ0_CNT_MON (0x9f10) -+#define AFE_IRQ1_CNT_MON (0x9f14) -+#define AFE_IRQ2_CNT_MON (0x9f18) -+#define AFE_IRQ3_CNT_MON (0x9f1c) -+#define AFE_IRQ4_CNT_MON (0x9f20) -+#define AFE_IRQ5_CNT_MON (0x9f24) -+#define AFE_IRQ6_CNT_MON (0x9f28) -+#define AFE_IRQ7_CNT_MON (0x9f2c) -+#define AFE_IRQ8_CNT_MON (0x9f30) -+#define AFE_IRQ9_CNT_MON (0x9f34) -+#define AFE_IRQ10_CNT_MON (0x9f38) -+#define AFE_IRQ11_CNT_MON (0x9f3c) -+#define AFE_IRQ12_CNT_MON (0x9f40) -+#define AFE_IRQ13_CNT_MON (0x9f44) -+#define AFE_IRQ14_CNT_MON (0x9f48) -+#define AFE_IRQ15_CNT_MON (0x9f4c) -+#define AFE_IRQ16_CNT_MON (0x9f50) -+#define AFE_IRQ17_CNT_MON (0x9f54) -+#define AFE_IRQ18_CNT_MON (0x9f58) -+#define AFE_IRQ19_CNT_MON (0x9f5c) -+#define AFE_IRQ20_CNT_MON (0x9f60) -+#define AFE_IRQ21_CNT_MON (0x9f64) -+#define AFE_IRQ22_CNT_MON (0x9f68) -+#define AFE_IRQ23_CNT_MON (0x9f6c) -+#define AFE_IRQ24_CNT_MON (0x9f70) -+#define AFE_IRQ25_CNT_MON (0x9f74) -+#define AFE_IRQ26_CNT_MON (0x9f78) -+#define AFE_IRQ_MCU_DSP3_EN (0xa000) -+#define AFE_CUSTOM_IRQ_MCU_DSP3_EN (0xa004) -+#define AFE_CUSTOM2_IRQ_MCU_EN (0xa008) -+#define AFE_CUSTOM2_IRQ_MCU_DSP_EN (0xa00c) -+#define AFE_CUSTOM2_IRQ_MCU_DSP2_EN (0xa010) -+#define AFE_CUSTOM2_IRQ_MCU_DSP3_EN (0xa014) -+#define AFE_CUSTOM2_IRQ_MCU_SCP_EN (0xa018) -+#define AFE_IRQ_MCU_MON3 (0xa01c) -+#define AFE_IRQ_MCU_MON0 (0xa024) -+#define AFE_IRQ_MCU_MON1 (0xa028) -+#define AFE_IRQ_MCU_MON2 (0xa02c) -+ -+#define AFE_MAX_REGISTER (AFE_IRQ_MCU_MON2) -+ -+#define AUDIO_TOP_FPGA_RG1 (0x76a8) -+ -+#define AFE_SOUNDWIRE_PDI_MON_TX_LR (0x955c) -+#define AFE_SOUNDWIRE_PDI_MON_TX_OUT (0x9560) -+#define AFE_SOUNDWIRE_PDI_MON_INC (0x956c) -+#define AFE_SOUNDWIRE_PDI_MON (0x9570) -+ -+/* AUDIO_TOP_CON0 */ -+#define AUDIO_TOP_CON0_PDN_HW_GAIN01 BIT(21) -+#define AUDIO_TOP_CON0_PDN_HW_GAIN23 BIT(20) -+#define AUDIO_TOP_CON0_PDN_CM0 BIT(18) -+#define AUDIO_TOP_CON0_PDN_CM1 BIT(17) -+#define AUDIO_TOP_CON0_PDN_CM2 BIT(16) -+ -+/* AUDIO_TOP_CON1 */ -+#define AUDIO_TOP_CON1_PDN_HW_GAIN_DL0_DL1 BIT(30) -+#define AUDIO_TOP_CON1_PDN_HW_GAIN_DL2_DL3 BIT(29) -+#define AUDIO_TOP_CON1_PDN_HW_GAIN_DL4_DL5 BIT(28) -+#define AUDIO_TOP_CON1_PDN_HW_GAIN_DL_24CH BIT(24) -+#define AUDIO_TOP_CON1_PDN_UL0_ADC BIT(23) -+#define AUDIO_TOP_CON1_PDN_UL0_TML BIT(22) -+#define AUDIO_TOP_CON1_PDN_UL0_ADC_HIRES BIT(21) -+#define AUDIO_TOP_CON1_PDN_UL0_TML_HIRES BIT(20) -+#define AUDIO_TOP_CON1_PDN_UL1_ADC BIT(19) -+#define AUDIO_TOP_CON1_PDN_UL1_TML BIT(18) -+#define AUDIO_TOP_CON1_PDN_UL1_ADC_HIRES BIT(17) -+#define AUDIO_TOP_CON1_PDN_UL1_TML_HIRES BIT(16) -+ -+/* AUDIO_TOP_CON2 */ -+#define AUDIO_TOP_CON2_PDN_ETDM_OUT0 BIT(21) -+#define AUDIO_TOP_CON2_PDN_ETDM_OUT5 BIT(16) -+#define AUDIO_TOP_CON2_PDN_ETDM_IN0 BIT(13) -+#define AUDIO_TOP_CON2_PDN_ETDM_IN5 BIT(8) -+ -+/* AUDIO_TOP_CON3 */ -+#define AUDIO_TOP_CON3_PDN_GASRC0 BIT(24) -+#define AUDIO_TOP_CON3_PDN_GASRC1 BIT(23) -+#define AUDIO_TOP_CON3_PDN_GASRC2 BIT(22) -+#define AUDIO_TOP_CON3_PDN_GASRC3 BIT(21) -+#define AUDIO_TOP_CON3_PDN_GASRC4 BIT(20) -+#define AUDIO_TOP_CON3_PDN_GASRC5 BIT(19) -+#define AUDIO_TOP_CON3_PDN_GASRC6 BIT(18) -+#define AUDIO_TOP_CON3_PDN_GASRC7 BIT(17) -+ -+/* AUDIO_TOP_CON4 */ -+#define AUDIO_TOP_CON4_PDN_APLL_TUNER1 BIT(13) -+#define AUDIO_TOP_CON4_PDN_APLL_TUNER2 BIT(12) -+#define AUDIO_TOP_CON4_PDN_H208M BIT(4) -+#define AUDIO_TOP_CON4_PDN_APLL2 BIT(3) -+#define AUDIO_TOP_CON4_PDN_APLL1 BIT(2) -+#define AUDIO_TOP_CON4_PDN_F26M BIT(1) -+#define AUDIO_TOP_CON4_PDN_HOPPING BIT(0) -+ -+/* AUDIO_TOP_CON5 */ -+#define AUDIO_TOP_CON5_SOUNDWIRE1 BIT(1) -+#define AUDIO_TOP_CON5_SOUNDWIRE0 BIT(0) -+ -+/* AUDIO_ENGEN_CON0 */ -+#define AUDIO_ENGEN_CON0_ON_APLL2 BIT(3) -+#define AUDIO_ENGEN_CON0_APLL2_MASK BIT(3) -+#define AUDIO_ENGEN_CON0_ON_APLL1 BIT(2) -+#define AUDIO_ENGEN_CON0_APLL1_MASK BIT(2) -+#define AUDIO_ENGEN_CON0_ON_F3P25M BIT(1) -+#define AUDIO_ENGEN_CON0_F3P25M_MASK BIT(1) -+#define AUDIO_ENGEN_CON0_ON_26M BIT(0) -+#define AUDIO_ENGEN_CON0_26M_MASK BIT(0) -+ -+/* AFE_SINEGEN_CON0 */ -+#define SINEGEN_DAC_EN_SET(x) (((x) & 0x1) << 26) -+#define SINEGEN_DAC_EN_MASK BIT(26) -+#define SINEGEN_TIE_SW_CH2_SET(x) (((x) & 0x1) << 25) -+#define SINEGEN_TIE_SW_CH2_MASK BIT(25) -+#define SINEGEN_TIE_SW_CH1_SET(x) (((x) & 0x1) << 24) -+#define SINEGEN_TIE_SW_CH1_MASK BIT(24) -+#define SINEGEN_AMP_DIV_CH2_SET(x) (((x) & 0xf) << 20) -+#define SINEGEN_AMP_DIV_CH2_MASK (0xfUL << 20) -+#define SINEGEN_FREQ_DIV_CH2_SET(x) (((x) & 0x1f) << 12) -+#define SINEGEN_FREQ_DIV_CH2_MASK (0x1fUL << 12) -+#define SINEGEN_AMP_DIV_CH1_SET(x) (((x) & 0xf) << 8) -+#define SINEGEN_AMP_DIV_CH1_MASK (0xfUL << 8) -+#define SINEGEN_FREQ_DIV_CH1_SET(x) (((x) & 0x1f) << 0) -+#define SINEGEN_FREQ_DIV_CH1_MASK (0x1fUL << 0) -+ -+/* AFE_SINEGEN_CON1 */ -+#define SINEGEN_SINE_MODE_SET(x) (((x) & 0x1f) << 12) -+#define SINEGEN_SINE_MODE_MASK (0x1fUL << 12) -+#define SINEGEN_INNER_LPBK_SEL_SET(x) (((x) & 0x1UL) << 8) -+#define SINEGEN_INNER_LPBK_SEL_MASK (0x1UL << 8) -+#define SINEGEN_INNER_LPBK_MODE_SET(x) (((x) & 0xff) << 0) -+#define SINEGEN_INNER_LPBK_MODE_MASK (0xffUL << 0) -+ -+/* AFE_APLLx_TUNER_CFG */ -+#define AUDIO_APLL_TUNER_CFG_ON BIT(0) -+#define AUDIO_APLL_TUNER_CFG_XTAL_SEL_SET(x) (((x) & 0x3) << 1) -+#define AUDIO_APLL_TUNER_CFG_XTAL_SEL_MASK (0x3UL << 1) -+#define AUDIO_APLL_TUNER_CFG_APLL_DIV_SET(x) (((x) & 0xf) << 4) -+#define AUDIO_APLL_TUNER_CFG_APLL_DIV_MASK (0xfUL << 4) -+#define AUDIO_APLL_TUNER_CFG_UPPER_BOUND_SET(x) (((x) & 0xf) << 8) -+#define AUDIO_APLL_TUNER_CFG_UPPER_BOUND_MASK (0xfUL << 8) -+ -+/* AFE_ADDA_ULSRC_PHASE_CLK_CON0 */ -+#define DMIC_CLK_PHASE_SYNC_SET_MODE(x) (((x) & 0x1UL) << 31) -+#define DMIC_CLK_PHASE_SYNC_SET_MASK BIT(31) -+ -+/* AFE_ADDA_ULSRC_PHASE_CLK_CON1 */ -+#define UL1_PHASE_SYNC_HCLK_SET_MODE(x) (((x) & 0x1) << 19) -+#define UL1_PHASE_SYNC_HCLK_SET_MASK BIT(19) -+#define UL1_PHASE_SYNC_FCLK_SET_MODE(x) (((x) & 0x1) << 18) -+#define UL1_PHASE_SYNC_FCLK_SET_MASK BIT(18) -+#define UL0_PHASE_SYNC_HCLK_SET_MODE(x) (((x) & 0x1) << 17) -+#define UL0_PHASE_SYNC_HCLK_SET_MASK BIT(17) -+#define UL0_PHASE_SYNC_FCLK_SET_MODE(x) (((x) & 0x1) << 16) -+#define UL0_PHASE_SYNC_FCLK_SET_MASK BIT(16) -+ -+/* AFE_ADDA_ULSRC_PHASE_ENGEN_CON0 */ -+#define UL_PHASE_SYNC_HCLK_1X_EN_3_ON_SET(x) (((x) & 0x1) << 11) -+#define UL_PHASE_SYNC_HCLK_1X_EN_3_ON_MASK BIT(11) -+#define UL_PHASE_SYNC_HCLK_1X_EN_2_ON_SET(x) (((x) & 0x1) << 10) -+#define UL_PHASE_SYNC_HCLK_1X_EN_2_ON_MASK BIT(10) -+#define UL_PHASE_SYNC_HCLK_1X_EN_1_ON_SET(x) (((x) & 0x1) << 9) -+#define UL_PHASE_SYNC_HCLK_1X_EN_1_ON_MASK BIT(9) -+#define UL_PHASE_SYNC_HCLK_1X_EN_0_ON_SET(x) (((x) & 0x1) << 8) -+#define UL_PHASE_SYNC_HCLK_1X_EN_0_ON_MASK BIT(8) -+#define UL_PHASE_SYNC_FCLK_1X_EN_3_ON_SET(x) (((x) & 0x1) << 7) -+#define UL_PHASE_SYNC_FCLK_1X_EN_3_ON_MASK BIT(7) -+#define UL_PHASE_SYNC_FCLK_1X_EN_2_ON_SET(x) (((x) & 0x1) << 6) -+#define UL_PHASE_SYNC_FCLK_1X_EN_2_ON_MASK BIT(6) -+#define UL_PHASE_SYNC_FCLK_1X_EN_1_ON_SET(x) (((x) & 0x1) << 5) -+#define UL_PHASE_SYNC_FCLK_1X_EN_1_ON_MASK BIT(5) -+#define UL_PHASE_SYNC_FCLK_1X_EN_0_ON_SET(x) (((x) & 0x1) << 4) -+#define UL_PHASE_SYNC_FCLK_1X_EN_0_ON_MASK BIT(4) -+ -+/* AFE_ADDA_ULSRC_PHASE_ENGEN_CON1 */ -+#define UL1_PHASE_SYNC_1X_EN_SEL(x) (((x) & 0x7) << 11) -+#define UL1_PHASE_SYNC_1X_EN_SEL_MASK (0x7UL << 11) -+#define UL0_PHASE_SYNC_1X_EN_SEL(x) (((x) & 0x7) << 8) -+#define UL0_PHASE_SYNC_1X_EN_SEL_MASK (0x7UL << 8) -+ -+/* ETDM_INx_CON8 */ -+#define ETDM_IN_USE_AFIFO BIT(8) -+#define ETDM_IN_AFIFO_CLOCK(x) ((x) << 5) -+#define ETDM_IN_AFIFO_CLOCK_MASK (0x7UL << 5) -+#define ETDM_IN_AFIFO_MODE(x) (x) -+#define ETDM_IN_AFIFO_MODE_MASK (0x1f) -+ -+/* ETDM_0_3_COWORK_CON0 */ -+#define ETDM_IN0_SYNC_SEL(x) ((x) << 28) -+#define ETDM_IN0_SYNC_SEL_MASK (0xfUL << 28) -+#define ETDM_IN0_SYNC_SEL_SHIFT 28 -+#define ETDM_IN0_SLAVE_SEL(x) ((x) << 24) -+#define ETDM_IN0_SLAVE_SEL_MASK (0xfUL << 24) -+#define ETDM_IN0_SLAVE_SEL_SHIFT 24 -+#define ETDM_OUT0_SLAVE_SEL(x) ((x) << 8) -+#define ETDM_OUT0_SLAVE_SEL_MASK (0xfUL << 8) -+#define ETDM_OUT0_SLAVE_SEL_SHIFT 8 -+#define ETDM_OUT0_SYNC_SEL(x) ((x) << 4) -+#define ETDM_OUT0_SYNC_SEL_MASK (0xfUL << 4) -+#define ETDM_OUT0_SYNC_SEL_SHIFT 4 -+ -+/* ETDM_0_3_COWORK_CON1 */ -+#define ETDM_IN0_SDATA1_15_SEL(x) ((x) << 4) -+#define ETDM_IN0_SDATA1_15_SEL_MASK (0xfUL << 4) -+#define ETDM_IN0_SDATA1_15_SEL_SHIFT 4 -+#define ETDM_IN0_SDATA0_SEL(x) ((x) << 0) -+#define ETDM_IN0_SDATA0_SEL_MASK (0xfUL << 0) -+#define ETDM_IN0_SDATA0_SEL_SHIFT 0 -+ -+/* ETDM_4_7_COWORK_CON0 */ -+#define ETDM_OUT5_SLAVE_SEL(x) ((x) << 20) -+#define ETDM_OUT5_SLAVE_SEL_MASK (0xfUL << 20) -+#define ETDM_OUT5_SLAVE_SEL_SHIFT 20 -+#define ETDM_OUT5_SYNC_SEL(x) ((x) << 16) -+#define ETDM_OUT5_SYNC_SEL_MASK (0xfUL << 16) -+#define ETDM_OUT5_SYNC_SEL_SHIFT 16 -+ -+/* ETDM_4_7_COWORK_CON1 */ -+#define ETDM_IN5_SYNC_SEL(x) ((x) << 12) -+#define ETDM_IN5_SYNC_SEL_MASK (0xfUL << 12) -+#define ETDM_IN5_SYNC_SEL_SHIFT 12 -+#define ETDM_IN5_SLAVE_SEL(x) ((x) << 8) -+#define ETDM_IN5_SLAVE_SEL_MASK (0xfUL << 8) -+#define ETDM_IN5_SLAVE_SEL_SHIFT 8 -+ -+/* ETDM_x_CONx */ -+#define ETDM_CON0_RELATCH_DOMAIN(x) ((x) << 28) -+#define ETDM_CON0_RELATCH_DOMAIN_MASK (0x7UL << 28) -+#define ETDM_CON0_CH_NUM(x) \ -+ ({ typeof(x) _x = (x); (_x > 0) ? ((_x - 1) << 23) : 0; }) -+#define ETDM_CON0_CH_NUM_MASK (0x1fUL << 23) -+#define ETDM_CON0_WORD_LEN(x) \ -+ ({ typeof(x) _x = (x); (_x > 0) ? ((_x - 1) << 16) : 0; }) -+#define ETDM_CON0_WORD_LEN_MASK (0x1fUL << 16) -+#define ETDM_CON0_BIT_LEN(x) \ -+ ({ typeof(x) _x = (x); (_x > 0) ? ((_x - 1) << 11) : 0; }) -+#define ETDM_CON0_BIT_LEN_MASK (0x1fUL << 11) -+#define ETDM_CON0_FORMAT(x) ((x) << 6) -+#define ETDM_CON0_FORMAT_MASK (0x7UL << 6) -+#define ETDM_CON0_SLAVE_MODE BIT(5) -+#define ETDM_CON0_SYNC_MODE BIT(1) -+#define ETDM_CON0_EN BIT(0) -+ -+#define ETDM_CON1_MCLK_OUTPUT BIT(16) -+#define ETDM_CON1_INITIAL_POINT(x) ((x) << 5) -+#define ETDM_CON1_INITIAL_POINT_MASK (0x1f << 5) -+ -+#define ETDM_IN_CON1_LRCK_AUTO_MODE BIT(31) -+#define ETDM_IN_CON1_LRCK_WIDTH(x) \ -+ ({ typeof(x) _x = (x); (_x > 0) ? ((_x - 1) << 20) : 0; }) -+#define ETDM_IN_CON1_LRCK_WIDTH_MASK (0x3ffUL << 20) -+#define ETDM_OUT_CON1_LRCK_AUTO_MODE BIT(29) -+#define ETDM_OUT_CON1_LRCK_WIDTH(x) \ -+ ({ typeof(x) _x = (x); (_x > 0) ? ((_x - 1) << 19) : 0; }) -+#define ETDM_OUT_CON1_LRCK_WIDTH_MASK (0x3ffUL << 19) -+ -+#define ETDM_CON2_LRCK_DELAY_BCK_INV BIT(30) -+#define ETDM_CON2_LRCK_DELAY_0P5T_EN BIT(29) -+#define ETDM_CON2_SDATA_DELAY_0P5T_EN BIT(27) -+ -+#define ETDM_OUT_CON2_IN2LATCH_TIME_MINUS3(x) (((x) - 3) & 0x1f) -+#define ETDM_OUT_CON2_IN2LATCH_TIME(x) ((x) & 0x1f) -+#define ETDM_OUT_CON2_IN2LATCH_TIME_MASK 0x1f -+ -+#define ETDM_IN_CON1_REG_OUT_EN(x) (((x) & 0x1) << 18) -+#define ETDM_IN_CON1_REG_OUT_EN_MASK BIT(18) -+ -+#define ETDM_IN_CON2_MULTI_IP_2CH_MODE BIT(31) -+#define ETDM_IN_CON2_MULTI_IP_TOTAL_CH(x) \ -+ ({ typeof(x) _x = (x); (_x > 0) ? ((_x - 1) << 15) : 0; }) -+#define ETDM_IN_CON2_MULTI_IP_TOTAL_CH_MASK (0x1fUL << 15) -+#define ETDM_IN_CON2_CLOCK(x) ((x) << 10) -+#define ETDM_IN_CON2_CLOCK_MASK (0x7UL << 10) -+#define ETDM_IN_CON2_CLOCK_SHIFT 10 -+#define ETDM_IN_CON2_UPDATE_GAP(x) ((x) << 5) -+#define ETDM_IN_CON2_UPDATE_GAP_MASK (0x1fUL << 5) -+ -+#define ETDM_IN_CON3_FS(x) ((x) << 26) -+#define ETDM_IN_CON3_FS_MASK (0x1fUL << 26) -+#define ETDM_IN_CON3_FS_SHIFT 26 -+#define ETDM_IN_CON3_DISABLE_OUT(x) (1UL << ((x) & 0xf)) -+#define ETDM_IN_CON3_DISABLE_OUT_MASK (0xffff) -+ -+#define ETDM_IN_CON4_MASTER_LRCK_INV BIT(19) -+#define ETDM_IN_CON4_MASTER_BCK_INV BIT(18) -+#define ETDM_IN_CON4_SLAVE_LRCK_INV BIT(17) -+#define ETDM_IN_CON4_SLAVE_BCK_INV BIT(16) -+#define ETDM_IN_CON4_RELATCH_EN(x) ((x) << 20) -+#define ETDM_IN_CON4_RELATCH_EN_MASK (0x1fUL << 20) -+ -+#define ETDM_OUT_CON4_RELATCH_EN(x) ((x) << 24) -+#define ETDM_OUT_CON4_RELATCH_EN_MASK (0x1fUL << 24) -+#define ETDM_OUT_CON4_CLOCK(x) ((x) << 6) -+#define ETDM_OUT_CON4_CLOCK_MASK (0x7UL << 6) -+#define ETDM_OUT_CON4_CLOCK_SHIFT 6 -+#define ETDM_OUT_CON4_FS(x) (x) -+#define ETDM_OUT_CON4_FS_MASK (0x1f) -+ -+#define ETDM_IN_CON5_LR_SWAP(x) BIT(((x) & 0xf) + 16) -+#define ETDM_IN_CON5_LR_SWAP_MASK (0xffffUL << 16) -+#define ETDM_IN_CON5_ENABLE_ODD(x) BIT((x) & 0xf) -+#define ETDM_IN_CON5_ENABLE_ODD_MASK (0xffff) -+ -+#define ETDM_OUT_CON5_MASTER_LRCK_INV BIT(10) -+#define ETDM_OUT_CON5_MASTER_BCK_INV BIT(9) -+#define ETDM_OUT_CON5_SLAVE_LRCK_INV BIT(8) -+#define ETDM_OUT_CON5_SLAVE_BCK_INV BIT(7) -+ -+#define ETDM_IN_CON9_OUT2LATCH_TIME(x) ((x) << 10) -+#define ETDM_IN_CON9_OUT2LATCH_TIME_MASK (0x1fUL << 10) -+ -+/* AFE_ADDA_ULx_SRC_CON0 */ -+#define AFE_ADDA_UL_SRC_CON0_ULCF_CFG_DEFAULT (0x0) -+#define AFE_ADDA_UL_SRC_CON0_ULCF_CFG_EN_CTL_MASK (0x80000000) -+#define AFE_ADDA_UL_SRC_CON0_UL_26M_SEL (0x0) -+#define AFE_ADDA_UL_SRC_CON0_UL_26M_APLL_SEL_MASK (0x40000000) -+#define AFE_ADDA_UL_SRC_CON0_UL_PHASE_SEL_CH1(x) (((x) & 0x7) << 27) -+#define AFE_ADDA_UL_SRC_CON0_UL_PHASE_SEL_CH2(x) (((x) & 0x7) << 24) -+#define AFE_ADDA_UL_SRC_CON0_UL_PHASE_SEL_MASK (0x3f000000) -+#define AFE_ADDA_UL_SRC_CON0_UL_TWO_WIRE_MODE_CTL (0x800000) -+#define AFE_ADDA_UL_SRC_CON0_UL_TWO_WIRE_MODE_CTL_MASK (0x800000) -+#define AFE_ADDA_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL (0x400000) -+#define AFE_ADDA_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL (0x200000) -+#define AFE_ADDA_UL_VOICE_MODE(x) (((x) & 0x7) << 17) -+#define AFE_ADDA_UL_VOICE_MODE_MASK (0xe0000) -+#define AFE_ADDA_UL_CON0_VOCIE_MODE_8K AFE_ADDA_UL_VOICE_MODE(0) -+#define AFE_ADDA_UL_CON0_VOCIE_MODE_16K AFE_ADDA_UL_VOICE_MODE(1) -+#define AFE_ADDA_UL_CON0_VOCIE_MODE_32K AFE_ADDA_UL_VOICE_MODE(2) -+#define AFE_ADDA_UL_CON0_VOCIE_MODE_48K AFE_ADDA_UL_VOICE_MODE(3) -+#define AFE_ADDA_UL_CON0_VOCIE_MODE_96K AFE_ADDA_UL_VOICE_MODE(4) -+#define AFE_ADDA_UL_CON0_VOCIE_MODE_192K AFE_ADDA_UL_VOICE_MODE(5) -+#define AFE_ADDA_UL_SRC_CON0_UL_AP_DMIC_ON (0x10000) -+#define AFE_ADDA_UL_SRC_CON0_UL_AP_DMIC_ON_MASK (0x10000) -+#define AFE_ADDA_UL_DMIC_LP_MODE(x) (((x) & 0x3) << 14) -+#define AFE_ADDA_UL_DMIC_LP_MODE_MASK (0xc000) -+#define AFE_ADDA_UL_DMIC_LP_MODE_3D25M AFE_ADDA_UL_DMIC_LP_MODE(0) -+#define AFE_ADDA_UL_DMIC_LP_MODE_1D625M AFE_ADDA_UL_DMIC_LP_MODE(1) -+#define AFE_ADDA_UL_DMIC_LP_MODE_8D125K AFE_ADDA_UL_DMIC_LP_MODE(2) -+#define AFE_ADDA_UL_DMIC_LP_MODE_4D0625K AFE_ADDA_UL_DMIC_LP_MODE(3) -+#define AFE_ADDA_UL_SRC_CON0_UL_IIR_MODE_CTL(x) (((x) & 0x7) << 7) -+#define AFE_ADDA_UL_SRC_CON0_UL_IIR_MODE_CTL_MASK (0x380) -+#define AFE_ADDA_UL_SRC_CON0_UL_IIR_ON_TMP_CTL (0x400) -+#define AFE_ADDA_UL_SRC_CON0_UL_IIR_ON_TMP_CTL_MASK (0x400) -+#define AFE_ADDA_UL_SRC_CON0_UL_DMIC_4P33M_SEL (0x40) -+#define AFE_ADDA_UL_SRC_CON0_UL_DMIC_4P33M_SEL_MASK (0x40) -+#define AFE_ADDA_UL_SRC_CON0_UL_DMIC_1P625M_SEL (0x20) -+#define AFE_ADDA_UL_SRC_CON0_UL_DMIC_1P625M_SEL_MASK (0x20) -+#define AFE_ADDA_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL (0x2) -+#define AFE_ADDA_UL_SRC_CON0_UL_SRC_ON_TMP_CTL (0x1) -+ -+/* AFE_ADDA_ULx_SRC_CON2 */ -+#define AFE_ADDA_UL_SRC_SINEGEN_DAC_EN_SET(x) (((x) & 0x1) << 27) -+#define AFE_ADDA_UL_SRC_SINEGEN_DAC_EN_MASK BIT(27) -+#define AFE_ADDA_UL_SRC_SINEGEN_AMP_DIV_CH2_SET(x) (((x) & 0x7) << 21) -+#define AFE_ADDA_UL_SRC_SINEGEN_AMP_DIV_CH2_MASK (0x7UL << 21) -+#define AFE_ADDA_UL_SRC_SINEGEN_FREQ_DIV_CH2_SET(x) (((x) & 0x1f) << 16) -+#define AFE_ADDA_UL_SRC_SINEGEN_FREQ_DIV_CH2_MASK (0x1fUL << 16) -+#define AFE_ADDA_UL_SRC_SINEGEN_SINE_MODE_CH2_SET(x) (((x) & 0xf) << 12) -+#define AFE_ADDA_UL_SRC_SINEGEN_SINE_MODE_CH2_MASK (0xfUL << 12) -+#define AFE_ADDA_UL_SRC_SINEGEN_AMP_DIV_CH1_SET(x) (((x) & 0x7) << 9) -+#define AFE_ADDA_UL_SRC_SINEGEN_AMP_DIV_CH1_MASK (0x7UL << 9) -+#define AFE_ADDA_UL_SRC_SINEGEN_FREQ_DIV_CH1_SET(x) (((x) & 0x1f) << 4) -+#define AFE_ADDA_UL_SRC_SINEGEN_FREQ_DIV_CH1_MASK (0x1fUL << 4) -+#define AFE_ADDA_UL_SRC_SINEGEN_SINE_MODE_CH1_SET(x) (((x) & 0xf) << 0) -+#define AFE_ADDA_UL_SRC_SINEGEN_SINE_MODE_CH1_MASK (0xfUL << 0) -+ -+/* AUDIO_TOP_FPGA_RG1 */ -+#define AUDIO_TOP_FPGA_RG1_PINMUX_TO_DBG_BOARD (0x0 << 4) -+#define AUDIO_TOP_FPGA_RG1_PINMUX_TO_AUDIO_DTB BIT(4) -+#define AUDIO_TOP_FPGA_RG1_PINMUX_MASK BIT(4) -+ -+/* AFE_GASRCx_NEW_CON0 */ -+#define GASRC_CON0_ONE_HEART_MASK BIT(31) -+#define GASRC_CON0_ONE_HEART(x) ((x) << 31) -+#define GASRC_CON0_CHSET0_OFS_ONE_HEART_DISABLE_MASK BIT(30) -+#define GASRC_CON0_CHSET0_OFS_ONE_HEART_DISABLE(x) ((x) << 30) -+#define GASRC_CON0_USE_SHORT_DELAY_COEFF_MASK BIT(29) -+#define GASRC_CON0_USE_SHORT_DELAY_COEFF(x) ((x) << 29) -+#define GASRC_CON0_CHSET0_O16BIT_MASK BIT(19) -+#define GASRC_CON0_CHSET0_O16BIT(x) ((x) << 19) -+#define GASRC_CON0_CHSET0_CLR_IIR_HISTORY BIT(17) -+#define GASRC_CON0_CHSET0_IS_MONO_MASK BIT(16) -+#define GASRC_CON0_CHSET0_IS_MONO(x) ((x) << 16) -+#define GASRC_CON0_CHSET0_OFS_SEL_MASK GENMASK(15, 14) -+#define GASRC_CON0_CHSET0_OFS_SEL_TX (0 << 14) -+#define GASRC_CON0_CHSET0_OFS_SEL_RX BIT(14) -+#define GASRC_CON0_CHSET0_IFS_SEL_MASK GENMASK(13, 12) -+#define GASRC_CON0_CHSET0_IFS_SEL_TX (3 << 12) -+#define GASRC_CON0_CHSET0_IFS_SEL_RX (2 << 12) -+#define GASRC_CON0_CHSET0_IIR_EN BIT(11) -+#define GASRC_CON0_CHSET0_IIR_STAGE_MASK GENMASK(10, 8) -+#define GASRC_CON0_CHSET0_IIR_STAGE(x) (((x) - 1) << 8) -+#define GASRC_CON0_CHSET_STR_CLR BIT(4) -+#define GASRC_CON0_COEFF_SRAM_CTRL BIT(1) -+#define GASRC_CON0_ASM_ON BIT(0) -+ -+/* AFE_GASRCx_NEW_CON1 ~ CON4 */ -+#define GASRC_CON1_ASM_FREQ_0_MASK GENMASK(23, 0) -+#define GASRC_CON2_ASM_FREQ_1_MASK GENMASK(23, 0) -+#define GASRC_CON3_ASM_FREQ_2_MASK GENMASK(23, 0) -+#define GASRC_CON4_ASM_FREQ_3_MASK GENMASK(23, 0) -+ -+/* AFE_GASRCx_NEW_CON5 */ -+#define GASRC_CON5_OUT_EN_SEL_DOMAIN_MASK GENMASK(31, 29) -+#define GASRC_CON5_OUT_EN_SEL_DOMAIN(x) ((x) << 29) -+#define GASRC_CON5_OUT_EN_SEL_FS_MASK GENMASK(28, 24) -+#define GASRC_CON5_OUT_EN_SEL_FS(x) ((x) << 24) -+#define GASRC_CON5_IN_EN_SEL_DOMAIN_MASK GENMASK(23, 21) -+#define GASRC_CON5_IN_EN_SEL_DOMAIN(x) ((x) << 21) -+#define GASRC_CON5_IN_EN_SEL_FS_MASK GENMASK(20, 16) -+#define GASRC_CON5_IN_EN_SEL_FS(x) ((x) << 16) -+#define GASRC_CON5_CALI_CK_SEL_MASK GENMASK(6, 4) -+#define GASRC_CON5_CALI_CK_SEL_26M (0 << 4) -+#define GASRC_CON5_CALI_CK_SEL_49M BIT(4) -+#define GASRC_CON5_CALI_CK_SEL_45M (2 << 4) -+#define GASRC_CON5_CALI_LRCK_SEL_MASK GENMASK(3, 1) -+#define GASRC_CON5_CALI_LRCK_SEL(x) ((x) << 1) -+#define GASRC_CON5_SOFT_RESET BIT(0) -+ -+/* AFE_GASRCx_NEW_CON6 */ -+#define GASRC_CON6_FREQ_CALI_CYCLE_MASK GENMASK(31, 16) -+#define GASRC_CON6_FREQ_CALI_CYCLE(x) ((((x) - 1) & GENMASK(15, 0)) << 16) -+#define GASRC_CON6_FREQ_CALI_AUTORST_EN BIT(15) -+#define GASRC_CON6_AUTO_TUNE_FREQ3 BIT(12) -+#define GASRC_CON6_AUTO_TUNE_FREQ2 BIT(3) -+#define GASRC_CON6_AUTO_TUNE_FREQ_MASK (GASRC_CON6_AUTO_TUNE_FREQ3 | \ -+ GASRC_CON6_AUTO_TUNE_FREQ2) -+#define GASRC_CON6_COMP_FREQ_RES_EN BIT(11) -+#define GASRC_CON6_FREQ_CALI_SEL_MASK GENMASK(9, 8) -+#define GASRC_CON6_FREQ_CALI_SEL(x) ((x) << 8) -+#define GASRC_CON6_FREQ_CALI_BP_DGL BIT(7) -+#define GASRC_CON6_FREQ_CALI_AUTO_RESTART BIT(2) -+#define GASRC_CON6_CALI_USE_FREQ_OUT BIT(1) -+#define GASRC_CON6_CALI_EN BIT(0) -+ -+/* AFE_GASRCx_NEW_CON7 */ -+#define GASRC_CON7_FREQ_CALC_DENOMINATOR_MASK GENMASK(23, 0) -+#define GASRC_CON7_FREQ_CALC_DENOMINATOR_49M (0x3c00) -+#define GASRC_CON7_FREQ_CALC_DENOMINATOR_45M (0x3720) -+#define GASRC_CON7_FREQ_CALC_DENOMINATOR_26M (0x1FBD) -+ -+/* AFE_GASRCx_NEW_CON13 */ -+#define GASRC_CON13_FREQ_CALI_AUTORST_TH_HIGH_MASK GENMASK(23, 0) -+#define GASRC_CON13_FREQ_CALI_AUTORST_TH_HIGH(x) (((x) * 0x11) >> 4) -+ -+/* AFE_GASRCx_NEW_CON14 */ -+#define GASRC_CON14_FREQ_CALI_AUTORST_TH_LOW_MASK GENMASK(23, 0) -+#define GASRC_CON14_FREQ_CALI_AUTORST_TH_LOW(x) (((x) * 0xFF) >> 4) -+ -+/* AFE DL*_CON0 */ -+#define DL_ON_SFT 28 -+#define DL_ONE_HEART_SEL_SFT 22 -+#define DL_ONE_HEART_SEL_MASK_SFT (0x3 << 22) -+#define DL_MINLEN_SFT 20 -+#define DL_MINLEN_MASK 0x3 -+#define DL_MAXLEN_SFT 16 -+#define DL_MAXLEN_MASK 0x3 -+#define DL_SEL_DOMAIN_SFT 13 -+#define DL_SEL_DOMAIN_MASK 0x7 -+#define DL_SEL_FS_SFT 8 -+#define DL_SEL_FS_MASK 0x1f -+#define DL_PBUF_SIZE_SFT 5 -+#define DL_PBUF_SIZE_MASK 0x3 -+#define DL_MONO_SFT 4 -+#define DL_NORMAL_MODE_SFT 3 -+#define DL_HD_MODE_SFT 0 -+#define DL_HD_MODE_MASK 0x3 -+ -+/* AFE VULx_CON0 */ -+#define VUL_ON_SFT 28 -+#define VUL_SEL_DOMAIN_SFT 13 -+#define VUL_SEL_DOMAIN_MASK 0x7 -+#define VUL_SEL_FS_SFT 8 -+#define VUL_SEL_FS_MASK 0x1f -+#define VUL_MONO_SFT 4 -+#define VUL_MONO_MASK 0x1 -+#define VUL_NORMAL_MODE_SFT 3 -+#define VUL_HALIGN_SFT 2 -+#define VUL_HD_MODE_SFT 0 -+#define VUL_HD_MODE_MASK 0x3 -+#define UL_MINLEN_SFT 20 -+#define UL_MINLEN_MASK 0x3 -+#define UL_MAXLEN_SFT 16 -+#define UL_MAXLEN_MASK 0x3 -+#define UL_ENABLE_INT_ODD_RFT 0 -+ -+/* AFE VUL_CMx_CON0 */ -+#define VUL_CM_NORMAL_MODE_SFT 17 -+#define UL_CM_MINLEN_SFT 8 -+#define UL_CM_MAXLEN_SFT 12 -+ -+#endif /* _MT8901_REG_H_ */ -From 3e220be45c709fb8744579f09c5ede4dbbf14fc6 Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:07 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: mt8901: add legacy machine - driver - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Add the mt8901 machine driver for SoundWire audio devices: Kconfig -and Makefile entries plus the machine driver implementation that binds -the AFE platform DAIs to the enumerated SoundWire codec endpoints. - -Folded review fix: size the codec_conf array by the number of codec -endpoints rather than the number of devices; a device contributing -several endpoints previously overran the array. - -Signed-off-by: Trevor Wu -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - sound/soc/mediatek/Kconfig | 14 + - sound/soc/mediatek/mt8901/Makefile | 1 + - .../mt8901/mt8901-acp-sdw-legacy-mach.c | 554 ++++++++++++++++++ - 3 files changed, 569 insertions(+) - create mode 100644 sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c - -diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig -index 80306dd20e..e5003dc009 100644 ---- a/sound/soc/mediatek/Kconfig -+++ b/sound/soc/mediatek/Kconfig -@@ -404,4 +404,18 @@ config SND_SOC_MT8901 - Select Y if you have such device. - If unsure select "N". - -+config SND_SOC_MT8901_LEGACY_SDW_MACH -+ tristate "ASoC Audio driver for MT8901 SoundWire machine" -+ depends on SND_SOC_MT8901 && ACPI -+ depends on SOUNDWIRE_MTK -+ select SND_SOC_SDW_UTILS -+ select SND_SOC_RT712_SDCA_SDW -+ select SND_SOC_RT712_SDCA_DMIC_SDW -+ select SND_SOC_RT1320_SDW -+ help -+ This adds support for Legacy(No DSP) sound card for MediaTek -+ MT8901 boards. -+ Select Y if you have such device. -+ If unsure select "N". -+ - endmenu -diff --git a/sound/soc/mediatek/mt8901/Makefile b/sound/soc/mediatek/mt8901/Makefile -index 8b4f9b54f6..b2c921f11c 100644 ---- a/sound/soc/mediatek/mt8901/Makefile -+++ b/sound/soc/mediatek/mt8901/Makefile -@@ -6,3 +6,4 @@ snd-soc-mt8901-afe-y := \ - mt8901-dai-soundwire.o - - obj-$(CONFIG_SND_SOC_MT8901) += snd-soc-mt8901-afe.o -+obj-$(CONFIG_SND_SOC_MT8901_LEGACY_SDW_MACH) += mt8901-acp-sdw-legacy-mach.o -diff --git a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -new file mode 100644 -index 0000000000..98010cffab ---- /dev/null -+++ b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -@@ -0,0 +1,554 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * ALSA SoC machine driver for ACPI legacy path -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static unsigned long soc_sdw_quirk; -+static int quirk_override = -1; -+module_param_named(quirk, quirk_override, int, 0444); -+MODULE_PARM_DESC(quirk, "Board-specific quirk override"); -+ -+#define MT8901_SDW_MAX_LINKS 2 -+#define PCM_STREAM_NUM (SNDRV_PCM_STREAM_LAST + 1) -+ -+static struct snd_soc_dai_link_component afe_platform_component[] = { -+ { .name = "NVDA9022:00" } -+}; -+ -+struct mtk_mc_ctx { -+ unsigned int sdw_pin_index[MT8901_SDW_MAX_LINKS][PCM_STREAM_NUM]; -+}; -+ -+static void log_quirks(struct device *dev) -+{ -+ if (SOC_SDW_JACK_JDSRC(soc_sdw_quirk)) -+ dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", -+ SOC_SDW_JACK_JDSRC(soc_sdw_quirk)); -+ if (soc_sdw_quirk & SOC_SDW_CODEC_SPKR) -+ dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n"); -+ if (soc_sdw_quirk & SOC_SDW_CODEC_MIC) -+ dev_dbg(dev, "quirk SOC_SDW_CODEC_MIC enabled\n"); -+} -+ -+static const struct snd_soc_dapm_route mt8901_card_routes[] = { -+ /* TX: AFE O-ports -> SDW PDIs (playback) */ -+ {"PDI0", NULL, "O148"}, {"PDI0", NULL, "O149"}, -+ {"PDI2", NULL, "O150"}, {"PDI2", NULL, "O151"}, -+ {"PDI3", NULL, "O152"}, {"PDI3", NULL, "O153"}, -+ {"PDI4", NULL, "O154"}, {"PDI4", NULL, "O155"}, -+ {"PDI5", NULL, "O156"}, {"PDI5", NULL, "O157"}, -+ {"PDI6", NULL, "O158"}, {"PDI6", NULL, "O159"}, -+ {"PDI16", NULL, "O160"}, {"PDI16", NULL, "O161"}, -+ -+ /* RX: SDW PDIs -> AFE I-ports (capture) */ -+ {"I166", NULL, "PDI1"}, {"I167", NULL, "PDI1"}, -+ {"I168", NULL, "PDI7"}, {"I169", NULL, "PDI7"}, -+ {"I170", NULL, "PDI8"}, {"I171", NULL, "PDI8"}, -+ {"I172", NULL, "PDI9"}, {"I173", NULL, "PDI9"}, -+ {"I174", NULL, "PDI10"}, {"I175", NULL, "PDI10"}, -+ {"I176", NULL, "PDI11"}, {"I177", NULL, "PDI11"}, -+ {"I178", NULL, "PDI12"}, {"I179", NULL, "PDI12"}, -+ {"I180", NULL, "PDI13"}, {"I181", NULL, "PDI13"}, -+ {"I182", NULL, "PDI14"}, {"I183", NULL, "PDI14"}, -+ {"I184", NULL, "PDI15"}, {"I185", NULL, "PDI15"}, -+ {"I186", NULL, "PDI17"}, {"I187", NULL, "PDI17"}, -+}; -+ -+static const struct snd_soc_ops sdw_ops = { -+ .startup = asoc_sdw_startup, -+ .prepare = asoc_sdw_prepare, -+ .trigger = asoc_sdw_trigger, -+ .hw_params = asoc_sdw_hw_params, -+ .hw_free = asoc_sdw_hw_free, -+ .shutdown = asoc_sdw_shutdown, -+}; -+ -+static const char * const type_strings[] = { -+ "SimpleJack", "SmartAmp", "SmartMic"}; -+ -+struct mtk_fe_dai { -+ const char *dai_name; /* AFE CPU DAI name, see mt8901-afe-pcm.c */ -+ int playback; /* 1 = playback FE, 0 = capture FE */ -+}; -+ -+static const struct mtk_fe_dai mt8901_fe_dais[] = { -+ { "DL0", 1 }, -+ { "DL1", 1 }, -+ { "DL2", 1 }, -+ { "DL3", 1 }, -+ { "DL4", 1 }, -+ { "DL5", 1 }, -+ { "DL_24CH", 1 }, -+ { "UL0", 0 }, -+ { "UL1", 0 }, -+ { "UL2", 0 }, -+ { "UL3", 0 }, -+ { "UL4", 0 }, -+ { "UL5", 0 }, -+ { "VUL_CM0", 0 }, -+ { "VUL_CM1", 0 }, -+ { "VUL_CM2", 0 }, -+}; -+ -+static int create_FE_dailinks(struct snd_soc_card *card, -+ struct snd_soc_dai_link **dai_links) -+{ -+ struct device *dev = card->dev; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_fe_dais); i++) { -+ const struct mtk_fe_dai *fe = &mt8901_fe_dais[i]; -+ struct snd_soc_dai_link_component *cpus; -+ struct snd_soc_dai_link *link = *dai_links; -+ -+ cpus = devm_kzalloc(dev, sizeof(*cpus), GFP_KERNEL); -+ if (!cpus) -+ return -ENOMEM; -+ -+ /* CPU = AFE memif DAI; platform = AFE; codec = shared dummy. */ -+ cpus->dai_name = fe->dai_name; -+ -+ link->name = devm_kasprintf(dev, GFP_KERNEL, "%s_FE", -+ fe->dai_name); -+ if (!link->name) -+ return -ENOMEM; -+ link->stream_name = -+ devm_kasprintf(dev, GFP_KERNEL, "%s %s", -+ fe->dai_name, -+ fe->playback ? "Playback" : "Capture"); -+ if (!link->stream_name) -+ return -ENOMEM; -+ -+ link->cpus = cpus; -+ link->num_cpus = 1; -+ link->codecs = &snd_soc_dummy_dlc; -+ link->num_codecs = 1; -+ link->platforms = afe_platform_component; -+ link->num_platforms = 1; -+ -+ link->dynamic = 1; /* DPCM front end */ -+ link->nonatomic = 1; /* same as BE */ -+ link->trigger[0] = SND_SOC_DPCM_TRIGGER_POST; -+ link->trigger[1] = SND_SOC_DPCM_TRIGGER_POST; -+ if (fe->playback) -+ link->playback_only = 1; -+ else -+ link->capture_only = 1; -+ -+ (*dai_links)++; -+ } -+ -+ return 0; -+} -+ -+static int create_sdw_dailink(struct snd_soc_card *card, -+ struct asoc_sdw_dailink *soc_dai, -+ struct snd_soc_dai_link **dai_links, -+ int *be_id, -+ struct snd_soc_codec_conf **codec_conf) -+{ -+ struct device *dev = card->dev; -+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); -+ struct mtk_mc_ctx *mtk_ctx = (struct mtk_mc_ctx *)ctx->private; -+ struct asoc_sdw_endpoint *soc_end; -+ int stream; -+ int ret; -+ -+ list_for_each_entry(soc_end, &soc_dai->endpoints, list) { -+ if (soc_end->name_prefix) { -+ (*codec_conf)->dlc.name = soc_end->codec_name; -+ (*codec_conf)->name_prefix = soc_end->name_prefix; -+ (*codec_conf)++; -+ } -+ -+ if (soc_end->include_sidecar && -+ soc_end->codec_info && -+ soc_end->codec_info->add_sidecar) { -+ ret = soc_end->codec_info->add_sidecar(card, dai_links, -+ codec_conf); -+ if (ret) -+ return ret; -+ } -+ } -+ -+ for_each_pcm_streams(stream) { -+ static const char * const sdw_stream_name[] = { -+ "SDW%d-PLAYBACK", -+ "SDW%d-CAPTURE", -+ "SDW%d-PLAYBACK-%s", -+ "SDW%d-CAPTURE-%s", -+ }; -+ struct snd_soc_dai_link_ch_map *codec_maps; -+ struct snd_soc_dai_link_component *codecs; -+ struct snd_soc_dai_link_component *cpus; -+ int num_cpus = hweight32(soc_dai->link_mask[stream]); -+ int num_codecs = soc_dai->num_devs[stream]; -+ int playback, capture; -+ int cur_link = 0; -+ int i = 0, j = 0; -+ int dai_type; -+ char *name; -+ const int str_name_with_type_offset = 2; -+ int str_offset = stream; -+ -+ if (!soc_dai->num_devs[stream]) -+ continue; -+ -+ soc_end = list_first_entry(&soc_dai->endpoints, -+ struct asoc_sdw_endpoint, list); -+ -+ *be_id = soc_end->dai_info->dailink[stream]; -+ if (*be_id < 0) { -+ dev_err(dev, "Invalid dailink id %d\n", *be_id); -+ return -EINVAL; -+ } -+ -+ /* create stream name according to first link id */ -+ if (ctx->append_dai_type) { -+ str_offset += str_name_with_type_offset; -+ dai_type = soc_end->dai_info->dai_type; -+ if (dai_type >= ARRAY_SIZE(type_strings)) { -+ dev_err(dev, "Invalid dai_type %d\n", dai_type); -+ return -EINVAL; -+ } -+ name = devm_kasprintf(dev, GFP_KERNEL, -+ sdw_stream_name[str_offset], -+ ffs(soc_end->link_mask) - 1, -+ type_strings[dai_type]); -+ } else { -+ name = devm_kasprintf(dev, GFP_KERNEL, -+ sdw_stream_name[str_offset], -+ ffs(soc_end->link_mask) - 1); -+ } -+ if (!name) -+ return -ENOMEM; -+ -+ cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); -+ if (!cpus) -+ return -ENOMEM; -+ -+ codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), -+ GFP_KERNEL); -+ if (!codecs) -+ return -ENOMEM; -+ -+ codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), -+ GFP_KERNEL); -+ if (!codec_maps) -+ return -ENOMEM; -+ -+ list_for_each_entry(soc_end, &soc_dai->endpoints, list) { -+ if (!soc_end->dai_info->direction[stream]) -+ continue; -+ -+ if (cur_link != soc_end->link_mask) { -+ int link = ffs(soc_end->link_mask) - 1; -+ int pin; -+ -+ if (link < 0 || link >= MT8901_SDW_MAX_LINKS) { -+ dev_err(dev, "Invalid link index %d", -+ link); -+ return -EINVAL; -+ } -+ -+ pin = mtk_ctx->sdw_pin_index[link][stream]++; -+ -+ cur_link = soc_end->link_mask; -+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ cpus[i].dai_name = -+ devm_kasprintf(dev, GFP_KERNEL, -+ "SDW%d_Playback%d", -+ link, pin); -+ } else { -+ cpus[i].dai_name = -+ devm_kasprintf(dev, GFP_KERNEL, -+ "SDW%d_Capture%d", -+ link, pin); -+ } -+ if (!cpus[i].dai_name) -+ return -ENOMEM; -+ i++; -+ } -+ -+ codec_maps[j].cpu = i - 1; -+ codec_maps[j].codec = j; -+ -+ codecs[j].name = soc_end->codec_name; -+ codecs[j].dai_name = soc_end->dai_info->dai_name; -+ j++; -+ } -+ -+ WARN_ON(i != num_cpus || j != num_codecs); -+ -+ playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); -+ capture = (stream == SNDRV_PCM_STREAM_CAPTURE); -+ -+ asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, -+ playback, capture, -+ cpus, num_cpus, &snd_soc_dummy_dlc, -+ 1, codecs, num_codecs, -+ 1, asoc_sdw_rtd_init, &sdw_ops); -+ -+ (*dai_links)->nonatomic = true; -+ (*dai_links)->ch_maps = codec_maps; -+ -+ list_for_each_entry(soc_end, &soc_dai->endpoints, list) { -+ if (soc_end->dai_info->init) -+ soc_end->dai_info->init(card, *dai_links, -+ soc_end->codec_info, -+ playback); -+ } -+ -+ (*dai_links)++; -+ } -+ -+ return 0; -+} -+ -+static int create_sdw_dailinks(struct snd_soc_card *card, -+ struct snd_soc_dai_link **dai_links, int *be_id, -+ struct asoc_sdw_dailink *soc_dais, -+ struct snd_soc_codec_conf **codec_conf) -+{ -+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); -+ struct mtk_mc_ctx *mtk_ctx = (struct mtk_mc_ctx *)ctx->private; -+ int ret, i, stream; -+ -+ for (i = 0; i < MT8901_SDW_MAX_LINKS; i++) -+ for_each_pcm_streams(stream) -+ mtk_ctx->sdw_pin_index[i][stream] = 0; -+ -+ /* generate DAI links by each sdw link */ -+ while (soc_dais->initialised) { -+ int current_be_id = 0; -+ -+ ret = create_sdw_dailink(card, soc_dais, dai_links, -+ ¤t_be_id, codec_conf); -+ if (ret) -+ return ret; -+ -+ /* Update the be_id to match the highest ID used for SDW link */ -+ if (*be_id < current_be_id) -+ *be_id = current_be_id; -+ -+ soc_dais++; -+ } -+ -+ return 0; -+} -+ -+static int soc_card_dai_links_create(struct snd_soc_card *card) -+{ -+ struct device *dev = card->dev; -+ int sdw_be_num = 0; -+ struct asoc_sdw_endpoint *soc_ends __free(kfree) = NULL; -+ struct asoc_sdw_dailink *soc_dais __free(kfree) = NULL; -+ struct snd_soc_aux_dev *soc_aux; -+ struct snd_soc_codec_conf *codec_conf; -+ struct snd_soc_dai_link *dai_links; -+ int num_devs = 0; -+ int num_ends = 0; -+ int num_confs; -+ int num_aux = 0; -+ int num_links; -+ int be_id = 0; -+ int ret; -+ -+ ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, -+ &num_aux); -+ if (ret < 0) { -+ dev_err(dev, "failed to count sdw devices/endpoints: %d\n", -+ ret); -+ return ret; -+ } -+ -+ /* -+ * One codec_conf entry is consumed per surviving endpoint (each -+ * endpoint of a multi-endpoint codec carries the name prefix), so the -+ * budget must start from the endpoint count, not the device count. -+ * asoc_sdw_parse_sdw_endpoints() decrements it for each endpoint it -+ * skips. Same accounting as upstream sof_sdw. -+ */ -+ num_confs = num_ends; -+ -+ /* One per DAI link, worst case is a DAI link for every endpoint */ -+ soc_dais = kcalloc(num_ends, sizeof(*soc_dais), GFP_KERNEL); -+ if (!soc_dais) -+ return -ENOMEM; -+ -+ /* One per endpoint, ie. each DAI on each codec/amp */ -+ soc_ends = kcalloc(num_ends, sizeof(*soc_ends), GFP_KERNEL); -+ if (!soc_ends) -+ return -ENOMEM; -+ -+ soc_aux = devm_kcalloc(dev, num_aux, sizeof(*soc_aux), GFP_KERNEL); -+ if (!soc_aux) -+ return -ENOMEM; -+ -+ ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, -+ &num_confs); -+ if (ret < 0) { -+ dev_err(dev, "failed to parse sdw devices/endpoints: %d\n", -+ ret); -+ return ret; -+ } -+ -+ sdw_be_num = ret; -+ dev_dbg(dev, "sdw be %d", sdw_be_num); -+ -+ codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), -+ GFP_KERNEL); -+ if (!codec_conf) -+ return -ENOMEM; -+ -+ /* allocate FE + BE dailinks */ -+ num_links = ARRAY_SIZE(mt8901_fe_dais) + sdw_be_num; -+ dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), -+ GFP_KERNEL); -+ if (!dai_links) -+ return -ENOMEM; -+ -+ card->codec_conf = codec_conf; -+ card->num_configs = num_confs; -+ card->dai_link = dai_links; -+ card->num_links = num_links; -+ -+ /* FE (AFE front ends) first, then BE (SoundWire). */ -+ ret = create_FE_dailinks(card, &dai_links); -+ if (ret) -+ return ret; -+ -+ /* SDW */ -+ if (sdw_be_num) { -+ ret = create_sdw_dailinks(card, &dai_links, &be_id, -+ soc_dais, &codec_conf); -+ if (ret) -+ return ret; -+ } -+ -+ WARN_ON(codec_conf != card->codec_conf + card->num_configs); -+ WARN_ON(dai_links != card->dai_link + card->num_links); -+ -+ return ret; -+} -+ -+static int mt8901_card_probe(struct platform_device *pdev) -+{ -+ struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); -+ struct snd_soc_card *card; -+ struct mtk_mc_ctx *mtk_ctx; -+ struct asoc_sdw_mc_private *ctx; -+ int amp_num = 0; -+ int i, ret; -+ -+ mtk_ctx = devm_kzalloc(&pdev->dev, sizeof(*mtk_ctx), GFP_KERNEL); -+ if (!mtk_ctx) -+ return -ENOMEM; -+ -+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; -+ ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); -+ ctx->private = mtk_ctx; -+ card = &ctx->card; -+ card->dev = &pdev->dev; -+ card->name = "mt8901-soundwire"; -+ card->owner = THIS_MODULE; -+ card->late_probe = asoc_sdw_card_late_probe; -+ card->dapm_routes = mt8901_card_routes; -+ card->num_dapm_routes = ARRAY_SIZE(mt8901_card_routes); -+ -+ snd_soc_card_set_drvdata(card, ctx); -+ -+ if (quirk_override != -1) { -+ dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", -+ soc_sdw_quirk, quirk_override); -+ soc_sdw_quirk = (unsigned int)quirk_override; -+ } -+ -+ log_quirks(card->dev); -+ -+ ctx->mc_quirk = soc_sdw_quirk; -+ dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk); -+ /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ -+ for (i = 0; i < ctx->codec_info_list_count; i++) -+ codec_info_list[i].amp_num = 0; -+ -+ ret = soc_card_dai_links_create(card); -+ if (ret < 0) -+ return ret; -+ -+ /* -+ * the default amp_num is zero for each codec and -+ * amp_num will only be increased for active amp -+ * codecs on used platform -+ */ -+ for (i = 0; i < ctx->codec_info_list_count; i++) -+ amp_num += codec_info_list[i].amp_num; -+ -+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, -+ "cfg-amp:%d", amp_num); -+ if (!card->components) -+ return -ENOMEM; -+ if (mach && mach->mach_params.dmic_num) { -+ card->components = devm_kasprintf(card->dev, GFP_KERNEL, -+ "%s mic:dmic cfg-mics:%d", -+ card->components, -+ mach->mach_params.dmic_num); -+ if (!card->components) -+ return -ENOMEM; -+ } -+ -+ /* Register the card */ -+ ret = devm_snd_soc_register_card(card->dev, card); -+ if (ret) { -+ dev_err_probe(card->dev, ret, -+ "snd_soc_register_card failed %d\n", ret); -+ asoc_sdw_mc_dailink_exit_loop(card); -+ return ret; -+ } -+ -+ platform_set_drvdata(pdev, card); -+ -+ return ret; -+} -+ -+static void mt8901_card_remove(struct platform_device *pdev) -+{ -+ struct snd_soc_card *card = platform_get_drvdata(pdev); -+ -+ asoc_sdw_mc_dailink_exit_loop(card); -+} -+ -+static const struct platform_device_id mc_id_table[] = { -+ { "mtk_sdw_mc", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(platform, mc_id_table); -+ -+static struct platform_driver soc_sdw_driver = { -+ .driver = { -+ .name = "mtk_sdw_mc", -+ .pm = &snd_soc_pm_ops, -+ }, -+ .probe = mt8901_card_probe, -+ .remove = mt8901_card_remove, -+ .id_table = mc_id_table, -+}; -+ -+module_platform_driver(soc_sdw_driver); -+ -+MODULE_DESCRIPTION("MTK SoundWire legacy MT8901 machine driver"); -+MODULE_AUTHOR("Trevor Wu "); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); -From b4a6769635c1d5f3357f1ed22acb6a274b445bc8 Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:07 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: add SDCA support for MediaTek - chip - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Codec integration requires SDCA support on the SoundWire manager -side. Introduce the SND_SOC_MTK_SDCA configuration and the glue that -enables SDCA class devices behind the MediaTek manager. - -Signed-off-by: Trevor Wu -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - sound/soc/mediatek/Kconfig | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig -index e5003dc009..8d1f97d682 100644 ---- a/sound/soc/mediatek/Kconfig -+++ b/sound/soc/mediatek/Kconfig -@@ -225,6 +225,16 @@ config SND_SOC_MTK_BTCVSD - Select Y if you have such device. - If unsure select "N". - -+config SND_SOC_MTK_SDCA -+ tristate "SDCA support for Mediatek chip" -+ depends on ACPI -+ select SND_SOC_SDCA -+ help -+ This enables SDCA support for codecs connecting with the -+ MediaTek SoundWire master. -+ Select Y if you use SDCA device. -+ If unsure select "N". -+ - config SND_SOC_MT8188 - tristate "ASoC support for MediaTek MT8188 chip" - depends on ARCH_MEDIATEK || COMPILE_TEST -From 27a87d85e8d80bbc3ab6ecb1cc1ca15df645b51e Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Wed, 9 Sep 2026 21:16:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: move the manager into its - own directory - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Move the MediaTek SoundWire manager sources from drivers/soundwire/ into -drivers/soundwire/mediatek/, matching how the other vendor managers are -laid out and making room for the MT8901 clock-control glue that follows. -No functional change. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/Makefile | 3 +- - drivers/soundwire/mediatek/Makefile | 7 + - drivers/soundwire/mediatek/mtk-sdw-common.h | 75 ++ - drivers/soundwire/mediatek/mtk-sdw-core.c | 895 ++++++++++++++++++ - drivers/soundwire/mediatek/mtk-sdw-core.h | 234 +++++ - drivers/soundwire/mediatek/mtk-sdw-mach.c | 167 ++++ - drivers/soundwire/mediatek/mtk-sdw-mach.h | 20 + - drivers/soundwire/mediatek/mtk-sdw-top.c | 301 ++++++ - drivers/soundwire/mediatek/mtk-sdw-top.h | 105 +++ - drivers/soundwire/mediatek/mtk-sdw.c | 982 ++++++++++++++++++++ - drivers/soundwire/mediatek/mtk-sdw.h | 85 ++ - drivers/soundwire/mtk-sdw-common.h | 75 -- - drivers/soundwire/mtk-sdw-core.c | 895 ------------------ - drivers/soundwire/mtk-sdw-core.h | 234 ----- - drivers/soundwire/mtk-sdw-mach.c | 167 ---- - drivers/soundwire/mtk-sdw-mach.h | 20 - - drivers/soundwire/mtk-sdw-top.c | 301 ------ - drivers/soundwire/mtk-sdw-top.h | 105 --- - drivers/soundwire/mtk-sdw.c | 982 -------------------- - drivers/soundwire/mtk-sdw.h | 85 -- - 20 files changed, 2872 insertions(+), 2866 deletions(-) - create mode 100644 drivers/soundwire/mediatek/Makefile - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-common.h - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-core.c - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-core.h - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-mach.c - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-mach.h - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-top.c - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-top.h - create mode 100644 drivers/soundwire/mediatek/mtk-sdw.c - create mode 100644 drivers/soundwire/mediatek/mtk-sdw.h - delete mode 100644 drivers/soundwire/mtk-sdw-common.h - delete mode 100644 drivers/soundwire/mtk-sdw-core.c - delete mode 100644 drivers/soundwire/mtk-sdw-core.h - delete mode 100644 drivers/soundwire/mtk-sdw-mach.c - delete mode 100644 drivers/soundwire/mtk-sdw-mach.h - delete mode 100644 drivers/soundwire/mtk-sdw-top.c - delete mode 100644 drivers/soundwire/mtk-sdw-top.h - delete mode 100644 drivers/soundwire/mtk-sdw.c - delete mode 100644 drivers/soundwire/mtk-sdw.h - -diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile -index 063de2b271..9663e80501 100644 ---- a/drivers/soundwire/Makefile -+++ b/drivers/soundwire/Makefile -@@ -38,5 +38,4 @@ soundwire-qcom-y := qcom.o - obj-$(CONFIG_SOUNDWIRE_QCOM) += soundwire-qcom.o - - #MediaTek driver --soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o mtk-sdw-mach.o --obj-$(CONFIG_SOUNDWIRE_MTK) += soundwire-mtk.o -+obj-$(CONFIG_SOUNDWIRE_MTK) += mediatek/ -diff --git a/drivers/soundwire/mediatek/Makefile b/drivers/soundwire/mediatek/Makefile -new file mode 100644 -index 0000000000..9e0ad24ce8 ---- /dev/null -+++ b/drivers/soundwire/mediatek/Makefile -@@ -0,0 +1,7 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# Makefile for MediaTek SoundWire driver -+# -+ -+soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o mtk-sdw-mach.o -+obj-$(CONFIG_SOUNDWIRE_MTK) += soundwire-mtk.o -diff --git a/drivers/soundwire/mediatek/mtk-sdw-common.h b/drivers/soundwire/mediatek/mtk-sdw-common.h -new file mode 100644 -index 0000000000..32912b1272 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-common.h -@@ -0,0 +1,75 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master — shared driver structure. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_COMMON_H -+#define __MTK_SDW_COMMON_H -+ -+#include "mtk-sdw-core.h" -+ -+struct mtk_sdw; -+struct mtk_sdw_top_cfg; -+struct mtk_sdw_top_pdi_params; -+ -+enum mtk_sdw_hw_ver { -+ MTK_SDW_HW_VER_MT8195 = 0, /* first chip */ -+ MTK_SDW_HW_VER_MT8901, /* second chip */ -+ MTK_SDW_HW_VER_MT8971, -+ MTK_SDW_HW_VER_MAX, -+}; -+ -+#define SDW_MAX_HWIP_NUM (2) -+#define SDW_PDI_CONFIG_NUM (8) -+#define MTK_SDW_MAX_GROUP_SYNC 4 -+#define MTK_SDW_MAX_DP 16 -+ -+struct mtk_sdw_link { -+ struct mtk_sdw_core core; -+ struct mtk_sdw *master; -+ int ip_idx; -+ int irq; -+ u32 src_base; -+ u32 src_num; -+ u32 sink_base; -+ u32 sink_num; -+}; -+ -+struct mtk_sdw_dai { -+ struct mtk_sdw_link *link; -+ unsigned int port_num; -+ struct sdw_stream_runtime *sruntime; -+ unsigned int pdi_count; -+ struct mtk_sdw_pdi_params pdi_params[SDW_PDI_CONFIG_NUM]; -+ struct mtk_sdw_top_pdi_params *top_pdi_params; -+ bool use_group_sync; -+ unsigned int group_sync_id; -+ bool need_enable_delay; -+}; -+ -+struct mtk_sdw { -+ struct device *dev; -+ void __iomem *base; /* full AFE MMIO */ -+ struct mtk_sdw_link links[SDW_MAX_HWIP_NUM]; -+ int num_links; -+ u32 controller_en_list; -+ const struct mtk_sdw_top_cfg *top_cfg; -+ void __iomem *top_pdi; /* base + top_cfg->pdi_base */ -+ void __iomem *top_con; /* base + top_cfg->con_base */ -+ u32 hw_ver; -+ /* group_lock: serializes group_refcnt[] group-sync allocation */ -+ struct mutex group_lock; -+ int group_refcnt[MTK_SDW_MAX_GROUP_SYNC]; -+ u32 tzd_delay; -+ bool tzd_inverse; -+ u32 phy_delay; -+ u32 phy_double_delay; -+ struct mtk_sdw_dai *dais; -+ int num_dais; -+ u16 dp_pdi_mask[MTK_SDW_MAX_DP]; -+ struct platform_device *mach_dev; -+}; -+ -+#endif /* __MTK_SDW_COMMON_H */ -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -new file mode 100644 -index 0000000000..c730c88d3b ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -0,0 +1,895 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire master — STABLE controller core. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "../bus.h" -+#include "mtk-sdw-core.h" -+#include "mtk-sdw.h" -+ -+/* ---- register helpers ---- */ -+static u32 core_readl(struct mtk_sdw_core *core, u32 off) -+{ -+ return readl(core->regs + off); -+} -+ -+static void core_writel(struct mtk_sdw_core *core, u32 off, u32 val) -+{ -+ writel(val, core->regs + off); -+} -+ -+static void core_updatel(struct mtk_sdw_core *core, u32 off, u32 mask, u32 val) -+{ -+ u32 tmp = core_readl(core, off); -+ -+ core_writel(core, off, (tmp & ~mask) | (val & mask)); -+} -+ -+static u32 core_get_slave_status(struct mtk_sdw_core *core, u32 dev_addr) -+{ -+ u32 slave_stat = 0; -+ -+ if (dev_addr > SDW_MAX_DEVICES) { -+ dev_err(core->dev, "Unexpected device id %u\n", dev_addr); -+ return slave_stat; -+ } -+ slave_stat = core_readl(core, MCP_SLAVESTAT); -+ slave_stat = MCP_SLAVESTAT_STATUS(slave_stat, dev_addr); -+ -+ return slave_stat; -+} -+ -+#define CORE_CMD_TIMEOUT_US 50000 -+#define CORE_CMD_POLL_US 10 -+ -+static int core_send_cmd(struct mtk_sdw_core *core, u32 cmd, u8 *rdata) -+{ -+ u32 resp; -+ int ret; -+ -+ core_writel(core, MCP_COMMAND(0), cmd); -+ -+ ret = readl_poll_timeout(core->regs + MCP_STAT, resp, -+ resp & MCP_STAT_RX_NE, -+ CORE_CMD_POLL_US, CORE_CMD_TIMEOUT_US); -+ if (ret) { -+ dev_err(core->dev, "cmd 0x%08x timeout\n", cmd); -+ return SDW_CMD_TIMEOUT; -+ } -+ -+ resp = core_readl(core, MCP_COMMAND(0)); -+ if (FIELD_GET(MCP_RESP_NAK, resp)) -+ return SDW_CMD_FAIL; -+ if (!FIELD_GET(MCP_RESP_ACK, resp)) -+ return SDW_CMD_IGNORED; -+ if (rdata) -+ *rdata = FIELD_GET(MCP_RESP_RDATA, resp); -+ -+ return SDW_CMD_OK; -+} -+ -+static enum sdw_command_response -+mtk_program_scp_addr(struct mtk_sdw_core *core, struct sdw_msg *msg) -+{ -+ int ret; -+ u32 p1 = FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -+ FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -+ FIELD_PREP(MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE1) | -+ FIELD_PREP(MCP_CMD_REG_DATA, msg->addr_page1); -+ u32 p2 = FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -+ FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -+ FIELD_PREP(MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE2) | -+ FIELD_PREP(MCP_CMD_REG_DATA, msg->addr_page2); -+ -+ ret = core_send_cmd(core, p1, NULL); -+ if (ret == SDW_CMD_OK) -+ ret = core_send_cmd(core, p2, NULL); -+ -+ return ret; -+} -+ -+static int mtk_core_prep_msg(struct mtk_sdw_core *core, struct sdw_msg *msg) -+{ -+ int ret; -+ -+ if (msg->page) { -+ ret = mtk_program_scp_addr(core, msg); -+ if (ret) { -+ msg->len = 0; -+ return ret; -+ } -+ } -+ -+ switch (msg->flags) { -+ case SDW_MSG_FLAG_READ: -+ case SDW_MSG_FLAG_WRITE: -+ break; -+ default: -+ dev_err(core->dev, "Invalid msg cmd: %d\n", msg->flags); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* ======================================================================= -+ * sdw_master_ops -+ * ======================================================================= -+ */ -+static enum sdw_command_response -+mtk_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ int i, ret = 0; -+ -+ ret = mtk_core_prep_msg(core, msg); -+ if (ret) -+ return SDW_CMD_FAIL_OTHER; -+ -+ for (i = 0; i < msg->len; i++) { -+ u32 cmd = FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -+ FIELD_PREP(MCP_CMD_REG_ADDR, msg->addr + i) | -+ FIELD_PREP(MCP_CMD_SSP_TAG, msg->ssp_sync); -+ -+ if (msg->flags == SDW_MSG_FLAG_READ) { -+ cmd |= FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_READ); -+ ret = core_send_cmd(core, cmd, &msg->buf[i]); -+ } else { -+ cmd |= FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -+ FIELD_PREP(MCP_CMD_REG_DATA, msg->buf[i]); -+ ret = core_send_cmd(core, cmd, NULL); -+ } -+ if (ret) -+ break; -+ } -+ -+ return ret; -+} -+ -+static u32 mtk_sdw_read_ping_status(struct sdw_bus *bus) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ -+ return core_readl(core, MCP_SLAVESTAT); -+} -+ -+static bool mipi_fwnode_property_read_bool(const struct fwnode_handle *fwnode, -+ const char *propname) -+{ -+ int ret; -+ u8 val; -+ -+ if (!fwnode_property_present(fwnode, propname)) -+ return false; -+ ret = fwnode_property_read_u8_array(fwnode, propname, &val, 1); -+ if (ret < 0) -+ return false; -+ return !!val; -+} -+ -+static int mtk_sdw_read_prop(struct sdw_bus *bus) -+{ -+ struct sdw_master_prop *prop = &bus->prop; -+ struct fwnode_handle *link; -+ char name[40]; -+ int nval; -+ int ret; -+ int i; -+ int id = 0; -+ -+ snprintf(name, sizeof(name), "mipi-sdw-%d-sw-interface-revision", -+ bus->link_id); -+ -+ device_property_read_u32(bus->dev, name, &prop->revision); -+ -+ /* Find master handle */ -+ snprintf(name, sizeof(name), -+ "mipi-sdw-%d-link-%d-subproperties", bus->link_id, id); -+ -+ link = device_get_named_child_node(bus->dev, name); -+ if (!link) { -+ dev_err(bus->dev, "Master node %s not found\n", name); -+ return -EIO; -+ } -+ -+ for (i = SDW_CLK_STOP_MODE0; i <= SDW_CLK_STOP_MODE1; i++) { -+ snprintf(name, sizeof(name), -+ "mipi-sdw-clock-stop-mode%d-supported", i); -+ if (mipi_fwnode_property_read_bool(link, name)) -+ prop->clk_stop_modes |= BIT(i); -+ } -+ -+ fwnode_property_read_u32(link, -+ "mipi-sdw-max-clock-frequency", -+ &prop->max_clk_freq); -+ -+ nval = fwnode_property_count_u32(link, -+ "mipi-sdw-clock-frequencies-supported"); -+ if (nval > 0) { -+ prop->num_clk_freq = nval; -+ prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq, -+ sizeof(*prop->clk_freq), -+ GFP_KERNEL); -+ if (!prop->clk_freq) { -+ fwnode_handle_put(link); -+ return -ENOMEM; -+ } -+ -+ ret = fwnode_property_read_u32_array(link, -+ "mipi-sdw-clock-frequencies-supported", -+ prop->clk_freq, -+ prop->num_clk_freq); -+ if (ret < 0) { -+ fwnode_handle_put(link); -+ return ret; -+ } -+ } -+ -+ /* -+ * Check the frequencies supported. If FW doesn't provide max -+ * freq, then populate here by checking values. -+ */ -+ if (!prop->max_clk_freq && prop->clk_freq) { -+ prop->max_clk_freq = prop->clk_freq[0]; -+ for (i = 1; i < prop->num_clk_freq; i++) { -+ if (prop->clk_freq[i] > prop->max_clk_freq) -+ prop->max_clk_freq = prop->clk_freq[i]; -+ } -+ } -+ -+ fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate", -+ &prop->default_frame_rate); -+ -+ fwnode_property_read_u32(link, "mipi-sdw-default-frame-row-size", -+ &prop->default_row); -+ -+ fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size", -+ &prop->default_col); -+ -+ fwnode_handle_put(link); -+ -+ /* -+ * sdw_bus_master_add() derives the bus data-rate limits from these -+ * right after read_prop returns, so the fallbacks must be in place -+ * here rather than after the master is added. -+ */ -+ if (!prop->max_clk_freq) -+ prop->max_clk_freq = SDW_DEFAULT_MAX_BUS_CLK_FREQ; -+ if (!prop->default_frame_rate) -+ prop->default_frame_rate = SDW_DEFAULT_FRAME_RATE; -+ if (!prop->default_row) -+ prop->default_row = SDW_DEFAULT_FRAME_SHAPE_ROW; -+ if (!prop->default_col) -+ prop->default_col = SDW_DEFAULT_FRAME_SHAPE_COL; -+ -+ return 0; -+} -+ -+static int mtk_sdw_set_bus_conf(struct sdw_bus *bus, -+ struct sdw_bus_params *params) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ struct sdw_master_prop *prop = &bus->prop; -+ u8 next = params->next_bank ? 1 : 0; -+ u32 mclkd; -+ -+ /* curr_dr_freq is the *double* rate; halve it to get the bus clock. */ -+ if (params->curr_dr_freq && prop->mclk_freq) { -+ mclkd = (prop->mclk_freq / params->curr_dr_freq); -+ if (mclkd > 0) -+ mclkd--; -+ core_updatel(core, MCP_CLOCKCTRL(next), MCP_CLOCKCTRL_MCLKD, -+ FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -+ core->curr_clk_freq = params->curr_dr_freq / 2; -+ } -+ return 0; -+} -+ -+/* ======================================================================= -+ * Port ops -+ * ======================================================================= -+ */ -+ -+/* Source: word length, flow mode, data mode */ -+static int mtk_sdw_dpn_set_port_params(struct sdw_bus *bus, -+ struct sdw_port_params *params, -+ unsigned int bank) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ unsigned int p = params->num; -+ u32 cfg; -+ -+ cfg = core_readl(core, MCP_DPN_CONFIG(p, bank)); -+ -+ /* Bits per sample: encoded as (bps - 1). */ -+ u32p_replace_bits(&cfg, params->bps - 1, MCP_DPN_CONFIG_WL); -+ /* Port flow mode (isochronous=0 / async=1).*/ -+ u32p_replace_bits(&cfg, params->flow_mode, MCP_DPN_CONFIG_PFM); -+ /* Test/normal data mode. */ -+ u32p_replace_bits(&cfg, params->data_mode, MCP_DPN_CONFIG_PDM); -+ -+ core_writel(core, MCP_DPN_CONFIG(p, bank), cfg); -+ return 0; -+} -+ -+/* sample interval, block offsets, h-ctrl, BGC/BPM */ -+static int -+mtk_sdw_dpn_set_port_transport_params(struct sdw_bus *bus, -+ struct sdw_transport_params *params, -+ enum sdw_reg_bank bank) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ unsigned int p = params->port_num; -+ u8 bk = (bank == SDW_BANK1) ? 1 : 0; -+ u32 cfg, offsetctrl, hctrl; -+ -+ /* BGC and BPM live in DPN_CONFIG alongside WL/PFM/PDM. */ -+ cfg = core_readl(core, MCP_DPN_CONFIG(p, bk)); -+ u32p_replace_bits(&cfg, params->blk_grp_ctrl, MCP_DPN_CONFIG_BGC); -+ u32p_replace_bits(&cfg, params->blk_pkg_mode, MCP_DPN_CONFIG_BPM); -+ core_writel(core, MCP_DPN_CONFIG(p, bk), cfg); -+ -+ /* Sample interval: encoded as (interval - 1). */ -+ core_writel(core, MCP_DPN_SAMPLECTRL(p, bk), -+ FIELD_PREP(MCP_DPN_SAMPLECTRL_INTERVAL, -+ params->sample_interval - 1)); -+ -+ /* Block offsets 1 and 2. */ -+ offsetctrl = FIELD_PREP(MCP_DPN_OFFSETCTRL_OFFSET1, params->offset1) | -+ FIELD_PREP(MCP_DPN_OFFSETCTRL_OFFSET2, params->offset2); -+ core_writel(core, MCP_DPN_OFFSETCTRL(p, bk), offsetctrl); -+ -+ /* Horizontal start/stop and lane control. */ -+ hctrl = FIELD_PREP(MCP_DPN_HCTRL_HSTART, params->hstart) | -+ FIELD_PREP(MCP_DPN_HCTRL_HSTOP, params->hstop) | -+ FIELD_PREP(MCP_DPN_HCTRL_LANECTRL, params->lane_ctrl); -+ core_writel(core, MCP_DPN_HCTRL(p, bk), hctrl); -+ -+ return 0; -+} -+ -+static int mtk_sdw_dpn_port_enable_ch(struct sdw_bus *bus, -+ struct sdw_enable_ch *enable_ch, -+ unsigned int bank) -+{ -+ struct mtk_sdw_core *core = bus_to_core(bus); -+ unsigned int p = enable_ch->port_num; -+ u32 val = 0; -+ -+ if (enable_ch->enable) -+ val = FIELD_PREP(MCP_DPN_CHANNELEN_EN, enable_ch->ch_mask); -+ -+ core_writel(core, MCP_DPN_CHANNELEN(p, bank), val); -+ return 0; -+} -+ -+void mtk_sdw_core_dump_dpn_regs(struct mtk_sdw_core *core, unsigned int port, -+ const char *tag) -+{ -+ struct sdw_bus *bus = &core->bus; -+ int bk; -+ -+ dev_dbg(core->dev, -+ "%s: port %u curr_bank=%d next_bank=%d\n", -+ tag, port, bus->params.curr_bank, bus->params.next_bank); -+ -+ for (bk = 0; bk < 2; bk++) { -+ u32 config = core_readl(core, MCP_DPN_CONFIG(port, bk)); -+ u32 channelen = core_readl(core, MCP_DPN_CHANNELEN(port, bk)); -+ u32 samplectrl = core_readl(core, MCP_DPN_SAMPLECTRL(port, bk)); -+ u32 offsetctrl = core_readl(core, MCP_DPN_OFFSETCTRL(port, bk)); -+ u32 hctrl = core_readl(core, MCP_DPN_HCTRL(port, bk)); -+ -+ dev_dbg(core->dev, -+ "%s: port %u bank%d:\n" -+ "CONFIG=0x%08x (wl=%lu pfm=%lu pdm=%lu bgc=%lu bpm=%lu)\n" -+ "CHANNELEN=0x%08x\n" -+ "SAMPLECTRL=0x%08x (interval=%lu)\n" -+ "OFFSETCTRL=0x%08x (off1=%lu off2=%lu)\n" -+ "HCTRL=0x%08x (hstart=%lu hstop=%lu lane=%lu)\n", -+ tag, port, bk, config, -+ FIELD_GET(MCP_DPN_CONFIG_WL, config) + 1, -+ FIELD_GET(MCP_DPN_CONFIG_PFM, config), -+ FIELD_GET(MCP_DPN_CONFIG_PDM, config), -+ FIELD_GET(MCP_DPN_CONFIG_BGC, config), -+ FIELD_GET(MCP_DPN_CONFIG_BPM, config), -+ channelen, samplectrl, -+ FIELD_GET(MCP_DPN_SAMPLECTRL_INTERVAL, samplectrl) + 1, -+ offsetctrl, -+ FIELD_GET(MCP_DPN_OFFSETCTRL_OFFSET1, offsetctrl), -+ FIELD_GET(MCP_DPN_OFFSETCTRL_OFFSET2, offsetctrl), -+ hctrl, -+ FIELD_GET(MCP_DPN_HCTRL_HSTART, hctrl), -+ FIELD_GET(MCP_DPN_HCTRL_HSTOP, hctrl), -+ FIELD_GET(MCP_DPN_HCTRL_LANECTRL, hctrl)); -+ } -+} -+EXPORT_SYMBOL_GPL(mtk_sdw_core_dump_dpn_regs); -+ -+const struct sdw_master_port_ops mtk_sdw_core_port_ops = { -+ .dpn_set_port_params = mtk_sdw_dpn_set_port_params, -+ .dpn_set_port_transport_params = mtk_sdw_dpn_set_port_transport_params, -+ .dpn_port_enable_ch = mtk_sdw_dpn_port_enable_ch, -+}; -+ -+const struct sdw_master_ops mtk_sdw_core_ops = { -+ .read_prop = mtk_sdw_read_prop, -+ .read_ping_status = mtk_sdw_read_ping_status, -+ .xfer_msg = mtk_sdw_xfer_msg, -+ .set_bus_conf = mtk_sdw_set_bus_conf, -+}; -+ -+static int mtk_do_config_update(struct mtk_sdw_core *core) -+{ -+ u32 val; -+ int ret; -+ -+ core_updatel(core, MCP_CONFIGUPDATE, MCP_CONFIGUPDATE_CU, -+ MCP_CONFIGUPDATE_CU); -+ ret = readl_poll_timeout(core->regs + MCP_CONFIGUPDATE, val, -+ !(val & MCP_CONFIGUPDATE_CU), 100, 2000); -+ if (ret) { -+ dev_err(core->dev, "config update timeout\n"); -+ return ret; -+ } -+ return 0; -+} -+ -+static int mtk_init_clock_ctrl(struct mtk_sdw_core *core) -+{ -+ struct sdw_bus *bus = &core->bus; -+ struct sdw_master_prop *prop = &bus->prop; -+ int c; -+ int r; -+ u32 val; -+ -+ dev_dbg(core->dev, "mclk %d max %d row %d col %d\n", -+ prop->mclk_freq, -+ prop->max_clk_freq, -+ prop->default_row, -+ prop->default_col); -+ -+ /* Set clock divider */ -+ if (bus->params.curr_dr_freq && prop->mclk_freq) { -+ u32 mclkd = (prop->mclk_freq / bus->params.curr_dr_freq); -+ -+ if (mclkd > 0) -+ mclkd--; -+ core_updatel(core, MCP_CLOCKCTRL_B0, MCP_CLOCKCTRL_MCLKD, -+ FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -+ core_updatel(core, MCP_CLOCKCTRL_B1, MCP_CLOCKCTRL_MCLKD, -+ FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -+ } -+ -+ r = sdw_find_row_index(prop->default_row); -+ c = sdw_find_col_index(prop->default_col); -+ val = FIELD_PREP(MCP_FRAMESHAPE_NC, c) | -+ FIELD_PREP(MCP_FRAMESHAPE_NR, r); -+ -+ core_updatel(core, MCP_FRAMESHAPEINIT, -+ (MCP_FRAMESHAPE_NC | MCP_FRAMESHAPE_NR), val); -+ -+ if (prop->default_frame_rate % SDW_GSYNC_HZ) { -+ dev_warn(core->dev, -+ "[%u] FrameRate:%u not aligned with GSYNC:%d", -+ bus->link_id, prop->default_frame_rate, SDW_GSYNC_HZ); -+ } -+ -+ val = prop->default_frame_rate / SDW_GSYNC_HZ; -+ val = FIELD_PREP(MCP_SSP_CTRL_SSP_INTERVAL, val); -+ -+ core_updatel(core, MCP_SSP_CTRL_B0, MCP_SSP_CTRL_SSP_INTERVAL, val); -+ core_updatel(core, MCP_SSP_CTRL_B1, MCP_SSP_CTRL_SSP_INTERVAL, val); -+ -+ return 0; -+} -+ -+static int mtk_init_control_setting(struct mtk_sdw_core *core) -+{ -+ u32 val; -+ u32 mask; -+ -+ mask = MCP_CONTROL_RST_DELAY | MCP_CONTROL_CMD_RST | -+ MCP_CONTROL_CMD_ACCEPT_MODE; -+ -+ val = FIELD_PREP(MCP_CONTROL_RST_DELAY, 1) | MCP_CONTROL_CMD_RST; -+ -+ core_updatel(core, MCP_CONTROL, mask, val); -+ -+ return mtk_do_config_update(core); -+} -+ -+static int mtk_init_config_setting(struct mtk_sdw_core *core) -+{ -+ u32 val; -+ u32 mask; -+ -+ mask = MCP_CONFIG_MCR | MCP_CONFIG_OP_MODE; -+ -+ val = FIELD_PREP(MCP_CONFIG_MCR, SDW_DEFAULT_MAX_CMD_RETRY) | -+ FIELD_PREP(MCP_CONFIG_OP_MODE, MCP_OP_MODE_NORMAL); -+ -+ core_updatel(core, MCP_CONFIG, mask, val); -+ -+ return mtk_do_config_update(core); -+} -+ -+static void mtk_sdw_enable_master_irq(struct mtk_sdw_core *core, bool enable) -+{ -+ core_updatel(core, MCP_INTMASK, (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP), -+ enable ? (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP) : 0); -+} -+ -+void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) -+{ -+ if (enable) { -+ core_writel(core, MCP_SLAVEINTMASK0, MCP_SLAVE_INTMASK0_MASK); -+ core_writel(core, MCP_SLAVEINTMASK1, MCP_SLAVE_INTMASK1_MASK); -+ } else { -+ core_writel(core, MCP_SLAVEINTMASK0, 0); -+ core_writel(core, MCP_SLAVEINTMASK1, 0); -+ } -+ -+ mtk_sdw_enable_slave_irq(core, enable); -+ -+ mtk_sdw_enable_master_irq(core, enable); -+ -+ core->interrupt_enabled = enable; -+ -+ if (!enable) -+ cancel_work_sync(&core->work); -+ -+ core_updatel(core, MCP_INTMASK, MCP_INT_IRQ, -+ enable ? MCP_INT_IRQ : 0); -+} -+ -+void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable) -+{ -+ core_updatel(core, MCP_INTMASK, MCP_INT_SLV_MASK, -+ enable ? MCP_INT_SLV_MASK : 0); -+} -+ -+/* -+ * slave IRQ handling -+ */ -+static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, -+ u64 slave_intstat) -+{ -+ enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; -+ bool need_handle_slave = false; -+ u32 intstat; -+ u32 val; -+ int i, set_status; -+ -+ memset(status, 0, sizeof(status)); -+ -+ for (i = 0; i <= SDW_MAX_DEVICES; i++) { -+ intstat = MCP_SLAVEINTSTAT_STATUS(slave_intstat, i); -+ -+ set_status = 0; -+ -+ if (intstat) { -+ need_handle_slave = true; -+ -+ if (intstat & MCP_SLAVEINTSTAT_RESERVED) { -+ status[i] = SDW_SLAVE_RESERVED; -+ set_status++; -+ } -+ -+ if (intstat & MCP_SLAVEINTSTAT_ALERT) { -+ status[i] = SDW_SLAVE_ALERT; -+ set_status++; -+ } -+ -+ if (intstat & MCP_SLAVEINTSTAT_ATTACHED) { -+ status[i] = SDW_SLAVE_ATTACHED; -+ set_status++; -+ } -+ -+ if (intstat & MCP_SLAVEINTSTAT_NOT_PRESENT) { -+ status[i] = SDW_SLAVE_UNATTACHED; -+ set_status++; -+ } -+ } -+ -+ if (set_status != 1) { -+ val = core_get_slave_status(core, i); -+ -+ switch (val) { -+ case 0: -+ status[i] = SDW_SLAVE_UNATTACHED; -+ break; -+ case 1: -+ status[i] = SDW_SLAVE_ATTACHED; -+ break; -+ case 2: -+ status[i] = SDW_SLAVE_ALERT; -+ break; -+ case 3: -+ default: -+ status[i] = SDW_SLAVE_RESERVED; -+ break; -+ } -+ } -+ } -+ -+ if (need_handle_slave) -+ return sdw_handle_slave_status(&core->bus, status); -+ -+ return 0; -+} -+ -+static void mtk_sdw_slave_status_work(struct work_struct *work) -+{ -+ struct mtk_sdw_core *core = -+ container_of(work, struct mtk_sdw_core, work); -+ u32 stat0; -+ u32 stat1; -+ u32 dev0_stat; -+ int retries = 0; -+ u64 slv_intstat; -+ -+ core_writel(core, MCP_INTSTAT, MCP_INT_SLV_MASK); -+ -+ stat0 = core_readl(core, MCP_SLAVEINTSTAT0); -+ stat1 = core_readl(core, MCP_SLAVEINTSTAT1); -+ -+ core_writel(core, MCP_SLAVEINTSTAT0, stat0); -+ core_writel(core, MCP_SLAVEINTSTAT1, stat1); -+ dev_dbg_ratelimited(core->dev, "Slave intstat0: 0x%x, intstat1 0x%x\n", -+ stat0, stat1); -+ -+ slv_intstat = ((u64)stat1 << 32) | stat0; -+ -+ do { -+ mtk_sdw_update_slave_status(core, slv_intstat); -+ -+ dev0_stat = core_get_slave_status(core, 0); -+ -+ if (dev0_stat == MCP_SLAVESTAT_ATTACHED) { -+ slv_intstat = MCP_SLAVEINTSTAT_ATTACHED; -+ dev_info(core->dev, -+ "[%u] slave attached Dev0Stat:0x%x Retries:%d", -+ core->bus.link_id, dev0_stat, retries); -+ } else { -+ break; -+ } -+ -+ } while (retries++ < SDW_MAX_DEVICES); -+ -+ mtk_sdw_enable_slave_irq(core, true); -+} -+ -+static void mtk_sdw_handle_master_dp_interrupt(struct mtk_sdw_core *core) -+{ -+ u32 portintstatus = core_readl(core, MCP_PORTINTSTAT); -+ u32 pdistatus = core_readl(core, MCP_PDISTAT); -+ struct sdw_bus *bus = &core->bus; -+ -+ dev_info(core->dev, "[%u]PortIntStatus:0x%x PdiStatus:0x%x\n", -+ bus->link_id, portintstatus, pdistatus); -+ -+ if (portintstatus) -+ core_writel(core, MCP_PORTINTSTAT, portintstatus); -+ -+ if (pdistatus) -+ core_writel(core, MCP_PDISTAT, pdistatus); -+} -+ -+static void mtk_sdw_recalc_block_offset(struct sdw_port_runtime *p_rt) -+{ -+ struct sdw_transport_params *tp = &p_rt->transport_params; -+ int offset; -+ -+ offset = (tp->offset2 << 8) + tp->offset1; -+ offset -= 1; -+ -+ tp->offset1 = offset & 0xFF; -+ tp->offset2 = offset >> 8; -+} -+ -+static int mtk_sdw_compute_params(struct sdw_bus *bus, -+ struct sdw_stream_runtime *stream) -+{ -+ struct sdw_master_runtime *m_rt; -+ struct sdw_slave_runtime *s_rt; -+ struct sdw_port_runtime *p_rt; -+ int ret; -+ -+ ret = sdw_compute_params(bus, stream); -+ if (ret) -+ return ret; -+ -+ /* block offset should begin from 0 */ -+ list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { -+ list_for_each_entry(p_rt, &m_rt->port_list, port_node) -+ mtk_sdw_recalc_block_offset(p_rt); -+ -+ list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) -+ list_for_each_entry(p_rt, &s_rt->port_list, port_node) -+ mtk_sdw_recalc_block_offset(p_rt); -+ } -+ -+ return 0; -+} -+ -+int mtk_sdw_core_init(struct mtk_sdw_core *core) -+{ -+ core->bus.ops = &mtk_sdw_core_ops; -+ core->bus.port_ops = &mtk_sdw_core_port_ops; -+ core->bus.compute_params = mtk_sdw_compute_params; -+ -+ INIT_WORK(&core->work, mtk_sdw_slave_status_work); -+ return 0; -+} -+ -+int mtk_sdw_core_hw_init(struct mtk_sdw_core *core) -+{ -+ int ret; -+ -+ ret = mtk_init_clock_ctrl(core); -+ if (ret) -+ return ret; -+ -+ ret = mtk_init_control_setting(core); -+ if (ret) -+ return ret; -+ -+ ret = mtk_init_config_setting(core); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+irqreturn_t mtk_sdw_core_irq(int irq, void *data) -+{ -+ struct mtk_sdw_core *core = data; -+ struct sdw_bus *bus = &core->bus; -+ u32 intstat = core_readl(core, MCP_INTSTAT); -+ u32 clearstat; -+ -+ if (!(intstat & MCP_INT_IRQ)) { -+ dev_warn(core->dev, -+ "[%u]interrupt request not enabled IntStatus:0x%x", -+ bus->link_id, intstat); -+ return IRQ_NONE; -+ } -+ -+ clearstat = intstat; -+ -+ if (intstat & MCP_INT_WAKEUP) -+ dev_err(core->dev, "[%u]wakeup IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ -+ if (intstat & MCP_INT_SLV_MASK) { -+ if (intstat & MCP_INT_SLV_RESERVED) { -+ dev_info(core->dev, "[%u]slave reserved int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ -+ if (intstat & MCP_INT_SLV_ALERT) { -+ dev_info(core->dev, -+ "[%u]slave alert int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ -+ if (intstat & MCP_INT_SLV_ATTACHED) { -+ dev_info(core->dev, -+ "[%u]slave attached int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ -+ if (intstat & MCP_INT_SLV_NOT_ATTACH) { -+ dev_info(core->dev, -+ "[%u]slave not attached int IntStatus:0x%x\n", -+ bus->link_id, intstat); -+ } -+ if (core->interrupt_enabled) { -+ schedule_work(&core->work); -+ mtk_sdw_enable_slave_irq(core, false); -+ clearstat &= ~MCP_INT_SLV_MASK; -+ } -+ } -+ if (intstat & MCP_INT_DP_INT) { -+ dev_info(core->dev, "[%u]dp int IntStatus:0x%x\n", bus->link_id, -+ intstat); -+ -+ mtk_sdw_handle_master_dp_interrupt(core); -+ } -+ -+ if (intstat & (MCP_INT_CTL_BUS_CLASH)) -+ dev_err(core->dev, "[%u]control bus clash 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & (MCP_INT_DATA_BUS_CLASH)) -+ dev_err(core->dev, "[%u]data bus clash 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & MCP_INT_PARITY_ERR) -+ dev_err(core->dev, "[%u]parity error 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & MCP_INT_CMD_ERR) -+ dev_err(core->dev, "[%u]command error 0x%x\n", bus->link_id, -+ intstat); -+ -+ if (intstat & MCP_INT_RXWL) -+ dev_info(core->dev, "[%u]rw wl 0x%x\n", bus->link_id, intstat); -+ -+ dev_info(core->dev, "[%u]ClearStatus 0x%x, IntStatus 0x%x\n", -+ bus->link_id, clearstat, intstat); -+ -+ core_writel(core, MCP_INTSTAT, clearstat); -+ -+ return IRQ_HANDLED; -+} -+ -+void mtk_sdw_configure_pdi_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *params) -+{ -+ u32 offset; -+ u32 val; -+ u32 mask; -+ -+ offset = MCP_PDIN_CONFIG(params->pdi_num); -+ -+ mask = MCP_PDIN_CONFIG_SOFTRST | MCP_PDIN_CONFIG_CHANNELMASK | -+ MCP_PDIN_CONFIG_PORTNUM; -+ -+ val = MCP_PDIN_CONFIG_SOFTRST | -+ FIELD_PREP(MCP_PDIN_CONFIG_CHANNELMASK, params->ch_mask) | -+ FIELD_PREP(MCP_PDIN_CONFIG_PORTNUM, params->port_num); -+ -+ core_updatel(core, offset, mask, val); -+} -+ -+void mtk_sdw_clear_pdi_settings(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *pdi) -+{ -+ u32 offset; -+ u32 val; -+ u32 mask; -+ -+ offset = MCP_PDIN_CONFIG(pdi->pdi_num); -+ -+ /* clear pdi fifo */ -+ mask = MCP_PDIN_CONFIG_SOFTRST; -+ val = MCP_PDIN_CONFIG_SOFTRST; -+ core_updatel(core, offset, mask, val); -+ -+ /* clear pdi channel mask */ -+ mask = MCP_PDIN_CONFIG_CHANNELMASK; -+ val = FIELD_PREP(MCP_PDIN_CONFIG_CHANNELMASK, 0); -+ core_updatel(core, offset, mask, val); -+} -+ -+void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_port_params *params, u32 dir) -+{ -+ u32 offset; -+ u32 val = 0; -+ u32 mask; -+ -+ offset = MCP_DPN_PORTCTRL(params->port_num); -+ mask = MCP_DPN_PORTCTRL_DIR | MCP_DPN_PORTCTRL_BPT_EN | -+ MCP_DPN_PORTCTRL_BPT_TYPE; -+ if (dir == SDW_DATA_DIR_RX) -+ val |= MCP_DPN_PORTCTRL_DIR; -+ -+ if (params->port_num == 0) /* bpt rx? */ -+ val |= FIELD_PREP(MCP_DPN_PORTCTRL_BPT_EN, params->bpt_en) | -+ FIELD_PREP(MCP_DPN_PORTCTRL_BPT_TYPE, -+ params->bpt_payload_type); -+ -+ core_updatel(core, offset, mask, val); -+} -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.h b/drivers/soundwire/mediatek/mtk-sdw-core.h -new file mode 100644 -index 0000000000..4708a10865 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.h -@@ -0,0 +1,234 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master — STABLE controller core. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_CORE_H -+#define __MTK_SDW_CORE_H -+ -+#include -+ -+#define SDW_GSYNC_HZ (8000) -+#define SDW_DEFAULT_MAX_CMD_RETRY (5) -+/* ======================================================================= -+ * MCP (Master Control Port) registers -+ * ======================================================================= -+ */ -+#define MCP_DP_SIZE 128 -+#define MCP_PDI_SIZE 16 -+ -+#define MCP_CONFIG 0x0000 -+#define MCP_CONTROL 0x0004 -+#define MCP_CMDCTRL 0x0008 -+#define MCP_SSPSTAT 0x000c -+#define MCP_FRAMESHAPE 0x0010 -+#define MCP_FRAMESHAPEINIT 0x0014 -+#define MCP_CONFIGUPDATE 0x0018 -+#define MCP_PHYCTRL 0x001c -+#define MCP_SSP_CTRL_B0 0x0020 -+#define MCP_SSP_CTRL_B1 0x0028 -+#define MCP_CLOCKCTRL_B0 0x0030 -+#define MCP_CLOCKCTRL_B1 0x0038 -+#define MCP_STAT 0x0040 -+#define MCP_INTSTAT 0x0044 -+#define MCP_INTMASK 0x0048 -+#define MCP_INTSET 0x004c -+#define MCP_SLAVESTAT 0x0050 -+#define MCP_SLAVEINTSTAT0 0x0054 -+#define MCP_SLAVEINTSTAT1 0x0058 -+#define MCP_SLAVEINTMASK0 0x005c -+#define MCP_SLAVEINTMASK1 0x0060 -+#define MCP_PORTINTSTAT 0x0064 -+#define MCP_PDISTAT 0x006c -+#define MCP_FIFOLEVEL 0x0078 -+#define MCP_FIFOSTAT 0x007c -+#define MCP_COMMAND(n) (0x0080 + (n) * 4) -+ -+#define MCP_DPN_CONFIG_B0(n) (0x0100 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_CHANNELEN_B0(n) (0x0104 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_SAMPLECTRL_B0(n) (0x0108 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_OFFSETCTRL_B0(n) (0x010c + (n) * MCP_DP_SIZE) -+#define MCP_DPN_HCTRL_B0(n) (0x0110 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_CONFIG_B1(n) (0x0118 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_CHANNELEN_B1(n) (0x011c + (n) * MCP_DP_SIZE) -+#define MCP_DPN_SAMPLECTRL_B1(n) (0x0120 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_OFFSETCTRL_B1(n) (0x0124 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_HCTRL_B1(n) (0x0128 + (n) * MCP_DP_SIZE) -+#define MCP_DPN_PORTCTRL(n) (0x0130 + ((n) & 0xf) * MCP_DP_SIZE) -+#define MCP_PDIN_CONFIG(n) (0x1100 + ((n) & 0xf) * MCP_PDI_SIZE) -+ -+/* Bank selectors: each takes (port, bank) / (bank) */ -+#define MCP_DPN_CONFIG(n, b) \ -+ ((b) ? MCP_DPN_CONFIG_B1(n) : MCP_DPN_CONFIG_B0(n)) -+#define MCP_DPN_CHANNELEN(n, b) \ -+ ((b) ? MCP_DPN_CHANNELEN_B1(n) : MCP_DPN_CHANNELEN_B0(n)) -+#define MCP_DPN_SAMPLECTRL(n, b) \ -+ ((b) ? MCP_DPN_SAMPLECTRL_B1(n) : MCP_DPN_SAMPLECTRL_B0(n)) -+#define MCP_DPN_OFFSETCTRL(n, b) \ -+ ((b) ? MCP_DPN_OFFSETCTRL_B1(n) : MCP_DPN_OFFSETCTRL_B0(n)) -+#define MCP_DPN_HCTRL(n, b) \ -+ ((b) ? MCP_DPN_HCTRL_B1(n) : MCP_DPN_HCTRL_B0(n)) -+#define MCP_CLOCKCTRL(b) ((b) ? MCP_CLOCKCTRL_B1 : MCP_CLOCKCTRL_B0) -+ -+/* MCP_CONFIG */ -+#define MCP_CONFIG_OP_MODE GENMASK(2, 0) -+#define MCP_CONFIG_MCR GENMASK(27, 24) -+#define MCP_OP_MODE_NORMAL 0 -+ -+/* MCP_CONTROL */ -+#define MCP_CONTROL_CMD_ACCEPT_MODE BIT(1) -+#define MCP_CONTROL_CLOCK_STOP_CLR BIT(2) -+#define MCP_CONTROL_HW_BUS_RST BIT(4) -+#define MCP_CONTROL_SOFT_RST BIT(6) -+#define MCP_CONTROL_CMD_RST BIT(7) -+#define MCP_CONTROL_RST_DELAY GENMASK(10, 8) -+ -+/* MCP_FRAMESHAPE(INIT) */ -+#define MCP_FRAMESHAPE_NC GENMASK(2, 0) /* columns index */ -+#define MCP_FRAMESHAPE_NR GENMASK(7, 3) /* rows, encoded (rows/2-1) */ -+ -+/* MCP_CONFIGUPDATE */ -+#define MCP_CONFIGUPDATE_CU BIT(0) -+ -+/* MCP_SSP_CTRL */ -+#define MCP_SSP_CTRL_SSP_INTERVAL GENMASK(7, 0) -+ -+/* MCP_CLOCKCTRL */ -+#define MCP_CLOCKCTRL_MCLKD GENMASK(7, 0) -+ -+/* MCP_STAT */ -+#define MCP_STAT_RX_NE BIT(3) -+#define MCP_STAT_CLK_STOP BIT(16) -+ -+/* MCP_INTMASK / MCP_INTSTAT */ -+#define MCP_INT_RXWL BIT(2) -+#define MCP_INT_RXNE BIT(3) -+#define MCP_INT_CMD_ERR BIT(7) -+#define MCP_INT_PARITY_ERR BIT(8) -+#define MCP_INT_DATA_BUS_CLASH BIT(9) -+#define MCP_INT_CTL_BUS_CLASH BIT(10) -+#define MCP_INT_DP_INT BIT(11) -+#define MCP_INT_SLV_NOT_ATTACH BIT(12) -+#define MCP_INT_SLV_ATTACHED BIT(13) -+#define MCP_INT_SLV_ALERT BIT(14) -+#define MCP_INT_SLV_RESERVED BIT(15) -+#define MCP_INT_WAKEUP BIT(16) -+#define MCP_INT_IRQ BIT(31) -+#define MCP_INT_SLV_MASK (MCP_INT_SLV_RESERVED | \ -+ MCP_INT_SLV_ALERT | \ -+ MCP_INT_SLV_ATTACHED | \ -+ MCP_INT_SLV_NOT_ATTACH) -+#define MCP_INT_MST_ERR_MASK (MCP_INT_RXWL | \ -+ MCP_INT_PARITY_ERR | \ -+ MCP_INT_DATA_BUS_CLASH | \ -+ MCP_INT_CTL_BUS_CLASH) -+ -+/* MCP_SLAVESTAT: 2 bits/slave; MCP_SLAVEINTSTAT: 4 bits/slave */ -+#define MCP_SLAVESTAT_STATUS(x, n) (((x) >> ((n) * 2)) & 0x3) -+#define MCP_SLAVESTAT_UNATTACHED 0x0 -+#define MCP_SLAVESTAT_ATTACHED 0x1 -+#define MCP_SLAVESTAT_ALERT 0x2 -+#define MCP_SLAVEINTSTAT_STATUS(x, n) (((x) >> ((n) * 4)) & 0xf) -+#define MCP_SLAVEINTSTAT_NOT_PRESENT BIT(0) -+#define MCP_SLAVEINTSTAT_ATTACHED BIT(1) -+#define MCP_SLAVEINTSTAT_ALERT BIT(2) -+#define MCP_SLAVEINTSTAT_RESERVED BIT(3) -+ -+/* MCP_SLAVEINTMASK */ -+#define MCP_SLAVE_INTMASK0_MASK GENMASK(31, 0) -+#define MCP_SLAVE_INTMASK1_MASK GENMASK(15, 0) -+ -+/* MCP command word. CONFIRMED: dev_addr is 4-bit [27:24]. */ -+#define MCP_CMD_READ 0x2 -+#define MCP_CMD_WRITE 0x3 -+#define MCP_CMD_SSP_TAG BIT(31) -+#define MCP_CMD_FIELD GENMASK(30, 28) -+#define MCP_CMD_DEV_ADDR GENMASK(27, 24) -+#define MCP_CMD_REG_ADDR GENMASK(23, 8) -+#define MCP_CMD_REG_DATA GENMASK(7, 0) -+ -+/* MCP command response. CONFIRMED. */ -+#define MCP_RESP_ACK BIT(0) -+#define MCP_RESP_NAK BIT(1) -+#define MCP_RESP_RDATA GENMASK(15, 8) -+ -+/* Per-port transport fields (used by streaming) */ -+#define MCP_DPN_CONFIG_PFM GENMASK(1, 0) /* port flow mode */ -+#define MCP_DPN_CONFIG_PDM GENMASK(3, 2) /* port data mode */ -+/* word length, encoded (wl-1) */ -+#define MCP_DPN_CONFIG_WL GENMASK(12, 8) -+#define MCP_DPN_CONFIG_BGC GENMASK(17, 16) /* block group control */ -+#define MCP_DPN_CONFIG_BPM BIT(18) /* block packing mode */ -+#define MCP_DPN_CHANNELEN_EN GENMASK(7, 0) -+#define MCP_DPN_SAMPLECTRL_INTERVAL GENMASK(15, 0) /* encoded (interval-1) */ -+#define MCP_DPN_OFFSETCTRL_OFFSET1 GENMASK(7, 0) -+#define MCP_DPN_OFFSETCTRL_OFFSET2 GENMASK(15, 8) -+#define MCP_DPN_HCTRL_HSTOP GENMASK(3, 0) -+#define MCP_DPN_HCTRL_HSTART GENMASK(7, 4) -+#define MCP_DPN_HCTRL_LANECTRL GENMASK(10, 8) /* data lane select */ -+ -+#define MCP_DPN_PORTCTRL_BPT_TYPE GENMASK(23, 22) -+#define MCP_DPN_PORTCTRL_BPT_EN BIT(16) -+#define MCP_DPN_PORTCTRL_DIR BIT(7) -+ -+#define MCP_PDIN_CONFIG_SOFTRST BIT(24) -+#define MCP_PDIN_CONFIG_CHANNELMASK GENMASK(15, 8) -+#define MCP_PDIN_CONFIG_PORTNUM GENMASK(4, 0) -+ -+/* ======================================================================= -+ * Core object -+ * ======================================================================= -+ */ -+struct mtk_sdw_core { -+ struct sdw_bus bus; -+ struct device *dev; -+ void __iomem *regs; -+ unsigned int curr_clk_freq; -+ bool interrupt_enabled; -+ u16 attached_slaves; -+ void *priv; -+ struct work_struct work; -+}; -+ -+struct mtk_sdw_pdi_params { -+ u32 pdi_num; -+ u32 port_num; -+ u32 ch_mask; -+}; -+ -+struct mtk_sdw_port_params { -+ u32 port_num; -+ u32 bpt_payload_type; -+ bool bpt_en; -+}; -+ -+static inline struct mtk_sdw_core *bus_to_core(struct sdw_bus *bus) -+{ -+ return container_of(bus, struct mtk_sdw_core, bus); -+} -+ -+/* ======================================================================= -+ * Core API — called by the glue -+ * ======================================================================= -+ */ -+extern const struct sdw_master_ops mtk_sdw_core_ops; -+extern const struct sdw_master_port_ops mtk_sdw_core_port_ops; -+ -+int mtk_sdw_core_init(struct mtk_sdw_core *core); -+int mtk_sdw_core_hw_init(struct mtk_sdw_core *core); -+void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable); -+void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable); -+irqreturn_t mtk_sdw_core_irq(int irq, void *data); -+void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_port_params *params, u32 dir); -+ -+void mtk_sdw_configure_pdi_params(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *params); -+void mtk_sdw_clear_pdi_settings(struct mtk_sdw_core *core, -+ struct mtk_sdw_pdi_params *pdi); -+void mtk_sdw_core_dump_dpn_regs(struct mtk_sdw_core *core, unsigned int port, -+ const char *tag); -+ -+#endif /* __MTK_SDW_CORE_H */ -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.c b/drivers/soundwire/mediatek/mtk-sdw-mach.c -new file mode 100644 -index 0000000000..582482b43e ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.c -@@ -0,0 +1,167 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire audio machine selection (codec-combination tables). -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#include -+#include -+#include -+#include "mtk-sdw-mach.h" -+ -+static const struct snd_soc_acpi_endpoint rt1320_endpoints[] = { -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 0, -+ .group_id = 1, -+ }, -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 1, -+ .group_id = 1, -+ }, -+}; -+ -+static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { -+ { -+ .num = 0, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+ { -+ .num = 2, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+}; -+ -+/* -+ * Config 0: SDW0 = RT1320 (amp), SDW1 = RT712 (jack codec). -+ */ -+static const struct snd_soc_acpi_adr_device rt1320_l0_adr[] = { -+ { -+ .adr = 0x000030025D132001ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[0], -+ .name_prefix = "rt1320-1", -+ }, -+ { -+ .adr = 0x000032025D132001ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[1], -+ .name_prefix = "rt1320-2", -+ }, -+}; -+ -+static const struct snd_soc_acpi_adr_device rt712_l1_adr[] = { -+ { -+ .adr = 0x000130025D071201ull, -+ .num_endpoints = ARRAY_SIZE(rt712_endpoints), -+ .endpoints = rt712_endpoints, -+ .name_prefix = "rt712", -+ }, -+}; -+ -+static const struct snd_soc_acpi_link_adr mtk_sdw_rt1320_l0_rt712_l1[] = { -+ { -+ .mask = BIT(0), -+ .num_adr = ARRAY_SIZE(rt1320_l0_adr), -+ .adr_d = rt1320_l0_adr, -+ }, -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(rt712_l1_adr), -+ .adr_d = rt712_l1_adr, -+ }, -+ {} -+}; -+ -+static struct snd_soc_acpi_mach mtk_sdw_machines[] = { -+ { -+ .link_mask = BIT(0) | BIT(1), -+ .links = mtk_sdw_rt1320_l0_rt712_l1, -+ .drv_name = "mtk_sdw_mc", -+ }, -+ {} -+}; -+ -+static void mtk_sdw_log_peripheral(struct device *dev, -+ struct sdw_slave *slave) -+{ -+ dev_info(dev, -+ "[%d] class=0x%02x mfg=0x%04x part=0x%04x uniq=0x%x ver=0x%x\n", -+ slave->bus->link_id, slave->id.class_id, slave->id.mfg_id, -+ slave->id.part_id, slave->id.unique_id, slave->id.sdw_version); -+} -+ -+static struct sdw_peripherals *mtk_sdw_get_peripherals(struct mtk_sdw *mst) -+{ -+ struct sdw_peripherals *peripherals; -+ struct sdw_slave *slave; -+ struct sdw_bus *bus; -+ int max_peripherals_num; -+ int i, idx = 0; -+ -+ max_peripherals_num = mst->num_links * SDW_MAX_DEVICES; -+ -+ peripherals = kmalloc_flex(*peripherals, array, max_peripherals_num, -+ GFP_KERNEL); -+ if (!peripherals) -+ return NULL; -+ -+ for (i = 0; i < mst->num_links; i++) { -+ bus = &mst->links[i].core.bus; -+ mutex_lock(&bus->bus_lock); -+ list_for_each_entry(slave, &bus->slaves, node) { -+ if (idx >= max_peripherals_num) { -+ dev_warn(mst->dev, "slave count exceeds capacity, truncating"); -+ break; -+ } -+ peripherals->array[idx++] = slave; -+ mtk_sdw_log_peripheral(mst->dev, slave); -+ } -+ mutex_unlock(&bus->bus_lock); -+ } -+ peripherals->num_peripherals = idx; -+ -+ return peripherals; -+} -+ -+struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst) -+{ -+ struct sdw_peripherals *peripherals; -+ struct snd_soc_acpi_mach *mach; -+ const struct snd_soc_acpi_link_adr *link; -+ -+ peripherals = mtk_sdw_get_peripherals(mst); -+ if (!peripherals) -+ return NULL; -+ -+ if (!peripherals->num_peripherals) { -+ dev_dbg(mst->dev, "no SoundWire peripherals enumerated\n"); -+ kfree(peripherals); -+ return NULL; -+ } -+ -+ for (mach = mtk_sdw_machines; mach->link_mask; mach++) { -+ for (link = mach->links; link && link->num_adr; link++) { -+ if (!snd_soc_acpi_sdw_link_slaves_found(mst->dev, link, -+ peripherals)) -+ break; -+ } -+ if (link && !link->num_adr) { -+ mach->mach_params.links = mach->links; -+ mach->mach_params.link_mask = mach->link_mask; -+ kfree(peripherals); -+ return mach; -+ } -+ } -+ dev_dbg(mst->dev, "no SoundWire machine matched\n"); -+ kfree(peripherals); -+ return NULL; -+} -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.h b/drivers/soundwire/mediatek/mtk-sdw-mach.h -new file mode 100644 -index 0000000000..158aae2652 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire audio machine selection (codec-combination tables). -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_MACH_H -+#define __MTK_SDW_MACH_H -+ -+#include "mtk-sdw-common.h" -+ -+struct snd_soc_acpi_mach; -+ -+/* mtk-sdw-mach.c: match enumerated SoundWire peripherals against the codec- -+ * combination tables; returns the machine row to spawn, or NULL. -+ */ -+struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst); -+ -+#endif /* __MTK_SDW_MACH_H */ -diff --git a/drivers/soundwire/mediatek/mtk-sdw-top.c b/drivers/soundwire/mediatek/mtk-sdw-top.c -new file mode 100644 -index 0000000000..edc412f4e1 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-top.c -@@ -0,0 +1,301 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire master — AFE TOP control -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "mtk-sdw-top.h" -+ -+static const struct mtk_sdw_top_cfg mtk_sdw_top_cfgs[MTK_SDW_TOP_VER_MAX] = { -+ [MTK_SDW_TOP_VER_0] = { -+ .name = "hw_8901", -+ .reg = { -+ .tzd_delay_reg = SDW_TOP_CON0, -+ .tzd_delay_sel = GENMASK(5, 3), -+ .tzd_inverse = BIT(2), -+ .tzd_delay_en = BIT(1), -+ .phy_delay_reg = SDW_TOP_CON1, -+ .phy_delay_sel = GENMASK(3, 1), -+ .phy_double_delay_sel = GENMASK(6, 4), -+ }, -+ }, -+}; -+ -+static u32 topcon_readl(struct mtk_sdw *mst, u32 off) -+{ -+ return readl(mst->top_con + off); -+} -+ -+static void topcon_writel(struct mtk_sdw *mst, u32 off, u32 val) -+{ -+ writel(val, mst->top_con + off); -+} -+ -+static void topcon_updatel(struct mtk_sdw *mst, u32 off, u32 mask, u32 val) -+{ -+ u32 tmp = topcon_readl(mst, off); -+ -+ topcon_writel(mst, off, (tmp & ~mask) | (val & mask)); -+} -+ -+static u32 toppdi_readl(struct mtk_sdw *mst, u32 off) -+{ -+ return readl(mst->top_pdi + off); -+} -+ -+static void toppdi_writel(struct mtk_sdw *mst, u32 off, u32 val) -+{ -+ writel(val, mst->top_pdi + off); -+} -+ -+static void toppdi_updatel(struct mtk_sdw *mst, u32 off, u32 mask, u32 val) -+{ -+ u32 tmp = toppdi_readl(mst, off); -+ -+ toppdi_writel(mst, off, (tmp & ~mask) | (val & mask)); -+} -+ -+static inline u32 mtk_field_prep(u32 mask, u32 val) -+{ -+ if (!mask) -+ return 0; -+ return (val << __bf_shf(mask)) & mask; -+} -+ -+int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver) -+{ -+ int ver_id; -+ -+ switch (hw_ver) { -+ case MTK_SDW_HW_VER_MT8901: -+ case MTK_SDW_HW_VER_MT8971: -+ ver_id = MTK_SDW_TOP_VER_0; -+ break; -+ default: -+ dev_err(mst->dev, "unsupported hw-ver %d\n", hw_ver); -+ return -EINVAL; -+ } -+ -+ mst->top_cfg = &mtk_sdw_top_cfgs[ver_id]; -+ dev_info(mst->dev, "AFE TOP variant: %s (hw-ver %u)\n", -+ mst->top_cfg->name, mst->hw_ver); -+ return 0; -+} -+ -+void mtk_sdw_top_init_settings(struct mtk_sdw *mst) -+{ -+ topcon_updatel(mst, SDW_TOP_CON0, SDW_TOP_CON0_GSYNC_DIR_CTRL, -+ SDW_TOP_CON0_GSYNC_DIR_CTRL); -+} -+ -+void mtk_sdw_top_configure_delays(struct mtk_sdw *mst) -+{ -+ u32 val = 0; -+ u32 mask; -+ const struct mtk_sdw_top_reg *top_reg = &mst->top_cfg->reg; -+ -+ mask = top_reg->tzd_delay_sel | top_reg->tzd_inverse | -+ top_reg->tzd_delay_en; -+ val |= mtk_field_prep(top_reg->tzd_delay_sel, mst->tzd_delay - 1); -+ if (mst->tzd_inverse) -+ val |= top_reg->tzd_inverse; -+ if (mst->tzd_delay) -+ val |= top_reg->tzd_delay_en; -+ topcon_updatel(mst, top_reg->tzd_delay_reg, mask, val); -+ -+ val = 0; -+ mask = top_reg->phy_delay_sel | top_reg->phy_double_delay_sel; -+ val |= mtk_field_prep(top_reg->phy_delay_sel, mst->phy_delay); -+ val |= mtk_field_prep(top_reg->phy_double_delay_sel, -+ mst->phy_double_delay); -+ -+ topcon_updatel(mst, top_reg->phy_delay_reg, mask, val); -+} -+ -+void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, -+ struct mtk_sdw_top_pdi_params *param) -+{ -+ u32 val = 0; -+ u32 mask = 0; -+ -+ mask |= SDW_TOP_PDI_GROUP_SYNC; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_SLAVE_MODE, param->slave_mode); -+ mask |= SDW_TOP_PDI_SLAVE_MODE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_BRA_SLAVE, param->bra_slave); -+ mask |= SDW_TOP_PDI_BRA_SLAVE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_BRA_EOP, param->bra_eop); -+ mask |= SDW_TOP_PDI_BRA_EOP; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_BRA_MODE, param->bra_mode); -+ mask |= SDW_TOP_PDI_BRA_MODE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_DMIC_1XEN, param->dmic_1xen); -+ mask |= SDW_TOP_PDI_DMIC_1XEN; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_PDM_ONE_WIRE, param->pdm_one_wire); -+ mask |= SDW_TOP_PDI_PDM_ONE_WIRE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_PDM_MODE, param->pdm_mode); -+ mask |= SDW_TOP_PDI_PDM_MODE; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_HD_SEL, param->hd_sel); -+ mask |= SDW_TOP_PDI_HD_SEL; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_CLOCK, param->clock); -+ mask |= SDW_TOP_PDI_CLOCK; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_PDM2PCM, param->pdm2pcm); -+ mask |= SDW_TOP_PDI_PDM2PCM; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_IP_SEL, param->sdw_ip_sel); -+ mask |= SDW_TOP_PDI_IP_SEL; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_DOMAIN, param->domain); -+ mask |= SDW_TOP_PDI_DOMAIN; -+ -+ val |= FIELD_PREP(SDW_TOP_PDI_FS, param->fs); -+ mask |= SDW_TOP_PDI_FS; -+ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), mask, val); -+} -+ -+static void mtk_sdw_top_enable_pdi_engen(struct mtk_sdw *mst, u32 pdi, -+ bool enable) -+{ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_EN, -+ enable ? SDW_TOP_PDI_EN : 0); -+} -+ -+static void mtk_sdw_top_enable_group_sync(struct mtk_sdw *mst, u32 pdi, -+ bool enable) -+{ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_GROUP_SYNC_ON, -+ enable ? SDW_TOP_PDI_GROUP_SYNC_ON : 0); -+} -+ -+static void mtk_sdw_top_config_group_sync(struct mtk_sdw *mst, u32 pdi, -+ u32 group) -+{ -+ toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_GROUP_SYNC, -+ FIELD_PREP(SDW_TOP_PDI_GROUP_SYNC, group)); -+} -+ -+int mtk_sdw_top_group_sync_config_get(struct mtk_sdw *mst, u8 id, u32 *cfg) -+{ -+ if (id > MTK_SDW_MAX_GROUP_SYNC) -+ return -EINVAL; -+ else if (id == GROUP_SYNC_NONE) -+ *cfg = 0; -+ else -+ *cfg = BIT(id - 1); -+ -+ return 0; -+} -+ -+int mtk_sdw_top_group_sync_acquire(struct mtk_sdw *mst, bool is_tx) -+{ -+ u8 min_id = is_tx ? TOP_GROUP_SYNC_TX_MIN_ID : TOP_GROUP_SYNC_RX_MIN_ID; -+ u8 max_id = is_tx ? TOP_GROUP_SYNC_TX_MAX_ID : TOP_GROUP_SYNC_RX_MAX_ID; -+ int best = -1; -+ int best_refcnt = INT_MAX; -+ int i, idx; -+ -+ guard(mutex)(&mst->group_lock); -+ -+ for (i = 0; i < MTK_SDW_MAX_GROUP_SYNC; i++) { -+ idx = is_tx ? i : (MTK_SDW_MAX_GROUP_SYNC - 1 - i); -+ -+ if (idx < min_id - 1 || idx > max_id - 1) -+ continue; -+ if (mst->group_refcnt[idx] < best_refcnt) { -+ best = idx; -+ best_refcnt = mst->group_refcnt[idx]; -+ } -+ } -+ if (best < 0) -+ return -EINVAL; -+ -+ mst->group_refcnt[best]++; -+ return best + 1; /* 1-based id */ -+} -+ -+void mtk_sdw_top_group_sync_release(struct mtk_sdw *mst, u8 id) -+{ -+ if (id == 0 || id > MTK_SDW_MAX_GROUP_SYNC) -+ return; -+ -+ guard(mutex)(&mst->group_lock); -+ -+ if (mst->group_refcnt[id - 1] <= 0) { -+ dev_err(mst->dev, "unexpected refcnt %d\n", -+ mst->group_refcnt[id - 1]); -+ return; -+ } -+ mst->group_refcnt[id - 1]--; -+} -+ -+int mtk_sdw_top_enable_stream(struct mtk_sdw *mst, int dai_id) -+{ -+ struct mtk_sdw_dai *mdai = &mst->dais[dai_id]; -+ int i; -+ u32 pdi_num, group_sync; -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_pdi_engen(mst, pdi_num, true); -+ } -+ -+ if (mdai->need_enable_delay) -+ usleep_range(1000, 1100); -+ -+ if (mdai->use_group_sync) { -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ group_sync = mdai->top_pdi_params[i].group_sync; -+ mtk_sdw_top_config_group_sync(mst, pdi_num, group_sync); -+ } -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_group_sync(mst, pdi_num, true); -+ } -+ } -+ -+ return 0; -+} -+ -+int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id) -+{ -+ struct mtk_sdw_dai *mdai = &mst->dais[dai_id]; -+ int i; -+ u32 pdi_num; -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_pdi_engen(mst, pdi_num, false); -+ } -+ -+ if (mdai->use_group_sync) { -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_enable_group_sync(mst, pdi_num, false); -+ } -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ pdi_num = mdai->pdi_params[i].pdi_num; -+ mtk_sdw_top_config_group_sync(mst, pdi_num, 0); -+ } -+ } -+ -+ return 0; -+} -diff --git a/drivers/soundwire/mediatek/mtk-sdw-top.h b/drivers/soundwire/mediatek/mtk-sdw-top.h -new file mode 100644 -index 0000000000..f12c090d60 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-top.h -@@ -0,0 +1,105 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master — AFE TOP control. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_TOP_H -+#define __MTK_SDW_TOP_H -+ -+#include "mtk-sdw-common.h" -+ -+enum mtk_sdw_group_sync_sel { -+ GROUP_SYNC_NONE = 0, -+ GROUP_1_SYNC, -+ GROUP_2_SYNC, -+ GROUP_3_SYNC, -+ GROUP_4_SYNC, -+}; -+ -+enum mtk_sdw_top_ver { -+ MTK_SDW_TOP_VER_0 = 0, -+ MTK_SDW_TOP_VER_MAX, -+}; -+ -+/* ---- AFE TOP registers (offsets that DON'T vary stay as #defines) ---- -+ */ -+#define SDW_TOP_PDIN_CON0(n) ((n) * 4) /* rel. top_pdi */ -+#define SDW_TOP_PDI_EN BIT(0) -+#define SDW_TOP_PDI_FS GENMASK(5, 1) -+#define SDW_TOP_PDI_DOMAIN GENMASK(8, 6) -+#define SDW_TOP_PDI_IP_SEL BIT(9) -+#define SDW_TOP_PDI_PDM2PCM BIT(10) -+#define SDW_TOP_PDI_CLOCK BIT(11) -+#define SDW_TOP_PDI_HD_SEL BIT(12) -+#define SDW_TOP_PDI_PDM_MODE BIT(13) -+#define SDW_TOP_PDI_PDM_ONE_WIRE BIT(14) -+#define SDW_TOP_PDI_DMIC_1XEN BIT(16) -+#define SDW_TOP_PDI_BRA_MODE BIT(17) -+#define SDW_TOP_PDI_BRA_EOP BIT(18) -+#define SDW_TOP_PDI_BRA_SLAVE BIT(19) -+#define SDW_TOP_PDI_SLAVE_MODE GENMASK(21, 20) -+#define SDW_TOP_PDI_GROUP_SYNC_ON BIT(22) -+#define SDW_TOP_PDI_GROUP_SYNC GENMASK(26, 23) -+ -+#define SDW_TOP_CON0 0x0000 /* rel. top_con */ -+#define SDW_TOP_CON0_GSYNC_DIR_CTRL BIT(7) -+ -+#define SDW_TOP_CON1 0x0004 -+ -+#define TOP_GROUP_SYNC_TX_MIN_ID 1 -+#define TOP_GROUP_SYNC_TX_MAX_ID 2 -+#define TOP_GROUP_SYNC_RX_MIN_ID 1 -+#define TOP_GROUP_SYNC_RX_MAX_ID 4 -+ -+struct mtk_sdw_top_pdi_params { -+ u32 group_sync; -+ u32 slave_mode; -+ u32 bra_slave; -+ u32 bra_eop; -+ u32 bra_mode; -+ u32 dmic_1xen; -+ u32 pdm_one_wire; -+ u32 pdm_mode; -+ u32 hd_sel; -+ u32 clock; -+ u32 pdm2pcm; -+ u32 sdw_ip_sel; -+ u32 domain; -+ u32 fs; -+}; -+ -+struct mtk_sdw_top_reg { -+ u32 tzd_delay_reg; -+ u32 tzd_delay_sel; -+ u32 tzd_inverse; -+ u32 tzd_delay_en; -+ u32 phy_delay_reg; -+ u32 phy_delay_sel; -+ u32 phy_double_delay_sel; -+}; -+ -+struct mtk_sdw_top_cfg { -+ const char *name; -+ struct mtk_sdw_top_reg reg; -+ /* -+ * u32 features; -+ * can be added for a bitfield if new features are supported -+ * in the future. -+ * -+ */ -+}; -+ -+int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver); -+void mtk_sdw_top_init_settings(struct mtk_sdw *mst); -+void mtk_sdw_top_configure_delays(struct mtk_sdw *mst); -+void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, -+ struct mtk_sdw_top_pdi_params *param); -+int mtk_sdw_top_group_sync_config_get(struct mtk_sdw *mst, u8 id, u32 *cfg); -+int mtk_sdw_top_group_sync_acquire(struct mtk_sdw *mst, bool is_tx); -+void mtk_sdw_top_group_sync_release(struct mtk_sdw *mst, u8 id); -+int mtk_sdw_top_enable_stream(struct mtk_sdw *mst, int dai_id); -+int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id); -+ -+#endif /* __MTK_SDW_TOP_H */ -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -new file mode 100644 -index 0000000000..09329088cd ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -0,0 +1,982 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek SoundWire master driver -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "mtk-sdw.h" -+#include "mtk-sdw-mach.h" -+#include "mtk-sdw-top.h" -+ -+static int mtk_sdw_parse_dp_allocation(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_link *link = &mst->links[idx]; -+ struct fwnode_handle *node; -+ char key[40]; -+ u32 dp[4]; -+ int ret; -+ -+ snprintf(key, sizeof(key), "acpi-scd-%d-subproperties", idx); -+ node = device_get_named_child_node(mst->dev, key); -+ if (!node) -+ return dev_err_probe(mst->dev, -ENODEV, -+ "link %d: missing %s node\n", idx, key); -+ -+ ret = fwnode_property_read_u32_array(node, "acpi-scd-dp-allocation", dp, -+ ARRAY_SIZE(dp)); -+ fwnode_handle_put(node); -+ if (ret) -+ return dev_err_probe(mst->dev, ret, -+ "link %d: bad acpi-scd-dp-allocation\n", -+ idx); -+ -+ /* -+ * { source_base, source_num, sink_base, sink_num }: every DP the -+ * firmware hands out indexes dp_pdi_mask[] and names a DP widget, -+ * so both ranges must fit in the MTK_SDW_MAX_DP ports of the -+ * manager. Check base first so the count test cannot underflow. -+ */ -+ if (dp[0] > MTK_SDW_MAX_DP || dp[1] > MTK_SDW_MAX_DP - dp[0] || -+ dp[2] > MTK_SDW_MAX_DP || dp[3] > MTK_SDW_MAX_DP - dp[2]) -+ return dev_err_probe(mst->dev, -EINVAL, -+ "link %d: DP allocation src %u+%u sink %u+%u exceeds %u ports\n", -+ idx, dp[0], dp[1], dp[2], dp[3], -+ MTK_SDW_MAX_DP); -+ -+ link->src_base = dp[0]; -+ link->src_num = dp[1]; -+ link->sink_base = dp[2]; -+ link->sink_num = dp[3]; -+ -+ dev_dbg(mst->dev, "link %d DP alloc: src %u..%u, sink %u..%u\n", idx, -+ link->src_base, link->src_base + link->src_num - 1, -+ link->sink_base, link->sink_base + link->sink_num - 1); -+ return 0; -+} -+ -+/* ======================================================================= -+ * ASoC DAI layer (ALSA <-> SoundWire stream binding) -+ * ======================================================================= -+ */ -+ -+static int mtk_sdw_set_sdw_stream(struct snd_soc_dai *dai, void *stream, -+ int direction) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ -+ mst->dais[dai->id].sruntime = stream; -+ return 0; -+} -+ -+static void *mtk_sdw_get_sdw_stream(struct snd_soc_dai *dai, int direction) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ -+ return mst->dais[dai->id].sruntime; -+} -+ -+static unsigned int derive_afe_fs_timing(unsigned int rate) -+{ -+ unsigned int fs = 0; -+ -+ switch (rate) { -+ case RATE_384000: -+ fs = MT8901_FS_384K; -+ break; -+ case RATE_352800: -+ fs = MT8901_FS_352D8K; -+ break; -+ case RATE_192000: -+ fs = MT8901_FS_192K; -+ break; -+ case RATE_176400: -+ fs = MT8901_FS_176D4K; -+ break; -+ case RATE_96000: -+ fs = MT8901_FS_96K; -+ break; -+ case RATE_88200: -+ fs = MT8901_FS_88D2K; -+ break; -+ case RATE_48000: -+ fs = MT8901_FS_48K; -+ break; -+ case RATE_44100: -+ fs = MT8901_FS_44D1K; -+ break; -+ case RATE_32000: -+ fs = MT8901_FS_32K; -+ break; -+ case RATE_24000: -+ fs = MT8901_FS_24K; -+ break; -+ case RATE_22050: -+ fs = MT8901_FS_22D05K; -+ break; -+ case RATE_16000: -+ fs = MT8901_FS_16K; -+ break; -+ case RATE_12000: -+ fs = MT8901_FS_12K; -+ break; -+ case RATE_8000: -+ fs = MT8901_FS_8K; -+ break; -+ default: -+ break; -+ } -+ -+ return fs; -+} -+ -+static void mtk_sdw_dai_release_params(struct mtk_sdw *mst, -+ struct mtk_sdw_dai *mdai) -+{ -+ int i; -+ -+ for (i = 0; i < mdai->pdi_count; i++) -+ mtk_sdw_clear_pdi_settings(&mdai->link->core, -+ &mdai->pdi_params[i]); -+ mdai->pdi_count = 0; -+ -+ if (mdai->group_sync_id > 0) { -+ mtk_sdw_top_group_sync_release(mst, mdai->group_sync_id); -+ mdai->group_sync_id = 0; -+ } -+ mdai->use_group_sync = false; -+ -+ if (mdai->top_pdi_params) { -+ devm_kfree(mst->dev, mdai->top_pdi_params); -+ mdai->top_pdi_params = NULL; -+ } -+} -+ -+static int mtk_sdw_dai_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -+ struct sdw_stream_config sconfig = { 0 }; -+ struct sdw_port_config pconfig = { 0 }; -+ struct mtk_sdw_port_params mtk_port_param = { 0 }; -+ struct mtk_sdw_top_pdi_params *top_params; -+ int dir, ret, i; -+ unsigned long pdis; -+ unsigned int pdi; -+ unsigned int channels = params_channels(params); -+ unsigned int rate = params_rate(params); -+ unsigned int pdi_count; -+ unsigned int ch_per_pdi = SDW_DEFAULT_CH_PER_PDI; -+ unsigned int tmp = 0; -+ unsigned int group_sync_config = 0; -+ unsigned int pdi_begin; -+ unsigned int last_pdi; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ dir = SDW_DATA_DIR_RX; -+ else -+ dir = SDW_DATA_DIR_TX; -+ -+ /* port_num is inside MTK_SDW_MAX_DP: validated when the DP allocation was parsed */ -+ pdis = mst->dp_pdi_mask[mdai->port_num]; -+ for_each_set_bit(pdi, &pdis, MTK_SDW_MAX_DP) { -+ dev_dbg(dai->dev, "DP%u <- PDI%u\n", mdai->port_num, pdi); -+ if (tmp++) { -+ if (pdi != last_pdi + 1) { -+ dev_dbg(dai->dev, "unexpected last PDI %u, PDI%u\n", -+ last_pdi, pdi); -+ return -EINVAL; -+ } -+ } else { -+ pdi_begin = pdi; -+ } -+ last_pdi = pdi; -+ } -+ -+ pdi_count = (channels + ch_per_pdi - 1) / ch_per_pdi; -+ if (tmp != pdi_count) { -+ dev_err(dai->dev, "DP%u pdi mask 0x%lx doesn't match channel %u\n", -+ mdai->port_num, pdis, channels); -+ return -EINVAL; -+ } -+ -+ /* -+ * ALSA allows HW_PARAMS again from SETUP or PREPARED without an -+ * intervening HW_FREE: drop the previous call's group sync -+ * reference and PDI state so nothing leaks or is released twice. -+ */ -+ mtk_sdw_dai_release_params(mst, mdai); -+ -+ if (pdi_count > 1) { -+ mdai->use_group_sync = true; -+ -+ ret = mtk_sdw_top_group_sync_acquire(mst, -+ dir == SDW_DATA_DIR_TX); -+ if (ret < 0) -+ return ret; -+ mdai->group_sync_id = ret; -+ -+ ret = mtk_sdw_top_group_sync_config_get(mst, -+ mdai->group_sync_id, -+ &group_sync_config); -+ if (ret < 0) { -+ mtk_sdw_top_group_sync_release(mst, -+ mdai->group_sync_id); -+ mdai->group_sync_id = 0; -+ return ret; -+ } -+ } -+ -+ /* update pdi_params */ -+ mdai->top_pdi_params = devm_kcalloc(mst->dev, pdi_count, -+ sizeof(*mdai->top_pdi_params), -+ GFP_KERNEL); -+ if (!mdai->top_pdi_params) { -+ ret = -ENOMEM; -+ goto err_release; -+ } -+ mdai->pdi_count = pdi_count; -+ mdai->need_enable_delay = TRUE; -+ for (i = 0; i < pdi_count; i++) { -+ mdai->pdi_params[i].pdi_num = pdi_begin++; -+ mdai->pdi_params[i].port_num = mdai->port_num; -+ mdai->pdi_params[i].ch_mask = (1 << (i * ch_per_pdi)) | -+ (1 << (i * ch_per_pdi + 1)); -+ -+ top_params = &mdai->top_pdi_params[i]; -+ top_params->group_sync = group_sync_config; -+ //top_params->slave_mode = 0; -+ top_params->bra_slave = 0; //ToDo : BRA -+ top_params->bra_mode = 0; //ToDo : BRA -+ top_params->bra_eop = (top_params->bra_mode != 0) ? 1 : 0; -+ top_params->dmic_1xen = 0; -+ top_params->pdm_one_wire = 0; -+ top_params->pdm_mode = 0; -+ //top_params->hd_sel = 0; -+ top_params->clock = IS_48K_RATE_DOMAIN(rate) ? 1 : 0; -+ top_params->pdm2pcm = 0; -+ top_params->sdw_ip_sel = mdai->link->ip_idx; -+ /* ToDo: SpecifyPdiMode for BRA */ -+ top_params->domain = MT8901_APLL_CLK_DOMAIN; -+ /* ToDo: SpecifyPdiFs for BRA */ -+ top_params->fs = derive_afe_fs_timing(rate); -+ -+ if (top_params->bra_mode != 0 && top_params->bra_slave != 0) -+ mdai->need_enable_delay = FALSE; -+ } -+ -+ pconfig.num = mdai->port_num; -+ pconfig.ch_mask = GENMASK(channels - 1, 0); -+ -+ sconfig.frame_rate = rate; -+ sconfig.ch_count = channels; -+ sconfig.bps = snd_pcm_format_width(params_format(params)); -+ sconfig.direction = dir; -+ sconfig.type = SDW_STREAM_PCM; -+ -+ mtk_port_param.port_num = pconfig.num; -+ mtk_port_param.bpt_payload_type = 0; -+ mtk_port_param.bpt_en = true; -+ mtk_sdw_configure_port_params(&mdai->link->core, &mtk_port_param, dir); -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ top_params = &mdai->top_pdi_params[i]; -+ mtk_sdw_top_configure_pdi(mst, mdai->pdi_params[i].pdi_num, -+ top_params); -+ mtk_sdw_configure_pdi_params(&mdai->link->core, -+ &mdai->pdi_params[i]); -+ } -+ -+ ret = sdw_stream_add_master(&mdai->link->core.bus, &sconfig, &pconfig, -+ 1, mdai->sruntime); -+ if (ret) -+ goto err_release; -+ -+ return 0; -+ -+err_release: -+ mtk_sdw_dai_release_params(mst, mdai); -+ return ret; -+} -+ -+static int mtk_sdw_dai_hw_free(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -+ int ret; -+ -+ ret = sdw_stream_remove_master(&mdai->link->core.bus, mdai->sruntime); -+ if (ret < 0) -+ dev_err(dai->dev, "remove manager from stream %s failed: %d\n", -+ mdai->sruntime->name, ret); -+ -+ mtk_sdw_dai_release_params(mst, mdai); -+ return ret; -+} -+ -+/* configure top stream here, it can be called before dai_link ops */ -+static int mtk_sdw_dai_trigger(struct snd_pcm_substream *substream, int cmd, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -+ -+ mtk_sdw_core_dump_dpn_regs(&mdai->link->core, mdai->port_num, -+ "trigger"); -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ return mtk_sdw_top_enable_stream(mst, dai->id); -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ return mtk_sdw_top_disable_stream(mst, dai->id); -+ default: -+ return -EINVAL; -+ } -+} -+ -+static const struct snd_soc_dai_ops mtk_sdw_dai_ops = { -+ .hw_params = mtk_sdw_dai_hw_params, -+ .hw_free = mtk_sdw_dai_hw_free, -+ .trigger = mtk_sdw_dai_trigger, -+ .set_stream = mtk_sdw_set_sdw_stream, -+ .get_stream = mtk_sdw_get_sdw_stream, -+}; -+ -+/* ======================================================================= -+ * DAPM: PDI <-> DP routing -+ * ======================================================================= -+ */ -+ -+/* Playback DEMUX target DPs (item 0 == "None"). */ -+static const char * const mtk_sdw_playback_dp_texts[] = { -+ "None", "DP2", "DP3", "DP4", "DP5", "DP6", -+}; -+ -+/* Capture MUX source DPs (item 0 == "None"). */ -+static const char * const mtk_sdw_capture_dp_texts[] = { -+ "None", "DP7", "DP8", "DP9", "DP10", -+ "DP11", "DP12", "DP13", "DP14", "DP15", -+}; -+ -+static int mtk_sdw_pdi_route_put(struct snd_kcontrol *kc, -+ struct snd_ctl_elem_value *uc) -+{ -+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kc); -+ struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm); -+ struct mtk_sdw *mst = snd_soc_component_get_drvdata(comp); -+ struct soc_enum *e = (struct soc_enum *)kc->private_value; -+ unsigned int item = uc->value.enumerated.item[0]; -+ unsigned int pdi, dp, d; -+ -+ if (sscanf(kc->id.name, "PDI%u", &pdi) != 1) -+ return -EINVAL; -+ if (pdi >= BITS_PER_TYPE(mst->dp_pdi_mask[0])) -+ return -EINVAL; -+ if (item >= e->items) -+ return -EINVAL; -+ -+ for (d = 0; d < MTK_SDW_MAX_DP; d++) -+ mst->dp_pdi_mask[d] &= ~BIT(pdi); -+ -+ if (item && sscanf(e->texts[item], "DP%u", &dp) == 1 && -+ dp < MTK_SDW_MAX_DP) -+ mst->dp_pdi_mask[dp] |= BIT(pdi); -+ -+ return snd_soc_dapm_put_enum_double(kc, uc); -+} -+ -+/* Playback: PGA(PDIn) -> DEMUX(PDIn) -> one of DP2..DP6. */ -+#define MTK_SDW_PLAYBACK_PDI(pdi) \ -+static SOC_ENUM_SINGLE_VIRT_DECL(mtk_sdw_pdi##pdi##_enum, \ -+ mtk_sdw_playback_dp_texts); \ -+static const struct snd_kcontrol_new mtk_sdw_pdi##pdi##_demux = \ -+ SOC_DAPM_ENUM_EXT("PDI" #pdi " Demux Select", \ -+ mtk_sdw_pdi##pdi##_enum, \ -+ snd_soc_dapm_get_enum_double, \ -+ mtk_sdw_pdi_route_put) -+ -+/* Capture: one of DP7..DP15 -> MUX(PDIn) -> PGA(PDIn). */ -+#define MTK_SDW_CAPTURE_PDI(pdi) \ -+static SOC_ENUM_SINGLE_VIRT_DECL(mtk_sdw_pdi##pdi##_enum, \ -+ mtk_sdw_capture_dp_texts); \ -+static const struct snd_kcontrol_new mtk_sdw_pdi##pdi##_mux = \ -+ SOC_DAPM_ENUM_EXT("PDI" #pdi " Mux Select", \ -+ mtk_sdw_pdi##pdi##_enum, \ -+ snd_soc_dapm_get_enum_double, \ -+ mtk_sdw_pdi_route_put) -+ -+MTK_SDW_PLAYBACK_PDI(2); -+MTK_SDW_PLAYBACK_PDI(3); -+MTK_SDW_PLAYBACK_PDI(4); -+MTK_SDW_PLAYBACK_PDI(5); -+MTK_SDW_PLAYBACK_PDI(6); -+ -+MTK_SDW_CAPTURE_PDI(7); -+MTK_SDW_CAPTURE_PDI(8); -+MTK_SDW_CAPTURE_PDI(9); -+MTK_SDW_CAPTURE_PDI(10); -+MTK_SDW_CAPTURE_PDI(11); -+MTK_SDW_CAPTURE_PDI(12); -+MTK_SDW_CAPTURE_PDI(13); -+MTK_SDW_CAPTURE_PDI(14); -+MTK_SDW_CAPTURE_PDI(15); -+ -+/* PDI node + its selector. */ -+#define MTK_SDW_PDI_PGA(pdi) \ -+ SND_SOC_DAPM_PGA("PDI" #pdi, SND_SOC_NOPM, 0, 0, NULL, 0) -+#define MTK_SDW_PLAYBACK_PDI_DEMUX(pdi) \ -+ SND_SOC_DAPM_DEMUX("PDI" #pdi " Demux", SND_SOC_NOPM, 0, 0, \ -+ &mtk_sdw_pdi##pdi##_demux) -+#define MTK_SDW_CAPTURE_PDI_MUX(pdi) \ -+ SND_SOC_DAPM_MUX("PDI" #pdi " Mux", SND_SOC_NOPM, 0, 0, \ -+ &mtk_sdw_pdi##pdi##_mux) -+ -+/* DP node. */ -+#define MTK_SDW_DP_WIDGET(dp) \ -+ SND_SOC_DAPM_PGA("DP" #dp, SND_SOC_NOPM, 0, 0, NULL, 0) -+ -+static const struct snd_soc_dapm_widget mtk_sdw_dapm_widgets[] = { -+ /* BRA PDIs, no DP connection */ -+ SND_SOC_DAPM_PGA("PDI0", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_PGA("PDI1", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_PGA("PDI16", SND_SOC_NOPM, 0, 0, NULL, 0), -+ SND_SOC_DAPM_PGA("PDI17", SND_SOC_NOPM, 0, 0, NULL, 0), -+ -+ /* Playback PDIs + demuxes */ -+ MTK_SDW_PDI_PGA(2), MTK_SDW_PLAYBACK_PDI_DEMUX(2), -+ MTK_SDW_PDI_PGA(3), MTK_SDW_PLAYBACK_PDI_DEMUX(3), -+ MTK_SDW_PDI_PGA(4), MTK_SDW_PLAYBACK_PDI_DEMUX(4), -+ MTK_SDW_PDI_PGA(5), MTK_SDW_PLAYBACK_PDI_DEMUX(5), -+ MTK_SDW_PDI_PGA(6), MTK_SDW_PLAYBACK_PDI_DEMUX(6), -+ /* Capture PDIs + muxes */ -+ MTK_SDW_PDI_PGA(7), MTK_SDW_CAPTURE_PDI_MUX(7), -+ MTK_SDW_PDI_PGA(8), MTK_SDW_CAPTURE_PDI_MUX(8), -+ MTK_SDW_PDI_PGA(9), MTK_SDW_CAPTURE_PDI_MUX(9), -+ MTK_SDW_PDI_PGA(10), MTK_SDW_CAPTURE_PDI_MUX(10), -+ MTK_SDW_PDI_PGA(11), MTK_SDW_CAPTURE_PDI_MUX(11), -+ MTK_SDW_PDI_PGA(12), MTK_SDW_CAPTURE_PDI_MUX(12), -+ MTK_SDW_PDI_PGA(13), MTK_SDW_CAPTURE_PDI_MUX(13), -+ MTK_SDW_PDI_PGA(14), MTK_SDW_CAPTURE_PDI_MUX(14), -+ MTK_SDW_PDI_PGA(15), MTK_SDW_CAPTURE_PDI_MUX(15), -+ /* DP nodes */ -+ MTK_SDW_DP_WIDGET(2), MTK_SDW_DP_WIDGET(3), MTK_SDW_DP_WIDGET(4), -+ MTK_SDW_DP_WIDGET(5), MTK_SDW_DP_WIDGET(6), MTK_SDW_DP_WIDGET(7), -+ MTK_SDW_DP_WIDGET(8), MTK_SDW_DP_WIDGET(9), MTK_SDW_DP_WIDGET(10), -+ MTK_SDW_DP_WIDGET(11), MTK_SDW_DP_WIDGET(12), MTK_SDW_DP_WIDGET(13), -+ MTK_SDW_DP_WIDGET(14), MTK_SDW_DP_WIDGET(15), -+}; -+ -+/* -+ * Playback edge: PDIn -> PDIn Demux -> DPx (active when demux selects "DPx"). -+ */ -+#define MTK_SDW_PLAYBACK_DEMUX_OUT(pdi, dp) \ -+ { "DP" #dp, "DP" #dp, "PDI" #pdi " Demux" } -+#define MTK_SDW_PLAYBACK_PDI_LINK(pdi) \ -+ { "PDI" #pdi " Demux", NULL, "PDI" #pdi } -+ -+/* Capture edge: DPx -> PDIn Mux -> PDIn (active when mux selects "DPx"). */ -+#define MTK_SDW_CAPTURE_MUX_IN(pdi, dp) \ -+ { "PDI" #pdi " Mux", "DP" #dp, "DP" #dp } -+#define MTK_SDW_CAPTURE_PDI_LINK(pdi) \ -+ { "PDI" #pdi, NULL, "PDI" #pdi " Mux" } -+ -+static const struct snd_soc_dapm_route mtk_sdw_dapm_routes[] = { -+ /* Playback: PDI2..PDI6 -> DP2..DP6 */ -+ MTK_SDW_PLAYBACK_PDI_LINK(2), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(2, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(2, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(2, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(2, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(2, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(3, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(3, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(3, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(3, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(3, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(4), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(4, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(4, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(4, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(4, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(4, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(5, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(5, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(5, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(5, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(5, 6), -+ MTK_SDW_PLAYBACK_PDI_LINK(6), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(6, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(6, 3), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(6, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(6, 5), -+ MTK_SDW_PLAYBACK_DEMUX_OUT(6, 6), -+ /* Capture: DP7..DP15 -> PDI7..PDI15 */ -+ MTK_SDW_CAPTURE_MUX_IN(7, 7), MTK_SDW_CAPTURE_MUX_IN(7, 8), -+ MTK_SDW_CAPTURE_MUX_IN(7, 9), MTK_SDW_CAPTURE_MUX_IN(7, 10), -+ MTK_SDW_CAPTURE_MUX_IN(7, 11), MTK_SDW_CAPTURE_MUX_IN(7, 12), -+ MTK_SDW_CAPTURE_MUX_IN(7, 13), MTK_SDW_CAPTURE_MUX_IN(7, 14), -+ MTK_SDW_CAPTURE_MUX_IN(7, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(7), -+ MTK_SDW_CAPTURE_MUX_IN(8, 7), MTK_SDW_CAPTURE_MUX_IN(8, 8), -+ MTK_SDW_CAPTURE_MUX_IN(8, 9), MTK_SDW_CAPTURE_MUX_IN(8, 10), -+ MTK_SDW_CAPTURE_MUX_IN(8, 11), MTK_SDW_CAPTURE_MUX_IN(8, 12), -+ MTK_SDW_CAPTURE_MUX_IN(8, 13), MTK_SDW_CAPTURE_MUX_IN(8, 14), -+ MTK_SDW_CAPTURE_MUX_IN(8, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(8), -+ MTK_SDW_CAPTURE_MUX_IN(9, 7), MTK_SDW_CAPTURE_MUX_IN(9, 8), -+ MTK_SDW_CAPTURE_MUX_IN(9, 9), MTK_SDW_CAPTURE_MUX_IN(9, 10), -+ MTK_SDW_CAPTURE_MUX_IN(9, 11), MTK_SDW_CAPTURE_MUX_IN(9, 12), -+ MTK_SDW_CAPTURE_MUX_IN(9, 13), MTK_SDW_CAPTURE_MUX_IN(9, 14), -+ MTK_SDW_CAPTURE_MUX_IN(9, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(9), -+ MTK_SDW_CAPTURE_MUX_IN(10, 7), MTK_SDW_CAPTURE_MUX_IN(10, 8), -+ MTK_SDW_CAPTURE_MUX_IN(10, 9), MTK_SDW_CAPTURE_MUX_IN(10, 10), -+ MTK_SDW_CAPTURE_MUX_IN(10, 11), MTK_SDW_CAPTURE_MUX_IN(10, 12), -+ MTK_SDW_CAPTURE_MUX_IN(10, 13), MTK_SDW_CAPTURE_MUX_IN(10, 14), -+ MTK_SDW_CAPTURE_MUX_IN(10, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(10), -+ MTK_SDW_CAPTURE_MUX_IN(11, 7), MTK_SDW_CAPTURE_MUX_IN(11, 8), -+ MTK_SDW_CAPTURE_MUX_IN(11, 9), MTK_SDW_CAPTURE_MUX_IN(11, 10), -+ MTK_SDW_CAPTURE_MUX_IN(11, 11), MTK_SDW_CAPTURE_MUX_IN(11, 12), -+ MTK_SDW_CAPTURE_MUX_IN(11, 13), MTK_SDW_CAPTURE_MUX_IN(11, 14), -+ MTK_SDW_CAPTURE_MUX_IN(11, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(11), -+ MTK_SDW_CAPTURE_MUX_IN(12, 7), MTK_SDW_CAPTURE_MUX_IN(12, 8), -+ MTK_SDW_CAPTURE_MUX_IN(12, 9), MTK_SDW_CAPTURE_MUX_IN(12, 10), -+ MTK_SDW_CAPTURE_MUX_IN(12, 11), MTK_SDW_CAPTURE_MUX_IN(12, 12), -+ MTK_SDW_CAPTURE_MUX_IN(12, 13), MTK_SDW_CAPTURE_MUX_IN(12, 14), -+ MTK_SDW_CAPTURE_MUX_IN(12, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(12), -+ MTK_SDW_CAPTURE_MUX_IN(13, 7), MTK_SDW_CAPTURE_MUX_IN(13, 8), -+ MTK_SDW_CAPTURE_MUX_IN(13, 9), MTK_SDW_CAPTURE_MUX_IN(13, 10), -+ MTK_SDW_CAPTURE_MUX_IN(13, 11), MTK_SDW_CAPTURE_MUX_IN(13, 12), -+ MTK_SDW_CAPTURE_MUX_IN(13, 13), MTK_SDW_CAPTURE_MUX_IN(13, 14), -+ MTK_SDW_CAPTURE_MUX_IN(13, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(13), -+ MTK_SDW_CAPTURE_MUX_IN(14, 7), MTK_SDW_CAPTURE_MUX_IN(14, 8), -+ MTK_SDW_CAPTURE_MUX_IN(14, 9), MTK_SDW_CAPTURE_MUX_IN(14, 10), -+ MTK_SDW_CAPTURE_MUX_IN(14, 11), MTK_SDW_CAPTURE_MUX_IN(14, 12), -+ MTK_SDW_CAPTURE_MUX_IN(14, 13), MTK_SDW_CAPTURE_MUX_IN(14, 14), -+ MTK_SDW_CAPTURE_MUX_IN(14, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(14), -+ MTK_SDW_CAPTURE_MUX_IN(15, 7), MTK_SDW_CAPTURE_MUX_IN(15, 8), -+ MTK_SDW_CAPTURE_MUX_IN(15, 9), MTK_SDW_CAPTURE_MUX_IN(15, 10), -+ MTK_SDW_CAPTURE_MUX_IN(15, 11), MTK_SDW_CAPTURE_MUX_IN(15, 12), -+ MTK_SDW_CAPTURE_MUX_IN(15, 13), MTK_SDW_CAPTURE_MUX_IN(15, 14), -+ MTK_SDW_CAPTURE_MUX_IN(15, 15), -+ MTK_SDW_CAPTURE_PDI_LINK(15), -+}; -+ -+static int mtk_sdw_add_dai_routes(struct snd_soc_component *comp) -+{ -+ struct mtk_sdw *mst = snd_soc_component_get_drvdata(comp); -+ struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp); -+ int i, p, ret; -+ -+ for (i = 0; i < mst->num_links; i++) { -+ struct mtk_sdw_link *link = &mst->links[i]; -+ int offset; -+ -+ offset = 0; -+ for (p = 0; p < link->src_num; p++, offset++) { -+ char dai[32], dp[8]; -+ struct snd_soc_dapm_route r = { dai, NULL, dp }; -+ -+ snprintf(dai, sizeof(dai), "SDW%d_Playback%u", -+ link->ip_idx, offset); -+ snprintf(dp, sizeof(dp), "DP%u", link->src_base + p); -+ ret = snd_soc_dapm_add_routes(dapm, &r, 1); -+ if (ret) -+ return ret; -+ } -+ -+ offset = 0; -+ for (p = 0; p < link->sink_num; p++, offset++) { -+ char dai[32], dp[8]; -+ struct snd_soc_dapm_route r = { dp, NULL, dai }; -+ -+ snprintf(dai, sizeof(dai), "SDW%d_Capture%u", -+ link->ip_idx, offset); -+ snprintf(dp, sizeof(dp), "DP%u", link->sink_base + p); -+ ret = snd_soc_dapm_add_routes(dapm, &r, 1); -+ if (ret) -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int mtk_sdw_component_probe(struct snd_soc_component *comp) -+{ -+ return mtk_sdw_add_dai_routes(comp); -+} -+ -+static const struct snd_soc_component_driver mtk_sdw_component = { -+ .name = "mtk-soundwire", -+ .probe = mtk_sdw_component_probe, -+ .dapm_widgets = mtk_sdw_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(mtk_sdw_dapm_widgets), -+ .dapm_routes = mtk_sdw_dapm_routes, -+ .num_dapm_routes = ARRAY_SIZE(mtk_sdw_dapm_routes), -+}; -+ -+static int mtk_sdw_init_dai(struct mtk_sdw *mst, struct snd_soc_dai_driver *drv, -+ int idx, struct mtk_sdw_link *link, -+ unsigned int port, int offset, bool playback) -+{ -+ struct snd_soc_pcm_stream *stream; -+ -+ drv->id = idx; -+ drv->ops = &mtk_sdw_dai_ops; -+ -+ if (playback) { -+ drv->name = devm_kasprintf(mst->dev, GFP_KERNEL, -+ "SDW%d_Playback%u", -+ link->ip_idx, offset); -+ if (!drv->name) -+ return -ENOMEM; -+ -+ stream = &drv->playback; -+ } else { -+ drv->name = devm_kasprintf(mst->dev, GFP_KERNEL, -+ "SDW%d_Capture%u", -+ link->ip_idx, offset); -+ if (!drv->name) -+ return -ENOMEM; -+ -+ stream = &drv->capture; -+ } -+ -+ stream->channels_min = 2; -+ stream->channels_max = 8; -+ stream->rates = SNDRV_PCM_RATE_48000; -+ stream->rates = SNDRV_PCM_RATE_8000_384000; -+ stream->formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE; -+ -+ stream->stream_name = drv->name; -+ -+ mst->dais[idx].link = link; -+ mst->dais[idx].port_num = port; -+ -+ return 0; -+} -+ -+static int mtk_sdw_register_dais(struct mtk_sdw *mst) -+{ -+ struct snd_soc_dai_driver *drvs; -+ struct device *dev = mst->dev; -+ int i, p, idx = 0, num = 0, ret; -+ -+ for (i = 0; i < mst->num_links; i++) -+ num += mst->links[i].src_num + mst->links[i].sink_num; -+ if (!num) -+ return dev_err_probe(dev, -EINVAL, "no data ports allocated\n"); -+ -+ mst->dais = devm_kcalloc(dev, num, sizeof(*mst->dais), GFP_KERNEL); -+ if (!mst->dais) -+ return -ENOMEM; -+ -+ drvs = devm_kcalloc(dev, num, sizeof(*drvs), GFP_KERNEL); -+ if (!drvs) -+ return -ENOMEM; -+ -+ for (i = 0; i < mst->num_links; i++) { -+ struct mtk_sdw_link *link = &mst->links[i]; -+ int offset; -+ -+ offset = 0; -+ /* Source ports -> playback DAIs */ -+ for (p = 0; p < link->src_num; p++, idx++, offset++) { -+ ret = mtk_sdw_init_dai(mst, &drvs[idx], idx, link, -+ link->src_base + p, offset, -+ true); -+ if (ret) -+ return ret; -+ } -+ -+ offset = 0; -+ /* Sink ports -> capture DAIs */ -+ for (p = 0; p < link->sink_num; p++, idx++, offset++) { -+ ret = mtk_sdw_init_dai(mst, &drvs[idx], idx, link, -+ link->sink_base + p, offset, -+ false); -+ if (ret) -+ return ret; -+ } -+ } -+ mst->num_dais = num; -+ -+ return devm_snd_soc_register_component(dev, &mtk_sdw_component, drvs, -+ num); -+} -+ -+/* ======================================================================= -+ * Per-IP bring-up -+ * ======================================================================= -+ */ -+ -+static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_link *link = &mst->links[idx]; -+ struct mtk_sdw_core *core = &link->core; -+ int ret; -+ -+ link->master = mst; -+ link->ip_idx = idx; -+ -+ core->dev = mst->dev; -+ core->priv = link; -+ -+ core->bus.link_id = idx; -+ core->bus.prop.mclk_freq = SDW_DEFAULT_MCLK_CLK_FREQ; -+ -+ core->bus.dev = mst->dev; -+ ret = sdw_bus_master_add(&core->bus, mst->dev, mst->dev->fwnode); -+ if (ret) { -+ dev_err(mst->dev, "IP%d: bus_master_add failed: %d\n", -+ idx, ret); -+ return ret; -+ } -+ -+ ret = mtk_sdw_core_hw_init(core); -+ if (ret) { -+ sdw_bus_master_delete(&core->bus); -+ return ret; -+ } -+ -+ mtk_sdw_enable_irq(core, true); -+ dev_info(mst->dev, "IP%d: SoundWire bus ready\n", idx); -+ return 0; -+} -+ -+static void mtk_sdw_link_deinit(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_core *core = &mst->links[idx].core; -+ -+ mtk_sdw_enable_irq(core, false); -+ sdw_bus_master_delete(&core->bus); -+} -+ -+static void mtk_init_sdw_master(struct mtk_sdw *mst) -+{ -+ int i; -+ -+ mst->tzd_delay = 3; -+ mst->tzd_inverse = 0; -+ mst->phy_delay = 2; -+ mst->phy_double_delay = 0; -+ mst->num_links = SDW_MAX_HWIP_NUM; -+ -+ for (i = 0; i < SDW_MAX_HWIP_NUM; i++) -+ mst->controller_en_list |= (1UL << i); -+} -+ -+static int mtk_sdw_register_machine(struct mtk_sdw *mst) -+{ -+ struct snd_soc_acpi_mach *mach; -+ -+ mach = mtk_sdw_machine_select(mst); -+ if (!mach) { -+ dev_info(mst->dev, "no card from this controller\n"); -+ return 0; /* no card from this controller; not an error */ -+ } -+ -+ mst->mach_dev = platform_device_register_data(mst->dev, mach->drv_name, -+ PLATFORM_DEVID_NONE, -+ mach, sizeof(*mach)); -+ if (IS_ERR(mst->mach_dev)) { -+ dev_err(mst->dev, "failed to register machine %s\n", -+ mach->drv_name); -+ return PTR_ERR(mst->mach_dev); -+ } -+ -+ dev_info(mst->dev, "registered SoundWire machine %s\n", mach->drv_name); -+ return 0; -+} -+ -+static int mtk_sdw_probe_controller(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct mtk_sdw *mst; -+ u32 hw_ver = MTK_SDW_HW_VER_MT8901; -+ u32 mmio[2]; -+ int i, ret; -+ -+ mst = devm_kzalloc(dev, sizeof(*mst), GFP_KERNEL); -+ if (!mst) -+ return -ENOMEM; -+ -+ mtk_init_sdw_master(mst); -+ -+ mst->dev = dev; -+ mutex_init(&mst->group_lock); -+ platform_set_drvdata(pdev, mst); -+ -+ ret = device_property_read_u32_array(dev, "afe-base", mmio, 2); -+ if (ret) -+ return dev_err_probe(dev, ret, -+ "missing/invalid afe-base property\n"); -+ dev_info(dev, "address %x, size %d\n", mmio[0], mmio[1]); -+ -+ mst->base = devm_ioremap(dev, mmio[0], mmio[1]); -+ if (!mst->base) -+ return -ENOMEM; -+ mst->top_pdi = mst->base + AFE_SDW_TOP_PDI_REG_BASE; -+ mst->top_con = mst->base + AFE_SDW_TOP_CON_REG_BASE; -+ -+ device_property_read_u32(dev, "acpi-scd-hw-ver", &hw_ver); -+ if (hw_ver >= MTK_SDW_HW_VER_MAX) -+ return dev_err_probe(dev, -EINVAL, -+ "unknown acpi-scd-hw-ver %u\n", hw_ver); -+ -+ mst->hw_ver = hw_ver; -+ -+ ret = mtk_sdw_top_config_select(mst, mst->hw_ver); -+ if (ret) -+ return ret; -+ -+ /* Timing delays from ACPI _DSD. */ -+ device_property_read_u32(dev, "acpi-scd-tzd-delay", &mst->tzd_delay); -+ device_property_read_u32(dev, "acpi-scd-phy-delay", &mst->phy_delay); -+ device_property_read_u32(dev, "acpi-scd-phy-double-delay", -+ &mst->phy_double_delay); -+ -+ if (mst->tzd_delay <= mst->phy_delay) { -+ dev_err(dev, "invalid delay, tzd %u - phy %u", mst->tzd_delay, -+ mst->phy_delay); -+ return -EINVAL; -+ } -+ -+ mtk_sdw_top_init_settings(mst); -+ mtk_sdw_top_configure_delays(mst); -+ -+ for (i = 0; i < mst->num_links; i++) { -+ int irq = platform_get_irq(pdev, i); -+ struct mtk_sdw_core *core = &mst->links[i].core; -+ -+ if (irq < 0) { -+ ret = irq; -+ goto err; -+ } -+ mst->links[i].irq = irq; -+ mst->links[i].ip_idx = i; -+ -+ ret = mtk_sdw_parse_dp_allocation(mst, i); -+ if (ret) -+ goto err; -+ -+ core->regs = devm_platform_ioremap_resource(pdev, i); -+ if (IS_ERR(core->regs)) { -+ ret = PTR_ERR(core->regs); -+ goto err; -+ } -+ -+ /* -+ * The line is shared and MCP_INTMASK holds whatever POST left, -+ * so the handler can run as soon as it is registered: the lock -+ * and work items it uses must exist first. -+ */ -+ ret = mtk_sdw_core_init(core); -+ if (ret) -+ goto err; -+ -+ ret = devm_request_irq(dev, irq, mtk_sdw_core_irq, IRQF_SHARED, -+ dev_name(dev), core); -+ if (ret) { -+ dev_err(dev, "IP%d: request_irq failed: %d\n", i, ret); -+ goto err; -+ } -+ -+ ret = mtk_sdw_link_init(mst, i); -+ if (ret) -+ goto err; -+ } -+ -+ ret = mtk_sdw_register_dais(mst); -+ if (ret) { -+ dev_err(dev, "failed to register DAIs: %d\n", ret); -+ goto err; -+ } -+ -+ dev_info(dev, "MediaTek SoundWire ready, %d link(s), %d DAI(s)\n", -+ mst->num_links, mst->num_dais); -+ -+ return 0; -+ -+err: -+ while (--i >= 0) -+ mtk_sdw_link_deinit(mst, i); -+ -+ return ret; -+} -+ -+static int mtk_sdw_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct mtk_sdw *mst; -+ int i, ret; -+ -+ ret = mtk_sdw_probe_controller(pdev); -+ if (ret) { -+ dev_err(dev, "failed to probe_controller %d\n", ret); -+ return ret; -+ } -+ -+ mst = platform_get_drvdata(pdev); -+ -+ ret = mtk_sdw_register_machine(mst); -+ if (ret) { -+ for (i = mst->num_links - 1; i >= 0; i--) -+ mtk_sdw_link_deinit(mst, i); -+ -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void mtk_sdw_remove(struct platform_device *pdev) -+{ -+ struct mtk_sdw *mst = platform_get_drvdata(pdev); -+ int i; -+ -+ if (mst->mach_dev) -+ platform_device_unregister(mst->mach_dev); -+ for (i = mst->num_links - 1; i >= 0; i--) -+ mtk_sdw_link_deinit(mst, i); -+} -+ -+static const struct acpi_device_id mtk_sdw_acpi_match[] = { -+ { "NVDA9100", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, mtk_sdw_acpi_match); -+ -+static struct platform_driver mtk_sdw_driver = { -+ .probe = mtk_sdw_probe, -+ .remove = mtk_sdw_remove, -+ .driver = { -+ .name = "mtk-soundwire", -+ .acpi_match_table = mtk_sdw_acpi_match, -+ }, -+}; -+module_platform_driver(mtk_sdw_driver); -+ -+MODULE_DESCRIPTION("MediaTek SoundWire master"); -+MODULE_AUTHOR("Trevor Wu "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/soundwire/mediatek/mtk-sdw.h b/drivers/soundwire/mediatek/mtk-sdw.h -new file mode 100644 -index 0000000000..2c91eb609b ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw.h -@@ -0,0 +1,85 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * MediaTek SoundWire master driver header. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+#ifndef __MTK_SDW_H -+#define __MTK_SDW_H -+ -+#include "mtk-sdw-common.h" -+ -+enum mt8901_afe_clk_domain { -+ MT8901_HOPPING_CLK_DOMAIN = 0, -+ MT8901_APLL_CLK_DOMAIN = 1, -+}; -+ -+enum mtk_sdw_sample_rate { -+ RATE_384000 = 384000, -+ RATE_352800 = 352800, -+ RATE_192000 = 192000, -+ RATE_176400 = 176400, -+ RATE_96000 = 96000, -+ RATE_88200 = 88200, -+ RATE_48000 = 48000, -+ RATE_44100 = 44100, -+ RATE_32000 = 32000, -+ RATE_29400 = 29400, -+ RATE_24000 = 24000, -+ RATE_22050 = 22050, -+ RATE_16000 = 16000, -+ RATE_14700 = 14700, -+ RATE_12000 = 12000, -+ RATE_11025 = 11025, -+ RATE_8000 = 8000, -+ RATE_7350 = 7350, -+}; -+ -+enum mt8901_afe_fs_mode { -+ MT8901_FS_8K = 0, -+ MT8901_FS_11D025K = 1, -+ MT8901_FS_12K = 2, -+ MT8901_FS_16K = 4, -+ MT8901_FS_22D05K = 5, -+ MT8901_FS_24K = 6, -+ MT8901_FS_32K = 8, -+ MT8901_FS_44D1K = 9, -+ MT8901_FS_48K = 10, -+ MT8901_FS_88D2K = 13, -+ MT8901_FS_96K = 14, -+ MT8901_FS_176D4K = 17, -+ MT8901_FS_192K = 18, -+ MT8901_FS_352D8K = 21, -+ MT8901_FS_384K = 22, -+ MT8901_ETDM_OUT0_HOPPING_DOMAIN = 4, -+ MT8901_ETDM_OUT5_HOPPING_DOMAIN = 9, -+ MT8901_ETDM_IN0_HOPPING_DOMAIN = 12, -+ MT8901_ETDM_IN5_HOPPING_DOMAIN = 17, -+ MT8901_FS_TOP_PDI_IP0_PDI0 = 24, -+ MT8901_FS_TOP_PDI_IP1_PDI0 = 25, -+ MT8901_FS_TOP_PDI_IP0_PDI1 = 26, -+ MT8901_FS_TOP_PDI_IP1_PDI1 = 27, -+}; -+ -+#define IS_48K_RATE_DOMAIN(x) (((x) % 8000) == 0) -+ -+#define SDW_DEFAULT_CH_PER_PDI 2 -+ -+#define AFE_SDW_TOP_PDI_REG_BASE (0x9000) -+#define AFE_SDW_TOP_CON_REG_BASE (0x9048) -+ -+#define SDW_DEFAULT_MAX_BUS_CLK_FREQ (6144000) -+#define SDW_DEFAULT_MCLK_CLK_FREQ (24576000) -+#define SDW_DEFAULT_FRAME_RATE (24000) -+#define SDW_DEFAULT_FRAME_SHAPE_ROW (64) -+#define SDW_DEFAULT_FRAME_SHAPE_COL (8) -+ -+#define MTK_SDW_DP_SOURCE_BASE 2 /* DP2.. (master source / playback) */ -+#define MTK_SDW_DP_SOURCE_NUM 5 -+#define MTK_SDW_DP_SINK_BASE 7 /* DP7.. (master sink / capture) */ -+#define MTK_SDW_DP_SINK_NUM 9 -+#define MTK_SDW_MAX_DAIS \ -+ ((MTK_SDW_DP_SOURCE_NUM) + (MTK_SDW_DP_SINK_NUM)) /* BRA not included */ -+ -+#endif /* __MTK_SDW_H */ -diff --git a/drivers/soundwire/mtk-sdw-common.h b/drivers/soundwire/mtk-sdw-common.h -deleted file mode 100644 -index 32912b1272..0000000000 ---- a/drivers/soundwire/mtk-sdw-common.h -+++ /dev/null -@@ -1,75 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * MediaTek SoundWire master — shared driver structure. -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ --#ifndef __MTK_SDW_COMMON_H --#define __MTK_SDW_COMMON_H -- --#include "mtk-sdw-core.h" -- --struct mtk_sdw; --struct mtk_sdw_top_cfg; --struct mtk_sdw_top_pdi_params; -- --enum mtk_sdw_hw_ver { -- MTK_SDW_HW_VER_MT8195 = 0, /* first chip */ -- MTK_SDW_HW_VER_MT8901, /* second chip */ -- MTK_SDW_HW_VER_MT8971, -- MTK_SDW_HW_VER_MAX, --}; -- --#define SDW_MAX_HWIP_NUM (2) --#define SDW_PDI_CONFIG_NUM (8) --#define MTK_SDW_MAX_GROUP_SYNC 4 --#define MTK_SDW_MAX_DP 16 -- --struct mtk_sdw_link { -- struct mtk_sdw_core core; -- struct mtk_sdw *master; -- int ip_idx; -- int irq; -- u32 src_base; -- u32 src_num; -- u32 sink_base; -- u32 sink_num; --}; -- --struct mtk_sdw_dai { -- struct mtk_sdw_link *link; -- unsigned int port_num; -- struct sdw_stream_runtime *sruntime; -- unsigned int pdi_count; -- struct mtk_sdw_pdi_params pdi_params[SDW_PDI_CONFIG_NUM]; -- struct mtk_sdw_top_pdi_params *top_pdi_params; -- bool use_group_sync; -- unsigned int group_sync_id; -- bool need_enable_delay; --}; -- --struct mtk_sdw { -- struct device *dev; -- void __iomem *base; /* full AFE MMIO */ -- struct mtk_sdw_link links[SDW_MAX_HWIP_NUM]; -- int num_links; -- u32 controller_en_list; -- const struct mtk_sdw_top_cfg *top_cfg; -- void __iomem *top_pdi; /* base + top_cfg->pdi_base */ -- void __iomem *top_con; /* base + top_cfg->con_base */ -- u32 hw_ver; -- /* group_lock: serializes group_refcnt[] group-sync allocation */ -- struct mutex group_lock; -- int group_refcnt[MTK_SDW_MAX_GROUP_SYNC]; -- u32 tzd_delay; -- bool tzd_inverse; -- u32 phy_delay; -- u32 phy_double_delay; -- struct mtk_sdw_dai *dais; -- int num_dais; -- u16 dp_pdi_mask[MTK_SDW_MAX_DP]; -- struct platform_device *mach_dev; --}; -- --#endif /* __MTK_SDW_COMMON_H */ -diff --git a/drivers/soundwire/mtk-sdw-core.c b/drivers/soundwire/mtk-sdw-core.c -deleted file mode 100644 -index 48b8346a80..0000000000 ---- a/drivers/soundwire/mtk-sdw-core.c -+++ /dev/null -@@ -1,895 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * MediaTek SoundWire master — STABLE controller core. -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ -- --#include --#include --#include --#include --#include -- --#include "bus.h" --#include "mtk-sdw-core.h" --#include "mtk-sdw.h" -- --/* ---- register helpers ---- */ --static u32 core_readl(struct mtk_sdw_core *core, u32 off) --{ -- return readl(core->regs + off); --} -- --static void core_writel(struct mtk_sdw_core *core, u32 off, u32 val) --{ -- writel(val, core->regs + off); --} -- --static void core_updatel(struct mtk_sdw_core *core, u32 off, u32 mask, u32 val) --{ -- u32 tmp = core_readl(core, off); -- -- core_writel(core, off, (tmp & ~mask) | (val & mask)); --} -- --static u32 core_get_slave_status(struct mtk_sdw_core *core, u32 dev_addr) --{ -- u32 slave_stat = 0; -- -- if (dev_addr > SDW_MAX_DEVICES) { -- dev_err(core->dev, "Unexpected device id %u\n", dev_addr); -- return slave_stat; -- } -- slave_stat = core_readl(core, MCP_SLAVESTAT); -- slave_stat = MCP_SLAVESTAT_STATUS(slave_stat, dev_addr); -- -- return slave_stat; --} -- --#define CORE_CMD_TIMEOUT_US 50000 --#define CORE_CMD_POLL_US 10 -- --static int core_send_cmd(struct mtk_sdw_core *core, u32 cmd, u8 *rdata) --{ -- u32 resp; -- int ret; -- -- core_writel(core, MCP_COMMAND(0), cmd); -- -- ret = readl_poll_timeout(core->regs + MCP_STAT, resp, -- resp & MCP_STAT_RX_NE, -- CORE_CMD_POLL_US, CORE_CMD_TIMEOUT_US); -- if (ret) { -- dev_err(core->dev, "cmd 0x%08x timeout\n", cmd); -- return SDW_CMD_TIMEOUT; -- } -- -- resp = core_readl(core, MCP_COMMAND(0)); -- if (FIELD_GET(MCP_RESP_NAK, resp)) -- return SDW_CMD_FAIL; -- if (!FIELD_GET(MCP_RESP_ACK, resp)) -- return SDW_CMD_IGNORED; -- if (rdata) -- *rdata = FIELD_GET(MCP_RESP_RDATA, resp); -- -- return SDW_CMD_OK; --} -- --static enum sdw_command_response --mtk_program_scp_addr(struct mtk_sdw_core *core, struct sdw_msg *msg) --{ -- int ret; -- u32 p1 = FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -- FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -- FIELD_PREP(MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE1) | -- FIELD_PREP(MCP_CMD_REG_DATA, msg->addr_page1); -- u32 p2 = FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -- FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -- FIELD_PREP(MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE2) | -- FIELD_PREP(MCP_CMD_REG_DATA, msg->addr_page2); -- -- ret = core_send_cmd(core, p1, NULL); -- if (ret == SDW_CMD_OK) -- ret = core_send_cmd(core, p2, NULL); -- -- return ret; --} -- --static int mtk_core_prep_msg(struct mtk_sdw_core *core, struct sdw_msg *msg) --{ -- int ret; -- -- if (msg->page) { -- ret = mtk_program_scp_addr(core, msg); -- if (ret) { -- msg->len = 0; -- return ret; -- } -- } -- -- switch (msg->flags) { -- case SDW_MSG_FLAG_READ: -- case SDW_MSG_FLAG_WRITE: -- break; -- default: -- dev_err(core->dev, "Invalid msg cmd: %d\n", msg->flags); -- return -EINVAL; -- } -- -- return 0; --} -- --/* ======================================================================= -- * sdw_master_ops -- * ======================================================================= -- */ --static enum sdw_command_response --mtk_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) --{ -- struct mtk_sdw_core *core = bus_to_core(bus); -- int i, ret = 0; -- -- ret = mtk_core_prep_msg(core, msg); -- if (ret) -- return SDW_CMD_FAIL_OTHER; -- -- for (i = 0; i < msg->len; i++) { -- u32 cmd = FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -- FIELD_PREP(MCP_CMD_REG_ADDR, msg->addr + i) | -- FIELD_PREP(MCP_CMD_SSP_TAG, msg->ssp_sync); -- -- if (msg->flags == SDW_MSG_FLAG_READ) { -- cmd |= FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_READ); -- ret = core_send_cmd(core, cmd, &msg->buf[i]); -- } else { -- cmd |= FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_WRITE) | -- FIELD_PREP(MCP_CMD_REG_DATA, msg->buf[i]); -- ret = core_send_cmd(core, cmd, NULL); -- } -- if (ret) -- break; -- } -- -- return ret; --} -- --static u32 mtk_sdw_read_ping_status(struct sdw_bus *bus) --{ -- struct mtk_sdw_core *core = bus_to_core(bus); -- -- return core_readl(core, MCP_SLAVESTAT); --} -- --static bool mipi_fwnode_property_read_bool(const struct fwnode_handle *fwnode, -- const char *propname) --{ -- int ret; -- u8 val; -- -- if (!fwnode_property_present(fwnode, propname)) -- return false; -- ret = fwnode_property_read_u8_array(fwnode, propname, &val, 1); -- if (ret < 0) -- return false; -- return !!val; --} -- --static int mtk_sdw_read_prop(struct sdw_bus *bus) --{ -- struct sdw_master_prop *prop = &bus->prop; -- struct fwnode_handle *link; -- char name[40]; -- int nval; -- int ret; -- int i; -- int id = 0; -- -- snprintf(name, sizeof(name), "mipi-sdw-%d-sw-interface-revision", -- bus->link_id); -- -- device_property_read_u32(bus->dev, name, &prop->revision); -- -- /* Find master handle */ -- snprintf(name, sizeof(name), -- "mipi-sdw-%d-link-%d-subproperties", bus->link_id, id); -- -- link = device_get_named_child_node(bus->dev, name); -- if (!link) { -- dev_err(bus->dev, "Master node %s not found\n", name); -- return -EIO; -- } -- -- for (i = SDW_CLK_STOP_MODE0; i <= SDW_CLK_STOP_MODE1; i++) { -- snprintf(name, sizeof(name), -- "mipi-sdw-clock-stop-mode%d-supported", i); -- if (mipi_fwnode_property_read_bool(link, name)) -- prop->clk_stop_modes |= BIT(i); -- } -- -- fwnode_property_read_u32(link, -- "mipi-sdw-max-clock-frequency", -- &prop->max_clk_freq); -- -- nval = fwnode_property_count_u32(link, -- "mipi-sdw-clock-frequencies-supported"); -- if (nval > 0) { -- prop->num_clk_freq = nval; -- prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq, -- sizeof(*prop->clk_freq), -- GFP_KERNEL); -- if (!prop->clk_freq) { -- fwnode_handle_put(link); -- return -ENOMEM; -- } -- -- ret = fwnode_property_read_u32_array(link, -- "mipi-sdw-clock-frequencies-supported", -- prop->clk_freq, -- prop->num_clk_freq); -- if (ret < 0) { -- fwnode_handle_put(link); -- return ret; -- } -- } -- -- /* -- * Check the frequencies supported. If FW doesn't provide max -- * freq, then populate here by checking values. -- */ -- if (!prop->max_clk_freq && prop->clk_freq) { -- prop->max_clk_freq = prop->clk_freq[0]; -- for (i = 1; i < prop->num_clk_freq; i++) { -- if (prop->clk_freq[i] > prop->max_clk_freq) -- prop->max_clk_freq = prop->clk_freq[i]; -- } -- } -- -- fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate", -- &prop->default_frame_rate); -- -- fwnode_property_read_u32(link, "mipi-sdw-default-frame-row-size", -- &prop->default_row); -- -- fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size", -- &prop->default_col); -- -- fwnode_handle_put(link); -- -- /* -- * sdw_bus_master_add() derives the bus data-rate limits from these -- * right after read_prop returns, so the fallbacks must be in place -- * here rather than after the master is added. -- */ -- if (!prop->max_clk_freq) -- prop->max_clk_freq = SDW_DEFAULT_MAX_BUS_CLK_FREQ; -- if (!prop->default_frame_rate) -- prop->default_frame_rate = SDW_DEFAULT_FRAME_RATE; -- if (!prop->default_row) -- prop->default_row = SDW_DEFAULT_FRAME_SHAPE_ROW; -- if (!prop->default_col) -- prop->default_col = SDW_DEFAULT_FRAME_SHAPE_COL; -- -- return 0; --} -- --static int mtk_sdw_set_bus_conf(struct sdw_bus *bus, -- struct sdw_bus_params *params) --{ -- struct mtk_sdw_core *core = bus_to_core(bus); -- struct sdw_master_prop *prop = &bus->prop; -- u8 next = params->next_bank ? 1 : 0; -- u32 mclkd; -- -- /* curr_dr_freq is the *double* rate; halve it to get the bus clock. */ -- if (params->curr_dr_freq && prop->mclk_freq) { -- mclkd = (prop->mclk_freq / params->curr_dr_freq); -- if (mclkd > 0) -- mclkd--; -- core_updatel(core, MCP_CLOCKCTRL(next), MCP_CLOCKCTRL_MCLKD, -- FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -- core->curr_clk_freq = params->curr_dr_freq / 2; -- } -- return 0; --} -- --/* ======================================================================= -- * Port ops -- * ======================================================================= -- */ -- --/* Source: word length, flow mode, data mode */ --static int mtk_sdw_dpn_set_port_params(struct sdw_bus *bus, -- struct sdw_port_params *params, -- unsigned int bank) --{ -- struct mtk_sdw_core *core = bus_to_core(bus); -- unsigned int p = params->num; -- u32 cfg; -- -- cfg = core_readl(core, MCP_DPN_CONFIG(p, bank)); -- -- /* Bits per sample: encoded as (bps - 1). */ -- u32p_replace_bits(&cfg, params->bps - 1, MCP_DPN_CONFIG_WL); -- /* Port flow mode (isochronous=0 / async=1).*/ -- u32p_replace_bits(&cfg, params->flow_mode, MCP_DPN_CONFIG_PFM); -- /* Test/normal data mode. */ -- u32p_replace_bits(&cfg, params->data_mode, MCP_DPN_CONFIG_PDM); -- -- core_writel(core, MCP_DPN_CONFIG(p, bank), cfg); -- return 0; --} -- --/* sample interval, block offsets, h-ctrl, BGC/BPM */ --static int --mtk_sdw_dpn_set_port_transport_params(struct sdw_bus *bus, -- struct sdw_transport_params *params, -- enum sdw_reg_bank bank) --{ -- struct mtk_sdw_core *core = bus_to_core(bus); -- unsigned int p = params->port_num; -- u8 bk = (bank == SDW_BANK1) ? 1 : 0; -- u32 cfg, offsetctrl, hctrl; -- -- /* BGC and BPM live in DPN_CONFIG alongside WL/PFM/PDM. */ -- cfg = core_readl(core, MCP_DPN_CONFIG(p, bk)); -- u32p_replace_bits(&cfg, params->blk_grp_ctrl, MCP_DPN_CONFIG_BGC); -- u32p_replace_bits(&cfg, params->blk_pkg_mode, MCP_DPN_CONFIG_BPM); -- core_writel(core, MCP_DPN_CONFIG(p, bk), cfg); -- -- /* Sample interval: encoded as (interval - 1). */ -- core_writel(core, MCP_DPN_SAMPLECTRL(p, bk), -- FIELD_PREP(MCP_DPN_SAMPLECTRL_INTERVAL, -- params->sample_interval - 1)); -- -- /* Block offsets 1 and 2. */ -- offsetctrl = FIELD_PREP(MCP_DPN_OFFSETCTRL_OFFSET1, params->offset1) | -- FIELD_PREP(MCP_DPN_OFFSETCTRL_OFFSET2, params->offset2); -- core_writel(core, MCP_DPN_OFFSETCTRL(p, bk), offsetctrl); -- -- /* Horizontal start/stop and lane control. */ -- hctrl = FIELD_PREP(MCP_DPN_HCTRL_HSTART, params->hstart) | -- FIELD_PREP(MCP_DPN_HCTRL_HSTOP, params->hstop) | -- FIELD_PREP(MCP_DPN_HCTRL_LANECTRL, params->lane_ctrl); -- core_writel(core, MCP_DPN_HCTRL(p, bk), hctrl); -- -- return 0; --} -- --static int mtk_sdw_dpn_port_enable_ch(struct sdw_bus *bus, -- struct sdw_enable_ch *enable_ch, -- unsigned int bank) --{ -- struct mtk_sdw_core *core = bus_to_core(bus); -- unsigned int p = enable_ch->port_num; -- u32 val = 0; -- -- if (enable_ch->enable) -- val = FIELD_PREP(MCP_DPN_CHANNELEN_EN, enable_ch->ch_mask); -- -- core_writel(core, MCP_DPN_CHANNELEN(p, bank), val); -- return 0; --} -- --void mtk_sdw_core_dump_dpn_regs(struct mtk_sdw_core *core, unsigned int port, -- const char *tag) --{ -- struct sdw_bus *bus = &core->bus; -- int bk; -- -- dev_dbg(core->dev, -- "%s: port %u curr_bank=%d next_bank=%d\n", -- tag, port, bus->params.curr_bank, bus->params.next_bank); -- -- for (bk = 0; bk < 2; bk++) { -- u32 config = core_readl(core, MCP_DPN_CONFIG(port, bk)); -- u32 channelen = core_readl(core, MCP_DPN_CHANNELEN(port, bk)); -- u32 samplectrl = core_readl(core, MCP_DPN_SAMPLECTRL(port, bk)); -- u32 offsetctrl = core_readl(core, MCP_DPN_OFFSETCTRL(port, bk)); -- u32 hctrl = core_readl(core, MCP_DPN_HCTRL(port, bk)); -- -- dev_dbg(core->dev, -- "%s: port %u bank%d:\n" -- "CONFIG=0x%08x (wl=%lu pfm=%lu pdm=%lu bgc=%lu bpm=%lu)\n" -- "CHANNELEN=0x%08x\n" -- "SAMPLECTRL=0x%08x (interval=%lu)\n" -- "OFFSETCTRL=0x%08x (off1=%lu off2=%lu)\n" -- "HCTRL=0x%08x (hstart=%lu hstop=%lu lane=%lu)\n", -- tag, port, bk, config, -- FIELD_GET(MCP_DPN_CONFIG_WL, config) + 1, -- FIELD_GET(MCP_DPN_CONFIG_PFM, config), -- FIELD_GET(MCP_DPN_CONFIG_PDM, config), -- FIELD_GET(MCP_DPN_CONFIG_BGC, config), -- FIELD_GET(MCP_DPN_CONFIG_BPM, config), -- channelen, samplectrl, -- FIELD_GET(MCP_DPN_SAMPLECTRL_INTERVAL, samplectrl) + 1, -- offsetctrl, -- FIELD_GET(MCP_DPN_OFFSETCTRL_OFFSET1, offsetctrl), -- FIELD_GET(MCP_DPN_OFFSETCTRL_OFFSET2, offsetctrl), -- hctrl, -- FIELD_GET(MCP_DPN_HCTRL_HSTART, hctrl), -- FIELD_GET(MCP_DPN_HCTRL_HSTOP, hctrl), -- FIELD_GET(MCP_DPN_HCTRL_LANECTRL, hctrl)); -- } --} --EXPORT_SYMBOL_GPL(mtk_sdw_core_dump_dpn_regs); -- --const struct sdw_master_port_ops mtk_sdw_core_port_ops = { -- .dpn_set_port_params = mtk_sdw_dpn_set_port_params, -- .dpn_set_port_transport_params = mtk_sdw_dpn_set_port_transport_params, -- .dpn_port_enable_ch = mtk_sdw_dpn_port_enable_ch, --}; -- --const struct sdw_master_ops mtk_sdw_core_ops = { -- .read_prop = mtk_sdw_read_prop, -- .read_ping_status = mtk_sdw_read_ping_status, -- .xfer_msg = mtk_sdw_xfer_msg, -- .set_bus_conf = mtk_sdw_set_bus_conf, --}; -- --static int mtk_do_config_update(struct mtk_sdw_core *core) --{ -- u32 val; -- int ret; -- -- core_updatel(core, MCP_CONFIGUPDATE, MCP_CONFIGUPDATE_CU, -- MCP_CONFIGUPDATE_CU); -- ret = readl_poll_timeout(core->regs + MCP_CONFIGUPDATE, val, -- !(val & MCP_CONFIGUPDATE_CU), 100, 2000); -- if (ret) { -- dev_err(core->dev, "config update timeout\n"); -- return ret; -- } -- return 0; --} -- --static int mtk_init_clock_ctrl(struct mtk_sdw_core *core) --{ -- struct sdw_bus *bus = &core->bus; -- struct sdw_master_prop *prop = &bus->prop; -- int c; -- int r; -- u32 val; -- -- dev_dbg(core->dev, "mclk %d max %d row %d col %d\n", -- prop->mclk_freq, -- prop->max_clk_freq, -- prop->default_row, -- prop->default_col); -- -- /* Set clock divider */ -- if (bus->params.curr_dr_freq && prop->mclk_freq) { -- u32 mclkd = (prop->mclk_freq / bus->params.curr_dr_freq); -- -- if (mclkd > 0) -- mclkd--; -- core_updatel(core, MCP_CLOCKCTRL_B0, MCP_CLOCKCTRL_MCLKD, -- FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -- core_updatel(core, MCP_CLOCKCTRL_B1, MCP_CLOCKCTRL_MCLKD, -- FIELD_PREP(MCP_CLOCKCTRL_MCLKD, mclkd)); -- } -- -- r = sdw_find_row_index(prop->default_row); -- c = sdw_find_col_index(prop->default_col); -- val = FIELD_PREP(MCP_FRAMESHAPE_NC, c) | -- FIELD_PREP(MCP_FRAMESHAPE_NR, r); -- -- core_updatel(core, MCP_FRAMESHAPEINIT, -- (MCP_FRAMESHAPE_NC | MCP_FRAMESHAPE_NR), val); -- -- if (prop->default_frame_rate % SDW_GSYNC_HZ) { -- dev_warn(core->dev, -- "[%u] FrameRate:%u not aligned with GSYNC:%d", -- bus->link_id, prop->default_frame_rate, SDW_GSYNC_HZ); -- } -- -- val = prop->default_frame_rate / SDW_GSYNC_HZ; -- val = FIELD_PREP(MCP_SSP_CTRL_SSP_INTERVAL, val); -- -- core_updatel(core, MCP_SSP_CTRL_B0, MCP_SSP_CTRL_SSP_INTERVAL, val); -- core_updatel(core, MCP_SSP_CTRL_B1, MCP_SSP_CTRL_SSP_INTERVAL, val); -- -- return 0; --} -- --static int mtk_init_control_setting(struct mtk_sdw_core *core) --{ -- u32 val; -- u32 mask; -- -- mask = MCP_CONTROL_RST_DELAY | MCP_CONTROL_CMD_RST | -- MCP_CONTROL_CMD_ACCEPT_MODE; -- -- val = FIELD_PREP(MCP_CONTROL_RST_DELAY, 1) | MCP_CONTROL_CMD_RST; -- -- core_updatel(core, MCP_CONTROL, mask, val); -- -- return mtk_do_config_update(core); --} -- --static int mtk_init_config_setting(struct mtk_sdw_core *core) --{ -- u32 val; -- u32 mask; -- -- mask = MCP_CONFIG_MCR | MCP_CONFIG_OP_MODE; -- -- val = FIELD_PREP(MCP_CONFIG_MCR, SDW_DEFAULT_MAX_CMD_RETRY) | -- FIELD_PREP(MCP_CONFIG_OP_MODE, MCP_OP_MODE_NORMAL); -- -- core_updatel(core, MCP_CONFIG, mask, val); -- -- return mtk_do_config_update(core); --} -- --static void mtk_sdw_enable_master_irq(struct mtk_sdw_core *core, bool enable) --{ -- core_updatel(core, MCP_INTMASK, (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP), -- enable ? (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP) : 0); --} -- --void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) --{ -- if (enable) { -- core_writel(core, MCP_SLAVEINTMASK0, MCP_SLAVE_INTMASK0_MASK); -- core_writel(core, MCP_SLAVEINTMASK1, MCP_SLAVE_INTMASK1_MASK); -- } else { -- core_writel(core, MCP_SLAVEINTMASK0, 0); -- core_writel(core, MCP_SLAVEINTMASK1, 0); -- } -- -- mtk_sdw_enable_slave_irq(core, enable); -- -- mtk_sdw_enable_master_irq(core, enable); -- -- core->interrupt_enabled = enable; -- -- if (!enable) -- cancel_work_sync(&core->work); -- -- core_updatel(core, MCP_INTMASK, MCP_INT_IRQ, -- enable ? MCP_INT_IRQ : 0); --} -- --void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable) --{ -- core_updatel(core, MCP_INTMASK, MCP_INT_SLV_MASK, -- enable ? MCP_INT_SLV_MASK : 0); --} -- --/* -- * slave IRQ handling -- */ --static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, -- u64 slave_intstat) --{ -- enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; -- bool need_handle_slave = false; -- u32 intstat; -- u32 val; -- int i, set_status; -- -- memset(status, 0, sizeof(status)); -- -- for (i = 0; i <= SDW_MAX_DEVICES; i++) { -- intstat = MCP_SLAVEINTSTAT_STATUS(slave_intstat, i); -- -- set_status = 0; -- -- if (intstat) { -- need_handle_slave = true; -- -- if (intstat & MCP_SLAVEINTSTAT_RESERVED) { -- status[i] = SDW_SLAVE_RESERVED; -- set_status++; -- } -- -- if (intstat & MCP_SLAVEINTSTAT_ALERT) { -- status[i] = SDW_SLAVE_ALERT; -- set_status++; -- } -- -- if (intstat & MCP_SLAVEINTSTAT_ATTACHED) { -- status[i] = SDW_SLAVE_ATTACHED; -- set_status++; -- } -- -- if (intstat & MCP_SLAVEINTSTAT_NOT_PRESENT) { -- status[i] = SDW_SLAVE_UNATTACHED; -- set_status++; -- } -- } -- -- if (set_status != 1) { -- val = core_get_slave_status(core, i); -- -- switch (val) { -- case 0: -- status[i] = SDW_SLAVE_UNATTACHED; -- break; -- case 1: -- status[i] = SDW_SLAVE_ATTACHED; -- break; -- case 2: -- status[i] = SDW_SLAVE_ALERT; -- break; -- case 3: -- default: -- status[i] = SDW_SLAVE_RESERVED; -- break; -- } -- } -- } -- -- if (need_handle_slave) -- return sdw_handle_slave_status(&core->bus, status); -- -- return 0; --} -- --static void mtk_sdw_slave_status_work(struct work_struct *work) --{ -- struct mtk_sdw_core *core = -- container_of(work, struct mtk_sdw_core, work); -- u32 stat0; -- u32 stat1; -- u32 dev0_stat; -- int retries = 0; -- u64 slv_intstat; -- -- core_writel(core, MCP_INTSTAT, MCP_INT_SLV_MASK); -- -- stat0 = core_readl(core, MCP_SLAVEINTSTAT0); -- stat1 = core_readl(core, MCP_SLAVEINTSTAT1); -- -- core_writel(core, MCP_SLAVEINTSTAT0, stat0); -- core_writel(core, MCP_SLAVEINTSTAT1, stat1); -- dev_dbg_ratelimited(core->dev, "Slave intstat0: 0x%x, intstat1 0x%x\n", -- stat0, stat1); -- -- slv_intstat = ((u64)stat1 << 32) | stat0; -- -- do { -- mtk_sdw_update_slave_status(core, slv_intstat); -- -- dev0_stat = core_get_slave_status(core, 0); -- -- if (dev0_stat == MCP_SLAVESTAT_ATTACHED) { -- slv_intstat = MCP_SLAVEINTSTAT_ATTACHED; -- dev_info(core->dev, -- "[%u] slave attached Dev0Stat:0x%x Retries:%d", -- core->bus.link_id, dev0_stat, retries); -- } else { -- break; -- } -- -- } while (retries++ < SDW_MAX_DEVICES); -- -- mtk_sdw_enable_slave_irq(core, true); --} -- --static void mtk_sdw_handle_master_dp_interrupt(struct mtk_sdw_core *core) --{ -- u32 portintstatus = core_readl(core, MCP_PORTINTSTAT); -- u32 pdistatus = core_readl(core, MCP_PDISTAT); -- struct sdw_bus *bus = &core->bus; -- -- dev_info(core->dev, "[%u]PortIntStatus:0x%x PdiStatus:0x%x\n", -- bus->link_id, portintstatus, pdistatus); -- -- if (portintstatus) -- core_writel(core, MCP_PORTINTSTAT, portintstatus); -- -- if (pdistatus) -- core_writel(core, MCP_PDISTAT, pdistatus); --} -- --static void mtk_sdw_recalc_block_offset(struct sdw_port_runtime *p_rt) --{ -- struct sdw_transport_params *tp = &p_rt->transport_params; -- int offset; -- -- offset = (tp->offset2 << 8) + tp->offset1; -- offset -= 1; -- -- tp->offset1 = offset & 0xFF; -- tp->offset2 = offset >> 8; --} -- --static int mtk_sdw_compute_params(struct sdw_bus *bus, -- struct sdw_stream_runtime *stream) --{ -- struct sdw_master_runtime *m_rt; -- struct sdw_slave_runtime *s_rt; -- struct sdw_port_runtime *p_rt; -- int ret; -- -- ret = sdw_compute_params(bus, stream); -- if (ret) -- return ret; -- -- /* block offset should begin from 0 */ -- list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { -- list_for_each_entry(p_rt, &m_rt->port_list, port_node) -- mtk_sdw_recalc_block_offset(p_rt); -- -- list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) -- list_for_each_entry(p_rt, &s_rt->port_list, port_node) -- mtk_sdw_recalc_block_offset(p_rt); -- } -- -- return 0; --} -- --int mtk_sdw_core_init(struct mtk_sdw_core *core) --{ -- core->bus.ops = &mtk_sdw_core_ops; -- core->bus.port_ops = &mtk_sdw_core_port_ops; -- core->bus.compute_params = mtk_sdw_compute_params; -- -- INIT_WORK(&core->work, mtk_sdw_slave_status_work); -- return 0; --} -- --int mtk_sdw_core_hw_init(struct mtk_sdw_core *core) --{ -- int ret; -- -- ret = mtk_init_clock_ctrl(core); -- if (ret) -- return ret; -- -- ret = mtk_init_control_setting(core); -- if (ret) -- return ret; -- -- ret = mtk_init_config_setting(core); -- if (ret) -- return ret; -- -- return 0; --} -- --irqreturn_t mtk_sdw_core_irq(int irq, void *data) --{ -- struct mtk_sdw_core *core = data; -- struct sdw_bus *bus = &core->bus; -- u32 intstat = core_readl(core, MCP_INTSTAT); -- u32 clearstat; -- -- if (!(intstat & MCP_INT_IRQ)) { -- dev_warn(core->dev, -- "[%u]interrupt request not enabled IntStatus:0x%x", -- bus->link_id, intstat); -- return IRQ_NONE; -- } -- -- clearstat = intstat; -- -- if (intstat & MCP_INT_WAKEUP) -- dev_err(core->dev, "[%u]wakeup IntStatus:0x%x\n", -- bus->link_id, intstat); -- -- if (intstat & MCP_INT_SLV_MASK) { -- if (intstat & MCP_INT_SLV_RESERVED) { -- dev_info(core->dev, "[%u]slave reserved int IntStatus:0x%x\n", -- bus->link_id, intstat); -- } -- -- if (intstat & MCP_INT_SLV_ALERT) { -- dev_info(core->dev, -- "[%u]slave alert int IntStatus:0x%x\n", -- bus->link_id, intstat); -- } -- -- if (intstat & MCP_INT_SLV_ATTACHED) { -- dev_info(core->dev, -- "[%u]slave attached int IntStatus:0x%x\n", -- bus->link_id, intstat); -- } -- -- if (intstat & MCP_INT_SLV_NOT_ATTACH) { -- dev_info(core->dev, -- "[%u]slave not attached int IntStatus:0x%x\n", -- bus->link_id, intstat); -- } -- if (core->interrupt_enabled) { -- schedule_work(&core->work); -- mtk_sdw_enable_slave_irq(core, false); -- clearstat &= ~MCP_INT_SLV_MASK; -- } -- } -- if (intstat & MCP_INT_DP_INT) { -- dev_info(core->dev, "[%u]dp int IntStatus:0x%x\n", bus->link_id, -- intstat); -- -- mtk_sdw_handle_master_dp_interrupt(core); -- } -- -- if (intstat & (MCP_INT_CTL_BUS_CLASH)) -- dev_err(core->dev, "[%u]control bus clash 0x%x\n", bus->link_id, -- intstat); -- -- if (intstat & (MCP_INT_DATA_BUS_CLASH)) -- dev_err(core->dev, "[%u]data bus clash 0x%x\n", bus->link_id, -- intstat); -- -- if (intstat & MCP_INT_PARITY_ERR) -- dev_err(core->dev, "[%u]parity error 0x%x\n", bus->link_id, -- intstat); -- -- if (intstat & MCP_INT_CMD_ERR) -- dev_err(core->dev, "[%u]command error 0x%x\n", bus->link_id, -- intstat); -- -- if (intstat & MCP_INT_RXWL) -- dev_info(core->dev, "[%u]rw wl 0x%x\n", bus->link_id, intstat); -- -- dev_info(core->dev, "[%u]ClearStatus 0x%x, IntStatus 0x%x\n", -- bus->link_id, clearstat, intstat); -- -- core_writel(core, MCP_INTSTAT, clearstat); -- -- return IRQ_HANDLED; --} -- --void mtk_sdw_configure_pdi_params(struct mtk_sdw_core *core, -- struct mtk_sdw_pdi_params *params) --{ -- u32 offset; -- u32 val; -- u32 mask; -- -- offset = MCP_PDIN_CONFIG(params->pdi_num); -- -- mask = MCP_PDIN_CONFIG_SOFTRST | MCP_PDIN_CONFIG_CHANNELMASK | -- MCP_PDIN_CONFIG_PORTNUM; -- -- val = MCP_PDIN_CONFIG_SOFTRST | -- FIELD_PREP(MCP_PDIN_CONFIG_CHANNELMASK, params->ch_mask) | -- FIELD_PREP(MCP_PDIN_CONFIG_PORTNUM, params->port_num); -- -- core_updatel(core, offset, mask, val); --} -- --void mtk_sdw_clear_pdi_settings(struct mtk_sdw_core *core, -- struct mtk_sdw_pdi_params *pdi) --{ -- u32 offset; -- u32 val; -- u32 mask; -- -- offset = MCP_PDIN_CONFIG(pdi->pdi_num); -- -- /* clear pdi fifo */ -- mask = MCP_PDIN_CONFIG_SOFTRST; -- val = MCP_PDIN_CONFIG_SOFTRST; -- core_updatel(core, offset, mask, val); -- -- /* clear pdi channel mask */ -- mask = MCP_PDIN_CONFIG_CHANNELMASK; -- val = FIELD_PREP(MCP_PDIN_CONFIG_CHANNELMASK, 0); -- core_updatel(core, offset, mask, val); --} -- --void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, -- struct mtk_sdw_port_params *params, u32 dir) --{ -- u32 offset; -- u32 val = 0; -- u32 mask; -- -- offset = MCP_DPN_PORTCTRL(params->port_num); -- mask = MCP_DPN_PORTCTRL_DIR | MCP_DPN_PORTCTRL_BPT_EN | -- MCP_DPN_PORTCTRL_BPT_TYPE; -- if (dir == SDW_DATA_DIR_RX) -- val |= MCP_DPN_PORTCTRL_DIR; -- -- if (params->port_num == 0) /* bpt rx? */ -- val |= FIELD_PREP(MCP_DPN_PORTCTRL_BPT_EN, params->bpt_en) | -- FIELD_PREP(MCP_DPN_PORTCTRL_BPT_TYPE, -- params->bpt_payload_type); -- -- core_updatel(core, offset, mask, val); --} -diff --git a/drivers/soundwire/mtk-sdw-core.h b/drivers/soundwire/mtk-sdw-core.h -deleted file mode 100644 -index 4708a10865..0000000000 ---- a/drivers/soundwire/mtk-sdw-core.h -+++ /dev/null -@@ -1,234 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * MediaTek SoundWire master — STABLE controller core. -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ --#ifndef __MTK_SDW_CORE_H --#define __MTK_SDW_CORE_H -- --#include -- --#define SDW_GSYNC_HZ (8000) --#define SDW_DEFAULT_MAX_CMD_RETRY (5) --/* ======================================================================= -- * MCP (Master Control Port) registers -- * ======================================================================= -- */ --#define MCP_DP_SIZE 128 --#define MCP_PDI_SIZE 16 -- --#define MCP_CONFIG 0x0000 --#define MCP_CONTROL 0x0004 --#define MCP_CMDCTRL 0x0008 --#define MCP_SSPSTAT 0x000c --#define MCP_FRAMESHAPE 0x0010 --#define MCP_FRAMESHAPEINIT 0x0014 --#define MCP_CONFIGUPDATE 0x0018 --#define MCP_PHYCTRL 0x001c --#define MCP_SSP_CTRL_B0 0x0020 --#define MCP_SSP_CTRL_B1 0x0028 --#define MCP_CLOCKCTRL_B0 0x0030 --#define MCP_CLOCKCTRL_B1 0x0038 --#define MCP_STAT 0x0040 --#define MCP_INTSTAT 0x0044 --#define MCP_INTMASK 0x0048 --#define MCP_INTSET 0x004c --#define MCP_SLAVESTAT 0x0050 --#define MCP_SLAVEINTSTAT0 0x0054 --#define MCP_SLAVEINTSTAT1 0x0058 --#define MCP_SLAVEINTMASK0 0x005c --#define MCP_SLAVEINTMASK1 0x0060 --#define MCP_PORTINTSTAT 0x0064 --#define MCP_PDISTAT 0x006c --#define MCP_FIFOLEVEL 0x0078 --#define MCP_FIFOSTAT 0x007c --#define MCP_COMMAND(n) (0x0080 + (n) * 4) -- --#define MCP_DPN_CONFIG_B0(n) (0x0100 + (n) * MCP_DP_SIZE) --#define MCP_DPN_CHANNELEN_B0(n) (0x0104 + (n) * MCP_DP_SIZE) --#define MCP_DPN_SAMPLECTRL_B0(n) (0x0108 + (n) * MCP_DP_SIZE) --#define MCP_DPN_OFFSETCTRL_B0(n) (0x010c + (n) * MCP_DP_SIZE) --#define MCP_DPN_HCTRL_B0(n) (0x0110 + (n) * MCP_DP_SIZE) --#define MCP_DPN_CONFIG_B1(n) (0x0118 + (n) * MCP_DP_SIZE) --#define MCP_DPN_CHANNELEN_B1(n) (0x011c + (n) * MCP_DP_SIZE) --#define MCP_DPN_SAMPLECTRL_B1(n) (0x0120 + (n) * MCP_DP_SIZE) --#define MCP_DPN_OFFSETCTRL_B1(n) (0x0124 + (n) * MCP_DP_SIZE) --#define MCP_DPN_HCTRL_B1(n) (0x0128 + (n) * MCP_DP_SIZE) --#define MCP_DPN_PORTCTRL(n) (0x0130 + ((n) & 0xf) * MCP_DP_SIZE) --#define MCP_PDIN_CONFIG(n) (0x1100 + ((n) & 0xf) * MCP_PDI_SIZE) -- --/* Bank selectors: each takes (port, bank) / (bank) */ --#define MCP_DPN_CONFIG(n, b) \ -- ((b) ? MCP_DPN_CONFIG_B1(n) : MCP_DPN_CONFIG_B0(n)) --#define MCP_DPN_CHANNELEN(n, b) \ -- ((b) ? MCP_DPN_CHANNELEN_B1(n) : MCP_DPN_CHANNELEN_B0(n)) --#define MCP_DPN_SAMPLECTRL(n, b) \ -- ((b) ? MCP_DPN_SAMPLECTRL_B1(n) : MCP_DPN_SAMPLECTRL_B0(n)) --#define MCP_DPN_OFFSETCTRL(n, b) \ -- ((b) ? MCP_DPN_OFFSETCTRL_B1(n) : MCP_DPN_OFFSETCTRL_B0(n)) --#define MCP_DPN_HCTRL(n, b) \ -- ((b) ? MCP_DPN_HCTRL_B1(n) : MCP_DPN_HCTRL_B0(n)) --#define MCP_CLOCKCTRL(b) ((b) ? MCP_CLOCKCTRL_B1 : MCP_CLOCKCTRL_B0) -- --/* MCP_CONFIG */ --#define MCP_CONFIG_OP_MODE GENMASK(2, 0) --#define MCP_CONFIG_MCR GENMASK(27, 24) --#define MCP_OP_MODE_NORMAL 0 -- --/* MCP_CONTROL */ --#define MCP_CONTROL_CMD_ACCEPT_MODE BIT(1) --#define MCP_CONTROL_CLOCK_STOP_CLR BIT(2) --#define MCP_CONTROL_HW_BUS_RST BIT(4) --#define MCP_CONTROL_SOFT_RST BIT(6) --#define MCP_CONTROL_CMD_RST BIT(7) --#define MCP_CONTROL_RST_DELAY GENMASK(10, 8) -- --/* MCP_FRAMESHAPE(INIT) */ --#define MCP_FRAMESHAPE_NC GENMASK(2, 0) /* columns index */ --#define MCP_FRAMESHAPE_NR GENMASK(7, 3) /* rows, encoded (rows/2-1) */ -- --/* MCP_CONFIGUPDATE */ --#define MCP_CONFIGUPDATE_CU BIT(0) -- --/* MCP_SSP_CTRL */ --#define MCP_SSP_CTRL_SSP_INTERVAL GENMASK(7, 0) -- --/* MCP_CLOCKCTRL */ --#define MCP_CLOCKCTRL_MCLKD GENMASK(7, 0) -- --/* MCP_STAT */ --#define MCP_STAT_RX_NE BIT(3) --#define MCP_STAT_CLK_STOP BIT(16) -- --/* MCP_INTMASK / MCP_INTSTAT */ --#define MCP_INT_RXWL BIT(2) --#define MCP_INT_RXNE BIT(3) --#define MCP_INT_CMD_ERR BIT(7) --#define MCP_INT_PARITY_ERR BIT(8) --#define MCP_INT_DATA_BUS_CLASH BIT(9) --#define MCP_INT_CTL_BUS_CLASH BIT(10) --#define MCP_INT_DP_INT BIT(11) --#define MCP_INT_SLV_NOT_ATTACH BIT(12) --#define MCP_INT_SLV_ATTACHED BIT(13) --#define MCP_INT_SLV_ALERT BIT(14) --#define MCP_INT_SLV_RESERVED BIT(15) --#define MCP_INT_WAKEUP BIT(16) --#define MCP_INT_IRQ BIT(31) --#define MCP_INT_SLV_MASK (MCP_INT_SLV_RESERVED | \ -- MCP_INT_SLV_ALERT | \ -- MCP_INT_SLV_ATTACHED | \ -- MCP_INT_SLV_NOT_ATTACH) --#define MCP_INT_MST_ERR_MASK (MCP_INT_RXWL | \ -- MCP_INT_PARITY_ERR | \ -- MCP_INT_DATA_BUS_CLASH | \ -- MCP_INT_CTL_BUS_CLASH) -- --/* MCP_SLAVESTAT: 2 bits/slave; MCP_SLAVEINTSTAT: 4 bits/slave */ --#define MCP_SLAVESTAT_STATUS(x, n) (((x) >> ((n) * 2)) & 0x3) --#define MCP_SLAVESTAT_UNATTACHED 0x0 --#define MCP_SLAVESTAT_ATTACHED 0x1 --#define MCP_SLAVESTAT_ALERT 0x2 --#define MCP_SLAVEINTSTAT_STATUS(x, n) (((x) >> ((n) * 4)) & 0xf) --#define MCP_SLAVEINTSTAT_NOT_PRESENT BIT(0) --#define MCP_SLAVEINTSTAT_ATTACHED BIT(1) --#define MCP_SLAVEINTSTAT_ALERT BIT(2) --#define MCP_SLAVEINTSTAT_RESERVED BIT(3) -- --/* MCP_SLAVEINTMASK */ --#define MCP_SLAVE_INTMASK0_MASK GENMASK(31, 0) --#define MCP_SLAVE_INTMASK1_MASK GENMASK(15, 0) -- --/* MCP command word. CONFIRMED: dev_addr is 4-bit [27:24]. */ --#define MCP_CMD_READ 0x2 --#define MCP_CMD_WRITE 0x3 --#define MCP_CMD_SSP_TAG BIT(31) --#define MCP_CMD_FIELD GENMASK(30, 28) --#define MCP_CMD_DEV_ADDR GENMASK(27, 24) --#define MCP_CMD_REG_ADDR GENMASK(23, 8) --#define MCP_CMD_REG_DATA GENMASK(7, 0) -- --/* MCP command response. CONFIRMED. */ --#define MCP_RESP_ACK BIT(0) --#define MCP_RESP_NAK BIT(1) --#define MCP_RESP_RDATA GENMASK(15, 8) -- --/* Per-port transport fields (used by streaming) */ --#define MCP_DPN_CONFIG_PFM GENMASK(1, 0) /* port flow mode */ --#define MCP_DPN_CONFIG_PDM GENMASK(3, 2) /* port data mode */ --/* word length, encoded (wl-1) */ --#define MCP_DPN_CONFIG_WL GENMASK(12, 8) --#define MCP_DPN_CONFIG_BGC GENMASK(17, 16) /* block group control */ --#define MCP_DPN_CONFIG_BPM BIT(18) /* block packing mode */ --#define MCP_DPN_CHANNELEN_EN GENMASK(7, 0) --#define MCP_DPN_SAMPLECTRL_INTERVAL GENMASK(15, 0) /* encoded (interval-1) */ --#define MCP_DPN_OFFSETCTRL_OFFSET1 GENMASK(7, 0) --#define MCP_DPN_OFFSETCTRL_OFFSET2 GENMASK(15, 8) --#define MCP_DPN_HCTRL_HSTOP GENMASK(3, 0) --#define MCP_DPN_HCTRL_HSTART GENMASK(7, 4) --#define MCP_DPN_HCTRL_LANECTRL GENMASK(10, 8) /* data lane select */ -- --#define MCP_DPN_PORTCTRL_BPT_TYPE GENMASK(23, 22) --#define MCP_DPN_PORTCTRL_BPT_EN BIT(16) --#define MCP_DPN_PORTCTRL_DIR BIT(7) -- --#define MCP_PDIN_CONFIG_SOFTRST BIT(24) --#define MCP_PDIN_CONFIG_CHANNELMASK GENMASK(15, 8) --#define MCP_PDIN_CONFIG_PORTNUM GENMASK(4, 0) -- --/* ======================================================================= -- * Core object -- * ======================================================================= -- */ --struct mtk_sdw_core { -- struct sdw_bus bus; -- struct device *dev; -- void __iomem *regs; -- unsigned int curr_clk_freq; -- bool interrupt_enabled; -- u16 attached_slaves; -- void *priv; -- struct work_struct work; --}; -- --struct mtk_sdw_pdi_params { -- u32 pdi_num; -- u32 port_num; -- u32 ch_mask; --}; -- --struct mtk_sdw_port_params { -- u32 port_num; -- u32 bpt_payload_type; -- bool bpt_en; --}; -- --static inline struct mtk_sdw_core *bus_to_core(struct sdw_bus *bus) --{ -- return container_of(bus, struct mtk_sdw_core, bus); --} -- --/* ======================================================================= -- * Core API — called by the glue -- * ======================================================================= -- */ --extern const struct sdw_master_ops mtk_sdw_core_ops; --extern const struct sdw_master_port_ops mtk_sdw_core_port_ops; -- --int mtk_sdw_core_init(struct mtk_sdw_core *core); --int mtk_sdw_core_hw_init(struct mtk_sdw_core *core); --void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable); --void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable); --irqreturn_t mtk_sdw_core_irq(int irq, void *data); --void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, -- struct mtk_sdw_port_params *params, u32 dir); -- --void mtk_sdw_configure_pdi_params(struct mtk_sdw_core *core, -- struct mtk_sdw_pdi_params *params); --void mtk_sdw_clear_pdi_settings(struct mtk_sdw_core *core, -- struct mtk_sdw_pdi_params *pdi); --void mtk_sdw_core_dump_dpn_regs(struct mtk_sdw_core *core, unsigned int port, -- const char *tag); -- --#endif /* __MTK_SDW_CORE_H */ -diff --git a/drivers/soundwire/mtk-sdw-mach.c b/drivers/soundwire/mtk-sdw-mach.c -deleted file mode 100644 -index 582482b43e..0000000000 ---- a/drivers/soundwire/mtk-sdw-mach.c -+++ /dev/null -@@ -1,167 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * MediaTek SoundWire audio machine selection (codec-combination tables). -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ --#include --#include --#include --#include "mtk-sdw-mach.h" -- --static const struct snd_soc_acpi_endpoint rt1320_endpoints[] = { -- { -- .num = 0, -- .aggregated = 1, -- .group_position = 0, -- .group_id = 1, -- }, -- { -- .num = 0, -- .aggregated = 1, -- .group_position = 1, -- .group_id = 1, -- }, --}; -- --static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { -- { -- .num = 0, -- .aggregated = 0, -- .group_position = 0, -- .group_id = 0, -- }, -- { -- .num = 2, -- .aggregated = 0, -- .group_position = 0, -- .group_id = 0, -- }, --}; -- --/* -- * Config 0: SDW0 = RT1320 (amp), SDW1 = RT712 (jack codec). -- */ --static const struct snd_soc_acpi_adr_device rt1320_l0_adr[] = { -- { -- .adr = 0x000030025D132001ull, -- .num_endpoints = 1, -- .endpoints = &rt1320_endpoints[0], -- .name_prefix = "rt1320-1", -- }, -- { -- .adr = 0x000032025D132001ull, -- .num_endpoints = 1, -- .endpoints = &rt1320_endpoints[1], -- .name_prefix = "rt1320-2", -- }, --}; -- --static const struct snd_soc_acpi_adr_device rt712_l1_adr[] = { -- { -- .adr = 0x000130025D071201ull, -- .num_endpoints = ARRAY_SIZE(rt712_endpoints), -- .endpoints = rt712_endpoints, -- .name_prefix = "rt712", -- }, --}; -- --static const struct snd_soc_acpi_link_adr mtk_sdw_rt1320_l0_rt712_l1[] = { -- { -- .mask = BIT(0), -- .num_adr = ARRAY_SIZE(rt1320_l0_adr), -- .adr_d = rt1320_l0_adr, -- }, -- { -- .mask = BIT(1), -- .num_adr = ARRAY_SIZE(rt712_l1_adr), -- .adr_d = rt712_l1_adr, -- }, -- {} --}; -- --static struct snd_soc_acpi_mach mtk_sdw_machines[] = { -- { -- .link_mask = BIT(0) | BIT(1), -- .links = mtk_sdw_rt1320_l0_rt712_l1, -- .drv_name = "mtk_sdw_mc", -- }, -- {} --}; -- --static void mtk_sdw_log_peripheral(struct device *dev, -- struct sdw_slave *slave) --{ -- dev_info(dev, -- "[%d] class=0x%02x mfg=0x%04x part=0x%04x uniq=0x%x ver=0x%x\n", -- slave->bus->link_id, slave->id.class_id, slave->id.mfg_id, -- slave->id.part_id, slave->id.unique_id, slave->id.sdw_version); --} -- --static struct sdw_peripherals *mtk_sdw_get_peripherals(struct mtk_sdw *mst) --{ -- struct sdw_peripherals *peripherals; -- struct sdw_slave *slave; -- struct sdw_bus *bus; -- int max_peripherals_num; -- int i, idx = 0; -- -- max_peripherals_num = mst->num_links * SDW_MAX_DEVICES; -- -- peripherals = kmalloc_flex(*peripherals, array, max_peripherals_num, -- GFP_KERNEL); -- if (!peripherals) -- return NULL; -- -- for (i = 0; i < mst->num_links; i++) { -- bus = &mst->links[i].core.bus; -- mutex_lock(&bus->bus_lock); -- list_for_each_entry(slave, &bus->slaves, node) { -- if (idx >= max_peripherals_num) { -- dev_warn(mst->dev, "slave count exceeds capacity, truncating"); -- break; -- } -- peripherals->array[idx++] = slave; -- mtk_sdw_log_peripheral(mst->dev, slave); -- } -- mutex_unlock(&bus->bus_lock); -- } -- peripherals->num_peripherals = idx; -- -- return peripherals; --} -- --struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst) --{ -- struct sdw_peripherals *peripherals; -- struct snd_soc_acpi_mach *mach; -- const struct snd_soc_acpi_link_adr *link; -- -- peripherals = mtk_sdw_get_peripherals(mst); -- if (!peripherals) -- return NULL; -- -- if (!peripherals->num_peripherals) { -- dev_dbg(mst->dev, "no SoundWire peripherals enumerated\n"); -- kfree(peripherals); -- return NULL; -- } -- -- for (mach = mtk_sdw_machines; mach->link_mask; mach++) { -- for (link = mach->links; link && link->num_adr; link++) { -- if (!snd_soc_acpi_sdw_link_slaves_found(mst->dev, link, -- peripherals)) -- break; -- } -- if (link && !link->num_adr) { -- mach->mach_params.links = mach->links; -- mach->mach_params.link_mask = mach->link_mask; -- kfree(peripherals); -- return mach; -- } -- } -- dev_dbg(mst->dev, "no SoundWire machine matched\n"); -- kfree(peripherals); -- return NULL; --} -diff --git a/drivers/soundwire/mtk-sdw-mach.h b/drivers/soundwire/mtk-sdw-mach.h -deleted file mode 100644 -index 158aae2652..0000000000 ---- a/drivers/soundwire/mtk-sdw-mach.h -+++ /dev/null -@@ -1,20 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * MediaTek SoundWire audio machine selection (codec-combination tables). -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ --#ifndef __MTK_SDW_MACH_H --#define __MTK_SDW_MACH_H -- --#include "mtk-sdw-common.h" -- --struct snd_soc_acpi_mach; -- --/* mtk-sdw-mach.c: match enumerated SoundWire peripherals against the codec- -- * combination tables; returns the machine row to spawn, or NULL. -- */ --struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst); -- --#endif /* __MTK_SDW_MACH_H */ -diff --git a/drivers/soundwire/mtk-sdw-top.c b/drivers/soundwire/mtk-sdw-top.c -deleted file mode 100644 -index edc412f4e1..0000000000 ---- a/drivers/soundwire/mtk-sdw-top.c -+++ /dev/null -@@ -1,301 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * MediaTek SoundWire master — AFE TOP control -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ -- --#include --#include --#include --#include --#include --#include --#include "mtk-sdw-top.h" -- --static const struct mtk_sdw_top_cfg mtk_sdw_top_cfgs[MTK_SDW_TOP_VER_MAX] = { -- [MTK_SDW_TOP_VER_0] = { -- .name = "hw_8901", -- .reg = { -- .tzd_delay_reg = SDW_TOP_CON0, -- .tzd_delay_sel = GENMASK(5, 3), -- .tzd_inverse = BIT(2), -- .tzd_delay_en = BIT(1), -- .phy_delay_reg = SDW_TOP_CON1, -- .phy_delay_sel = GENMASK(3, 1), -- .phy_double_delay_sel = GENMASK(6, 4), -- }, -- }, --}; -- --static u32 topcon_readl(struct mtk_sdw *mst, u32 off) --{ -- return readl(mst->top_con + off); --} -- --static void topcon_writel(struct mtk_sdw *mst, u32 off, u32 val) --{ -- writel(val, mst->top_con + off); --} -- --static void topcon_updatel(struct mtk_sdw *mst, u32 off, u32 mask, u32 val) --{ -- u32 tmp = topcon_readl(mst, off); -- -- topcon_writel(mst, off, (tmp & ~mask) | (val & mask)); --} -- --static u32 toppdi_readl(struct mtk_sdw *mst, u32 off) --{ -- return readl(mst->top_pdi + off); --} -- --static void toppdi_writel(struct mtk_sdw *mst, u32 off, u32 val) --{ -- writel(val, mst->top_pdi + off); --} -- --static void toppdi_updatel(struct mtk_sdw *mst, u32 off, u32 mask, u32 val) --{ -- u32 tmp = toppdi_readl(mst, off); -- -- toppdi_writel(mst, off, (tmp & ~mask) | (val & mask)); --} -- --static inline u32 mtk_field_prep(u32 mask, u32 val) --{ -- if (!mask) -- return 0; -- return (val << __bf_shf(mask)) & mask; --} -- --int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver) --{ -- int ver_id; -- -- switch (hw_ver) { -- case MTK_SDW_HW_VER_MT8901: -- case MTK_SDW_HW_VER_MT8971: -- ver_id = MTK_SDW_TOP_VER_0; -- break; -- default: -- dev_err(mst->dev, "unsupported hw-ver %d\n", hw_ver); -- return -EINVAL; -- } -- -- mst->top_cfg = &mtk_sdw_top_cfgs[ver_id]; -- dev_info(mst->dev, "AFE TOP variant: %s (hw-ver %u)\n", -- mst->top_cfg->name, mst->hw_ver); -- return 0; --} -- --void mtk_sdw_top_init_settings(struct mtk_sdw *mst) --{ -- topcon_updatel(mst, SDW_TOP_CON0, SDW_TOP_CON0_GSYNC_DIR_CTRL, -- SDW_TOP_CON0_GSYNC_DIR_CTRL); --} -- --void mtk_sdw_top_configure_delays(struct mtk_sdw *mst) --{ -- u32 val = 0; -- u32 mask; -- const struct mtk_sdw_top_reg *top_reg = &mst->top_cfg->reg; -- -- mask = top_reg->tzd_delay_sel | top_reg->tzd_inverse | -- top_reg->tzd_delay_en; -- val |= mtk_field_prep(top_reg->tzd_delay_sel, mst->tzd_delay - 1); -- if (mst->tzd_inverse) -- val |= top_reg->tzd_inverse; -- if (mst->tzd_delay) -- val |= top_reg->tzd_delay_en; -- topcon_updatel(mst, top_reg->tzd_delay_reg, mask, val); -- -- val = 0; -- mask = top_reg->phy_delay_sel | top_reg->phy_double_delay_sel; -- val |= mtk_field_prep(top_reg->phy_delay_sel, mst->phy_delay); -- val |= mtk_field_prep(top_reg->phy_double_delay_sel, -- mst->phy_double_delay); -- -- topcon_updatel(mst, top_reg->phy_delay_reg, mask, val); --} -- --void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, -- struct mtk_sdw_top_pdi_params *param) --{ -- u32 val = 0; -- u32 mask = 0; -- -- mask |= SDW_TOP_PDI_GROUP_SYNC; -- -- val |= FIELD_PREP(SDW_TOP_PDI_SLAVE_MODE, param->slave_mode); -- mask |= SDW_TOP_PDI_SLAVE_MODE; -- -- val |= FIELD_PREP(SDW_TOP_PDI_BRA_SLAVE, param->bra_slave); -- mask |= SDW_TOP_PDI_BRA_SLAVE; -- -- val |= FIELD_PREP(SDW_TOP_PDI_BRA_EOP, param->bra_eop); -- mask |= SDW_TOP_PDI_BRA_EOP; -- -- val |= FIELD_PREP(SDW_TOP_PDI_BRA_MODE, param->bra_mode); -- mask |= SDW_TOP_PDI_BRA_MODE; -- -- val |= FIELD_PREP(SDW_TOP_PDI_DMIC_1XEN, param->dmic_1xen); -- mask |= SDW_TOP_PDI_DMIC_1XEN; -- -- val |= FIELD_PREP(SDW_TOP_PDI_PDM_ONE_WIRE, param->pdm_one_wire); -- mask |= SDW_TOP_PDI_PDM_ONE_WIRE; -- -- val |= FIELD_PREP(SDW_TOP_PDI_PDM_MODE, param->pdm_mode); -- mask |= SDW_TOP_PDI_PDM_MODE; -- -- val |= FIELD_PREP(SDW_TOP_PDI_HD_SEL, param->hd_sel); -- mask |= SDW_TOP_PDI_HD_SEL; -- -- val |= FIELD_PREP(SDW_TOP_PDI_CLOCK, param->clock); -- mask |= SDW_TOP_PDI_CLOCK; -- -- val |= FIELD_PREP(SDW_TOP_PDI_PDM2PCM, param->pdm2pcm); -- mask |= SDW_TOP_PDI_PDM2PCM; -- -- val |= FIELD_PREP(SDW_TOP_PDI_IP_SEL, param->sdw_ip_sel); -- mask |= SDW_TOP_PDI_IP_SEL; -- -- val |= FIELD_PREP(SDW_TOP_PDI_DOMAIN, param->domain); -- mask |= SDW_TOP_PDI_DOMAIN; -- -- val |= FIELD_PREP(SDW_TOP_PDI_FS, param->fs); -- mask |= SDW_TOP_PDI_FS; -- -- toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), mask, val); --} -- --static void mtk_sdw_top_enable_pdi_engen(struct mtk_sdw *mst, u32 pdi, -- bool enable) --{ -- toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_EN, -- enable ? SDW_TOP_PDI_EN : 0); --} -- --static void mtk_sdw_top_enable_group_sync(struct mtk_sdw *mst, u32 pdi, -- bool enable) --{ -- toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_GROUP_SYNC_ON, -- enable ? SDW_TOP_PDI_GROUP_SYNC_ON : 0); --} -- --static void mtk_sdw_top_config_group_sync(struct mtk_sdw *mst, u32 pdi, -- u32 group) --{ -- toppdi_updatel(mst, SDW_TOP_PDIN_CON0(pdi), SDW_TOP_PDI_GROUP_SYNC, -- FIELD_PREP(SDW_TOP_PDI_GROUP_SYNC, group)); --} -- --int mtk_sdw_top_group_sync_config_get(struct mtk_sdw *mst, u8 id, u32 *cfg) --{ -- if (id > MTK_SDW_MAX_GROUP_SYNC) -- return -EINVAL; -- else if (id == GROUP_SYNC_NONE) -- *cfg = 0; -- else -- *cfg = BIT(id - 1); -- -- return 0; --} -- --int mtk_sdw_top_group_sync_acquire(struct mtk_sdw *mst, bool is_tx) --{ -- u8 min_id = is_tx ? TOP_GROUP_SYNC_TX_MIN_ID : TOP_GROUP_SYNC_RX_MIN_ID; -- u8 max_id = is_tx ? TOP_GROUP_SYNC_TX_MAX_ID : TOP_GROUP_SYNC_RX_MAX_ID; -- int best = -1; -- int best_refcnt = INT_MAX; -- int i, idx; -- -- guard(mutex)(&mst->group_lock); -- -- for (i = 0; i < MTK_SDW_MAX_GROUP_SYNC; i++) { -- idx = is_tx ? i : (MTK_SDW_MAX_GROUP_SYNC - 1 - i); -- -- if (idx < min_id - 1 || idx > max_id - 1) -- continue; -- if (mst->group_refcnt[idx] < best_refcnt) { -- best = idx; -- best_refcnt = mst->group_refcnt[idx]; -- } -- } -- if (best < 0) -- return -EINVAL; -- -- mst->group_refcnt[best]++; -- return best + 1; /* 1-based id */ --} -- --void mtk_sdw_top_group_sync_release(struct mtk_sdw *mst, u8 id) --{ -- if (id == 0 || id > MTK_SDW_MAX_GROUP_SYNC) -- return; -- -- guard(mutex)(&mst->group_lock); -- -- if (mst->group_refcnt[id - 1] <= 0) { -- dev_err(mst->dev, "unexpected refcnt %d\n", -- mst->group_refcnt[id - 1]); -- return; -- } -- mst->group_refcnt[id - 1]--; --} -- --int mtk_sdw_top_enable_stream(struct mtk_sdw *mst, int dai_id) --{ -- struct mtk_sdw_dai *mdai = &mst->dais[dai_id]; -- int i; -- u32 pdi_num, group_sync; -- -- for (i = 0; i < mdai->pdi_count; i++) { -- pdi_num = mdai->pdi_params[i].pdi_num; -- mtk_sdw_top_enable_pdi_engen(mst, pdi_num, true); -- } -- -- if (mdai->need_enable_delay) -- usleep_range(1000, 1100); -- -- if (mdai->use_group_sync) { -- for (i = 0; i < mdai->pdi_count; i++) { -- pdi_num = mdai->pdi_params[i].pdi_num; -- group_sync = mdai->top_pdi_params[i].group_sync; -- mtk_sdw_top_config_group_sync(mst, pdi_num, group_sync); -- } -- for (i = 0; i < mdai->pdi_count; i++) { -- pdi_num = mdai->pdi_params[i].pdi_num; -- mtk_sdw_top_enable_group_sync(mst, pdi_num, true); -- } -- } -- -- return 0; --} -- --int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id) --{ -- struct mtk_sdw_dai *mdai = &mst->dais[dai_id]; -- int i; -- u32 pdi_num; -- -- for (i = 0; i < mdai->pdi_count; i++) { -- pdi_num = mdai->pdi_params[i].pdi_num; -- mtk_sdw_top_enable_pdi_engen(mst, pdi_num, false); -- } -- -- if (mdai->use_group_sync) { -- for (i = 0; i < mdai->pdi_count; i++) { -- pdi_num = mdai->pdi_params[i].pdi_num; -- mtk_sdw_top_enable_group_sync(mst, pdi_num, false); -- } -- -- for (i = 0; i < mdai->pdi_count; i++) { -- pdi_num = mdai->pdi_params[i].pdi_num; -- mtk_sdw_top_config_group_sync(mst, pdi_num, 0); -- } -- } -- -- return 0; --} -diff --git a/drivers/soundwire/mtk-sdw-top.h b/drivers/soundwire/mtk-sdw-top.h -deleted file mode 100644 -index f12c090d60..0000000000 ---- a/drivers/soundwire/mtk-sdw-top.h -+++ /dev/null -@@ -1,105 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * MediaTek SoundWire master — AFE TOP control. -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ --#ifndef __MTK_SDW_TOP_H --#define __MTK_SDW_TOP_H -- --#include "mtk-sdw-common.h" -- --enum mtk_sdw_group_sync_sel { -- GROUP_SYNC_NONE = 0, -- GROUP_1_SYNC, -- GROUP_2_SYNC, -- GROUP_3_SYNC, -- GROUP_4_SYNC, --}; -- --enum mtk_sdw_top_ver { -- MTK_SDW_TOP_VER_0 = 0, -- MTK_SDW_TOP_VER_MAX, --}; -- --/* ---- AFE TOP registers (offsets that DON'T vary stay as #defines) ---- -- */ --#define SDW_TOP_PDIN_CON0(n) ((n) * 4) /* rel. top_pdi */ --#define SDW_TOP_PDI_EN BIT(0) --#define SDW_TOP_PDI_FS GENMASK(5, 1) --#define SDW_TOP_PDI_DOMAIN GENMASK(8, 6) --#define SDW_TOP_PDI_IP_SEL BIT(9) --#define SDW_TOP_PDI_PDM2PCM BIT(10) --#define SDW_TOP_PDI_CLOCK BIT(11) --#define SDW_TOP_PDI_HD_SEL BIT(12) --#define SDW_TOP_PDI_PDM_MODE BIT(13) --#define SDW_TOP_PDI_PDM_ONE_WIRE BIT(14) --#define SDW_TOP_PDI_DMIC_1XEN BIT(16) --#define SDW_TOP_PDI_BRA_MODE BIT(17) --#define SDW_TOP_PDI_BRA_EOP BIT(18) --#define SDW_TOP_PDI_BRA_SLAVE BIT(19) --#define SDW_TOP_PDI_SLAVE_MODE GENMASK(21, 20) --#define SDW_TOP_PDI_GROUP_SYNC_ON BIT(22) --#define SDW_TOP_PDI_GROUP_SYNC GENMASK(26, 23) -- --#define SDW_TOP_CON0 0x0000 /* rel. top_con */ --#define SDW_TOP_CON0_GSYNC_DIR_CTRL BIT(7) -- --#define SDW_TOP_CON1 0x0004 -- --#define TOP_GROUP_SYNC_TX_MIN_ID 1 --#define TOP_GROUP_SYNC_TX_MAX_ID 2 --#define TOP_GROUP_SYNC_RX_MIN_ID 1 --#define TOP_GROUP_SYNC_RX_MAX_ID 4 -- --struct mtk_sdw_top_pdi_params { -- u32 group_sync; -- u32 slave_mode; -- u32 bra_slave; -- u32 bra_eop; -- u32 bra_mode; -- u32 dmic_1xen; -- u32 pdm_one_wire; -- u32 pdm_mode; -- u32 hd_sel; -- u32 clock; -- u32 pdm2pcm; -- u32 sdw_ip_sel; -- u32 domain; -- u32 fs; --}; -- --struct mtk_sdw_top_reg { -- u32 tzd_delay_reg; -- u32 tzd_delay_sel; -- u32 tzd_inverse; -- u32 tzd_delay_en; -- u32 phy_delay_reg; -- u32 phy_delay_sel; -- u32 phy_double_delay_sel; --}; -- --struct mtk_sdw_top_cfg { -- const char *name; -- struct mtk_sdw_top_reg reg; -- /* -- * u32 features; -- * can be added for a bitfield if new features are supported -- * in the future. -- * -- */ --}; -- --int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver); --void mtk_sdw_top_init_settings(struct mtk_sdw *mst); --void mtk_sdw_top_configure_delays(struct mtk_sdw *mst); --void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, -- struct mtk_sdw_top_pdi_params *param); --int mtk_sdw_top_group_sync_config_get(struct mtk_sdw *mst, u8 id, u32 *cfg); --int mtk_sdw_top_group_sync_acquire(struct mtk_sdw *mst, bool is_tx); --void mtk_sdw_top_group_sync_release(struct mtk_sdw *mst, u8 id); --int mtk_sdw_top_enable_stream(struct mtk_sdw *mst, int dai_id); --int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id); -- --#endif /* __MTK_SDW_TOP_H */ -diff --git a/drivers/soundwire/mtk-sdw.c b/drivers/soundwire/mtk-sdw.c -deleted file mode 100644 -index 09329088cd..0000000000 ---- a/drivers/soundwire/mtk-sdw.c -+++ /dev/null -@@ -1,982 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * MediaTek SoundWire master driver -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include "mtk-sdw.h" --#include "mtk-sdw-mach.h" --#include "mtk-sdw-top.h" -- --static int mtk_sdw_parse_dp_allocation(struct mtk_sdw *mst, int idx) --{ -- struct mtk_sdw_link *link = &mst->links[idx]; -- struct fwnode_handle *node; -- char key[40]; -- u32 dp[4]; -- int ret; -- -- snprintf(key, sizeof(key), "acpi-scd-%d-subproperties", idx); -- node = device_get_named_child_node(mst->dev, key); -- if (!node) -- return dev_err_probe(mst->dev, -ENODEV, -- "link %d: missing %s node\n", idx, key); -- -- ret = fwnode_property_read_u32_array(node, "acpi-scd-dp-allocation", dp, -- ARRAY_SIZE(dp)); -- fwnode_handle_put(node); -- if (ret) -- return dev_err_probe(mst->dev, ret, -- "link %d: bad acpi-scd-dp-allocation\n", -- idx); -- -- /* -- * { source_base, source_num, sink_base, sink_num }: every DP the -- * firmware hands out indexes dp_pdi_mask[] and names a DP widget, -- * so both ranges must fit in the MTK_SDW_MAX_DP ports of the -- * manager. Check base first so the count test cannot underflow. -- */ -- if (dp[0] > MTK_SDW_MAX_DP || dp[1] > MTK_SDW_MAX_DP - dp[0] || -- dp[2] > MTK_SDW_MAX_DP || dp[3] > MTK_SDW_MAX_DP - dp[2]) -- return dev_err_probe(mst->dev, -EINVAL, -- "link %d: DP allocation src %u+%u sink %u+%u exceeds %u ports\n", -- idx, dp[0], dp[1], dp[2], dp[3], -- MTK_SDW_MAX_DP); -- -- link->src_base = dp[0]; -- link->src_num = dp[1]; -- link->sink_base = dp[2]; -- link->sink_num = dp[3]; -- -- dev_dbg(mst->dev, "link %d DP alloc: src %u..%u, sink %u..%u\n", idx, -- link->src_base, link->src_base + link->src_num - 1, -- link->sink_base, link->sink_base + link->sink_num - 1); -- return 0; --} -- --/* ======================================================================= -- * ASoC DAI layer (ALSA <-> SoundWire stream binding) -- * ======================================================================= -- */ -- --static int mtk_sdw_set_sdw_stream(struct snd_soc_dai *dai, void *stream, -- int direction) --{ -- struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -- -- mst->dais[dai->id].sruntime = stream; -- return 0; --} -- --static void *mtk_sdw_get_sdw_stream(struct snd_soc_dai *dai, int direction) --{ -- struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -- -- return mst->dais[dai->id].sruntime; --} -- --static unsigned int derive_afe_fs_timing(unsigned int rate) --{ -- unsigned int fs = 0; -- -- switch (rate) { -- case RATE_384000: -- fs = MT8901_FS_384K; -- break; -- case RATE_352800: -- fs = MT8901_FS_352D8K; -- break; -- case RATE_192000: -- fs = MT8901_FS_192K; -- break; -- case RATE_176400: -- fs = MT8901_FS_176D4K; -- break; -- case RATE_96000: -- fs = MT8901_FS_96K; -- break; -- case RATE_88200: -- fs = MT8901_FS_88D2K; -- break; -- case RATE_48000: -- fs = MT8901_FS_48K; -- break; -- case RATE_44100: -- fs = MT8901_FS_44D1K; -- break; -- case RATE_32000: -- fs = MT8901_FS_32K; -- break; -- case RATE_24000: -- fs = MT8901_FS_24K; -- break; -- case RATE_22050: -- fs = MT8901_FS_22D05K; -- break; -- case RATE_16000: -- fs = MT8901_FS_16K; -- break; -- case RATE_12000: -- fs = MT8901_FS_12K; -- break; -- case RATE_8000: -- fs = MT8901_FS_8K; -- break; -- default: -- break; -- } -- -- return fs; --} -- --static void mtk_sdw_dai_release_params(struct mtk_sdw *mst, -- struct mtk_sdw_dai *mdai) --{ -- int i; -- -- for (i = 0; i < mdai->pdi_count; i++) -- mtk_sdw_clear_pdi_settings(&mdai->link->core, -- &mdai->pdi_params[i]); -- mdai->pdi_count = 0; -- -- if (mdai->group_sync_id > 0) { -- mtk_sdw_top_group_sync_release(mst, mdai->group_sync_id); -- mdai->group_sync_id = 0; -- } -- mdai->use_group_sync = false; -- -- if (mdai->top_pdi_params) { -- devm_kfree(mst->dev, mdai->top_pdi_params); -- mdai->top_pdi_params = NULL; -- } --} -- --static int mtk_sdw_dai_hw_params(struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params, -- struct snd_soc_dai *dai) --{ -- struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -- struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -- struct sdw_stream_config sconfig = { 0 }; -- struct sdw_port_config pconfig = { 0 }; -- struct mtk_sdw_port_params mtk_port_param = { 0 }; -- struct mtk_sdw_top_pdi_params *top_params; -- int dir, ret, i; -- unsigned long pdis; -- unsigned int pdi; -- unsigned int channels = params_channels(params); -- unsigned int rate = params_rate(params); -- unsigned int pdi_count; -- unsigned int ch_per_pdi = SDW_DEFAULT_CH_PER_PDI; -- unsigned int tmp = 0; -- unsigned int group_sync_config = 0; -- unsigned int pdi_begin; -- unsigned int last_pdi; -- -- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -- dir = SDW_DATA_DIR_RX; -- else -- dir = SDW_DATA_DIR_TX; -- -- /* port_num is inside MTK_SDW_MAX_DP: validated when the DP allocation was parsed */ -- pdis = mst->dp_pdi_mask[mdai->port_num]; -- for_each_set_bit(pdi, &pdis, MTK_SDW_MAX_DP) { -- dev_dbg(dai->dev, "DP%u <- PDI%u\n", mdai->port_num, pdi); -- if (tmp++) { -- if (pdi != last_pdi + 1) { -- dev_dbg(dai->dev, "unexpected last PDI %u, PDI%u\n", -- last_pdi, pdi); -- return -EINVAL; -- } -- } else { -- pdi_begin = pdi; -- } -- last_pdi = pdi; -- } -- -- pdi_count = (channels + ch_per_pdi - 1) / ch_per_pdi; -- if (tmp != pdi_count) { -- dev_err(dai->dev, "DP%u pdi mask 0x%lx doesn't match channel %u\n", -- mdai->port_num, pdis, channels); -- return -EINVAL; -- } -- -- /* -- * ALSA allows HW_PARAMS again from SETUP or PREPARED without an -- * intervening HW_FREE: drop the previous call's group sync -- * reference and PDI state so nothing leaks or is released twice. -- */ -- mtk_sdw_dai_release_params(mst, mdai); -- -- if (pdi_count > 1) { -- mdai->use_group_sync = true; -- -- ret = mtk_sdw_top_group_sync_acquire(mst, -- dir == SDW_DATA_DIR_TX); -- if (ret < 0) -- return ret; -- mdai->group_sync_id = ret; -- -- ret = mtk_sdw_top_group_sync_config_get(mst, -- mdai->group_sync_id, -- &group_sync_config); -- if (ret < 0) { -- mtk_sdw_top_group_sync_release(mst, -- mdai->group_sync_id); -- mdai->group_sync_id = 0; -- return ret; -- } -- } -- -- /* update pdi_params */ -- mdai->top_pdi_params = devm_kcalloc(mst->dev, pdi_count, -- sizeof(*mdai->top_pdi_params), -- GFP_KERNEL); -- if (!mdai->top_pdi_params) { -- ret = -ENOMEM; -- goto err_release; -- } -- mdai->pdi_count = pdi_count; -- mdai->need_enable_delay = TRUE; -- for (i = 0; i < pdi_count; i++) { -- mdai->pdi_params[i].pdi_num = pdi_begin++; -- mdai->pdi_params[i].port_num = mdai->port_num; -- mdai->pdi_params[i].ch_mask = (1 << (i * ch_per_pdi)) | -- (1 << (i * ch_per_pdi + 1)); -- -- top_params = &mdai->top_pdi_params[i]; -- top_params->group_sync = group_sync_config; -- //top_params->slave_mode = 0; -- top_params->bra_slave = 0; //ToDo : BRA -- top_params->bra_mode = 0; //ToDo : BRA -- top_params->bra_eop = (top_params->bra_mode != 0) ? 1 : 0; -- top_params->dmic_1xen = 0; -- top_params->pdm_one_wire = 0; -- top_params->pdm_mode = 0; -- //top_params->hd_sel = 0; -- top_params->clock = IS_48K_RATE_DOMAIN(rate) ? 1 : 0; -- top_params->pdm2pcm = 0; -- top_params->sdw_ip_sel = mdai->link->ip_idx; -- /* ToDo: SpecifyPdiMode for BRA */ -- top_params->domain = MT8901_APLL_CLK_DOMAIN; -- /* ToDo: SpecifyPdiFs for BRA */ -- top_params->fs = derive_afe_fs_timing(rate); -- -- if (top_params->bra_mode != 0 && top_params->bra_slave != 0) -- mdai->need_enable_delay = FALSE; -- } -- -- pconfig.num = mdai->port_num; -- pconfig.ch_mask = GENMASK(channels - 1, 0); -- -- sconfig.frame_rate = rate; -- sconfig.ch_count = channels; -- sconfig.bps = snd_pcm_format_width(params_format(params)); -- sconfig.direction = dir; -- sconfig.type = SDW_STREAM_PCM; -- -- mtk_port_param.port_num = pconfig.num; -- mtk_port_param.bpt_payload_type = 0; -- mtk_port_param.bpt_en = true; -- mtk_sdw_configure_port_params(&mdai->link->core, &mtk_port_param, dir); -- -- for (i = 0; i < mdai->pdi_count; i++) { -- top_params = &mdai->top_pdi_params[i]; -- mtk_sdw_top_configure_pdi(mst, mdai->pdi_params[i].pdi_num, -- top_params); -- mtk_sdw_configure_pdi_params(&mdai->link->core, -- &mdai->pdi_params[i]); -- } -- -- ret = sdw_stream_add_master(&mdai->link->core.bus, &sconfig, &pconfig, -- 1, mdai->sruntime); -- if (ret) -- goto err_release; -- -- return 0; -- --err_release: -- mtk_sdw_dai_release_params(mst, mdai); -- return ret; --} -- --static int mtk_sdw_dai_hw_free(struct snd_pcm_substream *substream, -- struct snd_soc_dai *dai) --{ -- struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -- struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -- int ret; -- -- ret = sdw_stream_remove_master(&mdai->link->core.bus, mdai->sruntime); -- if (ret < 0) -- dev_err(dai->dev, "remove manager from stream %s failed: %d\n", -- mdai->sruntime->name, ret); -- -- mtk_sdw_dai_release_params(mst, mdai); -- return ret; --} -- --/* configure top stream here, it can be called before dai_link ops */ --static int mtk_sdw_dai_trigger(struct snd_pcm_substream *substream, int cmd, -- struct snd_soc_dai *dai) --{ -- struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -- struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -- -- mtk_sdw_core_dump_dpn_regs(&mdai->link->core, mdai->port_num, -- "trigger"); -- -- switch (cmd) { -- case SNDRV_PCM_TRIGGER_START: -- case SNDRV_PCM_TRIGGER_RESUME: -- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -- return mtk_sdw_top_enable_stream(mst, dai->id); -- case SNDRV_PCM_TRIGGER_STOP: -- case SNDRV_PCM_TRIGGER_SUSPEND: -- case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -- return mtk_sdw_top_disable_stream(mst, dai->id); -- default: -- return -EINVAL; -- } --} -- --static const struct snd_soc_dai_ops mtk_sdw_dai_ops = { -- .hw_params = mtk_sdw_dai_hw_params, -- .hw_free = mtk_sdw_dai_hw_free, -- .trigger = mtk_sdw_dai_trigger, -- .set_stream = mtk_sdw_set_sdw_stream, -- .get_stream = mtk_sdw_get_sdw_stream, --}; -- --/* ======================================================================= -- * DAPM: PDI <-> DP routing -- * ======================================================================= -- */ -- --/* Playback DEMUX target DPs (item 0 == "None"). */ --static const char * const mtk_sdw_playback_dp_texts[] = { -- "None", "DP2", "DP3", "DP4", "DP5", "DP6", --}; -- --/* Capture MUX source DPs (item 0 == "None"). */ --static const char * const mtk_sdw_capture_dp_texts[] = { -- "None", "DP7", "DP8", "DP9", "DP10", -- "DP11", "DP12", "DP13", "DP14", "DP15", --}; -- --static int mtk_sdw_pdi_route_put(struct snd_kcontrol *kc, -- struct snd_ctl_elem_value *uc) --{ -- struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_to_dapm(kc); -- struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm); -- struct mtk_sdw *mst = snd_soc_component_get_drvdata(comp); -- struct soc_enum *e = (struct soc_enum *)kc->private_value; -- unsigned int item = uc->value.enumerated.item[0]; -- unsigned int pdi, dp, d; -- -- if (sscanf(kc->id.name, "PDI%u", &pdi) != 1) -- return -EINVAL; -- if (pdi >= BITS_PER_TYPE(mst->dp_pdi_mask[0])) -- return -EINVAL; -- if (item >= e->items) -- return -EINVAL; -- -- for (d = 0; d < MTK_SDW_MAX_DP; d++) -- mst->dp_pdi_mask[d] &= ~BIT(pdi); -- -- if (item && sscanf(e->texts[item], "DP%u", &dp) == 1 && -- dp < MTK_SDW_MAX_DP) -- mst->dp_pdi_mask[dp] |= BIT(pdi); -- -- return snd_soc_dapm_put_enum_double(kc, uc); --} -- --/* Playback: PGA(PDIn) -> DEMUX(PDIn) -> one of DP2..DP6. */ --#define MTK_SDW_PLAYBACK_PDI(pdi) \ --static SOC_ENUM_SINGLE_VIRT_DECL(mtk_sdw_pdi##pdi##_enum, \ -- mtk_sdw_playback_dp_texts); \ --static const struct snd_kcontrol_new mtk_sdw_pdi##pdi##_demux = \ -- SOC_DAPM_ENUM_EXT("PDI" #pdi " Demux Select", \ -- mtk_sdw_pdi##pdi##_enum, \ -- snd_soc_dapm_get_enum_double, \ -- mtk_sdw_pdi_route_put) -- --/* Capture: one of DP7..DP15 -> MUX(PDIn) -> PGA(PDIn). */ --#define MTK_SDW_CAPTURE_PDI(pdi) \ --static SOC_ENUM_SINGLE_VIRT_DECL(mtk_sdw_pdi##pdi##_enum, \ -- mtk_sdw_capture_dp_texts); \ --static const struct snd_kcontrol_new mtk_sdw_pdi##pdi##_mux = \ -- SOC_DAPM_ENUM_EXT("PDI" #pdi " Mux Select", \ -- mtk_sdw_pdi##pdi##_enum, \ -- snd_soc_dapm_get_enum_double, \ -- mtk_sdw_pdi_route_put) -- --MTK_SDW_PLAYBACK_PDI(2); --MTK_SDW_PLAYBACK_PDI(3); --MTK_SDW_PLAYBACK_PDI(4); --MTK_SDW_PLAYBACK_PDI(5); --MTK_SDW_PLAYBACK_PDI(6); -- --MTK_SDW_CAPTURE_PDI(7); --MTK_SDW_CAPTURE_PDI(8); --MTK_SDW_CAPTURE_PDI(9); --MTK_SDW_CAPTURE_PDI(10); --MTK_SDW_CAPTURE_PDI(11); --MTK_SDW_CAPTURE_PDI(12); --MTK_SDW_CAPTURE_PDI(13); --MTK_SDW_CAPTURE_PDI(14); --MTK_SDW_CAPTURE_PDI(15); -- --/* PDI node + its selector. */ --#define MTK_SDW_PDI_PGA(pdi) \ -- SND_SOC_DAPM_PGA("PDI" #pdi, SND_SOC_NOPM, 0, 0, NULL, 0) --#define MTK_SDW_PLAYBACK_PDI_DEMUX(pdi) \ -- SND_SOC_DAPM_DEMUX("PDI" #pdi " Demux", SND_SOC_NOPM, 0, 0, \ -- &mtk_sdw_pdi##pdi##_demux) --#define MTK_SDW_CAPTURE_PDI_MUX(pdi) \ -- SND_SOC_DAPM_MUX("PDI" #pdi " Mux", SND_SOC_NOPM, 0, 0, \ -- &mtk_sdw_pdi##pdi##_mux) -- --/* DP node. */ --#define MTK_SDW_DP_WIDGET(dp) \ -- SND_SOC_DAPM_PGA("DP" #dp, SND_SOC_NOPM, 0, 0, NULL, 0) -- --static const struct snd_soc_dapm_widget mtk_sdw_dapm_widgets[] = { -- /* BRA PDIs, no DP connection */ -- SND_SOC_DAPM_PGA("PDI0", SND_SOC_NOPM, 0, 0, NULL, 0), -- SND_SOC_DAPM_PGA("PDI1", SND_SOC_NOPM, 0, 0, NULL, 0), -- SND_SOC_DAPM_PGA("PDI16", SND_SOC_NOPM, 0, 0, NULL, 0), -- SND_SOC_DAPM_PGA("PDI17", SND_SOC_NOPM, 0, 0, NULL, 0), -- -- /* Playback PDIs + demuxes */ -- MTK_SDW_PDI_PGA(2), MTK_SDW_PLAYBACK_PDI_DEMUX(2), -- MTK_SDW_PDI_PGA(3), MTK_SDW_PLAYBACK_PDI_DEMUX(3), -- MTK_SDW_PDI_PGA(4), MTK_SDW_PLAYBACK_PDI_DEMUX(4), -- MTK_SDW_PDI_PGA(5), MTK_SDW_PLAYBACK_PDI_DEMUX(5), -- MTK_SDW_PDI_PGA(6), MTK_SDW_PLAYBACK_PDI_DEMUX(6), -- /* Capture PDIs + muxes */ -- MTK_SDW_PDI_PGA(7), MTK_SDW_CAPTURE_PDI_MUX(7), -- MTK_SDW_PDI_PGA(8), MTK_SDW_CAPTURE_PDI_MUX(8), -- MTK_SDW_PDI_PGA(9), MTK_SDW_CAPTURE_PDI_MUX(9), -- MTK_SDW_PDI_PGA(10), MTK_SDW_CAPTURE_PDI_MUX(10), -- MTK_SDW_PDI_PGA(11), MTK_SDW_CAPTURE_PDI_MUX(11), -- MTK_SDW_PDI_PGA(12), MTK_SDW_CAPTURE_PDI_MUX(12), -- MTK_SDW_PDI_PGA(13), MTK_SDW_CAPTURE_PDI_MUX(13), -- MTK_SDW_PDI_PGA(14), MTK_SDW_CAPTURE_PDI_MUX(14), -- MTK_SDW_PDI_PGA(15), MTK_SDW_CAPTURE_PDI_MUX(15), -- /* DP nodes */ -- MTK_SDW_DP_WIDGET(2), MTK_SDW_DP_WIDGET(3), MTK_SDW_DP_WIDGET(4), -- MTK_SDW_DP_WIDGET(5), MTK_SDW_DP_WIDGET(6), MTK_SDW_DP_WIDGET(7), -- MTK_SDW_DP_WIDGET(8), MTK_SDW_DP_WIDGET(9), MTK_SDW_DP_WIDGET(10), -- MTK_SDW_DP_WIDGET(11), MTK_SDW_DP_WIDGET(12), MTK_SDW_DP_WIDGET(13), -- MTK_SDW_DP_WIDGET(14), MTK_SDW_DP_WIDGET(15), --}; -- --/* -- * Playback edge: PDIn -> PDIn Demux -> DPx (active when demux selects "DPx"). -- */ --#define MTK_SDW_PLAYBACK_DEMUX_OUT(pdi, dp) \ -- { "DP" #dp, "DP" #dp, "PDI" #pdi " Demux" } --#define MTK_SDW_PLAYBACK_PDI_LINK(pdi) \ -- { "PDI" #pdi " Demux", NULL, "PDI" #pdi } -- --/* Capture edge: DPx -> PDIn Mux -> PDIn (active when mux selects "DPx"). */ --#define MTK_SDW_CAPTURE_MUX_IN(pdi, dp) \ -- { "PDI" #pdi " Mux", "DP" #dp, "DP" #dp } --#define MTK_SDW_CAPTURE_PDI_LINK(pdi) \ -- { "PDI" #pdi, NULL, "PDI" #pdi " Mux" } -- --static const struct snd_soc_dapm_route mtk_sdw_dapm_routes[] = { -- /* Playback: PDI2..PDI6 -> DP2..DP6 */ -- MTK_SDW_PLAYBACK_PDI_LINK(2), -- MTK_SDW_PLAYBACK_DEMUX_OUT(2, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(2, 3), -- MTK_SDW_PLAYBACK_DEMUX_OUT(2, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(2, 5), -- MTK_SDW_PLAYBACK_DEMUX_OUT(2, 6), -- MTK_SDW_PLAYBACK_PDI_LINK(3), -- MTK_SDW_PLAYBACK_DEMUX_OUT(3, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(3, 3), -- MTK_SDW_PLAYBACK_DEMUX_OUT(3, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(3, 5), -- MTK_SDW_PLAYBACK_DEMUX_OUT(3, 6), -- MTK_SDW_PLAYBACK_PDI_LINK(4), -- MTK_SDW_PLAYBACK_DEMUX_OUT(4, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(4, 3), -- MTK_SDW_PLAYBACK_DEMUX_OUT(4, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(4, 5), -- MTK_SDW_PLAYBACK_DEMUX_OUT(4, 6), -- MTK_SDW_PLAYBACK_PDI_LINK(5), -- MTK_SDW_PLAYBACK_DEMUX_OUT(5, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(5, 3), -- MTK_SDW_PLAYBACK_DEMUX_OUT(5, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(5, 5), -- MTK_SDW_PLAYBACK_DEMUX_OUT(5, 6), -- MTK_SDW_PLAYBACK_PDI_LINK(6), -- MTK_SDW_PLAYBACK_DEMUX_OUT(6, 2), MTK_SDW_PLAYBACK_DEMUX_OUT(6, 3), -- MTK_SDW_PLAYBACK_DEMUX_OUT(6, 4), MTK_SDW_PLAYBACK_DEMUX_OUT(6, 5), -- MTK_SDW_PLAYBACK_DEMUX_OUT(6, 6), -- /* Capture: DP7..DP15 -> PDI7..PDI15 */ -- MTK_SDW_CAPTURE_MUX_IN(7, 7), MTK_SDW_CAPTURE_MUX_IN(7, 8), -- MTK_SDW_CAPTURE_MUX_IN(7, 9), MTK_SDW_CAPTURE_MUX_IN(7, 10), -- MTK_SDW_CAPTURE_MUX_IN(7, 11), MTK_SDW_CAPTURE_MUX_IN(7, 12), -- MTK_SDW_CAPTURE_MUX_IN(7, 13), MTK_SDW_CAPTURE_MUX_IN(7, 14), -- MTK_SDW_CAPTURE_MUX_IN(7, 15), -- MTK_SDW_CAPTURE_PDI_LINK(7), -- MTK_SDW_CAPTURE_MUX_IN(8, 7), MTK_SDW_CAPTURE_MUX_IN(8, 8), -- MTK_SDW_CAPTURE_MUX_IN(8, 9), MTK_SDW_CAPTURE_MUX_IN(8, 10), -- MTK_SDW_CAPTURE_MUX_IN(8, 11), MTK_SDW_CAPTURE_MUX_IN(8, 12), -- MTK_SDW_CAPTURE_MUX_IN(8, 13), MTK_SDW_CAPTURE_MUX_IN(8, 14), -- MTK_SDW_CAPTURE_MUX_IN(8, 15), -- MTK_SDW_CAPTURE_PDI_LINK(8), -- MTK_SDW_CAPTURE_MUX_IN(9, 7), MTK_SDW_CAPTURE_MUX_IN(9, 8), -- MTK_SDW_CAPTURE_MUX_IN(9, 9), MTK_SDW_CAPTURE_MUX_IN(9, 10), -- MTK_SDW_CAPTURE_MUX_IN(9, 11), MTK_SDW_CAPTURE_MUX_IN(9, 12), -- MTK_SDW_CAPTURE_MUX_IN(9, 13), MTK_SDW_CAPTURE_MUX_IN(9, 14), -- MTK_SDW_CAPTURE_MUX_IN(9, 15), -- MTK_SDW_CAPTURE_PDI_LINK(9), -- MTK_SDW_CAPTURE_MUX_IN(10, 7), MTK_SDW_CAPTURE_MUX_IN(10, 8), -- MTK_SDW_CAPTURE_MUX_IN(10, 9), MTK_SDW_CAPTURE_MUX_IN(10, 10), -- MTK_SDW_CAPTURE_MUX_IN(10, 11), MTK_SDW_CAPTURE_MUX_IN(10, 12), -- MTK_SDW_CAPTURE_MUX_IN(10, 13), MTK_SDW_CAPTURE_MUX_IN(10, 14), -- MTK_SDW_CAPTURE_MUX_IN(10, 15), -- MTK_SDW_CAPTURE_PDI_LINK(10), -- MTK_SDW_CAPTURE_MUX_IN(11, 7), MTK_SDW_CAPTURE_MUX_IN(11, 8), -- MTK_SDW_CAPTURE_MUX_IN(11, 9), MTK_SDW_CAPTURE_MUX_IN(11, 10), -- MTK_SDW_CAPTURE_MUX_IN(11, 11), MTK_SDW_CAPTURE_MUX_IN(11, 12), -- MTK_SDW_CAPTURE_MUX_IN(11, 13), MTK_SDW_CAPTURE_MUX_IN(11, 14), -- MTK_SDW_CAPTURE_MUX_IN(11, 15), -- MTK_SDW_CAPTURE_PDI_LINK(11), -- MTK_SDW_CAPTURE_MUX_IN(12, 7), MTK_SDW_CAPTURE_MUX_IN(12, 8), -- MTK_SDW_CAPTURE_MUX_IN(12, 9), MTK_SDW_CAPTURE_MUX_IN(12, 10), -- MTK_SDW_CAPTURE_MUX_IN(12, 11), MTK_SDW_CAPTURE_MUX_IN(12, 12), -- MTK_SDW_CAPTURE_MUX_IN(12, 13), MTK_SDW_CAPTURE_MUX_IN(12, 14), -- MTK_SDW_CAPTURE_MUX_IN(12, 15), -- MTK_SDW_CAPTURE_PDI_LINK(12), -- MTK_SDW_CAPTURE_MUX_IN(13, 7), MTK_SDW_CAPTURE_MUX_IN(13, 8), -- MTK_SDW_CAPTURE_MUX_IN(13, 9), MTK_SDW_CAPTURE_MUX_IN(13, 10), -- MTK_SDW_CAPTURE_MUX_IN(13, 11), MTK_SDW_CAPTURE_MUX_IN(13, 12), -- MTK_SDW_CAPTURE_MUX_IN(13, 13), MTK_SDW_CAPTURE_MUX_IN(13, 14), -- MTK_SDW_CAPTURE_MUX_IN(13, 15), -- MTK_SDW_CAPTURE_PDI_LINK(13), -- MTK_SDW_CAPTURE_MUX_IN(14, 7), MTK_SDW_CAPTURE_MUX_IN(14, 8), -- MTK_SDW_CAPTURE_MUX_IN(14, 9), MTK_SDW_CAPTURE_MUX_IN(14, 10), -- MTK_SDW_CAPTURE_MUX_IN(14, 11), MTK_SDW_CAPTURE_MUX_IN(14, 12), -- MTK_SDW_CAPTURE_MUX_IN(14, 13), MTK_SDW_CAPTURE_MUX_IN(14, 14), -- MTK_SDW_CAPTURE_MUX_IN(14, 15), -- MTK_SDW_CAPTURE_PDI_LINK(14), -- MTK_SDW_CAPTURE_MUX_IN(15, 7), MTK_SDW_CAPTURE_MUX_IN(15, 8), -- MTK_SDW_CAPTURE_MUX_IN(15, 9), MTK_SDW_CAPTURE_MUX_IN(15, 10), -- MTK_SDW_CAPTURE_MUX_IN(15, 11), MTK_SDW_CAPTURE_MUX_IN(15, 12), -- MTK_SDW_CAPTURE_MUX_IN(15, 13), MTK_SDW_CAPTURE_MUX_IN(15, 14), -- MTK_SDW_CAPTURE_MUX_IN(15, 15), -- MTK_SDW_CAPTURE_PDI_LINK(15), --}; -- --static int mtk_sdw_add_dai_routes(struct snd_soc_component *comp) --{ -- struct mtk_sdw *mst = snd_soc_component_get_drvdata(comp); -- struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp); -- int i, p, ret; -- -- for (i = 0; i < mst->num_links; i++) { -- struct mtk_sdw_link *link = &mst->links[i]; -- int offset; -- -- offset = 0; -- for (p = 0; p < link->src_num; p++, offset++) { -- char dai[32], dp[8]; -- struct snd_soc_dapm_route r = { dai, NULL, dp }; -- -- snprintf(dai, sizeof(dai), "SDW%d_Playback%u", -- link->ip_idx, offset); -- snprintf(dp, sizeof(dp), "DP%u", link->src_base + p); -- ret = snd_soc_dapm_add_routes(dapm, &r, 1); -- if (ret) -- return ret; -- } -- -- offset = 0; -- for (p = 0; p < link->sink_num; p++, offset++) { -- char dai[32], dp[8]; -- struct snd_soc_dapm_route r = { dp, NULL, dai }; -- -- snprintf(dai, sizeof(dai), "SDW%d_Capture%u", -- link->ip_idx, offset); -- snprintf(dp, sizeof(dp), "DP%u", link->sink_base + p); -- ret = snd_soc_dapm_add_routes(dapm, &r, 1); -- if (ret) -- return ret; -- } -- } -- -- return 0; --} -- --static int mtk_sdw_component_probe(struct snd_soc_component *comp) --{ -- return mtk_sdw_add_dai_routes(comp); --} -- --static const struct snd_soc_component_driver mtk_sdw_component = { -- .name = "mtk-soundwire", -- .probe = mtk_sdw_component_probe, -- .dapm_widgets = mtk_sdw_dapm_widgets, -- .num_dapm_widgets = ARRAY_SIZE(mtk_sdw_dapm_widgets), -- .dapm_routes = mtk_sdw_dapm_routes, -- .num_dapm_routes = ARRAY_SIZE(mtk_sdw_dapm_routes), --}; -- --static int mtk_sdw_init_dai(struct mtk_sdw *mst, struct snd_soc_dai_driver *drv, -- int idx, struct mtk_sdw_link *link, -- unsigned int port, int offset, bool playback) --{ -- struct snd_soc_pcm_stream *stream; -- -- drv->id = idx; -- drv->ops = &mtk_sdw_dai_ops; -- -- if (playback) { -- drv->name = devm_kasprintf(mst->dev, GFP_KERNEL, -- "SDW%d_Playback%u", -- link->ip_idx, offset); -- if (!drv->name) -- return -ENOMEM; -- -- stream = &drv->playback; -- } else { -- drv->name = devm_kasprintf(mst->dev, GFP_KERNEL, -- "SDW%d_Capture%u", -- link->ip_idx, offset); -- if (!drv->name) -- return -ENOMEM; -- -- stream = &drv->capture; -- } -- -- stream->channels_min = 2; -- stream->channels_max = 8; -- stream->rates = SNDRV_PCM_RATE_48000; -- stream->rates = SNDRV_PCM_RATE_8000_384000; -- stream->formats = SNDRV_PCM_FMTBIT_S16_LE | -- SNDRV_PCM_FMTBIT_S24_LE | -- SNDRV_PCM_FMTBIT_S32_LE; -- -- stream->stream_name = drv->name; -- -- mst->dais[idx].link = link; -- mst->dais[idx].port_num = port; -- -- return 0; --} -- --static int mtk_sdw_register_dais(struct mtk_sdw *mst) --{ -- struct snd_soc_dai_driver *drvs; -- struct device *dev = mst->dev; -- int i, p, idx = 0, num = 0, ret; -- -- for (i = 0; i < mst->num_links; i++) -- num += mst->links[i].src_num + mst->links[i].sink_num; -- if (!num) -- return dev_err_probe(dev, -EINVAL, "no data ports allocated\n"); -- -- mst->dais = devm_kcalloc(dev, num, sizeof(*mst->dais), GFP_KERNEL); -- if (!mst->dais) -- return -ENOMEM; -- -- drvs = devm_kcalloc(dev, num, sizeof(*drvs), GFP_KERNEL); -- if (!drvs) -- return -ENOMEM; -- -- for (i = 0; i < mst->num_links; i++) { -- struct mtk_sdw_link *link = &mst->links[i]; -- int offset; -- -- offset = 0; -- /* Source ports -> playback DAIs */ -- for (p = 0; p < link->src_num; p++, idx++, offset++) { -- ret = mtk_sdw_init_dai(mst, &drvs[idx], idx, link, -- link->src_base + p, offset, -- true); -- if (ret) -- return ret; -- } -- -- offset = 0; -- /* Sink ports -> capture DAIs */ -- for (p = 0; p < link->sink_num; p++, idx++, offset++) { -- ret = mtk_sdw_init_dai(mst, &drvs[idx], idx, link, -- link->sink_base + p, offset, -- false); -- if (ret) -- return ret; -- } -- } -- mst->num_dais = num; -- -- return devm_snd_soc_register_component(dev, &mtk_sdw_component, drvs, -- num); --} -- --/* ======================================================================= -- * Per-IP bring-up -- * ======================================================================= -- */ -- --static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) --{ -- struct mtk_sdw_link *link = &mst->links[idx]; -- struct mtk_sdw_core *core = &link->core; -- int ret; -- -- link->master = mst; -- link->ip_idx = idx; -- -- core->dev = mst->dev; -- core->priv = link; -- -- core->bus.link_id = idx; -- core->bus.prop.mclk_freq = SDW_DEFAULT_MCLK_CLK_FREQ; -- -- core->bus.dev = mst->dev; -- ret = sdw_bus_master_add(&core->bus, mst->dev, mst->dev->fwnode); -- if (ret) { -- dev_err(mst->dev, "IP%d: bus_master_add failed: %d\n", -- idx, ret); -- return ret; -- } -- -- ret = mtk_sdw_core_hw_init(core); -- if (ret) { -- sdw_bus_master_delete(&core->bus); -- return ret; -- } -- -- mtk_sdw_enable_irq(core, true); -- dev_info(mst->dev, "IP%d: SoundWire bus ready\n", idx); -- return 0; --} -- --static void mtk_sdw_link_deinit(struct mtk_sdw *mst, int idx) --{ -- struct mtk_sdw_core *core = &mst->links[idx].core; -- -- mtk_sdw_enable_irq(core, false); -- sdw_bus_master_delete(&core->bus); --} -- --static void mtk_init_sdw_master(struct mtk_sdw *mst) --{ -- int i; -- -- mst->tzd_delay = 3; -- mst->tzd_inverse = 0; -- mst->phy_delay = 2; -- mst->phy_double_delay = 0; -- mst->num_links = SDW_MAX_HWIP_NUM; -- -- for (i = 0; i < SDW_MAX_HWIP_NUM; i++) -- mst->controller_en_list |= (1UL << i); --} -- --static int mtk_sdw_register_machine(struct mtk_sdw *mst) --{ -- struct snd_soc_acpi_mach *mach; -- -- mach = mtk_sdw_machine_select(mst); -- if (!mach) { -- dev_info(mst->dev, "no card from this controller\n"); -- return 0; /* no card from this controller; not an error */ -- } -- -- mst->mach_dev = platform_device_register_data(mst->dev, mach->drv_name, -- PLATFORM_DEVID_NONE, -- mach, sizeof(*mach)); -- if (IS_ERR(mst->mach_dev)) { -- dev_err(mst->dev, "failed to register machine %s\n", -- mach->drv_name); -- return PTR_ERR(mst->mach_dev); -- } -- -- dev_info(mst->dev, "registered SoundWire machine %s\n", mach->drv_name); -- return 0; --} -- --static int mtk_sdw_probe_controller(struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- struct mtk_sdw *mst; -- u32 hw_ver = MTK_SDW_HW_VER_MT8901; -- u32 mmio[2]; -- int i, ret; -- -- mst = devm_kzalloc(dev, sizeof(*mst), GFP_KERNEL); -- if (!mst) -- return -ENOMEM; -- -- mtk_init_sdw_master(mst); -- -- mst->dev = dev; -- mutex_init(&mst->group_lock); -- platform_set_drvdata(pdev, mst); -- -- ret = device_property_read_u32_array(dev, "afe-base", mmio, 2); -- if (ret) -- return dev_err_probe(dev, ret, -- "missing/invalid afe-base property\n"); -- dev_info(dev, "address %x, size %d\n", mmio[0], mmio[1]); -- -- mst->base = devm_ioremap(dev, mmio[0], mmio[1]); -- if (!mst->base) -- return -ENOMEM; -- mst->top_pdi = mst->base + AFE_SDW_TOP_PDI_REG_BASE; -- mst->top_con = mst->base + AFE_SDW_TOP_CON_REG_BASE; -- -- device_property_read_u32(dev, "acpi-scd-hw-ver", &hw_ver); -- if (hw_ver >= MTK_SDW_HW_VER_MAX) -- return dev_err_probe(dev, -EINVAL, -- "unknown acpi-scd-hw-ver %u\n", hw_ver); -- -- mst->hw_ver = hw_ver; -- -- ret = mtk_sdw_top_config_select(mst, mst->hw_ver); -- if (ret) -- return ret; -- -- /* Timing delays from ACPI _DSD. */ -- device_property_read_u32(dev, "acpi-scd-tzd-delay", &mst->tzd_delay); -- device_property_read_u32(dev, "acpi-scd-phy-delay", &mst->phy_delay); -- device_property_read_u32(dev, "acpi-scd-phy-double-delay", -- &mst->phy_double_delay); -- -- if (mst->tzd_delay <= mst->phy_delay) { -- dev_err(dev, "invalid delay, tzd %u - phy %u", mst->tzd_delay, -- mst->phy_delay); -- return -EINVAL; -- } -- -- mtk_sdw_top_init_settings(mst); -- mtk_sdw_top_configure_delays(mst); -- -- for (i = 0; i < mst->num_links; i++) { -- int irq = platform_get_irq(pdev, i); -- struct mtk_sdw_core *core = &mst->links[i].core; -- -- if (irq < 0) { -- ret = irq; -- goto err; -- } -- mst->links[i].irq = irq; -- mst->links[i].ip_idx = i; -- -- ret = mtk_sdw_parse_dp_allocation(mst, i); -- if (ret) -- goto err; -- -- core->regs = devm_platform_ioremap_resource(pdev, i); -- if (IS_ERR(core->regs)) { -- ret = PTR_ERR(core->regs); -- goto err; -- } -- -- /* -- * The line is shared and MCP_INTMASK holds whatever POST left, -- * so the handler can run as soon as it is registered: the lock -- * and work items it uses must exist first. -- */ -- ret = mtk_sdw_core_init(core); -- if (ret) -- goto err; -- -- ret = devm_request_irq(dev, irq, mtk_sdw_core_irq, IRQF_SHARED, -- dev_name(dev), core); -- if (ret) { -- dev_err(dev, "IP%d: request_irq failed: %d\n", i, ret); -- goto err; -- } -- -- ret = mtk_sdw_link_init(mst, i); -- if (ret) -- goto err; -- } -- -- ret = mtk_sdw_register_dais(mst); -- if (ret) { -- dev_err(dev, "failed to register DAIs: %d\n", ret); -- goto err; -- } -- -- dev_info(dev, "MediaTek SoundWire ready, %d link(s), %d DAI(s)\n", -- mst->num_links, mst->num_dais); -- -- return 0; -- --err: -- while (--i >= 0) -- mtk_sdw_link_deinit(mst, i); -- -- return ret; --} -- --static int mtk_sdw_probe(struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- struct mtk_sdw *mst; -- int i, ret; -- -- ret = mtk_sdw_probe_controller(pdev); -- if (ret) { -- dev_err(dev, "failed to probe_controller %d\n", ret); -- return ret; -- } -- -- mst = platform_get_drvdata(pdev); -- -- ret = mtk_sdw_register_machine(mst); -- if (ret) { -- for (i = mst->num_links - 1; i >= 0; i--) -- mtk_sdw_link_deinit(mst, i); -- -- return ret; -- } -- -- return 0; --} -- --static void mtk_sdw_remove(struct platform_device *pdev) --{ -- struct mtk_sdw *mst = platform_get_drvdata(pdev); -- int i; -- -- if (mst->mach_dev) -- platform_device_unregister(mst->mach_dev); -- for (i = mst->num_links - 1; i >= 0; i--) -- mtk_sdw_link_deinit(mst, i); --} -- --static const struct acpi_device_id mtk_sdw_acpi_match[] = { -- { "NVDA9100", 0 }, -- { } --}; --MODULE_DEVICE_TABLE(acpi, mtk_sdw_acpi_match); -- --static struct platform_driver mtk_sdw_driver = { -- .probe = mtk_sdw_probe, -- .remove = mtk_sdw_remove, -- .driver = { -- .name = "mtk-soundwire", -- .acpi_match_table = mtk_sdw_acpi_match, -- }, --}; --module_platform_driver(mtk_sdw_driver); -- --MODULE_DESCRIPTION("MediaTek SoundWire master"); --MODULE_AUTHOR("Trevor Wu "); --MODULE_LICENSE("GPL"); -diff --git a/drivers/soundwire/mtk-sdw.h b/drivers/soundwire/mtk-sdw.h -deleted file mode 100644 -index 2c91eb609b..0000000000 ---- a/drivers/soundwire/mtk-sdw.h -+++ /dev/null -@@ -1,85 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * MediaTek SoundWire master driver header. -- * -- * Copyright (c) 2026 MediaTek Inc. -- * Author: Trevor Wu -- */ --#ifndef __MTK_SDW_H --#define __MTK_SDW_H -- --#include "mtk-sdw-common.h" -- --enum mt8901_afe_clk_domain { -- MT8901_HOPPING_CLK_DOMAIN = 0, -- MT8901_APLL_CLK_DOMAIN = 1, --}; -- --enum mtk_sdw_sample_rate { -- RATE_384000 = 384000, -- RATE_352800 = 352800, -- RATE_192000 = 192000, -- RATE_176400 = 176400, -- RATE_96000 = 96000, -- RATE_88200 = 88200, -- RATE_48000 = 48000, -- RATE_44100 = 44100, -- RATE_32000 = 32000, -- RATE_29400 = 29400, -- RATE_24000 = 24000, -- RATE_22050 = 22050, -- RATE_16000 = 16000, -- RATE_14700 = 14700, -- RATE_12000 = 12000, -- RATE_11025 = 11025, -- RATE_8000 = 8000, -- RATE_7350 = 7350, --}; -- --enum mt8901_afe_fs_mode { -- MT8901_FS_8K = 0, -- MT8901_FS_11D025K = 1, -- MT8901_FS_12K = 2, -- MT8901_FS_16K = 4, -- MT8901_FS_22D05K = 5, -- MT8901_FS_24K = 6, -- MT8901_FS_32K = 8, -- MT8901_FS_44D1K = 9, -- MT8901_FS_48K = 10, -- MT8901_FS_88D2K = 13, -- MT8901_FS_96K = 14, -- MT8901_FS_176D4K = 17, -- MT8901_FS_192K = 18, -- MT8901_FS_352D8K = 21, -- MT8901_FS_384K = 22, -- MT8901_ETDM_OUT0_HOPPING_DOMAIN = 4, -- MT8901_ETDM_OUT5_HOPPING_DOMAIN = 9, -- MT8901_ETDM_IN0_HOPPING_DOMAIN = 12, -- MT8901_ETDM_IN5_HOPPING_DOMAIN = 17, -- MT8901_FS_TOP_PDI_IP0_PDI0 = 24, -- MT8901_FS_TOP_PDI_IP1_PDI0 = 25, -- MT8901_FS_TOP_PDI_IP0_PDI1 = 26, -- MT8901_FS_TOP_PDI_IP1_PDI1 = 27, --}; -- --#define IS_48K_RATE_DOMAIN(x) (((x) % 8000) == 0) -- --#define SDW_DEFAULT_CH_PER_PDI 2 -- --#define AFE_SDW_TOP_PDI_REG_BASE (0x9000) --#define AFE_SDW_TOP_CON_REG_BASE (0x9048) -- --#define SDW_DEFAULT_MAX_BUS_CLK_FREQ (6144000) --#define SDW_DEFAULT_MCLK_CLK_FREQ (24576000) --#define SDW_DEFAULT_FRAME_RATE (24000) --#define SDW_DEFAULT_FRAME_SHAPE_ROW (64) --#define SDW_DEFAULT_FRAME_SHAPE_COL (8) -- --#define MTK_SDW_DP_SOURCE_BASE 2 /* DP2.. (master source / playback) */ --#define MTK_SDW_DP_SOURCE_NUM 5 --#define MTK_SDW_DP_SINK_BASE 7 /* DP7.. (master sink / capture) */ --#define MTK_SDW_DP_SINK_NUM 9 --#define MTK_SDW_MAX_DAIS \ -- ((MTK_SDW_DP_SOURCE_NUM) + (MTK_SDW_DP_SINK_NUM)) /* BRA not included */ -- --#endif /* __MTK_SDW_H */ -From ace64f72d155b720e94e31ac7142920b54d0daac Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:08 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add mt8901 clock control - support - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Integrate clock management into the mt8901 SoundWire manager: bring -the functional clock tree up during link initialization and release it -symmetrically on teardown, using the shared mt8901 AFE clock helpers. - -Folded review fixes: release the link top clock when link init fails -partway, and keep the register clock bookkeeping accurate in the probe -unwind path so a failed probe does not leave gates held. - -Depends on the MediaTek power_wrap driver (submitted separately). - -Signed-off-by: Trevor Wu -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/Kconfig | 12 + - drivers/soundwire/mediatek/Makefile | 3 +- - drivers/soundwire/mediatek/mt8901-afe-clk.c | 951 ++++++++++++++++++ - drivers/soundwire/mediatek/mt8901-afe-clk.h | 162 +++ - drivers/soundwire/mediatek/mtk-sdw-chipglue.c | 34 + - drivers/soundwire/mediatek/mtk-sdw-common.h | 29 +- - drivers/soundwire/mediatek/mtk-sdw.c | 98 +- - 7 files changed, 1282 insertions(+), 7 deletions(-) - create mode 100644 drivers/soundwire/mediatek/mt8901-afe-clk.c - create mode 100644 drivers/soundwire/mediatek/mt8901-afe-clk.h - create mode 100644 drivers/soundwire/mediatek/mtk-sdw-chipglue.c - -diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig -index 9e96cf1bca..38b8835b3c 100644 ---- a/drivers/soundwire/Kconfig -+++ b/drivers/soundwire/Kconfig -@@ -61,13 +61,25 @@ config SOUNDWIRE_MTK - tristate "MediaTek SoundWire Master driver" - select SOUNDWIRE_GENERIC_ALLOCATION - depends on SND_SOC && ACPI -+ depends on MTK_POWER_WRAP - select SND_SOC_ACPI -+ select SOUNDWIRE_MTK_MT8901_CLK - help - SoundWire MediaTek Master driver. - If you have an MediaTek platform which has a SoundWire Master then - enable this config option to get the SoundWire support for that - device. - -+config SOUNDWIRE_MTK_MT8901_CLK -+ bool -+ depends on SOUNDWIRE_MTK -+ depends on MTK_POWER_WRAP -+ help -+ MT8901 clock and power control backend for the MediaTek SoundWire -+ Master driver. Every hardware version the driver supports needs it, -+ so SOUNDWIRE_MTK selects it; there is no configuration in which the -+ manager probes without it. -+ - config SOUNDWIRE_GENERIC_ALLOCATION - tristate - -diff --git a/drivers/soundwire/mediatek/Makefile b/drivers/soundwire/mediatek/Makefile -index 9e0ad24ce8..39c451ab1c 100644 ---- a/drivers/soundwire/mediatek/Makefile -+++ b/drivers/soundwire/mediatek/Makefile -@@ -3,5 +3,6 @@ - # Makefile for MediaTek SoundWire driver - # - --soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o mtk-sdw-mach.o -+soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o mtk-sdw-mach.o mtk-sdw-chipglue.o -+soundwire-mtk-$(CONFIG_SOUNDWIRE_MTK_MT8901_CLK) += mt8901-afe-clk.o - obj-$(CONFIG_SOUNDWIRE_MTK) += soundwire-mtk.o -diff --git a/drivers/soundwire/mediatek/mt8901-afe-clk.c b/drivers/soundwire/mediatek/mt8901-afe-clk.c -new file mode 100644 -index 0000000000..24e3765544 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mt8901-afe-clk.c -@@ -0,0 +1,951 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * mt8901-afe-clk.c -- MediaTek 8901 afe clock ctrl -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#include -+#include -+#include "mtk-sdw-common.h" -+#include "mt8901-afe-clk.h" -+#include -+ -+#define AUDIO_ENGEN_CON0_USER1 (0x0018) -+#define AUDIO_ENGEN_CON0_APLL2_MASK BIT(3) -+#define AUDIO_ENGEN_CON0_APLL1_MASK BIT(2) -+#define AUDIO_ENGEN_CON0_26M_MASK BIT(0) -+ -+static const unsigned int mt8901_sdw_common_clk_muxes[] = { -+ AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+}; -+ -+static const unsigned int mt8901_sdw0_main_clk_muxes[] = { -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_PHY_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+}; -+ -+static const unsigned int mt8901_sdw1_main_clk_muxes[] = { -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_PHY_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+}; -+ -+static const unsigned int mt8901_apll_top_con_cgs[] = { -+ AUD_CG_APLL1_CK, -+ AUD_CG_APLL2_CK, -+ AUD_CG_APLL_TUNER1, -+ AUD_CG_APLL_TUNER2, -+}; -+ -+static const struct { -+ unsigned int mux; -+ const char *parent_name; -+ unsigned int level; -+} mt8901_clk_parent_map[] = { -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_APLL1_D2_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_APLL2_D2_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_APLL1_D8_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_APLL1_D4_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_APLL2_D8_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_APLL2_D4_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_MAINPLL2_D7_D4_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_MAINPLL2_D4_D4_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ CLK_PARENT_APLL1_NAME, 1 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ CLK_PARENT_APLL2_NAME, 1 }, -+}; -+ -+static const struct { -+ unsigned int mux; -+ const char *idle_parent_name; -+ const char *active_parent_name; -+} idle_clk_muxes[] = { -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_APLL2_D2_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_MAINPLL2_D4_D4_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, CLK_PARENT_APLL1_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, CLK_PARENT_APLL2_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_APLL1_D4_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_APLL2_D4_NAME }, -+}; -+ -+struct sdw_clk_parent_info { -+ unsigned int mux; -+ const char *apll_parent_name; -+ const char *lp_parent_name; -+}; -+ -+struct sdw_clk_parent_info sdw0_clk_parent_info[] = { -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_SEL, -+ CLK_PARENT_APLL2_D8_NAME, -+ CLK_PARENT_OSC_D20_NAME}, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_PHY_SEL, -+ CLK_PARENT_APLL2_NAME, -+ CLK_PARENT_OSC_D20_NAME}, -+}; -+ -+struct sdw_clk_parent_info sdw1_clk_parent_info[] = { -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_SEL, -+ CLK_PARENT_APLL2_D8_NAME, -+ CLK_PARENT_OSC_D20_NAME}, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_PHY_SEL, -+ CLK_PARENT_APLL2_NAME, -+ CLK_PARENT_OSC_D20_NAME}, -+}; -+ -+static const char * const mt8901_cg_names[] = { -+ [AUD_CG_HW_GAIN01] = "HW_GAIN01", -+ [AUD_CG_HW_GAIN23] = "HW_GAIN23", -+ [AUD_CG_CM0] = "CM0", -+ [AUD_CG_CM1] = "CM1", -+ [AUD_CG_CM2] = "CM2", -+ [AUD_CG_HW_GAIN_DL0_DL1] = "HW_GAIN_DL0_DL1", -+ [AUD_CG_HW_GAIN_DL2_DL3] = "HW_GAIN_DL2_DL3", -+ [AUD_CG_HW_GAIN_DL4_DL5] = "HW_GAIN_DL4_DL5", -+ [AUD_CG_HW_GAIN_DL24CH] = "HW_GAIN_DL24CH", -+ [AUD_CG_UL0_ADC] = "UL0_ADC", -+ [AUD_CG_UL0_TML] = "UL0_TML", -+ [AUD_CG_UL0_ADC_HIRES] = "UL0_ADC_HIRES", -+ [AUD_CG_UL0_ADC_HIRES_TML] = "UL0_ADC_HIRES_TML", -+ [AUD_CG_UL1_ADC] = "UL1_ADC", -+ [AUD_CG_UL1_TML] = "UL1_TML", -+ [AUD_CG_UL1_ADC_HIRES] = "UL1_ADC_HIRES", -+ [AUD_CG_UL1_ADC_HIRES_TML] = "UL1_ADC_HIRES_TML", -+ [AUD_CG_ETDM_OUT0] = "ETDM_OUT0", -+ [AUD_CG_ETDM_OUT5] = "ETDM_OUT5", -+ [AUD_CG_ETDM_IN0] = "ETDM_IN0", -+ [AUD_CG_ETDM_IN5] = "ETDM_IN5", -+ [AUD_CG_GENERAL0_ASRC] = "GASRC0", -+ [AUD_CG_GENERAL1_ASRC] = "GASRC1", -+ [AUD_CG_GENERAL2_ASRC] = "GASRC2", -+ [AUD_CG_GENERAL3_ASRC] = "GASRC3", -+ [AUD_CG_GENERAL4_ASRC] = "GASRC4", -+ [AUD_CG_GENERAL5_ASRC] = "GASRC5", -+ [AUD_CG_GENERAL6_ASRC] = "GASRC6", -+ [AUD_CG_GENERAL7_ASRC] = "GASRC7", -+ [AUD_CG_APLL_TUNER1] = "APLL_TUNER1", -+ [AUD_CG_APLL_TUNER2] = "APLL_TUNER2", -+ [AUD_CG_H208M_CK] = "H208M", -+ [AUD_CG_APLL2_CK] = "APLL2", -+ [AUD_CG_APLL1_CK] = "APLL1", -+ [AUD_CG_AUDIO_F26M_CK] = "F26M", -+ [AUD_CG_AUDIO_HOPPING_CK] = "HOPPING", -+ [AUD_CG_SOUNDWIRE_DMIC0_ADC] = "SDW_DMIC0_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC0_TML] = "SDW_DMIC0_TML", -+ [AUD_CG_SOUNDWIRE_DMIC1_ADC] = "SDW_DMIC1_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC1_TML] = "SDW_DMIC1_TML", -+ [AUD_CG_SOUNDWIRE_DMIC2_ADC] = "SDW_DMIC2_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC2_TML] = "SDW_DMIC2_TML", -+ [AUD_CG_SOUNDWIRE_DMIC3_ADC] = "SDW_DMIC3_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC3_TML] = "SDW_DMIC3_TML", -+ [AUD_CG_SOUNDWIRE_DMIC4_ADC] = "SDW_DMIC4_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC4_TML] = "SDW_DMIC4_TML", -+ [AUD_CG_SOUNDWIRE_DMIC5_ADC] = "SDW_DMIC5_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC5_TML] = "SDW_DMIC5_TML", -+ [AUD_CG_SOUNDWIRE_DMIC6_ADC] = "SDW_DMIC6_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC6_TML] = "SDW_DMIC6_TML", -+ [AUD_CG_SOUNDWIRE_DMIC7_ADC] = "SDW_DMIC7_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC7_TML] = "SDW_DMIC7_TML", -+ [AUD_CG_SOUNDWIRE1] = "SOUNDWIRE1", -+ [AUD_CG_SOUNDWIRE0] = "SOUNDWIRE0", -+}; -+ -+static int mt8901_afe_send_power_req(struct device *dev, u8 cmd, -+ u32 d0, u32 d1, u32 d2) -+{ -+ struct power_cntl_scmi_data scmidata = { -+ .requestId = cmd, -+ .customdata = { d0, d1, d2 }, -+ }; -+ struct _power_cntrl_request req = { -+ .dev = dev, -+ .InBuffer = &scmidata, -+ .InBufferSize = sizeof(scmidata), -+ }; -+ -+ return mtk_send_power_control_req(&req); -+} -+ -+static int mt8901_afe_pwr_ctrl_scene_req(struct device *dev, unsigned int scene) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_PWR_CTRL_SCENE, -+ scene, 0, 0); -+} -+ -+static int mt8901_afe_clk_cg_deinit_req(struct device *dev) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_CLK_CG_DEINIT, -+ 0, 0, 0); -+} -+ -+static int mt8901_afe_cg_req(struct device *dev, unsigned int cg, bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_CG, cg, enable, 0); -+} -+ -+static int mt8901_afe_mtcmos_req(struct device *dev, unsigned int mtcmos, -+ bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_MTCMOS, mtcmos, -+ enable, 0); -+} -+ -+static int mt8901_afe_afe_spm_ctrl_req(struct device *dev, unsigned int req, -+ bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_AFE_SPM_CTRL, -+ req, enable, 0); -+} -+ -+static int mt8901_afe_clk_mux_req(struct device *dev, unsigned int mux, -+ bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_VLP_SYS_CLK_MUX, -+ mux, enable, 0); -+} -+ -+static int mt8901_afe_clk_set_parent_req(struct device *dev, unsigned int mux, -+ unsigned int parent_level) -+{ -+ return mt8901_afe_send_power_req(dev, -+ SSPM_AUD_CMD_VLP_SYS_CLK_SET_PARENT, -+ mux, parent_level, 0); -+} -+ -+static int mt8901_afe_enable_afe_on(struct mtk_sdw *mst) -+{ -+ void *reg; -+ unsigned int mask; -+ unsigned int val; -+ -+ reg = mst->base + AUDIO_ENGEN_CON0_USER1; -+ mask = AUDIO_ENGEN_CON0_APLL2_MASK | -+ AUDIO_ENGEN_CON0_APLL1_MASK | -+ AUDIO_ENGEN_CON0_26M_MASK; -+ -+ guard(mutex)(&mst->afe_lock); -+ -+ mst->afe_on_refcnt++; -+ if (mst->afe_on_refcnt == 1) { -+ val = readl(reg); -+ val &= ~mask; -+ val |= mask; -+ writel(val, reg); -+ } -+ -+ return 0; -+} -+ -+static int mt8901_afe_disable_afe_on(struct mtk_sdw *mst) -+{ -+ void *reg; -+ unsigned int mask; -+ unsigned int val; -+ -+ reg = mst->base + AUDIO_ENGEN_CON0_USER1; -+ mask = AUDIO_ENGEN_CON0_APLL2_MASK | -+ AUDIO_ENGEN_CON0_APLL1_MASK | -+ AUDIO_ENGEN_CON0_26M_MASK; -+ -+ guard(mutex)(&mst->afe_lock); -+ -+ if (mst->afe_on_refcnt > 0) -+ mst->afe_on_refcnt--; -+ -+ if (mst->afe_on_refcnt == 0) { -+ val = readl(reg); -+ val &= ~mask; -+ writel(val, reg); -+ } -+ -+ return 0; -+} -+ -+static int mt8901_afe_check_sspm_probe(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ ret = mt8901_afe_pwr_ctrl_scene_req(dev, AUDIO_PWR_SCEN_NORMAL); -+ if (ret) { -+ dev_err(dev, "SSPM probe failed: %d\n", ret); -+ return ret; -+ } -+ -+ dev_dbg(dev, "SSPM available\n"); -+ return 0; -+} -+ -+static int mt8901_afe_disable_default_on_clk_and_top_cg(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ ret = mt8901_afe_clk_cg_deinit_req(dev); -+ dev_dbg(dev, "disable_default_on_clk_and_top_cg: %d\n", ret); -+ -+ return ret; -+} -+ -+static int mt8901_sdw_init_clock(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ ret = mt8901_afe_check_sspm_probe(mst); -+ if (ret) -+ return ret; -+ -+ ret = mt8901_afe_disable_default_on_clk_and_top_cg(mst); -+ if (ret) { -+ dev_err(dev, "disable_default_on_clk_and_top_cg failed: %d\n", -+ ret); -+ return ret; -+ } -+ -+ return ret; -+} -+ -+static int mt8901_afe_enable_top_cg(struct mtk_sdw *mst, unsigned int cg) -+{ -+ struct device *dev = mst->dev; -+ const char *name; -+ int ret; -+ -+ if (cg >= AUD_CG_NUMS) -+ return -EINVAL; -+ -+ name = mt8901_cg_names[cg]; -+ -+ ret = mt8901_afe_cg_req(dev, cg, true); -+ -+ dev_dbg(dev, "enable_top_cg %s: %d\n", name, ret); -+ return ret; -+} -+ -+static int mt8901_afe_disable_top_cg(struct mtk_sdw *mst, unsigned int cg) -+{ -+ struct device *dev = mst->dev; -+ const char *name; -+ int ret; -+ -+ if (cg >= AUD_CG_NUMS) -+ return -EINVAL; -+ -+ name = mt8901_cg_names[cg]; -+ -+ ret = mt8901_afe_cg_req(dev, cg, false); -+ -+ dev_dbg(dev, "disable_top_cg %s: %d\n", name, ret); -+ return ret; -+} -+ -+static int mt8901_afe_enable_mtcmos(struct mtk_sdw *mst, unsigned int mtcmos) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ if (mtcmos >= AUDIO_PD_NUM) -+ return -EINVAL; -+ -+ ret = mt8901_afe_mtcmos_req(dev, mtcmos, true); -+ dev_dbg(dev, "enable_mtcmos %u: %d\n", mtcmos, ret); -+ return ret; -+} -+ -+static int mt8901_afe_disable_mtcmos(struct mtk_sdw *mst, unsigned int mtcmos) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ if (mtcmos >= AUDIO_PD_NUM) -+ return -EINVAL; -+ -+ ret = mt8901_afe_mtcmos_req(dev, mtcmos, false); -+ dev_dbg(dev, "disable_mtcmos %u: %d\n", mtcmos, ret); -+ return ret; -+} -+ -+static int mt8901_afe_send_spm_req(struct mtk_sdw *mst, unsigned int req, -+ bool enable) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ if (req >= AFE_SPM_CTRL_REQ_NUMS) -+ return -EINVAL; -+ -+ ret = mt8901_afe_afe_spm_ctrl_req(dev, req, enable); -+ dev_dbg(dev, "send_spm_req %u en=%d: %d\n", req, enable, ret); -+ return ret; -+} -+ -+static int mt8901_afe_enable_main_clk_muxes(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_sdw_common_clk_muxes); i++) { -+ ret = mt8901_afe_clk_mux_req(dev, -+ mt8901_sdw_common_clk_muxes[i], -+ true); -+ dev_dbg(dev, "enable main_clk mux[%d]: %d\n", i, ret); -+ if (ret) -+ goto err_ret; -+ } -+ -+ return 0; -+err_ret: -+ while (i-- > 0) -+ mt8901_afe_clk_mux_req(dev, mt8901_sdw_common_clk_muxes[i], -+ false); -+ -+ return ret; -+} -+ -+static int mt8901_afe_disable_main_clk_muxes(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_sdw_common_clk_muxes); i++) { -+ ret = mt8901_afe_clk_mux_req(dev, -+ mt8901_sdw_common_clk_muxes[i], -+ false); -+ dev_dbg(dev, "disable main_clk mux[%d]: %d\n", i, ret); -+ if (ret) { -+ dev_warn(dev, "disable main_clk mux[%d] failed: %d\n", -+ i, ret); -+ goto err_ret; -+ } -+ } -+ -+ return 0; -+err_ret: -+ while (i-- > 0) -+ mt8901_afe_clk_mux_req(dev, mt8901_sdw_common_clk_muxes[i], -+ true); -+ -+ return ret; -+} -+ -+static int mt8901_afe_enable_main_clock(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ ret = mt8901_afe_enable_main_clk_muxes(mst); -+ if (ret) { -+ dev_err(dev, "enable_main_clk_muxes failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_enable_top_cg(mst, AUD_CG_AUDIO_HOPPING_CK); -+ if (ret) { -+ dev_err(dev, "enable_top_cg HOPPING failed: %d\n", ret); -+ goto err_muxes; -+ } -+ -+ ret = mt8901_afe_enable_top_cg(mst, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "enable_top_cg F26M failed: %d\n", ret); -+ goto err_hopping; -+ } -+ -+ ret = mt8901_afe_enable_afe_on(mst); -+ if (ret) { -+ dev_err(dev, "enable_afe_on failed: %d\n", ret); -+ goto err_f26m; -+ } -+ -+ return 0; -+ -+err_f26m: -+ mt8901_afe_disable_top_cg(mst, AUD_CG_AUDIO_F26M_CK); -+err_hopping: -+ mt8901_afe_disable_top_cg(mst, AUD_CG_AUDIO_HOPPING_CK); -+err_muxes: -+ mt8901_afe_disable_main_clk_muxes(mst); -+ -+ return ret; -+} -+ -+static int mt8901_afe_disable_main_clock(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ /* Transactional: stop at the first failure, re-enable what was released. */ -+ ret = mt8901_afe_disable_afe_on(mst); -+ if (ret) { -+ dev_err(dev, "disable_afe_on failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_disable_top_cg(mst, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "disable_top_cg F26M failed: %d\n", ret); -+ goto err_afe_on; -+ } -+ -+ ret = mt8901_afe_disable_top_cg(mst, AUD_CG_AUDIO_HOPPING_CK); -+ if (ret) { -+ dev_err(dev, "disable_top_cg HOPPING failed: %d\n", ret); -+ goto err_f26m; -+ } -+ -+ ret = mt8901_afe_disable_main_clk_muxes(mst); -+ if (ret) { -+ dev_err(dev, "disable_main_clk_muxes failed: %d\n", ret); -+ goto err_hopping; -+ } -+ -+ return 0; -+ -+err_hopping: -+ mt8901_afe_enable_top_cg(mst, AUD_CG_AUDIO_HOPPING_CK); -+err_f26m: -+ mt8901_afe_enable_top_cg(mst, AUD_CG_AUDIO_F26M_CK); -+err_afe_on: -+ mt8901_afe_enable_afe_on(mst); -+ -+ return ret; -+} -+ -+static int mt8901_afe_enable_reg_rw_clk(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ true); -+ if (ret) { -+ dev_err(dev, "enable reg_rw_clk INTBUS failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+ true); -+ if (ret) { -+ dev_err(dev, "enable reg_rw_clk VADSP failed: %d\n", ret); -+ goto err_intbus; -+ } -+ -+ ret = mt8901_afe_enable_top_cg(mst, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "enable_top_cg F26M failed: %d\n", ret); -+ goto err_vadsp; -+ } -+ -+ return 0; -+ -+err_vadsp: -+ mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, false); -+err_intbus: -+ mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ false); -+ -+ return ret; -+} -+ -+static int mt8901_afe_disable_reg_rw_clk(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ -+ ret = mt8901_afe_disable_top_cg(mst, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "disable_top_cg F26M failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+ false); -+ if (ret) { -+ dev_err(dev, "disable reg_rw_clk VADSP failed: %d\n", ret); -+ goto err_f26m; -+ } -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ false); -+ if (ret) { -+ dev_err(dev, "disable reg_rw_clk INTBUS failed: %d\n", ret); -+ goto err_vadsp; -+ } -+ -+ return 0; -+ -+err_vadsp: -+ mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, true); -+err_f26m: -+ mt8901_afe_enable_top_cg(mst, AUD_CG_AUDIO_F26M_CK); -+ -+ return ret; -+} -+ -+static int mt8901_afe_map_clk_parent(unsigned int mux, const char *parent_name, -+ unsigned int *level) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_clk_parent_map); i++) { -+ if (mt8901_clk_parent_map[i].mux == mux && -+ !strcmp(mt8901_clk_parent_map[i].parent_name, -+ parent_name)) { -+ *level = mt8901_clk_parent_map[i].level; -+ return 0; -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+static int mt8901_afe_set_clock_parent(struct mtk_sdw *mst, unsigned int mux, -+ const char *parent_name) -+{ -+ struct device *dev = mst->dev; -+ int ret; -+ unsigned int parent_level; -+ -+ ret = mt8901_afe_map_clk_parent(mux, parent_name, &parent_level); -+ if (ret) { -+ dev_err(dev, "map_clock_parent mux=%u parent=%s failed %d\n", -+ mux, parent_name, ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_clk_set_parent_req(dev, mux, parent_level); -+ dev_dbg(dev, "set_clock_parent mux=%u parent=%u: %d\n", -+ mux, parent_level, ret); -+ -+ return ret; -+} -+ -+static int mt8901_afe_enable_sdw_top_clock(struct mtk_sdw *mst, int link) -+{ -+ struct device *dev = mst->dev; -+ const unsigned int *clk_array; -+ unsigned int clk_array_size; -+ int i, ret; -+ -+ switch (link) { -+ case MTK_SDW_CONTROLLER_0: -+ clk_array = mt8901_sdw0_main_clk_muxes; -+ clk_array_size = ARRAY_SIZE(mt8901_sdw0_main_clk_muxes); -+ break; -+ case MTK_SDW_CONTROLLER_1: -+ clk_array = mt8901_sdw1_main_clk_muxes; -+ clk_array_size = ARRAY_SIZE(mt8901_sdw1_main_clk_muxes); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < clk_array_size; i++) { -+ ret = mt8901_afe_clk_mux_req(dev, clk_array[i], true); -+ if (ret) -+ goto err_ret; -+ dev_dbg(dev, "enable sdw_top_clk mux[%d]\n", i); -+ } -+ -+ return 0; -+err_ret: -+ while (i-- > 0) -+ mt8901_afe_clk_mux_req(dev, clk_array[i], false); -+ return ret; -+} -+ -+static int mt8901_afe_disable_sdw_top_clock(struct mtk_sdw *mst, int link) -+{ -+ struct device *dev = mst->dev; -+ const unsigned int *clk_array; -+ unsigned int clk_array_size; -+ int i, ret; -+ -+ switch (link) { -+ case MTK_SDW_CONTROLLER_0: -+ clk_array = mt8901_sdw0_main_clk_muxes; -+ clk_array_size = ARRAY_SIZE(mt8901_sdw0_main_clk_muxes); -+ break; -+ case MTK_SDW_CONTROLLER_1: -+ clk_array = mt8901_sdw1_main_clk_muxes; -+ clk_array_size = ARRAY_SIZE(mt8901_sdw1_main_clk_muxes); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < clk_array_size; i++) { -+ ret = mt8901_afe_clk_mux_req(dev, clk_array[i], false); -+ if (ret) -+ goto err_ret; -+ dev_dbg(dev, "disable sdw_top_clk mux[%u]\n", i); -+ } -+ -+ return 0; -+err_ret: -+ while (i-- > 0) -+ mt8901_afe_clk_mux_req(dev, clk_array[i], true); -+ return ret; -+} -+ -+static int mt8901_afe_enable_sdw_active_clock(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mt8901_afe_clk_mux_req(mst->dev, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ true); -+ if (ret) -+ return ret; -+ -+ dev_dbg(mst->dev, "enable active_clk mux\n"); -+ -+ return 0; -+} -+ -+static int mt8901_afe_disable_sdw_active_clock(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mt8901_afe_clk_mux_req(mst->dev, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ false); -+ if (ret) -+ return ret; -+ -+ dev_dbg(mst->dev, "disable active_clk mux\n"); -+ return 0; -+} -+ -+static int mt8901_sdw_enable_link_clock(struct mtk_sdw *mst, int link) -+{ -+ struct mtk_sdw_link *sdw_link = &mst->links[link]; -+ int ret; -+ -+ ret = mt8901_afe_enable_sdw_top_clock(mst, link); -+ if (ret) { -+ dev_err(mst->dev, "failed to enable sdw_top clock, ret %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_enable_main_clock(mst); -+ if (ret) { -+ dev_err(mst->dev, "failed to enable main clock, ret %d\n", ret); -+ mt8901_afe_disable_sdw_top_clock(mst, link); -+ return ret; -+ } -+ -+ if (!sdw_link->active_clk_enabled) { -+ ret = mt8901_afe_enable_sdw_active_clock(mst); -+ if (ret) { -+ dev_err(mst->dev, -+ "failed to enable main clock, ret %d\n", ret); -+ goto err_ret; -+ } -+ sdw_link->active_clk_enabled = true; -+ } -+ -+ if (link == MTK_SDW_CONTROLLER_0) { -+ ret = mt8901_afe_enable_top_cg(mst, AUD_CG_SOUNDWIRE0); -+ if (ret) { -+ dev_err(mst->dev, "failed to enable top cg %d, ret %d\n", -+ AUD_CG_SOUNDWIRE0, ret); -+ goto err_ret; -+ } -+ } else { -+ ret = mt8901_afe_enable_top_cg(mst, AUD_CG_SOUNDWIRE0); -+ if (ret) { -+ dev_err(mst->dev, "failed to enable top cg %d, ret %d\n", -+ AUD_CG_SOUNDWIRE0, ret); -+ goto err_ret; -+ } -+ ret = mt8901_afe_enable_top_cg(mst, AUD_CG_SOUNDWIRE1); -+ if (ret) { -+ dev_err(mst->dev, "failed to enable top cg %d, ret %d\n", -+ AUD_CG_SOUNDWIRE1, ret); -+ mt8901_afe_disable_top_cg(mst, AUD_CG_SOUNDWIRE0); -+ goto err_ret; -+ } -+ } -+ -+ ret = mt8901_afe_enable_top_cg(mst, AUD_CG_APLL2_CK); -+ if (ret) { -+ dev_err(mst->dev, "failed to enable top cg %d, ret %d\n", -+ AUD_CG_APLL2_CK, ret); -+ goto err_ret_cg; -+ } -+ -+ return 0; -+err_ret_cg: -+ if (link == MTK_SDW_CONTROLLER_0) { -+ mt8901_afe_disable_top_cg(mst, AUD_CG_SOUNDWIRE0); -+ } else { -+ mt8901_afe_disable_top_cg(mst, AUD_CG_SOUNDWIRE0); -+ mt8901_afe_disable_top_cg(mst, AUD_CG_SOUNDWIRE1); -+ } -+err_ret: -+ if (sdw_link->active_clk_enabled) { -+ mt8901_afe_disable_sdw_active_clock(mst); -+ sdw_link->active_clk_enabled = false; -+ } -+ -+ mt8901_afe_disable_main_clock(mst); -+ mt8901_afe_disable_sdw_top_clock(mst, link); -+ -+ return ret; -+} -+ -+static int mt8901_sdw_disable_link_clock(struct mtk_sdw *mst, int link) -+{ -+ struct mtk_sdw_link *sdw_link = &mst->links[link]; -+ int ret; -+ -+ /* -+ * Transactional: stop at the first failure and re-enable what was -+ * already released, so the caller always sees either a fully clocked -+ * or a fully unclocked link. -+ */ -+ ret = mt8901_afe_disable_top_cg(mst, AUD_CG_APLL2_CK); -+ if (ret) { -+ dev_err(mst->dev, "failed to disable top cg %d, ret %d\n", -+ AUD_CG_APLL2_CK, ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_disable_top_cg(mst, AUD_CG_SOUNDWIRE0); -+ if (ret) { -+ dev_err(mst->dev, "failed to disable top cg %d, ret %d\n", -+ AUD_CG_SOUNDWIRE0, ret); -+ goto err_apll2; -+ } -+ -+ if (link != MTK_SDW_CONTROLLER_0) { -+ ret = mt8901_afe_disable_top_cg(mst, AUD_CG_SOUNDWIRE1); -+ if (ret) { -+ dev_err(mst->dev, -+ "failed to disable top cg %d, ret %d\n", -+ AUD_CG_SOUNDWIRE1, ret); -+ goto err_sdw0; -+ } -+ } -+ -+ ret = mt8901_afe_disable_main_clock(mst); -+ if (ret) { -+ dev_err(mst->dev, "failed to disable main clock, ret %d\n", -+ ret); -+ goto err_sdw1; -+ } -+ -+ if (sdw_link->active_clk_enabled) { -+ ret = mt8901_afe_disable_sdw_active_clock(mst); -+ if (ret) { -+ dev_err(mst->dev, -+ "failed to disable active clock, ret %d\n", ret); -+ goto err_main; -+ } -+ sdw_link->active_clk_enabled = false; -+ } -+ -+ ret = mt8901_afe_disable_sdw_top_clock(mst, link); -+ if (ret) { -+ dev_err(mst->dev, "failed to disable sdw_top clock, ret %d\n", -+ ret); -+ goto err_active; -+ } -+ -+ return 0; -+ -+err_active: -+ if (!sdw_link->active_clk_enabled && -+ !mt8901_afe_enable_sdw_active_clock(mst)) -+ sdw_link->active_clk_enabled = true; -+err_main: -+ mt8901_afe_enable_main_clock(mst); -+err_sdw1: -+ if (link != MTK_SDW_CONTROLLER_0) -+ mt8901_afe_enable_top_cg(mst, AUD_CG_SOUNDWIRE1); -+err_sdw0: -+ mt8901_afe_enable_top_cg(mst, AUD_CG_SOUNDWIRE0); -+err_apll2: -+ mt8901_afe_enable_top_cg(mst, AUD_CG_APLL2_CK); -+ -+ return ret; -+} -+ -+static int mt8901_sdw_enable_reg_rw_clk(struct mtk_sdw *mst) -+{ -+ return mt8901_afe_enable_reg_rw_clk(mst); -+} -+ -+static int mt8901_sdw_disable_reg_rw_clk(struct mtk_sdw *mst) -+{ -+ return mt8901_afe_disable_reg_rw_clk(mst); -+} -+ -+static int mt8901_sdw_enable_power_domain(struct mtk_sdw *mst) -+{ -+ return mt8901_afe_enable_mtcmos(mst, AUDIO_PD); -+} -+ -+static int mt8901_sdw_disable_power_domain(struct mtk_sdw *mst) -+{ -+ return mt8901_afe_disable_mtcmos(mst, AUDIO_PD); -+} -+ -+const struct mtk_sdw_clk_ops mt8901_clk_ops = { -+ .init_clock = mt8901_sdw_init_clock, -+ .enable_reg_rw_clk = mt8901_sdw_enable_reg_rw_clk, -+ .disable_reg_rw_clk = mt8901_sdw_disable_reg_rw_clk, -+ .enable_link_clock = mt8901_sdw_enable_link_clock, -+ .disable_link_clock = mt8901_sdw_disable_link_clock, -+ .enable_power_domain = mt8901_sdw_enable_power_domain, -+ .disable_power_domain = mt8901_sdw_disable_power_domain, -+}; -diff --git a/drivers/soundwire/mediatek/mt8901-afe-clk.h b/drivers/soundwire/mediatek/mt8901-afe-clk.h -new file mode 100644 -index 0000000000..9980f496e6 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mt8901-afe-clk.h -@@ -0,0 +1,162 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * mt8901-afe-clk.h -- MediaTek 8901 afe clock ctrl definition -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ * Weiyi Hsieh -+ */ -+ -+#ifndef _MT8901_AFE_CLK_H_ -+#define _MT8901_AFE_CLK_H_ -+ -+#include "mtk-sdw-common.h" -+ -+enum sspm_aud_cmd { -+ SSPM_AUD_CMD_MTCMOS = 0, -+ SSPM_AUD_CMD_CG, -+ SSPM_AUD_CMD_VLP_SYS_CLK_MUX, -+ SSPM_AUD_CMD_VLP_SYS_CLK_SET_RATE, -+ SSPM_AUD_CMD_VLP_SYS_CLK_SET_PARENT, -+ SSPM_AUD_CMD_AFE_SPM_CTRL, -+ SSPM_AUD_CMD_PWR_CTRL_SCENE, -+ SSPM_AUD_CMD_CLK_CG_DEINIT, -+ SSPM_AUD_CMD_NUM, -+}; -+ -+enum audio_mtcmos_pd_id { -+ AUDIO_VADSYS_PD_AO = 0, -+ AUDIO_VADSYS_PD_INFRA, -+ AUDIO_PD, -+ AUDIO_PD_NUM, -+}; -+ -+enum afe_pwr_scene { -+ AUDIO_PWR_SCEN_NORMAL = 0, -+ AUDIO_PWR_SCEN_BY_DSTATE, -+ AUDIO_PWR_SCEN_AON, -+ AUDIO_PWR_SCEN_NUM, -+}; -+ -+enum afe_spm_ctrl_req_type { -+ AFE_SPM_CTRL_VCORE_REQ = 0, -+ AFE_SPM_CTRL_PMIC_REQ, -+ AFE_SPM_CTRL_SRCCLKENA_REQ, -+ AFE_SPM_CTRL_APSRC_REQ, -+ AFE_SPM_CTRL_VRF18_REQ, -+ AFE_SPM_CTRL_INFRA_REQ, -+ AFE_SPM_CTRL_DDREN_REQ, -+ AFE_SPM_CTRL_REQ_NUMS, -+}; -+ -+enum audio_top_con_cg_type { -+ AUD_CG_ASD_BEGIN, -+ /* AUDIO_TOP_CON0 (0x0000) */ -+ AUD_CG_HW_GAIN01 = AUD_CG_ASD_BEGIN, -+ AUD_CG_HW_GAIN23, -+ AUD_CG_CM0, -+ AUD_CG_CM1, -+ AUD_CG_CM2, -+ /* AUDIO_TOP_CON1 (0x0004) */ -+ AUD_CG_HW_GAIN_DL0_DL1, -+ AUD_CG_HW_GAIN_DL2_DL3, -+ AUD_CG_HW_GAIN_DL4_DL5, -+ AUD_CG_HW_GAIN_DL24CH, -+ AUD_CG_UL0_ADC, -+ AUD_CG_UL0_TML, -+ AUD_CG_UL0_ADC_HIRES, -+ AUD_CG_UL0_ADC_HIRES_TML, -+ AUD_CG_UL1_ADC, -+ AUD_CG_UL1_TML, -+ AUD_CG_UL1_ADC_HIRES, -+ AUD_CG_UL1_ADC_HIRES_TML, -+ /* AUDIO_TOP_CON2 (0x0008) */ -+ AUD_CG_ETDM_OUT0, -+ AUD_CG_ETDM_OUT5, -+ AUD_CG_ETDM_IN0, -+ AUD_CG_ETDM_IN5, -+ /* AUDIO_TOP_CON3 (0x0008) */ -+ AUD_CG_GENERAL0_ASRC, -+ AUD_CG_GENERAL1_ASRC, -+ AUD_CG_GENERAL2_ASRC, -+ AUD_CG_GENERAL3_ASRC, -+ AUD_CG_GENERAL4_ASRC, -+ AUD_CG_GENERAL5_ASRC, -+ AUD_CG_GENERAL6_ASRC, -+ AUD_CG_GENERAL7_ASRC, -+ /* AUDIO_TOP_CON4 (0x0010) */ -+ AUD_CG_APLL_TUNER1, -+ AUD_CG_APLL_TUNER2, -+ AUD_CG_H208M_CK, -+ AUD_CG_APLL2_CK, -+ AUD_CG_APLL1_CK, -+ AUD_CG_SDW_BEGIN, -+ AUD_CG_AUDIO_F26M_CK = AUD_CG_SDW_BEGIN, -+ AUD_CG_AUDIO_HOPPING_CK, -+ AUD_CG_ASD_END = AUD_CG_AUDIO_HOPPING_CK, -+ /* AUDIO_TOP_CON5 (0x0070) - SoundWire (owned by dai-soundwire.c) */ -+ AUD_CG_SOUNDWIRE_DMIC0_ADC, -+ AUD_CG_SOUNDWIRE_DMIC0_TML, -+ AUD_CG_SOUNDWIRE_DMIC1_ADC, -+ AUD_CG_SOUNDWIRE_DMIC1_TML, -+ AUD_CG_SOUNDWIRE_DMIC2_ADC, -+ AUD_CG_SOUNDWIRE_DMIC2_TML, -+ AUD_CG_SOUNDWIRE_DMIC3_ADC, -+ AUD_CG_SOUNDWIRE_DMIC3_TML, -+ AUD_CG_SOUNDWIRE_DMIC4_ADC, -+ AUD_CG_SOUNDWIRE_DMIC4_TML, -+ AUD_CG_SOUNDWIRE_DMIC5_ADC, -+ AUD_CG_SOUNDWIRE_DMIC5_TML, -+ AUD_CG_SOUNDWIRE_DMIC6_ADC, -+ AUD_CG_SOUNDWIRE_DMIC6_TML, -+ AUD_CG_SOUNDWIRE_DMIC7_ADC, -+ AUD_CG_SOUNDWIRE_DMIC7_TML, -+ AUD_CG_SOUNDWIRE1, -+ AUD_CG_SOUNDWIRE0, -+ AUD_CG_SDW_END = AUD_CG_SOUNDWIRE0, -+ AUD_CG_NUMS, -+}; -+ -+enum afe_clk_mux_type { -+ AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL = 0, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_PHY_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_PHY_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_APLL_I2S1_MCK_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+ AFE_CLK_NUMS, -+}; -+ -+/* Clock parent names, per audio_clock_interface.h (SSPM firmware header) */ -+#define CLK_PARENT_TCX_26M_MX9_CK_NAME "tcx_26m_mx9_ck" -+#define CLK_PARENT_OSC_D20_NAME "osc_d20" -+#define CLK_PARENT_OSC_D12_NAME "osc_d12" -+#define CLK_PARENT_OSC_D10_NAME "osc_d10" -+#define CLK_PARENT_OSC_D6_NAME "osc_d6" -+#define CLK_PARENT_OSC_D5_NAME "osc_d5" -+#define CLK_PARENT_OSC_D2_NAME "osc_d2" -+#define CLK_PARENT_AD_OSC_NAME "ad_osc_ck" -+#define CLK_PARENT_APLL1_D2_NAME "apll1_d2" -+#define CLK_PARENT_APLL2_D2_NAME "apll2_d2" -+#define CLK_PARENT_APLL1_D8_NAME "apll1_d8" -+#define CLK_PARENT_APLL1_D4_NAME "apll1_d4" -+#define CLK_PARENT_APLL2_D8_NAME "apll2_d8" -+#define CLK_PARENT_APLL2_D4_NAME "apll2_d4" -+#define CLK_PARENT_APLL1_NAME "apll1" -+#define CLK_PARENT_APLL2_NAME "apll2" -+#define CLK_PARENT_MAINPLL2_D7_D4_NAME "mainpll2_d7_d4" -+#define CLK_PARENT_MAINPLL2_D4_D4_NAME "mainpll2_d4_d4" -+#define CLK_PARENT_UNIVPLL2_D4_NAME "univpll2_d4" -+#define CLK_PARENT_UNIVPLL2_D4_D2_NAME "univpll2_d4_d2" -+#define CLK_PARENT_ADSPPLL_NAME "adsppll_ck" -+#define CLK_PARENT_ADSPPLL_D2_NAME "adsppll_d2" -+ -+extern const struct mtk_sdw_clk_ops mt8901_clk_ops; -+ -+#endif -diff --git a/drivers/soundwire/mediatek/mtk-sdw-chipglue.c b/drivers/soundwire/mediatek/mtk-sdw-chipglue.c -new file mode 100644 -index 0000000000..1ed676ed50 ---- /dev/null -+++ b/drivers/soundwire/mediatek/mtk-sdw-chipglue.c -@@ -0,0 +1,34 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * mtk-sdw-chipglue.c -- chip-specific selection for the MediaTek -+ * SoundWire controller driver. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ * Author: Trevor Wu -+ */ -+ -+#include -+#include "mtk-sdw-common.h" -+ -+#if IS_ENABLED(CONFIG_SOUNDWIRE_MTK_MT8901_CLK) -+#include "mt8901-afe-clk.h" -+#endif -+ -+int mtk_sdw_clk_ops_select(struct mtk_sdw *mst, int hw_ver) -+{ -+ switch (hw_ver) { -+#if IS_ENABLED(CONFIG_SOUNDWIRE_MTK_MT8901_CLK) -+ case MTK_SDW_HW_VER_MT8901: -+ case MTK_SDW_HW_VER_MT8971: -+ mst->clk_ops = &mt8901_clk_ops; -+ break; -+#endif -+ default: -+ dev_err(mst->dev, -+ "no clock control ops for hw-ver %u (unsupported or not compiled in)\n", -+ hw_ver); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -diff --git a/drivers/soundwire/mediatek/mtk-sdw-common.h b/drivers/soundwire/mediatek/mtk-sdw-common.h -index 32912b1272..98efbe550d 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-common.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-common.h -@@ -21,7 +21,12 @@ enum mtk_sdw_hw_ver { - MTK_SDW_HW_VER_MAX, - }; - --#define SDW_MAX_HWIP_NUM (2) -+enum mtk_sdw_controller_id { -+ MTK_SDW_CONTROLLER_0 = 0, -+ MTK_SDW_CONTROLLER_1, -+ MTK_SDW_CONTROLLE_NUM -+}; -+ - #define SDW_PDI_CONFIG_NUM (8) - #define MTK_SDW_MAX_GROUP_SYNC 4 - #define MTK_SDW_MAX_DP 16 -@@ -35,6 +40,7 @@ struct mtk_sdw_link { - u32 src_num; - u32 sink_base; - u32 sink_num; -+ bool active_clk_enabled; - }; - - struct mtk_sdw_dai { -@@ -49,19 +55,38 @@ struct mtk_sdw_dai { - bool need_enable_delay; - }; - -+/* -+ * Per-chip-generation AFE clock/MTCMOS control. -+ */ -+struct mtk_sdw_clk_ops { -+ int (*init_clock)(struct mtk_sdw *mst); -+ int (*enable_reg_rw_clk)(struct mtk_sdw *mst); -+ int (*disable_reg_rw_clk)(struct mtk_sdw *mst); -+ int (*enable_link_clock)(struct mtk_sdw *mst, int link); -+ int (*disable_link_clock)(struct mtk_sdw *mst, int link); -+ int (*enable_power_domain)(struct mtk_sdw *mst); -+ int (*disable_power_domain)(struct mtk_sdw *mst); -+}; -+ -+int mtk_sdw_clk_ops_select(struct mtk_sdw *mst, int hw_ver); -+ - struct mtk_sdw { - struct device *dev; - void __iomem *base; /* full AFE MMIO */ -- struct mtk_sdw_link links[SDW_MAX_HWIP_NUM]; -+ struct mtk_sdw_link links[MTK_SDW_CONTROLLE_NUM]; - int num_links; - u32 controller_en_list; - const struct mtk_sdw_top_cfg *top_cfg; - void __iomem *top_pdi; /* base + top_cfg->pdi_base */ - void __iomem *top_con; /* base + top_cfg->con_base */ -+ const struct mtk_sdw_clk_ops *clk_ops; - u32 hw_ver; - /* group_lock: serializes group_refcnt[] group-sync allocation */ - struct mutex group_lock; - int group_refcnt[MTK_SDW_MAX_GROUP_SYNC]; -+ /* afe_lock: serializes afe_on_refcnt for afe on/off */ -+ struct mutex afe_lock; -+ int afe_on_refcnt; - u32 tzd_delay; - bool tzd_inverse; - u32 phy_delay; -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index 09329088cd..5aebe75612 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -68,6 +68,61 @@ static int mtk_sdw_parse_dp_allocation(struct mtk_sdw *mst, int idx) - return 0; - } - -+static int mtk_sdw_init_clock(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->init_clock(mst); -+ if (ret) -+ dev_err(mst->dev, "failed to init clock, ret %d\n", ret); -+ -+ return ret; -+} -+ -+static int mtk_sdw_enable_top_clock(struct mtk_sdw *mst, int link) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->enable_link_clock(mst, link); -+ if (ret) -+ dev_err(mst->dev, "failed to enable top clock, ret %d\n", ret); -+ -+ return ret; -+} -+ -+static int mtk_sdw_disable_top_clock(struct mtk_sdw *mst, int link) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->disable_link_clock(mst, link); -+ if (ret) -+ dev_err(mst->dev, "failed to disable top clock, ret %d\n", ret); -+ -+ return ret; -+} -+ -+static int mtk_sdw_enable_reg_clock(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->enable_reg_rw_clk(mst); -+ if (ret) -+ dev_err(mst->dev, "failed to enable reg clock, ret %d\n", ret); -+ -+ return ret; -+} -+ -+static int mtk_sdw_disable_reg_clock(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->disable_reg_rw_clk(mst); -+ if (ret) -+ dev_err(mst->dev, "failed to disable reg clock, ret %d\n", ret); -+ -+ return ret; -+} -+ - /* ======================================================================= - * ASoC DAI layer (ALSA <-> SoundWire stream binding) - * ======================================================================= -@@ -745,23 +800,34 @@ static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) - core->bus.link_id = idx; - core->bus.prop.mclk_freq = SDW_DEFAULT_MCLK_CLK_FREQ; - -+ ret = mtk_sdw_enable_top_clock(mst, idx); -+ if (ret) { -+ dev_err(mst->dev, "IP%d: enable top clock failed: %d\n", -+ idx, ret); -+ return ret; -+ } -+ - core->bus.dev = mst->dev; - ret = sdw_bus_master_add(&core->bus, mst->dev, mst->dev->fwnode); - if (ret) { - dev_err(mst->dev, "IP%d: bus_master_add failed: %d\n", - idx, ret); -- return ret; -+ goto err_disable_top_clock; - } - - ret = mtk_sdw_core_hw_init(core); - if (ret) { - sdw_bus_master_delete(&core->bus); -- return ret; -+ goto err_disable_top_clock; - } - - mtk_sdw_enable_irq(core, true); - dev_info(mst->dev, "IP%d: SoundWire bus ready\n", idx); - return 0; -+ -+err_disable_top_clock: -+ mtk_sdw_disable_top_clock(mst, idx); -+ return ret; - } - - static void mtk_sdw_link_deinit(struct mtk_sdw *mst, int idx) -@@ -780,9 +846,9 @@ static void mtk_init_sdw_master(struct mtk_sdw *mst) - mst->tzd_inverse = 0; - mst->phy_delay = 2; - mst->phy_double_delay = 0; -- mst->num_links = SDW_MAX_HWIP_NUM; -+ mst->num_links = MTK_SDW_CONTROLLE_NUM; - -- for (i = 0; i < SDW_MAX_HWIP_NUM; i++) -+ for (i = 0; i < MTK_SDW_CONTROLLE_NUM; i++) - mst->controller_en_list |= (1UL << i); - } - -@@ -816,6 +882,7 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - u32 hw_ver = MTK_SDW_HW_VER_MT8901; - u32 mmio[2]; - int i, ret; -+ bool clk_on; - - mst = devm_kzalloc(dev, sizeof(*mst), GFP_KERNEL); - if (!mst) -@@ -825,6 +892,7 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - - mst->dev = dev; - mutex_init(&mst->group_lock); -+ mutex_init(&mst->afe_lock); - platform_set_drvdata(pdev, mst); - - ret = device_property_read_u32_array(dev, "afe-base", mmio, 2); -@@ -850,6 +918,10 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - if (ret) - return ret; - -+ ret = mtk_sdw_clk_ops_select(mst, mst->hw_ver); -+ if (ret) -+ return ret; -+ - /* Timing delays from ACPI _DSD. */ - device_property_read_u32(dev, "acpi-scd-tzd-delay", &mst->tzd_delay); - device_property_read_u32(dev, "acpi-scd-phy-delay", &mst->phy_delay); -@@ -862,6 +934,16 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - return -EINVAL; - } - -+ ret = mtk_sdw_init_clock(mst); -+ if (ret) -+ return ret; -+ -+ ret = mtk_sdw_enable_reg_clock(mst); -+ if (ret) -+ return ret; -+ -+ clk_on = true; -+ - mtk_sdw_top_init_settings(mst); - mtk_sdw_top_configure_delays(mst); - -@@ -907,6 +989,11 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - goto err; - } - -+ ret = mtk_sdw_disable_reg_clock(mst); -+ if (ret) -+ goto err; -+ clk_on = false; -+ - ret = mtk_sdw_register_dais(mst); - if (ret) { - dev_err(dev, "failed to register DAIs: %d\n", ret); -@@ -922,6 +1009,9 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - while (--i >= 0) - mtk_sdw_link_deinit(mst, i); - -+ if (clk_on) -+ mtk_sdw_disable_reg_clock(mst); -+ - return ret; - } - -From 45a48bfeef643cc068fba90ad00f8ead4b0e2679 Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:08 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: mt8901: add clock control - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Add the mt8901 audio clock control: the AFE clock tree (muxes, -gates, APLL tuner and engen control) and the SSPM-managed functional -clock requests issued through the power-wrap client API. Select -SOUNDWIRE_MTK_MT8901_CLK from the machine configuration so the clock -integration is always active with the machine driver. - -Folded review fix: roll back a partially applied idle clock parent -switch instead of leaving the mux chain in a mixed state when one step -fails. - -Depends on the MediaTek power_wrap driver providing -mtk_send_power_control_req() (submitted separately). - -Signed-off-by: Trevor Wu -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - sound/soc/mediatek/mt8901/mt8901-afe-clk.c | 626 ++++++++++++++++++++- - sound/soc/mediatek/mt8901/mt8901-afe-clk.h | 162 ++++++ - sound/soc/mediatek/mt8901/mt8901-afe-pcm.c | 30 +- - 3 files changed, 810 insertions(+), 8 deletions(-) - -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-clk.c b/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -index 44aa2b1ba2..bec45b7b66 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -@@ -7,9 +7,219 @@ - * Weiyi Hsieh - */ - -+#include -+#include - #include "mt8901-afe-common.h" - #include "mt8901-afe-clk.h" - #include "mt8901-reg.h" -+#include -+ -+static const unsigned int mt8901_main_clk_muxes[] = { -+ AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+}; -+ -+static const unsigned int mt8901_apll_top_con_cgs[] = { -+ AUD_CG_APLL1_CK, -+ AUD_CG_APLL2_CK, -+ AUD_CG_APLL_TUNER1, -+ AUD_CG_APLL_TUNER2, -+}; -+ -+static const struct { -+ unsigned int mux; -+ const char *parent_name; -+ unsigned int level; -+} mt8901_clk_parent_map[] = { -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_APLL1_D2_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_APLL2_D2_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_APLL1_D8_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_APLL1_D4_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_APLL2_D8_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_APLL2_D4_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_OSC_D20_NAME, 1 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_MAINPLL2_D7_D4_NAME, 2 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_MAINPLL2_D4_D4_NAME, 3 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ CLK_PARENT_APLL1_NAME, 1 }, -+ -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, 0 }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ CLK_PARENT_APLL2_NAME, 1 }, -+}; -+ -+static const struct { -+ unsigned int mux; -+ const char *idle_parent_name; -+ const char *active_parent_name; -+} idle_clk_muxes[] = { -+ { AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_APLL2_D2_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_MAINPLL2_D4_D4_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, CLK_PARENT_APLL1_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ CLK_PARENT_TCX_26M_MX9_CK_NAME, CLK_PARENT_APLL2_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_APLL1_D4_NAME }, -+ { AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ CLK_PARENT_OSC_D20_NAME, CLK_PARENT_APLL2_D4_NAME }, -+}; -+ -+static const char * const mt8901_cg_names[] = { -+ [AUD_CG_HW_GAIN01] = "HW_GAIN01", -+ [AUD_CG_HW_GAIN23] = "HW_GAIN23", -+ [AUD_CG_CM0] = "CM0", -+ [AUD_CG_CM1] = "CM1", -+ [AUD_CG_CM2] = "CM2", -+ [AUD_CG_HW_GAIN_DL0_DL1] = "HW_GAIN_DL0_DL1", -+ [AUD_CG_HW_GAIN_DL2_DL3] = "HW_GAIN_DL2_DL3", -+ [AUD_CG_HW_GAIN_DL4_DL5] = "HW_GAIN_DL4_DL5", -+ [AUD_CG_HW_GAIN_DL24CH] = "HW_GAIN_DL24CH", -+ [AUD_CG_UL0_ADC] = "UL0_ADC", -+ [AUD_CG_UL0_TML] = "UL0_TML", -+ [AUD_CG_UL0_ADC_HIRES] = "UL0_ADC_HIRES", -+ [AUD_CG_UL0_ADC_HIRES_TML] = "UL0_ADC_HIRES_TML", -+ [AUD_CG_UL1_ADC] = "UL1_ADC", -+ [AUD_CG_UL1_TML] = "UL1_TML", -+ [AUD_CG_UL1_ADC_HIRES] = "UL1_ADC_HIRES", -+ [AUD_CG_UL1_ADC_HIRES_TML] = "UL1_ADC_HIRES_TML", -+ [AUD_CG_ETDM_OUT0] = "ETDM_OUT0", -+ [AUD_CG_ETDM_OUT5] = "ETDM_OUT5", -+ [AUD_CG_ETDM_IN0] = "ETDM_IN0", -+ [AUD_CG_ETDM_IN5] = "ETDM_IN5", -+ [AUD_CG_GENERAL0_ASRC] = "GASRC0", -+ [AUD_CG_GENERAL1_ASRC] = "GASRC1", -+ [AUD_CG_GENERAL2_ASRC] = "GASRC2", -+ [AUD_CG_GENERAL3_ASRC] = "GASRC3", -+ [AUD_CG_GENERAL4_ASRC] = "GASRC4", -+ [AUD_CG_GENERAL5_ASRC] = "GASRC5", -+ [AUD_CG_GENERAL6_ASRC] = "GASRC6", -+ [AUD_CG_GENERAL7_ASRC] = "GASRC7", -+ [AUD_CG_APLL_TUNER1] = "APLL_TUNER1", -+ [AUD_CG_APLL_TUNER2] = "APLL_TUNER2", -+ [AUD_CG_H208M_CK] = "H208M", -+ [AUD_CG_APLL2_CK] = "APLL2", -+ [AUD_CG_APLL1_CK] = "APLL1", -+ [AUD_CG_AUDIO_F26M_CK] = "F26M", -+ [AUD_CG_AUDIO_HOPPING_CK] = "HOPPING", -+ [AUD_CG_SOUNDWIRE_DMIC0_ADC] = "SDW_DMIC0_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC0_TML] = "SDW_DMIC0_TML", -+ [AUD_CG_SOUNDWIRE_DMIC1_ADC] = "SDW_DMIC1_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC1_TML] = "SDW_DMIC1_TML", -+ [AUD_CG_SOUNDWIRE_DMIC2_ADC] = "SDW_DMIC2_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC2_TML] = "SDW_DMIC2_TML", -+ [AUD_CG_SOUNDWIRE_DMIC3_ADC] = "SDW_DMIC3_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC3_TML] = "SDW_DMIC3_TML", -+ [AUD_CG_SOUNDWIRE_DMIC4_ADC] = "SDW_DMIC4_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC4_TML] = "SDW_DMIC4_TML", -+ [AUD_CG_SOUNDWIRE_DMIC5_ADC] = "SDW_DMIC5_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC5_TML] = "SDW_DMIC5_TML", -+ [AUD_CG_SOUNDWIRE_DMIC6_ADC] = "SDW_DMIC6_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC6_TML] = "SDW_DMIC6_TML", -+ [AUD_CG_SOUNDWIRE_DMIC7_ADC] = "SDW_DMIC7_ADC", -+ [AUD_CG_SOUNDWIRE_DMIC7_TML] = "SDW_DMIC7_TML", -+ [AUD_CG_SOUNDWIRE1] = "SOUNDWIRE1", -+ [AUD_CG_SOUNDWIRE0] = "SOUNDWIRE0", -+}; -+ -+static int mt8901_afe_send_power_req(struct device *dev, u8 cmd, -+ u32 d0, u32 d1, u32 d2) -+{ -+ struct power_cntl_scmi_data scmidata = { -+ .requestId = cmd, -+ .customdata = { d0, d1, d2 }, -+ }; -+ struct _power_cntrl_request req = { -+ .dev = dev, -+ .InBuffer = &scmidata, -+ .InBufferSize = sizeof(scmidata), -+ }; -+ -+ return mtk_send_power_control_req(&req); -+} -+ -+static int mt8901_afe_pwr_ctrl_scene_req(struct device *dev, unsigned int scene) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_PWR_CTRL_SCENE, -+ scene, 0, 0); -+} -+ -+static int mt8901_afe_clk_cg_deinit_req(struct device *dev) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_CLK_CG_DEINIT, -+ 0, 0, 0); -+} -+ -+static int mt8901_afe_cg_req(struct device *dev, unsigned int cg, bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_CG, cg, enable, 0); -+} -+ -+static int mt8901_afe_mtcmos_req(struct device *dev, unsigned int mtcmos, -+ bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_MTCMOS, mtcmos, -+ enable, 0); -+} -+ -+static int mt8901_afe_afe_spm_ctrl_req(struct device *dev, unsigned int req, -+ bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_AFE_SPM_CTRL, -+ req, enable, 0); -+} -+ -+static int mt8901_afe_clk_mux_req(struct device *dev, unsigned int mux, -+ bool enable) -+{ -+ return mt8901_afe_send_power_req(dev, SSPM_AUD_CMD_VLP_SYS_CLK_MUX, -+ mux, enable, 0); -+} -+ -+static int mt8901_afe_clk_set_parent_req(struct device *dev, unsigned int mux, -+ unsigned int parent_level) -+{ -+ return mt8901_afe_send_power_req(dev, -+ SSPM_AUD_CMD_VLP_SYS_CLK_SET_PARENT, -+ mux, parent_level, 0); -+} - - static int mt8901_afe_enable_afe_on(struct mtk_base_afe *afe) - { -@@ -18,8 +228,7 @@ static int mt8901_afe_enable_afe_on(struct mtk_base_afe *afe) - mask = AUDIO_ENGEN_CON0_APLL2_MASK | - AUDIO_ENGEN_CON0_APLL1_MASK | - AUDIO_ENGEN_CON0_26M_MASK; -- regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, mask, mask); -- return 0; -+ return regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, mask, mask); - } - - static int mt8901_afe_disable_afe_on(struct mtk_base_afe *afe) -@@ -29,18 +238,425 @@ static int mt8901_afe_disable_afe_on(struct mtk_base_afe *afe) - mask = AUDIO_ENGEN_CON0_APLL2_MASK | - AUDIO_ENGEN_CON0_APLL1_MASK | - AUDIO_ENGEN_CON0_26M_MASK; -- regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, mask, 0x0); -+ return regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, mask, 0x0); -+} -+ -+static int mt8901_afe_check_sspm_probe(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_pwr_ctrl_scene_req(dev, AUDIO_PWR_SCEN_NORMAL); -+ if (ret) { -+ dev_err(dev, "SSPM probe failed: %d\n", ret); -+ return ret; -+ } -+ -+ dev_dbg(dev, "SSPM available\n"); - return 0; - } - -+int mt8901_afe_disable_default_on_clk_and_top_cg(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_clk_cg_deinit_req(dev); -+ dev_dbg(dev, "disable_default_on_clk_and_top_cg: %d\n", ret); -+ -+ return ret; -+} -+ -+int mt8901_afe_init_clock(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_check_sspm_probe(afe); -+ if (ret) -+ return ret; -+ -+ ret = mt8901_afe_disable_default_on_clk_and_top_cg(afe); -+ if (ret) { -+ dev_err(dev, "disable_default_on_clk_and_top_cg failed: %d\n", -+ ret); -+ return ret; -+ } -+ -+ return ret; -+} -+ -+int mt8901_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg) -+{ -+ struct device *dev = afe->dev; -+ const char *name; -+ int ret; -+ -+ if (cg >= AUD_CG_NUMS) -+ return -EINVAL; -+ -+ name = mt8901_cg_names[cg]; -+ -+ ret = mt8901_afe_cg_req(dev, cg, true); -+ -+ dev_dbg(dev, "enable_top_cg %s: %d\n", name, ret); -+ return ret; -+} -+ -+int mt8901_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg) -+{ -+ struct device *dev = afe->dev; -+ const char *name; -+ int ret; -+ -+ if (cg >= AUD_CG_NUMS) -+ return -EINVAL; -+ -+ name = mt8901_cg_names[cg]; -+ -+ ret = mt8901_afe_cg_req(dev, cg, false); -+ -+ dev_dbg(dev, "disable_top_cg %s: %d\n", name, ret); -+ return ret; -+} -+ -+int mt8901_afe_enable_apll_top_con_cg(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_apll_top_con_cgs); i++) { -+ ret = mt8901_afe_enable_top_cg(afe, mt8901_apll_top_con_cgs[i]); -+ if (ret) { -+ dev_err(dev, "enable_top_cg %s failed: %d\n", -+ mt8901_cg_names[mt8901_apll_top_con_cgs[i]], -+ ret); -+ goto err; -+ } -+ } -+ -+ return 0; -+ -+err: -+ while (i-- > 0) -+ mt8901_afe_disable_top_cg(afe, mt8901_apll_top_con_cgs[i]); -+ -+ return ret; -+} -+ -+int mt8901_afe_disable_apll_top_con_cg(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int i, ret; -+ int last_ret = 0; -+ -+ for (i = ARRAY_SIZE(mt8901_apll_top_con_cgs) - 1; i >= 0; i--) { -+ ret = mt8901_afe_disable_top_cg(afe, -+ mt8901_apll_top_con_cgs[i]); -+ if (ret) { -+ dev_warn(dev, "disable_top_cg %s failed: %d\n", -+ mt8901_cg_names[mt8901_apll_top_con_cgs[i]], -+ ret); -+ last_ret = ret; -+ } -+ } -+ -+ return last_ret; -+} -+ -+int mt8901_afe_enable_mtcmos(struct mtk_base_afe *afe, unsigned int mtcmos) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ if (mtcmos >= AUDIO_PD_NUM) -+ return -EINVAL; -+ -+ ret = mt8901_afe_mtcmos_req(dev, mtcmos, true); -+ dev_dbg(dev, "enable_mtcmos %u: %d\n", mtcmos, ret); -+ return ret; -+} -+ -+int mt8901_afe_disable_mtcmos(struct mtk_base_afe *afe, unsigned int mtcmos) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ if (mtcmos >= AUDIO_PD_NUM) -+ return -EINVAL; -+ -+ ret = mt8901_afe_mtcmos_req(dev, mtcmos, false); -+ dev_dbg(dev, "disable_mtcmos %u: %d\n", mtcmos, ret); -+ return ret; -+} -+ -+int mt8901_afe_send_spm_req(struct mtk_base_afe *afe, unsigned int req, -+ bool enable) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ if (req >= AFE_SPM_CTRL_REQ_NUMS) -+ return -EINVAL; -+ -+ ret = mt8901_afe_afe_spm_ctrl_req(dev, req, enable); -+ dev_dbg(dev, "send_spm_req %u en=%d: %d\n", req, enable, ret); -+ return ret; -+} -+ -+static int mt8901_afe_enable_main_clk_muxes(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_main_clk_muxes); i++) { -+ ret = mt8901_afe_clk_mux_req(dev, mt8901_main_clk_muxes[i], -+ true); -+ dev_dbg(dev, "enable main_clk mux[%d]: %d\n", i, ret); -+ if (ret) -+ goto err_ret; -+ } -+ -+ return 0; -+err_ret: -+ while (i-- > 0) -+ mt8901_afe_clk_mux_req(dev, mt8901_main_clk_muxes[i], false); -+ -+ return ret; -+} -+ -+static int mt8901_afe_disable_main_clk_muxes(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int i, ret; -+ int last_ret = 0; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_main_clk_muxes); i++) { -+ ret = mt8901_afe_clk_mux_req(dev, mt8901_main_clk_muxes[i], -+ false); -+ dev_dbg(dev, "disable main_clk mux[%d]: %d\n", i, ret); -+ if (ret) { -+ dev_warn(dev, "disable main_clk mux[%d] failed: %d\n", -+ i, ret); -+ last_ret = ret; -+ } -+ } -+ -+ return last_ret; -+} -+ - int mt8901_afe_enable_main_clock(struct mtk_base_afe *afe) - { -- mt8901_afe_enable_afe_on(afe); -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_enable_main_clk_muxes(afe); -+ if (ret) { -+ dev_err(dev, "enable_main_clk_muxes failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_enable_top_cg(afe, AUD_CG_AUDIO_HOPPING_CK); -+ if (ret) { -+ dev_err(dev, "enable_top_cg HOPPING failed: %d\n", ret); -+ goto err_muxes; -+ } -+ -+ ret = mt8901_afe_enable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "enable_top_cg F26M failed: %d\n", ret); -+ goto err_hopping; -+ } -+ -+ ret = mt8901_afe_enable_afe_on(afe); -+ if (ret) { -+ dev_err(dev, "enable_afe_on failed: %d\n", ret); -+ goto err_f26m; -+ } -+ - return 0; -+ -+err_f26m: -+ mt8901_afe_disable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); -+err_hopping: -+ mt8901_afe_disable_top_cg(afe, AUD_CG_AUDIO_HOPPING_CK); -+err_muxes: -+ mt8901_afe_disable_main_clk_muxes(afe); -+ -+ return ret; - } - - int mt8901_afe_disable_main_clock(struct mtk_base_afe *afe) - { -- mt8901_afe_disable_afe_on(afe); -+ struct device *dev = afe->dev; -+ int ret; -+ int last_ret = 0; -+ -+ ret = mt8901_afe_disable_afe_on(afe); -+ if (ret) { -+ dev_err(dev, "disable_afe_on failed: %d\n", ret); -+ last_ret = ret; -+ } -+ -+ ret = mt8901_afe_disable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "disable_top_cg F26M failed: %d\n", ret); -+ last_ret = ret; -+ } -+ -+ ret = mt8901_afe_disable_top_cg(afe, AUD_CG_AUDIO_HOPPING_CK); -+ if (ret) { -+ dev_err(dev, "disable_top_cg HOPPING failed: %d\n", ret); -+ last_ret = ret; -+ } -+ -+ ret = mt8901_afe_disable_main_clk_muxes(afe); -+ if (ret) { -+ dev_err(dev, "disable_main_clk_muxes failed: %d\n", ret); -+ last_ret = ret; -+ } -+ -+ return last_ret; -+} -+ -+int mt8901_afe_enable_reg_rw_clk(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ true); -+ if (ret) { -+ dev_err(dev, "enable reg_rw_clk INTBUS failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+ true); -+ if (ret) { -+ dev_err(dev, "enable reg_rw_clk VADSP failed: %d\n", ret); -+ goto err_intbus; -+ } -+ -+ ret = mt8901_afe_enable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "enable_top_cg F26M failed: %d\n", ret); -+ goto err_vadsp; -+ } -+ - return 0; -+ -+err_vadsp: -+ mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, false); -+err_intbus: -+ mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ false); -+ -+ return ret; -+} -+ -+int mt8901_afe_disable_reg_rw_clk(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_disable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); -+ if (ret) { -+ dev_err(dev, "disable_top_cg F26M failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+ false); -+ if (ret) { -+ dev_err(dev, "disable reg_rw_clk VADSP failed: %d\n", ret); -+ goto err_f26m; -+ } -+ -+ ret = mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ false); -+ if (ret) { -+ dev_err(dev, "disable reg_rw_clk INTBUS failed: %d\n", ret); -+ goto err_vadsp; -+ } -+ -+ return 0; -+ -+err_vadsp: -+ mt8901_afe_clk_mux_req(dev, AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, true); -+err_f26m: -+ mt8901_afe_enable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); -+ -+ return ret; -+} -+ -+static int mt8901_afe_map_clk_parent(unsigned int mux, const char *parent_name, -+ unsigned int *level) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mt8901_clk_parent_map); i++) { -+ if (mt8901_clk_parent_map[i].mux == mux && -+ !strcmp(mt8901_clk_parent_map[i].parent_name, -+ parent_name)) { -+ *level = mt8901_clk_parent_map[i].level; -+ return 0; -+ } -+ } -+ -+ return -EINVAL; -+} -+ -+int mt8901_afe_set_clock_parent(struct mtk_base_afe *afe, unsigned int mux, -+ const char *parent_name) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ unsigned int parent_level; -+ -+ ret = mt8901_afe_map_clk_parent(mux, parent_name, &parent_level); -+ if (ret) { -+ dev_err(dev, "map_clock_parent mux=%u parent=%s failed %d\n", -+ mux, parent_name, ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_clk_set_parent_req(dev, mux, parent_level); -+ dev_dbg(dev, "set_clock_parent mux=%u parent=%u: %d\n", -+ mux, parent_level, ret); -+ -+ return ret; -+} -+ -+int mt8901_afe_set_idle_clock_parent(struct mtk_base_afe *afe, bool idle) -+{ -+ const char *parent_name; -+ int i, j, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(idle_clk_muxes); i++) { -+ parent_name = idle ? idle_clk_muxes[i].idle_parent_name : -+ idle_clk_muxes[i].active_parent_name; -+ -+ ret = mt8901_afe_set_clock_parent(afe, idle_clk_muxes[i].mux, -+ parent_name); -+ if (ret) -+ goto err_rollback; -+ } -+ -+ return 0; -+ -+err_rollback: -+ /* -+ * Best effort: re-parent the muxes already switched back to the -+ * other set, so a failed transition does not leave a mixed -+ * idle/active clock topology. -+ */ -+ for (j = i - 1; j >= 0; j--) { -+ parent_name = idle ? idle_clk_muxes[j].active_parent_name : -+ idle_clk_muxes[j].idle_parent_name; -+ mt8901_afe_set_clock_parent(afe, idle_clk_muxes[j].mux, -+ parent_name); -+ } -+ -+ return ret; - } -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-clk.h b/sound/soc/mediatek/mt8901/mt8901-afe-clk.h -index 6099dcd680..171d62aa02 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-afe-clk.h -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-clk.h -@@ -11,8 +11,170 @@ - #define _MT8901_AFE_CLK_H_ - - struct mtk_base_afe; -+struct device; - -+enum sspm_aud_cmd { -+ SSPM_AUD_CMD_MTCMOS = 0, -+ SSPM_AUD_CMD_CG, -+ SSPM_AUD_CMD_VLP_SYS_CLK_MUX, -+ SSPM_AUD_CMD_VLP_SYS_CLK_SET_RATE, -+ SSPM_AUD_CMD_VLP_SYS_CLK_SET_PARENT, -+ SSPM_AUD_CMD_AFE_SPM_CTRL, -+ SSPM_AUD_CMD_PWR_CTRL_SCENE, -+ SSPM_AUD_CMD_CLK_CG_DEINIT, -+ SSPM_AUD_CMD_NUM, -+}; -+ -+enum audio_mtcmos_pd_id { -+ AUDIO_VADSYS_PD_AO = 0, -+ AUDIO_VADSYS_PD_INFRA, -+ AUDIO_PD, -+ AUDIO_PD_NUM, -+}; -+ -+enum afe_pwr_scene { -+ AUDIO_PWR_SCEN_NORMAL = 0, -+ AUDIO_PWR_SCEN_BY_DSTATE, -+ AUDIO_PWR_SCEN_AON, -+ AUDIO_PWR_SCEN_NUM, -+}; -+ -+enum afe_spm_ctrl_req_type { -+ AFE_SPM_CTRL_VCORE_REQ = 0, -+ AFE_SPM_CTRL_PMIC_REQ, -+ AFE_SPM_CTRL_SRCCLKENA_REQ, -+ AFE_SPM_CTRL_APSRC_REQ, -+ AFE_SPM_CTRL_VRF18_REQ, -+ AFE_SPM_CTRL_INFRA_REQ, -+ AFE_SPM_CTRL_DDREN_REQ, -+ AFE_SPM_CTRL_REQ_NUMS, -+}; -+ -+enum audio_top_con_cg_type { -+ AUD_CG_ASD_BEGIN, -+ /* AUDIO_TOP_CON0 (0x0000) */ -+ AUD_CG_HW_GAIN01 = AUD_CG_ASD_BEGIN, -+ AUD_CG_HW_GAIN23, -+ AUD_CG_CM0, -+ AUD_CG_CM1, -+ AUD_CG_CM2, -+ /* AUDIO_TOP_CON1 (0x0004) */ -+ AUD_CG_HW_GAIN_DL0_DL1, -+ AUD_CG_HW_GAIN_DL2_DL3, -+ AUD_CG_HW_GAIN_DL4_DL5, -+ AUD_CG_HW_GAIN_DL24CH, -+ AUD_CG_UL0_ADC, -+ AUD_CG_UL0_TML, -+ AUD_CG_UL0_ADC_HIRES, -+ AUD_CG_UL0_ADC_HIRES_TML, -+ AUD_CG_UL1_ADC, -+ AUD_CG_UL1_TML, -+ AUD_CG_UL1_ADC_HIRES, -+ AUD_CG_UL1_ADC_HIRES_TML, -+ /* AUDIO_TOP_CON2 (0x0008) */ -+ AUD_CG_ETDM_OUT0, -+ AUD_CG_ETDM_OUT5, -+ AUD_CG_ETDM_IN0, -+ AUD_CG_ETDM_IN5, -+ /* AUDIO_TOP_CON3 (0x0008) */ -+ AUD_CG_GENERAL0_ASRC, -+ AUD_CG_GENERAL1_ASRC, -+ AUD_CG_GENERAL2_ASRC, -+ AUD_CG_GENERAL3_ASRC, -+ AUD_CG_GENERAL4_ASRC, -+ AUD_CG_GENERAL5_ASRC, -+ AUD_CG_GENERAL6_ASRC, -+ AUD_CG_GENERAL7_ASRC, -+ /* AUDIO_TOP_CON4 (0x0010) */ -+ AUD_CG_APLL_TUNER1, -+ AUD_CG_APLL_TUNER2, -+ AUD_CG_H208M_CK, -+ AUD_CG_APLL2_CK, -+ AUD_CG_APLL1_CK, -+ AUD_CG_SDW_BEGIN, -+ AUD_CG_AUDIO_F26M_CK = AUD_CG_SDW_BEGIN, -+ AUD_CG_AUDIO_HOPPING_CK, -+ AUD_CG_ASD_END = AUD_CG_AUDIO_HOPPING_CK, -+ /* AUDIO_TOP_CON5 (0x0070) - SoundWire (owned by dai-soundwire.c) */ -+ AUD_CG_SOUNDWIRE_DMIC0_ADC, -+ AUD_CG_SOUNDWIRE_DMIC0_TML, -+ AUD_CG_SOUNDWIRE_DMIC1_ADC, -+ AUD_CG_SOUNDWIRE_DMIC1_TML, -+ AUD_CG_SOUNDWIRE_DMIC2_ADC, -+ AUD_CG_SOUNDWIRE_DMIC2_TML, -+ AUD_CG_SOUNDWIRE_DMIC3_ADC, -+ AUD_CG_SOUNDWIRE_DMIC3_TML, -+ AUD_CG_SOUNDWIRE_DMIC4_ADC, -+ AUD_CG_SOUNDWIRE_DMIC4_TML, -+ AUD_CG_SOUNDWIRE_DMIC5_ADC, -+ AUD_CG_SOUNDWIRE_DMIC5_TML, -+ AUD_CG_SOUNDWIRE_DMIC6_ADC, -+ AUD_CG_SOUNDWIRE_DMIC6_TML, -+ AUD_CG_SOUNDWIRE_DMIC7_ADC, -+ AUD_CG_SOUNDWIRE_DMIC7_TML, -+ AUD_CG_SOUNDWIRE1, -+ AUD_CG_SOUNDWIRE0, -+ AUD_CG_SDW_END = AUD_CG_SOUNDWIRE0, -+ AUD_CG_NUMS, -+}; -+ -+enum afe_clk_mux_type { -+ AFE_CLK_VLP_CKSYS_TOP_AUDIO_H_SEL = 0, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_ENGEN2_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE0_PHY_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_SOUNDWIRE1_PHY_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_INTBUS_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_1_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_AUD_2_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_APLL_I2S1_MCK_SEL, -+ AFE_CLK_VLP_CKSYS_TOP_VADSP_SEL, -+ AFE_CLK_NUMS, -+}; -+ -+/* Clock parent names, per audio_clock_interface.h (SSPM firmware header) */ -+#define CLK_PARENT_TCX_26M_MX9_CK_NAME "tcx_26m_mx9_ck" -+#define CLK_PARENT_OSC_D20_NAME "osc_d20" -+#define CLK_PARENT_OSC_D12_NAME "osc_d12" -+#define CLK_PARENT_OSC_D10_NAME "osc_d10" -+#define CLK_PARENT_OSC_D6_NAME "osc_d6" -+#define CLK_PARENT_OSC_D5_NAME "osc_d5" -+#define CLK_PARENT_OSC_D2_NAME "osc_d2" -+#define CLK_PARENT_AD_OSC_NAME "ad_osc_ck" -+#define CLK_PARENT_APLL1_D2_NAME "apll1_d2" -+#define CLK_PARENT_APLL2_D2_NAME "apll2_d2" -+#define CLK_PARENT_APLL1_D8_NAME "apll1_d8" -+#define CLK_PARENT_APLL1_D4_NAME "apll1_d4" -+#define CLK_PARENT_APLL2_D8_NAME "apll2_d8" -+#define CLK_PARENT_APLL2_D4_NAME "apll2_d4" -+#define CLK_PARENT_APLL1_NAME "apll1" -+#define CLK_PARENT_APLL2_NAME "apll2" -+#define CLK_PARENT_MAINPLL2_D7_D4_NAME "mainpll2_d7_d4" -+#define CLK_PARENT_MAINPLL2_D4_D4_NAME "mainpll2_d4_d4" -+#define CLK_PARENT_UNIVPLL2_D4_NAME "univpll2_d4" -+#define CLK_PARENT_UNIVPLL2_D4_D2_NAME "univpll2_d4_d2" -+#define CLK_PARENT_ADSPPLL_NAME "adsppll_ck" -+#define CLK_PARENT_ADSPPLL_D2_NAME "adsppll_d2" -+ -+/* SSPM-managed clock/MTCMOS control (via power_wrap SCMI requests) */ -+int mt8901_afe_init_clock(struct mtk_base_afe *afe); -+int mt8901_afe_disable_default_on_clk_and_top_cg(struct mtk_base_afe *afe); -+int mt8901_afe_enable_top_cg(struct mtk_base_afe *afe, unsigned int cg); -+int mt8901_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg); -+int mt8901_afe_enable_mtcmos(struct mtk_base_afe *afe, unsigned int mtcmos); -+int mt8901_afe_disable_mtcmos(struct mtk_base_afe *afe, unsigned int mtcmos); -+int mt8901_afe_send_spm_req(struct mtk_base_afe *afe, unsigned int req, -+ bool enable); - int mt8901_afe_enable_main_clock(struct mtk_base_afe *afe); - int mt8901_afe_disable_main_clock(struct mtk_base_afe *afe); -+int mt8901_afe_enable_reg_rw_clk(struct mtk_base_afe *afe); -+int mt8901_afe_disable_reg_rw_clk(struct mtk_base_afe *afe); -+int mt8901_afe_set_clock_parent(struct mtk_base_afe *afe, -+ unsigned int mux, const char *parent_name); -+int mt8901_afe_enable_apll_top_con_cg(struct mtk_base_afe *afe); -+int mt8901_afe_disable_apll_top_con_cg(struct mtk_base_afe *afe); -+int mt8901_afe_set_idle_clock_parent(struct mtk_base_afe *afe, bool idle); - - #endif -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -index 72d4c34c1a..cff5a3e891 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -@@ -1917,12 +1917,32 @@ static int mt8901_afe_pcm_dev_probe(struct platform_device *pdev) - return ret; - } - -- /* always on clock */ -- mt8901_afe_enable_main_clock(afe); -+ ret = mt8901_afe_init_clock(afe); -+ if (ret) { -+ dev_err(dev, "afe init clock failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* ToDo: check if we need to enable clock here */ -+ ret = mt8901_afe_enable_main_clock(afe); -+ if (ret) { -+ dev_err(dev, "mt8901_afe_enable_main_clock failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_enable_apll_top_con_cg(afe); -+ if (ret) { -+ dev_err(dev, "mt8901_afe_enable_apll_top_con_cg failed: %d\n", -+ ret); -+ mt8901_afe_disable_main_clock(afe); -+ return ret; -+ } - - ret = mt8901_afe_init_regs(afe); - if (ret) { - dev_err(dev, "afe init regs failed: %d\n", ret); -+ mt8901_afe_disable_apll_top_con_cg(afe); -+ mt8901_afe_disable_main_clock(afe); - return ret; - } - -@@ -1938,6 +1958,7 @@ static int mt8901_afe_pcm_dev_probe(struct platform_device *pdev) - IRQF_ONESHOT, - "AFE_ISR_Handle", (void *)afe); - if (ret) { -+ mt8901_afe_disable_apll_top_con_cg(afe); - mt8901_afe_disable_main_clock(afe); - return dev_err_probe(dev, ret, - "could not request_irq for AFE_ISR_Handle\n"); -@@ -1947,8 +1968,11 @@ static int mt8901_afe_pcm_dev_probe(struct platform_device *pdev) - ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform, - afe->dai_drivers, - afe->num_dai_drivers); -- if (ret) -+ if (ret) { -+ mt8901_afe_disable_apll_top_con_cg(afe); -+ mt8901_afe_disable_main_clock(afe); - return dev_err_probe(dev, ret, "err_platform\n"); -+ } - - return 0; - } -From 06c0b7b84842cba5556d2a5319e0cd744aec4f61 Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:08 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: mt8901: add system sleep - support - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Add system sleep suspend/resume callbacks to the mt8901 ASoC platform -driver so the audio block releases its clock and MTCMOS power requests -across suspend and the platform can reach its deepest sleep state. The -SSPM firmware reference counts power domain requests, so per-module -requests are intentionally symmetric with the other operating system -supported on this platform. - -On resume, restore the AFE hardware state: reprogram the memory -interfaces, interconnect routing and interrupt state so streams can -restart after system suspend without reloading the driver. Partial -failures during either transition are unwound instead of resuming into -a half-suspended configuration. - -Probe establishes the runtime PM baseline before publishing the -component. Its initial put may leave the device active when another -usage reference is outstanding (user space forbidding runtime PM before -bind); the bypass resume only brought up MTCMOS and the register clock -and no later runtime get calls runtime_resume() on an active device, so -probe then brings up the rest of the datapath (main clock, APLL gates, -DDR request) itself, leaving the device in the state a full -runtime_resume() produces. On unbind a devres action, ordered after the -ASoC component and the interrupt are released and before runtime PM is -disabled, forces a runtime suspend so whatever probe or a runtime resume -left held is released regardless of that reference, with no users left -to touch powered-down hardware, and the PM status matches the hardware -for the next bind. - -Signed-off-by: Trevor Wu -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - sound/soc/mediatek/mt8901/mt8901-afe-clk.c | 47 +- - sound/soc/mediatek/mt8901/mt8901-afe-common.h | 4 + - sound/soc/mediatek/mt8901/mt8901-afe-pcm.c | 401 ++++++++++++++++-- - sound/soc/mediatek/mt8901/mt8901-reg.h | 2 + - 4 files changed, 413 insertions(+), 41 deletions(-) - -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-clk.c b/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -index bec45b7b66..9b4482c327 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-clk.c -@@ -344,11 +344,15 @@ int mt8901_afe_enable_apll_top_con_cg(struct mtk_base_afe *afe) - return ret; - } - -+/* -+ * The disable helpers are transactional: on failure they re-enable what they -+ * already released and return the error, so a caller's own unwind can assume -+ * the clocks are still in the state they were in before the call. -+ */ - int mt8901_afe_disable_apll_top_con_cg(struct mtk_base_afe *afe) - { - struct device *dev = afe->dev; - int i, ret; -- int last_ret = 0; - - for (i = ARRAY_SIZE(mt8901_apll_top_con_cgs) - 1; i >= 0; i--) { - ret = mt8901_afe_disable_top_cg(afe, -@@ -357,11 +361,17 @@ int mt8901_afe_disable_apll_top_con_cg(struct mtk_base_afe *afe) - dev_warn(dev, "disable_top_cg %s failed: %d\n", - mt8901_cg_names[mt8901_apll_top_con_cgs[i]], - ret); -- last_ret = ret; -+ goto err; - } - } - -- return last_ret; -+ return 0; -+ -+err: -+ while (++i < ARRAY_SIZE(mt8901_apll_top_con_cgs)) -+ mt8901_afe_enable_top_cg(afe, mt8901_apll_top_con_cgs[i]); -+ -+ return ret; - } - - int mt8901_afe_enable_mtcmos(struct mtk_base_afe *afe, unsigned int mtcmos) -@@ -429,7 +439,6 @@ static int mt8901_afe_disable_main_clk_muxes(struct mtk_base_afe *afe) - { - struct device *dev = afe->dev; - int i, ret; -- int last_ret = 0; - - for (i = 0; i < ARRAY_SIZE(mt8901_main_clk_muxes); i++) { - ret = mt8901_afe_clk_mux_req(dev, mt8901_main_clk_muxes[i], -@@ -438,11 +447,17 @@ static int mt8901_afe_disable_main_clk_muxes(struct mtk_base_afe *afe) - if (ret) { - dev_warn(dev, "disable main_clk mux[%d] failed: %d\n", - i, ret); -- last_ret = ret; -+ goto err; - } - } - -- return last_ret; -+ return 0; -+ -+err: -+ while (i-- > 0) -+ mt8901_afe_clk_mux_req(dev, mt8901_main_clk_muxes[i], true); -+ -+ return ret; - } - - int mt8901_afe_enable_main_clock(struct mtk_base_afe *afe) -@@ -490,33 +505,41 @@ int mt8901_afe_disable_main_clock(struct mtk_base_afe *afe) - { - struct device *dev = afe->dev; - int ret; -- int last_ret = 0; - - ret = mt8901_afe_disable_afe_on(afe); - if (ret) { - dev_err(dev, "disable_afe_on failed: %d\n", ret); -- last_ret = ret; -+ return ret; - } - - ret = mt8901_afe_disable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); - if (ret) { - dev_err(dev, "disable_top_cg F26M failed: %d\n", ret); -- last_ret = ret; -+ goto err_afe_on; - } - - ret = mt8901_afe_disable_top_cg(afe, AUD_CG_AUDIO_HOPPING_CK); - if (ret) { - dev_err(dev, "disable_top_cg HOPPING failed: %d\n", ret); -- last_ret = ret; -+ goto err_f26m; - } - - ret = mt8901_afe_disable_main_clk_muxes(afe); - if (ret) { - dev_err(dev, "disable_main_clk_muxes failed: %d\n", ret); -- last_ret = ret; -+ goto err_hopping; - } - -- return last_ret; -+ return 0; -+ -+err_hopping: -+ mt8901_afe_enable_top_cg(afe, AUD_CG_AUDIO_HOPPING_CK); -+err_f26m: -+ mt8901_afe_enable_top_cg(afe, AUD_CG_AUDIO_F26M_CK); -+err_afe_on: -+ mt8901_afe_enable_afe_on(afe); -+ -+ return ret; - } - - int mt8901_afe_enable_reg_rw_clk(struct mtk_base_afe *afe) -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-common.h b/sound/soc/mediatek/mt8901/mt8901-afe-common.h -index 975059dcdb..2a81d387cd 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-afe-common.h -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-common.h -@@ -78,6 +78,10 @@ struct mtk_dai_memif_irq_priv { - struct mt8901_afe_private { - u32 hw_ver; /* acpi-asd-hw-ver from _DSD */ - struct mtk_dai_memif_irq_priv irq_priv[MT8901_AFE_IRQ_NUM]; -+ int pm_runtime_bypass_reg_ctl; -+ bool default_mtcmos_vote_dropped; -+ /* Set at the end of a successful probe: devres teardown owns runtime PM. */ -+ bool pm_teardown_armed; - - /* dai */ - void *dai_priv[MT8901_DAI_NUM]; -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -index cff5a3e891..82f42478ef 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include "mt8901-afe-common.h" - #include "mt8901-afe-clk.h" -@@ -1684,7 +1685,12 @@ static bool mt8901_is_volatile_reg(struct device *dev, unsigned int reg) - case AFE_GASRC11_NEW_IP_VERSION: - return true; - default: -- return false; -+ /* SoundWire registers are controlled by another driver */ -+ if (reg >= AFE_SOUNDWIRE_REG_BEGIN && -+ reg < AFE_SOUNDWIRE_REG_END) -+ return true; -+ else -+ return false; - }; - } - -@@ -1824,11 +1830,233 @@ static int mt8901_afe_init_regs(struct mtk_base_afe *afe) - init_regs, ARRAY_SIZE(init_regs)); - } - -+/* -+ * The audio datapath resources that sit on top of the register-access -+ * baseline (MTCMOS and the register clock): the main clock, the APLL top -+ * clock gates and the DDR request the memory interfaces need. Brought up by -+ * runtime_resume() once the regmap is live, and by probe when its initial -+ * put leaves the device runtime active, so that an active device is always -+ * in the state a full runtime_resume() produces and runtime_suspend() tears -+ * down exactly that. -+ */ -+static int mt8901_afe_datapath_on(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_enable_main_clock(afe); -+ if (ret) { -+ dev_err(dev, "mt8901_afe_enable_main_clock failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_enable_apll_top_con_cg(afe); -+ if (ret) { -+ dev_err(dev, "mt8901_afe_enable_apll_top_con_cg failed: %d\n", -+ ret); -+ goto err_apll; -+ } -+ -+ /* request DDR for memif */ -+ ret = mt8901_afe_send_spm_req(afe, AFE_SPM_CTRL_DDREN_REQ, true); -+ if (ret) { -+ dev_err(dev, "mt8901_afe_send_spm_req enable failed: %d\n", -+ ret); -+ goto err_spm; -+ } -+ -+ return 0; -+ -+err_spm: -+ mt8901_afe_disable_apll_top_con_cg(afe); -+err_apll: -+ mt8901_afe_disable_main_clock(afe); -+ -+ return ret; -+} -+ -+static int mt8901_afe_datapath_off(struct mtk_base_afe *afe) -+{ -+ struct device *dev = afe->dev; -+ int ret; -+ -+ ret = mt8901_afe_send_spm_req(afe, AFE_SPM_CTRL_DDREN_REQ, false); -+ if (ret) { -+ dev_warn(dev, -+ "mt8901_afe_send_spm_req disable failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = mt8901_afe_disable_apll_top_con_cg(afe); -+ if (ret) { -+ dev_warn(dev, "mt8901_afe_disable_apll_top_con_cg failed: %d\n", -+ ret); -+ goto err_apll; -+ } -+ -+ ret = mt8901_afe_disable_main_clock(afe); -+ if (ret) { -+ dev_warn(dev, "mt8901_afe_disable_main_clock failed: %d\n", -+ ret); -+ goto err_main; -+ } -+ -+ return 0; -+ -+err_main: -+ mt8901_afe_enable_apll_top_con_cg(afe); -+err_apll: -+ mt8901_afe_send_spm_req(afe, AFE_SPM_CTRL_DDREN_REQ, true); -+ -+ return ret; -+} -+ -+static int mt8901_afe_runtime_suspend(struct device *dev) -+{ -+ struct mtk_base_afe *afe = dev_get_drvdata(dev); -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ int ret; -+ bool skip = false; -+ -+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) { -+ skip = true; -+ goto skip_regmap; -+ } -+ -+ ret = mt8901_afe_datapath_off(afe); -+ if (ret) -+ return ret; -+ -+ regcache_cache_only(afe->regmap, true); -+ regcache_mark_dirty(afe->regmap); -+ -+skip_regmap: -+ ret = mt8901_afe_disable_reg_rw_clk(afe); -+ if (ret) { -+ dev_warn(dev, "mt8901_afe_disable_reg_rw_clk failed: %d\n", -+ ret); -+ goto err_reg; -+ } -+ -+ ret = mt8901_afe_disable_mtcmos(afe, AUDIO_PD); -+ if (ret) { -+ dev_warn(dev, "disable MTCMOS failed\n"); -+ goto err_mtcmos; -+ } -+ -+ return 0; -+err_mtcmos: -+ mt8901_afe_enable_reg_rw_clk(afe); -+err_reg: -+ if (skip) -+ return ret; -+ regcache_cache_only(afe->regmap, false); -+ mt8901_afe_datapath_on(afe); -+ -+ return ret; -+} -+ -+static int mt8901_afe_runtime_resume(struct device *dev) -+{ -+ struct mtk_base_afe *afe = dev_get_drvdata(dev); -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ int ret; -+ -+ ret = mt8901_afe_enable_mtcmos(afe, AUDIO_PD); -+ if (ret) { -+ dev_err(dev, "enable MTCMOS failed\n"); -+ return ret; -+ } -+ -+ ret = mt8901_afe_enable_reg_rw_clk(afe); -+ if (ret) { -+ dev_err(dev, "mt8901_afe_enable_reg_rw_clk failed: %d\n", ret); -+ goto err_reg; -+ } -+ -+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) -+ return 0; -+ -+ regcache_cache_only(afe->regmap, false); -+ ret = regcache_sync(afe->regmap); -+ if (ret) { -+ dev_err(dev, "regcache_sync failed: %d", ret); -+ goto err_main; -+ } -+ -+ ret = mt8901_afe_datapath_on(afe); -+ if (ret) -+ goto err_main; -+ -+ return 0; -+ -+err_main: -+ regcache_cache_only(afe->regmap, true); -+ regcache_mark_dirty(afe->regmap); -+ -+ mt8901_afe_disable_reg_rw_clk(afe); -+err_reg: -+ mt8901_afe_disable_mtcmos(afe, AUDIO_PD); -+ -+ return ret; -+} -+ -+/* -+ * Release what the bypass runtime resume took (MTCMOS and the register -+ * access clock) on a probe failure exit that leaves the device runtime -+ * active: the devres pm_runtime_disable() never runs runtime_suspend(). -+ */ -+static void mt8901_afe_release_bypass_resources(struct mtk_base_afe *afe) -+{ -+ mt8901_afe_disable_reg_rw_clk(afe); -+ mt8901_afe_disable_mtcmos(afe, AUDIO_PD); -+} -+ -+/* -+ * Devres action, ordered after the ASoC component and the IRQ are released -+ * and before the runtime PM disable registered at the start of probe. -+ * -+ * An outstanding usage reference (user space forbidding runtime PM, for -+ * instance) keeps the device active through the driver core's put around -+ * remove, and the devres runtime PM disable never runs the suspend callback. -+ * With no ASoC users and no IRQ left, force the suspend so everything probe -+ * or a runtime resume left held (MTCMOS, register clock, datapath) is -+ * released and the PM status matches the hardware for the next bind, then -+ * re-enable so the devres disable registered by probe stays balanced. Only -+ * acts once probe has completed: the probe failure exits release what they -+ * took by hand. -+ */ -+static void mt8901_afe_pm_teardown(void *data) -+{ -+ struct mtk_base_afe *afe = data; -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ struct device *dev = afe->dev; -+ int ret; -+ -+ if (!afe_priv->pm_teardown_armed) -+ return; -+ -+ ret = pm_runtime_force_suspend(dev); -+ if (ret) { -+ /* -+ * The PM core re-enabled runtime PM on this failure and the -+ * callback unwound what it had changed, so hardware and PM -+ * status still agree (both active). Nothing else can be -+ * released safely; say so. -+ */ -+ dev_warn(dev, "runtime force suspend failed: %d, device left active\n", -+ ret); -+ return; -+ } -+ pm_runtime_enable(dev); -+} -+ - static int mt8901_afe_pcm_dev_probe(struct platform_device *pdev) - { - struct mtk_base_afe *afe; - struct mt8901_afe_private *afe_priv; - struct device *dev = &pdev->dev; -+ bool runtime_active = false; - int i, irq_id, ret; - - ret = dma_set_mask_and_coherent(dev, -@@ -1910,40 +2138,32 @@ static int mt8901_afe_pcm_dev_probe(struct platform_device *pdev) - - dev_info(dev, "acpi-asd-hw-ver = %u\n", afe_priv->hw_ver); - -- afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, -- &mt8901_afe_regmap_config); -- if (IS_ERR(afe->regmap)) { -- ret = PTR_ERR(afe->regmap); -- return ret; -- } -- - ret = mt8901_afe_init_clock(afe); - if (ret) { - dev_err(dev, "afe init clock failed: %d\n", ret); - return ret; - } - -- /* ToDo: check if we need to enable clock here */ -- ret = mt8901_afe_enable_main_clock(afe); -- if (ret) { -- dev_err(dev, "mt8901_afe_enable_main_clock failed: %d\n", ret); -+ ret = devm_pm_runtime_enable(dev); -+ if (ret) - return ret; -- } - -- ret = mt8901_afe_enable_apll_top_con_cg(afe); -- if (ret) { -- dev_err(dev, "mt8901_afe_enable_apll_top_con_cg failed: %d\n", -- ret); -- mt8901_afe_disable_main_clock(afe); -- return ret; -+ afe_priv->pm_runtime_bypass_reg_ctl = true; -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to resume device\n"); -+ -+ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, -+ &mt8901_afe_regmap_config); -+ if (IS_ERR(afe->regmap)) { -+ ret = PTR_ERR(afe->regmap); -+ goto err_pm_put; - } - - ret = mt8901_afe_init_regs(afe); - if (ret) { - dev_err(dev, "afe init regs failed: %d\n", ret); -- mt8901_afe_disable_apll_top_con_cg(afe); -- mt8901_afe_disable_main_clock(afe); -- return ret; -+ goto err_pm_put; - } - - /* -@@ -1953,28 +2173,143 @@ static int mt8901_afe_pcm_dev_probe(struct platform_device *pdev) - * state asserted, so an earlier request can fire into a half-set-up - * driver. - */ -+ /* -+ * Registered after the regmap and before the IRQ and the component, -+ * so at devres release it runs once the component and the IRQ are -+ * gone and while the regmap still exists: see mt8901_afe_pm_teardown(). -+ */ -+ ret = devm_add_action_or_reset(dev, mt8901_afe_pm_teardown, afe); -+ if (ret) -+ goto err_pm_put; -+ - ret = devm_request_threaded_irq(dev, irq_id, NULL, - mt8901_afe_irq_handler, - IRQF_ONESHOT, - "AFE_ISR_Handle", (void *)afe); - if (ret) { -- mt8901_afe_disable_apll_top_con_cg(afe); -- mt8901_afe_disable_main_clock(afe); -- return dev_err_probe(dev, ret, -- "could not request_irq for AFE_ISR_Handle\n"); -+ dev_err_probe(dev, ret, -+ "could not request_irq for AFE_ISR_Handle\n"); -+ goto err_pm_put; - } - -- /* register component after regcache is in cache-only mode */ -+ ret = pm_runtime_put_sync(dev); -+ afe_priv->pm_runtime_bypass_reg_ctl = false; -+ if (ret < 0 && ret != -EAGAIN && ret != -EBUSY) { -+ /* -+ * The PM core latches a callback error in runtime_error and -+ * refuses every later runtime get, so the component would be -+ * unusable. Probe-failure devres disables runtime PM without -+ * running the suspend callback, so release what the bypass -+ * resume took (MTCMOS and the register-access clock) here. -+ */ -+ dev_err_probe(dev, ret, "initial runtime suspend failed\n"); -+ mt8901_afe_release_bypass_resources(afe); -+ return ret; -+ } -+ /* -+ * A zero return does not prove the suspend callback ran: with -+ * another usage reference outstanding (user space forbidding -+ * runtime PM before probe, for instance) the put only drops the -+ * count and the device stays active, exactly as on a transient -+ * -EAGAIN/-EBUSY refusal. Decide on the PM status, not on the -+ * return value: the regcache may go cache-only only once the -+ * hardware is actually suspended, and every probe failure exit -+ * that leaves the device active must release the bypass resources -+ * by hand. An active device suspends later through the regular -+ * runtime_suspend(), which switches the regcache itself. -+ */ -+ runtime_active = !pm_runtime_status_suspended(dev); -+ if (runtime_active) { -+ dev_warn(dev, "initial runtime suspend deferred (%d), device left active\n", -+ ret); -+ /* -+ * The bypass resume brought up only MTCMOS and the register -+ * clock, and the next runtime get will find an active device -+ * and not call runtime_resume(): bring up the rest of the -+ * datapath here so the device is in the state a full -+ * runtime_resume() leaves it in, and the runtime_suspend() -+ * that runs once the outstanding reference is dropped tears -+ * down exactly that. -+ */ -+ ret = mt8901_afe_datapath_on(afe); -+ if (ret) { -+ mt8901_afe_release_bypass_resources(afe); -+ return dev_err_probe(dev, ret, -+ "datapath bring-up on the active device failed\n"); -+ } -+ } else { -+ regcache_cache_only(afe->regmap, true); -+ regcache_mark_dirty(afe->regmap); -+ } -+ -+ /* -+ * Drop the firmware's default-on MTCMOS vote. Safe on the transient -+ * path too: the runtime vote keeps the domain powered while the -+ * device is active. Track it so remove() restores only a vote that -+ * was actually dropped. -+ */ -+ ret = mt8901_afe_disable_mtcmos(afe, AUDIO_PD); -+ if (ret) -+ dev_warn(dev, "disable MTCMOS failed: %d\n", ret); -+ else -+ afe_priv->default_mtcmos_vote_dropped = true; -+ -+ /* Publish the component only once the PM baseline is established. */ - ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform, - afe->dai_drivers, - afe->num_dai_drivers); - if (ret) { -- mt8901_afe_disable_apll_top_con_cg(afe); -- mt8901_afe_disable_main_clock(afe); -+ if (afe_priv->default_mtcmos_vote_dropped) -+ mt8901_afe_enable_mtcmos(afe, AUDIO_PD); -+ if (runtime_active) { -+ mt8901_afe_datapath_off(afe); -+ mt8901_afe_release_bypass_resources(afe); -+ } - return dev_err_probe(dev, ret, "err_platform\n"); - } - -+ /* From here on the devres teardown owns the runtime PM balance. */ -+ afe_priv->pm_teardown_armed = true; -+ - return 0; -+ -+err_pm_put: -+ /* -+ * Bypass mode is still set here, so a put that suspends releases -+ * the MTCMOS and register clock through runtime_suspend. Whenever -+ * the device is still active afterwards (a refused put, a callback -+ * failure that unwound itself, or another usage reference keeping -+ * it up) both are still held: release them by hand. -+ */ -+ pm_runtime_put_sync(dev); -+ if (!pm_runtime_status_suspended(dev)) -+ mt8901_afe_release_bypass_resources(afe); -+ -+ return ret; -+} -+ -+static void mt8901_afe_pcm_dev_remove(struct platform_device *pdev) -+{ -+ struct mtk_base_afe *afe = platform_get_drvdata(pdev); -+ struct mt8901_afe_private *afe_priv = afe->platform_priv; -+ struct device *dev = &pdev->dev; -+ int ret; -+ -+ /* -+ * The runtime PM balance is restored by mt8901_afe_pm_teardown() at -+ * devres release, after the component and the IRQ are gone. Only the -+ * firmware's default MTCMOS vote is handled here. -+ * -+ * Undo the default-vote drop at the end of probe, which accounts for -+ * MTCMOS defaulting to on before any driver has ever run, but only if -+ * probe actually managed to drop it. -+ */ -+ if (!afe_priv->default_mtcmos_vote_dropped) -+ return; -+ -+ ret = mt8901_afe_enable_mtcmos(afe, AUDIO_PD); -+ if (ret) -+ dev_warn(dev, "enable MTCMOS failed: %d\n", ret); - } - - /* ACPI match: ASD0 device in Audio.asl (_HID = "NVDA9022") */ -@@ -1984,12 +2319,20 @@ static const struct acpi_device_id mt8901_afe_acpi_match[] = { - }; - MODULE_DEVICE_TABLE(acpi, mt8901_afe_acpi_match); - -+static const struct dev_pm_ops mt8901_afe_pm_ops = { -+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) -+ RUNTIME_PM_OPS(mt8901_afe_runtime_suspend, -+ mt8901_afe_runtime_resume, NULL) -+}; -+ - static struct platform_driver mt8901_afe_pcm_driver = { - .driver = { - .name = "mt8901-audio", - .acpi_match_table = ACPI_PTR(mt8901_afe_acpi_match), -+ .pm = &mt8901_afe_pm_ops, - }, - .probe = mt8901_afe_pcm_dev_probe, -+ .remove = mt8901_afe_pcm_dev_remove, - }; - - module_platform_driver(mt8901_afe_pcm_driver); -diff --git a/sound/soc/mediatek/mt8901/mt8901-reg.h b/sound/soc/mediatek/mt8901/mt8901-reg.h -index 70ff5f0a55..4dcec1bfff 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-reg.h -+++ b/sound/soc/mediatek/mt8901/mt8901-reg.h -@@ -1574,6 +1574,8 @@ - #define AFE_GASRC11_NEW_CON13 (0x7b34) - #define AFE_GASRC11_NEW_CON14 (0x7b38) - #define AFE_GASRC11_NEW_IP_VERSION (0x7b3c) -+#define AFE_SOUNDWIRE_REG_BEGIN (0x9000) -+#define AFE_SOUNDWIRE_REG_END (0x9600) - #define AFE_GAIN_DL0_CON0 (0x9800) - #define AFE_GAIN_DL0_CON1_R (0x9804) - #define AFE_GAIN_DL0_CON1_L (0x9808) -From c13c7fb0f7a98b19a2a90085f645a1c605a7ac00 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add 4x CS35L56 + CS42L43 - machine entry - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -The machine table only described one Realtek layout (RT1320 x2 on link0 -plus RT712 on link1), so on boards with the dual-link Cirrus topology no -machine matches and no sound card is created. Add that layout: four -CS35L56 amps on link0 (unique IDs 0x30-0x33, aggregated into one speaker -group) and a CS42L43 jack codec on link1 (unique ID 0x30), with the -endpoint shapes used by the upstream AMD and Intel entries for the same -codec combination. - -_ADR values taken from the platform firmware ACPI dump. The -speaker-position-to-unique-ID mapping is assumed in ID order and will be -confirmed on hardware. The cs42l43 endpoint list carries only the jack -and mic endpoints; the sidecar speaker endpoint is omitted since these -boards use separate SoundWire amps. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-mach.c | 114 ++++++++++++++++++++++ - sound/soc/mediatek/Kconfig | 4 + - 2 files changed, 118 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.c b/drivers/soundwire/mediatek/mtk-sdw-mach.c -index 582482b43e..f452445358 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-mach.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.c -@@ -81,12 +81,126 @@ static const struct snd_soc_acpi_link_adr mtk_sdw_rt1320_l0_rt712_l1[] = { - {} - }; - -+/* -+ * Config 1: SDW0 = 4x CS35L56 (amps, aggregated), SDW1 = CS42L43 (jack codec). -+ * Topology: uids 0x30-0x33 on link0, 0x30 on -+ * link1. Speaker position vs uid mapping to be confirmed on hardware; the -+ * group positions below assume uid order. -+ */ -+static const struct snd_soc_acpi_endpoint cs35l56_endpoints[] = { -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 0, -+ .group_id = 1, -+ }, -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 1, -+ .group_id = 1, -+ }, -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 2, -+ .group_id = 1, -+ }, -+ { -+ .num = 0, -+ .aggregated = 1, -+ .group_position = 3, -+ .group_id = 1, -+ }, -+}; -+ -+static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { -+ { /* Jack Playback Endpoint */ -+ .num = 0, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+ { /* DMIC Capture Endpoint */ -+ .num = 1, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+ { /* Jack Capture Endpoint */ -+ .num = 2, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+}; -+ -+static const struct snd_soc_acpi_adr_device cs35l56x4_l0_adr[] = { -+ { -+ .adr = 0x00003001FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[0], -+ .name_prefix = "AMP1", -+ }, -+ { -+ .adr = 0x00003101FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[1], -+ .name_prefix = "AMP2", -+ }, -+ { -+ .adr = 0x00003201FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[2], -+ .name_prefix = "AMP3", -+ }, -+ { -+ .adr = 0x00003301FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[3], -+ .name_prefix = "AMP4", -+ }, -+}; -+ -+static const struct snd_soc_acpi_adr_device cs42l43_l1_adr[] = { -+ { -+ .adr = 0x00013001FA424301ull, -+ /* -+ * The cs42l43 Speaker Playback endpoint (num 3, the sidecar-amp -+ * path) is intentionally not in cs42l43_endpoints: on these -+ * boards the speaker amps are separate SoundWire peripherals. -+ */ -+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), -+ .endpoints = cs42l43_endpoints, -+ .name_prefix = "cs42l43", -+ }, -+}; -+ -+static const struct snd_soc_acpi_link_adr mtk_sdw_cs35l56_l0_cs42l43_l1[] = { -+ { -+ .mask = BIT(0), -+ .num_adr = ARRAY_SIZE(cs35l56x4_l0_adr), -+ .adr_d = cs35l56x4_l0_adr, -+ }, -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(cs42l43_l1_adr), -+ .adr_d = cs42l43_l1_adr, -+ }, -+ {} -+}; -+ - static struct snd_soc_acpi_mach mtk_sdw_machines[] = { - { - .link_mask = BIT(0) | BIT(1), - .links = mtk_sdw_rt1320_l0_rt712_l1, - .drv_name = "mtk_sdw_mc", - }, -+ { -+ .link_mask = BIT(0) | BIT(1), -+ .links = mtk_sdw_cs35l56_l0_cs42l43_l1, -+ .drv_name = "mtk_sdw_mc", -+ }, - {} - }; - -diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig -index 8d1f97d682..83197c6868 100644 ---- a/sound/soc/mediatek/Kconfig -+++ b/sound/soc/mediatek/Kconfig -@@ -422,6 +422,10 @@ config SND_SOC_MT8901_LEGACY_SDW_MACH - select SND_SOC_RT712_SDCA_SDW - select SND_SOC_RT712_SDCA_DMIC_SDW - select SND_SOC_RT1320_SDW -+ select SND_SOC_CS35L56_SDW -+ select MFD_CS42L43_SDW -+ select SND_SOC_CS42L43 -+ select SND_SOC_CS42L43_SDW - help - This adds support for Legacy(No DSP) sound card for MediaTek - MT8901 boards. -From f76d579af12041877bcc208895433b88ff89945e Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add 2x RT1321 + RT713 - machine entry - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Boards with this Realtek layout enumerate 2x RT1321 (unique IDs 0x30/ -0x31) on link0 and an RT713 on link1. The existing Realtek entry matches -the reference board parts (RT1320 at unique IDs 0x30/0x32, RT712), -so these boards enumerated but never registered a card. Add the -combination with the _ADR values from the platform firmware. RT1321 and -RT713 are already handled by the rt1320-sdw and rt712-sdca codec drivers -and are present in the sdw_utils codec_info_list. - -RT713 needs its own endpoint list {0, 1} (jack DAI 0, DMIC DAI 1 per the -sdw_utils codec info for part 0x713); reusing the RT712 endpoints {0, 2} -fails because the RT712 DMIC sits at index 2 behind the amp DAI. The -name prefixes follow the driver family so existing control names are -unchanged. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-mach.c | 70 +++++++++++++++++++++++ - 1 file changed, 70 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.c b/drivers/soundwire/mediatek/mtk-sdw-mach.c -index f452445358..ba6f0e5063 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-mach.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.c -@@ -190,12 +190,82 @@ static const struct snd_soc_acpi_link_adr mtk_sdw_cs35l56_l0_cs42l43_l1[] = { - {} - }; - -+/* -+ * Config 2: SDW0 = 2x RT1321 (amps, aggregated), SDW1 = RT713 (jack codec). -+ * Topology: uids 0x30/0x31 on link0, 0x30 -+ * on link1. RT1321/RT713 are handled by the rt1320-sdw/rt712-sdca drivers; -+ * name prefixes follow the driver family so the control names match the -+ * RT1320/RT712 configuration. -+ */ -+static const struct snd_soc_acpi_adr_device rt1321_l0_adr[] = { -+ { -+ .adr = 0x000030025D132101ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[0], -+ .name_prefix = "rt1320-1", -+ }, -+ { -+ .adr = 0x000031025D132101ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[1], -+ .name_prefix = "rt1320-2", -+ }, -+}; -+ -+/* -+ * RT713 exposes two DAIs (0 = jack, 1 = DMIC), unlike RT712 whose DMIC -+ * DAI sits at index 2 behind the amp DAI, so it needs its own endpoint -+ * list rather than reusing rt712_endpoints. -+ */ -+static const struct snd_soc_acpi_endpoint rt713_endpoints[] = { -+ { -+ .num = 0, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+ { -+ .num = 1, -+ .aggregated = 0, -+ .group_position = 0, -+ .group_id = 0, -+ }, -+}; -+ -+static const struct snd_soc_acpi_adr_device rt713_l1_adr[] = { -+ { -+ .adr = 0x000130025D071301ull, -+ .num_endpoints = ARRAY_SIZE(rt713_endpoints), -+ .endpoints = rt713_endpoints, -+ .name_prefix = "rt713", -+ }, -+}; -+ -+static const struct snd_soc_acpi_link_adr mtk_sdw_rt1321_l0_rt713_l1[] = { -+ { -+ .mask = BIT(0), -+ .num_adr = ARRAY_SIZE(rt1321_l0_adr), -+ .adr_d = rt1321_l0_adr, -+ }, -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(rt713_l1_adr), -+ .adr_d = rt713_l1_adr, -+ }, -+ {} -+}; -+ - static struct snd_soc_acpi_mach mtk_sdw_machines[] = { - { - .link_mask = BIT(0) | BIT(1), - .links = mtk_sdw_rt1320_l0_rt712_l1, - .drv_name = "mtk_sdw_mc", - }, -+ { -+ .link_mask = BIT(0) | BIT(1), -+ .links = mtk_sdw_rt1321_l0_rt713_l1, -+ .drv_name = "mtk_sdw_mc", -+ }, - { - .link_mask = BIT(0) | BIT(1), - .links = mtk_sdw_cs35l56_l0_cs42l43_l1, -From faa348093d4ba0a1803332621f0c6e4f23a60bfd Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add pin bias - configuration - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -The SoundWire pads need bus-keeper bias configuration; without it -codec enumeration fails unless the pads are configured by hand. -Program the pin bias from ACPI resources during link initialization. - -The vendor pin configuration values carried by the PinFunction() -descriptors (0x90 plain pull-down, 0xF0 bus-keeper) are a SoundWire -pad convention, so they are defined by this driver; the pinctrl side -only exports the generic bias helper and its pull modes. The helper -returns -EPROBE_DEFER until a pinctrl instance has registered, which -defers the probe here since the bias is required for enumeration, and --ENODEV for a pin no registered controller covers, which is a firmware -error and fails the probe instead of retrying forever. - -Depends on the MediaTek pinctrl bus-keeper support (submitted -separately). - -Signed-off-by: Trevor Wu -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/Kconfig | 1 + - drivers/soundwire/mediatek/mtk-sdw.c | 92 ++++++++++++++++++++++++++++ - drivers/soundwire/mediatek/mtk-sdw.h | 14 +++++ - 3 files changed, 107 insertions(+) - -diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig -index 38b8835b3c..b60324144a 100644 ---- a/drivers/soundwire/Kconfig -+++ b/drivers/soundwire/Kconfig -@@ -62,6 +62,7 @@ config SOUNDWIRE_MTK - select SOUNDWIRE_GENERIC_ALLOCATION - depends on SND_SOC && ACPI - depends on MTK_POWER_WRAP -+ depends on PINCTRL_MT8901 - select SND_SOC_ACPI - select SOUNDWIRE_MTK_MT8901_CLK - help -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index 5aebe75612..05d240e087 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -22,6 +23,93 @@ - #include "mtk-sdw-mach.h" - #include "mtk-sdw-top.h" - -+static acpi_status mtk_sdw_apply_pin_bias_cb(struct acpi_resource *res, -+ void *context) -+{ -+ struct mtk_sdw_acpi_cb_context *ctx = context; -+ struct device *dev = ctx->dev; -+ struct acpi_resource_pin_function *pf; -+ u32 pullup; -+ int i, err; -+ -+ if (res->type != ACPI_RESOURCE_TYPE_PIN_FUNCTION) -+ return AE_OK; -+ -+ pf = &res->data.pin_function; -+ -+ switch (pf->pin_config) { -+ case MTK_SDW_PIN_CFG_BUS_HOLD: -+ pullup = MTK_PIN_BUS_HOLD; -+ break; -+ case MTK_SDW_PIN_CFG_PD: -+ pullup = MTK_PIN_PULLDOWN; -+ break; -+ default: -+ dev_dbg(dev, -+ "SDW _CRS PinFunction pin_cfg=0x%02x - leaving default bias\n", -+ pf->pin_config); -+ return AE_OK; -+ } -+ -+ for (i = 0; i < pf->pin_table_length; i++) { -+ unsigned int pin = pf->pin_table[i]; -+ -+ err = mtk_pinctrl_program_bias_by_gpio(pin, pullup, -+ MTK_PIN_ENABLE); -+ if (err == -EPROBE_DEFER) { -+ /* -+ * No pinctrl instance has registered yet: the MT8901 -+ * pinctrl this driver depends on has not probed. The -+ * bias is required for enumeration, so retry later. -+ * -ENODEV, by contrast, means no controller covers the -+ * pin at all, which is a firmware error that a retry -+ * cannot fix, so it fails the probe below. -+ */ -+ ctx->err = -EPROBE_DEFER; -+ return AE_CTRL_TERMINATE; -+ } else if (err) { -+ dev_err(dev, -+ "SDW pin %u: bias program failed (pin_cfg=0x%02x, err=%d)\n", -+ pin, pf->pin_config, err); -+ ctx->err = err; -+ return AE_CTRL_TERMINATE; -+ } -+ -+ dev_dbg(dev, "SDW pin %u: pin_cfg=0x%02x -> pullup=%u applied\n", -+ pin, pf->pin_config, pullup); -+ } -+ -+ return AE_OK; -+} -+ -+static int mtk_sdw_apply_pin_config(struct device *dev) -+{ -+ acpi_handle handle = ACPI_HANDLE(dev); -+ acpi_status status; -+ struct mtk_sdw_acpi_cb_context ctx = { -+ .dev = dev, -+ .err = 0, -+ }; -+ -+ if (!handle) { -+ dev_info(dev, "No ACPI handle\n"); -+ return 0; -+ } -+ -+ /* pin bias */ -+ status = acpi_walk_resources(handle, METHOD_NAME__CRS, -+ mtk_sdw_apply_pin_bias_cb, &ctx); -+ -+ if (ACPI_FAILURE(status)) { -+ dev_warn(dev, -+ "SDW _CRS walk failed (0x%x) - pin bias not programmed from DSDT\n", -+ status); -+ return -EIO; -+ } -+ -+ return ctx.err; -+} -+ - static int mtk_sdw_parse_dp_allocation(struct mtk_sdw *mst, int idx) - { - struct mtk_sdw_link *link = &mst->links[idx]; -@@ -888,6 +976,10 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - if (!mst) - return -ENOMEM; - -+ ret = mtk_sdw_apply_pin_config(dev); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to apply pin bias\n"); -+ - mtk_init_sdw_master(mst); - - mst->dev = dev; -diff --git a/drivers/soundwire/mediatek/mtk-sdw.h b/drivers/soundwire/mediatek/mtk-sdw.h -index 2c91eb609b..e1d687a867 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.h -+++ b/drivers/soundwire/mediatek/mtk-sdw.h -@@ -82,4 +82,18 @@ enum mt8901_afe_fs_mode { - #define MTK_SDW_MAX_DAIS \ - ((MTK_SDW_DP_SOURCE_NUM) + (MTK_SDW_DP_SINK_NUM)) /* BRA not included */ - -+/* -+ * Vendor pin configuration values carried by the ACPI PinFunction() -+ * descriptors of the SoundWire pads: -+ * 0x90: PD=1, PU=0 (plain pull-down) -+ * 0xF0: PD=1, PU=1 (bus-keeper) -+ */ -+#define MTK_SDW_PIN_CFG_PD 0x90 -+#define MTK_SDW_PIN_CFG_BUS_HOLD 0xF0 -+ -+struct mtk_sdw_acpi_cb_context { -+ struct device *dev; -+ int err; -+}; -+ - #endif /* __MTK_SDW_H */ -From da79e1e94b4699a2691b0f331c8986d24bc4c168 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: mt8901: do not advertise - S32_LE - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -The AFE data path is 24-bit internally. S16 and S24 (24 valid bits in a -32-bit container) play clean on hardware, but true 32-bit memif mode -produces heavily distorted output regardless of the HD mode and align -settings (board verified: S16 clean, S24 clean, S32 badly distorted on -the same route). The reference driver for this silicon only uses the -16 and 24-bit memif modes. - -This matters for the default desktop experience: with S32 advertised, -PipeWire negotiates it by preference and out-of-the-box playback is -audibly degraded. Dropping it makes PipeWire pick S24, full quality, -with no userspace format pinning needed. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw.c | 4 ++-- - sound/soc/mediatek/mt8901/mt8901-afe-pcm.c | 13 +++++++++---- - 2 files changed, 11 insertions(+), 6 deletions(-) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index 05d240e087..f1b6794836 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -807,9 +807,9 @@ static int mtk_sdw_init_dai(struct mtk_sdw *mst, struct snd_soc_dai_driver *drv, - stream->channels_max = 8; - stream->rates = SNDRV_PCM_RATE_48000; - stream->rates = SNDRV_PCM_RATE_8000_384000; -+ /* S32 dropped: the AFE path is 24-bit internally, see MTK_PCM_FORMATS */ - stream->formats = SNDRV_PCM_FMTBIT_S16_LE | -- SNDRV_PCM_FMTBIT_S24_LE | -- SNDRV_PCM_FMTBIT_S32_LE; -+ SNDRV_PCM_FMTBIT_S24_LE; - - stream->stream_name = drv->name; - -diff --git a/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -index 82f42478ef..eaf6c54d12 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -+++ b/sound/soc/mediatek/mt8901/mt8901-afe-pcm.c -@@ -48,9 +48,15 @@ - SNDRV_PCM_RATE_352800 |\ - SNDRV_PCM_RATE_384000) - -+/* -+ * The AFE data path is 24-bit internally: S16 and S24 (24 valid bits in -+ * a 32-bit container) play clean, but true 32-bit memif mode produces -+ * distorted output on hardware regardless of the HD/align settings, so -+ * S32 is deliberately not offered (matches the reference driver, which -+ * only uses the 16/24-bit memif modes). -+ */ - #define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ -- SNDRV_PCM_FMTBIT_S24_LE |\ -- SNDRV_PCM_FMTBIT_S32_LE) -+ SNDRV_PCM_FMTBIT_S24_LE) - - struct mtk_dai_memif_priv { - unsigned int fs_timing; -@@ -65,8 +71,7 @@ static const struct snd_pcm_hardware mt8901_afe_hardware = { - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - .formats = SNDRV_PCM_FMTBIT_S16_LE | -- SNDRV_PCM_FMTBIT_S24_LE | -- SNDRV_PCM_FMTBIT_S32_LE, -+ SNDRV_PCM_FMTBIT_S24_LE, - .period_bytes_min = 64, - .period_bytes_max = 256 * 1024, - .periods_min = 2, -From 3db8c6164ef93f22b39dbd35910e91d722ea53ba Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: fix lost slave status - interrupts - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Two defects combined to permanently lose peripheral attach transitions -after initial enumeration: - -1) The interrupt handler scheduled the slave status work before masking - the slave interrupt. The work re-enables that interrupt when it - completes, so a work that ran to completion on another CPU before the - handler's mask landed left the slave interrupt masked forever; every - subsequent attach or detach transition on the link was invisible to - the manager. Dense links (five peripherals) lose this race reliably - during the enumeration interrupt storm. Mask first, then schedule. - -2) A peripheral that soft-resets after enumeration (the cs42l43 jack - codec does this during driver probe) drops to Dev0 and takes tens of - ms to re-sync before it can ACK a device number write. The status - work polls Dev0 in a tight loop bounded by SDW_MAX_DEVICES - iterations, which completes well inside that window: the device - number writes are ignored (-61) and the attach is dropped. Convert - the work to a delayed work that re-schedules itself (20 ms period, - bounded at 25 attempts) while Dev0 remains attached. - -Observed on a five-peripheral single-link topology where the cs42l43 -probe reset consistently left the codec UNATTACHED and the card at --EPROBE_DEFER. The reference stack never exercises either path because -it does not reset codecs after enumeration. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-core.c | 47 +++++++++++++++++++++-- - drivers/soundwire/mediatek/mtk-sdw-core.h | 3 +- - 2 files changed, 45 insertions(+), 5 deletions(-) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index c730c88d3b..0ae2f5728d 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -546,7 +546,7 @@ void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) - core->interrupt_enabled = enable; - - if (!enable) -- cancel_work_sync(&core->work); -+ cancel_delayed_work_sync(&core->work); - - core_updatel(core, MCP_INTMASK, MCP_INT_IRQ, - enable ? MCP_INT_IRQ : 0); -@@ -628,10 +628,23 @@ static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, - return 0; - } - -+/* -+ * A peripheral that soft-resets after enumeration (the cs42l43 does this -+ * during driver probe) drops to Dev0 and takes tens of ms to re-sync -+ * before it can ACK a new device number. The poll loop below exhausts its -+ * retries well inside that window, and the IP raises no further attach -+ * transition for a device already sitting at Dev0, so without a re-poll -+ * the attach is lost and the peripheral stays UNATTACHED forever. The -+ * reference driver never hits this (its codec stack does not reset after -+ * enumeration). -+ */ -+#define MTK_SDW_DEV0_REPOLL_MAX 25 -+#define MTK_SDW_DEV0_REPOLL_DELAY_MS 20 -+ - static void mtk_sdw_slave_status_work(struct work_struct *work) - { - struct mtk_sdw_core *core = -- container_of(work, struct mtk_sdw_core, work); -+ container_of(work, struct mtk_sdw_core, work.work); - u32 stat0; - u32 stat1; - u32 dev0_stat; -@@ -666,6 +679,24 @@ static void mtk_sdw_slave_status_work(struct work_struct *work) - - } while (retries++ < SDW_MAX_DEVICES); - -+ if (dev0_stat == MCP_SLAVESTAT_ATTACHED && -+ core->interrupt_enabled) { -+ if (core->dev0_repoll_count++ < MTK_SDW_DEV0_REPOLL_MAX) { -+ dev_dbg(core->dev, -+ "[%u] Dev0 still attached, re-polling (%u)\n", -+ core->bus.link_id, core->dev0_repoll_count); -+ schedule_delayed_work(&core->work, -+ msecs_to_jiffies(MTK_SDW_DEV0_REPOLL_DELAY_MS)); -+ } else { -+ dev_warn(core->dev, -+ "[%u] Dev0 attach unresolved after %u re-polls, giving up\n", -+ core->bus.link_id, core->dev0_repoll_count); -+ core->dev0_repoll_count = 0; -+ } -+ } else { -+ core->dev0_repoll_count = 0; -+ } -+ - mtk_sdw_enable_slave_irq(core, true); - } - -@@ -728,7 +759,7 @@ int mtk_sdw_core_init(struct mtk_sdw_core *core) - core->bus.port_ops = &mtk_sdw_core_port_ops; - core->bus.compute_params = mtk_sdw_compute_params; - -- INIT_WORK(&core->work, mtk_sdw_slave_status_work); -+ INIT_DELAYED_WORK(&core->work, mtk_sdw_slave_status_work); - return 0; - } - -@@ -795,8 +826,16 @@ irqreturn_t mtk_sdw_core_irq(int irq, void *data) - bus->link_id, intstat); - } - if (core->interrupt_enabled) { -- schedule_work(&core->work); -+ /* -+ * Mask before scheduling: the work re-enables the -+ * slave interrupt when it finishes, so masking after -+ * schedule_delayed_work() races a work that completes -+ * on another CPU first and leaves the interrupt -+ * masked forever (all subsequent attach/detach -+ * transitions are then lost). -+ */ - mtk_sdw_enable_slave_irq(core, false); -+ schedule_delayed_work(&core->work, 0); - clearstat &= ~MCP_INT_SLV_MASK; - } - } -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.h b/drivers/soundwire/mediatek/mtk-sdw-core.h -index 4708a10865..563db268d0 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.h -@@ -189,7 +189,8 @@ struct mtk_sdw_core { - bool interrupt_enabled; - u16 attached_slaves; - void *priv; -- struct work_struct work; -+ struct delayed_work work; -+ unsigned int dev0_repoll_count; - }; - - struct mtk_sdw_pdi_params { -From 126b8809aa7c278fa3800d915f9499956790662e Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: verify Dev0 DevId reads - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -A peripheral still re-synchronizing at Dev0 (or several colliding -there) ACKs DevId reads while returning corrupted bytes. The bus core -trusts a single read, so a corrupted ID registers a phantom peripheral -that consumes a device number while the real device stays orphaned; -observed on a five-peripheral link as dozens of phantom entries with -bit-mixed IDs (part 0x0043 from a 0x4243 device, class 0 from class 1 -peripherals) and the jack codec enumerated under a mangled identity -its driver never matches. - -Run the Dev0 DevId read as two complete sequential 0x50..0x55 passes -and report the command ignored on mismatch so the core retries the -attach later, once the peripheral answers stably. The passes must be -complete and in-order: peripherals track the sequential DevId read to -commit arbitration, so per-byte repeat reads leave them uncommitted -and they then ignore the device number write. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-core.c | 59 +++++++++++++++++++++++ - 1 file changed, 59 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index 0ae2f5728d..41611e97ce 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -125,6 +125,44 @@ static int mtk_core_prep_msg(struct mtk_sdw_core *core, struct sdw_msg *msg) - * sdw_master_ops - * ======================================================================= - */ -+static enum sdw_command_response -+mtk_sdw_do_xfer_msg(struct mtk_sdw_core *core, struct sdw_msg *msg, u8 *buf) -+{ -+ int i, ret = 0; -+ -+ for (i = 0; i < msg->len; i++) { -+ u32 cmd = FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | -+ FIELD_PREP(MCP_CMD_REG_ADDR, msg->addr + i) | -+ FIELD_PREP(MCP_CMD_SSP_TAG, msg->ssp_sync); -+ -+ cmd |= FIELD_PREP(MCP_CMD_FIELD, MCP_CMD_READ); -+ ret = core_send_cmd(core, cmd, &buf[i]); -+ if (ret) -+ break; -+ } -+ -+ return ret; -+} -+ -+/* -+ * A peripheral that is still re-synchronizing at Dev0 (or several -+ * peripherals colliding there) can return corrupted DevId bytes while -+ * still ACKing the read. The bus core trusts a single read, so a -+ * corrupted ID creates a phantom peripheral that consumes a device -+ * number while the real device stays orphaned. Run the whole DevId -+ * read twice as two complete sequential 0x50..0x55 passes (per-byte -+ * repeat reads would break the peripheral's enumeration commit -+ * tracking) and report the command ignored on mismatch; the core -+ * retries on the next attach pass, by which point the peripheral is -+ * stable. -+ */ -+static bool mtk_sdw_is_dev0_devid_msg(struct sdw_msg *msg) -+{ -+ return msg->dev_num == 0 && msg->flags == SDW_MSG_FLAG_READ && -+ msg->addr == SDW_SCP_DEVID_0 && -+ msg->addr + msg->len - 1 == SDW_SCP_DEVID_5; -+} -+ - static enum sdw_command_response - mtk_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) - { -@@ -135,6 +173,27 @@ mtk_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) - if (ret) - return SDW_CMD_FAIL_OTHER; - -+ if (mtk_sdw_is_dev0_devid_msg(msg)) { -+ u8 verify[SDW_SCP_DEVID_5 - SDW_SCP_DEVID_0 + 1] = {0}; -+ -+ ret = mtk_sdw_do_xfer_msg(core, msg, msg->buf); -+ if (ret) -+ return ret; -+ -+ ret = mtk_sdw_do_xfer_msg(core, msg, verify); -+ if (ret) -+ return ret; -+ -+ if (memcmp(msg->buf, verify, msg->len)) { -+ dev_dbg(core->dev, -+ "Dev0 DevId unstable (%*ph / %*ph), deferring\n", -+ msg->len, msg->buf, msg->len, verify); -+ return SDW_CMD_IGNORED; -+ } -+ -+ return SDW_CMD_OK; -+ } -+ - for (i = 0; i < msg->len; i++) { - u32 cmd = FIELD_PREP(MCP_CMD_DEV_ADDR, msg->dev_num) | - FIELD_PREP(MCP_CMD_REG_ADDR, msg->addr + i) | -From 7d2a5d50e26d04a7f479bd12b9dda0caf6871c50 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: pace Dev0 enumeration - rounds - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Two peripherals answering a Dev0 DevId read while one of them is still -regaining frame sync produce deterministic wire-mixed responses (the -misaligned straggler corrupts the synced responder's bits the same way -every round), so read-and-verify cannot filter them and the bus core -enumerates phantom identities. The status work currently burns all its -enumeration rounds within ~50 ms, entirely inside the straggler's -re-sync window. - -Sleep 30 ms between rounds while Dev0 reports attached so a straggler -reaches frame sync before the next DevId read, at which point both -peripherals arbitrate correctly and enumerate under their real -identities. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-core.c | 55 +++++++++++++++++++++++ - 1 file changed, 55 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index 41611e97ce..2de426cb4e 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -7,6 +7,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -184,6 +185,19 @@ mtk_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) - if (ret) - return ret; - -+ /* -+ * The status work cleared the Dev0 attach latch and saw it -+ * stay quiet before handing over to the bus core. A new -+ * arrival since then latches it again and may have mixed -+ * into both passes identically; discard this pass. -+ */ -+ if (core_readl(core, MCP_SLAVEINTSTAT0) & -+ MCP_SLAVEINTSTAT_ATTACHED) { -+ dev_dbg(core->dev, -+ "Dev0 attach changed during DevId read, deferring\n"); -+ return SDW_CMD_IGNORED; -+ } -+ - if (memcmp(msg->buf, verify, msg->len)) { - dev_dbg(core->dev, - "Dev0 DevId unstable (%*ph / %*ph), deferring\n", -@@ -699,6 +713,8 @@ static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, - */ - #define MTK_SDW_DEV0_REPOLL_MAX 25 - #define MTK_SDW_DEV0_REPOLL_DELAY_MS 20 -+#define MTK_SDW_DEV0_SETTLE_MS 30 -+#define MTK_SDW_DEV0_SETTLE_ROUNDS 4 - - static void mtk_sdw_slave_status_work(struct work_struct *work) - { -@@ -708,6 +724,8 @@ static void mtk_sdw_slave_status_work(struct work_struct *work) - u32 stat1; - u32 dev0_stat; - int retries = 0; -+ unsigned int n; -+ bool settled; - u64 slv_intstat; - - core_writel(core, MCP_INTSTAT, MCP_INT_SLV_MASK); -@@ -723,6 +741,43 @@ static void mtk_sdw_slave_status_work(struct work_struct *work) - slv_intstat = ((u64)stat1 << 32) | stat0; - - do { -+ /* -+ * Pace the enumeration rounds. A peripheral that just -+ * dropped to Dev0 (soft reset, late power-up) needs time to -+ * regain frame sync; reading DevId while it drives misaligned -+ * data corrupts the response of any synced peripheral -+ * answering in the same round, and the corruption is -+ * deterministic (wire-mixed), so re-reads cannot filter it. -+ * The wait must precede every round including the first, or -+ * the straggler is enumerated from its mixed response. A -+ * peripheral arriving at Dev0 during the wait latches a new -+ * attach transition for Dev0; give it a full interval too, -+ * bounded so a flapping device cannot stall the work. -+ */ -+ settled = true; -+ for (n = 0; core_get_slave_status(core, 0) == MCP_SLAVESTAT_ATTACHED; -+ n++) { -+ if (n == MTK_SDW_DEV0_SETTLE_ROUNDS) { -+ /* The last interval latched again: not settled. */ -+ settled = false; -+ break; -+ } -+ core_writel(core, MCP_SLAVEINTSTAT0, -+ MCP_SLAVEINTSTAT_ATTACHED); -+ msleep(MTK_SDW_DEV0_SETTLE_MS); -+ if (!(core_readl(core, MCP_SLAVEINTSTAT0) & -+ MCP_SLAVEINTSTAT_ATTACHED)) -+ break; -+ } -+ -+ if (!settled) { -+ dev_dbg(core->dev, -+ "[%u] Dev0 attach still changing after %u rounds, deferring enumeration\n", -+ core->bus.link_id, MTK_SDW_DEV0_SETTLE_ROUNDS); -+ dev0_stat = MCP_SLAVESTAT_ATTACHED; -+ break; -+ } -+ - mtk_sdw_update_slave_status(core, slv_intstat); - - dev0_stat = core_get_slave_status(core, 0); -From 6e4e55ee1609be19417d6ebf10fb46d0b5c588b3 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add bus reset recovery - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -The command reset issued once during hw_init is the only path that -brings every peripheral to Dev0 simultaneously for a clean group -enumeration; a link that fails enumeration (peripherals stuck -contending at Dev0, or carrying stale state from a previous OS run -across a warm reboot) currently has no way back to that state and -stays wedged until the next cold boot. - -Re-issue the command reset when the Dev0 re-poll gives up, bounded at -three attempts per episode, and re-kick the status work after a settle -delay. Also expose the reset manually via debugfs -(echo > mtk-sdw/bus_reset) for testing, and reject Dev0 DevId -reads that return all-zeros or all-ones (bus-keeper-held lines read -back stably but nothing real is driving). - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-common.h | 1 + - drivers/soundwire/mediatek/mtk-sdw-core.c | 108 +++++++++++++- - drivers/soundwire/mediatek/mtk-sdw-core.h | 13 +- - drivers/soundwire/mediatek/mtk-sdw.c | 149 ++++++++++++++++++++ - 4 files changed, 263 insertions(+), 8 deletions(-) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-common.h b/drivers/soundwire/mediatek/mtk-sdw-common.h -index 98efbe550d..cb012764c5 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-common.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-common.h -@@ -72,6 +72,7 @@ int mtk_sdw_clk_ops_select(struct mtk_sdw *mst, int hw_ver); - - struct mtk_sdw { - struct device *dev; -+ struct dentry *debugfs; - void __iomem *base; /* full AFE MMIO */ - struct mtk_sdw_link links[MTK_SDW_CONTROLLE_NUM]; - int num_links; -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index 2de426cb4e..336a99cc48 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -205,6 +205,18 @@ mtk_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) - return SDW_CMD_IGNORED; - } - -+ /* -+ * All-zeros / all-ones reads back stably (bus keepers hold -+ * the lines) but is not a DevId; nothing real was driving. -+ */ -+ if (memchr_inv(msg->buf, 0x00, msg->len) == NULL || -+ memchr_inv(msg->buf, 0xff, msg->len) == NULL) { -+ dev_dbg(core->dev, -+ "Dev0 DevId reads as keeper-held %02x, deferring\n", -+ msg->buf[0]); -+ return SDW_CMD_IGNORED; -+ } -+ - return SDW_CMD_OK; - } - -@@ -581,6 +593,69 @@ static int mtk_init_control_setting(struct mtk_sdw_core *core) - return mtk_do_config_update(core); - } - -+/* -+ * Re-issue the command reset that hw_init performs once at cold boot: -+ * every peripheral drops to Dev0 and re-synchronizes together, which is -+ * the one enumeration scenario known to work reliably. Used as recovery -+ * when the link is wedged (peripherals stuck contending at Dev0, or -+ * carrying stale state across a warm reboot). -+ */ -+/* -+ * Reference driver restart choreography: soft-reset -+ * the IP and drop to the quiesce operation mode (clock held LOW, data -+ * released, bus keepers holding) in one config update, dwell so the -+ * peripherals see a defined quiet bus, then run the full hw re-init which -+ * ends by switching back to normal mode - the clock restarts cleanly into -+ * the new frame configuration and peripherals re-synchronize from a known -+ * state. Re-initializing while the bus keeps running in normal mode (the -+ * previous behaviour) leaves peripherals unable to regain frame sync. -+ */ -+int mtk_sdw_core_bus_reset(struct mtk_sdw_core *core) -+{ -+ int ret; -+ -+ dev_info(core->dev, "[%u] bus restart (soft reset + quiesce)\n", -+ core->bus.link_id); -+ -+ /* -+ * Hold the bus message lock so the reset cannot overlap an -+ * sdw_transfer() issued by a peripheral driver on another CPU. -+ */ -+ mutex_lock(&core->bus.msg_lock); -+ -+ core->dev0_repoll_count = 0; -+ -+ core_updatel(core, MCP_CONTROL, MCP_CONTROL_SOFT_RST, -+ MCP_CONTROL_SOFT_RST); -+ core_updatel(core, MCP_CONFIG, MCP_CONFIG_OP_MODE, -+ FIELD_PREP(MCP_CONFIG_OP_MODE, -+ MCP_OP_MODE_CLK_LOW_DATA_OFF_KEEPER_ON)); -+ ret = mtk_do_config_update(core); -+ if (ret) -+ goto out; -+ -+ msleep(20); -+ -+ ret = mtk_sdw_core_hw_init(core); -+ if (ret) -+ goto out; -+ -+ /* -+ * SOFT_RST clears the per-device slave interrupt masks. Callers that -+ * quiesced interrupts around the reset get them back from their -+ * enable_irq(true); the status work cannot use that helper (it would -+ * cancel itself), so restore the masks here when interrupts are live. -+ */ -+ if (core->interrupt_enabled) { -+ core_writel(core, MCP_SLAVEINTMASK0, MCP_SLAVE_INTMASK0_MASK); -+ core_writel(core, MCP_SLAVEINTMASK1, MCP_SLAVE_INTMASK1_MASK); -+ } -+ -+out: -+ mutex_unlock(&core->bus.msg_lock); -+ return ret; -+} -+ - static int mtk_init_config_setting(struct mtk_sdw_core *core) - { - u32 val; -@@ -619,7 +694,7 @@ void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) - core->interrupt_enabled = enable; - - if (!enable) -- cancel_delayed_work_sync(&core->work); -+ cancel_delayed_work_sync(&core->status_work); - - core_updatel(core, MCP_INTMASK, MCP_INT_IRQ, - enable ? MCP_INT_IRQ : 0); -@@ -715,11 +790,13 @@ static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, - #define MTK_SDW_DEV0_REPOLL_DELAY_MS 20 - #define MTK_SDW_DEV0_SETTLE_MS 30 - #define MTK_SDW_DEV0_SETTLE_ROUNDS 4 -+#define MTK_SDW_BUS_RESET_MAX 3 -+#define MTK_SDW_BUS_RESET_SETTLE_MS 100 - - static void mtk_sdw_slave_status_work(struct work_struct *work) - { - struct mtk_sdw_core *core = -- container_of(work, struct mtk_sdw_core, work.work); -+ container_of(work, struct mtk_sdw_core, status_work.work); - u32 stat0; - u32 stat1; - u32 dev0_stat; -@@ -799,16 +876,32 @@ static void mtk_sdw_slave_status_work(struct work_struct *work) - dev_dbg(core->dev, - "[%u] Dev0 still attached, re-polling (%u)\n", - core->bus.link_id, core->dev0_repoll_count); -- schedule_delayed_work(&core->work, -+ schedule_delayed_work(&core->status_work, - msecs_to_jiffies(MTK_SDW_DEV0_REPOLL_DELAY_MS)); -+ } else if (core->bus_reset_count < MTK_SDW_BUS_RESET_MAX) { -+ core->bus_reset_count++; -+ dev_warn(core->dev, -+ "[%u] Dev0 attach unresolved after %u re-polls, bus reset %u/%u\n", -+ core->bus.link_id, core->dev0_repoll_count, -+ core->bus_reset_count, MTK_SDW_BUS_RESET_MAX); -+ core->dev0_repoll_count = 0; -+ if (mtk_sdw_core_bus_reset(core)) -+ dev_err(core->dev, -+ "[%u] bus reset failed, not re-polling\n", -+ core->bus.link_id); -+ else -+ schedule_delayed_work(&core->status_work, -+ msecs_to_jiffies(MTK_SDW_BUS_RESET_SETTLE_MS)); - } else { - dev_warn(core->dev, -- "[%u] Dev0 attach unresolved after %u re-polls, giving up\n", -- core->bus.link_id, core->dev0_repoll_count); -+ "[%u] Dev0 attach unresolved after %u re-polls and %u bus resets, giving up\n", -+ core->bus.link_id, core->dev0_repoll_count, -+ core->bus_reset_count); - core->dev0_repoll_count = 0; - } - } else { - core->dev0_repoll_count = 0; -+ core->bus_reset_count = 0; - } - - mtk_sdw_enable_slave_irq(core, true); -@@ -872,8 +965,9 @@ int mtk_sdw_core_init(struct mtk_sdw_core *core) - core->bus.ops = &mtk_sdw_core_ops; - core->bus.port_ops = &mtk_sdw_core_port_ops; - core->bus.compute_params = mtk_sdw_compute_params; -+ mutex_init(&core->reset_lock); - -- INIT_DELAYED_WORK(&core->work, mtk_sdw_slave_status_work); -+ INIT_DELAYED_WORK(&core->status_work, mtk_sdw_slave_status_work); - return 0; - } - -@@ -949,7 +1043,7 @@ irqreturn_t mtk_sdw_core_irq(int irq, void *data) - * transitions are then lost). - */ - mtk_sdw_enable_slave_irq(core, false); -- schedule_delayed_work(&core->work, 0); -+ schedule_delayed_work(&core->status_work, 0); - clearstat &= ~MCP_INT_SLV_MASK; - } - } -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.h b/drivers/soundwire/mediatek/mtk-sdw-core.h -index 563db268d0..7cd8a2389c 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.h -@@ -76,6 +76,7 @@ - #define MCP_CONFIG_OP_MODE GENMASK(2, 0) - #define MCP_CONFIG_MCR GENMASK(27, 24) - #define MCP_OP_MODE_NORMAL 0 -+#define MCP_OP_MODE_CLK_LOW_DATA_OFF_KEEPER_ON 5 - - /* MCP_CONTROL */ - #define MCP_CONTROL_CMD_ACCEPT_MODE BIT(1) -@@ -184,13 +185,22 @@ - struct mtk_sdw_core { - struct sdw_bus bus; - struct device *dev; -+ /* -+ * reset_lock: serializes every quiesce -> reset (or clock cycle) -+ * -> restore sequence on the link so one sequence cannot re-enable -+ * interrupt processing in the middle of another. The status work's -+ * own recovery reset does not take it: every holder quiesces that -+ * work first (enable_irq(false) cancels it synchronously). -+ */ -+ struct mutex reset_lock; - void __iomem *regs; - unsigned int curr_clk_freq; - bool interrupt_enabled; - u16 attached_slaves; - void *priv; -- struct delayed_work work; -+ struct delayed_work status_work; - unsigned int dev0_repoll_count; -+ unsigned int bus_reset_count; - }; - - struct mtk_sdw_pdi_params { -@@ -219,6 +229,7 @@ extern const struct sdw_master_port_ops mtk_sdw_core_port_ops; - - int mtk_sdw_core_init(struct mtk_sdw_core *core); - int mtk_sdw_core_hw_init(struct mtk_sdw_core *core); -+int mtk_sdw_core_bus_reset(struct mtk_sdw_core *core); - void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable); - void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable); - irqreturn_t mtk_sdw_core_irq(int irq, void *data); -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index f1b6794836..ddb8b13726 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -8,6 +8,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -963,6 +964,151 @@ static int mtk_sdw_register_machine(struct mtk_sdw *mst) - return 0; - } - -+/* -+ * Deep reset: gate the link clock so the peripherals lose sync entirely -+ * and reset their bus interface state machines, then re-init the core. -+ * Closest commanded equivalent to a power cycle. Caller holds -+ * core->reset_lock. -+ */ -+static int mtk_sdw_deep_reset(struct mtk_sdw *mst, unsigned int link) -+{ -+ struct mtk_sdw_core *core = &mst->links[link].core; -+ int ret; -+ -+ dev_info(mst->dev, "IP%u: deep reset (clock cycle)\n", link); -+ -+ /* -+ * Zero the recovery counters only after enable_irq(false) has -+ * cancelled the status work; a still-running work could write -+ * them back otherwise. -+ */ -+ mtk_sdw_enable_irq(core, false); -+ core->bus_reset_count = 0; -+ core->dev0_repoll_count = 0; -+ -+ /* -+ * Hold the bus message lock across the whole clock cycle so -+ * no sdw_transfer() or standard reset touches the unclocked -+ * controller, and restore interrupts only once the link clock -+ * is known to be back on (enable_irq writes controller -+ * registers). -+ */ -+ mutex_lock(&core->bus.msg_lock); -+ -+ ret = mtk_sdw_disable_top_clock(mst, link); -+ if (ret) -+ goto err_unlock_reenable; -+ -+ msleep(200); -+ -+ ret = mtk_sdw_enable_top_clock(mst, link); -+ if (ret) { -+ mutex_unlock(&core->bus.msg_lock); -+ dev_err(mst->dev, -+ "IP%u: link clock off after failed deep reset, interrupts left disabled\n", -+ link); -+ return ret; -+ } -+ -+ ret = mtk_sdw_core_hw_init(core); -+ mutex_unlock(&core->bus.msg_lock); -+ -+ mtk_sdw_enable_irq(core, true); -+ if (ret) -+ return ret; -+ -+ schedule_delayed_work(&core->status_work, msecs_to_jiffies(100)); -+ -+ return 0; -+ -+err_unlock_reenable: -+ mutex_unlock(&core->bus.msg_lock); -+ mtk_sdw_enable_irq(core, true); -+ return ret; -+} -+ -+/* -+ * Standard reset: re-issue the cold-boot command reset (all peripherals -+ * drop to Dev0 and re-enumerate together) and kick the status work. -+ * Caller holds core->reset_lock. -+ */ -+static int mtk_sdw_standard_reset(struct mtk_sdw *mst, unsigned int link) -+{ -+ struct mtk_sdw_core *core = &mst->links[link].core; -+ int ret; -+ -+ /* -+ * Quiesce interrupt handling and the status work (enable_irq(false) -+ * cancels it) so the reset does not race concurrent register access. -+ * Zero the recovery counters only after the cancellation, so a -+ * still-running work cannot write them back. -+ */ -+ mtk_sdw_enable_irq(core, false); -+ core->bus_reset_count = 0; -+ ret = mtk_sdw_core_bus_reset(core); -+ mtk_sdw_enable_irq(core, true); -+ if (ret) -+ return ret; -+ -+ schedule_delayed_work(&core->status_work, msecs_to_jiffies(100)); -+ -+ return 0; -+} -+ -+/* -+ * debugfs: echo > .../bus_reset re-issues the cold-boot -+ * command reset on that link; echo 10 + runs the deep -+ * (clock cycle) reset instead. Debug/recovery aid for links wedged by -+ * failed enumeration. -+ */ -+static ssize_t mtk_sdw_bus_reset_write(struct file *file, -+ const char __user *ubuf, -+ size_t count, loff_t *ppos) -+{ -+ struct mtk_sdw *mst = file->private_data; -+ struct mtk_sdw_core *core; -+ unsigned int link; -+ bool deep; -+ int ret; -+ -+ ret = kstrtouint_from_user(ubuf, count, 0, &link); -+ if (ret) -+ return ret; -+ -+ deep = link >= 10; -+ if (deep) -+ link -= 10; -+ if (link >= mst->num_links) -+ return -EINVAL; -+ -+ core = &mst->links[link].core; -+ -+ /* -+ * One quiesce -> reset -> restore sequence at a time per link: the -+ * other initiators of this choreography run under the same lock, so -+ * none of them can re-enable interrupt processing while another is -+ * halfway through its reset. -+ */ -+ mutex_lock(&core->reset_lock); -+ ret = deep ? mtk_sdw_deep_reset(mst, link) : -+ mtk_sdw_standard_reset(mst, link); -+ mutex_unlock(&core->reset_lock); -+ -+ return ret ? ret : count; -+} -+ -+static const struct file_operations mtk_sdw_bus_reset_fops = { -+ .open = simple_open, -+ .write = mtk_sdw_bus_reset_write, -+}; -+ -+static void mtk_sdw_debugfs_init(struct mtk_sdw *mst) -+{ -+ mst->debugfs = debugfs_create_dir(dev_name(mst->dev), NULL); -+ debugfs_create_file("bus_reset", 0200, mst->debugfs, mst, -+ &mtk_sdw_bus_reset_fops); -+} -+ - static int mtk_sdw_probe_controller(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -1129,6 +1275,8 @@ static int mtk_sdw_probe(struct platform_device *pdev) - return ret; - } - -+ mtk_sdw_debugfs_init(mst); -+ - return 0; - } - -@@ -1137,6 +1285,7 @@ static void mtk_sdw_remove(struct platform_device *pdev) - struct mtk_sdw *mst = platform_get_drvdata(pdev); - int i; - -+ debugfs_remove_recursive(mst->debugfs); - if (mst->mach_dev) - platform_device_unregister(mst->mach_dev); - for (i = mst->num_links - 1; i >= 0; i--) -From c753b89f2be729fad8a66a98d64ad317ff9b7ec9 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add a diagnostic - quarantine knob - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -An electrically faulty peripheral that asserts Alert permanently drags -the bus core into an endless alert-read retry storm (every interrupt -register read fails parity) and the traffic from the misbehaving -responder disturbs enumeration of the healthy peripherals sharing the -link. Add quarantine_uid: report the matching 0x3556 peripheral as -plainly attached so its alerts are never serviced, allowing the rest of -the link to enumerate and be validated. Diagnostic aid for a bad unit, -default off. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-core.c | 39 +++++++++++++++++++++-- - 1 file changed, 37 insertions(+), 2 deletions(-) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index 336a99cc48..25fd979f0c 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -709,6 +709,39 @@ void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable) - /* - * slave IRQ handling - */ -+/* -+ * Experiment/quarantine knob: suppress ALERT handling for one CS35L56 -+ * peripheral identified by unique id. An electrically faulty peripheral -+ * that asserts Alert permanently drags the bus core into an endless -+ * alert-read retry storm (every read of its interrupt registers fails -+ * parity), and the extra traffic from a misbehaving responder disturbs -+ * enumeration of the healthy peripherals on the link. Reporting it as -+ * plainly attached quiets the storm so the rest of the link can be -+ * validated. Not for production; diagnostic aid for a bad unit. -+ */ -+static int quarantine_uid = -1; -+module_param(quarantine_uid, int, 0644); -+MODULE_PARM_DESC(quarantine_uid, -+ "Suppress ALERT for the 0x3556 peripheral with this unique id (-1 = off)"); -+ -+static bool mtk_sdw_quarantined(struct mtk_sdw_core *core, int dev_num) -+{ -+ struct sdw_slave *slave; -+ -+ if (quarantine_uid < 0) -+ return false; -+ -+ list_for_each_entry(slave, &core->bus.slaves, node) { -+ if (slave->dev_num == dev_num && -+ slave->id.mfg_id == 0x01fa && -+ slave->id.part_id == 0x3556 && -+ slave->id.unique_id == quarantine_uid) -+ return true; -+ } -+ -+ return false; -+} -+ - static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, - u64 slave_intstat) - { -@@ -734,7 +767,8 @@ static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, - } - - if (intstat & MCP_SLAVEINTSTAT_ALERT) { -- status[i] = SDW_SLAVE_ALERT; -+ status[i] = mtk_sdw_quarantined(core, i) ? -+ SDW_SLAVE_ATTACHED : SDW_SLAVE_ALERT; - set_status++; - } - -@@ -760,7 +794,8 @@ static int mtk_sdw_update_slave_status(struct mtk_sdw_core *core, - status[i] = SDW_SLAVE_ATTACHED; - break; - case 2: -- status[i] = SDW_SLAVE_ALERT; -+ status[i] = mtk_sdw_quarantined(core, i) ? -+ SDW_SLAVE_ATTACHED : SDW_SLAVE_ALERT; - break; - case 3: - default: -From 70675ab90d69feaec0286305312a3246f84f8ea4 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: restart the bus when - nothing attaches - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -A re-initialized master (module reload, and eventually resume) comes up -in normal operation mode while the peripherals still hold their device -numbers from the previous enumeration. They raise no new attach -transition, so the interrupt-driven status machinery (including the bus -reset recovery) is never armed and the link sits dead with zero attach -events. The reference driver never hits this because it runs its restart -choreography unconditionally on every re-init. - -Detect the state instead of restarting unconditionally: schedule a -one-shot check per link at probe; if peripherals are declared for the -link but every one is still UNATTACHED 2 s after init, run the restart -choreography with the same interrupt quiesce/re-arm bracket as the -debugfs knob (SOFT_RST clears the slave interrupt masks; without the -re-arm the post-restart attach transitions never interrupt and -enumeration stalls after Dev0). The restart drops the peripherals to -Dev0 and re-enumerates them through the normal interrupt path. The 2 s -delay is far past the normal attach window (tens of ms out of POST, -where the check sees attached slaves and does nothing) but inside the -5 s the codec drivers wait for re-attach at probe, so the codecs -recover without a rebind. - -Board-proven on a laptop with five peripherals on link1: a -plain module remove/reload of the audio stack, previously the -zero-attach dead-link signature, now recovers fully automatically: -restart at +2 s, all five peripherals re-enumerate, amp DSP firmware -reloads, the card re-registers with no manual step, and acoustic -loopback passes identically to cold boot. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-core.c | 81 +++++++++++++++++++++++ - drivers/soundwire/mediatek/mtk-sdw-core.h | 10 +++ - drivers/soundwire/mediatek/mtk-sdw.c | 11 +++ - 3 files changed, 102 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index 25fd979f0c..585fee544b 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -693,6 +693,11 @@ void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) - - core->interrupt_enabled = enable; - -+ /* -+ * attach_check_work is NOT cancelled here: its handler calls this -+ * function, so a sync cancel would self-deadlock. It is cancelled -+ * explicitly on the teardown paths (link deinit, suspend). -+ */ - if (!enable) - cancel_delayed_work_sync(&core->status_work); - -@@ -995,6 +1000,81 @@ static int mtk_sdw_compute_params(struct sdw_bus *bus, - return 0; - } - -+/* -+ * One-shot check scheduled after link init. A re-initialized master (module -+ * reload, and eventually resume) comes up in normal operation mode while the -+ * peripherals still hold their previous device numbers, so they raise no new -+ * attach transition and the interrupt-driven recovery machinery is never -+ * armed: the link sits dead with zero attach events. The reference stack -+ * avoids this by always running its restart choreography on re-init. Detect -+ * the state instead (peripherals declared for the link but every one of them -+ * still UNATTACHED well past the normal attach window) and run the restart, -+ * which drops them to Dev0 and re-enumerates them through the normal -+ * interrupt path. On a first boot out of POST the peripherals attach within -+ * tens of ms, every slave leaves UNATTACHED, and this work does nothing. -+ */ -+static void mtk_sdw_attach_check_work(struct work_struct *work) -+{ -+ struct mtk_sdw_core *core = -+ container_of(work, struct mtk_sdw_core, attach_check_work.work); -+ struct sdw_slave *slave; -+ bool any_declared = false; -+ -+ /* -+ * One reset sequence at a time per link: the debugfs knob and system -+ * sleep run the same quiesce -> reset -> restore choreography, and -+ * neither side may re-enable interrupt processing halfway through -+ * the other's reset. -+ */ -+ mutex_lock(&core->reset_lock); -+ -+ if (!core->interrupt_enabled) -+ goto out; -+ -+ /* -+ * Same choreography as the debugfs knob: quiesce interrupt handling -+ * (which also cancels the status work) before looking at the slave -+ * states, so an attach completing concurrently cannot be judged on a -+ * stale snapshot, then re-enable it afterwards, which also restores -+ * the slave interrupt masks that SOFT_RST clears - without that the -+ * attach transitions after the restart never interrupt and -+ * enumeration stalls after Dev0. -+ */ -+ mtk_sdw_enable_irq(core, false); -+ -+ mutex_lock(&core->bus.bus_lock); -+ list_for_each_entry(slave, &core->bus.slaves, node) { -+ any_declared = true; -+ if (slave->status != SDW_SLAVE_UNATTACHED) { -+ mutex_unlock(&core->bus.bus_lock); -+ mtk_sdw_enable_irq(core, true); -+ goto out; -+ } -+ } -+ mutex_unlock(&core->bus.bus_lock); -+ -+ if (!any_declared) { -+ mtk_sdw_enable_irq(core, true); -+ goto out; -+ } -+ -+ dev_warn(core->dev, -+ "[%u] no peripheral attached %u ms after init, restarting the bus\n", -+ core->bus.link_id, MTK_SDW_ATTACH_CHECK_DELAY_MS); -+ -+ if (mtk_sdw_core_bus_reset(core)) { -+ dev_err(core->dev, "[%u] post-init bus restart failed\n", -+ core->bus.link_id); -+ mtk_sdw_enable_irq(core, true); -+ goto out; -+ } -+ mtk_sdw_enable_irq(core, true); -+ schedule_delayed_work(&core->status_work, -+ msecs_to_jiffies(MTK_SDW_BUS_RESET_SETTLE_MS)); -+out: -+ mutex_unlock(&core->reset_lock); -+} -+ - int mtk_sdw_core_init(struct mtk_sdw_core *core) - { - core->bus.ops = &mtk_sdw_core_ops; -@@ -1003,6 +1083,7 @@ int mtk_sdw_core_init(struct mtk_sdw_core *core) - mutex_init(&core->reset_lock); - - INIT_DELAYED_WORK(&core->status_work, mtk_sdw_slave_status_work); -+ INIT_DELAYED_WORK(&core->attach_check_work, mtk_sdw_attach_check_work); - return 0; - } - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.h b/drivers/soundwire/mediatek/mtk-sdw-core.h -index 7cd8a2389c..7222560bee 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.h -@@ -199,6 +199,7 @@ struct mtk_sdw_core { - u16 attached_slaves; - void *priv; - struct delayed_work status_work; -+ struct delayed_work attach_check_work; - unsigned int dev0_repoll_count; - unsigned int bus_reset_count; - }; -@@ -227,6 +228,15 @@ static inline struct mtk_sdw_core *bus_to_core(struct sdw_bus *bus) - extern const struct sdw_master_ops mtk_sdw_core_ops; - extern const struct sdw_master_port_ops mtk_sdw_core_port_ops; - -+/* -+ * Delay before the one-shot post-init attach check. Peripherals that are -+ * going to attach do so within tens of ms of the link coming up; 2 s is -+ * far past that but still inside the 5 s the codec drivers wait for -+ * re-attach at probe, so a restart triggered here lets them recover -+ * without a rebind. -+ */ -+#define MTK_SDW_ATTACH_CHECK_DELAY_MS 2000 -+ - int mtk_sdw_core_init(struct mtk_sdw_core *core); - int mtk_sdw_core_hw_init(struct mtk_sdw_core *core); - int mtk_sdw_core_bus_reset(struct mtk_sdw_core *core); -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index ddb8b13726..6036cfca2f 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -923,6 +923,7 @@ static void mtk_sdw_link_deinit(struct mtk_sdw *mst, int idx) - { - struct mtk_sdw_core *core = &mst->links[idx].core; - -+ cancel_delayed_work_sync(&core->attach_check_work); - mtk_sdw_enable_irq(core, false); - sdw_bus_master_delete(&core->bus); - } -@@ -1277,6 +1278,16 @@ static int mtk_sdw_probe(struct platform_device *pdev) - - mtk_sdw_debugfs_init(mst); - -+ /* -+ * Arm the post-init attach check on every link: if the ACPI-declared -+ * peripherals raise no attach event (re-init with the bus already -+ * running, see mtk_sdw_attach_check_work()), restart the bus so they -+ * re-enumerate. -+ */ -+ for (i = 0; i < mst->num_links; i++) -+ schedule_delayed_work(&mst->links[i].core.attach_check_work, -+ msecs_to_jiffies(MTK_SDW_ATTACH_CHECK_DELAY_MS)); -+ - return 0; - } - -From b2ff44a61ea645c21733b138f1f9fbbeb31ee498 Mon Sep 17 00:00:00 2001 -From: Greta Zhang -Date: Thu, 3 Sep 2026 17:45:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: SOF: mt8901: add ADSP power-management - driver - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Bind the MT8901 audio DSP ACPI devices (NVDA8301, NVDA8302, NVDA8303) -and manage their power state through the power_wrap client interface: -runtime-PM suspend releases the DSP domain vote so the SoC can reach -its low-power states, resume reacquires it. Without a bound driver the -DSP domain stays powered and blocks the deepest platform sleep state. - -No SOF core, firmware loading, IPC or topology is set up yet. This is -the power scaffold the SOF platform driver for the HiFi5 cores will -extend once the DSP firmware is available, and it lives under -sound/soc/sof/mediatek/mt8901 so that extension lands in place. - -Signed-off-by: Greta Zhang -Co-developed-by: Bharat Dintakurti -Signed-off-by: Bharat Dintakurti -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - sound/soc/sof/mediatek/Kconfig | 12 +- - sound/soc/sof/mediatek/Makefile | 1 + - sound/soc/sof/mediatek/mt8901/Makefile | 4 + - sound/soc/sof/mediatek/mt8901/mt8901.c | 179 +++++++++++++++++++++++++ - 4 files changed, 195 insertions(+), 1 deletion(-) - create mode 100644 sound/soc/sof/mediatek/mt8901/Makefile - create mode 100644 sound/soc/sof/mediatek/mt8901/mt8901.c - -diff --git a/sound/soc/sof/mediatek/Kconfig b/sound/soc/sof/mediatek/Kconfig -index 4a2eddf600..66caa6d13b 100644 ---- a/sound/soc/sof/mediatek/Kconfig -+++ b/sound/soc/sof/mediatek/Kconfig -@@ -3,7 +3,7 @@ - config SND_SOC_SOF_MTK_TOPLEVEL - bool "SOF support for MTK audio DSPs" - depends on ARM64 || COMPILE_TEST -- depends on SND_SOC_SOF_OF -+ depends on SND_SOC_SOF_OF || SND_SOC_SOF_ACPI - help - This adds support for Sound Open Firmware for Mediatek platforms. - It is top level for all mediatek platforms. -@@ -42,4 +42,14 @@ config SND_SOC_SOF_MT8195 - Say Y if you have such a device. - If unsure select "N". - -+config SND_SOC_SOF_MT8901 -+ tristate "SOF support for MT8901 audio DSP" -+ depends on ARCH_MEDIATEK && ACPI -+ depends on MTK_POWER_WRAP -+ help -+ This adds support for Sound Open Firmware for Mediatek platforms -+ using the mt8901 processors. -+ Say Y if you have such a device. -+ If unsure select "N". -+ - endif ## SND_SOC_SOF_MTK_TOPLEVEL -diff --git a/sound/soc/sof/mediatek/Makefile b/sound/soc/sof/mediatek/Makefile -index 29c5afb2f3..8a1068fcca 100644 ---- a/sound/soc/sof/mediatek/Makefile -+++ b/sound/soc/sof/mediatek/Makefile -@@ -2,3 +2,4 @@ - obj-$(CONFIG_SND_SOC_SOF_MTK_COMMON) += mtk-adsp-common.o - obj-$(CONFIG_SND_SOC_SOF_MT8195) += mt8195/ - obj-$(CONFIG_SND_SOC_SOF_MT8186) += mt8186/ -+obj-$(CONFIG_SND_SOC_SOF_MT8901) += mt8901/ -diff --git a/sound/soc/sof/mediatek/mt8901/Makefile b/sound/soc/sof/mediatek/mt8901/Makefile -new file mode 100644 -index 0000000000..5244974861 ---- /dev/null -+++ b/sound/soc/sof/mediatek/mt8901/Makefile -@@ -0,0 +1,4 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -+ -+snd-sof-mt8901-y := mt8901.o -+obj-$(CONFIG_SND_SOC_SOF_MT8901) += snd-sof-mt8901.o -diff --git a/sound/soc/sof/mediatek/mt8901/mt8901.c b/sound/soc/sof/mediatek/mt8901/mt8901.c -new file mode 100644 -index 0000000000..b574bedfa1 ---- /dev/null -+++ b/sound/soc/sof/mediatek/mt8901/mt8901.c -@@ -0,0 +1,179 @@ -+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ */ -+ -+/* -+ * ACPI platform driver for MT8901 audio DSP devices -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define MT8901_AUTOSUSPEND_DELAY_MS 100 -+ -+struct sof_mt8901_priv { -+ void *pwrap_ctrl; -+}; -+ -+#ifdef CONFIG_ACPI -+static const struct acpi_device_id sof_mt8901_match[] = { -+ { "NVDA8301" }, -+ { "NVDA8302" }, -+ { "NVDA8303" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, sof_mt8901_match); -+#endif -+ -+static int sof_mt8901_probe(struct platform_device *pdev) -+{ -+ const struct acpi_device_id *id; -+ struct acpi_device *adev; -+ struct acpi_buffer acpi_path = { ACPI_ALLOCATE_BUFFER, NULL }; -+ struct device *dev = &pdev->dev; -+ struct sof_mt8901_priv *priv; -+ acpi_status status; -+ int ret; -+ -+ id = acpi_match_device(dev->driver->acpi_match_table, dev); -+ if (!id) { -+ dev_err(dev, "failed to match ACPI device\n"); -+ return -ENODEV; -+ } -+ -+ dev_dbg(dev, "matched ACPI device %s\n", id->id); -+ -+ adev = ACPI_COMPANION(dev); -+ if (!adev) -+ return -ENODEV; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &acpi_path); -+ if (ACPI_FAILURE(status)) { -+ dev_err(dev, "failed to get ACPI device path\n"); -+ return -EINVAL; -+ } -+ -+ priv->pwrap_ctrl = mtk_pwrap_dev_probe(acpi_path.pointer); -+ if (!priv->pwrap_ctrl) { -+ ret = dev_err_probe(dev, -ENODEV, -+ "pwrap probe failed for %s\n", -+ (char *)acpi_path.pointer); -+ kfree(acpi_path.pointer); -+ return ret; -+ } -+ dev_dbg(dev, "pwrap probe succeeded for %s\n", -+ (char *)acpi_path.pointer); -+ -+ kfree(acpi_path.pointer); -+ platform_set_drvdata(pdev, priv); -+ -+ pm_runtime_set_autosuspend_delay(dev, MT8901_AUTOSUSPEND_DELAY_MS); -+ pm_runtime_use_autosuspend(dev); -+ -+ ret = pm_runtime_set_active(dev); -+ if (ret) { -+ dev_err(dev, "failed to set runtime active (%d)\n", ret); -+ pm_runtime_dont_use_autosuspend(dev); -+ goto err_pwrap_remove; -+ } -+ -+ pm_runtime_enable(dev); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_idle(dev); -+ -+ return 0; -+ -+err_pwrap_remove: -+ if (priv->pwrap_ctrl) { -+ mtk_pwrap_dev_remove(priv->pwrap_ctrl); -+ priv->pwrap_ctrl = NULL; -+ } -+ -+ return ret; -+} -+ -+static void sof_mt8901_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct sof_mt8901_priv *priv = platform_get_drvdata(pdev); -+ int ret; -+ -+ /* SSPM transitions the DSP to D3 as part of abandoning the device. */ -+ ret = pm_runtime_resume_and_get(dev); -+ if (ret < 0) -+ dev_warn(dev, "failed to resume before remove (%d)\n", ret); -+ -+ pm_runtime_dont_use_autosuspend(dev); -+ pm_runtime_disable(dev); -+ -+ if (priv && priv->pwrap_ctrl) { -+ mtk_pwrap_dev_remove(priv->pwrap_ctrl); -+ priv->pwrap_ctrl = NULL; -+ } -+ -+ if (ret >= 0) -+ pm_runtime_put_noidle(dev); -+} -+ -+static int sof_mt8901_runtime_suspend(struct device *dev) -+{ -+ struct sof_mt8901_priv *priv = dev_get_drvdata(dev); -+ int ret; -+ -+ if (priv && priv->pwrap_ctrl) { -+ ret = mtk_pwrap_dev_suspend(priv->pwrap_ctrl, 0); -+ if (ret) { -+ dev_err(dev, "pwrap suspend failed (%d)\n", ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int sof_mt8901_runtime_resume(struct device *dev) -+{ -+ struct sof_mt8901_priv *priv = dev_get_drvdata(dev); -+ int ret; -+ -+ if (priv && priv->pwrap_ctrl) { -+ ret = mtk_pwrap_dev_resume(priv->pwrap_ctrl, 0); -+ if (ret) { -+ dev_err(dev, "pwrap resume failed (%d)\n", ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops sof_mt8901_pm = { -+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -+ pm_runtime_force_resume) -+ RUNTIME_PM_OPS(sof_mt8901_runtime_suspend, -+ sof_mt8901_runtime_resume, NULL) -+}; -+ -+static struct platform_driver snd_sof_acpi_mt8901_driver = { -+ .probe = sof_mt8901_probe, -+ .remove = sof_mt8901_remove, -+ .driver = { -+ .name = "sof-audio-acpi-mt8901", -+ .pm = pm_ptr(&sof_mt8901_pm), -+ .acpi_match_table = ACPI_PTR(sof_mt8901_match), -+ }, -+}; -+module_platform_driver(snd_sof_acpi_mt8901_driver); -+ -+MODULE_LICENSE("Dual BSD/GPL"); -+MODULE_DESCRIPTION("MT8901 ACPI audio DSP driver"); -From b0a4463f8cfa9e45e8683e9cf82db47e3b7a495c Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: restart every link at - probe - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -POST leaves the peripherals enumerated and the bus running, and until -now Linux adopted that state. Adopting preserves whatever internal -state the peripherals hold, which has been observed to include -defective persistent state that register-level reconfiguration cannot -clear: the codec sits on an always-on rail that never drops while the -battery is connected, so such state survives reboots indefinitely. On -one unit the internal microphone path was broken this way for weeks; -one bus restart cleared it permanently and both microphones and -speakers validated acoustically immediately after. - -The reference driver never hits this class of problem because it runs -its restart choreography unconditionally on every init. Do the same: -run the bus restart in link init, after the hardware init and before -interrupts are enabled, so the slave interrupt masks that SOFT_RST -clears are armed after the restart and the fresh attach transitions -are processed normally. The post-init attach check remains as a -backstop. A restart_on_probe module parameter (default on) allows -reverting to the old adopt behavior from the kernel command line. - -Boot-time cost is one restart dwell (about 30 ms) per link. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw.c | 39 ++++++++++++++++++++++++++++ - 1 file changed, 39 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index 6036cfca2f..4fe32a5270 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -24,6 +24,17 @@ - #include "mtk-sdw-mach.h" - #include "mtk-sdw-top.h" - -+/* -+ * Restart (SOFT_RST + quiesce + re-init) every link at probe instead of -+ * adopting the POST-enumerated bus, matching the reference driver's -+ * restart-on-every-init behavior. Clears defective -+ * persistent peripheral state that survives reboots on the always-on -+ * codec rail. Boot-time cost is one restart dwell per link. -+ */ -+static bool restart_on_probe = true; -+module_param(restart_on_probe, bool, 0444); -+MODULE_PARM_DESC(restart_on_probe, "Restart each SoundWire link at probe instead of adopting the POST-enumerated bus (default: on)"); -+ - static acpi_status mtk_sdw_apply_pin_bias_cb(struct acpi_resource *res, - void *context) - { -@@ -910,7 +921,35 @@ static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) - goto err_disable_top_clock; - } - -+ /* -+ * Restart the bus unconditionally before enabling interrupts, the -+ * way the reference driver restarts the bus on every init. -+ * POST leaves the peripherals enumerated and running; adopting that -+ * state preserves whatever internal state the peripherals hold, -+ * which has been observed to include defective persistent state -+ * that register-level reconfiguration cannot clear (a codec's rail -+ * never drops while the battery is connected, so such state -+ * survives reboots indefinitely). The restart drops every -+ * peripheral to Dev0 and re-enumerates it from a known-clean -+ * state. Interrupt enabling AFTER the restart arms the slave -+ * interrupt masks that SOFT_RST clears, so the attach transitions -+ * are processed normally; the post-init attach check remains as a -+ * backstop. -+ */ -+ if (restart_on_probe) { -+ ret = mtk_sdw_core_bus_reset(core); -+ if (ret) { -+ sdw_bus_master_delete(&core->bus); -+ goto err_disable_top_clock; -+ } -+ } -+ - mtk_sdw_enable_irq(core, true); -+ -+ if (restart_on_probe) -+ schedule_delayed_work(&core->status_work, -+ msecs_to_jiffies(100)); -+ - dev_info(mst->dev, "IP%d: SoundWire bus ready\n", idx); - return 0; - -From aed5ff7d95cea5f5ef6a2ca29aadcb900571cb20 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:11 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: mt8901: put the jack stream on - DL1 - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -The AFE playback interconnect is fixed in hardware: PDI2/PDI3/PDI4 are -only reachable from the speaker memifs (DL0/DL_24CH) and PDI5/PDI6 -only from the headphone memif (DL1), and data port DP is hard-wired -to PDI. The machine driver hands out SoundWire cpu-DAI pins to -endpoint groups in plain endpoint order, which works on two-link -boards (the firmware allocates link1's DPs from DP5, so the jack group -lands on DP5 by accident of ordering) but breaks on single-link boards -(CS42L43 plus CS35L56 amps, everything on link1, DPs allocated from -DP2): the jack group got DP2, which DL1 cannot reach, so opening the -jack PCM (hw:,1) failed with -EINVAL (no backend DAIs for DL1_FE). -Worse, PipeWire drops an entire UCM verb when any of its PCMs fails -to open, so this removed every audio device on those boards. - -Read the firmware DP allocation (acpi-scd-dp-allocation, same property -the SoundWire controller parses; the machine device is a child of the -controller) and reserve the DP5 pin for the jack playback stream; -everything else allocates sequentially around it. On two-link boards -this computes the same assignment as before (jack pin 5 - 5 = 0). On -single-link boards the jack moves to DP5/PDI5 while the amps keep the -sequential pins they had before (DP3/DP4 on those boards, where the amp -backend is wired through the O152/O153 interconnect); DP2 is left -unused. If the property is absent the legacy sequential behaviour is -kept. - -The jack reservation burns the sequential slot the jack would have -taken, but only while the sequence has not yet stepped over the jack -pin: if a non-jack stream already skipped it, burning again would -leave a pin gap and could push later streams past the firmware DP -window (review finding on the first revision). - -Board-proven on a single-link CS42L43 board: full four-path matrix -(speakers, jack, DMIC capture, headset mic) passes with the UCM -profile unchanged for the non-jack paths. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - .../mt8901/mt8901-acp-sdw-legacy-mach.c | 109 +++++++++++++++++- - 1 file changed, 108 insertions(+), 1 deletion(-) - -diff --git a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -index 98010cffab..cda5d4c2c6 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -+++ b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -@@ -9,6 +9,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -21,14 +22,116 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); - #define MT8901_SDW_MAX_LINKS 2 - #define PCM_STREAM_NUM (SNDRV_PCM_STREAM_LAST + 1) - -+/* -+ * The AFE playback interconnect is fixed in hardware: PDI2/PDI3/PDI4 are -+ * only reachable from the speaker memifs (DL0/DL_24CH) and PDI5/PDI6 only -+ * from the headphone memif (DL1) - see the O150..O159 mixer inputs in -+ * mt8901-dai-soundwire.c. Data port DP is hard-wired to PDI, so the -+ * jack stream must sit on DP5 (or DP6) or DL1 has no path to it. -+ */ -+#define MT8901_SDW_JACK_PLAYBACK_DP 5 -+ - static struct snd_soc_dai_link_component afe_platform_component[] = { - { .name = "NVDA9022:00" } - }; - - struct mtk_mc_ctx { - unsigned int sdw_pin_index[MT8901_SDW_MAX_LINKS][PCM_STREAM_NUM]; -+ /* firmware DP allocation per link (acpi-scd-dp-allocation) */ -+ unsigned int sdw_src_base[MT8901_SDW_MAX_LINKS]; -+ unsigned int sdw_src_num[MT8901_SDW_MAX_LINKS]; - }; - -+/* -+ * Pin (DAI index) reserved for the jack playback stream on this link, or -+ * -1 when the firmware DP allocation is unknown or does not cover DP5. -+ */ -+static int mt8901_sdw_jack_pin(struct mtk_mc_ctx *mtk_ctx, int link) -+{ -+ unsigned int base = mtk_ctx->sdw_src_base[link]; -+ unsigned int num = mtk_ctx->sdw_src_num[link]; -+ -+ if (!num) -+ return -1; -+ if (base > MT8901_SDW_JACK_PLAYBACK_DP || -+ base + num <= MT8901_SDW_JACK_PLAYBACK_DP) -+ return -1; -+ return MT8901_SDW_JACK_PLAYBACK_DP - base; -+} -+ -+/* -+ * Historically pins were handed out sequentially in endpoint order. On -+ * two-link boards (amps on link0, jack codec on link1) that works out -+ * because the firmware allocates link1's DPs starting at DP5. On -+ * single-link boards (all codecs on link1, DPs from DP2) the sequential -+ * order gave the jack DP2, which DL1 cannot reach, so opening the jack -+ * PCM failed with EINVAL. Reserve the DP5 pin for the jack stream and -+ * let everything else allocate around it. -+ */ -+static unsigned int mt8901_sdw_alloc_pin(struct mtk_mc_ctx *mtk_ctx, -+ int link, int stream, int dai_type) -+{ -+ int jack_pin = -1; -+ unsigned int pin; -+ -+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) -+ jack_pin = mt8901_sdw_jack_pin(mtk_ctx, link); -+ -+ if (jack_pin >= 0 && dai_type == SOC_SDW_DAI_TYPE_JACK) { -+ /* -+ * Burn the sequential slot the jack would have taken so -+ * every other stream keeps the pin (and therefore the DP) -+ * it had before this reservation existed: UCM profiles -+ * written for the sequential order stay valid for all -+ * non-jack paths. Skip the burn when the sequence has -+ * already stepped over the jack pin (jack endpoint -+ * processed late): the skip below consumed the slot -+ * already, and burning again would leave a pin gap and -+ * push later streams past the firmware DP window. -+ */ -+ if (mtk_ctx->sdw_pin_index[link][stream] <= (unsigned int)jack_pin) -+ mtk_ctx->sdw_pin_index[link][stream]++; -+ return jack_pin; -+ } -+ -+ pin = mtk_ctx->sdw_pin_index[link][stream]++; -+ if ((int)pin == jack_pin) -+ pin = mtk_ctx->sdw_pin_index[link][stream]++; -+ return pin; -+} -+ -+static void mt8901_sdw_parse_dp_allocation(struct device *dev, -+ struct mtk_mc_ctx *mtk_ctx) -+{ -+ /* the machine device is a child of the SoundWire controller */ -+ struct device *sdw_dev = dev->parent; -+ int i; -+ -+ if (!sdw_dev) -+ return; -+ -+ for (i = 0; i < MT8901_SDW_MAX_LINKS; i++) { -+ struct fwnode_handle *node; -+ char key[32]; -+ u32 dp[4]; -+ -+ snprintf(key, sizeof(key), "acpi-scd-%d-subproperties", i); -+ node = device_get_named_child_node(sdw_dev, key); -+ if (!node) -+ continue; -+ -+ if (!fwnode_property_read_u32_array(node, -+ "acpi-scd-dp-allocation", -+ dp, ARRAY_SIZE(dp))) { -+ mtk_ctx->sdw_src_base[i] = dp[0]; -+ mtk_ctx->sdw_src_num[i] = dp[1]; -+ dev_dbg(dev, "link %d playback DPs %u..%u\n", i, -+ dp[0], dp[0] + dp[1] - 1); -+ } -+ fwnode_handle_put(node); -+ } -+} -+ - static void log_quirks(struct device *dev) - { - if (SOC_SDW_JACK_JDSRC(soc_sdw_quirk)) -@@ -261,7 +364,8 @@ static int create_sdw_dailink(struct snd_soc_card *card, - return -EINVAL; - } - -- pin = mtk_ctx->sdw_pin_index[link][stream]++; -+ pin = mt8901_sdw_alloc_pin(mtk_ctx, link, stream, -+ soc_end->dai_info->dai_type); - - cur_link = soc_end->link_mask; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { -@@ -480,6 +584,9 @@ static int mt8901_card_probe(struct platform_device *pdev) - - ctx->mc_quirk = soc_sdw_quirk; - dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk); -+ -+ mt8901_sdw_parse_dp_allocation(&pdev->dev, mtk_ctx); -+ - /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ctx->codec_info_list_count; i++) - codec_info_list[i].amp_num = 0; -From 8100fab1bc10bca553ae232b41ae7e3efe8c6a48 Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 3 Sep 2026 17:45:11 -0700 -Subject: [PATCH] NVIDIA: SAUCE: ASoC: mediatek: mt8901: add error handling in - card probe - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Handle failures during card probe: unwind the partially registered -card and return the error instead of continuing with an inconsistent -component state. - -Signed-off-by: Trevor Wu -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - .../mt8901/mt8901-acp-sdw-legacy-mach.c | 27 +++++++++++++------ - 1 file changed, 19 insertions(+), 8 deletions(-) - -diff --git a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -index cda5d4c2c6..cf374b3eee 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -+++ b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -@@ -592,8 +592,11 @@ static int mt8901_card_probe(struct platform_device *pdev) - codec_info_list[i].amp_num = 0; - - ret = soc_card_dai_links_create(card); -- if (ret < 0) -- return ret; -+ if (ret < 0) { -+ dev_err_probe(card->dev, ret, -+ "soc_card_dai_links_create failed %d\n", ret); -+ goto err_ret; -+ } - - /* - * the default amp_num is zero for each codec and -@@ -605,15 +608,20 @@ static int mt8901_card_probe(struct platform_device *pdev) - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "cfg-amp:%d", amp_num); -- if (!card->components) -- return -ENOMEM; -+ if (!card->components) { -+ ret = -ENOMEM; -+ goto err_ret; -+ } -+ - if (mach && mach->mach_params.dmic_num) { - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:dmic cfg-mics:%d", - card->components, - mach->mach_params.dmic_num); -- if (!card->components) -- return -ENOMEM; -+ if (!card->components) { -+ ret = -ENOMEM; -+ goto err_ret; -+ } - } - - /* Register the card */ -@@ -621,12 +629,15 @@ static int mt8901_card_probe(struct platform_device *pdev) - if (ret) { - dev_err_probe(card->dev, ret, - "snd_soc_register_card failed %d\n", ret); -- asoc_sdw_mc_dailink_exit_loop(card); -- return ret; -+ goto err_ret; - } - - platform_set_drvdata(pdev, card); - -+ return 0; -+ -+err_ret: -+ asoc_sdw_mc_dailink_exit_loop(card); - return ret; - } - -From 9f651a753c69da4ed8daefb8ace681b3b141256c Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:11 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: mask line error - interrupts on a storm - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -The bus clash and parity error interrupts are enabled unconditionally -and the handler only logs and clears them. Isolated clashes or parity -errors at bus power transitions are harmless (1-2 per suspend/resume -cycle in the reference board soak data), but a persistent line error -condition refires the interrupt as fast as it is cleared: on a laptop -with all peripherals on link1, an idle link0 storms continuously with -bus clashes, pinning CPU0 with softirqs and flooding the log, and a -reference unit with a marginal link1 produced 49,000 parity error -interrupts in 11 s and 97,000 log lines while the peripherals stayed -attached. Detect a storm (32 line error interrupts inside a 100 ms -window) and mask the line error bits that are firing on that link; -ratelimit the per-event log lines. The peripherals stay attached and -their own register traffic still reports errors. - -All MCP_INTMASK updates are read-modify-write from the ISR, the status -work, and the attach-check work with no shared guard, so the new -ISR-side masking write is funneled, together with the existing enable -helpers, through one spinlock-serialized updater. - -Audio is unaffected before and after masking: a storming empty link -carries no devices and stream traffic on the other link is serviced -normally; on the unit with the marginal link the masking is what keeps -the system responsive. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-core.c | 83 ++++++++++++++++++----- - drivers/soundwire/mediatek/mtk-sdw-core.h | 8 +++ - 2 files changed, 75 insertions(+), 16 deletions(-) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index 585fee544b..147a44727e 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -671,10 +671,24 @@ static int mtk_init_config_setting(struct mtk_sdw_core *core) - return mtk_do_config_update(core); - } - -+/* -+ * All MCP_INTMASK updates are read-modify-write and can run concurrently -+ * from the ISR, the status work, and the attach-check work: serialize -+ * them so no path can drop another path's mask bits. -+ */ -+static void mtk_sdw_update_intmask(struct mtk_sdw_core *core, u32 mask, u32 val) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&core->intmask_lock, flags); -+ core_updatel(core, MCP_INTMASK, mask, val); -+ spin_unlock_irqrestore(&core->intmask_lock, flags); -+} -+ - static void mtk_sdw_enable_master_irq(struct mtk_sdw_core *core, bool enable) - { -- core_updatel(core, MCP_INTMASK, (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP), -- enable ? (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP) : 0); -+ mtk_sdw_update_intmask(core, (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP), -+ enable ? (MCP_INT_MST_ERR_MASK | MCP_INT_WAKEUP) : 0); - } - - void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) -@@ -697,18 +711,27 @@ void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) - * attach_check_work is NOT cancelled here: its handler calls this - * function, so a sync cancel would self-deadlock. It is cancelled - * explicitly on the teardown paths (link deinit, suspend). -+ * -+ * A handler that already observed interrupt_enabled == true may still -+ * be running and about to queue status_work: wait for it before the -+ * cancel, or the work is re-queued behind the caller's back. The line -+ * is shared between links, so synchronize rather than disable it. - */ -- if (!enable) -- cancel_delayed_work_sync(&core->status_work); -+ if (!enable) { -+ struct mtk_sdw_link *link = -+ container_of(core, struct mtk_sdw_link, core); - -- core_updatel(core, MCP_INTMASK, MCP_INT_IRQ, -- enable ? MCP_INT_IRQ : 0); -+ synchronize_irq(link->irq); -+ cancel_delayed_work_sync(&core->status_work); -+ } -+ -+ mtk_sdw_update_intmask(core, MCP_INT_IRQ, enable ? MCP_INT_IRQ : 0); - } - - void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable) - { -- core_updatel(core, MCP_INTMASK, MCP_INT_SLV_MASK, -- enable ? MCP_INT_SLV_MASK : 0); -+ mtk_sdw_update_intmask(core, MCP_INT_SLV_MASK, -+ enable ? MCP_INT_SLV_MASK : 0); - } - - /* -@@ -1082,6 +1105,7 @@ int mtk_sdw_core_init(struct mtk_sdw_core *core) - core->bus.compute_params = mtk_sdw_compute_params; - mutex_init(&core->reset_lock); - -+ spin_lock_init(&core->intmask_lock); - INIT_DELAYED_WORK(&core->status_work, mtk_sdw_slave_status_work); - INIT_DELAYED_WORK(&core->attach_check_work, mtk_sdw_attach_check_work); - return 0; -@@ -1170,17 +1194,44 @@ irqreturn_t mtk_sdw_core_irq(int irq, void *data) - mtk_sdw_handle_master_dp_interrupt(core); - } - -+ if (intstat & MCP_INT_LINE_ERRORS) { -+ /* -+ * Isolated clashes or parity errors at bus power transitions -+ * are harmless. A persistent line error condition (floating -+ * pads on a link with no peripherals, or contention on a -+ * marginal link) refires the interrupt as fast as it is -+ * cleared and storms the CPU, to the point of starving the -+ * rest of the system: mask the line error interrupts that are -+ * firing on this link when a rapid burst is detected. The -+ * peripherals stay attached; their register traffic reports -+ * its own errors. -+ */ -+ if (time_after(jiffies, core->clash_window + HZ / 10)) { -+ core->clash_window = jiffies; -+ core->clash_burst = 0; -+ } -+ if (++core->clash_burst >= 32) { -+ u32 storm = intstat & MCP_INT_LINE_ERRORS; -+ -+ mtk_sdw_update_intmask(core, storm, 0); -+ dev_err(core->dev, -+ "[%u]line error interrupt storm: masking 0x%x IntStatus:0x%x\n", -+ bus->link_id, storm, intstat); -+ core->clash_burst = 0; -+ } -+ } -+ - if (intstat & (MCP_INT_CTL_BUS_CLASH)) -- dev_err(core->dev, "[%u]control bus clash 0x%x\n", bus->link_id, -- intstat); -+ dev_err_ratelimited(core->dev, "[%u]control bus clash 0x%x\n", -+ bus->link_id, intstat); - - if (intstat & (MCP_INT_DATA_BUS_CLASH)) -- dev_err(core->dev, "[%u]data bus clash 0x%x\n", bus->link_id, -- intstat); -+ dev_err_ratelimited(core->dev, "[%u]data bus clash 0x%x\n", -+ bus->link_id, intstat); - - if (intstat & MCP_INT_PARITY_ERR) -- dev_err(core->dev, "[%u]parity error 0x%x\n", bus->link_id, -- intstat); -+ dev_err_ratelimited(core->dev, "[%u]parity error 0x%x\n", -+ bus->link_id, intstat); - - if (intstat & MCP_INT_CMD_ERR) - dev_err(core->dev, "[%u]command error 0x%x\n", bus->link_id, -@@ -1189,8 +1240,8 @@ irqreturn_t mtk_sdw_core_irq(int irq, void *data) - if (intstat & MCP_INT_RXWL) - dev_info(core->dev, "[%u]rw wl 0x%x\n", bus->link_id, intstat); - -- dev_info(core->dev, "[%u]ClearStatus 0x%x, IntStatus 0x%x\n", -- bus->link_id, clearstat, intstat); -+ dev_info_ratelimited(core->dev, "[%u]ClearStatus 0x%x, IntStatus 0x%x\n", -+ bus->link_id, clearstat, intstat); - - core_writel(core, MCP_INTSTAT, clearstat); - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.h b/drivers/soundwire/mediatek/mtk-sdw-core.h -index 7222560bee..c3ab0eb3c7 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.h -@@ -110,6 +110,10 @@ - #define MCP_INT_PARITY_ERR BIT(8) - #define MCP_INT_DATA_BUS_CLASH BIT(9) - #define MCP_INT_CTL_BUS_CLASH BIT(10) -+/* Line-level errors that a marginal or unterminated link refires continuously. */ -+#define MCP_INT_LINE_ERRORS (MCP_INT_PARITY_ERR | \ -+ MCP_INT_DATA_BUS_CLASH | \ -+ MCP_INT_CTL_BUS_CLASH) - #define MCP_INT_DP_INT BIT(11) - #define MCP_INT_SLV_NOT_ATTACH BIT(12) - #define MCP_INT_SLV_ATTACHED BIT(13) -@@ -202,6 +206,10 @@ struct mtk_sdw_core { - struct delayed_work attach_check_work; - unsigned int dev0_repoll_count; - unsigned int bus_reset_count; -+ unsigned int clash_burst; -+ unsigned long clash_window; -+ /* serializes all MCP_INTMASK read-modify-write updates */ -+ spinlock_t intmask_lock; - }; - - struct mtk_sdw_pdi_params { -From de433df413333bc87af262e6b88fb295691fc9ff Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add CS42L43 + 2x CS35L56 - machine entry - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -This Cirrus variant puts all three codecs on link1 with link0 unused: a -CS42L43 jack codec at unique ID 0x30 plus two aggregated CS35L56 amps at -unique IDs 0x30/0x31 (_ADR values from the platform firmware dump; -peripherals of different part numbers may share unique IDs on one link). -Distinct from both the dual-link Cirrus arrangement (four amps on link0) -and the Realtek layouts. The cs42l43 entry uses the same speakerless -endpoint list as the dual-link Cirrus entry, and the amps take group -positions 0/1 of the existing aggregated group. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-mach.c | 45 +++++++++++++++++++++++ - 1 file changed, 45 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.c b/drivers/soundwire/mediatek/mtk-sdw-mach.c -index ba6f0e5063..f7f3c5da04 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-mach.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.c -@@ -255,6 +255,46 @@ static const struct snd_soc_acpi_link_adr mtk_sdw_rt1321_l0_rt713_l1[] = { - {} - }; - -+/* -+ * Config 3: SDW1 = CS42L43 (jack codec) + 2x CS35L56 (amps, aggregated), -+ * link0 unused. Topology: all three devices -+ * on link1, CS42L43 at uid 0x30, amps at uids 0x30/0x31 (peripherals of -+ * different part numbers may share unique IDs on one link). -+ */ -+static const struct snd_soc_acpi_adr_device cs35l56x2_cs42l43_l1_adr[] = { -+ { -+ .adr = 0x00013001FA424301ull, -+ /* Speaker Playback endpoint (num 3) excluded as on the 4x -+ * CS35L56 entry: the amps are SoundWire peripherals, not the cs42l43 -+ * sidecar path. -+ */ -+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), -+ .endpoints = cs42l43_endpoints, -+ .name_prefix = "cs42l43", -+ }, -+ { -+ .adr = 0x00013001FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[0], -+ .name_prefix = "AMP1", -+ }, -+ { -+ .adr = 0x00013101FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[1], -+ .name_prefix = "AMP2", -+ }, -+}; -+ -+static const struct snd_soc_acpi_link_adr mtk_sdw_cs42l43_cs35l56x2_l1[] = { -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(cs35l56x2_cs42l43_l1_adr), -+ .adr_d = cs35l56x2_cs42l43_l1_adr, -+ }, -+ {} -+}; -+ - static struct snd_soc_acpi_mach mtk_sdw_machines[] = { - { - .link_mask = BIT(0) | BIT(1), -@@ -271,6 +311,11 @@ static struct snd_soc_acpi_mach mtk_sdw_machines[] = { - .links = mtk_sdw_cs35l56_l0_cs42l43_l1, - .drv_name = "mtk_sdw_mc", - }, -+ { -+ .link_mask = BIT(1), -+ .links = mtk_sdw_cs42l43_cs35l56x2_l1, -+ .drv_name = "mtk_sdw_mc", -+ }, - {} - }; - -From c8faf6bbbdb20473a097766345dc3f422778a125 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:10 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add CS42L43 + 4x CS35L56 - machine entry - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -This Cirrus variant puts all five codecs on link1 with link0 unused: a -CS42L43 jack codec at unique ID 0x30 plus four aggregated CS35L56 amps -at unique IDs 0x30/0x31/0x34/0x35 (_ADR values from the platform -firmware dump; peripherals of different part numbers may share unique -IDs on one link). Distinct from the dual-link Cirrus arrangement (four -amps on link0) and from the two-amp single-link entry, of which it is a -superset: the entry is placed ahead of the two-amp one because matching -is first-fit and tolerates extra enumerated peripherals, so the two-amp -entry would otherwise match a four-amp board and register a card with -only half the speakers. The cs42l43 entry uses the same speakerless -endpoint list as the other Cirrus entries, and the amps take group -positions 0-3 of the existing aggregated group. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-mach.c | 64 +++++++++++++++++++++++ - 1 file changed, 64 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.c b/drivers/soundwire/mediatek/mtk-sdw-mach.c -index f7f3c5da04..229c05a7a0 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-mach.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.c -@@ -295,6 +295,59 @@ static const struct snd_soc_acpi_link_adr mtk_sdw_cs42l43_cs35l56x2_l1[] = { - {} - }; - -+/* -+ * Config 4: SDW1 = CS42L43 (jack codec) + 4x CS35L56 (amps, aggregated), -+ * link0 unused. All five devices on link1: CS42L43 at uid 0x30, amps at -+ * uids 0x30/0x31/0x34/0x35 (peripherals of different part numbers may -+ * share unique IDs on one link). Superset of the two-amp single-link -+ * entry, so it must precede that entry in the machine table. -+ */ -+static const struct snd_soc_acpi_adr_device cs35l56x4_cs42l43_l1_adr[] = { -+ { -+ .adr = 0x00013001FA424301ull, -+ /* Speaker Playback endpoint (num 3) excluded as on the other -+ * Cirrus entries: the amps are SoundWire peripherals, not the -+ * cs42l43 sidecar path. -+ */ -+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), -+ .endpoints = cs42l43_endpoints, -+ .name_prefix = "cs42l43", -+ }, -+ { -+ .adr = 0x00013001FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[0], -+ .name_prefix = "AMP1", -+ }, -+ { -+ .adr = 0x00013101FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[1], -+ .name_prefix = "AMP2", -+ }, -+ { -+ .adr = 0x00013401FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[2], -+ .name_prefix = "AMP3", -+ }, -+ { -+ .adr = 0x00013501FA355601ull, -+ .num_endpoints = 1, -+ .endpoints = &cs35l56_endpoints[3], -+ .name_prefix = "AMP4", -+ }, -+}; -+ -+static const struct snd_soc_acpi_link_adr mtk_sdw_cs42l43_cs35l56x4_l1[] = { -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(cs35l56x4_cs42l43_l1_adr), -+ .adr_d = cs35l56x4_cs42l43_l1_adr, -+ }, -+ {} -+}; -+ - static struct snd_soc_acpi_mach mtk_sdw_machines[] = { - { - .link_mask = BIT(0) | BIT(1), -@@ -311,6 +364,17 @@ static struct snd_soc_acpi_mach mtk_sdw_machines[] = { - .links = mtk_sdw_cs35l56_l0_cs42l43_l1, - .drv_name = "mtk_sdw_mc", - }, -+ /* -+ * The four-amp single-link entry must precede the two-amp one: -+ * matching is first-fit and tolerates extra enumerated peripherals, -+ * so on a four-amp board the two-amp entry would otherwise win and -+ * register a card with only half the speakers. -+ */ -+ { -+ .link_mask = BIT(1), -+ .links = mtk_sdw_cs42l43_cs35l56x4_l1, -+ .drv_name = "mtk_sdw_mc", -+ }, - { - .link_mask = BIT(1), - .links = mtk_sdw_cs42l43_cs35l56x2_l1, -From 61525d962a27862b13a530efae3df4c720b58664 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Thu, 3 Sep 2026 17:45:11 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add 2x RT1320 + RT712 - machine entry - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Boards with this Realtek layout enumerate two RT1320 amps on link0 at -unique IDs 0x30 and 0x31 plus an RT712 jack codec on link1. The existing -reference entry expects the second amp at unique ID 0x32, so these -boards enumerated but never matched a machine and no card was created. -Add the variant with the second amp at 0x31, reusing the existing RT712 -endpoint list and the rt1320-1/rt1320-2/rt712 name prefixes so existing -mixer recipes and profiles apply unchanged. - -_ADR values from the platform firmware ACPI dump. The firmware also -declares PinFunction pad entries (same 0x90/0xF0 policy as other -production boards) and full SDCA functions on the RT712. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw-mach.c | 38 +++++++++++++++++++++++ - 1 file changed, 38 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.c b/drivers/soundwire/mediatek/mtk-sdw-mach.c -index 229c05a7a0..2d7c240344 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-mach.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.c -@@ -67,6 +67,39 @@ static const struct snd_soc_acpi_adr_device rt712_l1_adr[] = { - }, - }; - -+/* -+ * Variant of the RT1320 pair with the second amp at unique ID 0x31 -+ * (the reference layout has it at 0x32). -+ */ -+static const struct snd_soc_acpi_adr_device rt1320x2_l0_adr[] = { -+ { -+ .adr = 0x000030025D132001ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[0], -+ .name_prefix = "rt1320-1", -+ }, -+ { -+ .adr = 0x000031025D132001ull, -+ .num_endpoints = 1, -+ .endpoints = &rt1320_endpoints[1], -+ .name_prefix = "rt1320-2", -+ }, -+}; -+ -+static const struct snd_soc_acpi_link_adr mtk_sdw_rt1320x2_l0_rt712_l1[] = { -+ { -+ .mask = BIT(0), -+ .num_adr = ARRAY_SIZE(rt1320x2_l0_adr), -+ .adr_d = rt1320x2_l0_adr, -+ }, -+ { -+ .mask = BIT(1), -+ .num_adr = ARRAY_SIZE(rt712_l1_adr), -+ .adr_d = rt712_l1_adr, -+ }, -+ {} -+}; -+ - static const struct snd_soc_acpi_link_adr mtk_sdw_rt1320_l0_rt712_l1[] = { - { - .mask = BIT(0), -@@ -359,6 +392,11 @@ static struct snd_soc_acpi_mach mtk_sdw_machines[] = { - .links = mtk_sdw_rt1321_l0_rt713_l1, - .drv_name = "mtk_sdw_mc", - }, -+ { -+ .link_mask = BIT(0) | BIT(1), -+ .links = mtk_sdw_rt1320x2_l0_rt712_l1, -+ .drv_name = "mtk_sdw_mc", -+ }, - { - .link_mask = BIT(0) | BIT(1), - .links = mtk_sdw_cs35l56_l0_cs42l43_l1, -From 78ddc3b15ec1e8b6a82edafc1a177735f8f9ced5 Mon Sep 17 00:00:00 2001 -From: Trevor Wu -Date: Thu, 10 Sep 2026 12:37:15 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: add system sleep support - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -Add system sleep suspend/resume callbacks to the mt8901 SoundWire -manager. Suspend releases the link clocks and the power domain votes so -the platform can reach its deepest sleep state; resume reacquires them, -reinitializes the links, restores the Cadence and TOP configuration, -re-enumerates the bus and restores the data port setup so peripherals -reattach and audio continues to work without reloading the driver. - -The power domain votes are taken and released per link: each link that -was active before suspend restores its own vote on resume. A -master-wide vote is not sufficient because links power on independently -and a single vote either leaks references or releases a domain that -another link still needs. - -Signed-off-by: Trevor Wu -Co-developed-by: David Cemin -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/Makefile | 3 + - drivers/soundwire/mediatek/mt8901-afe-clk.c | 66 ++++ - drivers/soundwire/mediatek/mtk-sdw-common.h | 7 + - drivers/soundwire/mediatek/mtk-sdw-core.c | 96 +++++- - drivers/soundwire/mediatek/mtk-sdw-core.h | 18 +- - drivers/soundwire/mediatek/mtk-sdw-top.c | 84 ++++- - drivers/soundwire/mediatek/mtk-sdw-top.h | 5 +- - drivers/soundwire/mediatek/mtk-sdw.c | 350 +++++++++++++++++++- - 8 files changed, 595 insertions(+), 34 deletions(-) - -diff --git a/drivers/soundwire/mediatek/Makefile b/drivers/soundwire/mediatek/Makefile -index 39c451ab1c..d82e26435b 100644 ---- a/drivers/soundwire/mediatek/Makefile -+++ b/drivers/soundwire/mediatek/Makefile -@@ -3,6 +3,9 @@ - # Makefile for MediaTek SoundWire driver - # - -+# for the soundwire core's internal bus.h (sdw_clear_slave_status) -+ccflags-y := -I$(srctree)/drivers/soundwire -+ - soundwire-mtk-y := mtk-sdw.o mtk-sdw-top.o mtk-sdw-core.o mtk-sdw-mach.o mtk-sdw-chipglue.o - soundwire-mtk-$(CONFIG_SOUNDWIRE_MTK_MT8901_CLK) += mt8901-afe-clk.o - obj-$(CONFIG_SOUNDWIRE_MTK) += soundwire-mtk.o -diff --git a/drivers/soundwire/mediatek/mt8901-afe-clk.c b/drivers/soundwire/mediatek/mt8901-afe-clk.c -index 24e3765544..08ff8c2fed 100644 ---- a/drivers/soundwire/mediatek/mt8901-afe-clk.c -+++ b/drivers/soundwire/mediatek/mt8901-afe-clk.c -@@ -764,6 +764,70 @@ static int mt8901_afe_disable_sdw_active_clock(struct mtk_sdw *mst) - return 0; - } - -+static int mt8901_sdw_enable_spm_request(struct mtk_sdw *mst, int link) -+{ -+ int ret; -+ -+ ret = mt8901_afe_send_spm_req(mst, AFE_SPM_CTRL_SRCCLKENA_REQ, true); -+ if (ret) { -+ dev_err(mst->dev, "[%d]request SRCCLKENA failed\n", link); -+ return ret; -+ } -+ -+ if (link == MTK_SDW_CONTROLLER_1) { -+ /* Link1 requires VCORE because the PINs are not AO */ -+ ret = mt8901_afe_send_spm_req(mst, AFE_SPM_CTRL_VCORE_REQ, -+ true); -+ if (ret) { -+ dev_err(mst->dev, "[%d]request VCORE failed\n", link); -+ mt8901_afe_send_spm_req(mst, AFE_SPM_CTRL_SRCCLKENA_REQ, -+ false); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int mt8901_sdw_disable_spm_request(struct mtk_sdw *mst, int link) -+{ -+ int ret; -+ -+ ret = mt8901_afe_send_spm_req(mst, AFE_SPM_CTRL_SRCCLKENA_REQ, false); -+ if (ret) { -+ dev_err(mst->dev, "[%d]release SRCCLKENA failed\n", link); -+ return ret; -+ } -+ -+ if (link == MTK_SDW_CONTROLLER_1) { -+ ret = mt8901_afe_send_spm_req(mst, AFE_SPM_CTRL_VCORE_REQ, -+ false); -+ if (ret) { -+ dev_err(mst->dev, "[%d]release VCORE failed\n", link); -+ mt8901_afe_send_spm_req(mst, AFE_SPM_CTRL_SRCCLKENA_REQ, -+ true); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Per-link clock bring-up and release. -+ * -+ * Every gate, mux, power domain and SPM request below is a vote sent to the -+ * SSPM firmware through the power control interface, and the firmware -+ * reference counts those votes per resource (the same model the reference -+ * driver on this platform follows, one vote per SoundWire controller). The -+ * shared resources (the main clock muxes and gates, AUD_CG_SOUNDWIRE0 that -+ * link 1 also depends on, AUD_CG_APLL2_CK) are therefore requested once per -+ * link on enable and released once per link on disable: releasing link 0 -+ * drops link 0's vote and leaves the gate on while link 1 still holds its -+ * own. No driver side count is needed for them. The one shared resource that -+ * is written directly, AFE_ON in AUDIO_ENGEN_CON0, is counted by the driver -+ * (afe_on_refcnt) for the same reason. -+ */ - static int mt8901_sdw_enable_link_clock(struct mtk_sdw *mst, int link) - { - struct mtk_sdw_link *sdw_link = &mst->links[link]; -@@ -948,4 +1012,6 @@ const struct mtk_sdw_clk_ops mt8901_clk_ops = { - .disable_link_clock = mt8901_sdw_disable_link_clock, - .enable_power_domain = mt8901_sdw_enable_power_domain, - .disable_power_domain = mt8901_sdw_disable_power_domain, -+ .enable_spm_request = mt8901_sdw_enable_spm_request, -+ .disable_spm_request = mt8901_sdw_disable_spm_request, - }; -diff --git a/drivers/soundwire/mediatek/mtk-sdw-common.h b/drivers/soundwire/mediatek/mtk-sdw-common.h -index cb012764c5..11d1d4c8b1 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-common.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-common.h -@@ -53,6 +53,7 @@ struct mtk_sdw_dai { - bool use_group_sync; - unsigned int group_sync_id; - bool need_enable_delay; -+ bool suspended; - }; - - /* -@@ -66,6 +67,8 @@ struct mtk_sdw_clk_ops { - int (*disable_link_clock)(struct mtk_sdw *mst, int link); - int (*enable_power_domain)(struct mtk_sdw *mst); - int (*disable_power_domain)(struct mtk_sdw *mst); -+ int (*enable_spm_request)(struct mtk_sdw *mst, int link); -+ int (*disable_spm_request)(struct mtk_sdw *mst, int link); - }; - - int mtk_sdw_clk_ops_select(struct mtk_sdw *mst, int hw_ver); -@@ -80,6 +83,10 @@ struct mtk_sdw { - const struct mtk_sdw_top_cfg *top_cfg; - void __iomem *top_pdi; /* base + top_cfg->pdi_base */ - void __iomem *top_con; /* base + top_cfg->con_base */ -+ unsigned int *top_pdi_reg_backup; -+ unsigned int top_pdi_reg_backup_num; -+ unsigned int *top_con_reg_backup; -+ unsigned int top_con_reg_backup_num; - const struct mtk_sdw_clk_ops *clk_ops; - u32 hw_ver; - /* group_lock: serializes group_refcnt[] group-sync allocation */ -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c -index 147a44727e..77a40e9eb5 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -523,7 +523,8 @@ static int mtk_do_config_update(struct mtk_sdw_core *core) - ret = readl_poll_timeout(core->regs + MCP_CONFIGUPDATE, val, - !(val & MCP_CONFIGUPDATE_CU), 100, 2000); - if (ret) { -- dev_err(core->dev, "config update timeout\n"); -+ dev_err(core->dev, "[%u]config update timeout\n", -+ core->bus.link_id); - return ret; - } - return 0; -@@ -537,11 +538,9 @@ static int mtk_init_clock_ctrl(struct mtk_sdw_core *core) - int r; - u32 val; - -- dev_dbg(core->dev, "mclk %d max %d row %d col %d\n", -- prop->mclk_freq, -- prop->max_clk_freq, -- prop->default_row, -- prop->default_col); -+ dev_dbg(core->dev, "[%u]mclk %d max %d row %d col %d\n", -+ bus->link_id, prop->mclk_freq, prop->max_clk_freq, -+ prop->default_row, prop->default_col); - - /* Set clock divider */ - if (bus->params.curr_dr_freq && prop->mclk_freq) { -@@ -565,7 +564,7 @@ static int mtk_init_clock_ctrl(struct mtk_sdw_core *core) - - if (prop->default_frame_rate % SDW_GSYNC_HZ) { - dev_warn(core->dev, -- "[%u] FrameRate:%u not aligned with GSYNC:%d", -+ "[%u]FrameRate:%u not aligned with GSYNC:%d", - bus->link_id, prop->default_frame_rate, SDW_GSYNC_HZ); - } - -@@ -629,7 +628,7 @@ int mtk_sdw_core_bus_reset(struct mtk_sdw_core *core) - MCP_CONTROL_SOFT_RST); - core_updatel(core, MCP_CONFIG, MCP_CONFIG_OP_MODE, - FIELD_PREP(MCP_CONFIG_OP_MODE, -- MCP_OP_MODE_CLK_LOW_DATA_OFF_KEEPER_ON)); -+ SDWC_OM_CLK_LOW_DATA_OFF_KEEPER_ON)); - ret = mtk_do_config_update(core); - if (ret) - goto out; -@@ -664,7 +663,7 @@ static int mtk_init_config_setting(struct mtk_sdw_core *core) - mask = MCP_CONFIG_MCR | MCP_CONFIG_OP_MODE; - - val = FIELD_PREP(MCP_CONFIG_MCR, SDW_DEFAULT_MAX_CMD_RETRY) | -- FIELD_PREP(MCP_CONFIG_OP_MODE, MCP_OP_MODE_NORMAL); -+ FIELD_PREP(MCP_CONFIG_OP_MODE, SDWC_OM_NORMAL); - - core_updatel(core, MCP_CONFIG, mask, val); - -@@ -875,8 +874,9 @@ static void mtk_sdw_slave_status_work(struct work_struct *work) - - core_writel(core, MCP_SLAVEINTSTAT0, stat0); - core_writel(core, MCP_SLAVEINTSTAT1, stat1); -- dev_dbg_ratelimited(core->dev, "Slave intstat0: 0x%x, intstat1 0x%x\n", -- stat0, stat1); -+ dev_dbg_ratelimited(core->dev, -+ "[%u]Slave intstat0: 0x%x, intstat1 0x%x\n", -+ core->bus.link_id, stat0, stat1); - - slv_intstat = ((u64)stat1 << 32) | stat0; - -@@ -925,7 +925,7 @@ static void mtk_sdw_slave_status_work(struct work_struct *work) - if (dev0_stat == MCP_SLAVESTAT_ATTACHED) { - slv_intstat = MCP_SLAVEINTSTAT_ATTACHED; - dev_info(core->dev, -- "[%u] slave attached Dev0Stat:0x%x Retries:%d", -+ "[%u]slave attached Dev0Stat:0x%x Retries:%d", - core->bus.link_id, dev0_stat, retries); - } else { - break; -@@ -1307,3 +1307,75 @@ void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, - - core_updatel(core, offset, mask, val); - } -+ -+/* passing sync=false without a follow up config update would leave the reset -+ * pending. -+ */ -+static int mtk_sdw_reset_master(struct mtk_sdw_core *core, bool sync) -+{ -+ int ret = 0; -+ -+ core_updatel(core, MCP_CONTROL, MCP_CONTROL_SOFT_RST, -+ MCP_CONTROL_SOFT_RST); -+ -+ if (sync) { -+ ret = mtk_do_config_update(core); -+ if (ret) { -+ dev_err(core->dev, -+ "do_config_update failed ret = %d\n", ret); -+ } -+ } -+ -+ return ret; -+} -+ -+static int mtk_sdw_change_op_mode(struct mtk_sdw_core *core, int mode) -+{ -+ u32 val; -+ u32 mask; -+ -+ mask = MCP_CONFIG_OP_MODE; -+ -+ val = FIELD_PREP(MCP_CONFIG_OP_MODE, mode); -+ -+ core_updatel(core, MCP_CONFIG, mask, val); -+ -+ return mtk_do_config_update(core); -+} -+ -+int mtk_sdw_shutdown_master(struct mtk_sdw_core *core) -+{ -+ int ret; -+ -+ ret = mtk_sdw_reset_master(core, false); -+ if (ret) -+ return ret; -+ -+ ret = mtk_sdw_change_op_mode(core, SDWC_OM_ALL_OFF); -+ if (ret) { -+ dev_err(core->dev, "change to SDWC_OM_ALL_OFF fail, ret = %d\n", -+ ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int mtk_sdw_reinit_master(struct mtk_sdw_core *core) -+{ -+ int ret; -+ -+ /* IRQ should be enabled first */ -+ mtk_sdw_enable_irq(core, true); -+ -+ ret = mtk_sdw_core_hw_init(core); -+ if (ret) { -+ dev_err(core->dev, -+ "[%u]mtk_sdw_core_hw_init failed, ret = %d\n", -+ core->bus.link_id, ret); -+ mtk_sdw_enable_irq(core, false); -+ return ret; -+ } -+ -+ return 0; -+} -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.h b/drivers/soundwire/mediatek/mtk-sdw-core.h -index c3ab0eb3c7..45f0ea0b84 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-core.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.h -@@ -10,6 +10,17 @@ - - #include - -+enum { -+ SDWC_OM_NORMAL = 0, -+ SDWC_OM_DATA_OFF, -+ SDWC_OM_CLK_DATA_LOW, -+ SDWC_OM_CLK_DATA_OFF, -+ SDWC_OM_KEEPER_OFF, -+ SDWC_OM_CLK_LOW_DATA_OFF_KEEPER_ON, -+ SDWC_OM_CLK_LOW_DATA_HIGH, -+ SDWC_OM_ALL_OFF, -+}; -+ - #define SDW_GSYNC_HZ (8000) - #define SDW_DEFAULT_MAX_CMD_RETRY (5) - /* ======================================================================= -@@ -75,8 +86,6 @@ - /* MCP_CONFIG */ - #define MCP_CONFIG_OP_MODE GENMASK(2, 0) - #define MCP_CONFIG_MCR GENMASK(27, 24) --#define MCP_OP_MODE_NORMAL 0 --#define MCP_OP_MODE_CLK_LOW_DATA_OFF_KEEPER_ON 5 - - /* MCP_CONTROL */ - #define MCP_CONTROL_CMD_ACCEPT_MODE BIT(1) -@@ -245,7 +254,7 @@ extern const struct sdw_master_port_ops mtk_sdw_core_port_ops; - */ - #define MTK_SDW_ATTACH_CHECK_DELAY_MS 2000 - --int mtk_sdw_core_init(struct mtk_sdw_core *core); -+int mtk_sdw_core_init(struct mtk_sdw_core *core); - int mtk_sdw_core_hw_init(struct mtk_sdw_core *core); - int mtk_sdw_core_bus_reset(struct mtk_sdw_core *core); - void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable); -@@ -253,12 +262,13 @@ void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable); - irqreturn_t mtk_sdw_core_irq(int irq, void *data); - void mtk_sdw_configure_port_params(struct mtk_sdw_core *core, - struct mtk_sdw_port_params *params, u32 dir); -- - void mtk_sdw_configure_pdi_params(struct mtk_sdw_core *core, - struct mtk_sdw_pdi_params *params); - void mtk_sdw_clear_pdi_settings(struct mtk_sdw_core *core, - struct mtk_sdw_pdi_params *pdi); - void mtk_sdw_core_dump_dpn_regs(struct mtk_sdw_core *core, unsigned int port, - const char *tag); -+int mtk_sdw_shutdown_master(struct mtk_sdw_core *core); -+int mtk_sdw_reinit_master(struct mtk_sdw_core *core); - - #endif /* __MTK_SDW_CORE_H */ -diff --git a/drivers/soundwire/mediatek/mtk-sdw-top.c b/drivers/soundwire/mediatek/mtk-sdw-top.c -index edc412f4e1..2c38a93b96 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-top.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-top.c -@@ -14,6 +14,33 @@ - #include - #include "mtk-sdw-top.h" - -+/* these two arrays cover everything written by top_init and configure_pdi */ -+static const unsigned int mtk_sdw_top_con_backup_regs[] = { -+ SDW_TOP_CON0, -+ SDW_TOP_CON1, -+}; -+ -+static const unsigned int mtk_sdw_top_pdi_backup_regs[] = { -+ SDW_TOP_PDIN_CON0(0), -+ SDW_TOP_PDIN_CON0(1), -+ SDW_TOP_PDIN_CON0(2), -+ SDW_TOP_PDIN_CON0(3), -+ SDW_TOP_PDIN_CON0(4), -+ SDW_TOP_PDIN_CON0(5), -+ SDW_TOP_PDIN_CON0(6), -+ SDW_TOP_PDIN_CON0(7), -+ SDW_TOP_PDIN_CON0(8), -+ SDW_TOP_PDIN_CON0(9), -+ SDW_TOP_PDIN_CON0(10), -+ SDW_TOP_PDIN_CON0(11), -+ SDW_TOP_PDIN_CON0(12), -+ SDW_TOP_PDIN_CON0(13), -+ SDW_TOP_PDIN_CON0(14), -+ SDW_TOP_PDIN_CON0(15), -+ SDW_TOP_PDIN_CON0(16), -+ SDW_TOP_PDIN_CON0(17), -+}; -+ - static const struct mtk_sdw_top_cfg mtk_sdw_top_cfgs[MTK_SDW_TOP_VER_MAX] = { - [MTK_SDW_TOP_VER_0] = { - .name = "hw_8901", -@@ -90,13 +117,13 @@ int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver) - return 0; - } - --void mtk_sdw_top_init_settings(struct mtk_sdw *mst) -+static void mtk_sdw_top_init_settings(struct mtk_sdw *mst) - { - topcon_updatel(mst, SDW_TOP_CON0, SDW_TOP_CON0_GSYNC_DIR_CTRL, - SDW_TOP_CON0_GSYNC_DIR_CTRL); - } - --void mtk_sdw_top_configure_delays(struct mtk_sdw *mst) -+static void mtk_sdw_top_configure_delays(struct mtk_sdw *mst) - { - u32 val = 0; - u32 mask; -@@ -120,6 +147,33 @@ void mtk_sdw_top_configure_delays(struct mtk_sdw *mst) - topcon_updatel(mst, top_reg->phy_delay_reg, mask, val); - } - -+int mtk_sdw_top_init(struct mtk_sdw *mst) -+{ -+ struct device *dev = mst->dev; -+ -+ mst->top_pdi_reg_backup_num = ARRAY_SIZE(mtk_sdw_top_pdi_backup_regs); -+ mst->top_con_reg_backup_num = ARRAY_SIZE(mtk_sdw_top_con_backup_regs); -+ -+ mst->top_pdi_reg_backup = -+ devm_kcalloc(dev, mst->top_pdi_reg_backup_num, -+ sizeof(*mst->top_pdi_reg_backup), -+ GFP_KERNEL); -+ if (!mst->top_pdi_reg_backup) -+ return -ENOMEM; -+ -+ mst->top_con_reg_backup = -+ devm_kcalloc(dev, mst->top_con_reg_backup_num, -+ sizeof(*mst->top_con_reg_backup), -+ GFP_KERNEL); -+ if (!mst->top_con_reg_backup) -+ return -ENOMEM; -+ -+ mtk_sdw_top_init_settings(mst); -+ mtk_sdw_top_configure_delays(mst); -+ -+ return 0; -+} -+ - void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, - struct mtk_sdw_top_pdi_params *param) - { -@@ -299,3 +353,29 @@ int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id) - - return 0; - } -+ -+void mtk_sdw_top_backup_regs(struct mtk_sdw *mst) -+{ -+ int i; -+ -+ for (i = 0; i < mst->top_con_reg_backup_num; i++) -+ mst->top_con_reg_backup[i] = -+ topcon_readl(mst, mtk_sdw_top_con_backup_regs[i]); -+ -+ for (i = 0; i < mst->top_pdi_reg_backup_num; i++) -+ mst->top_pdi_reg_backup[i] = -+ toppdi_readl(mst, mtk_sdw_top_pdi_backup_regs[i]); -+} -+ -+void mtk_sdw_top_restore_regs(struct mtk_sdw *mst) -+{ -+ int i; -+ -+ for (i = 0; i < mst->top_con_reg_backup_num; i++) -+ topcon_writel(mst, mtk_sdw_top_con_backup_regs[i], -+ mst->top_con_reg_backup[i]); -+ -+ for (i = 0; i < mst->top_pdi_reg_backup_num; i++) -+ toppdi_writel(mst, mtk_sdw_top_pdi_backup_regs[i], -+ mst->top_pdi_reg_backup[i]); -+} -diff --git a/drivers/soundwire/mediatek/mtk-sdw-top.h b/drivers/soundwire/mediatek/mtk-sdw-top.h -index f12c090d60..b643b5cfc0 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-top.h -+++ b/drivers/soundwire/mediatek/mtk-sdw-top.h -@@ -92,8 +92,7 @@ struct mtk_sdw_top_cfg { - }; - - int mtk_sdw_top_config_select(struct mtk_sdw *mst, int hw_ver); --void mtk_sdw_top_init_settings(struct mtk_sdw *mst); --void mtk_sdw_top_configure_delays(struct mtk_sdw *mst); -+int mtk_sdw_top_init(struct mtk_sdw *mst); - void mtk_sdw_top_configure_pdi(struct mtk_sdw *mst, u32 pdi, - struct mtk_sdw_top_pdi_params *param); - int mtk_sdw_top_group_sync_config_get(struct mtk_sdw *mst, u8 id, u32 *cfg); -@@ -101,5 +100,7 @@ int mtk_sdw_top_group_sync_acquire(struct mtk_sdw *mst, bool is_tx); - void mtk_sdw_top_group_sync_release(struct mtk_sdw *mst, u8 id); - int mtk_sdw_top_enable_stream(struct mtk_sdw *mst, int dai_id); - int mtk_sdw_top_disable_stream(struct mtk_sdw *mst, int dai_id); -+void mtk_sdw_top_backup_regs(struct mtk_sdw *mst); -+void mtk_sdw_top_restore_regs(struct mtk_sdw *mst); - - #endif /* __MTK_SDW_TOP_H */ -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index 4fe32a5270..71671ebb09 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -23,6 +24,7 @@ - #include "mtk-sdw.h" - #include "mtk-sdw-mach.h" - #include "mtk-sdw-top.h" -+#include "bus.h" - - /* - * Restart (SOFT_RST + quiesce + re-init) every link at probe instead of -@@ -185,7 +187,8 @@ static int mtk_sdw_enable_top_clock(struct mtk_sdw *mst, int link) - - ret = mst->clk_ops->enable_link_clock(mst, link); - if (ret) -- dev_err(mst->dev, "failed to enable top clock, ret %d\n", ret); -+ dev_err(mst->dev, "[%d]failed to enable top clock, ret %d\n", -+ link, ret); - - return ret; - } -@@ -196,7 +199,8 @@ static int mtk_sdw_disable_top_clock(struct mtk_sdw *mst, int link) - - ret = mst->clk_ops->disable_link_clock(mst, link); - if (ret) -- dev_err(mst->dev, "failed to disable top clock, ret %d\n", ret); -+ dev_err(mst->dev, "[%d]failed to disable top clock, ret %d\n", -+ link, ret); - - return ret; - } -@@ -223,6 +227,52 @@ static int mtk_sdw_disable_reg_clock(struct mtk_sdw *mst) - return ret; - } - -+static int mtk_sdw_enable_power(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->enable_power_domain(mst); -+ if (ret) -+ dev_err(mst->dev, "failed to enable power, ret %d\n", ret); -+ -+ return ret; -+} -+ -+static int mtk_sdw_disable_power(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->disable_power_domain(mst); -+ if (ret) -+ dev_err(mst->dev, "failed to disable power, ret %d\n", ret); -+ -+ return ret; -+} -+ -+static int mtk_sdw_enable_spm_request(struct mtk_sdw *mst, int link) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->enable_spm_request(mst, link); -+ if (ret) -+ dev_err(mst->dev, "[%d]failed to enable spm reqest, ret %d\n", -+ link, ret); -+ -+ return ret; -+} -+ -+static int mtk_sdw_disable_spm_request(struct mtk_sdw *mst, int link) -+{ -+ int ret; -+ -+ ret = mst->clk_ops->disable_spm_request(mst, link); -+ if (ret) -+ dev_err(mst->dev, "[%d]failed to disable spm request, ret %d\n", -+ link, ret); -+ -+ return ret; -+} -+ - /* ======================================================================= - * ASoC DAI layer (ALSA <-> SoundWire stream binding) - * ======================================================================= -@@ -342,6 +392,7 @@ static int mtk_sdw_dai_hw_params(struct snd_pcm_substream *substream, - unsigned int pdi_begin; - unsigned int last_pdi; - -+ mdai->suspended = false; - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - dir = SDW_DATA_DIR_RX; - else -@@ -481,10 +532,47 @@ static int mtk_sdw_dai_hw_free(struct snd_pcm_substream *substream, - dev_err(dai->dev, "remove manager from stream %s failed: %d\n", - mdai->sruntime->name, ret); - -+ mdai->suspended = false; - mtk_sdw_dai_release_params(mst, mdai); - return ret; - } - -+/* -+ * If we need to recover an active stream, the settings for TOP_PDI and TOP_CON -+ * are managed in the restore_regs function, while the others are managed in -+ * the prepare callback. -+ */ -+static int mtk_sdw_dai_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct mtk_sdw *mst = snd_soc_dai_get_drvdata(dai); -+ struct mtk_sdw_dai *mdai = &mst->dais[dai->id]; -+ struct mtk_sdw_port_params mtk_port_param = { 0 }; -+ int i, dir; -+ -+ if (!mdai->suspended) -+ return 0; -+ -+ mdai->suspended = false; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ dir = SDW_DATA_DIR_RX; -+ else -+ dir = SDW_DATA_DIR_TX; -+ -+ mtk_port_param.port_num = mdai->port_num; -+ mtk_port_param.bpt_payload_type = 0; -+ mtk_port_param.bpt_en = true; -+ mtk_sdw_configure_port_params(&mdai->link->core, &mtk_port_param, dir); -+ -+ for (i = 0; i < mdai->pdi_count; i++) { -+ mtk_sdw_configure_pdi_params(&mdai->link->core, -+ &mdai->pdi_params[i]); -+ } -+ -+ return 0; -+} -+ - /* configure top stream here, it can be called before dai_link ops */ - static int mtk_sdw_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -@@ -500,8 +588,10 @@ static int mtk_sdw_dai_trigger(struct snd_pcm_substream *substream, int cmd, - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - return mtk_sdw_top_enable_stream(mst, dai->id); -- case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: -+ mdai->suspended = true; -+ fallthrough; -+ case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - return mtk_sdw_top_disable_stream(mst, dai->id); - default: -@@ -512,6 +602,7 @@ static int mtk_sdw_dai_trigger(struct snd_pcm_substream *substream, int cmd, - static const struct snd_soc_dai_ops mtk_sdw_dai_ops = { - .hw_params = mtk_sdw_dai_hw_params, - .hw_free = mtk_sdw_dai_hw_free, -+ .prepare = mtk_sdw_dai_prepare, - .trigger = mtk_sdw_dai_trigger, - .set_stream = mtk_sdw_set_sdw_stream, - .get_stream = mtk_sdw_get_sdw_stream, -@@ -901,24 +992,25 @@ static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) - core->bus.prop.mclk_freq = SDW_DEFAULT_MCLK_CLK_FREQ; - - ret = mtk_sdw_enable_top_clock(mst, idx); -- if (ret) { -- dev_err(mst->dev, "IP%d: enable top clock failed: %d\n", -- idx, ret); -+ if (ret) - return ret; -- } -+ -+ ret = mtk_sdw_enable_spm_request(mst, idx); -+ if (ret) -+ goto err_spm; - - core->bus.dev = mst->dev; - ret = sdw_bus_master_add(&core->bus, mst->dev, mst->dev->fwnode); - if (ret) { - dev_err(mst->dev, "IP%d: bus_master_add failed: %d\n", - idx, ret); -- goto err_disable_top_clock; -+ goto err_bus; - } - - ret = mtk_sdw_core_hw_init(core); - if (ret) { - sdw_bus_master_delete(&core->bus); -- goto err_disable_top_clock; -+ goto err_bus; - } - - /* -@@ -940,7 +1032,7 @@ static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) - ret = mtk_sdw_core_bus_reset(core); - if (ret) { - sdw_bus_master_delete(&core->bus); -- goto err_disable_top_clock; -+ goto err_bus; - } - } - -@@ -953,8 +1045,11 @@ static int mtk_sdw_link_init(struct mtk_sdw *mst, int idx) - dev_info(mst->dev, "IP%d: SoundWire bus ready\n", idx); - return 0; - --err_disable_top_clock: -+err_bus: -+ mtk_sdw_disable_spm_request(mst, idx); -+err_spm: - mtk_sdw_disable_top_clock(mst, idx); -+ - return ret; - } - -@@ -965,6 +1060,8 @@ static void mtk_sdw_link_deinit(struct mtk_sdw *mst, int idx) - cancel_delayed_work_sync(&core->attach_check_work); - mtk_sdw_enable_irq(core, false); - sdw_bus_master_delete(&core->bus); -+ mtk_sdw_disable_spm_request(mst, idx); -+ mtk_sdw_disable_top_clock(mst, idx); - } - - static void mtk_init_sdw_master(struct mtk_sdw *mst) -@@ -1155,7 +1252,8 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - struct mtk_sdw *mst; - u32 hw_ver = MTK_SDW_HW_VER_MT8901; - u32 mmio[2]; -- int i, ret; -+ int i = 0; -+ int ret; - bool clk_on; - - mst = devm_kzalloc(dev, sizeof(*mst), GFP_KERNEL); -@@ -1222,8 +1320,11 @@ static int mtk_sdw_probe_controller(struct platform_device *pdev) - - clk_on = true; - -- mtk_sdw_top_init_settings(mst); -- mtk_sdw_top_configure_delays(mst); -+ ret = mtk_sdw_top_init(mst); -+ if (ret) { -+ dev_err(dev, "failed to init sdw top, ret %d\n", ret); -+ goto err; -+ } - - for (i = 0; i < mst->num_links; i++) { - int irq = platform_get_irq(pdev, i); -@@ -1342,18 +1443,239 @@ static void mtk_sdw_remove(struct platform_device *pdev) - mtk_sdw_link_deinit(mst, i); - } - -+static int mtk_sdw_enter_low_power_mode(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_link *link = &mst->links[idx]; -+ struct mtk_sdw_core *core = &link->core; -+ int ret; -+ -+ /* -+ * Cancel the attach check before taking reset_lock (its work takes -+ * the lock too), then hold the lock across quiesce, shutdown and -+ * power-down so no other reset initiator can restart the link -+ * halfway through. -+ */ -+ cancel_delayed_work_sync(&core->attach_check_work); -+ mutex_lock(&core->reset_lock); -+ mtk_sdw_enable_irq(core, false); -+ -+ ret = mtk_sdw_shutdown_master(core); -+ if (ret) { -+ dev_err(mst->dev, "shutdown master failed, ret = %d\n", ret); -+ /* -+ * The config update may have applied SOFT_RST and ALL_OFF even -+ * though it timed out: rebuild the controller while its clocks -+ * and power votes are still held (reinit re-enables the IRQs). -+ */ -+ goto err_spm; -+ } -+ -+ ret = mtk_sdw_disable_spm_request(mst, idx); -+ if (ret) -+ goto err_spm; -+ -+ ret = mtk_sdw_disable_top_clock(mst, idx); -+ if (ret) -+ goto err_top; -+ -+ mutex_unlock(&core->reset_lock); -+ return 0; -+ -+err_top: -+ if (mtk_sdw_enable_spm_request(mst, idx)) -+ dev_err(mst->dev, "[%d]failed to restore SPM on error path", -+ idx); -+err_spm: -+ if (mtk_sdw_reinit_master(core)) -+ dev_err(mst->dev, "[%d]failed to reinit master on error path", -+ idx); -+ -+ mutex_unlock(&core->reset_lock); -+ return ret; -+} -+ -+static int mtk_sdw_exit_low_power_mode(struct mtk_sdw *mst, int idx) -+{ -+ struct mtk_sdw_link *link = &mst->links[idx]; -+ struct mtk_sdw_core *core = &link->core; -+ int ret; -+ -+ /* Same lock as the suspend side: the restore is one sequence too. */ -+ mutex_lock(&core->reset_lock); -+ -+ ret = mtk_sdw_enable_top_clock(mst, idx); -+ if (ret) -+ goto out; -+ -+ ret = mtk_sdw_enable_spm_request(mst, idx); -+ if (ret) { -+ mtk_sdw_disable_top_clock(mst, idx); -+ goto out; -+ } -+ -+ sdw_clear_slave_status(&core->bus, SDW_UNATTACH_REQUEST_MASTER_RESET); -+ -+ ret = mtk_sdw_reinit_master(core); -+ if (ret) { -+ dev_err(mst->dev, "mtk_sdw_reinit_master failed: %d\n", ret); -+ mtk_sdw_disable_spm_request(mst, idx); -+ mtk_sdw_disable_top_clock(mst, idx); -+ } -+ -+out: -+ mutex_unlock(&core->reset_lock); -+ return ret; -+} -+ -+static int mtk_sdw_backup_hw_settings(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mtk_sdw_enable_reg_clock(mst); -+ if (ret) -+ return ret; -+ -+ mtk_sdw_top_backup_regs(mst); -+ -+ ret = mtk_sdw_disable_reg_clock(mst); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int mtk_sdw_restore_hw_settings(struct mtk_sdw *mst) -+{ -+ int ret; -+ -+ ret = mtk_sdw_enable_reg_clock(mst); -+ if (ret) -+ return ret; -+ -+ mtk_sdw_top_restore_regs(mst); -+ -+ ret = mtk_sdw_disable_reg_clock(mst); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int mtk_sdw_suspend(struct device *dev) -+{ -+ struct mtk_sdw *mst = dev_get_drvdata(dev); -+ int i, ret; -+ -+ /* 1. backup setting */ -+ ret = mtk_sdw_backup_hw_settings(mst); -+ if (ret) { -+ dev_err(dev, "backup hw settings failed: %d\n", ret); -+ return ret; -+ } -+ -+ /* -+ * The controller shutdown below wipes every configured port and PDI. -+ * Only running streams get TRIGGER_SUSPEND; a stream that is prepared -+ * but idle does not, so flag every configured DAI here and let the -+ * prepare callback rebuild its port state on the next start. -+ */ -+ for (i = 0; i < mst->num_dais; i++) -+ if (mst->dais[i].pdi_count) -+ mst->dais[i].suspended = true; -+ -+ /* 2. enter low power per link */ -+ for (i = 0; i < mst->num_links; i++) { -+ ret = mtk_sdw_enter_low_power_mode(mst, i); -+ if (ret) { -+ dev_err(dev, "[%d] enter low power mode failed: %d\n", -+ i, ret); -+ while (--i >= 0) -+ mtk_sdw_exit_low_power_mode(mst, i); -+ return ret; -+ } -+ } -+ -+ /* -+ * 3. disable mtcmos per link: the SSPM power refcount is one vote -+ * per link (the firmware initializes it to the link count, and the -+ * reference driver relinquishes once per SoundWire IP), so vote per -+ * link, not per master, or the count never reaches zero and the -+ * SoC cannot enter PPS7/PPS8. -+ */ -+ for (i = 0; i < mst->num_links; i++) { -+ ret = mtk_sdw_disable_power(mst); -+ if (ret) { -+ while (--i >= 0) -+ mtk_sdw_enable_power(mst); -+ -+ for (i = 0; i < mst->num_links; i++) -+ mtk_sdw_exit_low_power_mode(mst, i); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int mtk_sdw_resume(struct device *dev) -+{ -+ struct mtk_sdw *mst = dev_get_drvdata(dev); -+ int i, ret; -+ -+ /* 1. enable mtcmos per link */ -+ for (i = 0; i < mst->num_links; i++) { -+ ret = mtk_sdw_enable_power(mst); -+ if (ret) { -+ while (--i >= 0) -+ mtk_sdw_disable_power(mst); -+ return ret; -+ } -+ } -+ -+ /* 2. restore setting */ -+ ret = mtk_sdw_restore_hw_settings(mst); -+ if (ret) { -+ dev_err(dev, "restore hw settings failed: %d\n", ret); -+ goto err_power; -+ } -+ -+ /* 3. exit low power per link */ -+ for (i = 0; i < mst->num_links; i++) { -+ ret = mtk_sdw_exit_low_power_mode(mst, i); -+ if (ret) { -+ dev_err(dev, "[%d] exit low power mode failed: %d\n", -+ i, ret); -+ while (--i >= 0) -+ mtk_sdw_enter_low_power_mode(mst, i); -+ goto err_power; -+ } -+ } -+ -+ return 0; -+err_power: -+ for (i = 0; i < mst->num_links; i++) -+ mtk_sdw_disable_power(mst); -+ -+ return ret; -+} -+ - static const struct acpi_device_id mtk_sdw_acpi_match[] = { - { "NVDA9100", 0 }, - { } - }; - MODULE_DEVICE_TABLE(acpi, mtk_sdw_acpi_match); - -+static const struct dev_pm_ops mtk_sdw_pm_ops = { -+ SYSTEM_SLEEP_PM_OPS(mtk_sdw_suspend, mtk_sdw_resume) -+}; -+ - static struct platform_driver mtk_sdw_driver = { - .probe = mtk_sdw_probe, - .remove = mtk_sdw_remove, - .driver = { - .name = "mtk-soundwire", - .acpi_match_table = mtk_sdw_acpi_match, -+ .pm = &mtk_sdw_pm_ops, - }, - }; - module_platform_driver(mtk_sdw_driver); -From 6cf51bf792845c6e5fddf2719952f32832dd80c2 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Fri, 11 Sep 2026 14:07:09 -0700 -Subject: [PATCH] NVIDIA: SAUCE: soundwire: mediatek: reset the PDI FIFO in - prepare - -BugLink: https://bugs.launchpad.net/bugs/2166301 - -A stop/start cycle on an open PCM (desktop sound test, PipeWire) never -passes through hw_params/hw_free, and the prepare callback only -reprograms the DAI when it resumes from system sleep, so the PDI FIFO -is never reset between cycles. ASoC runs the STOP triggers in reverse -order: this CPU DAI disables the PDI engen first, and the dai_link -trigger then stops the manager port with sdw_disable_stream(), so -whatever was in flight between the two stays in the FIFO. On the -2-channel interleaved jack PDI (DL1 -> PDI5 -> RT712 DP5) an odd -residue shifts the word phase, and from the next START on the left -sample lands in the right slot. Observed as a left/right swap after a -few rapid clicks on "Test Front Left", and reproduced at the ALSA level -with the PCM held open: the channel alternates on every -drain/prepare/start cycle. - -Reset every PDI of the DAI in prepare, which runs after the previous -STOP has completed on both the PDI and the manager port side, so every -START begins with an empty FIFO. Eight consecutive held-open cycles -stay on the left channel with this change. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/soundwire/mediatek/mtk-sdw.c | 39 ++++++++++++++++++---------- - 1 file changed, 25 insertions(+), 14 deletions(-) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw.c b/drivers/soundwire/mediatek/mtk-sdw.c -index 71671ebb09..a14df4834c 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw.c -+++ b/drivers/soundwire/mediatek/mtk-sdw.c -@@ -550,25 +550,36 @@ static int mtk_sdw_dai_prepare(struct snd_pcm_substream *substream, - struct mtk_sdw_port_params mtk_port_param = { 0 }; - int i, dir; - -- if (!mdai->suspended) -- return 0; -+ if (mdai->suspended) { -+ mdai->suspended = false; - -- mdai->suspended = false; -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ dir = SDW_DATA_DIR_RX; -+ else -+ dir = SDW_DATA_DIR_TX; - -- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -- dir = SDW_DATA_DIR_RX; -- else -- dir = SDW_DATA_DIR_TX; -+ mtk_port_param.port_num = mdai->port_num; -+ mtk_port_param.bpt_payload_type = 0; -+ mtk_port_param.bpt_en = true; -+ mtk_sdw_configure_port_params(&mdai->link->core, &mtk_port_param, -+ dir); -+ } - -- mtk_port_param.port_num = mdai->port_num; -- mtk_port_param.bpt_payload_type = 0; -- mtk_port_param.bpt_en = true; -- mtk_sdw_configure_port_params(&mdai->link->core, &mtk_port_param, dir); -- -- for (i = 0; i < mdai->pdi_count; i++) { -+ /* -+ * ASoC runs the STOP triggers in reverse order: this DAI disables the -+ * PDI engen first and the dai_link trigger then stops the manager port -+ * (sdw_disable_stream), so whatever was in flight between the two -+ * stays in the PDI FIFO. On a 2-channel interleaved PDI an odd number -+ * of stale words shifts the word phase and the next START swaps left -+ * and right for the rest of the PCM's life. A stop/start cycle on an -+ * open PCM never passes hw_params/hw_free, so reset every PDI here, -+ * where the previous STOP has completed on both sides and nothing -+ * feeds or drains the FIFO. Re-writing the same channel mask and port -+ * number is harmless. -+ */ -+ for (i = 0; i < mdai->pdi_count; i++) - mtk_sdw_configure_pdi_params(&mdai->link->core, - &mdai->pdi_params[i]); -- } - - return 0; - } -From 92da0c561865da671ca18dadb5aa2c8ae2becb02 Mon Sep 17 00:00:00 2001 -From: Ryan -Date: Fri, 2 Oct 2026 00:58:13 -0400 -Subject: [PATCH] ASoC: mediatek: mt8901: follow the - asoc_sdw_parse_sdw_endpoints() change - -asoc_sdw_parse_sdw_endpoints() now takes the device and the machine's -asoc_sdw_mc_private instead of the card. Pass them like the AMD legacy -SoundWire machine driver does. ---- - sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -index cf374b3eee..94143829be 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -+++ b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -@@ -453,6 +453,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, - - static int soc_card_dai_links_create(struct snd_soc_card *card) - { -+ struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); - struct device *dev = card->dev; - int sdw_be_num = 0; - struct asoc_sdw_endpoint *soc_ends __free(kfree) = NULL; -@@ -499,7 +500,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) - if (!soc_aux) - return -ENOMEM; - -- ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, -+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, - &num_confs); - if (ret < 0) { - dev_err(dev, "failed to parse sdw devices/endpoints: %d\n", diff --git a/kernel/1031-ALSA-hda-acpi-add-runtime-PM-suspend-resume-to-the-ACPI-controller.patch b/kernel/1031-ALSA-hda-acpi-add-runtime-PM-suspend-resume-to-the-ACPI-controller.patch deleted file mode 100644 index 9b612a9..0000000 --- a/kernel/1031-ALSA-hda-acpi-add-runtime-PM-suspend-resume-to-the-ACPI-controller.patch +++ /dev/null @@ -1,100 +0,0 @@ -From a41da0bb086e7c170755c4d2bbb0520e82a2a738 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Sat, 12 Sep 2026 11:21:20 -0700 -Subject: [PATCH] ALSA: hda/acpi: add runtime PM suspend/resume to the ACPI - controller - -The hda-acpi platform driver never enables runtime PM, so -pm_runtime_force_suspend() in hda_acpi_suspend() skips the runtime -callbacks. On resume the controller is therefore never re-initialised: -azx_init_chip() is called only at probe time, so after S3 the codec -verbs time out and audio is dead until the driver is rebound. - -Add explicit runtime_suspend/runtime_resume callbacks and invoke them -from the system-sleep paths, mirroring the pattern used by snd-hda-intel. -Tested on an arm64 platform with the NVDA2014 controller: resume latency -drops from 81.5 s to 3.6 s and audio is live immediately after wake. - -Signed-off-by: David Cemin -Link: https://patch.msgid.link/20260912182120.1156356-1-dcemin@nvidia.com -Signed-off-by: Takashi Iwai ---- - sound/hda/controllers/acpi.c | 41 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 41 insertions(+) - -diff --git a/sound/hda/controllers/acpi.c b/sound/hda/controllers/acpi.c -index 505cc97e0ee9..04b261dde22e 100644 ---- a/sound/hda/controllers/acpi.c -+++ b/sound/hda/controllers/acpi.c -@@ -266,6 +266,38 @@ static void hda_acpi_shutdown(struct platform_device *pdev) - azx_stop_chip(chip); - } - -+static int hda_acpi_runtime_suspend(struct device *dev) -+{ -+ struct snd_card *card = dev_get_drvdata(dev); -+ struct azx *chip = card->private_data; -+ -+ if (chip && chip->running) { -+ /* enable controller wake up event */ -+ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | -+ STATESTS_INT_MASK); -+ -+ azx_stop_chip(chip); -+ azx_enter_link_reset(chip); -+ } -+ -+ return 0; -+} -+ -+static int hda_acpi_runtime_resume(struct device *dev) -+{ -+ struct snd_card *card = dev_get_drvdata(dev); -+ struct azx *chip = card->private_data; -+ -+ if (chip && chip->running) { -+ azx_init_chip(chip, 1); -+ /* disable controller wake up event */ -+ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & -+ ~STATESTS_INT_MASK); -+ } -+ -+ return 0; -+} -+ - static int hda_acpi_suspend(struct device *dev) - { - struct snd_card *card = dev_get_drvdata(dev); -@@ -274,6 +306,12 @@ static int hda_acpi_suspend(struct device *dev) - rc = pm_runtime_force_suspend(dev); - if (rc < 0) - return rc; -+ /* -+ * Runtime PM is never enabled for this device, so the force_suspend -+ * above does not reach the runtime callback; stop the controller -+ * explicitly. -+ */ -+ hda_acpi_runtime_suspend(dev); - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - - return 0; -@@ -287,6 +325,8 @@ static int hda_acpi_resume(struct device *dev) - rc = pm_runtime_force_resume(dev); - if (rc < 0) - return rc; -+ /* See hda_acpi_suspend(): re-init the controller explicitly. */ -+ hda_acpi_runtime_resume(dev); - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - - return 0; -@@ -294,6 +334,7 @@ static int hda_acpi_resume(struct device *dev) - - static const struct dev_pm_ops hda_acpi_pm = { - SYSTEM_SLEEP_PM_OPS(hda_acpi_suspend, hda_acpi_resume) -+ RUNTIME_PM_OPS(hda_acpi_runtime_suspend, hda_acpi_runtime_resume, NULL) - }; - - static const struct hda_data nvidia_hda_data = { --- -2.56.0 - diff --git a/kernel/1032-ASoC-cs35l56-Wait-for-firmware-timer-expiry-before-system-suspend.patch b/kernel/1032-ASoC-cs35l56-Wait-for-firmware-timer-expiry-before-system-suspend.patch deleted file mode 100644 index 4d74449..0000000 --- a/kernel/1032-ASoC-cs35l56-Wait-for-firmware-timer-expiry-before-system-suspend.patch +++ /dev/null @@ -1,239 +0,0 @@ -From 40a4c0dd142091256e08d470f60fa3fcabd7f945 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 9 Oct 2026 14:22:24 -0400 -Subject: [PATCH] ASoC: cs35l56: Wait for firmware timer expiry before system - suspend - -On CS35L5x firmware older than 3.13.7 (B0 silicon) and 4.7.16 (B2 silicon) -a SoundWire bus reset is not allowed within 250ms of the last firmware -timer start. - -This is already avoided during runtime suspend by the various idle -timeouts. System suspend can happen at any time so needs special -protection. The driver cannot cancel the firmware timer, so it must wait -long enough for the timer to expire. - -The delay is placed in the suspend stage because typically this has less -impact on end users than delays in resuming. The amp is in PS3 power -state when suspending and no new timers will be started in this state. -An extra 10ms is added to the delay to avoid a race on the exact instant -the firmware timer expires. - -There is no need to have the delay for every driver instance. The timers -on each amp will expire in parallel, so the delay is only needed once. -A global flag is used so that the first instance to reach its suspend() -callback will delay and then clear the flag. The cs35l56_fw_idle_wait_lock -mutex is to ensure this is still safe if async_suspend was ever enabled -for SoundWire devices. - -Fixes: e496112529006 ("ASoC: cs35l56: Add driver for Cirrus Logic CS35L56") -Reported-by: Ferenc Lengyel -Closes: https://github.com/thesofproject/linux/issues/5898 -Signed-off-by: Richard Fitzgerald -[omarchy: taken from the list posting - (https://patch.msgid.link/20260915102110.3276924-1-rf@opensource.cirrus.com). - It applies as posted on 7.2.8: 7.2.7 brought the component_registered - flag (1d80a4792f1d) and Omarchy's ASoC fixes the sdw_attached check in - cs35l56_sdw_system_suspend() (fbf2c660bac8)] ---- - include/sound/cs35l56.h | 4 ++++ - sound/soc/codecs/cs35l56-sdw.c | 27 +++++++++++++++++++++- - sound/soc/codecs/cs35l56-shared.c | 38 +++++++++++++++++++++++++++++++ - sound/soc/codecs/cs35l56.c | 17 ++++++++++++++ - sound/soc/codecs/cs35l56.h | 1 + - 5 files changed, 86 insertions(+), 1 deletion(-) - -diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h -index 45a5df574..447876ba2 100644 ---- a/include/sound/cs35l56.h -+++ b/include/sound/cs35l56.h -@@ -209,6 +209,9 @@ struct snd_ctl_elem_value; - - #define CS35L56_GPIO_FN_GPIO 0x00000001 - -+/* DSP1_FW_VER */ -+#define CS35L56_FW_MAIN_VERSION_MASK GENMASK(19, 0) -+ - /* Mixer input sources */ - #define CS35L56_INPUT_SRC_NONE 0x00 - #define CS35L56_INPUT_SRC_ASP1RX1 0x08 -@@ -445,6 +448,7 @@ int cs35l56_cal_set_status_get(struct cs35l56_base *cs35l56_base, - int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base, - bool *fw_missing, unsigned int *fw_version); - void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base); -+bool cs35l56_needs_wait_for_firmware_timer_expiry(struct cs35l56_base *cs35l56_base); - void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp); - int cs35l56_hw_init(struct cs35l56_base *cs35l56_base); - int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base); -diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c -index 98bb4542b..b2507a6a3 100644 ---- a/sound/soc/codecs/cs35l56-sdw.c -+++ b/sound/soc/codecs/cs35l56-sdw.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -36,6 +37,9 @@ - #define CS35L56_LATE_READ_POLL_US 10 - #define CS35L56_LATE_READ_TIMEOUT_US 1000 - -+static DEFINE_MUTEX(cs35l56_fw_idle_wait_lock); -+static bool cs35l56_fw_idle_wait_pending; -+ - static int cs35l56_sdw_poll_mem_status(struct sdw_slave *peripheral, - unsigned int mask, - unsigned int match) -@@ -382,14 +386,34 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev) - return 0; - } - -+static int cs35l56_sdw_system_suspend_prepare(struct device *dev) -+{ -+ cs35l56_fw_idle_wait_pending = true; -+ -+ return 0; -+} -+ - static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev) - { - struct cs35l56_private *cs35l56 = dev_get_drvdata(dev); -+ int ret; - - if (cs35l56->sdw_attached) - cs35l56_mask_soundwire_interrupts(cs35l56); - -- return cs35l56_system_suspend(dev); -+ ret = cs35l56_system_suspend(dev); -+ if (ret < 0) -+ return ret; -+ -+ scoped_guard(mutex, &cs35l56_fw_idle_wait_lock) { -+ if (cs35l56_fw_idle_wait_pending && cs35l56->needs_wait_for_fw_idle) { -+ dev_dbg(cs35l56->base.dev, "Wait for FW timer expiry\n"); -+ msleep(CS35L56_FW_REQ_ACTIVE_TIMEOUT_MS + 10); -+ cs35l56_fw_idle_wait_pending = false; -+ } -+ } -+ -+ return 0; - } - - static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id) -@@ -455,6 +479,7 @@ static void cs35l56_sdw_remove(struct sdw_slave *peripheral) - } - - static const struct dev_pm_ops cs35l56_sdw_pm = { -+ .prepare = cs35l56_sdw_system_suspend_prepare, - SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL) - SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_system_resume) - LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early) -diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c -index 7b3e37d46..b37f65cd4 100644 ---- a/sound/soc/codecs/cs35l56-shared.c -+++ b/sound/soc/codecs/cs35l56-shared.c -@@ -1379,6 +1379,44 @@ void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base) - } - EXPORT_SYMBOL_NS_GPL(cs35l56_warn_if_firmware_missing, "SND_SOC_CS35L56_SHARED"); - -+bool cs35l56_needs_wait_for_firmware_timer_expiry(struct cs35l56_base *cs35l56_base) -+{ -+ unsigned int fw_ver; -+ bool prot_sts; -+ int ret; -+ -+ switch (cs35l56_base->type) { -+ case 0x54: -+ case 0x56: -+ case 0x57: -+ switch (cs35l56_base->rev) { -+ case 0xb0: -+ ret = cs35l56_read_prot_status(cs35l56_base, &prot_sts, &fw_ver); -+ if (ret) -+ return true; -+ -+ if ((fw_ver & CS35L56_FW_MAIN_VERSION_MASK) < 0x30d07) -+ return true; -+ -+ return false; -+ case 0xb2: -+ ret = cs35l56_read_prot_status(cs35l56_base, &prot_sts, &fw_ver); -+ if (ret) -+ return true; -+ -+ if ((fw_ver & CS35L56_FW_MAIN_VERSION_MASK) < 0x40710) -+ return true; -+ -+ return false; -+ default: -+ return false; -+ } -+ default: -+ return false; -+ } -+} -+EXPORT_SYMBOL_NS_GPL(cs35l56_needs_wait_for_firmware_timer_expiry, "SND_SOC_CS35L56_SHARED"); -+ - void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp) - { - __be32 pid, sid, tid; -diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c -index 35d210626..07f773a1e 100644 ---- a/sound/soc/codecs/cs35l56.c -+++ b/sound/soc/codecs/cs35l56.c -@@ -1639,6 +1639,10 @@ int cs35l56_system_resume(struct device *dev) - - dev_dbg(dev, "system_resume\n"); - -+ /* Assume the firmware reset to default until we can check it */ -+ if (cs35l56->base.init_done) -+ cs35l56->needs_wait_for_fw_idle = true; -+ - /* - * We might have done a hard reset or the CS35L56 was power-cycled - * so wait for control port to be ready. -@@ -1653,6 +1657,16 @@ int cs35l56_system_resume(struct device *dev) - if (ret) - return ret; - -+ if (cs35l56->sdw_peripheral && cs35l56->base.init_done) { -+ ret = pm_runtime_resume_and_get(cs35l56->base.dev); -+ if (ret < 0) -+ return ret; -+ -+ cs35l56->needs_wait_for_fw_idle = -+ cs35l56_needs_wait_for_firmware_timer_expiry(&cs35l56->base); -+ pm_runtime_put_autosuspend(cs35l56->base.dev); -+ } -+ - /* Firmware won't have been loaded if the component hasn't probed */ - if (!cs35l56->component) - return 0; -@@ -2177,6 +2191,9 @@ int cs35l56_init(struct cs35l56_private *cs35l56) - if (ret) - return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n"); - -+ cs35l56->needs_wait_for_fw_idle = -+ cs35l56_needs_wait_for_firmware_timer_expiry(&cs35l56->base); -+ - cs35l56->base.init_done = true; - complete_all(&cs35l56->init_completion); - -diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h -index f7cf8aa65..b46f410f0 100644 ---- a/sound/soc/codecs/cs35l56.h -+++ b/sound/soc/codecs/cs35l56.h -@@ -43,6 +43,7 @@ struct cs35l56_private { - bool soft_resetting; - bool sdw_attached; - bool component_registered; -+ bool needs_wait_for_fw_idle; - struct completion init_completion; - - int speaker_id; --- -2.56.0 - diff --git a/kernel/1034-soundwire-mediatek-close-the-interrupt-gate-before-quiescing-a-link.patch b/kernel/1034-soundwire-mediatek-close-the-interrupt-gate-before-quiescing-a-link.patch deleted file mode 100644 index 8da6290..0000000 --- a/kernel/1034-soundwire-mediatek-close-the-interrupt-gate-before-quiescing-a-link.patch +++ /dev/null @@ -1,132 +0,0 @@ -From: Ryan Hughes -Date: Sat, 10 Oct 2026 21:30:00 -0400 -Subject: [PATCH] soundwire: mediatek: close the interrupt gate before - quiescing a link - -mtk_sdw_enable_irq(false) cleared interrupt_enabled, then waited for a -running status work in cancel_delayed_work_sync(), and only then cleared -MCP_INT_IRQ. Until then the line stayed live, and the status work it was -waiting for re-enables the slave interrupts as it finishes. A slave -interrupt in that window reached the handler with interrupt_enabled -false, which clears the status but neither masks it nor schedules the -status work. A peripheral sitting at Dev0 raises its attach status again -as soon as it is cleared, so the handler ran back to back, printing a -line every time. - -On the ASUS ProArt P14 the attach check (2 s after the link comes up) -hit that window on every boot of one kernel build. The level interrupt -is handled on CPU0, where the status work was also queued, so the work -never finished, the cancel never returned and the gate stayed open: -"[1]slave attached int IntStatus:0x80002000" about every 100 us, a -million times per boot, "ClearStatus 0x80002000" showing the flag was -off, and the boot never got past Plymouth. The same build in the -fallback entry was still storming nine minutes in. Earlier builds hit -the window too but escaped after a few hundred interrupts. - -Close the gate first when disabling, so nothing can arrive once the -flag is cleared, and open it last when enabling, as before. Mask the -slave interrupts in the handler whenever it sees one, not only when -interrupt processing is on: at probe and during a reset nothing handles -them, and mtk_sdw_enable_irq(true) unmasks them again. Rate-limit the -handler's slave status messages, so a storm from any other cause cannot -also flood the console. ---- - drivers/soundwire/mediatek/mtk-sdw-core.c | 59 ++++++++++++++++++++--------- - 1 file changed, 39 insertions(+), 20 deletions(-) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-core.c b/drivers/soundwire/mediatek/mtk-sdw-core.c ---- a/drivers/soundwire/mediatek/mtk-sdw-core.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-core.c -@@ -692,6 +692,19 @@ - - void mtk_sdw_enable_irq(struct mtk_sdw_core *core, bool enable) - { -+ /* -+ * Close the interrupt gate first when disabling. While it is open, -+ * a slave interrupt that arrives once interrupt_enabled is false is -+ * cleared but neither masked nor handed to the status work, and the -+ * status work cancelled below re-enables the slave interrupts as it -+ * finishes. A peripheral sitting at Dev0 raises its attach status -+ * again as soon as it is cleared, so the window became an interrupt -+ * storm on the CPU that had to finish the status work, the cancel -+ * never returned and the gate stayed open for good. -+ */ -+ if (!enable) -+ mtk_sdw_update_intmask(core, MCP_INT_IRQ, 0); -+ - if (enable) { - core_writel(core, MCP_SLAVEINTMASK0, MCP_SLAVE_INTMASK0_MASK); - core_writel(core, MCP_SLAVEINTMASK1, MCP_SLAVE_INTMASK1_MASK); -@@ -724,7 +737,8 @@ - cancel_delayed_work_sync(&core->status_work); - } - -- mtk_sdw_update_intmask(core, MCP_INT_IRQ, enable ? MCP_INT_IRQ : 0); -+ if (enable) -+ mtk_sdw_update_intmask(core, MCP_INT_IRQ, MCP_INT_IRQ); - } - - void mtk_sdw_enable_slave_irq(struct mtk_sdw_core *core, bool enable) -@@ -1152,37 +1166,42 @@ - - if (intstat & MCP_INT_SLV_MASK) { - if (intstat & MCP_INT_SLV_RESERVED) { -- dev_info(core->dev, "[%u]slave reserved int IntStatus:0x%x\n", -- bus->link_id, intstat); -+ dev_info_ratelimited(core->dev, -+ "[%u]slave reserved int IntStatus:0x%x\n", -+ bus->link_id, intstat); - } - - if (intstat & MCP_INT_SLV_ALERT) { -- dev_info(core->dev, -- "[%u]slave alert int IntStatus:0x%x\n", -- bus->link_id, intstat); -+ dev_info_ratelimited(core->dev, -+ "[%u]slave alert int IntStatus:0x%x\n", -+ bus->link_id, intstat); - } - - if (intstat & MCP_INT_SLV_ATTACHED) { -- dev_info(core->dev, -- "[%u]slave attached int IntStatus:0x%x\n", -- bus->link_id, intstat); -+ dev_info_ratelimited(core->dev, -+ "[%u]slave attached int IntStatus:0x%x\n", -+ bus->link_id, intstat); - } - - if (intstat & MCP_INT_SLV_NOT_ATTACH) { -- dev_info(core->dev, -- "[%u]slave not attached int IntStatus:0x%x\n", -- bus->link_id, intstat); -+ dev_info_ratelimited(core->dev, -+ "[%u]slave not attached int IntStatus:0x%x\n", -+ bus->link_id, intstat); - } -+ /* -+ * Mask before scheduling: the work re-enables the slave -+ * interrupt when it finishes, so masking after -+ * schedule_delayed_work() races a work that completes on -+ * another CPU first and leaves the interrupt masked forever -+ * (all subsequent attach/detach transitions are then lost). -+ * -+ * Mask while interrupt processing is off too (at probe, or -+ * while a reset quiesces the link): nothing handles the -+ * status then, and a peripheral at Dev0 raises it again as -+ * fast as it is cleared. mtk_sdw_enable_irq(true) unmasks it. -+ */ -+ mtk_sdw_enable_slave_irq(core, false); - if (core->interrupt_enabled) { -- /* -- * Mask before scheduling: the work re-enables the -- * slave interrupt when it finishes, so masking after -- * schedule_delayed_work() races a work that completes -- * on another CPU first and leaves the interrupt -- * masked forever (all subsequent attach/detach -- * transitions are then lost). -- */ -- mtk_sdw_enable_slave_irq(core, false); - schedule_delayed_work(&core->status_work, 0); - clearstat &= ~MCP_INT_SLV_MASK; - } diff --git a/kernel/1040-n1x-gpu-iommu.patch b/kernel/1040-n1x-gpu-iommu.patch deleted file mode 100644 index 97d3727..0000000 --- a/kernel/1040-n1x-gpu-iommu.patch +++ /dev/null @@ -1,123 +0,0 @@ -From ff491171eb5564f18e8e6efebb13996a9dea2fa7 Mon Sep 17 00:00:00 2001 -From: Nirmoy Das -Date: Wed, 10 Sep 2025 08:23:52 -0700 -Subject: [PATCH] NVIDIA: SAUCE: iommu/arm-smmu-v3: Set DGX Spark iGPU default - domain type to DMA - -BugLink: https://bugs.launchpad.net/bugs/2129776 - -Force DGX Spark systems to use DMA translation as current drivers -require this. - -Suggested-by: Jason Gunthorpe -Signed-off-by: Nirmoy Das -Acked-by: Matthew R. Ochs -Acked-by: Carol L Soto -Acked-by: Abdur Rahman -Acked-by: Jacob Martin -Signed-off-by: Ian May - -(cherry picked from commit 54575cfd0fa45463ba90a504e01fcd27d9dd020f noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -index 5f933d806a..2d6bd7994e 100644 ---- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -@@ -4298,6 +4298,9 @@ static int arm_smmu_def_domain_type(struct device *dev) - - if (IS_HISI_PTT_DEVICE(pdev)) - return IOMMU_DOMAIN_IDENTITY; -+ -+ if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && pdev->device == 0x2E12) -+ return IOMMU_DOMAIN_DMA; - } - - return 0; -From 00f46def1d5cdafdae7e7e864096a9b45c8255a7 Mon Sep 17 00:00:00 2001 -From: Nirmoy Das -Date: Thu, 20 Nov 2025 08:10:15 -0800 -Subject: [PATCH] NVIDIA: SAUCE: iommu/arm-smmu-v3: Add two more DGX Spark iGPU - IDs for existing iommu quirk - -BugLink: https://bugs.launchpad.net/bugs/2132033 - -Add two more device IDs for the existing Spark iommu quirk. - -Link: https://bugs.launchpad.net/ubuntu/+source/linux-nvidia-6.14/+bug/2132033 - -Signed-off-by: Nirmoy Das -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Abdur Rahman -Acked-by: Noah Wager -Signed-off--by: Brad Figg - -(cherry picked from commit ba9315458447d2677fb83131d78e1520f51b6c8a noble:linux-nvidia-6.17) -Signed-off-by: Jacob Martin ---- - drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -index 2d6bd7994e..07200fdb85 100644 ---- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -@@ -4299,7 +4299,9 @@ static int arm_smmu_def_domain_type(struct device *dev) - if (IS_HISI_PTT_DEVICE(pdev)) - return IOMMU_DOMAIN_IDENTITY; - -- if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && pdev->device == 0x2E12) -+ if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && -+ (pdev->device == 0x2E12 || pdev->device == 0x2E2A || -+ pdev->device == 0x2E2B)) - return IOMMU_DOMAIN_DMA; - } - -From e6efeafde42ec871f7f6d66fd3662236827965c3 Mon Sep 17 00:00:00 2001 -From: Abhishek Sahu -Date: Mon, 27 Apr 2026 05:04:56 +0000 -Subject: [PATCH] NVIDIA: SAUCE: iommu/arm-smmu-v3: Use device ID range for DGX - Spark iGPU iommu quirk - -BugLink: https://bugs.launchpad.net/bugs/2150487 - -Replace the explicit DGX Spark iGPU device ID list with a range check -covering 0x2E00-0x2E3F to accommodate all possible DGX Spark iGPU PCI -device IDs without requiring individual additions. - -The original quirk was introduced in -commit ab858638d96a ("NVIDIA: SAUCE: iommu/arm-smmu-v3: -Set DGX Spark iGPU default domain type to DMA") and -extended with two more IDs in -commit 8dc61abaa2eb ("NVIDIA: SAUCE: iommu/arm-smmu-v3: -Add two more DGX Spark iGPU IDs for existing iommu quirk"). -Using a range avoids further per-ID additions as new DGX Spark -variants are introduced. - -Signed-off-by: Abhishek Sahu -Acked-by: Jamie Nguyen -Acked-by: Matthew R. Ochs -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -index 07200fdb85..4d34b8964a 100644 ---- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c -@@ -4300,8 +4300,7 @@ static int arm_smmu_def_domain_type(struct device *dev) - return IOMMU_DOMAIN_IDENTITY; - - if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && -- (pdev->device == 0x2E12 || pdev->device == 0x2E2A || -- pdev->device == 0x2E2B)) -+ pdev->device >= 0x2E00 && pdev->device <= 0x2E3F) - return IOMMU_DOMAIN_DMA; - } - diff --git a/kernel/1060-ASoC-mediatek-mt8901-give-the-card-the-ACPI-subsystem-ID.patch b/kernel/1060-ASoC-mediatek-mt8901-give-the-card-the-ACPI-subsystem-ID.patch deleted file mode 100644 index 4acb1f7..0000000 --- a/kernel/1060-ASoC-mediatek-mt8901-give-the-card-the-ACPI-subsystem-ID.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 5e6a8e19f42f542767f2e4c58490e0829adadb81 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 14:11:18 -0400 -Subject: [PATCH] ASoC: mediatek: mt8901: give the card the ACPI subsystem ID - -Cirrus CS35L56 amplifiers name their DSP firmware and speaker tuning -after the sound card's PCI subsystem ID. Intel and AMD SoundWire machine -drivers take it from the audio controller's PCI device; the MT8901 card -has none, so the amplifiers never looked for their tuning and ran on ROM -defaults: quiet, and without the speaker voicing. - -The N1x firmware gives the ID as the SoundWire controller's _SUB, -written like Windows' SUBSYS value (device ID, then vendor ID: -"33A11043" on the ASUS ProArt P14). Read it when the machine is -selected and pass it to the card, as AMD's SoundWire driver does, so -the amplifiers request cs35l56-b0-dsp1-misc-104333a1*. ---- - drivers/soundwire/mediatek/mtk-sdw-mach.c | 26 +++++++++++++++++++ - .../mt8901/mt8901-acp-sdw-legacy-mach.c | 4 +++ - 2 files changed, 30 insertions(+) - -diff --git a/drivers/soundwire/mediatek/mtk-sdw-mach.c b/drivers/soundwire/mediatek/mtk-sdw-mach.c -index 2d7c240344..00054b2af7 100644 ---- a/drivers/soundwire/mediatek/mtk-sdw-mach.c -+++ b/drivers/soundwire/mediatek/mtk-sdw-mach.c -@@ -5,6 +5,8 @@ - * Copyright (c) 2026 MediaTek Inc. - * Author: Trevor Wu - */ -+#include -+#include - #include - #include - #include -@@ -463,6 +465,29 @@ static struct sdw_peripherals *mtk_sdw_get_peripherals(struct mtk_sdw *mst) - return peripherals; - } - -+/* -+ * Codec drivers name their per-system firmware after the sound card's PCI -+ * subsystem ID, which this ACPI-enumerated controller does not have. The -+ * firmware gives it as the controller's _SUB instead, written like Windows' -+ * SUBSYS value: subsystem device ID, then vendor ID ("33A11043" on the ASUS -+ * ProArt P14). -+ */ -+static void mtk_sdw_set_subsystem_id(struct mtk_sdw *mst, -+ struct snd_soc_acpi_mach *mach) -+{ -+ const char *sub __free(kfree) = acpi_get_subsystem_id(ACPI_HANDLE(mst->dev)); -+ u32 ssid; -+ -+ if (IS_ERR(sub) || strlen(sub) != 8 || kstrtou32(sub, 16, &ssid)) -+ return; -+ -+ mach->mach_params.subsystem_device = ssid >> 16; -+ mach->mach_params.subsystem_vendor = ssid & 0xffff; -+ mach->mach_params.subsystem_id_set = true; -+ dev_dbg(mst->dev, "SSID %04x:%04x\n", mach->mach_params.subsystem_vendor, -+ mach->mach_params.subsystem_device); -+} -+ - struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst) - { - struct sdw_peripherals *peripherals; -@@ -488,6 +513,7 @@ struct snd_soc_acpi_mach *mtk_sdw_machine_select(struct mtk_sdw *mst) - if (link && !link->num_adr) { - mach->mach_params.links = mach->links; - mach->mach_params.link_mask = mach->link_mask; -+ mtk_sdw_set_subsystem_id(mst, mach); - kfree(peripherals); - return mach; - } -diff --git a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -index 94143829be..4b989273df 100644 ---- a/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -+++ b/sound/soc/mediatek/mt8901/mt8901-acp-sdw-legacy-mach.c -@@ -574,6 +574,10 @@ static int mt8901_card_probe(struct platform_device *pdev) - card->num_dapm_routes = ARRAY_SIZE(mt8901_card_routes); - - snd_soc_card_set_drvdata(card, ctx); -+ if (mach && mach->mach_params.subsystem_id_set) -+ snd_soc_card_set_pci_ssid(card, -+ mach->mach_params.subsystem_vendor, -+ mach->mach_params.subsystem_device); - - if (quirk_override != -1) { - dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", --- -2.56.0 - diff --git a/kernel/1070-Revert-NVIDIA-SAUCE-usb-typec-ucsi-acpi-disable-USB4-via-vendor-_DSM-at-probe.patch b/kernel/1070-Revert-NVIDIA-SAUCE-usb-typec-ucsi-acpi-disable-USB4-via-vendor-_DSM-at-probe.patch deleted file mode 100644 index aef2dc7..0000000 --- a/kernel/1070-Revert-NVIDIA-SAUCE-usb-typec-ucsi-acpi-disable-USB4-via-vendor-_DSM-at-probe.patch +++ /dev/null @@ -1,97 +0,0 @@ -From cddb36ec223c693b7cf0d2a16676c008692cdfe7 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 19:18:10 -0400 -Subject: [PATCH 1070/1072] Revert "NVIDIA: SAUCE: usb: typec: ucsi: acpi: - disable USB4 via vendor _DSM at probe" - -This reverts commit 78ec5c1301aafe05f53d2ea7162f19838a1cfbba. - -The ASUS ProArt P14 (NVIDIA N1x) uses its USB4 ports, so disabling USB4 -from the OS is the opposite of what it needs. The vendor _DSM also does -not match this laptop's EC: it polls a mailbox the EC never clears, -stalling UCSI probe for about 2 s and returning failure on every boot -and resume. ---- - drivers/usb/typec/ucsi/ucsi_acpi.c | 52 ------------------------------ - 1 file changed, 52 deletions(-) - -diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c -index 0fdb33c3b0..18286d3e9c 100644 ---- a/drivers/usb/typec/ucsi/ucsi_acpi.c -+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c -@@ -173,54 +173,6 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = { - { } - }; - --/* -- * NVIDIA vendor extension for GB10 platforms: the firmware exposes an EC -- * control path to disable USB4 through a vendor _DSM on the UCSI device. -- * The presence check via acpi_check_dsm() gates it so non-GB10 -- * UCSI hardware is unaffected. -- */ --static void ucsi_acpi_nvidia_disable_usb4_gb10(struct ucsi_acpi *ua) --{ -- static const guid_t nvidia_usb4_dsm_guid = -- GUID_INIT(0x58ee92f1, 0x76ca, 0x48da, -- 0x92, 0xf0, 0xd5, 0x48, 0xe8, 0x3e, 0x80, 0xea); -- const u32 rev = 0; -- const u32 fn_disable = 2; -- acpi_handle handle = ACPI_HANDLE(ua->dev); -- union acpi_object *out; -- -- if (!acpi_check_dsm(handle, &nvidia_usb4_dsm_guid, rev, -- 1u << fn_disable)) -- return; -- -- out = acpi_evaluate_dsm(handle, &nvidia_usb4_dsm_guid, rev, -- fn_disable, NULL); -- if (!out) { -- dev_warn(ua->dev, "NVIDIA USB4 disable _DSM: evaluation failed\n"); -- return; -- } -- -- if (out->type == ACPI_TYPE_BUFFER && out->buffer.length >= 1) -- dev_info(ua->dev, "NVIDIA USB4 disable _DSM: returned 0x%02x (%s)\n", -- out->buffer.pointer[0], -- out->buffer.pointer[0] == 1 ? "success" : "failure"); -- else -- dev_warn(ua->dev, "NVIDIA USB4 disable _DSM: unexpected return type=%d len=%u\n", -- out->type, -- out->type == ACPI_TYPE_BUFFER ? out->buffer.length : 0); -- -- ACPI_FREE(out); --} -- --/* -- * Vendor-specific quirks that must run before UCSI async work is queued, -- * on both cold probe and resume. -- */ --static void ucsi_acpi_apply_vendor_quirks(struct ucsi_acpi *ua) --{ -- ucsi_acpi_nvidia_disable_usb4_gb10(ua); --} -- - static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) - { - struct ucsi_acpi *ua = data; -@@ -286,8 +238,6 @@ static int ucsi_acpi_probe(struct platform_device *pdev) - return -ENODEV; - } - -- ucsi_acpi_apply_vendor_quirks(ua); -- - ret = ucsi_register(ua->ucsi); - if (ret) { - acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), -@@ -324,8 +274,6 @@ static int ucsi_acpi_resume(struct device *dev) - { - struct ucsi_acpi *ua = dev_get_drvdata(dev); - -- ucsi_acpi_apply_vendor_quirks(ua); -- - return ucsi_resume(ua->ucsi); - } - --- -2.56.0 - diff --git a/kernel/1071-usb-typec-ucsi-acpi-query-the-_DSM-functions-before-using-them.patch b/kernel/1071-usb-typec-ucsi-acpi-query-the-_DSM-functions-before-using-them.patch deleted file mode 100644 index b25c29e..0000000 --- a/kernel/1071-usb-typec-ucsi-acpi-query-the-_DSM-functions-before-using-them.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 139631b3ea18b5c21216ec094c0647198d40f5c7 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 19:18:25 -0400 -Subject: [PATCH 1071/1072] usb: typec: ucsi: acpi: query the _DSM functions - before using them - -The ACPI specification has callers evaluate _DSM function 0 to learn -which functions are implemented before calling any. ucsi_acpi has never -done so, and calls the write and read functions directly. - -Firmware can depend on the query. On the ASUS ProArt P14 (NVIDIA N1x) -it opens the EC's UCSI service over FF-A; without it the EC never acts -on the commands written through function 1, so the PPM reset times out -and the driver fails to probe on every boot: - - ucsi_acpi USBC000:00: failed to reset PPM! - ucsi_acpi USBC000:00: error -ETIMEDOUT: PPM init failed - -Query the functions before registering. A firmware that does not report -them is only noted, as before the driver used them unconditionally. ---- - drivers/usb/typec/ucsi/ucsi_acpi.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c -index 18286d3e9c..f11feb7077 100644 ---- a/drivers/usb/typec/ucsi/ucsi_acpi.c -+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c -@@ -219,6 +219,16 @@ static int ucsi_acpi_probe(struct platform_device *pdev) - - ua->dev = &pdev->dev; - -+ /* -+ * Query the supported _DSM functions before calling any, as the ACPI -+ * specification asks callers to. Firmware may rely on it: on the ASUS -+ * ProArt P14 (NVIDIA N1x) the query opens the EC's UCSI service, and -+ * without it the PPM never completes its reset. -+ */ -+ if (!acpi_check_dsm(ACPI_HANDLE(&pdev->dev), &ua->guid, 1, -+ BIT(UCSI_DSM_FUNC_WRITE) | BIT(UCSI_DSM_FUNC_READ))) -+ dev_dbg(&pdev->dev, "_DSM does not report the UCSI read/write functions\n"); -+ - id = dmi_first_match(ucsi_acpi_quirks); - if (id) - ops = id->driver_data; --- -2.56.0 - diff --git a/kernel/1072-soc-mediatek-power_wrap-make-the-USB4-resource-release-optional.patch b/kernel/1072-soc-mediatek-power_wrap-make-the-USB4-resource-release-optional.patch deleted file mode 100644 index 89fdeb3..0000000 --- a/kernel/1072-soc-mediatek-power_wrap-make-the-USB4-resource-release-optional.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 2bc8e8fe5ed2dfb21b8993c427f326bcb0cdeadf Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 19:29:03 -0400 -Subject: [PATCH 1072/1072] soc: mediatek: power_wrap: make the USB4 resource - release optional - -Once every xHCI has bound, power_wrap tells the SSPM to release the USB4 -resources the bootloader left powered, for systems that do not use USB4. -After that the SSPM no longer answers device requests for the USB4 host -routers (\_SB.UBFn): probe and D0 both time out. A system that runs a -USB4 connection manager needs those requests. - -Add power_wrap_drv.usb4_release to keep the resources. It defaults to -releasing them, as before. ---- - drivers/soc/mediatek/power_wrap/power_wrap.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index 5db9077b56..50b1858aad 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -127,6 +127,15 @@ static struct device *pwrap_usb4_early_bound[PWRAP_USB4_MAX_XHCI]; - static unsigned int pwrap_usb4_nearly; - static bool pwrap_usb4_tracking; - static bool pwrap_usb4_done; -+ -+/* -+ * The release suits systems that leave USB4 unused. A system running a USB4 -+ * connection manager needs the host routers kept, so it can turn this off. -+ */ -+static bool usb4_release = true; -+module_param(usb4_release, bool, 0444); -+MODULE_PARM_DESC(usb4_release, -+ "Release the USB4 resources left powered by the bootloader once xHCI has bound (default: true)"); - static struct notifier_block pwrap_usb4_nb; - - /* Controllers found unbound by the collection pass, before commit. */ -@@ -772,6 +781,11 @@ static void pwrap_usb4_arm_release(struct device *dev) - unsigned int i; - int ret; - -+ if (!usb4_release) { -+ dev_info(dev, "USB4: release disabled, keeping usb4 resources\n"); -+ return; -+ } -+ - status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PLID", NULL, &plid); - if (ACPI_FAILURE(status)) { - dev_info(dev, "USB4: PLID unavailable (%s), skipping release\n", --- -2.56.0 - diff --git a/kernel/1073-thunderbolt-check-for-a-PCI-NHI-before-treating-it-as-one.patch b/kernel/1073-thunderbolt-check-for-a-PCI-NHI-before-treating-it-as-one.patch deleted file mode 100644 index 35b3bd8..0000000 --- a/kernel/1073-thunderbolt-check-for-a-PCI-NHI-before-treating-it-as-one.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 982dd56219fa2dd46ec434cd956dcc361f769681 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 20:13:29 -0400 -Subject: [PATCH 1073/1078] thunderbolt: check for a PCI NHI before treating it - as one - -icm_probe() and tb_apple_add_links() convert the NHI device with -to_pci_dev() unconditionally. icm_probe() then reads the PCI device ID, -which would read past the end of the device on a host interface that is -not on PCIe. The firmware connection manager only exists on Intel PCIe -host routers, so return early for anything else in both places. ---- - drivers/thunderbolt/icm.c | 7 ++++++- - drivers/thunderbolt/tb.c | 6 ++++-- - 2 files changed, 10 insertions(+), 3 deletions(-) - -diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c -index 669807f0ea..7f38b4d7a6 100644 ---- a/drivers/thunderbolt/icm.c -+++ b/drivers/thunderbolt/icm.c -@@ -2478,10 +2478,15 @@ static const struct tb_cm_ops icm_icl_ops = { - - struct tb *icm_probe(struct tb_nhi *nhi) - { -- struct pci_dev *pdev = to_pci_dev(nhi->dev); -+ struct pci_dev *pdev; - struct icm *icm; - struct tb *tb; - -+ /* Firmware connection managers only run on Intel PCIe host routers */ -+ if (!dev_is_pci(nhi->dev)) -+ return NULL; -+ pdev = to_pci_dev(nhi->dev); -+ - tb = tb_domain_alloc(nhi, ICM_TIMEOUT, sizeof(struct icm)); - if (!tb) - return NULL; -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c -index f43f2d9523..c2fe727800 100644 ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -3311,13 +3311,15 @@ static const struct tb_cm_ops tb_cm_ops = { - */ - static bool tb_apple_add_links(struct tb_nhi *nhi) - { -- struct pci_dev *nhi_pdev = to_pci_dev(nhi->dev); -+ struct pci_dev *nhi_pdev; - struct pci_dev *upstream, *pdev; - bool ret; - -- if (!x86_apple_machine) -+ if (!x86_apple_machine || !dev_is_pci(nhi->dev)) - return false; - -+ nhi_pdev = to_pci_dev(nhi->dev); -+ - switch (nhi_pdev->device) { - case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE: - case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C: --- -2.56.0 - diff --git a/kernel/1074-thunderbolt-nhi-let-a-single-wired-interrupt-service-the-rings.patch b/kernel/1074-thunderbolt-nhi-let-a-single-wired-interrupt-service-the-rings.patch deleted file mode 100644 index 8993e76..0000000 --- a/kernel/1074-thunderbolt-nhi-let-a-single-wired-interrupt-service-the-rings.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 2e77ab868c83eac5caf6b07e34bac50b12e8b559 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 20:13:54 -0400 -Subject: [PATCH 1074/1078] thunderbolt: nhi: let a single wired interrupt - service the rings - -Host interfaces without MSI-X signal every ring through one interrupt. -On PCIe that is a single MSI, handled by nhi_msi() scheduling -nhi_interrupt_work(). An edge-triggered MSI can return before the work -runs, but a level-triggered wired interrupt cannot: it stays asserted -until the ring notification registers are read, so it would fire again -as soon as the handler returned. - -Factor the notification scan out of nhi_interrupt_work() into -nhi_handle_interrupts(), which reports whether anything was pending, so -such a host interface can call it from a threaded handler and report -spurious interrupts. Initialize nhi->lock before init_interrupts() too, -since a level-triggered interrupt can already be asserted when it is -requested. ---- - drivers/thunderbolt/nhi.c | 30 ++++++++++++++++++++++++++---- - drivers/thunderbolt/nhi.h | 1 + - 2 files changed, 27 insertions(+), 4 deletions(-) - -diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c -index a4816db5ca..2e26967b0f 100644 ---- a/drivers/thunderbolt/nhi.c -+++ b/drivers/thunderbolt/nhi.c -@@ -930,14 +930,24 @@ enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi) - return (enum nhi_fw_mode)val; - } - --void nhi_interrupt_work(struct work_struct *work) -+/** -+ * nhi_handle_interrupts() - Service the pending ring interrupts -+ * @nhi: Host interface whose ring notification status is scanned -+ * -+ * For host interfaces that signal every ring through one interrupt. Reads -+ * the ring notification status registers, which clear on read, and services -+ * each ring with an event. Must be called from process context. -+ * -+ * Return: %true if any notification status bit was set. -+ */ -+bool nhi_handle_interrupts(struct tb_nhi *nhi) - { -- struct tb_nhi *nhi = container_of(work, typeof(*nhi), interrupt_work); - int value = 0; /* Suppress uninitialized usage warning. */ - int bit; - int hop = -1; - int type = 0; /* current interrupt type 0: TX, 1: RX, 2: RX overflow */ - struct tb_ring *ring; -+ bool handled = false; - - spin_lock_irq(&nhi->lock); - -@@ -957,6 +967,7 @@ void nhi_interrupt_work(struct work_struct *work) - } - if ((value & (1 << (bit % 32))) == 0) - continue; -+ handled = true; - if (type == 2) { - dev_warn(nhi->dev, "RX overflow for ring %d\n", hop); - continue; -@@ -978,6 +989,16 @@ void nhi_interrupt_work(struct work_struct *work) - spin_unlock(&ring->lock); - } - spin_unlock_irq(&nhi->lock); -+ -+ return handled; -+} -+EXPORT_SYMBOL_NS_GPL(nhi_handle_interrupts, "THUNDERBOLT_NHI"); -+ -+void nhi_interrupt_work(struct work_struct *work) -+{ -+ struct tb_nhi *nhi = container_of(work, typeof(*nhi), interrupt_work); -+ -+ nhi_handle_interrupts(nhi); - } - - irqreturn_t nhi_msi(int irq, void *data) -@@ -1225,12 +1246,13 @@ int nhi_probe(struct tb_nhi *nhi) - /* In case someone left them on. */ - nhi_disable_interrupts(nhi); - -+ /* A level-triggered interrupt may already be pending when requested */ -+ spin_lock_init(&nhi->lock); -+ - res = nhi->ops->init_interrupts(nhi); - if (res) - return dev_err_probe(dev, res, "cannot enable interrupts, aborting\n"); - -- spin_lock_init(&nhi->lock); -- - res = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); - if (res) - return dev_err_probe(dev, res, "failed to set DMA mask\n"); -diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h -index d488eadadf..4fcf818fea 100644 ---- a/drivers/thunderbolt/nhi.h -+++ b/drivers/thunderbolt/nhi.h -@@ -32,6 +32,7 @@ enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi); - void nhi_enable_int_throttling(struct tb_nhi *nhi); - void nhi_disable_interrupts(struct tb_nhi *nhi); - void nhi_interrupt_work(struct work_struct *work); -+bool nhi_handle_interrupts(struct tb_nhi *nhi); - irqreturn_t nhi_msi(int irq, void *data); - irqreturn_t ring_msix(int irq, void *data); - int nhi_probe(struct tb_nhi *nhi); --- -2.56.0 - diff --git a/kernel/1075-thunderbolt-nhi-share-teardown-and-export-the-NHI-core.patch b/kernel/1075-thunderbolt-nhi-share-teardown-and-export-the-NHI-core.patch deleted file mode 100644 index 7fff9f8..0000000 --- a/kernel/1075-thunderbolt-nhi-share-teardown-and-export-the-NHI-core.patch +++ /dev/null @@ -1,105 +0,0 @@ -From ef8a43a988346c65b34d235cf626b02b19ce0dd3 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 20:14:16 -0400 -Subject: [PATCH] thunderbolt: nhi: share teardown and export the NHI core - -Move the teardown from nhi_pci_remove() into nhi_remove() so other host -interface glue can use it, and export nhi_probe(), nhi_remove(), -nhi_pm_ops and nhi_handle_interrupts() in the THUNDERBOLT_NHI namespace. -Glue for host interfaces that are not on PCIe can then be a module of -its own, loaded only on the systems that have such a host interface. - -[omarchy: on 7.2.8 Omarchy's Thunderbolt fixes split nhi_pci_remove() - into nhi_pci_do_remove(), which sets nhi->host_reset for shutdown so - tb_stop() resets ports with Thunderbolt 3 devices; that stays in the - PCI glue and the rest of the teardown moves to nhi_remove()] ---- - drivers/thunderbolt/nhi.c | 24 ++++++++++++++++++++++++ - drivers/thunderbolt/nhi.h | 1 + - drivers/thunderbolt/pci.c | 11 ++--------- - 3 files changed, 27 insertions(+), 9 deletions(-) - -diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c -index 641f9aac4..ecfa875bc 100644 ---- a/drivers/thunderbolt/nhi.c -+++ b/drivers/thunderbolt/nhi.c -@@ -1301,6 +1301,29 @@ int nhi_probe(struct tb_nhi *nhi) - - return 0; - } -+EXPORT_SYMBOL_NS_GPL(nhi_probe, "THUNDERBOLT_NHI"); -+ -+/** -+ * nhi_remove() - Tear down a host interface set up by nhi_probe() -+ * @nhi: Host interface to remove -+ * -+ * Removes the domain, waits for it to be released and shuts the host -+ * interface down. Leaves runtime PM forbidden. -+ */ -+void nhi_remove(struct tb_nhi *nhi) -+{ -+ struct device *dev = nhi->dev; -+ struct tb *tb = dev_get_drvdata(dev); -+ -+ pm_runtime_get_sync(dev); -+ pm_runtime_dont_use_autosuspend(dev); -+ pm_runtime_forbid(dev); -+ -+ tb_domain_remove(tb); -+ wait_for_completion(&nhi->domain_released); -+ nhi_shutdown(nhi); -+} -+EXPORT_SYMBOL_NS_GPL(nhi_remove, "THUNDERBOLT_NHI"); - - /* - * The tunneled pci bridges are siblings of us. Use resume_noirq to reenable -@@ -1323,3 +1346,4 @@ const struct dev_pm_ops nhi_pm_ops = { - .runtime_suspend = nhi_runtime_suspend, - .runtime_resume = nhi_runtime_resume, - }; -+EXPORT_SYMBOL_NS_GPL(nhi_pm_ops, "THUNDERBOLT_NHI"); -diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h -index 4fcf818fe..6babd71e4 100644 ---- a/drivers/thunderbolt/nhi.h -+++ b/drivers/thunderbolt/nhi.h -@@ -36,6 +36,7 @@ bool nhi_handle_interrupts(struct tb_nhi *nhi); - irqreturn_t nhi_msi(int irq, void *data); - irqreturn_t ring_msix(int irq, void *data); - int nhi_probe(struct tb_nhi *nhi); -+void nhi_remove(struct tb_nhi *nhi); - void nhi_shutdown(struct tb_nhi *nhi); - extern const struct dev_pm_ops nhi_pm_ops; - -diff --git a/drivers/thunderbolt/pci.c b/drivers/thunderbolt/pci.c -index 8462ccb59..c012509fe 100644 ---- a/drivers/thunderbolt/pci.c -+++ b/drivers/thunderbolt/pci.c -@@ -481,7 +481,6 @@ static int nhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) - static void nhi_pci_do_remove(struct pci_dev *pdev, bool reset) - { - struct tb *tb = pci_get_drvdata(pdev); -- struct tb_nhi *nhi = tb->nhi; - - /* - * On system shutdown/reboot force a host router reset so the -@@ -489,15 +488,9 @@ static void nhi_pci_do_remove(struct pci_dev *pdev, bool reset) - * before the router tree is removed (see tb_stop()). - */ - if (reset) -- nhi->host_reset = true; -+ tb->nhi->host_reset = true; - -- pm_runtime_get_sync(&pdev->dev); -- pm_runtime_dont_use_autosuspend(&pdev->dev); -- pm_runtime_forbid(&pdev->dev); -- -- tb_domain_remove(tb); -- wait_for_completion(&nhi->domain_released); -- nhi_shutdown(nhi); -+ nhi_remove(tb->nhi); - } - - static void nhi_pci_remove(struct pci_dev *pdev) --- -2.56.0 - diff --git a/kernel/1076-soc-mediatek-power_wrap-report-whether-the-USB4-resources-are-released.patch b/kernel/1076-soc-mediatek-power_wrap-report-whether-the-USB4-resources-are-released.patch deleted file mode 100644 index 8a80542..0000000 --- a/kernel/1076-soc-mediatek-power_wrap-report-whether-the-USB4-resources-are-released.patch +++ /dev/null @@ -1,95 +0,0 @@ -From e8da759b3c4170030c01cc12edc50ae9925d1424 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 20:15:51 -0400 -Subject: [PATCH 1076/1078] soc: mediatek: power_wrap: report whether the USB4 - resources are released - -Once the USB4 resources are released, the SSPM stops answering device -requests for the USB4 host routers: a probe or D0 request for one times -out, and about a minute later the SoC resets. A USB4 host router driver -has to know before it sends anything. - -Add mtk_pwrap_usb4_released(), true once the release is armed. power_wrap -is built in and arms the release at probe, so the answer is settled by -the time a USB4 host router driver can load. ---- - drivers/soc/mediatek/power_wrap/power_wrap.c | 24 ++++++++++++++++++++ - include/linux/soc/mediatek/mtk-pwrap.h | 6 +++++ - 2 files changed, 30 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index 50b1858aad..33445cdf4f 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -127,6 +127,7 @@ static struct device *pwrap_usb4_early_bound[PWRAP_USB4_MAX_XHCI]; - static unsigned int pwrap_usb4_nearly; - static bool pwrap_usb4_tracking; - static bool pwrap_usb4_done; -+static bool pwrap_usb4_armed; - - /* - * The release suits systems that leave USB4 unused. A system running a USB4 -@@ -644,6 +645,27 @@ static void pwrap_write_bestperf_flag(struct device *dev) - iounmap(vaddr); - } - -+/** -+ * mtk_pwrap_usb4_released() - Whether the USB4 resources are released this boot -+ * -+ * Once the resources are released, the SSPM no longer answers device requests -+ * for the USB4 host routers and stops responding altogether, so a USB4 host -+ * router driver must not send any. -+ * -+ * Return: %true if the release has been armed or issued. -+ */ -+bool mtk_pwrap_usb4_released(void) -+{ -+ bool armed; -+ -+ mutex_lock(&pwrap_usb4_lock); -+ armed = pwrap_usb4_armed; -+ mutex_unlock(&pwrap_usb4_lock); -+ -+ return armed; -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_usb4_released); -+ - /* - * pwrap_release_usb4_resources() - release USB4 hardware resources via SSPM - * -@@ -803,6 +825,8 @@ static void pwrap_usb4_arm_release(struct device *dev) - pwrap_usb4_dev = dev; - pwrap_usb4_nb.notifier_call = pwrap_usb4_bus_notify; - ret = bus_register_notifier(&platform_bus_type, &pwrap_usb4_nb); -+ if (!ret) -+ pwrap_usb4_armed = true; - mutex_unlock(&pwrap_usb4_lock); - if (ret) { - dev_err(dev, "USB4: cannot register bus notifier (%d), release not armed\n", -diff --git a/include/linux/soc/mediatek/mtk-pwrap.h b/include/linux/soc/mediatek/mtk-pwrap.h -index 16d98e387c..a655c71444 100644 ---- a/include/linux/soc/mediatek/mtk-pwrap.h -+++ b/include/linux/soc/mediatek/mtk-pwrap.h -@@ -76,6 +76,7 @@ int mtk_pwrap_dev_resume(void *dev_ctrl, u8 sys_trans); - int mtk_pwrap_com_idle(void *dev_ctrl, u8 com_idx); - int mtk_pwrap_com_active(void *dev_ctrl, u8 com_idx); - void *mtk_pwrap_dev_probe(const char *acpi_path); -+bool mtk_pwrap_usb4_released(void); - #else - static inline int mtk_send_power_control_req(struct _power_cntrl_request *pwrctlreq) - { -@@ -116,6 +117,11 @@ static inline void *mtk_pwrap_dev_probe(const char *acpi_path) - { - return NULL; - } -+ -+static inline bool mtk_pwrap_usb4_released(void) -+{ -+ return false; -+} - #endif /* CONFIG_MTK_POWER_WRAP */ - - #endif --- -2.56.0 - diff --git a/kernel/1077-thunderbolt-add-a-driver-for-USB4-host-interfaces-described-by-ACPI.patch b/kernel/1077-thunderbolt-add-a-driver-for-USB4-host-interfaces-described-by-ACPI.patch deleted file mode 100644 index e105775..0000000 --- a/kernel/1077-thunderbolt-add-a-driver-for-USB4-host-interfaces-described-by-ACPI.patch +++ /dev/null @@ -1,334 +0,0 @@ -From ac830c4bff5b90700ea62d557173cdcabe8a31ba Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 20:17:48 -0400 -Subject: [PATCH 1077/1078] thunderbolt: add a driver for USB4 host interfaces - described by ACPI - -The NVIDIA N1x has no PCIe NHI. Its USB4 host interfaces are platform -devices (ACPI0015, _HID NVDA8100), one per USB-C port, each with the -USB4 host interface registers in its first memory window and one -level-triggered interrupt for every ring. With nothing to bind them, -no connection manager runs and USB4 and Thunderbolt devices only get -their USB 2.0 functions. - -Add glue that maps the registers, powers the host router, services the -interrupt from a thread through nhi_handle_interrupts() and hands the -host interface to the NHI core. The N1x powers its host routers through -the SSPM, which stops answering for them once power_wrap releases the -USB4 resources, so refuse to probe in that case rather than hang it. - -Runtime PM stays forbidden until a wake interrupt is wired up, since a -runtime suspended host router would not notice a device being plugged -in. ---- - drivers/thunderbolt/Kconfig | 11 ++ - drivers/thunderbolt/Makefile | 3 + - drivers/thunderbolt/nhi_platform.c | 260 +++++++++++++++++++++++++++++ - 3 files changed, 274 insertions(+) - create mode 100644 drivers/thunderbolt/nhi_platform.c - -diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig -index 294b3227a5..eb500f013f 100644 ---- a/drivers/thunderbolt/Kconfig -+++ b/drivers/thunderbolt/Kconfig -@@ -51,6 +51,17 @@ config USB4_KUNIT_TEST - depends on USB4 && KUNIT=y - default KUNIT_ALL_TESTS - -+config USB4_PLATFORM_NHI -+ tristate "USB4 host interfaces described by ACPI" -+ depends on ACPI -+ help -+ Support for USB4 host interfaces that are memory-mapped platform -+ devices described by ACPI rather than PCIe devices, such as those -+ of the NVIDIA N1x. -+ -+ To compile this driver as a module, choose M here. The module will -+ be called thunderbolt_platform. -+ - config USB4_DMA_TEST - tristate "DMA traffic test driver" - depends on DEBUG_FS -diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile -index beb054c312..9aee28769c 100644 ---- a/drivers/thunderbolt/Makefile -+++ b/drivers/thunderbolt/Makefile -@@ -11,6 +11,9 @@ thunderbolt-$(CONFIG_USB4_CONFIGFS) += configfs.o - thunderbolt-${CONFIG_USB4_KUNIT_TEST} += test.o - CFLAGS_test.o += $(DISABLE_STRUCTLEAK_PLUGIN) - -+thunderbolt_platform-y := nhi_platform.o -+obj-$(CONFIG_USB4_PLATFORM_NHI) += thunderbolt_platform.o -+ - thunderbolt_dma_test-${CONFIG_USB4_DMA_TEST} += dma_test.o - obj-$(CONFIG_USB4_DMA_TEST) += thunderbolt_dma_test.o - -diff --git a/drivers/thunderbolt/nhi_platform.c b/drivers/thunderbolt/nhi_platform.c -new file mode 100644 -index 0000000000..62743ec450 ---- /dev/null -+++ b/drivers/thunderbolt/nhi_platform.c -@@ -0,0 +1,260 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Thunderbolt driver - USB4 host interfaces described by ACPI -+ * -+ * Some Arm SoCs expose their USB4 host interfaces as memory-mapped platform -+ * devices (ACPI0015) with a wired interrupt, rather than as PCIe NHIs. The -+ * registers follow the USB4 specification, so the NHI core drives them; this -+ * glue maps them, powers the host router and services the interrupt. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "nhi.h" -+#include "nhi_regs.h" -+#include "tb.h" -+ -+/* -+ * Three status bits per path start at REG_RING_NOTIFY_BASE, and the 64 bits -+ * there end where REG_RING_INT_CLEAR begins. -+ */ -+#define NHI_PLAT_MAX_PATHS 21 -+ -+struct nhi_plat; -+ -+/** -+ * struct nhi_plat_data - Platform specific host router handling -+ * @power_on: Power the host router before its registers are accessed -+ * @power_off: Power the host router down again -+ */ -+struct nhi_plat_data { -+ int (*power_on)(struct nhi_plat *np); -+ void (*power_off)(struct nhi_plat *np); -+}; -+ -+/** -+ * struct nhi_plat - USB4 host interface described by ACPI -+ * @nhi: NHI device -+ * @data: Platform specific handling -+ * @irq: The interrupt every ring is signalled through -+ * @irq_requested: @irq is currently requested -+ * @pwrap: SSPM power control handle (NVIDIA N1x) -+ */ -+struct nhi_plat { -+ struct tb_nhi nhi; -+ const struct nhi_plat_data *data; -+ int irq; -+ bool irq_requested; -+ void *pwrap; -+}; -+ -+static inline struct nhi_plat *nhi_to_plat(struct tb_nhi *nhi) -+{ -+ return container_of(nhi, struct nhi_plat, nhi); -+} -+ -+static irqreturn_t nhi_plat_irq_thread(int irq, void *data) -+{ -+ struct tb_nhi *nhi = data; -+ -+ return nhi_handle_interrupts(nhi) ? IRQ_HANDLED : IRQ_NONE; -+} -+ -+/* -+ * The interrupt is level-triggered and stays asserted until the notification -+ * registers are read, so keep it masked until the thread has read them. -+ */ -+static int nhi_plat_init_interrupts(struct tb_nhi *nhi) -+{ -+ struct nhi_plat *np = nhi_to_plat(nhi); -+ int ret; -+ -+ ret = devm_request_threaded_irq(nhi->dev, np->irq, NULL, -+ nhi_plat_irq_thread, -+ IRQF_ONESHOT | IRQF_NO_SUSPEND, -+ dev_name(nhi->dev), nhi); -+ if (!ret) -+ np->irq_requested = true; -+ -+ return ret; -+} -+ -+/* Called before the host router is powered down, so nothing reads it after */ -+static void nhi_plat_shutdown(struct tb_nhi *nhi) -+{ -+ struct nhi_plat *np = nhi_to_plat(nhi); -+ -+ if (np->irq_requested) { -+ devm_free_irq(nhi->dev, np->irq, nhi); -+ np->irq_requested = false; -+ } -+} -+ -+static const struct tb_nhi_ops nhi_plat_ops = { -+ .init_interrupts = nhi_plat_init_interrupts, -+ .shutdown = nhi_plat_shutdown, -+}; -+ -+/* -+ * NVIDIA N1x: the host routers are powered through the SSPM. The firmware -+ * leaves them powered at boot, but power_wrap can release them once xHCI is -+ * up, after which the SSPM stops answering for them altogether. A request -+ * then hangs it and resets the SoC, so refuse to touch them in that case. -+ */ -+static int nhi_nvda8100_power_on(struct nhi_plat *np) -+{ -+ struct device *dev = np->nhi.dev; -+ struct acpi_buffer path = { ACPI_ALLOCATE_BUFFER, NULL }; -+ int ret; -+ -+ if (mtk_pwrap_usb4_released()) -+ return dev_err_probe(dev, -ENODEV, -+ "USB4 resources are released, boot with power_wrap_drv.usb4_release=0\n"); -+ -+ if (!np->pwrap) { -+ if (ACPI_FAILURE(acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, -+ &path))) -+ return -ENODEV; -+ np->pwrap = mtk_pwrap_dev_probe(path.pointer); -+ kfree(path.pointer); -+ if (!np->pwrap) -+ return dev_err_probe(dev, -ENODEV, -+ "no SSPM power control for the host router\n"); -+ } -+ -+ ret = mtk_pwrap_dev_resume(np->pwrap, 0); -+ if (ret) -+ return dev_err_probe(dev, ret, "cannot power the host router\n"); -+ -+ return 0; -+} -+ -+static void nhi_nvda8100_power_off(struct nhi_plat *np) -+{ -+ int ret; -+ -+ ret = mtk_pwrap_dev_suspend(np->pwrap, 0); -+ if (ret) -+ dev_warn(np->nhi.dev, "cannot power the host router down: %d\n", ret); -+} -+ -+static const struct nhi_plat_data nhi_nvda8100_data = { -+ .power_on = nhi_nvda8100_power_on, -+ .power_off = nhi_nvda8100_power_off, -+}; -+ -+static void nhi_plat_power_off(struct nhi_plat *np) -+{ -+ if (np->data->power_off) -+ np->data->power_off(np); -+} -+ -+static int nhi_plat_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct resource *res; -+ struct nhi_plat *np; -+ struct tb_nhi *nhi; -+ u32 caps, paths; -+ int ret; -+ -+ np = devm_kzalloc(dev, sizeof(*np), GFP_KERNEL); -+ if (!np) -+ return -ENOMEM; -+ -+ np->data = device_get_match_data(dev); -+ nhi = &np->nhi; -+ nhi->dev = dev; -+ nhi->ops = &nhi_plat_ops; -+ -+ nhi->iobase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); -+ if (IS_ERR(nhi->iobase)) -+ return dev_err_probe(dev, PTR_ERR(nhi->iobase), -+ "cannot map the host interface registers\n"); -+ if (resource_size(res) < REG_RESET + 4) -+ return dev_err_probe(dev, -ENODEV, -+ "host interface register window too small\n"); -+ -+ np->irq = platform_get_irq(pdev, 0); -+ if (np->irq < 0) -+ return np->irq; -+ -+ if (np->data->power_on) { -+ ret = np->data->power_on(np); -+ if (ret) -+ return ret; -+ } -+ -+ /* nhi_probe() sizes everything from the path count; check it first */ -+ caps = ioread32(nhi->iobase + REG_CAPS); -+ paths = caps & 0x3ff; -+ if (!paths || paths > NHI_PLAT_MAX_PATHS) { -+ ret = dev_err_probe(dev, -ENODEV, -+ "unexpected host interface capabilities %#x\n", caps); -+ goto err_power_off; -+ } -+ -+ pm_runtime_set_active(dev); -+ pm_runtime_get_noresume(dev); -+ ret = devm_pm_runtime_enable(dev); -+ if (ret) -+ goto err_put; -+ -+ ret = nhi_probe(nhi); -+ if (ret) -+ goto err_put; -+ -+ /* -+ * Nothing would notice a device being plugged in while the host router -+ * is runtime suspended, as there is no wake interrupt support yet. -+ */ -+ pm_runtime_forbid(dev); -+ -+ return 0; -+ -+err_put: -+ pm_runtime_put_noidle(dev); -+ nhi_plat_shutdown(nhi); -+err_power_off: -+ nhi_plat_power_off(np); -+ return ret; -+} -+ -+static void nhi_plat_remove(struct platform_device *pdev) -+{ -+ struct tb *tb = platform_get_drvdata(pdev); -+ struct nhi_plat *np = nhi_to_plat(tb->nhi); -+ -+ nhi_remove(tb->nhi); -+ nhi_plat_power_off(np); -+} -+ -+static const struct acpi_device_id nhi_plat_acpi_ids[] = { -+ { "NVDA8100", (kernel_ulong_t)&nhi_nvda8100_data }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, nhi_plat_acpi_ids); -+ -+static struct platform_driver nhi_plat_driver = { -+ .driver = { -+ .name = "thunderbolt-platform", -+ .acpi_match_table = nhi_plat_acpi_ids, -+ .pm = &nhi_pm_ops, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ }, -+ .probe = nhi_plat_probe, -+ .remove = nhi_plat_remove, -+ .shutdown = nhi_plat_remove, -+}; -+module_platform_driver(nhi_plat_driver); -+ -+MODULE_IMPORT_NS("THUNDERBOLT_NHI"); -+MODULE_DESCRIPTION("USB4 host interfaces described by ACPI"); -+MODULE_LICENSE("GPL"); --- -2.56.0 - diff --git a/kernel/1078-PCI-Keep-hotplug-bridges-below-a-switch-to-their-share-of-bus-numbers.patch b/kernel/1078-PCI-Keep-hotplug-bridges-below-a-switch-to-their-share-of-bus-numbers.patch deleted file mode 100644 index ed999f3..0000000 --- a/kernel/1078-PCI-Keep-hotplug-bridges-below-a-switch-to-their-share-of-bus-numbers.patch +++ /dev/null @@ -1,67 +0,0 @@ -From f9c61d9d30a2ec799653582b27106a60a3cf942c Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 20:31:19 -0400 -Subject: [PATCH 1078/1078] PCI: Keep hotplug bridges below a switch to their - share of bus numbers - -When a switch is hot-added below a hotplug bridge, pci_hp_add_bridge() -hands it every bus number up to the subordinate of the slot, and -pci_scan_child_bus_extend() divides them between the switch's hotplug -downstream ports. Each port is then extended to at least -pci_hotplug_bus_size - 1 numbers, capped only at the end of the parent -bus, so with "pci=hpbussize" larger than the share the first port takes -all that are left. The ports after it are given a secondary bus past -the parent's subordinate and nothing behind them is enumerated. - -This shows up on software connection manager USB4 hosts that leave the -tunnel root ports unconfigured, where hpbussize is the only way to give -a root port bus numbers for a dock. With hpbussize=0x20 and a CalDigit -TS4 (Goshen Ridge), its first downstream port took buses 04-20 and the -port leading to the dock's Ethernet controller was left with: - - pci_bus 000b:21: busn_res: can not insert [bus 21-20] under [bus 02-20] (conflicts with (null) [bus 02-20]) - -Apply the minimum only to hotplug bridges that were not given a share, -such as root ports scanned at boot, and let the others keep to it. ---- - Documentation/admin-guide/kernel-parameters.txt | 3 +++ - drivers/pci/probe.c | 7 +++++-- - 2 files changed, 8 insertions(+), 2 deletions(-) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 489de55bb5..b21d66a8f2 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -5227,6 +5227,9 @@ Kernel parameters - Default size is 2 megabytes. - hpbussize=nn The minimum amount of additional bus numbers - reserved for buses below a hotplug bridge. -+ A hotplug bridge below a hot-added switch -+ gets its share of the switch's bus numbers -+ instead. - Default is 1. - realloc= Enable/disable reallocating PCI bridge resources - if allocations done by BIOS are too small to -diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c -index dd0abbc63e..876cf0dfed 100644 ---- a/drivers/pci/probe.c -+++ b/drivers/pci/probe.c -@@ -3168,10 +3168,13 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus, - /* - * Make sure a hotplug bridge has at least the minimum requested - * number of buses but allow it to grow up to the maximum available -- * bus number if there is room. -+ * bus number if there is room. A bridge that was handed a share of -+ * its parent's buses keeps to that share instead: the rest is meant -+ * for its siblings, and growing to the minimum would leave the -+ * hotplug bridges after it on the parent bus without any. - */ - if (bus->self && bus->self->is_hotplug_bridge) { -- used_buses = max(available_buses, pci_hotplug_bus_size - 1); -+ used_buses = available_buses ?: pci_hotplug_bus_size - 1; - if (max - start < used_buses) { - max = start + used_buses; - --- -2.56.0 - diff --git a/kernel/1079-thunderbolt-quirks-disable-CL-states-on-the-NVIDIA-N1x-host-router.patch b/kernel/1079-thunderbolt-quirks-disable-CL-states-on-the-NVIDIA-N1x-host-router.patch deleted file mode 100644 index a408eaa..0000000 --- a/kernel/1079-thunderbolt-quirks-disable-CL-states-on-the-NVIDIA-N1x-host-router.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 3b15351cf7545fe03251b8ef2a8437d10190923b Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Sat, 3 Oct 2026 02:43:39 -0400 -Subject: [PATCH] thunderbolt: quirks: disable CL states on the NVIDIA N1x host - router - -With CL states enabled on its links, the N1x host router runs the TMU -in uni-directional LowRes mode and only raises it to HiFi once a -DisplayPort tunnel has been activated, while the GPU is doing its first -link training. A monitor behind the tunnel (an LG 4K/240 Hz panel -behind a CalDigit TS4 here) then never syncs, drops HPD about 15 s -later, and the tunnel is torn down and set up again in a loop. On boot -this usually ends with the display left dark. - -With CL states off the TMU stays in bi-directional HiFi mode from the -start, and the tunnel comes up at the first attempt, both with the dock -attached at boot and on hotplug. ---- - drivers/thunderbolt/quirks.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c -index 9f7914ac2f..cc6938a789 100644 ---- a/drivers/thunderbolt/quirks.c -+++ b/drivers/thunderbolt/quirks.c -@@ -114,6 +114,12 @@ static const struct tb_quirk tb_quirks[] = { - { 0x0438, 0x0209, 0x0000, 0x0000, quirk_clx_disable }, - { 0x0438, 0x020a, 0x0000, 0x0000, quirk_clx_disable }, - { 0x0438, 0x020b, 0x0000, 0x0000, quirk_clx_disable }, -+ /* -+ * With CL states on the links of the NVIDIA N1x host router, a -+ * monitor behind a DisplayPort tunnel never syncs to the first link -+ * training and keeps dropping HPD. -+ */ -+ { 0x0955, 0x1372, 0x0000, 0x0000, quirk_clx_disable }, - }; - - /** --- -2.56.0 - diff --git a/kernel/1080-thunderbolt-keep-the-NVIDIA-N1x-routers-awake-in-system-sleep.patch b/kernel/1080-thunderbolt-keep-the-NVIDIA-N1x-routers-awake-in-system-sleep.patch deleted file mode 100644 index 959dfe4..0000000 --- a/kernel/1080-thunderbolt-keep-the-NVIDIA-N1x-routers-awake-in-system-sleep.patch +++ /dev/null @@ -1,95 +0,0 @@ -From d09991adf3f96a679d2cc82c0c427655606f592a Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Sat, 3 Oct 2026 15:50:45 -0400 -Subject: [PATCH 1080/1081] thunderbolt: keep the NVIDIA N1x routers awake in - system sleep - -The software connection manager asks every router to sleep on system -suspend. A router only leaves sleep through the reset it gets when the -host interface is powered off, as a PCI host interface is in system -sleep, and the connection manager reconfigures the routers from scratch -on resume. - -The N1x host interfaces are platform devices that stay powered through -suspend to idle, and the SSPM cannot bring a host router back once it -has been powered down. A host router with a device connected was then -left in sleep after resume and no longer answered the control channel, -so the device and its tunnels were lost until it was unplugged twice: - - thunderbolt-platform NVDA8100:02: 0: timeout writing config space 2 to 0x1 - thunderbolt-platform NVDA8100:02: 0: failed to restore TMU configuration - -Add a quirk for the N1x host router that keeps the routers of its domain -out of sleep in system sleep. Wakes are still configured, and resume -reconfigures awake routers just as it does reset ones. ---- - drivers/thunderbolt/quirks.c | 12 ++++++++++++ - drivers/thunderbolt/switch.c | 8 ++++++++ - drivers/thunderbolt/tb.h | 2 ++ - 3 files changed, 22 insertions(+) - -diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c -index cc6938a789..801b9472a4 100644 ---- a/drivers/thunderbolt/quirks.c -+++ b/drivers/thunderbolt/quirks.c -@@ -30,6 +30,12 @@ static void quirk_clx_disable(struct tb_switch *sw) - tb_sw_dbg(sw, "disabling CL states\n"); - } - -+static void quirk_no_system_sleep(struct tb_switch *sw) -+{ -+ sw->quirks |= QUIRK_NO_SYSTEM_SLEEP; -+ tb_sw_dbg(sw, "keeping routers awake in system sleep\n"); -+} -+ - static void quirk_usb3_maximum_bandwidth(struct tb_switch *sw) - { - struct tb_port *port; -@@ -120,6 +126,12 @@ static const struct tb_quirk tb_quirks[] = { - * training and keeps dropping HPD. - */ - { 0x0955, 0x1372, 0x0000, 0x0000, quirk_clx_disable }, -+ /* -+ * The NVIDIA N1x keeps its host routers powered through system sleep, -+ * so a router asked to sleep never gets the reset that brings it back -+ * and stops answering once a device is connected. -+ */ -+ { 0x0955, 0x1372, 0x0000, 0x0000, quirk_no_system_sleep }, - }; - - /** -diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c -index a830c82bb9..b3c0cba6ca 100644 ---- a/drivers/thunderbolt/switch.c -+++ b/drivers/thunderbolt/switch.c -@@ -3673,6 +3673,14 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime) - - tb_switch_set_wake(sw, flags, runtime); - -+ /* -+ * A router leaves sleep through the reset it gets when the host -+ * interface is powered off. Where that does not happen in system -+ * sleep, keep the routers awake instead. -+ */ -+ if (!runtime && (sw->tb->root_switch->quirks & QUIRK_NO_SYSTEM_SLEEP)) -+ return; -+ - if (tb_switch_is_usb4(sw)) - usb4_switch_set_sleep(sw); - else -diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h -index ec9192b61b..8e1fd42a9c 100644 ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -26,6 +26,8 @@ - #define QUIRK_NO_CLX BIT(1) - /* Need to keep power on while USB4 port is in redrive mode */ - #define QUIRK_KEEP_POWER_IN_DP_REDRIVE BIT(2) -+/* Host interface keeps its power in system sleep, so routers cannot sleep */ -+#define QUIRK_NO_SYSTEM_SLEEP BIT(3) - - /** - * struct tb_nvm - Structure holding NVM information --- -2.56.0 - diff --git a/kernel/1081-thunderbolt-platform-leave-the-N1x-host-routers-powered.patch b/kernel/1081-thunderbolt-platform-leave-the-N1x-host-routers-powered.patch deleted file mode 100644 index 3e8f7f4..0000000 --- a/kernel/1081-thunderbolt-platform-leave-the-N1x-host-routers-powered.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 2e739dbedbcd0aec693f1b19c7d3ed980f96bbe2 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Sat, 3 Oct 2026 15:51:29 -0400 -Subject: [PATCH 1081/1081] thunderbolt: platform: leave the N1x host routers - powered - -The SSPM powers a host router down when asked to, but powering it up -again does not restore what the boot firmware set up: the router stops -answering the control channel until the next boot. Unbinding the driver -or unloading the module powered the routers down, after which probing -them again failed: - - thunderbolt-platform NVDA8100:00: error -ETIMEDOUT: failed to allocate host router - -Drop the power-down hook and leave the routers powered. ---- - drivers/thunderbolt/nhi_platform.c | 36 +++++++----------------------- - 1 file changed, 8 insertions(+), 28 deletions(-) - -diff --git a/drivers/thunderbolt/nhi_platform.c b/drivers/thunderbolt/nhi_platform.c -index 62743ec450..0466801ce8 100644 ---- a/drivers/thunderbolt/nhi_platform.c -+++ b/drivers/thunderbolt/nhi_platform.c -@@ -32,11 +32,9 @@ struct nhi_plat; - /** - * struct nhi_plat_data - Platform specific host router handling - * @power_on: Power the host router before its registers are accessed -- * @power_off: Power the host router down again - */ - struct nhi_plat_data { - int (*power_on)(struct nhi_plat *np); -- void (*power_off)(struct nhi_plat *np); - }; - - /** -@@ -86,7 +84,7 @@ static int nhi_plat_init_interrupts(struct tb_nhi *nhi) - return ret; - } - --/* Called before the host router is powered down, so nothing reads it after */ -+/* Called when the host interface is shut down, so nothing reads it after */ - static void nhi_plat_shutdown(struct tb_nhi *nhi) - { - struct nhi_plat *np = nhi_to_plat(nhi); -@@ -107,6 +105,10 @@ static const struct tb_nhi_ops nhi_plat_ops = { - * leaves them powered at boot, but power_wrap can release them once xHCI is - * up, after which the SSPM stops answering for them altogether. A request - * then hangs it and resets the SoC, so refuse to touch them in that case. -+ * -+ * They are never powered down again: the SSPM can turn a host router off, -+ * but turning it back on does not restore what the boot firmware set up, and -+ * the router no longer answers until the next boot. - */ - static int nhi_nvda8100_power_on(struct nhi_plat *np) - { -@@ -136,26 +138,10 @@ static int nhi_nvda8100_power_on(struct nhi_plat *np) - return 0; - } - --static void nhi_nvda8100_power_off(struct nhi_plat *np) --{ -- int ret; -- -- ret = mtk_pwrap_dev_suspend(np->pwrap, 0); -- if (ret) -- dev_warn(np->nhi.dev, "cannot power the host router down: %d\n", ret); --} -- - static const struct nhi_plat_data nhi_nvda8100_data = { - .power_on = nhi_nvda8100_power_on, -- .power_off = nhi_nvda8100_power_off, - }; - --static void nhi_plat_power_off(struct nhi_plat *np) --{ -- if (np->data->power_off) -- np->data->power_off(np); --} -- - static int nhi_plat_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -195,11 +181,9 @@ static int nhi_plat_probe(struct platform_device *pdev) - /* nhi_probe() sizes everything from the path count; check it first */ - caps = ioread32(nhi->iobase + REG_CAPS); - paths = caps & 0x3ff; -- if (!paths || paths > NHI_PLAT_MAX_PATHS) { -- ret = dev_err_probe(dev, -ENODEV, -- "unexpected host interface capabilities %#x\n", caps); -- goto err_power_off; -- } -+ if (!paths || paths > NHI_PLAT_MAX_PATHS) -+ return dev_err_probe(dev, -ENODEV, -+ "unexpected host interface capabilities %#x\n", caps); - - pm_runtime_set_active(dev); - pm_runtime_get_noresume(dev); -@@ -222,18 +206,14 @@ static int nhi_plat_probe(struct platform_device *pdev) - err_put: - pm_runtime_put_noidle(dev); - nhi_plat_shutdown(nhi); --err_power_off: -- nhi_plat_power_off(np); - return ret; - } - - static void nhi_plat_remove(struct platform_device *pdev) - { - struct tb *tb = platform_get_drvdata(pdev); -- struct nhi_plat *np = nhi_to_plat(tb->nhi); - - nhi_remove(tb->nhi); -- nhi_plat_power_off(np); - } - - static const struct acpi_device_id nhi_plat_acpi_ids[] = { --- -2.56.0 - diff --git a/kernel/1082-thunderbolt-retry-the-NVIDIA-N1x-DP-IN-adapters-after-a-DPRX-failure.patch b/kernel/1082-thunderbolt-retry-the-NVIDIA-N1x-DP-IN-adapters-after-a-DPRX-failure.patch deleted file mode 100644 index c1c38f5..0000000 --- a/kernel/1082-thunderbolt-retry-the-NVIDIA-N1x-DP-IN-adapters-after-a-DPRX-failure.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 8b769a8b685abacfdf357e54463aeecc5220a135 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Tue, 6 Oct 2026 20:28:06 -0400 -Subject: [PATCH] thunderbolt: retry the NVIDIA N1x DP IN adapters after a DPRX - failure - -When a DP tunnel does not finish DPRX capability negotiation in time, -the connection manager tears it down and takes the DP IN adapter off -its DP resources until the adapter reports a hotplug again. The DP IN -adapters of the N1x host router are wired to the GPU on the same chip -and never report hotplug, so after one failed negotiation they stayed -unused until the router was reset, and every monitor behind a dock on -that port stayed black: - - 0:5 <-> 1:13 (DP): not active, tearing down - 0:5: DP IN resource unavailable: DPRX negotiation failed - no suitable DP IN adapter available, not tunneling - -That happened after the GPU had missed a monitor's HPD and the dock -was then replugged. - -Add a quirk for the N1x host router: when a DP OUT adapter becomes -available, offer the host router's DP IN adapters that dropped out -again, as long as they are not in use and the router still grants them -as DP resources. ---- - drivers/thunderbolt/quirks.c | 13 +++++++++++++ - drivers/thunderbolt/tb.c | 29 +++++++++++++++++++++++++++++ - drivers/thunderbolt/tb.h | 2 ++ - 3 files changed, 44 insertions(+) - -diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c -index 801b9472a..c620febc1 100644 ---- a/drivers/thunderbolt/quirks.c -+++ b/drivers/thunderbolt/quirks.c -@@ -36,6 +36,12 @@ static void quirk_no_system_sleep(struct tb_switch *sw) - tb_sw_dbg(sw, "keeping routers awake in system sleep\n"); - } - -+static void quirk_dp_in_retry(struct tb_switch *sw) -+{ -+ sw->quirks |= QUIRK_DP_IN_RETRY; -+ tb_sw_dbg(sw, "retrying DP IN adapters after DPRX failures\n"); -+} -+ - static void quirk_usb3_maximum_bandwidth(struct tb_switch *sw) - { - struct tb_port *port; -@@ -132,6 +138,13 @@ static const struct tb_quirk tb_quirks[] = { - * and stops answering once a device is connected. - */ - { 0x0955, 0x1372, 0x0000, 0x0000, quirk_no_system_sleep }, -+ /* -+ * The DP IN adapters of the NVIDIA N1x host router are wired to the -+ * GPU on the same chip and never report hotplug, so one DPRX -+ * negotiation that does not finish (the GPU missed a monitor's HPD) -+ * would leave them unused until the router is reset. -+ */ -+ { 0x0955, 0x1372, 0x0000, 0x0000, quirk_dp_in_retry }, - }; - - /** -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c -index c2fe72780..e2ceb02cb 100644 ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -2206,6 +2206,32 @@ static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port, - tb_tunnel_dp(tb); - } - -+/* -+ * A DP IN adapter whose tunnel did not finish DPRX negotiation is taken -+ * off the DP resources until it reports a hotplug. Host router DP IN -+ * adapters that never do get another chance when a monitor is plugged in. -+ */ -+static void tb_retry_host_dp_in(struct tb *tb) -+{ -+ struct tb_cm *tcm = tb_priv(tb); -+ struct tb_switch *sw = tb->root_switch; -+ struct tb_port *port; -+ -+ if (!(sw->quirks & QUIRK_DP_IN_RETRY)) -+ return; -+ -+ tb_switch_for_each_port(sw, port) { -+ if (!tb_port_is_dpin(port) || !list_empty(&port->list)) -+ continue; -+ if (tb_port_is_enabled(port) || -+ !tb_switch_query_dp_resource(sw, port)) -+ continue; -+ -+ tb_port_dbg(port, "DP IN resource available again\n"); -+ list_add_tail(&port->list, &tcm->dp_resources); -+ } -+} -+ - static void tb_dp_resource_available(struct tb *tb, struct tb_port *port) - { - struct tb_cm *tcm = tb_priv(tb); -@@ -2224,6 +2250,9 @@ static void tb_dp_resource_available(struct tb *tb, struct tb_port *port) - list_add_tail(&port->list, &tcm->dp_resources); - tb_exit_redrive(port); - -+ if (tb_port_is_dpout(port)) -+ tb_retry_host_dp_in(tb); -+ - /* Look for suitable DP IN <-> DP OUT pairs now */ - tb_tunnel_dp(tb); - } -diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h -index 8e1fd42a9..da7636c2f 100644 ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -28,6 +28,8 @@ - #define QUIRK_KEEP_POWER_IN_DP_REDRIVE BIT(2) - /* Host interface keeps its power in system sleep, so routers cannot sleep */ - #define QUIRK_NO_SYSTEM_SLEEP BIT(3) -+/* DP IN adapters never report hotplug, so retry them after a DPRX failure */ -+#define QUIRK_DP_IN_RETRY BIT(4) - - /** - * struct tb_nvm - Structure holding NVM information --- -2.56.0 - diff --git a/kernel/1083-usb-typec-ucsi-retry-init-when-the-PPM-answers-early-commands-incorrectly.patch b/kernel/1083-usb-typec-ucsi-retry-init-when-the-PPM-answers-early-commands-incorrectly.patch deleted file mode 100644 index 1a9606b..0000000 --- a/kernel/1083-usb-typec-ucsi-retry-init-when-the-PPM-answers-early-commands-incorrectly.patch +++ /dev/null @@ -1,92 +0,0 @@ -From ef5d2d246cd98c7f574a8ea9d4f3ef8c010db75e Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 9 Oct 2026 14:23:21 -0400 -Subject: [PATCH] usb: typec: ucsi: retry init when the PPM answers early - commands incorrectly - -On some platforms the PPM is not ready to answer commands correctly -for a short window during boot. On the Lenovo ThinkPad X1 Carbon -Gen 14 (21V7, tested on BIOS 1.12 and 1.14) roughly half of all boots -fail ucsi_init() with either -ENODEV (GET_CAPABILITY completes but -reports zero connectors) or -EINVAL (a standard command is rejected, -logged as "possible UCSI driver bug"). The failure is not a timeout: -increasing the sync command completion wait does not change the rate. - -Since ucsi_init_work() only requeues on -EPROBE_DEFER, a single bad -answer during that window leaves UCSI dead for the whole session, so -Type-C events are never handled again; most visibly, the machine -silently never resumes charging after the charger is replugged. -Manually reloading ucsi_acpi a few seconds later has succeeded on -every attempt observed, which suggests simply retrying is enough. - -Retry -ENODEV and -EINVAL the same way as the role switch wait, log -the retries at debug level, keep the loud report for the case where -the retries are exhausted, and note when init only succeeded after -retrying. - -Tested on the affected machine: across 8 consecutive boots with this -patch, 5 hit the failure (matching the historical ~50-60% rate) and -all 5 recovered on the first retry ("PPM init succeeded after 2 -attempts"). 0 of 8 boots ended with UCSI unusable, where ~5 of 8 -would have without the patch. - -Signed-off-by: Jacob Riff -Acked-by: Heikki Krogerus -Link: https://patch.msgid.link/20260824173536.2395830-1-jacob@riff.dk -Signed-off-by: Greg Kroah-Hartman ---- - drivers/usb/typec/ucsi/ucsi.c | 34 ++++++++++++++++++++++++++-------- - 1 file changed, 26 insertions(+), 8 deletions(-) - -diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c -index c1450639c..35e70211f 100644 ---- a/drivers/usb/typec/ucsi/ucsi.c -+++ b/drivers/usb/typec/ucsi/ucsi.c -@@ -2223,18 +2223,36 @@ static void ucsi_init_work(struct work_struct *work) - int ret; - - ret = ucsi_init(ucsi); -- if (ret) -- dev_err_probe(ucsi->dev, ret, "PPM init failed\n"); -+ if (!ret) { -+ if (ucsi->work_count) -+ dev_info(ucsi->dev, -+ "PPM init succeeded after %u attempts\n", -+ ucsi->work_count + 1); -+ return; -+ } - -- if (ret == -EPROBE_DEFER) { -- if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT) { -- dev_err(ucsi->dev, "PPM init failed, stop trying\n"); -+ /* -+ * On some platforms the PPM is not ready to answer commands -+ * correctly for a short window during boot: standard commands are -+ * rejected or GET_CAPABILITY reports zero connectors, seen as -+ * -EINVAL or -ENODEV from ucsi_init(), and a retry moments later -+ * succeeds (observed on Lenovo ThinkPad X1 Carbon Gen 14, where -+ * this affects roughly half of all boots). Retry those like the -+ * USB role switch wait instead of giving up on the first attempt. -+ */ -+ if (ret == -EPROBE_DEFER || ret == -ENODEV || ret == -EINVAL) { -+ if (ucsi->work_count++ < UCSI_ROLE_SWITCH_WAIT_COUNT) { -+ dev_dbg(ucsi->dev, "PPM init failed (%pe), retrying\n", -+ ERR_PTR(ret)); -+ queue_delayed_work(system_dfl_long_wq, &ucsi->work, -+ UCSI_ROLE_SWITCH_INTERVAL); - return; - } -- -- queue_delayed_work(system_dfl_long_wq, &ucsi->work, -- UCSI_ROLE_SWITCH_INTERVAL); -+ dev_err(ucsi->dev, "PPM init failed, stop trying\n"); -+ return; - } -+ -+ dev_err_probe(ucsi->dev, ret, "PPM init failed\n"); - } - - /** --- -2.56.0 - diff --git a/kernel/1084-usb-typec-ucsi-allow-retries-of-ucsi_resume_work.patch b/kernel/1084-usb-typec-ucsi-allow-retries-of-ucsi_resume_work.patch deleted file mode 100644 index 3288e95..0000000 --- a/kernel/1084-usb-typec-ucsi-allow-retries-of-ucsi_resume_work.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 3f8793ad5a95d20bf4af99d91263430c3266684d Mon Sep 17 00:00:00 2001 -From: Jameson Thies -Date: Fri, 4 Sep 2026 23:41:23 +0000 -Subject: [PATCH] usb: typec: ucsi: allow retries of ucsi_resume_work - -On resume, the UCSI driver will re-enable notifications by sending -SET_NOTIFICATION_ENABLE. The LPM/PPM may be busy during system -resume causing SET_NOTIFICATION_ENABLE to fail and preventing the UCSI -driver from receiving connection status changes. - -Change resume work to a delayed workqueue to allow retries on failed -SET_NOTIFICATION_ENABLED commands. Additionally, cancel resume work -on suspend to prevent pending resume commands from impacting suspend. - -Signed-off-by: Jameson Thies -Reviewed-by: Benson Leung -Reviewed-by: Heikki Krogerus -Acked-by: Marco Crivellari -Link: https://patch.msgid.link/20260904234124.2336922-1-jthies@google.com -Signed-off-by: Greg Kroah-Hartman ---- - drivers/usb/typec/ucsi/ucsi.c | 18 +++++++++++++----- - drivers/usb/typec/ucsi/ucsi.h | 3 ++- - 2 files changed, 15 insertions(+), 6 deletions(-) - -diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c -index 35e70211f..a5479e488 100644 ---- a/drivers/usb/typec/ucsi/ucsi.c -+++ b/drivers/usb/typec/ucsi/ucsi.c -@@ -2169,7 +2169,7 @@ static int ucsi_init(struct ucsi *ucsi) - - static void ucsi_resume_work(struct work_struct *work) - { -- struct ucsi *ucsi = container_of(work, struct ucsi, resume_work); -+ struct ucsi *ucsi = container_of(to_delayed_work(work), struct ucsi, resume_work); - struct ucsi_connector *con; - u64 command; - int ret; -@@ -2178,6 +2178,11 @@ static void ucsi_resume_work(struct work_struct *work) - command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy; - ret = ucsi_send_command(ucsi, command, NULL, 0); - if (ret < 0) { -+ if (++ucsi->resume_retries < 5) { -+ queue_delayed_work(system_dfl_long_wq, &ucsi->resume_work, -+ msecs_to_jiffies(500)); -+ return; -+ } - dev_err(ucsi->dev, "failed to re-enable notifications (%d)\n", ret); - return; - } -@@ -2198,6 +2203,7 @@ int ucsi_suspend(struct ucsi *ucsi) - * EC is stopped for suspend; state is re-read on resume. - */ - cancel_delayed_work_sync(&ucsi->work); -+ cancel_delayed_work_sync(&ucsi->resume_work); - - if (!ucsi->connector) - return 0; -@@ -2211,8 +2217,10 @@ EXPORT_SYMBOL_GPL(ucsi_suspend); - - int ucsi_resume(struct ucsi *ucsi) - { -- if (ucsi->connector) -- queue_work(system_long_wq, &ucsi->resume_work); -+ if (ucsi->connector) { -+ ucsi->resume_retries = 0; -+ queue_delayed_work(system_dfl_long_wq, &ucsi->resume_work, 0); -+ } - return 0; - } - EXPORT_SYMBOL_GPL(ucsi_resume); -@@ -2328,7 +2336,7 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops) - if (!ucsi) - return ERR_PTR(-ENOMEM); - -- INIT_WORK(&ucsi->resume_work, ucsi_resume_work); -+ INIT_DELAYED_WORK(&ucsi->resume_work, ucsi_resume_work); - INIT_DELAYED_WORK(&ucsi->work, ucsi_init_work); - mutex_init(&ucsi->ppm_lock); - init_completion(&ucsi->complete); -@@ -2394,7 +2402,7 @@ void ucsi_unregister(struct ucsi *ucsi) - - /* Make sure that we are not in the middle of driver initialization */ - cancel_delayed_work_sync(&ucsi->work); -- cancel_work_sync(&ucsi->resume_work); -+ cancel_delayed_work_sync(&ucsi->resume_work); - - ucsi_debugfs_unregister(ucsi); - -diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h -index dc594388d..1996f04ed 100644 ---- a/drivers/usb/typec/ucsi/ucsi.h -+++ b/drivers/usb/typec/ucsi/ucsi.h -@@ -484,7 +484,8 @@ struct ucsi { - struct ucsi_connector *connector; - struct ucsi_debugfs_entry *debugfs; - -- struct work_struct resume_work; -+ struct delayed_work resume_work; -+ int resume_retries; - struct delayed_work work; - int work_count; - #define UCSI_ROLE_SWITCH_RETRY_PER_HZ 10 --- -2.56.0 - diff --git a/kernel/1085-thunderbolt-keep-the-tunnels-of-routers-kept-awake-in-system-sleep.patch b/kernel/1085-thunderbolt-keep-the-tunnels-of-routers-kept-awake-in-system-sleep.patch deleted file mode 100644 index 1713e38..0000000 --- a/kernel/1085-thunderbolt-keep-the-tunnels-of-routers-kept-awake-in-system-sleep.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 5ad67692f07f46de90dff79ed567c7eeb88b7ece Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Mon, 12 Oct 2026 18:26:36 -0400 -Subject: [PATCH] thunderbolt: keep the tunnels of routers kept awake in system - sleep - -With QUIRK_NO_SYSTEM_SLEEP the N1x routers stay awake through suspend to -idle and keep their configuration, but suspend and resume still treat -them as reset. Resume discovers the tunnels it finds in the hardware, -which are its own, tears them down and builds them again. With a dock -connected that dropped the dock's USB devices; the USB3 tunnel did not -get its bandwidth back and the xHCI behind it stopped responding 15 s -later: - - thunderbolt-platform NVDA8100:00: 0:4 <-> 1:16 (USB3): failed to allocate bandwidth - xhci-hcd NVDA8000:00: xHCI host controller not responding, assume dead - -The DP tunnels, torn down for every system sleep, never came back -either. They return through the plug events of routers that were reset, -and routers kept awake send none, so the dock's displays stayed dark -until the dock was replugged. - -When the routers are kept awake, keep all their tunnels, the DP ones -included, through system sleep, as runtime suspend keeps the PCIe and -USB3 ones. The monitors then see the display turned off, as they do -when the screen blanks, and the GPU finds them where it left them on -resume. ---- - drivers/thunderbolt/tb.c | 29 ++++++++++++++++++++++++++++- - 1 file changed, 28 insertions(+), 1 deletion(-) - -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c -index 7b97bfa70..68a192db3 100644 ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -70,6 +70,9 @@ struct tb_pci_rescan { - * @remove_work: Work used to remove any unplugged routers after - * runtime resume - * @groups: Bandwidth groups used in this domain. -+ * @kept_awake: The routers stayed awake through the current system sleep -+ * (%QUIRK_NO_SYSTEM_SLEEP), so they kept their configuration -+ * and their tunnels. - */ - struct tb_cm { - struct list_head tunnel_list; -@@ -78,6 +81,7 @@ struct tb_cm { - struct delayed_work remove_work; - struct tb_bandwidth_group groups[MAX_GROUPS]; - struct tb_pci_rescan *pci_rescan; -+ bool kept_awake; - }; - - static struct workqueue_struct *tb_pci_rescan_wq; -@@ -3231,7 +3235,15 @@ static int tb_suspend_noirq(struct tb *tb) - struct tb_cm *tcm = tb_priv(tb); - - tb_dbg(tb, "suspending...\n"); -- tb_disconnect_and_release_dp(tb); -+ tcm->kept_awake = tb->root_switch->quirks & QUIRK_NO_SYSTEM_SLEEP; -+ /* -+ * The DP tunnels come back through the plug events of routers -+ * that were reset. Routers kept awake send none, so keep their -+ * DP tunnels too: the monitors then see the display turned off, -+ * as they do when the screen blanks. -+ */ -+ if (!tcm->kept_awake) -+ tb_disconnect_and_release_dp(tb); - tb_switch_exit_redrive(tb->root_switch); - tb_switch_suspend(tb->root_switch, false); - tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ -@@ -3312,6 +3324,20 @@ static int tb_resume_noirq(struct tb *tb) - tb_free_unplugged_xdomains(tb->root_switch); - tb_restore_children(tb->root_switch); - -+ /* -+ * Routers kept awake still carry the paths of all our tunnels, -+ * and the devices behind them stayed connected. Tearing -+ * the tunnels down and building them again here only drops those -+ * devices: the USB3 tunnel then fails to get its bandwidth back -+ * and the xHCI behind it stops responding. Keep them, as runtime -+ * resume does. -+ */ -+ if (tcm->kept_awake) { -+ tcm->kept_awake = false; -+ tb_dbg(tb, "routers stayed awake, keeping tunnels\n"); -+ goto out; -+ } -+ - /* - * If we get here from suspend to disk the boot firmware or the - * restore kernel might have created tunnels of its own. Since -@@ -3344,6 +3370,7 @@ static int tb_resume_noirq(struct tb *tb) - tb_dbg(tb, "tunnels restarted, sleeping for 100ms\n"); - msleep(100); - } -+out: - tb_switch_enter_redrive(tb->root_switch); - /* Allow tb_handle_hotplug to progress events */ - tcm->hotplug_active = true; --- -2.56.0 - diff --git a/kernel/1086-thunderbolt-space-out-the-NVIDIA-N1x-DP-tunnel-teardowns.patch b/kernel/1086-thunderbolt-space-out-the-NVIDIA-N1x-DP-tunnel-teardowns.patch deleted file mode 100644 index d2650cc..0000000 --- a/kernel/1086-thunderbolt-space-out-the-NVIDIA-N1x-DP-tunnel-teardowns.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Wed, 14 Oct 2026 15:59:30 -0400 -Subject: [PATCH] thunderbolt: space out the NVIDIA N1x DP tunnel teardowns - -Unplugging a dock with two monitors tears down both DP tunnels within -a few milliseconds, and each teardown drops HPD on its DP IN adapter -towards the GPU. The N1x GPU firmware handles only the first of the -two drops. It keeps reporting the other monitor as connected, and -after a replug that monitor never finishes DPRX negotiation and stays -black until the next system sleep: - - 0:5 <-> 1:13 (DP): deactivating - 0:6 <-> 1:14 (DP): deactivating - nvidia-modeset: WARNING: DPCONN> Zombie? : 1 00000000419641c3 - -Add a quirk for the N1x host router that waits between DP tunnel -teardowns, 100 ms by default, adjustable with the dp_teardown_delay -module parameter. ---- - drivers/thunderbolt/quirks.c | 13 +++++++++++++ - drivers/thunderbolt/tb.c | 30 ++++++++++++++++++++++++++++-- - drivers/thunderbolt/tb.h | 2 ++ - 3 files changed, 43 insertions(+), 2 deletions(-) - -diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c -index 6852e4b..d9dd309 100644 ---- a/drivers/thunderbolt/quirks.c -+++ b/drivers/thunderbolt/quirks.c -@@ -42,6 +42,12 @@ static void quirk_dp_in_retry(struct tb_switch *sw) - tb_sw_dbg(sw, "retrying DP IN adapters after DPRX failures\n"); - } - -+static void quirk_dp_teardown_delay(struct tb_switch *sw) -+{ -+ sw->quirks |= QUIRK_DP_TEARDOWN_DELAY; -+ tb_sw_dbg(sw, "spacing out DP tunnel teardowns\n"); -+} -+ - static void quirk_usb3_maximum_bandwidth(struct tb_switch *sw) - { - struct tb_port *port; -@@ -148,6 +154,13 @@ static const struct tb_quirk tb_quirks[] = { - * would leave them unused until the router is reset. - */ - { 0x0955, 0x1372, 0x0000, 0x0000, quirk_dp_in_retry }, -+ /* -+ * When a dock with two monitors is unplugged, the N1x GPU firmware -+ * misses the second of two HPD drops that arrive within a few -+ * milliseconds and keeps reporting that monitor as connected until -+ * the next system sleep, so it cannot be used again after a replug. -+ */ -+ { 0x0955, 0x1372, 0x0000, 0x0000, quirk_dp_teardown_delay }, - }; - - /** -diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c -index 68a192d..a180989 100644 ---- a/drivers/thunderbolt/tb.c -+++ b/drivers/thunderbolt/tb.c -@@ -52,6 +52,14 @@ MODULE_PARM_DESC(asym_threshold, - "threshold (Mb/s) when to Gen 4 switch link symmetry. 0 disables. (default: " - __MODULE_STRING(TB_ASYM_THRESHOLD) ")"); - -+#define TB_DP_TEARDOWN_DELAY 100 /* ms */ -+ -+static unsigned int dp_teardown_delay = TB_DP_TEARDOWN_DELAY; -+module_param(dp_teardown_delay, uint, 0644); -+MODULE_PARM_DESC(dp_teardown_delay, -+ "delay (ms) between DP tunnel teardowns on routers that need it (default: " -+ __MODULE_STRING(TB_DP_TEARDOWN_DELAY) ")"); -+ - struct tb_pci_rescan { - struct delayed_work work; - struct kref kref; -@@ -1796,10 +1804,28 @@ static void tb_free_invalid_tunnels(struct tb *tb) - struct tb_cm *tcm = tb_priv(tb); - struct tb_tunnel *tunnel; - struct tb_tunnel *n; -+ bool dp_freed = false; - - list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) { -- if (tb_tunnel_is_invalid(tunnel)) -- tb_deactivate_and_free_tunnel(tunnel); -+ if (!tb_tunnel_is_invalid(tunnel)) -+ continue; -+ -+ /* -+ * Tearing down a DP tunnel drops HPD towards the graphics -+ * driver. Some GPUs miss one of two drops that arrive -+ * together, so give them time to handle each. -+ */ -+ if (tb_tunnel_is_dp(tunnel)) { -+ if (dp_freed && -+ tb->root_switch->quirks & QUIRK_DP_TEARDOWN_DELAY) { -+ tb_tunnel_dbg(tunnel, "waiting %u ms before tearing down\n", -+ dp_teardown_delay); -+ msleep(dp_teardown_delay); -+ } -+ dp_freed = true; -+ } -+ -+ tb_deactivate_and_free_tunnel(tunnel); - } - } - -diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h -index ce03453..27de83a 100644 ---- a/drivers/thunderbolt/tb.h -+++ b/drivers/thunderbolt/tb.h -@@ -30,6 +30,8 @@ - #define QUIRK_NO_SYSTEM_SLEEP BIT(3) - /* DP IN adapters never report hotplug, so retry them after a DPRX failure */ - #define QUIRK_DP_IN_RETRY BIT(4) -+/* GPU misses one of two HPD drops that arrive together, so space them out */ -+#define QUIRK_DP_TEARDOWN_DELAY BIT(5) - - /** - * struct tb_nvm - Structure holding NVM information --- -2.56.0 - diff --git a/kernel/1087-PCI-ACPI-Mark-USB4-tunneled-devices-removable-on-every-ACPI-platform.patch b/kernel/1087-PCI-ACPI-Mark-USB4-tunneled-devices-removable-on-every-ACPI-platform.patch deleted file mode 100644 index 13b7848..0000000 --- a/kernel/1087-PCI-ACPI-Mark-USB4-tunneled-devices-removable-on-every-ACPI-platform.patch +++ /dev/null @@ -1,362 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Thu, 15 Oct 2026 21:45:05 -0400 -Subject: [PATCH] PCI/ACPI: Mark USB4 tunneled devices removable on every ACPI - platform - -Whether a PCI device is tunneled through a USB4/Thunderbolt port, and so -untrusted and removable, is decided by arch_pci_dev_is_removable(). Only -x86 implements it, although it reads nothing but ACPI: the -"ExternalFacingPort" property of the Root Port and the -"usb4-host-interface" property of the tunneling port. - -ACPI arm64 laptops with USB4, such as those built on the NVIDIA N1x, -describe their tunnel Root Ports with the same properties. There the -check is stubbed out, so everything plugged into a dock is trusted: it -keeps the identity domain of a passthrough IOMMU and is never bounced, -and the Thunderbolt core cannot honestly report DMA protection. - -Move the check into pci-acpi.c as pci_acpi_dev_is_removable() so every -ACPI platform uses it. The Intel Root Port IDs it falls back to only -match Intel devices, so nothing changes on x86. ---- - arch/x86/pci/acpi.c | 119 -------------------------------------- - drivers/pci/pci-acpi.c | 127 +++++++++++++++++++++++++++++++++++++++++ - drivers/pci/pci.h | 5 ++ - drivers/pci/probe.c | 4 +- - include/linux/pci.h | 6 -- - 5 files changed, 134 insertions(+), 127 deletions(-) - -diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c -index 7cd5388..463d474 100644 ---- a/arch/x86/pci/acpi.c -+++ b/arch/x86/pci/acpi.c -@@ -250,125 +250,6 @@ void __init pci_acpi_crs_quirks(void) - pr_info("Please notify linux-pci@vger.kernel.org so future kernels can do this automatically\n"); - } - --/* -- * Check if pdev is part of a PCIe switch that is directly below the -- * specified bridge. -- */ --static bool pcie_switch_directly_under(struct pci_dev *bridge, -- struct pci_dev *pdev) --{ -- struct pci_dev *parent = pci_upstream_bridge(pdev); -- -- /* If the device doesn't have a parent, it's not under anything */ -- if (!parent) -- return false; -- -- /* -- * If the device has a PCIe type, check if it is below the -- * corresponding PCIe switch components (if applicable). Then check -- * if its upstream port is directly beneath the specified bridge. -- */ -- switch (pci_pcie_type(pdev)) { -- case PCI_EXP_TYPE_UPSTREAM: -- return parent == bridge; -- -- case PCI_EXP_TYPE_DOWNSTREAM: -- if (pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM) -- return false; -- parent = pci_upstream_bridge(parent); -- return parent == bridge; -- -- case PCI_EXP_TYPE_ENDPOINT: -- if (pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM) -- return false; -- parent = pci_upstream_bridge(parent); -- if (!parent || pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM) -- return false; -- parent = pci_upstream_bridge(parent); -- return parent == bridge; -- } -- -- return false; --} -- --static bool pcie_has_usb4_host_interface(struct pci_dev *pdev) --{ -- struct fwnode_handle *fwnode; -- -- /* -- * For USB4, the tunneled PCIe Root or Downstream Ports are marked -- * with the "usb4-host-interface" ACPI property, so we look for -- * that first. This should cover most cases. -- */ -- fwnode = fwnode_find_reference(dev_fwnode(&pdev->dev), -- "usb4-host-interface", 0); -- if (!IS_ERR(fwnode)) { -- fwnode_handle_put(fwnode); -- return true; -- } -- -- /* -- * Any integrated Thunderbolt 3/4 PCIe Root Ports from Intel -- * before Alder Lake do not have the "usb4-host-interface" -- * property so we use their PCI IDs instead. All these are -- * tunneled. This list is not expected to grow. -- */ -- if (pdev->vendor == PCI_VENDOR_ID_INTEL) { -- switch (pdev->device) { -- /* Ice Lake Thunderbolt 3 PCIe Root Ports */ -- case 0x8a1d: -- case 0x8a1f: -- case 0x8a21: -- case 0x8a23: -- /* Tiger Lake-LP Thunderbolt 4 PCIe Root Ports */ -- case 0x9a23: -- case 0x9a25: -- case 0x9a27: -- case 0x9a29: -- /* Tiger Lake-H Thunderbolt 4 PCIe Root Ports */ -- case 0x9a2b: -- case 0x9a2d: -- case 0x9a2f: -- case 0x9a31: -- return true; -- } -- } -- -- return false; --} -- --bool arch_pci_dev_is_removable(struct pci_dev *pdev) --{ -- struct pci_dev *parent, *root; -- -- /* pdev without a parent or Root Port is never tunneled */ -- parent = pci_upstream_bridge(pdev); -- if (!parent) -- return false; -- root = pcie_find_root_port(pdev); -- if (!root) -- return false; -- -- /* Internal PCIe devices are not tunneled */ -- if (!root->external_facing) -- return false; -- -- /* Anything directly behind a "usb4-host-interface" is tunneled */ -- if (pcie_has_usb4_host_interface(parent)) -- return true; -- -- /* -- * Check if this is a discrete Thunderbolt/USB4 controller that is -- * directly behind the non-USB4 PCIe Root Port marked as -- * "ExternalFacingPort". Those are not behind a PCIe tunnel. -- */ -- if (pcie_switch_directly_under(root, pdev)) -- return false; -- -- /* PCIe devices after the discrete chip are tunneled */ -- return true; --} -- - #ifdef CONFIG_PCI_MMCONFIG - static int check_segment(u16 seg, struct device *dev, char *estr) - { -diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c -index 4d0f2cb..2b1a85e 100644 ---- a/drivers/pci/pci-acpi.c -+++ b/drivers/pci/pci-acpi.c -@@ -1430,6 +1430,133 @@ static void pci_acpi_set_external_facing(struct pci_dev *dev) - dev->external_facing = 1; - } - -+/* -+ * Check if pdev is part of a PCIe switch that is directly below the -+ * specified bridge. -+ */ -+static bool pcie_switch_directly_under(struct pci_dev *bridge, -+ struct pci_dev *pdev) -+{ -+ struct pci_dev *parent = pci_upstream_bridge(pdev); -+ -+ /* If the device doesn't have a parent, it's not under anything */ -+ if (!parent) -+ return false; -+ -+ /* -+ * If the device has a PCIe type, check if it is below the -+ * corresponding PCIe switch components (if applicable). Then check -+ * if its upstream port is directly beneath the specified bridge. -+ */ -+ switch (pci_pcie_type(pdev)) { -+ case PCI_EXP_TYPE_UPSTREAM: -+ return parent == bridge; -+ -+ case PCI_EXP_TYPE_DOWNSTREAM: -+ if (pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM) -+ return false; -+ parent = pci_upstream_bridge(parent); -+ return parent == bridge; -+ -+ case PCI_EXP_TYPE_ENDPOINT: -+ if (pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM) -+ return false; -+ parent = pci_upstream_bridge(parent); -+ if (!parent || pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM) -+ return false; -+ parent = pci_upstream_bridge(parent); -+ return parent == bridge; -+ } -+ -+ return false; -+} -+ -+static bool pcie_has_usb4_host_interface(struct pci_dev *pdev) -+{ -+ struct fwnode_handle *fwnode; -+ -+ /* -+ * For USB4, the tunneled PCIe Root or Downstream Ports are marked -+ * with the "usb4-host-interface" ACPI property, so we look for -+ * that first. This should cover most cases. -+ */ -+ fwnode = fwnode_find_reference(dev_fwnode(&pdev->dev), -+ "usb4-host-interface", 0); -+ if (!IS_ERR(fwnode)) { -+ fwnode_handle_put(fwnode); -+ return true; -+ } -+ -+ /* -+ * Any integrated Thunderbolt 3/4 PCIe Root Ports from Intel -+ * before Alder Lake do not have the "usb4-host-interface" -+ * property so we use their PCI IDs instead. All these are -+ * tunneled. This list is not expected to grow. -+ */ -+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) { -+ switch (pdev->device) { -+ /* Ice Lake Thunderbolt 3 PCIe Root Ports */ -+ case 0x8a1d: -+ case 0x8a1f: -+ case 0x8a21: -+ case 0x8a23: -+ /* Tiger Lake-LP Thunderbolt 4 PCIe Root Ports */ -+ case 0x9a23: -+ case 0x9a25: -+ case 0x9a27: -+ case 0x9a29: -+ /* Tiger Lake-H Thunderbolt 4 PCIe Root Ports */ -+ case 0x9a2b: -+ case 0x9a2d: -+ case 0x9a2f: -+ case 0x9a31: -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+/** -+ * pci_acpi_dev_is_removable - Is @pdev tunneled through a USB4/Thunderbolt port? -+ * @pdev: PCI device -+ * -+ * The firmware marks the Root Ports that expose PCIe outside the system -+ * with "ExternalFacingPort", and the tunneled ones of a USB4 host with -+ * "usb4-host-interface". Nothing here is specific to one architecture. -+ */ -+bool pci_acpi_dev_is_removable(struct pci_dev *pdev) -+{ -+ struct pci_dev *parent, *root; -+ -+ /* pdev without a parent or Root Port is never tunneled */ -+ parent = pci_upstream_bridge(pdev); -+ if (!parent) -+ return false; -+ root = pcie_find_root_port(pdev); -+ if (!root) -+ return false; -+ -+ /* Internal PCIe devices are not tunneled */ -+ if (!root->external_facing) -+ return false; -+ -+ /* Anything directly behind a "usb4-host-interface" is tunneled */ -+ if (pcie_has_usb4_host_interface(parent)) -+ return true; -+ -+ /* -+ * Check if this is a discrete Thunderbolt/USB4 controller that is -+ * directly behind the non-USB4 PCIe Root Port marked as -+ * "ExternalFacingPort". Those are not behind a PCIe tunnel. -+ */ -+ if (pcie_switch_directly_under(root, pdev)) -+ return false; -+ -+ /* PCIe devices after the discrete chip are tunneled */ -+ return true; -+} -+ - void pci_acpi_setup(struct device *dev, struct acpi_device *adev) - { - struct pci_dev *pci_dev = to_pci_dev(dev); -diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h -index e116e86..1e2cf91 100644 ---- a/drivers/pci/pci.h -+++ b/drivers/pci/pci.h -@@ -1350,6 +1350,7 @@ static inline void pci_restore_aer_state(struct pci_dev *dev) { } - #ifdef CONFIG_ACPI - bool pci_acpi_preserve_config(struct pci_host_bridge *bridge); - int pci_acpi_program_hp_params(struct pci_dev *dev); -+bool pci_acpi_dev_is_removable(struct pci_dev *pdev); - extern const struct attribute_group pci_dev_acpi_attr_group; - void pci_set_acpi_fwnode(struct pci_dev *dev); - int pci_dev_acpi_reset(struct pci_dev *dev, bool probe); -@@ -1375,6 +1376,10 @@ static inline int pci_acpi_program_hp_params(struct pci_dev *dev) - { - return -ENODEV; - } -+static inline bool pci_acpi_dev_is_removable(struct pci_dev *pdev) -+{ -+ return false; -+} - static inline bool acpi_pci_power_manageable(struct pci_dev *dev) - { - return false; -diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c -index 876cf0d..22aed98 100644 ---- a/drivers/pci/probe.c -+++ b/drivers/pci/probe.c -@@ -1748,7 +1748,7 @@ static void set_pcie_untrusted(struct pci_dev *dev) - return; - } - -- if (arch_pci_dev_is_removable(dev)) { -+ if (pci_acpi_dev_is_removable(dev)) { - pci_dbg(dev, "marking as untrusted\n"); - dev->untrusted = true; - } -@@ -1776,7 +1776,7 @@ static void pci_set_removable(struct pci_dev *dev) - return; - } - -- if (arch_pci_dev_is_removable(dev)) { -+ if (pci_acpi_dev_is_removable(dev)) { - pci_dbg(dev, "marking as removable\n"); - dev_set_removable(&dev->dev, DEVICE_REMOVABLE); - } -diff --git a/include/linux/pci.h b/include/linux/pci.h -index 66a4fda..bdc9b2e 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -2818,12 +2818,6 @@ pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; } - static inline bool pci_pr3_present(struct pci_dev *pdev) { return false; } - #endif - --#if defined(CONFIG_X86) && defined(CONFIG_ACPI) --bool arch_pci_dev_is_removable(struct pci_dev *pdev); --#else --static inline bool arch_pci_dev_is_removable(struct pci_dev *pdev) { return false; } --#endif -- - #ifdef CONFIG_EEH - static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) - { --- -2.56.0 - diff --git a/kernel/1088-iommu-Give-external-facing-ports-the-domain-of-untrusted-devices.patch b/kernel/1088-iommu-Give-external-facing-ports-the-domain-of-untrusted-devices.patch deleted file mode 100644 index 71ec1c0..0000000 --- a/kernel/1088-iommu-Give-external-facing-ports-the-domain-of-untrusted-devices.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Thu, 15 Oct 2026 21:45:49 -0400 -Subject: [PATCH] iommu: Give external-facing ports the domain of untrusted - devices - -Devices tunneled below an external-facing Root Port are untrusted, and -iommu_get_default_domain_type() gives an untrusted device a DMA domain -even when the default is passthrough. That only works when the device -gets a group of its own. Behind a Root Port without ACS, such as the -USB4 tunnel Root Ports of the NVIDIA N1x, everything plugged in later -joins the Root Port's own group. Its domain was chosen at boot, when -only the trusted port was in it, so with IOMMU_DEFAULT_PASSTHROUGH a -dock's xHCI and Ethernet controller ran with an identity mapping. -Joining an existing group does not go through -iommu_get_default_domain_type(), so nothing noticed. - -Choose the domain of an external-facing port as if it were untrusted, -so whatever it carries later is translated, and refuse to probe an -untrusted device that would join a group in an identity domain rather -than give it unrestricted DMA. ---- - drivers/iommu/iommu.c | 30 +++++++++++++++++++++++++++++- - 1 file changed, 29 insertions(+), 1 deletion(-) - -diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c -index 23a5315..4639783 100644 ---- a/drivers/iommu/iommu.c -+++ b/drivers/iommu/iommu.c -@@ -667,6 +667,18 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list - */ - list_add_tail(&gdev->list, &group->devices); - WARN_ON(group->default_domain && !group->domain); -+ /* -+ * A device joining a group that already has a domain is not run -+ * through iommu_get_default_domain_type(). Never let an untrusted one -+ * share an identity domain. -+ */ -+ if (group->domain && group->domain->type == IOMMU_DOMAIN_IDENTITY && -+ dev_is_pci(dev) && to_pci_dev(dev)->untrusted) { -+ dev_err(dev, "Device is not trusted, but IOMMU group %u is in an identity domain, refusing to probe.\n", -+ group->id); -+ ret = -EPERM; -+ goto err_remove_gdev; -+ } - if (group->default_domain) - iommu_create_device_direct_mappings(group->default_domain, dev); - if (group->domain) { -@@ -1872,6 +1884,22 @@ static int iommu_get_def_domain_type(struct iommu_group *group, - return cur_type; - } - -+/* -+ * Devices plugged in below an external-facing Root Port are untrusted. When -+ * the port does not isolate them with ACS they join the port's own group, -+ * whose domain was chosen before anything was plugged in, so the port needs -+ * the same domain as the untrusted devices it will carry. -+ */ -+static bool iommu_dev_needs_untrusted_domain(struct device *dev) -+{ -+ struct pci_dev *pdev; -+ -+ if (!dev_is_pci(dev)) -+ return false; -+ pdev = to_pci_dev(dev); -+ return pdev->untrusted || pdev->external_facing; -+} -+ - /* - * A target_type of 0 will select the best domain type. 0 can be returned in - * this case meaning the global default should be used. -@@ -1901,7 +1929,7 @@ static int iommu_get_default_domain_type(struct iommu_group *group, - driver_type = iommu_get_def_domain_type(group, gdev->dev, - driver_type); - -- if (dev_is_pci(gdev->dev) && to_pci_dev(gdev->dev)->untrusted) { -+ if (iommu_dev_needs_untrusted_domain(gdev->dev)) { - /* - * No ARM32 using systems will set untrusted, it cannot - * work. --- -2.56.0 - diff --git a/kernel/1089-thunderbolt-platform-report-IOMMU-DMA-protection-for-the-NVIDIA-N1x.patch b/kernel/1089-thunderbolt-platform-report-IOMMU-DMA-protection-for-the-NVIDIA-N1x.patch deleted file mode 100644 index fb730e3..0000000 --- a/kernel/1089-thunderbolt-platform-report-IOMMU-DMA-protection-for-the-NVIDIA-N1x.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Thu, 15 Oct 2026 21:46:35 -0400 -Subject: [PATCH] thunderbolt: platform: report IOMMU DMA protection for the - NVIDIA N1x - -The PCI glue reports IOMMU DMA protection when a Root Port of the NHI's -segment is external facing and the IOMMU has pre-boot protection. The -platform glue never set it, so the N1x reported none, and Bolt left -every new dock unauthorized: its display tunnel came up, while its USB -controller and Ethernet never appeared until someone ran -"boltctl enroll". - -Check the Root Ports whose "usb4-host-interface" property names this -host interface instead. When each is external facing and behind an -IOMMU, what is plugged in below is untrusted and translated. Arm SMMUs -do not report pre-boot protection, but on the N1x there is nothing for -it to cover: the firmware has no connection manager and the OS powers -the host router, so no PCIe tunnel exists before this driver creates -one. Bolt then enrolls and authorizes new docks on its own, as it does -on Intel and AMD laptops. ---- - drivers/thunderbolt/nhi_platform.c | 57 ++++++++++++++++++++++++++++++ - 1 file changed, 57 insertions(+) - -diff --git a/drivers/thunderbolt/nhi_platform.c b/drivers/thunderbolt/nhi_platform.c -index 0466801..c50fb62 100644 ---- a/drivers/thunderbolt/nhi_platform.c -+++ b/drivers/thunderbolt/nhi_platform.c -@@ -11,10 +11,13 @@ - #include - #include - #include -+#include - #include -+#include - #include - #include - #include -+#include - #include - - #include "nhi.h" -@@ -32,9 +35,12 @@ struct nhi_plat; - /** - * struct nhi_plat_data - Platform specific host router handling - * @power_on: Power the host router before its registers are accessed -+ * @no_firmware_tunnels: The firmware has no connection manager, so no PCIe -+ * tunnel exists before this driver creates one - */ - struct nhi_plat_data { - int (*power_on)(struct nhi_plat *np); -+ bool no_firmware_tunnels; - }; - - /** -@@ -140,8 +146,57 @@ static int nhi_nvda8100_power_on(struct nhi_plat *np) - - static const struct nhi_plat_data nhi_nvda8100_data = { - .power_on = nhi_nvda8100_power_on, -+ .no_firmware_tunnels = true, - }; - -+/* -+ * The PCIe ports this host interface tunnels through point back at it with -+ * "usb4-host-interface". DMA from what is plugged in is contained when every -+ * such Root Port is external facing and behind an IOMMU: the devices below -+ * are then untrusted, and the IOMMU core translates the port's group, which -+ * they join when the port has no ACS. -+ * -+ * The PCI glue also wants IOMMU_CAP_PRE_BOOT_PROTECTION, which no Arm SMMU -+ * reports. It covers devices the firmware tunneled before the OS set up the -+ * IOMMU, which cannot exist when the firmware has no connection manager. -+ */ -+static void nhi_plat_check_iommu(struct nhi_plat *np) -+{ -+ struct tb_nhi *nhi = &np->nhi; -+ struct pci_dev *pdev = NULL; -+ struct fwnode_handle *fwnode; -+ bool found = false, port_ok = true; -+ -+ if (!np->data->no_firmware_tunnels) -+ return; -+ -+ for_each_pci_dev(pdev) { -+ if (!pci_is_pcie(pdev) || -+ pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) -+ continue; -+ -+ fwnode = fwnode_find_reference(dev_fwnode(&pdev->dev), -+ "usb4-host-interface", 0); -+ if (IS_ERR(fwnode)) -+ continue; -+ -+ if (fwnode == dev_fwnode(nhi->dev)) { -+ found = true; -+ if (!pdev->external_facing || -+ !device_iommu_mapped(&pdev->dev)) { -+ dev_dbg(nhi->dev, "%s is not protected\n", -+ pci_name(pdev)); -+ port_ok = false; -+ } -+ } -+ fwnode_handle_put(fwnode); -+ } -+ -+ nhi->iommu_dma_protection = found && port_ok; -+ dev_dbg(nhi->dev, "IOMMU DMA protection is %s\n", -+ str_enabled_disabled(nhi->iommu_dma_protection)); -+} -+ - static int nhi_plat_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -185,6 +240,8 @@ static int nhi_plat_probe(struct platform_device *pdev) - return dev_err_probe(dev, -ENODEV, - "unexpected host interface capabilities %#x\n", caps); - -+ nhi_plat_check_iommu(np); -+ - pm_runtime_set_active(dev); - pm_runtime_get_noresume(dev); - ret = devm_pm_runtime_enable(dev); --- -2.56.0 - diff --git a/kernel/1090-sspm_ci-distinguish-not-submitted-from-completion-unknown.patch b/kernel/1090-sspm_ci-distinguish-not-submitted-from-completion-unknown.patch deleted file mode 100644 index f439f1a..0000000 --- a/kernel/1090-sspm_ci-distinguish-not-submitted-from-completion-unknown.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 88ca385f074359694bc7c755085a5f12cb8cf5b6 Mon Sep 17 00:00:00 2001 -From: David Cemin -Date: Mon, 28 Sep 2026 10:22:06 -0700 -Subject: [PATCH 1/6] NVIDIA: SAUCE: soc: mediatek: sspm_ci: distinguish "not - submitted" from "completion unknown" - -BugLink: https://bugs.launchpad.net/bugs/2167887 - -sspm_ci_set() returned -ETIMEDOUT for two different situations: the -mailbox never became free before the command was written, and the -command was written and the doorbell rung but no acknowledgment -arrived. Clients that drive device power states through this interface -cannot tell them apart, yet the right reaction differs: in the first -case nothing was sent and the caller may keep its current state or -retry; in the second the firmware may still complete the request and -the caller has to treat the outcome as ambiguous. - -Return -EBUSY when the mailbox stays busy and nothing was submitted, -keep -ETIMEDOUT for the post-doorbell acknowledgment timeout (whose late -acknowledgment is drained before the next command), and document the -contract on the function and in the header. - -Signed-off-by: David Cemin -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg ---- - drivers/soc/mediatek/sspm_ci/sspm_ci.c | 32 +++++++++++++++++++++++--- - drivers/soc/mediatek/sspm_ci/sspm_ci.h | 5 ++++ - 2 files changed, 34 insertions(+), 3 deletions(-) - -diff --git a/drivers/soc/mediatek/sspm_ci/sspm_ci.c b/drivers/soc/mediatek/sspm_ci/sspm_ci.c -index 7aa947b..b1f4e81 100644 ---- a/drivers/soc/mediatek/sspm_ci/sspm_ci.c -+++ b/drivers/soc/mediatek/sspm_ci/sspm_ci.c -@@ -212,6 +212,25 @@ static uint32_t pack_message_header(u8 message_id, u8 message_type, u8 protocol_ - SCMI_MESSAGE_HEADER_TOKEN_MASK)); - } - -+/** -+ * sspm_ci_set() - send one TINYSYS SET command to the SSPM and wait for its ack -+ * @feature_id: firmware feature the command addresses -+ * @p1: first payload word (typically the device id) -+ * @p2: second payload word (typically the composite action word) -+ * @p3: third payload word -+ * @p4: fourth payload word -+ * @p5: fifth payload word -+ * -+ * Return: -+ * * 0 - the firmware acknowledged the command. -+ * * -ENODEV - the mailbox is not mapped (no SSPM on this platform). -+ * * -EBUSY - the mailbox never became free, the command was NOT written and -+ * nothing was sent; the caller's power state is unchanged and it may retry -+ * or keep its current state. -+ * * -ETIMEDOUT - the command WAS written and the doorbell rung, but no ack -+ * arrived in time; the firmware may still complete it, so the outcome is -+ * unknown. A late ack is drained before the next command. -+ */ - int sspm_ci_set(u32 feature_id, - u32 p1, u32 p2, u32 p3, u32 p4, u32 p5) - { -@@ -259,8 +278,14 @@ int sspm_ci_set(u32 feature_id, - count++; - if (count > SSPM_CI_MAX_POLL_COUNT) { - mutex_unlock(&_hw_rsc); -- dev_err(__dev, "scmi timeout\n"); -- return -ETIMEDOUT; -+ /* -+ * Nothing was written or sent: distinct from the ack -+ * timeout below so callers can tell "not submitted" -+ * (state unchanged, safe to retry) from "completion -+ * unknown". -+ */ -+ dev_err(__dev, "scmi mailbox busy, command not submitted\n"); -+ return -EBUSY; - } - mdelay(1); - } -@@ -295,7 +320,8 @@ int sspm_ci_set(u32 feature_id, - WRITE_ONCE(_inflight_hdr, 0); - _drain_needed = true; - mutex_unlock(&_hw_rsc); -- dev_err(__dev, "scmi timeout (hdr %#x)\n", message_header); -+ dev_err(__dev, "scmi ack timeout (hdr %#x), completion unknown\n", -+ message_header); - return -ETIMEDOUT; - } - mdelay(1); -diff --git a/drivers/soc/mediatek/sspm_ci/sspm_ci.h b/drivers/soc/mediatek/sspm_ci/sspm_ci.h -index 9df540f..7b040eb 100644 ---- a/drivers/soc/mediatek/sspm_ci/sspm_ci.h -+++ b/drivers/soc/mediatek/sspm_ci/sspm_ci.h -@@ -8,6 +8,11 @@ - #ifndef _SSPM_CI_H_ - #define _SSPM_CI_H_ - -+/* -+ * Returns 0 on ack, -ENODEV without a mailbox, -EBUSY if the command could not -+ * be submitted (nothing sent, caller state unchanged), -ETIMEDOUT if it was -+ * sent but not acknowledged in time (completion unknown). -+ */ - int sspm_ci_set(u32 feature_id, - u32 p1, u32 p2, u32 p3, u32 p4, u32 p5); - #endif /* _SSPM_CI_H_ */ --- -2.56.0 - diff --git a/kernel/1091-PCI-harden-MediaTek-Power-Wrap-system-sleep.patch b/kernel/1091-PCI-harden-MediaTek-Power-Wrap-system-sleep.patch deleted file mode 100644 index 28616ab..0000000 --- a/kernel/1091-PCI-harden-MediaTek-Power-Wrap-system-sleep.patch +++ /dev/null @@ -1,723 +0,0 @@ -From 464c44cc8974c2b868938f6266cfb5e3c1c587ec Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Sat, 26 Sep 2026 10:39:20 -0700 -Subject: [PATCH 2/6] NVIDIA: SAUCE: PCI: harden MediaTek Power Wrap system - sleep - -BugLink: https://bugs.launchpad.net/bugs/2167887 - -MediaTek Power Wrap removes configuration and MMIO access for a complete -PCI host segment. Restrict that coordination to system sleep, where PCI -devices and native port services can be quiesced as a unit. Runtime host -gating cannot safely contain a failed D0 restore while drivers, BAR users, -hotplug, and configuration-space interfaces remain active. - -Track all Root Ports belonging to a host and issue the D3 request only -after every direct root-bus function is a managed Root Port in D3cold. Veto -host gating for wake paths, unsafe hotplug configurations, or any untracked -function. Serialize final-port aggregation across hosts and revalidate the -complete hierarchy while holding the PCI topology locks. - -Run PCIe port-service suspend callbacks for managed ports. Quiesce pending -PME work and prevent the shared PME IRQ from touching configuration space -after its no-IRQ state is set. Restore the host to D0 before the first PCI -resume access. If a D3 timeout leaves host state ambiguous, or D0 cannot be -confirmed, stop execution instead of returning to PCI with potentially -inaccessible configuration space and BARs. - -This folds the PCI fixes identified during NV-Kernels review. - -Co-developed-by: Jieyy Yang -Signed-off-by: Jieyy Yang -Co-developed-by: Housong Zhang -Signed-off-by: Housong Zhang -Signed-off-by: Bharat Dintakurti -Signed-off-by: Abhishek Sahu -Acked-by: Carol L Soto -Acked-by: Jamie Nguyen -Acked-by: Nirmoy Das -Signed-off-by: Brad Figg -[rh: backported to 7.2.5 on top of our power_wrap USB4 patches; mtk-pwrap.h context] ---- - drivers/pci/Makefile | 1 + - drivers/pci/hotplug/pciehp_core.c | 33 ++ - drivers/pci/pci-driver.c | 5 + - drivers/pci/pci-mtk-pwrap.c | 444 +++++++++++++++++++ - drivers/pci/pci.h | 25 ++ - drivers/pci/pcie/pme.c | 6 + - drivers/pci/pcie/portdrv.c | 10 +- - drivers/soc/mediatek/power_wrap/power_wrap.c | 8 + - include/linux/soc/mediatek/mtk-pwrap.h | 6 + - 9 files changed, 536 insertions(+), 2 deletions(-) - create mode 100644 drivers/pci/pci-mtk-pwrap.c - -diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile -index 41ebc3b..c128af9 100644 ---- a/drivers/pci/Makefile -+++ b/drivers/pci/Makefile -@@ -12,6 +12,7 @@ obj-$(CONFIG_PCI) += pcie/ - obj-$(CONFIG_PCI) += pwrctrl/ - - ifdef CONFIG_PCI -+obj-$(CONFIG_MTK_POWER_WRAP) += pci-mtk-pwrap.o - obj-$(CONFIG_PROC_FS) += proc.o - obj-$(CONFIG_SYSFS) += pci-sysfs.o slot.o - obj-$(CONFIG_ACPI) += pci-acpi.o -diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c -index 2cafd3b..57a0126 100644 ---- a/drivers/pci/hotplug/pciehp_core.c -+++ b/drivers/pci/hotplug/pciehp_core.c -@@ -350,6 +350,39 @@ static int pciehp_runtime_resume(struct pcie_device *dev) - } - #endif /* PM */ - -+/* -+ * A caller which removes config-space access for the complete host may only -+ * do so after pciehp's system-suspend callback and the PM core have quiesced -+ * the IRQ. A polling controller or Attention Button delayed work can still -+ * access the port independently, so those configurations are not safe. -+ * Use the controller's cached state because the port may already be D3cold. -+ */ -+bool pciehp_is_safe_for_poweroff(struct pci_dev *pdev) -+{ -+ struct pci_host_bridge *host; -+ struct pcie_device *pcie; -+ struct controller *ctrl; -+ struct device *dev; -+ -+ if (!pdev->is_hotplug_bridge) -+ return true; -+ if (!pdev->is_pciehp) -+ return false; -+ -+ host = pci_find_host_bridge(pdev->bus); -+ if (!host || (!pcie_ports_native && !host->native_pme)) -+ return false; -+ -+ dev = pcie_port_find_device(pdev, PCIE_PORT_SERVICE_HP); -+ if (!dev) -+ return false; -+ -+ pcie = to_pcie_device(dev); -+ ctrl = get_service_data(pcie); -+ -+ return ctrl && !ctrl->poll_thread && !ATTN_BUTTN(ctrl); -+} -+ - static struct pcie_port_service_driver hpdriver_portdrv = { - .name = "pciehp", - .port_type = PCIE_ANY_PORT, -diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index f36778e..7634908 100644 ---- a/drivers/pci/pci-driver.c -+++ b/drivers/pci/pci-driver.c -@@ -973,6 +973,8 @@ Fixup: - if (device_can_wakeup(dev) && !device_may_wakeup(dev)) - dev->power.may_skip_resume = false; - -+ /* Gate only after every PCI configuration-space access is complete. */ -+ mtk_pci_pwrap_suspend_noirq(pci_dev); - return 0; - } - -@@ -983,6 +985,9 @@ static int pci_pm_resume_noirq(struct device *dev) - pci_power_t prev_state = pci_dev->current_state; - bool skip_bus_pm = pci_dev->skip_bus_pm; - -+ /* Restore host config and MMIO access before the first PCI access. */ -+ mtk_pci_pwrap_resume_noirq(pci_dev); -+ - if (dev_pm_skip_resume(dev)) - return 0; - -diff --git a/drivers/pci/pci-mtk-pwrap.c b/drivers/pci/pci-mtk-pwrap.c -new file mode 100644 -index 0000000..3496a20 ---- /dev/null -+++ b/drivers/pci/pci-mtk-pwrap.c -@@ -0,0 +1,444 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * MediaTek Power Wrap coordination for PCIe system suspend. -+ * -+ * Copyright (c) 2026 MediaTek Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pci.h" -+ -+struct mtk_pci_pwrap_ctrl { -+ void *dev_ctrl; -+ char *acpi_path; -+ struct pci_bus *root_bus; -+ unsigned int port_count; -+ unsigned int ready_count; -+ enum mtk_pwrap_dev_state dstate; -+ struct list_head list; -+}; -+ -+struct mtk_pci_pwrap_port { -+ struct pci_dev *pdev; -+ struct mtk_pci_pwrap_ctrl *ctrl; -+ struct list_head list; -+ bool system_ready; -+}; -+ -+static DEFINE_MUTEX(mtk_pci_pwrap_lock); -+static DEFINE_MUTEX(mtk_pci_pwrap_gate_lock); -+static LIST_HEAD(mtk_pci_pwrap_ctrls); -+static LIST_HEAD(mtk_pci_pwrap_ports); -+ -+static bool mtk_pci_pwrap_is_root_port(struct pci_dev *pdev) -+{ -+ return pci_is_pcie(pdev) && -+ pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT; -+} -+ -+static bool mtk_pci_pwrap_port_can_gate(struct pci_dev *pdev) -+{ -+ /* -+ * PCI config space remains accessible through D3hot. Only extend an -+ * already config-inaccessible D3cold hierarchy to whole-host gating. -+ */ -+ return !pdev->skip_bus_pm && pdev->current_state == PCI_D3cold && -+ !device_may_wakeup(&pdev->dev) && -+ !device_wakeup_path(&pdev->dev); -+} -+ -+/* Called with pci_bus_sem held for reading. */ -+static bool mtk_pci_pwrap_bus_can_gate(struct pci_bus *bus) -+{ -+ struct pci_dev *pdev; -+ -+ list_for_each_entry(pdev, &bus->devices, bus_list) { -+ if (device_may_wakeup(&pdev->dev) || -+ device_wakeup_path(&pdev->dev) || -+ !pciehp_is_safe_for_poweroff(pdev)) -+ return false; -+ -+ if (pdev->subordinate && -+ !mtk_pci_pwrap_bus_can_gate(pdev->subordinate)) -+ return false; -+ } -+ -+ return true; -+} -+ -+static char *mtk_pci_pwrap_get_host_path(struct pci_dev *pdev, -+ struct pci_bus **root_bus) -+{ -+ struct pci_host_bridge *host; -+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_handle handle; -+ acpi_status status; -+ -+ host = pci_find_host_bridge(pdev->bus); -+ if (!host || !host->bus) -+ return ERR_PTR(-ENODEV); -+ -+ /* -+ * A controller driver may access its registers outside the child PCI -+ * callbacks. Only firmware-created root buses have no such parent and -+ * can be safely bracketed here. -+ */ -+ if (host->dev.parent) -+ return ERR_PTR(-EOPNOTSUPP); -+ -+ handle = ACPI_HANDLE(&host->dev); -+ if (!handle) -+ return ERR_PTR(-ENODEV); -+ -+ status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buf); -+ if (ACPI_FAILURE(status)) -+ return ERR_PTR(-ENODEV); -+ -+ *root_bus = host->bus; -+ return buf.pointer; -+} -+ -+static struct mtk_pci_pwrap_port * -+mtk_pci_pwrap_find_port_locked(struct pci_dev *pdev) -+{ -+ struct mtk_pci_pwrap_port *port; -+ -+ list_for_each_entry(port, &mtk_pci_pwrap_ports, list) { -+ if (port->pdev == pdev) -+ return port; -+ } -+ -+ return NULL; -+} -+ -+static struct mtk_pci_pwrap_ctrl * -+mtk_pci_pwrap_find_ctrl_locked(const char *path) -+{ -+ struct mtk_pci_pwrap_ctrl *ctrl; -+ -+ list_for_each_entry(ctrl, &mtk_pci_pwrap_ctrls, list) { -+ if (!strcmp(ctrl->acpi_path, path)) -+ return ctrl; -+ } -+ -+ return NULL; -+} -+ -+static void mtk_pci_pwrap_clear_ready_locked(struct mtk_pci_pwrap_ctrl *ctrl) -+{ -+ struct mtk_pci_pwrap_port *port; -+ -+ list_for_each_entry(port, &mtk_pci_pwrap_ports, list) { -+ if (port->ctrl == ctrl) -+ port->system_ready = false; -+ } -+ ctrl->ready_count = 0; -+} -+ -+/* -+ * Power Wrap removes config and MMIO access for the complete host segment. -+ * Every function directly on the root bus must therefore be a tracked Root -+ * Port that has finished its PCI noirq suspend work. -+ */ -+static bool -+mtk_pci_pwrap_host_ready_locked(struct mtk_pci_pwrap_ctrl *ctrl) -+{ -+ struct mtk_pci_pwrap_port *port; -+ struct pci_dev *child; -+ unsigned int count = 0; -+ -+ list_for_each_entry(child, &ctrl->root_bus->devices, bus_list) { -+ port = mtk_pci_pwrap_find_port_locked(child); -+ if (!port || port->ctrl != ctrl || !port->system_ready || -+ !mtk_pci_pwrap_port_can_gate(child)) -+ return false; -+ count++; -+ } -+ -+ return count && count == ctrl->port_count && -+ ctrl->ready_count == ctrl->port_count && -+ mtk_pci_pwrap_bus_can_gate(ctrl->root_bus); -+} -+ -+static void mtk_pci_pwrap_free_ctrl_locked(struct mtk_pci_pwrap_ctrl *ctrl) -+{ -+ list_del(&ctrl->list); -+ ACPI_FREE(ctrl->acpi_path); -+ kfree(ctrl); -+} -+ -+static void mtk_pci_pwrap_put_ctrl_locked(struct mtk_pci_pwrap_ctrl *ctrl, -+ struct device *dev) -+{ -+ int ret; -+ -+ if (--ctrl->port_count) -+ return; -+ -+ ret = mtk_pwrap_dev_remove(ctrl->dev_ctrl); -+ if (ret) -+ dev_warn(dev, "pwrap remove failed: %d\n", ret); -+ -+ mtk_pci_pwrap_free_ctrl_locked(ctrl); -+} -+ -+static void mtk_pci_pwrap_release_port(void *data) -+{ -+ struct mtk_pci_pwrap_port *port = data; -+ struct mtk_pci_pwrap_ctrl *ctrl = port->ctrl; -+ -+ mutex_lock(&mtk_pci_pwrap_lock); -+ if (port->system_ready && ctrl->ready_count) -+ ctrl->ready_count--; -+ list_del(&port->list); -+ mtk_pci_pwrap_put_ctrl_locked(ctrl, &port->pdev->dev); -+ mutex_unlock(&mtk_pci_pwrap_lock); -+} -+ -+void mtk_pci_pwrap_init(struct pci_dev *pdev) -+{ -+ struct mtk_pci_pwrap_ctrl *ctrl; -+ struct mtk_pci_pwrap_port *port; -+ struct pci_bus *root_bus; -+ char *path; -+ int ret; -+ -+ if (!mtk_pci_pwrap_is_root_port(pdev)) -+ return; -+ -+ path = mtk_pci_pwrap_get_host_path(pdev, &root_bus); -+ if (IS_ERR(path)) { -+ dev_dbg(&pdev->dev, "unsupported pwrap host: %ld\n", -+ PTR_ERR(path)); -+ return; -+ } -+ -+ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); -+ if (!port) -+ goto out_free_path; -+ -+ mutex_lock(&mtk_pci_pwrap_lock); -+ if (mtk_pci_pwrap_find_port_locked(pdev)) -+ goto out_unlock; -+ -+ ctrl = mtk_pci_pwrap_find_ctrl_locked(path); -+ if (ctrl && ctrl->root_bus != root_bus) { -+ dev_warn(&pdev->dev, "pwrap path %s belongs to another host\n", -+ path); -+ goto out_unlock; -+ } -+ -+ if (!ctrl) { -+ ctrl = kzalloc_obj(*ctrl); -+ if (!ctrl) -+ goto out_unlock; -+ -+ ctrl->acpi_path = path; -+ path = NULL; -+ ctrl->root_bus = root_bus; -+ ctrl->dev_ctrl = mtk_pwrap_dev_probe(ctrl->acpi_path); -+ if (!mtk_pwrap_dev_supports_state_control(ctrl->dev_ctrl)) { -+ dev_dbg(&pdev->dev, "no pwrap state control for %s\n", -+ ctrl->acpi_path); -+ ACPI_FREE(ctrl->acpi_path); -+ kfree(ctrl); -+ goto out_unlock; -+ } -+ -+ ctrl->dstate = DEV_STA_D0; -+ list_add(&ctrl->list, &mtk_pci_pwrap_ctrls); -+ } -+ -+ port->pdev = pdev; -+ port->ctrl = ctrl; -+ list_add(&port->list, &mtk_pci_pwrap_ports); -+ ctrl->port_count++; -+ -+ ret = devm_add_action(&pdev->dev, mtk_pci_pwrap_release_port, port); -+ if (ret) { -+ list_del(&port->list); -+ mtk_pci_pwrap_put_ctrl_locked(ctrl, &pdev->dev); -+ dev_warn(&pdev->dev, -+ "pwrap cleanup registration failed: %d\n", ret); -+ } -+ -+out_unlock: -+ mutex_unlock(&mtk_pci_pwrap_lock); -+out_free_path: -+ ACPI_FREE(path); -+} -+ -+bool mtk_pci_pwrap_is_managed(struct pci_dev *pdev) -+{ -+ bool managed; -+ -+ if (!mtk_pci_pwrap_is_root_port(pdev)) -+ return false; -+ -+ mutex_lock(&mtk_pci_pwrap_lock); -+ managed = !!mtk_pci_pwrap_find_port_locked(pdev); -+ mutex_unlock(&mtk_pci_pwrap_lock); -+ -+ return managed; -+} -+ -+static void __noreturn mtk_pci_pwrap_fail_stop(void) -+{ -+ /* -+ * Do not return to PCI when host accessibility is unknown. Avoid the -+ * panic and restart paths because their dump, notifier, and reset -+ * handlers may touch a device below the host. MTK_POWER_WRAP is arm64 -+ * only, where machine_halt() disables local IRQs and stops other CPUs. -+ */ -+ machine_halt(); -+ for (;;) -+ cpu_relax(); -+} -+ -+void mtk_pci_pwrap_suspend_noirq(struct pci_dev *pdev) -+{ -+ struct mtk_pci_pwrap_ctrl *ctrl; -+ struct mtk_pci_pwrap_port *port; -+ bool fatal = false; -+ int ret; -+ -+ if (!mtk_pci_pwrap_is_root_port(pdev)) -+ return; -+ -+ if (!mtk_pci_pwrap_port_can_gate(pdev)) -+ return; -+ -+ mutex_lock(&mtk_pci_pwrap_lock); -+ port = mtk_pci_pwrap_find_port_locked(pdev); -+ if (!port || port->system_ready) -+ goto out_ready; -+ -+ ctrl = port->ctrl; -+ if (ctrl->dstate != DEV_STA_D0) -+ goto out_ready; -+ -+ port->system_ready = true; -+ ctrl->ready_count++; -+ if (ctrl->ready_count != ctrl->port_count) -+ goto out_ready; -+ mutex_unlock(&mtk_pci_pwrap_lock); -+ -+ /* -+ * PCI devices suspend asynchronously. Only the final ready port may -+ * compete for the topology locks. Serialize final ports from different -+ * hosts so one Power Wrap operation cannot make another host miss its -+ * only gating opportunity on the global rescan lock. -+ * -+ * Contention with a real topology operation means the host is not stable -+ * enough to remove ECAM. Clear the ready set and leave it in D0. -+ */ -+ mutex_lock(&mtk_pci_pwrap_gate_lock); -+ if (!mutex_trylock(&pci_rescan_remove_lock)) -+ goto clear_ready_gate; -+ if (!down_read_trylock(&pci_bus_sem)) -+ goto clear_ready_rescan; -+ -+ mutex_lock(&mtk_pci_pwrap_lock); -+ port = mtk_pci_pwrap_find_port_locked(pdev); -+ if (!port || !port->system_ready) -+ goto out_unlock; -+ -+ ctrl = port->ctrl; -+ if (ctrl->dstate != DEV_STA_D0) { -+ mtk_pci_pwrap_clear_ready_locked(ctrl); -+ goto out_unlock; -+ } -+ -+ if (!mtk_pci_pwrap_host_ready_locked(ctrl)) { -+ mtk_pci_pwrap_clear_ready_locked(ctrl); -+ goto out_unlock; -+ } -+ -+ ret = mtk_pwrap_dev_suspend(ctrl->dev_ctrl, true); -+ if (ret == -ETIMEDOUT) { -+ /* -+ * The command may have completed after the transport timed out, so -+ * neither PM unwind nor a later uncorrelated D0 acknowledgment can -+ * prove the host accessible. Fail-stop after dropping PCI topology -+ * locks, without logging through a possibly inaccessible device. -+ */ -+ ctrl->dstate = DEV_STA_UNKNOWN; -+ fatal = true; -+ } else if (ret) { -+ dev_warn(&pdev->dev, "pwrap D3 failed: %d\n", ret); -+ /* The host stayed in D0; keep PM unwind callbacks balanced. */ -+ mtk_pci_pwrap_clear_ready_locked(ctrl); -+ } else { -+ ctrl->dstate = DEV_STA_D3; -+ } -+ -+out_unlock: -+ mutex_unlock(&mtk_pci_pwrap_lock); -+ up_read(&pci_bus_sem); -+ mutex_unlock(&pci_rescan_remove_lock); -+ if (fatal) -+ mtk_pci_pwrap_fail_stop(); -+ mutex_unlock(&mtk_pci_pwrap_gate_lock); -+ return; -+ -+clear_ready_rescan: -+ mutex_unlock(&pci_rescan_remove_lock); -+clear_ready_gate: -+ mutex_unlock(&mtk_pci_pwrap_gate_lock); -+ mutex_lock(&mtk_pci_pwrap_lock); -+ port = mtk_pci_pwrap_find_port_locked(pdev); -+ if (port && port->system_ready) -+ mtk_pci_pwrap_clear_ready_locked(port->ctrl); -+out_ready: -+ mutex_unlock(&mtk_pci_pwrap_lock); -+} -+ -+void mtk_pci_pwrap_resume_noirq(struct pci_dev *pdev) -+{ -+ struct mtk_pci_pwrap_ctrl *ctrl; -+ struct mtk_pci_pwrap_port *port; -+ int ret = 0; -+ -+ if (!mtk_pci_pwrap_is_root_port(pdev)) -+ return; -+ -+ mutex_lock(&mtk_pci_pwrap_lock); -+ port = mtk_pci_pwrap_find_port_locked(pdev); -+ if (!port) -+ goto out_unlock; -+ -+ ctrl = port->ctrl; -+ if (ctrl->dstate == DEV_STA_UNKNOWN) { -+ ret = -EIO; -+ goto out_unlock; -+ } -+ -+ if (ctrl->dstate != DEV_STA_D0) { -+ ret = mtk_pwrap_dev_resume(ctrl->dev_ctrl, true); -+ if (ret) { -+ /* Prevent an asynchronous sibling from retrying D0. */ -+ ctrl->dstate = DEV_STA_UNKNOWN; -+ goto out_unlock; -+ } -+ ctrl->dstate = DEV_STA_D0; -+ } -+ -+ mtk_pci_pwrap_clear_ready_locked(ctrl); -+ -+out_unlock: -+ mutex_unlock(&mtk_pci_pwrap_lock); -+ if (ret) -+ mtk_pci_pwrap_fail_stop(); -+} -diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h -index 4469e1a..9d8b1f1 100644 ---- a/drivers/pci/pci.h -+++ b/drivers/pci/pci.h -@@ -269,6 +269,31 @@ int pci_finish_runtime_suspend(struct pci_dev *dev); - void pcie_clear_device_status(struct pci_dev *dev); - void pcie_clear_root_pme_status(struct pci_dev *dev); - bool pci_check_pme_status(struct pci_dev *dev); -+#ifdef CONFIG_HOTPLUG_PCI_PCIE -+bool pciehp_is_safe_for_poweroff(struct pci_dev *dev); -+#else -+static inline bool pciehp_is_safe_for_poweroff(struct pci_dev *dev) -+{ -+ return !dev->is_hotplug_bridge; -+} -+#endif -+#ifdef CONFIG_MTK_POWER_WRAP -+void mtk_pci_pwrap_init(struct pci_dev *dev); -+bool mtk_pci_pwrap_is_managed(struct pci_dev *dev); -+void mtk_pci_pwrap_suspend_noirq(struct pci_dev *dev); -+void mtk_pci_pwrap_resume_noirq(struct pci_dev *dev); -+#else -+static inline void mtk_pci_pwrap_init(struct pci_dev *dev) { } -+ -+static inline bool mtk_pci_pwrap_is_managed(struct pci_dev *dev) -+{ -+ return false; -+} -+ -+static inline void mtk_pci_pwrap_suspend_noirq(struct pci_dev *dev) { } -+ -+static inline void mtk_pci_pwrap_resume_noirq(struct pci_dev *dev) { } -+#endif - void pci_pme_wakeup_bus(struct pci_bus *bus); - void pci_pme_restore(struct pci_dev *dev); - bool pci_dev_need_resume(struct pci_dev *dev); -diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c -index 4996cc4..11b10f8 100644 ---- a/drivers/pci/pcie/pme.c -+++ b/drivers/pci/pcie/pme.c -@@ -274,6 +274,11 @@ static irqreturn_t pcie_pme_irq(int irq, void *context) - data = get_service_data((struct pcie_device *)context); - - spin_lock_irqsave(&data->lock, flags); -+ if (data->noirq) { -+ spin_unlock_irqrestore(&data->lock, flags); -+ return IRQ_NONE; -+ } -+ - pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta); - - if (PCI_POSSIBLE_ERROR(rtsta) || !(rtsta & PCI_EXP_RTSTA_PME)) { -@@ -412,6 +417,7 @@ static int pcie_pme_suspend(struct pcie_device *srv) - pcie_pme_disable_interrupt(port, data); - - synchronize_irq(srv->irq); -+ cancel_work_sync(&data->work); - - return 0; - } -diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c -index 2d6aa48..fe67eaa 100644 ---- a/drivers/pci/pcie/portdrv.c -+++ b/drivers/pci/pcie/portdrv.c -@@ -338,6 +338,8 @@ static int pcie_port_device_register(struct pci_dev *dev) - if (status) - return status; - -+ mtk_pci_pwrap_init(dev); -+ - /* Get and check PCI Express port services */ - capabilities = get_port_device_capability(dev); - if (!capabilities) -@@ -686,6 +688,7 @@ static int pcie_portdrv_probe(struct pci_dev *dev, - const struct pci_device_id *id) - { - int type = pci_pcie_type(dev); -+ u32 pm_flags = DPM_FLAG_NO_DIRECT_COMPLETE; - int status; - - if (!pci_is_pcie(dev) || -@@ -704,8 +707,11 @@ static int pcie_portdrv_probe(struct pci_dev *dev, - - pci_save_state(dev); - -- dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE | -- DPM_FLAG_SMART_SUSPEND); -+ /* Managed ports must run their PCIe service suspend callbacks. */ -+ if (!mtk_pci_pwrap_is_managed(dev)) -+ pm_flags |= DPM_FLAG_SMART_SUSPEND; -+ -+ dev_pm_set_driver_flags(&dev->dev, pm_flags); - - if (pci_bridge_d3_possible(dev)) { - /* -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index 33445cd..7fce9d3 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -441,6 +441,14 @@ void *mtk_pwrap_dev_probe(const char *acpi_path) - } - EXPORT_SYMBOL_GPL(mtk_pwrap_dev_probe); - -+bool mtk_pwrap_dev_supports_state_control(void *dev_ctrl) -+{ -+ struct pwrap_dev_config *cfg = dev_ctrl; -+ -+ return cfg && cfg->control_type == CTRL_BY_SCMI; -+} -+EXPORT_SYMBOL_GPL(mtk_pwrap_dev_supports_state_control); -+ - static int pwrap_config_resource(struct platform_device *pdev, kernel_ulong_t driver_data) - { - enum mtk_pwrap_type type; -diff --git a/include/linux/soc/mediatek/mtk-pwrap.h b/include/linux/soc/mediatek/mtk-pwrap.h -index a655c71..bb29c41 100644 ---- a/include/linux/soc/mediatek/mtk-pwrap.h -+++ b/include/linux/soc/mediatek/mtk-pwrap.h -@@ -77,6 +77,7 @@ int mtk_pwrap_com_idle(void *dev_ctrl, u8 com_idx); - int mtk_pwrap_com_active(void *dev_ctrl, u8 com_idx); - void *mtk_pwrap_dev_probe(const char *acpi_path); - bool mtk_pwrap_usb4_released(void); -+bool mtk_pwrap_dev_supports_state_control(void *dev_ctrl); - #else - static inline int mtk_send_power_control_req(struct _power_cntrl_request *pwrctlreq) - { -@@ -122,6 +123,11 @@ static inline bool mtk_pwrap_usb4_released(void) - { - return false; - } -+ -+static inline bool mtk_pwrap_dev_supports_state_control(void *dev_ctrl) -+{ -+ return false; -+} - #endif /* CONFIG_MTK_POWER_WRAP */ - - #endif --- -2.56.0 - diff --git a/kernel/1092-usb-xhci-mtk-v2-add-ACPI-power-management-support.patch b/kernel/1092-usb-xhci-mtk-v2-add-ACPI-power-management-support.patch deleted file mode 100644 index 8985e06..0000000 --- a/kernel/1092-usb-xhci-mtk-v2-add-ACPI-power-management-support.patch +++ /dev/null @@ -1,2123 +0,0 @@ -From d054faf0712ea2dfeb26952839d3751230cbb26a Mon Sep 17 00:00:00 2001 -From: Bharat Dintakurti -Date: Wed, 12 Aug 2026 09:31:24 -0700 -Subject: [PATCH 3/6] NVIDIA: SAUCE: usb: xhci-mtk-v2: add ACPI power - management support - -BugLink: https://bugs.launchpad.net/bugs/2167884 - -Add the MediaTek xHCI platform glue for ACPI-described controllers. -Parse the IPPC, MAC and PHY resources, configure the USB PHYs, and -coordinate controller D0/D3 transitions through Power Wrap. Add support -for the platform's dedicated wake interrupt. - -Integrate the platform sequence with probe, remove and system suspend. -Propagate IPPC and Power Wrap failures, unwind locally prepared hardware -on probe and suspend failures, and avoid MMIO recovery until firmware has -confirmed D0. Follow the platform power-on ordering by disabling IPPC bus -and PHY clock gating before releasing host power-down during initialization -and low-power exit. - -Keep runtime PM disabled until Power Wrap can report an authoritative -state after a failed transition, and reject MediaTek runtime PM callbacks. -Keep confirmed D0 after system-resume errors. If platform D0 exit fails, -mark both HCDs inaccessible; if controller restore or failed-suspend -rollback fails after D0, keep accessibility accurate while marking the host -dead before later IRQ, hub, unlink, remove, or shutdown paths can access -registers. - -Quiesce Debug Capability work and tear down its software state without -MMIO when hardware is inaccessible. Suppress stale clear-TT doorbells -during failed-host teardown. - -Validate the required PHY type before acquiring controller resources, -return standard timeout errors, and avoid hardware teardown when D0 is not -confirmed. - -Co-developed-by: Chunfeng Yun -Signed-off-by: Chunfeng Yun -Signed-off-by: Bharat Dintakurti -Acked-by: Emily Soto -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg -[rh: backported to 7.2.5; xhci_dbc_remove() keeps 7.2's enable_mutex around both stop paths] ---- - drivers/usb/host/Kconfig | 11 + - drivers/usb/host/Makefile | 5 + - drivers/usb/host/xhci-dbgcap.c | 62 +- - drivers/usb/host/xhci-dbgcap.h | 12 +- - drivers/usb/host/xhci-dbgtty.c | 4 +- - drivers/usb/host/xhci-ext-caps.h | 4 + - drivers/usb/host/xhci-hub.c | 11 + - drivers/usb/host/xhci-mem.c | 2 +- - drivers/usb/host/xhci-mtk-v2.c | 1019 ++++++++++++++++++++++++++++++ - drivers/usb/host/xhci-mtk-v2.h | 85 +++ - drivers/usb/host/xhci-plat.c | 207 +++++- - drivers/usb/host/xhci-plat.h | 13 + - drivers/usb/host/xhci-ring.c | 37 +- - drivers/usb/host/xhci.c | 78 ++- - 14 files changed, 1490 insertions(+), 60 deletions(-) - create mode 100644 drivers/usb/host/xhci-mtk-v2.c - create mode 100644 drivers/usb/host/xhci-mtk-v2.h - -diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index b3b1ec6..7a80311 100644 ---- a/drivers/usb/host/Kconfig -+++ b/drivers/usb/host/Kconfig -@@ -83,6 +83,17 @@ config USB_XHCI_MTK - found in MediaTek SoCs. - If unsure, say N. - -+config USB_XHCI_MTK_V2 -+ tristate "xHCI support for MediaTek MT8901 SoC" -+ depends on ACPI -+ depends on MTK_POWER_WRAP -+ depends on ARM64 || COMPILE_TEST -+ select USB_XHCI_PLATFORM -+ default y -+ help -+ Say 'Y' to enable the support for the xHCI host controller -+ for the MT8901 SoC. -+ - config USB_XHCI_MVEBU - tristate "xHCI support for Marvell Armada 375/38x/37xx" - select USB_XHCI_PLATFORM -diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 174580c..27e2873 100644 ---- a/drivers/usb/host/Makefile -+++ b/drivers/usb/host/Makefile -@@ -22,6 +22,11 @@ endif - xhci-mtk-hcd-y := xhci-mtk.o xhci-mtk-sch.o - - xhci-plat-hcd-y := xhci-plat.o -+ -+ifneq ($(CONFIG_USB_XHCI_MTK_V2), ) -+ xhci-plat-hcd-y += xhci-mtk-v2.o -+endif -+ - ifneq ($(CONFIG_USB_XHCI_MVEBU), ) - xhci-plat-hcd-y += xhci-mvebu.o - endif -diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c -index 48ee6a4..b91584a 100644 ---- a/drivers/usb/host/xhci-dbgcap.c -+++ b/drivers/usb/host/xhci-dbgcap.c -@@ -773,6 +773,43 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc) - pm_runtime_put(dbc->dev); - } - -+/* -+ * Tear down DbC software state after the platform has made xHCI registers -+ * inaccessible. Mark the state disabled before draining asynchronous work so -+ * neither the worker nor a request completion can issue another MMIO access. -+ */ -+static void xhci_dbc_stop_no_hw(struct xhci_dbc *dbc) -+{ -+ enum dbc_state state; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dbc->lock, flags); -+ state = dbc->state; -+ dbc->state = DS_DISABLED; -+ spin_unlock_irqrestore(&dbc->lock, flags); -+ -+ /* Stop the worker and prevent request completions from requeueing it. */ -+ disable_delayed_work_sync(&dbc->event_work); -+ -+ if (state == DS_DISABLED) -+ return; -+ -+ if (state == DS_CONFIGURED) { -+ spin_lock_irqsave(&dbc->lock, flags); -+ xhci_dbc_flush_requests(dbc); -+ spin_unlock_irqrestore(&dbc->lock, flags); -+ -+ if (dbc->driver->disconnect) -+ dbc->driver->disconnect(dbc); -+ } -+ -+ xhci_dbc_mem_cleanup(dbc); -+ -+ /* DS_INITIALIZED is left behind only after a failed start already put. */ -+ if (state >= DS_ENABLED) -+ pm_runtime_put_noidle(dbc->dev); -+} -+ - static void - handle_ep_halt_changes(struct xhci_dbc *dbc, struct dbc_ep *dep, bool halted) - { -@@ -1554,17 +1591,25 @@ err: - } - - /* undo what xhci_alloc_dbc() did */ --void xhci_dbc_remove(struct xhci_dbc *dbc) -+void xhci_dbc_remove(struct xhci_dbc *dbc, bool hw_accessible) - { - if (!dbc) - return; -- /* stop hw, stop wq and call dbc->ops->stop() */ -- mutex_lock(&dbc->enable_mutex); -- xhci_dbc_stop(dbc); -- mutex_unlock(&dbc->enable_mutex); -- /* remove sysfs files */ -+ -+ /* Prevent a concurrent sysfs write from restarting DbC during removal. */ - sysfs_remove_groups(&dbc->dev->kobj, dbc_dev_groups); - -+ /* stop hw when possible, then stop work and call dbc->ops->stop() */ -+ mutex_lock(&dbc->enable_mutex); -+ if (hw_accessible) { -+ /* Removal is final; prevent callbacks from requeueing the worker. */ -+ disable_delayed_work_sync(&dbc->event_work); -+ xhci_dbc_stop(dbc); -+ } else { -+ xhci_dbc_stop_no_hw(dbc); -+ } -+ mutex_unlock(&dbc->enable_mutex); -+ - kfree(dbc); - } - -@@ -1593,18 +1638,19 @@ int xhci_create_dbc_dev(struct xhci_hcd *xhci) - return ret; - } - --void xhci_remove_dbc_dev(struct xhci_hcd *xhci) -+void xhci_remove_dbc_dev(struct xhci_hcd *xhci, bool hw_accessible) - { - unsigned long flags; - - if (!xhci->dbc) - return; - -- xhci_dbc_tty_remove(xhci->dbc); -+ xhci_dbc_tty_remove(xhci->dbc, hw_accessible); - spin_lock_irqsave(&xhci->lock, flags); - xhci->dbc = NULL; - spin_unlock_irqrestore(&xhci->lock, flags); - } -+EXPORT_SYMBOL_GPL(xhci_remove_dbc_dev); - - #ifdef CONFIG_PM - int xhci_dbc_suspend(struct xhci_hcd *xhci) -diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h -index 5b18efb..2f05066 100644 ---- a/drivers/usb/host/xhci-dbgcap.h -+++ b/drivers/usb/host/xhci-dbgcap.h -@@ -230,16 +230,17 @@ static inline struct dbc_ep *get_out_ep(struct xhci_dbc *dbc) - - #ifdef CONFIG_USB_XHCI_DBGCAP - int xhci_create_dbc_dev(struct xhci_hcd *xhci); --void xhci_remove_dbc_dev(struct xhci_hcd *xhci); -+void xhci_remove_dbc_dev(struct xhci_hcd *xhci, bool hw_accessible); - int xhci_dbc_init(void); - void xhci_dbc_exit(void); - int dbc_tty_init(void); - void dbc_tty_exit(void); --int xhci_dbc_tty_probe(struct device *dev, void __iomem *res, struct xhci_hcd *xhci); --void xhci_dbc_tty_remove(struct xhci_dbc *dbc); -+int xhci_dbc_tty_probe(struct device *dev, void __iomem *res, -+ struct xhci_hcd *xhci); -+void xhci_dbc_tty_remove(struct xhci_dbc *dbc, bool hw_accessible); - struct xhci_dbc *xhci_alloc_dbc(struct device *dev, void __iomem *res, - const struct dbc_driver *driver); --void xhci_dbc_remove(struct xhci_dbc *dbc); -+void xhci_dbc_remove(struct xhci_dbc *dbc, bool hw_accessible); - struct dbc_request *dbc_alloc_request(struct xhci_dbc *dbc, - unsigned int direction, - gfp_t flags); -@@ -255,7 +256,8 @@ static inline int xhci_create_dbc_dev(struct xhci_hcd *xhci) - return 0; - } - --static inline void xhci_remove_dbc_dev(struct xhci_hcd *xhci) -+static inline void xhci_remove_dbc_dev(struct xhci_hcd *xhci, -+ bool hw_accessible) - { - } - static inline int xhci_dbc_init(void) -diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c -index 7e44e62..db8d00b 100644 ---- a/drivers/usb/host/xhci-dbgtty.c -+++ b/drivers/usb/host/xhci-dbgtty.c -@@ -611,11 +611,11 @@ out2: - * undo what probe did, assume dbc is stopped already. - * we also assume tty_unregister_device() is called before this - */ --void xhci_dbc_tty_remove(struct xhci_dbc *dbc) -+void xhci_dbc_tty_remove(struct xhci_dbc *dbc, bool hw_accessible) - { - struct dbc_port *port = dbc_to_port(dbc); - -- xhci_dbc_remove(dbc); -+ xhci_dbc_remove(dbc, hw_accessible); - kfree(port); - } - -diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h -index 67ecf73..1c3d6df 100644 ---- a/drivers/usb/host/xhci-ext-caps.h -+++ b/drivers/usb/host/xhci-ext-caps.h -@@ -8,6 +8,9 @@ - * Some code borrowed from the Linux EHCI driver. - */ - -+#ifndef __XHCI_EXT_CAPS_H -+#define __XHCI_EXT_CAPS_H -+ - /* HC should halt within 16 ms, but use 32 ms as some hosts take longer */ - #define XHCI_MAX_HALT_USEC (32 * 1000) - /* HC not running - set to 1 when run/stop bit is cleared. */ -@@ -155,3 +158,4 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id) - - return 0; - } -+#endif /* __XHCI_EXT_CAPS_H */ -diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c -index c2c2b74..174d9b7 100644 ---- a/drivers/usb/host/xhci-hub.c -+++ b/drivers/usb/host/xhci-hub.c -@@ -1203,6 +1203,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - bus_state = &rhub->bus_state; - - spin_lock_irqsave(&xhci->lock, flags); -+ if (unlikely(!HCD_HW_ACCESSIBLE(hcd) || -+ xhci->xhc_state & XHCI_STATE_DYING)) { -+ spin_unlock_irqrestore(&xhci->lock, flags); -+ return -ESHUTDOWN; -+ } -+ - switch (typeReq) { - case GetHubStatus: - /* No power source, over-current reported per port */ -@@ -1646,6 +1652,11 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) - * a non-zero value even if there are no status changes. - */ - spin_lock_irqsave(&xhci->lock, flags); -+ if (unlikely(!HCD_HW_ACCESSIBLE(hcd) || -+ xhci->xhc_state & XHCI_STATE_DYING)) { -+ spin_unlock_irqrestore(&xhci->lock, flags); -+ return 0; -+ } - - status = bus_state->resuming_ports; - -diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c -index a5e7f36..fe2d3e2 100644 ---- a/drivers/usb/host/xhci-mem.c -+++ b/drivers/usb/host/xhci-mem.c -@@ -1834,7 +1834,7 @@ xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) - * low or high 32 bits of ERSTBA immediately causes the controller to - * dereference the partially cleared 64 bit address, causing IOMMU error. - */ -- if (ir->ir_set) { -+ if (ir->ir_set && HCD_HW_ACCESSIBLE(xhci_to_hcd(xhci))) { - tmp = readl(&ir->ir_set->erst_size); - tmp &= ~ERST_SIZE_MASK; - writel(tmp, &ir->ir_set->erst_size); -diff --git a/drivers/usb/host/xhci-mtk-v2.c b/drivers/usb/host/xhci-mtk-v2.c -new file mode 100644 -index 0000000..779e471 ---- /dev/null -+++ b/drivers/usb/host/xhci-mtk-v2.c -@@ -0,0 +1,1019 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ * -+ * Author: Chunfeng Yun -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "xhci.h" -+#include "xhci-plat.h" -+#include "xhci-mtk-v2.h" -+ -+/* IPPC (IP Port Control) registers */ -+#define IPPC_IP_PW_CTRL0 0x00 -+#define CTRL0_IP_SW_RST BIT(0) -+ -+#define IPPC_IP_PW_CTRL1 0x04 -+#define CTRL1_IP_HOST_PDN BIT(0) -+ -+#define IPPC_IP_PW_CTRL2 0x08 -+/* U3D_SSUSB_IP_PW_CTRL2 */ -+#define CTRL2_IP_DEV_PDN BIT(0) -+ -+#define IPPC_IP_PW_STS1 0x10 -+#define STS1_SYSPLL_STABLE BIT(0) -+#define STS1_REF_RST BIT(8) -+#define STS1_SYS125_RST BIT(10) -+#define STS1_XHCI_RST BIT(11) -+#define STS1_U3_MAC_RST BIT(16) -+#define U3_MAC3_CSR_PLL_STB (STS1_SYSPLL_STABLE | STS1_U3_MAC_RST) -+#define U3_MAC2_CSR_PLL_STB (STS1_SYSPLL_STABLE | STS1_SYS125_RST) -+#define STS1_IP_SLEEP BIT(30) -+ -+#define IPPC_IP_XHCI_CAP 0x24 -+#define CAP_U3_PORT_NUM(p) ((p) & 0xff) -+#define CAP_U2_PORT_NUM(p) (((p) >> 8) & 0xff) -+ -+#define IPPC_U3_CTRL_P0 0x30 -+#define CTRL_U3_PORT_DIS BIT(0) -+#define CTRL_U3_PORT_PDN BIT(1) -+#define CTRL_U3_PORT_HOST_SEL BIT(2) -+#define CTRL_U3_PORT_SS_GEN2 BIT(9) -+#define CTRL_U3_PORT_SS_2LANE BIT(10) -+ -+#define IPPC_U2_CTRL_P0 0x50 -+#define IPPC_U2_CTRL_P1 0x58 -+#define CTRL_U2_PORT_DIS BIT(0) -+#define CTRL_U2_PORT_PDN BIT(1) -+#define CTRL_U2_PORT_HOST_SEL BIT(2) -+ -+#define IPPC_CSR_CK_CTRL 0x88 -+#define CK_CSR_BUS_CK_GATE_EN BIT(0) -+#define CK_PHY_BUS_CK_GATE_EN BIT(1) -+ -+/* Test Bank */ -+#define XHCI_VTIO_TEST_BASE 0 -+ -+#define TEST_HSRAM_DBGCTL (XHCI_VTIO_TEST_BASE + 0x00) -+#define THDC_SRAM_DBG_EN BIT(0) -+#define THDC_SRAM_DBG_WP BIT(1) -+ -+#define TEST_HSRAM_DBGMODE (XHCI_VTIO_TEST_BASE + 0x04) -+#define THDM_SRAM_DM_EP_SLOT BIT(3) -+ -+#define TEST_HSRAM_DBGSEL (XHCI_VTIO_TEST_BASE + 0x08) -+#define THDS_SRAM_DS_EP_SLOT BIT(3) -+ -+#define TEST_HSRAM_DBGADR (XHCI_VTIO_TEST_BASE + 0x0C) -+#define THDA_SRAM_DWSEL_MSK GENMASK(2, 0) -+#define THDA_SRAM_DWSEL_VAL(x) ((x) & THDA_SRAM_DWSEL_MSK) -+#define THDA_DWSEL_32B_TO_64B 1 -+#define THDA_SRAM_ADDR_MSK GENMASK(16, 3) -+#define THDA_SRAM_ADDR_VAL(x) (((x) << 3) & THDA_SRAM_ADDR_MSK) -+ -+#define TEST_HSRAM_DBGDR (XHCI_VTIO_TEST_BASE + 0x10) -+ -+#define TEST_XACT3_CFG (XHCI_VTIO_TEST_BASE + 0x48) -+#define TXC_TX_TMOUT_MSK GENMASK(7, 0) -+#define TXC_TX_TMOUT_VAL(x) ((x) & TXC_TX_TMOUT_MSK) -+#define TXC_TX_TMOUT_VAL_DFT 0x40 -+ -+#define TEST_HSCH_CFG1 (XHCI_VTIO_TEST_BASE + 0x60) -+#define THC1_PORT_IDLE_WITH_ISO BIT(0) -+#define THC1_BURST_TD_OFF BIT(2) -+#define THC1_OUT_NUMP_REF BIT(4) -+#define THC1_SCH3_INT_PING_TD_CHK BIT(12) -+#define THC1_PORT_IDLE_WITH_INT BIT(13) -+ -+#define TEST_CMD_CFG (XHCI_VTIO_TEST_BASE + 0x64) -+#define TCC_PARAM_ERR_CHK_DIS BIT(0) -+ -+#define TEST_EP_CFG (XHCI_VTIO_TEST_BASE + 0x68) -+#define TEC_STOP_EP_OPT BIT(2) -+ -+#define TEST_TRBQ_CFG (XHCI_VTIO_TEST_BASE + 0x70) -+#define TTC_TRB_ERR_CHK_DIS BIT(0) -+ -+#define TEST_RST_CTRL0 (XHCI_VTIO_TEST_BASE + 0xB0) -+#define TRC_HCRST_RXDETECT_EN BIT(7) -+ -+#define TEST_SCH_CFG5 (XHCI_VTIO_TEST_BASE + 0x114) -+#define TSC5_OH_FS_INT_IN_MSK GENMASK(7, 0) -+#define TSC5_OH_FS_INT_IN_VAL(x) ((x) & TSC5_OH_FS_INT_IN_MSK) -+#define TSC5_OH_FS_INT_OUT_MSK GENMASK(15, 8) -+#define TSC5_OH_FS_INT_OUT_VAL(x) (((x) << 8) & TSC5_OH_FS_INT_OUT_MSK) -+#define TSC5_OH_FS_INT_DFT 0xA -+#define TSC5_OH_FS_ISO_IN_MSK GENMASK(23, 16) -+#define TSC5_OH_FS_ISO_IN_VAL(x) (((x) << 16) & TSC5_OH_FS_ISO_IN_MSK) -+#define TSC5_OH_FS_ISO_OUT_MSK GENMASK(31, 24) -+#define TSC5_OH_FS_ISO_OUT_VAL(x) (((x) << 24) & TSC5_OH_FS_ISO_OUT_MSK) -+#define TSC5_OH_FS_ISO_DFT 0x8 -+ -+#define TEST_SCH_CFG6 (XHCI_VTIO_TEST_BASE + 0x118) -+#define TSC6_OH_LS_INT_IN_MSK GENMASK(7, 0) -+#define TSC6_OH_LS_INT_IN_VAL(x) ((x) & TSC6_OH_LS_INT_IN_MSK) -+#define TSC6_OH_LS_INT_OUT_MSK GENMASK(15, 8) -+#define TSC6_OH_LS_INT_OUT_VAL(x) (((x) << 8) & TSC6_OH_LS_INT_OUT_MSK) -+#define TSC6_OH_LS_INT_DFT 0xA -+ -+#define IPPC_U3_CTRL(p) (IPPC_U3_CTRL_P0 + ((p) << 3)) -+#define IPPC_U2_CTRL(p) (IPPC_U2_CTRL_P0 + ((p) << 3)) -+ -+#define SPHY_U3_BASE_OFFSET 0x3000 -+#define SPHY_PORT_BANKS_SIZE 0x4000 -+ -+/* S-PHY sub-banks offset base address */ -+/* u2 phy banks */ -+#define SPHY_U2_MISC 0x000 -+#define SPHY_U2_FREQ 0x100 -+#define SPHY_U2_COM 0x300 -+ -+/* u3/pcie phy banks */ -+#define SPHY_U3_DIG_GLB 0x000 -+#define SPHY_U3_PHYA_GLB 0x100 -+/* u3 phy banks, ln0/1 */ -+#define SPHY_LN0_OFFSET 0x400 -+#define SPHY_LN_BANKS_SIZE 0x600 -+/* ln0/1 banks */ -+#define SPHY_LN_DIG_TOP 0x000 -+#define SPHY_LN_DIG_TX0 0x100 -+#define SPHY_LN_DIG_RX0 0x200 -+#define SPHY_LN_DIG_DAIF 0x300 -+#define SPHY_LN_PHYA 0x400 -+#define SPHY_LN_FEDIG 0x500 -+ -+#define U2P_MISC_REG1 (SPHY_U2_MISC + 0x04) -+#define MR1_RG_EFUSE_AUTO_LOAD_DIS BIT(6) -+ -+#define U2P_USBPHYACR0 (SPHY_U2_COM + 0x000) -+#define PA0_RG_U2_INTR_EN BIT(5) -+ -+#define U2P_USBPHYACR2 (SPHY_U2_COM + 0x008) -+#define PA2_RG_U2_CLKREF_REV1_MSK GENMASK(15, 8) -+#define PA2_RG_U2_CLKREF_REV1_VAL(x) ((0xff & (x)) << 8) -+#define PA2_RG_U2_CLKREF_DFT PA2_RG_U2_CLKREF_REV1_VAL(0x32) -+ -+#define U2P_USBPHYACR5 (SPHY_U2_COM + 0x014) -+#define PA5_RG_U2_HSTX_SRCTRL_MSK GENMASK(14, 12) -+#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12) -+#define PA5_RG_U2_DE_EMPHASIS_MSK GENMASK(9, 8) -+#define PA5_RG_U2_DE_EMPHASIS(x) ((0x3 & (x)) << 8) -+ -+#define U2P_USBPHYACR6 (SPHY_U2_COM + 0x018) -+#define PA6_RG_U2_BC11_SW_EN BIT(23) -+#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20) -+#define PA6_RG_U2_DISCTH_MSK GENMASK(7, 4) -+#define PA6_RG_U2_DISCTH_VAL(x) ((0xf & (x)) << 4) -+#define PA6_RG_U2_SQTH_MSK GENMASK(3, 0) -+#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x)) -+ -+#define U2P_U2PHYACR4 (SPHY_U2_COM + 0x020) -+#define P2C_RG_U2_GPIO_CTL BIT(9) -+#define P2C_RG_U2_GPIO_MODE BIT(8) -+#define P2C_U2_GPIO_CTR_MSK (P2C_RG_U2_GPIO_CTL | P2C_RG_U2_GPIO_MODE) -+ -+#define U2P_U2PHYACR5 (SPHY_U2_COM + 0x050) -+#define PA5_RG_LDO_VREF_SEL_MSK GENMASK(2, 0) -+#define PA5_RG_LDO_VREF_SEL_VAL(x) ((0x7 & (x)) << 0) -+#define PA5_RG_LDO_VREF_SEL_VAL_MAX (0x7) -+#define PA5_RG_TERM_CAL_P_MSK GENMASK(19, 16) -+#define PA5_RG_TERM_CAL_P_VAL(x) ((0xF & (x)) << 16) -+#define PA5_RG_HSTX_LDO_OUT_SEL_MSK GENMASK(29, 28) -+#define PA5_RG_HSTX_LDO_OUT_SEL_VAL(x) ((0x3 & (x)) << 28) -+ -+#define U2P_U2PHYDTM0 (SPHY_U2_COM + 0x068) -+#define P2C_FORCE_UART_EN BIT(26) -+#define P2C_FORCE_DATAIN BIT(23) -+#define P2C_FORCE_DM_PULLDOWN BIT(21) -+#define P2C_FORCE_DP_PULLDOWN BIT(20) -+#define P2C_FORCE_XCVRSEL BIT(19) -+#define P2C_FORCE_SUSPENDM BIT(18) -+#define P2C_FORCE_TERMSEL BIT(17) -+#define P2C_RG_DATAIN_MSK GENMASK(13, 10) -+#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10) -+#define P2C_RG_DMPULLDOWN BIT(7) -+#define P2C_RG_DPPULLDOWN BIT(6) -+#define P2C_RG_XCVRSEL_MSK GENMASK(5, 4) -+#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4) -+#define P2C_RG_SUSPENDM BIT(3) -+#define P2C_RG_TERMSEL BIT(2) -+#define P2C_DTM0_PART_MSK \ -+ (P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \ -+ P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \ -+ P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \ -+ P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL) -+ -+#define U2P_U2PHYDTM1 (SPHY_U2_COM + 0x06C) -+#define P2C_RG_UART_EN BIT(16) -+#define P2C_FORCE_IDDIG BIT(9) -+#define P2C_RG_VBUSVALID BIT(5) -+#define P2C_RG_SESSEND BIT(4) -+#define P2C_RG_AVALID BIT(2) -+#define P2C_RG_IDDIG BIT(1) -+ -+/* u3 phy bit fileds */ -+#define U3P_DIG_GLB_38 (SPHY_U3_DIG_GLB + 0x38) -+#define P3D_TX_DET_P3_TRACK_OPTION BIT(14) -+ -+#define U3P_DIG_GLB_60 (SPHY_U3_DIG_GLB + 0x60) -+#define P3D_CKM_GATED_BIAS_DIS BIT(13) -+#define P3D_CKM_XTAL_CK_DETECT_DIS BIT(14) -+ -+#define U3P_DIG_LN_RX_34 (SPHY_LN_DIG_RX0 + 0x34) -+#define P3LR_RXLFPS_G1_FWAKE_TH GENMASK(7, 0) -+#define P3LR_RXLFPS_G1_FWAKE_TH_VAL(x) ((0xFF & (x)) << 0) -+#define P3LR_RXLFPS_G2_FWAKE_TH GENMASK(15, 8) -+#define P3LR_RXLFPS_G2_FWAKE_TH_VAL(x) ((0xFF & (x)) << 8) -+#define P3LR_RXLFPS_FILTER_VAL_DFT 0x46 -+#define P3LR_RXLFPS_FWAKE_SYS_TH GENMASK(23, 16) -+#define P3LR_RXLFPS_FWAKE_SYS_TH_VAL(x) ((0xFF & (x)) << 16) -+#define P3LR_RXLFPS_FWAKE_SYS_TH_DFT 0xB9 -+ -+#define U3P_FEDIG_RG_29 (SPHY_LN_FEDIG + 0x74) -+#define P3FE_LN_RX_DFE_AUTO_OFF_EN BIT(30) -+ -+/* SPHY3-only LN0 SI tuning (N1A P4U3 P0/P1) */ -+#define U3P_DIG_LN_RX_70 (SPHY_LN_DIG_RX0 + 0x70) -+#define P3LR_PPATH_DVN_G2_LTD0_MSK GENMASK(7, 0) -+#define P3LR_PPATH_DVN_G2_LTD0_VAL (0x28 << 0) -+#define P3LR_PPATH_DVN_G2_LTD1_MSK GENMASK(15, 8) -+#define P3LR_PPATH_DVN_G2_LTD1_VAL (0x58 << 8) -+ -+#define U3P_DIG_LN_RX_7C (SPHY_LN_DIG_RX0 + 0x7C) -+#define P3LR_STB_GAIN_G2_LTD0_MSK GENMASK(15, 14) -+#define P3LR_STB_GAIN_G2_LTD0_VAL (0x2 << 14) -+ -+#define U3P_DIG_LN_DAIF_44 (SPHY_LN_DIG_DAIF + 0x44) -+#define P3LD_G2_CDR_IIR_GAIN_MSK GENMASK(15, 13) -+#define P3LD_G2_CDR_IIR_GAIN_VAL (0x2 << 13) -+ -+#define U3P_DIG_LN_DAIF_58 (SPHY_LN_DIG_DAIF + 0x58) -+#define P3LD_G2_RX_CDR_FASTP_GAIN_MSK GENMASK(31, 28) -+#define P3LD_G2_RX_CDR_FASTP_GAIN_VAL (0xF << 28) -+ -+#define U3P_DIG_LN_DAIF_60 (SPHY_LN_DIG_DAIF + 0x60) -+#define P3LD_G2_RX_LF_CTLE_CSEL_MSK GENMASK(23, 21) -+#define P3LD_G2_RX_LF_CTLE_CSEL_VAL (0x1 << 21) -+#define P3LD_G2_RX_LF_CTLE_RSEL_MSK GENMASK(31, 28) -+#define P3LD_G2_RX_LF_CTLE_RSEL_VAL (0x3 << 28) -+ -+#define U3P_PHYA_LN_0C (SPHY_LN_PHYA + 0x0C) -+#define P3L_RX_FE_RESERVE_MSK GENMASK(23, 22) -+#define P3L_RX_FE_RESERVE_VAL (0x0 << 22) -+ -+// sw macros -+#define U3_CLK_WAIT_MS 10 -+#define MS_TO_US 1000 -+#define WAIT_UNIT_US 10 -+#define TEST_HSRAM_ARRAY_SIZE 32 -+ -+static inline void usb_write(void __iomem *base, u32 offset, u32 val) -+{ -+ writel(val, base + offset); -+} -+ -+static inline u32 usb_read(void __iomem *base, u32 offset) -+{ -+ return readl(base + offset); -+} -+ -+static inline void usb_clr_bits(void __iomem *base, u32 offset, u32 bits) -+{ -+ u32 tmp; -+ -+ tmp = readl(base + offset); -+ tmp &= ~bits; -+ writel(tmp, base + offset); -+} -+ -+static inline void usb_set_bits(void __iomem *base, u32 offset, u32 bits) -+{ -+ u32 tmp; -+ -+ tmp = readl(base + offset); -+ tmp |= bits; -+ writel(tmp, base + offset); -+} -+ -+static inline void usb_update_bits(void __iomem *base, u32 offset, u32 mask, u32 bits) -+{ -+ u32 tmp; -+ -+ tmp = readl(base + offset); -+ tmp &= ~mask; -+ tmp |= bits; -+ writel(tmp, base + offset); -+} -+ -+static inline int -+usb_read_poll_timeout(void __iomem *base, u32 offset, u32 check_val, int timeout_ms) -+{ -+ int times = timeout_ms * MS_TO_US / WAIT_UNIT_US; -+ u32 val; -+ -+ do { -+ val = usb_read(base, offset); -+ if (check_val == (val & check_val)) -+ break; -+ -+ udelay(WAIT_UNIT_US); -+ } while (--times > 0); -+ -+ return times > 0 ? 0 : -ETIMEDOUT; -+} -+ -+static void sphy_u2_init(struct mtk_usb_phy *phy) -+{ -+ void __iomem *pbase = phy->port_base; -+ -+ // switch to USB function, and enable usb pll -+ usb_clr_bits(pbase, U2P_U2PHYDTM0, P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM); -+ -+ usb_clr_bits(pbase, U2P_U2PHYDTM1, P2C_RG_UART_EN); -+ -+ usb_set_bits(pbase, U2P_USBPHYACR0, PA0_RG_U2_INTR_EN); -+ -+ usb_clr_bits(pbase, U2P_U2PHYACR4, P2C_U2_GPIO_CTR_MSK); -+ -+ // DP/DM BC1.1 path Disable -+ usb_clr_bits(pbase, U2P_USBPHYACR6, PA6_RG_U2_BC11_SW_EN); -+ -+ //usb_update_bits(pbase, U2P_USBPHYACR6, PA6_RG_U2_SQTH_MSK, PA6_RG_U2_SQTH_VAL(2)); -+ -+ // set HS slew rate -+ //usb_update_bits(pbase, U2P_USBPHYACR5, -+ // PA5_RG_U2_HSTX_SRCTRL_MSK, PA5_RG_U2_HSTX_SRCTRL_VAL(4)); -+ -+ // set de-emphasis (from sphy3/4) -+ usb_update_bits(pbase, U2P_USBPHYACR5, PA5_RG_U2_DE_EMPHASIS_MSK, PA5_RG_U2_DE_EMPHASIS(1)); -+ // set LDO output follow de-emphasis (from sphy3/4) -+ usb_update_bits(pbase, U2P_U2PHYACR5, PA5_RG_HSTX_LDO_OUT_SEL_MSK, -+ PA5_RG_HSTX_LDO_OUT_SEL_VAL(1)); -+ -+ usb_clr_bits(pbase, U2P_U2PHYDTM0, P2C_DTM0_PART_MSK); -+ -+ usb_update_bits(pbase, U2P_USBPHYACR2, PA2_RG_U2_CLKREF_REV1_MSK, PA2_RG_U2_CLKREF_DFT); -+ -+ /* OTG Enable */ -+ usb_set_bits(pbase, U2P_USBPHYACR6, PA6_RG_U2_OTG_VBUSCMP_EN); -+ -+ usb_set_bits(pbase, U2P_U2PHYDTM1, P2C_RG_VBUSVALID | P2C_RG_AVALID); -+ -+ usb_clr_bits(pbase, U2P_U2PHYDTM1, P2C_RG_SESSEND); -+ -+ pr_debug(" %s (%u)\n", __func__, phy->pid); -+} -+ -+static void sphy_u2_exit(struct mtk_usb_phy *phy) -+{ -+ /* OTG Enable */ -+ usb_clr_bits(phy->port_base, U2P_USBPHYACR6, PA6_RG_U2_OTG_VBUSCMP_EN); -+ -+ usb_clr_bits(phy->port_base, U2P_U2PHYDTM1, P2C_RG_VBUSVALID | P2C_RG_AVALID); -+ -+ usb_set_bits(phy->port_base, U2P_U2PHYDTM1, P2C_RG_SESSEND); -+ -+ pr_debug(" %s (%u)\n", __func__, phy->pid); -+} -+ -+static void sphy_u2_param_tune(struct mtk_usb_phy *phy) -+{ -+ void __iomem *pbase = phy->port_base; -+ -+ pr_debug(" %s (%u)\n", __func__, phy->pid); -+ -+ if (phy->u2p_disconnect_threshold) { -+ usb_update_bits(pbase, U2P_USBPHYACR6, PA6_RG_U2_DISCTH_MSK, -+ PA6_RG_U2_DISCTH_VAL(phy->u2p_disconnect_threshold)); -+ } -+ -+ if (phy->u2p_eye_rising_deemphasis) { -+ // set de-emphasis (from sphy3/4) -+ usb_update_bits(pbase, U2P_USBPHYACR5, PA5_RG_U2_DE_EMPHASIS_MSK, -+ PA5_RG_U2_DE_EMPHASIS(phy->u2p_eye_rising_deemphasis)); -+ } -+ -+ if (phy->u2p_eye_rising_txldoout) { -+ // it's better to set LDO-out as de-emphasis (from sphy3/4) -+ usb_update_bits(pbase, U2P_U2PHYACR5, PA5_RG_HSTX_LDO_OUT_SEL_MSK, -+ PA5_RG_HSTX_LDO_OUT_SEL_VAL(phy->u2p_eye_rising_txldoout)); -+ } -+ -+ if (phy->u2p_eye_swing_vref) { -+ // disable efuse auto-load first -+ usb_set_bits(pbase, U2P_MISC_REG1, MR1_RG_EFUSE_AUTO_LOAD_DIS); -+ usb_update_bits(pbase, U2P_U2PHYACR5, PA5_RG_LDO_VREF_SEL_MSK, -+ PA5_RG_LDO_VREF_SEL_VAL(phy->u2p_eye_swing_vref)); -+ // shall update Term only when Verf is max 7 -+ if (phy->u2p_eye_swing_term && -+ (phy->u2p_eye_swing_vref == PA5_RG_LDO_VREF_SEL_VAL_MAX)) { -+ usb_update_bits(pbase, U2P_U2PHYACR5, PA5_RG_TERM_CAL_P_MSK, -+ PA5_RG_TERM_CAL_P_VAL(phy->u2p_eye_swing_term)); -+ } -+ } -+} -+ -+static void sphy3_u3_lane0_init(struct mtk_usb_phy *phy) -+{ -+ void __iomem *lane_base = phy->port_base + phy->u3p_offset + SPHY_LN0_OFFSET; -+ -+ pr_debug("sphy3: %s\n", __func__); -+ -+ usb_update_bits(lane_base, U3P_DIG_LN_RX_70, -+ P3LR_PPATH_DVN_G2_LTD0_MSK | P3LR_PPATH_DVN_G2_LTD1_MSK, -+ P3LR_PPATH_DVN_G2_LTD0_VAL | P3LR_PPATH_DVN_G2_LTD1_VAL); -+ usb_update_bits(lane_base, U3P_DIG_LN_RX_7C, -+ P3LR_STB_GAIN_G2_LTD0_MSK, -+ P3LR_STB_GAIN_G2_LTD0_VAL); -+ usb_update_bits(lane_base, U3P_DIG_LN_DAIF_44, -+ P3LD_G2_CDR_IIR_GAIN_MSK, -+ P3LD_G2_CDR_IIR_GAIN_VAL); -+ usb_update_bits(lane_base, U3P_DIG_LN_DAIF_58, -+ P3LD_G2_RX_CDR_FASTP_GAIN_MSK, -+ P3LD_G2_RX_CDR_FASTP_GAIN_VAL); -+ usb_update_bits(lane_base, U3P_DIG_LN_DAIF_60, -+ P3LD_G2_RX_LF_CTLE_CSEL_MSK | P3LD_G2_RX_LF_CTLE_RSEL_MSK, -+ P3LD_G2_RX_LF_CTLE_CSEL_VAL | P3LD_G2_RX_LF_CTLE_RSEL_VAL); -+ usb_clr_bits(lane_base, U3P_PHYA_LN_0C, P3L_RX_FE_RESERVE_MSK); -+} -+ -+static void sphy4_u3_lane_init(struct mtk_usb_phy *phy, u32 lane_num) -+{ -+ void __iomem *lane_base; -+ -+ pr_debug(" %s (%u)\n", __func__, lane_num); -+ -+ lane_base = phy->port_base + phy->u3p_offset + SPHY_LN0_OFFSET; -+ if (lane_num != 0) -+ lane_base = lane_base + SPHY_LN_BANKS_SIZE; -+ -+ usb_update_bits(lane_base, U3P_DIG_LN_RX_34, -+ P3LR_RXLFPS_G1_FWAKE_TH | P3LR_RXLFPS_G2_FWAKE_TH | -+ P3LR_RXLFPS_FWAKE_SYS_TH, -+ (P3LR_RXLFPS_G1_FWAKE_TH_VAL(P3LR_RXLFPS_FILTER_VAL_DFT) | -+ P3LR_RXLFPS_G2_FWAKE_TH_VAL(P3LR_RXLFPS_FILTER_VAL_DFT) | -+ P3LR_RXLFPS_FWAKE_SYS_TH_VAL(P3LR_RXLFPS_FWAKE_SYS_TH_DFT))); -+ -+ // disable DFE auto off function -+ usb_clr_bits(lane_base, U3P_FEDIG_RG_29, P3FE_LN_RX_DFE_AUTO_OFF_EN); -+} -+ -+static void sphy_u3_init(struct mtk_usb_phy *phy) -+{ -+ void __iomem *pbase = phy->port_base + phy->u3p_offset; -+ -+ pr_debug(" %s (%u)\n", __func__, phy->pid); -+ -+ if (phy->hw_type == PHY_HWIP_SPHY3) { -+ usb_set_bits(pbase, U3P_DIG_GLB_60, P3D_CKM_XTAL_CK_DETECT_DIS); -+ usb_clr_bits(pbase, U3P_DIG_GLB_60, P3D_CKM_GATED_BIAS_DIS); -+ sphy3_u3_lane0_init(phy); -+ } else if (phy->hw_type == PHY_HWIP_SPHY4) { -+ // Apply detection option in P3 and backs to sleep -+ usb_set_bits(pbase, U3P_DIG_GLB_38, P3D_TX_DET_P3_TRACK_OPTION); -+ -+ sphy4_u3_lane_init(phy, 0); -+ sphy4_u3_lane_init(phy, 1); -+ } -+} -+ -+static void sphy_u3_exit(struct mtk_usb_phy *phy) -+{} -+ -+static int sphy_power_on(struct usb3_sphy *sphy) -+{ -+ struct mtk_usb_phy *phy; -+ int i; -+ -+ if (!sphy) -+ return 0; -+ -+ for (i = 0; i < sphy->phy_cnt; i++) { -+ phy = &sphy->phys[i]; -+ -+ sphy_u2_init(phy); -+ sphy_u2_param_tune(phy); -+ -+ if (phy->type == PHY_TYPE_USB3) -+ sphy_u3_init(phy); -+ } -+ -+ pr_debug(" %s\n", __func__); -+ return 0; -+} -+ -+static int sphy_power_off(struct usb3_sphy *sphy) -+{ -+ struct mtk_usb_phy *phy; -+ int i; -+ -+ if (!sphy) -+ return 0; -+ -+ for (i = 0; i < sphy->phy_cnt; i++) { -+ phy = &sphy->phys[i]; -+ -+ sphy_u2_exit(phy); -+ -+ if (phy->type == PHY_TYPE_USB3) -+ sphy_u3_exit(phy); -+ } -+ -+ pr_debug(" %s\n", __func__); -+ return 0; -+} -+ -+static void usb3_ippc_disable(struct xhci_plat_priv *priv) -+{ -+ void __iomem *ibase = priv->ippc_base; -+ u32 i; -+ -+ dev_dbg(priv->dev, " %s\n", __func__); -+ -+ // power down and disable u3 ports -+ for (i = 0; i < priv->u3port_cnt; i++) { -+ if (BIT(i) & priv->u3port_disable_mask) -+ continue; -+ -+ usb_set_bits(ibase, IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS); -+ } -+ -+ // power down and disable all u2 ports -+ for (i = 0; i < priv->u2port_cnt; i++) -+ usb_set_bits(ibase, IPPC_U2_CTRL(i), CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS); -+ -+ // power down host ip -+ usb_set_bits(ibase, IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); -+} -+ -+static int usb3_ippc_enable(struct xhci_plat_priv *priv) -+{ -+ void __iomem *ibase = priv->ippc_base; -+ u32 check_val; -+ u32 u3port_dis_cnt = 0; -+ u32 i; -+ int status; -+ -+ dev_dbg(priv->dev, " %s\n", __func__); -+ -+ // disable ck gate -+ usb_clr_bits(ibase, IPPC_CSR_CK_CTRL, CK_CSR_BUS_CK_GATE_EN | CK_PHY_BUS_CK_GATE_EN); -+ -+ // power on host ip -+ usb_clr_bits(ibase, IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); -+ -+ // power on and enable u3 ports -+ for (i = 0; i < priv->u3port_cnt; i++) { -+ if (BIT(i) & priv->u3port_disable_mask) { -+ usb_set_bits(ibase, IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS); -+ u3port_dis_cnt++; -+ continue; -+ } -+ -+ usb_update_bits(ibase, IPPC_U3_CTRL(i), -+ CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS | CTRL_U3_PORT_HOST_SEL, -+ CTRL_U3_PORT_HOST_SEL); -+ } -+ -+ // power on and enable all u2 ports -+ for (i = 0; i < priv->u2port_cnt; i++) { -+ usb_update_bits(ibase, IPPC_U2_CTRL(i), -+ CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS | CTRL_U2_PORT_HOST_SEL, -+ CTRL_U2_PORT_HOST_SEL); -+ } -+ -+ // -+ // wait for clocks to be stable, and clock domains reset to -+ // be inactive after power on and enable ports -+ // -+ check_val = STS1_SYSPLL_STABLE | STS1_REF_RST | STS1_SYS125_RST | STS1_XHCI_RST; -+ if (priv->u3port_cnt > u3port_dis_cnt) -+ check_val |= STS1_U3_MAC_RST; -+ -+ status = usb_read_poll_timeout(ibase, IPPC_IP_PW_STS1, check_val, U3_CLK_WAIT_MS); -+ if (status) -+ dev_warn(priv->dev, " xHCI wait clocks timeout\n"); -+ -+ return status; -+} -+ -+static int usb3_ippc_enter_lps(struct xhci_plat_priv *priv) -+{ -+ void __iomem *ibase = priv->ippc_base; -+ u32 i; -+ int status; -+ -+ // power down u3 ports -+ for (i = 0; i < priv->u3port_cnt; i++) { -+ if (BIT(i) & priv->u3port_disable_mask) -+ continue; -+ -+ usb_set_bits(ibase, IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN); -+ } -+ -+ // power down all u2 ports -+ for (i = 0; i < priv->u2port_cnt; i++) -+ usb_set_bits(ibase, IPPC_U2_CTRL(i), CTRL_U2_PORT_PDN); -+ -+ // power down host ip -+ usb_set_bits(ibase, IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); -+ -+ status = usb_read_poll_timeout(ibase, IPPC_IP_PW_STS1, STS1_IP_SLEEP, 10); -+ if (status) -+ dev_err(priv->dev, " xHCI sleep failed\n"); -+ -+ dev_info(priv->dev, " ip-sleep %d\n", -+ !!(usb_read(ibase, IPPC_IP_PW_STS1) & STS1_IP_SLEEP)); -+ -+ return status; -+} -+ -+static int usb3_ippc_exit_lps(struct xhci_plat_priv *priv) -+{ -+ void __iomem *ibase = priv->ippc_base; -+ u32 i; -+ int status; -+ -+ dev_info(priv->dev, " ip-sleep %d\n", -+ !!(usb_read(ibase, IPPC_IP_PW_STS1) & STS1_IP_SLEEP)); -+ -+ // clear reset -+ usb_clr_bits(ibase, IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST); -+ -+ // disable ck gate -+ usb_clr_bits(ibase, IPPC_CSR_CK_CTRL, CK_CSR_BUS_CK_GATE_EN | CK_PHY_BUS_CK_GATE_EN); -+ -+ // power on host ip -+ usb_clr_bits(ibase, IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); -+ -+ // power on u3 ports -+ for (i = 0; i < priv->u3port_cnt; i++) { -+ if (BIT(i) & priv->u3port_disable_mask) { -+ usb_set_bits(ibase, IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS); -+ continue; -+ } -+ -+ usb_update_bits(ibase, IPPC_U3_CTRL(i), -+ CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS | CTRL_U3_PORT_HOST_SEL, -+ CTRL_U3_PORT_HOST_SEL); -+ } -+ -+ // power on all u2 ports -+ for (i = 0; i < priv->u2port_cnt; i++) { -+ usb_update_bits(ibase, IPPC_U2_CTRL(i), -+ CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS | CTRL_U2_PORT_HOST_SEL, -+ CTRL_U2_PORT_HOST_SEL); -+ } -+ -+ status = usb_read_poll_timeout(ibase, IPPC_IP_PW_STS1, -+ STS1_SYSPLL_STABLE | STS1_XHCI_RST, U3_CLK_WAIT_MS); -+ if (status) -+ dev_err(priv->dev, " xHCI wait clocks timeout\n"); -+ -+ return status; -+} -+ -+static void usb3_ippc_get_port_cnt(struct xhci_plat_priv *priv) -+{ -+ u32 cap; -+ -+ cap = usb_read(priv->ippc_base, IPPC_IP_XHCI_CAP); -+ priv->u2port_cnt = CAP_U2_PORT_NUM(cap); -+ priv->u3port_cnt = CAP_U3_PORT_NUM(cap); -+ -+ dev_dbg(priv->dev, " xHCI - u2 ports:%u, u3 ports:%u\n", -+ priv->u2port_cnt, priv->u3port_cnt); -+} -+ -+static void usb3_ip_reset(struct xhci_plat_priv *priv) -+{ -+ // Todo: peri top reset? -+ -+ // reset whole ip -+ usb_set_bits(priv->ippc_base, IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST); -+ udelay(1); -+ usb_clr_bits(priv->ippc_base, IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST); -+ -+ // power down device ip, otherwise ip-sleep will fail -+ usb_set_bits(priv->ippc_base, IPPC_IP_PW_CTRL2, CTRL2_IP_DEV_PDN); -+} -+ -+static void usb3_hsram_init(struct xhci_plat_priv *priv) -+{ -+ void __iomem *embase = priv->ext_mac_base; -+ int i; -+ -+ usb_write(embase, TEST_HSRAM_DBGCTL, THDC_SRAM_DBG_EN); -+ usb_write(embase, TEST_HSRAM_DBGMODE, THDM_SRAM_DM_EP_SLOT); -+ usb_write(embase, TEST_HSRAM_DBGSEL, THDS_SRAM_DS_EP_SLOT); -+ -+ for (i = 0; i < TEST_HSRAM_ARRAY_SIZE; i++) { -+ usb_write(embase, TEST_HSRAM_DBGADR, -+ THDA_SRAM_ADDR_VAL(i) | THDA_SRAM_DWSEL_VAL(THDA_DWSEL_32B_TO_64B)); -+ usb_write(embase, TEST_HSRAM_DBGDR, 0); -+ } -+ -+ // restore default value -+ usb_write(embase, TEST_HSRAM_DBGCTL, THDC_SRAM_DBG_WP); -+ usb_write(embase, TEST_HSRAM_DBGMODE, 0); -+ usb_write(embase, TEST_HSRAM_DBGSEL, 0); -+} -+ -+static void usb3_mac_ext_init(struct xhci_plat_priv *priv) -+{ -+ void __iomem *embase = priv->ext_mac_base; -+ -+ // workaround: -+ // SSUSB INTR EP not resume link after doorbell issue, can't enter u1/u2 -+ // when isoc is active; -+ usb_set_bits(embase, TEST_HSCH_CFG1, THC1_PORT_IDLE_WITH_ISO); -+ usb_set_bits(embase, TEST_HSCH_CFG1, THC1_PORT_IDLE_WITH_INT); -+ // SSUSB ISO ACK missing due to unexpected PING reject issue -+ // don't check TD status, just resume anyway -+ usb_clr_bits(embase, TEST_HSCH_CFG1, THC1_SCH3_INT_PING_TD_CHK); -+ // isoc miss service error when run multi ep stress test(bulk/intr/isoc) -+ usb_set_bits(embase, TEST_HSCH_CFG1, THC1_BURST_TD_OFF | THC1_OUT_NUMP_REF); -+ // decrease LS/FS default BW overhead -+ usb_update_bits(embase, TEST_SCH_CFG6, -+ (TSC6_OH_LS_INT_IN_MSK | TSC6_OH_LS_INT_OUT_MSK), -+ (TSC6_OH_LS_INT_IN_VAL(TSC6_OH_LS_INT_DFT) | -+ TSC6_OH_LS_INT_OUT_VAL(TSC6_OH_LS_INT_DFT))); -+ usb_update_bits(embase, TEST_SCH_CFG5, -+ (TSC5_OH_FS_INT_IN_MSK | TSC5_OH_FS_INT_OUT_MSK), -+ (TSC5_OH_FS_INT_IN_VAL(TSC5_OH_FS_INT_DFT) | -+ TSC5_OH_FS_INT_OUT_VAL(TSC5_OH_FS_INT_DFT))); -+ usb_update_bits(embase, TEST_SCH_CFG5, -+ (TSC5_OH_FS_ISO_IN_MSK | TSC5_OH_FS_ISO_OUT_MSK), -+ (TSC5_OH_FS_ISO_IN_VAL(TSC5_OH_FS_ISO_DFT) | -+ TSC5_OH_FS_ISO_OUT_VAL(TSC5_OH_FS_ISO_DFT))); -+ -+ // fix Gen2 SSD UASP Read performance low issue -+ usb_update_bits(embase, TEST_XACT3_CFG, TXC_TX_TMOUT_MSK, -+ TXC_TX_TMOUT_VAL(TXC_TX_TMOUT_VAL_DFT)); -+ -+ // WA for xhcicv test -+ usb_set_bits(embase, TEST_CMD_CFG, TCC_PARAM_ERR_CHK_DIS); -+ usb_clr_bits(embase, TEST_RST_CTRL0, TRC_HCRST_RXDETECT_EN); -+ usb_set_bits(embase, TEST_EP_CFG, TEC_STOP_EP_OPT); -+ usb_set_bits(embase, TEST_TRBQ_CFG, TTC_TRB_ERR_CHK_DIS); -+ -+ usb3_hsram_init(priv); -+} -+ -+static int xhci_mtk_restore_local(struct xhci_plat_priv *priv) -+{ -+ int ret; -+ -+ sphy_power_on(&priv->sphy); -+ -+ usb3_ippc_get_port_cnt(priv); -+ -+ ret = usb3_ippc_exit_lps(priv); -+ if (ret) -+ return ret; -+ -+ usb3_mac_ext_init(priv); -+ -+ return 0; -+} -+ -+int xhci_mtk_exit_lps(struct xhci_hcd *xhci) -+{ -+ struct xhci_plat_priv *priv = xhci_to_priv(xhci); -+ int ret; -+ -+ dev_dbg(priv->dev, " %s\n", __func__); -+ -+ ret = mtk_pwrap_dev_resume(priv->pwrap_cfg, 0); -+ if (ret) { -+ dev_err(priv->dev, "pwrap resume failed (%d)\n", ret); -+ return ret; -+ } -+ -+ return xhci_mtk_restore_local(priv); -+} -+ -+int xhci_mtk_enter_lps(struct xhci_hcd *xhci) -+{ -+ struct xhci_plat_priv *priv = xhci_to_priv(xhci); -+ int ret, rollback_ret; -+ -+ ret = usb3_ippc_enter_lps(priv); -+ if (ret) -+ goto restore_local; -+ -+ sphy_power_off(&priv->sphy); -+ -+ ret = mtk_pwrap_dev_suspend(priv->pwrap_cfg, 0); -+ if (!ret) -+ return 0; -+ -+ dev_err(priv->dev, "pwrap suspend failed (%d)\n", ret); -+ -+ /* -+ * A failed Power Wrap request may still have reached firmware. Confirm -+ * D0 before accessing local USB registers during rollback. -+ */ -+ rollback_ret = mtk_pwrap_dev_resume(priv->pwrap_cfg, 0); -+ if (rollback_ret) { -+ dev_err(priv->dev, "pwrap suspend rollback failed (%d)\n", -+ rollback_ret); -+ /* Let the normal resume callback retry D0 before touching MMIO. */ -+ return 0; -+ } -+ -+restore_local: -+ rollback_ret = xhci_mtk_restore_local(priv); -+ if (rollback_ret) { -+ dev_err(priv->dev, "failed to restore local hardware (%d)\n", -+ rollback_ret); -+ /* Keep PM bookkeeping suspended for a later recovery attempt. */ -+ return 0; -+ } -+ -+ return ret; -+} -+ -+int xhci_mtk_prepare_hw(struct xhci_hcd *xhci) -+{ -+ struct xhci_plat_priv *priv = xhci_to_priv(xhci); -+ int ret; -+ -+ dev_dbg(priv->dev, " %s\n", __func__); -+ -+ // power up -+ priv->pwrap_cfg = mtk_pwrap_dev_probe((char *)priv->acpi_path.pointer); -+ if (!priv->pwrap_cfg) { -+ dev_err(priv->dev, "Not find power wrap config data\n"); -+ return -EINVAL; -+ } -+ -+ sphy_power_on(&priv->sphy); -+ -+ usb3_ip_reset(priv); -+ -+ usb3_ippc_get_port_cnt(priv); -+ -+ ret = usb3_ippc_enable(priv); -+ if (ret) { -+ xhci_mtk_release_hw(xhci, true); -+ return ret; -+ } -+ -+ usb3_mac_ext_init(priv); -+ -+ return 0; -+} -+ -+void xhci_mtk_release_hw(struct xhci_hcd *xhci, bool hw_accessible) -+{ -+ struct xhci_plat_priv *priv = xhci_to_priv(xhci); -+ -+ /* Avoid IPPC and PHY accesses when the power state is unconfirmed. */ -+ if (hw_accessible) { -+ usb3_ippc_disable(priv); -+ sphy_power_off(&priv->sphy); -+ } -+ -+ mtk_pwrap_dev_remove(priv->pwrap_cfg); -+ priv->pwrap_cfg = NULL; -+} -+ -+int xhci_mtk_get_resources(struct platform_device *pdev, struct xhci_hcd *xhci) -+{ -+ struct xhci_plat_priv *priv = xhci_to_priv(xhci); -+ struct device *dev = &pdev->dev; -+ struct acpi_device *adev = ACPI_COMPANION(dev); -+ acpi_status status; -+ void __iomem *phy_base; -+ struct usb3_sphy *sphy; -+ struct mtk_usb_phy *phy; -+ u32 phy_type = 0; -+ u32 eye_swing[2] = {0, }; -+ u32 disth = 0; -+ u32 deemph = 0; -+ u32 txldo = 0; -+ int ret; -+ -+ if (!adev) -+ return dev_err_probe(dev, -ENODEV, "missing ACPI companion\n"); -+ -+ // required -+ ret = device_property_read_u32(dev, "mtk-phy-type", &phy_type); -+ if (ret) -+ return dev_err_probe(dev, ret, "missing mtk-phy-type\n"); -+ if (phy_type != PHY_HWIP_SPHY3 && phy_type != PHY_HWIP_SPHY4) -+ return dev_err_probe(dev, -EINVAL, -+ "unsupported mtk-phy-type: %u\n", phy_type); -+ dev_info(dev, "mtk-phy-type: %x\n", phy_type); -+ -+ priv->ext_mac_base = devm_platform_ioremap_resource(pdev, 1); -+ if (IS_ERR(priv->ext_mac_base)) { -+ ret = PTR_ERR(priv->ext_mac_base); -+ goto err_ext_mac; -+ } -+ -+ priv->ippc_base = devm_platform_ioremap_resource(pdev, 2); -+ if (IS_ERR(priv->ippc_base)) { -+ ret = PTR_ERR(priv->ippc_base); -+ goto err_ippc; -+ } -+ -+ phy_base = devm_platform_ioremap_resource(pdev, 3); -+ if (IS_ERR(phy_base)) { -+ ret = PTR_ERR(phy_base); -+ goto err_phy; -+ } -+ -+ priv->dev = dev; -+ priv->acpi_path.length = ACPI_ALLOCATE_BUFFER; -+ priv->acpi_path.pointer = NULL; -+ status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &priv->acpi_path); -+ if (ACPI_FAILURE(status)) { -+ dev_err(&pdev->dev, "Failed to get ACPI device path\n"); -+ return -EINVAL; -+ } -+ -+ ret = acpi_dev_uid_to_integer(adev, &priv->uid); -+ if (ret) -+ dev_err(&pdev->dev, "error: no _UID found\n"); -+ else -+ dev_info(&pdev->dev, "find acpi _UID: %x\n", (int)priv->uid); -+ -+ // optional -+ device_property_read_u32(dev, "mtk-u3port-disable-mask", &priv->u3port_disable_mask); -+ dev_info(&pdev->dev, "mtk-u3port-disable-mask: %x\n", priv->u3port_disable_mask); -+ -+ // optional -+ device_property_read_u32(dev, "mtk-u2phy-discth", &disth); -+ dev_info(&pdev->dev, "mtk-u2phy-discth: %x\n", disth); -+ -+ // optional -+ device_property_read_u32(dev, "mtk-u2phy-de-emphasis", &deemph); -+ dev_info(&pdev->dev, "mtk-u2phy-de-emphasis: %x\n", deemph); -+ -+ // optional -+ device_property_read_u32(dev, "mtk-u2phy-tx-ldo-out", &txldo); -+ dev_info(&pdev->dev, "mtk-u2phy-tx-ldo-out: %x\n", txldo); -+ -+ /* -+ * get u2phy eye swing adjust, optional -+ * Note: tune Term only when Vref is max 7, otherwise Term is ignored -+ */ -+ device_property_read_u32_array(dev, "mtk-u2phy-eye-swing", eye_swing, 2); -+ dev_info(dev, "eye swing: val[0]=0x%x, val[1]=0x%x\n", eye_swing[0], eye_swing[1]); -+ -+ sphy = &priv->sphy; -+ sphy->phy_cnt = 1; // by default -+ phy = &sphy->phys[0]; -+ phy->port_base = phy_base; -+ phy->hw_type = phy_type; -+ phy->pid = PHY_ID_U3_P0; -+ phy->type = PHY_TYPE_USB3; -+ phy->u3p_offset = SPHY_U3_BASE_OFFSET; -+ phy->u2p_eye_swing_vref = eye_swing[0]; -+ phy->u2p_eye_swing_term = eye_swing[1]; -+ phy->u2p_eye_rising_deemphasis = deemph; -+ phy->u2p_eye_rising_txldoout = txldo; -+ phy->u2p_disconnect_threshold = disth; -+ -+ // p4u3 port-1 has the 2nd u2 port -+ if (priv->uid == 0x5) { -+ sphy->phy_cnt = 2; -+ phy = &sphy->phys[1]; -+ phy->port_base = phy_base + SPHY_PORT_BANKS_SIZE; -+ phy->hw_type = phy_type; -+ phy->pid = PHY_ID_U2_P1; -+ phy->type = PHY_TYPE_USB2; -+ phy->u2p_eye_swing_vref = eye_swing[0]; -+ phy->u2p_eye_swing_term = eye_swing[1]; -+ phy->u2p_eye_rising_deemphasis = deemph; -+ phy->u2p_eye_rising_txldoout = txldo; -+ phy->u2p_disconnect_threshold = disth; -+ } -+ -+ return 0; -+ -+err_ext_mac: -+err_ippc: -+err_phy: -+ return ret; -+} -+ -+void xhci_mtk_free_resources(struct platform_device *pdev, struct xhci_hcd *xhci) -+{ -+ struct xhci_plat_priv *priv = xhci_to_priv(xhci); -+ -+ ACPI_FREE(priv->acpi_path.pointer); -+ priv->acpi_path.pointer = NULL; -+ priv->acpi_path.length = 0; -+} -diff --git a/drivers/usb/host/xhci-mtk-v2.h b/drivers/usb/host/xhci-mtk-v2.h -new file mode 100644 -index 0000000..74cd4ab ---- /dev/null -+++ b/drivers/usb/host/xhci-mtk-v2.h -@@ -0,0 +1,85 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2026 MediaTek Inc. -+ * -+ * Author: Chunfeng Yun -+ */ -+ -+#ifndef __LINUX_XHCI_MTK_V2_H -+#define __LINUX_XHCI_MTK_V2_H -+ -+#include -+#include -+ -+#include "xhci.h" -+ -+enum phy_hwip_type { -+ PHY_HWIP_SPHY3 = 3, -+ PHY_HWIP_SPHY4, -+}; -+ -+enum usb_phy_id { -+ PHY_ID_U3_P0 = 0, -+ PHY_ID_U2_P1, -+ PHY_ID_U2_P2, -+ PHY_ID_U2_P3, -+}; -+ -+struct mtk_usb_phy { -+ void __iomem *port_base; -+ u32 u3p_offset; // when support u3 -+ u32 pid; -+ u32 type; -+ enum phy_hwip_type hw_type; -+ u32 u2p_disconnect_threshold; -+ u32 u2p_eye_swing_vref; -+ u32 u2p_eye_swing_term; -+ u32 u2p_eye_rising_deemphasis; -+ u32 u2p_eye_rising_txldoout; -+}; -+ -+struct usb3_sphy { -+ int phy_cnt; // total number of hw port, 'u2 + u3' pair or u2 only -+ struct mtk_usb_phy phys[4]; -+}; -+ -+#if IS_ENABLED(CONFIG_USB_XHCI_MTK_V2) -+int xhci_mtk_exit_lps(struct xhci_hcd *xhci); -+int xhci_mtk_enter_lps(struct xhci_hcd *xhci); -+int xhci_mtk_prepare_hw(struct xhci_hcd *xhci); -+void xhci_mtk_release_hw(struct xhci_hcd *xhci, bool hw_accessible); -+int xhci_mtk_get_resources(struct platform_device *pdev, struct xhci_hcd *xhci); -+void xhci_mtk_free_resources(struct platform_device *pdev, struct xhci_hcd *xhci); -+ -+#else -+ -+static inline int xhci_mtk_exit_lps(struct xhci_hcd *xhci) -+{ -+ return 0; -+} -+ -+static inline int xhci_mtk_enter_lps(struct xhci_hcd *xhci) -+{ -+ return 0; -+} -+ -+static inline int xhci_mtk_prepare_hw(struct xhci_hcd *xhci) -+{ -+ return 0; -+} -+ -+static inline void xhci_mtk_release_hw(struct xhci_hcd *xhci, -+ bool hw_accessible) -+{} -+ -+static inline int xhci_mtk_get_resources(struct platform_device *pdev, struct xhci_hcd *xhci) -+{ -+ return 0; -+} -+ -+static inline void xhci_mtk_free_resources(struct platform_device *pdev, struct xhci_hcd *xhci) -+{} -+ -+#endif -+ -+#endif /* __LINUX_XHCI_MTK_V2_H */ -diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c -index 771836a..07a5388 100644 ---- a/drivers/usb/host/xhci-plat.c -+++ b/drivers/usb/host/xhci-plat.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -23,8 +24,10 @@ - #include - - #include "xhci.h" -+#include "xhci-dbgcap.h" - #include "xhci-plat.h" - #include "xhci-mvebu.h" -+#include "xhci-mtk-v2.h" - - static struct hc_driver __read_mostly xhci_plat_hc_driver; - -@@ -97,7 +100,6 @@ static int xhci_plat_setup(struct usb_hcd *hcd) - { - int ret; - -- - ret = xhci_priv_init_quirk(hcd); - if (ret) - return ret; -@@ -164,6 +166,8 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - int irq; - struct xhci_plat_priv *priv = NULL; - const struct of_device_id *of_match; -+ bool mtk_hw_prepared = false; -+ int wakeup_irq = -1; - - if (usb_disabled()) - return -ENODEV; -@@ -246,6 +250,26 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - *priv = *priv_match; - } - -+ if (priv && priv->is_mtk_v2) { -+ -+ wakeup_irq = platform_get_irq_optional(pdev, 1); -+ if (wakeup_irq == -EPROBE_DEFER) { -+ ret = wakeup_irq; -+ goto disable_clk; -+ } -+ -+ ret = xhci_mtk_get_resources(pdev, xhci); -+ if (ret) -+ goto disable_clk; -+ -+ ret = xhci_mtk_prepare_hw(xhci); -+ if (ret) { -+ goto free_rscs; -+ } -+ -+ mtk_hw_prepared = true; -+ } -+ - device_set_wakeup_capable(&pdev->dev, true); - - xhci->main_hcd = hcd; -@@ -296,12 +320,12 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - if (IS_ERR(hcd->usb_phy)) { - ret = PTR_ERR(hcd->usb_phy); - if (ret == -EPROBE_DEFER) -- goto disable_clk; -+ goto free_rscs; - hcd->usb_phy = NULL; - } else { - ret = usb_phy_init(hcd->usb_phy); - if (ret) -- goto disable_clk; -+ goto free_rscs; - } - } - -@@ -355,6 +379,15 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - goto put_usb3_hcd; - } - -+ if (wakeup_irq > 0) { -+ ret = dev_pm_set_dedicated_wake_irq_reverse(&pdev->dev, wakeup_irq); -+ if (ret) { -+ dev_err(&pdev->dev, "set wakeup irq %d failed\n", wakeup_irq); -+ goto dealloc_usb3_hcd; -+ } -+ dev_info(&pdev->dev, "wakeup irq %d\n", wakeup_irq); -+ } -+ - device_enable_async_suspend(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - -@@ -363,9 +396,20 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s - * runtime pm using power/control in sysfs. - */ - pm_runtime_forbid(&pdev->dev); -+ if (priv && priv->is_mtk_v2) { -+ /* -+ * Runtime PM is unsupported until Power Wrap can report an -+ * authoritative final state after a transition failure. Keep -+ * system sleep enabled, but prevent userspace from enabling the -+ * unsafe runtime suspend path through power/control. -+ */ -+ pm_runtime_disable(&pdev->dev); -+ } - - return 0; - -+dealloc_usb3_hcd: -+ usb_remove_hcd(xhci->shared_hcd); - - put_usb3_hcd: - usb_put_hcd(xhci->shared_hcd); -@@ -376,6 +420,12 @@ dealloc_usb2_hcd: - disable_usb_phy: - usb_phy_shutdown(hcd->usb_phy); - -+free_rscs: -+ if (mtk_hw_prepared) -+ xhci_mtk_release_hw(xhci, true); -+ if (priv && priv->is_mtk_v2) -+ xhci_mtk_free_resources(pdev, xhci); -+ - disable_clk: - clk_disable_unprepare(xhci->clk); - -@@ -427,14 +477,46 @@ static int xhci_generic_plat_probe(struct platform_device *pdev) - return ret; - } - -- if (pdev->dev.of_node) -- priv_match = of_device_get_match_data(&pdev->dev); -- else -+ priv_match = device_get_match_data(&pdev->dev); -+ if (!priv_match) - priv_match = dev_get_platdata(&pdev->dev); - - return xhci_plat_probe(pdev, sysdev, priv_match); - } - -+static void xhci_plat_hc_died(struct xhci_hcd *xhci, bool hw_accessible) -+{ -+ struct usb_hcd *hcd = xhci_to_hcd(xhci); -+ -+ /* -+ * Make the host dead and update accessibility under the same lock. This -+ * keeps unlink and timeout paths from touching registers while an IRQ -+ * which passed usb_hcd_irq()'s accessibility check is synchronized. -+ */ -+ spin_lock_irq(&xhci->lock); -+ if (hw_accessible) { -+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); -+ if (xhci->shared_hcd) -+ set_bit(HCD_FLAG_HW_ACCESSIBLE, -+ &xhci->shared_hcd->flags); -+ } else { -+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); -+ if (xhci->shared_hcd) -+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, -+ &xhci->shared_hcd->flags); -+ } -+ xhci_hc_died(xhci); -+ spin_unlock_irq(&xhci->lock); -+ -+ if (hcd->irq > 0) -+ synchronize_irq(hcd->irq); -+ -+ /* A dead host must not leave DbC work or register sysfs files live. */ -+ mutex_lock(&xhci->mutex); -+ xhci_remove_dbc_dev(xhci, hw_accessible); -+ mutex_unlock(&xhci->mutex); -+} -+ - void xhci_plat_remove(struct platform_device *dev) - { - struct usb_hcd *hcd = platform_get_drvdata(dev); -@@ -442,28 +524,59 @@ void xhci_plat_remove(struct platform_device *dev) - struct clk *clk = xhci->clk; - struct clk *reg_clk = xhci->reg_clk; - struct usb_hcd *shared_hcd = xhci->shared_hcd; -+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); -+ bool mtk_hw_accessible = true; -+ bool mtk_host_suspended = false; -+ int ret; - - xhci->xhc_state |= XHCI_STATE_REMOVING; - pm_runtime_get_sync(&dev->dev); -+ if (priv->is_mtk_v2) { -+ mtk_hw_accessible = HCD_HW_ACCESSIBLE(hcd); -+ if (!mtk_hw_accessible) { -+ mtk_host_suspended = true; -+ ret = xhci_mtk_exit_lps(xhci); -+ if (ret) { -+ dev_warn(&dev->dev, -+ "failed to recover D0 for removal (%d)\n", -+ ret); -+ } else { -+ mtk_hw_accessible = true; -+ } -+ } -+ if (mtk_host_suspended) -+ xhci_plat_hc_died(xhci, mtk_hw_accessible); -+ } -+ -+ if (priv->is_mtk_v2) -+ dev_pm_clear_wake_irq(&dev->dev); - - if (shared_hcd) { - usb_remove_hcd(shared_hcd); - xhci->shared_hcd = NULL; - } - -- usb_phy_shutdown(hcd->usb_phy); -+ if (!priv->is_mtk_v2 || mtk_hw_accessible) -+ usb_phy_shutdown(hcd->usb_phy); - - usb_remove_hcd(hcd); - - if (shared_hcd) - usb_put_hcd(shared_hcd); - -+ if (priv->is_mtk_v2) { -+ xhci_mtk_release_hw(xhci, mtk_hw_accessible); -+ xhci_mtk_free_resources(dev, xhci); -+ } -+ - clk_disable_unprepare(clk); - clk_disable_unprepare(reg_clk); - reset_control_assert(xhci->reset); -+ - usb_put_hcd(hcd); - -- pm_runtime_disable(&dev->dev); -+ if (pm_runtime_enabled(&dev->dev)) -+ pm_runtime_disable(&dev->dev); - pm_runtime_put_noidle(&dev->dev); - pm_runtime_set_suspended(&dev->dev); - } -@@ -473,10 +586,16 @@ static int xhci_plat_suspend_common(struct device *dev) - { - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct xhci_hcd *xhci = hcd_to_xhci(hcd); -- int ret; -+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); -+ int ret, rollback_ret; - -- if (pm_runtime_suspended(dev)) -- pm_runtime_resume(dev); -+ if (pm_runtime_suspended(dev)) { -+ ret = pm_runtime_resume(dev); -+ if (ret < 0) -+ return ret; -+ } -+ if (priv->is_mtk_v2 && !HCD_HW_ACCESSIBLE(hcd)) -+ return -ESHUTDOWN; - - ret = xhci_priv_suspend_quirk(hcd); - if (ret) -@@ -489,6 +608,19 @@ static int xhci_plat_suspend_common(struct device *dev) - if (ret) - return ret; - -+ if (priv->is_mtk_v2) { -+ ret = xhci_mtk_enter_lps(xhci); -+ if (ret) { -+ rollback_ret = xhci_resume(xhci, false, false); -+ if (rollback_ret) { -+ xhci_plat_hc_died(xhci, true); -+ dev_err(dev, "failed to roll back xHCI suspend (%d)\n", -+ rollback_ret); -+ } -+ return ret; -+ } -+ } -+ - if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { - clk_disable_unprepare(xhci->clk); - clk_disable_unprepare(xhci->reg_clk); -@@ -535,24 +667,45 @@ static int xhci_plat_resume_common(struct device *dev, bool power_lost) - } - } - -+ if (priv->is_mtk_v2) { -+ ret = xhci_mtk_exit_lps(xhci); -+ if (ret) -+ goto hc_inaccessible; -+ } -+ -+ /* -+ * System PM clears its suspended bookkeeping before invoking this -+ * callback and does not restore it on error. Once the platform low-power -+ * exit succeeds, do not re-enter low power on later errors because -+ * subsequent callbacks may access the host registers. -+ */ - ret = xhci_priv_resume_quirk(hcd); - if (ret) - goto disable_clks; - - ret = xhci_resume(xhci, power_lost || priv->power_lost, false); -- if (ret) -+ if (ret) { -+ if (priv->is_mtk_v2) -+ xhci_plat_hc_died(xhci, true); - goto disable_clks; -+ } - - ret = xhci_priv_post_resume_quirk(hcd); - if (ret) - goto disable_clks; - -- pm_runtime_disable(dev); -- pm_runtime_set_active(dev); -- pm_runtime_enable(dev); -+ if (priv->is_mtk_v2) { -+ pm_runtime_set_active(dev); -+ } else { -+ pm_runtime_disable(dev); -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ } - - return 0; - -+hc_inaccessible: -+ xhci_plat_hc_died(xhci, false); - disable_clks: - if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { - clk_disable_unprepare(xhci->clk); -@@ -590,19 +743,31 @@ static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev) - { - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct xhci_hcd *xhci = hcd_to_xhci(hcd); -+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); - int ret; - -+ if (priv->is_mtk_v2) -+ return -EOPNOTSUPP; -+ - ret = xhci_priv_suspend_quirk(hcd); - if (ret) - return ret; - -- return xhci_suspend(xhci, true); -+ ret = xhci_suspend(xhci, true); -+ if (ret) -+ return ret; -+ -+ return 0; - } - - static int __maybe_unused xhci_plat_runtime_resume(struct device *dev) - { - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct xhci_hcd *xhci = hcd_to_xhci(hcd); -+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); -+ -+ if (priv->is_mtk_v2) -+ return -EOPNOTSUPP; - - return xhci_resume(xhci, false, true); - } -@@ -622,9 +787,19 @@ const struct dev_pm_ops xhci_plat_pm_ops = { - EXPORT_SYMBOL_GPL(xhci_plat_pm_ops); - - #ifdef CONFIG_ACPI -+#if IS_ENABLED(CONFIG_USB_XHCI_MTK_V2) -+static const struct xhci_plat_priv xhci_plat_mtk_v2 = { -+ .is_mtk_v2 = 1, -+}; -+#endif -+ - static const struct acpi_device_id usb_xhci_acpi_match[] = { - /* XHCI-compliant USB Controller */ - { "PNP0D10", }, -+#if IS_ENABLED(CONFIG_USB_XHCI_MTK_V2) -+ { "NVDA8000", (kernel_ulong_t)&xhci_plat_mtk_v2, }, -+ { "NVDA8001", (kernel_ulong_t)&xhci_plat_mtk_v2, }, -+#endif - { "PNP0D15", }, - { } - }; -diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h -index 00751d8..b04308c 100644 ---- a/drivers/usb/host/xhci-plat.h -+++ b/drivers/usb/host/xhci-plat.h -@@ -8,6 +8,8 @@ - #ifndef _XHCI_PLAT_H - #define _XHCI_PLAT_H - -+#include "xhci-mtk-v2.h" -+ - struct device; - struct platform_device; - struct usb_hcd; -@@ -17,11 +19,22 @@ struct xhci_plat_priv { - unsigned long long quirks; - bool power_lost; - unsigned sideband_at_suspend:1; -+ unsigned is_mtk_v2:1; - void (*plat_start)(struct usb_hcd *); - int (*init_quirk)(struct usb_hcd *); - int (*suspend_quirk)(struct usb_hcd *); - int (*resume_quirk)(struct usb_hcd *); - int (*post_resume_quirk)(struct usb_hcd *); -+ struct device *dev; -+ void __iomem *ippc_base; -+ void __iomem *ext_mac_base; -+ void *pwrap_cfg; /* power wrap scmi configuration */ -+ struct acpi_buffer acpi_path; /* ACPI name */ -+ struct usb3_sphy sphy; -+ u64 uid; -+ u32 u2port_cnt; -+ u32 u3port_cnt; -+ u32 u3port_disable_mask; - }; - - #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv) -diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c -index 8908f5c..09d180f 100644 ---- a/drivers/usb/host/xhci-ring.c -+++ b/drivers/usb/host/xhci-ring.c -@@ -1391,8 +1391,8 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, - * URBs need to be given back as usb core might be waiting with device locks - * held for the URBs to finish during device disconnect, blocking host remove. - * -- * Call with xhci->lock held. -- * lock is relased and re-acquired while giving back urb. -+ * Call with xhci->lock held. xHCI uses HCD_BH, so URB completion -+ * callbacks are deferred and the lock remains held while they are queued. - */ - void xhci_hc_died(struct xhci_hcd *xhci) - { -@@ -1421,6 +1421,7 @@ void xhci_hc_died(struct xhci_hcd *xhci) - if (notify) - usb_hc_died(xhci_to_hcd(xhci)); - } -+EXPORT_SYMBOL_GPL(xhci_hc_died); - - /* - * When we get a completion for a Set Transfer Ring Dequeue Pointer command, -@@ -3028,11 +3029,13 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter - else - xhci_warn(xhci, "ERROR unknown event type %d\n", trb_type); - } -- /* Any of the above functions may drop and re-acquire the lock, so check -- * to make sure a watchdog timer didn't mark the host as non-responsive. -+ /* -+ * Any of the above functions may drop and re-acquire the lock. Stop if -+ * suspend or failed recovery made the controller inaccessible meanwhile. - */ -- if (xhci->xhc_state & XHCI_STATE_DYING) { -- xhci_dbg(xhci, "xHCI host dying, returning from event handler.\n"); -+ if (!HCD_HW_ACCESSIBLE(xhci_to_hcd(xhci)) || -+ xhci->xhc_state & XHCI_STATE_DYING) { -+ xhci_dbg(xhci, "xHCI host inaccessible, returning from event handler.\n"); - return -ENODEV; - } - -@@ -3099,6 +3102,9 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir - int err = 0; - u64 temp; - -+ if (!HCD_HW_ACCESSIBLE(xhci_to_hcd(xhci))) -+ return -ENODEV; -+ - xhci_clear_interrupt_pending(ir); - - /* Event ring hasn't been allocated yet. */ -@@ -3111,7 +3117,7 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir - xhci->xhc_state & XHCI_STATE_HALTED) { - xhci_dbg(xhci, "xHCI dying, ignoring interrupt. Shouldn't IRQs be disabled?\n"); - -- /* Clear the event handler busy flag (RW1C) */ -+ /* Clear the event handler busy flag (RW1C). */ - temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); - xhci_write_64(xhci, temp | ERST_EHB, &ir->ir_set->erst_dequeue); - return -ENODEV; -@@ -3121,6 +3127,15 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir - while (unhandled_event_trb(ir->event_ring)) { - if (!skip_events) - err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); -+ if (err) { -+ /* -+ * The event was consumed before the controller became -+ * inaccessible. Advance only the software dequeue pointer; -+ * updating ERDP below would access unavailable hardware. -+ */ -+ inc_deq(xhci, ir->event_ring); -+ return err; -+ } - - /* - * If half a segment of events have been handled in one go then -@@ -3138,8 +3153,6 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir - /* Update SW event ring dequeue pointer */ - inc_deq(xhci, ir->event_ring); - -- if (err) -- break; - } - - xhci_update_erst_dequeue(xhci, ir, true); -@@ -3190,6 +3203,12 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) - u32 status; - - spin_lock(&xhci->lock); -+ /* Recheck after taking the lock to close the accessibility TOCTOU. */ -+ if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) { -+ ret = IRQ_NONE; -+ goto out; -+ } -+ - /* Check if the xHC generated the interrupt, or the irq is shared */ - status = readl(&xhci->op_regs->status); - if (status == ~(u32)0) { -diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c -index 181d4f0..50cbd74 100644 ---- a/drivers/usb/host/xhci.c -+++ b/drivers/usb/host/xhci.c -@@ -690,7 +690,11 @@ void xhci_stop(struct usb_hcd *hcd) - { - u32 temp; - struct xhci_hcd *xhci = hcd_to_xhci(hcd); -- struct xhci_interrupter *ir = xhci->interrupters[0]; -+ struct xhci_interrupter *ir = NULL; -+ bool hw_accessible; -+ -+ if (xhci->interrupters) -+ ir = xhci->interrupters[0]; - - mutex_lock(&xhci->mutex); - -@@ -700,13 +704,18 @@ void xhci_stop(struct usb_hcd *hcd) - return; - } - -- xhci_remove_dbc_dev(xhci); -+ hw_accessible = HCD_HW_ACCESSIBLE(hcd); -+ -+ /* A failed platform resume can leave only software teardown possible. */ -+ xhci_remove_dbc_dev(xhci, hw_accessible); - - spin_lock_irq(&xhci->lock); - xhci->xhc_state |= XHCI_STATE_HALTED; - xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; -- xhci_halt(xhci); -- xhci_reset(xhci, XHCI_RESET_SHORT_USEC); -+ if (hw_accessible) { -+ xhci_halt(xhci); -+ xhci_reset(xhci, XHCI_RESET_SHORT_USEC); -+ } - spin_unlock_irq(&xhci->lock); - - /* Deleting Compliance Mode Recovery Timer */ -@@ -721,18 +730,22 @@ void xhci_stop(struct usb_hcd *hcd) - if (xhci->quirks & XHCI_AMD_PLL_FIX) - usb_amd_dev_put(); - -- xhci_dbg_trace(xhci, trace_xhci_dbg_init, -- "// Disabling event ring interrupts"); -- temp = readl(&xhci->op_regs->status); -- writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status); -- xhci_disable_interrupter(xhci, ir); -+ if (hw_accessible) { -+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, -+ "// Disabling event ring interrupts"); -+ temp = readl(&xhci->op_regs->status); -+ writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status); -+ if (ir) -+ xhci_disable_interrupter(xhci, ir); -+ } - - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory"); - xhci_mem_cleanup(xhci); - xhci_debugfs_exit(xhci); -- xhci_dbg_trace(xhci, trace_xhci_dbg_init, -- "xhci_stop completed - status = %x", -- readl(&xhci->op_regs->status)); -+ if (hw_accessible) -+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, -+ "%s completed - status = %x", __func__, -+ readl(&xhci->op_regs->status)); - mutex_unlock(&xhci->mutex); - } - EXPORT_SYMBOL_GPL(xhci_stop); -@@ -749,8 +762,9 @@ EXPORT_SYMBOL_GPL(xhci_stop); - void xhci_shutdown(struct usb_hcd *hcd) - { - struct xhci_hcd *xhci = hcd_to_xhci(hcd); -+ bool hw_accessible = HCD_HW_ACCESSIBLE(hcd); - -- if (xhci->quirks & XHCI_SPURIOUS_REBOOT) -+ if (hw_accessible && (xhci->quirks & XHCI_SPURIOUS_REBOOT)) - usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev)); - - /* Don't poll the roothubs after shutdown. */ -@@ -764,6 +778,11 @@ void xhci_shutdown(struct usb_hcd *hcd) - timer_delete_sync(&xhci->shared_hcd->rh_timer); - } - -+ if (!hw_accessible) { -+ xhci_dbg(xhci, "skip shutdown of inaccessible hardware\n"); -+ return; -+ } -+ - spin_lock_irq(&xhci->lock); - xhci_halt(xhci); - -@@ -1786,9 +1805,13 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) - if (!ep || !ep_ring) - goto err_giveback; - -+ /* Failed platform recovery marks the host dead and drains its URBs. */ -+ if (xhci->xhc_state & XHCI_STATE_DYING) -+ goto done; -+ - /* If xHC is dead take it down and return ALL URBs in xhci_hc_died() */ - temp = readl(&xhci->op_regs->status); -- if (temp == ~(u32)0 || xhci->xhc_state & XHCI_STATE_DYING) { -+ if (temp == ~(u32)0) { - xhci_hc_died(xhci); - goto done; - } -@@ -4158,10 +4181,15 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) - xhci_debugfs_remove_slot(xhci, slot_id); - - spin_lock_irqsave(&xhci->lock, flags); -- /* Don't disable the slot if the host controller is dead. */ -+ /* Don't disable the slot if the host is inaccessible or dead. */ -+ if (!HCD_HW_ACCESSIBLE(xhci_to_hcd(xhci)) || -+ xhci->xhc_state & (XHCI_STATE_DYING | XHCI_STATE_HALTED)) { -+ spin_unlock_irqrestore(&xhci->lock, flags); -+ xhci_free_command(xhci, command); -+ return -ENODEV; -+ } - state = readl(&xhci->op_regs->status); -- if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || -- (xhci->xhc_state & XHCI_STATE_HALTED)) { -+ if (state == 0xffffffff) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_free_command(xhci, command); - return -ENODEV; -@@ -4673,6 +4701,9 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, - int hird, exit_latency; - int ret; - -+ if (!HCD_HW_ACCESSIBLE(hcd)) -+ return -ESHUTDOWN; -+ - if (xhci->quirks & XHCI_HW_LPM_DISABLE) - return -EPERM; - -@@ -5579,6 +5610,7 @@ static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd, - { - struct xhci_hcd *xhci; - struct usb_device *udev; -+ struct xhci_virt_device *vdev; - unsigned int slot_id; - unsigned int ep_index; - unsigned long flags; -@@ -5589,9 +5621,17 @@ static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd, - udev = (struct usb_device *)ep->hcpriv; - slot_id = udev->slot_id; - ep_index = xhci_get_endpoint_index(&ep->desc); -+ vdev = xhci->devs[slot_id]; - -- xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_CLEARING_TT; -- xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -+ if (!vdev) -+ goto out; -+ -+ vdev->eps[ep_index].ep_state &= ~EP_CLEARING_TT; -+ if (HCD_HW_ACCESSIBLE(hcd) && -+ !(xhci->xhc_state & XHCI_STATE_DYING)) -+ xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -+ -+out: - spin_unlock_irqrestore(&xhci->lock, flags); - } - --- -2.56.0 - diff --git a/kernel/1093-usb-xhci-add-XHCI_DELAY_BEFORE_CRS-quirk-for-MediaTek-v2.patch b/kernel/1093-usb-xhci-add-XHCI_DELAY_BEFORE_CRS-quirk-for-MediaTek-v2.patch deleted file mode 100644 index 6a9deed..0000000 --- a/kernel/1093-usb-xhci-add-XHCI_DELAY_BEFORE_CRS-quirk-for-MediaTek-v2.patch +++ /dev/null @@ -1,74 +0,0 @@ -From a9ff24715a98cd2080309a0afc98aac49ae13309 Mon Sep 17 00:00:00 2001 -From: xin lin -Date: Wed, 9 Sep 2026 15:26:23 +0800 -Subject: [PATCH 4/6] NVIDIA: SAUCE: usb: xhci: add XHCI_DELAY_BEFORE_CRS quirk - for MediaTek v2 - -BugLink: https://bugs.launchpad.net/bugs/2167884 - -xhci_restore_registers() triggers asynchronous DRAM reads during resume. -On MediaTek v2 platforms, the Controller Restore State operation can start -before those reads complete, causing the controller to time out while -restoring its state. - -Add XHCI_DELAY_BEFORE_CRS and insert a 2 ms delay in xhci_resume() between -register restoration and the CRS write. Enable the quirk only for the -MediaTek v2 platform so other controllers do not pay the delay. - -Signed-off-by: xin lin -Signed-off-by: Bharat Dintakurti -Acked-by: Emily Soto -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/usb/host/xhci-plat.c | 1 + - drivers/usb/host/xhci.c | 7 +++++++ - drivers/usb/host/xhci.h | 1 + - 3 files changed, 9 insertions(+) - -diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c -index 07a5388..7316315 100644 ---- a/drivers/usb/host/xhci-plat.c -+++ b/drivers/usb/host/xhci-plat.c -@@ -789,6 +789,7 @@ EXPORT_SYMBOL_GPL(xhci_plat_pm_ops); - #ifdef CONFIG_ACPI - #if IS_ENABLED(CONFIG_USB_XHCI_MTK_V2) - static const struct xhci_plat_priv xhci_plat_mtk_v2 = { -+ .quirks = XHCI_DELAY_BEFORE_CRS, - .is_mtk_v2 = 1, - }; - #endif -diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c -index 50cbd74..5552d71 100644 ---- a/drivers/usb/host/xhci.c -+++ b/drivers/usb/host/xhci.c -@@ -1142,6 +1142,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume) - xhci_restore_registers(xhci); - /* step 2: initialize command ring buffer */ - xhci_set_cmd_ring_deq(xhci); -+ if (xhci->quirks & XHCI_DELAY_BEFORE_CRS) { -+ /* -+ * Allow DRAM reads triggered by register restoration to -+ * complete before setting CRS. -+ */ -+ mdelay(2); -+ } - /* step 3: restore state and start state*/ - /* step 3: set CRS flag */ - command = readl(&xhci->op_regs->command); -diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h -index 3915f33..9ebc6e9 100644 ---- a/drivers/usb/host/xhci.h -+++ b/drivers/usb/host/xhci.h -@@ -1649,6 +1649,7 @@ struct xhci_hcd { - #define XHCI_ETRON_HOST BIT_ULL(49) - #define XHCI_LIMIT_ENDPOINT_INTERVAL_9 BIT_ULL(50) - #define XHCI_NVIDIA_MT8901_HOST BIT_ULL(51) -+#define XHCI_DELAY_BEFORE_CRS BIT_ULL(52) - - unsigned int num_active_eps; - unsigned int limit_active_eps; --- -2.56.0 - diff --git a/kernel/1094-spi-mt65xx-enable-ACPI-and-power-management.patch b/kernel/1094-spi-mt65xx-enable-ACPI-and-power-management.patch deleted file mode 100644 index e4b2ca4..0000000 --- a/kernel/1094-spi-mt65xx-enable-ACPI-and-power-management.patch +++ /dev/null @@ -1,689 +0,0 @@ -From 157172df1a685ea33c3a51e0d7c9330033d914d4 Mon Sep 17 00:00:00 2001 -From: srinivasareddy dasari -Date: Wed, 24 Jun 2026 15:03:08 +0800 -Subject: [PATCH 5/6] NVIDIA: SAUCE: spi: mt65xx: enable ACPI and power - management - -BugLink: https://bugs.launchpad.net/bugs/2167886 - -Add ACPI support for NVDA0210 controllers and skip DT-only clock, -pad-selection, and property handling on ACPI systems. - -Integrate Power Wrap for controller power control and add runtime and -system suspend/resume callbacks. Schedule autosuspend after successful -controller registration. - -Treat failed Power Wrap suspend requests as ambiguous. Recover D0 -immediately, keep runtime PM active only after D0 and clocks are restored, -and otherwise leave the device suspended so the next resume retries before -hardware access. Retry failed noirq rollback from regular system resume. - -Balance probe/remove and clock error paths, use ACPI_FREE() for ACPI paths, -and retain internal linkage for the local nbit helper. - -Signed-off-by: srinivasareddy dasari -Signed-off-by: Bharat Dintakurti -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/spi/spi-mt65xx.c | 447 ++++++++++++++++++++++++++++++++------- - 1 file changed, 374 insertions(+), 73 deletions(-) - -diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c -index 96f8555..5a48c1b 100644 ---- a/drivers/spi/spi-mt65xx.c -+++ b/drivers/spi/spi-mt65xx.c -@@ -4,6 +4,7 @@ - * Author: Leilk Liu - */ - -+#include - #include - #include - #include -@@ -17,10 +18,15 @@ - #include - #include - #include -+#include - #include - #include - #include - #include -+#include -+ -+#define MTK_SPI_CLK_FREQ_DEFAULT 52000000 /* 52 MHz default SPI clock */ -+#define MTK_SPI_AUTOSUSPEND_DELAY_MS 100 - - #define SPI_CFG0_REG 0x0000 - #define SPI_CFG1_REG 0x0004 -@@ -155,6 +161,10 @@ struct mtk_spi_compatible { - * @dev: Device pointer - * @tx_dma: DMA start for SPI-MEM TX - * @rx_dma: DMA start for SPI-MEM RX -+ * @pwrap_ctrl: Power Wrap control data for ACPI-enumerated controllers -+ * @power_state: True only when Power Wrap has confirmed controller D0 -+ * @pwrap_state_unknown: A D-state request failed without confirmed recovery -+ * @d3_retry_used: Automatic D3 retry used for this idle period - */ - struct mtk_spi { - void __iomem *base; -@@ -175,6 +185,10 @@ struct mtk_spi { - struct device *dev; - dma_addr_t tx_dma; - dma_addr_t rx_dma; -+ void *pwrap_ctrl; -+ bool power_state; -+ bool pwrap_state_unknown; -+ bool d3_retry_used; - }; - - static const struct mtk_spi_compatible mtk_common_compat; -@@ -281,6 +295,12 @@ static const struct of_device_id mtk_spi_of_match[] = { - }; - MODULE_DEVICE_TABLE(of, mtk_spi_of_match); - -+static const struct acpi_device_id mtk_spi_acpi_match[] = { -+ { "NVDA0210", (kernel_ulong_t)&mtk_ipm_compat }, -+ {} -+}; -+MODULE_DEVICE_TABLE(acpi, mtk_spi_acpi_match); -+ - static void mtk_spi_reset(struct mtk_spi *mdata) - { - u32 reg_val; -@@ -471,6 +491,12 @@ static int mtk_spi_hw_init(struct spi_controller *host, - static int mtk_spi_prepare_message(struct spi_controller *host, - struct spi_message *msg) - { -+ struct mtk_spi *mdata = spi_controller_get_devdata(host); -+ -+ if (mdata->pwrap_state_unknown) -+ return -EIO; -+ -+ mdata->d3_retry_used = false; - return mtk_spi_hw_init(host, msg->spi); - } - -@@ -563,7 +589,7 @@ static void mtk_spi_setup_packet(struct spi_controller *host) - writel(reg_val, mdata->base + SPI_CFG1_REG); - } - --inline u32 mtk_spi_set_nbit(u32 nbit) -+static inline u32 mtk_spi_set_nbit(u32 nbit) - { - switch (nbit) { - default: -@@ -1002,6 +1028,10 @@ static int mtk_spi_mem_exec_op(struct spi_mem *mem, - char *tx_tmp_buf, *rx_tmp_buf; - int ret = 0; - -+ if (mdata->pwrap_state_unknown) -+ return -EIO; -+ -+ mdata->d3_retry_used = false; - mdata->use_spimem = true; - reinit_completion(&mdata->spimem_done); - -@@ -1172,12 +1202,134 @@ static const struct spi_controller_mem_caps mtk_spi_mem_caps = { - .per_op_freq = true, - }; - -+static int mtk_spi_init_pad_sel(struct device *dev, struct mtk_spi *mdata) -+{ -+ int i; -+ -+ mdata->pad_num = of_property_count_u32_elems(dev->of_node, -+ "mediatek,pad-select"); -+ if (mdata->pad_num < 0) -+ return dev_err_probe(dev, -EINVAL, -+ "No 'mediatek,pad-select' property\n"); -+ -+ mdata->pad_sel = devm_kmalloc_array(dev, mdata->pad_num, -+ sizeof(u32), GFP_KERNEL); -+ if (!mdata->pad_sel) -+ return -ENOMEM; -+ -+ for (i = 0; i < mdata->pad_num; i++) { -+ of_property_read_u32_index(dev->of_node, -+ "mediatek,pad-select", -+ i, &mdata->pad_sel[i]); -+ if (mdata->pad_sel[i] > MT8173_SPI_MAX_PAD_SEL) -+ return dev_err_probe(dev, -EINVAL, -+ "wrong pad-sel[%d]: %u\n", -+ i, mdata->pad_sel[i]); -+ } -+ return 0; -+} -+ -+static int mtk_spi_init_clocks_of(struct device *dev, struct mtk_spi *mdata) -+{ -+ int ret; -+ -+ mdata->parent_clk = devm_clk_get(dev, "parent-clk"); -+ if (IS_ERR(mdata->parent_clk)) -+ return dev_err_probe(dev, PTR_ERR(mdata->parent_clk), -+ "failed to get parent-clk\n"); -+ -+ mdata->sel_clk = devm_clk_get(dev, "sel-clk"); -+ if (IS_ERR(mdata->sel_clk)) -+ return dev_err_probe(dev, PTR_ERR(mdata->sel_clk), -+ "failed to get sel-clk\n"); -+ -+ mdata->spi_clk = devm_clk_get(dev, "spi-clk"); -+ if (IS_ERR(mdata->spi_clk)) -+ return dev_err_probe(dev, PTR_ERR(mdata->spi_clk), -+ "failed to get spi-clk\n"); -+ -+ mdata->spi_hclk = devm_clk_get_optional(dev, "hclk"); -+ if (IS_ERR(mdata->spi_hclk)) -+ return dev_err_probe(dev, PTR_ERR(mdata->spi_hclk), -+ "failed to get hclk\n"); -+ -+ ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "failed to clk_set_parent\n"); -+ -+ ret = clk_prepare_enable(mdata->spi_hclk); -+ if (ret < 0) -+ return dev_err_probe(dev, ret, "failed to enable hclk\n"); -+ -+ ret = clk_prepare_enable(mdata->spi_clk); -+ if (ret < 0) { -+ clk_disable_unprepare(mdata->spi_hclk); -+ return dev_err_probe(dev, ret, "failed to enable spi_clk\n"); -+ } -+ -+ mdata->spi_clk_hz = clk_get_rate(mdata->spi_clk); -+ -+ if (mdata->dev_comp->no_need_unprepare) { -+ clk_disable(mdata->spi_clk); -+ clk_disable(mdata->spi_hclk); -+ } else { -+ clk_disable_unprepare(mdata->spi_clk); -+ clk_disable_unprepare(mdata->spi_hclk); -+ } -+ -+ return 0; -+} -+ -+#ifdef CONFIG_ACPI -+static int mtk_spi_init_clocks_acpi(struct device *dev, struct mtk_spi *mdata) -+{ -+ struct acpi_device *adev = ACPI_COMPANION(dev); -+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ const char *path; -+ int ret; -+ -+ if (!adev) -+ return -ENODEV; -+ -+ if (device_property_read_u32(dev, "clock-frequency", -+ &mdata->spi_clk_hz)) -+ mdata->spi_clk_hz = MTK_SPI_CLK_FREQ_DEFAULT; -+ -+ status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &buffer); -+ if (ACPI_FAILURE(status)) -+ return dev_err_probe(dev, -EINVAL, "failed to get ACPI path\n"); -+ path = buffer.pointer; -+ -+ mdata->pwrap_ctrl = mtk_pwrap_dev_probe(path); -+ if (!mdata->pwrap_ctrl) { -+ ret = dev_err_probe(dev, -ENODEV, -+ "pwrap probe failed for %s\n", path); -+ goto out_free; -+ } -+ -+ mdata->power_state = true; -+ ret = 0; -+ -+out_free: -+ ACPI_FREE(buffer.pointer); -+ return ret; -+} -+#else -+static int mtk_spi_init_clocks_acpi(struct device *dev, struct mtk_spi *mdata) -+{ -+ return -ENODEV; -+} -+#endif -+ - static int mtk_spi_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; - struct spi_controller *host; - struct mtk_spi *mdata; -- int i, irq, ret, addr_bits; -+ int irq, ret, addr_bits; -+ bool has_of = dev->of_node != NULL; -+ bool has_acpi = has_acpi_companion(dev); - - host = devm_spi_alloc_host(dev, sizeof(*mdata)); - if (!host) -@@ -1214,27 +1366,10 @@ static int mtk_spi_probe(struct platform_device *pdev) - init_completion(&mdata->spimem_done); - } - -- if (mdata->dev_comp->need_pad_sel) { -- mdata->pad_num = of_property_count_u32_elems(dev->of_node, -- "mediatek,pad-select"); -- if (mdata->pad_num < 0) -- return dev_err_probe(dev, -EINVAL, -- "No 'mediatek,pad-select' property\n"); -- -- mdata->pad_sel = devm_kmalloc_array(dev, mdata->pad_num, -- sizeof(u32), GFP_KERNEL); -- if (!mdata->pad_sel) -- return -ENOMEM; -- -- for (i = 0; i < mdata->pad_num; i++) { -- of_property_read_u32_index(dev->of_node, -- "mediatek,pad-select", -- i, &mdata->pad_sel[i]); -- if (mdata->pad_sel[i] > MT8173_SPI_MAX_PAD_SEL) -- return dev_err_probe(dev, -EINVAL, -- "wrong pad-sel[%d]: %u\n", -- i, mdata->pad_sel[i]); -- } -+ if (mdata->dev_comp->need_pad_sel && has_of) { -+ ret = mtk_spi_init_pad_sel(dev, mdata); -+ if (ret) -+ return ret; - } - - platform_set_drvdata(pdev, host); -@@ -1254,58 +1389,32 @@ static int mtk_spi_probe(struct platform_device *pdev) - else - dma_set_max_seg_size(dev, SZ_256K); - -- mdata->parent_clk = devm_clk_get(dev, "parent-clk"); -- if (IS_ERR(mdata->parent_clk)) -- return dev_err_probe(dev, PTR_ERR(mdata->parent_clk), -- "failed to get parent-clk\n"); -- -- mdata->sel_clk = devm_clk_get(dev, "sel-clk"); -- if (IS_ERR(mdata->sel_clk)) -- return dev_err_probe(dev, PTR_ERR(mdata->sel_clk), "failed to get sel-clk\n"); -- -- mdata->spi_clk = devm_clk_get(dev, "spi-clk"); -- if (IS_ERR(mdata->spi_clk)) -- return dev_err_probe(dev, PTR_ERR(mdata->spi_clk), "failed to get spi-clk\n"); -- -- mdata->spi_hclk = devm_clk_get_optional(dev, "hclk"); -- if (IS_ERR(mdata->spi_hclk)) -- return dev_err_probe(dev, PTR_ERR(mdata->spi_hclk), "failed to get hclk\n"); -- -- ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk); -- if (ret < 0) -- return dev_err_probe(dev, ret, "failed to clk_set_parent\n"); -- -- ret = clk_prepare_enable(mdata->spi_hclk); -- if (ret < 0) -- return dev_err_probe(dev, ret, "failed to enable hclk\n"); -- -- ret = clk_prepare_enable(mdata->spi_clk); -- if (ret < 0) { -- clk_disable_unprepare(mdata->spi_hclk); -- return dev_err_probe(dev, ret, "failed to enable spi_clk\n"); -- } -- -- mdata->spi_clk_hz = clk_get_rate(mdata->spi_clk); -- -- if (mdata->dev_comp->no_need_unprepare) { -- clk_disable(mdata->spi_clk); -- clk_disable(mdata->spi_hclk); -+ if (has_of) { -+ ret = mtk_spi_init_clocks_of(dev, mdata); -+ } else if (has_acpi) { -+ /* ACPI: clocks are managed by firmware via SSPM/SCMI */ -+ ret = mtk_spi_init_clocks_acpi(dev, mdata); - } else { -- clk_disable_unprepare(mdata->spi_clk); -- clk_disable_unprepare(mdata->spi_hclk); -+ return dev_err_probe(dev, -ENODEV, "no OF or ACPI node\n"); - } -+ if (ret) -+ return ret; - - cpu_latency_qos_add_request(&mdata->qos_request, PM_QOS_DEFAULT_VALUE); - -- if (mdata->dev_comp->need_pad_sel) { -- if (mdata->pad_num != host->num_chipselect) -- return dev_err_probe(dev, -EINVAL, -+ if (mdata->dev_comp->need_pad_sel && has_of) { -+ if (mdata->pad_num != host->num_chipselect) { -+ ret = dev_err_probe(dev, -EINVAL, - "pad_num does not match num_chipselect(%d != %d)\n", - mdata->pad_num, host->num_chipselect); -+ goto err_cleanup; -+ } - -- if (!host->cs_gpiods && host->num_chipselect > 1) -- return dev_err_probe(dev, -EINVAL, -+ if (!host->cs_gpiods && host->num_chipselect > 1) { -+ ret = dev_err_probe(dev, -EINVAL, - "cs_gpios not specified and num_chipselect > 1\n"); -+ goto err_cleanup; -+ } - } - - if (mdata->dev_comp->dma_ext) -@@ -1320,18 +1429,51 @@ static int mtk_spi_probe(struct platform_device *pdev) - ret = devm_request_threaded_irq(dev, irq, mtk_spi_interrupt, - mtk_spi_interrupt_thread, - IRQF_ONESHOT, dev_name(dev), host); -- if (ret) -- return dev_err_probe(dev, ret, "failed to register irq\n"); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to register irq\n"); -+ goto err_cleanup; -+ } - -+ /* -+ * ACPI: the pwrap is powered on in probe and the clk pointers are -+ * NULL, so the controller is genuinely active here. On the DT path -+ * the clocks are disabled at the end of mtk_spi_init_clocks_of(), so -+ * declaring the device active would skip the first runtime_resume and -+ * run transfers against gated clocks. Only mark active for ACPI. -+ */ -+ if (has_acpi) { -+ ret = pm_runtime_set_active(dev); -+ if (ret) { -+ dev_err_probe(dev, ret, "failed to set runtime active\n"); -+ goto err_cleanup; -+ } -+ /* Configure autosuspend before runtime PM can idle the controller. */ -+ pm_runtime_set_autosuspend_delay(dev, MTK_SPI_AUTOSUSPEND_DELAY_MS); -+ pm_runtime_use_autosuspend(dev); -+ } - pm_runtime_enable(dev); - - ret = spi_register_controller(host); - if (ret) { - pm_runtime_disable(dev); -- return dev_err_probe(dev, ret, "failed to register host\n"); -+ if (has_acpi) -+ pm_runtime_dont_use_autosuspend(dev); -+ dev_err_probe(dev, ret, "failed to register host\n"); -+ goto err_cleanup; - } -+ if (has_acpi) -+ pm_request_autosuspend(dev); - - return 0; -+ -+err_cleanup: -+ cpu_latency_qos_remove_request(&mdata->qos_request); -+ if (has_acpi && mdata->pwrap_ctrl) { -+ mtk_pwrap_dev_remove(mdata->pwrap_ctrl); -+ mdata->pwrap_ctrl = NULL; -+ mdata->power_state = false; -+ } -+ return ret; - } - - static void mtk_spi_remove(struct platform_device *pdev) -@@ -1349,6 +1491,9 @@ static void mtk_spi_remove(struct platform_device *pdev) - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - dev_warn(&pdev->dev, "Failed to resume hardware (%pe)\n", ERR_PTR(ret)); -+ } else if (has_acpi_companion(&pdev->dev) && !mdata->power_state) { -+ dev_warn(&pdev->dev, -+ "power state unconfirmed, skipping hardware reset\n"); - } else { - /* - * If pm runtime resume failed, clks are disabled and -@@ -1363,17 +1508,50 @@ static void mtk_spi_remove(struct platform_device *pdev) - } - } - -+ if (has_acpi_companion(&pdev->dev) && mdata->pwrap_ctrl) { -+ mtk_pwrap_dev_remove(mdata->pwrap_ctrl); -+ mdata->pwrap_ctrl = NULL; -+ mdata->power_state = false; -+ } -+ - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_disable(&pdev->dev); -+ if (has_acpi_companion(&pdev->dev)) -+ pm_runtime_dont_use_autosuspend(&pdev->dev); - } - - #ifdef CONFIG_PM_SLEEP -+static int mtk_spi_pwrap_resume(struct device *dev, struct mtk_spi *mdata) -+{ -+ int ret; -+ -+ if (!has_acpi_companion(dev) || !mdata->pwrap_ctrl || -+ mdata->power_state) -+ return 0; -+ -+ ret = mtk_pwrap_dev_resume(mdata->pwrap_ctrl, 0); -+ if (ret) { -+ mdata->pwrap_state_unknown = true; -+ return ret; -+ } -+ -+ mdata->power_state = true; -+ mdata->pwrap_state_unknown = false; -+ return 0; -+} -+ - static int mtk_spi_suspend(struct device *dev) - { - int ret; - struct spi_controller *host = dev_get_drvdata(dev); - struct mtk_spi *mdata = spi_controller_get_devdata(host); - -+ /* Do not skip D3 after a previous failed D-state recovery. */ -+ if (mdata->pwrap_state_unknown) { -+ dev_err(dev, "pwrap state unconfirmed, aborting suspend\n"); -+ return -EIO; -+ } -+ - ret = spi_controller_suspend(host); - if (ret) - return ret; -@@ -1383,18 +1561,35 @@ static int mtk_spi_suspend(struct device *dev) - clk_disable_unprepare(mdata->spi_hclk); - } - -- pinctrl_pm_select_sleep_state(dev); -+ if (dev->of_node) -+ pinctrl_pm_select_sleep_state(dev); - - return 0; - } - - static int mtk_spi_resume(struct device *dev) - { -+ bool clocks_enabled = false; - int ret; - struct spi_controller *host = dev_get_drvdata(dev); - struct mtk_spi *mdata = spi_controller_get_devdata(host); - -- pinctrl_pm_select_default_state(dev); -+ /* -+ * A failed noirq D3 request may still have reached firmware. The PM -+ * core skips ->resume_noirq() for the device whose ->suspend_noirq() -+ * failed, so confirm D0 here before enabling clocks or reopening the -+ * SPI queue. -+ */ -+ if (!pm_runtime_suspended(dev)) { -+ ret = mtk_spi_pwrap_resume(dev, mdata); -+ if (ret) { -+ dev_err(dev, "pwrap resume recovery failed (%d)\n", ret); -+ return ret; -+ } -+ } -+ -+ if (dev->of_node) -+ pinctrl_pm_select_default_state(dev); - - if (!pm_runtime_suspended(dev)) { - ret = clk_prepare_enable(mdata->spi_clk); -@@ -1409,23 +1604,81 @@ static int mtk_spi_resume(struct device *dev) - clk_disable_unprepare(mdata->spi_clk); - return ret; - } -+ clocks_enabled = true; - } - - ret = spi_controller_resume(host); -- if (ret < 0) { -- clk_disable_unprepare(mdata->spi_clk); -+ if (ret < 0 && clocks_enabled) { - clk_disable_unprepare(mdata->spi_hclk); -+ clk_disable_unprepare(mdata->spi_clk); - } - - return ret; - } -+ -+static int mtk_spi_suspend_noirq(struct device *dev) -+{ -+ struct spi_controller *host = dev_get_drvdata(dev); -+ struct mtk_spi *mdata = spi_controller_get_devdata(host); -+ int ret, rollback_ret; -+ -+ if (has_acpi_companion(dev) && mdata->pwrap_ctrl && mdata->power_state) { -+ ret = mtk_pwrap_dev_suspend(mdata->pwrap_ctrl, 0); -+ /* A failed request leaves the hardware state ambiguous. */ -+ mdata->power_state = false; -+ mdata->pwrap_state_unknown = !!ret; -+ if (ret) { -+ dev_err(dev, "pwrap suspend failed (%d)\n", ret); -+ -+ rollback_ret = mtk_spi_pwrap_resume(dev, mdata); -+ if (rollback_ret) -+ dev_err(dev, "pwrap D0 rollback failed (%d)\n", -+ rollback_ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int mtk_spi_resume_noirq(struct device *dev) -+{ -+ struct spi_controller *host = dev_get_drvdata(dev); -+ struct mtk_spi *mdata = spi_controller_get_devdata(host); -+ int ret; -+ -+ /* -+ * If the device was runtime suspended across system sleep, the pwrap -+ * is intentionally off. Leave it off and let the next transfer's -+ * runtime_resume power it on. Otherwise we would power it back on for -+ * a device that stays runtime suspended, leaking power on an idle -+ * controller that may never see another transaction. -+ */ -+ if (pm_runtime_status_suspended(dev)) -+ return 0; -+ -+ ret = mtk_spi_pwrap_resume(dev, mdata); -+ if (ret) { -+ dev_err(dev, "pwrap resume failed (%d)\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} - #endif /* CONFIG_PM_SLEEP */ - - #ifdef CONFIG_PM -+static int mtk_spi_runtime_resume(struct device *dev); -+ - static int mtk_spi_runtime_suspend(struct device *dev) - { - struct spi_controller *host = dev_get_drvdata(dev); - struct mtk_spi *mdata = spi_controller_get_devdata(host); -+ int ret, rollback_ret; -+ -+ /* A failed system resume left D0 unconfirmed and clocks disabled. */ -+ if (mdata->pwrap_state_unknown) -+ return -EBUSY; - - if (mdata->dev_comp->no_need_unprepare) { - clk_disable(mdata->spi_clk); -@@ -1435,6 +1688,36 @@ static int mtk_spi_runtime_suspend(struct device *dev) - clk_disable_unprepare(mdata->spi_hclk); - } - -+ if (has_acpi_companion(dev) && mdata->pwrap_ctrl && mdata->power_state) { -+ ret = mtk_pwrap_dev_suspend(mdata->pwrap_ctrl, 0); -+ /* A failed request leaves the hardware state ambiguous. */ -+ mdata->power_state = false; -+ mdata->pwrap_state_unknown = !!ret; -+ if (ret) { -+ dev_err(dev, "pwrap suspend failed (%d)\n", ret); -+ -+ rollback_ret = mtk_spi_runtime_resume(dev); -+ if (rollback_ret) { -+ dev_err(dev, "pwrap D0 rollback failed (%d)\n", -+ rollback_ret); -+ /* -+ * Reporting an error would leave runtime PM active with -+ * clocks off and D0 unconfirmed. Complete suspend so the -+ * normal resume path retries D0 before enabling clocks. -+ */ -+ return 0; -+ } -+ -+ /* Keep D0 active; retry once without repeated SSPM polling. */ -+ if (!mdata->d3_retry_used) { -+ mdata->d3_retry_used = true; -+ pm_runtime_mark_last_busy(dev); -+ } -+ return -EBUSY; -+ } -+ mdata->d3_retry_used = false; -+ } -+ - return 0; - } - -@@ -1444,6 +1727,22 @@ static int mtk_spi_runtime_resume(struct device *dev) - struct mtk_spi *mdata = spi_controller_get_devdata(host); - int ret; - -+ if (has_acpi_companion(dev) && mdata->pwrap_ctrl && !mdata->power_state) { -+ ret = mtk_pwrap_dev_resume(mdata->pwrap_ctrl, 0); -+ if (ret) { -+ mdata->pwrap_state_unknown = true; -+ /* -+ * Keep a firmware timeout retryable. Runtime PM still leaves -+ * the device suspended, while -EAGAIN avoids permanently -+ * setting runtime_error for this transient failure. -+ */ -+ dev_err(dev, "pwrap resume failed (%d)\n", ret); -+ return ret == -ETIMEDOUT ? -EAGAIN : ret; -+ } -+ mdata->power_state = true; -+ mdata->pwrap_state_unknown = false; -+ } -+ - if (mdata->dev_comp->no_need_unprepare) { - ret = clk_enable(mdata->spi_clk); - if (ret < 0) { -@@ -1477,6 +1776,7 @@ static int mtk_spi_runtime_resume(struct device *dev) - - static const struct dev_pm_ops mtk_spi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend, mtk_spi_resume) -+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend_noirq, mtk_spi_resume_noirq) - SET_RUNTIME_PM_OPS(mtk_spi_runtime_suspend, - mtk_spi_runtime_resume, NULL) - }; -@@ -1486,6 +1786,7 @@ static struct platform_driver mtk_spi_driver = { - .name = "mtk-spi", - .pm = &mtk_spi_pm, - .of_match_table = mtk_spi_of_match, -+ .acpi_match_table = ACPI_PTR(mtk_spi_acpi_match), - }, - .probe = mtk_spi_probe, - .remove = mtk_spi_remove, --- -2.56.0 - diff --git a/kernel/1095-i2c-mt65xx-enable-suspend-and-resume.patch b/kernel/1095-i2c-mt65xx-enable-suspend-and-resume.patch deleted file mode 100644 index 573e5e3..0000000 --- a/kernel/1095-i2c-mt65xx-enable-suspend-and-resume.patch +++ /dev/null @@ -1,260 +0,0 @@ -From 2e3be6fd52647c7300d75e02c0dd569efafa6d6f Mon Sep 17 00:00:00 2001 -From: Housong Zhang -Date: Tue, 21 Jul 2026 10:11:01 +0800 -Subject: [PATCH 6/6] NVIDIA: SAUCE: i2c: mt65xx: enable suspend and resume - -BugLink: https://bugs.launchpad.net/bugs/2167886 - -Integrate the Power Wrap client with the MediaTek I2C driver so -ACPI-enumerated controllers release their clocks and power resources -during suspend and restore them during resume. - -Add matching probe, remove, and error-unwind handling while leaving the -existing device-tree path unchanged. After an ambiguous system-suspend -failure, invalidate the cached state, attempt immediate D0 rollback, and -retry D0 during regular resume while keeping the adapter suspended until -hardware access is confirmed. - -Signed-off-by: Housong Zhang -Signed-off-by: Bharat Dintakurti -Acked-by: Jamie Nguyen -Acked-by: Carol L Soto -Signed-off-by: Brad Figg ---- - drivers/i2c/busses/i2c-mt65xx.c | 154 +++++++++++++++++++++++++++++++- - 1 file changed, 152 insertions(+), 2 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c -index ac6df7b..888324a 100644 ---- a/drivers/i2c/busses/i2c-mt65xx.c -+++ b/drivers/i2c/busses/i2c-mt65xx.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #define I2C_RS_TRANSFER (1 << 4) - #define I2C_ARB_LOST (1 << 3) -@@ -304,6 +305,11 @@ struct mtk_i2c { - void __iomem *base; /* i2c base addr */ - void __iomem *pdmabase; /* dma base address*/ - struct clk_bulk_data clocks[I2C_MT65XX_CLK_MAX]; /* clocks for i2c */ -+#ifdef CONFIG_ACPI -+ void *pwrap_ctrl; -+ bool power_state; -+#endif -+ bool system_suspended; - bool have_pmic; /* can use i2c pins from PMIC */ - bool use_push_pull; /* IO config push-pull mode */ - -@@ -1426,6 +1432,93 @@ static int mtk_i2c_parse_fw(struct mtk_i2c *i2c) - return 0; - } - -+#ifdef CONFIG_ACPI -+static int mtk_i2c_pwrap_probe(struct platform_device *pdev, -+ struct mtk_i2c *i2c) -+{ -+ struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); -+ struct acpi_buffer acpi_path = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ int ret; -+ -+ if (!adev) -+ return 0; -+ -+ status = acpi_get_name(adev->handle, ACPI_FULL_PATHNAME, &acpi_path); -+ if (ACPI_FAILURE(status)) -+ return dev_err_probe(&pdev->dev, -EINVAL, -+ "failed to get ACPI device path\n"); -+ -+ i2c->pwrap_ctrl = mtk_pwrap_dev_probe(acpi_path.pointer); -+ if (!i2c->pwrap_ctrl) { -+ ret = dev_err_probe(&pdev->dev, -ENODEV, -+ "pwrap probe failed for %s\n", -+ (char *)acpi_path.pointer); -+ goto out_free; -+ } -+ -+ i2c->power_state = true; -+ dev_dbg(&pdev->dev, "pwrap probe succeeded for %s\n", -+ (char *)acpi_path.pointer); -+ -+ ret = 0; -+ -+out_free: -+ ACPI_FREE(acpi_path.pointer); -+ return ret; -+} -+ -+static void mtk_i2c_pwrap_remove(struct mtk_i2c *i2c) -+{ -+ if (!i2c->pwrap_ctrl) -+ return; -+ -+ mtk_pwrap_dev_remove(i2c->pwrap_ctrl); -+ i2c->pwrap_ctrl = NULL; -+ i2c->power_state = false; -+} -+ -+static int mtk_i2c_pwrap_suspend(struct mtk_i2c *i2c) -+{ -+ int ret; -+ -+ if (!i2c->pwrap_ctrl) -+ return 0; -+ if (!i2c->power_state) -+ return -EIO; -+ -+ ret = mtk_pwrap_dev_suspend(i2c->pwrap_ctrl, 0); -+ /* A failed request leaves the hardware state ambiguous. */ -+ i2c->power_state = false; -+ return ret; -+} -+ -+static int mtk_i2c_pwrap_resume(struct mtk_i2c *i2c) -+{ -+ int ret; -+ -+ if (!i2c->pwrap_ctrl || i2c->power_state) -+ return 0; -+ -+ ret = mtk_pwrap_dev_resume(i2c->pwrap_ctrl, 0); -+ if (ret) -+ return ret; -+ -+ i2c->power_state = true; -+ return 0; -+} -+#else -+static int mtk_i2c_pwrap_probe(struct platform_device *pdev, -+ struct mtk_i2c *i2c) -+{ -+ return 0; -+} -+ -+static void mtk_i2c_pwrap_remove(struct mtk_i2c *i2c) {} -+static int mtk_i2c_pwrap_suspend(struct mtk_i2c *i2c) { return 0; } -+static int mtk_i2c_pwrap_resume(struct mtk_i2c *i2c) { return 0; } -+#endif -+ - static int mtk_i2c_probe(struct platform_device *pdev) - { - int ret = 0; -@@ -1549,10 +1642,15 @@ static int mtk_i2c_probe(struct platform_device *pdev) - } - } - -+ /* Establish ACPI Power Wrap control before the first controller MMIO. */ -+ ret = mtk_i2c_pwrap_probe(pdev, i2c); -+ if (ret) -+ return ret; -+ - ret = clk_bulk_prepare_enable(I2C_MT65XX_CLK_MAX, i2c->clocks); - if (ret) { - dev_err(&pdev->dev, "clock enable failed!\n"); -- return ret; -+ goto err_pwrap_remove; - } - mtk_i2c_init_hw(i2c); - clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks); -@@ -1578,6 +1676,9 @@ static int mtk_i2c_probe(struct platform_device *pdev) - err_bulk_unprepare: - clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); - -+err_pwrap_remove: -+ mtk_i2c_pwrap_remove(i2c); -+ - return ret; - } - -@@ -1586,16 +1687,40 @@ static void mtk_i2c_remove(struct platform_device *pdev) - struct mtk_i2c *i2c = platform_get_drvdata(pdev); - - i2c_del_adapter(&i2c->adap); -- - clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); -+ mtk_i2c_pwrap_remove(i2c); - } - -+static int mtk_i2c_resume_noirq(struct device *dev); -+ - static int mtk_i2c_suspend_noirq(struct device *dev) - { -+ int ret, rollback_ret; - struct mtk_i2c *i2c = dev_get_drvdata(dev); - -+ /* Recover an unresolved prior resume before starting another cycle. */ -+ if (i2c->system_suspended) { -+ ret = mtk_i2c_resume_noirq(dev); -+ if (ret) { -+ dev_err(dev, "pre-suspend recovery failed (%d)\n", ret); -+ return ret; -+ } -+ } -+ -+ i2c->system_suspended = true; - i2c_mark_adapter_suspended(&i2c->adap); -+ -+ ret = mtk_i2c_pwrap_suspend(i2c); - clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); -+ if (ret) { -+ dev_err(dev, "pwrap suspend failed (%d)\n", ret); -+ -+ rollback_ret = mtk_i2c_resume_noirq(dev); -+ if (rollback_ret) -+ dev_err(dev, "pwrap D0 rollback failed (%d)\n", -+ rollback_ret); -+ return ret; -+ } - - return 0; - } -@@ -1605,6 +1730,10 @@ static int mtk_i2c_resume_noirq(struct device *dev) - int ret; - struct mtk_i2c *i2c = dev_get_drvdata(dev); - -+ ret = mtk_i2c_pwrap_resume(i2c); -+ if (ret) -+ return ret; -+ - ret = clk_bulk_prepare_enable(I2C_MT65XX_CLK_MAX, i2c->clocks); - if (ret) { - dev_err(dev, "clock enable failed!\n"); -@@ -1616,11 +1745,32 @@ static int mtk_i2c_resume_noirq(struct device *dev) - clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks); - - i2c_mark_adapter_resumed(&i2c->adap); -+ i2c->system_suspended = false; - - return 0; - } - -+static int mtk_i2c_resume(struct device *dev) -+{ -+ struct mtk_i2c *i2c = dev_get_drvdata(dev); -+ int ret; -+ -+ if (!i2c->system_suspended) -+ return 0; -+ -+ /* -+ * The PM core skips ->resume_noirq() when this device's -+ * ->suspend_noirq() failed. Retry D0 before allowing transfers. -+ */ -+ ret = mtk_i2c_resume_noirq(dev); -+ if (ret) -+ dev_err(dev, "pwrap resume recovery failed (%d)\n", ret); -+ -+ return ret; -+} -+ - static const struct dev_pm_ops mtk_i2c_pm = { -+ SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume) - NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq, - mtk_i2c_resume_noirq) - }; --- -2.56.0 - diff --git a/kernel/1096-pinctrl-mt8901-sync-wake-EINT-event-mask.patch b/kernel/1096-pinctrl-mt8901-sync-wake-EINT-event-mask.patch deleted file mode 100644 index 8f48808..0000000 --- a/kernel/1096-pinctrl-mt8901-sync-wake-EINT-event-mask.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 0f0aeba492533b9dba991f131289d4a17c1f3c5d Mon Sep 17 00:00:00 2001 -From: Kaushal Rajeev Butala -Date: Thu, 8 Oct 2026 13:33:41 +0530 -Subject: [PATCH] NVIDIA: SAUCE: pinctrl: mt8901: sync wake EINT event mask - -MT8901 EINT has a separate event mask that controls whether an EINT can -be forwarded as a wake event. The current driver clears that mask only -for the static SoC list, which covers the ACPI event line. - -Firmware-described devices can be marked wake-capable independently, -so PM arms their IRQs through the normal irq_set_wake path. Clear the -hardware event mask when the IRQ core enables such an EINT as a wake -source so keyboard, touchpad, and other firmware-declared EINT wake -sources can reach the SPM without adding board-specific EINT numbers. - -Restore the hardware event mask when wake is disabled, otherwise a pin -that was armed once would remain an SPM wake event until reboot. Keep -pins from the SoC static event-unmask list unmasked so permanently -required wake events such as the ACPI event line remain armed. - -Make event-mask register programming opt-in for SoCs that declare -support for it, and re-apply both the static list and dynamically -armed wake_mask pins on resume in case the event register state is -lost across system sleep. - -Fixes: 927eedaaa809 ("NVIDIA: SAUCE: pinctrl: mt8901: Enable ACPI wake-event EINT support") -Signed-off-by: Kaushal Rajeev Butala ---- - drivers/pinctrl/mediatek/mtk-eint.c | 91 ++++++++++++++++++++--- - drivers/pinctrl/mediatek/mtk-eint.h | 1 + - drivers/pinctrl/mediatek/pinctrl-mt8901.c | 1 + - 3 files changed, 82 insertions(+), 11 deletions(-) - -diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c -index 461f1b131..0da6dafa0 100644 ---- a/drivers/pinctrl/mediatek/mtk-eint.c -+++ b/drivers/pinctrl/mediatek/mtk-eint.c -@@ -166,18 +166,17 @@ static void mtk_eint_unmask(struct irq_data *d) - mtk_eint_flip_edge(eint, d->hwirq); - } - --/* -- * Clear the event_clr bit for a single EINT so its wake-event is not -- * suppressed. Mirrors mtk_eint_unmask() addressing: register is banked -- * per instance and word-indexed by (idx / 32). -- */ --static void mtk_eint_event_unmask_one(struct mtk_eint *eint, -- unsigned int eint_num) -+static void mtk_eint_write_event_mask(struct mtk_eint *eint, -+ unsigned int eint_num, -+ unsigned int reg_offset) - { - unsigned int idx, inst; - unsigned int mask; - void __iomem *reg; - -+ if (!eint->hw->has_event_mask) -+ return; -+ - if (eint_num >= eint->hw->ap_num) - return; - -@@ -188,10 +187,47 @@ static void mtk_eint_event_unmask_one(struct mtk_eint *eint, - return; - - mask = BIT(idx & 0x1f); -- reg = mtk_eint_get_offset(eint, eint_num, eint->regs->event_clr); -+ reg = mtk_eint_get_offset(eint, eint_num, reg_offset); - writel(mask, reg); - } - -+/* -+ * Clear the event_clr bit for a single EINT so its wake-event is not -+ * suppressed. Mirrors mtk_eint_unmask() addressing: register is banked -+ * per instance and word-indexed by (idx / 32). -+ */ -+static void mtk_eint_event_unmask_one(struct mtk_eint *eint, -+ unsigned int eint_num) -+{ -+ mtk_eint_write_event_mask(eint, eint_num, eint->regs->event_clr); -+} -+ -+static bool mtk_eint_is_static_event_unmask_pin(struct mtk_eint *eint, -+ unsigned int eint_num) -+{ -+ unsigned int i; -+ -+ if (!eint->event_pins) -+ return false; -+ -+ for (i = 0; i < eint->num_event_pins; i++) { -+ if (eint->event_pins[i] == eint_num) -+ return true; -+ } -+ -+ return false; -+} -+ -+/* -+ * Set the event mask for a single EINT so its wake-event is suppressed -+ * again. Callers must skip pins in the SoC's static event-unmask list. -+ */ -+static void mtk_eint_event_mask_one(struct mtk_eint *eint, -+ unsigned int eint_num) -+{ -+ mtk_eint_write_event_mask(eint, eint_num, eint->regs->event_set); -+} -+ - /* - * Clear the event mask of every pin in the SoC's eint_event_unmask list so - * their wake events reach the SPM after init and resume. -@@ -200,13 +236,41 @@ static void mtk_eint_apply_event_unmask(struct mtk_eint *eint) - { - unsigned int i; - -- if (!eint->event_pins || !eint->num_event_pins) -+ if (!eint->hw->has_event_mask || !eint->event_pins || -+ !eint->num_event_pins) - return; - - for (i = 0; i < eint->num_event_pins; i++) - mtk_eint_event_unmask_one(eint, eint->event_pins[i]); - } - -+static void mtk_eint_apply_wake_event_unmask(struct mtk_eint *eint) -+{ -+ unsigned int eint_num, pin, shift; -+ int inst, port, port_num; -+ u32 bits; -+ -+ if (!eint->hw->has_event_mask) -+ return; -+ -+ for (inst = 0; inst < eint->nbase; inst++) { -+ port_num = DIV_ROUND_UP(eint->base_pin_num[inst], 32); -+ for (port = 0; port < port_num; port++) { -+ bits = eint->wake_mask[inst][port]; -+ while (bits) { -+ shift = __ffs(bits); -+ bits &= ~BIT(shift); -+ pin = port * 32 + shift; -+ if (pin >= eint->base_pin_num[inst]) -+ continue; -+ -+ eint_num = eint->pin_list[inst][pin]; -+ mtk_eint_event_unmask_one(eint, eint_num); -+ } -+ } -+ } -+} -+ - static unsigned int mtk_eint_get_mask(struct mtk_eint *eint, - unsigned int eint_num) - { -@@ -285,10 +349,14 @@ static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on) - unsigned int shift = idx & 0x1f; - unsigned int port = idx >> 5; - -- if (on) -+ if (on) { - eint->wake_mask[inst][port] |= BIT(shift); -- else -+ mtk_eint_event_unmask_one(eint, d->hwirq); -+ } else { - eint->wake_mask[inst][port] &= ~BIT(shift); -+ if (!mtk_eint_is_static_event_unmask_pin(eint, d->hwirq)) -+ mtk_eint_event_mask_one(eint, d->hwirq); -+ } - - return 0; - } -@@ -483,6 +551,7 @@ int mtk_eint_do_resume(struct mtk_eint *eint) - { - mtk_eint_chip_write_mask(eint, eint->cur_mask); - mtk_eint_apply_event_unmask(eint); -+ mtk_eint_apply_wake_event_unmask(eint); - - return 0; - } -diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h -index cbcca2830..443c4bec2 100644 ---- a/drivers/pinctrl/mediatek/mtk-eint.h -+++ b/drivers/pinctrl/mediatek/mtk-eint.h -@@ -42,6 +42,7 @@ struct mtk_eint_hw { - unsigned int ap_num; - unsigned int db_cnt; - const unsigned int *db_time; -+ bool has_event_mask; - }; - - struct mtk_eint_pin { -diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8901.c b/drivers/pinctrl/mediatek/pinctrl-mt8901.c -index 09f3ec336..4c3cca4e7 100644 ---- a/drivers/pinctrl/mediatek/pinctrl-mt8901.c -+++ b/drivers/pinctrl/mediatek/pinctrl-mt8901.c -@@ -1410,6 +1410,7 @@ static const struct mtk_eint_hw mt8901_eint_hw = { - .ap_num = 209, - .db_cnt = 32, - .db_time = debounce_time_mt8901, -+ .has_event_mask = true, - }; - - static const unsigned int mt8901_eint_event_unmask[] = {20}; --- -2.56.0 - diff --git a/kernel/1097-usb-xhci-plat-use-firmware-managed-USB-without-SSPM.patch b/kernel/1097-usb-xhci-plat-use-firmware-managed-USB-without-SSPM.patch deleted file mode 100644 index f56ac26..0000000 --- a/kernel/1097-usb-xhci-plat-use-firmware-managed-USB-without-SSPM.patch +++ /dev/null @@ -1,34 +0,0 @@ -From: Jim Martin -Subject: [PATCH] usb: xhci-plat: use generic ACPI initialization without SSPM - -The DGX Spark exposes NVDA8000/NVDA8001 controllers but its firmware can -report the SSPM mailbox as absent. Selecting the MediaTek power-management -path by controller ID alone then makes every USB probe fail: the required -Power Wrap request returns -ENODEV. USB storage and input never enumerate. - -Only select that path when firmware exposes one of the SSPM transport's -ACPI devices. Otherwise keep the generic ACPI xHCI initialization used by -the working unpatched kernel. Check firmware presence, not driver binding, -so a present transport that fails to initialize still produces an error. -Retain the controller's hardware quirks. - -Signed-off-by: Jim Martin ---- ---- a/drivers/usb/host/xhci-plat.c -+++ b/drivers/usb/host/xhci-plat.c -@@ -250,6 +250,15 @@ - *priv = *priv_match; - } - -+ /* -+ * GB10 firmware can expose the same controller IDs with SSPM disabled. -+ * In that case firmware owns the PHYs; use the generic ACPI xHCI path. -+ */ -+ if (priv && priv->is_mtk_v2 && -+ !acpi_dev_present("MTKW8400", NULL, -1) && -+ !acpi_dev_present("NVDA8400", NULL, -1)) -+ priv->is_mtk_v2 = false; -+ - if (priv && priv->is_mtk_v2) { - - wakeup_irq = platform_get_irq_optional(pdev, 1); diff --git a/kernel/1098-soc-mediatek-gate-SSPM-dependent-ACPI-paths.patch b/kernel/1098-soc-mediatek-gate-SSPM-dependent-ACPI-paths.patch deleted file mode 100644 index be4b49e..0000000 --- a/kernel/1098-soc-mediatek-gate-SSPM-dependent-ACPI-paths.patch +++ /dev/null @@ -1,59 +0,0 @@ -From: Jim Martin -Subject: [PATCH] soc: mediatek: gate SSPM-dependent ACPI paths on firmware presence - -GB10 firmware describes the MT8901 Power Wrap, SPI and DSP devices while -marking the SSPM mailbox absent. The USB4 resource-release hook still -arms, and the SPI and DSP power drivers try to obtain SSPM-backed control. -Each call fails with -ENODEV because the transport cannot be initialized. - -Require a firmware-present SSPM device before arming the release hook or -probing these SSPM-only ACPI clients. Leave Power Wrap's other setup and -the SPI device-tree path unchanged. This is not a transport-ready check: -a present mailbox whose driver or firmware fails still takes the existing -error path. Do not claim successful power transitions without a transport. - -Signed-off-by: Jim Martin ---- ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -829,6 +829,11 @@ - return; - } - -+ /* Firmware can describe MT8901 while hiding the SSPM mailbox. */ -+ if (!acpi_dev_present("MTKW8400", NULL, -1) && -+ !acpi_dev_present("NVDA8400", NULL, -1)) -+ return; -+ - mutex_lock(&pwrap_usb4_lock); - pwrap_usb4_dev = dev; - pwrap_usb4_nb.notifier_call = pwrap_usb4_bus_notify; ---- a/drivers/spi/spi-mt65xx.c -+++ b/drivers/spi/spi-mt65xx.c -@@ -1331,6 +1331,12 @@ - bool has_of = dev->of_node != NULL; - bool has_acpi = has_acpi_companion(dev); - -+ /* The ACPI path requires SSPM to control clocks and power. */ -+ if (!has_of && has_acpi && -+ !acpi_dev_present("MTKW8400", NULL, -1) && -+ !acpi_dev_present("NVDA8400", NULL, -1)) -+ return -ENODEV; -+ - host = devm_spi_alloc_host(dev, sizeof(*mdata)); - if (!host) - return -ENOMEM; ---- a/sound/soc/sof/mediatek/mt8901/mt8901.c -+++ b/sound/soc/sof/mediatek/mt8901/mt8901.c -@@ -51,6 +51,11 @@ - - adev = ACPI_COMPANION(dev); - if (!adev) -+ return -ENODEV; -+ -+ /* This driver only manages DSP power through the SSPM mailbox. */ -+ if (!acpi_dev_present("MTKW8400", NULL, -1) && -+ !acpi_dev_present("NVDA8400", NULL, -1)) - return -ENODEV; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); diff --git a/kernel/1099-soc-mediatek-power_wrap-keep-DGX-Spark-DVFSRC-policy.patch b/kernel/1099-soc-mediatek-power_wrap-keep-DGX-Spark-DVFSRC-policy.patch deleted file mode 100644 index d3a4521..0000000 --- a/kernel/1099-soc-mediatek-power_wrap-keep-DGX-Spark-DVFSRC-policy.patch +++ /dev/null @@ -1,52 +0,0 @@ -From a6535f6c549fa06a26fd998b20827edce5342102 Mon Sep 17 00:00:00 2001 -From: Jim Martin -Date: Fri, 16 Oct 2026 16:43:06 -0500 -Subject: [PATCH] soc: mediatek: power_wrap: keep DGX Spark DVFSRC policy - unchanged - -The DGX Spark exposes NVDA6210 and PLID 2, so the MT8901 check also -selects it for the N1x DVFSRC SYSRAM write. Setting that flag causes -repeatable idle resets on the Spark. With only this write omitted, the -same kernel configuration and BestPerf write remain stable. - -Leave the firmware's DVFSRC policy untouched on the NVIDIA DGX Spark. -Match both DMI vendor and product exactly, so the N1x path and other -MT8901 systems retain their existing behavior. Keep the remaining -power_wrap functionality enabled. - -The underlying firmware reset mechanism is not yet known. - -Signed-off-by: Jim Martin ---- - drivers/soc/mediatek/power_wrap/power_wrap.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/soc/mediatek/power_wrap/power_wrap.c b/drivers/soc/mediatek/power_wrap/power_wrap.c -index 5ee74a0..b1342be 100644 ---- a/drivers/soc/mediatek/power_wrap/power_wrap.c -+++ b/drivers/soc/mediatek/power_wrap/power_wrap.c -@@ -3,6 +3,7 @@ - * Copyright (c) 2026 MediaTek Inc. - */ - #include -+#include - #include - #include - #include -@@ -600,6 +601,13 @@ static void pwrap_write_dvfsrc_flag(struct device *dev) - { - void __iomem *vaddr; - -+ /* The DGX Spark resets at idle when this firmware flag is set. */ -+ if (dmi_match(DMI_SYS_VENDOR, "NVIDIA") && -+ dmi_match(DMI_PRODUCT_NAME, "NVIDIA_DGX_Spark")) { -+ dev_info(dev, "DVFSRC: leaving firmware policy unchanged on DGX Spark\n"); -+ return; -+ } -+ - vaddr = ioremap(PWRAP_DVFSRC_FLAG_ADDR, PWRAP_DVFSRC_FLAG_LEN); - if (!vaddr) { - dev_warn(dev, --- -2.56.0 - diff --git a/kernel/1100-HID-asus-support-the-Zenbook-A16-UX3607OA-keyboard.patch b/kernel/1100-HID-asus-support-the-Zenbook-A16-UX3607OA-keyboard.patch deleted file mode 100644 index 72a9dfd..0000000 --- a/kernel/1100-HID-asus-support-the-Zenbook-A16-UX3607OA-keyboard.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 625767deb33069e152114ba9cf109b608cd54c77 Mon Sep 17 00:00:00 2001 -From: Konrad Dybcio -Date: Fri, 24 Jul 2026 14:38:13 +0200 -Subject: [PATCH] HID: asus: support the Zenbook A16 (UX3607OA) keyboard - -The ASUS Zenbook A16 (UX3607OA), a Qualcomm Snapdragon X2 Elite Extreme -(Glymur)-based laptop, carries its main keyboard on an I2C-HID device -with the ID 0B05:4B42. Its Fn/media hotkeys are emitted as vendor-page -(HID_UP_ASUSVENDOR) usages on report 0x5A. - -Match the device in hid-asus with the standard I2C keyboard quirks and -add the three usage mappings observed on the hardware: - - 0x85 -> KEY_CAMERA (Fn+F11, camera toggle) - 0x86 -> KEY_PROG1 (Fn+F12, MyASUS key) - 0x5f -> KEY_PROG2 (extra programmable key) - -The camera-toggle key reports its usage (0x85) together with a companion -state byte in the same array report ("5a 85 01" / "5a 85 10"). The 0x10 -companion aliases the brightness-down vendor usage and spuriously dims -the panel, so add QUIRK_FILTER_CAMERA_COMPANION to zero the companion -slots for this device before input mapping. The quirk is device-gated so -no other ASUS model is affected. - -Assisted-by: Claude Code:claude-opus-4-8 -Signed-off-by: Konrad Dybcio -Signed-off-by: Jiri Kosina ---- - drivers/hid/hid-asus.c | 18 ++++++++++++++++++ - drivers/hid/hid-ids.h | 1 + - 2 files changed, 19 insertions(+) - -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index ebae16f990..8f6e4c0140 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -99,6 +99,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); - #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) - #define QUIRK_ROG_ALLY_XPAD BIT(13) - #define QUIRK_HID_FN_LOCK BIT(14) -+#define QUIRK_FILTER_CAMERA_COMPANION BIT(15) - - #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ - QUIRK_NO_INIT_REPORTS | \ -@@ -460,6 +461,17 @@ static int asus_raw_event(struct hid_device *hdev, - return -1; - } - -+ /* -+ * The camera-toggle key reports its vendor usage (0x85) together with a -+ * companion state byte in the same array report, e.g. "5a 85 01" and -+ * "5a 85 10" for the two toggle positions. The 0x10 companion aliases the -+ * brightness-down vendor usage and would spuriously dim the panel, so drop -+ * the companion slots and leave only the camera usage for input mapping. -+ */ -+ if (drvdata->quirks & QUIRK_FILTER_CAMERA_COMPANION && -+ report->id == FEATURE_KBD_REPORT_ID && size >= 3 && data[1] == 0x85) -+ memset(&data[2], 0, size - 2); -+ - return 0; - } - -@@ -1045,6 +1057,8 @@ static int asus_input_mapping(struct hid_device *hdev, - case 0x6c: asus_map_key_clear(KEY_SLEEP); break; - case 0x7c: asus_map_key_clear(KEY_MICMUTE); break; - case 0x82: asus_map_key_clear(KEY_CAMERA); break; -+ case 0x85: asus_map_key_clear(KEY_CAMERA); break; -+ case 0x86: asus_map_key_clear(KEY_PROG1); break; /* MyASUS key */ - case 0x88: asus_map_key_clear(KEY_RFKILL); break; - case 0xb5: asus_map_key_clear(KEY_CALC); break; - case 0xc4: asus_map_key_clear(KEY_KBDILLUMUP); break; -@@ -1054,6 +1068,7 @@ static int asus_input_mapping(struct hid_device *hdev, - case 0x7e: asus_map_key_clear(KEY_EMOJI_PICKER); break; - - case 0x8b: asus_map_key_clear(KEY_PROG1); break; /* ProArt Creator Hub key */ -+ case 0x5f: asus_map_key_clear(KEY_PROG2); break; /* S-shaped programmable key */ - case 0x6b: asus_map_key_clear(KEY_F21); break; /* ASUS touchpad toggle */ - case 0x38: asus_map_key_clear(KEY_PROG1); break; /* ROG key */ - case 0xba: asus_map_key_clear(KEY_PROG2); break; /* Fn+C ASUS Splendid */ -@@ -1479,6 +1494,9 @@ static const __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, - static const struct hid_device_id asus_devices[] = { - { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD), I2C_KEYBOARD_QUIRKS}, -+ { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, -+ USB_DEVICE_ID_ASUSTEK_I2C_ZENBOOK_KEYBOARD), -+ I2C_KEYBOARD_QUIRKS | QUIRK_FILTER_CAMERA_COMPANION }, - { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index 1059922baa..f70b0e5aaf 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -220,6 +220,7 @@ - #define USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD 0x183d - #define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD 0x184a - #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585 -+#define USB_DEVICE_ID_ASUSTEK_I2C_ZENBOOK_KEYBOARD 0x4b42 - #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101 - #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 - #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 diff --git a/kernel/1101-HID-asus-drive-the-0B05-4B42-keyboard-backlight-without-asus-wmi.patch b/kernel/1101-HID-asus-drive-the-0B05-4B42-keyboard-backlight-without-asus-wmi.patch deleted file mode 100644 index 8b9deeb..0000000 --- a/kernel/1101-HID-asus-drive-the-0B05-4B42-keyboard-backlight-without-asus-wmi.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 7aeab2522788ef716abd237cf6c7981c433aa4a3 Mon Sep 17 00:00:00 2001 -From: Ryan -Date: Fri, 9 Oct 2026 14:24:47 -0400 -Subject: [PATCH] HID: asus: drive the 0B05:4B42 keyboard backlight without - asus-wmi - -The 0B05:4B42 I2C keyboard (ASUS ProArt P14 H7407BA on NVIDIA N1x, ASUS -Zenbook A16 on Snapdragon) has a HID-controlled backlight, but on these -arm64 laptops nothing exposes it: - -- hid-asus only hands the level to asus-wmi through - asus_hid_register_listener(), and asus-wmi is x86-only, so the stub - returns -ENODEV and no asus::kbd_backlight LED exists. Register the LED - from hid-asus itself in that case. - -- The keyboard silently drops feature reports shorter than the 64 bytes - its descriptor declares for report 0x5a. Add QUIRK_PAD_FEATURE_REPORTS - to zero-pad feature reports to their declared length. - -Enable QUIRK_USE_KBD_BACKLIGHT and QUIRK_PAD_FEATURE_REPORTS for the -0B05:4B42 keyboard. The keyboard reports SUPPORT_KBD_BACKLIGHT and takes -levels 0-3; KEY_KBDILLUMTOGGLE from the same keyboard now cycles it -through the LED class. - -[omarchy: rebased onto 47669bec44fe ("HID: asus: refactor the two - workqueues and init sequence"), in 7.2.6. The listener and brightness - now live in asus_drvdata and go through the shared worker, so the LED - class device moved there too. The refactor already sends the backlight - and Fn-lock commands as 64-byte reports and no longer frees the - backlight state on a listener failure, so the padding now only matters - for the shorter init, function query and OOBE commands, and the - use-after-free fix this patch carried on 7.2.5 is gone] ---- - drivers/hid/hid-asus.c | 59 ++++++++++++++++++++++++++++++++++++++---- - 1 file changed, 54 insertions(+), 5 deletions(-) - -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index e0bc7f956..aaa1dbb46 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -100,6 +100,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); - #define QUIRK_ROG_ALLY_XPAD BIT(13) - #define QUIRK_HID_FN_LOCK BIT(14) - #define QUIRK_FILTER_CAMERA_COMPANION BIT(15) -+#define QUIRK_PAD_FEATURE_REPORTS BIT(16) - - #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ - QUIRK_NO_INIT_REPORTS | \ -@@ -169,6 +170,8 @@ struct asus_drvdata { - bool battery_in_query; - unsigned long battery_next_query; - struct asus_hid_listener listener; -+ struct led_classdev kbd_led; /* only used when asus-wmi is absent */ -+ bool kbd_led_standalone; - bool fn_lock; - }; - -@@ -576,15 +579,30 @@ static int asus_raw_event(struct hid_device *hdev, - - static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size) - { -- u8 *dmabuf __free(kfree) = kmemdup(buf, buf_size, GFP_KERNEL); -+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -+ struct hid_report *report; -+ size_t len = buf_size; -+ -+ /* -+ * Some keyboards silently drop feature reports shorter than the length -+ * their descriptor declares, so zero-pad the command up to that length. -+ */ -+ if (drvdata->quirks & QUIRK_PAD_FEATURE_REPORTS) { -+ report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[buf[0]]; -+ if (report) -+ len = max_t(size_t, buf_size, hid_report_len(report)); -+ } -+ -+ u8 *dmabuf __free(kfree) = kzalloc(len, GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; -+ memcpy(dmabuf, buf, buf_size); - - /* - * The report ID should be set from the incoming buffer due to LED and key - * interfaces having different pages - */ -- return hid_hw_raw_request(hdev, buf[0], dmabuf, buf_size, HID_FEATURE_REPORT, -+ return hid_hw_raw_request(hdev, buf[0], dmabuf, len, HID_FEATURE_REPORT, - HID_REQ_SET_REPORT); - } - -@@ -759,6 +777,21 @@ static void asus_kbd_backlight_set(struct asus_hid_listener *listener, int brigh - spin_unlock_irqrestore(&worker->lock, flags); - } - -+static void asus_kbd_led_set(struct led_classdev *cdev, -+ enum led_brightness brightness) -+{ -+ struct asus_drvdata *drvdata = container_of(cdev, struct asus_drvdata, kbd_led); -+ -+ asus_kbd_backlight_set(&drvdata->listener, brightness); -+} -+ -+static enum led_brightness asus_kbd_led_get(struct led_classdev *cdev) -+{ -+ struct asus_drvdata *drvdata = container_of(cdev, struct asus_drvdata, kbd_led); -+ -+ return drvdata->kbd_backlight_brightness; -+} -+ - static void asus_work(struct work_struct *work) - { - struct asus_worker *worker = container_of(work, struct asus_worker, work); -@@ -971,6 +1004,21 @@ static int asus_kbd_register_leds(struct hid_device *hdev) - - drvdata->listener.brightness_set = asus_kbd_backlight_set; - ret = asus_hid_register_listener(&drvdata->listener); -+ if (ret == -ENODEV) { -+ /* -+ * asus-wmi normally owns asus::kbd_backlight and forwards it to -+ * us through the listener. Without it (arm64 laptops) the -+ * keyboard still takes its level over HID, so expose it here. -+ */ -+ drvdata->kbd_led_standalone = true; -+ drvdata->kbd_led.name = "asus::kbd_backlight"; -+ drvdata->kbd_led.max_brightness = ASUS_EV_MAX_BRIGHTNESS; -+ drvdata->kbd_led.brightness_set = asus_kbd_led_set; -+ drvdata->kbd_led.brightness_get = asus_kbd_led_get; -+ ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_led); -+ if (ret < 0) -+ drvdata->kbd_led_standalone = false; -+ } - if (ret < 0) { - hid_err(hdev, "Unable to register kbd brightness listener: %d\n", ret); - drvdata->listener.brightness_set = NULL; -@@ -1540,7 +1588,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) - - return 0; - err_stop_hw: -- if (drvdata->listener.brightness_set) -+ if (drvdata->listener.brightness_set && !drvdata->kbd_led_standalone) - asus_hid_unregister_listener(&drvdata->listener); - - asus_worker_stop(drvdata->worker); -@@ -1552,7 +1600,7 @@ static void asus_remove(struct hid_device *hdev) - { - struct asus_drvdata *drvdata = hid_get_drvdata(hdev); - -- if (drvdata->listener.brightness_set) -+ if (drvdata->listener.brightness_set && !drvdata->kbd_led_standalone) - asus_hid_unregister_listener(&drvdata->listener); - - asus_worker_stop(drvdata->worker); -@@ -1676,7 +1724,8 @@ static const struct hid_device_id asus_devices[] = { - USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD), I2C_KEYBOARD_QUIRKS}, - { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_I2C_ZENBOOK_KEYBOARD), -- I2C_KEYBOARD_QUIRKS | QUIRK_FILTER_CAMERA_COMPANION }, -+ I2C_KEYBOARD_QUIRKS | QUIRK_FILTER_CAMERA_COMPANION | -+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_PAD_FEATURE_REPORTS }, - { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, --- -2.56.0 - diff --git a/kernel/1102-HID-asus-host-controlled-Fn-lock-for-the-0B05-4B42-keyboard.patch b/kernel/1102-HID-asus-host-controlled-Fn-lock-for-the-0B05-4B42-keyboard.patch deleted file mode 100644 index 7a9e3d7..0000000 --- a/kernel/1102-HID-asus-host-controlled-Fn-lock-for-the-0B05-4B42-keyboard.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 5d041991babf6ea524da641e00b039c9d41c90d0 Mon Sep 17 00:00:00 2001 -From: Ryan -Date: Fri, 9 Oct 2026 14:24:58 -0400 -Subject: [PATCH] HID: asus: host-controlled Fn-lock for the 0B05:4B42 keyboard - -The 0B05:4B42 I2C keyboard leaves Fn-lock to the host: Fn+Esc only -reports the vendor usage 0x4e (KEY_FN_ESC) and the keyboard switches the -F1-F12 row between function keys and media keys when the host writes -feature report 5a d0 4e (1: function keys, 0: media keys). So -Fn+Esc did nothing. Enable QUIRK_HID_FN_LOCK for it so hid-asus toggles -the state on KEY_FN_ESC. - -Add an fnlock_default module parameter, matching asus-wmi's, so the -boot-time state can be chosen; it defaults to function keys as before. -Restore the state on resume as the backlight level already is. - -[omarchy: rebased onto 47669bec44fe ("HID: asus: refactor the two - workqueues and init sequence"), in 7.2.6, which sends the Fn-lock state - through the shared worker; the boot-time and resume writes now go - through asus_kbd_fn_lock_set()] ---- - drivers/hid/hid-asus.c | 16 +++++++++++++--- - 1 file changed, 13 insertions(+), 3 deletions(-) - -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index aaa1dbb46..67cc024fe 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -39,6 +39,11 @@ MODULE_AUTHOR("Victor Vlasenko "); - MODULE_AUTHOR("Frederik Wenigwieser "); - MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); - -+static bool fnlock_default = true; -+module_param(fnlock_default, bool, 0444); -+MODULE_PARM_DESC(fnlock_default, -+ "Default Fn-lock state: true makes F1-F12 send function keys (default: true)"); -+ - #define T100_TPAD_INTF 2 - #define MEDION_E1239T_TPAD_INTF 1 - -@@ -1244,8 +1249,8 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) - drvdata->input = input; - - if ((drvdata->quirks & QUIRK_HID_FN_LOCK) && -- (asus_kbd_fn_lock_set(drvdata, true))) -- hid_warn(hdev, "Error while setting FN lock to ON\n"); -+ (asus_kbd_fn_lock_set(drvdata, fnlock_default))) -+ hid_warn(hdev, "Error while setting FN lock\n"); - - return 0; - } -@@ -1420,6 +1425,10 @@ static int __maybe_unused asus_resume(struct hid_device *hdev) - if (drvdata->listener.brightness_set) - asus_kbd_backlight_set(&drvdata->listener, drvdata->kbd_backlight_brightness); - -+ if ((drvdata->quirks & QUIRK_HID_FN_LOCK) && -+ asus_kbd_fn_lock_set(drvdata, drvdata->fn_lock)) -+ hid_err(hdev, "Asus failed to restore Fn-lock\n"); -+ - return 0; - } - -@@ -1725,7 +1734,8 @@ static const struct hid_device_id asus_devices[] = { - { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_I2C_ZENBOOK_KEYBOARD), - I2C_KEYBOARD_QUIRKS | QUIRK_FILTER_CAMERA_COMPANION | -- QUIRK_USE_KBD_BACKLIGHT | QUIRK_PAD_FEATURE_REPORTS }, -+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_PAD_FEATURE_REPORTS | -+ QUIRK_HID_FN_LOCK }, - { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, --- -2.56.0 - diff --git a/kernel/1103-HID-asus-disable-OOBE-mode-on-the-ProArt-P14-keyboard-too.patch b/kernel/1103-HID-asus-disable-OOBE-mode-on-the-ProArt-P14-keyboard-too.patch deleted file mode 100644 index 4d2eec2..0000000 --- a/kernel/1103-HID-asus-disable-OOBE-mode-on-the-ProArt-P14-keyboard-too.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 749f722157004221a703269c10d93c3da1f1f181 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 01:55:04 -0400 -Subject: [PATCH] HID: asus: disable OOBE mode on the ProArt P14 keyboard too - -The ProArt P14 H7407BA's 0B05:4B42 keyboard starts in the same OOBE mode -as the ProArt P16's: once it takes the init handshake its backlight keeps -fading in and out on its own and ignores the level the host sets. The -OOBE disable sequence already sent on the P16 stops it, so send it when -the DMI product family is "ProArt P14" as well. - -Co-Authored-By: Claude Opus 5.5 (1M context) ---- - drivers/hid/hid-asus.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index edba915531..791a78bd5e 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -803,7 +803,8 @@ static int asus_kbd_register_leds(struct hid_device *hdev) - if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) - return -ENODEV; - -- if (dmi_match(DMI_PRODUCT_FAMILY, "ProArt P16")) { -+ if (dmi_match(DMI_PRODUCT_FAMILY, "ProArt P16") || -+ dmi_match(DMI_PRODUCT_FAMILY, "ProArt P14")) { - ret = asus_kbd_disable_oobe(hdev); - if (ret < 0) - return ret; --- -2.56.0 - diff --git a/kernel/1104-HID-asus-turn-the-keyboard-backlight-off-for-sleep-without-asus-wmi.patch b/kernel/1104-HID-asus-turn-the-keyboard-backlight-off-for-sleep-without-asus-wmi.patch deleted file mode 100644 index 9f51584..0000000 --- a/kernel/1104-HID-asus-turn-the-keyboard-backlight-off-for-sleep-without-asus-wmi.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 43a0f64a5b8330b4973e3099dd32b9565ac23aa7 Mon Sep 17 00:00:00 2001 -From: Ryan Hughes -Date: Fri, 2 Oct 2026 10:43:42 -0400 -Subject: [PATCH] HID: asus: turn the keyboard backlight off for sleep without - asus-wmi - -On laptops without asus-wmi, such as the arm64 ProArt P14, hid-asus -drives the keyboard backlight itself and nothing else turns it off -when the system sleeps: the keyboard stays lit through suspend. -Set the level to 0 on suspend; asus_resume() already restores the -level on the way back. - -[omarchy: rebased onto 47669bec44fe ("HID: asus: refactor the two - workqueues and init sequence"), in 7.2.6: the backlight work is now the - shared asus_worker, so suspend cancels that and writes level 0 with - asus_kbd_set_brightness()] ---- - drivers/hid/hid-asus.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index 948cd3298..e0aeb2374 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -1414,6 +1414,26 @@ static int asus_start_multitouch(struct hid_device *hdev) - return 0; - } - -+static int __maybe_unused asus_suspend(struct hid_device *hdev, -+ pm_message_t message) -+{ -+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -+ -+ /* -+ * Without asus-wmi nothing else turns the keyboard backlight off for -+ * sleep, so it would stay lit. asus_resume() restores the level. -+ * Actions still queued run after it, in order, once resume schedules -+ * the worker again. -+ */ -+ if (!drvdata->kbd_led_standalone) -+ return 0; -+ -+ cancel_work_sync(&drvdata->worker->work); -+ asus_kbd_set_brightness(hdev, 0); -+ -+ return 0; -+} -+ - static int __maybe_unused asus_resume(struct hid_device *hdev) - { - struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -@@ -1806,6 +1826,7 @@ static struct hid_driver asus_driver = { - .remove = asus_remove, - .input_mapping = asus_input_mapping, - .input_configured = asus_input_configured, -+ .suspend = pm_ptr(asus_suspend), - .reset_resume = pm_ptr(asus_reset_resume), - .resume = pm_ptr(asus_resume), - .event = asus_event, --- -2.56.0 - diff --git a/kernel/1110-tools-linux-types.h-Add-128-bit-integer-types-for-arm64-UAPI-structures.patch b/kernel/1110-tools-linux-types.h-Add-128-bit-integer-types-for-arm64-UAPI-structures.patch deleted file mode 100644 index 35aca41..0000000 --- a/kernel/1110-tools-linux-types.h-Add-128-bit-integer-types-for-arm64-UAPI-structures.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 10a47fb67340bca274276faf855d7d460afd9a7a Mon Sep 17 00:00:00 2001 -From: Will Deacon -Date: Fri, 26 Jun 2026 15:17:28 +0100 -Subject: [PATCH] tools: linux/types.h: Add 128-bit integer types for arm64 - UAPI structures - -The arm64 UAPI exposes some 128-bit integer types to represent things -such as fpsimd registers in the sigcontext. In preparation for defining -these using the '__u128' typedef implemented by uapi/linux/types.h, copy -that typedef over to the private linux/types.h header used by the tools -directory. - -Cc: Arnd Bergmann -Cc: Arnaldo Carvalho de Melo -Cc: David Matlack -Signed-off-by: Will Deacon ---- - tools/include/linux/types.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h -index d41f8a261bce82..b6c473b7920db0 100644 ---- a/tools/include/linux/types.h -+++ b/tools/include/linux/types.h -@@ -23,6 +23,11 @@ typedef enum { - __GFP_HIGH - } gfp_t; - -+#ifdef __SIZEOF_INT128__ -+typedef __signed__ __int128 __s128 __attribute__((aligned(16))); -+typedef unsigned __int128 __u128 __attribute__((aligned(16))); -+#endif -+ - /* - * We define u64 as uint64_t for every architecture - * so that we can print it with "%"PRIx64 without getting warnings. diff --git a/kernel/2000-media-iris-reset-AHB-bridge-before-enabling-HW-mode.patch b/kernel/2000-media-iris-reset-AHB-bridge-before-enabling-HW-mode.patch deleted file mode 100644 index f0b0048..0000000 --- a/kernel/2000-media-iris-reset-AHB-bridge-before-enabling-HW-mode.patch +++ /dev/null @@ -1,43 +0,0 @@ -From cc330f5589965bcf99307ee9c66deb8a0a53e0ee Mon Sep 17 00:00:00 2001 -From: Vikash Garodia -Date: Thu, 24 Sep 2026 20:00:54 +0530 -Subject: [PATCH] media: iris: reset AHB bridge before enabling HW mode - -When video power domain is switched from software-controlled mode to -hardware-controlled mode, the core may be powered down without the AHB -bridge going through the required reset sequence. This may leave the -bridge FIFO in a stale state. -Reset the CPU-to-VPU AHB bridge before switching the power domain to -hardware-controlled mode. This ensures that the bridge FIFO are in -reset state before going for mode switch. - -Reported-by: Birk Skyum -Link: https://lore.kernel.org/all/20260913194707.91885-1-birk.skyum@pm.me -Fixes: 95a337f92f0a ("media: iris: switch to hardware mode after firmware boot") -Cc: stable@vger.kernel.org -Co-developed-by: Renjiang Han -Signed-off-by: Renjiang Han -Signed-off-by: Vikash Garodia -Reviewed-by: Vishnu Reddy -Tested-by: Birk Skyum # Lenovo Yoga Slim 7x -Signed-off-by: Bryan O'Donoghue ---- - drivers/media/platform/qcom/iris/iris_vpu_common.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c -index e4847c10770971..2ef8004e976e34 100644 ---- a/drivers/media/platform/qcom/iris/iris_vpu_common.c -+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c -@@ -311,6 +311,11 @@ int iris_vpu_power_on_hw(struct iris_core *core) - - int iris_vpu_set_hwmode(struct iris_core *core) - { -+ writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, -+ core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); -+ writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); -+ writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); -+ - return dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true); - } - diff --git a/kernel/2001-ASoC-qcom-q6apm-lpass-dais-Reset-the-codec-DMA-channel-map-in-hw_params.patch b/kernel/2001-ASoC-qcom-q6apm-lpass-dais-Reset-the-codec-DMA-channel-map-in-hw_params.patch deleted file mode 100644 index 765f57a..0000000 --- a/kernel/2001-ASoC-qcom-q6apm-lpass-dais-Reset-the-codec-DMA-channel-map-in-hw_params.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Birk Skyum -Date: Sun, 18 Oct 2026 21:26:26 +0000 -Subject: [PATCH] ASoC: qcom: q6apm-lpass-dais: Reset the codec DMA channel map - in hw_params - -Since commit c663014e452d ("ASoC: qcom: audioreach: compute active -channel maps from channel_map"), the codec DMA active channel mask is -built from the port's channel map instead of its channel count. -q6dma_hw_params() fills that map with -audioreach_set_default_channel_mapping(), but the map lives in the -DAI's module config for as long as the device exists and is never -cleared, and the default mapping only covers one, two and four -channels. Entries left from an earlier stream, or entries the default -mapping does not fill, give a mask that does not match the channel -count, and the DSP refuses to start the port. On the Lenovo Yoga Slim -7x every capture from the digital microphones fails with - - q6apm-lpass-dais ...: Failed to start APM port 110 - -Clear the map before filling it, and map any channel the default -mapping leaves out. With this, capture through PipeWire and direct -captures with two, four and two channels in a row work again. - -Fixes: c663014e452d ("ASoC: qcom: audioreach: compute active channel maps from channel_map") -Signed-off-by: Birk Skyum ---- - sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c -index e204fd5..403fe83 100644 ---- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c -+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c -@@ -173,11 +173,16 @@ static int q6dma_hw_params(struct snd_pcm_substream *substream, - struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); - struct audioreach_module_config *cfg = &dai_data->module_config[dai->id]; - int channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max; -+ int i; - - cfg->bit_width = params_width(params); - cfg->sample_rate = params_rate(params); - cfg->num_channels = channels; -+ memset(cfg->channel_map, 0, sizeof(cfg->channel_map)); - audioreach_set_default_channel_mapping(cfg->channel_map, channels); -+ for (i = 0; i < channels && i < AR_PCM_MAX_NUM_CHANNEL; i++) -+ if (!cfg->channel_map[i]) -+ cfg->channel_map[i] = i + 1; - - return 0; - } diff --git a/kernel/2002-power-supply-qcom_battmgr-Notify-charger-supplies-of-online-changes.patch b/kernel/2002-power-supply-qcom_battmgr-Notify-charger-supplies-of-online-changes.patch deleted file mode 100644 index 51655de..0000000 --- a/kernel/2002-power-supply-qcom_battmgr-Notify-charger-supplies-of-online-changes.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 8bacdd79f85caec9d7d623e18ad1791615c44d80 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Tue, 13 Oct 2026 13:14:41 -0400 -Subject: [PATCH] power: supply: qcom_battmgr: Notify charger supplies of - online changes - -On SC8280XP and X1E80100 the AC, USB and wireless supplies take their -online state from the charging source in the battery status response. -The firmware sends no notification for those supplies when the charging -source changes, and the driver only announces the battery, so userspace -never learns that the charger was plugged in or out. UPower keeps the -state it read at startup: a laptop booted on the charger never goes on -battery. - -Call power_supply_changed() for a supply whose online state changes when -a status response is parsed. A supply that is not registered yet, when -the battery is read during probe, reports its state when it registers. - -Tested on a Microsoft Surface Pro 11 (X1E80100): after restarting UPower -on the charger, unplugging now sets OnBattery, and plugging in clears it. - -Fixes: 29e8142b5623 ("power: supply: Introduce Qualcomm PMIC GLINK power supply") -Assisted-by: Claude:claude-opus-5-5 -Signed-off-by: Brandon Williams ---- - drivers/power/supply/qcom_battmgr.c | 26 +++++++++++++++++++++++--- - 1 file changed, 23 insertions(+), 3 deletions(-) - -diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c -index e84633278943..2c6576b93726 100644 ---- a/drivers/power/supply/qcom_battmgr.c -+++ b/drivers/power/supply/qcom_battmgr.c -@@ -1256,6 +1256,23 @@ static unsigned int qcom_battmgr_sc8280xp_convert_temp(unsigned int temperature) - return DIV_ROUND_CLOSEST(temperature, 10); - } - -+/* -+ * The charger supplies' online state comes from the battery status response, -+ * and the firmware sends no notification of its own when it changes, so -+ * announce the change here. A supply that is not registered yet announces its -+ * state when it is. -+ */ -+static void qcom_battmgr_sc8280xp_set_online(struct power_supply *psy, -+ bool *online, bool value) -+{ -+ if (*online == value) -+ return; -+ -+ *online = value; -+ if (psy) -+ power_supply_changed(psy); -+} -+ - static void qcom_battmgr_sc8280xp_callback(struct qcom_battmgr *battmgr, - const struct qcom_battmgr_message *resp, - size_t len) -@@ -1325,9 +1342,12 @@ static void qcom_battmgr_sc8280xp_callback(struct qcom_battmgr *battmgr, - battmgr->status.temperature = qcom_battmgr_sc8280xp_convert_temp(le32_to_cpu(resp->status.temperature)); - - source = le32_to_cpu(resp->status.charging_source); -- battmgr->ac.online = source == BATTMGR_CHARGING_SOURCE_AC; -- battmgr->usb.online = source == BATTMGR_CHARGING_SOURCE_USB; -- battmgr->wireless.online = source == BATTMGR_CHARGING_SOURCE_WIRELESS; -+ qcom_battmgr_sc8280xp_set_online(battmgr->ac_psy, &battmgr->ac.online, -+ source == BATTMGR_CHARGING_SOURCE_AC); -+ qcom_battmgr_sc8280xp_set_online(battmgr->usb_psy, &battmgr->usb.online, -+ source == BATTMGR_CHARGING_SOURCE_USB); -+ qcom_battmgr_sc8280xp_set_online(battmgr->wls_psy, &battmgr->wireless.online, -+ source == BATTMGR_CHARGING_SOURCE_WIRELESS); - if (battmgr->info.last_full_capacity != 0) { - /* - * 100 * battmgr->status.capacity can overflow a 32bit --- -2.56.0 - diff --git a/kernel/2003-wifi-ath12k-don-t-count-a-vdev-restart-as-a-started-.patch b/kernel/2003-wifi-ath12k-don-t-count-a-vdev-restart-as-a-started-.patch deleted file mode 100644 index 8605fc4..0000000 --- a/kernel/2003-wifi-ath12k-don-t-count-a-vdev-restart-as-a-started-.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Birk Skyum -Date: Tue, 20 Oct 2026 23:17:55 +0200 -Subject: [PATCH 2003/2006] wifi: ath12k: don't count a vdev restart as a - started vdev - -ath12k_mac_vdev_start_restart() increments ar->num_started_vdevs for a -restart as well as for a start. A restart is not paired with a stop, so -each one leaves the count one too high until the driver is restarted. -ath12k_mac_update_vif_chan() restarts every vdev that is up when its -channel context changes, for example when the AP changes the bandwidth -of the link. - -Since commit 18ae7d0cdd76 ("wifi: ath12k: Avoid CPU busy-wait by -handling VDEV_STAT and BCN_STAT"), ath12k_wmi_fw_stats_process() -completes a WMI_REQUEST_VDEV_STAT request only after as many vdev stats -events as there are started vdevs. With the count too high that never -happens, so from then on every station statistics request waits the -full 3 seconds in ath12k_mac_get_fw_stats(), with the wiphy lock held, -and logs "time out while waiting for fw stats done". - -On a Lenovo Yoga Slim 7x connected to an MLO AP, the timeouts start a -few seconds after the AP narrows its 5 GHz link from 160 to 80 MHz and -repeat every 3 seconds until the driver is reloaded. While they last, -channel switches take minutes to complete, transmits fail in bursts and -group rekeys end in a deauthentication. - -Count only vdev starts, as ath11k does. - -With this change the Yoga went through the AP's next switch of that -link, from channel 128 to channel 36 at 80 MHz, without a single -timeout, and the switch completed in under two seconds. - -Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3 - -Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") -Signed-off-by: Birk Skyum -Link: https://lore.kernel.org/all/20261020213505.31624-1-birk.skyum@pm.me/ ---- - drivers/net/wireless/ath/ath12k/mac.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c -index b24f977..e4a5fa4 100644 ---- a/drivers/net/wireless/ath/ath12k/mac.c -+++ b/drivers/net/wireless/ath/ath12k/mac.c -@@ -11437,7 +11437,8 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, - &arvif->reg_tpc_info); - } - -- ar->num_started_vdevs++; -+ if (!restart) -+ ar->num_started_vdevs++; - ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n", - ahvif->vif->addr, arvif->vdev_id); - diff --git a/kernel/2004-media-iris-Fix-out-of-bounds-read-in-timestamp-metad.patch b/kernel/2004-media-iris-Fix-out-of-bounds-read-in-timestamp-metad.patch deleted file mode 100644 index 4fee2de..0000000 --- a/kernel/2004-media-iris-Fix-out-of-bounds-read-in-timestamp-metad.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Vishnu Reddy -Date: Sat, 17 Oct 2026 08:55:04 +0530 -Subject: [PATCH 2004/2006] media: iris: Fix out-of-bounds read in timestamp - metadata fallback - -inst->tss[] has VIDEO_MAX_FRAME (32) entries, so valid indexes are 0 -through 31. iris_set_ts_metadata() writes at metadata_idx and then -increments it. After the 32nd input buffer, metadata_idx is 32 until -the next input buffer is queued. - -If iris_get_ts_metadata() finds no matching timestamp in that window, -its fallback reads inst->tss[32], one entry past the end of the array. -UBSAN (Undefined Behavior Sanity Checker) reports this as an -array-index-out-of-bounds error. - -Use the last written entry, metadata_idx - 1, in the fallback instead. -Fall back to slot 0 if nothing has been written yet. Even if stream off -and stream on happen multiple times on the same session, the fallback -always uses the latest metadata received. - -Fixes: 17f2a485ca67 ("media: iris: implement vb2 ops for buf_queue and firmware response") -Cc: stable@vger.kernel.org -Signed-off-by: Vishnu Reddy -Link: https://lore.kernel.org/all/20261017-fix-oob-tss-v1-1-fb86f4cabf65@oss.qualcomm.com/ -Tested-by: Birk Skyum # Lenovo Yoga Slim 7x ---- - drivers/media/platform/qcom/iris/iris_buffer.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c -index 246ad0a..9d2f16b 100644 ---- a/drivers/media/platform/qcom/iris/iris_buffer.c -+++ b/drivers/media/platform/qcom/iris/iris_buffer.c -@@ -928,9 +928,11 @@ static void iris_get_ts_metadata(struct iris_inst *inst, u64 timestamp_ns, - return; - } - -+ i = inst->metadata_idx ? inst->metadata_idx - 1 : 0; -+ - vbuf->flags &= ~mask; -- vbuf->flags |= inst->tss[inst->metadata_idx].flags; -- vbuf->timecode = inst->tss[inst->metadata_idx].tc; -+ vbuf->flags |= inst->tss[i].flags; -+ vbuf->timecode = inst->tss[i].tc; - } - - int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) diff --git a/kernel/2005-Revert-media-qcom-iris-use-disable_irq-during-power-.patch b/kernel/2005-Revert-media-qcom-iris-use-disable_irq-during-power-.patch deleted file mode 100644 index 648da58..0000000 --- a/kernel/2005-Revert-media-qcom-iris-use-disable_irq-during-power-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Vishnu Reddy -Date: Wed, 7 Oct 2026 17:01:05 +0530 -Subject: [PATCH 2005/2006] Revert "media: qcom: iris: use disable_irq() during - power-off" - -iris_vpu_power_off() is always called with core->lock held. The threaded -IRQ handler also requires core->lock to proceed. If the handler is woken -and queued around the same time power-off is entered, it cannot acquire -core->lock because it is held by the power-off caller. disable_irq() waits -for the handler to complete, resulting in a deadlock. - -Fixes: b9c2215bdedc9c ("media: qcom: iris: use disable_irq() during power-off") -Cc: stable@vger.kernel.org -Signed-off-by: Vishnu Reddy -Link: https://lore.kernel.org/all/20261007-fix-disable-irq-safely-v1-1-45746f9a92de@oss.qualcomm.com/ -Tested-by: Birk Skyum # Lenovo Yoga Slim 7x ---- - drivers/media/platform/qcom/iris/iris_vpu_common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c -index 2ef8004..2a63035 100644 ---- a/drivers/media/platform/qcom/iris/iris_vpu_common.c -+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c -@@ -237,7 +237,7 @@ void iris_vpu_power_off(struct iris_core *core) - iris_unset_icc_bw(core); - - if (!iris_vpu_watchdog(core, core->intr_status)) -- disable_irq(core->irq); -+ disable_irq_nosync(core->irq); - } - - int iris_vpu_power_on_controller(struct iris_core *core) diff --git a/kernel/2006-media-qcom-iris-Wait-for-threaded-IRQ-completion-dur.patch b/kernel/2006-media-qcom-iris-Wait-for-threaded-IRQ-completion-dur.patch deleted file mode 100644 index 22b3f95..0000000 --- a/kernel/2006-media-qcom-iris-Wait-for-threaded-IRQ-completion-dur.patch +++ /dev/null @@ -1,235 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Vishnu Reddy -Date: Wed, 7 Oct 2026 17:01:06 +0530 -Subject: [PATCH 2006/2006] media: qcom: iris: Wait for threaded IRQ completion - during power-off - -The VPU power-off path calls disable_irq_nosync() after powering down the -hardware, allowing a pending threaded IRQ handler to access powered-off -hardware. Switch to disable_irq() so that any in-flight threaded IRQ -handler completes before power is removed. - -However, disable_irq() waits for the threaded IRQ handler to complete, -while the handler requires core->lock to proceed. Since the caller of -iris_vpu_power_off() holds core->lock, calling disable_irq() directly can -deadlock if the IRQ handler is queued and waiting for the same lock. -Release core->lock before calling disable_irq() and reacquire it after the -handler completes. Introduce an irq_disabling flag and waitqueue to -serialize concurrent power management operations while the core->lock is -released. - -Fixes: bb8a95aa038e ("media: iris: implement power management") -Cc: stable@vger.kernel.org -Signed-off-by: Vishnu Reddy -Link: https://lore.kernel.org/all/20261007-fix-disable-irq-safely-v1-2-45746f9a92de@oss.qualcomm.com/ -Tested-by: Birk Skyum # Lenovo Yoga Slim 7x -[omarchy: backported to 7.2.8; iris_core.c, iris_core.h, iris_resources.c and iris_vpu_common.c - differ from the posted patch only in context] ---- - drivers/media/platform/qcom/iris/iris_core.c | 10 +++++----- - drivers/media/platform/qcom/iris/iris_core.h | 5 +++++ - drivers/media/platform/qcom/iris/iris_probe.c | 9 +++++---- - .../media/platform/qcom/iris/iris_resources.c | 16 ++++++++++++++++ - .../media/platform/qcom/iris/iris_resources.h | 2 ++ - .../media/platform/qcom/iris/iris_vpu_common.c | 16 +++++++++++++--- - 6 files changed, 46 insertions(+), 12 deletions(-) - -diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c -index 8c335db..56832df 100644 ---- a/drivers/media/platform/qcom/iris/iris_core.c -+++ b/drivers/media/platform/qcom/iris/iris_core.c -@@ -16,7 +16,7 @@ void iris_core_deinit(struct iris_core *core) - - ret = pm_runtime_resume_and_get(core->dev); - -- mutex_lock(&core->lock); -+ iris_acquire_core_lock(core); - if (core->state != IRIS_CORE_DEINIT) { - iris_fw_unload(core); - -@@ -26,7 +26,7 @@ void iris_core_deinit(struct iris_core *core) - iris_hfi_queues_deinit(core); - core->state = IRIS_CORE_DEINIT; - } -- mutex_unlock(&core->lock); -+ iris_release_core_lock(core); - - if (!ret) - pm_runtime_put_sync(core->dev); -@@ -53,7 +53,7 @@ int iris_core_init(struct iris_core *core) - { - int ret; - -- mutex_lock(&core->lock); -+ iris_acquire_core_lock(core); - if (core->state == IRIS_CORE_INIT) { - ret = 0; - goto exit; -@@ -90,7 +90,7 @@ int iris_core_init(struct iris_core *core) - if (ret) - goto error_unload_fw; - -- mutex_unlock(&core->lock); -+ iris_release_core_lock(core); - - return iris_wait_for_system_response(core); - -@@ -103,7 +103,7 @@ error_queue_deinit: - error: - core->state = IRIS_CORE_DEINIT; - exit: -- mutex_unlock(&core->lock); -+ iris_release_core_lock(core); - - return ret; - } -diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h -index 24da604..97ab888 100644 ---- a/drivers/media/platform/qcom/iris/iris_core.h -+++ b/drivers/media/platform/qcom/iris/iris_core.h -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - - #include "iris_hfi_common.h" - #include "iris_hfi_queue.h" -@@ -66,6 +67,8 @@ struct qcom_ubwc_cfg_data; - * @message_queue: shared interface queue to receive responses from firmware - * @debug_queue: shared interface queue to receive debug info from firmware - * @lock: a lock for this strucure -+ * @irq_disabling: flag to indicate an IRQ-disable is in-progress -+ * @irq_disable_waitqueue: waitqueue to wait for the IRQ-disable to complete - * @response_packet: a pointer to response packet from fw to driver - * @header_id: id of packet header - * @packet_id: id of packet -@@ -111,6 +114,8 @@ struct iris_core { - struct iris_iface_q_info message_queue; - struct iris_iface_q_info debug_queue; - struct mutex lock; /* lock for core related operations */ -+ bool irq_disabling; -+ wait_queue_head_t irq_disable_waitqueue; - u8 *response_packet; - u32 header_id; - u32 packet_id; -diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c -index c2dcb50..35c087c 100644 ---- a/drivers/media/platform/qcom/iris/iris_probe.c -+++ b/drivers/media/platform/qcom/iris/iris_probe.c -@@ -233,6 +233,7 @@ static int iris_probe(struct platform_device *pdev) - - core->state = IRIS_CORE_DEINIT; - mutex_init(&core->lock); -+ init_waitqueue_head(&core->irq_disable_waitqueue); - init_completion(&core->core_init_done); - - core->response_packet = devm_kzalloc(core->dev, IFACEQ_CORE_PKT_SIZE, GFP_KERNEL); -@@ -321,14 +322,14 @@ static int __maybe_unused iris_pm_suspend(struct device *dev) - - core = dev_get_drvdata(dev); - -- mutex_lock(&core->lock); -+ iris_acquire_core_lock(core); - if (core->state != IRIS_CORE_INIT) - goto exit; - - ret = iris_hfi_pm_suspend(core); - - exit: -- mutex_unlock(&core->lock); -+ iris_release_core_lock(core); - - return ret; - } -@@ -340,7 +341,7 @@ static int __maybe_unused iris_pm_resume(struct device *dev) - - core = dev_get_drvdata(dev); - -- mutex_lock(&core->lock); -+ iris_acquire_core_lock(core); - if (core->state != IRIS_CORE_INIT) - goto exit; - -@@ -348,7 +349,7 @@ static int __maybe_unused iris_pm_resume(struct device *dev) - pm_runtime_mark_last_busy(core->dev); - - exit: -- mutex_unlock(&core->lock); -+ iris_release_core_lock(core); - - return ret; - } -diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c -index 6d33394..5695071 100644 ---- a/drivers/media/platform/qcom/iris/iris_resources.c -+++ b/drivers/media/platform/qcom/iris/iris_resources.c -@@ -16,6 +16,22 @@ - - #define BW_THRESHOLD 50000 - -+void iris_acquire_core_lock(struct iris_core *core) -+{ -+ mutex_lock(&core->lock); -+ -+ while (READ_ONCE(core->irq_disabling)) { -+ mutex_unlock(&core->lock); -+ wait_event(core->irq_disable_waitqueue, !READ_ONCE(core->irq_disabling)); -+ mutex_lock(&core->lock); -+ } -+} -+ -+void iris_release_core_lock(struct iris_core *core) -+{ -+ mutex_unlock(&core->lock); -+} -+ - int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw) - { - unsigned long bw_kbps = 0, bw_prev = 0; -diff --git a/drivers/media/platform/qcom/iris/iris_resources.h b/drivers/media/platform/qcom/iris/iris_resources.h -index 6bfbd2d..6e1a5e7 100644 ---- a/drivers/media/platform/qcom/iris/iris_resources.h -+++ b/drivers/media/platform/qcom/iris/iris_resources.h -@@ -8,6 +8,8 @@ - - struct iris_core; - -+void iris_acquire_core_lock(struct iris_core *core); -+void iris_release_core_lock(struct iris_core *core); - int iris_opp_set_rate(struct device *dev, unsigned long freq); - int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev); - int iris_disable_power_domains(struct iris_core *core, struct device *pd_dev); -diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c -index 2a63035..a8f7541 100644 ---- a/drivers/media/platform/qcom/iris/iris_vpu_common.c -+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c -@@ -229,15 +229,25 @@ void iris_vpu_power_off_hw(struct iris_core *core) - iris_disable_unprepare_clock(core, IRIS_HW_CLK); - } - -+static void iris_vpu_disable_irq(struct iris_core *core) -+{ -+ WRITE_ONCE(core->irq_disabling, true); -+ mutex_unlock(&core->lock); -+ disable_irq(core->irq); -+ mutex_lock(&core->lock); -+ WRITE_ONCE(core->irq_disabling, false); -+ wake_up_all(&core->irq_disable_waitqueue); -+} -+ - void iris_vpu_power_off(struct iris_core *core) - { -+ if (!iris_vpu_watchdog(core, core->intr_status)) -+ iris_vpu_disable_irq(core); -+ - iris_opp_set_rate(core->dev, 0); - core->iris_platform_data->vpu_ops->power_off_hw(core); - core->iris_platform_data->vpu_ops->power_off_controller(core); - iris_unset_icc_bw(core); -- -- if (!iris_vpu_watchdog(core, core->intr_status)) -- disable_irq_nosync(core->irq); - } - - int iris_vpu_power_on_controller(struct iris_core *core) diff --git a/kernel/2100-irqchip-qcom-pdc-Restructure-version-support.patch b/kernel/2100-irqchip-qcom-pdc-Restructure-version-support.patch deleted file mode 100644 index 28acaa1..0000000 --- a/kernel/2100-irqchip-qcom-pdc-Restructure-version-support.patch +++ /dev/null @@ -1,449 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Maulik Shah -Date: Tue, 7 Jul 2026 14:51:33 +0530 -Subject: [PATCH] irqchip/qcom-pdc: Restructure version support - -The PDC irqchip driver updates IRQ_ENABLE and IRQ_CFG for three different -versions v2.7, v3.0 and v3.2. These registers are organized in hardware as -below on various SoCs: - -+---------------------------------------------------------------+ -| SM8350, SM8450 | SM8550, Hamoa | SM8650, SM8750 | -|---------------------------------------------------------------| -| v2.7 | v3.0 | v3.2 | -|---------------------------------------------------------------| -| IRQ_ENABLE_BANK | IRQ_ENABLE_BANK | NA | -|---------------------------------------------------------------| -| IRQ_CFG | IRQ_CFG | IRQ_CFG | -| | | | -| | | [31:6] Unused | -| | [31:5] Unused | [5] GPIO_STATUS | -| | [4] GPIO_STATUS| [4] GPIO_MASK | -| [31:3] Unused | [3] GPIO_MASK | [3] IRQ_ENABLE | -| [0:2] Type | [0:2] Type | [0:2] Type | -+---------------------------------------------------------------| - -All SoCs PDC chips support "pass through mode" in which all interrupts are -forwarded to the GIC without any latching in the PDC hardware. - -So far the driver did not utilize GPIO_STATUS and GPIO_MASK from IRQ_CFG -register for v3.0 and v3.2 since they are only needed to be configured when -PDC runs in a specific mode named "second level interrupt controller". In -that mode it can latch the GPIO interrupts in GPIO_STATUS and forward GPIO -interrupts to GIC as LEVEL_HIGH type SPI interrupt. - -All the SoCs defaulted to pass through mode with the exception of some x1e -types. x1e PDC may be set to secondary controller mode for builds on CRD -boards whereas it may be set to pass through mode for IoT-EVK boards. - -Restructure in preparation to add the second level interrupt controller -mode utilizing GPIO_STATUS and GPIO_MASK bits which changed the bit -positions between v3.0 and v3.2. - -No functional change intended. - -[ tglx: Massaged change log ] - -Signed-off-by: Maulik Shah -Signed-off-by: Thomas Gleixner -Reviewed-by: Konrad Dybcio -Link: https://patch.msgid.link/20260707-hamoa_pdc_v3-v4-1-dfd1f4a3ae89@oss.qualcomm.com -(cherry picked from commit 83e089ef0d4e045efa743dcbc8de5ea0a9e4195d) ---- - drivers/irqchip/qcom-pdc.c | 224 +++++++++++++++++++++++++------------ - 1 file changed, 154 insertions(+), 70 deletions(-) - -diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c -index 2014dbb0bc43..3d272a8e506e 100644 ---- a/drivers/irqchip/qcom-pdc.c -+++ b/drivers/irqchip/qcom-pdc.c -@@ -21,21 +21,12 @@ - #include - #include - --#define PDC_MAX_GPIO_IRQS 256 --#define PDC_DRV_SIZE 0x10000 -- --/* Valid only on HW version < 3.2 */ --#define IRQ_ENABLE_BANK 0x10 --#define IRQ_ENABLE_BANK_MAX (IRQ_ENABLE_BANK + BITS_TO_BYTES(PDC_MAX_GPIO_IRQS)) -+#define PDC_MAX_IRQS 256 -+#define IRQ_ENABLE_BANK_MAX BITS_TO_BYTES(PDC_MAX_IRQS) - #define IRQ_ENABLE_BANK_INDEX_MASK GENMASK(31, 5) - #define IRQ_ENABLE_BANK_BIT_MASK GENMASK(4, 0) --#define IRQ_i_CFG 0x110 -- --/* Valid only on HW version >= 3.2 */ --#define IRQ_i_CFG_IRQ_ENABLE 3 -- --#define IRQ_i_CFG_TYPE_MASK GENMASK(2, 0) - -+#define PDC_DRV_SIZE 0x10000 - #define PDC_VERSION_REG 0x1000 - #define PDC_VERSION_MAJOR GENMASK(23, 16) - #define PDC_VERSION_MINOR GENMASK(15, 8) -@@ -46,22 +37,113 @@ - - /* Notable PDC versions */ - #define PDC_VERSION_3_2 PDC_VERSION(3, 2, 0) -+#define PDC_VERSION_3_0 PDC_VERSION(3, 0, 0) -+#define PDC_VERSION_2_7 PDC_VERSION(2, 7, 0) -+ -+/* -+ * PDC Hardware registers layout per version: -+ * -+ * IRQ_ENABLE_BANK[b], b = 0....BITS_TO_BYTES(PDC_MAX_IRQS) -+ * IRQ_CFG[n], n = 0....PDC_MAX_IRQS -+ * -+ * +---------------------------------------------------------------+ -+ * | v2.7 | v3.0 | v3.2 | -+ * |---------------------------------------------------------------| -+ * | BASE | BASE | BASE | -+ * |---------------------------------------------------------------| -+ * | | -+ * | IRQ_ENABLE_BANK | IRQ_ENABLE_BANK | NA | -+ * |---------------------------------------------------------------| -+ * | IRQ_CFG | IRQ_CFG | IRQ_CFG | -+ * | | | | -+ * | | | [31:6] Unused | -+ * | | [31:5] Unused | [5] GPIO_STATUS | -+ * | | [4] GPIO_STATUS| [4] GPIO_MASK | -+ * | [31:3] Unused | [3] GPIO_MASK | [3] IRQ_ENABLE | -+ * | [0:2] Type | [0:2] Type | [0:2] Type | -+ * +---------------------------------------------------------------+ -+ */ -+ -+/** -+ * struct pdc_regs: PDC registers location -+ * -+ * @irq_en_reg: IRQ_ENABLE_BANK register location -+ * @irq_cfg_reg: IRQ_CFG register location -+ */ -+struct pdc_regs { -+ u32 irq_en_reg; -+ u32 irq_cfg_reg; -+}; -+ -+/** -+ * struct pdc_irq_cfg: bit fields for PDC IRQ_CFG register -+ * -+ * @irq_enable: bit number for IRQ_ENABLE field -+ * @irq_type: GENMASK for IRQ_TYPE field -+ */ -+struct pdc_irq_cfg { -+ u32 irq_enable; -+ u32 irq_type; -+}; -+ -+/** -+ * struct pdc_desc: PDC driver state -+ * -+ * @base: PDC base register for DRV2 / HLOS -+ * @prev_base: PDC DRV1 base, applicable only for x1e RTL bug. -+ * @version: PDC version -+ * @regs: PDC regs (IRQ_ENABLE_BANK and IRQ_CFG) -+ * @cfg_fields: Fields of IRQ_CFG reg -+ */ -+struct pdc_desc { -+ void __iomem *base; -+ void __iomem *prev_base; -+ u32 version; -+ const struct pdc_regs *regs; -+ const struct pdc_irq_cfg *cfg_fields; -+}; -+ -+static const struct pdc_regs pdc_v3_2 = { -+ .irq_cfg_reg = 0x110, -+}; -+ -+static const struct pdc_irq_cfg pdc_cfg_v3_2 = { -+ .irq_enable = 3, -+ .irq_type = GENMASK(2, 0), -+}; -+ -+static const struct pdc_regs pdc_v3_0 = { -+ .irq_en_reg = 0x10, -+ .irq_cfg_reg = 0x110, -+}; -+ -+static const struct pdc_irq_cfg pdc_cfg_v3_0 = { -+ .irq_type = GENMASK(2, 0), -+}; -+ -+static const struct pdc_regs pdc_v2_7 = { -+ .irq_en_reg = 0x10, -+ .irq_cfg_reg = 0x110, -+}; -+ -+static const struct pdc_irq_cfg pdc_cfg_v2_7 = { -+ .irq_type = GENMASK(2, 0), -+}; - - struct pdc_pin_region { -- u32 pin_base; -- u32 parent_base; -- u32 cnt; -+ u32 pin_base; -+ u32 parent_base; -+ u32 cnt; - }; - - #define pin_to_hwirq(r, p) ((r)->parent_base + (p) - (r)->pin_base) - - static DEFINE_RAW_SPINLOCK(pdc_lock); --static void __iomem *pdc_base; --static void __iomem *pdc_prev_base; - static struct pdc_pin_region *pdc_region; - static int pdc_region_cnt; - static unsigned int pdc_version; - static bool pdc_x1e_quirk; -+static struct pdc_desc *pdc; - - static void pdc_base_reg_write(void __iomem *base, int reg, u32 i, u32 val) - { -@@ -70,12 +152,12 @@ static void pdc_base_reg_write(void __iomem *base, int reg, u32 i, u32 val) - - static void pdc_reg_write(int reg, u32 i, u32 val) - { -- pdc_base_reg_write(pdc_base, reg, i, val); -+ pdc_base_reg_write(pdc->base, reg, i, val); - } - - static u32 pdc_reg_read(int reg, u32 i) - { -- return readl_relaxed(pdc_base + reg + i * sizeof(u32)); -+ return readl_relaxed(pdc->base + reg + i * sizeof(u32)); - } - - static void pdc_x1e_irq_enable_write(u32 bank, u32 enable) -@@ -86,24 +168,24 @@ static void pdc_x1e_irq_enable_write(u32 bank, u32 enable) - switch (bank) { - case 0 ... 1: - /* Use previous DRV (client) region and shift to bank 3-4 */ -- base = pdc_prev_base; -+ base = pdc->prev_base; - bank += 3; - break; - case 2 ... 4: - /* Use our own region and shift to bank 0-2 */ -- base = pdc_base; -+ base = pdc->base; - bank -= 2; - break; - case 5: - /* No fixup required for bank 5 */ -- base = pdc_base; -+ base = pdc->base; - break; - default: - WARN_ON(1); - return; - } - -- pdc_base_reg_write(base, IRQ_ENABLE_BANK, bank, enable); -+ pdc_base_reg_write(base, pdc->regs->irq_en_reg, bank, enable); - } - - static void pdc_enable_intr_bank(int pin_out, bool on) -@@ -114,21 +196,21 @@ static void pdc_enable_intr_bank(int pin_out, bool on) - index = FIELD_GET(IRQ_ENABLE_BANK_INDEX_MASK, pin_out); - mask = FIELD_GET(IRQ_ENABLE_BANK_BIT_MASK, pin_out); - -- enable = pdc_reg_read(IRQ_ENABLE_BANK, index); -+ enable = pdc_reg_read(pdc->regs->irq_en_reg, index); - __assign_bit(mask, &enable, on); - - if (pdc_x1e_quirk) - pdc_x1e_irq_enable_write(index, enable); - else -- pdc_reg_write(IRQ_ENABLE_BANK, index, enable); -+ pdc_reg_write(pdc->regs->irq_en_reg, index, enable); - } - - static void pdc_enable_intr_cfg(int pin_out, bool on) - { -- unsigned long enable = pdc_reg_read(IRQ_i_CFG, pin_out); -+ unsigned long enable = pdc_reg_read(pdc->regs->irq_cfg_reg, pin_out); - -- __assign_bit(IRQ_i_CFG_IRQ_ENABLE, &enable, on); -- pdc_reg_write(IRQ_i_CFG, pin_out, enable); -+ __assign_bit(pdc->cfg_fields->irq_enable, &enable, on); -+ pdc_reg_write(pdc->regs->irq_cfg_reg, pin_out, enable); - } - - static void __pdc_enable_intr(int pin_out, bool on) -@@ -224,9 +306,9 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) - return -EINVAL; - } - -- old_pdc_type = pdc_reg_read(IRQ_i_CFG, d->hwirq); -- pdc_type |= (old_pdc_type & ~IRQ_i_CFG_TYPE_MASK); -- pdc_reg_write(IRQ_i_CFG, d->hwirq, pdc_type); -+ old_pdc_type = pdc_reg_read(pdc->regs->irq_cfg_reg, d->hwirq); -+ pdc_type |= (old_pdc_type & ~pdc->cfg_fields->irq_type); -+ pdc_reg_write(pdc->regs->irq_cfg_reg, d->hwirq, pdc_type); - - ret = irq_chip_set_type_parent(d, type); - if (ret) -@@ -317,8 +399,7 @@ static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq, - parent_fwspec.param[1] = pin_to_hwirq(region, hwirq); - parent_fwspec.param[2] = type; - -- return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, -- &parent_fwspec); -+ return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); - } - - static const struct irq_domain_ops qcom_pdc_ops = { -@@ -327,8 +408,9 @@ static const struct irq_domain_ops qcom_pdc_ops = { - .free = irq_domain_free_irqs_common, - }; - --static int pdc_setup_pin_mapping(struct device_node *np) -+static int pdc_setup_pin_mapping(struct device *dev) - { -+ struct device_node *np = dev->of_node; - int ret, n, i; - - n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32)); -@@ -336,25 +418,22 @@ static int pdc_setup_pin_mapping(struct device_node *np) - return -EINVAL; - - pdc_region_cnt = n / 3; -- pdc_region = kzalloc_objs(*pdc_region, pdc_region_cnt); -+ pdc_region = devm_kcalloc(dev, pdc_region_cnt, sizeof(*pdc_region), GFP_KERNEL); - if (!pdc_region) { - pdc_region_cnt = 0; - return -ENOMEM; - } - - for (n = 0; n < pdc_region_cnt; n++) { -- ret = of_property_read_u32_index(np, "qcom,pdc-ranges", -- n * 3 + 0, -+ ret = of_property_read_u32_index(np, "qcom,pdc-ranges", n * 3 + 0, - &pdc_region[n].pin_base); - if (ret) - return ret; -- ret = of_property_read_u32_index(np, "qcom,pdc-ranges", -- n * 3 + 1, -+ ret = of_property_read_u32_index(np, "qcom,pdc-ranges", n * 3 + 1, - &pdc_region[n].parent_base); - if (ret) - return ret; -- ret = of_property_read_u32_index(np, "qcom,pdc-ranges", -- n * 3 + 2, -+ ret = of_property_read_u32_index(np, "qcom,pdc-ranges", n * 3 + 2, - &pdc_region[n].cnt); - if (ret) - return ret; -@@ -366,11 +445,11 @@ static int pdc_setup_pin_mapping(struct device_node *np) - return 0; - } - -- - static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *parent) - { - struct irq_domain *parent_domain, *pdc_domain; - struct device_node *node = pdev->dev.of_node; -+ struct device *dev = &pdev->dev; - resource_size_t res_size; - struct resource res; - int ret; -@@ -383,6 +462,29 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - if (res_size > resource_size(&res)) - pr_warn("%pOF: invalid reg size, please fix DT\n", node); - -+ pdc = devm_kzalloc(dev, sizeof(*pdc), GFP_KERNEL); -+ if (!pdc) -+ return -ENOMEM; -+ -+ pdc->base = devm_ioremap(dev, res.start, res_size); -+ if (!pdc->base) { -+ pr_err("%pOF: unable to map PDC registers\n", node); -+ return -ENXIO; -+ } -+ -+ pdc->version = pdc_reg_read(PDC_VERSION_REG, 0); -+ -+ if (pdc->version >= PDC_VERSION_3_2) { -+ pdc->cfg_fields = &pdc_cfg_v3_2; -+ pdc->regs = &pdc_v3_2; -+ } else if (pdc->version >= PDC_VERSION_3_0) { -+ pdc->cfg_fields = &pdc_cfg_v3_0; -+ pdc->regs = &pdc_v3_0; -+ } else { -+ pdc->cfg_fields = &pdc_cfg_v2_7; -+ pdc->regs = &pdc_v2_7; -+ } -+ - /* - * PDC has multiple DRV regions, each one provides the same set of - * registers for a particular client in the system. Due to a hardware -@@ -392,8 +494,9 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - * region with the expected offset to preserve support for old DTs. - */ - if (of_device_is_compatible(node, "qcom,x1e80100-pdc")) { -- pdc_prev_base = ioremap(res.start - PDC_DRV_SIZE, IRQ_ENABLE_BANK_MAX); -- if (!pdc_prev_base) { -+ pdc->prev_base = devm_ioremap(dev, res.start - PDC_DRV_SIZE, -+ pdc->regs->irq_en_reg + IRQ_ENABLE_BANK_MAX); -+ if (!pdc->prev_base) { - pr_err("%pOF: unable to map previous PDC DRV region\n", node); - return -ENXIO; - } -@@ -401,48 +504,29 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - pdc_x1e_quirk = true; - } - -- pdc_base = ioremap(res.start, res_size); -- if (!pdc_base) { -- pr_err("%pOF: unable to map PDC registers\n", node); -- ret = -ENXIO; -- goto fail; -- } -- -- pdc_version = pdc_reg_read(PDC_VERSION_REG, 0); -- - parent_domain = irq_find_host(parent); - if (!parent_domain) { - pr_err("%pOF: unable to find PDC's parent domain\n", node); -- ret = -ENXIO; -- goto fail; -+ return -ENXIO; - } - -- ret = pdc_setup_pin_mapping(node); -+ ret = pdc_setup_pin_mapping(dev); - if (ret) { - pr_err("%pOF: failed to init PDC pin-hwirq mapping\n", node); -- goto fail; -+ return ret; - } - -- pdc_domain = irq_domain_create_hierarchy(parent_domain, -- IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP, -- PDC_MAX_GPIO_IRQS, -- of_fwnode_handle(node), -- &qcom_pdc_ops, NULL); -+ pdc_domain = irq_domain_create_hierarchy(parent_domain, IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP, -+ PDC_MAX_IRQS, of_fwnode_handle(node), -+ &qcom_pdc_ops, NULL); - if (!pdc_domain) { - pr_err("%pOF: PDC domain add failed\n", node); -- ret = -ENOMEM; -- goto fail; -+ return -ENOMEM; - } - - irq_domain_update_bus_token(pdc_domain, DOMAIN_BUS_WAKEUP); - - return 0; -- --fail: -- kfree(pdc_region); -- iounmap(pdc_base); -- iounmap(pdc_prev_base); -- return ret; - } - - IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc) diff --git a/kernel/2101-irqchip-qcom-pdc-Move-all-static-variables-to-struct.patch b/kernel/2101-irqchip-qcom-pdc-Move-all-static-variables-to-struct.patch deleted file mode 100644 index 16accb6..0000000 --- a/kernel/2101-irqchip-qcom-pdc-Move-all-static-variables-to-struct.patch +++ /dev/null @@ -1,226 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Maulik Shah -Date: Tue, 7 Jul 2026 14:51:34 +0530 -Subject: [PATCH] irqchip/qcom-pdc: Move all static variables to struct - pdc_desc - -There are multiple static variables used in the driver. Move all to struct -pdc_desc to better align with versioning support. Document them. - -Add a new pdc->enable_intr() callback to point to the respective versions -specific enable function. Remove pdc_enable_intr() and __pdc_enable_intr() -and invoke pdc->enable_intr() from the call sites. - -Locking in pdc_enable_intr() applies lock to all version specific -pdc->enable_intr() however lock is needed only for pdc_enable_intr_bank() -which uses a shared bank across on PDC v2.7 and PDC v3.0. - -pdc_enable_intr_cfg() do not require locking as IRQ_CFG registers are one -per interrupt. Move the locking to pdc_enable_intr_bank(). - -No functional impact intended - -[ tglx: Massage change log. ] - -Signed-off-by: Maulik Shah -Signed-off-by: Thomas Gleixner -Link: https://patch.msgid.link/20260707-hamoa_pdc_v3-v4-2-dfd1f4a3ae89@oss.qualcomm.com -(cherry picked from commit 60caa95aa14aed8d05abc03b70e2ff14e5ab6820) ---- - drivers/irqchip/qcom-pdc.c | 84 +++++++++++++++++++------------------- - 1 file changed, 41 insertions(+), 43 deletions(-) - -diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c -index 3d272a8e506e..5100a10415e0 100644 ---- a/drivers/irqchip/qcom-pdc.c -+++ b/drivers/irqchip/qcom-pdc.c -@@ -92,15 +92,30 @@ struct pdc_irq_cfg { - * @base: PDC base register for DRV2 / HLOS - * @prev_base: PDC DRV1 base, applicable only for x1e RTL bug. - * @version: PDC version -+ * @region: PDC interrupt continuous range -+ * @region_cnt: Total PDC ranges -+ * @x1e_quirk: x1e H/W Bug handling -+ * @lock: lock for IRQ_ENABLE_BANK protection - * @regs: PDC regs (IRQ_ENABLE_BANK and IRQ_CFG) - * @cfg_fields: Fields of IRQ_CFG reg -+ * @enable_intr: pointer to enable function based on PDC version - */ - struct pdc_desc { - void __iomem *base; - void __iomem *prev_base; - u32 version; -+ -+ struct pdc_pin_region *region; -+ int region_cnt; -+ -+ bool x1e_quirk; -+ -+ raw_spinlock_t lock; -+ - const struct pdc_regs *regs; - const struct pdc_irq_cfg *cfg_fields; -+ -+ void (*enable_intr)(int pin_out, bool on); - }; - - static const struct pdc_regs pdc_v3_2 = { -@@ -138,11 +153,6 @@ struct pdc_pin_region { - - #define pin_to_hwirq(r, p) ((r)->parent_base + (p) - (r)->pin_base) - --static DEFINE_RAW_SPINLOCK(pdc_lock); --static struct pdc_pin_region *pdc_region; --static int pdc_region_cnt; --static unsigned int pdc_version; --static bool pdc_x1e_quirk; - static struct pdc_desc *pdc; - - static void pdc_base_reg_write(void __iomem *base, int reg, u32 i, u32 val) -@@ -196,10 +206,12 @@ static void pdc_enable_intr_bank(int pin_out, bool on) - index = FIELD_GET(IRQ_ENABLE_BANK_INDEX_MASK, pin_out); - mask = FIELD_GET(IRQ_ENABLE_BANK_BIT_MASK, pin_out); - -+ guard(raw_spinlock_irqsave)(&pdc->lock); -+ - enable = pdc_reg_read(pdc->regs->irq_en_reg, index); - __assign_bit(mask, &enable, on); - -- if (pdc_x1e_quirk) -+ if (pdc->x1e_quirk) - pdc_x1e_irq_enable_write(index, enable); - else - pdc_reg_write(pdc->regs->irq_en_reg, index, enable); -@@ -213,32 +225,15 @@ static void pdc_enable_intr_cfg(int pin_out, bool on) - pdc_reg_write(pdc->regs->irq_cfg_reg, pin_out, enable); - } - --static void __pdc_enable_intr(int pin_out, bool on) --{ -- if (pdc_version < PDC_VERSION_3_2) -- pdc_enable_intr_bank(pin_out, on); -- else -- pdc_enable_intr_cfg(pin_out, on); --} -- --static void pdc_enable_intr(struct irq_data *d, bool on) --{ -- unsigned long flags; -- -- raw_spin_lock_irqsave(&pdc_lock, flags); -- __pdc_enable_intr(d->hwirq, on); -- raw_spin_unlock_irqrestore(&pdc_lock, flags); --} -- - static void qcom_pdc_gic_disable(struct irq_data *d) - { -- pdc_enable_intr(d, false); -+ pdc->enable_intr(d->hwirq, false); - irq_chip_disable_parent(d); - } - - static void qcom_pdc_gic_enable(struct irq_data *d) - { -- pdc_enable_intr(d, true); -+ pdc->enable_intr(d->hwirq, true); - irq_chip_enable_parent(d); - } - -@@ -350,12 +345,10 @@ static struct irq_chip qcom_pdc_gic_chip = { - - static struct pdc_pin_region *get_pin_region(int pin) - { -- int i; -- -- for (i = 0; i < pdc_region_cnt; i++) { -- if (pin >= pdc_region[i].pin_base && -- pin < pdc_region[i].pin_base + pdc_region[i].cnt) -- return &pdc_region[i]; -+ for (int i = 0; i < pdc->region_cnt; i++) { -+ if (pin >= pdc->region[i].pin_base && -+ pin < pdc->region[i].pin_base + pdc->region[i].cnt) -+ return &pdc->region[i]; - } - - return NULL; -@@ -411,35 +404,35 @@ static const struct irq_domain_ops qcom_pdc_ops = { - static int pdc_setup_pin_mapping(struct device *dev) - { - struct device_node *np = dev->of_node; -- int ret, n, i; -+ int ret, n; - - n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32)); - if (n <= 0 || n % 3) - return -EINVAL; - -- pdc_region_cnt = n / 3; -- pdc_region = devm_kcalloc(dev, pdc_region_cnt, sizeof(*pdc_region), GFP_KERNEL); -- if (!pdc_region) { -- pdc_region_cnt = 0; -+ pdc->region_cnt = n / 3; -+ pdc->region = devm_kcalloc(dev, pdc->region_cnt, sizeof(*pdc->region), GFP_KERNEL); -+ if (!pdc->region) { -+ pdc->region_cnt = 0; - return -ENOMEM; - } - -- for (n = 0; n < pdc_region_cnt; n++) { -+ for (n = 0; n < pdc->region_cnt; n++) { - ret = of_property_read_u32_index(np, "qcom,pdc-ranges", n * 3 + 0, -- &pdc_region[n].pin_base); -+ &pdc->region[n].pin_base); - if (ret) - return ret; - ret = of_property_read_u32_index(np, "qcom,pdc-ranges", n * 3 + 1, -- &pdc_region[n].parent_base); -+ &pdc->region[n].parent_base); - if (ret) - return ret; - ret = of_property_read_u32_index(np, "qcom,pdc-ranges", n * 3 + 2, -- &pdc_region[n].cnt); -+ &pdc->region[n].cnt); - if (ret) - return ret; - -- for (i = 0; i < pdc_region[n].cnt; i++) -- __pdc_enable_intr(i + pdc_region[n].pin_base, 0); -+ for (int i = 0; i < pdc->region[n].cnt; i++) -+ pdc->enable_intr(i + pdc->region[n].pin_base, 0); - } - - return 0; -@@ -477,12 +470,15 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - if (pdc->version >= PDC_VERSION_3_2) { - pdc->cfg_fields = &pdc_cfg_v3_2; - pdc->regs = &pdc_v3_2; -+ pdc->enable_intr = pdc_enable_intr_cfg; - } else if (pdc->version >= PDC_VERSION_3_0) { - pdc->cfg_fields = &pdc_cfg_v3_0; - pdc->regs = &pdc_v3_0; -+ pdc->enable_intr = pdc_enable_intr_bank; - } else { - pdc->cfg_fields = &pdc_cfg_v2_7; - pdc->regs = &pdc_v2_7; -+ pdc->enable_intr = pdc_enable_intr_bank; - } - - /* -@@ -501,7 +497,7 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - return -ENXIO; - } - -- pdc_x1e_quirk = true; -+ pdc->x1e_quirk = true; - } - - parent_domain = irq_find_host(parent); -@@ -510,6 +506,8 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - return -ENXIO; - } - -+ raw_spin_lock_init(&pdc->lock); -+ - ret = pdc_setup_pin_mapping(dev); - if (ret) { - pr_err("%pOF: failed to init PDC pin-hwirq mapping\n", node); diff --git a/kernel/2102-irqchip-qcom-pdc-Differentiate-between-direct-SPI-an.patch b/kernel/2102-irqchip-qcom-pdc-Differentiate-between-direct-SPI-an.patch deleted file mode 100644 index 179c35f..0000000 --- a/kernel/2102-irqchip-qcom-pdc-Differentiate-between-direct-SPI-an.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Maulik Shah -Date: Tue, 7 Jul 2026 14:51:35 +0530 -Subject: [PATCH] irqchip/qcom-pdc: Differentiate between direct SPI and GPIO - as SPI - -Before commit 4dc70713dc24 ("irqchip/qcom-pdc: Kill non-wakeup irqdomain") -there were separate domains for direct SPIs and GPIOs used as SPIs. - -Separate domains can be useful to have separate interrupt chips for -different functionalities. Since the commit unified both domains there -is no way to differentiate. - -In preparation to add the second level interrupt controller support where -GPIO interrupts get latched at PDC (but not direct SPIs) there is a need to -differentiate between SPIs and GPIOs as SPIs. Reverting above commit does -is not a good option as it leads to waste of resources. - -PDC hardware provides the IRQ_PARAM register to enumerate the number of -direct SPIs and the number of GPIOs as SPIs. Further PDC allocates direct -SPIs at the beginning and all GPIOs as SPIs are allocated at the end. This -information can be used in the driver to differentiate them. - -Add the support to read this register and keep this information in struct -pdc_desc. Later change utilizes it. - -[ tglx: Massage change log ] - -Signed-off-by: Maulik Shah -Signed-off-by: Thomas Gleixner -Link: https://patch.msgid.link/20260707-hamoa_pdc_v3-v4-3-dfd1f4a3ae89@oss.qualcomm.com -(cherry picked from commit 45af2d61edf62938b021b86439a1dd797fd74a91) ---- - drivers/irqchip/qcom-pdc.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c -index 5100a10415e0..253fb69e7ef2 100644 ---- a/drivers/irqchip/qcom-pdc.c -+++ b/drivers/irqchip/qcom-pdc.c -@@ -61,6 +61,11 @@ - * | | [4] GPIO_STATUS| [4] GPIO_MASK | - * | [31:3] Unused | [3] GPIO_MASK | [3] IRQ_ENABLE | - * | [0:2] Type | [0:2] Type | [0:2] Type | -+ * |---------------------------------------------------------------| -+ * | IRQ_PARAM | IRQ_PARAM | IRQ_PARAM | -+ * | | | -+ * | [15:8] NUM_GPIO | [15:8] NUM_GPIO | [15:8] NUM_GPIO | -+ * | [7:0] NUM_SPI | [7:0] NUM_SPI | [7:0] NUM_SPI | - * +---------------------------------------------------------------+ - */ - -@@ -69,10 +74,12 @@ - * - * @irq_en_reg: IRQ_ENABLE_BANK register location - * @irq_cfg_reg: IRQ_CFG register location -+ * @irq_param_reg: IRQ_PARAM register location - */ - struct pdc_regs { - u32 irq_en_reg; - u32 irq_cfg_reg; -+ u32 irq_param_reg; - }; - - /** -@@ -92,6 +99,7 @@ struct pdc_irq_cfg { - * @base: PDC base register for DRV2 / HLOS - * @prev_base: PDC DRV1 base, applicable only for x1e RTL bug. - * @version: PDC version -+ * @num_spis: Total number of direct SPI interrupts - * @region: PDC interrupt continuous range - * @region_cnt: Total PDC ranges - * @x1e_quirk: x1e H/W Bug handling -@@ -104,6 +112,7 @@ struct pdc_desc { - void __iomem *base; - void __iomem *prev_base; - u32 version; -+ u32 num_spis; - - struct pdc_pin_region *region; - int region_cnt; -@@ -120,6 +129,7 @@ struct pdc_desc { - - static const struct pdc_regs pdc_v3_2 = { - .irq_cfg_reg = 0x110, -+ .irq_param_reg = 0x100c, - }; - - static const struct pdc_irq_cfg pdc_cfg_v3_2 = { -@@ -130,6 +140,7 @@ static const struct pdc_irq_cfg pdc_cfg_v3_2 = { - static const struct pdc_regs pdc_v3_0 = { - .irq_en_reg = 0x10, - .irq_cfg_reg = 0x110, -+ .irq_param_reg = 0x100c, - }; - - static const struct pdc_irq_cfg pdc_cfg_v3_0 = { -@@ -139,6 +150,7 @@ static const struct pdc_irq_cfg pdc_cfg_v3_0 = { - static const struct pdc_regs pdc_v2_7 = { - .irq_en_reg = 0x10, - .irq_cfg_reg = 0x110, -+ .irq_param_reg = 0x100c, - }; - - static const struct pdc_irq_cfg pdc_cfg_v2_7 = { -@@ -445,6 +457,7 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - struct device *dev = &pdev->dev; - resource_size_t res_size; - struct resource res; -+ u32 irq_param; - int ret; - - /* compat with old sm8150 DT which had very small region for PDC */ -@@ -500,6 +513,9 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - pdc->x1e_quirk = true; - } - -+ irq_param = pdc_reg_read(pdc->regs->irq_param_reg, 0); -+ pdc->num_spis = FIELD_GET(GENMASK(7, 0), irq_param); -+ - parent_domain = irq_find_host(parent); - if (!parent_domain) { - pr_err("%pOF: unable to find PDC's parent domain\n", node); diff --git a/kernel/2103-irqchip-qcom-pdc-Configure-PDC-to-pass-through-mode.patch b/kernel/2103-irqchip-qcom-pdc-Configure-PDC-to-pass-through-mode.patch deleted file mode 100644 index 9a37261..0000000 --- a/kernel/2103-irqchip-qcom-pdc-Configure-PDC-to-pass-through-mode.patch +++ /dev/null @@ -1,436 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Maulik Shah -Date: Tue, 7 Jul 2026 14:51:36 +0530 -Subject: [PATCH] irqchip/qcom-pdc: Configure PDC to pass through mode - -All PDC hardware versions support pass-through mode in which both Direct -SPIs and GPIO interrupts (as SPIs) are sent to the GIC without latching at -the PDC level. - -Newer PDCs (v3.0 onwards) also support an additional secondary controller -mode where PDC latches the GPIO interrupts and sends them to the GIC as -level type interrupts. Direct SPIs works the same as pass-through mode -without latching at PDC even in secondary controller mode. - -All the SoCs use pass-through mode with the exception of x1e. The x1e PDC -may be set to secondary controller mode for builds on CRD boards whereas it -may be set to pass through mode for IoT-EVK boards. The mode configuration -is done in firmware and initially shipped windows firmware did not have a -SCM interface to read or modify the PDC mode. Only later write access was -opened up for the non-secure world. The availability of write access can be -probed. - -Therefore try to modify the to modify the PDC mode to pass-through mode via -SCM write. When the write fails on older firmware assume it to work in -secondary mode. - -In secondary mode set the separate irqchip for the GPIOs to perform -additional operations only for the GPIO interrupts. - -[ tglx: Massage change log ] - -Co-developed-by: Sneh Mankad -Signed-off-by: Sneh Mankad -Signed-off-by: Maulik Shah -Signed-off-by: Thomas Gleixner -Link: https://patch.msgid.link/20260707-hamoa_pdc_v3-v4-4-dfd1f4a3ae89@oss.qualcomm.com -(cherry picked from commit ad01c2b2f29163ca0bbe1fd4f9343fbc5119c239) ---- - drivers/irqchip/qcom-pdc.c | 240 +++++++++++++++++++++++++++++++++++-- - 1 file changed, 227 insertions(+), 13 deletions(-) - -diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c -index 253fb69e7ef2..f38ee74b0397 100644 ---- a/drivers/irqchip/qcom-pdc.c -+++ b/drivers/irqchip/qcom-pdc.c -@@ -20,12 +20,18 @@ - #include - #include - #include -+#include - - #define PDC_MAX_IRQS 256 - #define IRQ_ENABLE_BANK_MAX BITS_TO_BYTES(PDC_MAX_IRQS) - #define IRQ_ENABLE_BANK_INDEX_MASK GENMASK(31, 5) - #define IRQ_ENABLE_BANK_BIT_MASK GENMASK(4, 0) - -+/* Secure DRV register to configure the PDC mode via qcom_scm_io_writel() */ -+#define PDC_GPIO_INT_CTL_ENABLE 0xb2045e8 -+#define PDC_PASS_THROUGH_MODE 0x0 -+#define PDC_SECONDARY_MODE 0x1 -+ - #define PDC_DRV_SIZE 0x10000 - #define PDC_VERSION_REG 0x1000 - #define PDC_VERSION_MAJOR GENMASK(23, 16) -@@ -85,10 +91,14 @@ struct pdc_regs { - /** - * struct pdc_irq_cfg: bit fields for PDC IRQ_CFG register - * -+ * @gpio_irq_sts: bit number for GPIO_STATUS field -+ * @gpio_irq_mask: bit number for GPIO_MASK field - * @irq_enable: bit number for IRQ_ENABLE field - * @irq_type: GENMASK for IRQ_TYPE field - */ - struct pdc_irq_cfg { -+ u32 gpio_irq_sts; -+ u32 gpio_irq_mask; - u32 irq_enable; - u32 irq_type; - }; -@@ -102,11 +112,14 @@ struct pdc_irq_cfg { - * @num_spis: Total number of direct SPI interrupts - * @region: PDC interrupt continuous range - * @region_cnt: Total PDC ranges -+ * @mode: PDC_PASS_THROUGH_MODE or PDC_SECONDARY_MODE - * @x1e_quirk: x1e H/W Bug handling - * @lock: lock for IRQ_ENABLE_BANK protection - * @regs: PDC regs (IRQ_ENABLE_BANK and IRQ_CFG) - * @cfg_fields: Fields of IRQ_CFG reg - * @enable_intr: pointer to enable function based on PDC version -+ * @unmask_gpio: pointer to GPIO irq unmask function -+ * @clear_gpio: pointer to GPIO irq clear function - */ - struct pdc_desc { - void __iomem *base; -@@ -119,12 +132,15 @@ struct pdc_desc { - - bool x1e_quirk; - -+ u8 mode; - raw_spinlock_t lock; - - const struct pdc_regs *regs; - const struct pdc_irq_cfg *cfg_fields; - - void (*enable_intr)(int pin_out, bool on); -+ void (*unmask_gpio)(int pin_out, bool on); -+ void (*clear_gpio)(int pin_out); - }; - - static const struct pdc_regs pdc_v3_2 = { -@@ -133,6 +149,8 @@ static const struct pdc_regs pdc_v3_2 = { - }; - - static const struct pdc_irq_cfg pdc_cfg_v3_2 = { -+ .gpio_irq_sts = 5, -+ .gpio_irq_mask = 4, - .irq_enable = 3, - .irq_type = GENMASK(2, 0), - }; -@@ -144,6 +162,8 @@ static const struct pdc_regs pdc_v3_0 = { - }; - - static const struct pdc_irq_cfg pdc_cfg_v3_0 = { -+ .gpio_irq_sts = 4, -+ .gpio_irq_mask = 3, - .irq_type = GENMASK(2, 0), - }; - -@@ -182,6 +202,15 @@ static u32 pdc_reg_read(int reg, u32 i) - return readl_relaxed(pdc->base + reg + i * sizeof(u32)); - } - -+static inline bool pdc_pin_is_gpio(int pin_out) -+{ -+ /* -+ * PDC allocates direct SPIs at the beginning and -+ * all GPIOs as SPIs are allocated after direct SPIs. -+ */ -+ return pin_out >= pdc->num_spis; -+} -+ - static void pdc_x1e_irq_enable_write(u32 bank, u32 enable) - { - void __iomem *base; -@@ -229,6 +258,24 @@ static void pdc_enable_intr_bank(int pin_out, bool on) - pdc_reg_write(pdc->regs->irq_en_reg, index, enable); - } - -+static void pdc_clear_gpio_cfg(int pin_out) -+{ -+ unsigned long gpio_sts; -+ -+ gpio_sts = pdc_reg_read(pdc->regs->irq_cfg_reg, pin_out); -+ __clear_bit(pdc->cfg_fields->gpio_irq_sts, &gpio_sts); -+ pdc_reg_write(pdc->regs->irq_cfg_reg, pin_out, gpio_sts); -+} -+ -+static void pdc_unmask_gpio_cfg(int pin_out, bool unmask) -+{ -+ unsigned long gpio_mask; -+ -+ gpio_mask = pdc_reg_read(pdc->regs->irq_cfg_reg, pin_out); -+ __assign_bit(pdc->cfg_fields->gpio_irq_mask, &gpio_mask, !unmask); -+ pdc_reg_write(pdc->regs->irq_cfg_reg, pin_out, gpio_mask); -+} -+ - static void pdc_enable_intr_cfg(int pin_out, bool on) - { - unsigned long enable = pdc_reg_read(pdc->regs->irq_cfg_reg, pin_out); -@@ -237,6 +284,13 @@ static void pdc_enable_intr_cfg(int pin_out, bool on) - pdc_reg_write(pdc->regs->irq_cfg_reg, pin_out, enable); - } - -+static void qcom_pdc_gic_secondary_disable(struct irq_data *d) -+{ -+ pdc->enable_intr(d->hwirq, false); -+ pdc->unmask_gpio(d->hwirq, false); -+ irq_chip_disable_parent(d); -+} -+ - static void qcom_pdc_gic_disable(struct irq_data *d) - { - pdc->enable_intr(d->hwirq, false); -@@ -249,6 +303,41 @@ static void qcom_pdc_gic_enable(struct irq_data *d) - irq_chip_enable_parent(d); - } - -+static void qcom_pdc_gic_secondary_enable(struct irq_data *d) -+{ -+ pdc->enable_intr(d->hwirq, true); -+ pdc->unmask_gpio(d->hwirq, true); -+ irq_chip_enable_parent(d); -+} -+ -+static void qcom_pdc_secondary_ack(struct irq_data *d) -+{ -+ if (!irqd_is_level_type(d)) -+ pdc->clear_gpio(d->hwirq); -+} -+ -+static void qcom_pdc_gic_secondary_eoi(struct irq_data *d) -+{ -+ if (irqd_is_level_type(d)) -+ pdc->clear_gpio(d->hwirq); -+ -+ irq_chip_eoi_parent(d); -+} -+ -+static void qcom_pdc_secondary_mask(struct irq_data *d) -+{ -+ pdc->enable_intr(d->hwirq, false); -+ pdc->unmask_gpio(d->hwirq, false); -+ irq_chip_mask_parent(d); -+} -+ -+static void qcom_pdc_secondary_unmask(struct irq_data *d) -+{ -+ pdc->enable_intr(d->hwirq, true); -+ pdc->unmask_gpio(d->hwirq, true); -+ irq_chip_unmask_parent(d); -+} -+ - /* - * GIC does not handle falling edge or active low. To allow falling edge and - * active low interrupts to be handled at GIC, PDC has an inverter that inverts -@@ -275,18 +364,18 @@ enum pdc_irq_config_bits { - /** - * qcom_pdc_gic_set_type: Configure PDC for the interrupt - * -- * @d: the interrupt data -+ * @d: the interrupt data - * @type: the interrupt type - * -- * If @type is edge triggered, forward that as Rising edge as PDC -- * takes care of converting falling edge to rising edge signal -+ * If @type is edge triggered, forward that as rising edge as PDC -+ * takes care of converting all edge types to rising edge signal - * If @type is level, then forward that as level high as PDC -- * takes care of converting falling edge to rising edge signal -+ * takes care of converting all level types to level high signal - */ - static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) - { -- enum pdc_irq_config_bits pdc_type; - enum pdc_irq_config_bits old_pdc_type; -+ enum pdc_irq_config_bits pdc_type; - int ret; - - switch (type) { -@@ -336,6 +425,72 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) - return 0; - } - -+/** -+ * qcom_pdc_gic_set_type: Configure PDC for the interrupt -+ * -+ * @d: the interrupt data -+ * @type: the interrupt type -+ * -+ * All @type are forwarded as level high type to parent GIC -+ */ -+static int qcom_pdc_gic_secondary_set_type(struct irq_data *d, unsigned int type) -+{ -+ enum pdc_irq_config_bits old_pdc_type; -+ enum pdc_irq_config_bits pdc_type; -+ int ret; -+ -+ switch (type) { -+ case IRQ_TYPE_EDGE_RISING: -+ pdc_type = PDC_EDGE_RISING; -+ break; -+ case IRQ_TYPE_EDGE_FALLING: -+ pdc_type = PDC_EDGE_FALLING; -+ break; -+ case IRQ_TYPE_EDGE_BOTH: -+ pdc_type = PDC_EDGE_DUAL; -+ break; -+ case IRQ_TYPE_LEVEL_HIGH: -+ pdc_type = PDC_LEVEL_HIGH; -+ break; -+ case IRQ_TYPE_LEVEL_LOW: -+ pdc_type = PDC_LEVEL_LOW; -+ break; -+ default: -+ WARN_ON(1); -+ return -EINVAL; -+ } -+ -+ old_pdc_type = pdc_reg_read(pdc->regs->irq_cfg_reg, d->hwirq); -+ pdc_type |= (old_pdc_type & ~pdc->cfg_fields->irq_type); -+ pdc_reg_write(pdc->regs->irq_cfg_reg, d->hwirq, pdc_type); -+ -+ /* -+ * PDC forwards GPIOs as level high to GIC in secondary -+ * mode. Update the type and clear any previously latched -+ * phantom interrupt at PDC. -+ */ -+ type = IRQ_TYPE_LEVEL_HIGH; -+ pdc->clear_gpio(d->hwirq); -+ -+ ret = irq_chip_set_type_parent(d, type); -+ if (ret) -+ return ret; -+ -+ /* -+ * When we change types the PDC can give a phantom interrupt. -+ * Clear it. Specifically the phantom shows up when reconfiguring -+ * polarity of interrupt without changing the state of the signal -+ * but let's be consistent and clear it always. -+ * -+ * Doing this works because we have IRQCHIP_SET_TYPE_MASKED so the -+ * interrupt will be cleared before the rest of the system sees it. -+ */ -+ if (old_pdc_type != pdc_type) -+ irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false); -+ -+ return 0; -+} -+ - static struct irq_chip qcom_pdc_gic_chip = { - .name = "PDC", - .irq_eoi = irq_chip_eoi_parent, -@@ -355,6 +510,26 @@ static struct irq_chip qcom_pdc_gic_chip = { - .irq_set_affinity = irq_chip_set_affinity_parent, - }; - -+static struct irq_chip qcom_pdc_gic_secondary_chip = { -+ .name = "PDC", -+ .irq_ack = qcom_pdc_secondary_ack, -+ .irq_eoi = qcom_pdc_gic_secondary_eoi, -+ .irq_mask = qcom_pdc_secondary_mask, -+ .irq_unmask = qcom_pdc_secondary_unmask, -+ .irq_disable = qcom_pdc_gic_secondary_disable, -+ .irq_enable = qcom_pdc_gic_secondary_enable, -+ .irq_get_irqchip_state = irq_chip_get_parent_state, -+ .irq_set_irqchip_state = irq_chip_set_parent_state, -+ .irq_retrigger = irq_chip_retrigger_hierarchy, -+ .irq_set_type = qcom_pdc_gic_secondary_set_type, -+ .flags = IRQCHIP_MASK_ON_SUSPEND | -+ IRQCHIP_SET_TYPE_MASKED | -+ IRQCHIP_SKIP_SET_WAKE | -+ IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND, -+ .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, -+ .irq_set_affinity = irq_chip_set_affinity_parent, -+}; -+ - static struct pdc_pin_region *get_pin_region(int pin) - { - for (int i = 0; i < pdc->region_cnt; i++) { -@@ -388,16 +563,38 @@ static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq, - if (ret) - return ret; - -+ /* -+ * PDC secondary chip is only set for the GPIO interrupts as SPIs. -+ * Direct SPI interrupts are still in pass through mode (no latching -+ * at PDC). -+ */ -+ if (pdc->mode == PDC_SECONDARY_MODE && pdc_pin_is_gpio(hwirq)) { -+ ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, -+ &qcom_pdc_gic_secondary_chip, -+ NULL); -+ if (ret) -+ return ret; -+ -+ /* Secondary mode converts all interrupts to LEVEL HIGH type */ -+ type = IRQ_TYPE_LEVEL_HIGH; -+ } else { -+ ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, -+ &qcom_pdc_gic_chip, -+ NULL); -+ if (ret) -+ return ret; -+ -+ if (type & IRQ_TYPE_EDGE_BOTH) -+ type = IRQ_TYPE_EDGE_RISING; -+ -+ if (type & IRQ_TYPE_LEVEL_MASK) -+ type = IRQ_TYPE_LEVEL_HIGH; -+ } -+ - region = get_pin_region(hwirq); - if (!region) - return irq_domain_disconnect_hierarchy(domain->parent, virq); - -- if (type & IRQ_TYPE_EDGE_BOTH) -- type = IRQ_TYPE_EDGE_RISING; -- -- if (type & IRQ_TYPE_LEVEL_MASK) -- type = IRQ_TYPE_LEVEL_HIGH; -- - parent_fwspec.fwnode = domain->parent->fwnode; - parent_fwspec.param_count = 3; - parent_fwspec.param[0] = 0; -@@ -443,8 +640,13 @@ static int pdc_setup_pin_mapping(struct device *dev) - if (ret) - return ret; - -- for (int i = 0; i < pdc->region[n].cnt; i++) -- pdc->enable_intr(i + pdc->region[n].pin_base, 0); -+ for (int i = 0; i < pdc->region[n].cnt; i++) { -+ if (pdc_pin_is_gpio(i + pdc->region[n].pin_base) && -+ pdc->mode == PDC_SECONDARY_MODE) -+ pdc->clear_gpio(i + pdc->region[n].pin_base); -+ -+ pdc->enable_intr(i + pdc->region[n].pin_base, false); -+ } - } - - return 0; -@@ -494,6 +696,8 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - pdc->enable_intr = pdc_enable_intr_bank; - } - -+ pdc->mode = PDC_PASS_THROUGH_MODE; -+ - /* - * PDC has multiple DRV regions, each one provides the same set of - * registers for a particular client in the system. Due to a hardware -@@ -511,6 +715,16 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - } - - pdc->x1e_quirk = true; -+ -+ if (!qcom_scm_is_available()) -+ return -EPROBE_DEFER; -+ -+ ret = qcom_scm_io_writel(PDC_GPIO_INT_CTL_ENABLE, PDC_PASS_THROUGH_MODE); -+ if (ret) { -+ pdc->mode = PDC_SECONDARY_MODE; -+ pdc->unmask_gpio = pdc_unmask_gpio_cfg; -+ pdc->clear_gpio = pdc_clear_gpio_cfg; -+ } - } - - irq_param = pdc_reg_read(pdc->regs->irq_param_reg, 0); diff --git a/kernel/2104-irqchip-qcom-pdc-Fix-kernel-doc-for-qcom_pdc_gic_sec.patch b/kernel/2104-irqchip-qcom-pdc-Fix-kernel-doc-for-qcom_pdc_gic_sec.patch deleted file mode 100644 index 5716bba..0000000 --- a/kernel/2104-irqchip-qcom-pdc-Fix-kernel-doc-for-qcom_pdc_gic_sec.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Wed, 8 Jul 2026 19:54:14 +0200 -Subject: [PATCH] irqchip/qcom-pdc: Fix kernel doc for - qcom_pdc_gic_secondary_set_type() - -Copy and pasta without fixing up the comment results in kernel doc build fail. - -Fixes: ad01c2b2f291 ("irqchip/qcom-pdc: Configure PDC to pass through mode") -Reported-by: kernel test robot -Signed-off-by: Thomas Gleixner -Closes: https://lore.kernel.org/oe-kbuild-all/202607081724.42MewVti-lkp@intel.com/ -(cherry picked from commit d307a7e7d9395875022ef89e6179118afb66eca8) ---- - drivers/irqchip/qcom-pdc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c -index f38ee74b0397..ce6d80c7f17a 100644 ---- a/drivers/irqchip/qcom-pdc.c -+++ b/drivers/irqchip/qcom-pdc.c -@@ -426,7 +426,7 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) - } - - /** -- * qcom_pdc_gic_set_type: Configure PDC for the interrupt -+ * qcom_pdc_gic_secondary_set_type: Configure PDC for the interrupt in secondary mode - * - * @d: the interrupt data - * @type: the interrupt type diff --git a/kernel/2105-arm64-dts-qcom-x1e80100-Reduce-OS-PDC-DRV-span-to-0x.patch b/kernel/2105-arm64-dts-qcom-x1e80100-Reduce-OS-PDC-DRV-span-to-0x.patch deleted file mode 100644 index 79866dc..0000000 --- a/kernel/2105-arm64-dts-qcom-x1e80100-Reduce-OS-PDC-DRV-span-to-0x.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mukesh Ojha -Date: Wed, 27 May 2026 15:13:20 +0530 -Subject: [PATCH] arm64: dts: qcom: x1e80100: Reduce OS PDC DRV span to 0x10000 - -The OS PDC DRV register window on x1e80100 spans 0x10000 bytes. Reduce -the size of the first reg entry from 0x30000 to 0x10000. - -Signed-off-by: Mukesh Ojha -Reviewed-by: Dmitry Baryshkov -Reviewed-by: Konrad Dybcio -Link: https://lore.kernel.org/r/20260527094333.2311731-16-mukesh.ojha@oss.qualcomm.com -Signed-off-by: Bjorn Andersson -(cherry picked from commit c39df6b350ef51a9374fbd7c399a56b563be8deb) ---- - arch/arm64/boot/dts/qcom/hamoa.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi -index fd86f4761eab..f6f7af3a41ef 100644 ---- a/arch/arm64/boot/dts/qcom/hamoa.dtsi -+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi -@@ -6047,7 +6047,7 @@ dispcc: clock-controller@af00000 { - - pdc: interrupt-controller@b220000 { - compatible = "qcom,x1e80100-pdc", "qcom,pdc"; -- reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>; -+ reg = <0 0x0b220000 0 0x10000>, <0 0x174000f0 0 0x64>; - - qcom,pdc-ranges = <0 480 42>, <42 251 5>, - <47 522 52>, <99 609 32>, diff --git a/kernel/2106-pinctrl-qcom-Acknowledge-IRQs-for-PDC-interrupt-cont.patch b/kernel/2106-pinctrl-qcom-Acknowledge-IRQs-for-PDC-interrupt-cont.patch deleted file mode 100644 index 7dd5bc7..0000000 --- a/kernel/2106-pinctrl-qcom-Acknowledge-IRQs-for-PDC-interrupt-cont.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Stephan Gerhold -Date: Tue, 7 Jul 2026 14:51:37 +0530 -Subject: [PATCH] pinctrl: qcom: Acknowledge IRQs for PDC interrupt controller - -PDC needs to acknowledge incoming GPIO interrupts to clear the latched -interrupt status in secondary mode of PDC. For level-triggered IRQs this -happens automatically in irq_eoi() but for edge-triggered IRQs this needs -to happen as early as possible in the IRQ handler. - -Implement this by using handle_fasteoi_ack_irq() as IRQ handler in this -situation and forward the irq_ack() callback to the parent IRQ chip. - -Signed-off-by: Stephan Gerhold -Signed-off-by: Maulik Shah -Link: https://patch.msgid.link/20260707-hamoa_pdc_v3-v4-5-dfd1f4a3ae89@oss.qualcomm.com -Signed-off-by: Bartosz Golaszewski -(cherry picked from commit f790ea0b699d95d18572979b1bc1673d8f31eb3c) ---- - drivers/pinctrl/qcom/pinctrl-msm.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - -diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c -index fd0add4e71da..694709fb9cfb 100644 ---- a/drivers/pinctrl/qcom/pinctrl-msm.c -+++ b/drivers/pinctrl/qcom/pinctrl-msm.c -@@ -995,6 +995,16 @@ static void msm_gpio_irq_ack(struct irq_data *d) - if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) { - if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) - msm_gpio_update_dual_edge_parent(d); -+ -+ /* -+ * During early initialization of the IRQ hierarchy, -+ * irq_ack() is called by __irq_set_handler() before -+ * the parent IRQ chip has been set up. This is why -+ * we additionally need to check for d->parent_data->chip. -+ */ -+ -+ if (d->parent_data->chip && d->parent_data->chip->irq_ack) -+ irq_chip_ack_parent(d); - return; - } - -@@ -1067,7 +1077,10 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) - - if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) { - clear_bit(d->hwirq, pctrl->dual_edge_irqs); -- irq_set_handler_locked(d, handle_fasteoi_irq); -+ if (type & IRQ_TYPE_LEVEL_MASK) -+ irq_set_handler_locked(d, handle_fasteoi_irq); -+ else -+ irq_set_handler_locked(d, handle_fasteoi_ack_irq); - return 0; - } - diff --git a/kernel/2107-Revert-pinctrl-qcom-x1e80100-Bypass-PDC-wakeup-paren.patch b/kernel/2107-Revert-pinctrl-qcom-x1e80100-Bypass-PDC-wakeup-paren.patch deleted file mode 100644 index 16a6db5..0000000 --- a/kernel/2107-Revert-pinctrl-qcom-x1e80100-Bypass-PDC-wakeup-paren.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Maulik Shah -Date: Tue, 7 Jul 2026 14:51:38 +0530 -Subject: [PATCH] Revert "pinctrl: qcom: x1e80100: Bypass PDC wakeup parent for - now" - -This reverts commit 602cb14e310a ("pinctrl: qcom: x1e80100: Bypass PDC -wakeup parent for now"). - -PDC interrupts no more break GPIOs PDC irqchip is updated to work for -pass through or secondary mode. Update nwakeirq_map to reflect the GPIO -to PDC irq map size. - -Signed-off-by: Maulik Shah -Link: https://patch.msgid.link/20260707-hamoa_pdc_v3-v4-6-dfd1f4a3ae89@oss.qualcomm.com -Signed-off-by: Bartosz Golaszewski -(cherry picked from commit 77fbc756d9cbe53a9496cb2c53ae209d37d5af2d) ---- - drivers/pinctrl/qcom/pinctrl-x1e80100.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/drivers/pinctrl/qcom/pinctrl-x1e80100.c b/drivers/pinctrl/qcom/pinctrl-x1e80100.c -index 8d2b8246170b..e4c0abcd95b9 100644 ---- a/drivers/pinctrl/qcom/pinctrl-x1e80100.c -+++ b/drivers/pinctrl/qcom/pinctrl-x1e80100.c -@@ -1836,9 +1836,7 @@ static const struct msm_pinctrl_soc_data x1e80100_pinctrl = { - .ngroups = ARRAY_SIZE(x1e80100_groups), - .ngpios = 239, - .wakeirq_map = x1e80100_pdc_map, -- /* TODO: Enabling PDC currently breaks GPIO interrupts */ -- .nwakeirq_map = 0, -- /* .nwakeirq_map = ARRAY_SIZE(x1e80100_pdc_map), */ -+ .nwakeirq_map = ARRAY_SIZE(x1e80100_pdc_map), - .egpio_func = 9, - }; - diff --git a/kernel/2108-arm64-dts-qcom-x1e80100-Add-deepest-idle-state.patch b/kernel/2108-arm64-dts-qcom-x1e80100-Add-deepest-idle-state.patch deleted file mode 100644 index fe018e9..0000000 --- a/kernel/2108-arm64-dts-qcom-x1e80100-Add-deepest-idle-state.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Maulik Shah -Date: Wed, 15 Jul 2026 18:31:30 +0530 -Subject: [PATCH] arm64: dts: qcom: x1e80100: Add deepest idle state - -CPU subsystem deepest idle state can lead SoC to low power mode like CxPC -(chip rail power collapse). SoC deepest low power mode requires the PDC -interrupt controller to wake up the SoC as the GIC interrupt controller -is on Cx (chip rail) and will not be functional to wake up the CPU. - -PDC monitors both direct SPI interrupts and GPIOs used as interrupts -in SoC low power mode. Further all wake up capable interrupts gets routed -via PDC to GIC when SoC is out of low power mode. - -The wake up capable GPIOs used as interrupts were by passing PDC on x1e -with commit 602cb14e310a ("pinctrl: qcom: x1e80100: Bypass PDC wakeup -parent for now") as a result CPU deepest idle state was not added so -far. - -The blocker for enabling deepest idle state was GPIO IRQ wakeup support. -The x1e80100 PDC can operate in two modes: pass-through mode (GPIO -IRQs forwarded directly to GIC without latching at PDC) and secondary -controller mode (PDC latches GPIO IRQs and sends them as level IRQs to -GIC). - -All the SoCs on Linux so far worked in pass-through mode of PDC. -On some x1e boards the firmware configures the PDC in secondary controller -mode, which caused GPIO interrupt storms as the level latched at PDC gets -never cleared. - -The secondary mode is originally a requirement for windows SW platforms -(which could not work with all types of interrupts and require level -interrupts for GPIOs). Initially shipped windows firmware did not have -SCM interface to configure PDC back to pass-through mode if with such -firmware Linux is booted up. - -PDC irqchip has got secondary mode and SCM interface support to configure -PDC irqchip mode to pass-through mode on newer firmware where SCM interface -is available and for older firmware on which SCM interface is not present -PDC irqchip works in secondary irqchip mode [1]. Above mentioned commit is -also reverted via [1]. - -With PDC now working on older firmware as well add the CPU deepest idle -state domain_ss3. - -The newly added domain_ss3 state has entry/exit latencies of 2500 us. -The shallower cluster_cl5 state had entry/exit latencies of 2200/4000 us -which are higher than the deeper state. This create an inconsistency that -would confuse the idle governor. Correct cluster_cl5 latencies to 2000 us -each to match production configuration values. - -[1] https://lore.kernel.org/linux-arm-msm/20260707-hamoa_pdc_v3-v4-0-dfd1f4a3ae89@oss.qualcomm.com/#t - -Tested-by: Daniel J Blueman -Signed-off-by: Maulik Shah -Link: https://lore.kernel.org/r/20260715-hamoa_pdc_v3-v5-1-00440cfaf711@oss.qualcomm.com -Signed-off-by: Bjorn Andersson -(cherry picked from commit 95f827ceb21e2885f40eec5d93a340abbcc22d13) ---- - arch/arm64/boot/dts/qcom/hamoa.dtsi | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi -index f6f7af3a41ef..20939c9d69e6 100644 ---- a/arch/arm64/boot/dts/qcom/hamoa.dtsi -+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi -@@ -298,10 +298,18 @@ cluster_cl4: cluster-sleep-0 { - cluster_cl5: cluster-sleep-1 { - compatible = "domain-idle-state"; - arm,psci-suspend-param = <0x01000054>; -- entry-latency-us = <2200>; -- exit-latency-us = <4000>; -+ entry-latency-us = <2000>; -+ exit-latency-us = <2000>; - min-residency-us = <7000>; - }; -+ -+ domain_ss3: domain-sleep-0 { -+ compatible = "domain-idle-state"; -+ arm,psci-suspend-param = <0x0200c354>; -+ entry-latency-us = <2500>; -+ exit-latency-us = <2500>; -+ min-residency-us = <9000>; -+ }; - }; - }; - -@@ -460,7 +468,7 @@ cluster_pd2: power-domain-cpu-cluster2 { - - system_pd: power-domain-system { - #power-domain-cells = <0>; -- /* TODO: system-wide idle states */ -+ domain-idle-states = <&domain_ss3>; - }; - }; - diff --git a/kernel/2110-Documentation-Correction-in-HID-output_report-callba.patch b/kernel/2110-Documentation-Correction-in-HID-output_report-callba.patch deleted file mode 100644 index a4b8ada..0000000 --- a/kernel/2110-Documentation-Correction-in-HID-output_report-callba.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jarrett Schultz -Date: Tue, 9 Jun 2026 04:40:52 +0000 -Subject: [PATCH] Documentation: Correction in HID output_report callback - description. - -Originally output_report callback was described as must-be asynchronous, -but that is not the case in some implementations, namely i2c-hid. -Correct the documentation to say that it may be asynchronous. - -Signed-off-by: Dmitry Antipov -Reviewed-by: Dmitry Torokhov -Signed-off-by: Jingyuan Liang ---- - Documentation/hid/hid-transport.rst | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/Documentation/hid/hid-transport.rst b/Documentation/hid/hid-transport.rst -index 6f1692da296c..2008cf432af1 100644 ---- a/Documentation/hid/hid-transport.rst -+++ b/Documentation/hid/hid-transport.rst -@@ -327,8 +327,8 @@ The available HID callbacks are: - - Send raw output report via intr channel. Used by some HID device drivers - which require high throughput for outgoing requests on the intr channel. This -- must not cause SET_REPORT calls! This must be implemented as asynchronous -- output report on the intr channel! -+ must not cause SET_REPORT calls! This call might be asynchronous, so the -+ caller should not expect an immediate response! - - :: - diff --git a/kernel/2111-HID-Add-BUS_SPI-support-and-define-HID_SPI_DEVICE-ma.patch b/kernel/2111-HID-Add-BUS_SPI-support-and-define-HID_SPI_DEVICE-ma.patch deleted file mode 100644 index c1aede2..0000000 --- a/kernel/2111-HID-Add-BUS_SPI-support-and-define-HID_SPI_DEVICE-ma.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jarrett Schultz -Date: Tue, 9 Jun 2026 04:40:53 +0000 -Subject: [PATCH] HID: Add BUS_SPI support and define HID_SPI_DEVICE macro - -If connecting a hid_device with bus field indicating BUS_SPI print out -"SPI" in the debug print. - -Macro sets the bus field to BUS_SPI and uses arguments to set vendor -product fields. - -Signed-off-by: Dmitry Antipov -Reviewed-by: Dmitry Torokhov -Signed-off-by: Jingyuan Liang ---- - drivers/hid/hid-core.c | 3 +++ - include/linux/hid.h | 2 ++ - 2 files changed, 5 insertions(+) - -diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c -index 14a06ab435a2..b8b57a737390 100644 ---- a/drivers/hid/hid-core.c -+++ b/drivers/hid/hid-core.c -@@ -2377,6 +2377,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) - case BUS_I2C: - bus = "I2C"; - break; -+ case BUS_SPI: -+ bus = "SPI"; -+ break; - case BUS_SDW: - bus = "SOUNDWIRE"; - break; -diff --git a/include/linux/hid.h b/include/linux/hid.h -index 4e2422ec03db..0aa4cc0a9850 100644 ---- a/include/linux/hid.h -+++ b/include/linux/hid.h -@@ -821,6 +821,8 @@ struct hid_descriptor { - .bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod) - #define HID_I2C_DEVICE(ven, prod) \ - .bus = BUS_I2C, .vendor = (ven), .product = (prod) -+#define HID_SPI_DEVICE(ven, prod) \ -+ .bus = BUS_SPI, .vendor = (ven), .product = (prod) - - #define HID_REPORT_ID(rep) \ - .report_type = (rep) diff --git a/kernel/2112-HID-spi-hid-add-transport-driver-skeleton-for-HID-ov.patch b/kernel/2112-HID-spi-hid-add-transport-driver-skeleton-for-HID-ov.patch deleted file mode 100644 index 76a65b4..0000000 --- a/kernel/2112-HID-spi-hid-add-transport-driver-skeleton-for-HID-ov.patch +++ /dev/null @@ -1,304 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Angela Czubak -Date: Tue, 9 Jun 2026 04:40:54 +0000 -Subject: [PATCH] HID: spi-hid: add transport driver skeleton for HID over SPI - bus - -Create spi-hid folder and add Kconfig and Makefile for spi-hid driver. -Add basic device structure, definitions, and probe/remove functions. - -Signed-off-by: Dmitry Antipov -Signed-off-by: Angela Czubak -Signed-off-by: Jingyuan Liang ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 2 + - drivers/hid/spi-hid/Kconfig | 15 ++ - drivers/hid/spi-hid/Makefile | 9 ++ - drivers/hid/spi-hid/spi-hid-core.c | 213 +++++++++++++++++++++++++++++ - 5 files changed, 241 insertions(+) - create mode 100644 drivers/hid/spi-hid/Kconfig - create mode 100644 drivers/hid/spi-hid/Makefile - create mode 100644 drivers/hid/spi-hid/spi-hid-core.c - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 48934c4f3c45..3569168846a9 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1481,6 +1481,8 @@ source "drivers/hid/bpf/Kconfig" - - source "drivers/hid/i2c-hid/Kconfig" - -+source "drivers/hid/spi-hid/Kconfig" -+ - source "drivers/hid/intel-ish-hid/Kconfig" - - source "drivers/hid/amd-sfh-hid/Kconfig" -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 23e6e3dd0c56..562f19b64d5f 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -175,6 +175,8 @@ obj-$(CONFIG_USB_KBD) += usbhid/ - - obj-$(CONFIG_I2C_HID_CORE) += i2c-hid/ - -+obj-$(CONFIG_SPI_HID_CORE) += spi-hid/ -+ - obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ - - obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ -diff --git a/drivers/hid/spi-hid/Kconfig b/drivers/hid/spi-hid/Kconfig -new file mode 100644 -index 000000000000..836fdefe8345 ---- /dev/null -+++ b/drivers/hid/spi-hid/Kconfig -@@ -0,0 +1,15 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# Copyright (c) 2021 Microsoft Corporation -+# -+ -+menuconfig SPI_HID -+ tristate "SPI HID support" -+ default y -+ depends on SPI -+ -+if SPI_HID -+ -+config SPI_HID_CORE -+ tristate -+endif -diff --git a/drivers/hid/spi-hid/Makefile b/drivers/hid/spi-hid/Makefile -new file mode 100644 -index 000000000000..92e24cddbfc2 ---- /dev/null -+++ b/drivers/hid/spi-hid/Makefile -@@ -0,0 +1,9 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# Makefile for the SPI HID input drivers -+# -+# Copyright (c) 2021 Microsoft Corporation -+# -+ -+obj-$(CONFIG_SPI_HID_CORE) += spi-hid.o -+spi-hid-objs = spi-hid-core.o -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -new file mode 100644 -index 000000000000..02a7608c4b88 ---- /dev/null -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -0,0 +1,213 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * HID over SPI protocol implementation -+ * -+ * Copyright (c) 2021 Microsoft Corporation -+ * Copyright (c) 2026 Google LLC -+ * -+ * This code is partly based on "HID over I2C protocol implementation: -+ * -+ * Copyright (c) 2012 Benjamin Tissoires -+ * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France -+ * Copyright (c) 2012 Red Hat, Inc -+ * -+ * which in turn is partly based on "USB HID support for Linux": -+ * -+ * Copyright (c) 1999 Andreas Gal -+ * Copyright (c) 2000-2005 Vojtech Pavlik -+ * Copyright (c) 2005 Michael Haboustak for Concept2, Inc -+ * Copyright (c) 2007-2008 Oliver Neukum -+ * Copyright (c) 2006-2010 Jiri Kosina -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* struct spi_hid_conf - Conf provided to the core */ -+struct spi_hid_conf { -+ u32 input_report_header_address; -+ u32 input_report_body_address; -+ u32 output_report_address; -+ u8 read_opcode; -+ u8 write_opcode; -+}; -+ -+/** -+ * struct spihid_ops - Ops provided to the core -+ * @power_up: do sequencing to power up the device -+ * @power_down: do sequencing to power down the device -+ * @assert_reset: do sequencing to assert the reset line -+ * @deassert_reset: do sequencing to deassert the reset line -+ * @sleep_minimal_reset_delay: minimal sleep delay during reset -+ */ -+struct spihid_ops { -+ int (*power_up)(struct spihid_ops *ops); -+ int (*power_down)(struct spihid_ops *ops); -+ int (*assert_reset)(struct spihid_ops *ops); -+ int (*deassert_reset)(struct spihid_ops *ops); -+ void (*sleep_minimal_reset_delay)(struct spihid_ops *ops); -+}; -+ -+/* Driver context */ -+struct spi_hid { -+ struct spi_device *spi; /* spi device. */ -+ struct hid_device *hid; /* pointer to corresponding HID dev. */ -+ -+ struct spihid_ops *ops; -+ struct spi_hid_conf *conf; -+ -+ enum hidspi_power_state power_state; -+ -+ u32 regulator_error_count; -+ int regulator_last_error; -+ u32 bus_error_count; -+ int bus_last_error; -+ u32 dir_count; /* device initiated reset count. */ -+}; -+ -+static const char *spi_hid_power_mode_string(enum hidspi_power_state power_state) -+{ -+ switch (power_state) { -+ case HIDSPI_ON: -+ return "d0"; -+ case HIDSPI_SLEEP: -+ return "d2"; -+ case HIDSPI_OFF: -+ return "d3"; -+ default: -+ return "unknown"; -+ } -+} -+ -+static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) -+{ -+ return IRQ_HANDLED; -+} -+ -+static ssize_t bus_error_count_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct spi_hid *shid = dev_get_drvdata(dev); -+ -+ return sysfs_emit(buf, "%u (%d)\n", -+ shid->bus_error_count, shid->bus_last_error); -+} -+static DEVICE_ATTR_RO(bus_error_count); -+ -+static ssize_t regulator_error_count_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct spi_hid *shid = dev_get_drvdata(dev); -+ -+ return sysfs_emit(buf, "%u (%d)\n", -+ shid->regulator_error_count, -+ shid->regulator_last_error); -+} -+static DEVICE_ATTR_RO(regulator_error_count); -+ -+static ssize_t device_initiated_reset_count_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct spi_hid *shid = dev_get_drvdata(dev); -+ -+ return sysfs_emit(buf, "%u\n", shid->dir_count); -+} -+static DEVICE_ATTR_RO(device_initiated_reset_count); -+ -+static struct attribute *spi_hid_attrs[] = { -+ &dev_attr_bus_error_count.attr, -+ &dev_attr_regulator_error_count.attr, -+ &dev_attr_device_initiated_reset_count.attr, -+ NULL /* Terminator */ -+}; -+ -+static const struct attribute_group spi_hid_group = { -+ .attrs = spi_hid_attrs, -+}; -+ -+const struct attribute_group *spi_hid_groups[] = { -+ &spi_hid_group, -+ NULL -+}; -+EXPORT_SYMBOL_GPL(spi_hid_groups); -+ -+int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, -+ struct spi_hid_conf *conf) -+{ -+ struct device *dev = &spi->dev; -+ struct spi_hid *shid; -+ int error; -+ -+ if (spi->irq <= 0) -+ return dev_err_probe(dev, spi->irq ?: -EINVAL, "Missing IRQ\n"); -+ -+ shid = devm_kzalloc(dev, sizeof(*shid), GFP_KERNEL); -+ if (!shid) -+ return -ENOMEM; -+ -+ shid->spi = spi; -+ shid->power_state = HIDSPI_ON; -+ shid->ops = ops; -+ shid->conf = conf; -+ -+ spi_set_drvdata(spi, shid); -+ -+ /* -+ * At the end of probe we initialize the device: -+ * 0) assert reset, bias the interrupt line -+ * 1) sleep minimal reset delay -+ * 2) request IRQ -+ * 3) power up the device -+ * 4) deassert reset (high) -+ * After this we expect an IRQ with a reset response. -+ */ -+ -+ shid->ops->assert_reset(shid->ops); -+ -+ shid->ops->sleep_minimal_reset_delay(shid->ops); -+ -+ error = devm_request_threaded_irq(dev, spi->irq, NULL, spi_hid_dev_irq, -+ IRQF_ONESHOT, dev_name(&spi->dev), shid); -+ if (error) { -+ dev_err(dev, "%s: unable to request threaded IRQ\n", __func__); -+ return error; -+ } -+ -+ error = shid->ops->power_up(shid->ops); -+ if (error) { -+ dev_err(dev, "%s: could not power up\n", __func__); -+ return error; -+ } -+ -+ shid->ops->deassert_reset(shid->ops); -+ -+ dev_dbg(dev, "%s: d3 -> %s\n", __func__, -+ spi_hid_power_mode_string(shid->power_state)); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(spi_hid_core_probe); -+ -+void spi_hid_core_remove(struct spi_device *spi) -+{ -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ struct device *dev = &spi->dev; -+ int error; -+ -+ shid->ops->assert_reset(shid->ops); -+ error = shid->ops->power_down(shid->ops); -+ if (error) -+ dev_err(dev, "failed to disable regulator\n"); -+} -+EXPORT_SYMBOL_GPL(spi_hid_core_remove); -+ -+MODULE_DESCRIPTION("HID over SPI transport driver"); -+MODULE_AUTHOR("Dmitry Antipov "); -+MODULE_LICENSE("GPL"); diff --git a/kernel/2113-HID-spi-hid-add-spi-hid-driver-HID-layer.patch b/kernel/2113-HID-spi-hid-add-spi-hid-driver-HID-layer.patch deleted file mode 100644 index ebbae6c..0000000 --- a/kernel/2113-HID-spi-hid-add-spi-hid-driver-HID-layer.patch +++ /dev/null @@ -1,645 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jingyuan Liang -Date: Tue, 9 Jun 2026 04:40:55 +0000 -Subject: [PATCH] HID: spi-hid: add spi-hid driver HID layer - -Add HID low level driver callbacks to register SPI as a HID driver, and -an external touch device as a HID device. - -Signed-off-by: Dmitry Antipov -Signed-off-by: Angela Czubak -Signed-off-by: Jingyuan Liang ---- - drivers/hid/spi-hid/spi-hid-core.c | 563 +++++++++++++++++++++++++++++ - 1 file changed, 563 insertions(+) - -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -index 02a7608c4b88..72c2e1ce3e8d 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.c -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -20,13 +20,69 @@ - * Copyright (c) 2006-2010 Jiri Kosina - */ - -+#include -+#include - #include -+#include - #include - #include - #include -+#include - #include -+#include - #include - #include -+#include -+#include -+#include -+ -+#define SPI_HID_OUTPUT_REPORT_CONTENT_ID_DESC_REQUEST 0x00 -+ -+#define SPI_HID_RESP_TIMEOUT 1000 -+ -+/* Protocol message size constants */ -+#define SPI_HID_OUTPUT_HEADER_LEN 8 -+ -+/* flags */ -+/* -+ * ready flag indicates that the FW is ready to accept commands and -+ * requests. The FW becomes ready after sending the report descriptor. -+ */ -+#define SPI_HID_READY 0 -+ -+/* Raw input buffer with data from the bus */ -+struct spi_hid_input_buf { -+ u8 header[HIDSPI_INPUT_HEADER_SIZE]; -+ u8 body[HIDSPI_INPUT_BODY_HEADER_SIZE]; -+ u8 content[]; -+}; -+ -+/* Raw output report buffer to be put on the bus */ -+struct spi_hid_output_buf { -+ u8 header[SPI_HID_OUTPUT_HEADER_LEN]; -+ u8 content[]; -+}; -+ -+/* Data necessary to send an output report */ -+struct spi_hid_output_report { -+ u8 report_type; -+ u16 content_length; -+ u8 content_id; -+ u8 *content; -+}; -+ -+/* Processed data from a device descriptor */ -+struct spi_hid_device_descriptor { -+ u16 hid_version; -+ u16 report_descriptor_length; -+ u16 max_input_length; -+ u16 max_output_length; -+ u16 max_fragment_length; -+ u16 vendor_id; -+ u16 product_id; -+ u16 version_id; -+ u8 no_output_report_ack; -+}; - - /* struct spi_hid_conf - Conf provided to the core */ - struct spi_hid_conf { -@@ -61,8 +117,26 @@ struct spi_hid { - struct spihid_ops *ops; - struct spi_hid_conf *conf; - -+ struct spi_hid_device_descriptor desc; /* HID device descriptor. */ -+ struct spi_hid_output_buf *output; /* Output buffer. */ -+ struct spi_hid_input_buf *input; /* Input buffer. */ -+ struct spi_hid_input_buf *response; /* Response buffer. */ -+ -+ u16 response_length; -+ u16 bufsize; -+ - enum hidspi_power_state power_state; - -+ u8 reset_attempts; /* The number of reset attempts. */ -+ -+ unsigned long flags; /* device flags. */ -+ -+ /* Control lock to make sure one output transaction at a time. */ -+ struct mutex output_lock; -+ struct completion output_done; -+ -+ u32 report_descriptor_crc32; /* HID report descriptor crc32 checksum. */ -+ - u32 regulator_error_count; - int regulator_last_error; - u32 bus_error_count; -@@ -70,6 +144,33 @@ struct spi_hid { - u32 dir_count; /* device initiated reset count. */ - }; - -+static struct hid_ll_driver spi_hid_ll_driver; -+ -+static void spi_hid_populate_output_header(u8 *buf, -+ const struct spi_hid_conf *conf, -+ const struct spi_hid_output_report *report) -+{ -+ buf[0] = conf->write_opcode; -+ put_unaligned_be24(conf->output_report_address, &buf[1]); -+ buf[4] = report->report_type; -+ put_unaligned_le16(report->content_length, &buf[5]); -+ buf[7] = report->content_id; -+} -+ -+static int spi_hid_output(struct spi_hid *shid, const void *buf, u16 length) -+{ -+ int error; -+ -+ error = spi_write(shid->spi, buf, length); -+ -+ if (error) { -+ shid->bus_error_count++; -+ shid->bus_last_error = error; -+ } -+ -+ return error; -+} -+ - static const char *spi_hid_power_mode_string(enum hidspi_power_state power_state) - { - switch (power_state) { -@@ -84,11 +185,455 @@ static const char *spi_hid_power_mode_string(enum hidspi_power_state power_state - } - } - -+static void spi_hid_stop_hid(struct spi_hid *shid) -+{ -+ struct hid_device *hid = shid->hid; -+ -+ shid->hid = NULL; -+ clear_bit(SPI_HID_READY, &shid->flags); -+ -+ if (hid) -+ hid_destroy_device(hid); -+} -+ -+static int __spi_hid_send_output_report(struct spi_hid *shid, -+ struct spi_hid_output_report *report) -+{ -+ struct spi_hid_output_buf *buf = shid->output; -+ struct device *dev = &shid->spi->dev; -+ u16 report_length; -+ u16 padded_length; -+ u8 padding; -+ int error; -+ -+ if (report->content_length > shid->desc.max_output_length || -+ report->content_length > shid->bufsize) { -+ dev_err(dev, "Output report too big, content_length 0x%x\n", -+ report->content_length); -+ return -E2BIG; -+ } -+ -+ spi_hid_populate_output_header(buf->header, shid->conf, report); -+ -+ if (report->content_length) -+ memcpy(&buf->content, report->content, report->content_length); -+ -+ report_length = sizeof(buf->header) + report->content_length; -+ padded_length = round_up(report_length, 4); -+ padding = padded_length - report_length; -+ memset(&buf->content[report->content_length], 0, padding); -+ -+ error = spi_hid_output(shid, buf, padded_length); -+ if (error) -+ dev_err(dev, "Failed output transfer: %d\n", error); -+ -+ return error; -+} -+ -+static int spi_hid_send_output_report(struct spi_hid *shid, -+ struct spi_hid_output_report *report) -+{ -+ guard(mutex)(&shid->output_lock); -+ return __spi_hid_send_output_report(shid, report); -+} -+ -+static int spi_hid_sync_request(struct spi_hid *shid, -+ struct spi_hid_output_report *report) -+{ -+ struct device *dev = &shid->spi->dev; -+ int error; -+ -+ guard(mutex)(&shid->output_lock); -+ -+ reinit_completion(&shid->output_done); -+ -+ error = __spi_hid_send_output_report(shid, report); -+ if (error) -+ return error; -+ -+ error = wait_for_completion_interruptible_timeout(&shid->output_done, -+ msecs_to_jiffies(SPI_HID_RESP_TIMEOUT)); -+ if (error == 0) { -+ dev_err(dev, "Response timed out\n"); -+ return -ETIMEDOUT; -+ } -+ if (error < 0) -+ return error; -+ -+ return 0; -+} -+ -+/* -+ * This function returns the length of the report descriptor, or a negative -+ * error code if something went wrong. -+ */ -+static int spi_hid_report_descriptor_request(struct spi_hid *shid) -+{ -+ struct device *dev = &shid->spi->dev; -+ struct spi_hid_output_report report = { -+ .report_type = REPORT_DESCRIPTOR, -+ .content_length = 0, -+ .content_id = SPI_HID_OUTPUT_REPORT_CONTENT_ID_DESC_REQUEST, -+ .content = NULL, -+ }; -+ int ret; -+ -+ ret = spi_hid_sync_request(shid, &report); -+ if (ret) { -+ dev_err(dev, -+ "Expected report descriptor not received: %d\n", ret); -+ return ret; -+ } -+ -+ ret = shid->response_length; -+ if (ret != shid->desc.report_descriptor_length) { -+ ret = min_t(unsigned int, ret, shid->desc.report_descriptor_length); -+ dev_err(dev, "Received report descriptor length doesn't match device descriptor field, using min of the two: %d\n", -+ ret); -+ } -+ -+ return ret; -+} -+ -+static int spi_hid_create_device(struct spi_hid *shid) -+{ -+ struct hid_device *hid; -+ struct device *dev = &shid->spi->dev; -+ int error; -+ -+ hid = hid_allocate_device(); -+ error = PTR_ERR_OR_ZERO(hid); -+ if (error) { -+ dev_err(dev, "Failed to allocate hid device: %d\n", error); -+ return error; -+ } -+ -+ hid->driver_data = shid->spi; -+ hid->ll_driver = &spi_hid_ll_driver; -+ hid->dev.parent = &shid->spi->dev; -+ hid->bus = BUS_SPI; -+ hid->version = shid->desc.hid_version; -+ hid->vendor = shid->desc.vendor_id; -+ hid->product = shid->desc.product_id; -+ -+ snprintf(hid->name, sizeof(hid->name), "spi %04X:%04X", -+ hid->vendor, hid->product); -+ strscpy(hid->phys, dev_name(&shid->spi->dev), sizeof(hid->phys)); -+ -+ shid->hid = hid; -+ -+ error = hid_add_device(hid); -+ if (error) { -+ dev_err(dev, "Failed to add hid device: %d\n", error); -+ /* -+ * We likely got here because report descriptor request timed -+ * out. Let's disconnect and destroy the hid_device structure. -+ */ -+ spi_hid_stop_hid(shid); -+ return error; -+ } -+ -+ return 0; -+} -+ -+static int spi_hid_get_request(struct spi_hid *shid, u8 content_id) -+{ -+ struct device *dev = &shid->spi->dev; -+ struct spi_hid_output_report report = { -+ .report_type = GET_FEATURE, -+ .content_length = 0, -+ .content_id = content_id, -+ .content = NULL, -+ }; -+ int error; -+ -+ error = spi_hid_sync_request(shid, &report); -+ if (error) { -+ dev_err(dev, -+ "Expected get request response not received! Error %d\n", -+ error); -+ return error; -+ } -+ -+ return 0; -+} -+ -+static int spi_hid_set_request(struct spi_hid *shid, u8 *arg_buf, u16 arg_len, -+ u8 content_id) -+{ -+ struct spi_hid_output_report report = { -+ .report_type = SET_FEATURE, -+ .content_length = arg_len, -+ .content_id = content_id, -+ .content = arg_buf, -+ }; -+ -+ return spi_hid_sync_request(shid, &report); -+} -+ -+/* This is a placeholder. Will be implemented in the next patch. */ - static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - { - return IRQ_HANDLED; - } - -+static int spi_hid_alloc_buffers(struct spi_hid *shid, size_t report_size) -+{ -+ struct device *dev = &shid->spi->dev; -+ int inbufsize = round_up(sizeof(shid->input->header) + -+ sizeof(shid->input->body) + report_size, 4); -+ int outbufsize = round_up(sizeof(shid->output->header) + report_size, 4); -+ void *tmp; -+ -+ tmp = devm_krealloc(dev, shid->output, outbufsize, GFP_KERNEL | __GFP_ZERO); -+ if (!tmp) -+ return -ENOMEM; -+ shid->output = tmp; -+ -+ tmp = devm_krealloc(dev, shid->input, inbufsize, GFP_KERNEL | __GFP_ZERO); -+ if (!tmp) -+ return -ENOMEM; -+ shid->input = tmp; -+ -+ tmp = devm_krealloc(dev, shid->response, inbufsize, GFP_KERNEL | __GFP_ZERO); -+ if (!tmp) -+ return -ENOMEM; -+ shid->response = tmp; -+ -+ if (!shid->output || !shid->input || !shid->response) -+ return -ENOMEM; -+ -+ shid->bufsize = report_size; -+ -+ return 0; -+} -+ -+static int spi_hid_get_report_length(struct hid_report *report) -+{ -+ return DIV_ROUND_UP(report->size, 8) + -+ report->device->report_enum[report->type].numbered + 2; -+} -+ -+/* -+ * Traverse the supplied list of reports and find the longest -+ */ -+static void spi_hid_find_max_report(struct hid_device *hid, u32 type, -+ u16 *max) -+{ -+ struct hid_report *report; -+ u16 size; -+ -+ /* -+ * We should not rely on wMaxInputLength, as some devices may set it to -+ * a wrong length. -+ */ -+ list_for_each_entry(report, &hid->report_enum[type].report_list, list) { -+ size = spi_hid_get_report_length(report); -+ if (*max < size) -+ *max = size; -+ } -+} -+ -+/* hid_ll_driver interface functions */ -+ -+static int spi_hid_ll_start(struct hid_device *hid) -+{ -+ struct spi_device *spi = hid->driver_data; -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ int error = 0; -+ u16 bufsize = 0; -+ -+ spi_hid_find_max_report(hid, HID_INPUT_REPORT, &bufsize); -+ spi_hid_find_max_report(hid, HID_OUTPUT_REPORT, &bufsize); -+ spi_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize); -+ -+ if (bufsize < HID_MIN_BUFFER_SIZE) { -+ dev_err(&spi->dev, -+ "HID_MIN_BUFFER_SIZE > max_input_length (%d)\n", -+ bufsize); -+ return -EINVAL; -+ } -+ -+ if (bufsize > shid->bufsize) { -+ guard(disable_irq)(&shid->spi->irq); -+ -+ error = spi_hid_alloc_buffers(shid, bufsize); -+ if (error) -+ return error; -+ } -+ -+ return 0; -+} -+ -+static void spi_hid_ll_stop(struct hid_device *hid) -+{ -+ hid->claimed = 0; -+} -+ -+static int spi_hid_ll_open(struct hid_device *hid) -+{ -+ struct spi_device *spi = hid->driver_data; -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ -+ set_bit(SPI_HID_READY, &shid->flags); -+ return 0; -+} -+ -+static void spi_hid_ll_close(struct hid_device *hid) -+{ -+ struct spi_device *spi = hid->driver_data; -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ -+ clear_bit(SPI_HID_READY, &shid->flags); -+ shid->reset_attempts = 0; -+} -+ -+static int spi_hid_ll_power(struct hid_device *hid, int level) -+{ -+ struct spi_device *spi = hid->driver_data; -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ int error = 0; -+ -+ guard(mutex)(&shid->output_lock); -+ if (!shid->hid) -+ error = -ENODEV; -+ -+ return error; -+} -+ -+static int spi_hid_ll_parse(struct hid_device *hid) -+{ -+ struct spi_device *spi = hid->driver_data; -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ struct device *dev = &spi->dev; -+ unsigned int rsize = shid->desc.report_descriptor_length; -+ int error, len; -+ -+ if (rsize > HID_MAX_DESCRIPTOR_SIZE) { -+ dev_err(dev, -+ "Report descriptor size %d is greater than HID_MAX_DESCRIPTOR_SIZE %d\n", -+ rsize, HID_MAX_DESCRIPTOR_SIZE); -+ return -EINVAL; -+ } -+ -+ if (rsize > shid->bufsize) { -+ error = spi_hid_alloc_buffers(shid, rsize); -+ if (error) -+ return error; -+ } -+ -+ len = spi_hid_report_descriptor_request(shid); -+ if (len < 0) { -+ dev_err(dev, "Report descriptor request failed, %d\n", len); -+ return len; -+ } -+ -+ /* -+ * FIXME: below call returning 0 doesn't mean that the report descriptor -+ * is good. We might be caching a crc32 of a corrupted r. d. or who -+ * knows what the FW sent. Need to have a feedback loop about r. d. -+ * being ok and only then cache it. -+ */ -+ error = hid_parse_report(hid, (u8 *)shid->response->content, len); -+ if (error) { -+ dev_err(dev, "failed parsing report: %d\n", error); -+ return error; -+ } -+ shid->report_descriptor_crc32 = crc32_le(0, -+ (unsigned char const *)shid->response->content, -+ len); -+ -+ return 0; -+} -+ -+static int spi_hid_ll_raw_request(struct hid_device *hid, -+ unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct spi_device *spi = hid->driver_data; -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ struct device *dev = &spi->dev; -+ int ret; -+ -+ switch (reqtype) { -+ case HID_REQ_SET_REPORT: -+ if (buf[0] != reportnum) { -+ dev_err(dev, "report id mismatch\n"); -+ return -EINVAL; -+ } -+ -+ ret = spi_hid_set_request(shid, &buf[1], len - 1, -+ reportnum); -+ if (ret) { -+ dev_err(dev, "failed to set report\n"); -+ return ret; -+ } -+ -+ ret = len; -+ break; -+ case HID_REQ_GET_REPORT: -+ ret = spi_hid_get_request(shid, reportnum); -+ if (ret) { -+ dev_err(dev, "failed to get report\n"); -+ return ret; -+ } -+ -+ ret = min_t(size_t, len, -+ (shid->response->body[1] | (shid->response->body[2] << 8)) + 1); -+ buf[0] = shid->response->body[3]; -+ memcpy(&buf[1], &shid->response->content, ret); -+ break; -+ default: -+ dev_err(dev, "invalid request type\n"); -+ return -EIO; -+ } -+ -+ return ret; -+} -+ -+static int spi_hid_ll_output_report(struct hid_device *hid, __u8 *buf, -+ size_t len) -+{ -+ struct spi_device *spi = hid->driver_data; -+ struct spi_hid *shid = spi_get_drvdata(spi); -+ struct device *dev = &spi->dev; -+ struct spi_hid_output_report report = { -+ .report_type = OUTPUT_REPORT, -+ .content_length = len - 1, -+ .content_id = buf[0], -+ .content = &buf[1], -+ }; -+ int error; -+ -+ if (!test_bit(SPI_HID_READY, &shid->flags)) { -+ dev_err(dev, "%s called in unready state\n", __func__); -+ return -ENODEV; -+ } -+ -+ if (shid->desc.no_output_report_ack) -+ error = spi_hid_send_output_report(shid, &report); -+ else -+ error = spi_hid_sync_request(shid, &report); -+ -+ if (error) { -+ dev_err(dev, "failed to send output report\n"); -+ return error; -+ } -+ -+ return len; -+} -+ -+static struct hid_ll_driver spi_hid_ll_driver = { -+ .start = spi_hid_ll_start, -+ .stop = spi_hid_ll_stop, -+ .open = spi_hid_ll_open, -+ .close = spi_hid_ll_close, -+ .power = spi_hid_ll_power, -+ .parse = spi_hid_ll_parse, -+ .output_report = spi_hid_ll_output_report, -+ .raw_request = spi_hid_ll_raw_request, -+}; -+ - static ssize_t bus_error_count_show(struct device *dev, - struct device_attribute *attr, char *buf) - { -@@ -159,6 +704,18 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - - spi_set_drvdata(spi, shid); - -+ mutex_init(&shid->output_lock); -+ init_completion(&shid->output_done); -+ -+ /* -+ * we need to allocate the buffer without knowing the maximum -+ * size of the reports. Let's use SZ_2K, then we do the -+ * real computation later. -+ */ -+ error = spi_hid_alloc_buffers(shid, SZ_2K); -+ if (error) -+ return error; -+ - /* - * At the end of probe we initialize the device: - * 0) assert reset, bias the interrupt line -@@ -191,6 +748,10 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - dev_dbg(dev, "%s: d3 -> %s\n", __func__, - spi_hid_power_mode_string(shid->power_state)); - -+ error = spi_hid_create_device(shid); -+ if (error) -+ return error; -+ - return 0; - } - EXPORT_SYMBOL_GPL(spi_hid_core_probe); -@@ -201,6 +762,8 @@ void spi_hid_core_remove(struct spi_device *spi) - struct device *dev = &spi->dev; - int error; - -+ spi_hid_stop_hid(shid); -+ - shid->ops->assert_reset(shid->ops); - error = shid->ops->power_down(shid->ops); - if (error) diff --git a/kernel/2114-HID-spi-hid-add-HID-SPI-protocol-implementation.patch b/kernel/2114-HID-spi-hid-add-HID-SPI-protocol-implementation.patch deleted file mode 100644 index 917324c..0000000 --- a/kernel/2114-HID-spi-hid-add-HID-SPI-protocol-implementation.patch +++ /dev/null @@ -1,815 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jingyuan Liang -Date: Tue, 9 Jun 2026 04:40:56 +0000 -Subject: [PATCH] HID: spi-hid: add HID SPI protocol implementation - -This driver follows HID Over SPI Protocol Specification 1.0 available at -https://www.microsoft.com/en-us/download/details.aspx?id=103325. The -initial version of the driver does not support: 1) multi-fragment input -reports, 2) sending GET_INPUT and COMMAND output report types and -processing their respective acknowledge input reports, and 3) device -sleep power state. - -Signed-off-by: Dmitry Antipov -Signed-off-by: Angela Czubak -Signed-off-by: Jingyuan Liang ---- - drivers/hid/spi-hid/spi-hid-core.c | 608 ++++++++++++++++++++++++++++- - 1 file changed, 592 insertions(+), 16 deletions(-) - -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -index 72c2e1ce3e8d..f6ea2d4365a7 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.c -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -20,14 +20,20 @@ - * Copyright (c) 2006-2010 Jiri Kosina - */ - -+#include - #include - #include - #include -+#include - #include - #include - #include -+#include - #include -+#include - #include -+#include -+#include - #include - #include - #include -@@ -35,12 +41,22 @@ - #include - #include - #include -+#include -+#include -+ -+/* Protocol constants */ -+#define SPI_HID_READ_APPROVAL_CONSTANT 0xff -+#define SPI_HID_INPUT_HEADER_SYNC_BYTE 0x5a -+#define SPI_HID_INPUT_HEADER_VERSION 0x03 -+#define SPI_HID_SUPPORTED_VERSION 0x0300 - - #define SPI_HID_OUTPUT_REPORT_CONTENT_ID_DESC_REQUEST 0x00 - --#define SPI_HID_RESP_TIMEOUT 1000 -+#define SPI_HID_MAX_RESET_ATTEMPTS 3 -+#define SPI_HID_RESP_TIMEOUT 1000 - - /* Protocol message size constants */ -+#define SPI_HID_READ_APPROVAL_LEN 5 - #define SPI_HID_OUTPUT_HEADER_LEN 8 - - /* flags */ -@@ -49,6 +65,22 @@ - * requests. The FW becomes ready after sending the report descriptor. - */ - #define SPI_HID_READY 0 -+/* -+ * refresh_in_progress is set to true while the refresh_device worker -+ * thread is destroying and recreating the hidraw device. When this flag -+ * is set to true, the ll_close and ll_open functions will not cause -+ * power state changes. -+ */ -+#define SPI_HID_REFRESH_IN_PROGRESS 1 -+/* -+ * reset_pending indicates that the device is being reset. When this flag -+ * is set to true, garbage interrupts triggered during reset will be -+ * dropped and will not cause error handling. -+ */ -+#define SPI_HID_RESET_PENDING 2 -+#define SPI_HID_RESET_RESPONSE 3 -+#define SPI_HID_CREATE_DEVICE 4 -+#define SPI_HID_ERROR 5 - - /* Raw input buffer with data from the bus */ - struct spi_hid_input_buf { -@@ -57,6 +89,22 @@ struct spi_hid_input_buf { - u8 content[]; - }; - -+/* Processed data from input report header */ -+struct spi_hid_input_header { -+ u8 version; -+ u16 report_length; -+ u8 last_fragment_flag; -+ u8 sync_const; -+}; -+ -+/* Processed data from an input report */ -+struct spi_hid_input_report { -+ u8 report_type; -+ u16 content_length; -+ u8 content_id; -+ u8 *content; -+}; -+ - /* Raw output report buffer to be put on the bus */ - struct spi_hid_output_buf { - u8 header[SPI_HID_OUTPUT_HEADER_LEN]; -@@ -114,6 +162,9 @@ struct spi_hid { - struct spi_device *spi; /* spi device. */ - struct hid_device *hid; /* pointer to corresponding HID dev. */ - -+ struct spi_transfer input_transfer[2]; /* Transfer buffer for read and write. */ -+ struct spi_message input_message; /* used to execute a sequence of spi transfers. */ -+ - struct spihid_ops *ops; - struct spi_hid_conf *conf; - -@@ -131,8 +182,15 @@ struct spi_hid { - - unsigned long flags; /* device flags. */ - -- /* Control lock to make sure one output transaction at a time. */ -+ struct work_struct reset_work; -+ -+ /* Control lock to ensure complete output transaction. */ - struct mutex output_lock; -+ /* Power lock to make sure one power state change at a time. */ -+ struct mutex power_lock; -+ /* Protect bus I/O and shid->hid pointer lifecycle. */ -+ struct mutex io_lock; -+ - struct completion output_done; - - u32 report_descriptor_crc32; /* HID report descriptor crc32 checksum. */ -@@ -142,10 +200,74 @@ struct spi_hid { - u32 bus_error_count; - int bus_last_error; - u32 dir_count; /* device initiated reset count. */ -+ -+ /* DMA-safe transfer buffers */ -+ u8 read_approval_header[SPI_HID_READ_APPROVAL_LEN] ____cacheline_aligned; -+ u8 read_approval_body[SPI_HID_READ_APPROVAL_LEN]; - }; - - static struct hid_ll_driver spi_hid_ll_driver; - -+static void spi_hid_populate_read_approvals(const struct spi_hid_conf *conf, -+ u8 *header_buf, u8 *body_buf) -+{ -+ header_buf[0] = conf->read_opcode; -+ put_unaligned_be24(conf->input_report_header_address, &header_buf[1]); -+ header_buf[4] = SPI_HID_READ_APPROVAL_CONSTANT; -+ -+ body_buf[0] = conf->read_opcode; -+ put_unaligned_be24(conf->input_report_body_address, &body_buf[1]); -+ body_buf[4] = SPI_HID_READ_APPROVAL_CONSTANT; -+} -+ -+static void spi_hid_parse_dev_desc(const struct hidspi_dev_descriptor *raw, -+ struct spi_hid_device_descriptor *desc) -+{ -+ desc->hid_version = le16_to_cpu(raw->bcd_ver); -+ desc->report_descriptor_length = le16_to_cpu(raw->rep_desc_len); -+ desc->max_input_length = le16_to_cpu(raw->max_input_len); -+ desc->max_output_length = le16_to_cpu(raw->max_output_len); -+ -+ /* FIXME: multi-fragment not supported, field below not used */ -+ desc->max_fragment_length = le16_to_cpu(raw->max_frag_len); -+ -+ desc->vendor_id = le16_to_cpu(raw->vendor_id); -+ desc->product_id = le16_to_cpu(raw->product_id); -+ desc->version_id = le16_to_cpu(raw->version_id); -+ desc->no_output_report_ack = le16_to_cpu(raw->flags) & BIT(0); -+} -+ -+static void spi_hid_populate_input_header(const u8 *buf, -+ struct spi_hid_input_header *header) -+{ -+ header->version = buf[0] & 0xf; -+ header->report_length = (get_unaligned_le16(&buf[1]) & 0x3fff) * 4; -+ header->last_fragment_flag = (buf[2] & 0x40) >> 6; -+ header->sync_const = buf[3]; -+} -+ -+static void spi_hid_populate_input_body(const u8 *buf, -+ struct input_report_body_header *body) -+{ -+ body->input_report_type = buf[0]; -+ body->content_len = get_unaligned_le16(&buf[1]); -+ body->content_id = buf[3]; -+} -+ -+static void spi_hid_input_report_prepare(struct spi_hid_input_buf *buf, -+ struct spi_hid_input_report *report) -+{ -+ struct spi_hid_input_header header; -+ struct input_report_body_header body; -+ -+ spi_hid_populate_input_header(buf->header, &header); -+ spi_hid_populate_input_body(buf->body, &body); -+ report->report_type = body.input_report_type; -+ report->content_length = body.content_len; -+ report->content_id = body.content_id; -+ report->content = buf->content; -+} -+ - static void spi_hid_populate_output_header(u8 *buf, - const struct spi_hid_conf *conf, - const struct spi_hid_output_report *report) -@@ -157,6 +279,33 @@ static void spi_hid_populate_output_header(u8 *buf, - buf[7] = report->content_id; - } - -+static int spi_hid_input_sync(struct spi_hid *shid, void *buf, u16 length, -+ bool is_header) -+{ -+ int error; -+ -+ shid->input_transfer[0].tx_buf = is_header ? -+ shid->read_approval_header : -+ shid->read_approval_body; -+ shid->input_transfer[0].len = SPI_HID_READ_APPROVAL_LEN; -+ -+ shid->input_transfer[1].rx_buf = buf; -+ shid->input_transfer[1].len = length; -+ -+ spi_message_init_with_transfers(&shid->input_message, -+ shid->input_transfer, 2); -+ -+ error = spi_sync(shid->spi, &shid->input_message); -+ if (error) { -+ dev_err(&shid->spi->dev, "Error starting sync transfer: %d\n", error); -+ shid->bus_error_count++; -+ shid->bus_last_error = error; -+ return error; -+ } -+ -+ return 0; -+} -+ - static int spi_hid_output(struct spi_hid *shid, const void *buf, u16 length) - { - int error; -@@ -187,15 +336,64 @@ static const char *spi_hid_power_mode_string(enum hidspi_power_state power_state - - static void spi_hid_stop_hid(struct spi_hid *shid) - { -- struct hid_device *hid = shid->hid; -+ struct hid_device *hid; - -- shid->hid = NULL; -- clear_bit(SPI_HID_READY, &shid->flags); -+ scoped_guard(mutex, &shid->io_lock) { -+ hid = shid->hid; -+ shid->hid = NULL; -+ clear_bit(SPI_HID_READY, &shid->flags); -+ } - - if (hid) - hid_destroy_device(hid); - } - -+static void spi_hid_error_handler(struct spi_hid *shid) -+{ -+ struct device *dev = &shid->spi->dev; -+ int error; -+ -+ guard(mutex)(&shid->power_lock); -+ if (shid->power_state == HIDSPI_OFF) -+ return; -+ -+ guard(disable_irq)(&shid->spi->irq); -+ -+ if (shid->reset_attempts++ >= SPI_HID_MAX_RESET_ATTEMPTS) { -+ dev_err(dev, "unresponsive device, aborting\n"); -+ spi_hid_stop_hid(shid); -+ shid->ops->assert_reset(shid->ops); -+ error = shid->ops->power_down(shid->ops); -+ if (error) { -+ dev_err(dev, "failed to disable regulator\n"); -+ shid->regulator_error_count++; -+ shid->regulator_last_error = error; -+ } -+ return; -+ } -+ -+ clear_bit(SPI_HID_READY, &shid->flags); -+ set_bit(SPI_HID_RESET_PENDING, &shid->flags); -+ -+ shid->ops->assert_reset(shid->ops); -+ -+ shid->power_state = HIDSPI_OFF; -+ -+ /* -+ * We want to cancel pending reset work as the device is being reset -+ * to recover from an error. cancel_work_sync will put us in a deadlock -+ * because this function is scheduled in 'reset_work' and we should -+ * avoid waiting for itself. -+ */ -+ cancel_work(&shid->reset_work); -+ -+ shid->ops->sleep_minimal_reset_delay(shid->ops); -+ -+ shid->power_state = HIDSPI_ON; -+ -+ shid->ops->deassert_reset(shid->ops); -+} -+ - static int __spi_hid_send_output_report(struct spi_hid *shid, - struct spi_hid_output_report *report) - { -@@ -213,6 +411,7 @@ static int __spi_hid_send_output_report(struct spi_hid *shid, - return -E2BIG; - } - -+ guard(mutex)(&shid->io_lock); - spi_hid_populate_output_header(buf->header, shid->conf, report); - - if (report->content_length) -@@ -263,6 +462,88 @@ static int spi_hid_sync_request(struct spi_hid *shid, - return 0; - } - -+/* -+ * Handle the reset response from the FW by sending a request for the device -+ * descriptor. -+ */ -+static void spi_hid_reset_response(struct spi_hid *shid) -+{ -+ struct device *dev = &shid->spi->dev; -+ struct spi_hid_output_report report = { -+ .report_type = DEVICE_DESCRIPTOR, -+ .content_length = 0x0, -+ .content_id = SPI_HID_OUTPUT_REPORT_CONTENT_ID_DESC_REQUEST, -+ .content = NULL, -+ }; -+ int error; -+ -+ if (test_bit(SPI_HID_READY, &shid->flags)) { -+ dev_err(dev, "Spontaneous FW reset!\n"); -+ clear_bit(SPI_HID_READY, &shid->flags); -+ shid->dir_count++; -+ } -+ -+ if (shid->power_state == HIDSPI_OFF) -+ return; -+ -+ error = spi_hid_sync_request(shid, &report); -+ if (error) { -+ dev_WARN_ONCE(dev, true, -+ "Failed to send device descriptor request: %d\n", error); -+ set_bit(SPI_HID_ERROR, &shid->flags); -+ schedule_work(&shid->reset_work); -+ } -+} -+ -+static int spi_hid_input_report_handler(struct spi_hid *shid, -+ struct spi_hid_input_buf *buf) -+{ -+ struct device *dev = &shid->spi->dev; -+ struct spi_hid_input_report r; -+ int error = 0; -+ -+ guard(mutex)(&shid->io_lock); -+ -+ if (!test_bit(SPI_HID_READY, &shid->flags) || -+ test_bit(SPI_HID_REFRESH_IN_PROGRESS, &shid->flags) || !shid->hid) { -+ dev_err(dev, "HID not ready\n"); -+ return 0; -+ } -+ -+ spi_hid_input_report_prepare(buf, &r); -+ -+ error = hid_input_report(shid->hid, HID_INPUT_REPORT, -+ r.content - 1, r.content_length + 1, 1); -+ -+ if (error == -ENODEV || error == -EBUSY) { -+ dev_err(dev, "ignoring report --> %d\n", error); -+ return 0; -+ } else if (error) { -+ dev_err(dev, "Bad input report: %d\n", error); -+ } -+ -+ return error; -+} -+ -+static void spi_hid_response_handler(struct spi_hid *shid, -+ struct input_report_body_header *body) -+{ -+ shid->response_length = body->content_len; -+ /* completion_done returns 0 if there are waiters, otherwise 1 */ -+ if (completion_done(&shid->output_done)) { -+ dev_err(&shid->spi->dev, "Unexpected response report\n"); -+ } else { -+ if (body->input_report_type == REPORT_DESCRIPTOR_RESPONSE || -+ body->input_report_type == GET_FEATURE_RESPONSE) { -+ memcpy(shid->response->body, shid->input->body, -+ sizeof(shid->input->body)); -+ memcpy(shid->response->content, shid->input->content, -+ body->content_len); -+ } -+ complete(&shid->output_done); -+ } -+} -+ - /* - * This function returns the length of the report descriptor, or a negative - * error code if something went wrong. -@@ -282,6 +563,8 @@ static int spi_hid_report_descriptor_request(struct spi_hid *shid) - if (ret) { - dev_err(dev, - "Expected report descriptor not received: %d\n", ret); -+ set_bit(SPI_HID_ERROR, &shid->flags); -+ schedule_work(&shid->reset_work); - return ret; - } - -@@ -320,7 +603,9 @@ static int spi_hid_create_device(struct spi_hid *shid) - hid->vendor, hid->product); - strscpy(hid->phys, dev_name(&shid->spi->dev), sizeof(hid->phys)); - -- shid->hid = hid; -+ scoped_guard(mutex, &shid->io_lock) { -+ shid->hid = hid; -+ } - - error = hid_add_device(hid); - if (error) { -@@ -336,6 +621,208 @@ static int spi_hid_create_device(struct spi_hid *shid) - return 0; - } - -+static void spi_hid_refresh_device(struct spi_hid *shid) -+{ -+ struct device *dev = &shid->spi->dev; -+ u32 new_crc32 = 0; -+ int error = 0; -+ -+ error = spi_hid_report_descriptor_request(shid); -+ if (error < 0) { -+ dev_err(dev, -+ "%s: failed report descriptor request: %d\n", -+ __func__, error); -+ return; -+ } -+ new_crc32 = crc32_le(0, (unsigned char const *)shid->response->content, -+ (size_t)error); -+ -+ /* Same report descriptor, so no need to create a new hid device. */ -+ if (new_crc32 == shid->report_descriptor_crc32) { -+ set_bit(SPI_HID_READY, &shid->flags); -+ return; -+ } -+ -+ shid->report_descriptor_crc32 = new_crc32; -+ -+ set_bit(SPI_HID_REFRESH_IN_PROGRESS, &shid->flags); -+ -+ spi_hid_stop_hid(shid); -+ -+ error = spi_hid_create_device(shid); -+ if (error) { -+ dev_err(dev, "%s: Failed to create hid device: %d\n", __func__, error); -+ return; -+ } -+ -+ clear_bit(SPI_HID_REFRESH_IN_PROGRESS, &shid->flags); -+} -+ -+static void spi_hid_reset_work(struct work_struct *work) -+{ -+ struct spi_hid *shid = -+ container_of(work, struct spi_hid, reset_work); -+ struct device *dev = &shid->spi->dev; -+ int error = 0; -+ bool resched = false; -+ -+ if (test_and_clear_bit(SPI_HID_RESET_RESPONSE, &shid->flags)) { -+ spi_hid_reset_response(shid); -+ resched = true; -+ } else if (test_and_clear_bit(SPI_HID_CREATE_DEVICE, &shid->flags)) { -+ guard(mutex)(&shid->power_lock); -+ if (shid->power_state != HIDSPI_OFF) { -+ if (!shid->hid) { -+ error = spi_hid_create_device(shid); -+ if (error) { -+ dev_err(dev, "%s: Failed to create hid device: %d\n", -+ __func__, error); -+ } -+ } else { -+ spi_hid_refresh_device(shid); -+ } -+ } else { -+ dev_err(dev, "%s: Powered off, returning\n", __func__); -+ } -+ resched = true; -+ } else if (test_and_clear_bit(SPI_HID_ERROR, &shid->flags)) { -+ spi_hid_error_handler(shid); -+ } -+ -+ /* -+ * If other flags are still pending, safely reschedule ourselves -+ * to process them in the next workqueue cycle. -+ */ -+ if (resched && (shid->flags & (BIT(SPI_HID_RESET_RESPONSE) | -+ BIT(SPI_HID_CREATE_DEVICE) | -+ BIT(SPI_HID_ERROR)))) { -+ schedule_work(&shid->reset_work); -+ } -+} -+ -+static int spi_hid_process_input_report(struct spi_hid *shid, -+ struct spi_hid_input_buf *buf) -+{ -+ struct spi_hid_input_header header; -+ struct input_report_body_header body; -+ struct device *dev = &shid->spi->dev; -+ struct hidspi_dev_descriptor *raw; -+ -+ spi_hid_populate_input_header(buf->header, &header); -+ spi_hid_populate_input_body(buf->body, &body); -+ -+ if (HIDSPI_INPUT_BODY_SIZE(body.content_len) > header.report_length) { -+ dev_err(dev, "Bad body length %zu > %u\n", HIDSPI_INPUT_BODY_SIZE(body.content_len), -+ header.report_length); -+ return -EPROTO; -+ } -+ -+ switch (body.input_report_type) { -+ case DATA: -+ return spi_hid_input_report_handler(shid, buf); -+ case RESET_RESPONSE: -+ clear_bit(SPI_HID_RESET_PENDING, &shid->flags); -+ set_bit(SPI_HID_RESET_RESPONSE, &shid->flags); -+ schedule_work(&shid->reset_work); -+ break; -+ case DEVICE_DESCRIPTOR_RESPONSE: -+ /* Mark the completion done to avoid timeout */ -+ spi_hid_response_handler(shid, &body); -+ -+ /* Reset attempts at every device descriptor fetch */ -+ shid->reset_attempts = 0; -+ raw = (struct hidspi_dev_descriptor *)buf->content; -+ -+ /* Validate device descriptor length before parsing */ -+ if (body.content_len != HIDSPI_DEVICE_DESCRIPTOR_SIZE) { -+ dev_err(dev, "Invalid content length %d, expected %zu\n", -+ body.content_len, -+ HIDSPI_DEVICE_DESCRIPTOR_SIZE); -+ return -EPROTO; -+ } -+ -+ if (le16_to_cpu(raw->dev_desc_len) != -+ HIDSPI_DEVICE_DESCRIPTOR_SIZE) { -+ dev_err(dev, -+ "Invalid wDeviceDescLength %d, expected %zu\n", -+ le16_to_cpu(raw->dev_desc_len), -+ HIDSPI_DEVICE_DESCRIPTOR_SIZE); -+ return -EPROTO; -+ } -+ -+ spi_hid_parse_dev_desc(raw, &shid->desc); -+ -+ if (shid->desc.hid_version != SPI_HID_SUPPORTED_VERSION) { -+ dev_err(dev, -+ "Unsupported device descriptor version %4x\n", -+ shid->desc.hid_version); -+ return -EPROTONOSUPPORT; -+ } -+ -+ set_bit(SPI_HID_CREATE_DEVICE, &shid->flags); -+ schedule_work(&shid->reset_work); -+ -+ break; -+ case OUTPUT_REPORT_RESPONSE: -+ if (shid->desc.no_output_report_ack) { -+ dev_err(dev, "Unexpected output report response\n"); -+ break; -+ } -+ fallthrough; -+ case GET_FEATURE_RESPONSE: -+ case SET_FEATURE_RESPONSE: -+ case REPORT_DESCRIPTOR_RESPONSE: -+ spi_hid_response_handler(shid, &body); -+ break; -+ /* -+ * FIXME: sending GET_INPUT and COMMAND reports not supported, thus -+ * throw away responses to those, they should never come. -+ */ -+ case GET_INPUT_REPORT_RESPONSE: -+ case COMMAND_RESPONSE: -+ dev_err(dev, "Not a supported report type: 0x%x\n", -+ body.input_report_type); -+ break; -+ default: -+ dev_err(dev, "Unknown input report: 0x%x\n", body.input_report_type); -+ return -EPROTO; -+ } -+ -+ return 0; -+} -+ -+static int spi_hid_bus_validate_header(struct spi_hid *shid, -+ struct spi_hid_input_header *header) -+{ -+ struct device *dev = &shid->spi->dev; -+ -+ if (header->version != SPI_HID_INPUT_HEADER_VERSION) { -+ dev_err(dev, "Unknown input report version (v 0x%x)\n", -+ header->version); -+ return -EINVAL; -+ } -+ -+ if (shid->desc.max_input_length != 0 && -+ header->report_length > shid->desc.max_input_length) { -+ dev_err(dev, "Input report body size %u > max expected of %u\n", -+ header->report_length, shid->desc.max_input_length); -+ return -EMSGSIZE; -+ } -+ -+ if (header->last_fragment_flag != 1) { -+ dev_err(dev, "Multi-fragment reports not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ if (header->sync_const != SPI_HID_INPUT_HEADER_SYNC_BYTE) { -+ dev_err(dev, "Invalid input report sync constant (0x%x)\n", -+ header->sync_const); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ - static int spi_hid_get_request(struct spi_hid *shid, u8 content_id) - { - struct device *dev = &shid->spi->dev; -@@ -352,6 +839,8 @@ static int spi_hid_get_request(struct spi_hid *shid, u8 content_id) - dev_err(dev, - "Expected get request response not received! Error %d\n", - error); -+ set_bit(SPI_HID_ERROR, &shid->flags); -+ schedule_work(&shid->reset_work); - return error; - } - -@@ -371,9 +860,83 @@ static int spi_hid_set_request(struct spi_hid *shid, u8 *arg_buf, u16 arg_len, - return spi_hid_sync_request(shid, &report); - } - --/* This is a placeholder. Will be implemented in the next patch. */ - static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - { -+ struct spi_hid *shid = _shid; -+ struct device *dev = &shid->spi->dev; -+ struct spi_hid_input_header header; -+ int error = 0; -+ -+ scoped_guard(mutex, &shid->io_lock) { -+ error = spi_hid_input_sync(shid, shid->input->header, -+ sizeof(shid->input->header), true); -+ if (error) { -+ dev_err(dev, "Failed to transfer header: %d\n", error); -+ goto err; -+ } -+ -+ if (shid->power_state == HIDSPI_OFF) { -+ dev_warn(dev, "Device is off after header was received\n"); -+ goto out; -+ } -+ -+ if (shid->input_message.status < 0) { -+ dev_warn(dev, "Error reading header: %d\n", -+ shid->input_message.status); -+ shid->bus_error_count++; -+ shid->bus_last_error = shid->input_message.status; -+ goto err; -+ } -+ -+ spi_hid_populate_input_header(shid->input->header, &header); -+ -+ error = spi_hid_bus_validate_header(shid, &header); -+ if (error) { -+ if (!test_bit(SPI_HID_RESET_PENDING, &shid->flags)) { -+ dev_err(dev, "Failed to validate header: %d\n", error); -+ print_hex_dump(KERN_ERR, "spi_hid: header buffer: ", -+ DUMP_PREFIX_NONE, 16, 1, shid->input->header, -+ sizeof(shid->input->header), false); -+ shid->bus_error_count++; -+ shid->bus_last_error = error; -+ goto err; -+ } -+ goto out; -+ } -+ -+ error = spi_hid_input_sync(shid, shid->input->body, header.report_length, -+ false); -+ if (error) { -+ dev_err(dev, "Failed to transfer body: %d\n", error); -+ goto err; -+ } -+ -+ if (shid->power_state == HIDSPI_OFF) { -+ dev_warn(dev, "Device is off after body was received\n"); -+ goto out; -+ } -+ -+ if (shid->input_message.status < 0) { -+ dev_warn(dev, "Error reading body: %d\n", -+ shid->input_message.status); -+ shid->bus_error_count++; -+ shid->bus_last_error = shid->input_message.status; -+ goto err; -+ } -+ } -+ -+ error = spi_hid_process_input_report(shid, shid->input); -+ if (error) { -+ dev_err(dev, "Failed to process input report: %d\n", error); -+ goto err; -+ } -+ -+out: -+ return IRQ_HANDLED; -+ -+err: -+ set_bit(SPI_HID_ERROR, &shid->flags); -+ schedule_work(&shid->reset_work); - return IRQ_HANDLED; - } - -@@ -610,10 +1173,13 @@ static int spi_hid_ll_output_report(struct hid_device *hid, __u8 *buf, - return -ENODEV; - } - -- if (shid->desc.no_output_report_ack) -- error = spi_hid_send_output_report(shid, &report); -- else -+ if (shid->desc.no_output_report_ack) { -+ scoped_guard(mutex, &shid->output_lock) { -+ error = spi_hid_send_output_report(shid, &report); -+ } -+ } else { - error = spi_hid_sync_request(shid, &report); -+ } - - if (error) { - dev_err(dev, "failed to send output report\n"); -@@ -701,14 +1267,23 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - shid->power_state = HIDSPI_ON; - shid->ops = ops; - shid->conf = conf; -+ set_bit(SPI_HID_RESET_PENDING, &shid->flags); - - spi_set_drvdata(spi, shid); - -+ /* Using now populated conf let's pre-calculate the read approvals */ -+ spi_hid_populate_read_approvals(shid->conf, shid->read_approval_header, -+ shid->read_approval_body); -+ - mutex_init(&shid->output_lock); -+ mutex_init(&shid->power_lock); -+ mutex_init(&shid->io_lock); - init_completion(&shid->output_done); - -+ INIT_WORK(&shid->reset_work, spi_hid_reset_work); -+ - /* -- * we need to allocate the buffer without knowing the maximum -+ * We need to allocate the buffer without knowing the maximum - * size of the reports. Let's use SZ_2K, then we do the - * real computation later. - */ -@@ -731,7 +1306,7 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - shid->ops->sleep_minimal_reset_delay(shid->ops); - - error = devm_request_threaded_irq(dev, spi->irq, NULL, spi_hid_dev_irq, -- IRQF_ONESHOT, dev_name(&spi->dev), shid); -+ IRQF_ONESHOT | IRQF_NO_AUTOEN, dev_name(&spi->dev), shid); - if (error) { - dev_err(dev, "%s: unable to request threaded IRQ\n", __func__); - return error; -@@ -745,13 +1320,11 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - - shid->ops->deassert_reset(shid->ops); - -+ enable_irq(spi->irq); -+ - dev_dbg(dev, "%s: d3 -> %s\n", __func__, - spi_hid_power_mode_string(shid->power_state)); - -- error = spi_hid_create_device(shid); -- if (error) -- return error; -- - return 0; - } - EXPORT_SYMBOL_GPL(spi_hid_core_probe); -@@ -762,6 +1335,9 @@ void spi_hid_core_remove(struct spi_device *spi) - struct device *dev = &spi->dev; - int error; - -+ disable_irq(spi->irq); -+ cancel_work_sync(&shid->reset_work); -+ - spi_hid_stop_hid(shid); - - shid->ops->assert_reset(shid->ops); diff --git a/kernel/2115-HID-spi_hid-add-spi_hid-traces.patch b/kernel/2115-HID-spi_hid-add-spi_hid-traces.patch deleted file mode 100644 index f109942..0000000 --- a/kernel/2115-HID-spi_hid-add-spi_hid-traces.patch +++ /dev/null @@ -1,530 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jingyuan Liang -Date: Tue, 9 Jun 2026 04:40:57 +0000 -Subject: [PATCH] HID: spi_hid: add spi_hid traces - -Add traces for purposed of debugging spi_hid driver. - -Signed-off-by: Dmitry Antipov -Signed-off-by: Angela Czubak -Signed-off-by: Jingyuan Liang ---- - drivers/hid/spi-hid/Makefile | 1 + - drivers/hid/spi-hid/spi-hid-core.c | 114 +++++++------------ - drivers/hid/spi-hid/spi-hid-core.h | 91 +++++++++++++++ - drivers/hid/spi-hid/spi-hid-trace.h | 169 ++++++++++++++++++++++++++++ - 4 files changed, 300 insertions(+), 75 deletions(-) - create mode 100644 drivers/hid/spi-hid/spi-hid-core.h - create mode 100644 drivers/hid/spi-hid/spi-hid-trace.h - -diff --git a/drivers/hid/spi-hid/Makefile b/drivers/hid/spi-hid/Makefile -index 92e24cddbfc2..733e006df56e 100644 ---- a/drivers/hid/spi-hid/Makefile -+++ b/drivers/hid/spi-hid/Makefile -@@ -7,3 +7,4 @@ - - obj-$(CONFIG_SPI_HID_CORE) += spi-hid.o - spi-hid-objs = spi-hid-core.o -+CFLAGS_spi-hid-core.o := -I$(src) -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -index f6ea2d4365a7..ef527999d6dc 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.c -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -44,6 +44,11 @@ - #include - #include - -+#include "spi-hid-core.h" -+ -+#define CREATE_TRACE_POINTS -+#include "spi-hid-trace.h" -+ - /* Protocol constants */ - #define SPI_HID_READ_APPROVAL_CONSTANT 0xff - #define SPI_HID_INPUT_HEADER_SYNC_BYTE 0x5a -@@ -82,13 +87,6 @@ - #define SPI_HID_CREATE_DEVICE 4 - #define SPI_HID_ERROR 5 - --/* Raw input buffer with data from the bus */ --struct spi_hid_input_buf { -- u8 header[HIDSPI_INPUT_HEADER_SIZE]; -- u8 body[HIDSPI_INPUT_BODY_HEADER_SIZE]; -- u8 content[]; --}; -- - /* Processed data from input report header */ - struct spi_hid_input_header { - u8 version; -@@ -105,12 +103,6 @@ struct spi_hid_input_report { - u8 *content; - }; - --/* Raw output report buffer to be put on the bus */ --struct spi_hid_output_buf { -- u8 header[SPI_HID_OUTPUT_HEADER_LEN]; -- u8 content[]; --}; -- - /* Data necessary to send an output report */ - struct spi_hid_output_report { - u8 report_type; -@@ -119,19 +111,6 @@ struct spi_hid_output_report { - u8 *content; - }; - --/* Processed data from a device descriptor */ --struct spi_hid_device_descriptor { -- u16 hid_version; -- u16 report_descriptor_length; -- u16 max_input_length; -- u16 max_output_length; -- u16 max_fragment_length; -- u16 vendor_id; -- u16 product_id; -- u16 version_id; -- u8 no_output_report_ack; --}; -- - /* struct spi_hid_conf - Conf provided to the core */ - struct spi_hid_conf { - u32 input_report_header_address; -@@ -157,55 +136,6 @@ struct spihid_ops { - void (*sleep_minimal_reset_delay)(struct spihid_ops *ops); - }; - --/* Driver context */ --struct spi_hid { -- struct spi_device *spi; /* spi device. */ -- struct hid_device *hid; /* pointer to corresponding HID dev. */ -- -- struct spi_transfer input_transfer[2]; /* Transfer buffer for read and write. */ -- struct spi_message input_message; /* used to execute a sequence of spi transfers. */ -- -- struct spihid_ops *ops; -- struct spi_hid_conf *conf; -- -- struct spi_hid_device_descriptor desc; /* HID device descriptor. */ -- struct spi_hid_output_buf *output; /* Output buffer. */ -- struct spi_hid_input_buf *input; /* Input buffer. */ -- struct spi_hid_input_buf *response; /* Response buffer. */ -- -- u16 response_length; -- u16 bufsize; -- -- enum hidspi_power_state power_state; -- -- u8 reset_attempts; /* The number of reset attempts. */ -- -- unsigned long flags; /* device flags. */ -- -- struct work_struct reset_work; -- -- /* Control lock to ensure complete output transaction. */ -- struct mutex output_lock; -- /* Power lock to make sure one power state change at a time. */ -- struct mutex power_lock; -- /* Protect bus I/O and shid->hid pointer lifecycle. */ -- struct mutex io_lock; -- -- struct completion output_done; -- -- u32 report_descriptor_crc32; /* HID report descriptor crc32 checksum. */ -- -- u32 regulator_error_count; -- int regulator_last_error; -- u32 bus_error_count; -- int bus_last_error; -- u32 dir_count; /* device initiated reset count. */ -- -- /* DMA-safe transfer buffers */ -- u8 read_approval_header[SPI_HID_READ_APPROVAL_LEN] ____cacheline_aligned; -- u8 read_approval_body[SPI_HID_READ_APPROVAL_LEN]; --}; -- - static struct hid_ll_driver spi_hid_ll_driver; - - static void spi_hid_populate_read_approvals(const struct spi_hid_conf *conf, -@@ -295,6 +225,11 @@ static int spi_hid_input_sync(struct spi_hid *shid, void *buf, u16 length, - spi_message_init_with_transfers(&shid->input_message, - shid->input_transfer, 2); - -+ trace_spi_hid_input_sync(shid, shid->input_transfer[0].tx_buf, -+ shid->input_transfer[0].len, -+ shid->input_transfer[1].rx_buf, -+ shid->input_transfer[1].len, 0); -+ - error = spi_sync(shid->spi, &shid->input_message); - if (error) { - dev_err(&shid->spi->dev, "Error starting sync transfer: %d\n", error); -@@ -353,6 +288,8 @@ static void spi_hid_error_handler(struct spi_hid *shid) - struct device *dev = &shid->spi->dev; - int error; - -+ trace_spi_hid_error_handler(shid); -+ - guard(mutex)(&shid->power_lock); - if (shid->power_state == HIDSPI_OFF) - return; -@@ -477,6 +414,8 @@ static void spi_hid_reset_response(struct spi_hid *shid) - }; - int error; - -+ trace_spi_hid_reset_response(shid); -+ - if (test_bit(SPI_HID_READY, &shid->flags)) { - dev_err(dev, "Spontaneous FW reset!\n"); - clear_bit(SPI_HID_READY, &shid->flags); -@@ -503,6 +442,7 @@ static int spi_hid_input_report_handler(struct spi_hid *shid, - int error = 0; - - guard(mutex)(&shid->io_lock); -+ trace_spi_hid_input_report_handler(shid); - - if (!test_bit(SPI_HID_READY, &shid->flags) || - test_bit(SPI_HID_REFRESH_IN_PROGRESS, &shid->flags) || !shid->hid) { -@@ -528,6 +468,8 @@ static int spi_hid_input_report_handler(struct spi_hid *shid, - static void spi_hid_response_handler(struct spi_hid *shid, - struct input_report_body_header *body) - { -+ trace_spi_hid_response_handler(shid); -+ - shid->response_length = body->content_len; - /* completion_done returns 0 if there are waiters, otherwise 1 */ - if (completion_done(&shid->output_done)) { -@@ -584,6 +526,8 @@ static int spi_hid_create_device(struct spi_hid *shid) - struct device *dev = &shid->spi->dev; - int error; - -+ trace_spi_hid_create_device(shid); -+ - hid = hid_allocate_device(); - error = PTR_ERR_OR_ZERO(hid); - if (error) { -@@ -627,6 +571,8 @@ static void spi_hid_refresh_device(struct spi_hid *shid) - u32 new_crc32 = 0; - int error = 0; - -+ trace_spi_hid_refresh_device(shid); -+ - error = spi_hid_report_descriptor_request(shid); - if (error < 0) { - dev_err(dev, -@@ -708,6 +654,8 @@ static int spi_hid_process_input_report(struct spi_hid *shid, - struct device *dev = &shid->spi->dev; - struct hidspi_dev_descriptor *raw; - -+ trace_spi_hid_process_input_report(shid); -+ - spi_hid_populate_input_header(buf->header, &header); - spi_hid_populate_input_body(buf->body, &body); - -@@ -867,6 +815,9 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - struct spi_hid_input_header header; - int error = 0; - -+ trace_spi_hid_dev_irq(shid, irq); -+ trace_spi_hid_header_transfer(shid); -+ - scoped_guard(mutex, &shid->io_lock) { - error = spi_hid_input_sync(shid, shid->input->header, - sizeof(shid->input->header), true); -@@ -880,6 +831,13 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - goto out; - } - -+ trace_spi_hid_input_header_complete(shid, -+ shid->input_transfer[0].tx_buf, -+ shid->input_transfer[0].len, -+ shid->input_transfer[1].rx_buf, -+ shid->input_transfer[1].len, -+ shid->input_message.status); -+ - if (shid->input_message.status < 0) { - dev_warn(dev, "Error reading header: %d\n", - shid->input_message.status); -@@ -916,6 +874,12 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - goto out; - } - -+ trace_spi_hid_input_body_complete(shid, shid->input_transfer[0].tx_buf, -+ shid->input_transfer[0].len, -+ shid->input_transfer[1].rx_buf, -+ shid->input_transfer[1].len, -+ shid->input_message.status); -+ - if (shid->input_message.status < 0) { - dev_warn(dev, "Error reading body: %d\n", - shid->input_message.status); -diff --git a/drivers/hid/spi-hid/spi-hid-core.h b/drivers/hid/spi-hid/spi-hid-core.h -new file mode 100644 -index 000000000000..293e2cfcfbf7 ---- /dev/null -+++ b/drivers/hid/spi-hid/spi-hid-core.h -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021 Microsoft Corporation -+ * Copyright (c) 2026 Google LLC -+ */ -+ -+#ifndef SPI_HID_CORE_H -+#define SPI_HID_CORE_H -+ -+#include -+#include -+ -+/* Protocol message size constants */ -+#define SPI_HID_READ_APPROVAL_LEN 5 -+#define SPI_HID_OUTPUT_HEADER_LEN 8 -+ -+/* Raw input buffer with data from the bus */ -+struct spi_hid_input_buf { -+ u8 header[HIDSPI_INPUT_HEADER_SIZE]; -+ u8 body[HIDSPI_INPUT_BODY_HEADER_SIZE]; -+ u8 content[]; -+}; -+ -+/* Raw output report buffer to be put on the bus */ -+struct spi_hid_output_buf { -+ u8 header[SPI_HID_OUTPUT_HEADER_LEN]; -+ u8 content[]; -+}; -+ -+/* Processed data from a device descriptor */ -+struct spi_hid_device_descriptor { -+ u16 hid_version; -+ u16 report_descriptor_length; -+ u16 max_input_length; -+ u16 max_output_length; -+ u16 max_fragment_length; -+ u16 vendor_id; -+ u16 product_id; -+ u16 version_id; -+ u8 no_output_report_ack; -+}; -+ -+/* Driver context */ -+struct spi_hid { -+ struct spi_device *spi; /* spi device. */ -+ struct hid_device *hid; /* pointer to corresponding HID dev. */ -+ -+ struct spi_transfer input_transfer[2]; /* Transfer buffer for read and write. */ -+ struct spi_message input_message; /* used to execute a sequence of spi transfers. */ -+ -+ struct spihid_ops *ops; -+ struct spi_hid_conf *conf; -+ -+ struct spi_hid_device_descriptor desc; /* HID device descriptor. */ -+ struct spi_hid_output_buf *output; /* Output buffer. */ -+ struct spi_hid_input_buf *input; /* Input buffer. */ -+ struct spi_hid_input_buf *response; /* Response buffer. */ -+ -+ u16 response_length; -+ u16 bufsize; -+ -+ enum hidspi_power_state power_state; -+ -+ u8 reset_attempts; /* The number of reset attempts. */ -+ -+ unsigned long flags; /* device flags. */ -+ -+ struct work_struct reset_work; -+ -+ /* Control lock to ensure complete output transaction. */ -+ struct mutex output_lock; -+ /* Power lock to make sure one power state change at a time. */ -+ struct mutex power_lock; -+ /* I/O lock to prevent concurrent output writes during the input read. */ -+ struct mutex io_lock; -+ -+ struct completion output_done; -+ -+ u8 read_approval_header[SPI_HID_READ_APPROVAL_LEN]; -+ u8 read_approval_body[SPI_HID_READ_APPROVAL_LEN]; -+ -+ u32 report_descriptor_crc32; /* HID report descriptor crc32 checksum. */ -+ -+ u32 regulator_error_count; -+ int regulator_last_error; -+ u32 bus_error_count; -+ int bus_last_error; -+ u32 dir_count; /* device initiated reset count. */ -+}; -+ -+#endif /* SPI_HID_CORE_H */ -diff --git a/drivers/hid/spi-hid/spi-hid-trace.h b/drivers/hid/spi-hid/spi-hid-trace.h -new file mode 100644 -index 000000000000..841ec491826d ---- /dev/null -+++ b/drivers/hid/spi-hid/spi-hid-trace.h -@@ -0,0 +1,169 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021 Microsoft Corporation -+ */ -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM spi_hid -+ -+#if !defined(_SPI_HID_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _SPI_HID_TRACE_H -+ -+#include -+#include -+#include "spi-hid-core.h" -+ -+DECLARE_EVENT_CLASS(spi_hid_transfer, -+ TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len, -+ const void *rx_buf, u16 rx_len, int ret), -+ -+ TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret), -+ -+ TP_STRUCT__entry( -+ __field(int, bus_num) -+ __field(int, chip_select) -+ __field(int, ret) -+ __dynamic_array(u8, rx_buf, rx_len) -+ __dynamic_array(u8, tx_buf, tx_len) -+ ), -+ -+ TP_fast_assign( -+ __entry->bus_num = shid->spi->controller->bus_num; -+ __entry->chip_select = spi_get_chipselect(shid->spi, 0); -+ __entry->ret = ret; -+ -+ memcpy(__get_dynamic_array(tx_buf), tx_buf, tx_len); -+ memcpy(__get_dynamic_array(rx_buf), rx_buf, rx_len); -+ ), -+ -+ TP_printk("spi%d.%d: len=%d tx=[%*phD] rx=[%*phD] --> %d", -+ __entry->bus_num, __entry->chip_select, -+ __get_dynamic_array_len(tx_buf) + __get_dynamic_array_len(rx_buf), -+ __get_dynamic_array_len(tx_buf), __get_dynamic_array(tx_buf), -+ __get_dynamic_array_len(rx_buf), __get_dynamic_array(rx_buf), -+ __entry->ret) -+); -+ -+DEFINE_EVENT(spi_hid_transfer, spi_hid_input_sync, -+ TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len, -+ const void *rx_buf, u16 rx_len, int ret), -+ TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)); -+ -+DEFINE_EVENT(spi_hid_transfer, spi_hid_input_header_complete, -+ TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len, -+ const void *rx_buf, u16 rx_len, int ret), -+ TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)); -+ -+DEFINE_EVENT(spi_hid_transfer, spi_hid_input_body_complete, -+ TP_PROTO(struct spi_hid *shid, const void *tx_buf, int tx_len, -+ const void *rx_buf, u16 rx_len, int ret), -+ TP_ARGS(shid, tx_buf, tx_len, rx_buf, rx_len, ret)); -+ -+DECLARE_EVENT_CLASS(spi_hid_irq, -+ TP_PROTO(struct spi_hid *shid, int irq), -+ -+ TP_ARGS(shid, irq), -+ -+ TP_STRUCT__entry( -+ __field(int, bus_num) -+ __field(int, chip_select) -+ __field(int, irq) -+ ), -+ -+ TP_fast_assign( -+ __entry->bus_num = shid->spi->controller->bus_num; -+ __entry->chip_select = spi_get_chipselect(shid->spi, 0); -+ __entry->irq = irq; -+ ), -+ -+ TP_printk("spi%d.%d: IRQ %d", -+ __entry->bus_num, __entry->chip_select, __entry->irq) -+); -+ -+DEFINE_EVENT(spi_hid_irq, spi_hid_dev_irq, -+ TP_PROTO(struct spi_hid *shid, int irq), TP_ARGS(shid, irq)); -+ -+DECLARE_EVENT_CLASS(spi_hid, -+ TP_PROTO(struct spi_hid *shid), -+ -+ TP_ARGS(shid), -+ -+ TP_STRUCT__entry( -+ __field(int, bus_num) -+ __field(int, chip_select) -+ __field(int, power_state) -+ __field(u32, flags) -+ -+ __field(int, vendor_id) -+ __field(int, product_id) -+ __field(int, max_input_length) -+ __field(int, max_output_length) -+ __field(u16, hid_version) -+ __field(u16, report_descriptor_length) -+ __field(u16, version_id) -+ ), -+ -+ TP_fast_assign( -+ __entry->bus_num = shid->spi->controller->bus_num; -+ __entry->chip_select = spi_get_chipselect(shid->spi, 0); -+ __entry->power_state = shid->power_state; -+ __entry->flags = shid->flags; -+ -+ __entry->vendor_id = shid->desc.vendor_id; -+ __entry->product_id = shid->desc.product_id; -+ __entry->max_input_length = shid->desc.max_input_length; -+ __entry->max_output_length = shid->desc.max_output_length; -+ __entry->hid_version = shid->desc.hid_version; -+ __entry->report_descriptor_length = -+ shid->desc.report_descriptor_length; -+ __entry->version_id = shid->desc.version_id; -+ ), -+ -+ TP_printk("spi%d.%d: (%04x:%04x v%d) HID v%d.%d state p:%d len i:%d o:%d r:%d flags 0x%08x", -+ __entry->bus_num, __entry->chip_select, -+ __entry->vendor_id, __entry->product_id, __entry->version_id, -+ __entry->hid_version >> 8, __entry->hid_version & 0xff, -+ __entry->power_state, __entry->max_input_length, -+ __entry->max_output_length, __entry->report_descriptor_length, -+ __entry->flags) -+); -+ -+DEFINE_EVENT(spi_hid, spi_hid_header_transfer, TP_PROTO(struct spi_hid *shid), -+ TP_ARGS(shid)); -+ -+DEFINE_EVENT(spi_hid, spi_hid_process_input_report, -+ TP_PROTO(struct spi_hid *shid), TP_ARGS(shid)); -+ -+DEFINE_EVENT(spi_hid, spi_hid_input_report_handler, -+ TP_PROTO(struct spi_hid *shid), TP_ARGS(shid)); -+ -+DEFINE_EVENT(spi_hid, spi_hid_reset_response, TP_PROTO(struct spi_hid *shid), -+ TP_ARGS(shid)); -+ -+DEFINE_EVENT(spi_hid, spi_hid_create_device, TP_PROTO(struct spi_hid *shid), -+ TP_ARGS(shid)); -+ -+DEFINE_EVENT(spi_hid, spi_hid_refresh_device, TP_PROTO(struct spi_hid *shid), -+ TP_ARGS(shid)); -+ -+DEFINE_EVENT(spi_hid, spi_hid_response_handler, TP_PROTO(struct spi_hid *shid), -+ TP_ARGS(shid)); -+ -+DEFINE_EVENT(spi_hid, spi_hid_error_handler, TP_PROTO(struct spi_hid *shid), -+ TP_ARGS(shid)); -+ -+#endif /* _SPI_HID_TRACE_H */ -+ -+/* -+ * The following must be outside the protection of the above #if block. -+ */ -+#undef TRACE_INCLUDE_PATH -+#undef TRACE_INCLUDE_FILE -+#define TRACE_INCLUDE_PATH . -+ -+/* -+ * It is required that the TRACE_INCLUDE_FILE be the same -+ * as this file without the ".h". -+ */ -+#define TRACE_INCLUDE_FILE spi-hid-trace -+#include diff --git a/kernel/2116-HID-spi_hid-add-ACPI-support-for-SPI-over-HID.patch b/kernel/2116-HID-spi_hid-add-ACPI-support-for-SPI-over-HID.patch deleted file mode 100644 index d4d648b..0000000 --- a/kernel/2116-HID-spi_hid-add-ACPI-support-for-SPI-over-HID.patch +++ /dev/null @@ -1,409 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Angela Czubak -Date: Tue, 9 Jun 2026 04:40:58 +0000 -Subject: [PATCH] HID: spi_hid: add ACPI support for SPI over HID - -Detect SPI HID devices described in ACPI. - -Signed-off-by: Angela Czubak -Reviewed-by: Dmitry Torokhov -Signed-off-by: Jingyuan Liang ---- - drivers/hid/spi-hid/Kconfig | 15 ++ - drivers/hid/spi-hid/Makefile | 1 + - drivers/hid/spi-hid/spi-hid-acpi.c | 253 +++++++++++++++++++++++++++++ - drivers/hid/spi-hid/spi-hid-core.c | 26 +-- - drivers/hid/spi-hid/spi-hid.h | 45 +++++ - 5 files changed, 315 insertions(+), 25 deletions(-) - create mode 100644 drivers/hid/spi-hid/spi-hid-acpi.c - create mode 100644 drivers/hid/spi-hid/spi-hid.h - -diff --git a/drivers/hid/spi-hid/Kconfig b/drivers/hid/spi-hid/Kconfig -index 836fdefe8345..114b1e00da39 100644 ---- a/drivers/hid/spi-hid/Kconfig -+++ b/drivers/hid/spi-hid/Kconfig -@@ -10,6 +10,21 @@ menuconfig SPI_HID - - if SPI_HID - -+config SPI_HID_ACPI -+ tristate "HID over SPI transport layer ACPI driver" -+ depends on ACPI -+ select SPI_HID_CORE -+ help -+ Say Y here if you use a keyboard, a touchpad, a touchscreen, or any -+ other HID based devices which are connected to your computer via SPI. -+ This driver supports ACPI-based systems. -+ -+ If unsure, say N. -+ -+ This support is also available as a module. If so, the module -+ will be called spi-hid-acpi. It will also build/depend on the -+ module spi-hid. -+ - config SPI_HID_CORE - tristate - endif -diff --git a/drivers/hid/spi-hid/Makefile b/drivers/hid/spi-hid/Makefile -index 733e006df56e..3ca326602643 100644 ---- a/drivers/hid/spi-hid/Makefile -+++ b/drivers/hid/spi-hid/Makefile -@@ -8,3 +8,4 @@ - obj-$(CONFIG_SPI_HID_CORE) += spi-hid.o - spi-hid-objs = spi-hid-core.o - CFLAGS_spi-hid-core.o := -I$(src) -+obj-$(CONFIG_SPI_HID_ACPI) += spi-hid-acpi.o -diff --git a/drivers/hid/spi-hid/spi-hid-acpi.c b/drivers/hid/spi-hid/spi-hid-acpi.c -new file mode 100644 -index 000000000000..298e3ba44d8a ---- /dev/null -+++ b/drivers/hid/spi-hid/spi-hid-acpi.c -@@ -0,0 +1,253 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * HID over SPI protocol, ACPI related code -+ * -+ * Copyright (c) 2021 Microsoft Corporation -+ * Copyright (c) 2026 Google LLC -+ * -+ * This code was forked out of the HID over SPI core code, which is partially -+ * based on "HID over I2C protocol implementation: -+ * -+ * Copyright (c) 2012 Benjamin Tissoires -+ * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France -+ * Copyright (c) 2012 Red Hat, Inc -+ * -+ * which in turn is partially based on "USB HID support for Linux": -+ * -+ * Copyright (c) 1999 Andreas Gal -+ * Copyright (c) 2000-2005 Vojtech Pavlik -+ * Copyright (c) 2005 Michael Haboustak for Concept2, Inc -+ * Copyright (c) 2007-2008 Oliver Neukum -+ * Copyright (c) 2006-2010 Jiri Kosina -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "spi-hid.h" -+ -+/* Config structure is filled with data from ACPI */ -+struct spi_hid_acpi_config { -+ struct spihid_ops ops; -+ -+ struct spi_hid_conf property_conf; -+ u32 post_power_on_delay_ms; -+ u32 minimal_reset_delay_ms; -+ struct acpi_device *adev; -+}; -+ -+/* HID SPI Device: 6e2ac436-0fcf41af-a265-b32a220dcfab */ -+static guid_t spi_hid_guid = -+ GUID_INIT(0x6E2AC436, 0x0FCF, 0x41AF, -+ 0xA2, 0x65, 0xB3, 0x2A, 0x22, 0x0D, 0xCF, 0xAB); -+ -+static int spi_hid_acpi_populate_config(struct spi_hid_acpi_config *conf, -+ struct acpi_device *adev) -+{ -+ acpi_handle handle = acpi_device_handle(adev); -+ union acpi_object *obj; -+ -+ conf->adev = adev; -+ -+ /* Revision 3 for HID over SPI V1, see specification. */ -+ obj = acpi_evaluate_dsm_typed(handle, &spi_hid_guid, 3, 1, NULL, -+ ACPI_TYPE_INTEGER); -+ if (!obj) { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID input report header address failed"); -+ return -ENODEV; -+ } -+ conf->property_conf.input_report_header_address = obj->integer.value; -+ ACPI_FREE(obj); -+ -+ obj = acpi_evaluate_dsm_typed(handle, &spi_hid_guid, 3, 2, NULL, -+ ACPI_TYPE_INTEGER); -+ if (!obj) { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID input report body address failed"); -+ return -ENODEV; -+ } -+ conf->property_conf.input_report_body_address = obj->integer.value; -+ ACPI_FREE(obj); -+ -+ obj = acpi_evaluate_dsm_typed(handle, &spi_hid_guid, 3, 3, NULL, -+ ACPI_TYPE_INTEGER); -+ if (!obj) { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID output report header address failed"); -+ return -ENODEV; -+ } -+ conf->property_conf.output_report_address = obj->integer.value; -+ ACPI_FREE(obj); -+ -+ obj = acpi_evaluate_dsm_typed(handle, &spi_hid_guid, 3, 4, NULL, -+ ACPI_TYPE_BUFFER); -+ if (!obj) { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID read opcode failed"); -+ return -ENODEV; -+ } -+ if (obj->buffer.length == 1) { -+ conf->property_conf.read_opcode = obj->buffer.pointer[0]; -+ } else { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID read opcode, too long buffer"); -+ ACPI_FREE(obj); -+ return -ENODEV; -+ } -+ ACPI_FREE(obj); -+ -+ obj = acpi_evaluate_dsm_typed(handle, &spi_hid_guid, 3, 5, NULL, -+ ACPI_TYPE_BUFFER); -+ if (!obj) { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID write opcode failed"); -+ return -ENODEV; -+ } -+ if (obj->buffer.length == 1) { -+ conf->property_conf.write_opcode = obj->buffer.pointer[0]; -+ } else { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID write opcode, too long buffer"); -+ ACPI_FREE(obj); -+ return -ENODEV; -+ } -+ ACPI_FREE(obj); -+ -+ /* Value not provided in ACPI,*/ -+ conf->post_power_on_delay_ms = 5; -+ conf->minimal_reset_delay_ms = 150; -+ -+ if (!acpi_has_method(handle, "_RST")) { -+ acpi_handle_err(handle, "No reset method for acpi handle"); -+ return -EINVAL; -+ } -+ -+ /* FIXME: not reading hid-over-spi-flags, multi-SPI not supported */ -+ -+ return 0; -+} -+ -+static int spi_hid_acpi_power_none(struct spihid_ops *ops) -+{ -+ return 0; -+} -+ -+static int spi_hid_acpi_power_down(struct spihid_ops *ops) -+{ -+ struct spi_hid_acpi_config *conf = container_of(ops, -+ struct spi_hid_acpi_config, -+ ops); -+ -+ return acpi_device_set_power(conf->adev, ACPI_STATE_D3); -+} -+ -+static int spi_hid_acpi_power_up(struct spihid_ops *ops) -+{ -+ struct spi_hid_acpi_config *conf = container_of(ops, -+ struct spi_hid_acpi_config, -+ ops); -+ int error; -+ -+ error = acpi_device_set_power(conf->adev, ACPI_STATE_D0); -+ if (error) { -+ dev_err(&conf->adev->dev, "Error could not power up ACPI device: %d.", error); -+ return error; -+ } -+ -+ if (conf->post_power_on_delay_ms) -+ msleep(conf->post_power_on_delay_ms); -+ -+ return 0; -+} -+ -+static int spi_hid_acpi_assert_reset(struct spihid_ops *ops) -+{ -+ return 0; -+} -+ -+static int spi_hid_acpi_deassert_reset(struct spihid_ops *ops) -+{ -+ struct spi_hid_acpi_config *conf = container_of(ops, -+ struct spi_hid_acpi_config, -+ ops); -+ -+ return device_reset(&conf->adev->dev); -+} -+ -+static void spi_hid_acpi_sleep_minimal_reset_delay(struct spihid_ops *ops) -+{ -+ struct spi_hid_acpi_config *conf = container_of(ops, -+ struct spi_hid_acpi_config, -+ ops); -+ fsleep(1000 * conf->minimal_reset_delay_ms); -+} -+ -+static int spi_hid_acpi_probe(struct spi_device *spi) -+{ -+ struct device *dev = &spi->dev; -+ struct acpi_device *adev; -+ struct spi_hid_acpi_config *config; -+ int error; -+ -+ adev = ACPI_COMPANION(dev); -+ if (!adev) { -+ dev_err(dev, "Error could not get ACPI device."); -+ return -ENODEV; -+ } -+ -+ config = devm_kzalloc(dev, sizeof(struct spi_hid_acpi_config), -+ GFP_KERNEL); -+ if (!config) -+ return -ENOMEM; -+ -+ if (acpi_device_power_manageable(adev)) { -+ config->ops.power_up = spi_hid_acpi_power_up; -+ config->ops.power_down = spi_hid_acpi_power_down; -+ } else { -+ config->ops.power_up = spi_hid_acpi_power_none; -+ config->ops.power_down = spi_hid_acpi_power_none; -+ } -+ config->ops.assert_reset = spi_hid_acpi_assert_reset; -+ config->ops.deassert_reset = spi_hid_acpi_deassert_reset; -+ config->ops.sleep_minimal_reset_delay = -+ spi_hid_acpi_sleep_minimal_reset_delay; -+ -+ error = spi_hid_acpi_populate_config(config, adev); -+ if (error) { -+ dev_err(dev, "%s: unable to populate config data.", __func__); -+ return error; -+ } -+ -+ return spi_hid_core_probe(spi, &config->ops, &config->property_conf); -+} -+ -+static const struct acpi_device_id spi_hid_acpi_match[] = { -+ { "ACPI0C51", 0 }, -+ { "PNP0C51", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, spi_hid_acpi_match); -+ -+static struct spi_driver spi_hid_acpi_driver = { -+ .driver = { -+ .name = "spi_hid_acpi", -+ .owner = THIS_MODULE, -+ .acpi_match_table = spi_hid_acpi_match, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ .dev_groups = spi_hid_groups, -+ }, -+ .probe = spi_hid_acpi_probe, -+ .remove = spi_hid_core_remove, -+}; -+ -+module_spi_driver(spi_hid_acpi_driver); -+ -+MODULE_DESCRIPTION("HID over SPI ACPI transport driver"); -+MODULE_AUTHOR("Angela Czubak "); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -index ef527999d6dc..698e72102c11 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.c -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -44,6 +44,7 @@ - #include - #include - -+#include "spi-hid.h" - #include "spi-hid-core.h" - - #define CREATE_TRACE_POINTS -@@ -111,31 +112,6 @@ struct spi_hid_output_report { - u8 *content; - }; - --/* struct spi_hid_conf - Conf provided to the core */ --struct spi_hid_conf { -- u32 input_report_header_address; -- u32 input_report_body_address; -- u32 output_report_address; -- u8 read_opcode; -- u8 write_opcode; --}; -- --/** -- * struct spihid_ops - Ops provided to the core -- * @power_up: do sequencing to power up the device -- * @power_down: do sequencing to power down the device -- * @assert_reset: do sequencing to assert the reset line -- * @deassert_reset: do sequencing to deassert the reset line -- * @sleep_minimal_reset_delay: minimal sleep delay during reset -- */ --struct spihid_ops { -- int (*power_up)(struct spihid_ops *ops); -- int (*power_down)(struct spihid_ops *ops); -- int (*assert_reset)(struct spihid_ops *ops); -- int (*deassert_reset)(struct spihid_ops *ops); -- void (*sleep_minimal_reset_delay)(struct spihid_ops *ops); --}; -- - static struct hid_ll_driver spi_hid_ll_driver; - - static void spi_hid_populate_read_approvals(const struct spi_hid_conf *conf, -diff --git a/drivers/hid/spi-hid/spi-hid.h b/drivers/hid/spi-hid/spi-hid.h -new file mode 100644 -index 000000000000..f5a5f4d54beb ---- /dev/null -+++ b/drivers/hid/spi-hid/spi-hid.h -@@ -0,0 +1,45 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2021 Microsoft Corporation -+ * Copyright (c) 2026 Google LLC -+ */ -+ -+#ifndef SPI_HID_H -+#define SPI_HID_H -+ -+#include -+#include -+ -+/* struct spi_hid_conf - Conf provided to the core */ -+struct spi_hid_conf { -+ u32 input_report_header_address; -+ u32 input_report_body_address; -+ u32 output_report_address; -+ u8 read_opcode; -+ u8 write_opcode; -+}; -+ -+/** -+ * struct spihid_ops - Ops provided to the core -+ * @power_up: do sequencing to power up the device -+ * @power_down: do sequencing to power down the device -+ * @assert_reset: do sequencing to assert the reset line -+ * @deassert_reset: do sequencing to deassert the reset line -+ * @sleep_minimal_reset_delay: minimal sleep delay during reset -+ */ -+struct spihid_ops { -+ int (*power_up)(struct spihid_ops *ops); -+ int (*power_down)(struct spihid_ops *ops); -+ int (*assert_reset)(struct spihid_ops *ops); -+ int (*deassert_reset)(struct spihid_ops *ops); -+ void (*sleep_minimal_reset_delay)(struct spihid_ops *ops); -+}; -+ -+int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, -+ struct spi_hid_conf *conf); -+ -+void spi_hid_core_remove(struct spi_device *spi); -+ -+extern const struct attribute_group *spi_hid_groups[]; -+ -+#endif /* SPI_HID_H */ diff --git a/kernel/2117-HID-spi_hid-add-device-tree-support-for-SPI-over-HID.patch b/kernel/2117-HID-spi_hid-add-device-tree-support-for-SPI-over-HID.patch deleted file mode 100644 index e9b2fb4..0000000 --- a/kernel/2117-HID-spi_hid-add-device-tree-support-for-SPI-over-HID.patch +++ /dev/null @@ -1,301 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jarrett Schultz -Date: Tue, 9 Jun 2026 04:40:59 +0000 -Subject: [PATCH] HID: spi_hid: add device tree support for SPI over HID - -Signed-off-by: Dmitry Antipov -Signed-off-by: Jingyuan Liang ---- - drivers/hid/spi-hid/Kconfig | 15 ++ - drivers/hid/spi-hid/Makefile | 1 + - drivers/hid/spi-hid/spi-hid-of.c | 246 +++++++++++++++++++++++++++++++ - 3 files changed, 262 insertions(+) - create mode 100644 drivers/hid/spi-hid/spi-hid-of.c - -diff --git a/drivers/hid/spi-hid/Kconfig b/drivers/hid/spi-hid/Kconfig -index 114b1e00da39..76a2cd587a3e 100644 ---- a/drivers/hid/spi-hid/Kconfig -+++ b/drivers/hid/spi-hid/Kconfig -@@ -25,6 +25,21 @@ config SPI_HID_ACPI - will be called spi-hid-acpi. It will also build/depend on the - module spi-hid. - -+config SPI_HID_OF -+ tristate "HID over SPI transport layer Open Firmware driver" -+ depends on OF -+ select SPI_HID_CORE -+ help -+ Say Y here if you use a keyboard, a touchpad, a touchscreen, or any -+ other HID based devices which are connected to your computer via SPI. -+ This driver supports Open Firmware (Device Tree)-based systems. -+ -+ If unsure, say N. -+ -+ This support is also available as a module. If so, the module -+ will be called spi-hid-of. It will also build/depend on the -+ module spi-hid. -+ - config SPI_HID_CORE - tristate - endif -diff --git a/drivers/hid/spi-hid/Makefile b/drivers/hid/spi-hid/Makefile -index 3ca326602643..31192e71edae 100644 ---- a/drivers/hid/spi-hid/Makefile -+++ b/drivers/hid/spi-hid/Makefile -@@ -9,3 +9,4 @@ obj-$(CONFIG_SPI_HID_CORE) += spi-hid.o - spi-hid-objs = spi-hid-core.o - CFLAGS_spi-hid-core.o := -I$(src) - obj-$(CONFIG_SPI_HID_ACPI) += spi-hid-acpi.o -+obj-$(CONFIG_SPI_HID_OF) += spi-hid-of.o -diff --git a/drivers/hid/spi-hid/spi-hid-of.c b/drivers/hid/spi-hid/spi-hid-of.c -new file mode 100644 -index 000000000000..ba7d5338f5d8 ---- /dev/null -+++ b/drivers/hid/spi-hid/spi-hid-of.c -@@ -0,0 +1,246 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * HID over SPI protocol, Open Firmware related code -+ * -+ * Copyright (c) 2021 Microsoft Corporation -+ * -+ * This code was forked out of the HID over SPI core code, which is partially -+ * based on "HID over I2C protocol implementation: -+ * -+ * Copyright (c) 2012 Benjamin Tissoires -+ * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France -+ * Copyright (c) 2012 Red Hat, Inc -+ * -+ * which in turn is partially based on "USB HID support for Linux": -+ * -+ * Copyright (c) 1999 Andreas Gal -+ * Copyright (c) 2000-2005 Vojtech Pavlik -+ * Copyright (c) 2005 Michael Haboustak for Concept2, Inc -+ * Copyright (c) 2007-2008 Oliver Neukum -+ * Copyright (c) 2006-2010 Jiri Kosina -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "spi-hid.h" -+ -+struct spi_hid_timing_data { -+ u32 post_power_on_delay_ms; -+ u32 minimal_reset_delay_ms; -+}; -+ -+/* Config structure is filled with data from Device Tree */ -+struct spi_hid_of_config { -+ struct spihid_ops ops; -+ -+ struct spi_hid_conf property_conf; -+ const struct spi_hid_timing_data *timing_data; -+ -+ struct gpio_desc *reset_gpio; -+ struct regulator *supply; -+ bool supply_enabled; -+ u16 hid_over_spi_flags; -+}; -+ -+static const struct spi_hid_timing_data timing_data = { -+ .post_power_on_delay_ms = 10, -+ .minimal_reset_delay_ms = 100, -+}; -+ -+static int spi_hid_of_populate_config(struct spi_hid_of_config *conf, -+ struct device *dev) -+{ -+ int error; -+ u32 val; -+ -+ error = device_property_read_u32(dev, "input-report-header-address", -+ &val); -+ if (error) { -+ dev_err(dev, "Input report header address not provided."); -+ return -ENODEV; -+ } -+ conf->property_conf.input_report_header_address = val; -+ -+ error = device_property_read_u32(dev, "input-report-body-address", &val); -+ if (error) { -+ dev_err(dev, "Input report body address not provided."); -+ return -ENODEV; -+ } -+ conf->property_conf.input_report_body_address = val; -+ -+ error = device_property_read_u32(dev, "output-report-address", &val); -+ if (error) { -+ dev_err(dev, "Output report address not provided."); -+ return -ENODEV; -+ } -+ conf->property_conf.output_report_address = val; -+ -+ error = device_property_read_u32(dev, "read-opcode", &val); -+ if (error) { -+ dev_err(dev, "Read opcode not provided."); -+ return -ENODEV; -+ } -+ conf->property_conf.read_opcode = val; -+ -+ error = device_property_read_u32(dev, "write-opcode", &val); -+ if (error) { -+ dev_err(dev, "Write opcode not provided."); -+ return -ENODEV; -+ } -+ conf->property_conf.write_opcode = val; -+ -+ conf->supply = devm_regulator_get(dev, "vdd"); -+ if (IS_ERR(conf->supply)) { -+ if (PTR_ERR(conf->supply) != -EPROBE_DEFER) -+ dev_err(dev, "Failed to get regulator: %ld.", -+ PTR_ERR(conf->supply)); -+ return PTR_ERR(conf->supply); -+ } -+ conf->supply_enabled = false; -+ -+ conf->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); -+ if (IS_ERR(conf->reset_gpio)) { -+ dev_err(dev, "%s: error getting reset GPIO.", __func__); -+ return PTR_ERR(conf->reset_gpio); -+ } -+ -+ return 0; -+} -+ -+static int spi_hid_of_power_down(struct spihid_ops *ops) -+{ -+ struct spi_hid_of_config *conf = container_of(ops, -+ struct spi_hid_of_config, -+ ops); -+ int error; -+ -+ if (!conf->supply_enabled) -+ return 0; -+ -+ error = regulator_disable(conf->supply); -+ if (error == 0) -+ conf->supply_enabled = false; -+ -+ return error; -+} -+ -+static int spi_hid_of_power_up(struct spihid_ops *ops) -+{ -+ struct spi_hid_of_config *conf = container_of(ops, -+ struct spi_hid_of_config, -+ ops); -+ int error; -+ -+ if (conf->supply_enabled) -+ return 0; -+ -+ error = regulator_enable(conf->supply); -+ -+ if (error == 0) { -+ conf->supply_enabled = true; -+ fsleep(1000 * conf->timing_data->post_power_on_delay_ms); -+ } -+ -+ return error; -+} -+ -+static int spi_hid_of_assert_reset(struct spihid_ops *ops) -+{ -+ struct spi_hid_of_config *conf = container_of(ops, -+ struct spi_hid_of_config, -+ ops); -+ -+ gpiod_set_value(conf->reset_gpio, 1); -+ return 0; -+} -+ -+static int spi_hid_of_deassert_reset(struct spihid_ops *ops) -+{ -+ struct spi_hid_of_config *conf = container_of(ops, -+ struct spi_hid_of_config, -+ ops); -+ -+ gpiod_set_value(conf->reset_gpio, 0); -+ return 0; -+} -+ -+static void spi_hid_of_sleep_minimal_reset_delay(struct spihid_ops *ops) -+{ -+ struct spi_hid_of_config *conf = container_of(ops, -+ struct spi_hid_of_config, -+ ops); -+ fsleep(1000 * conf->timing_data->minimal_reset_delay_ms); -+} -+ -+static int spi_hid_of_probe(struct spi_device *spi) -+{ -+ struct device *dev = &spi->dev; -+ struct spi_hid_of_config *config; -+ int error; -+ -+ config = devm_kzalloc(dev, sizeof(struct spi_hid_of_config), -+ GFP_KERNEL); -+ if (!config) -+ return -ENOMEM; -+ -+ config->ops.power_up = spi_hid_of_power_up; -+ config->ops.power_down = spi_hid_of_power_down; -+ config->ops.assert_reset = spi_hid_of_assert_reset; -+ config->ops.deassert_reset = spi_hid_of_deassert_reset; -+ config->ops.sleep_minimal_reset_delay = -+ spi_hid_of_sleep_minimal_reset_delay; -+ -+ config->timing_data = device_get_match_data(dev); -+ if (!config->timing_data) -+ config->timing_data = &timing_data; -+ -+ /* -+ * FIXME: hid_over_spi_flags could be retrieved from spi mode. -+ * It is always 0 because multi-SPI not supported. -+ */ -+ config->hid_over_spi_flags = 0; -+ -+ error = spi_hid_of_populate_config(config, dev); -+ if (error) { -+ dev_err(dev, "%s: unable to populate config data.", __func__); -+ return error; -+ } -+ -+ return spi_hid_core_probe(spi, &config->ops, &config->property_conf); -+} -+ -+static const struct of_device_id spi_hid_of_match[] = { -+ { .compatible = "hid-over-spi", .data = &timing_data }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, spi_hid_of_match); -+ -+static const struct spi_device_id spi_hid_of_id_table[] = { -+ { "hid", 0 }, -+ { "hid-over-spi", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(spi, spi_hid_of_id_table); -+ -+static struct spi_driver spi_hid_of_driver = { -+ .driver = { -+ .name = "spi_hid_of", -+ .owner = THIS_MODULE, -+ .of_match_table = spi_hid_of_match, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ .dev_groups = spi_hid_groups, -+ }, -+ .probe = spi_hid_of_probe, -+ .remove = spi_hid_core_remove, -+ .id_table = spi_hid_of_id_table, -+}; -+ -+module_spi_driver(spi_hid_of_driver); -+ -+MODULE_DESCRIPTION("HID over SPI OF transport driver"); -+MODULE_AUTHOR("Dmitry Antipov "); -+MODULE_LICENSE("GPL"); diff --git a/kernel/2118-dt-bindings-input-Document-hid-over-spi-DT-schema.patch b/kernel/2118-dt-bindings-input-Document-hid-over-spi-DT-schema.patch deleted file mode 100644 index f37ccdc..0000000 --- a/kernel/2118-dt-bindings-input-Document-hid-over-spi-DT-schema.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jingyuan Liang -Date: Tue, 9 Jun 2026 04:41:00 +0000 -Subject: [PATCH] dt-bindings: input: Document hid-over-spi DT schema - -Documentation describes the required and optional properties for -implementing Device Tree for a Microsoft G6 Touch Digitizer that -supports HID over SPI Protocol 1.0 specification. - -The properties are common to HID over SPI. - -Signed-off-by: Dmitry Antipov -Signed-off-by: Jarrett Schultz -Signed-off-by: Jingyuan Liang ---- - .../bindings/input/hid-over-spi.yaml | 128 ++++++++++++++++++ - 1 file changed, 128 insertions(+) - create mode 100644 Documentation/devicetree/bindings/input/hid-over-spi.yaml - -diff --git a/Documentation/devicetree/bindings/input/hid-over-spi.yaml b/Documentation/devicetree/bindings/input/hid-over-spi.yaml -new file mode 100644 -index 000000000000..27cf311e0aab ---- /dev/null -+++ b/Documentation/devicetree/bindings/input/hid-over-spi.yaml -@@ -0,0 +1,128 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/input/hid-over-spi.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: HID over SPI Devices -+ -+maintainers: -+ - Benjamin Tissoires -+ - Jiri Kosina -+ - Jingyuan Liang -+ -+description: |+ -+ HID over SPI provides support for various Human Interface Devices over the -+ SPI bus. These devices can be for example touchpads, keyboards, touch screens -+ or sensors. -+ -+ The specification has been written by Microsoft and is currently available -+ here: https://www.microsoft.com/en-us/download/details.aspx?id=103325 -+ -+ The Microsoft HID over SPI specification explicitly dictates that SPI -+ opcodes and register addresses (such as input/output report addresses) -+ are not standardized. Instead, the specification requires the system -+ firmware (e.g., ACPI or Device Tree) to provide these board-specific -+ parameters to the OS. Therefore, these varying parameters must be -+ defined as properties in the Device Tree. -+ -+allOf: -+ - $ref: /schemas/input/touchscreen/touchscreen.yaml# -+ - $ref: /schemas/spi/spi-peripheral-props.yaml# -+ -+properties: -+ compatible: -+ items: -+ - enum: -+ - microsoft,g6-touch-digitizer -+ - const: hid-over-spi -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts: -+ maxItems: 1 -+ -+ reset-gpios: -+ maxItems: 1 -+ description: -+ GPIO specifier for the digitizer's reset pin (active low). The line must -+ be flagged with GPIO_ACTIVE_LOW. -+ -+ vdd-supply: -+ description: -+ Regulator for the VDD supply voltage. -+ -+ input-report-header-address: -+ $ref: /schemas/types.yaml#/definitions/uint32 -+ minimum: 0 -+ maximum: 0xffffff -+ description: -+ A value to be included in the Read Approval packet, listing an address of -+ the input report header to be put on the SPI bus. This address has 24 -+ bits. -+ -+ input-report-body-address: -+ $ref: /schemas/types.yaml#/definitions/uint32 -+ minimum: 0 -+ maximum: 0xffffff -+ description: -+ A value to be included in the Read Approval packet, listing an address of -+ the input report body to be put on the SPI bus. This address has 24 bits. -+ -+ output-report-address: -+ $ref: /schemas/types.yaml#/definitions/uint32 -+ minimum: 0 -+ maximum: 0xffffff -+ description: -+ A value to be included in the Output Report sent by the host, listing an -+ address where the output report on the SPI bus is to be written to. This -+ address has 24 bits. -+ -+ read-opcode: -+ $ref: /schemas/types.yaml#/definitions/uint8 -+ description: -+ Value to be used in Read Approval packets. 1 byte. -+ -+ write-opcode: -+ $ref: /schemas/types.yaml#/definitions/uint8 -+ description: -+ Value to be used in Write Approval packets. 1 byte. -+ -+required: -+ - compatible -+ - interrupts -+ - reset-gpios -+ - vdd-supply -+ - input-report-header-address -+ - input-report-body-address -+ - output-report-address -+ - read-opcode -+ - write-opcode -+ -+unevaluatedProperties: false -+ -+examples: -+ - | -+ #include -+ #include -+ -+ spi { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ hid@0 { -+ compatible = "microsoft,g6-touch-digitizer", "hid-over-spi"; -+ reg = <0x0>; -+ interrupts-extended = <&gpio 42 IRQ_TYPE_EDGE_FALLING>; -+ reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>; -+ vdd-supply = <&pm8350c_l3>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&ts_d6_int_bias>; -+ input-report-header-address = <0x1000>; -+ input-report-body-address = <0x1004>; -+ output-report-address = <0x2000>; -+ read-opcode = /bits/ 8 <0x0b>; -+ write-opcode = /bits/ 8 <0x02>; -+ }; -+ }; diff --git a/kernel/2119-HID-spi-hid-add-power-management-implementation.patch b/kernel/2119-HID-spi-hid-add-power-management-implementation.patch deleted file mode 100644 index 2c760c8..0000000 --- a/kernel/2119-HID-spi-hid-add-power-management-implementation.patch +++ /dev/null @@ -1,236 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jingyuan Liang -Date: Tue, 9 Jun 2026 04:41:01 +0000 -Subject: [PATCH] HID: spi-hid: add power management implementation - -Implement HID over SPI driver power management callbacks. - -Signed-off-by: Jingyuan Liang ---- - drivers/hid/spi-hid/spi-hid-acpi.c | 1 + - drivers/hid/spi-hid/spi-hid-core.c | 133 +++++++++++++++++++++++++++-- - drivers/hid/spi-hid/spi-hid-of.c | 1 + - drivers/hid/spi-hid/spi-hid.h | 1 + - 4 files changed, 131 insertions(+), 5 deletions(-) - -diff --git a/drivers/hid/spi-hid/spi-hid-acpi.c b/drivers/hid/spi-hid/spi-hid-acpi.c -index 298e3ba44d8a..15cfc4e6cc2f 100644 ---- a/drivers/hid/spi-hid/spi-hid-acpi.c -+++ b/drivers/hid/spi-hid/spi-hid-acpi.c -@@ -238,6 +238,7 @@ static struct spi_driver spi_hid_acpi_driver = { - .driver = { - .name = "spi_hid_acpi", - .owner = THIS_MODULE, -+ .pm = &spi_hid_core_pm, - .acpi_match_table = spi_hid_acpi_match, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .dev_groups = spi_hid_groups, -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -index 698e72102c11..517f06913477 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.c -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -36,6 +36,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -245,6 +247,96 @@ static const char *spi_hid_power_mode_string(enum hidspi_power_state power_state - } - } - -+static int spi_hid_suspend(struct spi_hid *shid) -+{ -+ int error; -+ struct device *dev = &shid->spi->dev; -+ -+ guard(mutex)(&shid->power_lock); -+ if (shid->power_state == HIDSPI_OFF) -+ return 0; -+ -+ if (shid->hid) { -+ error = hid_driver_suspend(shid->hid, PMSG_SUSPEND); -+ if (error) { -+ dev_err(dev, "%s failed to suspend hid driver: %d\n", -+ __func__, error); -+ return error; -+ } -+ } -+ -+ disable_irq(shid->spi->irq); -+ -+ if (!device_may_wakeup(dev)) { -+ set_bit(SPI_HID_RESET_PENDING, &shid->flags); -+ -+ shid->ops->assert_reset(shid->ops); -+ -+ error = shid->ops->power_down(shid->ops); -+ if (error) { -+ dev_err(dev, "%s: could not power down\n", __func__); -+ shid->regulator_error_count++; -+ shid->regulator_last_error = error; -+ /* Undo partial suspend before returning error */ -+ shid->ops->deassert_reset(shid->ops); -+ clear_bit(SPI_HID_RESET_PENDING, &shid->flags); -+ enable_irq(shid->spi->irq); -+ if (shid->hid) -+ hid_driver_reset_resume(shid->hid); -+ return error; -+ } -+ -+ shid->power_state = HIDSPI_OFF; -+ } -+ return 0; -+} -+ -+static int spi_hid_resume(struct spi_hid *shid) -+{ -+ int error; -+ struct device *dev = &shid->spi->dev; -+ -+ guard(mutex)(&shid->power_lock); -+ -+ if (!device_may_wakeup(dev)) { -+ if (shid->power_state == HIDSPI_OFF) { -+ shid->ops->assert_reset(shid->ops); -+ -+ shid->ops->sleep_minimal_reset_delay(shid->ops); -+ -+ error = shid->ops->power_up(shid->ops); -+ if (error) { -+ dev_err(dev, "%s: could not power up\n", __func__); -+ shid->regulator_error_count++; -+ shid->regulator_last_error = error; -+ return error; -+ } -+ shid->power_state = HIDSPI_ON; -+ shid->ops->deassert_reset(shid->ops); -+ } -+ } -+ -+ enable_irq(shid->spi->irq); -+ -+ if (shid->hid) { -+ error = hid_driver_reset_resume(shid->hid); -+ if (error) { -+ dev_err(dev, "%s: failed to reset resume hid driver: %d\n", -+ __func__, error); -+ /* Undo partial resume before returning error */ -+ disable_irq(shid->spi->irq); -+ if (!device_may_wakeup(dev)) { -+ set_bit(SPI_HID_RESET_PENDING, &shid->flags); -+ shid->ops->assert_reset(shid->ops); -+ shid->ops->power_down(shid->ops); -+ shid->power_state = HIDSPI_OFF; -+ } -+ return error; -+ } -+ } -+ return 0; -+} -+ - static void spi_hid_stop_hid(struct spi_hid *shid) - { - struct hid_device *hid; -@@ -795,6 +887,11 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - trace_spi_hid_header_transfer(shid); - - scoped_guard(mutex, &shid->io_lock) { -+ if (shid->power_state == HIDSPI_OFF) { -+ dev_warn(dev, "Device is off, ignoring interrupt\n"); -+ goto out; -+ } -+ - error = spi_hid_input_sync(shid, shid->input->header, - sizeof(shid->input->header), true); - if (error) { -@@ -802,11 +899,6 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - goto err; - } - -- if (shid->power_state == HIDSPI_OFF) { -- dev_warn(dev, "Device is off after header was received\n"); -- goto out; -- } -- - trace_spi_hid_input_header_complete(shid, - shid->input_transfer[0].tx_buf, - shid->input_transfer[0].len, -@@ -1251,10 +1343,19 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - dev_err(dev, "%s: unable to request threaded IRQ\n", __func__); - return error; - } -+ if (device_may_wakeup(dev)) { -+ error = dev_pm_set_wake_irq(dev, spi->irq); -+ if (error) { -+ dev_err(dev, "%s: failed to set wake IRQ\n", __func__); -+ return error; -+ } -+ } - - error = shid->ops->power_up(shid->ops); - if (error) { - dev_err(dev, "%s: could not power up\n", __func__); -+ if (device_may_wakeup(dev)) -+ dev_pm_clear_wake_irq(dev); - return error; - } - -@@ -1284,9 +1385,31 @@ void spi_hid_core_remove(struct spi_device *spi) - error = shid->ops->power_down(shid->ops); - if (error) - dev_err(dev, "failed to disable regulator\n"); -+ -+ if (device_may_wakeup(dev)) -+ dev_pm_clear_wake_irq(dev); - } - EXPORT_SYMBOL_GPL(spi_hid_core_remove); - -+static int spi_hid_core_pm_suspend(struct device *dev) -+{ -+ struct spi_hid *shid = dev_get_drvdata(dev); -+ -+ return spi_hid_suspend(shid); -+} -+ -+static int spi_hid_core_pm_resume(struct device *dev) -+{ -+ struct spi_hid *shid = dev_get_drvdata(dev); -+ -+ return spi_hid_resume(shid); -+} -+ -+const struct dev_pm_ops spi_hid_core_pm = { -+ SYSTEM_SLEEP_PM_OPS(spi_hid_core_pm_suspend, spi_hid_core_pm_resume) -+}; -+EXPORT_SYMBOL_GPL(spi_hid_core_pm); -+ - MODULE_DESCRIPTION("HID over SPI transport driver"); - MODULE_AUTHOR("Dmitry Antipov "); - MODULE_LICENSE("GPL"); -diff --git a/drivers/hid/spi-hid/spi-hid-of.c b/drivers/hid/spi-hid/spi-hid-of.c -index ba7d5338f5d8..561cf453e44a 100644 ---- a/drivers/hid/spi-hid/spi-hid-of.c -+++ b/drivers/hid/spi-hid/spi-hid-of.c -@@ -230,6 +230,7 @@ static struct spi_driver spi_hid_of_driver = { - .driver = { - .name = "spi_hid_of", - .owner = THIS_MODULE, -+ .pm = &spi_hid_core_pm, - .of_match_table = spi_hid_of_match, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .dev_groups = spi_hid_groups, -diff --git a/drivers/hid/spi-hid/spi-hid.h b/drivers/hid/spi-hid/spi-hid.h -index f5a5f4d54beb..17b2fdf192ed 100644 ---- a/drivers/hid/spi-hid/spi-hid.h -+++ b/drivers/hid/spi-hid/spi-hid.h -@@ -41,5 +41,6 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - void spi_hid_core_remove(struct spi_device *spi); - - extern const struct attribute_group *spi_hid_groups[]; -+extern const struct dev_pm_ops spi_hid_core_pm; - - #endif /* SPI_HID_H */ diff --git a/kernel/2120-HID-spi-hid-add-panel-follower-support.patch b/kernel/2120-HID-spi-hid-add-panel-follower-support.patch deleted file mode 100644 index f863b14..0000000 --- a/kernel/2120-HID-spi-hid-add-panel-follower-support.patch +++ /dev/null @@ -1,279 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jingyuan Liang -Date: Tue, 9 Jun 2026 04:41:02 +0000 -Subject: [PATCH] HID: spi-hid: add panel follower support - -Add support to spi-hid to be a panel follower. - -Signed-off-by: Jingyuan Liang ---- - drivers/hid/spi-hid/spi-hid-core.c | 164 ++++++++++++++++++++++++----- - drivers/hid/spi-hid/spi-hid-core.h | 7 ++ - 2 files changed, 142 insertions(+), 29 deletions(-) - -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -index 517f06913477..27f25d95ed28 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.c -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -1281,6 +1281,106 @@ const struct attribute_group *spi_hid_groups[] = { - }; - EXPORT_SYMBOL_GPL(spi_hid_groups); - -+/* -+ * At the end of probe we initialize the device: -+ * 0) assert reset, bias the interrupt line -+ * 1) sleep minimal reset delay -+ * 2) power up the device -+ * 3) deassert reset (high) -+ * After this we expect an IRQ with a reset response. -+ */ -+static int spi_hid_dev_init(struct spi_hid *shid) -+{ -+ struct spi_device *spi = shid->spi; -+ struct device *dev = &spi->dev; -+ int error; -+ -+ shid->ops->assert_reset(shid->ops); -+ -+ shid->ops->sleep_minimal_reset_delay(shid->ops); -+ -+ error = shid->ops->power_up(shid->ops); -+ if (error) { -+ dev_err(dev, "%s: could not power up\n", __func__); -+ shid->regulator_error_count++; -+ shid->regulator_last_error = error; -+ return error; -+ } -+ -+ shid->ops->deassert_reset(shid->ops); -+ -+ enable_irq(spi->irq); -+ -+ return 0; -+} -+ -+static void spi_hid_panel_follower_work(struct work_struct *work) -+{ -+ struct spi_hid *shid = container_of(work, struct spi_hid, -+ panel_follower_work); -+ int error; -+ -+ if (!shid->desc.hid_version) -+ error = spi_hid_dev_init(shid); -+ else -+ error = spi_hid_resume(shid); -+ if (error) -+ dev_warn(&shid->spi->dev, "Power on failed: %d\n", error); -+ else -+ WRITE_ONCE(shid->panel_follower_work_finished, true); -+} -+ -+static int spi_hid_panel_follower_resume(struct drm_panel_follower *follower) -+{ -+ struct spi_hid *shid = container_of(follower, struct spi_hid, panel_follower); -+ -+ /* -+ * Powering on a touchscreen can be a slow process. Queue the work to -+ * the system workqueue so we don't block the panel's power up. -+ */ -+ WRITE_ONCE(shid->panel_follower_work_finished, false); -+ schedule_work(&shid->panel_follower_work); -+ -+ return 0; -+} -+ -+static int spi_hid_panel_follower_suspend(struct drm_panel_follower *follower) -+{ -+ struct spi_hid *shid = container_of(follower, struct spi_hid, panel_follower); -+ -+ cancel_work_sync(&shid->panel_follower_work); -+ -+ if (!READ_ONCE(shid->panel_follower_work_finished)) -+ return 0; -+ -+ return spi_hid_suspend(shid); -+} -+ -+static const struct drm_panel_follower_funcs -+ spi_hid_panel_follower_prepare_funcs = { -+ .panel_prepared = spi_hid_panel_follower_resume, -+ .panel_unpreparing = spi_hid_panel_follower_suspend, -+}; -+ -+static int spi_hid_register_panel_follower(struct spi_hid *shid) -+{ -+ struct device *dev = &shid->spi->dev; -+ -+ shid->panel_follower.funcs = &spi_hid_panel_follower_prepare_funcs; -+ -+ /* -+ * If we're not in control of our own power up/power down then we can't -+ * do the logic to manage wakeups. Give a warning if a user thought -+ * that was possible then force the capability off. -+ */ -+ if (device_can_wakeup(dev)) { -+ dev_warn(dev, "Can't wakeup if following panel\n"); -+ device_set_wakeup_capable(dev, false); -+ } -+ -+ return drm_panel_add_follower(dev, &shid->panel_follower); -+} -+ - int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - struct spi_hid_conf *conf) - { -@@ -1300,6 +1400,7 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - shid->ops = ops; - shid->conf = conf; - set_bit(SPI_HID_RESET_PENDING, &shid->flags); -+ shid->is_panel_follower = drm_is_panel_follower(&spi->dev); - - spi_set_drvdata(spi, shid); - -@@ -1313,6 +1414,7 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - init_completion(&shid->output_done); - - INIT_WORK(&shid->reset_work, spi_hid_reset_work); -+ INIT_WORK(&shid->panel_follower_work, spi_hid_panel_follower_work); - - /* - * We need to allocate the buffer without knowing the maximum -@@ -1323,20 +1425,6 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - if (error) - return error; - -- /* -- * At the end of probe we initialize the device: -- * 0) assert reset, bias the interrupt line -- * 1) sleep minimal reset delay -- * 2) request IRQ -- * 3) power up the device -- * 4) deassert reset (high) -- * After this we expect an IRQ with a reset response. -- */ -- -- shid->ops->assert_reset(shid->ops); -- -- shid->ops->sleep_minimal_reset_delay(shid->ops); -- - error = devm_request_threaded_irq(dev, spi->irq, NULL, spi_hid_dev_irq, - IRQF_ONESHOT | IRQF_NO_AUTOEN, dev_name(&spi->dev), shid); - if (error) { -@@ -1351,22 +1439,28 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - } - } - -- error = shid->ops->power_up(shid->ops); -- if (error) { -- dev_err(dev, "%s: could not power up\n", __func__); -- if (device_may_wakeup(dev)) -- dev_pm_clear_wake_irq(dev); -- return error; -+ if (shid->is_panel_follower) { -+ error = spi_hid_register_panel_follower(shid); -+ if (error) { -+ dev_err_probe(dev, error, -+ "Failed to register panel follower"); -+ goto err_wake_irq; -+ } -+ } else { -+ error = spi_hid_dev_init(shid); -+ if (error) -+ goto err_wake_irq; - } - -- shid->ops->deassert_reset(shid->ops); -- -- enable_irq(spi->irq); -- - dev_dbg(dev, "%s: d3 -> %s\n", __func__, - spi_hid_power_mode_string(shid->power_state)); - - return 0; -+ -+err_wake_irq: -+ if (device_may_wakeup(dev)) -+ dev_pm_clear_wake_irq(dev); -+ return error; - } - EXPORT_SYMBOL_GPL(spi_hid_core_probe); - -@@ -1376,15 +1470,21 @@ void spi_hid_core_remove(struct spi_device *spi) - struct device *dev = &spi->dev; - int error; - -- disable_irq(spi->irq); -+ if (shid->is_panel_follower) -+ drm_panel_remove_follower(&shid->panel_follower); -+ else -+ disable_irq(spi->irq); -+ - cancel_work_sync(&shid->reset_work); - - spi_hid_stop_hid(shid); - -- shid->ops->assert_reset(shid->ops); -- error = shid->ops->power_down(shid->ops); -- if (error) -- dev_err(dev, "failed to disable regulator\n"); -+ if (shid->power_state != HIDSPI_OFF) { -+ shid->ops->assert_reset(shid->ops); -+ error = shid->ops->power_down(shid->ops); -+ if (error) -+ dev_err(dev, "failed to disable regulator\n"); -+ } - - if (device_may_wakeup(dev)) - dev_pm_clear_wake_irq(dev); -@@ -1395,6 +1495,9 @@ static int spi_hid_core_pm_suspend(struct device *dev) - { - struct spi_hid *shid = dev_get_drvdata(dev); - -+ if (shid->is_panel_follower) -+ return 0; -+ - return spi_hid_suspend(shid); - } - -@@ -1402,6 +1505,9 @@ static int spi_hid_core_pm_resume(struct device *dev) - { - struct spi_hid *shid = dev_get_drvdata(dev); - -+ if (shid->is_panel_follower) -+ return 0; -+ - return spi_hid_resume(shid); - } - -diff --git a/drivers/hid/spi-hid/spi-hid-core.h b/drivers/hid/spi-hid/spi-hid-core.h -index 293e2cfcfbf7..261b2fd7f332 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.h -+++ b/drivers/hid/spi-hid/spi-hid-core.h -@@ -10,6 +10,8 @@ - #include - #include - -+#include -+ - /* Protocol message size constants */ - #define SPI_HID_READ_APPROVAL_LEN 5 - #define SPI_HID_OUTPUT_HEADER_LEN 8 -@@ -56,6 +58,10 @@ struct spi_hid { - struct spi_hid_input_buf *input; /* Input buffer. */ - struct spi_hid_input_buf *response; /* Response buffer. */ - -+ struct drm_panel_follower panel_follower; -+ bool is_panel_follower; -+ bool panel_follower_work_finished; -+ - u16 response_length; - u16 bufsize; - -@@ -66,6 +72,7 @@ struct spi_hid { - unsigned long flags; /* device flags. */ - - struct work_struct reset_work; -+ struct work_struct panel_follower_work; - - /* Control lock to ensure complete output transaction. */ - struct mutex output_lock; diff --git a/kernel/2121-dt-bindings-media-qcom-x1e80100-camss-correct-resour.patch b/kernel/2121-dt-bindings-media-qcom-x1e80100-camss-correct-resour.patch deleted file mode 100644 index 0a082c1..0000000 --- a/kernel/2121-dt-bindings-media-qcom-x1e80100-camss-correct-resour.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] dt-bindings: media: qcom,x1e80100-camss: correct resources - -Describe the five current HLOS CAMSS IOMMU stream IDs while retaining -the legacy eight-entry form. Correct the CSIPHY0-2 register sizes in the -example. - -The IOMMU description is adapted from Bryan O'Donoghue's X1E80100 CAMSS -binding work. - -Signed-off-by: Brandon Williams ---- - .../bindings/media/qcom,x1e80100-camss.yaml | 32 +++++++++++++------ - 1 file changed, 22 insertions(+), 10 deletions(-) - -diff --git a/Documentation/devicetree/bindings/media/qcom,x1e80100-camss.yaml b/Documentation/devicetree/bindings/media/qcom,x1e80100-camss.yaml -index 2d1662ef522b..534b3c810fa8 100644 ---- a/Documentation/devicetree/bindings/media/qcom,x1e80100-camss.yaml -+++ b/Documentation/devicetree/bindings/media/qcom,x1e80100-camss.yaml -@@ -104,7 +104,22 @@ properties: - - const: sf_icp_mnoc - - iommus: -- maxItems: 8 -+ oneOf: -+ - items: -+ - description: S1 HLOS IFE and IFE_LITE non-protected read -+ - description: S1 HLOS IFE and IFE_LITE non-protected write -+ - description: S1 HLOS SFE non-protected read -+ - description: S1 HLOS SFE non-protected write -+ - description: S1 HLOS CDM IFE non-protected -+ - description: Legacy slot 0 - do not use -+ - description: Legacy slot 1 - do not use -+ - description: Legacy slot 2 - do not use -+ - items: -+ - description: S1 HLOS IFE and IFE_LITE non-protected read -+ - description: S1 HLOS IFE and IFE_LITE non-protected write -+ - description: S1 HLOS SFE non-protected read -+ - description: S1 HLOS SFE non-protected write -+ - description: S1 HLOS CDM IFE non-protected - - power-domains: - items: -@@ -199,9 +214,9 @@ examples: - <0 0x0acc6000 0 0x1000>, - <0 0x0acca000 0 0x1000>, - <0 0x0acb6000 0 0x1000>, -- <0 0x0ace4000 0 0x1000>, -- <0 0x0ace6000 0 0x1000>, -- <0 0x0ace8000 0 0x1000>, -+ <0 0x0ace4000 0 0x2000>, -+ <0 0x0ace6000 0 0x2000>, -+ <0 0x0ace8000 0 0x2000>, - <0 0x0acec000 0 0x4000>, - <0 0x0acf6000 0 0x1000>, - <0 0x0acf7000 0 0x1000>, -@@ -332,13 +347,10 @@ examples: - "sf_icp_mnoc"; - - iommus = <&apps_smmu 0x800 0x60>, -+ <&apps_smmu 0x820 0x60>, -+ <&apps_smmu 0x840 0x60>, - <&apps_smmu 0x860 0x60>, -- <&apps_smmu 0x1800 0x60>, -- <&apps_smmu 0x1860 0x60>, -- <&apps_smmu 0x18e0 0x00>, -- <&apps_smmu 0x1980 0x20>, -- <&apps_smmu 0x1900 0x00>, -- <&apps_smmu 0x19a0 0x20>; -+ <&apps_smmu 0x18a0 0x0>; - - power-domains = <&camcc CAM_CC_IFE_0_GDSC>, - <&camcc CAM_CC_IFE_1_GDSC>, diff --git a/kernel/2122-dt-bindings-media-add-OV13858-and-VD55G0-sensors.patch b/kernel/2122-dt-bindings-media-add-OV13858-and-VD55G0-sensors.patch deleted file mode 100644 index 2615c41..0000000 --- a/kernel/2122-dt-bindings-media-add-OV13858-and-VD55G0-sensors.patch +++ /dev/null @@ -1,282 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] dt-bindings: media: add OV13858 and VD55G0 sensors - -Document the power, clock, and CSI-2 connections used by the -OmniVision OV13858 and STMicroelectronics VD55G0 sensors. - -The VD55G0 binding is adapted from STMicroelectronics -vd55g0-linux-driver revision: - - 9134fe572b77f906344f37ba227f375db73dc026 - -Signed-off-by: Brandon Williams ---- - .../bindings/media/i2c/ovti,ov13858.yaml | 114 +++++++++++++++ - .../bindings/media/i2c/st,vd55g0.yaml | 135 ++++++++++++++++++ - 2 files changed, 249 insertions(+) - create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov13858.yaml - create mode 100644 Documentation/devicetree/bindings/media/i2c/st,vd55g0.yaml - -diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov13858.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov13858.yaml -new file mode 100644 -index 000000000000..7f146a016638 ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov13858.yaml -@@ -0,0 +1,114 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/media/i2c/ovti,ov13858.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Omnivision OV13858 CMOS Sensor -+ -+maintainers: -+ - Sakari Ailus -+ -+description: | -+ The Omnivision OV13858 is a 13.2 megapixel, CMOS image sensor with an -+ active array size of 4224H x 3136V. It supports: -+ - Automatic black level calibration (BLC) -+ - Programmable controls for frame rate, mirror and flip, binning, -+ cropping and windowing -+ - Output format 10-bit Bayer RAW -+ - 4-lane MIPI D-PHY TX @ 1.08 Gbps per lane -+ - Standard SCCB command interface -+ -+allOf: -+ - $ref: /schemas/media/video-interface-devices.yaml# -+ -+properties: -+ compatible: -+ const: ovti,ov13858 -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ description: XVCLK external clock, 19.2 MHz. -+ maxItems: 1 -+ -+ avdd-supply: -+ description: Analogue circuit voltage supply. -+ -+ dovdd-supply: -+ description: I/O circuit voltage supply. -+ -+ dvdd-supply: -+ description: Digital circuit voltage supply. -+ -+ reset-gpios: -+ description: Active low GPIO connected to XSHUTDOWN pad of the sensor. -+ -+ port: -+ $ref: /schemas/graph.yaml#/$defs/port-base -+ additionalProperties: false -+ -+ properties: -+ endpoint: -+ $ref: /schemas/media/video-interfaces.yaml# -+ additionalProperties: false -+ -+ properties: -+ data-lanes: -+ items: -+ - const: 1 -+ - const: 2 -+ - const: 3 -+ - const: 4 -+ link-frequencies: true -+ remote-endpoint: true -+ -+ required: -+ - data-lanes -+ - link-frequencies -+ - remote-endpoint -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - port -+ -+unevaluatedProperties: false -+ -+examples: -+ - | -+ #include -+ -+ i2c { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ov13858: camera@10 { -+ compatible = "ovti,ov13858"; -+ reg = <0x10>; -+ -+ reset-gpios = <&tlmm 110 GPIO_ACTIVE_LOW>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&cam_rear_default>; -+ -+ clocks = <&camcc_mclk1>; -+ -+ assigned-clocks = <&camcc_mclk1>; -+ assigned-clock-rates = <19200000>; -+ -+ avdd-supply = <&vreg_l5m_2p8>; -+ dvdd-supply = <&vreg_l1m_1p2>; -+ dovdd-supply = <&vreg_l6m_1p8>; -+ -+ port { -+ ov13858_ep: endpoint { -+ remote-endpoint = <&csiphy0_ep>; -+ data-lanes = <1 2 3 4>; -+ link-frequencies = /bits/ 64 <540000000 270000000>; -+ }; -+ }; -+ }; -+ }; -+... -diff --git a/Documentation/devicetree/bindings/media/i2c/st,vd55g0.yaml b/Documentation/devicetree/bindings/media/i2c/st,vd55g0.yaml -new file mode 100644 -index 000000000000..221c024ea3ea ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/i2c/st,vd55g0.yaml -@@ -0,0 +1,135 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+# Copyright (c) 2022 STMicroelectronics SA. -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/media/i2c/st,vd55g0.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: STMicroelectronics VD55G0 HDR global-shutter image sensor -+ -+maintainers: -+ - Benjamin Mugnier -+ - Sylvain Petinot -+ -+description: | -+ VD55G0 is a 644x604 global-shutter image sensor with a one- or two-lane -+ CSI-2 output. Supported formats are RAW8, RAW10, RAW12, RAW14 and RAW16. -+ -+allOf: -+ - $ref: /schemas/media/video-interface-devices.yaml# -+ -+properties: -+ compatible: -+ const: st,vd55g0 -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ maxItems: 1 -+ -+ VCORE-supply: -+ description: -+ Sensor digital core supply. Must be 1.2 volts. -+ -+ VDDIO-supply: -+ description: -+ Sensor digital IO supply. Must be 1.8 volts. -+ -+ VANA-supply: -+ description: -+ Sensor analog supply. Must be 2.8 volts. -+ -+ reset-gpios: -+ description: -+ Reference to the GPIO connected to the reset pin, if any. -+ This is an active low signal to the vd55g0. -+ maxItems: 1 -+ -+ st,leds: -+ description: -+ Sensor LEDs GPIOs numbers to be used for illumination. -+ $ref: /schemas/types.yaml#/definitions/uint32-array -+ minItems: 1 -+ maxItems: 4 -+ items: -+ minimum: 0 -+ maximum: 3 -+ -+ st,out-sync: -+ description: -+ Sensor GPIOs numbers to output a synchronisation signal, used in -+ conjonction with st,in-sync-gpios. -+ $ref: /schemas/types.yaml#/definitions/uint32-array -+ minItems: 1 -+ maxItems: 4 -+ items: -+ minimum: 0 -+ maximum: 3 -+ -+ st,in-sync: -+ description: -+ Sensor GPIO number to trigger Slave mode. If present the sensor will -+ aquire frames only when a raising edge is received on this GPIO. -+ $ref: /schemas/types.yaml#/definitions/uint32 -+ const: 0 -+ -+ port: -+ $ref: /schemas/graph.yaml#/$defs/port-base -+ additionalProperties: false -+ -+ properties: -+ endpoint: -+ $ref: /schemas/media/video-interfaces.yaml# -+ unevaluatedProperties: false -+ -+ properties: -+ data-lanes: -+ description: -+ CSI lanes to use -+ minItems: 1 -+ maxItems: 2 -+ items: -+ enum: [1, 2] -+ -+ remote-endpoint: true -+ -+ required: -+ - data-lanes -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - VCORE-supply -+ - VDDIO-supply -+ - VANA-supply -+ - port -+ -+unevaluatedProperties: false -+ -+examples: -+ - | -+ #include -+ i2c { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ vd55g0: csi2tx@10 { -+ compatible = "st,vd55g0"; -+ reg = <0x10>; -+ clocks = <&clk_ext_camera>; -+ VCORE-supply = <&v1v2>; -+ VDDIO-supply = <&v1v8>; -+ VANA-supply = <&v2v8>; -+ reset-gpios = <&mfxgpio 18 GPIO_ACTIVE_LOW>; -+ st,leds = <0 1>; -+ st,out-sync = <2 3>; -+ port { -+ ep0: endpoint { -+ data-lanes = <1 2>; -+ remote-endpoint = <&mipi_csi2_out>; -+ }; -+ }; -+ }; -+ }; -+... diff --git a/kernel/2123-media-qcom-camss-unwind-failed-stream-starts.patch b/kernel/2123-media-qcom-camss-unwind-failed-stream-starts.patch deleted file mode 100644 index 2089473..0000000 --- a/kernel/2123-media-qcom-camss-unwind-failed-stream-starts.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] media: qcom: camss: unwind failed stream starts - -Stop each subdevice that started successfully when a later pipeline -entity fails. Continue stopping the remaining subdevices after an -individual stop error. - -Signed-off-by: Brandon Williams ---- - .../media/platform/qcom/camss/camss-video.c | 58 +++++++++++-------- - 1 file changed, 33 insertions(+), 25 deletions(-) - -diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c -index 0852eb6f1315..a2fa11005d18 100644 ---- a/drivers/media/platform/qcom/camss/camss-video.c -+++ b/drivers/media/platform/qcom/camss/camss-video.c -@@ -249,6 +249,35 @@ static int video_prepare_streaming(struct vb2_queue *q) - return ret; - } - -+static void video_stop_subdevices(struct camss_video *video, -+ const struct media_entity *stop_entity) -+{ -+ struct media_entity *entity = &video->vdev.entity; -+ struct media_pad *pad; -+ struct v4l2_subdev *subdev; -+ int ret; -+ -+ while (1) { -+ pad = &entity->pads[0]; -+ if (!(pad->flags & MEDIA_PAD_FL_SINK)) -+ break; -+ -+ pad = media_pad_remote_pad_first(pad); -+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) -+ break; -+ -+ entity = pad->entity; -+ if (entity == stop_entity) -+ break; -+ -+ subdev = media_entity_to_v4l2_subdev(entity); -+ ret = v4l2_subdev_call(subdev, video, s_stream, 0); -+ if (ret < 0 && ret != -ENOIOCTLCMD) -+ dev_err(video->camss->dev, -+ "Video pipeline stop failed: %d\n", ret); -+ } -+} -+ - static int video_start_streaming(struct vb2_queue *q, unsigned int count) - { - struct camss_video *video = vb2_get_drv_priv(q); -@@ -283,11 +312,13 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count) - - ret = v4l2_subdev_call(subdev, video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) -- goto error; -+ goto error_stop_subdevices; - } - - return 0; - -+error_stop_subdevices: -+ video_stop_subdevices(video, entity); - error: - video_device_pipeline_stop(vdev); - -@@ -301,31 +332,8 @@ static void video_stop_streaming(struct vb2_queue *q) - { - struct camss_video *video = vb2_get_drv_priv(q); - struct video_device *vdev = &video->vdev; -- struct media_entity *entity; -- struct media_pad *pad; -- struct v4l2_subdev *subdev; -- int ret; - -- entity = &vdev->entity; -- while (1) { -- pad = &entity->pads[0]; -- if (!(pad->flags & MEDIA_PAD_FL_SINK)) -- break; -- -- pad = media_pad_remote_pad_first(pad); -- if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) -- break; -- -- entity = pad->entity; -- subdev = media_entity_to_v4l2_subdev(entity); -- -- ret = v4l2_subdev_call(subdev, video, s_stream, 0); -- -- if (ret) { -- dev_err(video->camss->dev, "Video pipeline stop failed: %d\n", ret); -- return; -- } -- } -+ video_stop_subdevices(video, NULL); - - video_device_pipeline_stop(vdev); - diff --git a/kernel/2124-media-qcom-camss-support-X1E80100-C-PHY-links.patch b/kernel/2124-media-qcom-camss-support-X1E80100-C-PHY-links.patch deleted file mode 100644 index 662b46d..0000000 --- a/kernel/2124-media-qcom-camss-support-X1E80100-C-PHY-links.patch +++ /dev/null @@ -1,376 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] media: qcom: camss: support X1E80100 C-PHY links - -Accept C-PHY endpoints, propagate the PHY mode into CSID, select the -X1E80100 receive clocks, and configure the 4 nm 3PH v2.1.2 PHY for the -IMX681 link. - -The common, lane, interrupt, and 2.5-Gsym/s data-rate tables are adapted -under GPL-2.0-only from Qualcomm cam_csiphy_2_1_2_hwreg.h blob: - - 347fb4944ccedfead1aa0c5260e6b41a5a038017 - -The Surface-specific lane-enable value is an independent runtime -observation. - -Signed-off-by: Brandon Williams ---- - .../platform/qcom/camss/camss-csid-680.c | 3 + - .../platform/qcom/camss/camss-csid-gen3.c | 3 + - .../media/platform/qcom/camss/camss-csid.c | 8 +- - .../media/platform/qcom/camss/camss-csid.h | 1 + - .../qcom/camss/camss-csiphy-3ph-1-0.c | 188 ++++++++++++++++++ - .../media/platform/qcom/camss/camss-csiphy.h | 1 + - drivers/media/platform/qcom/camss/camss.c | 8 +- - 7 files changed, 205 insertions(+), 7 deletions(-) - -diff --git a/drivers/media/platform/qcom/camss/camss-csid-680.c b/drivers/media/platform/qcom/camss/camss-csid-680.c -index 345a67c8fb94..d0741777c65c 100644 ---- a/drivers/media/platform/qcom/camss/camss-csid-680.c -+++ b/drivers/media/platform/qcom/camss/camss-csid-680.c -@@ -101,6 +101,7 @@ - #define CSI2_RX_CFG0_DL2_INPUT_SEL 12 - #define CSI2_RX_CFG0_DL3_INPUT_SEL 16 - #define CSI2_RX_CFG0_PHY_NUM_SEL 20 -+#define CSI2_RX_CFG0_PHY_TYPE_SEL_CPHY BIT(24) - #define CSI2_RX_CFG0_PHY_SEL_BASE_IDX 1 - #define CSI2_RX_CFG0_PHY_TYPE_SEL 24 - #define CSI2_RX_CFG0_TPG_MUX_EN BIT(27) -@@ -200,6 +201,8 @@ static void __csid_configure_rx(struct csid_device *csid, - } else { - val |= (phy->csiphy_id + CSI2_RX_CFG0_PHY_SEL_BASE_IDX) - << CSI2_RX_CFG0_PHY_NUM_SEL; -+ if (phy->is_cphy) -+ val |= CSI2_RX_CFG0_PHY_TYPE_SEL_CPHY; - } - - writel(val, csid->base + CSID_CSI2_RX_CFG0); -diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c -index 0fdbf75fb27d..b52b54b54295 100644 ---- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c -+++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c -@@ -66,6 +66,7 @@ - #define CSI2_RX_CFG0_VC_MODE 3 - #define CSI2_RX_CFG0_DL0_INPUT_SEL 4 - #define CSI2_RX_CFG0_PHY_NUM_SEL 20 -+#define CSI2_RX_CFG0_PHY_TYPE_SEL_CPHY BIT(24) - #define CSI2_RX_CFG0_TPG_MUX_EN BIT(27) - #define CSI2_RX_CFG0_TPG_MUX_SEL GENMASK(29, 28) - -@@ -124,6 +125,8 @@ static void __csid_configure_rx(struct csid_device *csid, - } else { - val |= (phy->csiphy_id + CSI2_RX_CFG0_PHY_SEL_BASE_IDX) - << CSI2_RX_CFG0_PHY_NUM_SEL; -+ if (phy->is_cphy) -+ val |= CSI2_RX_CFG0_PHY_TYPE_SEL_CPHY; - } - - writel(val, csid->base + CSID_CSI2_RX_CFG0); -diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c -index 48459b46a981..f3bba6feaf39 100644 ---- a/drivers/media/platform/qcom/camss/camss-csid.c -+++ b/drivers/media/platform/qcom/camss/camss-csid.c -@@ -534,7 +534,7 @@ const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info - - /* - * csid_set_clock_rates - Calculate and set clock rates on CSID module -- * @csiphy: CSID device -+ * @csid: CSID device - */ - static int csid_set_clock_rates(struct csid_device *csid) - { -@@ -557,7 +557,10 @@ static int csid_set_clock_rates(struct csid_device *csid) - if (!strcmp(clock->name, "csi0") || - !strcmp(clock->name, "csi1") || - !strcmp(clock->name, "csi2") || -- !strcmp(clock->name, "csi3")) { -+ !strcmp(clock->name, "csi3") || -+ (csid->camss->res->version == CAMSS_X1E80100 && -+ (!strcmp(clock->name, "csid") || -+ !strcmp(clock->name, "csid_csiphy_rx")))) { - u64 min_rate = link_freq / 4; - long rate; - -@@ -1292,6 +1295,7 @@ static int csid_link_setup(struct media_entity *entity, - lane_cfg = &csiphy->cfg.csi2->lane_cfg; - csid->phy.lane_cnt = lane_cfg->num_data; - csid->phy.lane_assign = csid_get_lane_assign(lane_cfg, lane_cfg->num_data); -+ csid->phy.is_cphy = csiphy->cfg.csi2->is_cphy; - csid->tpg_linked = false; - } - } -diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h -index 5296b10f6bac..827c9b2f032e 100644 ---- a/drivers/media/platform/qcom/camss/camss-csid.h -+++ b/drivers/media/platform/qcom/camss/camss-csid.h -@@ -70,6 +70,7 @@ struct csid_phy_config { - u32 lane_assign; - u32 en_vc; - u8 need_vc_update; -+ bool is_cphy; - }; - - struct csid_device; -diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c -index dac8d2ecf799..3972b7ebe5cd 100644 ---- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c -+++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c -@@ -6,6 +6,7 @@ - * - * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2016-2018 Linaro Ltd. -+ * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. - */ - - #include "camss.h" -@@ -921,6 +922,185 @@ csiphy_lane_regs lane_regs_x1e80100[] = { - {0x0C64, 0x7F, 0x00, CSIPHY_SKEW_CAL}, - }; - -+/* -+ * C-PHY mode tables for Qualcomm's 4 nm 3PH v2.1.2 PHY. Adapted from -+ * cam_csiphy_2_1_2_hwreg.h (GPL-2.0-only); the exact source revision is -+ * recorded in Documentation/driver-api/media/sp11-camera-provenance.rst. -+ */ -+/* 4nm 3PH v 2.1.2 C-PHY mode: common block init */ -+static const struct -+csiphy_lane_regs cphy_common_regs_x1e80100[] = { -+ {0x1084, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x108C, 0x00, 0x01, CSIPHY_DEFAULT_PARAMS}, -+ {0x101C, 0x7A, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x1018, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, -+}; -+ -+/* 4 nm 3PH v2.1.2 C-PHY data-rate delta for the observed 2.406 Gsps link. */ -+static const struct csiphy_lane_regs cphy_datarate_2p5g_x1e80100[] = { -+ {0x0268, 0xF1, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0294, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0288, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0278, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x026C, 0x3D, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x028C, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0270, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0274, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0668, 0xF1, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0694, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0688, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0678, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x066C, 0x3D, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x068C, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0670, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0674, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A68, 0xF1, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A94, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A88, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A78, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A6C, 0x3D, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A8C, 0x30, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A70, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A74, 0x03, 0x0A, CSIPHY_DEFAULT_PARAMS}, -+ {0x020C, 0x22, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, -+ {0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, -+ {0x0210, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0214, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x060C, 0x22, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, -+ {0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, -+ {0x0610, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0614, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A0C, 0x22, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, -+ {0x0A08, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, -+ {0x0A10, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A14, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+}; -+ -+/* 4nm 3PH v 2.1.2 C-PHY mode: three-phase lane init */ -+static const struct -+csiphy_lane_regs cphy_lane_regs_x1e80100[] = { -+ {0x02F4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x02F8, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x02FC, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x02F0, 0xEF, 0x03, CSIPHY_DEFAULT_PARAMS}, -+ {0x06F4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x06F8, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x06FC, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x06F0, 0xEF, 0x03, CSIPHY_DEFAULT_PARAMS}, -+ {0x0AF4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0AF8, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0AFC, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0AF0, 0xEF, 0x03, CSIPHY_DEFAULT_PARAMS}, -+ {0x0204, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x02E4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x02E8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x02EC, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0218, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x021C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0220, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0224, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0228, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x022C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0264, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0244, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0310, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x02BC, 0xD0, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0254, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0240, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0260, 0xA8, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0284, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0290, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0604, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x06E4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x06E8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x06EC, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0618, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x061C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0620, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0624, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0628, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x062C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0664, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0644, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0710, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x06BC, 0xD0, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0654, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0640, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0660, 0xA8, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0684, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0690, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0AE4, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0AE8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0AEC, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A18, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A1C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A20, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A24, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A28, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A2C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A64, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A44, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0B10, 0x35, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0ABC, 0xD0, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A54, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A40, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A60, 0xA8, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, -+ {0x0A90, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, -+}; -+ -+static void csiphy_gen2_config_cphy(struct csiphy_device *csiphy) -+{ -+ const struct csiphy_lane_regs *r; -+ unsigned int i; -+ -+ writel_relaxed(0x01, csiphy->base + 0x1000); -+ udelay(1); -+ -+ for (r = cphy_common_regs_x1e80100, i = 0; -+ i < ARRAY_SIZE(cphy_common_regs_x1e80100); i++, r++) { -+ writel_relaxed(r->reg_data, csiphy->base + r->reg_addr); -+ if (r->delay_us) -+ udelay(r->delay_us); -+ } -+ -+ for (r = cphy_datarate_2p5g_x1e80100, i = 0; -+ i < ARRAY_SIZE(cphy_datarate_2p5g_x1e80100); i++, r++) { -+ writel_relaxed(r->reg_data, csiphy->base + r->reg_addr); -+ if (r->delay_us) -+ udelay(r->delay_us); -+ } -+ -+ for (r = cphy_lane_regs_x1e80100, i = 0; -+ i < ARRAY_SIZE(cphy_lane_regs_x1e80100); i++, r++) { -+ writel_relaxed(r->reg_data, csiphy->base + r->reg_addr); -+ if (r->delay_us) -+ udelay(r->delay_us); -+ } -+ -+ /* -+ * Lane-enable value observed for the Surface Pro 11 IMX681 path. -+ * The surrounding register tables come from Qualcomm's GPL driver. -+ */ -+ writel_relaxed(0xd5, csiphy->base + 0x1014); -+ -+ writel_relaxed(0xff, csiphy->base + 0x102c); -+ writel_relaxed(0xff, csiphy->base + 0x1030); -+ writel_relaxed(0xfb, csiphy->base + 0x1034); -+ writel_relaxed(0xff, csiphy->base + 0x1038); -+ writel_relaxed(0x7f, csiphy->base + 0x103c); -+ writel_relaxed(0xff, csiphy->base + 0x1040); -+ writel_relaxed(0xff, csiphy->base + 0x1044); -+ writel_relaxed(0xef, csiphy->base + 0x1048); -+ writel_relaxed(0xff, csiphy->base + 0x104c); -+ writel_relaxed(0xff, csiphy->base + 0x1050); -+ writel_relaxed(0xff, csiphy->base + 0x1054); -+ -+ writel_relaxed(0x0e, csiphy->base + 0x1000); -+ usleep_range(3048, 3100); -+} -+ - static void csiphy_hw_version_read(struct csiphy_device *csiphy, - struct device *dev) - { -@@ -1158,6 +1338,11 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, - u8 val; - int i; - -+ if (cfg->csi2->is_cphy && csiphy_is_gen2(csiphy->camss->res->version)) { -+ csiphy_gen2_config_cphy(csiphy); -+ return; -+ } -+ - settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); - - val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL5_CLK_ENABLE; -@@ -1189,6 +1374,7 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, - writel_relaxed(0, csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, i)); - } -+ - } - - static void csiphy_lanes_disable(struct csiphy_device *csiphy, -@@ -1196,6 +1382,8 @@ static void csiphy_lanes_disable(struct csiphy_device *csiphy, - { - struct csiphy_device_regs *regs = csiphy->regs; - -+ (void)cfg; -+ - writel_relaxed(0, csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 5)); - -diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h -index 9d9657b82f74..9dab9a8946de 100644 ---- a/drivers/media/platform/qcom/camss/camss-csiphy.h -+++ b/drivers/media/platform/qcom/camss/camss-csiphy.h -@@ -42,6 +42,7 @@ struct csiphy_lanes_cfg { - - struct csiphy_csi2_cfg { - struct csiphy_lanes_cfg lane_cfg; -+ bool is_cphy; - }; - - struct csiphy_config { -diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c -index 2123f6388e3d..9fe3bc34495e 100644 ---- a/drivers/media/platform/qcom/camss/camss.c -+++ b/drivers/media/platform/qcom/camss/camss.c -@@ -4754,14 +4754,12 @@ static int camss_parse_endpoint_node(struct device *dev, - if (ret) - return ret; - -- /* -- * Most SoCs support both D-PHY and C-PHY standards, but currently only -- * D-PHY is supported in the driver. -- */ -- if (vep.bus_type != V4L2_MBUS_CSI2_DPHY) { -+ if (vep.bus_type != V4L2_MBUS_CSI2_DPHY && -+ vep.bus_type != V4L2_MBUS_CSI2_CPHY) { - dev_err(dev, "Unsupported bus type %d\n", vep.bus_type); - return -EINVAL; - } -+ csd->interface.csi2.is_cphy = vep.bus_type == V4L2_MBUS_CSI2_CPHY; - - csd->interface.csiphy_id = vep.base.port; - diff --git a/kernel/2125-Documentation-media-record-Surface-Pro-11-camera-pro.patch b/kernel/2125-Documentation-media-record-Surface-Pro-11-camera-pro.patch deleted file mode 100644 index 203651f..0000000 --- a/kernel/2125-Documentation-media-record-Surface-Pro-11-camera-pro.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] Documentation: media: record Surface Pro 11 camera provenance - -Classify the independently observed portions of the implementation, pin -the GPL source revisions used for Qualcomm C-PHY and ST VD55G0 support, -and document material that must not be added to this branch. - -Signed-off-by: Brandon Williams ---- - Documentation/driver-api/media/index.rst | 1 + - .../media/sp11-camera-provenance.rst | 74 +++++++++++++++++++ - 2 files changed, 75 insertions(+) - create mode 100644 Documentation/driver-api/media/sp11-camera-provenance.rst - -diff --git a/Documentation/driver-api/media/index.rst b/Documentation/driver-api/media/index.rst -index 08fc2cfc07a3..fc2c185732f6 100644 ---- a/Documentation/driver-api/media/index.rst -+++ b/Documentation/driver-api/media/index.rst -@@ -35,6 +35,7 @@ Documentation/userspace-api/media/index.rst - cec-core - tx-rx - camera-sensor -+ sp11-camera-provenance - - drivers/index - -diff --git a/Documentation/driver-api/media/sp11-camera-provenance.rst b/Documentation/driver-api/media/sp11-camera-provenance.rst -new file mode 100644 -index 000000000000..64fb9346e4fc ---- /dev/null -+++ b/Documentation/driver-api/media/sp11-camera-provenance.rst -@@ -0,0 +1,74 @@ -+.. SPDX-License-Identifier: GPL-2.0-only -+ -+Surface Pro 11 camera support provenance -+======================================== -+ -+Scope -+----- -+ -+This document records the origin of the Surface Pro 11 camera changes in -+this tree. It is a provenance record, not legal advice. -+ -+No Microsoft or other third-party binary, source file, debug trace, firmware -+image, symbol file, or configuration file is included. The author worked on -+personally owned hardware, had ordinary end-user access only, and was not -+subject to an NDA. Windows driver and firmware file names were used to -+identify relevant devices and runtime activity. Sensor transactions and the -+small number of board-specific register values retained here were independently -+written from runtime observations made on that hardware. -+ -+Source classification -+--------------------- -+ -+``drivers/media/i2c/imx681.c`` and ``imx681-tables.h`` -+ Independently authored Linux driver. The Surface Pro 11 mode table records -+ runtime I2C transactions observed on the author's hardware. It does not -+ contain a copied vendor configuration table. An unobserved table used only -+ during early experiments is deliberately excluded. -+ -+``drivers/media/i2c/ov13858.c`` -+ Extends the existing GPL-2.0 Linux OV13858 driver with one Surface Pro 11 -+ mode reconstructed from runtime I2C observations. Probe-time bus scanners -+ and bring-up-only controls are deliberately excluded. -+ -+``drivers/media/i2c/vd55g0.c``, ``vd55g0_patches.h``, and the VD55G0 binding -+ Imported from STMicroelectronics' GPL driver at commit -+ ``9134fe572b77f906344f37ba227f375db73dc026``:: -+ -+ https://github.com/STMicroelectronics/vd55g0-linux-driver -+ -+ ST's patch arrays are sensor firmware distributed by ST under GPL-2.0 in -+ that repository. They replace an earlier experimental reconstruction. -+ -+``drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c`` -+ The X1E80100 C-PHY common, lane, interrupt, and 2.5-Gsym/s data-rate values -+ are adapted from Qualcomm's ``cam_csiphy_2_1_2_hwreg.h`` under -+ GPL-2.0-only. The exact source blob is -+ ``347fb4944ccedfead1aa0c5260e6b41a5a038017``:: -+ -+ https://github.com/LineageOS/android_kernel_oneplus_sm8550-modules/blob/lineage-23.2/qcom/opensource/camera-kernel/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_1_2_hwreg.h -+ -+ Copyright for those values remains with Qualcomm Innovation Center, Inc. -+ The Surface-specific lane-enable value is an independent runtime -+ observation. Private replay tables and CAMNOC comparison data are not -+ included. -+ -+CAMSS and devicetree foundations -+ The implementation builds on the upstream Linux CAMSS, CCI, camera clock, -+ media-controller, and X1E80100 binding work. In particular, retain credit -+ for Bryan O'Donoghue and Linaro's X1E80100 CAMSS binding work. The board -+ description uses hardware enumeration, standard firmware descriptions, and -+ observations made on the author's Surface Pro 11. -+ -+Review policy -+------------- -+ -+Do not add generated dumps, extracted binary payloads, decompiled output, -+private replay tables, or diagnostic traces to this branch. New observed -+hardware behavior should be expressed as ordinary Linux driver logic and -+documented as an independent runtime observation. Third-party source must -+carry a compatible license, its copyright notice, and an immutable source -+revision. -+ -+The code was developed with LLM assistance. Provenance classifications and -+the decision to publish remain the human maintainer's responsibility. diff --git a/kernel/2126-wifi-ath12k-Add-support-for-disabling-rfkill-via-dev.patch b/kernel/2126-wifi-ath12k-Add-support-for-disabling-rfkill-via-dev.patch deleted file mode 100644 index 1ab0e39..0000000 --- a/kernel/2126-wifi-ath12k-Add-support-for-disabling-rfkill-via-dev.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Dale Whinham -Date: Mon, 12 May 2025 18:37:13 +0000 -Subject: [PATCH] wifi: ath12k: Add support for disabling rfkill via devicetree - -Signed-off-by: Dale Whinham ---- - drivers/net/wireless/ath/ath12k/core.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c -index 5cdf4973d986..6230d54d8be9 100644 ---- a/drivers/net/wireless/ath/ath12k/core.c -+++ b/drivers/net/wireless/ath/ath12k/core.c -@@ -80,6 +80,9 @@ static int ath12k_core_rfkill_config(struct ath12k_base *ab) - if (ath12k_acpi_get_disable_rfkill(ab)) - return 0; - -+ if (of_property_read_bool(ab->dev->of_node, "disable-rfkill")) -+ return 0; -+ - for (i = 0; i < ab->num_radios; i++) { - ar = ab->pdevs[i].ar; - diff --git a/kernel/2127-arm64-dts-qcom-denali-preserve-ath12k-rfkill-quirk.patch b/kernel/2127-arm64-dts-qcom-denali-preserve-ath12k-rfkill-quirk.patch deleted file mode 100644 index 654dbf0..0000000 --- a/kernel/2127-arm64-dts-qcom-denali-preserve-ath12k-rfkill-quirk.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 18:45:42 -0400 -Subject: [PATCH] arm64: dts: qcom: denali: preserve ath12k rfkill quirk - -The WCN7850 firmware reaches mission mode but does not register a -wireless PHY when ath12k configures its firmware rfkill input on -Denali. Bluetooth is unaffected because it uses a separate UART -transport. - -Restore the board property consumed by the Dale Whinham devicetree -rfkill support and record the dependency in the provenance document. - -Signed-off-by: Brandon Williams ---- - .../driver-api/media/sp11-camera-provenance.rst | 9 +++++++++ - arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi | 3 +++ - 2 files changed, 12 insertions(+) - -diff --git a/Documentation/driver-api/media/sp11-camera-provenance.rst b/Documentation/driver-api/media/sp11-camera-provenance.rst -index 64fb9346e4fc..a71858c5705e 100644 ---- a/Documentation/driver-api/media/sp11-camera-provenance.rst -+++ b/Documentation/driver-api/media/sp11-camera-provenance.rst -@@ -60,6 +60,15 @@ CAMSS and devicetree foundations - description uses hardware enumeration, standard firmware descriptions, and - observations made on the author's Surface Pro 11. - -+Denali ath12k rfkill prerequisite -+ The ath12k devicetree ``disable-rfkill`` support is Dale Whinham's GPL -+ contribution, originally commit -+ ``d7e0b837ef4672f294af3d7f59eefe7a241371db`` with his authorship and -+ Signed-off-by trailer preserved. The matching Denali property was -+ reintroduced after a one-shot hardware test showed that WCN7850 firmware -+ initialized but no wireless PHY registered without the quirk. Bluetooth -+ continued to operate over its separate UART transport. -+ - Review policy - ------------- - -diff --git a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -index ce7d958ca687..9cf8e1a5e0bf 100644 ---- a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -+++ b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -@@ -950,6 +950,9 @@ wifi@0 { - compatible = "pci17cb,1107"; - reg = <0x10000 0x0 0x0 0x0 0x0>; - -+ /* Denali does not expose a usable firmware rfkill input. */ -+ disable-rfkill; -+ - vddaon-supply = <&vreg_pmu_aon_0p59>; - vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; - vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; diff --git a/kernel/2128-dt-bindings-net-qcom-ath12k-document-disable-rfkill.patch b/kernel/2128-dt-bindings-net-qcom-ath12k-document-disable-rfkill.patch deleted file mode 100644 index 60b4282..0000000 --- a/kernel/2128-dt-bindings-net-qcom-ath12k-document-disable-rfkill.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 18:46:35 -0400 -Subject: [PATCH] dt-bindings: net: qcom,ath12k: document disable-rfkill - -Allow boards without a usable hardware rfkill input to request that -the driver skip firmware rfkill configuration. - -Signed-off-by: Brandon Williams ---- - .../devicetree/bindings/net/wireless/qcom,ath12k.yaml | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml -index dc68dd59988f..6de83f18b63b 100644 ---- a/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml -+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath12k.yaml -@@ -27,6 +27,12 @@ properties: - If present, a board or platform specific string used to lookup - usecase-specific firmware files for the device. - -+ disable-rfkill: -+ type: boolean -+ description: -+ Skip firmware rfkill configuration on platforms that do not expose a -+ usable hardware rfkill input to the wireless device. -+ - vddaon-supply: - description: VDD_AON supply regulator handle - diff --git a/kernel/2129-media-qcom-camss-restore-observed-Denali-C-PHY-seque.patch b/kernel/2129-media-qcom-camss-restore-observed-Denali-C-PHY-seque.patch deleted file mode 100644 index 0fce7d8..0000000 --- a/kernel/2129-media-qcom-camss-restore-observed-Denali-C-PHY-seque.patch +++ /dev/null @@ -1,380 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 19:01:32 -0400 -Subject: [PATCH] media: qcom: camss: restore observed Denali C-PHY sequence - -Signed-off-by: Brandon Williams ---- - .../media/sp11-camera-provenance.rst | 31 +-- - .../qcom/camss/camss-csiphy-3ph-1-0.c | 73 ++++++- - .../qcom/camss/x1e80100-cphy-observed.h | 198 ++++++++++++++++++ - 3 files changed, 287 insertions(+), 15 deletions(-) - create mode 100644 drivers/media/platform/qcom/camss/x1e80100-cphy-observed.h - -diff --git a/Documentation/driver-api/media/sp11-camera-provenance.rst b/Documentation/driver-api/media/sp11-camera-provenance.rst -index a71858c5705e..b774d676d3ee 100644 ---- a/Documentation/driver-api/media/sp11-camera-provenance.rst -+++ b/Documentation/driver-api/media/sp11-camera-provenance.rst -@@ -41,17 +41,22 @@ Source classification - that repository. They replace an earlier experimental reconstruction. - - ``drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c`` -- The X1E80100 C-PHY common, lane, interrupt, and 2.5-Gsym/s data-rate values -- are adapted from Qualcomm's ``cam_csiphy_2_1_2_hwreg.h`` under -- GPL-2.0-only. The exact source blob is -+ The generic 4 nm C-PHY common, lane, and 2.5-Gsym/s data-rate values are -+ adapted from Qualcomm's ``cam_csiphy_2_1_2_hwreg.h`` under GPL-2.0-only. -+ The exact source blob is - ``347fb4944ccedfead1aa0c5260e6b41a5a038017``:: - - https://github.com/LineageOS/android_kernel_oneplus_sm8550-modules/blob/lineage-23.2/qcom/opensource/camera-kernel/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_1_2_hwreg.h - -- Copyright for those values remains with Qualcomm Innovation Center, Inc. -- The Surface-specific lane-enable value is an independent runtime -- observation. Private replay tables and CAMNOC comparison data are not -- included. -+ Copyright for those generic values remains with Qualcomm Innovation Center, -+ Inc. Hardware testing showed that the generic sequence did not bring up the -+ Surface Pro 11 front-camera link. The Surface-specific initialization, -+ interrupt-clear, shutdown, and delay values in -+ ``x1e80100-cphy-observed.h`` are instead an independently transcribed record -+ of MMIO writes observed at runtime with WinDbg on the maintainer's own -+ hardware. No vendor source, decompiled output, driver binary, symbol file, -+ or raw debug trace is included. A fresh source build using this bounded -+ observation table restored front-camera frames on the target machine. - - CAMSS and devicetree foundations - The implementation builds on the upstream Linux CAMSS, CCI, camera clock, -@@ -72,12 +77,12 @@ Denali ath12k rfkill prerequisite - Review policy - ------------- - --Do not add generated dumps, extracted binary payloads, decompiled output, --private replay tables, or diagnostic traces to this branch. New observed --hardware behavior should be expressed as ordinary Linux driver logic and --documented as an independent runtime observation. Third-party source must --carry a compatible license, its copyright notice, and an immutable source --revision. -+Do not add generated dumps, extracted binary payloads, decompiled output, raw -+diagnostic traces, or unrelated register collections to this branch. New -+observed hardware behavior should be reduced to the bounded values required by -+ordinary Linux driver logic and documented as an independent runtime -+observation. Third-party source must carry a compatible license, its -+copyright notice, and an immutable source revision. - - The code was developed with LLM assistance. Provenance classifications and - the decision to publish remain the human maintainer's responsibility. -diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c -index 3972b7ebe5cd..219434d2696a 100644 ---- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c -+++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c -@@ -1050,11 +1050,68 @@ csiphy_lane_regs cphy_lane_regs_x1e80100[] = { - {0x0A90, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, - }; - -+#include "x1e80100-cphy-observed.h" -+ -+static bool csiphy_uses_x1e80100_observed_cphy(struct csiphy_device *csiphy) -+{ -+ return csiphy->camss->res->version == CAMSS_X1E80100 && -+ csiphy->cfg.csi2 && csiphy->cfg.csi2->is_cphy; -+} -+ -+static void -+csiphy_write_x1e80100_observations(struct csiphy_device *csiphy, -+ const struct x1e80100_cphy_reg *table, -+ unsigned int num_entries) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < num_entries; i++) { -+ u32 delay_us; -+ -+ /* writel() preserves the ordering seen at the runtime MMIO writer. */ -+ writel(table[i].reg_data, csiphy->base + table[i].reg_addr); -+ -+ if (!table[i].delay_ns) -+ continue; -+ -+ /* The observed writer floors nanoseconds and enforces a 1 us minimum. */ -+ delay_us = max_t(u32, table[i].delay_ns / NSEC_PER_USEC, 1); -+ if (delay_us <= 50) -+ udelay(delay_us); -+ else -+ usleep_range(delay_us, -+ delay_us + max(delay_us / 100, 10U)); -+ } -+} -+ - static void csiphy_gen2_config_cphy(struct csiphy_device *csiphy) - { - const struct csiphy_lane_regs *r; - unsigned int i; - -+ if (csiphy_uses_x1e80100_observed_cphy(csiphy)) { -+ BUILD_BUG_ON(ARRAY_SIZE(x1e80100_cphy_reset) != 2); -+ BUILD_BUG_ON(ARRAY_SIZE(x1e80100_cphy_toggle) != 6); -+ BUILD_BUG_ON(ARRAY_SIZE(x1e80100_cphy_common) != 9); -+ BUILD_BUG_ON(ARRAY_SIZE(x1e80100_cphy_config) != 121); -+ BUILD_BUG_ON(ARRAY_SIZE(x1e80100_cphy_irq_clear) != 24); -+ BUILD_BUG_ON(ARRAY_SIZE(x1e80100_cphy_shutdown) != 3); -+ -+ csiphy_write_x1e80100_observations(csiphy, -+ x1e80100_cphy_reset, -+ ARRAY_SIZE(x1e80100_cphy_reset)); -+ csiphy_write_x1e80100_observations(csiphy, -+ x1e80100_cphy_toggle, -+ ARRAY_SIZE(x1e80100_cphy_toggle)); -+ csiphy_write_x1e80100_observations(csiphy, -+ x1e80100_cphy_common, -+ ARRAY_SIZE(x1e80100_cphy_common)); -+ csiphy_write_x1e80100_observations(csiphy, -+ x1e80100_cphy_config, -+ ARRAY_SIZE(x1e80100_cphy_config)); -+ return; -+ } -+ - writel_relaxed(0x01, csiphy->base + 0x1000); - udelay(1); - -@@ -1147,6 +1204,13 @@ static irqreturn_t csiphy_isr(int irq, void *dev) - struct csiphy_device_regs *regs = csiphy->regs; - int i; - -+ if (csiphy_uses_x1e80100_observed_cphy(csiphy)) { -+ csiphy_write_x1e80100_observations(csiphy, -+ x1e80100_cphy_irq_clear, -+ ARRAY_SIZE(x1e80100_cphy_irq_clear)); -+ return IRQ_HANDLED; -+ } -+ - for (i = 0; i < 11; i++) { - int c = i + 22; - u8 val = readl_relaxed(csiphy->base + -@@ -1374,7 +1438,6 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, - writel_relaxed(0, csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, i)); - } -- - } - - static void csiphy_lanes_disable(struct csiphy_device *csiphy, -@@ -1382,7 +1445,13 @@ static void csiphy_lanes_disable(struct csiphy_device *csiphy, - { - struct csiphy_device_regs *regs = csiphy->regs; - -- (void)cfg; -+ if (cfg->csi2->is_cphy && -+ csiphy->camss->res->version == CAMSS_X1E80100) { -+ csiphy_write_x1e80100_observations(csiphy, -+ x1e80100_cphy_shutdown, -+ ARRAY_SIZE(x1e80100_cphy_shutdown)); -+ return; -+ } - - writel_relaxed(0, csiphy->base + - CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(regs->offset, 5)); -diff --git a/drivers/media/platform/qcom/camss/x1e80100-cphy-observed.h b/drivers/media/platform/qcom/camss/x1e80100-cphy-observed.h -new file mode 100644 -index 000000000000..7eaeb97db4bd ---- /dev/null -+++ b/drivers/media/platform/qcom/camss/x1e80100-cphy-observed.h -@@ -0,0 +1,198 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Surface Pro 11 X1E80100 C-PHY register observations. -+ * -+ * These address/value/delay triples were independently transcribed from -+ * runtime WinDbg MMIO observations on the maintainer's own Surface Pro 11 -+ * while its front camera was streaming. They are hardware observations, not -+ * copied vendor source, decompiled output, or an extracted binary payload. -+ * Delays retain the observed nanosecond argument passed to the common writer. -+ */ -+struct x1e80100_cphy_reg { -+ u32 reg_addr; -+ u32 reg_data; -+ u32 delay_ns; -+}; -+ -+static const struct x1e80100_cphy_reg x1e80100_cphy_reset[] = { -+ { 0x1000, 0x01, 0x00000014 }, -+ { 0x1000, 0x00, 0x00000000 }, -+}; -+ -+static const struct x1e80100_cphy_reg x1e80100_cphy_toggle[] = { -+ { 0x025c, 0x10, 0x00000064 }, -+ { 0x025c, 0x00, 0x00000000 }, -+ { 0x065c, 0x10, 0x00000064 }, -+ { 0x065c, 0x00, 0x00000000 }, -+ { 0x0a5c, 0x10, 0x00000064 }, -+ { 0x0a5c, 0x00, 0x00000000 }, -+}; -+ -+static const struct x1e80100_cphy_reg x1e80100_cphy_common[] = { -+ { 0x1084, 0x00, 0x00000000 }, -+ { 0x108c, 0x00, 0x000003e8 }, -+ { 0x02f0, 0x00, 0x00000000 }, -+ { 0x06f0, 0x00, 0x00000000 }, -+ { 0x0af0, 0x00, 0x00000000 }, -+ { 0x1014, 0x02, 0x00000000 }, -+ { 0x101c, 0x7a, 0x00000000 }, -+ { 0x1018, 0x01, 0x00000000 }, -+ { 0x101c, 0x7a, 0x00000000 }, -+}; -+ -+static const struct x1e80100_cphy_reg x1e80100_cphy_config[] = { -+ { 0x0268, 0xf1, 0x00 }, -+ { 0x0294, 0x01, 0x00 }, -+ { 0x0278, 0x20, 0x00 }, -+ { 0x0288, 0x20, 0x00 }, -+ { 0x026c, 0x3d, 0x00 }, -+ { 0x028c, 0x30, 0x00 }, -+ { 0x0270, 0x00, 0x00 }, -+ { 0x0274, 0x03, 0x00 }, -+ { 0x0668, 0xf1, 0x00 }, -+ { 0x0694, 0x01, 0x00 }, -+ { 0x0678, 0x20, 0x00 }, -+ { 0x0688, 0x20, 0x00 }, -+ { 0x066c, 0x3d, 0x00 }, -+ { 0x068c, 0x30, 0x00 }, -+ { 0x0670, 0x00, 0x00 }, -+ { 0x0674, 0x03, 0x00 }, -+ { 0x0a68, 0xf1, 0x00 }, -+ { 0x0a94, 0x01, 0x00 }, -+ { 0x0a78, 0x20, 0x00 }, -+ { 0x0a88, 0x20, 0x00 }, -+ { 0x0a6c, 0x3d, 0x00 }, -+ { 0x0a8c, 0x30, 0x00 }, -+ { 0x0a70, 0x00, 0x00 }, -+ { 0x0a74, 0x03, 0x00989680 }, -+ { 0x0294, 0x09, 0x00000000 }, -+ { 0x02f4, 0x00, 0x00000000 }, -+ { 0x02f8, 0x00, 0x00000000 }, -+ { 0x02fc, 0x00, 0x00000000 }, -+ { 0x02f0, 0xef, 0x000f4240 }, -+ { 0x0694, 0x09, 0x00000000 }, -+ { 0x06f4, 0x00, 0x00000000 }, -+ { 0x06f8, 0x00, 0x00000000 }, -+ { 0x06fc, 0x00, 0x00000000 }, -+ { 0x06f0, 0xef, 0x00000000 }, -+ { 0x0a94, 0x09, 0x00000000 }, -+ { 0x0af4, 0x00, 0x00000000 }, -+ { 0x0af8, 0x00, 0x00000000 }, -+ { 0x0afc, 0x00, 0x00000000 }, -+ { 0x0af0, 0xef, 0x00989680 }, -+ { 0x020c, 0x22, 0x00 }, -+ { 0x0208, 0x00, 0x00 }, -+ { 0x0210, 0x00, 0x00 }, -+ { 0x0214, 0x00, 0x00 }, -+ { 0x0204, 0x00, 0x00 }, -+ { 0x02e4, 0x00, 0x00 }, -+ { 0x02e8, 0x7f, 0x00 }, -+ { 0x02ec, 0x7f, 0x00 }, -+ { 0x0218, 0x3e, 0x00 }, -+ { 0x021c, 0x41, 0x00 }, -+ { 0x0220, 0x41, 0x00 }, -+ { 0x0224, 0x7f, 0x00 }, -+ { 0x0228, 0x00, 0x00 }, -+ { 0x022c, 0x00, 0x00 }, -+ { 0x0264, 0x01, 0x00 }, -+ { 0x0244, 0xb2, 0x00 }, -+ { 0x0310, 0x35, 0x00 }, -+ { 0x02bc, 0xd0, 0x00 }, -+ { 0x0254, 0x00, 0x00 }, -+ { 0x0240, 0x00, 0x00 }, -+ { 0x0260, 0xa8, 0x00 }, -+ { 0x0284, 0x00, 0x00 }, -+ { 0x0290, 0x02, 0x00 }, -+ { 0x060c, 0x22, 0x00 }, -+ { 0x0608, 0x00, 0x00 }, -+ { 0x0610, 0x00, 0x00 }, -+ { 0x0614, 0x00, 0x00 }, -+ { 0x0604, 0x00, 0x00 }, -+ { 0x06e4, 0x00, 0x00 }, -+ { 0x06e8, 0x7f, 0x00 }, -+ { 0x06ec, 0x7f, 0x00 }, -+ { 0x0618, 0x3e, 0x00 }, -+ { 0x061c, 0x41, 0x00 }, -+ { 0x0620, 0x41, 0x00 }, -+ { 0x0624, 0x7f, 0x00 }, -+ { 0x0628, 0x00, 0x00 }, -+ { 0x062c, 0x00, 0x00 }, -+ { 0x0664, 0x01, 0x00 }, -+ { 0x0644, 0xb2, 0x00 }, -+ { 0x0710, 0x35, 0x00 }, -+ { 0x06bc, 0xd0, 0x00 }, -+ { 0x0654, 0x00, 0x00 }, -+ { 0x0640, 0x00, 0x00 }, -+ { 0x0660, 0xa8, 0x00 }, -+ { 0x0684, 0x00, 0x00 }, -+ { 0x0690, 0x02, 0x00 }, -+ { 0x0a0c, 0x22, 0x00 }, -+ { 0x0a08, 0x00, 0x00 }, -+ { 0x0a10, 0x00, 0x00 }, -+ { 0x0a14, 0x00, 0x00 }, -+ { 0x0a00, 0x00, 0x00 }, -+ { 0x0a04, 0x00, 0x00 }, -+ { 0x0ae4, 0x00, 0x00 }, -+ { 0x0ae8, 0x7f, 0x00 }, -+ { 0x0aec, 0x7f, 0x00 }, -+ { 0x0a18, 0x3e, 0x00 }, -+ { 0x0a1c, 0x41, 0x00 }, -+ { 0x0a20, 0x41, 0x00 }, -+ { 0x0a24, 0x7f, 0x00 }, -+ { 0x0a28, 0x00, 0x00 }, -+ { 0x0a2c, 0x00, 0x00 }, -+ { 0x0a64, 0x01, 0x00 }, -+ { 0x0a44, 0xb2, 0x00 }, -+ { 0x0b10, 0x35, 0x00 }, -+ { 0x0abc, 0xd0, 0x00 }, -+ { 0x0a54, 0x00, 0x00 }, -+ { 0x0a40, 0x00, 0x00 }, -+ { 0x0a60, 0xa8, 0x00 }, -+ { 0x0a84, 0x00, 0x00 }, -+ { 0x0a90, 0x02, 0x00 }, -+ { 0x102c, 0xff, 0x00 }, -+ { 0x1030, 0xfe, 0x00 }, -+ { 0x1034, 0xe2, 0x00 }, -+ { 0x1038, 0xdf, 0x00 }, -+ { 0x103c, 0x5f, 0x00 }, -+ { 0x1040, 0xfc, 0x00 }, -+ { 0x1044, 0xfb, 0x00 }, -+ { 0x1048, 0x8b, 0x00 }, -+ { 0x104c, 0x7f, 0x00 }, -+ { 0x1050, 0xbf, 0x00 }, -+ { 0x1054, 0xff, 0x00 }, -+ { 0x1000, 0x0e, 0x00 }, -+}; -+ -+static const struct x1e80100_cphy_reg x1e80100_cphy_irq_clear[] = { -+ { 0x1058, 0xff, 0x00000000 }, -+ { 0x105c, 0xff, 0x00000000 }, -+ { 0x1060, 0xff, 0x00000000 }, -+ { 0x1064, 0xff, 0x00000000 }, -+ { 0x1068, 0xff, 0x00000000 }, -+ { 0x106c, 0xff, 0x00000000 }, -+ { 0x1070, 0xff, 0x00000000 }, -+ { 0x1074, 0xff, 0x00000000 }, -+ { 0x1078, 0xff, 0x00000000 }, -+ { 0x107c, 0xff, 0x00000000 }, -+ { 0x1080, 0xff, 0x00000064 }, -+ { 0x1028, 0x01, 0x00000064 }, -+ { 0x1058, 0x00, 0x00000000 }, -+ { 0x105c, 0x00, 0x00000000 }, -+ { 0x1060, 0x00, 0x00000000 }, -+ { 0x1064, 0x00, 0x00000000 }, -+ { 0x1068, 0x00, 0x00000000 }, -+ { 0x106c, 0x00, 0x00000000 }, -+ { 0x1070, 0x00, 0x00000000 }, -+ { 0x1074, 0x00, 0x00000000 }, -+ { 0x1078, 0x00, 0x00000000 }, -+ { 0x107c, 0x00, 0x00000000 }, -+ { 0x1080, 0x00, 0x00000064 }, -+ { 0x1028, 0x00, 0x00000064 }, -+}; -+ -+static const struct x1e80100_cphy_reg x1e80100_cphy_shutdown[] = { -+ { 0x1014, 0x00, 0x00000000 }, -+ { 0x101c, 0x00, 0x00000000 }, -+ { 0x1018, 0x00, 0x00000000 }, -+}; diff --git a/kernel/2130-platform-surface-recheck-tablet-mode-after-resume.patch b/kernel/2130-platform-surface-recheck-tablet-mode-after-resume.patch deleted file mode 100644 index 2b92a88..0000000 --- a/kernel/2130-platform-surface-recheck-tablet-mode-after-resume.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Tue, 21 Jul 2026 21:24:19 -0400 -Subject: [PATCH] platform/surface: recheck tablet mode after resume - -Some Surface devices can report an early stale posture during resume and -then miss the correction notification, leaving SW_TABLET_MODE asserted -after the controller has settled. - -Keep the immediate query and schedule one delayed re-query after two -seconds. Route the delayed request through the existing update work so -state queries and input events remain serialized. - -Signed-off-by: Brandon Williams ---- - .../surface/surface_aggregator_tabletsw.c | 32 ++++++++++++++++++- - 1 file changed, 31 insertions(+), 1 deletion(-) - -diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c -index 13031c329553..ca499a360373 100644 ---- a/drivers/platform/surface/surface_aggregator_tabletsw.c -+++ b/drivers/platform/surface/surface_aggregator_tabletsw.c -@@ -38,6 +38,7 @@ struct ssam_tablet_sw { - - struct ssam_tablet_sw_state state; - struct work_struct update_work; -+ struct delayed_work resume_update_work; - struct input_dev *mode_switch; - - struct ssam_tablet_sw_ops ops; -@@ -105,14 +106,40 @@ static void ssam_tablet_sw_update_workfn(struct work_struct *work) - input_sync(sw->mode_switch); - } - -+static void ssam_tablet_sw_resume_update_workfn(struct work_struct *work) -+{ -+ struct ssam_tablet_sw *sw = container_of(to_delayed_work(work), -+ struct ssam_tablet_sw, -+ resume_update_work); -+ -+ /* Serialize the delayed re-query through the normal update work. */ -+ schedule_work(&sw->update_work); -+} -+ -+static int __maybe_unused ssam_tablet_sw_suspend(struct device *dev) -+{ -+ struct ssam_tablet_sw *sw = dev_get_drvdata(dev); -+ -+ cancel_delayed_work_sync(&sw->resume_update_work); -+ return 0; -+} -+ - static int __maybe_unused ssam_tablet_sw_resume(struct device *dev) - { - struct ssam_tablet_sw *sw = dev_get_drvdata(dev); - -+ /* -+ * Query immediately, then re-query after the controller has had time to -+ * report its settled post-resume posture. Some devices can otherwise -+ * retain the early state if the corresponding notification is missed. -+ */ - schedule_work(&sw->update_work); -+ mod_delayed_work(system_wq, &sw->resume_update_work, msecs_to_jiffies(2000)); - return 0; - } --static SIMPLE_DEV_PM_OPS(ssam_tablet_sw_pm_ops, NULL, ssam_tablet_sw_resume); -+ -+static SIMPLE_DEV_PM_OPS(ssam_tablet_sw_pm_ops, ssam_tablet_sw_suspend, -+ ssam_tablet_sw_resume); - - static int ssam_tablet_sw_probe(struct ssam_device *sdev) - { -@@ -137,6 +164,7 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - sw->ops.state_is_tablet_mode = desc->ops.state_is_tablet_mode; - - INIT_WORK(&sw->update_work, ssam_tablet_sw_update_workfn); -+ INIT_DELAYED_WORK(&sw->resume_update_work, ssam_tablet_sw_resume_update_workfn); - - ssam_device_set_drvdata(sdev, sw); - -@@ -185,6 +213,7 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - - err: - ssam_device_notifier_unregister(sdev, &sw->notif); -+ cancel_delayed_work_sync(&sw->resume_update_work); - cancel_work_sync(&sw->update_work); - return status; - } -@@ -196,6 +225,7 @@ static void ssam_tablet_sw_remove(struct ssam_device *sdev) - sysfs_remove_group(&sdev->dev.kobj, &ssam_tablet_sw_group); - - ssam_device_notifier_unregister(sdev, &sw->notif); -+ cancel_delayed_work_sync(&sw->resume_update_work); - cancel_work_sync(&sw->update_work); - } - diff --git a/kernel/2131-platform-surface-resync-tablet-mode-on-KIP-connectio.patch b/kernel/2131-platform-surface-resync-tablet-mode-on-KIP-connectio.patch deleted file mode 100644 index 6b95c6c..0000000 --- a/kernel/2131-platform-surface-resync-tablet-mode-on-KIP-connectio.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Tue, 21 Jul 2026 22:50:26 -0400 -Subject: [PATCH] platform/surface: resync tablet mode on KIP connection - -The KIP hub connection event can arrive and re-enumerate the keyboard -and touchpad even when the separate cover-state notification is lost. In -that case the tablet-mode switch retains a stale disconnected state and -userspace suppresses the attached touchpad. - -Observe KIP connection changes and schedule a controller-backed state -query after two seconds. Keep the hub as the primary event handler and -share the delayed serialized update path with the resume correction. - -Signed-off-by: Brandon Williams ---- - .../surface/surface_aggregator_tabletsw.c | 46 +++++++++++++------ - 1 file changed, 31 insertions(+), 15 deletions(-) - -diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c -index ca499a360373..d4604eb8aeda 100644 ---- a/drivers/platform/surface/surface_aggregator_tabletsw.c -+++ b/drivers/platform/surface/surface_aggregator_tabletsw.c -@@ -38,7 +38,7 @@ struct ssam_tablet_sw { - - struct ssam_tablet_sw_state state; - struct work_struct update_work; -- struct delayed_work resume_update_work; -+ struct delayed_work delayed_update_work; - struct input_dev *mode_switch; - - struct ssam_tablet_sw_ops ops; -@@ -106,11 +106,11 @@ static void ssam_tablet_sw_update_workfn(struct work_struct *work) - input_sync(sw->mode_switch); - } - --static void ssam_tablet_sw_resume_update_workfn(struct work_struct *work) -+static void ssam_tablet_sw_delayed_update_workfn(struct work_struct *work) - { - struct ssam_tablet_sw *sw = container_of(to_delayed_work(work), - struct ssam_tablet_sw, -- resume_update_work); -+ delayed_update_work); - - /* Serialize the delayed re-query through the normal update work. */ - schedule_work(&sw->update_work); -@@ -120,7 +120,7 @@ static int __maybe_unused ssam_tablet_sw_suspend(struct device *dev) - { - struct ssam_tablet_sw *sw = dev_get_drvdata(dev); - -- cancel_delayed_work_sync(&sw->resume_update_work); -+ cancel_delayed_work_sync(&sw->delayed_update_work); - return 0; - } - -@@ -134,7 +134,7 @@ static int __maybe_unused ssam_tablet_sw_resume(struct device *dev) - * retain the early state if the corresponding notification is missed. - */ - schedule_work(&sw->update_work); -- mod_delayed_work(system_wq, &sw->resume_update_work, msecs_to_jiffies(2000)); -+ mod_delayed_work(system_wq, &sw->delayed_update_work, msecs_to_jiffies(2000)); - return 0; - } - -@@ -164,7 +164,7 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - sw->ops.state_is_tablet_mode = desc->ops.state_is_tablet_mode; - - INIT_WORK(&sw->update_work, ssam_tablet_sw_update_workfn); -- INIT_DELAYED_WORK(&sw->resume_update_work, ssam_tablet_sw_resume_update_workfn); -+ INIT_DELAYED_WORK(&sw->delayed_update_work, ssam_tablet_sw_delayed_update_workfn); - - ssam_device_set_drvdata(sdev, sw); - -@@ -213,7 +213,7 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - - err: - ssam_device_notifier_unregister(sdev, &sw->notif); -- cancel_delayed_work_sync(&sw->resume_update_work); -+ cancel_delayed_work_sync(&sw->delayed_update_work); - cancel_work_sync(&sw->update_work); - return status; - } -@@ -225,7 +225,7 @@ static void ssam_tablet_sw_remove(struct ssam_device *sdev) - sysfs_remove_group(&sdev->dev.kobj, &ssam_tablet_sw_group); - - ssam_device_notifier_unregister(sdev, &sw->notif); -- cancel_delayed_work_sync(&sw->resume_update_work); -+ cancel_delayed_work_sync(&sw->delayed_update_work); - cancel_work_sync(&sw->update_work); - } - -@@ -233,6 +233,7 @@ static void ssam_tablet_sw_remove(struct ssam_device *sdev) - /* -- SSAM KIP tablet switch implementation. -------------------------------- */ - - #define SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED 0x1d -+#define SSAM_EVENT_KIP_CID_CONNECTION_CHANGED 0x2c - - enum ssam_kip_cover_state { - SSAM_KIP_COVER_STATE_DISCONNECTED = 0x01, -@@ -318,14 +319,29 @@ static u32 ssam_kip_sw_notif(struct ssam_event_notifier *nf, const struct ssam_e - { - struct ssam_tablet_sw *sw = container_of(nf, struct ssam_tablet_sw, notif); - -- if (event->command_id != SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED) -+ switch (event->command_id) { -+ case SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED: -+ if (event->length < 1) -+ dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", -+ event->length); -+ -+ schedule_work(&sw->update_work); -+ return SSAM_NOTIF_HANDLED; -+ -+ case SSAM_EVENT_KIP_CID_CONNECTION_CHANGED: -+ /* -+ * Cover-state notifications can be lost while the KIP devices are -+ * being re-enumerated. Re-query once the controller and devices have -+ * had time to settle so that the input switch cannot remain stale. -+ * The subsystem hub remains the primary handler for this event. -+ */ -+ mod_delayed_work(system_wq, &sw->delayed_update_work, -+ msecs_to_jiffies(2000)); -+ return 0; -+ -+ default: - return 0; /* Return "unhandled". */ -- -- if (event->length < 1) -- dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length); -- -- schedule_work(&sw->update_work); -- return SSAM_NOTIF_HANDLED; -+ } - } - - static const struct ssam_tablet_sw_desc ssam_kip_sw_desc = { diff --git a/kernel/2132-platform-surface-retry-KIP-cover-state-while-settlin.patch b/kernel/2132-platform-surface-retry-KIP-cover-state-while-settlin.patch deleted file mode 100644 index 0bea397..0000000 --- a/kernel/2132-platform-surface-retry-KIP-cover-state-while-settlin.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Wed, 22 Jul 2026 06:05:04 -0400 -Subject: [PATCH] platform/surface: retry KIP cover state while settling - -The KIP cover-state query can transiently return zero while the Flex -Keyboard devices are being re-enumerated. Zero is outside the documented -posture range, and caching it can leave SW_TABLET_MODE asserted after -the keyboard has been reattached. - -Treat out-of-range states as not ready and perform bounded delayed queries -after KIP connection changes. Stop the sequence as soon as the controller -returns a valid posture, while retaining the existing delayed post-resume -check. If the cover is still settling at probe, bind with an empty state -and start the same retry sequence instead of failing the probe. - -Signed-off-by: Brandon Williams ---- - .../surface/surface_aggregator_tabletsw.c | 62 ++++++++++++++++--- - 1 file changed, 52 insertions(+), 10 deletions(-) - -diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c -index d4604eb8aeda..4ee64d6c2cfc 100644 ---- a/drivers/platform/surface/surface_aggregator_tabletsw.c -+++ b/drivers/platform/surface/surface_aggregator_tabletsw.c -@@ -5,6 +5,7 @@ - * Copyright (C) 2022 Maximilian Luz - */ - -+#include - #include - #include - #include -@@ -39,12 +40,16 @@ struct ssam_tablet_sw { - struct ssam_tablet_sw_state state; - struct work_struct update_work; - struct delayed_work delayed_update_work; -+ atomic_t delayed_update_count; - struct input_dev *mode_switch; - - struct ssam_tablet_sw_ops ops; - struct ssam_event_notifier notif; - }; - -+#define SSAM_TABLET_SW_UPDATE_DELAY_MS 2000 -+#define SSAM_KIP_UPDATE_COUNT 15 -+ - struct ssam_tablet_sw_desc { - struct { - const char *name; -@@ -97,13 +102,18 @@ static void ssam_tablet_sw_update_workfn(struct work_struct *work) - return; - - if (sw->state.source == state.source && sw->state.state == state.state) -- return; -+ goto out; - sw->state = state; - - /* Send SW_TABLET_MODE event. */ - tablet = sw->ops.state_is_tablet_mode(sw, &state); - input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); - input_sync(sw->mode_switch); -+ -+out: -+ /* A settled KIP response ends a connection-change retry sequence. */ -+ if (atomic_read(&sw->delayed_update_count) > 1) -+ atomic_set(&sw->delayed_update_count, 0); - } - - static void ssam_tablet_sw_delayed_update_workfn(struct work_struct *work) -@@ -112,14 +122,30 @@ static void ssam_tablet_sw_delayed_update_workfn(struct work_struct *work) - struct ssam_tablet_sw, - delayed_update_work); - -+ if (atomic_read(&sw->delayed_update_count) <= 0) -+ return; -+ - /* Serialize the delayed re-query through the normal update work. */ - schedule_work(&sw->update_work); -+ -+ if (atomic_dec_if_positive(&sw->delayed_update_count) > 0) -+ mod_delayed_work(system_percpu_wq, &sw->delayed_update_work, -+ msecs_to_jiffies(SSAM_TABLET_SW_UPDATE_DELAY_MS)); -+} -+ -+static void ssam_tablet_sw_schedule_delayed_updates(struct ssam_tablet_sw *sw, -+ unsigned int count) -+{ -+ atomic_set(&sw->delayed_update_count, count); -+ mod_delayed_work(system_percpu_wq, &sw->delayed_update_work, -+ msecs_to_jiffies(SSAM_TABLET_SW_UPDATE_DELAY_MS)); - } - - static int __maybe_unused ssam_tablet_sw_suspend(struct device *dev) - { - struct ssam_tablet_sw *sw = dev_get_drvdata(dev); - -+ atomic_set(&sw->delayed_update_count, 0); - cancel_delayed_work_sync(&sw->delayed_update_work); - return 0; - } -@@ -134,7 +160,7 @@ static int __maybe_unused ssam_tablet_sw_resume(struct device *dev) - * retain the early state if the corresponding notification is missed. - */ - schedule_work(&sw->update_work); -- mod_delayed_work(system_wq, &sw->delayed_update_work, msecs_to_jiffies(2000)); -+ ssam_tablet_sw_schedule_delayed_updates(sw, 1); - return 0; - } - -@@ -145,6 +171,7 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - { - const struct ssam_tablet_sw_desc *desc; - struct ssam_tablet_sw *sw; -+ bool settling; - int tablet, status; - - desc = ssam_device_get_match_data(sdev); -@@ -165,12 +192,19 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - - INIT_WORK(&sw->update_work, ssam_tablet_sw_update_workfn); - INIT_DELAYED_WORK(&sw->delayed_update_work, ssam_tablet_sw_delayed_update_workfn); -+ atomic_set(&sw->delayed_update_count, 0); - - ssam_device_set_drvdata(sdev, sw); - -- /* Get initial state. */ -+ /* -+ * Get initial state. A KIP cover can still be settling here; start -+ * from an empty state and re-query until it reports a valid one. -+ */ - status = sw->ops.get_state(sw, &sw->state); -- if (status) -+ settling = status == -EAGAIN; -+ if (settling) -+ sw->state = (struct ssam_tablet_sw_state) { }; -+ else if (status) - return status; - - /* Set up tablet mode switch. */ -@@ -183,7 +217,7 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - sw->mode_switch->id.bustype = BUS_HOST; - sw->mode_switch->dev.parent = &sdev->dev; - -- tablet = sw->ops.state_is_tablet_mode(sw, &sw->state); -+ tablet = settling || sw->ops.state_is_tablet_mode(sw, &sw->state); - input_set_capability(sw->mode_switch, EV_SW, SW_TABLET_MODE); - input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); - -@@ -208,11 +242,14 @@ static int ssam_tablet_sw_probe(struct ssam_device *sdev) - goto err; - - /* We might have missed events during setup, so check again. */ -+ if (settling) -+ ssam_tablet_sw_schedule_delayed_updates(sw, SSAM_KIP_UPDATE_COUNT); - schedule_work(&sw->update_work); - return 0; - - err: - ssam_device_notifier_unregister(sdev, &sw->notif); -+ atomic_set(&sw->delayed_update_count, 0); - cancel_delayed_work_sync(&sw->delayed_update_work); - cancel_work_sync(&sw->update_work); - return status; -@@ -225,6 +262,7 @@ static void ssam_tablet_sw_remove(struct ssam_device *sdev) - sysfs_remove_group(&sdev->dev.kobj, &ssam_tablet_sw_group); - - ssam_device_notifier_unregister(sdev, &sw->notif); -+ atomic_set(&sw->delayed_update_count, 0); - cancel_delayed_work_sync(&sw->delayed_update_work); - cancel_work_sync(&sw->update_work); - } -@@ -310,6 +348,11 @@ static int ssam_kip_get_cover_state(struct ssam_tablet_sw *sw, struct ssam_table - return status; - } - -+ if (raw < SSAM_KIP_COVER_STATE_DISCONNECTED || raw > SSAM_KIP_COVER_STATE_BOOK) { -+ dev_dbg(&sw->sdev->dev, "KIP cover state not ready: %u\n", raw); -+ return -EAGAIN; -+ } -+ - state->source = 0; /* Unused for KIP switch. */ - state->state = raw; - return 0; -@@ -331,12 +374,11 @@ static u32 ssam_kip_sw_notif(struct ssam_event_notifier *nf, const struct ssam_e - case SSAM_EVENT_KIP_CID_CONNECTION_CHANGED: - /* - * Cover-state notifications can be lost while the KIP devices are -- * being re-enumerated. Re-query once the controller and devices have -- * had time to settle so that the input switch cannot remain stale. -- * The subsystem hub remains the primary handler for this event. -+ * being re-enumerated. Re-query for a bounded period while the -+ * controller and devices settle so that the input switch cannot remain -+ * stale. The subsystem hub remains the primary handler for this event. - */ -- mod_delayed_work(system_wq, &sw->delayed_update_work, -- msecs_to_jiffies(2000)); -+ ssam_tablet_sw_schedule_delayed_updates(sw, SSAM_KIP_UPDATE_COUNT); - return 0; - - default: diff --git a/kernel/2133-power-supply-qcom_battmgr-preserve-charge-limits.patch b/kernel/2133-power-supply-qcom_battmgr-preserve-charge-limits.patch deleted file mode 100644 index a285c78..0000000 --- a/kernel/2133-power-supply-qcom_battmgr-preserve-charge-limits.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Fri, 24 Jul 2026 18:27:54 -0400 -Subject: [PATCH] power: supply: qcom_battmgr: preserve charge limits - -Charge-control setters currently report success even when the PMIC -GLINK request fails. Return the request status and keep threshold -calculation and cache updates under the request lock. - -The remote battery-manager service can also lose its active -charge-control state across a restart while the driver retains the -requested thresholds. Reapply that cached window after notification -registration when the service comes back. - -Signed-off-by: Brandon Williams ---- - drivers/power/supply/qcom_battmgr.c | 38 +++++++++++++++++++++++------ - 1 file changed, 31 insertions(+), 7 deletions(-) - -diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c -index 91cf39b0083a..e84633278943 100644 ---- a/drivers/power/supply/qcom_battmgr.c -+++ b/drivers/power/supply/qcom_battmgr.c -@@ -681,6 +681,8 @@ static int qcom_battmgr_set_charge_start_threshold(struct qcom_battmgr *battmgr, - - start_soc = clamp(start_soc, CHARGE_CTRL_START_THR_MIN, CHARGE_CTRL_START_THR_MAX); - -+ mutex_lock(&battmgr->lock); -+ - /* - * If the new start threshold is larger than the old end threshold, - * move the end threshold one step (DELTA_SOC) after the new start -@@ -696,15 +698,14 @@ static int qcom_battmgr_set_charge_start_threshold(struct qcom_battmgr *battmgr, - delta_soc = battmgr->info.charge_ctrl_end - start_soc; - } - -- mutex_lock(&battmgr->lock); - ret = qcom_battmgr_set_charge_control(battmgr, target_soc, delta_soc); -- mutex_unlock(&battmgr->lock); - if (!ret) { - battmgr->info.charge_ctrl_start = start_soc; - battmgr->info.charge_ctrl_end = target_soc; - } -+ mutex_unlock(&battmgr->lock); - -- return 0; -+ return ret; - } - - static int qcom_battmgr_set_charge_end_threshold(struct qcom_battmgr *battmgr, int end_soc) -@@ -714,18 +715,19 @@ static int qcom_battmgr_set_charge_end_threshold(struct qcom_battmgr *battmgr, i - - end_soc = clamp(end_soc, CHARGE_CTRL_END_THR_MIN, CHARGE_CTRL_END_THR_MAX); - -+ mutex_lock(&battmgr->lock); -+ - if (battmgr->info.charge_ctrl_start && end_soc > battmgr->info.charge_ctrl_start) - delta_soc = end_soc - battmgr->info.charge_ctrl_start; - -- mutex_lock(&battmgr->lock); - ret = qcom_battmgr_set_charge_control(battmgr, end_soc, delta_soc); -- mutex_unlock(&battmgr->lock); - if (!ret) { - battmgr->info.charge_ctrl_start = end_soc - delta_soc; - battmgr->info.charge_ctrl_end = end_soc; - } -+ mutex_unlock(&battmgr->lock); - -- return 0; -+ return ret; - } - - static int qcom_battmgr_charge_control_thresholds_init(struct qcom_battmgr *battmgr) -@@ -1594,9 +1596,31 @@ static void qcom_battmgr_enable_worker(struct work_struct *work) - }; - int ret; - -+ mutex_lock(&battmgr->lock); - ret = qcom_battmgr_request(battmgr, &req, sizeof(req)); -- if (ret) -+ if (ret) { - dev_err(battmgr->dev, "failed to request power notifications\n"); -+ goto out_unlock; -+ } -+ -+ /* -+ * The remote service can lose its charge-control state across a -+ * restart, while the thresholds cached in this driver remain valid. -+ */ -+ if (battmgr->info.charge_ctrl_end) { -+ u32 delta_soc = battmgr->info.charge_ctrl_end - -+ battmgr->info.charge_ctrl_start; -+ -+ ret = qcom_battmgr_set_charge_control(battmgr, -+ battmgr->info.charge_ctrl_end, -+ delta_soc); -+ if (ret) -+ dev_err(battmgr->dev, -+ "failed to restore battery charge thresholds\n"); -+ } -+ -+out_unlock: -+ mutex_unlock(&battmgr->lock); - } - - static void qcom_battmgr_pdr_notify(void *priv, int state) diff --git a/kernel/2134-media-ov13858-retry-the-first-SCCB-write-after-power.patch b/kernel/2134-media-ov13858-retry-the-first-SCCB-write-after-power.patch deleted file mode 100644 index 4dcd7e3..0000000 --- a/kernel/2134-media-ov13858-retry-the-first-SCCB-write-after-power.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 25 Jul 2026 10:52:59 -0400 -Subject: [PATCH] media: ov13858: retry the first SCCB write after power-up - -On the Surface Pro 11 (X1E80100, Denali) the rear OV13858 intermittently -fails to start streaming. The first SCCB transaction after the sensor -powers up returns -EIO, preceded by a CCI queue timeout: - - i2c-qcom-cci ac15000.cci: master 1 queue 0 timeout - ov13858 3-0010: ov13858_start_streaming failed to set powerup registers - -The failure only occurs when another camera on the same SoC was active -shortly beforehand, and never when the rear sensor is used on its own. -Measured over 120 rear opens with the sensor exercised immediately after -a front or IR session, it reproduces on 26% of opens. - -The condition is transient and has already cleared by the time the -failed transfer returns. Retrying this one write is sufficient: - - no retry 31 capture failures / 120 opens 0.26 - one retry 0 capture failures / 100 opens 0.00 - -with 39 retries observed to succeed on the second attempt across those -100 opens. A zero delay before the retry is enough; adding 1 ms or 20 ms -made no difference. - -Enlarging the power-up timing does not help, which rules out a settle -time problem: separately varying the post-regulator settle (1 ms to -20 ms), the reset-release-to-SCCB delay (10 ms to 50 ms), the power-off -reset hold (1 ms to 20 ms) and a forced minimum off time (0 to 50 ms) -all left the rate inside the 0.20-0.45 noise band. - -Scope the retry to the software reset register only. It is the first -transaction after power-up, the only one observed to fail, and it is -idempotent. Later writes in the sequence are not, and are left alone. - -Why the first transaction errors when another camera is powered is not -yet explained; this makes the sensor tolerate it. - -Co-authored-by: Claude Opus 5 (1M context) -Signed-off-by: Brandon Williams ---- - drivers/media/i2c/ov13858.c | 24 +++++++++++++++++++++++- - 1 file changed, 23 insertions(+), 1 deletion(-) - -diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c -index 09d58e8b1c7f..b324d9a27fc5 100644 ---- a/drivers/media/i2c/ov13858.c -+++ b/drivers/media/i2c/ov13858.c -@@ -1413,9 +1413,31 @@ static int ov13858_start_streaming(struct ov13858 *ov13858) - const struct ov13858_reg_list *reg_list; - int ret, link_freq_index; - -- /* Get out of from software reset */ -+ /* -+ * Get out of from software reset. -+ * -+ * The first SCCB transaction after the sensor powers up can fail when -+ * another camera on the same SoC is powered at the same time: the CCI -+ * master logs a queue timeout and the transfer returns -EIO. The -+ * condition is transient and clears by the time the failed transfer -+ * returns, so retry once. -+ * -+ * Scoped deliberately to this one register. It is the first -+ * transaction after power-up and the only one observed to fail, and -+ * the write is idempotent -- it asserts the sensor's software reset, -+ * which is already the state it is in. Later writes in this sequence -+ * are not idempotent and must not be retried blindly. -+ */ - ret = ov13858_write_reg(ov13858, OV13858_REG_SOFTWARE_RST, - OV13858_REG_VALUE_08BIT, OV13858_SOFTWARE_RST); -+ if (ret) { -+ dev_dbg(ov13858->dev, -+ "software reset write failed (%d), retrying once\n", -+ ret); -+ ret = ov13858_write_reg(ov13858, OV13858_REG_SOFTWARE_RST, -+ OV13858_REG_VALUE_08BIT, -+ OV13858_SOFTWARE_RST); -+ } - if (ret) { - dev_err(ov13858->dev, "%s failed to set powerup registers\n", - __func__); diff --git a/kernel/2135-drm-msm-dp-restrict-the-EDID-read-workaround-to-EDID.patch b/kernel/2135-drm-msm-dp-restrict-the-EDID-read-workaround-to-EDID.patch deleted file mode 100644 index a0c032d..0000000 --- a/kernel/2135-drm-msm-dp-restrict-the-EDID-read-workaround-to-EDID.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 25 Jul 2026 15:20:46 -0400 -Subject: [PATCH] drm/msm/dp: restrict the EDID read workaround to EDID - addresses - -msm_dp_aux_transfer_helper() exists to work around sinks that mishandle -the I2C middle-of-transaction flag during EDID reads. It tracks a read -offset within a 128-byte EDID block and periodically writes that offset -back to the sink so the read pointer stays correct. - -It never checks the target address, so it runs for every I2C-over-AUX -read with MOT set, not just EDID reads. For any other target the offset -accumulates on unrelated traffic and is then injected as a one-byte -write to that target ahead of the read, desynchronising the transfer. - -DDC/CI at 0x37 is the visible casualty. On a Surface Pro 11 (X1E80100) -with an external DisplayPort monitor, EDID reads at 0x50 are correct and -repeatable while every read from 0x37 returns different garbage, so -brightness control via ddcutil cannot work. The sink is fine; the same -monitor works on other hosts. - -Restrict the workaround to the EDID and segment addresses, matching the -guard msm_dp_aux_update_offset_and_segment() already applies. - -Signed-off-by: Brandon Williams ---- - drivers/gpu/drm/msm/dp/dp_aux.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c -index 3825a2fb48e2..914c1f159267 100644 ---- a/drivers/gpu/drm/msm/dp/dp_aux.c -+++ b/drivers/gpu/drm/msm/dp/dp_aux.c -@@ -279,6 +279,7 @@ static void msm_dp_aux_transfer_helper(struct msm_dp_aux_private *aux, - { - struct drm_dp_aux_msg helper_msg; - u32 message_size = 0x10; -+ u32 edid_address = 0x50; - u32 segment_address = 0x30; - u32 const edid_block_length = 0x80; - bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT; -@@ -288,6 +289,22 @@ static void msm_dp_aux_transfer_helper(struct msm_dp_aux_private *aux, - if (!i2c_mot || !i2c_read || (input_msg->size == 0)) - return; - -+ /* -+ * This workaround is specific to EDID reads, and the offset it tracks -+ * is only meaningful within an EDID block. Applying it to any other -+ * I2C-over-AUX target corrupts that target's transactions: the offset -+ * accumulates on unrelated traffic and is then written back to the -+ * device as if it were an EDID read pointer. -+ * -+ * DDC/CI at 0x37 is the common casualty. Its replies come back as -+ * garbage because a stale offset byte is injected ahead of the read, -+ * which is why brightness control over DisplayPort does not work while -+ * EDID reads at 0x50 succeed. -+ */ -+ if (input_msg->address != edid_address && -+ input_msg->address != segment_address) -+ return; -+ - /* - * Sending the segment value and EDID offset will be performed - * from the DRM upstream EDID driver for each block. Avoid diff --git a/kernel/2136-drm-msm-dp-attach-the-AUX-i2c-adapter-to-the-connect.patch b/kernel/2136-drm-msm-dp-attach-the-AUX-i2c-adapter-to-the-connect.patch deleted file mode 100644 index 06e48f0..0000000 --- a/kernel/2136-drm-msm-dp-attach-the-AUX-i2c-adapter-to-the-connect.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 25 Jul 2026 16:06:09 -0400 -Subject: [PATCH] drm/msm/dp: attach the AUX i2c adapter to the connector - -drm_dp_aux_register() already creates an i2c adapter for DDC traffic over -the AUX channel, and drm_bridge_connector_init() will attach whatever a -bridge advertises in drm_bridge.ddc to the connector it creates. The DP -bridge never sets that field, so the connector ends up with no ddc link -in sysfs. - -Userspace uses that link to work out which /dev/i2c-N belongs to which -display. Without it, tools that drive DDC/CI have no way to associate a -bus with a monitor. ddcutil reports "No display adapters with i2c buses -appear to exist" and refuses to run, on a machine where the bus is -present and DDC/CI works when addressed directly. - -Publish the adapter so the association is visible. The adapter is -created during component bind, well before modesetting init reaches -msm_dp_bridge_init(), so it is safe to reference here. - -This is set for eDP as well as DP, since the association is equally -accurate there. Internal panels generally NAK DDC/CI, so a probing tool -will simply find nothing on that bus. - -Signed-off-by: Brandon Williams ---- - drivers/gpu/drm/msm/dp/dp_display.c | 3 ++- - drivers/gpu/drm/msm/dp/dp_drm.c | 16 +++++++++++++++- - drivers/gpu/drm/msm/dp/dp_drm.h | 3 ++- - 3 files changed, 19 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c -index 22eade11c615..ba208f753cc7 100644 ---- a/drivers/gpu/drm/msm/dp/dp_display.c -+++ b/drivers/gpu/drm/msm/dp/dp_display.c -@@ -1330,7 +1330,8 @@ int msm_dp_modeset_init(struct msm_dp *msm_dp_display, struct drm_device *dev, - - msm_dp_priv = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - -- ret = msm_dp_bridge_init(msm_dp_display, dev, encoder, yuv_supported); -+ ret = msm_dp_bridge_init(msm_dp_display, dev, encoder, yuv_supported, -+ msm_dp_priv->aux); - if (ret) { - DRM_DEV_ERROR(dev->dev, - "failed to create dp bridge: %d\n", ret); -diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c -index b659d22f5f28..1e1d30de9d71 100644 ---- a/drivers/gpu/drm/msm/dp/dp_drm.c -+++ b/drivers/gpu/drm/msm/dp/dp_drm.c -@@ -243,7 +243,8 @@ static const struct drm_bridge_funcs msm_edp_bridge_ops = { - }; - - int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, -- struct drm_encoder *encoder, bool yuv_supported) -+ struct drm_encoder *encoder, bool yuv_supported, -+ struct drm_dp_aux *aux) - { - int rc; - struct msm_dp_bridge *msm_dp_bridge; -@@ -261,6 +262,19 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, - bridge->type = msm_dp_display->connector_type; - bridge->ycbcr_420_allowed = yuv_supported; - -+ /* -+ * Publish the AUX I2C adapter so drm_bridge_connector_init() attaches -+ * it to the connector. Without this the connector has no ddc link in -+ * sysfs, and userspace cannot tell which /dev/i2c-N belongs to which -+ * display. Tools that drive DDC/CI, such as ddcutil, then report that -+ * no display adapter with an i2c bus exists and refuse to run, even -+ * though the bus is present and works. -+ * -+ * The adapter is created by drm_dp_aux_register(), which runs from the -+ * component bind long before modesetting init reaches this point. -+ */ -+ bridge->ddc = &aux->ddc; -+ - /* - * Many ops only make sense for DP. Why? - * - Detect/HPD are used by DRM to know if a display is _physically_ -diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h -index 041aa026ae2e..d48c85a948f5 100644 ---- a/drivers/gpu/drm/msm/dp/dp_drm.h -+++ b/drivers/gpu/drm/msm/dp/dp_drm.h -@@ -23,7 +23,8 @@ struct drm_connector *msm_dp_drm_connector_init(struct msm_dp *msm_dp_display, - struct drm_encoder *encoder); - int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, - struct drm_encoder *encoder, -- bool yuv_supported); -+ bool yuv_supported, -+ struct drm_dp_aux *aux); - - enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge, - struct drm_connector *connector); diff --git a/kernel/2137-irqchip-qcom-pdc-report-the-selected-X1E-mode.patch b/kernel/2137-irqchip-qcom-pdc-report-the-selected-X1E-mode.patch deleted file mode 100644 index cce7555..0000000 --- a/kernel/2137-irqchip-qcom-pdc-report-the-selected-X1E-mode.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 26 Jul 2026 06:36:54 -0400 -Subject: [PATCH] irqchip: qcom-pdc: report the selected X1E mode - -The X1E PDC v4 backport either selects pass-through mode through SCM or -falls back to supporting firmware-configured secondary-controller mode. -Report which path the retail Surface firmware takes so suspend results -can be interpreted. - -Signed-off-by: Brandon Williams ---- - drivers/irqchip/qcom-pdc.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c -index ce6d80c7f17a..97835e1542e7 100644 ---- a/drivers/irqchip/qcom-pdc.c -+++ b/drivers/irqchip/qcom-pdc.c -@@ -724,6 +724,11 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare - pdc->mode = PDC_SECONDARY_MODE; - pdc->unmask_gpio = pdc_unmask_gpio_cfg; - pdc->clear_gpio = pdc_clear_gpio_cfg; -+ dev_warn(dev, -+ "SCM could not select PDC pass-through mode (%d); using secondary-controller mode\n", -+ ret); -+ } else { -+ dev_info(dev, "PDC pass-through mode selected through SCM\n"); - } - } - diff --git a/kernel/2138-soc-qcom-smp2p-reset-inbound-state-only-on-restart.patch b/kernel/2138-soc-qcom-smp2p-reset-inbound-state-only-on-restart.patch deleted file mode 100644 index c6e9110..0000000 --- a/kernel/2138-soc-qcom-smp2p-reset-inbound-state-only-on-restart.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 26 Jul 2026 08:21:43 -0400 -Subject: [PATCH] soc: qcom: smp2p: reset inbound state only on restart - -SMP2P v2 needs cached inbound values reset when an SSR is detected -because the remote no longer waits for the acknowledgement before -setting its state. The current code performs that reset for every -inbound notification instead. - -With persistent ready and handover bits, unrelated ADSP notifications -are therefore reported as fresh rising edges. This repeatedly invokes -the q6v5 handlers and can keep the AP awake. - -Return early when the restart flag has not changed so the cached values -are preserved for ordinary notifications. - -Fixes: 42c4cf5d4828 ("soc: qcom: smp2p: Add support for smp2p v2") -Signed-off-by: Brandon Williams ---- - drivers/soc/qcom/smp2p.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c -index af0ceeaf6e07..89e242f4d0ca 100644 ---- a/drivers/soc/qcom/smp2p.c -+++ b/drivers/soc/qcom/smp2p.c -@@ -194,13 +194,16 @@ static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) - - restart_done = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT); - restart = restart_done != smp2p->ssr_ack; -+ if (!restart) -+ return false; -+ - list_for_each_entry(entry, &smp2p->inbound, node) { - if (!entry->value) - continue; - entry->last_value = 0; - } - -- return restart; -+ return true; - } - - static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p) diff --git a/kernel/2139-arm64-dts-qcom-x1e80100-drop-QCE-sleep-bandwidth-vot.patch b/kernel/2139-arm64-dts-qcom-x1e80100-drop-QCE-sleep-bandwidth-vot.patch deleted file mode 100644 index 690eadf..0000000 --- a/kernel/2139-arm64-dts-qcom-x1e80100-drop-QCE-sleep-bandwidth-vot.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 26 Jul 2026 10:35:25 -0400 -Subject: [PATCH] arm64: dts: qcom: x1e80100: drop QCE sleep bandwidth vote - -The QCE driver installs a constant 393600 kB/s memory interconnect vote -at probe time. The X1E80100 device tree tags that path for active, wake -and sleep buckets, so the vote remains in the RPMh sleep batch after QCE -and the rest of the devices have suspended. - -QCE cannot issue transactions after APSS enters suspend. Tag its memory -path active-only so the normal and wake constraints are preserved while -the sleep bucket can fall to zero. - -Signed-off-by: Brandon Williams ---- - arch/arm64/boot/dts/qcom/hamoa.dtsi | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi -index 20939c9d69e6..5d7b80ae57c4 100644 ---- a/arch/arm64/boot/dts/qcom/hamoa.dtsi -+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi -@@ -4026,8 +4026,8 @@ crypto: crypto@1dfa000 { - "tx"; - iommus = <&apps_smmu 0x480 0x0>, - <&apps_smmu 0x481 0x0>; -- interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS -- &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; -+ interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ACTIVE_ONLY -+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; - interconnect-names = "memory"; - }; - diff --git a/kernel/2140-platform-surface-aggregator_registry-add-KIP-OOB-pai.patch b/kernel/2140-platform-surface-aggregator_registry-add-KIP-OOB-pai.patch deleted file mode 100644 index e9717f2..0000000 --- a/kernel/2140-platform-surface-aggregator_registry-add-KIP-OOB-pai.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 29 Aug 2026 18:47:25 -0400 -Subject: [PATCH] platform/surface: aggregator_registry: add KIP OOB pairing - node for SP11 - -The Surface Pro 11 Flex Keyboard exposes a Bluetooth out-of-band pairing -channel on KIP HID instance 9 (PID 0C8F). It carries the Microsoft -"Bluetooth OOB Coupling" HID collection (vendor usage page 0xFFF4), which -a host uses to hand the keyboard its Bluetooth address and a pairing key -over the wired connector, so the keyboard can subsequently be used -detached over Bluetooth. - -The instance was not registered, so the device never appeared and there -was no way to pair the keyboard for detached use except by importing a -bond created by another operating system. - -Register it for the SP11 node group. - -Co-Authored-By: Claude Opus 5 (1M context) -Signed-off-by: Brandon Williams ---- - .../platform/surface/surface_aggregator_registry.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index d37a7e4c6b02..2192e4e6389a 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -215,6 +215,17 @@ static const struct software_node ssam_node_hid_kip_fwupd = { - .parent = &ssam_node_hub_kip, - }; - -+/* HID device instance 9 (KIP hub, Bluetooth OOB pairing channel). -+ * -+ * Exposes the Microsoft "Bluetooth OOB Coupling" collection (HID usage page -+ * 0xFFF4) used to hand the host's Bluetooth address and a pairing key to a -+ * detachable keyboard over the wired link, so it can then be used detached. -+ */ -+static const struct software_node ssam_node_hid_kip_oobpair = { -+ .name = "ssam:01:15:02:09:00", -+ .parent = &ssam_node_hub_kip, -+}; -+ - /* Tablet-mode switch via POS subsystem. */ - static const struct software_node ssam_node_pos_tablet_switch = { - .name = "ssam:01:26:01:00:01", -@@ -415,6 +426,7 @@ static const struct software_node *ssam_node_group_sp11[] = { - &ssam_node_hid_kip_penstash, - &ssam_node_hid_kip_touchpad, - &ssam_node_hid_kip_fwupd, -+ &ssam_node_hid_kip_oobpair, - &ssam_node_hid_sam_sensors, - &ssam_node_kip_tablet_switch, - NULL, diff --git a/kernel/2141-Bluetooth-SMP-implement-LE-legacy-out-of-band-pairin.patch b/kernel/2141-Bluetooth-SMP-implement-LE-legacy-out-of-band-pairin.patch deleted file mode 100644 index 5f161ec..0000000 --- a/kernel/2141-Bluetooth-SMP-implement-LE-legacy-out-of-band-pairin.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 29 Aug 2026 18:47:25 -0400 -Subject: [PATCH] Bluetooth: SMP: implement LE legacy out-of-band pairing - -LE legacy pairing can authenticate with a 128-bit TK supplied out of -band, but only the Secure Connections OOB path was implemented. The -entire OOB block in build_pairing_cmd() sits inside the SMP_FLAG_SC -branch, so a legacy pairing never advertised OOB data, and tk_request() -had no REQ_OOB case at all -- its remote_oob argument was passed a -hardcoded zero by all three callers. - -mgmt already reserved the P-192 fields for this, rejecting non-zero -values for LE addresses with the comment "as long as legacy SMP OOB -isn't implemented". Carry the TK in the P-192 random field: unlike an -SC OOB pair, a legacy TK is a bare value with no confirm, so allow a -rand192 with no hash192 and mark such data present as P-192 only. - -Select REQ_OOB when both sides signal OOB and a TK is held for the peer, -and record the resulting keys as authenticated, since out-of-band -authentication provides MITM protection. - -Finally, do not request Secure Connections when the only out-of-band -data held for a peer is a legacy TK. The TK cannot authenticate an SC -pairing, so requesting SC would leave it unused and fall back to an -association model the peer may refuse -- a real case for keyboards that -report DisplayOnly and require MITM, where no passkey model is possible. - -This makes the Surface Pro 11 Flex Keyboard pair for detached Bluetooth -use without keys imported from another operating system. - -Co-Authored-By: Claude Opus 5 (1M context) -Signed-off-by: Brandon Williams ---- - net/bluetooth/hci_core.c | 12 +++-- - net/bluetooth/mgmt.c | 14 +++--- - net/bluetooth/smp.c | 96 ++++++++++++++++++++++++++++++++++++++-- - 3 files changed, 111 insertions(+), 11 deletions(-) - -diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c -index aea017ee5b0a..75b33d95a362 100644 ---- a/net/bluetooth/hci_core.c -+++ b/net/bluetooth/hci_core.c -@@ -1526,8 +1526,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, - list_add(&data->list, &hdev->remote_oob_data); - } - -- if (hash192 && rand192) { -- memcpy(data->hash192, hash192, sizeof(data->hash192)); -+ if (rand192) { -+ /* An LE legacy OOB TK is a bare 128-bit value: it has no -+ * confirm, so hash192 may legitimately be absent. -+ */ -+ if (hash192) -+ memcpy(data->hash192, hash192, sizeof(data->hash192)); -+ else -+ memset(data->hash192, 0, sizeof(data->hash192)); - memcpy(data->rand192, rand192, sizeof(data->rand192)); - if (hash256 && rand256) - data->present = 0x03; -@@ -1546,7 +1552,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, - } else { - memset(data->hash256, 0, sizeof(data->hash256)); - memset(data->rand256, 0, sizeof(data->rand256)); -- if (hash192 && rand192) -+ if (rand192) - data->present = 0x01; - } - -diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c -index deced8a5bc2d..1de5d77aa7fb 100644 ---- a/net/bluetooth/mgmt.c -+++ b/net/bluetooth/mgmt.c -@@ -5918,11 +5918,12 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, - u8 status; - - if (bdaddr_type_is_le(cp->addr.type)) { -- /* Enforce zero-valued 192-bit parameters as -- * long as legacy SMP OOB isn't implemented. -+ /* LE legacy SMP OOB authenticates with a single -+ * 128-bit TK, which has no confirm value. Carry it in -+ * the P-192 random field and require the unused P-192 -+ * hash to stay zero. - */ -- if (memcmp(cp->rand192, ZERO_KEY, 16) || -- memcmp(cp->hash192, ZERO_KEY, 16)) { -+ if (memcmp(cp->hash192, ZERO_KEY, 16)) { - err = mgmt_cmd_complete(sk, hdev->id, - MGMT_OP_ADD_REMOTE_OOB_DATA, - MGMT_STATUS_INVALID_PARAMS, -@@ -5930,8 +5931,11 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev, - goto unlock; - } - -- rand192 = NULL; - hash192 = NULL; -+ if (memcmp(cp->rand192, ZERO_KEY, 16)) -+ rand192 = cp->rand192; -+ else -+ rand192 = NULL; - } else { - /* In case one of the P-192 values is set to zero, - * then just disable OOB data for P-192. -diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c -index 853d02d4f07f..ce0c7427728f 100644 ---- a/net/bluetooth/smp.c -+++ b/net/bluetooth/smp.c -@@ -646,6 +646,29 @@ static void build_pairing_cmd(struct l2cap_conn *conn, - if (hci_dev_test_flag(hdev, HCI_PRIVACY)) - local_dist |= SMP_DIST_ID_KEY; - -+ /* A legacy OOB TK can only authenticate a legacy pairing. When that is -+ * the only out of band data held for this peer, do not ask for Secure -+ * Connections: the TK would go unused and pairing would fall back to an -+ * association model the peer may refuse. -+ */ -+ if (authreq & SMP_AUTH_SC) { -+ struct oob_data *oob_legacy; -+ u8 legacy_type; -+ -+ if (hcon->dst_type == ADDR_LE_DEV_PUBLIC) -+ legacy_type = BDADDR_LE_PUBLIC; -+ else -+ legacy_type = BDADDR_LE_RANDOM; -+ -+ mutex_lock(&hdev->remote_oob_lock); -+ oob_legacy = hci_find_remote_oob_data(hdev, &hcon->dst, -+ legacy_type); -+ if (oob_legacy && (oob_legacy->present & 0x01) && -+ !(oob_legacy->present & 0x02)) -+ authreq &= ~SMP_AUTH_SC; -+ mutex_unlock(&hdev->remote_oob_lock); -+ } -+ - if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) && - (authreq & SMP_AUTH_SC)) { - struct oob_data *oob_data; -@@ -675,7 +698,30 @@ static void build_pairing_cmd(struct l2cap_conn *conn, - mutex_unlock(&hdev->remote_oob_lock); - - } else { -+ struct oob_data *oob_data; -+ u8 bdaddr_type; -+ - authreq &= ~SMP_AUTH_SC; -+ -+ /* LE legacy pairing can also authenticate out of band, using a -+ * single 128-bit TK rather than the Secure Connections -+ * random/confirm pair. Carry that TK in the P-192 random field, -+ * which mgmt has always reserved for this purpose. -+ */ -+ if (hcon->dst_type == ADDR_LE_DEV_PUBLIC) -+ bdaddr_type = BDADDR_LE_PUBLIC; -+ else -+ bdaddr_type = BDADDR_LE_RANDOM; -+ -+ mutex_lock(&hdev->remote_oob_lock); -+ oob_data = hci_find_remote_oob_data(hdev, &hcon->dst, -+ bdaddr_type); -+ if (oob_data && (oob_data->present & 0x01)) { -+ set_bit(SMP_FLAG_REMOTE_OOB, &smp->flags); -+ oob_flag = SMP_OOB_PRESENT; -+ SMP_DBG("OOB legacy TK available"); -+ } -+ mutex_unlock(&hdev->remote_oob_lock); - } - - if (rsp == NULL) { -@@ -842,6 +888,47 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, - bt_dev_dbg(hcon->hdev, "auth:%u lcl:%u rem:%u", auth, local_io, - remote_io); - -+ /* LE legacy out of band: used only when both sides hold the same TK, -+ * per the spec. The Secure Connections OOB path is handled elsewhere. -+ */ -+ if (!test_bit(SMP_FLAG_SC, &smp->flags) && -+ remote_oob == SMP_OOB_PRESENT && -+ test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) { -+ struct hci_dev *hdev = hcon->hdev; -+ struct oob_data *oob_data; -+ bool have_tk = false; -+ u8 bdaddr_type; -+ -+ if (hcon->dst_type == ADDR_LE_DEV_PUBLIC) -+ bdaddr_type = BDADDR_LE_PUBLIC; -+ else -+ bdaddr_type = BDADDR_LE_RANDOM; -+ -+ mutex_lock(&hdev->remote_oob_lock); -+ oob_data = hci_find_remote_oob_data(hdev, &hcon->dst, -+ bdaddr_type); -+ if (oob_data && (oob_data->present & 0x01)) { -+ memcpy(smp->tk, oob_data->rand192, sizeof(smp->tk)); -+ have_tk = true; -+ } -+ mutex_unlock(&hdev->remote_oob_lock); -+ -+ if (have_tk) { -+ smp->method = REQ_OOB; -+ set_bit(SMP_FLAG_TK_VALID, &smp->flags); -+ -+ /* Out of band authentication gives MITM protection, -+ * so the resulting keys are authenticated. -+ */ -+ set_bit(SMP_FLAG_MITM_AUTH, &smp->flags); -+ if (hcon->pending_sec_level < BT_SECURITY_HIGH) -+ hcon->pending_sec_level = BT_SECURITY_HIGH; -+ -+ SMP_DBG("Using OOB TK for LE legacy pairing"); -+ return 0; -+ } -+ } -+ - /* If neither side wants MITM, either "just" confirm an incoming - * request or use just-works for outgoing ones. The JUST_CFM - * will be converted to JUST_WORKS if necessary later in this -@@ -1836,7 +1923,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) - } - - /* Request setup of TK */ -- ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability); -+ ret = tk_request(conn, req->oob_flag, auth, rsp.io_capability, -+ req->io_capability); - if (ret) - return SMP_UNSPECIFIED; - -@@ -1983,7 +2071,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) - - auth |= req->auth_req; - -- ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability); -+ ret = tk_request(conn, rsp->oob_flag, auth, req->io_capability, -+ rsp->io_capability); - if (ret) - return SMP_UNSPECIFIED; - -@@ -2045,7 +2134,8 @@ static int fixup_sc_false_positive(struct smp_chan *smp) - - auth = req->auth_req & AUTH_REQ_MASK(hdev); - -- if (tk_request(conn, 0, auth, rsp->io_capability, req->io_capability)) { -+ if (tk_request(conn, req->oob_flag, auth, rsp->io_capability, -+ req->io_capability)) { - bt_dev_err(hdev, "failed to fall back to legacy SMP"); - return SMP_UNSPECIFIED; - } diff --git a/kernel/2142-drm-msm-dpu-re-program-colour-processing-blocks-on-t.patch b/kernel/2142-drm-msm-dpu-re-program-colour-processing-blocks-on-t.patch deleted file mode 100644 index 8c8fa71..0000000 --- a/kernel/2142-drm-msm-dpu-re-program-colour-processing-blocks-on-t.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 29 Aug 2026 20:44:12 -0400 -Subject: [PATCH] drm/msm/dpu: re-program colour-processing blocks on the - commit after a modeset - -On a modeset (resume, DPMS on, mode change) _dpu_crtc_setup_cp_blocks() -programs the DSPP before the first flush has activated it. The plain -register writes (GC_EN, LUT_SWAP, PCC) stick, but the writes into the -SRAM-backed GC LUT through the index/data ports are lost. The result on -a dual-LM panel with a GAMMA_LUT user (Hyprland + wlsunset) is gamma -enabled over uninitialised SRAM: a random colour tint / artifacts on one -half of the panel after every resume or DPMS off/on, cleared by any later -colour-management commit. - -Register evidence on x1e80100 (DPU 9.2) eDP-1: bad vs good dumps of -dri/0/kms are identical except the GC block at dspp+0x17c0, where GC_EN=1 -and the LUT data ports return garbage. - -Remember that the CP blocks were programmed during a modeset and repeat -the programming on the next commit, once the pipeline is running. -Verified on Surface Pro 11: DPMS off/on 10/10 clean, previously defective -every cycle. - -Signed-off-by: Brandon Williams -Co-Authored-By: Claude Fable 5 ---- - drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 15 ++++++++++++++- - drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 7 +++++++ - 2 files changed, 21 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c -index 42d0a529b4d5..3d1c138bfde8 100644 ---- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c -+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c -@@ -853,12 +853,24 @@ static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) - struct dpu_hw_gc_lut *gc_lut; - struct dpu_hw_ctl *ctl; - struct dpu_hw_dspp *dspp; -+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); -+ bool modeset = drm_atomic_crtc_needs_modeset(state); - int i; - - -- if (!state->color_mgmt_changed && !drm_atomic_crtc_needs_modeset(state)) -+ if (!state->color_mgmt_changed && !modeset && -+ !dpu_crtc->cp_reprogram_pending) - return; - -+ /* -+ * During a modeset the DSPP is programmed before the first flush -+ * activates it, and writes into SRAM-backed sub-blocks (the GC LUT) -+ * are lost while the enable bit sticks -- leaving the block enabled -+ * over uninitialised SRAM. Repeat the programming on the next commit, -+ * once the pipeline is running. -+ */ -+ dpu_crtc->cp_reprogram_pending = modeset; -+ - for (i = 0; i < cstate->num_mixers; i++) { - ctl = mixer[i].lm_ctl; - dspp = mixer[i].hw_dspp; -@@ -1240,6 +1252,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, - atomic_read(&dpu_crtc->frame_pending)); - - trace_dpu_crtc_disable(DRMID(crtc), false, dpu_crtc); -+ dpu_crtc->cp_reprogram_pending = false; - dpu_crtc->enabled = false; - - if (atomic_read(&dpu_crtc->frame_pending)) { -diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h -index 6eaba5696e8e..12c25bc860d3 100644 ---- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h -+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h -@@ -165,6 +165,13 @@ struct dpu_crtc { - ktime_t vblank_cb_time; - bool enabled; - -+ /* -+ * Colour-processing blocks were programmed during a modeset, before -+ * the DSPP was active; SRAM-backed sub-blocks (GC LUT) must be written -+ * again on the next commit. -+ */ -+ bool cp_reprogram_pending; -+ - struct list_head feature_list; - struct list_head active_list; - struct list_head dirty_list; diff --git a/kernel/2143-HID-surface-hid-suspend-HID-clients-on-shutdown.patch b/kernel/2143-HID-surface-hid-suspend-HID-clients-on-shutdown.patch deleted file mode 100644 index 088f4e3..0000000 --- a/kernel/2143-HID-surface-hid-suspend-HID-clients-on-shutdown.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 5 Sep 2026 15:50:36 -0400 -Subject: [PATCH] HID: surface-hid: suspend HID clients on shutdown - -Add a shutdown callback that runs the HID client's existing suspend -routine before the Surface Aggregator shuts the transport down. For the -attached Flex Keyboard touchpad this issues the same report-disable -sequence suspend uses, so shutdown no longer leaves the device in -active reporting mode. - -On the Surface Pro 11 this alone does not reliably stop the keyboard's -haptics after a battery-powered poweroff; captured traces of a success -and a failure carried identical successful commands, so the remaining -difference is on the EC/pogo power hand-off side. AC poweroff and -suspend behave correctly. The callback is still the right thing to do: -it is symmetric with suspend and costs nothing. - -Signed-off-by: Brandon Williams ---- - drivers/hid/surface-hid/surface_hid.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c -index eae47e0d95ed..5a341b2aeb01 100644 ---- a/drivers/hid/surface-hid/surface_hid.c -+++ b/drivers/hid/surface-hid/surface_hid.c -@@ -229,6 +229,18 @@ static void surface_hid_remove(struct ssam_device *sdev) - surface_hid_device_destroy(ssam_device_get_drvdata(sdev)); - } - -+static void surface_hid_shutdown(struct device *dev) -+{ -+ struct surface_hid_device *shid = dev_get_drvdata(dev); -+ int status; -+ -+ /* Put HID clients into their low-power mode before SAM shuts down. */ -+ status = hid_driver_suspend(shid->hid, PMSG_SUSPEND); -+ if (status) -+ dev_warn(dev, "failed to suspend HID device for shutdown: %d\n", -+ status); -+} -+ - static const struct ssam_device_id surface_hid_match[] = { - { SSAM_SDEV(HID, ANY, SSAM_SSH_IID_ANY, 0x00) }, - { }, -@@ -241,6 +253,7 @@ static struct ssam_device_driver surface_hid_driver = { - .match_table = surface_hid_match, - .driver = { - .name = "surface_hid", -+ .shutdown = surface_hid_shutdown, - .pm = &surface_hid_pm_ops, - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - }, diff --git a/kernel/2144-arm64-skip-the-EFI-reset-path-when-restarting-from-a.patch b/kernel/2144-arm64-skip-the-EFI-reset-path-when-restarting-from-a.patch deleted file mode 100644 index bfdb89e..0000000 --- a/kernel/2144-arm64-skip-the-EFI-reset-path-when-restarting-from-a.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Mon, 14 Sep 2026 09:43:25 -0400 -Subject: [PATCH] arm64: skip the EFI reset path when restarting from a panic - in interrupt context - -ResetSystem() runs EFI runtime services, which fault when invoked from -interrupt context (softlockup/hardlockup panic). On the Surface Pro 11 -the EFI reset from IRQ context oopses and wedges instead of rebooting. -Fall through to the PSCI restart handler in that case. Restarts from -process context, including other panics, still go through ResetSystem(). - -Co-Authored-By: Claude Fable 5.1 -Signed-off-by: Brandon Williams ---- - arch/arm64/kernel/process.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c -index 581f80e9b9b7..90651cb8144d 100644 ---- a/arch/arm64/kernel/process.c -+++ b/arch/arm64/kernel/process.c -@@ -135,9 +135,14 @@ void machine_restart(char *cmd) - - /* - * UpdateCapsule() depends on the system being reset via -- * ResetSystem(). -+ * ResetSystem(). However ResetSystem() runs EFI runtime services, -+ * which fault if invoked from interrupt context (e.g. a softlockup -+ * or hardlockup panic). There, skip the EFI reset and leave it to -+ * the PSCI restart handler, which resets cleanly from any context. -+ * (SP11/X1E80100: EFI reset from IRQ context oopses and wedges -+ * instead of rebooting.) - */ -- if (efi_enabled(EFI_RUNTIME_SERVICES)) -+ if (efi_enabled(EFI_RUNTIME_SERVICES) && !in_interrupt()) - efi_reboot(reboot_mode, NULL); - - /* Now call the architecture specific reboot code. */ diff --git a/kernel/2145-drm-msm-dpu-Reassert-core-clock-rate-on-runtime-resu.patch b/kernel/2145-drm-msm-dpu-Reassert-core-clock-rate-on-runtime-resu.patch deleted file mode 100644 index 4721c38..0000000 --- a/kernel/2145-drm-msm-dpu-Reassert-core-clock-rate-on-runtime-resu.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Xilin Wu -Date: Wed, 13 May 2026 16:59:50 +0800 -Subject: [PATCH] drm/msm/dpu: Reassert core clock rate on runtime resume - -DPU runtime suspend can drop the power-domain performance state even -though the clock framework still reports the previously programmed core -clock rate after the clocks are enabled again. In that case the DPU perf -code may not call dev_pm_opp_set_rate() before the hardware state is -restored, leaving the clock rate and the OPP required-opps vote out of -sync. - -This can make high bandwidth modes fail after system suspend/resume. On -SC8280XP, a 4k120 mode can resume with the DP link trained successfully, -but later hit CTL recovery and vblank timeouts because the MMCX -performance state was not reasserted before DPU register programming. - -Reapply the current DPU core clock rate during runtime resume, after -enabling the clocks and before restoring VBIF and encoder state. This -makes the OPP framework restore the required-opps vote without forcing a -higher clock rate than the one already selected. - -Fixes: b0530eb11913 ("drm/msm/dpu: Use OPP API to set clk/perf state") -Signed-off-by: Xilin Wu ---- - drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c -index da3556eb6ecc..23e0a5b2ca22 100644 ---- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c -+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c -@@ -1454,6 +1454,7 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) - struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); - struct drm_encoder *encoder; - struct drm_device *ddev; -+ unsigned long core_rate; - - ddev = dpu_kms->dev; - -@@ -1463,6 +1464,24 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) - return rc; - } - -+ /* -+ * Runtime suspend can drop the power-domain performance state even when -+ * the clock framework still reports the previously programmed rate. -+ * Re-assert the current core clock rate so OPP required-opps are restored -+ * before touching DPU registers. -+ */ -+ core_rate = dpu_kms_get_clk_rate(dpu_kms, "core"); -+ if (core_rate) { -+ core_rate = min_t(unsigned long, core_rate, dpu_kms->perf.max_core_clk_rate); -+ rc = dev_pm_opp_set_rate(&dpu_kms->pdev->dev, core_rate); -+ if (rc) { -+ DPU_ERROR("failed to restore core clock rate %lu: %d\n", -+ core_rate, rc); -+ return rc; -+ } -+ dpu_kms->perf.core_clk_rate = core_rate; -+ } -+ - dpu_vbif_init_memtypes(dpu_kms); - - drm_for_each_encoder(encoder, ddev) diff --git a/kernel/2146-drm-msm-dp-use-direct-SDP-flush-for-PSR.patch b/kernel/2146-drm-msm-dp-use-direct-SDP-flush-for-PSR.patch deleted file mode 100644 index daf001e..0000000 --- a/kernel/2146-drm-msm-dp-use-direct-SDP-flush-for-PSR.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lars Karlslund <8929787+lkarlslund@users.noreply.github.com> -Date: Wed, 29 Jul 2026 15:49:36 +0200 -Subject: [PATCH] drm/msm/dp: use direct SDP flush for PSR - -Newer DP controller revisions normally use the SDE peripheral-update flush -mode. With PSR, that path can report successful frame-capture, update and -exit interrupts while the sink captures a black frame. - -Select the direct UPDATE_SDP flush mode when configuring PSR. This is also -the mode already used by older DP controller revisions. - -Signed-off-by: Lars Karlslund <8929787+lkarlslund@users.noreply.github.com> ---- - drivers/gpu/drm/msm/dp/dp_ctrl.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c -index 9024abdc2c56..cd4a73269716 100644 ---- a/drivers/gpu/drm/msm/dp/dp_ctrl.c -+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c -@@ -1855,6 +1855,15 @@ void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl) - if (!ctrl->panel->psr_cap.version) - return; - -+ /* -+ * PSR SDPs must be flushed directly. The peripheral flush path can -+ * complete normally while the sink captures an invalid frame. -+ */ -+ cfg = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); -+ cfg &= ~DP_MAINLINK_CTRL_FLUSH_MODE_MASK; -+ cfg |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP; -+ msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, cfg); -+ - /* enable PSR1 function */ - cfg = msm_dp_read_link(ctrl, REG_PSR_CONFIG); - cfg |= PSR1_SUPPORTED; diff --git a/kernel/2147-ASoC-qcom-x1e80100-raise-the-speaker-volume-ceiling-.patch b/kernel/2147-ASoC-qcom-x1e80100-raise-the-speaker-volume-ceiling-.patch deleted file mode 100644 index fb8729f..0000000 --- a/kernel/2147-ASoC-qcom-x1e80100-raise-the-speaker-volume-ceiling-.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Mon, 14 Sep 2026 09:44:26 -0400 -Subject: [PATCH] ASoC: qcom: x1e80100: raise the speaker volume ceiling to 0 - dB digital / +9 dB PA - -The upstream limit of -3 dB digital and 0 dB PA (commit 0a5ee0e520ef) -leaves the Surface Pro 11 speakers at roughly half the loudness they -have under Windows. Raise the ceiling to the values the upstream UCM -sequences request (WSA macro init: Digital Volume 84; wsa884x -two-speaker SpeakerSeq: PA Volume 12), which is +12 dB over the previous -cap and still far below the hardware maximum (+40 dB digital, +37.5 dB -PA). Amplifier-side OCP/PBR/thermal protection and the 2S/4-ohm profile -are relied on for safety; UCM is what actually sets the levels. - -Only microsoft,denali-oled gets the higher ceiling. Other X1E80100 -machines keep the upstream -3 dB digital and 0 dB PA limits. - -Co-Authored-By: Claude Fable 5.1 -Signed-off-by: Brandon Williams ---- - sound/soc/qcom/x1e80100.c | 36 ++++++++++++++++++++++++++---------- - 1 file changed, 26 insertions(+), 10 deletions(-) - -diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c -index c81df41ace88..0d213f6d629f 100644 ---- a/sound/soc/qcom/x1e80100.c -+++ b/sound/soc/qcom/x1e80100.c -@@ -3,6 +3,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -30,6 +31,7 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) - struct snd_soc_card *card = rtd->card; - struct snd_soc_jack *dp_jack = NULL; - int dp_pcm_id = 0; -+ int digital_max, pa_max; - - switch (cpu_dai->id) { - case WSA_CODEC_DMA_RX_0: -@@ -38,17 +40,31 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd) - * Set limit of -3 dB on Digital Volume and 0 dB on PA Volume - * to reduce the risk of speaker damage until we have active - * speaker protection in place. -+ * -+ * The Surface Pro 11 is raised to 0 dB (84) digital and +9 dB -+ * (12) PA, the values the upstream UCM sequences for the WSA -+ * macro and the wsa884x two-speaker profile request. Upstream's -+ * cap left its speakers at roughly half the Windows loudness; -+ * its amplifiers' OCP, PBR and thermal protection (the wsa884x -+ * 2S/4 ohm profile) are relied on instead. - */ -- snd_soc_limit_volume(card, "WSA WSA_RX0 Digital Volume", 81); -- snd_soc_limit_volume(card, "WSA WSA_RX1 Digital Volume", 81); -- snd_soc_limit_volume(card, "WSA2 WSA_RX0 Digital Volume", 81); -- snd_soc_limit_volume(card, "WSA2 WSA_RX1 Digital Volume", 81); -- snd_soc_limit_volume(card, "SpkrLeft PA Volume", 6); -- snd_soc_limit_volume(card, "SpkrRight PA Volume", 6); -- snd_soc_limit_volume(card, "WooferLeft PA Volume", 6); -- snd_soc_limit_volume(card, "TweeterLeft PA Volume", 6); -- snd_soc_limit_volume(card, "WooferRight PA Volume", 6); -- snd_soc_limit_volume(card, "TweeterRight PA Volume", 6); -+ if (of_machine_is_compatible("microsoft,denali-oled")) { -+ digital_max = 84; -+ pa_max = 12; -+ } else { -+ digital_max = 81; -+ pa_max = 6; -+ } -+ snd_soc_limit_volume(card, "WSA WSA_RX0 Digital Volume", digital_max); -+ snd_soc_limit_volume(card, "WSA WSA_RX1 Digital Volume", digital_max); -+ snd_soc_limit_volume(card, "WSA2 WSA_RX0 Digital Volume", digital_max); -+ snd_soc_limit_volume(card, "WSA2 WSA_RX1 Digital Volume", digital_max); -+ snd_soc_limit_volume(card, "SpkrLeft PA Volume", pa_max); -+ snd_soc_limit_volume(card, "SpkrRight PA Volume", pa_max); -+ snd_soc_limit_volume(card, "WooferLeft PA Volume", pa_max); -+ snd_soc_limit_volume(card, "TweeterLeft PA Volume", pa_max); -+ snd_soc_limit_volume(card, "WooferRight PA Volume", pa_max); -+ snd_soc_limit_volume(card, "TweeterRight PA Volume", pa_max); - break; - case DISPLAY_PORT_RX_0: - dp_pcm_id = 0; diff --git a/kernel/2148-Bluetooth-hci_qca-Drop-unused-event-during-BT-on.patch b/kernel/2148-Bluetooth-hci_qca-Drop-unused-event-during-BT-on.patch deleted file mode 100644 index f671375..0000000 --- a/kernel/2148-Bluetooth-hci_qca-Drop-unused-event-during-BT-on.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Cheng Jiang -Date: Wed, 21 Aug 2024 17:13:40 +0800 -Subject: [PATCH] Bluetooth: hci_qca: Drop unused event during BT on - -For the WCN6750/WCN6855/WCN7850, the vendor command for a baudrate -change is not sent as synchronous HCI command, controller sends the -corresponding vendor event with the new baudrate. It needs to be -dropped, otherwise it may be misinterpreted as response to a later -command. - -According to -80-WL520-14_REV_F_Bluetooth_HCI_Vendor_Specific_Commands_Application_Note.pdf -event for set baudrate HCI command is sent with event code -HCI_EV_CMD_COMPLETE(0x0e), add related handle in qca_recv_event when -sending set baudrate HCI command. - -Signed-off-by: Cheng Jiang ---- - drivers/bluetooth/hci_qca.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - -diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c -index 875093e61c68..9aa5cad82bac 100644 ---- a/drivers/bluetooth/hci_qca.c -+++ b/drivers/bluetooth/hci_qca.c -@@ -1227,7 +1227,14 @@ static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb) - * vendor command). - */ - -- if (hdr->evt == HCI_EV_VENDOR) -+ /* For the WCN6750/WCN6855/WCN7850, like the WCN3990, the -+ * vendor command for a baudrate change command isn't sent as -+ * synchronous HCI command, the controller sends the corresponding -+ * command complete event with the new baudrate. The event is -+ * received and properly decoded after changing the baudrate of -+ * the host port. It needs to be dropped. -+ */ -+ if (hdr->evt == HCI_EV_VENDOR || hdr->evt == HCI_EV_CMD_COMPLETE) - complete(&qca->drop_ev_comp); - - kfree_skb(skb); -@@ -1522,6 +1529,9 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) - - switch (soc_type) { - case QCA_WCN3990: -+ case QCA_WCN6750: -+ case QCA_WCN6855: -+ case QCA_WCN7850: - reinit_completion(&qca->drop_ev_comp); - set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags); - break; -@@ -1557,6 +1567,9 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) - - switch (soc_type) { - case QCA_WCN3990: -+ case QCA_WCN6750: -+ case QCA_WCN6855: -+ case QCA_WCN7850: - /* Wait for the controller to send the vendor event - * for the baudrate change command. - */ diff --git a/kernel/2149-Bluetooth-SCO-accept-incoming-eSCO-with-Enhanced-Acc.patch b/kernel/2149-Bluetooth-SCO-accept-incoming-eSCO-with-Enhanced-Acc.patch deleted file mode 100644 index 51b0d8f..0000000 --- a/kernel/2149-Bluetooth-SCO-accept-incoming-eSCO-with-Enhanced-Acc.patch +++ /dev/null @@ -1,260 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Tue, 15 Sep 2026 08:44:19 -0400 -Subject: [PATCH] Bluetooth: SCO: accept incoming eSCO with Enhanced Accept and - HCI data path - -The deferred accept path (BT_DEFER_SETUP, used by BlueZ/PipeWire) -answers an incoming (e)SCO Connection Request with the legacy Accept -Synchronous Connection Request command, which has no data path -parameter. The controller then routes the audio wherever its -firmware/NVM default points. - -On the Qualcomm WCN7850 in the Surface Pro 11 (Windows-tuned firmware -that advertises "HFP non-HCI data transport"), that default is the -platform PCM path. HCI traces of iPhone HFP calls show the host -transmitting eSCO packets continuously while not a single inbound eSCO -packet ever reaches the host, and the controller wedges (command tx -timeout, memdump, hardware error) some tens of seconds into the call. - -When the controller supports Enhanced Accept Synchronous Connection -Request (Supported Commands octet 29 bit 4), use it and set -Input/Output_Data_Path to 0x00 (HCI) explicitly, with coding formats -derived from the socket's BT_VOICE air mode, mirroring -hci_enhanced_setup_sync() for outgoing links. Controllers without the -command keep the legacy accept. - -Co-Authored-By: Claude Fable 5.1 -Signed-off-by: Brandon Williams ---- - include/net/bluetooth/hci.h | 28 +++++++++ - include/net/bluetooth/hci_core.h | 6 ++ - net/bluetooth/hci_conn.c | 102 +++++++++++++++++++++++++++++++ - net/bluetooth/sco.c | 31 +--------- - 4 files changed, 137 insertions(+), 30 deletions(-) - -diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h -index 50f0eef71fb1..a1f0c899f788 100644 ---- a/include/net/bluetooth/hci.h -+++ b/include/net/bluetooth/hci.h -@@ -1021,6 +1021,34 @@ struct hci_cp_enhanced_setup_sync_conn { - __u8 retrans_effort; - } __packed; - -+#define HCI_OP_ENHANCED_ACCEPT_SYNC_CONN_REQ 0x043e -+struct hci_cp_enhanced_accept_sync_conn_req { -+ bdaddr_t bdaddr; -+ __le32 tx_bandwidth; -+ __le32 rx_bandwidth; -+ struct hci_coding_format tx_coding_format; -+ struct hci_coding_format rx_coding_format; -+ __le16 tx_codec_frame_size; -+ __le16 rx_codec_frame_size; -+ __le32 in_bandwidth; -+ __le32 out_bandwidth; -+ struct hci_coding_format in_coding_format; -+ struct hci_coding_format out_coding_format; -+ __le16 in_coded_data_size; -+ __le16 out_coded_data_size; -+ __u8 in_pcm_data_format; -+ __u8 out_pcm_data_format; -+ __u8 in_pcm_sample_payload_msb_pos; -+ __u8 out_pcm_sample_payload_msb_pos; -+ __u8 in_data_path; -+ __u8 out_data_path; -+ __u8 in_transport_unit_size; -+ __u8 out_transport_unit_size; -+ __le16 max_latency; -+ __le16 pkt_type; -+ __u8 retrans_effort; -+} __packed; -+ - struct hci_rp_logical_link_cancel { - __u8 status; - __u8 phy_handle; -diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h -index 9084fcd7125a..0f5ec0d8f1ac 100644 ---- a/include/net/bluetooth/hci_core.h -+++ b/include/net/bluetooth/hci_core.h -@@ -1569,6 +1569,7 @@ static inline bool hci_is_le_conn_scanning(struct hci_dev *hdev) - - int hci_disconnect(struct hci_conn *conn, __u8 reason); - bool hci_setup_sync(struct hci_conn *conn, __u16 handle); -+void hci_accept_sync_conn(struct hci_conn *conn, __u16 setting); - void hci_sco_setup(struct hci_conn *conn, __u8 status); - bool hci_iso_setup_path(struct hci_conn *conn); - int hci_le_create_cis_pending(struct hci_dev *hdev); -@@ -2008,6 +2009,11 @@ void hci_conn_del_sysfs(struct hci_conn *conn); - /* Use enhanced synchronous connection if command is supported and its quirk - * has not been set. - */ -+/* Enhanced Accept Synchronous Connection Request: octet 29 bit 4 */ -+#define enhanced_accept_sync_conn_capable(dev) \ -+ (((dev)->commands[29] & 0x10) && \ -+ !hci_test_quirk((dev), HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN)) -+ - #define enhanced_sync_conn_capable(dev) \ - (((dev)->commands[29] & 0x08) && \ - !hci_test_quirk((dev), HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN)) -diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c -index 6f5131c771b3..0eb94e5d96b9 100644 ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -468,6 +469,107 @@ static void hci_enhanced_setup_sync_destroy(struct hci_dev *hdev, void *data, - kfree(conn_handle); - } - -+/* Accept an incoming (e)SCO connection request. -+ * -+ * The legacy Accept Synchronous Connection Request command carries no data -+ * path field, so the controller routes the audio wherever its firmware/NVM -+ * default says. On controllers whose firmware is tuned for a platform PCM -+ * path (Qualcomm WCN7850 with "HFP non-HCI data transport"), that default -+ * sends the peer's audio to an interface Linux does not drive, and the host -+ * never sees an inbound SCO packet. When the controller implements the -+ * Enhanced Accept command, use it and pin both directions to the HCI data -+ * path (0x00), exactly as hci_enhanced_setup_sync() does for outgoing links. -+ * This is limited to the Surface Pro 11 (microsoft,denali), where it was -+ * tested; other machines may route SCO through an offload path on purpose. -+ */ -+void hci_accept_sync_conn(struct hci_conn *conn, __u16 setting) -+{ -+ struct hci_dev *hdev = conn->hdev; -+ -+ if (enhanced_accept_sync_conn_capable(hdev) && -+ of_machine_is_compatible("microsoft,denali")) { -+ struct hci_cp_enhanced_accept_sync_conn_req cp; -+ -+ memset(&cp, 0, sizeof(cp)); -+ bacpy(&cp.bdaddr, &conn->dst); -+ cp.pkt_type = cpu_to_le16(conn->pkt_type); -+ cp.tx_bandwidth = cpu_to_le32(0x00001f40); -+ cp.rx_bandwidth = cpu_to_le32(0x00001f40); -+ cp.tx_codec_frame_size = cpu_to_le16(60); -+ cp.rx_codec_frame_size = cpu_to_le16(60); -+ cp.in_coded_data_size = cpu_to_le16(16); -+ cp.out_coded_data_size = cpu_to_le16(16); -+ cp.in_pcm_data_format = 2; -+ cp.out_pcm_data_format = 2; -+ cp.in_data_path = 0x00; /* HCI */ -+ cp.out_data_path = 0x00; /* HCI */ -+ -+ switch (setting & SCO_AIRMODE_MASK) { -+ case SCO_AIRMODE_TRANSP: -+ cp.tx_coding_format.id = 0x03; -+ cp.rx_coding_format.id = 0x03; -+ cp.in_coding_format.id = 0x03; -+ cp.out_coding_format.id = 0x03; -+ cp.in_bandwidth = cpu_to_le32(0x1f40); -+ cp.out_bandwidth = cpu_to_le32(0x1f40); -+ cp.in_transport_unit_size = 1; -+ cp.out_transport_unit_size = 1; -+ if (conn->pkt_type & ESCO_2EV3) -+ cp.max_latency = cpu_to_le16(0x0008); -+ else -+ cp.max_latency = cpu_to_le16(0x000D); -+ cp.retrans_effort = 0x02; -+ break; -+ case SCO_AIRMODE_CVSD: -+ default: -+ cp.tx_coding_format.id = 0x02; -+ cp.rx_coding_format.id = 0x02; -+ cp.in_coding_format.id = 0x04; -+ cp.out_coding_format.id = 0x04; -+ cp.in_bandwidth = cpu_to_le32(16000); -+ cp.out_bandwidth = cpu_to_le32(16000); -+ cp.in_transport_unit_size = 16; -+ cp.out_transport_unit_size = 16; -+ cp.max_latency = cpu_to_le16(0xffff); -+ cp.retrans_effort = 0xff; -+ break; -+ } -+ -+ bt_dev_dbg(hdev, "enhanced accept, air mode %u, HCI data path", -+ setting & SCO_AIRMODE_MASK); -+ hci_send_cmd(hdev, HCI_OP_ENHANCED_ACCEPT_SYNC_CONN_REQ, -+ sizeof(cp), &cp); -+ } else { -+ struct hci_cp_accept_sync_conn_req cp; -+ -+ bacpy(&cp.bdaddr, &conn->dst); -+ cp.pkt_type = cpu_to_le16(conn->pkt_type); -+ -+ cp.tx_bandwidth = cpu_to_le32(0x00001f40); -+ cp.rx_bandwidth = cpu_to_le32(0x00001f40); -+ cp.content_format = cpu_to_le16(setting); -+ -+ switch (setting & SCO_AIRMODE_MASK) { -+ case SCO_AIRMODE_TRANSP: -+ if (conn->pkt_type & ESCO_2EV3) -+ cp.max_latency = cpu_to_le16(0x0008); -+ else -+ cp.max_latency = cpu_to_le16(0x000D); -+ cp.retrans_effort = 0x02; -+ break; -+ case SCO_AIRMODE_CVSD: -+ default: -+ cp.max_latency = cpu_to_le16(0xffff); -+ cp.retrans_effort = 0xff; -+ break; -+ } -+ -+ hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, -+ sizeof(cp), &cp); -+ } -+} -+EXPORT_SYMBOL(hci_accept_sync_conn); -+ - bool hci_setup_sync(struct hci_conn *conn, __u16 handle) - { - int result; -diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c -index 3d4362a09df4..06b6b1f54248 100644 ---- a/net/bluetooth/sco.c -+++ b/net/bluetooth/sco.c -@@ -906,36 +906,7 @@ static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting) - - hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); - } else { -- struct hci_cp_accept_sync_conn_req cp; -- -- bacpy(&cp.bdaddr, &conn->dst); -- cp.pkt_type = cpu_to_le16(conn->pkt_type); -- -- cp.tx_bandwidth = cpu_to_le32(0x00001f40); -- cp.rx_bandwidth = cpu_to_le32(0x00001f40); -- cp.content_format = cpu_to_le16(setting); -- -- switch (setting & SCO_AIRMODE_MASK) { -- case SCO_AIRMODE_TRANSP: -- if (conn->pkt_type & ESCO_2EV3) -- cp.max_latency = cpu_to_le16(0x0008); -- else -- cp.max_latency = cpu_to_le16(0x000D); -- cp.retrans_effort = 0x02; -- break; -- case SCO_AIRMODE_CVSD: -- cp.max_latency = cpu_to_le16(0xffff); -- cp.retrans_effort = 0xff; -- break; -- default: -- /* use CVSD settings as fallback */ -- cp.max_latency = cpu_to_le16(0xffff); -- cp.retrans_effort = 0xff; -- break; -- } -- -- hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, -- sizeof(cp), &cp); -+ hci_accept_sync_conn(conn, setting); - } - } - diff --git a/kernel/2150-wifi-ath12k-avoid-sleeping-PCI-wakeup-during-panic-r.patch b/kernel/2150-wifi-ath12k-avoid-sleeping-PCI-wakeup-during-panic-r.patch deleted file mode 100644 index da215ee..0000000 --- a/kernel/2150-wifi-ath12k-avoid-sleeping-PCI-wakeup-during-panic-r.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 20 Sep 2026 09:39:44 -0400 -Subject: [PATCH] wifi: ath12k: avoid sleeping PCI wakeup during panic reset - -The WCN7850 PCI panic callback reaches mhi_device_get_sync through its -register wakeup helper. An archived SP11 hung-task panic shows this -sleeping with preemption and interrupts disabled after other CPUs have -stopped, disrupting the dump path. Skip the panic-only reset on PCI -variants with a wakeup callback. Normal operation and recovery are -unchanged. - -Signed-off-by: Brandon Williams ---- - drivers/net/wireless/ath/ath12k/pci.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c -index fee4129ea405..b546910f046d 100644 ---- a/drivers/net/wireless/ath/ath12k/pci.c -+++ b/drivers/net/wireless/ath/ath12k/pci.c -@@ -1475,6 +1475,17 @@ void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend) - - static int ath12k_pci_panic_handler(struct ath12k_base *ab) - { -+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); -+ -+ /* -+ * Register accesses on devices with a wakeup callback can wait for -+ * MHI, which sleeps. Panic notifiers run with interrupts disabled -+ * after the other CPUs have stopped, so such a reset can prevent -+ * the kernel from reaching its crash dump handlers. -+ */ -+ if (ab_pci->pci_ops->wakeup) -+ return NOTIFY_DONE; -+ - ath12k_pci_sw_reset(ab, false); - - return NOTIFY_OK; diff --git a/kernel/2151-arm64-dts-qcom-hamoa-Drop-cluster_cl5-idle-state-fro.patch b/kernel/2151-arm64-dts-qcom-hamoa-Drop-cluster_cl5-idle-state-fro.patch deleted file mode 100644 index 03b33ed..0000000 --- a/kernel/2151-arm64-dts-qcom-hamoa-Drop-cluster_cl5-idle-state-fro.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jens Glathe -Date: Mon, 25 May 2026 21:54:56 +0200 -Subject: [PATCH] arm64: dts: qcom: hamoa: Drop cluster_cl5 idle state from CPU - clusters - -The cluster_cl5 idle state triggers DC ZVA misbehaviour that resets -X1 SoCs. Remove it from cluster_pd0/1/2 domain-idle-states for now. - -Suggested-by: Marc Zyngier -Signed-off-by: Jens Glathe -Link: https://lore.kernel.org/all/20260604-dc_zva_mitigation-v1-1-d1148c1c0259@oldschoolsolutions.biz/ ---- - arch/arm64/boot/dts/qcom/hamoa.dtsi | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi -index 5d7b80ae57c4..8863cee1b6cb 100644 ---- a/arch/arm64/boot/dts/qcom/hamoa.dtsi -+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi -@@ -450,19 +450,19 @@ cpu_pd11: power-domain-cpu11 { - - cluster_pd0: power-domain-cpu-cluster0 { - #power-domain-cells = <0>; -- domain-idle-states = <&cluster_cl4>, <&cluster_cl5>; -+ domain-idle-states = <&cluster_cl4>; - power-domains = <&system_pd>; - }; - - cluster_pd1: power-domain-cpu-cluster1 { - #power-domain-cells = <0>; -- domain-idle-states = <&cluster_cl4>, <&cluster_cl5>; -+ domain-idle-states = <&cluster_cl4>; - power-domains = <&system_pd>; - }; - - cluster_pd2: power-domain-cpu-cluster2 { - #power-domain-cells = <0>; -- domain-idle-states = <&cluster_cl4>, <&cluster_cl5>; -+ domain-idle-states = <&cluster_cl4>; - power-domains = <&system_pd>; - }; - diff --git a/kernel/2152-arm64-qcom-add-Surface-Pro-11-platform-support.patch b/kernel/2152-arm64-qcom-add-Surface-Pro-11-platform-support.patch deleted file mode 100644 index 4a0a1bf..0000000 --- a/kernel/2152-arm64-qcom-add-Surface-Pro-11-platform-support.patch +++ /dev/null @@ -1,2474 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 16:35:16 -0400 -Subject: [PATCH] arm64: qcom: add Surface Pro 11 platform support - -Add the reviewed SP11 end state for touch and pen over HID-over-SPI and -QSPI, audio, volume keys, suspend mitigation, fan telemetry, and -platform profiles. - -The SP11-specific touch/QSPI behavior was independently implemented from -public specifications, GPL-licensed Linux source, ACPI/device -information, hardware experiments, and WinDbg runtime observations on -the author's own licensed device. No Windows driver, firmware, trace, -captured descriptor fixture, decompilation output, or proprietary source -is included. - -The private research history is intentionally not reproduced because it -contained unused descriptor-only diagnostic experiments. The preceding -eleven HID-over-SPI commits retain their original authorship, sign-offs, -copyright notices, and published specification reference. - -Signed-off-by: Brandon Williams ---- - .../bindings/input/hid-over-spi.yaml | 7 + - .../bindings/spi/qcom,spi-geni-qcom.yaml | 4 +- - .../boot/dts/qcom/x1-microsoft-denali.dtsi | 98 +++- - drivers/acpi/platform_profile.c | 43 +- - drivers/dma/qcom/gpi.c | 480 +++++++++++++++++- - drivers/hid/spi-hid/spi-hid-acpi.c | 14 +- - drivers/hid/spi-hid/spi-hid-core.c | 224 +++++++- - drivers/hid/spi-hid/spi-hid-core.h | 17 +- - drivers/hid/spi-hid/spi-hid-of.c | 37 +- - drivers/hid/spi-hid/spi-hid-trace.h | 2 +- - drivers/hid/spi-hid/spi-hid.h | 3 +- - .../surface/surface_aggregator_registry.c | 2 + - drivers/soc/qcom/qcom-geni-se.c | 12 +- - drivers/spi/spi-geni-qcom.c | 316 +++++++++++- - drivers/spi/spi.c | 29 +- - include/dt-bindings/dma/qcom-gpi.h | 1 + - include/linux/soc/qcom/geni-se.h | 1 + - include/linux/spi/spi.h | 5 + - 18 files changed, 1172 insertions(+), 123 deletions(-) - -diff --git a/Documentation/devicetree/bindings/input/hid-over-spi.yaml b/Documentation/devicetree/bindings/input/hid-over-spi.yaml -index 27cf311e0aab..1bf761085459 100644 ---- a/Documentation/devicetree/bindings/input/hid-over-spi.yaml -+++ b/Documentation/devicetree/bindings/input/hid-over-spi.yaml -@@ -89,6 +89,12 @@ properties: - description: - Value to be used in Write Approval packets. 1 byte. - -+ hid-over-spi-flags: -+ $ref: /schemas/types.yaml#/definitions/uint16 -+ description: -+ Firmware-provided HID over SPI protocol flags. Bits 15:14 select the -+ multi-lane mode and bit 13 enables multi-lane output reports. -+ - required: - - compatible - - interrupts -@@ -124,5 +130,6 @@ examples: - output-report-address = <0x2000>; - read-opcode = /bits/ 8 <0x0b>; - write-opcode = /bits/ 8 <0x02>; -+ hid-over-spi-flags = <0>; - }; - }; -diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.yaml b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.yaml -index edf399681d7a..55d9f62abc46 100644 ---- a/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.yaml -+++ b/Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.yaml -@@ -29,7 +29,9 @@ allOf: - - properties: - compatible: -- const: qcom,geni-spi -+ enum: -+ - qcom,geni-qspi -+ - qcom,geni-spi - - clocks: - maxItems: 1 -diff --git a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -index 9cf8e1a5e0bf..5a32f393a704 100644 ---- a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -+++ b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -@@ -7,6 +7,7 @@ - #include - #include - #include -+#include - #include - - #include "hamoa-pmics.dtsi" -@@ -19,10 +20,27 @@ aliases { - - gpio-keys { - compatible = "gpio-keys"; -+ autorepeat; - -- pinctrl-0 = <&hall_int_n_default>; -+ pinctrl-0 = <&hall_int_n_default>, <&volume_buttons_default>; - pinctrl-names = "default"; - -+ key-volume-up { -+ label = "Volume Up"; -+ gpios = <&pm8550_gpios 8 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ debounce-interval = <15>; -+ linux,can-disable; -+ }; -+ -+ key-volume-down { -+ label = "Volume Down"; -+ gpios = <&pm8550_gpios 6 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ debounce-interval = <15>; -+ linux,can-disable; -+ }; -+ - switch-lid { - gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; - linux,input-type = ; -@@ -125,6 +143,17 @@ linux,cma { - }; - }; - -+ vreg_touch: regulator-touch { -+ compatible = "regulator-fixed"; -+ -+ regulator-name = "VREG_TOUCH"; -+ gpio = <&tlmm 64 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ -+ pinctrl-0 = <&touchscreen_power_en>; -+ pinctrl-names = "default"; -+ }; -+ - vreg_edp_3p3: regulator-edp-3p3 { - compatible = "regulator-fixed"; - -@@ -867,7 +896,7 @@ &lpass_vamacro { - pinctrl-names = "default"; - - vdd-micb-supply = <&vreg_l1b_1p8>; -- qcom,dmic-sample-rate = <4800000>; -+ qcom,dmic-sample-rate = <3200000>; - }; - - &mdss { -@@ -987,6 +1016,14 @@ &pcie6a_port0 { - }; - - &pm8550_gpios { -+ volume_buttons_default: volume-buttons-default-state { -+ pins = "gpio6", "gpio8"; -+ function = "normal"; -+ power-source = <1>; /* 1.8V */ -+ bias-pull-up; -+ input-enable; -+ }; -+ - rtmr0_default: rtmr0-reset-n-active-state { - pins = "gpio10"; - function = "normal"; -@@ -1110,10 +1147,67 @@ right_spkr: speaker@0,1 { - }; - }; - -+&gpi_dma1 { -+ /* Use GPII0 for the paired QSPI TX and RX channels. */ -+ dma-channel-mask = <0x3f>; -+ status = "okay"; -+}; -+ -+&spi10 { -+ compatible = "qcom,geni-qspi"; -+ dmas = <&gpi_dma1 0 2 QCOM_GPI_QSPI>, -+ <&gpi_dma1 1 2 QCOM_GPI_QSPI>; -+ pinctrl-0 = <&qup_spi10_data_clk>, <&qup_spi10_data2>, -+ <&qup_spi10_cs>; -+ status = "okay"; -+ -+ touchscreen@0 { -+ compatible = "microsoft,g6-touch-digitizer", "hid-over-spi"; -+ reg = <0>; -+ spi-max-frequency = <40000000>; -+ -+ interrupts-extended = <&tlmm 51 IRQ_TYPE_EDGE_FALLING>; -+ reset-gpios = <&tlmm 48 GPIO_ACTIVE_LOW>; -+ vdd-supply = <&vreg_touch>; -+ -+ pinctrl-0 = <&touchscreen_int>; -+ pinctrl-names = "default"; -+ -+ input-report-header-address = <0x1000>; -+ input-report-body-address = <0x1004>; -+ output-report-address = <0x2000>; -+ read-opcode = /bits/ 8 <0xeb>; -+ write-opcode = /bits/ 8 <0xe2>; -+ hid-over-spi-flags = <0xa000>; -+ }; -+}; -+ - &tlmm { - gpio-reserved-ranges = <44 4>, /* SPI (TPM) */ - <238 1>; /* UFS Reset */ - -+ qup_spi10_data2: qup-spi10-data2-state { -+ /* DATA2, DATA3 */ -+ pins = "gpio49", "gpio50"; -+ function = "qup1_se2"; -+ drive-strength = <6>; -+ bias-disable; -+ }; -+ -+ touchscreen_int: touchscreen-int-state { -+ pins = "gpio51"; -+ function = "gpio"; -+ input-enable; -+ bias-disable; -+ }; -+ -+ touchscreen_power_en: touchscreen-power-en-state { -+ pins = "gpio64"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-disable; -+ }; -+ - hall_int_n_default: hall-int-n-state { - pins = "gpio2"; - function = "gpio"; -diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c -index 79d2e92e5c28..f120fa60f0d9 100644 ---- a/drivers/acpi/platform_profile.c -+++ b/drivers/acpi/platform_profile.c -@@ -44,6 +44,17 @@ static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST); - - static DEFINE_IDA(platform_profile_ida); - -+/* -+ * The per-device class interface is firmware agnostic. Keep the legacy -+ * aggregate interface under /sys/firmware/acpi optional so platform-profile -+ * drivers can also be used on device-tree systems. -+ */ -+static void platform_profile_legacy_notify(void) -+{ -+ if (acpi_kobj) -+ sysfs_notify(acpi_kobj, NULL, "platform_profile"); -+} -+ - /** - * _commmon_choices_show - Show the available profile choices - * @choices: The available profile choices -@@ -216,7 +227,7 @@ static ssize_t profile_store(struct device *dev, - return ret; - } - -- sysfs_notify(acpi_kobj, NULL, "platform_profile"); -+ platform_profile_legacy_notify(); - - return count; - } -@@ -436,7 +447,7 @@ static ssize_t platform_profile_store(struct kobject *kobj, - return ret; - } - -- sysfs_notify(acpi_kobj, NULL, "platform_profile"); -+ platform_profile_legacy_notify(); - - return count; - } -@@ -482,7 +493,7 @@ void platform_profile_notify(struct device *dev) - scoped_cond_guard(mutex_intr, return, &profile_lock) { - _notify_class_profile(dev, NULL); - } -- sysfs_notify(acpi_kobj, NULL, "platform_profile"); -+ platform_profile_legacy_notify(); - } - EXPORT_SYMBOL_GPL(platform_profile_notify); - -@@ -532,7 +543,7 @@ int platform_profile_cycle(void) - return err; - } - -- sysfs_notify(acpi_kobj, NULL, "platform_profile"); -+ platform_profile_legacy_notify(); - - return 0; - } -@@ -605,11 +616,13 @@ struct device *platform_profile_register(struct device *dev, const char *name, - goto cleanup_ida; - } - -- sysfs_notify(acpi_kobj, NULL, "platform_profile"); -+ platform_profile_legacy_notify(); - -- err = sysfs_update_group(acpi_kobj, &platform_profile_group); -- if (err) -- goto cleanup_cur; -+ if (acpi_kobj) { -+ err = sysfs_update_group(acpi_kobj, &platform_profile_group); -+ if (err) -+ goto cleanup_cur; -+ } - - return ppdev; - -@@ -641,8 +654,9 @@ void platform_profile_remove(struct device *dev) - ida_free(&platform_profile_ida, pprof->minor); - device_unregister(&pprof->dev); - -- sysfs_notify(acpi_kobj, NULL, "platform_profile"); -- sysfs_update_group(acpi_kobj, &platform_profile_group); -+ platform_profile_legacy_notify(); -+ if (acpi_kobj) -+ sysfs_update_group(acpi_kobj, &platform_profile_group); - } - EXPORT_SYMBOL_GPL(platform_profile_remove); - -@@ -690,13 +704,13 @@ static int __init platform_profile_init(void) - { - int err; - -- if (acpi_disabled) -- return -EOPNOTSUPP; -- - err = class_register(&platform_profile_class); - if (err) - return err; - -+ if (!acpi_kobj) -+ return 0; -+ - err = sysfs_create_group(acpi_kobj, &platform_profile_group); - if (err) - class_unregister(&platform_profile_class); -@@ -706,7 +720,8 @@ static int __init platform_profile_init(void) - - static void __exit platform_profile_exit(void) - { -- sysfs_remove_group(acpi_kobj, &platform_profile_group); -+ if (acpi_kobj) -+ sysfs_remove_group(acpi_kobj, &platform_profile_group); - class_unregister(&platform_profile_class); - } - module_init(platform_profile_init); -diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c -index a5055a6273af..c6bf91be2b64 100644 ---- a/drivers/dma/qcom/gpi.c -+++ b/drivers/dma/qcom/gpi.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -46,8 +47,17 @@ - /* SPI GO WD0 */ - #define TRE_SPI_GO_CMD GENMASK(4, 0) - #define TRE_SPI_GO_CS GENMASK(10, 8) -+#define TRE_QSPI_GO BIT(29) - #define TRE_SPI_GO_FRAG BIT(26) - -+ -+/* -+ * A timed-out SP11 QSPI transfer can complete after channel RESET. Keep old -+ * transfer-ring allocations alive and give each recovery a fresh DMA address, -+ * so a delayed completion cannot alias a new descriptor at the same ring slot. -+ */ -+#define SP11_QSPI_RETIRED_RING_LIMIT 256 -+ - /* GO WD2 */ - #define TRE_RX_LEN GENMASK(23, 0) - -@@ -147,6 +157,7 @@ enum CNTXT_OFFS { - #define GPII_n_EV_CH_CMD_RESET (0x09) - #define GPII_n_EV_CH_CMD_DE_ALLOC (0x0A) - -+#define GPII_n_CNTXT_0_OFFS(n) (0x23000 + (0x4000 * (n))) - #define GPII_n_CNTXT_TYPE_IRQ_OFFS(n) (0x23080 + (0x4000 * (n))) - - /* mask type register */ -@@ -172,6 +183,8 @@ enum CNTXT_OFFS { - #define GPII_n_CNTXT_SRC_CH_IRQ_CLR_OFFS(n) (0x230A0 + (0x4000 * (n))) - #define GPII_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(n) (0x230A4 + (0x4000 * (n))) - -+#define GPII_n_CNTXT_SRC_IEOB_IRQ_OFFS(n) (0x230B0 + (0x4000 * (n))) -+ - /* Mask event interrupt register */ - #define GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(n) (0x230B8 + (0x4000 * (n))) - #define GPII_n_CNTXT_SRC_IEOB_IRQ_MSK_BMSK BIT(0) -@@ -197,6 +210,7 @@ enum CNTXT_OFFS { - - #define GPII_n_CNTXT_MSI_BASE_LSB_OFFS(n) (0x23188 + (0x4000 * (n))) - #define GPII_n_CNTXT_MSI_BASE_MSB_OFFS(n) (0x2318C + (0x4000 * (n))) -+#define GPII_n_CNTXT_190_OFFS(n) (0x23190 + (0x4000 * (n))) - #define GPII_n_CNTXT_SCRATCH_0_OFFS(n) (0x23400 + (0x4000 * (n))) - #define GPII_n_CNTXT_SCRATCH_1_OFFS(n) (0x23404 + (0x4000 * (n))) - -@@ -238,6 +252,7 @@ enum msm_gpi_tce_code { - #define EV_FACTOR (2) - #define REQ_OF_DMA_ARGS (5) /* # of arguments required from client */ - #define CHAN_TRES 64 -+#define SP11_QSPI_CHAN_TRES 16 - - struct __packed xfer_compl_event { - u64 ptr; -@@ -466,15 +481,22 @@ struct gpi_ring { - bool configured; - }; - -+struct gpi_retired_ring { -+ struct gpi_retired_ring *next; -+ struct gpi_ring ring; -+}; -+ - struct gpi_dev { - struct dma_device dma_device; - struct device *dev; - struct resource *res; - void __iomem *regs; - void __iomem *ee_base; /*ee register base address*/ -+ u32 ee_offset; - u32 max_gpii; /* maximum # of gpii instances available per gpi block */ - u32 gpii_mask; /* gpii instances available for apps */ - u32 ev_factor; /* ev ring length factor */ -+ bool sp11_qspi_quirk; /* Surface Pro 11 QSPI completion workaround */ - struct gpii *gpiis; - }; - -@@ -491,6 +513,8 @@ struct gchan { - void __iomem *ch_cmd_reg; - u32 dir; - struct gpi_ring ch_ring; -+ struct gpi_retired_ring *retired_rings; -+ u32 retired_ring_count; - void *config; - }; - -@@ -511,6 +535,9 @@ struct gpii { - enum gpi_pm_state pm_state; - rwlock_t pm_lock; - struct gpi_ring ev_ring; -+ struct gpi_retired_ring *retired_ev_rings; -+ u32 retired_ev_ring_count; -+ u32 recovery_generation; - struct tasklet_struct ev_task; /* event processing tasklet */ - struct completion cmd_completion; - enum gpi_cmd gpi_cmd; -@@ -527,6 +554,7 @@ struct gpi_desc { - struct gchan *gchan; - struct gpi_tre tre[MAX_TRE]; - u32 num_tre; -+ phys_addr_t first_tre; - }; - - static const u32 GPII_CHAN_DIR[MAX_CHANNELS_PER_GPII] = { -@@ -559,6 +587,112 @@ static inline void *to_virtual(const struct gpi_ring *const ring, phys_addr_t ad - return ring->base + (addr - ring->phys_addr); - } - -+static bool gpi_ring_addr_valid(const struct gpi_ring *ring, phys_addr_t addr) -+{ -+ phys_addr_t offset; -+ -+ if (!ring->configured || !ring->el_size || addr < ring->phys_addr) -+ return false; -+ -+ offset = addr - ring->phys_addr; -+ return offset < ring->len && !(offset % ring->el_size); -+} -+ -+static void gpi_log_invalid_ring_addr(struct gpii *gpii, -+ const struct gpi_ring *ring, -+ const char *kind, u32 chid, -+ phys_addr_t addr) -+{ -+ phys_addr_t offset = 0; -+ bool below = addr < ring->phys_addr; -+ -+ if (!below) -+ offset = addr - ring->phys_addr; -+ -+ dev_warn_ratelimited(gpii->gpi_dev->dev, -+ "ignoring %s outside active ring: generation=%u ch=%u ptr=%016llx ring=%pa+%#x configured=%u el-size=%u below=%u offset=%pa\n", -+ kind, gpii->recovery_generation, chid, -+ (unsigned long long)addr, &ring->phys_addr, -+ ring->len, ring->configured, ring->el_size, -+ below, &offset); -+} -+ -+static bool gpi_desc_owns_tre(const struct gpi_desc *desc, -+ const struct gpi_ring *ring, phys_addr_t addr) -+{ -+ phys_addr_t tre = desc->first_tre; -+ u32 i; -+ -+ for (i = 0; i < desc->num_tre; i++) { -+ if (addr == tre) -+ return true; -+ tre += ring->el_size; -+ if (tre >= ring->phys_addr + ring->len) -+ tre = ring->phys_addr; -+ } -+ -+ return false; -+} -+ -+static bool gpi_is_spi_protocol(u32 protocol) -+{ -+ return protocol == QCOM_GPI_SPI || protocol == QCOM_GPI_QSPI; -+} -+ -+static bool gpi_is_sp11_qspi_chan(const struct gchan *gchan) -+{ -+ const struct gpi_dev *gpi_dev = gchan->gpii->gpi_dev; -+ -+ return gpi_dev->sp11_qspi_quirk && -+ gpi_dev->res->start == 0xa00000 && -+ gpi_dev->ee_offset == 0x10000 && -+ gpi_dev->max_gpii == 12 && gpi_dev->gpii_mask == 0x3f && -+ gpi_is_spi_protocol(gchan->protocol) && gchan->seid == 2; -+} -+ -+static struct gchan * -+gpi_resolve_sp11_qspi_completion(struct gpii *gpii, -+ struct xfer_compl_event *compl_event) -+{ -+ struct gchan *reported = &gpii->gchan[compl_event->chid]; -+ struct gchan *resolved; -+ struct virt_dma_desc *vd; -+ struct gpi_desc *desc; -+ unsigned long flags; -+ bool owns_tre = false; -+ -+ if (!gpi_is_sp11_qspi_chan(reported) || -+ gpi_ring_addr_valid(&reported->ch_ring, compl_event->ptr)) -+ return reported; -+ -+ resolved = &gpii->gchan[compl_event->chid ^ 1]; -+ if (!gpi_is_sp11_qspi_chan(resolved) || -+ !gpi_ring_addr_valid(&resolved->ch_ring, compl_event->ptr)) -+ return reported; -+ -+ spin_lock_irqsave(&resolved->vc.lock, flags); -+ vd = vchan_next_desc(&resolved->vc); -+ if (vd) { -+ desc = to_gpi_desc(vd); -+ owns_tre = gpi_desc_owns_tre(desc, &resolved->ch_ring, -+ compl_event->ptr); -+ } -+ spin_unlock_irqrestore(&resolved->vc.lock, flags); -+ -+ if (!owns_tre) -+ return reported; -+ -+ dev_warn_ratelimited(gpii->gpi_dev->dev, -+ "SP11 QSPI correcting completion channel: generation=%u reported=%u resolved=%u ptr=%016llx length=%u code=%u status=%u type=%u\n", -+ gpii->recovery_generation, compl_event->chid, -+ resolved->chid, -+ (unsigned long long)compl_event->ptr, -+ compl_event->length, compl_event->code, -+ compl_event->status, compl_event->type); -+ -+ return resolved; -+} -+ - static inline u32 gpi_read_reg(struct gpii *gpii, void __iomem *addr) - { - return readl_relaxed(addr); -@@ -998,11 +1132,12 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan, - { - struct gpii *gpii = gchan->gpii; - struct gpi_ring *ch_ring = &gchan->ch_ring; -- void *ev_rp = to_virtual(ch_ring, compl_event->ptr); -+ void *ev_rp; - struct virt_dma_desc *vd; - struct gpi_desc *gpi_desc; - struct dmaengine_result result; - unsigned long flags; -+ bool owns_tre; - u32 chid; - - /* only process events on active channel */ -@@ -1012,6 +1147,12 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan, - return; - } - -+ if (unlikely(!gpi_ring_addr_valid(ch_ring, compl_event->ptr))) { -+ gpi_log_invalid_ring_addr(gpii, ch_ring, "completion", -+ gchan->chid, compl_event->ptr); -+ return; -+ } -+ - spin_lock_irqsave(&gchan->vc.lock, flags); - vd = vchan_next_desc(&gchan->vc); - if (!vd) { -@@ -1028,7 +1169,20 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan, - } - - gpi_desc = to_gpi_desc(vd); -+ owns_tre = !gpi_is_sp11_qspi_chan(gchan) || -+ gpi_desc_owns_tre(gpi_desc, ch_ring, compl_event->ptr); -+ if (unlikely(!owns_tre)) { -+ spin_unlock_irqrestore(&gchan->vc.lock, flags); -+ dev_warn_ratelimited(gpii->gpi_dev->dev, -+ "ignoring completion not owned by pending descriptor: generation=%u ch=%u ptr=%016llx first=%pa tres=%u\n", -+ gpii->recovery_generation, gchan->chid, -+ (unsigned long long)compl_event->ptr, -+ &gpi_desc->first_tre, -+ gpi_desc->num_tre); -+ return; -+ } - spin_unlock_irqrestore(&gchan->vc.lock, flags); -+ ev_rp = to_virtual(ch_ring, compl_event->ptr); - - /* - * RP pointed by Event is to last TRE processed, -@@ -1042,7 +1196,12 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan, - /* update must be visible to other cores */ - smp_wmb(); - -- chid = compl_event->chid; -+ chid = gchan->chid; -+ /* QSPI CONFIG and GO blocks remain chained until the final DMA EOT. */ -+ if (gchan->protocol == QCOM_GPI_QSPI && -+ compl_event->code == MSM_GPI_TCE_EOB) -+ return; -+ - if (compl_event->code == MSM_GPI_TCE_EOT && gpii->ieob_set) { - if (chid == GPI_RX_CHAN) - goto gpi_free_desc; -@@ -1077,16 +1236,26 @@ static void gpi_process_events(struct gpii *gpii) - struct gpi_ring *ev_ring = &gpii->ev_ring; - phys_addr_t cntxt_rp; - void *rp; -+ union gpi_event event; - union gpi_event *gpi_event; -+ struct xfer_compl_event *compl_event; - struct gchan *gchan; - u32 chid, type; - -- cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); -+ /* Order subsequent coherent event reads after the producer pointer. */ -+ cntxt_rp = readl(gpii->ev_ring_rp_lsb_reg); -+ if (unlikely(!gpi_ring_addr_valid(ev_ring, cntxt_rp))) { -+ gpi_log_invalid_ring_addr(gpii, ev_ring, "event read pointer", -+ MAX_CHANNELS_PER_GPII, cntxt_rp); -+ return; -+ } - rp = to_virtual(ev_ring, cntxt_rp); - - do { - while (rp != ev_ring->rp) { -- gpi_event = ev_ring->rp; -+ /* Keep every field read for this event internally consistent. */ -+ memcpy(&event, ev_ring->rp, sizeof(event)); -+ gpi_event = &event; - chid = gpi_event->xfer_compl_event.chid; - type = gpi_event->xfer_compl_event.type; - -@@ -1098,9 +1267,9 @@ static void gpi_process_events(struct gpii *gpii) - - switch (type) { - case XFER_COMPLETE_EV_TYPE: -- gchan = &gpii->gchan[chid]; -- gpi_process_xfer_compl_event(gchan, -- &gpi_event->xfer_compl_event); -+ compl_event = &gpi_event->xfer_compl_event; -+ gchan = gpi_resolve_sp11_qspi_completion(gpii, compl_event); -+ gpi_process_xfer_compl_event(gchan, compl_event); - break; - case STALE_EV_TYPE: - dev_dbg(gpii->gpi_dev->dev, "stale event, not processing\n"); -@@ -1124,7 +1293,14 @@ static void gpi_process_events(struct gpii *gpii) - /* clear pending IEOB events */ - gpi_write_reg(gpii, gpii->ieob_clr_reg, BIT(0)); - -- cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); -+ cntxt_rp = readl(gpii->ev_ring_rp_lsb_reg); -+ if (unlikely(!gpi_ring_addr_valid(ev_ring, cntxt_rp))) { -+ gpi_log_invalid_ring_addr(gpii, ev_ring, -+ "event read pointer", -+ MAX_CHANNELS_PER_GPII, -+ cntxt_rp); -+ return; -+ } - rp = to_virtual(ev_ring, cntxt_rp); - - } while (rp != ev_ring->rp); -@@ -1160,6 +1336,11 @@ static void gpi_mark_stale_events(struct gchan *gchan) - void *ev_rp; - - cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); -+ if (unlikely(!gpi_ring_addr_valid(ev_ring, cntxt_rp))) { -+ gpi_log_invalid_ring_addr(gpii, ev_ring, "stale read pointer", -+ gchan->chid, cntxt_rp); -+ return; -+ } - - ev_rp = ev_ring->rp; - local_rp = (u32)to_physical(ev_ring, ev_rp); -@@ -1173,6 +1354,12 @@ static void gpi_mark_stale_events(struct gchan *gchan) - if (ev_rp >= (ev_ring->base + ev_ring->len)) - ev_rp = ev_ring->base; - cntxt_rp = gpi_read_reg(gpii, gpii->ev_ring_rp_lsb_reg); -+ if (unlikely(!gpi_ring_addr_valid(ev_ring, cntxt_rp))) { -+ gpi_log_invalid_ring_addr(gpii, ev_ring, -+ "stale read pointer", -+ gchan->chid, cntxt_rp); -+ return; -+ } - local_rp = (u32)to_physical(ev_ring, ev_rp); - } - } -@@ -1288,17 +1475,19 @@ static int gpi_alloc_chan(struct gchan *chan, bool send_alloc_cmd) - } - - /* allocate and configure event ring */ --static int gpi_alloc_ev_chan(struct gpii *gpii) -+static int gpi_config_ev_chan(struct gpii *gpii, bool send_alloc_cmd) - { - struct gpi_ring *ring = &gpii->ev_ring; - void __iomem *base = gpii->ev_cntxt_base_reg; - int ret; - -- ret = gpi_send_cmd(gpii, NULL, GPI_EV_CMD_ALLOCATE); -- if (ret) { -- dev_err(gpii->gpi_dev->dev, "error with cmd:%s ret:%d\n", -- TO_GPI_CMD_STR(GPI_EV_CMD_ALLOCATE), ret); -- return ret; -+ if (send_alloc_cmd) { -+ ret = gpi_send_cmd(gpii, NULL, GPI_EV_CMD_ALLOCATE); -+ if (ret) { -+ dev_err(gpii->gpi_dev->dev, "error with cmd:%s ret:%d\n", -+ TO_GPI_CMD_STR(GPI_EV_CMD_ALLOCATE), ret); -+ return ret; -+ } - } - - /* program event context */ -@@ -1435,6 +1624,100 @@ static int gpi_alloc_ring(struct gpi_ring *ring, u32 elements, - return 0; - } - -+static int gpi_prepare_fresh_ring(struct gpii *gpii, -+ const struct gpi_ring *active_ring, -+ u32 retired_ring_count, -+ struct gpi_ring *replacement, -+ struct gpi_retired_ring **retired) -+{ -+ struct gpi_retired_ring *old; -+ int ret; -+ -+ if (retired_ring_count >= SP11_QSPI_RETIRED_RING_LIMIT) -+ return -ENOSPC; -+ -+ old = kzalloc_obj(*old, GFP_KERNEL); -+ if (!old) -+ return -ENOMEM; -+ -+ ret = gpi_alloc_ring(replacement, active_ring->elements, -+ active_ring->el_size, gpii); -+ if (ret) { -+ kfree(old); -+ return ret; -+ } -+ -+ *retired = old; -+ return 0; -+} -+ -+static void gpi_install_fresh_chan_ring(struct gchan *gchan, -+ struct gpi_ring *replacement, -+ struct gpi_retired_ring *retired, -+ u32 generation) -+{ -+ retired->ring = gchan->ch_ring; -+ retired->next = gchan->retired_rings; -+ gchan->retired_rings = retired; -+ gchan->retired_ring_count++; -+ gchan->ch_ring = *replacement; -+ memset(replacement, 0, sizeof(*replacement)); -+ dev_info(gchan->gpii->gpi_dev->dev, -+ "SP11 QSPI recovery ring rotated: ch=%u generation=%u old=%pa new=%pa\n", -+ gchan->chid, generation, -+ &retired->ring.phys_addr, &gchan->ch_ring.phys_addr); -+} -+ -+static void gpi_install_fresh_ev_ring(struct gpii *gpii, -+ struct gpi_ring *replacement, -+ struct gpi_retired_ring *retired, -+ u32 generation) -+{ -+ retired->ring = gpii->ev_ring; -+ retired->next = gpii->retired_ev_rings; -+ gpii->retired_ev_rings = retired; -+ gpii->retired_ev_ring_count++; -+ gpii->ev_ring = *replacement; -+ memset(replacement, 0, sizeof(*replacement)); -+ dev_info(gpii->gpi_dev->dev, -+ "SP11 QSPI recovery event ring rotated: generation=%u old=%pa new=%pa\n", -+ generation, &retired->ring.phys_addr, -+ &gpii->ev_ring.phys_addr); -+} -+ -+static void gpi_free_retired_rings(struct gchan *gchan) -+{ -+ struct gpi_retired_ring *retired = gchan->retired_rings; -+ -+ while (retired) { -+ struct gpi_retired_ring *next = retired->next; -+ -+ gpi_free_ring(&retired->ring, gchan->gpii); -+ kfree(retired); -+ retired = next; -+ } -+ -+ gchan->retired_rings = NULL; -+ gchan->retired_ring_count = 0; -+} -+ -+static void gpi_free_retired_ev_rings(struct gpii *gpii) -+{ -+ struct gpi_retired_ring *retired = gpii->retired_ev_rings; -+ -+ while (retired) { -+ struct gpi_retired_ring *next = retired->next; -+ -+ gpi_free_ring(&retired->ring, gpii); -+ kfree(retired); -+ retired = next; -+ } -+ -+ gpii->retired_ev_rings = NULL; -+ gpii->retired_ev_ring_count = 0; -+ gpii->recovery_generation = 0; -+} -+ - /* copy tre into transfer ring */ - static void gpi_queue_xfer(struct gpii *gpii, struct gchan *gchan, - struct gpi_tre *gpi_tre, void **wp) -@@ -1459,6 +1742,13 @@ static int gpi_terminate_all(struct dma_chan *chan) - { - struct gchan *gchan = to_gchan(chan); - struct gpii *gpii = gchan->gpii; -+ struct gpi_ring replacement[MAX_CHANNELS_PER_GPII] = {}; -+ struct gpi_ring ev_replacement = {}; -+ struct gpi_retired_ring *retired[MAX_CHANNELS_PER_GPII] = {}; -+ struct gpi_retired_ring *retired_ev = NULL; -+ bool rotate_sp11_qspi; -+ bool ieob_disabled = false; -+ u32 generation = 0; - int schid, echid, i; - int ret = 0; - -@@ -1470,6 +1760,66 @@ static int gpi_terminate_all(struct dma_chan *chan) - */ - schid = (gchan->protocol == QCOM_GPI_UART) ? gchan->chid : 0; - echid = (gchan->protocol == QCOM_GPI_UART) ? schid + 1 : MAX_CHANNELS_PER_GPII; -+ rotate_sp11_qspi = schid == 0 && -+ echid == MAX_CHANNELS_PER_GPII && -+ gpi_is_sp11_qspi_chan(&gpii->gchan[GPI_TX_CHAN]) && -+ gpi_is_sp11_qspi_chan(&gpii->gchan[GPI_RX_CHAN]); -+ if (rotate_sp11_qspi && -+ (!gpii->ev_ring.configured || -+ !gpii->gchan[GPI_TX_CHAN].ch_ring.configured || -+ !gpii->gchan[GPI_RX_CHAN].ch_ring.configured)) { -+ dev_err(gpii->gpi_dev->dev, -+ "refusing SP11 QSPI recovery with an unconfigured ring\n"); -+ ret = -EINVAL; -+ goto terminate_exit; -+ } -+ if (rotate_sp11_qspi && -+ (gpii->recovery_generation != gpii->retired_ev_ring_count || -+ gpii->recovery_generation != -+ gpii->gchan[GPI_TX_CHAN].retired_ring_count || -+ gpii->recovery_generation != -+ gpii->gchan[GPI_RX_CHAN].retired_ring_count)) { -+ dev_err(gpii->gpi_dev->dev, -+ "refusing SP11 QSPI recovery with incoherent generations: active=%u ev=%u tx=%u rx=%u\n", -+ gpii->recovery_generation, gpii->retired_ev_ring_count, -+ gpii->gchan[GPI_TX_CHAN].retired_ring_count, -+ gpii->gchan[GPI_RX_CHAN].retired_ring_count); -+ ret = -EUCLEAN; -+ goto terminate_exit; -+ } -+ -+ /* -+ * Allocate all three replacements before disturbing the active pair. -+ * Keeping every prior allocation alive makes transfer and event ring DMA -+ * addresses generation-unique until the channels are deallocated. -+ */ -+ if (rotate_sp11_qspi) { -+ generation = gpii->recovery_generation + 1; -+ for (i = schid; i < echid; i++) { -+ ret = gpi_prepare_fresh_ring(gpii, -+ &gpii->gchan[i].ch_ring, -+ gpii->gchan[i].retired_ring_count, -+ &replacement[i], -+ &retired[i]); -+ if (ret) { -+ dev_err(gpii->gpi_dev->dev, -+ "refusing SP11 QSPI recovery without a fresh ring: ch=%d ret=%d retired=%u\n", -+ i, ret, -+ gpii->gchan[i].retired_ring_count); -+ goto terminate_exit; -+ } -+ } -+ -+ ret = gpi_prepare_fresh_ring(gpii, &gpii->ev_ring, -+ gpii->retired_ev_ring_count, -+ &ev_replacement, &retired_ev); -+ if (ret) { -+ dev_err(gpii->gpi_dev->dev, -+ "refusing SP11 QSPI recovery without a fresh event ring: ret=%d retired=%u\n", -+ ret, gpii->retired_ev_ring_count); -+ goto terminate_exit; -+ } -+ } - - /* stop the channel */ - for (i = schid; i < echid; i++) { -@@ -1482,6 +1832,8 @@ static int gpi_terminate_all(struct dma_chan *chan) - - /* send command to Stop the channel */ - ret = gpi_stop_chan(gchan); -+ if (ret) -+ goto terminate_exit; - } - - /* reset the channels (clears any pending tre) */ -@@ -1493,8 +1845,57 @@ static int gpi_terminate_all(struct dma_chan *chan) - dev_err(gpii->gpi_dev->dev, "Error resetting channel ret:%d\n", ret); - goto terminate_exit; - } -+ } - -- /* reprogram channel CNTXT */ -+ if (rotate_sp11_qspi) { -+ /* -+ * Leave EV control and channel-control interrupts available for the -+ * reset command, but stop all transfer-event processing before the -+ * active event ring changes. -+ */ -+ ret = gpi_config_interrupts(gpii, MASK_IEOB_SETTINGS, 0); -+ if (ret) -+ goto terminate_exit; -+ ieob_disabled = true; -+ tasklet_kill(&gpii->ev_task); -+ -+ ret = gpi_send_cmd(gpii, NULL, GPI_EV_CMD_RESET); -+ if (ret) { -+ dev_err(gpii->gpi_dev->dev, -+ "Error resetting event channel ret:%d\n", ret); -+ goto terminate_exit; -+ } -+ -+ /* -+ * The event tasklet holds pm_lock for its whole ring walk. Publish -+ * the event and transfer rings under the matching writer lock so a -+ * validator sees one coherent recovery generation. -+ */ -+ write_lock_irq(&gpii->pm_lock); -+ gpii->recovery_generation = generation; -+ gpi_install_fresh_ev_ring(gpii, &ev_replacement, retired_ev, -+ generation); -+ retired_ev = NULL; -+ for (i = schid; i < echid; i++) { -+ gpi_install_fresh_chan_ring(&gpii->gchan[i], -+ &replacement[i], retired[i], -+ generation); -+ retired[i] = NULL; -+ } -+ write_unlock_irq(&gpii->pm_lock); -+ -+ /* EV RESET keeps the event channel allocated. */ -+ ret = gpi_config_ev_chan(gpii, false); -+ if (ret) { -+ dev_err(gpii->gpi_dev->dev, -+ "Error configuring fresh event ring ret:%d\n", ret); -+ goto terminate_exit; -+ } -+ } -+ -+ /* reprogram channel contexts, including any fresh transfer-ring bases */ -+ for (i = schid; i < echid; i++) { -+ gchan = &gpii->gchan[i]; - ret = gpi_alloc_chan(gchan, false); - if (ret) { - dev_err(gpii->gpi_dev->dev, "Error alloc_channel ret:%d\n", ret); -@@ -1514,6 +1915,19 @@ static int gpi_terminate_all(struct dma_chan *chan) - } - - terminate_exit: -+ if (ieob_disabled) { -+ /* Discard a status raised against the retired event queue. */ -+ gpi_write_reg(gpii, gpii->ieob_clr_reg, BIT(0)); -+ gpi_config_interrupts(gpii, MASK_IEOB_SETTINGS, 1); -+ } -+ if (ev_replacement.configured) -+ gpi_free_ring(&ev_replacement, gpii); -+ kfree(retired_ev); -+ for (i = schid; i < echid; i++) { -+ if (replacement[i].configured) -+ gpi_free_ring(&replacement[i], gpii); -+ kfree(retired[i]); -+ } - mutex_unlock(&gpii->ctrl_lock); - return ret; - } -@@ -1708,8 +2122,11 @@ static int gpi_create_spi_tre(struct gchan *chan, struct gpi_desc *desc, - dma_addr_t address; - struct gpi_tre *tre; - unsigned int i; -+ bool qspi; - int len; - -+ qspi = chan->protocol == QCOM_GPI_QSPI; -+ - /* first create config tre if applicable */ - if (direction == DMA_MEM_TO_DEV && spi->set_config) { - tre = &desc->tre[tre_idx]; -@@ -1729,6 +2146,8 @@ static int gpi_create_spi_tre(struct gchan *chan, struct gpi_desc *desc, - - tre->dword[3] = u32_encode_bits(TRE_TYPE_CONFIG0, TRE_FLAGS_TYPE); - tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_CHAIN); -+ if (qspi) -+ tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOB); - } - - /* create the GO tre for Tx */ -@@ -1739,12 +2158,16 @@ static int gpi_create_spi_tre(struct gchan *chan, struct gpi_desc *desc, - tre->dword[0] = u32_encode_bits(spi->fragmentation, TRE_SPI_GO_FRAG); - tre->dword[0] |= u32_encode_bits(spi->cs, TRE_SPI_GO_CS); - tre->dword[0] |= u32_encode_bits(spi->cmd, TRE_SPI_GO_CMD); -+ if (qspi) -+ tre->dword[0] |= TRE_QSPI_GO; - - tre->dword[1] = 0; - - tre->dword[2] = u32_encode_bits(spi->rx_len, TRE_RX_LEN); - - tre->dword[3] = u32_encode_bits(TRE_TYPE_GO, TRE_FLAGS_TYPE); -+ if (qspi) -+ tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOB); - if (spi->cmd == SPI_RX) { - tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOB); - tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_LINK); -@@ -1764,7 +2187,8 @@ static int gpi_create_spi_tre(struct gchan *chan, struct gpi_desc *desc, - len = sg_dma_len(sgl); - - /* Support Immediate dma for write transfers for data length up to 8 bytes */ -- if (direction == DMA_MEM_TO_DEV && len <= 2 * sizeof(tre->dword[0])) { -+ if (!qspi && direction == DMA_MEM_TO_DEV && -+ len <= 2 * sizeof(tre->dword[0])) { - /* - * For Immediate dma, data length may not always be length of 8 bytes, - * it can be length less than 8, hence initialize both dword's with 0 -@@ -1783,12 +2207,13 @@ static int gpi_create_spi_tre(struct gchan *chan, struct gpi_desc *desc, - tre->dword[3] = u32_encode_bits(TRE_TYPE_DMA, TRE_FLAGS_TYPE); - } - -- tre->dword[3] |= u32_encode_bits(direction == DMA_MEM_TO_DEV, -+ tre->dword[3] |= u32_encode_bits(direction == DMA_MEM_TO_DEV || qspi, - TRE_FLAGS_IEOT); - -- for (i = 0; i < tre_idx; i++) -+ for (i = 0; i < tre_idx; i++) { - dev_dbg(dev, "TRE:%d %x:%x:%x:%x\n", i, desc->tre[i].dword[0], - desc->tre[i].dword[1], desc->tre[i].dword[2], desc->tre[i].dword[3]); -+ } - - return tre_idx; - } -@@ -1841,7 +2266,7 @@ gpi_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - return NULL; - - /* create TREs for xfer */ -- if (gchan->protocol == QCOM_GPI_SPI) { -+ if (gpi_is_spi_protocol(gchan->protocol)) { - i = gpi_create_spi_tre(gchan, gpi_desc, sgl, direction); - } else if (gchan->protocol == QCOM_GPI_I2C) { - i = gpi_create_i2c_tre(gchan, gpi_desc, sgl, direction, flags); -@@ -1890,6 +2315,8 @@ static void gpi_issue_pending(struct dma_chan *chan) - for (i = 0; i < gpi_desc->num_tre; i++) { - tre = &gpi_desc->tre[i]; - gpi_queue_xfer(gpii, gchan, tre, &wp); -+ if (!i) -+ gpi_desc->first_tre = to_physical(ch_ring, wp); - } - - gpi_desc->db = ch_ring->wp; -@@ -1937,7 +2364,7 @@ static int gpi_ch_init(struct gchan *gchan) - } - - /* allocate event rings */ -- ret = gpi_alloc_ev_chan(gpii); -+ ret = gpi_config_ev_chan(gpii, true); - if (ret) { - dev_err(gpii->gpi_dev->dev, "error alloc_ev_chan:%d\n", ret); - goto error_alloc_ev_ring; -@@ -1951,7 +2378,6 @@ static int gpi_ch_init(struct gchan *gchan) - goto error_alloc_chan; - } - } -- - /* start channels */ - for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) { - ret = gpi_start_chan(&gpii->gchan[i]); -@@ -2009,6 +2435,7 @@ static void gpi_free_chan_resources(struct dma_chan *chan) - - /* free all allocated memory */ - gpi_free_ring(&gchan->ch_ring, gpii); -+ gpi_free_retired_rings(gchan); - vchan_free_chan_resources(&gchan->vc); - kfree(gchan->config); - -@@ -2035,6 +2462,7 @@ static void gpi_free_chan_resources(struct dma_chan *chan) - gpi_send_cmd(gpii, NULL, GPI_EV_CMD_DEALLOC); - - gpi_free_ring(&gpii->ev_ring, gpii); -+ gpi_free_retired_ev_rings(gpii); - - /* disable interrupts */ - if (cur_state == ACTIVE_STATE) -@@ -2054,12 +2482,17 @@ static int gpi_alloc_chan_resources(struct dma_chan *chan) - { - struct gchan *gchan = to_gchan(chan); - struct gpii *gpii = gchan->gpii; -+ u32 elements = CHAN_TRES; - int ret; - - mutex_lock(&gpii->ctrl_lock); - -+ /* SP11 QSPI requires a 16-element transfer ring for paired channels. */ -+ if (gpi_is_sp11_qspi_chan(gchan)) -+ elements = SP11_QSPI_CHAN_TRES; -+ - /* allocate memory for transfer ring */ -- ret = gpi_alloc_ring(&gchan->ch_ring, CHAN_TRES, -+ ret = gpi_alloc_ring(&gchan->ch_ring, elements, - sizeof(struct gpi_tre), gpii); - if (ret) - goto xfer_alloc_err; -@@ -2189,7 +2622,10 @@ static int gpi_probe(struct platform_device *pdev) - return ret; - } - -+ gpi_dev->sp11_qspi_quirk = of_machine_is_compatible("microsoft,denali"); -+ - ee_offset = (uintptr_t)device_get_match_data(gpi_dev->dev); -+ gpi_dev->ee_offset = ee_offset; - gpi_dev->ee_base = gpi_dev->ee_base - ee_offset; - - gpi_dev->ev_factor = EV_FACTOR; -diff --git a/drivers/hid/spi-hid/spi-hid-acpi.c b/drivers/hid/spi-hid/spi-hid-acpi.c -index 15cfc4e6cc2f..17bf943add50 100644 ---- a/drivers/hid/spi-hid/spi-hid-acpi.c -+++ b/drivers/hid/spi-hid/spi-hid-acpi.c -@@ -1,4 +1,4 @@ --// SPDX-License-Identifier: GPL-2.0 -+// SPDX-License-Identifier: GPL-2.0-only - /* - * HID over SPI protocol, ACPI related code - * -@@ -119,6 +119,16 @@ static int spi_hid_acpi_populate_config(struct spi_hid_acpi_config *conf, - } - ACPI_FREE(obj); - -+ obj = acpi_evaluate_dsm_typed(handle, &spi_hid_guid, 3, 6, NULL, -+ ACPI_TYPE_INTEGER); -+ if (!obj) { -+ acpi_handle_err(handle, -+ "Error _DSM call to get HID over SPI flags failed"); -+ return -ENODEV; -+ } -+ conf->property_conf.flags = obj->integer.value; -+ ACPI_FREE(obj); -+ - /* Value not provided in ACPI,*/ - conf->post_power_on_delay_ms = 5; - conf->minimal_reset_delay_ms = 150; -@@ -128,8 +138,6 @@ static int spi_hid_acpi_populate_config(struct spi_hid_acpi_config *conf, - return -EINVAL; - } - -- /* FIXME: not reading hid-over-spi-flags, multi-SPI not supported */ -- - return 0; - } - -diff --git a/drivers/hid/spi-hid/spi-hid-core.c b/drivers/hid/spi-hid/spi-hid-core.c -index 27f25d95ed28..e04810d03825 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.c -+++ b/drivers/hid/spi-hid/spi-hid-core.c -@@ -1,4 +1,4 @@ --// SPDX-License-Identifier: GPL-2.0 -+// SPDX-License-Identifier: GPL-2.0-only - /* - * HID over SPI protocol implementation - * -@@ -20,10 +20,12 @@ - * Copyright (c) 2006-2010 Jiri Kosina - */ - -+#include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -58,13 +60,18 @@ - #define SPI_HID_INPUT_HEADER_VERSION 0x03 - #define SPI_HID_SUPPORTED_VERSION 0x0300 - -+#define SPI_HID_FLAG_WRITE_MULTILANE BIT(13) -+#define SPI_HID_FLAG_MULTILANE_MODE GENMASK(15, 14) -+#define SPI_HID_MULTILANE_SINGLE 0 -+#define SPI_HID_MULTILANE_DUAL 1 -+#define SPI_HID_MULTILANE_QUAD 2 -+ - #define SPI_HID_OUTPUT_REPORT_CONTENT_ID_DESC_REQUEST 0x00 - - #define SPI_HID_MAX_RESET_ATTEMPTS 3 - #define SPI_HID_RESP_TIMEOUT 1000 - - /* Protocol message size constants */ --#define SPI_HID_READ_APPROVAL_LEN 5 - #define SPI_HID_OUTPUT_HEADER_LEN 8 - - /* flags */ -@@ -116,16 +123,50 @@ struct spi_hid_output_report { - - static struct hid_ll_driver spi_hid_ll_driver; - -+static int spi_hid_configure_bus(struct spi_hid *shid) -+{ -+ u16 mode = FIELD_GET(SPI_HID_FLAG_MULTILANE_MODE, shid->conf->flags); -+ struct spi_device *spi = shid->spi; -+ -+ switch (mode) { -+ case SPI_HID_MULTILANE_SINGLE: -+ shid->read_nbits = SPI_NBITS_SINGLE; -+ shid->read_approval_length = 5; -+ break; -+ case SPI_HID_MULTILANE_DUAL: -+ shid->read_nbits = SPI_NBITS_DUAL; -+ shid->read_approval_length = 6; -+ spi->mode |= SPI_TX_DUAL | SPI_RX_DUAL; -+ break; -+ case SPI_HID_MULTILANE_QUAD: -+ shid->read_nbits = SPI_NBITS_QUAD; -+ shid->read_approval_length = 8; -+ spi->mode |= SPI_TX_QUAD | SPI_RX_QUAD; -+ break; -+ default: -+ dev_err(&spi->dev, "Reserved HID over SPI multi-lane mode: %u\n", mode); -+ return -EINVAL; -+ } -+ -+ shid->write_nbits = shid->conf->flags & SPI_HID_FLAG_WRITE_MULTILANE ? -+ shid->read_nbits : SPI_NBITS_SINGLE; -+ -+ return spi_setup(spi); -+} -+ - static void spi_hid_populate_read_approvals(const struct spi_hid_conf *conf, -- u8 *header_buf, u8 *body_buf) -+ u8 *header_buf, u8 *body_buf, -+ u8 approval_length) - { - header_buf[0] = conf->read_opcode; - put_unaligned_be24(conf->input_report_header_address, &header_buf[1]); -- header_buf[4] = SPI_HID_READ_APPROVAL_CONSTANT; -+ memset(&header_buf[4], SPI_HID_READ_APPROVAL_CONSTANT, -+ approval_length - 4); - - body_buf[0] = conf->read_opcode; - put_unaligned_be24(conf->input_report_body_address, &body_buf[1]); -- body_buf[4] = SPI_HID_READ_APPROVAL_CONSTANT; -+ memset(&body_buf[4], SPI_HID_READ_APPROVAL_CONSTANT, -+ approval_length - 4); - } - - static void spi_hid_parse_dev_desc(const struct hidspi_dev_descriptor *raw, -@@ -187,26 +228,125 @@ static void spi_hid_populate_output_header(u8 *buf, - buf[7] = report->content_id; - } - -+static void spi_hid_free_input_dma(void *data) -+{ -+ struct spi_hid *shid = data; -+ -+ dma_free_coherent(shid->input_dma_dev, shid->input_dma_size, -+ shid->input_dma_buf, shid->input_dma); -+} -+ -+static struct device *spi_hid_input_dma_dev(struct spi_controller *ctlr) -+{ -+ if (ctlr->dma_rx) -+ return ctlr->dma_rx->device->dev; -+ if (ctlr->dma_map_dev) -+ return ctlr->dma_map_dev; -+ -+ return ctlr->dev.parent; -+} -+ -+static int spi_hid_grow_input_dma(struct spi_hid *shid, size_t size) -+{ -+ struct spi_controller *ctlr = shid->spi->controller; -+ struct device *dev = &shid->spi->dev; -+ void *input_dma_buf; -+ dma_addr_t input_dma; -+ int error; -+ -+ if (size <= shid->input_dma_size) -+ return 0; -+ -+ if (!shid->input_dma_dev) -+ shid->input_dma_dev = spi_hid_input_dma_dev(ctlr); -+ if (!shid->input_dma_dev) -+ return dev_err_probe(dev, -ENODEV, -+ "RX DMA mapping device unavailable\n"); -+ -+ input_dma_buf = dma_alloc_coherent(shid->input_dma_dev, size, -+ &input_dma, GFP_KERNEL); -+ if (!input_dma_buf) -+ return dev_err_probe(dev, -ENOMEM, -+ "coherent input allocation failed\n"); -+ -+ if (shid->input_dma_buf) { -+ dma_free_coherent(shid->input_dma_dev, shid->input_dma_size, -+ shid->input_dma_buf, shid->input_dma); -+ } else { -+ error = devm_add_action(dev, spi_hid_free_input_dma, shid); -+ if (error) { -+ dma_free_coherent(shid->input_dma_dev, size, -+ input_dma_buf, input_dma); -+ return error; -+ } -+ } -+ -+ shid->input_dma_buf = input_dma_buf; -+ shid->input_dma = input_dma; -+ shid->input_dma_size = size; -+ -+ return 0; -+} -+ -+static int spi_hid_validate_input_target(struct spi_hid *shid, void *buf, -+ u16 length, bool is_header) -+{ -+ size_t bufsize; -+ -+ if (is_header) { -+ if (buf != shid->input->header || -+ length != sizeof(shid->input->header)) -+ return -EINVAL; -+ bufsize = sizeof(shid->input->header); -+ } else { -+ if (buf != shid->input->body) -+ return -EINVAL; -+ bufsize = HIDSPI_INPUT_BODY_SIZE(shid->bufsize); -+ } -+ -+ if (length > bufsize || length > shid->input_dma_size) -+ return -EMSGSIZE; -+ -+ return 0; -+} -+ - static int spi_hid_input_sync(struct spi_hid *shid, void *buf, u16 length, - bool is_header) - { -+ void *rx_buf = shid->input_dma_buf; - int error; - -+ error = spi_hid_validate_input_target(shid, buf, length, is_header); -+ if (error) { -+ dev_err(&shid->spi->dev, -+ "Invalid input target or length %u: %d\n", length, error); -+ return error; -+ } -+ memset(rx_buf, 0, length); -+ - shid->input_transfer[0].tx_buf = is_header ? - shid->read_approval_header : - shid->read_approval_body; -- shid->input_transfer[0].len = SPI_HID_READ_APPROVAL_LEN; -+ shid->input_transfer[0].len = 1; -+ shid->input_transfer[0].tx_nbits = SPI_NBITS_SINGLE; - -- shid->input_transfer[1].rx_buf = buf; -- shid->input_transfer[1].len = length; -+ shid->input_transfer[1].tx_buf = shid->input_transfer[0].tx_buf + 1; -+ shid->input_transfer[1].len = shid->read_approval_length - 1; -+ shid->input_transfer[1].tx_nbits = shid->read_nbits; -+ -+ shid->input_transfer[2].rx_buf = rx_buf; -+ shid->input_transfer[2].len = length; -+ shid->input_transfer[2].rx_nbits = shid->read_nbits; -+ shid->input_transfer[2].rx_dma = shid->input_dma; -+ shid->input_transfer[2].rx_dma_coherent = true; - - spi_message_init_with_transfers(&shid->input_message, -- shid->input_transfer, 2); -+ shid->input_transfer, 3); - - trace_spi_hid_input_sync(shid, shid->input_transfer[0].tx_buf, -- shid->input_transfer[0].len, -- shid->input_transfer[1].rx_buf, -- shid->input_transfer[1].len, 0); -+ shid->read_approval_length, -+ shid->input_transfer[2].rx_buf, -+ shid->input_transfer[2].len, 0); - - error = spi_sync(shid->spi, &shid->input_message); - if (error) { -@@ -215,15 +355,28 @@ static int spi_hid_input_sync(struct spi_hid *shid, void *buf, u16 length, - shid->bus_last_error = error; - return error; - } -+ memcpy(buf, rx_buf, length); - - return 0; - } - - static int spi_hid_output(struct spi_hid *shid, const void *buf, u16 length) - { -+ struct spi_transfer xfers[2] = { -+ { -+ .tx_buf = buf, -+ .len = 1, -+ .tx_nbits = SPI_NBITS_SINGLE, -+ }, -+ { -+ .tx_buf = (const u8 *)buf + 1, -+ .len = length - 1, -+ .tx_nbits = shid->write_nbits, -+ }, -+ }; - int error; - -- error = spi_write(shid->spi, buf, length); -+ error = spi_sync_transfer(shid->spi, xfers, ARRAY_SIZE(xfers)); - - if (error) { - shid->bus_error_count++; -@@ -901,9 +1054,9 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - - trace_spi_hid_input_header_complete(shid, - shid->input_transfer[0].tx_buf, -- shid->input_transfer[0].len, -- shid->input_transfer[1].rx_buf, -- shid->input_transfer[1].len, -+ shid->read_approval_length, -+ shid->input_transfer[2].rx_buf, -+ shid->input_transfer[2].len, - shid->input_message.status); - - if (shid->input_message.status < 0) { -@@ -943,9 +1096,9 @@ static irqreturn_t spi_hid_dev_irq(int irq, void *_shid) - } - - trace_spi_hid_input_body_complete(shid, shid->input_transfer[0].tx_buf, -- shid->input_transfer[0].len, -- shid->input_transfer[1].rx_buf, -- shid->input_transfer[1].len, -+ shid->read_approval_length, -+ shid->input_transfer[2].rx_buf, -+ shid->input_transfer[2].len, - shid->input_message.status); - - if (shid->input_message.status < 0) { -@@ -978,6 +1131,7 @@ static int spi_hid_alloc_buffers(struct spi_hid *shid, size_t report_size) - int inbufsize = round_up(sizeof(shid->input->header) + - sizeof(shid->input->body) + report_size, 4); - int outbufsize = round_up(sizeof(shid->output->header) + report_size, 4); -+ int error; - void *tmp; - - tmp = devm_krealloc(dev, shid->output, outbufsize, GFP_KERNEL | __GFP_ZERO); -@@ -998,6 +1152,11 @@ static int spi_hid_alloc_buffers(struct spi_hid *shid, size_t report_size) - if (!shid->output || !shid->input || !shid->response) - return -ENOMEM; - -+ error = spi_hid_grow_input_dma(shid, -+ HIDSPI_INPUT_BODY_SIZE(report_size)); -+ if (error) -+ return error; -+ - shid->bufsize = report_size; - - return 0; -@@ -1149,6 +1308,10 @@ static int spi_hid_ll_raw_request(struct hid_device *hid, - struct spi_hid *shid = spi_get_drvdata(spi); - struct device *dev = &spi->dev; - int ret; -+ size_t content_len; -+ -+ if (!len) -+ return -EINVAL; - - switch (reqtype) { - case HID_REQ_SET_REPORT: -@@ -1173,10 +1336,18 @@ static int spi_hid_ll_raw_request(struct hid_device *hid, - return ret; - } - -- ret = min_t(size_t, len, -- (shid->response->body[1] | (shid->response->body[2] << 8)) + 1); -- buf[0] = shid->response->body[3]; -- memcpy(&buf[1], &shid->response->content, ret); -+ if (shid->response->body[3] != reportnum) { -+ dev_err(dev, -+ "get report id mismatch: expected 0x%02x, got 0x%02x\n", -+ reportnum, shid->response->body[3]); -+ return -EPROTO; -+ } -+ -+ /* Leave room for the report ID at buf[0]. */ -+ content_len = min_t(size_t, len - 1, shid->response_length); -+ buf[0] = reportnum; -+ memcpy(buf + 1, shid->response->content, content_len); -+ ret = content_len + 1; - break; - default: - dev_err(dev, "invalid request type\n"); -@@ -1402,11 +1573,16 @@ int spi_hid_core_probe(struct spi_device *spi, struct spihid_ops *ops, - set_bit(SPI_HID_RESET_PENDING, &shid->flags); - shid->is_panel_follower = drm_is_panel_follower(&spi->dev); - -+ error = spi_hid_configure_bus(shid); -+ if (error) -+ return dev_err_probe(dev, error, "Failed to configure SPI bus width\n"); -+ - spi_set_drvdata(spi, shid); - - /* Using now populated conf let's pre-calculate the read approvals */ - spi_hid_populate_read_approvals(shid->conf, shid->read_approval_header, -- shid->read_approval_body); -+ shid->read_approval_body, -+ shid->read_approval_length); - - mutex_init(&shid->output_lock); - mutex_init(&shid->power_lock); -diff --git a/drivers/hid/spi-hid/spi-hid-core.h b/drivers/hid/spi-hid/spi-hid-core.h -index 261b2fd7f332..ffe3e4b231e1 100644 ---- a/drivers/hid/spi-hid/spi-hid-core.h -+++ b/drivers/hid/spi-hid/spi-hid-core.h -@@ -1,4 +1,4 @@ --/* SPDX-License-Identifier: GPL-2.0 */ -+/* SPDX-License-Identifier: GPL-2.0-only */ - /* - * Copyright (c) 2021 Microsoft Corporation - * Copyright (c) 2026 Google LLC -@@ -13,7 +13,7 @@ - #include - - /* Protocol message size constants */ --#define SPI_HID_READ_APPROVAL_LEN 5 -+#define SPI_HID_READ_APPROVAL_MAX_LEN 8 - #define SPI_HID_OUTPUT_HEADER_LEN 8 - - /* Raw input buffer with data from the bus */ -@@ -47,7 +47,7 @@ struct spi_hid { - struct spi_device *spi; /* spi device. */ - struct hid_device *hid; /* pointer to corresponding HID dev. */ - -- struct spi_transfer input_transfer[2]; /* Transfer buffer for read and write. */ -+ struct spi_transfer input_transfer[3]; /* Transfers for read approval and data. */ - struct spi_message input_message; /* used to execute a sequence of spi transfers. */ - - struct spihid_ops *ops; -@@ -57,6 +57,10 @@ struct spi_hid { - struct spi_hid_output_buf *output; /* Output buffer. */ - struct spi_hid_input_buf *input; /* Input buffer. */ - struct spi_hid_input_buf *response; /* Response buffer. */ -+ struct device *input_dma_dev; -+ void *input_dma_buf; -+ dma_addr_t input_dma; -+ size_t input_dma_size; - - struct drm_panel_follower panel_follower; - bool is_panel_follower; -@@ -83,8 +87,11 @@ struct spi_hid { - - struct completion output_done; - -- u8 read_approval_header[SPI_HID_READ_APPROVAL_LEN]; -- u8 read_approval_body[SPI_HID_READ_APPROVAL_LEN]; -+ u8 read_approval_header[SPI_HID_READ_APPROVAL_MAX_LEN]; -+ u8 read_approval_body[SPI_HID_READ_APPROVAL_MAX_LEN]; -+ u8 read_approval_length; -+ u8 read_nbits; -+ u8 write_nbits; - - u32 report_descriptor_crc32; /* HID report descriptor crc32 checksum. */ - -diff --git a/drivers/hid/spi-hid/spi-hid-of.c b/drivers/hid/spi-hid/spi-hid-of.c -index 561cf453e44a..804988cab931 100644 ---- a/drivers/hid/spi-hid/spi-hid-of.c -+++ b/drivers/hid/spi-hid/spi-hid-of.c -@@ -1,4 +1,4 @@ --// SPDX-License-Identifier: GPL-2.0 -+// SPDX-License-Identifier: GPL-2.0-only - /* - * HID over SPI protocol, Open Firmware related code - * -@@ -43,11 +43,11 @@ struct spi_hid_of_config { - struct gpio_desc *reset_gpio; - struct regulator *supply; - bool supply_enabled; -- u16 hid_over_spi_flags; - }; - - static const struct spi_hid_timing_data timing_data = { -- .post_power_on_delay_ms = 10, -+ /* Allow the controller to finish its power-on debounce interval. */ -+ .post_power_on_delay_ms = 1000, - .minimal_reset_delay_ms = 100, - }; - -@@ -56,6 +56,7 @@ static int spi_hid_of_populate_config(struct spi_hid_of_config *conf, - { - int error; - u32 val; -+ u8 opcode; - - error = device_property_read_u32(dev, "input-report-header-address", - &val); -@@ -79,19 +80,31 @@ static int spi_hid_of_populate_config(struct spi_hid_of_config *conf, - } - conf->property_conf.output_report_address = val; - -- error = device_property_read_u32(dev, "read-opcode", &val); -+ error = device_property_read_u8(dev, "read-opcode", &opcode); - if (error) { - dev_err(dev, "Read opcode not provided."); - return -ENODEV; - } -- conf->property_conf.read_opcode = val; -+ conf->property_conf.read_opcode = opcode; - -- error = device_property_read_u32(dev, "write-opcode", &val); -+ error = device_property_read_u8(dev, "write-opcode", &opcode); - if (error) { - dev_err(dev, "Write opcode not provided."); - return -ENODEV; - } -- conf->property_conf.write_opcode = val; -+ conf->property_conf.write_opcode = opcode; -+ -+ error = device_property_read_u32(dev, "hid-over-spi-flags", &val); -+ if (!error) { -+ if (val > U16_MAX) { -+ dev_err(dev, "HID over SPI flags exceed 16 bits."); -+ return -EINVAL; -+ } -+ conf->property_conf.flags = val; -+ } else if (error != -EINVAL && error != -ENODATA) { -+ return dev_err_probe(dev, error, -+ "Failed to read HID over SPI flags.\n"); -+ } - - conf->supply = devm_regulator_get(dev, "vdd"); - if (IS_ERR(conf->supply)) { -@@ -102,7 +115,8 @@ static int spi_hid_of_populate_config(struct spi_hid_of_config *conf, - } - conf->supply_enabled = false; - -- conf->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); -+ /* Keep an active-low reset asserted from the moment it is acquired. */ -+ conf->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(conf->reset_gpio)) { - dev_err(dev, "%s: error getting reset GPIO.", __func__); - return PTR_ERR(conf->reset_gpio); -@@ -198,12 +212,6 @@ static int spi_hid_of_probe(struct spi_device *spi) - if (!config->timing_data) - config->timing_data = &timing_data; - -- /* -- * FIXME: hid_over_spi_flags could be retrieved from spi mode. -- * It is always 0 because multi-SPI not supported. -- */ -- config->hid_over_spi_flags = 0; -- - error = spi_hid_of_populate_config(config, dev); - if (error) { - dev_err(dev, "%s: unable to populate config data.", __func__); -@@ -222,6 +230,7 @@ MODULE_DEVICE_TABLE(of, spi_hid_of_match); - static const struct spi_device_id spi_hid_of_id_table[] = { - { "hid", 0 }, - { "hid-over-spi", 0 }, -+ { "microsoft,g6-touch-digitizer", 0 }, - { } - }; - MODULE_DEVICE_TABLE(spi, spi_hid_of_id_table); -diff --git a/drivers/hid/spi-hid/spi-hid-trace.h b/drivers/hid/spi-hid/spi-hid-trace.h -index 841ec491826d..bbf7a1bf2007 100644 ---- a/drivers/hid/spi-hid/spi-hid-trace.h -+++ b/drivers/hid/spi-hid/spi-hid-trace.h -@@ -1,4 +1,4 @@ --/* SPDX-License-Identifier: GPL-2.0 */ -+/* SPDX-License-Identifier: GPL-2.0-only */ - /* - * Copyright (c) 2021 Microsoft Corporation - */ -diff --git a/drivers/hid/spi-hid/spi-hid.h b/drivers/hid/spi-hid/spi-hid.h -index 17b2fdf192ed..c5c25f1934d0 100644 ---- a/drivers/hid/spi-hid/spi-hid.h -+++ b/drivers/hid/spi-hid/spi-hid.h -@@ -1,4 +1,4 @@ --/* SPDX-License-Identifier: GPL-2.0 */ -+/* SPDX-License-Identifier: GPL-2.0-only */ - /* - * Copyright (c) 2021 Microsoft Corporation - * Copyright (c) 2026 Google LLC -@@ -15,6 +15,7 @@ struct spi_hid_conf { - u32 input_report_header_address; - u32 input_report_body_address; - u32 output_report_address; -+ u16 flags; - u8 read_opcode; - u8 write_opcode; - }; -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 2192e4e6389a..7b42e0038eb0 100644 ---- a/drivers/platform/surface/surface_aggregator_registry.c -+++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -421,7 +421,9 @@ static const struct software_node *ssam_node_group_sp11[] = { - &ssam_node_hub_kip, - &ssam_node_bat_ac, - &ssam_node_bat_main, -+ &ssam_node_tmp_perf_profile_with_fan, - &ssam_node_tmp_sensors, -+ &ssam_node_fan_speed, - &ssam_node_hid_kip_keyboard, - &ssam_node_hid_kip_penstash, - &ssam_node_hid_kip_touchpad, -diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c -index 107fa2057654..9640c66ec8b6 100644 ---- a/drivers/soc/qcom/qcom-geni-se.c -+++ b/drivers/soc/qcom/qcom-geni-se.c -@@ -117,7 +117,15 @@ struct geni_se_desc { - static const char * const icc_path_names[] = {"qup-core", "qup-config", - "qup-memory"}; - --static const char * const protocol_name[] = { "None", "SPI", "UART", "I2C", "I3C", "SPI SLAVE" }; -+static const char * const protocol_name[] = { -+ [GENI_SE_NONE] = "None", -+ [GENI_SE_SPI] = "SPI", -+ [GENI_SE_UART] = "UART", -+ [GENI_SE_I2C] = "I2C", -+ [GENI_SE_I3C] = "I3C", -+ [GENI_SE_SPI_SLAVE] = "SPI SLAVE", -+ [GENI_SE_QSPI] = "QSPI", -+}; - - /** - * struct se_fw_hdr - Serial Engine firmware configuration header -@@ -1552,7 +1560,7 @@ int geni_load_se_firmware(struct geni_se *se, enum geni_se_protocol_type protoco - enum geni_se_xfer_mode mode = GENI_SE_FIFO; - int ret; - -- if (protocol >= ARRAY_SIZE(protocol_name)) { -+ if (protocol >= ARRAY_SIZE(protocol_name) || !protocol_name[protocol]) { - dev_err(se->dev, "Invalid geni-se protocol: %d", protocol); - return -EINVAL; - } -diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c -index 1fd9cf6e30f7..051d6ad6d180 100644 ---- a/drivers/spi/spi-geni-qcom.c -+++ b/drivers/spi/spi-geni-qcom.c -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -19,8 +20,12 @@ - #include - #include - #include -+#include - - /* SPI SE specific registers and respective register fields */ -+#define GENI_SE_QSPI_PRELOADED 9 -+#define QSPI_TX_POLL_TIMEOUT_US 10 -+ - #define SE_SPI_CPHA 0x224 - #define CPHA BIT(0) - -@@ -38,9 +43,14 @@ - #define SE_SPI_DEMUX_SEL 0x250 - #define CS_DEMUX_OUTPUT_SEL GENMASK(3, 0) - -+#define SE_GENI_BYTE_GRAN 0x254 -+ - #define SE_SPI_TRANS_CFG 0x25c - #define CS_TOGGLE BIT(1) - -+#define SE_GENI_TX_PACKING_CFG0 0x260 -+#define SE_GENI_TX_PACKING_CFG1 0x264 -+ - #define SE_SPI_WORD_LEN 0x268 - #define WORD_LEN_MSK GENMASK(9, 0) - #define MIN_WORD_LEN 4 -@@ -56,6 +66,9 @@ - #define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10) - #define SPI_CS_CLK_DELAY_SHFT 10 - -+#define SE_GENI_RX_PACKING_CFG0 0x284 -+#define SE_GENI_RX_PACKING_CFG1 0x288 -+ - #define SE_SPI_SLAVE_EN (0x2BC) - #define SPI_SLAVE_EN BIT(0) - -@@ -102,11 +115,94 @@ struct spi_geni_master { - int irq; - bool cs_flag; - bool abort_failed; -+ bool is_qspi; -+ struct spi_transfer *qspi_linked_rx; - struct dma_chan *tx; - struct dma_chan *rx; - int cur_xfer_mode; - }; - -+static bool spi_geni_qspi_has_transfer_controls(const struct spi_transfer *xfer) -+{ -+ return xfer->cs_change || xfer->cs_off || xfer->delay.value || -+ xfer->cs_change_delay.value || xfer->word_delay.value || -+ xfer->dtr_mode; -+} -+ -+/* -+ * Protocol-9 QSPI consumes a complete TX phase as one GENI command. The -+ * firmware sends the first byte on one lane and the rest on four lanes. The -+ * generic SPI representation uses two adjacent transfers to describe that -+ * lane transition, so join the physically contiguous HID-over-SPI buffers -+ * before the core maps or submits them. -+ */ -+static int spi_geni_qspi_optimize_message(struct spi_message *msg) -+{ -+ struct spi_transfer *opcode, *payload, *response = NULL; -+ -+ if (list_empty(&msg->transfers)) -+ return -EINVAL; -+ -+ opcode = list_first_entry(&msg->transfers, struct spi_transfer, -+ transfer_list); -+ if (list_is_last(&opcode->transfer_list, &msg->transfers)) -+ return -EINVAL; -+ -+ payload = list_next_entry(opcode, transfer_list); -+ if (!list_is_last(&payload->transfer_list, &msg->transfers)) { -+ response = list_next_entry(payload, transfer_list); -+ if (!list_is_last(&response->transfer_list, &msg->transfers)) -+ return -EINVAL; -+ } -+ -+ if (!opcode->tx_buf || opcode->rx_buf || opcode->len != 1 || -+ opcode->bits_per_word != 8 || -+ opcode->tx_nbits != SPI_NBITS_SINGLE || opcode->rx_nbits || -+ spi_geni_qspi_has_transfer_controls(opcode)) -+ return -EINVAL; -+ -+ if (!payload->tx_buf || payload->rx_buf || !payload->len || -+ payload->tx_nbits != SPI_NBITS_QUAD || payload->rx_nbits || -+ spi_geni_qspi_has_transfer_controls(payload) || -+ opcode->bits_per_word != payload->bits_per_word || -+ opcode->speed_hz != payload->speed_hz || -+ (const u8 *)opcode->tx_buf + opcode->len != payload->tx_buf || -+ payload->len > UINT_MAX - opcode->len) -+ return -EINVAL; -+ -+ if (response && -+ (response->tx_buf || !response->rx_buf || !response->len || -+ response->tx_nbits || response->rx_nbits != SPI_NBITS_QUAD || -+ spi_geni_qspi_has_transfer_controls(response) || -+ response->bits_per_word != opcode->bits_per_word || -+ response->speed_hz != opcode->speed_hz)) -+ return -EINVAL; -+ -+ msg->opt_state = payload; -+ -+ opcode->len += payload->len; -+ opcode->tx_nbits = SPI_NBITS_QUAD; -+ list_del_init(&payload->transfer_list); -+ -+ return 0; -+} -+ -+static int spi_geni_qspi_unoptimize_message(struct spi_message *msg) -+{ -+ struct spi_transfer *opcode, *payload = msg->opt_state; -+ -+ if (!payload) -+ return 0; -+ -+ opcode = list_first_entry(&msg->transfers, struct spi_transfer, -+ transfer_list); -+ opcode->len = 1; -+ opcode->tx_nbits = SPI_NBITS_SINGLE; -+ list_add(&payload->transfer_list, &opcode->transfer_list); -+ -+ return 0; -+} -+ - static void spi_slv_setup(struct spi_geni_master *mas) - { - struct geni_se *se = &mas->se; -@@ -169,7 +265,6 @@ static void handle_se_timeout(struct spi_controller *spi) - geni_se_cancel_m_cmd(se); - - spin_unlock_irq(&mas->lock); -- - time_left = wait_for_completion_timeout(&mas->cancel_done, HZ); - if (time_left) - goto reset_if_dma; -@@ -228,14 +323,18 @@ static void handle_gpi_timeout(struct spi_controller *spi) - { - struct spi_geni_master *mas = spi_controller_get_devdata(spi); - -+ /* QSPI GPI resets its paired TX/RX channels as one group. */ - dmaengine_terminate_sync(mas->tx); -- dmaengine_terminate_sync(mas->rx); -+ if (!mas->is_qspi) -+ dmaengine_terminate_sync(mas->rx); - } - - static void spi_geni_handle_err(struct spi_controller *spi, struct spi_message *msg) - { - struct spi_geni_master *mas = spi_controller_get_devdata(spi); - -+ mas->qspi_linked_rx = NULL; -+ - switch (mas->cur_xfer_mode) { - case GENI_SE_FIFO: - case GENI_SE_DMA: -@@ -407,6 +506,9 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas - struct dma_slave_config config = {}; - struct gpi_spi_config peripheral = {}; - struct dma_async_tx_descriptor *tx_desc, *rx_desc; -+ struct spi_transfer *rx_xfer = xfer; -+ struct spi_message *msg = spi->cur_msg; -+ bool qspi_linked = false; - int ret; - - config.peripheral_config = &peripheral; -@@ -419,7 +521,16 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas - mas->cur_speed_hz = xfer->speed_hz; - } - -- if (xfer->tx_buf && xfer->rx_buf) { -+ if (mas->is_qspi && msg->opt_state && -+ xfer == list_first_entry(&msg->transfers, struct spi_transfer, -+ transfer_list) && -+ !list_is_last(&xfer->transfer_list, &msg->transfers)) { -+ rx_xfer = list_next_entry(xfer, transfer_list); -+ qspi_linked = true; -+ peripheral.cmd = SPI_TX_RX; -+ peripheral.rx_len = rx_xfer->len * BITS_PER_BYTE / -+ rx_xfer->bits_per_word; -+ } else if (xfer->tx_buf && xfer->rx_buf) { - peripheral.cmd = SPI_DUPLEX; - } else if (xfer->tx_buf) { - peripheral.cmd = SPI_TX; -@@ -456,12 +567,22 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas - * (e.g. TPM TIS SPI uses cs_change=1 on single-transfer messages to - * keep CS asserted across header, wait-state and data phases) - */ -- peripheral.fragmentation = list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers) ? -- xfer->cs_change : !xfer->cs_change; -+ peripheral.fragmentation = qspi_linked ? false : -+ list_is_last(&xfer->transfer_list, &msg->transfers) ? -+ xfer->cs_change : !xfer->cs_change; - -- if (peripheral.cmd & SPI_RX) { -+ if (qspi_linked) { -+ if (!rx_xfer->rx_sg_mapped) -+ return -EINVAL; -+ if (!rx_xfer->rx_dma_coherent) -+ dma_sync_sgtable_for_device(spi->cur_rx_dma_dev, -+ &rx_xfer->rx_sg, -+ DMA_FROM_DEVICE); -+ } else if (peripheral.cmd & SPI_RX) { - dmaengine_slave_config(mas->rx, &config); -- rx_desc = dmaengine_prep_slave_sg(mas->rx, xfer->rx_sg.sgl, xfer->rx_sg.nents, -+ rx_desc = dmaengine_prep_slave_sg(mas->rx, -+ rx_xfer->rx_sg.sgl, -+ rx_xfer->rx_sg.nents, - DMA_DEV_TO_MEM, flags); - if (!rx_desc) { - dev_err(mas->dev, "Err setting up rx desc\n"); -@@ -481,12 +602,31 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas - return -EIO; - } - -- tx_desc->callback_result = spi_gsi_callback_result; -- tx_desc->callback_param = spi; -+ if (qspi_linked) { -+ dmaengine_slave_config(mas->rx, &config); -+ rx_desc = dmaengine_prep_slave_sg(mas->rx, -+ rx_xfer->rx_sg.sgl, -+ rx_xfer->rx_sg.nents, -+ DMA_DEV_TO_MEM, flags); -+ if (!rx_desc) { -+ dev_err(mas->dev, "Err setting up rx desc\n"); -+ return -EIO; -+ } -+ } -+ -+ if (qspi_linked) { -+ rx_desc->callback_result = spi_gsi_callback_result; -+ rx_desc->callback_param = spi; -+ } else { -+ tx_desc->callback_result = spi_gsi_callback_result; -+ tx_desc->callback_param = spi; -+ } - - if (peripheral.cmd & SPI_RX) - dmaengine_submit(rx_desc); - dmaengine_submit(tx_desc); -+ if (qspi_linked) -+ mas->qspi_linked_rx = rx_xfer; - - if (peripheral.cmd & SPI_RX) - dma_async_issue_pending(mas->rx); -@@ -518,6 +658,10 @@ static bool geni_can_dma(struct spi_controller *ctlr, - if (mas->cur_xfer_mode == GENI_GPI_DMA) - return true; - -+ /* Protocol-9 QSPI must use its paired GPI channels. */ -+ if (mas->is_qspi) -+ return false; -+ - /* Set SE DMA mode for SPI target. */ - if (ctlr->target) - return true; -@@ -537,6 +681,8 @@ static int spi_geni_prepare_message(struct spi_controller *spi, - struct spi_geni_master *mas = spi_controller_get_devdata(spi); - int ret; - -+ mas->qspi_linked_rx = NULL; -+ - switch (mas->cur_xfer_mode) { - case GENI_SE_FIFO: - case GENI_SE_DMA: -@@ -609,8 +755,8 @@ static int spi_geni_init(struct spi_geni_master *mas) - { - struct spi_controller *spi = dev_get_drvdata(mas->dev); - struct geni_se *se = &mas->se; -- unsigned int proto, major, minor, ver; -- u32 spi_tx_cfg, fifo_disable; -+ unsigned int proto, expected_proto, major, minor, ver; -+ u32 fw_rev, spi_tx_cfg, fifo_disable; - int ret = -ENXIO; - - PM_RUNTIME_ACQUIRE_IF_ENABLED(mas->dev, pm); -@@ -620,7 +766,9 @@ static int spi_geni_init(struct spi_geni_master *mas) - return ret; - } - -- proto = geni_se_read_proto(se); -+ fw_rev = readl_relaxed(se->base + GENI_FW_REVISION_RO); -+ proto = FIELD_GET(FW_REV_PROTOCOL_MSK, fw_rev); -+ expected_proto = mas->is_qspi ? GENI_SE_QSPI_PRELOADED : GENI_SE_SPI; - - if (spi->target) { - if (proto != GENI_SE_SPI_SLAVE) { -@@ -629,19 +777,33 @@ static int spi_geni_init(struct spi_geni_master *mas) - } - spi_slv_setup(mas); - } else if (proto == GENI_SE_INVALID_PROTO) { -- ret = geni_load_se_firmware(se, GENI_SE_SPI); -- if (ret) { -- dev_err(mas->dev, "spi master firmware load failed ret: %d\n", ret); -+ if (mas->is_qspi) { -+ dev_err(mas->dev, "preloaded protocol-9 QSPI firmware is absent\n"); - return ret; - } -- } else if (proto != GENI_SE_SPI) { -- dev_err(mas->dev, "Invalid proto %d\n", proto); -- return -EINVAL; -+ -+ ret = geni_load_se_firmware(se, GENI_SE_SPI); -+ if (ret) { -+ dev_err(mas->dev, "SPI firmware load failed ret: %d\n", ret); -+ return ret; -+ } -+ proto = GENI_SE_SPI; -+ } else if (proto != expected_proto) { -+ dev_err(mas->dev, "Invalid proto %d, expected %d\n", -+ proto, expected_proto); -+ return ret; - } -+ - mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se); - - /* Width of Tx and Rx FIFO is same */ - mas->fifo_width_bits = geni_se_get_tx_fifo_width(se); -+ fifo_disable = readl(se->base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; -+ -+ if (mas->tx_fifo_depth < 3 || !mas->fifo_width_bits) { -+ dev_err(mas->dev, "invalid FIFO capabilities\n"); -+ return ret; -+ } - - /* - * Hardware programming guide suggests to configure -@@ -659,7 +821,21 @@ static int spi_geni_init(struct spi_geni_master *mas) - else - mas->oversampling = 1; - -- fifo_disable = readl(se->base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; -+ /* -+ * Protocol-9 QSPI needs its paired GPI channels. Select the GPI event -+ * route and retain that mode for every transfer. -+ */ -+ if (mas->is_qspi) { -+ ret = spi_geni_grab_gpi_chan(mas); -+ if (ret) -+ return ret; -+ -+ mas->cur_xfer_mode = GENI_GPI_DMA; -+ geni_se_select_mode(se, GENI_GPI_DMA); -+ ret = 0; -+ goto configure_cs; -+ } -+ - switch (fifo_disable) { - case 1: - ret = spi_geni_grab_gpi_chan(mas); -@@ -691,6 +867,7 @@ static int spi_geni_init(struct spi_geni_master *mas) - break; - } - -+configure_cs: - /* We never control CS manually */ - if (!spi->target) { - spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); -@@ -719,7 +896,10 @@ static bool geni_spi_handle_tx(struct spi_geni_master *mas) - { - struct geni_se *se = &mas->se; - unsigned int max_bytes; -+ bool final_chunk; -+ bool adjacent_qspi_stores; - const u8 *tx_buf; -+ u32 adjacent_words[2]; - unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); - unsigned int i = 0; - -@@ -732,8 +912,27 @@ static bool geni_spi_handle_tx(struct spi_geni_master *mas) - max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word; - if (mas->tx_rem_bytes < max_bytes) - max_bytes = mas->tx_rem_bytes; -- -+ final_chunk = mas->tx_rem_bytes <= max_bytes; - tx_buf = mas->cur_xfer->tx_buf + mas->cur_xfer->len - mas->tx_rem_bytes; -+ adjacent_qspi_stores = mas->is_qspi && final_chunk && -+ bytes_per_fifo_word == sizeof(u32) && -+ max_bytes == sizeof(adjacent_words); -+ if (adjacent_qspi_stores) { -+ adjacent_words[0] = get_unaligned_le32(tx_buf); -+ adjacent_words[1] = get_unaligned_le32(tx_buf + sizeof(u32)); -+ } -+ -+ /* Protocol-9 clears the final watermark before filling the FIFO. */ -+ if (mas->is_qspi && final_chunk) -+ writel(0, se->base + SE_GENI_TX_WATERMARK_REG); -+ -+ if (adjacent_qspi_stores) { -+ /* Keep both final FIFO words adjacent to avoid a QSPI underrun. */ -+ writel_relaxed(adjacent_words[0], se->base + SE_GENI_TX_FIFOn); -+ writel_relaxed(adjacent_words[1], se->base + SE_GENI_TX_FIFOn); -+ i = max_bytes; -+ } -+ - while (i < max_bytes) { - unsigned int j; - unsigned int bytes_to_write; -@@ -747,7 +946,8 @@ static bool geni_spi_handle_tx(struct spi_geni_master *mas) - } - mas->tx_rem_bytes -= max_bytes; - if (!mas->tx_rem_bytes) { -- writel(0, se->base + SE_GENI_TX_WATERMARK_REG); -+ if (!mas->is_qspi) -+ writel(0, se->base + SE_GENI_TX_WATERMARK_REG); - return false; - } - return true; -@@ -801,12 +1001,22 @@ static int setup_se_xfer(struct spi_transfer *xfer, - struct spi_geni_master *mas, - u16 mode, struct spi_controller *spi) - { -+ u32 qspi_sync_tx_irq = 0; - u32 m_cmd = 0; - u32 m_params = 0; - u32 len; - struct geni_se *se = &mas->se; -+ int qspi_sync_tx_ret = 0; - int ret; - -+ if (mas->is_qspi) { -+ /* Protocol 9 is half-duplex and owns the first-byte lane change. */ -+ if (!!xfer->tx_buf == !!xfer->rx_buf || -+ (xfer->tx_buf && xfer->tx_nbits != SPI_NBITS_QUAD) || -+ (xfer->rx_buf && xfer->rx_nbits != SPI_NBITS_QUAD)) -+ return -EINVAL; -+ } -+ - /* - * Ensure that our interrupt handler isn't still running from some - * prior command before we start messing with the hardware behind -@@ -841,14 +1051,22 @@ static int setup_se_xfer(struct spi_transfer *xfer, - if (xfer->tx_buf) { - m_cmd |= SPI_TX_ONLY; - mas->tx_rem_bytes = xfer->len; -- writel(len, se->base + SE_SPI_TX_TRANS_LEN); - } - - if (xfer->rx_buf) { - m_cmd |= SPI_RX_ONLY; -- writel(len, se->base + SE_SPI_RX_TRANS_LEN); - mas->rx_rem_bytes = xfer->len; - } -+ if (mas->is_qspi) { -+ /* Protocol-9 PIO always programs both lengths, TX first. */ -+ writel(xfer->tx_buf ? len : 0, se->base + SE_SPI_TX_TRANS_LEN); -+ writel(xfer->rx_buf ? len : 0, se->base + SE_SPI_RX_TRANS_LEN); -+ } else { -+ if (xfer->tx_buf) -+ writel(len, se->base + SE_SPI_TX_TRANS_LEN); -+ if (xfer->rx_buf) -+ writel(len, se->base + SE_SPI_RX_TRANS_LEN); -+ } - - /* - * Select DMA mode if sgt are present; and with only 1 entry -@@ -882,7 +1100,37 @@ static int setup_se_xfer(struct spi_transfer *xfer, - * interrupt could come in at any time now. - */ - spin_lock_irq(&mas->lock); -+ /* -+ * Match the protocol-9 PIO sequence: arm the TX watermark before -+ * M_CMD0, then let its IRQ service fill the FIFO. Starting with an -+ * empty FIFO is intentional; the watermark prevents an underrun while -+ * the controller requests its first payload chunk. -+ */ -+ if (mas->is_qspi && mas->cur_xfer_mode == GENI_SE_FIFO) { -+ writel(m_cmd & SPI_TX_ONLY ? mas->tx_wm : 0, -+ se->base + SE_GENI_TX_WATERMARK_REG); -+ writel(0, se->base + SE_GENI_RX_WATERMARK_REG); -+ } - geni_se_setup_m_cmd(se, m_cmd, m_params); -+ /* -+ * Service the first TX watermark synchronously after M_CMD0 so hard-IRQ -+ * latency cannot leave the protocol-9 QSPI sequencer with an empty FIFO. -+ * The TX helper clears the final watermark before filling, so clear the -+ * latched bit only after the FIFO writes. -+ */ -+ if (mas->is_qspi && mas->cur_xfer_mode == GENI_SE_FIFO && -+ (m_cmd & SPI_TX_ONLY)) { -+ qspi_sync_tx_ret = -+ readl_poll_timeout_atomic(se->base + SE_GENI_M_IRQ_STATUS, -+ qspi_sync_tx_irq, -+ qspi_sync_tx_irq & M_TX_FIFO_WATERMARK_EN, 0, -+ QSPI_TX_POLL_TIMEOUT_US); -+ if (!qspi_sync_tx_ret) { -+ geni_spi_handle_tx(mas); -+ writel(M_TX_FIFO_WATERMARK_EN, -+ se->base + SE_GENI_M_IRQ_CLEAR); -+ } -+ } - - trace_geni_spi_transfer(mas->dev, len, m_cmd); - -@@ -893,7 +1141,7 @@ static int setup_se_xfer(struct spi_transfer *xfer, - if (m_cmd & SPI_TX_ONLY) - geni_se_tx_init_dma(se, sg_dma_address(xfer->tx_sg.sgl), - sg_dma_len(xfer->tx_sg.sgl)); -- } else if (m_cmd & SPI_TX_ONLY) { -+ } else if ((m_cmd & SPI_TX_ONLY) && !mas->is_qspi) { - if (geni_spi_handle_tx(mas)) - writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); - } -@@ -915,6 +1163,10 @@ static int spi_geni_transfer_one(struct spi_controller *spi, - /* Terminate and return success for 0 byte length transfer */ - if (!xfer->len) - return 0; -+ if (mas->qspi_linked_rx == xfer) { -+ mas->qspi_linked_rx = NULL; -+ return 0; -+ } - - if (mas->cur_xfer_mode == GENI_SE_FIFO || mas->cur_xfer_mode == GENI_SE_DMA) { - ret = setup_se_xfer(xfer, mas, slv->mode, spi); -@@ -950,7 +1202,10 @@ static irqreturn_t geni_spi_isr(int irq, void *data) - spin_lock(&mas->lock); - - if (mas->cur_xfer_mode == GENI_SE_FIFO) { -- if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) -+ if ((m_irq & M_RX_FIFO_WATERMARK_EN) || -+ (m_irq & M_RX_FIFO_LAST_EN) || -+ (mas->is_qspi && (m_irq & M_CMD_DONE_EN) && -+ mas->rx_rem_bytes)) - geni_spi_handle_rx(mas); - - if (m_irq & M_TX_FIFO_WATERMARK_EN) -@@ -1083,6 +1338,7 @@ static int spi_geni_probe(struct platform_device *pdev) - mas->se.wrapper = dev_get_drvdata(dev->parent); - mas->se.base = base; - mas->se.clk = clk; -+ mas->is_qspi = device_is_compatible(dev, "qcom,geni-qspi"); - - ret = devm_pm_opp_set_clkname(&pdev->dev, "se"); - if (ret) -@@ -1096,6 +1352,8 @@ static int spi_geni_probe(struct platform_device *pdev) - - spi->bus_num = -1; - spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; -+ if (mas->is_qspi) -+ spi->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD; - spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); - spi->num_chipselect = 4; - spi->max_speed_hz = 50000000; -@@ -1107,6 +1365,11 @@ static int spi_geni_probe(struct platform_device *pdev) - spi->auto_runtime_pm = true; - spi->handle_err = spi_geni_handle_err; - spi->use_gpio_descriptors = true; -+ if (mas->is_qspi) { -+ spi->flags |= SPI_CONTROLLER_HALF_DUPLEX; -+ spi->optimize_message = spi_geni_qspi_optimize_message; -+ spi->unoptimize_message = spi_geni_qspi_unoptimize_message; -+ } - - init_completion(&mas->cs_done); - init_completion(&mas->cancel_done); -@@ -1144,7 +1407,7 @@ static int spi_geni_probe(struct platform_device *pdev) - * TX is required per GSI spec, see setup_gsi_xfer(). - */ - if (mas->cur_xfer_mode == GENI_GPI_DMA) -- spi->flags = SPI_CONTROLLER_MUST_TX; -+ spi->flags |= SPI_CONTROLLER_MUST_TX; - - ret = devm_request_irq(dev, mas->irq, geni_spi_isr, 0, dev_name(dev), spi); - if (ret) -@@ -1225,6 +1488,7 @@ static const struct dev_pm_ops spi_geni_pm_ops = { - }; - - static const struct of_device_id spi_geni_dt_match[] = { -+ { .compatible = "qcom,geni-qspi" }, - { .compatible = "qcom,geni-spi" }, - {} - }; -diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c -index 12b3a3b29a89..6e996906cf9b 100644 ---- a/drivers/spi/spi.c -+++ b/drivers/spi/spi.c -@@ -1282,9 +1282,18 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) - } - - if (xfer->rx_buf != NULL) { -- ret = spi_map_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, -- xfer->rx_buf, xfer->len, -- DMA_FROM_DEVICE, attrs); -+ if (xfer->rx_dma_coherent) { -+ ret = sg_alloc_table(&xfer->rx_sg, 1, GFP_KERNEL); -+ if (!ret) { -+ xfer->rx_sg.sgl->length = xfer->len; -+ sg_dma_address(xfer->rx_sg.sgl) = xfer->rx_dma; -+ sg_dma_len(xfer->rx_sg.sgl) = xfer->len; -+ } -+ } else { -+ ret = spi_map_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, -+ xfer->rx_buf, xfer->len, -+ DMA_FROM_DEVICE, attrs); -+ } - if (ret) - goto unwind; - -@@ -1310,9 +1319,13 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) - /* The sync has already been done after each transfer. */ - unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC; - -- if (xfer->rx_sg_mapped) -- spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, -- DMA_FROM_DEVICE, attrs); -+ if (xfer->rx_sg_mapped) { -+ if (xfer->rx_dma_coherent) -+ sg_free_table(&xfer->rx_sg); -+ else -+ spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg, -+ DMA_FROM_DEVICE, attrs); -+ } - xfer->rx_sg_mapped = false; - - if (xfer->tx_sg_mapped) -@@ -1332,7 +1345,7 @@ static void spi_dma_sync_for_device(struct spi_controller *ctlr, - - if (xfer->tx_sg_mapped) - dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); -- if (xfer->rx_sg_mapped) -+ if (xfer->rx_sg_mapped && !xfer->rx_dma_coherent) - dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); - } - -@@ -1342,7 +1355,7 @@ static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, - struct device *rx_dev = ctlr->cur_rx_dma_dev; - struct device *tx_dev = ctlr->cur_tx_dma_dev; - -- if (xfer->rx_sg_mapped) -+ if (xfer->rx_sg_mapped && !xfer->rx_dma_coherent) - dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); - if (xfer->tx_sg_mapped) - dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); -diff --git a/include/dt-bindings/dma/qcom-gpi.h b/include/dt-bindings/dma/qcom-gpi.h -index ebda2a37f52a..68fc1414af55 100644 ---- a/include/dt-bindings/dma/qcom-gpi.h -+++ b/include/dt-bindings/dma/qcom-gpi.h -@@ -7,5 +7,6 @@ - #define QCOM_GPI_SPI 1 - #define QCOM_GPI_UART 2 - #define QCOM_GPI_I2C 3 -+#define QCOM_GPI_QSPI 9 - - #endif /* __DT_BINDINGS_DMA_QCOM_GPI_H__ */ -diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h -index 0991ef7ec092..d64a07c9397b 100644 ---- a/include/linux/soc/qcom/geni-se.h -+++ b/include/linux/soc/qcom/geni-se.h -@@ -37,6 +37,7 @@ enum geni_se_protocol_type { - GENI_SE_I2C, - GENI_SE_I3C, - GENI_SE_SPI_SLAVE, -+ GENI_SE_QSPI = 8, - GENI_SE_INVALID_PROTO = 255, - }; - -diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h -index 4c285d3ede1d..c7c68735f7ff 100644 ---- a/include/linux/spi/spi.h -+++ b/include/linux/spi/spi.h -@@ -1007,6 +1007,10 @@ struct spi_res { - * @transfer_list: transfers are sequenced through @spi_message.transfers - * @tx_sg_mapped: If true, the @tx_sg is mapped for DMA - * @rx_sg_mapped: If true, the @rx_sg is mapped for DMA -+ * @rx_dma_coherent: @rx_buf was allocated with dma_alloc_coherent() for the -+ * device the controller uses to map RX buffers and @rx_dma is its DMA -+ * address. The SPI core builds the scatterlist wrapper but skips streaming -+ * DMA map, sync, and unmap operations. - * @tx_sg: Scatterlist for transmit, currently not for client use - * @rx_sg: Scatterlist for receive, currently not for client use - * @offload_flags: Flags that are only applicable to specialized SPI offload -@@ -1111,6 +1115,7 @@ struct spi_transfer { - - bool tx_sg_mapped; - bool rx_sg_mapped; -+ bool rx_dma_coherent; - - struct sg_table tx_sg; - struct sg_table rx_sg; diff --git a/kernel/2153-HID-spi-fix-G6-touch-digitizer-module-alias.patch b/kernel/2153-HID-spi-fix-G6-touch-digitizer-module-alias.patch deleted file mode 100644 index 10eaf67..0000000 --- a/kernel/2153-HID-spi-fix-G6-touch-digitizer-module-alias.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 22:48:20 -0400 -Subject: [PATCH] HID: spi: fix G6 touch digitizer module alias - -Signed-off-by: Brandon Williams ---- - drivers/hid/spi-hid/spi-hid-of.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/hid/spi-hid/spi-hid-of.c b/drivers/hid/spi-hid/spi-hid-of.c -index 804988cab931..dae5b2af9148 100644 ---- a/drivers/hid/spi-hid/spi-hid-of.c -+++ b/drivers/hid/spi-hid/spi-hid-of.c -@@ -230,7 +230,7 @@ MODULE_DEVICE_TABLE(of, spi_hid_of_match); - static const struct spi_device_id spi_hid_of_id_table[] = { - { "hid", 0 }, - { "hid-over-spi", 0 }, -- { "microsoft,g6-touch-digitizer", 0 }, -+ { "g6-touch-digitizer", 0 }, - { } - }; - MODULE_DEVICE_TABLE(spi, spi_hid_of_id_table); diff --git a/kernel/2154-ASoC-wsa884x-recover-PA-faults-and-apply-SP11-2S-4-o.patch b/kernel/2154-ASoC-wsa884x-recover-PA-faults-and-apply-SP11-2S-4-o.patch deleted file mode 100644 index 3a8dcf0..0000000 --- a/kernel/2154-ASoC-wsa884x-recover-PA-faults-and-apply-SP11-2S-4-o.patch +++ /dev/null @@ -1,464 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jens Glathe -Date: Mon, 17 Aug 2026 22:34:00 +0100 -Subject: [PATCH] ASoC: wsa884x: recover PA faults and apply SP11 2S 4-ohm - profile - -Port the proven Surface Pro 11 2S supply detection, latched PA fault recovery, and 2S/4-ohm OCP/PBR profile from the SP11 audio reconstruction series (patches 0021 and 0022) onto the v5 source base. - -The upstream driver hard-codes QRD8550-oriented 1S supply defaults, while both SP11 amplifiers report CONFIG_2S through VPHX_SYS_EN_STATUS. This mismatch repeatedly trips the left PA state machine during sustained full-volume playback, wedging audio until reboot. Detect the hardware supply configuration and apply Qualcomm downstream's 2S class-H, DAC VCM, UVLO, current-limit, and write-once analogue enable settings, plus the 4-ohm OCP/PBR table, and add bounded PA-state recovery without relying on the amplifier interrupt path. - -The 2S settings carry the Surface Pro 11 4 ohm load policy, so a 2S -supply is acted on only for microsoft,denali-oled; other boards keep the -upstream 1S defaults. PA fault recovery applies to every board. - -Link: https://github.com/jglathe/linux_ms_dev_kit/commit/547bba651aad9a5156aef6941231cd34de51b1a2 ---- - sound/soc/codecs/wsa884x.c | 291 ++++++++++++++++++++++++++++++++++++- - 1 file changed, 286 insertions(+), 5 deletions(-) - -diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c -index a367c94bfb4d..eb138ab4e922 100644 ---- a/sound/soc/codecs/wsa884x.c -+++ b/sound/soc/codecs/wsa884x.c -@@ -6,12 +6,14 @@ - - #include - #include -+#include - #include - #include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -21,6 +23,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -155,6 +158,7 @@ - #define WSA884X_BBM_CTL (WSA884X_ANA_SPK_TOP_BASE + 0x28) - #define WSA884X_TOP_MISC1 (WSA884X_ANA_SPK_TOP_BASE + 0x29) - #define WSA884X_DAC_VCM_CTRL_REG7 (WSA884X_ANA_SPK_TOP_BASE + 0x2a) -+#define WSA884X_DAC_VCM_CTRL_REG7_FINAL_OVERRIDE_MASK 0x02 - #define WSA884X_TOP_BIAS_REG5 (WSA884X_ANA_SPK_TOP_BASE + 0x2b) - #define WSA884X_DRV_LF_MISC_CTL2 (WSA884X_ANA_SPK_TOP_BASE + 0x2c) - #define WSA884X_SPK_TOP_SPARE_TUNE_2 (WSA884X_ANA_SPK_TOP_BASE + 0x2d) -@@ -437,7 +441,9 @@ - #define WSA884X_CLSH_CTL_0_INPUT_EN_SHIFT 1 - #define WSA884X_CLSH_CTL_0_CLSH_EN_SHIFT 0 - #define WSA884X_CLSH_CTL_1 (WSA884X_DIG_CTRL0_BASE + 0xd1) -+#define WSA884X_CLSH_CTL_1_SLR_MAX_MASK 0xf0 - #define WSA884X_CLSH_V_HD_PA (WSA884X_DIG_CTRL0_BASE + 0xd2) -+#define WSA884X_CLSH_V_HD_PA_MASK 0x1f - #define WSA884X_CLSH_V_PA_MIN (WSA884X_DIG_CTRL0_BASE + 0xd3) - #define WSA884X_CLSH_OVRD_VAL (WSA884X_DIG_CTRL0_BASE + 0xd4) - #define WSA884X_CLSH_HARD_MAX (WSA884X_DIG_CTRL0_BASE + 0xd5) -@@ -725,6 +731,12 @@ - #define WSA884X_LOW_TEMP_THRESHOLD 5 - #define WSA884X_HIGH_TEMP_THRESHOLD 45 - -+#define WSA884X_PA_FSM_RESET_MASK BIT(4) -+#define WSA884X_PA_ERROR_MASK GENMASK(4, 0) -+#define WSA884X_PA_RECOVERY_RETRIES 3 -+#define WSA884X_PA_RECOVERY_FAILURES 3 -+#define WSA884X_PA_HEALTH_INTERVAL_MS 100 -+ - struct wsa884x_priv { - struct regmap *regmap; - struct device *dev; -@@ -747,6 +759,16 @@ struct wsa884x_priv { - struct mutex sp_lock; - unsigned int temperature; - bool pa_on; -+ struct delayed_work pa_health_work; -+ unsigned int pa_recovery_failures; -+ unsigned int supply_config; -+}; -+ -+enum wsa884x_supply_config { -+ WSA884X_SUPPLY_EXT_ABOVE_3S, -+ WSA884X_SUPPLY_1S, -+ WSA884X_SUPPLY_2S, -+ WSA884X_SUPPLY_3S, - }; - - enum { -@@ -1462,6 +1484,20 @@ static void wsa884x_set_gain_parameters(struct wsa884x_priv *wsa884x) - struct regmap *regmap = wsa884x->regmap; - unsigned int min_gain, igain, vgain, comp_offset; - -+ /* -+ * Surface Pro 11 ACDB selects a 4 Ohm speaker load. Qualcomm's -+ * downstream WSA884x tables pair that load with G_18_DB system gain; -+ * its 2S configuration keeps compander offset/minimum/aux gain at 0 dB. -+ */ -+ if (wsa884x->supply_config == WSA884X_SUPPLY_2S && -+ wsa884x->dev_mode == WSA884X_SPEAKER) { -+ comp_offset = COMP_OFFSET0; -+ min_gain = G_0_DB; -+ igain = ISENSE_6_DB; -+ vgain = VSENSE_M21_DB; -+ goto apply; -+ } -+ - /* - * Downstream sets gain parameters customized per boards per use-case. - * Choose here some sane values matching knowon users, like QRD8550 -@@ -1484,6 +1520,7 @@ static void wsa884x_set_gain_parameters(struct wsa884x_priv *wsa884x) - vgain = VSENSE_M24_DB; - } - -+apply: - regmap_update_bits(regmap, WSA884X_ISENSE2, - WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK, - FIELD_PREP(WSA884X_ISENSE2_ISENSE_GAIN_CTL_MASK, igain)); -@@ -1509,18 +1546,119 @@ static void wsa884x_set_gain_parameters(struct wsa884x_priv *wsa884x) - } - } - -+/* -+ * Qualcomm's full WSA884x driver has board-specific supply initialization -+ * which is not represented by the upstream driver's QRD8550-oriented 1S -+ * defaults. VPHX_SYS_EN_STATUS is a hardware strap/status value, so use it -+ * to select the electrically correct initialization without depending on an -+ * incomplete board description. -+ */ -+static void wsa884x_apply_supply_config(struct wsa884x_priv *wsa884x) -+{ -+ struct regmap *regmap = wsa884x->regmap; -+ static const struct reg_sequence sp11_2s_4ohm_pbr[] = { -+ /* -+ * Qualcomm downstream G_18_DB / CONFIG_2S / WSA_4_OHMS: -+ * 808, 839, 894, 925, 973, 996, 1051, 1114, 1184, 1255, -+ * 1318, 1467, 1616, 1788 and 2000 (millivolts * 100). -+ */ -+ { WSA884X_CLSH_VTH1, WSA884X_VTH_TO_REG(808) }, -+ { WSA884X_CLSH_VTH2, WSA884X_VTH_TO_REG(839) }, -+ { WSA884X_CLSH_VTH3, WSA884X_VTH_TO_REG(894) }, -+ { WSA884X_CLSH_VTH4, WSA884X_VTH_TO_REG(925) }, -+ { WSA884X_CLSH_VTH5, WSA884X_VTH_TO_REG(973) }, -+ { WSA884X_CLSH_VTH6, WSA884X_VTH_TO_REG(996) }, -+ { WSA884X_CLSH_VTH7, WSA884X_VTH_TO_REG(1051) }, -+ { WSA884X_CLSH_VTH8, WSA884X_VTH_TO_REG(1114) }, -+ { WSA884X_CLSH_VTH9, WSA884X_VTH_TO_REG(1184) }, -+ { WSA884X_CLSH_VTH10, WSA884X_VTH_TO_REG(1255) }, -+ { WSA884X_CLSH_VTH11, WSA884X_VTH_TO_REG(1318) }, -+ { WSA884X_CLSH_VTH12, WSA884X_VTH_TO_REG(1467) }, -+ { WSA884X_CLSH_VTH13, WSA884X_VTH_TO_REG(1616) }, -+ { WSA884X_CLSH_VTH14, WSA884X_VTH_TO_REG(1788) }, -+ { WSA884X_CLSH_VTH15, WSA884X_VTH_TO_REG(2000) }, -+ }; -+ -+ if (wsa884x->supply_config != WSA884X_SUPPLY_2S) -+ return; -+ -+ /* -+ * Exact Surface ACDB 4 Ohm load policy and CONFIG_2S overrides from -+ * Qualcomm's Windows and downstream Linux drivers. -+ */ -+ regmap_write(regmap, WSA884X_OCP_CTL, 0xf6); -+ regmap_multi_reg_write(regmap, sp11_2s_4ohm_pbr, -+ ARRAY_SIZE(sp11_2s_4ohm_pbr)); -+ regmap_update_bits(regmap, WSA884X_CLSH_CTL_1, -+ WSA884X_CLSH_CTL_1_SLR_MAX_MASK, -+ FIELD_PREP(WSA884X_CLSH_CTL_1_SLR_MAX_MASK, 0x2)); -+ regmap_update_bits(regmap, WSA884X_CLSH_V_HD_PA, -+ WSA884X_CLSH_V_HD_PA_MASK, -+ FIELD_PREP(WSA884X_CLSH_V_HD_PA_MASK, 0x13)); -+ regmap_write(regmap, WSA884X_DAC_VCM_CTRL_REG2, 0x06); -+ regmap_write(regmap, WSA884X_DAC_VCM_CTRL_REG3, 0x14); -+ regmap_write(regmap, WSA884X_DAC_VCM_CTRL_REG4, 0x19); -+ regmap_write(regmap, WSA884X_DAC_VCM_CTRL_REG5, 0x1b); -+ regmap_write(regmap, WSA884X_DAC_VCM_CTRL_REG6, 0x1c); -+ regmap_update_bits(regmap, WSA884X_DAC_VCM_CTRL_REG7, -+ WSA884X_DAC_VCM_CTRL_REG7_FINAL_OVERRIDE_MASK, -+ WSA884X_DAC_VCM_CTRL_REG7_FINAL_OVERRIDE_MASK); -+ -+ /* -+ * These UVLO values are applied after the 2S overrides in both the -+ * downstream source and a newer WSA884x module decompilation. -+ */ -+ regmap_write(regmap, WSA884X_UVLO_PROG, 0x77); -+ regmap_write(regmap, WSA884X_PA_FSM_TIMER0, 0xc0); -+ regmap_write(regmap, WSA884X_UVLO_DEGLITCH_CTL, 0x1d); -+ regmap_write(regmap, WSA884X_UVLO_PROG1, 0x40); -+ -+ regmap_update_bits(regmap, WSA884X_TOP_CTRL1, -+ WSA884X_TOP_CTRL1_OCP_LOWVBAT_ITH_EN_MASK, 0); -+} -+ - static void wsa884x_init(struct wsa884x_priv *wsa884x) - { - unsigned int wo_ctl_0; -+ unsigned int supply_config; - unsigned int variant = 0; - - if (!regmap_read(wsa884x->regmap, WSA884X_OTP_REG_0, &variant)) - variant = variant & WSA884X_OTP_REG_0_ID_MASK; - -+ if (regmap_read(wsa884x->regmap, WSA884X_VPHX_SYS_EN_STATUS, -+ &supply_config)) { -+ wsa884x->supply_config = WSA884X_SUPPLY_1S; -+ dev_warn(wsa884x->dev, -+ "cannot read VPHX supply configuration; retaining 1S defaults\n"); -+ } else { -+ wsa884x->supply_config = supply_config; -+ /* -+ * The 2S settings below include the Surface Pro 11's 4 ohm -+ * load policy, so other boards keep the upstream 1S defaults -+ * until their speakers are characterised. -+ */ -+ if (supply_config == WSA884X_SUPPLY_2S && -+ !of_machine_is_compatible("microsoft,denali-oled")) { -+ wsa884x->supply_config = WSA884X_SUPPLY_1S; -+ dev_info(wsa884x->dev, -+ "VPHX supply configuration is 2S; retaining upstream 1S defaults on this board\n"); -+ } else if (supply_config == WSA884X_SUPPLY_2S) -+ dev_info(wsa884x->dev, -+ "detected VPHX supply configuration: 2S\n"); -+ else if (supply_config != WSA884X_SUPPLY_1S) -+ dev_warn(wsa884x->dev, -+ "unsupported VPHX supply configuration %#x; retaining upstream defaults\n", -+ supply_config); -+ } -+ - regmap_multi_reg_write(wsa884x->regmap, wsa884x_reg_init, - ARRAY_SIZE(wsa884x_reg_init)); -+ wsa884x_apply_supply_config(wsa884x); - - wo_ctl_0 = 0xc; -+ if (wsa884x->supply_config == WSA884X_SUPPLY_2S) -+ wo_ctl_0 |= WSA884X_ANA_WO_CTL_0_VPHX_SYS_EN_MASK; - wo_ctl_0 |= FIELD_PREP(WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MASK, - WSA884X_ANA_WO_CTL_0_DAC_CM_CLAMP_EN_MODE_SPEAKER); - /* Assume that compander is enabled by default unless it is haptics sku */ -@@ -1537,6 +1675,111 @@ static void wsa884x_init(struct wsa884x_priv *wsa884x) - wsa884x->hw_init = true; - } - -+static void wsa884x_reset_pa_fsm(struct wsa884x_priv *wsa884x) -+{ -+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_CTL0, -+ WSA884X_PA_FSM_RESET_MASK, 0); -+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_CTL0, -+ WSA884X_PA_FSM_RESET_MASK, -+ WSA884X_PA_FSM_RESET_MASK); -+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_CTL0, -+ WSA884X_PA_FSM_RESET_MASK, 0); -+} -+ -+/* -+ * Recover the PA state machine using the sequence from Qualcomm's downstream -+ * WSA884x driver. Caller serializes this with sp_lock. -+ */ -+static int wsa884x_recover_pa(struct wsa884x_priv *wsa884x, bool reenable) -+{ -+ unsigned int sta0 = 0, sta1 = 0, err0 = 0, err1 = 0; -+ int ret = -EIO; -+ int retry; -+ -+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_EN, -+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK, 0); -+ regmap_read(wsa884x->regmap, WSA884X_PA_FSM_STA0, &sta0); -+ regmap_read(wsa884x->regmap, WSA884X_PA_FSM_STA1, &sta1); -+ regmap_read(wsa884x->regmap, WSA884X_PA_FSM_ERR_COND0, &err0); -+ regmap_read(wsa884x->regmap, WSA884X_PA_FSM_ERR_COND1, &err1); -+ -+ dev_warn_ratelimited(wsa884x->dev, -+ "PA fault: sta0=%#02x sta1=%#02x err0=%#02x err1=%#02x; resetting FSM\n", -+ sta0, sta1, err0, err1); -+ -+ wsa884x_reset_pa_fsm(wsa884x); -+ regmap_write(wsa884x->regmap, WSA884X_INTR_CLEAR1, BIT(1)); -+ if (!reenable) -+ return 0; -+ -+ for (retry = 0; retry < WSA884X_PA_RECOVERY_RETRIES; retry++) { -+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_EN, -+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK, -+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK); -+ usleep_range(1000, 1100); -+ -+ ret = regmap_read(wsa884x->regmap, WSA884X_PA_FSM_STA1, &sta1); -+ if (!ret && !(sta1 & WSA884X_PA_ERROR_MASK)) { -+ regmap_write(wsa884x->regmap, WSA884X_INTR_CLEAR1, BIT(1)); -+ dev_info(wsa884x->dev, -+ "PA state machine recovered after %d attempt(s)\n", -+ retry + 1); -+ return 0; -+ } -+ -+ regmap_update_bits(wsa884x->regmap, WSA884X_PA_FSM_EN, -+ WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK, 0); -+ wsa884x_reset_pa_fsm(wsa884x); -+ } -+ -+ regmap_read(wsa884x->regmap, WSA884X_PA_FSM_ERR_COND0, &err0); -+ regmap_read(wsa884x->regmap, WSA884X_PA_FSM_ERR_COND1, &err1); -+ dev_err_ratelimited(wsa884x->dev, -+ "PA recovery failed: sta1=%#02x err0=%#02x err1=%#02x; amplifier left disabled\n", -+ sta1, err0, err1); -+ -+ return ret ?: -EIO; -+} -+ -+static void wsa884x_pa_health_work(struct work_struct *work) -+{ -+ struct wsa884x_priv *wsa884x = -+ container_of(to_delayed_work(work), struct wsa884x_priv, -+ pa_health_work); -+ unsigned int sta1 = 0; -+ bool rearm; -+ int ret; -+ -+ ret = pm_runtime_resume_and_get(wsa884x->dev); -+ if (ret < 0) -+ goto out_rearm; -+ -+ mutex_lock(&wsa884x->sp_lock); -+ if (!wsa884x->pa_on) -+ goto out_unlock; -+ -+ ret = regmap_read(wsa884x->regmap, WSA884X_PA_FSM_STA1, &sta1); -+ if (!ret && (sta1 & WSA884X_PA_ERROR_MASK) && -+ wsa884x->pa_recovery_failures < WSA884X_PA_RECOVERY_FAILURES) { -+ ret = wsa884x_recover_pa(wsa884x, true); -+ if (ret) -+ wsa884x->pa_recovery_failures++; -+ else -+ wsa884x->pa_recovery_failures = 0; -+ } -+ -+out_unlock: -+ mutex_unlock(&wsa884x->sp_lock); -+ pm_runtime_mark_last_busy(wsa884x->dev); -+ pm_runtime_put_autosuspend(wsa884x->dev); -+ -+out_rearm: -+ rearm = READ_ONCE(wsa884x->pa_on); -+ if (rearm) -+ schedule_delayed_work(&wsa884x->pa_health_work, -+ msecs_to_jiffies(WSA884X_PA_HEALTH_INTERVAL_MS)); -+} -+ - static int wsa884x_update_status(struct sdw_slave *slave, - enum sdw_slave_status status) - { -@@ -1677,7 +1920,10 @@ static void wsa884x_spkr_post_pmu(struct snd_soc_component *component, - - if (wsa884x->port_enable[WSA884X_PORT_PBR]) { - curr_ovrd_en = 0x0; -- curr_limit = 0x15; -+ if (wsa884x->supply_config == WSA884X_SUPPLY_2S) -+ curr_limit = 0x11; -+ else -+ curr_limit = 0x15; - } else { - curr_ovrd_en = 0x1; - if (wsa884x->dev_mode == WSA884X_RECEIVER) -@@ -1701,8 +1947,10 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, - - switch (event) { - case SND_SOC_DAPM_POST_PMU: -- scoped_guard(mutex, &wsa884x->sp_lock) -+ scoped_guard(mutex, &wsa884x->sp_lock) { - wsa884x->pa_on = true; -+ wsa884x->pa_recovery_failures = 0; -+ } - - wsa884x_spkr_post_pmu(component, wsa884x); - -@@ -1710,14 +1958,17 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w, - WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, - 0x1); - -+ mod_delayed_work(system_wq, &wsa884x->pa_health_work, -+ msecs_to_jiffies(WSA884X_PA_HEALTH_INTERVAL_MS)); - break; - case SND_SOC_DAPM_PRE_PMD: -+ scoped_guard(mutex, &wsa884x->sp_lock) -+ wsa884x->pa_on = false; -+ cancel_delayed_work_sync(&wsa884x->pa_health_work); -+ - snd_soc_component_write_field(component, WSA884X_PDM_WD_CTL, - WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK, - 0x0); -- -- scoped_guard(mutex, &wsa884x->sp_lock) -- wsa884x->pa_on = false; - break; - } - -@@ -1802,6 +2053,10 @@ static int wsa884x_hw_free(struct snd_pcm_substream *substream, - static int wsa884x_mute_stream(struct snd_soc_dai *dai, int mute, int stream) - { - struct snd_soc_component *component = dai->component; -+ struct wsa884x_priv *wsa884x = snd_soc_component_get_drvdata(component); -+ unsigned int sta1 = 0; -+ -+ guard(mutex)(&wsa884x->sp_lock); - - if (mute) { - snd_soc_component_write_field(component, WSA884X_DRE_CTL_1, -@@ -1812,12 +2067,25 @@ static int wsa884x_mute_stream(struct snd_soc_dai *dai, int mute, int stream) - 0x0); - - } else { -+ /* -+ * A PA_ON_ERR can remain latched across a normal graph -+ * teardown. Clear it before trying to start the amplifier. -+ */ -+ if (!regmap_read(wsa884x->regmap, WSA884X_PA_FSM_STA1, &sta1) && -+ (sta1 & WSA884X_PA_ERROR_MASK)) -+ wsa884x_recover_pa(wsa884x, false); -+ - snd_soc_component_write_field(component, WSA884X_DRE_CTL_1, - WSA884X_DRE_CTL_1_CSR_GAIN_EN_MASK, - 0x1); - snd_soc_component_write_field(component, WSA884X_PA_FSM_EN, - WSA884X_PA_FSM_EN_GLOBAL_PA_EN_MASK, - 0x1); -+ usleep_range(1000, 1100); -+ -+ if (!regmap_read(wsa884x->regmap, WSA884X_PA_FSM_STA1, &sta1) && -+ (sta1 & WSA884X_PA_ERROR_MASK)) -+ wsa884x_recover_pa(wsa884x, true); - } - - return 0; -@@ -2038,6 +2306,13 @@ static int wsa884x_get_reset(struct device *dev, struct wsa884x_priv *wsa884x) - return 0; - } - -+static void wsa884x_cancel_pa_health_work(void *data) -+{ -+ struct wsa884x_priv *wsa884x = data; -+ -+ cancel_delayed_work_sync(&wsa884x->pa_health_work); -+} -+ - static int wsa884x_probe(struct sdw_slave *pdev, - const struct sdw_device_id *id) - { -@@ -2051,6 +2326,12 @@ static int wsa884x_probe(struct sdw_slave *pdev, - return -ENOMEM; - - mutex_init(&wsa884x->sp_lock); -+ INIT_DELAYED_WORK(&wsa884x->pa_health_work, wsa884x_pa_health_work); -+ -+ ret = devm_add_action_or_reset(dev, wsa884x_cancel_pa_health_work, -+ wsa884x); -+ if (ret) -+ return ret; - - for (i = 0; i < WSA884X_SUPPLIES_NUM; i++) - wsa884x->supplies[i].supply = wsa884x_supply_name[i]; diff --git a/kernel/2155-Bluetooth-hci_qca-keep-the-WCN6750-baudrate-event-dr.patch b/kernel/2155-Bluetooth-hci_qca-keep-the-WCN6750-baudrate-event-dr.patch deleted file mode 100644 index 36d06f1..0000000 --- a/kernel/2155-Bluetooth-hci_qca-keep-the-WCN6750-baudrate-event-dr.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 17 Oct 2026 19:52:08 -0400 -Subject: [PATCH] Bluetooth: hci_qca: keep the WCN6750+ baudrate event drop to - Denali - -The previous patch makes these controllers wait up to 100 ms for a -Command Complete after a baudrate change, and fails setup without it. -That is confirmed only on the Surface Pro 11's WCN7850. Keep it to -microsoft,denali until other boards have been tested, so they keep the -upstream behaviour. - -Signed-off-by: Brandon Williams ---- - drivers/bluetooth/hci_qca.c | 40 ++++++++++++++++++++----------------- - 1 file changed, 22 insertions(+), 18 deletions(-) - -diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c -index 9aa5cad82bac..047e8a38b891 100644 ---- a/drivers/bluetooth/hci_qca.c -+++ b/drivers/bluetooth/hci_qca.c -@@ -1491,6 +1491,26 @@ static int qca_check_speeds(struct hci_uart *hu) - return 0; - } - -+/* -+ * The WCN3990 answers a baudrate change with a vendor event that has to be -+ * dropped. The WCN6750, WCN6855 and WCN7850 answer with a Command Complete -+ * that needs the same treatment. That is confirmed only on the Surface Pro -+ * 11's WCN7850, so other boards keep the upstream behaviour for now. -+ */ -+static bool qca_drops_baudrate_event(enum qca_btsoc_type soc_type) -+{ -+ switch (soc_type) { -+ case QCA_WCN3990: -+ return true; -+ case QCA_WCN6750: -+ case QCA_WCN6855: -+ case QCA_WCN7850: -+ return of_machine_is_compatible("microsoft,denali"); -+ default: -+ return false; -+ } -+} -+ - static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) - { - unsigned int speed, qca_baudrate; -@@ -1527,17 +1547,9 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) - break; - } - -- switch (soc_type) { -- case QCA_WCN3990: -- case QCA_WCN6750: -- case QCA_WCN6855: -- case QCA_WCN7850: -+ if (qca_drops_baudrate_event(soc_type)) { - reinit_completion(&qca->drop_ev_comp); - set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags); -- break; -- -- default: -- break; - } - - qca_baudrate = qca_get_baudrate_value(speed); -@@ -1565,11 +1577,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) - break; - } - -- switch (soc_type) { -- case QCA_WCN3990: -- case QCA_WCN6750: -- case QCA_WCN6855: -- case QCA_WCN7850: -+ if (qca_drops_baudrate_event(soc_type)) { - /* Wait for the controller to send the vendor event - * for the baudrate change command. - */ -@@ -1581,10 +1589,6 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) - } - - clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags); -- break; -- -- default: -- break; - } - } - diff --git a/kernel/2156-drm-msm-dpu-disable-the-clocks-if-the-core-rate-rest.patch b/kernel/2156-drm-msm-dpu-disable-the-clocks-if-the-core-rate-rest.patch deleted file mode 100644 index 0e2f8cc..0000000 --- a/kernel/2156-drm-msm-dpu-disable-the-clocks-if-the-core-rate-rest.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sat, 17 Oct 2026 19:50:40 -0400 -Subject: [PATCH] drm/msm/dpu: disable the clocks if the core rate restore - fails on resume - -dpu_runtime_resume() returns the error from dev_pm_opp_set_rate() after -clk_bulk_prepare_enable() has already enabled the DPU clocks, so a failed -resume leaves them prepared and enabled. Disable them on that path. - -Follows "drm/msm/dpu: Reassert core clock rate on runtime resume" -Signed-off-by: Brandon Williams ---- - drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c -index 23e0a5b2ca22..453b9ef3787d 100644 ---- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c -+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c -@@ -1477,6 +1477,8 @@ static int __maybe_unused dpu_runtime_resume(struct device *dev) - if (rc) { - DPU_ERROR("failed to restore core clock rate %lu: %d\n", - core_rate, rc); -+ clk_bulk_disable_unprepare(dpu_kms->num_clocks, -+ dpu_kms->clocks); - return rc; - } - dpu_kms->perf.core_clk_rate = core_rate; diff --git a/kernel/2160-arm64-dts-qcom-x1e80100-Add-CAMCC-block-definition.patch b/kernel/2160-arm64-dts-qcom-x1e80100-Add-CAMCC-block-definition.patch deleted file mode 100644 index a2b79df..0000000 --- a/kernel/2160-arm64-dts-qcom-x1e80100-Add-CAMCC-block-definition.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bryan O'Donoghue -Date: Thu, 7 May 2026 11:08:31 +0530 -Subject: [PATCH] arm64: dts: qcom: x1e80100: Add CAMCC block definition - -Add the CAMCC block for x1e80100. The x1e80100 CAMCC block is an iteration -of previous CAMCC blocks with the exception of having two required -power-domains not just one. And update the compatible for camcc and -videocc nodes on Purwa to match with their respective Purwa (X1P42100) -specific drivers. - -Reviewed-by: Vladimir Zapolskiy -Reviewed-by: Konrad Dybcio -Reviewed-by: Abel Vesa -Signed-off-by: Bryan O'Donoghue -Signed-off-by: Jagadeesh Kona -Link: https://lore.kernel.org/r/20260507-purwa-videocc-camcc-v5-6-fc3af4130282@oss.qualcomm.com -Signed-off-by: Bjorn Andersson ---- - arch/arm64/boot/dts/qcom/hamoa.dtsi | 17 +++++++++++++++++ - arch/arm64/boot/dts/qcom/purwa.dtsi | 10 ++++++++++ - 2 files changed, 27 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi -index 8863cee1b6cb..fb964ee0922c 100644 ---- a/arch/arm64/boot/dts/qcom/hamoa.dtsi -+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -5558,6 +5559,22 @@ videocc: clock-controller@aaf0000 { - #power-domain-cells = <1>; - }; - -+ camcc: clock-controller@ade0000 { -+ compatible = "qcom,x1e80100-camcc"; -+ reg = <0x0 0x0ade0000 0x0 0x20000>; -+ clocks = <&gcc GCC_CAMERA_AHB_CLK>, -+ <&bi_tcxo_div2>, -+ <&bi_tcxo_ao_div2>, -+ <&sleep_clk>; -+ power-domains = <&rpmhpd RPMHPD_MXC>, -+ <&rpmhpd RPMHPD_MMCX>; -+ required-opps = <&rpmhpd_opp_low_svs>, -+ <&rpmhpd_opp_low_svs>; -+ #clock-cells = <1>; -+ #reset-cells = <1>; -+ #power-domain-cells = <1>; -+ }; -+ - mdss: display-subsystem@ae00000 { - compatible = "qcom,x1e80100-mdss"; - reg = <0 0x0ae00000 0 0x1000>; -diff --git a/arch/arm64/boot/dts/qcom/purwa.dtsi b/arch/arm64/boot/dts/qcom/purwa.dtsi -index 5b17840fb62f..3d73d1211cd0 100644 ---- a/arch/arm64/boot/dts/qcom/purwa.dtsi -+++ b/arch/arm64/boot/dts/qcom/purwa.dtsi -@@ -6,6 +6,8 @@ - /* X1P42100 is heavily based on hamoa, with some meaningful differences */ - #include "hamoa.dtsi" - -+#include -+ - /delete-node/ &bwmon_cluster0; - /delete-node/ &cluster_pd2; - /delete-node/ &cpu_map_cluster2; -@@ -36,6 +38,10 @@ - /delete-node/ &thermal_gpuss_6; - /delete-node/ &thermal_gpuss_7; - -+&camcc { -+ compatible = "qcom,x1p42100-camcc"; -+}; -+ - &gcc { - compatible = "qcom,x1p42100-gcc", "qcom,x1e80100-gcc"; - }; -@@ -258,3 +264,7 @@ &thermal_nsp3 { - &tsens3 { - status = "disabled"; - }; -+ -+&videocc { -+ compatible = "qcom,x1p42100-videocc"; -+}; diff --git a/kernel/2161-arm64-dts-qcom-hamoa-add-camera-subsystem-nodes.patch b/kernel/2161-arm64-dts-qcom-hamoa-add-camera-subsystem-nodes.patch deleted file mode 100644 index a0a4ee0..0000000 --- a/kernel/2161-arm64-dts-qcom-hamoa-add-camera-subsystem-nodes.patch +++ /dev/null @@ -1,350 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] arm64: dts: qcom: hamoa: add camera subsystem nodes - -Describe CAMCC, CAMSS, both CCI controllers, their I2C buses, and the -associated pin states. Keep every hardware block disabled for boards to -opt in. - -Signed-off-by: Brandon Williams ---- - arch/arm64/boot/dts/qcom/hamoa.dtsi | 318 ++++++++++++++++++++++++++++ - 1 file changed, 318 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi -index fb964ee0922c..2e72fa81e807 100644 ---- a/arch/arm64/boot/dts/qcom/hamoa.dtsi -+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi -@@ -5559,6 +5559,260 @@ videocc: clock-controller@aaf0000 { - #power-domain-cells = <1>; - }; - -+ cci0: cci@ac15000 { -+ compatible = "qcom,x1e80100-cci", "qcom,msm8996-cci"; -+ reg = <0 0x0ac15000 0 0x1000>; -+ interrupts = ; -+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; -+ -+ clocks = <&camcc CAM_CC_CAMNOC_AXI_NRT_CLK>, -+ <&camcc CAM_CC_CPAS_AHB_CLK>, -+ <&camcc CAM_CC_CCI_0_CLK>; -+ clock-names = "camnoc_axi", -+ "cpas_ahb", -+ "cci"; -+ -+ pinctrl-0 = <&cci0_0_default>, <&cci0_1_default>; -+ pinctrl-1 = <&cci0_0_sleep>, <&cci0_1_sleep>; -+ pinctrl-names = "default", "sleep"; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "disabled"; -+ -+ cci0_i2c0: i2c-bus@0 { -+ reg = <0>; -+ clock-frequency = <1000000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ -+ cci0_i2c1: i2c-bus@1 { -+ reg = <1>; -+ clock-frequency = <1000000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ }; -+ -+ cci1: cci@ac16000 { -+ compatible = "qcom,x1e80100-cci", "qcom,msm8996-cci"; -+ reg = <0 0x0ac16000 0 0x1000>; -+ interrupts = ; -+ power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; -+ -+ clocks = <&camcc CAM_CC_CAMNOC_AXI_NRT_CLK>, -+ <&camcc CAM_CC_CPAS_AHB_CLK>, -+ <&camcc CAM_CC_CCI_1_CLK>; -+ clock-names = "camnoc_axi", -+ "cpas_ahb", -+ "cci"; -+ -+ pinctrl-0 = <&cci1_0_default>, <&cci1_1_default>; -+ pinctrl-1 = <&cci1_0_sleep>, <&cci1_1_sleep>; -+ pinctrl-names = "default", "sleep"; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "disabled"; -+ -+ cci1_i2c0: i2c-bus@0 { -+ reg = <0>; -+ clock-frequency = <1000000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ -+ cci1_i2c1: i2c-bus@1 { -+ reg = <1>; -+ clock-frequency = <1000000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ }; -+ -+ camss: isp@acb7000 { -+ compatible = "qcom,x1e80100-camss"; -+ -+ reg = <0 0x0acb7000 0 0x2000>, -+ <0 0x0acb9000 0 0x2000>, -+ <0 0x0acbb000 0 0x2000>, -+ <0 0x0acc6000 0 0x1000>, -+ <0 0x0acca000 0 0x1000>, -+ <0 0x0acb6000 0 0x1000>, -+ <0 0x0ace4000 0 0x2000>, -+ <0 0x0ace6000 0 0x2000>, -+ <0 0x0ace8000 0 0x2000>, -+ <0 0x0acec000 0 0x4000>, -+ <0 0x0acf6000 0 0x1000>, -+ <0 0x0acf7000 0 0x1000>, -+ <0 0x0acf8000 0 0x1000>, -+ <0 0x0ac62000 0 0x4000>, -+ <0 0x0ac71000 0 0x4000>, -+ <0 0x0acc7000 0 0x2000>, -+ <0 0x0accb000 0 0x2000>; -+ reg-names = "csid0", -+ "csid1", -+ "csid2", -+ "csid_lite0", -+ "csid_lite1", -+ "csid_wrapper", -+ "csiphy0", -+ "csiphy1", -+ "csiphy2", -+ "csiphy4", -+ "csitpg0", -+ "csitpg1", -+ "csitpg2", -+ "vfe0", -+ "vfe1", -+ "vfe_lite0", -+ "vfe_lite1"; -+ -+ clocks = <&camcc CAM_CC_CAMNOC_AXI_NRT_CLK>, -+ <&camcc CAM_CC_CAMNOC_AXI_RT_CLK>, -+ <&camcc CAM_CC_CORE_AHB_CLK>, -+ <&camcc CAM_CC_CPAS_AHB_CLK>, -+ <&camcc CAM_CC_CPAS_FAST_AHB_CLK>, -+ <&camcc CAM_CC_CPAS_IFE_0_CLK>, -+ <&camcc CAM_CC_CPAS_IFE_1_CLK>, -+ <&camcc CAM_CC_CPAS_IFE_LITE_CLK>, -+ <&camcc CAM_CC_CPHY_RX_CLK_SRC>, -+ <&camcc CAM_CC_CSID_CLK>, -+ <&camcc CAM_CC_CSID_CSIPHY_RX_CLK>, -+ <&camcc CAM_CC_CSIPHY0_CLK>, -+ <&camcc CAM_CC_CSI0PHYTIMER_CLK>, -+ <&camcc CAM_CC_CSIPHY1_CLK>, -+ <&camcc CAM_CC_CSI1PHYTIMER_CLK>, -+ <&camcc CAM_CC_CSIPHY2_CLK>, -+ <&camcc CAM_CC_CSI2PHYTIMER_CLK>, -+ <&camcc CAM_CC_CSIPHY4_CLK>, -+ <&camcc CAM_CC_CSI4PHYTIMER_CLK>, -+ <&gcc GCC_CAMERA_HF_AXI_CLK>, -+ <&gcc GCC_CAMERA_SF_AXI_CLK>, -+ <&camcc CAM_CC_IFE_0_CLK>, -+ <&camcc CAM_CC_IFE_0_FAST_AHB_CLK>, -+ <&camcc CAM_CC_IFE_1_CLK>, -+ <&camcc CAM_CC_IFE_1_FAST_AHB_CLK>, -+ <&camcc CAM_CC_IFE_LITE_CLK>, -+ <&camcc CAM_CC_IFE_LITE_AHB_CLK>, -+ <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, -+ <&camcc CAM_CC_IFE_LITE_CSID_CLK>; -+ clock-names = "camnoc_nrt_axi", -+ "camnoc_rt_axi", -+ "core_ahb", -+ "cpas_ahb", -+ "cpas_fast_ahb", -+ "cpas_vfe0", -+ "cpas_vfe1", -+ "cpas_vfe_lite", -+ "cphy_rx_clk_src", -+ "csid", -+ "csid_csiphy_rx", -+ "csiphy0", -+ "csiphy0_timer", -+ "csiphy1", -+ "csiphy1_timer", -+ "csiphy2", -+ "csiphy2_timer", -+ "csiphy4", -+ "csiphy4_timer", -+ "gcc_axi_hf", -+ "gcc_axi_sf", -+ "vfe0", -+ "vfe0_fast_ahb", -+ "vfe1", -+ "vfe1_fast_ahb", -+ "vfe_lite", -+ "vfe_lite_ahb", -+ "vfe_lite_cphy_rx", -+ "vfe_lite_csid"; -+ -+ interrupts = , -+ , -+ , -+ , -+ , -+ , -+ , -+ , -+ , -+ , -+ , -+ , -+ ; -+ interrupt-names = "csid0", -+ "csid1", -+ "csid2", -+ "csid_lite0", -+ "csid_lite1", -+ "csiphy0", -+ "csiphy1", -+ "csiphy2", -+ "csiphy4", -+ "vfe0", -+ "vfe1", -+ "vfe_lite0", -+ "vfe_lite1"; -+ -+ interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY -+ &config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>, -+ <&mmss_noc MASTER_CAMNOC_HF QCOM_ICC_TAG_ALWAYS -+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, -+ <&mmss_noc MASTER_CAMNOC_SF QCOM_ICC_TAG_ALWAYS -+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, -+ <&mmss_noc MASTER_CAMNOC_ICP QCOM_ICC_TAG_ALWAYS -+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; -+ interconnect-names = "ahb", -+ "hf_mnoc", -+ "sf_mnoc", -+ "sf_icp_mnoc"; -+ -+ iommus = <&apps_smmu 0x800 0x60>, -+ <&apps_smmu 0x820 0x60>, -+ <&apps_smmu 0x840 0x60>, -+ <&apps_smmu 0x860 0x60>, -+ <&apps_smmu 0x18a0 0x0>; -+ -+ power-domains = <&camcc CAM_CC_IFE_0_GDSC>, -+ <&camcc CAM_CC_IFE_1_GDSC>, -+ <&camcc CAM_CC_TITAN_TOP_GDSC>; -+ power-domain-names = "ife0", -+ "ife1", -+ "top"; -+ -+ status = "disabled"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ /* -+ * port@0: CSIPHY0 -+ * port@1: CSIPHY1 -+ * port@2: CSIPHY2 -+ * port@3: CSIPHY4 -+ */ -+ port@0 { -+ reg = <0>; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ }; -+ -+ port@2 { -+ reg = <2>; -+ }; -+ -+ port@3 { -+ reg = <3>; -+ }; -+ }; -+ }; -+ - camcc: clock-controller@ade0000 { - compatible = "qcom,x1e80100-camcc"; - reg = <0x0 0x0ade0000 0x0 0x20000>; -@@ -6156,6 +6410,70 @@ tlmm: pinctrl@f100000 { - gpio-ranges = <&tlmm 0 0 239>; - wakeup-parent = <&pdc>; - -+ cci0_0_default: cci0-0-default-state { -+ /* SDA, SCL */ -+ pins = "gpio101", "gpio102"; -+ function = "cci_i2c"; -+ drive-strength = <2>; -+ bias-pull-up = <2200>; -+ }; -+ -+ cci0_0_sleep: cci0-0-sleep-state { -+ /* SDA, SCL */ -+ pins = "gpio101", "gpio102"; -+ function = "cci_i2c"; -+ drive-strength = <2>; -+ bias-pull-down; -+ }; -+ -+ cci0_1_default: cci0-1-default-state { -+ /* SDA, SCL */ -+ pins = "gpio103", "gpio104"; -+ function = "cci_i2c"; -+ drive-strength = <2>; -+ bias-pull-up = <2200>; -+ }; -+ -+ cci0_1_sleep: cci0-1-sleep-state { -+ /* SDA, SCL */ -+ pins = "gpio103", "gpio104"; -+ function = "cci_i2c"; -+ drive-strength = <2>; -+ bias-pull-down; -+ }; -+ -+ cci1_0_default: cci1-0-default-state { -+ /* SDA, SCL */ -+ pins = "gpio105", "gpio106"; -+ function = "cci_i2c"; -+ drive-strength = <2>; -+ bias-pull-up = <2200>; -+ }; -+ -+ cci1_0_sleep: cci1-0-sleep-state { -+ /* SDA, SCL */ -+ pins = "gpio105", "gpio106"; -+ function = "cci_i2c"; -+ drive-strength = <2>; -+ bias-pull-down; -+ }; -+ -+ cci1_1_default: cci1-1-default-state { -+ /* SDA, SCL */ -+ pins = "gpio235", "gpio236"; -+ function = "aon_cci"; -+ drive-strength = <2>; -+ bias-pull-up = <2200>; -+ }; -+ -+ cci1_1_sleep: cci1-1-sleep-state { -+ /* SDA, SCL */ -+ pins = "gpio235", "gpio236"; -+ function = "aon_cci"; -+ drive-strength = <2>; -+ bias-pull-down; -+ }; -+ - edp0_hpd_default: edp0-hpd-default-state { - pins = "gpio119"; - function = "edp0_hot"; diff --git a/kernel/2162-media-i2c-add-Surface-Pro-11-camera-sensors.patch b/kernel/2162-media-i2c-add-Surface-Pro-11-camera-sensors.patch deleted file mode 100644 index 3db1555..0000000 --- a/kernel/2162-media-i2c-add-Surface-Pro-11-camera-sensors.patch +++ /dev/null @@ -1,4326 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] media: i2c: add Surface Pro 11 camera sensors - -Add an IMX681 driver, extend OV13858 with the Surface Pro 11 rear-camera -mode, and import the VD55G0 driver and sensor patches from -STMicroelectronics. - -The IMX681 and OV13858 mode sequences are independently authored -representations of runtime I2C transactions observed on the hardware. No -vendor binary or extracted configuration payload is included. - -The VD55G0 files are adapted under GPL-2.0 from STMicroelectronics -vd55g0-linux-driver revision: - - 9134fe572b77f906344f37ba227f375db73dc026 - -Signed-off-by: Brandon Williams ---- - MAINTAINERS | 9 + - drivers/media/i2c/Kconfig | 22 + - drivers/media/i2c/Makefile | 2 + - drivers/media/i2c/imx681-tables.h | 454 +++++++ - drivers/media/i2c/imx681.c | 554 ++++++++ - drivers/media/i2c/ov13858.c | 420 +++++- - drivers/media/i2c/vd55g0.c | 1995 ++++++++++++++++++++++++++++ - drivers/media/i2c/vd55g0_patches.h | 585 ++++++++ - 8 files changed, 4020 insertions(+), 21 deletions(-) - create mode 100644 drivers/media/i2c/imx681-tables.h - create mode 100644 drivers/media/i2c/imx681.c - create mode 100644 drivers/media/i2c/vd55g0.c - create mode 100644 drivers/media/i2c/vd55g0_patches.h - -diff --git a/MAINTAINERS b/MAINTAINERS -index 95cd976a068c..91ad92e5a9ab 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -17959,6 +17959,14 @@ L: platform-driver-x86@vger.kernel.org - S: Supported - F: drivers/platform/surface/surfacepro3_button.c - -+MICROSOFT SURFACE PRO 11 CAMERA SUPPORT -+M: turbinebmw -+L: linux-media@vger.kernel.org -+S: Maintained -+F: Documentation/driver-api/media/sp11-camera-provenance.rst -+F: drivers/media/i2c/imx681* -+F: drivers/media/i2c/vd55g0* -+ - MICROSOFT SURFACE SYSTEM AGGREGATOR HUB DRIVER - M: Maximilian Luz - L: platform-driver-x86@vger.kernel.org -@@ -19956,6 +19964,7 @@ M: Sakari Ailus - L: linux-media@vger.kernel.org - S: Maintained - T: git git://linuxtv.org/media.git -+F: Documentation/devicetree/bindings/media/i2c/ovti,ov13858.yaml - F: drivers/media/i2c/ov13858.c - - OMNIVISION OV13B10 SENSOR DRIVER -diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index df94cc55f1ff..b72919104159 100644 ---- a/drivers/media/i2c/Kconfig -+++ b/drivers/media/i2c/Kconfig -@@ -298,6 +298,18 @@ config VIDEO_IMX471 - To compile this driver as a module, choose M here: the - module will be called imx471. - -+config VIDEO_IMX681 -+ tristate "Sony IMX681 sensor support" -+ depends on OF_GPIO -+ select V4L2_CCI_I2C -+ help -+ This is a Video4Linux2 sensor driver for the Sony IMX681 camera. -+ It currently supports the 3840x2640 RAW10 C-PHY mode used by the -+ front-facing camera in the Microsoft Surface Pro 11. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called imx681. -+ - config VIDEO_MAX9271_LIB - tristate - -@@ -837,6 +849,16 @@ config VIDEO_VD55G1 - To compile this driver as a module, choose M here: the - module will be called vd55g1. - -+config VIDEO_VD55G0 -+ tristate "ST VD55G0 sensor support" -+ depends on GPIOLIB -+ help -+ This is a Video4Linux2 sensor driver for the ST VD55G0 global -+ shutter camera sensor. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called vd55g0. -+ - config VIDEO_VD56G3 - tristate "ST VD56G3 sensor support" - select V4L2_CCI_I2C -diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile -index acbd321fc12e..c97e9ae42506 100644 ---- a/drivers/media/i2c/Makefile -+++ b/drivers/media/i2c/Makefile -@@ -62,6 +62,7 @@ obj-$(CONFIG_VIDEO_IMX355) += imx355.o - obj-$(CONFIG_VIDEO_IMX412) += imx412.o - obj-$(CONFIG_VIDEO_IMX415) += imx415.o - obj-$(CONFIG_VIDEO_IMX471) += imx471.o -+obj-$(CONFIG_VIDEO_IMX681) += imx681.o - obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o - obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o - obj-$(CONFIG_VIDEO_KS0127) += ks0127.o -@@ -166,6 +167,7 @@ obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o - obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o - obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o - obj-$(CONFIG_VIDEO_VD55G1) += vd55g1.o -+obj-$(CONFIG_VIDEO_VD55G0) += vd55g0.o - obj-$(CONFIG_VIDEO_VD56G3) += vd56g3.o - obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o - obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o -diff --git a/drivers/media/i2c/imx681-tables.h b/drivers/media/i2c/imx681-tables.h -new file mode 100644 -index 000000000000..3b492c21da7b ---- /dev/null -+++ b/drivers/media/i2c/imx681-tables.h -@@ -0,0 +1,454 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Sony IMX681 register tables for the Surface Pro 11 front camera. -+ * -+ * These tables are an independently written representation of runtime I2C -+ * transactions observed on the author's own hardware. The observed -+ * stream-start order is global initialization, followed by the selected mode. -+ * Mode: 3840x2640 RAW10, LLP 6752, VT pixel clock 548571428 Hz -+ * (~30 fps at FLL 2708), ONE C-PHY TRIO at 2406 Msym/s. -+ */ -+#ifndef __IMX681_TABLES_H -+#define __IMX681_TABLES_H -+ -+#include -+ -+static const struct cci_reg_sequence imx681_global_init_table[] = { -+ { CCI_REG8(0x0136), 0x13 }, -+ { CCI_REG8(0x0137), 0x33 }, -+ { CCI_REG8(0x002c), 0x05 }, -+ { CCI_REG8(0x002d), 0x05 }, -+ { CCI_REG8(0x0111), 0x03 }, -+ { CCI_REG8(0x30eb), 0x05 }, -+ { CCI_REG8(0x30eb), 0x0c }, -+ { CCI_REG8(0x300a), 0xff }, -+ { CCI_REG8(0x300b), 0xff }, -+ { CCI_REG8(0x3532), 0xff }, -+ { CCI_REG8(0x3533), 0xff }, -+ { CCI_REG8(0x051e), 0x00 }, -+ { CCI_REG8(0x0905), 0x04 }, -+ { CCI_REG8(0x2029), 0x01 }, -+ { CCI_REG8(0x202a), 0x11 }, -+ { CCI_REG8(0x20a1), 0x00 }, -+ { CCI_REG8(0x20a2), 0x02 }, -+ { CCI_REG8(0x20a3), 0x03 }, -+ { CCI_REG8(0x20ac), 0x01 }, -+ { CCI_REG8(0x20ad), 0x01 }, -+ { CCI_REG8(0x20ae), 0x01 }, -+ { CCI_REG8(0x20af), 0x01 }, -+ { CCI_REG8(0x20b0), 0x00 }, -+ { CCI_REG8(0x20b1), 0x01 }, -+ { CCI_REG8(0x20b2), 0x02 }, -+ { CCI_REG8(0x20b3), 0x03 }, -+ { CCI_REG8(0x706f), 0x00 }, -+ { CCI_REG8(0x7130), 0x08 }, -+ { CCI_REG8(0x7131), 0x08 }, -+ { CCI_REG8(0x7408), 0x89 }, -+ { CCI_REG8(0x7437), 0x3d }, -+ { CCI_REG8(0x7439), 0x29 }, -+ { CCI_REG8(0x7443), 0x38 }, -+ { CCI_REG8(0x7447), 0x55 }, -+ { CCI_REG8(0x744b), 0x00 }, -+ { CCI_REG8(0x7451), 0x8e }, -+ { CCI_REG8(0x746d), 0x29 }, -+ { CCI_REG8(0x747d), 0x68 }, -+ { CCI_REG8(0x7481), 0x60 }, -+ { CCI_REG8(0x7491), 0x2d }, -+ { CCI_REG8(0x7493), 0x31 }, -+ { CCI_REG8(0x74a5), 0x52 }, -+ { CCI_REG8(0x74af), 0x4a }, -+ { CCI_REG8(0x74b5), 0x1f }, -+ { CCI_REG8(0x74b7), 0x31 }, -+ { CCI_REG8(0x74bd), 0x75 }, -+ { CCI_REG8(0x74c5), 0x06 }, -+ { CCI_REG8(0x74c9), 0x52 }, -+ { CCI_REG8(0x74d3), 0x4a }, -+ { CCI_REG8(0x74d9), 0x1f }, -+ { CCI_REG8(0x74db), 0x31 }, -+ { CCI_REG8(0x74e1), 0x75 }, -+ { CCI_REG8(0x74e9), 0x06 }, -+ { CCI_REG8(0x74ed), 0x52 }, -+ { CCI_REG8(0x74f7), 0x4a }, -+ { CCI_REG8(0x74fd), 0x1f }, -+ { CCI_REG8(0x74ff), 0x31 }, -+ { CCI_REG8(0x7505), 0x75 }, -+ { CCI_REG8(0x750d), 0x06 }, -+ { CCI_REG8(0x7537), 0x38 }, -+ { CCI_REG8(0x753d), 0x4a }, -+ { CCI_REG8(0x753f), 0x4a }, -+ { CCI_REG8(0x7541), 0x4a }, -+ { CCI_REG8(0x7549), 0x8e }, -+ { CCI_REG8(0x754f), 0x75 }, -+ { CCI_REG8(0x7551), 0x75 }, -+ { CCI_REG8(0x7553), 0x75 }, -+ { CCI_REG8(0x792b), 0x39 }, -+ { CCI_REG8(0x792d), 0x43 }, -+ { CCI_REG8(0x79d3), 0x25 }, -+ { CCI_REG8(0x79d6), 0x8e }, -+ { CCI_REG8(0x79d7), 0x01 }, -+ { CCI_REG8(0x79d8), 0xe7 }, -+ { CCI_REG8(0x79d9), 0x25 }, -+ { CCI_REG8(0x79db), 0x76 }, -+ { CCI_REG8(0x79dc), 0x8e }, -+ { CCI_REG8(0x79dd), 0x01 }, -+ { CCI_REG8(0x79de), 0xe7 }, -+ { CCI_REG8(0x79df), 0x25 }, -+ { CCI_REG8(0x79e1), 0x76 }, -+ { CCI_REG8(0x79e2), 0x8e }, -+ { CCI_REG8(0x79e3), 0x01 }, -+ { CCI_REG8(0x79e4), 0xe7 }, -+ { CCI_REG8(0x79e5), 0x25 }, -+ { CCI_REG8(0x79e7), 0x76 }, -+ { CCI_REG8(0x79e8), 0x8e }, -+ { CCI_REG8(0x7a01), 0xff }, -+ { CCI_REG8(0x7a29), 0x6c }, -+ { CCI_REG8(0x7a2b), 0xda }, -+ { CCI_REG8(0x7a34), 0x6c }, -+ { CCI_REG8(0x7a37), 0xda }, -+ { CCI_REG8(0x7a40), 0x6c }, -+ { CCI_REG8(0x7a43), 0xda }, -+ { CCI_REG8(0x7b08), 0x00 }, -+ { CCI_REG8(0x7b09), 0x01 }, -+ { CCI_REG8(0x7c03), 0x38 }, -+ { CCI_REG8(0x7c09), 0x4a }, -+ { CCI_REG8(0x7c0b), 0x4a }, -+ { CCI_REG8(0x7c0d), 0x4a }, -+ { CCI_REG8(0x7c13), 0x8e }, -+ { CCI_REG8(0x7c19), 0x75 }, -+ { CCI_REG8(0x7c1b), 0x75 }, -+ { CCI_REG8(0x7c1d), 0x75 }, -+ { CCI_REG8(0x7c90), 0x00 }, -+ { CCI_REG8(0x7c91), 0x00 }, -+ { CCI_REG8(0x7c92), 0x00 }, -+ { CCI_REG8(0x7c9d), 0x01 }, -+ { CCI_REG8(0x7c9e), 0x01 }, -+ { CCI_REG8(0x7c9f), 0x01 }, -+ { CCI_REG8(0x7e9b), 0x07 }, -+ { CCI_REG8(0x7f09), 0x00 }, -+ { CCI_REG8(0x7f36), 0x00 }, -+ { CCI_REG8(0x7f4f), 0x0a }, -+ { CCI_REG8(0x7f50), 0x0a }, -+ { CCI_REG8(0x7f51), 0x0a }, -+ { CCI_REG8(0x7f55), 0x05 }, -+ { CCI_REG8(0x7f56), 0x05 }, -+ { CCI_REG8(0x7f57), 0x05 }, -+ { CCI_REG8(0x7f5b), 0x03 }, -+ { CCI_REG8(0x7f5c), 0x03 }, -+ { CCI_REG8(0x7f5d), 0x03 }, -+ { CCI_REG8(0x7f61), 0x03 }, -+ { CCI_REG8(0x7f62), 0x03 }, -+ { CCI_REG8(0x7f63), 0x03 }, -+ { CCI_REG8(0x7f67), 0x03 }, -+ { CCI_REG8(0x7f68), 0x03 }, -+ { CCI_REG8(0x7f69), 0x03 }, -+ { CCI_REG8(0x7f6a), 0x05 }, -+ { CCI_REG8(0x7f6b), 0x05 }, -+ { CCI_REG8(0x7f6c), 0x05 }, -+ { CCI_REG8(0x7f6d), 0x11 }, -+ { CCI_REG8(0x7f6e), 0x14 }, -+ { CCI_REG8(0x7f6f), 0x14 }, -+ { CCI_REG8(0x7f73), 0x14 }, -+ { CCI_REG8(0x7f74), 0x1c }, -+ { CCI_REG8(0x7f75), 0x14 }, -+ { CCI_REG8(0x7f76), 0x08 }, -+ { CCI_REG8(0x7f79), 0x14 }, -+ { CCI_REG8(0x7f7a), 0x1c }, -+ { CCI_REG8(0x7f7b), 0x14 }, -+ { CCI_REG8(0x7f7f), 0x1c }, -+ { CCI_REG8(0x7f80), 0x1c }, -+ { CCI_REG8(0x7f81), 0x1c }, -+ { CCI_REG8(0x7f85), 0x1c }, -+ { CCI_REG8(0x7f86), 0x1c }, -+ { CCI_REG8(0x7f87), 0x1c }, -+ { CCI_REG8(0x7f9d), 0x09 }, -+ { CCI_REG8(0x7f9e), 0x09 }, -+ { CCI_REG8(0x7f9f), 0x09 }, -+ { CCI_REG8(0x7fa3), 0x09 }, -+ { CCI_REG8(0x7fa4), 0x09 }, -+ { CCI_REG8(0x7fa5), 0x09 }, -+ { CCI_REG8(0x7fac), 0x00 }, -+ { CCI_REG8(0x7fad), 0x00 }, -+ { CCI_REG8(0x7fae), 0x00 }, -+ { CCI_REG8(0x7faf), 0x00 }, -+ { CCI_REG8(0x7fb0), 0x00 }, -+ { CCI_REG8(0x7fb1), 0x00 }, -+ { CCI_REG8(0x7fb2), 0x00 }, -+ { CCI_REG8(0x7fb3), 0x00 }, -+ { CCI_REG8(0x7fb4), 0x00 }, -+ { CCI_REG8(0x7fb5), 0x00 }, -+ { CCI_REG8(0x7fb6), 0x00 }, -+ { CCI_REG8(0x7fb7), 0x00 }, -+ { CCI_REG8(0x7fb8), 0x00 }, -+ { CCI_REG8(0x7fb9), 0x00 }, -+ { CCI_REG8(0x7fba), 0x00 }, -+ { CCI_REG8(0x7fbb), 0x00 }, -+ { CCI_REG8(0x7fbc), 0x00 }, -+ { CCI_REG8(0x7fbd), 0x00 }, -+ { CCI_REG8(0x7fbe), 0x00 }, -+ { CCI_REG8(0x7fbf), 0x00 }, -+ { CCI_REG8(0x7fc0), 0x00 }, -+ { CCI_REG8(0x7fc1), 0x00 }, -+ { CCI_REG8(0x7fc2), 0x00 }, -+ { CCI_REG8(0x7fc3), 0x00 }, -+ { CCI_REG8(0x7fcb), 0x37 }, -+ { CCI_REG8(0x7fcd), 0x37 }, -+ { CCI_REG8(0x7fcf), 0x37 }, -+ { CCI_REG8(0x7fd7), 0x44 }, -+ { CCI_REG8(0x7fd9), 0x44 }, -+ { CCI_REG8(0x7fdb), 0x44 }, -+ { CCI_REG8(0x7fdd), 0x38 }, -+ { CCI_REG8(0x7fe3), 0x4a }, -+ { CCI_REG8(0x7fe5), 0x4a }, -+ { CCI_REG8(0x7fe7), 0x4a }, -+ { CCI_REG8(0x7fef), 0x4a }, -+ { CCI_REG8(0x7ff1), 0x4a }, -+ { CCI_REG8(0x7ff3), 0x4a }, -+ { CCI_REG8(0x7ffb), 0x4a }, -+ { CCI_REG8(0x7ffd), 0x4a }, -+ { CCI_REG8(0x7fff), 0x4a }, -+ { CCI_REG8(0x8007), 0x62 }, -+ { CCI_REG8(0x8009), 0x62 }, -+ { CCI_REG8(0x800b), 0x62 }, -+ { CCI_REG8(0x8013), 0x6f }, -+ { CCI_REG8(0x8015), 0x6f }, -+ { CCI_REG8(0x8017), 0x6f }, -+ { CCI_REG8(0x8019), 0x8e }, -+ { CCI_REG8(0x801f), 0x75 }, -+ { CCI_REG8(0x8021), 0x75 }, -+ { CCI_REG8(0x8023), 0x75 }, -+ { CCI_REG8(0x802b), 0x75 }, -+ { CCI_REG8(0x802d), 0x75 }, -+ { CCI_REG8(0x802f), 0x75 }, -+ { CCI_REG8(0x8037), 0x75 }, -+ { CCI_REG8(0x8039), 0x75 }, -+ { CCI_REG8(0x803b), 0x75 }, -+ { CCI_REG8(0x803c), 0x13 }, -+ { CCI_REG8(0x803d), 0x17 }, -+ { CCI_REG8(0x803e), 0x15 }, -+ { CCI_REG8(0x803f), 0x11 }, -+ { CCI_REG8(0x8040), 0x0a }, -+ { CCI_REG8(0x8041), 0x08 }, -+ { CCI_REG8(0x8047), 0x17 }, -+ { CCI_REG8(0x80f0), 0x24 }, -+ { CCI_REG8(0x80f1), 0x1b }, -+ { CCI_REG8(0x80f2), 0x1a }, -+ { CCI_REG8(0x80f3), 0x14 }, -+ { CCI_REG8(0x80f4), 0x14 }, -+ { CCI_REG8(0x80f5), 0x12 }, -+ { CCI_REG8(0x80f6), 0x25 }, -+ { CCI_REG8(0x80f7), 0x1c }, -+ { CCI_REG8(0x80f8), 0x1b }, -+ { CCI_REG8(0x80f9), 0x18 }, -+ { CCI_REG8(0x80fa), 0x17 }, -+ { CCI_REG8(0x80fb), 0x18 }, -+ { CCI_REG8(0x80fc), 0x26 }, -+ { CCI_REG8(0x80fd), 0x1e }, -+ { CCI_REG8(0x80fe), 0x1d }, -+ { CCI_REG8(0x80ff), 0x1c }, -+ { CCI_REG8(0x8100), 0x1b }, -+ { CCI_REG8(0x8101), 0x1c }, -+ { CCI_REG8(0x8102), 0x27 }, -+ { CCI_REG8(0x8103), 0x1e }, -+ { CCI_REG8(0x8104), 0x1d }, -+ { CCI_REG8(0x8105), 0x1e }, -+ { CCI_REG8(0x8106), 0x1e }, -+ { CCI_REG8(0x8107), 0x1e }, -+ { CCI_REG8(0x8108), 0x27 }, -+ { CCI_REG8(0x8109), 0x1e }, -+ { CCI_REG8(0x810a), 0x1e }, -+ { CCI_REG8(0x810b), 0x1e }, -+ { CCI_REG8(0x810c), 0x1e }, -+ { CCI_REG8(0x810d), 0x1f }, -+ { CCI_REG8(0x810e), 0x00 }, -+ { CCI_REG8(0x8168), 0x0b }, -+ { CCI_REG8(0x8169), 0x0b }, -+ { CCI_REG8(0x816a), 0x09 }, -+ { CCI_REG8(0x816b), 0x0f }, -+ { CCI_REG8(0x816c), 0x0f }, -+ { CCI_REG8(0x816d), 0x0f }, -+ { CCI_REG8(0x816e), 0x0b }, -+ { CCI_REG8(0x816f), 0x0b }, -+ { CCI_REG8(0x8170), 0x0a }, -+ { CCI_REG8(0x8171), 0x0f }, -+ { CCI_REG8(0x8172), 0x0f }, -+ { CCI_REG8(0x8173), 0x0f }, -+ { CCI_REG8(0x8174), 0x0d }, -+ { CCI_REG8(0x8175), 0x0c }, -+ { CCI_REG8(0x8176), 0x09 }, -+ { CCI_REG8(0x8177), 0x0f }, -+ { CCI_REG8(0x8178), 0x0f }, -+ { CCI_REG8(0x8179), 0x0f }, -+ { CCI_REG8(0x817a), 0x0c }, -+ { CCI_REG8(0x817b), 0x0d }, -+ { CCI_REG8(0x817c), 0x09 }, -+ { CCI_REG8(0x817d), 0x0f }, -+ { CCI_REG8(0x817e), 0x0f }, -+ { CCI_REG8(0x817f), 0x0f }, -+ { CCI_REG8(0x8180), 0x0d }, -+ { CCI_REG8(0x8181), 0x0d }, -+ { CCI_REG8(0x8182), 0x09 }, -+ { CCI_REG8(0x8183), 0x0f }, -+ { CCI_REG8(0x8184), 0x0f }, -+ { CCI_REG8(0x8185), 0x0f }, -+ { CCI_REG8(0x81b0), 0x03 }, -+ { CCI_REG8(0x81e3), 0x04 }, -+ { CCI_REG8(0x81e4), 0x04 }, -+ { CCI_REG8(0x81e9), 0x04 }, -+ { CCI_REG8(0x81ea), 0x04 }, -+ { CCI_REG8(0x81ef), 0x04 }, -+ { CCI_REG8(0x81f0), 0x04 }, -+ { CCI_REG8(0x9186), 0x00 }, -+ { CCI_REG8(0xd030), 0x01 }, -+ { CCI_REG8(0xd04c), 0x10 }, -+ { CCI_REG8(0xd123), 0x75 }, -+ { CCI_REG8(0xd144), 0x10 }, -+ { CCI_REG8(0xd1af), 0x08 }, -+ { CCI_REG8(0xd1bd), 0x67 }, -+ { CCI_REG8(0xd1d4), 0x04 }, -+ { CCI_REG8(0xd1d5), 0x04 }, -+ { CCI_REG8(0xd1d6), 0x07 }, -+ { CCI_REG8(0xd1d7), 0x07 }, -+ { CCI_REG8(0xd1d9), 0x40 }, -+ { CCI_REG8(0xd1db), 0x58 }, -+ { CCI_REG8(0xd1dd), 0xd4 }, -+ { CCI_REG8(0xd1df), 0xd4 }, -+ { CCI_REG8(0xd1e1), 0xd4 }, -+ { CCI_REG8(0xd348), 0x0f }, -+ { CCI_REG8(0xd357), 0x00 }, -+ { CCI_REG8(0xd3ae), 0x11 }, -+ { CCI_REG8(0xd3af), 0x44 }, -+ { CCI_REG8(0xd3b1), 0x7d }, -+ { CCI_REG8(0xd803), 0xf0 }, -+ { CCI_REG8(0xd80b), 0xf0 }, -+ { CCI_REG8(0xd813), 0xf1 }, -+ { CCI_REG8(0xd81b), 0xf0 }, -+ { CCI_REG8(0xd843), 0xf1 }, -+ { CCI_REG8(0xd84f), 0xf0 }, -+ { CCI_REG8(0xd934), 0x23 }, -+ { CCI_REG8(0xd935), 0xc8 }, -+ { CCI_REG8(0xd938), 0x27 }, -+ { CCI_REG8(0xd939), 0x10 }, -+ { CCI_REG8(0xd93a), 0x23 }, -+ { CCI_REG8(0xd93b), 0xc8 }, -+ { CCI_REG8(0xd955), 0x07 }, -+ { CCI_REG8(0xd95a), 0x04 }, -+ { CCI_REG8(0xd95b), 0x0a }, -+ { CCI_REG8(0xd95c), 0x1e }, -+ { CCI_REG8(0xd95d), 0x00 }, -+ { CCI_REG8(0xd95e), 0x14 }, -+ { CCI_REG8(0xd95f), 0x21 }, -+ { CCI_REG8(0xd960), 0x00 }, -+ { CCI_REG8(0xd961), 0x00 }, -+ { CCI_REG8(0xd962), 0x0a }, -+ { CCI_REG8(0xd963), 0x50 }, -+ { CCI_REG8(0xd964), 0x0a }, -+ { CCI_REG8(0xd965), 0xa0 }, -+ { CCI_REG8(0xd966), 0x00 }, -+ { CCI_REG8(0xd967), 0x28 }, -+ { CCI_REG8(0xd968), 0x0a }, -+ { CCI_REG8(0xd969), 0x50 }, -+ { CCI_REG8(0xd96a), 0x0a }, -+ { CCI_REG8(0xd96b), 0xa0 }, -+ { CCI_REG8(0xd96c), 0x00 }, -+ { CCI_REG8(0xd96d), 0x00 }, -+ { CCI_REG8(0xd96e), 0x0a }, -+ { CCI_REG8(0xd96f), 0x44 }, -+ { CCI_REG8(0xd970), 0x0a }, -+ { CCI_REG8(0xd971), 0x50 }, -+ { CCI_REG8(0xd972), 0x00 }, -+ { CCI_REG8(0xd973), 0x00 }, -+ { CCI_REG8(0xd974), 0x0a }, -+ { CCI_REG8(0xd975), 0x44 }, -+ { CCI_REG8(0xd976), 0x0a }, -+ { CCI_REG8(0xd977), 0x50 }, -+ { CCI_REG8(0xda10), 0x00 }, -+ { CCI_REG8(0xda11), 0x14 }, -+ { CCI_REG8(0xda12), 0x64 }, -+ { CCI_REG8(0xda13), 0x00 }, -+ { CCI_REG8(0xda14), 0x14 }, -+ { CCI_REG8(0xda15), 0xc8 }, -+ { CCI_REG8(0xda22), 0x00 }, -+ { CCI_REG8(0xda23), 0x56 }, -+ { CCI_REG8(0xda24), 0x00 }, -+ { CCI_REG8(0xda25), 0xb5 }, -+ { CCI_REG8(0xda26), 0x00 }, -+ { CCI_REG8(0xda27), 0xe8 }, -+ { CCI_REG8(0xda28), 0x08 }, -+ { CCI_REG8(0xda29), 0xa6 }, -+ { CCI_REG8(0xda2a), 0x00 }, -+ { CCI_REG8(0xda2b), 0xa2 }, -+ { CCI_REG8(0xda2f), 0x01 }, -+}; -+ -+static const struct cci_reg_sequence imx681_mode_3840x2640[] = { -+ { CCI_REG8(0x0110), 0x00 }, -+ { CCI_REG8(0x0112), 0x0a }, -+ { CCI_REG8(0x0113), 0x0a }, -+ { CCI_REG8(0x0114), 0x00 }, -+ { CCI_REG8(0x0342), 0x1a }, -+ { CCI_REG8(0x0343), 0x60 }, -+ { CCI_REG8(0x033d), 0x00 }, -+ { CCI_REG8(0x033e), 0x0d }, -+ { CCI_REG8(0x033f), 0xe2 }, -+ { CCI_REG8(0x0344), 0x00 }, -+ { CCI_REG8(0x0345), 0x68 }, -+ { CCI_REG8(0x0346), 0x01 }, -+ { CCI_REG8(0x0347), 0x00 }, -+ { CCI_REG8(0x0348), 0x0f }, -+ { CCI_REG8(0x0349), 0x67 }, -+ { CCI_REG8(0x034a), 0x0b }, -+ { CCI_REG8(0x034b), 0x4f }, -+ { CCI_REG8(0x017c), 0x01 }, -+ { CCI_REG8(0x017d), 0x01 }, -+ { CCI_REG8(0x017e), 0x00 }, -+ { CCI_REG8(0x017f), 0x01 }, -+ { CCI_REG8(0x0180), 0x00 }, -+ { CCI_REG8(0x038c), 0x13 }, -+ { CCI_REG8(0x038d), 0x33 }, -+ { CCI_REG8(0x2000), 0x01 }, -+ { CCI_REG8(0x0408), 0x00 }, -+ { CCI_REG8(0x0409), 0x00 }, -+ { CCI_REG8(0x040a), 0x00 }, -+ { CCI_REG8(0x040b), 0x00 }, -+ { CCI_REG8(0x040c), 0x0f }, -+ { CCI_REG8(0x040d), 0x00 }, -+ { CCI_REG8(0x040e), 0x0a }, -+ { CCI_REG8(0x040f), 0x50 }, -+ { CCI_REG8(0x034c), 0x0f }, -+ { CCI_REG8(0x034d), 0x00 }, -+ { CCI_REG8(0x034e), 0x0a }, -+ { CCI_REG8(0x034f), 0x50 }, -+ { CCI_REG8(0x0301), 0x06 }, -+ { CCI_REG8(0x0303), 0x02 }, -+ { CCI_REG8(0x0305), 0x02 }, -+ { CCI_REG8(0x0306), 0x00 }, -+ { CCI_REG8(0x0307), 0xe1 }, -+ { CCI_REG8(0x030d), 0x03 }, -+ { CCI_REG8(0x030e), 0x01 }, -+ { CCI_REG8(0x030f), 0x77 }, -+ { CCI_REG8(0x0323), 0x00 }, -+ { CCI_REG8(0x0229), 0x00 }, -+ { CCI_REG8(0x022a), 0x0d }, -+ { CCI_REG8(0x022b), 0xda }, -+ { CCI_REG8(0xd383), 0x01 }, -+ { CCI_REG8(0x0204), 0x00 }, -+ { CCI_REG8(0x0205), 0x00 }, -+ { CCI_REG8(0x020e), 0x01 }, -+ { CCI_REG8(0x020f), 0x00 }, -+ { CCI_REG8(0x0210), 0x01 }, -+ { CCI_REG8(0x0211), 0x00 }, -+ { CCI_REG8(0x0212), 0x01 }, -+ { CCI_REG8(0x0213), 0x00 }, -+ { CCI_REG8(0x0214), 0x01 }, -+ { CCI_REG8(0x0215), 0x00 }, -+ { CCI_REG8(0x6a83), 0x03 }, -+ { CCI_REG8(0x7e9b), 0x02 }, -+ { CCI_REG8(0xd1ce), 0x00 }, -+ { CCI_REG8(0xdc3c), 0x01 }, -+ { CCI_REG8(0x0368), 0x00 }, -+ { CCI_REG8(0x036a), 0x08 }, -+ { CCI_REG8(0x036b), 0x70 }, -+ { CCI_REG8(0x2001), 0x00 }, -+}; -+ -+#endif /* __IMX681_TABLES_H */ -diff --git a/drivers/media/i2c/imx681.c b/drivers/media/i2c/imx681.c -new file mode 100644 -index 000000000000..cf99dd211dc0 ---- /dev/null -+++ b/drivers/media/i2c/imx681.c -@@ -0,0 +1,554 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Sony IMX681 sensor driver (Surface Pro 11 front camera). -+ * -+ * The SP11 mode is an independently written representation of register -+ * transactions observed while operating the author's own camera hardware. -+ * Single supported mode: -+ * 3840x2640 RAW10 at ~30 fps over ONE C-PHY TRIO at 2406 Msym/s -+ * (CSI_SIGNALING_MODE 0x0111=3). This tree carries experimental -+ * three-phase qcom camss support. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "imx681-tables.h" -+ -+#define IMX681_REG_MODEL_ID CCI_REG16(0x0016) -+#define IMX681_MODEL_ID 0x0681 -+#define IMX681_REG_MODE_SELECT CCI_REG8(0x0100) -+#define IMX681_MODE_STREAMING 1 -+#define IMX681_MODE_STANDBY 0 -+#define IMX681_REG_GROUP_HOLD CCI_REG8(0x0104) -+#define IMX681_REG_EXPOSURE CCI_REG16(0x0202) -+#define IMX681_REG_ANALOG_GAIN CCI_REG16(0x0204) -+#define IMX681_REG_DIGITAL_GAIN CCI_REG16(0x020e) -+#define IMX681_REG_FRAME_LENGTH CCI_REG16(0x0340) -+ -+#define IMX681_WIDTH 3840 -+#define IMX681_HEIGHT 2640 -+#define IMX681_LINE_LENGTH 6752 -+#define IMX681_FRAME_LENGTH_DEF 2708 -+#define IMX681_FRAME_LENGTH_MAX 0xffff -+#define IMX681_EXPOSURE_MARGIN 48 -+#define IMX681_EXPOSURE_DEF 1600 -+#define IMX681_AGAIN_MAX 960 /* gain = 1024 / (1024 - code) */ -+#define IMX681_DGAIN_DEF 0x0100 -+#define IMX681_PIXEL_RATE 548571428 -+/* V4L2 C-PHY link frequency is half the 2406-Msym/s symbol rate. */ -+#define IMX681_LINK_FREQ 1203000000 -+#define IMX681_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10 -+ -+#define IMX681_XCLR_MIN_DELAY_US 6200 -+#define IMX681_XCLR_DELAY_RANGE_US 1000 -+ -+static const char * const imx681_supply_name[] = { -+ "dovdd", /* IO 1.8 V (PM8010 LDO3_M) */ -+ "avdd", /* analog 2.8 V (PM8550 LDO7_B) */ -+}; -+ -+static const s64 imx681_link_freq_menu[] = { -+ IMX681_LINK_FREQ, -+}; -+ -+struct imx681 { -+ struct device *dev; -+ struct regmap *regmap; -+ struct clk *xclk; -+ struct gpio_desc *reset_gpio; -+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx681_supply_name)]; -+ -+ struct v4l2_subdev sd; -+ struct media_pad pad; -+ struct v4l2_ctrl_handler ctrl_handler; -+ struct v4l2_ctrl *vblank_ctrl; -+ struct v4l2_ctrl *expo_ctrl; -+ struct v4l2_ctrl *again_ctrl; -+ struct v4l2_ctrl *dgain_ctrl; -+}; -+ -+static inline struct imx681 *to_imx681(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct imx681, sd); -+} -+ -+static int imx681_power_on(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct imx681 *sensor = to_imx681(sd); -+ int ret; -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(imx681_supply_name), -+ sensor->supplies); -+ if (ret) { -+ dev_err(dev, "failed to enable regulators: %d\n", ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(sensor->xclk); -+ if (ret) { -+ dev_err(dev, "failed to enable xclk: %d\n", ret); -+ goto disable_reg; -+ } -+ -+ gpiod_set_value_cansleep(sensor->reset_gpio, 0); -+ usleep_range(IMX681_XCLR_MIN_DELAY_US, -+ IMX681_XCLR_MIN_DELAY_US + IMX681_XCLR_DELAY_RANGE_US); -+ return 0; -+ -+disable_reg: -+ regulator_bulk_disable(ARRAY_SIZE(imx681_supply_name), -+ sensor->supplies); -+ return ret; -+} -+ -+static int imx681_power_off(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct imx681 *sensor = to_imx681(sd); -+ -+ gpiod_set_value_cansleep(sensor->reset_gpio, 1); -+ clk_disable_unprepare(sensor->xclk); -+ regulator_bulk_disable(ARRAY_SIZE(imx681_supply_name), -+ sensor->supplies); -+ return 0; -+} -+ -+static int imx681_identify(struct imx681 *sensor) -+{ -+ u64 id = 0; -+ int ret; -+ -+ ret = cci_read(sensor->regmap, IMX681_REG_MODEL_ID, &id, NULL); -+ if (ret) { -+ dev_err(sensor->dev, "model ID read failed: %d\n", ret); -+ return ret; -+ } -+ -+ dev_info(sensor->dev, "detected model id 0x%04llx%s\n", id, -+ id == IMX681_MODEL_ID ? " (IMX681)" : " (UNEXPECTED)"); -+ -+ return id == IMX681_MODEL_ID ? 0 : -ENODEV; -+} -+ -+/* ----------------------------------------------------------- controls */ -+ -+static int imx681_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct imx681 *sensor = -+ container_of(ctrl->handler, struct imx681, ctrl_handler); -+ int ret = 0; -+ -+ if (ctrl->id == V4L2_CID_VBLANK) { -+ unsigned int expo_max = IMX681_HEIGHT + ctrl->val - -+ IMX681_EXPOSURE_MARGIN; -+ -+ ret = __v4l2_ctrl_modify_range(sensor->expo_ctrl, -+ sensor->expo_ctrl->minimum, -+ expo_max, 1, -+ min_t(int, IMX681_EXPOSURE_DEF, -+ expo_max)); -+ if (ret) -+ return ret; -+ } -+ -+ if (!pm_runtime_get_if_in_use(sensor->dev)) -+ return 0; -+ -+ cci_write(sensor->regmap, IMX681_REG_GROUP_HOLD, 1, &ret); -+ switch (ctrl->id) { -+ case V4L2_CID_VBLANK: -+ cci_write(sensor->regmap, IMX681_REG_FRAME_LENGTH, -+ IMX681_HEIGHT + ctrl->val, &ret); -+ break; -+ case V4L2_CID_EXPOSURE: -+ cci_write(sensor->regmap, IMX681_REG_EXPOSURE, ctrl->val, -+ &ret); -+ break; -+ case V4L2_CID_ANALOGUE_GAIN: -+ cci_write(sensor->regmap, IMX681_REG_ANALOG_GAIN, ctrl->val, -+ &ret); -+ break; -+ case V4L2_CID_DIGITAL_GAIN: -+ cci_write(sensor->regmap, IMX681_REG_DIGITAL_GAIN, ctrl->val, -+ &ret); -+ break; -+ default: -+ break; -+ } -+ cci_write(sensor->regmap, IMX681_REG_GROUP_HOLD, 0, &ret); -+ -+ pm_runtime_put_autosuspend(sensor->dev); -+ -+ return ret; -+} -+ -+static const struct v4l2_ctrl_ops imx681_ctrl_ops = { -+ .s_ctrl = imx681_s_ctrl, -+}; -+ -+static int imx681_init_controls(struct imx681 *sensor) -+{ -+ struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler; -+ const struct v4l2_ctrl_ops *ops = &imx681_ctrl_ops; -+ struct v4l2_fwnode_device_properties props; -+ struct v4l2_ctrl *ctrl; -+ int ret; -+ -+ ret = v4l2_fwnode_device_parse(sensor->dev, &props); -+ if (ret) -+ return ret; -+ -+ /* v4l2_fwnode_device_properties can add two more controls. */ -+ ret = v4l2_ctrl_handler_init(hdl, 10); -+ if (ret) -+ return ret; -+ -+ ctrl = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, -+ ARRAY_SIZE(imx681_link_freq_menu) - 1, 0, -+ imx681_link_freq_menu); -+ if (ctrl) -+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ -+ ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, -+ IMX681_PIXEL_RATE, IMX681_PIXEL_RATE, 1, -+ IMX681_PIXEL_RATE); -+ if (ctrl) -+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ -+ ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, -+ IMX681_LINE_LENGTH - IMX681_WIDTH, -+ IMX681_LINE_LENGTH - IMX681_WIDTH, 1, -+ IMX681_LINE_LENGTH - IMX681_WIDTH); -+ if (ctrl) -+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ -+ sensor->vblank_ctrl = -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, -+ IMX681_EXPOSURE_MARGIN, -+ IMX681_FRAME_LENGTH_MAX - IMX681_HEIGHT, 1, -+ IMX681_FRAME_LENGTH_DEF - IMX681_HEIGHT); -+ sensor->expo_ctrl = -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 8, -+ IMX681_FRAME_LENGTH_DEF - -+ IMX681_EXPOSURE_MARGIN, 1, -+ IMX681_EXPOSURE_DEF); -+ sensor->again_ctrl = -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, -+ IMX681_AGAIN_MAX, 1, 0); -+ sensor->dgain_ctrl = -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, 0x0100, -+ 0x0fff, 1, IMX681_DGAIN_DEF); -+ -+ v4l2_ctrl_new_fwnode_properties(hdl, ops, &props); -+ -+ if (hdl->error) { -+ ret = hdl->error; -+ v4l2_ctrl_handler_free(hdl); -+ return ret; -+ } -+ -+ sensor->sd.ctrl_handler = hdl; -+ return 0; -+} -+ -+/* ------------------------------------------------------------- format */ -+ -+static void imx681_fill_fmt(struct v4l2_mbus_framefmt *fmt) -+{ -+ fmt->code = IMX681_MBUS_CODE; -+ fmt->width = IMX681_WIDTH; -+ fmt->height = IMX681_HEIGHT; -+ fmt->field = V4L2_FIELD_NONE; -+ fmt->colorspace = V4L2_COLORSPACE_RAW; -+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; -+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; -+ fmt->xfer_func = V4L2_XFER_FUNC_NONE; -+} -+ -+static int imx681_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *state, -+ struct v4l2_subdev_mbus_code_enum *code) -+{ -+ if (code->index) -+ return -EINVAL; -+ code->code = IMX681_MBUS_CODE; -+ return 0; -+} -+ -+static int imx681_enum_frame_size(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *state, -+ struct v4l2_subdev_frame_size_enum *fse) -+{ -+ if (fse->index || fse->code != IMX681_MBUS_CODE) -+ return -EINVAL; -+ fse->min_width = IMX681_WIDTH; -+ fse->max_width = IMX681_WIDTH; -+ fse->min_height = IMX681_HEIGHT; -+ fse->max_height = IMX681_HEIGHT; -+ return 0; -+} -+ -+static int imx681_set_pad_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *state, -+ struct v4l2_subdev_format *fmt) -+{ -+ imx681_fill_fmt(&fmt->format); -+ *v4l2_subdev_state_get_format(state, 0) = fmt->format; -+ return 0; -+} -+ -+static int imx681_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *state, -+ struct v4l2_subdev_selection *sel) -+{ -+ switch (sel->target) { -+ case V4L2_SEL_TGT_CROP: -+ sel->r = *v4l2_subdev_state_get_crop(state, sel->pad); -+ break; -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ sel->r.left = 0; -+ sel->r.top = 0; -+ sel->r.width = IMX681_WIDTH; -+ sel->r.height = IMX681_HEIGHT; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int imx681_init_state(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *state) -+{ -+ imx681_fill_fmt(v4l2_subdev_state_get_format(state, 0)); -+ *v4l2_subdev_state_get_crop(state, 0) = (struct v4l2_rect) { -+ .width = IMX681_WIDTH, -+ .height = IMX681_HEIGHT, -+ }; -+ -+ return 0; -+} -+ -+/* ------------------------------------------------------------ streaming */ -+ -+static int imx681_start_streaming(struct imx681 *sensor) -+{ -+ int ret; -+ -+ ret = pm_runtime_resume_and_get(sensor->dev); -+ if (ret < 0) -+ return ret; -+ -+ ret = cci_multi_reg_write(sensor->regmap, imx681_global_init_table, -+ ARRAY_SIZE(imx681_global_init_table), NULL); -+ if (!ret) -+ ret = cci_multi_reg_write(sensor->regmap, -+ imx681_mode_3840x2640, -+ ARRAY_SIZE(imx681_mode_3840x2640), -+ NULL); -+ if (!ret) -+ ret = cci_write(sensor->regmap, IMX681_REG_FRAME_LENGTH, -+ IMX681_HEIGHT + sensor->vblank_ctrl->val, -+ NULL); -+ if (ret) -+ goto err_rpm_put; -+ -+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); -+ if (ret) -+ goto err_rpm_put; -+ -+ ret = cci_write(sensor->regmap, IMX681_REG_MODE_SELECT, -+ IMX681_MODE_STREAMING, NULL); -+ if (ret) -+ goto err_rpm_put; -+ -+ dev_dbg(sensor->dev, "streaming started\n"); -+ return 0; -+ -+err_rpm_put: -+ dev_err(sensor->dev, "failed to start streaming: %d\n", ret); -+ pm_runtime_put(sensor->dev); -+ return ret; -+} -+ -+static int imx681_stop_streaming(struct imx681 *sensor) -+{ -+ int ret; -+ -+ ret = cci_write(sensor->regmap, IMX681_REG_MODE_SELECT, -+ IMX681_MODE_STANDBY, NULL); -+ pm_runtime_put_autosuspend(sensor->dev); -+ return ret; -+} -+ -+static int imx681_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct imx681 *sensor = to_imx681(sd); -+ -+ return enable ? imx681_start_streaming(sensor) : -+ imx681_stop_streaming(sensor); -+} -+ -+static const struct v4l2_subdev_video_ops imx681_video_ops = { -+ .s_stream = imx681_s_stream, -+}; -+ -+static const struct v4l2_subdev_pad_ops imx681_pad_ops = { -+ .enum_mbus_code = imx681_enum_mbus_code, -+ .enum_frame_size = imx681_enum_frame_size, -+ .get_fmt = v4l2_subdev_get_fmt, -+ .set_fmt = imx681_set_pad_fmt, -+ .get_selection = imx681_get_selection, -+}; -+ -+static const struct v4l2_subdev_ops imx681_subdev_ops = { -+ .video = &imx681_video_ops, -+ .pad = &imx681_pad_ops, -+}; -+ -+static const struct v4l2_subdev_internal_ops imx681_internal_ops = { -+ .init_state = imx681_init_state, -+}; -+ -+static int imx681_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct imx681 *sensor; -+ unsigned int i; -+ int ret; -+ -+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); -+ if (!sensor) -+ return -ENOMEM; -+ sensor->dev = dev; -+ -+ v4l2_i2c_subdev_init(&sensor->sd, client, &imx681_subdev_ops); -+ sensor->sd.internal_ops = &imx681_internal_ops; -+ -+ for (i = 0; i < ARRAY_SIZE(imx681_supply_name); i++) -+ sensor->supplies[i].supply = imx681_supply_name[i]; -+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(imx681_supply_name), -+ sensor->supplies); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to get regulators\n"); -+ -+ sensor->xclk = devm_clk_get(dev, NULL); -+ if (IS_ERR(sensor->xclk)) -+ return dev_err_probe(dev, PTR_ERR(sensor->xclk), -+ "failed to get xclk\n"); -+ -+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", -+ GPIOD_OUT_HIGH); -+ if (IS_ERR(sensor->reset_gpio)) -+ return dev_err_probe(dev, PTR_ERR(sensor->reset_gpio), -+ "failed to get reset gpio\n"); -+ -+ sensor->regmap = devm_cci_regmap_init_i2c(client, 16); -+ if (IS_ERR(sensor->regmap)) -+ return dev_err_probe(dev, PTR_ERR(sensor->regmap), -+ "failed to init regmap\n"); -+ -+ ret = imx681_power_on(dev); -+ if (ret) -+ return ret; -+ -+ ret = imx681_identify(sensor); -+ if (ret) -+ goto err_power_off; -+ -+ ret = imx681_init_controls(sensor); -+ if (ret) -+ goto err_power_off; -+ -+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE; -+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; -+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); -+ if (ret) -+ goto err_ctrls; -+ -+ ret = v4l2_subdev_init_finalize(&sensor->sd); -+ if (ret) -+ goto err_entity; -+ -+ pm_runtime_set_active(dev); -+ pm_runtime_get_noresume(dev); -+ pm_runtime_enable(dev); -+ pm_runtime_set_autosuspend_delay(dev, 2000); -+ pm_runtime_use_autosuspend(dev); -+ -+ ret = v4l2_async_register_subdev_sensor(&sensor->sd); -+ if (ret) { -+ dev_err(dev, "async subdev register failed: %d\n", ret); -+ goto err_pm; -+ } -+ -+ pm_runtime_put_autosuspend(dev); -+ return 0; -+ -+err_pm: -+ pm_runtime_disable(dev); -+ pm_runtime_put_noidle(dev); -+ v4l2_subdev_cleanup(&sensor->sd); -+err_entity: -+ media_entity_cleanup(&sensor->sd.entity); -+err_ctrls: -+ v4l2_ctrl_handler_free(&sensor->ctrl_handler); -+err_power_off: -+ imx681_power_off(dev); -+ return ret; -+} -+ -+static void imx681_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct imx681 *sensor = to_imx681(sd); -+ -+ v4l2_async_unregister_subdev(sd); -+ v4l2_subdev_cleanup(sd); -+ media_entity_cleanup(&sd->entity); -+ v4l2_ctrl_handler_free(&sensor->ctrl_handler); -+ -+ pm_runtime_disable(&client->dev); -+ if (!pm_runtime_status_suspended(&client->dev)) -+ imx681_power_off(&client->dev); -+ pm_runtime_set_suspended(&client->dev); -+} -+ -+static const struct dev_pm_ops imx681_pm_ops = { -+ SET_RUNTIME_PM_OPS(imx681_power_off, imx681_power_on, NULL) -+}; -+ -+static const struct of_device_id imx681_dt_ids[] = { -+ { .compatible = "sony,imx681" }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, imx681_dt_ids); -+ -+static struct i2c_driver imx681_i2c_driver = { -+ .driver = { -+ .name = "imx681", -+ .of_match_table = imx681_dt_ids, -+ .pm = &imx681_pm_ops, -+ }, -+ .probe = imx681_probe, -+ .remove = imx681_remove, -+}; -+ -+module_i2c_driver(imx681_i2c_driver); -+ -+MODULE_DESCRIPTION("Sony IMX681 sensor driver (Surface Pro 11)"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c -index b324d9a27fc5..ce6999b57c55 100644 ---- a/drivers/media/i2c/ov13858.c -+++ b/drivers/media/i2c/ov13858.c -@@ -3,9 +3,13 @@ - - #include - #include -+#include -+#include - #include -+#include - #include - #include -+#include - #include - #include - #include -@@ -165,7 +169,8 @@ static const struct ov13858_reg mipi_data_rate_540mbps[] = { - }; - - static const struct ov13858_reg mode_4224x3136_regs[] = { -- {0x3013, 0x32}, -+ {0x3012, 0x40}, -+ {0x3013, 0x72}, - {0x301b, 0xf0}, - {0x301f, 0xd0}, - {0x3106, 0x15}, -@@ -249,7 +254,7 @@ static const struct ov13858_reg mode_4224x3136_regs[] = { - {0x3815, 0x01}, - {0x3816, 0x01}, - {0x3817, 0x01}, -- {0x3820, 0xa8}, -+ {0x3820, 0xb0}, - {0x3821, 0x00}, - {0x3822, 0xc2}, - {0x3823, 0x18}, -@@ -356,7 +361,8 @@ static const struct ov13858_reg mode_4224x3136_regs[] = { - }; - - static const struct ov13858_reg mode_2112x1568_regs[] = { -- {0x3013, 0x32}, -+ {0x3012, 0x40}, -+ {0x3013, 0x72}, - {0x301b, 0xf0}, - {0x301f, 0xd0}, - {0x3106, 0x15}, -@@ -440,7 +446,7 @@ static const struct ov13858_reg mode_2112x1568_regs[] = { - {0x3815, 0x01}, - {0x3816, 0x03}, - {0x3817, 0x01}, -- {0x3820, 0xab}, -+ {0x3820, 0xb3}, - {0x3821, 0x00}, - {0x3822, 0xc2}, - {0x3823, 0x18}, -@@ -547,7 +553,8 @@ static const struct ov13858_reg mode_2112x1568_regs[] = { - }; - - static const struct ov13858_reg mode_2112x1188_regs[] = { -- {0x3013, 0x32}, -+ {0x3012, 0x40}, -+ {0x3013, 0x72}, - {0x301b, 0xf0}, - {0x301f, 0xd0}, - {0x3106, 0x15}, -@@ -631,7 +638,7 @@ static const struct ov13858_reg mode_2112x1188_regs[] = { - {0x3815, 0x01}, - {0x3816, 0x03}, - {0x3817, 0x01}, -- {0x3820, 0xab}, -+ {0x3820, 0xb3}, - {0x3821, 0x00}, - {0x3822, 0xc2}, - {0x3823, 0x18}, -@@ -738,7 +745,8 @@ static const struct ov13858_reg mode_2112x1188_regs[] = { - }; - - static const struct ov13858_reg mode_1056x784_regs[] = { -- {0x3013, 0x32}, -+ {0x3012, 0x40}, -+ {0x3013, 0x72}, - {0x301b, 0xf0}, - {0x301f, 0xd0}, - {0x3106, 0x15}, -@@ -822,7 +830,7 @@ static const struct ov13858_reg mode_1056x784_regs[] = { - {0x3815, 0x01}, - {0x3816, 0x07}, - {0x3817, 0x01}, -- {0x3820, 0xac}, -+ {0x3820, 0xb4}, - {0x3821, 0x00}, - {0x3822, 0xc2}, - {0x3823, 0x18}, -@@ -936,12 +944,231 @@ static const char * const ov13858_test_pattern_menu[] = { - "Vertical Color Bar Type 4" - }; - --/* Configurations for supported link frequencies */ --#define OV13858_NUM_OF_LINK_FREQS 2 -+/* -+ * Surface Pro 11 rear-camera mode, independently reconstructed from runtime -+ * I2C transactions observed on the author's own hardware: 4076x2806 at -+ * 30 fps, four data lanes, 1185.6 Mbps/lane (D-PHY clock 592.8 MHz). -+ */ -+static const struct ov13858_reg mipi_data_rate_1186mbps[] = { -+ {0x0300, 0x05}, -+ {0x0301, 0x00}, -+ {0x0302, 0xf7}, -+ {0x0303, 0x00}, -+ {0x0304, 0x00}, -+ {0x0305, 0x01}, -+ {0x030b, 0x05}, -+ {0x030c, 0x01}, -+ {0x030d, 0x0e}, -+ {0x0312, 0x01}, -+}; -+ -+static const struct ov13858_reg mode_4076x2806_regs[] = { -+ {0x3022, 0x01}, -+ {0x3012, 0x40}, -+ {0x3013, 0x72}, -+ {0x3016, 0x72}, -+ {0x301b, 0xf0}, -+ {0x301f, 0xd0}, -+ {0x3106, 0x15}, -+ {0x3107, 0x23}, -+ {0x3500, 0x00}, -+ {0x3501, 0x80}, -+ {0x3502, 0x00}, -+ {0x3508, 0x02}, -+ {0x3509, 0x00}, -+ {0x350a, 0x00}, -+ {0x350e, 0x00}, -+ {0x3510, 0x00}, -+ {0x3511, 0x02}, -+ {0x3512, 0x00}, -+ {0x3600, 0x2b}, -+ {0x3601, 0x52}, -+ {0x3602, 0x60}, -+ {0x3612, 0x05}, -+ {0x3613, 0xa4}, -+ {0x3620, 0x80}, -+ {0x3621, 0x10}, -+ {0x3622, 0x30}, -+ {0x3624, 0x1c}, -+ {0x3640, 0x10}, -+ {0x3641, 0x70}, -+ {0x3660, 0x04}, -+ {0x3661, 0x80}, -+ {0x3662, 0x12}, -+ {0x3664, 0x73}, -+ {0x3665, 0xa7}, -+ {0x366e, 0xff}, -+ {0x366f, 0xf4}, -+ {0x3674, 0x00}, -+ {0x3679, 0x0c}, -+ {0x367f, 0x01}, -+ {0x3680, 0x0c}, -+ {0x3681, 0x50}, -+ {0x3682, 0x50}, -+ {0x3683, 0xa9}, -+ {0x3684, 0xa9}, -+ {0x3706, 0x40}, -+ {0x3709, 0x5f}, -+ {0x3714, 0x24}, -+ {0x371a, 0x3e}, -+ {0x3737, 0x04}, -+ {0x3738, 0xcc}, -+ {0x3739, 0x12}, -+ {0x373d, 0x26}, -+ {0x3764, 0x20}, -+ {0x3765, 0x20}, -+ {0x37a1, 0x36}, -+ {0x37a8, 0x3b}, -+ {0x37ab, 0x31}, -+ {0x37c2, 0x04}, -+ {0x37c3, 0xf1}, -+ {0x37c5, 0x00}, -+ {0x37d8, 0x03}, -+ {0x37d9, 0x0c}, -+ {0x37da, 0xc2}, -+ {0x37dc, 0x02}, -+ {0x37e0, 0x00}, -+ {0x37e1, 0x0a}, -+ {0x37e2, 0x14}, -+ {0x37e3, 0x04}, -+ {0x37e4, 0x2a}, -+ {0x37e5, 0x03}, -+ {0x37e6, 0x04}, -+ {0x3800, 0x00}, -+ {0x3801, 0x40}, -+ {0x3802, 0x00}, -+ {0x3803, 0xa0}, -+ {0x3804, 0x10}, -+ {0x3805, 0x5f}, -+ {0x3806, 0x0b}, -+ {0x3807, 0xbf}, -+ {0x3808, 0x0f}, -+ {0x3809, 0xec}, -+ {0x380a, 0x0a}, -+ {0x380b, 0xf6}, -+ {0x380c, 0x04}, -+ {0x380d, 0x62}, -+ {0x380e, 0x0c}, -+ {0x380f, 0x88}, -+ {0x3811, 0x1a}, -+ {0x3813, 0x15}, -+ {0x3814, 0x01}, -+ {0x3815, 0x01}, -+ {0x3816, 0x01}, -+ {0x3817, 0x01}, -+ {0x3820, 0xb0}, -+ {0x3821, 0x00}, -+ {0x3822, 0xc2}, -+ {0x3823, 0x18}, -+ {0x3826, 0x11}, -+ {0x3827, 0x1c}, -+ {0x3829, 0x03}, -+ {0x3832, 0x00}, -+ {0x3c80, 0x00}, -+ {0x3c87, 0x01}, -+ {0x3c8c, 0x19}, -+ {0x3c8d, 0x1c}, -+ {0x3c90, 0x00}, -+ {0x3c91, 0x00}, -+ {0x3c92, 0x00}, -+ {0x3c93, 0x00}, -+ {0x3c94, 0x40}, -+ {0x3c95, 0x54}, -+ {0x3c96, 0x34}, -+ {0x3c97, 0x04}, -+ {0x3c98, 0x00}, -+ {0x3d8c, 0x73}, -+ {0x3d8d, 0xc0}, -+ {0x3f00, 0x0b}, -+ {0x3f03, 0x00}, -+ {0x4001, 0xe0}, -+ {0x4008, 0x00}, -+ {0x4009, 0x0f}, -+ {0x4011, 0xf0}, -+ {0x4017, 0x08}, -+ {0x4050, 0x04}, -+ {0x4051, 0x0b}, -+ {0x4052, 0x00}, -+ {0x4053, 0x80}, -+ {0x4054, 0x00}, -+ {0x4055, 0x80}, -+ {0x4056, 0x00}, -+ {0x4057, 0x80}, -+ {0x4058, 0x00}, -+ {0x4059, 0x80}, -+ {0x405e, 0x00}, -+ {0x4500, 0x07}, -+ {0x450a, 0x04}, -+ {0x4800, 0x60}, -+ {0x4809, 0x04}, -+ {0x480c, 0x12}, -+ {0x481f, 0x30}, -+ {0x4833, 0x10}, -+ {0x4837, 0x0d}, -+ {0x4902, 0x01}, -+ {0x4d00, 0x03}, -+ {0x4d01, 0xc9}, -+ {0x4d02, 0xbc}, -+ {0x4d03, 0xd7}, -+ {0x4d04, 0xf0}, -+ {0x4d05, 0xa2}, -+ {0x5000, 0xfd}, -+ {0x5001, 0x01}, -+ {0x5040, 0x39}, -+ {0x5041, 0x10}, -+ {0x5042, 0x10}, -+ {0x5043, 0x84}, -+ {0x5044, 0x62}, -+ {0x5180, 0x00}, -+ {0x5181, 0x10}, -+ {0x5182, 0x02}, -+ {0x5183, 0x0f}, -+ {0x5200, 0x1b}, -+ {0x520b, 0x07}, -+ {0x520c, 0x0f}, -+ {0x5300, 0x04}, -+ {0x5301, 0x0c}, -+ {0x5302, 0x0c}, -+ {0x5303, 0x0f}, -+ {0x5304, 0x00}, -+ {0x5305, 0x70}, -+ {0x5306, 0x00}, -+ {0x5307, 0x80}, -+ {0x5308, 0x00}, -+ {0x5309, 0xa5}, -+ {0x530a, 0x00}, -+ {0x530b, 0xd3}, -+ {0x530c, 0x00}, -+ {0x530d, 0xf0}, -+ {0x530e, 0x01}, -+ {0x530f, 0x10}, -+ {0x5310, 0x01}, -+ {0x5311, 0x20}, -+ {0x5312, 0x01}, -+ {0x5313, 0x20}, -+ {0x5314, 0x01}, -+ {0x5315, 0x20}, -+ {0x5316, 0x08}, -+ {0x5317, 0x08}, -+ {0x5318, 0x10}, -+ {0x5319, 0x88}, -+ {0x531a, 0x88}, -+ {0x531b, 0xa9}, -+ {0x531c, 0xaa}, -+ {0x531d, 0x0a}, -+ {0x5405, 0x02}, -+ {0x5406, 0x67}, -+ {0x5407, 0x01}, -+ {0x5408, 0x4a}, -+}; -+ -+#define OV13858_NUM_OF_LINK_FREQS 3 -+#define OV13858_LINK_FREQ_593MHZ 592800000ULL - #define OV13858_LINK_FREQ_540MHZ 540000000ULL - #define OV13858_LINK_FREQ_270MHZ 270000000ULL --#define OV13858_LINK_FREQ_INDEX_0 0 --#define OV13858_LINK_FREQ_INDEX_1 1 -+#define OV13858_LINK_FREQ_INDEX_593 0 -+#define OV13858_LINK_FREQ_INDEX_0 1 -+#define OV13858_LINK_FREQ_INDEX_1 2 - - /* - * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample -@@ -957,6 +1184,7 @@ static u64 link_freq_to_pixel_rate(u64 f) - - /* Menu items for LINK_FREQ V4L2 control */ - static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = { -+ OV13858_LINK_FREQ_593MHZ, - OV13858_LINK_FREQ_540MHZ, - OV13858_LINK_FREQ_270MHZ - }; -@@ -964,6 +1192,13 @@ static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = { - /* Link frequency configs */ - static const struct ov13858_link_freq_config - link_freq_configs[OV13858_NUM_OF_LINK_FREQS] = { -+ { -+ .pixels_per_line = 4488, -+ .reg_list = { -+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_1186mbps), -+ .regs = mipi_data_rate_1186mbps, -+ } -+ }, - { - .pixels_per_line = OV13858_PPL_540MHZ, - .reg_list = { -@@ -982,6 +1217,17 @@ static const struct ov13858_link_freq_config - - /* Mode configs */ - static const struct ov13858_mode supported_modes[] = { -+ { -+ .width = 4076, -+ .height = 2806, -+ .vts_def = 3208, -+ .vts_min = 3208, -+ .reg_list = { -+ .num_of_regs = ARRAY_SIZE(mode_4076x2806_regs), -+ .regs = mode_4076x2806_regs, -+ }, -+ .link_freq_index = OV13858_LINK_FREQ_INDEX_593, -+ }, - { - .width = 4224, - .height = 3136, -@@ -1028,9 +1274,19 @@ static const struct ov13858_mode supported_modes[] = { - } - }; - -+static const char * const ov13858_supply_names[] = { -+ "dovdd", /* Digital I/O power */ -+ "dvdd", /* Digital core power */ -+ "avdd", /* Analog power */ -+}; -+ -+#define OV13858_NUM_SUPPLIES ARRAY_SIZE(ov13858_supply_names) -+ - struct ov13858 { - struct device *dev; - struct clk *clk; -+ struct gpio_desc *reset; -+ struct regulator_bulk_data supplies[OV13858_NUM_SUPPLIES]; - - struct v4l2_subdev sd; - struct media_pad pad; -@@ -1677,10 +1933,86 @@ static void ov13858_free_controls(struct ov13858 *ov13858) - mutex_destroy(&ov13858->mutex); - } - -+static int ov13858_enable_regulators(struct ov13858 *ov13858) -+{ -+ unsigned int i; -+ int ret; -+ -+ /* CAMS_RES_MSHW0491 D0 order: DOVDD, DVDD, then AVDD. */ -+ for (i = 0; i < OV13858_NUM_SUPPLIES; i++) { -+ ret = regulator_enable(ov13858->supplies[i].consumer); -+ if (ret) { -+ dev_err(ov13858->dev, "failed to enable %s: %d\n", -+ ov13858->supplies[i].supply, ret); -+ regulator_bulk_disable(i, ov13858->supplies); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int ov13858_power_on(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct ov13858 *ov13858 = to_ov13858(sd); -+ int ret; -+ -+ gpiod_set_value_cansleep(ov13858->reset, 1); -+ -+ ret = ov13858_enable_regulators(ov13858); -+ if (ret) -+ return ret; -+ -+ /* Let the sensor rails settle before enabling MCLK. */ -+ usleep_range(1000, 1100); -+ -+ ret = clk_prepare_enable(ov13858->clk); -+ if (ret) { -+ dev_err(dev, "failed to enable clock: %d\n", ret); -+ regulator_bulk_disable(OV13858_NUM_SUPPLIES, -+ ov13858->supplies); -+ return ret; -+ } -+ -+ gpiod_set_value_cansleep(ov13858->reset, 0); -+ -+ /* Reset release to first SCCB transaction */ -+ usleep_range(10000, 12000); -+ -+ return 0; -+} -+ -+static int ov13858_power_off(struct device *dev) -+{ -+ struct v4l2_subdev *sd = dev_get_drvdata(dev); -+ struct ov13858 *ov13858 = to_ov13858(sd); -+ -+ gpiod_set_value_cansleep(ov13858->reset, 1); -+ -+ /* -+ * CAMS_RES_MSHW0491 keeps reset asserted for 1 ms before stopping -+ * MCLK. Give the sensor clock cycles to enter reset before its clock -+ * and rails disappear; rapid power cycles otherwise can leave SCCB -+ * unable to complete the first transaction after power-up. -+ */ -+ if (ov13858->reset) -+ usleep_range(1000, 1100); -+ -+ clk_disable_unprepare(ov13858->clk); -+ -+ /* regulator_bulk_disable() reverses the D0 array: AVDD, DVDD, DOVDD. */ -+ regulator_bulk_disable(OV13858_NUM_SUPPLIES, ov13858->supplies); -+ -+ return 0; -+} -+ - static int ov13858_probe(struct i2c_client *client) - { - struct ov13858 *ov13858; - unsigned long freq; -+ bool full_power; -+ unsigned int i; - int ret; - - ov13858 = devm_kzalloc(&client->dev, sizeof(*ov13858), GFP_KERNEL); -@@ -1700,14 +2032,43 @@ static int ov13858_probe(struct i2c_client *client) - "external clock %lu is not supported\n", - freq); - -+ for (i = 0; i < OV13858_NUM_SUPPLIES; i++) -+ ov13858->supplies[i].supply = ov13858_supply_names[i]; -+ -+ ret = devm_regulator_bulk_get(ov13858->dev, OV13858_NUM_SUPPLIES, -+ ov13858->supplies); -+ if (ret) -+ return dev_err_probe(ov13858->dev, ret, -+ "failed to get regulators\n"); -+ -+ /* Request the reset GPIO asserted, power-on releases it */ -+ ov13858->reset = devm_gpiod_get_optional(ov13858->dev, "reset", -+ GPIOD_OUT_HIGH); -+ if (IS_ERR(ov13858->reset)) -+ return dev_err_probe(ov13858->dev, PTR_ERR(ov13858->reset), -+ "failed to get reset GPIO\n"); -+ - /* Initialize subdev */ - v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); - -- /* Check module identity */ -- ret = ov13858_identify_module(ov13858); -- if (ret) { -- dev_err(ov13858->dev, "failed to find sensor: %d\n", ret); -- return ret; -+ /* -+ * With ACPI domain PM the device may already be powered; only -+ * drive the power sequence ourselves when probing in full power -+ * state (always the case for OF). -+ */ -+ full_power = acpi_dev_state_d0(ov13858->dev); -+ if (full_power) { -+ ret = ov13858_power_on(ov13858->dev); -+ if (ret) -+ return ret; -+ -+ /* Check module identity */ -+ ret = ov13858_identify_module(ov13858); -+ if (ret) { -+ dev_err(ov13858->dev, "failed to find sensor: %d\n", -+ ret); -+ goto error_power_off; -+ } - } - - /* Set default mode to max resolution */ -@@ -1715,7 +2076,7 @@ static int ov13858_probe(struct i2c_client *client) - - ret = ov13858_init_controls(ov13858); - if (ret) -- return ret; -+ goto error_power_off; - - /* Initialize subdev */ - ov13858->sd.internal_ops = &ov13858_internal_ops; -@@ -1737,10 +2098,11 @@ static int ov13858_probe(struct i2c_client *client) - goto error_media_entity; - - /* -- * Device is already turned on by i2c-core with ACPI domain PM. -- * Enable runtime PM and turn off the device. -+ * Device is turned on either by i2c-core with ACPI domain PM or -+ * explicitly above. Enable runtime PM and turn off the device. - */ -- pm_runtime_set_active(ov13858->dev); -+ if (full_power) -+ pm_runtime_set_active(ov13858->dev); - pm_runtime_enable(ov13858->dev); - pm_runtime_idle(ov13858->dev); - -@@ -1753,6 +2115,10 @@ static int ov13858_probe(struct i2c_client *client) - ov13858_free_controls(ov13858); - dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret); - -+error_power_off: -+ if (full_power) -+ ov13858_power_off(ov13858->dev); -+ - return ret; - } - -@@ -1766,8 +2132,12 @@ static void ov13858_remove(struct i2c_client *client) - ov13858_free_controls(ov13858); - - pm_runtime_disable(ov13858->dev); -+ pm_runtime_set_suspended(ov13858->dev); - } - -+static DEFINE_RUNTIME_DEV_PM_OPS(ov13858_pm_ops, ov13858_power_off, -+ ov13858_power_on, NULL); -+ - static const struct i2c_device_id ov13858_id_table[] = { - { .name = "ov13858" }, - { } -@@ -1784,10 +2154,18 @@ static const struct acpi_device_id ov13858_acpi_ids[] = { - MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids); - #endif - -+static const struct of_device_id ov13858_of_match[] = { -+ { .compatible = "ovti,ov13858" }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, ov13858_of_match); -+ - static struct i2c_driver ov13858_i2c_driver = { - .driver = { - .name = "ov13858", -+ .pm = pm_ptr(&ov13858_pm_ops), - .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), -+ .of_match_table = ov13858_of_match, - }, - .probe = ov13858_probe, - .remove = ov13858_remove, -diff --git a/drivers/media/i2c/vd55g0.c b/drivers/media/i2c/vd55g0.c -new file mode 100644 -index 000000000000..21b678093b62 ---- /dev/null -+++ b/drivers/media/i2c/vd55g0.c -@@ -0,0 +1,1995 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Driver for VD55G0 global shutter sensor family driver -+ * -+ * Copyright (C) 2024 STMicroelectronics SA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* Backward compatibility */ -+#include -+ -+#include -+ -+#include -+ -+#define VD55G0_REG_8BIT(n) ((1 << 16) | (n)) -+#define VD55G0_REG_16BIT(n) ((2 << 16) | (n)) -+#define VD55G0_REG_32BIT(n) ((4 << 16) | (n)) -+#define VD55G0_REG_SIZE_SHIFT 16 -+#define VD55G0_REG_ADDR_MASK 0xffff -+ -+#define VD55G0_REG_MODEL_ID VD55G0_REG_16BIT(0x0000) -+#define VD55G0_MODEL_ID 0x4730 -+#define VD55G0_REG_REVISION VD55G0_REG_16BIT(0x0004) -+#define VD55G0_REVISION_CUT1 0x1111 -+#define VD55G0_REVISION_CUT2 0x1120 -+#define VD55G0_REG_FWPATCH_REVISION VD55G0_REG_16BIT(0x0022) -+#define VD55G0_REG_FWPATCH_START_ADDR VD55G0_REG_8BIT(0x2000) -+#define VD55G0_REG_SYSTEM_FSM VD55G0_REG_8BIT(0x002c) -+#define VD55G0_SYSTEM_FSM_READY_TO_BOOT 0x01 -+#define VD55G0_SYSTEM_FSM_SW_STBY 0x02 -+#define VD55G0_SYSTEM_FSM_STREAMING 0x03 -+#define VD55G0_REG_TEMPERATURE VD55G0_REG_16BIT(0x004c) -+#define VD55G0_REG_BOOT VD55G0_REG_8BIT(0x0200) -+#define VD55G0_BOOT_BOOT 1 -+#define VD55G0_BOOT_PATCH_SETUP 2 -+#define VD55G0_REG_SW_STBY VD55G0_REG_8BIT(0x0201) -+#define VD55G0_SW_STBY_START_STREAM 1 -+#define VD55G0_SW_STBY_THSENS_READ 4 -+#define VD55G0_REG_STREAMING VD55G0_REG_8BIT(0x0202) -+#define VD55G0_STREAMING_STOP_STREAM 1 -+#define VD55G0_REG_EXT_CLOCK VD55G0_REG_32BIT(0x0220) -+#define VD55G0_REG_LINE_LENGTH VD55G0_REG_16BIT(0x0300) -+#define VD55G0_REG_ORIENTATION VD55G0_REG_8BIT(0x0302) -+#define VD55G0_REG_FORMAT_CTRL VD55G0_REG_8BIT(0x030a) -+#define VD55G0_REG_OIF_CTRL VD55G0_REG_16BIT(0x030c) -+#define VD55G0_REG_OIF_IMG_CTRL VD55G0_REG_8BIT(0x030f) -+#define VD55G0_REG_CLK_PLL_MIPI VD55G0_REG_32BIT(0x0224) -+#define VD55G0_REG_PATGEN_CTRL VD55G0_REG_16BIT(0x0400) -+#define VD55G0_PATGEN_TYPE_SHIFT 4 -+#define VD55G0_PATGEN_ENABLE BIT(0) -+#define VD55G0_REG_MANUAL_ANALOG_GAIN VD55G0_REG_8BIT(0x044d) -+#define VD55G0_REG_MANUAL_COARSE_EXPOSURE VD55G0_REG_16BIT(0x044e) -+#define VD55G0_REG_MANUAL_DIGITAL_GAIN VD55G0_REG_16BIT(0x0450) -+#define VD55G0_REG_APPLIED_COARSE_EXPOSURE VD55G0_REG_16BIT(0x0064) -+#define VD55G0_REG_APPLIED_ANALOG_GAIN VD55G0_REG_8BIT(0x0066) -+#define VD55G0_REG_APPLIED_DIGITAL_GAIN VD55G0_REG_16BIT(0x0068) -+#define VD55G0_REG_AE_COLDSTART_COARSE_EXPOSURE VD55G0_REG_16BIT(0x042e) -+#define VD55G0_REG_AE_COLDSTART_ANALOG_GAIN VD55G0_REG_8BIT(0x0430) -+#define VD55G0_REG_AE_COLDSTART_DIGITAL_GAIN VD55G0_REG_16BIT(0x0432) -+#define VD55G0_REG_EXP_MODE VD55G0_REG_8BIT(0x044c) -+#define VD55G0_EXP_MODE_AUTO 0 -+#define VD55G0_EXP_MODE_FREEZE 1 -+#define VD55G0_EXP_MODE_MANUAL 2 -+#define VD55G0_REG_FRAME_LENGTH VD55G0_REG_16BIT(0x0458) -+#define VD55G0_REG_ROI_X_START VD55G0_REG_16BIT(0x045e) -+#define VD55G0_REG_ROI_X_END VD55G0_REG_16BIT(0x0460) -+#define VD55G0_REG_ROI_Y_START VD55G0_REG_16BIT(0x0462) -+#define VD55G0_REG_ROI_Y_END VD55G0_REG_16BIT(0x0464) -+#define VD55G0_REG_Y_START VD55G0_REG_16BIT(0x045a) -+#define VD55G0_REG_Y_END VD55G0_REG_16BIT(0x045c) -+#define VD55G0_REG_AE_ROI_START_H VD55G0_REG_16BIT(0x0436) -+#define VD55G0_REG_AE_ROI_START_V VD55G0_REG_16BIT(0x0438) -+#define VD55G0_REG_AE_ROI_END_H VD55G0_REG_16BIT(0x043a) -+#define VD55G0_REG_AE_ROI_END_V VD55G0_REG_16BIT(0x043c) -+#define VD55G0_REG_GPIO_0_CTRL VD55G0_REG_8BIT(0x0467) -+#define VD55G0_REG_GPIO_1_CTRL VD55G0_REG_8BIT(0x0468) -+#define VD55G0_REG_GPIO_2_CTRL VD55G0_REG_8BIT(0x0469) -+#define VD55G0_REG_GPIO_3_CTRL VD55G0_REG_8BIT(0x046a) -+#define VD55G0_REG_READOUT_CTRL VD55G0_REG_8BIT(0x047a) -+#define VD55G0_REG_DARKCAL_CTRL VD55G0_REG_8BIT(0x032c) -+#define VD55G0_DARKCAL_BYPASS 0 -+#define VD55G0_DARKCAL_AUTO 1 -+#define VD55G0_REG_DUSTER_CTRL VD55G0_REG_8BIT(0x0316) -+#define VD55G0_DUSTER_ENABLE BIT(0) -+#define VD55G0_DUSTER_DISABLE 0 -+#define VD55G0_DUSTER_DYN_ENABLE BIT(1) -+#define VD55G0_DUSTER_RING_ENABLE BIT(4) -+#define VD55G0_REG_DARKCAL_PEDESTAL VD55G0_REG_8BIT(0x0416) -+#define VD55G0_REG_AE_TARGET_PERCENTAGE VD55G0_REG_8BIT(0x0440) -+#define VD55G0_REG_VT_CTRL VD55G0_REG_8BIT(0x0309) -+#define VD55G0_VT_SLAVE_GPIO 1 -+ -+#define VD55G0_WIDTH 644 -+#define VD55G0_HEIGHT 604 -+#define VD55G0_DEFAULT_MODE 1 -+#define VD55G0_WRITE_MULTIPLE_CHUNK_MAX 16 -+#define VD55G0_NB_GPIOS 4 -+#define VD55G0_NB_POLARITIES 3 -+#define VD55G0_MIN_FRAME_LENGTH (605 + 76) -+#define VD55G0_FRAME_LENGTH_DEF 1860 /* 60 fps */ -+#define VD55G0_TIMEOUT_MS 500 -+#define VD55G0_MEDIA_BUS_FMT_DEF MEDIA_BUS_FMT_Y8_1X8 -+#define VD55G0_DARKCAL_PEDESTAL_DEF 0x40 -+#define VD55G0_EXPO_MAX_TERM 64 -+#define VD55G0_EXPO_DEF 200 -+#define VD55G0_LINE_LENGTH_SLOW 1200 -+#define VD55G0_LINE_LENGTH_FAST 1128 -+ -+#define V4L2_CID_TEMPERATURE (V4L2_CID_USER_BASE | 0x1020) -+#define V4L2_CID_DARKCAL_PEDESTAL (V4L2_CID_USER_BASE | 0x1021) -+#define V4L2_CID_SLAVE (V4L2_CID_USER_BASE | 0x1022) -+ -+#include "vd55g0_patches.h" -+ -+static const char * const vd55g0_test_pattern_menu[] = { -+ "Disabled", -+ "Solid", -+ "Colorbar", -+ "Gradbar", -+ "Hgrey", -+ "Vgrey", -+ "Dgrey", -+ "PN28", -+}; -+ -+static const s64 vd55g0_ev_bias_menu[] = { -+ -3000, -2500, -2000, -1500, -1000, -500, -+ 0, -+ 500, 1000, 1500, 2000, 2500, 3000, -+}; -+ -+static const char * const vd55g0_supply_name[] = { -+ "VCORE", -+ "VDDIO", -+ "VANA", -+}; -+ -+static const s64 link_freq[] = { -+ /* -+ * MIPI output freq is 804Mhz / 2, as it uses both rising edge and -+ * falling edges to send data -+ */ -+ 402000000ULL -+}; -+ -+enum vd55g0_bin_mode { -+ VD55G0_BIN_MODE_NORMAL, -+ VD55G0_BIN_MODE_DIGITAL_X2, -+ VD55G0_BIN_MODE_DIGITAL_X4, -+}; -+ -+enum vd55g0_gpio_modes { -+ VD55G0_GPIO_MODE_DISABLED, -+ VD55G0_GPIO_MODE_STROBE, -+ VD55G0_GPIO_MODE_VSYNC_OUT_0, -+ VD55G0_GPIO_MODE_VTSLAVE, -+}; -+ -+struct vd55g0_mode_info { -+ u32 width; -+ u32 height; -+ enum vd55g0_bin_mode bin_mode; -+ struct v4l2_rect crop; -+}; -+ -+struct vd55g0_fmt_desc { -+ u32 code; -+ u8 bpp; -+ u8 data_type; -+}; -+ -+static const struct vd55g0_fmt_desc vd55g0_supported_codes[] = { -+ { -+ .code = MEDIA_BUS_FMT_Y8_1X8, -+ .bpp = 8, -+ .data_type = MIPI_CSI2_DT_RAW8, -+ }, -+ { -+ .code = MEDIA_BUS_FMT_Y10_1X10, -+ .bpp = 10, -+ .data_type = MIPI_CSI2_DT_RAW10, -+ }, -+}; -+ -+static const struct vd55g0_mode_info vd55g0_mode_data[] = { -+ { -+ .width = VD55G0_WIDTH, -+ .height = VD55G0_HEIGHT, -+ .bin_mode = VD55G0_BIN_MODE_NORMAL, -+ .crop = { -+ .left = 0, -+ .top = 0, -+ .width = VD55G0_WIDTH, -+ .height = VD55G0_HEIGHT, -+ }, -+ }, -+ { -+ .width = 640, -+ .height = 600, -+ .bin_mode = VD55G0_BIN_MODE_NORMAL, -+ .crop = { -+ .left = 2, -+ .top = 2, -+ .width = 640, -+ .height = 600, -+ }, -+ }, -+ { -+ .width = 640, -+ .height = 480, -+ .bin_mode = VD55G0_BIN_MODE_NORMAL, -+ .crop = { -+ .left = 2, -+ .top = 62, -+ .width = 640, -+ .height = 480, -+ }, -+ }, -+ { -+ .width = 320, -+ .height = 240, -+ .bin_mode = VD55G0_BIN_MODE_DIGITAL_X2, -+ .crop = { -+ .left = 2, -+ .top = 62, -+ .width = 640, -+ .height = 480, -+ }, -+ }, -+}; -+ -+enum vd55g0_expo_state { -+ VD55G0_EXP_AUTO, -+ VD55G0_EXP_FREEZE, -+ VD55G0_EXP_MANUAL -+}; -+ -+struct vd55g0_gpios { -+ u32 leds[VD55G0_NB_GPIOS]; -+ u32 out_sync[VD55G0_NB_GPIOS]; -+ u32 in_sync; -+}; -+ -+struct vd55g0_dev { -+ struct i2c_client *i2c_client; -+ struct v4l2_subdev sd; -+ struct media_pad pad; -+ struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g0_supply_name)]; -+ struct gpio_desc *reset_gpio; -+ struct clk *xclk; -+ u32 clk_freq; -+ u16 oif_ctrl; -+ int nb_of_lane; -+ int data_rate_in_mbps; -+ u16 line_length; -+ u16 revision; -+ /* Lock to protect all members below */ -+ struct mutex lock; -+ struct v4l2_ctrl_handler ctrl_handler; -+ struct v4l2_ctrl *pixel_rate_ctrl; -+ struct v4l2_ctrl *vblank_ctrl; -+ struct v4l2_ctrl *hblank_ctrl; -+ struct v4l2_ctrl *vflip_ctrl; -+ struct v4l2_ctrl *hflip_ctrl; -+ struct v4l2_ctrl *pattern_ctrl; -+ struct v4l2_ctrl *slave_ctrl; -+ struct v4l2_ctrl *expo_ctrl; -+ bool streaming; -+ struct v4l2_mbus_framefmt fmt; -+ const struct vd55g0_mode_info *current_mode; -+ bool hflip; -+ bool vflip; -+ u16 manual_expo; -+ enum vd55g0_expo_state expo_state; -+ u16 digital_gain; -+ u8 analog_gain; -+ u16 vblank; -+ u16 vblank_min; -+ u16 frame_length; -+ bool ae_frozen; -+ u32 pattern; -+ u8 darkcal_pedestal; -+ u16 exposure_target; -+ struct vd55g0_gpios gpios; -+ bool is_slave; -+ bool flash_en; -+ struct { -+ u16 expo; -+ u16 digital_gain; -+ u8 analog_gain; -+ } cold_start; -+}; -+ -+static inline struct vd55g0_dev *to_vd55g0_dev(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct vd55g0_dev, sd); -+} -+ -+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) -+{ -+ return &container_of(ctrl->handler, struct vd55g0_dev, -+ ctrl_handler)->sd; -+} -+ -+static u8 get_bpp_by_code(__u32 code) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++) { -+ if (vd55g0_supported_codes[i].code == code) -+ return vd55g0_supported_codes[i].bpp; -+ } -+ /* Should never happen */ -+ WARN(1, "Unsupported code %d. default to 8 bpp", code); -+ return 8; -+} -+ -+static u8 get_data_type_by_code(__u32 code) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(vd55g0_supported_codes); i++) { -+ if (vd55g0_supported_codes[i].code == code) -+ return vd55g0_supported_codes[i].data_type; -+ } -+ /* Should never happen */ -+ WARN(1, "Unsupported code %d. default to MIPI_CSI2_DT_RAW8 data type", -+ code); -+ return MIPI_CSI2_DT_RAW8; -+} -+ -+static s32 get_pixel_rate(struct vd55g0_dev *sensor) -+{ -+ return div64_u64((u64)sensor->data_rate_in_mbps * sensor->nb_of_lane, -+ get_bpp_by_code(sensor->fmt.code)); -+} -+ -+static int get_chunk_size(struct vd55g0_dev *sensor) -+{ -+ int max_write_len = VD55G0_WRITE_MULTIPLE_CHUNK_MAX; -+ struct i2c_adapter *adapter = sensor->i2c_client->adapter; -+ -+ if (adapter->quirks && adapter->quirks->max_write_len) -+ max_write_len = adapter->quirks->max_write_len - 2; -+ -+ max_write_len = min(max_write_len, VD55G0_WRITE_MULTIPLE_CHUNK_MAX); -+ -+ return max(max_write_len, 1); -+} -+ -+static int vd55g0_read_multiple(struct vd55g0_dev *sensor, u32 reg, -+ unsigned int len) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ struct i2c_msg msg[2]; -+ u8 buf[2]; -+ u8 val[sizeof(u32)] = {0}; -+ int ret; -+ -+ if (len > sizeof(u32)) -+ return -EINVAL; -+ buf[0] = reg >> 8; -+ buf[1] = reg & 0xff; -+ -+ msg[0].addr = client->addr; -+ msg[0].flags = client->flags; -+ msg[0].buf = buf; -+ msg[0].len = sizeof(buf); -+ -+ msg[1].addr = client->addr; -+ msg[1].flags = client->flags | I2C_M_RD; -+ msg[1].buf = val; -+ msg[1].len = len; -+ -+ ret = i2c_transfer(client->adapter, msg, 2); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", -+ __func__, client->addr, reg, ret); -+ return ret; -+ } -+ -+ return get_unaligned_le32(val); -+} -+ -+static inline int vd55g0_read_reg(struct vd55g0_dev *sensor, u32 reg) -+{ -+ return vd55g0_read_multiple(sensor, reg & VD55G0_REG_ADDR_MASK, -+ (reg >> VD55G0_REG_SIZE_SHIFT) & 7); -+} -+ -+static int vd55g0_write_multiple(struct vd55g0_dev *sensor, u32 reg, -+ const u8 *data, unsigned int len, int *err) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ struct i2c_msg msg; -+ u8 buf[VD55G0_WRITE_MULTIPLE_CHUNK_MAX + 2]; -+ unsigned int i; -+ int ret; -+ -+ if (err && *err) -+ return *err; -+ -+ if (len > VD55G0_WRITE_MULTIPLE_CHUNK_MAX) -+ return -EINVAL; -+ buf[0] = reg >> 8; -+ buf[1] = reg & 0xff; -+ for (i = 0; i < len; i++) -+ buf[i + 2] = data[i]; -+ -+ msg.addr = client->addr; -+ msg.flags = client->flags; -+ msg.buf = buf; -+ msg.len = len + 2; -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", -+ __func__, reg, ret); -+ if (err) -+ *err = ret; -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int vd55g0_write_array(struct vd55g0_dev *sensor, u32 reg, -+ unsigned int nb, const u8 *array) -+{ -+ const unsigned int chunk_size = get_chunk_size(sensor); -+ int ret; -+ unsigned int sz; -+ -+ while (nb) { -+ sz = min(nb, chunk_size); -+ ret = vd55g0_write_multiple(sensor, reg, array, sz, NULL); -+ if (ret < 0) -+ return ret; -+ nb -= sz; -+ reg += sz; -+ array += sz; -+ } -+ -+ return 0; -+} -+ -+static inline int vd55g0_write_reg(struct vd55g0_dev *sensor, u32 reg, u32 val, -+ int *err) -+{ -+ return vd55g0_write_multiple(sensor, reg & VD55G0_REG_ADDR_MASK, -+ (u8 *)&val, -+ (reg >> VD55G0_REG_SIZE_SHIFT) & 7, err); -+} -+ -+static int vd55g0_poll_reg(struct vd55g0_dev *sensor, u32 reg, u8 poll_val, -+ unsigned int timeout_ms) -+{ -+ const unsigned int loop_delay_ms = 10; -+ int ret; -+ -+ return read_poll_timeout(vd55g0_read_reg, ret, -+ ((ret < 0) || (ret == poll_val)), -+ loop_delay_ms * 1000, timeout_ms * 1000, -+ false, sensor, reg); -+} -+ -+static int vd55g0_wait_state(struct vd55g0_dev *sensor, int state, -+ unsigned int timeout_ms) -+{ -+ return vd55g0_poll_reg(sensor, VD55G0_REG_SYSTEM_FSM, state, -+ timeout_ms); -+} -+ -+static int vd55g0_update_gpio_mode(struct vd55g0_dev *sensor, u32 mode, -+ int gpio) -+{ -+ u8 index2val[] = {0x01, 0x02, 0x06, 0x0a}; -+ -+ return vd55g0_write_reg(sensor, VD55G0_REG_GPIO_0_CTRL + gpio, -+ index2val[mode], NULL); -+} -+ -+static int vd55g0_set_gpios_array(struct vd55g0_dev *sensor, u32 *array, -+ int size, enum vd55g0_gpio_modes mode) -+{ -+ unsigned int i; -+ int ret; -+ -+ for (i = 0; i < size; i++) { -+ if (array[i] == ~0) -+ break; -+ ret = vd55g0_update_gpio_mode(sensor, mode, array[i]); -+ if (ret) -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int vd55g0_apply_exposure_auto(struct vd55g0_dev *sensor) -+{ -+ enum vd55g0_expo_state exp = sensor->expo_state; -+ -+ if (sensor->ae_frozen && sensor->expo_state == VD55G0_EXP_AUTO) -+ exp = VD55G0_EXP_FREEZE; -+ -+ return vd55g0_write_reg(sensor, VD55G0_REG_EXP_MODE, exp, NULL); -+} -+ -+static int vd55g0_get_regulators(struct vd55g0_dev *sensor) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(vd55g0_supply_name); i++) -+ sensor->supplies[i].supply = vd55g0_supply_name[i]; -+ -+ return devm_regulator_bulk_get(&sensor->i2c_client->dev, -+ ARRAY_SIZE(vd55g0_supply_name), -+ sensor->supplies); -+} -+ -+static int vd55g0_apply_patgen(struct vd55g0_dev *sensor) -+{ -+ static const u8 index2val[] = { -+ 0x0, 0x0, 0x8, 0x10, 0x20, 0x21, 0x22, 0x28 -+ }; -+ u32 pattern = index2val[sensor->pattern]; -+ u32 reg = pattern << VD55G0_PATGEN_TYPE_SHIFT; -+ u8 darkcal = VD55G0_DARKCAL_AUTO; -+ u8 duster = VD55G0_DUSTER_RING_ENABLE | VD55G0_DUSTER_DYN_ENABLE | -+ VD55G0_DUSTER_ENABLE; -+ int ret = 0; -+ -+ if (sensor->pattern != 0) { -+ reg |= VD55G0_PATGEN_ENABLE; -+ /* -+ * Take care of dark calibaration and duster to not mess up the -+ * test pattern output. -+ */ -+ darkcal = VD55G0_DARKCAL_BYPASS; -+ duster = VD55G0_DUSTER_DISABLE; -+ } -+ -+ vd55g0_write_reg(sensor, VD55G0_REG_DARKCAL_CTRL, darkcal, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_DUSTER_CTRL, duster, &ret); -+ if (ret) -+ return ret; -+ -+ return vd55g0_write_reg(sensor, VD55G0_REG_PATGEN_CTRL, reg, NULL); -+} -+ -+static int vd55g0_apply_flash(struct vd55g0_dev *sensor) -+{ -+ struct vd55g0_gpios *gpios = &sensor->gpios; -+ -+ enum vd55g0_gpio_modes mode = sensor->flash_en ? -+ VD55G0_GPIO_MODE_STROBE : -+ VD55G0_GPIO_MODE_DISABLED; -+ -+ return vd55g0_set_gpios_array(sensor, gpios->leds, -+ ARRAY_SIZE(gpios->leds), mode); -+} -+ -+static int vd55g0_update_exposure_auto(struct vd55g0_dev *sensor, u32 index) -+{ -+ switch (index) { -+ case V4L2_EXPOSURE_AUTO: -+ sensor->expo_state = VD55G0_EXP_AUTO; -+ break; -+ case V4L2_EXPOSURE_MANUAL: -+ sensor->expo_state = VD55G0_EXP_MANUAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (sensor->streaming) -+ return vd55g0_apply_exposure_auto(sensor); -+ return 0; -+} -+ -+static int vd55g0_lock_exposure(struct vd55g0_dev *sensor, -+ struct v4l2_ctrl *ctrl) -+{ -+ /* Only exposure lock is supported */ -+ bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; -+ int ret; -+ -+ sensor->ae_frozen = ae_lock; -+ -+ /* Cap control value to reflect the hardware state */ -+ ctrl->val = ae_lock; -+ -+ ret = vd55g0_apply_exposure_auto(sensor); -+ if (ret) -+ return ret; -+ return 0; -+} -+ -+static int vd55g0_get_temp_stream_enable(struct vd55g0_dev *sensor, int *temp) -+{ -+ int temperature; -+ -+ temperature = vd55g0_read_reg(sensor, VD55G0_REG_TEMPERATURE); -+ if (temperature < 0) -+ return temperature; -+ -+ /* temperature is signed 10 bits value. extend sign */ -+ temperature = (temperature << 6) >> 6; -+ *temp = temperature; -+ -+ return 0; -+} -+ -+static int vd55g0_apply_framelength(struct vd55g0_dev *sensor) -+{ -+ return vd55g0_write_reg(sensor, VD55G0_REG_FRAME_LENGTH, -+ sensor->frame_length, NULL); -+} -+ -+static int vd55g0_update_vblank(struct vd55g0_dev *sensor, u16 vblank) -+{ -+ sensor->vblank_min = VD55G0_MIN_FRAME_LENGTH - -+ sensor->current_mode->crop.height; -+ sensor->vblank = vblank; -+ sensor->frame_length = sensor->current_mode->crop.height + -+ sensor->vblank; -+ -+ if (sensor->streaming) -+ return vd55g0_apply_framelength(sensor); -+ return 0; -+} -+ -+static int vd55g0_get_temp_stream_disable(struct vd55g0_dev *sensor, int *temp) -+{ -+ int ret; -+ -+ /* request temperature read */ -+ ret = vd55g0_write_reg(sensor, VD55G0_REG_SW_STBY, -+ VD55G0_SW_STBY_THSENS_READ, NULL); -+ if (ret) -+ return ret; -+ ret = vd55g0_poll_reg(sensor, VD55G0_REG_SW_STBY, 0, VD55G0_TIMEOUT_MS); -+ if (ret) -+ return ret; -+ -+ return vd55g0_get_temp_stream_enable(sensor, temp); -+} -+ -+static int vd55g0_get_temp(struct vd55g0_dev *sensor, int *temp) -+{ -+ *temp = 0; -+ if (sensor->streaming) -+ return vd55g0_get_temp_stream_enable(sensor, temp); -+ else -+ return vd55g0_get_temp_stream_disable(sensor, temp); -+} -+ -+static int vd55g0_update_analog_gain(struct vd55g0_dev *sensor, u32 target) -+{ -+ sensor->analog_gain = target; -+ -+ if (sensor->streaming) -+ return vd55g0_write_reg(sensor, VD55G0_REG_MANUAL_ANALOG_GAIN, -+ target, NULL); -+ return 0; -+} -+ -+static int vd55g0_update_digital_gain(struct vd55g0_dev *sensor, u32 target) -+{ -+ sensor->digital_gain = target; -+ -+ if (sensor->streaming) -+ return vd55g0_write_reg(sensor, VD55G0_REG_MANUAL_DIGITAL_GAIN, -+ target, NULL); -+ return 0; -+} -+ -+static int vd55g0_update_exposure(struct vd55g0_dev *sensor, int expo_ms) -+{ -+ sensor->manual_expo = expo_ms; -+ if (sensor->streaming) -+ return vd55g0_write_reg(sensor, -+ VD55G0_REG_MANUAL_COARSE_EXPOSURE, -+ sensor->manual_expo, NULL); -+ -+ return 0; -+} -+ -+static int vd55g0_update_darkcal_pedestal(struct vd55g0_dev *sensor, -+ int pedestal) -+{ -+ sensor->darkcal_pedestal = pedestal; -+ if (sensor->streaming) -+ return vd55g0_write_reg(sensor, VD55G0_REG_DARKCAL_PEDESTAL, -+ sensor->darkcal_pedestal, NULL); -+ -+ return 0; -+} -+ -+static int vd55g0_update_exposure_target(struct vd55g0_dev *sensor, int index) -+{ -+ /* -+ * Find auto exposure target with: default target exposure * 2^EV -+ * Defaut target exposure being 27 for the sensor. -+ */ -+ static const unsigned int index2exposure_target[] = { -+ 3, 5, 7, 10, 14, 19, 27, 38, 54, 76, 108, 153, 216, -+ }; -+ -+ sensor->exposure_target = index2exposure_target[index]; -+ if (sensor->streaming) -+ return vd55g0_write_reg(sensor, VD55G0_REG_AE_TARGET_PERCENTAGE, -+ sensor->exposure_target, NULL); -+ -+ return 0; -+} -+ -+static int vd55g0_update_flash(struct vd55g0_dev *sensor, int flash_en) -+{ -+ sensor->flash_en = flash_en; -+ if (sensor->streaming) -+ return vd55g0_apply_flash(sensor); -+ -+ return 0; -+} -+ -+static void vd55g0_apply_reset(struct vd55g0_dev *sensor) -+{ -+ gpiod_set_value_cansleep(sensor->reset_gpio, 0); -+ usleep_range(5000, 10000); -+ gpiod_set_value_cansleep(sensor->reset_gpio, 1); -+ usleep_range(5000, 10000); -+ gpiod_set_value_cansleep(sensor->reset_gpio, 0); -+ usleep_range(5000, 10000); -+} -+ -+static void vd55g0_fill_framefmt(struct vd55g0_dev *sensor, -+ const struct vd55g0_mode_info *mode, -+ struct v4l2_mbus_framefmt *fmt, u32 code) -+{ -+ fmt->code = code; -+ fmt->width = mode->width; -+ fmt->height = mode->height; -+ fmt->colorspace = V4L2_COLORSPACE_RAW; -+ fmt->field = V4L2_FIELD_NONE; -+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; -+ fmt->quantization = V4L2_QUANTIZATION_DEFAULT; -+ fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; -+} -+ -+static int vd55g0_try_fmt_internal(struct v4l2_subdev *sd, -+ struct v4l2_mbus_framefmt *fmt, -+ const struct vd55g0_mode_info **new_mode) -+{ -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ const struct vd55g0_mode_info *mode = vd55g0_mode_data; -+ unsigned int index; -+ -+ for (index = 0; index < ARRAY_SIZE(vd55g0_supported_codes); index++) { -+ if (vd55g0_supported_codes[index].code == fmt->code) -+ break; -+ } -+ if (index == ARRAY_SIZE(vd55g0_supported_codes)) -+ index = 0; -+ -+ mode = v4l2_find_nearest_size(vd55g0_mode_data, -+ ARRAY_SIZE(vd55g0_mode_data), width, -+ height, fmt->width, fmt->height); -+ if (new_mode) -+ *new_mode = mode; -+ -+ vd55g0_fill_framefmt(sensor, mode, fmt, -+ vd55g0_supported_codes[index].code); -+ -+ return 0; -+} -+ -+static int vd55g0_apply_cold_start(struct vd55g0_dev *sensor) -+{ -+ int ret = 0; -+ -+ vd55g0_write_reg(sensor, VD55G0_REG_AE_COLDSTART_COARSE_EXPOSURE, -+ sensor->cold_start.expo, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_AE_COLDSTART_ANALOG_GAIN, -+ sensor->cold_start.analog_gain, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_AE_COLDSTART_DIGITAL_GAIN, -+ sensor->cold_start.digital_gain, &ret); -+ -+ return ret; -+} -+ -+static int vd55g0_apply_settings(struct vd55g0_dev *sensor) -+{ -+ int ret; -+ -+ ret = vd55g0_apply_framelength(sensor); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_apply_exposure_auto(sensor); -+ if (ret) -+ return ret; -+ -+ vd55g0_write_reg(sensor, VD55G0_REG_MANUAL_COARSE_EXPOSURE, -+ sensor->manual_expo, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_MANUAL_ANALOG_GAIN, -+ sensor->analog_gain, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_MANUAL_DIGITAL_GAIN, -+ sensor->digital_gain, &ret); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_apply_cold_start(sensor); -+ if (ret) -+ return ret; -+ -+ vd55g0_write_reg(sensor, VD55G0_REG_ORIENTATION, -+ sensor->hflip | (sensor->vflip << 1), &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_DARKCAL_PEDESTAL, -+ sensor->darkcal_pedestal, &ret); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_apply_patgen(sensor); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int vd55g0_apply_frame_format(struct vd55g0_dev *sensor) -+{ -+ const struct v4l2_rect *crop = &sensor->current_mode->crop; -+ int ret = 0; -+ -+ vd55g0_write_reg(sensor, VD55G0_REG_READOUT_CTRL, -+ sensor->current_mode->bin_mode, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_ROI_X_START, crop->left, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_ROI_X_END, -+ crop->left + crop->width - 1, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_ROI_Y_START, crop->top, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_ROI_Y_END, -+ crop->top + crop->height - 1, &ret); -+ -+ /* -+ * Use the same auto exposure crop as the image crop, performing auto -+ * exposure computation only on image boundaries. -+ */ -+ vd55g0_write_reg(sensor, VD55G0_REG_AE_ROI_START_H, crop->left, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_AE_ROI_END_H, -+ crop->left + crop->width - 1, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_AE_ROI_START_V, crop->top, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_AE_ROI_END_V, -+ crop->top + crop->height - 1, &ret); -+ -+ /* -+ * Only aquire lines required for this image format, optimizing power -+ * usage -+ */ -+/* -+ * vd55g0_write_reg(sensor, VD55G0_REG_Y_START, crop->top - 50, &ret); -+ * vd55g0_write_reg(sensor, VD55G0_REG_Y_END, -+ * crop->top + crop->height - 1, &ret); -+ */ -+ -+ return ret; -+} -+ -+static int vd55g0_set_gpios(struct vd55g0_dev *sensor) -+{ -+ struct vd55g0_gpios *gpios = &sensor->gpios; -+ int ret; -+ unsigned int i; -+ -+ /* GPIOs in input (disabled) by default */ -+ for (i = 0; i < VD55G0_NB_GPIOS; i++) { -+ ret = vd55g0_update_gpio_mode(sensor, -+ VD55G0_GPIO_MODE_DISABLED, i); -+ if (ret) -+ return ret; -+ } -+ -+ ret = vd55g0_apply_flash(sensor); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_set_gpios_array(sensor, gpios->out_sync, -+ ARRAY_SIZE(gpios->out_sync), -+ VD55G0_GPIO_MODE_VSYNC_OUT_0); -+ if (ret) -+ return ret; -+ -+ if (!sensor->is_slave) -+ return 0; -+ -+ ret = vd55g0_update_gpio_mode(sensor, VD55G0_GPIO_MODE_VTSLAVE, -+ gpios->in_sync); -+ if (ret) -+ return -EINVAL; -+ ret = vd55g0_write_reg(sensor, VD55G0_REG_VT_CTRL, VD55G0_VT_SLAVE_GPIO, -+ NULL); -+ -+ return ret; -+} -+ -+static int vd55g0_stream_enable(struct vd55g0_dev *sensor) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); -+ int ret; -+ -+ ret = pm_runtime_get_sync(&client->dev); -+ if (ret < 0) { -+ pm_runtime_put_autosuspend(&client->dev); -+ return ret; -+ } -+ -+ /* pm_runtime_get_sync() can return 1 as a valid return code */ -+ ret = 0; -+ -+ ret = vd55g0_set_gpios(sensor); -+ if (ret) -+ goto err_rpm_put; -+ -+ vd55g0_write_reg(sensor, VD55G0_REG_FORMAT_CTRL, -+ get_bpp_by_code(sensor->fmt.code), &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_OIF_IMG_CTRL, -+ get_data_type_by_code(sensor->fmt.code), &ret); -+ if (ret) -+ goto err_rpm_put; -+ -+ ret = vd55g0_apply_frame_format(sensor); -+ if (ret) -+ goto err_rpm_put; -+ -+ ret = vd55g0_apply_settings(sensor); -+ if (ret) -+ goto err_rpm_put; -+ -+ ret = vd55g0_write_reg(sensor, VD55G0_REG_SW_STBY, -+ VD55G0_SW_STBY_START_STREAM, NULL); -+ if (ret) -+ goto err_rpm_put; -+ -+ ret = vd55g0_poll_reg(sensor, VD55G0_REG_SW_STBY, 0, VD55G0_TIMEOUT_MS); -+ if (ret) -+ goto err_rpm_put; -+ -+ ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_STREAMING, -+ VD55G0_TIMEOUT_MS); -+ if (ret) -+ goto err_rpm_put; -+ -+ return 0; -+ -+err_rpm_put: -+ pm_runtime_put(&client->dev); -+ return ret; -+} -+ -+static void vd55g0_save_exposure(struct vd55g0_dev *sensor) -+{ -+ int ret; -+ -+ ret = vd55g0_read_reg(sensor, VD55G0_REG_APPLIED_COARSE_EXPOSURE); -+ sensor->cold_start.expo = ret < 0 ? 0 : ret; -+ ret = vd55g0_read_reg(sensor, VD55G0_REG_APPLIED_DIGITAL_GAIN); -+ sensor->cold_start.digital_gain = ret < 0 ? 0 : ret; -+ ret = vd55g0_read_reg(sensor, VD55G0_REG_APPLIED_ANALOG_GAIN); -+ sensor->cold_start.analog_gain = ret < 0 ? 0 : ret; -+} -+ -+static int vd55g0_stream_disable(struct vd55g0_dev *sensor) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); -+ int ret; -+ -+ /* Keep exposure values for next cold start boot */ -+ vd55g0_save_exposure(sensor); -+ -+ ret = vd55g0_write_reg(sensor, VD55G0_REG_STREAMING, -+ VD55G0_STREAMING_STOP_STREAM, NULL); -+ if (ret) -+ goto err_str_dis; -+ -+ ret = vd55g0_poll_reg(sensor, VD55G0_REG_STREAMING, 0, 2000); -+ if (ret) -+ goto err_str_dis; -+ -+ ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_SW_STBY, -+ VD55G0_TIMEOUT_MS); -+ -+err_str_dis: -+ if (ret) -+ WARN(1, "Can't disable stream"); -+ pm_runtime_put(&client->dev); -+ -+ return ret; -+} -+ -+static int vd55g0_tx_from_ep(struct vd55g0_dev *sensor, -+ struct fwnode_handle *handle) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ struct v4l2_fwnode_endpoint *ep; -+ u32 log2phy[VD55G0_NB_POLARITIES] = {~0, ~0, ~0}; -+ u32 phy2log[VD55G0_NB_POLARITIES] = {~0, ~0, ~0}; -+ int polarities[VD55G0_NB_POLARITIES] = {0, 0, 0}; -+ int l_nb; -+ int p, l; -+ int i; -+ -+ struct v4l2_fwnode_endpoint ep_node = { .bus_type = -+ V4L2_MBUS_CSI2_DPHY -+ }; -+ int ret; -+ -+ ep = &ep_node; -+ ret = v4l2_fwnode_endpoint_alloc_parse(handle, ep); -+ if (ret) -+ return -EINVAL; -+ -+ l_nb = ep->bus.mipi_csi2.num_data_lanes; -+ if (l_nb != 1 && l_nb != 2) { -+ dev_err(&client->dev, "invalid data lane number %d\n", l_nb); -+ goto error_ep; -+ } -+ -+ /* build log2phy, phy2log and polarities from ep info */ -+ log2phy[0] = ep->bus.mipi_csi2.clock_lane; -+ phy2log[log2phy[0]] = 0; -+ for (l = 1; l < l_nb + 1; l++) { -+ log2phy[l] = ep->bus.mipi_csi2.data_lanes[l - 1]; -+ phy2log[log2phy[l]] = l; -+ } -+ /* -+ * then fill remaining slots for every physical slot have something -+ * valid for hardware stuff. -+ */ -+ for (p = 0; p < VD55G0_NB_POLARITIES; p++) { -+ if (phy2log[p] != ~0) -+ continue; -+ phy2log[p] = l; -+ log2phy[l] = p; -+ l++; -+ } -+ for (l = 0; l < l_nb + 1; l++) -+ polarities[l] = ep->bus.mipi_csi2.lane_polarities[l]; -+ -+ if (log2phy[0] != 0) { -+ dev_err(&client->dev, "clk lane must be map to physical lane 0\n"); -+ goto error_ep; -+ } -+ sensor->oif_ctrl = l_nb | -+ (polarities[0] << 3) | -+ ((phy2log[1] - 1) << 4) | -+ (polarities[1] << 6) | -+ ((phy2log[2] - 1) << 7) | -+ (polarities[2] << 9); -+ sensor->nb_of_lane = l_nb; -+ -+ dev_dbg(&client->dev, "tx uses %d lanes", l_nb); -+ for (i = 0; i < VD55G0_NB_POLARITIES; i++) { -+ dev_dbg(&client->dev, "log2phy[%d] = %d", i, log2phy[i]); -+ dev_dbg(&client->dev, "phy2log[%d] = %d", i, phy2log[i]); -+ dev_dbg(&client->dev, "polarity[%d] = %d", i, polarities[i]); -+ } -+ dev_dbg(&client->dev, "oif_ctrl = 0x%04x\n", sensor->oif_ctrl); -+ -+ v4l2_fwnode_endpoint_free(ep); -+ -+ return 0; -+ -+error_ep: -+ v4l2_fwnode_endpoint_free(ep); -+ -+ return -EINVAL; -+} -+ -+static int vd55g0_patch(struct vd55g0_dev *sensor) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ struct vd55g0_patch *patch; -+ int patch_version, ret; -+ -+ /* Choose appropriate patch for sensor revision */ -+ if (sensor->revision == VD55G0_REVISION_CUT1) -+ patch = &vd55g0_patch_cut1; -+ else if (sensor->revision == VD55G0_REVISION_CUT2) -+ patch = &vd55g0_patch_cut2; -+ else -+ return -EINVAL; -+ -+ /* Write patch */ -+ ret = vd55g0_write_array(sensor, VD55G0_REG_FWPATCH_START_ADDR, -+ patch->size, patch->bin); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_write_reg(sensor, VD55G0_REG_BOOT, -+ VD55G0_BOOT_PATCH_SETUP, NULL); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_poll_reg(sensor, VD55G0_REG_BOOT, 0, VD55G0_TIMEOUT_MS); -+ if (ret) -+ return ret; -+ -+ /* Read back patch version */ -+ patch_version = vd55g0_read_reg(sensor, VD55G0_REG_FWPATCH_REVISION); -+ if (patch_version < 0) -+ return patch_version; -+ -+ if (patch_version != (patch->major << 8) + patch->minor) { -+ dev_err(&client->dev, "bad patch version expected %d.%d got %d.%d", -+ patch->major, patch->minor, -+ patch_version >> 8, patch_version & 0xff); -+ return -ENODEV; -+ } -+ dev_dbg(&client->dev, "patch %d.%d applied", -+ patch_version >> 8, patch_version & 0xff); -+ -+ return 0; -+} -+ -+static int vd55g0_boot(struct vd55g0_dev *sensor) -+{ -+ int ret; -+ -+ ret = vd55g0_write_reg(sensor, VD55G0_REG_BOOT, VD55G0_BOOT_BOOT, NULL); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_poll_reg(sensor, VD55G0_REG_BOOT, 0, VD55G0_TIMEOUT_MS); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_SW_STBY, -+ VD55G0_TIMEOUT_MS); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int vd55g0_configure(struct vd55g0_dev *sensor) -+{ -+ /* Double data rate */ -+ u32 mipi_bps = link_freq[0] * 2; -+ int ret = 0; -+ -+ /* Frequency to data rate is 1:1 ratio for MIPI */ -+ sensor->data_rate_in_mbps = mipi_bps; -+ -+ sensor->line_length = VD55G0_LINE_LENGTH_FAST; -+ if (mipi_bps < 900 * HZ_PER_MHZ) -+ sensor->line_length = VD55G0_LINE_LENGTH_SLOW; -+ vd55g0_write_reg(sensor, VD55G0_REG_LINE_LENGTH, sensor->line_length, -+ &ret); -+ -+ /* -+ * PLL_PREDIV and PLL_MULT are not accessible. We rely on the firmware -+ * to set the correct multiplier for the clock. Hence we don't do -+ * anything more here. -+ */ -+ vd55g0_write_reg(sensor, VD55G0_REG_EXT_CLOCK, sensor->clk_freq, &ret); -+ -+ vd55g0_write_reg(sensor, VD55G0_REG_OIF_CTRL, sensor->oif_ctrl, &ret); -+ vd55g0_write_reg(sensor, VD55G0_REG_CLK_PLL_MIPI, mipi_bps, &ret); -+ -+ return ret; -+} -+ -+static inline bool vd55g0_can_be_slave(struct vd55g0_dev *sensor) -+{ -+ return sensor->gpios.in_sync != ~0; -+} -+ -+static int vd55g0_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ int ret = 0; -+ -+ mutex_lock(&sensor->lock); -+ -+ ret = enable ? vd55g0_stream_enable(sensor) : -+ vd55g0_stream_disable(sensor); -+ if (!ret) -+ sensor->streaming = enable; -+ -+ mutex_unlock(&sensor->lock); -+ -+ if (!ret) { -+ /* These settings cannot change during streaming */ -+ v4l2_ctrl_grab(sensor->vflip_ctrl, enable); -+ v4l2_ctrl_grab(sensor->hflip_ctrl, enable); -+ v4l2_ctrl_grab(sensor->pattern_ctrl, enable); -+ if (vd55g0_can_be_slave(sensor)) -+ v4l2_ctrl_grab(sensor->slave_ctrl, enable); -+ } -+ -+ return ret; -+} -+ -+static int vd55g0_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_selection *sel) -+{ -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ -+ switch (sel->target) { -+ case V4L2_SEL_TGT_CROP: -+ sel->r = sensor->current_mode->crop; -+ return 0; -+ case V4L2_SEL_TGT_NATIVE_SIZE: -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ sel->r.top = 0; -+ sel->r.left = 0; -+ sel->r.width = VD55G0_WIDTH; -+ sel->r.height = VD55G0_HEIGHT; -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static int vd55g0_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_mbus_code_enum *code) -+{ -+ if (code->index >= ARRAY_SIZE(vd55g0_supported_codes)) -+ return -EINVAL; -+ -+ code->code = vd55g0_supported_codes[code->index].code; -+ -+ return 0; -+} -+ -+static int vd55g0_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_format *format) -+{ -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ struct v4l2_mbus_framefmt *fmt; -+ -+ mutex_lock(&sensor->lock); -+ -+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) -+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad); -+ else -+ fmt = &sensor->fmt; -+ -+ format->format = *fmt; -+ -+ mutex_unlock(&sensor->lock); -+ -+ return 0; -+} -+ -+static int vd55g0_set_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_format *format) -+{ -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ const struct vd55g0_mode_info *new_mode; -+ struct v4l2_mbus_framefmt *fmt; -+ unsigned int expo_max, hblank; -+ int ret; -+ -+ mutex_lock(&sensor->lock); -+ -+ ret = vd55g0_try_fmt_internal(sd, &format->format, &new_mode); -+ if (ret) -+ goto out; -+ -+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -+ fmt = v4l2_subdev_state_get_format(sd_state, 0); -+ *fmt = format->format; -+ } else if (sensor->current_mode != new_mode || -+ sensor->fmt.code != format->format.code) { -+ fmt = &sensor->fmt; -+ *fmt = format->format; -+ -+ sensor->current_mode = new_mode; -+ -+ /* Reset vblank and framelength to default */ -+ ret = vd55g0_update_vblank(sensor, -+ VD55G0_FRAME_LENGTH_DEF - -+ new_mode->crop.height); -+ -+ /* Update controls to reflect new mode */ -+ __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl, -+ get_pixel_rate(sensor)); -+ __v4l2_ctrl_modify_range(sensor->vblank_ctrl, -+ sensor->vblank_min, -+ 0xffff - new_mode->crop.height, -+ 1, sensor->vblank); -+ __v4l2_ctrl_s_ctrl(sensor->vblank_ctrl, sensor->vblank); -+ /* Max exposure changes with vblank */ -+ expo_max = sensor->frame_length - VD55G0_EXPO_MAX_TERM; -+ __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, 1, -+ VD55G0_EXPO_DEF); -+ /* Update hblank according to new width */ -+ hblank = sensor->line_length - sensor->current_mode->width; -+ __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1, -+ hblank); -+ ret = __v4l2_ctrl_s_ctrl(sensor->hblank_ctrl, hblank); -+ } -+ -+out: -+ mutex_unlock(&sensor->lock); -+ -+ return ret; -+} -+ -+static int vd55g0_init_state(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state) -+{ -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ struct v4l2_subdev_format fmt = { 0 }; -+ -+ vd55g0_fill_framefmt(sensor, sensor->current_mode, &fmt.format, -+ VD55G0_MEDIA_BUS_FMT_DEF); -+ -+ return vd55g0_set_fmt(sd, sd_state, &fmt); -+} -+ -+static int vd55g0_enum_frame_size(struct v4l2_subdev *sd, -+ struct v4l2_subdev_state *sd_state, -+ struct v4l2_subdev_frame_size_enum *fse) -+{ -+ if (fse->index >= ARRAY_SIZE(vd55g0_mode_data)) -+ return -EINVAL; -+ -+ fse->min_width = vd55g0_mode_data[fse->index].width; -+ fse->max_width = fse->min_width; -+ fse->min_height = vd55g0_mode_data[fse->index].height; -+ fse->max_height = fse->min_height; -+ -+ return 0; -+} -+ -+static const struct v4l2_subdev_core_ops vd55g0_core_ops = { -+}; -+ -+static const struct v4l2_subdev_video_ops vd55g0_video_ops = { -+ .s_stream = vd55g0_s_stream, -+}; -+ -+static const struct v4l2_subdev_pad_ops vd55g0_pad_ops = { -+ .enum_mbus_code = vd55g0_enum_mbus_code, -+ .get_fmt = vd55g0_get_fmt, -+ .set_fmt = vd55g0_set_fmt, -+ .get_selection = vd55g0_get_selection, -+ .enum_frame_size = vd55g0_enum_frame_size, -+}; -+ -+static const struct v4l2_subdev_ops vd55g0_subdev_ops = { -+ .core = &vd55g0_core_ops, -+ .video = &vd55g0_video_ops, -+ .pad = &vd55g0_pad_ops, -+}; -+ -+static const struct media_entity_operations vd55g0_subdev_entity_ops = { -+ .link_validate = v4l2_subdev_link_validate, -+}; -+ -+static const struct v4l2_subdev_internal_ops vd55g0_internal_ops = { -+ .init_state = vd55g0_init_state, -+}; -+ -+static int vd55g0_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl); -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ int temperature; -+ int ret; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_PIXEL_RATE: -+ ret = __v4l2_ctrl_s_ctrl_int64(ctrl, get_pixel_rate(sensor)); -+ break; -+ case V4L2_CID_TEMPERATURE: -+ ret = vd55g0_get_temp(sensor, &temperature); -+ if (ret) -+ break; -+ ret = __v4l2_ctrl_s_ctrl(ctrl, temperature); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int vd55g0_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl); -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ unsigned int expo_max; -+ int ret; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_VFLIP: -+ case V4L2_CID_HFLIP: -+ if (sensor->streaming) { -+ ret = -EBUSY; -+ break; -+ } -+ if (ctrl->id == V4L2_CID_VFLIP) -+ sensor->vflip = ctrl->val; -+ if (ctrl->id == V4L2_CID_HFLIP) -+ sensor->hflip = ctrl->val; -+ ret = 0; -+ break; -+ case V4L2_CID_TEST_PATTERN: -+ /* Can't be done while streaming because of duster disabling */ -+ sensor->pattern = ctrl->val; -+ ret = 0; -+ break; -+ case V4L2_CID_EXPOSURE_AUTO: -+ ret = vd55g0_update_exposure_auto(sensor, ctrl->val); -+ break; -+ case V4L2_CID_ANALOGUE_GAIN: -+ ret = vd55g0_update_analog_gain(sensor, ctrl->val); -+ break; -+ case V4L2_CID_DIGITAL_GAIN: -+ ret = vd55g0_update_digital_gain(sensor, ctrl->val); -+ break; -+ case V4L2_CID_EXPOSURE: -+ ret = vd55g0_update_exposure(sensor, ctrl->val); -+ break; -+ case V4L2_CID_3A_LOCK: -+ ret = vd55g0_lock_exposure(sensor, ctrl); -+ break; -+ case V4L2_CID_DARKCAL_PEDESTAL: -+ ret = vd55g0_update_darkcal_pedestal(sensor, ctrl->val); -+ break; -+ case V4L2_CID_VBLANK: -+ ret = vd55g0_update_vblank(sensor, ctrl->val); -+ /* Max exposure changes with vblank */ -+ expo_max = sensor->frame_length - VD55G0_EXPO_MAX_TERM; -+ __v4l2_ctrl_modify_range(sensor->expo_ctrl, 0, expo_max, 1, -+ VD55G0_EXPO_DEF); -+ break; -+ case V4L2_CID_HBLANK: -+ /* Read only control, can only be activated by V4L2 framework */ -+ ret = 0; -+ break; -+ case V4L2_CID_AUTO_EXPOSURE_BIAS: -+ /* -+ * We use auto exposure target percentage register to control -+ * exposure bias for more precision. -+ */ -+ ret = vd55g0_update_exposure_target(sensor, ctrl->val); -+ break; -+ case V4L2_CID_SLAVE: -+ sensor->is_slave = ctrl->val; -+ ret = 0; -+ break; -+ case V4L2_CID_FLASH_LED_MODE: -+ ret = vd55g0_update_flash(sensor, ctrl->val); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static const struct v4l2_ctrl_ops vd55g0_ctrl_ops = { -+ .g_volatile_ctrl = vd55g0_g_volatile_ctrl, -+ .s_ctrl = vd55g0_s_ctrl, -+}; -+ -+static const struct v4l2_ctrl_config vd55g0_temp_ctrl = { -+ .ops = &vd55g0_ctrl_ops, -+ .id = V4L2_CID_TEMPERATURE, -+ .name = "Temperature in celsius", -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .min = -1024, -+ .max = 1023, -+ .step = 1, -+}; -+ -+static const struct v4l2_ctrl_config vd55g0_darkcal_pedestal_ctrl = { -+ .ops = &vd55g0_ctrl_ops, -+ .id = V4L2_CID_DARKCAL_PEDESTAL, -+ .name = "Dark Calibration Pedestal", -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .min = 0, -+ .max = 255, -+ .step = 1, -+ .def = VD55G0_DARKCAL_PEDESTAL_DEF, -+}; -+ -+static const struct v4l2_ctrl_config vd55g0_slave_ctrl = { -+ .ops = &vd55g0_ctrl_ops, -+ .id = V4L2_CID_SLAVE, -+ .name = "VT Slave Mode", -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def = 1, -+}; -+ -+static int vd55g0_init_controls(struct vd55g0_dev *sensor) -+{ -+ const struct v4l2_ctrl_ops *ops = &vd55g0_ctrl_ops; -+ struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler; -+ const struct vd55g0_mode_info *cur_mode = sensor->current_mode; -+ struct v4l2_ctrl *ctrl; -+ unsigned int patgen_size = ARRAY_SIZE(vd55g0_test_pattern_menu) - 1; -+ unsigned int hblank = sensor->line_length - sensor->current_mode->width; -+ unsigned int expo_mode = sensor->expo_state == VD55G0_EXP_AUTO ? -+ V4L2_EXPOSURE_AUTO : V4L2_EXPOSURE_MANUAL; -+ int ret; -+ -+ v4l2_ctrl_handler_init(hdl, 16); -+ /* we can use our own mutex for the ctrl lock */ -+ hdl->lock = &sensor->lock; -+ v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_AUTO_EXPOSURE_BIAS, -+ ARRAY_SIZE(vd55g0_ev_bias_menu) - 1, -+ ARRAY_SIZE(vd55g0_ev_bias_menu) / 2, -+ vd55g0_ev_bias_menu); -+ ctrl = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, -+ ARRAY_SIZE(link_freq) - 1, 0, link_freq); -+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_EXPOSURE_AUTO, 1, ~0x3, -+ expo_mode); -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, 24, 1, -+ sensor->analog_gain); -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, 256, 2048, 1, -+ sensor->digital_gain); -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, 0, 1, 0, 0); -+ ctrl = v4l2_ctrl_new_custom(hdl, &vd55g0_temp_ctrl, NULL); -+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY; -+ v4l2_ctrl_new_custom(hdl, &vd55g0_darkcal_pedestal_ctrl, NULL); -+ v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_FLASH_LED_MODE, -+ V4L2_FLASH_LED_MODE_FLASH, ~0x7, -+ sensor->flash_en); -+ -+ /* -+ * Keep a pointer to these controls as we need to update them when -+ * setting the format -+ */ -+ sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops, -+ V4L2_CID_PIXEL_RATE, 1, -+ INT_MAX, 1, -+ get_pixel_rate(sensor)); -+ if (sensor->pixel_rate_ctrl) -+ sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ sensor->vblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, -+ sensor->vblank_min, -+ 0xffff - cur_mode->crop.height, -+ 1, sensor->vblank); -+ sensor->hblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, -+ hblank, hblank, 1, hblank); -+ if (sensor->hblank_ctrl) -+ sensor->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; -+ sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, -+ 0, 1, 1, sensor->vflip); -+ sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, -+ 0, 1, 1, sensor->hflip); -+ sensor->pattern_ctrl = -+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, -+ patgen_size, 0, 0, -+ vd55g0_test_pattern_menu); -+ sensor->slave_ctrl = v4l2_ctrl_new_custom(hdl, &vd55g0_slave_ctrl, -+ NULL); -+ sensor->expo_ctrl = -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0, -+ sensor->frame_length - VD55G0_EXPO_MAX_TERM, -+ 1, sensor->manual_expo); -+ -+ if (hdl->error) { -+ ret = hdl->error; -+ goto free_ctrls; -+ } -+ -+ /* Disable this control if not possible by device tree */ -+ if (!vd55g0_can_be_slave(sensor)) { -+ v4l2_ctrl_s_ctrl(sensor->slave_ctrl, false); -+ v4l2_ctrl_grab(sensor->slave_ctrl, true); -+ } -+ -+ sensor->sd.ctrl_handler = hdl; -+ return 0; -+ -+free_ctrls: -+ v4l2_ctrl_handler_free(hdl); -+ return ret; -+} -+ -+static int vd55g0_detect(struct vd55g0_dev *sensor) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ int revision, id = 0; -+ -+ id = vd55g0_read_reg(sensor, VD55G0_REG_MODEL_ID); -+ if (id < 0) -+ return id; -+ -+ if (id != VD55G0_MODEL_ID) { -+ dev_warn(&client->dev, "Unsupported sensor id %x", id); -+ return -ENODEV; -+ } -+ -+ revision = vd55g0_read_reg(sensor, VD55G0_REG_REVISION); -+ dev_dbg(&client->dev, "Sensor revision 0x%x", revision); -+ if (revision < 0) -+ return revision; -+ -+ if (revision != VD55G0_REVISION_CUT1 && -+ revision != VD55G0_REVISION_CUT2) { -+ dev_err(&client->dev, "Unsupported device revision 0x%x\n", -+ revision); -+ return -ENODEV; -+ } -+ -+ sensor->revision = revision; -+ -+ return 0; -+} -+ -+/* Power/clock management functions */ -+static int vd55g0_power_on(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ int ret; -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(vd55g0_supply_name), -+ sensor->supplies); -+ if (ret) { -+ dev_err(&client->dev, "failed to enable regulators %d", ret); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(sensor->xclk); -+ if (ret) { -+ dev_err(&client->dev, "failed to enable clock %d", ret); -+ goto disable_bulk; -+ } -+ -+ if (sensor->reset_gpio) -+ vd55g0_apply_reset(sensor); -+ -+ ret = vd55g0_wait_state(sensor, VD55G0_SYSTEM_FSM_READY_TO_BOOT, -+ VD55G0_TIMEOUT_MS); -+ if (ret) { -+ dev_err(&client->dev, "sensor reset failed %d\n", ret); -+ goto disable_clock; -+ } -+ -+ ret = vd55g0_detect(sensor); -+ if (ret) { -+ dev_err(&client->dev, "sensor detect failed %d", ret); -+ goto disable_clock; -+ } -+ -+ ret = vd55g0_patch(sensor); -+ if (ret) { -+ dev_err(&client->dev, "sensor patch failed %d", ret); -+ goto disable_clock; -+ } -+ -+ ret = vd55g0_boot(sensor); -+ if (ret) { -+ dev_err(&client->dev, "sensor boot failed %d", ret); -+ goto disable_clock; -+ } -+ -+ ret = vd55g0_configure(sensor); -+ if (ret) { -+ dev_err(&client->dev, "sensor configuration failed %d", ret); -+ goto disable_clock; -+ } -+ -+ return 0; -+ -+disable_clock: -+ clk_disable_unprepare(sensor->xclk); -+disable_bulk: -+ regulator_bulk_disable(ARRAY_SIZE(vd55g0_supply_name), -+ sensor->supplies); -+ -+ return ret; -+} -+ -+static int vd55g0_power_off(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ -+ clk_disable_unprepare(sensor->xclk); -+ regulator_bulk_disable(ARRAY_SIZE(vd55g0_supply_name), -+ sensor->supplies); -+ return 0; -+} -+ -+static int vd55g0_parse_dt_gpios_array(struct vd55g0_dev *sensor, -+ char *prop_name, u32 *array, int *nb) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ struct device_node *np = client->dev.of_node; -+ unsigned int i; -+ -+ *nb = of_property_read_variable_u32_array(np, prop_name, array, 0, -+ VD55G0_NB_GPIOS); -+ *nb = max(0, *nb); -+ if (*nb > 0) { -+ for (i = 0; i < *nb; i++) { -+ if (array[i] >= VD55G0_NB_GPIOS) { -+ dev_err(&client->dev, "invalid GPIO %d for leds\n", -+ array[i]); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int vd55g0_parse_dt_gpios(struct vd55g0_dev *sensor) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ struct device_node *np = client->dev.of_node; -+ struct vd55g0_gpios *gpios = &sensor->gpios; -+ int nb_gpios_leds, nb_gpios_out; -+ int ret; -+ unsigned int i, j; -+ -+ memset(gpios->leds, ~0, -+ ARRAY_SIZE(gpios->leds) * sizeof(gpios->leds[0])); -+ memset(gpios->out_sync, ~0, -+ ARRAY_SIZE(gpios->out_sync) * sizeof(gpios->out_sync[0])); -+ gpios->in_sync = ~0; -+ -+ ret = vd55g0_parse_dt_gpios_array(sensor, "st,leds", -+ (u32 *)&gpios->leds, -+ &nb_gpios_leds); -+ if (ret) -+ return ret; -+ -+ ret = vd55g0_parse_dt_gpios_array(sensor, "st,out-sync", -+ (u32 *)&gpios->out_sync, -+ &nb_gpios_out); -+ if (ret) -+ return ret; -+ -+ ret = of_property_read_u32(np, "st,in-sync", &gpios->in_sync); -+ if (ret == 0) { -+ if (gpios->in_sync != 0) { -+ dev_err(&client->dev, "input sync gpio must be 0 if present, found %d\n", -+ gpios->in_sync); -+ return -EINVAL; -+ } -+ -+ /* Check no other gpios array use gpio 0 */ -+ for (i = 0; i < nb_gpios_leds; i++) { -+ if (gpios->leds[i] == gpios->in_sync) { -+ dev_err(&client->dev, "in-sync GPIO %d is used by another led gpio\n", -+ gpios->in_sync); -+ return -EINVAL; -+ } -+ } -+ for (i = 0; i < nb_gpios_out; i++) { -+ if (gpios->out_sync[i] == gpios->in_sync) { -+ dev_err(&client->dev, "in-sync GPIO %d is used by another out-sync gpio\n", -+ gpios->in_sync); -+ return -EINVAL; -+ } -+ } -+ -+ dev_dbg(&client->dev, "GPIO %d in input slave mode\n", -+ gpios->in_sync); -+ -+ sensor->is_slave = true; -+ } -+ -+ /* Check mutual exclusivity between leds and out_sync */ -+ for (i = 0; i < nb_gpios_leds; i++) { -+ for (j = 0; j < nb_gpios_out; j++) { -+ if (gpios->leds[i] == gpios->out_sync[j]) { -+ dev_err(&client->dev, "GPIO %d used in both leds and out-sync\n", -+ gpios->leds[i]); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int vd55g0_probe(struct i2c_client *client) -+{ -+ struct device *dev = &client->dev; -+ struct fwnode_handle *handle; -+ struct vd55g0_dev *sensor; -+ int ret; -+ -+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); -+ if (!sensor) -+ return -ENOMEM; -+ -+ sensor->analog_gain = 0; -+ sensor->digital_gain = 256; -+ -+ sensor->i2c_client = client; -+ sensor->streaming = false; -+ sensor->fmt.code = MEDIA_BUS_FMT_SGBRG8_1X8; -+ sensor->fmt.field = V4L2_FIELD_NONE; -+ sensor->fmt.colorspace = V4L2_COLORSPACE_SRGB; -+ sensor->manual_expo = VD55G0_EXPO_DEF; -+ sensor->vflip = false; -+ sensor->hflip = false; -+ sensor->darkcal_pedestal = VD55G0_DARKCAL_PEDESTAL_DEF; -+ sensor->flash_en = false; -+ sensor->cold_start.expo = 0x32; -+ sensor->cold_start.digital_gain = 256; -+ sensor->cold_start.analog_gain = 0; -+ -+ sensor->current_mode = &vd55g0_mode_data[VD55G0_DEFAULT_MODE]; -+ -+ handle = fwnode_graph_get_next_endpoint(of_fwnode_handle(dev->of_node), -+ NULL); -+ if (!handle) { -+ dev_err(dev, "handle node not found\n"); -+ return -EINVAL; -+ } -+ -+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", -+ GPIOD_OUT_HIGH); -+ -+ ret = vd55g0_parse_dt_gpios(sensor); -+ if (ret) { -+ dev_err(dev, "Failed to get gpios\n"); -+ return ret; -+ } -+ -+ ret = vd55g0_tx_from_ep(sensor, handle); -+ fwnode_handle_put(handle); -+ if (ret) { -+ dev_err(dev, "Failed to parse handle %d\n", ret); -+ return ret; -+ } -+ -+ sensor->xclk = devm_clk_get(dev, NULL); -+ if (IS_ERR(sensor->xclk)) { -+ dev_err(dev, "failed to get xclk\n"); -+ return PTR_ERR(sensor->xclk); -+ } -+ sensor->clk_freq = clk_get_rate(sensor->xclk); -+ if (sensor->clk_freq < 6 * HZ_PER_MHZ || -+ sensor->clk_freq > 27 * HZ_PER_MHZ) { -+ dev_err(dev, "Only 6Mhz-27Mhz clock range supported. provide %lu MHz\n", -+ sensor->clk_freq / HZ_PER_MHZ); -+ return -EINVAL; -+ } -+ -+ v4l2_i2c_subdev_init(&sensor->sd, client, &vd55g0_subdev_ops); -+ sensor->sd.internal_ops = &vd55g0_internal_ops; -+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE; -+ sensor->sd.entity.ops = &vd55g0_subdev_entity_ops; -+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; -+ -+ ret = vd55g0_get_regulators(sensor); -+ if (ret) { -+ dev_err(&client->dev, "failed to get regulators %d", ret); -+ return ret; -+ } -+ -+ //TODO power on should not be necessary -+ ret = vd55g0_power_on(dev); -+ if (ret) -+ return ret; -+ -+ vd55g0_fill_framefmt(sensor, sensor->current_mode, &sensor->fmt, -+ VD55G0_MEDIA_BUS_FMT_DEF); -+ -+ mutex_init(&sensor->lock); -+ -+ ret = vd55g0_update_vblank(sensor, VD55G0_FRAME_LENGTH_DEF - -+ sensor->current_mode->crop.height); -+ if (ret) -+ goto error_power_off; -+ -+ ret = vd55g0_init_controls(sensor); -+ if (ret) { -+ dev_err(&client->dev, "controls initialization failed %d", ret); -+ goto error_power_off; -+ } -+ -+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); -+ if (ret) { -+ dev_err(&client->dev, "pads init failed %d", ret); -+ goto error_handler_free; -+ } -+ -+ /* Enable runtime PM and turn off the device */ -+ pm_runtime_set_active(dev); -+ pm_runtime_enable(dev); -+ pm_runtime_idle(dev); -+ -+ ret = v4l2_async_register_subdev(&sensor->sd); -+ if (ret) { -+ dev_err(&client->dev, "async subdev register failed %d", ret); -+ goto error_pm_runtime; -+ } -+ -+ pm_runtime_set_autosuspend_delay(&client->dev, 1000); -+ pm_runtime_use_autosuspend(&client->dev); -+ -+ dev_dbg(&client->dev, "vd55g0 probe successfully"); -+ -+ return 0; -+ -+error_pm_runtime: -+ pm_runtime_disable(&client->dev); -+ pm_runtime_set_suspended(&client->dev); -+ media_entity_cleanup(&sensor->sd.entity); -+error_handler_free: -+ v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); -+error_power_off: -+ mutex_destroy(&sensor->lock); -+ vd55g0_power_off(dev); -+ -+ return ret; -+} -+ -+static void vd55g0_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct vd55g0_dev *sensor = to_vd55g0_dev(sd); -+ -+ v4l2_async_unregister_subdev(&sensor->sd); -+ mutex_destroy(&sensor->lock); -+ media_entity_cleanup(&sensor->sd.entity); -+ -+ pm_runtime_disable(&client->dev); -+ if (!pm_runtime_status_suspended(&client->dev)) -+ vd55g0_power_off(&client->dev); -+ pm_runtime_set_suspended(&client->dev); -+} -+ -+static const struct of_device_id vd55g0_dt_ids[] = { -+ { .compatible = "st,vd55g0" }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, vd55g0_dt_ids); -+ -+static const struct dev_pm_ops vd55g0_pm_ops = { -+ SET_RUNTIME_PM_OPS(vd55g0_power_off, vd55g0_power_on, NULL) -+}; -+ -+static struct i2c_driver vd55g0_i2c_driver = { -+ .driver = { -+ .name = "vd55g0", -+ .of_match_table = vd55g0_dt_ids, -+ .pm = &vd55g0_pm_ops, -+ }, -+ .probe = vd55g0_probe, -+ .remove = vd55g0_remove, -+}; -+ -+module_i2c_driver(vd55g0_i2c_driver); -+ -+MODULE_AUTHOR("Benjamin Mugnier "); -+MODULE_AUTHOR("Mickael Guene "); -+MODULE_AUTHOR("Sylvain Petinot "); -+MODULE_DESCRIPTION("VD55G0 camera subdev driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/i2c/vd55g0_patches.h b/drivers/media/i2c/vd55g0_patches.h -new file mode 100644 -index 000000000000..5582745fd018 ---- /dev/null -+++ b/drivers/media/i2c/vd55g0_patches.h -@@ -0,0 +1,585 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Firmware patches for the VD55G0 sensor family -+ * -+ * Copyright (C) 2024 STMicroelectronics SA -+ */ -+ -+#include -+#include -+ -+static const u8 cut1_patch[] = { -+0x81, 0x06, 0x0b, 0x02, 0x00, 0x09, 0x42, 0x00, 0xd2, 0x08, 0x42, 0x00, 0xe6, -+0x08, 0x42, 0x00, 0x12, 0x09, 0x42, 0x00, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40, 0x01, 0x60, 0x10, 0x40, 0x11, -+0x81, 0x16, 0x80, 0x93, 0xdd, 0x4c, 0x04, 0x04, 0xfa, 0x06, 0x4c, 0x94, 0x60, -+0xe6, 0x0e, 0xdc, 0xe0, 0x04, 0x18, 0x70, 0x02, 0x08, 0xe7, 0xce, 0x44, 0x01, -+0x60, 0x10, 0x40, 0x31, 0x85, 0x1e, 0x08, 0x4e, 0x43, 0x01, 0x60, 0x10, 0xc0, -+0x31, 0x40, 0x20, 0xe0, 0x04, 0x98, 0x29, 0x00, 0x50, 0xeb, 0x2e, 0x84, 0x24, -+0x84, 0x29, 0x86, 0x2e, 0x84, 0x24, 0x84, 0x2b, 0xa1, 0x15, 0xfe, 0xd8, 0x41, -+0x00, 0xe8, 0xf8, 0x47, 0x00, 0xe8, 0x78, 0x44, 0x40, 0xef, 0x0a, 0x9c, 0x1a, -+0x9e, 0x2a, 0xdc, 0x3a, 0xde, 0x03, 0x4e, 0x7c, 0xf9, 0x13, 0x4e, 0x78, 0xf9, -+0x23, 0x4e, 0x74, 0xf9, 0x33, 0x4e, 0x70, 0xf9, 0x18, 0x50, 0x40, 0xef, 0x38, -+0x49, 0x44, 0xef, 0x04, 0x18, 0x11, 0x83, 0x11, 0x40, 0x20, 0xe0, 0x4c, 0x0c, -+0x04, 0xf2, 0x93, 0xdd, 0x86, 0x44, 0x88, 0xe0, 0x05, 0x04, 0x40, 0xf8, 0x09, -+0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0x60, 0x06, 0x40, 0x94, 0xe0, 0x04, 0x80, -+0x65, 0x86, 0x31, 0x01, 0x06, 0x02, 0x0c, 0xe1, 0x33, 0x40, 0xc8, 0xe2, 0x33, -+0x40, 0x70, 0xe2, 0x14, 0x84, 0x18, 0x48, 0x1b, 0xa3, 0x55, 0x8a, 0x0a, 0x02, -+0x08, 0x70, 0x16, 0x43, 0x58, 0xe0, 0x26, 0x08, 0x00, 0x40, 0x16, 0x0a, 0x00, -+0xc0, 0x41, 0x44, 0x08, 0x40, 0x06, 0x46, 0x08, 0xe0, 0x51, 0x44, 0x04, 0xc0, -+0x45, 0x85, 0x66, 0x02, 0x04, 0xe0, 0x13, 0x40, 0x70, 0x62, 0x06, 0x02, 0x0c, -+0xe1, 0x14, 0x84, 0x18, 0x48, 0x1b, 0xa3, 0xb5, 0x86, 0x0a, 0x02, 0x08, 0x70, -+0xa6, 0x02, 0x68, 0xe0, 0x26, 0x0a, 0x00, 0x40, 0x16, 0x18, 0x00, 0xc0, 0x31, -+0x01, 0xc6, 0x09, 0x0c, 0xe0, 0x51, 0x44, 0x08, 0xc0, 0xc1, 0x44, 0x04, 0xc0, -+0x95, 0x83, 0x0a, 0x02, 0x04, 0xf0, 0x16, 0x02, 0x00, 0xc0, 0x11, 0x44, 0x08, -+0xc0, 0x11, 0x44, 0x04, 0x40, 0x11, 0x81, 0x33, 0x40, 0x18, 0xe3, 0x15, 0x83, -+0x0a, 0x02, 0x04, 0x70, 0x11, 0x81, 0x16, 0x0a, 0x00, 0x40, 0x31, 0x9d, 0x51, -+0x44, 0x08, 0x40, 0x06, 0x09, 0x04, 0xe0, 0x51, 0x44, 0x04, 0xc0, 0x43, 0x40, -+0x18, 0xe3, 0x33, 0x40, 0xc8, 0xe2, 0x13, 0x40, 0xc0, 0x62, 0xa6, 0x05, 0x78, -+0xe0, 0x23, 0x40, 0xd0, 0xe3, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x7c, 0xfa, -+0x86, 0x42, 0x84, 0x60, 0x06, 0x00, 0x0c, 0xe1, 0x14, 0x04, 0xf6, 0x50, 0x78, -+0xe3, 0x04, 0x00, 0x26, 0x0f, 0x28, 0xe2, 0x16, 0x15, 0x2c, 0x64, 0xb1, 0xbb, -+0x6a, 0x84, 0x0b, 0xa3, 0x36, 0x10, 0x10, 0x41, 0x2e, 0x54, 0x08, 0xd8, 0x16, -+0x4f, 0x44, 0x43, 0x06, 0x16, 0x00, 0xc0, 0x0b, 0x10, 0x1b, 0x8c, 0xb8, 0x4f, -+0x00, 0x6f, 0xa4, 0x12, 0x80, 0xfb, 0x06, 0x42, 0x1a, 0x60, 0x00, 0x40, 0xfc, -+0x73, 0x03, 0xc0, 0x83, 0x22, 0x0e, 0x02, 0xc1, 0x7f, 0x1f, 0xc0, 0x87, 0xd4, -+0x8f, 0x02, 0x1b, 0x8c, 0x8f, 0x20, 0x0b, 0x8e, 0x98, 0x4e, 0x00, 0xef, 0x06, -+0x42, 0x1a, 0x60, 0x00, 0x40, 0xfc, 0xf0, 0x73, 0xa2, 0x77, 0xcc, 0x70, 0x42, -+0x01, 0x73, 0xff, 0xc7, 0x12, 0x4e, 0x80, 0x79, 0x0b, 0x92, 0xb8, 0x4d, 0x00, -+0x6f, 0x1b, 0x8c, 0x06, 0x42, 0x94, 0x60, 0x06, 0x46, 0x1a, 0xe0, 0x24, 0x04, -+0x00, 0x40, 0xfd, 0x73, 0x03, 0xc0, 0xa3, 0xa6, 0xa7, 0xd4, 0xb3, 0x44, 0x60, -+0xe3, 0x85, 0x44, 0x9c, 0xe0, 0x24, 0x84, 0x75, 0x44, 0xa0, 0x60, 0x0e, 0x04, -+0xc0, 0x7f, 0x1f, 0xc0, 0x14, 0x04, 0xaf, 0x84, 0xaf, 0xa0, 0xa5, 0x42, 0xa4, -+0xe0, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x0c, 0x04, 0x0c, 0xfa, 0x46, 0x0d, -+0xcc, 0xe0, 0x09, 0x0c, 0xbc, 0xee, 0x0a, 0x40, 0x80, 0xe0, 0x45, 0x82, 0xa6, -+0x40, 0x08, 0xe0, 0x06, 0x98, 0x08, 0x7f, 0x74, 0xef, 0x0b, 0xa1, 0xb5, 0xfe, -+0x01, 0x87, 0x06, 0x98, 0x06, 0x4c, 0x94, 0x60, 0x06, 0x42, 0x0c, 0xe0, 0x05, -+0x0c, 0x14, 0xe0, 0x11, 0x40, 0x30, 0x62, 0x26, 0x42, 0x00, 0xe0, 0x05, 0x0c, -+0x14, 0xe0, 0x11, 0x40, 0xa0, 0x62, 0x56, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x14, -+0xe0, 0x11, 0x40, 0x40, 0x62, 0x76, 0x43, 0x04, 0xe0, 0x05, 0x0c, 0x14, 0xe0, -+0x11, 0x40, 0x50, 0xe2, 0x04, 0x98, 0x19, 0x00, 0x50, 0xeb, 0x4a, 0x42, 0x88, -+0xe0, 0xc5, 0x80, 0x28, 0x67, 0x54, 0x6f, 0x66, 0x00, 0xa0, 0xe0, 0x04, 0x98, -+0x19, 0x00, 0x30, 0xe0, 0x19, 0xc4, 0x11, 0x40, 0x30, 0x60, 0x11, 0x83, 0x04, -+0x9a, 0x11, 0x40, 0x10, 0xe0, 0x04, 0x98, 0x11, 0x40, 0x20, 0x60, 0x11, 0x81, -+0x04, 0x98, 0x11, 0x40, 0xb0, 0xe7, 0x19, 0x00, 0x50, 0xeb, 0x4a, 0x02, 0x0c, -+0xfc, 0x85, 0xfe, 0xc6, 0x4c, 0xb4, 0xe0, 0x60, 0x10, 0xb1, 0x64, 0x01, 0xc0, -+0x0a, 0xe0, 0x0b, 0xa1, 0x95, 0x8c, 0x04, 0xe0, 0x0b, 0xa1, 0x25, 0x8c, 0xd8, -+0x43, 0x5c, 0xef, 0x0a, 0xe0, 0x0b, 0xa1, 0x95, 0x8a, 0x04, 0xe0, 0x0b, 0xa1, -+0x25, 0x8a, 0xc6, 0x4e, 0x84, 0xe0, 0x04, 0x9c, 0x09, 0x00, 0x20, 0xe1, 0x4a, -+0x40, 0x80, 0xe0, 0x25, 0x86, 0x08, 0x22, 0x46, 0x43, 0x00, 0xe0, 0x06, 0x40, -+0x06, 0xe0, 0x63, 0x80, 0x09, 0x0c, 0x40, 0xe2, 0x09, 0x86, 0x0b, 0xa5, 0xd5, -+0x82, 0x68, 0x4e, 0x48, 0x6f, 0x01, 0x85, 0x78, 0x44, 0x48, 0x6f, 0x06, 0x00, -+0x80, 0xe1, 0xf8, 0x75, 0x4c, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0x78, 0x48, 0x48, -+0xef, 0x09, 0x0e, 0x48, 0xe0, 0x0b, 0xa1, 0xb5, 0x80, 0x58, 0x7b, 0x3c, 0xef, -+0x78, 0x74, 0x40, 0xef, 0xa6, 0x40, 0x08, 0xe0, 0x0c, 0x0c, 0x0c, 0xf2, 0x18, -+0x12, 0x50, 0xff, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x7b, 0x00, 0x06, 0x01, -+0x08, 0xe1, 0x08, 0x00, 0x6b, 0x82, 0x0b, 0xa1, 0x15, 0x82, 0xa6, 0x41, 0x84, -+0xe0, 0x18, 0x00, 0x01, 0x89, 0x18, 0x42, 0x00, 0xef, 0x63, 0x80, 0x04, 0x1c, -+0x64, 0x02, 0x84, 0xe0, 0x78, 0x40, 0x00, 0x68, 0x00, 0x00, 0x40, 0xe6, 0x4c, -+0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x1e, 0x80, 0x93, 0xdd, 0x0c, 0x04, 0x3c, 0xfa, -+0xf0, 0x1e, 0x40, 0x6c, 0x86, 0x0f, 0xe0, 0xe0, 0x01, 0x05, 0x91, 0x81, 0x06, -+0x02, 0x00, 0x62, 0x81, 0xb1, 0x01, 0x4e, 0xd8, 0x69, 0x0e, 0x00, 0x00, 0x60, -+0x01, 0xc0, 0x0e, 0x7c, 0x6b, 0x9e, 0x93, 0x4e, 0x14, 0x65, 0x86, 0x00, 0x30, -+0xe1, 0x93, 0x4e, 0x18, 0x65, 0x2b, 0x8c, 0x91, 0x4e, 0x50, 0xe1, 0x81, 0x4e, -+0xc8, 0xe9, 0x1e, 0xbe, 0x1e, 0x7e, 0x11, 0x8f, 0x9e, 0xbc, 0xd8, 0x55, 0x30, -+0xef, 0x06, 0x00, 0x00, 0x64, 0x46, 0x02, 0x54, 0xe1, 0x0e, 0x3e, 0x06, 0x00, -+0x20, 0xe0, 0x0e, 0x7e, 0x86, 0x00, 0x30, 0xe1, 0x1e, 0x7c, 0x11, 0x91, 0x9e, -+0x3c, 0x2b, 0x8c, 0xd8, 0x54, 0x30, 0xef, 0x06, 0x00, 0x00, 0x66, 0xa1, 0x83, -+0x0e, 0x3e, 0xf6, 0x41, 0xfc, 0xe9, 0x0e, 0x7e, 0x06, 0x00, 0x01, 0x60, 0x20, -+0xc0, 0x0e, 0x7c, 0x86, 0x00, 0x30, 0xe1, 0xae, 0x3c, 0x11, 0x93, 0xc8, 0x53, -+0x30, 0x6f, 0x2b, 0x8c, 0x06, 0x40, 0x88, 0x60, 0xf6, 0x45, 0xfc, 0x63, 0xff, -+0xc3, 0x14, 0x00, 0xf1, 0xa0, 0x95, 0x4e, 0xa8, 0xe2, 0xa1, 0x4e, 0x44, 0xea, -+0x81, 0x4e, 0xf0, 0x69, 0x10, 0x42, 0x00, 0x7c, 0x00, 0xcc, 0x1f, 0x04, 0x21, -+0x8b, 0x1e, 0x00, 0x86, 0x40, 0xfc, 0xe7, 0x05, 0x4e, 0xa4, 0x62, 0xc6, 0x01, -+0x5c, 0xe0, 0x05, 0x4e, 0xac, 0x62, 0x9e, 0x00, 0x00, 0x60, 0x02, 0xc0, 0x05, -+0x4e, 0x94, 0x62, 0x86, 0x40, 0x3c, 0x60, 0x10, 0xe7, 0x0e, 0x9c, 0x09, 0x0e, -+0x0c, 0xe1, 0x15, 0x4e, 0x3c, 0x79, 0x06, 0x02, 0x80, 0xe0, 0x13, 0x4e, 0xf4, -+0x64, 0x86, 0x02, 0x00, 0x60, 0x02, 0xc0, 0x21, 0x4e, 0x5c, 0x69, 0x00, 0x40, -+0xc0, 0xf3, 0x1e, 0x9e, 0x01, 0x4e, 0x0c, 0xe1, 0x0c, 0x0c, 0x3c, 0xf2, 0x93, -+0xdd, 0xc6, 0x01, 0xcc, 0x60, 0x06, 0x42, 0x88, 0xe0, 0x29, 0x00, 0x98, 0xee, -+0x34, 0x84, 0x4a, 0x44, 0x80, 0x60, 0x86, 0x04, 0x30, 0xe1, 0x24, 0x08, 0x30, -+0x46, 0xfd, 0x73, 0xff, 0xc3, 0x3e, 0x04, 0xa6, 0x08, 0xa0, 0x80, 0x34, 0x06, -+0xc8, 0x9c, 0x45, 0x44, 0xa0, 0x80, 0x35, 0x42, 0x00, 0x00, 0x06, 0x06, 0x00, -+0xc0, 0x35, 0x44, 0xa0, 0xc0, 0x35, 0x02, 0x00, 0xc0, 0x3e, 0x80, 0x93, 0xdd, -+0x4c, 0x00, 0x00, 0xfa, 0x88, 0x40, 0x00, 0xe8, 0x86, 0x02, 0x0c, 0xe1, 0x0e, -+0x84, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, -+0x00, 0xf8, 0xc6, 0x40, 0xb4, 0xe0, 0x00, 0x02, 0xb1, 0x64, 0x01, 0xc0, 0x2a, -+0xc4, 0x2b, 0xa1, 0x35, 0x92, 0x24, 0xc4, 0x2b, 0xa1, 0xc5, 0x90, 0x38, 0x06, -+0x46, 0x45, 0x00, 0xe0, 0x36, 0x46, 0x0a, 0xe0, 0x33, 0x80, 0x49, 0x06, 0xf0, -+0xe2, 0x4d, 0xe6, 0xc6, 0x40, 0x48, 0x41, 0x16, 0x02, 0x00, 0xc0, 0x11, 0x40, -+0x00, 0xc0, 0xd5, 0x8c, 0xc9, 0x06, 0x44, 0x62, 0x06, 0x4b, 0x00, 0xe0, 0x46, -+0x48, 0x16, 0x60, 0x86, 0x4a, 0xc8, 0xe0, 0x53, 0x08, 0xc0, 0x58, 0x80, 0xf3, -+0x49, 0x0a, 0xa4, 0xe7, 0x6b, 0x0a, 0xd8, 0xe3, 0x49, 0xbe, 0xcf, 0xa8, 0xc1, -+0x46, 0x44, 0xe2, 0x48, 0x86, 0xc9, 0x0a, 0xa0, 0xe7, 0x46, 0x48, 0x0a, 0xe0, -+0xc1, 0x46, 0x40, 0xe2, 0xcb, 0x0a, 0xe0, 0x63, 0x43, 0x80, 0x63, 0x48, 0x28, -+0xe1, 0x38, 0x86, 0x36, 0x46, 0x0a, 0xe0, 0x33, 0x80, 0xc3, 0x46, 0x30, 0xe1, -+0x18, 0x86, 0xcb, 0x0a, 0xd4, 0xe3, 0x2b, 0x0a, 0xdc, 0x63, 0x16, 0x42, 0x0a, -+0xe0, 0x5b, 0x0a, 0xe4, 0xe3, 0xc3, 0x48, 0x24, 0x61, 0x03, 0x82, 0x23, 0x46, -+0x2c, 0xe1, 0x53, 0x40, 0x34, 0xe1, 0x4c, 0x0c, 0x00, 0xf0, 0x93, 0xdd, 0xc3, -+0xc1, 0x0c, 0x00, 0x80, 0xfa, 0x86, 0x43, 0xcc, 0x60, 0x0b, 0xa3, 0x29, 0x02, -+0xc4, 0xee, 0xb5, 0x84, 0x4a, 0x04, 0xfc, 0xfb, 0x45, 0x84, 0xc6, 0x40, 0x84, -+0xe0, 0x14, 0x82, 0x18, 0x84, 0x19, 0x86, 0x1b, 0xa5, 0x85, 0x8c, 0x04, 0x80, -+0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0xc5, 0x8a, 0x0c, 0x08, 0x80, -+0xf2, 0x08, 0x34, 0x44, 0xff, 0x0b, 0xa5, 0x15, 0x8a, 0x0a, 0x04, 0x04, 0xf0, -+0xb5, 0x88, 0xc6, 0x40, 0x84, 0xe0, 0x24, 0x82, 0x28, 0x88, 0x29, 0x86, 0x2b, -+0xa5, 0xc5, 0x86, 0x04, 0x80, 0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, -+0x05, 0x86, 0x09, 0x02, 0x24, 0xee, 0x0b, 0xa3, 0xd5, 0x80, 0x08, 0x84, 0x0a, -+0x40, 0x80, 0xe0, 0x75, 0xf8, 0xf5, 0x81, 0x38, 0x72, 0x44, 0xef, 0xf8, 0x51, -+0xfc, 0xef, 0x4e, 0x40, 0x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0xa5, -+0x80, 0x0c, 0x08, 0x80, 0xf2, 0xb8, 0x11, 0xfc, 0xff, 0x0c, 0x08, 0x80, 0xf2, -+0x93, 0xdd, 0xcc, 0x04, 0x0c, 0xfa, 0x06, 0x4f, 0x84, 0x60, 0x86, 0x50, 0x4c, -+0xe1, 0x04, 0x1c, 0x80, 0x0c, 0x21, 0x6f, 0x01, 0xc0, 0xf0, 0x04, 0x50, 0x64, -+0x11, 0x81, 0x09, 0x00, 0x6c, 0xe0, 0x06, 0x29, 0x0b, 0x8c, 0x58, 0x4c, 0x58, -+0xef, 0x04, 0x9c, 0x19, 0x00, 0x6c, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3, -+0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, 0x2f, -+0xa2, 0x21, 0x40, 0x6c, 0xe0, 0x86, 0x43, 0xcc, 0xe0, 0x29, 0x02, 0x24, 0xee, -+0x2b, 0xa3, 0xd5, 0x80, 0x18, 0x84, 0x4a, 0x42, 0x80, 0x60, 0x11, 0x8b, 0x65, -+0x80, 0x19, 0x00, 0x70, 0xe0, 0x16, 0x29, 0xf0, 0x04, 0x50, 0xe4, 0x11, 0x03, -+0x0b, 0x8c, 0x28, 0x4a, 0x58, 0xef, 0x04, 0x9c, 0x19, 0x00, 0x70, 0xe0, 0x10, -+0x44, 0x3c, 0xf0, 0x2b, 0xa3, 0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, -+0x27, 0xc8, 0x29, 0xa0, 0x2f, 0xa2, 0x21, 0x40, 0x70, 0xe0, 0x09, 0x00, 0x74, -+0x60, 0xf0, 0x04, 0x50, 0xe4, 0x11, 0x85, 0x06, 0x29, 0x0b, 0x8c, 0xa8, 0x48, -+0x58, 0xef, 0x04, 0x9c, 0x19, 0x00, 0x74, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, -+0xa3, 0x35, 0x82, 0x28, 0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, -+0x2f, 0xa2, 0x21, 0x40, 0x74, 0xe0, 0x09, 0x00, 0x78, 0x60, 0xf0, 0x04, 0x50, -+0xe4, 0x11, 0x87, 0x06, 0x29, 0x0b, 0x8c, 0x28, 0x47, 0x58, 0xef, 0x04, 0x9c, -+0x19, 0x00, 0x78, 0xe0, 0x10, 0x44, 0x3c, 0xf0, 0x2b, 0xa3, 0x35, 0x82, 0x28, -+0x2b, 0x10, 0x42, 0xbc, 0xf3, 0x27, 0xc8, 0x29, 0xa0, 0x2f, 0xa2, 0x21, 0x40, -+0x78, 0xe0, 0x19, 0x0e, 0xd0, 0xe0, 0x1b, 0xa1, 0x85, 0x86, 0x05, 0x00, 0x24, -+0xe0, 0x1a, 0xa2, 0x04, 0x04, 0xc0, 0xe1, 0x2b, 0x83, 0xd5, 0x80, 0x19, 0x10, -+0x10, 0x60, 0x09, 0x9e, 0x0b, 0x83, 0x85, 0x84, 0x08, 0xa0, 0x0b, 0xa1, 0x38, -+0x61, 0x74, 0xcf, 0x58, 0x49, 0x34, 0xef, 0x14, 0x9c, 0x25, 0x02, 0x24, 0xe0, -+0x24, 0x02, 0xc0, 0x61, 0x29, 0x9e, 0x18, 0x58, 0x74, 0xef, 0x55, 0x81, 0x08, -+0xa0, 0x0b, 0xa1, 0x48, 0x60, 0x74, 0xcf, 0x28, 0x72, 0x4c, 0x6f, 0x46, 0x01, -+0x08, 0xe0, 0xcc, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x65, 0x5e, 0x04, -+0xfa, 0xf0, 0x0c, 0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, 0x61, 0x88, 0x6e, 0xbc, -+0xfc, 0x07, 0x80, 0xfe, 0xf0, 0x1e, 0x20, 0x6c, 0xe6, 0x40, 0x00, 0xe0, 0xc8, -+0x70, 0x4c, 0xef, 0x0b, 0xa1, 0xb5, 0x88, 0xc6, 0x0d, 0xdc, 0xe0, 0x09, 0x0c, -+0x94, 0xea, 0x0b, 0xa3, 0xf5, 0x80, 0x09, 0x0c, 0x91, 0x79, 0x01, 0xc0, 0x0a, -+0x40, 0x80, 0xe0, 0xe5, 0x82, 0xc8, 0x71, 0x44, 0xef, 0x04, 0x18, 0x86, 0x02, -+0x84, 0xe0, 0x24, 0x04, 0x31, 0x83, 0x01, 0x82, 0x0e, 0x18, 0xe6, 0x00, 0x48, -+0xe1, 0x36, 0x00, 0x21, 0x82, 0x2e, 0x84, 0x46, 0x00, 0x2c, 0x61, 0x21, 0x83, -+0x14, 0x00, 0x46, 0x40, 0x34, 0xe1, 0x25, 0x42, 0x44, 0xe0, 0x28, 0x51, 0x28, -+0xef, 0x88, 0x40, 0x00, 0xe8, 0xf1, 0x90, 0xfc, 0x0f, 0x80, 0xf6, 0xf4, 0xbc, -+0x64, 0xfd, 0x53, 0xc1, 0x4c, 0x00, 0x00, 0xfa, 0x01, 0x03, 0x11, 0x81, 0x48, -+0x79, 0x08, 0xef, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x00, -+0x00, 0xfa, 0x0d, 0x62, 0x8e, 0x45, 0xf0, 0xff, 0x75, 0x82, 0x4e, 0x05, 0x01, -+0x60, 0x10, 0x40, 0x07, 0xc8, 0x24, 0x88, 0x23, 0x80, 0x1e, 0x8a, 0x78, 0x40, -+0x00, 0xe8, 0x21, 0x81, 0x0b, 0x84, 0x4c, 0x08, 0x00, 0xf2, 0x93, 0xdd, 0x83, -+0xc1, 0x93, 0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x41, 0xb9, 0x06, 0x48, 0x12, 0xe0, -+0x33, 0x88, 0x45, 0x06, 0x14, 0xe0, 0x4b, 0xa3, 0xc5, 0x80, 0x35, 0x06, 0x18, -+0xe0, 0x3b, 0x23, 0x31, 0x81, 0x55, 0x80, 0x31, 0x83, 0x0d, 0xe6, 0x04, 0x00, -+0x88, 0x00, 0x4e, 0x08, 0x00, 0x00, 0x10, 0x80, 0x05, 0x00, 0x10, 0x9c, 0x08, -+0x40, 0x00, 0x98, 0x25, 0x0b, 0x8e, 0x40, 0xf0, 0xff, 0x3b, 0xa1, 0x45, 0x8a, -+0x2b, 0x23, 0x06, 0x4c, 0x00, 0xe0, 0x45, 0x90, 0x2b, 0x25, 0x6e, 0x40, 0xf0, -+0xff, 0x25, 0x87, 0x3b, 0xa1, 0x25, 0x8a, 0x2b, 0x23, 0x06, 0x0c, 0x08, 0xe0, -+0x05, 0x8e, 0x2b, 0x25, 0x5e, 0x40, 0xf0, 0xff, 0x85, 0x0c, 0x06, 0x0c, 0x04, -+0xe0, 0x95, 0x87, 0x3b, 0xa1, 0xc5, 0x88, 0x2b, 0x23, 0x61, 0x91, 0x85, 0x8a, -+0x2b, 0x25, 0x7e, 0x40, 0xf0, 0xff, 0x25, 0x83, 0x2b, 0xa3, 0xc5, 0x08, 0x06, -+0x0c, 0x08, 0x80, 0x2b, 0x25, 0x4e, 0x40, 0xf0, 0xff, 0x15, 0x8a, 0xf5, 0x03, -+0x06, 0x0c, 0x04, 0xe0, 0x2b, 0x23, 0x61, 0x91, 0x45, 0x86, 0x2b, 0x25, 0x6e, -+0x40, 0xf0, 0xff, 0xc5, 0x04, 0x61, 0x89, 0xc5, 0x83, 0x2b, 0x23, 0x06, 0x4c, -+0x00, 0xe0, 0x05, 0x84, 0x2b, 0x25, 0x5e, 0x40, 0xf0, 0xff, 0x85, 0x02, 0x61, -+0xa1, 0x25, 0x83, 0x2b, 0x23, 0x61, 0x85, 0xe5, 0x80, 0x2b, 0x25, 0x7e, 0x40, -+0xf0, 0xff, 0x65, 0x00, 0x61, 0x83, 0x95, 0x81, 0x0b, 0x02, 0x1b, 0x8c, 0x48, -+0x78, 0xfc, 0xef, 0x0b, 0xa1, 0x00, 0x4c, 0x00, 0xdc, 0x0b, 0x8c, 0x0c, 0x0c, -+0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x04, 0xfa, 0x6b, 0x00, 0xc6, -+0x40, 0xdc, 0xe0, 0x04, 0x00, 0xf0, 0x1e, 0x30, 0xec, 0x48, 0x55, 0xfc, 0x6e, -+0x0e, 0x02, 0x24, 0x74, 0x03, 0xc0, 0xb8, 0x68, 0xfc, 0xee, 0x58, 0x71, 0x08, -+0xef, 0x78, 0x68, 0xfc, 0x6e, 0x0b, 0x8c, 0x71, 0x01, 0x5b, 0x80, 0x7e, 0x3c, -+0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, 0x11, 0x03, 0x21, 0x81, 0x31, 0x05, 0x41, -+0x81, 0xa8, 0x77, 0x08, 0xef, 0x0e, 0x3e, 0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, -+0x48, 0x4b, 0x0c, 0xef, 0x0e, 0x7c, 0x11, 0x81, 0x04, 0x3e, 0x21, 0x83, 0x68, -+0x76, 0xfc, 0x6f, 0x0e, 0x06, 0x04, 0x60, 0x10, 0xc0, 0xce, 0x0d, 0x01, 0x60, -+0x10, 0xc0, 0x76, 0x98, 0x04, 0xfc, 0xc8, 0x59, 0x0c, 0xef, 0x13, 0xc3, 0x08, -+0x98, 0x0b, 0xa1, 0xa5, 0xfe, 0x04, 0xfc, 0x18, 0x5c, 0x0c, 0xef, 0x14, 0x3e, -+0x0e, 0x00, 0x05, 0x60, 0x10, 0xc0, 0x38, 0x46, 0x0c, 0xef, 0x01, 0x01, 0xf1, -+0x98, 0x0c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x65, 0x5e, 0x04, 0xfa, 0xf0, 0x0c, -+0x10, 0xec, 0x60, 0x5e, 0x1c, 0x74, 0x61, 0x88, 0x6e, 0xbc, 0xfc, 0x03, 0x80, -+0xfe, 0x26, 0x00, 0x4c, 0x61, 0x11, 0x83, 0x16, 0x00, 0xce, 0x01, 0x01, 0x60, -+0x10, 0xc0, 0x16, 0x00, 0x46, 0x00, 0x2c, 0xe1, 0x04, 0x00, 0xf0, 0x1e, 0x30, -+0xec, 0x14, 0xc0, 0x14, 0x02, 0x20, 0xfc, 0x1e, 0xc0, 0x98, 0x40, 0x00, 0xe8, -+0xf1, 0x98, 0xfc, 0x0b, 0x80, 0xf6, 0xf4, 0xbc, 0x64, 0xfd, 0x53, 0xc1, 0xc3, -+0xc1, 0x06, 0x00, 0x01, 0x60, 0x00, 0xe0, 0x06, 0x00, 0x62, 0xf4, 0x93, 0xdd, -+0x4c, 0x04, 0x7c, 0xfa, 0xc6, 0x54, 0x84, 0x60, 0x06, 0x0f, 0xdc, 0xe0, 0x04, -+0x2a, 0xae, 0x4d, 0x01, 0x60, 0x10, 0xc0, 0x29, 0x14, 0x70, 0x60, 0x8e, 0x51, -+0x00, 0x60, 0x10, 0xc0, 0x3b, 0x0e, 0x9c, 0x65, 0x06, 0x52, 0x94, 0xe0, 0x1b, -+0x00, 0x20, 0x60, 0x0e, 0x57, 0x08, 0x60, 0x10, 0xc0, 0x0b, 0x00, 0x1c, 0xe0, -+0x13, 0x20, 0x01, 0x81, 0x13, 0x84, 0x13, 0x86, 0x11, 0x9e, 0x1c, 0x98, 0x0c, -+0xa0, 0x04, 0xa4, 0x0b, 0x00, 0xa0, 0xe5, 0x0c, 0xac, 0x0a, 0x98, 0x1a, 0xac, -+0x0d, 0xc3, 0xf5, 0x82, 0x04, 0xa4, 0x0b, 0x00, 0xa0, 0xe5, 0x0c, 0x2c, 0x01, -+0x8b, 0x08, 0x56, 0x2c, 0xef, 0x0a, 0xa0, 0x01, 0x82, 0x0c, 0xa0, 0x0a, 0xa0, -+0x8a, 0x00, 0x24, 0xe7, 0xf5, 0xfa, 0x05, 0x0e, 0xbc, 0x61, 0x06, 0x04, 0x00, -+0x60, 0x00, 0xf0, 0x13, 0x0e, 0xb8, 0x79, 0x06, 0x06, 0x00, 0x60, 0x00, 0xe0, -+0x2f, 0x80, 0x2b, 0x07, 0x0e, 0x45, 0x01, 0x60, 0x10, 0xc0, 0x1c, 0x88, 0x95, -+0x86, 0x07, 0xe1, 0x09, 0xbe, 0x0b, 0xa1, 0x05, 0x86, 0x21, 0xff, 0x1d, 0x84, -+0x85, 0x02, 0x00, 0x00, 0x08, 0x8c, 0x10, 0x04, 0x18, 0xec, 0x8a, 0x04, 0x14, -+0xed, 0xb5, 0x80, 0x8a, 0x02, 0x40, 0xe1, 0x75, 0x82, 0x01, 0x84, 0x14, 0x24, -+0x09, 0xbe, 0x29, 0x02, 0x00, 0xe3, 0x20, 0x44, 0x80, 0xf3, 0x2f, 0xa0, 0x21, -+0x42, 0x00, 0xe3, 0x8e, 0x41, 0x09, 0x60, 0x10, 0x40, 0xc6, 0x0d, 0x30, 0xe1, -+0x04, 0x80, 0x0b, 0xa3, 0x75, 0xa0, 0x19, 0x0c, 0xcc, 0xe5, 0x4a, 0x02, 0xfc, -+0xfb, 0xc5, 0x9e, 0xa8, 0x54, 0x00, 0x68, 0x01, 0x81, 0x04, 0x24, 0x11, 0x85, -+0x11, 0x40, 0x20, 0x60, 0x4e, 0x43, 0x00, 0x60, 0x10, 0xc0, 0x04, 0xa4, 0x29, -+0x00, 0x50, 0xeb, 0x2e, 0x84, 0x24, 0x84, 0x29, 0x86, 0x2e, 0x84, 0x24, 0x84, -+0x2b, 0xa1, 0x15, 0xfe, 0xa8, 0x52, 0x44, 0xef, 0x04, 0xaa, 0x08, 0x80, 0x0b, -+0xa5, 0xe5, 0x80, 0x04, 0xa8, 0x09, 0x00, 0x20, 0xe1, 0x0b, 0xa1, 0x48, 0x4a, -+0x44, 0x8f, 0x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, 0x14, 0xc0, 0x14, 0x02, 0x2c, -+0xfc, 0x1e, 0xc0, 0x14, 0xc0, 0x14, 0x02, 0x08, 0xfc, 0x1e, 0x40, 0x11, 0x83, -+0x04, 0xa4, 0x11, 0x40, 0xb0, 0x67, 0x11, 0x81, 0x04, 0xa6, 0x11, 0x40, 0x10, -+0xe0, 0xb8, 0x73, 0x74, 0xef, 0x84, 0x20, 0x70, 0x06, 0x00, 0xe7, 0x8e, 0x17, -+0x01, 0x60, 0x10, 0x40, 0xce, 0x54, 0x01, 0x60, 0x10, 0xc0, 0x04, 0xe0, 0x04, -+0x00, 0x04, 0xfc, 0x0e, 0xe0, 0x04, 0xe0, 0x04, 0x00, 0x0c, 0xfc, 0x0e, 0xe0, -+0x04, 0xe0, 0x04, 0x00, 0x10, 0xfc, 0x0e, 0xe0, 0x45, 0x10, 0x2c, 0xe0, 0x44, -+0x00, 0x00, 0xfc, 0x05, 0x50, 0x2c, 0x60, 0x4e, 0x41, 0x08, 0x60, 0x10, 0xc0, -+0x1b, 0x0e, 0xa0, 0xe1, 0x04, 0x80, 0x2b, 0x0e, 0x9c, 0xe1, 0x1b, 0xc2, 0x03, -+0x02, 0xce, 0x42, 0x01, 0x60, 0x10, 0xc0, 0x3e, 0x04, 0x03, 0x84, 0x00, 0x00, -+0xf4, 0xec, 0x0e, 0xac, 0x09, 0x0e, 0x00, 0xe3, 0x4e, 0x8f, 0x0b, 0xa5, 0x0b, -+0x0e, 0x10, 0xd8, 0x95, 0x96, 0x0b, 0x0e, 0x84, 0xe1, 0x15, 0x0e, 0x10, 0xe0, -+0x03, 0x4e, 0x10, 0xf8, 0x1d, 0xc1, 0x13, 0x4e, 0x10, 0x58, 0x10, 0x40, 0x00, -+0xdc, 0x1a, 0x5e, 0x04, 0x04, 0x80, 0xfb, 0x2d, 0xc3, 0x13, 0x4e, 0x10, 0x58, -+0x10, 0x40, 0x00, 0xdc, 0x85, 0x89, 0x0b, 0xa1, 0x98, 0x0c, 0x00, 0xc0, 0x68, -+0x7b, 0x68, 0x6f, 0x01, 0x85, 0x60, 0x00, 0x10, 0x64, 0x11, 0x81, 0xc8, 0x71, -+0x54, 0xef, 0x28, 0x45, 0x70, 0xef, 0x09, 0x0e, 0xe8, 0xea, 0x4a, 0x40, 0x90, -+0xe0, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x4b, 0x00, 0xc8, 0x09, 0x0e, 0x5c, 0xeb, -+0x0a, 0x40, 0x80, 0xe0, 0x25, 0xac, 0x19, 0x0c, 0xcc, 0xe5, 0x4a, 0x02, 0xfc, -+0xfb, 0x85, 0xaa, 0x0a, 0x40, 0x90, 0xe0, 0x45, 0x82, 0x46, 0x00, 0x74, 0xe1, -+0x04, 0x80, 0x14, 0xc0, 0x14, 0x02, 0x2c, 0xfc, 0x1e, 0xc0, 0x09, 0x0e, 0x5c, -+0xeb, 0x0a, 0x40, 0x84, 0xe0, 0x25, 0x82, 0xb8, 0x68, 0x30, 0x6f, 0x01, 0x81, -+0xc8, 0x58, 0x2c, 0x6f, 0x0b, 0x8c, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x94, -+0xe0, 0x45, 0x82, 0x46, 0x00, 0x74, 0xe1, 0x04, 0x80, 0x14, 0xc0, 0x14, 0x02, -+0x08, 0xfc, 0x1e, 0xc0, 0x09, 0x0e, 0x5c, 0xeb, 0x0a, 0x40, 0x98, 0xe0, 0x18, -+0x49, 0x00, 0xc8, 0x45, 0x91, 0x14, 0x2c, 0x04, 0x00, 0x80, 0xfb, 0x13, 0x20, -+0x06, 0x41, 0x2c, 0xe0, 0x16, 0x40, 0x02, 0x60, 0x46, 0x42, 0x04, 0xe0, 0xc8, -+0x7a, 0xf8, 0xee, 0x0e, 0x2c, 0x0e, 0x4c, 0x01, 0x60, 0x10, 0xc0, 0x04, 0xac, -+0x00, 0x00, 0xd1, 0x6f, 0x0f, 0xc0, 0x0e, 0xac, 0x05, 0x10, 0x40, 0xe0, 0x04, -+0x00, 0x38, 0xfc, 0x0e, 0x98, 0x05, 0x50, 0x40, 0xe0, 0x04, 0xac, 0xd8, 0x63, -+0xfc, 0xef, 0x46, 0x10, 0x74, 0xe1, 0x04, 0xa0, 0x15, 0x00, 0x40, 0xe0, 0x14, -+0x02, 0xb8, 0xfc, 0x1e, 0x98, 0x15, 0x40, 0x40, 0xe0, 0x98, 0x52, 0x30, 0xef, -+0x0b, 0xa1, 0xa5, 0xfe, 0x34, 0x28, 0xc6, 0x0d, 0x30, 0xe1, 0x08, 0x8c, 0x0b, -+0xa5, 0x0b, 0x0e, 0x04, 0xd8, 0x1b, 0x0e, 0x00, 0xc0, 0x2b, 0x0e, 0x04, 0xc0, -+0x3b, 0x0e, 0x08, 0xc0, 0x75, 0x84, 0x08, 0x8e, 0x19, 0x0e, 0x10, 0xeb, 0x12, -+0x40, 0x80, 0xfb, 0x01, 0x4e, 0x10, 0xf8, 0x0a, 0xcc, 0x03, 0x4e, 0x04, 0xf8, -+0x1a, 0xce, 0x1c, 0x9c, 0x2b, 0x06, 0x10, 0xe0, 0x2c, 0x9e, 0x3b, 0x06, 0x14, -+0xe0, 0x3c, 0xdc, 0xa4, 0x8f, 0x03, 0x4e, 0x80, 0xf9, 0x13, 0x4e, 0x7c, 0xf9, -+0x23, 0x4e, 0x78, 0xf9, 0x33, 0x4e, 0x74, 0xf9, 0xc8, 0x6d, 0x38, 0xef, 0xe8, -+0x66, 0x3c, 0xef, 0x04, 0x20, 0xa9, 0xc2, 0xa5, 0x40, 0x2c, 0xe0, 0x19, 0x0c, -+0x40, 0xe6, 0x1b, 0xa1, 0x55, 0x88, 0x14, 0xc0, 0x19, 0xd0, 0x1e, 0xc0, 0x14, -+0xc0, 0x19, 0xe0, 0x1e, 0xc0, 0x14, 0xc0, 0x19, 0xc4, 0x1e, 0x40, 0x01, 0x83, -+0xa8, 0x41, 0x00, 0xe8, 0x04, 0xa0, 0x14, 0xc0, 0x14, 0x02, 0xac, 0xfc, 0x1e, -+0xc0, 0x14, 0xc0, 0x19, 0xc8, 0x1e, 0xc0, 0x48, 0x51, 0x74, 0xef, 0x04, 0x26, -+0x11, 0x83, 0x11, 0x40, 0x10, 0xe0, 0x04, 0xa4, 0x11, 0x40, 0x20, 0x60, 0x11, -+0x81, 0x04, 0xa4, 0x11, 0x40, 0xb0, 0xe7, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, -+0x1b, 0x00, 0x06, 0x01, 0x38, 0xe1, 0x04, 0x80, 0xc8, 0x20, 0x04, 0x60, 0x01, -+0xb8, 0xc3, 0xc1, 0x83, 0xc1, 0x13, 0xc3, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, -+0x00, 0xfa, 0xe6, 0x41, 0x84, 0x60, 0x8e, 0x42, 0x00, 0x60, 0x10, 0xc0, 0x08, -+0x80, 0x14, 0x84, 0x0b, 0x21, 0xa6, 0x41, 0x04, 0xe1, 0x1c, 0x80, 0x05, 0x82, -+0x28, 0x47, 0x64, 0xef, 0x88, 0x7b, 0x28, 0x6f, 0x46, 0x40, 0x04, 0xe0, 0x35, -+0x81, 0x38, 0x56, 0x40, 0xef, 0xd8, 0x67, 0x64, 0xef, 0x38, 0x63, 0x64, 0xef, -+0xd8, 0x44, 0x44, 0xef, 0x06, 0x40, 0x94, 0xe0, 0x04, 0x80, 0x09, 0x00, 0x50, -+0xeb, 0x0a, 0x40, 0x88, 0xe0, 0x76, 0x00, 0xa0, 0xc0, 0x68, 0x4e, 0x50, 0xcf, -+0xc6, 0x0d, 0x30, 0xe1, 0x09, 0x0c, 0x30, 0xe7, 0x0b, 0xa1, 0x78, 0x6c, 0x70, -+0xcf, 0x98, 0x7f, 0x6c, 0xef, 0x38, 0x4b, 0x2c, 0x6f, 0x0b, 0x8c, 0xc8, 0x5a, -+0x30, 0x6f, 0x01, 0x81, 0x58, 0x49, 0x30, 0xef, 0xb8, 0x5f, 0x70, 0xef, 0x01, -+0x83, 0x01, 0x4c, 0xc0, 0xe5, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, -+0x0c, 0x04, 0x84, 0xfa, 0x06, 0x4e, 0x88, 0x60, 0x06, 0x0c, 0x0c, 0xe1, 0x05, -+0x0e, 0x38, 0x78, 0x06, 0x04, 0x00, 0x70, 0x40, 0xc0, 0x19, 0x0c, 0x94, 0x78, -+0x06, 0x06, 0x10, 0x60, 0x40, 0xc0, 0x08, 0xc0, 0x4a, 0x02, 0x00, 0xe0, 0x09, -+0x86, 0x07, 0xc6, 0x2f, 0x61, 0x3f, 0xe1, 0x21, 0x4e, 0x10, 0xf8, 0x0c, 0x00, -+0x00, 0xe2, 0x31, 0x4e, 0x0c, 0xf8, 0x18, 0x62, 0x30, 0xef, 0x05, 0x0e, 0x38, -+0xf8, 0x14, 0x98, 0x09, 0x00, 0x24, 0xe0, 0x4a, 0x40, 0x88, 0xe0, 0x65, 0x82, -+0x0b, 0x0c, 0x28, 0x78, 0x1b, 0xa1, 0x0c, 0xde, 0x05, 0x84, 0x0a, 0x01, 0x20, -+0xec, 0xf5, 0x84, 0x55, 0x03, 0x01, 0x93, 0x0b, 0x0c, 0x24, 0x78, 0x1b, 0xa1, -+0x0c, 0xde, 0x65, 0x82, 0x0a, 0x01, 0x24, 0xec, 0xb5, 0x82, 0xb5, 0x01, 0x01, -+0x95, 0x0a, 0x01, 0x48, 0xec, 0x15, 0x82, 0x65, 0x01, 0x01, 0xa7, 0x0a, 0x01, -+0x50, 0xec, 0x75, 0x80, 0x01, 0xab, 0x0c, 0xde, 0x15, 0x0c, 0x20, 0x79, 0x06, -+0x04, 0x00, 0x60, 0x00, 0xf0, 0x49, 0x0c, 0x64, 0x78, 0x06, 0x06, 0x00, 0x60, -+0x00, 0xe0, 0x2f, 0x82, 0x3b, 0x0c, 0x8c, 0x78, 0x2b, 0x87, 0x30, 0x42, 0x00, -+0x5c, 0x4a, 0x08, 0x14, 0xfc, 0x14, 0x04, 0x80, 0x7a, 0xce, 0x43, 0x00, 0x60, -+0x10, 0xc0, 0x2c, 0x04, 0x8e, 0x48, 0x01, 0x60, 0x10, 0xc0, 0x3e, 0x90, 0x85, -+0x88, 0x45, 0x0e, 0x30, 0xf8, 0x3b, 0x08, 0x18, 0xe0, 0x5b, 0x08, 0x20, 0xe0, -+0x4b, 0x08, 0x1c, 0xe0, 0x32, 0x4a, 0x94, 0xf1, 0x53, 0x88, 0x8a, 0x0a, 0x89, -+0x63, 0x05, 0xc0, 0xb5, 0x84, 0x54, 0x1a, 0x8e, 0x59, 0x09, 0x60, 0x10, 0xc0, -+0x71, 0x83, 0x7e, 0x30, 0x2e, 0x59, 0x09, 0x60, 0x10, 0xc0, 0x5c, 0x30, 0x54, -+0x08, 0x80, 0xfb, 0x4d, 0x44, 0x4e, 0x45, 0x09, 0x60, 0x10, 0xc0, 0x3e, 0x88, -+0x43, 0x42, 0x00, 0xc0, 0x65, 0x81, 0x8e, 0x43, 0x09, 0x60, 0x10, 0x40, 0x21, -+0x81, 0x2e, 0x84, 0x03, 0x4c, 0xd5, 0x79, 0x02, 0x40, 0xd6, 0x41, 0x00, 0xe0, -+0x0c, 0x0c, 0x84, 0xf2, 0x18, 0x34, 0x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0xfc, -+0xfa, 0x6b, 0x00, 0x06, 0x41, 0x08, 0xe0, 0x98, 0x73, 0x48, 0xef, 0x0b, 0xa1, -+0x78, 0x14, 0x00, 0xc0, 0x86, 0x52, 0x84, 0xe0, 0x74, 0xe4, 0x08, 0x9c, 0x09, -+0x86, 0x0b, 0xa3, 0x36, 0x40, 0x98, 0x40, 0x06, 0x02, 0x00, 0xc0, 0x11, 0x40, -+0x00, 0xc0, 0xf5, 0x80, 0x21, 0x01, 0x36, 0x40, 0x98, 0xe0, 0x2e, 0x18, 0x11, -+0x83, 0x16, 0x80, 0x84, 0x26, 0x16, 0x44, 0x98, 0xe0, 0x18, 0x9c, 0x09, 0x10, -+0xb4, 0xe0, 0x0a, 0x02, 0x0c, 0xfc, 0x0c, 0x02, 0x00, 0xe2, 0x01, 0x4c, 0x10, -+0xe1, 0x0b, 0x10, 0x80, 0xe0, 0x16, 0x88, 0xe8, 0x75, 0xf8, 0xee, 0x05, 0x4c, -+0x48, 0xe0, 0x08, 0x9c, 0x00, 0x42, 0x08, 0xfc, 0x19, 0x86, 0x1b, 0xa5, 0xd5, -+0x80, 0x4a, 0x00, 0x0c, 0xf8, 0x0c, 0x00, 0x00, 0xe2, 0x0e, 0x98, 0x09, 0x10, -+0xb0, 0xe0, 0x98, 0x51, 0x00, 0x68, 0x09, 0x82, 0x01, 0x4c, 0x18, 0x60, 0x11, -+0x9f, 0x0b, 0x10, 0x88, 0xe0, 0x78, 0x51, 0x00, 0xe8, 0x14, 0xa6, 0x05, 0x4c, -+0x4c, 0xe0, 0x0b, 0x02, 0x84, 0x60, 0x11, 0x91, 0xf8, 0x50, 0x00, 0xe8, 0xb4, -+0xa6, 0x05, 0x4c, 0x50, 0xe0, 0x09, 0x16, 0xd0, 0xe0, 0x0a, 0x40, 0x84, 0x60, -+0x06, 0x00, 0x00, 0x60, 0x48, 0xd0, 0x56, 0x01, 0x55, 0x15, 0x41, 0xd0, 0x05, -+0x4c, 0x34, 0xe0, 0x09, 0x16, 0xd0, 0xe0, 0x68, 0x4f, 0x00, 0x68, 0x09, 0x82, -+0x14, 0x64, 0x06, 0x54, 0xdc, 0xe0, 0x01, 0x4c, 0x10, 0x60, 0xce, 0x41, 0x00, -+0x60, 0x10, 0xc0, 0x0a, 0x80, 0x2b, 0x02, 0x18, 0xe0, 0x23, 0xa0, 0x23, 0x4c, -+0x60, 0xe0, 0x09, 0x14, 0x70, 0xea, 0x22, 0x40, 0x80, 0xf1, 0x03, 0x4c, 0x60, -+0xe0, 0x25, 0x14, 0xe0, 0xe2, 0x2b, 0xa3, 0x35, 0x88, 0x24, 0xa4, 0x3b, 0x02, -+0x18, 0xe0, 0x4b, 0x02, 0x20, 0xe0, 0x1b, 0x02, 0x1c, 0xe0, 0x59, 0x04, 0x24, -+0xe0, 0x33, 0xa8, 0x32, 0x44, 0x84, 0x70, 0x2e, 0x47, 0x08, 0x60, 0x10, 0xc0, -+0x20, 0x02, 0xfc, 0x6c, 0x0a, 0x4a, 0x88, 0xe0, 0x1c, 0x0c, 0x20, 0x02, 0x14, -+0xcc, 0x10, 0x02, 0xf0, 0xcc, 0x13, 0x46, 0x00, 0x40, 0x0a, 0x41, 0x04, 0xec, -+0x13, 0x4c, 0x60, 0x40, 0x10, 0x40, 0x00, 0xdc, 0x15, 0x14, 0xdc, 0x62, 0x04, -+0x00, 0x80, 0xfb, 0x86, 0x05, 0x74, 0xe1, 0x1d, 0xc1, 0x13, 0x4c, 0x60, 0x40, -+0x14, 0x00, 0x80, 0xdb, 0x14, 0xa4, 0x0e, 0xa8, 0x04, 0x88, 0x7a, 0x84, 0x73, -+0x4c, 0x64, 0xe0, 0xe8, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x8e, 0x40, 0xb1, 0x66, -+0x9b, 0xd3, 0x08, 0x6d, 0xf8, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x85, 0x4c, 0x3c, -+0xe0, 0x28, 0x6d, 0xf8, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0x28, 0x6d, 0xf8, 0xee, -+0x48, 0x6c, 0xf8, 0x6e, 0x0e, 0x02, 0x00, 0x60, 0x1e, 0xd1, 0x05, 0x4c, 0x40, -+0x60, 0x11, 0x91, 0x0b, 0x16, 0x64, 0xe0, 0x7b, 0x16, 0x5c, 0xe0, 0x89, 0x16, -+0xc0, 0xe0, 0x08, 0x49, 0x00, 0xe8, 0x3b, 0x00, 0x80, 0x44, 0x7c, 0xf0, 0x81, -+0x01, 0x11, 0x81, 0xb8, 0x40, 0x40, 0x6f, 0x0b, 0x8e, 0x4b, 0x0c, 0x60, 0x60, -+0x06, 0x0e, 0x00, 0x60, 0xe0, 0xcf, 0x0e, 0x5a, 0x11, 0x81, 0x21, 0x01, 0x06, -+0x06, 0x01, 0x60, 0xe0, 0xcf, 0xd8, 0x7f, 0x3c, 0x6f, 0x0b, 0x88, 0x14, 0x64, -+0x86, 0x57, 0x94, 0xe1, 0x05, 0x4c, 0x2c, 0xe0, 0x0a, 0x86, 0x83, 0x4c, 0xe4, -+0xe0, 0x03, 0x4c, 0xe0, 0xe0, 0x08, 0x86, 0x09, 0xbe, 0x03, 0x4c, 0xe8, 0xe0, -+0x08, 0x86, 0x09, 0xbe, 0x07, 0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, 0x54, -+0xe0, 0x0a, 0xc4, 0x03, 0x4c, 0xec, 0xe0, 0x0a, 0x44, 0x11, 0x91, 0xe8, 0x45, -+0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x58, 0xe0, 0x0a, 0x46, 0x11, 0x91, 0x78, -+0x45, 0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x5c, 0xe0, 0x0b, 0x02, 0x10, 0x60, -+0x11, 0x91, 0xf8, 0x44, 0x00, 0xe8, 0x14, 0xe4, 0x05, 0x4c, 0x60, 0xe0, 0x0b, -+0x02, 0x14, 0x60, 0x11, 0x91, 0x78, 0x44, 0x00, 0xe8, 0x14, 0xa6, 0x05, 0x4c, -+0x64, 0xe0, 0x85, 0x4c, 0x14, 0xe0, 0x85, 0x4c, 0x18, 0xe0, 0x0b, 0x02, 0x7c, -+0x60, 0x11, 0x91, 0xb8, 0x43, 0x00, 0xe8, 0x05, 0x4c, 0x10, 0x60, 0x11, 0x91, -+0x81, 0x4c, 0x14, 0xe0, 0x75, 0x4c, 0x1c, 0xe0, 0x09, 0x14, 0xd0, 0xea, 0x07, -+0xc4, 0x05, 0x00, 0x2c, 0xfc, 0x05, 0x4c, 0x20, 0xe0, 0x0b, 0x14, 0x94, 0xe5, -+0x98, 0x42, 0x00, 0xe8, 0x05, 0x4c, 0x38, 0x60, 0x11, 0x91, 0x0b, 0x14, 0x64, -+0xe5, 0x28, 0x42, 0x00, 0xe8, 0x05, 0x4c, 0x28, 0x60, 0x11, 0x81, 0x09, 0x14, -+0x8c, 0x6a, 0x21, 0x81, 0x0b, 0x12, 0x7c, 0x60, 0x0a, 0x40, 0x88, 0xe0, 0xd6, -+0x0e, 0xcd, 0x0c, 0x73, 0xcf, 0x75, 0x4c, 0x24, 0x60, 0x3b, 0x8e, 0x28, 0x79, -+0x3c, 0xef, 0x0e, 0xd8, 0x16, 0x41, 0x08, 0xe0, 0x0c, 0x0c, 0xfc, 0xf2, 0xb8, -+0x1e, 0x48, 0xff, 0xc3, 0xc1, 0x4a, 0x00, 0x00, 0xe0, 0x0c, 0x00, 0x00, 0xe2, -+0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x00, 0x00, 0xfa, 0x88, 0x61, 0x28, 0xef, 0x4c, -+0x08, 0x00, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x88, 0x5d, -+0x48, 0x6f, 0xf6, 0x40, 0x04, 0xe0, 0x0b, 0xa1, 0x85, 0x80, 0x0c, 0x0c, 0x00, -+0xf2, 0x93, 0xdd, 0xb8, 0x6b, 0x54, 0xef, 0xc6, 0x4c, 0x84, 0xe0, 0x04, 0x98, -+0x09, 0x00, 0x20, 0xe1, 0x4a, 0x40, 0x80, 0xe0, 0x85, 0x88, 0xc6, 0x40, 0xb4, -+0x60, 0x46, 0x45, 0x00, 0xe0, 0x19, 0x00, 0xb4, 0xe4, 0x16, 0x42, 0x0a, 0xe0, -+0x03, 0x82, 0x09, 0x00, 0x40, 0xe2, 0x0b, 0xa5, 0xf5, 0x84, 0x48, 0x56, 0x40, -+0x6f, 0x01, 0x85, 0x58, 0x4c, 0x40, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0xd8, 0x7d, -+0x44, 0x6f, 0x06, 0x00, 0x80, 0xe1, 0x58, 0x50, 0x40, 0xef, 0x18, 0x70, 0xf4, -+0xef, 0x4e, 0x40, 0x01, 0x60, 0x10, 0xc0, 0x08, 0x80, 0x0b, 0xa1, 0x08, 0x70, -+0xf4, 0xcf, 0x09, 0x0c, 0x48, 0xe0, 0x0b, 0xa1, 0x95, 0x84, 0xe8, 0x70, 0x38, -+0xef, 0x06, 0x40, 0x94, 0x60, 0x16, 0x07, 0x04, 0xe1, 0x04, 0x80, 0x1b, 0x00, -+0x18, 0xe1, 0x2b, 0x00, 0x50, 0xe1, 0x48, 0x8c, 0x39, 0x06, 0xac, 0xe0, 0x13, -+0xa4, 0x13, 0xa8, 0x13, 0xa6, 0x15, 0x40, 0x2c, 0xe0, 0xc6, 0x00, 0x2c, 0x61, -+0x11, 0xa1, 0x04, 0x80, 0x13, 0x40, 0xd0, 0x65, 0xe6, 0x40, 0xe0, 0xe0, 0x0a, -+0x00, 0x06, 0x42, 0x94, 0xe0, 0x14, 0x84, 0x03, 0x42, 0x10, 0x62, 0x06, 0x41, -+0x04, 0xe0, 0x0c, 0x0c, 0x00, 0xf2, 0x98, 0x17, 0x48, 0xff, 0xc3, 0xc1, 0x66, -+0x01, 0xcc, 0xe0, 0x18, 0x80, 0x0a, 0x42, 0x84, 0xe0, 0x10, 0x42, 0xf8, 0xd3, -+0x11, 0x40, 0x00, 0xc0, 0x93, 0xdd, 0x4a, 0x40, 0x80, 0xe0, 0x55, 0x84, 0x14, -+0x04, 0xa0, 0x60, 0x0e, 0x06, 0x00, 0x70, 0x3f, 0xc0, 0x2f, 0x06, 0x14, 0x06, -+0xa0, 0xe1, 0x14, 0x00, 0xe0, 0x61, 0x30, 0x46, 0x00, 0x70, 0xff, 0xc0, 0x17, -+0x70, 0x3f, 0xa0, 0x1f, 0xa4, 0x1f, 0xa6, 0x93, 0x5d, 0x0b, 0x82, 0x4c, 0x04, -+0x04, 0xfa, 0x86, 0x0d, 0xcc, 0x60, 0x71, 0x81, 0x7c, 0x98, 0x88, 0x55, 0x68, -+0xef, 0x0a, 0x98, 0x00, 0x42, 0xf1, 0x73, 0xff, 0xc0, 0x19, 0xc2, 0x1c, 0x18, -+0x60, 0x02, 0xe1, 0x65, 0x02, 0xc0, 0x65, 0x81, 0x24, 0x84, 0x2b, 0xa1, 0xf5, -+0x80, 0x71, 0x02, 0x11, 0x88, 0x0a, 0x0e, 0x00, 0xe1, 0x35, 0xfe, 0x75, 0x81, -+0x77, 0x50, 0x00, 0x40, 0xf0, 0xf3, 0x0f, 0xae, 0x09, 0xc4, 0x0c, 0x98, 0x4c, -+0x0c, 0x04, 0xf2, 0x93, 0xdd, 0x4c, 0x04, 0x7c, 0xfa, 0xbb, 0x06, 0x6b, 0x82, -+0x14, 0x2c, 0x9b, 0x80, 0x74, 0x24, 0xab, 0x84, 0xa4, 0x00, 0xa0, 0x61, 0x8b, -+0x88, 0x1b, 0x81, 0x65, 0x82, 0x0e, 0x2c, 0x0b, 0x8e, 0x78, 0x56, 0x30, 0x6f, -+0x1b, 0x8c, 0x24, 0x2c, 0x0b, 0x8e, 0x28, 0x59, 0x30, 0x6f, 0x1b, 0x8c, 0x04, -+0x18, 0xb1, 0x83, 0x11, 0x01, 0x21, 0x83, 0x38, 0x44, 0x00, 0x68, 0x31, 0x85, -+0xa4, 0x02, 0x80, 0x7a, 0x21, 0x8b, 0xd8, 0x43, 0x00, 0x68, 0x06, 0x46, 0xfc, -+0xe1, 0xab, 0x00, 0x0b, 0x8e, 0x78, 0x40, 0xf8, 0x6f, 0x1b, 0x94, 0x09, 0x12, -+0x10, 0x60, 0x1b, 0x90, 0x98, 0x79, 0xfc, 0x6f, 0x70, 0x12, 0x10, 0xe4, 0x1b, -+0x00, 0x0b, 0x92, 0xb8, 0x7f, 0xf4, 0xef, 0x11, 0x03, 0x21, 0x85, 0x31, 0x09, -+0x0b, 0x94, 0x58, 0x42, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, 0x18, 0x7f, 0xf4, -+0x6f, 0x1b, 0x90, 0x70, 0x12, 0x50, 0x64, 0x36, 0x54, 0x48, 0xe1, 0x08, 0x42, -+0x00, 0x68, 0x0b, 0x92, 0x0a, 0x00, 0x00, 0xfb, 0xb1, 0x54, 0x00, 0x40, 0x0a, -+0x40, 0xa0, 0xe0, 0xe5, 0xfc, 0x11, 0x01, 0x21, 0x85, 0x31, 0x09, 0x0b, 0x90, -+0xc8, 0x40, 0x00, 0xe8, 0x8b, 0x00, 0x0b, 0x8e, 0x88, 0x7d, 0xf4, 0x6f, 0x1b, -+0x90, 0x8e, 0x98, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x1f, 0x25, -+0x32, 0x40, 0x80, 0xf8, 0x1f, 0x86, 0x93, 0x5d, 0x0f, 0xa2, 0x04, 0x80, 0x93, -+0xdd, 0x0c, 0x00, 0x80, 0xfa, 0xa8, 0x4c, 0x48, 0x6f, 0xe6, 0x40, 0x08, 0xe0, -+0x0b, 0xa1, 0x95, 0x84, 0xc8, 0x46, 0x40, 0xef, 0x86, 0x02, 0x84, 0x60, 0xc6, -+0x04, 0x84, 0xe0, 0x14, 0x04, 0x5a, 0x00, 0x08, 0xe0, 0x24, 0x88, 0x4a, 0x42, -+0x08, 0x60, 0x46, 0x02, 0x84, 0xe0, 0x0a, 0x42, 0x80, 0xe1, 0x0c, 0x00, 0x00, -+0xe2, 0x06, 0x84, 0xf6, 0x40, 0x08, 0xe0, 0x0c, 0x08, 0x80, 0xf2, 0xd8, 0x0a, -+0x48, 0xff, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0xf0, 0x1e, 0x60, 0x6c, 0xa6, -+0x01, 0x04, 0xe0, 0x48, 0x4a, 0x48, 0xef, 0x0b, 0xa1, 0x15, 0x90, 0xc8, 0x5d, -+0x2c, 0xef, 0xe8, 0x7a, 0xf4, 0x6e, 0x0e, 0x02, 0x24, 0x74, 0x03, 0xc0, 0x86, -+0x50, 0x84, 0xe0, 0x69, 0x10, 0x44, 0xe0, 0x58, 0x7a, 0xf4, 0x6e, 0x1b, 0x8c, -+0x04, 0x60, 0x7b, 0x80, 0x1b, 0x00, 0x28, 0xe0, 0x0b, 0x00, 0x24, 0xe0, 0x13, -+0xa0, 0x10, 0x00, 0x04, 0x64, 0x1b, 0x8c, 0x88, 0x79, 0xf4, 0xee, 0x14, 0xa0, -+0x19, 0x02, 0x28, 0xe0, 0x19, 0xbe, 0x06, 0x44, 0x06, 0x60, 0x06, 0x41, 0xdc, -+0xe0, 0x04, 0x00, 0x16, 0x42, 0x1e, 0xe0, 0x21, 0xbe, 0x1e, 0x7c, 0x27, 0xcb, -+0x2c, 0x7c, 0x0e, 0x02, 0x25, 0x74, 0x03, 0xc0, 0x48, 0x78, 0xf4, 0xee, 0x0e, -+0x7e, 0x11, 0x81, 0x1e, 0x09, 0xf0, 0x00, 0x10, 0xe4, 0x1c, 0x95, 0x88, 0x7e, -+0x1c, 0xef, 0x0a, 0x95, 0x18, 0x41, 0x00, 0x68, 0x01, 0xa0, 0x06, 0x00, 0x38, -+0x61, 0x11, 0x83, 0x78, 0x7c, 0x1c, 0xef, 0x18, 0x46, 0x48, 0x6f, 0xb6, 0x01, -+0x04, 0xe0, 0xf1, 0xb0, 0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x1b, -+0x00, 0x06, 0x00, 0x38, 0xe1, 0x04, 0x80, 0x08, 0x35, 0xf4, 0x7f, 0x01, 0xc8, -+0xc3, 0xc1, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x4e, 0x84, 0x60, 0xf0, 0x1e, 0x20, -+0xee, 0x84, 0x9c, 0x19, 0x0e, 0x48, 0xe0, 0x0a, 0xe2, 0x2a, 0xe0, 0x03, 0xa4, -+0x01, 0x82, 0x38, 0x75, 0xf4, 0x6e, 0x04, 0x00, 0x80, 0xfb, 0x0b, 0x10, 0x64, -+0x60, 0x6b, 0x80, 0x0b, 0xa1, 0x05, 0x0e, 0x04, 0xc0, 0x99, 0x00, 0xa0, 0xc0, -+0xd5, 0x84, 0x09, 0x10, 0x24, 0x60, 0x06, 0x03, 0xd0, 0xe0, 0x1a, 0x84, 0x07, -+0xc5, 0x09, 0x82, 0x1f, 0x21, 0x06, 0x00, 0x04, 0xe0, 0x10, 0x42, 0x01, 0x70, -+0xff, 0xc0, 0x17, 0xd1, 0x1b, 0xa1, 0x78, 0x73, 0xf4, 0x6e, 0x16, 0x02, 0x00, -+0x80, 0x00, 0x12, 0x04, 0xec, 0x18, 0x42, 0x48, 0x6f, 0x36, 0x01, 0x04, 0xe0, -+0x0b, 0xa1, 0xb5, 0xb0, 0x04, 0x1c, 0x06, 0x11, 0xd0, 0xe0, 0x19, 0x10, 0x24, -+0x6e, 0x46, 0x05, 0xb8, 0xe0, 0xa4, 0x9e, 0x09, 0x00, 0xb0, 0xe0, 0x18, 0x08, -+0x5a, 0x02, 0x00, 0xe0, 0x1c, 0x06, 0x00, 0xe2, 0x36, 0x3e, 0x09, 0x86, 0x0b, -+0x21, 0x19, 0x82, 0x0c, 0x04, 0x00, 0x62, 0x0b, 0xa5, 0x16, 0x7c, 0x64, 0x02, -+0x80, 0xfb, 0x26, 0x3c, 0x6b, 0x9e, 0x1e, 0xbe, 0x19, 0x0e, 0x60, 0xe0, 0x2b, -+0x10, 0x30, 0xf8, 0x0c, 0x00, 0x00, 0xe2, 0x16, 0x1b, 0x11, 0x81, 0x06, 0x7e, -+0x2b, 0xa3, 0x19, 0x14, 0x5c, 0xc0, 0x09, 0x0e, 0x80, 0xe0, 0x25, 0x10, 0xa4, -+0xe3, 0x35, 0x10, 0xa8, 0x63, 0x10, 0x42, 0x3c, 0xd0, 0x0c, 0x0b, 0x01, 0x81, -+0x16, 0x1d, 0x11, 0x81, 0x26, 0x1f, 0x46, 0x05, 0x04, 0xe0, 0x0c, 0x89, 0x06, -+0x99, 0x06, 0xa5, 0x0c, 0x91, 0x3e, 0x8b, 0x0e, 0x91, 0x0e, 0x8f, 0x0e, 0x0d, -+0x60, 0x00, 0xa0, 0xe4, 0x91, 0x5e, 0x90, 0xe0, 0xc8, 0x7a, 0xf4, 0xee, 0x09, -+0x14, 0x58, 0xe0, 0x19, 0x10, 0xf0, 0xf8, 0x0e, 0x3f, 0xfe, 0x41, 0x3d, 0x70, -+0xff, 0xc0, 0x1b, 0x25, 0xf6, 0x43, 0x3c, 0xe0, 0x05, 0x5e, 0x80, 0x60, 0x16, -+0x00, 0x00, 0x80, 0x15, 0x5e, 0x84, 0xe0, 0x01, 0x5e, 0x34, 0x80, 0x05, 0x14, -+0x18, 0xe0, 0x38, 0x47, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x2a, -+0x20, 0x11, 0x91, 0x0e, 0x97, 0x78, 0x5d, 0xfc, 0x6f, 0x0b, 0x84, 0x19, 0x10, -+0xc0, 0xe9, 0x0e, 0xb7, 0x4a, 0x42, 0x80, 0xe0, 0xc5, 0x82, 0x60, 0x00, 0xc0, -+0x65, 0x11, 0xfb, 0x75, 0x81, 0x24, 0x37, 0x11, 0x82, 0x2e, 0xc1, 0x24, 0x97, -+0x25, 0x40, 0x44, 0xf8, 0x1b, 0xa1, 0x35, 0xfe, 0xe5, 0x85, 0x04, 0x9e, 0x05, -+0x00, 0x1c, 0xe0, 0x28, 0x45, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, -+0x14, 0x9e, 0x0e, 0x99, 0x05, 0x02, 0x20, 0xe0, 0x98, 0x44, 0x00, 0x68, 0x00, -+0x40, 0xfc, 0x73, 0xff, 0xc7, 0x14, 0x9e, 0x0e, 0x9b, 0x05, 0x02, 0x24, 0xe0, -+0x08, 0x44, 0x00, 0x68, 0x00, 0x40, 0xfc, 0x73, 0xff, 0xc7, 0x2a, 0x22, 0x11, -+0x91, 0x0e, 0x9d, 0x48, 0x5a, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x60, 0x11, 0x91, -+0x0e, 0xb9, 0xe8, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x2a, 0x62, 0x11, 0x91, 0x0e, -+0xbb, 0x88, 0x59, 0xfc, 0x6f, 0x0b, 0x84, 0x0e, 0xbd, 0x04, 0x9c, 0x09, 0x00, -+0x24, 0xe0, 0x0a, 0x40, 0x88, 0xe0, 0xa5, 0x84, 0x04, 0xb7, 0xf8, 0x7a, 0xf4, -+0x6e, 0x1b, 0x80, 0x14, 0xb9, 0x0e, 0xb7, 0xa8, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, -+0x14, 0xbb, 0x0e, 0xb9, 0x58, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, 0x14, 0xbd, 0x0e, -+0xbb, 0x08, 0x7a, 0xf4, 0x6e, 0x0b, 0x82, 0x0e, 0xbd, 0x86, 0x41, 0x30, 0x61, -+0x1b, 0x9e, 0xd8, 0x4c, 0x08, 0xef, 0x78, 0x75, 0x44, 0x6f, 0x46, 0x01, 0x04, -+0xe0, 0xf0, 0x1e, 0x20, 0xe6, 0x0c, 0x0c, 0x3c, 0xf2, 0x93, 0xdd, 0x4c, 0x00, -+0x00, 0xfa, 0x08, 0x74, 0x24, 0x6f, 0x11, 0x8f, 0x4c, 0x08, 0x00, 0xf2, 0x93, -+0xdd, 0x0c, 0x04, 0x7c, 0xfe, 0x6b, 0x04, 0xf0, 0x1e, 0x60, 0xec, 0xb5, 0x0c, -+0x10, 0xe0, 0x85, 0x0c, 0x18, 0xe0, 0x79, 0x0c, 0x24, 0xe0, 0xa4, 0xda, 0x1e, -+0x0b, 0x11, 0x81, 0x0e, 0x7e, 0x0b, 0x96, 0x68, 0x79, 0xf4, 0xee, 0x0b, 0xa1, -+0x15, 0x82, 0x14, 0x18, 0x0b, 0x96, 0x88, 0x79, 0xf4, 0xee, 0x0b, 0xa1, 0xb5, -+0x4c, 0x00, 0xc0, 0x11, 0x01, 0x0b, 0x94, 0x98, 0x78, 0xf4, 0xee, 0x94, 0x18, -+0x0b, 0xa1, 0x05, 0x1e, 0x14, 0xc0, 0xbe, 0xbe, 0x75, 0x82, 0x0b, 0x14, 0x1b, -+0x92, 0xf8, 0x78, 0xf4, 0xee, 0x04, 0x0b, 0x0b, 0xa1, 0xa5, 0x4c, 0x00, 0x40, -+0xa0, 0x52, 0x00, 0xdc, 0xae, 0x7c, 0xab, 0x80, 0x77, 0x42, 0x0b, 0x92, 0x15, -+0x14, 0x1c, 0xfe, 0x58, 0x75, 0xf4, 0xee, 0x0b, 0x14, 0x44, 0x60, 0x9b, 0x80, -+0x88, 0x75, 0xf4, 0xee, 0xbb, 0x00, 0x0b, 0x92, 0x08, 0x77, 0xf4, 0x6e, 0x1b, -+0x96, 0x0b, 0xa1, 0x90, 0x56, 0x00, 0x1c, 0xa0, 0x12, 0x88, 0xe4, 0xc8, 0x75, -+0xf4, 0x6e, 0x0b, 0x96, 0xab, 0x00, 0x01, 0x81, 0x01, 0x4c, 0x20, 0x60, 0x8b, -+0xa1, 0x04, 0x7e, 0x76, 0x03, 0x71, 0x7b, 0x34, 0xce, 0xac, 0xd8, 0x03, 0x8e, -+0x00, 0x00, 0x70, 0xe7, 0x0e, 0x89, 0x65, 0x88, 0x8b, 0xa3, 0x35, 0x08, 0x06, -+0x02, 0x01, 0x00, 0xc0, 0xcf, 0x58, 0x74, 0xf4, 0x6e, 0x0b, 0x96, 0x28, 0x73, -+0xf4, 0x6e, 0x8b, 0x80, 0x1b, 0x00, 0x0b, 0x96, 0x58, 0x73, 0xf4, 0xee, 0xd8, -+0x49, 0x00, 0xe8, 0x18, 0x74, 0xf4, 0x6e, 0x76, 0x03, 0x70, 0x7b, 0x34, 0xce, -+0x0b, 0xa1, 0x25, 0x84, 0x11, 0x01, 0x0b, 0x96, 0x48, 0x74, 0xf4, 0xee, 0x0b, -+0xa1, 0x80, 0x14, 0x04, 0x04, 0x80, 0x54, 0x00, 0xdc, 0x75, 0x81, 0xc8, 0x70, -+0xf4, 0x6e, 0x0b, 0x96, 0x58, 0x72, 0xf4, 0xee, 0xab, 0x80, 0xac, 0xd8, 0x0a, -+0xa4, 0x08, 0x71, 0xf4, 0xee, 0x04, 0x0b, 0x9b, 0x80, 0x73, 0x80, 0x0b, 0x0e, -+0x40, 0xe0, 0x98, 0x70, 0xf4, 0xee, 0xbb, 0x00, 0xa4, 0x00, 0x80, 0xfb, 0x48, -+0x70, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x96, 0x68, 0x49, 0x00, 0xe8, 0x1b, 0x00, -+0x0b, 0x92, 0xc8, 0x47, 0x00, 0xe8, 0xa8, 0x70, 0xf4, 0xee, 0x04, 0x09, 0xab, -+0x80, 0xac, 0xd8, 0x9a, 0x80, 0x9c, 0xda, 0x0b, 0x0e, 0x4c, 0xe0, 0x18, 0x6f, -+0xf4, 0xee, 0x0b, 0x0e, 0x48, 0x60, 0xbb, 0x80, 0xc8, 0x6e, 0xf4, 0xee, 0x8b, -+0x00, 0x0b, 0x92, 0x88, 0x6e, 0xf4, 0xee, 0x1b, 0x00, 0x0b, 0x90, 0xa8, 0x47, -+0x00, 0xe8, 0x1b, 0x00, 0x0b, 0x96, 0x08, 0x46, 0x00, 0xe8, 0xe8, 0x6e, 0xf4, -+0xee, 0xb4, 0x3e, 0x9b, 0x80, 0x84, 0xfc, 0x9c, 0xda, 0x1b, 0x96, 0xf8, 0x6d, -+0xf4, 0x6e, 0x0b, 0x90, 0x68, 0x44, 0x00, 0xe8, 0xe8, 0x6e, 0xf4, 0x6e, 0x11, -+0x81, 0x0b, 0xa1, 0x85, 0x8e, 0x11, 0x01, 0x0b, 0x96, 0xf8, 0x6d, 0xf4, 0xee, -+0x2a, 0x00, 0x00, 0x60, 0x0b, 0x94, 0x24, 0x7e, 0x1b, 0x92, 0x34, 0x8b, 0xf8, -+0x74, 0x18, 0xef, 0x58, 0x01, 0x01, 0x40, 0x00, 0x40, 0x9b, 0x80, 0x0b, 0x16, -+0x1b, 0x92, 0x78, 0x6d, 0xf4, 0xee, 0x0b, 0xa1, 0x85, 0x82, 0x1a, 0xd8, 0x09, -+0x0c, 0x20, 0xe0, 0x11, 0x82, 0x04, 0x09, 0x0b, 0xa1, 0x1c, 0x58, 0x70, 0x00, -+0x90, 0xc4, 0x0a, 0x80, 0x0c, 0xda, 0x11, 0x01, 0x0b, 0x90, 0xe8, 0x6b, 0xf4, -+0xee, 0x0b, 0xa1, 0xb5, 0x84, 0x0b, 0x10, 0x1b, 0x92, 0x88, 0x6c, 0xf4, 0xee, -+0x0b, 0xa1, 0xe5, 0x82, 0x09, 0x0c, 0x20, 0xe0, 0x1a, 0xd8, 0x0b, 0xa1, 0x70, -+0x0e, 0x98, 0x44, 0x10, 0x00, 0x04, 0xec, 0x75, 0x5e, 0x10, 0xc0, 0x0c, 0xd8, -+0x04, 0x89, 0x0a, 0x80, 0x0c, 0xda, 0xf1, 0xb0, 0x0c, 0x0c, 0x7c, 0xf6, 0x93, -+0xdd, 0x0c, 0x04, 0x00, 0xfa, 0x6b, 0x00, 0x11, 0x81, 0xe8, 0x6a, 0xf4, 0xee, -+0x0b, 0xa1, 0x64, 0x0c, 0x7c, 0xdd, 0x0b, 0x8c, 0x0c, 0x0c, 0x00, 0xf2, 0x93, -+0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x0c, 0xfa, 0x6b, 0x02, 0x7b, 0x80, 0x08, 0x6a, -+0xf4, 0xee, 0x8b, 0x00, 0x0b, 0x8e, 0x48, 0x69, 0xf4, 0x6e, 0x1b, 0x8c, 0x0b, -+0xa1, 0x70, 0x4c, 0x00, 0x1c, 0x8b, 0xa1, 0x70, 0x4c, 0x00, 0xdc, 0x0b, 0x8c, -+0x0c, 0x0c, 0x0c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x4c, 0x04, 0x04, 0xfa, 0x6b, -+0x02, 0x7b, 0x80, 0xa8, 0x68, 0xf4, 0xee, 0x0b, 0xa1, 0x70, 0x4c, 0x00, 0x9c, -+0x0b, 0x8c, 0x4c, 0x0c, 0x04, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, -+0xfa, 0x6b, 0x00, 0x21, 0x81, 0x04, 0x18, 0x31, 0x83, 0x68, 0x53, 0xfc, 0xef, -+0x0e, 0x98, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0x18, 0xa9, 0x00, 0x00, 0x38, -+0x90, 0x40, 0x00, 0x08, 0x14, 0xb8, 0xe0, 0x80, 0x2c, 0x40, 0x00, 0xa8, 0x3a, -+0xe8, 0xe0, 0x08, 0x9f, 0x40, 0x00, 0x28, 0x28, 0xb0, 0xe0, 0x18, 0x72, 0x40, -+0x00, 0x88, 0x19, 0xc8, 0xe0, 0xe0, 0xbb, 0x40, 0x00, 0x08, 0x0c, 0xa4, 0xe0, -+0xa8, 0xe3, 0x40, 0x00, 0x28, 0x13, 0x90, 0xe0, 0xf0, 0xec, 0x40, 0x00, 0x68, -+0x0d, 0x8c, 0xe0, 0x48, 0xa8, 0x40, 0x00, 0xa8, 0x3c, 0xac, 0xe0, 0x28, 0xe4, -+0x40, 0x00, 0x08, 0x0e, 0x94, 0xe0, 0xb8, 0xe2, 0x40, 0x00, 0x28, 0x3d, 0x90, -+0xe0, 0x90, 0xa7, 0x40, 0x00, 0xc8, 0x13, 0xb0, 0xe0, 0x18, 0xc1, 0x40, 0x00, -+0xa8, 0x2a, 0xa4, 0xe0, 0xa8, 0x91, 0x40, 0x00, 0x68, 0x2f, 0xbc, 0xe0, 0x88, -+0xf1, 0x40, 0x00, 0x08, 0x1c, 0x88, 0xe0, 0xd0, 0x8e, 0x40, 0x00, 0xa8, 0x19, -+0xb8, 0xe0, 0x38, 0x82, 0x40, 0x00, 0x28, 0x38, 0xbc, 0xe0, 0x88, 0xe0, 0x40, -+0x00, 0xa8, 0x0e, 0x98, 0xe0, 0xd8, 0xe4, 0x40, 0x00, 0x68, 0x32, 0x94, 0xe0, -+0x18, 0xd7, 0x40, 0x00, 0x28, 0x2d, 0x9c, 0xe0, 0x40, 0xe8, 0x40, 0x00, 0x28, -+0x19, 0x94, 0xe0, 0xa8, 0x78, 0x40, 0x00, 0x28, 0x18, 0xcc, 0xe0, 0xf0, 0x95, -+0x40, 0x00, 0x48, 0x34, 0xbc, 0xe0, 0xa8, 0xd2, 0x40, 0x00, 0x48, 0x16, 0xa0, -+0xe0, 0x18, 0x52, 0x40, 0x00, 0x68, 0x2b, 0xe0, 0xe0, 0x00, 0xb9, 0x00, 0x00, -+0x23, 0xdb, 0x00, 0x00 -+}; -+ -+static const u8 cut2_patch[] = { -+0x37, 0x00, 0x05, 0x00, 0x0c, 0x04, 0x3c, 0xfa, 0x86, 0x0e, 0x84, 0x60, 0x06, -+0x11, 0x84, 0xe0, 0x04, 0x1c, 0x06, 0x13, 0x88, 0xe1, 0x14, 0xa0, 0x0d, 0xc2, -+0x95, 0x80, 0x04, 0xa4, 0x0b, 0xa3, 0xb5, 0x88, 0x78, 0x6c, 0x40, 0xef, 0x6b, -+0x00, 0x46, 0x01, 0x84, 0xe0, 0x88, 0x53, 0x48, 0x6f, 0x46, 0x15, 0x84, 0xe0, -+0x6b, 0x25, 0xc6, 0x0d, 0x84, 0xe0, 0x95, 0x84, 0x08, 0xa8, 0x4a, 0x00, 0xfc, -+0xfb, 0x05, 0x84, 0x09, 0x12, 0x1c, 0xe0, 0xa8, 0x46, 0x48, 0xef, 0x04, 0x1c, -+0x11, 0x83, 0x16, 0x18, 0xc6, 0x04, 0x84, 0xe0, 0x0e, 0x08, 0x01, 0x87, 0xf8, -+0x6a, 0x40, 0xef, 0x46, 0x0c, 0x84, 0xe0, 0x04, 0x1c, 0x11, 0x81, 0x16, 0x98, -+0x0e, 0xa0, 0x06, 0x41, 0x84, 0x60, 0xc6, 0x02, 0xd8, 0xe0, 0x04, 0x80, 0x08, -+0x80, 0x06, 0x84, 0x0c, 0x0c, 0x3c, 0xf2, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x00, -+0x80, 0xfa, 0xc6, 0x40, 0x84, 0x60, 0x86, 0x43, 0xd8, 0xe0, 0x04, 0x80, 0x09, -+0x00, 0x18, 0xe1, 0x06, 0x84, 0x88, 0x41, 0x68, 0xef, 0x0c, 0x08, 0x80, 0xf2, -+0x48, 0x20, 0x68, 0xff, 0x1e, 0xc0, 0xb5, 0x00, 0x2c, 0xe0, 0xb4, 0x02, 0x00, -+0xfc, 0x15, 0x40, 0x2c, 0xe0, 0x19, 0x10, 0x31, 0x78, 0x01, 0x40, 0x86, 0x04, -+0x0c, 0xe0, 0x4a, 0x04, 0x00, 0x64, 0x31, 0x81, 0x30, 0x0a, 0x04, 0x64, 0x4b, -+0x82, 0x1b, 0x06, 0x3b, 0x8a, 0xc8, 0x44, 0xfc, 0x87, 0x41, 0x50, 0x31, 0x78, -+0x01, 0x40, 0xa1, 0xe1, 0xe6, 0x43, 0x99, 0x6c, 0x10, 0xc0, 0x08, 0x42, 0x00, -+0xf8, 0x00, 0x00, 0x03, 0xa9, 0x00, 0x00, 0x30, 0x85, 0x40, 0x00, 0xa8, 0x16, -+0xbc, 0xe0, 0xcc, 0xc1, 0x40, 0x00, 0xa8, 0x35, 0x9c, 0xe0, 0xb0, 0xc9, 0x40, -+0x00, 0x88, 0x37, 0x98, 0xe0, 0x00, 0xb9, 0x00, 0x00, 0x49, 0xa7, 0x00, 0x00, -+}; -+ -+struct vd55g0_patch { -+ const u8 *bin; -+ const uint size; -+ const u16 major; -+ const u16 minor; -+}; -+ -+struct vd55g0_patch vd55g0_patch_cut1 = { -+ .bin = cut1_patch, -+ .size = ARRAY_SIZE(cut1_patch), -+ .major = 2, -+ .minor = 11, -+}; -+ -+struct vd55g0_patch vd55g0_patch_cut2 = { -+ .bin = cut2_patch, -+ .size = ARRAY_SIZE(cut2_patch), -+ .major = 0, -+ .minor = 5, -+}; diff --git a/kernel/2163-arm64-dts-qcom-enable-Surface-Pro-11-cameras.patch b/kernel/2163-arm64-dts-qcom-enable-Surface-Pro-11-cameras.patch deleted file mode 100644 index 92f8135..0000000 --- a/kernel/2163-arm64-dts-qcom-enable-Surface-Pro-11-cameras.patch +++ /dev/null @@ -1,356 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 17:32:14 -0400 -Subject: [PATCH] arm64: dts: qcom: enable Surface Pro 11 cameras - -Describe the camera PMIC rails, clocks, resets, CCI buses, and CAMSS -endpoints for the VD55G0 IR, OV13858 rear, and IMX681 front camera -modules. - -The board description is based on standard firmware enumeration and -hardware observations made on the author's Surface Pro 11. - -Signed-off-by: Brandon Williams ---- - .../boot/dts/qcom/x1-microsoft-denali.dtsi | 301 ++++++++++++++++++ - 1 file changed, 301 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -index 5a32f393a704..83376d84fb2d 100644 ---- a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -+++ b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - - #include "hamoa-pmics.dtsi" -@@ -495,6 +496,14 @@ vreg_l6b_1p8: ldo6 { - regulator-initial-mode = ; - }; - -+ /* Front camera (IMX681) analog rail. */ -+ vreg_l7b_2p8: ldo7 { -+ regulator-name = "vreg_l7b_2p8"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ regulator-initial-mode = ; -+ }; -+ - vreg_l8b_3p0: ldo8 { - regulator-name = "vreg_l8b_3p0"; - regulator-min-microvolt = <3072000>; -@@ -743,12 +752,256 @@ vreg_l3j_0p8: ldo3 { - regulator-initial-mode = ; - }; - }; -+ -+ /* -+ * PM8010 "m": camera PMIC supplying the rear, front and IR modules. -+ */ -+ regulators-8 { -+ compatible = "qcom,pm8010-rpmh-regulators"; -+ qcom,pmic-id = "m"; -+ -+ /* -+ * TODO: supply parents are unverified. Chosen by voltage -+ * headroom from the rails present on this board, following -+ * the PM8010 wiring seen on other X1E80100 designs -+ * (1.8 V LDOs from vreg_s4c_1p8, 2.8 V LDOs from vreg_bob1). -+ */ -+ vdd-l1-l2-supply = <&vreg_s5j_1p2>; -+ vdd-l3-l4-supply = <&vreg_s4c_1p8>; -+ vdd-l5-supply = <&vreg_bob1>; -+ vdd-l6-supply = <&vreg_s4c_1p8>; -+ vdd-l7-supply = <&vreg_bob1>; -+ -+ vreg_l1m_1p2: ldo1 { -+ regulator-name = "vreg_l1m_1p2"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1200000>; -+ regulator-initial-mode = ; -+ }; -+ -+ /* Front camera (IMX681) IO rail. */ -+ vreg_l3m_1p8: ldo3 { -+ regulator-name = "vreg_l3m_1p8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l2m_1p15: ldo2 { -+ /* 1.152 V is the closest PM8010 step to the 1.15 V rail. */ -+ regulator-name = "vreg_l2m_1p15"; -+ regulator-min-microvolt = <1152000>; -+ regulator-max-microvolt = <1152000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l4m_1p8: ldo4 { -+ regulator-name = "vreg_l4m_1p8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l5m_2p8: ldo5 { -+ regulator-name = "vreg_l5m_2p8"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l6m_1p8: ldo6 { -+ regulator-name = "vreg_l6m_1p8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l7m_2p8: ldo7 { -+ regulator-name = "vreg_l7m_2p8"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ regulator-initial-mode = ; -+ }; -+ }; -+}; -+ -+&camcc { -+ status = "okay"; -+}; -+ -+&camss { -+ vdd-csiphy-0p8-supply = <&vreg_l2c_0p8>; -+ vdd-csiphy-1p2-supply = <&vreg_l1c_1p2>; -+ -+ status = "okay"; -+ -+ ports { -+ /* -+ * port@0 => CSIPHY0: IR camera (ST VD55G0, 1-lane D-PHY) -+ * port@1 => CSIPHY1: rear camera (OV13858, 4-lane D-PHY) -+ * port@2 => CSIPHY2: front camera (Sony IMX681, 1-trio C-PHY), -+ * MCLK4 (gpio100 "cam_aon") @ 19.2 MHz, reset GPIO -+ * 237, rails LDO3_M 1.8 V + LDO7_B 2.8 V. -+ */ -+ port@0 { -+ csiphy0_ep: endpoint { -+ clock-lanes = <7>; -+ data-lanes = <0>; -+ remote-endpoint = <&vd55g0_ep>; -+ }; -+ }; -+ -+ port@1 { -+ csiphy1_ep: endpoint { -+ clock-lanes = <7>; -+ data-lanes = <0 1 2 3>; -+ remote-endpoint = <&ov13858_ep>; -+ }; -+ }; -+ -+ port@2 { -+ csiphy2_ep: endpoint { -+ bus-type = ; -+ data-lanes = <0>; -+ remote-endpoint = <&imx681_ep>; -+ }; -+ }; -+ }; -+}; -+ -+&cci0 { -+ status = "okay"; -+}; -+ -+&cci0_i2c0 { -+ /* -+ * IR camera: ST VD55G0 (ACPI SMO55F0, MSHW0492). -+ * -+ * Hardware observations and firmware enumeration identify MCLK0 at -+ * 19.2 MHz (gpio96), reset TLMM 109 active-low, rails LDO4_M 1.8 V -+ * (vddio) -> LDO2_M 1.15 V (vcore) -> LDO7_M 2.8 V (vana). The -+ * gpio101/102 CCI pair floated during the rear-camera bus hunt while -+ * the rear rails were up, consistent with it being the (unpowered) -+ * IR camera pair. The VD55G0 answers at 0x60 (verified on hardware; -+ * unlike the VD55G1 whose address is fixed at 0x10). 1-lane -+ * D-PHY into CSIPHY0 at 840 Mbps (link-frequency 420 MHz), -+ * 644x604 RAW10 (Y10P) at approximately 30 fps. -+ */ -+ camera@60 { -+ compatible = "st,vd55g0"; -+ reg = <0x60>; -+ -+ reset-gpios = <&tlmm 109 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&cam_ir_default>; -+ pinctrl-names = "default"; -+ -+ clocks = <&camcc CAM_CC_MCLK0_CLK>; -+ assigned-clocks = <&camcc CAM_CC_MCLK0_CLK>; -+ assigned-clock-rates = <19200000>; -+ -+ VCORE-supply = <&vreg_l2m_1p15>; -+ VDDIO-supply = <&vreg_l4m_1p8>; -+ VANA-supply = <&vreg_l7m_2p8>; -+ -+ orientation = <0>; /* Front-facing */ -+ -+ port { -+ vd55g0_ep: endpoint { -+ data-lanes = <1>; -+ link-frequencies = /bits/ 64 <420000000>; -+ remote-endpoint = <&csiphy0_ep>; -+ }; -+ }; -+ }; -+}; -+ -+&cci0_i2c1 { -+ /* -+ * Rear camera: OmniVision OV13858 (ACPI OVTID858, MSHW0491). -+ * -+ * Bus + address verified on hardware 2026-07-11: with the sensor -+ * rails, MCLK1 and reset held active, the sensor ACKs at 0x10 on -+ * the gpio103/104 CCI pair, while the gpio101/102 pair floats -+ * (presumed IR camera pair, unpowered). 0x10 is the OV13858 -+ * default SCCB address (SID low). -+ */ -+ camera@10 { -+ compatible = "ovti,ov13858"; -+ reg = <0x10>; -+ -+ reset-gpios = <&tlmm 110 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&cam_rear_default>; -+ pinctrl-names = "default"; -+ -+ clocks = <&camcc CAM_CC_MCLK1_CLK>; -+ assigned-clocks = <&camcc CAM_CC_MCLK1_CLK>; -+ assigned-clock-rates = <19200000>; -+ -+ avdd-supply = <&vreg_l5m_2p8>; -+ dvdd-supply = <&vreg_l1m_1p2>; -+ dovdd-supply = <&vreg_l6m_1p8>; -+ -+ orientation = <1>; /* Rear-facing */ -+ -+ port { -+ ov13858_ep: endpoint { -+ data-lanes = <1 2 3 4>; -+ link-frequencies = /bits/ 64 <540000000 270000000>; -+ remote-endpoint = <&csiphy1_ep>; -+ }; -+ }; -+ }; - }; - - &gpu { - status = "okay"; - }; - -+&cci1 { -+ status = "okay"; -+}; -+ -+&cci1_i2c1 { -+ /* -+ * Front camera: Sony IMX681 (ACPI SONY0681, MSHW0490). The bus is -+ * cci1 master 1 on gpio235/236 ("aon_cci" -+ * pads on the AON IO island, same arrangement as the Zenbook A14 -+ * front camera on &cci1_i2c1). Hardware observations identify MCLK4 -+ * at 19.2 MHz (gpio100, "cam_aon"), reset TLMM 237 active-low, -+ * LDO3_M 1.8 V (IO) + LDO7_B 2.8 V (analog). Address 0x1a is the -+ * Sony default, and was verified on the hardware. -+ * -+ */ -+ camera@1a { -+ compatible = "sony,imx681"; -+ reg = <0x1a>; -+ -+ reset-gpios = <&tlmm 237 GPIO_ACTIVE_LOW>; -+ pinctrl-0 = <&cam_front_default>; -+ pinctrl-names = "default"; -+ -+ clocks = <&camcc CAM_CC_MCLK4_CLK>; -+ assigned-clocks = <&camcc CAM_CC_MCLK4_CLK>; -+ assigned-clock-rates = <19200000>; -+ -+ avdd-supply = <&vreg_l7b_2p8>; -+ dovdd-supply = <&vreg_l3m_1p8>; -+ -+ orientation = <0>; /* Front-facing */ -+ rotation = <0>; -+ -+ port { -+ imx681_ep: endpoint { -+ bus-type = ; -+ data-lanes = <0>; -+ /* Half of the observed 2406-Msym/s C-PHY symbol rate. */ -+ link-frequencies = /bits/ 64 <1203000000>; -+ remote-endpoint = <&csiphy2_ep>; -+ }; -+ }; -+ }; -+}; -+ - &gpu_zap_shader { - firmware-name = "qcom/x1e80100/microsoft/qcdxkmsuc8380.mbn"; - }; -@@ -1234,6 +1487,54 @@ ssam_state: ssam-state-state { - bias-disable; - }; - -+ cam_front_default: cam-front-default-state { -+ mclk-pins { -+ pins = "gpio100"; -+ function = "cam_aon"; -+ drive-strength = <16>; -+ bias-disable; -+ }; -+ -+ reset-n-pins { -+ pins = "gpio237"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-disable; -+ }; -+ }; -+ -+ cam_ir_default: cam-ir-default-state { -+ mclk-pins { -+ pins = "gpio96"; -+ function = "cam_mclk"; -+ drive-strength = <16>; -+ bias-disable; -+ }; -+ -+ reset-n-pins { -+ pins = "gpio109"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-disable; -+ }; -+ }; -+ -+ cam_rear_default: cam-rear-default-state { -+ mclk-pins { -+ pins = "gpio97"; -+ function = "cam_mclk"; -+ drive-strength = <16>; -+ bias-disable; -+ }; -+ -+ reset-n-pins { -+ pins = "gpio110"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-disable; -+ }; -+ }; -+ - wcn_wlan_bt_en: wcn-wlan-bt-en-state { - pins = "gpio116", "gpio117"; - function = "gpio"; diff --git a/kernel/2164-arm64-dts-qcom-denali-enable-verified-IR-illuminator.patch b/kernel/2164-arm64-dts-qcom-denali-enable-verified-IR-illuminator.patch deleted file mode 100644 index 41e724c..0000000 --- a/kernel/2164-arm64-dts-qcom-denali-enable-verified-IR-illuminator.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Sun, 19 Jul 2026 19:26:01 -0400 -Subject: [PATCH] arm64: dts: qcom: denali: enable verified IR illuminator - -Signed-off-by: Brandon Williams ---- - .../driver-api/media/sp11-camera-provenance.rst | 9 +++++++++ - .../boot/dts/qcom/x1-microsoft-denali.dtsi | 17 +++++++++++++++++ - 2 files changed, 26 insertions(+) - -diff --git a/Documentation/driver-api/media/sp11-camera-provenance.rst b/Documentation/driver-api/media/sp11-camera-provenance.rst -index b774d676d3ee..b8bc3aaaa20a 100644 ---- a/Documentation/driver-api/media/sp11-camera-provenance.rst -+++ b/Documentation/driver-api/media/sp11-camera-provenance.rst -@@ -65,6 +65,15 @@ CAMSS and devicetree foundations - description uses hardware enumeration, standard firmware descriptions, and - observations made on the author's Surface Pro 11. - -+IR illuminator -+ The PM8550 flash-controller description follows the upstream -+ ``qcom,spmi-flash-led`` binding. Current sinks 1 and 4 were identified by -+ independently exercising each controller channel and measuring the resulting -+ VD55G0 frames on the maintainer's own hardware. A combined 600 mA torch -+ ceiling was then verified to provide stable continuous illumination. The -+ board description retains only those bounded hardware facts; it does not -+ include a vendor configuration file or values copied from one. -+ - Denali ath12k rfkill prerequisite - The ath12k devicetree ``disable-rfkill`` support is Dale Whinham's GPL - contribution, originally commit -diff --git a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -index 83376d84fb2d..df0de50e0d85 100644 ---- a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -+++ b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -1002,6 +1003,22 @@ imx681_ep: endpoint { - }; - }; - -+/* -+ * The IR illuminator uses PM8550 current sinks 1 and 4 in parallel. The -+ * channel mapping and 600 mA total torch ceiling were verified on this board -+ * by comparing VD55G0 frames while exercising each sink independently. -+ */ -+&pm8550_flash { -+ status = "okay"; -+ -+ led-0 { -+ function = LED_FUNCTION_FLASH; -+ color = ; -+ led-sources = <1>, <4>; -+ led-max-microamp = <600000>; -+ }; -+}; -+ - &gpu_zap_shader { - firmware-name = "qcom/x1e80100/microsoft/qcdxkmsuc8380.mbn"; - }; diff --git a/kernel/2165-media-imx681-write-exposure-through-the-24-bit-latch.patch b/kernel/2165-media-imx681-write-exposure-through-the-24-bit-latch.patch deleted file mode 100644 index e43f573..0000000 --- a/kernel/2165-media-imx681-write-exposure-through-the-24-bit-latch.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Leon Silcott -Date: Sat, 5 Sep 2026 15:50:36 -0400 -Subject: [PATCH] media: imx681: write exposure through the 24-bit latch - -Use the coarse-integration latch initialized by the sensor mode table. -The inherited 16-bit 0x0202 write did not change brightness in the -upstream author's fixed-light experiment. - -Adapted from Leon Silcott's correction in ooaklee/linux_ms_dev_kit-sp11, -linked below. No frame-timing or sensor-table changes are included. -Local fixed-gain RAW tests on a Surface Pro 11 confirmed monotonic -brightness response and return to the initial level, including a stream -restart. Automatic-exposure tuning and suspend/resume are not qualified. - -Link: https://github.com/ooaklee/linux_ms_dev_kit-sp11/commit/b1754869f458 ---- - drivers/media/i2c/imx681.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/i2c/imx681.c b/drivers/media/i2c/imx681.c -index cf99dd211dc0..b963373951de 100644 ---- a/drivers/media/i2c/imx681.c -+++ b/drivers/media/i2c/imx681.c -@@ -30,7 +30,7 @@ - #define IMX681_MODE_STREAMING 1 - #define IMX681_MODE_STANDBY 0 - #define IMX681_REG_GROUP_HOLD CCI_REG8(0x0104) --#define IMX681_REG_EXPOSURE CCI_REG16(0x0202) -+#define IMX681_REG_EXPOSURE CCI_REG24(0x0229) - #define IMX681_REG_ANALOG_GAIN CCI_REG16(0x0204) - #define IMX681_REG_DIGITAL_GAIN CCI_REG16(0x020e) - #define IMX681_REG_FRAME_LENGTH CCI_REG16(0x0340) diff --git a/kernel/2166-media-imx681-expose-analogue-gain-as-a-linear-value.patch b/kernel/2166-media-imx681-expose-analogue-gain-as-a-linear-value.patch deleted file mode 100644 index e03c87a..0000000 --- a/kernel/2166-media-imx681-expose-analogue-gain-as-a-linear-value.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Mon, 12 Oct 2026 08:46:32 -0400 -Subject: [PATCH] media: imx681: expose analogue gain as a linear value - -The analogue gain register takes a code with gain = 1024 / (1024 - code). -Exposing that code directly as V4L2_CID_ANALOGUE_GAIN means libcamera -needs an IMX681 sensor helper to interpret it. Without one, the soft ISP -takes the code for the gain itself, holds exposure down and leaves the -front camera dark indoors. - -Expose the control in linear 1/256 steps instead, from 256 (1x) to 4096 -(16x, code 960, the previous maximum), and convert to the register code -when writing it. Stock libcamera then drives the sensor correctly with no -sensor-specific code. - -Signed-off-by: Brandon Williams ---- - drivers/media/i2c/imx681.c | 18 +++++++++++++----- - 1 file changed, 13 insertions(+), 5 deletions(-) - -diff --git a/drivers/media/i2c/imx681.c b/drivers/media/i2c/imx681.c -index b963373951de..9dc110d04a9d 100644 ---- a/drivers/media/i2c/imx681.c -+++ b/drivers/media/i2c/imx681.c -@@ -42,7 +42,13 @@ - #define IMX681_FRAME_LENGTH_MAX 0xffff - #define IMX681_EXPOSURE_MARGIN 48 - #define IMX681_EXPOSURE_DEF 1600 --#define IMX681_AGAIN_MAX 960 /* gain = 1024 / (1024 - code) */ -+/* -+ * The analogue gain register holds a code with gain = 1024 / (1024 - code). -+ * V4L2_CID_ANALOGUE_GAIN is linear in 1/256 steps (256 = 1x, 4096 = 16x) so -+ * that userspace without a sensor-specific gain model computes it correctly. -+ */ -+#define IMX681_AGAIN_ONE 256 -+#define IMX681_AGAIN_MAX (16 * IMX681_AGAIN_ONE) - #define IMX681_DGAIN_DEF 0x0100 - #define IMX681_PIXEL_RATE 548571428 - /* V4L2 C-PHY link frequency is half the 2406-Msym/s symbol rate. */ -@@ -176,8 +182,9 @@ static int imx681_s_ctrl(struct v4l2_ctrl *ctrl) - &ret); - break; - case V4L2_CID_ANALOGUE_GAIN: -- cci_write(sensor->regmap, IMX681_REG_ANALOG_GAIN, ctrl->val, -- &ret); -+ cci_write(sensor->regmap, IMX681_REG_ANALOG_GAIN, -+ 1024 - DIV_ROUND_CLOSEST(1024 * IMX681_AGAIN_ONE, -+ ctrl->val), &ret); - break; - case V4L2_CID_DIGITAL_GAIN: - cci_write(sensor->regmap, IMX681_REG_DIGITAL_GAIN, ctrl->val, -@@ -244,8 +251,9 @@ static int imx681_init_controls(struct imx681 *sensor) - IMX681_EXPOSURE_MARGIN, 1, - IMX681_EXPOSURE_DEF); - sensor->again_ctrl = -- v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, -- IMX681_AGAIN_MAX, 1, 0); -+ v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, -+ IMX681_AGAIN_ONE, IMX681_AGAIN_MAX, 1, -+ IMX681_AGAIN_ONE); - sensor->dgain_ctrl = - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, 0x0100, - 0x0fff, 1, IMX681_DGAIN_DEF); diff --git a/kernel/2167-media-i2c-vd55g0-power-the-sensor-off-only-once-when.patch b/kernel/2167-media-i2c-vd55g0-power-the-sensor-off-only-once-when.patch deleted file mode 100644 index 2d58bb7..0000000 --- a/kernel/2167-media-i2c-vd55g0-power-the-sensor-off-only-once-when.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 99dded9d4ae4144adda4405bb22245880c13570d Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Tue, 13 Oct 2026 14:21:46 -0400 -Subject: [PATCH 2167/2169] media: i2c: vd55g0: power the sensor off only once - when probe fails - -probe() let runtime PM suspend the sensor, which powers it off, before -registering the subdevice, and the error path then powered it off again, -unbalancing the clock and regulator enables. Keep a runtime PM reference -until the subdevice is registered, as the imx681 driver does, so a failed -or deferred registration powers the sensor off exactly once. - -Assisted-by: Claude:claude-opus-5-5 -Signed-off-by: Brandon Williams ---- - drivers/media/i2c/vd55g0.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/drivers/media/i2c/vd55g0.c b/drivers/media/i2c/vd55g0.c -index 21b678093b62..98918ecd6e8a 100644 ---- a/drivers/media/i2c/vd55g0.c -+++ b/drivers/media/i2c/vd55g0.c -@@ -1920,10 +1920,13 @@ static int vd55g0_probe(struct i2c_client *client) - goto error_handler_free; - } - -- /* Enable runtime PM and turn off the device */ -+ /* -+ * Enable runtime PM, but keep the device powered until it is -+ * registered: the error path below powers it off itself. -+ */ - pm_runtime_set_active(dev); -+ pm_runtime_get_noresume(dev); - pm_runtime_enable(dev); -- pm_runtime_idle(dev); - - ret = v4l2_async_register_subdev(&sensor->sd); - if (ret) { -@@ -1933,6 +1936,7 @@ static int vd55g0_probe(struct i2c_client *client) - - pm_runtime_set_autosuspend_delay(&client->dev, 1000); - pm_runtime_use_autosuspend(&client->dev); -+ pm_runtime_put_autosuspend(&client->dev); - - dev_dbg(&client->dev, "vd55g0 probe successfully"); - -@@ -1940,6 +1944,7 @@ static int vd55g0_probe(struct i2c_client *client) - - error_pm_runtime: - pm_runtime_disable(&client->dev); -+ pm_runtime_put_noidle(&client->dev); - pm_runtime_set_suspended(&client->dev); - media_entity_cleanup(&sensor->sd.entity); - error_handler_free: diff --git a/kernel/2168-media-i2c-vd55g0-register-as-a-sensor-subdevice.patch b/kernel/2168-media-i2c-vd55g0-register-as-a-sensor-subdevice.patch deleted file mode 100644 index d9985e7..0000000 --- a/kernel/2168-media-i2c-vd55g0-register-as-a-sensor-subdevice.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 169be80a541b106e57f8f9d3a92eb9a18003b58a Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Tue, 13 Oct 2026 14:21:47 -0400 -Subject: [PATCH 2168/2169] media: i2c: vd55g0: register as a sensor subdevice - -Use v4l2_async_register_subdev_sensor() so the V4L2 core looks up the -sensor's privacy LED and other sensor firmware properties, and lights the -LED while the sensor streams. With plain v4l2_async_register_subdev() a -privacy LED described for the IR camera was never used. - -Tested on a Microsoft Surface Pro 11 (X1E80100): the camera privacy LED -now lights while the IR camera streams. - -Assisted-by: Claude:claude-opus-5-5 -Signed-off-by: Brandon Williams ---- - drivers/media/i2c/vd55g0.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/i2c/vd55g0.c b/drivers/media/i2c/vd55g0.c -index 98918ecd6e8a..a62a99f40ba4 100644 ---- a/drivers/media/i2c/vd55g0.c -+++ b/drivers/media/i2c/vd55g0.c -@@ -1928,7 +1928,7 @@ static int vd55g0_probe(struct i2c_client *client) - pm_runtime_get_noresume(dev); - pm_runtime_enable(dev); - -- ret = v4l2_async_register_subdev(&sensor->sd); -+ ret = v4l2_async_register_subdev_sensor(&sensor->sd); - if (ret) { - dev_err(&client->dev, "async subdev register failed %d", ret); - goto error_pm_runtime; diff --git a/kernel/2169-arm64-dts-qcom-x1-microsoft-denali-describe-the-came.patch b/kernel/2169-arm64-dts-qcom-x1-microsoft-denali-describe-the-came.patch deleted file mode 100644 index 342514f..0000000 --- a/kernel/2169-arm64-dts-qcom-x1-microsoft-denali-describe-the-came.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 9064bccf87c0740d1968ef4e417324df26d15510 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Tue, 13 Oct 2026 14:12:38 -0400 -Subject: [PATCH 2169/2169] arm64: dts: qcom: x1-microsoft-denali: describe the - camera privacy LED - -The camera privacy indicator next to the front camera is driven by TLMM -gpio225, whose "cam_indicator_en" pin state nothing used. Describe it as a -gpio-leds privacy LED and point the front, rear and IR camera sensors at -it, so the V4L2 core lights it while any of them streams. - -Tested on a Microsoft Surface Pro 11 (X1E80100): the LED lights while the -front, rear or IR camera streams and goes off when it stops. - -Assisted-by: Claude:claude-opus-5-5 -Signed-off-by: Brandon Williams ---- - .../boot/dts/qcom/x1-microsoft-denali.dtsi | 23 +++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -index df0de50e0d85..1cafff5cf0e7 100644 ---- a/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -+++ b/arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi -@@ -52,6 +52,20 @@ switch-lid { - }; - }; - -+ leds { -+ compatible = "gpio-leds"; -+ -+ pinctrl-0 = <&cam_indicator_en>; -+ pinctrl-names = "default"; -+ -+ privacy_led: privacy-led { -+ function = LED_FUNCTION_INDICATOR; -+ color = ; -+ gpios = <&tlmm 225 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ }; -+ }; -+ - pmic-glink { - compatible = "qcom,x1e80100-pmic-glink", - "qcom,sm8550-pmic-glink", -@@ -896,6 +910,9 @@ camera@60 { - pinctrl-0 = <&cam_ir_default>; - pinctrl-names = "default"; - -+ leds = <&privacy_led>; -+ led-names = "privacy"; -+ - clocks = <&camcc CAM_CC_MCLK0_CLK>; - assigned-clocks = <&camcc CAM_CC_MCLK0_CLK>; - assigned-clock-rates = <19200000>; -@@ -934,6 +951,9 @@ camera@10 { - pinctrl-0 = <&cam_rear_default>; - pinctrl-names = "default"; - -+ leds = <&privacy_led>; -+ led-names = "privacy"; -+ - clocks = <&camcc CAM_CC_MCLK1_CLK>; - assigned-clocks = <&camcc CAM_CC_MCLK1_CLK>; - assigned-clock-rates = <19200000>; -@@ -981,6 +1001,9 @@ camera@1a { - pinctrl-0 = <&cam_front_default>; - pinctrl-names = "default"; - -+ leds = <&privacy_led>; -+ led-names = "privacy"; -+ - clocks = <&camcc CAM_CC_MCLK4_CLK>; - assigned-clocks = <&camcc CAM_CC_MCLK4_CLK>; - assigned-clock-rates = <19200000>; diff --git a/kernel/2170-drm-msm-adreno-a6xx-Mark-cxpd-device_link-as-statele.patch b/kernel/2170-drm-msm-adreno-a6xx-Mark-cxpd-device_link-as-statele.patch deleted file mode 100644 index 00b7b35..0000000 --- a/kernel/2170-drm-msm-adreno-a6xx-Mark-cxpd-device_link-as-statele.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Akhil P Oommen -Date: Wed, 13 May 2026 02:22:56 +0530 -Subject: [PATCH 2170/2179] drm/msm/adreno/a6xx: Mark cxpd device_link as - stateless - -Since the cxpd virtual device is a driverless device, it has no real -struct device_driver bound it the way a normal platform device does. So, -the managed lifecycle doesn't map cleanly onto it. Since the lifecycle of -this device_link is managed by the msm driver, pass DL_FLAG_STATELESS -together with the existing DL_FLAG_PM_RUNTIME flag. - -This fix is required to avoid the below splat when a driver is attached to -the GMU: - -[ 9.624509] WARNING: drivers/base/core.c:1383 at dvice_links_driver_bound+0x178/0x330, CPU#6: (udev-worker)/354e -[ 9.781167] pc : device_links_driver_bound+0x178/0x330 -[ 9.786456] lr : device_links_driver_bound+0x158/0x330 -[ 9.798622] sp : ffff8000827bb820 -[ 9.802042] x29: ffff8000827bb820 x28: ffff000808915800 x27: 0000000000000044 -[ 9.809573] x26: ffffb7caf3f983d0 x25: 0000000000000003 x24: ffffb7caf41645a0 -[ 9.816920] x23: ffffb7caf3f982d8 x22: ffff000801239cb8 x21: ffff000801239c10 -[ 9.816921] x20: ffff00080b3a8c00 x19: ffff000801239c98 x18: 00000000ffffffff -[ 9.816922] x17: 736d5b2073706f5f x16: ffffb7caf1eb5940 x15: ffff8001027bb3b7 -[ 9.816922] x14: 0000000000000026 x13: ffff00080084c110 x12: 0000000000000000 -[ 9.816923] x11: ffff0008004a5828 x10: ffff0008004a56d0 x9 : ffffb7caf2227870 -[ 9.816924] x8 : ffff0008004a56f8 x7 : 0000000000000001 x6 : 0000000000001000ocket. -[ 9.816925] x5 : 00000000001a7fbf x4 : ffff0008004a56e8 x3 : ffff000801238cc8 -[ 9.816926] x2 : ffffb7caf4164000 x1 : ffff000801239c10 x0 : 0000000000000000 -[ 9.816927] Call trace: -[ 9.816927] device_links_driver_bound+0x178/0x330 (P) -[ 9.893492] driver_bound+0x7c/0xd0 -[ 9.893493] really_probe+0x208/0x2a8 -[ 9.893495] __driver_probe_device+0x88/0x170 -[ 9.893496] driver_probe_device+0x44/0x178 -[ 9.909639] __driver_attach+0x9c/0x1b8 -[ 9.913592] bus_for_each_dev+0x7c/0xe8System Message Bus Socket. -[ 9.925839] driver_attach+0x2c/0x40 -[ 9.929733] bus_add_driver+0xec/0x218 -[ 9.933609] driver_register+0x68/0x138 -[ 9.937555] __platform_driver_register+0x2c/0x40 -[ 9.937556] adreno_gmu_register+0x2c/0x40 [msm] -[ 9.947141] adreno_register+0x3c/0x50 [msm] -[ 9.951544] msm_drm_register+0x50/0x78 [msm]for the API... -[ 9.962813] do_one_initcall+0x4c/0x3e0 -[ 9.966975] do_init_module+0x60/0x280 -[ 9.970849] load_module+0x1c70/0x1fa0 -[ 9.974708] init_module_from_file+0xdc/0x100 -[ 9.979188] __arm64_sys_finit_module+0x1c0/0x2e0 -[ 9.984026] invoke_syscall+0x5c/0x120 -[ 9.987882] el0_svc_common.constprop.0+0xd0/0xf8 -[ 9.992715] do_el0_svc+0x28/0x40 -[ 9.995243] qcom_q6v5_pas 6800000.remoteproc: Handover signaled, but it already happened -[ 9.996128] el0_svc+0x38/0x148 -[ 10.007672] el0t_64_sync_handler+0xa0/0xe8 -[ 10.011975] el0t_64_sync+0x198/0x1a0 - -Fixes: ead5d3e5eb37 ("drm/msm/a6xx: Vote for cx gdsc from gpu driver") -Signed-off-by: Akhil P Oommen -Reviewed-by: Dmitry Baryshkov ---- - drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -index a2f6918c4f7f..2b633cf8fbb7 100644 ---- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -@@ -2241,7 +2241,8 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - goto err_mmio; - } - -- if (!device_link_add(gmu->dev, gmu->cxpd, DL_FLAG_PM_RUNTIME)) { -+ if (!device_link_add(gmu->dev, gmu->cxpd, -+ DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS)) { - ret = -ENODEV; - goto detach_cxpd; - } -@@ -2427,7 +2428,8 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - goto err_mmio; - } - -- link = device_link_add(gmu->dev, gmu->cxpd, DL_FLAG_PM_RUNTIME); -+ link = device_link_add(gmu->dev, gmu->cxpd, -+ DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); - if (!link) { - ret = -ENODEV; - goto detach_cxpd; --- -2.56.0 - diff --git a/kernel/2171-drm-msm-Centralize-the-standalone-drm-device-check-f.patch b/kernel/2171-drm-msm-Centralize-the-standalone-drm-device-check-f.patch deleted file mode 100644 index 236dc13..0000000 --- a/kernel/2171-drm-msm-Centralize-the-standalone-drm-device-check-f.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Akhil P Oommen -Date: Wed, 13 May 2026 02:22:57 +0530 -Subject: [PATCH 2171/2179] drm/msm: Centralize the standalone drm device check - for GPU - -Replace msm_gpu_no_components() with msm_gpu_use_separate_drm_dev() and -move the platform-specific check for "amd,imageon" into the helper so the -policy is centralized and reused by both the core driver and adreno probe -path. No functional change intended. - -Signed-off-by: Akhil P Oommen ---- - drivers/gpu/drm/msm/adreno/adreno_device.c | 3 +-- - drivers/gpu/drm/msm/msm_drv.c | 11 +++++++---- - drivers/gpu/drm/msm/msm_drv.h | 2 +- - 3 files changed, 9 insertions(+), 7 deletions(-) - -diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c -index 05c77fe27e62..84bdc33898fc 100644 ---- a/drivers/gpu/drm/msm/adreno/adreno_device.c -+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c -@@ -271,8 +271,7 @@ static const struct component_ops a3xx_ops = { - - static int adreno_probe(struct platform_device *pdev) - { -- if (of_device_is_compatible(pdev->dev.of_node, "amd,imageon") || -- msm_gpu_no_components()) -+ if (msm_gpu_use_separate_drm_dev(pdev)) - return msm_gpu_probe(pdev, &a3xx_ops); - - return component_add(&pdev->dev, &a3xx_ops); -diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c -index fa46ab3063e6..8b740aba63be 100644 ---- a/drivers/gpu/drm/msm/msm_drv.c -+++ b/drivers/gpu/drm/msm/msm_drv.c -@@ -61,9 +61,12 @@ module_param(separate_gpu_kms, bool, 0400); - DECLARE_FAULT_ATTR(fail_gem_alloc); - DECLARE_FAULT_ATTR(fail_gem_iova); - --bool msm_gpu_no_components(void) -+bool msm_gpu_use_separate_drm_dev(struct platform_device *pdev) - { -- return separate_gpu_kms; -+ if (!pdev) -+ return separate_gpu_kms; -+ -+ return of_device_is_compatible(pdev->dev.of_node, "amd,imageon") || separate_gpu_kms; - } - - static int msm_drm_uninit(struct device *dev, const struct component_ops *gpu_ops) -@@ -1034,7 +1037,7 @@ static int add_gpu_components(struct device *dev, - static int msm_drm_bind(struct device *dev) - { - return msm_drm_init(dev, -- msm_gpu_no_components() ? -+ msm_gpu_use_separate_drm_dev(NULL) ? - &msm_kms_driver : - &msm_driver, - NULL); -@@ -1073,7 +1076,7 @@ int msm_drv_probe(struct device *master_dev, - return ret; - } - -- if (!msm_gpu_no_components()) { -+ if (!msm_gpu_use_separate_drm_dev(NULL)) { - ret = add_gpu_components(master_dev, &match); - if (ret) - return ret; -diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h -index 3d5679be488e..2657e85dd6b0 100644 ---- a/drivers/gpu/drm/msm/msm_drv.h -+++ b/drivers/gpu/drm/msm/msm_drv.h -@@ -543,6 +543,6 @@ void msm_kms_shutdown(struct platform_device *pdev); - - bool msm_disp_drv_should_bind(struct device *dev, bool dpu_driver); - --bool msm_gpu_no_components(void); -+bool msm_gpu_use_separate_drm_dev(struct platform_device *pdev); - - #endif /* __MSM_DRV_H__ */ --- -2.56.0 - diff --git a/kernel/2172-drm-msm-adreno-Fix-invalid-drvdata-typecast-in-adren.patch b/kernel/2172-drm-msm-adreno-Fix-invalid-drvdata-typecast-in-adren.patch deleted file mode 100644 index 4539fe3..0000000 --- a/kernel/2172-drm-msm-adreno-Fix-invalid-drvdata-typecast-in-adren.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Akhil P Oommen -Date: Wed, 13 May 2026 02:22:58 +0530 -Subject: [PATCH 2172/2179] drm/msm/adreno: Fix invalid drvdata typecast in - adreno_remove() - -adreno_remove() decides between component_del() and msm_gpu_remove() -based on platform_get_drvdata(pdev), interpreted as a struct -msm_drm_private *. That dereference is wrong because msm_gpu_init() -overwrites the GPU pdev's drvdata with adreno_smmu_priv pointer. - -Fix this by using msm_gpu_use_separate_drm_dev() instead of relying on -drvdata. - -Fixes: 643515a9cd09 ("drm/msm: rework binding of Imageon GPUs") -Signed-off-by: Akhil P Oommen -Reviewed-by: Dmitry Baryshkov ---- - drivers/gpu/drm/msm/adreno/adreno_device.c | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c -index 84bdc33898fc..f048972b8cbe 100644 ---- a/drivers/gpu/drm/msm/adreno/adreno_device.c -+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c -@@ -279,12 +279,10 @@ static int adreno_probe(struct platform_device *pdev) - - static void adreno_remove(struct platform_device *pdev) - { -- struct msm_drm_private *priv = platform_get_drvdata(pdev); -- -- if (priv->kms_init) -- component_del(&pdev->dev, &a3xx_ops); -- else -+ if (msm_gpu_use_separate_drm_dev(pdev)) - msm_gpu_remove(pdev, &a3xx_ops); -+ else -+ component_del(&pdev->dev, &a3xx_ops); - } - - static void adreno_shutdown(struct platform_device *pdev) --- -2.56.0 - diff --git a/kernel/2173-drm-msm-Always-use-component-model-for-standalone-GP.patch b/kernel/2173-drm-msm-Always-use-component-model-for-standalone-GP.patch deleted file mode 100644 index 0538661..0000000 --- a/kernel/2173-drm-msm-Always-use-component-model-for-standalone-GP.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Akhil P Oommen -Date: Wed, 13 May 2026 02:22:59 +0530 -Subject: [PATCH 2173/2179] drm/msm: Always use component model for standalone - GPU - -When separate_gpu_kms=1 (or the device is compatible with "amd,imageon"), -msm_gpu_no_components() evaluates true and adreno_probe() bypasses the -component framework by calling msm_gpu_probe() directly. In this case, -we skip creating components and directly bind the GPU. - -That shortcut makes it impossible to add a second sibling on the GPU -master without introducing ad-hoc plumbing. To prepare for adding the -GMU as a peer component on this master, turn the GPU pdev into both a -component master and the sole component of itself in this path. A follow -up patch will introduce GMU as a component device. - -Signed-off-by: Akhil P Oommen ---- - drivers/gpu/drm/msm/adreno/adreno_device.c | 20 +++++++++---- - drivers/gpu/drm/msm/msm_drv.c | 35 ++++++++++++++++++---- - drivers/gpu/drm/msm/msm_drv.h | 6 ++-- - 3 files changed, 45 insertions(+), 16 deletions(-) - -diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c -index f048972b8cbe..a0386a235275 100644 ---- a/drivers/gpu/drm/msm/adreno/adreno_device.c -+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c -@@ -271,18 +271,26 @@ static const struct component_ops a3xx_ops = { - - static int adreno_probe(struct platform_device *pdev) - { -- if (msm_gpu_use_separate_drm_dev(pdev)) -- return msm_gpu_probe(pdev, &a3xx_ops); -+ int ret; - -- return component_add(&pdev->dev, &a3xx_ops); -+ if (msm_gpu_use_separate_drm_dev(pdev)) { -+ ret = msm_gpu_probe(pdev); -+ if (ret) -+ return ret; -+ } -+ -+ ret = component_add(&pdev->dev, &a3xx_ops); -+ if (ret && msm_gpu_use_separate_drm_dev(pdev)) -+ msm_gpu_remove(pdev); -+ -+ return ret; - } - - static void adreno_remove(struct platform_device *pdev) - { -+ component_del(&pdev->dev, &a3xx_ops); - if (msm_gpu_use_separate_drm_dev(pdev)) -- msm_gpu_remove(pdev, &a3xx_ops); -- else -- component_del(&pdev->dev, &a3xx_ops); -+ msm_gpu_remove(pdev); - } - - static void adreno_shutdown(struct platform_device *pdev) -diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c -index 8b740aba63be..92681043c481 100644 ---- a/drivers/gpu/drm/msm/msm_drv.c -+++ b/drivers/gpu/drm/msm/msm_drv.c -@@ -1096,10 +1096,25 @@ int msm_drv_probe(struct device *master_dev, - return 0; - } - --int msm_gpu_probe(struct platform_device *pdev, -- const struct component_ops *ops) -+static int msm_gpu_drm_bind(struct device *dev) -+{ -+ return msm_drm_init(dev, &msm_gpu_driver, NULL); -+} -+ -+static void msm_gpu_drm_unbind(struct device *dev) -+{ -+ msm_drm_uninit(dev, NULL); -+} -+ -+static const struct component_master_ops msm_gpu_drm_ops = { -+ .bind = msm_gpu_drm_bind, -+ .unbind = msm_gpu_drm_unbind, -+}; -+ -+int msm_gpu_probe(struct platform_device *pdev) - { - struct msm_drm_private *priv; -+ struct component_match *match = NULL; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -@@ -1115,13 +1130,21 @@ int msm_gpu_probe(struct platform_device *pdev, - if (ret) - return ret; - -- return msm_drm_init(&pdev->dev, &msm_gpu_driver, ops); -+ /* -+ * The GPU pdev acts as both the component master and the sole -+ * component (added by adreno_probe()). Future patches add the -+ * GMU node as a second component on this same master. -+ */ -+ drm_of_component_match_add(&pdev->dev, &match, -+ component_compare_of, pdev->dev.of_node); -+ -+ return component_master_add_with_match(&pdev->dev, &msm_gpu_drm_ops, -+ match); - } - --void msm_gpu_remove(struct platform_device *pdev, -- const struct component_ops *ops) -+void msm_gpu_remove(struct platform_device *pdev) - { -- msm_drm_uninit(&pdev->dev, ops); -+ component_master_del(&pdev->dev, &msm_gpu_drm_ops); - } - - static int __init msm_drm_register(void) -diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h -index 2657e85dd6b0..b890729a60c9 100644 ---- a/drivers/gpu/drm/msm/msm_drv.h -+++ b/drivers/gpu/drm/msm/msm_drv.h -@@ -532,10 +532,8 @@ extern const struct component_master_ops msm_drm_ops; - int msm_kms_pm_prepare(struct device *dev); - void msm_kms_pm_complete(struct device *dev); - --int msm_gpu_probe(struct platform_device *pdev, -- const struct component_ops *ops); --void msm_gpu_remove(struct platform_device *pdev, -- const struct component_ops *ops); -+int msm_gpu_probe(struct platform_device *pdev); -+void msm_gpu_remove(struct platform_device *pdev); - int msm_drv_probe(struct device *dev, - int (*kms_init)(struct drm_device *dev), - struct msm_kms *kms); --- -2.56.0 - diff --git a/kernel/2174-drm-msm-Attach-a-driver-to-the-GMU.patch b/kernel/2174-drm-msm-Attach-a-driver-to-the-GMU.patch deleted file mode 100644 index 9cec0cc..0000000 --- a/kernel/2174-drm-msm-Attach-a-driver-to-the-GMU.patch +++ /dev/null @@ -1,318 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Akhil P Oommen -Date: Wed, 13 May 2026 02:23:00 +0530 -Subject: [PATCH 2174/2179] drm/msm: Attach a driver to the GMU - -With the introduction of sync_state in the genpd framework, any consumer -device of GCC and GPUCC which is not bound to a driver will result in -bootup warnings like below: - -[ 24.362666] gcc-kaanapali 100000.clock-controller: sync_state() pending due to 3d37000.gmu -[ 24.371210] gxclkctl-kaanapali 3d64000.clock-controller: sync_state() pending due to 3d37000.gmu -[ 24.380268] gpucc-kaanapali 3d90000.clock-controller: sync_state() pending due to 3d37000.gmu - -To silence these warnings and also to have a proper state in driver core, -attach a driver to the GMU and set it up as a component device for the drm -master device. - -[Brandon: ported to v7.2.8 for the Surface Pro 11: a6xx_gpu_init() there - declares node with __free(device_node), so the trailing of_node_put() - is dropped; the other a6xx_gpu.c/.h hunks only needed new context.] - -Signed-off-by: Akhil P Oommen -Reviewed-by: Dmitry Baryshkov -Signed-off-by: Brandon Williams ---- - drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 70 +++++++++++++++++++++- - drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 28 ++++----- - drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 3 - - drivers/gpu/drm/msm/adreno/adreno_device.c | 2 + - drivers/gpu/drm/msm/adreno/adreno_gpu.h | 3 +- - drivers/gpu/drm/msm/msm_drv.c | 17 +++--- - 6 files changed, 91 insertions(+), 32 deletions(-) - -diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -index 2b633cf8fbb7..e1d932d577e5 100644 ---- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -@@ -2108,7 +2108,7 @@ void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu, bool force_on) - pm_runtime_put(&gpu->pdev->dev); - } - --void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu) -+static void a6xx_gmu_destroy(struct a6xx_gpu *a6xx_gpu) - { - struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; - struct a6xx_gmu *gmu = &a6xx_gpu->gmu; -@@ -2188,7 +2188,7 @@ static void __iomem *a6xx_gmu_get_mmio(struct platform_device *pdev, resource_si - return ret; - } - --int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) -+static int a6xx_gmu_wrapper_pdev_bind(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - { - struct platform_device *pdev = of_find_device_by_node(node); - struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; -@@ -2258,6 +2258,8 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - goto err_mmio; - } - -+ mutex_init(&gmu->lock); -+ - gmu->initialized = true; - - return 0; -@@ -2275,7 +2277,7 @@ int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - return ret; - } - --int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) -+static int a6xx_gmu_pdev_bind(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - { - struct platform_device *pdev = of_find_device_by_node(node); - struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; -@@ -2465,6 +2467,7 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - /* Initialize RPMh */ - a6xx_gmu_rpmh_init(gmu); - -+ mutex_init(&gmu->lock); - gmu->initialized = true; - - return 0; -@@ -2494,3 +2497,64 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) - - return ret; - } -+ -+static int a6xx_gmu_bind(struct device *dev, struct device *master, void *data) -+{ -+ int (*bind)(struct a6xx_gpu *gpu, struct device_node *node) = of_device_get_match_data(dev); -+ struct a6xx_gpu *a6xx_gpu = dev_get_drvdata(dev); -+ -+ if (WARN_ON(!a6xx_gpu)) -+ return -ENODEV; -+ -+ return bind(a6xx_gpu, dev->of_node); -+} -+ -+static void a6xx_gmu_unbind(struct device *dev, struct device *master, void *data) -+{ -+ struct a6xx_gpu *a6xx_gpu = dev_get_drvdata(dev); -+ -+ a6xx_gmu_destroy(a6xx_gpu); -+ dev_set_drvdata(dev, NULL); -+} -+ -+static const struct component_ops a6xx_gmu_bind_ops = { -+ .bind = a6xx_gmu_bind, -+ .unbind = a6xx_gmu_unbind, -+}; -+ -+static int a6xx_gmu_probe(struct platform_device *pdev) -+{ -+ return component_add(&pdev->dev, &a6xx_gmu_bind_ops); -+} -+ -+static void a6xx_gmu_remove(struct platform_device *pdev) -+{ -+ component_del(&pdev->dev, &a6xx_gmu_bind_ops); -+} -+ -+static const struct of_device_id a6xx_gmu_dt_match[] = { -+ { .compatible = "qcom,adreno-gmu", .data = a6xx_gmu_pdev_bind }, -+ { .compatible = "qcom,adreno-rgmu", .data = a6xx_gmu_wrapper_pdev_bind }, -+ { .compatible = "qcom,adreno-gmu-wrapper", .data = a6xx_gmu_wrapper_pdev_bind }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, a6xx_gmu_dt_match); -+ -+static struct platform_driver adreno_gmu_driver = { -+ .probe = a6xx_gmu_probe, -+ .remove = a6xx_gmu_remove, -+ .driver = { -+ .name = "adreno_gmu", -+ .of_match_table = a6xx_gmu_dt_match, -+ }, -+}; -+ -+void __init adreno_gmu_register(void) -+{ -+ platform_driver_register(&adreno_gmu_driver); -+} -+ -+void __exit adreno_gmu_unregister(void) -+{ -+ platform_driver_unregister(&adreno_gmu_driver); -+} -diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c -index e293b4ca808a..adccfa186226 100644 ---- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c -+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c -@@ -11,6 +11,7 @@ - - #include - #include -+#include - #include - #include - -@@ -2315,8 +2316,6 @@ static void a6xx_destroy(struct msm_gpu *gpu) - - a6xx_llc_slices_destroy(a6xx_gpu); - -- a6xx_gmu_remove(a6xx_gpu); -- - adreno_gpu_cleanup(adreno_gpu); - - kfree(a6xx_gpu); -@@ -2664,6 +2663,7 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) - struct adreno_platform_config *config = pdev->dev.platform_data; - const struct adreno_info *info = config->info; - struct device_node *phandle; -+ struct platform_device *gmu_pdev; - struct a6xx_gpu *a6xx_gpu; - struct adreno_gpu *adreno_gpu; - struct msm_gpu *gpu; -@@ -2693,18 +2693,15 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) - gpu->num_perfcntr_groups = a8xx_num_perfcntr_groups; - } - -- mutex_init(&a6xx_gpu->gmu.lock); - spin_lock_init(&a6xx_gpu->aperture_lock); - - adreno_gpu->registers = NULL; - -- /* Check if there is a GMU phandle and set it up */ - struct device_node *node __free(device_node) = - of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0); -- /* FIXME: How do we gracefully handle this? */ -- BUG_ON(!node); -- -- adreno_gpu->gmu_is_wrapper = of_device_is_compatible(node, "qcom,adreno-gmu-wrapper"); -+ WARN_ON(!node); -+ adreno_gpu->gmu_is_wrapper = of_device_is_compatible(node, -+ "qcom,adreno-gmu-wrapper"); - - adreno_gpu->base.hw_apriv = - !!(info->quirks & ADRENO_QUIRK_HAS_HW_APRIV); -@@ -2757,15 +2754,6 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) - if (adreno_is_a618(adreno_gpu) || adreno_is_7c3(adreno_gpu)) - priv->gpu_clamp_to_idle = true; - -- if (adreno_has_gmu_wrapper(adreno_gpu) || adreno_has_rgmu(adreno_gpu)) -- ret = a6xx_gmu_wrapper_init(a6xx_gpu, node); -- else -- ret = a6xx_gmu_init(a6xx_gpu, node); -- if (ret) { -- a6xx_destroy(&(a6xx_gpu->base.base)); -- return ERR_PTR(ret); -- } -- - adreno_gpu->uche_trap_base = 0x1fffffffff000ull; - - msm_mmu_set_fault_handler(to_msm_vm(gpu->vm)->mmu, gpu, -@@ -2781,6 +2769,12 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) - /* Set up the preemption specific bits and pieces for each ringbuffer */ - a6xx_preempt_init(gpu); - -+ gmu_pdev = of_find_device_by_node(node); -+ if (gmu_pdev) { -+ platform_set_drvdata(gmu_pdev, a6xx_gpu); -+ put_device(&gmu_pdev->dev); -+ } -+ - return gpu; - } - -diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h -index b50c57f427b4..cb53de26a79b 100644 ---- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h -+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h -@@ -278,9 +278,6 @@ bool a6xx_gmu_isidle(struct a6xx_gmu *gmu); - int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state); - void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state); - --int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node); --int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node); --void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu); - void a6xx_gmu_sysprof_setup(struct msm_gpu *gpu, bool force_on); - - void a6xx_preempt_init(struct msm_gpu *gpu); -diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c -index a0386a235275..9c1816d67a1c 100644 ---- a/drivers/gpu/drm/msm/adreno/adreno_device.c -+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c -@@ -427,6 +427,7 @@ void __init adreno_register(void) - return; - - platform_driver_register(&adreno_driver); -+ adreno_gmu_register(); - } - - void __exit adreno_unregister(void) -@@ -434,5 +435,6 @@ void __exit adreno_unregister(void) - if (skip_gpu) - return; - -+ adreno_gmu_unregister(); - platform_driver_unregister(&adreno_driver); - } -diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h -index 1f201322cb6e..d01f163b0e4e 100644 ---- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h -+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h -@@ -642,7 +642,8 @@ int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state); - int adreno_gpu_state_put(struct msm_gpu_state *state); - void adreno_show_object(struct drm_printer *p, void **ptr, int len, - bool *encoded); -- -+void adreno_gmu_register(void); -+void adreno_gmu_unregister(void); - /* - * Common helper function to initialize the default address space for arm-smmu - * attached targets -diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c -index 92681043c481..65df7f0570e9 100644 ---- a/drivers/gpu/drm/msm/msm_drv.c -+++ b/drivers/gpu/drm/msm/msm_drv.c -@@ -1020,7 +1020,7 @@ static const struct of_device_id msm_gpu_match[] = { - static int add_gpu_components(struct device *dev, - struct component_match **matchptr) - { -- struct device_node *np; -+ struct device_node *np, *gmu_np; - - np = of_find_matching_node(NULL, msm_gpu_match); - if (!np) -@@ -1029,6 +1029,11 @@ static int add_gpu_components(struct device *dev, - if (of_device_is_available(np) && adreno_has_gpu(np)) - drm_of_component_match_add(dev, matchptr, component_compare_of, np); - -+ gmu_np = of_parse_phandle(np, "qcom,gmu", 0); -+ if (of_device_is_available(gmu_np)) -+ drm_of_component_match_add(dev, matchptr, component_compare_of, gmu_np); -+ -+ of_node_put(gmu_np); - of_node_put(np); - - return 0; -@@ -1130,13 +1135,9 @@ int msm_gpu_probe(struct platform_device *pdev) - if (ret) - return ret; - -- /* -- * The GPU pdev acts as both the component master and the sole -- * component (added by adreno_probe()). Future patches add the -- * GMU node as a second component on this same master. -- */ -- drm_of_component_match_add(&pdev->dev, &match, -- component_compare_of, pdev->dev.of_node); -+ ret = add_gpu_components(&pdev->dev, &match); -+ if (ret) -+ return ret; - - return component_master_add_with_match(&pdev->dev, &msm_gpu_drm_ops, - match); --- -2.56.0 - diff --git a/kernel/2175-serial-qcom-geni-add-force-suspend-resume-to-system-.patch b/kernel/2175-serial-qcom-geni-add-force-suspend-resume-to-system-.patch deleted file mode 100644 index a3a7449..0000000 --- a/kernel/2175-serial-qcom-geni-add-force-suspend-resume-to-system-.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Praveen Talari -Date: Thu, 2 Jul 2026 17:11:50 +0530 -Subject: [PATCH 2175/2179] serial: qcom-geni: add force suspend/resume to - system sleep callbacks - -During system sleep the hardware resources (clocks, interconnect) are -not gated because the runtime-suspend callback is never invoked from -the system sleep path. This prevents the platform from reaching its -lowest idle state. - -The system sleep callbacks qcom_geni_serial_suspend() and -qcom_geni_serial_resume() rely solely on uart_suspend_port() / -uart_resume_port() to manage power. uart_suspend_port() drives the -UART PM state machine to UART_PM_STATE_OFF, which in turn calls -pm_runtime_put_sync() and eventually the runtime-suspend callback. -However, if the runtime-PM usage count is still elevated at the time -of system sleep (e.g. the port is held active by an open file -descriptor), the runtime-suspend callback is never invoked and the -hardware resources (clocks, interconnect) remain enabled across -suspend, preventing the platform from reaching its lowest idle state. - -Fix this by calling pm_runtime_force_suspend() at the end of -qcom_geni_serial_suspend() so that the runtime-suspend callback is -always executed regardless of the usage count, and by calling -pm_runtime_force_resume() at the start of qcom_geni_serial_resume() -to restore those resources before uart_resume_port() re-opens the -port. - -Signed-off-by: Praveen Talari -Link: https://patch.msgid.link/20260702-add_force_suspend_resume_to_system_sleep_callbacks-v2-1-b79e254a7015@oss.qualcomm.com -Signed-off-by: Greg Kroah-Hartman -(cherry picked from commit d0cd9c8d0fd59bc7d140f3d60cf02e1d80376dab) ---- - drivers/tty/serial/qcom_geni_serial.c | 19 ++++++++++++++++++- - 1 file changed, 18 insertions(+), 1 deletion(-) - -diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c -index 1fc869ad84bd..5758895d24fe 100644 ---- a/drivers/tty/serial/qcom_geni_serial.c -+++ b/drivers/tty/serial/qcom_geni_serial.c -@@ -1983,6 +1983,7 @@ static int qcom_geni_serial_suspend(struct device *dev) - struct qcom_geni_serial_port *port = dev_get_drvdata(dev); - struct uart_port *uport = &port->uport; - struct qcom_geni_private_data *private_data = uport->private_data; -+ int ret; - - /* - * This is done so we can hit the lowest possible state in suspend -@@ -1992,7 +1993,19 @@ static int qcom_geni_serial_suspend(struct device *dev) - geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ACTIVE_ONLY); - geni_icc_set_bw(&port->se); - } -- return uart_suspend_port(private_data->drv, uport); -+ -+ ret = uart_suspend_port(private_data->drv, uport); -+ if (ret) -+ return ret; -+ -+ /* -+ * When no_console_suspend is set the console must remain active -+ * across system sleep, so skip the force suspend path. -+ */ -+ if (!console_suspend_enabled && uart_console(uport)) -+ return 0; -+ -+ return pm_runtime_force_suspend(dev); - } - - static int qcom_geni_serial_resume(struct device *dev) -@@ -2002,6 +2015,10 @@ static int qcom_geni_serial_resume(struct device *dev) - struct uart_port *uport = &port->uport; - struct qcom_geni_private_data *private_data = uport->private_data; - -+ ret = pm_runtime_force_resume(dev); -+ if (ret) -+ return ret; -+ - ret = uart_resume_port(private_data->drv, uport); - if (uart_console(uport)) { - geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS); --- -2.56.0 - diff --git a/kernel/2176-soc-qcom-add-ADSP-power-limits-Modern-Standby-notifi.patch b/kernel/2176-soc-qcom-add-ADSP-power-limits-Modern-Standby-notifi.patch deleted file mode 100644 index 7bcccd2..0000000 --- a/kernel/2176-soc-qcom-add-ADSP-power-limits-Modern-Standby-notifi.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Kirill <69245353+justririll@users.noreply.github.com> -Date: Mon, 19 Oct 2026 10:08:30 -0400 -Subject: [PATCH 2176/2179] soc: qcom: add ADSP power-limits Modern Standby - notification - -Windows' PEP (qcpep8380.sys) sends a MODERN_STANDBY_STATE message on the -ADSP's APPS_ADSP_PWR_LMTS_GLINK_PORT channel when the platform enters -(state 1) and leaves (state 0) Modern Standby. On entry the ADSP stops its -power-limits timer; without the message it wakes about 100 times per -second while the system is suspended, and each wake pulls the SoC out of -CX collapse. - -Send the same messages from the system suspend and resume callbacks of -the rpmsg device; the glink edge is its parent, so it is still up there. - -On the Surface Pro 11 (X1E80100) in deep suspend this takes CX/AOSS/DDR -residency from about 92% to 99.9%: 6 CX exits in 15 minutes instead of -about ten per second. - -[Brandon: taken unchanged from github.com/justririll/x1e-sleep - modules/adsp-pwr-lmts (commit 0f3f55b, GPL-2.0) and wired into Kconfig.] - -Link: https://github.com/justririll/x1e-sleep -Signed-off-by: Brandon Williams ---- - drivers/soc/qcom/Kconfig | 11 ++++ - drivers/soc/qcom/Makefile | 1 + - drivers/soc/qcom/qcom_adsp_pwr_lmts.c | 90 +++++++++++++++++++++++++++ - 3 files changed, 102 insertions(+) - create mode 100644 drivers/soc/qcom/qcom_adsp_pwr_lmts.c - -diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig -index 2caadbbcf830..4a18522ecd34 100644 ---- a/drivers/soc/qcom/Kconfig -+++ b/drivers/soc/qcom/Kconfig -@@ -4,6 +4,17 @@ - # - menu "Qualcomm SoC drivers" - -+config QCOM_ADSP_PWR_LMTS -+ tristate "Qualcomm ADSP power-limits Modern Standby notification" -+ depends on ARCH_QCOM || COMPILE_TEST -+ depends on RPMSG -+ help -+ Tell the audio DSP when the system enters and leaves sleep, the way -+ Windows' power engine plug-in does, over the ADSP's -+ APPS_ADSP_PWR_LMTS_GLINK_PORT channel. Without it the ADSP keeps its -+ power-limits timer running and wakes about 100 times per second while -+ the system is suspended. -+ - config QCOM_AOSS_QMP - tristate "Qualcomm AOSS Driver" - depends on ARCH_QCOM || COMPILE_TEST -diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile -index b7f1d2a57367..3be3445e73f4 100644 ---- a/drivers/soc/qcom/Makefile -+++ b/drivers/soc/qcom/Makefile -@@ -1,6 +1,7 @@ - # SPDX-License-Identifier: GPL-2.0 - CFLAGS_rpmh-rsc.o := -I$(src) - CFLAGS_qcom_aoss.o := -I$(src) -+obj-$(CONFIG_QCOM_ADSP_PWR_LMTS) += qcom_adsp_pwr_lmts.o - obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o - obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o - obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o -diff --git a/drivers/soc/qcom/qcom_adsp_pwr_lmts.c b/drivers/soc/qcom/qcom_adsp_pwr_lmts.c -new file mode 100644 -index 000000000000..5b09a9ad65dd ---- /dev/null -+++ b/drivers/soc/qcom/qcom_adsp_pwr_lmts.c -@@ -0,0 +1,90 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Tell the ADSP when the system enters and leaves sleep, like Windows does. -+ * -+ * Windows' PEP (qcpep8380.sys) sends a MODERN_STANDBY_STATE message on the -+ * APPS_ADSP_PWR_LMTS_GLINK_PORT channel when the platform enters Modern -+ * Standby (state 1) and when it leaves it (state 0). On entry the ADSP stops -+ * its power-limits (PLD) timer, which otherwise wakes it ~100 times per -+ * second; with the message it wakes ~2 times per second during sleep. -+ * -+ * Send the same messages from the system suspend/resume callbacks of the -+ * rpmsg device. The glink edge is its parent, so it is still up here. -+ */ -+#include -+#include -+#include -+#include -+ -+#define PWR_LMTS_MODERN_STANDBY_STATE 1 -+ -+struct pwr_lmts_msg { -+ __le32 size; -+ __le32 type; -+ __le32 count; -+ __le32 state; -+ __le32 reserved[2]; -+} __packed; -+ -+static int pwr_lmts_send_state(struct rpmsg_device *rpdev, u32 state) -+{ -+ struct pwr_lmts_msg msg = { -+ .size = cpu_to_le32(sizeof(msg)), -+ .type = cpu_to_le32(PWR_LMTS_MODERN_STANDBY_STATE), -+ .count = cpu_to_le32(1), -+ .state = cpu_to_le32(state), -+ }; -+ int ret; -+ -+ ret = rpmsg_send(rpdev->ept, &msg, sizeof(msg)); -+ if (ret) -+ dev_warn(&rpdev->dev, "failed to send standby state %u: %d\n", state, ret); -+ return ret; -+} -+ -+static int pwr_lmts_callback(struct rpmsg_device *rpdev, void *data, int len, -+ void *priv, u32 addr) -+{ -+ dev_dbg(&rpdev->dev, "rx %d bytes\n", len); -+ return 0; -+} -+ -+static int pwr_lmts_probe(struct rpmsg_device *rpdev) -+{ -+ return 0; -+} -+ -+static int pwr_lmts_suspend(struct device *dev) -+{ -+ /* Do not block suspend if the ADSP does not take the message */ -+ pwr_lmts_send_state(container_of(dev, struct rpmsg_device, dev), 1); -+ return 0; -+} -+ -+static int pwr_lmts_resume(struct device *dev) -+{ -+ pwr_lmts_send_state(container_of(dev, struct rpmsg_device, dev), 0); -+ return 0; -+} -+ -+static DEFINE_SIMPLE_DEV_PM_OPS(pwr_lmts_pm_ops, pwr_lmts_suspend, pwr_lmts_resume); -+ -+static const struct rpmsg_device_id pwr_lmts_id_table[] = { -+ { .name = "APPS_ADSP_PWR_LMTS_GLINK_PORT" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(rpmsg, pwr_lmts_id_table); -+ -+static struct rpmsg_driver pwr_lmts_driver = { -+ .drv = { -+ .name = "qcom_adsp_pwr_lmts", -+ .pm = pm_sleep_ptr(&pwr_lmts_pm_ops), -+ }, -+ .id_table = pwr_lmts_id_table, -+ .probe = pwr_lmts_probe, -+ .callback = pwr_lmts_callback, -+}; -+module_rpmsg_driver(pwr_lmts_driver); -+ -+MODULE_DESCRIPTION("Qualcomm ADSP power-limits Modern Standby notification"); -+MODULE_LICENSE("GPL"); --- -2.56.0 - diff --git a/kernel/2177-PCI-allow-D3-for-hotplug-capable-root-ports-on-Qualc.patch b/kernel/2177-PCI-allow-D3-for-hotplug-capable-root-ports-on-Qualc.patch deleted file mode 100644 index 35b8dcf..0000000 --- a/kernel/2177-PCI-allow-D3-for-hotplug-capable-root-ports-on-Qualc.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Mon, 19 Oct 2026 12:56:22 -0400 -Subject: [PATCH 2177/2179] PCI: allow D3 for hotplug-capable root ports on - Qualcomm PCIe - -7.2.8 never lets a natively hotplug-capable root port into D3. The -Snapdragon X1 root ports report hotplug, so they stay in D0 through -system suspend, pci_host_common_d3cold_possible() fails, pcie-qcom keeps -a 1 kBps PCIe-to-DDR vote, and the SoC never reaches DDR sleep or CX -collapse. - -Mainline 7.3 allows D3 for these ports on every non-x86 platform -(d4c79b63d82d, "PCI: Allow D3 for native hotplug-capable Root Ports on -non-x86 platforms", Manivannan Sadhasivam). This package also serves -ACPI arm64 machines whose root ports were never runtime-suspended on -7.2.8, so this backport limits the change to root ports on Qualcomm -PCIe controllers. Drop it when moving to 7.3. - -On a Surface Pro 11 (X1E80100) in deep suspend: CX, AOSS and DDR asleep -99.9% of a one-hour suspend, about 0.23 W, instead of never. - -Link: https://patch.msgid.link/20260729165005.896725-1-manivannan.sadhasivam@oss.qualcomm.com -Signed-off-by: Brandon Williams -Assisted-by: Claude:claude-opus-5-5 ---- - drivers/pci/pci.c | 17 +++++++++++++++-- - 1 file changed, 15 insertions(+), 2 deletions(-) - -diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c -index 350bae907ebf..d9a85df81aec 100644 ---- a/drivers/pci/pci.c -+++ b/drivers/pci/pci.c -@@ -2974,6 +2974,18 @@ static const struct dmi_system_id bridge_d3_blacklist[] = { - { } - }; - -+/* -+ * Root ports on Qualcomm (Snapdragon) PCIe controllers. Mainline allows D3 -+ * for every non-x86 hotplug-capable root port from 7.3 (d4c79b63d82d); this -+ * 7.2.8 backport limits it to these so other arm64 hosts keep 7.2.8 behaviour. -+ */ -+static bool pci_bridge_on_qcom_pcie(struct pci_dev *bridge) -+{ -+ struct device *ctrl = pci_find_host_bridge(bridge->bus)->dev.parent; -+ -+ return ctrl && ctrl->driver && !strcmp(ctrl->driver->name, "qcom-pcie"); -+} -+ - /** - * pci_bridge_d3_possible - Is it possible to put the bridge into D3 - * @bridge: Bridge to check -@@ -3022,9 +3034,10 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge) - /* - * Hotplug ports handled natively by the OS were not validated - * by vendors for runtime D3 at least until 2018 because there -- * was no OS support. -+ * was no OS support. Qualcomm's root ports report hotplug, and -+ * keeping them in D0 keeps a DDR vote through system suspend. - */ -- if (bridge->is_pciehp) -+ if (bridge->is_pciehp && !pci_bridge_on_qcom_pcie(bridge)) - return false; - - if (dmi_check_system(bridge_d3_blacklist)) --- -2.56.0 - diff --git a/kernel/2178-drm-msm-keep-the-GMU-optional-and-its-lock-initialis.patch b/kernel/2178-drm-msm-keep-the-GMU-optional-and-its-lock-initialis.patch deleted file mode 100644 index a69414e..0000000 --- a/kernel/2178-drm-msm-keep-the-GMU-optional-and-its-lock-initialis.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Mon, 19 Oct 2026 12:50:00 -0400 -Subject: [PATCH 2178/2179] drm/msm: keep the GMU optional and its lock - initialised early - -Fixes for the "Attach a driver to the GMU" series as carried here: - -- add_gpu_components() added the GMU to the match list even when the GPU - itself was not added (GPU disabled, unknown chip id, msm.skip_gpu=1), so - the display master waited for a GMU that could never bind. Add it only - together with its GPU. -- msm_gpu_probe() handed an empty match list to the component framework - when no GPU was usable. Return -ENXIO instead. -- The GPU code takes gmu.lock (devfreq, hw_init, PM) before the GMU binds. - Initialise it in a6xx_gpu_init() again, as before the series, instead of - in the GMU bind callbacks, which could also re-initialise it while held. - -Signed-off-by: Brandon Williams -Assisted-by: Claude:claude-opus-5-5 ---- - drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 3 --- - drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 1 + - drivers/gpu/drm/msm/msm_drv.c | 16 +++++++++++----- - 3 files changed, 12 insertions(+), 8 deletions(-) - -diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -index e1d932d577e5..71c236d1dff0 100644 ---- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c -@@ -2258,8 +2258,6 @@ static int a6xx_gmu_wrapper_pdev_bind(struct a6xx_gpu *a6xx_gpu, struct device_n - goto err_mmio; - } - -- mutex_init(&gmu->lock); -- - gmu->initialized = true; - - return 0; -@@ -2467,7 +2465,6 @@ static int a6xx_gmu_pdev_bind(struct a6xx_gpu *a6xx_gpu, struct device_node *nod - /* Initialize RPMh */ - a6xx_gmu_rpmh_init(gmu); - -- mutex_init(&gmu->lock); - gmu->initialized = true; - - return 0; -diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c -index adccfa186226..576268637713 100644 ---- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c -+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c -@@ -2693,6 +2693,7 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) - gpu->num_perfcntr_groups = a8xx_num_perfcntr_groups; - } - -+ mutex_init(&a6xx_gpu->gmu.lock); - spin_lock_init(&a6xx_gpu->aperture_lock); - - adreno_gpu->registers = NULL; -diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c -index 65df7f0570e9..fd992f42029e 100644 ---- a/drivers/gpu/drm/msm/msm_drv.c -+++ b/drivers/gpu/drm/msm/msm_drv.c -@@ -1026,14 +1026,16 @@ static int add_gpu_components(struct device *dev, - if (!np) - return 0; - -- if (of_device_is_available(np) && adreno_has_gpu(np)) -+ if (of_device_is_available(np) && adreno_has_gpu(np)) { - drm_of_component_match_add(dev, matchptr, component_compare_of, np); - -- gmu_np = of_parse_phandle(np, "qcom,gmu", 0); -- if (of_device_is_available(gmu_np)) -- drm_of_component_match_add(dev, matchptr, component_compare_of, gmu_np); -+ /* The GMU binds only alongside its GPU; never wait for it alone. */ -+ gmu_np = of_parse_phandle(np, "qcom,gmu", 0); -+ if (of_device_is_available(gmu_np)) -+ drm_of_component_match_add(dev, matchptr, component_compare_of, gmu_np); -+ of_node_put(gmu_np); -+ } - -- of_node_put(gmu_np); - of_node_put(np); - - return 0; -@@ -1139,6 +1141,10 @@ int msm_gpu_probe(struct platform_device *pdev) - if (ret) - return ret; - -+ /* No usable GPU: nothing to bind. */ -+ if (!match) -+ return -ENXIO; -+ - return component_master_add_with_match(&pdev->dev, &msm_gpu_drm_ops, - match); - } --- -2.56.0 - diff --git a/kernel/2179-soc-qcom-adsp-pwr-lmts-drop-an-unused-include-and-sa.patch b/kernel/2179-soc-qcom-adsp-pwr-lmts-drop-an-unused-include-and-sa.patch deleted file mode 100644 index 484662f..0000000 --- a/kernel/2179-soc-qcom-adsp-pwr-lmts-drop-an-unused-include-and-sa.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Brandon Williams -Date: Mon, 19 Oct 2026 14:29:26 -0400 -Subject: [PATCH 2179/2179] soc: qcom: adsp-pwr-lmts: drop an unused include - and say why the send blocks - -rpmsg.h provides rpmsg_device_id, so the mod_devicetable.h include is -unused. - -The standby message has to be sent with the blocking rpmsg_send(). The -ADSP queues no intent on this channel in advance, so glink requests one -and waits for it. With rpmsg_trysend() the suspend-time send failed with --EBUSY on a Surface Pro 11, and the ADSP kept waking about 45 times a -second through suspend. - -Signed-off-by: Brandon Williams -Assisted-by: Claude:claude-opus-5-5 ---- - drivers/soc/qcom/qcom_adsp_pwr_lmts.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/drivers/soc/qcom/qcom_adsp_pwr_lmts.c b/drivers/soc/qcom/qcom_adsp_pwr_lmts.c -index 5b09a9ad65dd..5564e74134af 100644 ---- a/drivers/soc/qcom/qcom_adsp_pwr_lmts.c -+++ b/drivers/soc/qcom/qcom_adsp_pwr_lmts.c -@@ -12,7 +12,6 @@ - * rpmsg device. The glink edge is its parent, so it is still up here. - */ - #include --#include - #include - #include - -@@ -36,6 +35,11 @@ static int pwr_lmts_send_state(struct rpmsg_device *rpdev, u32 state) - }; - int ret; - -+ /* -+ * The ADSP queues no intent on this channel in advance, so glink has -+ * to request one and wait for it (up to 10 s). rpmsg_trysend() fails -+ * with -EBUSY here, and the message never reaches the ADSP. -+ */ - ret = rpmsg_send(rpdev->ept, &msg, sizeof(msg)); - if (ret) - dev_warn(&rpdev->dev, "failed to send standby state %u: %d\n", state, ret); --- -2.56.0 - diff --git a/kernel/2200-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-pm8010-camera-PMIC.patch b/kernel/2200-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-pm8010-camera-PMIC.patch deleted file mode 100644 index abb87a7..0000000 --- a/kernel/2200-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-pm8010-camera-PMIC.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bryan O'Donoghue -Date: Thu, 17 Sep 2026 14:20:34 +0100 -Subject: [PATCH] arm64: dts: qcom: x1e80100-lenovo-yoga-slim7x: Add pm8010 - camera PMIC with voltage levels for IR and RGB camera - -Add voltage regulators-8 for Camera on slim7x including: - -- vreg_l1m_1p2 -- vreg_l3m_1p8 - -Tested-by: Daniel J Blueman # Lenovo Slim 7x X1E80100 -Signed-off-by: Bryan O'Donoghue -Link: https://lore.kernel.org/all/20260917-x1e-camss-csi2-phy-dtsi-v7-9-1a63eb35838b@linaro.org/ ---- - .../dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 51 +++++++++++++++++++ - 1 file changed, 51 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -index 9eb2dfd..f4064e0 100644 ---- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -+++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -@@ -795,6 +795,57 @@ vreg_l3j_0p8: ldo3 { - regulator-initial-mode = ; - }; - }; -+ -+ regulators-8 { -+ compatible = "qcom,pm8010-rpmh-regulators"; -+ qcom,pmic-id = "m"; -+ -+ vdd-l1-l2-supply = <&vreg_s5j_1p2>; -+ vdd-l3-l4-supply = <&vreg_s4c_1p8>; -+ vdd-l7-supply = <&vreg_bob1>; -+ -+ vreg_l1m_1p2: ldo1 { -+ regulator-name = "vreg_l1m_1p2"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1260000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l2m_1p2: ldo2 { -+ regulator-name = "vreg_l2m_1p2"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1260000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l3m_1p8: ldo3 { -+ regulator-name = "vreg_l3m_1p8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1900000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l4m_1p8: ldo4 { -+ regulator-name = "vreg_l4m_1p8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1900000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l5m_2p8: ldo5 { -+ regulator-name = "vreg_l5m_2p8"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <3072000>; -+ regulator-initial-mode = ; -+ }; -+ -+ vreg_l7m_2p8: ldo7 { -+ regulator-name = "vreg_l7m_2p8"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <3072000>; -+ regulator-initial-mode = ; -+ }; -+ }; - }; - - &gpu { diff --git a/kernel/2201-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-l7b_2p8-regulator.patch b/kernel/2201-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-l7b_2p8-regulator.patch deleted file mode 100644 index 0e3270b..0000000 --- a/kernel/2201-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-l7b_2p8-regulator.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bryan O'Donoghue -Date: Thu, 17 Sep 2026 14:20:35 +0100 -Subject: [PATCH] arm64: dts: qcom: x1e80100-lenovo-yoga-slim7x: Add - l7b_2p8 voltage regulator for RGB camera - -Some sleuthing work by Aleksandrs Vinarskis in the bowels of the ACPI -tables for this part shows we need l7b_2p8 for the avdd supply. - -Suggested-by: Aleksandrs Vinarskis -Tested-by: Daniel J Blueman # Lenovo Slim 7x X1E80100 -Signed-off-by: Bryan O'Donoghue -Link: https://lore.kernel.org/all/20260917-x1e-camss-csi2-phy-dtsi-v7-10-1a63eb35838b@linaro.org/ ---- - arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -index f4064e0..79e1c47 100644 ---- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -+++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -@@ -552,6 +552,13 @@ vreg_l2b_3p0: ldo2 { - regulator-initial-mode = ; - }; - -+ vreg_l7b_2p8: ldo7 { -+ regulator-name = "vreg_l7b_2p8"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ regulator-initial-mode = ; -+ }; -+ - vreg_l8b_3p0: ldo8 { - regulator-name = "vreg_l8b_3p0"; - regulator-min-microvolt = <3072000>; diff --git a/kernel/2202-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-ov02c10-RGB-sensor.patch b/kernel/2202-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-ov02c10-RGB-sensor.patch deleted file mode 100644 index becb568..0000000 --- a/kernel/2202-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-ov02c10-RGB-sensor.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Bryan O'Donoghue -Date: Thu, 17 Sep 2026 14:20:36 +0100 -Subject: [PATCH] arm64: dts: qcom: x1e80100-lenovo-yoga-slim7x: Add - ov02c10 RGB sensor on CSIPHY4 - -Add in the RGB sensor on CSIPHY4. - -Signed-off-by: Bryan O'Donoghue -Link: https://lore.kernel.org/all/20260917-x1e-camss-csi2-phy-dtsi-v7-11-1a63eb35838b@linaro.org/ -[Birk: connect the sensor to port@3 of the CAMSS node, whose built-in - CSIPHY driver 7.2.8 has, instead of the csiphy4 node from v7, which - needs the separate CSI2 PHY driver; write the orientation as a number, - since 7.2.8 has no dt-bindings/media/video-interface-devices.h] -Signed-off-by: Birk Skyum ---- - .../dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 66 +++++++++++++++++++ - 1 file changed, 66 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -index 79e1c47..659c7f9 100644 ---- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -+++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -@@ -863,6 +863,56 @@ &gpu_zap_shader { - firmware-name = "qcom/x1e80100/LENOVO/83ED/qcdxkmsuc8380.mbn"; - }; - -+&camss { -+ vdd-csiphy-0p8-supply = <&vreg_l2c_0p8>; -+ vdd-csiphy-1p2-supply = <&vreg_l1c_1p2>; -+ -+ status = "okay"; -+ -+ ports { -+ port@3 { -+ camss_csiphy4_inep: endpoint { -+ clock-lanes = <7>; -+ data-lanes = <0 1>; -+ remote-endpoint = <&ov02c10_ep>; -+ }; -+ }; -+ }; -+}; -+ -+&cci1 { -+ status = "okay"; -+}; -+ -+&cci1_i2c1 { -+ camera@36 { -+ compatible = "ovti,ov02c10"; -+ reg = <0x36>; -+ -+ reset-gpios = <&tlmm 237 GPIO_ACTIVE_LOW>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&cam_rgb_default>; -+ -+ clocks = <&camcc CAM_CC_MCLK4_CLK>; -+ assigned-clocks = <&camcc CAM_CC_MCLK4_CLK>; -+ assigned-clock-rates = <19200000>; -+ -+ orientation = <0>; /* Front facing */ -+ -+ avdd-supply = <&vreg_l7b_2p8>; -+ dvdd-supply = <&vreg_l1m_1p2>; -+ dovdd-supply = <&vreg_l3m_1p8>; -+ -+ port { -+ ov02c10_ep: endpoint { -+ data-lanes = <1 2>; -+ link-frequencies = /bits/ 64 <400000000>; -+ remote-endpoint = <&camss_csiphy4_inep>; -+ }; -+ }; -+ }; -+}; -+ - &i2c0 { - clock-frequency = <400000>; - -@@ -1410,6 +1460,22 @@ &tlmm { - <44 4>, /* SPI (TPM) */ - <238 1>; /* UFS Reset */ - -+ cam_rgb_default: cam-rgb-default-state { -+ mclk-pins { -+ pins = "gpio100"; -+ function = "cam_aon"; -+ drive-strength = <16>; -+ bias-disable; -+ }; -+ -+ reset-n-pins { -+ pins = "gpio237"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-disable; -+ }; -+ }; -+ - edp_reg_en: edp-reg-en-state { - pins = "gpio70"; - function = "gpio"; diff --git a/kernel/2203-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-enable-camera-privacy-indicator.patch b/kernel/2203-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-enable-camera-privacy-indicator.patch deleted file mode 100644 index f33a765..0000000 --- a/kernel/2203-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-enable-camera-privacy-indicator.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aleksandrs Vinarskis -Date: Wed, 31 Dec 2025 15:49:18 +0100 -Subject: [PATCH] arm64: dts: qcom: x1e80100-lenovo-yoga-slim7x: enable - camera privacy indicator - -Leverage newly introduced 'leds' and 'led-names' properties to pass -indicator's phandle and function to v4l2 subnode. The latter supports -privacy led since couple of years ago under 'privacy-led' designation. -Unlike initially proposed trigger-source based approach, this solution -cannot be easily bypassed from userspace, thus reducing privacy -concerns. - -Signed-off-by: Aleksandrs Vinarskis -Link: https://bugs.launchpad.net/bugs/2138706 -[Birk: rebased onto the sensor node from Bryan O'Donoghue's v7 series] -Signed-off-by: Birk Skyum ---- - .../dts/qcom/x1e80100-lenovo-yoga-slim7x.dts | 26 +++++++++++++++++++ - 1 file changed, 26 insertions(+) - -diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -index 659c7f9..19d9409 100644 ---- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -+++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts -@@ -7,6 +7,7 @@ - - #include - #include -+#include - #include - - #include "hamoa.dtsi" -@@ -40,6 +41,21 @@ switch-lid { - }; - }; - -+ leds { -+ compatible = "gpio-leds"; -+ -+ pinctrl-0 = <&cam_indicator_en>; -+ pinctrl-names = "default"; -+ -+ privacy_led: privacy-led { -+ function = LED_FUNCTION_INDICATOR; -+ color = ; -+ gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>; -+ default-state = "off"; -+ panic-indicator; -+ }; -+ }; -+ - pmic-glink { - compatible = "qcom,x1e80100-pmic-glink", - "qcom,sm8550-pmic-glink", -@@ -893,6 +909,9 @@ camera@36 { - pinctrl-names = "default"; - pinctrl-0 = <&cam_rgb_default>; - -+ leds = <&privacy_led>; -+ led-names = "privacy"; -+ - clocks = <&camcc CAM_CC_MCLK4_CLK>; - assigned-clocks = <&camcc CAM_CC_MCLK4_CLK>; - assigned-clock-rates = <19200000>; -@@ -1476,6 +1495,13 @@ reset-n-pins { - }; - }; - -+ cam_indicator_en: cam-indicator-en-state { -+ pins = "gpio110"; -+ function = "gpio"; -+ drive-strength = <2>; -+ bias-disable; -+ }; -+ - edp_reg_en: edp-reg-en-state { - pins = "gpio70"; - function = "gpio"; diff --git a/kernel/2207-arm64-dts-qcom-hamoa-Power-the-display-GDSC-while-the-camera-runs.patch b/kernel/2207-arm64-dts-qcom-hamoa-Power-the-display-GDSC-while-the-camera-runs.patch deleted file mode 100644 index fb24a02..0000000 --- a/kernel/2207-arm64-dts-qcom-hamoa-Power-the-display-GDSC-while-the-camera-runs.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Birk Skyum -Date: Sun, 18 Oct 2026 19:58:55 +0000 -Subject: [PATCH] arm64: dts: qcom: hamoa: Power the display GDSC while the - camera runs - -CAMSS on X1E80100 delivers no frames once the display subsystem has been -powered down for a while, although the sensor is programmed over CCI and -CSID starts. Holding MDSS_GDSC on brings the frames back, with the panel -off, MMCX at low_svs and the rest of the display subsystem suspended. -Raising MXC, MMCX or MX, or holding GCC_DISP_HF_AXI_CLK or the eDP PHY -supplies, does not. - -List MDSS_GDSC as a third power domain of the camera clock controller. -Its top-level GDSC then becomes a subdomain of MDSS_GDSC, so the display -GDSC is on whenever TITAN_TOP_GDSC is. - -Signed-off-by: Birk Skyum ---- - arch/arm64/boot/dts/qcom/hamoa.dtsi | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/arch/arm64/boot/dts/qcom/hamoa.dtsi b/arch/arm64/boot/dts/qcom/hamoa.dtsi -index 2e72fa8..e00b48f 100644 ---- a/arch/arm64/boot/dts/qcom/hamoa.dtsi -+++ b/arch/arm64/boot/dts/qcom/hamoa.dtsi -@@ -5821,7 +5821,8 @@ camcc: clock-controller@ade0000 { - <&bi_tcxo_ao_div2>, - <&sleep_clk>; - power-domains = <&rpmhpd RPMHPD_MXC>, -- <&rpmhpd RPMHPD_MMCX>; -+ <&rpmhpd RPMHPD_MMCX>, -+ <&dispcc MDSS_GDSC>; - required-opps = <&rpmhpd_opp_low_svs>, - <&rpmhpd_opp_low_svs>; - #clock-cells = <1>; diff --git a/kernel/2208-i2c-qcom-cci-Reset-the-controller-when-it-resumes.patch b/kernel/2208-i2c-qcom-cci-Reset-the-controller-when-it-resumes.patch deleted file mode 100644 index 4026e19..0000000 --- a/kernel/2208-i2c-qcom-cci-Reset-the-controller-when-it-resumes.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Birk Skyum -Date: Tue, 20 Oct 2026 20:19:35 +0200 -Subject: [PATCH 1/2] i2c: qcom-cci: Reset the controller when it resumes - -A CCI master can stop starting transfers after a target on its bus was -powered down and up again while the controller kept its clocks running. -The next transfer's queue then stays on its first command, neither -CCI_IRQ_STATUS_0 nor the queue's report status changes, and -cci_run_queue() times out after 100 ms ("master 1 queue 0 timeout"). -Only the controller reset in that error path, or the controller's power -domain collapsing while it is runtime suspended, brings it back. - -On the Lenovo Yoga Slim 7x (X1E80100) the OV02C10 front camera is -powered down whenever it stops streaming, and the unpowered sensor -holds SCL and SDA low: both read low at the TLMM pins with the internal -pull-ups enabled. The queue registers at the timeout show the stuck -first command (CUR_CMD 0x08010339, a write of 03 01 08) with the bus -timing registers intact and no error or halt interrupt before it. - -cci_resume_runtime() only programs the interrupt mask and the bus timing -again, so a controller that was runtime suspended without its power -domain collapsing keeps the stuck state. With the camera's TITAN_TOP -GDSC held on and the controller suspended between camera starts, 3 of -40 starts failed this way; with a reset on resume, 0 of 40. - -Reset the controller on every runtime resume, as the timeout path does. - -Signed-off-by: Birk Skyum ---- - drivers/i2c/busses/i2c-qcom-cci.c | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c -index 873e901..c81cc16 100644 ---- a/drivers/i2c/busses/i2c-qcom-cci.c -+++ b/drivers/i2c/busses/i2c-qcom-cci.c -@@ -488,8 +488,19 @@ static int __maybe_unused cci_resume_runtime(struct device *dev) - if (ret) - return ret; - -+ /* -+ * A master can stop starting transfers after a target was powered -+ * down and up again while the controller ran, and keeps that state -+ * over a runtime suspend unless the power domain collapsed. Reset -+ * the controller, with the interrupt mask set first so that the -+ * reset-done interrupt also arrives after a power collapse. -+ */ - cci_init(cci); -- return 0; -+ ret = cci_reset(cci); -+ if (ret) -+ cci_disable_clocks(cci); -+ -+ return ret; - } - - static const struct dev_pm_ops qcom_cci_pm = { diff --git a/kernel/2209-i2c-qcom-cci-Suspend-the-controller-50-ms-after-the-last-transfer.patch b/kernel/2209-i2c-qcom-cci-Suspend-the-controller-50-ms-after-the-last-transfer.patch deleted file mode 100644 index fdac80b..0000000 --- a/kernel/2209-i2c-qcom-cci-Suspend-the-controller-50-ms-after-the-last-transfer.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Birk Skyum -Date: Tue, 20 Oct 2026 20:19:35 +0200 -Subject: [PATCH 2/2] i2c: qcom-cci: Suspend the controller 50 ms after the - last transfer - -With a 1 s autosuspend delay the controller stays clocked across any -power cycle of a target that is shorter than a second, so the reset on -resume never runs in between and the first transfer after the target -comes back stalls until the 100 ms timeout. Camera sensors are powered -down when they stop streaming and up again when they start, so closing -and reopening a camera quickly hits this. - -On the Lenovo Yoga Slim 7x (X1E80100), restarting the OV02C10 with -v4l2-ctl after pauses of 0.05, 0.1, 0.2 and 0.5 s failed in 19 of 20 -cycles each, and in 14 of 20 after 1 s pauses. With this change and the -reset on resume, all 100 cycles started, and so did 150 of 150 raw and -50 of 50 processed libcamera starts back to back. - -Transfers come in bursts, a sensor mode alone is a few hundred register -writes, so suspending 50 ms after the last one costs one reset per -burst. - -Signed-off-by: Birk Skyum ---- - drivers/i2c/busses/i2c-qcom-cci.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c -index c81cc16..4f9dae5 100644 ---- a/drivers/i2c/busses/i2c-qcom-cci.c -+++ b/drivers/i2c/busses/i2c-qcom-cci.c -@@ -612,7 +612,7 @@ static int cci_probe(struct platform_device *pdev) - if (ret < 0) - goto disable_clocks; - -- pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); -+ pm_runtime_set_autosuspend_delay(dev, 50); - ret = devm_pm_runtime_set_active_enabled(dev); - if (ret) - goto disable_clocks; diff --git a/kernel/8204-mm-opportunistic-compaction.patch b/kernel/8204-mm-opportunistic-compaction.patch deleted file mode 100644 index 353ca7c..0000000 --- a/kernel/8204-mm-opportunistic-compaction.patch +++ /dev/null @@ -1,381 +0,0 @@ -diff --git c/include/linux/mmzone.h i/include/linux/mmzone.h ---- c/include/linux/mmzone.h -+++ i/include/linux/mmzone.h -@@ -1465,6 +1465,39 @@ struct memory_failure_stats { - }; - #endif - -+/* -+ * Per-pgdat state machine for the kswapd "opportunistic compaction" hint. -+ * -+ * wakeup_kswapd() collapses the gfp flags of all wakers that arrive between -+ * two kswapd runs into a single tri-state, which kswapd then forwards to the -+ * shrinkers via shrink_control::opportunistic_compaction: -+ * -+ * KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION -+ * Initial state after kswapd consumes the previous value. No waker has -+ * been observed yet for the upcoming run. -+ * -+ * KSWAPD_NO_OPPORTUNISTIC_COMPACTION -+ * At least one waker is an order-0 allocation, or a high-order -+ * allocation that cannot tolerate failure (i.e., not eligible for -+ * opportunistic behaviour). Shrinkers must do their normal best-effort -+ * work; the hint is cleared. -+ * -+ * KSWAPD_OPPORTUNISTIC_COMPACTION -+ * All wakers seen so far are high-order allocations that may fail -+ * (__GFP_NORETRY or __GFP_RETRY_MAYFAIL, without __GFP_NOFAIL). Shrinkers -+ * may skip work that is unlikely to produce a contiguous high-order -+ * block (e.g., evicting working-set pages). -+ * -+ * The state is sticky in the "NO" direction within a single kswapd run: once -+ * any non-eligible waker is observed, subsequent eligible wakers cannot -+ * upgrade it back to KSWAPD_OPPORTUNISTIC_COMPACTION. -+ */ -+enum kswapd_opportunistic_compaction_type { -+ KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION = 0, -+ KSWAPD_NO_OPPORTUNISTIC_COMPACTION, -+ KSWAPD_OPPORTUNISTIC_COMPACTION, -+}; -+ - /* - * On NUMA machines, each NUMA node would have a pg_data_t to describe - * it's memory layout. On UMA machines there is a single pglist_data which -@@ -1529,6 +1562,13 @@ typedef struct pglist_data { - #endif - struct task_struct *kswapd; /* Protected by kswapd_lock */ - int kswapd_order; -+ /* -+ * Aggregated opportunistic-compaction hint for the next kswapd run. -+ * Updated by wakeup_kswapd() based on the gfp flags / order of each -+ * waker, and consumed (and reset) by kswapd before balance_pgdat(). -+ * See enum kswapd_opportunistic_compaction_type for the state machine. -+ */ -+ atomic_t kswapd_opportunistic_compaction; - enum zone_type kswapd_highest_zoneidx; - - atomic_t kswapd_failures; /* Number of 'reclaimed == 0' runs */ -diff --git c/include/linux/shrinker.h i/include/linux/shrinker.h ---- c/include/linux/shrinker.h -+++ i/include/linux/shrinker.h -@@ -37,6 +37,26 @@ struct shrink_control { - /* current node being shrunk (for NUMA aware shrinkers) */ - int nid; - -+ /* -+ * Opportunistic compaction hint. -+ * -+ * Set by the reclaim path to tell shrinkers that this pass is -+ * driven by an order > 0 allocation that the caller is willing to -+ * have fail (e.g., __GFP_NORETRY / __GFP_RETRY_MAYFAIL without -+ * __GFP_NOFAIL). Such allocations only really benefit from -+ * shrinking when doing so frees up a contiguous, high-order block; -+ * thrashing working sets in the hope of producing one is typically -+ * counter-productive. -+ * -+ * Shrinkers that can produce naturally-aligned high-order folios -+ * (see shrink_control::order) should treat this as a hint to skip -+ * costly work that is unlikely to help compaction (for example, -+ * evicting hot/working-set pages just to free single pages). -+ * -+ * Only meaningful when @order > 0; ignored otherwise. -+ */ -+ bool opportunistic_compaction; -+ - /* - * How many objects scan_objects should scan and try to reclaim. - * This is reset before every call, so it is safe for callees -diff --git c/mm/internal.h i/mm/internal.h ---- c/mm/internal.h -+++ i/mm/internal.h -@@ -1767,7 +1767,7 @@ void __meminit __init_page_from_nid(unsigned long pfn, int nid); - - /* shrinker related functions */ - unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg, -- int priority); -+ int priority, bool opportunistic_compaction); - - int shmem_add_to_page_cache(struct folio *folio, - struct address_space *mapping, -diff --git c/mm/shrinker.c i/mm/shrinker.c ---- c/mm/shrinker.c -+++ i/mm/shrinker.c -@@ -476,7 +476,7 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl, - - #ifdef CONFIG_MEMCG - static unsigned long shrink_slab_memcg(gfp_t gfp_mask, int nid, -- struct mem_cgroup *memcg, int priority) -+ struct mem_cgroup *memcg, int priority, bool opportunistic_compaction) - { - struct shrinker_info *info; - unsigned long ret, freed = 0; -@@ -538,6 +538,7 @@ static unsigned long shrink_slab_memcg(gfp_t gfp_mask, int nid, - .gfp_mask = gfp_mask, - .nid = nid, - .memcg = memcg, -+ .opportunistic_compaction = opportunistic_compaction, - }; - struct shrinker *shrinker; - int shrinker_id = calc_shrinker_id(index, offset); -@@ -597,7 +598,8 @@ static unsigned long shrink_slab_memcg(gfp_t gfp_mask, int nid, - } - #else /* !CONFIG_MEMCG */ - static unsigned long shrink_slab_memcg(gfp_t gfp_mask, int nid, -- struct mem_cgroup *memcg, int priority) -+ struct mem_cgroup *memcg, int priority, -+ bool opportunistic_compaction) - { - return 0; - } -@@ -609,6 +611,7 @@ static unsigned long shrink_slab_memcg(gfp_t gfp_mask, int nid, - * @nid: node whose slab caches to target - * @memcg: memory cgroup whose slab caches to target - * @priority: the reclaim priority -+ * @opportunistic_compaction: do compaction opportunistically (e.g., do not swap working sets) - * - * Call the shrink functions to age shrinkable caches. - * -@@ -624,7 +627,7 @@ static unsigned long shrink_slab_memcg(gfp_t gfp_mask, int nid, - * Returns the number of reclaimed slab objects. - */ - unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg, -- int priority) -+ int priority, bool opportunistic_compaction) - { - unsigned long ret, freed = 0; - struct shrinker *shrinker; -@@ -637,7 +640,8 @@ unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg, - * oom. - */ - if (!mem_cgroup_disabled() && !mem_cgroup_is_root(memcg)) -- return shrink_slab_memcg(gfp_mask, nid, memcg, priority); -+ return shrink_slab_memcg(gfp_mask, nid, memcg, priority, -+ opportunistic_compaction); - - /* - * lockless algorithm of global shrink. -@@ -666,6 +670,7 @@ unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg, - .gfp_mask = gfp_mask, - .nid = nid, - .memcg = memcg, -+ .opportunistic_compaction = opportunistic_compaction, - }; - - if (!shrinker_try_get(shrinker)) -diff --git c/mm/vmscan.c i/mm/vmscan.c ---- c/mm/vmscan.c -+++ i/mm/vmscan.c -@@ -96,6 +96,14 @@ struct scan_control { - /* Swappiness value for proactive reclaim. Always use sc_swappiness()! */ - int *proactive_swappiness; - -+ /* -+ * Opportunistic compaction hint snapshotted from the pgdat at the -+ * start of this reclaim pass. Forwarded to shrinkers through -+ * shrink_control::opportunistic_compaction so they can skip -+ * non-productive work for failable high-order allocations. -+ */ -+ enum kswapd_opportunistic_compaction_type kswapd_opportunistic_compaction; -+ - /* Can active folios be deactivated as part of reclaim? */ - #define DEACTIVATE_ANON 1 - #define DEACTIVATE_FILE 2 -@@ -198,6 +206,29 @@ struct scan_control { - */ - int vm_swappiness = 60; - -+/* -+ * Is @gfp_flags a high-order allocation that is eligible for the -+ * "opportunistic compaction" treatment in kswapd / shrinkers? -+ * -+ * The caller must be willing to tolerate failure (__GFP_NORETRY or -+ * __GFP_RETRY_MAYFAIL) and must not have set __GFP_NOFAIL. For such -+ * allocations there is little value in burning working-set pages just to -+ * scrape together a single high-order block: if compaction can't easily -+ * succeed, the caller would rather see the allocation fail. -+ */ -+static bool gfp_opportunistic_compaction(gfp_t gfp_flags) -+{ -+ return (gfp_flags & (__GFP_NORETRY | __GFP_RETRY_MAYFAIL)) && -+ !(gfp_flags & __GFP_NOFAIL); -+} -+ -+static bool sc_opportunistic_compaction(struct scan_control *sc) -+{ -+ return sc->order && (sc->kswapd_opportunistic_compaction == -+ KSWAPD_OPPORTUNISTIC_COMPACTION || (!current_is_kswapd() && -+ gfp_opportunistic_compaction(sc->gfp_mask))); -+} -+ - static int sc_swappiness(struct scan_control *sc, struct mem_cgroup *memcg) - { - if (sc->proactive && sc->proactive_swappiness) -@@ -411,7 +442,7 @@ static unsigned long drop_slab_node(int nid) - - memcg = mem_cgroup_iter(NULL, NULL, NULL); - do { -- freed += shrink_slab(GFP_KERNEL, nid, memcg, 0); -+ freed += shrink_slab(GFP_KERNEL, nid, memcg, 0, false); - } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL); - - return freed; -@@ -5081,6 +5112,7 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc) - unsigned long reclaimed = sc->nr_reclaimed; - struct mem_cgroup *memcg = lruvec_memcg(lruvec); - struct pglist_data *pgdat = lruvec_pgdat(lruvec); -+ bool opportunistic_compaction = sc_opportunistic_compaction(sc); - - /* lru_gen_age_node() called mem_cgroup_calculate_protection() */ - if (mem_cgroup_below_min(NULL, memcg)) -@@ -5096,7 +5128,8 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc) - - need_rotate = try_to_shrink_lruvec(lruvec, sc); - -- shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority); -+ shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority, -+ opportunistic_compaction); - - if (!sc->proactive) - vmpressure(sc->gfp_mask, sc->order, memcg, false, -@@ -6163,6 +6196,7 @@ static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc) - struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); - unsigned long reclaimed; - unsigned long scanned; -+ bool opportunistic_compaction = sc_opportunistic_compaction(sc); - - /* - * This loop can become CPU-bound when target memcgs -@@ -6200,7 +6234,7 @@ static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc) - shrink_lruvec(lruvec, sc); - - shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, -- sc->priority); -+ sc->priority, opportunistic_compaction); - - /* Record the group's reclaim efficiency */ - if (!sc->proactive) -@@ -7133,8 +7167,14 @@ clear_reclaim_active(pg_data_t *pgdat, int highest_zoneidx) - * found to have free_pages <= high_wmark_pages(zone), any page in that zone - * or lower is eligible for reclaim until at least one usable zone is - * balanced. -+ * -+ * @kswapd_opportunistic_compaction is the aggregated hint produced by -+ * wakeup_kswapd() for this run; it is propagated into scan_control so that -+ * shrinkers can skip costly work that is unlikely to help compaction when -+ * all wakers are failable high-order allocations. - */ --static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx) -+static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx, -+ enum kswapd_opportunistic_compaction_type kswapd_opportunistic_compaction) - { - int i; - unsigned long nr_soft_reclaimed; -@@ -7148,6 +7188,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx) - .gfp_mask = GFP_KERNEL, - .order = order, - .may_unmap = 1, -+ .kswapd_opportunistic_compaction = kswapd_opportunistic_compaction, - }; - - trace_mm_vmscan_balance_pgdat_begin(pgdat->node_id, order, -@@ -7372,8 +7413,10 @@ static enum zone_type kswapd_highest_zoneidx(pg_data_t *pgdat, - return curr_idx == MAX_NR_ZONES ? prev_highest_zoneidx : curr_idx; - } - --static void kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order, -- unsigned int highest_zoneidx) -+static void -+kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order, -+ unsigned int highest_zoneidx, -+ enum kswapd_opportunistic_compaction_type kswapd_opportunistic_compaction) - { - long remaining = 0; - DEFINE_WAIT(wait); -@@ -7419,6 +7462,11 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_o - - if (READ_ONCE(pgdat->kswapd_order) < reclaim_order) - WRITE_ONCE(pgdat->kswapd_order, reclaim_order); -+ -+ if (kswapd_opportunistic_compaction == -+ KSWAPD_NO_OPPORTUNISTIC_COMPACTION) -+ atomic_set(&pgdat->kswapd_opportunistic_compaction, -+ KSWAPD_NO_OPPORTUNISTIC_COMPACTION); - } - - finish_wait(&pgdat->kswapd_wait, &wait); -@@ -7475,6 +7523,7 @@ static int kswapd(void *p) - unsigned int highest_zoneidx = MAX_NR_ZONES - 1; - pg_data_t *pgdat = (pg_data_t *)p; - struct task_struct *tsk = current; -+ enum kswapd_opportunistic_compaction_type kswapd_opportunistic_compaction; - - /* - * Tell the memory management that we're a "memory allocator", -@@ -7492,6 +7541,8 @@ static int kswapd(void *p) - set_freezable(); - - WRITE_ONCE(pgdat->kswapd_order, 0); -+ atomic_set(&pgdat->kswapd_opportunistic_compaction, -+ KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION); - WRITE_ONCE(pgdat->kswapd_highest_zoneidx, MAX_NR_ZONES); - atomic_set(&pgdat->nr_writeback_throttled, 0); - for ( ; ; ) { -@@ -7500,13 +7551,18 @@ static int kswapd(void *p) - alloc_order = reclaim_order = READ_ONCE(pgdat->kswapd_order); - highest_zoneidx = kswapd_highest_zoneidx(pgdat, - highest_zoneidx); -+ kswapd_opportunistic_compaction = -+ atomic_read(&pgdat->kswapd_opportunistic_compaction); - - kswapd_try_sleep: - kswapd_try_to_sleep(pgdat, alloc_order, reclaim_order, -- highest_zoneidx); -+ highest_zoneidx, kswapd_opportunistic_compaction); - - /* Read the new order and highest_zoneidx */ - alloc_order = READ_ONCE(pgdat->kswapd_order); -+ kswapd_opportunistic_compaction = -+ atomic_xchg(&pgdat->kswapd_opportunistic_compaction, -+ KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION); - highest_zoneidx = kswapd_highest_zoneidx(pgdat, - highest_zoneidx); - WRITE_ONCE(pgdat->kswapd_order, 0); -@@ -7533,7 +7589,8 @@ static int kswapd(void *p) - trace_mm_vmscan_kswapd_wake(pgdat->node_id, highest_zoneidx, - alloc_order); - reclaim_order = balance_pgdat(pgdat, alloc_order, -- highest_zoneidx); -+ highest_zoneidx, -+ kswapd_opportunistic_compaction); - if (reclaim_order < alloc_order) - goto kswapd_try_sleep; - } -@@ -7571,6 +7628,28 @@ void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order, - if (READ_ONCE(pgdat->kswapd_order) < order) - WRITE_ONCE(pgdat->kswapd_order, order); - -+ /* -+ * Fold this waker into the per-pgdat opportunistic-compaction hint -+ * that kswapd will pick up at the start of its next run. -+ * -+ * The state is sticky in the "NO" direction: once any waker in this -+ * batch is order-0 or a non-failable high-order allocation, the hint -+ * stays cleared until kswapd consumes it. Only when every waker so -+ * far is a failable high-order allocation do we set -+ * KSWAPD_OPPORTUNISTIC_COMPACTION, asking shrinkers to skip work -+ * that won't realistically help compaction. -+ */ -+ if (atomic_read(&pgdat->kswapd_opportunistic_compaction) != -+ KSWAPD_NO_OPPORTUNISTIC_COMPACTION) { -+ if (!order || !gfp_opportunistic_compaction(gfp_flags)) -+ atomic_set(&pgdat->kswapd_opportunistic_compaction, -+ KSWAPD_NO_OPPORTUNISTIC_COMPACTION); -+ else if (order && gfp_opportunistic_compaction(gfp_flags)) -+ atomic_cmpxchg(&pgdat->kswapd_opportunistic_compaction, -+ KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION, -+ KSWAPD_OPPORTUNISTIC_COMPACTION); -+ } -+ - if (!waitqueue_active(&pgdat->kswapd_wait)) - return; - diff --git a/kernel/8204-mm-opportunistic-compaction.patch.sig b/kernel/8204-mm-opportunistic-compaction.patch.sig deleted file mode 100644 index d4744f8..0000000 Binary files a/kernel/8204-mm-opportunistic-compaction.patch.sig and /dev/null differ diff --git a/kernel/8205-mm-hint-uses-allocation-order.patch b/kernel/8205-mm-hint-uses-allocation-order.patch deleted file mode 100644 index f579b27..0000000 --- a/kernel/8205-mm-hint-uses-allocation-order.patch +++ /dev/null @@ -1,236 +0,0 @@ -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -1680,7 +1680,7 @@ enum kswapd_clear_hopeless_reason { - }; - - void wakeup_kswapd(struct zone *zone, gfp_t gfp_mask, int order, -- enum zone_type highest_zoneidx); -+ bool opportunistic, enum zone_type highest_zoneidx); - void kswapd_try_clear_hopeless(struct pglist_data *pgdat, - unsigned int order, int highest_zoneidx); - void kswapd_clear_hopeless(pg_data_t *pgdat, enum kswapd_clear_hopeless_reason reason); -diff --git a/include/linux/swap.h b/include/linux/swap.h ---- a/include/linux/swap.h -+++ b/include/linux/swap.h -@@ -348,7 +348,8 @@ extern void swap_setup(void); - /* linux/mm/vmscan.c */ - extern unsigned long zone_reclaimable_pages(struct zone *zone); - extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order, -- gfp_t gfp_mask, nodemask_t *mask); -+ int alloc_order, gfp_t gfp_mask, -+ nodemask_t *mask); - unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx); - - #define MEMCG_RECLAIM_MAY_SWAP (1 << 1) -diff --git a/mm/internal.h b/mm/internal.h ---- a/mm/internal.h -+++ b/mm/internal.h -@@ -1765,6 +1765,28 @@ void __meminit __init_single_page(struct page *page, unsigned long pfn, - unsigned long zone, int nid); - void __meminit __init_page_from_nid(unsigned long pfn, int nid); - -+/* -+ * Is this allocation eligible for the "opportunistic compaction" treatment -+ * in kswapd and the shrinkers? -+ * -+ * The caller must be willing to tolerate failure (__GFP_NORETRY or -+ * __GFP_RETRY_MAYFAIL) and must not have set __GFP_NOFAIL. For such -+ * allocations there is little value in burning working-set pages just to -+ * scrape together a single high-order block: if compaction can't easily -+ * succeed, the caller would rather see the allocation fail. -+ * -+ * @order is the order the caller asked for, not the order reclaim was -+ * promoted to. defrag_mode raises the reclaim order to pageblock_order, -+ * which says nothing about what the caller can tolerate. -+ */ -+static inline bool gfp_opportunistic_compaction(gfp_t gfp_flags, int order) -+{ -+ if (!order || (gfp_flags & __GFP_NOFAIL)) -+ return false; -+ -+ return !!(gfp_flags & (__GFP_NORETRY | __GFP_RETRY_MAYFAIL)); -+} -+ - /* shrinker related functions */ - unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg, - int priority, bool opportunistic_compaction); -diff --git a/mm/migrate.c b/mm/migrate.c ---- a/mm/migrate.c -+++ b/mm/migrate.c -@@ -2727,7 +2727,7 @@ int migrate_misplaced_folio_prepare(struct folio *folio, - return -EAGAIN; - - wakeup_kswapd(pgdat->node_zones + z, 0, -- folio_order(folio), ZONE_MOVABLE); -+ folio_order(folio), false, ZONE_MOVABLE); - return -EAGAIN; - } - -diff --git a/mm/page_alloc.c b/mm/page_alloc.c ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -3422,7 +3422,7 @@ struct page *rmqueue(struct zone *preferred_zone, - if ((alloc_flags & ALLOC_KSWAPD) && - unlikely(test_bit(ZONE_BOOSTED_WATERMARK, &zone->flags))) { - clear_bit(ZONE_BOOSTED_WATERMARK, &zone->flags); -- wakeup_kswapd(zone, 0, 0, zone_idx(zone)); -+ wakeup_kswapd(zone, 0, 0, false, zone_idx(zone)); - } - - VM_BUG_ON_PAGE(page && bad_range(zone, page), page); -@@ -4441,6 +4441,7 @@ static unsigned int check_retry_zonelist(unsigned int seq) - /* Perform direct synchronous page reclaim */ - static unsigned long - __perform_reclaim(gfp_t gfp_mask, unsigned int order, -+ unsigned int alloc_order, - const struct alloc_context *ac) - { - unsigned int noreclaim_flag; -@@ -4453,7 +4454,7 @@ __perform_reclaim(gfp_t gfp_mask, unsigned int order, - fs_reclaim_acquire(gfp_mask); - noreclaim_flag = memalloc_noreclaim_save(); - -- progress = try_to_free_pages(ac->zonelist, order, gfp_mask, -+ progress = try_to_free_pages(ac->zonelist, order, alloc_order, gfp_mask, - ac->nodemask); - - memalloc_noreclaim_restore(noreclaim_flag); -@@ -4480,7 +4481,7 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, - reclaim_order = max(order, pageblock_order); - - psi_memstall_enter(&pflags); -- *did_some_progress = __perform_reclaim(gfp_mask, reclaim_order, ac); -+ *did_some_progress = __perform_reclaim(gfp_mask, reclaim_order, order, ac); - if (unlikely(!(*did_some_progress))) - goto out; - -@@ -4512,19 +4513,24 @@ static void wake_all_kswapds(unsigned int order, gfp_t gfp_mask, - pg_data_t *last_pgdat = NULL; - enum zone_type highest_zoneidx = ac->highest_zoneidx; - unsigned int reclaim_order; -+ bool opportunistic; - - if (defrag_mode) - reclaim_order = max(order, pageblock_order); - else - reclaim_order = order; - -+ /* Classify what the caller asked for, not what reclaim was raised to. */ -+ opportunistic = gfp_opportunistic_compaction(gfp_mask, order); -+ - for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, highest_zoneidx, - ac->nodemask) { - if (!managed_zone(zone)) - continue; - if (last_pgdat == zone->zone_pgdat) - continue; -- wakeup_kswapd(zone, gfp_mask, reclaim_order, highest_zoneidx); -+ wakeup_kswapd(zone, gfp_mask, reclaim_order, opportunistic, -+ highest_zoneidx); - last_pgdat = zone->zone_pgdat; - } - } -diff --git a/mm/vmscan.c b/mm/vmscan.c ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -160,6 +160,12 @@ struct scan_control { - /* Allocation order */ - s8 order; - -+ /* -+ * The order the allocation asked for. @order above may have been -+ * raised to pageblock_order by defrag_mode. -+ */ -+ s8 alloc_order; -+ - /* Scan (total_size >> priority) pages at once */ - s8 priority; - -@@ -206,27 +212,19 @@ struct scan_control { - */ - int vm_swappiness = 60; - --/* -- * Is @gfp_flags a high-order allocation that is eligible for the -- * "opportunistic compaction" treatment in kswapd / shrinkers? -- * -- * The caller must be willing to tolerate failure (__GFP_NORETRY or -- * __GFP_RETRY_MAYFAIL) and must not have set __GFP_NOFAIL. For such -- * allocations there is little value in burning working-set pages just to -- * scrape together a single high-order block: if compaction can't easily -- * succeed, the caller would rather see the allocation fail. -- */ --static bool gfp_opportunistic_compaction(gfp_t gfp_flags) --{ -- return (gfp_flags & (__GFP_NORETRY | __GFP_RETRY_MAYFAIL)) && -- !(gfp_flags & __GFP_NOFAIL); --} -- - static bool sc_opportunistic_compaction(struct scan_control *sc) - { -- return sc->order && (sc->kswapd_opportunistic_compaction == -- KSWAPD_OPPORTUNISTIC_COMPACTION || (!current_is_kswapd() && -- gfp_opportunistic_compaction(sc->gfp_mask))); -+ if (!sc->order) -+ return false; -+ -+ if (sc->kswapd_opportunistic_compaction == -+ KSWAPD_OPPORTUNISTIC_COMPACTION) -+ return true; -+ -+ if (current_is_kswapd()) -+ return false; -+ -+ return gfp_opportunistic_compaction(sc->gfp_mask, sc->alloc_order); - } - - static int sc_swappiness(struct scan_control *sc, struct mem_cgroup *memcg) -@@ -6781,7 +6779,8 @@ static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist, - } - - unsigned long try_to_free_pages(struct zonelist *zonelist, int order, -- gfp_t gfp_mask, nodemask_t *nodemask) -+ int alloc_order, gfp_t gfp_mask, -+ nodemask_t *nodemask) - { - unsigned long nr_reclaimed; - struct scan_control sc = { -@@ -6789,6 +6788,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order, - .gfp_mask = current_gfp_context(gfp_mask), - .reclaim_idx = gfp_zone(gfp_mask), - .order = order, -+ .alloc_order = alloc_order, - .nodemask = nodemask, - .priority = DEF_PRIORITY, - .may_writepage = 1, -@@ -7608,7 +7608,7 @@ static int kswapd(void *p) - * needed. - */ - void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order, -- enum zone_type highest_zoneidx) -+ bool opportunistic, enum zone_type highest_zoneidx) - { - pg_data_t *pgdat; - enum zone_type curr_idx; -@@ -7641,10 +7641,10 @@ void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order, - */ - if (atomic_read(&pgdat->kswapd_opportunistic_compaction) != - KSWAPD_NO_OPPORTUNISTIC_COMPACTION) { -- if (!order || !gfp_opportunistic_compaction(gfp_flags)) -+ if (!opportunistic) - atomic_set(&pgdat->kswapd_opportunistic_compaction, - KSWAPD_NO_OPPORTUNISTIC_COMPACTION); -- else if (order && gfp_opportunistic_compaction(gfp_flags)) -+ else - atomic_cmpxchg(&pgdat->kswapd_opportunistic_compaction, - KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION, - KSWAPD_OPPORTUNISTIC_COMPACTION); -@@ -7942,6 +7942,7 @@ int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) - .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX), - .gfp_mask = current_gfp_context(gfp_mask), - .order = order, -+ .alloc_order = order, - .priority = NODE_RECLAIM_PRIORITY, - .may_writepage = !!(node_reclaim_mode & RECLAIM_WRITE), - .may_unmap = !!(node_reclaim_mode & RECLAIM_UNMAP), diff --git a/kernel/8205-mm-hint-uses-allocation-order.patch.sig b/kernel/8205-mm-hint-uses-allocation-order.patch.sig deleted file mode 100644 index 7c3ef42..0000000 Binary files a/kernel/8205-mm-hint-uses-allocation-order.patch.sig and /dev/null differ diff --git a/kernel/8206-mm-carry-order-and-hint-in-one-word.patch b/kernel/8206-mm-carry-order-and-hint-in-one-word.patch deleted file mode 100644 index 65dd70b..0000000 --- a/kernel/8206-mm-carry-order-and-hint-in-one-word.patch +++ /dev/null @@ -1,232 +0,0 @@ -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -1498,6 +1498,32 @@ enum kswapd_opportunistic_compaction_type { - KSWAPD_OPPORTUNISTIC_COMPACTION, - }; - -+/* -+ * pgdat->kswapd_request holds the order and the hint above in one word. A -+ * waker folds both in with a single cmpxchg and kswapd takes both with a -+ * single exchange, so a run cannot serve one waker's order under another -+ * waker's hint. -+ */ -+#define KSWAPD_REQUEST_HINT_MASK 3 -+#define KSWAPD_REQUEST_ORDER_SHIFT 2 -+ -+static inline int kswapd_request(int order, -+ enum kswapd_opportunistic_compaction_type hint) -+{ -+ return (order << KSWAPD_REQUEST_ORDER_SHIFT) | hint; -+} -+ -+static inline int kswapd_request_order(int request) -+{ -+ return request >> KSWAPD_REQUEST_ORDER_SHIFT; -+} -+ -+static inline enum kswapd_opportunistic_compaction_type -+kswapd_request_hint(int request) -+{ -+ return request & KSWAPD_REQUEST_HINT_MASK; -+} -+ - /* - * On NUMA machines, each NUMA node would have a pg_data_t to describe - * it's memory layout. On UMA machines there is a single pglist_data which -@@ -1561,14 +1587,15 @@ typedef struct pglist_data { - struct mutex kswapd_lock; - #endif - struct task_struct *kswapd; /* Protected by kswapd_lock */ -- int kswapd_order; - /* -- * Aggregated opportunistic-compaction hint for the next kswapd run. -- * Updated by wakeup_kswapd() based on the gfp flags / order of each -- * waker, and consumed (and reset) by kswapd before balance_pgdat(). -- * See enum kswapd_opportunistic_compaction_type for the state machine. -+ * The next kswapd run's request: the highest order asked for since -+ * kswapd last consumed one, and the aggregated opportunistic- -+ * compaction hint, in one word. Updated by wakeup_kswapd() from the -+ * gfp flags and order of each waker, and consumed by kswapd before -+ * balance_pgdat(). See kswapd_request() and -+ * enum kswapd_opportunistic_compaction_type. - */ -- atomic_t kswapd_opportunistic_compaction; -+ atomic_t kswapd_request; - enum zone_type kswapd_highest_zoneidx; - - atomic_t kswapd_failures; /* Number of 'reclaimed == 0' runs */ -diff --git a/mm/mm_init.c b/mm/mm_init.c ---- a/mm/mm_init.c -+++ b/mm/mm_init.c -@@ -1558,7 +1558,8 @@ int __ref free_area_init_core_hotplug(struct pglist_data *pgdat) - * when it starts in the near future. - */ - pgdat->nr_zones = 0; -- pgdat->kswapd_order = 0; -+ atomic_set(&pgdat->kswapd_request, -+ kswapd_request(0, KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION)); - pgdat->kswapd_highest_zoneidx = 0; - pgdat->node_start_pfn = 0; - pgdat->node_present_pages = 0; -diff --git a/mm/vmscan.c b/mm/vmscan.c ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -7413,6 +7413,49 @@ static enum zone_type kswapd_highest_zoneidx(pg_data_t *pgdat, - return curr_idx == MAX_NR_ZONES ? prev_highest_zoneidx : curr_idx; - } - -+/* -+ * How a caller votes on the opportunistic-compaction hint when it folds a -+ * request into pgdat->kswapd_request. -+ */ -+enum kswapd_vote { -+ KSWAPD_VOTE_NONE, -+ KSWAPD_VOTE_NO_OPPORTUNISTIC, -+ KSWAPD_VOTE_OPPORTUNISTIC, -+}; -+ -+/* -+ * Raise the requested order to @order and fold in @vote, in one step. -+ * -+ * The hint is sticky in the "NO" direction: once any waker votes against -+ * opportunistic treatment, the hint stays cleared until kswapd consumes the -+ * request. KSWAPD_VOTE_NONE raises the order and leaves the hint alone. -+ * -+ * Order and hint live in the same word, so a waker whose order kswapd -+ * observes always contributed its vote to the hint kswapd observes with it. -+ */ -+static void kswapd_request_fold(pg_data_t *pgdat, int order, -+ enum kswapd_vote vote) -+{ -+ int old = atomic_read(&pgdat->kswapd_request); -+ int new; -+ -+ do { -+ enum kswapd_opportunistic_compaction_type hint = -+ kswapd_request_hint(old); -+ int req_order = max(kswapd_request_order(old), order); -+ -+ if (vote == KSWAPD_VOTE_NO_OPPORTUNISTIC) -+ hint = KSWAPD_NO_OPPORTUNISTIC_COMPACTION; -+ else if (vote == KSWAPD_VOTE_OPPORTUNISTIC && -+ hint == KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION) -+ hint = KSWAPD_OPPORTUNISTIC_COMPACTION; -+ -+ new = kswapd_request(req_order, hint); -+ if (new == old) -+ return; -+ } while (!atomic_try_cmpxchg(&pgdat->kswapd_request, &old, new)); -+} -+ - static void - kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order, - unsigned int highest_zoneidx, -@@ -7460,13 +7503,11 @@ kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order, - kswapd_highest_zoneidx(pgdat, - highest_zoneidx)); - -- if (READ_ONCE(pgdat->kswapd_order) < reclaim_order) -- WRITE_ONCE(pgdat->kswapd_order, reclaim_order); -- -- if (kswapd_opportunistic_compaction == -- KSWAPD_NO_OPPORTUNISTIC_COMPACTION) -- atomic_set(&pgdat->kswapd_opportunistic_compaction, -- KSWAPD_NO_OPPORTUNISTIC_COMPACTION); -+ kswapd_request_fold(pgdat, reclaim_order, -+ kswapd_opportunistic_compaction == -+ KSWAPD_NO_OPPORTUNISTIC_COMPACTION ? -+ KSWAPD_VOTE_NO_OPPORTUNISTIC : -+ KSWAPD_VOTE_NONE); - } - - finish_wait(&pgdat->kswapd_wait, &wait); -@@ -7524,6 +7565,7 @@ static int kswapd(void *p) - pg_data_t *pgdat = (pg_data_t *)p; - struct task_struct *tsk = current; - enum kswapd_opportunistic_compaction_type kswapd_opportunistic_compaction; -+ int request; - - /* - * Tell the memory management that we're a "memory allocator", -@@ -7540,32 +7582,30 @@ static int kswapd(void *p) - tsk->flags |= PF_MEMALLOC | PF_KSWAPD; - set_freezable(); - -- WRITE_ONCE(pgdat->kswapd_order, 0); -- atomic_set(&pgdat->kswapd_opportunistic_compaction, -- KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION); -+ atomic_set(&pgdat->kswapd_request, -+ kswapd_request(0, KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION)); - WRITE_ONCE(pgdat->kswapd_highest_zoneidx, MAX_NR_ZONES); - atomic_set(&pgdat->nr_writeback_throttled, 0); - for ( ; ; ) { - bool was_frozen; - -- alloc_order = reclaim_order = READ_ONCE(pgdat->kswapd_order); -+ request = atomic_read(&pgdat->kswapd_request); -+ alloc_order = reclaim_order = kswapd_request_order(request); - highest_zoneidx = kswapd_highest_zoneidx(pgdat, - highest_zoneidx); -- kswapd_opportunistic_compaction = -- atomic_read(&pgdat->kswapd_opportunistic_compaction); -+ kswapd_opportunistic_compaction = kswapd_request_hint(request); - - kswapd_try_sleep: - kswapd_try_to_sleep(pgdat, alloc_order, reclaim_order, - highest_zoneidx, kswapd_opportunistic_compaction); - -- /* Read the new order and highest_zoneidx */ -- alloc_order = READ_ONCE(pgdat->kswapd_order); -- kswapd_opportunistic_compaction = -- atomic_xchg(&pgdat->kswapd_opportunistic_compaction, -- KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION); -+ /* Take the new request and highest_zoneidx */ -+ request = atomic_xchg(&pgdat->kswapd_request, -+ kswapd_request(0, KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION)); -+ alloc_order = kswapd_request_order(request); -+ kswapd_opportunistic_compaction = kswapd_request_hint(request); - highest_zoneidx = kswapd_highest_zoneidx(pgdat, - highest_zoneidx); -- WRITE_ONCE(pgdat->kswapd_order, 0); - WRITE_ONCE(pgdat->kswapd_highest_zoneidx, MAX_NR_ZONES); - - if (kthread_freezable_should_stop(&was_frozen)) -@@ -7625,30 +7665,15 @@ void wakeup_kswapd(struct zone *zone, gfp_t gfp_flags, int order, - if (curr_idx == MAX_NR_ZONES || curr_idx < highest_zoneidx) - WRITE_ONCE(pgdat->kswapd_highest_zoneidx, highest_zoneidx); - -- if (READ_ONCE(pgdat->kswapd_order) < order) -- WRITE_ONCE(pgdat->kswapd_order, order); -- - /* -- * Fold this waker into the per-pgdat opportunistic-compaction hint -- * that kswapd will pick up at the start of its next run. -- * -- * The state is sticky in the "NO" direction: once any waker in this -- * batch is order-0 or a non-failable high-order allocation, the hint -- * stays cleared until kswapd consumes it. Only when every waker so -- * far is a failable high-order allocation do we set -- * KSWAPD_OPPORTUNISTIC_COMPACTION, asking shrinkers to skip work -- * that won't realistically help compaction. -+ * Fold this waker's order and its vote on the opportunistic-compaction -+ * hint into the request kswapd will pick up at the start of its next -+ * run. Both change together, so the run that serves this order also -+ * carries this waker's vote. - */ -- if (atomic_read(&pgdat->kswapd_opportunistic_compaction) != -- KSWAPD_NO_OPPORTUNISTIC_COMPACTION) { -- if (!opportunistic) -- atomic_set(&pgdat->kswapd_opportunistic_compaction, -- KSWAPD_NO_OPPORTUNISTIC_COMPACTION); -- else -- atomic_cmpxchg(&pgdat->kswapd_opportunistic_compaction, -- KSWAPD_UNSET_OPPORTUNISTIC_COMPACTION, -- KSWAPD_OPPORTUNISTIC_COMPACTION); -- } -+ kswapd_request_fold(pgdat, order, -+ opportunistic ? KSWAPD_VOTE_OPPORTUNISTIC : -+ KSWAPD_VOTE_NO_OPPORTUNISTIC); - - if (!waitqueue_active(&pgdat->kswapd_wait)) - return; diff --git a/kernel/8206-mm-carry-order-and-hint-in-one-word.patch.sig b/kernel/8206-mm-carry-order-and-hint-in-one-word.patch.sig deleted file mode 100644 index 684949b..0000000 Binary files a/kernel/8206-mm-carry-order-and-hint-in-one-word.patch.sig and /dev/null differ diff --git a/kernel/8207-mm-classify-huge-page-allocations-as-failable.patch b/kernel/8207-mm-classify-huge-page-allocations-as-failable.patch deleted file mode 100644 index bfa7d1e..0000000 --- a/kernel/8207-mm-classify-huge-page-allocations-as-failable.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git c/mm/internal.h i/mm/internal.h ---- c/mm/internal.h -+++ i/mm/internal.h -@@ -1778,12 +1778,24 @@ void __meminit __init_page_from_nid(unsigned long pfn, int nid); - * @order is the order the caller asked for, not the order reclaim was - * promoted to. defrag_mode raises the reclaim order to pageblock_order, - * which says nothing about what the caller can tolerate. -+ * -+ * A transparent huge page allocation sets neither flag, yet a failed -+ * collapse or fault falls back to small pages. Recognise it by its mask. -+ * In this tree the complete GFP_TRANSHUGE_LIGHT set is carried by the -+ * huge page fault path, khugepaged and the large folio migration -+ * targets. The huge zero folio clears __GFP_MOVABLE and so keeps normal -+ * shrinker behaviour. The three other sites that combine __GFP_COMP -+ * with __GFP_NOMEMALLOC do not carry the movable, highmem and -+ * filesystem bits, so they do not match. - */ - static inline bool gfp_opportunistic_compaction(gfp_t gfp_flags, int order) - { - if (!order || (gfp_flags & __GFP_NOFAIL)) - return false; - -+ if ((gfp_flags & GFP_TRANSHUGE_LIGHT) == GFP_TRANSHUGE_LIGHT) -+ return true; -+ - return !!(gfp_flags & (__GFP_NORETRY | __GFP_RETRY_MAYFAIL)); - } - diff --git a/kernel/8207-mm-classify-huge-page-allocations-as-failable.patch.sig b/kernel/8207-mm-classify-huge-page-allocations-as-failable.patch.sig deleted file mode 100644 index e60df1b..0000000 Binary files a/kernel/8207-mm-classify-huge-page-allocations-as-failable.patch.sig and /dev/null differ diff --git a/kernel/8209-xe-shrinker-use-opportunistic-hint.patch b/kernel/8209-xe-shrinker-use-opportunistic-hint.patch deleted file mode 100644 index 0552be0..0000000 --- a/kernel/8209-xe-shrinker-use-opportunistic-hint.patch +++ /dev/null @@ -1,39 +0,0 @@ -diff --git c/drivers/gpu/drm/xe/xe_shrinker.c i/drivers/gpu/drm/xe/xe_shrinker.c ---- c/drivers/gpu/drm/xe/xe_shrinker.c -+++ i/drivers/gpu/drm/xe/xe_shrinker.c -@@ -174,10 +174,17 @@ static unsigned long - xe_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) - { - struct xe_shrinker *shrinker = to_xe_shrinker(shrink); -- unsigned long num_pages; -+ unsigned long num_pages = 0; - bool can_backup = !!(sc->gfp_mask & __GFP_FS); - -- num_pages = ttm_backup_bytes_avail() >> PAGE_SHIFT; -+ /* -+ * Skip accounting backup-able pages when this is an opportunistic -+ * high-order pass: TTM backup work shrinks at native page granularity -+ * and is unlikely to produce the contiguous block the caller wants, -+ * so don't advertise it as reclaimable for this hint. -+ */ -+ if (!sc->opportunistic_compaction) -+ num_pages = ttm_backup_bytes_avail() >> PAGE_SHIFT; - read_lock(&shrinker->lock); - - if (can_backup) -@@ -249,7 +256,14 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con - nr_to_scan, &nr_scanned, &freed); - - sc->nr_scanned = nr_scanned; -- if (nr_scanned >= nr_to_scan || !can_backup) -+ /* -+ * Stop after the purge pass for opportunistic high-order reclaim: -+ * the subsequent backup/writeback pass works at native page order -+ * and is unlikely to free a contiguous high-order block, so doing -+ * it here would just churn working sets for no compaction benefit. -+ */ -+ if (nr_scanned >= nr_to_scan || !can_backup || -+ sc->opportunistic_compaction) - goto out; - - /* If we didn't wake before, try to do it now if needed. */ diff --git a/kernel/8209-xe-shrinker-use-opportunistic-hint.patch.sig b/kernel/8209-xe-shrinker-use-opportunistic-hint.patch.sig deleted file mode 100644 index 7928b4e..0000000 Binary files a/kernel/8209-xe-shrinker-use-opportunistic-hint.patch.sig and /dev/null differ diff --git a/kernel/8210-xe-shrinker-single-backup-decision.patch b/kernel/8210-xe-shrinker-single-backup-decision.patch deleted file mode 100644 index 9daf161..0000000 --- a/kernel/8210-xe-shrinker-single-backup-decision.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff --git c/drivers/gpu/drm/xe/xe_shrinker.c i/drivers/gpu/drm/xe/xe_shrinker.c ---- c/drivers/gpu/drm/xe/xe_shrinker.c -+++ i/drivers/gpu/drm/xe/xe_shrinker.c -@@ -170,27 +170,28 @@ static int xe_shrinker_walk(struct xe_shrinker *shrinker, - return ret; - } - -+static inline bool xe_shrinker_can_backup(const struct shrink_control *sc) -+{ -+ return (sc->gfp_mask & __GFP_FS) && !sc->opportunistic_compaction; -+} -+ - static unsigned long - xe_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) - { - struct xe_shrinker *shrinker = to_xe_shrinker(shrink); - unsigned long num_pages = 0; -- bool can_backup = !!(sc->gfp_mask & __GFP_FS); - - /* -- * Skip accounting backup-able pages when this is an opportunistic -- * high-order pass: TTM backup work shrinks at native page granularity -- * and is unlikely to produce the contiguous block the caller wants, -- * so don't advertise it as reclaimable for this hint. -+ * Only advertise backup-able pages when the backup pass can run. TTM -+ * backup work shrinks at native page granularity and is unlikely to -+ * produce the contiguous block an opportunistic high-order caller -+ * wants, and it needs __GFP_FS. - */ -- if (!sc->opportunistic_compaction) -- num_pages = ttm_backup_bytes_avail() >> PAGE_SHIFT; - read_lock(&shrinker->lock); -- -- if (can_backup) -- num_pages = min_t(unsigned long, num_pages, shrinker->shrinkable_pages); -- else -- num_pages = 0; -+ if (xe_shrinker_can_backup(sc)) -+ num_pages = min_t(unsigned long, -+ ttm_backup_bytes_avail() >> PAGE_SHIFT, -+ shrinker->shrinkable_pages); - - num_pages += shrinker->purgeable_pages; - read_unlock(&shrinker->lock); -@@ -240,7 +241,7 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con - }; - bool runtime_pm; - bool purgeable; -- bool can_backup = !!(sc->gfp_mask & __GFP_FS); -+ bool can_backup = xe_shrinker_can_backup(sc); - - nr_to_scan = sc->nr_to_scan; - -@@ -257,13 +258,15 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con - - sc->nr_scanned = nr_scanned; - /* -- * Stop after the purge pass for opportunistic high-order reclaim: -- * the subsequent backup/writeback pass works at native page order -- * and is unlikely to free a contiguous high-order block, so doing -- * it here would just churn working sets for no compaction benefit. -+ * Stop after the purge pass when the backup pass may not run. The -+ * backup/writeback pass works at native page order and is unlikely to -+ * free a contiguous high-order block for an opportunistic caller, so -+ * doing it there would churn working sets for no compaction benefit. -+ * -+ * The per-walk runtime PM reference in __xe_shrinker_walk() is not -+ * affected. Only the outer backup-driven reference is. - */ -- if (nr_scanned >= nr_to_scan || !can_backup || -- sc->opportunistic_compaction) -+ if (nr_scanned >= nr_to_scan || !can_backup) - goto out; - - /* If we didn't wake before, try to do it now if needed. */ diff --git a/kernel/8210-xe-shrinker-single-backup-decision.patch.sig b/kernel/8210-xe-shrinker-single-backup-decision.patch.sig deleted file mode 100644 index a823434..0000000 Binary files a/kernel/8210-xe-shrinker-single-backup-decision.patch.sig and /dev/null differ diff --git a/kernel/8211-xe-shrinker-skip-active-vm.patch b/kernel/8211-xe-shrinker-skip-active-vm.patch deleted file mode 100644 index 76470c1..0000000 --- a/kernel/8211-xe-shrinker-skip-active-vm.patch +++ /dev/null @@ -1,116 +0,0 @@ -diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c ---- a/drivers/gpu/drm/xe/xe_bo.c -+++ b/drivers/gpu/drm/xe/xe_bo.c -@@ -28,6 +28,7 @@ - #include "xe_ggtt.h" - #include "xe_map.h" - #include "xe_migrate.h" -+#include "xe_module.h" - #include "xe_pat.h" - #include "xe_pm.h" - #include "xe_preempt_fence.h" -@@ -1244,6 +1245,26 @@ xe_bo_eviction_valuable(struct ttm_buffer_object *bo, const struct ttm_place *pl - return true; - } - -+static bool xe_bo_bound_to_active_vm(struct xe_bo *bo) -+{ -+ u64 window = (u64)READ_ONCE(xe_modparam.shrink_active_ms) * NSEC_PER_MSEC; -+ u64 now = ktime_get_ns(); -+ struct drm_gpuvm_bo *vm_bo; -+ -+ if (!window) -+ return false; -+ -+ drm_gem_for_each_gpuvm_bo(vm_bo, &bo->ttm.base) { -+ struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm); -+ u64 last = READ_ONCE(vm->last_exec_ns); -+ -+ if (!xe_vm_in_fault_mode(vm) && last && now - last < window) -+ return true; -+ } -+ -+ return false; -+} -+ - /** - * xe_bo_shrink() - Try to shrink an xe bo. - * @ctx: The struct ttm_operation_ctx used for shrinking. -@@ -1295,6 +1316,10 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo, - goto out_unref; - } - -+ if (xe_bo_bound_to_active_vm(xe_bo) && -+ try_wait_for_completion(&xe->pm_block)) -+ goto out_unref; -+ - /* System CCS needs gpu copy when moving PL_TT -> PL_SYSTEM */ - needs_rpm = (!IS_DGFX(xe) && bo->resource->mem_type != XE_PL_SYSTEM && - xe_bo_needs_ccs_pages(xe_bo)); -diff --git a/drivers/gpu/drm/xe/xe_defaults.h b/drivers/gpu/drm/xe/xe_defaults.h ---- a/drivers/gpu/drm/xe/xe_defaults.h -+++ b/drivers/gpu/drm/xe/xe_defaults.h -@@ -22,5 +22,6 @@ - #define XE_DEFAULT_WEDGED_MODE XE_WEDGED_MODE_UPON_CRITICAL_ERROR - #define XE_DEFAULT_WEDGED_MODE_STR "upon-critical-error" - #define XE_DEFAULT_SVM_NOTIFIER_SIZE 512 -+#define XE_DEFAULT_SHRINK_ACTIVE_MS 1000 - - #endif -diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c ---- a/drivers/gpu/drm/xe/xe_exec.c -+++ b/drivers/gpu/drm/xe/xe_exec.c -@@ -344,6 +344,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) - if (!xe_vm_in_lr_mode(vm)) - xe_exec_queue_last_fence_set(q, vm, &job->drm.s_fence->finished); - xe_sched_job_push(job); -+ WRITE_ONCE(vm->last_exec_ns, ktime_get_ns()); - xe_vm_reactivate_rebind(vm); - - if (!err && !xe_vm_in_lr_mode(vm)) { -diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c ---- a/drivers/gpu/drm/xe/xe_module.c -+++ b/drivers/gpu/drm/xe/xe_module.c -@@ -30,6 +30,7 @@ struct xe_modparam xe_modparam = { - #endif - .wedged_mode = XE_DEFAULT_WEDGED_MODE, - .svm_notifier_size = XE_DEFAULT_SVM_NOTIFIER_SIZE, -+ .shrink_active_ms = XE_DEFAULT_SHRINK_ACTIVE_MS, - /* the rest are 0 by default */ - }; - -@@ -37,6 +38,11 @@ module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, uint, 0600) - MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size in MiB, must be power of 2 " - "[default=" __stringify(XE_DEFAULT_SVM_NOTIFIER_SIZE) "]"); - -+module_param_named(shrink_active_ms, xe_modparam.shrink_active_ms, uint, 0600); -+MODULE_PARM_DESC(shrink_active_ms, "Do not back up a buffer object bound to a VM that submitted work " -+ "within this many ms, 0=disabled " -+ "[default=" __stringify(XE_DEFAULT_SHRINK_ACTIVE_MS) "]"); -+ - module_param_named_unsafe(force_execlist, xe_modparam.force_execlist, bool, 0444); - MODULE_PARM_DESC(force_execlist, "Force Execlist submission"); - -diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h ---- a/drivers/gpu/drm/xe/xe_module.h -+++ b/drivers/gpu/drm/xe/xe_module.h -@@ -25,6 +25,7 @@ struct xe_modparam { - #endif - unsigned int wedged_mode; - u32 svm_notifier_size; -+ unsigned int shrink_active_ms; - }; - - extern struct xe_modparam xe_modparam; -diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h ---- a/drivers/gpu/drm/xe/xe_vm_types.h -+++ b/drivers/gpu/drm/xe/xe_vm_types.h -@@ -245,6 +245,8 @@ struct xe_vm { - /** @lru_bulk_move: Bulk LRU move list for this VM's BOs */ - struct ttm_lru_bulk_move lru_bulk_move; - -+ u64 last_exec_ns; -+ - u64 size; - - struct xe_pt *pt_root[XE_MAX_TILES_PER_DEVICE]; diff --git a/kernel/8211-xe-shrinker-skip-active-vm.patch.sig b/kernel/8211-xe-shrinker-skip-active-vm.patch.sig deleted file mode 100644 index 0a4ed41..0000000 Binary files a/kernel/8211-xe-shrinker-skip-active-vm.patch.sig and /dev/null differ diff --git a/kernel/8212-xe-shrinker-backup-in-kswapd-only.patch b/kernel/8212-xe-shrinker-backup-in-kswapd-only.patch deleted file mode 100644 index f77d2f2..0000000 --- a/kernel/8212-xe-shrinker-backup-in-kswapd-only.patch +++ /dev/null @@ -1,95 +0,0 @@ -diff --git a/drivers/gpu/drm/xe/xe_defaults.h b/drivers/gpu/drm/xe/xe_defaults.h ---- a/drivers/gpu/drm/xe/xe_defaults.h -+++ b/drivers/gpu/drm/xe/xe_defaults.h -@@ -23,5 +23,6 @@ - #define XE_DEFAULT_WEDGED_MODE_STR "upon-critical-error" - #define XE_DEFAULT_SVM_NOTIFIER_SIZE 512 - #define XE_DEFAULT_SHRINK_ACTIVE_MS 1000 -+#define XE_DEFAULT_SHRINK_DIRECT_BACKUP false - - #endif -diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c ---- a/drivers/gpu/drm/xe/xe_module.c -+++ b/drivers/gpu/drm/xe/xe_module.c -@@ -31,6 +31,7 @@ struct xe_modparam xe_modparam = { - .wedged_mode = XE_DEFAULT_WEDGED_MODE, - .svm_notifier_size = XE_DEFAULT_SVM_NOTIFIER_SIZE, - .shrink_active_ms = XE_DEFAULT_SHRINK_ACTIVE_MS, -+ .shrink_direct_backup = XE_DEFAULT_SHRINK_DIRECT_BACKUP, - /* the rest are 0 by default */ - }; - -@@ -43,6 +44,10 @@ MODULE_PARM_DESC(shrink_active_ms, "Do not back up a buffer object bound to a VM - "within this many ms, 0=disabled " - "[default=" __stringify(XE_DEFAULT_SHRINK_ACTIVE_MS) "]"); - -+module_param_named(shrink_direct_backup, xe_modparam.shrink_direct_backup, bool, 0600); -+MODULE_PARM_DESC(shrink_direct_backup, "Back up buffer objects in direct reclaim too, not only in kswapd " -+ "[default=" __stringify(XE_DEFAULT_SHRINK_DIRECT_BACKUP) "]"); -+ - module_param_named_unsafe(force_execlist, xe_modparam.force_execlist, bool, 0444); - MODULE_PARM_DESC(force_execlist, "Force Execlist submission"); - -diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h ---- a/drivers/gpu/drm/xe/xe_module.h -+++ b/drivers/gpu/drm/xe/xe_module.h -@@ -26,6 +26,7 @@ struct xe_modparam { - unsigned int wedged_mode; - u32 svm_notifier_size; - unsigned int shrink_active_ms; -+ bool shrink_direct_backup; - }; - - extern struct xe_modparam xe_modparam; -diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c ---- a/drivers/gpu/drm/xe/xe_shrinker.c -+++ b/drivers/gpu/drm/xe/xe_shrinker.c -@@ -4,6 +4,7 @@ - */ - - #include -+#include - - #include - #include -@@ -11,6 +12,7 @@ - #include - - #include "xe_bo.h" -+#include "xe_module.h" - #include "xe_pm.h" - #include "xe_shrinker.h" - -@@ -170,9 +172,12 @@ static int xe_shrinker_walk(struct xe_shrinker *shrinker, - return ret; - } - --static inline bool xe_shrinker_can_backup(const struct shrink_control *sc) -+static inline bool xe_shrinker_can_backup(struct xe_shrinker *shrinker, -+ const struct shrink_control *sc) - { -- return (sc->gfp_mask & __GFP_FS) && !sc->opportunistic_compaction; -+ return (sc->gfp_mask & __GFP_FS) && !sc->opportunistic_compaction && -+ (current_is_kswapd() || READ_ONCE(xe_modparam.shrink_direct_backup) || -+ !try_wait_for_completion(&shrinker->xe->pm_block)); - } - - static unsigned long -@@ -188,7 +193,7 @@ xe_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) - * wants, and it needs __GFP_FS. - */ - read_lock(&shrinker->lock); -- if (xe_shrinker_can_backup(sc)) -+ if (xe_shrinker_can_backup(shrinker, sc)) - num_pages = min_t(unsigned long, - ttm_backup_bytes_avail() >> PAGE_SHIFT, - shrinker->shrinkable_pages); -@@ -241,7 +246,7 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con - }; - bool runtime_pm; - bool purgeable; -- bool can_backup = xe_shrinker_can_backup(sc); -+ bool can_backup = xe_shrinker_can_backup(shrinker, sc); - - nr_to_scan = sc->nr_to_scan; - diff --git a/kernel/8212-xe-shrinker-backup-in-kswapd-only.patch.sig b/kernel/8212-xe-shrinker-backup-in-kswapd-only.patch.sig deleted file mode 100644 index 30e13a0..0000000 Binary files a/kernel/8212-xe-shrinker-backup-in-kswapd-only.patch.sig and /dev/null differ diff --git a/kernel/8213-xe-hibernation-writeback-gated.patch b/kernel/8213-xe-hibernation-writeback-gated.patch deleted file mode 100644 index b639c28..0000000 --- a/kernel/8213-xe-hibernation-writeback-gated.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff --git a/drivers/gpu/drm/xe/xe_defaults.h b/drivers/gpu/drm/xe/xe_defaults.h ---- a/drivers/gpu/drm/xe/xe_defaults.h -+++ b/drivers/gpu/drm/xe/xe_defaults.h -@@ -24,5 +24,6 @@ - #define XE_DEFAULT_SVM_NOTIFIER_SIZE 512 - #define XE_DEFAULT_SHRINK_ACTIVE_MS 1000 - #define XE_DEFAULT_SHRINK_DIRECT_BACKUP false -+#define XE_DEFAULT_HIBERNATE_WRITEBACK false - - #endif -diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c ---- a/drivers/gpu/drm/xe/xe_module.c -+++ b/drivers/gpu/drm/xe/xe_module.c -@@ -32,6 +32,7 @@ struct xe_modparam xe_modparam = { - .svm_notifier_size = XE_DEFAULT_SVM_NOTIFIER_SIZE, - .shrink_active_ms = XE_DEFAULT_SHRINK_ACTIVE_MS, - .shrink_direct_backup = XE_DEFAULT_SHRINK_DIRECT_BACKUP, -+ .hibernate_writeback = XE_DEFAULT_HIBERNATE_WRITEBACK, - /* the rest are 0 by default */ - }; - -@@ -48,6 +49,10 @@ module_param_named(shrink_direct_backup, xe_modparam.shrink_direct_backup, bool, - MODULE_PARM_DESC(shrink_direct_backup, "Back up buffer objects in direct reclaim too, not only in kswapd " - "[default=" __stringify(XE_DEFAULT_SHRINK_DIRECT_BACKUP) "]"); - -+module_param_named(hibernate_writeback, xe_modparam.hibernate_writeback, bool, 0600); -+MODULE_PARM_DESC(hibernate_writeback, "Write buffer objects to swap before hibernation, " -+ "integrated GPUs only [default=" __stringify(XE_DEFAULT_HIBERNATE_WRITEBACK) "]"); -+ - module_param_named_unsafe(force_execlist, xe_modparam.force_execlist, bool, 0444); - MODULE_PARM_DESC(force_execlist, "Force Execlist submission"); - -diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h ---- a/drivers/gpu/drm/xe/xe_module.h -+++ b/drivers/gpu/drm/xe/xe_module.h -@@ -27,6 +27,7 @@ struct xe_modparam { - u32 svm_notifier_size; - unsigned int shrink_active_ms; - bool shrink_direct_backup; -+ bool hibernate_writeback; - }; - - extern struct xe_modparam xe_modparam; -diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c ---- a/drivers/gpu/drm/xe/xe_pm.c -+++ b/drivers/gpu/drm/xe/xe_pm.c -@@ -26,6 +26,7 @@ - #include "xe_pcode.h" - #include "xe_printk.h" - #include "xe_pxp.h" -+#include "xe_shrinker.h" - #include "xe_sriov_vf_ccs.h" - #include "xe_sysctrl.h" - #include "xe_trace.h" -@@ -450,6 +451,9 @@ static int xe_pm_notifier_callback(struct notifier_block *nb, - if (err) - drm_dbg(&xe->drm, "Notifier evict user failed (%d)\n", err); - -+ if (action == PM_HIBERNATION_PREPARE) -+ xe_shrinker_backup_for_hibernation(xe->mem.shrinker); -+ - err = xe_bo_notifier_prepare_all_pinned(xe); - if (err) - drm_dbg(&xe->drm, "Notifier prepare pin failed (%d)\n", err); -diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c ---- a/drivers/gpu/drm/xe/xe_shrinker.c -+++ b/drivers/gpu/drm/xe/xe_shrinker.c -@@ -172,6 +172,34 @@ static int xe_shrinker_walk(struct xe_shrinker *shrinker, - return ret; - } - -+void xe_shrinker_backup_for_hibernation(struct xe_shrinker *shrinker) -+{ -+ struct ttm_operation_ctx ctx = { -+ .interruptible = false, -+ .no_wait_gpu = false, -+ }; -+ struct xe_bo_shrink_flags flags = { -+ .purge = false, -+ .writeback = true, -+ }; -+ unsigned long to_scan, scanned = 0, freed = 0; -+ ktime_t start = ktime_get(); -+ int ret; -+ -+ if (!READ_ONCE(xe_modparam.hibernate_writeback) || IS_DGFX(shrinker->xe) || -+ !ttm_backup_bytes_avail()) -+ return; -+ -+ read_lock(&shrinker->lock); -+ to_scan = shrinker->shrinkable_pages; -+ read_unlock(&shrinker->lock); -+ -+ ret = __xe_shrinker_walk(shrinker, &ctx, flags, to_scan, &scanned, &freed); -+ drm_info(&shrinker->xe->drm, -+ "Hibernation writeback: %lu of %lu pages scanned, %lu freed in %lld ms (%d)\n", -+ scanned, to_scan, freed, ktime_ms_delta(ktime_get(), start), ret); -+} -+ - static inline bool xe_shrinker_can_backup(struct xe_shrinker *shrinker, - const struct shrink_control *sc) - { -diff --git a/drivers/gpu/drm/xe/xe_shrinker.h b/drivers/gpu/drm/xe/xe_shrinker.h ---- a/drivers/gpu/drm/xe/xe_shrinker.h -+++ b/drivers/gpu/drm/xe/xe_shrinker.h -@@ -13,4 +13,6 @@ void xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long p - - int xe_shrinker_create(struct xe_device *xe); - -+void xe_shrinker_backup_for_hibernation(struct xe_shrinker *shrinker); -+ - #endif diff --git a/kernel/8213-xe-hibernation-writeback-gated.patch.sig b/kernel/8213-xe-hibernation-writeback-gated.patch.sig deleted file mode 100644 index 0a27dd0..0000000 Binary files a/kernel/8213-xe-hibernation-writeback-gated.patch.sig and /dev/null differ diff --git a/kernel/9100-asus-arm64-wmi-p16.patch b/kernel/9100-asus-arm64-wmi-p16.patch new file mode 100644 index 0000000..b69a582 --- /dev/null +++ b/kernel/9100-asus-arm64-wmi-p16.patch @@ -0,0 +1,245 @@ +--- a/drivers/platform/wmi/Kconfig ++++ b/drivers/platform/wmi/Kconfig +@@ -5,7 +5,7 @@ + + menuconfig ACPI_WMI + tristate "ACPI-WMI support" +- depends on ACPI && X86 ++ depends on ACPI + select NLS + help + This option enables support for the ACPI-WMI driver core. +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -252,64 +252,6 @@ + + If you choose to compile this driver as a module the module will be + called asus-wireless. +- +-config ASUS_ARMOURY +- tristate "ASUS Armoury driver" +- depends on ASUS_WMI +- select FW_ATTR_CLASS +- help +- Say Y here if you have a WMI aware Asus machine and would like to use the +- firmware_attributes API to control various settings typically exposed in +- the ASUS Armoury Crate application available on Windows. +- +- To compile this driver as a module, choose M here: the module will +- be called asus-armoury. +- +-config ASUS_WMI +- tristate "ASUS WMI Driver" +- depends on ACPI_WMI +- depends on ACPI_BATTERY +- depends on INPUT +- depends on HWMON +- depends on BACKLIGHT_CLASS_DEVICE +- depends on RFKILL || RFKILL = n +- depends on HOTPLUG_PCI +- depends on ACPI_VIDEO || ACPI_VIDEO = n +- depends on SERIO_I8042 || SERIO_I8042 = n +- select INPUT_SPARSEKMAP +- select LEDS_CLASS +- select NEW_LEDS +- select ACPI_PLATFORM_PROFILE +- help +- Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new +- Asus Notebooks). +- +- To compile this driver as a module, choose M here: the module will +- be called asus-wmi. +- +-config ASUS_WMI_DEPRECATED_ATTRS +- bool "BIOS option support in WMI platform (DEPRECATED)" +- depends on ASUS_WMI +- default y +- help +- Say Y to expose the configurable BIOS options through the asus-wmi +- driver. +- +- This can be used with or without the asus-armoury driver which +- has the same attributes, but more, and better features. +- +-config ASUS_NB_WMI +- tristate "Asus Notebook WMI Driver" +- depends on ASUS_WMI +- help +- This is a driver for newer Asus notebooks. It adds extra features +- like wireless radio and bluetooth control, leds, hotkeys, backlight... +- +- For more information, see +- +- +- If you have an ACPI-WMI compatible Asus Notebook, say Y or M +- here. + + config ASUS_TF103C_DOCK + tristate "Asus TF103C 2-in-1 keyboard dock" +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -33,9 +33,6 @@ + # ASUS + obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o + obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o +-obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o +-obj-$(CONFIG_ASUS_WMI) += asus-wmi.o +-obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o + obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o + obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o + obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -17,6 +17,8 @@ + + source "drivers/platform/x86/Kconfig" + ++source "drivers/platform/asus/Kconfig" ++ + source "drivers/platform/arm64/Kconfig" + + source "drivers/platform/raspberrypi/Kconfig" +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -4,6 +4,7 @@ + # + + obj-$(CONFIG_X86) += x86/ ++obj-$(CONFIG_ASUS_WMI) += asus/ + obj-$(CONFIG_LOONGARCH) += loongarch/ + obj-$(CONFIG_MELLANOX_PLATFORM) += mellanox/ + obj-$(CONFIG_MIPS) += mips/ +--- a/drivers/platform/asus/Kconfig ++++ b/drivers/platform/asus/Kconfig +@@ -0,0 +1,61 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ASUS platform drivers shared across architectures ++ ++config ASUS_ARMOURY ++ tristate "ASUS Armoury driver" ++ depends on ASUS_WMI ++ select FW_ATTR_CLASS ++ help ++ Say Y here if you have a WMI aware Asus machine and would like to use the ++ firmware_attributes API to control various settings typically exposed in ++ the ASUS Armoury Crate application available on Windows. ++ ++ To compile this driver as a module, choose M here: the module will ++ be called asus-armoury. ++ ++config ASUS_WMI ++ tristate "ASUS WMI Driver" ++ depends on ACPI_WMI ++ depends on ACPI_BATTERY ++ depends on INPUT ++ depends on HWMON ++ depends on BACKLIGHT_CLASS_DEVICE ++ depends on RFKILL || RFKILL = n ++ depends on HOTPLUG_PCI ++ depends on ACPI_VIDEO || ACPI_VIDEO = n ++ depends on SERIO_I8042 || SERIO_I8042 = n ++ select INPUT_SPARSEKMAP ++ select LEDS_CLASS ++ select NEW_LEDS ++ select ACPI_PLATFORM_PROFILE ++ help ++ Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new ++ Asus Notebooks). ++ ++ To compile this driver as a module, choose M here: the module will ++ be called asus-wmi. ++ ++config ASUS_WMI_DEPRECATED_ATTRS ++ bool "BIOS option support in WMI platform (DEPRECATED)" ++ depends on ASUS_WMI ++ default y ++ help ++ Say Y to expose the configurable BIOS options through the asus-wmi ++ driver. ++ ++ This can be used with or without the asus-armoury driver which ++ has the same attributes, but more, and better features. ++ ++config ASUS_NB_WMI ++ tristate "Asus Notebook WMI Driver" ++ depends on ASUS_WMI ++ help ++ This is a driver for newer Asus notebooks. It adds extra features ++ like wireless radio and bluetooth control, leds, hotkeys, backlight... ++ ++ For more information, see ++ ++ ++ If you have an ACPI-WMI compatible Asus Notebook, say Y or M ++ here. ++ +--- a/drivers/platform/asus/Makefile ++++ b/drivers/platform/asus/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ASUS WMI drivers ++obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o ++obj-$(CONFIG_ASUS_WMI) += asus-wmi.o ++obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o +--- a/drivers/platform/asus/asus-armoury.c ++++ b/drivers/platform/asus/asus-armoury.c +@@ -0,0 +1 @@ ++#include "../x86/asus-armoury.c" +--- a/drivers/platform/asus/asus-wmi.c ++++ b/drivers/platform/asus/asus-wmi.c +@@ -0,0 +1 @@ ++#include "../x86/asus-wmi.c" +--- a/drivers/platform/asus/asus-nb-wmi.c ++++ b/drivers/platform/asus/asus-nb-wmi.c +@@ -0,0 +1 @@ ++#include "../x86/asus-nb-wmi.c" +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -353,6 +354,13 @@ + + /* WMI ************************************************************************/ + ++/* The ProArt P16 firmware exposes RSOC status as a two-dword buffer. */ ++static bool asus_wmi_p16_extended_rsoc(void) ++{ ++ return dmi_match(DMI_SYS_VENDOR, "ASUS") && ++ dmi_match(DMI_PRODUCT_NAME, "ProArt P16 H7607BA"); ++} ++ + static int asus_wmi_evaluate_method3(u32 method_id, + u32 arg0, u32 arg1, u32 arg2, u32 *retval) + { +@@ -381,6 +389,12 @@ + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32) obj->integer.value; ++ else if (obj && obj->type == ACPI_TYPE_BUFFER && ++ obj->buffer.length == 8 && ++ method_id == ASUS_WMI_METHODID_DSTS && ++ arg0 == ASUS_WMI_DEVID_RSOC && ++ asus_wmi_p16_extended_rsoc()) ++ tmp = get_unaligned_le32(obj->buffer.pointer); + + pr_debug("Result: 0x%08x\n", tmp); + if (retval) +@@ -1634,6 +1648,12 @@ + if (device_create_file(&battery->dev, + &dev_attr_charge_control_end_threshold)) + return -ENODEV; ++ ++ /* Do not change the existing firmware limit until userspace requests one. */ ++ if (asus_wmi_p16_extended_rsoc()) { ++ charge_end_threshold = -1; ++ return 0; ++ } + + /* The charge threshold is only reset when the system is power cycled, + * and we can't read the current threshold, however the majority of diff --git a/kernel/9101-p16-virtual-gpio.patch b/kernel/9101-p16-virtual-gpio.patch new file mode 100644 index 0000000..d90b330 --- /dev/null +++ b/kernel/9101-p16-virtual-gpio.patch @@ -0,0 +1,234 @@ +--- a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h ++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h +@@ -1912,6 +1912,169 @@ + DRV_GRP4, + MTK_FUNCTION(0, "B_GPIO181"), + MTK_FUNCTION(1, "O_GPU_PWRGOOD") ++ ), ++ /* EINT-only input lines; firmware uses GPIO190 for MSFW1111. */ ++ MTK_PIN( ++ 182, "GPIO182", ++ MTK_EINT_FUNCTION(0, 182), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 183, "GPIO183", ++ MTK_EINT_FUNCTION(0, 183), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 184, "GPIO184", ++ MTK_EINT_FUNCTION(0, 184), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 185, "GPIO185", ++ MTK_EINT_FUNCTION(0, 185), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 186, "GPIO186", ++ MTK_EINT_FUNCTION(0, 186), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 187, "GPIO187", ++ MTK_EINT_FUNCTION(0, 187), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 188, "GPIO188", ++ MTK_EINT_FUNCTION(0, 188), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 189, "GPIO189", ++ MTK_EINT_FUNCTION(0, 189), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 190, "GPIO190", ++ MTK_EINT_FUNCTION(0, 190), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 191, "GPIO191", ++ MTK_EINT_FUNCTION(0, 191), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 192, "GPIO192", ++ MTK_EINT_FUNCTION(0, 192), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 193, "GPIO193", ++ MTK_EINT_FUNCTION(0, 193), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 194, "GPIO194", ++ MTK_EINT_FUNCTION(0, 194), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 195, "GPIO195", ++ MTK_EINT_FUNCTION(0, 195), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 196, "GPIO196", ++ MTK_EINT_FUNCTION(0, 196), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 197, "GPIO197", ++ MTK_EINT_FUNCTION(0, 197), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 198, "GPIO198", ++ MTK_EINT_FUNCTION(0, 198), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 199, "GPIO199", ++ MTK_EINT_FUNCTION(0, 199), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 200, "GPIO200", ++ MTK_EINT_FUNCTION(0, 200), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 201, "GPIO201", ++ MTK_EINT_FUNCTION(0, 201), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 202, "GPIO202", ++ MTK_EINT_FUNCTION(0, 202), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 203, "GPIO203", ++ MTK_EINT_FUNCTION(0, 203), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 204, "GPIO204", ++ MTK_EINT_FUNCTION(0, 204), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 205, "GPIO205", ++ MTK_EINT_FUNCTION(0, 205), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 206, "GPIO206", ++ MTK_EINT_FUNCTION(0, 206), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 207, "GPIO207", ++ MTK_EINT_FUNCTION(0, 207), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) ++ ), ++ MTK_PIN( ++ 208, "GPIO208", ++ MTK_EINT_FUNCTION(0, 208), ++ DRV_FIXED, ++ MTK_FUNCTION(0, NULL) + ), + }; + +--- a/drivers/pinctrl/mediatek/pinctrl-paris.c ++++ b/drivers/pinctrl/mediatek/pinctrl-paris.c +@@ -107,6 +107,9 @@ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + ++ if (mtk_is_virt_gpio(hw, pin)) ++ return 0; ++ + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, +@@ -120,6 +123,9 @@ + struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); + const struct mtk_pin_desc *desc; + ++ if (mtk_is_virt_gpio(hw, pin)) ++ return input ? 0 : -ENOTSUPP; ++ + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + + /* hardware would take 0 as input direction */ +@@ -136,6 +142,9 @@ + + if (pin >= hw->soc->npins) + return -EINVAL; ++ ++ if (mtk_is_virt_gpio(hw, pin)) ++ return -ENOTSUPP; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + +@@ -271,6 +280,9 @@ + + if (pin >= hw->soc->npins) + return -EINVAL; ++ ++ if (mtk_is_virt_gpio(hw, pin)) ++ return -ENOTSUPP; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; + +@@ -879,6 +891,9 @@ + const struct mtk_pin_desc *desc; + int value, err; + ++ if (mtk_is_virt_gpio(hw, gpio)) ++ return -ENOTSUPP; ++ + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); +@@ -892,6 +907,9 @@ + { + struct mtk_pinctrl *hw = gpiochip_get_data(chip); + const struct mtk_pin_desc *desc; ++ ++ if (mtk_is_virt_gpio(hw, gpio)) ++ return -ENOTSUPP; + + desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; + diff --git a/kernel/9103-asus-capability-aware-initialization.patch b/kernel/9103-asus-capability-aware-initialization.patch new file mode 100644 index 0000000..03d993a --- /dev/null +++ b/kernel/9103-asus-capability-aware-initialization.patch @@ -0,0 +1,41 @@ +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -3656,7 +3656,10 @@ + + *available = false; + +- if (asus->fan_type == FAN_TYPE_NONE) ++ /* Each optional curve belongs to its own fan capability. */ ++ if ((fan_dev == ASUS_WMI_DEVID_CPU_FAN_CURVE && asus->fan_type == FAN_TYPE_NONE) || ++ (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE && asus->gpu_fan_type == FAN_TYPE_NONE) || ++ (fan_dev == ASUS_WMI_DEVID_MID_FAN_CURVE && asus->mid_fan_type == FAN_TYPE_NONE)) + return 0; + + err = fan_curve_get_factory_default(asus, fan_dev); +@@ -5275,7 +5278,7 @@ + goto fail_wmi_handler; + } + +- if (asus->driver->i8042_filter) { ++ if (IS_REACHABLE(CONFIG_SERIO_I8042) && asus->driver->i8042_filter) { + err = i8042_install_filter(asus->driver->i8042_filter, NULL); + if (err) + pr_warn("Unable to install key filter - %d\n", err); +@@ -5314,7 +5317,7 @@ + struct asus_wmi *asus; + + asus = platform_get_drvdata(device); +- if (asus->driver->i8042_filter) ++ if (IS_REACHABLE(CONFIG_SERIO_I8042) && asus->driver->i8042_filter) + i8042_remove_filter(asus->driver->i8042_filter); + wmi_remove_notify_handler(asus->driver->event_guid); + asus_wmi_backlight_exit(asus); +@@ -5424,7 +5427,7 @@ + return 0; + } + +-#if defined(CONFIG_SUSPEND) ++#if defined(CONFIG_SUSPEND) && defined(CONFIG_X86) + static void asus_ally_s2idle_restore(void) + { + if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_ENABLED) { diff --git a/kernel/9104-spi-hid-acpi-reset-handle.patch b/kernel/9104-spi-hid-acpi-reset-handle.patch new file mode 100644 index 0000000..ba0c926 --- /dev/null +++ b/kernel/9104-spi-hid-acpi-reset-handle.patch @@ -0,0 +1,21 @@ +--- a/drivers/hid/spi-hid/spi-hid-acpi.c ++++ b/drivers/hid/spi-hid/spi-hid-acpi.c +@@ -185,7 +185,17 @@ + struct spi_hid_acpi_config, + ops); + +- return device_reset(&conf->adev->dev); ++ acpi_status status; ++ ++ /* The ACPI namespace device is not its own physical-device companion. */ ++ status = acpi_evaluate_object(conf->adev->handle, "_RST", NULL, NULL); ++ if (ACPI_FAILURE(status)) { ++ acpi_handle_err(conf->adev->handle, "Failed to execute _RST: %s\n", ++ acpi_format_exception(status)); ++ return -EIO; ++ } ++ ++ return 0; + } + + static void spi_hid_acpi_sleep_minimal_reset_delay(struct spihid_ops *ops) diff --git a/kernel/PKGBUILD b/kernel/PKGBUILD deleted file mode 100644 index 06c6b0b..0000000 --- a/kernel/PKGBUILD +++ /dev/null @@ -1,1498 +0,0 @@ -# Maintainer: The Omarchy Authors -# Adopted from the Arch Linux linux package. - -# Versioned P16 package: preserve earlier working kernels alongside this build. -pkgbase=linux-p16-asus-25 -_kernel=linux-p16-asus-25 -pkgver=7.2.8 -pkgrel=25 -pkgdesc='Omarchy kernel for ASUS ProArt P16 H7607BA.300 (N1X, ACPI, SPI HID, ASUS WMI)' -url='https://omarchy.org' -arch=( - aarch64 -) -license=(GPL-2.0-only) -makedepends=( - bc - binutils - cpio - gettext - glibc - libelf - libgcc - openssl - pahole - perl - python - rust - rust-bindgen - rust-src - tar - xxhash - xz - zlib - zstd -) -options=( - !debug - !strip -) -_major=${pkgver%%.*} -if [[ $pkgver == *rc* ]]; then - _base=${pkgver%rc*} - _prev=${_base%.*}.$(( ${_base##*.} - 1 )) - _srcname=linux-${_prev%.0} - _rcpatch=patch-${pkgver//rc/-rc} -else - _srcname=linux-$pkgver -fi -source=( - https://cdn.kernel.org/pub/linux/kernel/v${_major}.x/${_srcname}.tar.{xz,sign} - ${_rcpatch:+https://cdn.kernel.org/pub/linux/kernel/v${_major}.x/stable-review/${_rcpatch}.xz} - ${_rcpatch:+https://cdn.kernel.org/pub/linux/kernel/v${_major}.x/stable-review/${_rcpatch}.sign} - 0010-archlinux-base.patch{,.sig} - 0011-kbuild-optimize-for-performance-o3.patch{,.sig} - 0110-bore-6.8.0.patch{,.sig} - 0120-tlbpull.patch{,.sig} - 0121-smp-preempt.patch{,.sig} - 0130-sched-detach-tasks.patch{,.sig} - 0140-sched-always-inline.patch{,.sig} - 0141-sched-urgent-fixes.patch{,.sig} - 0143-sched-hybrid-cluster-balancing.patch{,.sig} - 0144-sched-nohz-idle-core.patch{,.sig} - 0150-adios-3.2.0.patch{,.sig} - 0210-pm-updates.patch{,.sig} - 0211-pm-fixes-1.patch{,.sig} - 0212-pm-fixes-2.patch{,.sig} - 0213-pm-fixes-3.patch{,.sig} - 0220-x86-amd-zen5-tlb-sizes.patch{,.sig} - 0250-zsmalloc.patch{,.sig} - 0260-mglru-exec-protect.patch{,.sig} - 0270-ksm-rmap-walk.patch{,.sig} - 0280-mm-updates.patch{,.sig} - 0281-mm-no-deferred-kernel-page-table-free-at-boot.patch{,.sig} - 0290-zstd-bmi2-fallback-aliases.patch{,.sig} - 0291-zstd-bmi2-cpu-feature-dispatch.patch{,.sig} - 0292-crypto-zstd-defer-cstream-init.patch{,.sig} - 0293-crypto-zstd-defer-dstream-init.patch{,.sig} - 0295-af-alg-restrict.patch{,.sig} - 0300-btrfs.patch{,.sig} - 0301-btrfs-fixes-1.patch{,.sig} - 0302-btrfs-zstd-decompress-direct-to-page.patch{,.sig} - 0303-btrfs-fixes-2.patch{,.sig} - 0304-btrfs-fixes-3.patch{,.sig} - 0310-fuse-eof-zeroing.patch{,.sig} - 0311-fuse-perf.patch{,.sig} - 0312-fuse-writethrough-uptodate.patch{,.sig} - 0313-fuse-background-wakeup.patch{,.sig} - 0320-vfs-open-consume-path-reference.patch{,.sig} - 0350-drm-edid-populate-monitor-range-from-displayid-adaptive-sync.patch{,.sig} - 0360-gpu-mem-cgroup.patch{,.sig} - 0400-drm-i915-alpm-limit-pr-alpm-to-panel-replay.patch{,.sig} - 0401-psr2-early-transport-panels.patch{,.sig} - 0402-drm-i915-quirk-panel-replay-exit-on-flush.patch{,.sig} - 0403-drm-i915-quirk-dell-xps14-ptl-panel-replay-exit-on-flush.patch{,.sig} - 0404-drm-i915-quirk-dell-xps16-ptl-panel-replay-exit-on-flush.patch{,.sig} - 0405-drm-i915-quirk-dell-xps13-dx13260-ptl-psr1-only.patch{,.sig} - 0406-drm-i915-quirk-dell-xps13-dx13260-wcl-panel-replay-exit-on-flush.patch{,.sig} - 0411-drm-xe-display-no-stolen-framebuffers.patch{,.sig} - 0420-safe-window.patch{,.sig} - 0430-fbc.patch{,.sig} - 0440-xe3-peak-bandwidth.patch{,.sig} - 0442-drm-i915-psr-clear-stale-sel-fetch-bits.patch{,.sig} - 0443-drm-i915-dsb-delayed-vblank-scanline-shift.patch{,.sig} - 0444-drm-i915-vrr-dc-balance-off-by-default.patch{,.sig} - 0450-amd-hdmi-vrr-allm.patch{,.sig} - 0451-amd-vtem-tmds-links.patch{,.sig} - 0452-amd-hdmi-frl-default.patch{,.sig} - 0453-amd-vtem-null-sink.patch{,.sig} - 0454-amd-hdmi-frl-status-polling.patch{,.sig} - 0455-amd-hdmi-frl-cap-on-nondestructive-verify.patch{,.sig} - 0456-amd-dml-frl-compressed-cap-check.patch{,.sig} - 0460-vesa-displayid-dsc-bpp.patch{,.sig} - 0461-vesa-dsc-passthru-mode-match-fix.patch{,.sig} - 0472-amdgpu-userq-post-reset-error.patch{,.sig} - 0474-amd-display-oled-vesa-backlight.patch{,.sig} - 0475-revert-drm-i915-dp-as-sdp-vrr-or-pr.patch{,.sig} - 0476-amd-display-ycbcr420-only-modes.patch{,.sig} - 0477-amd-display-irq-atomic-rmw.patch{,.sig} - 0478-amd-freesync-vcp-code-check-hdmi-pcon.patch{,.sig} - 0479-amd-hdmi-allm-hf-vsif-in-vsp-infopacket.patch{,.sig} - 0510-sound-updates.patch{,.sig} - 0511-asoc-updates.patch{,.sig} - 0512-sound-fixes-1.patch{,.sig} - 0513-asoc-fixes-1.patch{,.sig} - 0514-sound-fixes-2.patch{,.sig} - 0515-xps13-sof-quirk.patch{,.sig} - 0516-rt766-stream-config-type.patch{,.sig} - 0517-hda-realtek-rog-strix-g733zw-speakers.patch{,.sig} - 0518-asoc-amd-yc-acer-aspire-a314-23p.patch{,.sig} - 0522-sound-fixes-3.patch{,.sig} - 0523-asoc-fixes-2.patch{,.sig} - 0524-sound-fixes-4.patch{,.sig} - 0525-asoc-fixes-3.patch{,.sig} - 0526-sof-amd-acp7x-suspend-unknown-revision.patch{,.sig} - 0527-sound-fixes-5.patch{,.sig} - 0528-asoc-fixes-4.patch{,.sig} - 0541-cvs-nova-lake-acpi-id.patch{,.sig} - 0542-media-cvs-wake-irq-without-claiming-gpio.patch{,.sig} - 0543-media-laptop-cameras.patch{,.sig} - 0544-ipu-bridge-lenovo-x9-upside-down.patch{,.sig} - 0545-ipu-bridge-dell-16-premium-da16250-upside-down.patch{,.sig} - 0546-ipu-bridge-samsung-galaxy-book5-pro-360-upside-down.patch{,.sig} - 0547-int3472-imx471-vana-power-enable.patch{,.sig} - 0548-media-cvs-sensor-node-in-bound-callback.patch{,.sig} - 0549-media-imx471-analog-gain-max-960.patch{,.sig} - 0560-input-updates.patch{,.sig} - 0561-input-fixes.patch{,.sig} - 0562-hid-fixes.patch{,.sig} - 0563-input-fixes-2.patch{,.sig} - 0565-i2c-asue140d-touchpad-100khz.patch{,.sig} - 0566-hid-asus-no-keyboard-init-reports-to-touchpads.patch{,.sig} - 0601-thunderbolt-updates.patch{,.sig} - 0602-thunderbolt-fixes.patch{,.sig} - 0603-usb-updates.patch{,.sig} - 0604-xhci-fixes.patch{,.sig} - 0605-thunderbolt-pcie-rescan-after-tunnel.patch{,.sig} - 0606-thunderbolt-fixes-2.patch{,.sig} - 0607-usb-fixes.patch{,.sig} - 0620-usb-string-sanitize.patch{,.sig} - 0650-wireguard-tstamp-type.patch{,.sig} - 0660-btusb-mediatek-mt7922-13d3-3625.patch{,.sig} - 0662-iwlwifi-mld-skip-tx-when-firmware-dead.patch{,.sig} - 0663-btintel-pcie-serialize-reset-type.patch{,.sig} - 0664-btintel-pcie-stale-cache-in-dxstate-fallback.patch{,.sig} - 0665-btintel-pcie-pm-flow-s0ix-s3-s4.patch{,.sig} - 0666-btintel-pcie-verify-serialize-dstate.patch{,.sig} - 0667-btintel-pcie-gp0-cause-w1c-write.patch{,.sig} - 0668-btintel-pcie-dstate-races.patch{,.sig} - 0669-btintel-version-tlv-parse-errors.patch{,.sig} - 0670-bluetooth-fixes.patch{,.sig} - 0700-pci-target-speed-quirk.patch{,.sig} - 0701-pci-amd-enhanced-atomics.patch{,.sig} - 0702-ahci-jmb585-32bit-dma-revert.patch{,.sig} - 0703-pci-vmd-scan-bios-enumerated-devices.patch{,.sig} - 0704-pci-vmd-meteor-lake-mtl016-flush.patch{,.sig} - 0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch{,.sig} - 0711-iommu-amd-perfopt-support.patch{,.sig} - 0712-drm-amdgpu-perfopt-in-identity-domain.patch{,.sig} - 0740-hwmon-updates.patch{,.sig} - 0741-hwmon-fixes-1.patch{,.sig} - 0742-hwmon-fixes-2.patch{,.sig} - 0770-acpi-pm-acer-swift3-sf314-56g-power-resource.patch{,.sig} - 0800-platform-updates.patch{,.sig} - 0801-amd-pmf-util-unbind-use-after-free.patch{,.sig} - 0802-platform-fixes.patch{,.sig} - 0803-acpi-battery-hook-api-acpi-prefix.patch{,.sig} - 0804-acpi-battery-unified-hooks-acpi-sbs.patch{,.sig} - 0805-hwmon-applesmc-charge-control-end-threshold.patch{,.sig} - 0850-futex-wait-multiple.patch{,.sig} - 0851-futex-wait-multiple-fixes.patch{,.sig} - 0852-futex-wait-multiple-abi-fixes.patch{,.sig} - 0860-module-add-module-kallsyms-on-each-addr.patch{,.sig} - 0861-ftrace-drop-weak-function-locations-of-modules.patch{,.sig} - 8204-mm-opportunistic-compaction.patch{,.sig} - 8205-mm-hint-uses-allocation-order.patch{,.sig} - 8206-mm-carry-order-and-hint-in-one-word.patch{,.sig} - 8207-mm-classify-huge-page-allocations-as-failable.patch{,.sig} - 8209-xe-shrinker-use-opportunistic-hint.patch{,.sig} - 8210-xe-shrinker-single-backup-decision.patch{,.sig} - 8211-xe-shrinker-skip-active-vm.patch{,.sig} - 8212-xe-shrinker-backup-in-kswapd-only.patch{,.sig} - 8213-xe-hibernation-writeback-gated.patch{,.sig} - # NVIDIA N1x platform support from NVIDIA's Ubuntu-nvidia-7.0-7.0.0-1021.21 - # SAUCE (MediaTek MT8901 I/O, FF-A EC, power management, SoundWire audio, - # DMA-mode IOMMU for the integrated GPU), - # rebased onto this kernel, and the ASUS ProArt P14 keyboard. - 1000-n1x-mediatek-platform.patch - 1010-n1x-ffa-ec.patch - 1011-n1x-dell-xps16-battery-status.patch - 1012-n1x-acpi-thermal-skip-power-telemetry.patch - 1013-n1x-dell-arm64-hotkeys.patch - 1020-n1x-power.patch - 1021-ACPI-processor_idle-let-LPI-states-freeze-the-tick-in-suspend-to-idle.patch - 1023-ACPI-processor_idle-let-suspend-to-idle-reach-the-NVIDIA-N1x-DRIPS-state.patch - 1024-PCI-quirks-let-the-NVIDIA-N1x-NVMe-link-reach-L1.2-so-the-SoC-can-sleep.patch - 1030-n1x-audio.patch - 1031-ALSA-hda-acpi-add-runtime-PM-suspend-resume-to-the-ACPI-controller.patch - 1032-ASoC-cs35l56-Wait-for-firmware-timer-expiry-before-system-suspend.patch - 1034-soundwire-mediatek-close-the-interrupt-gate-before-quiescing-a-link.patch - 1040-n1x-gpu-iommu.patch - 1060-ASoC-mediatek-mt8901-give-the-card-the-ACPI-subsystem-ID.patch - 1070-Revert-NVIDIA-SAUCE-usb-typec-ucsi-acpi-disable-USB4-via-vendor-_DSM-at-probe.patch - 1071-usb-typec-ucsi-acpi-query-the-_DSM-functions-before-using-them.patch - 1072-soc-mediatek-power_wrap-make-the-USB4-resource-release-optional.patch - 1073-thunderbolt-check-for-a-PCI-NHI-before-treating-it-as-one.patch - 1074-thunderbolt-nhi-let-a-single-wired-interrupt-service-the-rings.patch - 1075-thunderbolt-nhi-share-teardown-and-export-the-NHI-core.patch - 1076-soc-mediatek-power_wrap-report-whether-the-USB4-resources-are-released.patch - 1077-thunderbolt-add-a-driver-for-USB4-host-interfaces-described-by-ACPI.patch - 1078-PCI-Keep-hotplug-bridges-below-a-switch-to-their-share-of-bus-numbers.patch - 1079-thunderbolt-quirks-disable-CL-states-on-the-NVIDIA-N1x-host-router.patch - 1080-thunderbolt-keep-the-NVIDIA-N1x-routers-awake-in-system-sleep.patch - 1081-thunderbolt-platform-leave-the-N1x-host-routers-powered.patch - 1082-thunderbolt-retry-the-NVIDIA-N1x-DP-IN-adapters-after-a-DPRX-failure.patch - 1083-usb-typec-ucsi-retry-init-when-the-PPM-answers-early-commands-incorrectly.patch - 1084-usb-typec-ucsi-allow-retries-of-ucsi_resume_work.patch - 1085-thunderbolt-keep-the-tunnels-of-routers-kept-awake-in-system-sleep.patch - 1086-thunderbolt-space-out-the-NVIDIA-N1x-DP-tunnel-teardowns.patch - 1087-PCI-ACPI-Mark-USB4-tunneled-devices-removable-on-every-ACPI-platform.patch - 1088-iommu-Give-external-facing-ports-the-domain-of-untrusted-devices.patch - 1089-thunderbolt-platform-report-IOMMU-DMA-protection-for-the-NVIDIA-N1x.patch - 1090-sspm_ci-distinguish-not-submitted-from-completion-unknown.patch - 1091-PCI-harden-MediaTek-Power-Wrap-system-sleep.patch - 1092-usb-xhci-mtk-v2-add-ACPI-power-management-support.patch - 1093-usb-xhci-add-XHCI_DELAY_BEFORE_CRS-quirk-for-MediaTek-v2.patch - 1094-spi-mt65xx-enable-ACPI-and-power-management.patch - 1095-i2c-mt65xx-enable-suspend-and-resume.patch - 1096-pinctrl-mt8901-sync-wake-EINT-event-mask.patch - 1097-usb-xhci-plat-use-firmware-managed-USB-without-SSPM.patch - 1098-soc-mediatek-gate-SSPM-dependent-ACPI-paths.patch - 1099-soc-mediatek-power_wrap-keep-DGX-Spark-DVFSRC-policy.patch - 1100-HID-asus-support-the-Zenbook-A16-UX3607OA-keyboard.patch - 1101-HID-asus-drive-the-0B05-4B42-keyboard-backlight-without-asus-wmi.patch - 1102-HID-asus-host-controlled-Fn-lock-for-the-0B05-4B42-keyboard.patch - 1103-HID-asus-disable-OOBE-mode-on-the-ProArt-P14-keyboard-too.patch - 1104-HID-asus-turn-the-keyboard-backlight-off-for-sleep-without-asus-wmi.patch - 1110-tools-linux-types.h-Add-128-bit-integer-types-for-arm64-UAPI-structures.patch - 2000-media-iris-reset-AHB-bridge-before-enabling-HW-mode.patch - 2001-ASoC-qcom-q6apm-lpass-dais-Reset-the-codec-DMA-channel-map-in-hw_params.patch - 2002-power-supply-qcom_battmgr-Notify-charger-supplies-of-online-changes.patch - 2003-wifi-ath12k-don-t-count-a-vdev-restart-as-a-started-.patch - 2004-media-iris-Fix-out-of-bounds-read-in-timestamp-metad.patch - 2005-Revert-media-qcom-iris-use-disable_irq-during-power-.patch - 2006-media-qcom-iris-Wait-for-threaded-IRQ-completion-dur.patch - 2100-irqchip-qcom-pdc-Restructure-version-support.patch - 2101-irqchip-qcom-pdc-Move-all-static-variables-to-struct.patch - 2102-irqchip-qcom-pdc-Differentiate-between-direct-SPI-an.patch - 2103-irqchip-qcom-pdc-Configure-PDC-to-pass-through-mode.patch - 2104-irqchip-qcom-pdc-Fix-kernel-doc-for-qcom_pdc_gic_sec.patch - 2105-arm64-dts-qcom-x1e80100-Reduce-OS-PDC-DRV-span-to-0x.patch - 2106-pinctrl-qcom-Acknowledge-IRQs-for-PDC-interrupt-cont.patch - 2107-Revert-pinctrl-qcom-x1e80100-Bypass-PDC-wakeup-paren.patch - 2108-arm64-dts-qcom-x1e80100-Add-deepest-idle-state.patch - 2110-Documentation-Correction-in-HID-output_report-callba.patch - 2111-HID-Add-BUS_SPI-support-and-define-HID_SPI_DEVICE-ma.patch - 2112-HID-spi-hid-add-transport-driver-skeleton-for-HID-ov.patch - 2113-HID-spi-hid-add-spi-hid-driver-HID-layer.patch - 2114-HID-spi-hid-add-HID-SPI-protocol-implementation.patch - 2115-HID-spi_hid-add-spi_hid-traces.patch - 2116-HID-spi_hid-add-ACPI-support-for-SPI-over-HID.patch - 2117-HID-spi_hid-add-device-tree-support-for-SPI-over-HID.patch - 2118-dt-bindings-input-Document-hid-over-spi-DT-schema.patch - 2119-HID-spi-hid-add-power-management-implementation.patch - 2120-HID-spi-hid-add-panel-follower-support.patch - 2121-dt-bindings-media-qcom-x1e80100-camss-correct-resour.patch - 2122-dt-bindings-media-add-OV13858-and-VD55G0-sensors.patch - 2123-media-qcom-camss-unwind-failed-stream-starts.patch - 2124-media-qcom-camss-support-X1E80100-C-PHY-links.patch - 2125-Documentation-media-record-Surface-Pro-11-camera-pro.patch - 2126-wifi-ath12k-Add-support-for-disabling-rfkill-via-dev.patch - 2127-arm64-dts-qcom-denali-preserve-ath12k-rfkill-quirk.patch - 2128-dt-bindings-net-qcom-ath12k-document-disable-rfkill.patch - 2129-media-qcom-camss-restore-observed-Denali-C-PHY-seque.patch - 2130-platform-surface-recheck-tablet-mode-after-resume.patch - 2131-platform-surface-resync-tablet-mode-on-KIP-connectio.patch - 2132-platform-surface-retry-KIP-cover-state-while-settlin.patch - 2133-power-supply-qcom_battmgr-preserve-charge-limits.patch - 2134-media-ov13858-retry-the-first-SCCB-write-after-power.patch - 2135-drm-msm-dp-restrict-the-EDID-read-workaround-to-EDID.patch - 2136-drm-msm-dp-attach-the-AUX-i2c-adapter-to-the-connect.patch - 2137-irqchip-qcom-pdc-report-the-selected-X1E-mode.patch - 2138-soc-qcom-smp2p-reset-inbound-state-only-on-restart.patch - 2139-arm64-dts-qcom-x1e80100-drop-QCE-sleep-bandwidth-vot.patch - 2140-platform-surface-aggregator_registry-add-KIP-OOB-pai.patch - 2141-Bluetooth-SMP-implement-LE-legacy-out-of-band-pairin.patch - 2142-drm-msm-dpu-re-program-colour-processing-blocks-on-t.patch - 2143-HID-surface-hid-suspend-HID-clients-on-shutdown.patch - 2144-arm64-skip-the-EFI-reset-path-when-restarting-from-a.patch - 2145-drm-msm-dpu-Reassert-core-clock-rate-on-runtime-resu.patch - 2146-drm-msm-dp-use-direct-SDP-flush-for-PSR.patch - 2147-ASoC-qcom-x1e80100-raise-the-speaker-volume-ceiling-.patch - 2148-Bluetooth-hci_qca-Drop-unused-event-during-BT-on.patch - 2149-Bluetooth-SCO-accept-incoming-eSCO-with-Enhanced-Acc.patch - 2150-wifi-ath12k-avoid-sleeping-PCI-wakeup-during-panic-r.patch - 2151-arm64-dts-qcom-hamoa-Drop-cluster_cl5-idle-state-fro.patch - 2152-arm64-qcom-add-Surface-Pro-11-platform-support.patch - 2153-HID-spi-fix-G6-touch-digitizer-module-alias.patch - 2154-ASoC-wsa884x-recover-PA-faults-and-apply-SP11-2S-4-o.patch - 2155-Bluetooth-hci_qca-keep-the-WCN6750-baudrate-event-dr.patch - 2156-drm-msm-dpu-disable-the-clocks-if-the-core-rate-rest.patch - 2160-arm64-dts-qcom-x1e80100-Add-CAMCC-block-definition.patch - 2161-arm64-dts-qcom-hamoa-add-camera-subsystem-nodes.patch - 2162-media-i2c-add-Surface-Pro-11-camera-sensors.patch - 2163-arm64-dts-qcom-enable-Surface-Pro-11-cameras.patch - 2164-arm64-dts-qcom-denali-enable-verified-IR-illuminator.patch - 2165-media-imx681-write-exposure-through-the-24-bit-latch.patch - 2166-media-imx681-expose-analogue-gain-as-a-linear-value.patch - 2167-media-i2c-vd55g0-power-the-sensor-off-only-once-when.patch - 2168-media-i2c-vd55g0-register-as-a-sensor-subdevice.patch - 2169-arm64-dts-qcom-x1-microsoft-denali-describe-the-came.patch - 2170-drm-msm-adreno-a6xx-Mark-cxpd-device_link-as-statele.patch - 2171-drm-msm-Centralize-the-standalone-drm-device-check-f.patch - 2172-drm-msm-adreno-Fix-invalid-drvdata-typecast-in-adren.patch - 2173-drm-msm-Always-use-component-model-for-standalone-GP.patch - 2174-drm-msm-Attach-a-driver-to-the-GMU.patch - 2175-serial-qcom-geni-add-force-suspend-resume-to-system-.patch - 2176-soc-qcom-add-ADSP-power-limits-Modern-Standby-notifi.patch - 2177-PCI-allow-D3-for-hotplug-capable-root-ports-on-Qualc.patch - 2178-drm-msm-keep-the-GMU-optional-and-its-lock-initialis.patch - 2179-soc-qcom-adsp-pwr-lmts-drop-an-unused-include-and-sa.patch - 2200-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-pm8010-camera-PMIC.patch - 2201-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-l7b_2p8-regulator.patch - 2202-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-Add-ov02c10-RGB-sensor.patch - 2203-arm64-dts-qcom-x1e80100-lenovo-yoga-slim7x-enable-camera-privacy-indicator.patch - 2207-arm64-dts-qcom-hamoa-Power-the-display-GDSC-while-the-camera-runs.patch - 2208-i2c-qcom-cci-Reset-the-controller-when-it-resumes.patch - 2209-i2c-qcom-cci-Suspend-the-controller-50-ms-after-the-last-transfer.patch -) -source_aarch64=(config.aarch64) -validpgpkeys=( - ABAF11C65A2970B130ABE3C479BE3E4300411886 # Linus Torvalds - 647F28654894E3BD457199BE38DBBDC86092693E # Greg Kroah-Hartman - 12D27D5D8C8E9BF1AABC7C7C7C64768D3DE334E7 # Krzysztof Wilczynski -) -sha256sums=('12e8d5a973d1ad7c5a5c69882e4022b131ed715db7003fdcd760ddf8c3e51941' - 'SKIP' - '777e4bbfe44531c6504fa646ee74e95e8ff11f264a3fa281b528e25960e741ad' - 'SKIP' - '6cf74fc3f28a751354187b6cf610c3e43cf9088b5f730b68dbb575828c3a7478' - 'SKIP' - '5de3a8f11e9217c9b7815f9348396e8a35f68c2d440bb4fc0746a3e1401e7ca5' - 'SKIP' - '58f21f8c48dbbb1295d488815aae50003155ec9ea5633ffbca4f0e17b18e8803' - 'SKIP' - '413e9994d35bc722cfe45752ab60a1bd8454443170d80987e6a5be6b7b745940' - 'SKIP' - '19cf60d05f912155ce54ad6af70b933ab63a8277785efa03695851089d87ac29' - 'SKIP' - 'd7c247f4e9f84e05b482c0294ef9053587cc50e46e29962cabcb27f97aa2277d' - 'SKIP' - '064d5c5429b491e5b62e29cddc7b31a7cf29a4b66597428ce042a017deb2d2c4' - 'SKIP' - '574b3e1152b16c27b281c56564044c38fc80a82a591acb41e99fbb23a658b03b' - 'SKIP' - '04350da18867666ef240e3a1d2d69281ad9990412154408564e2399bbc96628f' - 'SKIP' - '07baad05112a47cb0aea81191502c87e496e13b4f23a6ec36ea65bb4219c35a8' - 'SKIP' - 'df870910371645a95140a3f92424db43c4e1a92bd493393e598d61c6266f1c7b' - 'SKIP' - '3d5550935087a7d82b527227e8f08ed98c2ffdb830b526c09e30b93137b3e607' - 'SKIP' - '2351136c78ad2dfe68e34bf9a70d377724257f6239e68bf8f501637b607af6b2' - 'SKIP' - '6c93475fc28d211ad7c15c691ea882deedeea8c0defe153cdde0a2a74488c7a0' - 'SKIP' - '718b40e15350049e03c0ed281b9257fca5432b8dec2e0e145e8b26507ee8892d' - 'SKIP' - 'b7ba949eea77e169aceb2c401d4eb83a7413aab6f15ee2a7ab1a96352f0aa12d' - 'SKIP' - '341424b925d506869793686e22ea8f095a34048595ebebec409c0a7bbd346ca2' - 'SKIP' - '7c25d0a53a115bc1f072ff0cfdd9aa88858e754ae8b15026a2582656e8bd9c43' - 'SKIP' - '336d72ab830bb33ef2a23bda1869e1fc071af64b24779281e197073ab70c851a' - 'SKIP' - '829300e576f418e64101a20d87f30f7c90798cd6e179bfb72768a83d99fa711e' - 'SKIP' - '5e3b455024fab2855b590091c9d14b0d12d5363f3d4bf025b31b9aa88b65eba5' - 'SKIP' - 'abd8c9326cecc9bb85db4b3dc98ddcb66306b34a6d84fb05d0805aed537e2dc4' - 'SKIP' - '60a9df54821cd98581e7476f8a7bb6cb0819762bdbed4d356332e41d164a8182' - 'SKIP' - '929108ae0a8eb4782cafdd89e3d4426d02d86f2c2102ed99e760e31f0bc3794a' - 'SKIP' - 'e1226c836a9c2fb6daff109e56ba21c13fd198e109cbb181de920af04fe153e6' - 'SKIP' - '2cdd81f5520b935e1d99629fbd6e1cc9d1351b301396316f37946b95084f1a26' - 'SKIP' - 'e65c2645b0d01301a91874183faed44a390b7a402d2dffd45171d210034dcc93' - 'SKIP' - 'd8e64b9da3beab7c33832c019da50d0977b39dc32ec1f649a7c3bc93a2fdb9a5' - 'SKIP' - '5e2515879d58eba10c861f73318f4c4b478b8dd592680eb58961aa4065d4c3df' - 'SKIP' - '874efac3eb32970f3e06275adc072a384b89ff69e2e5b7452d6146a6e89049b0' - 'SKIP' - '43aa4a11d9d48f5094b4c0e807d1d31598e861a50695bdfa52f19819b5ff5285' - 'SKIP' - '2b49e4c98c5d704bee0a0e2b38051d59177161bca7b0188e6c0feb555a95fbf1' - 'SKIP' - 'e6b770d37e80509ed7ec5d8b59b4d2e5d6dba54ba659d7392de3b567f1eb6e54' - 'SKIP' - 'a9b3ef8aa79488d1cd813507e040e0762d4c8c5845b7f4ecc29c6cea1ade8056' - 'SKIP' - '264d49d74eb4006c8eded08e39409045032920d76df035aebe8a1d0939d4b7b7' - 'SKIP' - '5cc215215fed4247c2d6b9732deff586331a07d54c3b00538a81921093a3a1a1' - 'SKIP' - 'e303da14a3c8a15fd1cb45394138f03dd16e66d2ac0d1ebcd933977df937d771' - 'SKIP' - '1f0c958b64ba48b8dc8b5548e1ad1934b8d4903fc16fec15014759e3681ea275' - 'SKIP' - 'd9eb3717ba98e270b0a998f8dd90cbda072f63b6a6ea8f66763bde3ea64e591d' - 'SKIP' - 'ce634014dc0131a44c3c95a8e9cb0a9de433f59d73fd99d3e3297adde65fef71' - 'SKIP' - 'd069e594d170adb016c5000d9cb7eac12c3c267a6b60c27afde7f046dba0509b' - 'SKIP' - '78feb2e2fabccaf954fdae5b776a22cec4a3f4135fbd24f79596a5274fc0129b' - 'SKIP' - 'f864c7daeaac0bad482bbf3853583d8a6cbbf2bf264562e397fc26355ffd5504' - 'SKIP' - 'c3a709af1589bd0c467565dc66ec4c01bed9c2b94314dde30c839084e594557b' - 'SKIP' - '1e2fddb2e0c5d184a2e8c774886cf9be2f2f292e4f05832b50e5b49c48a7bacc' - 'SKIP' - 'b9b8771b6a8bd7128f4344ad189e32c155abf72abd3ff646dcf5c78b08eb94c4' - 'SKIP' - '34991cf6cec6c22bc1a55a76bc5f72b405165a2f14ef977a0446df7c18bdfbb4' - 'SKIP' - 'cae59282e3d1afd69f4f5dc00a180c712ef464c98b8fd7ccc9b03de944dc79b9' - 'SKIP' - '3b06b5285923c251b0ebaf69911875f796cf7f1d7580ec33bb218509fea313a7' - 'SKIP' - '15609bef72571868fec6b8971f53b74441e5e93fbdd3c677ede963d0719cbc40' - 'SKIP' - '1231a6e23557936b811ce5dc184c23a7fbd268a20d582b6820c67125df8f07c0' - 'SKIP' - 'ec12a77671afb85f8297c86fc97f8314b4f00a1630acb199af12e3550a9d4ec8' - 'SKIP' - '1b1660064a3dadf2bb3006b140d1c7016a1ad051f27e7a4d6d9f3f40d491fe9c' - 'SKIP' - '40ac31789399a5964c4fd820d4cdc7214add91109bbcf4a614619e5d8b367441' - 'SKIP' - 'ab3b968d8bc2073e8c53478aa5d5afbadc5329a22b1486a014e5d0d84bfcf752' - 'SKIP' - '2a2a81e647aefda80192d230cd1dbae2aeb611f66b7d6c83694b9f9f8e2befdb' - 'SKIP' - '2772f0733267d12f36ae2a339c9aeaf0a133a20381a6b73e0c26f2ef92996ff3' - 'SKIP' - '3998c774884fdfc94be3da3c4c3641bd4b5aeb1878d8ef13bf0e27cd9f2e9994' - 'SKIP' - '0d5afb79681a948a65943f557d143c15126e2497e71c5ff50ac13ed8619a67e5' - 'SKIP' - 'e95f8fb6d116b30c2b86d9fb51747a9f9b4e5f980c1a3b627a38940db9d0e521' - 'SKIP' - 'dab92dbc6eac02771c72801d94e6a53aabcf629a9cd79e85e0ce2ba44a65b06b' - 'SKIP' - 'f55bc6366f8b9ffef744b289788a19e8604239e84c1af8b929a6922cf07d223d' - 'SKIP' - '0057dff07a3ce9c7b7085edd1f912958e01ce8f7400151d55dfb74c0c6a084e2' - 'SKIP' - '9c4c16b9593449ce556a4d6325e5e2205cb1698f9000a967ba7df118395b1ef0' - 'SKIP' - '00afdc277c53dff0898ac86fd44ead020e007373134d7c7c333285a9f1dbf786' - 'SKIP' - 'bed39a5e6bbb7cdac3f56a883a4684b2a63f3e8fe2f8cdcdd0b89b374b8d2a21' - 'SKIP' - '75d7fc371ba9b00a78af2e4b0fdb7cf79bf25a6620c983662d6b2e90cf5ce8c0' - 'SKIP' - '0fe32924142868879ac9417c67b0233b6ef8ddb0163183352479f5163bf7b5df' - 'SKIP' - '7444186ad4f6d8e2b52a3729064f649b035af6eae4f4ad46b9768c006419fdbc' - 'SKIP' - '94750a925a726ad6631d0486e7f3cb3796b3941715b188e790fa135d0aa5734d' - 'SKIP' - '143193a175084d65035bcfdcc81e9dfef2e794dd56d637556db2c73b117f708f' - 'SKIP' - 'f18821fa9527c7ee07a49b9c1c983a3584d5058f9734b520b5d51cb485c93f17' - 'SKIP' - 'f7ff13ea46359217d696c6ccd49bc3d74c441ac5893d5151d95138017b0d10aa' - 'SKIP' - 'd17493b3579c730d27dc723447175b70d991f50253c9fd419df5e923bdf7a244' - 'SKIP' - '92971bb4dbde209cf170838cfcd75d8ac9978239821d3493c28cc12623c2bb60' - 'SKIP' - '7245c6e2cb5c0b0ddf800894f087770cbf8ccc6f8b3f53b9a21c704e9dfa42c2' - 'SKIP' - 'd49629fd003900f13418c05d8c2fc37c8dea2fd8a15debb5b863008c9c46021f' - 'SKIP' - '411fe33ab7021dcf73b02cdc80a64094a511333c52dd754e54d382fe1145de08' - 'SKIP' - '5104ee45fc11994b1cb44130811435c84fe4db532a2fa9a722c7b03dbbdc8bf1' - 'SKIP' - 'f7617e3c4248e015f6f174e7c8659299d831035d0fb3c89acd1a858a202f91b9' - 'SKIP' - 'e7dd17ccd4b417a1813c21285c738a3fdede1326d8a1445086ea1af294c3710b' - 'SKIP' - '058aa32a18723035b18a770e1bd7f4b4f101bf5618bf0114e1874a398de42e06' - 'SKIP' - '833c5ede23f4a014f428c64b7da550cdcd7ecc939dfeb45dce172b18417888a5' - 'SKIP' - '21a9196887fe8453218e4805e171b19958005f38e5d21886c58a55f8d9b86795' - 'SKIP' - '29c61ec984bd342113b3c4310a3d5fddfd6d7db83847cfb26b84cc730385320a' - 'SKIP' - '4b5abcc24f557e83e4d385c8304c781d6ab78fc0a3935db97e01e7d27fc617ea' - 'SKIP' - '0dc5f0f91640715ee1744fb8cfe680de6ac1370f4df8e17d31016744f31d3638' - 'SKIP' - 'cd068c7e199f458356886eb321f759a91894bca374c71ccac242407d8b22a1f5' - 'SKIP' - '618369a173be9a5a2f91fb6044931d897bbf4911586bd94a10b43a25838872a2' - 'SKIP' - 'bd3535f78183d56b133986b814ec31a8c1aa933d71b3a611937e6377ee04af10' - 'SKIP' - 'bb1e2ab62b109e434bd2c2635b5912602b8a8cc0ba24743b7bb5f691dcde2353' - 'SKIP' - '55ddb7c072f3933eef42ac48f3b32f90a5298f5cf90b4ba5b2128a197250494a' - 'SKIP' - '62e446b250e96fb65a3068bac424e1e5fe4482ad6d7ac473fa94cb8ac047c0ab' - 'SKIP' - '8b55dbedf730b0dc675793418c21b909aed5db4311248bd277d3184839d261f0' - 'SKIP' - '5a09e7b8e10fdc61839ada49e9a33a64b240fa54847c1c0e0044518297196f0b' - 'SKIP' - 'b857f4c98ff5998adab1765a06ad307f9334a8d7d9644a3de556f2b0e9cb2b4b' - 'SKIP' - 'c28fca9ba015e96599627acf42e52737a6a846bdcbfd3d4af4147eda3109e12d' - 'SKIP' - 'd15cdfc9b86c40a119a4f21f4fbaec72efebc67677a7386df46a61816d4c6e02' - 'SKIP' - '1b070eef78ccffb3763b464f5a1b0636936f4c33b0be9b44ab116c5dcbadbebe' - 'SKIP' - 'eb0923de01175707151930d28b1a1a912d24bbc171248fa9f45f57a2125d077a' - 'SKIP' - 'c076ed3752bcc2033e435043668fe007eb1ea1760597416fbb5d90bed4947bec' - 'SKIP' - '0fa9fdc6d6c85435d7b3cb38b51823f458ab273c527fcbe21b945dbd89686304' - 'SKIP' - 'ef66f6c32ac98a311b7437265b21a8c70746f1ea4dfbe28aff655e778d09c28b' - 'SKIP' - 'b45303b559ab8990ecb4e0281e5d529625311e795d6c3a9a52c2c27498141e18' - 'SKIP' - '1728e516153acca3c343f5184c9894fe6f1a1fbc95abe1594f544ef601db39ed' - 'SKIP' - '534e68a989d36823f14a10299803f294eef39391619b4c329d78c20539d9fcd5' - 'SKIP' - '516e6ec51ca0330989128a4eb2a8f6785e5d45d930899cbbbf37b8147ddfd854' - 'SKIP' - '757ccc291d53030b89088802615ecf727df6f18ab2515cc0075008ebbd564e36' - 'SKIP' - '3a271bc6b0219152047fb2b78d9e695eb791b796ea6d8233096912c77d62a5c0' - 'SKIP' - 'fd6bf3ed3d16c788330630fdd15604836ec2a0b6a7db2b04216f756da9117bd2' - 'SKIP' - '4d598b9e00edf7c17d915eec7c8d369fc0ea40badb7f4576cb3dedd92a685d4b' - 'SKIP' - '98ff0d6196470c582b3e3841ef35bf82a63b57ebaef952885bd1905bcb8e627b' - 'SKIP' - 'de2682af1db7f5ae8cd74da4f9020bfb7d2167f030eb15f0afb7bd46ffe49e84' - 'SKIP' - '73dc22b7f97a6cc5a5f35d6b30b9b7b12be2566160a024769550290a0e7e4029' - 'SKIP' - 'f06834dfaa9e976a5778fa4fd07117a85bbff3b788c91e61d8cbc628e1b8bfb3' - 'SKIP' - '11884198740c5ac572cbe87086b1744ce19f0e1f856775e6edccce843ab097a3' - 'SKIP' - 'e6d848172228e98dde3a7ec679e7ea6bb0a42cca0b0105c58c8f9d6d44e33943' - 'SKIP' - '4e80f2d05591175d4ed0a1a144509e97260e5593472aae586c07956215d99162' - 'SKIP' - '1b442ad6f28c684068844ce93616690b84651e35870802b02937351bea078b4a' - 'SKIP' - '9be4f91e6a4be87791d700f44c228fe599468f06a4f627b79e75718ac020db4d' - 'SKIP' - 'ed635ed3b63cdb61614b8805aa5a9515d5b538522165be625dca89bdb7d6e801' - 'SKIP' - 'e28c29b9f359db85a60bfd49d2f28ba51f4d2272eb79b7d3e19ba8b3d5acdac9' - 'SKIP' - '3175c56fd2935848ce99fe10be1bc348231909f8479c3d3af911c5c7ab7f381b' - 'SKIP' - '30a12a616afa8fe95b969e90b42aeb240962b9fab8b8bd357ac00706abdd68c7' - 'SKIP' - 'eb0ebb8c55332dab8931c667ec84cd32c91c657d21af4504327ae05643108e1d' - 'SKIP' - '945c90d99f9a9fa47d61e471f76d17c0229ffa0fa8cda22de990a2ccc4194bb2' - 'SKIP' - '70ff41b2341836c27c5545a7948258f137d991c2879cbeb29f7af740c11d20e6' - 'SKIP' - 'b4efd997d3f09cbf258fd0f78aca44e4c96694dc4efc5c8c9a677ea67ebf5a54' - 'SKIP' - '2e1e2a0eb039ce61c1612bf6c7ab5227b99df053bcd5592da7758715dd333fda' - 'SKIP' - '6800dd82115ebe71d80dde0bb368fbd8563caa6c29127ffde0d6b5df81b502b0' - 'SKIP' - 'd90cc6570a47c8754e4c5d45834e0434c0a1fcabda9b8933b1fba84e3dabc083' - 'SKIP' - 'a008c052ca657efcd4e27b8f7b819adbc9606e261aac37d41a40cf67c094cff9' - 'SKIP' - '57169ef893dff957cbf33f7c0dc22f2fdfcfcb3befcd62ad59e2456484423bac' - 'SKIP' - '01ecc1adbe715bb31153a2350ca46e1cb8a6e3fdc6899b2debeff015af2412ed' - 'SKIP' - 'a4331d3968fc5002534063b42bd219bddfe4a7d6b08e4cb30ed60f4366ca3c41' - 'SKIP' - '028bf538c870465e1752514725372fa9eef6b7178d9b8d1e2ecc15edc5a63cc8' - 'SKIP' - 'a92a84405ee9845738c6b52d8f0f0eca16eb40afe0ebe0f4e9e1168597675311' - 'SKIP' - '44a0b10a6dc83465ea86f5fba936b2bfbeffb1b3f0b2e04013bfed99ba4f6c5a' - 'SKIP' - '6f01b5357af7deed3f4bccea6678b4d9e8afc83e598978f42f244241667f975d' - 'SKIP' - '0da7247035a359e2491933f9effff43ea7b29748f21a0e3080bef0018c2488e3' - 'SKIP' - 'f81f6b5769e47716ca318ecf76ab1c0fafa0e165fa858a64251359937bffcf04' - 'SKIP' - 'c67fee35a42866dd3c9056ff099fc504cdad9530c107d959331b5572b21af818' - 'SKIP' - 'fdfe62019e6ef5dfba2fabecc6ee5b58400f41ef000883fed135ecaca881b40c' - 'SKIP' - '07683e522d6dea3d3ce658ee80bf4317f6c3caf248259da960bc4610f4d1e807' - 'SKIP' - 'c5279468d93e562f509a6b599a2b7ca7ee0032d3fe35314c5769fc6c9a9234ab' - 'SKIP' - 'c0111614ec44014cbf621eedf5a4ef302a855423bc1633ee692392950e971d0e' - 'SKIP' - 'c2f916fa04d91edf926abf8fed086302fe538ba62d92450af0ddb6d3a33942f1' - 'SKIP' - 'd17774053ab07de92e18abdb0ff4d00352a02b6a97c48e28d8c875954c8eec36' - 'SKIP' - '774f337663b215c5aa8877c06ffce95be44403fe77516c1be9ef9789e2d049e5' - 'SKIP' - 'e0c879e7d148e23eda2ac0cdfa3260aab329f1e6c917e74687181647bfe056ff' - '4fd1f0f783be1b336f92816246316372bb14f612b584b55883698b5ac6487bfa' - 'eec36e2b086ad53b1d78c1f745c3cc833ac9e671a9dcc5cb4fa7b41b434a7b50' - '00ae8b338670e7930dae5bf021ed5ab76745df1f292539a4cd41659113ac1d1e' - 'b26351abf9c30dc2e2293d5c23c0deaf9f071c6fb5b0881f98ebbf4f30725bfd' - 'f97397f95d4cdb9ed85a140b943c909f4fb2f84cd075dc06e42820854a00f06b' - 'ac4d4f5f6e552d7b783694b0b9d8a4a9c6ba7f1858d03f452619bec987ff359a' - '9787a31255d5b31fa3f8ae79b9825a660944b43b83588484d50d7eb9ada1faca' - 'fc8a5798be57d0b0514601fae8a592a3f9db0e44ee04eeb730142d6c1f256ab7' - '025a71916a65683a7fe672eee2fa73bd05859e9d4f0e926e1e8678ecc8e6ef7d' - '45f6ae0ea53e4edb40a61a49100413bd8e66a814fb95e8d1175938d76a12b4fc' - 'ea4526ff83f659e55b0ad0b4aaac1e8402a8a645ed82fc697b80d36565586749' - '0251766c52add0dfb792616dd93244aa242f406dd7ff8b20eec043b3fe50fa47' - '937ea870466d793eee9844a90949864d726356a0bfba0f4ee8fb2baede0142c9' - '763c138559d7f1c831a6ea6b28a3ba3c889c58662899bcc3570d49ffc4eba31d' - 'aef7e8c83a90102e041b1423436c98cf685ddb85b258c3a05e7cd7581c37ffe5' - 'e1305e8153910700cd649d9c0ff6d9376c7f169f1254341e1bc2b82c722d1c69' - '72ae95ec18284732f8790d29c1cf2802523b745be1d2953e3878e5ce10a4cc92' - '0cbab0c874dbc2acf0310cae24e5a16f2853d86218a688e29beb7394e10a61a3' - '1c259aed7ba4004fa323ac94c9f4e8af8eb833f59f4dd8c9dabd6080fbb3bb31' - '71dde7e7a457e4f5e9fa1e7b1ee6aebc97eea8e0bc05a2c05ad1befe572615b7' - '2571bef8e0bdbfa3799e0684a4a0f72e16cbf8766777c3cd91f69983907db950' - '9ee5070e04dc2ca3a0183c0f4264a9d7585757e1c3f95d37f3ba91d6fe083529' - 'c87ba519bb7df6714b49a848cc31caca6f91a3fa32805f947ef4cfc91f67f4ef' - '2857a276701029d46cd849ed6af9799714a2f704f20e0cdf9a53086085ff8c4d' - '85d6b1ecfdf7403f4499e6e79949e57e9b0ee1b013fabfb7fc5f85b80ac5d495' - 'a35febcac94e24698b65d623ca937125b989537a9886dc2f616c9d035add4025' - '5c24923ed9e4d16116e8067cbbd0b0074b62eeb120a86162052a165927c11732' - '44d34d84852429497e146d5f8f19b576a5c36c8b9a9f3e7f45792f51fd7b4e6f' - '63c3741a283dcd762de5bc975b8e97aa236328de68e8fd6623bf6d7fd125c3a2' - '1de7b523ca7fea0dcd4a4bbd5b7afd2824880ad74748e0ea83b7a83f6c74a45d' - '8117c9060df26fc93f75c77fb8adee80697b396fd485e40461276756c205e54c' - 'bab1a8ba58e2407fc2fd423a64c4ba95d30f6a3fa887af32471185505de58e0e' - '74ed8863892903452fe5117b7672d8fe32fcef3054386b472a435d4b0eef1b00' - '3e8bbf257870b8f6d376e984a22ec819a1c1e67de47b61d0ba35ed28b039e516' - '8bd7382591d136f35fee515fd634767ffa8b2ec1bb28e945fdd01fac0cc1469c' - '62f996f0d8a1723ce5aa2c73e09888ece981e6b46b4f37842022110067b712ba' - '01b9987523cb65f53481052f3160bc595bbbb55713df3094f00a851e71bf1182' - 'b4322ff5da350c62a870627f9f001e0a4d26757b96a4634785f3b302bb11bab8' - 'fa13ddb55a1a230c185ce3f4fe3c378436bcb32d3d8e1acd10442be900f8ffb7' - 'c27c35588d0aafee4e5721487daf7ce58624d5be42bb53a94a9604084b1d2f83' - '4a9f091bfdcff9c0e280885db9b4f88a75626c391001c108f86b90e457a3097d' - 'c365369fcf8a5fb3d3d7cc501ee317dab093ded82e63a1bbe76cddee8048ebef' - '712dac6fb7af23aecadb01b2ca851a64fd88e0173fd5c992913a85bf9a4d222a' - '1267ec5f1ded5fdeda1f996582b4b1f60cdfec84f5364a7f8d8e9ba1250bf363' - '16cbaf601ead8539374ba4b756c5927e457f7f5e55ff1ad0b446cb8d0d2ec861' - 'a4475812319b7aecd6ea49216d7d45b70d76cd0a53b0838c933d73e9a625bfc0' - '9b5940534409ec08d285fbb749c7f6ba1649825f346e7ab2a1f975b5dfbcf310' - 'c7b388262ae9f8f9ec2e4f3366eb2d0cbd4d1e93f0bb563b7d3df3a17fd16e74' - '2efbd3f5d196c31c85a3733707a89cd54f8579756e30f3a16b8ac45ed76b32a6' - '30b45a34e029aee8cd57123300a83ab1dfe473cb6c88d87ad1b3cccd891e0648' - '61260d5828b8d5009df572d5efe50ae359879fb0fbb1bc42d9145dc1947fc8dd' - '2c2eeccb8ac53d8626494fc4a5f47ab4b7271f68c5318a67fc5f5cd130763671' - '9f08ec0bb897a496283e8f82a9478bdf42189b739094613ddc0a378b68a12dc7' - '6fcc3b801f72f15bb9e299c1dd6e876348777e01cc9e55c3a504264109f09c50' - '6df3f94e9ea59f3c2e10de77225880113c4b1808e0b3e6736346c47778be985e' - '0aa39c07310466f74fd8ac48a1d2abef2dddb07f0d9211f5b801f905c919f0de' - 'fe384e8722f5f8702186e4629c585fde64ff61085234d87787c32b4572ac13bf' - '762ad0060990fc4efee26138a0a02b507b7fdbb0cfe02d0860cf60709db7cfa2' - '6ba3e86204628fb925cdde1c53b97c02b93c790c41eb57eead7de53074295a38' - '8f8eed910185f263e395388fea964ea53ed7992d5e09ea0598274d9c5f43ab7e' - '13719af91befcba7b4fb0b276f0c34b4dcca1502e01656870c9a475e79a23e4d' - '1cccdfd000a6a460b9cd11988e8080ca8ce579862b0d7be25b5ef50e7da95fb6' - '48b101685fcf59783ebaee21cb9f1abd04740a88eff224220676b4dfb1ddb161' - 'cc0c4a111483906b780c3d886f52954a7ffbfde26ef758eda9ec38355ee72145' - '31d9251885f2fb2946ab69400700c6ba41078d47161ddb8ecab5aef308ff250d' - '7f420c1ffe57b59204f0e3e05fabd07a7991235cd76406544e53d15a453e2569' - '5e1621ce1e260bcda757aaeb8ff706ca474d444aedb35e80be26d393047375a1' - 'b8731b4c1b9517039b31133e905c7c856bf046b2357c0497859836959d4fe5f0' - 'a26e5a13d093e91969b98b5f969c635e6bd3118c847ede42ec0f83dbdbf043a6' - 'a5664d88d81da2aae289a4a0287f22ef4eeb71270614edbee2573fea11fcb0d8' - '7464f35463265edfef4106767ae906b440b1dc217869ecb64e2f2ab6bfee19db' - 'd09050a74e20ef20730febde750491b646210a5fa95254cd6dc6b1115a36846e' - '81cdaf4977af84abebe9e5ed57b7e632ded834620a0c953d9df691297540e66c' - 'd8e3f549e0a5705ef3877f91d7bb8b3b727f9d8d4806c955be988f7d2fe9d0db' - 'a20ad7745aa84a6c90a88e639b4d697664111b363f7dbb8599d16e3c5377ce5b' - '4c56326fa72421bec2232cb86081a9857d1f5cc37f98ba790bdbbbce563f134e' - 'bdc0203ae6ecce9c71ef8a6ce710ea4bd214e1d51b8ea97df4e79925ddc3cfcc' - '9ea51488527672913fefc5b8a0255574e21950df92eda7e1c536cfdd2686268a' - 'f56b3be5ef56339f140ecb3a7e507a2dd64ff1205f83a9a686fd9959566b1b6a' - '6b7998284b6b04234837e475a59f9ef42a28665fa5a12f05c165ac24557bd5e0' - '4f2a5e6d4e46fc62a6cfd7bde5af878d2dca64c32ffc7e3dd6ad4d94e37aec3b' - 'de441b1e44682ef8e73d4b1d44096c4ebae241a47219422d2b679af679c2ee4c' - '1af553dccb286f4cfb6c10b83d9dd70297afaa264450e4b5f9fd4d8649737242' - 'cc36e89df67fa385e592deb669bfcd9ecb4583a994834341429ae5526c7ee1dd' - '1ae6e571ea8d34fe62e03a3037f4e25aeca10d0ff1f0e8f0afd6899ab284123c' - '02392ca073bd502086fb64b6945d956b1a37aedcd852078ae6e34aa5102dd6f6' - 'aa35f4819fc30e52a6e8f84994225f62357d773dfa3390aebdbbbd7011abcf38' - '7d4472524d43e5f6d2431dc04d4dc76f7d8103aa2a72c0b63f640eaf7a8a63b5' - 'f55ce58adf469c617a5c2efb430ec7c66bff74de67788bf60f41572baef616a3' - '1928fdbeb36fb505484048c7bfa8341c024aeceb6c301ca3e3fc68f0b903d97b' - '3fffbc51b79da923225f8a02d46372d11a1b7e596b52a8b552e79f211116415f' - '56bd013677b94ed927d8e7b595a3d2867c70cedf05d15a68c3535f9ebe54b6e6' - '0bab82f32e7e1d4a4bb778f2d64639c5b2f3f0b3eeec29e331bd6f5225f2488f' - '8614832330fa120d61213bbaa103bca30156e6be381eeab69c0b31573011c553' - '7ac960efaf67e64849baecab09a3c8681d05b5ac5553828c8833f8323d7c85aa' - '1b28581ff79a0b94d344f356f2282da3b110a337bfbeae8ad0f768f3484d11de' - '616b4c3e1d5ca8525a461b33ab791c1b348130066d6ca35bdfafdfee1f7cd182' - '3c2bec044825202e6fb70501c3d75aad5957344ff54e25151ac2bbb0b712d09d' - '842b67c9fcaf0fbc3f4f01a3a214ca976fe4f74010555812d7b0c6a2322d2ae7' - '401c366a2e4b4c075930b1aa05c4c1554d61cf16695011937d48f250880083c9' - 'fb93691adec100e3a7d40941bf70388f61cd407183ed9b1d467606f7cee6d4ff' - '7c76502536af653bdb9a05a35621b05a7c574be45dc5b2f532083b625a94915b' - 'ad4f8bbdbcffe0f6f93f6997c9a6c0b786c45499441382922418ae1e9c5dd293' - '7fa05715a6251357284fa1906a98439cb6870aa11284952942d867f3f9b5bc34' - 'f9bec1e20b2ca6652dc7084e658bd7eb01e1e3a0b505537dd872d47b3bde4e16' - '44f360cfb56db8c17b3d8b9c7b73f7abdb736f97b854c3099049d5802fd2087c' - '42b67f86491c6a4fa32a5d8eab96e0754ec992caea253c82de5a87e7fd177e7a' - '02db6d8198c97f6ec4ed4a7e960fa23fc563fcfad0c63f735a6a8cfe254edc89' - '3102665d9e8276f8a9089bbb09efcab5a3e61a06907d55d11911f4a23a63fd2a' - 'f23cbb753cee7c3d7289bd6018b3d5c5b1317ad5bb30118a4dea55077017cb1b' - '9bcf9b22f6968b5f36094e333761e18edc8141d273bc3c3c914ad336697cade6' - '988c4416223fde4d45738f5dcefad3b67545ea2de96ca4415f575e6d0f692254' - '6113d32fb448f09e3618789e6ed24ea7fd2faf597664bdf4c508c473c43f8c34' - '720017482aa39321f1146daf8a2fe103e3b211b40cc0f05bea4826f40c42e112' - '344c8c26038208bf75fbdfe208bcacf6a0dec216c89c5c7430d58ce2fcd85b65' - '7224ffe0714892ff645ffa69060dd1fa1dd604906c7d01da8a5551eb21b5b161' - 'c9a615bd90f44b65febbe1b214897d9a55bd612ff77016a65730e9a8d8000d09' - '16df73790288ccf63be5c3d3e776e7e0cbb518823fadd4dd3a1d649b99f0d27a' - '995cc1dc0829f5abb61f670db8ff0193d104d0299e9538b9cda587b25b5309a5' - 'c55f25ceb88488f7c3e4b0bbc986bd752095aa5c6919b6c685a1e79aa679366e' - 'd381bee00bef449b1fc4553c318f15d4fbcfd068ed5c03ab4238b76d3f87cf70' - 'aee3b02e6d24606dc82c89282630532147de75c3253278d8aff89ea54a4e5250' - 'e2ffeb741a169c226663acda8f9e119f1660d924847f06a87cba41bb12f107dc' - '5eeb64bd6546a280a30388a58c7ec71cc7c25cc338519d011bdbfca8d49d7666' - '396401cd7d1dbf781fcb8ce7ed5374e03826bbbdde188542cb385211d76ead95' - 'fbe4af873797bfea0efd9987a8a744cadd32c25bd12a59d080f784edefa62908' - 'a56a08cfc3c2a82f9a0c408fa680aea69a463fa7674e2f12dfb9857a65e2312e' - '822fc723fff0318ccd6a8094eb9bfcea6c6d4e279abfb885c15f9183c9ab40af' - 'a4079b8965fdebdf99e2e9f62e97f6c749bcfde2abbc6d6f4e46ad94e7a6c7b9' - '3e1f3526e989c0d9f26f3ed81229675b1aa419be21b99584d65c595cadb3fb90' - '9784af3d74269b567d1a2bb7455052b2a4ed969f9be370b0fd13ab5c34d1ad98' - '498fb0728b5e78446f0f7aa4a0fd5546df7b6a7e979eb97111a6314213019071' - '89770095e3a2c651e52fa7fe997032c0447924b015ca636462f12dcb8ea62ce0' - 'f23b59aec9288b499bf17b19e29a29d7307841ac31e07e7acc8748736061d06a' - '9ca3d621fb4da0712bc8835845ced553c46c43c47e31830c52bd0c3da4a2131b' - '885894a3f007a6f265371e4464da3c40b41fe67ed971a8b8281feaced9ed16b2' - 'fbe7f557b091b151c9f91eb1de437068fab0901608081216d8a7c687e8101ea9' - 'bd77fa17f6c05b4d09a722529d08de90e7348522906eec8146ee225083c778c5' - 'b3b19a3205ce8e981a0e92921ff5316f51fe329f81951c700d7ac3416e63790f' - '5eb763f45fdef2428571d4a8988522e350c71158ef83b2f1a76d3dba9798d677') -sha256sums_aarch64=('509f5e01b9fdf64ee35f24c95e6ba11985c9ea875147a38549f9f8adf4792e6f') -b2sums=('5326dde778eb945f282740ef0d8765b46fbd198f1209cdfd7b91e5dac1312fc01f8bf0b2bc67b16a76de736edd8ea21b38b6c91e696ec0c4b39746cd21a15214' - 'SKIP' - '60eac409f1ba50fe319f6b3aa5b0af81bc7ce5628ca41c1af346a6d5ef0fc9c577527742d1f70ece7e07ea410fcd112b32d64f0a05af5b532f27b62e5e7d837a' - 'SKIP' - 'cc2a66a097b5567e80c59b7d6c492fef5e667fc71a0390908712c69512c4136dbaf3d150b62d04eff960c796f7a94e6d0915d3b92cb336318b49f5f516a3bba6' - 'SKIP' - '9bdc9b93b30431d1b788f8a44cbf7e9030b8ff2b4e0cef9ceb7b8405b497eab1526567f840b0fc643e25626312322fcb008fcfd914363d42e3d3bc3eea6ed6ab' - 'SKIP' - 'c5a06c5632ba1eeb592f19b7f1581acfb7adf603b098d1d966359a1bb266a330a5707b64aa1f0e0346003e0b3008f46d8af669b621ccacd9f219838fb5e122bc' - 'SKIP' - '4651980c9d988ed73dc91fd440467de0a1de21efa3efae0fc006524c88af40173182ce6826c212e8b7faaaae1aa512fc755272ec4663c185533e65c936780db3' - 'SKIP' - 'c974858b6e01c8db72700a472722d88820efb8b784cb2facb80c5babc8e93f00621b954ceafa22033b9a8cd61a981afcff4a2f759cc4f66ece013a71ce1572d7' - 'SKIP' - 'a55d203cef25122f29ae651a8011f15bb3210bb959b459c521dd7d18d3d65a79594196ba3eafffc223114eb640cb41e8c36310600ff451b3cd7d6b852ba6307a' - 'SKIP' - '28179167d761963a2a988e1aaf2f2aa0724aed94ad6f79232701f2e13d5c5e0a4a8396e2b8c5a56bdd91a5a325f62ad22a14370ab1f717baaeb913abbee2d6eb' - 'SKIP' - 'fc6deeaa32b42416a5f5c92ee507aaead8d088ea9a5795848c96ce58c3d745d1b1f101916ded9d7163b52d3d705e35b5de9a1a8e910fd4cb100a37f53444b6b2' - 'SKIP' - '775d7f30c8eaa56989793050ed0e856fae3cfbc698681004f5b12945d90802c46fcf09a400fd2ee1af983ac2987d4dfc771e4542be69ec38352538afc09d07ee' - 'SKIP' - '4f58fc77bc13fe9492fe4662e0a4b879a8a1616e271c2095959dccdffed9b0a866a4eb9dc3ac74fad9eed11c362e43a7bfa56d8ea6f571572a63ff4550c5dc23' - 'SKIP' - '921a4b6ca25fb1a10588d7a3df65277cf6acf1115e618741486d230bd8eee16daef3f712518f98c8a49222aed468e706015eb238ba289769a464f5f33a21b21e' - 'SKIP' - '486987a57ff24ae8c58953c01db6c8e4f4eca4093a8484b28b9a647790a6757a381631e13d64605bb009613985b686a0f98ef58b2e2f9c9ddc5b4d0de1c62de1' - 'SKIP' - 'e2d21e10be9239260aaf41ec5584885555d3d5150a817fdc2b04001444ae07cebefd140b20e841c0988843749e850ad52f93b98d005d5b158e158454c2020691' - 'SKIP' - 'cd6d3232202e8e6a44e80783becc1b527336027420e308f354b32b6de1f83de210aac78ee0c639ba23030b4a0811cf7728bcaeed08e9dbe11caf3edff380ed6c' - 'SKIP' - 'e59c4da548b2ea4fd6144886e3e2e765b3e73972121e9e73dbc05c066834b2b35e6ef4c17617e77efc90260566bf7c0910d2138d8d5c1c3b6094eeac9de64cfe' - 'SKIP' - '9809e258eb684b80d508fa2f2fa270683b62bd1412ed05a970114aaa7d84c37c0beaea51f9ff8c6ee1bc7318c4aee3725e9a1131fefb51ba700801de6ac414c5' - 'SKIP' - 'f115e8c80d723f7c24e6b1638b801cd664bef20acb1d2f6e6f5612744b916278693011782228cd3f4d0518654b8d53309bc5b06bbe8ed722fab9995f369bf548' - 'SKIP' - '31abdd15ae3f9709d6912c90319a0b62d8380e1ae1169575c0e8e419f8ce264a7cf7c72558a85719cd5a1cae7341007adb3e3936268999ebd5215c2ed288f22c' - 'SKIP' - 'f95af54bcfaf17e80d9c0f60243d946aff2bbb796ae47c92a97a353f598483f03ca87fccefbaa47639b1018b82e7879dae4b8759e8fd9206b33d219560d682a7' - 'SKIP' - 'ff9a3e5df8457880b25caef9de90a7eb513ad8de99296ed503268749a32d8fa79da11f598a5fd80d28231abdd65a247e2aa92ce7c8ccc9f497fa483eee93aa82' - 'SKIP' - '55951c59286df43f069302b0b1036424812f80b45c5ea13219fce1bfc3e831731432c216288d722e44493c736cbf89a3e44801b5a4f1f242c17b5a89b236a5ef' - 'SKIP' - '737db39c2f7f46550de4d6d80659bd6c1fc2bf1ca42bd7bd6fc345fc90af995acd056051e12175ac6c957333629a017051d76d5359c871158c93f0a294fb8de5' - 'SKIP' - '4d0646c8ad139add6abb62d75308d2d7b5b07afbc74a0f0297ffc2148f0db38abaea16b048704187da49fe3ddee8370b10a7a41d6e62b665650cd79e8c392b4e' - 'SKIP' - 'bd7bce1bf0ee24ce201fe0e5f0b8a6c829a84d224800547cf97a893326381e2e6eaed9c70529a6864b0c338276b3a307b14e26fba221e62263b90c02eb5e5f34' - 'SKIP' - 'ad2cfdc3d8de2193110325395e11015577f26ef1081307bb236ed73fbd109822dd44ea026a57c2e17233e1fb7982e78aa986b71c043f42887e6c5d7f51b84ea9' - 'SKIP' - '92cadbb0f7c288987838534f523f85a67d07db19ce27fd6c8717f73c02f7ec7b7b47276fea8b2a86593178dbc4f44e774727050f2b46baafdb7296028fb24a0f' - 'SKIP' - '0b281a5780efd064a6c98a08a41eadb1286a2aa5a7f1bab33d3adaa82713f4676bd3acf07556f3617ab0649f95fa5ce3a0418da1b6ae48cb580f0d7d5d9752b3' - 'SKIP' - 'a51e5f2a5e37c350fb4d715ece644c565a508970c3aeb1d28cb6cd03a0c7316a1935e028b64f20a03818926c611b50ae0ffd77d04c676d604d303beed0f96e1f' - 'SKIP' - '71e8a5d91d285519367ba73241d01adc3b61a2b7b21f8061ecc3749fbf9d87f5ca414809343fd37530bfd5226f919cc3d87dc3b4034cc5b8be9c720f8b4676b2' - 'SKIP' - '64ca5b3c45b579c51c04f1177c8e6eb25db4c76f17f7b253c5ed959c9688bafaa97da701257435b34338432e88071f04a8d4049ba66895dd3ba804173cb08b28' - 'SKIP' - '4dfbcdb23d7117b75202944547f7ce956dd8fa7405bc5ca4856135e2becc21d950eb6e1aaec082da4290ac6cffa402686c2c9137d4dc23952796ce3334b95ff7' - 'SKIP' - '51a7a4f87d53e4b3d25041a0536b238d4550fcfdef0e7de5aa75c26a7a9217f6f3e260670154b9fa6674470f72e5e09c76571e6224d8be4eb5dd4383fef64a55' - 'SKIP' - 'fd487cb02212ffdae5d8beb7d895819377686085b95658dcf597a534b017adcb65dfdf06e0276e7322a46dc28118803b05c246c22e7d3c361f1778ed9e12a3c6' - 'SKIP' - '2c58614d716943cc1883dc513c2206e82f49574eca79f3e7dde21f8dd0f02f18611b2b2a444745df820c30c887d8263bdf9786a4a90b7979efee8d86633cbb88' - 'SKIP' - '218d01002d5487e2cb29f479f9ef9a2beb8226d2adccd1a9f932dc162a8502003db19b1bf74395b0239a2a15888131bcdc969b737cf56358dac6ab14d1b4501d' - 'SKIP' - '1b340a502dcf5a1680caf5320b3aa72aa4317e4cf1d877c1f6425e281a5668d5f092417e1f282371c0a211344f5c187fb3bdaf3f97c7e122951edf7e4c08ca58' - 'SKIP' - '1124c5c3fd5104c886c841ead1ae9afb42683388b640b1a86523dad9919c6bd59a1f78b07ee5a213e0dca77c636a29676af0592d4ed1735ea35f282f6f23e46f' - 'SKIP' - '505bf01a9d6b0926b557b673bb686d1a4ff73ee70539991e52272fbf58aad3ea25cf5ffc5c2d094a2d5e78b18a1a134f2ab530f595073a2d3eba9ff2c1418e1e' - 'SKIP' - 'b4bf4c4c0672bad91d7f8d309e741104918dd8ee8688a00d600379eba5828d1b8157953377c73d0b58050b4ff888c43013ede4e9c959be8d9c028a6143bf58ed' - 'SKIP' - 'a5ae2f6c29ba850292fcd1cd39d7af6041169ad9d73151d8fcc07ec2e1da473f3ac801eda892082b615d7f19c2a3ac17bceeb1d100dc1e2ff4b30287bbd8fc8b' - 'SKIP' - '3b8e01822f9f97842c5f7d7211df876d46d8477321546bd5b8cb74484550a2c520ffe351ce0ebb7df5659d2745187081883c091574c855ae7361315d153bc557' - 'SKIP' - '90e189032c6a04ca809607a5c9a8e798ff2f3dfa7d82bb510eb608da961196bb4b53f35907bfa9ce4006fe182102900bfa20f4566b146aaddaace4fc19adc305' - 'SKIP' - 'b9f60ea91694fb859543cf895ac9d654edd0aad92a3bce6ba9cfcfc450f413e49bc8cdb08adc6fba1a46ef319c10cdc501e3ffe6b37de222b11cd1c6cf138db9' - 'SKIP' - 'f80573494f330b31af70f1a079100082e00e3c7e185bbc51928d09d2ad3ccabb3134c72a0edcef994d6cc517015190d88c41301cf73c73419c594977f86a2906' - 'SKIP' - 'e403bdc300284c4f0f4302e501b8ccfe5e9af04e73a6070eb6615322f5f40ed6edad53af2ed278741f61a4e3811b92faf1af02f113dbcc2a19bde335a55930d7' - 'SKIP' - '5de29d0eb5264e24ab9228bea2ea4b549b3fe37ea67c045df9f83064f11c2f557b9641e772d28db59f8d258418c77435b66ff471c3695043f0f8275d5e7b1685' - 'SKIP' - '25a4ec87d1c789cab55e8ee6357276eb2e87b5e70eba2cd978b2c898e7b79de3fbc8cf5997fcd660998223b6173c98e440c853ad7c3e116f52a48d38622dfb46' - 'SKIP' - '2b33b11e48d8dd8d6743f26170fb99eae38541e3665e2448d91cedf729cca7c0278bfba1078ecbe88201eac4407ec5bd0292a97dbab9cfc67e42646712befc1f' - 'SKIP' - '5ef0d9561a570941752fd1976a2929eb25fb4dc16ff7fad09ce71e0d6881924f1ba8839574f7f877bd8089d116d689e33a54c14e2f177fe797dc86b305a74c0f' - 'SKIP' - '0415549ab1bf3ef0f2af4e62130b66e80d31dd3a1d1acda1cfcc2e4c926f25cf9449153736216a564cbd0710c0f0f1294607bf27c26790bad16e0f8956127e32' - 'SKIP' - 'a0a17aa48cdbf60db7a6d3677fae8a3388757b0f1de71043d8eb93028710f5a26aa57eb2011199b84e9689f7e4457843b74a5731c7dc14e4d1fca44b957bf33e' - 'SKIP' - 'ff1f07b3ad829d444b92c93fa63ab2c08277fa512483806d119a4cc75efbbcfc197dc982d9a146b7e9b94a9ca5bac95eed54735f607d7715cd52444ff0039e30' - 'SKIP' - 'a5670a422ae3d084f20800a5ca2c5615efaef4cdc58e466ceb25a8c56597e592cbf3eea7f4b8b28f1e7c79e9ecc7ff29c284d7be41de26fc6291df020fdd3d33' - 'SKIP' - '353b7e89a7044b7426db730d5b900eb347907aa0c20e307d2317925d6021a969a343649ede7a32e698dad60dd4472eb197c9578fb0e36fc354a60266fd680cd7' - 'SKIP' - 'd70e2f90fd0630f53b9680a1a935294d0a9e86e52ef9a712905a7799827ced2ff5acfa27a51980cf6f8157d60d9831cc0d62c623f98cf577810a4cab02b334fe' - 'SKIP' - '88a071e8e20be14db31253152064a26961b74c329793b7fd0c81b629973bd39040e9a66189e3dfda31ecc189f82e65781b310603f498e13456b8090662f80b0a' - 'SKIP' - '0cdfeb8a469295f0d7afc27800f5109f5c88c4afda93056d4c4fc9601988334c32d287e1490966ae21bbe80c5e4f8b8da2cdb6a019ec72682521972840247b8c' - 'SKIP' - 'acc6611ef0605b18b3326e2170f32c3daad02b6472b4fd8fd2a8ba4f99a35b319f2d67b6f1f017e9beb6e8cdb8edc081e97382f3cbe7999d8ad57bd5e929a9bb' - 'SKIP' - '29f44ba6256ca05c8f40f0f1b0e813a5b3928f23e37a23cef9e7e148832f41d8ab4ec43b398ef21a06cc8588e4feee24fbf1f3ec4428ef1b22b1d43a776022c8' - 'SKIP' - 'f3437588231ac856c45eee210b6d1e4f31019480665ae31f62e0fcc4b9931cea4bdcd2bb95345cb9dea26dba43931ccc73e9c9ed209ab3281a1618378658ec0d' - 'SKIP' - '824089f9f45e2ff9e788d874bb9294b9208b4486fd22c56cb59d4d88cb996ff5a81ac22f8ff136ddffa1e40330f02e53ab759ffea7e4535c11d4f8195069966b' - 'SKIP' - '22e8b6835a86ad485e5b23ba73a4e1515242b06f42063c99d0dda1f9248ce222e003acd43a517dced198a28bbd1812ce5faf66fa589717734558783fa385bb13' - 'SKIP' - '7228e249d25a99f5106040b8ddb5705979b3a5af21ca60d0d43a9ecaf6eaccef6bde8ea69c896cffbf2b5963ec4f68987e69b184a8885c7f4c98d2b05fd59fbb' - 'SKIP' - '4d5c5e2fbb5d8fe50a899bcfc629645d1bc9ef995c76611ecb38d25070552487d53ea59cb48bb3922d9d9965cc1f7d37ceea4f2ec789ed1bf37d69b831dea6bf' - 'SKIP' - '47015b9baebb1d6dd2a68321980c1c97da097825966f480c8569bcc9df5bef0257c51d5f7398960f28016258eaf1fff25bf142a64a01b829e882b4c1dda10612' - 'SKIP' - '4f3df2be1b52573ef4299934896dd5b4a5b9ebfa1f69c92f125edee1aa2db2f99bd2e6cf67734e1c953e9413bc6936067e8ac619cad66a5fe8dbcfcfc7906b83' - 'SKIP' - 'ee01ba98e614695154ba62789874843e48ce2a4715b3e6ca0304da0526f705672bb29253e0c52dc8f8fd3148c072067232ae6f4e86315dfc27b1563073cb92eb' - 'SKIP' - '0963ee814b6f64903d67757c5c55a93ec1f5b16374af16aeff2e7e494254d19031d4e1422428f4f7a8167592b7750a1db87476871eeb5cba851b377e59911149' - 'SKIP' - 'dcb350ef2987b801e481b5cf32cdfbe47018939f6b43e45b6dcff87eb75cc1a48f25e679caa823f3fe6391048f216ed9d95ae79b9cac237041857458f56e7f7a' - 'SKIP' - '0e4156949673d16caa6ee1405bf33d432ce2632e433d0abea2f4e9bc5b413500573ca06c10b8dfb477d2a6c7b4201f66ebe81ffb05302e3771dd2f0c515fc5da' - 'SKIP' - '9576c977d2c95cc474e84ac8dd7683a71df38d1d6e1ad80065cfa78db8185c7a52bb408af9881a71767a1c7e3f011424a180d0cba574b14ea53f65a567784181' - 'SKIP' - '4834e1cc74f3902e8e88eb28f9fb1f2bc3cdcda6745083092e7fc39c131bb0b1a8b06d74e6112e5d4c97d14e8b56302096691005474e6e5d2720da02463246a9' - 'SKIP' - '5d82f32f7c04b084530722b9848254aac289c2a754a10e16821083a871ec14065dd9ee83e72b8e9e8ba2915f3fbaf17b0874df724002eb08a5f4f84d1b6aecd8' - 'SKIP' - '4928cc008dc91fddb89b154b89b1ce2bbff14d8186c0ec1f81971fb9d3b622475e93e42015916699c3442e2268680779f545d183112b57dedae96fc48a75844c' - 'SKIP' - 'f93494f5f3196cc35d017ff9719d146bf3e5e7bfe32a7f5e75d96468ce30ef367428ba83b1c99b665064d3edaec84cf3bf18211d8f7b4f118b3bdee495eb8ef9' - 'SKIP' - 'eb79554ef0d014b94bc72d4d559c2cc5419df96486acb3b6a09d5e8e9dc48db626ce0f90338c67fe873b2cc3c45c3f308c8080532b60f74a07c9e39e01d34197' - 'SKIP' - '89482f70ea83fde5a88554f54c866d11c98baab1cbcb7fa6fe0079187821736b7ad9896246cb3976ec9d471fc0ebcec6dab32b95b4928704e23e3f4ff935f221' - 'SKIP' - '31202d94636ee8a62214952d0d54eb12b8e1e264edd20c374678dd442d5fc9f8b3ffa2e94cdb6d27c58004a660823d62ffe11aa81decb5af166cc6912486b9cc' - 'SKIP' - 'c0551a31a3c63b70966c9f87eb852cbbf43a13f649bb14b6fd2e8ca23f7fb311ba55d94ddb589a78a432eb225cd2336e553d399787071cee9933f2078fe8b5ad' - 'SKIP' - 'e6f6460dd43c5a7e4d943e6545479438286712237c9feec357317b1431aa778684132b734c5c113f1e57180de366411542c29f62507095e7db62e2d9aa6ad9a6' - 'SKIP' - '58899f7c2bb14ee442c6cfedb9a354f729c03cefd325cfe71da23f33d5a548f6083d5ad922231108fb58ee00f7ef2a2d45ce58c5767079e3ae3efaff306924d8' - 'SKIP' - 'acfcf80889e146bde867b12a7c1b4a7b88a71c09603d58974b647d8066cc281b300b7a43c0e1820f22fafb5f7056522091b9c6c0072ae6a4835e603578c5f95f' - 'SKIP' - 'c446acd1c5e498f0972febf76bf6198b4ee72c6e3e4ef285862564f2467d7ad7ad74eee88191fe1fd887a90a19ad61a3945ed9ee22a2ff6902fc5a806788b151' - 'SKIP' - '8bf8f181ffbd249b0af3a8fcc8463d84daa3c4aeb567595065c311f29b2dec2344fdd240d30314eae2c3d4a4daac53dad34e8452df11e386ce0a028267b18c0d' - 'SKIP' - 'bb06066e90132f0172333d46be54ca816eb7d3230a193a6cae765d8edc50df4a6ba9fb7c0647cd6befc8c3bbbe1d96c285ee202812477d7295c1130ea8cdd6f4' - 'SKIP' - '788488e828ac47a55ab78ad43251f7a2e5ad15bd5b5468bb31d4ee31e5de01a79b5680d5b048cb123eb3b7bde75e6b3d1e366e745009ed4129c8a6585d92b6b1' - 'SKIP' - '3bdf369bc73fad9bcf5b866043ff007365302318f42de7107fee47a7e8404c02c9c8fb5762d07ef10aebd2eb815c5483fc4960b7936e30ea5aa969a55f392474' - 'SKIP' - 'bdc66e50a9ef697e3baeee768f0f2dc56485afeb8a4e9f9ffd45f183d9614c33e0d0e72a8babca87963d1d9d701148eb41990730f2215a1c40e0965cc7f05e78' - 'SKIP' - 'a22e13b9bf0eac5d4190fd42bfde72ad0830cdbde8c0d309b2dfe9b0151e4c85f9f14f595ba3f36af479173ba1274f7700293c3d61dd913f711196a2dae8d6dd' - 'SKIP' - 'ebf13eb83afc051e3b9c84bfff7b326d73de6bac03f5b4d5996485d06a9cc87aca795b5c029646f804d62314a97e4a2b5da0b5f72f71556f33b62fd26529797e' - 'SKIP' - '8c6b5b96a3992c7cfbe50384fc0a4504e6d522c6918739f822b5bab29066eaeee7d1cc525b41a9b5b354ce020b1837e88d9bb940f3d2ba55a034aa9a845d489e' - 'SKIP' - 'aa24ab789db9badbd38db52f1e01fbc9d5abc09d812e2426ff281c869bbc0923cd903842d0c10ed8cf0e1a4695d3508b8ee4650f6a3eac3655247830aebb2c0b' - 'SKIP' - '1cf95a50e985ac37abd0faf86f4138e510cfb33af0ec172a2ca63f9252e6e4cba2f6c43a0babb11a96973bef3b7bf309a0f22ede26dc437673fcc77afef7fc31' - 'SKIP' - 'd5ab07d8a1db9191fc3b0d1f44c0237e93d662fb8bf04dd55385d8cded9589f66c8212a4d37c651c505fcfcb4a26da072c0be71d97fa0774b4724ba925a7af8e' - 'SKIP' - '7da8c7cd405efee8b37aff9916215b2d7052850f734b693656d2b66bae485661484efadc7207fa00dca5aa02d5e1bbaec2df9abc3e583f280097a939fc32096b' - 'SKIP' - '36fa6403c6519e064972afa0905cbff55f88fb89cad7582a89079f657537458da3d93deae474e33e018928d03090e1a373c6246b180d79f43366e16ccee533f7' - 'SKIP' - '44dcaad2ab326ebee62d3e63207a161dcb1b63bdb21412b5624ca7875bb6e99997528683a633d7dd526dc5ae9408e73bd066e2a1e5b34ba5c829162df2265346' - 'SKIP' - '69c1d61ffec58e2d3058d9e9e5fda57a089397d5ad451224f75f1cc2816c7f3fbd650b31bfb5911157fd364f77cb6f720e0825ae3deed8fe9f03576b8f7f1b31' - 'SKIP' - 'e3d60abe9fbfa046409598588dd23a9b16439474595136526e3169ff47982e011ede263d403211f5f5692ac43cf88af5bbf0d11b8e7e959478305c67687c525d' - 'SKIP' - '1fb895cb1deb1b227515087e12fb0f7fab70b0db25a1a535fa3c294a5455af4d987d02c7c8ff24aed41359055d1383ea90bf9709999382610ed156dbc4069086' - 'SKIP' - 'a2fb510d537b9afe8719334e5578a79a8ce7b021ff76c59830c749dbd963c38b7dfb60a61422b88f76886ccffb5ad5cb456b307a14ed68a5c86981eefd4fe3d0' - 'SKIP' - '5ecc37fe83f8dad00a82aa40a0c75d7518d6458b2f22d77820a28a34d772f1255cdb2befa5e525344d5deabac8f5dd092434a9ee2a9c27ccca5c5c231790c017' - 'SKIP' - 'bf138fd2ba2618ae9ff64838706c2212b478513e04b54ca3bdd8bf97292a8a310d73e0cd96533be62f139b645d7ac5de22a4c3bc1fd9f67e807bb862e965ea08' - 'SKIP' - '825397852f1c25b18c37d25bc53a7706af1eedd97cb9cf85ac590d1044e2254d06c4639bd54cac06ad42534399081b4ca17b0b10605c152ed41a22674c0ae42d' - 'SKIP' - '42a4c3debfa847f46c26db0d3e7cb1a540d3d15deae359b582eb2c71514c2cdb36c28c8c57b22dc32d0cee4d00ad7519da01c66127446692c81ea7a9178d722e' - 'SKIP' - 'ab28a1f4f1756b8451840566d8100cb3d0b498b13d006593c72829b9783e94900bae78ab47c576d156e1d08c56602274b3f7d5bd885de17336623b23c3e4f255' - 'SKIP' - '8481f23c33a84d8efb798f4b83f78011f74cd5a3dec428b177d7e600922836c1eec61c4238724038221d8ca2e2cdf20462c5911085da3461aa315f7dd19d96d8' - 'SKIP' - 'eca2778279d88085b6bf7af742773ad533906f98b146ba2526a9e00136e154913f233be728105765b0d2fc2774068f670a4ab1b49d8a7486d20e04d116f71c0b' - 'SKIP' - 'fea498b5c5ada6d7f57caf652b68f687081aae8552d2d04cd9e96764efd1b896208671f4f501210bb557710cca3ceb0c02ac2b5da6d4c04c210e87ec2d715384' - 'SKIP' - '39650b6ac7f62174d4b24e5267f9c6042c22452f16c649e032570eacf428e83ef8e10959fe54adf8573ac1c84d6082eb713ae5f173165af7d1f687e5d26fe6bc' - 'SKIP' - '3acc8aeadbac6ea2dd5a4fba4c10165dc1e6a4a55b838bff184fa46e827df67ea4e9a8535e17ed8cc80cc5338252306a76049af5956dc767bd591729b2aceb4c' - 'SKIP' - 'd442bf561a4b5dd1058c45a8181157feb268a84da94ec7f260dc6d10f7e0ddb71f1097bef945509f3d212431975ad3197f778bcc1c93ce1829ed2070bcf6bf9c' - 'SKIP' - 'c966ed5918d71acb91e988f3776d84db0b072f42e3e3f05cc178fa92a0d902fa3e34beb790c963042b52bc500d6ab9a2802b84a8411ca02cc1e28d361603bb2d' - 'SKIP' - '60fde203ea68744ea9bb8b81a18aedc8a4de8a985dc65bfd6b2f6b43210f87c2875e53eb61f4498c9b236892abde92da32755b69ee5bdb23f079079f22b529ac' - 'SKIP' - '56420f41da60382143b4df2d1fd58384180ca3a179b9f1b5082b2e4b74976ed13a29725c622e61c698631d923384082b43c9f703ce417d09e99556e4600f981f' - 'SKIP' - '5d880f3cdb32ed6fb7ce26ffbd1774fda56641d9304b5372806b6e559dab31dcac233cd6765a0b64bb6afe99fd9602402fb5e3b8c791cd1a9eaf9af28ca01bee' - 'SKIP' - 'a6098df3b653702e2689ec25934839c8a986b0e2f113b216ff4f86c8c5d530584f61d33bf4a027d1b304deb989406a3b342f13e11a66cc91ec69457c5d2e6f14' - 'SKIP' - '4a4af88fc8a8c37ae6d20b35d19e60a17672569d5489be120edbcc62ab3ba4bbc43b78cd0799b9fd73c84b089364320bcbad6fcb7128c2cb06d15ed984d6fc8c' - 'SKIP' - '411fd61157830b68da00e19be0d0db7ed61de97fd99b46a31c3958c5f66885265521e9e099c4f3404975db9de9b178cb698dbbe1399d81bf13ecff79b9ebd8b8' - 'SKIP' - '49adc1fc4c68da5c39d96746007d19107ae2d293518cfb36f3742aeba7723db31660fb1f7b3579e8fa88bb53206dbd1e718934f9b37e87925c6c0b06759e77fd' - 'SKIP' - 'f8a67f01fca5614f0eb3bfef59658913fb9b88b043f57c8bfedf04ad79912ff04d5d356dce8ff453ca001c151ab1bc017dcd7daffd5024e2bc20b087d08ab8ce' - 'SKIP' - '561a635f88fb3729937e1632d736a8981002cffd57cf16edad538381de8bb6a583f48b05e4d2bf1c8b6c03aece2495ac2850c1d66c4b540af2b88e1a9a0d9c2b' - 'SKIP' - 'da96dbbe3b6b4e189cf7bdce14647bba07bbc5599ce28ed385a1c34d237ee7ae3ac595d2552444615f2b15c2b7eda42f40743d5bdebd443e3ec31e5743f59056' - 'SKIP' - 'cb2494c930b2c2c4cd6755494339c5f95ace87940b2b2e51928d98ea63262e4bf7a4245f629b8bb06e7592f45a0c379e5583c8695563011009fdb07f965d7c1a' - 'SKIP' - '6083db5b92aa46bf54144b4d2fab368916974ef01334fbe934bded3818c5dfb4fc8d5d0e896bf1baddc29aac1c559f80dabc727082a757301117843def8089c8' - 'SKIP' - 'c25bff6e5be62aca887ae0781899e37a39e1aec90f0eb934ec5394abf560f4d02ad1fb3973a45d00058b46555bbc8d9febfcc8026e210f53a8864a91b3b80a9d' - 'SKIP' - 'e70e0077249bf008e069041a0239c6bb63075044cd0df3218649ff92a6a2d43467026886f2a6a70c70552268f6936764459d7cc0817a103b6a0f74c37c52c72d' - 'SKIP' - 'f1f853a0ef095a53080629a00598b7b1e0023141fb1890622ffd8efc4688afdeb87be4f1a096b76868840d45c10b3c88bb33f44677ff70378d63ec81eb3110e3' - 'SKIP' - '1b63569b589e994d1869e2f8eaf5d4ee225fe68862ac5c848e46544b827ca5fddb4bf060f5f39001608fd9bb284eec005f5f9b095307d3a008c9ea8957c2fad1' - 'SKIP' - 'f6430036af77a31a9ddd16200bd3c2c7b1b7e46475c7917dee91c835766be046a31736123ba8429ca2f0f8d3b93ef60522873bbec45d50b954cbb8319e6f25ba' - 'SKIP' - 'd7dffb68fd22db7ef41d1ac193dd297fb6150f034f257a44e6cb0a4848dc4a94e328c2e26d5296a72993e2db75d09e3ac46456d337a5bae767fb266082d3cc66' - 'SKIP' - '4e4792acaf0455f41cb1541d20d37e7a39104aa2dfb505e9be29dc3e7fecf328557780982b32cd8f67f77594542f5b8104766a4e8b5ce2270c9c601728363b3f' - 'SKIP' - '00417f024d2cc0b0fad28dec7f11c3054f5da7bf8c353d06fd1086be1926eacbe07ba924380157f270aac910d771f909f34beed0f60106f6ae60c96f58423b4a' - 'SKIP' - '2c254a2df00e79f03b51d13846f232073e9276e022c7bf46bfe810cc98456d481535152afa9d915e0726e7701594453f9363b6190b8e616db203d176a08fd31f' - 'SKIP' - 'cbfa20431371f3332f28013bfa21beef21a5a6f616e09fa91e9adb42899cb2e1880e27cf4b90bba980bce26710af3ac3c1e49054df4e48051bcc4612732d3e9e' - 'SKIP' - 'aca0527f5630671a319e7ecff958a3a64f29df73b427c67c1d29763cc1801fa82e96761c3a61c22d936913943a49261da64d490a0752ba9ffc8e0c1d92f99835' - 'SKIP' - '803736a8e836560b3e50b7c0c8cf1f9ebb16b8642cc7bc6e5167d19037bd757431565fe4581776e50eb2693c49f778a24fecff41a553612e7e498f755b8f2f67' - 'SKIP' - '4bc132d9c34deaae9b13d08dcff8ea83aa8f9ce4398531e0e0a80df30da3808815f3a587fe5627f6553b8e9c2aea6cc1749b752250a91c94f1cf8ba4f3eb5e8d' - 'SKIP' - '335c0c1164e9a2b9a9a252ddf7418ca0e6493f2f0fddcf3f01ae20666b6cb6713b8bf7a2a165d37485d2107b6c00f42b201974154c41c15c4456615b3bb0d78f' - 'SKIP' - '01a28159b9c42e6b52147d1b061e1a2cb40ee381f8b6f7e2db3f94adc160365bc0dee602713cf42745fd2275b822b273df25d739d7b77f03273922edc746e50f' - 'SKIP' - '42703ec988c2b1865fbe4eef67840f4370958e3e874d9f8a03a46c43619bed7656c56cae0ef1d8cca5340648b47ba7ddf813d25d9db3307f10146c45b8e34ade' - 'SKIP' - '029d9e899dd9e7bdbcacee34ee9b468e2e2a8f726e38d014891c8353f6afcc52a58c7d9289fb0487cce4d90c8d51f578c27b1dbcdab42de7308f50b7baf27877' - 'SKIP' - '343b48e982195e3f07aa95dac09d5e09d5c02f823b91cc4f0775fa9529e9a985923a5af48067a1f071b99613acfa25b18e3b083e094f3cd97f6758a495c91c3e' - 'SKIP' - '9ac15b3542629c5333cc7d7f53b4f2995d807a31331b9e04d3da051be0ddde7e8c3cbc79837ffb49a4d364db1680cdc6d763465fa56bd4d26b16b765985babe1' - 'SKIP' - '70e35154f9385156a11280294cc254cb314fd89653daedb46546a6bd64c550e3fc7e7a8df3e653c516687f0317bcc710fce82b4d649472333c501ed85fcd6cf6' - 'SKIP' - '576fd826f28d945782840865f3e5b7c87d7f6f91f08e473ff0d06a37caa2f89cdd9cb4a7aafef5551363aab9c60e887ee794d5b6292874c12baf88c23ea5668e' - 'SKIP' - '01125c624a4971686d02a23918e3da697645a322e5a7638159636d9a16c82f815efdad1d8e22c507518dc0b92b6842277637cb2d0940f4eaab40c0faa77d8da6' - 'SKIP' - '322e4e255a2b900ad224ff376b00199c40e26fc5407e15dd36c1ca4e51c7ca0431397a69696959d1c1910b02a4bdac8efbaa20f6f6f6dd5424b711c149ea367b' - 'SKIP' - 'ae93d961d0eef41ed39c473fe9478b62fab13ba395333b3c11b34b7787904a3d2684520ec76dbe2603dd96a146a68bcbe98da1b7e4cc1e659246127384bce22c' - 'SKIP' - '78376df2c548039620797ff202f85cc505047e3eabecfa8d2bb7858460ada5798a42b9671489327dcc217940845fb4b1e8648088a28342f0cfb630cada3d34f5' - 'fddb4fc3dc9887b5ae93a4bd2934c4296f559b672b9c759185ec3c3371fb626e17fcda9570568c8b796f2d38930e91f2595bede5eeb0b69a1efd3241413bb316' - '86ce7f5965f5bcf56447fb39588a6e3c8180f7ee4ba479d23e7695a1e28a4a1c6f761bf52d292e27e28c062045b36d4aedd6def8b6397f38b64fcb3ccc28ddfa' - '9f777ea3ebf2cbb36e93ba1a513244f4f203410899785fd64895328d91aa3f8b6576c2970d013ace254e72962af346b732ee6ff202c4433d23ecfec1e055cffa' - '213f55aa12bd5bfc3a04f057f28722c4747960c3a453c6173232557bd4b9ff1a2980c80604d75901bbf74099e8f741550e2a2df2e5a2728a0f5febd89f17c716' - '2803bcb958ee2e2e38a3ee75922bcc2c9f78bc108c7bcaedcf7e1f1002d9430945c967c3beeafc2a82127c0c7868d2fadcc73049ecad9a93545fb65e54a6ce64' - 'b8560579d4b8ae352a8e29c8335f4dd75df182f4d67cfb81d88a8a7f4df6d69389b34685364e45eb740c948865a1aeefaaed25cf393fa7a31d8863d07fb4db92' - '90b6177f60f18fb4b11e88cf0789f5426fceaeadd876503b3be2dff02b1c821e89c3873ae5d22ff1bb2df7d16f4dfb25471bf845372118bfbfe7b1079036da6d' - 'bc8656d038bb92eec7e49de1dccc0ecd6ef69b696103a4cb0e59d537dc5fa6dcbd927ff066743d9422d34750710410c5cdc1cf576b553f1693890cfe60828016' - '2e760b5f1fdc1a8cfc6f61c6ea894f9ba3aebc80788c332a945d23828c6479c5fda4af195010e7c50abcec5d3716bc1b10b3b4a70a6309e13fb7c4dd0b7a6404' - 'e2563eea0b9694d8dbe193b96f817b783485b25b6d01db0c2003a6d1302760cf15a8c084badc4ac33bdd324517cad5d02a0b6088f897167e628e575bc9214d0e' - 'e399a5ce09295cb2b9faccde569a27f879cc406b4a81ae537d499f7b0af4f73dfb5ebbdb9560d3adbcee6f6e4157e12528a50e5acd62a4cfe357bb24d112e43d' - '3c99b0dfc4164fa388901dc61695ab835f6457630f066ee1f11a0836bae4253081167530ebcca502441b3235e611f7e55a73a732378de08b21caab37132205e5' - 'c87df2ca6c4d22d892a7380dbacf11f7339c44819a431468646da6b0710787b10d30877a5715f2112952b8009da56a82f62eb6b56de237c0a898f29444987456' - 'f76a4d5e1018a9714c35b72fa1ec8b7ae733a0f08c013a5708b2077db4d4a9cdf4e7b2011099a89b6a534edd1bed7521dceb921532cce53d00d61ce9b0fdfab8' - '46466a484a3a0e35ee0dd518cbc5835d67555fb956e6437e5dcd36777526426064924fb3055f45da8683325acfbc9483dc0ad38359561a4c2e43cd9e80c8309c' - 'ef6d438bb8ee16e7ba6335e7b3d093249a71047a18d77128d928a07298163cc9758783fd6238c0c6e6fcfbc9b0e431ee9573b2032b8358076b8a93959c57ef5d' - '2ad62e57068b8d55eececbdb77312dbfdbc90d72c3a7b42247df25ad13e45009bb20bf30d5561733f6a8ddd93c0794cfa23fbcd37c0179a84a0cd33126f59afc' - '1cd764d2c118bc3056741b70f1f1c190ac9499e333abda842f062b2dad89c15bfd71453f2b131a7dcb7b5f63f2edec49dbdec24fef7190582e6584e52f5464a2' - '66e070bed3dfae3d47458927f3a6025870285647e9cd5725b272746dd7f5bb1618270b212730ca3956bfee280695b763357da8a3a4bc4acd92637ac6d291a879' - '54c2701af4979b633286d998eb7de436334c916bdc03c851ccb55ef924097df0b064fa5c203463cf0374318dcccc2c417b6d1b4779e8c4f13a8c1cfc47d012f2' - 'fdac37a7e08bdcc02ca18f08f07fc77d9deda250b317d74d34a67b876fc9dd5b33f9a710a5b460cb3b76e867a34ab67a5f1d224766fbd33029f43592b995dcdb' - '0a96c8157afc4edd464a009a26485f94a0572175dfa9d4459e2507f8c6bd5a5ba8bdd1a41597e8e557395b09f6b8ec2a0f66673c3bfce09a5f46e06e2bea7ad8' - 'b19d7c557981da2fd4b05fa8177b602cf87aa6713d58a32612b20682acba0226b7f562a694a7403308f4a32c55774425b8bb5d3ba9d5eb48c454fe1b9d4b9ae7' - '35a7cd64f4486669017f2f4164fce2f962f4bae222265d44afd4a83bc8c9b45d15539f9f246a4b6ed5759eb1fc77afe0c32ddf67a5db80343b2d080704327a99' - 'e826ffe9f46095211856369cde9ac68509b90caffaca4701c1936f19ccc30a494ca514feef563039b73e2d33a633b24d027c23e5492901deda6fa68cf2691eb0' - '8705c43043e8a1f76ba506039330a8c64df3794676ab911a8c89ff1adbd018f59343ff1becb383cb626112b81b14afa812c46e457ed3b323c718b29d5ebad71e' - 'c415a83603af5e53a8d61109abd6a28c486263be92fc3c8ed196244ad09b87e72a3c713fa87737703e2a050684dcd605ad90ac2f7b81c9d7cb53bb3c55fa373f' - 'ef20c22016ec56cf2c8afd183b39b3472fb030d788b8803da20bf6753773b54d28221d2f595fe27b7951d1fc269f3572e1a23bb533252de0f20ab8ee1ad3b56e' - '48f5e13d1f4e23e0bac628ab6766c13ca24d38698f37934b7dfc839c5de2e3d3842d5f6c9ee4591c0b2d934b7ac882d14abe793b9d33b84d888ce7965c194208' - 'c9dac039a1a2851e5b07e98307e0b6b78c1bfc30b7e413675ed64a833f820058093f49a845a2e1908c54967b7ed231b6d9592d4e91d460101c938bdb26a1ea37' - '623399900827bf19e84c3d3f4101e56a989882dde92cacc12153660b7c23681847ba92e215d455e40ada0cfb2b691de9017604a4f399044e4c74efaed2f291b2' - '6e7f15f76940756e928d9945290a74dc3ad665db4b1f2e2e91b24040f2c7cab837deae88b85879ce378689535e44f8ff9c672f974c8453520e20bf1acba0e3a6' - 'ab10791a9f66ed43bbd00433df10b345ae4c5ed16432849ff820c0d4d7f155ef28d9f028c00ee702f4a22075f0a9c57f44297c2a683e4cd326e8e2ac59f264ee' - '2406f0018ba3a5ad07239b11fb43d49f3571a57a3392a59169185ea54f0a50d1f4949b7741dd25d9c97bb6e332d49a115fd0d82d88e3ded648263125f4b8f20e' - '45b72aecaacccf061d50279f790598b22475b723184451dd1927c96471ff584b72062a3bf6e0a77c01ea297adca89154e3a30114aa6d8c32f664c90a7d8e4953' - '856b0de2f3ce534d47cdf34c70533e6a09878c4a5972b2bd42f12a42947178a67e449798bd1ad049de48df7f01e036119578fd5fe63d460d805c6147e78051a3' - '84afc20a730a7e94719238788db563abf8e02837e3a53814f848ce607ab42340de0c90f70eb565727a5fbc22ef254497fd08bf20286ead48b7cc175a1257eeb2' - '56c88c16b5f33c86c30e2bba355fef8ea63427124ed60afce39ee404c693eb2b688dfabaaedae3f27d0c9fb24aa1f8394b512be55afff4fdbb4155c1f27fa23b' - '9727b700967951095199ff0e9a7a8225fbad26b8e16757f5554c6ae6a62a38f0171a1228aa1b5c14f4f954a231aae13d512a27ed2ab32322dbed6a1e4ee3abb8' - 'fdcbc417f95e376e71fd2bdbbc7f991cd8a1bd16a36f6430f12cf66a72d60c75b1225c283d2451f7a303d49739b6088c4f2b4388059a09d4b0c54f7fe2a125d6' - '2f53a9a69084ce6c7bb680b68037fb59eddbe7d9dc8ddce38e2ac955100db9757272b735dd5c52d37829e3a30e7221dd5135e9537023b62447669828127a3770' - '9b030e1b2af31033360974a38bae0245263b675362b4fdd9d762d8f657710c0d6d08f3bbbd1bfd4a4a6dd3e8424f8eab56c4fc29bf9c059230c4c07b2d54b729' - 'd113c1fd41fd4c0a78d8989adde6b8e583662eae300a0d9d2667944a2f5621b653577d1d147bc3df94d06cba64c72bfac3ce09ec3a5dcf6b7478de4a9d81e9b1' - '66f5a50095d8c3e7b047ad7c0048a2a430e88241ba43b60247abe3d99faf7ea62568966eeeb38e6f8ed2b232c2b2bfc4afd46efed883a48660fc420793a13662' - 'c51eb6c7ecdd180e1cf2abc5dad2fa1c9d680545579b68576d97a0226b0cac2530c23a123284973f3ea9f8e8cce54772a567f9dd0ad5d9fa3e153ee4a60aed40' - '8a0ec91144691e2274a243cefc354dd1bf7949140da91ebd9113d8f4a54ee2e9d1f53ad352d75db545264bddc29e9a2fe3c4d0bc73807dcbf0b35945313c38c6' - '4d7f30645b60a53f38426ae3b81d63aeaa5131c37de609a29ed6f860b9c8c4af135344adc2ebf34d2578c5b7e24fc2f5953313626133a84dd11899ec8ddf86d4' - 'fe4c9b5c3daa914887734219bf63c651e28981cbc6ea9fdb11316b40e7c6e91d2784fdcc8307e5592eeed85809fb7e0ed284bd4b1e2e0714202f014705e4247d' - '5c5a6d3a59de1be12520ec544e9f259ceef4c0981f371b363a54b4b4764ffcec198d499059e94b4ebb1bdd0293438ea6b3ea6eff6812698d9c754e98af2a946b' - '013bd337c6bd839cfb5a0f2a3bbfc897a4662c414e048674d6a02187acdcd7ce85b380d5209f9fd88e6a29fc198921e29aac65a858f8c5f789a1ce23d0dfe6b4' - 'dd6c431db54ed291186cbe2ede032d8839caeaef83141d4f2fc4304c8580b426937da40aa29b66d3cbb52fedbc734c0dc6c99e5b5c266badb0d78b194f73c093' - '6c10ffec36ef7b097a4f0562cb559eaf49bbff31213181c725e6896bfb3f9112bc7a6f127a396ead99792ccd8d93019e3e4090806a417ba50d99711bb309cecb' - '83491203f17dcf589f99b7e677e7cbeb36d5bd22e05d5bb564a254776fbcfb6020606975bd5c44cb4bc603d7a89162f7c8be2a299758b5680b73aba49f6459e0' - '53291505b82c7c46cf40a8bed2fbb33bf452f521aa0c31aecbbc132a3de729288a03ff70e7cbbac4b615524306efcaae05d5fe33cfca3c0571bc539ab8eeeacf' - '5e11247e62024d30aa4f120c64fe44d9ba1633b0ebd34920a1152d3359b09f4bad33cf3cca6c559d84688b80471dcf6b7e0831aecd99d4e4a3dd6102064f70b7' - 'd9cd6ed387b51edb2c440d868b3c52828d2055269f956440ede8daa17cf0a9f9b892a760a84715193a46457369bfd418719fa36652a6365db74a26accda55df9' - '3ea8419ed27576b28f3a4f2aba084aba39304a38c580ad2da1c55f45d2ac248cf9bd0cc76be3ed12c6a62375469429ff762376ad07232269ee6d38134f495628' - '41e304ef1525b63dcbe5e25f27ce5f6a4d77fb27d69afc5f3a034b58a80902de75928fbb90cfa7171446ce657a6ddf11677172e0cee0efe56b4c4684644138bc' - '030d276a04d251647a138fda4d049db34873855aa87a493ff81d21ac4efe8ed6715315d6b39790c4d0fd0fe9760eee6bbca55e201934c93b914585aaa9cd0ac9' - 'c95dd40942604e42aae58a598f65a1741a4d87dc1d926e9d995aae5e6f839964b7ffcb55c59cbf7fc5f8a613ad68294fa15dd41d50705fb5d25483d847b00774' - '244402d04a67441247b677b67c20ce062aa9f7e5f0c22ff3fb96184cc06e457e7e93ce5dc2cb1c375a6f576c908bb8054fb5c4176ea5a0bc4261e9eee611cf9b' - '32eccd24610a5dacba9180be7cc18b9c8730437cc35d92fc59fb60bee9d02bb726ff96ef493cd4b8d92c8235a8c9f6d8a7bcebd5367852b08ae2ff886b5eb6bc' - 'd808120dc159bbfb34f40ccbe17aa294ea02f597ef55b9399fe79e38b53030f8dc050984dd25e7a77cc6ef7866cb873a58e1ae6a0ed1729072220dd3656cb472' - '1f066d60e0d6231c435953ae2eeef44c770ec5f3d3795c9bfe020c5cfc2394f9d58fd5add78ae73ec831b458818287ecf1875041da19b9e1ae5650a3324b86a2' - '37d68d540654b546174b477552d8efe8bfcbc973a7aea9bb2093824c000c55012200e822dfb5e4d66b17b55c170a631b4c89790c1cfa137afa73454de7a3a725' - 'b794ba2ca51562a16e845ff05cdfa1e7f1a872c06fdc9788bd3fc453ab339d8f4a5ae3969a948c5390819859d09295c761dafdf6370d04d17eda9412d7cbc608' - '2a8721f516ef944386388f618e0aa3b1470f12f9ce24ff1882428e3f27eb2974a61203470d3fb7b8cca73d6613a03c99872c9a63fafdbf1619a800418ca244be' - '2620608e725fe12c138ed72a5c57dcd862b589edd30c2d985fdbf641cccb2b381747315fad17e60bf078c6c76a139efb303dce24c78cbec72c971cc2870ac98f' - '216857269abc54234e29b58c8fe9a31c1d7948af398a3f28ff24c93bb07f6166440112a819bf72bb958db68457db1258eb5770602cb03e308d78034338667468' - '153e64cfc2b27bf53e0d494b28dace2d2929bed3257e223405e266c4ee7bdb27b5f0f175e731d84cadc0d54e3cbc7583dd03032c25e86cd2527a76b92c47f4e7' - 'c417088013c018053004a1a3d1c0f00455ad544ea80cbadc1f8e1a6004f1708a79ab9a0b8627b7e7e4d561d1d1977859fe9012e724059b18473fcea57e3bb28a' - 'a3ddf020bb109aa2b19904e5c054669e8c2abf2f0987de9f0dc2e501e753b96503636a9b6c440c8a65b5c214e83cd8b028044202525e1498172f5584f2b5f06d' - '9d0c0a46d6ad6d569324bc758e9d3734df0f761edaf58fb4634713afd6ec02b17dfc723d04a8cc71f2c7ac994d7159a2313b7d2ced844b8931f9a2ab9d55b2f0' - '54ded61d68ac30568aeefc921ce8bd7ae8a4402ac84d12cba71c57c7d54c9a73e3bdf8106d4307fff7aab7bdbcd432a5a4c07cb39fa2d1a27b4fd64d1e379651' - 'fabed5ff1b21970069e31c445c12834c116305aab7aa12213aa5f534c718431b5a400acd936b38e0422e98b16c8385a04a094aefc4a093317f06ad2c5a6cdefc' - '467c7bf855d6d259ab22fce97fa7bd9743f26f1de51c55c6b23d59c708b34c16c712c6db1d9a73f7860e2480bd38dbca7869cc0f46a0e62b3fa1f0ca188a8b3f' - 'beb17ef9a9aaf78d8508e783665c4cb53da1b19f2a845919f0678d6f59f3eab241378cae321c2aede2bb5cca4c205ba95290475a345d667938c3b6d0333d671b' - '9b5cc40d4223bc596ec47d8b6cd0cf20df97b984a41978a134e71b78541d73f065f0d70337030675f37b70a9d0b39f5ca36e323a59e02aee27affb2cad275c64' - '35bb4e672a7bec3875128a92e1d4abd8f81ae3957faef9a9ecb862abfab7b84e21011a6684abe1e8bca920f11bdd20e7a068104535a5cedfdc396cb529b7d655' - '8f7d17eed0344e60e064b65207ce3958c98fd1f65805b13d4b4dba40671d4674816abf290d381db6ca21617f81799dae7b5aff0e482f045e7d96b2bdc6052d50' - 'd361c571f4a17bf9bb617098b8650b248a1b4e740e4b92e5068a709b1221135f85d8996bde94d4bf9398481a7bd55aaaabb4a72d5d60337da248c1500e1da381' - '6bcfd735b77bc621a3a9fc59e8193d507c6c451c3deffbad2776a3c6bbba759a510151c24adde1971977d2286823b0f1fa5d933cdc9ba3058cbc8f1a60209efd' - 'e243ab1f123e4d5a67c973df11d6bb03d9c9bc5b4ecc9a1fa706fa9739113fdbd8900bce0dae4e1825acd90fe4058cc5a5df6e7cf02588c88f55194a8894f7af' - '3d8d021c91f7d63a502ec4730cff9927e45a1555412c09a31b7bec151e484ee56d7aec445d6a062083de235ef094da05d6c05576e94afd2266fa0f539d23c6c3' - 'ea81cc1afe6c844e88565149c6c0585679a94f0e93466e914a99e3428e3be8533406af4e763c883b69c5f6e1ea25490f13c3871e5609646e349816b5c0222674' - '2e7b7aa453cc5456d42f3a6d4ca5f2453bdd559402ad89337be7ad701b5edf4ec7602fa47d7c0761c40aaf6ffbd8c0e62b710d88d98254dfe8581f764bfe2623' - 'afe938f51f1a82fe3ab0c4098154f98e052c03b66fb653da9bda99412b443322057292c9eb5017540191c763adc39b7b9fb2c488e8a7af06138546b0dc69a113' - '22ed618b49163c3dc1bc2d0d63d9d012e346c7c79c123cf804eea60138c51066eb3e7e8b5020981c23e54d39d622b7db1f8664c5ec2f3c4780e29572c4c37550' - '6ea6ebe33883b40ceb2a58b858e4046b61d34f82af4a63420eda79409fe198cfe3750fb1bc58a6b84745d4989cbf0827fcff550598c80ace79248ff7d30f786e' - 'd49e1172dfbb88d132078447c65e3e3ba979a001be3dbee84bff7dec88f30f6b207410c3cd868bef583b2355f8fb11b8549aa5fa6102148f83ec61693a6e0060' - '919bc61ec0b031f0cf6c551ea841384c97f769ce67118e5971600947b93d96fe51457712d2034d3587c30a3a780cff346489c75b5fc4987131b1fb6f3356c0ed' - '8d4901da1777c596aa8d39b13cb7e96a463c0b258f8ed22146d1a1c4d89e947befb8596f7d7b74da06ccb8f61e4b3ced83b4edc18461d92620cae9ff0c8ed8a0' - 'c7a0bcf0dd326e6d682df26c1c82c325ab5607158a1aab37734a7cf3b7490dc8573e9e9c11eafa9ebd770c12c97211b80ce9affa02613d8ce4e5dde22fe822a7' - '174a2b8368718b02f82542b097806089e7d3c91d860b1dc4835e1cd95f4dad506ba1e12282e5337022ae83fb31456ad38587407b8652d205b07d5759e645d041' - '5ef622fe966a59db8ac97e8faaaf730a00068b17d8a19047c877cb2702a1f35c7a4251ddd3a4255880d0d5b9f0d155e7b69dc637ad2d8c4b091fe175c163f0d9' - '793a9d29908215f7b8008a582c652e3cc9098228daf3410c198fd4d2a3ef7c7f64c851237d937104ff0b53c1a38c9046afc63eb4b4e469d8ee5cf64235973fe5' - '092de1c8d086d3609e508df4ed8495d9f22be60df05768d3bf48e45b2fe1fbcc7f0a986e96a8758e3e15bef5dce3d678dcbbc6c68cff488e79e5ceccd99373ad' - 'b589e97e4b1b95972c2efa67d1b0b9f5821eaaf53c69b43c37a216dba93c56b1b645fac02ca8897b599791c82664b3f365f2b8985d72ac945ebb88510ec3e747' - 'af3e2a635a1bcf17f9d8f9261e1cdd34e01869af83d6bb7d7098e42f22ee957164d5bb132e8110061594d51bf104c13ea25d6be3736f46e0f7c13b398b2ac3d9' - '61ae0ade3339fa6c6651393345740a435a584bed06374ef5cefbee14890f131af9f8ce3d3fc4dd179f1823a3a766ba2ece73bfede1ccbb6ce4b48f1ea50dec8d' - 'b49142d2f0735f8811adab9b876a16c05aadc0de80b24eaf18b708c2ad085558c7e35120a2f68ead47d5f0b1df21cfd7194d63513cb5f04b3886a9b77a99eea3' - '0aa6b640bebce63600d0bda8e662c6b74160017abf9a6d4105f8012144c69b267aaea0dd853cc14c1a2d85b5c29058ac8c9f27ad54471c8472fda15b21168526' - '8fe995223e15e42b7dfe9525a9a962d84606f257730560bdabb00fa81db85266052c9019ea177d70dddfb572c00e6f98248abd5ec808468fbcdfbfbc3a974456' - 'e33658aff13dad71b554293f0ef52aa7ca9b7e618adeadb948defc7343a8cba1d6d96de3184a8350e6b362cf77a7e006dd1896c3ab6b040a1766cf290bf1f99c' - '1f00f2d9a752d2f5a0c9155ede6ff87c6880e26e523182348e539f5db3ceb34fc3028602feebee762e23007481943ae08652cb74e273eec3ac10d4599b268b2e' - '28d29e86afb4a64c74887bce2d8a3416ba2a77d5d67575749eb0e7a118241484a76f2769084c276e8393110d9576c521c14e997c6ee65a5a8181e18e8525d833' - '099075b848e7d962bbb3a3b0462bb32320616c3fbae5f0a97dc09f9ea7f3de2d8a7b72fdee7ba05ffec3fcc3d363c8c67e19e9a94d630a6bea02d85d3d551a97' - 'f0dea172bff374f107f3d814fe9f5b7967aedb3ed754e79b83119fa3945d73be45767dc7f1f042b481dffbc1cf54b1371da410632fd363717ed6f1f969dc00f4' - '1e3db632b5807555848796e66fee2854c0919e83681515bb8abcee6ae4f880e2b900b28207fd9167cb7f4a49fbd113ee99bd42cbd2d9c6b66313ed38e39c50fe' - '8a64671e0ff18698c3aedb351a6ac84e2d6f57924b9fec4718918db2b6f555b07136aeb171bb122cc45ad6577ddd6e6fdee12b1f743c621b965cc7ad2c735cd5' - '3de54bf2f218aaa31931b27e6733615be8842475ec1d30d70eaeae86d806a0999469641edc6b1b363e1555983cfb58ae47bfe8aad5bf2fa2c6247c0555fdd574' - '2f1818d83a7e93b2499ef49708d15cb50022e4c932c6078d8a02ba609c2f239b059e0a52d1c71766f102318c36abf8a0301031c1018c3489046c13531270e5af' - '23a395f52648c250d288e631b1dd019a158b2a44f75a953e3d6a116f37b3aaf7e9c6483eb680bcb579945dbbf1aa15545815f5be5679283d464c2bac293420a4' - '40fdc819dc18b20f1bb468079f356860bb75d5f98e3239c22b435bc0e08fa2d08273c9fe6a4d4a528b670032e9a0efd4f5173d67d2d8fcceed8a30f243f6cc53' - '9267f5a66fc6cb1c636fc2c49dc8bf9a62f2b4aa1ce5ac68babab9e9457c7d8e512ae266ec32cd191a4a4db9cd232f0f0a4d37461f029e9e456d3d63feb5d16f' - 'e9bfcecfda7fc7260b19c6fd91052f0dff309ae2ce47b8ac60634af825ec8fa26dfc4f2e24a87c7967686e90f5ba894221bc59b152abd79d8f601db7400543b3' - 'f3d54be6c399564c7d4b8a96e99a8a9baeacfa2bb0f21559dabb1c223e615d4c8c6b50b11b40cd066ac9d9ded042e208bdaa1b34c1725924677677e9d0643a80' - '031e05f2d6e9890cb9347e0038791de2431fc8671750d0281ee081c8991387a75c0ee8271bc0f7cc97fe63e0be63dd5bd83fb48066738b96051cc1195fbbda52' - '01783721b2c77e016c74773262f0dbdc30a31fe58985e66e2de1a0cb07b16bba1637d0d36351372dfe74726ab55add7208296771b7c128faf89fc0d7bef9737a' - 'e32dcea4aebab71527c22be170d392324f5a5fad6794a31d3ac7994f99f9ff695fcda1ace940666d08d5cc3eac57b6de3be7ee7ae98e93bd443019d67ac73324' - '153b7fcfeba27394a1293bcb0df0670ed7389212584d5eb0ee7b8cb201bd078f53ed77dba88b7101f00e15f841f83d8b6edcdc373ba9bcfdb4c65745ca553bb8' - '775790b47d076882834bd2df0a5cc6ded07fba024f76022b32476db27115e80f7c4322e671f601fd3a1c61b190fbfa392186191303596c01a5d851e224a0d5cb' - '8dc998edcbf7c36335aaeb6b3700df9fdb44e32ce3025830e07af59148715faadd3fbccdefee0c828442996d2c88e49bd2390d3b30eca4ee5545e97a51727cd6' - 'b03e89230088d6adae22bc52e4b93e3ddfd6b0496c02d8f36a946bb30b55a2741e76b9d5a5eda1e1d17261d4d5f9f7e07137a9fe298ef3c734a21a3c4ac09025' - '6c7f77d61ac0b38a282c3ca7a58cbf263f3c7834b2565ea70979ff97802354c8ff689b5b14ed09f1caee49859ed092448742a59c8297eb5c65e106a832083d1a' - '93a6afb6926c69f8c74141e71aad526050609b5a7792376a0c2e8f77d4c7b9b9dd8f6a9c7a6fe91c6f862d408ecb76c88bafcacedbe307b6981e19b262877554' - '516b3d185744836ce010a3e96225d4fa4c90e8ee3be927b1452326009c3e9f44a3651c6e05f52a7b62385dd95fba42c588de096a59853d7a19770f65ef8e8bec' - '7ec40f50f4c1dc9bba3fbafd4d78b6d8832a32b9d1fccc482d0d353ebe512189dff6cc5d6b2861f6d407dafb8660d856feb116bd2e1e3712b10e00c93a1bcc52' - 'ab282f162a30ee054ba0415099ba176d9b93187ca51b076fda570e73e566b33ca9133635f8373796f0b7e4e1b10b7dc879d3d40a1147d4649c8ac1d779898cd6' - '954547ae2ec21bd4accc78ac98c3c006fc59f4de664dcea9e2a7a7983e307d69ec9d36bec71affa35f55c45a0df48825360e3173974787744f631c2fc5899772' - 'fc9b1f669658782b0b1bd24d78f417ab1adb7fa2f03d1e786dc417f20f062a1636ae39e388c3dcb0e2cbe4b85715bcdc4d1e14781e02117a8da3aac002f589cc' - '07257129cd109ff9bac262ea609d986be416a5b51ed3c59eca7ab8a1f208a09e6e84d02e8a5afb582396531602bd5230ab452398a77eb5d995c54c9ec129f356' - 'f9ff214893ee8e12c1dfbe7998b5e5c46eff9ae99fc9b7be3b5570bddb11621b3d3de4738cc5c07f36e8aee6b2340450e23b85ad5fb5e3cba0ae07492593bcd6' - 'f291a2ceab4c4d3a77232cae61c512afa4fbd7ef2d246ae34949530381890107aa2eff821e0619f72c5e0e59e06a9cb8a91597514b3493f91a5bf6dedf6a6959' - 'eb7bb50d8dbb66f61466c21abcb513ce8e9ca7cc92f528e8a6bb79378d82c77e1ce8bf5d43cce2691002f01a797b593e119808213b33fd41b89339862295c169' - 'd5c33c3913958e4a274cbf7259277139992b5223f66ce4d78f3caa01ee1268f3f4f03dda031617b46753375bd845aab9f9d6ef1579f8d3fcf8e7b27001995197' - '6e76476209999f9bcc7d90c4124f30eea7756b9acbd919793c93198ef504d47e80b89423c0b93c9c7b6db55479e8f795593c69d540094a8b845899f7bec46411' - '84e559dce8b21d6611619f48352bfe7b00bdb933b9b984ce2cd2724782efd7c1eae21856cf5f94d8a0ffe3ff66e4d00c2b099236527c7defbcdcf7cb4c04b7aa' - 'd26c85dd95e4474d35439684140bfa3955d6b545b910db3a1e50062a60be75bba668d91e73b5fb5e38aaac21b31715c2ffa2cc168f3b48bd9637eb381b243c77' - '753658af251a83196626a8767d345a43d6fbf8b93574a1fc13287bb9b173c24e805df9a6b463f52fa8c887367d52c5e572ce92381a4c3b3d44af5dcbcef6ebc3') -b2sums_aarch64=('9ee4a04952676941a0aca4ded0cfa79f1b33e485828d620807da04a3dfd3c3fc920746182091dadb32fb6fa2f289cd939a3a35569fb4ef8f923682b421461b58') - -# Remaining P16 fixes; SPI-HID transport is already in the Omarchy patch set. -source+=( - arm64-acpi-allocation.patch - p16-thermal.patch - p16-virtual-gpio.patch - spi-acpi-irq-retry.patch - asus-arm64-combined.patch - ipv4-free-inet_opt-ireq_opt-after-rcu.patch -) -sha256sums+=( - '0ababbaed19c7108e8564916fac1b8fecc44010e7f3e4b419c34d01c66049e19' - '64bffcc23de4b023aa6bfe5e351eb39b3e5c4ba572122564690a5e0e9837d392' - '0e20e5854cb0613e154f18cb8ddbae52a3ae614915815ea2872dd7db6dc97018' - '6e94e341bcd221dbfec7432c12a7668b6da9eac34a1f3ba7e3d337657baa8d79' - '2d3e0c20fc1e451e3d127462e59540fc74dce829f5244060e07c24e36027612e' - '3f6a2afd7b321d618a06e18b6fc0bd6c911d5b40547d22b6fa109c0077dfc5ff' -) -b2sums+=( - '693cd18dfde6d3a831bd7a47d0ee64dcbd206bb9bf99832365c653839f6b4116cc086f5596c53b74eb07210cf0f74ffd496a7157681cc50421e8fdcc2fc9ae98' - 'cf5400aeafa03b8ad3370ee6cc5c2a524d37100b578db665cfbf882feb19143480c103a55970859f4b67016124c0271ce98bc3130cefeb08f7a6f4bd35aadd8b' - '54d04dd82919f90b5645da972f928eef016ecba2ff7c3cb61968f1687d4f796093756cc040d5e4254270e1a4a49a774d76c71caeff978e1875baf36f748b90ab' - 'da3f0ce31b953b4b6a5162423d06a692d81349457533cf5ac8758a00aa5f305526ba567fb25a4ad28b10c631ce47b2b617753e6f207b63aaf5a1bd8bf1e10681' - 'cf6ed7bf171a34b508b3b945614172c89bb46cf72953236e6b902deb5c0b3d58084727e4ed27dfaa36adc06c9862b32b21ba41aa8ca080363990837b73682a17' - '27cf2005deec3f7314420bb6fe93718e05315aa932204e2ce28a8a86b5ee6eba2fc96b9597d9b672a5eec6af3a482b8422d9fc9c5f20b51269d6679434e08213' -) - -# https://www.kernel.org/pub/linux/kernel/v7.x/sha256sums.asc - -export KBUILD_BUILD_HOST=omarchy -export KBUILD_BUILD_USER=$_kernel -export KBUILD_BUILD_TIMESTAMP="$(date -Ru${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH})" - -prepare() { - cd $_srcname - - echo "Setting version..." - echo "-$pkgrel" > localversion.10-pkgrel - echo "-omarchy" > localversion.20-pkgname - echo "-p16" > localversion.30-p16 - - if [[ -n ${_rcpatch:-} ]]; then - echo "Applying patch $_rcpatch..." - patch -Np1 --fuzz=0 < "../$_rcpatch" - fi - - local src - for src in "${source[@]}"; do - src="${src%%::*}" - src="${src##*/}" - src="${src%.zst}" - [[ $src = *.patch ]] || continue - echo "Applying patch $src..." - patch -Np1 --fuzz=0 < "../$src" - done - - echo "Setting config..." - cp ../config.$CARCH .config - scripts/config --disable RUST --module SPI_HID --module SPI_HID_ACPI \ - --module SPI_HID_OF --module ACPI_WMI --module ASUS_WMI \ - --module ASUS_NB_WMI --disable ASUS_ARMOURY \ - --disable ASUS_WMI_DEPRECATED_ATTRS --disable DELL_ARM64_HOTKEYS - make olddefconfig - diff -u ../config.$CARCH .config || : - - make -s kernelrelease > version - echo "Prepared $_kernel version $( localversion.10-pkgrel +- echo "${_kernel#linux}" > localversion.20-pkgname ++ echo "-omarchy-p16-asus" > localversion.20-pkgname + + if [[ -n ${_rcpatch:-} ]]; then + echo "Applying patch $_rcpatch..." +@@ -1640,23 +1633,14 @@ + + echo "Setting config..." + cp ../config.$CARCH .config ++ scripts/config --module SPI_HID_ACPI --module ACPI_WMI --module ASUS_WMI \ ++ --module ASUS_NB_WMI --disable ASUS_ARMOURY \ ++ --disable ASUS_WMI_DEPRECATED_ATTRS --disable DELL_ARM64_HOTKEYS + make olddefconfig + diff -u ../config.$CARCH .config || : + + make -s kernelrelease > version + echo "Prepared $_kernel version $( -- -- If you have an ACPI-WMI compatible Asus Notebook, say Y or M -- here. - - config ASUS_TF103C_DOCK - tristate "Asus TF103C 2-in-1 keyboard dock" ---- a/drivers/platform/x86/Makefile -+++ b/drivers/platform/x86/Makefile -@@ -33,9 +33,6 @@ - # ASUS - obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o - obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o --obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o --obj-$(CONFIG_ASUS_WMI) += asus-wmi.o --obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o - obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o - obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o - obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o ---- a/drivers/platform/x86/eeepc-wmi.c -+++ b/drivers/platform/x86/eeepc-wmi.c -@@ -22,7 +22,7 @@ - #include - #include - --#include "asus-wmi.h" -+#include "../asus/asus-wmi.h" - - #define EEEPC_WMI_FILE "eeepc-wmi" - ---- a/drivers/platform/x86/asus-wmi.c -+++ /dev/null -@@ -1,5515 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Asus PC WMI hotkey driver -- * -- * Copyright(C) 2010 Intel Corporation. -- * Copyright(C) 2010-2011 Corentin Chary -- * -- * Portions based on wistron_btns.c: -- * Copyright (C) 2005 Miloslav Trmac -- * Copyright (C) 2005 Bernhard Rosenkraenzer -- * Copyright (C) 2005 Dmitry Torokhov -- */ -- --#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include -- --#include "asus-wmi.h" -- --MODULE_AUTHOR("Corentin Chary "); --MODULE_AUTHOR("Yong Wang "); --MODULE_DESCRIPTION("Asus Generic WMI Driver"); --MODULE_LICENSE("GPL"); -- --static bool fnlock_default = true; --module_param(fnlock_default, bool, 0444); -- --#define to_asus_wmi_driver(pdrv) \ -- (container_of((pdrv), struct asus_wmi_driver, platform_driver)) -- --#define NOTIFY_BRNUP_MIN 0x11 --#define NOTIFY_BRNUP_MAX 0x1f --#define NOTIFY_BRNDOWN_MIN 0x20 --#define NOTIFY_BRNDOWN_MAX 0x2e --#define NOTIFY_FNLOCK_TOGGLE 0x4e --#define NOTIFY_KBD_DOCK_CHANGE 0x75 --#define NOTIFY_KBD_BRTUP 0xc4 --#define NOTIFY_KBD_BRTDWN 0xc5 --#define NOTIFY_KBD_BRTTOGGLE 0xc7 --#define NOTIFY_KBD_FBM 0x99 --#define NOTIFY_KBD_TTP 0xae --#define NOTIFY_LID_FLIP 0xfa --#define NOTIFY_LID_FLIP_ROG 0xbd --#define NOTIFY_KEYSTONE 0xb4 -- --#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0) -- --#define ASUS_MID_FAN_DESC "mid_fan" --#define ASUS_GPU_FAN_DESC "gpu_fan" --#define ASUS_FAN_DESC "cpu_fan" --#define ASUS_FAN_MFUN 0x13 --#define ASUS_FAN_SFUN_READ 0x06 --#define ASUS_FAN_SFUN_WRITE 0x07 -- --/* Based on standard hwmon pwmX_enable values */ --#define ASUS_FAN_CTRL_FULLSPEED 0 --#define ASUS_FAN_CTRL_MANUAL 1 --#define ASUS_FAN_CTRL_AUTO 2 -- --#define ASUS_FAN_BOOST_MODE_NORMAL 0 --#define ASUS_FAN_BOOST_MODE_OVERBOOST 1 --#define ASUS_FAN_BOOST_MODE_OVERBOOST_MASK 0x01 --#define ASUS_FAN_BOOST_MODE_SILENT 2 --#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02 --#define ASUS_FAN_BOOST_MODES_MASK 0x03 -- --#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT 0 --#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1 --#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2 -- --#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0 --#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1 --#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2 -- --#define PLATFORM_PROFILE_MAX 2 -- --#define USB_INTEL_XUSB2PR 0xD0 --#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 -- --#define WMI_EVENT_MASK 0xFFFF -- --#define FAN_CURVE_POINTS 8 --#define FAN_CURVE_BUF_LEN 32 --#define FAN_CURVE_DEV_CPU 0x00 --#define FAN_CURVE_DEV_GPU 0x01 --#define FAN_CURVE_DEV_MID 0x02 --/* Mask to determine if setting temperature or percentage */ --#define FAN_CURVE_PWM_MASK 0x04 -- --/* Limits for tunables available on ASUS ROG laptops */ --#define PPT_TOTAL_MIN 5 --#define PPT_TOTAL_MAX 250 --#define PPT_CPU_MIN 5 --#define PPT_CPU_MAX 130 --#define NVIDIA_BOOST_MIN 5 --#define NVIDIA_BOOST_MAX 25 --#define NVIDIA_TEMP_MIN 75 --#define NVIDIA_TEMP_MAX 87 -- --#define ASUS_SCREENPAD_BRIGHT_MAX 255 --#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 -- --#define ASUS_MINI_LED_MODE_MASK 0x03 --/* Standard modes for devices with only on/off */ --#define ASUS_MINI_LED_OFF 0x00 --#define ASUS_MINI_LED_ON 0x01 --/* New mode on some devices, define here to clarify remapping later */ --#define ASUS_MINI_LED_STRONG_MODE 0x02 --/* New modes for devices with 3 mini-led mode types */ --#define ASUS_MINI_LED_2024_WEAK 0x00 --#define ASUS_MINI_LED_2024_STRONG 0x01 --#define ASUS_MINI_LED_2024_OFF 0x02 -- --#define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE" --/* -- * The period required to wait after screen off/on/s2idle.check in MS. -- * Time here greatly impacts the wake behaviour. Used in suspend/wake. -- */ --#define ASUS_USB0_PWR_EC0_CSEE_WAIT 600 --#define ASUS_USB0_PWR_EC0_CSEE_OFF 0xB7 --#define ASUS_USB0_PWR_EC0_CSEE_ON 0xB8 -- --static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; -- --static int throttle_thermal_policy_write(struct asus_wmi *); -- --static const struct dmi_system_id asus_rog_ally_device[] = { -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "RC71L"), -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "RC72L"), -- }, -- }, -- { }, --}; -- --static bool ashs_present(void) --{ -- int i = 0; -- while (ashs_ids[i]) { -- if (acpi_dev_found(ashs_ids[i++])) -- return true; -- } -- return false; --} -- --struct bios_args { -- u32 arg0; -- u32 arg1; -- u32 arg2; /* At least TUF Gaming series uses 3 dword input buffer. */ -- u32 arg3; -- u32 arg4; /* Some ROG laptops require a full 5 input args */ -- u32 arg5; --} __packed; -- --/* -- * Struct that's used for all methods called via AGFN. Naming is -- * identically to the AML code. -- */ --struct agfn_args { -- u16 mfun; /* probably "Multi-function" to be called */ -- u16 sfun; /* probably "Sub-function" to be called */ -- u16 len; /* size of the hole struct, including subfunction fields */ -- u8 stas; /* not used by now */ -- u8 err; /* zero on success */ --} __packed; -- --/* struct used for calling fan read and write methods */ --struct agfn_fan_args { -- struct agfn_args agfn; /* common fields */ -- u8 fan; /* fan number: 0: set auto mode 1: 1st fan */ -- u32 speed; /* read: RPM/100 - write: 0-255 */ --} __packed; -- --/* -- * / - debugfs root directory -- * dev_id - current dev_id -- * ctrl_param - current ctrl_param -- * method_id - current method_id -- * devs - call DEVS(dev_id, ctrl_param) and print result -- * dsts - call DSTS(dev_id) and print result -- * call - call method_id(dev_id, ctrl_param) and print result -- */ --struct asus_wmi_debug { -- struct dentry *root; -- u32 method_id; -- u32 dev_id; -- u32 ctrl_param; --}; -- --struct asus_rfkill { -- struct asus_wmi *asus; -- struct rfkill *rfkill; -- u32 dev_id; --}; -- --enum fan_type { -- FAN_TYPE_NONE = 0, -- FAN_TYPE_AGFN, /* deprecated on newer platforms */ -- FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */ --}; -- --struct fan_curve_data { -- bool enabled; -- u32 device_id; -- u8 temps[FAN_CURVE_POINTS]; -- u8 percents[FAN_CURVE_POINTS]; --}; -- --struct asus_wmi { -- int dsts_id; -- int spec; -- int sfun; -- -- struct input_dev *inputdev; -- struct backlight_device *backlight_device; -- struct backlight_device *screenpad_backlight_device; -- struct platform_device *platform_device; -- -- struct led_classdev wlan_led; -- int wlan_led_wk; -- struct led_classdev tpd_led; -- int tpd_led_wk; -- struct led_classdev kbd_led; -- int kbd_led_wk; -- bool kbd_led_notify; -- bool kbd_led_avail; -- bool kbd_led_registered; -- struct led_classdev lightbar_led; -- int lightbar_led_wk; -- struct led_classdev micmute_led; -- struct led_classdev camera_led; -- struct workqueue_struct *led_workqueue; -- struct work_struct tpd_led_work; -- struct work_struct wlan_led_work; -- struct work_struct lightbar_led_work; -- struct work_struct kbd_led_work; -- -- struct asus_rfkill wlan; -- struct asus_rfkill bluetooth; -- struct asus_rfkill wimax; -- struct asus_rfkill wwan3g; -- struct asus_rfkill gps; -- struct asus_rfkill uwb; -- -- int tablet_switch_event_code; -- u32 tablet_switch_dev_id; -- bool tablet_switch_inverted; -- -- bool keystone_available; -- -- enum fan_type fan_type; -- enum fan_type gpu_fan_type; -- enum fan_type mid_fan_type; -- int fan_pwm_mode; -- int gpu_fan_pwm_mode; -- int mid_fan_pwm_mode; -- int agfn_pwm; -- -- bool fan_boost_mode_available; -- u8 fan_boost_mode_mask; -- u8 fan_boost_mode; -- -- bool egpu_enable_available; -- bool dgpu_disable_available; -- u32 gpu_mux_dev; -- -- /* Tunables provided by ASUS for gaming laptops */ -- u32 ppt_pl2_sppt; -- u32 ppt_pl1_spl; -- u32 ppt_apu_sppt; -- u32 ppt_platform_sppt; -- u32 ppt_fppt; -- u32 nv_dynamic_boost; -- u32 nv_temp_target; -- -- u32 kbd_rgb_dev; -- bool kbd_rgb_state_available; -- bool oobe_state_available; -- -- u8 throttle_thermal_policy_mode; -- u32 throttle_thermal_policy_dev; -- -- bool cpu_fan_curve_available; -- bool gpu_fan_curve_available; -- bool mid_fan_curve_available; -- struct fan_curve_data custom_fan_curves[3]; -- -- struct device *ppdev; -- bool platform_profile_support; -- -- // The RSOC controls the maximum charging percentage. -- bool battery_rsoc_available; -- -- bool panel_overdrive_available; -- u32 mini_led_dev_id; -- -- struct hotplug_slot hotplug_slot; -- struct mutex hotplug_lock; -- struct mutex wmi_lock; -- struct workqueue_struct *hotplug_workqueue; -- struct work_struct hotplug_work; -- -- bool fnlock_locked; -- -- struct asus_wmi_debug debug; -- -- struct asus_wmi_driver *driver; --}; -- --/* Global to allow setting externally without requiring driver data */ --static enum asus_ally_mcu_hack use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_INIT; -- --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static void asus_wmi_show_deprecated(void) --{ -- pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi is deprecated and will be removed in a future release. Please switch over to /sys/class/firmware_attributes.\n"); --} --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* WMI ************************************************************************/ -- --static int asus_wmi_evaluate_method3(u32 method_id, -- u32 arg0, u32 arg1, u32 arg2, u32 *retval) --{ -- struct bios_args args = { -- .arg0 = arg0, -- .arg1 = arg1, -- .arg2 = arg2, -- }; -- struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -- acpi_status status; -- union acpi_object *obj; -- u32 tmp = 0; -- -- status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, -- &input, &output); -- -- pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x\n", -- __func__, method_id, arg0, arg1, arg2); -- if (ACPI_FAILURE(status)) { -- pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -- __func__, method_id, arg0, -EIO); -- return -EIO; -- } -- -- obj = (union acpi_object *)output.pointer; -- if (obj && obj->type == ACPI_TYPE_INTEGER) -- tmp = (u32) obj->integer.value; -- -- pr_debug("Result: 0x%08x\n", tmp); -- if (retval) -- *retval = tmp; -- -- kfree(obj); -- -- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -- pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -- __func__, method_id, arg0, -ENODEV); -- return -ENODEV; -- } -- -- return 0; --} -- --int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) --{ -- return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval); --} --EXPORT_SYMBOL_NS_GPL(asus_wmi_evaluate_method, "ASUS_WMI"); -- --static int asus_wmi_evaluate_method5(u32 method_id, -- u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval) --{ -- struct bios_args args = { -- .arg0 = arg0, -- .arg1 = arg1, -- .arg2 = arg2, -- .arg3 = arg3, -- .arg4 = arg4, -- }; -- struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -- acpi_status status; -- union acpi_object *obj; -- u32 tmp = 0; -- -- status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, -- &input, &output); -- -- pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", -- __func__, method_id, arg0, arg1, arg2, arg3, arg4); -- if (ACPI_FAILURE(status)) { -- pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -- __func__, method_id, arg0, -EIO); -- return -EIO; -- } -- -- obj = (union acpi_object *)output.pointer; -- if (obj && obj->type == ACPI_TYPE_INTEGER) -- tmp = (u32) obj->integer.value; -- -- pr_debug("Result: %x\n", tmp); -- if (retval) -- *retval = tmp; -- -- kfree(obj); -- -- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -- pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -- __func__, method_id, arg0, -ENODEV); -- return -ENODEV; -- } -- -- return 0; --} -- --/* -- * Returns as an error if the method output is not a buffer. Typically this -- * means that the method called is unsupported. -- */ --static int asus_wmi_evaluate_method_buf(u32 method_id, -- u32 arg0, u32 arg1, u8 *ret_buffer, size_t size) --{ -- struct bios_args args = { -- .arg0 = arg0, -- .arg1 = arg1, -- .arg2 = 0, -- }; -- struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -- acpi_status status; -- union acpi_object *obj; -- int err = 0; -- -- status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, -- &input, &output); -- -- pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x\n", -- __func__, method_id, arg0, arg1); -- if (ACPI_FAILURE(status)) { -- pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -- __func__, method_id, arg0, -EIO); -- return -EIO; -- } -- -- obj = (union acpi_object *)output.pointer; -- -- switch (obj->type) { -- case ACPI_TYPE_BUFFER: -- if (obj->buffer.length > size) { -- err = -ENOSPC; -- break; -- } -- if (obj->buffer.length == 0) { -- err = -ENODATA; -- break; -- } -- -- memcpy(ret_buffer, obj->buffer.pointer, obj->buffer.length); -- break; -- case ACPI_TYPE_INTEGER: -- err = (u32)obj->integer.value; -- -- if (err == ASUS_WMI_UNSUPPORTED_METHOD) -- err = -ENODEV; -- /* -- * At least one method returns a 0 with no buffer if no arg -- * is provided, such as ASUS_WMI_DEVID_CPU_FAN_CURVE -- */ -- if (err == 0) -- err = -ENODATA; -- break; -- default: -- err = -ENODATA; -- break; -- } -- -- kfree(obj); -- -- if (err) { -- pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -- __func__, method_id, arg0, err); -- return err; -- } -- -- return 0; --} -- --static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args) --{ -- struct acpi_buffer input; -- u64 phys_addr; -- u32 retval; -- u32 status; -- -- /* -- * Copy to dma capable address otherwise memory corruption occurs as -- * bios has to be able to access it. -- */ -- input.pointer = kmemdup(args.pointer, args.length, GFP_DMA | GFP_KERNEL); -- input.length = args.length; -- if (!input.pointer) -- return -ENOMEM; -- phys_addr = virt_to_phys(input.pointer); -- -- status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_AGFN, -- phys_addr, 0, &retval); -- if (!status) -- memcpy(args.pointer, input.pointer, args.length); -- -- kfree(input.pointer); -- if (status) -- return -ENXIO; -- -- return retval; --} -- --static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) --{ -- int err; -- -- err = asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval); -- -- if (err) -- return err; -- -- if (*retval == ~0) -- return -ENODEV; -- -- return 0; --} -- --/** -- * asus_wmi_get_devstate_dsts() - Get the WMI function state. -- * @dev_id: The WMI method ID to call. -- * @retval: A pointer to where to store the value returned from WMI. -- * -- * Returns: -- * * %-ENODEV - method ID is unsupported. -- * * %0 - successful and retval is filled. -- * * %other - error from WMI call. -- */ --int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval) --{ -- int err; -- -- err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval); -- if (err) -- return err; -- -- if ((*retval & ASUS_WMI_DSTS_PRESENCE_BIT) == 0x00) -- return -ENODEV; -- -- return 0; --} --EXPORT_SYMBOL_NS_GPL(asus_wmi_get_devstate_dsts, "ASUS_WMI"); -- --/** -- * asus_wmi_set_devstate() - Set the WMI function state. -- * -- * Note: an asus_wmi_set_devstate() call must be paired with a -- * asus_wmi_get_devstate_dsts() to check if the WMI function is supported. -- * -- * @dev_id: The WMI function to call. -- * @ctrl_param: The argument to be used for this WMI function. -- * @retval: A pointer to where to store the value returned from WMI. -- * -- * Returns: -- * * %-ENODEV - method ID is unsupported. -- * * %0 - successful and retval is filled. -- * * %other - error from WMI call. -- */ --int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval) --{ -- return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, -- ctrl_param, retval); --} --EXPORT_SYMBOL_NS_GPL(asus_wmi_set_devstate, "ASUS_WMI"); -- --/* Helper for special devices with magic return codes */ --static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, -- u32 dev_id, u32 mask) --{ -- u32 retval = 0; -- int err; -- -- err = asus_wmi_get_devstate(asus, dev_id, &retval); -- if (err < 0) -- return err; -- -- if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) -- return -ENODEV; -- -- if (mask == ASUS_WMI_DSTS_STATUS_BIT) { -- if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT) -- return -ENODEV; -- } -- -- return retval & mask; --} -- --static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) --{ -- return asus_wmi_get_devstate_bits(asus, dev_id, -- ASUS_WMI_DSTS_STATUS_BIT); --} -- --static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id) --{ -- u32 retval; -- int status = asus_wmi_get_devstate(asus, dev_id, &retval); -- pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); -- -- return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); --} -- --/* Keystone *******************************************************************/ -- --static int keystone_check_present(struct asus_wmi *asus) --{ -- u32 retval; -- int err; -- -- asus->keystone_available = false; -- -- /* -- * Use a raw devstate call rather than asus_wmi_dev_is_present(). -- * For this devid, PRESENCE_BIT encodes current insert state, not -- * feature presence, so asus_wmi_dev_is_present() would return false -- * whenever the dongle is absent at boot, even on machines that have -- * a keystone slot. -- * -ENODEV means the firmware doesn't know this devid at all. -- * retval is not examined here, only the return code matters. -- */ -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_KEYSTONE, &retval); -- if (err == -ENODEV) -- return 0; -- if (err) -- return err; -- -- asus->keystone_available = true; -- return 0; --} -- --static ssize_t keystone_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- u32 retval; -- int err; -- -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_KEYSTONE, &retval); -- if (err) -- return err; -- -- return sysfs_emit(buf, "%d\n", !!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)); --} -- --static DEVICE_ATTR_RO(keystone); -- --static void asus_wmi_keystone_notify(struct asus_wmi *asus) --{ -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "keystone"); --} -- --/* Input **********************************************************************/ --static void asus_wmi_tablet_sw_report(struct asus_wmi *asus, bool value) --{ -- input_report_switch(asus->inputdev, SW_TABLET_MODE, -- asus->tablet_switch_inverted ? !value : value); -- input_sync(asus->inputdev); --} -- --static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code) --{ -- struct device *dev = &asus->platform_device->dev; -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, dev_id); -- if (result >= 0) { -- input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); -- asus_wmi_tablet_sw_report(asus, result); -- asus->tablet_switch_dev_id = dev_id; -- asus->tablet_switch_event_code = event_code; -- } else if (result == -ENODEV) { -- dev_err(dev, "This device has tablet-mode-switch quirk but got ENODEV checking it. This is a bug."); -- } else { -- dev_err(dev, "Error checking for tablet-mode-switch: %d\n", result); -- } --} -- --static int asus_wmi_input_init(struct asus_wmi *asus) --{ -- struct device *dev = &asus->platform_device->dev; -- int err; -- -- asus->inputdev = input_allocate_device(); -- if (!asus->inputdev) -- return -ENOMEM; -- -- asus->inputdev->name = asus->driver->input_name; -- asus->inputdev->phys = asus->driver->input_phys; -- asus->inputdev->id.bustype = BUS_HOST; -- asus->inputdev->dev.parent = dev; -- set_bit(EV_REP, asus->inputdev->evbit); -- -- err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); -- if (err) -- goto err_free_dev; -- -- switch (asus->driver->quirks->tablet_switch_mode) { -- case asus_wmi_no_tablet_switch: -- break; -- case asus_wmi_kbd_dock_devid: -- asus->tablet_switch_inverted = true; -- asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE); -- break; -- case asus_wmi_lid_flip_devid: -- asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP, NOTIFY_LID_FLIP); -- break; -- case asus_wmi_lid_flip_rog_devid: -- asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP_ROG, NOTIFY_LID_FLIP_ROG); -- break; -- } -- -- err = input_register_device(asus->inputdev); -- if (err) -- goto err_free_dev; -- -- return 0; -- --err_free_dev: -- input_free_device(asus->inputdev); -- return err; --} -- --static void asus_wmi_input_exit(struct asus_wmi *asus) --{ -- if (asus->inputdev) -- input_unregister_device(asus->inputdev); -- -- asus->inputdev = NULL; --} -- --/* Tablet mode ****************************************************************/ -- --static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) --{ -- int result; -- -- if (!asus->tablet_switch_dev_id) -- return; -- -- result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id); -- if (result >= 0) -- asus_wmi_tablet_sw_report(asus, result); --} -- --/* Charging mode, 1=Barrel, 2=USB ******************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t charge_mode_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, value; -- -- result = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CHARGE_MODE, &value); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", value & 0xff); --} -- --static DEVICE_ATTR_RO(charge_mode); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* dGPU ********************************************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t dgpu_disable_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", result); --} -- --/* -- * A user may be required to store the value twice, typcial store first, then -- * rescan PCI bus to activate power, then store a second time to save correctly. -- * The reason for this is that an extra code path in the ACPI is enabled when -- * the device and bus are powered. -- */ --static ssize_t dgpu_disable_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- u32 disable; -- -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- result = kstrtou32(buf, 10, &disable); -- if (result) -- return result; -- -- if (disable > 1) -- return -EINVAL; -- -- if (asus->gpu_mux_dev) { -- result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); -- if (result < 0) -- /* An error here may signal greater failure of GPU handling */ -- return result; -- if (!result && disable) { -- err = -ENODEV; -- pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err); -- return err; -- } -- } -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result); -- if (err) { -- pr_warn("Failed to set dgpu disable: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set dgpu disable (result): 0x%x\n", result); -- return -EIO; -- } -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "dgpu_disable"); -- -- return count; --} --static DEVICE_ATTR_RW(dgpu_disable); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* eGPU ********************************************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t egpu_enable_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", result); --} -- --/* The ACPI call to enable the eGPU also disables the internal dGPU */ --static ssize_t egpu_enable_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- u32 enable; -- -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- err = kstrtou32(buf, 10, &enable); -- if (err) -- return err; -- -- if (enable > 1) -- return -EINVAL; -- -- err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); -- if (err < 0) { -- pr_warn("Failed to get egpu connection status: %d\n", err); -- return err; -- } -- -- if (asus->gpu_mux_dev) { -- result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); -- if (result < 0) { -- /* An error here may signal greater failure of GPU handling */ -- pr_warn("Failed to get gpu mux status: %d\n", result); -- return result; -- } -- if (!result && enable) { -- err = -ENODEV; -- pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err); -- return err; -- } -- } -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); -- if (err) { -- pr_warn("Failed to set egpu state: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set egpu state (retval): 0x%x\n", result); -- return -EIO; -- } -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable"); -- -- return count; --} --static DEVICE_ATTR_RW(egpu_enable); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* Is eGPU connected? *********************************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t egpu_connected_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", result); --} -- --static DEVICE_ATTR_RO(egpu_connected); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* gpu mux switch *************************************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t gpu_mux_mode_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", result); --} -- --static ssize_t gpu_mux_mode_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 optimus; -- -- err = kstrtou32(buf, 10, &optimus); -- if (err) -- return err; -- -- if (optimus > 1) -- return -EINVAL; -- -- if (asus->dgpu_disable_available) { -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU); -- if (result < 0) -- /* An error here may signal greater failure of GPU handling */ -- return result; -- if (result && !optimus) { -- err = -ENODEV; -- pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err); -- return err; -- } -- } -- -- if (asus->egpu_enable_available) { -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU); -- if (result < 0) -- /* An error here may signal greater failure of GPU handling */ -- return result; -- if (result && !optimus) { -- err = -ENODEV; -- pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err); -- return err; -- } -- } -- -- err = asus_wmi_set_devstate(asus->gpu_mux_dev, optimus, &result); -- if (err) { -- dev_err(dev, "Failed to set GPU MUX mode: %d\n", err); -- return err; -- } -- /* !1 is considered a fail by ASUS */ -- if (result != 1) { -- dev_warn(dev, "Failed to set GPU MUX mode (result): 0x%x\n", result); -- return -EIO; -- } -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "gpu_mux_mode"); -- -- return count; --} --static DEVICE_ATTR_RW(gpu_mux_mode); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* TUF Laptop Keyboard RGB Modes **********************************************/ --static ssize_t kbd_rgb_mode_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- u32 cmd, mode, r, g, b, speed; -- struct led_classdev *led; -- struct asus_wmi *asus; -- int err; -- -- led = dev_get_drvdata(dev); -- asus = container_of(led, struct asus_wmi, kbd_led); -- -- if (sscanf(buf, "%d %d %d %d %d %d", &cmd, &mode, &r, &g, &b, &speed) != 6) -- return -EINVAL; -- -- /* B3 is set and B4 is save to BIOS */ -- switch (cmd) { -- case 0: -- cmd = 0xb3; -- break; -- case 1: -- cmd = 0xb4; -- break; -- default: -- return -EINVAL; -- } -- -- /* These are the known usable modes across all TUF/ROG */ -- if (mode >= 12 || mode == 9) -- mode = 10; -- -- switch (speed) { -- case 0: -- speed = 0xe1; -- break; -- case 1: -- speed = 0xeb; -- break; -- case 2: -- speed = 0xf5; -- break; -- default: -- speed = 0xeb; -- } -- -- err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, asus->kbd_rgb_dev, -- cmd | (mode << 8) | (r << 16) | (g << 24), b | (speed << 8), NULL); -- if (err) -- return err; -- -- return count; --} --static DEVICE_ATTR_WO(kbd_rgb_mode); -- --static DEVICE_STRING_ATTR_RO(kbd_rgb_mode_index, 0444, -- "cmd mode red green blue speed"); -- --static struct attribute *kbd_rgb_mode_attrs[] = { -- &dev_attr_kbd_rgb_mode.attr, -- &dev_attr_kbd_rgb_mode_index.attr.attr, -- NULL, --}; -- --static const struct attribute_group kbd_rgb_mode_group = { -- .attrs = kbd_rgb_mode_attrs, --}; -- --/* TUF Laptop Keyboard RGB State **********************************************/ --static ssize_t kbd_rgb_state_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- u32 flags, cmd, boot, awake, sleep, keyboard; -- int err; -- -- if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &keyboard) != 5) -- return -EINVAL; -- -- if (cmd) -- cmd = BIT(2); -- -- flags = 0; -- if (boot) -- flags |= BIT(1); -- if (awake) -- flags |= BIT(3); -- if (sleep) -- flags |= BIT(5); -- if (keyboard) -- flags |= BIT(7); -- -- /* 0xbd is the required default arg0 for the method. Nothing happens otherwise */ -- err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, -- ASUS_WMI_DEVID_TUF_RGB_STATE, 0xbd | cmd << 8 | (flags << 16), 0, NULL); -- if (err) -- return err; -- -- return count; --} --static DEVICE_ATTR_WO(kbd_rgb_state); -- --static DEVICE_STRING_ATTR_RO(kbd_rgb_state_index, 0444, -- "cmd boot awake sleep keyboard"); -- --static struct attribute *kbd_rgb_state_attrs[] = { -- &dev_attr_kbd_rgb_state.attr, -- &dev_attr_kbd_rgb_state_index.attr.attr, -- NULL, --}; -- --static const struct attribute_group kbd_rgb_state_group = { -- .attrs = kbd_rgb_state_attrs, --}; -- --static const struct attribute_group *kbd_rgb_mode_groups[] = { -- NULL, -- NULL, -- NULL, --}; -- --/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t ppt_pl2_sppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL2_SPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_pl2_sppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_pl2_sppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_pl2_sppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt"); -- -- return count; --} -- --static ssize_t ppt_pl2_sppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt); --} --static DEVICE_ATTR_RW(ppt_pl2_sppt); -- --/* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/ --static ssize_t ppt_pl1_spl_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL1_SPL, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_pl1_spl: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_pl1_spl (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_pl1_spl = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl"); -- -- return count; --} --static ssize_t ppt_pl1_spl_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl); --} --static DEVICE_ATTR_RW(ppt_pl1_spl); -- --/* Tunable: PPT APU FPPT ******************************************************/ --static ssize_t ppt_fppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL3_FPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_fppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_fppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_fppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt"); -- -- return count; --} -- --static ssize_t ppt_fppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_fppt); --} --static DEVICE_ATTR_RW(ppt_fppt); -- --/* Tunable: PPT APU SPPT *****************************************************/ --static ssize_t ppt_apu_sppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_APU_SPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_apu_sppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_apu_sppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_apu_sppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt"); -- -- return count; --} -- --static ssize_t ppt_apu_sppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt); --} --static DEVICE_ATTR_RW(ppt_apu_sppt); -- --/* Tunable: PPT platform SPPT ************************************************/ --static ssize_t ppt_platform_sppt_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PLAT_SPPT, value, &result); -- if (err) { -- pr_warn("Failed to set ppt_platform_sppt: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set ppt_platform_sppt (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->ppt_platform_sppt = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt"); -- -- return count; --} -- --static ssize_t ppt_platform_sppt_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt); --} --static DEVICE_ATTR_RW(ppt_platform_sppt); -- --/* Tunable: NVIDIA dynamic boost *********************************************/ --static ssize_t nv_dynamic_boost_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < NVIDIA_BOOST_MIN || value > NVIDIA_BOOST_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_DYN_BOOST, value, &result); -- if (err) { -- pr_warn("Failed to set nv_dynamic_boost: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set nv_dynamic_boost (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->nv_dynamic_boost = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost"); -- -- return count; --} -- --static ssize_t nv_dynamic_boost_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost); --} --static DEVICE_ATTR_RW(nv_dynamic_boost); -- --/* Tunable: NVIDIA temperature target ****************************************/ --static ssize_t nv_temp_target_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result, err; -- u32 value; -- -- result = kstrtou32(buf, 10, &value); -- if (result) -- return result; -- -- if (value < NVIDIA_TEMP_MIN || value > NVIDIA_TEMP_MAX) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_THERM_TARGET, value, &result); -- if (err) { -- pr_warn("Failed to set nv_temp_target: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set nv_temp_target (result): 0x%x\n", result); -- return -EIO; -- } -- -- asus->nv_temp_target = value; -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target"); -- -- return count; --} -- --static ssize_t nv_temp_target_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%u\n", asus->nv_temp_target); --} --static DEVICE_ATTR_RW(nv_temp_target); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* Ally MCU Powersave ********************************************************/ -- --/* -- * The HID driver needs to check MCU version and set this to false if the MCU FW -- * version is >= the minimum requirements. New FW do not need the hacks. -- */ --void set_ally_mcu_hack(enum asus_ally_mcu_hack status) --{ -- use_ally_mcu_hack = status; -- pr_debug("%s Ally MCU suspend quirk\n", -- status == ASUS_WMI_ALLY_MCU_HACK_ENABLED ? "Enabled" : "Disabled"); --} --EXPORT_SYMBOL_NS_GPL(set_ally_mcu_hack, "ASUS_WMI"); -- --/* -- * mcu_powersave should be enabled always, as it is fixed in MCU FW versions: -- * - v313 for Ally X -- * - v319 for Ally 1 -- * The HID driver checks MCU versions and so should set this if requirements match -- */ --void set_ally_mcu_powersave(bool enabled) --{ -- int result, err; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, enabled, &result); -- if (err) { -- pr_warn("Failed to set MCU powersave: %d\n", err); -- return; -- } -- if (result > 1) { -- pr_warn("Failed to set MCU powersave (result): 0x%x\n", result); -- return; -- } -- -- pr_debug("%s MCU Powersave\n", -- enabled ? "Enabled" : "Disabled"); --} --EXPORT_SYMBOL_NS_GPL(set_ally_mcu_powersave, "ASUS_WMI"); -- --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t mcu_powersave_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MCU_POWERSAVE); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", result); --} -- --static ssize_t mcu_powersave_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- u32 enable; -- -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- result = kstrtou32(buf, 10, &enable); -- if (result) -- return result; -- -- if (enable > 1) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, enable, &result); -- if (err) { -- pr_warn("Failed to set MCU powersave: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set MCU powersave (result): 0x%x\n", result); -- return -EIO; -- } -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mcu_powersave"); -- -- return count; --} --static DEVICE_ATTR_RW(mcu_powersave); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* Battery ********************************************************************/ -- --/* The battery maximum charging percentage */ --static int charge_end_threshold; -- --static ssize_t charge_control_end_threshold_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int value, ret, rv; -- -- ret = kstrtouint(buf, 10, &value); -- if (ret) -- return ret; -- -- if (value < 0 || value > 100) -- return -EINVAL; -- -- ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, value, &rv); -- if (ret) -- return ret; -- -- if (rv != 1) -- return -EIO; -- -- /* There isn't any method in the DSDT to read the threshold, so we -- * save the threshold. -- */ -- charge_end_threshold = value; -- return count; --} -- --static ssize_t charge_control_end_threshold_show(struct device *device, -- struct device_attribute *attr, -- char *buf) --{ -- if ((charge_end_threshold >= 0) && (charge_end_threshold <= 100)) -- return sysfs_emit(buf, "%d\n", charge_end_threshold); -- -- return -ENODATA; --} -- --static DEVICE_ATTR_RW(charge_control_end_threshold); -- --static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) --{ -- int ret, rv; -- -- /* The WMI method does not provide a way to specific a battery, so we -- * just assume it is the first battery. -- * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first -- * battery is named BATT. -- */ -- if (strcmp(battery->desc->name, "BAT0") != 0 && -- strcmp(battery->desc->name, "BAT1") != 0 && -- strcmp(battery->desc->name, "BATC") != 0 && -- strcmp(battery->desc->name, "BATT") != 0) -- return -ENODEV; -- -- if (device_create_file(&battery->dev, -- &dev_attr_charge_control_end_threshold)) -- return -ENODEV; -- -- /* The charge threshold is only reset when the system is power cycled, -- * and we can't read the current threshold, however the majority of -- * platforms retains it. -- * -- * Setting a negative value would signal the threshold as unknown -- * until user explicitly sets it to a new value, however to avoid -- * regressing userspace, we initialize it to a value of 100. -- */ -- charge_end_threshold = 100; -- ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, charge_end_threshold, &rv); -- if (ret) { -- pr_err("Failed to reset battery charge threshold\n"); -- goto asus_wmi_battery_add_err; -- } -- -- if (rv != 1) { -- pr_err("Error in battery charge threshold reset\n"); -- ret = -EIO; -- goto asus_wmi_battery_add_err; -- } -- -- return 0; --asus_wmi_battery_add_err: -- device_remove_file(&battery->dev, -- &dev_attr_charge_control_end_threshold); -- return ret; --} -- --static int asus_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) --{ -- device_remove_file(&battery->dev, -- &dev_attr_charge_control_end_threshold); -- return 0; --} -- --static struct acpi_battery_hook battery_hook = { -- .add_battery = asus_wmi_battery_add, -- .remove_battery = asus_wmi_battery_remove, -- .name = "ASUS Battery Extension", --}; -- --static void asus_wmi_battery_init(struct asus_wmi *asus) --{ -- asus->battery_rsoc_available = false; -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_RSOC)) { -- asus->battery_rsoc_available = true; -- acpi_battery_hook_register(&battery_hook); -- } --} -- --static void asus_wmi_battery_exit(struct asus_wmi *asus) --{ -- if (asus->battery_rsoc_available) -- acpi_battery_hook_unregister(&battery_hook); --} -- --/* LEDs ***********************************************************************/ -- --struct asus_hid_ref { -- struct list_head listeners; -- struct asus_wmi *asus; -- /* Protects concurrent access from hid-asus and asus-wmi to leds */ -- spinlock_t lock; --}; -- --static struct asus_hid_ref asus_ref = { -- .listeners = LIST_HEAD_INIT(asus_ref.listeners), -- .asus = NULL, -- /* -- * Protects .asus, .asus.kbd_led_{wk,notify}, and .listener refs. Other -- * asus variables are read-only after .asus is set. -- * -- * The led cdev device is not protected because it calls backlight_get -- * during initialization, which would result in a nested lock attempt. -- * -- * The led cdev is safe to access without a lock because if -- * kbd_led_avail is true it is initialized before .asus is set and never -- * changed until .asus is dropped. If kbd_led_avail is false, the led -- * cdev is registered by the workqueue, which is single-threaded and -- * cancelled before asus-wmi would access the led cdev to unregister it. -- * -- * A spinlock is used, because the protected variables can be accessed -- * from an IRQ context from asus-hid. -- */ -- .lock = __SPIN_LOCK_UNLOCKED(asus_ref.lock), --}; -- --/* -- * Allows registering hid-asus listeners that want to be notified of -- * keyboard backlight changes. -- */ --int asus_hid_register_listener(struct asus_hid_listener *bdev) --{ -- struct asus_wmi *asus; -- -- guard(spinlock_irqsave)(&asus_ref.lock); -- list_add_tail(&bdev->list, &asus_ref.listeners); -- asus = asus_ref.asus; -- if (asus) -- queue_work(asus->led_workqueue, &asus->kbd_led_work); -- return 0; --} --EXPORT_SYMBOL_GPL(asus_hid_register_listener); -- --/* -- * Allows unregistering hid-asus listeners that were added with -- * asus_hid_register_listener(). -- */ --void asus_hid_unregister_listener(struct asus_hid_listener *bdev) --{ -- guard(spinlock_irqsave)(&asus_ref.lock); -- list_del(&bdev->list); --} --EXPORT_SYMBOL_GPL(asus_hid_unregister_listener); -- --static void do_kbd_led_set(struct led_classdev *led_cdev, int value); -- --static void kbd_led_update_all(struct work_struct *work) --{ -- struct asus_wmi *asus; -- bool registered, notify; -- int ret, value; -- -- asus = container_of(work, struct asus_wmi, kbd_led_work); -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) { -- registered = asus->kbd_led_registered; -- value = asus->kbd_led_wk; -- notify = asus->kbd_led_notify; -- } -- -- if (!registered) { -- /* -- * This workqueue runs under asus-wmi, which means probe has -- * completed and asus-wmi will keep running until it finishes. -- * Therefore, we can safely register the LED without holding -- * a spinlock. -- */ -- ret = devm_led_classdev_register(&asus->platform_device->dev, -- &asus->kbd_led); -- if (!ret) { -- scoped_guard(spinlock_irqsave, &asus_ref.lock) -- asus->kbd_led_registered = true; -- } else { -- pr_warn("Failed to register keyboard backlight LED: %d\n", ret); -- return; -- } -- } -- -- if (value >= 0) -- do_kbd_led_set(&asus->kbd_led, value); -- if (notify) { -- scoped_guard(spinlock_irqsave, &asus_ref.lock) -- asus->kbd_led_notify = false; -- led_classdev_notify_brightness_hw_changed(&asus->kbd_led, value); -- } --} -- --/* -- * This function is called from hid-asus to inform asus-wmi of brightness -- * changes initiated by the keyboard backlight keys. -- */ --int asus_hid_event(enum asus_hid_event event) --{ -- struct asus_wmi *asus; -- int brightness; -- -- guard(spinlock_irqsave)(&asus_ref.lock); -- asus = asus_ref.asus; -- if (!asus || !asus->kbd_led_registered) -- return -EBUSY; -- -- brightness = asus->kbd_led_wk; -- -- switch (event) { -- case ASUS_EV_BRTUP: -- brightness += 1; -- break; -- case ASUS_EV_BRTDOWN: -- brightness -= 1; -- break; -- case ASUS_EV_BRTTOGGLE: -- if (brightness >= ASUS_EV_MAX_BRIGHTNESS) -- brightness = 0; -- else -- brightness += 1; -- break; -- } -- -- asus->kbd_led_wk = clamp_val(brightness, 0, ASUS_EV_MAX_BRIGHTNESS); -- asus->kbd_led_notify = true; -- queue_work(asus->led_workqueue, &asus->kbd_led_work); -- return 0; --} --EXPORT_SYMBOL_GPL(asus_hid_event); -- --/* -- * These functions actually update the LED's, and are called from a -- * workqueue. By doing this as separate work rather than when the LED -- * subsystem asks, we avoid messing with the Asus ACPI stuff during a -- * potentially bad time, such as a timer interrupt. -- */ --static void tpd_led_update(struct work_struct *work) --{ -- int ctrl_param; -- struct asus_wmi *asus; -- -- asus = container_of(work, struct asus_wmi, tpd_led_work); -- -- ctrl_param = asus->tpd_led_wk; -- asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); --} -- --static void tpd_led_set(struct led_classdev *led_cdev, -- enum led_brightness value) --{ -- struct asus_wmi *asus; -- -- asus = container_of(led_cdev, struct asus_wmi, tpd_led); -- -- asus->tpd_led_wk = !!value; -- queue_work(asus->led_workqueue, &asus->tpd_led_work); --} -- --static int read_tpd_led_state(struct asus_wmi *asus) --{ -- return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED); --} -- --static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) --{ -- struct asus_wmi *asus; -- -- asus = container_of(led_cdev, struct asus_wmi, tpd_led); -- -- return read_tpd_led_state(asus); --} -- --static void kbd_led_update(struct asus_wmi *asus) --{ -- int ctrl_param = 0; -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) -- ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); -- asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); --} -- --static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) --{ -- int retval; -- -- /* -- * bits 0-2: level -- * bit 7: light on/off -- * bit 8-10: environment (0: dark, 1: normal, 2: light) -- * bit 17: status unknown -- */ -- retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT, -- 0xFFFF); -- -- /* Unknown status is considered as off */ -- if (retval == 0x8000) -- retval = 0; -- -- if (retval < 0) -- return retval; -- -- if (level) -- *level = retval & 0x7F; -- if (env) -- *env = (retval >> 8) & 0x7F; -- return 0; --} -- --static void do_kbd_led_set(struct led_classdev *led_cdev, int value) --{ -- struct asus_hid_listener *listener; -- struct asus_wmi *asus; -- -- asus = container_of(led_cdev, struct asus_wmi, kbd_led); -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) -- asus->kbd_led_wk = clamp_val(value, 0, ASUS_EV_MAX_BRIGHTNESS); -- -- if (asus->kbd_led_avail) -- kbd_led_update(asus); -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) { -- list_for_each_entry(listener, &asus_ref.listeners, list) -- listener->brightness_set(listener, asus->kbd_led_wk); -- } --} -- --static int kbd_led_set(struct led_classdev *led_cdev, enum led_brightness value) --{ -- /* Prevent disabling keyboard backlight on module unregister */ -- if (led_cdev->flags & LED_UNREGISTERING) -- return 0; -- -- do_kbd_led_set(led_cdev, value); -- return 0; --} -- --static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value) --{ -- scoped_guard(spinlock_irqsave, &asus_ref.lock) { -- asus->kbd_led_wk = value; -- asus->kbd_led_notify = true; -- } -- queue_work(asus->led_workqueue, &asus->kbd_led_work); --} -- --static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) --{ -- struct asus_wmi *asus; -- int retval, value; -- -- asus = container_of(led_cdev, struct asus_wmi, kbd_led); -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) { -- if (!asus->kbd_led_avail) -- return asus->kbd_led_wk; -- } -- -- retval = kbd_led_read(asus, &value, NULL); -- if (retval < 0) -- return retval; -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) -- asus->kbd_led_wk = value; -- -- return value; --} -- --static int wlan_led_unknown_state(struct asus_wmi *asus) --{ -- u32 result; -- -- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); -- -- return result & ASUS_WMI_DSTS_UNKNOWN_BIT; --} -- --static void wlan_led_update(struct work_struct *work) --{ -- int ctrl_param; -- struct asus_wmi *asus; -- -- asus = container_of(work, struct asus_wmi, wlan_led_work); -- -- ctrl_param = asus->wlan_led_wk; -- asus_wmi_set_devstate(ASUS_WMI_DEVID_WIRELESS_LED, ctrl_param, NULL); --} -- --static void wlan_led_set(struct led_classdev *led_cdev, -- enum led_brightness value) --{ -- struct asus_wmi *asus; -- -- asus = container_of(led_cdev, struct asus_wmi, wlan_led); -- -- asus->wlan_led_wk = !!value; -- queue_work(asus->led_workqueue, &asus->wlan_led_work); --} -- --static enum led_brightness wlan_led_get(struct led_classdev *led_cdev) --{ -- struct asus_wmi *asus; -- u32 result; -- -- asus = container_of(led_cdev, struct asus_wmi, wlan_led); -- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); -- -- return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; --} -- --static void lightbar_led_update(struct work_struct *work) --{ -- struct asus_wmi *asus; -- int ctrl_param; -- -- asus = container_of(work, struct asus_wmi, lightbar_led_work); -- -- ctrl_param = asus->lightbar_led_wk; -- asus_wmi_set_devstate(ASUS_WMI_DEVID_LIGHTBAR, ctrl_param, NULL); --} -- --static void lightbar_led_set(struct led_classdev *led_cdev, -- enum led_brightness value) --{ -- struct asus_wmi *asus; -- -- asus = container_of(led_cdev, struct asus_wmi, lightbar_led); -- -- asus->lightbar_led_wk = !!value; -- queue_work(asus->led_workqueue, &asus->lightbar_led_work); --} -- --static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev) --{ -- struct asus_wmi *asus; -- u32 result; -- -- asus = container_of(led_cdev, struct asus_wmi, lightbar_led); -- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result); -- -- return result & ASUS_WMI_DSTS_LIGHTBAR_MASK; --} -- --static int micmute_led_set(struct led_classdev *led_cdev, -- enum led_brightness brightness) --{ -- int state = brightness != LED_OFF; -- int err; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MICMUTE_LED, state, NULL); -- return err < 0 ? err : 0; --} -- --static enum led_brightness camera_led_get(struct led_classdev *led_cdev) --{ -- struct asus_wmi *asus; -- u32 result; -- -- asus = container_of(led_cdev, struct asus_wmi, camera_led); -- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CAMERA_LED, &result); -- -- return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; --} -- --static int camera_led_set(struct led_classdev *led_cdev, -- enum led_brightness brightness) --{ -- int state = brightness != LED_OFF; -- int err; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CAMERA_LED, state, NULL); -- return err < 0 ? err : 0; --} -- --static void asus_wmi_led_exit(struct asus_wmi *asus) --{ -- scoped_guard(spinlock_irqsave, &asus_ref.lock) -- asus_ref.asus = NULL; -- -- led_classdev_unregister(&asus->tpd_led); -- led_classdev_unregister(&asus->wlan_led); -- led_classdev_unregister(&asus->lightbar_led); -- led_classdev_unregister(&asus->micmute_led); -- led_classdev_unregister(&asus->camera_led); -- -- if (asus->led_workqueue) -- destroy_workqueue(asus->led_workqueue); --} -- --static int asus_wmi_led_init(struct asus_wmi *asus) --{ -- int rv = 0, num_rgb_groups = 0, led_val; -- -- if (asus->kbd_rgb_dev) -- kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group; -- if (asus->kbd_rgb_state_available) -- kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_state_group; -- -- asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); -- if (!asus->led_workqueue) -- return -ENOMEM; -- -- if (read_tpd_led_state(asus) >= 0) { -- INIT_WORK(&asus->tpd_led_work, tpd_led_update); -- -- asus->tpd_led.name = "asus::touchpad"; -- asus->tpd_led.brightness_set = tpd_led_set; -- asus->tpd_led.brightness_get = tpd_led_get; -- asus->tpd_led.max_brightness = 1; -- -- rv = led_classdev_register(&asus->platform_device->dev, -- &asus->tpd_led); -- if (rv) -- goto error; -- } -- -- asus->kbd_led.name = "asus::kbd_backlight"; -- asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; -- asus->kbd_led.brightness_set_blocking = kbd_led_set; -- asus->kbd_led.brightness_get = kbd_led_get; -- asus->kbd_led.max_brightness = ASUS_EV_MAX_BRIGHTNESS; -- asus->kbd_led_avail = !kbd_led_read(asus, &led_val, NULL); -- INIT_WORK(&asus->kbd_led_work, kbd_led_update_all); -- -- if (asus->kbd_led_avail) { -- asus->kbd_led_wk = led_val; -- if (num_rgb_groups != 0) -- asus->kbd_led.groups = kbd_rgb_mode_groups; -- } else { -- asus->kbd_led_wk = -1; -- } -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) { -- asus_ref.asus = asus; -- if (asus->kbd_led_avail || !list_empty(&asus_ref.listeners)) -- queue_work(asus->led_workqueue, &asus->kbd_led_work); -- } -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_WIRELESS_LED) -- && (asus->driver->quirks->wapf > 0)) { -- INIT_WORK(&asus->wlan_led_work, wlan_led_update); -- -- asus->wlan_led.name = "asus::wlan"; -- asus->wlan_led.brightness_set = wlan_led_set; -- if (!wlan_led_unknown_state(asus)) -- asus->wlan_led.brightness_get = wlan_led_get; -- asus->wlan_led.flags = LED_CORE_SUSPENDRESUME; -- asus->wlan_led.max_brightness = 1; -- asus->wlan_led.default_trigger = "asus-wlan"; -- -- rv = led_classdev_register(&asus->platform_device->dev, -- &asus->wlan_led); -- if (rv) -- goto error; -- } -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_LIGHTBAR)) { -- INIT_WORK(&asus->lightbar_led_work, lightbar_led_update); -- -- asus->lightbar_led.name = "asus::lightbar"; -- asus->lightbar_led.brightness_set = lightbar_led_set; -- asus->lightbar_led.brightness_get = lightbar_led_get; -- asus->lightbar_led.max_brightness = 1; -- -- rv = led_classdev_register(&asus->platform_device->dev, -- &asus->lightbar_led); -- } -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MICMUTE_LED)) { -- asus->micmute_led.name = "platform::micmute"; -- asus->micmute_led.max_brightness = 1; -- asus->micmute_led.brightness_set_blocking = micmute_led_set; -- asus->micmute_led.default_trigger = "audio-micmute"; -- -- rv = led_classdev_register(&asus->platform_device->dev, -- &asus->micmute_led); -- if (rv) -- goto error; -- } -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CAMERA_LED)) { -- asus->camera_led.name = "asus::camera"; -- asus->camera_led.max_brightness = 1; -- asus->camera_led.brightness_get = camera_led_get; -- asus->camera_led.brightness_set_blocking = camera_led_set; -- -- rv = led_classdev_register(&asus->platform_device->dev, -- &asus->camera_led); -- if (rv) -- goto error; -- } -- -- if (asus->oobe_state_available) { -- /* -- * Disable OOBE state, so that e.g. the keyboard backlight -- * works. -- */ -- rv = asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL); -- if (rv) -- goto error; -- } -- --error: -- if (rv) -- asus_wmi_led_exit(asus); -- -- return rv; --} -- --/* RF *************************************************************************/ -- --/* -- * PCI hotplug (for wlan rfkill) -- */ --static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) --{ -- int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); -- -- if (result < 0) -- return false; -- return !result; --} -- --static void asus_rfkill_hotplug(struct asus_wmi *asus) --{ -- struct pci_dev *dev; -- struct pci_bus *bus; -- bool blocked; -- bool absent; -- u32 l; -- -- mutex_lock(&asus->wmi_lock); -- blocked = asus_wlan_rfkill_blocked(asus); -- mutex_unlock(&asus->wmi_lock); -- -- mutex_lock(&asus->hotplug_lock); -- pci_lock_rescan_remove(); -- -- if (asus->wlan.rfkill) -- rfkill_set_sw_state(asus->wlan.rfkill, blocked); -- -- if (asus->hotplug_slot.ops) { -- bus = pci_find_bus(0, 1); -- if (!bus) { -- pr_warn("Unable to find PCI bus 1?\n"); -- goto out_unlock; -- } -- -- if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { -- pr_err("Unable to read PCI config space?\n"); -- goto out_unlock; -- } -- absent = (l == 0xffffffff); -- -- if (blocked != absent) { -- pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n", -- blocked ? "blocked" : "unblocked", -- absent ? "absent" : "present"); -- pr_warn("skipped wireless hotplug as probably inappropriate for this model\n"); -- goto out_unlock; -- } -- -- if (!blocked) { -- dev = pci_get_slot(bus, 0); -- if (dev) { -- /* Device already present */ -- pci_dev_put(dev); -- goto out_unlock; -- } -- dev = pci_scan_single_device(bus, 0); -- if (dev) { -- pci_bus_assign_resources(bus); -- pci_bus_add_device(dev); -- } -- } else { -- dev = pci_get_slot(bus, 0); -- if (dev) { -- pci_stop_and_remove_bus_device(dev); -- pci_dev_put(dev); -- } -- } -- } -- --out_unlock: -- pci_unlock_rescan_remove(); -- mutex_unlock(&asus->hotplug_lock); --} -- --static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data) --{ -- struct asus_wmi *asus = data; -- -- if (event != ACPI_NOTIFY_BUS_CHECK) -- return; -- -- /* -- * We can't call directly asus_rfkill_hotplug because most -- * of the time WMBC is still being executed and not reetrant. -- * There is currently no way to tell ACPICA that we want this -- * method to be serialized, we schedule a asus_rfkill_hotplug -- * call later, in a safer context. -- */ -- queue_work(asus->hotplug_workqueue, &asus->hotplug_work); --} -- --static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node) --{ -- acpi_status status; -- acpi_handle handle; -- -- status = acpi_get_handle(NULL, node, &handle); -- if (ACPI_FAILURE(status)) -- return -ENODEV; -- -- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, -- asus_rfkill_notify, asus); -- if (ACPI_FAILURE(status)) -- pr_warn("Failed to register notify on %s\n", node); -- -- return 0; --} -- --static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) --{ -- acpi_status status = AE_OK; -- acpi_handle handle; -- -- status = acpi_get_handle(NULL, node, &handle); -- if (ACPI_FAILURE(status)) -- return; -- -- status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, -- asus_rfkill_notify); -- if (ACPI_FAILURE(status)) -- pr_err("Error removing rfkill notify handler %s\n", node); --} -- --static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, -- u8 *value) --{ -- struct asus_wmi *asus = container_of(hotplug_slot, -- struct asus_wmi, hotplug_slot); -- int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); -- -- if (result < 0) -- return result; -- -- *value = !!result; -- return 0; --} -- --static const struct hotplug_slot_ops asus_hotplug_slot_ops = { -- .get_adapter_status = asus_get_adapter_status, -- .get_power_status = asus_get_adapter_status, --}; -- --static void asus_hotplug_work(struct work_struct *work) --{ -- struct asus_wmi *asus; -- -- asus = container_of(work, struct asus_wmi, hotplug_work); -- asus_rfkill_hotplug(asus); --} -- --static int asus_setup_pci_hotplug(struct asus_wmi *asus) --{ -- int ret = -ENOMEM; -- struct pci_bus *bus = pci_find_bus(0, 1); -- -- if (!bus) { -- pr_err("Unable to find wifi PCI bus\n"); -- return -ENODEV; -- } -- -- asus->hotplug_workqueue = -- create_singlethread_workqueue("hotplug_workqueue"); -- if (!asus->hotplug_workqueue) -- goto error_workqueue; -- -- INIT_WORK(&asus->hotplug_work, asus_hotplug_work); -- -- asus->hotplug_slot.ops = &asus_hotplug_slot_ops; -- -- ret = pci_hp_register(&asus->hotplug_slot, bus, 0, "asus-wifi"); -- if (ret) { -- pr_err("Unable to register hotplug slot - %d\n", ret); -- goto error_register; -- } -- -- return 0; -- --error_register: -- asus->hotplug_slot.ops = NULL; -- destroy_workqueue(asus->hotplug_workqueue); --error_workqueue: -- return ret; --} -- --/* -- * Rfkill devices -- */ --static int asus_rfkill_set(void *data, bool blocked) --{ -- struct asus_rfkill *priv = data; -- u32 ctrl_param = !blocked; -- u32 dev_id = priv->dev_id; -- -- /* -- * If the user bit is set, BIOS can't set and record the wlan status, -- * it will report the value read from id ASUS_WMI_DEVID_WLAN_LED -- * while we query the wlan status through WMI(ASUS_WMI_DEVID_WLAN). -- * So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED -- * while setting the wlan status through WMI. -- * This is also the behavior that windows app will do. -- */ -- if ((dev_id == ASUS_WMI_DEVID_WLAN) && -- priv->asus->driver->wlan_ctrl_by_user) -- dev_id = ASUS_WMI_DEVID_WLAN_LED; -- -- return asus_wmi_set_devstate(dev_id, ctrl_param, NULL); --} -- --static void asus_rfkill_query(struct rfkill *rfkill, void *data) --{ -- struct asus_rfkill *priv = data; -- int result; -- -- result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id); -- -- if (result < 0) -- return; -- -- rfkill_set_sw_state(priv->rfkill, !result); --} -- --static int asus_rfkill_wlan_set(void *data, bool blocked) --{ -- struct asus_rfkill *priv = data; -- struct asus_wmi *asus = priv->asus; -- int ret; -- -- /* -- * This handler is enabled only if hotplug is enabled. -- * In this case, the asus_wmi_set_devstate() will -- * trigger a wmi notification and we need to wait -- * this call to finish before being able to call -- * any wmi method -- */ -- mutex_lock(&asus->wmi_lock); -- ret = asus_rfkill_set(data, blocked); -- mutex_unlock(&asus->wmi_lock); -- return ret; --} -- --static const struct rfkill_ops asus_rfkill_wlan_ops = { -- .set_block = asus_rfkill_wlan_set, -- .query = asus_rfkill_query, --}; -- --static const struct rfkill_ops asus_rfkill_ops = { -- .set_block = asus_rfkill_set, -- .query = asus_rfkill_query, --}; -- --static int asus_new_rfkill(struct asus_wmi *asus, -- struct asus_rfkill *arfkill, -- const char *name, enum rfkill_type type, int dev_id) --{ -- int result = asus_wmi_get_devstate_simple(asus, dev_id); -- struct rfkill **rfkill = &arfkill->rfkill; -- -- if (result < 0) -- return result; -- -- arfkill->dev_id = dev_id; -- arfkill->asus = asus; -- -- if (dev_id == ASUS_WMI_DEVID_WLAN && -- asus->driver->quirks->hotplug_wireless) -- *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, -- &asus_rfkill_wlan_ops, arfkill); -- else -- *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, -- &asus_rfkill_ops, arfkill); -- -- if (!*rfkill) -- return -EINVAL; -- -- if ((dev_id == ASUS_WMI_DEVID_WLAN) && -- (asus->driver->quirks->wapf > 0)) -- rfkill_set_led_trigger_name(*rfkill, "asus-wlan"); -- -- rfkill_init_sw_state(*rfkill, !result); -- result = rfkill_register(*rfkill); -- if (result) { -- rfkill_destroy(*rfkill); -- *rfkill = NULL; -- return result; -- } -- return 0; --} -- --static void asus_wmi_rfkill_exit(struct asus_wmi *asus) --{ -- if (asus->driver->wlan_ctrl_by_user && ashs_present()) -- return; -- -- asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); -- asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); -- asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); -- if (asus->wlan.rfkill) { -- rfkill_unregister(asus->wlan.rfkill); -- rfkill_destroy(asus->wlan.rfkill); -- asus->wlan.rfkill = NULL; -- } -- /* -- * Refresh pci hotplug in case the rfkill state was changed after -- * asus_unregister_rfkill_notifier() -- */ -- asus_rfkill_hotplug(asus); -- if (asus->hotplug_slot.ops) -- pci_hp_deregister(&asus->hotplug_slot); -- if (asus->hotplug_workqueue) -- destroy_workqueue(asus->hotplug_workqueue); -- -- if (asus->bluetooth.rfkill) { -- rfkill_unregister(asus->bluetooth.rfkill); -- rfkill_destroy(asus->bluetooth.rfkill); -- asus->bluetooth.rfkill = NULL; -- } -- if (asus->wimax.rfkill) { -- rfkill_unregister(asus->wimax.rfkill); -- rfkill_destroy(asus->wimax.rfkill); -- asus->wimax.rfkill = NULL; -- } -- if (asus->wwan3g.rfkill) { -- rfkill_unregister(asus->wwan3g.rfkill); -- rfkill_destroy(asus->wwan3g.rfkill); -- asus->wwan3g.rfkill = NULL; -- } -- if (asus->gps.rfkill) { -- rfkill_unregister(asus->gps.rfkill); -- rfkill_destroy(asus->gps.rfkill); -- asus->gps.rfkill = NULL; -- } -- if (asus->uwb.rfkill) { -- rfkill_unregister(asus->uwb.rfkill); -- rfkill_destroy(asus->uwb.rfkill); -- asus->uwb.rfkill = NULL; -- } --} -- --static int asus_wmi_rfkill_init(struct asus_wmi *asus) --{ -- int result = 0; -- -- mutex_init(&asus->hotplug_lock); -- mutex_init(&asus->wmi_lock); -- -- result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan", -- RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN); -- -- if (result && result != -ENODEV) -- goto exit; -- -- result = asus_new_rfkill(asus, &asus->bluetooth, -- "asus-bluetooth", RFKILL_TYPE_BLUETOOTH, -- ASUS_WMI_DEVID_BLUETOOTH); -- -- if (result && result != -ENODEV) -- goto exit; -- -- result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax", -- RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX); -- -- if (result && result != -ENODEV) -- goto exit; -- -- result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g", -- RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G); -- -- if (result && result != -ENODEV) -- goto exit; -- -- result = asus_new_rfkill(asus, &asus->gps, "asus-gps", -- RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS); -- -- if (result && result != -ENODEV) -- goto exit; -- -- result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb", -- RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB); -- -- if (result && result != -ENODEV) -- goto exit; -- -- if (!asus->driver->quirks->hotplug_wireless) -- goto exit; -- -- result = asus_setup_pci_hotplug(asus); -- /* -- * If we get -EBUSY then something else is handling the PCI hotplug - -- * don't fail in this case -- */ -- if (result == -EBUSY) -- result = 0; -- -- asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); -- asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); -- asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); -- /* -- * Refresh pci hotplug in case the rfkill state was changed during -- * setup. -- */ -- asus_rfkill_hotplug(asus); -- --exit: -- if (result && result != -ENODEV) -- asus_wmi_rfkill_exit(asus); -- -- if (result == -ENODEV) -- result = 0; -- -- return result; --} -- --/* Panel Overdrive ************************************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t panel_od_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_PANEL_OD); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", result); --} -- --static ssize_t panel_od_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- u32 overdrive; -- -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- result = kstrtou32(buf, 10, &overdrive); -- if (result) -- return result; -- -- if (overdrive > 1) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, overdrive, &result); -- -- if (err) { -- pr_warn("Failed to set panel overdrive: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set panel overdrive (result): 0x%x\n", result); -- return -EIO; -- } -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od"); -- -- return count; --} --static DEVICE_ATTR_RW(panel_od); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* Bootup sound ***************************************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t boot_sound_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int result; -- -- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BOOT_SOUND); -- if (result < 0) -- return result; -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", result); --} -- --static ssize_t boot_sound_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- u32 snd; -- -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- result = kstrtou32(buf, 10, &snd); -- if (result) -- return result; -- -- if (snd > 1) -- return -EINVAL; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BOOT_SOUND, snd, &result); -- if (err) { -- pr_warn("Failed to set boot sound: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set panel boot sound (result): 0x%x\n", result); -- return -EIO; -- } -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "boot_sound"); -- -- return count; --} --static DEVICE_ATTR_RW(boot_sound); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* Mini-LED mode **************************************************************/ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t mini_led_mode_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- u32 value; -- int err; -- -- err = asus_wmi_get_devstate(asus, asus->mini_led_dev_id, &value); -- if (err < 0) -- return err; -- value = value & ASUS_MINI_LED_MODE_MASK; -- -- /* -- * Remap the mode values to match previous generation mini-led. The last gen -- * WMI 0 == off, while on this version WMI 2 ==off (flipped). -- */ -- if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -- switch (value) { -- case ASUS_MINI_LED_2024_WEAK: -- value = ASUS_MINI_LED_ON; -- break; -- case ASUS_MINI_LED_2024_STRONG: -- value = ASUS_MINI_LED_STRONG_MODE; -- break; -- case ASUS_MINI_LED_2024_OFF: -- value = ASUS_MINI_LED_OFF; -- break; -- } -- } -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "%d\n", value); --} -- --static ssize_t mini_led_mode_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- u32 mode; -- -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- result = kstrtou32(buf, 10, &mode); -- if (result) -- return result; -- -- if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE && -- mode > ASUS_MINI_LED_ON) -- return -EINVAL; -- if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 && -- mode > ASUS_MINI_LED_STRONG_MODE) -- return -EINVAL; -- -- /* -- * Remap the mode values so expected behaviour is the same as the last -- * generation of mini-LED with 0 == off, 1 == on. -- */ -- if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -- switch (mode) { -- case ASUS_MINI_LED_OFF: -- mode = ASUS_MINI_LED_2024_OFF; -- break; -- case ASUS_MINI_LED_ON: -- mode = ASUS_MINI_LED_2024_WEAK; -- break; -- case ASUS_MINI_LED_STRONG_MODE: -- mode = ASUS_MINI_LED_2024_STRONG; -- break; -- } -- } -- -- err = asus_wmi_set_devstate(asus->mini_led_dev_id, mode, &result); -- if (err) { -- pr_warn("Failed to set mini-LED: %d\n", err); -- return err; -- } -- -- if (result > 1) { -- pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result); -- return -EIO; -- } -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mini_led_mode"); -- -- return count; --} --static DEVICE_ATTR_RW(mini_led_mode); -- --static ssize_t available_mini_led_mode_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- switch (asus->mini_led_dev_id) { -- case ASUS_WMI_DEVID_MINI_LED_MODE: -- return sysfs_emit(buf, "0 1\n"); -- case ASUS_WMI_DEVID_MINI_LED_MODE2: -- return sysfs_emit(buf, "0 1 2\n"); -- } -- -- asus_wmi_show_deprecated(); -- -- return sysfs_emit(buf, "0\n"); --} -- --static DEVICE_ATTR_RO(available_mini_led_mode); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* Quirks *********************************************************************/ -- --static void asus_wmi_set_xusb2pr(struct asus_wmi *asus) --{ -- struct pci_dev *xhci_pdev; -- u32 orig_ports_available; -- u32 ports_available = asus->driver->quirks->xusb2pr; -- -- xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, -- PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI, -- NULL); -- -- if (!xhci_pdev) -- return; -- -- pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, -- &orig_ports_available); -- -- pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, -- cpu_to_le32(ports_available)); -- -- pci_dev_put(xhci_pdev); -- -- pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n", -- orig_ports_available, ports_available); --} -- --/* -- * Some devices dont support or have borcken get_als method -- * but still support set method. -- */ --static void asus_wmi_set_als(void) --{ -- asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL); --} -- --/* Hwmon device ***************************************************************/ -- --static int asus_agfn_fan_speed_read(struct asus_wmi *asus, int fan, -- int *speed) --{ -- struct agfn_fan_args args = { -- .agfn.len = sizeof(args), -- .agfn.mfun = ASUS_FAN_MFUN, -- .agfn.sfun = ASUS_FAN_SFUN_READ, -- .fan = fan, -- .speed = 0, -- }; -- struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -- int status; -- -- if (fan != 1) -- return -EINVAL; -- -- status = asus_wmi_evaluate_method_agfn(input); -- -- if (status || args.agfn.err) -- return -ENXIO; -- -- if (speed) -- *speed = args.speed; -- -- return 0; --} -- --static int asus_agfn_fan_speed_write(struct asus_wmi *asus, int fan, -- int *speed) --{ -- struct agfn_fan_args args = { -- .agfn.len = sizeof(args), -- .agfn.mfun = ASUS_FAN_MFUN, -- .agfn.sfun = ASUS_FAN_SFUN_WRITE, -- .fan = fan, -- .speed = speed ? *speed : 0, -- }; -- struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -- int status; -- -- /* 1: for setting 1st fan's speed 0: setting auto mode */ -- if (fan != 1 && fan != 0) -- return -EINVAL; -- -- status = asus_wmi_evaluate_method_agfn(input); -- -- if (status || args.agfn.err) -- return -ENXIO; -- -- if (speed && fan == 1) -- asus->agfn_pwm = *speed; -- -- return 0; --} -- --/* -- * Check if we can read the speed of one fan. If true we assume we can also -- * control it. -- */ --static bool asus_wmi_has_agfn_fan(struct asus_wmi *asus) --{ -- int status; -- int speed; -- u32 value; -- -- status = asus_agfn_fan_speed_read(asus, 1, &speed); -- if (status != 0) -- return false; -- -- status = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); -- if (status != 0) -- return false; -- -- /* -- * We need to find a better way, probably using sfun, -- * bits or spec ... -- * Currently we disable it if: -- * - ASUS_WMI_UNSUPPORTED_METHOD is returned -- * - reverved bits are non-zero -- * - sfun and presence bit are not set -- */ -- return !(value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 -- || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))); --} -- --static int asus_fan_set_auto(struct asus_wmi *asus) --{ -- int status; -- u32 retval; -- -- switch (asus->fan_type) { -- case FAN_TYPE_SPEC83: -- status = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL, -- 0, &retval); -- if (status) -- return status; -- -- if (retval != 1) -- return -EIO; -- break; -- -- case FAN_TYPE_AGFN: -- status = asus_agfn_fan_speed_write(asus, 0, NULL); -- if (status) -- return -ENXIO; -- break; -- -- default: -- return -ENXIO; -- } -- -- /* -- * Modern models like the G713 also have GPU fan control (this is not AGFN) -- */ -- if (asus->gpu_fan_type == FAN_TYPE_SPEC83) { -- status = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL, -- 0, &retval); -- if (status) -- return status; -- -- if (retval != 1) -- return -EIO; -- } -- -- return 0; --} -- --static ssize_t pwm1_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int err; -- int value; -- -- /* If we already set a value then just return it */ -- if (asus->agfn_pwm >= 0) -- return sysfs_emit(buf, "%d\n", asus->agfn_pwm); -- -- /* -- * If we haven't set already set a value through the AGFN interface, -- * we read a current value through the (now-deprecated) FAN_CTRL device. -- */ -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); -- if (err < 0) -- return err; -- -- value &= 0xFF; -- -- if (value == 1) /* Low Speed */ -- value = 85; -- else if (value == 2) -- value = 170; -- else if (value == 3) -- value = 255; -- else if (value) { -- pr_err("Unknown fan speed %#x\n", value); -- value = -1; -- } -- -- return sysfs_emit(buf, "%d\n", value); --} -- --static ssize_t pwm1_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) { -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int value; -- int state; -- int ret; -- -- ret = kstrtouint(buf, 10, &value); -- if (ret) -- return ret; -- -- value = clamp(value, 0, 255); -- -- state = asus_agfn_fan_speed_write(asus, 1, &value); -- if (state) -- pr_warn("Setting fan speed failed: %d\n", state); -- else -- asus->fan_pwm_mode = ASUS_FAN_CTRL_MANUAL; -- -- return count; --} -- --static ssize_t fan1_input_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int value; -- int ret; -- -- switch (asus->fan_type) { -- case FAN_TYPE_SPEC83: -- ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL, -- &value); -- if (ret < 0) -- return ret; -- -- value &= 0xffff; -- break; -- -- case FAN_TYPE_AGFN: -- /* no speed readable on manual mode */ -- if (asus->fan_pwm_mode == ASUS_FAN_CTRL_MANUAL) -- return -ENXIO; -- -- ret = asus_agfn_fan_speed_read(asus, 1, &value); -- if (ret) { -- pr_warn("reading fan speed failed: %d\n", ret); -- return -ENXIO; -- } -- break; -- -- default: -- return -ENXIO; -- } -- -- return sysfs_emit(buf, "%d\n", value < 0 ? -1 : value * 100); --} -- --static ssize_t pwm1_enable_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- /* -- * Just read back the cached pwm mode. -- * -- * For the CPU_FAN device, the spec indicates that we should be -- * able to read the device status and consult bit 19 to see if we -- * are in Full On or Automatic mode. However, this does not work -- * in practice on X532FL at least (the bit is always 0) and there's -- * also nothing in the DSDT to indicate that this behaviour exists. -- */ -- return sysfs_emit(buf, "%d\n", asus->fan_pwm_mode); --} -- --static ssize_t pwm1_enable_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int status = 0; -- int state; -- int value; -- int ret; -- u32 retval; -- -- ret = kstrtouint(buf, 10, &state); -- if (ret) -- return ret; -- -- if (asus->fan_type == FAN_TYPE_SPEC83) { -- switch (state) { /* standard documented hwmon values */ -- case ASUS_FAN_CTRL_FULLSPEED: -- value = 1; -- break; -- case ASUS_FAN_CTRL_AUTO: -- value = 0; -- break; -- default: -- return -EINVAL; -- } -- -- ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL, -- value, &retval); -- if (ret) -- return ret; -- -- if (retval != 1) -- return -EIO; -- } else if (asus->fan_type == FAN_TYPE_AGFN) { -- switch (state) { -- case ASUS_FAN_CTRL_MANUAL: -- break; -- -- case ASUS_FAN_CTRL_AUTO: -- status = asus_fan_set_auto(asus); -- if (status) -- return status; -- break; -- -- default: -- return -EINVAL; -- } -- } -- -- asus->fan_pwm_mode = state; -- -- /* Must set to disabled if mode is toggled */ -- if (asus->cpu_fan_curve_available) -- asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; -- if (asus->gpu_fan_curve_available) -- asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; -- if (asus->mid_fan_curve_available) -- asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false; -- -- return count; --} -- --static ssize_t asus_hwmon_temp1(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- u32 value; -- int err; -- -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value); -- if (err < 0) -- return err; -- -- return sysfs_emit(buf, "%ld\n", -- deci_kelvin_to_millicelsius(value & 0xFFFF)); --} -- --/* GPU fan on modern ROG laptops */ --static ssize_t fan2_input_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int value; -- int ret; -- -- ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL, &value); -- if (ret < 0) -- return ret; -- -- value &= 0xffff; -- -- return sysfs_emit(buf, "%d\n", value * 100); --} -- --/* Middle/Center fan on modern ROG laptops */ --static ssize_t fan3_input_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int value; -- int ret; -- -- ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_MID_FAN_CTRL, &value); -- if (ret < 0) -- return ret; -- -- value &= 0xffff; -- -- return sysfs_emit(buf, "%d\n", value * 100); --} -- --static ssize_t pwm2_enable_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%d\n", asus->gpu_fan_pwm_mode); --} -- --static ssize_t pwm2_enable_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int state; -- int value; -- int ret; -- u32 retval; -- -- ret = kstrtouint(buf, 10, &state); -- if (ret) -- return ret; -- -- switch (state) { /* standard documented hwmon values */ -- case ASUS_FAN_CTRL_FULLSPEED: -- value = 1; -- break; -- case ASUS_FAN_CTRL_AUTO: -- value = 0; -- break; -- default: -- return -EINVAL; -- } -- -- ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL, -- value, &retval); -- if (ret) -- return ret; -- -- if (retval != 1) -- return -EIO; -- -- asus->gpu_fan_pwm_mode = state; -- return count; --} -- --static ssize_t pwm3_enable_show(struct device *dev, -- struct device_attribute *attr, -- char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%d\n", asus->mid_fan_pwm_mode); --} -- --static ssize_t pwm3_enable_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- int state; -- int value; -- int ret; -- u32 retval; -- -- ret = kstrtouint(buf, 10, &state); -- if (ret) -- return ret; -- -- switch (state) { /* standard documented hwmon values */ -- case ASUS_FAN_CTRL_FULLSPEED: -- value = 1; -- break; -- case ASUS_FAN_CTRL_AUTO: -- value = 0; -- break; -- default: -- return -EINVAL; -- } -- -- ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_MID_FAN_CTRL, -- value, &retval); -- if (ret) -- return ret; -- -- if (retval != 1) -- return -EIO; -- -- asus->mid_fan_pwm_mode = state; -- return count; --} -- --/* Fan1 */ --static DEVICE_ATTR_RW(pwm1); --static DEVICE_ATTR_RW(pwm1_enable); --static DEVICE_ATTR_RO(fan1_input); --static DEVICE_STRING_ATTR_RO(fan1_label, 0444, ASUS_FAN_DESC); -- --/* Fan2 - GPU fan */ --static DEVICE_ATTR_RW(pwm2_enable); --static DEVICE_ATTR_RO(fan2_input); --static DEVICE_STRING_ATTR_RO(fan2_label, 0444, ASUS_GPU_FAN_DESC); --/* Fan3 - Middle/center fan */ --static DEVICE_ATTR_RW(pwm3_enable); --static DEVICE_ATTR_RO(fan3_input); --static DEVICE_STRING_ATTR_RO(fan3_label, 0444, ASUS_MID_FAN_DESC); -- --/* Temperature */ --static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL); -- --static struct attribute *hwmon_attributes[] = { -- &dev_attr_pwm1.attr, -- &dev_attr_pwm1_enable.attr, -- &dev_attr_pwm2_enable.attr, -- &dev_attr_pwm3_enable.attr, -- &dev_attr_fan1_input.attr, -- &dev_attr_fan1_label.attr.attr, -- &dev_attr_fan2_input.attr, -- &dev_attr_fan2_label.attr.attr, -- &dev_attr_fan3_input.attr, -- &dev_attr_fan3_label.attr.attr, -- -- &dev_attr_temp1_input.attr, -- NULL --}; -- --static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, -- struct attribute *attr, int idx) --{ -- struct device *dev = kobj_to_dev(kobj); -- struct asus_wmi *asus = dev_get_drvdata(dev->parent); -- u32 value = ASUS_WMI_UNSUPPORTED_METHOD; -- -- if (attr == &dev_attr_pwm1.attr) { -- if (asus->fan_type != FAN_TYPE_AGFN) -- return 0; -- } else if (attr == &dev_attr_fan1_input.attr -- || attr == &dev_attr_fan1_label.attr.attr -- || attr == &dev_attr_pwm1_enable.attr) { -- if (asus->fan_type == FAN_TYPE_NONE) -- return 0; -- } else if (attr == &dev_attr_fan2_input.attr -- || attr == &dev_attr_fan2_label.attr.attr -- || attr == &dev_attr_pwm2_enable.attr) { -- if (asus->gpu_fan_type == FAN_TYPE_NONE) -- return 0; -- } else if (attr == &dev_attr_fan3_input.attr -- || attr == &dev_attr_fan3_label.attr.attr -- || attr == &dev_attr_pwm3_enable.attr) { -- if (asus->mid_fan_type == FAN_TYPE_NONE) -- return 0; -- } else if (attr == &dev_attr_temp1_input.attr) { -- int err = asus_wmi_get_devstate(asus, -- ASUS_WMI_DEVID_THERMAL_CTRL, -- &value); -- -- if (err < 0) -- return 0; /* can't return negative here */ -- -- /* -- * If the temperature value in deci-Kelvin is near the absolute -- * zero temperature, something is clearly wrong -- */ -- if (value == 0 || value == 1) -- return 0; -- } -- -- return attr->mode; --} -- --static const struct attribute_group hwmon_attribute_group = { -- .is_visible = asus_hwmon_sysfs_is_visible, -- .attrs = hwmon_attributes --}; --__ATTRIBUTE_GROUPS(hwmon_attribute); -- --static int asus_wmi_hwmon_init(struct asus_wmi *asus) --{ -- struct device *dev = &asus->platform_device->dev; -- struct device *hwmon; -- -- hwmon = devm_hwmon_device_register_with_groups(dev, "asus", asus, -- hwmon_attribute_groups); -- -- if (IS_ERR(hwmon)) { -- pr_err("Could not register asus hwmon device\n"); -- return PTR_ERR(hwmon); -- } -- return 0; --} -- --static int asus_wmi_fan_init(struct asus_wmi *asus) --{ -- asus->gpu_fan_type = FAN_TYPE_NONE; -- asus->mid_fan_type = FAN_TYPE_NONE; -- asus->fan_type = FAN_TYPE_NONE; -- asus->agfn_pwm = -1; -- -- if (asus->driver->quirks->wmi_ignore_fan) -- asus->fan_type = FAN_TYPE_NONE; -- else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL)) -- asus->fan_type = FAN_TYPE_SPEC83; -- else if (asus_wmi_has_agfn_fan(asus)) -- asus->fan_type = FAN_TYPE_AGFN; -- -- /* Modern models like G713 also have GPU fan control */ -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL)) -- asus->gpu_fan_type = FAN_TYPE_SPEC83; -- -- /* Some models also have a center/middle fan */ -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MID_FAN_CTRL)) -- asus->mid_fan_type = FAN_TYPE_SPEC83; -- -- if (asus->fan_type == FAN_TYPE_NONE) -- return -ENODEV; -- -- asus_fan_set_auto(asus); -- asus->fan_pwm_mode = ASUS_FAN_CTRL_AUTO; -- return 0; --} -- --/* Fan mode *******************************************************************/ -- --static int fan_boost_mode_check_present(struct asus_wmi *asus) --{ -- u32 result; -- int err; -- -- asus->fan_boost_mode_available = false; -- -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_BOOST_MODE, -- &result); -- if (err) { -- if (err == -ENODEV) -- return 0; -- else -- return err; -- } -- -- if ((result & ASUS_WMI_DSTS_PRESENCE_BIT) && -- (result & ASUS_FAN_BOOST_MODES_MASK)) { -- asus->fan_boost_mode_available = true; -- asus->fan_boost_mode_mask = result & ASUS_FAN_BOOST_MODES_MASK; -- } -- -- return 0; --} -- --static int fan_boost_mode_write(struct asus_wmi *asus) --{ -- u32 retval; -- u8 value; -- int err; -- -- value = asus->fan_boost_mode; -- -- pr_info("Set fan boost mode: %u\n", value); -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_BOOST_MODE, value, -- &retval); -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, -- "fan_boost_mode"); -- -- if (err) { -- pr_warn("Failed to set fan boost mode: %d\n", err); -- return err; -- } -- -- if (retval != 1) { -- pr_warn("Failed to set fan boost mode (retval): 0x%x\n", -- retval); -- return -EIO; -- } -- -- return 0; --} -- --static int fan_boost_mode_switch_next(struct asus_wmi *asus) --{ -- u8 mask = asus->fan_boost_mode_mask; -- -- if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_NORMAL) { -- if (mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK) -- asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_OVERBOOST; -- else if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK) -- asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT; -- } else if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) { -- if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK) -- asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT; -- else -- asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL; -- } else { -- asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL; -- } -- -- return fan_boost_mode_write(asus); --} -- --static ssize_t fan_boost_mode_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- -- return sysfs_emit(buf, "%d\n", asus->fan_boost_mode); --} -- --static ssize_t fan_boost_mode_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- u8 mask = asus->fan_boost_mode_mask; -- u8 new_mode; -- int result; -- -- result = kstrtou8(buf, 10, &new_mode); -- if (result < 0) { -- pr_warn("Trying to store invalid value\n"); -- return result; -- } -- -- if (new_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) { -- if (!(mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK)) -- return -EINVAL; -- } else if (new_mode == ASUS_FAN_BOOST_MODE_SILENT) { -- if (!(mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)) -- return -EINVAL; -- } else if (new_mode != ASUS_FAN_BOOST_MODE_NORMAL) { -- return -EINVAL; -- } -- -- asus->fan_boost_mode = new_mode; -- fan_boost_mode_write(asus); -- -- return count; --} -- --// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent --static DEVICE_ATTR_RW(fan_boost_mode); -- --/* Custom fan curves **********************************************************/ -- --static void fan_curve_copy_from_buf(struct fan_curve_data *data, u8 *buf) --{ -- int i; -- -- for (i = 0; i < FAN_CURVE_POINTS; i++) { -- data->temps[i] = buf[i]; -- } -- -- for (i = 0; i < FAN_CURVE_POINTS; i++) { -- data->percents[i] = -- 255 * buf[i + FAN_CURVE_POINTS] / 100; -- } --} -- --static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) --{ -- struct fan_curve_data *curves; -- u8 buf[FAN_CURVE_BUF_LEN]; -- int err, fan_idx; -- u8 mode = 0; -- -- if (asus->throttle_thermal_policy_dev) -- mode = asus->throttle_thermal_policy_mode; -- /* DEVID_PU_FAN_CURVE is switched for OVERBOOST vs SILENT */ -- if (mode == 2) -- mode = 1; -- else if (mode == 1) -- mode = 2; -- -- err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf, -- FAN_CURVE_BUF_LEN); -- if (err) { -- pr_warn("%s (0x%08x) failed: %d\n", __func__, fan_dev, err); -- return err; -- } -- -- fan_idx = FAN_CURVE_DEV_CPU; -- if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE) -- fan_idx = FAN_CURVE_DEV_GPU; -- -- if (fan_dev == ASUS_WMI_DEVID_MID_FAN_CURVE) -- fan_idx = FAN_CURVE_DEV_MID; -- -- curves = &asus->custom_fan_curves[fan_idx]; -- curves->device_id = fan_dev; -- -- fan_curve_copy_from_buf(curves, buf); -- return 0; --} -- --/* Check if capability exists, and populate defaults */ --static int fan_curve_check_present(struct asus_wmi *asus, bool *available, -- u32 fan_dev) --{ -- int err; -- -- *available = false; -- -- if (asus->fan_type == FAN_TYPE_NONE) -- return 0; -- -- err = fan_curve_get_factory_default(asus, fan_dev); -- if (err) { -- return 0; -- } -- -- *available = true; -- return 0; --} -- --/* Determine which fan the attribute is for if SENSOR_ATTR */ --static struct fan_curve_data *fan_curve_attr_select(struct asus_wmi *asus, -- struct device_attribute *attr) --{ -- int index = to_sensor_dev_attr(attr)->index; -- -- return &asus->custom_fan_curves[index]; --} -- --/* Determine which fan the attribute is for if SENSOR_ATTR_2 */ --static struct fan_curve_data *fan_curve_attr_2_select(struct asus_wmi *asus, -- struct device_attribute *attr) --{ -- int nr = to_sensor_dev_attr_2(attr)->nr; -- -- return &asus->custom_fan_curves[nr & ~FAN_CURVE_PWM_MASK]; --} -- --static ssize_t fan_curve_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); -- struct asus_wmi *asus = dev_get_drvdata(dev); -- struct fan_curve_data *data; -- int value, pwm, index; -- -- data = fan_curve_attr_2_select(asus, attr); -- pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; -- index = dev_attr->index; -- -- if (pwm) -- value = data->percents[index]; -- else -- value = data->temps[index]; -- -- return sysfs_emit(buf, "%d\n", value); --} -- --/* -- * "fan_dev" is the related WMI method such as ASUS_WMI_DEVID_CPU_FAN_CURVE. -- */ --static int fan_curve_write(struct asus_wmi *asus, -- struct fan_curve_data *data) --{ -- u32 arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0; -- u8 *percents = data->percents; -- u8 *temps = data->temps; -- int ret, i, shift = 0; -- -- if (!data->enabled) -- return 0; -- -- for (i = 0; i < FAN_CURVE_POINTS / 2; i++) { -- arg1 += (temps[i]) << shift; -- arg2 += (temps[i + 4]) << shift; -- /* Scale to percentage for device */ -- arg3 += (100 * percents[i] / 255) << shift; -- arg4 += (100 * percents[i + 4] / 255) << shift; -- shift += 8; -- } -- -- return asus_wmi_evaluate_method5(ASUS_WMI_METHODID_DEVS, -- data->device_id, -- arg1, arg2, arg3, arg4, &ret); --} -- --static ssize_t fan_curve_store(struct device *dev, -- struct device_attribute *attr, const char *buf, -- size_t count) --{ -- struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); -- struct asus_wmi *asus = dev_get_drvdata(dev); -- struct fan_curve_data *data; -- int err, pwm, index; -- u8 value; -- -- data = fan_curve_attr_2_select(asus, attr); -- pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; -- index = dev_attr->index; -- -- err = kstrtou8(buf, 10, &value); -- if (err < 0) -- return err; -- -- if (pwm) -- data->percents[index] = value; -- else -- data->temps[index] = value; -- -- /* -- * Mark as disabled so the user has to explicitly enable to apply a -- * changed fan curve. This prevents potential lockups from writing out -- * many changes as one-write-per-change. -- */ -- data->enabled = false; -- -- return count; --} -- --static ssize_t fan_curve_enable_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- struct fan_curve_data *data; -- int out = 2; -- -- data = fan_curve_attr_select(asus, attr); -- -- if (data->enabled) -- out = 1; -- -- return sysfs_emit(buf, "%d\n", out); --} -- --static ssize_t fan_curve_enable_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- struct fan_curve_data *data; -- int value, err; -- -- data = fan_curve_attr_select(asus, attr); -- -- err = kstrtoint(buf, 10, &value); -- if (err < 0) -- return err; -- -- switch (value) { -- case 1: -- data->enabled = true; -- break; -- case 2: -- data->enabled = false; -- break; -- /* -- * Auto + reset the fan curve data to defaults. Make it an explicit -- * option so that users don't accidentally overwrite a set fan curve. -- */ -- case 3: -- err = fan_curve_get_factory_default(asus, data->device_id); -- if (err) -- return err; -- data->enabled = false; -- break; -- default: -- return -EINVAL; -- } -- -- if (data->enabled) { -- err = fan_curve_write(asus, data); -- if (err) -- return err; -- } else { -- /* -- * For machines with throttle this is the only way to reset fans -- * to default mode of operation (does not erase curve data). -- */ -- if (asus->throttle_thermal_policy_dev) { -- err = throttle_thermal_policy_write(asus); -- if (err) -- return err; -- /* Similar is true for laptops with this fan */ -- } else if (asus->fan_type == FAN_TYPE_SPEC83) { -- err = asus_fan_set_auto(asus); -- if (err) -- return err; -- } else { -- /* Safeguard against fautly ACPI tables */ -- err = fan_curve_get_factory_default(asus, data->device_id); -- if (err) -- return err; -- err = fan_curve_write(asus, data); -- if (err) -- return err; -- } -- } -- return count; --} -- --/* CPU */ --static SENSOR_DEVICE_ATTR_RW(pwm1_enable, fan_curve_enable, FAN_CURVE_DEV_CPU); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 0); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 1); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 2); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 3); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 4); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 5); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 6); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_temp, fan_curve, -- FAN_CURVE_DEV_CPU, 7); -- --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 0); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 1); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 2); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 3); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 4); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 5); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 6); --static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_pwm, fan_curve, -- FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 7); -- --/* GPU */ --static SENSOR_DEVICE_ATTR_RW(pwm2_enable, fan_curve_enable, FAN_CURVE_DEV_GPU); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 0); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 1); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 2); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 3); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 4); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 5); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 6); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_temp, fan_curve, -- FAN_CURVE_DEV_GPU, 7); -- --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 0); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 1); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 2); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 3); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 4); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 5); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 6); --static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_pwm, fan_curve, -- FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7); -- --/* MID */ --static SENSOR_DEVICE_ATTR_RW(pwm3_enable, fan_curve_enable, FAN_CURVE_DEV_MID); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_temp, fan_curve, -- FAN_CURVE_DEV_MID, 0); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_temp, fan_curve, -- FAN_CURVE_DEV_MID, 1); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_temp, fan_curve, -- FAN_CURVE_DEV_MID, 2); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_temp, fan_curve, -- FAN_CURVE_DEV_MID, 3); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_temp, fan_curve, -- FAN_CURVE_DEV_MID, 4); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_temp, fan_curve, -- FAN_CURVE_DEV_MID, 5); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_temp, fan_curve, -- FAN_CURVE_DEV_MID, 6); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_temp, fan_curve, -- FAN_CURVE_DEV_MID, 7); -- --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 0); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 1); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 2); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 3); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 4); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 5); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 6); --static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_pwm, fan_curve, -- FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 7); -- --static struct attribute *asus_fan_curve_attr[] = { -- /* CPU */ -- &sensor_dev_attr_pwm1_enable.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, -- /* GPU */ -- &sensor_dev_attr_pwm2_enable.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point6_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point7_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point8_temp.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr, -- /* MID */ -- &sensor_dev_attr_pwm3_enable.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point6_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point7_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point8_temp.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point6_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point7_pwm.dev_attr.attr, -- &sensor_dev_attr_pwm3_auto_point8_pwm.dev_attr.attr, -- NULL --}; -- --static umode_t asus_fan_curve_is_visible(struct kobject *kobj, -- struct attribute *attr, int idx) --{ -- struct device *dev = kobj_to_dev(kobj); -- struct asus_wmi *asus = dev_get_drvdata(dev->parent); -- -- /* -- * Check the char instead of casting attr as there are two attr types -- * involved here (attr1 and attr2) -- */ -- if (asus->cpu_fan_curve_available && attr->name[3] == '1') -- return 0644; -- -- if (asus->gpu_fan_curve_available && attr->name[3] == '2') -- return 0644; -- -- if (asus->mid_fan_curve_available && attr->name[3] == '3') -- return 0644; -- -- return 0; --} -- --static const struct attribute_group asus_fan_curve_attr_group = { -- .is_visible = asus_fan_curve_is_visible, -- .attrs = asus_fan_curve_attr, --}; --__ATTRIBUTE_GROUPS(asus_fan_curve_attr); -- --/* -- * Must be initialised after throttle_thermal_policy_dev is set as -- * we check the status of throttle_thermal_policy_dev during init. -- */ --static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) --{ -- struct device *dev = &asus->platform_device->dev; -- struct device *hwmon; -- int err; -- -- err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available, -- ASUS_WMI_DEVID_CPU_FAN_CURVE); -- if (err) { -- pr_debug("%s, checked 0x%08x, failed: %d\n", -- __func__, ASUS_WMI_DEVID_CPU_FAN_CURVE, err); -- return err; -- } -- -- err = fan_curve_check_present(asus, &asus->gpu_fan_curve_available, -- ASUS_WMI_DEVID_GPU_FAN_CURVE); -- if (err) { -- pr_debug("%s, checked 0x%08x, failed: %d\n", -- __func__, ASUS_WMI_DEVID_GPU_FAN_CURVE, err); -- return err; -- } -- -- err = fan_curve_check_present(asus, &asus->mid_fan_curve_available, -- ASUS_WMI_DEVID_MID_FAN_CURVE); -- if (err) { -- pr_debug("%s, checked 0x%08x, failed: %d\n", -- __func__, ASUS_WMI_DEVID_MID_FAN_CURVE, err); -- return err; -- } -- -- if (!asus->cpu_fan_curve_available -- && !asus->gpu_fan_curve_available -- && !asus->mid_fan_curve_available) -- return 0; -- -- hwmon = devm_hwmon_device_register_with_groups( -- dev, "asus_custom_fan_curve", asus, asus_fan_curve_attr_groups); -- -- if (IS_ERR(hwmon)) { -- dev_err(dev, -- "Could not register asus_custom_fan_curve device\n"); -- return PTR_ERR(hwmon); -- } -- -- return 0; --} -- --/* -- * Returns true if at least one custom fan curve is active -- * -- * Used by asus-armoury to check if PPT writes will be accepted by the BIOS -- * on models that require an active fan curve for TDP changes. -- */ --bool asus_wmi_custom_fan_curve_is_enabled(void) --{ -- struct fan_curve_data *curves; -- struct asus_wmi *asus; -- -- guard(spinlock_irqsave)(&asus_ref.lock); -- asus = asus_ref.asus; -- if (!asus) -- return false; -- -- curves = asus->custom_fan_curves; -- -- return (asus->cpu_fan_curve_available && curves[FAN_CURVE_DEV_CPU].enabled) || -- (asus->gpu_fan_curve_available && curves[FAN_CURVE_DEV_GPU].enabled) || -- (asus->mid_fan_curve_available && curves[FAN_CURVE_DEV_MID].enabled); --} --EXPORT_SYMBOL_NS_GPL(asus_wmi_custom_fan_curve_is_enabled, "ASUS_WMI"); -- --/* Throttle thermal policy ****************************************************/ --static int throttle_thermal_policy_write(struct asus_wmi *asus) --{ -- u8 value; -- int err; -- -- if (asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO) { -- switch (asus->throttle_thermal_policy_mode) { -- case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: -- value = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; -- break; -- case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: -- value = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; -- break; -- case ASUS_THROTTLE_THERMAL_POLICY_SILENT: -- value = ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; -- break; -- default: -- return -EINVAL; -- } -- } else { -- value = asus->throttle_thermal_policy_mode; -- } -- -- /* Some machines do not return an error code as a result, so we ignore it */ -- err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, value, NULL); -- -- sysfs_notify(&asus->platform_device->dev.kobj, NULL, -- "throttle_thermal_policy"); -- -- if (err) { -- pr_warn("Failed to set throttle thermal policy: %d\n", err); -- return err; -- } -- -- /* Must set to disabled if mode is toggled */ -- if (asus->cpu_fan_curve_available) -- asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; -- if (asus->gpu_fan_curve_available) -- asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; -- if (asus->mid_fan_curve_available) -- asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false; -- -- return 0; --} -- --static int throttle_thermal_policy_set_default(struct asus_wmi *asus) --{ -- if (!asus->throttle_thermal_policy_dev) -- return 0; -- -- asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -- return throttle_thermal_policy_write(asus); --} -- --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) --static ssize_t throttle_thermal_policy_show(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- u8 mode = asus->throttle_thermal_policy_mode; -- -- return sysfs_emit(buf, "%d\n", mode); --} -- --static ssize_t throttle_thermal_policy_store(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct asus_wmi *asus = dev_get_drvdata(dev); -- u8 new_mode; -- int result; -- int err; -- -- result = kstrtou8(buf, 10, &new_mode); -- if (result < 0) -- return result; -- -- if (new_mode > PLATFORM_PROFILE_MAX) -- return -EINVAL; -- -- asus->throttle_thermal_policy_mode = new_mode; -- err = throttle_thermal_policy_write(asus); -- if (err) -- return err; -- -- /* -- * Ensure that platform_profile updates userspace with the change to ensure -- * that platform_profile and throttle_thermal_policy_mode are in sync. -- */ -- platform_profile_notify(asus->ppdev); -- -- return count; --} -- --/* -- * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent -- */ --static DEVICE_ATTR_RW(throttle_thermal_policy); --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- --/* Platform profile ***********************************************************/ --static int asus_wmi_platform_profile_get(struct device *dev, -- enum platform_profile_option *profile) --{ -- struct asus_wmi *asus; -- int tp; -- -- asus = dev_get_drvdata(dev); -- tp = asus->throttle_thermal_policy_mode; -- -- switch (tp) { -- case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: -- *profile = PLATFORM_PROFILE_BALANCED; -- break; -- case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: -- *profile = PLATFORM_PROFILE_PERFORMANCE; -- break; -- case ASUS_THROTTLE_THERMAL_POLICY_SILENT: -- *profile = PLATFORM_PROFILE_QUIET; -- break; -- default: -- return -EINVAL; -- } -- -- return 0; --} -- --static int asus_wmi_platform_profile_set(struct device *dev, -- enum platform_profile_option profile) --{ -- struct asus_wmi *asus; -- int tp; -- -- asus = dev_get_drvdata(dev); -- -- switch (profile) { -- case PLATFORM_PROFILE_PERFORMANCE: -- tp = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST; -- break; -- case PLATFORM_PROFILE_BALANCED: -- tp = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -- break; -- case PLATFORM_PROFILE_QUIET: -- tp = ASUS_THROTTLE_THERMAL_POLICY_SILENT; -- break; -- default: -- return -EOPNOTSUPP; -- } -- -- asus->throttle_thermal_policy_mode = tp; -- return throttle_thermal_policy_write(asus); --} -- --static int asus_wmi_platform_profile_probe(void *drvdata, unsigned long *choices) --{ -- set_bit(PLATFORM_PROFILE_QUIET, choices); -- set_bit(PLATFORM_PROFILE_BALANCED, choices); -- set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); -- -- return 0; --} -- --static const struct platform_profile_ops asus_wmi_platform_profile_ops = { -- .probe = asus_wmi_platform_profile_probe, -- .profile_get = asus_wmi_platform_profile_get, -- .profile_set = asus_wmi_platform_profile_set, --}; -- --static int platform_profile_setup(struct asus_wmi *asus) --{ -- struct device *dev = &asus->platform_device->dev; -- int err; -- -- /* -- * Not an error if a component platform_profile relies on is unavailable -- * so early return, skipping the setup of platform_profile. -- */ -- if (!asus->throttle_thermal_policy_dev) -- return 0; -- -- /* -- * We need to set the default thermal profile during probe or otherwise -- * the system will often remain in silent mode, causing low performance. -- */ -- err = throttle_thermal_policy_set_default(asus); -- if (err < 0) { -- pr_warn("Failed to set default thermal profile\n"); -- return err; -- } -- -- dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n"); -- -- asus->ppdev = devm_platform_profile_register(dev, "asus-wmi", asus, -- &asus_wmi_platform_profile_ops); -- if (IS_ERR(asus->ppdev)) { -- dev_err(dev, "Failed to register a platform_profile class device\n"); -- return PTR_ERR(asus->ppdev); -- } -- -- asus->platform_profile_support = true; -- return 0; --} -- --/* Backlight ******************************************************************/ -- --static int read_backlight_power(struct asus_wmi *asus) --{ -- int ret; -- -- if (asus->driver->quirks->store_backlight_power) -- ret = !asus->driver->panel_power; -- else -- ret = asus_wmi_get_devstate_simple(asus, -- ASUS_WMI_DEVID_BACKLIGHT); -- -- if (ret < 0) -- return ret; -- -- return ret ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; --} -- --static int read_brightness_max(struct asus_wmi *asus) --{ -- u32 retval; -- int err; -- -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); -- if (err < 0) -- return err; -- -- retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK; -- retval >>= 8; -- -- if (!retval) -- return -ENODEV; -- -- return retval; --} -- --static int read_brightness(struct backlight_device *bd) --{ -- struct asus_wmi *asus = bl_get_data(bd); -- u32 retval; -- int err; -- -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); -- if (err < 0) -- return err; -- -- return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; --} -- --static u32 get_scalar_command(struct backlight_device *bd) --{ -- struct asus_wmi *asus = bl_get_data(bd); -- u32 ctrl_param = 0; -- -- if ((asus->driver->brightness < bd->props.brightness) || -- bd->props.brightness == bd->props.max_brightness) -- ctrl_param = 0x00008001; -- else if ((asus->driver->brightness > bd->props.brightness) || -- bd->props.brightness == 0) -- ctrl_param = 0x00008000; -- -- asus->driver->brightness = bd->props.brightness; -- -- return ctrl_param; --} -- --static int update_bl_status(struct backlight_device *bd) --{ -- struct asus_wmi *asus = bl_get_data(bd); -- u32 ctrl_param; -- int power, err = 0; -- -- power = read_backlight_power(asus); -- if (power != -ENODEV && bd->props.power != power) { -- ctrl_param = !!(bd->props.power == BACKLIGHT_POWER_ON); -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, -- ctrl_param, NULL); -- if (asus->driver->quirks->store_backlight_power) -- asus->driver->panel_power = bd->props.power; -- -- /* When using scalar brightness, updating the brightness -- * will mess with the backlight power */ -- if (asus->driver->quirks->scalar_panel_brightness) -- return err; -- } -- -- if (asus->driver->quirks->scalar_panel_brightness) -- ctrl_param = get_scalar_command(bd); -- else -- ctrl_param = bd->props.brightness; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, -- ctrl_param, NULL); -- -- return err; --} -- --static const struct backlight_ops asus_wmi_bl_ops = { -- .get_brightness = read_brightness, -- .update_status = update_bl_status, --}; -- --static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code) --{ -- struct backlight_device *bd = asus->backlight_device; -- int old = bd->props.brightness; -- int new = old; -- -- if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) -- new = code - NOTIFY_BRNUP_MIN + 1; -- else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) -- new = code - NOTIFY_BRNDOWN_MIN; -- -- bd->props.brightness = new; -- backlight_update_status(bd); -- backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); -- -- return old; --} -- --static int asus_wmi_backlight_init(struct asus_wmi *asus) --{ -- struct backlight_device *bd; -- struct backlight_properties props; -- int max; -- int power; -- -- max = read_brightness_max(asus); -- if (max < 0) -- return max; -- -- power = read_backlight_power(asus); -- if (power == -ENODEV) -- power = BACKLIGHT_POWER_ON; -- else if (power < 0) -- return power; -- -- memset(&props, 0, sizeof(struct backlight_properties)); -- props.type = BACKLIGHT_PLATFORM; -- props.max_brightness = max; -- bd = backlight_device_register(asus->driver->name, -- &asus->platform_device->dev, asus, -- &asus_wmi_bl_ops, &props); -- if (IS_ERR(bd)) { -- pr_err("Could not register backlight device\n"); -- return PTR_ERR(bd); -- } -- -- asus->backlight_device = bd; -- -- if (asus->driver->quirks->store_backlight_power) -- asus->driver->panel_power = power; -- -- bd->props.brightness = read_brightness(bd); -- bd->props.power = power; -- backlight_update_status(bd); -- -- asus->driver->brightness = bd->props.brightness; -- -- return 0; --} -- --static void asus_wmi_backlight_exit(struct asus_wmi *asus) --{ -- backlight_device_unregister(asus->backlight_device); -- -- asus->backlight_device = NULL; --} -- --static int is_display_toggle(int code) --{ -- /* display toggle keys */ -- if ((code >= 0x61 && code <= 0x67) || -- (code >= 0x8c && code <= 0x93) || -- (code >= 0xa0 && code <= 0xa7) || -- (code >= 0xd0 && code <= 0xd5)) -- return 1; -- -- return 0; --} -- --/* Screenpad backlight *******************************************************/ -- --static int read_screenpad_backlight_power(struct asus_wmi *asus) --{ -- int ret; -- -- ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); -- if (ret < 0) -- return ret; -- /* 1 == powered */ -- return ret ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; --} -- --static int read_screenpad_brightness(struct backlight_device *bd) --{ -- struct asus_wmi *asus = bl_get_data(bd); -- u32 retval; -- int err; -- -- err = read_screenpad_backlight_power(asus); -- if (err < 0) -- return err; -- /* The device brightness can only be read if powered, so return stored */ -- if (err == BACKLIGHT_POWER_OFF) -- return bd->props.brightness; -- -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); -- if (err < 0) -- return err; -- -- return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; --} -- --static int update_screenpad_bl_status(struct backlight_device *bd) --{ -- u32 ctrl_param = bd->props.brightness; -- int err = 0; -- -- if (bd->props.power) { -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL); -- if (err < 0) -- return err; -- -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); -- if (err < 0) -- return err; -- } -- -- if (!bd->props.power) { -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); -- if (err < 0) -- return err; -- } -- -- return err; --} -- --static const struct backlight_ops asus_screenpad_bl_ops = { -- .get_brightness = read_screenpad_brightness, -- .update_status = update_screenpad_bl_status, -- .options = BL_CORE_SUSPENDRESUME, --}; -- --static int asus_screenpad_init(struct asus_wmi *asus) --{ -- struct backlight_device *bd; -- struct backlight_properties props; -- int err, power; -- int brightness = 0; -- -- power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); -- if (power < 0) -- return power; -- -- if (power) { -- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); -- if (err < 0) -- return err; -- } -- -- memset(&props, 0, sizeof(struct backlight_properties)); -- props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ -- props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX; -- bd = backlight_device_register("asus_screenpad", -- &asus->platform_device->dev, asus, -- &asus_screenpad_bl_ops, &props); -- if (IS_ERR(bd)) { -- pr_err("Could not register backlight device\n"); -- return PTR_ERR(bd); -- } -- -- asus->screenpad_backlight_device = bd; -- asus->driver->screenpad_brightness = brightness; -- bd->props.brightness = brightness; -- bd->props.power = power; -- backlight_update_status(bd); -- -- return 0; --} -- --static void asus_screenpad_exit(struct asus_wmi *asus) --{ -- backlight_device_unregister(asus->screenpad_backlight_device); -- -- asus->screenpad_backlight_device = NULL; --} -- --/* Fn-lock ********************************************************************/ -- --static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus) --{ -- u32 result; -- -- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result); -- -- return (result & ASUS_WMI_DSTS_PRESENCE_BIT) && -- !(result & ASUS_WMI_FNLOCK_BIOS_DISABLED); --} -- --static void asus_wmi_fnlock_update(struct asus_wmi *asus) --{ -- int mode = asus->fnlock_locked; -- -- asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL); --} -- --/* WMI events *****************************************************************/ -- --static int asus_wmi_get_event_code(union acpi_object *obj) --{ -- int code; -- -- if (obj && obj->type == ACPI_TYPE_INTEGER) -- code = (int)(obj->integer.value & WMI_EVENT_MASK); -- else -- code = -EIO; -- -- return code; --} -- --static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) --{ -- enum led_brightness led_value; -- unsigned int key_value = 1; -- bool autorelease = 1; -- -- if (asus->driver->key_filter) { -- asus->driver->key_filter(asus->driver, &code, &key_value, -- &autorelease); -- if (code == ASUS_WMI_KEY_IGNORE) -- return; -- } -- -- if (acpi_video_get_backlight_type() == acpi_backlight_vendor && -- code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNDOWN_MAX) { -- asus_wmi_backlight_notify(asus, code); -- return; -- } -- -- scoped_guard(spinlock_irqsave, &asus_ref.lock) -- led_value = asus->kbd_led_wk; -- -- if (code == NOTIFY_KBD_BRTUP) { -- kbd_led_set_by_kbd(asus, led_value + 1); -- return; -- } -- if (code == NOTIFY_KBD_BRTDWN) { -- kbd_led_set_by_kbd(asus, led_value - 1); -- return; -- } -- if (code == NOTIFY_KBD_BRTTOGGLE) { -- if (led_value >= ASUS_EV_MAX_BRIGHTNESS) -- kbd_led_set_by_kbd(asus, 0); -- else -- kbd_led_set_by_kbd(asus, led_value + 1); -- return; -- } -- -- if (code == NOTIFY_FNLOCK_TOGGLE) { -- asus->fnlock_locked = !asus->fnlock_locked; -- asus_wmi_fnlock_update(asus); -- return; -- } -- -- if (code == asus->tablet_switch_event_code) { -- asus_wmi_tablet_mode_get_state(asus); -- return; -- } -- -- if (code == NOTIFY_KEYSTONE) { -- if (asus->keystone_available) -- asus_wmi_keystone_notify(asus); -- return; -- } -- -- if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) { -- if (asus->fan_boost_mode_available) -- fan_boost_mode_switch_next(asus); -- if (asus->throttle_thermal_policy_dev) -- platform_profile_cycle(); -- return; -- -- } -- -- if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle) -- return; -- -- if (!sparse_keymap_report_event(asus->inputdev, code, -- key_value, autorelease)) -- pr_info("Unknown key code 0x%x\n", code); --} -- --static void asus_wmi_notify(union acpi_object *obj, void *context) --{ -- struct asus_wmi *asus = context; -- int code = asus_wmi_get_event_code(obj); -- -- if (code < 0) { -- pr_warn("Failed to get notify code: %d\n", code); -- return; -- } -- -- asus_wmi_handle_event_code(code, asus); --} -- --/* Sysfs **********************************************************************/ -- --static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, -- const char *buf, size_t count) --{ -- u32 retval; -- int err, value; -- -- value = asus_wmi_get_devstate_simple(asus, devid); -- if (value < 0) -- return value; -- -- err = kstrtoint(buf, 0, &value); -- if (err) -- return err; -- -- err = asus_wmi_set_devstate(devid, value, &retval); -- if (err < 0) -- return err; -- -- return count; --} -- --static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) --{ -- int value = asus_wmi_get_devstate_simple(asus, devid); -- -- if (value < 0) -- return value; -- -- return sysfs_emit(buf, "%d\n", value); --} -- --#define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ -- static ssize_t show_##_name(struct device *dev, \ -- struct device_attribute *attr, \ -- char *buf) \ -- { \ -- struct asus_wmi *asus = dev_get_drvdata(dev); \ -- \ -- return show_sys_wmi(asus, _cm, buf); \ -- } \ -- static ssize_t store_##_name(struct device *dev, \ -- struct device_attribute *attr, \ -- const char *buf, size_t count) \ -- { \ -- struct asus_wmi *asus = dev_get_drvdata(dev); \ -- \ -- return store_sys_wmi(asus, _cm, buf, count); \ -- } \ -- static struct device_attribute dev_attr_##_name = { \ -- .attr = { \ -- .name = __stringify(_name), \ -- .mode = _mode }, \ -- .show = show_##_name, \ -- .store = store_##_name, \ -- } -- --ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); --ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); --ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); --ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME); --ASUS_WMI_CREATE_DEVICE_ATTR(als_enable, 0644, ASUS_WMI_DEVID_ALS_ENABLE); -- --static ssize_t cpufv_store(struct device *dev, struct device_attribute *attr, -- const char *buf, size_t count) --{ -- int value, rv; -- -- rv = kstrtoint(buf, 0, &value); -- if (rv) -- return rv; -- -- if (value < 0 || value > 2) -- return -EINVAL; -- -- rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); -- if (rv < 0) -- return rv; -- -- return count; --} -- --static DEVICE_ATTR_WO(cpufv); -- --static struct attribute *platform_attributes[] = { -- &dev_attr_cpufv.attr, -- &dev_attr_camera.attr, -- &dev_attr_cardr.attr, -- &dev_attr_touchpad.attr, -- &dev_attr_lid_resume.attr, -- &dev_attr_als_enable.attr, -- &dev_attr_fan_boost_mode.attr, -- &dev_attr_keystone.attr, --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -- &dev_attr_charge_mode.attr, -- &dev_attr_egpu_enable.attr, -- &dev_attr_egpu_connected.attr, -- &dev_attr_dgpu_disable.attr, -- &dev_attr_gpu_mux_mode.attr, -- &dev_attr_ppt_pl2_sppt.attr, -- &dev_attr_ppt_pl1_spl.attr, -- &dev_attr_ppt_fppt.attr, -- &dev_attr_ppt_apu_sppt.attr, -- &dev_attr_ppt_platform_sppt.attr, -- &dev_attr_nv_dynamic_boost.attr, -- &dev_attr_nv_temp_target.attr, -- &dev_attr_mcu_powersave.attr, -- &dev_attr_boot_sound.attr, -- &dev_attr_panel_od.attr, -- &dev_attr_mini_led_mode.attr, -- &dev_attr_available_mini_led_mode.attr, -- &dev_attr_throttle_thermal_policy.attr, --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- NULL --}; -- --static umode_t asus_sysfs_is_visible(struct kobject *kobj, -- struct attribute *attr, int idx) --{ -- struct device *dev = kobj_to_dev(kobj); -- struct asus_wmi *asus = dev_get_drvdata(dev); -- bool ok = true; -- int devid = -1; -- -- if (attr == &dev_attr_camera.attr) -- devid = ASUS_WMI_DEVID_CAMERA; -- else if (attr == &dev_attr_cardr.attr) -- devid = ASUS_WMI_DEVID_CARDREADER; -- else if (attr == &dev_attr_touchpad.attr) -- devid = ASUS_WMI_DEVID_TOUCHPAD; -- else if (attr == &dev_attr_lid_resume.attr) -- devid = ASUS_WMI_DEVID_LID_RESUME; -- else if (attr == &dev_attr_als_enable.attr) -- devid = ASUS_WMI_DEVID_ALS_ENABLE; -- else if (attr == &dev_attr_fan_boost_mode.attr) -- ok = asus->fan_boost_mode_available; -- else if (attr == &dev_attr_keystone.attr) -- ok = asus->keystone_available; -- --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -- if (attr == &dev_attr_charge_mode.attr) -- devid = ASUS_WMI_DEVID_CHARGE_MODE; -- else if (attr == &dev_attr_egpu_enable.attr) -- ok = asus->egpu_enable_available; -- else if (attr == &dev_attr_egpu_connected.attr) -- devid = ASUS_WMI_DEVID_EGPU_CONNECTED; -- else if (attr == &dev_attr_dgpu_disable.attr) -- ok = asus->dgpu_disable_available; -- else if (attr == &dev_attr_gpu_mux_mode.attr) -- ok = asus->gpu_mux_dev != 0; -- else if (attr == &dev_attr_fan_boost_mode.attr) -- ok = asus->fan_boost_mode_available; -- else if (attr == &dev_attr_throttle_thermal_policy.attr) -- ok = asus->throttle_thermal_policy_dev != 0; -- else if (attr == &dev_attr_ppt_pl2_sppt.attr) -- devid = ASUS_WMI_DEVID_PPT_PL2_SPPT; -- else if (attr == &dev_attr_ppt_pl1_spl.attr) -- devid = ASUS_WMI_DEVID_PPT_PL1_SPL; -- else if (attr == &dev_attr_ppt_fppt.attr) -- devid = ASUS_WMI_DEVID_PPT_PL3_FPPT; -- else if (attr == &dev_attr_ppt_apu_sppt.attr) -- devid = ASUS_WMI_DEVID_PPT_APU_SPPT; -- else if (attr == &dev_attr_ppt_platform_sppt.attr) -- devid = ASUS_WMI_DEVID_PPT_PLAT_SPPT; -- else if (attr == &dev_attr_nv_dynamic_boost.attr) -- devid = ASUS_WMI_DEVID_NV_DYN_BOOST; -- else if (attr == &dev_attr_nv_temp_target.attr) -- devid = ASUS_WMI_DEVID_NV_THERM_TARGET; -- else if (attr == &dev_attr_mcu_powersave.attr) -- devid = ASUS_WMI_DEVID_MCU_POWERSAVE; -- else if (attr == &dev_attr_boot_sound.attr) -- devid = ASUS_WMI_DEVID_BOOT_SOUND; -- else if (attr == &dev_attr_panel_od.attr) -- devid = ASUS_WMI_DEVID_PANEL_OD; -- else if (attr == &dev_attr_mini_led_mode.attr) -- ok = asus->mini_led_dev_id != 0; -- else if (attr == &dev_attr_available_mini_led_mode.attr) -- ok = asus->mini_led_dev_id != 0; --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- -- if (devid != -1) { -- ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); -- pr_debug("%s called 0x%08x, ok: %x\n", __func__, devid, ok); -- } -- -- return ok ? attr->mode : 0; --} -- --static const struct attribute_group platform_attribute_group = { -- .is_visible = asus_sysfs_is_visible, -- .attrs = platform_attributes --}; -- --static void asus_wmi_sysfs_exit(struct platform_device *device) --{ -- sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); --} -- --static int asus_wmi_sysfs_init(struct platform_device *device) --{ -- return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); --} -- --/* Platform device ************************************************************/ -- --static int asus_wmi_platform_init(struct asus_wmi *asus) --{ -- struct device *dev = &asus->platform_device->dev; -- char *wmi_uid; -- int rv; -- -- /* INIT enable hotkeys on some models */ -- if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv)) -- pr_info("Initialization: %#x\n", rv); -- -- /* We don't know yet what to do with this version... */ -- if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { -- pr_info("BIOS WMI version: %d.%d\n", rv >> 16, rv & 0xFF); -- asus->spec = rv; -- } -- -- /* -- * The SFUN method probably allows the original driver to get the list -- * of features supported by a given model. For now, 0x0100 or 0x0800 -- * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. -- * The significance of others is yet to be found. -- */ -- if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) { -- pr_info("SFUN value: %#x\n", rv); -- asus->sfun = rv; -- } -- -- /* -- * Eee PC and Notebooks seems to have different method_id for DSTS, -- * but it may also be related to the BIOS's SPEC. -- * Note, on most Eeepc, there is no way to check if a method exist -- * or note, while on notebooks, they returns 0xFFFFFFFE on failure, -- * but once again, SPEC may probably be used for that kind of things. -- * -- * Additionally at least TUF Gaming series laptops return nothing for -- * unknown methods, so the detection in this way is not possible. -- * -- * There is strong indication that only ACPI WMI devices that have _UID -- * equal to "ASUSWMI" use DCTS whereas those with "ATK" use DSTS. -- */ -- wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); -- if (!wmi_uid) -- return -ENODEV; -- -- if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) { -- dev_info(dev, "Detected ASUSWMI, use DCTS\n"); -- asus->dsts_id = ASUS_WMI_METHODID_DCTS; -- } else { -- dev_info(dev, "Detected %s, not ASUSWMI, use DSTS\n", wmi_uid); -- asus->dsts_id = ASUS_WMI_METHODID_DSTS; -- } -- -- /* CWAP allow to define the behavior of the Fn+F2 key, -- * this method doesn't seems to be present on Eee PCs */ -- if (asus->driver->quirks->wapf >= 0) -- asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP, -- asus->driver->quirks->wapf, NULL); -- -- return 0; --} -- --/* debugfs ********************************************************************/ -- --struct asus_wmi_debugfs_node { -- struct asus_wmi *asus; -- char *name; -- int (*show) (struct seq_file *m, void *data); --}; -- --static int show_dsts(struct seq_file *m, void *data) --{ -- struct asus_wmi *asus = m->private; -- int err; -- u32 retval = -1; -- -- err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); -- if (err < 0) -- return err; -- -- seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval); -- -- return 0; --} -- --static int show_devs(struct seq_file *m, void *data) --{ -- struct asus_wmi *asus = m->private; -- int err; -- u32 retval = -1; -- -- err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, -- &retval); -- if (err < 0) -- return err; -- -- seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id, -- asus->debug.ctrl_param, retval); -- -- return 0; --} -- --static int show_call(struct seq_file *m, void *data) --{ -- struct asus_wmi *asus = m->private; -- struct bios_args args = { -- .arg0 = asus->debug.dev_id, -- .arg1 = asus->debug.ctrl_param, -- }; -- struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -- union acpi_object *obj; -- acpi_status status; -- -- status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, -- 0, asus->debug.method_id, -- &input, &output); -- -- if (ACPI_FAILURE(status)) -- return -EIO; -- -- obj = (union acpi_object *)output.pointer; -- if (obj && obj->type == ACPI_TYPE_INTEGER) -- seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id, -- asus->debug.dev_id, asus->debug.ctrl_param, -- (u32) obj->integer.value); -- else -- seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id, -- asus->debug.dev_id, asus->debug.ctrl_param, -- obj ? obj->type : -1); -- -- kfree(obj); -- -- return 0; --} -- --static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = { -- {NULL, "devs", show_devs}, -- {NULL, "dsts", show_dsts}, -- {NULL, "call", show_call}, --}; -- --static int asus_wmi_debugfs_open(struct inode *inode, struct file *file) --{ -- struct asus_wmi_debugfs_node *node = inode->i_private; -- -- return single_open(file, node->show, node->asus); --} -- --static const struct file_operations asus_wmi_debugfs_io_ops = { -- .owner = THIS_MODULE, -- .open = asus_wmi_debugfs_open, -- .read = seq_read, -- .llseek = seq_lseek, -- .release = single_release, --}; -- --static void asus_wmi_debugfs_exit(struct asus_wmi *asus) --{ -- debugfs_remove_recursive(asus->debug.root); --} -- --static void asus_wmi_debugfs_init(struct asus_wmi *asus) --{ -- int i; -- -- asus->debug.root = debugfs_create_dir(asus->driver->name, NULL); -- -- debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, asus->debug.root, -- &asus->debug.method_id); -- -- debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, asus->debug.root, -- &asus->debug.dev_id); -- -- debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, asus->debug.root, -- &asus->debug.ctrl_param); -- -- for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) { -- struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i]; -- -- node->asus = asus; -- debugfs_create_file(node->name, S_IFREG | S_IRUGO, -- asus->debug.root, node, -- &asus_wmi_debugfs_io_ops); -- } --} -- --/* Init / exit ****************************************************************/ -- --static int asus_wmi_add(struct platform_device *pdev) --{ -- struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); -- struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); -- struct asus_wmi *asus; -- acpi_status status; -- int err; -- u32 result; -- -- asus = kzalloc_obj(struct asus_wmi); -- if (!asus) -- return -ENOMEM; -- -- asus->driver = wdrv; -- asus->platform_device = pdev; -- wdrv->platform_device = pdev; -- platform_set_drvdata(asus->platform_device, asus); -- -- if (wdrv->detect_quirks) -- wdrv->detect_quirks(asus->driver); -- -- err = asus_wmi_platform_init(asus); -- if (err) -- goto fail_platform; -- -- if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_INIT) { -- if (acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) -- && dmi_check_system(asus_rog_ally_device)) -- use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_ENABLED; -- if (dmi_match(DMI_BOARD_NAME, "RC71")) { -- /* -- * These steps ensure the device is in a valid good state, this is -- * especially important for the Ally 1 after a reboot. -- */ -- acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, -- ASUS_USB0_PWR_EC0_CSEE_ON); -- msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -- } -- } -- -- /* ensure defaults for tunables */ --#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -- asus->ppt_pl2_sppt = 5; -- asus->ppt_pl1_spl = 5; -- asus->ppt_apu_sppt = 5; -- asus->ppt_platform_sppt = 5; -- asus->ppt_fppt = 5; -- asus->nv_dynamic_boost = 5; -- asus->nv_temp_target = 75; -- -- asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); -- asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); -- asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) -- asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -- else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE2)) -- asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX)) -- asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX; -- else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO)) -- asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO; --#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -- -- asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE); -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY)) -- asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY; -- else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO)) -- asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE)) -- asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE; -- else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2)) -- asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2; -- -- err = fan_boost_mode_check_present(asus); -- if (err) -- goto fail_fan_boost_mode; -- -- err = platform_profile_setup(asus); -- if (err) -- goto fail_platform_profile_setup; -- -- err = keystone_check_present(asus); -- if (err) -- dev_warn(&pdev->dev, "Failed to check Keystone presence: %d\n", err); -- -- err = asus_wmi_sysfs_init(asus->platform_device); -- if (err) -- goto fail_sysfs; -- -- err = asus_wmi_input_init(asus); -- if (err) -- goto fail_input; -- -- err = asus_wmi_fan_init(asus); /* probably no problems on error */ -- -- err = asus_wmi_hwmon_init(asus); -- if (err) -- goto fail_hwmon; -- -- err = asus_wmi_custom_fan_curve_init(asus); -- if (err) -- goto fail_custom_fan_curve; -- -- err = asus_wmi_led_init(asus); -- if (err) -- goto fail_leds; -- -- asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result); -- if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) == -- (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) -- asus->driver->wlan_ctrl_by_user = 1; -- -- if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) { -- err = asus_wmi_rfkill_init(asus); -- if (err) -- goto fail_rfkill; -- } -- -- if (asus->driver->quirks->wmi_force_als_set) -- asus_wmi_set_als(); -- -- if (asus->driver->quirks->xusb2pr) -- asus_wmi_set_xusb2pr(asus); -- -- if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { -- err = asus_wmi_backlight_init(asus); -- if (err && err != -ENODEV) -- goto fail_backlight; -- } else if (asus->driver->quirks->wmi_backlight_set_devstate) -- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); -- -- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT)) { -- err = asus_screenpad_init(asus); -- if (err && err != -ENODEV) -- goto fail_screenpad; -- } -- -- if (asus_wmi_has_fnlock_key(asus)) { -- asus->fnlock_locked = fnlock_default; -- asus_wmi_fnlock_update(asus); -- } -- -- status = wmi_install_notify_handler(asus->driver->event_guid, -- asus_wmi_notify, asus); -- if (ACPI_FAILURE(status)) { -- pr_err("Unable to register notify handler - %d\n", status); -- err = -ENODEV; -- goto fail_wmi_handler; -- } -- -- if (asus->driver->i8042_filter) { -- err = i8042_install_filter(asus->driver->i8042_filter, NULL); -- if (err) -- pr_warn("Unable to install key filter - %d\n", err); -- } -- -- asus_wmi_battery_init(asus); -- -- asus_wmi_debugfs_init(asus); -- -- return 0; -- --fail_wmi_handler: -- asus_screenpad_exit(asus); --fail_screenpad: -- asus_wmi_backlight_exit(asus); --fail_backlight: -- asus_wmi_rfkill_exit(asus); --fail_rfkill: -- asus_wmi_led_exit(asus); --fail_leds: --fail_custom_fan_curve: --fail_hwmon: -- asus_wmi_input_exit(asus); --fail_input: -- asus_wmi_sysfs_exit(asus->platform_device); --fail_sysfs: --fail_platform_profile_setup: --fail_fan_boost_mode: --fail_platform: -- kfree(asus); -- return err; --} -- --static void asus_wmi_remove(struct platform_device *device) --{ -- struct asus_wmi *asus; -- -- asus = platform_get_drvdata(device); -- if (asus->driver->i8042_filter) -- i8042_remove_filter(asus->driver->i8042_filter); -- wmi_remove_notify_handler(asus->driver->event_guid); -- asus_wmi_backlight_exit(asus); -- asus_screenpad_exit(asus); -- asus_wmi_input_exit(asus); -- asus_wmi_led_exit(asus); -- asus_wmi_rfkill_exit(asus); -- asus_wmi_debugfs_exit(asus); -- asus_wmi_sysfs_exit(asus->platform_device); -- asus_fan_set_auto(asus); -- throttle_thermal_policy_set_default(asus); -- asus_wmi_battery_exit(asus); -- -- kfree(asus); --} -- --/* Platform driver - hibernate/resume callbacks *******************************/ -- --static int asus_hotk_thaw(struct device *device) --{ -- struct asus_wmi *asus = dev_get_drvdata(device); -- -- if (asus->wlan.rfkill) { -- bool wlan; -- -- /* -- * Work around bios bug - acpi _PTS turns off the wireless led -- * during suspend. Normally it restores it on resume, but -- * we should kick it ourselves in case hibernation is aborted. -- */ -- wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); -- asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); -- } -- -- return 0; --} -- --static int asus_hotk_resume(struct device *device) --{ -- struct asus_wmi *asus = dev_get_drvdata(device); -- -- if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) -- kbd_led_update(asus); -- -- if (asus_wmi_has_fnlock_key(asus)) -- asus_wmi_fnlock_update(asus); -- -- asus_wmi_tablet_mode_get_state(asus); -- -- return 0; --} -- --static int asus_hotk_restore(struct device *device) --{ -- struct asus_wmi *asus = dev_get_drvdata(device); -- int bl; -- -- /* Refresh both wlan rfkill state and pci hotplug */ -- if (asus->wlan.rfkill) -- asus_rfkill_hotplug(asus); -- -- if (asus->bluetooth.rfkill) { -- bl = !asus_wmi_get_devstate_simple(asus, -- ASUS_WMI_DEVID_BLUETOOTH); -- rfkill_set_sw_state(asus->bluetooth.rfkill, bl); -- } -- if (asus->wimax.rfkill) { -- bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX); -- rfkill_set_sw_state(asus->wimax.rfkill, bl); -- } -- if (asus->wwan3g.rfkill) { -- bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); -- rfkill_set_sw_state(asus->wwan3g.rfkill, bl); -- } -- if (asus->gps.rfkill) { -- bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS); -- rfkill_set_sw_state(asus->gps.rfkill, bl); -- } -- if (asus->uwb.rfkill) { -- bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); -- rfkill_set_sw_state(asus->uwb.rfkill, bl); -- } -- if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) -- kbd_led_update(asus); -- if (asus->oobe_state_available) { -- /* -- * Disable OOBE state, so that e.g. the keyboard backlight -- * works. -- */ -- asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL); -- } -- -- if (asus_wmi_has_fnlock_key(asus)) -- asus_wmi_fnlock_update(asus); -- -- asus_wmi_tablet_mode_get_state(asus); -- return 0; --} -- --static int asus_hotk_prepare(struct device *device) --{ -- if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_ENABLED) { -- acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, -- ASUS_USB0_PWR_EC0_CSEE_OFF); -- msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -- } -- return 0; --} -- --#if defined(CONFIG_SUSPEND) --static void asus_ally_s2idle_restore(void) --{ -- if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_ENABLED) { -- acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, -- ASUS_USB0_PWR_EC0_CSEE_ON); -- msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -- } --} -- --/* Use only for Ally devices due to the wake_on_ac */ --static struct acpi_s2idle_dev_ops asus_ally_s2idle_dev_ops = { -- .restore = asus_ally_s2idle_restore, --}; -- --static void asus_s2idle_check_register(void) --{ -- if (acpi_register_lps0_dev(&asus_ally_s2idle_dev_ops)) -- pr_warn("failed to register LPS0 sleep handler in asus-wmi\n"); --} -- --static void asus_s2idle_check_unregister(void) --{ -- acpi_unregister_lps0_dev(&asus_ally_s2idle_dev_ops); --} --#else --static void asus_s2idle_check_register(void) {} --static void asus_s2idle_check_unregister(void) {} --#endif /* CONFIG_SUSPEND */ -- --static const struct dev_pm_ops asus_pm_ops = { -- .thaw = asus_hotk_thaw, -- .restore = asus_hotk_restore, -- .resume = asus_hotk_resume, -- .prepare = asus_hotk_prepare, --}; -- --/* Registration ***************************************************************/ -- --static int asus_wmi_probe(struct platform_device *pdev) --{ -- struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); -- struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); -- int ret; -- -- if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { -- pr_warn("ASUS Management GUID not found\n"); -- return -ENODEV; -- } -- -- if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) { -- pr_warn("ASUS Event GUID not found\n"); -- return -ENODEV; -- } -- -- if (wdrv->probe) { -- ret = wdrv->probe(pdev); -- if (ret) -- return ret; -- } -- -- asus_s2idle_check_register(); -- -- ret = asus_wmi_add(pdev); -- if (ret) -- asus_s2idle_check_unregister(); -- -- return ret; --} -- --static bool used; --static DEFINE_MUTEX(register_mutex); -- --int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver) --{ -- struct platform_driver *platform_driver; -- struct platform_device *platform_device; -- -- guard(mutex)(®ister_mutex); -- if (used) -- return -EBUSY; -- -- platform_driver = &driver->platform_driver; -- platform_driver->remove = asus_wmi_remove; -- platform_driver->driver.owner = driver->owner; -- platform_driver->driver.name = driver->name; -- platform_driver->driver.pm = &asus_pm_ops; -- -- platform_device = platform_create_bundle(platform_driver, -- asus_wmi_probe, -- NULL, 0, NULL, 0); -- if (IS_ERR(platform_device)) -- return PTR_ERR(platform_device); -- -- used = true; -- return 0; --} --EXPORT_SYMBOL_GPL(asus_wmi_register_driver); -- --void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) --{ -- guard(mutex)(®ister_mutex); -- asus_s2idle_check_unregister(); -- -- platform_device_unregister(driver->platform_device); -- platform_driver_unregister(&driver->platform_driver); -- used = false; --} --EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver); ---- /dev/null -+++ b/drivers/platform/asus/asus-wmi.c -@@ -0,0 +1,5538 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Asus PC WMI hotkey driver -+ * -+ * Copyright(C) 2010 Intel Corporation. -+ * Copyright(C) 2010-2011 Corentin Chary -+ * -+ * Portions based on wistron_btns.c: -+ * Copyright (C) 2005 Miloslav Trmac -+ * Copyright (C) 2005 Bernhard Rosenkraenzer -+ * Copyright (C) 2005 Dmitry Torokhov -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "asus-wmi.h" -+ -+MODULE_AUTHOR("Corentin Chary "); -+MODULE_AUTHOR("Yong Wang "); -+MODULE_DESCRIPTION("Asus Generic WMI Driver"); -+MODULE_LICENSE("GPL"); -+ -+static bool fnlock_default = true; -+module_param(fnlock_default, bool, 0444); -+ -+#define to_asus_wmi_driver(pdrv) \ -+ (container_of((pdrv), struct asus_wmi_driver, platform_driver)) -+ -+#define NOTIFY_BRNUP_MIN 0x11 -+#define NOTIFY_BRNUP_MAX 0x1f -+#define NOTIFY_BRNDOWN_MIN 0x20 -+#define NOTIFY_BRNDOWN_MAX 0x2e -+#define NOTIFY_FNLOCK_TOGGLE 0x4e -+#define NOTIFY_KBD_DOCK_CHANGE 0x75 -+#define NOTIFY_KBD_BRTUP 0xc4 -+#define NOTIFY_KBD_BRTDWN 0xc5 -+#define NOTIFY_KBD_BRTTOGGLE 0xc7 -+#define NOTIFY_KBD_FBM 0x99 -+#define NOTIFY_KBD_TTP 0xae -+#define NOTIFY_LID_FLIP 0xfa -+#define NOTIFY_LID_FLIP_ROG 0xbd -+#define NOTIFY_KEYSTONE 0xb4 -+ -+#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0) -+ -+#define ASUS_MID_FAN_DESC "mid_fan" -+#define ASUS_GPU_FAN_DESC "gpu_fan" -+#define ASUS_FAN_DESC "cpu_fan" -+#define ASUS_FAN_MFUN 0x13 -+#define ASUS_FAN_SFUN_READ 0x06 -+#define ASUS_FAN_SFUN_WRITE 0x07 -+ -+/* Based on standard hwmon pwmX_enable values */ -+#define ASUS_FAN_CTRL_FULLSPEED 0 -+#define ASUS_FAN_CTRL_MANUAL 1 -+#define ASUS_FAN_CTRL_AUTO 2 -+ -+#define ASUS_FAN_BOOST_MODE_NORMAL 0 -+#define ASUS_FAN_BOOST_MODE_OVERBOOST 1 -+#define ASUS_FAN_BOOST_MODE_OVERBOOST_MASK 0x01 -+#define ASUS_FAN_BOOST_MODE_SILENT 2 -+#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02 -+#define ASUS_FAN_BOOST_MODES_MASK 0x03 -+ -+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT 0 -+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1 -+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2 -+ -+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0 -+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1 -+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2 -+ -+#define PLATFORM_PROFILE_MAX 2 -+ -+#define USB_INTEL_XUSB2PR 0xD0 -+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 -+ -+#define WMI_EVENT_MASK 0xFFFF -+ -+#define FAN_CURVE_POINTS 8 -+#define FAN_CURVE_BUF_LEN 32 -+#define FAN_CURVE_DEV_CPU 0x00 -+#define FAN_CURVE_DEV_GPU 0x01 -+#define FAN_CURVE_DEV_MID 0x02 -+/* Mask to determine if setting temperature or percentage */ -+#define FAN_CURVE_PWM_MASK 0x04 -+ -+/* Limits for tunables available on ASUS ROG laptops */ -+#define PPT_TOTAL_MIN 5 -+#define PPT_TOTAL_MAX 250 -+#define PPT_CPU_MIN 5 -+#define PPT_CPU_MAX 130 -+#define NVIDIA_BOOST_MIN 5 -+#define NVIDIA_BOOST_MAX 25 -+#define NVIDIA_TEMP_MIN 75 -+#define NVIDIA_TEMP_MAX 87 -+ -+#define ASUS_SCREENPAD_BRIGHT_MAX 255 -+#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 -+ -+#define ASUS_MINI_LED_MODE_MASK 0x03 -+/* Standard modes for devices with only on/off */ -+#define ASUS_MINI_LED_OFF 0x00 -+#define ASUS_MINI_LED_ON 0x01 -+/* New mode on some devices, define here to clarify remapping later */ -+#define ASUS_MINI_LED_STRONG_MODE 0x02 -+/* New modes for devices with 3 mini-led mode types */ -+#define ASUS_MINI_LED_2024_WEAK 0x00 -+#define ASUS_MINI_LED_2024_STRONG 0x01 -+#define ASUS_MINI_LED_2024_OFF 0x02 -+ -+#define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE" -+/* -+ * The period required to wait after screen off/on/s2idle.check in MS. -+ * Time here greatly impacts the wake behaviour. Used in suspend/wake. -+ */ -+#define ASUS_USB0_PWR_EC0_CSEE_WAIT 600 -+#define ASUS_USB0_PWR_EC0_CSEE_OFF 0xB7 -+#define ASUS_USB0_PWR_EC0_CSEE_ON 0xB8 -+ -+static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; -+ -+static int throttle_thermal_policy_write(struct asus_wmi *); -+ -+static const struct dmi_system_id asus_rog_ally_device[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC71L"), -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC72L"), -+ }, -+ }, -+ { }, -+}; -+ -+static bool ashs_present(void) -+{ -+ int i = 0; -+ while (ashs_ids[i]) { -+ if (acpi_dev_found(ashs_ids[i++])) -+ return true; -+ } -+ return false; -+} -+ -+struct bios_args { -+ u32 arg0; -+ u32 arg1; -+ u32 arg2; /* At least TUF Gaming series uses 3 dword input buffer. */ -+ u32 arg3; -+ u32 arg4; /* Some ROG laptops require a full 5 input args */ -+ u32 arg5; -+} __packed; -+ -+/* -+ * Struct that's used for all methods called via AGFN. Naming is -+ * identically to the AML code. -+ */ -+struct agfn_args { -+ u16 mfun; /* probably "Multi-function" to be called */ -+ u16 sfun; /* probably "Sub-function" to be called */ -+ u16 len; /* size of the hole struct, including subfunction fields */ -+ u8 stas; /* not used by now */ -+ u8 err; /* zero on success */ -+} __packed; -+ -+/* struct used for calling fan read and write methods */ -+struct agfn_fan_args { -+ struct agfn_args agfn; /* common fields */ -+ u8 fan; /* fan number: 0: set auto mode 1: 1st fan */ -+ u32 speed; /* read: RPM/100 - write: 0-255 */ -+} __packed; -+ -+/* -+ * / - debugfs root directory -+ * dev_id - current dev_id -+ * ctrl_param - current ctrl_param -+ * method_id - current method_id -+ * devs - call DEVS(dev_id, ctrl_param) and print result -+ * dsts - call DSTS(dev_id) and print result -+ * call - call method_id(dev_id, ctrl_param) and print result -+ */ -+struct asus_wmi_debug { -+ struct dentry *root; -+ u32 method_id; -+ u32 dev_id; -+ u32 ctrl_param; -+}; -+ -+struct asus_rfkill { -+ struct asus_wmi *asus; -+ struct rfkill *rfkill; -+ u32 dev_id; -+}; -+ -+enum fan_type { -+ FAN_TYPE_NONE = 0, -+ FAN_TYPE_AGFN, /* deprecated on newer platforms */ -+ FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */ -+}; -+ -+struct fan_curve_data { -+ bool enabled; -+ u32 device_id; -+ u8 temps[FAN_CURVE_POINTS]; -+ u8 percents[FAN_CURVE_POINTS]; -+}; -+ -+struct asus_wmi { -+ int dsts_id; -+ int spec; -+ int sfun; -+ -+ struct input_dev *inputdev; -+ struct backlight_device *backlight_device; -+ struct backlight_device *screenpad_backlight_device; -+ struct platform_device *platform_device; -+ -+ struct led_classdev wlan_led; -+ int wlan_led_wk; -+ struct led_classdev tpd_led; -+ int tpd_led_wk; -+ struct led_classdev kbd_led; -+ int kbd_led_wk; -+ bool kbd_led_notify; -+ bool kbd_led_avail; -+ bool kbd_led_registered; -+ struct led_classdev lightbar_led; -+ int lightbar_led_wk; -+ struct led_classdev micmute_led; -+ struct led_classdev camera_led; -+ struct workqueue_struct *led_workqueue; -+ struct work_struct tpd_led_work; -+ struct work_struct wlan_led_work; -+ struct work_struct lightbar_led_work; -+ struct work_struct kbd_led_work; -+ -+ struct asus_rfkill wlan; -+ struct asus_rfkill bluetooth; -+ struct asus_rfkill wimax; -+ struct asus_rfkill wwan3g; -+ struct asus_rfkill gps; -+ struct asus_rfkill uwb; -+ -+ int tablet_switch_event_code; -+ u32 tablet_switch_dev_id; -+ bool tablet_switch_inverted; -+ -+ bool keystone_available; -+ -+ enum fan_type fan_type; -+ enum fan_type gpu_fan_type; -+ enum fan_type mid_fan_type; -+ int fan_pwm_mode; -+ int gpu_fan_pwm_mode; -+ int mid_fan_pwm_mode; -+ int agfn_pwm; -+ -+ bool fan_boost_mode_available; -+ u8 fan_boost_mode_mask; -+ u8 fan_boost_mode; -+ -+ bool egpu_enable_available; -+ bool dgpu_disable_available; -+ u32 gpu_mux_dev; -+ -+ /* Tunables provided by ASUS for gaming laptops */ -+ u32 ppt_pl2_sppt; -+ u32 ppt_pl1_spl; -+ u32 ppt_apu_sppt; -+ u32 ppt_platform_sppt; -+ u32 ppt_fppt; -+ u32 nv_dynamic_boost; -+ u32 nv_temp_target; -+ -+ u32 kbd_rgb_dev; -+ bool kbd_rgb_state_available; -+ bool oobe_state_available; -+ -+ u8 throttle_thermal_policy_mode; -+ u32 throttle_thermal_policy_dev; -+ -+ bool cpu_fan_curve_available; -+ bool gpu_fan_curve_available; -+ bool mid_fan_curve_available; -+ struct fan_curve_data custom_fan_curves[3]; -+ -+ struct device *ppdev; -+ bool platform_profile_support; -+ -+ // The RSOC controls the maximum charging percentage. -+ bool battery_rsoc_available; -+ -+ bool panel_overdrive_available; -+ u32 mini_led_dev_id; -+ -+ struct hotplug_slot hotplug_slot; -+ struct mutex hotplug_lock; -+ struct mutex wmi_lock; -+ struct workqueue_struct *hotplug_workqueue; -+ struct work_struct hotplug_work; -+ -+ bool fnlock_locked; -+ -+ struct asus_wmi_debug debug; -+ -+ struct asus_wmi_driver *driver; -+}; -+ -+/* Global to allow setting externally without requiring driver data */ -+static enum asus_ally_mcu_hack use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_INIT; -+ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static void asus_wmi_show_deprecated(void) -+{ -+ pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi is deprecated and will be removed in a future release. Please switch over to /sys/class/firmware_attributes.\n"); -+} -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* WMI ************************************************************************/ -+ -+/* H7607BA.300 returns an extended RSOC capability buffer, not an integer. */ -+static bool asus_wmi_p16_extended_rsoc(void) -+{ -+ return dmi_match(DMI_SYS_VENDOR, "ASUS") && -+ dmi_match(DMI_PRODUCT_NAME, "ProArt P16 H7607BA") && -+ dmi_match(DMI_BIOS_VERSION, "H7607BA.300"); -+} -+ -+static int asus_wmi_evaluate_method3(u32 method_id, -+ u32 arg0, u32 arg1, u32 arg2, u32 *retval) -+{ -+ struct bios_args args = { -+ .arg0 = arg0, -+ .arg1 = arg1, -+ .arg2 = arg2, -+ }; -+ struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ union acpi_object *obj; -+ u32 tmp = 0; -+ -+ status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, -+ &input, &output); -+ -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1, arg2); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); -+ return -EIO; -+ } -+ -+ obj = (union acpi_object *)output.pointer; -+ if (obj && obj->type == ACPI_TYPE_INTEGER) -+ tmp = (u32) obj->integer.value; -+ else if (obj && obj->type == ACPI_TYPE_BUFFER && -+ obj->buffer.length == 8 && -+ method_id == ASUS_WMI_METHODID_DSTS && -+ arg0 == ASUS_WMI_DEVID_RSOC && -+ asus_wmi_p16_extended_rsoc()) -+ tmp = get_unaligned_le32(obj->buffer.pointer); -+ -+ pr_debug("Result: 0x%08x\n", tmp); -+ if (retval) -+ *retval = tmp; -+ -+ kfree(obj); -+ -+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -ENODEV); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval) -+{ -+ return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval); -+} -+EXPORT_SYMBOL_NS_GPL(asus_wmi_evaluate_method, "ASUS_WMI"); -+ -+static int asus_wmi_evaluate_method5(u32 method_id, -+ u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval) -+{ -+ struct bios_args args = { -+ .arg0 = arg0, -+ .arg1 = arg1, -+ .arg2 = arg2, -+ .arg3 = arg3, -+ .arg4 = arg4, -+ }; -+ struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ union acpi_object *obj; -+ u32 tmp = 0; -+ -+ status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, -+ &input, &output); -+ -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1, arg2, arg3, arg4); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); -+ return -EIO; -+ } -+ -+ obj = (union acpi_object *)output.pointer; -+ if (obj && obj->type == ACPI_TYPE_INTEGER) -+ tmp = (u32) obj->integer.value; -+ -+ pr_debug("Result: %x\n", tmp); -+ if (retval) -+ *retval = tmp; -+ -+ kfree(obj); -+ -+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -ENODEV); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Returns as an error if the method output is not a buffer. Typically this -+ * means that the method called is unsupported. -+ */ -+static int asus_wmi_evaluate_method_buf(u32 method_id, -+ u32 arg0, u32 arg1, u8 *ret_buffer, size_t size) -+{ -+ struct bios_args args = { -+ .arg0 = arg0, -+ .arg1 = arg1, -+ .arg2 = 0, -+ }; -+ struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -+ acpi_status status; -+ union acpi_object *obj; -+ int err = 0; -+ -+ status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id, -+ &input, &output); -+ -+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x\n", -+ __func__, method_id, arg0, arg1); -+ if (ACPI_FAILURE(status)) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, -EIO); -+ return -EIO; -+ } -+ -+ obj = (union acpi_object *)output.pointer; -+ -+ switch (obj->type) { -+ case ACPI_TYPE_BUFFER: -+ if (obj->buffer.length > size) { -+ err = -ENOSPC; -+ break; -+ } -+ if (obj->buffer.length == 0) { -+ err = -ENODATA; -+ break; -+ } -+ -+ memcpy(ret_buffer, obj->buffer.pointer, obj->buffer.length); -+ break; -+ case ACPI_TYPE_INTEGER: -+ err = (u32)obj->integer.value; -+ -+ if (err == ASUS_WMI_UNSUPPORTED_METHOD) -+ err = -ENODEV; -+ /* -+ * At least one method returns a 0 with no buffer if no arg -+ * is provided, such as ASUS_WMI_DEVID_CPU_FAN_CURVE -+ */ -+ if (err == 0) -+ err = -ENODATA; -+ break; -+ default: -+ err = -ENODATA; -+ break; -+ } -+ -+ kfree(obj); -+ -+ if (err) { -+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n", -+ __func__, method_id, arg0, err); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args) -+{ -+ struct acpi_buffer input; -+ u64 phys_addr; -+ u32 retval; -+ u32 status; -+ -+ /* -+ * Copy to dma capable address otherwise memory corruption occurs as -+ * bios has to be able to access it. -+ */ -+ input.pointer = kmemdup(args.pointer, args.length, GFP_DMA | GFP_KERNEL); -+ input.length = args.length; -+ if (!input.pointer) -+ return -ENOMEM; -+ phys_addr = virt_to_phys(input.pointer); -+ -+ status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_AGFN, -+ phys_addr, 0, &retval); -+ if (!status) -+ memcpy(args.pointer, input.pointer, args.length); -+ -+ kfree(input.pointer); -+ if (status) -+ return -ENXIO; -+ -+ return retval; -+} -+ -+static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) -+{ -+ int err; -+ -+ err = asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval); -+ -+ if (err) -+ return err; -+ -+ if (*retval == ~0) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+/** -+ * asus_wmi_get_devstate_dsts() - Get the WMI function state. -+ * @dev_id: The WMI method ID to call. -+ * @retval: A pointer to where to store the value returned from WMI. -+ * -+ * Returns: -+ * * %-ENODEV - method ID is unsupported. -+ * * %0 - successful and retval is filled. -+ * * %other - error from WMI call. -+ */ -+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval) -+{ -+ int err; -+ -+ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval); -+ if (err) -+ return err; -+ -+ if ((*retval & ASUS_WMI_DSTS_PRESENCE_BIT) == 0x00) -+ return -ENODEV; -+ -+ return 0; -+} -+EXPORT_SYMBOL_NS_GPL(asus_wmi_get_devstate_dsts, "ASUS_WMI"); -+ -+/** -+ * asus_wmi_set_devstate() - Set the WMI function state. -+ * -+ * Note: an asus_wmi_set_devstate() call must be paired with a -+ * asus_wmi_get_devstate_dsts() to check if the WMI function is supported. -+ * -+ * @dev_id: The WMI function to call. -+ * @ctrl_param: The argument to be used for this WMI function. -+ * @retval: A pointer to where to store the value returned from WMI. -+ * -+ * Returns: -+ * * %-ENODEV - method ID is unsupported. -+ * * %0 - successful and retval is filled. -+ * * %other - error from WMI call. -+ */ -+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval) -+{ -+ return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, -+ ctrl_param, retval); -+} -+EXPORT_SYMBOL_NS_GPL(asus_wmi_set_devstate, "ASUS_WMI"); -+ -+/* Helper for special devices with magic return codes */ -+static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, -+ u32 dev_id, u32 mask) -+{ -+ u32 retval = 0; -+ int err; -+ -+ err = asus_wmi_get_devstate(asus, dev_id, &retval); -+ if (err < 0) -+ return err; -+ -+ if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) -+ return -ENODEV; -+ -+ if (mask == ASUS_WMI_DSTS_STATUS_BIT) { -+ if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT) -+ return -ENODEV; -+ } -+ -+ return retval & mask; -+} -+ -+static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) -+{ -+ return asus_wmi_get_devstate_bits(asus, dev_id, -+ ASUS_WMI_DSTS_STATUS_BIT); -+} -+ -+static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id) -+{ -+ u32 retval; -+ int status = asus_wmi_get_devstate(asus, dev_id, &retval); -+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); -+ -+ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); -+} -+ -+/* Keystone *******************************************************************/ -+ -+static int keystone_check_present(struct asus_wmi *asus) -+{ -+ u32 retval; -+ int err; -+ -+ asus->keystone_available = false; -+ -+ /* -+ * Use a raw devstate call rather than asus_wmi_dev_is_present(). -+ * For this devid, PRESENCE_BIT encodes current insert state, not -+ * feature presence, so asus_wmi_dev_is_present() would return false -+ * whenever the dongle is absent at boot, even on machines that have -+ * a keystone slot. -+ * -ENODEV means the firmware doesn't know this devid at all. -+ * retval is not examined here, only the return code matters. -+ */ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_KEYSTONE, &retval); -+ if (err == -ENODEV) -+ return 0; -+ if (err) -+ return err; -+ -+ asus->keystone_available = true; -+ return 0; -+} -+ -+static ssize_t keystone_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ u32 retval; -+ int err; -+ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_KEYSTONE, &retval); -+ if (err) -+ return err; -+ -+ return sysfs_emit(buf, "%d\n", !!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)); -+} -+ -+static DEVICE_ATTR_RO(keystone); -+ -+static void asus_wmi_keystone_notify(struct asus_wmi *asus) -+{ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "keystone"); -+} -+ -+/* Input **********************************************************************/ -+static void asus_wmi_tablet_sw_report(struct asus_wmi *asus, bool value) -+{ -+ input_report_switch(asus->inputdev, SW_TABLET_MODE, -+ asus->tablet_switch_inverted ? !value : value); -+ input_sync(asus->inputdev); -+} -+ -+static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code) -+{ -+ struct device *dev = &asus->platform_device->dev; -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, dev_id); -+ if (result >= 0) { -+ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); -+ asus_wmi_tablet_sw_report(asus, result); -+ asus->tablet_switch_dev_id = dev_id; -+ asus->tablet_switch_event_code = event_code; -+ } else if (result == -ENODEV) { -+ dev_err(dev, "This device has tablet-mode-switch quirk but got ENODEV checking it. This is a bug."); -+ } else { -+ dev_err(dev, "Error checking for tablet-mode-switch: %d\n", result); -+ } -+} -+ -+static int asus_wmi_input_init(struct asus_wmi *asus) -+{ -+ struct device *dev = &asus->platform_device->dev; -+ int err; -+ -+ asus->inputdev = input_allocate_device(); -+ if (!asus->inputdev) -+ return -ENOMEM; -+ -+ asus->inputdev->name = asus->driver->input_name; -+ asus->inputdev->phys = asus->driver->input_phys; -+ asus->inputdev->id.bustype = BUS_HOST; -+ asus->inputdev->dev.parent = dev; -+ set_bit(EV_REP, asus->inputdev->evbit); -+ -+ err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); -+ if (err) -+ goto err_free_dev; -+ -+ switch (asus->driver->quirks->tablet_switch_mode) { -+ case asus_wmi_no_tablet_switch: -+ break; -+ case asus_wmi_kbd_dock_devid: -+ asus->tablet_switch_inverted = true; -+ asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE); -+ break; -+ case asus_wmi_lid_flip_devid: -+ asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP, NOTIFY_LID_FLIP); -+ break; -+ case asus_wmi_lid_flip_rog_devid: -+ asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP_ROG, NOTIFY_LID_FLIP_ROG); -+ break; -+ } -+ -+ err = input_register_device(asus->inputdev); -+ if (err) -+ goto err_free_dev; -+ -+ return 0; -+ -+err_free_dev: -+ input_free_device(asus->inputdev); -+ return err; -+} -+ -+static void asus_wmi_input_exit(struct asus_wmi *asus) -+{ -+ if (asus->inputdev) -+ input_unregister_device(asus->inputdev); -+ -+ asus->inputdev = NULL; -+} -+ -+/* Tablet mode ****************************************************************/ -+ -+static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) -+{ -+ int result; -+ -+ if (!asus->tablet_switch_dev_id) -+ return; -+ -+ result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id); -+ if (result >= 0) -+ asus_wmi_tablet_sw_report(asus, result); -+} -+ -+/* Charging mode, 1=Barrel, 2=USB ******************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t charge_mode_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, value; -+ -+ result = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CHARGE_MODE, &value); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", value & 0xff); -+} -+ -+static DEVICE_ATTR_RO(charge_mode); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* dGPU ********************************************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t dgpu_disable_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", result); -+} -+ -+/* -+ * A user may be required to store the value twice, typcial store first, then -+ * rescan PCI bus to activate power, then store a second time to save correctly. -+ * The reason for this is that an extra code path in the ACPI is enabled when -+ * the device and bus are powered. -+ */ -+static ssize_t dgpu_disable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 disable; -+ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ result = kstrtou32(buf, 10, &disable); -+ if (result) -+ return result; -+ -+ if (disable > 1) -+ return -EINVAL; -+ -+ if (asus->gpu_mux_dev) { -+ result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); -+ if (result < 0) -+ /* An error here may signal greater failure of GPU handling */ -+ return result; -+ if (!result && disable) { -+ err = -ENODEV; -+ pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err); -+ return err; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result); -+ if (err) { -+ pr_warn("Failed to set dgpu disable: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set dgpu disable (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "dgpu_disable"); -+ -+ return count; -+} -+static DEVICE_ATTR_RW(dgpu_disable); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* eGPU ********************************************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t egpu_enable_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", result); -+} -+ -+/* The ACPI call to enable the eGPU also disables the internal dGPU */ -+static ssize_t egpu_enable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 enable; -+ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ err = kstrtou32(buf, 10, &enable); -+ if (err) -+ return err; -+ -+ if (enable > 1) -+ return -EINVAL; -+ -+ err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); -+ if (err < 0) { -+ pr_warn("Failed to get egpu connection status: %d\n", err); -+ return err; -+ } -+ -+ if (asus->gpu_mux_dev) { -+ result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); -+ if (result < 0) { -+ /* An error here may signal greater failure of GPU handling */ -+ pr_warn("Failed to get gpu mux status: %d\n", result); -+ return result; -+ } -+ if (!result && enable) { -+ err = -ENODEV; -+ pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err); -+ return err; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); -+ if (err) { -+ pr_warn("Failed to set egpu state: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set egpu state (retval): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable"); -+ -+ return count; -+} -+static DEVICE_ATTR_RW(egpu_enable); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* Is eGPU connected? *********************************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t egpu_connected_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", result); -+} -+ -+static DEVICE_ATTR_RO(egpu_connected); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* gpu mux switch *************************************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t gpu_mux_mode_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, asus->gpu_mux_dev); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", result); -+} -+ -+static ssize_t gpu_mux_mode_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 optimus; -+ -+ err = kstrtou32(buf, 10, &optimus); -+ if (err) -+ return err; -+ -+ if (optimus > 1) -+ return -EINVAL; -+ -+ if (asus->dgpu_disable_available) { -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU); -+ if (result < 0) -+ /* An error here may signal greater failure of GPU handling */ -+ return result; -+ if (result && !optimus) { -+ err = -ENODEV; -+ pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err); -+ return err; -+ } -+ } -+ -+ if (asus->egpu_enable_available) { -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU); -+ if (result < 0) -+ /* An error here may signal greater failure of GPU handling */ -+ return result; -+ if (result && !optimus) { -+ err = -ENODEV; -+ pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err); -+ return err; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(asus->gpu_mux_dev, optimus, &result); -+ if (err) { -+ dev_err(dev, "Failed to set GPU MUX mode: %d\n", err); -+ return err; -+ } -+ /* !1 is considered a fail by ASUS */ -+ if (result != 1) { -+ dev_warn(dev, "Failed to set GPU MUX mode (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "gpu_mux_mode"); -+ -+ return count; -+} -+static DEVICE_ATTR_RW(gpu_mux_mode); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* TUF Laptop Keyboard RGB Modes **********************************************/ -+static ssize_t kbd_rgb_mode_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ u32 cmd, mode, r, g, b, speed; -+ struct led_classdev *led; -+ struct asus_wmi *asus; -+ int err; -+ -+ led = dev_get_drvdata(dev); -+ asus = container_of(led, struct asus_wmi, kbd_led); -+ -+ if (sscanf(buf, "%d %d %d %d %d %d", &cmd, &mode, &r, &g, &b, &speed) != 6) -+ return -EINVAL; -+ -+ /* B3 is set and B4 is save to BIOS */ -+ switch (cmd) { -+ case 0: -+ cmd = 0xb3; -+ break; -+ case 1: -+ cmd = 0xb4; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* These are the known usable modes across all TUF/ROG */ -+ if (mode >= 12 || mode == 9) -+ mode = 10; -+ -+ switch (speed) { -+ case 0: -+ speed = 0xe1; -+ break; -+ case 1: -+ speed = 0xeb; -+ break; -+ case 2: -+ speed = 0xf5; -+ break; -+ default: -+ speed = 0xeb; -+ } -+ -+ err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, asus->kbd_rgb_dev, -+ cmd | (mode << 8) | (r << 16) | (g << 24), b | (speed << 8), NULL); -+ if (err) -+ return err; -+ -+ return count; -+} -+static DEVICE_ATTR_WO(kbd_rgb_mode); -+ -+static DEVICE_STRING_ATTR_RO(kbd_rgb_mode_index, 0444, -+ "cmd mode red green blue speed"); -+ -+static struct attribute *kbd_rgb_mode_attrs[] = { -+ &dev_attr_kbd_rgb_mode.attr, -+ &dev_attr_kbd_rgb_mode_index.attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group kbd_rgb_mode_group = { -+ .attrs = kbd_rgb_mode_attrs, -+}; -+ -+/* TUF Laptop Keyboard RGB State **********************************************/ -+static ssize_t kbd_rgb_state_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ u32 flags, cmd, boot, awake, sleep, keyboard; -+ int err; -+ -+ if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &keyboard) != 5) -+ return -EINVAL; -+ -+ if (cmd) -+ cmd = BIT(2); -+ -+ flags = 0; -+ if (boot) -+ flags |= BIT(1); -+ if (awake) -+ flags |= BIT(3); -+ if (sleep) -+ flags |= BIT(5); -+ if (keyboard) -+ flags |= BIT(7); -+ -+ /* 0xbd is the required default arg0 for the method. Nothing happens otherwise */ -+ err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, -+ ASUS_WMI_DEVID_TUF_RGB_STATE, 0xbd | cmd << 8 | (flags << 16), 0, NULL); -+ if (err) -+ return err; -+ -+ return count; -+} -+static DEVICE_ATTR_WO(kbd_rgb_state); -+ -+static DEVICE_STRING_ATTR_RO(kbd_rgb_state_index, 0444, -+ "cmd boot awake sleep keyboard"); -+ -+static struct attribute *kbd_rgb_state_attrs[] = { -+ &dev_attr_kbd_rgb_state.attr, -+ &dev_attr_kbd_rgb_state_index.attr.attr, -+ NULL, -+}; -+ -+static const struct attribute_group kbd_rgb_state_group = { -+ .attrs = kbd_rgb_state_attrs, -+}; -+ -+static const struct attribute_group *kbd_rgb_mode_groups[] = { -+ NULL, -+ NULL, -+ NULL, -+}; -+ -+/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t ppt_pl2_sppt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 value; -+ -+ result = kstrtou32(buf, 10, &value); -+ if (result) -+ return result; -+ -+ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL2_SPPT, value, &result); -+ if (err) { -+ pr_warn("Failed to set ppt_pl2_sppt: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set ppt_pl2_sppt (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ asus->ppt_pl2_sppt = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt"); -+ -+ return count; -+} -+ -+static ssize_t ppt_pl2_sppt_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt); -+} -+static DEVICE_ATTR_RW(ppt_pl2_sppt); -+ -+/* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/ -+static ssize_t ppt_pl1_spl_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 value; -+ -+ result = kstrtou32(buf, 10, &value); -+ if (result) -+ return result; -+ -+ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL1_SPL, value, &result); -+ if (err) { -+ pr_warn("Failed to set ppt_pl1_spl: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set ppt_pl1_spl (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ asus->ppt_pl1_spl = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl"); -+ -+ return count; -+} -+static ssize_t ppt_pl1_spl_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl); -+} -+static DEVICE_ATTR_RW(ppt_pl1_spl); -+ -+/* Tunable: PPT APU FPPT ******************************************************/ -+static ssize_t ppt_fppt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 value; -+ -+ result = kstrtou32(buf, 10, &value); -+ if (result) -+ return result; -+ -+ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL3_FPPT, value, &result); -+ if (err) { -+ pr_warn("Failed to set ppt_fppt: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set ppt_fppt (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ asus->ppt_fppt = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt"); -+ -+ return count; -+} -+ -+static ssize_t ppt_fppt_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%u\n", asus->ppt_fppt); -+} -+static DEVICE_ATTR_RW(ppt_fppt); -+ -+/* Tunable: PPT APU SPPT *****************************************************/ -+static ssize_t ppt_apu_sppt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 value; -+ -+ result = kstrtou32(buf, 10, &value); -+ if (result) -+ return result; -+ -+ if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_APU_SPPT, value, &result); -+ if (err) { -+ pr_warn("Failed to set ppt_apu_sppt: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set ppt_apu_sppt (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ asus->ppt_apu_sppt = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt"); -+ -+ return count; -+} -+ -+static ssize_t ppt_apu_sppt_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt); -+} -+static DEVICE_ATTR_RW(ppt_apu_sppt); -+ -+/* Tunable: PPT platform SPPT ************************************************/ -+static ssize_t ppt_platform_sppt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 value; -+ -+ result = kstrtou32(buf, 10, &value); -+ if (result) -+ return result; -+ -+ if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PLAT_SPPT, value, &result); -+ if (err) { -+ pr_warn("Failed to set ppt_platform_sppt: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set ppt_platform_sppt (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ asus->ppt_platform_sppt = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt"); -+ -+ return count; -+} -+ -+static ssize_t ppt_platform_sppt_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt); -+} -+static DEVICE_ATTR_RW(ppt_platform_sppt); -+ -+/* Tunable: NVIDIA dynamic boost *********************************************/ -+static ssize_t nv_dynamic_boost_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 value; -+ -+ result = kstrtou32(buf, 10, &value); -+ if (result) -+ return result; -+ -+ if (value < NVIDIA_BOOST_MIN || value > NVIDIA_BOOST_MAX) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_DYN_BOOST, value, &result); -+ if (err) { -+ pr_warn("Failed to set nv_dynamic_boost: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set nv_dynamic_boost (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ asus->nv_dynamic_boost = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost"); -+ -+ return count; -+} -+ -+static ssize_t nv_dynamic_boost_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost); -+} -+static DEVICE_ATTR_RW(nv_dynamic_boost); -+ -+/* Tunable: NVIDIA temperature target ****************************************/ -+static ssize_t nv_temp_target_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result, err; -+ u32 value; -+ -+ result = kstrtou32(buf, 10, &value); -+ if (result) -+ return result; -+ -+ if (value < NVIDIA_TEMP_MIN || value > NVIDIA_TEMP_MAX) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_THERM_TARGET, value, &result); -+ if (err) { -+ pr_warn("Failed to set nv_temp_target: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set nv_temp_target (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ asus->nv_temp_target = value; -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target"); -+ -+ return count; -+} -+ -+static ssize_t nv_temp_target_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%u\n", asus->nv_temp_target); -+} -+static DEVICE_ATTR_RW(nv_temp_target); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* Ally MCU Powersave ********************************************************/ -+ -+/* -+ * The HID driver needs to check MCU version and set this to false if the MCU FW -+ * version is >= the minimum requirements. New FW do not need the hacks. -+ */ -+void set_ally_mcu_hack(enum asus_ally_mcu_hack status) -+{ -+ use_ally_mcu_hack = status; -+ pr_debug("%s Ally MCU suspend quirk\n", -+ status == ASUS_WMI_ALLY_MCU_HACK_ENABLED ? "Enabled" : "Disabled"); -+} -+EXPORT_SYMBOL_NS_GPL(set_ally_mcu_hack, "ASUS_WMI"); -+ -+/* -+ * mcu_powersave should be enabled always, as it is fixed in MCU FW versions: -+ * - v313 for Ally X -+ * - v319 for Ally 1 -+ * The HID driver checks MCU versions and so should set this if requirements match -+ */ -+void set_ally_mcu_powersave(bool enabled) -+{ -+ int result, err; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, enabled, &result); -+ if (err) { -+ pr_warn("Failed to set MCU powersave: %d\n", err); -+ return; -+ } -+ if (result > 1) { -+ pr_warn("Failed to set MCU powersave (result): 0x%x\n", result); -+ return; -+ } -+ -+ pr_debug("%s MCU Powersave\n", -+ enabled ? "Enabled" : "Disabled"); -+} -+EXPORT_SYMBOL_NS_GPL(set_ally_mcu_powersave, "ASUS_WMI"); -+ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t mcu_powersave_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MCU_POWERSAVE); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", result); -+} -+ -+static ssize_t mcu_powersave_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 enable; -+ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ result = kstrtou32(buf, 10, &enable); -+ if (result) -+ return result; -+ -+ if (enable > 1) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, enable, &result); -+ if (err) { -+ pr_warn("Failed to set MCU powersave: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set MCU powersave (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mcu_powersave"); -+ -+ return count; -+} -+static DEVICE_ATTR_RW(mcu_powersave); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* Battery ********************************************************************/ -+ -+/* The battery maximum charging percentage */ -+static int charge_end_threshold; -+ -+static ssize_t charge_control_end_threshold_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int value, ret, rv; -+ -+ ret = kstrtouint(buf, 10, &value); -+ if (ret) -+ return ret; -+ -+ if (value < 0 || value > 100) -+ return -EINVAL; -+ -+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, value, &rv); -+ if (ret) -+ return ret; -+ -+ if (rv != 1) -+ return -EIO; -+ -+ /* There isn't any method in the DSDT to read the threshold, so we -+ * save the threshold. -+ */ -+ charge_end_threshold = value; -+ return count; -+} -+ -+static ssize_t charge_control_end_threshold_show(struct device *device, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ if ((charge_end_threshold >= 0) && (charge_end_threshold <= 100)) -+ return sysfs_emit(buf, "%d\n", charge_end_threshold); -+ -+ return -ENODATA; -+} -+ -+static DEVICE_ATTR_RW(charge_control_end_threshold); -+ -+static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) -+{ -+ int ret, rv; -+ -+ /* The WMI method does not provide a way to specific a battery, so we -+ * just assume it is the first battery. -+ * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first -+ * battery is named BATT. -+ */ -+ if (strcmp(battery->desc->name, "BAT0") != 0 && -+ strcmp(battery->desc->name, "BAT1") != 0 && -+ strcmp(battery->desc->name, "BATC") != 0 && -+ strcmp(battery->desc->name, "BATT") != 0) -+ return -ENODEV; -+ -+ if (device_create_file(&battery->dev, -+ &dev_attr_charge_control_end_threshold)) -+ return -ENODEV; -+ -+ /* Preserve firmware policy until the user explicitly writes a limit. -+ * The cached sysfs value must not claim an unobserved threshold. -+ */ -+ if (asus_wmi_p16_extended_rsoc()) { -+ charge_end_threshold = -1; -+ return 0; -+ } -+ -+ /* The charge threshold is only reset when the system is power cycled, -+ * and we can't read the current threshold, however the majority of -+ * platforms retains it. -+ * -+ * Setting a negative value would signal the threshold as unknown -+ * until user explicitly sets it to a new value, however to avoid -+ * regressing userspace, we initialize it to a value of 100. -+ */ -+ charge_end_threshold = 100; -+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, charge_end_threshold, &rv); -+ if (ret) { -+ pr_err("Failed to reset battery charge threshold\n"); -+ goto asus_wmi_battery_add_err; -+ } -+ -+ if (rv != 1) { -+ pr_err("Error in battery charge threshold reset\n"); -+ ret = -EIO; -+ goto asus_wmi_battery_add_err; -+ } -+ -+ return 0; -+asus_wmi_battery_add_err: -+ device_remove_file(&battery->dev, -+ &dev_attr_charge_control_end_threshold); -+ return ret; -+} -+ -+static int asus_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) -+{ -+ device_remove_file(&battery->dev, -+ &dev_attr_charge_control_end_threshold); -+ return 0; -+} -+ -+static struct acpi_battery_hook battery_hook = { -+ .add_battery = asus_wmi_battery_add, -+ .remove_battery = asus_wmi_battery_remove, -+ .name = "ASUS Battery Extension", -+}; -+ -+static void asus_wmi_battery_init(struct asus_wmi *asus) -+{ -+ asus->battery_rsoc_available = false; -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_RSOC)) { -+ asus->battery_rsoc_available = true; -+ acpi_battery_hook_register(&battery_hook); -+ } -+} -+ -+static void asus_wmi_battery_exit(struct asus_wmi *asus) -+{ -+ if (asus->battery_rsoc_available) -+ acpi_battery_hook_unregister(&battery_hook); -+} -+ -+/* LEDs ***********************************************************************/ -+ -+struct asus_hid_ref { -+ struct list_head listeners; -+ struct asus_wmi *asus; -+ /* Protects concurrent access from hid-asus and asus-wmi to leds */ -+ spinlock_t lock; -+}; -+ -+static struct asus_hid_ref asus_ref = { -+ .listeners = LIST_HEAD_INIT(asus_ref.listeners), -+ .asus = NULL, -+ /* -+ * Protects .asus, .asus.kbd_led_{wk,notify}, and .listener refs. Other -+ * asus variables are read-only after .asus is set. -+ * -+ * The led cdev device is not protected because it calls backlight_get -+ * during initialization, which would result in a nested lock attempt. -+ * -+ * The led cdev is safe to access without a lock because if -+ * kbd_led_avail is true it is initialized before .asus is set and never -+ * changed until .asus is dropped. If kbd_led_avail is false, the led -+ * cdev is registered by the workqueue, which is single-threaded and -+ * cancelled before asus-wmi would access the led cdev to unregister it. -+ * -+ * A spinlock is used, because the protected variables can be accessed -+ * from an IRQ context from asus-hid. -+ */ -+ .lock = __SPIN_LOCK_UNLOCKED(asus_ref.lock), -+}; -+ -+/* -+ * Allows registering hid-asus listeners that want to be notified of -+ * keyboard backlight changes. -+ */ -+int asus_hid_register_listener(struct asus_hid_listener *bdev) -+{ -+ struct asus_wmi *asus; -+ -+ guard(spinlock_irqsave)(&asus_ref.lock); -+ list_add_tail(&bdev->list, &asus_ref.listeners); -+ asus = asus_ref.asus; -+ if (asus) -+ queue_work(asus->led_workqueue, &asus->kbd_led_work); -+ return 0; -+} -+EXPORT_SYMBOL_GPL(asus_hid_register_listener); -+ -+/* -+ * Allows unregistering hid-asus listeners that were added with -+ * asus_hid_register_listener(). -+ */ -+void asus_hid_unregister_listener(struct asus_hid_listener *bdev) -+{ -+ guard(spinlock_irqsave)(&asus_ref.lock); -+ list_del(&bdev->list); -+} -+EXPORT_SYMBOL_GPL(asus_hid_unregister_listener); -+ -+static void do_kbd_led_set(struct led_classdev *led_cdev, int value); -+ -+static void kbd_led_update_all(struct work_struct *work) -+{ -+ struct asus_wmi *asus; -+ bool registered, notify; -+ int ret, value; -+ -+ asus = container_of(work, struct asus_wmi, kbd_led_work); -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) { -+ registered = asus->kbd_led_registered; -+ value = asus->kbd_led_wk; -+ notify = asus->kbd_led_notify; -+ } -+ -+ if (!registered) { -+ /* -+ * This workqueue runs under asus-wmi, which means probe has -+ * completed and asus-wmi will keep running until it finishes. -+ * Therefore, we can safely register the LED without holding -+ * a spinlock. -+ */ -+ ret = devm_led_classdev_register(&asus->platform_device->dev, -+ &asus->kbd_led); -+ if (!ret) { -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) -+ asus->kbd_led_registered = true; -+ } else { -+ pr_warn("Failed to register keyboard backlight LED: %d\n", ret); -+ return; -+ } -+ } -+ -+ if (value >= 0) -+ do_kbd_led_set(&asus->kbd_led, value); -+ if (notify) { -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) -+ asus->kbd_led_notify = false; -+ led_classdev_notify_brightness_hw_changed(&asus->kbd_led, value); -+ } -+} -+ -+/* -+ * This function is called from hid-asus to inform asus-wmi of brightness -+ * changes initiated by the keyboard backlight keys. -+ */ -+int asus_hid_event(enum asus_hid_event event) -+{ -+ struct asus_wmi *asus; -+ int brightness; -+ -+ guard(spinlock_irqsave)(&asus_ref.lock); -+ asus = asus_ref.asus; -+ if (!asus || !asus->kbd_led_registered) -+ return -EBUSY; -+ -+ brightness = asus->kbd_led_wk; -+ -+ switch (event) { -+ case ASUS_EV_BRTUP: -+ brightness += 1; -+ break; -+ case ASUS_EV_BRTDOWN: -+ brightness -= 1; -+ break; -+ case ASUS_EV_BRTTOGGLE: -+ if (brightness >= ASUS_EV_MAX_BRIGHTNESS) -+ brightness = 0; -+ else -+ brightness += 1; -+ break; -+ } -+ -+ asus->kbd_led_wk = clamp_val(brightness, 0, ASUS_EV_MAX_BRIGHTNESS); -+ asus->kbd_led_notify = true; -+ queue_work(asus->led_workqueue, &asus->kbd_led_work); -+ return 0; -+} -+EXPORT_SYMBOL_GPL(asus_hid_event); -+ -+/* -+ * These functions actually update the LED's, and are called from a -+ * workqueue. By doing this as separate work rather than when the LED -+ * subsystem asks, we avoid messing with the Asus ACPI stuff during a -+ * potentially bad time, such as a timer interrupt. -+ */ -+static void tpd_led_update(struct work_struct *work) -+{ -+ int ctrl_param; -+ struct asus_wmi *asus; -+ -+ asus = container_of(work, struct asus_wmi, tpd_led_work); -+ -+ ctrl_param = asus->tpd_led_wk; -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); -+} -+ -+static void tpd_led_set(struct led_classdev *led_cdev, -+ enum led_brightness value) -+{ -+ struct asus_wmi *asus; -+ -+ asus = container_of(led_cdev, struct asus_wmi, tpd_led); -+ -+ asus->tpd_led_wk = !!value; -+ queue_work(asus->led_workqueue, &asus->tpd_led_work); -+} -+ -+static int read_tpd_led_state(struct asus_wmi *asus) -+{ -+ return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED); -+} -+ -+static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) -+{ -+ struct asus_wmi *asus; -+ -+ asus = container_of(led_cdev, struct asus_wmi, tpd_led); -+ -+ return read_tpd_led_state(asus); -+} -+ -+static void kbd_led_update(struct asus_wmi *asus) -+{ -+ int ctrl_param = 0; -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) -+ ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); -+} -+ -+static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) -+{ -+ int retval; -+ -+ /* -+ * bits 0-2: level -+ * bit 7: light on/off -+ * bit 8-10: environment (0: dark, 1: normal, 2: light) -+ * bit 17: status unknown -+ */ -+ retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT, -+ 0xFFFF); -+ -+ /* Unknown status is considered as off */ -+ if (retval == 0x8000) -+ retval = 0; -+ -+ if (retval < 0) -+ return retval; -+ -+ if (level) -+ *level = retval & 0x7F; -+ if (env) -+ *env = (retval >> 8) & 0x7F; -+ return 0; -+} -+ -+static void do_kbd_led_set(struct led_classdev *led_cdev, int value) -+{ -+ struct asus_hid_listener *listener; -+ struct asus_wmi *asus; -+ -+ asus = container_of(led_cdev, struct asus_wmi, kbd_led); -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) -+ asus->kbd_led_wk = clamp_val(value, 0, ASUS_EV_MAX_BRIGHTNESS); -+ -+ if (asus->kbd_led_avail) -+ kbd_led_update(asus); -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) { -+ list_for_each_entry(listener, &asus_ref.listeners, list) -+ listener->brightness_set(listener, asus->kbd_led_wk); -+ } -+} -+ -+static int kbd_led_set(struct led_classdev *led_cdev, enum led_brightness value) -+{ -+ /* Prevent disabling keyboard backlight on module unregister */ -+ if (led_cdev->flags & LED_UNREGISTERING) -+ return 0; -+ -+ do_kbd_led_set(led_cdev, value); -+ return 0; -+} -+ -+static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value) -+{ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) { -+ asus->kbd_led_wk = value; -+ asus->kbd_led_notify = true; -+ } -+ queue_work(asus->led_workqueue, &asus->kbd_led_work); -+} -+ -+static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) -+{ -+ struct asus_wmi *asus; -+ int retval, value; -+ -+ asus = container_of(led_cdev, struct asus_wmi, kbd_led); -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) { -+ if (!asus->kbd_led_avail) -+ return asus->kbd_led_wk; -+ } -+ -+ retval = kbd_led_read(asus, &value, NULL); -+ if (retval < 0) -+ return retval; -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) -+ asus->kbd_led_wk = value; -+ -+ return value; -+} -+ -+static int wlan_led_unknown_state(struct asus_wmi *asus) -+{ -+ u32 result; -+ -+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); -+ -+ return result & ASUS_WMI_DSTS_UNKNOWN_BIT; -+} -+ -+static void wlan_led_update(struct work_struct *work) -+{ -+ int ctrl_param; -+ struct asus_wmi *asus; -+ -+ asus = container_of(work, struct asus_wmi, wlan_led_work); -+ -+ ctrl_param = asus->wlan_led_wk; -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_WIRELESS_LED, ctrl_param, NULL); -+} -+ -+static void wlan_led_set(struct led_classdev *led_cdev, -+ enum led_brightness value) -+{ -+ struct asus_wmi *asus; -+ -+ asus = container_of(led_cdev, struct asus_wmi, wlan_led); -+ -+ asus->wlan_led_wk = !!value; -+ queue_work(asus->led_workqueue, &asus->wlan_led_work); -+} -+ -+static enum led_brightness wlan_led_get(struct led_classdev *led_cdev) -+{ -+ struct asus_wmi *asus; -+ u32 result; -+ -+ asus = container_of(led_cdev, struct asus_wmi, wlan_led); -+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); -+ -+ return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; -+} -+ -+static void lightbar_led_update(struct work_struct *work) -+{ -+ struct asus_wmi *asus; -+ int ctrl_param; -+ -+ asus = container_of(work, struct asus_wmi, lightbar_led_work); -+ -+ ctrl_param = asus->lightbar_led_wk; -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_LIGHTBAR, ctrl_param, NULL); -+} -+ -+static void lightbar_led_set(struct led_classdev *led_cdev, -+ enum led_brightness value) -+{ -+ struct asus_wmi *asus; -+ -+ asus = container_of(led_cdev, struct asus_wmi, lightbar_led); -+ -+ asus->lightbar_led_wk = !!value; -+ queue_work(asus->led_workqueue, &asus->lightbar_led_work); -+} -+ -+static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev) -+{ -+ struct asus_wmi *asus; -+ u32 result; -+ -+ asus = container_of(led_cdev, struct asus_wmi, lightbar_led); -+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result); -+ -+ return result & ASUS_WMI_DSTS_LIGHTBAR_MASK; -+} -+ -+static int micmute_led_set(struct led_classdev *led_cdev, -+ enum led_brightness brightness) -+{ -+ int state = brightness != LED_OFF; -+ int err; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MICMUTE_LED, state, NULL); -+ return err < 0 ? err : 0; -+} -+ -+static enum led_brightness camera_led_get(struct led_classdev *led_cdev) -+{ -+ struct asus_wmi *asus; -+ u32 result; -+ -+ asus = container_of(led_cdev, struct asus_wmi, camera_led); -+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CAMERA_LED, &result); -+ -+ return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK; -+} -+ -+static int camera_led_set(struct led_classdev *led_cdev, -+ enum led_brightness brightness) -+{ -+ int state = brightness != LED_OFF; -+ int err; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CAMERA_LED, state, NULL); -+ return err < 0 ? err : 0; -+} -+ -+static void asus_wmi_led_exit(struct asus_wmi *asus) -+{ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) -+ asus_ref.asus = NULL; -+ -+ led_classdev_unregister(&asus->tpd_led); -+ led_classdev_unregister(&asus->wlan_led); -+ led_classdev_unregister(&asus->lightbar_led); -+ led_classdev_unregister(&asus->micmute_led); -+ led_classdev_unregister(&asus->camera_led); -+ -+ if (asus->led_workqueue) -+ destroy_workqueue(asus->led_workqueue); -+} -+ -+static int asus_wmi_led_init(struct asus_wmi *asus) -+{ -+ int rv = 0, num_rgb_groups = 0, led_val; -+ -+ if (asus->kbd_rgb_dev) -+ kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group; -+ if (asus->kbd_rgb_state_available) -+ kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_state_group; -+ -+ asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); -+ if (!asus->led_workqueue) -+ return -ENOMEM; -+ -+ if (read_tpd_led_state(asus) >= 0) { -+ INIT_WORK(&asus->tpd_led_work, tpd_led_update); -+ -+ asus->tpd_led.name = "asus::touchpad"; -+ asus->tpd_led.brightness_set = tpd_led_set; -+ asus->tpd_led.brightness_get = tpd_led_get; -+ asus->tpd_led.max_brightness = 1; -+ -+ rv = led_classdev_register(&asus->platform_device->dev, -+ &asus->tpd_led); -+ if (rv) -+ goto error; -+ } -+ -+ asus->kbd_led.name = "asus::kbd_backlight"; -+ asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; -+ asus->kbd_led.brightness_set_blocking = kbd_led_set; -+ asus->kbd_led.brightness_get = kbd_led_get; -+ asus->kbd_led.max_brightness = ASUS_EV_MAX_BRIGHTNESS; -+ asus->kbd_led_avail = !kbd_led_read(asus, &led_val, NULL); -+ INIT_WORK(&asus->kbd_led_work, kbd_led_update_all); -+ -+ if (asus->kbd_led_avail) { -+ asus->kbd_led_wk = led_val; -+ if (num_rgb_groups != 0) -+ asus->kbd_led.groups = kbd_rgb_mode_groups; -+ } else { -+ asus->kbd_led_wk = -1; -+ } -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) { -+ asus_ref.asus = asus; -+ if (asus->kbd_led_avail || !list_empty(&asus_ref.listeners)) -+ queue_work(asus->led_workqueue, &asus->kbd_led_work); -+ } -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_WIRELESS_LED) -+ && (asus->driver->quirks->wapf > 0)) { -+ INIT_WORK(&asus->wlan_led_work, wlan_led_update); -+ -+ asus->wlan_led.name = "asus::wlan"; -+ asus->wlan_led.brightness_set = wlan_led_set; -+ if (!wlan_led_unknown_state(asus)) -+ asus->wlan_led.brightness_get = wlan_led_get; -+ asus->wlan_led.flags = LED_CORE_SUSPENDRESUME; -+ asus->wlan_led.max_brightness = 1; -+ asus->wlan_led.default_trigger = "asus-wlan"; -+ -+ rv = led_classdev_register(&asus->platform_device->dev, -+ &asus->wlan_led); -+ if (rv) -+ goto error; -+ } -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_LIGHTBAR)) { -+ INIT_WORK(&asus->lightbar_led_work, lightbar_led_update); -+ -+ asus->lightbar_led.name = "asus::lightbar"; -+ asus->lightbar_led.brightness_set = lightbar_led_set; -+ asus->lightbar_led.brightness_get = lightbar_led_get; -+ asus->lightbar_led.max_brightness = 1; -+ -+ rv = led_classdev_register(&asus->platform_device->dev, -+ &asus->lightbar_led); -+ } -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MICMUTE_LED)) { -+ asus->micmute_led.name = "platform::micmute"; -+ asus->micmute_led.max_brightness = 1; -+ asus->micmute_led.brightness_set_blocking = micmute_led_set; -+ asus->micmute_led.default_trigger = "audio-micmute"; -+ -+ rv = led_classdev_register(&asus->platform_device->dev, -+ &asus->micmute_led); -+ if (rv) -+ goto error; -+ } -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CAMERA_LED)) { -+ asus->camera_led.name = "asus::camera"; -+ asus->camera_led.max_brightness = 1; -+ asus->camera_led.brightness_get = camera_led_get; -+ asus->camera_led.brightness_set_blocking = camera_led_set; -+ -+ rv = led_classdev_register(&asus->platform_device->dev, -+ &asus->camera_led); -+ if (rv) -+ goto error; -+ } -+ -+ if (asus->oobe_state_available) { -+ /* -+ * Disable OOBE state, so that e.g. the keyboard backlight -+ * works. -+ */ -+ rv = asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL); -+ if (rv) -+ goto error; -+ } -+ -+error: -+ if (rv) -+ asus_wmi_led_exit(asus); -+ -+ return rv; -+} -+ -+/* RF *************************************************************************/ -+ -+/* -+ * PCI hotplug (for wlan rfkill) -+ */ -+static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) -+{ -+ int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); -+ -+ if (result < 0) -+ return false; -+ return !result; -+} -+ -+static void asus_rfkill_hotplug(struct asus_wmi *asus) -+{ -+ struct pci_dev *dev; -+ struct pci_bus *bus; -+ bool blocked; -+ bool absent; -+ u32 l; -+ -+ mutex_lock(&asus->wmi_lock); -+ blocked = asus_wlan_rfkill_blocked(asus); -+ mutex_unlock(&asus->wmi_lock); -+ -+ mutex_lock(&asus->hotplug_lock); -+ pci_lock_rescan_remove(); -+ -+ if (asus->wlan.rfkill) -+ rfkill_set_sw_state(asus->wlan.rfkill, blocked); -+ -+ if (asus->hotplug_slot.ops) { -+ bus = pci_find_bus(0, 1); -+ if (!bus) { -+ pr_warn("Unable to find PCI bus 1?\n"); -+ goto out_unlock; -+ } -+ -+ if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { -+ pr_err("Unable to read PCI config space?\n"); -+ goto out_unlock; -+ } -+ absent = (l == 0xffffffff); -+ -+ if (blocked != absent) { -+ pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n", -+ blocked ? "blocked" : "unblocked", -+ absent ? "absent" : "present"); -+ pr_warn("skipped wireless hotplug as probably inappropriate for this model\n"); -+ goto out_unlock; -+ } -+ -+ if (!blocked) { -+ dev = pci_get_slot(bus, 0); -+ if (dev) { -+ /* Device already present */ -+ pci_dev_put(dev); -+ goto out_unlock; -+ } -+ dev = pci_scan_single_device(bus, 0); -+ if (dev) { -+ pci_bus_assign_resources(bus); -+ pci_bus_add_device(dev); -+ } -+ } else { -+ dev = pci_get_slot(bus, 0); -+ if (dev) { -+ pci_stop_and_remove_bus_device(dev); -+ pci_dev_put(dev); -+ } -+ } -+ } -+ -+out_unlock: -+ pci_unlock_rescan_remove(); -+ mutex_unlock(&asus->hotplug_lock); -+} -+ -+static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data) -+{ -+ struct asus_wmi *asus = data; -+ -+ if (event != ACPI_NOTIFY_BUS_CHECK) -+ return; -+ -+ /* -+ * We can't call directly asus_rfkill_hotplug because most -+ * of the time WMBC is still being executed and not reetrant. -+ * There is currently no way to tell ACPICA that we want this -+ * method to be serialized, we schedule a asus_rfkill_hotplug -+ * call later, in a safer context. -+ */ -+ queue_work(asus->hotplug_workqueue, &asus->hotplug_work); -+} -+ -+static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node) -+{ -+ acpi_status status; -+ acpi_handle handle; -+ -+ status = acpi_get_handle(NULL, node, &handle); -+ if (ACPI_FAILURE(status)) -+ return -ENODEV; -+ -+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, -+ asus_rfkill_notify, asus); -+ if (ACPI_FAILURE(status)) -+ pr_warn("Failed to register notify on %s\n", node); -+ -+ return 0; -+} -+ -+static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) -+{ -+ acpi_status status = AE_OK; -+ acpi_handle handle; -+ -+ status = acpi_get_handle(NULL, node, &handle); -+ if (ACPI_FAILURE(status)) -+ return; -+ -+ status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, -+ asus_rfkill_notify); -+ if (ACPI_FAILURE(status)) -+ pr_err("Error removing rfkill notify handler %s\n", node); -+} -+ -+static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, -+ u8 *value) -+{ -+ struct asus_wmi *asus = container_of(hotplug_slot, -+ struct asus_wmi, hotplug_slot); -+ int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); -+ -+ if (result < 0) -+ return result; -+ -+ *value = !!result; -+ return 0; -+} -+ -+static const struct hotplug_slot_ops asus_hotplug_slot_ops = { -+ .get_adapter_status = asus_get_adapter_status, -+ .get_power_status = asus_get_adapter_status, -+}; -+ -+static void asus_hotplug_work(struct work_struct *work) -+{ -+ struct asus_wmi *asus; -+ -+ asus = container_of(work, struct asus_wmi, hotplug_work); -+ asus_rfkill_hotplug(asus); -+} -+ -+static int asus_setup_pci_hotplug(struct asus_wmi *asus) -+{ -+ int ret = -ENOMEM; -+ struct pci_bus *bus = pci_find_bus(0, 1); -+ -+ if (!bus) { -+ pr_err("Unable to find wifi PCI bus\n"); -+ return -ENODEV; -+ } -+ -+ asus->hotplug_workqueue = -+ create_singlethread_workqueue("hotplug_workqueue"); -+ if (!asus->hotplug_workqueue) -+ goto error_workqueue; -+ -+ INIT_WORK(&asus->hotplug_work, asus_hotplug_work); -+ -+ asus->hotplug_slot.ops = &asus_hotplug_slot_ops; -+ -+ ret = pci_hp_register(&asus->hotplug_slot, bus, 0, "asus-wifi"); -+ if (ret) { -+ pr_err("Unable to register hotplug slot - %d\n", ret); -+ goto error_register; -+ } -+ -+ return 0; -+ -+error_register: -+ asus->hotplug_slot.ops = NULL; -+ destroy_workqueue(asus->hotplug_workqueue); -+error_workqueue: -+ return ret; -+} -+ -+/* -+ * Rfkill devices -+ */ -+static int asus_rfkill_set(void *data, bool blocked) -+{ -+ struct asus_rfkill *priv = data; -+ u32 ctrl_param = !blocked; -+ u32 dev_id = priv->dev_id; -+ -+ /* -+ * If the user bit is set, BIOS can't set and record the wlan status, -+ * it will report the value read from id ASUS_WMI_DEVID_WLAN_LED -+ * while we query the wlan status through WMI(ASUS_WMI_DEVID_WLAN). -+ * So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED -+ * while setting the wlan status through WMI. -+ * This is also the behavior that windows app will do. -+ */ -+ if ((dev_id == ASUS_WMI_DEVID_WLAN) && -+ priv->asus->driver->wlan_ctrl_by_user) -+ dev_id = ASUS_WMI_DEVID_WLAN_LED; -+ -+ return asus_wmi_set_devstate(dev_id, ctrl_param, NULL); -+} -+ -+static void asus_rfkill_query(struct rfkill *rfkill, void *data) -+{ -+ struct asus_rfkill *priv = data; -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id); -+ -+ if (result < 0) -+ return; -+ -+ rfkill_set_sw_state(priv->rfkill, !result); -+} -+ -+static int asus_rfkill_wlan_set(void *data, bool blocked) -+{ -+ struct asus_rfkill *priv = data; -+ struct asus_wmi *asus = priv->asus; -+ int ret; -+ -+ /* -+ * This handler is enabled only if hotplug is enabled. -+ * In this case, the asus_wmi_set_devstate() will -+ * trigger a wmi notification and we need to wait -+ * this call to finish before being able to call -+ * any wmi method -+ */ -+ mutex_lock(&asus->wmi_lock); -+ ret = asus_rfkill_set(data, blocked); -+ mutex_unlock(&asus->wmi_lock); -+ return ret; -+} -+ -+static const struct rfkill_ops asus_rfkill_wlan_ops = { -+ .set_block = asus_rfkill_wlan_set, -+ .query = asus_rfkill_query, -+}; -+ -+static const struct rfkill_ops asus_rfkill_ops = { -+ .set_block = asus_rfkill_set, -+ .query = asus_rfkill_query, -+}; -+ -+static int asus_new_rfkill(struct asus_wmi *asus, -+ struct asus_rfkill *arfkill, -+ const char *name, enum rfkill_type type, int dev_id) -+{ -+ int result = asus_wmi_get_devstate_simple(asus, dev_id); -+ struct rfkill **rfkill = &arfkill->rfkill; -+ -+ if (result < 0) -+ return result; -+ -+ arfkill->dev_id = dev_id; -+ arfkill->asus = asus; -+ -+ if (dev_id == ASUS_WMI_DEVID_WLAN && -+ asus->driver->quirks->hotplug_wireless) -+ *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, -+ &asus_rfkill_wlan_ops, arfkill); -+ else -+ *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, -+ &asus_rfkill_ops, arfkill); -+ -+ if (!*rfkill) -+ return -EINVAL; -+ -+ if ((dev_id == ASUS_WMI_DEVID_WLAN) && -+ (asus->driver->quirks->wapf > 0)) -+ rfkill_set_led_trigger_name(*rfkill, "asus-wlan"); -+ -+ rfkill_init_sw_state(*rfkill, !result); -+ result = rfkill_register(*rfkill); -+ if (result) { -+ rfkill_destroy(*rfkill); -+ *rfkill = NULL; -+ return result; -+ } -+ return 0; -+} -+ -+static void asus_wmi_rfkill_exit(struct asus_wmi *asus) -+{ -+ if (asus->driver->wlan_ctrl_by_user && ashs_present()) -+ return; -+ -+ asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); -+ asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); -+ asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); -+ if (asus->wlan.rfkill) { -+ rfkill_unregister(asus->wlan.rfkill); -+ rfkill_destroy(asus->wlan.rfkill); -+ asus->wlan.rfkill = NULL; -+ } -+ /* -+ * Refresh pci hotplug in case the rfkill state was changed after -+ * asus_unregister_rfkill_notifier() -+ */ -+ asus_rfkill_hotplug(asus); -+ if (asus->hotplug_slot.ops) -+ pci_hp_deregister(&asus->hotplug_slot); -+ if (asus->hotplug_workqueue) -+ destroy_workqueue(asus->hotplug_workqueue); -+ -+ if (asus->bluetooth.rfkill) { -+ rfkill_unregister(asus->bluetooth.rfkill); -+ rfkill_destroy(asus->bluetooth.rfkill); -+ asus->bluetooth.rfkill = NULL; -+ } -+ if (asus->wimax.rfkill) { -+ rfkill_unregister(asus->wimax.rfkill); -+ rfkill_destroy(asus->wimax.rfkill); -+ asus->wimax.rfkill = NULL; -+ } -+ if (asus->wwan3g.rfkill) { -+ rfkill_unregister(asus->wwan3g.rfkill); -+ rfkill_destroy(asus->wwan3g.rfkill); -+ asus->wwan3g.rfkill = NULL; -+ } -+ if (asus->gps.rfkill) { -+ rfkill_unregister(asus->gps.rfkill); -+ rfkill_destroy(asus->gps.rfkill); -+ asus->gps.rfkill = NULL; -+ } -+ if (asus->uwb.rfkill) { -+ rfkill_unregister(asus->uwb.rfkill); -+ rfkill_destroy(asus->uwb.rfkill); -+ asus->uwb.rfkill = NULL; -+ } -+} -+ -+static int asus_wmi_rfkill_init(struct asus_wmi *asus) -+{ -+ int result = 0; -+ -+ mutex_init(&asus->hotplug_lock); -+ mutex_init(&asus->wmi_lock); -+ -+ result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan", -+ RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN); -+ -+ if (result && result != -ENODEV) -+ goto exit; -+ -+ result = asus_new_rfkill(asus, &asus->bluetooth, -+ "asus-bluetooth", RFKILL_TYPE_BLUETOOTH, -+ ASUS_WMI_DEVID_BLUETOOTH); -+ -+ if (result && result != -ENODEV) -+ goto exit; -+ -+ result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax", -+ RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX); -+ -+ if (result && result != -ENODEV) -+ goto exit; -+ -+ result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g", -+ RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G); -+ -+ if (result && result != -ENODEV) -+ goto exit; -+ -+ result = asus_new_rfkill(asus, &asus->gps, "asus-gps", -+ RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS); -+ -+ if (result && result != -ENODEV) -+ goto exit; -+ -+ result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb", -+ RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB); -+ -+ if (result && result != -ENODEV) -+ goto exit; -+ -+ if (!asus->driver->quirks->hotplug_wireless) -+ goto exit; -+ -+ result = asus_setup_pci_hotplug(asus); -+ /* -+ * If we get -EBUSY then something else is handling the PCI hotplug - -+ * don't fail in this case -+ */ -+ if (result == -EBUSY) -+ result = 0; -+ -+ asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); -+ asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); -+ asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); -+ /* -+ * Refresh pci hotplug in case the rfkill state was changed during -+ * setup. -+ */ -+ asus_rfkill_hotplug(asus); -+ -+exit: -+ if (result && result != -ENODEV) -+ asus_wmi_rfkill_exit(asus); -+ -+ if (result == -ENODEV) -+ result = 0; -+ -+ return result; -+} -+ -+/* Panel Overdrive ************************************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t panel_od_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_PANEL_OD); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", result); -+} -+ -+static ssize_t panel_od_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 overdrive; -+ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ result = kstrtou32(buf, 10, &overdrive); -+ if (result) -+ return result; -+ -+ if (overdrive > 1) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, overdrive, &result); -+ -+ if (err) { -+ pr_warn("Failed to set panel overdrive: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set panel overdrive (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od"); -+ -+ return count; -+} -+static DEVICE_ATTR_RW(panel_od); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* Bootup sound ***************************************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t boot_sound_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int result; -+ -+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BOOT_SOUND); -+ if (result < 0) -+ return result; -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", result); -+} -+ -+static ssize_t boot_sound_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 snd; -+ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ result = kstrtou32(buf, 10, &snd); -+ if (result) -+ return result; -+ -+ if (snd > 1) -+ return -EINVAL; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BOOT_SOUND, snd, &result); -+ if (err) { -+ pr_warn("Failed to set boot sound: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set panel boot sound (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "boot_sound"); -+ -+ return count; -+} -+static DEVICE_ATTR_RW(boot_sound); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* Mini-LED mode **************************************************************/ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t mini_led_mode_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ u32 value; -+ int err; -+ -+ err = asus_wmi_get_devstate(asus, asus->mini_led_dev_id, &value); -+ if (err < 0) -+ return err; -+ value = value & ASUS_MINI_LED_MODE_MASK; -+ -+ /* -+ * Remap the mode values to match previous generation mini-led. The last gen -+ * WMI 0 == off, while on this version WMI 2 ==off (flipped). -+ */ -+ if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -+ switch (value) { -+ case ASUS_MINI_LED_2024_WEAK: -+ value = ASUS_MINI_LED_ON; -+ break; -+ case ASUS_MINI_LED_2024_STRONG: -+ value = ASUS_MINI_LED_STRONG_MODE; -+ break; -+ case ASUS_MINI_LED_2024_OFF: -+ value = ASUS_MINI_LED_OFF; -+ break; -+ } -+ } -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "%d\n", value); -+} -+ -+static ssize_t mini_led_mode_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 mode; -+ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ result = kstrtou32(buf, 10, &mode); -+ if (result) -+ return result; -+ -+ if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE && -+ mode > ASUS_MINI_LED_ON) -+ return -EINVAL; -+ if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 && -+ mode > ASUS_MINI_LED_STRONG_MODE) -+ return -EINVAL; -+ -+ /* -+ * Remap the mode values so expected behaviour is the same as the last -+ * generation of mini-LED with 0 == off, 1 == on. -+ */ -+ if (asus->mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) { -+ switch (mode) { -+ case ASUS_MINI_LED_OFF: -+ mode = ASUS_MINI_LED_2024_OFF; -+ break; -+ case ASUS_MINI_LED_ON: -+ mode = ASUS_MINI_LED_2024_WEAK; -+ break; -+ case ASUS_MINI_LED_STRONG_MODE: -+ mode = ASUS_MINI_LED_2024_STRONG; -+ break; -+ } -+ } -+ -+ err = asus_wmi_set_devstate(asus->mini_led_dev_id, mode, &result); -+ if (err) { -+ pr_warn("Failed to set mini-LED: %d\n", err); -+ return err; -+ } -+ -+ if (result > 1) { -+ pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result); -+ return -EIO; -+ } -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mini_led_mode"); -+ -+ return count; -+} -+static DEVICE_ATTR_RW(mini_led_mode); -+ -+static ssize_t available_mini_led_mode_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ switch (asus->mini_led_dev_id) { -+ case ASUS_WMI_DEVID_MINI_LED_MODE: -+ return sysfs_emit(buf, "0 1\n"); -+ case ASUS_WMI_DEVID_MINI_LED_MODE2: -+ return sysfs_emit(buf, "0 1 2\n"); -+ } -+ -+ asus_wmi_show_deprecated(); -+ -+ return sysfs_emit(buf, "0\n"); -+} -+ -+static DEVICE_ATTR_RO(available_mini_led_mode); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* Quirks *********************************************************************/ -+ -+static void asus_wmi_set_xusb2pr(struct asus_wmi *asus) -+{ -+ struct pci_dev *xhci_pdev; -+ u32 orig_ports_available; -+ u32 ports_available = asus->driver->quirks->xusb2pr; -+ -+ xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, -+ PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI, -+ NULL); -+ -+ if (!xhci_pdev) -+ return; -+ -+ pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, -+ &orig_ports_available); -+ -+ pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, -+ cpu_to_le32(ports_available)); -+ -+ pci_dev_put(xhci_pdev); -+ -+ pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n", -+ orig_ports_available, ports_available); -+} -+ -+/* -+ * Some devices dont support or have borcken get_als method -+ * but still support set method. -+ */ -+static void asus_wmi_set_als(void) -+{ -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL); -+} -+ -+/* Hwmon device ***************************************************************/ -+ -+static int asus_agfn_fan_speed_read(struct asus_wmi *asus, int fan, -+ int *speed) -+{ -+ struct agfn_fan_args args = { -+ .agfn.len = sizeof(args), -+ .agfn.mfun = ASUS_FAN_MFUN, -+ .agfn.sfun = ASUS_FAN_SFUN_READ, -+ .fan = fan, -+ .speed = 0, -+ }; -+ struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -+ int status; -+ -+ if (fan != 1) -+ return -EINVAL; -+ -+ status = asus_wmi_evaluate_method_agfn(input); -+ -+ if (status || args.agfn.err) -+ return -ENXIO; -+ -+ if (speed) -+ *speed = args.speed; -+ -+ return 0; -+} -+ -+static int asus_agfn_fan_speed_write(struct asus_wmi *asus, int fan, -+ int *speed) -+{ -+ struct agfn_fan_args args = { -+ .agfn.len = sizeof(args), -+ .agfn.mfun = ASUS_FAN_MFUN, -+ .agfn.sfun = ASUS_FAN_SFUN_WRITE, -+ .fan = fan, -+ .speed = speed ? *speed : 0, -+ }; -+ struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -+ int status; -+ -+ /* 1: for setting 1st fan's speed 0: setting auto mode */ -+ if (fan != 1 && fan != 0) -+ return -EINVAL; -+ -+ status = asus_wmi_evaluate_method_agfn(input); -+ -+ if (status || args.agfn.err) -+ return -ENXIO; -+ -+ if (speed && fan == 1) -+ asus->agfn_pwm = *speed; -+ -+ return 0; -+} -+ -+/* -+ * Check if we can read the speed of one fan. If true we assume we can also -+ * control it. -+ */ -+static bool asus_wmi_has_agfn_fan(struct asus_wmi *asus) -+{ -+ int status; -+ int speed; -+ u32 value; -+ -+ status = asus_agfn_fan_speed_read(asus, 1, &speed); -+ if (status != 0) -+ return false; -+ -+ status = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); -+ if (status != 0) -+ return false; -+ -+ /* -+ * We need to find a better way, probably using sfun, -+ * bits or spec ... -+ * Currently we disable it if: -+ * - ASUS_WMI_UNSUPPORTED_METHOD is returned -+ * - reverved bits are non-zero -+ * - sfun and presence bit are not set -+ */ -+ return !(value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 -+ || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))); -+} -+ -+static int asus_fan_set_auto(struct asus_wmi *asus) -+{ -+ int status; -+ u32 retval; -+ -+ switch (asus->fan_type) { -+ case FAN_TYPE_SPEC83: -+ status = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL, -+ 0, &retval); -+ if (status) -+ return status; -+ -+ if (retval != 1) -+ return -EIO; -+ break; -+ -+ case FAN_TYPE_AGFN: -+ status = asus_agfn_fan_speed_write(asus, 0, NULL); -+ if (status) -+ return -ENXIO; -+ break; -+ -+ default: -+ return -ENXIO; -+ } -+ -+ /* -+ * Modern models like the G713 also have GPU fan control (this is not AGFN) -+ */ -+ if (asus->gpu_fan_type == FAN_TYPE_SPEC83) { -+ status = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL, -+ 0, &retval); -+ if (status) -+ return status; -+ -+ if (retval != 1) -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static ssize_t pwm1_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int err; -+ int value; -+ -+ /* If we already set a value then just return it */ -+ if (asus->agfn_pwm >= 0) -+ return sysfs_emit(buf, "%d\n", asus->agfn_pwm); -+ -+ /* -+ * If we haven't set already set a value through the AGFN interface, -+ * we read a current value through the (now-deprecated) FAN_CTRL device. -+ */ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); -+ if (err < 0) -+ return err; -+ -+ value &= 0xFF; -+ -+ if (value == 1) /* Low Speed */ -+ value = 85; -+ else if (value == 2) -+ value = 170; -+ else if (value == 3) -+ value = 255; -+ else if (value) { -+ pr_err("Unknown fan speed %#x\n", value); -+ value = -1; -+ } -+ -+ return sysfs_emit(buf, "%d\n", value); -+} -+ -+static ssize_t pwm1_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) { -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int value; -+ int state; -+ int ret; -+ -+ ret = kstrtouint(buf, 10, &value); -+ if (ret) -+ return ret; -+ -+ value = clamp(value, 0, 255); -+ -+ state = asus_agfn_fan_speed_write(asus, 1, &value); -+ if (state) -+ pr_warn("Setting fan speed failed: %d\n", state); -+ else -+ asus->fan_pwm_mode = ASUS_FAN_CTRL_MANUAL; -+ -+ return count; -+} -+ -+static ssize_t fan1_input_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int value; -+ int ret; -+ -+ switch (asus->fan_type) { -+ case FAN_TYPE_SPEC83: -+ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL, -+ &value); -+ if (ret < 0) -+ return ret; -+ -+ value &= 0xffff; -+ break; -+ -+ case FAN_TYPE_AGFN: -+ /* no speed readable on manual mode */ -+ if (asus->fan_pwm_mode == ASUS_FAN_CTRL_MANUAL) -+ return -ENXIO; -+ -+ ret = asus_agfn_fan_speed_read(asus, 1, &value); -+ if (ret) { -+ pr_warn("reading fan speed failed: %d\n", ret); -+ return -ENXIO; -+ } -+ break; -+ -+ default: -+ return -ENXIO; -+ } -+ -+ return sysfs_emit(buf, "%d\n", value < 0 ? -1 : value * 100); -+} -+ -+static ssize_t pwm1_enable_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ /* -+ * Just read back the cached pwm mode. -+ * -+ * For the CPU_FAN device, the spec indicates that we should be -+ * able to read the device status and consult bit 19 to see if we -+ * are in Full On or Automatic mode. However, this does not work -+ * in practice on X532FL at least (the bit is always 0) and there's -+ * also nothing in the DSDT to indicate that this behaviour exists. -+ */ -+ return sysfs_emit(buf, "%d\n", asus->fan_pwm_mode); -+} -+ -+static ssize_t pwm1_enable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int status = 0; -+ int state; -+ int value; -+ int ret; -+ u32 retval; -+ -+ ret = kstrtouint(buf, 10, &state); -+ if (ret) -+ return ret; -+ -+ if (asus->fan_type == FAN_TYPE_SPEC83) { -+ switch (state) { /* standard documented hwmon values */ -+ case ASUS_FAN_CTRL_FULLSPEED: -+ value = 1; -+ break; -+ case ASUS_FAN_CTRL_AUTO: -+ value = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL, -+ value, &retval); -+ if (ret) -+ return ret; -+ -+ if (retval != 1) -+ return -EIO; -+ } else if (asus->fan_type == FAN_TYPE_AGFN) { -+ switch (state) { -+ case ASUS_FAN_CTRL_MANUAL: -+ break; -+ -+ case ASUS_FAN_CTRL_AUTO: -+ status = asus_fan_set_auto(asus); -+ if (status) -+ return status; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ asus->fan_pwm_mode = state; -+ -+ /* Must set to disabled if mode is toggled */ -+ if (asus->cpu_fan_curve_available) -+ asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; -+ if (asus->gpu_fan_curve_available) -+ asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; -+ if (asus->mid_fan_curve_available) -+ asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false; -+ -+ return count; -+} -+ -+static ssize_t asus_hwmon_temp1(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ u32 value; -+ int err; -+ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value); -+ if (err < 0) -+ return err; -+ -+ return sysfs_emit(buf, "%ld\n", -+ deci_kelvin_to_millicelsius(value & 0xFFFF)); -+} -+ -+/* GPU fan on modern ROG laptops */ -+static ssize_t fan2_input_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int value; -+ int ret; -+ -+ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL, &value); -+ if (ret < 0) -+ return ret; -+ -+ value &= 0xffff; -+ -+ return sysfs_emit(buf, "%d\n", value * 100); -+} -+ -+/* Middle/Center fan on modern ROG laptops */ -+static ssize_t fan3_input_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int value; -+ int ret; -+ -+ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_MID_FAN_CTRL, &value); -+ if (ret < 0) -+ return ret; -+ -+ value &= 0xffff; -+ -+ return sysfs_emit(buf, "%d\n", value * 100); -+} -+ -+static ssize_t pwm2_enable_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ return sysfs_emit(buf, "%d\n", asus->gpu_fan_pwm_mode); -+} -+ -+static ssize_t pwm2_enable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int state; -+ int value; -+ int ret; -+ u32 retval; -+ -+ ret = kstrtouint(buf, 10, &state); -+ if (ret) -+ return ret; -+ -+ switch (state) { /* standard documented hwmon values */ -+ case ASUS_FAN_CTRL_FULLSPEED: -+ value = 1; -+ break; -+ case ASUS_FAN_CTRL_AUTO: -+ value = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL, -+ value, &retval); -+ if (ret) -+ return ret; -+ -+ if (retval != 1) -+ return -EIO; -+ -+ asus->gpu_fan_pwm_mode = state; -+ return count; -+} -+ -+static ssize_t pwm3_enable_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ return sysfs_emit(buf, "%d\n", asus->mid_fan_pwm_mode); -+} -+ -+static ssize_t pwm3_enable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ int state; -+ int value; -+ int ret; -+ u32 retval; -+ -+ ret = kstrtouint(buf, 10, &state); -+ if (ret) -+ return ret; -+ -+ switch (state) { /* standard documented hwmon values */ -+ case ASUS_FAN_CTRL_FULLSPEED: -+ value = 1; -+ break; -+ case ASUS_FAN_CTRL_AUTO: -+ value = 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_MID_FAN_CTRL, -+ value, &retval); -+ if (ret) -+ return ret; -+ -+ if (retval != 1) -+ return -EIO; -+ -+ asus->mid_fan_pwm_mode = state; -+ return count; -+} -+ -+/* Fan1 */ -+static DEVICE_ATTR_RW(pwm1); -+static DEVICE_ATTR_RW(pwm1_enable); -+static DEVICE_ATTR_RO(fan1_input); -+static DEVICE_STRING_ATTR_RO(fan1_label, 0444, ASUS_FAN_DESC); -+ -+/* Fan2 - GPU fan */ -+static DEVICE_ATTR_RW(pwm2_enable); -+static DEVICE_ATTR_RO(fan2_input); -+static DEVICE_STRING_ATTR_RO(fan2_label, 0444, ASUS_GPU_FAN_DESC); -+/* Fan3 - Middle/center fan */ -+static DEVICE_ATTR_RW(pwm3_enable); -+static DEVICE_ATTR_RO(fan3_input); -+static DEVICE_STRING_ATTR_RO(fan3_label, 0444, ASUS_MID_FAN_DESC); -+ -+/* Temperature */ -+static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL); -+ -+static struct attribute *hwmon_attributes[] = { -+ &dev_attr_pwm1.attr, -+ &dev_attr_pwm1_enable.attr, -+ &dev_attr_pwm2_enable.attr, -+ &dev_attr_pwm3_enable.attr, -+ &dev_attr_fan1_input.attr, -+ &dev_attr_fan1_label.attr.attr, -+ &dev_attr_fan2_input.attr, -+ &dev_attr_fan2_label.attr.attr, -+ &dev_attr_fan3_input.attr, -+ &dev_attr_fan3_label.attr.attr, -+ -+ &dev_attr_temp1_input.attr, -+ NULL -+}; -+ -+static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, -+ struct attribute *attr, int idx) -+{ -+ struct device *dev = kobj_to_dev(kobj); -+ struct asus_wmi *asus = dev_get_drvdata(dev->parent); -+ u32 value = ASUS_WMI_UNSUPPORTED_METHOD; -+ -+ if (attr == &dev_attr_pwm1.attr) { -+ if (asus->fan_type != FAN_TYPE_AGFN) -+ return 0; -+ } else if (attr == &dev_attr_fan1_input.attr -+ || attr == &dev_attr_fan1_label.attr.attr -+ || attr == &dev_attr_pwm1_enable.attr) { -+ if (asus->fan_type == FAN_TYPE_NONE) -+ return 0; -+ } else if (attr == &dev_attr_fan2_input.attr -+ || attr == &dev_attr_fan2_label.attr.attr -+ || attr == &dev_attr_pwm2_enable.attr) { -+ if (asus->gpu_fan_type == FAN_TYPE_NONE) -+ return 0; -+ } else if (attr == &dev_attr_fan3_input.attr -+ || attr == &dev_attr_fan3_label.attr.attr -+ || attr == &dev_attr_pwm3_enable.attr) { -+ if (asus->mid_fan_type == FAN_TYPE_NONE) -+ return 0; -+ } else if (attr == &dev_attr_temp1_input.attr) { -+ int err = asus_wmi_get_devstate(asus, -+ ASUS_WMI_DEVID_THERMAL_CTRL, -+ &value); -+ -+ if (err < 0) -+ return 0; /* can't return negative here */ -+ -+ /* -+ * If the temperature value in deci-Kelvin is near the absolute -+ * zero temperature, something is clearly wrong -+ */ -+ if (value == 0 || value == 1) -+ return 0; -+ } -+ -+ return attr->mode; -+} -+ -+static const struct attribute_group hwmon_attribute_group = { -+ .is_visible = asus_hwmon_sysfs_is_visible, -+ .attrs = hwmon_attributes -+}; -+__ATTRIBUTE_GROUPS(hwmon_attribute); -+ -+static int asus_wmi_hwmon_init(struct asus_wmi *asus) -+{ -+ struct device *dev = &asus->platform_device->dev; -+ struct device *hwmon; -+ -+ hwmon = devm_hwmon_device_register_with_groups(dev, "asus", asus, -+ hwmon_attribute_groups); -+ -+ if (IS_ERR(hwmon)) { -+ pr_err("Could not register asus hwmon device\n"); -+ return PTR_ERR(hwmon); -+ } -+ return 0; -+} -+ -+static int asus_wmi_fan_init(struct asus_wmi *asus) -+{ -+ asus->gpu_fan_type = FAN_TYPE_NONE; -+ asus->mid_fan_type = FAN_TYPE_NONE; -+ asus->fan_type = FAN_TYPE_NONE; -+ asus->agfn_pwm = -1; -+ -+ if (asus->driver->quirks->wmi_ignore_fan) -+ asus->fan_type = FAN_TYPE_NONE; -+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL)) -+ asus->fan_type = FAN_TYPE_SPEC83; -+ else if (asus_wmi_has_agfn_fan(asus)) -+ asus->fan_type = FAN_TYPE_AGFN; -+ -+ /* Modern models like G713 also have GPU fan control */ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL)) -+ asus->gpu_fan_type = FAN_TYPE_SPEC83; -+ -+ /* Some models also have a center/middle fan */ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MID_FAN_CTRL)) -+ asus->mid_fan_type = FAN_TYPE_SPEC83; -+ -+ if (asus->fan_type == FAN_TYPE_NONE) -+ return -ENODEV; -+ -+ asus_fan_set_auto(asus); -+ asus->fan_pwm_mode = ASUS_FAN_CTRL_AUTO; -+ return 0; -+} -+ -+/* Fan mode *******************************************************************/ -+ -+static int fan_boost_mode_check_present(struct asus_wmi *asus) -+{ -+ u32 result; -+ int err; -+ -+ asus->fan_boost_mode_available = false; -+ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_BOOST_MODE, -+ &result); -+ if (err) { -+ if (err == -ENODEV) -+ return 0; -+ else -+ return err; -+ } -+ -+ if ((result & ASUS_WMI_DSTS_PRESENCE_BIT) && -+ (result & ASUS_FAN_BOOST_MODES_MASK)) { -+ asus->fan_boost_mode_available = true; -+ asus->fan_boost_mode_mask = result & ASUS_FAN_BOOST_MODES_MASK; -+ } -+ -+ return 0; -+} -+ -+static int fan_boost_mode_write(struct asus_wmi *asus) -+{ -+ u32 retval; -+ u8 value; -+ int err; -+ -+ value = asus->fan_boost_mode; -+ -+ pr_info("Set fan boost mode: %u\n", value); -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_BOOST_MODE, value, -+ &retval); -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, -+ "fan_boost_mode"); -+ -+ if (err) { -+ pr_warn("Failed to set fan boost mode: %d\n", err); -+ return err; -+ } -+ -+ if (retval != 1) { -+ pr_warn("Failed to set fan boost mode (retval): 0x%x\n", -+ retval); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int fan_boost_mode_switch_next(struct asus_wmi *asus) -+{ -+ u8 mask = asus->fan_boost_mode_mask; -+ -+ if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_NORMAL) { -+ if (mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK) -+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_OVERBOOST; -+ else if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK) -+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT; -+ } else if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) { -+ if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK) -+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT; -+ else -+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL; -+ } else { -+ asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL; -+ } -+ -+ return fan_boost_mode_write(asus); -+} -+ -+static ssize_t fan_boost_mode_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ -+ return sysfs_emit(buf, "%d\n", asus->fan_boost_mode); -+} -+ -+static ssize_t fan_boost_mode_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ u8 mask = asus->fan_boost_mode_mask; -+ u8 new_mode; -+ int result; -+ -+ result = kstrtou8(buf, 10, &new_mode); -+ if (result < 0) { -+ pr_warn("Trying to store invalid value\n"); -+ return result; -+ } -+ -+ if (new_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) { -+ if (!(mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK)) -+ return -EINVAL; -+ } else if (new_mode == ASUS_FAN_BOOST_MODE_SILENT) { -+ if (!(mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)) -+ return -EINVAL; -+ } else if (new_mode != ASUS_FAN_BOOST_MODE_NORMAL) { -+ return -EINVAL; -+ } -+ -+ asus->fan_boost_mode = new_mode; -+ fan_boost_mode_write(asus); -+ -+ return count; -+} -+ -+// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent -+static DEVICE_ATTR_RW(fan_boost_mode); -+ -+/* Custom fan curves **********************************************************/ -+ -+static void fan_curve_copy_from_buf(struct fan_curve_data *data, u8 *buf) -+{ -+ int i; -+ -+ for (i = 0; i < FAN_CURVE_POINTS; i++) { -+ data->temps[i] = buf[i]; -+ } -+ -+ for (i = 0; i < FAN_CURVE_POINTS; i++) { -+ data->percents[i] = -+ 255 * buf[i + FAN_CURVE_POINTS] / 100; -+ } -+} -+ -+static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) -+{ -+ struct fan_curve_data *curves; -+ u8 buf[FAN_CURVE_BUF_LEN]; -+ int err, fan_idx; -+ u8 mode = 0; -+ -+ if (asus->throttle_thermal_policy_dev) -+ mode = asus->throttle_thermal_policy_mode; -+ /* DEVID_PU_FAN_CURVE is switched for OVERBOOST vs SILENT */ -+ if (mode == 2) -+ mode = 1; -+ else if (mode == 1) -+ mode = 2; -+ -+ err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf, -+ FAN_CURVE_BUF_LEN); -+ if (err) { -+ pr_warn("%s (0x%08x) failed: %d\n", __func__, fan_dev, err); -+ return err; -+ } -+ -+ fan_idx = FAN_CURVE_DEV_CPU; -+ if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE) -+ fan_idx = FAN_CURVE_DEV_GPU; -+ -+ if (fan_dev == ASUS_WMI_DEVID_MID_FAN_CURVE) -+ fan_idx = FAN_CURVE_DEV_MID; -+ -+ curves = &asus->custom_fan_curves[fan_idx]; -+ curves->device_id = fan_dev; -+ -+ fan_curve_copy_from_buf(curves, buf); -+ return 0; -+} -+ -+/* Check if capability exists, and populate defaults */ -+static int fan_curve_check_present(struct asus_wmi *asus, bool *available, -+ u32 fan_dev) -+{ -+ int err; -+ -+ *available = false; -+ -+ if (asus->fan_type == FAN_TYPE_NONE) -+ return 0; -+ -+ err = fan_curve_get_factory_default(asus, fan_dev); -+ if (err) { -+ return 0; -+ } -+ -+ *available = true; -+ return 0; -+} -+ -+/* Determine which fan the attribute is for if SENSOR_ATTR */ -+static struct fan_curve_data *fan_curve_attr_select(struct asus_wmi *asus, -+ struct device_attribute *attr) -+{ -+ int index = to_sensor_dev_attr(attr)->index; -+ -+ return &asus->custom_fan_curves[index]; -+} -+ -+/* Determine which fan the attribute is for if SENSOR_ATTR_2 */ -+static struct fan_curve_data *fan_curve_attr_2_select(struct asus_wmi *asus, -+ struct device_attribute *attr) -+{ -+ int nr = to_sensor_dev_attr_2(attr)->nr; -+ -+ return &asus->custom_fan_curves[nr & ~FAN_CURVE_PWM_MASK]; -+} -+ -+static ssize_t fan_curve_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ struct fan_curve_data *data; -+ int value, pwm, index; -+ -+ data = fan_curve_attr_2_select(asus, attr); -+ pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; -+ index = dev_attr->index; -+ -+ if (pwm) -+ value = data->percents[index]; -+ else -+ value = data->temps[index]; -+ -+ return sysfs_emit(buf, "%d\n", value); -+} -+ -+/* -+ * "fan_dev" is the related WMI method such as ASUS_WMI_DEVID_CPU_FAN_CURVE. -+ */ -+static int fan_curve_write(struct asus_wmi *asus, -+ struct fan_curve_data *data) -+{ -+ u32 arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0; -+ u8 *percents = data->percents; -+ u8 *temps = data->temps; -+ int ret, i, shift = 0; -+ -+ if (!data->enabled) -+ return 0; -+ -+ for (i = 0; i < FAN_CURVE_POINTS / 2; i++) { -+ arg1 += (temps[i]) << shift; -+ arg2 += (temps[i + 4]) << shift; -+ /* Scale to percentage for device */ -+ arg3 += (100 * percents[i] / 255) << shift; -+ arg4 += (100 * percents[i + 4] / 255) << shift; -+ shift += 8; -+ } -+ -+ return asus_wmi_evaluate_method5(ASUS_WMI_METHODID_DEVS, -+ data->device_id, -+ arg1, arg2, arg3, arg4, &ret); -+} -+ -+static ssize_t fan_curve_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, -+ size_t count) -+{ -+ struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ struct fan_curve_data *data; -+ int err, pwm, index; -+ u8 value; -+ -+ data = fan_curve_attr_2_select(asus, attr); -+ pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; -+ index = dev_attr->index; -+ -+ err = kstrtou8(buf, 10, &value); -+ if (err < 0) -+ return err; -+ -+ if (pwm) -+ data->percents[index] = value; -+ else -+ data->temps[index] = value; -+ -+ /* -+ * Mark as disabled so the user has to explicitly enable to apply a -+ * changed fan curve. This prevents potential lockups from writing out -+ * many changes as one-write-per-change. -+ */ -+ data->enabled = false; -+ -+ return count; -+} -+ -+static ssize_t fan_curve_enable_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ struct fan_curve_data *data; -+ int out = 2; -+ -+ data = fan_curve_attr_select(asus, attr); -+ -+ if (data->enabled) -+ out = 1; -+ -+ return sysfs_emit(buf, "%d\n", out); -+} -+ -+static ssize_t fan_curve_enable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ struct fan_curve_data *data; -+ int value, err; -+ -+ data = fan_curve_attr_select(asus, attr); -+ -+ err = kstrtoint(buf, 10, &value); -+ if (err < 0) -+ return err; -+ -+ switch (value) { -+ case 1: -+ data->enabled = true; -+ break; -+ case 2: -+ data->enabled = false; -+ break; -+ /* -+ * Auto + reset the fan curve data to defaults. Make it an explicit -+ * option so that users don't accidentally overwrite a set fan curve. -+ */ -+ case 3: -+ err = fan_curve_get_factory_default(asus, data->device_id); -+ if (err) -+ return err; -+ data->enabled = false; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (data->enabled) { -+ err = fan_curve_write(asus, data); -+ if (err) -+ return err; -+ } else { -+ /* -+ * For machines with throttle this is the only way to reset fans -+ * to default mode of operation (does not erase curve data). -+ */ -+ if (asus->throttle_thermal_policy_dev) { -+ err = throttle_thermal_policy_write(asus); -+ if (err) -+ return err; -+ /* Similar is true for laptops with this fan */ -+ } else if (asus->fan_type == FAN_TYPE_SPEC83) { -+ err = asus_fan_set_auto(asus); -+ if (err) -+ return err; -+ } else { -+ /* Safeguard against fautly ACPI tables */ -+ err = fan_curve_get_factory_default(asus, data->device_id); -+ if (err) -+ return err; -+ err = fan_curve_write(asus, data); -+ if (err) -+ return err; -+ } -+ } -+ return count; -+} -+ -+/* CPU */ -+static SENSOR_DEVICE_ATTR_RW(pwm1_enable, fan_curve_enable, FAN_CURVE_DEV_CPU); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 0); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 1); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 2); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 3); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 4); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 5); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 6); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_temp, fan_curve, -+ FAN_CURVE_DEV_CPU, 7); -+ -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 0); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 1); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 2); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point4_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 3); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point5_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 4); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point6_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 5); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point7_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 6); -+static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_pwm, fan_curve, -+ FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 7); -+ -+/* GPU */ -+static SENSOR_DEVICE_ATTR_RW(pwm2_enable, fan_curve_enable, FAN_CURVE_DEV_GPU); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 0); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 1); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 2); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 3); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 4); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 5); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 6); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_temp, fan_curve, -+ FAN_CURVE_DEV_GPU, 7); -+ -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point1_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 0); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point2_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 1); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point3_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 2); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point4_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 3); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point5_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 4); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point6_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 5); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 6); -+static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_pwm, fan_curve, -+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7); -+ -+/* MID */ -+static SENSOR_DEVICE_ATTR_RW(pwm3_enable, fan_curve_enable, FAN_CURVE_DEV_MID); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 0); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 1); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 2); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 3); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 4); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 5); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 6); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_temp, fan_curve, -+ FAN_CURVE_DEV_MID, 7); -+ -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 0); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 1); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 2); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 3); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 4); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 5); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 6); -+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_pwm, fan_curve, -+ FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 7); -+ -+static struct attribute *asus_fan_curve_attr[] = { -+ /* CPU */ -+ &sensor_dev_attr_pwm1_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, -+ /* GPU */ -+ &sensor_dev_attr_pwm2_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point6_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point7_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point8_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr, -+ /* MID */ -+ &sensor_dev_attr_pwm3_enable.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point6_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point7_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point8_temp.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point6_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point7_pwm.dev_attr.attr, -+ &sensor_dev_attr_pwm3_auto_point8_pwm.dev_attr.attr, -+ NULL -+}; -+ -+static umode_t asus_fan_curve_is_visible(struct kobject *kobj, -+ struct attribute *attr, int idx) -+{ -+ struct device *dev = kobj_to_dev(kobj); -+ struct asus_wmi *asus = dev_get_drvdata(dev->parent); -+ -+ /* -+ * Check the char instead of casting attr as there are two attr types -+ * involved here (attr1 and attr2) -+ */ -+ if (asus->cpu_fan_curve_available && attr->name[3] == '1') -+ return 0644; -+ -+ if (asus->gpu_fan_curve_available && attr->name[3] == '2') -+ return 0644; -+ -+ if (asus->mid_fan_curve_available && attr->name[3] == '3') -+ return 0644; -+ -+ return 0; -+} -+ -+static const struct attribute_group asus_fan_curve_attr_group = { -+ .is_visible = asus_fan_curve_is_visible, -+ .attrs = asus_fan_curve_attr, -+}; -+__ATTRIBUTE_GROUPS(asus_fan_curve_attr); -+ -+/* -+ * Must be initialised after throttle_thermal_policy_dev is set as -+ * we check the status of throttle_thermal_policy_dev during init. -+ */ -+static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) -+{ -+ struct device *dev = &asus->platform_device->dev; -+ struct device *hwmon; -+ int err; -+ -+ err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available, -+ ASUS_WMI_DEVID_CPU_FAN_CURVE); -+ if (err) { -+ pr_debug("%s, checked 0x%08x, failed: %d\n", -+ __func__, ASUS_WMI_DEVID_CPU_FAN_CURVE, err); -+ return err; -+ } -+ -+ err = fan_curve_check_present(asus, &asus->gpu_fan_curve_available, -+ ASUS_WMI_DEVID_GPU_FAN_CURVE); -+ if (err) { -+ pr_debug("%s, checked 0x%08x, failed: %d\n", -+ __func__, ASUS_WMI_DEVID_GPU_FAN_CURVE, err); -+ return err; -+ } -+ -+ err = fan_curve_check_present(asus, &asus->mid_fan_curve_available, -+ ASUS_WMI_DEVID_MID_FAN_CURVE); -+ if (err) { -+ pr_debug("%s, checked 0x%08x, failed: %d\n", -+ __func__, ASUS_WMI_DEVID_MID_FAN_CURVE, err); -+ return err; -+ } -+ -+ if (!asus->cpu_fan_curve_available -+ && !asus->gpu_fan_curve_available -+ && !asus->mid_fan_curve_available) -+ return 0; -+ -+ hwmon = devm_hwmon_device_register_with_groups( -+ dev, "asus_custom_fan_curve", asus, asus_fan_curve_attr_groups); -+ -+ if (IS_ERR(hwmon)) { -+ dev_err(dev, -+ "Could not register asus_custom_fan_curve device\n"); -+ return PTR_ERR(hwmon); -+ } -+ -+ return 0; -+} -+ -+/* -+ * Returns true if at least one custom fan curve is active -+ * -+ * Used by asus-armoury to check if PPT writes will be accepted by the BIOS -+ * on models that require an active fan curve for TDP changes. -+ */ -+bool asus_wmi_custom_fan_curve_is_enabled(void) -+{ -+ struct fan_curve_data *curves; -+ struct asus_wmi *asus; -+ -+ guard(spinlock_irqsave)(&asus_ref.lock); -+ asus = asus_ref.asus; -+ if (!asus) -+ return false; -+ -+ curves = asus->custom_fan_curves; -+ -+ return (asus->cpu_fan_curve_available && curves[FAN_CURVE_DEV_CPU].enabled) || -+ (asus->gpu_fan_curve_available && curves[FAN_CURVE_DEV_GPU].enabled) || -+ (asus->mid_fan_curve_available && curves[FAN_CURVE_DEV_MID].enabled); -+} -+EXPORT_SYMBOL_NS_GPL(asus_wmi_custom_fan_curve_is_enabled, "ASUS_WMI"); -+ -+/* Throttle thermal policy ****************************************************/ -+static int throttle_thermal_policy_write(struct asus_wmi *asus) -+{ -+ u8 value; -+ int err; -+ -+ if (asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO) { -+ switch (asus->throttle_thermal_policy_mode) { -+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: -+ value = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; -+ break; -+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: -+ value = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; -+ break; -+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT: -+ value = ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } else { -+ value = asus->throttle_thermal_policy_mode; -+ } -+ -+ /* Some machines do not return an error code as a result, so we ignore it */ -+ err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, value, NULL); -+ -+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, -+ "throttle_thermal_policy"); -+ -+ if (err) { -+ pr_warn("Failed to set throttle thermal policy: %d\n", err); -+ return err; -+ } -+ -+ /* Must set to disabled if mode is toggled */ -+ if (asus->cpu_fan_curve_available) -+ asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; -+ if (asus->gpu_fan_curve_available) -+ asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; -+ if (asus->mid_fan_curve_available) -+ asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false; -+ -+ return 0; -+} -+ -+static int throttle_thermal_policy_set_default(struct asus_wmi *asus) -+{ -+ if (!asus->throttle_thermal_policy_dev) -+ return 0; -+ -+ asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -+ return throttle_thermal_policy_write(asus); -+} -+ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+static ssize_t throttle_thermal_policy_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ u8 mode = asus->throttle_thermal_policy_mode; -+ -+ return sysfs_emit(buf, "%d\n", mode); -+} -+ -+static ssize_t throttle_thermal_policy_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ u8 new_mode; -+ int result; -+ int err; -+ -+ result = kstrtou8(buf, 10, &new_mode); -+ if (result < 0) -+ return result; -+ -+ if (new_mode > PLATFORM_PROFILE_MAX) -+ return -EINVAL; -+ -+ asus->throttle_thermal_policy_mode = new_mode; -+ err = throttle_thermal_policy_write(asus); -+ if (err) -+ return err; -+ -+ /* -+ * Ensure that platform_profile updates userspace with the change to ensure -+ * that platform_profile and throttle_thermal_policy_mode are in sync. -+ */ -+ platform_profile_notify(asus->ppdev); -+ -+ return count; -+} -+ -+/* -+ * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent -+ */ -+static DEVICE_ATTR_RW(throttle_thermal_policy); -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+/* Platform profile ***********************************************************/ -+static int asus_wmi_platform_profile_get(struct device *dev, -+ enum platform_profile_option *profile) -+{ -+ struct asus_wmi *asus; -+ int tp; -+ -+ asus = dev_get_drvdata(dev); -+ tp = asus->throttle_thermal_policy_mode; -+ -+ switch (tp) { -+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: -+ *profile = PLATFORM_PROFILE_BALANCED; -+ break; -+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: -+ *profile = PLATFORM_PROFILE_PERFORMANCE; -+ break; -+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT: -+ *profile = PLATFORM_PROFILE_QUIET; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int asus_wmi_platform_profile_set(struct device *dev, -+ enum platform_profile_option profile) -+{ -+ struct asus_wmi *asus; -+ int tp; -+ -+ asus = dev_get_drvdata(dev); -+ -+ switch (profile) { -+ case PLATFORM_PROFILE_PERFORMANCE: -+ tp = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST; -+ break; -+ case PLATFORM_PROFILE_BALANCED: -+ tp = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; -+ break; -+ case PLATFORM_PROFILE_QUIET: -+ tp = ASUS_THROTTLE_THERMAL_POLICY_SILENT; -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ asus->throttle_thermal_policy_mode = tp; -+ return throttle_thermal_policy_write(asus); -+} -+ -+static int asus_wmi_platform_profile_probe(void *drvdata, unsigned long *choices) -+{ -+ set_bit(PLATFORM_PROFILE_QUIET, choices); -+ set_bit(PLATFORM_PROFILE_BALANCED, choices); -+ set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); -+ -+ return 0; -+} -+ -+static const struct platform_profile_ops asus_wmi_platform_profile_ops = { -+ .probe = asus_wmi_platform_profile_probe, -+ .profile_get = asus_wmi_platform_profile_get, -+ .profile_set = asus_wmi_platform_profile_set, -+}; -+ -+static int platform_profile_setup(struct asus_wmi *asus) -+{ -+ struct device *dev = &asus->platform_device->dev; -+ int err; -+ -+ /* -+ * Not an error if a component platform_profile relies on is unavailable -+ * so early return, skipping the setup of platform_profile. -+ */ -+ if (!asus->throttle_thermal_policy_dev) -+ return 0; -+ -+ /* -+ * We need to set the default thermal profile during probe or otherwise -+ * the system will often remain in silent mode, causing low performance. -+ */ -+ err = throttle_thermal_policy_set_default(asus); -+ if (err < 0) { -+ pr_warn("Failed to set default thermal profile\n"); -+ return err; -+ } -+ -+ dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n"); -+ -+ asus->ppdev = devm_platform_profile_register(dev, "asus-wmi", asus, -+ &asus_wmi_platform_profile_ops); -+ if (IS_ERR(asus->ppdev)) { -+ dev_err(dev, "Failed to register a platform_profile class device\n"); -+ return PTR_ERR(asus->ppdev); -+ } -+ -+ asus->platform_profile_support = true; -+ return 0; -+} -+ -+/* Backlight ******************************************************************/ -+ -+static int read_backlight_power(struct asus_wmi *asus) -+{ -+ int ret; -+ -+ if (asus->driver->quirks->store_backlight_power) -+ ret = !asus->driver->panel_power; -+ else -+ ret = asus_wmi_get_devstate_simple(asus, -+ ASUS_WMI_DEVID_BACKLIGHT); -+ -+ if (ret < 0) -+ return ret; -+ -+ return ret ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; -+} -+ -+static int read_brightness_max(struct asus_wmi *asus) -+{ -+ u32 retval; -+ int err; -+ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); -+ if (err < 0) -+ return err; -+ -+ retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK; -+ retval >>= 8; -+ -+ if (!retval) -+ return -ENODEV; -+ -+ return retval; -+} -+ -+static int read_brightness(struct backlight_device *bd) -+{ -+ struct asus_wmi *asus = bl_get_data(bd); -+ u32 retval; -+ int err; -+ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); -+ if (err < 0) -+ return err; -+ -+ return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; -+} -+ -+static u32 get_scalar_command(struct backlight_device *bd) -+{ -+ struct asus_wmi *asus = bl_get_data(bd); -+ u32 ctrl_param = 0; -+ -+ if ((asus->driver->brightness < bd->props.brightness) || -+ bd->props.brightness == bd->props.max_brightness) -+ ctrl_param = 0x00008001; -+ else if ((asus->driver->brightness > bd->props.brightness) || -+ bd->props.brightness == 0) -+ ctrl_param = 0x00008000; -+ -+ asus->driver->brightness = bd->props.brightness; -+ -+ return ctrl_param; -+} -+ -+static int update_bl_status(struct backlight_device *bd) -+{ -+ struct asus_wmi *asus = bl_get_data(bd); -+ u32 ctrl_param; -+ int power, err = 0; -+ -+ power = read_backlight_power(asus); -+ if (power != -ENODEV && bd->props.power != power) { -+ ctrl_param = !!(bd->props.power == BACKLIGHT_POWER_ON); -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, -+ ctrl_param, NULL); -+ if (asus->driver->quirks->store_backlight_power) -+ asus->driver->panel_power = bd->props.power; -+ -+ /* When using scalar brightness, updating the brightness -+ * will mess with the backlight power */ -+ if (asus->driver->quirks->scalar_panel_brightness) -+ return err; -+ } -+ -+ if (asus->driver->quirks->scalar_panel_brightness) -+ ctrl_param = get_scalar_command(bd); -+ else -+ ctrl_param = bd->props.brightness; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, -+ ctrl_param, NULL); -+ -+ return err; -+} -+ -+static const struct backlight_ops asus_wmi_bl_ops = { -+ .get_brightness = read_brightness, -+ .update_status = update_bl_status, -+}; -+ -+static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code) -+{ -+ struct backlight_device *bd = asus->backlight_device; -+ int old = bd->props.brightness; -+ int new = old; -+ -+ if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) -+ new = code - NOTIFY_BRNUP_MIN + 1; -+ else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) -+ new = code - NOTIFY_BRNDOWN_MIN; -+ -+ bd->props.brightness = new; -+ backlight_update_status(bd); -+ backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); -+ -+ return old; -+} -+ -+static int asus_wmi_backlight_init(struct asus_wmi *asus) -+{ -+ struct backlight_device *bd; -+ struct backlight_properties props; -+ int max; -+ int power; -+ -+ max = read_brightness_max(asus); -+ if (max < 0) -+ return max; -+ -+ power = read_backlight_power(asus); -+ if (power == -ENODEV) -+ power = BACKLIGHT_POWER_ON; -+ else if (power < 0) -+ return power; -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.type = BACKLIGHT_PLATFORM; -+ props.max_brightness = max; -+ bd = backlight_device_register(asus->driver->name, -+ &asus->platform_device->dev, asus, -+ &asus_wmi_bl_ops, &props); -+ if (IS_ERR(bd)) { -+ pr_err("Could not register backlight device\n"); -+ return PTR_ERR(bd); -+ } -+ -+ asus->backlight_device = bd; -+ -+ if (asus->driver->quirks->store_backlight_power) -+ asus->driver->panel_power = power; -+ -+ bd->props.brightness = read_brightness(bd); -+ bd->props.power = power; -+ backlight_update_status(bd); -+ -+ asus->driver->brightness = bd->props.brightness; -+ -+ return 0; -+} -+ -+static void asus_wmi_backlight_exit(struct asus_wmi *asus) -+{ -+ backlight_device_unregister(asus->backlight_device); -+ -+ asus->backlight_device = NULL; -+} -+ -+static int is_display_toggle(int code) -+{ -+ /* display toggle keys */ -+ if ((code >= 0x61 && code <= 0x67) || -+ (code >= 0x8c && code <= 0x93) || -+ (code >= 0xa0 && code <= 0xa7) || -+ (code >= 0xd0 && code <= 0xd5)) -+ return 1; -+ -+ return 0; -+} -+ -+/* Screenpad backlight *******************************************************/ -+ -+static int read_screenpad_backlight_power(struct asus_wmi *asus) -+{ -+ int ret; -+ -+ ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); -+ if (ret < 0) -+ return ret; -+ /* 1 == powered */ -+ return ret ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF; -+} -+ -+static int read_screenpad_brightness(struct backlight_device *bd) -+{ -+ struct asus_wmi *asus = bl_get_data(bd); -+ u32 retval; -+ int err; -+ -+ err = read_screenpad_backlight_power(asus); -+ if (err < 0) -+ return err; -+ /* The device brightness can only be read if powered, so return stored */ -+ if (err == BACKLIGHT_POWER_OFF) -+ return bd->props.brightness; -+ -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); -+ if (err < 0) -+ return err; -+ -+ return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; -+} -+ -+static int update_screenpad_bl_status(struct backlight_device *bd) -+{ -+ u32 ctrl_param = bd->props.brightness; -+ int err = 0; -+ -+ if (bd->props.power) { -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 1, NULL); -+ if (err < 0) -+ return err; -+ -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); -+ if (err < 0) -+ return err; -+ } -+ -+ if (!bd->props.power) { -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); -+ if (err < 0) -+ return err; -+ } -+ -+ return err; -+} -+ -+static const struct backlight_ops asus_screenpad_bl_ops = { -+ .get_brightness = read_screenpad_brightness, -+ .update_status = update_screenpad_bl_status, -+ .options = BL_CORE_SUSPENDRESUME, -+}; -+ -+static int asus_screenpad_init(struct asus_wmi *asus) -+{ -+ struct backlight_device *bd; -+ struct backlight_properties props; -+ int err, power; -+ int brightness = 0; -+ -+ power = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); -+ if (power < 0) -+ return power; -+ -+ if (power) { -+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); -+ if (err < 0) -+ return err; -+ } -+ -+ memset(&props, 0, sizeof(struct backlight_properties)); -+ props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ -+ props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX; -+ bd = backlight_device_register("asus_screenpad", -+ &asus->platform_device->dev, asus, -+ &asus_screenpad_bl_ops, &props); -+ if (IS_ERR(bd)) { -+ pr_err("Could not register backlight device\n"); -+ return PTR_ERR(bd); -+ } -+ -+ asus->screenpad_backlight_device = bd; -+ asus->driver->screenpad_brightness = brightness; -+ bd->props.brightness = brightness; -+ bd->props.power = power; -+ backlight_update_status(bd); -+ -+ return 0; -+} -+ -+static void asus_screenpad_exit(struct asus_wmi *asus) -+{ -+ backlight_device_unregister(asus->screenpad_backlight_device); -+ -+ asus->screenpad_backlight_device = NULL; -+} -+ -+/* Fn-lock ********************************************************************/ -+ -+static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus) -+{ -+ u32 result; -+ -+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result); -+ -+ return (result & ASUS_WMI_DSTS_PRESENCE_BIT) && -+ !(result & ASUS_WMI_FNLOCK_BIOS_DISABLED); -+} -+ -+static void asus_wmi_fnlock_update(struct asus_wmi *asus) -+{ -+ int mode = asus->fnlock_locked; -+ -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL); -+} -+ -+/* WMI events *****************************************************************/ -+ -+static int asus_wmi_get_event_code(union acpi_object *obj) -+{ -+ int code; -+ -+ if (obj && obj->type == ACPI_TYPE_INTEGER) -+ code = (int)(obj->integer.value & WMI_EVENT_MASK); -+ else -+ code = -EIO; -+ -+ return code; -+} -+ -+static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) -+{ -+ enum led_brightness led_value; -+ unsigned int key_value = 1; -+ bool autorelease = 1; -+ -+ if (asus->driver->key_filter) { -+ asus->driver->key_filter(asus->driver, &code, &key_value, -+ &autorelease); -+ if (code == ASUS_WMI_KEY_IGNORE) -+ return; -+ } -+ -+ if (acpi_video_get_backlight_type() == acpi_backlight_vendor && -+ code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNDOWN_MAX) { -+ asus_wmi_backlight_notify(asus, code); -+ return; -+ } -+ -+ scoped_guard(spinlock_irqsave, &asus_ref.lock) -+ led_value = asus->kbd_led_wk; -+ -+ if (code == NOTIFY_KBD_BRTUP) { -+ kbd_led_set_by_kbd(asus, led_value + 1); -+ return; -+ } -+ if (code == NOTIFY_KBD_BRTDWN) { -+ kbd_led_set_by_kbd(asus, led_value - 1); -+ return; -+ } -+ if (code == NOTIFY_KBD_BRTTOGGLE) { -+ if (led_value >= ASUS_EV_MAX_BRIGHTNESS) -+ kbd_led_set_by_kbd(asus, 0); -+ else -+ kbd_led_set_by_kbd(asus, led_value + 1); -+ return; -+ } -+ -+ if (code == NOTIFY_FNLOCK_TOGGLE) { -+ asus->fnlock_locked = !asus->fnlock_locked; -+ asus_wmi_fnlock_update(asus); -+ return; -+ } -+ -+ if (code == asus->tablet_switch_event_code) { -+ asus_wmi_tablet_mode_get_state(asus); -+ return; -+ } -+ -+ if (code == NOTIFY_KEYSTONE) { -+ if (asus->keystone_available) -+ asus_wmi_keystone_notify(asus); -+ return; -+ } -+ -+ if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) { -+ if (asus->fan_boost_mode_available) -+ fan_boost_mode_switch_next(asus); -+ if (asus->throttle_thermal_policy_dev) -+ platform_profile_cycle(); -+ return; -+ -+ } -+ -+ if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle) -+ return; -+ -+ if (!sparse_keymap_report_event(asus->inputdev, code, -+ key_value, autorelease)) -+ pr_info("Unknown key code 0x%x\n", code); -+} -+ -+static void asus_wmi_notify(union acpi_object *obj, void *context) -+{ -+ struct asus_wmi *asus = context; -+ int code = asus_wmi_get_event_code(obj); -+ -+ if (code < 0) { -+ pr_warn("Failed to get notify code: %d\n", code); -+ return; -+ } -+ -+ asus_wmi_handle_event_code(code, asus); -+} -+ -+/* Sysfs **********************************************************************/ -+ -+static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, -+ const char *buf, size_t count) -+{ -+ u32 retval; -+ int err, value; -+ -+ value = asus_wmi_get_devstate_simple(asus, devid); -+ if (value < 0) -+ return value; -+ -+ err = kstrtoint(buf, 0, &value); -+ if (err) -+ return err; -+ -+ err = asus_wmi_set_devstate(devid, value, &retval); -+ if (err < 0) -+ return err; -+ -+ return count; -+} -+ -+static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) -+{ -+ int value = asus_wmi_get_devstate_simple(asus, devid); -+ -+ if (value < 0) -+ return value; -+ -+ return sysfs_emit(buf, "%d\n", value); -+} -+ -+#define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ -+ static ssize_t show_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ char *buf) \ -+ { \ -+ struct asus_wmi *asus = dev_get_drvdata(dev); \ -+ \ -+ return show_sys_wmi(asus, _cm, buf); \ -+ } \ -+ static ssize_t store_##_name(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ struct asus_wmi *asus = dev_get_drvdata(dev); \ -+ \ -+ return store_sys_wmi(asus, _cm, buf, count); \ -+ } \ -+ static struct device_attribute dev_attr_##_name = { \ -+ .attr = { \ -+ .name = __stringify(_name), \ -+ .mode = _mode }, \ -+ .show = show_##_name, \ -+ .store = store_##_name, \ -+ } -+ -+ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); -+ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); -+ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); -+ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME); -+ASUS_WMI_CREATE_DEVICE_ATTR(als_enable, 0644, ASUS_WMI_DEVID_ALS_ENABLE); -+ -+static ssize_t cpufv_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int value, rv; -+ -+ rv = kstrtoint(buf, 0, &value); -+ if (rv) -+ return rv; -+ -+ if (value < 0 || value > 2) -+ return -EINVAL; -+ -+ rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); -+ if (rv < 0) -+ return rv; -+ -+ return count; -+} -+ -+static DEVICE_ATTR_WO(cpufv); -+ -+static struct attribute *platform_attributes[] = { -+ &dev_attr_cpufv.attr, -+ &dev_attr_camera.attr, -+ &dev_attr_cardr.attr, -+ &dev_attr_touchpad.attr, -+ &dev_attr_lid_resume.attr, -+ &dev_attr_als_enable.attr, -+ &dev_attr_fan_boost_mode.attr, -+ &dev_attr_keystone.attr, -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+ &dev_attr_charge_mode.attr, -+ &dev_attr_egpu_enable.attr, -+ &dev_attr_egpu_connected.attr, -+ &dev_attr_dgpu_disable.attr, -+ &dev_attr_gpu_mux_mode.attr, -+ &dev_attr_ppt_pl2_sppt.attr, -+ &dev_attr_ppt_pl1_spl.attr, -+ &dev_attr_ppt_fppt.attr, -+ &dev_attr_ppt_apu_sppt.attr, -+ &dev_attr_ppt_platform_sppt.attr, -+ &dev_attr_nv_dynamic_boost.attr, -+ &dev_attr_nv_temp_target.attr, -+ &dev_attr_mcu_powersave.attr, -+ &dev_attr_boot_sound.attr, -+ &dev_attr_panel_od.attr, -+ &dev_attr_mini_led_mode.attr, -+ &dev_attr_available_mini_led_mode.attr, -+ &dev_attr_throttle_thermal_policy.attr, -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ NULL -+}; -+ -+static umode_t asus_sysfs_is_visible(struct kobject *kobj, -+ struct attribute *attr, int idx) -+{ -+ struct device *dev = kobj_to_dev(kobj); -+ struct asus_wmi *asus = dev_get_drvdata(dev); -+ bool ok = true; -+ int devid = -1; -+ -+ if (attr == &dev_attr_camera.attr) -+ devid = ASUS_WMI_DEVID_CAMERA; -+ else if (attr == &dev_attr_cardr.attr) -+ devid = ASUS_WMI_DEVID_CARDREADER; -+ else if (attr == &dev_attr_touchpad.attr) -+ devid = ASUS_WMI_DEVID_TOUCHPAD; -+ else if (attr == &dev_attr_lid_resume.attr) -+ devid = ASUS_WMI_DEVID_LID_RESUME; -+ else if (attr == &dev_attr_als_enable.attr) -+ devid = ASUS_WMI_DEVID_ALS_ENABLE; -+ else if (attr == &dev_attr_fan_boost_mode.attr) -+ ok = asus->fan_boost_mode_available; -+ else if (attr == &dev_attr_keystone.attr) -+ ok = asus->keystone_available; -+ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+ if (attr == &dev_attr_charge_mode.attr) -+ devid = ASUS_WMI_DEVID_CHARGE_MODE; -+ else if (attr == &dev_attr_egpu_enable.attr) -+ ok = asus->egpu_enable_available; -+ else if (attr == &dev_attr_egpu_connected.attr) -+ devid = ASUS_WMI_DEVID_EGPU_CONNECTED; -+ else if (attr == &dev_attr_dgpu_disable.attr) -+ ok = asus->dgpu_disable_available; -+ else if (attr == &dev_attr_gpu_mux_mode.attr) -+ ok = asus->gpu_mux_dev != 0; -+ else if (attr == &dev_attr_fan_boost_mode.attr) -+ ok = asus->fan_boost_mode_available; -+ else if (attr == &dev_attr_throttle_thermal_policy.attr) -+ ok = asus->throttle_thermal_policy_dev != 0; -+ else if (attr == &dev_attr_ppt_pl2_sppt.attr) -+ devid = ASUS_WMI_DEVID_PPT_PL2_SPPT; -+ else if (attr == &dev_attr_ppt_pl1_spl.attr) -+ devid = ASUS_WMI_DEVID_PPT_PL1_SPL; -+ else if (attr == &dev_attr_ppt_fppt.attr) -+ devid = ASUS_WMI_DEVID_PPT_PL3_FPPT; -+ else if (attr == &dev_attr_ppt_apu_sppt.attr) -+ devid = ASUS_WMI_DEVID_PPT_APU_SPPT; -+ else if (attr == &dev_attr_ppt_platform_sppt.attr) -+ devid = ASUS_WMI_DEVID_PPT_PLAT_SPPT; -+ else if (attr == &dev_attr_nv_dynamic_boost.attr) -+ devid = ASUS_WMI_DEVID_NV_DYN_BOOST; -+ else if (attr == &dev_attr_nv_temp_target.attr) -+ devid = ASUS_WMI_DEVID_NV_THERM_TARGET; -+ else if (attr == &dev_attr_mcu_powersave.attr) -+ devid = ASUS_WMI_DEVID_MCU_POWERSAVE; -+ else if (attr == &dev_attr_boot_sound.attr) -+ devid = ASUS_WMI_DEVID_BOOT_SOUND; -+ else if (attr == &dev_attr_panel_od.attr) -+ devid = ASUS_WMI_DEVID_PANEL_OD; -+ else if (attr == &dev_attr_mini_led_mode.attr) -+ ok = asus->mini_led_dev_id != 0; -+ else if (attr == &dev_attr_available_mini_led_mode.attr) -+ ok = asus->mini_led_dev_id != 0; -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+ if (devid != -1) { -+ ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); -+ pr_debug("%s called 0x%08x, ok: %x\n", __func__, devid, ok); -+ } -+ -+ return ok ? attr->mode : 0; -+} -+ -+static const struct attribute_group platform_attribute_group = { -+ .is_visible = asus_sysfs_is_visible, -+ .attrs = platform_attributes -+}; -+ -+static void asus_wmi_sysfs_exit(struct platform_device *device) -+{ -+ sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); -+} -+ -+static int asus_wmi_sysfs_init(struct platform_device *device) -+{ -+ return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); -+} -+ -+/* Platform device ************************************************************/ -+ -+static int asus_wmi_platform_init(struct asus_wmi *asus) -+{ -+ struct device *dev = &asus->platform_device->dev; -+ char *wmi_uid; -+ int rv; -+ -+ /* INIT enable hotkeys on some models */ -+ if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv)) -+ pr_info("Initialization: %#x\n", rv); -+ -+ /* We don't know yet what to do with this version... */ -+ if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { -+ pr_info("BIOS WMI version: %d.%d\n", rv >> 16, rv & 0xFF); -+ asus->spec = rv; -+ } -+ -+ /* -+ * The SFUN method probably allows the original driver to get the list -+ * of features supported by a given model. For now, 0x0100 or 0x0800 -+ * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. -+ * The significance of others is yet to be found. -+ */ -+ if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) { -+ pr_info("SFUN value: %#x\n", rv); -+ asus->sfun = rv; -+ } -+ -+ /* -+ * Eee PC and Notebooks seems to have different method_id for DSTS, -+ * but it may also be related to the BIOS's SPEC. -+ * Note, on most Eeepc, there is no way to check if a method exist -+ * or note, while on notebooks, they returns 0xFFFFFFFE on failure, -+ * but once again, SPEC may probably be used for that kind of things. -+ * -+ * Additionally at least TUF Gaming series laptops return nothing for -+ * unknown methods, so the detection in this way is not possible. -+ * -+ * There is strong indication that only ACPI WMI devices that have _UID -+ * equal to "ASUSWMI" use DCTS whereas those with "ATK" use DSTS. -+ */ -+ wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); -+ if (!wmi_uid) -+ return -ENODEV; -+ -+ if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) { -+ dev_info(dev, "Detected ASUSWMI, use DCTS\n"); -+ asus->dsts_id = ASUS_WMI_METHODID_DCTS; -+ } else { -+ dev_info(dev, "Detected %s, not ASUSWMI, use DSTS\n", wmi_uid); -+ asus->dsts_id = ASUS_WMI_METHODID_DSTS; -+ } -+ -+ /* CWAP allow to define the behavior of the Fn+F2 key, -+ * this method doesn't seems to be present on Eee PCs */ -+ if (asus->driver->quirks->wapf >= 0) -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP, -+ asus->driver->quirks->wapf, NULL); -+ -+ return 0; -+} -+ -+/* debugfs ********************************************************************/ -+ -+struct asus_wmi_debugfs_node { -+ struct asus_wmi *asus; -+ char *name; -+ int (*show) (struct seq_file *m, void *data); -+}; -+ -+static int show_dsts(struct seq_file *m, void *data) -+{ -+ struct asus_wmi *asus = m->private; -+ int err; -+ u32 retval = -1; -+ -+ err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); -+ if (err < 0) -+ return err; -+ -+ seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval); -+ -+ return 0; -+} -+ -+static int show_devs(struct seq_file *m, void *data) -+{ -+ struct asus_wmi *asus = m->private; -+ int err; -+ u32 retval = -1; -+ -+ err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, -+ &retval); -+ if (err < 0) -+ return err; -+ -+ seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id, -+ asus->debug.ctrl_param, retval); -+ -+ return 0; -+} -+ -+static int show_call(struct seq_file *m, void *data) -+{ -+ struct asus_wmi *asus = m->private; -+ struct bios_args args = { -+ .arg0 = asus->debug.dev_id, -+ .arg1 = asus->debug.ctrl_param, -+ }; -+ struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; -+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; -+ union acpi_object *obj; -+ acpi_status status; -+ -+ status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, -+ 0, asus->debug.method_id, -+ &input, &output); -+ -+ if (ACPI_FAILURE(status)) -+ return -EIO; -+ -+ obj = (union acpi_object *)output.pointer; -+ if (obj && obj->type == ACPI_TYPE_INTEGER) -+ seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id, -+ asus->debug.dev_id, asus->debug.ctrl_param, -+ (u32) obj->integer.value); -+ else -+ seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id, -+ asus->debug.dev_id, asus->debug.ctrl_param, -+ obj ? obj->type : -1); -+ -+ kfree(obj); -+ -+ return 0; -+} -+ -+static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = { -+ {NULL, "devs", show_devs}, -+ {NULL, "dsts", show_dsts}, -+ {NULL, "call", show_call}, -+}; -+ -+static int asus_wmi_debugfs_open(struct inode *inode, struct file *file) -+{ -+ struct asus_wmi_debugfs_node *node = inode->i_private; -+ -+ return single_open(file, node->show, node->asus); -+} -+ -+static const struct file_operations asus_wmi_debugfs_io_ops = { -+ .owner = THIS_MODULE, -+ .open = asus_wmi_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void asus_wmi_debugfs_exit(struct asus_wmi *asus) -+{ -+ debugfs_remove_recursive(asus->debug.root); -+} -+ -+static void asus_wmi_debugfs_init(struct asus_wmi *asus) -+{ -+ int i; -+ -+ asus->debug.root = debugfs_create_dir(asus->driver->name, NULL); -+ -+ debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, asus->debug.root, -+ &asus->debug.method_id); -+ -+ debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, asus->debug.root, -+ &asus->debug.dev_id); -+ -+ debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, asus->debug.root, -+ &asus->debug.ctrl_param); -+ -+ for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) { -+ struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i]; -+ -+ node->asus = asus; -+ debugfs_create_file(node->name, S_IFREG | S_IRUGO, -+ asus->debug.root, node, -+ &asus_wmi_debugfs_io_ops); -+ } -+} -+ -+/* Init / exit ****************************************************************/ -+ -+static int asus_wmi_add(struct platform_device *pdev) -+{ -+ struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); -+ struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); -+ struct asus_wmi *asus; -+ acpi_status status; -+ int err; -+ u32 result; -+ -+ asus = kzalloc_obj(struct asus_wmi); -+ if (!asus) -+ return -ENOMEM; -+ -+ asus->driver = wdrv; -+ asus->platform_device = pdev; -+ wdrv->platform_device = pdev; -+ platform_set_drvdata(asus->platform_device, asus); -+ -+ if (wdrv->detect_quirks) -+ wdrv->detect_quirks(asus->driver); -+ -+ err = asus_wmi_platform_init(asus); -+ if (err) -+ goto fail_platform; -+ -+ if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_INIT) { -+ if (acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) -+ && dmi_check_system(asus_rog_ally_device)) -+ use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_ENABLED; -+ if (dmi_match(DMI_BOARD_NAME, "RC71")) { -+ /* -+ * These steps ensure the device is in a valid good state, this is -+ * especially important for the Ally 1 after a reboot. -+ */ -+ acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, -+ ASUS_USB0_PWR_EC0_CSEE_ON); -+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -+ } -+ } -+ -+ /* ensure defaults for tunables */ -+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) -+ asus->ppt_pl2_sppt = 5; -+ asus->ppt_pl1_spl = 5; -+ asus->ppt_apu_sppt = 5; -+ asus->ppt_platform_sppt = 5; -+ asus->ppt_fppt = 5; -+ asus->nv_dynamic_boost = 5; -+ asus->nv_temp_target = 75; -+ -+ asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); -+ asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); -+ asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) -+ asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE2)) -+ asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX)) -+ asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX; -+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO)) -+ asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO; -+#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */ -+ -+ asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE); -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY)) -+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY; -+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO)) -+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE)) -+ asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE; -+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2)) -+ asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2; -+ -+ err = fan_boost_mode_check_present(asus); -+ if (err) -+ goto fail_fan_boost_mode; -+ -+ err = platform_profile_setup(asus); -+ if (err) -+ goto fail_platform_profile_setup; -+ -+ err = keystone_check_present(asus); -+ if (err) -+ dev_warn(&pdev->dev, "Failed to check Keystone presence: %d\n", err); -+ -+ err = asus_wmi_sysfs_init(asus->platform_device); -+ if (err) -+ goto fail_sysfs; -+ -+ err = asus_wmi_input_init(asus); -+ if (err) -+ goto fail_input; -+ -+ err = asus_wmi_fan_init(asus); /* probably no problems on error */ -+ -+ err = asus_wmi_hwmon_init(asus); -+ if (err) -+ goto fail_hwmon; -+ -+ err = asus_wmi_custom_fan_curve_init(asus); -+ if (err) -+ goto fail_custom_fan_curve; -+ -+ err = asus_wmi_led_init(asus); -+ if (err) -+ goto fail_leds; -+ -+ asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result); -+ if ((result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) == -+ (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT)) -+ asus->driver->wlan_ctrl_by_user = 1; -+ -+ if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) { -+ err = asus_wmi_rfkill_init(asus); -+ if (err) -+ goto fail_rfkill; -+ } -+ -+ if (asus->driver->quirks->wmi_force_als_set) -+ asus_wmi_set_als(); -+ -+ if (asus->driver->quirks->xusb2pr) -+ asus_wmi_set_xusb2pr(asus); -+ -+ if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { -+ err = asus_wmi_backlight_init(asus); -+ if (err && err != -ENODEV) -+ goto fail_backlight; -+ } else if (asus->driver->quirks->wmi_backlight_set_devstate) -+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); -+ -+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT)) { -+ err = asus_screenpad_init(asus); -+ if (err && err != -ENODEV) -+ goto fail_screenpad; -+ } -+ -+ if (asus_wmi_has_fnlock_key(asus)) { -+ asus->fnlock_locked = fnlock_default; -+ asus_wmi_fnlock_update(asus); -+ } -+ -+ status = wmi_install_notify_handler(asus->driver->event_guid, -+ asus_wmi_notify, asus); -+ if (ACPI_FAILURE(status)) { -+ pr_err("Unable to register notify handler - %d\n", status); -+ err = -ENODEV; -+ goto fail_wmi_handler; -+ } -+ -+ if (asus->driver->i8042_filter) { -+ err = i8042_install_filter(asus->driver->i8042_filter, NULL); -+ if (err) -+ pr_warn("Unable to install key filter - %d\n", err); -+ } -+ -+ asus_wmi_battery_init(asus); -+ -+ asus_wmi_debugfs_init(asus); -+ -+ return 0; -+ -+fail_wmi_handler: -+ asus_screenpad_exit(asus); -+fail_screenpad: -+ asus_wmi_backlight_exit(asus); -+fail_backlight: -+ asus_wmi_rfkill_exit(asus); -+fail_rfkill: -+ asus_wmi_led_exit(asus); -+fail_leds: -+fail_custom_fan_curve: -+fail_hwmon: -+ asus_wmi_input_exit(asus); -+fail_input: -+ asus_wmi_sysfs_exit(asus->platform_device); -+fail_sysfs: -+fail_platform_profile_setup: -+fail_fan_boost_mode: -+fail_platform: -+ kfree(asus); -+ return err; -+} -+ -+static void asus_wmi_remove(struct platform_device *device) -+{ -+ struct asus_wmi *asus; -+ -+ asus = platform_get_drvdata(device); -+ if (asus->driver->i8042_filter) -+ i8042_remove_filter(asus->driver->i8042_filter); -+ wmi_remove_notify_handler(asus->driver->event_guid); -+ asus_wmi_backlight_exit(asus); -+ asus_screenpad_exit(asus); -+ asus_wmi_input_exit(asus); -+ asus_wmi_led_exit(asus); -+ asus_wmi_rfkill_exit(asus); -+ asus_wmi_debugfs_exit(asus); -+ asus_wmi_sysfs_exit(asus->platform_device); -+ asus_fan_set_auto(asus); -+ throttle_thermal_policy_set_default(asus); -+ asus_wmi_battery_exit(asus); -+ -+ kfree(asus); -+} -+ -+/* Platform driver - hibernate/resume callbacks *******************************/ -+ -+static int asus_hotk_thaw(struct device *device) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(device); -+ -+ if (asus->wlan.rfkill) { -+ bool wlan; -+ -+ /* -+ * Work around bios bug - acpi _PTS turns off the wireless led -+ * during suspend. Normally it restores it on resume, but -+ * we should kick it ourselves in case hibernation is aborted. -+ */ -+ wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); -+ } -+ -+ return 0; -+} -+ -+static int asus_hotk_resume(struct device *device) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(device); -+ -+ if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) -+ kbd_led_update(asus); -+ -+ if (asus_wmi_has_fnlock_key(asus)) -+ asus_wmi_fnlock_update(asus); -+ -+ asus_wmi_tablet_mode_get_state(asus); -+ -+ return 0; -+} -+ -+static int asus_hotk_restore(struct device *device) -+{ -+ struct asus_wmi *asus = dev_get_drvdata(device); -+ int bl; -+ -+ /* Refresh both wlan rfkill state and pci hotplug */ -+ if (asus->wlan.rfkill) -+ asus_rfkill_hotplug(asus); -+ -+ if (asus->bluetooth.rfkill) { -+ bl = !asus_wmi_get_devstate_simple(asus, -+ ASUS_WMI_DEVID_BLUETOOTH); -+ rfkill_set_sw_state(asus->bluetooth.rfkill, bl); -+ } -+ if (asus->wimax.rfkill) { -+ bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX); -+ rfkill_set_sw_state(asus->wimax.rfkill, bl); -+ } -+ if (asus->wwan3g.rfkill) { -+ bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); -+ rfkill_set_sw_state(asus->wwan3g.rfkill, bl); -+ } -+ if (asus->gps.rfkill) { -+ bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS); -+ rfkill_set_sw_state(asus->gps.rfkill, bl); -+ } -+ if (asus->uwb.rfkill) { -+ bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); -+ rfkill_set_sw_state(asus->uwb.rfkill, bl); -+ } -+ if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) -+ kbd_led_update(asus); -+ if (asus->oobe_state_available) { -+ /* -+ * Disable OOBE state, so that e.g. the keyboard backlight -+ * works. -+ */ -+ asus_wmi_set_devstate(ASUS_WMI_DEVID_OOBE, 1, NULL); -+ } -+ -+ if (asus_wmi_has_fnlock_key(asus)) -+ asus_wmi_fnlock_update(asus); -+ -+ asus_wmi_tablet_mode_get_state(asus); -+ return 0; -+} -+ -+static int asus_hotk_prepare(struct device *device) -+{ -+ if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_ENABLED) { -+ acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, -+ ASUS_USB0_PWR_EC0_CSEE_OFF); -+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -+ } -+ return 0; -+} -+ -+#if defined(CONFIG_SUSPEND) -+static void asus_ally_s2idle_restore(void) -+{ -+ if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_ENABLED) { -+ acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, -+ ASUS_USB0_PWR_EC0_CSEE_ON); -+ msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); -+ } -+} -+ -+/* Use only for Ally devices due to the wake_on_ac */ -+static struct acpi_s2idle_dev_ops asus_ally_s2idle_dev_ops = { -+ .restore = asus_ally_s2idle_restore, -+}; -+ -+static void asus_s2idle_check_register(void) -+{ -+ if (acpi_register_lps0_dev(&asus_ally_s2idle_dev_ops)) -+ pr_warn("failed to register LPS0 sleep handler in asus-wmi\n"); -+} -+ -+static void asus_s2idle_check_unregister(void) -+{ -+ acpi_unregister_lps0_dev(&asus_ally_s2idle_dev_ops); -+} -+#else -+static void asus_s2idle_check_register(void) {} -+static void asus_s2idle_check_unregister(void) {} -+#endif /* CONFIG_SUSPEND */ -+ -+static const struct dev_pm_ops asus_pm_ops = { -+ .thaw = asus_hotk_thaw, -+ .restore = asus_hotk_restore, -+ .resume = asus_hotk_resume, -+ .prepare = asus_hotk_prepare, -+}; -+ -+/* Registration ***************************************************************/ -+ -+static int asus_wmi_probe(struct platform_device *pdev) -+{ -+ struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); -+ struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); -+ int ret; -+ -+ if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { -+ pr_warn("ASUS Management GUID not found\n"); -+ return -ENODEV; -+ } -+ -+ if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) { -+ pr_warn("ASUS Event GUID not found\n"); -+ return -ENODEV; -+ } -+ -+ if (wdrv->probe) { -+ ret = wdrv->probe(pdev); -+ if (ret) -+ return ret; -+ } -+ -+ asus_s2idle_check_register(); -+ -+ ret = asus_wmi_add(pdev); -+ if (ret) -+ asus_s2idle_check_unregister(); -+ -+ return ret; -+} -+ -+static bool used; -+static DEFINE_MUTEX(register_mutex); -+ -+int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver) -+{ -+ struct platform_driver *platform_driver; -+ struct platform_device *platform_device; -+ -+ guard(mutex)(®ister_mutex); -+ if (used) -+ return -EBUSY; -+ -+ platform_driver = &driver->platform_driver; -+ platform_driver->remove = asus_wmi_remove; -+ platform_driver->driver.owner = driver->owner; -+ platform_driver->driver.name = driver->name; -+ platform_driver->driver.pm = &asus_pm_ops; -+ -+ platform_device = platform_create_bundle(platform_driver, -+ asus_wmi_probe, -+ NULL, 0, NULL, 0); -+ if (IS_ERR(platform_device)) -+ return PTR_ERR(platform_device); -+ -+ used = true; -+ return 0; -+} -+EXPORT_SYMBOL_GPL(asus_wmi_register_driver); -+ -+void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) -+{ -+ guard(mutex)(®ister_mutex); -+ asus_s2idle_check_unregister(); -+ -+ platform_device_unregister(driver->platform_device); -+ platform_driver_unregister(&driver->platform_driver); -+ used = false; -+} -+EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver); ---- a/drivers/platform/x86/asus-wmi.h -+++ /dev/null -@@ -1,89 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-or-later */ --/* -- * Asus PC WMI hotkey driver -- * -- * Copyright(C) 2010 Intel Corporation. -- * Copyright(C) 2010-2011 Corentin Chary -- * -- * Portions based on wistron_btns.c: -- * Copyright (C) 2005 Miloslav Trmac -- * Copyright (C) 2005 Bernhard Rosenkraenzer -- * Copyright (C) 2005 Dmitry Torokhov -- */ -- --#ifndef _ASUS_WMI_H_ --#define _ASUS_WMI_H_ -- --#include --#include -- --#define ASUS_WMI_KEY_IGNORE (-1) --#define ASUS_WMI_KEY_ARMOURY 0xffff01 --#define ASUS_WMI_BRN_DOWN 0x2e --#define ASUS_WMI_BRN_UP 0x2f -- --struct module; --struct key_entry; --struct asus_wmi; -- --enum asus_wmi_tablet_switch_mode { -- asus_wmi_no_tablet_switch, -- asus_wmi_kbd_dock_devid, -- asus_wmi_lid_flip_devid, -- asus_wmi_lid_flip_rog_devid, --}; -- --struct quirk_entry { -- bool hotplug_wireless; -- bool scalar_panel_brightness; -- bool store_backlight_power; -- bool wmi_backlight_set_devstate; -- bool wmi_force_als_set; -- bool wmi_ignore_fan; -- bool filter_i8042_e1_extended_codes; -- int key_wlan_event; -- enum asus_wmi_tablet_switch_mode tablet_switch_mode; -- int wapf; -- /* -- * For machines with AMD graphic chips, it will send out WMI event -- * and ACPI interrupt at the same time while hitting the hotkey. -- * To simplify the problem, we just have to ignore the WMI event, -- * and let the ACPI interrupt to send out the key event. -- */ -- int no_display_toggle; -- u32 xusb2pr; --}; -- --struct asus_wmi_driver { -- int brightness; -- int panel_power; -- int screenpad_brightness; -- int wlan_ctrl_by_user; -- -- const char *name; -- struct module *owner; -- -- const char *event_guid; -- -- const struct key_entry *keymap; -- const char *input_name; -- const char *input_phys; -- struct quirk_entry *quirks; -- /* Returns new code, value, and autorelease values in arguments. -- * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */ -- void (*key_filter) (struct asus_wmi_driver *driver, int *code, -- unsigned int *value, bool *autorelease); -- /* Optional standard i8042 filter */ -- i8042_filter_t i8042_filter; -- -- int (*probe) (struct platform_device *device); -- void (*detect_quirks) (struct asus_wmi_driver *driver); -- -- struct platform_driver platform_driver; -- struct platform_device *platform_device; --}; -- --int asus_wmi_register_driver(struct asus_wmi_driver *driver); --void asus_wmi_unregister_driver(struct asus_wmi_driver *driver); -- --#endif /* !_ASUS_WMI_H_ */ ---- /dev/null -+++ b/drivers/platform/asus/asus-wmi.h -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Asus PC WMI hotkey driver -+ * -+ * Copyright(C) 2010 Intel Corporation. -+ * Copyright(C) 2010-2011 Corentin Chary -+ * -+ * Portions based on wistron_btns.c: -+ * Copyright (C) 2005 Miloslav Trmac -+ * Copyright (C) 2005 Bernhard Rosenkraenzer -+ * Copyright (C) 2005 Dmitry Torokhov -+ */ -+ -+#ifndef _ASUS_WMI_H_ -+#define _ASUS_WMI_H_ -+ -+#include -+#include -+ -+#define ASUS_WMI_KEY_IGNORE (-1) -+#define ASUS_WMI_KEY_ARMOURY 0xffff01 -+#define ASUS_WMI_BRN_DOWN 0x2e -+#define ASUS_WMI_BRN_UP 0x2f -+ -+struct module; -+struct key_entry; -+struct asus_wmi; -+ -+enum asus_wmi_tablet_switch_mode { -+ asus_wmi_no_tablet_switch, -+ asus_wmi_kbd_dock_devid, -+ asus_wmi_lid_flip_devid, -+ asus_wmi_lid_flip_rog_devid, -+}; -+ -+struct quirk_entry { -+ bool hotplug_wireless; -+ bool scalar_panel_brightness; -+ bool store_backlight_power; -+ bool wmi_backlight_set_devstate; -+ bool wmi_force_als_set; -+ bool wmi_ignore_fan; -+ bool filter_i8042_e1_extended_codes; -+ int key_wlan_event; -+ enum asus_wmi_tablet_switch_mode tablet_switch_mode; -+ int wapf; -+ /* -+ * For machines with AMD graphic chips, it will send out WMI event -+ * and ACPI interrupt at the same time while hitting the hotkey. -+ * To simplify the problem, we just have to ignore the WMI event, -+ * and let the ACPI interrupt to send out the key event. -+ */ -+ int no_display_toggle; -+ u32 xusb2pr; -+}; -+ -+struct asus_wmi_driver { -+ int brightness; -+ int panel_power; -+ int screenpad_brightness; -+ int wlan_ctrl_by_user; -+ -+ const char *name; -+ struct module *owner; -+ -+ const char *event_guid; -+ -+ const struct key_entry *keymap; -+ const char *input_name; -+ const char *input_phys; -+ struct quirk_entry *quirks; -+ /* Returns new code, value, and autorelease values in arguments. -+ * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */ -+ void (*key_filter) (struct asus_wmi_driver *driver, int *code, -+ unsigned int *value, bool *autorelease); -+ /* Optional standard i8042 filter */ -+ i8042_filter_t i8042_filter; -+ -+ int (*probe) (struct platform_device *device); -+ void (*detect_quirks) (struct asus_wmi_driver *driver); -+ -+ struct platform_driver platform_driver; -+ struct platform_device *platform_device; -+}; -+ -+int asus_wmi_register_driver(struct asus_wmi_driver *driver); -+void asus_wmi_unregister_driver(struct asus_wmi_driver *driver); -+ -+#endif /* !_ASUS_WMI_H_ */ ---- a/drivers/platform/x86/asus-nb-wmi.c -+++ /dev/null -@@ -1,720 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Asus Notebooks WMI hotkey driver -- * -- * Copyright(C) 2010 Corentin Chary -- */ -- --#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -- --#include --#include --#include --#include --#include --#include --#include --#include -- --#include -- --#include "asus-wmi.h" -- --#define ASUS_NB_WMI_FILE "asus-nb-wmi" -- --MODULE_AUTHOR("Corentin Chary "); --MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver"); --MODULE_LICENSE("GPL"); -- --#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" -- --MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); -- --/* -- * WAPF defines the behavior of the Fn+Fx wlan key -- * The significance of values is yet to be found, but -- * most of the time: -- * Bit | Bluetooth | WLAN -- * 0 | Hardware | Hardware -- * 1 | Hardware | Software -- * 4 | Software | Software -- */ --static int wapf = -1; --module_param(wapf, uint, 0444); --MODULE_PARM_DESC(wapf, "WAPF value"); -- --static int tablet_mode_sw = -1; --module_param(tablet_mode_sw, uint, 0444); --MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip 3:lid-flip-rog"); -- --static struct quirk_entry *quirks; --static bool atkbd_reports_vol_keys; -- --static bool asus_i8042_filter(unsigned char data, unsigned char str, struct serio *port, -- void *context) --{ -- static bool extended_e0; -- static bool extended_e1; -- -- if (str & I8042_STR_AUXDATA) -- return false; -- -- if (quirks->filter_i8042_e1_extended_codes) { -- if (data == 0xe1) { -- extended_e1 = true; -- return true; -- } -- -- if (extended_e1) { -- extended_e1 = false; -- return true; -- } -- } -- -- if (data == 0xe0) { -- extended_e0 = true; -- } else if (extended_e0) { -- extended_e0 = false; -- -- switch (data & 0x7f) { -- case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */ -- case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */ -- case 0x30: /* e0 30 / e0 b0, Volume Up press / release */ -- atkbd_reports_vol_keys = true; -- break; -- } -- } -- -- return false; --} -- --static struct quirk_entry quirk_asus_unknown = { -- .wapf = 0, -- .wmi_backlight_set_devstate = true, --}; -- --static struct quirk_entry quirk_asus_q500a = { -- .filter_i8042_e1_extended_codes = true, -- .wmi_backlight_set_devstate = true, --}; -- --/* -- * For those machines that need software to control bt/wifi status -- * and have duplicate events(ACPI and WMI) for display toggle -- */ --static struct quirk_entry quirk_asus_x55u = { -- .wapf = 4, -- .wmi_backlight_set_devstate = true, -- .no_display_toggle = true, --}; -- --static struct quirk_entry quirk_asus_wapf4 = { -- .wapf = 4, -- .wmi_backlight_set_devstate = true, --}; -- --static struct quirk_entry quirk_asus_x200ca = { -- .wapf = 2, -- .wmi_backlight_set_devstate = true, --}; -- --static struct quirk_entry quirk_asus_x550lb = { -- .wmi_backlight_set_devstate = true, -- .xusb2pr = 0x01D9, --}; -- --static struct quirk_entry quirk_asus_forceals = { -- .wmi_backlight_set_devstate = true, -- .wmi_force_als_set = true, --}; -- --static struct quirk_entry quirk_asus_use_kbd_dock_devid = { -- .tablet_switch_mode = asus_wmi_kbd_dock_devid, --}; -- --static struct quirk_entry quirk_asus_use_lid_flip_devid = { -- .wmi_backlight_set_devstate = true, -- .tablet_switch_mode = asus_wmi_lid_flip_devid, --}; -- --static struct quirk_entry quirk_asus_tablet_mode = { -- .wmi_backlight_set_devstate = true, -- .tablet_switch_mode = asus_wmi_lid_flip_rog_devid, --}; -- --static struct quirk_entry quirk_asus_ignore_fan = { -- .wmi_ignore_fan = true, --}; -- --static struct quirk_entry quirk_asus_zenbook_duo_kbd = { -- .key_wlan_event = ASUS_WMI_KEY_IGNORE, --}; -- --static struct quirk_entry quirk_asus_z13 = { -- .key_wlan_event = ASUS_WMI_KEY_ARMOURY, -- .tablet_switch_mode = asus_wmi_kbd_dock_devid, --}; -- --static int dmi_matched(const struct dmi_system_id *dmi) --{ -- pr_info("Identified laptop model '%s'\n", dmi->ident); -- quirks = dmi->driver_data; -- return 1; --} -- --static const struct dmi_system_id asus_quirks[] = { -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. Q500A", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "Q500A"), -- }, -- .driver_data = &quirk_asus_q500a, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. U32U", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), -- DMI_MATCH(DMI_PRODUCT_NAME, "U32U"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X302UA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X401U", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), -- }, -- .driver_data = &quirk_asus_x55u, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X401A", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X401A"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X401A1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X45U", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X45U"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X456UA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X456UA"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X456UF", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X501U", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), -- }, -- .driver_data = &quirk_asus_x55u, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X501A", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X501A"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X501A1", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X550CA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X550CC", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X550CC"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X550CL", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X550CL"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X550VB", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X550VB"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X551CA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X551CA"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X55A", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X55A"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X55C", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X55C"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X55U", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), -- }, -- .driver_data = &quirk_asus_x55u, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X55VD", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X75A", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X75A"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X75VBP", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X75VBP"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X75VD", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X75VD"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. 1015E", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "1015E"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. 1015U", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "1015U"), -- }, -- .driver_data = &quirk_asus_wapf4, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X200CA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X200CA"), -- }, -- .driver_data = &quirk_asus_x200ca, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. UX330UAK", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"), -- }, -- .driver_data = &quirk_asus_forceals, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. X550LB", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"), -- }, -- .driver_data = &quirk_asus_x550lb, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. UX430UQ", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"), -- }, -- .driver_data = &quirk_asus_forceals, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUSTeK COMPUTER INC. UX430UNR", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "UX430UNR"), -- }, -- .driver_data = &quirk_asus_forceals, -- }, -- { -- .callback = dmi_matched, -- .ident = "Asus Transformer T100TA / T100HA / T100CHI", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- /* Match *T100* */ -- DMI_MATCH(DMI_PRODUCT_NAME, "T100"), -- }, -- .driver_data = &quirk_asus_use_kbd_dock_devid, -- }, -- { -- .callback = dmi_matched, -- .ident = "Asus Transformer T101HA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "T101HA"), -- }, -- .driver_data = &quirk_asus_use_kbd_dock_devid, -- }, -- { -- .callback = dmi_matched, -- .ident = "Asus Transformer T200TA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"), -- }, -- .driver_data = &quirk_asus_use_kbd_dock_devid, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS ZenBook Flip UX360", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- /* Match UX360* */ -- DMI_MATCH(DMI_PRODUCT_NAME, "UX360"), -- }, -- .driver_data = &quirk_asus_use_lid_flip_devid, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS TP200s / E205SA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "E205SA"), -- }, -- .driver_data = &quirk_asus_use_lid_flip_devid, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS ROG FLOW X13", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- /* Match GV301** */ -- DMI_MATCH(DMI_PRODUCT_NAME, "GV301"), -- }, -- .driver_data = &quirk_asus_tablet_mode, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS ROG FLOW X16", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "GV601R"), -- }, -- .driver_data = &quirk_asus_tablet_mode, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS ROG FLOW X16", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "GV601V"), -- }, -- .driver_data = &quirk_asus_tablet_mode, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS VivoBook E410MA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "E410MA"), -- }, -- .driver_data = &quirk_asus_ignore_fan, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS Zenbook Duo UX8406MA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "UX8406MA"), -- }, -- .driver_data = &quirk_asus_zenbook_duo_kbd, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS Zenbook Duo UX8406CA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- DMI_MATCH(DMI_PRODUCT_NAME, "UX8406CA"), -- }, -- .driver_data = &quirk_asus_zenbook_duo_kbd, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS Zenbook Duo UX8407AA", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), -- DMI_MATCH(DMI_PRODUCT_NAME, "Zenbook Duo UX8407AA"), -- }, -- .driver_data = &quirk_asus_zenbook_duo_kbd, -- }, -- { -- .callback = dmi_matched, -- .ident = "ASUS ROG Z13", -- .matches = { -- DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), -- DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow Z13"), -- }, -- .driver_data = &quirk_asus_z13, -- }, -- {}, --}; -- --static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) --{ -- quirks = &quirk_asus_unknown; -- dmi_check_system(asus_quirks); -- -- driver->quirks = quirks; -- driver->panel_power = BACKLIGHT_POWER_ON; -- -- /* overwrite the wapf setting if the wapf paramater is specified */ -- if (wapf != -1) -- quirks->wapf = wapf; -- else -- wapf = quirks->wapf; -- -- if (tablet_mode_sw != -1) -- quirks->tablet_switch_mode = tablet_mode_sw; --} -- --static const struct key_entry asus_nb_wmi_keymap[] = { -- { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } }, -- { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } }, -- { KE_KEY, 0x2a, { KEY_SELECTIVE_SCREENSHOT } }, -- { KE_IGNORE, 0x2b, }, /* PrintScreen (also send via PS/2) on newer models */ -- { KE_IGNORE, 0x2c, }, /* CapsLock (also send via PS/2) on newer models */ -- { KE_KEY, 0x2d, { KEY_DISPLAYTOGGLE } }, -- { KE_KEY, 0x30, { KEY_VOLUMEUP } }, -- { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, -- { KE_KEY, 0x32, { KEY_MUTE } }, -- { KE_KEY, 0x33, { KEY_SCREENLOCK } }, -- { KE_KEY, 0x35, { KEY_SCREENLOCK } }, -- { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */ -- { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, -- { KE_KEY, 0x41, { KEY_NEXTSONG } }, -- { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */ -- { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, -- { KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */ -- { KE_KEY, 0x50, { KEY_EMAIL } }, -- { KE_KEY, 0x51, { KEY_WWW } }, -- { KE_KEY, 0x55, { KEY_CALC } }, -- { KE_IGNORE, 0x57, }, /* Battery mode */ -- { KE_IGNORE, 0x58, }, /* AC mode */ -- { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ -- { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ -- { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ -- { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */ -- { KE_KEY, 0x60, { KEY_TOUCHPAD_ON } }, -- { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */ -- { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */ -- { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */ -- { KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */ -- { KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */ -- { KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */ -- { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ -- { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, -- { KE_IGNORE, 0x6E, }, /* Low Battery notification */ -- { KE_KEY, 0x71, { KEY_F13 } }, /* General-purpose button */ -- { KE_IGNORE, 0x79, }, /* Charger type dectection notification */ -- { KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */ -- { KE_IGNORE, 0x7B, }, /* Charger connect/disconnect notification */ -- { KE_KEY, 0x7c, { KEY_MICMUTE } }, -- { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ -- { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ -- { KE_KEY, 0x82, { KEY_CAMERA } }, -- { KE_KEY, 0x85, { KEY_CAMERA } }, -- { KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */ -- { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ -- { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ -- { KE_KEY, 0x8B, { KEY_PROG3 } }, /* ProArt key (PX13/HN7306) */ -- { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */ -- { KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */ -- { KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */ -- { KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */ -- { KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */ -- { KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */ -- { KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */ -- { KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */ -- { KE_KEY, 0x95, { KEY_MEDIA } }, -- { KE_KEY, 0x99, { KEY_PHONE } }, /* Conflicts with fan mode switch */ -- { KE_KEY, 0X9D, { KEY_FN_F } }, -- { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ -- { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ -- { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ -- { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ -- { KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */ -- { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */ -- { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */ -- { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */ -- { KE_KEY, 0xAE, { KEY_FN_F5 } }, /* Fn+F5 fan mode on 2020+ */ -- { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */ -- { KE_KEY, 0xB5, { KEY_CALC } }, -- { KE_IGNORE, 0xC0, }, /* External display connect/disconnect notification */ -- { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, -- { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, -- { KE_KEY, 0xCA, { KEY_F13 } }, /* Noise cancelling on Expertbook B9 */ -- { KE_KEY, 0xCB, { KEY_F14 } }, /* Fn+noise-cancel */ -- { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ -- { KE_IGNORE, 0xCF, }, /* AC mode */ -- { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ -- { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */ -- { KE_KEY, ASUS_WMI_KEY_ARMOURY, { KEY_PROG3 } }, -- { KE_END, 0}, --}; -- --static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, -- unsigned int *value, bool *autorelease) --{ -- switch (*code) { -- case ASUS_WMI_BRN_DOWN: -- case ASUS_WMI_BRN_UP: -- if (acpi_video_handles_brightness_key_presses()) -- *code = ASUS_WMI_KEY_IGNORE; -- -- break; -- case 0x30: /* Volume Up */ -- case 0x31: /* Volume Down */ -- case 0x32: /* Volume Mute */ -- if (atkbd_reports_vol_keys) -- *code = ASUS_WMI_KEY_IGNORE; -- break; -- case 0x5D: /* Wireless console Toggle */ -- case 0x5E: /* Wireless console Enable / Keyboard Attach, Detach */ -- case 0x5F: /* Wireless console Disable / Special Key */ -- if (quirks->key_wlan_event) -- *code = quirks->key_wlan_event; -- break; -- } --} -- --static struct asus_wmi_driver asus_nb_wmi_driver = { -- .name = ASUS_NB_WMI_FILE, -- .owner = THIS_MODULE, -- .event_guid = ASUS_NB_WMI_EVENT_GUID, -- .keymap = asus_nb_wmi_keymap, -- .input_name = "Asus WMI hotkeys", -- .input_phys = ASUS_NB_WMI_FILE "/input0", -- .detect_quirks = asus_nb_wmi_quirks, -- .key_filter = asus_nb_wmi_key_filter, -- .i8042_filter = asus_i8042_filter, --}; -- -- --static int __init asus_nb_wmi_init(void) --{ -- return asus_wmi_register_driver(&asus_nb_wmi_driver); --} -- --static void __exit asus_nb_wmi_exit(void) --{ -- asus_wmi_unregister_driver(&asus_nb_wmi_driver); --} -- --module_init(asus_nb_wmi_init); --module_exit(asus_nb_wmi_exit); ---- /dev/null -+++ b/drivers/platform/asus/asus-nb-wmi.c -@@ -0,0 +1,720 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Asus Notebooks WMI hotkey driver -+ * -+ * Copyright(C) 2010 Corentin Chary -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "asus-wmi.h" -+ -+#define ASUS_NB_WMI_FILE "asus-nb-wmi" -+ -+MODULE_AUTHOR("Corentin Chary "); -+MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver"); -+MODULE_LICENSE("GPL"); -+ -+#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" -+ -+MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); -+ -+/* -+ * WAPF defines the behavior of the Fn+Fx wlan key -+ * The significance of values is yet to be found, but -+ * most of the time: -+ * Bit | Bluetooth | WLAN -+ * 0 | Hardware | Hardware -+ * 1 | Hardware | Software -+ * 4 | Software | Software -+ */ -+static int wapf = -1; -+module_param(wapf, uint, 0444); -+MODULE_PARM_DESC(wapf, "WAPF value"); -+ -+static int tablet_mode_sw = -1; -+module_param(tablet_mode_sw, uint, 0444); -+MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip 3:lid-flip-rog"); -+ -+static struct quirk_entry *quirks; -+static bool atkbd_reports_vol_keys; -+ -+static bool asus_i8042_filter(unsigned char data, unsigned char str, struct serio *port, -+ void *context) -+{ -+ static bool extended_e0; -+ static bool extended_e1; -+ -+ if (str & I8042_STR_AUXDATA) -+ return false; -+ -+ if (quirks->filter_i8042_e1_extended_codes) { -+ if (data == 0xe1) { -+ extended_e1 = true; -+ return true; -+ } -+ -+ if (extended_e1) { -+ extended_e1 = false; -+ return true; -+ } -+ } -+ -+ if (data == 0xe0) { -+ extended_e0 = true; -+ } else if (extended_e0) { -+ extended_e0 = false; -+ -+ switch (data & 0x7f) { -+ case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */ -+ case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */ -+ case 0x30: /* e0 30 / e0 b0, Volume Up press / release */ -+ atkbd_reports_vol_keys = true; -+ break; -+ } -+ } -+ -+ return false; -+} -+ -+static struct quirk_entry quirk_asus_unknown = { -+ .wapf = 0, -+ .wmi_backlight_set_devstate = true, -+}; -+ -+static struct quirk_entry quirk_asus_q500a = { -+ .filter_i8042_e1_extended_codes = true, -+ .wmi_backlight_set_devstate = true, -+}; -+ -+/* -+ * For those machines that need software to control bt/wifi status -+ * and have duplicate events(ACPI and WMI) for display toggle -+ */ -+static struct quirk_entry quirk_asus_x55u = { -+ .wapf = 4, -+ .wmi_backlight_set_devstate = true, -+ .no_display_toggle = true, -+}; -+ -+static struct quirk_entry quirk_asus_wapf4 = { -+ .wapf = 4, -+ .wmi_backlight_set_devstate = true, -+}; -+ -+static struct quirk_entry quirk_asus_x200ca = { -+ .wapf = 2, -+ .wmi_backlight_set_devstate = true, -+}; -+ -+static struct quirk_entry quirk_asus_x550lb = { -+ .wmi_backlight_set_devstate = true, -+ .xusb2pr = 0x01D9, -+}; -+ -+static struct quirk_entry quirk_asus_forceals = { -+ .wmi_backlight_set_devstate = true, -+ .wmi_force_als_set = true, -+}; -+ -+static struct quirk_entry quirk_asus_use_kbd_dock_devid = { -+ .tablet_switch_mode = asus_wmi_kbd_dock_devid, -+}; -+ -+static struct quirk_entry quirk_asus_use_lid_flip_devid = { -+ .wmi_backlight_set_devstate = true, -+ .tablet_switch_mode = asus_wmi_lid_flip_devid, -+}; -+ -+static struct quirk_entry quirk_asus_tablet_mode = { -+ .wmi_backlight_set_devstate = true, -+ .tablet_switch_mode = asus_wmi_lid_flip_rog_devid, -+}; -+ -+static struct quirk_entry quirk_asus_ignore_fan = { -+ .wmi_ignore_fan = true, -+}; -+ -+static struct quirk_entry quirk_asus_zenbook_duo_kbd = { -+ .key_wlan_event = ASUS_WMI_KEY_IGNORE, -+}; -+ -+static struct quirk_entry quirk_asus_z13 = { -+ .key_wlan_event = ASUS_WMI_KEY_ARMOURY, -+ .tablet_switch_mode = asus_wmi_kbd_dock_devid, -+}; -+ -+static int dmi_matched(const struct dmi_system_id *dmi) -+{ -+ pr_info("Identified laptop model '%s'\n", dmi->ident); -+ quirks = dmi->driver_data; -+ return 1; -+} -+ -+static const struct dmi_system_id asus_quirks[] = { -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. Q500A", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Q500A"), -+ }, -+ .driver_data = &quirk_asus_q500a, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. U32U", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "U32U"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X302UA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X401U", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), -+ }, -+ .driver_data = &quirk_asus_x55u, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X401A", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X401A"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X401A1", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X45U", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X45U"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X456UA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X456UA"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X456UF", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X501U", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), -+ }, -+ .driver_data = &quirk_asus_x55u, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X501A", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X501A"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X501A1", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X550CA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X550CC", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X550CC"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X550CL", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X550CL"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X550VB", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X550VB"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X551CA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X551CA"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X55A", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X55A"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X55C", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X55C"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X55U", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), -+ }, -+ .driver_data = &quirk_asus_x55u, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X55VD", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X75A", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X75A"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X75VBP", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X75VBP"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X75VD", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X75VD"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. 1015E", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "1015E"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. 1015U", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "1015U"), -+ }, -+ .driver_data = &quirk_asus_wapf4, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X200CA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X200CA"), -+ }, -+ .driver_data = &quirk_asus_x200ca, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. UX330UAK", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"), -+ }, -+ .driver_data = &quirk_asus_forceals, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. X550LB", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"), -+ }, -+ .driver_data = &quirk_asus_x550lb, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. UX430UQ", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"), -+ }, -+ .driver_data = &quirk_asus_forceals, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUSTeK COMPUTER INC. UX430UNR", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "UX430UNR"), -+ }, -+ .driver_data = &quirk_asus_forceals, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "Asus Transformer T100TA / T100HA / T100CHI", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ /* Match *T100* */ -+ DMI_MATCH(DMI_PRODUCT_NAME, "T100"), -+ }, -+ .driver_data = &quirk_asus_use_kbd_dock_devid, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "Asus Transformer T101HA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "T101HA"), -+ }, -+ .driver_data = &quirk_asus_use_kbd_dock_devid, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "Asus Transformer T200TA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"), -+ }, -+ .driver_data = &quirk_asus_use_kbd_dock_devid, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS ZenBook Flip UX360", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ /* Match UX360* */ -+ DMI_MATCH(DMI_PRODUCT_NAME, "UX360"), -+ }, -+ .driver_data = &quirk_asus_use_lid_flip_devid, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS TP200s / E205SA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "E205SA"), -+ }, -+ .driver_data = &quirk_asus_use_lid_flip_devid, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS ROG FLOW X13", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ /* Match GV301** */ -+ DMI_MATCH(DMI_PRODUCT_NAME, "GV301"), -+ }, -+ .driver_data = &quirk_asus_tablet_mode, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS ROG FLOW X16", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "GV601R"), -+ }, -+ .driver_data = &quirk_asus_tablet_mode, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS ROG FLOW X16", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "GV601V"), -+ }, -+ .driver_data = &quirk_asus_tablet_mode, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS VivoBook E410MA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "E410MA"), -+ }, -+ .driver_data = &quirk_asus_ignore_fan, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS Zenbook Duo UX8406MA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "UX8406MA"), -+ }, -+ .driver_data = &quirk_asus_zenbook_duo_kbd, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS Zenbook Duo UX8406CA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "UX8406CA"), -+ }, -+ .driver_data = &quirk_asus_zenbook_duo_kbd, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS Zenbook Duo UX8407AA", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Zenbook Duo UX8407AA"), -+ }, -+ .driver_data = &quirk_asus_zenbook_duo_kbd, -+ }, -+ { -+ .callback = dmi_matched, -+ .ident = "ASUS ROG Z13", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow Z13"), -+ }, -+ .driver_data = &quirk_asus_z13, -+ }, -+ {}, -+}; -+ -+static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) -+{ -+ quirks = &quirk_asus_unknown; -+ dmi_check_system(asus_quirks); -+ -+ driver->quirks = quirks; -+ driver->panel_power = BACKLIGHT_POWER_ON; -+ -+ /* overwrite the wapf setting if the wapf paramater is specified */ -+ if (wapf != -1) -+ quirks->wapf = wapf; -+ else -+ wapf = quirks->wapf; -+ -+ if (tablet_mode_sw != -1) -+ quirks->tablet_switch_mode = tablet_mode_sw; -+} -+ -+static const struct key_entry asus_nb_wmi_keymap[] = { -+ { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } }, -+ { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } }, -+ { KE_KEY, 0x2a, { KEY_SELECTIVE_SCREENSHOT } }, -+ { KE_IGNORE, 0x2b, }, /* PrintScreen (also send via PS/2) on newer models */ -+ { KE_IGNORE, 0x2c, }, /* CapsLock (also send via PS/2) on newer models */ -+ { KE_KEY, 0x2d, { KEY_DISPLAYTOGGLE } }, -+ { KE_KEY, 0x30, { KEY_VOLUMEUP } }, -+ { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, -+ { KE_KEY, 0x32, { KEY_MUTE } }, -+ { KE_KEY, 0x33, { KEY_SCREENLOCK } }, -+ { KE_KEY, 0x35, { KEY_SCREENLOCK } }, -+ { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */ -+ { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, -+ { KE_KEY, 0x41, { KEY_NEXTSONG } }, -+ { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */ -+ { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, -+ { KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */ -+ { KE_KEY, 0x50, { KEY_EMAIL } }, -+ { KE_KEY, 0x51, { KEY_WWW } }, -+ { KE_KEY, 0x55, { KEY_CALC } }, -+ { KE_IGNORE, 0x57, }, /* Battery mode */ -+ { KE_IGNORE, 0x58, }, /* AC mode */ -+ { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ -+ { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ -+ { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ -+ { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */ -+ { KE_KEY, 0x60, { KEY_TOUCHPAD_ON } }, -+ { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */ -+ { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */ -+ { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */ -+ { KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */ -+ { KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */ -+ { KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */ -+ { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ -+ { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, -+ { KE_IGNORE, 0x6E, }, /* Low Battery notification */ -+ { KE_KEY, 0x71, { KEY_F13 } }, /* General-purpose button */ -+ { KE_IGNORE, 0x79, }, /* Charger type dectection notification */ -+ { KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */ -+ { KE_IGNORE, 0x7B, }, /* Charger connect/disconnect notification */ -+ { KE_KEY, 0x7c, { KEY_MICMUTE } }, -+ { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ -+ { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ -+ { KE_KEY, 0x82, { KEY_CAMERA } }, -+ { KE_KEY, 0x85, { KEY_CAMERA } }, -+ { KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */ -+ { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ -+ { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ -+ { KE_KEY, 0x8B, { KEY_PROG3 } }, /* ProArt key (PX13/HN7306) */ -+ { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */ -+ { KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */ -+ { KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */ -+ { KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */ -+ { KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */ -+ { KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */ -+ { KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */ -+ { KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */ -+ { KE_KEY, 0x95, { KEY_MEDIA } }, -+ { KE_KEY, 0x99, { KEY_PHONE } }, /* Conflicts with fan mode switch */ -+ { KE_KEY, 0X9D, { KEY_FN_F } }, -+ { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ -+ { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ -+ { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ -+ { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ -+ { KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */ -+ { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */ -+ { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */ -+ { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */ -+ { KE_KEY, 0xAE, { KEY_FN_F5 } }, /* Fn+F5 fan mode on 2020+ */ -+ { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */ -+ { KE_KEY, 0xB5, { KEY_CALC } }, -+ { KE_IGNORE, 0xC0, }, /* External display connect/disconnect notification */ -+ { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, -+ { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, -+ { KE_KEY, 0xCA, { KEY_F13 } }, /* Noise cancelling on Expertbook B9 */ -+ { KE_KEY, 0xCB, { KEY_F14 } }, /* Fn+noise-cancel */ -+ { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ -+ { KE_IGNORE, 0xCF, }, /* AC mode */ -+ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ -+ { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */ -+ { KE_KEY, ASUS_WMI_KEY_ARMOURY, { KEY_PROG3 } }, -+ { KE_END, 0}, -+}; -+ -+static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, -+ unsigned int *value, bool *autorelease) -+{ -+ switch (*code) { -+ case ASUS_WMI_BRN_DOWN: -+ case ASUS_WMI_BRN_UP: -+ if (acpi_video_handles_brightness_key_presses()) -+ *code = ASUS_WMI_KEY_IGNORE; -+ -+ break; -+ case 0x30: /* Volume Up */ -+ case 0x31: /* Volume Down */ -+ case 0x32: /* Volume Mute */ -+ if (atkbd_reports_vol_keys) -+ *code = ASUS_WMI_KEY_IGNORE; -+ break; -+ case 0x5D: /* Wireless console Toggle */ -+ case 0x5E: /* Wireless console Enable / Keyboard Attach, Detach */ -+ case 0x5F: /* Wireless console Disable / Special Key */ -+ if (quirks->key_wlan_event) -+ *code = quirks->key_wlan_event; -+ break; -+ } -+} -+ -+static struct asus_wmi_driver asus_nb_wmi_driver = { -+ .name = ASUS_NB_WMI_FILE, -+ .owner = THIS_MODULE, -+ .event_guid = ASUS_NB_WMI_EVENT_GUID, -+ .keymap = asus_nb_wmi_keymap, -+ .input_name = "Asus WMI hotkeys", -+ .input_phys = ASUS_NB_WMI_FILE "/input0", -+ .detect_quirks = asus_nb_wmi_quirks, -+ .key_filter = asus_nb_wmi_key_filter, -+ .i8042_filter = IS_ENABLED(CONFIG_SERIO_I8042) ? asus_i8042_filter : NULL, -+}; -+ -+ -+static int __init asus_nb_wmi_init(void) -+{ -+ return asus_wmi_register_driver(&asus_nb_wmi_driver); -+} -+ -+static void __exit asus_nb_wmi_exit(void) -+{ -+ asus_wmi_unregister_driver(&asus_nb_wmi_driver); -+} -+ -+module_init(asus_nb_wmi_init); -+module_exit(asus_nb_wmi_exit); ---- a/drivers/platform/x86/asus-armoury.c -+++ /dev/null -@@ -1,1197 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * Asus Armoury (WMI) attributes driver. -- * -- * This driver uses the fw_attributes class to expose various WMI functions -- * that are present in many gaming and some non-gaming ASUS laptops. -- * -- * These typically don't fit anywhere else in the sysfs such as under LED class, -- * hwmon or others, and are set in Windows using the ASUS Armoury Crate tool. -- * -- * Copyright(C) 2024 Luke Jones -- */ -- --#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "asus-armoury.h" --#include "firmware_attributes_class.h" -- --#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" -- --#define ASUS_MINI_LED_MODE_MASK GENMASK(1, 0) --/* Standard modes for devices with only on/off */ --#define ASUS_MINI_LED_OFF 0x00 --#define ASUS_MINI_LED_ON 0x01 --/* Like "on" but the effect is more vibrant or brighter */ --#define ASUS_MINI_LED_STRONG_MODE 0x02 --/* New modes for devices with 3 mini-led mode types */ --#define ASUS_MINI_LED_2024_WEAK 0x00 --#define ASUS_MINI_LED_2024_STRONG 0x01 --#define ASUS_MINI_LED_2024_OFF 0x02 -- --/* Power tunable attribute name defines */ --#define ATTR_PPT_PL1_SPL "ppt_pl1_spl" --#define ATTR_PPT_PL2_SPPT "ppt_pl2_sppt" --#define ATTR_PPT_PL3_FPPT "ppt_pl3_fppt" --#define ATTR_PPT_APU_SPPT "ppt_apu_sppt" --#define ATTR_PPT_PLATFORM_SPPT "ppt_platform_sppt" --#define ATTR_NV_DYNAMIC_BOOST "nv_dynamic_boost" --#define ATTR_NV_TEMP_TARGET "nv_temp_target" --#define ATTR_NV_BASE_TGP "nv_base_tgp" --#define ATTR_NV_TGP "nv_tgp" -- --#define ASUS_ROG_TUNABLE_DC 0 --#define ASUS_ROG_TUNABLE_AC 1 -- --struct rog_tunables { -- const struct power_limits *power_limits; -- u32 ppt_pl1_spl; // cpu -- u32 ppt_pl2_sppt; // cpu -- u32 ppt_pl3_fppt; // cpu -- u32 ppt_apu_sppt; // plat -- u32 ppt_platform_sppt; // plat -- -- u32 nv_dynamic_boost; -- u32 nv_temp_target; -- u32 nv_tgp; --}; -- --struct asus_armoury_priv { -- struct device *fw_attr_dev; -- struct kset *fw_attr_kset; -- -- /* -- * Mutex to protect eGPU activation/deactivation -- * sequences and dGPU connection status: -- * do not allow concurrent changes or changes -- * before a reboot if dGPU got disabled. -- */ -- struct mutex egpu_mutex; -- -- /* Index 0 for DC, 1 for AC */ -- struct rog_tunables *rog_tunables[2]; -- -- u32 mini_led_dev_id; -- u32 gpu_mux_dev_id; -- -- bool requires_fan_curve; --}; -- --static struct asus_armoury_priv asus_armoury = { -- .egpu_mutex = __MUTEX_INITIALIZER(asus_armoury.egpu_mutex), --}; -- --struct fw_attrs_group { -- bool pending_reboot; --}; -- --static struct fw_attrs_group fw_attrs = { -- .pending_reboot = false, --}; -- --struct asus_attr_group { -- const struct attribute_group *attr_group; -- u32 wmi_devid; --}; -- --static void asus_set_reboot_and_signal_event(void) --{ -- fw_attrs.pending_reboot = true; -- kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE); --} -- --static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) --{ -- return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot); --} -- --static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); -- --static bool asus_bios_requires_reboot(struct kobj_attribute *attr) --{ -- return !strcmp(attr->attr.name, "gpu_mux_mode") || -- !strcmp(attr->attr.name, "panel_hd_mode"); --} -- --/** -- * armoury_has_devstate() - Check presence of the WMI function state. -- * -- * @dev_id: The WMI method ID to check for presence. -- * -- * Returns: true iif method is supported. -- */ --static bool armoury_has_devstate(u32 dev_id) --{ -- u32 retval; -- int status; -- -- status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval); -- pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); -- -- return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); --} -- --/** -- * armoury_get_devstate() - Get the WMI function state. -- * @attr: NULL or the kobj_attribute associated to called WMI function. -- * @dev_id: The WMI method ID to call. -- * @retval: -- * * non-NULL pointer to where to store the value returned from WMI -- * * with the function presence bit cleared. -- * -- * Intended usage is from sysfs attribute checking associated WMI function. -- * -- * Returns: -- * * %-ENODEV - method ID is unsupported. -- * * %0 - successful and retval is filled. -- * * %other - error from WMI call. -- */ --static int armoury_get_devstate(struct kobj_attribute *attr, u32 *retval, u32 dev_id) --{ -- int err; -- -- err = asus_wmi_get_devstate_dsts(dev_id, retval); -- if (err) { -- if (attr) -- pr_err("Failed to get %s: %d\n", attr->attr.name, err); -- else -- pr_err("Failed to get devstate for 0x%x: %d\n", dev_id, err); -- -- return err; -- } -- -- /* -- * asus_wmi_get_devstate_dsts will populate retval with WMI return, but -- * the true value is expressed when ASUS_WMI_DSTS_PRESENCE_BIT is clear. -- */ -- *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT; -- -- return 0; --} -- --/** -- * armoury_set_devstate() - Set the WMI function state. -- * @attr: The kobj_attribute associated to called WMI function. -- * @dev_id: The WMI method ID to call. -- * @value: The new value to be set. -- * @retval: Where to store the value returned from WMI or NULL. -- * -- * Intended usage is from sysfs attribute setting associated WMI function. -- * Before calling the presence of the function should be checked. -- * -- * Every WMI write MUST go through this function to enforce safety checks. -- * -- * Results !1 is usually considered a fail by ASUS, but some WMI methods -- * (like eGPU or CPU cores) do use > 1 to return a status code or similar: -- * in these cases caller is interested in the actual return value -- * and should perform relevant checks. -- * -- * Returns: -- * * %-EINVAL - attempt to set a dangerous or unsupported value. -- * * %-EIO - WMI function returned an error. -- * * %0 - successful and retval is filled. -- * * %other - error from WMI call. -- */ --static int armoury_set_devstate(struct kobj_attribute *attr, -- u32 value, u32 *retval, u32 dev_id) --{ -- u32 result; -- int err; -- -- /* On some models, PPT changes require an active fan curve */ -- if (asus_armoury.requires_fan_curve) { -- switch (dev_id) { -- case ASUS_WMI_DEVID_PPT_PL1_SPL: -- case ASUS_WMI_DEVID_PPT_PL2_SPPT: -- case ASUS_WMI_DEVID_PPT_PL3_FPPT: -- case ASUS_WMI_DEVID_PPT_APU_SPPT: -- case ASUS_WMI_DEVID_PPT_PLAT_SPPT: -- if (!asus_wmi_custom_fan_curve_is_enabled()) { -- pr_warn_once("PPT change requires an active fan curve on this model. Enable a custom fan curve first.\n"); -- return -EBUSY; -- } -- break; -- } -- } -- -- /* -- * Prevent developers from bricking devices or issuing dangerous -- * commands that can be difficult or impossible to recover from. -- */ -- switch (dev_id) { -- case ASUS_WMI_DEVID_APU_MEM: -- /* -- * A hard reset might suffice to save the device, -- * but there is no value in sending these commands. -- */ -- if (value == 0x100 || value == 0x101) { -- pr_err("Refusing to set APU memory to unsafe value: 0x%x\n", value); -- return -EINVAL; -- } -- break; -- default: -- /* No problems are known for this dev_id */ -- break; -- } -- -- err = asus_wmi_set_devstate(dev_id, value, retval ? retval : &result); -- if (err) { -- if (attr) -- pr_err("Failed to set %s: %d\n", attr->attr.name, err); -- else -- pr_err("Failed to set devstate for 0x%x: %d\n", dev_id, err); -- -- return err; -- } -- -- /* -- * If retval == NULL caller is uninterested in return value: -- * perform the most common result check here. -- */ -- if ((retval == NULL) && (result == 0)) { -- pr_err("Failed to set %s: (result): 0x%x\n", attr->attr.name, result); -- return -EIO; -- } -- -- return 0; --} -- --static int armoury_attr_enum_list(char *buf, size_t enum_values) --{ -- size_t i; -- int len = 0; -- -- for (i = 0; i < enum_values; i++) { -- if (i == 0) -- len += sysfs_emit_at(buf, len, "%zu", i); -- else -- len += sysfs_emit_at(buf, len, ";%zu", i); -- } -- len += sysfs_emit_at(buf, len, "\n"); -- -- return len; --} -- --ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr, -- const char *buf, size_t count, u32 min, u32 max, -- u32 *store_value, u32 wmi_dev) --{ -- u32 value; -- int err; -- -- err = kstrtou32(buf, 10, &value); -- if (err) -- return err; -- -- if (value < min || value > max) -- return -EINVAL; -- -- err = armoury_set_devstate(attr, value, NULL, wmi_dev); -- if (err) -- return err; -- -- if (store_value != NULL) -- *store_value = value; -- sysfs_notify(kobj, NULL, attr->attr.name); -- -- if (asus_bios_requires_reboot(attr)) -- asus_set_reboot_and_signal_event(); -- -- return count; --} -- --ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf, u32 wmi_dev) --{ -- u32 result; -- int err; -- -- err = armoury_get_devstate(attr, &result, wmi_dev); -- if (err) -- return err; -- -- return sysfs_emit(buf, "%u\n", result); --} -- --static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf) --{ -- return sysfs_emit(buf, "enumeration\n"); --} -- --static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf) --{ -- return sysfs_emit(buf, "integer\n"); --} -- --/* Mini-LED mode **************************************************************/ -- --/* Values map for mini-led modes on 2023 and earlier models. */ --static u32 mini_led_mode1_map[] = { -- [0] = ASUS_MINI_LED_OFF, -- [1] = ASUS_MINI_LED_ON, --}; -- --/* Values map for mini-led modes on 2024 and later models. */ --static u32 mini_led_mode2_map[] = { -- [0] = ASUS_MINI_LED_2024_OFF, -- [1] = ASUS_MINI_LED_2024_WEAK, -- [2] = ASUS_MINI_LED_2024_STRONG, --}; -- --static ssize_t mini_led_mode_current_value_show(struct kobject *kobj, -- struct kobj_attribute *attr, char *buf) --{ -- u32 *mini_led_mode_map; -- size_t mini_led_mode_map_size; -- u32 i, mode; -- int err; -- -- switch (asus_armoury.mini_led_dev_id) { -- case ASUS_WMI_DEVID_MINI_LED_MODE: -- mini_led_mode_map = mini_led_mode1_map; -- mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); -- break; -- -- case ASUS_WMI_DEVID_MINI_LED_MODE2: -- mini_led_mode_map = mini_led_mode2_map; -- mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); -- break; -- -- default: -- pr_err("Unrecognized mini-LED device: %u\n", asus_armoury.mini_led_dev_id); -- return -ENODEV; -- } -- -- err = armoury_get_devstate(attr, &mode, asus_armoury.mini_led_dev_id); -- if (err) -- return err; -- -- mode = FIELD_GET(ASUS_MINI_LED_MODE_MASK, mode); -- -- for (i = 0; i < mini_led_mode_map_size; i++) -- if (mode == mini_led_mode_map[i]) -- return sysfs_emit(buf, "%u\n", i); -- -- pr_warn("Unrecognized mini-LED mode: %u", mode); -- return -EINVAL; --} -- --static ssize_t mini_led_mode_current_value_store(struct kobject *kobj, -- struct kobj_attribute *attr, -- const char *buf, size_t count) --{ -- u32 *mini_led_mode_map; -- size_t mini_led_mode_map_size; -- char mapped_value[12]; -- u32 mode; -- int err; -- -- err = kstrtou32(buf, 10, &mode); -- if (err) -- return err; -- -- switch (asus_armoury.mini_led_dev_id) { -- case ASUS_WMI_DEVID_MINI_LED_MODE: -- mini_led_mode_map = mini_led_mode1_map; -- mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); -- break; -- -- case ASUS_WMI_DEVID_MINI_LED_MODE2: -- mini_led_mode_map = mini_led_mode2_map; -- mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); -- break; -- -- default: -- pr_err("Unrecognized mini-LED devid: %u\n", asus_armoury.mini_led_dev_id); -- return -EINVAL; -- } -- -- if (mode >= mini_led_mode_map_size) { -- pr_warn("mini-LED mode unrecognized device: %u\n", mode); -- return -ENODEV; -- } -- -- /* -- * armoury_attr_uint_store() parses and sends the value from the -- * passed buffer; hand it the mapped firmware value so the device -- * receives the translated mode instead of the raw index. -- */ -- snprintf(mapped_value, sizeof(mapped_value), "%u", mini_led_mode_map[mode]); -- -- return armoury_attr_uint_store(kobj, attr, mapped_value, count, 0, -- mini_led_mode_map[mode], NULL, -- asus_armoury.mini_led_dev_id); --} -- --static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj, -- struct kobj_attribute *attr, char *buf) --{ -- switch (asus_armoury.mini_led_dev_id) { -- case ASUS_WMI_DEVID_MINI_LED_MODE: -- return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode1_map)); -- case ASUS_WMI_DEVID_MINI_LED_MODE2: -- return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode2_map)); -- default: -- return -ENODEV; -- } --} --ASUS_ATTR_GROUP_ENUM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode"); -- --static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj, -- struct kobj_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- bool optimus; -- -- err = kstrtobool(buf, &optimus); -- if (err) -- return err; -- -- if (armoury_has_devstate(ASUS_WMI_DEVID_DGPU)) { -- err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_DGPU); -- if (err) -- return err; -- if (result && !optimus) { -- pr_warn("Cannot switch MUX to dGPU mode when dGPU is disabled: %02X\n", -- result); -- return -ENODEV; -- } -- } -- -- if (armoury_has_devstate(ASUS_WMI_DEVID_EGPU)) { -- err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU); -- if (err) -- return err; -- if (result && !optimus) { -- pr_warn("Cannot switch MUX to dGPU mode when eGPU is enabled\n"); -- return -EBUSY; -- } -- } -- -- err = armoury_set_devstate(attr, optimus ? 1 : 0, NULL, asus_armoury.gpu_mux_dev_id); -- if (err) -- return err; -- -- sysfs_notify(kobj, NULL, attr->attr.name); -- asus_set_reboot_and_signal_event(); -- -- return count; --} --ASUS_WMI_SHOW_INT(gpu_mux_mode_current_value, asus_armoury.gpu_mux_dev_id); --ASUS_ATTR_GROUP_BOOL(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode"); -- --static ssize_t dgpu_disable_current_value_store(struct kobject *kobj, -- struct kobj_attribute *attr, const char *buf, -- size_t count) --{ -- int result, err; -- bool disable; -- -- err = kstrtobool(buf, &disable); -- if (err) -- return err; -- -- if (asus_armoury.gpu_mux_dev_id) { -- err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); -- if (err) -- return err; -- if (!result && disable) { -- pr_warn("Cannot disable dGPU when the MUX is in dGPU mode\n"); -- return -EBUSY; -- } -- } -- -- scoped_guard(mutex, &asus_armoury.egpu_mutex) { -- err = armoury_set_devstate(attr, disable ? 1 : 0, NULL, ASUS_WMI_DEVID_DGPU); -- if (err) -- return err; -- } -- -- sysfs_notify(kobj, NULL, attr->attr.name); -- -- return count; --} --ASUS_WMI_SHOW_INT(dgpu_disable_current_value, ASUS_WMI_DEVID_DGPU); --ASUS_ATTR_GROUP_BOOL(dgpu_disable, "dgpu_disable", "Disable the dGPU"); -- --/* Values map for eGPU activation requests. */ --static u32 egpu_status_map[] = { -- [0] = 0x00000000U, -- [1] = 0x00000001U, -- [2] = 0x00000101U, -- [3] = 0x00000201U, --}; -- --/* -- * armoury_pci_rescan() - Performs a PCI rescan -- * -- * Bring up any GPU that has been hotplugged in the system. -- */ --static void armoury_pci_rescan(void) --{ -- struct pci_bus *b = NULL; -- -- pci_lock_rescan_remove(); -- while ((b = pci_find_next_bus(b)) != NULL) -- pci_rescan_bus(b); -- pci_unlock_rescan_remove(); --} -- --/* -- * The ACPI call to enable the eGPU might also disable the internal dGPU, -- * but this is not always the case and on certain models enabling the eGPU -- * when the dGPU is either still active or has been disabled without rebooting -- * will make both GPUs malfunction and the kernel will detect many -- * PCI AER unrecoverable errors. -- */ --static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, -- const char *buf, size_t count) --{ -- int err; -- u32 requested, enable, result; -- -- err = kstrtou32(buf, 10, &requested); -- if (err) -- return err; -- -- if (requested >= ARRAY_SIZE(egpu_status_map)) -- return -EINVAL; -- enable = egpu_status_map[requested]; -- -- scoped_guard(mutex, &asus_armoury.egpu_mutex) { -- /* Ensure the eGPU is connected before attempting to activate it. */ -- if (enable) { -- err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU_CONNECTED); -- if (err) { -- pr_warn("Failed to get eGPU connection status: %d\n", err); -- return err; -- } -- if (!result) { -- pr_warn("Cannot activate eGPU while undetected\n"); -- return -ENOENT; -- } -- } -- -- if (asus_armoury.gpu_mux_dev_id) { -- err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); -- if (err) -- return err; -- -- if (!result && enable) { -- pr_warn("Cannot enable eGPU when the MUX is in dGPU mode\n"); -- return -ENODEV; -- } -- } -- -- err = armoury_set_devstate(attr, enable, &result, ASUS_WMI_DEVID_EGPU); -- if (err) { -- pr_err("Failed to set %s: %d\n", attr->attr.name, err); -- return err; -- } -- -- /* -- * ACPI returns value 0x01 on success and 0x02 on a partial activation: -- * performing a pci rescan will bring up the device in pci-e 3.0 speed, -- * after a reboot the device will work at full speed. -- */ -- switch (result) { -- case 0x01: -- /* -- * When a GPU is in use it does not get disconnected even if -- * the ACPI call returns a success. -- */ -- if (!enable) { -- err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_EGPU); -- if (err) { -- pr_warn("Failed to ensure eGPU is deactivated: %d\n", err); -- return err; -- } -- -- if (result != 0) -- return -EBUSY; -- } -- -- pr_debug("Success changing the eGPU status\n"); -- break; -- case 0x02: -- pr_info("Success changing the eGPU status, a reboot is strongly advised\n"); -- asus_set_reboot_and_signal_event(); -- break; -- default: -- pr_err("Failed to change the eGPU status: wmi result is 0x%x\n", result); -- return -EIO; -- } -- } -- -- /* -- * Perform a PCI rescan: on every tested model this is necessary -- * to make the eGPU visible on the bus without rebooting. -- */ -- armoury_pci_rescan(); -- -- sysfs_notify(kobj, NULL, attr->attr.name); -- -- return count; --} -- --static ssize_t egpu_enable_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf) --{ -- int i, err; -- u32 status; -- -- scoped_guard(mutex, &asus_armoury.egpu_mutex) { -- err = armoury_get_devstate(attr, &status, ASUS_WMI_DEVID_EGPU); -- if (err) -- return err; -- } -- -- for (i = 0; i < ARRAY_SIZE(egpu_status_map); i++) { -- if (egpu_status_map[i] == status) -- return sysfs_emit(buf, "%u\n", i); -- } -- -- return -EIO; --} -- --static ssize_t egpu_enable_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf) --{ -- return armoury_attr_enum_list(buf, ARRAY_SIZE(egpu_status_map)); --} --ASUS_ATTR_GROUP_ENUM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)"); -- --/* Device memory available to APU */ -- --/* -- * Values map for APU reserved memory (index + 1 number of GB). -- * Some looks out of order, but are actually correct. -- */ --static u32 apu_mem_map[] = { -- [0] = 0x000, /* called "AUTO" on the BIOS, is the minimum available */ -- [1] = 0x102, -- [2] = 0x103, -- [3] = 0x104, -- [4] = 0x105, -- [5] = 0x107, -- [6] = 0x108, -- [7] = 0x109, -- [8] = 0x106, --}; -- --static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf) --{ -- int err; -- u32 mem; -- -- err = armoury_get_devstate(attr, &mem, ASUS_WMI_DEVID_APU_MEM); -- if (err) -- return err; -- -- /* After 0x000 is set, a read will return 0x100 */ -- if (mem == 0x100) -- return sysfs_emit(buf, "0\n"); -- -- for (unsigned int i = 0; i < ARRAY_SIZE(apu_mem_map); i++) { -- if (apu_mem_map[i] == mem) -- return sysfs_emit(buf, "%u\n", i); -- } -- -- pr_warn("Unrecognised value for APU mem 0x%08x\n", mem); -- return -EIO; --} -- --static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, -- const char *buf, size_t count) --{ -- int result, err; -- u32 requested, mem; -- -- result = kstrtou32(buf, 10, &requested); -- if (result) -- return result; -- -- if (requested >= ARRAY_SIZE(apu_mem_map)) -- return -EINVAL; -- mem = apu_mem_map[requested]; -- -- err = armoury_set_devstate(attr, mem, NULL, ASUS_WMI_DEVID_APU_MEM); -- if (err) { -- pr_warn("Failed to set apu_mem 0x%x: %d\n", mem, err); -- return err; -- } -- -- pr_info("APU memory changed to %uGB, reboot required\n", requested + 1); -- sysfs_notify(kobj, NULL, attr->attr.name); -- -- asus_set_reboot_and_signal_event(); -- -- return count; --} -- --static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf) --{ -- return armoury_attr_enum_list(buf, ARRAY_SIZE(apu_mem_map)); --} --ASUS_ATTR_GROUP_ENUM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use"); -- --/* Define helper to access the current power mode tunable values */ --static inline struct rog_tunables *get_current_tunables(void) --{ -- if (power_supply_is_system_supplied()) -- return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; -- -- return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]; --} -- --/* Simple attribute creation */ --ASUS_ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2\n", -- "Show the current mode of charging"); --ASUS_ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND, -- "Set the boot POST sound"); --ASUS_ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, -- "Set MCU powersaving mode"); --ASUS_ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD, -- "Set the panel refresh overdrive"); --ASUS_ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD, -- "Set the panel HD mode to UHD<0> or FHD<1>"); --ASUS_ATTR_GROUP_BOOL_RW(screen_auto_brightness, "screen_auto_brightness", -- ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS, -- "Set the panel brightness to Off<0> or On<1>"); --ASUS_ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, -- "Show the eGPU connection status"); --ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, ATTR_PPT_PL1_SPL, ASUS_WMI_DEVID_PPT_PL1_SPL, -- "Set the CPU slow package limit"); --ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, ATTR_PPT_PL2_SPPT, ASUS_WMI_DEVID_PPT_PL2_SPPT, -- "Set the CPU fast package limit"); --ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl3_fppt, ATTR_PPT_PL3_FPPT, ASUS_WMI_DEVID_PPT_PL3_FPPT, -- "Set the CPU fastest package limit"); --ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, ATTR_PPT_APU_SPPT, ASUS_WMI_DEVID_PPT_APU_SPPT, -- "Set the APU package limit"); --ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, ATTR_PPT_PLATFORM_SPPT, ASUS_WMI_DEVID_PPT_PLAT_SPPT, -- "Set the platform package limit"); --ASUS_ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, ATTR_NV_DYNAMIC_BOOST, ASUS_WMI_DEVID_NV_DYN_BOOST, -- "Set the Nvidia dynamic boost limit"); --ASUS_ATTR_GROUP_ROG_TUNABLE(nv_temp_target, ATTR_NV_TEMP_TARGET, ASUS_WMI_DEVID_NV_THERM_TARGET, -- "Set the Nvidia max thermal limit"); --ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, -- "Set the additional TGP on top of the base TGP"); --ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, -- "Read the base TGP value"); -- --/* If an attribute does not require any special case handling add it here */ --static const struct asus_attr_group armoury_attr_groups[] = { -- { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, -- { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU }, -- { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU }, -- { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM }, -- -- { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, -- { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, -- { &ppt_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_PL3_FPPT }, -- { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, -- { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, -- { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, -- { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, -- { &nv_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, -- { &nv_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, -- -- { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, -- { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, -- { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE }, -- { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD }, -- { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD }, -- { &screen_auto_brightness_attr_group, ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS }, --}; -- --/** -- * is_power_tunable_attr - Determines if an attribute is a power-related tunable -- * @name: The name of the attribute to check -- * -- * This function checks if the given attribute name is related to power tuning. -- * -- * Return: true if the attribute is a power-related tunable, false otherwise -- */ --static bool is_power_tunable_attr(const char *name) --{ -- static const char * const power_tunable_attrs[] = { -- ATTR_PPT_PL1_SPL, ATTR_PPT_PL2_SPPT, -- ATTR_PPT_PL3_FPPT, ATTR_PPT_APU_SPPT, -- ATTR_PPT_PLATFORM_SPPT, ATTR_NV_DYNAMIC_BOOST, -- ATTR_NV_TEMP_TARGET, ATTR_NV_BASE_TGP, -- ATTR_NV_TGP -- }; -- -- for (unsigned int i = 0; i < ARRAY_SIZE(power_tunable_attrs); i++) { -- if (!strcmp(name, power_tunable_attrs[i])) -- return true; -- } -- -- return false; --} -- --/** -- * has_valid_limit - Checks if a power-related attribute has a valid limit value -- * @name: The name of the attribute to check -- * @limits: Pointer to the power_limits structure containing limit values -- * -- * This function checks if a power-related attribute has a valid limit value. -- * It returns false if limits is NULL or if the corresponding limit value is zero. -- * -- * Return: true if the attribute has a valid limit value, false otherwise -- */ --static bool has_valid_limit(const char *name, const struct power_limits *limits) --{ -- u32 limit_value = 0; -- -- if (!limits) -- return false; -- -- if (!strcmp(name, ATTR_PPT_PL1_SPL)) -- limit_value = limits->ppt_pl1_spl_max; -- else if (!strcmp(name, ATTR_PPT_PL2_SPPT)) -- limit_value = limits->ppt_pl2_sppt_max; -- else if (!strcmp(name, ATTR_PPT_PL3_FPPT)) -- limit_value = limits->ppt_pl3_fppt_max; -- else if (!strcmp(name, ATTR_PPT_APU_SPPT)) -- limit_value = limits->ppt_apu_sppt_max; -- else if (!strcmp(name, ATTR_PPT_PLATFORM_SPPT)) -- limit_value = limits->ppt_platform_sppt_max; -- else if (!strcmp(name, ATTR_NV_DYNAMIC_BOOST)) -- limit_value = limits->nv_dynamic_boost_max; -- else if (!strcmp(name, ATTR_NV_TEMP_TARGET)) -- limit_value = limits->nv_temp_target_max; -- else if (!strcmp(name, ATTR_NV_BASE_TGP) || -- !strcmp(name, ATTR_NV_TGP)) -- limit_value = limits->nv_tgp_max; -- -- return limit_value > 0; --} -- --static int asus_fw_attr_add(void) --{ -- const struct rog_tunables *const ac_rog_tunables = -- asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; -- const struct power_limits *limits; -- bool should_create; -- const char *name; -- int err, i; -- -- asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), -- NULL, "%s", DRIVER_NAME); -- if (IS_ERR(asus_armoury.fw_attr_dev)) { -- err = PTR_ERR(asus_armoury.fw_attr_dev); -- goto fail_class_get; -- } -- -- asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL, -- &asus_armoury.fw_attr_dev->kobj); -- if (!asus_armoury.fw_attr_kset) { -- err = -ENOMEM; -- goto err_destroy_classdev; -- } -- -- err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); -- if (err) { -- pr_err("Failed to create sysfs level attributes\n"); -- goto err_destroy_kset; -- } -- -- asus_armoury.mini_led_dev_id = 0; -- if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE)) -- asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -- else if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE2)) -- asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; -- -- if (asus_armoury.mini_led_dev_id) { -- err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -- &mini_led_mode_attr_group); -- if (err) { -- pr_err("Failed to create sysfs-group for mini_led\n"); -- goto err_remove_file; -- } -- } -- -- asus_armoury.gpu_mux_dev_id = 0; -- if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX)) -- asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX; -- else if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX_VIVO)) -- asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO; -- -- if (asus_armoury.gpu_mux_dev_id) { -- err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -- &gpu_mux_mode_attr_group); -- if (err) { -- pr_err("Failed to create sysfs-group for gpu_mux\n"); -- goto err_remove_mini_led_group; -- } -- } -- -- for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { -- if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) -- continue; -- -- /* Always create by default, unless PPT is not present */ -- should_create = true; -- name = armoury_attr_groups[i].attr_group->name; -- -- /* Check if this is a power-related tunable requiring limits */ -- if (ac_rog_tunables && ac_rog_tunables->power_limits && -- is_power_tunable_attr(name)) { -- limits = ac_rog_tunables->power_limits; -- /* Check only AC: if not present then DC won't be either */ -- should_create = has_valid_limit(name, limits); -- if (!should_create) -- pr_debug("Missing max value for tunable %s\n", name); -- } -- -- if (should_create) { -- err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -- armoury_attr_groups[i].attr_group); -- if (err) { -- pr_err("Failed to create sysfs-group for %s\n", -- armoury_attr_groups[i].attr_group->name); -- goto err_remove_groups; -- } -- } -- } -- -- return 0; -- --err_remove_groups: -- while (i--) { -- if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) -- sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, -- armoury_attr_groups[i].attr_group); -- } -- if (asus_armoury.gpu_mux_dev_id) -- sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); --err_remove_mini_led_group: -- if (asus_armoury.mini_led_dev_id) -- sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); --err_remove_file: -- sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); --err_destroy_kset: -- kset_unregister(asus_armoury.fw_attr_kset); --err_destroy_classdev: --fail_class_get: -- device_destroy(&firmware_attributes_class, MKDEV(0, 0)); -- return err; --} -- --/* Init / exit ****************************************************************/ -- --/* Set up the min/max and defaults for ROG tunables */ --static int init_rog_tunables(void) --{ -- const struct power_limits *ac_limits, *dc_limits; -- struct rog_tunables *ac_rog_tunables __free(kfree) = NULL; -- struct rog_tunables *dc_rog_tunables __free(kfree) = NULL; -- const struct power_data *power_data; -- const struct dmi_system_id *dmi_id; -- -- /* Match the system against the power_limits table */ -- dmi_id = dmi_first_match(power_limits); -- if (!dmi_id) { -- pr_warn("No matching power limits found for this system\n"); -- return 0; -- } -- -- /* Get the power data for this system */ -- power_data = dmi_id->driver_data; -- if (!power_data) { -- pr_info("No power data available for this system\n"); -- return 0; -- } -- -- asus_armoury.requires_fan_curve = power_data->requires_fan_curve; -- -- /* Initialize AC power tunables */ -- ac_limits = power_data->ac_data; -- if (ac_limits) { -- ac_rog_tunables = kzalloc_obj(*ac_rog_tunables); -- if (!ac_rog_tunables) -- return -ENOMEM; -- -- ac_rog_tunables->power_limits = ac_limits; -- -- /* Set initial AC values */ -- ac_rog_tunables->ppt_pl1_spl = -- ac_limits->ppt_pl1_spl_def ? -- ac_limits->ppt_pl1_spl_def : -- ac_limits->ppt_pl1_spl_max; -- -- ac_rog_tunables->ppt_pl2_sppt = -- ac_limits->ppt_pl2_sppt_def ? -- ac_limits->ppt_pl2_sppt_def : -- ac_limits->ppt_pl2_sppt_max; -- -- ac_rog_tunables->ppt_pl3_fppt = -- ac_limits->ppt_pl3_fppt_def ? -- ac_limits->ppt_pl3_fppt_def : -- ac_limits->ppt_pl3_fppt_max; -- -- ac_rog_tunables->ppt_apu_sppt = -- ac_limits->ppt_apu_sppt_def ? -- ac_limits->ppt_apu_sppt_def : -- ac_limits->ppt_apu_sppt_max; -- -- ac_rog_tunables->ppt_platform_sppt = -- ac_limits->ppt_platform_sppt_def ? -- ac_limits->ppt_platform_sppt_def : -- ac_limits->ppt_platform_sppt_max; -- -- ac_rog_tunables->nv_dynamic_boost = -- ac_limits->nv_dynamic_boost_max; -- ac_rog_tunables->nv_temp_target = -- ac_limits->nv_temp_target_max; -- ac_rog_tunables->nv_tgp = ac_limits->nv_tgp_max; -- -- pr_debug("AC power limits initialized for %s\n", dmi_id->matches[0].substr); -- } else { -- pr_debug("No AC PPT limits defined\n"); -- } -- -- /* Initialize DC power tunables */ -- dc_limits = power_data->dc_data; -- if (dc_limits) { -- dc_rog_tunables = kzalloc_obj(*dc_rog_tunables); -- if (!dc_rog_tunables) -- return -ENOMEM; -- -- dc_rog_tunables->power_limits = dc_limits; -- -- /* Set initial DC values */ -- dc_rog_tunables->ppt_pl1_spl = -- dc_limits->ppt_pl1_spl_def ? -- dc_limits->ppt_pl1_spl_def : -- dc_limits->ppt_pl1_spl_max; -- -- dc_rog_tunables->ppt_pl2_sppt = -- dc_limits->ppt_pl2_sppt_def ? -- dc_limits->ppt_pl2_sppt_def : -- dc_limits->ppt_pl2_sppt_max; -- -- dc_rog_tunables->ppt_pl3_fppt = -- dc_limits->ppt_pl3_fppt_def ? -- dc_limits->ppt_pl3_fppt_def : -- dc_limits->ppt_pl3_fppt_max; -- -- dc_rog_tunables->ppt_apu_sppt = -- dc_limits->ppt_apu_sppt_def ? -- dc_limits->ppt_apu_sppt_def : -- dc_limits->ppt_apu_sppt_max; -- -- dc_rog_tunables->ppt_platform_sppt = -- dc_limits->ppt_platform_sppt_def ? -- dc_limits->ppt_platform_sppt_def : -- dc_limits->ppt_platform_sppt_max; -- -- dc_rog_tunables->nv_dynamic_boost = -- dc_limits->nv_dynamic_boost_max; -- dc_rog_tunables->nv_temp_target = -- dc_limits->nv_temp_target_max; -- dc_rog_tunables->nv_tgp = dc_limits->nv_tgp_max; -- -- pr_debug("DC power limits initialized for %s\n", dmi_id->matches[0].substr); -- } else { -- pr_debug("No DC PPT limits defined\n"); -- } -- -- asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = no_free_ptr(ac_rog_tunables); -- asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = no_free_ptr(dc_rog_tunables); -- -- return 0; --} -- --static int __init asus_fw_init(void) --{ -- char *wmi_uid; -- int err; -- -- wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); -- if (!wmi_uid) -- return -ENODEV; -- -- /* -- * if equal to "ASUSWMI" then it's DCTS that can't be used for this -- * driver, DSTS is required. -- */ -- if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) -- return -ENODEV; -- -- err = init_rog_tunables(); -- if (err) -- return err; -- -- /* Must always be last step to ensure data is available */ -- err = asus_fw_attr_add(); -- if (err) -- goto err_free_tunables; -- -- return 0; -- --err_free_tunables: -- kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); -- kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); -- return err; --} -- --static void __exit asus_fw_exit(void) --{ -- int i; -- -- for (i = ARRAY_SIZE(armoury_attr_groups) - 1; i >= 0; i--) { -- if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) -- sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, -- armoury_attr_groups[i].attr_group); -- } -- -- if (asus_armoury.gpu_mux_dev_id) -- sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); -- -- if (asus_armoury.mini_led_dev_id) -- sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); -- -- sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); -- kset_unregister(asus_armoury.fw_attr_kset); -- device_destroy(&firmware_attributes_class, MKDEV(0, 0)); -- -- kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); -- kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); --} -- --module_init(asus_fw_init); --module_exit(asus_fw_exit); -- --MODULE_IMPORT_NS("ASUS_WMI"); --MODULE_AUTHOR("Luke Jones "); --MODULE_DESCRIPTION("ASUS BIOS Configuration Driver"); --MODULE_LICENSE("GPL"); --MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID); ---- /dev/null -+++ b/drivers/platform/asus/asus-armoury.c -@@ -0,0 +1,1197 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Asus Armoury (WMI) attributes driver. -+ * -+ * This driver uses the fw_attributes class to expose various WMI functions -+ * that are present in many gaming and some non-gaming ASUS laptops. -+ * -+ * These typically don't fit anywhere else in the sysfs such as under LED class, -+ * hwmon or others, and are set in Windows using the ASUS Armoury Crate tool. -+ * -+ * Copyright(C) 2024 Luke Jones -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "asus-armoury.h" -+#include "firmware_attributes_class.h" -+ -+#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" -+ -+#define ASUS_MINI_LED_MODE_MASK GENMASK(1, 0) -+/* Standard modes for devices with only on/off */ -+#define ASUS_MINI_LED_OFF 0x00 -+#define ASUS_MINI_LED_ON 0x01 -+/* Like "on" but the effect is more vibrant or brighter */ -+#define ASUS_MINI_LED_STRONG_MODE 0x02 -+/* New modes for devices with 3 mini-led mode types */ -+#define ASUS_MINI_LED_2024_WEAK 0x00 -+#define ASUS_MINI_LED_2024_STRONG 0x01 -+#define ASUS_MINI_LED_2024_OFF 0x02 -+ -+/* Power tunable attribute name defines */ -+#define ATTR_PPT_PL1_SPL "ppt_pl1_spl" -+#define ATTR_PPT_PL2_SPPT "ppt_pl2_sppt" -+#define ATTR_PPT_PL3_FPPT "ppt_pl3_fppt" -+#define ATTR_PPT_APU_SPPT "ppt_apu_sppt" -+#define ATTR_PPT_PLATFORM_SPPT "ppt_platform_sppt" -+#define ATTR_NV_DYNAMIC_BOOST "nv_dynamic_boost" -+#define ATTR_NV_TEMP_TARGET "nv_temp_target" -+#define ATTR_NV_BASE_TGP "nv_base_tgp" -+#define ATTR_NV_TGP "nv_tgp" -+ -+#define ASUS_ROG_TUNABLE_DC 0 -+#define ASUS_ROG_TUNABLE_AC 1 -+ -+struct rog_tunables { -+ const struct power_limits *power_limits; -+ u32 ppt_pl1_spl; // cpu -+ u32 ppt_pl2_sppt; // cpu -+ u32 ppt_pl3_fppt; // cpu -+ u32 ppt_apu_sppt; // plat -+ u32 ppt_platform_sppt; // plat -+ -+ u32 nv_dynamic_boost; -+ u32 nv_temp_target; -+ u32 nv_tgp; -+}; -+ -+struct asus_armoury_priv { -+ struct device *fw_attr_dev; -+ struct kset *fw_attr_kset; -+ -+ /* -+ * Mutex to protect eGPU activation/deactivation -+ * sequences and dGPU connection status: -+ * do not allow concurrent changes or changes -+ * before a reboot if dGPU got disabled. -+ */ -+ struct mutex egpu_mutex; -+ -+ /* Index 0 for DC, 1 for AC */ -+ struct rog_tunables *rog_tunables[2]; -+ -+ u32 mini_led_dev_id; -+ u32 gpu_mux_dev_id; -+ -+ bool requires_fan_curve; -+}; -+ -+static struct asus_armoury_priv asus_armoury = { -+ .egpu_mutex = __MUTEX_INITIALIZER(asus_armoury.egpu_mutex), -+}; -+ -+struct fw_attrs_group { -+ bool pending_reboot; -+}; -+ -+static struct fw_attrs_group fw_attrs = { -+ .pending_reboot = false, -+}; -+ -+struct asus_attr_group { -+ const struct attribute_group *attr_group; -+ u32 wmi_devid; -+}; -+ -+static void asus_set_reboot_and_signal_event(void) -+{ -+ fw_attrs.pending_reboot = true; -+ kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE); -+} -+ -+static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -+{ -+ return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot); -+} -+ -+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); -+ -+static bool asus_bios_requires_reboot(struct kobj_attribute *attr) -+{ -+ return !strcmp(attr->attr.name, "gpu_mux_mode") || -+ !strcmp(attr->attr.name, "panel_hd_mode"); -+} -+ -+/** -+ * armoury_has_devstate() - Check presence of the WMI function state. -+ * -+ * @dev_id: The WMI method ID to check for presence. -+ * -+ * Returns: true iif method is supported. -+ */ -+static bool armoury_has_devstate(u32 dev_id) -+{ -+ u32 retval; -+ int status; -+ -+ status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval); -+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); -+ -+ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); -+} -+ -+/** -+ * armoury_get_devstate() - Get the WMI function state. -+ * @attr: NULL or the kobj_attribute associated to called WMI function. -+ * @dev_id: The WMI method ID to call. -+ * @retval: -+ * * non-NULL pointer to where to store the value returned from WMI -+ * * with the function presence bit cleared. -+ * -+ * Intended usage is from sysfs attribute checking associated WMI function. -+ * -+ * Returns: -+ * * %-ENODEV - method ID is unsupported. -+ * * %0 - successful and retval is filled. -+ * * %other - error from WMI call. -+ */ -+static int armoury_get_devstate(struct kobj_attribute *attr, u32 *retval, u32 dev_id) -+{ -+ int err; -+ -+ err = asus_wmi_get_devstate_dsts(dev_id, retval); -+ if (err) { -+ if (attr) -+ pr_err("Failed to get %s: %d\n", attr->attr.name, err); -+ else -+ pr_err("Failed to get devstate for 0x%x: %d\n", dev_id, err); -+ -+ return err; -+ } -+ -+ /* -+ * asus_wmi_get_devstate_dsts will populate retval with WMI return, but -+ * the true value is expressed when ASUS_WMI_DSTS_PRESENCE_BIT is clear. -+ */ -+ *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT; -+ -+ return 0; -+} -+ -+/** -+ * armoury_set_devstate() - Set the WMI function state. -+ * @attr: The kobj_attribute associated to called WMI function. -+ * @dev_id: The WMI method ID to call. -+ * @value: The new value to be set. -+ * @retval: Where to store the value returned from WMI or NULL. -+ * -+ * Intended usage is from sysfs attribute setting associated WMI function. -+ * Before calling the presence of the function should be checked. -+ * -+ * Every WMI write MUST go through this function to enforce safety checks. -+ * -+ * Results !1 is usually considered a fail by ASUS, but some WMI methods -+ * (like eGPU or CPU cores) do use > 1 to return a status code or similar: -+ * in these cases caller is interested in the actual return value -+ * and should perform relevant checks. -+ * -+ * Returns: -+ * * %-EINVAL - attempt to set a dangerous or unsupported value. -+ * * %-EIO - WMI function returned an error. -+ * * %0 - successful and retval is filled. -+ * * %other - error from WMI call. -+ */ -+static int armoury_set_devstate(struct kobj_attribute *attr, -+ u32 value, u32 *retval, u32 dev_id) -+{ -+ u32 result; -+ int err; -+ -+ /* On some models, PPT changes require an active fan curve */ -+ if (asus_armoury.requires_fan_curve) { -+ switch (dev_id) { -+ case ASUS_WMI_DEVID_PPT_PL1_SPL: -+ case ASUS_WMI_DEVID_PPT_PL2_SPPT: -+ case ASUS_WMI_DEVID_PPT_PL3_FPPT: -+ case ASUS_WMI_DEVID_PPT_APU_SPPT: -+ case ASUS_WMI_DEVID_PPT_PLAT_SPPT: -+ if (!asus_wmi_custom_fan_curve_is_enabled()) { -+ pr_warn_once("PPT change requires an active fan curve on this model. Enable a custom fan curve first.\n"); -+ return -EBUSY; -+ } -+ break; -+ } -+ } -+ -+ /* -+ * Prevent developers from bricking devices or issuing dangerous -+ * commands that can be difficult or impossible to recover from. -+ */ -+ switch (dev_id) { -+ case ASUS_WMI_DEVID_APU_MEM: -+ /* -+ * A hard reset might suffice to save the device, -+ * but there is no value in sending these commands. -+ */ -+ if (value == 0x100 || value == 0x101) { -+ pr_err("Refusing to set APU memory to unsafe value: 0x%x\n", value); -+ return -EINVAL; -+ } -+ break; -+ default: -+ /* No problems are known for this dev_id */ -+ break; -+ } -+ -+ err = asus_wmi_set_devstate(dev_id, value, retval ? retval : &result); -+ if (err) { -+ if (attr) -+ pr_err("Failed to set %s: %d\n", attr->attr.name, err); -+ else -+ pr_err("Failed to set devstate for 0x%x: %d\n", dev_id, err); -+ -+ return err; -+ } -+ -+ /* -+ * If retval == NULL caller is uninterested in return value: -+ * perform the most common result check here. -+ */ -+ if ((retval == NULL) && (result == 0)) { -+ pr_err("Failed to set %s: (result): 0x%x\n", attr->attr.name, result); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int armoury_attr_enum_list(char *buf, size_t enum_values) -+{ -+ size_t i; -+ int len = 0; -+ -+ for (i = 0; i < enum_values; i++) { -+ if (i == 0) -+ len += sysfs_emit_at(buf, len, "%zu", i); -+ else -+ len += sysfs_emit_at(buf, len, ";%zu", i); -+ } -+ len += sysfs_emit_at(buf, len, "\n"); -+ -+ return len; -+} -+ -+ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t count, u32 min, u32 max, -+ u32 *store_value, u32 wmi_dev) -+{ -+ u32 value; -+ int err; -+ -+ err = kstrtou32(buf, 10, &value); -+ if (err) -+ return err; -+ -+ if (value < min || value > max) -+ return -EINVAL; -+ -+ err = armoury_set_devstate(attr, value, NULL, wmi_dev); -+ if (err) -+ return err; -+ -+ if (store_value != NULL) -+ *store_value = value; -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ if (asus_bios_requires_reboot(attr)) -+ asus_set_reboot_and_signal_event(); -+ -+ return count; -+} -+ -+ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf, u32 wmi_dev) -+{ -+ u32 result; -+ int err; -+ -+ err = armoury_get_devstate(attr, &result, wmi_dev); -+ if (err) -+ return err; -+ -+ return sysfs_emit(buf, "%u\n", result); -+} -+ -+static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "enumeration\n"); -+} -+ -+static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return sysfs_emit(buf, "integer\n"); -+} -+ -+/* Mini-LED mode **************************************************************/ -+ -+/* Values map for mini-led modes on 2023 and earlier models. */ -+static u32 mini_led_mode1_map[] = { -+ [0] = ASUS_MINI_LED_OFF, -+ [1] = ASUS_MINI_LED_ON, -+}; -+ -+/* Values map for mini-led modes on 2024 and later models. */ -+static u32 mini_led_mode2_map[] = { -+ [0] = ASUS_MINI_LED_2024_OFF, -+ [1] = ASUS_MINI_LED_2024_WEAK, -+ [2] = ASUS_MINI_LED_2024_STRONG, -+}; -+ -+static ssize_t mini_led_mode_current_value_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ u32 *mini_led_mode_map; -+ size_t mini_led_mode_map_size; -+ u32 i, mode; -+ int err; -+ -+ switch (asus_armoury.mini_led_dev_id) { -+ case ASUS_WMI_DEVID_MINI_LED_MODE: -+ mini_led_mode_map = mini_led_mode1_map; -+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); -+ break; -+ -+ case ASUS_WMI_DEVID_MINI_LED_MODE2: -+ mini_led_mode_map = mini_led_mode2_map; -+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); -+ break; -+ -+ default: -+ pr_err("Unrecognized mini-LED device: %u\n", asus_armoury.mini_led_dev_id); -+ return -ENODEV; -+ } -+ -+ err = armoury_get_devstate(attr, &mode, asus_armoury.mini_led_dev_id); -+ if (err) -+ return err; -+ -+ mode = FIELD_GET(ASUS_MINI_LED_MODE_MASK, mode); -+ -+ for (i = 0; i < mini_led_mode_map_size; i++) -+ if (mode == mini_led_mode_map[i]) -+ return sysfs_emit(buf, "%u\n", i); -+ -+ pr_warn("Unrecognized mini-LED mode: %u", mode); -+ return -EINVAL; -+} -+ -+static ssize_t mini_led_mode_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ u32 *mini_led_mode_map; -+ size_t mini_led_mode_map_size; -+ char mapped_value[12]; -+ u32 mode; -+ int err; -+ -+ err = kstrtou32(buf, 10, &mode); -+ if (err) -+ return err; -+ -+ switch (asus_armoury.mini_led_dev_id) { -+ case ASUS_WMI_DEVID_MINI_LED_MODE: -+ mini_led_mode_map = mini_led_mode1_map; -+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); -+ break; -+ -+ case ASUS_WMI_DEVID_MINI_LED_MODE2: -+ mini_led_mode_map = mini_led_mode2_map; -+ mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); -+ break; -+ -+ default: -+ pr_err("Unrecognized mini-LED devid: %u\n", asus_armoury.mini_led_dev_id); -+ return -EINVAL; -+ } -+ -+ if (mode >= mini_led_mode_map_size) { -+ pr_warn("mini-LED mode unrecognized device: %u\n", mode); -+ return -ENODEV; -+ } -+ -+ /* -+ * armoury_attr_uint_store() parses and sends the value from the -+ * passed buffer; hand it the mapped firmware value so the device -+ * receives the translated mode instead of the raw index. -+ */ -+ snprintf(mapped_value, sizeof(mapped_value), "%u", mini_led_mode_map[mode]); -+ -+ return armoury_attr_uint_store(kobj, attr, mapped_value, count, 0, -+ mini_led_mode_map[mode], NULL, -+ asus_armoury.mini_led_dev_id); -+} -+ -+static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj, -+ struct kobj_attribute *attr, char *buf) -+{ -+ switch (asus_armoury.mini_led_dev_id) { -+ case ASUS_WMI_DEVID_MINI_LED_MODE: -+ return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode1_map)); -+ case ASUS_WMI_DEVID_MINI_LED_MODE2: -+ return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode2_map)); -+ default: -+ return -ENODEV; -+ } -+} -+ASUS_ATTR_GROUP_ENUM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode"); -+ -+static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ bool optimus; -+ -+ err = kstrtobool(buf, &optimus); -+ if (err) -+ return err; -+ -+ if (armoury_has_devstate(ASUS_WMI_DEVID_DGPU)) { -+ err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_DGPU); -+ if (err) -+ return err; -+ if (result && !optimus) { -+ pr_warn("Cannot switch MUX to dGPU mode when dGPU is disabled: %02X\n", -+ result); -+ return -ENODEV; -+ } -+ } -+ -+ if (armoury_has_devstate(ASUS_WMI_DEVID_EGPU)) { -+ err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU); -+ if (err) -+ return err; -+ if (result && !optimus) { -+ pr_warn("Cannot switch MUX to dGPU mode when eGPU is enabled\n"); -+ return -EBUSY; -+ } -+ } -+ -+ err = armoury_set_devstate(attr, optimus ? 1 : 0, NULL, asus_armoury.gpu_mux_dev_id); -+ if (err) -+ return err; -+ -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ asus_set_reboot_and_signal_event(); -+ -+ return count; -+} -+ASUS_WMI_SHOW_INT(gpu_mux_mode_current_value, asus_armoury.gpu_mux_dev_id); -+ASUS_ATTR_GROUP_BOOL(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode"); -+ -+static ssize_t dgpu_disable_current_value_store(struct kobject *kobj, -+ struct kobj_attribute *attr, const char *buf, -+ size_t count) -+{ -+ int result, err; -+ bool disable; -+ -+ err = kstrtobool(buf, &disable); -+ if (err) -+ return err; -+ -+ if (asus_armoury.gpu_mux_dev_id) { -+ err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); -+ if (err) -+ return err; -+ if (!result && disable) { -+ pr_warn("Cannot disable dGPU when the MUX is in dGPU mode\n"); -+ return -EBUSY; -+ } -+ } -+ -+ scoped_guard(mutex, &asus_armoury.egpu_mutex) { -+ err = armoury_set_devstate(attr, disable ? 1 : 0, NULL, ASUS_WMI_DEVID_DGPU); -+ if (err) -+ return err; -+ } -+ -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ return count; -+} -+ASUS_WMI_SHOW_INT(dgpu_disable_current_value, ASUS_WMI_DEVID_DGPU); -+ASUS_ATTR_GROUP_BOOL(dgpu_disable, "dgpu_disable", "Disable the dGPU"); -+ -+/* Values map for eGPU activation requests. */ -+static u32 egpu_status_map[] = { -+ [0] = 0x00000000U, -+ [1] = 0x00000001U, -+ [2] = 0x00000101U, -+ [3] = 0x00000201U, -+}; -+ -+/* -+ * armoury_pci_rescan() - Performs a PCI rescan -+ * -+ * Bring up any GPU that has been hotplugged in the system. -+ */ -+static void armoury_pci_rescan(void) -+{ -+ struct pci_bus *b = NULL; -+ -+ pci_lock_rescan_remove(); -+ while ((b = pci_find_next_bus(b)) != NULL) -+ pci_rescan_bus(b); -+ pci_unlock_rescan_remove(); -+} -+ -+/* -+ * The ACPI call to enable the eGPU might also disable the internal dGPU, -+ * but this is not always the case and on certain models enabling the eGPU -+ * when the dGPU is either still active or has been disabled without rebooting -+ * will make both GPUs malfunction and the kernel will detect many -+ * PCI AER unrecoverable errors. -+ */ -+static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int err; -+ u32 requested, enable, result; -+ -+ err = kstrtou32(buf, 10, &requested); -+ if (err) -+ return err; -+ -+ if (requested >= ARRAY_SIZE(egpu_status_map)) -+ return -EINVAL; -+ enable = egpu_status_map[requested]; -+ -+ scoped_guard(mutex, &asus_armoury.egpu_mutex) { -+ /* Ensure the eGPU is connected before attempting to activate it. */ -+ if (enable) { -+ err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU_CONNECTED); -+ if (err) { -+ pr_warn("Failed to get eGPU connection status: %d\n", err); -+ return err; -+ } -+ if (!result) { -+ pr_warn("Cannot activate eGPU while undetected\n"); -+ return -ENOENT; -+ } -+ } -+ -+ if (asus_armoury.gpu_mux_dev_id) { -+ err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); -+ if (err) -+ return err; -+ -+ if (!result && enable) { -+ pr_warn("Cannot enable eGPU when the MUX is in dGPU mode\n"); -+ return -ENODEV; -+ } -+ } -+ -+ err = armoury_set_devstate(attr, enable, &result, ASUS_WMI_DEVID_EGPU); -+ if (err) { -+ pr_err("Failed to set %s: %d\n", attr->attr.name, err); -+ return err; -+ } -+ -+ /* -+ * ACPI returns value 0x01 on success and 0x02 on a partial activation: -+ * performing a pci rescan will bring up the device in pci-e 3.0 speed, -+ * after a reboot the device will work at full speed. -+ */ -+ switch (result) { -+ case 0x01: -+ /* -+ * When a GPU is in use it does not get disconnected even if -+ * the ACPI call returns a success. -+ */ -+ if (!enable) { -+ err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_EGPU); -+ if (err) { -+ pr_warn("Failed to ensure eGPU is deactivated: %d\n", err); -+ return err; -+ } -+ -+ if (result != 0) -+ return -EBUSY; -+ } -+ -+ pr_debug("Success changing the eGPU status\n"); -+ break; -+ case 0x02: -+ pr_info("Success changing the eGPU status, a reboot is strongly advised\n"); -+ asus_set_reboot_and_signal_event(); -+ break; -+ default: -+ pr_err("Failed to change the eGPU status: wmi result is 0x%x\n", result); -+ return -EIO; -+ } -+ } -+ -+ /* -+ * Perform a PCI rescan: on every tested model this is necessary -+ * to make the eGPU visible on the bus without rebooting. -+ */ -+ armoury_pci_rescan(); -+ -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ return count; -+} -+ -+static ssize_t egpu_enable_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ int i, err; -+ u32 status; -+ -+ scoped_guard(mutex, &asus_armoury.egpu_mutex) { -+ err = armoury_get_devstate(attr, &status, ASUS_WMI_DEVID_EGPU); -+ if (err) -+ return err; -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(egpu_status_map); i++) { -+ if (egpu_status_map[i] == status) -+ return sysfs_emit(buf, "%u\n", i); -+ } -+ -+ return -EIO; -+} -+ -+static ssize_t egpu_enable_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return armoury_attr_enum_list(buf, ARRAY_SIZE(egpu_status_map)); -+} -+ASUS_ATTR_GROUP_ENUM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)"); -+ -+/* Device memory available to APU */ -+ -+/* -+ * Values map for APU reserved memory (index + 1 number of GB). -+ * Some looks out of order, but are actually correct. -+ */ -+static u32 apu_mem_map[] = { -+ [0] = 0x000, /* called "AUTO" on the BIOS, is the minimum available */ -+ [1] = 0x102, -+ [2] = 0x103, -+ [3] = 0x104, -+ [4] = 0x105, -+ [5] = 0x107, -+ [6] = 0x108, -+ [7] = 0x109, -+ [8] = 0x106, -+}; -+ -+static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ int err; -+ u32 mem; -+ -+ err = armoury_get_devstate(attr, &mem, ASUS_WMI_DEVID_APU_MEM); -+ if (err) -+ return err; -+ -+ /* After 0x000 is set, a read will return 0x100 */ -+ if (mem == 0x100) -+ return sysfs_emit(buf, "0\n"); -+ -+ for (unsigned int i = 0; i < ARRAY_SIZE(apu_mem_map); i++) { -+ if (apu_mem_map[i] == mem) -+ return sysfs_emit(buf, "%u\n", i); -+ } -+ -+ pr_warn("Unrecognised value for APU mem 0x%08x\n", mem); -+ return -EIO; -+} -+ -+static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t count) -+{ -+ int result, err; -+ u32 requested, mem; -+ -+ result = kstrtou32(buf, 10, &requested); -+ if (result) -+ return result; -+ -+ if (requested >= ARRAY_SIZE(apu_mem_map)) -+ return -EINVAL; -+ mem = apu_mem_map[requested]; -+ -+ err = armoury_set_devstate(attr, mem, NULL, ASUS_WMI_DEVID_APU_MEM); -+ if (err) { -+ pr_warn("Failed to set apu_mem 0x%x: %d\n", mem, err); -+ return err; -+ } -+ -+ pr_info("APU memory changed to %uGB, reboot required\n", requested + 1); -+ sysfs_notify(kobj, NULL, attr->attr.name); -+ -+ asus_set_reboot_and_signal_event(); -+ -+ return count; -+} -+ -+static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ return armoury_attr_enum_list(buf, ARRAY_SIZE(apu_mem_map)); -+} -+ASUS_ATTR_GROUP_ENUM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use"); -+ -+/* Define helper to access the current power mode tunable values */ -+static inline struct rog_tunables *get_current_tunables(void) -+{ -+ if (power_supply_is_system_supplied()) -+ return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; -+ -+ return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]; -+} -+ -+/* Simple attribute creation */ -+ASUS_ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2\n", -+ "Show the current mode of charging"); -+ASUS_ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND, -+ "Set the boot POST sound"); -+ASUS_ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, -+ "Set MCU powersaving mode"); -+ASUS_ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD, -+ "Set the panel refresh overdrive"); -+ASUS_ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD, -+ "Set the panel HD mode to UHD<0> or FHD<1>"); -+ASUS_ATTR_GROUP_BOOL_RW(screen_auto_brightness, "screen_auto_brightness", -+ ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS, -+ "Set the panel brightness to Off<0> or On<1>"); -+ASUS_ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, -+ "Show the eGPU connection status"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, ATTR_PPT_PL1_SPL, ASUS_WMI_DEVID_PPT_PL1_SPL, -+ "Set the CPU slow package limit"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, ATTR_PPT_PL2_SPPT, ASUS_WMI_DEVID_PPT_PL2_SPPT, -+ "Set the CPU fast package limit"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl3_fppt, ATTR_PPT_PL3_FPPT, ASUS_WMI_DEVID_PPT_PL3_FPPT, -+ "Set the CPU fastest package limit"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, ATTR_PPT_APU_SPPT, ASUS_WMI_DEVID_PPT_APU_SPPT, -+ "Set the APU package limit"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, ATTR_PPT_PLATFORM_SPPT, ASUS_WMI_DEVID_PPT_PLAT_SPPT, -+ "Set the platform package limit"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, ATTR_NV_DYNAMIC_BOOST, ASUS_WMI_DEVID_NV_DYN_BOOST, -+ "Set the Nvidia dynamic boost limit"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(nv_temp_target, ATTR_NV_TEMP_TARGET, ASUS_WMI_DEVID_NV_THERM_TARGET, -+ "Set the Nvidia max thermal limit"); -+ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, -+ "Set the additional TGP on top of the base TGP"); -+ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, -+ "Read the base TGP value"); -+ -+/* If an attribute does not require any special case handling add it here */ -+static const struct asus_attr_group armoury_attr_groups[] = { -+ { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, -+ { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU }, -+ { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU }, -+ { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM }, -+ -+ { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, -+ { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, -+ { &ppt_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_PL3_FPPT }, -+ { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, -+ { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, -+ { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, -+ { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, -+ { &nv_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, -+ { &nv_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, -+ -+ { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, -+ { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, -+ { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE }, -+ { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD }, -+ { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD }, -+ { &screen_auto_brightness_attr_group, ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS }, -+}; -+ -+/** -+ * is_power_tunable_attr - Determines if an attribute is a power-related tunable -+ * @name: The name of the attribute to check -+ * -+ * This function checks if the given attribute name is related to power tuning. -+ * -+ * Return: true if the attribute is a power-related tunable, false otherwise -+ */ -+static bool is_power_tunable_attr(const char *name) -+{ -+ static const char * const power_tunable_attrs[] = { -+ ATTR_PPT_PL1_SPL, ATTR_PPT_PL2_SPPT, -+ ATTR_PPT_PL3_FPPT, ATTR_PPT_APU_SPPT, -+ ATTR_PPT_PLATFORM_SPPT, ATTR_NV_DYNAMIC_BOOST, -+ ATTR_NV_TEMP_TARGET, ATTR_NV_BASE_TGP, -+ ATTR_NV_TGP -+ }; -+ -+ for (unsigned int i = 0; i < ARRAY_SIZE(power_tunable_attrs); i++) { -+ if (!strcmp(name, power_tunable_attrs[i])) -+ return true; -+ } -+ -+ return false; -+} -+ -+/** -+ * has_valid_limit - Checks if a power-related attribute has a valid limit value -+ * @name: The name of the attribute to check -+ * @limits: Pointer to the power_limits structure containing limit values -+ * -+ * This function checks if a power-related attribute has a valid limit value. -+ * It returns false if limits is NULL or if the corresponding limit value is zero. -+ * -+ * Return: true if the attribute has a valid limit value, false otherwise -+ */ -+static bool has_valid_limit(const char *name, const struct power_limits *limits) -+{ -+ u32 limit_value = 0; -+ -+ if (!limits) -+ return false; -+ -+ if (!strcmp(name, ATTR_PPT_PL1_SPL)) -+ limit_value = limits->ppt_pl1_spl_max; -+ else if (!strcmp(name, ATTR_PPT_PL2_SPPT)) -+ limit_value = limits->ppt_pl2_sppt_max; -+ else if (!strcmp(name, ATTR_PPT_PL3_FPPT)) -+ limit_value = limits->ppt_pl3_fppt_max; -+ else if (!strcmp(name, ATTR_PPT_APU_SPPT)) -+ limit_value = limits->ppt_apu_sppt_max; -+ else if (!strcmp(name, ATTR_PPT_PLATFORM_SPPT)) -+ limit_value = limits->ppt_platform_sppt_max; -+ else if (!strcmp(name, ATTR_NV_DYNAMIC_BOOST)) -+ limit_value = limits->nv_dynamic_boost_max; -+ else if (!strcmp(name, ATTR_NV_TEMP_TARGET)) -+ limit_value = limits->nv_temp_target_max; -+ else if (!strcmp(name, ATTR_NV_BASE_TGP) || -+ !strcmp(name, ATTR_NV_TGP)) -+ limit_value = limits->nv_tgp_max; -+ -+ return limit_value > 0; -+} -+ -+static int asus_fw_attr_add(void) -+{ -+ const struct rog_tunables *const ac_rog_tunables = -+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; -+ const struct power_limits *limits; -+ bool should_create; -+ const char *name; -+ int err, i; -+ -+ asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), -+ NULL, "%s", DRIVER_NAME); -+ if (IS_ERR(asus_armoury.fw_attr_dev)) { -+ err = PTR_ERR(asus_armoury.fw_attr_dev); -+ goto fail_class_get; -+ } -+ -+ asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL, -+ &asus_armoury.fw_attr_dev->kobj); -+ if (!asus_armoury.fw_attr_kset) { -+ err = -ENOMEM; -+ goto err_destroy_classdev; -+ } -+ -+ err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); -+ if (err) { -+ pr_err("Failed to create sysfs level attributes\n"); -+ goto err_destroy_kset; -+ } -+ -+ asus_armoury.mini_led_dev_id = 0; -+ if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE)) -+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; -+ else if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE2)) -+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; -+ -+ if (asus_armoury.mini_led_dev_id) { -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -+ &mini_led_mode_attr_group); -+ if (err) { -+ pr_err("Failed to create sysfs-group for mini_led\n"); -+ goto err_remove_file; -+ } -+ } -+ -+ asus_armoury.gpu_mux_dev_id = 0; -+ if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX)) -+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX; -+ else if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX_VIVO)) -+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO; -+ -+ if (asus_armoury.gpu_mux_dev_id) { -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -+ &gpu_mux_mode_attr_group); -+ if (err) { -+ pr_err("Failed to create sysfs-group for gpu_mux\n"); -+ goto err_remove_mini_led_group; -+ } -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { -+ if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) -+ continue; -+ -+ /* Always create by default, unless PPT is not present */ -+ should_create = true; -+ name = armoury_attr_groups[i].attr_group->name; -+ -+ /* Check if this is a power-related tunable requiring limits */ -+ if (ac_rog_tunables && ac_rog_tunables->power_limits && -+ is_power_tunable_attr(name)) { -+ limits = ac_rog_tunables->power_limits; -+ /* Check only AC: if not present then DC won't be either */ -+ should_create = has_valid_limit(name, limits); -+ if (!should_create) -+ pr_debug("Missing max value for tunable %s\n", name); -+ } -+ -+ if (should_create) { -+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, -+ armoury_attr_groups[i].attr_group); -+ if (err) { -+ pr_err("Failed to create sysfs-group for %s\n", -+ armoury_attr_groups[i].attr_group->name); -+ goto err_remove_groups; -+ } -+ } -+ } -+ -+ return 0; -+ -+err_remove_groups: -+ while (i--) { -+ if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) -+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, -+ armoury_attr_groups[i].attr_group); -+ } -+ if (asus_armoury.gpu_mux_dev_id) -+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); -+err_remove_mini_led_group: -+ if (asus_armoury.mini_led_dev_id) -+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); -+err_remove_file: -+ sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); -+err_destroy_kset: -+ kset_unregister(asus_armoury.fw_attr_kset); -+err_destroy_classdev: -+fail_class_get: -+ device_destroy(&firmware_attributes_class, MKDEV(0, 0)); -+ return err; -+} -+ -+/* Init / exit ****************************************************************/ -+ -+/* Set up the min/max and defaults for ROG tunables */ -+static int init_rog_tunables(void) -+{ -+ const struct power_limits *ac_limits, *dc_limits; -+ struct rog_tunables *ac_rog_tunables __free(kfree) = NULL; -+ struct rog_tunables *dc_rog_tunables __free(kfree) = NULL; -+ const struct power_data *power_data; -+ const struct dmi_system_id *dmi_id; -+ -+ /* Match the system against the power_limits table */ -+ dmi_id = dmi_first_match(power_limits); -+ if (!dmi_id) { -+ pr_warn("No matching power limits found for this system\n"); -+ return 0; -+ } -+ -+ /* Get the power data for this system */ -+ power_data = dmi_id->driver_data; -+ if (!power_data) { -+ pr_info("No power data available for this system\n"); -+ return 0; -+ } -+ -+ asus_armoury.requires_fan_curve = power_data->requires_fan_curve; -+ -+ /* Initialize AC power tunables */ -+ ac_limits = power_data->ac_data; -+ if (ac_limits) { -+ ac_rog_tunables = kzalloc_obj(*ac_rog_tunables); -+ if (!ac_rog_tunables) -+ return -ENOMEM; -+ -+ ac_rog_tunables->power_limits = ac_limits; -+ -+ /* Set initial AC values */ -+ ac_rog_tunables->ppt_pl1_spl = -+ ac_limits->ppt_pl1_spl_def ? -+ ac_limits->ppt_pl1_spl_def : -+ ac_limits->ppt_pl1_spl_max; -+ -+ ac_rog_tunables->ppt_pl2_sppt = -+ ac_limits->ppt_pl2_sppt_def ? -+ ac_limits->ppt_pl2_sppt_def : -+ ac_limits->ppt_pl2_sppt_max; -+ -+ ac_rog_tunables->ppt_pl3_fppt = -+ ac_limits->ppt_pl3_fppt_def ? -+ ac_limits->ppt_pl3_fppt_def : -+ ac_limits->ppt_pl3_fppt_max; -+ -+ ac_rog_tunables->ppt_apu_sppt = -+ ac_limits->ppt_apu_sppt_def ? -+ ac_limits->ppt_apu_sppt_def : -+ ac_limits->ppt_apu_sppt_max; -+ -+ ac_rog_tunables->ppt_platform_sppt = -+ ac_limits->ppt_platform_sppt_def ? -+ ac_limits->ppt_platform_sppt_def : -+ ac_limits->ppt_platform_sppt_max; -+ -+ ac_rog_tunables->nv_dynamic_boost = -+ ac_limits->nv_dynamic_boost_max; -+ ac_rog_tunables->nv_temp_target = -+ ac_limits->nv_temp_target_max; -+ ac_rog_tunables->nv_tgp = ac_limits->nv_tgp_max; -+ -+ pr_debug("AC power limits initialized for %s\n", dmi_id->matches[0].substr); -+ } else { -+ pr_debug("No AC PPT limits defined\n"); -+ } -+ -+ /* Initialize DC power tunables */ -+ dc_limits = power_data->dc_data; -+ if (dc_limits) { -+ dc_rog_tunables = kzalloc_obj(*dc_rog_tunables); -+ if (!dc_rog_tunables) -+ return -ENOMEM; -+ -+ dc_rog_tunables->power_limits = dc_limits; -+ -+ /* Set initial DC values */ -+ dc_rog_tunables->ppt_pl1_spl = -+ dc_limits->ppt_pl1_spl_def ? -+ dc_limits->ppt_pl1_spl_def : -+ dc_limits->ppt_pl1_spl_max; -+ -+ dc_rog_tunables->ppt_pl2_sppt = -+ dc_limits->ppt_pl2_sppt_def ? -+ dc_limits->ppt_pl2_sppt_def : -+ dc_limits->ppt_pl2_sppt_max; -+ -+ dc_rog_tunables->ppt_pl3_fppt = -+ dc_limits->ppt_pl3_fppt_def ? -+ dc_limits->ppt_pl3_fppt_def : -+ dc_limits->ppt_pl3_fppt_max; -+ -+ dc_rog_tunables->ppt_apu_sppt = -+ dc_limits->ppt_apu_sppt_def ? -+ dc_limits->ppt_apu_sppt_def : -+ dc_limits->ppt_apu_sppt_max; -+ -+ dc_rog_tunables->ppt_platform_sppt = -+ dc_limits->ppt_platform_sppt_def ? -+ dc_limits->ppt_platform_sppt_def : -+ dc_limits->ppt_platform_sppt_max; -+ -+ dc_rog_tunables->nv_dynamic_boost = -+ dc_limits->nv_dynamic_boost_max; -+ dc_rog_tunables->nv_temp_target = -+ dc_limits->nv_temp_target_max; -+ dc_rog_tunables->nv_tgp = dc_limits->nv_tgp_max; -+ -+ pr_debug("DC power limits initialized for %s\n", dmi_id->matches[0].substr); -+ } else { -+ pr_debug("No DC PPT limits defined\n"); -+ } -+ -+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = no_free_ptr(ac_rog_tunables); -+ asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = no_free_ptr(dc_rog_tunables); -+ -+ return 0; -+} -+ -+static int __init asus_fw_init(void) -+{ -+ char *wmi_uid; -+ int err; -+ -+ wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); -+ if (!wmi_uid) -+ return -ENODEV; -+ -+ /* -+ * if equal to "ASUSWMI" then it's DCTS that can't be used for this -+ * driver, DSTS is required. -+ */ -+ if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) -+ return -ENODEV; -+ -+ err = init_rog_tunables(); -+ if (err) -+ return err; -+ -+ /* Must always be last step to ensure data is available */ -+ err = asus_fw_attr_add(); -+ if (err) -+ goto err_free_tunables; -+ -+ return 0; -+ -+err_free_tunables: -+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); -+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); -+ return err; -+} -+ -+static void __exit asus_fw_exit(void) -+{ -+ int i; -+ -+ for (i = ARRAY_SIZE(armoury_attr_groups) - 1; i >= 0; i--) { -+ if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) -+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, -+ armoury_attr_groups[i].attr_group); -+ } -+ -+ if (asus_armoury.gpu_mux_dev_id) -+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); -+ -+ if (asus_armoury.mini_led_dev_id) -+ sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); -+ -+ sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); -+ kset_unregister(asus_armoury.fw_attr_kset); -+ device_destroy(&firmware_attributes_class, MKDEV(0, 0)); -+ -+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); -+ kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); -+} -+ -+module_init(asus_fw_init); -+module_exit(asus_fw_exit); -+ -+MODULE_IMPORT_NS("ASUS_WMI"); -+MODULE_AUTHOR("Luke Jones "); -+MODULE_DESCRIPTION("ASUS BIOS Configuration Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID); ---- a/drivers/platform/x86/asus-armoury.h -+++ /dev/null -@@ -1,2556 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 -- * -- * Definitions for kernel modules using asus-armoury driver -- * -- * Copyright (c) 2024 Luke Jones -- */ -- --#ifndef _ASUS_ARMOURY_H_ --#define _ASUS_ARMOURY_H_ -- --#include --#include --#include --#include -- --#define DRIVER_NAME "asus-armoury" -- --/** -- * armoury_attr_uint_store() - Send an uint to WMI method if within min/max. -- * @kobj: Pointer to the driver object. -- * @attr: Pointer to the attribute calling this function. -- * @buf: The buffer to read from, this is parsed to `uint` type. -- * @count: Required by sysfs attribute macros, pass in from the callee attr. -- * @min: Minimum accepted value. Below this returns -EINVAL. -- * @max: Maximum accepted value. Above this returns -EINVAL. -- * @store_value: Pointer to where the parsed value should be stored. -- * @wmi_dev: The WMI function ID to use. -- * -- * This function is intended to be generic so it can be called from any "_store" -- * attribute which works only with integers. -- * -- * Integers to be sent to the WMI method is inclusive range checked and -- * an error returned if out of range. -- * -- * If the value is valid and WMI is success then the sysfs attribute is notified -- * and if asus_bios_requires_reboot() is true then reboot attribute -- * is also notified. -- * -- * Returns: Either count, or an error. -- */ --ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr, -- const char *buf, size_t count, u32 min, u32 max, -- u32 *store_value, u32 wmi_dev); -- --/** -- * armoury_attr_uint_show() - Receive an uint from a WMI method. -- * @kobj: Pointer to the driver object. -- * @attr: Pointer to the attribute calling this function. -- * @buf: The buffer to write to, as an `uint` type. -- * @wmi_dev: The WMI function ID to use. -- * -- * This function is intended to be generic so it can be called from any "_show" -- * attribute which works only with integers. -- * -- * Returns: Either count, or an error. -- */ --ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr, -- char *buf, u32 wmi_dev); -- --#define __ASUS_ATTR_RO(_func, _name) \ -- { \ -- .attr = { .name = __stringify(_name), .mode = 0444 }, \ -- .show = _func##_##_name##_show, \ -- } -- --#define __ASUS_ATTR_RO_AS(_name, _show) \ -- { \ -- .attr = { .name = __stringify(_name), .mode = 0444 }, \ -- .show = _show, \ -- } -- --#define __ASUS_ATTR_RW(_func, _name) \ -- __ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store) -- --#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \ -- static ssize_t _attr##_store(struct kobject *kobj, \ -- struct kobj_attribute *attr, \ -- const char *buf, size_t count) \ -- { \ -- return armoury_attr_uint_store(kobj, attr, buf, count, _min, \ -- _max, NULL, _wmi); \ -- } -- --#define ASUS_WMI_SHOW_INT(_attr, _wmi) \ -- static ssize_t _attr##_show(struct kobject *kobj, \ -- struct kobj_attribute *attr, char *buf) \ -- { \ -- return armoury_attr_uint_show(kobj, attr, buf, _wmi); \ -- } -- --/* Create functions and attributes for use in other macros or on their own */ -- --/* Shows a formatted static variable */ --#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \ -- static ssize_t _attrname##_##_prop##_show( \ -- struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -- { \ -- return sysfs_emit(buf, _fmt, _val); \ -- } \ -- static struct kobj_attribute attr_##_attrname##_##_prop = \ -- __ASUS_ATTR_RO(_attrname, _prop) -- --#define __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname)\ -- ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ -- static struct kobj_attribute attr_##_attrname##_current_value = \ -- __ASUS_ATTR_RO(_attrname, current_value); \ -- __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -- __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -- static struct kobj_attribute attr_##_attrname##_type = \ -- __ASUS_ATTR_RO_AS(type, enum_type_show); \ -- static struct attribute *_attrname##_attrs[] = { \ -- &attr_##_attrname##_current_value.attr, \ -- &attr_##_attrname##_display_name.attr, \ -- &attr_##_attrname##_possible_values.attr, \ -- &attr_##_attrname##_type.attr, \ -- NULL \ -- }; \ -- static const struct attribute_group _attrname##_attr_group = { \ -- .name = _fsname, .attrs = _attrname##_attrs \ -- } -- --#define __ATTR_RW_INT_GROUP_ENUM(_attrname, _minv, _maxv, _wmi, _fsname,\ -- _possible, _dispname) \ -- __WMI_STORE_INT(_attrname##_current_value, _minv, _maxv, _wmi); \ -- ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ -- static struct kobj_attribute attr_##_attrname##_current_value = \ -- __ASUS_ATTR_RW(_attrname, current_value); \ -- __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -- __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -- static struct kobj_attribute attr_##_attrname##_type = \ -- __ASUS_ATTR_RO_AS(type, enum_type_show); \ -- static struct attribute *_attrname##_attrs[] = { \ -- &attr_##_attrname##_current_value.attr, \ -- &attr_##_attrname##_display_name.attr, \ -- &attr_##_attrname##_possible_values.attr, \ -- &attr_##_attrname##_type.attr, \ -- NULL \ -- }; \ -- static const struct attribute_group _attrname##_attr_group = { \ -- .name = _fsname, .attrs = _attrname##_attrs \ -- } -- --/* Boolean style enumeration, base macro. Requires adding show/store */ --#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \ -- __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -- __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -- static struct kobj_attribute attr_##_attrname##_type = \ -- __ASUS_ATTR_RO_AS(type, enum_type_show); \ -- static struct attribute *_attrname##_attrs[] = { \ -- &attr_##_attrname##_current_value.attr, \ -- &attr_##_attrname##_display_name.attr, \ -- &attr_##_attrname##_possible_values.attr, \ -- &attr_##_attrname##_type.attr, \ -- NULL \ -- }; \ -- static const struct attribute_group _attrname##_attr_group = { \ -- .name = _fsname, .attrs = _attrname##_attrs \ -- } -- --#define ASUS_ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \ -- __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, "0;1", _dispname) -- -- --#define ASUS_ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \ -- __ATTR_RW_INT_GROUP_ENUM(_attrname, 0, 1, _wmi, _fsname, "0;1", _dispname) -- --#define ASUS_ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _possible, _dispname) \ -- __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname) -- --/* -- * Requires _current_value_show(), _current_value_show() -- */ --#define ASUS_ATTR_GROUP_BOOL(_attrname, _fsname, _dispname) \ -- static struct kobj_attribute attr_##_attrname##_current_value = \ -- __ASUS_ATTR_RW(_attrname, current_value); \ -- __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) -- --/* -- * Requires _current_value_show(), _current_value_show() -- * and _possible_values_show() -- */ --#define ASUS_ATTR_GROUP_ENUM(_attrname, _fsname, _dispname) \ -- __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -- static struct kobj_attribute attr_##_attrname##_current_value = \ -- __ASUS_ATTR_RW(_attrname, current_value); \ -- static struct kobj_attribute attr_##_attrname##_possible_values = \ -- __ASUS_ATTR_RO(_attrname, possible_values); \ -- static struct kobj_attribute attr_##_attrname##_type = \ -- __ASUS_ATTR_RO_AS(type, enum_type_show); \ -- static struct attribute *_attrname##_attrs[] = { \ -- &attr_##_attrname##_current_value.attr, \ -- &attr_##_attrname##_display_name.attr, \ -- &attr_##_attrname##_possible_values.attr, \ -- &attr_##_attrname##_type.attr, \ -- NULL \ -- }; \ -- static const struct attribute_group _attrname##_attr_group = { \ -- .name = _fsname, .attrs = _attrname##_attrs \ -- } -- --#define ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \ -- ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ -- static struct kobj_attribute attr_##_attrname##_current_value = \ -- __ASUS_ATTR_RO(_attrname, current_value); \ -- __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -- static struct kobj_attribute attr_##_attrname##_type = \ -- __ASUS_ATTR_RO_AS(type, int_type_show); \ -- static struct attribute *_attrname##_attrs[] = { \ -- &attr_##_attrname##_current_value.attr, \ -- &attr_##_attrname##_display_name.attr, \ -- &attr_##_attrname##_type.attr, NULL \ -- }; \ -- static const struct attribute_group _attrname##_attr_group = { \ -- .name = _fsname, .attrs = _attrname##_attrs \ -- } -- --/* -- * ROG PPT attributes need a little different in setup as they -- * require rog_tunables members. -- */ -- --#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ -- static ssize_t _attrname##_##_prop##_show( \ -- struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -- { \ -- struct rog_tunables *tunables = get_current_tunables(); \ -- \ -- if (!tunables || !tunables->power_limits) \ -- return -ENODEV; \ -- \ -- return sysfs_emit(buf, "%d\n", tunables->power_limits->_val); \ -- } \ -- static struct kobj_attribute attr_##_attrname##_##_prop = \ -- __ASUS_ATTR_RO(_attrname, _prop) -- --#define __ROG_TUNABLE_SHOW_DEFAULT(_attrname) \ -- static ssize_t _attrname##_default_value_show( \ -- struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -- { \ -- struct rog_tunables *tunables = get_current_tunables(); \ -- \ -- if (!tunables || !tunables->power_limits) \ -- return -ENODEV; \ -- \ -- return sysfs_emit( \ -- buf, "%d\n", \ -- tunables->power_limits->_attrname##_def ? \ -- tunables->power_limits->_attrname##_def : \ -- tunables->power_limits->_attrname##_max); \ -- } \ -- static struct kobj_attribute attr_##_attrname##_default_value = \ -- __ASUS_ATTR_RO(_attrname, default_value) -- --#define __ROG_TUNABLE_RW(_attr, _wmi) \ -- static ssize_t _attr##_current_value_store( \ -- struct kobject *kobj, struct kobj_attribute *attr, \ -- const char *buf, size_t count) \ -- { \ -- struct rog_tunables *tunables = get_current_tunables(); \ -- \ -- if (!tunables || !tunables->power_limits) \ -- return -ENODEV; \ -- \ -- if (tunables->power_limits->_attr##_min == \ -- tunables->power_limits->_attr##_max) \ -- return -EINVAL; \ -- \ -- return armoury_attr_uint_store(kobj, attr, buf, count, \ -- tunables->power_limits->_attr##_min, \ -- tunables->power_limits->_attr##_max, \ -- &tunables->_attr, _wmi); \ -- } \ -- static ssize_t _attr##_current_value_show( \ -- struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -- { \ -- struct rog_tunables *tunables = get_current_tunables(); \ -- \ -- if (!tunables) \ -- return -ENODEV; \ -- \ -- return sysfs_emit(buf, "%u\n", tunables->_attr); \ -- } \ -- static struct kobj_attribute attr_##_attr##_current_value = \ -- __ASUS_ATTR_RW(_attr, current_value) -- --#define ASUS_ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _dispname) \ -- __ROG_TUNABLE_RW(_attrname, _wmi); \ -- __ROG_TUNABLE_SHOW_DEFAULT(_attrname); \ -- __ROG_TUNABLE_SHOW(min_value, _attrname, _attrname##_min); \ -- __ROG_TUNABLE_SHOW(max_value, _attrname, _attrname##_max); \ -- __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ -- __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -- static struct kobj_attribute attr_##_attrname##_type = \ -- __ASUS_ATTR_RO_AS(type, int_type_show); \ -- static struct attribute *_attrname##_attrs[] = { \ -- &attr_##_attrname##_current_value.attr, \ -- &attr_##_attrname##_default_value.attr, \ -- &attr_##_attrname##_min_value.attr, \ -- &attr_##_attrname##_max_value.attr, \ -- &attr_##_attrname##_scalar_increment.attr, \ -- &attr_##_attrname##_display_name.attr, \ -- &attr_##_attrname##_type.attr, \ -- NULL \ -- }; \ -- static const struct attribute_group _attrname##_attr_group = { \ -- .name = _fsname, .attrs = _attrname##_attrs \ -- } -- --/* Default is always the maximum value unless *_def is specified */ --struct power_limits { -- u8 ppt_pl1_spl_min; -- u8 ppt_pl1_spl_def; -- u8 ppt_pl1_spl_max; -- u8 ppt_pl2_sppt_min; -- u8 ppt_pl2_sppt_def; -- u8 ppt_pl2_sppt_max; -- u8 ppt_pl3_fppt_min; -- u8 ppt_pl3_fppt_def; -- u8 ppt_pl3_fppt_max; -- u8 ppt_apu_sppt_min; -- u8 ppt_apu_sppt_def; -- u8 ppt_apu_sppt_max; -- u8 ppt_platform_sppt_min; -- u8 ppt_platform_sppt_def; -- u8 ppt_platform_sppt_max; -- /* Nvidia GPU specific, default is always max */ -- u8 nv_dynamic_boost_def; // unused. exists for macro -- u8 nv_dynamic_boost_min; -- u8 nv_dynamic_boost_max; -- u8 nv_temp_target_def; // unused. exists for macro -- u8 nv_temp_target_min; -- u8 nv_temp_target_max; -- u8 nv_tgp_def; // unused. exists for macro -- u8 nv_tgp_min; -- u8 nv_tgp_max; --}; -- --struct power_data { -- const struct power_limits *ac_data; -- const struct power_limits *dc_data; -- bool requires_fan_curve; --}; -- --/* -- * For each available attribute there must be a min and a max. -- * _def is not required and will be assumed to be default == max if missing. -- */ --static const struct dmi_system_id power_limits[] = { -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA401EA"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 95, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 100, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 71, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 71, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 71, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA401KM"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .nv_dynamic_boost_max = 15, -- .nv_dynamic_boost_min = 5, -- .nv_temp_target_max = 87, -- .nv_temp_target_min = 75, -- .nv_tgp_max = 95, -- .nv_tgp_min = 55, -- .ppt_pl1_spl_max = 80, -- .ppt_pl1_spl_min = 15, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- }, -- .dc_data = &(struct power_limits) { -- .nv_temp_target_max = 87, -- .nv_temp_target_min = 75, -- .ppt_pl1_spl_max = 35, -- .ppt_pl1_spl_min = 25, -- .ppt_pl2_sppt_max = 44, -- .ppt_pl2_sppt_min = 31, -- .ppt_pl3_fppt_max = 65, -- .ppt_pl3_fppt_min = 45, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA401UM"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 15, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 31, -- .ppt_pl2_sppt_max = 44, -- .ppt_pl3_fppt_min = 45, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA401UV"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 75, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 31, -- .ppt_pl2_sppt_max = 44, -- .ppt_pl3_fppt_min = 45, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA401W"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 75, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 30, -- .ppt_pl2_sppt_min = 31, -- .ppt_pl2_sppt_max = 44, -- .ppt_pl3_fppt_min = 45, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA507N"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA507UV"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA507R"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA507X"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 85, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA507Z"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 105, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 15, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 85, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 60, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA607NU"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 25, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA607P"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_def = 100, -- .ppt_pl1_spl_max = 135, -- .ppt_pl2_sppt_min = 30, -- .ppt_pl2_sppt_def = 115, -- .ppt_pl2_sppt_max = 135, -- .ppt_pl3_fppt_min = 30, -- .ppt_pl3_fppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_def = 60, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 25, -- .ppt_pl3_fppt_max = 80, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA608UM"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 90, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_def = 65, -- .ppt_pl3_fppt_max = 90, -- .nv_dynamic_boost_min = 10, -- .nv_dynamic_boost_max = 15, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 100, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA608WI"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 90, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 90, -- .ppt_pl2_sppt_max = 90, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_def = 90, -- .ppt_pl3_fppt_max = 90, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_def = 65, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA608WV"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .nv_dynamic_boost_max = 25, -- .nv_dynamic_boost_min = 5, -- .nv_temp_target_max = 87, -- .nv_temp_target_min = 75, -- .nv_tgp_max = 115, -- .nv_tgp_min = 55, -- .ppt_pl1_spl_max = 90, -- .ppt_pl1_spl_min = 15, -- .ppt_pl2_sppt_max = 90, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl3_fppt_max = 90, -- .ppt_pl3_fppt_min = 35, -- }, -- .dc_data = &(struct power_limits) { -- .nv_temp_target_max = 87, -- .nv_temp_target_min = 75, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 65, -- .ppt_pl1_spl_min = 15, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA617NS"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 15, -- .ppt_apu_sppt_max = 80, -- .ppt_platform_sppt_min = 30, -- .ppt_platform_sppt_max = 120, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 25, -- .ppt_apu_sppt_max = 35, -- .ppt_platform_sppt_min = 45, -- .ppt_platform_sppt_max = 100, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA617NT"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 15, -- .ppt_apu_sppt_max = 80, -- .ppt_platform_sppt_min = 30, -- .ppt_platform_sppt_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 15, -- .ppt_apu_sppt_max = 45, -- .ppt_platform_sppt_min = 30, -- .ppt_platform_sppt_max = 50, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA617XS"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 15, -- .ppt_apu_sppt_max = 80, -- .ppt_platform_sppt_min = 30, -- .ppt_platform_sppt_max = 120, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 25, -- .ppt_apu_sppt_max = 35, -- .ppt_platform_sppt_min = 45, -- .ppt_platform_sppt_max = 100, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FA617XT"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 15, -- .ppt_apu_sppt_max = 80, -- .ppt_platform_sppt_min = 30, -- .ppt_platform_sppt_max = 145, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 25, -- .ppt_apu_sppt_max = 35, -- .ppt_platform_sppt_min = 45, -- .ppt_platform_sppt_max = 100, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FX507VI"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 135, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 60, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FX507VV"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 115, -- .ppt_pl1_spl_max = 135, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 60, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FX507Z"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 15, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 60, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FX517ZR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 60, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FX607VU"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 115, -- .ppt_pl1_spl_max = 135, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 60, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "FX608JPR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 100, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 10, -- .nv_dynamic_boost_max = 15, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 100, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 53, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA401Q"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_max = 80, -- }, -- .dc_data = NULL, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA402NJ"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 35, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_def = 65, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_def = 10, -- .nv_dynamic_boost_max = 15, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- // This model is full AMD. No Nvidia dGPU. -- DMI_MATCH(DMI_BOARD_NAME, "GA402R"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 15, -- .ppt_apu_sppt_max = 80, -- .ppt_platform_sppt_min = 30, -- .ppt_platform_sppt_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_apu_sppt_min = 25, -- .ppt_apu_sppt_def = 30, -- .ppt_apu_sppt_max = 45, -- .ppt_platform_sppt_min = 40, -- .ppt_platform_sppt_max = 60, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA402X"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 35, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_def = 65, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA403UI"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 65, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA403UM"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 0, -- .nv_dynamic_boost_max = 15, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 85, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA403UV"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 65, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA403WM"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 0, -- .nv_dynamic_boost_max = 15, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 85, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA403WR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 0, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 80, -- .nv_tgp_max = 95, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA403WW"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 0, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 80, -- .nv_tgp_max = 95, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA503QM"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 35, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_max = 80, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA503QR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 35, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_max = 80, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA503R"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 35, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 65, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 25, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 60, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GA605W"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 85, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 31, -- .ppt_pl2_sppt_max = 44, -- .ppt_pl3_fppt_min = 45, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU603Z"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 60, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 40, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 40, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- } -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU604V"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 65, -- .ppt_pl1_spl_max = 120, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_max = 150, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 40, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 40, -- .ppt_pl2_sppt_max = 60, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU605CP"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 45, -- .ppt_pl1_spl_max = 75, -- .ppt_pl2_sppt_min = 56, -- .ppt_pl2_sppt_max = 95, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 15, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_def = 75, -- .nv_tgp_max = 95, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 75, -- .ppt_pl2_sppt_min = 32, -- .ppt_pl2_sppt_max = 95, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU605CR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 38, -- .ppt_pl2_sppt_max = 110, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 80, -- .nv_tgp_def = 90, -- .nv_tgp_max = 105, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 38, -- .ppt_pl2_sppt_max = 110, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU605CW"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 45, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 56, -- .ppt_pl2_sppt_max = 110, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 80, -- .nv_tgp_def = 90, -- .nv_tgp_max = 110, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 32, -- .ppt_pl2_sppt_max = 110, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU605CX"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 45, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 56, -- .ppt_pl2_sppt_max = 110, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 7, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 95, -- .nv_tgp_def = 100, -- .nv_tgp_max = 110, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 32, -- .ppt_pl2_sppt_max = 110, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU605MU"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 85, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 38, -- .ppt_pl2_sppt_max = 53, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GU605M"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 38, -- .ppt_pl2_sppt_max = 53, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GV301Q"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_max = 80, -- }, -- .dc_data = NULL, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GV301R"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 45, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 54, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GV302XU"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 60, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GV302XV"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 60, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 35, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GV601R"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 35, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 100, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_def = 80, -- .ppt_pl3_fppt_max = 125, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 28, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 54, -- .ppt_pl2_sppt_max = 60, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_def = 80, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GV601V"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 100, -- .ppt_pl1_spl_max = 110, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 40, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 40, -- .ppt_pl2_sppt_max = 60, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GX650P"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 110, -- .ppt_pl1_spl_max = 130, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 125, -- .ppt_pl2_sppt_max = 130, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_def = 125, -- .ppt_pl3_fppt_max = 135, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_def = 25, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_def = 35, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_def = 42, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GX650RX"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 70, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_def = 70, -- .ppt_pl2_sppt_max = 100, -- .ppt_pl3_fppt_min = 28, -- .ppt_pl3_fppt_def = 110, -- .ppt_pl3_fppt_max = 125, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 76, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 50, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 50, -- .ppt_pl3_fppt_min = 28, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 76, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "GZ302EA"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 60, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 32, -- .ppt_pl2_sppt_def = 75, -- .ppt_pl2_sppt_max = 92, -- .ppt_pl3_fppt_min = 45, -- .ppt_pl3_fppt_def = 86, -- .ppt_pl3_fppt_max = 93, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 32, -- .ppt_pl2_sppt_def = 52, -- .ppt_pl2_sppt_max = 92, -- .ppt_pl3_fppt_min = 45, -- .ppt_pl3_fppt_def = 71, -- .ppt_pl3_fppt_max = 93, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G513I"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- /* Yes this laptop is very limited */ -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_max = 80, -- }, -- .dc_data = NULL, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G513QM"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- /* Yes this laptop is very limited */ -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 100, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_max = 190, -- }, -- .dc_data = NULL, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G513QY"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- /* Advantage Edition Laptop, no PL1 or PL2 limits */ -- .ppt_apu_sppt_min = 15, -- .ppt_apu_sppt_max = 100, -- .ppt_platform_sppt_min = 70, -- .ppt_platform_sppt_max = 190, -- }, -- .dc_data = NULL, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G513R"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 35, -- .ppt_pl1_spl_max = 90, -- .ppt_pl2_sppt_min = 54, -- .ppt_pl2_sppt_max = 100, -- .ppt_pl3_fppt_min = 54, -- .ppt_pl3_fppt_max = 125, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 50, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 50, -- .ppt_pl3_fppt_min = 28, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G614FP"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_max = 120, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_def = 140, -- .ppt_pl2_sppt_max = 165, -- .ppt_pl3_fppt_min = 65, -- .ppt_pl3_fppt_def = 140, -- .ppt_pl3_fppt_max = 165, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 15, -- .nv_tgp_min = 50, -- .nv_tgp_max = 100, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 75, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G614FR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_max = 120, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_def = 140, -- .ppt_pl2_sppt_max = 162, -- .ppt_pl3_fppt_min = 65, -- .ppt_pl3_fppt_def = 140, -- .ppt_pl3_fppt_max = 162, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_tgp_min = 65, -- .nv_tgp_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 75, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G614J"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 140, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G614PR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_max = 120, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_def = 140, -- .ppt_pl2_sppt_max = 145, -- .ppt_pl3_fppt_min = 65, -- .ppt_pl3_fppt_def = 140, -- .ppt_pl3_fppt_max = 145, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_tgp_min = 65, -- .nv_tgp_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 75, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G615LR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 140, -- .ppt_pl1_spl_max = 175, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_tgp_min = 65, -- .nv_tgp_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G634J"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 140, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G635LX"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 140, -- .ppt_pl1_spl_max = 175, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 80, -- .nv_tgp_max = 150, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G713PV"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_def = 120, -- .ppt_pl1_spl_max = 130, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_def = 125, -- .ppt_pl2_sppt_max = 130, -- .ppt_pl3_fppt_min = 65, -- .ppt_pl3_fppt_def = 125, -- .ppt_pl3_fppt_max = 130, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 75, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G733C"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 170, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 35, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G733P"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 30, -- .ppt_pl1_spl_def = 100, -- .ppt_pl1_spl_max = 130, -- .ppt_pl2_sppt_min = 65, -- .ppt_pl2_sppt_def = 125, -- .ppt_pl2_sppt_max = 130, -- .ppt_pl3_fppt_min = 65, -- .ppt_pl3_fppt_def = 125, -- .ppt_pl3_fppt_max = 130, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 65, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 65, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 75, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G733QS"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_max = 80, -- }, -- .requires_fan_curve = false, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G814J"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 140, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 140, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G834J"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_max = 140, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G835LR"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 140, -- .ppt_pl1_spl_max = 175, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 65, -- .nv_tgp_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "G835LW"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 28, -- .ppt_pl1_spl_def = 140, -- .ppt_pl1_spl_max = 175, -- .ppt_pl2_sppt_min = 28, -- .ppt_pl2_sppt_max = 175, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 25, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 80, -- .nv_tgp_max = 150, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 55, -- .ppt_pl2_sppt_min = 25, -- .ppt_pl2_sppt_max = 70, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- .requires_fan_curve = true, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "H7606W"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 15, -- .ppt_pl1_spl_max = 80, -- .ppt_pl2_sppt_min = 35, -- .ppt_pl2_sppt_max = 80, -- .ppt_pl3_fppt_min = 35, -- .ppt_pl3_fppt_max = 80, -- .nv_dynamic_boost_min = 5, -- .nv_dynamic_boost_max = 20, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- .nv_tgp_min = 55, -- .nv_tgp_max = 85, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 25, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 31, -- .ppt_pl2_sppt_max = 44, -- .ppt_pl3_fppt_min = 45, -- .ppt_pl3_fppt_max = 65, -- .nv_temp_target_min = 75, -- .nv_temp_target_max = 87, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "HN7306EA"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 35, -- .ppt_pl1_spl_def = 60, -- .ppt_pl1_spl_max = 85, -- .ppt_pl2_sppt_min = 40, -- .ppt_pl2_sppt_def = 70, -- .ppt_pl2_sppt_max = 95, -- .ppt_pl3_fppt_min = 50, -- .ppt_pl3_fppt_def = 85, -- .ppt_pl3_fppt_max = 115, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 35, -- .ppt_pl1_spl_def = 45, -- .ppt_pl1_spl_max = 60, -- .ppt_pl2_sppt_min = 40, -- .ppt_pl2_sppt_def = 55, -- .ppt_pl2_sppt_max = 70, -- .ppt_pl3_fppt_min = 50, -- .ppt_pl3_fppt_def = 65, -- .ppt_pl3_fppt_max = 85, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "RC71"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 7, -- .ppt_pl1_spl_max = 30, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_max = 43, -- .ppt_pl3_fppt_min = 15, -- .ppt_pl3_fppt_max = 53, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 7, -- .ppt_pl1_spl_def = 15, -- .ppt_pl1_spl_max = 25, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_def = 20, -- .ppt_pl2_sppt_max = 30, -- .ppt_pl3_fppt_min = 15, -- .ppt_pl3_fppt_def = 25, -- .ppt_pl3_fppt_max = 35, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "RC72"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 7, -- .ppt_pl1_spl_max = 30, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_max = 43, -- .ppt_pl3_fppt_min = 15, -- .ppt_pl3_fppt_max = 53, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 7, -- .ppt_pl1_spl_def = 17, -- .ppt_pl1_spl_max = 25, -- .ppt_pl2_sppt_min = 15, -- .ppt_pl2_sppt_def = 24, -- .ppt_pl2_sppt_max = 30, -- .ppt_pl3_fppt_min = 15, -- .ppt_pl3_fppt_def = 30, -- .ppt_pl3_fppt_max = 35, -- }, -- }, -- }, -- { -- .matches = { -- DMI_MATCH(DMI_BOARD_NAME, "RC73XA"), -- }, -- .driver_data = &(struct power_data) { -- .ac_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 7, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 14, -- .ppt_pl2_sppt_max = 45, -- .ppt_pl3_fppt_min = 19, -- .ppt_pl3_fppt_max = 55, -- }, -- .dc_data = &(struct power_limits) { -- .ppt_pl1_spl_min = 7, -- .ppt_pl1_spl_def = 17, -- .ppt_pl1_spl_max = 35, -- .ppt_pl2_sppt_min = 13, -- .ppt_pl2_sppt_def = 21, -- .ppt_pl2_sppt_max = 45, -- .ppt_pl3_fppt_min = 19, -- .ppt_pl3_fppt_def = 26, -- .ppt_pl3_fppt_max = 55, -- }, -- }, -- }, -- {} --}; -- --#endif /* _ASUS_ARMOURY_H_ */ ---- /dev/null -+++ b/drivers/platform/asus/asus-armoury.h -@@ -0,0 +1,2556 @@ -+/* SPDX-License-Identifier: GPL-2.0 -+ * -+ * Definitions for kernel modules using asus-armoury driver -+ * -+ * Copyright (c) 2024 Luke Jones -+ */ -+ -+#ifndef _ASUS_ARMOURY_H_ -+#define _ASUS_ARMOURY_H_ -+ -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "asus-armoury" -+ -+/** -+ * armoury_attr_uint_store() - Send an uint to WMI method if within min/max. -+ * @kobj: Pointer to the driver object. -+ * @attr: Pointer to the attribute calling this function. -+ * @buf: The buffer to read from, this is parsed to `uint` type. -+ * @count: Required by sysfs attribute macros, pass in from the callee attr. -+ * @min: Minimum accepted value. Below this returns -EINVAL. -+ * @max: Maximum accepted value. Above this returns -EINVAL. -+ * @store_value: Pointer to where the parsed value should be stored. -+ * @wmi_dev: The WMI function ID to use. -+ * -+ * This function is intended to be generic so it can be called from any "_store" -+ * attribute which works only with integers. -+ * -+ * Integers to be sent to the WMI method is inclusive range checked and -+ * an error returned if out of range. -+ * -+ * If the value is valid and WMI is success then the sysfs attribute is notified -+ * and if asus_bios_requires_reboot() is true then reboot attribute -+ * is also notified. -+ * -+ * Returns: Either count, or an error. -+ */ -+ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t count, u32 min, u32 max, -+ u32 *store_value, u32 wmi_dev); -+ -+/** -+ * armoury_attr_uint_show() - Receive an uint from a WMI method. -+ * @kobj: Pointer to the driver object. -+ * @attr: Pointer to the attribute calling this function. -+ * @buf: The buffer to write to, as an `uint` type. -+ * @wmi_dev: The WMI function ID to use. -+ * -+ * This function is intended to be generic so it can be called from any "_show" -+ * attribute which works only with integers. -+ * -+ * Returns: Either count, or an error. -+ */ -+ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf, u32 wmi_dev); -+ -+#define __ASUS_ATTR_RO(_func, _name) \ -+ { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = _func##_##_name##_show, \ -+ } -+ -+#define __ASUS_ATTR_RO_AS(_name, _show) \ -+ { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = _show, \ -+ } -+ -+#define __ASUS_ATTR_RW(_func, _name) \ -+ __ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store) -+ -+#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \ -+ static ssize_t _attr##_store(struct kobject *kobj, \ -+ struct kobj_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ return armoury_attr_uint_store(kobj, attr, buf, count, _min, \ -+ _max, NULL, _wmi); \ -+ } -+ -+#define ASUS_WMI_SHOW_INT(_attr, _wmi) \ -+ static ssize_t _attr##_show(struct kobject *kobj, \ -+ struct kobj_attribute *attr, char *buf) \ -+ { \ -+ return armoury_attr_uint_show(kobj, attr, buf, _wmi); \ -+ } -+ -+/* Create functions and attributes for use in other macros or on their own */ -+ -+/* Shows a formatted static variable */ -+#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \ -+ static ssize_t _attrname##_##_prop##_show( \ -+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -+ { \ -+ return sysfs_emit(buf, _fmt, _val); \ -+ } \ -+ static struct kobj_attribute attr_##_attrname##_##_prop = \ -+ __ASUS_ATTR_RO(_attrname, _prop) -+ -+#define __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname)\ -+ ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ -+ static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RO(_attrname, current_value); \ -+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+ __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -+ static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+ static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+ }; \ -+ static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, .attrs = _attrname##_attrs \ -+ } -+ -+#define __ATTR_RW_INT_GROUP_ENUM(_attrname, _minv, _maxv, _wmi, _fsname,\ -+ _possible, _dispname) \ -+ __WMI_STORE_INT(_attrname##_current_value, _minv, _maxv, _wmi); \ -+ ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ -+ static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+ __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -+ static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+ static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+ }; \ -+ static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, .attrs = _attrname##_attrs \ -+ } -+ -+/* Boolean style enumeration, base macro. Requires adding show/store */ -+#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \ -+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+ __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \ -+ static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+ static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+ }; \ -+ static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, .attrs = _attrname##_attrs \ -+ } -+ -+#define ASUS_ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \ -+ __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, "0;1", _dispname) -+ -+ -+#define ASUS_ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \ -+ __ATTR_RW_INT_GROUP_ENUM(_attrname, 0, 1, _wmi, _fsname, "0;1", _dispname) -+ -+#define ASUS_ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _possible, _dispname) \ -+ __ATTR_RO_INT_GROUP_ENUM(_attrname, _wmi, _fsname, _possible, _dispname) -+ -+/* -+ * Requires _current_value_show(), _current_value_show() -+ */ -+#define ASUS_ATTR_GROUP_BOOL(_attrname, _fsname, _dispname) \ -+ static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname) -+ -+/* -+ * Requires _current_value_show(), _current_value_show() -+ * and _possible_values_show() -+ */ -+#define ASUS_ATTR_GROUP_ENUM(_attrname, _fsname, _dispname) \ -+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+ static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RW(_attrname, current_value); \ -+ static struct kobj_attribute attr_##_attrname##_possible_values = \ -+ __ASUS_ATTR_RO(_attrname, possible_values); \ -+ static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, enum_type_show); \ -+ static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_possible_values.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+ }; \ -+ static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, .attrs = _attrname##_attrs \ -+ } -+ -+#define ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \ -+ ASUS_WMI_SHOW_INT(_attrname##_current_value, _wmi); \ -+ static struct kobj_attribute attr_##_attrname##_current_value = \ -+ __ASUS_ATTR_RO(_attrname, current_value); \ -+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+ static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+ static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, NULL \ -+ }; \ -+ static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, .attrs = _attrname##_attrs \ -+ } -+ -+/* -+ * ROG PPT attributes need a little different in setup as they -+ * require rog_tunables members. -+ */ -+ -+#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ -+ static ssize_t _attrname##_##_prop##_show( \ -+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -+ { \ -+ struct rog_tunables *tunables = get_current_tunables(); \ -+ \ -+ if (!tunables || !tunables->power_limits) \ -+ return -ENODEV; \ -+ \ -+ return sysfs_emit(buf, "%d\n", tunables->power_limits->_val); \ -+ } \ -+ static struct kobj_attribute attr_##_attrname##_##_prop = \ -+ __ASUS_ATTR_RO(_attrname, _prop) -+ -+#define __ROG_TUNABLE_SHOW_DEFAULT(_attrname) \ -+ static ssize_t _attrname##_default_value_show( \ -+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -+ { \ -+ struct rog_tunables *tunables = get_current_tunables(); \ -+ \ -+ if (!tunables || !tunables->power_limits) \ -+ return -ENODEV; \ -+ \ -+ return sysfs_emit( \ -+ buf, "%d\n", \ -+ tunables->power_limits->_attrname##_def ? \ -+ tunables->power_limits->_attrname##_def : \ -+ tunables->power_limits->_attrname##_max); \ -+ } \ -+ static struct kobj_attribute attr_##_attrname##_default_value = \ -+ __ASUS_ATTR_RO(_attrname, default_value) -+ -+#define __ROG_TUNABLE_RW(_attr, _wmi) \ -+ static ssize_t _attr##_current_value_store( \ -+ struct kobject *kobj, struct kobj_attribute *attr, \ -+ const char *buf, size_t count) \ -+ { \ -+ struct rog_tunables *tunables = get_current_tunables(); \ -+ \ -+ if (!tunables || !tunables->power_limits) \ -+ return -ENODEV; \ -+ \ -+ if (tunables->power_limits->_attr##_min == \ -+ tunables->power_limits->_attr##_max) \ -+ return -EINVAL; \ -+ \ -+ return armoury_attr_uint_store(kobj, attr, buf, count, \ -+ tunables->power_limits->_attr##_min, \ -+ tunables->power_limits->_attr##_max, \ -+ &tunables->_attr, _wmi); \ -+ } \ -+ static ssize_t _attr##_current_value_show( \ -+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ -+ { \ -+ struct rog_tunables *tunables = get_current_tunables(); \ -+ \ -+ if (!tunables) \ -+ return -ENODEV; \ -+ \ -+ return sysfs_emit(buf, "%u\n", tunables->_attr); \ -+ } \ -+ static struct kobj_attribute attr_##_attr##_current_value = \ -+ __ASUS_ATTR_RW(_attr, current_value) -+ -+#define ASUS_ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _dispname) \ -+ __ROG_TUNABLE_RW(_attrname, _wmi); \ -+ __ROG_TUNABLE_SHOW_DEFAULT(_attrname); \ -+ __ROG_TUNABLE_SHOW(min_value, _attrname, _attrname##_min); \ -+ __ROG_TUNABLE_SHOW(max_value, _attrname, _attrname##_max); \ -+ __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ -+ __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ -+ static struct kobj_attribute attr_##_attrname##_type = \ -+ __ASUS_ATTR_RO_AS(type, int_type_show); \ -+ static struct attribute *_attrname##_attrs[] = { \ -+ &attr_##_attrname##_current_value.attr, \ -+ &attr_##_attrname##_default_value.attr, \ -+ &attr_##_attrname##_min_value.attr, \ -+ &attr_##_attrname##_max_value.attr, \ -+ &attr_##_attrname##_scalar_increment.attr, \ -+ &attr_##_attrname##_display_name.attr, \ -+ &attr_##_attrname##_type.attr, \ -+ NULL \ -+ }; \ -+ static const struct attribute_group _attrname##_attr_group = { \ -+ .name = _fsname, .attrs = _attrname##_attrs \ -+ } -+ -+/* Default is always the maximum value unless *_def is specified */ -+struct power_limits { -+ u8 ppt_pl1_spl_min; -+ u8 ppt_pl1_spl_def; -+ u8 ppt_pl1_spl_max; -+ u8 ppt_pl2_sppt_min; -+ u8 ppt_pl2_sppt_def; -+ u8 ppt_pl2_sppt_max; -+ u8 ppt_pl3_fppt_min; -+ u8 ppt_pl3_fppt_def; -+ u8 ppt_pl3_fppt_max; -+ u8 ppt_apu_sppt_min; -+ u8 ppt_apu_sppt_def; -+ u8 ppt_apu_sppt_max; -+ u8 ppt_platform_sppt_min; -+ u8 ppt_platform_sppt_def; -+ u8 ppt_platform_sppt_max; -+ /* Nvidia GPU specific, default is always max */ -+ u8 nv_dynamic_boost_def; // unused. exists for macro -+ u8 nv_dynamic_boost_min; -+ u8 nv_dynamic_boost_max; -+ u8 nv_temp_target_def; // unused. exists for macro -+ u8 nv_temp_target_min; -+ u8 nv_temp_target_max; -+ u8 nv_tgp_def; // unused. exists for macro -+ u8 nv_tgp_min; -+ u8 nv_tgp_max; -+}; -+ -+struct power_data { -+ const struct power_limits *ac_data; -+ const struct power_limits *dc_data; -+ bool requires_fan_curve; -+}; -+ -+/* -+ * For each available attribute there must be a min and a max. -+ * _def is not required and will be assumed to be default == max if missing. -+ */ -+static const struct dmi_system_id power_limits[] = { -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA401EA"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 95, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 100, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 71, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 71, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 71, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA401KM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .nv_dynamic_boost_max = 15, -+ .nv_dynamic_boost_min = 5, -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .nv_tgp_max = 95, -+ .nv_tgp_min = 55, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ }, -+ .dc_data = &(struct power_limits) { -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl2_sppt_max = 44, -+ .ppt_pl2_sppt_min = 31, -+ .ppt_pl3_fppt_max = 65, -+ .ppt_pl3_fppt_min = 45, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA401UM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 15, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 31, -+ .ppt_pl2_sppt_max = 44, -+ .ppt_pl3_fppt_min = 45, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA401UV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 75, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 31, -+ .ppt_pl2_sppt_max = 44, -+ .ppt_pl3_fppt_min = 45, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA401W"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 75, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 30, -+ .ppt_pl2_sppt_min = 31, -+ .ppt_pl2_sppt_max = 44, -+ .ppt_pl3_fppt_min = 45, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA507N"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA507UV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA507R"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA507X"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 85, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA507Z"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 105, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 15, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 85, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA607NU"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 25, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA607P"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_def = 100, -+ .ppt_pl1_spl_max = 135, -+ .ppt_pl2_sppt_min = 30, -+ .ppt_pl2_sppt_def = 115, -+ .ppt_pl2_sppt_max = 135, -+ .ppt_pl3_fppt_min = 30, -+ .ppt_pl3_fppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_def = 60, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 25, -+ .ppt_pl3_fppt_max = 80, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA608UM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 90, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_def = 65, -+ .ppt_pl3_fppt_max = 90, -+ .nv_dynamic_boost_min = 10, -+ .nv_dynamic_boost_max = 15, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 100, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA608WI"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 90, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 90, -+ .ppt_pl2_sppt_max = 90, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_def = 90, -+ .ppt_pl3_fppt_max = 90, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_def = 65, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA608WV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .nv_dynamic_boost_max = 25, -+ .nv_dynamic_boost_min = 5, -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .nv_tgp_max = 115, -+ .nv_tgp_min = 55, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl2_sppt_max = 90, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl3_fppt_max = 90, -+ .ppt_pl3_fppt_min = 35, -+ }, -+ .dc_data = &(struct power_limits) { -+ .nv_temp_target_max = 87, -+ .nv_temp_target_min = 75, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA617NS"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 15, -+ .ppt_apu_sppt_max = 80, -+ .ppt_platform_sppt_min = 30, -+ .ppt_platform_sppt_max = 120, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 25, -+ .ppt_apu_sppt_max = 35, -+ .ppt_platform_sppt_min = 45, -+ .ppt_platform_sppt_max = 100, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA617NT"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 15, -+ .ppt_apu_sppt_max = 80, -+ .ppt_platform_sppt_min = 30, -+ .ppt_platform_sppt_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 15, -+ .ppt_apu_sppt_max = 45, -+ .ppt_platform_sppt_min = 30, -+ .ppt_platform_sppt_max = 50, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA617XS"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 15, -+ .ppt_apu_sppt_max = 80, -+ .ppt_platform_sppt_min = 30, -+ .ppt_platform_sppt_max = 120, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 25, -+ .ppt_apu_sppt_max = 35, -+ .ppt_platform_sppt_min = 45, -+ .ppt_platform_sppt_max = 100, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FA617XT"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 15, -+ .ppt_apu_sppt_max = 80, -+ .ppt_platform_sppt_min = 30, -+ .ppt_platform_sppt_max = 145, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 25, -+ .ppt_apu_sppt_max = 35, -+ .ppt_platform_sppt_min = 45, -+ .ppt_platform_sppt_max = 100, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FX507VI"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 135, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FX507VV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 115, -+ .ppt_pl1_spl_max = 135, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FX507Z"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 15, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 60, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FX517ZR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FX607VU"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 115, -+ .ppt_pl1_spl_max = 135, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "FX608JPR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 100, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 10, -+ .nv_dynamic_boost_max = 15, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 100, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 53, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA401Q"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_max = 80, -+ }, -+ .dc_data = NULL, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA402NJ"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 35, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_def = 65, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_def = 10, -+ .nv_dynamic_boost_max = 15, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ // This model is full AMD. No Nvidia dGPU. -+ DMI_MATCH(DMI_BOARD_NAME, "GA402R"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 15, -+ .ppt_apu_sppt_max = 80, -+ .ppt_platform_sppt_min = 30, -+ .ppt_platform_sppt_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_apu_sppt_min = 25, -+ .ppt_apu_sppt_def = 30, -+ .ppt_apu_sppt_max = 45, -+ .ppt_platform_sppt_min = 40, -+ .ppt_platform_sppt_max = 60, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA402X"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 35, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_def = 65, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA403UI"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 65, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA403UM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 0, -+ .nv_dynamic_boost_max = 15, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 85, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA403UV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 65, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA403WM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 0, -+ .nv_dynamic_boost_max = 15, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 85, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA403WR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 0, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 80, -+ .nv_tgp_max = 95, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA403WW"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 0, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 80, -+ .nv_tgp_max = 95, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA503QM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 35, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_max = 80, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA503QR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 35, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_max = 80, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA503R"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 35, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 65, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 25, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 60, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GA605W"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 85, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 31, -+ .ppt_pl2_sppt_max = 44, -+ .ppt_pl3_fppt_min = 45, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU603Z"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 60, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 40, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 40, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ } -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU604V"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 65, -+ .ppt_pl1_spl_max = 120, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_max = 150, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 40, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 40, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU605CP"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 45, -+ .ppt_pl1_spl_max = 75, -+ .ppt_pl2_sppt_min = 56, -+ .ppt_pl2_sppt_max = 95, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 15, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_def = 75, -+ .nv_tgp_max = 95, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 75, -+ .ppt_pl2_sppt_min = 32, -+ .ppt_pl2_sppt_max = 95, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU605CR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 38, -+ .ppt_pl2_sppt_max = 110, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 80, -+ .nv_tgp_def = 90, -+ .nv_tgp_max = 105, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 38, -+ .ppt_pl2_sppt_max = 110, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU605CW"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 45, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 56, -+ .ppt_pl2_sppt_max = 110, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 80, -+ .nv_tgp_def = 90, -+ .nv_tgp_max = 110, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 32, -+ .ppt_pl2_sppt_max = 110, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU605CX"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 45, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 56, -+ .ppt_pl2_sppt_max = 110, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 7, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 95, -+ .nv_tgp_def = 100, -+ .nv_tgp_max = 110, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 32, -+ .ppt_pl2_sppt_max = 110, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU605MU"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 85, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 38, -+ .ppt_pl2_sppt_max = 53, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GU605M"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 38, -+ .ppt_pl2_sppt_max = 53, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GV301Q"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_max = 80, -+ }, -+ .dc_data = NULL, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GV301R"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 45, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 54, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GV302XU"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 60, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GV302XV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 60, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 35, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GV601R"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 35, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 100, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_def = 80, -+ .ppt_pl3_fppt_max = 125, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 28, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 54, -+ .ppt_pl2_sppt_max = 60, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_def = 80, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GV601V"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 100, -+ .ppt_pl1_spl_max = 110, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 40, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 40, -+ .ppt_pl2_sppt_max = 60, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GX650P"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 110, -+ .ppt_pl1_spl_max = 130, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 125, -+ .ppt_pl2_sppt_max = 130, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_def = 125, -+ .ppt_pl3_fppt_max = 135, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_def = 25, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_def = 35, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_def = 42, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GX650RX"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 70, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_def = 70, -+ .ppt_pl2_sppt_max = 100, -+ .ppt_pl3_fppt_min = 28, -+ .ppt_pl3_fppt_def = 110, -+ .ppt_pl3_fppt_max = 125, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 76, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 50, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 50, -+ .ppt_pl3_fppt_min = 28, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 76, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "GZ302EA"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 60, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 32, -+ .ppt_pl2_sppt_def = 75, -+ .ppt_pl2_sppt_max = 92, -+ .ppt_pl3_fppt_min = 45, -+ .ppt_pl3_fppt_def = 86, -+ .ppt_pl3_fppt_max = 93, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 32, -+ .ppt_pl2_sppt_def = 52, -+ .ppt_pl2_sppt_max = 92, -+ .ppt_pl3_fppt_min = 45, -+ .ppt_pl3_fppt_def = 71, -+ .ppt_pl3_fppt_max = 93, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G513I"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ /* Yes this laptop is very limited */ -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_max = 80, -+ }, -+ .dc_data = NULL, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G513QM"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ /* Yes this laptop is very limited */ -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 100, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_max = 190, -+ }, -+ .dc_data = NULL, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G513QY"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ /* Advantage Edition Laptop, no PL1 or PL2 limits */ -+ .ppt_apu_sppt_min = 15, -+ .ppt_apu_sppt_max = 100, -+ .ppt_platform_sppt_min = 70, -+ .ppt_platform_sppt_max = 190, -+ }, -+ .dc_data = NULL, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G513R"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 35, -+ .ppt_pl1_spl_max = 90, -+ .ppt_pl2_sppt_min = 54, -+ .ppt_pl2_sppt_max = 100, -+ .ppt_pl3_fppt_min = 54, -+ .ppt_pl3_fppt_max = 125, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 50, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 50, -+ .ppt_pl3_fppt_min = 28, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G614FP"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_max = 120, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_def = 140, -+ .ppt_pl2_sppt_max = 165, -+ .ppt_pl3_fppt_min = 65, -+ .ppt_pl3_fppt_def = 140, -+ .ppt_pl3_fppt_max = 165, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 15, -+ .nv_tgp_min = 50, -+ .nv_tgp_max = 100, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 75, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G614FR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_max = 120, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_def = 140, -+ .ppt_pl2_sppt_max = 162, -+ .ppt_pl3_fppt_min = 65, -+ .ppt_pl3_fppt_def = 140, -+ .ppt_pl3_fppt_max = 162, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_tgp_min = 65, -+ .nv_tgp_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 75, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G614J"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 140, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G614PR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_max = 120, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_def = 140, -+ .ppt_pl2_sppt_max = 145, -+ .ppt_pl3_fppt_min = 65, -+ .ppt_pl3_fppt_def = 140, -+ .ppt_pl3_fppt_max = 145, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_tgp_min = 65, -+ .nv_tgp_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 75, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G615LR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 140, -+ .ppt_pl1_spl_max = 175, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_tgp_min = 65, -+ .nv_tgp_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G634J"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 140, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G635LX"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 140, -+ .ppt_pl1_spl_max = 175, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 80, -+ .nv_tgp_max = 150, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G713PV"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_def = 120, -+ .ppt_pl1_spl_max = 130, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_def = 125, -+ .ppt_pl2_sppt_max = 130, -+ .ppt_pl3_fppt_min = 65, -+ .ppt_pl3_fppt_def = 125, -+ .ppt_pl3_fppt_max = 130, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 75, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G733C"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 170, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 35, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G733P"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 30, -+ .ppt_pl1_spl_def = 100, -+ .ppt_pl1_spl_max = 130, -+ .ppt_pl2_sppt_min = 65, -+ .ppt_pl2_sppt_def = 125, -+ .ppt_pl2_sppt_max = 130, -+ .ppt_pl3_fppt_min = 65, -+ .ppt_pl3_fppt_def = 125, -+ .ppt_pl3_fppt_max = 130, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 65, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 65, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 75, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G733QS"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_max = 80, -+ }, -+ .requires_fan_curve = false, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G814J"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 140, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 140, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G834J"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_max = 140, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G835LR"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 140, -+ .ppt_pl1_spl_max = 175, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 65, -+ .nv_tgp_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "G835LW"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 28, -+ .ppt_pl1_spl_def = 140, -+ .ppt_pl1_spl_max = 175, -+ .ppt_pl2_sppt_min = 28, -+ .ppt_pl2_sppt_max = 175, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 25, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 80, -+ .nv_tgp_max = 150, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 55, -+ .ppt_pl2_sppt_min = 25, -+ .ppt_pl2_sppt_max = 70, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ .requires_fan_curve = true, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "H7606W"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 15, -+ .ppt_pl1_spl_max = 80, -+ .ppt_pl2_sppt_min = 35, -+ .ppt_pl2_sppt_max = 80, -+ .ppt_pl3_fppt_min = 35, -+ .ppt_pl3_fppt_max = 80, -+ .nv_dynamic_boost_min = 5, -+ .nv_dynamic_boost_max = 20, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ .nv_tgp_min = 55, -+ .nv_tgp_max = 85, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 25, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 31, -+ .ppt_pl2_sppt_max = 44, -+ .ppt_pl3_fppt_min = 45, -+ .ppt_pl3_fppt_max = 65, -+ .nv_temp_target_min = 75, -+ .nv_temp_target_max = 87, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "HN7306EA"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 35, -+ .ppt_pl1_spl_def = 60, -+ .ppt_pl1_spl_max = 85, -+ .ppt_pl2_sppt_min = 40, -+ .ppt_pl2_sppt_def = 70, -+ .ppt_pl2_sppt_max = 95, -+ .ppt_pl3_fppt_min = 50, -+ .ppt_pl3_fppt_def = 85, -+ .ppt_pl3_fppt_max = 115, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 35, -+ .ppt_pl1_spl_def = 45, -+ .ppt_pl1_spl_max = 60, -+ .ppt_pl2_sppt_min = 40, -+ .ppt_pl2_sppt_def = 55, -+ .ppt_pl2_sppt_max = 70, -+ .ppt_pl3_fppt_min = 50, -+ .ppt_pl3_fppt_def = 65, -+ .ppt_pl3_fppt_max = 85, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC71"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 7, -+ .ppt_pl1_spl_max = 30, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_max = 43, -+ .ppt_pl3_fppt_min = 15, -+ .ppt_pl3_fppt_max = 53, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 7, -+ .ppt_pl1_spl_def = 15, -+ .ppt_pl1_spl_max = 25, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_def = 20, -+ .ppt_pl2_sppt_max = 30, -+ .ppt_pl3_fppt_min = 15, -+ .ppt_pl3_fppt_def = 25, -+ .ppt_pl3_fppt_max = 35, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC72"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 7, -+ .ppt_pl1_spl_max = 30, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_max = 43, -+ .ppt_pl3_fppt_min = 15, -+ .ppt_pl3_fppt_max = 53, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 7, -+ .ppt_pl1_spl_def = 17, -+ .ppt_pl1_spl_max = 25, -+ .ppt_pl2_sppt_min = 15, -+ .ppt_pl2_sppt_def = 24, -+ .ppt_pl2_sppt_max = 30, -+ .ppt_pl3_fppt_min = 15, -+ .ppt_pl3_fppt_def = 30, -+ .ppt_pl3_fppt_max = 35, -+ }, -+ }, -+ }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "RC73XA"), -+ }, -+ .driver_data = &(struct power_data) { -+ .ac_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 7, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 14, -+ .ppt_pl2_sppt_max = 45, -+ .ppt_pl3_fppt_min = 19, -+ .ppt_pl3_fppt_max = 55, -+ }, -+ .dc_data = &(struct power_limits) { -+ .ppt_pl1_spl_min = 7, -+ .ppt_pl1_spl_def = 17, -+ .ppt_pl1_spl_max = 35, -+ .ppt_pl2_sppt_min = 13, -+ .ppt_pl2_sppt_def = 21, -+ .ppt_pl2_sppt_max = 45, -+ .ppt_pl3_fppt_min = 19, -+ .ppt_pl3_fppt_def = 26, -+ .ppt_pl3_fppt_max = 55, -+ }, -+ }, -+ }, -+ {} -+}; -+ -+#endif /* _ASUS_ARMOURY_H_ */ ---- /dev/null -+++ b/drivers/platform/asus/Kconfig -@@ -0,0 +1,65 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# Asus Platform Specific Drivers -+# -+ -+config ASUS_ARMOURY -+ depends on X86 -+ tristate "ASUS Armoury driver" -+ depends on ASUS_WMI -+ select FW_ATTR_CLASS -+ help -+ Say Y here if you have a WMI aware Asus machine and would like to use the -+ firmware_attributes API to control various settings typically exposed in -+ the ASUS Armoury Crate application available on Windows. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called asus-armoury. -+ -+config ASUS_WMI -+ tristate "ASUS WMI Driver" -+ depends on ACPI_WMI -+ depends on ACPI_BATTERY -+ depends on INPUT -+ depends on HWMON -+ depends on BACKLIGHT_CLASS_DEVICE -+ depends on RFKILL || RFKILL = n -+ depends on HOTPLUG_PCI -+ depends on ACPI_VIDEO || ACPI_VIDEO = n -+ depends on SERIO_I8042 || SERIO_I8042 = n -+ select INPUT_SPARSEKMAP -+ select LEDS_CLASS -+ select NEW_LEDS -+ select ACPI_PLATFORM_PROFILE -+ help -+ Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new -+ Asus Notebooks). -+ -+ To compile this driver as a module, choose M here: the module will -+ be called asus-wmi. -+ -+config ASUS_WMI_DEPRECATED_ATTRS -+ bool "BIOS option support in WMI platform (DEPRECATED)" -+ depends on ASUS_WMI -+ default y -+ help -+ Say Y to expose the configurable BIOS options through the asus-wmi -+ driver. -+ -+ This can be used with or without the asus-armoury driver which -+ has the same attributes, but more, and better features. -+ -+config ASUS_NB_WMI -+ tristate "Asus Notebook WMI Driver" -+ depends on ASUS_WMI -+ help -+ This is a driver for newer Asus notebooks. It adds extra features -+ like wireless radio and bluetooth control, leds, hotkeys, backlight... -+ -+ For more information, see -+ -+ -+ If you have an ACPI-WMI compatible Asus Notebook, say Y or M -+ here. -+ -+ ---- /dev/null -+++ b/drivers/platform/asus/Makefile -@@ -0,0 +1,9 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# Makefile for linux/drivers/platform/asus -+# Asus Platform-Specific Drivers -+# -+ -+obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o -+obj-$(CONFIG_ASUS_WMI) += asus-wmi.o -+obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o ---- /dev/null -+++ b/localversion.40-asus -@@ -0,0 +1 @@ -+-asus diff --git a/kernel/config.aarch64 b/kernel/config.aarch64 deleted file mode 100644 index e8f9523..0000000 --- a/kernel/config.aarch64 +++ /dev/null @@ -1,15912 +0,0 @@ -# -# Automatically generated file; DO NOT EDIT. -# Linux/arm64 7.2.8 Kernel Configuration -# -CONFIG_CC_VERSION_TEXT="gcc (GCC) 16.1.1 20260430" -CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=160101 -CONFIG_CLANG_VERSION=0 -CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=24600 -CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=24600 -CONFIG_LLD_VERSION=0 -CONFIG_RUSTC_VERSION=109900 -CONFIG_RUST_IS_AVAILABLE=y -CONFIG_RUSTC_LLVM_VERSION=230101 -CONFIG_RUSTC_LLVM_MAJOR_VERSION=23 -CONFIG_CC_CAN_LINK=y -CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y -CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y -CONFIG_TOOLS_SUPPORT_RELR=y -CONFIG_CC_HAS_ASM_INLINE=y -CONFIG_CC_HAS_ASSUME=y -CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_CC_HAS_COUNTED_BY=y -CONFIG_CC_HAS_COUNTED_BY_PTR=y -CONFIG_CC_HAS_MULTIDIMENSIONAL_NONSTRING=y -CONFIG_LD_CAN_USE_KEEP_IN_OVERLAY=y -CONFIG_RUSTC_HAS_SPAN_FILE=y -CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES=y -CONFIG_RUSTC_HAS_FILE_WITH_NUL=y -CONFIG_RUSTC_HAS_FILE_AS_C_STR=y -CONFIG_RUSTC_HAS_SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS=y -CONFIG_PAHOLE_VERSION=132 -CONFIG_IRQ_WORK=y -CONFIG_BUILDTIME_TABLE_SORT=y -CONFIG_THREAD_INFO_IN_TASK=y - -# -# General setup -# -CONFIG_INIT_ENV_ARG_LIMIT=32 -# CONFIG_COMPILE_TEST is not set -# CONFIG_WERROR is not set -CONFIG_LOCALVERSION="" -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_BUILD_SALT="" -CONFIG_HAVE_KERNEL_GZIP=y -CONFIG_HAVE_KERNEL_ZSTD=y -# CONFIG_KERNEL_GZIP is not set -CONFIG_KERNEL_ZSTD=y -CONFIG_DEFAULT_INIT="" -CONFIG_DEFAULT_HOSTNAME="(none)" -CONFIG_SYSVIPC=y -CONFIG_SYSVIPC_SYSCTL=y -CONFIG_SYSVIPC_COMPAT=y -CONFIG_POSIX_MQUEUE=y -CONFIG_POSIX_MQUEUE_SYSCTL=y -CONFIG_WATCH_QUEUE=y -CONFIG_CROSS_MEMORY_ATTACH=y -CONFIG_AUDIT=y -CONFIG_HAVE_ARCH_AUDITSYSCALL=y -CONFIG_AUDITSYSCALL=y - -# -# IRQ subsystem -# -CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_GENERIC_IRQ_SHOW=y -CONFIG_GENERIC_IRQ_SHOW_LEVEL=y -CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y -CONFIG_GENERIC_IRQ_MIGRATION=y -CONFIG_HARDIRQS_SW_RESEND=y -CONFIG_GENERIC_IRQ_CHIP=y -CONFIG_IRQ_DOMAIN=y -CONFIG_IRQ_SIM=y -CONFIG_IRQ_DOMAIN_HIERARCHY=y -CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y -CONFIG_GENERIC_IRQ_IPI=y -CONFIG_GENERIC_IRQ_IPI_MUX=y -CONFIG_GENERIC_MSI_IRQ=y -CONFIG_IRQ_MSI_IOMMU=y -CONFIG_IRQ_FORCED_THREADING=y -CONFIG_SPARSE_IRQ=y -# CONFIG_GENERIC_IRQ_DEBUGFS is not set -CONFIG_GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD=y -# end of IRQ subsystem - -CONFIG_GENERIC_CLOCKEVENTS=y -CONFIG_ARCH_HAS_TICK_BROADCAST=y -CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y -CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y -CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y -CONFIG_CONTEXT_TRACKING=y -CONFIG_CONTEXT_TRACKING_IDLE=y - -# -# Timers subsystem -# -CONFIG_TICK_ONESHOT=y -CONFIG_NO_HZ_COMMON=y -# CONFIG_HZ_PERIODIC is not set -# CONFIG_NO_HZ_IDLE is not set -CONFIG_NO_HZ_FULL=y -CONFIG_CONTEXT_TRACKING_USER=y -# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_POSIX_AUX_CLOCKS=y -# end of Timers subsystem - -CONFIG_BPF=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y - -# -# BPF subsystem -# -CONFIG_BPF_SYSCALL=y -CONFIG_BPF_JIT=y -CONFIG_BPF_JIT_ALWAYS_ON=y -CONFIG_BPF_JIT_DEFAULT_ON=y -CONFIG_BPF_UNPRIV_DEFAULT_OFF=y -# CONFIG_BPF_PRELOAD is not set -CONFIG_BPF_LSM=y -# end of BPF subsystem - -CONFIG_PREEMPT_BUILD=y -CONFIG_ARCH_HAS_PREEMPT_LAZY=y -CONFIG_PREEMPT=y -# CONFIG_PREEMPT_LAZY is not set -# CONFIG_PREEMPT_RT is not set -CONFIG_PREEMPT_COUNT=y -CONFIG_PREEMPTION=y -CONFIG_PREEMPT_DYNAMIC=y -CONFIG_SCHED_CORE=y -CONFIG_SCHED_CLASS_EXT=y - -# -# CPU/Task time and stats accounting -# -CONFIG_VIRT_CPU_ACCOUNTING=y -CONFIG_VIRT_CPU_ACCOUNTING_GEN=y -# CONFIG_IRQ_TIME_ACCOUNTING is not set -CONFIG_SCHED_HW_PRESSURE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_PSI=y -# CONFIG_PSI_DEFAULT_DISABLED is not set -# end of CPU/Task time and stats accounting - -CONFIG_CPU_ISOLATION=y - -# -# RCU Subsystem -# -CONFIG_TREE_RCU=y -CONFIG_PREEMPT_RCU=y -# CONFIG_RCU_EXPERT is not set -CONFIG_TREE_SRCU=y -CONFIG_TASKS_RCU_GENERIC=y -CONFIG_NEED_TASKS_RCU=y -CONFIG_TASKS_RCU=y -CONFIG_TASKS_RUDE_RCU=y -CONFIG_TASKS_TRACE_RCU=y -CONFIG_RCU_STALL_COMMON=y -CONFIG_RCU_NEED_SEGCBLIST=y -CONFIG_RCU_NOCB_CPU=y -# CONFIG_RCU_NOCB_CPU_DEFAULT_ALL is not set -CONFIG_RCU_LAZY=y -CONFIG_RCU_LAZY_DEFAULT_OFF=y -# end of RCU Subsystem - -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_IKHEADERS=m -CONFIG_LOG_BUF_SHIFT=18 -CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 -# CONFIG_PRINTK_INDEX is not set -CONFIG_GENERIC_SCHED_CLOCK=y - -# -# Scheduler features -# -CONFIG_UCLAMP_TASK=y -CONFIG_UCLAMP_BUCKETS_COUNT=5 -# end of Scheduler features - -CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y -CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y -CONFIG_CC_HAS_INT128=y -CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" -CONFIG_CC_MS_EXTENSIONS="-fms-extensions" -CONFIG_GCC10_NO_ARRAY_BOUNDS=y -CONFIG_CC_NO_ARRAY_BOUNDS=y -CONFIG_GCC_NO_STRINGOP_OVERFLOW=y -CONFIG_CC_NO_STRINGOP_OVERFLOW=y -CONFIG_ARCH_SUPPORTS_INT128=y -CONFIG_NUMA_BALANCING=y -CONFIG_SCHED_CACHE=y -CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y -CONFIG_SLAB_OBJ_EXT=y -CONFIG_CGROUPS=y -CONFIG_PAGE_COUNTER=y -# CONFIG_CGROUP_FAVOR_DYNMODS is not set -CONFIG_MEMCG=y -# CONFIG_MEMCG_V1 is not set -CONFIG_BLK_CGROUP=y -CONFIG_CGROUP_WRITEBACK=y -CONFIG_CGROUP_SCHED=y -CONFIG_GROUP_SCHED_WEIGHT=y -CONFIG_GROUP_SCHED_BANDWIDTH=y -CONFIG_FAIR_GROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -# CONFIG_RT_GROUP_SCHED is not set -CONFIG_EXT_GROUP_SCHED=y -CONFIG_EXT_SUB_SCHED=y -CONFIG_SCHED_MM_CID=y -CONFIG_UCLAMP_TASK_GROUP=y -CONFIG_CGROUP_PIDS=y -CONFIG_CGROUP_RDMA=y -CONFIG_CGROUP_DMEM=y -CONFIG_CGROUP_FREEZER=y -CONFIG_CGROUP_HUGETLB=y -CONFIG_CPUSETS=y -# CONFIG_CPUSETS_V1 is not set -CONFIG_CGROUP_DEVICE=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_PERF=y -CONFIG_CGROUP_BPF=y -CONFIG_CGROUP_MISC=y -# CONFIG_CGROUP_DEBUG is not set -CONFIG_SOCK_CGROUP_DATA=y -CONFIG_NAMESPACES=y -CONFIG_UTS_NS=y -CONFIG_TIME_NS=y -CONFIG_TIME_NS_VDSO=y -CONFIG_IPC_NS=y -CONFIG_USER_NS=y -CONFIG_PID_NS=y -CONFIG_NET_NS=y -CONFIG_CHECKPOINT_RESTORE=y -CONFIG_SCHED_BORE=y -CONFIG_SCHED_AUTOGROUP=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_RD_GZIP=y -CONFIG_RD_BZIP2=y -CONFIG_RD_LZMA=y -CONFIG_RD_XZ=y -CONFIG_RD_LZO=y -CONFIG_RD_LZ4=y -CONFIG_RD_ZSTD=y -CONFIG_BOOT_CONFIG=y -# CONFIG_BOOT_CONFIG_FORCE is not set -# CONFIG_BOOT_CONFIG_EMBED is not set -CONFIG_CMDLINE_LOG_WRAP_IDEAL_LEN=1021 -CONFIG_INITRAMFS_PRESERVE_MTIME=y -CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3 is not set -CONFIG_LD_ORPHAN_WARN=y -CONFIG_LD_ORPHAN_WARN_LEVEL="warn" -CONFIG_SYSCTL=y -CONFIG_HAVE_UID16=y -CONFIG_SYSCTL_EXCEPTION_TRACE=y -CONFIG_SYSFS_SYSCALL=y -CONFIG_EXPERT=y -CONFIG_UID16=y -CONFIG_MULTIUSER=y -CONFIG_SGETMASK_SYSCALL=y -CONFIG_FHANDLE=y -CONFIG_POSIX_TIMERS=y -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_ELF_CORE=y -# CONFIG_BASE_SMALL is not set -CONFIG_FUTEX=y -CONFIG_FUTEX_PI=y -CONFIG_FUTEX_PRIVATE_HASH=y -CONFIG_FUTEX_MPOL=y -CONFIG_EPOLL=y -CONFIG_SIGNALFD=y -CONFIG_TIMERFD=y -CONFIG_EVENTFD=y -CONFIG_SHMEM=y -CONFIG_AIO=y -CONFIG_IO_URING=y -CONFIG_IO_URING_MOCK_FILE=m -CONFIG_ADVISE_SYSCALLS=y -CONFIG_MEMBARRIER=y -CONFIG_KCMP=y -CONFIG_RSEQ=y -CONFIG_RSEQ_STATS=y -# CONFIG_RSEQ_DEBUG_DEFAULT_ENABLE is not set -# CONFIG_DEBUG_RSEQ is not set -CONFIG_CACHESTAT_SYSCALL=y -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_SELFTEST is not set -CONFIG_KALLSYMS_ALL=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_GUEST_PERF_EVENTS=y - -# -# Kernel Performance Events And Counters -# -CONFIG_PERF_EVENTS=y -# CONFIG_DEBUG_PERF_USE_VMALLOC is not set -# end of Kernel Performance Events And Counters - -CONFIG_SYSTEM_DATA_VERIFICATION=y -CONFIG_PROFILING=y -# CONFIG_RUST is not set -CONFIG_TRACEPOINTS=y - -# -# Kexec and crash features -# -CONFIG_CRASH_RESERVE=y -CONFIG_VMCORE_INFO=y -CONFIG_KEXEC_CORE=y -CONFIG_HAVE_IMA_KEXEC=y -CONFIG_KEXEC=y -CONFIG_KEXEC_FILE=y -CONFIG_KEXEC_SIG=y -CONFIG_KEXEC_IMAGE_VERIFY_SIG=y -CONFIG_CRASH_DUMP=y -CONFIG_CRASH_DM_CRYPT=y -CONFIG_CRASH_DM_CRYPT_CONFIGS=y -# end of Kexec and crash features - -# -# Live Update and Kexec HandOver -# -CONFIG_KEXEC_HANDOVER=y -# CONFIG_KEXEC_HANDOVER_DEBUG is not set -CONFIG_KEXEC_HANDOVER_DEBUGFS=y -# CONFIG_KEXEC_HANDOVER_ENABLE_DEFAULT is not set -CONFIG_LIVEUPDATE=y -CONFIG_LIVEUPDATE_MEMFD=y -# end of Live Update and Kexec HandOver -# end of General setup - -CONFIG_ARM64=y -CONFIG_RUSTC_SUPPORTS_ARM64=y -CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y -CONFIG_64BIT=y -CONFIG_MMU=y -CONFIG_ARM64_CONT_PTE_SHIFT=4 -CONFIG_ARM64_CONT_PMD_SHIFT=4 -CONFIG_ARCH_MMAP_RND_BITS_MIN=18 -CONFIG_ARCH_MMAP_RND_BITS_MAX=33 -CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 -CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 -CONFIG_STACKTRACE_SUPPORT=y -CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 -CONFIG_LOCKDEP_SUPPORT=y -CONFIG_GENERIC_BUG=y -CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y -CONFIG_GENERIC_HWEIGHT=y -CONFIG_GENERIC_CSUM=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_SMP=y -CONFIG_KERNEL_MODE_NEON=y -CONFIG_FIX_EARLYCON_MEM=y -CONFIG_PGTABLE_LEVELS=4 -CONFIG_ARCH_SUPPORTS_UPROBES=y -CONFIG_ARCH_PROC_KCORE_TEXT=y -CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC=y - -# -# Platform selection -# -CONFIG_ARCH_ACTIONS=y -CONFIG_ARCH_AIROHA=y -CONFIG_ARCH_SUNXI=y -# CONFIG_ARCH_ALPINE is not set -CONFIG_ARCH_APPLE=y -# CONFIG_ARCH_ASPEED is not set -CONFIG_ARCH_AXIADO=y -# CONFIG_ARCH_BCM is not set -CONFIG_ARCH_BERLIN=y -CONFIG_ARCH_BITMAIN=y -CONFIG_ARCH_BLAIZE=y -CONFIG_ARCH_BST=y -CONFIG_ARCH_CIX=y -# CONFIG_ARCH_EXYNOS is not set -CONFIG_ARCH_K3=y -CONFIG_ARCH_LG1K=y -CONFIG_ARCH_HISI=y -CONFIG_ARCH_KEEMBAY=y -CONFIG_ARCH_MEDIATEK=y -CONFIG_ARCH_MESON=y -CONFIG_ARCH_MICROCHIP=y -CONFIG_ARCH_LAN969X=y -CONFIG_ARCH_SPARX5=y -CONFIG_ARCH_MMP=y -CONFIG_ARCH_MVEBU=y -CONFIG_ARCH_NXP=y -CONFIG_ARCH_LAYERSCAPE=y -CONFIG_ARCH_MXC=y -CONFIG_ARCH_S32=y -CONFIG_ARCH_MA35=y -CONFIG_ARCH_NPCM=y -CONFIG_ARCH_PENSANDO=y -CONFIG_ARCH_QCOM=y -CONFIG_ARCH_REALTEK=y -CONFIG_ARCH_RENESAS=y -CONFIG_ARCH_ROCKCHIP=y -CONFIG_ARCH_SEATTLE=y -CONFIG_ARCH_INTEL_SOCFPGA=y -CONFIG_ARCH_SOPHGO=y -CONFIG_ARCH_STM32=y -CONFIG_ARCH_SYNQUACER=y -CONFIG_ARCH_TEGRA=y -CONFIG_ARCH_SPRD=y -CONFIG_ARCH_THUNDER=y -CONFIG_ARCH_THUNDER2=y -# CONFIG_ARCH_UNIPHIER is not set -CONFIG_ARCH_VEXPRESS=y -CONFIG_ARCH_VISCONTI=y -CONFIG_ARCH_XGENE=y -CONFIG_ARCH_ZYNQMP=y -# end of Platform selection - -# -# Kernel Features -# - -# -# ARM errata workarounds via the alternatives framework -# -CONFIG_AMPERE_ERRATUM_AC03_CPU_38=y -CONFIG_AMPERE_ERRATUM_AC04_CPU_23=y -CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y -CONFIG_ARM64_ERRATUM_826319=y -CONFIG_ARM64_ERRATUM_827319=y -CONFIG_ARM64_ERRATUM_824069=y -CONFIG_ARM64_ERRATUM_819472=y -CONFIG_ARM64_ERRATUM_832075=y -CONFIG_ARM64_ERRATUM_834220=y -CONFIG_ARM64_ERRATUM_1742098=y -CONFIG_ARM64_ERRATUM_845719=y -CONFIG_ARM64_ERRATUM_843419=y -CONFIG_ARM64_ERRATUM_1024718=y -CONFIG_ARM64_ERRATUM_1418040=y -CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y -CONFIG_ARM64_ERRATUM_1165522=y -CONFIG_ARM64_ERRATUM_1319367=y -CONFIG_ARM64_ERRATUM_1530923=y -CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y -CONFIG_ARM64_ERRATUM_2441007=y -CONFIG_ARM64_ERRATUM_1286807=y -CONFIG_ARM64_ERRATUM_1463225=y -CONFIG_ARM64_ERRATUM_1542419=y -CONFIG_ARM64_ERRATUM_1508412=y -CONFIG_ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE=y -CONFIG_ARM64_ERRATUM_2051678=y -CONFIG_ARM64_ERRATUM_2077057=y -CONFIG_ARM64_ERRATUM_2658417=y -CONFIG_ARM64_ERRATUM_2119858=y -CONFIG_ARM64_ERRATUM_2139208=y -CONFIG_ARM64_WORKAROUND_TSB_FLUSH_FAILURE=y -CONFIG_ARM64_ERRATUM_2054223=y -CONFIG_ARM64_ERRATUM_2067961=y -CONFIG_ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE=y -CONFIG_ARM64_ERRATUM_2253138=y -CONFIG_ARM64_ERRATUM_2224489=y -CONFIG_ARM64_ERRATUM_2441009=y -CONFIG_ARM64_ERRATUM_2064142=y -CONFIG_ARM64_ERRATUM_2038923=y -CONFIG_ARM64_ERRATUM_1902691=y -CONFIG_ARM64_ERRATUM_2457168=y -CONFIG_ARM64_ERRATUM_2645198=y -CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD=y -CONFIG_ARM64_ERRATUM_2966298=y -CONFIG_ARM64_ERRATUM_3117295=y -CONFIG_ARM64_ERRATUM_3194386=y -CONFIG_ARM64_ERRATUM_4311569=y -CONFIG_ARM64_ERRATUM_4193714=y -CONFIG_ARM64_ERRATUM_4118414=y -CONFIG_CAVIUM_ERRATUM_22375=y -CONFIG_CAVIUM_ERRATUM_23144=y -CONFIG_CAVIUM_ERRATUM_23154=y -CONFIG_CAVIUM_ERRATUM_27456=y -CONFIG_CAVIUM_ERRATUM_30115=y -CONFIG_CAVIUM_TX2_ERRATUM_219=y -CONFIG_FUJITSU_ERRATUM_010001=y -CONFIG_HISILICON_ERRATUM_161600802=y -CONFIG_HISILICON_ERRATUM_162100801=y -CONFIG_HISILICON_ERRATUM_162100125=y -CONFIG_QCOM_FALKOR_ERRATUM_1003=y -CONFIG_QCOM_FALKOR_ERRATUM_1009=y -CONFIG_QCOM_QDF2400_ERRATUM_0065=y -CONFIG_QCOM_FALKOR_ERRATUM_E1041=y -CONFIG_ARM64_WORKAROUND_DISABLE_CNP=y -CONFIG_NVIDIA_CARMEL_CNP_ERRATUM=y -CONFIG_ROCKCHIP_ERRATUM_3568002=y -CONFIG_ROCKCHIP_ERRATUM_3588001=y -CONFIG_SOCIONEXT_SYNQUACER_PREITS=y -# end of ARM errata workarounds via the alternatives framework - -CONFIG_ARM64_4K_PAGES=y -# CONFIG_ARM64_16K_PAGES is not set -# CONFIG_ARM64_64K_PAGES is not set -# CONFIG_ARM64_VA_BITS_39 is not set -CONFIG_ARM64_VA_BITS_48=y -# CONFIG_ARM64_VA_BITS_52 is not set -CONFIG_ARM64_VA_BITS=48 -CONFIG_ARM64_PA_BITS_48=y -CONFIG_ARM64_PA_BITS=48 -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_NR_CPUS=512 -CONFIG_HOTPLUG_CPU=y -CONFIG_NUMA=y -CONFIG_NODES_SHIFT=6 -# CONFIG_HZ_100 is not set -# CONFIG_HZ_250 is not set -# CONFIG_HZ_300 is not set -CONFIG_HZ_1000=y -CONFIG_HZ=1000 -CONFIG_SCHED_HRTICK=y -CONFIG_MIN_BASE_SLICE_NS=2000000 -CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_HW_PERF_EVENTS=y -CONFIG_CC_HAVE_SHADOW_CALL_STACK=y -CONFIG_PARAVIRT=y -# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set -CONFIG_ARCH_SUPPORTS_KEXEC=y -CONFIG_ARCH_SUPPORTS_KEXEC_FILE=y -CONFIG_ARCH_SELECTS_KEXEC_FILE=y -CONFIG_ARCH_SUPPORTS_KEXEC_SIG=y -CONFIG_ARCH_SUPPORTS_KEXEC_IMAGE_VERIFY_SIG=y -CONFIG_ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG=y -CONFIG_ARCH_SUPPORTS_KEXEC_HANDOVER=y -CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y -CONFIG_ARCH_DEFAULT_CRASH_DUMP=y -CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION=y -CONFIG_TRANS_TABLE=y -CONFIG_XEN_DOM0=y -CONFIG_XEN=y -CONFIG_ARCH_FORCE_MAX_ORDER=10 -CONFIG_UNMAP_KERNEL_AT_EL0=y -CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y -CONFIG_ARM64_SW_TTBR0_PAN=y -CONFIG_ARM64_TAGGED_ADDR_ABI=y -CONFIG_COMPAT=y -CONFIG_KUSER_HELPERS=y -# CONFIG_COMPAT_ALIGNMENT_FIXUPS is not set -CONFIG_ARMV8_DEPRECATED=y -CONFIG_SWP_EMULATION=y -CONFIG_CP15_BARRIER_EMULATION=y -CONFIG_SETEND_EMULATION=y - -# -# ARMv8.1 architectural features -# -CONFIG_ARM64_HW_AFDBM=y -# end of ARMv8.1 architectural features - -# -# ARMv8.2 architectural features -# -CONFIG_ARM64_PMEM=y -CONFIG_ARM64_RAS_EXTN=y -CONFIG_ARM64_CNP=y -# end of ARMv8.2 architectural features - -# -# ARMv8.3 architectural features -# -CONFIG_ARM64_PTR_AUTH=y -CONFIG_ARM64_PTR_AUTH_KERNEL=y -CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y -CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y -# end of ARMv8.3 architectural features - -# -# ARMv8.4 architectural features -# -CONFIG_ARM64_AMU_EXTN=y -CONFIG_ARM64_TLB_RANGE=y -CONFIG_ARM64_MPAM=y -# end of ARMv8.4 architectural features - -# -# ARMv8.5 architectural features -# -CONFIG_AS_HAS_ARMV8_5=y -CONFIG_ARM64_BTI=y -CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y -CONFIG_ARM64_E0PD=y -CONFIG_ARM64_AS_HAS_MTE=y -CONFIG_ARM64_MTE=y -# end of ARMv8.5 architectural features - -# -# ARMv8.7 architectural features -# -CONFIG_ARM64_EPAN=y -# end of ARMv8.7 architectural features - -CONFIG_AS_HAS_MOPS=y - -# -# ARMv8.9 architectural features -# -CONFIG_ARM64_POE=y -CONFIG_ARCH_PKEY_BITS=3 -CONFIG_ARM64_HAFT=y -# end of ARMv8.9 architectural features - -# -# ARMv9.4 architectural features -# -CONFIG_ARM64_GCS=y -# end of ARMv9.4 architectural features - -CONFIG_AS_HAS_LSUI=y - -# -# ARMv9.6 architectural features -# -CONFIG_ARM64_LSUI=y -# end of ARMv9.6 architectural features - -CONFIG_ARM64_SVE=y -CONFIG_AS_HAS_SME=y -CONFIG_ARM64_SME=y -CONFIG_ARM64_PSEUDO_NMI=y -# CONFIG_ARM64_DEBUG_PRIORITY_MASKING is not set -CONFIG_RELOCATABLE=y -CONFIG_RANDOMIZE_BASE=y -CONFIG_RANDOMIZE_MODULE_REGION_FULL=y -CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y -CONFIG_STACKPROTECTOR_PER_TASK=y -CONFIG_ARM64_CONTPTE=y -# end of Kernel Features - -# -# Boot options -# -CONFIG_ARM64_ACPI_PARKING_PROTOCOL=y -CONFIG_CMDLINE="console=ttyAMA0" -CONFIG_CMDLINE_FROM_BOOTLOADER=y -# CONFIG_CMDLINE_FORCE is not set -CONFIG_EFI_STUB=y -CONFIG_EFI=y -# CONFIG_COMPRESSED_INSTALL is not set -CONFIG_DMI=y -# end of Boot options - -# -# Power management options -# -CONFIG_SUSPEND=y -CONFIG_SUSPEND_FREEZER=y -# CONFIG_SUSPEND_SKIP_SYNC is not set -# CONFIG_HIBERNATION is not set -CONFIG_PM_SLEEP=y -CONFIG_PM_SLEEP_SMP=y -# CONFIG_PM_AUTOSLEEP is not set -# CONFIG_PM_USERSPACE_AUTOSLEEP is not set -CONFIG_PM_WAKELOCKS=y -CONFIG_PM_WAKELOCKS_LIMIT=100 -CONFIG_PM_WAKELOCKS_GC=y -CONFIG_PM_QOS_CPU_SYSTEM_WAKEUP=y -CONFIG_PM=y -CONFIG_PM_DEBUG=y -CONFIG_PM_ADVANCED_DEBUG=y -# CONFIG_PM_TEST_SUSPEND is not set -CONFIG_PM_SLEEP_DEBUG=y -# CONFIG_DPM_WATCHDOG is not set -CONFIG_PM_CLK=y -CONFIG_PM_GENERIC_DOMAINS=y -CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y -CONFIG_PM_GENERIC_DOMAINS_SLEEP=y -CONFIG_PM_GENERIC_DOMAINS_OF=y -CONFIG_CPU_PM=y -CONFIG_ENERGY_MODEL=y -CONFIG_ARCH_HIBERNATION_POSSIBLE=y -CONFIG_ARCH_SUSPEND_POSSIBLE=y -# end of Power management options - -# -# CPU Power Management -# - -# -# CPU Idle -# -CONFIG_CPU_IDLE=y -CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y -CONFIG_CPU_IDLE_GOV_LADDER=y -CONFIG_CPU_IDLE_GOV_MENU=y -CONFIG_CPU_IDLE_GOV_TEO=y -CONFIG_DT_IDLE_STATES=y -CONFIG_DT_IDLE_GENPD=y - -# -# ARM CPU Idle Drivers -# -CONFIG_ARM_PSCI_CPUIDLE=y -CONFIG_ARM_PSCI_CPUIDLE_DOMAIN=y -# end of ARM CPU Idle Drivers -# end of CPU Idle - -# -# CPU Frequency scaling -# -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_GOV_ATTR_SET=y -CONFIG_CPU_FREQ_GOV_COMMON=y -CONFIG_CPU_FREQ_STAT=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=y -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y -CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y - -# -# CPU frequency scaling drivers -# -CONFIG_CPUFREQ_DT=y -CONFIG_CPUFREQ_VIRT=m -CONFIG_CPUFREQ_DT_PLATDEV=y -CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM=m -CONFIG_ARM_AIROHA_SOC_CPUFREQ=m -CONFIG_ARM_APPLE_SOC_CPUFREQ=m -CONFIG_ARM_ARMADA_37XX_CPUFREQ=m -CONFIG_ARM_ARMADA_8K_CPUFREQ=m -CONFIG_ARM_SCPI_CPUFREQ=m -CONFIG_ARM_IMX6Q_CPUFREQ=m -CONFIG_ARM_IMX_CPUFREQ_DT=m -CONFIG_ARM_MEDIATEK_CPUFREQ=m -CONFIG_ARM_MEDIATEK_CPUFREQ_HW=m -CONFIG_ARM_QCOM_CPUFREQ_NVMEM=m -CONFIG_ARM_QCOM_CPUFREQ_HW=m -CONFIG_ARM_SCMI_CPUFREQ=y -CONFIG_ARM_TEGRA20_CPUFREQ=y -CONFIG_ARM_TEGRA124_CPUFREQ=y -CONFIG_ARM_TEGRA186_CPUFREQ=m -CONFIG_ARM_TEGRA194_CPUFREQ=m -CONFIG_ARM_TI_CPUFREQ=y -CONFIG_QORIQ_CPUFREQ=m -CONFIG_ACPI_CPPC_CPUFREQ=m -CONFIG_ACPI_CPPC_CPUFREQ_FIE=y -# end of CPU Frequency scaling -# end of CPU Power Management - -CONFIG_ARCH_SUPPORTS_ACPI=y -CONFIG_ACPI=y -CONFIG_ACPI_GENERIC_GSI=y -CONFIG_ACPI_CCA_REQUIRED=y -CONFIG_ACPI_TABLE_LIB=y -CONFIG_ACPI_THERMAL_LIB=y -# CONFIG_ACPI_DEBUGGER is not set -CONFIG_ACPI_SPCR_TABLE=y -CONFIG_ACPI_FPDT=y -CONFIG_ACPI_EC=y -CONFIG_ACPI_EC_DEBUGFS=m -CONFIG_ACPI_AC=y -CONFIG_ACPI_BATTERY_HOOKS=y -CONFIG_ACPI_BATTERY=y -CONFIG_ACPI_BUTTON=y -CONFIG_ACPI_VIDEO=m -CONFIG_ACPI_FAN=y -CONFIG_ACPI_TAD=m -CONFIG_ACPI_DOCK=y -CONFIG_ACPI_PROCESSOR_IDLE=y -CONFIG_ACPI_MCFG=y -CONFIG_ACPI_CPPC_LIB=y -CONFIG_ACPI_PROCESSOR=y -CONFIG_ACPI_IPMI=m -CONFIG_ACPI_HOTPLUG_CPU=y -CONFIG_ACPI_THERMAL=y -CONFIG_ACPI_PLATFORM_PROFILE=m -CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y -CONFIG_ACPI_TABLE_UPGRADE=y -# CONFIG_ACPI_DEBUG is not set -CONFIG_ACPI_PCI_SLOT=y -CONFIG_ACPI_CONTAINER=y -CONFIG_ACPI_HOTPLUG_MEMORY=y -CONFIG_ACPI_HED=y -CONFIG_ACPI_BGRT=y -CONFIG_ACPI_REDUCED_HARDWARE_ONLY=y -CONFIG_ACPI_NHLT=y -CONFIG_ACPI_NFIT=m -# CONFIG_NFIT_SECURITY_DEBUG is not set -CONFIG_ACPI_NUMA=y -CONFIG_ACPI_HMAT=y -CONFIG_HAVE_ACPI_APEI=y -CONFIG_ACPI_APEI=y -CONFIG_ACPI_APEI_GHES=y -CONFIG_ACPI_APEI_PCIEAER=y -CONFIG_ACPI_APEI_SEA=y -CONFIG_ACPI_APEI_MEMORY_FAILURE=y -CONFIG_ACPI_APEI_EINJ=m -CONFIG_ACPI_APEI_EINJ_CXL=y -# CONFIG_ACPI_APEI_GHES_NVIDIA is not set -# CONFIG_ACPI_APEI_ERST_DEBUG is not set -CONFIG_ACPI_WATCHDOG=y -CONFIG_ACPI_CONFIGFS=m -CONFIG_ACPI_PFRUT=m -CONFIG_ACPI_IORT=y -CONFIG_ACPI_GTDT=y -CONFIG_ACPI_AGDI=y -CONFIG_ACPI_APMT=y -CONFIG_ACPI_MPAM=y -CONFIG_ACPI_PPTT=y -CONFIG_ACPI_PCC=y -CONFIG_ACPI_FFH=y -# CONFIG_PMIC_OPREGION is not set -CONFIG_ACPI_VIOT=y -CONFIG_ACPI_PRMT=y -CONFIG_KVM_COMMON=y -CONFIG_HAVE_KVM_IRQCHIP=y -CONFIG_HAVE_KVM_IRQ_ROUTING=y -CONFIG_HAVE_KVM_DIRTY_RING=y -CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y -CONFIG_NEED_KVM_DIRTY_RING_WITH_BITMAP=y -CONFIG_KVM_MMIO=y -CONFIG_HAVE_KVM_MSI=y -CONFIG_HAVE_KVM_READONLY_MEM=y -CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y -CONFIG_KVM_VFIO=y -CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y -CONFIG_HAVE_KVM_IRQ_BYPASS=y -CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE=y -CONFIG_VIRT_XFER_TO_GUEST_WORK=y -CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y -CONFIG_KVM_GUEST_MEMFD=y -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=y -# CONFIG_PTDUMP_STAGE2_DEBUGFS is not set -# CONFIG_NVHE_EL2_DEBUG is not set -CONFIG_HAVE_LIVEPATCH=y -CONFIG_LIVEPATCH=y -CONFIG_CPU_MITIGATIONS=y -CONFIG_ARCH_HAS_DMA_OPS=y - -# -# General architecture-dependent options -# -CONFIG_ARCH_HAS_SUBPAGE_FAULTS=y -CONFIG_HOTPLUG_SMT=y -CONFIG_ARCH_SUPPORTS_SCHED_SMT=y -CONFIG_ARCH_SUPPORTS_SCHED_CLUSTER=y -CONFIG_ARCH_SUPPORTS_SCHED_MC=y -CONFIG_SCHED_SMT=y -CONFIG_SCHED_CLUSTER=y -CONFIG_SCHED_MC=y -CONFIG_HOTPLUG_CORE_SYNC=y -CONFIG_HOTPLUG_CORE_SYNC_DEAD=y -CONFIG_GENERIC_IRQ_ENTRY=y -CONFIG_KPROBES=y -CONFIG_JUMP_LABEL=y -# CONFIG_STATIC_KEYS_SELFTEST is not set -CONFIG_UPROBES=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_KRETPROBES=y -CONFIG_HAVE_IOREMAP_PROT=y -CONFIG_HAVE_KPROBES=y -CONFIG_HAVE_KRETPROBES=y -CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y -CONFIG_HAVE_NMI=y -CONFIG_TRACE_IRQFLAGS_SUPPORT=y -CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_GENERIC_SMP_IDLE_THREAD=y -CONFIG_GENERIC_IDLE_POLL_SETUP=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_SET_DIRECT_MAP=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_ARCH_WANTS_NO_INSTR=y -CONFIG_HAVE_ASM_MODVERSIONS=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y -CONFIG_HAVE_RUST=y -CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y -CONFIG_HAVE_HW_BREAKPOINT=y -CONFIG_HAVE_PERF_EVENTS_NMI=y -CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y -CONFIG_MMU_GATHER_TABLE_FREE=y -CONFIG_MMU_GATHER_RCU_TABLE_FREE=y -CONFIG_MMU_LAZY_TLB_REFCOUNT=y -CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y -CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y -CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y -CONFIG_HAVE_CMPXCHG_LOCAL=y -CONFIG_HAVE_CMPXCHG_DOUBLE=y -CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y -CONFIG_HAVE_ARCH_SECCOMP=y -CONFIG_HAVE_ARCH_SECCOMP_FILTER=y -CONFIG_SECCOMP=y -CONFIG_SECCOMP_FILTER=y -# CONFIG_SECCOMP_CACHE_DEBUG is not set -CONFIG_HAVE_ARCH_KSTACK_ERASE=y -CONFIG_HAVE_STACKPROTECTOR=y -CONFIG_STACKPROTECTOR=y -CONFIG_STACKPROTECTOR_STRONG=y -CONFIG_ARCH_SUPPORTS_SHADOW_CALL_STACK=y -CONFIG_SHADOW_CALL_STACK=y -CONFIG_ARCH_SUPPORTS_LTO_CLANG=y -CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y -CONFIG_LTO_NONE=y -CONFIG_ARCH_SUPPORTS_CFI=y -CONFIG_HAVE_CONTEXT_TRACKING_USER=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_PV_STEAL_CLOCK_GEN=y -CONFIG_HAVE_MOVE_PUD=y -CONFIG_HAVE_MOVE_PMD=y -CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y -CONFIG_HAVE_ARCH_HUGE_VMAP=y -CONFIG_HAVE_ARCH_HUGE_VMALLOC=y -CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y -CONFIG_ARCH_WANT_PMD_MKWRITE=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_MODULES_USE_ELF_RELA=y -CONFIG_ARCH_WANTS_EXECMEM_LATE=y -CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y -CONFIG_SOFTIRQ_ON_OWN_STACK=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_HAVE_ARCH_MMAP_RND_BITS=y -CONFIG_ARCH_MMAP_RND_BITS=33 -CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y -CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16 -CONFIG_HAVE_PAGE_SIZE_4KB=y -CONFIG_PAGE_SIZE_4KB=y -CONFIG_PAGE_SIZE_LESS_THAN_64KB=y -CONFIG_PAGE_SIZE_LESS_THAN_256KB=y -CONFIG_PAGE_SHIFT=12 -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_HAVE_RELIABLE_STACKTRACE=y -CONFIG_CLONE_BACKWARDS=y -CONFIG_OLD_SIGSUSPEND3=y -CONFIG_COMPAT_OLD_SIGACTION=y -CONFIG_COMPAT_32BIT_TIME=y -CONFIG_ARCH_SUPPORTS_RT=y -CONFIG_HAVE_ARCH_VMAP_STACK=y -CONFIG_VMAP_STACK=y -CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y -CONFIG_RANDOMIZE_KSTACK_OFFSET=y -CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_CPU_RESCTRL=y -CONFIG_HAVE_ARCH_COMPILER_H=y -CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y -CONFIG_ARCH_USE_MEMREMAP_PROT=y -# CONFIG_LOCK_EVENT_COUNTS is not set -CONFIG_ARCH_HAS_RELR=y -CONFIG_RELR=y -CONFIG_ARCH_HAS_MEM_ENCRYPT=y -CONFIG_ARCH_HAS_CC_PLATFORM=y -CONFIG_HAVE_PREEMPT_DYNAMIC=y -CONFIG_HAVE_PREEMPT_DYNAMIC_KEY=y -CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y -CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y -CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y -CONFIG_ARCH_HAVE_TRACE_MMIO_ACCESS=y -CONFIG_ARCH_HAS_HW_PTE_YOUNG=y -CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y -CONFIG_ARCH_HAS_KERNEL_FPU_SUPPORT=y - -# -# GCOV-based kernel profiling -# -# CONFIG_GCOV_KERNEL is not set -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -# end of GCOV-based kernel profiling - -CONFIG_HAVE_GCC_PLUGINS=y -CONFIG_GCC_PLUGINS=y -# CONFIG_GCC_PLUGIN_LATENT_ENTROPY is not set -CONFIG_FUNCTION_ALIGNMENT_4B=y -CONFIG_FUNCTION_ALIGNMENT_8B=y -CONFIG_FUNCTION_ALIGNMENT=8 -CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT=y -CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y -CONFIG_HAVE_ARCH_GET_SECUREBOOT=y -# end of General architecture-dependent options - -CONFIG_RT_MUTEXES=y -CONFIG_MODULE_SIG_FORMAT=y -CONFIG_MODULES=y -# CONFIG_MODULE_DEBUG is not set -# CONFIG_MODULE_FORCE_LOAD is not set -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set -CONFIG_MODVERSIONS=y -# CONFIG_GENKSYMS is not set -CONFIG_GENDWARFKSYMS=y -CONFIG_ASM_MODVERSIONS=y -CONFIG_EXTENDED_MODVERSIONS=y -CONFIG_BASIC_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_MODULE_SIG=y -# CONFIG_MODULE_SIG_FORCE is not set -CONFIG_MODULE_SIG_ALL=y -# CONFIG_MODULE_SIG_SHA256 is not set -# CONFIG_MODULE_SIG_SHA384 is not set -CONFIG_MODULE_SIG_SHA512=y -# CONFIG_MODULE_SIG_SHA3_256 is not set -# CONFIG_MODULE_SIG_SHA3_384 is not set -# CONFIG_MODULE_SIG_SHA3_512 is not set -CONFIG_MODULE_SIG_HASH="sha512" -CONFIG_MODULE_COMPRESS=y -# CONFIG_MODULE_COMPRESS_GZIP is not set -# CONFIG_MODULE_COMPRESS_XZ is not set -CONFIG_MODULE_COMPRESS_ZSTD=y -# CONFIG_MODULE_COMPRESS_ALL is not set -CONFIG_MODULE_DECOMPRESS=y -# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set -CONFIG_MODPROBE_PATH="/sbin/modprobe" -# CONFIG_TRIM_UNUSED_KSYMS is not set -CONFIG_MODULES_TREE_LOOKUP=y -CONFIG_BLOCK=y -CONFIG_BLOCK_LEGACY_AUTOLOAD=y -CONFIG_BLK_RQ_ALLOC_TIME=y -CONFIG_BLK_CGROUP_RWSTAT=y -CONFIG_BLK_CGROUP_PUNT_BIO=y -CONFIG_BLK_DEV_BSG_COMMON=y -CONFIG_BLK_ICQ=y -CONFIG_BLK_DEV_BSGLIB=y -CONFIG_BLK_DEV_INTEGRITY=y -CONFIG_BLK_DEV_WRITE_MOUNTED=y -CONFIG_BLK_DEV_ZONED=y -CONFIG_BLK_DEV_THROTTLING=y -CONFIG_BLK_WBT=y -CONFIG_BLK_WBT_MQ=y -# CONFIG_BLK_CGROUP_IOLATENCY is not set -CONFIG_BLK_CGROUP_FC_APPID=y -CONFIG_BLK_CGROUP_IOCOST=y -CONFIG_BLK_CGROUP_IOPRIO=y -CONFIG_BLK_DEBUG_FS=y -CONFIG_BLK_SED_OPAL=y -CONFIG_BLK_INLINE_ENCRYPTION=y -CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -CONFIG_AIX_PARTITION=y -CONFIG_OSF_PARTITION=y -CONFIG_AMIGA_PARTITION=y -CONFIG_ATARI_PARTITION=y -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_LDM_PARTITION=y -# CONFIG_LDM_DEBUG is not set -CONFIG_SGI_PARTITION=y -CONFIG_ULTRIX_PARTITION=y -CONFIG_SUN_PARTITION=y -CONFIG_KARMA_PARTITION=y -CONFIG_EFI_PARTITION=y -CONFIG_SYSV68_PARTITION=y -CONFIG_CMDLINE_PARTITION=y -CONFIG_OF_PARTITION=y -# end of Partition Types - -CONFIG_BLK_PM=y -CONFIG_BLOCK_HOLDER_DEPRECATED=y -CONFIG_BLK_MQ_STACKING=y -# CONFIG_BLK_ERROR_INJECTION is not set - -# -# IO Schedulers -# -CONFIG_MQ_IOSCHED_DEADLINE=y -CONFIG_MQ_IOSCHED_KYBER=y -CONFIG_MQ_IOSCHED_ADIOS=m -CONFIG_IOSCHED_BFQ=y -CONFIG_BFQ_GROUP_IOSCHED=y -# CONFIG_BFQ_CGROUP_DEBUG is not set -# end of IO Schedulers - -CONFIG_PREEMPT_NOTIFIERS=y -CONFIG_PADATA=y -CONFIG_ASN1=y -CONFIG_UNINLINE_SPIN_UNLOCK=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_MUTEX_SPIN_ON_OWNER=y -CONFIG_RWSEM_SPIN_ON_OWNER=y -CONFIG_LOCK_SPIN_ON_OWNER=y -CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y -CONFIG_QUEUED_SPINLOCKS=y -CONFIG_ARCH_USE_QUEUED_RWLOCKS=y -CONFIG_QUEUED_RWLOCKS=y -CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y -CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y -CONFIG_FREEZER=y - -# -# Executable file formats -# -CONFIG_BINFMT_ELF=y -CONFIG_COMPAT_BINFMT_ELF=y -CONFIG_ARCH_BINFMT_ELF_STATE=y -CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y -CONFIG_ARCH_HAVE_ELF_PROT=y -CONFIG_ARCH_USE_GNU_PROPERTY=y -CONFIG_ELFCORE=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -CONFIG_BINFMT_SCRIPT=y -CONFIG_BINFMT_MISC=m -CONFIG_COREDUMP=y -# end of Executable file formats - -# -# Memory Management options -# -CONFIG_SWAP=y -CONFIG_ZSWAP=y -CONFIG_ZSWAP_DEFAULT_ON=y -CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y -# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set -CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO=y -# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_842 is not set -# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4 is not set -# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set -# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD is not set -CONFIG_ZSWAP_COMPRESSOR_DEFAULT="lzo" -CONFIG_ZSMALLOC=y - -# -# Zsmalloc allocator options -# - -# -# Zsmalloc is a common backend allocator for zswap & zram -# -# CONFIG_ZSMALLOC_STAT is not set -CONFIG_ZSMALLOC_CHAIN_SIZE=8 -# end of Zsmalloc allocator options - -# -# Slab allocator options -# -CONFIG_SLUB=y -CONFIG_KVFREE_RCU_BATCHED=y -# CONFIG_SLUB_TINY is not set -CONFIG_SLAB_MERGE_DEFAULT=y -CONFIG_SLAB_FREELIST_RANDOM=y -CONFIG_SLAB_FREELIST_HARDENED=y -CONFIG_SLAB_BUCKETS=y -# CONFIG_SLUB_STATS is not set -CONFIG_KMALLOC_PARTITION_CACHES=y -CONFIG_KMALLOC_PARTITION_RANDOM=y -# end of Slab allocator options - -CONFIG_SHUFFLE_PAGE_ALLOCATOR=y -# CONFIG_COMPAT_BRK is not set -CONFIG_SPARSEMEM=y -CONFIG_SPARSEMEM_EXTREME=y -CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y -CONFIG_SPARSEMEM_VMEMMAP=y -CONFIG_HAVE_GUP_FAST=y -CONFIG_MEMBLOCK_KHO_SCRATCH=y -CONFIG_ARCH_KEEP_MEMBLOCK=y -CONFIG_NUMA_KEEP_MEMINFO=y -CONFIG_MEMORY_ISOLATION=y -CONFIG_EXCLUSIVE_SYSTEM_RAM=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTPLUG=y -# CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE is not set -CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y -# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_KERNEL is not set -# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE is not set -CONFIG_MEMORY_HOTREMOVE=y -CONFIG_MHP_MEMMAP_ON_MEMORY=y -CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y -CONFIG_SPLIT_PTE_PTLOCKS=y -CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y -CONFIG_SPLIT_PMD_PTLOCKS=y -CONFIG_BALLOON=y -CONFIG_BALLOON_MIGRATION=y -CONFIG_COMPACTION=y -CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 -CONFIG_PAGE_REPORTING=y -CONFIG_NUMA_MIGRATION=y -CONFIG_MIGRATION=y -CONFIG_DEVICE_MIGRATION=y -CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y -CONFIG_ARCH_ENABLE_THP_MIGRATION=y -CONFIG_CONTIG_ALLOC=y -CONFIG_PCP_BATCH_SCALE_MAX=5 -CONFIG_PHYS_ADDR_T_64BIT=y -CONFIG_MMU_NOTIFIER=y -CONFIG_KSM=y -CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 -CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y -CONFIG_MEMORY_FAILURE=y -CONFIG_HWPOISON_INJECT=m -CONFIG_ARCH_WANTS_THP_SWAP=y -# CONFIG_PERSISTENT_HUGE_ZERO_FOLIO is not set -CONFIG_MM_ID=y -CONFIG_TRANSPARENT_HUGEPAGE=y -CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y -# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set -# CONFIG_TRANSPARENT_HUGEPAGE_NEVER is not set -CONFIG_TRANSPARENT_HUGEPAGE_SHMEM_HUGE_NEVER=y -# CONFIG_TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ALWAYS is not set -# CONFIG_TRANSPARENT_HUGEPAGE_SHMEM_HUGE_WITHIN_SIZE is not set -# CONFIG_TRANSPARENT_HUGEPAGE_SHMEM_HUGE_ADVISE is not set -CONFIG_TRANSPARENT_HUGEPAGE_TMPFS_HUGE_NEVER=y -# CONFIG_TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ALWAYS is not set -# CONFIG_TRANSPARENT_HUGEPAGE_TMPFS_HUGE_WITHIN_SIZE is not set -# CONFIG_TRANSPARENT_HUGEPAGE_TMPFS_HUGE_ADVISE is not set -CONFIG_THP_SWAP=y -# CONFIG_NO_PAGE_MAPCOUNT is not set -CONFIG_PAGE_MAPCOUNT=y -CONFIG_PGTABLE_HAS_HUGE_LEAVES=y -CONFIG_HAVE_GIGANTIC_FOLIOS=y -CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP=y -CONFIG_ARCH_SUPPORTS_PMD_PFNMAP=y -CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y -CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y -CONFIG_USE_PERCPU_NUMA_NODE_ID=y -CONFIG_HAVE_SETUP_PER_CPU_AREA=y -CONFIG_CMA=y -# CONFIG_CMA_DEBUGFS is not set -CONFIG_CMA_SYSFS=y -CONFIG_CMA_AREAS=7 -CONFIG_PAGE_BLOCK_MAX_ORDER=10 -CONFIG_GENERIC_EARLY_IOREMAP=y -# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set -CONFIG_PAGE_IDLE_FLAG=y -CONFIG_IDLE_PAGE_TRACKING=y -CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y -CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y -CONFIG_ARCH_HAS_ZONE_DMA_SET=y -CONFIG_ZONE_DMA=y -CONFIG_ZONE_DMA32=y -CONFIG_ZONE_DEVICE=y -CONFIG_HMM_MIRROR=y -CONFIG_GET_FREE_REGION=y -CONFIG_DEVICE_PRIVATE=y -CONFIG_VMAP_PFN=y -CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y -CONFIG_ARCH_HAS_PKEYS=y -CONFIG_ARCH_USES_PG_ARCH_2=y -CONFIG_ARCH_USES_PG_ARCH_3=y -CONFIG_VM_EVENT_COUNTERS=y -# CONFIG_PERCPU_STATS is not set -# CONFIG_GUP_TEST is not set -# CONFIG_DMAPOOL_TEST is not set -CONFIG_ARCH_HAS_PTE_SPECIAL=y -CONFIG_MAPPING_DIRTY_HELPERS=y -CONFIG_MEMFD_CREATE=y -CONFIG_SECRETMEM=y -CONFIG_ANON_VMA_NAME=y -CONFIG_HAVE_ARCH_USERFAULTFD_WP=y -CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y -CONFIG_USERFAULTFD=y -CONFIG_PTE_MARKER_UFFD_WP=y -CONFIG_LRU_GEN=y -CONFIG_LRU_GEN_ENABLED=y -# CONFIG_LRU_GEN_STATS is not set -CONFIG_LRU_GEN_WALKS_MMU=y -CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y -CONFIG_PER_VMA_LOCK=y -CONFIG_LOCK_MM_AND_FIND_VMA=y -CONFIG_IOMMU_MM_DATA=y -CONFIG_EXECMEM=y -CONFIG_NUMA_MEMBLKS=y -# CONFIG_NUMA_EMU is not set -CONFIG_ARCH_HAS_USER_SHADOW_STACK=y -CONFIG_PT_RECLAIM=y -CONFIG_FIND_NORMAL_PAGE=y -CONFIG_ARCH_HAS_LAZY_MMU_MODE=y - -# -# Data Access Monitoring -# -# CONFIG_DAMON is not set -# end of Data Access Monitoring -# end of Memory Management options - -CONFIG_NET=y -CONFIG_COMPAT_NETLINK_MESSAGES=y -CONFIG_NET_INGRESS=y -CONFIG_NET_EGRESS=y -CONFIG_NET_XGRESS=y -CONFIG_NET_REDIRECT=y -CONFIG_SKB_DECRYPTED=y -CONFIG_SKB_EXTENSIONS=y -CONFIG_NET_DEVMEM=y -CONFIG_NET_SHAPER=y -CONFIG_NET_CRC32C=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_DIAG=m -CONFIG_INET_PSP=y -CONFIG_UNIX=y -CONFIG_AF_UNIX_OOB=y -CONFIG_UNIX_DIAG=m -CONFIG_TLS=m -CONFIG_TLS_DEVICE=y -CONFIG_XFRM=y -CONFIG_XFRM_OFFLOAD=y -CONFIG_XFRM_ALGO=m -CONFIG_XFRM_USER=m -CONFIG_XFRM_INTERFACE=m -# CONFIG_XFRM_SUB_POLICY is not set -# CONFIG_XFRM_MIGRATE is not set -CONFIG_XFRM_STATISTICS=y -CONFIG_XFRM_AH=m -CONFIG_XFRM_ESP=m -CONFIG_XFRM_IPCOMP=m -CONFIG_NET_KEY=m -# CONFIG_NET_KEY_MIGRATE is not set -CONFIG_XFRM_IPTFS=m -CONFIG_XFRM_ESPINTCP=y -CONFIG_SMC=m -CONFIG_SMC_DIAG=m -CONFIG_SMC_HS_CTRL_BPF=y -CONFIG_DIBS=m -CONFIG_DIBS_LO=y -CONFIG_XDP_SOCKETS=y -CONFIG_XDP_SOCKETS_DIAG=m -CONFIG_NET_HANDSHAKE=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_FIB_TRIE_STATS=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_ROUTE_CLASSID=y -# CONFIG_IP_PNP is not set -CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE_DEMUX=m -CONFIG_NET_IP_TUNNEL=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y -CONFIG_IP_MROUTE_COMMON=y -CONFIG_IP_MROUTE=y -CONFIG_IP_MROUTE_MULTIPLE_TABLES=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_SYN_COOKIES=y -CONFIG_NET_IPVTI=m -CONFIG_NET_UDP_TUNNEL=m -CONFIG_NET_FOU=m -CONFIG_NET_FOU_IP_TUNNELS=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_ESP_OFFLOAD=m -CONFIG_INET_ESPINTCP=y -CONFIG_INET_IPCOMP=m -CONFIG_INET_TABLE_PERTURB_ORDER=16 -CONFIG_INET_XFRM_TUNNEL=m -CONFIG_INET_TUNNEL=m -CONFIG_INET_DIAG=m -CONFIG_INET_TCP_DIAG=m -CONFIG_INET_UDP_DIAG=m -CONFIG_INET_RAW_DIAG=m -CONFIG_INET_DIAG_DESTROY=y -CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_BIC=m -CONFIG_TCP_CONG_CUBIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_VEGAS=m -CONFIG_TCP_CONG_NV=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m -CONFIG_TCP_CONG_DCTCP=m -CONFIG_TCP_CONG_CDG=m -CONFIG_TCP_CONG_BBR=m -CONFIG_DEFAULT_CUBIC=y -# CONFIG_DEFAULT_RENO is not set -CONFIG_DEFAULT_TCP_CONG="cubic" -CONFIG_TCP_AO=y -CONFIG_TCP_MD5SIG=y -CONFIG_IPV6=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_ESP_OFFLOAD=m -CONFIG_INET6_ESPINTCP=y -CONFIG_INET6_IPCOMP=m -CONFIG_IPV6_MIP6=m -CONFIG_IPV6_ILA=m -CONFIG_INET6_XFRM_TUNNEL=m -CONFIG_INET6_TUNNEL=m -CONFIG_IPV6_VTI=m -CONFIG_IPV6_SIT=m -CONFIG_IPV6_SIT_6RD=y -CONFIG_IPV6_NDISC_NODETYPE=y -CONFIG_IPV6_TUNNEL=m -CONFIG_IPV6_GRE=m -CONFIG_IPV6_FOU=m -CONFIG_IPV6_FOU_TUNNEL=m -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_SUBTREES=y -CONFIG_IPV6_MROUTE=y -CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y -CONFIG_IPV6_PIMSM_V2=y -CONFIG_IPV6_SEG6_LWTUNNEL=y -CONFIG_IPV6_SEG6_HMAC=y -CONFIG_IPV6_SEG6_BPF=y -# CONFIG_IPV6_RPL_LWTUNNEL is not set -CONFIG_IPV6_IOAM6_LWTUNNEL=y -CONFIG_NETLABEL=y -CONFIG_MPTCP=y -CONFIG_INET_MPTCP_DIAG=m -CONFIG_MPTCP_IPV6=y -CONFIG_NETWORK_SECMARK=y -CONFIG_NET_PTP_CLASSIFY=y -CONFIG_NETWORK_PHY_TIMESTAMPING=y -CONFIG_NETFILTER=y -CONFIG_NETFILTER_ADVANCED=y -CONFIG_BRIDGE_NETFILTER=m - -# -# Core Netfilter Configuration -# -CONFIG_NETFILTER_INGRESS=y -CONFIG_NETFILTER_EGRESS=y -CONFIG_NETFILTER_SKIP_EGRESS=y -CONFIG_NETFILTER_NETLINK=y -CONFIG_NETFILTER_FAMILY_BRIDGE=y -CONFIG_NETFILTER_FAMILY_ARP=y -CONFIG_NETFILTER_BPF_LINK=y -CONFIG_NETFILTER_NETLINK_HOOK=m -CONFIG_NETFILTER_NETLINK_ACCT=m -CONFIG_NETFILTER_NETLINK_QUEUE=m -CONFIG_NETFILTER_NETLINK_LOG=m -CONFIG_NETFILTER_NETLINK_OSF=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_LOG_SYSLOG=m -CONFIG_NETFILTER_CONNCOUNT=m -CONFIG_NF_CONNTRACK_MARK=y -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_ZONES=y -# CONFIG_NF_CONNTRACK_PROCFS is not set -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CONNTRACK_TIMEOUT=y -CONFIG_NF_CONNTRACK_TIMESTAMP=y -CONFIG_NF_CONNTRACK_LABELS=y -CONFIG_NF_CONNTRACK_OVS=y -CONFIG_NF_CT_PROTO_GRE=y -CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_BROADCAST=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_SNMP=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NF_CT_NETLINK_TIMEOUT=m -CONFIG_NF_CT_NETLINK_HELPER=m -CONFIG_NETFILTER_NETLINK_GLUE_CT=y -CONFIG_NF_NAT=m -CONFIG_NF_NAT_AMANDA=m -CONFIG_NF_NAT_FTP=m -CONFIG_NF_NAT_IRC=m -CONFIG_NF_NAT_SIP=m -CONFIG_NF_NAT_TFTP=m -CONFIG_NF_NAT_REDIRECT=y -CONFIG_NF_NAT_MASQUERADE=y -CONFIG_NF_NAT_OVS=y -CONFIG_NETFILTER_SYNPROXY=m -CONFIG_NF_TABLES=m -CONFIG_NF_TABLES_INET=y -CONFIG_NF_TABLES_NETDEV=y -CONFIG_NFT_NUMGEN=m -CONFIG_NFT_CT=m -# CONFIG_NFT_EXTHDR_DCCP is not set -CONFIG_NFT_FLOW_OFFLOAD=m -CONFIG_NFT_CONNLIMIT=m -CONFIG_NFT_LOG=m -CONFIG_NFT_LIMIT=m -CONFIG_NFT_MASQ=m -CONFIG_NFT_REDIR=m -CONFIG_NFT_NAT=m -CONFIG_NFT_TUNNEL=m -CONFIG_NFT_QUEUE=m -CONFIG_NFT_QUOTA=m -CONFIG_NFT_REJECT=m -CONFIG_NFT_REJECT_INET=m -CONFIG_NFT_COMPAT=m -CONFIG_NFT_HASH=m -CONFIG_NFT_FIB=m -CONFIG_NFT_FIB_INET=m -CONFIG_NFT_XFRM=m -CONFIG_NFT_SOCKET=m -CONFIG_NFT_OSF=m -CONFIG_NFT_TPROXY=m -CONFIG_NFT_SYNPROXY=m -CONFIG_NF_DUP_NETDEV=m -CONFIG_NFT_DUP_NETDEV=m -CONFIG_NFT_FWD_NETDEV=m -CONFIG_NFT_FIB_NETDEV=m -CONFIG_NFT_REJECT_NETDEV=m -CONFIG_NF_FLOW_TABLE_INET=m -CONFIG_NF_FLOW_TABLE=m -# CONFIG_NF_FLOW_TABLE_PROCFS is not set -CONFIG_NETFILTER_XTABLES=m -CONFIG_NETFILTER_XTABLES_COMPAT=y -CONFIG_NETFILTER_XTABLES_LEGACY=y - -# -# Xtables combined modules -# -CONFIG_NETFILTER_XT_MARK=m -CONFIG_NETFILTER_XT_CONNMARK=m -CONFIG_NETFILTER_XT_SET=m - -# -# Xtables targets -# -CONFIG_NETFILTER_XT_TARGET_AUDIT=m -CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m -CONFIG_NETFILTER_XT_TARGET_CT=m -CONFIG_NETFILTER_XT_TARGET_DSCP=m -CONFIG_NETFILTER_XT_TARGET_HL=m -CONFIG_NETFILTER_XT_TARGET_HMARK=m -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m -CONFIG_NETFILTER_XT_TARGET_LED=m -CONFIG_NETFILTER_XT_TARGET_LOG=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_NAT=m -CONFIG_NETFILTER_XT_TARGET_NETMAP=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m -CONFIG_NETFILTER_XT_TARGET_RATEEST=m -CONFIG_NETFILTER_XT_TARGET_REDIRECT=m -CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m -CONFIG_NETFILTER_XT_TARGET_TEE=m -CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TRACE=m -CONFIG_NETFILTER_XT_TARGET_SECMARK=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m - -# -# Xtables matches -# -CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m -CONFIG_NETFILTER_XT_MATCH_BPF=m -CONFIG_NETFILTER_XT_MATCH_CGROUP=m -CONFIG_NETFILTER_XT_MATCH_CLUSTER=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_CPU=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ECN=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_HL=m -CONFIG_NETFILTER_XT_MATCH_IPCOMP=m -CONFIG_NETFILTER_XT_MATCH_IPRANGE=m -CONFIG_NETFILTER_XT_MATCH_IPVS=m -CONFIG_NETFILTER_XT_MATCH_L2TP=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_NFACCT=m -CONFIG_NETFILTER_XT_MATCH_OSF=m -CONFIG_NETFILTER_XT_MATCH_OWNER=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_RATEEST=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_RECENT=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_SOCKET=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_TIME=m -CONFIG_NETFILTER_XT_MATCH_U32=m -# end of Core Netfilter Configuration - -CONFIG_IP_SET=m -CONFIG_IP_SET_MAX=256 -CONFIG_IP_SET_BITMAP_IP=m -CONFIG_IP_SET_BITMAP_IPMAC=m -CONFIG_IP_SET_BITMAP_PORT=m -CONFIG_IP_SET_HASH_IP=m -CONFIG_IP_SET_HASH_IPMARK=m -CONFIG_IP_SET_HASH_IPPORT=m -CONFIG_IP_SET_HASH_IPPORTIP=m -CONFIG_IP_SET_HASH_IPPORTNET=m -CONFIG_IP_SET_HASH_IPMAC=m -CONFIG_IP_SET_HASH_MAC=m -CONFIG_IP_SET_HASH_NETPORTNET=m -CONFIG_IP_SET_HASH_NET=m -CONFIG_IP_SET_HASH_NETNET=m -CONFIG_IP_SET_HASH_NETPORT=m -CONFIG_IP_SET_HASH_NETIFACE=m -CONFIG_IP_SET_LIST_SET=m -CONFIG_IP_VS=m -CONFIG_IP_VS_IPV6=y -# CONFIG_IP_VS_DEBUG is not set -CONFIG_IP_VS_TAB_BITS=12 - -# -# IPVS transport protocol load balancing support -# -CONFIG_IP_VS_PROTO_TCP=y -CONFIG_IP_VS_PROTO_UDP=y -CONFIG_IP_VS_PROTO_AH_ESP=y -CONFIG_IP_VS_PROTO_ESP=y -CONFIG_IP_VS_PROTO_AH=y -CONFIG_IP_VS_PROTO_SCTP=y - -# -# IPVS scheduler -# -CONFIG_IP_VS_RR=m -CONFIG_IP_VS_WRR=m -CONFIG_IP_VS_LC=m -CONFIG_IP_VS_WLC=m -CONFIG_IP_VS_FO=m -CONFIG_IP_VS_OVF=m -CONFIG_IP_VS_LBLC=m -CONFIG_IP_VS_LBLCR=m -CONFIG_IP_VS_DH=m -CONFIG_IP_VS_SH=m -CONFIG_IP_VS_MH=m -CONFIG_IP_VS_SED=m -CONFIG_IP_VS_NQ=m -CONFIG_IP_VS_TWOS=m - -# -# IPVS SH scheduler -# -CONFIG_IP_VS_SH_TAB_BITS=8 - -# -# IPVS MH scheduler -# -CONFIG_IP_VS_MH_TAB_INDEX=12 - -# -# IPVS application helper -# -CONFIG_IP_VS_FTP=m -CONFIG_IP_VS_NFCT=y -CONFIG_IP_VS_PE_SIP=m - -# -# IP: Netfilter Configuration -# -CONFIG_NF_DEFRAG_IPV4=m -CONFIG_IP_NF_IPTABLES_LEGACY=m -CONFIG_NF_SOCKET_IPV4=m -CONFIG_NF_TPROXY_IPV4=m -CONFIG_NF_TABLES_IPV4=y -CONFIG_NFT_REJECT_IPV4=m -CONFIG_NFT_DUP_IPV4=m -CONFIG_NFT_FIB_IPV4=m -CONFIG_NF_TABLES_ARP=y -CONFIG_NF_DUP_IPV4=m -CONFIG_NF_LOG_ARP=m -CONFIG_NF_LOG_IPV4=m -CONFIG_NF_REJECT_IPV4=m -CONFIG_NF_NAT_SNMP_BASIC=m -CONFIG_NF_NAT_PPTP=m -CONFIG_NF_NAT_H323=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_RPFILTER=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_SYNPROXY=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_SECURITY=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_NFT_COMPAT_ARP=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -# end of IP: Netfilter Configuration - -# -# IPv6: Netfilter Configuration -# -CONFIG_IP6_NF_IPTABLES_LEGACY=m -CONFIG_NF_SOCKET_IPV6=m -CONFIG_NF_TPROXY_IPV6=m -CONFIG_NF_TABLES_IPV6=y -CONFIG_NFT_REJECT_IPV6=m -CONFIG_NFT_DUP_IPV6=m -CONFIG_NFT_FIB_IPV6=m -CONFIG_NF_DUP_IPV6=m -CONFIG_NF_REJECT_IPV6=m -CONFIG_NF_LOG_IPV6=m -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_RPFILTER=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_MATCH_SRH=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_TARGET_SYNPROXY=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_RAW=m -CONFIG_IP6_NF_SECURITY=m -CONFIG_IP6_NF_NAT=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m -CONFIG_IP6_NF_TARGET_NPT=m -# end of IPv6: Netfilter Configuration - -CONFIG_NF_DEFRAG_IPV6=m -CONFIG_NF_TABLES_BRIDGE=m -CONFIG_NFT_BRIDGE_META=m -CONFIG_NFT_BRIDGE_REJECT=m -CONFIG_NF_CONNTRACK_BRIDGE=m -CONFIG_BRIDGE_NF_EBTABLES_LEGACY=m -CONFIG_BRIDGE_NF_EBTABLES=m -CONFIG_BRIDGE_EBT_BROUTE=m -CONFIG_BRIDGE_EBT_T_FILTER=m -CONFIG_BRIDGE_EBT_T_NAT=m -CONFIG_BRIDGE_EBT_802_3=m -CONFIG_BRIDGE_EBT_AMONG=m -CONFIG_BRIDGE_EBT_ARP=m -CONFIG_BRIDGE_EBT_IP=m -CONFIG_BRIDGE_EBT_IP6=m -CONFIG_BRIDGE_EBT_LIMIT=m -CONFIG_BRIDGE_EBT_MARK=m -CONFIG_BRIDGE_EBT_PKTTYPE=m -CONFIG_BRIDGE_EBT_STP=m -CONFIG_BRIDGE_EBT_VLAN=m -CONFIG_BRIDGE_EBT_ARPREPLY=m -CONFIG_BRIDGE_EBT_DNAT=m -CONFIG_BRIDGE_EBT_MARK_T=m -CONFIG_BRIDGE_EBT_REDIRECT=m -CONFIG_BRIDGE_EBT_SNAT=m -CONFIG_BRIDGE_EBT_LOG=m -CONFIG_BRIDGE_EBT_NFLOG=m -CONFIG_IP_SCTP=m -# CONFIG_SCTP_DBG_OBJCNT is not set -CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA256=y -# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set -CONFIG_INET_SCTP_DIAG=m -CONFIG_RDS=m -CONFIG_RDS_RDMA=m -CONFIG_RDS_TCP=m -# CONFIG_RDS_DEBUG is not set -CONFIG_TIPC=m -CONFIG_TIPC_MEDIA_IB=y -CONFIG_TIPC_MEDIA_UDP=y -CONFIG_TIPC_CRYPTO=y -CONFIG_TIPC_DIAG=m -CONFIG_ATM=m -CONFIG_ATM_BR2684=m -# CONFIG_ATM_BR2684_IPFILTER is not set -CONFIG_L2TP=m -CONFIG_L2TP_DEBUGFS=m -CONFIG_L2TP_V3=y -CONFIG_L2TP_IP=m -CONFIG_L2TP_ETH=m -CONFIG_STP=m -CONFIG_GARP=m -CONFIG_MRP=m -CONFIG_BRIDGE=m -CONFIG_BRIDGE_IGMP_SNOOPING=y -CONFIG_BRIDGE_VLAN_FILTERING=y -CONFIG_BRIDGE_MRP=y -CONFIG_BRIDGE_CFM=y -CONFIG_NET_DSA=m -CONFIG_NET_DSA_TAG_NONE=m -CONFIG_NET_DSA_TAG_AR9331=m -CONFIG_NET_DSA_TAG_BRCM_COMMON=m -CONFIG_NET_DSA_TAG_BRCM=m -CONFIG_NET_DSA_TAG_BRCM_LEGACY=m -CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS=m -CONFIG_NET_DSA_TAG_BRCM_PREPEND=m -CONFIG_NET_DSA_TAG_HELLCREEK=m -CONFIG_NET_DSA_TAG_GSWIP=m -CONFIG_NET_DSA_TAG_DSA_COMMON=m -CONFIG_NET_DSA_TAG_DSA=m -CONFIG_NET_DSA_TAG_EDSA=m -CONFIG_NET_DSA_TAG_MTK=m -CONFIG_NET_DSA_TAG_MXL_862XX=m -CONFIG_NET_DSA_TAG_MXL_GSW1XX=m -CONFIG_NET_DSA_TAG_KSZ=m -# CONFIG_NET_DSA_TAG_NETC is not set -CONFIG_NET_DSA_TAG_OCELOT=m -CONFIG_NET_DSA_TAG_OCELOT_8021Q=m -CONFIG_NET_DSA_TAG_QCA=m -CONFIG_NET_DSA_TAG_RTL4_A=m -CONFIG_NET_DSA_TAG_RTL8_4=m -CONFIG_NET_DSA_TAG_RZN1_A5PSW=m -CONFIG_NET_DSA_TAG_LAN9303=m -CONFIG_NET_DSA_TAG_SJA1105=m -CONFIG_NET_DSA_TAG_TRAILER=m -CONFIG_NET_DSA_TAG_VSC73XX_8021Q=m -CONFIG_NET_DSA_TAG_XRS700X=m -CONFIG_NET_DSA_TAG_YT921X=m -CONFIG_VLAN_8021Q=m -CONFIG_VLAN_8021Q_GVRP=y -CONFIG_VLAN_8021Q_MVRP=y -CONFIG_LLC=m -CONFIG_LLC2=m -CONFIG_X25=m -CONFIG_LAPB=m -CONFIG_PHONET=m -CONFIG_6LOWPAN=m -# CONFIG_6LOWPAN_DEBUGFS is not set -CONFIG_6LOWPAN_NHC=m -CONFIG_6LOWPAN_NHC_DEST=m -CONFIG_6LOWPAN_NHC_FRAGMENT=m -CONFIG_6LOWPAN_NHC_HOP=m -CONFIG_6LOWPAN_NHC_IPV6=m -CONFIG_6LOWPAN_NHC_MOBILITY=m -CONFIG_6LOWPAN_NHC_ROUTING=m -CONFIG_6LOWPAN_NHC_UDP=m -# CONFIG_6LOWPAN_GHC_EXT_HDR_HOP is not set -# CONFIG_6LOWPAN_GHC_UDP is not set -# CONFIG_6LOWPAN_GHC_ICMPV6 is not set -# CONFIG_6LOWPAN_GHC_EXT_HDR_DEST is not set -# CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG is not set -# CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE is not set -CONFIG_IEEE802154=m -# CONFIG_IEEE802154_NL802154_EXPERIMENTAL is not set -CONFIG_IEEE802154_SOCKET=m -CONFIG_IEEE802154_6LOWPAN=m -CONFIG_MAC802154=m -CONFIG_NET_SCHED=y - -# -# Queueing/Scheduling -# -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_MULTIQ=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFB=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -CONFIG_NET_SCH_CBS=m -CONFIG_NET_SCH_ETF=m -CONFIG_NET_SCH_MQPRIO_LIB=m -CONFIG_NET_SCH_TAPRIO=m -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_DRR=m -CONFIG_NET_SCH_MQPRIO=m -CONFIG_NET_SCH_SKBPRIO=m -CONFIG_NET_SCH_CHOKE=m -CONFIG_NET_SCH_QFQ=m -CONFIG_NET_SCH_CODEL=m -CONFIG_NET_SCH_FQ_CODEL=m -CONFIG_NET_SCH_CAKE=m -CONFIG_NET_SCH_FQ=m -CONFIG_NET_SCH_HHF=m -CONFIG_NET_SCH_PIE=m -CONFIG_NET_SCH_FQ_PIE=m -CONFIG_NET_SCH_INGRESS=m -CONFIG_NET_SCH_PLUG=m -CONFIG_NET_SCH_ETS=m -CONFIG_NET_SCH_BPF=y -CONFIG_NET_SCH_DUALPI2=m -# CONFIG_NET_SCH_DEFAULT is not set - -# -# Classification -# -CONFIG_NET_CLS=y -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -# CONFIG_CLS_U32_PERF is not set -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_FLOW=m -CONFIG_NET_CLS_CGROUP=m -CONFIG_NET_CLS_BPF=m -CONFIG_NET_CLS_FLOWER=m -CONFIG_NET_CLS_MATCHALL=m -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_STACK=32 -CONFIG_NET_EMATCH_CMP=m -CONFIG_NET_EMATCH_NBYTE=m -CONFIG_NET_EMATCH_U32=m -CONFIG_NET_EMATCH_META=m -CONFIG_NET_EMATCH_TEXT=m -CONFIG_NET_EMATCH_CANID=m -CONFIG_NET_EMATCH_IPSET=m -CONFIG_NET_EMATCH_IPT=m -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_POLICE=m -CONFIG_NET_ACT_GACT=m -CONFIG_GACT_PROB=y -CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_SAMPLE=m -CONFIG_NET_ACT_NAT=m -CONFIG_NET_ACT_PEDIT=m -CONFIG_NET_ACT_SIMP=m -CONFIG_NET_ACT_SKBEDIT=m -CONFIG_NET_ACT_CSUM=m -CONFIG_NET_ACT_MPLS=m -CONFIG_NET_ACT_VLAN=m -CONFIG_NET_ACT_BPF=m -CONFIG_NET_ACT_CONNMARK=m -CONFIG_NET_ACT_CTINFO=m -CONFIG_NET_ACT_SKBMOD=m -# CONFIG_NET_ACT_IFE is not set -CONFIG_NET_ACT_TUNNEL_KEY=m -CONFIG_NET_ACT_CT=m -CONFIG_NET_ACT_GATE=m -CONFIG_NET_TC_SKB_EXT=y -CONFIG_NET_SCH_FIFO=y -CONFIG_DCB=y -CONFIG_DNS_RESOLVER=y -CONFIG_BATMAN_ADV=m -# CONFIG_BATMAN_ADV_BATMAN_V is not set -CONFIG_BATMAN_ADV_BLA=y -CONFIG_BATMAN_ADV_DAT=y -CONFIG_BATMAN_ADV_MCAST=y -# CONFIG_BATMAN_ADV_DEBUG is not set -# CONFIG_BATMAN_ADV_TRACING is not set -CONFIG_OPENVSWITCH=m -CONFIG_OPENVSWITCH_GRE=m -CONFIG_OPENVSWITCH_VXLAN=m -CONFIG_OPENVSWITCH_GENEVE=m -CONFIG_VSOCKETS=m -CONFIG_VSOCKETS_DIAG=m -CONFIG_VSOCKETS_LOOPBACK=m -CONFIG_VMWARE_VMCI_VSOCKETS=m -CONFIG_VIRTIO_VSOCKETS=m -CONFIG_VIRTIO_VSOCKETS_COMMON=m -CONFIG_HYPERV_VSOCKETS=m -CONFIG_NETLINK_DIAG=m -CONFIG_MPLS=y -CONFIG_NET_MPLS_GSO=m -CONFIG_MPLS_ROUTING=m -CONFIG_MPLS_IPTUNNEL=m -CONFIG_NET_NSH=m -CONFIG_HSR=m -CONFIG_NET_SWITCHDEV=y -CONFIG_NET_L3_MASTER_DEV=y -CONFIG_QRTR=m -CONFIG_QRTR_SMD=m -CONFIG_QRTR_TUN=m -CONFIG_QRTR_MHI=m -CONFIG_NET_NCSI=y -CONFIG_NCSI_OEM_CMD_GET_MAC=y -# CONFIG_NCSI_OEM_CMD_KEEP_PHY is not set -CONFIG_PCPU_DEV_REFCNT=y -CONFIG_MAX_SKB_FRAGS=17 -CONFIG_RPS=y -CONFIG_RFS_ACCEL=y -CONFIG_SOCK_RX_QUEUE_MAPPING=y -CONFIG_XPS=y -CONFIG_CGROUP_NET_PRIO=y -CONFIG_CGROUP_NET_CLASSID=y -CONFIG_NET_RX_BUSY_POLL=y -CONFIG_BQL=y -CONFIG_BPF_STREAM_PARSER=y -CONFIG_NET_FLOW_LIMIT=y - -# -# Network testing -# -CONFIG_NET_PKTGEN=m -CONFIG_NET_DROP_MONITOR=y -# end of Network testing -# end of Networking options - -CONFIG_CAN=m -CONFIG_CAN_RAW=m -CONFIG_CAN_BCM=m -CONFIG_CAN_GW=m -CONFIG_CAN_J1939=m -CONFIG_CAN_ISOTP=m -CONFIG_BT=m -CONFIG_BT_BREDR=y -CONFIG_BT_RFCOMM=m -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=m -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=m -CONFIG_BT_LE=y -CONFIG_BT_LE_L2CAP_ECRED=y -CONFIG_BT_6LOWPAN=m -CONFIG_BT_LEDS=y -CONFIG_BT_MSFTEXT=y -CONFIG_BT_AOSPEXT=y -CONFIG_BT_DEBUGFS=y -# CONFIG_BT_SELFTEST is not set - -# -# Bluetooth device drivers -# -CONFIG_BT_INTEL=m -CONFIG_BT_BCM=m -CONFIG_BT_RTL=m -CONFIG_BT_QCA=m -CONFIG_BT_MTK=m -CONFIG_BT_HCIBTUSB=m -CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y -CONFIG_BT_HCIBTUSB_POLL_SYNC=y -CONFIG_BT_HCIBTUSB_BCM=y -CONFIG_BT_HCIBTUSB_MTK=y -CONFIG_BT_HCIBTUSB_RTL=y -CONFIG_BT_HCIBTSDIO=m -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_SERDEV=y -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_NOKIA=m -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIUART_ATH3K=y -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIUART_3WIRE=y -CONFIG_BT_HCIUART_INTEL=y -CONFIG_BT_HCIUART_BCM=y -CONFIG_BT_HCIUART_RTL=y -CONFIG_BT_HCIUART_QCA=y -CONFIG_BT_HCIUART_AG6XX=y -CONFIG_BT_HCIUART_MRVL=y -CONFIG_BT_HCIUART_AML=y -CONFIG_BT_HCIBCM203X=m -CONFIG_BT_HCIBCM4377=m -CONFIG_BT_HCIBPA10X=m -CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIVHCI=m -CONFIG_BT_MRVL=m -CONFIG_BT_MRVL_SDIO=m -CONFIG_BT_ATH3K=m -CONFIG_BT_MTKSDIO=m -CONFIG_BT_MTKUART=m -CONFIG_BT_QCOMSMD=m -CONFIG_BT_HCIRSI=m -CONFIG_BT_VIRTIO=m -CONFIG_BT_NXPUART=m -CONFIG_BT_INTEL_PCIE=m -# end of Bluetooth device drivers - -CONFIG_AF_RXRPC=m -CONFIG_AF_RXRPC_IPV6=y -# CONFIG_AF_RXRPC_INJECT_LOSS is not set -# CONFIG_AF_RXRPC_INJECT_RX_DELAY is not set -# CONFIG_AF_RXRPC_DEBUG is not set -CONFIG_RXKAD=y -CONFIG_RXGK=y -CONFIG_RXPERF=m -CONFIG_AF_KCM=m -CONFIG_STREAM_PARSER=y -CONFIG_MCTP=y -CONFIG_MCTP_FLOWS=y -CONFIG_FIB_RULES=y -CONFIG_WIRELESS=y -CONFIG_WIRELESS_EXT=y -CONFIG_WEXT_CORE=y -CONFIG_WEXT_PROC=y -CONFIG_WEXT_PRIV=y -CONFIG_CFG80211=m -# CONFIG_NL80211_TESTMODE is not set -# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set -# CONFIG_CFG80211_CERTIFICATION_ONUS is not set -CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y -CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y -CONFIG_CFG80211_DEFAULT_PS=y -CONFIG_CFG80211_DEBUGFS=y -CONFIG_CFG80211_CRDA_SUPPORT=y -CONFIG_CFG80211_WEXT=y -CONFIG_MAC80211=m -CONFIG_MAC80211_HAS_RC=y -CONFIG_MAC80211_RC_MINSTREL=y -CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y -CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" -CONFIG_MAC80211_MESH=y -CONFIG_MAC80211_LEDS=y -CONFIG_MAC80211_DEBUGFS=y -CONFIG_MAC80211_MESSAGE_TRACING=y -# CONFIG_MAC80211_DEBUG_MENU is not set -CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 -CONFIG_RFKILL=y -CONFIG_RFKILL_LEDS=y -CONFIG_RFKILL_INPUT=y -CONFIG_RFKILL_GPIO=m -CONFIG_NET_9P=m -CONFIG_NET_9P_FD=m -CONFIG_NET_9P_VIRTIO=m -CONFIG_NET_9P_XEN=m -CONFIG_NET_9P_USBG=m -CONFIG_NET_9P_RDMA=m -# CONFIG_NET_9P_DEBUG is not set -CONFIG_CEPH_LIB=m -# CONFIG_CEPH_LIB_PRETTYDEBUG is not set -CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y -CONFIG_NFC=m -CONFIG_NFC_DIGITAL=m -CONFIG_NFC_NCI=m -CONFIG_NFC_NCI_SPI=m -CONFIG_NFC_NCI_UART=m -CONFIG_NFC_HCI=m -CONFIG_NFC_SHDLC=y - -# -# Near Field Communication (NFC) devices -# -CONFIG_NFC_TRF7970A=m -CONFIG_NFC_MEI_PHY=m -CONFIG_NFC_SIM=m -CONFIG_NFC_PORT100=m -CONFIG_NFC_VIRTUAL_NCI=m -CONFIG_NFC_FDP=m -CONFIG_NFC_FDP_I2C=m -CONFIG_NFC_PN544=m -CONFIG_NFC_PN544_I2C=m -CONFIG_NFC_PN544_MEI=m -CONFIG_NFC_PN533=m -CONFIG_NFC_PN533_USB=m -CONFIG_NFC_PN533_I2C=m -CONFIG_NFC_PN532_UART=m -CONFIG_NFC_MICROREAD=m -CONFIG_NFC_MICROREAD_I2C=m -CONFIG_NFC_MICROREAD_MEI=m -CONFIG_NFC_MRVL=m -CONFIG_NFC_MRVL_USB=m -CONFIG_NFC_MRVL_UART=m -CONFIG_NFC_MRVL_I2C=m -CONFIG_NFC_MRVL_SPI=m -CONFIG_NFC_ST21NFCA=m -CONFIG_NFC_ST21NFCA_I2C=m -CONFIG_NFC_ST_NCI=m -CONFIG_NFC_ST_NCI_I2C=m -CONFIG_NFC_ST_NCI_SPI=m -CONFIG_NFC_NXP_NCI=m -CONFIG_NFC_NXP_NCI_I2C=m -CONFIG_NFC_S3FWRN5=m -CONFIG_NFC_S3FWRN5_I2C=m -CONFIG_NFC_S3FWRN82_UART=m -CONFIG_NFC_ST95HF=m -# end of Near Field Communication (NFC) devices - -CONFIG_PSAMPLE=m -CONFIG_NET_IFE=m -CONFIG_LWTUNNEL=y -CONFIG_LWTUNNEL_BPF=y -CONFIG_DST_CACHE=y -CONFIG_GRO_CELLS=y -CONFIG_SOCK_VALIDATE_XMIT=y -CONFIG_NET_IEEE8021Q_HELPERS=y -CONFIG_NET_SELFTESTS=y -CONFIG_NET_SOCK_MSG=y -CONFIG_NET_DEVLINK=y -CONFIG_PAGE_POOL=y -CONFIG_PAGE_POOL_STATS=y -CONFIG_FAILOVER=y -CONFIG_ETHTOOL_NETLINK=y - -# -# Device Drivers -# -CONFIG_ARM_AMBA=y -CONFIG_TEGRA_AHB=y -CONFIG_HAVE_PCI=y -CONFIG_GENERIC_PCI_IOMAP=y -CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -CONFIG_PCI_DOMAINS_GENERIC=y -CONFIG_PCI_SYSCALL=y -CONFIG_PCIEPORTBUS=y -CONFIG_HOTPLUG_PCI_PCIE=y -CONFIG_PCIEAER=y -# CONFIG_PCIEAER_INJECT is not set -# CONFIG_PCIE_ECRC is not set -CONFIG_PCIEASPM=y -CONFIG_PCIEASPM_DEFAULT=y -# CONFIG_PCIEASPM_POWERSAVE is not set -# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set -# CONFIG_PCIEASPM_PERFORMANCE is not set -CONFIG_PCIE_PME=y -CONFIG_PCIE_DPC=y -CONFIG_PCIE_PTM=y -CONFIG_PCIE_EDR=y -CONFIG_PCI_MSI=y -CONFIG_PCI_QUIRKS=y -# CONFIG_PCI_DEBUG is not set -CONFIG_PCI_REALLOC_ENABLE_AUTO=y -CONFIG_PCI_STUB=m -CONFIG_PCI_PF_STUB=m -CONFIG_PCI_ATS=y -CONFIG_PCI_IDE=y -CONFIG_PCI_TSM=y -CONFIG_PCI_DOE=y -CONFIG_PCI_ECAM=y -CONFIG_PCI_BRIDGE_EMUL=y -CONFIG_PCI_IOV=y -CONFIG_PCI_NPEM=y -CONFIG_PCI_PRI=y -CONFIG_PCI_PASID=y -CONFIG_PCIE_TPH=y -CONFIG_PCI_P2PDMA=y -CONFIG_PCI_LABEL=y -CONFIG_PCI_HYPERV=m -CONFIG_PCI_DYNAMIC_OF_NODES=y -CONFIG_VGA_ARB=y -CONFIG_VGA_ARB_MAX_GPUS=16 -CONFIG_HOTPLUG_PCI=y -CONFIG_HOTPLUG_PCI_ACPI=y -CONFIG_HOTPLUG_PCI_ACPI_AMPERE_ALTRA=m -CONFIG_HOTPLUG_PCI_ACPI_IBM=m -CONFIG_HOTPLUG_PCI_CPCI=y -CONFIG_HOTPLUG_PCI_OCTEONEP=y -CONFIG_HOTPLUG_PCI_SHPC=y - -# -# PCI controller drivers -# -CONFIG_PCI_HOST_COMMON=y -CONFIG_PCI_AARDVARK=y -CONFIG_PCIE_ALTERA=y -CONFIG_PCIE_ALTERA_MSI=y -CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR=0xfffff000 -CONFIG_PCIE_APPLE=m -CONFIG_PCI_HOST_THUNDER_PEM=y -CONFIG_PCI_HOST_THUNDER_ECAM=y -CONFIG_PCI_FTPCI100=y -CONFIG_PCI_HOST_GENERIC=y -CONFIG_PCIE_HISI_ERR=y -CONFIG_PCIE_MEDIATEK=y -CONFIG_PCIE_MEDIATEK_GEN3=m -CONFIG_PCI_HYPERV_INTERFACE=m -CONFIG_PCI_TEGRA=y -CONFIG_PCIE_RCAR_HOST=y -CONFIG_PCIE_RCAR_EP=y -CONFIG_PCIE_RENESAS_RZG3S_HOST=y -CONFIG_PCIE_ROCKCHIP=y -CONFIG_PCIE_ROCKCHIP_HOST=m -CONFIG_PCIE_ROCKCHIP_EP=y -CONFIG_PCI_XGENE=y -CONFIG_PCI_XGENE_MSI=y -CONFIG_PCIE_XILINX=y -CONFIG_PCIE_XILINX_DMA_PL=y -CONFIG_PCIE_XILINX_NWL=y -CONFIG_PCIE_XILINX_CPM=y - -# -# Cadence-based PCIe controllers -# -CONFIG_PCIE_CADENCE=y -CONFIG_PCIE_CADENCE_HOST=y -CONFIG_PCIE_CADENCE_EP=y -CONFIG_PCIE_CADENCE_PLAT=y -CONFIG_PCIE_CADENCE_PLAT_HOST=y -CONFIG_PCIE_CADENCE_PLAT_EP=y -CONFIG_PCI_SKY1_HOST=m -CONFIG_PCIE_SG2042_HOST=m -CONFIG_PCI_J721E=y -CONFIG_PCI_J721E_HOST=y -CONFIG_PCI_J721E_EP=y -# end of Cadence-based PCIe controllers - -# -# DesignWare-based PCIe controllers -# -CONFIG_PCIE_DW=y -# CONFIG_PCIE_DW_DEBUGFS is not set -CONFIG_PCIE_DW_HOST=y -CONFIG_PCIE_DW_EP=y -CONFIG_PCIE_AL=y -CONFIG_PCIE_AMD_MDB=y -CONFIG_PCI_MESON=m -CONFIG_PCI_IMX6=y -CONFIG_PCI_IMX6_HOST=y -CONFIG_PCI_IMX6_EP=y -CONFIG_PCI_LAYERSCAPE=y -CONFIG_PCI_LAYERSCAPE_EP=y -CONFIG_PCI_HISI=y -CONFIG_PCIE_KIRIN=y -CONFIG_PCIE_HISI_STB=y -CONFIG_PCIE_KEEMBAY=y -CONFIG_PCIE_KEEMBAY_HOST=y -CONFIG_PCIE_KEEMBAY_EP=y -CONFIG_PCIE_ARMADA_8K=y -CONFIG_PCIE_TEGRA194=m -CONFIG_PCIE_TEGRA194_HOST=m -CONFIG_PCIE_TEGRA194_EP=m -CONFIG_PCIE_NXP_S32G=y -CONFIG_PCIE_DW_PLAT=y -CONFIG_PCIE_DW_PLAT_HOST=y -CONFIG_PCIE_DW_PLAT_EP=y -CONFIG_PCIE_QCOM_COMMON=y -CONFIG_PCIE_QCOM=y -CONFIG_PCIE_QCOM_EP=m -CONFIG_PCIE_RCAR_GEN4=m -CONFIG_PCIE_RCAR_GEN4_HOST=m -CONFIG_PCIE_RCAR_GEN4_EP=m -CONFIG_PCIE_ROCKCHIP_DW=y -CONFIG_PCIE_ROCKCHIP_DW_HOST=y -CONFIG_PCIE_ROCKCHIP_DW_EP=y -CONFIG_PCIE_SOPHGO_DW=y -CONFIG_PCIE_STM32_HOST=m -CONFIG_PCIE_STM32_EP=m -CONFIG_PCI_KEYSTONE_TRISTATE=y -CONFIG_PCI_KEYSTONE_HOST=y -CONFIG_PCI_KEYSTONE_EP=y -CONFIG_PCIE_VISCONTI_HOST=y -# end of DesignWare-based PCIe controllers - -# -# Mobiveil-based PCIe controllers -# -# CONFIG_PCIE_LAYERSCAPE_GEN4 is not set -# CONFIG_PCIE_MOBIVEIL_PLAT is not set -# end of Mobiveil-based PCIe controllers - -# -# PLDA-based PCIe controllers -# -CONFIG_PCIE_PLDA_HOST=y -CONFIG_PCIE_MICROCHIP_HOST=y -# end of PLDA-based PCIe controllers -# end of PCI controller drivers - -# -# PCI Endpoint -# -CONFIG_PCI_ENDPOINT=y -CONFIG_PCI_ENDPOINT_CONFIGFS=y -CONFIG_PCI_ENDPOINT_MSI_DOORBELL=y -# CONFIG_PCI_EPF_TEST is not set -CONFIG_PCI_EPF_NTB=m -CONFIG_PCI_EPF_VNTB=m -CONFIG_PCI_EPF_MHI=m -# end of PCI Endpoint - -# -# PCI switch controller drivers -# -CONFIG_PCI_SW_SWITCHTEC=m -# end of PCI switch controller drivers - -CONFIG_HAVE_PWRCTRL=y -CONFIG_PCI_PWRCTRL=y -CONFIG_PCI_PWRCTRL_PWRSEQ=m -CONFIG_PCI_PWRCTRL_GENERIC=y -CONFIG_PCI_PWRCTRL_TC9563=m -CONFIG_CXL_BUS=m -CONFIG_CXL_PCI=m -# CONFIG_CXL_MEM_RAW_COMMANDS is not set -CONFIG_CXL_ACPI=m -CONFIG_CXL_PMEM=m -CONFIG_CXL_MEM=m -CONFIG_CXL_FEATURES=y -# CONFIG_CXL_EDAC_MEM_FEATURES is not set -CONFIG_CXL_PORT=m -CONFIG_CXL_SUSPEND=y -CONFIG_CXL_REGION=y -# CONFIG_CXL_REGION_INVALIDATION_TEST is not set -CONFIG_CXL_RAS=y -CONFIG_PCCARD=m -# CONFIG_PCMCIA is not set -CONFIG_CARDBUS=y - -# -# PC-card bridges -# -CONFIG_YENTA=m -CONFIG_YENTA_O2=y -CONFIG_YENTA_RICOH=y -CONFIG_YENTA_TI=y -CONFIG_YENTA_ENE_TUNE=y -CONFIG_YENTA_TOSHIBA=y -CONFIG_RAPIDIO=y -CONFIG_RAPIDIO_TSI721=m -CONFIG_RAPIDIO_DISC_TIMEOUT=30 -# CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS is not set -CONFIG_RAPIDIO_DMA_ENGINE=y -# CONFIG_RAPIDIO_DEBUG is not set -CONFIG_RAPIDIO_ENUM_BASIC=m -CONFIG_RAPIDIO_CHMAN=m -CONFIG_RAPIDIO_MPORT_CDEV=m - -# -# RapidIO Switch drivers -# -CONFIG_RAPIDIO_CPS_XX=m -CONFIG_RAPIDIO_CPS_GEN2=m -CONFIG_RAPIDIO_RXS_GEN3=m -# end of RapidIO Switch drivers - -CONFIG_PC104=y - -# -# Generic Driver Options -# -CONFIG_AUXILIARY_BUS=y -CONFIG_UEVENT_HELPER=y -CONFIG_UEVENT_HELPER_PATH="" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_DEVTMPFS_SAFE=y -CONFIG_DRIVER_DEFERRED_PROBE_TIMEOUT=10 -CONFIG_STANDALONE=y -CONFIG_PREVENT_FIRMWARE_BUILD=y - -# -# Firmware loader -# -CONFIG_FW_LOADER=y -CONFIG_FW_LOADER_DEBUG=y -CONFIG_FW_LOADER_PAGED_BUF=y -CONFIG_FW_LOADER_SYSFS=y -CONFIG_EXTRA_FIRMWARE="" -CONFIG_FW_LOADER_USER_HELPER=y -# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set -CONFIG_FW_LOADER_COMPRESS=y -CONFIG_FW_LOADER_COMPRESS_XZ=y -CONFIG_FW_LOADER_COMPRESS_ZSTD=y -CONFIG_FW_CACHE=y -CONFIG_FW_UPLOAD=y -# end of Firmware loader - -CONFIG_WANT_DEV_COREDUMP=y -CONFIG_ALLOW_DEV_COREDUMP=y -CONFIG_DEV_COREDUMP=y -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_DEVRES is not set -# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set -CONFIG_HMEM_REPORTING=y -# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set -CONFIG_SYS_HYPERVISOR=y -CONFIG_GENERIC_CPU_DEVICES=y -CONFIG_GENERIC_CPU_AUTOPROBE=y -CONFIG_GENERIC_CPU_VULNERABILITIES=y -CONFIG_SOC_BUS=y -CONFIG_REGMAP=y -CONFIG_REGMAP_AC97=m -CONFIG_REGMAP_I2C=y -CONFIG_REGMAP_SLIMBUS=m -CONFIG_REGMAP_SPI=y -CONFIG_REGMAP_SPMI=m -CONFIG_REGMAP_W1=m -CONFIG_REGMAP_MMIO=y -CONFIG_REGMAP_IRQ=y -CONFIG_REGMAP_SOUNDWIRE=m -CONFIG_REGMAP_SOUNDWIRE_MBQ=m -CONFIG_REGMAP_SCCB=m -CONFIG_REGMAP_I3C=m -CONFIG_REGMAP_SPI_AVMM=m -CONFIG_DMA_SHARED_BUFFER=y -# CONFIG_DMA_FENCE_TRACE is not set -CONFIG_GENERIC_ARCH_TOPOLOGY=y -CONFIG_GENERIC_ARCH_NUMA=y -# CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT is not set -# end of Generic Driver Options - -# -# Bus devices -# -CONFIG_ARM_CCI=y -CONFIG_ARM_CCI400_COMMON=y -CONFIG_MOXTET=m -CONFIG_HISILICON_LPC=y -CONFIG_IMX_AIPSTZ=m -CONFIG_IMX_WEIM=y -CONFIG_QCOM_EBI2=y -CONFIG_QCOM_SSC_BLOCK_BUS=y -# CONFIG_STM32_DBG_BUS is not set -CONFIG_STM32_FIREWALL=y -CONFIG_SUN50I_DE2_BUS=y -CONFIG_SUNXI_RSB=m -CONFIG_TEGRA_ACONNECT=m -CONFIG_TEGRA_GMI=m -CONFIG_TI_SYSC=y -CONFIG_VEXPRESS_CONFIG=y -CONFIG_FSL_MC_BUS=y -CONFIG_FSL_MC_UAPI_SUPPORT=y -CONFIG_MHI_BUS=m -# CONFIG_MHI_BUS_DEBUG is not set -CONFIG_MHI_BUS_PCI_GENERIC=m -CONFIG_MHI_BUS_EP=m -# end of Bus devices - -CONFIG_CACHEMAINT_FOR_HOTPLUG=y -CONFIG_HISI_SOC_HHA=m -CONFIG_CONNECTOR=y -CONFIG_PROC_EVENTS=y - -# -# Firmware Drivers -# - -# -# ARM System Control and Management Interface Protocol -# -CONFIG_ARM_SCMI_PROTOCOL=y -CONFIG_ARM_SCMI_NEED_DEBUGFS=y -CONFIG_ARM_SCMI_RAW_MODE_SUPPORT=y -CONFIG_ARM_SCMI_RAW_MODE_SUPPORT_COEX=y -# CONFIG_ARM_SCMI_DEBUG_COUNTERS is not set -CONFIG_ARM_SCMI_QUIRKS=y - -# -# SCMI Transport Drivers -# -CONFIG_ARM_SCMI_HAVE_TRANSPORT=y -CONFIG_ARM_SCMI_HAVE_SHMEM=y -CONFIG_ARM_SCMI_HAVE_MSG=y -CONFIG_ARM_SCMI_TRANSPORT_MAILBOX=y -CONFIG_ARM_SCMI_TRANSPORT_SMC=y -CONFIG_ARM_SCMI_TRANSPORT_SMC_ATOMIC_ENABLE=y -CONFIG_ARM_SCMI_TRANSPORT_OPTEE=m -CONFIG_ARM_SCMI_TRANSPORT_VIRTIO=y -CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_VERSION1_COMPLIANCE=y -CONFIG_ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE=y -# end of SCMI Transport Drivers - -# -# ARM SCMI NXP i.MX Vendor Protocols -# -CONFIG_IMX_SCMI_BBM_EXT=y -CONFIG_IMX_SCMI_CPU_EXT=m -CONFIG_IMX_SCMI_LMM_EXT=m -CONFIG_IMX_SCMI_MISC_EXT=m -# end of ARM SCMI NXP i.MX Vendor Protocols - -CONFIG_ARM_SCMI_POWER_CONTROL=m -# end of ARM System Control and Management Interface Protocol - -CONFIG_ARM_SCPI_PROTOCOL=m -CONFIG_ARM_SDE_INTERFACE=y -CONFIG_FIRMWARE_MEMMAP=y -CONFIG_DMIID=y -CONFIG_DMI_SYSFS=m -CONFIG_ISCSI_IBFT=m -CONFIG_FW_CFG_SYSFS=m -# CONFIG_FW_CFG_SYSFS_CMDLINE is not set -CONFIG_INTEL_STRATIX10_SERVICE=m -CONFIG_INTEL_STRATIX10_RSU=m -CONFIG_MTK_ADSP_IPC=m -CONFIG_SYSFB=y -CONFIG_SYSFB_SIMPLEFB=y -CONFIG_TI_SCI_PROTOCOL=y -CONFIG_TURRIS_MOX_RWTM=m -CONFIG_TURRIS_MOX_RWTM_KEYCTL=y -CONFIG_ARM_FFA_TRANSPORT=y -CONFIG_ARM_FFA_SMCCC=y -CONFIG_FW_CS_DSP=m -# CONFIG_GOOGLE_FIRMWARE is not set - -# -# EFI (Extensible Firmware Interface) Support -# -CONFIG_EFI_ESRT=y -CONFIG_EFI_VARS_PSTORE=m -# CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE is not set -CONFIG_EFI_SOFT_RESERVE=y -CONFIG_EFI_PARAMS_FROM_FDT=y -CONFIG_EFI_RUNTIME_WRAPPERS=y -CONFIG_EFI_GENERIC_STUB=y -CONFIG_EFI_ZBOOT=y -# CONFIG_EFI_ARMSTUB_DTB_LOADER is not set -CONFIG_EFI_BOOTLOADER_CONTROL=m -CONFIG_EFI_CAPSULE_LOADER=y -CONFIG_EFI_TEST=m -# CONFIG_RESET_ATTACK_MITIGATION is not set -# CONFIG_EFI_DISABLE_PCI_DMA is not set -CONFIG_EFI_EARLYCON=y -CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y -# CONFIG_EFI_DISABLE_RUNTIME is not set -CONFIG_EFI_COCO_SECRET=y -# CONFIG_OVMF_DEBUG_LOG is not set -CONFIG_EFI_SBAT_FILE="" -# end of EFI (Extensible Firmware Interface) Support - -CONFIG_UEFI_CPER=y -CONFIG_UEFI_CPER_ARM=y -# CONFIG_TEE_STMM_EFI is not set -CONFIG_IMX_DSP=m -CONFIG_IMX_SCU=y -CONFIG_IMX_SCMI_CPU_DRV=m -CONFIG_IMX_SCMI_LMM_DRV=m -CONFIG_IMX_SCMI_MISC_DRV=m -CONFIG_MESON_SM=y -CONFIG_POLARFIRE_SOC_AUTO_UPDATE=m -CONFIG_ARM_PSCI_FW=y -# CONFIG_ARM_PSCI_CHECKER is not set - -# -# Qualcomm firmware drivers -# -CONFIG_QCOM_SCM=y -CONFIG_QCOM_TZMEM=y -# CONFIG_QCOM_TZMEM_MODE_GENERIC is not set -CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE=y -CONFIG_QCOM_QSEECOM=y -CONFIG_QCOM_QSEECOM_UEFISECAPP=y -# end of Qualcomm firmware drivers - -CONFIG_HAVE_ARM_SMCCC=y -CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y -CONFIG_ARM_SMCCC_SOC_ID=y - -# -# Tegra firmware driver -# -CONFIG_TEGRA_IVC=y -CONFIG_TEGRA_BPMP=y -# end of Tegra firmware driver - -# -# Zynq MPSoC Firmware Drivers -# -CONFIG_ZYNQMP_FIRMWARE=y -# CONFIG_ZYNQMP_FIRMWARE_DEBUG is not set -# end of Zynq MPSoC Firmware Drivers -# end of Firmware Drivers - -CONFIG_FWCTL=m -# CONFIG_FWCTL_BNXT is not set -CONFIG_FWCTL_MLX5=m -CONFIG_FWCTL_PDS=m -CONFIG_GNSS=m -CONFIG_GNSS_SERIAL=m -CONFIG_GNSS_MTK_SERIAL=m -CONFIG_GNSS_SIRF_SERIAL=m -CONFIG_GNSS_UBX_SERIAL=m -CONFIG_GNSS_USB=m -CONFIG_MTD=y -# CONFIG_MTD_TESTS is not set - -# -# Partition parsers -# -CONFIG_MTD_CMDLINE_PARTS=m -CONFIG_MTD_OF_PARTS=m -CONFIG_MTD_AFS_PARTS=m -CONFIG_MTD_PARSER_TRX=m -CONFIG_MTD_REDBOOT_PARTS=m -CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 -# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set -# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set -CONFIG_MTD_QCOMSMEM_PARTS=m -# end of Partition parsers - -# -# User Modules And Translation Layers -# -CONFIG_MTD_BLKDEVS=m -CONFIG_MTD_BLOCK=m -CONFIG_MTD_BLOCK_RO=m - -# -# Note that in some cases UBI block is preferred. See MTD_UBI_BLOCK. -# -CONFIG_FTL=m -CONFIG_NFTL=m -CONFIG_NFTL_RW=y -CONFIG_INFTL=m -CONFIG_RFD_FTL=m -CONFIG_SSFDC=m -CONFIG_SM_FTL=m -CONFIG_MTD_OOPS=m -CONFIG_MTD_PSTORE=m -CONFIG_MTD_SWAP=m -# CONFIG_MTD_PARTITIONED_MASTER is not set - -# -# RAM/ROM/Flash chip drivers -# -CONFIG_MTD_CFI=m -CONFIG_MTD_JEDECPROBE=m -CONFIG_MTD_GEN_PROBE=m -# CONFIG_MTD_CFI_ADV_OPTIONS is not set -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y -CONFIG_MTD_CFI_INTELEXT=m -CONFIG_MTD_CFI_AMDSTD=m -CONFIG_MTD_CFI_STAA=m -CONFIG_MTD_CFI_UTIL=m -CONFIG_MTD_RAM=m -CONFIG_MTD_ROM=m -CONFIG_MTD_ABSENT=m -# end of RAM/ROM/Flash chip drivers - -# -# Mapping drivers for chip access -# -CONFIG_MTD_COMPLEX_MAPPINGS=y -CONFIG_MTD_PHYSMAP=m -# CONFIG_MTD_PHYSMAP_COMPAT is not set -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_PHYSMAP_VERSATILE=y -CONFIG_MTD_PHYSMAP_GEMINI=y -CONFIG_MTD_PHYSMAP_GPIO_ADDR=y -CONFIG_MTD_PCI=m -CONFIG_MTD_PLATRAM=m -# end of Mapping drivers for chip access - -# -# Self-contained MTD device drivers -# -CONFIG_MTD_PMC551=m -# CONFIG_MTD_PMC551_BUGFIX is not set -# CONFIG_MTD_PMC551_DEBUG is not set -CONFIG_MTD_DATAFLASH=m -# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set -CONFIG_MTD_DATAFLASH_OTP=y -CONFIG_MTD_MCHP23K256=m -CONFIG_MTD_MCHP48L640=m -CONFIG_MTD_SST25L=m -CONFIG_MTD_SLRAM=m -CONFIG_MTD_PHRAM=m -CONFIG_MTD_MTDRAM=m -CONFIG_MTDRAM_TOTAL_SIZE=4096 -CONFIG_MTDRAM_ERASE_SIZE=128 -CONFIG_MTD_BLOCK2MTD=m -CONFIG_MTD_INTEL_DG=m - -# -# Disk-On-Chip Device Drivers -# -# CONFIG_MTD_DOCG3 is not set -# end of Self-contained MTD device drivers - -# -# NAND -# -CONFIG_MTD_NAND_CORE=y -CONFIG_MTD_ONENAND=m -CONFIG_MTD_ONENAND_VERIFY_WRITE=y -CONFIG_MTD_ONENAND_GENERIC=m -# CONFIG_MTD_ONENAND_OTP is not set -CONFIG_MTD_ONENAND_2X_PROGRAM=y -CONFIG_MTD_RAW_NAND=m - -# -# Raw/parallel NAND flash controllers -# -CONFIG_MTD_NAND_DENALI=m -CONFIG_MTD_NAND_DENALI_PCI=m -CONFIG_MTD_NAND_DENALI_DT=m -CONFIG_MTD_NAND_OMAP2=m -CONFIG_MTD_NAND_OMAP_BCH=y -CONFIG_MTD_NAND_OMAP_BCH_BUILD=m -CONFIG_MTD_NAND_CAFE=m -CONFIG_MTD_NAND_MARVELL=m -CONFIG_MTD_NAND_BRCMNAND=m -CONFIG_MTD_NAND_BRCMNAND_BCM63XX=m -CONFIG_MTD_NAND_BRCMNAND_BCMBCA=m -CONFIG_MTD_NAND_BRCMNAND_BRCMSTB=m -CONFIG_MTD_NAND_BRCMNAND_IPROC=m -CONFIG_MTD_NAND_GPMI_NAND=m -CONFIG_MTD_NAND_FSL_IFC=m -CONFIG_MTD_NAND_MXC=m -# CONFIG_MTD_NAND_SUNXI is not set -CONFIG_MTD_NAND_HISI504=m -CONFIG_MTD_NAND_QCOM=m -CONFIG_MTD_NAND_MTK=m -CONFIG_MTD_NAND_MXIC=m -CONFIG_MTD_NAND_TEGRA=m -CONFIG_MTD_NAND_STM32_FMC2=m -CONFIG_MTD_NAND_MESON=m -CONFIG_MTD_NAND_GPIO=m -CONFIG_MTD_NAND_PLATFORM=m -CONFIG_MTD_NAND_CADENCE=m -CONFIG_MTD_NAND_ARASAN=m -CONFIG_MTD_NAND_INTEL_LGM=m -CONFIG_MTD_NAND_ROCKCHIP=m -CONFIG_MTD_NAND_RENESAS=m -CONFIG_MTD_NAND_NUVOTON_MA35=m - -# -# Misc -# -CONFIG_MTD_SM_COMMON=m -CONFIG_MTD_NAND_NANDSIM=m -CONFIG_MTD_NAND_RICOH=m -CONFIG_MTD_NAND_DISKONCHIP=m -# CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED is not set -CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0 -# CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE is not set -CONFIG_MTD_SPI_NAND=m - -# -# ECC engine support -# -CONFIG_MTD_NAND_ECC=y -CONFIG_MTD_NAND_ECC_SW_HAMMING=y -# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set -CONFIG_MTD_NAND_ECC_SW_BCH=y -CONFIG_MTD_NAND_ECC_MXIC=y -CONFIG_MTD_NAND_ECC_MEDIATEK=m -# end of ECC engine support -# end of NAND - -# -# LPDDR & LPDDR2 PCM memory drivers -# -CONFIG_MTD_LPDDR=m -CONFIG_MTD_QINFO_PROBE=m -# end of LPDDR & LPDDR2 PCM memory drivers - -CONFIG_MTD_SPI_NOR=m -CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y -# CONFIG_MTD_SPI_NOR_SWP_DISABLE is not set -CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE=y -# CONFIG_MTD_SPI_NOR_SWP_KEEP is not set -CONFIG_SPI_HISI_SFC=m -CONFIG_MTD_UBI=m -CONFIG_MTD_UBI_WL_THRESHOLD=4096 -CONFIG_MTD_UBI_BEB_LIMIT=20 -CONFIG_MTD_UBI_FASTMAP=y -CONFIG_MTD_UBI_GLUEBI=m -CONFIG_MTD_UBI_BLOCK=y -CONFIG_MTD_UBI_NVMEM=m -CONFIG_MTD_HYPERBUS=m -CONFIG_HBMC_AM654=m -CONFIG_DTC=y -CONFIG_OF=y -# CONFIG_OF_UNITTEST is not set -CONFIG_OF_FLATTREE=y -CONFIG_OF_EARLY_FLATTREE=y -CONFIG_OF_KOBJ=y -CONFIG_OF_DYNAMIC=y -CONFIG_OF_ADDRESS=y -CONFIG_OF_IRQ=y -CONFIG_OF_RESERVED_MEM=y -CONFIG_OF_RESOLVE=y -CONFIG_OF_OVERLAY=y -CONFIG_OF_NUMA=y -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -CONFIG_PARPORT_SERIAL=m -CONFIG_PARPORT_PC_FIFO=y -CONFIG_PARPORT_1284=y -CONFIG_PARPORT_NOT_PC=y -CONFIG_PNP=y -# CONFIG_PNP_DEBUG_MESSAGES is not set - -# -# Protocols -# -CONFIG_PNPACPI=y -CONFIG_BLK_DEV=y -CONFIG_BLK_DEV_NULL_BLK=m -CONFIG_CDROM=y -CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m -CONFIG_ZRAM=m -CONFIG_ZRAM_BACKEND_LZ4=y -CONFIG_ZRAM_BACKEND_LZ4HC=y -CONFIG_ZRAM_BACKEND_ZSTD=y -CONFIG_ZRAM_BACKEND_DEFLATE=y -CONFIG_ZRAM_BACKEND_842=y -CONFIG_ZRAM_BACKEND_LZO=y -# CONFIG_ZRAM_DEF_COMP_LZORLE is not set -# CONFIG_ZRAM_DEF_COMP_LZO is not set -# CONFIG_ZRAM_DEF_COMP_LZ4 is not set -# CONFIG_ZRAM_DEF_COMP_LZ4HC is not set -CONFIG_ZRAM_DEF_COMP_ZSTD=y -# CONFIG_ZRAM_DEF_COMP_DEFLATE is not set -# CONFIG_ZRAM_DEF_COMP_842 is not set -CONFIG_ZRAM_DEF_COMP="zstd" -CONFIG_ZRAM_WRITEBACK=y -CONFIG_ZRAM_TRACK_ENTRY_ACTIME=y -CONFIG_ZRAM_MEMORY_TRACKING=y -# CONFIG_ZRAM_MULTI_COMP is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 -CONFIG_BLK_DEV_DRBD=m -# CONFIG_DRBD_FAULT_INJECTION is not set -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=m -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=65536 -CONFIG_ATA_OVER_ETH=m -CONFIG_XEN_BLKDEV_FRONTEND=y -CONFIG_XEN_BLKDEV_BACKEND=m -CONFIG_VIRTIO_BLK=y -CONFIG_BLK_DEV_RBD=m -CONFIG_BLK_DEV_UBLK=m -# CONFIG_BLKDEV_UBLK_LEGACY_OPCODES is not set -CONFIG_BLK_DEV_RNBD=y -CONFIG_BLK_DEV_RNBD_CLIENT=m -CONFIG_BLK_DEV_RNBD_SERVER=m -CONFIG_BLK_DEV_ZONED_LOOP=m - -# -# NVME Support -# -CONFIG_NVME_KEYRING=m -CONFIG_NVME_AUTH=m -CONFIG_NVME_CORE=m -CONFIG_BLK_DEV_NVME=m -CONFIG_NVME_MULTIPATH=y -# CONFIG_NVME_VERBOSE_ERRORS is not set -CONFIG_NVME_HWMON=y -CONFIG_NVME_FABRICS=m -CONFIG_NVME_RDMA=m -CONFIG_NVME_FC=m -CONFIG_NVME_TCP=m -CONFIG_NVME_TCP_TLS=y -CONFIG_NVME_HOST_AUTH=y -CONFIG_NVME_APPLE=m -CONFIG_NVME_TARGET=m -# CONFIG_NVME_TARGET_DEBUGFS is not set -CONFIG_NVME_TARGET_PASSTHRU=y -CONFIG_NVME_TARGET_LOOP=m -CONFIG_NVME_TARGET_RDMA=m -CONFIG_NVME_TARGET_FC=m -# CONFIG_NVME_TARGET_FCLOOP is not set -CONFIG_NVME_TARGET_TCP=m -CONFIG_NVME_TARGET_TCP_TLS=y -CONFIG_NVME_TARGET_AUTH=y -# CONFIG_NVME_TARGET_AUTH_DEBUG is not set -CONFIG_NVME_TARGET_PCI_EPF=m -# end of NVME Support - -# -# Misc devices -# -CONFIG_SENSORS_LIS3LV02D=m -CONFIG_AD525X_DPOT=m -CONFIG_AD525X_DPOT_I2C=m -CONFIG_AD525X_DPOT_SPI=m -CONFIG_DUMMY_IRQ=m -CONFIG_PHANTOM=m -CONFIG_RPMB=m -CONFIG_TI_FPC202=m -CONFIG_TIFM_CORE=m -CONFIG_TIFM_7XX1=m -CONFIG_ICS932S401=m -CONFIG_ENCLOSURE_SERVICES=m -CONFIG_SMPRO_ERRMON=m -CONFIG_SMPRO_MISC=m -CONFIG_HI6421V600_IRQ=m -CONFIG_HP_ILO=m -CONFIG_QCOM_COINCELL=m -CONFIG_QCOM_FASTRPC=m -CONFIG_APDS9802ALS=m -CONFIG_ISL29003=m -CONFIG_ISL29020=m -CONFIG_SENSORS_TSL2550=m -CONFIG_SENSORS_BH1770=m -CONFIG_HMC6352=m -CONFIG_DS1682=m -CONFIG_LATTICE_ECP3_CONFIG=m -CONFIG_SRAM=y -CONFIG_DW_XDATA_PCIE=m -# CONFIG_PCI_ENDPOINT_TEST is not set -CONFIG_XILINX_SDFEC=m -CONFIG_MISC_RTSX=m -CONFIG_HISI_HIKEY_USB=m -CONFIG_OPEN_DICE=m -CONFIG_NTSYNC=m -CONFIG_VCPU_STALL_DETECTOR=m -CONFIG_TPS6594_ESM=m -CONFIG_TPS6594_PFSM=m -CONFIG_NSM=m -CONFIG_MARVELL_CN10K_DPI=m -CONFIG_MCHP_LAN966X_PCI=m -CONFIG_C2PORT=m - -# -# EEPROM support -# -CONFIG_EEPROM_AT24=m -CONFIG_EEPROM_AT25=m -CONFIG_EEPROM_MAX6875=m -CONFIG_EEPROM_93CX6=m -CONFIG_EEPROM_93XX46=m -CONFIG_EEPROM_IDT_89HPESX=m -CONFIG_EEPROM_EE1004=m -CONFIG_EEPROM_M24LR=m -# end of EEPROM support - -CONFIG_CB710_CORE=m -# CONFIG_CB710_DEBUG is not set -CONFIG_CB710_DEBUG_ASSUMPTIONS=y -CONFIG_SENSORS_LIS3_I2C=m -CONFIG_ALTERA_STAPL=m -CONFIG_INTEL_MEI=m -CONFIG_INTEL_MEI_ME=m -CONFIG_INTEL_MEI_TXE=m -CONFIG_INTEL_MEI_GSC=m -# CONFIG_INTEL_MEI_CSC is not set -CONFIG_INTEL_MEI_VSC_HW=m -CONFIG_INTEL_MEI_VSC=m -CONFIG_INTEL_MEI_LB=m -CONFIG_INTEL_MEI_HDCP=m -CONFIG_INTEL_MEI_PXP=m -CONFIG_INTEL_MEI_GSC_PROXY=m -CONFIG_VMWARE_VMCI=m -CONFIG_GENWQE=m -CONFIG_GENWQE_PLATFORM_ERROR_RECOVERY=0 -CONFIG_BCM_VK=m -CONFIG_BCM_VK_TTY=y -CONFIG_MISC_ALCOR_PCI=m -CONFIG_MISC_RTSX_PCI=m -CONFIG_MISC_RTSX_USB=m -CONFIG_UACCE=m -CONFIG_PVPANIC=y -CONFIG_PVPANIC_MMIO=m -CONFIG_PVPANIC_PCI=m -CONFIG_GP_PCI1XXXX=m -CONFIG_KEBA_CP500=m -CONFIG_KEBA_LAN9252=m -CONFIG_AMD_SBRMI_I2C=m -CONFIG_AMD_SBRMI_HWMON=y -CONFIG_MISC_RP1=m -# end of Misc devices - -# -# SCSI device support -# -CONFIG_SCSI_MOD=y -CONFIG_RAID_ATTRS=m -CONFIG_SCSI_COMMON=y -CONFIG_SCSI=y -CONFIG_SCSI_DMA=y -CONFIG_SCSI_NETLINK=y -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=m -CONFIG_BLK_DEV_SR=y -CONFIG_CHR_DEV_SG=y -CONFIG_BLK_DEV_BSG=y -CONFIG_CHR_DEV_SCH=m -CONFIG_SCSI_ENCLOSURE=m -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SCAN_ASYNC=y - -# -# SCSI Transports -# -CONFIG_SCSI_SPI_ATTRS=y -CONFIG_SCSI_FC_ATTRS=m -CONFIG_SCSI_ISCSI_ATTRS=m -CONFIG_SCSI_SAS_ATTRS=m -CONFIG_SCSI_SAS_LIBSAS=m -CONFIG_SCSI_SAS_ATA=y -CONFIG_SCSI_SAS_HOST_SMP=y -CONFIG_SCSI_SRP_ATTRS=m -# end of SCSI Transports - -CONFIG_SCSI_LOWLEVEL=y -CONFIG_ISCSI_TCP=m -CONFIG_ISCSI_BOOT_SYSFS=m -CONFIG_SCSI_CXGB3_ISCSI=m -CONFIG_SCSI_CXGB4_ISCSI=m -CONFIG_SCSI_BNX2_ISCSI=m -CONFIG_SCSI_BNX2X_FCOE=m -CONFIG_BE2ISCSI=m -CONFIG_BLK_DEV_3W_XXXX_RAID=m -CONFIG_SCSI_HPSA=m -CONFIG_SCSI_3W_9XXX=m -CONFIG_SCSI_3W_SAS=m -CONFIG_SCSI_ACARD=m -CONFIG_SCSI_AACRAID=m -CONFIG_SCSI_AIC7XXX=m -CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_RESET_DELAY_MS=5000 -# CONFIG_AIC7XXX_DEBUG_ENABLE is not set -CONFIG_AIC7XXX_DEBUG_MASK=0 -CONFIG_AIC7XXX_REG_PRETTY_PRINT=y -CONFIG_SCSI_AIC79XX=m -CONFIG_AIC79XX_CMDS_PER_DEVICE=32 -CONFIG_AIC79XX_RESET_DELAY_MS=5000 -# CONFIG_AIC79XX_DEBUG_ENABLE is not set -CONFIG_AIC79XX_DEBUG_MASK=0 -CONFIG_AIC79XX_REG_PRETTY_PRINT=y -CONFIG_SCSI_AIC94XX=m -# CONFIG_AIC94XX_DEBUG is not set -CONFIG_SCSI_HISI_SAS=m -CONFIG_SCSI_HISI_SAS_PCI=m -# CONFIG_SCSI_HISI_SAS_DEBUGFS_DEFAULT_ENABLE is not set -CONFIG_SCSI_MVSAS=m -# CONFIG_SCSI_MVSAS_DEBUG is not set -# CONFIG_SCSI_MVSAS_TASKLET is not set -CONFIG_SCSI_MVUMI=m -CONFIG_SCSI_ADVANSYS=m -CONFIG_SCSI_ARCMSR=m -CONFIG_SCSI_ESAS2R=m -CONFIG_MEGARAID_NEWGEN=y -CONFIG_MEGARAID_MM=m -CONFIG_MEGARAID_MAILBOX=m -CONFIG_MEGARAID_LEGACY=m -CONFIG_MEGARAID_SAS=m -CONFIG_SCSI_MPT3SAS=m -CONFIG_SCSI_MPT2SAS_MAX_SGE=128 -CONFIG_SCSI_MPT3SAS_MAX_SGE=128 -CONFIG_SCSI_MPT2SAS=m -CONFIG_SCSI_MPI3MR=m -CONFIG_SCSI_SMARTPQI=m -CONFIG_SCSI_HPTIOP=m -CONFIG_SCSI_BUSLOGIC=m -CONFIG_SCSI_FLASHPOINT=y -CONFIG_SCSI_MYRB=m -CONFIG_SCSI_MYRS=m -CONFIG_XEN_SCSI_FRONTEND=m -CONFIG_HYPERV_STORAGE=m -CONFIG_LIBFC=m -CONFIG_LIBFCOE=m -CONFIG_FCOE=m -CONFIG_SCSI_SNIC=m -# CONFIG_SCSI_SNIC_DEBUG_FS is not set -CONFIG_SCSI_DMX3191D=m -CONFIG_SCSI_FDOMAIN=m -CONFIG_SCSI_FDOMAIN_PCI=m -CONFIG_SCSI_IPS=m -CONFIG_SCSI_INITIO=m -CONFIG_SCSI_INIA100=m -CONFIG_SCSI_PPA=m -CONFIG_SCSI_IMM=m -# CONFIG_SCSI_IZIP_SLOW_CTR is not set -CONFIG_SCSI_STEX=m -CONFIG_SCSI_SYM53C8XX_2=y -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -CONFIG_SCSI_SYM53C8XX_MMIO=y -CONFIG_SCSI_IPR=m -CONFIG_SCSI_IPR_TRACE=y -CONFIG_SCSI_IPR_DUMP=y -CONFIG_SCSI_QLOGIC_1280=m -CONFIG_SCSI_QLA_FC=m -CONFIG_TCM_QLA2XXX=m -# CONFIG_TCM_QLA2XXX_DEBUG is not set -CONFIG_SCSI_QLA_ISCSI=m -CONFIG_QEDI=m -CONFIG_QEDF=m -CONFIG_SCSI_LPFC=m -# CONFIG_SCSI_LPFC_DEBUG_FS is not set -CONFIG_SCSI_EFCT=m -CONFIG_SCSI_DC395x=m -CONFIG_SCSI_AM53C974=m -CONFIG_SCSI_WD719X=m -CONFIG_SCSI_DEBUG=m -CONFIG_SCSI_PMCRAID=m -CONFIG_SCSI_PM8001=m -CONFIG_SCSI_BFA_FC=m -CONFIG_SCSI_VIRTIO=y -CONFIG_SCSI_CHELSIO_FCOE=m -CONFIG_SCSI_DH=y -CONFIG_SCSI_DH_RDAC=m -CONFIG_SCSI_DH_HP_SW=m -CONFIG_SCSI_DH_EMC=m -CONFIG_SCSI_DH_ALUA=m -# end of SCSI device support - -CONFIG_ATA=y -CONFIG_SATA_HOST=y -CONFIG_PATA_TIMINGS=y -CONFIG_ATA_VERBOSE_ERROR=y -CONFIG_ATA_FORCE=y -CONFIG_ATA_ACPI=y -CONFIG_SATA_ZPODD=y -CONFIG_SATA_PMP=y - -# -# Controllers with non-SFF native interface -# -CONFIG_SATA_AHCI=m -CONFIG_SATA_MOBILE_LPM_POLICY=3 -CONFIG_SATA_AHCI_PLATFORM=m -CONFIG_AHCI_DWC=m -CONFIG_AHCI_IMX=y -CONFIG_AHCI_CEVA=m -CONFIG_AHCI_MTK=m -CONFIG_AHCI_MVEBU=m -# CONFIG_AHCI_SUNXI is not set -CONFIG_AHCI_TEGRA=m -CONFIG_AHCI_XGENE=m -CONFIG_AHCI_QORIQ=m -CONFIG_SATA_AHCI_SEATTLE=m -CONFIG_SATA_INIC162X=m -CONFIG_SATA_ACARD_AHCI=m -CONFIG_SATA_SIL24=m -CONFIG_ATA_SFF=y - -# -# SFF controllers with custom DMA interface -# -CONFIG_PDC_ADMA=m -CONFIG_SATA_QSTOR=m -CONFIG_SATA_SX4=m -CONFIG_ATA_BMDMA=y - -# -# SATA SFF controllers with BMDMA -# -CONFIG_ATA_PIIX=m -CONFIG_SATA_DWC=m -CONFIG_SATA_DWC_OLD_DMA=y -CONFIG_SATA_MV=m -CONFIG_SATA_NV=m -CONFIG_SATA_PROMISE=m -CONFIG_SATA_RCAR=m -CONFIG_SATA_SIL=m -CONFIG_SATA_SIS=m -CONFIG_SATA_SVW=m -CONFIG_SATA_ULI=m -CONFIG_SATA_VIA=m -CONFIG_SATA_VITESSE=m - -# -# PATA SFF controllers with BMDMA -# -CONFIG_PATA_ALI=m -CONFIG_PATA_AMD=m -CONFIG_PATA_ARTOP=m -CONFIG_PATA_ATIIXP=m -CONFIG_PATA_ATP867X=m -CONFIG_PATA_CMD64X=m -CONFIG_PATA_CYPRESS=m -CONFIG_PATA_EFAR=m -CONFIG_PATA_HPT366=m -CONFIG_PATA_HPT37X=m -CONFIG_PATA_HPT3X2N=m -CONFIG_PATA_HPT3X3=m -# CONFIG_PATA_HPT3X3_DMA is not set -CONFIG_PATA_IMX=m -CONFIG_PATA_IT8213=m -CONFIG_PATA_IT821X=m -CONFIG_PATA_JMICRON=m -CONFIG_PATA_MARVELL=m -CONFIG_PATA_NETCELL=m -CONFIG_PATA_NINJA32=m -CONFIG_PATA_NS87415=m -CONFIG_PATA_OLDPIIX=m -CONFIG_PATA_OPTIDMA=m -CONFIG_PATA_PDC2027X=m -CONFIG_PATA_PDC_OLD=m -CONFIG_PATA_RADISYS=m -CONFIG_PATA_RDC=m -CONFIG_PATA_SCH=m -CONFIG_PATA_SERVERWORKS=m -CONFIG_PATA_SIL680=m -CONFIG_PATA_SIS=m -CONFIG_PATA_TOSHIBA=m -CONFIG_PATA_TRIFLEX=m -CONFIG_PATA_VIA=m -CONFIG_PATA_WINBOND=m - -# -# PIO-only SFF controllers -# -CONFIG_PATA_CMD640_PCI=m -CONFIG_PATA_MPIIX=m -CONFIG_PATA_NS87410=m -CONFIG_PATA_OPTI=m -CONFIG_PATA_PLATFORM=m -CONFIG_PATA_OF_PLATFORM=m -CONFIG_PATA_RZ1000=m -CONFIG_PATA_PARPORT=m - -# -# Parallel IDE protocol modules -# -CONFIG_PATA_PARPORT_ATEN=m -CONFIG_PATA_PARPORT_BPCK=m -CONFIG_PATA_PARPORT_BPCK6=m -# CONFIG_PATA_PARPORT_COMM is not set -CONFIG_PATA_PARPORT_DSTR=m -CONFIG_PATA_PARPORT_FIT2=m -CONFIG_PATA_PARPORT_FIT3=m -CONFIG_PATA_PARPORT_EPAT=m -CONFIG_PATA_PARPORT_EPATC8=y -CONFIG_PATA_PARPORT_EPIA=m -CONFIG_PATA_PARPORT_FRIQ=m -CONFIG_PATA_PARPORT_FRPW=m -CONFIG_PATA_PARPORT_KBIC=m -CONFIG_PATA_PARPORT_KTTI=m -CONFIG_PATA_PARPORT_ON20=m -CONFIG_PATA_PARPORT_ON26=m - -# -# Generic fallback / legacy drivers -# -CONFIG_PATA_ACPI=m -CONFIG_ATA_GENERIC=m -CONFIG_PATA_LEGACY=m -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_BITMAP=y -CONFIG_MD_LLBITMAP=y -CONFIG_MD_AUTODETECT=y -CONFIG_MD_BITMAP_FILE=y -CONFIG_MD_LINEAR=m -CONFIG_MD_RAID0=m -CONFIG_MD_RAID1=m -CONFIG_MD_RAID10=m -CONFIG_MD_RAID456=m -CONFIG_MD_CLUSTER=m -CONFIG_BCACHE=m -# CONFIG_BCACHE_DEBUG is not set -CONFIG_BCACHE_ASYNC_REGISTRATION=y -CONFIG_BLK_DEV_DM_BUILTIN=y -CONFIG_BLK_DEV_DM=y -# CONFIG_DM_DEBUG is not set -CONFIG_DM_BUFIO=m -# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set -CONFIG_DM_BIO_PRISON=m -CONFIG_DM_PERSISTENT_DATA=m -CONFIG_DM_UNSTRIPED=m -CONFIG_DM_CRYPT=m -# CONFIG_DM_INLINECRYPT is not set -CONFIG_DM_SNAPSHOT=m -CONFIG_DM_THIN_PROVISIONING=m -CONFIG_DM_CACHE=m -CONFIG_DM_CACHE_SMQ=m -CONFIG_DM_WRITECACHE=m -CONFIG_DM_EBS=m -CONFIG_DM_ERA=m -CONFIG_DM_CLONE=m -CONFIG_DM_MIRROR=m -CONFIG_DM_LOG_USERSPACE=m -CONFIG_DM_RAID=m -CONFIG_DM_ZERO=m -CONFIG_DM_MULTIPATH=m -CONFIG_DM_MULTIPATH_QL=m -CONFIG_DM_MULTIPATH_ST=m -CONFIG_DM_MULTIPATH_HST=m -CONFIG_DM_MULTIPATH_IOA=m -CONFIG_DM_DELAY=m -# CONFIG_DM_DUST is not set -CONFIG_DM_INIT=y -CONFIG_DM_UEVENT=y -CONFIG_DM_FLAKEY=m -CONFIG_DM_VERITY=m -CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y -CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING=y -CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING=y -# CONFIG_DM_VERITY_FEC is not set -CONFIG_DM_SWITCH=m -CONFIG_DM_LOG_WRITES=m -CONFIG_DM_INTEGRITY=m -CONFIG_DM_ZONED=m -CONFIG_DM_AUDIT=y -CONFIG_DM_VDO=m -CONFIG_DM_PCACHE=m -CONFIG_TARGET_CORE=m -CONFIG_TCM_IBLOCK=m -CONFIG_TCM_FILEIO=m -CONFIG_TCM_PSCSI=m -CONFIG_TCM_USER2=m -CONFIG_LOOPBACK_TARGET=m -CONFIG_TCM_FC=m -CONFIG_ISCSI_TARGET=m -CONFIG_ISCSI_TARGET_CXGB4=m -CONFIG_SBP_TARGET=m -CONFIG_REMOTE_TARGET=m -CONFIG_FUSION=y -CONFIG_FUSION_SPI=m -CONFIG_FUSION_FC=m -CONFIG_FUSION_SAS=m -CONFIG_FUSION_MAX_SGE=128 -CONFIG_FUSION_CTL=m -CONFIG_FUSION_LAN=m -CONFIG_FUSION_LOGGING=y - -# -# IEEE 1394 (FireWire) support -# -CONFIG_FIREWIRE=m -CONFIG_FIREWIRE_OHCI=m -CONFIG_FIREWIRE_SBP2=m -CONFIG_FIREWIRE_NET=m -CONFIG_FIREWIRE_NOSY=m -# end of IEEE 1394 (FireWire) support - -CONFIG_NETDEVICES=y -CONFIG_MII=y -CONFIG_NET_CORE=y -CONFIG_BONDING=m -CONFIG_DUMMY=m -CONFIG_WIREGUARD=m -# CONFIG_WIREGUARD_DEBUG is not set -CONFIG_OVPN=m -CONFIG_EQUALIZER=m -CONFIG_NET_FC=y -CONFIG_IFB=m -CONFIG_NET_TEAM=m -CONFIG_NET_TEAM_MODE_BROADCAST=m -CONFIG_NET_TEAM_MODE_ROUNDROBIN=m -CONFIG_NET_TEAM_MODE_RANDOM=m -CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m -CONFIG_NET_TEAM_MODE_LOADBALANCE=m -CONFIG_MACVLAN=m -CONFIG_MACVTAP=m -CONFIG_IPVLAN_L3S=y -CONFIG_IPVLAN=m -CONFIG_IPVTAP=m -CONFIG_VXLAN=m -CONFIG_GENEVE=m -CONFIG_BAREUDP=m -CONFIG_GTP=m -CONFIG_PFCP=m -CONFIG_AMT=m -CONFIG_MACSEC=m -CONFIG_NETCONSOLE=m -CONFIG_NETCONSOLE_DYNAMIC=y -# CONFIG_NETCONSOLE_EXTENDED_LOG is not set -CONFIG_NETPOLL=y -CONFIG_NET_POLL_CONTROLLER=y -CONFIG_NTB_NETDEV=m -CONFIG_RIONET=m -CONFIG_RIONET_TX_SIZE=128 -CONFIG_RIONET_RX_SIZE=128 -CONFIG_TUN=y -CONFIG_TAP=m -# CONFIG_TUN_VNET_CROSS_LE is not set -CONFIG_VETH=m -CONFIG_VIRTIO_NET=y -CONFIG_NLMON=m -CONFIG_NETKIT=y -CONFIG_NET_VRF=m -CONFIG_VSOCKMON=m -CONFIG_MHI_NET=m -CONFIG_SUNGEM_PHY=m -CONFIG_ARCNET=m -CONFIG_ARCNET_1201=m -CONFIG_ARCNET_1051=m -CONFIG_ARCNET_RAW=m -CONFIG_ARCNET_CAP=m -CONFIG_ARCNET_COM20020=m -CONFIG_ARCNET_COM20020_PCI=m -CONFIG_ATM_DRIVERS=y -CONFIG_ATM_SOLOS=m - -# -# Distributed Switch Architecture drivers -# -CONFIG_B53=m -CONFIG_B53_SPI_DRIVER=m -CONFIG_B53_MDIO_DRIVER=m -CONFIG_B53_MMAP_DRIVER=m -CONFIG_B53_SRAB_DRIVER=m -CONFIG_B53_SERDES=m -CONFIG_NET_DSA_BCM_SF2=m -# CONFIG_NET_DSA_LOOP is not set -CONFIG_NET_DSA_HIRSCHMANN_HELLCREEK=m -CONFIG_NET_DSA_LANTIQ_COMMON=m -CONFIG_NET_DSA_LANTIQ_GSWIP=m -CONFIG_NET_DSA_MXL_GSW1XX=m -CONFIG_NET_DSA_MT7530=m -CONFIG_NET_DSA_MT7530_MDIO=m -CONFIG_NET_DSA_MT7530_MMIO=m -CONFIG_NET_DSA_MV88E6060=m -CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON=m -CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C=m -CONFIG_NET_DSA_MICROCHIP_KSZ_SPI=m -CONFIG_NET_DSA_MICROCHIP_KSZ_PTP=y -CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI=m -CONFIG_NET_DSA_MV88E6XXX=m -CONFIG_NET_DSA_MV88E6XXX_PTP=y -CONFIG_NET_DSA_MV88E6XXX_LEDS=y -CONFIG_NET_DSA_MXL862=m -# CONFIG_NET_DSA_NETC_SWITCH is not set -CONFIG_NET_DSA_MSCC_FELIX_DSA_LIB=m -CONFIG_NET_DSA_MSCC_OCELOT_EXT=m -CONFIG_NET_DSA_MSCC_FELIX=m -CONFIG_NET_DSA_MSCC_SEVILLE=m -CONFIG_NET_DSA_AR9331=m -CONFIG_NET_DSA_QCA8K=m -CONFIG_NET_DSA_QCA8K_LEDS_SUPPORT=y -CONFIG_NET_DSA_SJA1105=m -CONFIG_NET_DSA_SJA1105_PTP=y -CONFIG_NET_DSA_SJA1105_TAS=y -CONFIG_NET_DSA_SJA1105_VL=y -CONFIG_NET_DSA_XRS700X=m -CONFIG_NET_DSA_XRS700X_I2C=m -CONFIG_NET_DSA_XRS700X_MDIO=m -CONFIG_NET_DSA_REALTEK=m -CONFIG_NET_DSA_REALTEK_MDIO=y -CONFIG_NET_DSA_REALTEK_SMI=y -CONFIG_NET_DSA_REALTEK_RTL8365MB=m -CONFIG_NET_DSA_REALTEK_RTL8366RB=m -CONFIG_NET_DSA_REALTEK_RTL8366RB_LEDS=y -CONFIG_NET_DSA_KS8995=m -CONFIG_NET_DSA_SMSC_LAN9303=m -CONFIG_NET_DSA_SMSC_LAN9303_I2C=m -CONFIG_NET_DSA_SMSC_LAN9303_MDIO=m -CONFIG_NET_DSA_VITESSE_VSC73XX=m -CONFIG_NET_DSA_VITESSE_VSC73XX_SPI=m -CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM=m -CONFIG_NET_DSA_YT921X=m -# end of Distributed Switch Architecture drivers - -CONFIG_ETHERNET=y -CONFIG_MDIO=m -CONFIG_NET_VENDOR_3COM=y -CONFIG_VORTEX=m -CONFIG_TYPHOON=m -CONFIG_NET_VENDOR_ACTIONS=y -CONFIG_OWL_EMAC=m -CONFIG_NET_VENDOR_ADAPTEC=y -CONFIG_ADAPTEC_STARFIRE=m -CONFIG_NET_VENDOR_AGERE=y -CONFIG_ET131X=m -CONFIG_NET_VENDOR_AIROHA=y -CONFIG_NET_AIROHA_NPU=m -CONFIG_NET_AIROHA=m -CONFIG_NET_AIROHA_FLOW_STATS=y -CONFIG_NET_VENDOR_ALACRITECH=y -CONFIG_SLICOSS=m -CONFIG_NET_VENDOR_ALIBABA=y -# CONFIG_ALIBABA_EEA is not set -CONFIG_NET_VENDOR_ALLWINNER=y -# CONFIG_SUN4I_EMAC is not set -CONFIG_ALTERA_TSE=m -CONFIG_NET_VENDOR_AMAZON=y -CONFIG_ENA_ETHERNET=m -CONFIG_NET_VENDOR_AMD=y -CONFIG_AMD8111_ETH=m -CONFIG_PCNET32=m -CONFIG_AMD_XGBE=m -CONFIG_AMD_XGBE_DCB=y -CONFIG_PDS_CORE=m -CONFIG_NET_XGENE=m -CONFIG_NET_XGENE_V2=m -CONFIG_NET_VENDOR_AQUANTIA=y -CONFIG_AQTION=m -CONFIG_NET_VENDOR_ARC=y -CONFIG_ARC_EMAC_CORE=m -CONFIG_EMAC_ROCKCHIP=m -CONFIG_NET_VENDOR_ASIX=y -CONFIG_SPI_AX88796C=m -# CONFIG_SPI_AX88796C_COMPRESSION is not set -CONFIG_NET_VENDOR_ATHEROS=y -CONFIG_ATL2=m -CONFIG_ATL1=m -CONFIG_ATL1E=m -CONFIG_ATL1C=m -CONFIG_ALX=m -CONFIG_NET_VENDOR_BROADCOM=y -CONFIG_B44=m -CONFIG_B44_PCI_AUTOSELECT=y -CONFIG_B44_PCICORE_AUTOSELECT=y -CONFIG_B44_PCI=y -CONFIG_BCMGENET=m -CONFIG_BNX2=m -CONFIG_CNIC=m -CONFIG_TIGON3=m -CONFIG_TIGON3_HWMON=y -CONFIG_BNX2X=m -CONFIG_BNX2X_SRIOV=y -CONFIG_SYSTEMPORT=m -CONFIG_BNXT=m -CONFIG_BNXT_SRIOV=y -CONFIG_BNXT_FLOWER_OFFLOAD=y -CONFIG_BNXT_DCB=y -CONFIG_BNXT_HWMON=y -CONFIG_BNGE=m -CONFIG_NET_VENDOR_CADENCE=y -CONFIG_MACB=m -CONFIG_MACB_USE_HWSTAMP=y -CONFIG_MACB_PCI=m -CONFIG_NET_VENDOR_CAVIUM=y -CONFIG_THUNDER_NIC_PF=m -CONFIG_THUNDER_NIC_VF=m -CONFIG_THUNDER_NIC_BGX=m -CONFIG_THUNDER_NIC_RGX=m -CONFIG_CAVIUM_PTP=m -CONFIG_LIQUIDIO_CORE=m -CONFIG_LIQUIDIO=m -CONFIG_LIQUIDIO_VF=m -CONFIG_NET_VENDOR_CHELSIO=y -CONFIG_CHELSIO_T1=m -CONFIG_CHELSIO_T1_1G=y -CONFIG_CHELSIO_T3=m -CONFIG_CHELSIO_T4=m -CONFIG_CHELSIO_T4_DCB=y -CONFIG_CHELSIO_T4_FCOE=y -CONFIG_CHELSIO_T4VF=m -CONFIG_CHELSIO_LIB=m -CONFIG_CHELSIO_INLINE_CRYPTO=y -CONFIG_CHELSIO_IPSEC_INLINE=m -CONFIG_CHELSIO_TLS_DEVICE=m -CONFIG_NET_VENDOR_CISCO=y -CONFIG_ENIC=m -CONFIG_NET_VENDOR_CORTINA=y -CONFIG_GEMINI_ETHERNET=m -CONFIG_NET_VENDOR_DAVICOM=y -CONFIG_DM9051=m -CONFIG_NET_VENDOR_DEC=y -CONFIG_NET_TULIP=y -CONFIG_DE2104X=m -CONFIG_DE2104X_DSL=0 -CONFIG_TULIP=m -# CONFIG_TULIP_MWI is not set -# CONFIG_TULIP_MMIO is not set -# CONFIG_TULIP_NAPI is not set -CONFIG_WINBOND_840=m -CONFIG_DM9102=m -CONFIG_ULI526X=m -CONFIG_PCMCIA_XIRCOM=m -CONFIG_NET_VENDOR_DLINK=y -CONFIG_DL2K=m -CONFIG_SUNDANCE=m -# CONFIG_SUNDANCE_MMIO is not set -CONFIG_NET_VENDOR_EMULEX=y -CONFIG_BE2NET=m -CONFIG_BE2NET_HWMON=y -CONFIG_BE2NET_BE2=y -CONFIG_BE2NET_BE3=y -CONFIG_BE2NET_LANCER=y -CONFIG_BE2NET_SKYHAWK=y -CONFIG_NET_VENDOR_ENGLEDER=y -CONFIG_TSNEP=m -# CONFIG_TSNEP_SELFTESTS is not set -CONFIG_NET_VENDOR_EZCHIP=y -CONFIG_EZCHIP_NPS_MANAGEMENT_ENET=m -CONFIG_NET_VENDOR_FREESCALE=y -CONFIG_FEC=y -CONFIG_FSL_FMAN=y -CONFIG_DPAA_ERRATUM_A050385=y -CONFIG_FSL_PQ_MDIO=m -CONFIG_FSL_XGMAC_MDIO=y -CONFIG_GIANFAR=m -CONFIG_FSL_DPAA_ETH=m -CONFIG_FSL_DPAA2_ETH=m -CONFIG_FSL_DPAA2_ETH_DCB=y -CONFIG_FSL_DPAA2_PTP_CLOCK=m -CONFIG_FSL_DPAA2_SWITCH=m -CONFIG_FSL_ENETC_CORE=m -CONFIG_NXP_ENETC_PF_COMMON=m -CONFIG_NXP_NETC_LIB=m -CONFIG_NXP_NTMP=y -CONFIG_FSL_ENETC=m -CONFIG_NXP_ENETC4=m -CONFIG_FSL_ENETC_VF=m -CONFIG_FSL_ENETC_IERB=m -CONFIG_FSL_ENETC_MDIO=m -CONFIG_FSL_ENETC_PTP_CLOCK=m -CONFIG_FSL_ENETC_QOS=y -CONFIG_NXP_NETC_BLK_CTRL=m -CONFIG_NET_VENDOR_FUNGIBLE=y -CONFIG_FUN_CORE=m -CONFIG_FUN_ETH=m -CONFIG_NET_VENDOR_GOOGLE=y -CONFIG_GVE=m -CONFIG_NET_VENDOR_HISILICON=y -CONFIG_HIX5HD2_GMAC=m -CONFIG_HISI_FEMAC=m -CONFIG_HIP04_ETH=m -CONFIG_HI13X1_GMAC=y -CONFIG_HNS_MDIO=m -CONFIG_HNS=m -CONFIG_HNS_DSAF=m -CONFIG_HNS_ENET=m -CONFIG_HNS3=m -CONFIG_HNS3_HCLGE=m -CONFIG_HNS3_DCB=y -CONFIG_HNS3_HCLGEVF=m -CONFIG_HNS3_ENET=m -CONFIG_HIBMCGE=m -CONFIG_NET_VENDOR_HUAWEI=y -CONFIG_HINIC=m -CONFIG_HINIC3=m -CONFIG_NET_VENDOR_I825XX=y -CONFIG_NET_VENDOR_INTEL=y -CONFIG_LIBETH=m -CONFIG_LIBETH_XDP=m -CONFIG_LIBIE=m -CONFIG_LIBIE_ADMINQ=m -CONFIG_LIBIE_FWLOG=m -CONFIG_E100=m -CONFIG_E1000=m -CONFIG_E1000E=m -CONFIG_IGB=m -CONFIG_IGB_HWMON=y -CONFIG_IGBVF=m -CONFIG_IXGBE=m -CONFIG_IXGBE_HWMON=y -CONFIG_IXGBE_DCB=y -CONFIG_IXGBE_IPSEC=y -CONFIG_IXGBEVF=m -CONFIG_IXGBEVF_IPSEC=y -CONFIG_I40E=m -CONFIG_I40E_DCB=y -CONFIG_IAVF=m -CONFIG_I40EVF=m -CONFIG_ICE=m -CONFIG_ICE_HWMON=y -CONFIG_ICE_SWITCHDEV=y -CONFIG_FM10K=m -CONFIG_IGC=m -CONFIG_IGC_LEDS=y -CONFIG_IDPF=m -# CONFIG_IDPF_SINGLEQ is not set -CONFIG_JME=m -CONFIG_NET_VENDOR_ADI=y -CONFIG_ADIN1110=m -CONFIG_NET_VENDOR_LITEX=y -CONFIG_LITEX_LITEETH=m -CONFIG_NET_VENDOR_MARVELL=y -CONFIG_MVMDIO=m -CONFIG_MVNETA=m -CONFIG_MVPP2=m -CONFIG_MVPP2_PTP=y -CONFIG_PXA168_ETH=m -CONFIG_SKGE=m -# CONFIG_SKGE_DEBUG is not set -CONFIG_SKGE_GENESIS=y -CONFIG_SKY2=m -# CONFIG_SKY2_DEBUG is not set -CONFIG_OCTEONTX2_MBOX=m -CONFIG_OCTEONTX2_AF=m -CONFIG_NDC_DIS_DYNAMIC_CACHING=y -CONFIG_OCTEONTX2_PF=m -CONFIG_OCTEONTX2_VF=m -CONFIG_RVU_ESWITCH=m -CONFIG_OCTEON_EP=m -CONFIG_OCTEON_EP_VF=m -CONFIG_PRESTERA=m -CONFIG_PRESTERA_PCI=m -# CONFIG_NET_VENDOR_MEDIATEK is not set -CONFIG_NET_VENDOR_MELLANOX=y -CONFIG_MLX4_EN=m -CONFIG_MLX4_EN_DCB=y -CONFIG_MLX4_CORE=m -CONFIG_MLX4_DEBUG=y -CONFIG_MLX4_CORE_GEN2=y -CONFIG_MLX5_CORE=m -CONFIG_MLX5_FPGA=y -CONFIG_MLX5_CORE_EN=y -CONFIG_MLX5_EN_ARFS=y -CONFIG_MLX5_EN_RXNFC=y -CONFIG_MLX5_MPFS=y -CONFIG_MLX5_ESWITCH=y -CONFIG_MLX5_BRIDGE=y -CONFIG_MLX5_CLS_ACT=y -CONFIG_MLX5_TC_CT=y -CONFIG_MLX5_TC_SAMPLE=y -CONFIG_MLX5_CORE_EN_DCB=y -CONFIG_MLX5_CORE_IPOIB=y -CONFIG_MLX5_MACSEC=y -CONFIG_MLX5_EN_IPSEC=y -CONFIG_MLX5_EN_TLS=y -CONFIG_MLX5_SW_STEERING=y -CONFIG_MLX5_HW_STEERING=y -CONFIG_MLX5_SF=y -CONFIG_MLX5_SF_MANAGER=y -CONFIG_MLX5_DPLL=m -CONFIG_MLX5_EN_PSP=y -CONFIG_MLXSW_CORE=m -CONFIG_MLXSW_CORE_HWMON=y -CONFIG_MLXSW_CORE_THERMAL=y -CONFIG_MLXSW_PCI=m -CONFIG_MLXSW_I2C=m -CONFIG_MLXSW_SPECTRUM=m -CONFIG_MLXSW_SPECTRUM_DCB=y -CONFIG_MLXSW_MINIMAL=m -CONFIG_MLXFW=m -CONFIG_MLXBF_GIGE=m -CONFIG_NET_VENDOR_META=y -CONFIG_FBNIC=m -CONFIG_NET_VENDOR_MICREL=y -CONFIG_KS8842=m -CONFIG_KS8851=m -CONFIG_KS8851_MLL=m -CONFIG_KSZ884X_PCI=m -CONFIG_NET_VENDOR_MICROCHIP=y -CONFIG_ENC28J60=m -# CONFIG_ENC28J60_WRITEVERIFY is not set -CONFIG_ENCX24J600=m -CONFIG_LAN743X=m -CONFIG_LAN865X=m -CONFIG_LAN966X_SWITCH=m -CONFIG_LAN966X_DCB=y -CONFIG_SPARX5_SWITCH=m -CONFIG_SPARX5_DCB=y -CONFIG_LAN969X_SWITCH=y -CONFIG_VCAP=y -CONFIG_FDMA=y -CONFIG_NET_VENDOR_MICROSEMI=y -CONFIG_MSCC_OCELOT_SWITCH_LIB=m -CONFIG_MSCC_OCELOT_SWITCH=m -CONFIG_NET_VENDOR_MICROSOFT=y -CONFIG_MICROSOFT_MANA=m -CONFIG_NET_VENDOR_MUCSE=y -CONFIG_MGBE=m -CONFIG_NET_VENDOR_MYRI=y -CONFIG_MYRI10GE=m -CONFIG_FEALNX=m -CONFIG_NET_VENDOR_NI=y -CONFIG_NI_XGE_MANAGEMENT_ENET=m -CONFIG_NET_VENDOR_NATSEMI=y -CONFIG_NATSEMI=m -CONFIG_NS83820=m -CONFIG_NET_VENDOR_NETRONOME=y -CONFIG_NFP=m -CONFIG_NFP_APP_FLOWER=y -CONFIG_NFP_APP_ABM_NIC=y -CONFIG_NFP_NET_IPSEC=y -# CONFIG_NFP_DEBUG is not set -CONFIG_NET_VENDOR_8390=y -CONFIG_NE2K_PCI=m -CONFIG_NET_VENDOR_NVIDIA=y -CONFIG_FORCEDETH=m -CONFIG_NET_VENDOR_OKI=y -CONFIG_ETHOC=m -CONFIG_OA_TC6=m -CONFIG_NET_VENDOR_PENSANDO=y -CONFIG_IONIC=m -CONFIG_NET_VENDOR_QLOGIC=y -CONFIG_QLA3XXX=m -CONFIG_QLCNIC=m -CONFIG_QLCNIC_SRIOV=y -CONFIG_QLCNIC_DCB=y -CONFIG_QLCNIC_HWMON=y -CONFIG_NETXEN_NIC=m -CONFIG_QED=m -CONFIG_QED_LL2=y -CONFIG_QED_SRIOV=y -CONFIG_QEDE=m -CONFIG_QED_RDMA=y -CONFIG_QED_ISCSI=y -CONFIG_QED_FCOE=y -CONFIG_QED_OOO=y -CONFIG_NET_VENDOR_BROCADE=y -CONFIG_BNA=m -CONFIG_NET_VENDOR_QUALCOMM=y -CONFIG_QCA7000=m -CONFIG_QCA7000_SPI=m -CONFIG_QCA7000_UART=m -CONFIG_QCOM_EMAC=m -CONFIG_QCOM_PPE=m -CONFIG_RMNET=m -CONFIG_NET_VENDOR_RDC=y -CONFIG_R6040=m -CONFIG_NET_VENDOR_REALTEK=y -CONFIG_8139CP=m -CONFIG_8139TOO=m -CONFIG_8139TOO_PIO=y -# CONFIG_8139TOO_TUNE_TWISTER is not set -CONFIG_8139TOO_8129=y -# CONFIG_8139_OLD_RX_RESET is not set -CONFIG_R8169=m -CONFIG_R8169_LEDS=y -CONFIG_RTASE=m -CONFIG_NET_VENDOR_RENESAS=y -CONFIG_SH_ETH=m -CONFIG_RAVB=m -CONFIG_RENESAS_ETHER_SWITCH=m -CONFIG_RENESAS_GEN4_PTP=m -CONFIG_RTSN=m -CONFIG_NET_VENDOR_ROCKER=y -CONFIG_ROCKER=m -CONFIG_NET_VENDOR_SAMSUNG=y -CONFIG_SXGBE_ETH=m -CONFIG_NET_VENDOR_SEEQ=y -CONFIG_NET_VENDOR_SILAN=y -CONFIG_SC92031=m -CONFIG_NET_VENDOR_SIS=y -CONFIG_SIS900=m -CONFIG_SIS190=m -CONFIG_NET_VENDOR_SOLARFLARE=y -CONFIG_SFC=m -CONFIG_SFC_MTD=y -CONFIG_SFC_MCDI_MON=y -CONFIG_SFC_SRIOV=y -CONFIG_SFC_MCDI_LOGGING=y -CONFIG_SFC_FALCON=m -CONFIG_SFC_FALCON_MTD=y -CONFIG_SFC_SIENA=m -CONFIG_SFC_SIENA_MTD=y -CONFIG_SFC_SIENA_MCDI_MON=y -CONFIG_SFC_SIENA_SRIOV=y -CONFIG_SFC_SIENA_MCDI_LOGGING=y -CONFIG_NET_VENDOR_SMSC=y -CONFIG_SMC91X=y -CONFIG_EPIC100=m -CONFIG_SMSC911X=m -CONFIG_SMSC9420=m -CONFIG_NET_VENDOR_SOCIONEXT=y -CONFIG_SNI_NETSEC=m -CONFIG_NET_VENDOR_STMICRO=y -CONFIG_STMMAC_ETH=m -# CONFIG_STMMAC_SELFTESTS is not set -CONFIG_STMMAC_PLATFORM=m -CONFIG_DWMAC_DWC_QOS_ETH=m -CONFIG_DWMAC_GENERIC=m -CONFIG_DWMAC_IPQ806X=m -CONFIG_DWMAC_MEDIATEK=m -CONFIG_DWMAC_MESON=m -CONFIG_DWMAC_NUVOTON=m -CONFIG_DWMAC_QCOM_ETHQOS=m -CONFIG_DWMAC_RENESAS_GBETH=m -CONFIG_DWMAC_ROCKCHIP=m -CONFIG_DWMAC_S32=m -CONFIG_DWMAC_SOCFPGA=m -CONFIG_DWMAC_SOPHGO=m -CONFIG_DWMAC_STM32=m -# CONFIG_DWMAC_SUNXI is not set -CONFIG_DWMAC_SUN8I=m -CONFIG_DWMAC_SUN55I=m -CONFIG_DWMAC_IMX8=m -CONFIG_DWMAC_INTEL_PLAT=m -CONFIG_DWMAC_TEGRA=m -CONFIG_DWMAC_VISCONTI=m -CONFIG_STMMAC_LIBPCI=m -CONFIG_DWMAC_MOTORCOMM=m -CONFIG_STMMAC_PCI=m -CONFIG_NET_VENDOR_SUN=y -CONFIG_HAPPYMEAL=m -CONFIG_SUNGEM=m -CONFIG_CASSINI=m -CONFIG_NIU=m -CONFIG_NET_VENDOR_SYNOPSYS=y -CONFIG_DWC_XLGMAC=m -CONFIG_DWC_XLGMAC_PCI=m -CONFIG_NET_VENDOR_TEHUTI=y -CONFIG_TEHUTI=m -CONFIG_TEHUTI_TN40=m -CONFIG_NET_VENDOR_TI=y -CONFIG_TI_DAVINCI_MDIO=y -# CONFIG_TI_CPSW_PHY_SEL is not set -CONFIG_TI_K3_CPPI_DESC_POOL=m -CONFIG_TI_K3_AM65_CPSW_NUSS=m -CONFIG_TI_K3_AM65_CPSW_SWITCHDEV=y -CONFIG_TI_K3_AM65_CPTS=m -CONFIG_TI_AM65_CPSW_QOS=y -CONFIG_TLAN=m -CONFIG_TI_ICSSG_PRUETH=m -CONFIG_TI_ICSSG_PRUETH_SR1=m -CONFIG_TI_ICSS_IEP=m -CONFIG_TI_PRUETH=m -CONFIG_NET_VENDOR_VERTEXCOM=y -CONFIG_MSE102X=m -CONFIG_NET_VENDOR_VIA=y -CONFIG_VIA_RHINE=m -CONFIG_VIA_RHINE_MMIO=y -CONFIG_VIA_VELOCITY=m -CONFIG_NET_VENDOR_WANGXUN=y -CONFIG_LIBWX=m -CONFIG_NGBE=m -CONFIG_TXGBE=m -CONFIG_TXGBEVF=m -CONFIG_NGBEVF=m -CONFIG_NET_VENDOR_WIZNET=y -CONFIG_WIZNET_W5100=m -CONFIG_NET_VENDOR_XILINX=y -CONFIG_XILINX_EMACLITE=m -CONFIG_XILINX_AXI_EMAC=m -CONFIG_XILINX_LL_TEMAC=m -CONFIG_FDDI=y -CONFIG_DEFXX=m -CONFIG_SKFP=m -CONFIG_QCOM_IPA=m -CONFIG_PHYLINK=y -CONFIG_PHYLIB=y -CONFIG_SWPHY=y -CONFIG_PHY_PACKAGE=m -CONFIG_LED_TRIGGER_PHY=y -CONFIG_OPEN_ALLIANCE_HELPERS=y -CONFIG_PHYLIB_LEDS=y -CONFIG_FIXED_PHY=y -CONFIG_SFP=m - -# -# MII PHY device drivers -# -CONFIG_AS21XXX_PHY=m -# CONFIG_AIR_AN8801_PHY is not set -CONFIG_AIR_EN8811H_PHY=m -CONFIG_AIR_NET_PHYLIB=m -CONFIG_AMD_PHY=m -CONFIG_MESON_GXL_PHY=m -CONFIG_ADIN_PHY=m -CONFIG_ADIN1100_PHY=m -CONFIG_AQUANTIA_PHY=m -CONFIG_AX88796B_PHY=m -CONFIG_BROADCOM_PHY=m -CONFIG_BCM54140_PHY=m -CONFIG_BCM7XXX_PHY=m -CONFIG_BCM84881_PHY=y -CONFIG_BCM87XX_PHY=m -CONFIG_BCM_NET_PHYLIB=m -CONFIG_BCM_NET_PHYPTP=m -CONFIG_CICADA_PHY=m -CONFIG_CORTINA_PHY=m -CONFIG_DAVICOM_PHY=m -CONFIG_ICPLUS_PHY=m -CONFIG_LXT_PHY=m -CONFIG_INTEL_XWAY_PHY=m -CONFIG_LSI_ET1011C_PHY=m -CONFIG_MARVELL_PHY=m -CONFIG_MARVELL_10G_PHY=m -CONFIG_MARVELL_88Q2XXX_PHY=m -CONFIG_MARVELL_88X2222_PHY=m -CONFIG_MAXLINEAR_GPHY=m -CONFIG_MAXLINEAR_86110_PHY=m -CONFIG_MEDIATEK_2P5GE_PHY=m -CONFIG_MEDIATEK_GE_PHY=m -CONFIG_MEDIATEK_GE_SOC_PHY=m -CONFIG_MTK_NET_PHYLIB=m -CONFIG_MICREL_PHY=m -CONFIG_MICROCHIP_T1S_PHY=m -CONFIG_MICROCHIP_PHY=m -CONFIG_MICROCHIP_T1_PHY=m -CONFIG_MICROCHIP_PHY_RDS_PTP=m -CONFIG_MICROSEMI_PHY=m -CONFIG_MOTORCOMM_PHY=m -CONFIG_NATIONAL_PHY=m -CONFIG_NXP_CBTX_PHY=m -CONFIG_NXP_C45_TJA11XX_PHY=m -CONFIG_NXP_TJA11XX_PHY=m -CONFIG_NCN26000_PHY=m -CONFIG_QCOM_NET_PHYLIB=m -CONFIG_AT803X_PHY=m -CONFIG_QCA83XX_PHY=m -CONFIG_QCA808X_PHY=m -CONFIG_QCA807X_PHY=m -CONFIG_QSEMI_PHY=m -CONFIG_REALTEK_PHY=m -CONFIG_REALTEK_PHY_HWMON=y -CONFIG_RENESAS_PHY=m -CONFIG_ROCKCHIP_PHY=m -CONFIG_SMSC_PHY=m -CONFIG_STE10XP=m -CONFIG_TERANETICS_PHY=m -CONFIG_DP83822_PHY=m -CONFIG_DP83TC811_PHY=m -CONFIG_DP83848_PHY=m -CONFIG_DP83867_PHY=m -CONFIG_DP83869_PHY=m -CONFIG_DP83TD510_PHY=m -CONFIG_DP83TG720_PHY=m -CONFIG_VITESSE_PHY=m -CONFIG_XILINX_GMII2RGMII=m -CONFIG_PSE_CONTROLLER=y -CONFIG_PSE_REGULATOR=m -CONFIG_PSE_PD692X0=m -CONFIG_PSE_SI3474=m -CONFIG_PSE_TPS23881=m -CONFIG_CAN_DEV=m -CONFIG_CAN_VCAN=m -CONFIG_CAN_VXCAN=m -CONFIG_CAN_NETLINK=y -CONFIG_CAN_CALC_BITTIMING=y -CONFIG_CAN_RX_OFFLOAD=y -CONFIG_CAN_BXCAN=m -CONFIG_CAN_CAN327=m -CONFIG_CAN_DUMMY=m -CONFIG_CAN_FLEXCAN=m -CONFIG_CAN_GRCAN=m -CONFIG_CAN_JANZ_ICAN3=m -CONFIG_CAN_KVASER_PCIEFD=m -CONFIG_CAN_SLCAN=m -# CONFIG_CAN_VIRTIO_CAN is not set -CONFIG_CAN_XILINXCAN=m -CONFIG_CAN_C_CAN=m -CONFIG_CAN_C_CAN_PLATFORM=m -CONFIG_CAN_C_CAN_PCI=m -CONFIG_CAN_CC770=m -CONFIG_CAN_CC770_ISA=m -CONFIG_CAN_CC770_PLATFORM=m -CONFIG_CAN_CTUCANFD=m -CONFIG_CAN_CTUCANFD_PCI=m -CONFIG_CAN_CTUCANFD_PLATFORM=m -CONFIG_CAN_ESD_402_PCI=m -CONFIG_CAN_IFI_CANFD=m -CONFIG_CAN_M_CAN=m -CONFIG_CAN_M_CAN_PCI=m -CONFIG_CAN_M_CAN_PLATFORM=m -CONFIG_CAN_M_CAN_TCAN4X5X=m -CONFIG_CAN_PEAK_PCIEFD=m -CONFIG_CAN_RCAR=m -CONFIG_CAN_RCAR_CANFD=m -# CONFIG_CAN_ROCKCHIP_CANFD is not set -CONFIG_CAN_SJA1000=m -CONFIG_CAN_EMS_PCI=m -CONFIG_CAN_F81601=m -CONFIG_CAN_KVASER_PCI=m -CONFIG_CAN_PEAK_PCI=m -CONFIG_CAN_PEAK_PCIEC=y -CONFIG_CAN_PLX_PCI=m -CONFIG_CAN_SJA1000_ISA=m -CONFIG_CAN_SJA1000_PLATFORM=m -CONFIG_CAN_SOFTING=m - -# -# CAN SPI interfaces -# -CONFIG_CAN_HI311X=m -CONFIG_CAN_MCP251X=m -CONFIG_CAN_MCP251XFD=m -# CONFIG_CAN_MCP251XFD_SANITY is not set -# end of CAN SPI interfaces - -# -# CAN USB interfaces -# -CONFIG_CAN_8DEV_USB=m -CONFIG_CAN_EMS_USB=m -CONFIG_CAN_ESD_USB=m -CONFIG_CAN_ETAS_ES58X=m -CONFIG_CAN_F81604=m -CONFIG_CAN_GS_USB=m -CONFIG_CAN_KVASER_USB=m -CONFIG_CAN_MCBA_USB=m -CONFIG_CAN_NCT6694=m -CONFIG_CAN_PEAK_USB=m -CONFIG_CAN_UCAN=m -# end of CAN USB interfaces - -# CONFIG_CAN_DEBUG_DEVICES is not set - -# -# MCTP Device Drivers -# -CONFIG_MCTP_SERIAL=m -CONFIG_MCTP_TRANSPORT_I2C=m -CONFIG_MCTP_TRANSPORT_I3C=m -CONFIG_MCTP_TRANSPORT_USB=m -# end of MCTP Device Drivers - -CONFIG_FWNODE_MDIO=y -CONFIG_OF_MDIO=y -CONFIG_ACPI_MDIO=y -CONFIG_MDIO_AIROHA=m -# CONFIG_MDIO_SUN4I is not set -CONFIG_MDIO_XGENE=m -CONFIG_MDIO_BITBANG=y -CONFIG_MDIO_BCM_UNIMAC=m -CONFIG_MDIO_CAVIUM=m -CONFIG_MDIO_GPIO=m -CONFIG_MDIO_HISI_FEMAC=m -CONFIG_MDIO_I2C=m -CONFIG_MDIO_MVUSB=m -CONFIG_MDIO_MSCC_MIIM=m -CONFIG_MDIO_OCTEON=m -# CONFIG_MDIO_PIC64HPSC is not set -CONFIG_MDIO_IPQ4019=m -CONFIG_MDIO_IPQ8064=m -CONFIG_MDIO_REGMAP=m -CONFIG_MDIO_THUNDER=m - -# -# MDIO Multiplexers -# -CONFIG_MDIO_BUS_MUX=m -CONFIG_MDIO_BUS_MUX_MESON_G12A=m -CONFIG_MDIO_BUS_MUX_MESON_GXL=m -CONFIG_MDIO_BUS_MUX_GPIO=m -CONFIG_MDIO_BUS_MUX_MULTIPLEXER=m -CONFIG_MDIO_BUS_MUX_MMIOREG=m - -# -# PCS device drivers -# -CONFIG_PCS_XPCS=m -CONFIG_PCS_LYNX=y -CONFIG_PCS_MTK_LYNXI=m -CONFIG_PCS_RZN1_MIIC=m -# end of PCS device drivers - -CONFIG_PLIP=m -CONFIG_PPP=y -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_MPPE=m -CONFIG_PPP_MULTILINK=y -CONFIG_PPPOATM=m -CONFIG_PPPOX=m -CONFIG_PPPOE=m -# CONFIG_PPPOE_HASH_BITS_1 is not set -# CONFIG_PPPOE_HASH_BITS_2 is not set -CONFIG_PPPOE_HASH_BITS_4=y -# CONFIG_PPPOE_HASH_BITS_8 is not set -CONFIG_PPPOE_HASH_BITS=4 -CONFIG_PPTP=m -CONFIG_PPPOL2TP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_SLIP=m -CONFIG_SLHC=y -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -CONFIG_SLIP_MODE_SLIP6=y -CONFIG_USB_NET_DRIVERS=m -CONFIG_USB_CATC=m -CONFIG_USB_KAWETH=m -CONFIG_USB_PEGASUS=m -CONFIG_USB_RTL8150=m -CONFIG_USB_RTL8152=m -CONFIG_USB_LAN78XX=m -CONFIG_USB_USBNET=m -CONFIG_USB_NET_AX8817X=m -CONFIG_USB_NET_AX88179_178A=m -CONFIG_USB_NET_CDCETHER=m -CONFIG_USB_NET_CDC_EEM=m -CONFIG_USB_NET_CDC_NCM=m -CONFIG_USB_NET_HUAWEI_CDC_NCM=m -CONFIG_USB_NET_CDC_MBIM=m -CONFIG_USB_NET_DM9601=m -CONFIG_USB_NET_SR9700=m -CONFIG_USB_NET_SR9800=m -CONFIG_USB_NET_SMSC75XX=m -CONFIG_USB_NET_SMSC95XX=m -CONFIG_USB_NET_GL620A=m -CONFIG_USB_NET_NET1080=m -CONFIG_USB_NET_PLUSB=m -CONFIG_USB_NET_MCS7830=m -CONFIG_USB_NET_RNDIS_HOST=m -CONFIG_USB_NET_CDC_SUBSET_ENABLE=m -CONFIG_USB_NET_CDC_SUBSET=m -CONFIG_USB_ALI_M5632=y -CONFIG_USB_AN2720=y -CONFIG_USB_BELKIN=y -CONFIG_USB_ARMLINUX=y -CONFIG_USB_EPSON2888=y -CONFIG_USB_KC2190=y -CONFIG_USB_NET_ZAURUS=m -CONFIG_USB_NET_CX82310_ETH=m -CONFIG_USB_NET_KALMIA=m -CONFIG_USB_NET_QMI_WWAN=m -CONFIG_USB_HSO=m -CONFIG_USB_NET_INT51X1=m -CONFIG_USB_CDC_PHONET=m -CONFIG_USB_IPHETH=m -CONFIG_USB_SIERRA_NET=m -CONFIG_USB_VL600=m -CONFIG_USB_NET_CH9200=m -CONFIG_USB_NET_AQC111=m -CONFIG_USB_RTL8153_ECM=m -CONFIG_WLAN=y -CONFIG_WLAN_VENDOR_ADMTEK=y -CONFIG_ADM8211=m -CONFIG_ATH_COMMON=m -CONFIG_WLAN_VENDOR_ATH=y -# CONFIG_ATH_DEBUG is not set -CONFIG_ATH5K=m -# CONFIG_ATH5K_DEBUG is not set -# CONFIG_ATH5K_TRACER is not set -CONFIG_ATH5K_PCI=y -CONFIG_ATH9K_HW=m -CONFIG_ATH9K_COMMON=m -CONFIG_ATH9K_COMMON_DEBUG=y -CONFIG_ATH9K_BTCOEX_SUPPORT=y -CONFIG_ATH9K=m -CONFIG_ATH9K_PCI=y -CONFIG_ATH9K_AHB=y -CONFIG_ATH9K_DEBUGFS=y -CONFIG_ATH9K_STATION_STATISTICS=y -# CONFIG_ATH9K_DYNACK is not set -CONFIG_ATH9K_WOW=y -CONFIG_ATH9K_RFKILL=y -CONFIG_ATH9K_CHANNEL_CONTEXT=y -CONFIG_ATH9K_PCOEM=y -CONFIG_ATH9K_PCI_NO_EEPROM=m -CONFIG_ATH9K_HTC=m -CONFIG_ATH9K_HTC_DEBUGFS=y -CONFIG_ATH9K_HWRNG=y -CONFIG_ATH9K_COMMON_SPECTRAL=y -CONFIG_CARL9170=m -CONFIG_CARL9170_LEDS=y -# CONFIG_CARL9170_DEBUGFS is not set -CONFIG_CARL9170_WPC=y -CONFIG_CARL9170_HWRNG=y -CONFIG_ATH6KL=m -CONFIG_ATH6KL_SDIO=m -CONFIG_ATH6KL_USB=m -# CONFIG_ATH6KL_DEBUG is not set -# CONFIG_ATH6KL_TRACING is not set -CONFIG_AR5523=m -CONFIG_WIL6210=m -CONFIG_WIL6210_ISR_COR=y -CONFIG_WIL6210_TRACING=y -CONFIG_WIL6210_DEBUGFS=y -CONFIG_ATH10K=m -CONFIG_ATH10K_CE=y -CONFIG_ATH10K_PCI=m -CONFIG_ATH10K_AHB=y -CONFIG_ATH10K_SDIO=m -CONFIG_ATH10K_USB=m -CONFIG_ATH10K_SNOC=m -# CONFIG_ATH10K_DEBUG is not set -CONFIG_ATH10K_DEBUGFS=y -CONFIG_ATH10K_LEDS=y -CONFIG_ATH10K_SPECTRAL=y -CONFIG_ATH10K_TRACING=y -CONFIG_WCN36XX=m -# CONFIG_WCN36XX_DEBUGFS is not set -CONFIG_ATH11K=m -CONFIG_ATH11K_AHB=m -CONFIG_ATH11K_PCI=m -# CONFIG_ATH11K_DEBUG is not set -CONFIG_ATH11K_DEBUGFS=y -CONFIG_ATH11K_TRACING=y -CONFIG_ATH11K_SPECTRAL=y -# CONFIG_ATH11K_CFR is not set -CONFIG_ATH12K=m -CONFIG_ATH12K_AHB=y -# CONFIG_ATH12K_DEBUG is not set -CONFIG_ATH12K_DEBUGFS=y -CONFIG_ATH12K_TRACING=y -# CONFIG_ATH12K_COREDUMP is not set -CONFIG_WLAN_VENDOR_ATMEL=y -CONFIG_AT76C50X_USB=m -CONFIG_WLAN_VENDOR_BROADCOM=y -CONFIG_B43=m -CONFIG_B43_BCMA=y -CONFIG_B43_SSB=y -CONFIG_B43_BUSES_BCMA_AND_SSB=y -# CONFIG_B43_BUSES_BCMA is not set -# CONFIG_B43_BUSES_SSB is not set -CONFIG_B43_PCI_AUTOSELECT=y -CONFIG_B43_PCICORE_AUTOSELECT=y -# CONFIG_B43_SDIO is not set -CONFIG_B43_BCMA_PIO=y -CONFIG_B43_PIO=y -CONFIG_B43_PHY_G=y -CONFIG_B43_PHY_N=y -CONFIG_B43_PHY_LP=y -CONFIG_B43_PHY_HT=y -CONFIG_B43_LEDS=y -CONFIG_B43_HWRNG=y -# CONFIG_B43_DEBUG is not set -CONFIG_B43LEGACY=m -CONFIG_B43LEGACY_PCI_AUTOSELECT=y -CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y -CONFIG_B43LEGACY_LEDS=y -CONFIG_B43LEGACY_HWRNG=y -# CONFIG_B43LEGACY_DEBUG is not set -CONFIG_B43LEGACY_DMA=y -CONFIG_B43LEGACY_PIO=y -CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y -# CONFIG_B43LEGACY_DMA_MODE is not set -# CONFIG_B43LEGACY_PIO_MODE is not set -CONFIG_BRCMUTIL=m -CONFIG_BRCMSMAC=m -CONFIG_BRCMSMAC_LEDS=y -CONFIG_BRCMFMAC=m -CONFIG_BRCMFMAC_PROTO_BCDC=y -CONFIG_BRCMFMAC_PROTO_MSGBUF=y -CONFIG_BRCMFMAC_SDIO=y -CONFIG_BRCMFMAC_USB=y -CONFIG_BRCMFMAC_PCIE=y -CONFIG_BRCM_TRACING=y -# CONFIG_BRCMDBG is not set -CONFIG_WLAN_VENDOR_INTEL=y -CONFIG_IPW2100=m -CONFIG_IPW2100_MONITOR=y -# CONFIG_IPW2100_DEBUG is not set -CONFIG_IPW2200=m -CONFIG_IPW2200_MONITOR=y -CONFIG_IPW2200_RADIOTAP=y -CONFIG_IPW2200_PROMISCUOUS=y -CONFIG_IPW2200_QOS=y -# CONFIG_IPW2200_DEBUG is not set -CONFIG_LIBIPW=m -# CONFIG_LIBIPW_DEBUG is not set -CONFIG_IWLEGACY=m -CONFIG_IWL4965=m -CONFIG_IWL3945=m - -# -# iwl3945 / iwl4965 Debugging Options -# -# CONFIG_IWLEGACY_DEBUG is not set -CONFIG_IWLEGACY_DEBUGFS=y -# end of iwl3945 / iwl4965 Debugging Options - -CONFIG_IWLWIFI=m -CONFIG_IWLWIFI_LEDS=y -CONFIG_IWLDVM=m -CONFIG_IWLMVM=m -CONFIG_IWLMLD=m -CONFIG_IWLWIFI_OPMODE_MODULAR=y - -# -# Debugging Options -# -# CONFIG_IWLWIFI_DEBUG is not set -CONFIG_IWLWIFI_DEBUGFS=y -CONFIG_IWLWIFI_DEVICE_TRACING=y -# end of Debugging Options - -CONFIG_WLAN_VENDOR_INTERSIL=y -CONFIG_P54_COMMON=m -CONFIG_P54_USB=m -CONFIG_P54_PCI=m -CONFIG_P54_SPI=m -# CONFIG_P54_SPI_DEFAULT_EEPROM is not set -CONFIG_P54_LEDS=y -CONFIG_WLAN_VENDOR_MARVELL=y -CONFIG_LIBERTAS=m -CONFIG_LIBERTAS_USB=m -CONFIG_LIBERTAS_SDIO=m -CONFIG_LIBERTAS_SPI=m -# CONFIG_LIBERTAS_DEBUG is not set -CONFIG_LIBERTAS_MESH=y -CONFIG_LIBERTAS_THINFIRM=m -# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set -CONFIG_LIBERTAS_THINFIRM_USB=m -CONFIG_MWIFIEX=m -CONFIG_MWIFIEX_SDIO=m -CONFIG_MWIFIEX_PCIE=m -CONFIG_MWIFIEX_USB=m -CONFIG_MWL8K=m -CONFIG_WLAN_VENDOR_MEDIATEK=y -CONFIG_MT7601U=m -CONFIG_MT76_CORE=m -CONFIG_MT76_LEDS=y -CONFIG_MT76_USB=m -CONFIG_MT76_SDIO=m -CONFIG_MT76x02_LIB=m -CONFIG_MT76x02_USB=m -CONFIG_MT76_CONNAC_LIB=m -CONFIG_MT792x_LIB=m -CONFIG_MT792x_USB=m -CONFIG_MT76_NPU=m -CONFIG_MT76x0_COMMON=m -CONFIG_MT76x0U=m -CONFIG_MT76x0E=m -CONFIG_MT76x2_COMMON=m -CONFIG_MT76x2E=m -CONFIG_MT76x2U=m -CONFIG_MT7603E=m -CONFIG_MT7615_COMMON=m -CONFIG_MT7615E=m -CONFIG_MT7622_WMAC=y -CONFIG_MT7663_USB_SDIO_COMMON=m -CONFIG_MT7663U=m -CONFIG_MT7663S=m -CONFIG_MT7915E=m -CONFIG_MT798X_WMAC=y -CONFIG_MT7921_COMMON=m -CONFIG_MT7921E=m -CONFIG_MT7921S=m -CONFIG_MT7921U=m -CONFIG_MT7996E=m -CONFIG_MT7996_NPU=y -CONFIG_MT7925_COMMON=m -CONFIG_MT7925E=m -CONFIG_MT7925U=m -CONFIG_WLAN_VENDOR_MICROCHIP=y -CONFIG_WILC1000=m -CONFIG_WILC1000_SDIO=m -CONFIG_WILC1000_SPI=m -CONFIG_WILC1000_HW_OOB_INTR=y -CONFIG_WLAN_VENDOR_PURELIFI=y -CONFIG_PLFXLC=m -CONFIG_WLAN_VENDOR_RALINK=y -CONFIG_RT2X00=m -CONFIG_RT2400PCI=m -CONFIG_RT2500PCI=m -CONFIG_RT61PCI=m -CONFIG_RT2800PCI=m -CONFIG_RT2800PCI_RT33XX=y -CONFIG_RT2800PCI_RT35XX=y -CONFIG_RT2800PCI_RT53XX=y -CONFIG_RT2800PCI_RT3290=y -CONFIG_RT2500USB=m -CONFIG_RT73USB=m -CONFIG_RT2800USB=m -CONFIG_RT2800USB_RT33XX=y -CONFIG_RT2800USB_RT35XX=y -CONFIG_RT2800USB_RT3573=y -CONFIG_RT2800USB_RT53XX=y -CONFIG_RT2800USB_RT55XX=y -CONFIG_RT2800USB_UNKNOWN=y -CONFIG_RT2800_LIB=m -CONFIG_RT2800_LIB_MMIO=m -CONFIG_RT2X00_LIB_MMIO=m -CONFIG_RT2X00_LIB_PCI=m -CONFIG_RT2X00_LIB_USB=m -CONFIG_RT2X00_LIB=m -CONFIG_RT2X00_LIB_FIRMWARE=y -CONFIG_RT2X00_LIB_CRYPTO=y -CONFIG_RT2X00_LIB_LEDS=y -# CONFIG_RT2X00_LIB_DEBUGFS is not set -# CONFIG_RT2X00_DEBUG is not set -CONFIG_WLAN_VENDOR_REALTEK=y -CONFIG_RTL8180=m -CONFIG_RTL8187=m -CONFIG_RTL8187_LEDS=y -CONFIG_RTL_CARDS=m -CONFIG_RTL8192CE=m -CONFIG_RTL8192SE=m -CONFIG_RTL8192DE=m -CONFIG_RTL8723AE=m -CONFIG_RTL8723BE=m -CONFIG_RTL8188EE=m -CONFIG_RTL8192EE=m -CONFIG_RTL8821AE=m -CONFIG_RTL8192CU=m -CONFIG_RTL8192DU=m -CONFIG_RTLWIFI=m -CONFIG_RTLWIFI_PCI=m -CONFIG_RTLWIFI_USB=m -# CONFIG_RTLWIFI_DEBUG is not set -CONFIG_RTL8192C_COMMON=m -CONFIG_RTL8192D_COMMON=m -CONFIG_RTL8723_COMMON=m -CONFIG_RTLBTCOEXIST=m -CONFIG_RTL8XXXU=m -CONFIG_RTL8XXXU_UNTESTED=y -CONFIG_RTW88=m -CONFIG_RTW88_CORE=m -CONFIG_RTW88_PCI=m -CONFIG_RTW88_SDIO=m -CONFIG_RTW88_USB=m -CONFIG_RTW88_8822B=m -CONFIG_RTW88_8822C=m -CONFIG_RTW88_8723X=m -CONFIG_RTW88_8703B=m -CONFIG_RTW88_8723D=m -CONFIG_RTW88_8821C=m -CONFIG_RTW88_88XXA=m -CONFIG_RTW88_8821A=m -CONFIG_RTW88_8812A=m -CONFIG_RTW88_8814A=m -CONFIG_RTW88_8822BE=m -CONFIG_RTW88_8822BS=m -CONFIG_RTW88_8822BU=m -CONFIG_RTW88_8822CE=m -CONFIG_RTW88_8822CS=m -CONFIG_RTW88_8822CU=m -CONFIG_RTW88_8723DE=m -CONFIG_RTW88_8723DS=m -CONFIG_RTW88_8723CS=m -CONFIG_RTW88_8723DU=m -CONFIG_RTW88_8821CE=m -CONFIG_RTW88_8821CS=m -CONFIG_RTW88_8821CU=m -CONFIG_RTW88_8821AU=m -CONFIG_RTW88_8812AU=m -CONFIG_RTW88_8814AE=m -CONFIG_RTW88_8814AU=m -CONFIG_RTW88_DEBUG=y -CONFIG_RTW88_DEBUGFS=y -CONFIG_RTW88_LEDS=y -CONFIG_RTW89=m -CONFIG_RTW89_CORE=m -CONFIG_RTW89_PCI=m -CONFIG_RTW89_USB=m -CONFIG_RTW89_8851B=m -CONFIG_RTW89_8852A=m -CONFIG_RTW89_8852B_COMMON=m -CONFIG_RTW89_8852B=m -CONFIG_RTW89_8852BT=m -CONFIG_RTW89_8852C=m -CONFIG_RTW89_8922A=m -CONFIG_RTW89_8851BE=m -CONFIG_RTW89_8851BU=m -CONFIG_RTW89_8852AE=m -CONFIG_RTW89_8852AU=m -CONFIG_RTW89_8852BE=m -CONFIG_RTW89_8852BU=m -CONFIG_RTW89_8852BTE=m -CONFIG_RTW89_8852CE=m -CONFIG_RTW89_8852CU=m -CONFIG_RTW89_8922AE=m -# CONFIG_RTW89_8922AU is not set -CONFIG_RTW89_DEBUG=y -CONFIG_RTW89_DEBUGMSG=y -CONFIG_RTW89_DEBUGFS=y -CONFIG_WLAN_VENDOR_RSI=y -CONFIG_RSI_91X=m -# CONFIG_RSI_DEBUGFS is not set -CONFIG_RSI_SDIO=m -CONFIG_RSI_USB=m -CONFIG_RSI_COEX=y -CONFIG_WLAN_VENDOR_SILABS=y -CONFIG_WFX=m -CONFIG_WLAN_VENDOR_ST=y -CONFIG_CW1200=m -CONFIG_CW1200_WLAN_SDIO=m -CONFIG_CW1200_WLAN_SPI=m -CONFIG_WLAN_VENDOR_TI=y -CONFIG_WL1251=m -CONFIG_WL1251_SPI=m -CONFIG_WL1251_SDIO=m -CONFIG_WL12XX=m -CONFIG_WL18XX=m -CONFIG_WLCORE=m -CONFIG_WLCORE_SPI=m -CONFIG_WLCORE_SDIO=m -CONFIG_WLAN_VENDOR_ZYDAS=y -CONFIG_ZD1211RW=m -# CONFIG_ZD1211RW_DEBUG is not set -CONFIG_WLAN_VENDOR_QUANTENNA=y -CONFIG_QTNFMAC=m -CONFIG_QTNFMAC_PCIE=m -CONFIG_MAC80211_HWSIM=m -CONFIG_VIRT_WIFI=m -CONFIG_WAN=y -CONFIG_HDLC=m -CONFIG_HDLC_RAW=m -CONFIG_HDLC_RAW_ETH=m -CONFIG_HDLC_CISCO=m -CONFIG_HDLC_FR=m -CONFIG_HDLC_PPP=m -CONFIG_HDLC_X25=m -CONFIG_FRAMER=m -CONFIG_GENERIC_FRAMER=y -CONFIG_FRAMER_PEF2256=m -CONFIG_PCI200SYN=m -CONFIG_WANXL=m -CONFIG_PC300TOO=m -CONFIG_FARSYNC=m -CONFIG_FSL_UCC_HDLC=m -CONFIG_SLIC_DS26522=m -CONFIG_LAPBETHER=m -CONFIG_IEEE802154_DRIVERS=m -CONFIG_IEEE802154_FAKELB=m -CONFIG_IEEE802154_AT86RF230=m -CONFIG_IEEE802154_MRF24J40=m -CONFIG_IEEE802154_CC2520=m -CONFIG_IEEE802154_ATUSB=m -CONFIG_IEEE802154_ADF7242=m -CONFIG_IEEE802154_CA8210=m -CONFIG_IEEE802154_CA8210_DEBUGFS=y -CONFIG_IEEE802154_MCR20A=m -CONFIG_IEEE802154_HWSIM=m - -# -# Wireless WAN -# -CONFIG_WWAN=m -CONFIG_WWAN_DEBUGFS=y -CONFIG_WWAN_HWSIM=m -CONFIG_MHI_WWAN_CTRL=m -CONFIG_MHI_WWAN_MBIM=m -CONFIG_QCOM_BAM_DMUX=m -CONFIG_RPMSG_WWAN_CTRL=m -CONFIG_IOSM=m -CONFIG_MTK_T7XX=m -# end of Wireless WAN - -CONFIG_XEN_NETDEV_FRONTEND=y -CONFIG_XEN_NETDEV_BACKEND=m -CONFIG_VMXNET3=m -CONFIG_FUJITSU_ES=m -CONFIG_USB4_NET=m -CONFIG_HYPERV_NET=m -CONFIG_NETDEVSIM=m -CONFIG_NET_FAILOVER=y - -# -# Input device support -# -CONFIG_INPUT=y -CONFIG_INPUT_LEDS=m -CONFIG_INPUT_FF_MEMLESS=m -CONFIG_INPUT_SPARSEKMAP=m -CONFIG_INPUT_MATRIXKMAP=m -CONFIG_INPUT_VIVALDIFMAP=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -CONFIG_INPUT_JOYDEV=m -CONFIG_INPUT_EVDEV=y - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ADC=m -CONFIG_KEYBOARD_ADP5520=m -CONFIG_KEYBOARD_ADP5585=m -CONFIG_KEYBOARD_ADP5588=m -CONFIG_KEYBOARD_ATKBD=y -CONFIG_KEYBOARD_QT1050=m -CONFIG_KEYBOARD_QT1070=m -CONFIG_KEYBOARD_QT2160=m -CONFIG_KEYBOARD_DLINK_DIR685=m -CONFIG_KEYBOARD_LKKBD=m -CONFIG_KEYBOARD_GPIO=m -CONFIG_KEYBOARD_GPIO_POLLED=m -CONFIG_KEYBOARD_TCA8418=m -CONFIG_KEYBOARD_MATRIX=m -# CONFIG_KEYBOARD_CHARLIEPLEX is not set -CONFIG_KEYBOARD_LM8323=m -CONFIG_KEYBOARD_LM8333=m -CONFIG_KEYBOARD_MAX7359=m -CONFIG_KEYBOARD_MAX7360=m -CONFIG_KEYBOARD_MPR121=m -CONFIG_KEYBOARD_SNVS_PWRKEY=m -CONFIG_KEYBOARD_IMX=m -CONFIG_KEYBOARD_IMX_BBM_SCMI=y -CONFIG_KEYBOARD_IMX_SC_KEY=m -CONFIG_KEYBOARD_NEWTON=m -CONFIG_KEYBOARD_TEGRA=m -CONFIG_KEYBOARD_OPENCORES=m -CONFIG_KEYBOARD_PINEPHONE=m -CONFIG_KEYBOARD_PXA27x=m -CONFIG_KEYBOARD_SAMSUNG=m -CONFIG_KEYBOARD_STOWAWAY=m -CONFIG_KEYBOARD_SUNKBD=m -CONFIG_KEYBOARD_STMPE=m -# CONFIG_KEYBOARD_SUN4I_LRADC is not set -CONFIG_KEYBOARD_IQS62X=m -CONFIG_KEYBOARD_OMAP4=m -CONFIG_KEYBOARD_TC3589X=m -CONFIG_KEYBOARD_TM2_TOUCHKEY=m -CONFIG_KEYBOARD_TWL4030=m -CONFIG_KEYBOARD_XTKBD=m -CONFIG_KEYBOARD_CROS_EC=m -CONFIG_KEYBOARD_CAP11XX=m -CONFIG_KEYBOARD_BCM=m -CONFIG_KEYBOARD_MT6779=m -CONFIG_KEYBOARD_MTK_PMIC=m -CONFIG_KEYBOARD_CYPRESS_SF=m -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=m -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_BYD=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y -CONFIG_MOUSE_PS2_CYPRESS=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -CONFIG_MOUSE_PS2_ELANTECH=y -CONFIG_MOUSE_PS2_ELANTECH_SMBUS=y -CONFIG_MOUSE_PS2_SENTELIC=y -CONFIG_MOUSE_PS2_TOUCHKIT=y -CONFIG_MOUSE_PS2_FOCALTECH=y -CONFIG_MOUSE_PS2_SMBUS=y -CONFIG_MOUSE_SERIAL=m -CONFIG_MOUSE_APPLETOUCH=m -CONFIG_MOUSE_BCM5974=m -CONFIG_MOUSE_CYAPA=m -CONFIG_MOUSE_ELAN_I2C=m -CONFIG_MOUSE_ELAN_I2C_I2C=y -CONFIG_MOUSE_ELAN_I2C_SMBUS=y -CONFIG_MOUSE_VSXXXAA=m -CONFIG_MOUSE_GPIO=m -CONFIG_MOUSE_SYNAPTICS_I2C=m -CONFIG_MOUSE_SYNAPTICS_USB=m -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_ANALOG=m -CONFIG_JOYSTICK_A3D=m -CONFIG_JOYSTICK_ADC=m -CONFIG_JOYSTICK_ADI=m -CONFIG_JOYSTICK_COBRA=m -CONFIG_JOYSTICK_GF2K=m -CONFIG_JOYSTICK_GRIP=m -CONFIG_JOYSTICK_GRIP_MP=m -CONFIG_JOYSTICK_GUILLEMOT=m -CONFIG_JOYSTICK_INTERACT=m -CONFIG_JOYSTICK_SIDEWINDER=m -CONFIG_JOYSTICK_TMDC=m -CONFIG_JOYSTICK_IFORCE=m -CONFIG_JOYSTICK_IFORCE_USB=m -CONFIG_JOYSTICK_IFORCE_232=m -CONFIG_JOYSTICK_WARRIOR=m -CONFIG_JOYSTICK_MAGELLAN=m -CONFIG_JOYSTICK_SPACEORB=m -CONFIG_JOYSTICK_SPACEBALL=m -CONFIG_JOYSTICK_STINGER=m -CONFIG_JOYSTICK_TWIDJOY=m -CONFIG_JOYSTICK_ZHENHUA=m -CONFIG_JOYSTICK_DB9=m -CONFIG_JOYSTICK_GAMECON=m -CONFIG_JOYSTICK_TURBOGRAFX=m -CONFIG_JOYSTICK_AS5011=m -CONFIG_JOYSTICK_JOYDUMP=m -CONFIG_JOYSTICK_XPAD=m -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_JOYSTICK_WALKERA0701=m -CONFIG_JOYSTICK_PSXPAD_SPI=m -CONFIG_JOYSTICK_PSXPAD_SPI_FF=y -CONFIG_JOYSTICK_PXRC=m -CONFIG_JOYSTICK_QWIIC=m -CONFIG_JOYSTICK_FSIA6B=m -CONFIG_JOYSTICK_SENSEHAT=m -CONFIG_JOYSTICK_SEESAW=m -CONFIG_INPUT_TABLET=y -CONFIG_TABLET_USB_ACECAD=m -CONFIG_TABLET_USB_AIPTEK=m -CONFIG_TABLET_USB_HANWANG=m -CONFIG_TABLET_USB_KBTAB=m -CONFIG_TABLET_USB_PEGASUS=m -CONFIG_TABLET_SERIAL_WACOM4=m -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_88PM860X=m -CONFIG_TOUCHSCREEN_ADS7846=m -CONFIG_TOUCHSCREEN_AD7877=m -CONFIG_TOUCHSCREEN_AD7879=m -CONFIG_TOUCHSCREEN_AD7879_I2C=m -CONFIG_TOUCHSCREEN_AD7879_SPI=m -CONFIG_TOUCHSCREEN_ADC=m -CONFIG_TOUCHSCREEN_APPLE_Z2=m -CONFIG_TOUCHSCREEN_AR1021_I2C=m -CONFIG_TOUCHSCREEN_ATMEL_MXT=m -CONFIG_TOUCHSCREEN_ATMEL_MXT_T37=y -CONFIG_TOUCHSCREEN_AUO_PIXCIR=m -CONFIG_TOUCHSCREEN_BU21013=m -CONFIG_TOUCHSCREEN_BU21029=m -CONFIG_TOUCHSCREEN_CHIPONE_ICN8318=m -CONFIG_TOUCHSCREEN_CHIPONE_ICN8505=m -CONFIG_TOUCHSCREEN_CY8CTMA140=m -CONFIG_TOUCHSCREEN_CY8CTMG110=m -CONFIG_TOUCHSCREEN_CYTTSP_CORE=m -CONFIG_TOUCHSCREEN_CYTTSP_I2C=m -CONFIG_TOUCHSCREEN_CYTTSP_SPI=m -CONFIG_TOUCHSCREEN_CYTTSP5=m -CONFIG_TOUCHSCREEN_DA9034=m -CONFIG_TOUCHSCREEN_DA9052=m -CONFIG_TOUCHSCREEN_DYNAPRO=m -CONFIG_TOUCHSCREEN_HAMPSHIRE=m -CONFIG_TOUCHSCREEN_EETI=m -CONFIG_TOUCHSCREEN_EGALAX=m -CONFIG_TOUCHSCREEN_EGALAX_SERIAL=m -CONFIG_TOUCHSCREEN_EXC3000=m -CONFIG_TOUCHSCREEN_FUJITSU=m -CONFIG_TOUCHSCREEN_GOODIX=m -CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE=m -CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C=m -CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI=m -CONFIG_TOUCHSCREEN_HIDEEP=m -CONFIG_TOUCHSCREEN_HIMAX_HX852X=m -CONFIG_TOUCHSCREEN_HYCON_HY46XX=m -CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX=m -CONFIG_TOUCHSCREEN_HYNITRON_CST816X=m -CONFIG_TOUCHSCREEN_ILI210X=m -CONFIG_TOUCHSCREEN_ILITEK=m -CONFIG_TOUCHSCREEN_S6SY761=m -CONFIG_TOUCHSCREEN_GUNZE=m -CONFIG_TOUCHSCREEN_EKTF2127=m -CONFIG_TOUCHSCREEN_ELAN=m -CONFIG_TOUCHSCREEN_ELO=m -CONFIG_TOUCHSCREEN_WACOM_W8001=m -CONFIG_TOUCHSCREEN_WACOM_I2C=m -# CONFIG_TOUCHSCREEN_WACOM_W9000 is not set -CONFIG_TOUCHSCREEN_MAX11801=m -CONFIG_TOUCHSCREEN_MMS114=m -CONFIG_TOUCHSCREEN_MELFAS_MIP4=m -CONFIG_TOUCHSCREEN_MSG2638=m -CONFIG_TOUCHSCREEN_MTOUCH=m -CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS=m -CONFIG_TOUCHSCREEN_IMAGIS=m -CONFIG_TOUCHSCREEN_IMX6UL_TSC=m -CONFIG_TOUCHSCREEN_INEXIO=m -CONFIG_TOUCHSCREEN_PENMOUNT=m -CONFIG_TOUCHSCREEN_EDT_FT5X06=m -CONFIG_TOUCHSCREEN_TOUCHRIGHT=m -CONFIG_TOUCHSCREEN_TOUCHWIN=m -CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m -CONFIG_TOUCHSCREEN_PIXCIR=m -CONFIG_TOUCHSCREEN_WDT87XX_I2C=m -CONFIG_TOUCHSCREEN_WM831X=m -CONFIG_TOUCHSCREEN_WM97XX=m -CONFIG_TOUCHSCREEN_WM9705=y -CONFIG_TOUCHSCREEN_WM9712=y -CONFIG_TOUCHSCREEN_WM9713=y -CONFIG_TOUCHSCREEN_USB_COMPOSITE=m -CONFIG_TOUCHSCREEN_MC13783=m -CONFIG_TOUCHSCREEN_USB_EGALAX=y -CONFIG_TOUCHSCREEN_USB_PANJIT=y -CONFIG_TOUCHSCREEN_USB_3M=y -CONFIG_TOUCHSCREEN_USB_ITM=y -CONFIG_TOUCHSCREEN_USB_ETURBO=y -CONFIG_TOUCHSCREEN_USB_GUNZE=y -CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y -CONFIG_TOUCHSCREEN_USB_IRTOUCH=y -CONFIG_TOUCHSCREEN_USB_IDEALTEK=y -CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y -CONFIG_TOUCHSCREEN_USB_GOTOP=y -CONFIG_TOUCHSCREEN_USB_JASTEC=y -CONFIG_TOUCHSCREEN_USB_ELO=y -CONFIG_TOUCHSCREEN_USB_E2I=y -CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y -CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y -CONFIG_TOUCHSCREEN_USB_NEXIO=y -CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y -CONFIG_TOUCHSCREEN_TOUCHIT213=m -CONFIG_TOUCHSCREEN_TSC_SERIO=m -CONFIG_TOUCHSCREEN_TSC200X_CORE=m -CONFIG_TOUCHSCREEN_TSC2004=m -CONFIG_TOUCHSCREEN_TSC2005=m -CONFIG_TOUCHSCREEN_TSC2007=m -CONFIG_TOUCHSCREEN_TSC2007_IIO=y -CONFIG_TOUCHSCREEN_RM_TS=m -CONFIG_TOUCHSCREEN_SILEAD=m -CONFIG_TOUCHSCREEN_SIS_I2C=m -CONFIG_TOUCHSCREEN_ST1232=m -CONFIG_TOUCHSCREEN_STMFTS=m -CONFIG_TOUCHSCREEN_STMPE=m -# CONFIG_TOUCHSCREEN_SUN4I is not set -CONFIG_TOUCHSCREEN_SUR40=m -CONFIG_TOUCHSCREEN_SURFACE3_SPI=m -CONFIG_TOUCHSCREEN_SX8654=m -CONFIG_TOUCHSCREEN_TPS6507X=m -CONFIG_TOUCHSCREEN_ZET6223=m -CONFIG_TOUCHSCREEN_ZFORCE=m -CONFIG_TOUCHSCREEN_COLIBRI_VF50=m -CONFIG_TOUCHSCREEN_ROHM_BU21023=m -CONFIG_TOUCHSCREEN_IQS5XX=m -CONFIG_TOUCHSCREEN_IQS7211=m -CONFIG_TOUCHSCREEN_ZINITIX=m -CONFIG_TOUCHSCREEN_HIMAX_HX83112B=m -CONFIG_INPUT_MISC=y -CONFIG_INPUT_88PM860X_ONKEY=m -CONFIG_INPUT_88PM80X_ONKEY=m -CONFIG_INPUT_88PM886_ONKEY=m -CONFIG_INPUT_AD714X=m -CONFIG_INPUT_AD714X_I2C=m -CONFIG_INPUT_AD714X_SPI=m -CONFIG_INPUT_ARIZONA_HAPTICS=m -CONFIG_INPUT_ATC260X_ONKEY=m -CONFIG_INPUT_ATMEL_CAPTOUCH=m -CONFIG_INPUT_AW86927=m -CONFIG_INPUT_BBNSM_PWRKEY=m -CONFIG_INPUT_BMA150=m -CONFIG_INPUT_CS40L50_VIBRA=m -CONFIG_INPUT_E3X0_BUTTON=m -CONFIG_INPUT_PF1550_ONKEY=m -CONFIG_INPUT_PM8941_PWRKEY=m -CONFIG_INPUT_PM8XXX_VIBRATOR=m -CONFIG_INPUT_MAX7360_ROTARY=m -CONFIG_INPUT_MAX77650_ONKEY=m -CONFIG_INPUT_MAX77693_HAPTIC=m -CONFIG_INPUT_MAX8925_ONKEY=m -CONFIG_INPUT_MAX8997_HAPTIC=m -CONFIG_INPUT_MC13783_PWRBUTTON=m -CONFIG_INPUT_MMA8450=m -CONFIG_INPUT_GPIO_BEEPER=m -CONFIG_INPUT_GPIO_DECODER=m -CONFIG_INPUT_GPIO_VIBRA=m -CONFIG_INPUT_CPCAP_PWRBUTTON=m -CONFIG_INPUT_ATI_REMOTE2=m -CONFIG_INPUT_KEYSPAN_REMOTE=m -CONFIG_INPUT_KXTJ9=m -CONFIG_INPUT_POWERMATE=m -CONFIG_INPUT_YEALINK=m -CONFIG_INPUT_CM109=m -CONFIG_INPUT_REGULATOR_HAPTIC=m -CONFIG_INPUT_RETU_PWRBUTTON=m -CONFIG_INPUT_TPS65218_PWRBUTTON=m -CONFIG_INPUT_TPS65219_PWRBUTTON=m -CONFIG_INPUT_TPS6594_PWRBUTTON=m -CONFIG_INPUT_AXP20X_PEK=m -CONFIG_INPUT_TWL4030_PWRBUTTON=m -CONFIG_INPUT_TWL4030_VIBRA=m -CONFIG_INPUT_TWL6040_VIBRA=m -CONFIG_INPUT_UINPUT=y -CONFIG_INPUT_PALMAS_PWRBUTTON=m -CONFIG_INPUT_PCF8574=m -CONFIG_INPUT_PWM_BEEPER=m -CONFIG_INPUT_PWM_VIBRA=m -CONFIG_INPUT_RK805_PWRKEY=m -CONFIG_INPUT_GPIO_ROTARY_ENCODER=m -CONFIG_INPUT_DA7280_HAPTICS=m -CONFIG_INPUT_DA9052_ONKEY=m -CONFIG_INPUT_DA9055_ONKEY=m -CONFIG_INPUT_DA9063_ONKEY=m -CONFIG_INPUT_WM831X_ON=m -CONFIG_INPUT_ADXL34X=m -CONFIG_INPUT_ADXL34X_I2C=m -CONFIG_INPUT_ADXL34X_SPI=m -CONFIG_INPUT_IBM_PANEL=m -CONFIG_INPUT_IMS_PCU=m -CONFIG_INPUT_IQS269A=m -CONFIG_INPUT_IQS626A=m -CONFIG_INPUT_IQS7222=m -# CONFIG_INPUT_ISA1200_HAPTIC is not set -CONFIG_INPUT_CMA3000=m -CONFIG_INPUT_CMA3000_I2C=m -CONFIG_INPUT_XEN_KBDDEV_FRONTEND=m -CONFIG_INPUT_SOC_BUTTON_ARRAY=m -CONFIG_INPUT_DRV260X_HAPTICS=m -CONFIG_INPUT_DRV2665_HAPTICS=m -CONFIG_INPUT_DRV2667_HAPTICS=m -CONFIG_INPUT_HISI_POWERKEY=m -CONFIG_INPUT_QNAP_MCU=m -CONFIG_INPUT_RAVE_SP_PWRBUTTON=m -CONFIG_INPUT_SC27XX_VIBRA=m -CONFIG_INPUT_RT5120_PWRKEY=m -CONFIG_INPUT_STPMIC1_ONKEY=m -CONFIG_RMI4_CORE=m -CONFIG_RMI4_I2C=m -CONFIG_RMI4_SPI=m -CONFIG_RMI4_SMB=m -CONFIG_RMI4_F03=y -CONFIG_RMI4_F03_SERIO=m -CONFIG_RMI4_2D_SENSOR=y -CONFIG_RMI4_F11=y -CONFIG_RMI4_F12=y -CONFIG_RMI4_F1A=y -CONFIG_RMI4_F21=y -CONFIG_RMI4_F30=y -CONFIG_RMI4_F34=y -CONFIG_RMI4_F3A=y -CONFIG_RMI4_F54=y -CONFIG_RMI4_F55=y - -# -# Hardware I/O ports -# -CONFIG_SERIO=y -CONFIG_SERIO_SERPORT=m -CONFIG_SERIO_PARKBD=m -CONFIG_SERIO_AMBAKMI=m -CONFIG_SERIO_PCIPS2=m -CONFIG_SERIO_LIBPS2=y -CONFIG_SERIO_RAW=m -CONFIG_SERIO_ALTERA_PS2=m -CONFIG_SERIO_PS2MULT=m -CONFIG_SERIO_ARC_PS2=m -CONFIG_SERIO_APBPS2=m -CONFIG_SERIO_OLPC_APSP=m -CONFIG_HYPERV_KEYBOARD=m -# CONFIG_SERIO_SUN4I_PS2 is not set -CONFIG_SERIO_GPIO_PS2=m -CONFIG_USERIO=m -CONFIG_GAMEPORT=m -CONFIG_GAMEPORT_EMU10K1=m -CONFIG_GAMEPORT_FM801=m -# end of Hardware I/O ports -# end of Input device support - -# -# Character devices -# -CONFIG_TTY=y -CONFIG_VT=y -CONFIG_CONSOLE_TRANSLATIONS=y -CONFIG_VT_CONSOLE=y -CONFIG_VT_CONSOLE_SLEEP=y -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_UNIX98_PTYS=y -# CONFIG_LEGACY_PTYS is not set -# CONFIG_LEGACY_TIOCSTI is not set -# CONFIG_LDISC_AUTOLOAD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_EARLYCON=y -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_PNP=y -CONFIG_SERIAL_8250_16550A_VARIANTS=y -CONFIG_SERIAL_8250_FINTEK=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_DMA=y -CONFIG_SERIAL_8250_PCILIB=y -CONFIG_SERIAL_8250_PCI=y -CONFIG_SERIAL_8250_EXAR=m -CONFIG_SERIAL_8250_MEN_MCB=m -CONFIG_SERIAL_8250_NR_UARTS=48 -CONFIG_SERIAL_8250_RUNTIME_UARTS=32 -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -# CONFIG_SERIAL_8250_DETECT_IRQ is not set -CONFIG_SERIAL_8250_RSA=y -CONFIG_SERIAL_8250_MANY_PORTS=y -CONFIG_SERIAL_8250_PCI1XXXX=m -CONFIG_SERIAL_8250_FSL=y -CONFIG_SERIAL_8250_DFL=m -CONFIG_SERIAL_8250_DW=y -# CONFIG_SERIAL_8250_EM is not set -CONFIG_SERIAL_8250_KEBA=m -CONFIG_SERIAL_8250_RT288X=y -CONFIG_SERIAL_8250_OMAP=y -CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP=y -CONFIG_SERIAL_8250_MT6577=y -CONFIG_SERIAL_8250_PERICOM=m -CONFIG_SERIAL_8250_PXA=y -CONFIG_SERIAL_8250_TEGRA=y -CONFIG_SERIAL_OF_PLATFORM=y -CONFIG_SERIAL_8250_DWLIB=y - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_AMBA_PL010=m -CONFIG_SERIAL_AMBA_PL011=y -CONFIG_SERIAL_AMBA_PL011_CONSOLE=y -CONFIG_SERIAL_EARLYCON_SEMIHOST=y -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_SERIAL_ATMEL_PDC=y -# CONFIG_SERIAL_ATMEL_TTYAT is not set -CONFIG_SERIAL_MESON=y -CONFIG_SERIAL_MESON_CONSOLE=y -CONFIG_SERIAL_SAMSUNG=m -CONFIG_SERIAL_SAMSUNG_UARTS=4 -CONFIG_SERIAL_SAMSUNG_CONSOLE=y -CONFIG_SERIAL_TEGRA=m -CONFIG_SERIAL_TEGRA_TCU=y -CONFIG_SERIAL_TEGRA_TCU_CONSOLE=y -CONFIG_SERIAL_TEGRA_UTC=m -CONFIG_SERIAL_TEGRA_UTC_CONSOLE=y -CONFIG_SERIAL_MAX3100=m -CONFIG_SERIAL_MAX310X=y -CONFIG_SERIAL_PXA=y -CONFIG_SERIAL_PXA_CONSOLE=y -CONFIG_SERIAL_IMX=y -CONFIG_SERIAL_IMX_CONSOLE=y -# CONFIG_SERIAL_IMX_EARLYCON is not set -CONFIG_SERIAL_UARTLITE=m -CONFIG_SERIAL_UARTLITE_NR_UARTS=1 -CONFIG_SERIAL_SH_SCI=y -CONFIG_SERIAL_SH_SCI_NR_UARTS=18 -CONFIG_SERIAL_SH_SCI_CONSOLE=y -CONFIG_SERIAL_SH_SCI_EARLYCON=y -CONFIG_SERIAL_SH_SCI_DMA=y -CONFIG_SERIAL_RSCI=m -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_CONSOLE_POLL=y -CONFIG_SERIAL_JSM=m -CONFIG_SERIAL_MSM=y -CONFIG_SERIAL_MSM_CONSOLE=y -CONFIG_SERIAL_QCOM_GENI=y -CONFIG_SERIAL_QCOM_GENI_CONSOLE=y -CONFIG_SERIAL_QCOM_GENI_UART_PORTS=8 -CONFIG_SERIAL_SIFIVE=m -CONFIG_SERIAL_QE=m -CONFIG_SERIAL_SCCNXP=y -CONFIG_SERIAL_SCCNXP_CONSOLE=y -CONFIG_SERIAL_SC16IS7XX=m -CONFIG_SERIAL_SC16IS7XX_I2C=m -CONFIG_SERIAL_SC16IS7XX_SPI=m -CONFIG_SERIAL_ALTERA_JTAGUART=m -CONFIG_SERIAL_ALTERA_UART=m -CONFIG_SERIAL_ALTERA_UART_MAXPORTS=4 -CONFIG_SERIAL_ALTERA_UART_BAUDRATE=115200 -CONFIG_SERIAL_XILINX_PS_UART=y -CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y -CONFIG_SERIAL_ARC=m -CONFIG_SERIAL_ARC_NR_PORTS=1 -CONFIG_SERIAL_RP2=m -CONFIG_SERIAL_RP2_NR_UARTS=32 -CONFIG_SERIAL_FSL_LPUART=m -CONFIG_SERIAL_FSL_LINFLEXUART=m -CONFIG_SERIAL_CONEXANT_DIGICOLOR=m -CONFIG_SERIAL_MEN_Z135=m -CONFIG_SERIAL_SPRD=m -CONFIG_SERIAL_STM32=m -CONFIG_SERIAL_STM32_CONSOLE=y -CONFIG_SERIAL_MVEBU_UART=y -CONFIG_SERIAL_MVEBU_CONSOLE=y -CONFIG_SERIAL_OWL=y -CONFIG_SERIAL_OWL_CONSOLE=y -CONFIG_SERIAL_LITEUART=m -CONFIG_SERIAL_LITEUART_MAX_PORTS=1 -CONFIG_SERIAL_NUVOTON_MA35D1=m -# end of Serial drivers - -CONFIG_SERIAL_MCTRL_GPIO=y -CONFIG_SERIAL_NONSTANDARD=y -CONFIG_MOXA_INTELLIO=m -CONFIG_MOXA_SMARTIO=m -CONFIG_N_HDLC=m -CONFIG_N_GSM=m -CONFIG_NOZOMI=m -CONFIG_NULL_TTY=m -CONFIG_HVC_DRIVER=y -CONFIG_HVC_IRQ=y -CONFIG_HVC_XEN=y -CONFIG_HVC_XEN_FRONTEND=y -# CONFIG_HVC_DCC is not set -CONFIG_RPMSG_TTY=m -CONFIG_SERIAL_DEV_BUS=y -CONFIG_SERIAL_DEV_CTRL_TTYPORT=y -CONFIG_TTY_PRINTK=y -CONFIG_TTY_PRINTK_LEVEL=6 -CONFIG_PRINTER=m -# CONFIG_LP_CONSOLE is not set -CONFIG_PPDEV=m -CONFIG_VIRTIO_CONSOLE=y -CONFIG_IPMI_HANDLER=m -CONFIG_IPMI_DMI_DECODE=y -CONFIG_IPMI_PLAT_DATA=y -# CONFIG_IPMI_PANIC_EVENT is not set -CONFIG_IPMI_DEVICE_INTERFACE=m -CONFIG_IPMI_SI=m -CONFIG_IPMI_SSIF=m -CONFIG_IPMI_IPMB=m -CONFIG_IPMI_WATCHDOG=m -CONFIG_IPMI_POWEROFF=m -CONFIG_IPMI_KCS_BMC=m -CONFIG_NPCM7XX_KCS_IPMI_BMC=m -CONFIG_IPMI_KCS_BMC_CDEV_IPMI=m -CONFIG_IPMI_KCS_BMC_SERIO=m -CONFIG_SSIF_IPMI_BMC=m -CONFIG_IPMB_DEVICE_INTERFACE=m -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_TIMERIOMEM=m -CONFIG_HW_RANDOM_AIROHA=m -CONFIG_HW_RANDOM_ATMEL=m -CONFIG_HW_RANDOM_BA431=m -CONFIG_HW_RANDOM_OMAP=m -CONFIG_HW_RANDOM_VIRTIO=m -CONFIG_HW_RANDOM_HISI=m -CONFIG_HW_RANDOM_HISTB=m -# CONFIG_HW_RANDOM_HISI_TRNG is not set -CONFIG_HW_RANDOM_XGENE=m -CONFIG_HW_RANDOM_STM32=m -CONFIG_HW_RANDOM_POLARFIRE_SOC=m -CONFIG_HW_RANDOM_MESON=m -CONFIG_HW_RANDOM_CAVIUM=m -CONFIG_HW_RANDOM_MTK=m -CONFIG_HW_RANDOM_OPTEE=m -CONFIG_HW_RANDOM_NPCM=m -CONFIG_HW_RANDOM_CCTRNG=m -CONFIG_HW_RANDOM_XIPHERA=m -CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=m -CONFIG_HW_RANDOM_CN10K=m -CONFIG_HW_RANDOM_ROCKCHIP=y -# CONFIG_HW_RANDOM_XILINX is not set -CONFIG_DEVMEM=y -CONFIG_DEVPORT=y -CONFIG_TCG_TPM=y -# CONFIG_TCG_TPM2_HMAC is not set -CONFIG_HW_RANDOM_TPM=y -CONFIG_TCG_TIS_CORE=y -CONFIG_TCG_TIS=y -CONFIG_TCG_TIS_SPI=y -CONFIG_TCG_TIS_SPI_CR50=y -CONFIG_TCG_TIS_I2C=m -CONFIG_TCG_TIS_SYNQUACER=m -CONFIG_TCG_TIS_I2C_CR50=m -CONFIG_TCG_TIS_I2C_ATMEL=m -CONFIG_TCG_TIS_I2C_INFINEON=m -CONFIG_TCG_TIS_I2C_NUVOTON=m -CONFIG_TCG_ATMEL=m -CONFIG_TCG_INFINEON=m -CONFIG_TCG_XEN=m -CONFIG_TCG_CRB=y -CONFIG_TCG_ARM_CRB_FFA=y -CONFIG_TCG_VTPM_PROXY=m -CONFIG_TCG_FTPM_TEE=m -CONFIG_TCG_TIS_ST33ZP24=m -CONFIG_TCG_TIS_ST33ZP24_I2C=m -CONFIG_TCG_TIS_ST33ZP24_SPI=m -CONFIG_XILLYBUS_CLASS=m -CONFIG_XILLYBUS=m -CONFIG_XILLYBUS_PCIE=m -CONFIG_XILLYBUS_OF=m -CONFIG_XILLYUSB=m -# end of Character devices - -# -# I2C support -# -CONFIG_I2C=y -CONFIG_ACPI_I2C_OPREGION=y -CONFIG_I2C_BOARDINFO=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_MUX=m - -# -# Multiplexer I2C Chip support -# -CONFIG_I2C_ARB_GPIO_CHALLENGE=m -CONFIG_I2C_MUX_GPIO=m -CONFIG_I2C_MUX_GPMUX=m -CONFIG_I2C_MUX_LTC4306=m -CONFIG_I2C_MUX_PCA9541=m -CONFIG_I2C_MUX_PCA954x=m -CONFIG_I2C_MUX_PINCTRL=m -CONFIG_I2C_MUX_REG=m -CONFIG_I2C_DEMUX_PINCTRL=m -CONFIG_I2C_MUX_MLXCPLD=m -CONFIG_I2C_MUX_MULE=m -# end of Multiplexer I2C Chip support - -CONFIG_I2C_ATR=m -CONFIG_I2C_HELPER_AUTO=y -CONFIG_I2C_SMBUS=m -CONFIG_I2C_ALGOBIT=m -CONFIG_I2C_ALGOPCA=m - -# -# I2C Hardware Bus support -# - -# -# PC SMBus host controller drivers -# -CONFIG_I2C_CCGX_UCSI=m -CONFIG_I2C_ALI1535=m -CONFIG_I2C_ALI1563=m -CONFIG_I2C_ALI15X3=m -CONFIG_I2C_AMD756=m -CONFIG_I2C_AMD8111=m -# CONFIG_I2C_AMD_MP2 is not set -CONFIG_I2C_AMD_ASF=m -CONFIG_I2C_HIX5HD2=m -CONFIG_I2C_I801=m -CONFIG_I2C_I801_MUX=y -CONFIG_I2C_ISCH=m -CONFIG_I2C_PIIX4=m -CONFIG_I2C_NFORCE2=m -CONFIG_I2C_NVIDIA_GPU=m -CONFIG_I2C_SIS5595=m -CONFIG_I2C_SIS630=m -CONFIG_I2C_SIS96X=m -CONFIG_I2C_VIA=m -CONFIG_I2C_VIAPRO=m -CONFIG_I2C_ZHAOXIN=m - -# -# ACPI drivers -# -CONFIG_I2C_SCMI=m - -# -# I2C system bus drivers (mostly embedded / system-on-chip) -# -CONFIG_I2C_ALTERA=m -CONFIG_I2C_AT91=m -# CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL is not set -# CONFIG_I2C_CADENCE is not set -CONFIG_I2C_CBUS_GPIO=m -CONFIG_I2C_DESIGNWARE_CORE=y -CONFIG_I2C_DESIGNWARE_PLATFORM=y -CONFIG_I2C_DESIGNWARE_AMDISP=m -CONFIG_I2C_DESIGNWARE_PCI=m -# CONFIG_I2C_EMEV2 is not set -CONFIG_I2C_GPIO=m -# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set -CONFIG_I2C_HISI=m -CONFIG_I2C_IMX=m -CONFIG_I2C_IMX_LPI2C=m -CONFIG_I2C_KEBA=m -CONFIG_I2C_KEMPLD=m -CONFIG_I2C_MLXBF=m -CONFIG_I2C_MESON=m -CONFIG_I2C_MT65XX=m -CONFIG_I2C_MT7621=m -CONFIG_I2C_MV64XXX=m -CONFIG_I2C_NOMADIK=m -CONFIG_I2C_NPCM=m -CONFIG_I2C_OCORES=m -CONFIG_I2C_OMAP=y -CONFIG_I2C_OWL=m -CONFIG_I2C_APPLE=m -CONFIG_I2C_PCA_PLATFORM=m -CONFIG_I2C_PXA=m -CONFIG_I2C_PXA_SLAVE=y -CONFIG_I2C_QCOM_CCI=m -CONFIG_I2C_QCOM_GENI=m -CONFIG_I2C_QUP=m -CONFIG_I2C_RIIC=m -CONFIG_I2C_RK3X=m -CONFIG_I2C_RZV2M=m -CONFIG_I2C_SH_MOBILE=m -CONFIG_I2C_SIMTEC=m -CONFIG_I2C_SPRD=y -CONFIG_I2C_STM32F4=m -CONFIG_I2C_STM32F7=m -CONFIG_I2C_SYNQUACER=m -CONFIG_I2C_TEGRA=m -CONFIG_I2C_TEGRA_BPMP=m -CONFIG_I2C_VERSATILE=m -CONFIG_I2C_THUNDERX=m -CONFIG_I2C_XILINX=m -CONFIG_I2C_XLP9XX=m -CONFIG_I2C_RCAR=m - -# -# External I2C/SMBus adapter drivers -# -CONFIG_I2C_DIOLAN_U2C=m -CONFIG_I2C_DLN2=m -CONFIG_I2C_LJCA=m -CONFIG_I2C_NCT6694=m -CONFIG_I2C_CP2615=m -CONFIG_I2C_PARPORT=m -CONFIG_I2C_PCI1XXXX=m -CONFIG_I2C_ROBOTFUZZ_OSIF=m -CONFIG_I2C_TAOS_EVM=m -CONFIG_I2C_TINY_USB=m -CONFIG_I2C_VIPERBOARD=m - -# -# Other I2C/SMBus bus drivers -# -CONFIG_I2C_MLXCPLD=m -CONFIG_I2C_CROS_EC_TUNNEL=m -CONFIG_I2C_XGENE_SLIMPRO=m -CONFIG_I2C_FSI=m -CONFIG_I2C_VIRTIO=m -# end of I2C Hardware Bus support - -CONFIG_I2C_STUB=m -CONFIG_I2C_SLAVE=y -CONFIG_I2C_SLAVE_EEPROM=m -CONFIG_I2C_SLAVE_TESTUNIT=m -# CONFIG_I2C_DEBUG_CORE is not set -# CONFIG_I2C_DEBUG_ALGO is not set -# CONFIG_I2C_DEBUG_BUS is not set -# end of I2C support - -CONFIG_I3C=m -CONFIG_ADI_I3C_MASTER=m -CONFIG_CDNS_I3C_MASTER=m -CONFIG_DW_I3C_MASTER=m -CONFIG_SVC_I3C_MASTER=m -CONFIG_MIPI_I3C_HCI=m -CONFIG_MIPI_I3C_HCI_PCI=m -CONFIG_RENESAS_I3C=m -CONFIG_I3C_OR_I2C=m -CONFIG_SPI=y -# CONFIG_SPI_DEBUG is not set -CONFIG_SPI_MASTER=y -CONFIG_SPI_MEM=y -CONFIG_SPI_OFFLOAD=y - -# -# SPI Master Controller Drivers -# -CONFIG_SPI_AIROHA_SNFI=m -CONFIG_SPI_ALTERA=m -CONFIG_SPI_ALTERA_CORE=m -CONFIG_SPI_ALTERA_DFL=m -CONFIG_SPI_AMLOGIC_SPIFC_A1=m -CONFIG_SPI_AMLOGIC_SPIFC_A4=m -CONFIG_SPI_AMLOGIC_SPISG=m -CONFIG_SPI_APPLE=m -CONFIG_SPI_ARMADA_3700=m -CONFIG_SPI_ATMEL=m -CONFIG_SPI_AXI_SPI_ENGINE=m -CONFIG_SPI_AXIADO=m -CONFIG_SPI_BITBANG=m -CONFIG_SPI_BUTTERFLY=m -CONFIG_SPI_CADENCE=m -CONFIG_SPI_CADENCE_QUADSPI=m -CONFIG_SPI_CADENCE_XSPI=m -CONFIG_SPI_CH341=m -CONFIG_SPI_CS42L43=m -CONFIG_SPI_DESIGNWARE=m -CONFIG_SPI_DW_DMA=y -CONFIG_SPI_DW_PCI=m -CONFIG_SPI_DW_MMIO=m -CONFIG_SPI_DLN2=m -CONFIG_SPI_FSI=m -CONFIG_SPI_FSL_LPSPI=m -CONFIG_SPI_FSL_QUADSPI=m -CONFIG_SPI_HISI_KUNPENG=m -CONFIG_SPI_HISI_SFC_V3XX=m -CONFIG_SPI_NXP_FLEXSPI=m -CONFIG_SPI_NXP_XSPI=m -CONFIG_SPI_GPIO=m -CONFIG_SPI_IMX=m -CONFIG_SPI_KSPI2=m -CONFIG_SPI_LM70_LLP=m -CONFIG_SPI_FSL_LIB=y -CONFIG_SPI_FSL_SPI=y -CONFIG_SPI_FSL_DSPI=m -CONFIG_SPI_LJCA=m -CONFIG_SPI_MESON_SPICC=m -CONFIG_SPI_MESON_SPIFC=m -CONFIG_SPI_MICROCHIP_CORE_QSPI=m -CONFIG_SPI_MICROCHIP_CORE_SPI=m -CONFIG_SPI_MT65XX=m -CONFIG_SPI_MTK_NOR=m -CONFIG_SPI_MTK_SNFI=m -CONFIG_SPI_WPCM_FIU=m -CONFIG_SPI_NPCM_FIU=m -CONFIG_SPI_NPCM_PSPI=m -CONFIG_SPI_OC_TINY=m -CONFIG_SPI_OMAP24XX=y -CONFIG_SPI_ORION=m -CONFIG_SPI_PCI1XXXX=m -CONFIG_SPI_PL022=m -CONFIG_SPI_POLARFIRE_SOC=m -CONFIG_SPI_PXA2XX=m -CONFIG_SPI_PXA2XX_PCI=m -CONFIG_SPI_ROCKCHIP=m -CONFIG_SPI_ROCKCHIP_SFC=m -CONFIG_SPI_RPCIF=m -CONFIG_SPI_RSPI=m -CONFIG_SPI_RZV2H_RSPI=m -CONFIG_SPI_RZV2M_CSI=m -CONFIG_SPI_QCOM_QSPI=m -CONFIG_SPI_QPIC_SNAND=m -CONFIG_SPI_QUP=m -CONFIG_SPI_QCOM_GENI=m -CONFIG_SPI_SC18IS602=m -CONFIG_SPI_SH_MSIOF=m -CONFIG_SPI_SH_HSPI=m -CONFIG_SPI_SIFIVE=m -CONFIG_SPI_SLAVE_MT27XX=m -CONFIG_SPI_SN_F_OSPI=m -CONFIG_SPI_SG2044_NOR=m -CONFIG_SPI_SPRD=m -CONFIG_SPI_SPRD_ADI=m -CONFIG_SPI_STM32=m -CONFIG_SPI_STM32_OSPI=m -CONFIG_SPI_STM32_QSPI=m -# CONFIG_SPI_SUN4I is not set -CONFIG_SPI_SUN6I=m -CONFIG_SPI_SYNQUACER=m -CONFIG_SPI_MXIC=m -CONFIG_SPI_TEGRA210_QUAD=y -CONFIG_SPI_TEGRA114=m -CONFIG_SPI_TEGRA20_SFLASH=m -CONFIG_SPI_TEGRA20_SLINK=m -CONFIG_SPI_THUNDERX=m -CONFIG_SPI_VIRTIO=m -CONFIG_SPI_XCOMM=m -CONFIG_SPI_XILINX=m -CONFIG_SPI_XLP=m -CONFIG_SPI_ZYNQMP_GQSPI=m -CONFIG_SPI_AMD=m - -# -# SPI Multiplexer support -# -CONFIG_SPI_MUX=m - -# -# SPI Protocol Masters -# -CONFIG_SPI_SPIDEV=m -CONFIG_SPI_LOOPBACK_TEST=m -CONFIG_SPI_TLE62X0=m -CONFIG_SPI_SLAVE=y -CONFIG_SPI_SLAVE_TIME=m -CONFIG_SPI_SLAVE_SYSTEM_CONTROL=m -CONFIG_SPI_DYNAMIC=y - -# -# SPI Offload triggers -# -CONFIG_SPI_OFFLOAD_TRIGGER_ADI_UTIL_SD=m -CONFIG_SPI_OFFLOAD_TRIGGER_PWM=m -CONFIG_SPMI=m -CONFIG_SPMI_APPLE=m -CONFIG_SPMI_HISI3670=m -CONFIG_SPMI_MSM_PMIC_ARB=m -CONFIG_SPMI_MTK_PMIF=m -CONFIG_HSI=m -CONFIG_HSI_BOARDINFO=y - -# -# HSI controllers -# - -# -# HSI clients -# -CONFIG_HSI_CHAR=m -CONFIG_PPS=y -# CONFIG_PPS_DEBUG is not set - -# -# PPS clients support -# -# CONFIG_PPS_CLIENT_KTIMER is not set -CONFIG_PPS_CLIENT_LDISC=m -CONFIG_PPS_CLIENT_PARPORT=m -CONFIG_PPS_CLIENT_GPIO=m -CONFIG_PPS_GENERATOR=m -CONFIG_PPS_GENERATOR_DUMMY=m - -# -# PTP clock support -# -CONFIG_PTP_1588_CLOCK=y -CONFIG_PTP_1588_CLOCK_OPTIONAL=y -CONFIG_PTP_1588_CLOCK_QORIQ=m -CONFIG_DP83640_PHY=m -CONFIG_PTP_1588_CLOCK_INES=m -CONFIG_PTP_1588_CLOCK_KVM=m -CONFIG_PTP_1588_CLOCK_VMCLOCK=m -CONFIG_PTP_1588_CLOCK_IDT82P33=m -CONFIG_PTP_1588_CLOCK_IDTCM=m -CONFIG_PTP_1588_CLOCK_FC3W=m -CONFIG_PTP_1588_CLOCK_MOCK=m -CONFIG_PTP_1588_CLOCK_OCP=m -CONFIG_PTP_DFL_TOD=m -CONFIG_PTP_NETC_V4_TIMER=m -# end of PTP clock support - -# -# DPLL device support -# -CONFIG_DPLL=y -# CONFIG_DPLL_REFCNT_TRACKER is not set -CONFIG_ZL3073X=m -CONFIG_ZL3073X_I2C=m -CONFIG_ZL3073X_SPI=m -# end of DPLL device support - -CONFIG_PINCTRL=y -CONFIG_GENERIC_PINCTRL_GROUPS=y -CONFIG_PINMUX=y -CONFIG_GENERIC_PINMUX_FUNCTIONS=y -CONFIG_PINCONF=y -CONFIG_GENERIC_PINCONF=y -CONFIG_GENERIC_PINCTRL=y -# CONFIG_DEBUG_PINCTRL is not set -CONFIG_PINCTRL_AMD=y -CONFIG_PINCTRL_AMDISP=m -CONFIG_PINCTRL_APPLE_GPIO=m -CONFIG_PINCTRL_AS3722=y -CONFIG_PINCTRL_AXP209=m -CONFIG_PINCTRL_AW9523=m -CONFIG_PINCTRL_BM1880=y -CONFIG_PINCTRL_CY8C95X0=m -CONFIG_PINCTRL_DA9062=m -# CONFIG_PINCTRL_GENERIC_MUX is not set -CONFIG_PINCTRL_KEEMBAY=m -CONFIG_PINCTRL_MAX7360=m -CONFIG_PINCTRL_MAX77620=m -CONFIG_PINCTRL_MCP23S08_I2C=m -CONFIG_PINCTRL_MCP23S08_SPI=m -CONFIG_PINCTRL_MCP23S08=m -CONFIG_PINCTRL_MICROCHIP_SGPIO=y -CONFIG_PINCTRL_OCELOT=y -CONFIG_PINCTRL_PALMAS=y -CONFIG_PINCTRL_PEF2256=m -CONFIG_PINCTRL_RK805=m -CONFIG_PINCTRL_ROCKCHIP=y -CONFIG_PINCTRL_SCMI=m -CONFIG_PINCTRL_SINGLE=y -CONFIG_PINCTRL_STMFX=m -CONFIG_PINCTRL_SX150X=y -CONFIG_PINCTRL_TPS6594=m -CONFIG_PINCTRL_ZYNQMP=m -CONFIG_PINCTRL_MLXBF3=m -CONFIG_PINCTRL_RP1=m -CONFIG_PINCTRL_OWL=y -CONFIG_PINCTRL_S700=y -CONFIG_PINCTRL_S900=y - -# -# Airoha pinctrl drivers -# -CONFIG_PINCTRL_AIROHA=m -# end of Airoha pinctrl drivers - -CONFIG_PINCTRL_BERLIN=y -CONFIG_PINCTRL_AS370=y -CONFIG_PINCTRL_BERLIN_BG4CT=y -CONFIG_PINCTRL_CS42L43=m -CONFIG_PINCTRL_LOCHNAGAR=m -CONFIG_PINCTRL_MADERA=m -CONFIG_PINCTRL_CS47L15=y -CONFIG_PINCTRL_CS47L35=y -CONFIG_PINCTRL_CS47L85=y -CONFIG_PINCTRL_CS47L90=y -CONFIG_PINCTRL_CS47L92=y -CONFIG_PINCTRL_SKY1_BASE=m -CONFIG_PINCTRL_SKY1=m -CONFIG_PINCTRL_IMX=y -CONFIG_PINCTRL_IMX_SCMI=m -CONFIG_PINCTRL_IMX_SCU=y -CONFIG_PINCTRL_IMX8MM=y -CONFIG_PINCTRL_IMX8MN=y -CONFIG_PINCTRL_IMX8MP=y -CONFIG_PINCTRL_IMX8MQ=y -CONFIG_PINCTRL_IMX8QM=y -CONFIG_PINCTRL_IMX8QXP=y -CONFIG_PINCTRL_IMX8DXL=y -CONFIG_PINCTRL_IMX8ULP=m -CONFIG_PINCTRL_IMX91=m -CONFIG_PINCTRL_IMX93=m - -# -# MediaTek pinctrl drivers -# -CONFIG_EINT_MTK=y -CONFIG_PINCTRL_MTK=y -CONFIG_PINCTRL_MTK_V2=y -CONFIG_PINCTRL_MTK_MOORE=y -CONFIG_PINCTRL_MTK_PARIS=y -CONFIG_PINCTRL_MT2712=y -CONFIG_PINCTRL_MT6765=y -CONFIG_PINCTRL_MT6779=m -CONFIG_PINCTRL_MT6795=y -CONFIG_PINCTRL_MT6797=y -CONFIG_PINCTRL_MT6878=y -CONFIG_PINCTRL_MT6893=y -CONFIG_PINCTRL_MT7622=y -CONFIG_PINCTRL_MT7981=y -CONFIG_PINCTRL_MT7986=y -CONFIG_PINCTRL_MT7988=y -CONFIG_PINCTRL_MT8167=y -CONFIG_PINCTRL_MT8173=y -CONFIG_PINCTRL_MT8183=y -CONFIG_PINCTRL_MT8186=y -CONFIG_PINCTRL_MT8188=y -CONFIG_PINCTRL_MT8189=y -CONFIG_PINCTRL_MT8901=y -CONFIG_PINCTRL_MT8192=y -CONFIG_PINCTRL_MT8195=y -CONFIG_PINCTRL_MT8196=y -CONFIG_PINCTRL_MT8365=y -CONFIG_PINCTRL_MT8516=y -CONFIG_PINCTRL_MT6397=y -# end of MediaTek pinctrl drivers - -CONFIG_PINCTRL_MESON=y -CONFIG_PINCTRL_MESON_GXBB=y -CONFIG_PINCTRL_MESON_GXL=y -CONFIG_PINCTRL_MESON8_PMX=y -CONFIG_PINCTRL_MESON_AXG=y -CONFIG_PINCTRL_MESON_AXG_PMX=y -CONFIG_PINCTRL_MESON_G12A=y -CONFIG_PINCTRL_MESON_A1=y -CONFIG_PINCTRL_MESON_S4=m -CONFIG_PINCTRL_AMLOGIC_A4=y -CONFIG_PINCTRL_AMLOGIC_C3=m -CONFIG_PINCTRL_AMLOGIC_T7=m -CONFIG_PINCTRL_PIC64GX=y -CONFIG_PINCTRL_POLARFIRE_SOC=y -CONFIG_PINCTRL_MVEBU=y -CONFIG_PINCTRL_ARMADA_AP806=y -CONFIG_PINCTRL_ARMADA_CP110=y -CONFIG_PINCTRL_AC5=y -CONFIG_PINCTRL_ARMADA_37XX=y -CONFIG_PINCTRL_NPCM8XX=m -CONFIG_PINCTRL_MA35=y -CONFIG_PINCTRL_MA35D1=y -CONFIG_PINCTRL_S32CC=y -CONFIG_PINCTRL_S32G2=y -CONFIG_PINCTRL_MSM=y -CONFIG_PINCTRL_ELIZA=y -CONFIG_PINCTRL_GLYMUR=m -CONFIG_PINCTRL_HAWI=y -CONFIG_PINCTRL_IPQ5018=m -CONFIG_PINCTRL_IPQ5210=y -CONFIG_PINCTRL_IPQ5332=m -CONFIG_PINCTRL_IPQ5424=m -CONFIG_PINCTRL_IPQ8074=m -CONFIG_PINCTRL_IPQ6018=m -CONFIG_PINCTRL_IPQ9574=m -CONFIG_PINCTRL_IPQ9650=y -CONFIG_PINCTRL_KAANAPALI=m -CONFIG_PINCTRL_MDM9607=m -CONFIG_PINCTRL_MSM8916=m -CONFIG_PINCTRL_MSM8917=m -CONFIG_PINCTRL_MSM8953=m -CONFIG_PINCTRL_MSM8976=m -CONFIG_PINCTRL_MSM8994=m -CONFIG_PINCTRL_MSM8996=m -CONFIG_PINCTRL_MSM8998=m -CONFIG_PINCTRL_NORD=y -CONFIG_PINCTRL_QCM2290=m -CONFIG_PINCTRL_QCS404=m -CONFIG_PINCTRL_QCS615=m -CONFIG_PINCTRL_QCS8300=m -CONFIG_PINCTRL_QDF2XXX=m -CONFIG_PINCTRL_QDU1000=m -CONFIG_PINCTRL_SA8775P=y -CONFIG_PINCTRL_SAR2130P=m -CONFIG_PINCTRL_SC7180=y -CONFIG_PINCTRL_SC7280=y -CONFIG_PINCTRL_SC8180X=y -CONFIG_PINCTRL_SC8280XP=y -CONFIG_PINCTRL_SDM660=m -CONFIG_PINCTRL_SDM670=m -CONFIG_PINCTRL_SDM845=m -CONFIG_PINCTRL_SDX75=m -CONFIG_PINCTRL_SHIKRA=y -CONFIG_PINCTRL_SM4450=m -CONFIG_PINCTRL_SM6115=m -CONFIG_PINCTRL_SM6125=m -CONFIG_PINCTRL_SM6350=m -CONFIG_PINCTRL_SM6375=m -CONFIG_PINCTRL_SM7150=m -CONFIG_PINCTRL_MILOS=m -CONFIG_PINCTRL_SM8150=m -CONFIG_PINCTRL_SM8250=m -CONFIG_PINCTRL_SM8350=m -CONFIG_PINCTRL_SM8450=m -CONFIG_PINCTRL_SM8550=m -CONFIG_PINCTRL_SM8650=m -CONFIG_PINCTRL_SM8750=m -CONFIG_PINCTRL_X1E80100=m -CONFIG_PINCTRL_QCOM_SPMI_PMIC=m -CONFIG_PINCTRL_QCOM_SSBI_PMIC=m -CONFIG_PINCTRL_LPASS_LPI=m -# CONFIG_PINCTRL_MILOS_LPASS_LPI is not set -CONFIG_PINCTRL_SC7280_LPASS_LPI=m -CONFIG_PINCTRL_SDM660_LPASS_LPI=m -CONFIG_PINCTRL_SM4250_LPASS_LPI=m -# CONFIG_PINCTRL_SDM670_LPASS_LPI is not set -CONFIG_PINCTRL_SM6115_LPASS_LPI=m -# CONFIG_PINCTRL_SM6350_LPASS_LPI is not set -CONFIG_PINCTRL_SM8250_LPASS_LPI=m -CONFIG_PINCTRL_SM8450_LPASS_LPI=m -CONFIG_PINCTRL_SC8280XP_LPASS_LPI=m -CONFIG_PINCTRL_SM8550_LPASS_LPI=m -CONFIG_PINCTRL_SM8650_LPASS_LPI=m -CONFIG_PINCTRL_RTD=m -CONFIG_PINCTRL_RTD1619B=m -CONFIG_PINCTRL_RTD1319D=m -CONFIG_PINCTRL_RTD1315E=m -CONFIG_PINCTRL_RTD1625=m - -# -# Renesas pinctrl drivers -# -CONFIG_PINCTRL_RENESAS=y -CONFIG_PINCTRL_SH_PFC=y -CONFIG_PINCTRL_PFC_R8A774A1=y -CONFIG_PINCTRL_PFC_R8A774B1=y -CONFIG_PINCTRL_PFC_R8A774C0=y -CONFIG_PINCTRL_PFC_R8A774E1=y -CONFIG_PINCTRL_PFC_R8A77951=y -CONFIG_PINCTRL_PFC_R8A77960=y -CONFIG_PINCTRL_PFC_R8A77961=y -CONFIG_PINCTRL_PFC_R8A77965=y -CONFIG_PINCTRL_PFC_R8A77970=y -CONFIG_PINCTRL_PFC_R8A77980=y -CONFIG_PINCTRL_PFC_R8A77990=y -CONFIG_PINCTRL_PFC_R8A77995=y -CONFIG_PINCTRL_PFC_R8A779A0=y -CONFIG_PINCTRL_PFC_R8A779F0=y -CONFIG_PINCTRL_PFC_R8A779G0=y -CONFIG_PINCTRL_PFC_R8A779H0=y -CONFIG_PINCTRL_RZG2L=y -CONFIG_PINCTRL_RZT2H=y -CONFIG_PINCTRL_RZV2M=y -# end of Renesas pinctrl drivers - -CONFIG_PINCTRL_SOPHGO_COMMON=m -CONFIG_PINCTRL_SOPHGO_CV18XX_OPS=y -CONFIG_PINCTRL_SOPHGO_CV1800B=m -CONFIG_PINCTRL_SOPHGO_CV1812H=m -CONFIG_PINCTRL_SOPHGO_SG2000=m -CONFIG_PINCTRL_SOPHGO_SG2002=m -CONFIG_PINCTRL_SOPHGO_SG2042_OPS=y -CONFIG_PINCTRL_SOPHGO_SG2042=m -CONFIG_PINCTRL_SOPHGO_SG2044=m -CONFIG_PINCTRL_SPRD=y -CONFIG_PINCTRL_SPRD_SC9860=y -CONFIG_PINCTRL_STM32=y -CONFIG_PINCTRL_STM32MP257=y -CONFIG_PINCTRL_STM32_HDP=y -CONFIG_PINCTRL_SUNXI=y -CONFIG_PINCTRL_SUN4I_A10=y -CONFIG_PINCTRL_SUN5I=y -CONFIG_PINCTRL_SUN6I_A31=y -CONFIG_PINCTRL_SUN6I_A31_R=y -CONFIG_PINCTRL_SUN8I_A23=y -CONFIG_PINCTRL_SUN8I_A33=y -CONFIG_PINCTRL_SUN8I_A83T=y -CONFIG_PINCTRL_SUN8I_A83T_R=y -CONFIG_PINCTRL_SUN8I_A23_R=y -CONFIG_PINCTRL_SUN8I_H3=y -CONFIG_PINCTRL_SUN8I_H3_R=y -CONFIG_PINCTRL_SUN8I_V3S=y -CONFIG_PINCTRL_SUN9I_A80=y -CONFIG_PINCTRL_SUN9I_A80_R=y -CONFIG_PINCTRL_SUN20I_D1=y -CONFIG_PINCTRL_SUN50I_A64=y -CONFIG_PINCTRL_SUN50I_A64_R=y -CONFIG_PINCTRL_SUN50I_A100=y -CONFIG_PINCTRL_SUN50I_A100_R=y -CONFIG_PINCTRL_SUN50I_H5=y -CONFIG_PINCTRL_SUN50I_H6=y -CONFIG_PINCTRL_SUN50I_H6_R=y -CONFIG_PINCTRL_SUN50I_H616=y -CONFIG_PINCTRL_SUN50I_H616_R=y -CONFIG_PINCTRL_SUN55I_A523=y -CONFIG_PINCTRL_SUN55I_A523_R=y -CONFIG_PINCTRL_TEGRA=y -CONFIG_PINCTRL_TEGRA124=y -CONFIG_PINCTRL_TEGRA210=y -CONFIG_PINCTRL_TEGRA186=y -CONFIG_PINCTRL_TEGRA194=y -CONFIG_PINCTRL_TEGRA234=y -CONFIG_PINCTRL_TEGRA238=m -CONFIG_PINCTRL_TEGRA264=m -CONFIG_PINCTRL_TEGRA_XUSB=y -CONFIG_PINCTRL_VISCONTI=y -CONFIG_PINCTRL_TMPV7700=y -CONFIG_GPIOLIB_LEGACY=y -CONFIG_HAVE_SHARED_GPIOS=y -CONFIG_GPIOLIB=y -CONFIG_GPIOLIB_FASTPATH_LIMIT=512 -CONFIG_OF_GPIO=y -CONFIG_GPIO_ACPI=y -CONFIG_GPIOLIB_IRQCHIP=y -CONFIG_GPIO_SHARED=y -# CONFIG_DEBUG_GPIO is not set -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_SYSFS_LEGACY=y -CONFIG_GPIO_CDEV=y -CONFIG_GPIO_CDEV_V1=y -CONFIG_GPIO_GENERIC=y -CONFIG_GPIO_REGMAP=m -CONFIG_GPIO_SWNODE_UNDEFINED=y -CONFIG_GPIO_MAX730X=m -CONFIG_GPIO_IDIO_16=m - -# -# Memory mapped GPIO drivers -# -CONFIG_GPIO_74XX_MMIO=m -CONFIG_GPIO_ALTERA=m -CONFIG_GPIO_AMDPT=m -CONFIG_GPIO_BLZP1600=m -# CONFIG_GPIO_BY_PINCTRL is not set -CONFIG_GPIO_CADENCE=m -CONFIG_GPIO_DAVINCI=y -CONFIG_GPIO_DWAPB=m -CONFIG_GPIO_EIC_SPRD=m -CONFIG_GPIO_EN7523=m -CONFIG_GPIO_EXAR=m -CONFIG_GPIO_FTGPIO010=y -CONFIG_GPIO_GENERIC_PLATFORM=y -CONFIG_GPIO_GRGPIO=m -CONFIG_GPIO_HISI=m -CONFIG_GPIO_HLWD=m -CONFIG_GPIO_IMX_SCU=y -CONFIG_GPIO_LOGICVC=m -CONFIG_GPIO_MB86S7X=m -CONFIG_GPIO_MENZ127=m -CONFIG_GPIO_MPC8XXX=y -CONFIG_GPIO_MVEBU=y -CONFIG_GPIO_MXC=y -CONFIG_GPIO_NPCM_SGPIO=y -CONFIG_GPIO_PL061=y -CONFIG_GPIO_POLARFIRE_SOC=y -CONFIG_GPIO_PXA=y -CONFIG_GPIO_RCAR=m -CONFIG_GPIO_ROCKCHIP=m -CONFIG_GPIO_RTD=m -CONFIG_GPIO_SIFIVE=y -CONFIG_GPIO_SIOX=m -CONFIG_GPIO_SPRD=m -CONFIG_GPIO_SYSCON=m -CONFIG_GPIO_TEGRA=y -CONFIG_GPIO_TEGRA186=y -CONFIG_GPIO_THUNDERX=m -CONFIG_GPIO_VF610=y -CONFIG_GPIO_VISCONTI=m -# CONFIG_GPIO_WAVESHARE_DSI_TOUCH is not set -CONFIG_GPIO_WCD934X=m -CONFIG_GPIO_XGENE=y -CONFIG_GPIO_XGENE_SB=m -CONFIG_GPIO_XILINX=y -CONFIG_GPIO_XLP=m -CONFIG_GPIO_ZYNQ=m -CONFIG_GPIO_ZYNQMP_MODEPIN=m -CONFIG_GPIO_AMD_FCH=m -# end of Memory mapped GPIO drivers - -# -# I2C GPIO expanders -# -CONFIG_GPIO_ADNP=m -CONFIG_GPIO_FXL6408=m -CONFIG_GPIO_DS4520=m -CONFIG_GPIO_GW_PLD=m -CONFIG_GPIO_MAX7300=m -CONFIG_GPIO_MAX732X=m -CONFIG_GPIO_PCA953X=m -CONFIG_GPIO_PCA953X_IRQ=y -CONFIG_GPIO_PCA9570=m -CONFIG_GPIO_PCF857X=m -CONFIG_GPIO_TPIC2810=m -# end of I2C GPIO expanders - -# -# MFD GPIO expanders -# -CONFIG_GPIO_ADP5520=m -CONFIG_GPIO_ADP5585=m -CONFIG_GPIO_ALTERA_A10SR=m -CONFIG_GPIO_ARIZONA=m -CONFIG_GPIO_BD71815=m -CONFIG_GPIO_BD71828=m -CONFIG_GPIO_BD72720=m -CONFIG_GPIO_BD9571MWV=m -CONFIG_GPIO_CROS_EC=m -CONFIG_GPIO_DA9052=m -CONFIG_GPIO_DA9055=m -CONFIG_GPIO_DLN2=m -CONFIG_GPIO_JANZ_TTL=m -CONFIG_GPIO_KEMPLD=m -CONFIG_GPIO_LJCA=m -CONFIG_GPIO_LP3943=m -CONFIG_GPIO_LP873X=m -CONFIG_GPIO_LP87565=m -CONFIG_GPIO_MACSMC=m -CONFIG_GPIO_MADERA=m -CONFIG_GPIO_MAX7360=m -CONFIG_GPIO_MAX77620=m -CONFIG_GPIO_MAX77650=m -CONFIG_GPIO_MAX77759=m -CONFIG_GPIO_NCT6694=m -CONFIG_GPIO_PALMAS=y -CONFIG_GPIO_PMIC_EIC_SPRD=m -CONFIG_GPIO_QIXIS_FPGA=m -CONFIG_GPIO_RC5T583=y -CONFIG_GPIO_SL28CPLD=m -CONFIG_GPIO_STMPE=y -CONFIG_GPIO_TC3589X=y -CONFIG_GPIO_TN48M_CPLD=m -CONFIG_GPIO_TPS65086=m -CONFIG_GPIO_TPS65218=m -CONFIG_GPIO_TPS65219=m -CONFIG_GPIO_TPS6586X=y -CONFIG_GPIO_TPS65910=y -CONFIG_GPIO_TPS65912=m -CONFIG_GPIO_TQMX86=m -CONFIG_GPIO_TWL4030=m -CONFIG_GPIO_TWL6040=m -CONFIG_GPIO_WM831X=m -CONFIG_GPIO_WM8350=m -CONFIG_GPIO_WM8994=m -# end of MFD GPIO expanders - -# -# Auxiliary Bus GPIO drivers -# -# end of Auxiliary Bus GPIO drivers - -# -# PCI GPIO expanders -# -CONFIG_GPIO_MLXBF=m -CONFIG_GPIO_MLXBF2=m -CONFIG_GPIO_MLXBF3=m -CONFIG_GPIO_PCI_IDIO_16=m -CONFIG_GPIO_PCIE_IDIO_24=m -CONFIG_GPIO_RDC321X=m -# end of PCI GPIO expanders - -# -# SPI GPIO expanders -# -CONFIG_GPIO_74X164=m -CONFIG_GPIO_MAX3191X=m -CONFIG_GPIO_MAX7301=m -CONFIG_GPIO_MC33880=m -CONFIG_GPIO_PISOSR=m -CONFIG_GPIO_XRA1403=m -CONFIG_GPIO_MOXTET=m -# end of SPI GPIO expanders - -# -# USB GPIO expanders -# -CONFIG_GPIO_VIPERBOARD=m -CONFIG_GPIO_MPSSE=m -# end of USB GPIO expanders - -# -# Virtual GPIO drivers -# -CONFIG_GPIO_AGGREGATOR=m -CONFIG_GPIO_LATCH=m -CONFIG_GPIO_LINE_MUX=m -# CONFIG_GPIO_MOCKUP is not set -CONFIG_GPIO_VIRTIO=m -CONFIG_GPIO_SIM=m -CONFIG_GPIO_SHARED_PROXY=m -# end of Virtual GPIO drivers - -# -# GPIO Debugging utilities -# -CONFIG_GPIO_SLOPPY_LOGIC_ANALYZER=m -CONFIG_GPIO_VIRTUSER=m -# end of GPIO Debugging utilities - -CONFIG_W1=m -CONFIG_W1_CON=y - -# -# 1-wire Bus Masters -# -CONFIG_W1_MASTER_AMD_AXI=m -CONFIG_W1_MASTER_MATROX=m -CONFIG_W1_MASTER_DS2490=m -CONFIG_W1_MASTER_DS2482=m -CONFIG_W1_MASTER_MXC=m -CONFIG_W1_MASTER_GPIO=m -CONFIG_W1_MASTER_SGI=m -CONFIG_W1_MASTER_UART=m -# end of 1-wire Bus Masters - -# -# 1-wire Slaves -# -CONFIG_W1_SLAVE_THERM=m -CONFIG_W1_SLAVE_SMEM=m -CONFIG_W1_SLAVE_DS2405=m -CONFIG_W1_SLAVE_DS2408=m -CONFIG_W1_SLAVE_DS2408_READBACK=y -CONFIG_W1_SLAVE_DS2413=m -CONFIG_W1_SLAVE_DS2406=m -CONFIG_W1_SLAVE_DS2423=m -CONFIG_W1_SLAVE_DS2805=m -CONFIG_W1_SLAVE_DS2430=m -CONFIG_W1_SLAVE_DS2431=m -CONFIG_W1_SLAVE_DS2433=m -# CONFIG_W1_SLAVE_DS2433_CRC is not set -CONFIG_W1_SLAVE_DS2438=m -CONFIG_W1_SLAVE_DS250X=m -CONFIG_W1_SLAVE_DS2780=m -CONFIG_W1_SLAVE_DS2781=m -CONFIG_W1_SLAVE_DS28E04=m -CONFIG_W1_SLAVE_DS28E17=m -# end of 1-wire Slaves - -CONFIG_POWER_RESET=y -CONFIG_POWER_RESET_AS3722=y -CONFIG_POWER_RESET_ATC260X=m -CONFIG_POWER_RESET_GPIO=y -CONFIG_POWER_RESET_GPIO_RESTART=y -CONFIG_POWER_RESET_HISI=y -CONFIG_POWER_RESET_LINKSTATION=m -CONFIG_POWER_RESET_MACSMC=m -CONFIG_POWER_RESET_MSM=y -CONFIG_POWER_RESET_QCOM_PON=m -CONFIG_POWER_RESET_OCELOT_RESET=y -CONFIG_POWER_RESET_ODROID_GO_ULTRA_POWEROFF=y -CONFIG_POWER_RESET_LTC2952=y -CONFIG_POWER_RESET_MT6323=y -CONFIG_POWER_RESET_REGULATOR=y -CONFIG_POWER_RESET_RESTART=y -CONFIG_POWER_RESET_TORADEX_EC=m -CONFIG_POWER_RESET_TPS65086=y -CONFIG_POWER_RESET_VEXPRESS=y -# CONFIG_POWER_RESET_XGENE is not set -CONFIG_POWER_RESET_SYSCON=y -CONFIG_POWER_RESET_SYSCON_POWEROFF=y -CONFIG_REBOOT_MODE=m -CONFIG_SYSCON_REBOOT_MODE=m -CONFIG_POWER_RESET_SC27XX=m -CONFIG_NVMEM_REBOOT_MODE=m -CONFIG_POWER_MLXBF=m -# CONFIG_POWER_RESET_QEMU_VIRT_CTRL is not set -CONFIG_POWER_SEQUENCING=y -CONFIG_POWER_SEQUENCING_QCOM_WCN=m -CONFIG_POWER_SEQUENCING_PCIE_M2=m -CONFIG_POWER_SUPPLY=y -# CONFIG_POWER_SUPPLY_DEBUG is not set -CONFIG_POWER_SUPPLY_HWMON=y -CONFIG_ADC_BATTERY_HELPER=m -CONFIG_GENERIC_ADC_BATTERY=m -CONFIG_IP5XXX_POWER=m -CONFIG_MAX8925_POWER=m -CONFIG_WM831X_BACKUP=m -CONFIG_WM831X_POWER=m -CONFIG_WM8350_POWER=m -CONFIG_TEST_POWER=m -CONFIG_BATTERY_88PM860X=m -CONFIG_CHARGER_ADP5061=m -CONFIG_BATTERY_ACT8945A=m -CONFIG_BATTERY_CHAGALL=m -CONFIG_BATTERY_CPCAP=m -CONFIG_BATTERY_CW2015=m -CONFIG_BATTERY_DS2760=m -CONFIG_BATTERY_DS2780=m -CONFIG_BATTERY_DS2781=m -CONFIG_BATTERY_DS2782=m -CONFIG_BATTERY_HUAWEI_GAOKUN=m -CONFIG_BATTERY_LENOVO_YOGA_C630=m -CONFIG_BATTERY_QCOM_BATTMGR=m -CONFIG_BATTERY_OLPC=m -CONFIG_BATTERY_SAMSUNG_SDI=y -# CONFIG_BATTERY_S2MU005 is not set -CONFIG_BATTERY_SBS=m -CONFIG_CHARGER_SBS=m -CONFIG_MANAGER_SBS=m -CONFIG_BATTERY_BQ27XXX=m -CONFIG_BATTERY_BQ27XXX_I2C=m -CONFIG_BATTERY_BQ27XXX_HDQ=m -# CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM is not set -CONFIG_BATTERY_DA9030=m -CONFIG_BATTERY_DA9052=m -CONFIG_CHARGER_DA9150=m -CONFIG_BATTERY_DA9150=m -CONFIG_CHARGER_AXP20X=m -CONFIG_BATTERY_AXP20X=m -CONFIG_AXP20X_POWER=m -CONFIG_BATTERY_MAX17040=m -CONFIG_BATTERY_MAX17042=m -CONFIG_BATTERY_MAX1720X=m -CONFIG_BATTERY_MAX1721X=m -CONFIG_BATTERY_TWL4030_MADC=m -CONFIG_CHARGER_88PM860X=m -CONFIG_CHARGER_PF1550=m -CONFIG_BATTERY_RX51=m -CONFIG_CHARGER_CPCAP=m -CONFIG_CHARGER_ISP1704=m -CONFIG_CHARGER_MAX8903=m -CONFIG_CHARGER_TWL4030=m -CONFIG_CHARGER_TWL6030=m -CONFIG_CHARGER_LP8727=m -CONFIG_CHARGER_LP8788=m -CONFIG_CHARGER_GPIO=m -CONFIG_CHARGER_MANAGER=y -CONFIG_CHARGER_LT3651=m -CONFIG_CHARGER_LTC4162L=m -CONFIG_CHARGER_MAX14577=m -CONFIG_CHARGER_DETECTOR_MAX14656=m -CONFIG_CHARGER_MAX77650=m -CONFIG_CHARGER_MAX77693=m -CONFIG_CHARGER_MAX77705=m -CONFIG_CHARGER_MAX77759=m -CONFIG_CHARGER_MAX77976=m -CONFIG_CHARGER_MAX8971=m -CONFIG_CHARGER_MAX8997=m -CONFIG_CHARGER_MAX8998=m -CONFIG_CHARGER_MP2629=m -CONFIG_CHARGER_MT6360=m -CONFIG_CHARGER_MT6370=m -CONFIG_CHARGER_QCOM_SMBB=m -CONFIG_BATTERY_PM8916_BMS_VM=m -CONFIG_CHARGER_PM8916_LBC=m -CONFIG_CHARGER_BQ2415X=m -CONFIG_CHARGER_BQ24190=m -CONFIG_CHARGER_BQ24257=m -CONFIG_CHARGER_BQ24735=m -CONFIG_CHARGER_BQ2515X=m -CONFIG_CHARGER_BQ257XX=m -CONFIG_CHARGER_BQ25890=m -CONFIG_CHARGER_BQ25980=m -CONFIG_CHARGER_BQ256XX=m -CONFIG_CHARGER_RK817=m -CONFIG_CHARGER_SMB347=m -CONFIG_CHARGER_TPS65090=m -CONFIG_CHARGER_TPS65217=m -CONFIG_BATTERY_GAUGE_LTC2941=m -CONFIG_BATTERY_GOLDFISH=m -CONFIG_BATTERY_RT5033=m -CONFIG_CHARGER_RT5033=m -CONFIG_CHARGER_RT9455=m -CONFIG_CHARGER_RT9467=m -CONFIG_CHARGER_RT9471=m -CONFIG_CHARGER_RT9756=m -CONFIG_CHARGER_CROS_USBPD=m -CONFIG_CHARGER_CROS_PCHG=m -CONFIG_CHARGER_CROS_CONTROL=m -CONFIG_CHARGER_SC2731=m -CONFIG_FUEL_GAUGE_SC27XX=m -CONFIG_FUEL_GAUGE_STC3117=m -CONFIG_CHARGER_UCS1002=m -CONFIG_CHARGER_BD71828=m -CONFIG_CHARGER_BD99954=m -CONFIG_RN5T618_POWER=m -CONFIG_BATTERY_SURFACE=m -CONFIG_CHARGER_SURFACE=m -CONFIG_BATTERY_UG3105=m -# CONFIG_BATTERY_CHARGER_SURFACE_RT is not set -CONFIG_CHARGER_QCOM_SMB2=m -CONFIG_FUEL_GAUGE_MM8013=m -# CONFIG_MACSMC_POWER is not set -CONFIG_HWMON=y -CONFIG_HWMON_VID=m -# CONFIG_HWMON_DEBUG_CHIP is not set - -# -# Native drivers -# -CONFIG_SENSORS_SMPRO=m -CONFIG_SENSORS_AD7314=m -CONFIG_SENSORS_AD7414=m -CONFIG_SENSORS_AD7418=m -CONFIG_SENSORS_ADM1025=m -CONFIG_SENSORS_ADM1026=m -CONFIG_SENSORS_ADM1029=m -CONFIG_SENSORS_ADM1031=m -CONFIG_SENSORS_ADM1177=m -CONFIG_SENSORS_ADM9240=m -CONFIG_SENSORS_ADT7X10=m -CONFIG_SENSORS_ADT7310=m -CONFIG_SENSORS_ADT7410=m -CONFIG_SENSORS_ADT7411=m -CONFIG_SENSORS_ADT7462=m -CONFIG_SENSORS_ADT7470=m -CONFIG_SENSORS_ADT7475=m -CONFIG_SENSORS_AHT10=m -CONFIG_SENSORS_AQUACOMPUTER_D5NEXT=m -CONFIG_SENSORS_AS370=m -CONFIG_SENSORS_ASC7621=m -CONFIG_SENSORS_ASUS_ROG_RYUJIN=m -CONFIG_SENSORS_AXI_FAN_CONTROL=m -# CONFIG_SENSORS_KB9002 is not set -CONFIG_SENSORS_KBATT=m -CONFIG_SENSORS_KFAN=m -# CONFIG_SENSORS_ARCTIC_FAN_CONTROLLER is not set -CONFIG_SENSORS_ARM_SCMI=m -CONFIG_SENSORS_ARM_SCPI=m -CONFIG_SENSORS_ATXP1=m -CONFIG_SENSORS_CHIPCAP2=m -CONFIG_SENSORS_CORSAIR_CPRO=m -CONFIG_SENSORS_CORSAIR_PSU=m -CONFIG_SENSORS_CROS_EC=m -CONFIG_SENSORS_DRIVETEMP=m -CONFIG_SENSORS_DS620=m -CONFIG_SENSORS_DS1621=m -CONFIG_SENSORS_DA9052_ADC=m -CONFIG_SENSORS_DA9055=m -CONFIG_SENSORS_I5K_AMB=m -CONFIG_SENSORS_SPARX5=m -CONFIG_SENSORS_F71805F=m -CONFIG_SENSORS_F71882FG=m -CONFIG_SENSORS_F75375S=m -CONFIG_SENSORS_GSC=m -CONFIG_SENSORS_MC13783_ADC=m -CONFIG_SENSORS_MC33XS2410=m -CONFIG_SENSORS_FTSTEUTATES=m -CONFIG_SENSORS_GIGABYTE_WATERFORCE=m -CONFIG_SENSORS_GL518SM=m -CONFIG_SENSORS_GL520SM=m -CONFIG_SENSORS_G760A=m -CONFIG_SENSORS_G762=m -CONFIG_SENSORS_GPIO_FAN=m -CONFIG_SENSORS_HIH6130=m -CONFIG_SENSORS_HS3001=m -CONFIG_SENSORS_HTU31=m -CONFIG_SENSORS_IBMAEM=m -CONFIG_SENSORS_IBMPEX=m -CONFIG_SENSORS_IIO_HWMON=m -CONFIG_SENSORS_ISL28022=m -CONFIG_SENSORS_IT87=m -CONFIG_SENSORS_JC42=m -# CONFIG_SENSORS_POLARFIRE_SOC_TVS is not set -CONFIG_SENSORS_POWERZ=m -CONFIG_SENSORS_POWR1220=m -# CONFIG_SENSORS_PROM21_XHCI is not set -CONFIG_SENSORS_LINEAGE=m -CONFIG_SENSORS_LOCHNAGAR=m -CONFIG_SENSORS_LTC2945=m -CONFIG_SENSORS_LTC2947=m -CONFIG_SENSORS_LTC2947_I2C=m -CONFIG_SENSORS_LTC2947_SPI=m -CONFIG_SENSORS_LTC2990=m -CONFIG_SENSORS_LTC2991=m -CONFIG_SENSORS_LTC2992=m -CONFIG_SENSORS_LTC4151=m -CONFIG_SENSORS_LTC4215=m -CONFIG_SENSORS_LTC4222=m -CONFIG_SENSORS_LTC4245=m -CONFIG_SENSORS_LTC4260=m -CONFIG_SENSORS_LTC4261=m -CONFIG_SENSORS_LTC4282=m -# CONFIG_SENSORS_LTC4283 is not set -CONFIG_SENSORS_MACSMC_HWMON=m -CONFIG_SENSORS_MAX1111=m -CONFIG_SENSORS_MAX127=m -CONFIG_SENSORS_MAX16065=m -CONFIG_SENSORS_MAX1619=m -CONFIG_SENSORS_MAX1668=m -CONFIG_SENSORS_MAX197=m -CONFIG_SENSORS_MAX31722=m -CONFIG_SENSORS_MAX31730=m -CONFIG_SENSORS_MAX31760=m -CONFIG_MAX31827=m -CONFIG_SENSORS_MAX6620=m -CONFIG_SENSORS_MAX6621=m -CONFIG_SENSORS_MAX6639=m -CONFIG_SENSORS_MAX6650=m -CONFIG_SENSORS_MAX6697=m -CONFIG_SENSORS_MAX31790=m -CONFIG_SENSORS_MAX77705=m -CONFIG_SENSORS_MC34VR500=m -CONFIG_SENSORS_MCP3021=m -# CONFIG_SENSORS_MCP9982 is not set -CONFIG_SENSORS_MLXREG_FAN=m -CONFIG_SENSORS_TC654=m -CONFIG_SENSORS_TPS23861=m -CONFIG_SENSORS_MENF21BMC_HWMON=m -CONFIG_SENSORS_MR75203=m -CONFIG_SENSORS_ADCXX=m -CONFIG_SENSORS_LM63=m -CONFIG_SENSORS_LM70=m -CONFIG_SENSORS_LM73=m -CONFIG_SENSORS_LM75=m -CONFIG_SENSORS_LM77=m -CONFIG_SENSORS_LM78=m -CONFIG_SENSORS_LM80=m -CONFIG_SENSORS_LM83=m -CONFIG_SENSORS_LM85=m -CONFIG_SENSORS_LM87=m -CONFIG_SENSORS_LM90=m -CONFIG_SENSORS_LM92=m -CONFIG_SENSORS_LM93=m -CONFIG_SENSORS_LM95234=m -CONFIG_SENSORS_LM95241=m -CONFIG_SENSORS_LM95245=m -CONFIG_SENSORS_PC87360=m -CONFIG_SENSORS_PC87427=m -CONFIG_SENSORS_NTC_THERMISTOR=m -CONFIG_SENSORS_NCT6683=m -CONFIG_SENSORS_NCT6694=m -CONFIG_SENSORS_NCT6775_CORE=m -CONFIG_SENSORS_NCT6775=m -CONFIG_SENSORS_NCT6775_I2C=m -CONFIG_SENSORS_NCT7363=m -CONFIG_SENSORS_NCT7802=m -CONFIG_SENSORS_NCT7904=m -CONFIG_SENSORS_NPCM7XX=m -CONFIG_SENSORS_NZXT_KRAKEN2=m -CONFIG_SENSORS_NZXT_KRAKEN3=m -CONFIG_SENSORS_NZXT_SMART2=m -# CONFIG_SENSORS_OCC_P8_I2C is not set -# CONFIG_SENSORS_OCC_P9_SBE is not set -CONFIG_SENSORS_PCF8591=m -CONFIG_SENSORS_PECI_CPUTEMP=m -CONFIG_SENSORS_PECI_DIMMTEMP=m -CONFIG_SENSORS_PECI=m -CONFIG_PMBUS=m -CONFIG_SENSORS_PMBUS=m -CONFIG_SENSORS_ACBEL_FSG032=m -CONFIG_SENSORS_ADM1266=m -CONFIG_SENSORS_ADM1275=m -CONFIG_SENSORS_ADP1050=m -CONFIG_SENSORS_ADP1050_REGULATOR=y -# CONFIG_SENSORS_APS_379 is not set -CONFIG_SENSORS_BEL_PFE=m -CONFIG_SENSORS_BPA_RS600=m -CONFIG_SENSORS_CRPS=m -# CONFIG_SENSORS_D1U74T is not set -CONFIG_SENSORS_DELTA_AHE50DC_FAN=m -CONFIG_SENSORS_FSP_3Y=m -CONFIG_SENSORS_HAC300S=m -CONFIG_SENSORS_IBM_CFFPS=m -CONFIG_SENSORS_DPS920AB=m -# CONFIG_SENSORS_E50SN12051 is not set -CONFIG_SENSORS_INA233=m -CONFIG_SENSORS_INSPUR_IPSPS=m -CONFIG_SENSORS_IR35221=m -CONFIG_SENSORS_IR36021=m -CONFIG_SENSORS_IR38064=m -CONFIG_SENSORS_IR38064_REGULATOR=y -CONFIG_SENSORS_IRPS5401=m -CONFIG_SENSORS_ISL68137=m -CONFIG_SENSORS_LM25066=m -CONFIG_SENSORS_LM25066_REGULATOR=y -CONFIG_SENSORS_LT3074=m -CONFIG_SENSORS_LT3074_REGULATOR=m -CONFIG_SENSORS_LT7182S=m -CONFIG_SENSORS_LTC2978=m -CONFIG_SENSORS_LTC2978_REGULATOR=y -CONFIG_SENSORS_LTC3815=m -CONFIG_SENSORS_LTC4286=y -# CONFIG_SENSORS_LX1308 is not set -CONFIG_SENSORS_MAX15301=m -CONFIG_SENSORS_MAX16064=m -CONFIG_SENSORS_MAX16601=m -CONFIG_SENSORS_MAX17616=m -CONFIG_SENSORS_MAX20730=m -CONFIG_SENSORS_MAX20751=m -# CONFIG_SENSORS_MAX20830 is not set -# CONFIG_SENSORS_MAX20860A is not set -CONFIG_SENSORS_MAX31785=m -CONFIG_SENSORS_MAX34440=m -CONFIG_SENSORS_MAX8688=m -CONFIG_SENSORS_MP2856=m -CONFIG_SENSORS_MP2869=m -CONFIG_SENSORS_MP2888=m -CONFIG_SENSORS_MP2891=m -CONFIG_SENSORS_MP2925=m -CONFIG_SENSORS_MP29502=m -CONFIG_SENSORS_MP2975=m -# CONFIG_SENSORS_MP2985 is not set -CONFIG_SENSORS_MP2993=m -CONFIG_SENSORS_MP2975_REGULATOR=y -CONFIG_SENSORS_MP5023=m -CONFIG_SENSORS_MP5920=m -CONFIG_SENSORS_MP5926=m -CONFIG_SENSORS_MP5990=m -CONFIG_SENSORS_MP9941=m -CONFIG_SENSORS_MP9945=m -CONFIG_SENSORS_MPQ7932_REGULATOR=y -CONFIG_SENSORS_MPQ7932=m -# CONFIG_SENSORS_MPQ82D00 is not set -CONFIG_SENSORS_MPQ8785=m -# CONFIG_SENSORS_MPQ8646 is not set -CONFIG_SENSORS_PIM4328=m -CONFIG_SENSORS_PLI1209BC=m -CONFIG_SENSORS_PLI1209BC_REGULATOR=y -CONFIG_SENSORS_PM6764TR=m -CONFIG_SENSORS_PXE1610=m -CONFIG_SENSORS_Q54SJ108A2=m -CONFIG_SENSORS_STEF48H28=m -# CONFIG_SENSORS_SQ24860 is not set -CONFIG_SENSORS_STPDDC60=m -CONFIG_SENSORS_TDA38640=m -CONFIG_SENSORS_TDA38640_REGULATOR=y -CONFIG_SENSORS_TPS25990=m -CONFIG_SENSORS_TPS25990_REGULATOR=y -CONFIG_SENSORS_TPS40422=m -CONFIG_SENSORS_TPS53679=m -CONFIG_SENSORS_TPS546D24=m -CONFIG_SENSORS_UCD9000=m -CONFIG_SENSORS_UCD9200=m -# CONFIG_SENSORS_VT7505 is not set -CONFIG_SENSORS_XDP710=m -# CONFIG_SENSORS_XDP720 is not set -CONFIG_SENSORS_XDPE152=m -# CONFIG_SENSORS_XDPE1A2G7B is not set -CONFIG_SENSORS_XDPE122=m -CONFIG_SENSORS_XDPE122_REGULATOR=y -CONFIG_SENSORS_ZL6100=m -CONFIG_SENSORS_PT5161L=m -CONFIG_SENSORS_PWM_FAN=m -CONFIG_SENSORS_QNAP_MCU_HWMON=m -CONFIG_SENSORS_SL28CPLD=m -CONFIG_SENSORS_SBTSI=m -CONFIG_SENSORS_SHT15=m -CONFIG_SENSORS_SHT21=m -CONFIG_SENSORS_SHT3x=m -CONFIG_SENSORS_SHT4x=m -CONFIG_SENSORS_SHTC1=m -CONFIG_SENSORS_SIS5595=m -CONFIG_SENSORS_SY7636A=m -CONFIG_SENSORS_DME1737=m -CONFIG_SENSORS_EMC1403=m -# CONFIG_SENSORS_EMC1812 is not set -CONFIG_SENSORS_EMC2103=m -CONFIG_SENSORS_EMC2305=m -CONFIG_SENSORS_EMC6W201=m -CONFIG_SENSORS_SMSC47M1=m -CONFIG_SENSORS_SMSC47M192=m -CONFIG_SENSORS_SMSC47B397=m -CONFIG_SENSORS_SCH56XX_COMMON=m -CONFIG_SENSORS_SCH5627=m -CONFIG_SENSORS_SCH5636=m -CONFIG_SENSORS_STTS751=m -CONFIG_SENSORS_SG2042_MCU=m -CONFIG_SENSORS_SURFACE_FAN=m -CONFIG_SENSORS_SURFACE_TEMP=m -CONFIG_SENSORS_ADC128D818=m -CONFIG_SENSORS_ADS7828=m -CONFIG_SENSORS_ADS7871=m -CONFIG_SENSORS_AMC6821=m -CONFIG_SENSORS_INA209=m -CONFIG_SENSORS_INA2XX=m -CONFIG_SENSORS_INA238=m -CONFIG_SENSORS_INA3221=m -CONFIG_SENSORS_SPD5118=m -CONFIG_SENSORS_SPD5118_DETECT=y -CONFIG_SENSORS_TC74=m -CONFIG_SENSORS_THMC50=m -CONFIG_SENSORS_TMP102=m -CONFIG_SENSORS_TMP103=m -CONFIG_SENSORS_TMP108=m -CONFIG_SENSORS_TMP401=m -CONFIG_SENSORS_TMP421=m -CONFIG_SENSORS_TMP464=m -CONFIG_SENSORS_TMP513=m -CONFIG_SENSORS_TSC1641=m -CONFIG_SENSORS_VEXPRESS=m -CONFIG_SENSORS_VIA686A=m -CONFIG_SENSORS_VT1211=m -CONFIG_SENSORS_VT8231=m -CONFIG_SENSORS_W83773G=m -CONFIG_SENSORS_W83781D=m -CONFIG_SENSORS_W83791D=m -CONFIG_SENSORS_W83792D=m -CONFIG_SENSORS_W83793=m -CONFIG_SENSORS_W83795=m -# CONFIG_SENSORS_W83795_FANCTRL is not set -CONFIG_SENSORS_W83L785TS=m -CONFIG_SENSORS_W83L786NG=m -CONFIG_SENSORS_W83627HF=m -CONFIG_SENSORS_W83627EHF=m -CONFIG_SENSORS_WM831X=m -CONFIG_SENSORS_WM8350=m -CONFIG_SENSORS_XGENE=m -# CONFIG_SENSORS_YOGAFAN is not set -CONFIG_SENSORS_INTEL_M10_BMC_HWMON=m - -# -# ACPI drivers -# -CONFIG_SENSORS_ACPI_POWER=m -CONFIG_THERMAL=y -CONFIG_THERMAL_NETLINK=y -CONFIG_THERMAL_STATISTICS=y -# CONFIG_THERMAL_DEBUGFS is not set -CONFIG_THERMAL_CORE_TESTING=m -CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 -CONFIG_THERMAL_HWMON=y -CONFIG_THERMAL_OF=y -CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y -# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set -# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set -# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set -# CONFIG_THERMAL_DEFAULT_GOV_BANG_BANG is not set -CONFIG_THERMAL_GOV_FAIR_SHARE=y -CONFIG_THERMAL_GOV_STEP_WISE=y -CONFIG_THERMAL_GOV_BANG_BANG=y -CONFIG_THERMAL_GOV_USER_SPACE=y -CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y -CONFIG_CPU_THERMAL=y -CONFIG_CPU_FREQ_THERMAL=y -CONFIG_CPU_IDLE_THERMAL=y -CONFIG_DEVFREQ_THERMAL=y -CONFIG_PCIE_THERMAL=y -CONFIG_THERMAL_EMULATION=y -CONFIG_THERMAL_MMIO=m -CONFIG_HISI_THERMAL=m -CONFIG_IMX_THERMAL=m -CONFIG_IMX_SC_THERMAL=m -CONFIG_IMX8MM_THERMAL=m -CONFIG_IMX91_THERMAL=m -CONFIG_K3_THERMAL=m -CONFIG_MAX77620_THERMAL=m -CONFIG_QORIQ_THERMAL=m -CONFIG_AIROHA_THERMAL=m -CONFIG_SUN8I_THERMAL=m -CONFIG_ROCKCHIP_THERMAL=m -CONFIG_ARMADA_THERMAL=y -CONFIG_DA9062_THERMAL=m - -# -# Mediatek thermal drivers -# -CONFIG_MTK_THERMAL=m -CONFIG_MTK_SOC_THERMAL=m -CONFIG_MTK_LVTS_THERMAL=m -CONFIG_MTK_LVTS_THERMAL_DEBUGFS=y -# end of Mediatek thermal drivers - -CONFIG_AMLOGIC_THERMAL=m - -# -# STMicroelectronics thermal drivers -# -CONFIG_ST_THERMAL=m -CONFIG_ST_THERMAL_MEMMAP=m -# end of STMicroelectronics thermal drivers - -CONFIG_RCAR_THERMAL=m -CONFIG_RCAR_GEN3_THERMAL=m -CONFIG_RZG2L_THERMAL=m -CONFIG_RZG3E_THERMAL=m -CONFIG_RZG3S_THERMAL=m - -# -# NVIDIA Tegra thermal drivers -# -# CONFIG_TEGRA_SOCTHERM is not set -CONFIG_TEGRA_BPMP_THERMAL=m -# end of NVIDIA Tegra thermal drivers - -CONFIG_GENERIC_ADC_THERMAL=m - -# -# Qualcomm thermal drivers -# -CONFIG_QCOM_TSENS=m -CONFIG_QCOM_SPMI_ADC_TM5=m -CONFIG_QCOM_SPMI_TEMP_ALARM=m -CONFIG_QCOM_LMH=m -# end of Qualcomm thermal drivers - -CONFIG_SPRD_THERMAL=m -CONFIG_KHADAS_MCU_FAN_THERMAL=m -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_CORE=y -# CONFIG_WATCHDOG_NOWAYOUT is not set -CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y -CONFIG_WATCHDOG_OPEN_TIMEOUT=0 -CONFIG_WATCHDOG_SYSFS=y -# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set - -# -# Watchdog Pretimeout Governors -# -CONFIG_WATCHDOG_PRETIMEOUT_GOV=y -CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m -CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP=y -CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=m -CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP=y -# CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC is not set - -# -# Watchdog Device Drivers -# -CONFIG_SOFT_WATCHDOG=m -CONFIG_SOFT_WATCHDOG_PRETIMEOUT=y -CONFIG_BD957XMUF_WATCHDOG=m -CONFIG_BD96801_WATCHDOG=m -CONFIG_CROS_EC_WATCHDOG=m -CONFIG_DA9052_WATCHDOG=m -CONFIG_DA9055_WATCHDOG=m -CONFIG_DA9063_WATCHDOG=m -CONFIG_DA9062_WATCHDOG=m -CONFIG_GPIO_WATCHDOG=m -CONFIG_MENF21BMC_WATCHDOG=m -CONFIG_MENZ069_WATCHDOG=m -CONFIG_WDAT_WDT=m -CONFIG_WM831X_WATCHDOG=m -CONFIG_WM8350_WATCHDOG=m -CONFIG_XILINX_WATCHDOG=m -CONFIG_XILINX_WINDOW_WATCHDOG=m -CONFIG_ZIIRAVE_WATCHDOG=m -CONFIG_RAVE_SP_WATCHDOG=m -CONFIG_MLX_WDT=m -CONFIG_SL28CPLD_WATCHDOG=m -CONFIG_AIROHA_WATCHDOG=m -CONFIG_ARM_SP805_WATCHDOG=m -CONFIG_ARM_SBSA_WATCHDOG=m -CONFIG_ARMADA_37XX_WATCHDOG=m -CONFIG_CADENCE_WATCHDOG=m -CONFIG_DW_WATCHDOG=m -CONFIG_K3_RTI_WATCHDOG=m -CONFIG_RN5T618_WATCHDOG=m -CONFIG_SUNXI_WATCHDOG=m -CONFIG_NPCM7XX_WATCHDOG=y -CONFIG_TWL4030_WATCHDOG=m -CONFIG_MAX63XX_WATCHDOG=m -CONFIG_MAX77620_WATCHDOG=m -CONFIG_NCT6694_WATCHDOG=m -CONFIG_IMX2_WDT=m -CONFIG_IMX_SC_WDT=m -CONFIG_IMX7ULP_WDT=m -CONFIG_S32G_WDT=m -CONFIG_RETU_WATCHDOG=m -CONFIG_TEGRA_WATCHDOG=m -CONFIG_QCOM_WDT=m -CONFIG_MESON_GXBB_WATCHDOG=m -CONFIG_MESON_WATCHDOG=m -CONFIG_MEDIATEK_WATCHDOG=m -CONFIG_ARM_SMC_WATCHDOG=m -CONFIG_RENESAS_WDT=m -CONFIG_RENESAS_WWDT=m -CONFIG_RENESAS_RZAWDT=m -CONFIG_RENESAS_RZN1WDT=m -CONFIG_RENESAS_RZG2LWDT=m -CONFIG_RENESAS_RZV2HWDT=m -CONFIG_STM32_WATCHDOG=m -CONFIG_STPMIC1_WATCHDOG=m -CONFIG_RTD119X_WATCHDOG=y -CONFIG_SPRD_WATCHDOG=m -CONFIG_PM8916_WATCHDOG=m -CONFIG_VISCONTI_WATCHDOG=m -CONFIG_APPLE_WATCHDOG=m -CONFIG_ALIM7101_WDT=m -CONFIG_I6300ESB_WDT=m -CONFIG_HP_WATCHDOG=m -CONFIG_KEMPLD_WDT=m -CONFIG_NIC7018_WDT=m -CONFIG_MARVELL_GTI_WDT=m -CONFIG_MEN_A21_WDT=m -CONFIG_XEN_WDT=m - -# -# PCI-based Watchdog Cards -# -CONFIG_PCIPCWATCHDOG=m -CONFIG_WDTPCI=m - -# -# USB-based Watchdog Cards -# -CONFIG_USBPCWATCHDOG=m -CONFIG_KEEMBAY_WATCHDOG=m -# CONFIG_GUNYAH_WATCHDOG is not set -CONFIG_SSB_POSSIBLE=y -CONFIG_SSB=m -CONFIG_SSB_SPROM=y -CONFIG_SSB_BLOCKIO=y -CONFIG_SSB_PCIHOST_POSSIBLE=y -CONFIG_SSB_PCIHOST=y -CONFIG_SSB_B43_PCI_BRIDGE=y -CONFIG_SSB_SDIOHOST_POSSIBLE=y -CONFIG_SSB_SDIOHOST=y -CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y -CONFIG_SSB_DRIVER_PCICORE=y -CONFIG_SSB_DRIVER_GPIO=y -CONFIG_BCMA_POSSIBLE=y -CONFIG_BCMA=m -CONFIG_BCMA_BLOCKIO=y -CONFIG_BCMA_HOST_PCI_POSSIBLE=y -CONFIG_BCMA_HOST_PCI=y -CONFIG_BCMA_HOST_SOC=y -CONFIG_BCMA_DRIVER_PCI=y -CONFIG_BCMA_SFLASH=y -CONFIG_BCMA_DRIVER_GMAC_CMN=y -CONFIG_BCMA_DRIVER_GPIO=y -# CONFIG_BCMA_DEBUG is not set - -# -# Multifunction device drivers -# -CONFIG_MFD_CORE=y -CONFIG_MFD_ADP5585=m -CONFIG_MFD_ALTERA_A10SR=y -CONFIG_MFD_ALTERA_SYSMGR=y -CONFIG_MFD_ACT8945A=m -CONFIG_MFD_SUN4I_GPADC=m -CONFIG_MFD_AS3711=y -CONFIG_MFD_SMPRO=m -CONFIG_MFD_AS3722=y -CONFIG_PMIC_ADP5520=y -CONFIG_MFD_AAT2870_CORE=y -CONFIG_MFD_AT91_USART=y -CONFIG_MFD_ATMEL_FLEXCOM=m -CONFIG_MFD_ATMEL_HLCDC=m -CONFIG_MFD_BCM590XX=m -CONFIG_MFD_BD9571MWV=m -# CONFIG_MFD_AC100 is not set -CONFIG_MFD_AXP20X=m -CONFIG_MFD_AXP20X_I2C=m -CONFIG_MFD_AXP20X_RSB=m -CONFIG_MFD_CROS_EC_DEV=m -CONFIG_MFD_CS40L50_CORE=m -CONFIG_MFD_CS40L50_I2C=m -CONFIG_MFD_CS40L50_SPI=m -CONFIG_MFD_CS42L43=m -CONFIG_MFD_CS42L43_I2C=m -CONFIG_MFD_CS42L43_SDW=m -CONFIG_MFD_LOCHNAGAR=y -CONFIG_MFD_MACSMC=m -CONFIG_MFD_MADERA=m -CONFIG_MFD_MADERA_I2C=m -CONFIG_MFD_MADERA_SPI=m -CONFIG_MFD_CS47L15=y -CONFIG_MFD_CS47L35=y -CONFIG_MFD_CS47L85=y -CONFIG_MFD_CS47L90=y -CONFIG_MFD_CS47L92=y -CONFIG_MFD_TN48M_CPLD=m -CONFIG_PMIC_DA903X=y -CONFIG_PMIC_DA9052=y -CONFIG_MFD_DA9052_SPI=y -CONFIG_MFD_DA9052_I2C=y -CONFIG_MFD_DA9055=y -CONFIG_MFD_DA9062=m -CONFIG_MFD_DA9063=y -CONFIG_MFD_DA9150=m -CONFIG_MFD_DLN2=m -CONFIG_MFD_GATEWORKS_GSC=m -CONFIG_MFD_MC13XXX=m -CONFIG_MFD_MC13XXX_SPI=m -CONFIG_MFD_MC13XXX_I2C=m -CONFIG_MFD_MP2629=m -CONFIG_MFD_PF1550=m -CONFIG_MFD_HI6421_PMIC=m -CONFIG_MFD_HI6421_SPMI=m -CONFIG_MFD_HI655X_PMIC=m -CONFIG_LPC_ICH=m -CONFIG_LPC_SCH=m -CONFIG_MFD_IQS62X=m -CONFIG_MFD_JANZ_CMODIO=m -CONFIG_MFD_KEMPLD=m -CONFIG_MFD_88PM800=m -CONFIG_MFD_88PM805=m -CONFIG_MFD_88PM860X=y -CONFIG_MFD_88PM886_PMIC=y -CONFIG_MFD_MAX5970=m -CONFIG_MFD_MAX14577=y -CONFIG_MFD_MAX77541=m -CONFIG_MFD_MAX77620=y -CONFIG_MFD_MAX77650=m -CONFIG_MFD_MAX77686=y -CONFIG_MFD_MAX77693=y -CONFIG_MFD_MAX77705=m -CONFIG_MFD_MAX77714=m -CONFIG_MFD_MAX77759=m -CONFIG_MFD_MAX77843=y -CONFIG_MFD_MAX8907=m -CONFIG_MFD_MAX8925=y -CONFIG_MFD_MAX8997=y -CONFIG_MFD_MAX8998=y -CONFIG_MFD_MT6360=m -CONFIG_MFD_MT6370=m -CONFIG_MFD_MT6397=m -CONFIG_MFD_MENF21BMC=m -CONFIG_MFD_NCT6694=m -CONFIG_MFD_OCELOT=m -CONFIG_MFD_CPCAP=m -CONFIG_MFD_VIPERBOARD=m -CONFIG_MFD_NTXEC=m -CONFIG_MFD_RETU=m -CONFIG_MFD_QCOM_RPM=m -CONFIG_MFD_SPMI_PMIC=m -CONFIG_MFD_SY7636A=m -CONFIG_MFD_RDC321X=m -CONFIG_MFD_RT4831=m -CONFIG_MFD_RT5033=m -CONFIG_MFD_RT5120=m -CONFIG_MFD_RC5T583=y -CONFIG_MFD_RK8XX=m -CONFIG_MFD_RK8XX_I2C=m -CONFIG_MFD_RK8XX_SPI=m -CONFIG_MFD_RN5T618=m -CONFIG_MFD_SEC_CORE=m -CONFIG_MFD_SEC_I2C=m -CONFIG_MFD_SI476X_CORE=m -CONFIG_MFD_SIMPLE_MFD_I2C=m -CONFIG_MFD_SL28CPLD=m -CONFIG_MFD_SM501=m -CONFIG_MFD_SM501_GPIO=y -CONFIG_MFD_SKY81452=m -CONFIG_MFD_SC27XX_PMIC=m -CONFIG_RZ_MTU3=y -CONFIG_MFD_STMPE=y - -# -# STMicroelectronics STMPE Interface Drivers -# -CONFIG_STMPE_I2C=y -CONFIG_STMPE_SPI=y -# end of STMicroelectronics STMPE Interface Drivers - -CONFIG_MFD_SUN6I_PRCM=y -CONFIG_MFD_SYSCON=y -CONFIG_MFD_TI_AM335X_TSCADC=m -CONFIG_MFD_LP3943=m -CONFIG_MFD_LP8788=y -CONFIG_MFD_TI_LMU=m -CONFIG_MFD_BQ257XX=m -CONFIG_MFD_PALMAS=y -CONFIG_TPS6105X=m -CONFIG_TPS65010=m -CONFIG_TPS6507X=m -CONFIG_MFD_TPS65086=m -CONFIG_MFD_TPS65090=y -CONFIG_MFD_TPS65217=m -CONFIG_MFD_TI_LP873X=m -CONFIG_MFD_TI_LP87565=m -CONFIG_MFD_TPS65218=m -CONFIG_MFD_TPS65219=m -CONFIG_MFD_TPS6586X=y -CONFIG_MFD_TPS65910=y -CONFIG_MFD_TPS65912=y -CONFIG_MFD_TPS65912_I2C=y -CONFIG_MFD_TPS65912_SPI=y -CONFIG_MFD_TPS6594=m -CONFIG_MFD_TPS6594_I2C=m -CONFIG_MFD_TPS6594_SPI=m -CONFIG_TWL4030_CORE=y -CONFIG_MFD_TWL4030_AUDIO=y -CONFIG_TWL6040_CORE=y -CONFIG_MFD_LM3533=m -CONFIG_MFD_TC3589X=y -CONFIG_MFD_TQMX86=m -CONFIG_MFD_VX855=m -CONFIG_MFD_ARIZONA=m -CONFIG_MFD_ARIZONA_I2C=m -CONFIG_MFD_ARIZONA_SPI=m -CONFIG_MFD_CS47L24=y -CONFIG_MFD_WM5102=y -CONFIG_MFD_WM5110=y -CONFIG_MFD_WM8997=y -CONFIG_MFD_WM8998=y -CONFIG_MFD_WM8400=y -CONFIG_MFD_WM831X=y -CONFIG_MFD_WM831X_I2C=y -CONFIG_MFD_WM831X_SPI=y -CONFIG_MFD_WM8350=y -CONFIG_MFD_WM8350_I2C=y -CONFIG_MFD_WM8994=m -CONFIG_MFD_ROHM_BD718XX=m -CONFIG_MFD_ROHM_BD71828=m -CONFIG_MFD_ROHM_BD957XMUF=m -CONFIG_MFD_ROHM_BD96801=m -CONFIG_MFD_STM32_LPTIMER=m -CONFIG_MFD_STM32_TIMERS=m -CONFIG_MFD_STPMIC1=m -CONFIG_MFD_STMFX=m -CONFIG_MFD_WCD934X=m -CONFIG_MFD_ATC260X=m -CONFIG_MFD_ATC260X_I2C=m -CONFIG_MFD_KHADAS_MCU=m -CONFIG_MFD_QCOM_PM8008=m -CONFIG_MFD_VEXPRESS_SYSREG=y -CONFIG_RAVE_SP_CORE=m -CONFIG_MFD_INTEL_M10_BMC_CORE=m -CONFIG_MFD_INTEL_M10_BMC_SPI=m -CONFIG_MFD_INTEL_M10_BMC_PMCI=m -CONFIG_MFD_LS2K_BMC_CORE=y -CONFIG_MFD_QNAP_MCU=m -CONFIG_MFD_RSMU_I2C=m -CONFIG_MFD_RSMU_SPI=m -CONFIG_MFD_MAX7360=m -# end of Multifunction device drivers - -CONFIG_REGULATOR=y -# CONFIG_REGULATOR_DEBUG is not set -CONFIG_REGULATOR_FIXED_VOLTAGE=m -CONFIG_REGULATOR_VIRTUAL_CONSUMER=m -CONFIG_REGULATOR_USERSPACE_CONSUMER=m -CONFIG_REGULATOR_NETLINK_EVENTS=y -CONFIG_REGULATOR_88PG86X=m -CONFIG_REGULATOR_88PM800=m -CONFIG_REGULATOR_88PM8607=m -CONFIG_REGULATOR_88PM886=m -CONFIG_REGULATOR_ACT8865=m -CONFIG_REGULATOR_ACT8945A=m -CONFIG_REGULATOR_AD5398=m -CONFIG_REGULATOR_ADP5055=m -CONFIG_REGULATOR_ANATOP=m -CONFIG_REGULATOR_AAT2870=m -CONFIG_REGULATOR_ARIZONA_LDO1=m -CONFIG_REGULATOR_ARIZONA_MICSUPP=m -CONFIG_REGULATOR_ARM_SCMI=y -CONFIG_REGULATOR_AS3711=m -CONFIG_REGULATOR_AS3722=m -CONFIG_REGULATOR_ATC260X=m -CONFIG_REGULATOR_AW37503=m -CONFIG_REGULATOR_AXP20X=m -CONFIG_REGULATOR_BCM590XX=m -CONFIG_REGULATOR_BD71815=m -CONFIG_REGULATOR_BD71828=m -CONFIG_REGULATOR_BD718XX=m -CONFIG_REGULATOR_BD9571MWV=m -CONFIG_REGULATOR_BD957XMUF=m -CONFIG_REGULATOR_BD96801=m -CONFIG_REGULATOR_BQ257XX=m -CONFIG_REGULATOR_CPCAP=m -CONFIG_REGULATOR_CROS_EC=m -CONFIG_REGULATOR_DA903X=m -CONFIG_REGULATOR_DA9052=m -CONFIG_REGULATOR_DA9055=m -CONFIG_REGULATOR_DA9062=m -CONFIG_REGULATOR_DA9063=m -CONFIG_REGULATOR_DA9121=m -CONFIG_REGULATOR_DA9210=m -CONFIG_REGULATOR_DA9211=m -CONFIG_REGULATOR_FAN53555=m -CONFIG_REGULATOR_FAN53880=m -CONFIG_REGULATOR_GPIO=m -CONFIG_REGULATOR_HI6421=m -CONFIG_REGULATOR_HI6421V530=m -CONFIG_REGULATOR_HI655X=m -CONFIG_REGULATOR_HI6421V600=m -CONFIG_REGULATOR_ISL9305=m -CONFIG_REGULATOR_ISL6271A=m -CONFIG_REGULATOR_FP9931=m -CONFIG_REGULATOR_LM363X=m -CONFIG_REGULATOR_LOCHNAGAR=m -CONFIG_REGULATOR_LP3971=m -CONFIG_REGULATOR_LP3972=m -CONFIG_REGULATOR_LP872X=m -CONFIG_REGULATOR_LP873X=m -CONFIG_REGULATOR_LP8755=m -CONFIG_REGULATOR_LP87565=m -CONFIG_REGULATOR_LP8788=m -CONFIG_REGULATOR_LTC3589=m -CONFIG_REGULATOR_LTC3676=m -CONFIG_REGULATOR_MAX14577=m -CONFIG_REGULATOR_MAX1586=m -CONFIG_REGULATOR_MAX5970=m -CONFIG_REGULATOR_MAX77503=m -CONFIG_REGULATOR_MAX77541=m -CONFIG_REGULATOR_MAX77620=m -CONFIG_REGULATOR_MAX77650=m -CONFIG_REGULATOR_MAX77675=m -CONFIG_REGULATOR_MAX77857=m -CONFIG_REGULATOR_MAX8649=m -CONFIG_REGULATOR_MAX8660=m -CONFIG_REGULATOR_MAX8893=m -CONFIG_REGULATOR_MAX8907=m -CONFIG_REGULATOR_MAX8925=m -CONFIG_REGULATOR_MAX8952=m -CONFIG_REGULATOR_MAX8973=m -CONFIG_REGULATOR_MAX8997=m -CONFIG_REGULATOR_MAX8998=m -CONFIG_REGULATOR_MAX20086=m -CONFIG_REGULATOR_MAX20411=m -CONFIG_REGULATOR_MAX77686=m -CONFIG_REGULATOR_MAX77693=m -CONFIG_REGULATOR_MAX77802=m -CONFIG_REGULATOR_MAX77826=m -CONFIG_REGULATOR_MAX77838=m -CONFIG_REGULATOR_MC13XXX_CORE=m -CONFIG_REGULATOR_MC13783=m -CONFIG_REGULATOR_MC13892=m -CONFIG_REGULATOR_MCP16502=m -CONFIG_REGULATOR_MP5416=m -CONFIG_REGULATOR_MP8859=m -CONFIG_REGULATOR_MP886X=m -CONFIG_REGULATOR_MPQ7920=m -CONFIG_REGULATOR_MT6311=m -CONFIG_REGULATOR_MT6315=m -CONFIG_REGULATOR_MT6316=m -CONFIG_REGULATOR_MT6323=m -CONFIG_REGULATOR_MT6331=m -CONFIG_REGULATOR_MT6332=m -CONFIG_REGULATOR_MT6357=m -CONFIG_REGULATOR_MT6358=m -CONFIG_REGULATOR_MT6359=m -CONFIG_REGULATOR_MT6360=m -CONFIG_REGULATOR_MT6363=m -CONFIG_REGULATOR_MT6370=m -CONFIG_REGULATOR_MT6380=m -CONFIG_REGULATOR_MT6397=m -CONFIG_REGULATOR_MTK_DVFSRC=m -CONFIG_REGULATOR_PALMAS=m -CONFIG_REGULATOR_PCA9450=m -CONFIG_REGULATOR_PF9453=m -CONFIG_REGULATOR_PF0900=m -CONFIG_REGULATOR_PF530X=m -CONFIG_REGULATOR_PF8X00=m -CONFIG_REGULATOR_PFUZE100=m -CONFIG_REGULATOR_PV88060=m -CONFIG_REGULATOR_PV88080=m -CONFIG_REGULATOR_PV88090=m -CONFIG_REGULATOR_PF1550=m -CONFIG_REGULATOR_PWM=m -CONFIG_REGULATOR_QCOM_PM8008=m -CONFIG_REGULATOR_QCOM_REFGEN=m -CONFIG_REGULATOR_QCOM_RPM=m -CONFIG_REGULATOR_QCOM_RPMH=m -CONFIG_REGULATOR_QCOM_SMD_RPM=m -CONFIG_REGULATOR_QCOM_SPMI=m -CONFIG_REGULATOR_QCOM_USB_VBUS=m -CONFIG_REGULATOR_RAA215300=m -CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m -CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_V2=m -CONFIG_REGULATOR_RC5T583=m -CONFIG_REGULATOR_RK808=m -CONFIG_REGULATOR_RN5T618=m -CONFIG_REGULATOR_ROHM=m -CONFIG_REGULATOR_RT4801=m -CONFIG_REGULATOR_RT4803=m -CONFIG_REGULATOR_RT4831=m -CONFIG_REGULATOR_RT5033=m -CONFIG_REGULATOR_RT5120=m -CONFIG_REGULATOR_RT5133=m -CONFIG_REGULATOR_RT5190A=m -CONFIG_REGULATOR_RT5739=m -CONFIG_REGULATOR_RT5759=m -CONFIG_REGULATOR_RT6160=m -CONFIG_REGULATOR_RT6190=m -CONFIG_REGULATOR_RT6245=m -CONFIG_REGULATOR_RT8092=m -CONFIG_REGULATOR_RTQ2134=m -CONFIG_REGULATOR_RTMV20=m -CONFIG_REGULATOR_RTQ6752=m -CONFIG_REGULATOR_RTQ2208=m -CONFIG_REGULATOR_S2DOS05=m -CONFIG_REGULATOR_S2MPA01=m -CONFIG_REGULATOR_S2MPS11=m -CONFIG_REGULATOR_S5M8767=m -CONFIG_REGULATOR_SC2731=m -# CONFIG_REGULATOR_SGM3804 is not set -CONFIG_REGULATOR_SKY81452=m -CONFIG_REGULATOR_SLG51000=m -CONFIG_REGULATOR_STM32_BOOSTER=m -CONFIG_REGULATOR_STM32_VREFBUF=m -CONFIG_REGULATOR_STM32_PWR=y -CONFIG_REGULATOR_STPMIC1=m -CONFIG_REGULATOR_SUN20I=m -CONFIG_REGULATOR_SY7636A=m -CONFIG_REGULATOR_SY8106A=m -CONFIG_REGULATOR_SY8824X=m -CONFIG_REGULATOR_SY8827N=m -CONFIG_REGULATOR_TPS51632=m -CONFIG_REGULATOR_TPS6105X=m -CONFIG_REGULATOR_TPS62360=m -CONFIG_REGULATOR_TPS6286X=m -CONFIG_REGULATOR_TPS6287X=m -CONFIG_REGULATOR_TPS65023=m -CONFIG_REGULATOR_TPS6507X=m -CONFIG_REGULATOR_TPS65086=m -CONFIG_REGULATOR_TPS65090=m -CONFIG_REGULATOR_TPS65132=m -CONFIG_REGULATOR_TPS65185=m -CONFIG_REGULATOR_TPS65217=m -CONFIG_REGULATOR_TPS65218=m -CONFIG_REGULATOR_TPS65219=m -CONFIG_REGULATOR_TPS6594=m -CONFIG_REGULATOR_TPS6524X=m -CONFIG_REGULATOR_TPS6586X=m -CONFIG_REGULATOR_TPS65910=m -CONFIG_REGULATOR_TPS65912=m -CONFIG_REGULATOR_TWL4030=m -CONFIG_REGULATOR_RZG2L_VBCTRL=y -CONFIG_REGULATOR_VCTRL=m -CONFIG_REGULATOR_VEXPRESS=m -CONFIG_REGULATOR_VQMMC_IPQ4019=m -CONFIG_REGULATOR_WM831X=m -CONFIG_REGULATOR_WM8350=m -CONFIG_REGULATOR_WM8400=m -CONFIG_REGULATOR_WM8994=m -CONFIG_REGULATOR_QCOM_LABIBB=m -CONFIG_RC_CORE=m -CONFIG_LIRC=y -CONFIG_RC_MAP=m -CONFIG_RC_DECODERS=y -CONFIG_IR_IMON_DECODER=m -CONFIG_IR_JVC_DECODER=m -CONFIG_IR_MCE_KBD_DECODER=m -CONFIG_IR_NEC_DECODER=m -CONFIG_IR_RC5_DECODER=m -CONFIG_IR_RC6_DECODER=m -CONFIG_IR_RCMM_DECODER=m -CONFIG_IR_SANYO_DECODER=m -CONFIG_IR_SHARP_DECODER=m -CONFIG_IR_SONY_DECODER=m -CONFIG_IR_XMP_DECODER=m -CONFIG_RC_DEVICES=y -CONFIG_IR_ENE=m -CONFIG_IR_FINTEK=m -CONFIG_IR_GPIO_CIR=m -CONFIG_IR_GPIO_TX=m -CONFIG_IR_HIX5HD2=m -CONFIG_IR_IGORPLUGUSB=m -CONFIG_IR_IGUANA=m -CONFIG_IR_IMON=m -CONFIG_IR_IMON_RAW=m -CONFIG_IR_ITE_CIR=m -CONFIG_IR_MCEUSB=m -CONFIG_IR_MESON=m -CONFIG_IR_MESON_TX=m -CONFIG_IR_MTK=m -CONFIG_IR_NUVOTON=m -CONFIG_IR_PWM_TX=m -CONFIG_IR_REDRAT3=m -CONFIG_IR_SERIAL=m -CONFIG_IR_SERIAL_TRANSMITTER=y -CONFIG_IR_SPI=m -CONFIG_IR_STREAMZAP=m -CONFIG_IR_SUNXI=m -CONFIG_IR_TOY=m -CONFIG_IR_TTUSBIR=m -CONFIG_RC_ATI_REMOTE=m -CONFIG_RC_LOOPBACK=m -CONFIG_RC_XBOX_DVD=m -CONFIG_CEC_CORE=m -CONFIG_CEC_NOTIFIER=y -CONFIG_CEC_PIN=y - -# -# CEC support -# -CONFIG_MEDIA_CEC_RC=y -# CONFIG_CEC_PIN_ERROR_INJ is not set -CONFIG_MEDIA_CEC_SUPPORT=y -CONFIG_CEC_CH7322=m -CONFIG_CEC_NXP_TDA9950=m -CONFIG_CEC_CROS_EC=m -CONFIG_CEC_MESON_AO=m -CONFIG_CEC_MESON_G12A_AO=m -CONFIG_CEC_GPIO=m -CONFIG_CEC_STM32=m -CONFIG_CEC_TEGRA=m -CONFIG_USB_EXTRON_DA_HD_4K_PLUS_CEC=m -CONFIG_USB_PULSE8_CEC=m -CONFIG_USB_RAINSHADOW_CEC=m -# end of CEC support - -CONFIG_MEDIA_SUPPORT=m -CONFIG_MEDIA_SUPPORT_FILTER=y -CONFIG_MEDIA_SUBDRV_AUTOSELECT=y - -# -# Media device types -# -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_ANALOG_TV_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_RADIO_SUPPORT=y -CONFIG_MEDIA_SDR_SUPPORT=y -CONFIG_MEDIA_PLATFORM_SUPPORT=y -CONFIG_MEDIA_TEST_SUPPORT=y -# end of Media device types - -CONFIG_VIDEO_DEV=m -CONFIG_MEDIA_CONTROLLER=y -CONFIG_DVB_CORE=m - -# -# Video4Linux options -# -CONFIG_VIDEO_V4L2_I2C=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -# CONFIG_VIDEO_ADV_DEBUG is not set -# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set -CONFIG_VIDEO_TUNER=m -CONFIG_V4L2_JPEG_HELPER=m -CONFIG_V4L2_H264=m -CONFIG_V4L2_VP9=m -CONFIG_V4L2_MEM2MEM_DEV=m -CONFIG_V4L2_FLASH_LED_CLASS=m -CONFIG_V4L2_FWNODE=m -CONFIG_V4L2_ASYNC=m -CONFIG_V4L2_CCI=m -CONFIG_V4L2_CCI_I2C=m -CONFIG_V4L2_ISP=m -# end of Video4Linux options - -# -# Media controller options -# -CONFIG_MEDIA_CONTROLLER_DVB=y -# end of Media controller options - -# -# Digital TV options -# -# CONFIG_DVB_MMAP is not set -CONFIG_DVB_NET=y -CONFIG_DVB_MAX_ADAPTERS=8 -CONFIG_DVB_DYNAMIC_MINORS=y -# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set -# CONFIG_DVB_ULE_DEBUG is not set -# end of Digital TV options - -# -# Media drivers -# - -# -# Drivers filtered as selected at 'Filter media drivers' -# - -# -# Media drivers -# -CONFIG_MEDIA_USB_SUPPORT=y - -# -# Webcam devices -# -CONFIG_USB_GSPCA=m -CONFIG_USB_GSPCA_BENQ=m -CONFIG_USB_GSPCA_CONEX=m -CONFIG_USB_GSPCA_CPIA1=m -CONFIG_USB_GSPCA_DTCS033=m -CONFIG_USB_GSPCA_ETOMS=m -CONFIG_USB_GSPCA_FINEPIX=m -CONFIG_USB_GSPCA_JEILINJ=m -CONFIG_USB_GSPCA_JL2005BCD=m -CONFIG_USB_GSPCA_KINECT=m -CONFIG_USB_GSPCA_KONICA=m -CONFIG_USB_GSPCA_MARS=m -CONFIG_USB_GSPCA_MR97310A=m -CONFIG_USB_GSPCA_NW80X=m -CONFIG_USB_GSPCA_OV519=m -CONFIG_USB_GSPCA_OV534=m -CONFIG_USB_GSPCA_OV534_9=m -CONFIG_USB_GSPCA_PAC207=m -CONFIG_USB_GSPCA_PAC7302=m -CONFIG_USB_GSPCA_PAC7311=m -CONFIG_USB_GSPCA_SE401=m -CONFIG_USB_GSPCA_SN9C2028=m -CONFIG_USB_GSPCA_SN9C20X=m -CONFIG_USB_GSPCA_SONIXB=m -CONFIG_USB_GSPCA_SONIXJ=m -CONFIG_USB_GSPCA_SPCA1528=m -CONFIG_USB_GSPCA_SPCA500=m -CONFIG_USB_GSPCA_SPCA501=m -CONFIG_USB_GSPCA_SPCA505=m -CONFIG_USB_GSPCA_SPCA506=m -CONFIG_USB_GSPCA_SPCA508=m -CONFIG_USB_GSPCA_SPCA561=m -CONFIG_USB_GSPCA_SQ905=m -CONFIG_USB_GSPCA_SQ905C=m -CONFIG_USB_GSPCA_SQ930X=m -CONFIG_USB_GSPCA_STK014=m -CONFIG_USB_GSPCA_STK1135=m -CONFIG_USB_GSPCA_STV0680=m -CONFIG_USB_GSPCA_SUNPLUS=m -CONFIG_USB_GSPCA_T613=m -CONFIG_USB_GSPCA_TOPRO=m -CONFIG_USB_GSPCA_TOUPTEK=m -CONFIG_USB_GSPCA_TV8532=m -CONFIG_USB_GSPCA_VC032X=m -CONFIG_USB_GSPCA_VICAM=m -CONFIG_USB_GSPCA_XIRLINK_CIT=m -CONFIG_USB_GSPCA_ZC3XX=m -CONFIG_USB_GL860=m -CONFIG_USB_M5602=m -CONFIG_USB_STV06XX=m -CONFIG_USB_PWC=m -# CONFIG_USB_PWC_DEBUG is not set -CONFIG_USB_PWC_INPUT_EVDEV=y -CONFIG_USB_S2255=m -CONFIG_VIDEO_USBTV=m -CONFIG_USB_VIDEO_CLASS=m -CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y - -# -# Analog TV USB devices -# -CONFIG_VIDEO_GO7007=m -CONFIG_VIDEO_GO7007_USB=m -CONFIG_VIDEO_GO7007_LOADER=m -CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m -CONFIG_VIDEO_HDPVR=m -CONFIG_VIDEO_PVRUSB2=m -CONFIG_VIDEO_PVRUSB2_SYSFS=y -CONFIG_VIDEO_PVRUSB2_DVB=y -# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set -CONFIG_VIDEO_STK1160=m - -# -# Analog/digital TV USB devices -# -CONFIG_VIDEO_AU0828=m -CONFIG_VIDEO_AU0828_V4L2=y -CONFIG_VIDEO_AU0828_RC=y -CONFIG_VIDEO_CX231XX=m -CONFIG_VIDEO_CX231XX_RC=y -CONFIG_VIDEO_CX231XX_ALSA=m -CONFIG_VIDEO_CX231XX_DVB=m - -# -# Digital TV USB devices -# -CONFIG_DVB_AS102=m -CONFIG_DVB_B2C2_FLEXCOP_USB=m -# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set -CONFIG_DVB_USB_V2=m -CONFIG_DVB_USB_AF9015=m -CONFIG_DVB_USB_AF9035=m -CONFIG_DVB_USB_ANYSEE=m -CONFIG_DVB_USB_AU6610=m -CONFIG_DVB_USB_AZ6007=m -CONFIG_DVB_USB_CE6230=m -CONFIG_DVB_USB_DVBSKY=m -CONFIG_DVB_USB_EC168=m -CONFIG_DVB_USB_GL861=m -CONFIG_DVB_USB_LME2510=m -CONFIG_DVB_USB_MXL111SF=m -CONFIG_DVB_USB_RTL28XXU=m -CONFIG_DVB_USB_ZD1301=m -CONFIG_DVB_USB=m -# CONFIG_DVB_USB_DEBUG is not set -CONFIG_DVB_USB_A800=m -CONFIG_DVB_USB_AF9005=m -CONFIG_DVB_USB_AF9005_REMOTE=m -CONFIG_DVB_USB_AZ6027=m -CONFIG_DVB_USB_CINERGY_T2=m -CONFIG_DVB_USB_CXUSB=m -CONFIG_DVB_USB_CXUSB_ANALOG=y -CONFIG_DVB_USB_DIB0700=m -CONFIG_DVB_USB_DIB3000MC=m -CONFIG_DVB_USB_DIBUSB_MB=m -# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set -CONFIG_DVB_USB_DIBUSB_MC=m -CONFIG_DVB_USB_DIGITV=m -CONFIG_DVB_USB_DTT200U=m -CONFIG_DVB_USB_DTV5100=m -CONFIG_DVB_USB_DW2102=m -CONFIG_DVB_USB_GP8PSK=m -CONFIG_DVB_USB_M920X=m -CONFIG_DVB_USB_NOVA_T_USB2=m -CONFIG_DVB_USB_OPERA1=m -CONFIG_DVB_USB_PCTV452E=m -CONFIG_DVB_USB_TECHNISAT_USB2=m -CONFIG_DVB_USB_TTUSB2=m -CONFIG_DVB_USB_UMT_010=m -CONFIG_DVB_USB_VP702X=m -CONFIG_DVB_USB_VP7045=m -CONFIG_SMS_USB_DRV=m -CONFIG_DVB_TTUSB_BUDGET=m -CONFIG_DVB_TTUSB_DEC=m - -# -# Webcam, TV (analog/digital) USB devices -# -CONFIG_VIDEO_EM28XX=m -CONFIG_VIDEO_EM28XX_V4L2=m -CONFIG_VIDEO_EM28XX_ALSA=m -CONFIG_VIDEO_EM28XX_DVB=m -CONFIG_VIDEO_EM28XX_RC=m - -# -# Software defined radio USB devices -# -CONFIG_USB_AIRSPY=m -CONFIG_USB_HACKRF=m -CONFIG_USB_MSI2500=m -CONFIG_MEDIA_PCI_SUPPORT=y - -# -# Media capture support -# -# CONFIG_VIDEO_HWS is not set -CONFIG_VIDEO_MGB4=m -CONFIG_VIDEO_SOLO6X10=m -CONFIG_VIDEO_TW5864=m -CONFIG_VIDEO_TW68=m -CONFIG_VIDEO_TW686X=m -# CONFIG_VIDEO_ZORAN is not set - -# -# Media capture/analog TV support -# -CONFIG_VIDEO_DT3155=m -CONFIG_VIDEO_IVTV=m -CONFIG_VIDEO_IVTV_ALSA=m -CONFIG_VIDEO_FB_IVTV=m -CONFIG_VIDEO_HEXIUM_GEMINI=m -CONFIG_VIDEO_HEXIUM_ORION=m -CONFIG_VIDEO_MXB=m - -# -# Media capture/analog/hybrid TV support -# -CONFIG_VIDEO_BT848=m -CONFIG_DVB_BT8XX=m -CONFIG_VIDEO_CX18=m -CONFIG_VIDEO_CX18_ALSA=m -CONFIG_VIDEO_CX23885=m -CONFIG_MEDIA_ALTERA_CI=m -CONFIG_VIDEO_CX25821=m -CONFIG_VIDEO_CX25821_ALSA=m -CONFIG_VIDEO_CX88=m -CONFIG_VIDEO_CX88_ALSA=m -CONFIG_VIDEO_CX88_BLACKBIRD=m -CONFIG_VIDEO_CX88_DVB=m -CONFIG_VIDEO_CX88_ENABLE_VP3054=y -CONFIG_VIDEO_CX88_VP3054=m -CONFIG_VIDEO_CX88_MPEG=m -CONFIG_VIDEO_SAA7134=m -CONFIG_VIDEO_SAA7134_ALSA=m -CONFIG_VIDEO_SAA7134_RC=y -CONFIG_VIDEO_SAA7134_DVB=m -CONFIG_VIDEO_SAA7134_GO7007=m -CONFIG_VIDEO_SAA7164=m - -# -# Media digital TV PCI Adapters -# -CONFIG_DVB_B2C2_FLEXCOP_PCI=m -# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set -CONFIG_DVB_DDBRIDGE=m -# CONFIG_DVB_DDBRIDGE_MSIENABLE is not set -CONFIG_DVB_DM1105=m -CONFIG_MANTIS_CORE=m -CONFIG_DVB_MANTIS=m -CONFIG_DVB_HOPPER=m -CONFIG_DVB_NETUP_UNIDVB=m -CONFIG_DVB_NGENE=m -CONFIG_DVB_PLUTO2=m -CONFIG_DVB_PT1=m -CONFIG_DVB_PT3=m -CONFIG_DVB_SMIPCIE=m -CONFIG_DVB_BUDGET_CORE=m -CONFIG_DVB_BUDGET=m -CONFIG_DVB_BUDGET_CI=m -CONFIG_DVB_BUDGET_AV=m -# CONFIG_VIDEO_PCI_SKELETON is not set -CONFIG_INTEL_VSC=m -CONFIG_IPU_BRIDGE=m -CONFIG_RADIO_ADAPTERS=m -CONFIG_RADIO_MAXIRADIO=m -CONFIG_RADIO_SAA7706H=m -CONFIG_RADIO_SHARK=m -CONFIG_RADIO_SHARK2=m -CONFIG_RADIO_SI4713=m -CONFIG_RADIO_SI476X=m -CONFIG_RADIO_TEA575X=m -CONFIG_RADIO_TEA5764=m -CONFIG_RADIO_TEF6862=m -CONFIG_USB_DSBR=m -CONFIG_USB_KEENE=m -CONFIG_USB_MA901=m -CONFIG_USB_MR800=m -CONFIG_USB_RAREMONO=m -CONFIG_RADIO_SI470X=m -CONFIG_USB_SI470X=m -CONFIG_I2C_SI470X=m -CONFIG_USB_SI4713=m -CONFIG_PLATFORM_SI4713=m -CONFIG_I2C_SI4713=m -CONFIG_MEDIA_PLATFORM_DRIVERS=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_SDR_PLATFORM_DRIVERS=y -CONFIG_DVB_PLATFORM_DRIVERS=y -CONFIG_V4L_MEM2MEM_DRIVERS=y -CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m -CONFIG_VIDEO_MUX=m - -# -# Allegro DVT media platform drivers -# -CONFIG_VIDEO_ALLEGRO_DVT=m -CONFIG_VIDEO_AMD_ISP4_CAPTURE=m - -# -# Amlogic media platform drivers -# -CONFIG_VIDEO_C3_ISP=m -CONFIG_VIDEO_C3_MIPI_ADAPTER=m -CONFIG_VIDEO_C3_MIPI_CSI2=m -CONFIG_VIDEO_MESON_GE2D=m - -# -# Amphion drivers -# -CONFIG_VIDEO_AMPHION_VPU=m - -# -# ARM media platform drivers -# -CONFIG_VIDEO_MALI_C55=m - -# -# Aspeed media platform drivers -# - -# -# Atmel media platform drivers -# - -# -# Cadence media platform drivers -# -CONFIG_VIDEO_CADENCE_CSI2RX=m -CONFIG_VIDEO_CADENCE_CSI2TX=m - -# -# Chips&Media media platform drivers -# -CONFIG_VIDEO_CODA=m -CONFIG_VIDEO_WAVE_VPU=m -CONFIG_VIDEO_E5010_JPEG_ENC=m - -# -# Intel media platform drivers -# - -# -# Marvell media platform drivers -# -CONFIG_VIDEO_CAFE_CCIC=m -CONFIG_VIDEO_MMP_CAMERA=m - -# -# Mediatek media platform drivers -# -CONFIG_VIDEO_MEDIATEK_JPEG=m -CONFIG_VIDEO_MEDIATEK_MDP=m -CONFIG_VIDEO_MEDIATEK_VCODEC_SCP=y -CONFIG_VIDEO_MEDIATEK_VCODEC_VPU=y -CONFIG_VIDEO_MEDIATEK_VCODEC=m -CONFIG_VIDEO_MEDIATEK_VPU=m -CONFIG_VIDEO_MEDIATEK_MDP3=m - -# -# Microchip Technology, Inc. media platform drivers -# - -# -# Nuvoton media platform drivers -# -CONFIG_VIDEO_NPCM_VCD_ECE=m - -# -# NVidia media platform drivers -# -CONFIG_VIDEO_TEGRA_VDE=m - -# -# NXP media platform drivers -# -CONFIG_VIDEO_IMX7_CSI=m -CONFIG_VIDEO_IMX8MQ_MIPI_CSI2=m -CONFIG_VIDEO_IMX_MIPI_CSIS=m -CONFIG_VIDEO_IMX8_ISI=m -CONFIG_VIDEO_IMX8_ISI_M2M=y -CONFIG_VIDEO_IMX_PXP=m -CONFIG_VIDEO_DW100=m -CONFIG_VIDEO_IMX8_JPEG=m - -# -# Qualcomm media platform drivers -# -CONFIG_VIDEO_QCOM_CAMSS=m -CONFIG_VIDEO_QCOM_IRIS=m -CONFIG_VIDEO_QCOM_VENUS=m - -# -# Raspberry Pi media platform drivers -# -CONFIG_VIDEO_RP1_CFE=m - -# -# Renesas media platform drivers -# -CONFIG_VIDEO_RCAR_CSI2=m -CONFIG_VIDEO_RCAR_ISP=m -CONFIG_VIDEO_RCAR_VIN=m -CONFIG_VIDEO_RZG2L_CSI2=m -CONFIG_VIDEO_RZG2L_CRU=m -CONFIG_VIDEO_RZV2H_IVC=m -CONFIG_VIDEO_RENESAS_FCP=m -CONFIG_VIDEO_RENESAS_FDP1=m -CONFIG_VIDEO_RENESAS_JPU=m -CONFIG_VIDEO_RENESAS_VSP1=m -CONFIG_VIDEO_RCAR_DRIF=m - -# -# Rockchip media platform drivers -# -CONFIG_VIDEO_ROCKCHIP_RGA=m -CONFIG_VIDEO_ROCKCHIP_CIF=m -CONFIG_VIDEO_ROCKCHIP_ISP1=m -CONFIG_VIDEO_ROCKCHIP_VDEC=m - -# -# Samsung media platform drivers -# - -# -# STMicroelectronics media platform drivers -# -CONFIG_VIDEO_STM32_CSI=m -CONFIG_VIDEO_STM32_DCMI=m -CONFIG_VIDEO_STM32_DCMIPP=m -CONFIG_VIDEO_STM32_DMA2D=m - -# -# Sunxi media platform drivers -# -CONFIG_VIDEO_SUN4I_CSI=m -CONFIG_VIDEO_SUN6I_CSI=m -CONFIG_VIDEO_SUN6I_MIPI_CSI2=m -CONFIG_VIDEO_SUN8I_A83T_MIPI_CSI2=m -CONFIG_VIDEO_SUN8I_DEINTERLACE=m -CONFIG_VIDEO_SUN8I_ROTATE=m -CONFIG_VIDEO_SYNOPSYS_HDMIRX=m -CONFIG_VIDEO_SYNOPSYS_HDMIRX_LOAD_DEFAULT_EDID=y -CONFIG_VIDEO_DW_MIPI_CSI2RX=m - -# -# Texas Instruments drivers -# -CONFIG_VIDEO_TI_CAL=m -CONFIG_VIDEO_TI_CAL_MC=y -CONFIG_VIDEO_TI_J721E_CSI2RX=m - -# -# Verisilicon media platform drivers -# -CONFIG_VIDEO_HANTRO=m -CONFIG_VIDEO_HANTRO_HEVC_RFC=y -CONFIG_VIDEO_HANTRO_IMX8M=y -CONFIG_VIDEO_HANTRO_ROCKCHIP=y -CONFIG_VIDEO_HANTRO_SUNXI=y -CONFIG_VIDEO_HANTRO_STM32MP25=y - -# -# VIA media platform drivers -# - -# -# Xilinx media platform drivers -# -CONFIG_VIDEO_XILINX=m -CONFIG_VIDEO_XILINX_CSI2RXSS=m -CONFIG_VIDEO_XILINX_TPG=m -CONFIG_VIDEO_XILINX_VTC=m - -# -# MMC/SDIO DVB adapters -# -CONFIG_SMS_SDIO_DRV=m -CONFIG_V4L_TEST_DRIVERS=y -CONFIG_VIDEO_VIM2M=m -CONFIG_VIDEO_VICODEC=m -CONFIG_VIDEO_VIMC=m -CONFIG_VIDEO_VIVID=m -CONFIG_VIDEO_VIVID_CEC=y -CONFIG_VIDEO_VIVID_OSD=y -CONFIG_VIDEO_VIVID_MAX_DEVS=64 -CONFIG_VIDEO_VISL=m -# CONFIG_VISL_DEBUGFS is not set -# CONFIG_DVB_TEST_DRIVERS is not set - -# -# FireWire (IEEE 1394) Adapters -# -CONFIG_DVB_FIREDTV=m -CONFIG_DVB_FIREDTV_INPUT=y -CONFIG_MEDIA_COMMON_OPTIONS=y - -# -# common driver options -# -CONFIG_CYPRESS_FIRMWARE=m -CONFIG_TTPCI_EEPROM=m -CONFIG_UVC_COMMON=m -CONFIG_VIDEO_CX2341X=m -CONFIG_VIDEO_TVEEPROM=m -CONFIG_DVB_B2C2_FLEXCOP=m -CONFIG_VIDEO_SAA7146=m -CONFIG_VIDEO_SAA7146_VV=m -CONFIG_SMS_SIANO_MDTV=m -CONFIG_SMS_SIANO_RC=y -CONFIG_SMS_SIANO_DEBUGFS=y -CONFIG_VIDEO_V4L2_TPG=m -CONFIG_VIDEOBUF2_CORE=m -CONFIG_VIDEOBUF2_V4L2=m -CONFIG_VIDEOBUF2_MEMOPS=m -CONFIG_VIDEOBUF2_DMA_CONTIG=m -CONFIG_VIDEOBUF2_VMALLOC=m -CONFIG_VIDEOBUF2_DMA_SG=m -CONFIG_VIDEOBUF2_DVB=m -# end of Media drivers - -# -# Media ancillary drivers -# -CONFIG_MEDIA_ATTACH=y - -# -# IR I2C driver auto-selected by 'Autoselect ancillary drivers' -# -CONFIG_VIDEO_IR_I2C=m -CONFIG_VIDEO_CAMERA_SENSOR=y -CONFIG_VIDEO_APTINA_PLL=m -CONFIG_VIDEO_CCS_PLL=m -CONFIG_VIDEO_ALVIUM_CSI2=m -CONFIG_VIDEO_AR0521=m -CONFIG_VIDEO_GC0308=m -CONFIG_VIDEO_GC0310=m -CONFIG_VIDEO_GC05A2=m -CONFIG_VIDEO_GC08A3=m -CONFIG_VIDEO_GC2145=m -CONFIG_VIDEO_HI556=m -CONFIG_VIDEO_HI846=m -CONFIG_VIDEO_HI847=m -CONFIG_VIDEO_IMX111=m -CONFIG_VIDEO_IMX208=m -CONFIG_VIDEO_IMX214=m -CONFIG_VIDEO_IMX219=m -CONFIG_VIDEO_IMX258=m -CONFIG_VIDEO_IMX274=m -CONFIG_VIDEO_IMX283=m -CONFIG_VIDEO_IMX290=m -CONFIG_VIDEO_IMX296=m -CONFIG_VIDEO_IMX319=m -CONFIG_VIDEO_IMX334=m -CONFIG_VIDEO_IMX335=m -CONFIG_VIDEO_IMX355=m -CONFIG_VIDEO_IMX412=m -CONFIG_VIDEO_IMX415=m -# CONFIG_VIDEO_IMX471 is not set -CONFIG_VIDEO_IMX681=m -CONFIG_VIDEO_MAX9271_LIB=m -CONFIG_VIDEO_MT9M001=m -CONFIG_VIDEO_MT9M111=m -CONFIG_VIDEO_MT9M114=m -CONFIG_VIDEO_MT9P031=m -CONFIG_VIDEO_MT9T112=m -CONFIG_VIDEO_MT9V011=m -CONFIG_VIDEO_MT9V032=m -CONFIG_VIDEO_MT9V111=m -CONFIG_VIDEO_OG01A1B=m -CONFIG_VIDEO_OG0VE1B=m -CONFIG_VIDEO_OS05B10=m -CONFIG_VIDEO_OV01A10=m -CONFIG_VIDEO_OV02A10=m -CONFIG_VIDEO_OV02E10=m -CONFIG_VIDEO_OV02C10=m -CONFIG_VIDEO_OV08D10=m -CONFIG_VIDEO_OV08X40=m -CONFIG_VIDEO_OV13858=m -CONFIG_VIDEO_OV13B10=m -CONFIG_VIDEO_OV2640=m -CONFIG_VIDEO_OV2659=m -CONFIG_VIDEO_OV2680=m -CONFIG_VIDEO_OV2685=m -# CONFIG_VIDEO_OV2732 is not set -CONFIG_VIDEO_OV2735=m -CONFIG_VIDEO_OV2740=m -CONFIG_VIDEO_OV4689=m -CONFIG_VIDEO_OV5640=m -CONFIG_VIDEO_OV5645=m -CONFIG_VIDEO_OV5647=m -CONFIG_VIDEO_OV5648=m -CONFIG_VIDEO_OV5670=m -CONFIG_VIDEO_OV5675=m -CONFIG_VIDEO_OV5693=m -CONFIG_VIDEO_OV5695=m -CONFIG_VIDEO_OV6211=m -CONFIG_VIDEO_OV64A40=m -CONFIG_VIDEO_OV7251=m -CONFIG_VIDEO_OV7640=m -CONFIG_VIDEO_OV7670=m -CONFIG_VIDEO_OV772X=m -CONFIG_VIDEO_OV7740=m -CONFIG_VIDEO_OV8856=m -CONFIG_VIDEO_OV8858=m -CONFIG_VIDEO_OV8865=m -CONFIG_VIDEO_OV9282=m -CONFIG_VIDEO_OV9640=m -CONFIG_VIDEO_OV9650=m -CONFIG_VIDEO_OV9734=m -CONFIG_VIDEO_RDACM20=m -CONFIG_VIDEO_RDACM21=m -CONFIG_VIDEO_RJ54N1=m -CONFIG_VIDEO_S5C73M3=m -CONFIG_VIDEO_S5K3M5=m -CONFIG_VIDEO_S5K5BAF=m -CONFIG_VIDEO_S5K6A3=m -CONFIG_VIDEO_S5KJN1=m -# CONFIG_VIDEO_T4KA3 is not set -CONFIG_VIDEO_VD55G1=m -CONFIG_VIDEO_VD55G0=m -CONFIG_VIDEO_VD56G3=m -CONFIG_VIDEO_VGXY61=m -CONFIG_VIDEO_CCS=m -CONFIG_VIDEO_ET8EK8=m - -# -# Camera ISPs -# -CONFIG_VIDEO_THP7312=m -# end of Camera ISPs - -CONFIG_VIDEO_CAMERA_LENS=y -CONFIG_VIDEO_AD5820=m -CONFIG_VIDEO_AK7375=m -CONFIG_VIDEO_DW9714=m -CONFIG_VIDEO_DW9719=m -CONFIG_VIDEO_DW9768=m -CONFIG_VIDEO_DW9807_VCM=m - -# -# Flash devices -# -CONFIG_VIDEO_ADP1653=m -CONFIG_VIDEO_LM3560=m -CONFIG_VIDEO_LM3646=m -# end of Flash devices - -# -# Audio decoders, processors and mixers -# -CONFIG_VIDEO_CS3308=m -CONFIG_VIDEO_CS5345=m -CONFIG_VIDEO_CS53L32A=m -CONFIG_VIDEO_MSP3400=m -CONFIG_VIDEO_SONY_BTF_MPX=m -CONFIG_VIDEO_TDA1997X=m -CONFIG_VIDEO_TDA7432=m -CONFIG_VIDEO_TDA9840=m -CONFIG_VIDEO_TEA6415C=m -CONFIG_VIDEO_TEA6420=m -CONFIG_VIDEO_TLV320AIC23B=m -CONFIG_VIDEO_TVAUDIO=m -CONFIG_VIDEO_UDA1342=m -CONFIG_VIDEO_VP27SMPX=m -CONFIG_VIDEO_WM8739=m -CONFIG_VIDEO_WM8775=m -# end of Audio decoders, processors and mixers - -# -# RDS decoders -# -CONFIG_VIDEO_SAA6588=m -# end of RDS decoders - -# -# Video decoders -# -CONFIG_VIDEO_ADV7180=m -CONFIG_VIDEO_ADV7183=m -CONFIG_VIDEO_ADV748X=m -CONFIG_VIDEO_ADV7604=m -CONFIG_VIDEO_ADV7604_CEC=y -CONFIG_VIDEO_ADV7842=m -CONFIG_VIDEO_ADV7842_CEC=y -CONFIG_VIDEO_BT819=m -CONFIG_VIDEO_BT856=m -CONFIG_VIDEO_BT866=m -CONFIG_VIDEO_ISL7998X=m -CONFIG_VIDEO_LT6911UXE=m -CONFIG_VIDEO_KS0127=m -CONFIG_VIDEO_MAX9286=m -CONFIG_VIDEO_ML86V7667=m -CONFIG_VIDEO_SAA7110=m -CONFIG_VIDEO_SAA711X=m -CONFIG_VIDEO_TC358743=m -CONFIG_VIDEO_TC358743_CEC=y -CONFIG_VIDEO_TC358746=m -CONFIG_VIDEO_TVP514X=m -CONFIG_VIDEO_TVP5150=m -CONFIG_VIDEO_TVP7002=m -CONFIG_VIDEO_TW2804=m -CONFIG_VIDEO_TW9900=m -CONFIG_VIDEO_TW9903=m -CONFIG_VIDEO_TW9906=m -CONFIG_VIDEO_TW9910=m -CONFIG_VIDEO_VPX3220=m - -# -# Video and audio decoders -# -CONFIG_VIDEO_SAA717X=m -CONFIG_VIDEO_CX25840=m -# end of Video decoders - -# -# Video encoders -# -CONFIG_VIDEO_ADV7170=m -CONFIG_VIDEO_ADV7175=m -CONFIG_VIDEO_ADV7343=m -CONFIG_VIDEO_ADV7393=m -CONFIG_VIDEO_AK881X=m -CONFIG_VIDEO_SAA7127=m -CONFIG_VIDEO_SAA7185=m -CONFIG_VIDEO_THS8200=m -# end of Video encoders - -# -# Video improvement chips -# -CONFIG_VIDEO_UPD64031A=m -CONFIG_VIDEO_UPD64083=m -# end of Video improvement chips - -# -# Audio/Video compression chips -# -CONFIG_VIDEO_SAA6752HS=m -# end of Audio/Video compression chips - -# -# SDR tuner chips -# -CONFIG_SDR_MAX2175=m -# end of SDR tuner chips - -# -# Miscellaneous helper chips -# -# CONFIG_VIDEO_INTEL_CVS is not set -CONFIG_VIDEO_I2C=m -CONFIG_VIDEO_M52790=m -CONFIG_VIDEO_ST_MIPID02=m -CONFIG_VIDEO_THS7303=m -# end of Miscellaneous helper chips - -# -# Video serializers and deserializers -# -CONFIG_VIDEO_DS90UB913=m -CONFIG_VIDEO_DS90UB953=m -CONFIG_VIDEO_DS90UB960=m -CONFIG_VIDEO_MAX96714=m -CONFIG_VIDEO_MAX96717=m -# end of Video serializers and deserializers - -# -# Media SPI Adapters -# -CONFIG_CXD2880_SPI_DRV=m -CONFIG_VIDEO_GS1662=m -# end of Media SPI Adapters - -CONFIG_MEDIA_TUNER=m - -# -# Customize TV tuners -# -CONFIG_MEDIA_TUNER_E4000=m -CONFIG_MEDIA_TUNER_FC0011=m -CONFIG_MEDIA_TUNER_FC0012=m -CONFIG_MEDIA_TUNER_FC0013=m -CONFIG_MEDIA_TUNER_FC2580=m -CONFIG_MEDIA_TUNER_IT913X=m -CONFIG_MEDIA_TUNER_M88RS6000T=m -CONFIG_MEDIA_TUNER_MAX2165=m -CONFIG_MEDIA_TUNER_MC44S803=m -CONFIG_MEDIA_TUNER_MSI001=m -CONFIG_MEDIA_TUNER_MT2060=m -CONFIG_MEDIA_TUNER_MT2063=m -CONFIG_MEDIA_TUNER_MT20XX=m -CONFIG_MEDIA_TUNER_MT2131=m -CONFIG_MEDIA_TUNER_MT2266=m -CONFIG_MEDIA_TUNER_MXL301RF=m -CONFIG_MEDIA_TUNER_MXL5005S=m -CONFIG_MEDIA_TUNER_MXL5007T=m -CONFIG_MEDIA_TUNER_QM1D1B0004=m -CONFIG_MEDIA_TUNER_QM1D1C0042=m -CONFIG_MEDIA_TUNER_QT1010=m -CONFIG_MEDIA_TUNER_R820T=m -CONFIG_MEDIA_TUNER_SI2157=m -CONFIG_MEDIA_TUNER_SIMPLE=m -CONFIG_MEDIA_TUNER_TDA18212=m -CONFIG_MEDIA_TUNER_TDA18218=m -CONFIG_MEDIA_TUNER_TDA18250=m -CONFIG_MEDIA_TUNER_TDA18271=m -CONFIG_MEDIA_TUNER_TDA827X=m -CONFIG_MEDIA_TUNER_TDA8290=m -CONFIG_MEDIA_TUNER_TDA9887=m -CONFIG_MEDIA_TUNER_TEA5761=m -CONFIG_MEDIA_TUNER_TEA5767=m -CONFIG_MEDIA_TUNER_TUA9001=m -CONFIG_MEDIA_TUNER_XC2028=m -CONFIG_MEDIA_TUNER_XC4000=m -CONFIG_MEDIA_TUNER_XC5000=m -# end of Customize TV tuners - -# -# Customise DVB Frontends -# - -# -# Multistandard (satellite) frontends -# -CONFIG_DVB_M88DS3103=m -CONFIG_DVB_MXL5XX=m -CONFIG_DVB_STB0899=m -CONFIG_DVB_STB6100=m -CONFIG_DVB_STV090x=m -CONFIG_DVB_STV0910=m -CONFIG_DVB_STV6110x=m -CONFIG_DVB_STV6111=m - -# -# Multistandard (cable + terrestrial) frontends -# -CONFIG_DVB_DRXK=m -CONFIG_DVB_MN88472=m -CONFIG_DVB_MN88473=m -CONFIG_DVB_SI2165=m -CONFIG_DVB_TDA18271C2DD=m - -# -# DVB-S (satellite) frontends -# -CONFIG_DVB_CX24110=m -CONFIG_DVB_CX24116=m -CONFIG_DVB_CX24117=m -CONFIG_DVB_CX24120=m -CONFIG_DVB_CX24123=m -CONFIG_DVB_DS3000=m -CONFIG_DVB_MB86A16=m -CONFIG_DVB_MT312=m -CONFIG_DVB_S5H1420=m -CONFIG_DVB_SI21XX=m -CONFIG_DVB_STB6000=m -CONFIG_DVB_STV0288=m -CONFIG_DVB_STV0299=m -CONFIG_DVB_STV0900=m -CONFIG_DVB_STV6110=m -CONFIG_DVB_TDA10071=m -CONFIG_DVB_TDA10086=m -CONFIG_DVB_TDA8083=m -CONFIG_DVB_TDA8261=m -CONFIG_DVB_TDA826X=m -CONFIG_DVB_TS2020=m -CONFIG_DVB_TUA6100=m -CONFIG_DVB_TUNER_CX24113=m -CONFIG_DVB_TUNER_ITD1000=m -CONFIG_DVB_VES1X93=m -CONFIG_DVB_ZL10036=m -CONFIG_DVB_ZL10039=m - -# -# DVB-T (terrestrial) frontends -# -CONFIG_DVB_AF9013=m -CONFIG_DVB_AS102_FE=m -CONFIG_DVB_CX22700=m -CONFIG_DVB_CX22702=m -CONFIG_DVB_CXD2820R=m -CONFIG_DVB_CXD2841ER=m -CONFIG_DVB_DIB3000MB=m -CONFIG_DVB_DIB3000MC=m -CONFIG_DVB_DIB7000M=m -CONFIG_DVB_DIB7000P=m -CONFIG_DVB_DIB9000=m -CONFIG_DVB_DRXD=m -CONFIG_DVB_EC100=m -CONFIG_DVB_GP8PSK_FE=m -CONFIG_DVB_L64781=m -CONFIG_DVB_MT352=m -CONFIG_DVB_NXT6000=m -CONFIG_DVB_RTL2830=m -CONFIG_DVB_RTL2832=m -CONFIG_DVB_RTL2832_SDR=m -CONFIG_DVB_S5H1432=m -CONFIG_DVB_SI2168=m -CONFIG_DVB_SP887X=m -CONFIG_DVB_STV0367=m -CONFIG_DVB_TDA10048=m -CONFIG_DVB_TDA1004X=m -CONFIG_DVB_ZD1301_DEMOD=m -CONFIG_DVB_ZL10353=m -CONFIG_DVB_CXD2880=m - -# -# DVB-C (cable) frontends -# -CONFIG_DVB_STV0297=m -CONFIG_DVB_TDA10021=m -CONFIG_DVB_TDA10023=m -CONFIG_DVB_VES1820=m - -# -# ATSC (North American/Korean Terrestrial/Cable DTV) frontends -# -CONFIG_DVB_AU8522=m -CONFIG_DVB_AU8522_DTV=m -CONFIG_DVB_AU8522_V4L=m -CONFIG_DVB_BCM3510=m -CONFIG_DVB_LG2160=m -CONFIG_DVB_LGDT3305=m -CONFIG_DVB_LGDT3306A=m -CONFIG_DVB_LGDT330X=m -CONFIG_DVB_MXL692=m -CONFIG_DVB_NXT200X=m -CONFIG_DVB_OR51132=m -CONFIG_DVB_OR51211=m -CONFIG_DVB_S5H1409=m -CONFIG_DVB_S5H1411=m - -# -# ISDB-T (terrestrial) frontends -# -CONFIG_DVB_DIB8000=m -CONFIG_DVB_MB86A20S=m -CONFIG_DVB_S921=m - -# -# ISDB-S (satellite) & ISDB-T (terrestrial) frontends -# -CONFIG_DVB_MN88443X=m -CONFIG_DVB_TC90522=m - -# -# Digital terrestrial only tuners/PLL -# -CONFIG_DVB_PLL=m -CONFIG_DVB_TUNER_DIB0070=m -CONFIG_DVB_TUNER_DIB0090=m - -# -# SEC control devices for DVB-S -# -CONFIG_DVB_A8293=m -CONFIG_DVB_AF9033=m -CONFIG_DVB_ASCOT2E=m -CONFIG_DVB_ATBM8830=m -CONFIG_DVB_HELENE=m -CONFIG_DVB_HORUS3A=m -CONFIG_DVB_ISL6405=m -CONFIG_DVB_ISL6421=m -CONFIG_DVB_ISL6423=m -CONFIG_DVB_IX2505V=m -CONFIG_DVB_LGS8GL5=m -CONFIG_DVB_LGS8GXX=m -CONFIG_DVB_LNBH25=m -CONFIG_DVB_LNBH29=m -CONFIG_DVB_LNBP21=m -CONFIG_DVB_LNBP22=m -CONFIG_DVB_M88RS2000=m -CONFIG_DVB_TDA665x=m -CONFIG_DVB_DRX39XYJ=m - -# -# Common Interface (EN50221) controller drivers -# -CONFIG_DVB_CXD2099=m -CONFIG_DVB_SP2=m -# end of Customise DVB Frontends - -# -# Tools to develop new frontends -# -CONFIG_DVB_DUMMY_FE=m -# end of Media ancillary drivers - -# -# Graphics support -# -CONFIG_APERTURE_HELPERS=y -CONFIG_SCREEN_INFO=y -CONFIG_VIDEO=y -CONFIG_AUXDISPLAY=y -CONFIG_CHARLCD=m -CONFIG_HD44780_COMMON=m -CONFIG_HD44780=m -CONFIG_LCD2S=m -CONFIG_PARPORT_PANEL=m -CONFIG_PANEL_PARPORT=0 -CONFIG_PANEL_PROFILE=5 -# CONFIG_PANEL_CHANGE_MESSAGE is not set -# CONFIG_CHARLCD_BL_OFF is not set -# CONFIG_CHARLCD_BL_ON is not set -CONFIG_CHARLCD_BL_FLASH=y -CONFIG_KS0108=m -CONFIG_KS0108_PORT=0x378 -CONFIG_KS0108_DELAY=2 -CONFIG_LINEDISP=m -CONFIG_IMG_ASCII_LCD=m -CONFIG_HT16K33=m -CONFIG_MAX6959=m -CONFIG_SEG_LED_GPIO=m -CONFIG_PANEL=m -CONFIG_GPU_BUDDY=y -CONFIG_TEGRA_HOST1X_CONTEXT_BUS=y -CONFIG_TEGRA_HOST1X=m -CONFIG_TEGRA_HOST1X_FIREWALL=y -CONFIG_DRM=y - -# -# DRM debugging options -# -# CONFIG_DRM_WERROR is not set -# CONFIG_DRM_DEBUG_MM is not set -# end of DRM debugging options - -CONFIG_DRM_MIPI_DBI=m -CONFIG_DRM_MIPI_DSI=y -CONFIG_DRM_KMS_HELPER=y -CONFIG_DRM_DRAW=y -CONFIG_DRM_PANIC=y -CONFIG_DRM_PANIC_FOREGROUND_COLOR=0xffffff -CONFIG_DRM_PANIC_BACKGROUND_COLOR=0x5e2750 -# CONFIG_DRM_PANIC_DEBUG is not set -CONFIG_DRM_PANIC_SCREEN="user" -# CONFIG_DRM_RAS is not set -# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set -# CONFIG_DRM_DEBUG_MODESET_LOCK is not set -CONFIG_DRM_CLIENT=y -CONFIG_DRM_CLIENT_LIB=y -CONFIG_DRM_CLIENT_SELECTION=y -CONFIG_DRM_CLIENT_SETUP=y - -# -# Supported DRM clients -# -CONFIG_DRM_FBDEV_EMULATION=y -CONFIG_DRM_FBDEV_OVERALLOC=100 -# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set -CONFIG_DRM_CLIENT_LOG=y -CONFIG_DRM_CLIENT_DEFAULT_FBDEV=y -# CONFIG_DRM_CLIENT_DEFAULT_LOG is not set -CONFIG_DRM_CLIENT_DEFAULT="fbdev" -# end of Supported DRM clients - -CONFIG_DRM_LOAD_EDID_FIRMWARE=y -CONFIG_DRM_DISPLAY_DP_AUX_BUS=m -CONFIG_DRM_DISPLAY_HELPER=m -CONFIG_DRM_BRIDGE_CONNECTOR=y -CONFIG_DRM_DISPLAY_DP_AUX_CEC=y -CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV=y -CONFIG_DRM_DISPLAY_DP_HELPER=y -CONFIG_DRM_DISPLAY_DP_TUNNEL=y -CONFIG_DRM_DISPLAY_DSC_HELPER=y -CONFIG_DRM_DISPLAY_HDCP_HELPER=y -CONFIG_DRM_DISPLAY_HDMI_AUDIO_HELPER=y -CONFIG_DRM_DISPLAY_HDMI_CEC_HELPER=y -CONFIG_DRM_DISPLAY_HDMI_CEC_NOTIFIER_HELPER=y -CONFIG_DRM_DISPLAY_HDMI_HELPER=y -CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER=y -CONFIG_DRM_TTM=m -CONFIG_DRM_EXEC=m -CONFIG_DRM_GPUVM=m -CONFIG_DRM_GPUSVM=m -CONFIG_DRM_BUDDY=m -CONFIG_DRM_TTM_HELPER=m -CONFIG_DRM_GEM_DMA_HELPER=m -CONFIG_DRM_GEM_SHMEM_HELPER=y -CONFIG_DRM_SUBALLOC_HELPER=m -CONFIG_DRM_SCHED=m -CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS=m -CONFIG_DRM_PRIVACY_SCREEN=y -CONFIG_DRM_ADP=m -CONFIG_DRM_AMDGPU=m -CONFIG_DRM_AMDGPU_SI=y -CONFIG_DRM_AMDGPU_CIK=y -CONFIG_DRM_AMDGPU_USERPTR=y -CONFIG_DRM_AMD_ISP=y -# CONFIG_DRM_AMDGPU_WERROR is not set - -# -# ACP (Audio CoProcessor) Configuration -# -CONFIG_DRM_AMD_ACP=y -# end of ACP (Audio CoProcessor) Configuration - -# -# Display Engine Configuration -# -CONFIG_DRM_AMD_DC=y -CONFIG_DRM_AMD_DC_FP=y -CONFIG_DRM_AMD_DC_SI=y -# CONFIG_DEBUG_KERNEL_DC is not set -CONFIG_DRM_AMD_SECURE_DISPLAY=y -# end of Display Engine Configuration - -CONFIG_HSA_AMD=y -CONFIG_HSA_AMD_SVM=y -CONFIG_HSA_AMD_P2P=y - -# -# ARM devices -# -CONFIG_DRM_HDLCD=m -# CONFIG_DRM_HDLCD_SHOW_UNDERRUN is not set -CONFIG_DRM_MALI_DISPLAY=m -CONFIG_DRM_KOMEDA=m -# end of ARM devices - -CONFIG_DRM_AST=m -CONFIG_DRM_BRIDGE=y -CONFIG_DRM_PANEL_BRIDGE=y -CONFIG_DRM_AUX_BRIDGE=m -CONFIG_DRM_AUX_HPD_BRIDGE=m - -# -# Display Interface Bridges -# -CONFIG_DRM_CHIPONE_ICN6211=m -CONFIG_DRM_CHRONTEL_CH7033=m -CONFIG_DRM_CROS_EC_ANX7688=m -CONFIG_DRM_DISPLAY_CONNECTOR=m -CONFIG_DRM_FSL_LDB=m -CONFIG_DRM_I2C_NXP_TDA998X=m -CONFIG_DRM_INNO_HDMI=m -CONFIG_DRM_ITE_IT6263=m -CONFIG_DRM_ITE_IT6505=m -CONFIG_DRM_LONTIUM_LT8912B=m -CONFIG_DRM_LONTIUM_LT9211=m -CONFIG_DRM_LONTIUM_LT9611=m -CONFIG_DRM_LONTIUM_LT9611UXC=m -# CONFIG_DRM_LONTIUM_LT8713SX is not set -CONFIG_DRM_ITE_IT66121=m -CONFIG_DRM_LVDS_CODEC=m -CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW=m -CONFIG_DRM_NWL_MIPI_DSI=m -CONFIG_DRM_NXP_PTN3460=m -CONFIG_DRM_PARADE_PS8622=m -CONFIG_DRM_PARADE_PS8640=m -CONFIG_DRM_SAMSUNG_DSIM=m -CONFIG_DRM_SIL_SII8620=m -CONFIG_DRM_SII902X=m -CONFIG_DRM_SII9234=m -CONFIG_DRM_SIMPLE_BRIDGE=m -CONFIG_DRM_SOLOMON_SSD2825=m -CONFIG_DRM_THINE_THC63LVD1024=m -CONFIG_DRM_TOSHIBA_TC358762=m -CONFIG_DRM_TOSHIBA_TC358764=m -CONFIG_DRM_TOSHIBA_TC358767=m -CONFIG_DRM_TOSHIBA_TC358768=m -CONFIG_DRM_TOSHIBA_TC358775=m -CONFIG_DRM_TI_DLPC3433=m -CONFIG_DRM_TI_TDP158=m -CONFIG_DRM_TI_TFP410=m -CONFIG_DRM_TI_SN65DSI83=m -CONFIG_DRM_TI_SN65DSI86=m -CONFIG_DRM_TI_TPD12S015=m -CONFIG_DRM_WAVESHARE_BRIDGE=m -CONFIG_DRM_ANALOGIX_ANX6345=m -CONFIG_DRM_ANALOGIX_ANX78XX=m -CONFIG_DRM_ANALOGIX_DP=m -CONFIG_DRM_ANALOGIX_ANX7625=m -CONFIG_DRM_I2C_ADV7511=m -CONFIG_DRM_I2C_ADV7511_AUDIO=y -CONFIG_DRM_I2C_ADV7511_CEC=y -CONFIG_DRM_CDNS_DSI=m -CONFIG_DRM_CDNS_DSI_J721E=y -CONFIG_DRM_CDNS_MHDP8546=m -CONFIG_DRM_CDNS_MHDP8546_J721E=y -CONFIG_DRM_IMX_LDB_HELPER=m -CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE=m -CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE_CONNECTOR_FIXUP=y -CONFIG_DRM_IMX8MP_HDMI_PAI=m -CONFIG_DRM_IMX8MP_HDMI_PVI=m -CONFIG_DRM_IMX8QM_LDB=m -CONFIG_DRM_IMX8QXP_LDB=m -CONFIG_DRM_IMX8QXP_PIXEL_COMBINER=m -CONFIG_DRM_IMX8QXP_PIXEL_LINK=m -CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI=m -CONFIG_DRM_IMX93_MIPI_DSI=m -CONFIG_DRM_DW_DP=m -CONFIG_DRM_DW_HDMI=m -CONFIG_DRM_DW_HDMI_AHB_AUDIO=m -CONFIG_DRM_DW_HDMI_I2S_AUDIO=m -CONFIG_DRM_DW_HDMI_GP_AUDIO=m -CONFIG_DRM_DW_HDMI_CEC=m -CONFIG_DRM_DW_HDMI_QP=m -CONFIG_DRM_DW_HDMI_QP_CEC=y -CONFIG_DRM_DW_MIPI_DSI=m -CONFIG_DRM_DW_MIPI_DSI2=m -# end of Display Interface Bridges - -CONFIG_DRM_ETNAVIV=m -CONFIG_DRM_ETNAVIV_THERMAL=y -CONFIG_DRM_GUD=m -# CONFIG_DRM_HISI_HIBMC is not set -CONFIG_DRM_HISI_KIRIN=m -CONFIG_DRM_HYPERV=m -CONFIG_DRM_POWERVR=m -CONFIG_DRM_IMX8_DC=m -CONFIG_DRM_IMX_DCSS=m -CONFIG_DRM_IMX_LCDC=m -CONFIG_DRM_KMB_DISPLAY=m -CONFIG_DRM_LIMA=m -CONFIG_DRM_LOGICVC=m -CONFIG_DRM_MEDIATEK=m -CONFIG_DRM_MEDIATEK_DP=m -CONFIG_DRM_MEDIATEK_HDMI_COMMON=m -CONFIG_DRM_MEDIATEK_HDMI=m -CONFIG_DRM_MEDIATEK_HDMI_V2=m -CONFIG_DRM_MESON=m -CONFIG_DRM_MESON_DW_HDMI=m -CONFIG_DRM_MESON_DW_MIPI_DSI=m -CONFIG_DRM_MGAG200=m -CONFIG_DRM_MSM=m -CONFIG_DRM_MSM_GPU_STATE=y -# CONFIG_DRM_MSM_GPU_SUDO is not set -CONFIG_DRM_MSM_KMS=y -CONFIG_DRM_MSM_KMS_FBDEV=y -CONFIG_DRM_MSM_MDSS=y -CONFIG_DRM_MSM_MDP4=y -CONFIG_DRM_MSM_MDP5=y -CONFIG_DRM_MSM_DPU=y -CONFIG_DRM_MSM_DP=y -CONFIG_DRM_MSM_DSI=y -CONFIG_DRM_MSM_DSI_28NM_PHY=y -CONFIG_DRM_MSM_DSI_20NM_PHY=y -CONFIG_DRM_MSM_DSI_28NM_8960_PHY=y -CONFIG_DRM_MSM_DSI_14NM_PHY=y -CONFIG_DRM_MSM_DSI_10NM_PHY=y -CONFIG_DRM_MSM_DSI_7NM_PHY=y -CONFIG_DRM_MSM_HDMI=y -CONFIG_DRM_MSM_HDMI_HDCP=y -CONFIG_DRM_MXS=y -CONFIG_DRM_MXSFB=m -CONFIG_DRM_IMX_LCDIF=m -# CONFIG_DRM_NOUVEAU is not set -CONFIG_DRM_PANEL=y - -# -# Display Panels -# -CONFIG_DRM_PANEL_ABT_Y030XX067A=m -CONFIG_DRM_PANEL_ARM_VERSATILE=m -CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596=m -CONFIG_DRM_PANEL_AUO_A030JTN01=m -CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0=m -CONFIG_DRM_PANEL_BOE_HIMAX8279D=m -CONFIG_DRM_PANEL_BOE_TD4320=m -CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A=m -CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m -# CONFIG_DRM_PANEL_BOE_TV101WUM_LL2 is not set -# CONFIG_DRM_PANEL_CHIPWEALTH_CH13726A is not set -CONFIG_DRM_PANEL_EBBG_FT8719=m -CONFIG_DRM_PANEL_ELIDA_KD35T133=m -CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02=m -CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D=m -# CONFIG_DRM_PANEL_FOCALTECH_OTA7290B is not set -CONFIG_DRM_PANEL_DSI_CM=m -CONFIG_DRM_PANEL_LVDS=m -CONFIG_DRM_PANEL_HIMAX_HX8279=m -CONFIG_DRM_PANEL_HIMAX_HX83102=m -CONFIG_DRM_PANEL_HIMAX_HX83112A=m -CONFIG_DRM_PANEL_HIMAX_HX83112B=m -# CONFIG_DRM_PANEL_HIMAX_HX83121A is not set -CONFIG_DRM_PANEL_HIMAX_HX8394=m -CONFIG_DRM_PANEL_HYDIS_HV101HD1=m -CONFIG_DRM_PANEL_ILITEK_IL9322=m -CONFIG_DRM_PANEL_ILITEK_ILI9341=m -CONFIG_DRM_PANEL_ILITEK_ILI9805=m -# CONFIG_DRM_PANEL_ILITEK_ILI9806E_DSI is not set -# CONFIG_DRM_PANEL_ILITEK_ILI9806E_SPI is not set -CONFIG_DRM_PANEL_ILITEK_ILI9881C=m -CONFIG_DRM_PANEL_ILITEK_ILI9882T=m -CONFIG_DRM_PANEL_INNOLUX_EJ030NA=m -CONFIG_DRM_PANEL_INNOLUX_P079ZCA=m -CONFIG_DRM_PANEL_JADARD_JD9365DA_H3=m -CONFIG_DRM_PANEL_JDI_LPM102A188A=m -CONFIG_DRM_PANEL_JDI_LT070ME05000=m -CONFIG_DRM_PANEL_JDI_R63452=m -CONFIG_DRM_PANEL_KHADAS_TS050=m -CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04=m -CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W=m -CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829=m -CONFIG_DRM_PANEL_LINCOLNTECH_LCD197=m -CONFIG_DRM_PANEL_LG_LB035Q02=m -CONFIG_DRM_PANEL_LG_LD070WX3=m -CONFIG_DRM_PANEL_LG_LG4573=m -CONFIG_DRM_PANEL_LG_SW43408=m -# CONFIG_DRM_PANEL_LXD_M9189A is not set -CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966=m -CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m -# CONFIG_DRM_PANEL_MOTOROLA_MOT is not set -CONFIG_DRM_PANEL_NEC_NL8048HL11=m -CONFIG_DRM_PANEL_NEWVISION_NV3051D=m -CONFIG_DRM_PANEL_NEWVISION_NV3052C=m -CONFIG_DRM_PANEL_NOVATEK_NT35510=m -# CONFIG_DRM_PANEL_NOVATEK_NT35532 is not set -CONFIG_DRM_PANEL_NOVATEK_NT35560=m -CONFIG_DRM_PANEL_NOVATEK_NT35950=m -CONFIG_DRM_PANEL_NOVATEK_NT36523=m -CONFIG_DRM_PANEL_NOVATEK_NT36672A=m -CONFIG_DRM_PANEL_NOVATEK_NT36672E=m -# CONFIG_DRM_PANEL_NOVATEK_NT37700F is not set -CONFIG_DRM_PANEL_NOVATEK_NT37801=m -CONFIG_DRM_PANEL_NOVATEK_NT39016=m -CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO=m -CONFIG_DRM_PANEL_ORISETECH_OTA5601A=m -CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m -CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS=m -CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00=m -CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m -CONFIG_DRM_PANEL_RAYDIUM_RM67191=m -CONFIG_DRM_PANEL_RAYDIUM_RM67200=m -CONFIG_DRM_PANEL_RAYDIUM_RM68200=m -CONFIG_DRM_PANEL_RAYDIUM_RM692E5=m -CONFIG_DRM_PANEL_RAYDIUM_RM69380=m -CONFIG_DRM_PANEL_RENESAS_R61307=m -CONFIG_DRM_PANEL_RENESAS_R69328=m -CONFIG_DRM_PANEL_RONBO_RB070D30=m -CONFIG_DRM_PANEL_SAMSUNG_AMS581VF01=m -CONFIG_DRM_PANEL_SAMSUNG_AMS639RQ08=m -CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24=m -CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01=m -CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20=m -CONFIG_DRM_PANEL_SAMSUNG_DB7430=m -CONFIG_DRM_PANEL_SAMSUNG_LD9040=m -CONFIG_DRM_PANEL_SAMSUNG_LTL106HL02=m -CONFIG_DRM_PANEL_SAMSUNG_S6E3FA7=m -CONFIG_DRM_PANEL_SAMSUNG_S6D16D0=m -CONFIG_DRM_PANEL_SAMSUNG_S6D27A1=m -CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0=m -CONFIG_DRM_PANEL_SAMSUNG_S6E3FC2X01=m -CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2=m -CONFIG_DRM_PANEL_SAMSUNG_S6E3HA8=m -CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=m -CONFIG_DRM_PANEL_SAMSUNG_S6E63M0=m -CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_SPI=m -CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI=m -CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m -CONFIG_DRM_PANEL_SAMSUNG_S6E8AA5X01_AMS561RA01=m -# CONFIG_DRM_PANEL_SAMSUNG_S6E8FC0 is not set -CONFIG_DRM_PANEL_SAMSUNG_SOFEF00=m -CONFIG_DRM_PANEL_SEIKO_43WVF1G=m -CONFIG_DRM_PANEL_SHARP_LQ079L1SX01=m -CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m -CONFIG_DRM_PANEL_SHARP_LS037V7DW01=m -CONFIG_DRM_PANEL_SHARP_LS043T1LE01=m -CONFIG_DRM_PANEL_SHARP_LS060T1SX01=m -CONFIG_DRM_PANEL_SITRONIX_ST7701=m -CONFIG_DRM_PANEL_SITRONIX_ST7703=m -CONFIG_DRM_PANEL_SITRONIX_ST7789V=m -CONFIG_DRM_PANEL_SONY_ACX565AKM=m -CONFIG_DRM_PANEL_SONY_TD4353_JDI=m -CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521=m -CONFIG_DRM_PANEL_STARTEK_KD070FHFID015=m -CONFIG_DRM_PANEL_EDP=m -CONFIG_DRM_PANEL_SIMPLE=m -CONFIG_DRM_PANEL_SUMMIT=m -CONFIG_DRM_PANEL_SYNAPTICS_R63353=m -CONFIG_DRM_PANEL_SYNAPTICS_TDDI=m -CONFIG_DRM_PANEL_TDO_TL070WSH30=m -CONFIG_DRM_PANEL_TPO_TD028TTEC1=m -CONFIG_DRM_PANEL_TPO_TD043MTEA1=m -CONFIG_DRM_PANEL_TPO_TPG110=m -CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m -CONFIG_DRM_PANEL_VISIONOX_G2647FB105=m -CONFIG_DRM_PANEL_VISIONOX_R66451=m -CONFIG_DRM_PANEL_VISIONOX_RM69299=m -CONFIG_DRM_PANEL_VISIONOX_RM692E5=m -CONFIG_DRM_PANEL_VISIONOX_VTDR6130=m -CONFIG_DRM_PANEL_WIDECHIPS_WS2401=m -CONFIG_DRM_PANEL_XINPENG_XPP055C272=m -# end of Display Panels - -CONFIG_DRM_PANFROST=m -CONFIG_DRM_PANTHOR=m -CONFIG_DRM_PL111=m -CONFIG_DRM_QXL=m -CONFIG_DRM_RADEON=m -# CONFIG_DRM_RADEON_USERPTR is not set -CONFIG_DRM_RCAR_DU=m -CONFIG_DRM_RCAR_USE_CMM=y -CONFIG_DRM_RCAR_CMM=m -CONFIG_DRM_RCAR_DW_HDMI=m -CONFIG_DRM_RCAR_USE_LVDS=y -CONFIG_DRM_RCAR_LVDS=m -CONFIG_DRM_RCAR_USE_MIPI_DSI=y -CONFIG_DRM_RCAR_MIPI_DSI=m -CONFIG_DRM_RCAR_VSP=y -CONFIG_DRM_RCAR_WRITEBACK=y -CONFIG_DRM_RZG2L_DU=m -CONFIG_DRM_RZG2L_USE_MIPI_DSI=y -CONFIG_DRM_RZG2L_MIPI_DSI=m -CONFIG_DRM_SHMOBILE=m -CONFIG_DRM_ROCKCHIP=m -CONFIG_ROCKCHIP_VOP=y -CONFIG_ROCKCHIP_VOP2=y -CONFIG_ROCKCHIP_ANALOGIX_DP=y -CONFIG_ROCKCHIP_CDN_DP=y -CONFIG_ROCKCHIP_DW_DP=y -CONFIG_ROCKCHIP_DW_HDMI=y -CONFIG_ROCKCHIP_DW_HDMI_QP=y -CONFIG_ROCKCHIP_DW_MIPI_DSI=y -CONFIG_ROCKCHIP_DW_MIPI_DSI2=y -CONFIG_ROCKCHIP_INNO_HDMI=y -CONFIG_ROCKCHIP_LVDS=y -CONFIG_ROCKCHIP_RGB=y -CONFIG_ROCKCHIP_RK3066_HDMI=y -CONFIG_DRM_ST7571=m -CONFIG_DRM_ST7571_I2C=m -CONFIG_DRM_ST7571_SPI=m -CONFIG_DRM_ST7586=m -CONFIG_DRM_ST7735R=m -CONFIG_DRM_ST7920=m -CONFIG_DRM_SSD130X=m -CONFIG_DRM_SSD130X_I2C=m -CONFIG_DRM_SSD130X_SPI=m -CONFIG_DRM_SPRD=m -CONFIG_DRM_STM=m -CONFIG_DRM_STM_DSI=m -CONFIG_DRM_STM_LVDS=m -CONFIG_DRM_SUN4I=m -CONFIG_DRM_SUN6I_DSI=m -CONFIG_DRM_SUN8I_DW_HDMI=m -CONFIG_DRM_SUN8I_MIXER=m -CONFIG_DRM_SUN8I_TCON_TOP=m - -# -# Drivers for system framebuffers -# -CONFIG_DRM_SYSFB_HELPER=y -CONFIG_DRM_SIMPLEDRM=y -# end of Drivers for system framebuffers - -CONFIG_DRM_TEGRA=m -# CONFIG_DRM_TEGRA_DEBUG is not set -CONFIG_DRM_TEGRA_STAGING=y -CONFIG_DRM_TIDSS=m -CONFIG_DRM_ARCPGU=m -CONFIG_DRM_BOCHS=m -CONFIG_DRM_CIRRUS_QEMU=m -CONFIG_DRM_GM12U320=m -CONFIG_DRM_PANEL_MIPI_DBI=m -CONFIG_DRM_PIXPAPER=m -CONFIG_TINYDRM_HX8357D=m -CONFIG_TINYDRM_ILI9163=m -CONFIG_TINYDRM_ILI9225=m -CONFIG_TINYDRM_ILI9341=m -CONFIG_TINYDRM_ILI9486=m -CONFIG_TINYDRM_MI0283QT=m -CONFIG_TINYDRM_REPAPER=m -CONFIG_TINYDRM_SHARP_MEMORY=m -CONFIG_DRM_UDL=m -CONFIG_DRM_VGEM=m -CONFIG_DRM_VIRTIO_GPU=m -CONFIG_DRM_VIRTIO_GPU_KMS=y -CONFIG_DRM_VKMS=m -CONFIG_DRM_VMWGFX=m -CONFIG_DRM_XE=m -CONFIG_DRM_XE_DISPLAY=y -CONFIG_DRM_XE_DP_TUNNEL=y -CONFIG_DRM_XE_GPUSVM=y -CONFIG_DRM_XE_PAGEMAP=y -CONFIG_DRM_XE_FORCE_PROBE="" - -# -# drm/Xe Debugging -# -# CONFIG_DRM_XE_WERROR is not set -# CONFIG_DRM_XE_DEBUG is not set -# CONFIG_DRM_XE_DEBUG_VM is not set -# CONFIG_DRM_XE_DEBUG_SRIOV is not set -# CONFIG_DRM_XE_DEBUG_MEMIRQ is not set -# CONFIG_DRM_XE_DEBUG_MEM is not set -# CONFIG_DRM_XE_USERPTR_INVAL_INJECT is not set -# end of drm/Xe Debugging - -# -# drm/xe Profile Guided Optimisation -# -CONFIG_DRM_XE_JOB_TIMEOUT_MAX=10000 -CONFIG_DRM_XE_JOB_TIMEOUT_MIN=1 -CONFIG_DRM_XE_TIMESLICE_MAX=10000000 -CONFIG_DRM_XE_TIMESLICE_MIN=1 -CONFIG_DRM_XE_PREEMPT_TIMEOUT=640000 -CONFIG_DRM_XE_PREEMPT_TIMEOUT_MAX=10000000 -CONFIG_DRM_XE_PREEMPT_TIMEOUT_MIN=1 -CONFIG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT=y -# end of drm/xe Profile Guided Optimisation - -CONFIG_DRM_XEN=y -CONFIG_DRM_XEN_FRONTEND=m -CONFIG_DRM_ZYNQMP_DPSUB=m -CONFIG_DRM_ZYNQMP_DPSUB_AUDIO=y -CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y - -# -# Frame buffer Devices -# -CONFIG_FB=y -CONFIG_FB_SVGALIB=m -CONFIG_FB_CIRRUS=m -CONFIG_FB_PM2=m -CONFIG_FB_PM2_FIFO_DISCONNECT=y -CONFIG_FB_IMX=m -CONFIG_FB_CYBER2000=m -CONFIG_FB_CYBER2000_DDC=y -CONFIG_FB_ASILIANT=y -CONFIG_FB_IMSTT=y -CONFIG_FB_UVESA=m -# CONFIG_FB_EFI is not set -CONFIG_FB_OPENCORES=m -CONFIG_FB_S1D13XXX=m -CONFIG_FB_NVIDIA=m -CONFIG_FB_NVIDIA_I2C=y -# CONFIG_FB_NVIDIA_DEBUG is not set -CONFIG_FB_NVIDIA_BACKLIGHT=y -CONFIG_FB_RIVA=m -CONFIG_FB_RIVA_I2C=y -# CONFIG_FB_RIVA_DEBUG is not set -CONFIG_FB_RIVA_BACKLIGHT=y -CONFIG_FB_I740=m -CONFIG_FB_MATROX=m -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -CONFIG_FB_MATROX_G=y -CONFIG_FB_MATROX_I2C=m -CONFIG_FB_MATROX_MAVEN=m -CONFIG_FB_RADEON=m -CONFIG_FB_RADEON_I2C=y -CONFIG_FB_RADEON_BACKLIGHT=y -# CONFIG_FB_RADEON_DEBUG is not set -CONFIG_FB_ATY128=m -CONFIG_FB_ATY128_BACKLIGHT=y -CONFIG_FB_ATY=m -CONFIG_FB_ATY_CT=y -# CONFIG_FB_ATY_GENERIC_LCD is not set -CONFIG_FB_ATY_GX=y -CONFIG_FB_ATY_BACKLIGHT=y -CONFIG_FB_S3=m -CONFIG_FB_S3_DDC=y -CONFIG_FB_SAVAGE=m -CONFIG_FB_SAVAGE_I2C=y -# CONFIG_FB_SAVAGE_ACCEL is not set -CONFIG_FB_SIS=m -CONFIG_FB_SIS_300=y -CONFIG_FB_SIS_315=y -CONFIG_FB_NEOMAGIC=m -CONFIG_FB_KYRO=m -CONFIG_FB_3DFX=m -# CONFIG_FB_3DFX_ACCEL is not set -# CONFIG_FB_3DFX_I2C is not set -CONFIG_FB_VOODOO1=m -CONFIG_FB_VT8623=m -CONFIG_FB_TRIDENT=m -CONFIG_FB_ARK=m -CONFIG_FB_PM3=m -CONFIG_FB_CARMINE=m -CONFIG_FB_CARMINE_DRAM_EVAL=y -# CONFIG_CARMINE_DRAM_CUSTOM is not set -CONFIG_FB_SM501=m -CONFIG_FB_SMSCUFX=m -CONFIG_FB_UDL=m -# CONFIG_FB_IBM_GXT4500 is not set -CONFIG_FB_XILINX=m -# CONFIG_FB_VIRTUAL is not set -CONFIG_XEN_FBDEV_FRONTEND=m -CONFIG_FB_METRONOME=m -CONFIG_FB_MB862XX=m -CONFIG_FB_MB862XX_PCI_GDC=y -CONFIG_FB_MB862XX_I2C=y -CONFIG_FB_SSD1307=m -CONFIG_FB_SM712=m -CONFIG_FB_CORE=y -CONFIG_FB_NOTIFY=y -CONFIG_FB_DEVICE=y -CONFIG_FB_DDC=m -CONFIG_FB_CFB_FILLRECT=y -CONFIG_FB_CFB_COPYAREA=y -CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_CFB_REV_PIXELS_IN_BYTE=y -CONFIG_FB_SYS_FILLRECT=y -CONFIG_FB_SYS_COPYAREA=y -CONFIG_FB_SYS_IMAGEBLIT=y -CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA=y -# CONFIG_FB_FOREIGN_ENDIAN is not set -CONFIG_FB_SYSMEM_FOPS=y -CONFIG_FB_DEFERRED_IO=y -CONFIG_FB_DMAMEM_HELPERS=y -CONFIG_FB_DMAMEM_HELPERS_DEFERRED=y -CONFIG_FB_IOMEM_FOPS=y -CONFIG_FB_IOMEM_HELPERS=y -CONFIG_FB_SYSMEM_HELPERS=y -CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y -CONFIG_FB_BACKLIGHT=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_TILEBLITTING=y -# end of Frame buffer Devices - -# -# Backlight & LCD device support -# -CONFIG_LCD_CLASS_DEVICE=m -CONFIG_LCD_L4F00242T03=m -CONFIG_LCD_LMS283GF05=m -CONFIG_LCD_LTV350QV=m -CONFIG_LCD_ILI922X=m -CONFIG_LCD_ILI9320=m -CONFIG_LCD_TDO24M=m -CONFIG_LCD_VGG2432A4=m -CONFIG_LCD_PLATFORM=m -CONFIG_LCD_AMS369FG06=m -CONFIG_LCD_LMS501KF03=m -CONFIG_LCD_HX8357=m -CONFIG_LCD_OTM3225A=m -CONFIG_BACKLIGHT_CLASS_DEVICE=y -CONFIG_BACKLIGHT_AW99706=m -CONFIG_BACKLIGHT_KTD253=m -CONFIG_BACKLIGHT_KTD2801=m -CONFIG_BACKLIGHT_KTZ8866=m -CONFIG_BACKLIGHT_LM3533=m -CONFIG_BACKLIGHT_PWM=m -CONFIG_BACKLIGHT_DA903X=m -CONFIG_BACKLIGHT_DA9052=m -# CONFIG_BACKLIGHT_MAX25014 is not set -CONFIG_BACKLIGHT_MAX8925=m -CONFIG_BACKLIGHT_MT6370=m -CONFIG_BACKLIGHT_APPLE_DWI=m -CONFIG_BACKLIGHT_QCOM_WLED=m -CONFIG_BACKLIGHT_RT4831=m -CONFIG_BACKLIGHT_WM831X=m -CONFIG_BACKLIGHT_ADP5520=m -CONFIG_BACKLIGHT_ADP8860=m -CONFIG_BACKLIGHT_ADP8870=m -CONFIG_BACKLIGHT_88PM860X=m -CONFIG_BACKLIGHT_AAT2870=m -CONFIG_BACKLIGHT_LM3509=m -CONFIG_BACKLIGHT_LM3630A=m -CONFIG_BACKLIGHT_LM3639=m -CONFIG_BACKLIGHT_LP855X=m -CONFIG_BACKLIGHT_LP8788=m -CONFIG_BACKLIGHT_MP3309C=m -CONFIG_BACKLIGHT_PANDORA=m -CONFIG_BACKLIGHT_SKY81452=m -CONFIG_BACKLIGHT_TPS65217=m -CONFIG_BACKLIGHT_AS3711=m -CONFIG_BACKLIGHT_GPIO=m -CONFIG_BACKLIGHT_LV5207LP=m -CONFIG_BACKLIGHT_BD6107=m -CONFIG_BACKLIGHT_ARCXCNN=m -CONFIG_BACKLIGHT_RAVE_SP=m -CONFIG_BACKLIGHT_LED=m -# end of Backlight & LCD device support - -CONFIG_VGASTATE=m -CONFIG_VIDEOMODE_HELPERS=y -CONFIG_HDMI=y -# CONFIG_FIRMWARE_EDID is not set - -# -# Console display driver support -# -CONFIG_DUMMY_CONSOLE=y -CONFIG_DUMMY_CONSOLE_COLUMNS=80 -CONFIG_DUMMY_CONSOLE_ROWS=25 -CONFIG_FRAMEBUFFER_CONSOLE=y -# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y -CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y -CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y -# end of Console display driver support - -# CONFIG_LOGO is not set -CONFIG_TRACE_GPU_MEM=y -# end of Graphics support - -CONFIG_DRM_ACCEL=y -CONFIG_DRM_ACCEL_ARM_ETHOSU=m -CONFIG_DRM_ACCEL_QAIC=m -CONFIG_DRM_ACCEL_ROCKET=m -CONFIG_SOUND=m -CONFIG_SOUND_OSS_CORE=y -# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set -CONFIG_SND=m -CONFIG_SND_TIMER=m -CONFIG_SND_PCM=m -CONFIG_SND_PCM_ELD=y -CONFIG_SND_PCM_IEC958=y -CONFIG_SND_DMAENGINE_PCM=m -CONFIG_SND_HWDEP=m -CONFIG_SND_SEQ_DEVICE=m -CONFIG_SND_RAWMIDI=m -CONFIG_SND_UMP=m -CONFIG_SND_UMP_LEGACY_RAWMIDI=y -CONFIG_SND_COMPRESS_OFFLOAD=m -CONFIG_SND_COMPRESS_ACCEL=y -CONFIG_SND_JACK=y -CONFIG_SND_JACK_INPUT_DEV=y -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=m -# CONFIG_SND_PCM_OSS is not set -CONFIG_SND_PCM_TIMER=y -CONFIG_SND_HRTIMER=m -CONFIG_SND_DYNAMIC_MINORS=y -CONFIG_SND_MAX_CARDS=32 -CONFIG_SND_SUPPORT_OLD_API=y -CONFIG_SND_PROC_FS=y -CONFIG_SND_VERBOSE_PROCFS=y -# CONFIG_SND_CTL_FAST_LOOKUP is not set -# CONFIG_SND_DEBUG is not set -# CONFIG_SND_CTL_INPUT_VALIDATION is not set -CONFIG_SND_UTIMER=y -CONFIG_SND_VMASTER=y -CONFIG_SND_CTL_LED=m -CONFIG_SND_SEQUENCER=m -CONFIG_SND_SEQ_DUMMY=m -# CONFIG_SND_SEQUENCER_OSS is not set -CONFIG_SND_SEQ_HRTIMER_DEFAULT=y -CONFIG_SND_SEQ_MIDI_EVENT=m -CONFIG_SND_SEQ_MIDI=m -CONFIG_SND_SEQ_MIDI_EMUL=m -CONFIG_SND_SEQ_VIRMIDI=m -CONFIG_SND_SEQ_UMP=y -CONFIG_SND_SEQ_UMP_CLIENT=m -CONFIG_SND_MPU401_UART=m -CONFIG_SND_OPL3_LIB=m -CONFIG_SND_OPL3_LIB_SEQ=m -CONFIG_SND_VX_LIB=m -CONFIG_SND_AC97_CODEC=m -CONFIG_SND_DRIVERS=y -CONFIG_SND_DUMMY=m -CONFIG_SND_ALOOP=m -CONFIG_SND_PCMTEST=m -CONFIG_SND_VIRMIDI=m -CONFIG_SND_MTPAV=m -CONFIG_SND_MTS64=m -CONFIG_SND_SERIAL_U16550=m -CONFIG_SND_SERIAL_GENERIC=m -CONFIG_SND_MPU401=m -CONFIG_SND_PORTMAN2X4=m -CONFIG_SND_AC97_POWER_SAVE=y -CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 -CONFIG_SND_PCI=y -CONFIG_SND_AD1889=m -CONFIG_SND_ALS300=m -CONFIG_SND_ALI5451=m -CONFIG_SND_ATIIXP=m -CONFIG_SND_ATIIXP_MODEM=m -CONFIG_SND_AU8810=m -CONFIG_SND_AU8820=m -CONFIG_SND_AU8830=m -CONFIG_SND_AW2=m -CONFIG_SND_AZT3328=m -CONFIG_SND_BT87X=m -# CONFIG_SND_BT87X_OVERCLOCK is not set -CONFIG_SND_CA0106=m -CONFIG_SND_CMIPCI=m -CONFIG_SND_OXYGEN_LIB=m -CONFIG_SND_OXYGEN=m -CONFIG_SND_CS4281=m -CONFIG_SND_CS46XX=m -CONFIG_SND_CS46XX_NEW_DSP=y -CONFIG_SND_CTXFI=m -CONFIG_SND_DARLA20=m -CONFIG_SND_GINA20=m -CONFIG_SND_LAYLA20=m -CONFIG_SND_DARLA24=m -CONFIG_SND_GINA24=m -CONFIG_SND_LAYLA24=m -CONFIG_SND_MONA=m -CONFIG_SND_MIA=m -CONFIG_SND_ECHO3G=m -CONFIG_SND_INDIGO=m -CONFIG_SND_INDIGOIO=m -CONFIG_SND_INDIGODJ=m -CONFIG_SND_INDIGOIOX=m -CONFIG_SND_INDIGODJX=m -CONFIG_SND_EMU10K1=m -CONFIG_SND_EMU10K1_SEQ=m -CONFIG_SND_EMU10K1X=m -CONFIG_SND_ENS1370=m -CONFIG_SND_ENS1371=m -CONFIG_SND_ES1938=m -CONFIG_SND_ES1968=m -CONFIG_SND_ES1968_INPUT=y -CONFIG_SND_ES1968_RADIO=y -CONFIG_SND_FM801=m -CONFIG_SND_FM801_TEA575X_BOOL=y -CONFIG_SND_HDSP=m -CONFIG_SND_HDSPM=m -CONFIG_SND_ICE1712=m -CONFIG_SND_ICE1724=m -CONFIG_SND_INTEL8X0=m -CONFIG_SND_INTEL8X0M=m -CONFIG_SND_KORG1212=m -CONFIG_SND_LOLA=m -CONFIG_SND_LX6464ES=m -CONFIG_SND_MAESTRO3=m -CONFIG_SND_MAESTRO3_INPUT=y -CONFIG_SND_MIXART=m -CONFIG_SND_NM256=m -CONFIG_SND_PCXHR=m -CONFIG_SND_RIPTIDE=m -CONFIG_SND_RME32=m -CONFIG_SND_RME96=m -CONFIG_SND_RME9652=m -CONFIG_SND_SONICVIBES=m -CONFIG_SND_TRIDENT=m -CONFIG_SND_VIA82XX=m -CONFIG_SND_VIA82XX_MODEM=m -CONFIG_SND_VIRTUOSO=m -CONFIG_SND_VX222=m -CONFIG_SND_YMFPCI=m - -# -# HD-Audio -# -CONFIG_SND_HDA=m -CONFIG_SND_HDA_HWDEP=y -CONFIG_SND_HDA_RECONFIG=y -CONFIG_SND_HDA_INPUT_BEEP=y -CONFIG_SND_HDA_INPUT_BEEP_MODE=0 -CONFIG_SND_HDA_PATCH_LOADER=y -CONFIG_SND_HDA_POWER_SAVE_DEFAULT=1 -# CONFIG_SND_HDA_CTL_DEV_ID is not set -CONFIG_SND_HDA_PREALLOC_SIZE=64 -CONFIG_SND_HDA_INTEL=m -CONFIG_SND_HDA_TEGRA=m -CONFIG_SND_HDA_CIX_IPBLOQ=m -CONFIG_SND_HDA_ACPI=m -CONFIG_SND_HDA_GENERIC_LEDS=y -CONFIG_SND_HDA_CODEC_ANALOG=m -CONFIG_SND_HDA_CODEC_SIGMATEL=m -CONFIG_SND_HDA_CODEC_VIA=m -CONFIG_SND_HDA_CODEC_CONEXANT=m -CONFIG_SND_HDA_CODEC_SENARYTECH=m -CONFIG_SND_HDA_CODEC_CA0110=m -CONFIG_SND_HDA_CODEC_CA0132=m -CONFIG_SND_HDA_CODEC_CA0132_DSP=y -CONFIG_SND_HDA_CODEC_CMEDIA=m -CONFIG_SND_HDA_CODEC_CM9825=m -CONFIG_SND_HDA_CODEC_SI3054=m -CONFIG_SND_HDA_GENERIC=m -CONFIG_SND_HDA_CODEC_REALTEK=m -CONFIG_SND_HDA_CODEC_REALTEK_LIB=m -CONFIG_SND_HDA_CODEC_ALC260=m -CONFIG_SND_HDA_CODEC_ALC262=m -CONFIG_SND_HDA_CODEC_ALC268=m -CONFIG_SND_HDA_CODEC_ALC269=m -CONFIG_SND_HDA_CODEC_ALC662=m -CONFIG_SND_HDA_CODEC_ALC680=m -CONFIG_SND_HDA_CODEC_ALC861=m -CONFIG_SND_HDA_CODEC_ALC861VD=m -CONFIG_SND_HDA_CODEC_ALC880=m -CONFIG_SND_HDA_CODEC_ALC882=m -CONFIG_SND_HDA_CODEC_CIRRUS=m -CONFIG_SND_HDA_CODEC_CS420X=m -CONFIG_SND_HDA_CODEC_CS421X=m -CONFIG_SND_HDA_CODEC_CS8409=m -CONFIG_SND_HDA_CODEC_HDMI=m -CONFIG_SND_HDA_CODEC_HDMI_GENERIC=m -CONFIG_SND_HDA_CODEC_HDMI_SIMPLE=m -CONFIG_SND_HDA_CODEC_HDMI_INTEL=m -# CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM is not set -CONFIG_SND_HDA_CODEC_HDMI_ATI=m -CONFIG_SND_HDA_CODEC_HDMI_NVIDIA=m -CONFIG_SND_HDA_CODEC_HDMI_NVIDIA_MCP=m -CONFIG_SND_HDA_CODEC_HDMI_TEGRA=m -CONFIG_SND_HDA_CIRRUS_SCODEC=m -# CONFIG_SND_HDA_SCODEC_AW88399_I2C is not set -CONFIG_SND_HDA_SCODEC_CS35L41=m -CONFIG_SND_HDA_SCODEC_COMPONENT=m -CONFIG_SND_HDA_SCODEC_CS35L41_I2C=m -CONFIG_SND_HDA_SCODEC_CS35L41_SPI=m -CONFIG_SND_HDA_SCODEC_CS35L56=m -CONFIG_SND_HDA_SCODEC_CS35L56_I2C=m -CONFIG_SND_HDA_SCODEC_CS35L56_SPI=m - -# -# CS35L56 driver options -# -# CONFIG_SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS is not set -# end of CS35L56 driver options - -CONFIG_SND_HDA_SCODEC_TAS2781=m -CONFIG_SND_HDA_SCODEC_TAS2781_I2C=m -CONFIG_SND_HDA_SCODEC_TAS2781_SPI=m -CONFIG_SND_HDA_CORE=m -CONFIG_SND_HDA_DSP_LOADER=y -CONFIG_SND_HDA_ALIGNED_MMIO=y -CONFIG_SND_HDA_COMPONENT=y -CONFIG_SND_HDA_I915=y -CONFIG_SND_HDA_EXT_CORE=m -CONFIG_SND_INTEL_NHLT=y -CONFIG_SND_INTEL_DSP_CONFIG=m -CONFIG_SND_INTEL_SOUNDWIRE_ACPI=m -# end of HD-Audio - -CONFIG_SND_SPI=y -CONFIG_SND_USB=y -CONFIG_SND_USB_AUDIO=m -CONFIG_SND_USB_AUDIO_MIDI_V2=y -CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER=y -CONFIG_SND_USB_UA101=m -CONFIG_SND_USB_CAIAQ=m -CONFIG_SND_USB_CAIAQ_INPUT=y -CONFIG_SND_USB_6FIRE=m -CONFIG_SND_USB_HIFACE=m -CONFIG_SND_BCD2000=m -CONFIG_SND_USB_AUDIO_QMI=m -CONFIG_SND_USB_LINE6=m -CONFIG_SND_USB_POD=m -CONFIG_SND_USB_PODHD=m -CONFIG_SND_USB_TONEPORT=m -CONFIG_SND_USB_VARIAX=m -CONFIG_SND_FIREWIRE=y -CONFIG_SND_FIREWIRE_LIB=m -CONFIG_SND_DICE=m -CONFIG_SND_OXFW=m -CONFIG_SND_ISIGHT=m -CONFIG_SND_FIREWORKS=m -CONFIG_SND_BEBOB=m -CONFIG_SND_FIREWIRE_DIGI00X=m -CONFIG_SND_FIREWIRE_TASCAM=m -CONFIG_SND_FIREWIRE_MOTU=m -CONFIG_SND_FIREFACE=m -CONFIG_SND_SOC=m -CONFIG_SND_SOC_AC97_BUS=y -CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y -CONFIG_SND_SOC_COMPRESS=y -CONFIG_SND_SOC_TOPOLOGY=y -CONFIG_SND_SOC_ACPI=m -CONFIG_SND_SOC_USB=m - -# -# Analog Devices -# -CONFIG_SND_SOC_ADI_AXI_I2S=m -CONFIG_SND_SOC_ADI_AXI_SPDIF=m -# end of Analog Devices - -# -# AMD -# -CONFIG_SND_SOC_AMD_ACP=m -CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH=m -CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m -CONFIG_SND_SOC_AMD_ST_ES8336_MACH=m -CONFIG_SND_AMD_ACP_CONFIG=m -# end of AMD - -# -# Apple -# -CONFIG_SND_SOC_APPLE_MCA=m -# end of Apple - -# -# Atmel -# -CONFIG_SND_SOC_MIKROE_PROTO=m -# end of Atmel - -# -# Au1x -# -# end of Au1x - -# -# Broadcom -# -CONFIG_SND_BCM63XX_I2S_WHISTLER=m -# end of Broadcom - -# -# Cirrus Logic -# -# end of Cirrus Logic - -# -# DesignWare -# -CONFIG_SND_DESIGNWARE_I2S=m -CONFIG_SND_DESIGNWARE_PCM=y -# end of DesignWare - -# -# Freescale -# - -# -# Common SoC Audio options for Freescale CPUs: -# -CONFIG_SND_SOC_FSL_ASRC=m -CONFIG_SND_SOC_FSL_SAI=m -CONFIG_SND_SOC_FSL_MQS=m -CONFIG_SND_SOC_FSL_AUDMIX=m -CONFIG_SND_SOC_FSL_SSI=m -CONFIG_SND_SOC_FSL_SPDIF=m -CONFIG_SND_SOC_FSL_ESAI=m -CONFIG_SND_SOC_FSL_MICFIL=m -CONFIG_SND_SOC_FSL_EASRC=m -CONFIG_SND_SOC_FSL_XCVR=m -CONFIG_SND_SOC_FSL_AUD2HTX=m -CONFIG_SND_SOC_FSL_UTILS=m -CONFIG_SND_SOC_FSL_RPMSG=m -CONFIG_SND_SOC_IMX_PCM_DMA=m -CONFIG_SND_SOC_IMX_AUDIO_RPMSG=m -CONFIG_SND_SOC_IMX_PCM_RPMSG=m -CONFIG_SND_SOC_IMX_AUDMUX=m -CONFIG_SND_IMX_SOC=m - -# -# SoC Audio support for Freescale i.MX boards: -# -CONFIG_SND_SOC_IMX_ES8328=m -CONFIG_SND_SOC_IMX_SGTL5000=m -CONFIG_SND_SOC_FSL_ASOC_CARD=m -CONFIG_SND_SOC_IMX_AUDMIX=m -CONFIG_SND_SOC_IMX_HDMI=m -CONFIG_SND_SOC_IMX_RPMSG=m -CONFIG_SND_SOC_IMX_CARD=m -# end of Freescale - -# -# Google -# -CONFIG_SND_SOC_CHV3_I2S=m -# end of Google - -# -# Hisilicon -# -CONFIG_SND_I2S_HI6210_I2S=m -# end of Hisilicon - -# -# JZ4740 -# -# end of JZ4740 - -# -# Kirkwood -# -CONFIG_SND_KIRKWOOD_SOC=m -CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB=m -# end of Kirkwood - -# -# Loongson -# -# end of Loongson - -# -# Intel -# -CONFIG_SND_SOC_INTEL_KEEMBAY=m -# end of Intel - -# -# Mediatek -# -CONFIG_SND_SOC_MEDIATEK=m -# CONFIG_SND_SOC_MT2701 is not set -CONFIG_SND_SOC_MT6797=m -CONFIG_SND_SOC_MT6797_MT6351=m -CONFIG_SND_SOC_MT7986=m -CONFIG_SND_SOC_MT7986_WM8960=m -# CONFIG_SND_SOC_MT8173 is not set -CONFIG_SND_SOC_MT8183=m -CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A=m -CONFIG_SND_SOC_MT8183_DA7219_MAX98357A=m -CONFIG_SND_SOC_MT8186=m -CONFIG_SND_SOC_MT8186_MT6366=m -CONFIG_SND_SOC_MTK_BTCVSD=m -CONFIG_SND_SOC_MTK_SDCA=m -CONFIG_SND_SOC_MT8188=m -CONFIG_SND_SOC_MT8188_MT6359=m -CONFIG_SND_SOC_MT8189=m -CONFIG_SND_SOC_MT8189_NAU8825=m -CONFIG_SND_SOC_MT8192=m -CONFIG_SND_SOC_MT8192_MT6359_RT1015_RT5682=m -CONFIG_SND_SOC_MT8195=m -CONFIG_SND_SOC_MT8195_MT6359=m -CONFIG_SND_SOC_MT8365=m -CONFIG_SND_SOC_MT8365_MT6357=m -# CONFIG_SND_SOC_MT8196 is not set -CONFIG_SND_SOC_MT8901=m -CONFIG_SND_SOC_MT8901_LEGACY_SDW_MACH=m -# end of Mediatek - -# -# Amlogic -# -CONFIG_SND_MESON_AIU=m -CONFIG_SND_MESON_AXG_FIFO=m -CONFIG_SND_MESON_AXG_FRDDR=m -CONFIG_SND_MESON_AXG_TODDR=m -CONFIG_SND_MESON_AXG_TDM_FORMATTER=m -CONFIG_SND_MESON_AXG_TDM_INTERFACE=m -CONFIG_SND_MESON_AXG_TDMIN=m -CONFIG_SND_MESON_AXG_TDMOUT=m -CONFIG_SND_MESON_AXG_SOUND_CARD=m -CONFIG_SND_MESON_AXG_SPDIFOUT=m -CONFIG_SND_MESON_AXG_SPDIFIN=m -CONFIG_SND_MESON_AXG_PDM=m -CONFIG_SND_MESON_CARD_UTILS=m -CONFIG_SND_MESON_CODEC_GLUE=m -CONFIG_SND_MESON_GX_SOUND_CARD=m -CONFIG_SND_MESON_G12A_TOACODEC=m -CONFIG_SND_MESON_G12A_TOHDMITX=m -CONFIG_SND_SOC_MESON_T9015=m -# end of Amlogic - -# -# PXA -# -CONFIG_SND_MMP_SOC_SSPA=m -CONFIG_SND_PXA910_SOC=m -# end of PXA - -CONFIG_SND_SOC_QCOM=m -CONFIG_SND_SOC_LPASS_CPU=m -CONFIG_SND_SOC_LPASS_HDMI=m -CONFIG_SND_SOC_LPASS_PLATFORM=m -CONFIG_SND_SOC_LPASS_CDC_DMA=m -CONFIG_SND_SOC_LPASS_IPQ806X=m -CONFIG_SND_SOC_LPASS_APQ8016=m -CONFIG_SND_SOC_LPASS_SC7180=m -CONFIG_SND_SOC_LPASS_SC7280=m -CONFIG_SND_SOC_STORM=m -CONFIG_SND_SOC_APQ8016_SBC=m -CONFIG_SND_SOC_QCOM_COMMON=m -CONFIG_SND_SOC_QCOM_SDW=m -CONFIG_SND_SOC_QDSP6_COMMON=m -CONFIG_SND_SOC_QDSP6_CORE=m -CONFIG_SND_SOC_QDSP6_AFE=m -CONFIG_SND_SOC_QDSP6_AFE_DAI=m -CONFIG_SND_SOC_QDSP6_AFE_CLOCKS=m -CONFIG_SND_SOC_QDSP6_ADM=m -CONFIG_SND_SOC_QDSP6_ROUTING=m -CONFIG_SND_SOC_QDSP6_ASM=m -CONFIG_SND_SOC_QDSP6_ASM_DAI=m -CONFIG_SND_SOC_QDSP6_APM_DAI=m -CONFIG_SND_SOC_QDSP6_APM_LPASS_DAI=m -CONFIG_SND_SOC_QDSP6_APM=m -CONFIG_SND_SOC_QDSP6_PRM_LPASS_CLOCKS=m -CONFIG_SND_SOC_QDSP6_PRM=m -CONFIG_SND_SOC_QCOM_OFFLOAD_UTILS=m -CONFIG_SND_SOC_QDSP6_USB=m -CONFIG_SND_SOC_QDSP6=m -CONFIG_SND_SOC_MSM8996=m -CONFIG_SND_SOC_SDM845=m -CONFIG_SND_SOC_SM8250=m -CONFIG_SND_SOC_SC8280XP=m -CONFIG_SND_SOC_SC7180=m -CONFIG_SND_SOC_SC7280=m -CONFIG_SND_SOC_X1E80100=m - -# -# Renesas -# -CONFIG_SND_SOC_SH4_FSI=m -CONFIG_SND_SOC_RCAR=m -CONFIG_SND_SOC_MSIOF=m -CONFIG_SND_SOC_RZ=m -# end of Renesas - -# -# Rockchip -# -CONFIG_SND_SOC_ROCKCHIP_I2S=m -CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=m -CONFIG_SND_SOC_ROCKCHIP_PDM=m -CONFIG_SND_SOC_ROCKCHIP_SAI=m -CONFIG_SND_SOC_ROCKCHIP_SPDIF=m -CONFIG_SND_SOC_ROCKCHIP_MAX98090=m -CONFIG_SND_SOC_ROCKCHIP_RT5645=m -CONFIG_SND_SOC_RK3288_HDMI_ANALOG=m -CONFIG_SND_SOC_RK3399_GRU_SOUND=m -# end of Rockchip - -# -# SoundWire (SDCA) -# -CONFIG_SND_SOC_SDCA=m -CONFIG_SND_SOC_SDCA_HID=y -CONFIG_SND_SOC_SDCA_IRQ=y -CONFIG_SND_SOC_SDCA_FDL=y -CONFIG_SND_SOC_SDCA_OPTIONAL=m -# CONFIG_SND_SOC_SDCA_CLASS is not set -# end of SoundWire (SDCA) - -# -# Sophgo -# -CONFIG_SND_SOC_CV1800B_TDM=m -CONFIG_SND_SOC_CV1800B_ADC_CODEC=m -CONFIG_SND_SOC_CV1800B_DAC_CODEC=m -# end of Sophgo - -# -# ST SPEAr -# -# end of ST SPEAr - -# -# Spreadtrum -# -CONFIG_SND_SOC_SPRD=m -CONFIG_SND_SOC_SPRD_MCDT=m -# end of Spreadtrum - -# -# STMicroelectronics STM32 -# -CONFIG_SND_SOC_STM32_SAI=m -CONFIG_SND_SOC_STM32_I2S=m -CONFIG_SND_SOC_STM32_SPDIFRX=m -CONFIG_SND_SOC_STM32_DFSDM=m -# end of STMicroelectronics STM32 - -# -# Allwinner -# -# CONFIG_SND_SUN4I_CODEC is not set -CONFIG_SND_SUN8I_CODEC=m -CONFIG_SND_SUN8I_CODEC_ANALOG=m -CONFIG_SND_SUN50I_CODEC_ANALOG=m -# CONFIG_SND_SUN4I_I2S is not set -# CONFIG_SND_SUN4I_SPDIF is not set -CONFIG_SND_SUN50I_DMIC=m -CONFIG_SND_SUN8I_ADDA_PR_REGMAP=m -# end of Allwinner - -# -# Tegra -# -CONFIG_SND_SOC_TEGRA=m -CONFIG_SND_SOC_TEGRA20_AC97=m -CONFIG_SND_SOC_TEGRA20_DAS=m -CONFIG_SND_SOC_TEGRA20_I2S=m -CONFIG_SND_SOC_TEGRA20_SPDIF=m -CONFIG_SND_SOC_TEGRA30_AHUB=m -CONFIG_SND_SOC_TEGRA30_I2S=m -CONFIG_SND_SOC_TEGRA210_AHUB=m -CONFIG_SND_SOC_TEGRA210_DMIC=m -CONFIG_SND_SOC_TEGRA210_I2S=m -CONFIG_SND_SOC_TEGRA210_OPE=m -CONFIG_SND_SOC_TEGRA186_ASRC=m -CONFIG_SND_SOC_TEGRA186_DSPK=m -CONFIG_SND_SOC_TEGRA210_ADMAIF=m -CONFIG_SND_SOC_TEGRA210_MVC=m -CONFIG_SND_SOC_TEGRA210_SFC=m -CONFIG_SND_SOC_TEGRA210_AMX=m -CONFIG_SND_SOC_TEGRA210_ADX=m -CONFIG_SND_SOC_TEGRA210_MIXER=m -CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD=m -CONFIG_SND_SOC_TEGRA_MACHINE_DRV=m -CONFIG_SND_SOC_TEGRA_RT5631=m -CONFIG_SND_SOC_TEGRA_RT5640=m -CONFIG_SND_SOC_TEGRA_WM8753=m -CONFIG_SND_SOC_TEGRA_WM8903=m -# CONFIG_SND_SOC_TEGRA_WM8962 is not set -CONFIG_SND_SOC_TEGRA_WM9712=m -CONFIG_SND_SOC_TEGRA_TRIMSLICE=m -CONFIG_SND_SOC_TEGRA_ALC5632=m -CONFIG_SND_SOC_TEGRA_MAX98090=m -CONFIG_SND_SOC_TEGRA_MAX98088=m -CONFIG_SND_SOC_TEGRA_RT5677=m -CONFIG_SND_SOC_TEGRA_SGTL5000=m -# CONFIG_SND_SOC_TEGRA_CPCAP is not set -# end of Tegra - -# -# Texas Instruments -# -CONFIG_SND_SOC_TI_EDMA_PCM=m -CONFIG_SND_SOC_TI_SDMA_PCM=m -CONFIG_SND_SOC_TI_UDMA_PCM=m - -# -# Texas Instruments DAI support for: -# -CONFIG_SND_SOC_DAVINCI_MCASP=m - -# -# Audio support for boards with Texas Instruments SoCs -# -CONFIG_SND_SOC_J721E_EVM=m -# end of Texas Instruments - -# -# Xilinx -# -CONFIG_SND_SOC_XILINX_I2S=m -CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER=m -CONFIG_SND_SOC_XILINX_SPDIF=m -# end of Xilinx - -# -# Xtensa -# -CONFIG_SND_SOC_XTFPGA_I2S=m -# end of Xtensa - -CONFIG_SND_SOC_SOF_TOPLEVEL=y -CONFIG_SND_SOC_SOF_PCI=m -CONFIG_SND_SOC_SOF_ACPI=m -CONFIG_SND_SOC_SOF_OF=m -CONFIG_SND_SOC_SOF_OF_DEV=m -CONFIG_SND_SOC_SOF_COMPRESS=y -# CONFIG_SND_SOC_SOF_DEVELOPER_SUPPORT is not set -CONFIG_SND_SOC_SOF=m -CONFIG_SND_SOC_SOF_IPC3=y -CONFIG_SND_SOC_SOF_IMX_TOPLEVEL=y -CONFIG_SND_SOC_SOF_IMX_COMMON=m -CONFIG_SND_SOC_SOF_IMX8=m -CONFIG_SND_SOC_SOF_IMX9=m -CONFIG_SND_SOC_SOF_MTK_TOPLEVEL=y -CONFIG_SND_SOC_SOF_MTK_COMMON=m -CONFIG_SND_SOC_SOF_MT8186=m -CONFIG_SND_SOC_SOF_MT8195=m -CONFIG_SND_SOC_SOF_MT8901=m -CONFIG_SND_SOC_SOF_XTENSA=m -CONFIG_SND_SOC_I2C_AND_SPI=m - -# -# CODEC drivers -# -CONFIG_SND_SOC_ARIZONA=m -CONFIG_SND_SOC_WM_HUBS=m -CONFIG_SND_SOC_WM_ADSP=m -CONFIG_SND_SOC_AC97_CODEC=m -CONFIG_SND_SOC_ADAU_UTILS=m -CONFIG_SND_SOC_ADAU1372=m -CONFIG_SND_SOC_ADAU1372_I2C=m -CONFIG_SND_SOC_ADAU1372_SPI=m -CONFIG_SND_SOC_ADAU1373=m -CONFIG_SND_SOC_ADAU1701=m -CONFIG_SND_SOC_ADAU17X1=m -CONFIG_SND_SOC_ADAU1761=m -CONFIG_SND_SOC_ADAU1761_I2C=m -CONFIG_SND_SOC_ADAU1761_SPI=m -# CONFIG_SND_SOC_ADAU1977_SPI is not set -# CONFIG_SND_SOC_ADAU1977_I2C is not set -CONFIG_SND_SOC_ADAU7002=m -CONFIG_SND_SOC_ADAU7118=m -CONFIG_SND_SOC_ADAU7118_HW=m -CONFIG_SND_SOC_ADAU7118_I2C=m -CONFIG_SND_SOC_AK4104=m -CONFIG_SND_SOC_AK4118=m -CONFIG_SND_SOC_AK4375=m -CONFIG_SND_SOC_AK4458=m -CONFIG_SND_SOC_AK4554=m -CONFIG_SND_SOC_AK4613=m -CONFIG_SND_SOC_AK4619=m -CONFIG_SND_SOC_AK4642=m -CONFIG_SND_SOC_AK5386=m -CONFIG_SND_SOC_AK5558=m -CONFIG_SND_SOC_ALC5623=m -CONFIG_SND_SOC_ALC5632=m -CONFIG_SND_SOC_AUDIO_IIO_AUX=m -CONFIG_SND_SOC_AW8738=m -CONFIG_SND_SOC_AW88395_LIB=m -CONFIG_SND_SOC_AW88395=m -CONFIG_SND_SOC_AW88166=m -CONFIG_SND_SOC_AW88261=m -CONFIG_SND_SOC_AW88081=m -CONFIG_SND_SOC_AW87390=m -CONFIG_SND_SOC_AW88399_LIB=m -CONFIG_SND_SOC_AW88399=m -CONFIG_SND_SOC_BD28623=m -CONFIG_SND_SOC_BT_SCO=m -CONFIG_SND_SOC_CHV3_CODEC=m -CONFIG_SND_SOC_CPCAP=m -CONFIG_SND_SOC_CROS_EC_CODEC=m -CONFIG_SND_SOC_CS_AMP_LIB=m -CONFIG_SND_SOC_CS35L32=m -CONFIG_SND_SOC_CS35L33=m -CONFIG_SND_SOC_CS35L34=m -CONFIG_SND_SOC_CS35L35=m -CONFIG_SND_SOC_CS35L36=m -CONFIG_SND_SOC_CS35L41_LIB=m -CONFIG_SND_SOC_CS35L41=m -CONFIG_SND_SOC_CS35L41_SPI=m -CONFIG_SND_SOC_CS35L41_I2C=m -CONFIG_SND_SOC_CS35L45=m -CONFIG_SND_SOC_CS35L45_SPI=m -CONFIG_SND_SOC_CS35L45_I2C=m -CONFIG_SND_SOC_CS35L56=m -CONFIG_SND_SOC_CS35L56_SHARED=m -CONFIG_SND_SOC_CS35L56_I2C=m -CONFIG_SND_SOC_CS35L56_SPI=m -CONFIG_SND_SOC_CS35L56_SDW=m - -# -# CS35L56 driver options -# -# CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS is not set -# CONFIG_SND_SOC_CS35L56_CAL_SET_CTRL is not set -# CONFIG_SND_SOC_CS35L56_CAL_PERFORM_CTRL is not set -# end of CS35L56 driver options - -CONFIG_SND_SOC_CS40L50=m -CONFIG_SND_SOC_CS42L42_CORE=m -CONFIG_SND_SOC_CS42L42=m -CONFIG_SND_SOC_CS42L42_SDW=m -CONFIG_SND_SOC_CS42L43=m -CONFIG_SND_SOC_CS42L43_SDW=m -CONFIG_SND_SOC_CS42L51=m -CONFIG_SND_SOC_CS42L51_I2C=m -CONFIG_SND_SOC_CS42L52=m -CONFIG_SND_SOC_CS42L56=m -CONFIG_SND_SOC_CS42L73=m -CONFIG_SND_SOC_CS42L83=m -CONFIG_SND_SOC_CS42L84=m -CONFIG_SND_SOC_CS4234=m -CONFIG_SND_SOC_CS4265=m -CONFIG_SND_SOC_CS4270=m -CONFIG_SND_SOC_CS4271=m -CONFIG_SND_SOC_CS4271_I2C=m -CONFIG_SND_SOC_CS4271_SPI=m -CONFIG_SND_SOC_CS42XX8=m -# CONFIG_SND_SOC_CS42XX8_SPI is not set -CONFIG_SND_SOC_CS42XX8_I2C=m -CONFIG_SND_SOC_CS43130=m -CONFIG_SND_SOC_CS4341=m -CONFIG_SND_SOC_CS4349=m -CONFIG_SND_SOC_CS48L32=m -CONFIG_SND_SOC_CS53L30=m -CONFIG_SND_SOC_CS530X=m -CONFIG_SND_SOC_CS530X_I2C=m -CONFIG_SND_SOC_CS530X_SPI=m -CONFIG_SND_SOC_CX2072X=m -CONFIG_SND_SOC_DA7213=m -CONFIG_SND_SOC_DA7219=m -CONFIG_SND_SOC_DMIC=m -CONFIG_SND_SOC_HDMI_CODEC=m -CONFIG_SND_SOC_ES7134=m -CONFIG_SND_SOC_ES7241=m -CONFIG_SND_SOC_ES8311=m -CONFIG_SND_SOC_ES8316=m -CONFIG_SND_SOC_ES8323=m -CONFIG_SND_SOC_ES8326=m -CONFIG_SND_SOC_ES8328=m -CONFIG_SND_SOC_ES8328_I2C=m -CONFIG_SND_SOC_ES8328_SPI=m -CONFIG_SND_SOC_ES8375=m -CONFIG_SND_SOC_ES8389=m -# CONFIG_SND_SOC_ES9356 is not set -CONFIG_SND_SOC_FRAMER=m -CONFIG_SND_SOC_FS_AMP_LIB=m -CONFIG_SND_SOC_FS210X=m -CONFIG_SND_SOC_GTM601=m -CONFIG_SND_SOC_HDA=m -CONFIG_SND_SOC_ICS43432=m -CONFIG_SND_SOC_IDT821034=m -CONFIG_SND_SOC_INNO_RK3036=m -CONFIG_SND_SOC_LOCHNAGAR_SC=m -CONFIG_SND_SOC_MAX98088=m -CONFIG_SND_SOC_MAX98090=m -CONFIG_SND_SOC_MAX98357A=m -CONFIG_SND_SOC_MAX98504=m -CONFIG_SND_SOC_MAX9867=m -CONFIG_SND_SOC_MAX98927=m -CONFIG_SND_SOC_MAX98520=m -CONFIG_SND_SOC_MAX98363=m -CONFIG_SND_SOC_MAX98373=m -CONFIG_SND_SOC_MAX98373_I2C=m -CONFIG_SND_SOC_MAX98373_SDW=m -CONFIG_SND_SOC_MAX98388=m -CONFIG_SND_SOC_MAX98390=m -CONFIG_SND_SOC_MAX98396=m -CONFIG_SND_SOC_MAX9860=m -CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m -CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m -CONFIG_SND_SOC_PCM1681=m -CONFIG_SND_SOC_PCM1754=m -CONFIG_SND_SOC_PCM1789=m -CONFIG_SND_SOC_PCM1789_I2C=m -CONFIG_SND_SOC_PCM179X=m -CONFIG_SND_SOC_PCM179X_I2C=m -CONFIG_SND_SOC_PCM179X_SPI=m -CONFIG_SND_SOC_PCM186X=m -CONFIG_SND_SOC_PCM186X_I2C=m -CONFIG_SND_SOC_PCM186X_SPI=m -CONFIG_SND_SOC_PCM3060=m -CONFIG_SND_SOC_PCM3060_I2C=m -CONFIG_SND_SOC_PCM3060_SPI=m -CONFIG_SND_SOC_PCM3168A=m -CONFIG_SND_SOC_PCM3168A_I2C=m -CONFIG_SND_SOC_PCM3168A_SPI=m -CONFIG_SND_SOC_PCM5102A=m -CONFIG_SND_SOC_PCM512x=m -CONFIG_SND_SOC_PCM512x_I2C=m -CONFIG_SND_SOC_PCM512x_SPI=m -CONFIG_SND_SOC_PCM6240=m -CONFIG_SND_SOC_PEB2466=m -CONFIG_SND_SOC_PM4125=m -CONFIG_SND_SOC_PM4125_SDW=m -CONFIG_SND_SOC_RK3308=m -CONFIG_SND_SOC_RK3328=m -CONFIG_SND_SOC_RK817=m -CONFIG_SND_SOC_RL6231=m -CONFIG_SND_SOC_RT_SDW_COMMON=m -CONFIG_SND_SOC_RT1011=m -CONFIG_SND_SOC_RT1015=m -CONFIG_SND_SOC_RT1015P=m -CONFIG_SND_SOC_RT1017_SDCA_SDW=m -CONFIG_SND_SOC_RT1308_SDW=m -CONFIG_SND_SOC_RT1316_SDW=m -CONFIG_SND_SOC_RT1318_SDW=m -CONFIG_SND_SOC_RT1320_SDW=m -CONFIG_SND_SOC_RT5514=m -CONFIG_SND_SOC_RT5514_SPI=m -CONFIG_SND_SOC_RT5575=m -CONFIG_SND_SOC_RT5575_SPI=y -CONFIG_SND_SOC_RT5616=m -CONFIG_SND_SOC_RT5631=m -CONFIG_SND_SOC_RT5640=m -CONFIG_SND_SOC_RT5645=m -CONFIG_SND_SOC_RT5659=m -CONFIG_SND_SOC_RT5663=m -CONFIG_SND_SOC_RT5677=m -CONFIG_SND_SOC_RT5677_SPI=m -CONFIG_SND_SOC_RT5682=m -CONFIG_SND_SOC_RT5682_I2C=m -CONFIG_SND_SOC_RT5682_SDW=m -CONFIG_SND_SOC_RT5682S=m -CONFIG_SND_SOC_RT700=m -CONFIG_SND_SOC_RT700_SDW=m -CONFIG_SND_SOC_RT711=m -CONFIG_SND_SOC_RT711_SDW=m -CONFIG_SND_SOC_RT711_SDCA_SDW=m -CONFIG_SND_SOC_RT712_SDCA_SDW=m -CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW=m -CONFIG_SND_SOC_RT721_SDCA_SDW=m -CONFIG_SND_SOC_RT722_SDCA_SDW=m -CONFIG_SND_SOC_RT715=m -CONFIG_SND_SOC_RT715_SDW=m -CONFIG_SND_SOC_RT715_SDCA_SDW=m -CONFIG_SND_SOC_RT9120=m -CONFIG_SND_SOC_RT9123=m -CONFIG_SND_SOC_RT9123P=m -CONFIG_SND_SOC_RTQ9124=m -CONFIG_SND_SOC_RTQ9128=m -CONFIG_SND_SOC_SDW_MOCKUP=m -CONFIG_SND_SOC_SGTL5000=m -CONFIG_SND_SOC_SI476X=m -CONFIG_SND_SOC_SIGMADSP=m -CONFIG_SND_SOC_SIGMADSP_I2C=m -CONFIG_SND_SOC_SIGMADSP_REGMAP=m -CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m -CONFIG_SND_SOC_SIMPLE_MUX=m -CONFIG_SND_SOC_SMA1303=m -CONFIG_SND_SOC_SMA1307=m -CONFIG_SND_SOC_SPDIF=m -CONFIG_SND_SOC_SRC4XXX_I2C=m -CONFIG_SND_SOC_SRC4XXX=m -CONFIG_SND_SOC_SSM2305=m -CONFIG_SND_SOC_SSM2518=m -CONFIG_SND_SOC_SSM2602=m -CONFIG_SND_SOC_SSM2602_SPI=m -CONFIG_SND_SOC_SSM2602_I2C=m -CONFIG_SND_SOC_SSM3515=m -CONFIG_SND_SOC_SSM4567=m -CONFIG_SND_SOC_STA32X=m -CONFIG_SND_SOC_STA350=m -CONFIG_SND_SOC_STI_SAS=m -# CONFIG_SND_SOC_TAC5XX2_SDW is not set -CONFIG_SND_SOC_TAS2552=m -CONFIG_SND_SOC_TAS2562=m -CONFIG_SND_SOC_TAS2764=m -CONFIG_SND_SOC_TAS2770=m -CONFIG_SND_SOC_TAS2780=m -CONFIG_SND_SOC_TAS2781_COMLIB=m -CONFIG_SND_SOC_TAS2781_COMLIB_I2C=m -CONFIG_SND_SOC_TAS2781_FMWLIB=m -CONFIG_SND_SOC_TAS2781_I2C=m -# CONFIG_SND_SOC_TAS2783_SDW is not set -CONFIG_SND_SOC_TAS5086=m -CONFIG_SND_SOC_TAS571X=m -CONFIG_SND_SOC_TAS5720=m -CONFIG_SND_SOC_TAS5805M=m -CONFIG_SND_SOC_TAS6424=m -# CONFIG_SND_SOC_TAS675X is not set -CONFIG_SND_SOC_TDA7419=m -CONFIG_SND_SOC_TFA9879=m -CONFIG_SND_SOC_TFA989X=m -CONFIG_SND_SOC_TLV320ADC3XXX=m -CONFIG_SND_SOC_TLV320AIC23=m -CONFIG_SND_SOC_TLV320AIC23_I2C=m -CONFIG_SND_SOC_TLV320AIC23_SPI=m -CONFIG_SND_SOC_TLV320AIC31XX=m -CONFIG_SND_SOC_TLV320AIC32X4=m -CONFIG_SND_SOC_TLV320AIC32X4_I2C=m -CONFIG_SND_SOC_TLV320AIC32X4_SPI=m -CONFIG_SND_SOC_TLV320AIC3X=m -CONFIG_SND_SOC_TLV320AIC3X_I2C=m -CONFIG_SND_SOC_TLV320AIC3X_SPI=m -CONFIG_SND_SOC_TLV320ADCX140=m -CONFIG_SND_SOC_TS3A227E=m -CONFIG_SND_SOC_TSCS42XX=m -CONFIG_SND_SOC_TSCS454=m -CONFIG_SND_SOC_UDA1334=m -CONFIG_SND_SOC_UDA1342=m -# CONFIG_SND_SOC_UDA1380 is not set -CONFIG_SND_SOC_WCD_CLASSH=m -CONFIG_SND_SOC_WCD_COMMON=m -CONFIG_SND_SOC_WCD9335=m -CONFIG_SND_SOC_WCD_MBHC=m -CONFIG_SND_SOC_WCD934X=m -CONFIG_SND_SOC_WCD937X=m -CONFIG_SND_SOC_WCD937X_SDW=m -CONFIG_SND_SOC_WCD938X=m -CONFIG_SND_SOC_WCD938X_SDW=m -CONFIG_SND_SOC_WCD939X=m -CONFIG_SND_SOC_WCD939X_SDW=m -CONFIG_SND_SOC_WM8510=m -CONFIG_SND_SOC_WM8523=m -CONFIG_SND_SOC_WM8524=m -CONFIG_SND_SOC_WM8580=m -CONFIG_SND_SOC_WM8711=m -CONFIG_SND_SOC_WM8728=m -CONFIG_SND_SOC_WM8731=m -CONFIG_SND_SOC_WM8731_I2C=m -CONFIG_SND_SOC_WM8731_SPI=m -CONFIG_SND_SOC_WM8737=m -CONFIG_SND_SOC_WM8741=m -CONFIG_SND_SOC_WM8750=m -CONFIG_SND_SOC_WM8753=m -CONFIG_SND_SOC_WM8770=m -CONFIG_SND_SOC_WM8776=m -CONFIG_SND_SOC_WM8782=m -CONFIG_SND_SOC_WM8804=m -CONFIG_SND_SOC_WM8804_I2C=m -CONFIG_SND_SOC_WM8804_SPI=m -CONFIG_SND_SOC_WM8903=m -CONFIG_SND_SOC_WM8904=m -CONFIG_SND_SOC_WM8940=m -CONFIG_SND_SOC_WM8960=m -CONFIG_SND_SOC_WM8961=m -CONFIG_SND_SOC_WM8962=m -CONFIG_SND_SOC_WM8974=m -CONFIG_SND_SOC_WM8978=m -CONFIG_SND_SOC_WM8985=m -CONFIG_SND_SOC_WM8994=m -CONFIG_SND_SOC_WM8998=m -CONFIG_SND_SOC_WM9712=m -CONFIG_SND_SOC_WSA881X=m -CONFIG_SND_SOC_WSA883X=m -CONFIG_SND_SOC_WSA884X=m -# CONFIG_SND_SOC_WSA885X is not set -CONFIG_SND_SOC_ZL38060=m -CONFIG_SND_SOC_MAX9759=m -CONFIG_SND_SOC_MT6351=m -CONFIG_SND_SOC_MT6357=m -CONFIG_SND_SOC_MT6358=m -CONFIG_SND_SOC_MT6359=m -CONFIG_SND_SOC_MT6359_ACCDET=m -CONFIG_SND_SOC_MT6660=m -CONFIG_SND_SOC_NAU8315=m -CONFIG_SND_SOC_NAU8325=m -CONFIG_SND_SOC_NAU8540=m -CONFIG_SND_SOC_NAU8810=m -CONFIG_SND_SOC_NAU8821=m -CONFIG_SND_SOC_NAU8822=m -CONFIG_SND_SOC_NAU8824=m -CONFIG_SND_SOC_NAU8825=m -CONFIG_SND_SOC_NTPFW=m -CONFIG_SND_SOC_NTP8918=m -CONFIG_SND_SOC_NTP8835=m -CONFIG_SND_SOC_TPA6130A2=m -CONFIG_SND_SOC_LPASS_MACRO_COMMON=m -CONFIG_SND_SOC_LPASS_WSA_MACRO=m -CONFIG_SND_SOC_LPASS_VA_MACRO=m -CONFIG_SND_SOC_LPASS_RX_MACRO=m -CONFIG_SND_SOC_LPASS_TX_MACRO=m -# end of CODEC drivers - -CONFIG_SND_SOC_SDW_UTILS=m - -# -# Generic drivers -# -CONFIG_SND_SIMPLE_CARD_UTILS=m -CONFIG_SND_SIMPLE_CARD=m -CONFIG_SND_AUDIO_GRAPH_CARD=m -CONFIG_SND_AUDIO_GRAPH_CARD2=m -CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE=m -CONFIG_SND_TEST_COMPONENT=m -# end of Generic drivers - -CONFIG_SND_SYNTH_EMUX=m -CONFIG_SND_XEN_FRONTEND=m -CONFIG_SND_VIRTIO=m -CONFIG_AC97_BUS=m -CONFIG_HID_SUPPORT=y -CONFIG_HID=m -CONFIG_HID_BATTERY_STRENGTH=y -CONFIG_HIDRAW=y -CONFIG_UHID=m -CONFIG_HID_GENERIC=m -CONFIG_HID_HAPTIC=y - -# -# Special HID drivers -# -CONFIG_HID_A4TECH=m -CONFIG_HID_ACCUTOUCH=m -CONFIG_HID_ACRUX=m -CONFIG_HID_ACRUX_FF=y -CONFIG_HID_APPLE=m -CONFIG_HID_APPLEIR=m -CONFIG_HID_ASUS=m -CONFIG_HID_AUREAL=m -CONFIG_HID_BELKIN=m -CONFIG_HID_BETOP_FF=m -CONFIG_HID_BIGBEN_FF=m -CONFIG_HID_CHERRY=m -CONFIG_HID_CHICONY=m -CONFIG_HID_CORSAIR=m -CONFIG_HID_COUGAR=m -CONFIG_HID_MACALLY=m -CONFIG_HID_PRODIKEYS=m -CONFIG_HID_CMEDIA=m -CONFIG_HID_CP2112=m -CONFIG_HID_CREATIVE_SB0540=m -CONFIG_HID_CYPRESS=m -CONFIG_HID_DRAGONRISE=m -CONFIG_DRAGONRISE_FF=y -CONFIG_HID_EMS_FF=m -CONFIG_HID_ELAN=m -CONFIG_HID_ELECOM=m -CONFIG_HID_ELO=m -CONFIG_HID_EVISION=m -CONFIG_HID_EZKEY=m -CONFIG_HID_FT260=m -CONFIG_HID_GEMBIRD=m -CONFIG_HID_GFRM=m -CONFIG_HID_GLORIOUS=m -CONFIG_HID_HOLTEK=m -CONFIG_HOLTEK_FF=y -CONFIG_HID_VIVALDI_COMMON=m -CONFIG_HID_GOODIX_SPI=m -CONFIG_HID_GOOGLE_HAMMER=m -CONFIG_HID_GOOGLE_STADIA_FF=m -CONFIG_HID_VIVALDI=m -CONFIG_HID_GT683R=m -CONFIG_HID_KEYTOUCH=m -CONFIG_HID_KYE=m -CONFIG_HID_KYSONA=m -CONFIG_HID_UCLOGIC=m -CONFIG_HID_WALTOP=m -CONFIG_HID_VIEWSONIC=m -CONFIG_HID_VRC2=m -CONFIG_HID_XIAOMI=m -CONFIG_HID_GYRATION=m -CONFIG_HID_ICADE=m -CONFIG_HID_ITE=m -CONFIG_HID_JABRA=m -CONFIG_HID_TWINHAN=m -CONFIG_HID_KENSINGTON=m -CONFIG_HID_LCPOWER=m -CONFIG_HID_LED=m -CONFIG_HID_LENOVO=m -# CONFIG_HID_LENOVO_GO is not set -# CONFIG_HID_LENOVO_GO_S is not set -CONFIG_HID_LETSKETCH=m -CONFIG_HID_LOGITECH=m -CONFIG_HID_LOGITECH_DJ=m -CONFIG_HID_LOGITECH_HIDPP=m -CONFIG_LOGITECH_FF=y -CONFIG_LOGIRUMBLEPAD2_FF=y -CONFIG_LOGIG940_FF=y -CONFIG_LOGIWHEELS_FF=y -CONFIG_HID_MAGICMOUSE=m -CONFIG_HID_MALTRON=m -CONFIG_HID_MAYFLASH=m -CONFIG_HID_MEGAWORLD_FF=m -# CONFIG_HID_RAKK is not set -CONFIG_HID_REDRAGON=m -CONFIG_HID_MICROSOFT=m -CONFIG_HID_MONTEREY=m -CONFIG_HID_MULTITOUCH=m -CONFIG_HID_NINTENDO=m -CONFIG_NINTENDO_FF=y -CONFIG_HID_NTI=m -CONFIG_HID_NTRIG=m -CONFIG_HID_NVIDIA_SHIELD=m -CONFIG_NVIDIA_SHIELD_FF=y -CONFIG_HID_ORTEK=m -# CONFIG_HID_OXP is not set -CONFIG_HID_PANTHERLORD=m -CONFIG_PANTHERLORD_FF=y -CONFIG_HID_PENMOUNT=m -CONFIG_HID_PETALYNX=m -CONFIG_HID_PICOLCD=m -CONFIG_HID_PICOLCD_FB=y -CONFIG_HID_PICOLCD_BACKLIGHT=y -CONFIG_HID_PICOLCD_LCD=y -CONFIG_HID_PICOLCD_LEDS=y -CONFIG_HID_PICOLCD_CIR=y -CONFIG_HID_PLANTRONICS=m -CONFIG_HID_PLAYSTATION=m -CONFIG_PLAYSTATION_FF=y -CONFIG_HID_PXRC=m -CONFIG_HID_RAPOO=m -CONFIG_HID_RAZER=m -CONFIG_HID_PRIMAX=m -CONFIG_HID_RETRODE=m -CONFIG_HID_ROCCAT=m -CONFIG_HID_SAITEK=m -CONFIG_HID_SAMSUNG=m -CONFIG_HID_SEMITEK=m -CONFIG_HID_SIGMAMICRO=m -CONFIG_HID_SONY=m -CONFIG_SONY_FF=y -CONFIG_HID_SPEEDLINK=m -CONFIG_HID_STEAM=m -CONFIG_STEAM_FF=y -CONFIG_HID_STEELSERIES=m -CONFIG_HID_SUNPLUS=m -CONFIG_HID_RMI=m -CONFIG_HID_GREENASIA=m -CONFIG_GREENASIA_FF=y -CONFIG_HID_HYPERV_MOUSE=m -CONFIG_HID_SMARTJOYPLUS=m -CONFIG_SMARTJOYPLUS_FF=y -CONFIG_HID_TIVO=m -CONFIG_HID_TOPSEED=m -CONFIG_HID_TOPRE=m -CONFIG_HID_THINGM=m -CONFIG_HID_THRUSTMASTER=m -CONFIG_THRUSTMASTER_FF=y -CONFIG_HID_UDRAW_PS3=m -CONFIG_HID_U2FZERO=m -CONFIG_HID_UNIVERSAL_PIDFF=m -CONFIG_HID_WACOM=m -CONFIG_HID_WIIMOTE=m -CONFIG_HID_WINWING=m -CONFIG_HID_XINMO=m -CONFIG_HID_ZEROPLUS=m -CONFIG_ZEROPLUS_FF=y -CONFIG_HID_ZYDACRON=m -CONFIG_HID_SENSOR_HUB=m -CONFIG_HID_SENSOR_CUSTOM_SENSOR=m -CONFIG_HID_ALPS=m -CONFIG_HID_MCP2200=m -CONFIG_HID_MCP2221=m -# CONFIG_HID_HUAWEI is not set -# end of Special HID drivers - -# -# HID-BPF support -# -CONFIG_HID_BPF=y -# end of HID-BPF support - -CONFIG_I2C_HID=m -CONFIG_I2C_HID_ACPI=m -CONFIG_I2C_HID_OF=m -CONFIG_I2C_HID_OF_ELAN=m -CONFIG_I2C_HID_OF_GOODIX=m -CONFIG_I2C_HID_CORE=m -CONFIG_SPI_HID=m -# CONFIG_SPI_HID_ACPI is not set -CONFIG_SPI_HID_OF=m -CONFIG_SPI_HID_CORE=m - -# -# Surface System Aggregator Module HID support -# -CONFIG_SURFACE_HID=m -CONFIG_SURFACE_KBD=m -# end of Surface System Aggregator Module HID support - -CONFIG_SURFACE_HID_CORE=m - -# -# USB HID support -# -CONFIG_USB_HID=m -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y - -# -# USB HID Boot Protocol drivers -# -CONFIG_USB_KBD=m -CONFIG_USB_MOUSE=m -# end of USB HID Boot Protocol drivers -# end of USB HID support - -CONFIG_USB_OHCI_LITTLE_ENDIAN=y -CONFIG_USB_SUPPORT=y -CONFIG_USB_COMMON=y -CONFIG_USB_LED_TRIG=y -CONFIG_USB_ULPI_BUS=m -CONFIG_USB_CONN_GPIO=m -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB=y -CONFIG_USB_PCI=y -CONFIG_USB_PCI_AMD=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y - -# -# Miscellaneous USB options -# -CONFIG_USB_DEFAULT_PERSIST=y -# CONFIG_USB_FEW_INIT_RETRIES is not set -CONFIG_USB_DYNAMIC_MINORS=y -# CONFIG_USB_OTG is not set -# CONFIG_USB_OTG_PRODUCTLIST is not set -# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set -CONFIG_USB_LEDS_TRIGGER_USBPORT=m -CONFIG_USB_AUTOSUSPEND_DELAY=2 -CONFIG_USB_DEFAULT_AUTHORIZATION_MODE=1 -CONFIG_USB_MON=m - -# -# USB Host Controller Drivers -# -CONFIG_USB_C67X00_HCD=m -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_XHCI_DBGCAP=y -CONFIG_USB_XHCI_PCI=y -CONFIG_USB_XHCI_PCI_RENESAS=m -CONFIG_USB_XHCI_PLATFORM=m -CONFIG_USB_XHCI_HISTB=m -CONFIG_USB_XHCI_MTK=m -CONFIG_USB_XHCI_MTK_V2=m -CONFIG_USB_XHCI_MVEBU=m -CONFIG_USB_XHCI_RCAR=m -CONFIG_USB_XHCI_RZV2M=y -CONFIG_USB_XHCI_SIDEBAND=y -CONFIG_USB_XHCI_TEGRA=m -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_EHCI_TT_NEWSCHED=y -CONFIG_USB_EHCI_PCI=y -CONFIG_USB_EHCI_FSL=m -CONFIG_USB_EHCI_HCD_NPCM7XX=m -CONFIG_USB_EHCI_HCD_ORION=y -CONFIG_USB_EHCI_TEGRA=m -CONFIG_USB_EHCI_MV=m -CONFIG_USB_EHCI_HCD_PLATFORM=m -CONFIG_USB_OXU210HP_HCD=m -CONFIG_USB_ISP116X_HCD=m -CONFIG_USB_MAX3421_HCD=m -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PCI=y -CONFIG_USB_OHCI_HCD_PLATFORM=m -CONFIG_USB_UHCI_HCD=y -CONFIG_USB_SL811_HCD=m -CONFIG_USB_SL811_HCD_ISO=y -CONFIG_USB_R8A66597_HCD=m -CONFIG_USB_RENESAS_USBHS_HCD=m -CONFIG_USB_HCD_BCMA=m -CONFIG_USB_HCD_SSB=m -# CONFIG_USB_HCD_TEST_MODE is not set -CONFIG_USB_XEN_HCD=m -CONFIG_USB_RENESAS_USBHS=m - -# -# USB Device Class drivers -# -CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m -CONFIG_USB_WDM=m -CONFIG_USB_TMC=m - -# -# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; see USB_STORAGE Help for more info -# -CONFIG_USB_STORAGE=m -# CONFIG_USB_STORAGE_DEBUG is not set -CONFIG_USB_STORAGE_REALTEK=m -CONFIG_REALTEK_AUTOPM=y -CONFIG_USB_STORAGE_DATAFAB=m -CONFIG_USB_STORAGE_FREECOM=m -CONFIG_USB_STORAGE_ISD200=m -CONFIG_USB_STORAGE_USBAT=m -CONFIG_USB_STORAGE_SDDR09=m -CONFIG_USB_STORAGE_SDDR55=m -CONFIG_USB_STORAGE_JUMPSHOT=m -CONFIG_USB_STORAGE_ALAUDA=m -CONFIG_USB_STORAGE_ONETOUCH=m -CONFIG_USB_STORAGE_KARMA=m -CONFIG_USB_STORAGE_CYPRESS_ATACB=m -CONFIG_USB_STORAGE_ENE_UB6250=m -CONFIG_USB_UAS=m - -# -# USB Imaging devices -# -CONFIG_USB_MDC800=m -CONFIG_USB_MICROTEK=m -CONFIG_USBIP_CORE=m -CONFIG_USBIP_VHCI_HCD=m -CONFIG_USBIP_VHCI_HC_PORTS=8 -CONFIG_USBIP_VHCI_NR_HCS=1 -CONFIG_USBIP_HOST=m -CONFIG_USBIP_VUDC=m -# CONFIG_USBIP_DEBUG is not set - -# -# USB dual-mode controller drivers -# -CONFIG_USB_CDNS_SUPPORT=m -CONFIG_USB_CDNS3=m -CONFIG_USB_CDNS3_HOST=y -CONFIG_USB_CDNS3_GADGET=y - -# -# Platform glue driver support -# -CONFIG_USB_CDNS3_PCI_WRAP=m -CONFIG_USB_CDNSP_PCI=m -CONFIG_USB_CDNS3_TI=m -CONFIG_USB_CDNS3_IMX=m -CONFIG_USB_MTU3=m -# CONFIG_USB_MTU3_HOST is not set -# CONFIG_USB_MTU3_GADGET is not set -CONFIG_USB_MTU3_DUAL_ROLE=y -# CONFIG_USB_MTU3_DEBUG is not set -CONFIG_USB_MUSB_HDRC=m -# CONFIG_USB_MUSB_HOST is not set -# CONFIG_USB_MUSB_GADGET is not set -CONFIG_USB_MUSB_DUAL_ROLE=y - -# -# Platform Glue Layer -# -CONFIG_USB_MUSB_SUNXI=m -CONFIG_USB_MUSB_MEDIATEK=m - -# -# MUSB DMA mode -# -CONFIG_MUSB_PIO_ONLY=y -CONFIG_USB_DWC3=m -CONFIG_USB_DWC3_ULPI=y -# CONFIG_USB_DWC3_HOST is not set -# CONFIG_USB_DWC3_GADGET is not set -CONFIG_USB_DWC3_DUAL_ROLE=y - -# -# Platform Glue Driver Support -# -CONFIG_USB_DWC3_PCI=m -CONFIG_USB_DWC3_HAPS=m -CONFIG_USB_DWC3_KEYSTONE=m -CONFIG_USB_DWC3_MESON_G12A=m -CONFIG_USB_DWC3_OF_SIMPLE=m -CONFIG_USB_DWC3_QCOM=m -CONFIG_USB_DWC3_IMX8MP=m -CONFIG_USB_DWC3_IMX=m -CONFIG_USB_DWC3_XILINX=m -CONFIG_USB_DWC3_AM62=m -CONFIG_USB_DWC3_RTK=m -CONFIG_USB_DWC3_GENERIC_PLAT=m -CONFIG_USB_DWC3_APPLE=m -CONFIG_USB_DWC3_GOOGLE=m -CONFIG_USB_DWC2=y -CONFIG_USB_DWC2_HOST=y - -# -# Gadget/Dual-role mode requires USB Gadget support to be enabled -# -CONFIG_USB_DWC2_PCI=m -# CONFIG_USB_DWC2_DEBUG is not set -# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set -CONFIG_USB_CHIPIDEA=m -CONFIG_USB_CHIPIDEA_UDC=y -CONFIG_USB_CHIPIDEA_HOST=y -CONFIG_USB_CHIPIDEA_PCI=m -CONFIG_USB_CHIPIDEA_MSM=m -CONFIG_USB_CHIPIDEA_NPCM=m -CONFIG_USB_CHIPIDEA_IMX=m -CONFIG_USB_CHIPIDEA_GENERIC=m -CONFIG_USB_CHIPIDEA_TEGRA=m -CONFIG_USB_ISP1760=m -CONFIG_USB_ISP1760_HCD=y -CONFIG_USB_ISP1761_UDC=y -# CONFIG_USB_ISP1760_HOST_ROLE is not set -# CONFIG_USB_ISP1760_GADGET_ROLE is not set -CONFIG_USB_ISP1760_DUAL_ROLE=y - -# -# USB port drivers -# -CONFIG_USB_SERIAL=m -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_SIMPLE=m -CONFIG_USB_SERIAL_AIRCABLE=m -CONFIG_USB_SERIAL_ARK3116=m -CONFIG_USB_SERIAL_BELKIN=m -CONFIG_USB_SERIAL_CH341=m -CONFIG_USB_SERIAL_WHITEHEAT=m -CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m -CONFIG_USB_SERIAL_CP210X=m -CONFIG_USB_SERIAL_CYPRESS_M8=m -CONFIG_USB_SERIAL_EMPEG=m -CONFIG_USB_SERIAL_FTDI_SIO=m -CONFIG_USB_SERIAL_VISOR=m -CONFIG_USB_SERIAL_IPAQ=m -CONFIG_USB_SERIAL_IR=m -CONFIG_USB_SERIAL_EDGEPORT=m -CONFIG_USB_SERIAL_EDGEPORT_TI=m -CONFIG_USB_SERIAL_F81232=m -CONFIG_USB_SERIAL_F8153X=m -CONFIG_USB_SERIAL_GARMIN=m -CONFIG_USB_SERIAL_IPW=m -CONFIG_USB_SERIAL_IUU=m -CONFIG_USB_SERIAL_KEYSPAN_PDA=m -CONFIG_USB_SERIAL_KEYSPAN=m -CONFIG_USB_SERIAL_KLSI=m -CONFIG_USB_SERIAL_KOBIL_SCT=m -CONFIG_USB_SERIAL_MCT_U232=m -CONFIG_USB_SERIAL_METRO=m -CONFIG_USB_SERIAL_MOS7720=m -CONFIG_USB_SERIAL_MOS7715_PARPORT=y -CONFIG_USB_SERIAL_MOS7840=m -CONFIG_USB_SERIAL_MXUPORT=m -CONFIG_USB_SERIAL_NAVMAN=m -CONFIG_USB_SERIAL_PL2303=m -CONFIG_USB_SERIAL_OTI6858=m -CONFIG_USB_SERIAL_QCAUX=m -CONFIG_USB_SERIAL_QUALCOMM=m -CONFIG_USB_SERIAL_SPCP8X5=m -CONFIG_USB_SERIAL_SAFE=m -# CONFIG_USB_SERIAL_SAFE_PADDED is not set -CONFIG_USB_SERIAL_SIERRAWIRELESS=m -CONFIG_USB_SERIAL_SYMBOL=m -CONFIG_USB_SERIAL_TI=m -CONFIG_USB_SERIAL_CYBERJACK=m -CONFIG_USB_SERIAL_WWAN=m -CONFIG_USB_SERIAL_OPTION=m -CONFIG_USB_SERIAL_OMNINET=m -CONFIG_USB_SERIAL_OPTICON=m -CONFIG_USB_SERIAL_XSENS_MT=m -CONFIG_USB_SERIAL_WISHBONE=m -CONFIG_USB_SERIAL_SSU100=m -CONFIG_USB_SERIAL_QT2=m -CONFIG_USB_SERIAL_UPD78F0730=m -CONFIG_USB_SERIAL_XR=m -CONFIG_USB_SERIAL_DEBUG=m - -# -# USB Miscellaneous drivers -# -CONFIG_USB_USS720=m -CONFIG_USB_EMI62=m -CONFIG_USB_EMI26=m -CONFIG_USB_ADUTUX=m -CONFIG_USB_SEVSEG=m -CONFIG_USB_LEGOTOWER=m -CONFIG_USB_LCD=m -CONFIG_USB_CYPRESS_CY7C63=m -CONFIG_USB_CYTHERM=m -CONFIG_USB_IDMOUSE=m -CONFIG_USB_APPLEDISPLAY=m -CONFIG_USB_QCOM_EUD=m -CONFIG_APPLE_MFI_FASTCHARGE=m -CONFIG_USB_LJCA=m -CONFIG_USB_SISUSBVGA=m -CONFIG_USB_LD=m -CONFIG_USB_TRANCEVIBRATOR=m -CONFIG_USB_IOWARRIOR=m -CONFIG_USB_TEST=m -CONFIG_USB_EHSET_TEST_FIXTURE=m -CONFIG_USB_ISIGHTFW=m -CONFIG_USB_YUREX=m -CONFIG_USB_EZUSB_FX2=m -CONFIG_USB_HUB_USB251XB=m -CONFIG_USB_HSIC_USB3503=m -CONFIG_USB_HSIC_USB4604=m -CONFIG_USB_LINK_LAYER_TEST=m -CONFIG_USB_CHAOSKEY=m -CONFIG_USB_ONBOARD_DEV=m -# CONFIG_USB_ONBOARD_DEV_USB5744 is not set -CONFIG_USB_ATM=m -CONFIG_USB_SPEEDTOUCH=m -CONFIG_USB_CXACRU=m -CONFIG_USB_UEAGLEATM=m -CONFIG_USB_XUSBATM=m - -# -# USB Physical Layer drivers -# -CONFIG_USB_PHY=y -CONFIG_NOP_USB_XCEIV=m -CONFIG_USB_GPIO_VBUS=m -CONFIG_TAHVO_USB=m -CONFIG_TAHVO_USB_HOST_BY_DEFAULT=y -CONFIG_USB_ISP1301=m -CONFIG_USB_MXS_PHY=y -CONFIG_USB_TEGRA_PHY=m -CONFIG_USB_ULPI=y -CONFIG_USB_ULPI_VIEWPORT=y -# end of USB Physical Layer drivers - -CONFIG_USB_GADGET=m -# CONFIG_USB_GADGET_DEBUG is not set -# CONFIG_USB_GADGET_DEBUG_FILES is not set -# CONFIG_USB_GADGET_DEBUG_FS is not set -CONFIG_USB_GADGET_VBUS_DRAW=2 -CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -CONFIG_U_SERIAL_CONSOLE=y - -# -# USB Peripheral Controller -# -CONFIG_USB_GR_UDC=m -CONFIG_USB_R8A66597=m -CONFIG_USB_RENESAS_USBHS_UDC=m -CONFIG_USB_RZV2M_USB3DRD=m -CONFIG_USB_RENESAS_USB3=m -CONFIG_USB_RENESAS_USBF=m -CONFIG_USB_PXA27X=m -CONFIG_USB_SNP_CORE=m -CONFIG_USB_SNP_UDC_PLAT=m -# CONFIG_USB_M66592 is not set -CONFIG_USB_BDC_UDC=m -CONFIG_USB_AMD5536UDC=m -CONFIG_USB_NET2280=m -CONFIG_USB_GOKU=m -CONFIG_USB_EG20T=m -CONFIG_USB_GADGET_XILINX=m -CONFIG_USB_MAX3420_UDC=m -CONFIG_USB_TEGRA_XUDC=m -CONFIG_USB_CDNS2_UDC=m -# CONFIG_USB_DUMMY_HCD is not set -# end of USB Peripheral Controller - -CONFIG_USB_LIBCOMPOSITE=m -CONFIG_USB_F_ACM=m -CONFIG_USB_F_SS_LB=m -CONFIG_USB_U_SERIAL=m -CONFIG_USB_U_ETHER=m -CONFIG_USB_U_AUDIO=m -CONFIG_USB_F_SERIAL=m -CONFIG_USB_F_OBEX=m -CONFIG_USB_F_NCM=m -CONFIG_USB_F_ECM=m -CONFIG_USB_F_PHONET=m -CONFIG_USB_F_EEM=m -CONFIG_USB_F_SUBSET=m -CONFIG_USB_F_RNDIS=m -CONFIG_USB_F_MASS_STORAGE=m -CONFIG_USB_F_FS=m -CONFIG_USB_F_UAC1=m -CONFIG_USB_F_UAC1_LEGACY=m -CONFIG_USB_F_UAC2=m -CONFIG_USB_F_UVC=m -CONFIG_USB_F_MIDI=m -CONFIG_USB_F_MIDI2=m -CONFIG_USB_F_HID=m -CONFIG_USB_F_PRINTER=m -CONFIG_USB_F_TCM=m -CONFIG_USB_CONFIGFS=m -CONFIG_USB_CONFIGFS_SERIAL=y -CONFIG_USB_CONFIGFS_ACM=y -CONFIG_USB_CONFIGFS_OBEX=y -CONFIG_USB_CONFIGFS_NCM=y -CONFIG_USB_CONFIGFS_ECM=y -CONFIG_USB_CONFIGFS_ECM_SUBSET=y -CONFIG_USB_CONFIGFS_RNDIS=y -CONFIG_USB_CONFIGFS_EEM=y -CONFIG_USB_CONFIGFS_PHONET=y -CONFIG_USB_CONFIGFS_MASS_STORAGE=y -CONFIG_USB_CONFIGFS_F_LB_SS=y -CONFIG_USB_CONFIGFS_F_FS=y -CONFIG_USB_CONFIGFS_F_UAC1=y -CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y -CONFIG_USB_CONFIGFS_F_UAC2=y -CONFIG_USB_CONFIGFS_F_MIDI=y -CONFIG_USB_CONFIGFS_F_MIDI2=y -CONFIG_USB_CONFIGFS_F_HID=y -CONFIG_USB_CONFIGFS_F_UVC=y -CONFIG_USB_CONFIGFS_F_PRINTER=y -CONFIG_USB_CONFIGFS_F_TCM=y - -# -# USB Gadget precomposed configurations -# -CONFIG_USB_ZERO=m -CONFIG_USB_AUDIO=m -CONFIG_GADGET_UAC1=y -# CONFIG_GADGET_UAC1_LEGACY is not set -CONFIG_USB_ETH=m -CONFIG_USB_ETH_RNDIS=y -CONFIG_USB_ETH_EEM=y -CONFIG_USB_G_NCM=m -CONFIG_USB_GADGETFS=m -CONFIG_USB_FUNCTIONFS=m -CONFIG_USB_FUNCTIONFS_ETH=y -CONFIG_USB_FUNCTIONFS_RNDIS=y -CONFIG_USB_FUNCTIONFS_GENERIC=y -CONFIG_USB_MASS_STORAGE=m -CONFIG_USB_GADGET_TARGET=m -CONFIG_USB_G_SERIAL=m -CONFIG_USB_MIDI_GADGET=m -CONFIG_USB_G_PRINTER=m -CONFIG_USB_CDC_COMPOSITE=m -CONFIG_USB_G_NOKIA=m -CONFIG_USB_G_ACM_MS=m -# CONFIG_USB_G_MULTI is not set -CONFIG_USB_G_HID=m -CONFIG_USB_G_DBGP=m -# CONFIG_USB_G_DBGP_PRINTK is not set -CONFIG_USB_G_DBGP_SERIAL=y -CONFIG_USB_G_WEBCAM=m -CONFIG_USB_RAW_GADGET=m -# end of USB Gadget precomposed configurations - -CONFIG_TYPEC=m -CONFIG_TYPEC_TCPM=m -CONFIG_TYPEC_TCPCI=m -CONFIG_TYPEC_RT1711H=m -CONFIG_TYPEC_MT6360=m -CONFIG_TYPEC_TCPCI_MT6370=m -CONFIG_TYPEC_TCPCI_MAXIM=m -CONFIG_TYPEC_FUSB302=m -CONFIG_TYPEC_QCOM_PMIC=m -CONFIG_TYPEC_UCSI=m -CONFIG_UCSI_CCG=m -CONFIG_UCSI_ACPI=m -CONFIG_UCSI_STM32G0=m -CONFIG_UCSI_PMIC_GLINK=m -CONFIG_CROS_EC_UCSI=m -CONFIG_UCSI_LENOVO_YOGA_C630=m -CONFIG_UCSI_HUAWEI_GAOKUN=m -CONFIG_TYPEC_TPS6598X=m -CONFIG_TYPEC_ANX7411=m -CONFIG_TYPEC_RT1719=m -CONFIG_TYPEC_HD3SS3220=m -CONFIG_TYPEC_STUSB160X=m -CONFIG_TYPEC_WUSB3801=m - -# -# USB Type-C Multiplexer/DeMultiplexer Switch support -# -CONFIG_TYPEC_MUX_FSA4480=m -CONFIG_TYPEC_MUX_GPIO_SBU=m -CONFIG_TYPEC_MUX_PI3USB30532=m -CONFIG_TYPEC_MUX_IT5205=m -CONFIG_TYPEC_MUX_NB7VPQ904M=m -CONFIG_TYPEC_MUX_PS883X=m -CONFIG_TYPEC_MUX_PTN36502=m -CONFIG_TYPEC_MUX_TUSB1046=m -CONFIG_TYPEC_MUX_WCD939X_USBSS=m -# end of USB Type-C Multiplexer/DeMultiplexer Switch support - -# -# USB Type-C Alternate Mode drivers -# -CONFIG_TYPEC_DP_ALTMODE=m -CONFIG_TYPEC_NVIDIA_ALTMODE=m -CONFIG_TYPEC_TBT_ALTMODE=m -# end of USB Type-C Alternate Mode drivers - -CONFIG_USB_ROLE_SWITCH=y -CONFIG_MMC=y -CONFIG_PWRSEQ_EMMC=m -CONFIG_PWRSEQ_SD8787=m -CONFIG_PWRSEQ_SIMPLE=m -CONFIG_MMC_BLOCK=m -CONFIG_MMC_BLOCK_MINORS=8 -CONFIG_SDIO_UART=m -# CONFIG_MMC_TEST is not set -CONFIG_MMC_CRYPTO=y - -# -# MMC/SD/SDIO Host Controller Drivers -# -# CONFIG_MMC_DEBUG is not set -CONFIG_MMC_ARMMMCI=y -CONFIG_MMC_QCOM_DML=y -CONFIG_MMC_STM32_SDMMC=y -CONFIG_MMC_SDHCI=m -CONFIG_MMC_SDHCI_IO_ACCESSORS=y -CONFIG_MMC_SDHCI_UHS2=m -CONFIG_MMC_SDHCI_PCI=m -CONFIG_MMC_RICOH_MMC=y -CONFIG_MMC_SDHCI_ACPI=m -CONFIG_MMC_SDHCI_PLTFM=m -CONFIG_MMC_SDHCI_OF_ARASAN=m -CONFIG_MMC_SDHCI_OF_AT91=m -CONFIG_MMC_SDHCI_OF_ESDHC=m -CONFIG_MMC_SDHCI_OF_DWCMSHC=m -CONFIG_MMC_SDHCI_OF_SPARX5=m -CONFIG_MMC_SDHCI_OF_MA35D1=m -CONFIG_MMC_SDHCI_CADENCE=m -CONFIG_MMC_SDHCI_ESDHC_IMX=m -CONFIG_MMC_SDHCI_TEGRA=m -CONFIG_MMC_SDHCI_PXAV3=m -CONFIG_MMC_SDHCI_PXAV2=m -# CONFIG_MMC_SDHCI_BST is not set -CONFIG_MMC_SDHCI_F_SDH30=m -CONFIG_MMC_SDHCI_MILBEAUT=m -CONFIG_MMC_SDHCI_NPCM=m -CONFIG_MMC_MESON_GX=m -CONFIG_MMC_MESON_MX_SDIO=m -CONFIG_MMC_ALCOR=m -CONFIG_MMC_SDHCI_MSM=m -CONFIG_MMC_MXC=m -CONFIG_MMC_TIFM_SD=m -CONFIG_MMC_SPI=m -CONFIG_MMC_SDHCI_SPRD=m -CONFIG_MMC_TMIO_CORE=m -CONFIG_MMC_SDHI=m -CONFIG_MMC_SDHI_SYS_DMAC=m -CONFIG_MMC_SDHI_INTERNAL_DMAC=m -CONFIG_MMC_CB710=m -CONFIG_MMC_VIA_SDMMC=m -CONFIG_MMC_CAVIUM_THUNDERX=m -CONFIG_MMC_DW=m -CONFIG_MMC_DW_PLTFM=m -CONFIG_MMC_DW_BLUEFIELD=m -CONFIG_MMC_DW_EXYNOS=m -CONFIG_MMC_DW_HI3798CV200=m -CONFIG_MMC_DW_HI3798MV200=m -CONFIG_MMC_DW_K3=m -CONFIG_MMC_DW_PCI=m -CONFIG_MMC_DW_ROCKCHIP=m -CONFIG_MMC_SH_MMCIF=m -CONFIG_MMC_VUB300=m -CONFIG_MMC_USHC=m -CONFIG_MMC_USDHI6ROL0=m -CONFIG_MMC_REALTEK_PCI=m -CONFIG_MMC_REALTEK_USB=m -CONFIG_MMC_SUNXI=m -CONFIG_MMC_CQHCI=m -CONFIG_MMC_HSQ=m -CONFIG_MMC_TOSHIBA_PCI=m -CONFIG_MMC_MTK=m -CONFIG_MMC_SDHCI_XENON=m -CONFIG_MMC_SDHCI_AM654=m -CONFIG_MMC_OWL=m -CONFIG_MMC_LITEX=m -CONFIG_SCSI_UFSHCD=m -CONFIG_SCSI_UFS_BSG=y -CONFIG_SCSI_UFS_CRYPTO=y -# CONFIG_SCSI_UFS_HWMON is not set -CONFIG_SCSI_UFSHCD_PCI=m -CONFIG_SCSI_UFS_DWC_TC_PCI=m -CONFIG_SCSI_UFSHCD_PLATFORM=m -CONFIG_SCSI_UFS_CDNS_PLATFORM=m -CONFIG_SCSI_UFS_DWC_TC_PLATFORM=m -CONFIG_SCSI_UFS_QCOM=m -CONFIG_SCSI_UFS_MEDIATEK=m -CONFIG_SCSI_UFS_HISI=m -CONFIG_SCSI_UFS_RENESAS=m -CONFIG_SCSI_UFS_TI_J721E=m -CONFIG_SCSI_UFS_SPRD=m -CONFIG_SCSI_UFS_ROCKCHIP=m -CONFIG_SCSI_UFS_AMD_VERSAL2=m -CONFIG_MEMSTICK=m -# CONFIG_MEMSTICK_DEBUG is not set - -# -# MemoryStick drivers -# -# CONFIG_MEMSTICK_UNSAFE_RESUME is not set -CONFIG_MSPRO_BLOCK=m -CONFIG_MS_BLOCK=m - -# -# MemoryStick Host Controller Drivers -# -CONFIG_MEMSTICK_TIFM_MS=m -CONFIG_MEMSTICK_JMICRON_38X=m -CONFIG_MEMSTICK_R592=m -CONFIG_MEMSTICK_REALTEK_USB=m -CONFIG_LEDS_EXPRESSWIRE=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_CLASS_FLASH=m -CONFIG_LEDS_CLASS_MULTICOLOR=m -CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y - -# -# LED drivers -# -CONFIG_LEDS_88PM860X=m -CONFIG_LEDS_AN30259A=m -CONFIG_LEDS_OSRAM_AMS_AS3668=m -CONFIG_LEDS_AW200XX=m -CONFIG_LEDS_AW2013=m -CONFIG_LEDS_BCM6328=m -CONFIG_LEDS_BCM6358=m -CONFIG_LEDS_CPCAP=m -CONFIG_LEDS_CR0014114=m -CONFIG_LEDS_CROS_EC=m -CONFIG_LEDS_EL15203000=m -CONFIG_LEDS_LM3530=m -CONFIG_LEDS_LM3532=m -CONFIG_LEDS_LM3533=m -CONFIG_LEDS_LM3642=m -CONFIG_LEDS_LM3692X=m -CONFIG_LEDS_MT6323=m -CONFIG_LEDS_SUN50I_A100=m -CONFIG_LEDS_PCA9532=m -CONFIG_LEDS_PCA9532_GPIO=y -CONFIG_LEDS_GPIO=m -CONFIG_LEDS_LP3944=m -CONFIG_LEDS_LP3952=m -CONFIG_LEDS_LP50XX=m -CONFIG_LEDS_LP55XX_COMMON=m -CONFIG_LEDS_LP5521=m -CONFIG_LEDS_LP5523=m -CONFIG_LEDS_LP5562=m -CONFIG_LEDS_LP5569=m -CONFIG_LEDS_LP8501=m -CONFIG_LEDS_LP8788=m -CONFIG_LEDS_LP8860=m -CONFIG_LEDS_LP8864=m -CONFIG_LEDS_PCA955X=m -CONFIG_LEDS_PCA955X_GPIO=y -CONFIG_LEDS_PCA963X=m -CONFIG_LEDS_PCA995X=m -CONFIG_LEDS_QNAP_MCU=m -CONFIG_LEDS_WM831X_STATUS=m -CONFIG_LEDS_WM8350=m -CONFIG_LEDS_DA903X=m -CONFIG_LEDS_DA9052=m -CONFIG_LEDS_DAC124S085=m -CONFIG_LEDS_PWM=m -CONFIG_LEDS_REGULATOR=m -CONFIG_LEDS_BD2606MVV=m -CONFIG_LEDS_BD2802=m -CONFIG_LEDS_LT3593=m -CONFIG_LEDS_ADP5520=m -CONFIG_LEDS_MAX5970=m -CONFIG_LEDS_MC13783=m -CONFIG_LEDS_TCA6507=m -CONFIG_LEDS_TLC591XX=m -CONFIG_LEDS_MAX77650=m -CONFIG_LEDS_MAX77705=m -CONFIG_LEDS_MAX8997=m -CONFIG_LEDS_LM355x=m -CONFIG_LEDS_MENF21BMC=m -CONFIG_LEDS_IS31FL319X=m -CONFIG_LEDS_IS31FL32XX=m -CONFIG_LEDS_SC27XX_BLTC=m - -# -# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) -# -CONFIG_LEDS_BLINKM=m -CONFIG_LEDS_BLINKM_MULTICOLOR=y -CONFIG_LEDS_SYSCON=y -CONFIG_LEDS_MLXREG=m -CONFIG_LEDS_USER=m -CONFIG_LEDS_SPI_BYTE=m -CONFIG_LEDS_TI_LMU_COMMON=m -CONFIG_LEDS_LM3697=m -CONFIG_LEDS_LM36274=m -CONFIG_LEDS_ST1202=m -CONFIG_LEDS_TPS6105X=m - -# -# Flash and Torch LED drivers -# -CONFIG_LEDS_AAT1290=m -CONFIG_LEDS_AS3645A=m -CONFIG_LEDS_KTD2692=m -CONFIG_LEDS_LM3601X=m -CONFIG_LEDS_MAX77693=m -CONFIG_LEDS_MT6360=m -CONFIG_LEDS_MT6370_FLASH=m -CONFIG_LEDS_QCOM_FLASH=m -CONFIG_LEDS_RT4505=m -CONFIG_LEDS_RT8515=m -# CONFIG_LEDS_S2M_FLASH is not set -CONFIG_LEDS_SGM3140=m -CONFIG_LEDS_SY7802=m -CONFIG_LEDS_TPS6131X=m - -# -# RGB LED drivers -# -CONFIG_LEDS_GROUP_MULTICOLOR=m -CONFIG_LEDS_KTD202X=m -CONFIG_LEDS_LP5812=m -# CONFIG_LEDS_LP5860_CORE is not set -# CONFIG_LEDS_LP5860_SPI is not set -CONFIG_LEDS_NCP5623=m -CONFIG_LEDS_PWM_MULTICOLOR=m -CONFIG_LEDS_QCOM_LPG=m -# CONFIG_LEDS_S2M_RGB is not set -CONFIG_LEDS_MT6370_RGB=m - -# -# LED Triggers -# -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_TIMER=m -CONFIG_LEDS_TRIGGER_ONESHOT=m -CONFIG_LEDS_TRIGGER_DISK=y -CONFIG_LEDS_TRIGGER_MTD=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=m -CONFIG_LEDS_TRIGGER_BACKLIGHT=m -CONFIG_LEDS_TRIGGER_CPU=y -CONFIG_LEDS_TRIGGER_ACTIVITY=m -CONFIG_LEDS_TRIGGER_GPIO=m -CONFIG_LEDS_TRIGGER_DEFAULT_ON=m - -# -# iptables trigger is under Netfilter config (LED target) -# -CONFIG_LEDS_TRIGGER_TRANSIENT=m -CONFIG_LEDS_TRIGGER_CAMERA=m -CONFIG_LEDS_TRIGGER_PANIC=y -CONFIG_LEDS_TRIGGER_NETDEV=m -CONFIG_LEDS_TRIGGER_PATTERN=m -CONFIG_LEDS_TRIGGER_TTY=m -CONFIG_LEDS_TRIGGER_INPUT_EVENTS=m - -# -# Simatic LED drivers -# -CONFIG_ACCESSIBILITY=y -# CONFIG_A11Y_BRAILLE_CONSOLE is not set - -# -# Speakup console speech -# -CONFIG_SPEAKUP=m -CONFIG_SPEAKUP_SYNTH_ACNTSA=m -CONFIG_SPEAKUP_SYNTH_APOLLO=m -CONFIG_SPEAKUP_SYNTH_AUDPTR=m -CONFIG_SPEAKUP_SYNTH_BNS=m -CONFIG_SPEAKUP_SYNTH_DECTLK=m -CONFIG_SPEAKUP_SYNTH_DECEXT=m -CONFIG_SPEAKUP_SYNTH_LTLK=m -CONFIG_SPEAKUP_SYNTH_SOFT=m -CONFIG_SPEAKUP_SYNTH_SPKOUT=m -CONFIG_SPEAKUP_SYNTH_TXPRT=m -CONFIG_SPEAKUP_SYNTH_DUMMY=m -# end of Speakup console speech - -CONFIG_INFINIBAND=m -CONFIG_INFINIBAND_USER_MAD=m -CONFIG_INFINIBAND_USER_ACCESS=m -CONFIG_INFINIBAND_USER_ACCESS_CORE=y -CONFIG_INFINIBAND_USER_MEM=y -CONFIG_INFINIBAND_ON_DEMAND_PAGING=y -CONFIG_INFINIBAND_ADDR_TRANS=y -CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y -CONFIG_INFINIBAND_VIRT_DMA=y -CONFIG_INFINIBAND_BNXT_RE=m -CONFIG_INFINIBAND_BNG_RE=m -CONFIG_INFINIBAND_CXGB4=m -CONFIG_INFINIBAND_EFA=m -CONFIG_INFINIBAND_ERDMA=m -CONFIG_INFINIBAND_HNS_HIP08=m -CONFIG_INFINIBAND_IONIC=m -CONFIG_INFINIBAND_IRDMA=m -CONFIG_MANA_INFINIBAND=m -CONFIG_MLX4_INFINIBAND=m -CONFIG_MLX5_INFINIBAND=m -CONFIG_INFINIBAND_MTHCA=m -# CONFIG_INFINIBAND_MTHCA_DEBUG is not set -CONFIG_INFINIBAND_OCRDMA=m -CONFIG_INFINIBAND_QEDR=m -CONFIG_INFINIBAND_VMWARE_PVRDMA=m -CONFIG_RDMA_RXE=m -CONFIG_RDMA_SIW=m -CONFIG_INFINIBAND_IPOIB=m -CONFIG_INFINIBAND_IPOIB_CM=y -# CONFIG_INFINIBAND_IPOIB_DEBUG is not set -CONFIG_INFINIBAND_SRP=m -CONFIG_INFINIBAND_SRPT=m -CONFIG_INFINIBAND_ISER=m -CONFIG_INFINIBAND_ISERT=m -CONFIG_INFINIBAND_RTRS=m -CONFIG_INFINIBAND_RTRS_CLIENT=m -CONFIG_INFINIBAND_RTRS_SERVER=m -CONFIG_EDAC_SUPPORT=y -CONFIG_EDAC=y -# CONFIG_EDAC_DEBUG is not set -CONFIG_EDAC_GHES=y -CONFIG_EDAC_SCRUB=y -CONFIG_EDAC_ECS=y -CONFIG_EDAC_MEM_REPAIR=y -CONFIG_EDAC_LAYERSCAPE=m -CONFIG_EDAC_THUNDERX=m -CONFIG_EDAC_ALTERA=y -CONFIG_EDAC_ALTERA_SDRAM=y -CONFIG_EDAC_ALTERA_OCRAM=y -CONFIG_EDAC_ALTERA_ETHERNET=y -CONFIG_EDAC_ALTERA_NAND=y -CONFIG_EDAC_ALTERA_USB=y -CONFIG_EDAC_ALTERA_QSPI=y -CONFIG_EDAC_ALTERA_SDMMC=y -CONFIG_EDAC_SYNOPSYS=m -CONFIG_EDAC_XGENE=m -CONFIG_EDAC_QCOM=m -CONFIG_EDAC_BLUEFIELD=m -CONFIG_EDAC_DMC520=m -CONFIG_EDAC_ZYNQMP=m -CONFIG_EDAC_NPCM=m -CONFIG_EDAC_VERSAL=m -CONFIG_EDAC_CORTEX_A72=m -CONFIG_EDAC_VERSALNET=m -CONFIG_RTC_LIB=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_HCTOSYS=y -CONFIG_RTC_HCTOSYS_DEVICE="rtc0" -CONFIG_RTC_SYSTOHC=y -CONFIG_RTC_SYSTOHC_DEVICE="rtc0" -# CONFIG_RTC_DEBUG is not set -CONFIG_RTC_NVMEM=y - -# -# RTC interfaces -# -CONFIG_RTC_INTF_SYSFS=y -CONFIG_RTC_INTF_PROC=y -CONFIG_RTC_INTF_DEV=y -# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set -# CONFIG_RTC_DRV_TEST is not set - -# -# I2C RTC drivers -# -CONFIG_RTC_DRV_88PM860X=m -CONFIG_RTC_DRV_88PM80X=m -CONFIG_RTC_DRV_88PM886=m -CONFIG_RTC_DRV_ABB5ZES3=m -CONFIG_RTC_DRV_ABEOZ9=m -CONFIG_RTC_DRV_ABX80X=m -CONFIG_RTC_DRV_AS3722=m -CONFIG_RTC_DRV_DS1307=m -CONFIG_RTC_DRV_DS1307_CENTURY=y -CONFIG_RTC_DRV_DS1374=m -CONFIG_RTC_DRV_DS1374_WDT=y -CONFIG_RTC_DRV_DS1672=m -CONFIG_RTC_DRV_HYM8563=m -CONFIG_RTC_DRV_LP8788=m -CONFIG_RTC_DRV_MAX6900=m -CONFIG_RTC_DRV_MAX8907=m -CONFIG_RTC_DRV_MAX8925=m -CONFIG_RTC_DRV_MAX8998=m -CONFIG_RTC_DRV_MAX8997=m -CONFIG_RTC_DRV_MAX31335=m -CONFIG_RTC_DRV_MAX77686=m -CONFIG_RTC_DRV_NVIDIA_VRS10=m -CONFIG_RTC_DRV_NCT3018Y=m -CONFIG_RTC_DRV_NCT6694=m -CONFIG_RTC_DRV_RK808=m -CONFIG_RTC_DRV_RS5C372=m -CONFIG_RTC_DRV_ISL1208=m -CONFIG_RTC_DRV_ISL12022=m -CONFIG_RTC_DRV_ISL12026=m -CONFIG_RTC_DRV_X1205=m -CONFIG_RTC_DRV_PCF8523=m -CONFIG_RTC_DRV_PCF85363=m -CONFIG_RTC_DRV_PCF8563=m -CONFIG_RTC_DRV_PCF8583=m -CONFIG_RTC_DRV_M41T80=m -CONFIG_RTC_DRV_M41T80_WDT=y -CONFIG_RTC_DRV_BD70528=m -CONFIG_RTC_DRV_BQ32K=m -CONFIG_RTC_DRV_TWL4030=m -CONFIG_RTC_DRV_PALMAS=m -CONFIG_RTC_DRV_TPS6586X=m -CONFIG_RTC_DRV_TPS6594=m -CONFIG_RTC_DRV_TPS65910=m -CONFIG_RTC_DRV_RC5T583=m -CONFIG_RTC_DRV_RC5T619=m -CONFIG_RTC_DRV_S35390A=m -CONFIG_RTC_DRV_FM3130=m -CONFIG_RTC_DRV_RX8010=m -CONFIG_RTC_DRV_RX8111=m -CONFIG_RTC_DRV_RX8581=m -CONFIG_RTC_DRV_RX8025=m -CONFIG_RTC_DRV_EM3027=m -CONFIG_RTC_DRV_RV3028=m -CONFIG_RTC_DRV_RV3032=m -CONFIG_RTC_DRV_RV8803=m -CONFIG_RTC_DRV_S5M=m -CONFIG_RTC_DRV_SD2405AL=m -CONFIG_RTC_DRV_SD3078=m - -# -# SPI RTC drivers -# -CONFIG_RTC_DRV_M41T93=m -CONFIG_RTC_DRV_M41T94=m -CONFIG_RTC_DRV_DS1302=m -CONFIG_RTC_DRV_DS1305=m -CONFIG_RTC_DRV_DS1343=m -CONFIG_RTC_DRV_DS1347=m -CONFIG_RTC_DRV_DS1390=m -CONFIG_RTC_DRV_MAX6916=m -CONFIG_RTC_DRV_R9701=m -CONFIG_RTC_DRV_RX4581=m -CONFIG_RTC_DRV_RS5C348=m -CONFIG_RTC_DRV_MAX6902=m -CONFIG_RTC_DRV_PCF2123=m -CONFIG_RTC_DRV_MCP795=m -CONFIG_RTC_I2C_AND_SPI=y - -# -# SPI and I2C RTC drivers -# -CONFIG_RTC_DRV_DS3232=m -CONFIG_RTC_DRV_DS3232_HWMON=y -CONFIG_RTC_DRV_PCF2127=m -CONFIG_RTC_DRV_PCF85063=m -CONFIG_RTC_DRV_RV3029C2=m -CONFIG_RTC_DRV_RV3029_HWMON=y -CONFIG_RTC_DRV_RX6110=m - -# -# Platform RTC drivers -# -CONFIG_RTC_DRV_DS1286=m -CONFIG_RTC_DRV_DS1511=m -CONFIG_RTC_DRV_DS1553=m -CONFIG_RTC_DRV_DS1685_FAMILY=m -CONFIG_RTC_DRV_DS1685=y -# CONFIG_RTC_DRV_DS1689 is not set -# CONFIG_RTC_DRV_DS17285 is not set -# CONFIG_RTC_DRV_DS17485 is not set -# CONFIG_RTC_DRV_DS17885 is not set -CONFIG_RTC_DRV_DS1742=m -CONFIG_RTC_DRV_DS2404=m -CONFIG_RTC_DRV_DA9052=m -CONFIG_RTC_DRV_DA9055=m -CONFIG_RTC_DRV_DA9063=m -CONFIG_RTC_DRV_EFI=y -CONFIG_RTC_DRV_STK17TA8=m -CONFIG_RTC_DRV_M48T86=m -CONFIG_RTC_DRV_M48T35=m -CONFIG_RTC_DRV_M48T59=m -CONFIG_RTC_DRV_MSM6242=m -CONFIG_RTC_DRV_RP5C01=m -CONFIG_RTC_DRV_WM831X=m -CONFIG_RTC_DRV_WM8350=m -CONFIG_RTC_DRV_SC27XX=m -CONFIG_RTC_DRV_OPTEE=m -CONFIG_RTC_DRV_ZYNQMP=m -CONFIG_RTC_DRV_CROS_EC=m -CONFIG_RTC_DRV_NTXEC=m - -# -# on-CPU RTC drivers -# -CONFIG_RTC_DRV_CV1800=m -CONFIG_RTC_DRV_IMXDI=m -CONFIG_RTC_DRV_FSL_FTM_ALARM=m -CONFIG_RTC_DRV_MESON_VRTC=m -CONFIG_RTC_DRV_SA1100=m -CONFIG_RTC_DRV_SH=m -CONFIG_RTC_DRV_PL030=m -CONFIG_RTC_DRV_PL031=m -CONFIG_RTC_DRV_SUN6I=y -CONFIG_RTC_DRV_MV=y -CONFIG_RTC_DRV_ARMADA38X=m -CONFIG_RTC_DRV_CADENCE=m -CONFIG_RTC_DRV_FTRTC010=m -CONFIG_RTC_DRV_MC13XXX=m -CONFIG_RTC_DRV_PM8XXX=m -CONFIG_RTC_DRV_TEGRA=m -CONFIG_RTC_DRV_MXC=m -CONFIG_RTC_DRV_MXC_V2=m -CONFIG_RTC_DRV_SNVS=m -CONFIG_RTC_DRV_BBNSM=m -CONFIG_RTC_DRV_IMX_BBM_SCMI=m -CONFIG_RTC_DRV_IMX_SC=m -CONFIG_RTC_DRV_MT2712=m -CONFIG_RTC_DRV_MT6397=m -CONFIG_RTC_DRV_MT7622=m -CONFIG_RTC_DRV_XGENE=y -CONFIG_RTC_DRV_R7301=m -CONFIG_RTC_DRV_STM32=m -CONFIG_RTC_DRV_CPCAP=m -CONFIG_RTC_DRV_RTD119X=y -CONFIG_RTC_DRV_TI_K3=m -CONFIG_RTC_DRV_MA35D1=m -CONFIG_RTC_DRV_RENESAS_RTCA3=m -CONFIG_RTC_DRV_GOLDFISH=m -CONFIG_RTC_DRV_MACSMC=m -CONFIG_RTC_DRV_AMLOGIC_A4=m -CONFIG_RTC_DRV_S32G=m - -# -# HID Sensor RTC drivers -# -CONFIG_RTC_DRV_HID_SENSOR_TIME=m -CONFIG_DMADEVICES=y -# CONFIG_DMADEVICES_DEBUG is not set - -# -# DMA Devices -# -CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y -CONFIG_DMA_ENGINE=y -CONFIG_DMA_VIRTUAL_CHANNELS=y -CONFIG_DMA_ACPI=y -CONFIG_DMA_OF=y -CONFIG_ALTERA_MSGDMA=m -CONFIG_AMBA_PL08X=y -CONFIG_APPLE_ADMAC=m -CONFIG_ARM_DMA350=m -CONFIG_AT_XDMAC=m -CONFIG_AXI_DMAC=m -CONFIG_BCM_SBA_RAID=m -CONFIG_DMA_SUN6I=m -CONFIG_DW_AXI_DMAC=m -CONFIG_FSL_EDMA=m -CONFIG_FSL_QDMA=m -# CONFIG_HISI_DMA is not set -CONFIG_IMX_DMA=m -CONFIG_IMX_SDMA=m -CONFIG_INTEL_IDMA64=m -CONFIG_K3_DMA=m -CONFIG_MMP_PDMA=m -CONFIG_MMP_TDMA=m -CONFIG_MV_XOR=y -CONFIG_MV_XOR_V2=y -CONFIG_MXS_DMA=y -CONFIG_OWL_DMA=m -CONFIG_PL330_DMA=m -CONFIG_PXA_DMA=y -CONFIG_PLX_DMA=m -CONFIG_SOPHGO_CV1800B_DMAMUX=m -CONFIG_SPRD_DMA=m -# CONFIG_SWITCHTEC_DMA is not set -CONFIG_TEGRA186_GPC_DMA=m -CONFIG_TEGRA20_APB_DMA=y -CONFIG_TEGRA210_ADMA=m -CONFIG_XGENE_DMA=m -CONFIG_XILINX_DMA=m -CONFIG_XILINX_XDMA=m -CONFIG_XILINX_ZYNQMP_DMA=m -CONFIG_XILINX_ZYNQMP_DPDMA=m -CONFIG_AMD_QDMA=m -CONFIG_MTK_HSDMA=m -CONFIG_MTK_CQDMA=m -CONFIG_MTK_UART_APDMA=m -CONFIG_QCOM_BAM_DMA=m -CONFIG_QCOM_GPI_DMA=m -CONFIG_QCOM_HIDMA_MGMT=m -CONFIG_QCOM_HIDMA=m -CONFIG_DW_DMAC_CORE=m -CONFIG_DW_DMAC=m -CONFIG_DW_DMAC_PCI=m -CONFIG_DW_EDMA=m -CONFIG_DW_EDMA_PCIE=m -CONFIG_SF_PDMA=m -CONFIG_RENESAS_DMA=y -CONFIG_RCAR_DMAC=m -CONFIG_RENESAS_USB_DMAC=m -CONFIG_RZ_DMAC=m -CONFIG_TI_K3_UDMA=y -CONFIG_TI_K3_UDMA_GLUE_LAYER=y -CONFIG_TI_K3_PSIL=y -CONFIG_FSL_DPAA2_QDMA=m -CONFIG_STM32_DMA=y -CONFIG_STM32_DMAMUX=y -CONFIG_STM32_MDMA=y -CONFIG_STM32_DMA3=m - -# -# DMA Clients -# -CONFIG_ASYNC_TX_DMA=y -# CONFIG_DMATEST is not set -CONFIG_DMA_ENGINE_RAID=y - -# -# DMABUF options -# -CONFIG_SYNC_FILE=y -CONFIG_SW_SYNC=y -CONFIG_UDMABUF=y -# CONFIG_DMABUF_DEBUG is not set -CONFIG_DMABUF_HEAPS=y -CONFIG_DMABUF_HEAPS_SYSTEM=y -# CONFIG_DMABUF_HEAPS_SYSTEM_CC_SHARED is not set -CONFIG_DMABUF_HEAPS_CMA=y -# end of DMABUF options - -CONFIG_UIO=m -CONFIG_UIO_CIF=m -CONFIG_UIO_PDRV_GENIRQ=m -CONFIG_UIO_DMEM_GENIRQ=m -CONFIG_UIO_AEC=m -CONFIG_UIO_SERCOS3=m -CONFIG_UIO_PCI_GENERIC=m -CONFIG_UIO_NETX=m -CONFIG_UIO_MF624=m -CONFIG_UIO_HV_GENERIC=m -CONFIG_UIO_DFL=m -CONFIG_UIO_PCI_GENERIC_SVA=m -CONFIG_VFIO=m -CONFIG_VFIO_DEVICE_CDEV=y -CONFIG_VFIO_GROUP=y -# CONFIG_VFIO_CONTAINER is not set -CONFIG_VFIO_NOIOMMU=y -CONFIG_VFIO_VIRQFD=y -# CONFIG_VFIO_DEBUGFS is not set - -# -# VFIO support for PCI devices -# -CONFIG_VFIO_PCI_CORE=m -CONFIG_VFIO_PCI_INTX=y -CONFIG_VFIO_PCI=m -CONFIG_VFIO_PCI_DMABUF=y -CONFIG_MLX5_VFIO_PCI=m -CONFIG_HISI_ACC_VFIO_PCI=m -CONFIG_PDS_VFIO_PCI=m -CONFIG_VIRTIO_VFIO_PCI=m -CONFIG_NVGRACE_GPU_VFIO_PCI=m -CONFIG_QAT_VFIO_PCI=m -CONFIG_XE_VFIO_PCI=m -# end of VFIO support for PCI devices - -# -# VFIO support for platform devices -# -CONFIG_VFIO_PLATFORM_BASE=m -CONFIG_VFIO_PLATFORM=m -CONFIG_VFIO_AMBA=m - -# -# VFIO platform reset drivers -# -CONFIG_VFIO_PLATFORM_CALXEDAXGMAC_RESET=m -CONFIG_VFIO_PLATFORM_AMDXGBE_RESET=m -# end of VFIO platform reset drivers -# end of VFIO support for platform devices - -# -# VFIO support for FSL_MC bus devices -# -CONFIG_VFIO_FSL_MC=m -# end of VFIO support for FSL_MC bus devices - -CONFIG_VFIO_CDX=m -CONFIG_IRQ_BYPASS_MANAGER=y -CONFIG_VIRT_DRIVERS=y -CONFIG_VMGENID=m -CONFIG_VBOXGUEST=m -CONFIG_NITRO_ENCLAVES=m -# CONFIG_EFI_SECRET is not set -# CONFIG_ARM_PKVM_GUEST is not set -CONFIG_ARM_CCA_GUEST=m -CONFIG_TSM_GUEST=y -CONFIG_TSM_REPORTS=m -CONFIG_TSM_MEASUREMENTS=y -CONFIG_TSM=y -CONFIG_VIRTIO_ANCHOR=y -CONFIG_VIRTIO=y -CONFIG_VIRTIO_PCI_LIB=y -CONFIG_VIRTIO_PCI_LIB_LEGACY=y -CONFIG_VIRTIO_MENU=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_PCI_LEGACY=y -CONFIG_VIRTIO_VDPA=m -CONFIG_VIRTIO_PMEM=m -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_MEM=m -CONFIG_VIRTIO_INPUT=m -CONFIG_VIRTIO_MMIO=y -CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y -CONFIG_VIRTIO_DMA_SHARED_BUFFER=m -# CONFIG_VIRTIO_DEBUG is not set -CONFIG_VIRTIO_RTC=m -CONFIG_VIRTIO_RTC_PTP=y -CONFIG_VIRTIO_RTC_ARM=y -CONFIG_VIRTIO_RTC_CLASS=y -CONFIG_VDPA=m -CONFIG_VDPA_SIM=m -CONFIG_VDPA_SIM_NET=m -CONFIG_VDPA_SIM_BLOCK=m -CONFIG_VDPA_USER=m -CONFIG_IFCVF=m -CONFIG_MLX5_VDPA=y -CONFIG_MLX5_VDPA_NET=m -CONFIG_MLX5_VDPA_STEERING_DEBUG=y -CONFIG_VP_VDPA=m -CONFIG_SNET_VDPA=m -CONFIG_PDS_VDPA=m -CONFIG_OCTEONEP_VDPA=m -CONFIG_VHOST_IOTLB=m -CONFIG_VHOST_RING=m -CONFIG_VHOST_TASK=y -CONFIG_VHOST=m -CONFIG_VHOST_MENU=y -CONFIG_VHOST_NET=m -CONFIG_VHOST_SCSI=m -CONFIG_VHOST_VSOCK=m -CONFIG_VHOST_VDPA=m -# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set -CONFIG_VHOST_ENABLE_FORK_OWNER_CONTROL=y - -# -# Microsoft Hyper-V guest support -# -CONFIG_HYPERV=y -# CONFIG_HYPERV_VTL_MODE is not set -CONFIG_HYPERV_UTILS=m -CONFIG_HYPERV_BALLOON=m -CONFIG_HYPERV_VMBUS=m -CONFIG_MSHV_ROOT=m -# end of Microsoft Hyper-V guest support - -# -# Xen driver support -# -CONFIG_XEN_BALLOON=y -CONFIG_XEN_BALLOON_MEMORY_HOTPLUG=y -CONFIG_XEN_SCRUB_PAGES_DEFAULT=y -CONFIG_XEN_DEV_EVTCHN=m -CONFIG_XEN_BACKEND=y -CONFIG_XENFS=m -CONFIG_XEN_COMPAT_XENFS=y -CONFIG_XEN_SYS_HYPERVISOR=y -CONFIG_XEN_XENBUS_FRONTEND=y -CONFIG_XEN_GNTDEV=m -CONFIG_XEN_GNTDEV_DMABUF=y -CONFIG_XEN_GRANT_DEV_ALLOC=m -CONFIG_XEN_GRANT_DMA_ALLOC=y -CONFIG_SWIOTLB_XEN=y -CONFIG_XEN_PCI_STUB=y -CONFIG_XEN_PCIDEV_STUB=m -CONFIG_XEN_PVCALLS_FRONTEND=m -# CONFIG_XEN_PVCALLS_BACKEND is not set -CONFIG_XEN_SCSI_BACKEND=m -CONFIG_XEN_PRIVCMD=m -CONFIG_XEN_PRIVCMD_EVENTFD=y -CONFIG_XEN_EFI=y -CONFIG_XEN_AUTO_XLATE=y -CONFIG_XEN_FRONT_PGDIR_SHBUF=m -CONFIG_XEN_UNPOPULATED_ALLOC=y -CONFIG_XEN_GRANT_DMA_IOMMU=y -CONFIG_XEN_GRANT_DMA_OPS=y -CONFIG_XEN_VIRTIO=y -# CONFIG_XEN_VIRTIO_FORCE_GRANT is not set -# end of Xen driver support - -CONFIG_GREYBUS=m -CONFIG_GREYBUS_BEAGLEPLAY=m -CONFIG_GREYBUS_ES2=m -CONFIG_COMEDI=m -# CONFIG_COMEDI_DEBUG is not set -CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB=2048 -CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB=20480 -CONFIG_COMEDI_MISC_DRIVERS=y -CONFIG_COMEDI_BOND=m -CONFIG_COMEDI_TEST=m -CONFIG_COMEDI_PARPORT=m -CONFIG_COMEDI_ISA_DRIVERS=y -CONFIG_COMEDI_PCL711=m -CONFIG_COMEDI_PCL724=m -CONFIG_COMEDI_PCL726=m -CONFIG_COMEDI_PCL730=m -CONFIG_COMEDI_PCL812=m -CONFIG_COMEDI_PCL816=m -CONFIG_COMEDI_PCL818=m -CONFIG_COMEDI_PCM3724=m -CONFIG_COMEDI_AMPLC_DIO200_ISA=m -CONFIG_COMEDI_AMPLC_PC236_ISA=m -CONFIG_COMEDI_AMPLC_PC263_ISA=m -CONFIG_COMEDI_RTI800=m -CONFIG_COMEDI_RTI802=m -CONFIG_COMEDI_DAC02=m -CONFIG_COMEDI_DAS16M1=m -CONFIG_COMEDI_DAS08_ISA=m -CONFIG_COMEDI_DAS16=m -CONFIG_COMEDI_DAS800=m -CONFIG_COMEDI_DAS1800=m -CONFIG_COMEDI_DAS6402=m -CONFIG_COMEDI_DT2801=m -CONFIG_COMEDI_DT2811=m -CONFIG_COMEDI_DT2814=m -CONFIG_COMEDI_DT2815=m -CONFIG_COMEDI_DT2817=m -CONFIG_COMEDI_DT282X=m -CONFIG_COMEDI_DMM32AT=m -CONFIG_COMEDI_FL512=m -CONFIG_COMEDI_AIO_AIO12_8=m -CONFIG_COMEDI_AIO_IIRO_16=m -CONFIG_COMEDI_II_PCI20KC=m -CONFIG_COMEDI_C6XDIGIO=m -CONFIG_COMEDI_MPC624=m -CONFIG_COMEDI_ADQ12B=m -CONFIG_COMEDI_NI_AT_A2150=m -CONFIG_COMEDI_NI_AT_AO=m -CONFIG_COMEDI_NI_ATMIO=m -CONFIG_COMEDI_NI_ATMIO16D=m -CONFIG_COMEDI_NI_LABPC_ISA=m -CONFIG_COMEDI_PCMAD=m -CONFIG_COMEDI_PCMDA12=m -CONFIG_COMEDI_PCMMIO=m -CONFIG_COMEDI_PCMUIO=m -CONFIG_COMEDI_MULTIQ3=m -CONFIG_COMEDI_S526=m -CONFIG_COMEDI_PCI_DRIVERS=m -CONFIG_COMEDI_8255_PCI=m -CONFIG_COMEDI_ADDI_WATCHDOG=m -CONFIG_COMEDI_ADDI_APCI_1032=m -CONFIG_COMEDI_ADDI_APCI_1500=m -CONFIG_COMEDI_ADDI_APCI_1516=m -CONFIG_COMEDI_ADDI_APCI_1564=m -CONFIG_COMEDI_ADDI_APCI_16XX=m -CONFIG_COMEDI_ADDI_APCI_2032=m -CONFIG_COMEDI_ADDI_APCI_2200=m -CONFIG_COMEDI_ADDI_APCI_3120=m -CONFIG_COMEDI_ADDI_APCI_3501=m -CONFIG_COMEDI_ADDI_APCI_3XXX=m -CONFIG_COMEDI_ADL_PCI6208=m -CONFIG_COMEDI_ADL_PCI7250=m -CONFIG_COMEDI_ADL_PCI7X3X=m -CONFIG_COMEDI_ADL_PCI8164=m -CONFIG_COMEDI_ADL_PCI9111=m -CONFIG_COMEDI_ADL_PCI9118=m -CONFIG_COMEDI_ADV_PCI1710=m -CONFIG_COMEDI_ADV_PCI1720=m -CONFIG_COMEDI_ADV_PCI1723=m -CONFIG_COMEDI_ADV_PCI1724=m -CONFIG_COMEDI_ADV_PCI1760=m -CONFIG_COMEDI_ADV_PCI_DIO=m -CONFIG_COMEDI_AMPLC_DIO200_PCI=m -CONFIG_COMEDI_AMPLC_PC236_PCI=m -CONFIG_COMEDI_AMPLC_PC263_PCI=m -CONFIG_COMEDI_AMPLC_PCI224=m -CONFIG_COMEDI_AMPLC_PCI230=m -CONFIG_COMEDI_CONTEC_PCI_DIO=m -CONFIG_COMEDI_DAS08_PCI=m -CONFIG_COMEDI_DT3000=m -CONFIG_COMEDI_DYNA_PCI10XX=m -CONFIG_COMEDI_GSC_HPDI=m -CONFIG_COMEDI_MF6X4=m -CONFIG_COMEDI_ICP_MULTI=m -CONFIG_COMEDI_DAQBOARD2000=m -CONFIG_COMEDI_JR3_PCI=m -CONFIG_COMEDI_KE_COUNTER=m -CONFIG_COMEDI_CB_PCIDAS64=m -CONFIG_COMEDI_CB_PCIDAS=m -CONFIG_COMEDI_CB_PCIDDA=m -CONFIG_COMEDI_CB_PCIMDAS=m -CONFIG_COMEDI_CB_PCIMDDA=m -CONFIG_COMEDI_ME4000=m -CONFIG_COMEDI_ME_DAQ=m -CONFIG_COMEDI_NI_6527=m -CONFIG_COMEDI_NI_65XX=m -CONFIG_COMEDI_NI_660X=m -CONFIG_COMEDI_NI_670X=m -CONFIG_COMEDI_NI_LABPC_PCI=m -CONFIG_COMEDI_NI_PCIDIO=m -CONFIG_COMEDI_NI_PCIMIO=m -CONFIG_COMEDI_RTD520=m -CONFIG_COMEDI_S626=m -CONFIG_COMEDI_MITE=m -CONFIG_COMEDI_NI_TIOCMD=m -CONFIG_COMEDI_USB_DRIVERS=m -CONFIG_COMEDI_DT9812=m -CONFIG_COMEDI_NI_USB6501=m -CONFIG_COMEDI_USBDUX=m -CONFIG_COMEDI_USBDUXFAST=m -CONFIG_COMEDI_USBDUXSIGMA=m -CONFIG_COMEDI_VMK80XX=m -CONFIG_COMEDI_8254=m -CONFIG_COMEDI_8255=m -CONFIG_COMEDI_8255_SA=m -CONFIG_COMEDI_KCOMEDILIB=m -CONFIG_COMEDI_AMPLC_DIO200=m -CONFIG_COMEDI_AMPLC_PC236=m -CONFIG_COMEDI_DAS08=m -CONFIG_COMEDI_NI_LABPC=m -CONFIG_COMEDI_NI_TIO=m -CONFIG_COMEDI_NI_ROUTING=m -CONFIG_COMEDI_TESTS=m -CONFIG_COMEDI_TESTS_EXAMPLE=m -CONFIG_COMEDI_TESTS_NI_ROUTES=m -# CONFIG_GPIB is not set -CONFIG_STAGING=y -CONFIG_RTL8723BS=m - -# -# IIO staging drivers -# - -# -# Accelerometers -# -CONFIG_ADIS16203=m -# end of Accelerometers - -# -# Analog to digital converters -# -CONFIG_AD7816=m -# end of Analog to digital converters - -# -# Analog digital bi-direction converters -# -CONFIG_ADT7316=m -CONFIG_ADT7316_SPI=m -CONFIG_ADT7316_I2C=m -# end of Analog digital bi-direction converters - -# -# Direct Digital Synthesis -# -CONFIG_AD9832=m -CONFIG_AD9834=m -# end of Direct Digital Synthesis - -# -# Network Analyzer, Impedance Converters -# -CONFIG_AD5933=m -# end of Network Analyzer, Impedance Converters -# end of IIO staging drivers - -CONFIG_FB_SM750=m -CONFIG_MFD_NVEC=m -CONFIG_KEYBOARD_NVEC=m -CONFIG_SERIO_NVEC_PS2=m -CONFIG_NVEC_POWER=m -CONFIG_NVEC_PAZ00=m -CONFIG_STAGING_MEDIA=y -CONFIG_DVB_AV7110_IR=y -CONFIG_DVB_AV7110=m -CONFIG_DVB_AV7110_OSD=y -CONFIG_DVB_SP8870=m -CONFIG_VIDEO_MAX96712=m -CONFIG_VIDEO_MESON_VDEC=m -CONFIG_VIDEO_SUNXI=y -CONFIG_VIDEO_SUNXI_CEDRUS=m -CONFIG_VIDEO_SUN6I_ISP=m -CONFIG_VIDEO_TEGRA=m -CONFIG_VIDEO_TEGRA_TPG=y -# CONFIG_STAGING_MEDIA_DEPRECATED is not set -CONFIG_FB_TFT=m -CONFIG_FB_TFT_AGM1264K_FL=m -CONFIG_FB_TFT_BD663474=m -CONFIG_FB_TFT_HX8340BN=m -CONFIG_FB_TFT_HX8347D=m -CONFIG_FB_TFT_HX8353D=m -CONFIG_FB_TFT_HX8357D=m -CONFIG_FB_TFT_ILI9163=m -CONFIG_FB_TFT_ILI9320=m -CONFIG_FB_TFT_ILI9325=m -CONFIG_FB_TFT_ILI9340=m -CONFIG_FB_TFT_ILI9341=m -CONFIG_FB_TFT_ILI9481=m -CONFIG_FB_TFT_ILI9486=m -CONFIG_FB_TFT_PCD8544=m -CONFIG_FB_TFT_RA8875=m -CONFIG_FB_TFT_S6D02A1=m -CONFIG_FB_TFT_S6D1121=m -CONFIG_FB_TFT_SEPS525=m -CONFIG_FB_TFT_SH1106=m -CONFIG_FB_TFT_SSD1289=m -CONFIG_FB_TFT_SSD1305=m -CONFIG_FB_TFT_SSD1306=m -CONFIG_FB_TFT_SSD1331=m -CONFIG_FB_TFT_SSD1351=m -CONFIG_FB_TFT_ST7735R=m -CONFIG_FB_TFT_ST7789V=m -CONFIG_FB_TFT_TINYLCD=m -CONFIG_FB_TFT_TLS8204=m -CONFIG_FB_TFT_UC1611=m -CONFIG_FB_TFT_UC1701=m -CONFIG_FB_TFT_UPD161704=m -CONFIG_MOST_COMPONENTS=m -CONFIG_MOST_NET=m -CONFIG_MOST_VIDEO=m -CONFIG_MOST_DIM2=m -CONFIG_GREYBUS_AUDIO=m -CONFIG_GREYBUS_AUDIO_APB_CODEC=m -CONFIG_GREYBUS_BOOTROM=m -CONFIG_GREYBUS_FIRMWARE=m -CONFIG_GREYBUS_HID=m -CONFIG_GREYBUS_LIGHT=m -CONFIG_GREYBUS_LOG=m -CONFIG_GREYBUS_LOOPBACK=m -CONFIG_GREYBUS_POWER=m -CONFIG_GREYBUS_RAW=m -CONFIG_GREYBUS_VIBRATOR=m -CONFIG_GREYBUS_BRIDGED_PHY=m -CONFIG_GREYBUS_GPIO=m -CONFIG_GREYBUS_I2C=m -CONFIG_GREYBUS_PWM=m -CONFIG_GREYBUS_SDIO=m -CONFIG_GREYBUS_SPI=m -CONFIG_GREYBUS_UART=m -CONFIG_GREYBUS_USB=m -CONFIG_XIL_AXIS_FIFO=m -CONFIG_VME_BUS=y - -# -# VME Bridge Drivers -# -CONFIG_VME_TSI148=m -CONFIG_VME_FAKE=m - -# -# VME Device Drivers -# -CONFIG_VME_USER=m -# CONFIG_GOLDFISH is not set -CONFIG_CHROME_PLATFORMS=y -CONFIG_CHROMEOS_ACPI=m -CONFIG_CHROMEOS_TBMC=m -CONFIG_CHROMEOS_OF_HW_PROBER=m -CONFIG_CROS_EC=m -CONFIG_CROS_EC_I2C=m -CONFIG_CROS_EC_RPMSG=m -CONFIG_CROS_EC_SPI=m -CONFIG_CROS_EC_UART=m -CONFIG_CROS_EC_PROTO=m -CONFIG_CROS_KBD_LED_BACKLIGHT=m -CONFIG_CROS_EC_CHARDEV=m -CONFIG_CROS_EC_LIGHTBAR=m -CONFIG_CROS_EC_VBC=m -CONFIG_CROS_EC_DEBUGFS=m -CONFIG_CROS_EC_SENSORHUB=m -CONFIG_CROS_EC_SYSFS=m -CONFIG_CROS_EC_TYPEC_ALTMODES=y -CONFIG_CROS_EC_TYPEC=m -CONFIG_CROS_HPS_I2C=m -CONFIG_CROS_USBPD_LOGGER=m -CONFIG_CROS_USBPD_NOTIFY=m -CONFIG_CHROMEOS_PRIVACY_SCREEN=m -CONFIG_CROS_TYPEC_SWITCH=m -CONFIG_CZNIC_PLATFORMS=y -CONFIG_TURRIS_SIGNING_KEY=m -CONFIG_MELLANOX_PLATFORM=y -CONFIG_MLX_PLATFORM=m -CONFIG_MLXREG_DPU=m -CONFIG_MLXREG_HOTPLUG=m -CONFIG_MLXREG_IO=m -CONFIG_MLXREG_LC=m -CONFIG_MLXBF_TMFIFO=m -CONFIG_MLXBF_BOOTCTL=m -CONFIG_MLXBF_PMC=m -CONFIG_NVSW_SN2201=m -CONFIG_OLPC_EC=y -CONFIG_OLPC_XO175=y -CONFIG_OLPC_XO175_EC=m -CONFIG_SURFACE_PLATFORMS=y -# CONFIG_SURFACE_3_POWER_OPREGION is not set -CONFIG_SURFACE_ACPI_NOTIFY=m -CONFIG_SURFACE_AGGREGATOR_CDEV=m -CONFIG_SURFACE_AGGREGATOR_HUB=m -CONFIG_SURFACE_AGGREGATOR_REGISTRY=m -CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH=m -CONFIG_SURFACE_DTX=m -CONFIG_SURFACE_GPE=m -CONFIG_SURFACE_HOTPLUG=m -CONFIG_SURFACE_PLATFORM_PROFILE=m -# CONFIG_SURFACE_PRO3_BUTTON is not set -CONFIG_SURFACE_AGGREGATOR=m -CONFIG_SURFACE_AGGREGATOR_BUS=y -# CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION is not set -# CONFIG_SERIAL_MULTI_INSTANTIATE is not set -CONFIG_ARM64_PLATFORM_DEVICES=y -CONFIG_DELL_ARM64_HOTKEYS=m -CONFIG_EC_ACER_ASPIRE1=m -CONFIG_EC_HUAWEI_GAOKUN=m -CONFIG_EC_LENOVO_YOGA_C630=m -CONFIG_EC_LENOVO_THINKPAD_T14S=m -# CONFIG_EC_QCOM_HAMOA is not set -CONFIG_NVIDIA_FFA_EC=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_COMMON_CLK=y -CONFIG_COMMON_CLK_WM831X=m - -# -# Clock driver for ARM Reference designs -# -CONFIG_CLK_ICST=y -CONFIG_CLK_SP810=y -CONFIG_CLK_VEXPRESS_OSC=y -# end of Clock driver for ARM Reference designs - -CONFIG_LMK04832=m -CONFIG_COMMON_CLK_APPLE_NCO=m -CONFIG_COMMON_CLK_MAX77686=m -CONFIG_COMMON_CLK_MAX9485=m -CONFIG_COMMON_CLK_RK808=m -CONFIG_COMMON_CLK_RP1=m -CONFIG_COMMON_CLK_HI655X=m -CONFIG_COMMON_CLK_SCMI=y -CONFIG_COMMON_CLK_SCPI=m -CONFIG_COMMON_CLK_SI5341=m -CONFIG_COMMON_CLK_SI5351=m -CONFIG_COMMON_CLK_SI514=m -CONFIG_COMMON_CLK_SI544=m -CONFIG_COMMON_CLK_SI570=m -CONFIG_COMMON_CLK_BM1880=y -CONFIG_COMMON_CLK_CDCE706=m -CONFIG_COMMON_CLK_CDCE925=m -CONFIG_COMMON_CLK_CS2000_CP=m -CONFIG_COMMON_CLK_EN7523=y -CONFIG_COMMON_CLK_FSL_FLEXSPI=m -CONFIG_COMMON_CLK_FSL_SAI=y -CONFIG_COMMON_CLK_LAN966X=m -CONFIG_COMMON_CLK_S2MPS11=m -CONFIG_CLK_TWL=m -CONFIG_CLK_TWL6040=m -CONFIG_COMMON_CLK_AXI_CLKGEN=m -CONFIG_CLK_QORIQ=y -CONFIG_CLK_LS1028A_PLLDIG=m -CONFIG_COMMON_CLK_XGENE=y -CONFIG_COMMON_CLK_LOCHNAGAR=m -CONFIG_COMMON_CLK_NPCM8XX=m -CONFIG_COMMON_CLK_PALMAS=m -CONFIG_COMMON_CLK_PWM=m -CONFIG_COMMON_CLK_RS9_PCIE=m -CONFIG_COMMON_CLK_SI521XX=m -CONFIG_COMMON_CLK_VC3=m -CONFIG_COMMON_CLK_VC5=m -CONFIG_COMMON_CLK_VC7=m -CONFIG_COMMON_CLK_BD718XX=m -CONFIG_COMMON_CLK_FIXED_MMIO=y -CONFIG_CLK_ACTIONS=y -CONFIG_CLK_OWL_S500=y -CONFIG_CLK_OWL_S700=y -CONFIG_CLK_OWL_S900=y -CONFIG_COMMON_CLK_HI3516CV300=m -CONFIG_COMMON_CLK_HI3519=m -CONFIG_COMMON_CLK_HI3559A=y -CONFIG_COMMON_CLK_HI3660=y -CONFIG_COMMON_CLK_HI3670=y -CONFIG_COMMON_CLK_HI3798CV200=m -CONFIG_COMMON_CLK_HI6220=y -CONFIG_RESET_HISI=y -CONFIG_STUB_CLK_HI6220=y -CONFIG_STUB_CLK_HI3660=y -CONFIG_MXC_CLK=y -CONFIG_MXC_CLK_SCU=y -CONFIG_CLK_IMX8MM=y -CONFIG_CLK_IMX8MN=y -CONFIG_CLK_IMX8MP=y -CONFIG_CLK_IMX8MQ=y -CONFIG_CLK_IMX8QXP=y -CONFIG_CLK_IMX8ULP=m -CONFIG_CLK_IMX93=m -CONFIG_CLK_IMX95_BLK_CTL=m -CONFIG_TI_SCI_CLK=m -# CONFIG_TI_SCI_CLK_PROBE_FROM_FW is not set -CONFIG_TI_SYSCON_CLK=y - -# -# Clock driver for MediaTek SoC -# -CONFIG_COMMON_CLK_MEDIATEK=y -CONFIG_COMMON_CLK_MEDIATEK_FHCTL=y -CONFIG_COMMON_CLK_MT2712=y -CONFIG_COMMON_CLK_MT2712_BDPSYS=y -CONFIG_COMMON_CLK_MT2712_IMGSYS=y -CONFIG_COMMON_CLK_MT2712_JPGDECSYS=y -CONFIG_COMMON_CLK_MT2712_MFGCFG=y -CONFIG_COMMON_CLK_MT2712_MMSYS=y -CONFIG_COMMON_CLK_MT2712_VDECSYS=y -CONFIG_COMMON_CLK_MT2712_VENCSYS=y -CONFIG_COMMON_CLK_MT6735=m -CONFIG_COMMON_CLK_MT6735_IMGSYS=m -CONFIG_COMMON_CLK_MT6735_MFGCFG=m -CONFIG_COMMON_CLK_MT6735_VDECSYS=m -CONFIG_COMMON_CLK_MT6735_VENCSYS=m -CONFIG_COMMON_CLK_MT6765=y -CONFIG_COMMON_CLK_MT6765_AUDIOSYS=y -CONFIG_COMMON_CLK_MT6765_CAMSYS=y -CONFIG_COMMON_CLK_MT6765_GCESYS=y -CONFIG_COMMON_CLK_MT6765_MMSYS=y -CONFIG_COMMON_CLK_MT6765_IMGSYS=y -CONFIG_COMMON_CLK_MT6765_VCODECSYS=y -CONFIG_COMMON_CLK_MT6765_MFGSYS=y -CONFIG_COMMON_CLK_MT6765_MIPI0ASYS=y -CONFIG_COMMON_CLK_MT6765_MIPI0BSYS=y -CONFIG_COMMON_CLK_MT6765_MIPI1ASYS=y -CONFIG_COMMON_CLK_MT6765_MIPI1BSYS=y -CONFIG_COMMON_CLK_MT6765_MIPI2ASYS=y -CONFIG_COMMON_CLK_MT6765_MIPI2BSYS=y -CONFIG_COMMON_CLK_MT6779=y -CONFIG_COMMON_CLK_MT6779_MMSYS=y -CONFIG_COMMON_CLK_MT6779_IMGSYS=y -CONFIG_COMMON_CLK_MT6779_IPESYS=y -CONFIG_COMMON_CLK_MT6779_CAMSYS=y -CONFIG_COMMON_CLK_MT6779_VDECSYS=y -CONFIG_COMMON_CLK_MT6779_VENCSYS=y -CONFIG_COMMON_CLK_MT6779_MFGCFG=y -CONFIG_COMMON_CLK_MT6779_AUDSYS=y -CONFIG_COMMON_CLK_MT6795=m -CONFIG_COMMON_CLK_MT6795_MFGCFG=m -CONFIG_COMMON_CLK_MT6795_MMSYS=m -CONFIG_COMMON_CLK_MT6795_VDECSYS=m -CONFIG_COMMON_CLK_MT6795_VENCSYS=m -CONFIG_COMMON_CLK_MT6797=y -CONFIG_COMMON_CLK_MT6797_MMSYS=y -CONFIG_COMMON_CLK_MT6797_IMGSYS=y -CONFIG_COMMON_CLK_MT6797_VDECSYS=y -CONFIG_COMMON_CLK_MT6797_VENCSYS=y -CONFIG_COMMON_CLK_MT7622=y -CONFIG_COMMON_CLK_MT7622_ETHSYS=y -CONFIG_COMMON_CLK_MT7622_HIFSYS=y -CONFIG_COMMON_CLK_MT7622_AUDSYS=y -CONFIG_COMMON_CLK_MT7981=y -CONFIG_COMMON_CLK_MT7981_ETHSYS=m -CONFIG_COMMON_CLK_MT7986=y -CONFIG_COMMON_CLK_MT7986_ETHSYS=y -CONFIG_COMMON_CLK_MT7988=m -CONFIG_COMMON_CLK_MT8167=y -CONFIG_COMMON_CLK_MT8167_AUDSYS=y -CONFIG_COMMON_CLK_MT8167_IMGSYS=y -CONFIG_COMMON_CLK_MT8167_MFGCFG=y -CONFIG_COMMON_CLK_MT8167_MMSYS=y -CONFIG_COMMON_CLK_MT8167_VDECSYS=y -CONFIG_COMMON_CLK_MT8173=y -CONFIG_COMMON_CLK_MT8173_IMGSYS=m -CONFIG_COMMON_CLK_MT8173_MMSYS=y -CONFIG_COMMON_CLK_MT8173_VDECSYS=m -CONFIG_COMMON_CLK_MT8173_VENCSYS=m -CONFIG_COMMON_CLK_MT8183=y -CONFIG_COMMON_CLK_MT8183_AUDIOSYS=y -CONFIG_COMMON_CLK_MT8183_CAMSYS=y -CONFIG_COMMON_CLK_MT8183_IMGSYS=y -CONFIG_COMMON_CLK_MT8183_IPU_CORE0=y -CONFIG_COMMON_CLK_MT8183_IPU_CORE1=y -CONFIG_COMMON_CLK_MT8183_IPU_ADL=y -CONFIG_COMMON_CLK_MT8183_IPU_CONN=y -CONFIG_COMMON_CLK_MT8183_MFGCFG=y -CONFIG_COMMON_CLK_MT8183_MMSYS=y -CONFIG_COMMON_CLK_MT8183_VDECSYS=y -CONFIG_COMMON_CLK_MT8183_VENCSYS=y -CONFIG_COMMON_CLK_MT8186=y -CONFIG_COMMON_CLK_MT8186_CAMSYS=m -CONFIG_COMMON_CLK_MT8186_IMGSYS=m -CONFIG_COMMON_CLK_MT8186_IPESYS=m -CONFIG_COMMON_CLK_MT8186_WPESYS=m -CONFIG_COMMON_CLK_MT8186_IMP_IIC_WRAP=m -CONFIG_COMMON_CLK_MT8186_MCUSYS=m -CONFIG_COMMON_CLK_MT8186_MDPSYS=m -CONFIG_COMMON_CLK_MT8186_MFGCFG=m -CONFIG_COMMON_CLK_MT8186_MMSYS=m -CONFIG_COMMON_CLK_MT8186_VDECSYS=m -CONFIG_COMMON_CLK_MT8186_VENCSYS=m -CONFIG_COMMON_CLK_MT8188=m -CONFIG_COMMON_CLK_MT8188_ADSP_AUDIO26M=m -CONFIG_COMMON_CLK_MT8188_CAMSYS=m -CONFIG_COMMON_CLK_MT8188_IMGSYS=m -CONFIG_COMMON_CLK_MT8188_IMP_IIC_WRAP=m -CONFIG_COMMON_CLK_MT8188_IPESYS=m -CONFIG_COMMON_CLK_MT8188_MFGCFG=m -CONFIG_COMMON_CLK_MT8188_VDECSYS=m -CONFIG_COMMON_CLK_MT8188_VDOSYS=m -CONFIG_COMMON_CLK_MT8188_VENCSYS=m -CONFIG_COMMON_CLK_MT8188_VPPSYS=m -CONFIG_COMMON_CLK_MT8188_WPESYS=m -CONFIG_COMMON_CLK_MT8192=y -CONFIG_COMMON_CLK_MT8192_AUDSYS=y -CONFIG_COMMON_CLK_MT8192_CAMSYS=y -CONFIG_COMMON_CLK_MT8192_IMGSYS=y -CONFIG_COMMON_CLK_MT8192_IMP_IIC_WRAP=y -CONFIG_COMMON_CLK_MT8192_IPESYS=y -CONFIG_COMMON_CLK_MT8192_MDPSYS=y -CONFIG_COMMON_CLK_MT8192_MFGCFG=y -CONFIG_COMMON_CLK_MT8192_MMSYS=y -CONFIG_COMMON_CLK_MT8192_MSDC=y -CONFIG_COMMON_CLK_MT8192_SCP_ADSP=y -CONFIG_COMMON_CLK_MT8192_VDECSYS=y -CONFIG_COMMON_CLK_MT8192_VENCSYS=y -CONFIG_COMMON_CLK_MT8195=y -CONFIG_COMMON_CLK_MT8195_APUSYS=m -CONFIG_COMMON_CLK_MT8195_IMP_IIC_WRAP=m -CONFIG_COMMON_CLK_MT8195_MFGCFG=m -CONFIG_COMMON_CLK_MT8195_SCP_ADSP=m -CONFIG_COMMON_CLK_MT8195_VDOSYS=m -CONFIG_COMMON_CLK_MT8195_VPPSYS=m -CONFIG_COMMON_CLK_MT8195_CAMSYS=m -CONFIG_COMMON_CLK_MT8195_IMGSYS=m -CONFIG_COMMON_CLK_MT8195_IPESYS=m -CONFIG_COMMON_CLK_MT8195_WPESYS=m -CONFIG_COMMON_CLK_MT8195_VDECSYS=m -CONFIG_COMMON_CLK_MT8195_VENCSYS=m -CONFIG_COMMON_CLK_MT8196=m -CONFIG_COMMON_CLK_MT8196_IMP_IIC_WRAP=m -CONFIG_COMMON_CLK_MT8196_MCUSYS=m -CONFIG_COMMON_CLK_MT8196_MDPSYS=m -CONFIG_COMMON_CLK_MT8196_MFGCFG=m -CONFIG_COMMON_CLK_MT8196_MMSYS=m -CONFIG_COMMON_CLK_MT8196_PEXTPSYS=m -CONFIG_COMMON_CLK_MT8196_UFSSYS=m -CONFIG_COMMON_CLK_MT8196_VDECSYS=m -CONFIG_COMMON_CLK_MT8196_VENCSYS=m -CONFIG_COMMON_CLK_MT8365=m -CONFIG_COMMON_CLK_MT8365_APU=m -CONFIG_COMMON_CLK_MT8365_CAM=m -CONFIG_COMMON_CLK_MT8365_MFG=m -CONFIG_COMMON_CLK_MT8365_MMSYS=m -CONFIG_COMMON_CLK_MT8365_VDEC=m -CONFIG_COMMON_CLK_MT8365_VENC=m -CONFIG_COMMON_CLK_MT8516=y -CONFIG_COMMON_CLK_MT8516_AUDSYS=y -# end of Clock driver for MediaTek SoC - -CONFIG_COMMON_CLK_PXA1908=y - -# -# Clock support for Amlogic platforms -# -CONFIG_COMMON_CLK_MESON_REGMAP=y -CONFIG_COMMON_CLK_MESON_DUALDIV=y -CONFIG_COMMON_CLK_MESON_MPLL=y -CONFIG_COMMON_CLK_MESON_PHASE=m -CONFIG_COMMON_CLK_MESON_PLL=y -CONFIG_COMMON_CLK_MESON_SCLK_DIV=m -CONFIG_COMMON_CLK_MESON_VID_PLL_DIV=y -CONFIG_COMMON_CLK_MESON_VCLK=y -CONFIG_COMMON_CLK_MESON_CLKC_UTILS=y -CONFIG_COMMON_CLK_MESON_AO_CLKC=y -CONFIG_COMMON_CLK_MESON_CPU_DYNDIV=y -CONFIG_COMMON_CLK_GXBB=y -CONFIG_COMMON_CLK_AXG=y -CONFIG_COMMON_CLK_AXG_AUDIO=m -CONFIG_COMMON_CLK_A1_PLL=m -CONFIG_COMMON_CLK_A1_PERIPHERALS=m -CONFIG_COMMON_CLK_C3_PLL=y -CONFIG_COMMON_CLK_C3_PERIPHERALS=m -CONFIG_COMMON_CLK_G12A=y -CONFIG_COMMON_CLK_S4_PLL=m -CONFIG_COMMON_CLK_S4_PERIPHERALS=m -CONFIG_COMMON_CLK_T7_PLL=m -CONFIG_COMMON_CLK_T7_PERIPHERALS=m -# end of Clock support for Amlogic platforms - -CONFIG_MCHP_CLK_MPFS=y -CONFIG_ARMADA_AP_CP_HELPER=y -CONFIG_ARMADA_37XX_CLK=y -CONFIG_ARMADA_AP806_SYSCON=y -CONFIG_ARMADA_AP_CPU_CLK=y -CONFIG_ARMADA_CP110_SYSCON=y -CONFIG_COMMON_CLK_NUVOTON=y -CONFIG_CLK_MA35D1=y -CONFIG_QCOM_GDSC=y -CONFIG_COMMON_CLK_QCOM=y -# CONFIG_CLK_ELIZA_DISPCC is not set -# CONFIG_CLK_ELIZA_GCC is not set -# CONFIG_CLK_ELIZA_TCSRCC is not set -CONFIG_CLK_GLYMUR_DISPCC=m -CONFIG_CLK_GLYMUR_GCC=m -# CONFIG_CLK_GLYMUR_GPUCC is not set -CONFIG_CLK_GLYMUR_TCSRCC=m -# CONFIG_CLK_GLYMUR_VIDEOCC is not set -CONFIG_CLK_KAANAPALI_CAMCC=m -CONFIG_CLK_KAANAPALI_DISPCC=m -CONFIG_CLK_KAANAPALI_GCC=m -CONFIG_CLK_KAANAPALI_GPUCC=m -CONFIG_CLK_KAANAPALI_TCSRCC=m -CONFIG_CLK_KAANAPALI_VIDEOCC=m -# CONFIG_CLK_NORD_GCC is not set -CONFIG_CLK_X1E80100_CAMCC=m -CONFIG_CLK_X1E80100_DISPCC=m -CONFIG_CLK_X1E80100_GCC=m -CONFIG_CLK_X1E80100_GPUCC=m -CONFIG_CLK_X1E80100_TCSRCC=m -CONFIG_CLK_X1P42100_CAMCC=m -CONFIG_CLK_X1P42100_GPUCC=m -CONFIG_CLK_X1P42100_VIDEOCC=m -CONFIG_CLK_QCM2290_GPUCC=m -CONFIG_QCOM_A53PLL=m -CONFIG_QCOM_A7PLL=m -CONFIG_QCOM_CLK_APCS_MSM8916=m -CONFIG_QCOM_CLK_APCC_MSM8996=m -CONFIG_QCOM_CLK_RPM=m -CONFIG_QCOM_CLK_SMD_RPM=m -CONFIG_QCOM_CLK_RPMH=y -# CONFIG_CLK_HAWI_GCC is not set -# CONFIG_CLK_HAWI_TCSRCC is not set -CONFIG_IPQ_APSS_PLL=m -CONFIG_IPQ_APSS_5424=m -CONFIG_IPQ_APSS_6018=m -CONFIG_IPQ_CMN_PLL=m -CONFIG_IPQ_GCC_4019=m -CONFIG_IPQ_GCC_5018=m -# CONFIG_IPQ_GCC_5210 is not set -CONFIG_IPQ_GCC_5332=m -CONFIG_IPQ_GCC_5424=m -CONFIG_IPQ_GCC_6018=m -CONFIG_IPQ_GCC_8074=m -CONFIG_IPQ_GCC_9574=m -CONFIG_IPQ_GCC_9650=y -CONFIG_IPQ_NSSCC_5424=m -CONFIG_IPQ_NSSCC_9574=m -CONFIG_IPQ_NSSCC_QCA8K=m -CONFIG_MSM_GCC_8916=m -CONFIG_MSM_GCC_8917=m -CONFIG_MSM_GCC_8939=m -CONFIG_MSM_GCC_8953=m -CONFIG_MSM_GCC_8976=m -CONFIG_MSM_MMCC_8994=m -CONFIG_MSM_GCC_8994=m -CONFIG_MSM_GCC_8996=m -CONFIG_MSM_MMCC_8996=m -CONFIG_MSM_GCC_8998=m -CONFIG_MSM_GPUCC_8998=m -CONFIG_MSM_MMCC_8998=m -CONFIG_QCM_GCC_2290=m -CONFIG_QCM_DISPCC_2290=m -CONFIG_QCS_DISPCC_615=m -CONFIG_QCS_CAMCC_615=m -CONFIG_QCS_GCC_404=m -# CONFIG_CLK_NORD_TCSRCC is not set -CONFIG_SA_CAMCC_8775P=m -CONFIG_QCS_GCC_8300=m -CONFIG_QCS_GCC_615=m -CONFIG_QCS_GPUCC_615=m -CONFIG_QCS_VIDEOCC_615=m -CONFIG_SC_CAMCC_7180=m -CONFIG_SC_CAMCC_7280=m -CONFIG_SC_CAMCC_8180X=m -CONFIG_SC_CAMCC_8280XP=m -CONFIG_SA_DISPCC_8775P=m -CONFIG_SC_DISPCC_7180=m -CONFIG_SC_DISPCC_7280=m -CONFIG_SC_DISPCC_8280XP=m -CONFIG_SA_GCC_8775P=y -CONFIG_SA_GPUCC_8775P=m -CONFIG_SAR_GCC_2130P=m -CONFIG_SAR_GPUCC_2130P=m -CONFIG_SC_GCC_7180=y -CONFIG_SC_GCC_7280=y -CONFIG_SC_GCC_8180X=y -CONFIG_SC_GCC_8280XP=y -CONFIG_SC_GPUCC_7180=m -CONFIG_SC_GPUCC_7280=m -CONFIG_SC_GPUCC_8280XP=m -CONFIG_SC_LPASSCC_7280=m -CONFIG_SC_LPASSCC_8280XP=m -CONFIG_SC_LPASS_CORECC_7180=m -CONFIG_SC_LPASS_CORECC_7280=m -CONFIG_SC_VIDEOCC_7180=m -CONFIG_SC_VIDEOCC_7280=m -CONFIG_SDM_CAMCC_845=m -CONFIG_SDM_GCC_660=m -CONFIG_SDM_MMCC_660=m -CONFIG_SDM_GPUCC_660=m -CONFIG_QCS_TURING_404=m -CONFIG_QCS_Q6SSTOP_404=m -CONFIG_QDU_GCC_1000=m -CONFIG_QDU_ECPRICC_1000=m -CONFIG_SDM_GCC_845=m -CONFIG_SDM_GPUCC_845=m -CONFIG_SDM_VIDEOCC_845=m -CONFIG_SDM_DISPCC_845=m -CONFIG_SDM_LPASSCC_845=m -CONFIG_SDX_GCC_75=m -CONFIG_SM_CAMCC_4450=m -CONFIG_SM_CAMCC_6350=m -CONFIG_SM_CAMCC_7150=m -CONFIG_SM_CAMCC_MILOS=m -CONFIG_SM_CAMCC_8150=m -CONFIG_SM_CAMCC_8250=m -CONFIG_SM_CAMCC_8450=m -CONFIG_SM_CAMCC_8550=m -CONFIG_SM_CAMCC_8650=m -CONFIG_SM_CAMCC_8750=m -CONFIG_SM_DISPCC_4450=m -CONFIG_SM_DISPCC_6115=m -CONFIG_SM_DISPCC_6125=m -CONFIG_SM_DISPCC_7150=m -CONFIG_SM_DISPCC_8250=m -CONFIG_SM_DISPCC_6350=m -CONFIG_SM_DISPCC_6375=m -CONFIG_SM_DISPCC_MILOS=m -CONFIG_SM_DISPCC_8450=m -CONFIG_SM_DISPCC_8550=m -CONFIG_SM_DISPCC_8750=m -CONFIG_SM_GCC_4450=m -CONFIG_SM_GCC_6115=m -CONFIG_SM_GCC_6125=m -CONFIG_SM_GCC_6350=m -CONFIG_SM_GCC_6375=m -CONFIG_SM_GCC_7150=m -CONFIG_SM_GCC_MILOS=m -CONFIG_SM_GCC_8150=m -CONFIG_SM_GCC_8250=m -CONFIG_SM_GCC_8350=m -CONFIG_SM_GCC_8450=m -CONFIG_SM_GCC_8550=m -CONFIG_SM_GCC_8650=m -CONFIG_SM_GCC_8750=m -CONFIG_SM_GPUCC_4450=m -CONFIG_SM_GPUCC_6115=m -CONFIG_SM_GPUCC_6125=m -CONFIG_SM_GPUCC_6375=m -CONFIG_SM_GPUCC_6350=m -CONFIG_SM_GPUCC_MILOS=m -CONFIG_SM_GPUCC_8150=m -CONFIG_SM_GPUCC_8250=m -CONFIG_SM_GPUCC_8350=m -CONFIG_SM_GPUCC_8450=m -CONFIG_SM_GPUCC_8550=m -CONFIG_SM_GPUCC_8650=m -# CONFIG_SM_GPUCC_8750 is not set -CONFIG_SM_LPASSCC_6115=m -CONFIG_SM_TCSRCC_8550=m -CONFIG_SM_TCSRCC_8650=m -CONFIG_SM_TCSRCC_8750=m -CONFIG_SA_VIDEOCC_8775P=m -CONFIG_SM_VIDEOCC_6350=m -CONFIG_SM_VIDEOCC_7150=m -CONFIG_SM_VIDEOCC_MILOS=m -CONFIG_SM_VIDEOCC_8150=m -CONFIG_SM_VIDEOCC_8250=m -CONFIG_SM_VIDEOCC_8350=m -CONFIG_SM_VIDEOCC_8550=m -CONFIG_SM_VIDEOCC_8750=m -CONFIG_SPMI_PMIC_CLKDIV=m -CONFIG_QCOM_HFPLL=m -CONFIG_KPSS_XCC=m -CONFIG_CLK_GFM_LPASS_SM8250=m -CONFIG_SM_VIDEOCC_8450=m -CONFIG_CLK_RENESAS=y -CONFIG_CLK_R8A774A1=y -CONFIG_CLK_R8A774B1=y -CONFIG_CLK_R8A774C0=y -CONFIG_CLK_R8A774E1=y -CONFIG_CLK_R8A7795=y -CONFIG_CLK_R8A77960=y -CONFIG_CLK_R8A77961=y -CONFIG_CLK_R8A77965=y -CONFIG_CLK_R8A77970=y -CONFIG_CLK_R8A77980=y -CONFIG_CLK_R8A77990=y -CONFIG_CLK_R8A77995=y -CONFIG_CLK_R8A779A0=y -CONFIG_CLK_R8A779F0=y -CONFIG_CLK_R8A779G0=y -CONFIG_CLK_R8A779H0=y -CONFIG_CLK_R9A07G043=y -CONFIG_CLK_R9A07G044=y -CONFIG_CLK_R9A07G054=y -CONFIG_CLK_R9A08G045=y -CONFIG_CLK_R9A08G046=y -CONFIG_CLK_R9A09G011=y -CONFIG_CLK_R9A09G047=y -CONFIG_CLK_R9A09G056=y -CONFIG_CLK_R9A09G057=y -CONFIG_CLK_R9A09G077=y -CONFIG_CLK_R9A09G087=y -CONFIG_CLK_RCAR_CPG_LIB=y -CONFIG_CLK_RCAR_GEN3_CPG=y -CONFIG_CLK_RCAR_GEN4_CPG=y -CONFIG_CLK_RCAR_USB2_CLOCK_SEL=y -CONFIG_CLK_RZG2L=y -CONFIG_CLK_RZV2H=y -CONFIG_CLK_RENESAS_VBATTB=m -CONFIG_CLK_RENESAS_CPG_MSSR=y -CONFIG_CLK_RENESAS_DIV6=y -CONFIG_COMMON_CLK_ROCKCHIP=y -CONFIG_CLK_PX30=y -CONFIG_CLK_RV1126B=y -CONFIG_CLK_RK3308=y -CONFIG_CLK_RK3328=y -CONFIG_CLK_RK3368=y -CONFIG_CLK_RK3399=y -CONFIG_CLK_RK3528=y -CONFIG_CLK_RK3562=y -CONFIG_CLK_RK3568=y -CONFIG_CLK_RK3576=y -CONFIG_CLK_RK3588=y -CONFIG_CLK_INTEL_SOCFPGA=y -CONFIG_CLK_INTEL_SOCFPGA64=y -CONFIG_CLK_SOPHGO_CV1800=m -CONFIG_CLK_SOPHGO_SG2042_PLL=m -CONFIG_CLK_SOPHGO_SG2042_CLKGEN=m -CONFIG_CLK_SOPHGO_SG2042_RPGATE=m -CONFIG_CLK_SOPHGO_SG2044=m -CONFIG_CLK_SOPHGO_SG2044_PLL=m -CONFIG_SPRD_COMMON_CLK=m -CONFIG_SPRD_SC9860_CLK=m -CONFIG_SPRD_SC9863A_CLK=m -CONFIG_SPRD_UMS512_CLK=m -CONFIG_SUNXI_CCU=y -CONFIG_SUN50I_A64_CCU=y -CONFIG_SUN50I_A100_CCU=y -CONFIG_SUN50I_A100_R_CCU=y -CONFIG_SUN50I_H6_CCU=y -CONFIG_SUN50I_H616_CCU=y -CONFIG_SUN50I_H6_R_CCU=y -CONFIG_SUN55I_A523_CCU=y -CONFIG_SUN55I_A523_MCU_CCU=m -CONFIG_SUN55I_A523_R_CCU=y -CONFIG_SUN6I_RTC_CCU=m -CONFIG_SUN8I_H3_CCU=y -CONFIG_SUN8I_DE2_CCU=y -CONFIG_SUN8I_R_CCU=y -CONFIG_CLK_TEGRA_BPMP=y -CONFIG_TEGRA_CLK_DFLL=y -CONFIG_COMMON_CLK_STM32MP=y -CONFIG_COMMON_CLK_STM32MP215=y -CONFIG_COMMON_CLK_STM32MP257=y -CONFIG_COMMON_CLK_VISCONTI=y -CONFIG_XILINX_VCU=m -CONFIG_COMMON_CLK_XLNX_CLKWZRD=m -CONFIG_COMMON_CLK_ZYNQMP=y -CONFIG_HWSPINLOCK=y -CONFIG_HWSPINLOCK_OMAP=m -CONFIG_HWSPINLOCK_QCOM=m -CONFIG_HWSPINLOCK_SPRD=m -CONFIG_HWSPINLOCK_SUN6I=m - -# -# Clock Source drivers -# -CONFIG_TIMER_OF=y -CONFIG_TIMER_ACPI=y -CONFIG_TIMER_PROBE=y -CONFIG_CLKSRC_MMIO=y -CONFIG_OMAP_DM_TIMER=y -CONFIG_DW_APB_TIMER=y -CONFIG_DW_APB_TIMER_OF=y -CONFIG_ROCKCHIP_TIMER=y -CONFIG_OWL_TIMER=y -CONFIG_SUN4I_TIMER=y -CONFIG_TEGRA_TIMER=y -CONFIG_TEGRA186_TIMER=y -CONFIG_NPCM7XX_TIMER=y -CONFIG_CLKSRC_STM32_LP=y -CONFIG_ARM_ARCH_TIMER=y -CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y -CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y -CONFIG_FSL_ERRATUM_A008585=y -CONFIG_HISILICON_ERRATUM_161010101=y -CONFIG_ARM64_ERRATUM_858921=y -CONFIG_SUN50I_ERRATUM_UNKNOWN1=y -CONFIG_ARM_TIMER_SP804=y -CONFIG_SYS_SUPPORTS_SH_CMT=y -CONFIG_MTK_TIMER=y -CONFIG_MTK_CPUX_TIMER=y -CONFIG_SPRD_TIMER=y -CONFIG_SYS_SUPPORTS_SH_TMU=y -CONFIG_SH_TIMER_CMT=y -CONFIG_RENESAS_OSTM=y -CONFIG_SH_TIMER_TMU=y -CONFIG_TIMER_IMX_SYS_CTR=y -CONFIG_NXP_STM_TIMER=y -CONFIG_RTK_SYSTIMER=y -# CONFIG_VF_USE_PIT_TIMER is not set -CONFIG_VF_TIMER_NONE=y -# end of Clock Source drivers - -CONFIG_MAILBOX=y -CONFIG_ARM_MHU=m -CONFIG_ARM_MHU_V2=m -CONFIG_ARM_MHU_V3=m -CONFIG_CV1800_MBOX=m -CONFIG_IMX_MBOX=m -CONFIG_PLATFORM_MHU=m -CONFIG_PL320_MBOX=y -CONFIG_ARMADA_37XX_RWTM_MBOX=m -CONFIG_OMAP2PLUS_MBOX=m -CONFIG_ROCKCHIP_MBOX=y -CONFIG_PCC=y -CONFIG_ALTERA_MBOX=m -CONFIG_TI_MESSAGE_MANAGER=y -CONFIG_HI3660_MBOX=m -CONFIG_HI6220_MBOX=m -CONFIG_MAILBOX_TEST=m -CONFIG_POLARFIRE_SOC_MAILBOX=m -CONFIG_QCOM_APCS_IPC=m -CONFIG_TEGRA_HSP_MBOX=y -CONFIG_XGENE_SLIMPRO_MBOX=m -CONFIG_MTK_ADSP_MBOX=m -CONFIG_MTK_CMDQ_MBOX=m -CONFIG_MTK_GPUEB_MBOX=m -CONFIG_MTK_VCP_MBOX=m -CONFIG_ZYNQMP_IPI_MBOX=y -CONFIG_SUN6I_MSGBOX=y -CONFIG_SPRD_MBOX=m -CONFIG_QCOM_CPUCP_MBOX=m -CONFIG_QCOM_IPCC=y -CONFIG_CIX_MBOX=m -CONFIG_IOMMU_IOVA=y -CONFIG_IOMMU_API=y -CONFIG_IOMMUFD_DRIVER=y -CONFIG_IOMMU_SUPPORT=y - -# -# Generic IOMMU Pagetable Support -# -CONFIG_IOMMU_IO_PGTABLE=y -CONFIG_IOMMU_IO_PGTABLE_LPAE=y -CONFIG_IOMMU_IO_PGTABLE_ARMV7S=y -# CONFIG_IOMMU_IO_PGTABLE_ARMV7S_SELFTEST is not set -CONFIG_IOMMU_IO_PGTABLE_DART=y -# end of Generic IOMMU Pagetable Support - -# CONFIG_IOMMU_DEBUGFS is not set -# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set -# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set -CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y -CONFIG_OF_IOMMU=y -CONFIG_IOMMU_DMA=y -CONFIG_IOMMU_SVA=y -CONFIG_IOMMU_IOPF=y -CONFIG_ARM_SMMU=y -# CONFIG_ARM_SMMU_LEGACY_DT_BINDINGS is not set -# CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT is not set -CONFIG_ARM_SMMU_MMU_500_CPRE_ERRATA=y -CONFIG_ARM_SMMU_QCOM=y -CONFIG_ARM_SMMU_QCOM_DEBUG=y -CONFIG_ARM_SMMU_V3=y -CONFIG_ARM_SMMU_V3_SVA=y -CONFIG_ARM_SMMU_V3_IOMMUFD=y -CONFIG_TEGRA241_CMDQV=y -CONFIG_QCOM_IOMMU=y -CONFIG_IOMMUFD_DRIVER_CORE=y -CONFIG_IOMMUFD=m -CONFIG_IOMMUFD_VFIO_CONTAINER=y -CONFIG_ROCKCHIP_IOMMU=y -CONFIG_SUN50I_IOMMU=y -CONFIG_TEGRA_IOMMU_SMMU=y -# CONFIG_IPMMU_VMSA is not set -CONFIG_APPLE_DART=m -CONFIG_MTK_IOMMU=m -CONFIG_VIRTIO_IOMMU=y -CONFIG_SPRD_IOMMU=m -# CONFIG_VSI_IOMMU is not set - -# -# Remoteproc drivers -# -CONFIG_REMOTEPROC=y -CONFIG_REMOTEPROC_CDEV=y -CONFIG_IMX_REMOTEPROC=m -CONFIG_IMX_DSP_REMOTEPROC=m -CONFIG_MTK_SCP=m -CONFIG_PRU_REMOTEPROC=m -CONFIG_QCOM_PIL_INFO=m -CONFIG_QCOM_RPROC_COMMON=m -CONFIG_QCOM_Q6V5_COMMON=m -CONFIG_QCOM_Q6V5_ADSP=m -CONFIG_QCOM_Q6V5_MSS=m -CONFIG_QCOM_Q6V5_PAS=m -CONFIG_QCOM_Q6V5_WCSS=m -CONFIG_QCOM_SYSMON=m -# CONFIG_QCOM_WCNSS_PIL is not set -CONFIG_RCAR_REMOTEPROC=m -CONFIG_STM32_RPROC=m -CONFIG_TI_K3_DSP_REMOTEPROC=m -# CONFIG_TI_K3_M4_REMOTEPROC is not set -CONFIG_TI_K3_R5_REMOTEPROC=m -CONFIG_XLNX_R5_REMOTEPROC=m -# end of Remoteproc drivers - -# -# Rpmsg drivers -# -CONFIG_RPMSG=m -CONFIG_RPMSG_CHAR=m -CONFIG_RPMSG_CTRL=m -CONFIG_RPMSG_NS=m -CONFIG_RPMSG_MTK_SCP=m -CONFIG_RPMSG_QCOM_GLINK=m -CONFIG_RPMSG_QCOM_GLINK_RPM=m -CONFIG_RPMSG_QCOM_GLINK_SMEM=m -CONFIG_RPMSG_QCOM_SMD=m -CONFIG_RPMSG_VIRTIO=m -# end of Rpmsg drivers - -CONFIG_SOUNDWIRE=m - -# -# SoundWire Devices -# -CONFIG_SOUNDWIRE_AMD=m -CONFIG_SOUNDWIRE_CADENCE=m -CONFIG_SOUNDWIRE_INTEL=m -CONFIG_SOUNDWIRE_QCOM=m -CONFIG_SOUNDWIRE_MTK=m -CONFIG_SOUNDWIRE_MTK_MT8901_CLK=y -CONFIG_SOUNDWIRE_GENERIC_ALLOCATION=m - -# -# SOC (System On Chip) specific Drivers -# - -# -# Amlogic SoC drivers -# -CONFIG_MESON_CANVAS=m -CONFIG_MESON_CLK_MEASURE=y -CONFIG_MESON_GX_SOCINFO=y -# end of Amlogic SoC drivers - -# -# Apple SoC drivers -# -CONFIG_APPLE_MAILBOX=m -CONFIG_APPLE_RTKIT=m -CONFIG_APPLE_SART=m -CONFIG_APPLE_TUNABLE=m -# end of Apple SoC drivers - -# -# Broadcom SoC drivers -# -# end of Broadcom SoC drivers - -# -# NXP/Freescale QorIQ SoC drivers -# -CONFIG_FSL_DPAA=y -CONFIG_FSL_DPAA_CHECKING=y -CONFIG_FSL_BMAN_TEST=m -# CONFIG_FSL_BMAN_TEST_API is not set -# CONFIG_FSL_QMAN_TEST is not set -CONFIG_QUICC_ENGINE=y -CONFIG_UCC_SLOW=y -CONFIG_UCC_FAST=y -CONFIG_UCC=y -# CONFIG_CPM_TSA is not set -CONFIG_QE_TDM=y -CONFIG_FSL_GUTS=y -CONFIG_FSL_MC_DPIO=m -CONFIG_DPAA2_CONSOLE=m -CONFIG_FSL_RCPM=y -# end of NXP/Freescale QorIQ SoC drivers - -# -# fujitsu SoC drivers -# -CONFIG_A64FX_DIAG=y -# end of fujitsu SoC drivers - -# -# Hisilicon SoC drivers -# -CONFIG_KUNPENG_HCCS=m -# end of Hisilicon SoC drivers - -# -# i.MX SoC drivers -# -CONFIG_SOC_IMX8M=y -CONFIG_SOC_IMX9=m -# end of i.MX SoC drivers - -# -# Enable LiteX SoC Builder specific drivers -# -CONFIG_LITEX=y -CONFIG_LITEX_SOC_CONTROLLER=m -# end of Enable LiteX SoC Builder specific drivers - -# -# MediaTek SoC drivers -# -CONFIG_MTK_CMDQ=m -CONFIG_MTK_DEVAPC=m -CONFIG_MTK_DVFSRC=m -CONFIG_MTK_INFRACFG=y -CONFIG_MTK_PMIC_WRAP=m -CONFIG_MTK_REGULATOR_COUPLER=y -CONFIG_MTK_MMSYS=m -CONFIG_MTK_SVS=m -CONFIG_MTK_SOCINFO=m -CONFIG_MTK_SSPM_CI=y -CONFIG_MTK_POWER_WRAP=y -# end of MediaTek SoC drivers - -CONFIG_POLARFIRE_SOC_IRQ_MUX=y -CONFIG_POLARFIRE_SOC_SYS_CTRL=m -CONFIG_POLARFIRE_SOC_SYSCONS=y -CONFIG_WPCM450_SOC=m -CONFIG_PXA_SSP=m - -# -# Qualcomm SoC drivers -# -CONFIG_QCOM_ADSP_PWR_LMTS=m -CONFIG_QCOM_AOSS_QMP=m -CONFIG_QCOM_COMMAND_DB=y -CONFIG_QCOM_GENI_SE=y -CONFIG_QCOM_GSBI=m -CONFIG_QCOM_LLCC=m -CONFIG_QCOM_KRYO_L2_ACCESSORS=y -CONFIG_QCOM_MDT_LOADER=m -CONFIG_QCOM_OCMEM=m -CONFIG_QCOM_PD_MAPPER=m -CONFIG_QCOM_PDR_HELPERS=m -CONFIG_QCOM_PDR_MSG=m -CONFIG_QCOM_PMIC_PDCHARGER_ULOG=m -CONFIG_QCOM_PMIC_GLINK=m -CONFIG_QCOM_QMI_HELPERS=m -CONFIG_QCOM_RAMP_CTRL=m -CONFIG_QCOM_RMTFS_MEM=m -CONFIG_QCOM_RPM_MASTER_STATS=m -CONFIG_QCOM_RPMH=y -CONFIG_QCOM_SMEM=m -CONFIG_QCOM_SMD_RPM=m -CONFIG_QCOM_SMEM_STATE=y -CONFIG_QCOM_SMP2P=m -CONFIG_QCOM_SMSM=m -CONFIG_QCOM_SOCINFO=m -CONFIG_QCOM_SPM=y -CONFIG_QCOM_STATS=m -CONFIG_QCOM_WCNSS_CTRL=m -CONFIG_QCOM_APR=m -CONFIG_QCOM_ICC_BWMON=m -CONFIG_QCOM_INLINE_CRYPTO_ENGINE=m -CONFIG_QCOM_PBS=m -# end of Qualcomm SoC drivers - -CONFIG_QCOM_UBWC_CONFIG=m -CONFIG_SOC_RENESAS=y -CONFIG_ARCH_RCAR_GEN3=y -CONFIG_ARCH_RCAR_GEN4=y -CONFIG_ARCH_RCAR_GEN5=y -CONFIG_ARCH_RZG2L=y -CONFIG_ARCH_R8A774A1=y -CONFIG_ARCH_R8A774B1=y -CONFIG_ARCH_R8A774C0=y -CONFIG_ARCH_R8A774E1=y -CONFIG_ARCH_R8A77951=y -CONFIG_ARCH_R8A77960=y -CONFIG_ARCH_R8A77961=y -CONFIG_ARCH_R8A77965=y -CONFIG_ARCH_R8A77970=y -CONFIG_ARCH_R8A77980=y -CONFIG_ARCH_R8A77990=y -CONFIG_ARCH_R8A77995=y -CONFIG_ARCH_R8A779A0=y -CONFIG_ARCH_R8A779F0=y -CONFIG_ARCH_R8A779G0=y -CONFIG_ARCH_R8A779H0=y -CONFIG_ARCH_R8A78000=y -CONFIG_ARCH_R9A07G043=y -CONFIG_ARCH_R9A07G044=y -CONFIG_ARCH_R9A07G054=y -CONFIG_ARCH_R9A08G045=y -CONFIG_ARCH_R9A08G046=y -CONFIG_ARCH_R9A09G011=y -CONFIG_ARCH_R9A09G047=y -CONFIG_ARCH_R9A09G056=y -CONFIG_ARCH_R9A09G057=y -CONFIG_ARCH_R9A09G077=y -CONFIG_ARCH_R9A09G087=y -# CONFIG_RCAR_MFIS is not set -CONFIG_PWC_RZV2M=y -CONFIG_RST_RCAR=y -CONFIG_SYSC_RZ=y -CONFIG_SYSC_R9A08G045=y -CONFIG_SYSC_R9A08G046=y -CONFIG_SYS_R9A09G047=y -CONFIG_SYS_R9A09G056=y -CONFIG_SYS_R9A09G057=y -CONFIG_ROCKCHIP_GRF=y -CONFIG_ROCKCHIP_IODOMAIN=m -CONFIG_ROCKCHIP_DTPM=m - -# -# Sophgo SoC drivers -# -CONFIG_SOPHGO_CV1800_RTCSYS=m -CONFIG_SOPHGO_SG2044_TOPSYS=m -# end of Sophgo SoC drivers - -CONFIG_SUNXI_MBUS=y -CONFIG_SUNXI_SRAM=y -CONFIG_ARCH_TEGRA_132_SOC=y -CONFIG_ARCH_TEGRA_210_SOC=y -CONFIG_ARCH_TEGRA_186_SOC=y -CONFIG_ARCH_TEGRA_194_SOC=y -CONFIG_ARCH_TEGRA_234_SOC=y -CONFIG_ARCH_TEGRA_238_SOC=y -CONFIG_ARCH_TEGRA_241_SOC=y -CONFIG_ARCH_TEGRA_264_SOC=y -CONFIG_SOC_TEGRA_FUSE=y -CONFIG_SOC_TEGRA_FLOWCTRL=y -CONFIG_SOC_TEGRA_PMC=y -CONFIG_SOC_TEGRA_CBB=m -CONFIG_SOC_TI=y -CONFIG_TI_K3_RINGACC=y -CONFIG_TI_K3_SOCINFO=y -CONFIG_TI_PRUSS=m -CONFIG_TI_SCI_INTA_MSI_DOMAIN=y - -# -# Xilinx SoC drivers -# -CONFIG_ZYNQMP_POWER=y -CONFIG_XLNX_EVENT_MANAGER=y -# end of Xilinx SoC drivers -# end of SOC (System On Chip) specific Drivers - -# -# PM Domains -# -CONFIG_OWL_PM_DOMAINS_HELPER=y -CONFIG_OWL_PM_DOMAINS=y - -# -# Amlogic PM Domains -# -CONFIG_MESON_EE_PM_DOMAINS=y -CONFIG_MESON_SECURE_PM_DOMAINS=y -# end of Amlogic PM Domains - -CONFIG_APPLE_PMGR_PWRSTATE=y -CONFIG_ARM_SCMI_PERF_DOMAIN=y -CONFIG_ARM_SCMI_POWER_DOMAIN=m -CONFIG_ARM_SCPI_POWER_DOMAIN=m - -# -# Broadcom PM Domains -# -# end of Broadcom PM Domains - -# -# i.MX PM Domains -# -CONFIG_IMX_GPCV2_PM_DOMAINS=y -CONFIG_IMX8M_BLK_CTRL=y -CONFIG_IMX9_BLK_CTRL=y -CONFIG_IMX_SCU_PD=y -# end of i.MX PM Domains - -# -# Marvell PM Domains -# -CONFIG_PXA1908_PM_DOMAINS=m -# end of Marvell PM Domains - -# -# MediaTek PM Domains -# -CONFIG_MTK_SCPSYS=y -CONFIG_MTK_SCPSYS_PM_DOMAINS=y -CONFIG_MTK_MFG_PM_DOMAIN=y -# end of MediaTek PM Domains - -CONFIG_AIROHA_CPU_PM_DOMAIN=m - -# -# Qualcomm PM Domains -# -CONFIG_QCOM_CPR=m -CONFIG_QCOM_RPMHPD=y -CONFIG_QCOM_RPMPD=m -# end of Qualcomm PM Domains - -# -# Renesas PM Domains -# -CONFIG_SYSC_RCAR=y -CONFIG_SYSC_RCAR_GEN4=y -CONFIG_SYSC_R8A774A1=y -CONFIG_SYSC_R8A774B1=y -CONFIG_SYSC_R8A774C0=y -CONFIG_SYSC_R8A774E1=y -CONFIG_SYSC_R8A7795=y -CONFIG_SYSC_R8A77960=y -CONFIG_SYSC_R8A77961=y -CONFIG_SYSC_R8A77965=y -CONFIG_SYSC_R8A77970=y -CONFIG_SYSC_R8A77980=y -CONFIG_SYSC_R8A77990=y -CONFIG_SYSC_R8A77995=y -CONFIG_SYSC_R8A779A0=y -CONFIG_SYSC_R8A779F0=y -CONFIG_SYSC_R8A779G0=y -CONFIG_SYSC_R8A779H0=y -# end of Renesas PM Domains - -CONFIG_ROCKCHIP_PM_DOMAINS=y -CONFIG_SUN20I_PPU=y -CONFIG_SUN50I_H6_PRCM_PPU=m -CONFIG_SUN55I_PCK600=m -CONFIG_SOC_TEGRA_POWERGATE_BPMP=y -CONFIG_TI_SCI_PM_DOMAINS=m -CONFIG_ZYNQMP_PM_DOMAINS=y -# end of PM Domains - -CONFIG_PM_DEVFREQ=y - -# -# DEVFREQ Governors -# -CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y -CONFIG_DEVFREQ_GOV_PERFORMANCE=y -CONFIG_DEVFREQ_GOV_POWERSAVE=y -CONFIG_DEVFREQ_GOV_USERSPACE=y -CONFIG_DEVFREQ_GOV_PASSIVE=y - -# -# DEVFREQ Drivers -# -CONFIG_ARM_HISI_UNCORE_DEVFREQ=m -CONFIG_ARM_IMX_BUS_DEVFREQ=m -CONFIG_ARM_IMX8M_DDRC_DEVFREQ=m -CONFIG_ARM_TEGRA_DEVFREQ=m -CONFIG_ARM_MEDIATEK_CCI_DEVFREQ=m -CONFIG_ARM_RK3399_DMC_DEVFREQ=m -CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ=m -CONFIG_PM_DEVFREQ_EVENT=y -CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI=m -CONFIG_EXTCON=y - -# -# Extcon Device Drivers -# -CONFIG_EXTCON_ADC_JACK=m -CONFIG_EXTCON_FSA9480=m -CONFIG_EXTCON_GPIO=m -CONFIG_EXTCON_LC824206XA=m -CONFIG_EXTCON_MAX14577=m -CONFIG_EXTCON_MAX3355=m -CONFIG_EXTCON_MAX77693=m -CONFIG_EXTCON_MAX77843=m -CONFIG_EXTCON_MAX8997=m -CONFIG_EXTCON_MAX14526=m -CONFIG_EXTCON_PALMAS=m -CONFIG_EXTCON_PTN5150=m -CONFIG_EXTCON_QCOM_SPMI_MISC=m -CONFIG_EXTCON_RT8973A=m -CONFIG_EXTCON_SM5502=m -CONFIG_EXTCON_USB_GPIO=m -CONFIG_EXTCON_USBC_CROS_EC=m -CONFIG_EXTCON_USBC_TUSB320=m -CONFIG_EXTCON_RTK_TYPE_C=m -CONFIG_MEMORY=y -CONFIG_ARM_PL172_MPMC=m -CONFIG_OMAP_GPMC=y -# CONFIG_OMAP_GPMC_DEBUG is not set -CONFIG_FPGA_DFL_EMIF=m -CONFIG_FSL_IFC=y -CONFIG_MTK_SMI=m -CONFIG_RENESAS_RPCIF=m -CONFIG_STM32_FMC2_EBI=m -CONFIG_STM32_OMM=m -CONFIG_TEGRA_MC=y -CONFIG_TEGRA210_EMC_TABLE=y -CONFIG_TEGRA210_EMC=m -CONFIG_IIO=m -CONFIG_IIO_BUFFER=y -CONFIG_IIO_BUFFER_CB=m -CONFIG_IIO_BUFFER_DMA=m -CONFIG_IIO_BUFFER_DMAENGINE=m -CONFIG_IIO_BUFFER_HW_CONSUMER=m -CONFIG_IIO_KFIFO_BUF=m -CONFIG_IIO_TRIGGERED_BUFFER=m -CONFIG_IIO_CONFIGFS=m -CONFIG_IIO_GTS_HELPER=m -CONFIG_IIO_TRIGGER=y -CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 -CONFIG_IIO_SW_DEVICE=m -CONFIG_IIO_SW_TRIGGER=m -CONFIG_IIO_TRIGGERED_EVENT=m -CONFIG_IIO_BACKEND=m - -# -# Accelerometers -# -CONFIG_ADIS16201=m -CONFIG_ADIS16209=m -CONFIG_ADXL313=m -CONFIG_ADXL313_I2C=m -CONFIG_ADXL313_SPI=m -CONFIG_ADXL345=m -CONFIG_ADXL345_I2C=m -CONFIG_ADXL345_SPI=m -CONFIG_ADXL355=m -CONFIG_ADXL355_I2C=m -CONFIG_ADXL355_SPI=m -CONFIG_ADXL367=m -CONFIG_ADXL367_SPI=m -CONFIG_ADXL367_I2C=m -CONFIG_ADXL372=m -CONFIG_ADXL372_SPI=m -CONFIG_ADXL372_I2C=m -CONFIG_ADXL380=m -CONFIG_ADXL380_SPI=m -CONFIG_ADXL380_I2C=m -CONFIG_BMA220=m -CONFIG_BMA220_I2C=m -CONFIG_BMA220_SPI=m -CONFIG_BMA400=m -CONFIG_BMA400_I2C=m -CONFIG_BMA400_SPI=m -CONFIG_BMC150_ACCEL=m -CONFIG_BMC150_ACCEL_I2C=m -CONFIG_BMC150_ACCEL_SPI=m -CONFIG_BMI088_ACCEL=m -CONFIG_BMI088_ACCEL_I2C=m -CONFIG_BMI088_ACCEL_SPI=m -CONFIG_DA280=m -CONFIG_DA311=m -CONFIG_DMARD06=m -CONFIG_DMARD09=m -CONFIG_DMARD10=m -CONFIG_FXLS8962AF=m -CONFIG_FXLS8962AF_I2C=m -CONFIG_FXLS8962AF_SPI=m -CONFIG_HID_SENSOR_ACCEL_3D=m -CONFIG_IIO_CROS_EC_ACCEL_LEGACY=m -CONFIG_IIO_ST_ACCEL_3AXIS=m -CONFIG_IIO_ST_ACCEL_I2C_3AXIS=m -CONFIG_IIO_ST_ACCEL_SPI_3AXIS=m -CONFIG_IIO_KX022A=m -CONFIG_IIO_KX022A_SPI=m -CONFIG_IIO_KX022A_I2C=m -CONFIG_KXSD9=m -CONFIG_KXSD9_SPI=m -CONFIG_KXSD9_I2C=m -CONFIG_KXCJK1013=m -CONFIG_MC3230=m -CONFIG_MMA7455=m -CONFIG_MMA7455_I2C=m -CONFIG_MMA7455_SPI=m -CONFIG_MMA7660=m -CONFIG_MMA8452=m -CONFIG_MMA9551_CORE=m -CONFIG_MMA9551=m -CONFIG_MMA9553=m -CONFIG_MSA311=m -CONFIG_MXC4005=m -CONFIG_MXC6255=m -CONFIG_SCA3000=m -CONFIG_SCA3300=m -CONFIG_STK8312=m -CONFIG_STK8BA50=m -# end of Accelerometers - -# -# Analog to digital converters -# -CONFIG_IIO_ADC_HELPER=m -CONFIG_88PM886_GPADC=m -CONFIG_AD_SIGMA_DELTA=m -CONFIG_AD4000=m -CONFIG_AD4030=m -CONFIG_AD4062=m -CONFIG_AD4080=m -CONFIG_AD4130=m -CONFIG_AD4134=m -CONFIG_AD4170_4=m -# CONFIG_AD4691 is not set -CONFIG_AD4695=m -CONFIG_AD4851=m -CONFIG_AD7091R=m -CONFIG_AD7091R5=m -CONFIG_AD7091R8=m -CONFIG_AD7124=m -CONFIG_AD7173=m -CONFIG_AD7191=m -CONFIG_AD7192=m -CONFIG_AD7266=m -CONFIG_AD7280=m -CONFIG_AD7291=m -CONFIG_AD7292=m -CONFIG_AD7298=m -CONFIG_AD7380=m -CONFIG_AD7405=m -CONFIG_AD7476=m -CONFIG_AD7606=m -CONFIG_AD7606_IFACE_PARALLEL=m -CONFIG_AD7606_IFACE_SPI=m -CONFIG_AD7625=m -CONFIG_AD7766=m -CONFIG_AD7768_1=m -CONFIG_AD7779=m -CONFIG_AD7780=m -CONFIG_AD7791=m -CONFIG_AD7793=m -CONFIG_AD7887=m -CONFIG_AD7923=m -CONFIG_AD7944=m -CONFIG_AD7949=m -CONFIG_AD799X=m -CONFIG_AD9467=m -CONFIG_ADE9000=m -CONFIG_ADI_AXI_ADC=m -CONFIG_AXP20X_ADC=m -CONFIG_AXP288_ADC=m -CONFIG_BERLIN2_ADC=m -CONFIG_CC10001_ADC=m -CONFIG_CPCAP_ADC=m -CONFIG_DA9150_GPADC=m -CONFIG_DLN2_ADC=m -CONFIG_ENVELOPE_DETECTOR=m -CONFIG_GEHC_PMC_ADC=m -CONFIG_HI8435=m -CONFIG_HX711=m -CONFIG_INA2XX_ADC=m -CONFIG_IMX7D_ADC=m -CONFIG_IMX8QXP_ADC=m -CONFIG_IMX93_ADC=m -CONFIG_LP8788_ADC=m -CONFIG_LTC2309=m -CONFIG_LTC2471=m -CONFIG_LTC2485=m -CONFIG_LTC2496=m -CONFIG_LTC2497=m -CONFIG_MAX1027=m -CONFIG_MAX11100=m -CONFIG_MAX1118=m -CONFIG_MAX11205=m -CONFIG_MAX11410=m -CONFIG_MAX1241=m -CONFIG_MAX1363=m -CONFIG_MAX14001=m -CONFIG_MAX34408=m -CONFIG_MAX77541_ADC=m -CONFIG_MAX9611=m -CONFIG_MCP320X=m -CONFIG_MCP3422=m -CONFIG_MCP3564=m -CONFIG_MCP3911=m -CONFIG_MEDIATEK_MT6359_AUXADC=m -CONFIG_MEDIATEK_MT6360_ADC=m -CONFIG_MEDIATEK_MT6370_ADC=m -CONFIG_MEDIATEK_MT6577_AUXADC=m -CONFIG_MEN_Z188_ADC=m -CONFIG_MESON_SARADC=m -CONFIG_MP2629_ADC=m -CONFIG_NAU7802=m -CONFIG_NCT7201=m -CONFIG_NPCM_ADC=m -CONFIG_NXP_SAR_ADC=m -CONFIG_PAC1921=m -CONFIG_PAC1934=m -CONFIG_PALMAS_GPADC=m -CONFIG_QCOM_VADC_COMMON=m -CONFIG_QCOM_SPMI_RRADC=m -CONFIG_QCOM_SPMI_IADC=m -CONFIG_QCOM_SPMI_VADC=m -CONFIG_QCOM_SPMI_ADC5=m -# CONFIG_QCOM_SPMI_ADC5_GEN3 is not set -CONFIG_RN5T618_ADC=m -CONFIG_ROHM_BD79112=m -CONFIG_ROHM_BD79124=m -CONFIG_ROCKCHIP_SARADC=m -CONFIG_RICHTEK_RTQ6056=m -CONFIG_RZG2L_ADC=m -CONFIG_RZT2H_ADC=m -CONFIG_SC27XX_ADC=m -# CONFIG_SOPHGO_CV1800B_ADC is not set -CONFIG_SD_ADC_MODULATOR=m -CONFIG_STM32_ADC_CORE=m -CONFIG_STM32_ADC=m -CONFIG_STM32_DFSDM_CORE=m -CONFIG_STM32_DFSDM_ADC=m -CONFIG_STMPE_ADC=m -# CONFIG_SUN4I_GPADC is not set -CONFIG_SUN20I_GPADC=m -CONFIG_TI_ADC081C=m -CONFIG_TI_ADC0832=m -CONFIG_TI_ADC084S021=m -CONFIG_TI_ADC108S102=m -CONFIG_TI_ADC12138=m -CONFIG_TI_ADC128S052=m -CONFIG_TI_ADC161S626=m -CONFIG_TI_ADS1015=m -CONFIG_TI_ADS1018=m -CONFIG_TI_ADS1100=m -CONFIG_TI_ADS1119=m -CONFIG_TI_ADS124S08=m -CONFIG_TI_ADS1298=m -CONFIG_TI_ADS131E08=m -CONFIG_TI_ADS131M02=m -CONFIG_TI_ADS7138=m -CONFIG_TI_ADS7924=m -CONFIG_TI_ADS7950=m -CONFIG_TI_ADS8344=m -CONFIG_TI_ADS8688=m -CONFIG_TI_AM335X_ADC=m -CONFIG_TI_LMP92064=m -CONFIG_TI_TLC4541=m -CONFIG_TI_TSC2046=m -CONFIG_TWL4030_MADC=m -CONFIG_TWL6030_GPADC=m -CONFIG_VF610_ADC=m -CONFIG_VIPERBOARD_ADC=m -CONFIG_XILINX_XADC=m -CONFIG_XILINX_AMS=m -# end of Analog to digital converters - -# -# Analog to digital and digital to analog converters -# -CONFIG_AD74115=m -CONFIG_AD74413R=m -# end of Analog to digital and digital to analog converters - -# -# Analog Front Ends -# -CONFIG_IIO_RESCALE=m -# end of Analog Front Ends - -# -# Amplifiers -# -CONFIG_AD8366=m -CONFIG_ADA4250=m -CONFIG_ADL8113=m -CONFIG_HMC425=m -# end of Amplifiers - -# -# Capacitance to digital converters -# -CONFIG_AD7150=m -CONFIG_AD7746=m -# end of Capacitance to digital converters - -# -# Chemical Sensors -# -CONFIG_AOSONG_AGS02MA=m -CONFIG_ATLAS_PH_SENSOR=m -CONFIG_ATLAS_EZO_SENSOR=m -CONFIG_BME680=m -CONFIG_BME680_I2C=m -CONFIG_BME680_SPI=m -CONFIG_CCS811=m -CONFIG_ENS160=m -CONFIG_ENS160_I2C=m -CONFIG_ENS160_SPI=m -CONFIG_IAQCORE=m -CONFIG_MHZ19B=m -CONFIG_PMS7003=m -CONFIG_SCD30_CORE=m -CONFIG_SCD30_I2C=m -CONFIG_SCD30_SERIAL=m -CONFIG_SCD4X=m -CONFIG_SEN0322=m -CONFIG_SENSIRION_SGP30=m -CONFIG_SENSIRION_SGP40=m -CONFIG_SPS30=m -CONFIG_SPS30_I2C=m -CONFIG_SPS30_SERIAL=m -CONFIG_SENSEAIR_SUNRISE_CO2=m -CONFIG_VZ89X=m -# end of Chemical Sensors - -CONFIG_IIO_CROS_EC_SENSORS_CORE=m -CONFIG_IIO_CROS_EC_SENSORS=m -CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE=m -CONFIG_IIO_CROS_EC_ACTIVITY=m - -# -# Hid Sensor IIO Common -# -CONFIG_HID_SENSOR_IIO_COMMON=m -CONFIG_HID_SENSOR_IIO_TRIGGER=m -# end of Hid Sensor IIO Common - -CONFIG_IIO_INV_SENSORS_TIMESTAMP=m -CONFIG_IIO_MS_SENSORS_I2C=m - -# -# IIO SCMI Sensors -# -CONFIG_IIO_SCMI=m -# end of IIO SCMI Sensors - -# -# SSP Sensor Common -# -CONFIG_IIO_SSP_SENSORS_COMMONS=m -CONFIG_IIO_SSP_SENSORHUB=m -# end of SSP Sensor Common - -CONFIG_IIO_ST_SENSORS_I2C=m -CONFIG_IIO_ST_SENSORS_SPI=m -CONFIG_IIO_ST_SENSORS_CORE=m - -# -# Digital to analog converters -# -CONFIG_AD3530R=m -CONFIG_AD3552R_HS=m -CONFIG_AD3552R_LIB=m -CONFIG_AD3552R=m -CONFIG_AD5064=m -CONFIG_AD5360=m -CONFIG_AD5380=m -CONFIG_AD5421=m -CONFIG_AD5446=m -CONFIG_AD5446_SPI=m -CONFIG_AD5446_I2C=m -CONFIG_AD5449=m -CONFIG_AD5592R_BASE=m -CONFIG_AD5592R=m -CONFIG_AD5593R=m -CONFIG_AD5504=m -CONFIG_AD5624R_SPI=m -# CONFIG_AD5706R is not set -CONFIG_AD9739A=m -CONFIG_ADI_AXI_DAC=m -CONFIG_LTC2688=m -CONFIG_AD5686=m -CONFIG_AD5686_SPI=m -CONFIG_AD5696_I2C=m -CONFIG_AD5755=m -CONFIG_AD5758=m -CONFIG_AD5761=m -CONFIG_AD5764=m -CONFIG_AD5766=m -CONFIG_AD5770R=m -CONFIG_AD5791=m -CONFIG_AD7293=m -CONFIG_AD7303=m -CONFIG_AD8460=m -CONFIG_AD8801=m -CONFIG_BD79703=m -CONFIG_DPOT_DAC=m -CONFIG_DS4424=m -CONFIG_LTC1660=m -CONFIG_LTC2632=m -CONFIG_LTC2664=m -CONFIG_M62332=m -CONFIG_MAX517=m -CONFIG_MAX22007=m -CONFIG_MAX5522=m -CONFIG_MAX5821=m -CONFIG_MCP4725=m -CONFIG_MCP4728=m -CONFIG_MCP47FEB02=m -CONFIG_MCP4821=m -CONFIG_MCP4922=m -CONFIG_STM32_DAC=m -CONFIG_STM32_DAC_CORE=m -CONFIG_TI_DAC082S085=m -CONFIG_TI_DAC5571=m -CONFIG_TI_DAC7311=m -CONFIG_TI_DAC7612=m -CONFIG_VF610_DAC=m -# end of Digital to analog converters - -# -# IIO dummy driver -# -CONFIG_IIO_SIMPLE_DUMMY=m -# CONFIG_IIO_SIMPLE_DUMMY_EVENTS is not set -# CONFIG_IIO_SIMPLE_DUMMY_BUFFER is not set -# end of IIO dummy driver - -# -# Filters -# -CONFIG_ADMV8818=m -# end of Filters - -# -# Frequency Synthesizers DDS/PLL -# - -# -# Clock Generator/Distribution -# -CONFIG_AD9523=m -# end of Clock Generator/Distribution - -# -# Phase-Locked Loop (PLL) frequency synthesizers -# -CONFIG_ADF4350=m -CONFIG_ADF4371=m -CONFIG_ADF4377=m -CONFIG_ADMFM2000=m -CONFIG_ADMV1013=m -CONFIG_ADMV1014=m -CONFIG_ADMV4420=m -CONFIG_ADRF6780=m -# end of Phase-Locked Loop (PLL) frequency synthesizers -# end of Frequency Synthesizers DDS/PLL - -# -# Digital gyroscope sensors -# -CONFIG_ADIS16080=m -CONFIG_ADIS16130=m -CONFIG_ADIS16136=m -CONFIG_ADIS16260=m -CONFIG_ADXRS290=m -CONFIG_ADXRS450=m -CONFIG_BMG160=m -CONFIG_BMG160_I2C=m -CONFIG_BMG160_SPI=m -CONFIG_FXAS21002C=m -CONFIG_FXAS21002C_I2C=m -CONFIG_FXAS21002C_SPI=m -CONFIG_HID_SENSOR_GYRO_3D=m -CONFIG_MPU3050=m -CONFIG_MPU3050_I2C=m -CONFIG_IIO_ST_GYRO_3AXIS=m -CONFIG_IIO_ST_GYRO_I2C_3AXIS=m -CONFIG_IIO_ST_GYRO_SPI_3AXIS=m -CONFIG_ITG3200=m -# end of Digital gyroscope sensors - -# -# Health Sensors -# - -# -# Heart Rate Monitors -# -CONFIG_AFE4403=m -CONFIG_AFE4404=m -CONFIG_MAX30100=m -CONFIG_MAX30102=m -# end of Heart Rate Monitors -# end of Health Sensors - -# -# Humidity sensors -# -CONFIG_AM2315=m -CONFIG_DHT11=m -CONFIG_ENS210=m -CONFIG_HDC100X=m -CONFIG_HDC2010=m -CONFIG_HDC3020=m -CONFIG_HID_SENSOR_HUMIDITY=m -CONFIG_HTS221=m -CONFIG_HTS221_I2C=m -CONFIG_HTS221_SPI=m -CONFIG_HTU21=m -CONFIG_SI7005=m -CONFIG_SI7020=m -# end of Humidity sensors - -# -# Inertial measurement units -# -CONFIG_ADIS16400=m -CONFIG_ADIS16460=m -CONFIG_ADIS16475=m -CONFIG_ADIS16480=m -CONFIG_ADIS16550=m -CONFIG_BMI160=m -CONFIG_BMI160_I2C=m -CONFIG_BMI160_SPI=m -CONFIG_BMI270=m -CONFIG_BMI270_I2C=m -CONFIG_BMI270_SPI=m -CONFIG_BMI323=m -CONFIG_BMI323_I2C=m -CONFIG_BMI323_SPI=m -CONFIG_BOSCH_BNO055=m -CONFIG_BOSCH_BNO055_SERIAL=m -CONFIG_BOSCH_BNO055_I2C=m -CONFIG_FXOS8700=m -CONFIG_FXOS8700_I2C=m -CONFIG_FXOS8700_SPI=m -CONFIG_KMX61=m -CONFIG_INV_ICM42600=m -CONFIG_INV_ICM42600_I2C=m -CONFIG_INV_ICM42600_SPI=m -CONFIG_INV_ICM45600=m -CONFIG_INV_ICM45600_I2C=m -CONFIG_INV_ICM45600_SPI=m -CONFIG_INV_ICM45600_I3C=m -CONFIG_INV_MPU6050_IIO=m -CONFIG_INV_MPU6050_I2C=m -CONFIG_INV_MPU6050_SPI=m -CONFIG_SMI240=m -CONFIG_SMI330=m -CONFIG_SMI330_I2C=m -CONFIG_SMI330_SPI=m -CONFIG_IIO_ST_LSM6DSX=m -CONFIG_IIO_ST_LSM6DSX_I2C=m -CONFIG_IIO_ST_LSM6DSX_SPI=m -CONFIG_IIO_ST_LSM6DSX_I3C=m -CONFIG_IIO_ST_LSM9DS0=m -CONFIG_IIO_ST_LSM9DS0_I2C=m -CONFIG_IIO_ST_LSM9DS0_SPI=m -# end of Inertial measurement units - -CONFIG_IIO_ADIS_LIB=m -CONFIG_IIO_ADIS_LIB_BUFFER=y - -# -# Light sensors -# -CONFIG_ACPI_ALS=m -CONFIG_ADJD_S311=m -CONFIG_ADUX1020=m -CONFIG_AL3000A=m -CONFIG_AL3010=m -CONFIG_AL3320A=m -CONFIG_APDS9160=m -CONFIG_APDS9300=m -CONFIG_APDS9306=m -CONFIG_APDS9960=m -# CONFIG_APDS9999 is not set -CONFIG_AS73211=m -CONFIG_BH1745=m -CONFIG_BH1750=m -CONFIG_BH1780=m -CONFIG_CM32181=m -CONFIG_CM3232=m -CONFIG_CM3323=m -CONFIG_CM3605=m -CONFIG_CM36651=m -CONFIG_IIO_CROS_EC_LIGHT_PROX=m -CONFIG_GP2AP002=m -CONFIG_GP2AP020A00F=m -CONFIG_IQS621_ALS=m -CONFIG_SENSORS_ISL29018=m -CONFIG_SENSORS_ISL29028=m -CONFIG_ISL29125=m -CONFIG_ISL76682=m -CONFIG_HID_SENSOR_ALS=m -CONFIG_HID_SENSOR_PROX=m -CONFIG_JSA1212=m -CONFIG_ROHM_BU27034=m -CONFIG_RPR0521=m -CONFIG_SENSORS_LM3533=m -CONFIG_LTR390=m -CONFIG_LTR501=m -CONFIG_LTRF216A=m -CONFIG_LV0104CS=m -CONFIG_MAX44000=m -CONFIG_MAX44009=m -CONFIG_NOA1305=m -CONFIG_OPT3001=m -CONFIG_OPT4001=m -CONFIG_OPT4060=m -CONFIG_PA12203001=m -CONFIG_SI1133=m -CONFIG_SI1145=m -CONFIG_STK3310=m -CONFIG_ST_UVIS25=m -CONFIG_ST_UVIS25_I2C=m -CONFIG_ST_UVIS25_SPI=m -CONFIG_TCS3414=m -CONFIG_TCS3472=m -CONFIG_SENSORS_TSL2563=m -CONFIG_TSL2583=m -CONFIG_TSL2591=m -CONFIG_TSL2772=m -CONFIG_TSL4531=m -CONFIG_US5182D=m -CONFIG_VCNL4000=m -CONFIG_VCNL4035=m -CONFIG_VEML3235=m -# CONFIG_VEML3328 is not set -CONFIG_VEML6030=m -CONFIG_VEML6040=m -CONFIG_VEML6046X00=m -CONFIG_VEML6070=m -CONFIG_VEML6075=m -CONFIG_VL6180=m -CONFIG_ZOPT2201=m -# end of Light sensors - -# -# Magnetometer sensors -# -CONFIG_AF8133J=m -CONFIG_AK8974=m -CONFIG_AK8975=m -CONFIG_AK09911=m -CONFIG_ALS31300=m -CONFIG_BMC150_MAGN=m -CONFIG_BMC150_MAGN_I2C=m -CONFIG_BMC150_MAGN_SPI=m -CONFIG_MAG3110=m -CONFIG_HID_SENSOR_MAGNETOMETER_3D=m -CONFIG_MMC35240=m -CONFIG_MMC5633=m -# CONFIG_MMC5983 is not set -CONFIG_IIO_ST_MAGN_3AXIS=m -CONFIG_IIO_ST_MAGN_I2C_3AXIS=m -CONFIG_IIO_ST_MAGN_SPI_3AXIS=m -CONFIG_INFINEON_TLV493D=m -CONFIG_SENSORS_HMC5843=m -CONFIG_SENSORS_HMC5843_I2C=m -CONFIG_SENSORS_HMC5843_SPI=m -CONFIG_SENSORS_RM3100=m -CONFIG_SENSORS_RM3100_I2C=m -CONFIG_SENSORS_RM3100_SPI=m -CONFIG_SI7210=m -CONFIG_TI_TMAG5273=m -CONFIG_YAMAHA_YAS530=m -# end of Magnetometer sensors - -# -# Multiplexers -# -CONFIG_IIO_MUX=m -# end of Multiplexers - -# -# Inclinometer sensors -# -CONFIG_HID_SENSOR_INCLINOMETER_3D=m -CONFIG_HID_SENSOR_DEVICE_ROTATION=m -# end of Inclinometer sensors - -# -# Triggers - standalone -# -CONFIG_IIO_HRTIMER_TRIGGER=m -CONFIG_IIO_STM32_LPTIMER_TRIGGER=m -CONFIG_IIO_STM32_TIMER_TRIGGER=m -CONFIG_IIO_TIGHTLOOP_TRIGGER=m -CONFIG_IIO_SYSFS_TRIGGER=m -# end of Triggers - standalone - -# -# Linear and angular position sensors -# -CONFIG_IQS624_POS=m -CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=m -# end of Linear and angular position sensors - -# -# Digital potentiometers -# -CONFIG_AD5110=m -CONFIG_AD5272=m -CONFIG_DS1803=m -CONFIG_MAX5432=m -CONFIG_MAX5481=m -CONFIG_MAX5487=m -CONFIG_MCP4018=m -CONFIG_MCP4131=m -CONFIG_MCP4531=m -CONFIG_MCP41010=m -CONFIG_TPL0102=m -CONFIG_X9250=m -# end of Digital potentiometers - -# -# Digital potentiostats -# -CONFIG_LMP91000=m -# end of Digital potentiostats - -# -# Pressure sensors -# -CONFIG_ABP060MG=m -CONFIG_ABP2030PA=m -CONFIG_ABP2030PA_I2C=m -CONFIG_ABP2030PA_SPI=m -CONFIG_ROHM_BM1390=m -CONFIG_BMP280=m -CONFIG_BMP280_I2C=m -CONFIG_BMP280_SPI=m -CONFIG_IIO_CROS_EC_BARO=m -CONFIG_DLHL60D=m -CONFIG_DPS310=m -CONFIG_HID_SENSOR_PRESS=m -CONFIG_HP03=m -CONFIG_HSC030PA=m -CONFIG_HSC030PA_I2C=m -CONFIG_HSC030PA_SPI=m -CONFIG_ICP10100=m -CONFIG_MPL115=m -CONFIG_MPL115_I2C=m -CONFIG_MPL115_SPI=m -CONFIG_MPL3115=m -CONFIG_MPRLS0025PA=m -CONFIG_MPRLS0025PA_I2C=m -CONFIG_MPRLS0025PA_SPI=m -CONFIG_MS5611=m -CONFIG_MS5611_I2C=m -CONFIG_MS5611_SPI=m -CONFIG_MS5637=m -CONFIG_SDP500=m -CONFIG_IIO_ST_PRESS=m -CONFIG_IIO_ST_PRESS_I2C=m -CONFIG_IIO_ST_PRESS_SPI=m -CONFIG_T5403=m -CONFIG_HP206C=m -CONFIG_ZPA2326=m -CONFIG_ZPA2326_I2C=m -CONFIG_ZPA2326_SPI=m -CONFIG_ADP810=m -# end of Pressure sensors - -# -# Lightning sensors -# -CONFIG_AS3935=m -# end of Lightning sensors - -# -# Proximity and distance sensors -# -CONFIG_CROS_EC_MKBP_PROXIMITY=m -CONFIG_D3323AA=m -CONFIG_HX9023S=m -CONFIG_IRSD200=m -CONFIG_ISL29501=m -CONFIG_LIDAR_LITE_V2=m -CONFIG_MB1232=m -CONFIG_PING=m -CONFIG_RFD77402=m -CONFIG_SRF04=m -CONFIG_SX_COMMON=m -CONFIG_SX9310=m -CONFIG_SX9324=m -CONFIG_SX9360=m -CONFIG_SX9500=m -CONFIG_SRF08=m -CONFIG_VCNL3020=m -CONFIG_VL53L0X_I2C=m -# CONFIG_VL53L1X_I2C is not set -CONFIG_AW96103=m -# end of Proximity and distance sensors - -# -# Resolver to digital converters -# -CONFIG_AD2S90=m -CONFIG_AD2S1200=m -CONFIG_AD2S1210=m -# end of Resolver to digital converters - -# -# Temperature sensors -# -CONFIG_IQS620AT_TEMP=m -CONFIG_LTC2983=m -CONFIG_MAXIM_THERMOCOUPLE=m -CONFIG_HID_SENSOR_TEMP=m -CONFIG_MLX90614=m -CONFIG_MLX90632=m -CONFIG_MLX90635=m -CONFIG_TMP006=m -CONFIG_TMP007=m -CONFIG_TMP117=m -CONFIG_TSYS01=m -CONFIG_TSYS02D=m -CONFIG_MAX30208=m -CONFIG_MAX31856=m -CONFIG_MAX31865=m -CONFIG_MCP9600=m -# end of Temperature sensors - -CONFIG_NTB=m -CONFIG_NTB_MSI=y -CONFIG_NTB_IDT=m -CONFIG_NTB_EPF=m -CONFIG_NTB_SWITCHTEC=m -CONFIG_NTB_PINGPONG=m -CONFIG_NTB_TOOL=m -CONFIG_NTB_PERF=m -# CONFIG_NTB_MSI_TEST is not set -CONFIG_NTB_TRANSPORT=m -CONFIG_PWM=y -# CONFIG_PWM_DEBUG is not set -CONFIG_PWM_PROVIDE_GPIO=y -CONFIG_PWM_ADP5585=m -CONFIG_PWM_AIROHA=m -CONFIG_PWM_APPLE=m -CONFIG_PWM_ARGON_FAN_HAT=m -CONFIG_PWM_ATMEL_HLCDC_PWM=m -CONFIG_PWM_ATMEL_TCB=m -CONFIG_PWM_AXI_PWMGEN=m -CONFIG_PWM_BERLIN=m -CONFIG_PWM_CLK=m -CONFIG_PWM_CROS_EC=m -CONFIG_PWM_DWC_CORE=m -CONFIG_PWM_DWC=m -CONFIG_PWM_FSL_FTM=m -CONFIG_PWM_GPIO=m -CONFIG_PWM_HIBVT=m -CONFIG_PWM_IMX1=m -CONFIG_PWM_IMX27=m -CONFIG_PWM_IMX_TPM=m -# CONFIG_PWM_IPQ is not set -CONFIG_PWM_IQS620A=m -CONFIG_PWM_KEEMBAY=m -CONFIG_PWM_LP3943=m -CONFIG_PWM_MAX7360=m -CONFIG_PWM_MC33XS2410=m -CONFIG_PWM_MEDIATEK=m -CONFIG_PWM_MESON=m -CONFIG_PWM_MTK_DISP=m -CONFIG_PWM_NTXEC=m -CONFIG_PWM_OMAP_DMTIMER=m -CONFIG_PWM_PCA9685=m -CONFIG_PWM_PXA=m -CONFIG_PWM_RENESAS_RCAR=m -CONFIG_PWM_RENESAS_RZG2L_GPT=m -CONFIG_PWM_RENESAS_RZ_MTU3=m -CONFIG_PWM_RENESAS_TPU=m -CONFIG_PWM_ROCKCHIP=m -CONFIG_PWM_SL28CPLD=m -CONFIG_PWM_SOPHGO_SG2042=m -CONFIG_PWM_SPRD=m -CONFIG_PWM_STM32=m -CONFIG_PWM_STM32_LP=m -CONFIG_PWM_STMPE=y -CONFIG_PWM_SUN4I=m -CONFIG_PWM_TEGRA=m -CONFIG_PWM_TIECAP=m -CONFIG_PWM_TIEHRPWM=m -CONFIG_PWM_TWL=m -CONFIG_PWM_TWL_LED=m -CONFIG_PWM_VISCONTI=m -CONFIG_PWM_XILINX=m - -# -# IRQ chip support -# -CONFIG_IRQCHIP=y -CONFIG_ARM_GIC=y -CONFIG_ARM_GIC_PM=y -CONFIG_ARM_GIC_MAX_NR=1 -CONFIG_ARM_GIC_V2M=y -CONFIG_ARM_GIC_V3=y -CONFIG_ARM_GIC_ITS_PARENT=y -CONFIG_ARM_GIC_V3_ITS=y -CONFIG_ARM_GIC_V5=y -CONFIG_IRQ_MSI_LIB=y -CONFIG_AL_FIC=y -CONFIG_DW_APB_ICTL=y -CONFIG_HISILICON_IRQ_MBIGEN=y -CONFIG_LAN966X_OIC=m -CONFIG_MADERA_IRQ=m -CONFIG_RENESAS_IRQC=y -CONFIG_RENESAS_RZG2L_IRQC=y -CONFIG_RENESAS_RZT2H_ICU=y -CONFIG_RENESAS_RZV2H_ICU=y -CONFIG_SUN6I_R_INTC=y -CONFIG_SUNXI_NMI_INTC=y -CONFIG_XILINX_INTC=y -CONFIG_IMX_GPCV2=y -CONFIG_MVEBU_GICP=y -CONFIG_MVEBU_ICU=y -CONFIG_MVEBU_ODMI=y -CONFIG_MVEBU_PIC=y -CONFIG_MVEBU_SEI=y -CONFIG_LS_EXTIRQ=y -CONFIG_LS_SCFG_MSI=y -CONFIG_STM32MP_EXTI=m -CONFIG_QCOM_IRQ_COMBINER=y -CONFIG_MESON_IRQ_GPIO=y -CONFIG_QCOM_PDC=y -CONFIG_QCOM_MPM=m -CONFIG_IMX_IRQSTEER=y -CONFIG_IMX_INTMUX=y -CONFIG_IMX_MU_MSI=m -CONFIG_TI_SCI_INTR_IRQCHIP=y -CONFIG_TI_SCI_INTA_IRQCHIP=y -CONFIG_TI_PRUSS_INTC=m -CONFIG_MST_IRQ=y -CONFIG_APPLE_AIC=y -CONFIG_SOPHGO_SG2042_MSI=y -# end of IRQ chip support - -CONFIG_IPACK_BUS=m -CONFIG_BOARD_TPCI200=m -CONFIG_SERIAL_IPOCTAL=m -CONFIG_ARCH_HAS_RESET_CONTROLLER=y -CONFIG_RESET_CONTROLLER=y -CONFIG_RESET_A10SR=m -CONFIG_RESET_BERLIN=y -CONFIG_RESET_GPIO=m -CONFIG_RESET_IMX_SCU=m -CONFIG_RESET_IMX7=y -CONFIG_RESET_IMX8MP_AUDIOMIX=m -CONFIG_RESET_MCHP_SPARX5=y -CONFIG_RESET_NPCM=y -CONFIG_RESET_NUVOTON_MA35D1=y -CONFIG_RESET_POLARFIRE_SOC=y -CONFIG_RESET_QCOM_AOSS=y -CONFIG_RESET_QCOM_PDC=m -CONFIG_RESET_RZG2L_USBPHY_CTRL=y -CONFIG_RESET_RZV2H_USB2PHY=m -CONFIG_RESET_SCMI=m -CONFIG_RESET_SIMPLE=y -# CONFIG_RESET_SKY1 is not set -CONFIG_RESET_SUNXI=y -CONFIG_RESET_TI_SCI=m -CONFIG_RESET_TI_SYSCON=m -CONFIG_RESET_TI_TPS380X=m -CONFIG_RESET_TN48M_CPLD=m -CONFIG_RESET_ZYNQMP=y -CONFIG_RESET_MESON_COMMON=y -CONFIG_RESET_MESON=y -CONFIG_RESET_MESON_AUX=m -CONFIG_RESET_MESON_AUDIO_ARB=m -CONFIG_COMMON_RESET_HI3660=m -CONFIG_COMMON_RESET_HI6220=m -CONFIG_RESET_TEGRA_BPMP=y - -# -# PHY Subsystem -# -CONFIG_PHY_COMMON_PROPS=y -CONFIG_GENERIC_PHY=y -CONFIG_GENERIC_PHY_MIPI_DPHY=y -CONFIG_PHY_AIROHA_PCIE=m -CONFIG_PHY_CAN_TRANSCEIVER=m -CONFIG_PHY_GOOGLE_USB=m -CONFIG_PHY_NXP_PTN3222=m -# CONFIG_PHY_NXP_TJA1145 is not set -CONFIG_PHY_SNPS_EUSB2=m -CONFIG_PHY_XGENE=y -CONFIG_PHY_SUN4I_USB=m -CONFIG_PHY_SUN6I_MIPI_DPHY=m -# CONFIG_PHY_SUN9I_USB is not set -CONFIG_PHY_SUN50I_USB3=m -CONFIG_PHY_MESON8B_USB2=m -CONFIG_PHY_MESON_GXL_USB2=m -CONFIG_PHY_MESON_G12A_MIPI_DPHY_ANALOG=m -CONFIG_PHY_MESON_G12A_USB2=m -CONFIG_PHY_MESON_G12A_USB3_PCIE=m -CONFIG_PHY_MESON_AXG_PCIE=y -CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG=y -CONFIG_PHY_MESON_AXG_MIPI_DPHY=m -CONFIG_PHY_APPLE_ATC=m -# CONFIG_PHY_AX3000_EMMC is not set - -# -# PHY drivers for Broadcom platforms -# -CONFIG_BCM_KONA_USB2_PHY=m -# end of PHY drivers for Broadcom platforms - -CONFIG_PHY_CADENCE_TORRENT=m -CONFIG_PHY_CADENCE_DPHY=m -CONFIG_PHY_CADENCE_DPHY_RX=m -CONFIG_PHY_CADENCE_SIERRA=m -CONFIG_PHY_CADENCE_SALVO=m -CONFIG_PHY_FSL_IMX8MQ_USB=m -CONFIG_PHY_MIXEL_LVDS_PHY=m -CONFIG_PHY_MIXEL_MIPI_DPHY=m -CONFIG_PHY_FSL_IMX8M_PCIE=m -CONFIG_PHY_FSL_IMX8QM_HSIO=m -CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY=m -CONFIG_PHY_FSL_LYNX_CORE=m -# CONFIG_PHY_FSL_LYNX_10G is not set -CONFIG_PHY_FSL_LYNX_28G=m -CONFIG_PHY_HI6220_USB=m -CONFIG_PHY_HI3660_USB=m -CONFIG_PHY_HI3670_USB=m -CONFIG_PHY_HI3670_PCIE=m -CONFIG_PHY_HISTB_COMBPHY=m -CONFIG_PHY_HISI_INNO_USB2=m -CONFIG_PHY_INTEL_KEEMBAY_EMMC=m -CONFIG_PHY_INTEL_KEEMBAY_USB=m -CONFIG_PHY_BERLIN_SATA=m -CONFIG_PHY_BERLIN_USB=m -CONFIG_PHY_MVEBU_A3700_COMPHY=m -CONFIG_PHY_MVEBU_A3700_UTMI=m -CONFIG_PHY_MVEBU_A38X_COMPHY=m -CONFIG_PHY_MVEBU_CP110_COMPHY=m -CONFIG_PHY_MVEBU_CP110_UTMI=m -CONFIG_PHY_PXA_28NM_HSIC=m -CONFIG_PHY_PXA_28NM_USB2=m -CONFIG_PHY_PXA_USB=m -CONFIG_PHY_MTK_PCIE=m -CONFIG_PHY_MTK_XFI_TPHY=m -CONFIG_PHY_MTK_TPHY=m -CONFIG_PHY_MTK_UFS=m -CONFIG_PHY_MTK_XSPHY=m -CONFIG_PHY_MTK_HDMI=m -CONFIG_PHY_MTK_MIPI_CSI_0_5=m -CONFIG_PHY_MTK_MIPI_DSI=m -CONFIG_PHY_MTK_DP=m -CONFIG_PHY_SPARX5_SERDES=m -CONFIG_PHY_LAN966X_SERDES=m -CONFIG_PHY_CPCAP_USB=m -CONFIG_PHY_MAPPHONE_MDM6600=m -CONFIG_PHY_OCELOT_SERDES=m -# CONFIG_PHY_MA35_USB is not set -CONFIG_PHY_QCOM_APQ8064_SATA=m -CONFIG_PHY_QCOM_EDP=m -CONFIG_PHY_QCOM_IPQ4019_USB=m -CONFIG_PHY_QCOM_IPQ806X_SATA=m -CONFIG_PHY_QCOM_PCIE2=m -CONFIG_PHY_QCOM_QMP=m -CONFIG_PHY_QCOM_QMP_COMBO=m -CONFIG_PHY_QCOM_QMP_PCIE=m -CONFIG_PHY_QCOM_QMP_PCIE_8996=m -CONFIG_PHY_QCOM_QMP_UFS=m -CONFIG_PHY_QCOM_QMP_USB=m -CONFIG_PHY_QCOM_QMP_USB_LEGACY=m -CONFIG_PHY_QCOM_QUSB2=m -CONFIG_PHY_QCOM_EUSB2_REPEATER=m -CONFIG_PHY_QCOM_M31_USB=m -CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP=y -CONFIG_PHY_QCOM_M31_EUSB=m -CONFIG_PHY_QCOM_USB_HS=m -CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=m -CONFIG_PHY_QCOM_USB_HSIC=m -CONFIG_PHY_QCOM_USB_HS_28NM=m -CONFIG_PHY_QCOM_USB_SS=m -CONFIG_PHY_QCOM_IPQ806X_USB=m -CONFIG_PHY_QCOM_SGMII_ETH=m -CONFIG_PHY_RTK_RTD_USB2PHY=m -CONFIG_PHY_RTK_RTD_USB3PHY=m -CONFIG_PHY_R8A779F0_ETHERNET_SERDES=m -CONFIG_PHY_RCAR_GEN2=m -CONFIG_PHY_RCAR_GEN3_PCIE=m -CONFIG_PHY_RCAR_GEN3_USB2=m -CONFIG_PHY_RCAR_GEN3_USB3=m -CONFIG_PHY_RZ_G3E_USB3=m -CONFIG_PHY_ROCKCHIP_DP=m -CONFIG_PHY_ROCKCHIP_DPHY_RX0=m -CONFIG_PHY_ROCKCHIP_EMMC=m -CONFIG_PHY_ROCKCHIP_INNO_HDMI=m -CONFIG_PHY_ROCKCHIP_INNO_USB2=m -CONFIG_PHY_ROCKCHIP_INNO_CSIDPHY=m -CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=m -CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY=m -CONFIG_PHY_ROCKCHIP_PCIE=m -CONFIG_PHY_ROCKCHIP_SAMSUNG_DCPHY=m -CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX=m -CONFIG_PHY_ROCKCHIP_SNPS_PCIE3=m -CONFIG_PHY_ROCKCHIP_TYPEC=m -CONFIG_PHY_ROCKCHIP_USB=m -CONFIG_PHY_ROCKCHIP_USBDP=m -CONFIG_PHY_SAMSUNG_USB2=m -CONFIG_PHY_SOPHGO_CV1800_USB2=m -CONFIG_PHY_STM32_COMBOPHY=m -CONFIG_PHY_STM32_USBPHYC=m -CONFIG_PHY_TEGRA_XUSB=m -CONFIG_PHY_TEGRA194_P2U=m -CONFIG_OMAP_USB2=m -CONFIG_PHY_AM654_SERDES=m -CONFIG_PHY_J721E_WIZ=m -# CONFIG_PHY_TI_DS125DF111 is not set -CONFIG_PHY_TI_GMII_SEL=m -CONFIG_PHY_TUSB1210=m -CONFIG_PHY_XILINX_ZYNQMP=m -# end of PHY Subsystem - -CONFIG_POWERCAP=y -CONFIG_IDLE_INJECT=y -CONFIG_ARM_SCMI_POWERCAP=m -CONFIG_DTPM=y -CONFIG_DTPM_CPU=y -# CONFIG_DTPM_DEVFREQ is not set -CONFIG_MCB=m -CONFIG_MCB_PCI=m -CONFIG_MCB_LPC=m - -# -# Performance monitor support -# -CONFIG_ARM_CCI_PMU=y -CONFIG_ARM_CCI400_PMU=y -CONFIG_ARM_CCI5xx_PMU=y -CONFIG_ARM_CCN=y -CONFIG_ARM_CMN=m -# CONFIG_ARM_NI is not set -CONFIG_ARM_PMU=y -CONFIG_ARM_PMU_ACPI=y -CONFIG_ARM_SMMU_V3_PMU=m -CONFIG_ARM_PMUV3=y -CONFIG_ARM_DSU_PMU=m -CONFIG_FSL_IMX8_DDR_PMU=m -CONFIG_FSL_IMX9_DDR_PMU=m -CONFIG_FUJITSU_UNCORE_PMU=m -CONFIG_QCOM_L2_PMU=y -CONFIG_QCOM_L3_PMU=y -CONFIG_THUNDERX2_PMU=m -CONFIG_XGENE_PMU=y -CONFIG_ARM_SPE_PMU=m -CONFIG_ARM64_BRBE=y -CONFIG_ARM_DMC620_PMU=m -CONFIG_MARVELL_CN10K_TAD_PMU=m -CONFIG_APPLE_M1_CPU_PMU=y -CONFIG_ALIBABA_UNCORE_DRW_PMU=m -CONFIG_HISI_PMU=m -CONFIG_HISI_PCIE_PMU=m -CONFIG_HNS3_PMU=m -CONFIG_MARVELL_CN10K_DDR_PMU=m -CONFIG_DWC_PCIE_PMU=m -CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m -CONFIG_NVIDIA_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m -CONFIG_AMPERE_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m -CONFIG_MESON_DDR_PMU=m -CONFIG_CXL_PMU=m -CONFIG_MARVELL_PEM_PMU=m -# CONFIG_NVIDIA_TEGRA410_CMEM_LATENCY_PMU is not set -# CONFIG_NVIDIA_TEGRA410_C2C_PMU is not set -# end of Performance monitor support - -CONFIG_RAS=y -CONFIG_USB4=m -CONFIG_USB4_CONFIGFS=m -# CONFIG_USB4_DEBUGFS_WRITE is not set -CONFIG_USB4_PLATFORM_NHI=m -# CONFIG_USB4_DMA_TEST is not set -# CONFIG_USB4_STREAM is not set - -# -# Android -# -# CONFIG_ANDROID_BINDER_IPC is not set -# end of Android - -CONFIG_LIBNVDIMM=y -CONFIG_BLK_DEV_PMEM=m -CONFIG_ND_CLAIM=y -CONFIG_ND_BTT=m -CONFIG_BTT=y -CONFIG_ND_PFN=m -CONFIG_NVDIMM_PFN=y -CONFIG_NVDIMM_DAX=y -CONFIG_OF_PMEM=m -CONFIG_RAMDAX=m -CONFIG_NVDIMM_KEYS=y -# CONFIG_NVDIMM_SECURITY_TEST is not set -CONFIG_DAX=y -CONFIG_DEV_DAX=m -CONFIG_DEV_DAX_PMEM=m -CONFIG_DEV_DAX_HMEM=m -CONFIG_DEV_DAX_CXL=m -CONFIG_DEV_DAX_HMEM_DEVICES=y -CONFIG_DEV_DAX_FSDEV=m -CONFIG_DEV_DAX_KMEM=m -CONFIG_NVMEM=y -CONFIG_NVMEM_SYSFS=y -CONFIG_NVMEM_LAYOUTS=y - -# -# Layout Types -# -CONFIG_NVMEM_LAYOUT_SL28_VPD=m -CONFIG_NVMEM_LAYOUT_ONIE_TLV=m -CONFIG_NVMEM_LAYOUT_U_BOOT_ENV=m -# end of Layout Types - -CONFIG_NVMEM_APPLE_EFUSES=m -CONFIG_NVMEM_APPLE_SPMI=m -CONFIG_NVMEM_IMX_IIM=m -CONFIG_NVMEM_IMX_OCOTP=m -CONFIG_NVMEM_IMX_OCOTP_ELE=m -CONFIG_NVMEM_IMX_OCOTP_SCU=m -CONFIG_NVMEM_LAYERSCAPE_SFP=m -CONFIG_NVMEM_MAX77759=m -CONFIG_NVMEM_MESON_EFUSE=m -CONFIG_NVMEM_MESON_MX_EFUSE=m -CONFIG_NVMEM_MTK_EFUSE=m -CONFIG_NVMEM_S32G_OCOTP=m -CONFIG_NVMEM_QCOM_QFPROM=m -CONFIG_NVMEM_QCOM_SEC_QFPROM=m -CONFIG_NVMEM_QNAP_MCU_EEPROM=m -CONFIG_NVMEM_RAVE_SP_EEPROM=m -CONFIG_NVMEM_RCAR_EFUSE=m -CONFIG_NVMEM_RMEM=m -CONFIG_NVMEM_ROCKCHIP_EFUSE=m -CONFIG_NVMEM_ROCKCHIP_OTP=m -CONFIG_NVMEM_SC27XX_EFUSE=m -CONFIG_NVMEM_SNVS_LPGPR=m -CONFIG_NVMEM_SPMI_SDAM=m -CONFIG_NVMEM_SPRD_EFUSE=m -CONFIG_NVMEM_STM32_BSEC_OPTEE_TA=y -CONFIG_NVMEM_STM32_ROMEM=m -CONFIG_NVMEM_SUNXI_SID=m -CONFIG_NVMEM_U_BOOT_ENV=m -CONFIG_NVMEM_ZYNQMP=y - -# -# HW tracing support -# -CONFIG_STM=m -CONFIG_STM_PROTO_BASIC=m -CONFIG_STM_PROTO_SYS_T=m -CONFIG_STM_DUMMY=m -CONFIG_STM_SOURCE_CONSOLE=m -CONFIG_STM_SOURCE_HEARTBEAT=m -CONFIG_STM_SOURCE_FTRACE=m -CONFIG_INTEL_TH=m -CONFIG_INTEL_TH_PCI=m -CONFIG_INTEL_TH_ACPI=m -CONFIG_INTEL_TH_GTH=m -CONFIG_INTEL_TH_STH=m -CONFIG_INTEL_TH_MSU=m -CONFIG_INTEL_TH_PTI=m -# CONFIG_INTEL_TH_DEBUG is not set -CONFIG_HISI_PTT=m -# end of HW tracing support - -CONFIG_FPGA=m -CONFIG_FPGA_MGR_SOCFPGA=m -CONFIG_FPGA_MGR_SOCFPGA_A10=m -CONFIG_ALTERA_PR_IP_CORE=m -CONFIG_ALTERA_PR_IP_CORE_PLAT=m -CONFIG_FPGA_MGR_ALTERA_PS_SPI=m -CONFIG_FPGA_MGR_ALTERA_CVP=m -CONFIG_FPGA_MGR_STRATIX10_SOC=m -CONFIG_FPGA_MGR_XILINX_CORE=m -CONFIG_FPGA_MGR_XILINX_SELECTMAP=m -CONFIG_FPGA_MGR_XILINX_SPI=m -CONFIG_FPGA_MGR_ICE40_SPI=m -CONFIG_FPGA_MGR_MACHXO2_SPI=m -CONFIG_FPGA_BRIDGE=m -CONFIG_SOCFPGA_FPGA_BRIDGE=m -CONFIG_ALTERA_FREEZE_BRIDGE=m -CONFIG_XILINX_PR_DECOUPLER=m -CONFIG_FPGA_REGION=m -CONFIG_OF_FPGA_REGION=m -CONFIG_FPGA_DFL=m -CONFIG_FPGA_DFL_FME=m -CONFIG_FPGA_DFL_FME_MGR=m -CONFIG_FPGA_DFL_FME_BRIDGE=m -CONFIG_FPGA_DFL_FME_REGION=m -CONFIG_FPGA_DFL_AFU=m -CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000=m -CONFIG_FPGA_DFL_PCI=m -CONFIG_FPGA_MGR_ZYNQMP_FPGA=m -CONFIG_FPGA_MGR_VERSAL_FPGA=m -# CONFIG_FPGA_M10_BMC_SEC_UPDATE is not set -CONFIG_FPGA_MGR_MICROCHIP_SPI=m -CONFIG_FPGA_MGR_LATTICE_SYSCONFIG=m -CONFIG_FPGA_MGR_LATTICE_SYSCONFIG_SPI=m -# CONFIG_FPGA_MGR_EFINIX_SPI is not set -CONFIG_FSI=m -# CONFIG_FSI_NEW_DEV_NODE is not set -CONFIG_FSI_MASTER_GPIO=m -CONFIG_FSI_MASTER_HUB=m -CONFIG_FSI_MASTER_ASPEED=m -CONFIG_FSI_MASTER_I2CR=m -CONFIG_FSI_SCOM=m -CONFIG_FSI_SBEFIFO=m -CONFIG_FSI_OCC=m -CONFIG_I2CR_SCOM=m -CONFIG_TEE=m -CONFIG_TEE_DMABUF_HEAPS=y -CONFIG_OPTEE=m -# CONFIG_OPTEE_INSECURE_LOAD_IMAGE is not set -CONFIG_OPTEE_STATIC_PROTMEM_POOL=y -CONFIG_ARM_TSTEE=m -CONFIG_QCOMTEE=m -CONFIG_MULTIPLEXER=y -# CONFIG_MUX_CORE is not set - -# -# Multiplexer drivers -# -CONFIG_MUX_ADG792A=m -CONFIG_MUX_ADGS1408=m -CONFIG_MUX_GPIO=m -CONFIG_MUX_MMIO=m -# end of Multiplexer drivers - -CONFIG_PM_OPP=y -CONFIG_SIOX=m -CONFIG_SIOX_BUS_GPIO=m -CONFIG_SLIMBUS=m -CONFIG_SLIM_QCOM_NGD_CTRL=m -CONFIG_INTERCONNECT=y -CONFIG_INTERCONNECT_IMX=m -CONFIG_INTERCONNECT_IMX8MM=m -CONFIG_INTERCONNECT_IMX8MN=m -CONFIG_INTERCONNECT_IMX8MQ=m -CONFIG_INTERCONNECT_IMX8MP=m -CONFIG_INTERCONNECT_MTK=y -CONFIG_INTERCONNECT_MTK_DVFSRC_EMI=m -CONFIG_INTERCONNECT_MTK_MT8183=m -CONFIG_INTERCONNECT_MTK_MT8195=m -CONFIG_INTERCONNECT_MTK_MT8196=m -CONFIG_INTERCONNECT_QCOM=y -CONFIG_INTERCONNECT_QCOM_BCM_VOTER=y -# CONFIG_INTERCONNECT_QCOM_ELIZA is not set -CONFIG_INTERCONNECT_QCOM_GLYMUR=m -# CONFIG_INTERCONNECT_QCOM_HAWI is not set -CONFIG_INTERCONNECT_QCOM_KAANAPALI=m -CONFIG_INTERCONNECT_QCOM_MSM8916=m -CONFIG_INTERCONNECT_QCOM_MSM8937=m -CONFIG_INTERCONNECT_QCOM_MSM8939=m -CONFIG_INTERCONNECT_QCOM_MSM8953=m -CONFIG_INTERCONNECT_QCOM_MSM8976=m -CONFIG_INTERCONNECT_QCOM_MSM8996=m -# CONFIG_INTERCONNECT_QCOM_NORD is not set -CONFIG_INTERCONNECT_QCOM_OSM_L3=m -CONFIG_INTERCONNECT_QCOM_QCM2290=m -CONFIG_INTERCONNECT_QCOM_QCS404=m -CONFIG_INTERCONNECT_QCOM_QCS615=m -CONFIG_INTERCONNECT_QCOM_QCS8300=m -CONFIG_INTERCONNECT_QCOM_QDU1000=m -CONFIG_INTERCONNECT_QCOM_RPMH_POSSIBLE=y -CONFIG_INTERCONNECT_QCOM_RPMH=y -CONFIG_INTERCONNECT_QCOM_SA8775P=y -CONFIG_INTERCONNECT_QCOM_SAR2130P=m -CONFIG_INTERCONNECT_QCOM_SC7180=y -CONFIG_INTERCONNECT_QCOM_SC7280=y -CONFIG_INTERCONNECT_QCOM_SC8180X=y -CONFIG_INTERCONNECT_QCOM_SC8280XP=y -CONFIG_INTERCONNECT_QCOM_SDM660=m -CONFIG_INTERCONNECT_QCOM_SDM670=m -CONFIG_INTERCONNECT_QCOM_SDM845=m -CONFIG_INTERCONNECT_QCOM_SDX75=m -# CONFIG_INTERCONNECT_QCOM_SHIKRA is not set -CONFIG_INTERCONNECT_QCOM_SM6115=m -CONFIG_INTERCONNECT_QCOM_SM6350=m -CONFIG_INTERCONNECT_QCOM_SM7150=m -CONFIG_INTERCONNECT_QCOM_MILOS=y -CONFIG_INTERCONNECT_QCOM_SM8150=m -CONFIG_INTERCONNECT_QCOM_SM8250=m -CONFIG_INTERCONNECT_QCOM_SM8350=m -CONFIG_INTERCONNECT_QCOM_SM8450=m -CONFIG_INTERCONNECT_QCOM_SM8550=m -CONFIG_INTERCONNECT_QCOM_SM8650=m -CONFIG_INTERCONNECT_QCOM_SM8750=m -CONFIG_INTERCONNECT_QCOM_X1E80100=m -CONFIG_INTERCONNECT_QCOM_SMD_RPM=m -CONFIG_INTERCONNECT_CLK=y -CONFIG_COUNTER=m -CONFIG_INTERRUPT_CNT=m -CONFIG_RZ_MTU3_CNT=m -CONFIG_STM32_LPTIMER_CNT=m -CONFIG_STM32_TIMER_CNT=m -CONFIG_TI_ECAP_CAPTURE=m -CONFIG_TI_EQEP=m -CONFIG_MOST=m -CONFIG_MOST_USB_HDM=m -CONFIG_MOST_CDEV=m -CONFIG_MOST_SND=m -CONFIG_PECI=m -CONFIG_PECI_CPU=m -CONFIG_PECI_NPCM=m -CONFIG_HTE=y -CONFIG_HTE_TEGRA194=m -CONFIG_HTE_TEGRA194_TEST=m -CONFIG_CDX_BUS=y -CONFIG_CDX_CONTROLLER=m -CONFIG_ARM64_MPAM_DRIVER=y -# CONFIG_ARM64_MPAM_DRIVER_DEBUG is not set -CONFIG_ARM64_MPAM_RESCTRL_FS=y -# end of Device Drivers - -# -# File systems -# -CONFIG_DCACHE_WORD_ACCESS=y -CONFIG_VALIDATE_FS_PARSER=y -CONFIG_FS_IOMAP=y -CONFIG_FS_STACK=y -CONFIG_BUFFER_HEAD=y -CONFIG_LEGACY_DIRECT_IO=y -# CONFIG_EXT2_FS is not set -CONFIG_EXT4_FS=y -CONFIG_EXT4_USE_FOR_EXT2=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -# CONFIG_EXT4_DEBUG is not set -CONFIG_JBD2=y -# CONFIG_JBD2_DEBUG is not set -CONFIG_FS_MBCACHE=y -CONFIG_JFS_FS=m -CONFIG_JFS_POSIX_ACL=y -CONFIG_JFS_SECURITY=y -# CONFIG_JFS_DEBUG is not set -CONFIG_JFS_STATISTICS=y -CONFIG_XFS_FS=m -CONFIG_XFS_SUPPORT_V4=y -CONFIG_XFS_SUPPORT_ASCII_CI=y -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_XFS_RT=y -# CONFIG_XFS_ONLINE_SCRUB is not set -# CONFIG_XFS_WARN is not set -# CONFIG_XFS_DEBUG is not set -CONFIG_GFS2_FS=m -CONFIG_GFS2_FS_LOCKING_DLM=y -CONFIG_OCFS2_FS=m -CONFIG_OCFS2_FS_O2CB=m -CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m -CONFIG_OCFS2_FS_STATS=y -CONFIG_OCFS2_DEBUG_MASKLOG=y -# CONFIG_OCFS2_DEBUG_FS is not set -CONFIG_BTRFS_FS=y -CONFIG_BTRFS_FS_POSIX_ACL=y -# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set -# CONFIG_BTRFS_DEBUG is not set -# CONFIG_BTRFS_ASSERT is not set -# CONFIG_BTRFS_EXPERIMENTAL is not set -CONFIG_NILFS2_FS=m -CONFIG_F2FS_FS=m -CONFIG_F2FS_STAT_FS=y -CONFIG_F2FS_FS_XATTR=y -CONFIG_F2FS_FS_POSIX_ACL=y -CONFIG_F2FS_FS_SECURITY=y -# CONFIG_F2FS_CHECK_FS is not set -# CONFIG_F2FS_FAULT_INJECTION is not set -CONFIG_F2FS_FS_COMPRESSION=y -CONFIG_F2FS_FS_LZO=y -CONFIG_F2FS_FS_LZORLE=y -CONFIG_F2FS_FS_LZ4=y -CONFIG_F2FS_FS_LZ4HC=y -CONFIG_F2FS_FS_ZSTD=y -# CONFIG_F2FS_IOSTAT is not set -CONFIG_F2FS_UNFAIR_RWSEM=y -CONFIG_ZONEFS_FS=m -CONFIG_FS_DAX=y -CONFIG_FS_DAX_PMD=y -CONFIG_FS_POSIX_ACL=y -CONFIG_EXPORTFS=y -CONFIG_EXPORTFS_BLOCK_OPS=y -CONFIG_FILE_LOCKING=y -CONFIG_FS_ENCRYPTION=y -CONFIG_FS_ENCRYPTION_ALGS=y -CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y -CONFIG_FS_VERITY=y -CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y -CONFIG_FSNOTIFY=y -CONFIG_DNOTIFY=y -CONFIG_INOTIFY_USER=y -CONFIG_FANOTIFY=y -CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -# CONFIG_QUOTA_DEBUG is not set -CONFIG_QUOTA_TREE=m -CONFIG_QFMT_V1=m -CONFIG_QFMT_V2=m -CONFIG_QUOTACTL=y -CONFIG_AUTOFS_FS=m -CONFIG_FUSE_FS=y -CONFIG_CUSE=m -CONFIG_VIRTIO_FS=m -CONFIG_FUSE_DAX=y -CONFIG_FUSE_PASSTHROUGH=y -CONFIG_FUSE_IO_URING=y -CONFIG_OVERLAY_FS=m -# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set -CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y -# CONFIG_OVERLAY_FS_INDEX is not set -CONFIG_OVERLAY_FS_XINO_AUTO=y -# CONFIG_OVERLAY_FS_METACOPY is not set -# CONFIG_OVERLAY_FS_DEBUG is not set - -# -# Caches -# -CONFIG_NETFS_SUPPORT=m -CONFIG_NETFS_STATS=y -CONFIG_NETFS_DEBUG=y -CONFIG_FSCACHE=y -CONFIG_FSCACHE_STATS=y -CONFIG_CACHEFILES=m -# CONFIG_CACHEFILES_DEBUG is not set -CONFIG_CACHEFILES_ERROR_INJECTION=y -# CONFIG_CACHEFILES_ONDEMAND is not set -# end of Caches - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -# end of CD-ROM/DVD Filesystems - -# -# DOS/FAT/EXFAT/NT Filesystems -# -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_FAT_DEFAULT_CODEPAGE=437 -CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -# CONFIG_FAT_DEFAULT_UTF8 is not set -CONFIG_EXFAT_FS=m -CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" -CONFIG_NTFS_FS=m -# CONFIG_NTFS_DEBUG is not set -# CONFIG_NTFS_FS_POSIX_ACL is not set -CONFIG_NTFS3_FS=m -# CONFIG_NTFS3_64BIT_CLUSTER is not set -CONFIG_NTFS3_LZX_XPRESS=y -CONFIG_NTFS3_FS_POSIX_ACL=y -# end of DOS/FAT/EXFAT/NT Filesystems - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_PROC_VMCORE=y -CONFIG_PROC_VMCORE_DEVICE_DUMP=y -CONFIG_PROC_SYSCTL=y -CONFIG_PROC_PAGE_MONITOR=y -CONFIG_PROC_CHILDREN=y -CONFIG_PROC_CPU_RESCTRL=y -CONFIG_KERNFS=y -CONFIG_SYSFS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_TMPFS_XATTR=y -CONFIG_TMPFS_INODE64=y -CONFIG_TMPFS_QUOTA=y -CONFIG_ARCH_SUPPORTS_HUGETLBFS=y -CONFIG_HUGETLBFS=y -CONFIG_HUGETLB_PAGE=y -CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING=y -CONFIG_ARCH_HAS_GIGANTIC_PAGE=y -CONFIG_CONFIGFS_FS=y -CONFIG_EFIVAR_FS=y -# end of Pseudo filesystems - -CONFIG_MISC_FILESYSTEMS=y -CONFIG_ORANGEFS_FS=m -CONFIG_ADFS_FS=m -# CONFIG_ADFS_FS_RW is not set -CONFIG_AFFS_FS=m -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -CONFIG_BEFS_FS=m -# CONFIG_BEFS_DEBUG is not set -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m -CONFIG_JFFS2_FS=m -CONFIG_JFFS2_FS_DEBUG=0 -CONFIG_JFFS2_FS_WRITEBUFFER=y -# CONFIG_JFFS2_FS_WBUF_VERIFY is not set -# CONFIG_JFFS2_SUMMARY is not set -CONFIG_JFFS2_FS_XATTR=y -CONFIG_JFFS2_FS_POSIX_ACL=y -CONFIG_JFFS2_FS_SECURITY=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_ZLIB=y -CONFIG_JFFS2_LZO=y -CONFIG_JFFS2_RTIME=y -# CONFIG_JFFS2_RUBIN is not set -# CONFIG_JFFS2_CMODE_NONE is not set -# CONFIG_JFFS2_CMODE_PRIORITY is not set -# CONFIG_JFFS2_CMODE_SIZE is not set -CONFIG_JFFS2_CMODE_FAVOURLZO=y -CONFIG_UBIFS_FS=m -# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -CONFIG_UBIFS_FS_LZO=y -CONFIG_UBIFS_FS_ZLIB=y -CONFIG_UBIFS_FS_ZSTD=y -# CONFIG_UBIFS_ATIME_SUPPORT is not set -CONFIG_UBIFS_FS_XATTR=y -CONFIG_UBIFS_FS_SECURITY=y -CONFIG_UBIFS_FS_AUTHENTICATION=y -CONFIG_CRAMFS=m -CONFIG_CRAMFS_BLOCKDEV=y -CONFIG_CRAMFS_MTD=y -CONFIG_SQUASHFS=y -# CONFIG_SQUASHFS_FILE_CACHE is not set -CONFIG_SQUASHFS_FILE_DIRECT=y -CONFIG_SQUASHFS_DECOMP_SINGLE=y -CONFIG_SQUASHFS_DECOMP_MULTI=y -CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y -CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT=y -CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS=y -CONFIG_SQUASHFS_XATTR=y -# CONFIG_SQUASHFS_COMP_CACHE_FULL is not set -CONFIG_SQUASHFS_ZLIB=y -CONFIG_SQUASHFS_LZ4=y -CONFIG_SQUASHFS_LZO=y -CONFIG_SQUASHFS_XZ=y -CONFIG_SQUASHFS_ZSTD=y -# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set -# CONFIG_SQUASHFS_EMBEDDED is not set -CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 -CONFIG_VXFS_FS=m -CONFIG_MINIX_FS=m -CONFIG_OMFS_FS=m -CONFIG_HPFS_FS=m -CONFIG_QNX4FS_FS=m -CONFIG_QNX6FS_FS=m -# CONFIG_QNX6FS_DEBUG is not set -CONFIG_RESCTRL_FS=y -CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID=y -CONFIG_ROMFS_FS=m -CONFIG_ROMFS_BACKED_BY_BLOCK=y -# CONFIG_ROMFS_BACKED_BY_MTD is not set -# CONFIG_ROMFS_BACKED_BY_BOTH is not set -CONFIG_ROMFS_ON_BLOCK=y -CONFIG_PSTORE=y -CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240 -CONFIG_PSTORE_COMPRESS=y -# CONFIG_PSTORE_CONSOLE is not set -# CONFIG_PSTORE_PMSG is not set -# CONFIG_PSTORE_FTRACE is not set -CONFIG_PSTORE_RAM=m -CONFIG_PSTORE_ZONE=m -CONFIG_PSTORE_BLK=m -CONFIG_PSTORE_BLK_BLKDEV="" -CONFIG_PSTORE_BLK_KMSG_SIZE=64 -CONFIG_PSTORE_BLK_MAX_REASON=2 -CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_UFS_DEBUG is not set -CONFIG_EROFS_FS=m -# CONFIG_EROFS_FS_DEBUG is not set -CONFIG_EROFS_FS_XATTR=y -CONFIG_EROFS_FS_POSIX_ACL=y -CONFIG_EROFS_FS_SECURITY=y -CONFIG_EROFS_FS_BACKED_BY_FILE=y -CONFIG_EROFS_FS_ZIP=y -CONFIG_EROFS_FS_ZIP_LZMA=y -CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS=16 -CONFIG_EROFS_FS_ZIP_DEFLATE=y -CONFIG_EROFS_FS_ZIP_ZSTD=y -CONFIG_EROFS_FS_ZIP_ACCEL=y -CONFIG_EROFS_FS_PCPU_KTHREAD=y -# CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI is not set -# CONFIG_EROFS_FS_PAGE_CACHE_SHARE is not set -CONFIG_VBOXSF_FS=m -CONFIG_NETWORK_FILESYSTEMS=y -CONFIG_NFS_FS=m -CONFIG_NFS_V2=m -CONFIG_NFS_V3=m -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=m -CONFIG_NFS_SWAP=y -CONFIG_NFS_V4_0=y -CONFIG_NFS_V4_2=y -CONFIG_PNFS_FILE_LAYOUT=m -CONFIG_PNFS_BLOCK=m -CONFIG_PNFS_FLEXFILE_LAYOUT=m -CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" -CONFIG_NFS_V4_1_MIGRATION=y -CONFIG_NFS_V4_SECURITY_LABEL=y -CONFIG_NFS_FSCACHE=y -# CONFIG_NFS_USE_LEGACY_DNS is not set -CONFIG_NFS_USE_KERNEL_DNS=y -CONFIG_NFS_DEBUG=y -CONFIG_NFS_DISABLE_UDP_SUPPORT=y -# CONFIG_NFS_V4_2_READ_PLUS is not set -CONFIG_NFSD=m -# CONFIG_NFSD_V2 is not set -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -CONFIG_NFSD_PNFS=y -CONFIG_NFSD_BLOCKLAYOUT=y -CONFIG_NFSD_SCSILAYOUT=y -CONFIG_NFSD_FLEXFILELAYOUT=y -CONFIG_NFSD_V4_2_INTER_SSC=y -CONFIG_NFSD_V4_SECURITY_LABEL=y -# CONFIG_NFSD_LEGACY_CLIENT_TRACKING is not set -# CONFIG_NFSD_V4_POSIX_ACLS is not set -CONFIG_GRACE_PERIOD=m -CONFIG_LOCKD=m -CONFIG_LOCKD_V4=y -CONFIG_NFS_ACL_SUPPORT=m -CONFIG_NFS_COMMON=y -# CONFIG_NFS_LOCALIO is not set -CONFIG_NFS_V4_2_SSC_HELPER=y -CONFIG_SUNRPC=m -CONFIG_SUNRPC_GSS=m -CONFIG_SUNRPC_BACKCHANNEL=y -CONFIG_SUNRPC_SWAP=y -CONFIG_RPCSEC_GSS_KRB5=m -CONFIG_SUNRPC_DEBUG=y -# CONFIG_SUNRPC_DEBUG_TRACE is not set -CONFIG_SUNRPC_XPRT_RDMA=m -CONFIG_CEPH_FS=m -CONFIG_CEPH_FSCACHE=y -CONFIG_CEPH_FS_POSIX_ACL=y -CONFIG_CEPH_FS_SECURITY_LABEL=y -CONFIG_CIFS=m -# CONFIG_CIFS_STATS2 is not set -CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y -CONFIG_CIFS_UPCALL=y -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -CONFIG_CIFS_DEBUG=y -# CONFIG_CIFS_DEBUG2 is not set -# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set -CONFIG_CIFS_DFS_UPCALL=y -CONFIG_CIFS_SWN_UPCALL=y -# CONFIG_CIFS_SMB_DIRECT is not set -CONFIG_CIFS_FSCACHE=y -# CONFIG_CIFS_COMPRESSION is not set -CONFIG_SMB_SERVER=m -CONFIG_SMB_SERVER_SMBDIRECT=y -CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=y -CONFIG_SMB_SERVER_KERBEROS5=y -CONFIG_SMBDIRECT=m -CONFIG_SMBFS=m -CONFIG_CODA_FS=m -CONFIG_AFS_FS=m -# CONFIG_AFS_DEBUG is not set -CONFIG_AFS_FSCACHE=y -# CONFIG_AFS_DEBUG_CURSOR is not set -CONFIG_9P_FS=m -CONFIG_9P_FSCACHE=y -CONFIG_9P_FS_POSIX_ACL=y -CONFIG_9P_FS_SECURITY=y -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="utf8" -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_MAC_ROMAN=m -CONFIG_NLS_MAC_CELTIC=m -CONFIG_NLS_MAC_CENTEURO=m -CONFIG_NLS_MAC_CROATIAN=m -CONFIG_NLS_MAC_CYRILLIC=m -CONFIG_NLS_MAC_GAELIC=m -CONFIG_NLS_MAC_GREEK=m -CONFIG_NLS_MAC_ICELAND=m -CONFIG_NLS_MAC_INUIT=m -CONFIG_NLS_MAC_ROMANIAN=m -CONFIG_NLS_MAC_TURKISH=m -CONFIG_NLS_UTF8=m -CONFIG_NLS_UCS2_UTILS=m -CONFIG_DLM=m -# CONFIG_DLM_DEBUG is not set -CONFIG_UNICODE=y -CONFIG_IO_WQ=y -# end of File systems - -# -# Security options -# -CONFIG_KEYS=y -CONFIG_KEYS_REQUEST_CACHE=y -CONFIG_PERSISTENT_KEYRINGS=y -CONFIG_BIG_KEYS=y -CONFIG_TRUSTED_KEYS=y -CONFIG_HAVE_TRUSTED_KEYS=y -CONFIG_HAVE_TRUSTED_KEYS_DEBUG=y -# CONFIG_TRUSTED_KEYS_DEBUG is not set -CONFIG_TRUSTED_KEYS_TPM=y -CONFIG_ENCRYPTED_KEYS=y -CONFIG_USER_DECRYPTED_DATA=y -CONFIG_KEY_DH_OPERATIONS=y -CONFIG_KEY_NOTIFICATIONS=y -CONFIG_SECURITY_DMESG_RESTRICT=y -CONFIG_PROC_MEM_ALWAYS_FORCE=y -# CONFIG_PROC_MEM_FORCE_PTRACE is not set -# CONFIG_PROC_MEM_NO_FORCE is not set -CONFIG_SECURITY=y -CONFIG_HAS_SECURITY_AUDIT=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_SECURITY_INFINIBAND=y -CONFIG_SECURITY_NETWORK_XFRM=y -CONFIG_SECURITY_PATH=y -CONFIG_LSM_MMAP_MIN_ADDR=0 -# CONFIG_STATIC_USERMODEHELPER is not set -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_SECURITY_SELINUX_DEVELOP=y -CONFIG_SECURITY_SELINUX_AVC_STATS=y -CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS=9 -CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE=256 -CONFIG_SECURITY_SELINUX_AVC_HASH_BITS=9 -# CONFIG_SECURITY_SELINUX_DEBUG is not set -CONFIG_SECURITY_SMACK=y -# CONFIG_SECURITY_SMACK_BRINGUP is not set -CONFIG_SECURITY_SMACK_NETFILTER=y -CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y -CONFIG_SECURITY_TOMOYO=y -CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY=2048 -CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG=1024 -# CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER is not set -CONFIG_SECURITY_TOMOYO_POLICY_LOADER="/sbin/tomoyo-init" -CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER="/sbin/init" -# CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING is not set -CONFIG_SECURITY_APPARMOR=y -# CONFIG_SECURITY_APPARMOR_DEBUG is not set -CONFIG_SECURITY_APPARMOR_INTROSPECT_POLICY=y -CONFIG_SECURITY_APPARMOR_HASH=y -CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y -CONFIG_SECURITY_APPARMOR_EXPORT_BINARY=y -CONFIG_SECURITY_APPARMOR_PARANOID_LOAD=y -# CONFIG_SECURITY_LOADPIN is not set -CONFIG_SECURITY_YAMA=y -CONFIG_SECURITY_SAFESETID=y -CONFIG_SECURITY_LOCKDOWN_LSM=y -CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y -CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE=y -# CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY is not set -# CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY is not set -CONFIG_SECURITY_LANDLOCK=y -CONFIG_SECURITY_IPE=y -CONFIG_IPE_BOOT_POLICY="" -CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING=y -CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING=y - -# -# IPE Trust Providers -# -CONFIG_IPE_PROP_DM_VERITY=y -CONFIG_IPE_PROP_DM_VERITY_SIGNATURE=y -CONFIG_IPE_PROP_FS_VERITY=y -CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG=y -# end of IPE Trust Providers - -CONFIG_INTEGRITY=y -CONFIG_INTEGRITY_SIGNATURE=y -CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y -CONFIG_INTEGRITY_TRUSTED_KEYRING=y -CONFIG_INTEGRITY_PLATFORM_KEYRING=y -CONFIG_INTEGRITY_MACHINE_KEYRING=y -# CONFIG_INTEGRITY_CA_MACHINE_KEYRING is not set -CONFIG_LOAD_UEFI_KEYS=y -CONFIG_INTEGRITY_AUDIT=y -CONFIG_IMA=y -CONFIG_IMA_KEXEC=y -CONFIG_IMA_MEASURE_PCR_IDX=10 -CONFIG_IMA_LSM_RULES=y -CONFIG_IMA_NG_TEMPLATE=y -# CONFIG_IMA_SIG_TEMPLATE is not set -CONFIG_IMA_DEFAULT_TEMPLATE="ima-ng" -# CONFIG_IMA_DEFAULT_HASH_SHA1 is not set -CONFIG_IMA_DEFAULT_HASH_SHA256=y -# CONFIG_IMA_DEFAULT_HASH_SHA512 is not set -CONFIG_IMA_DEFAULT_HASH="sha256" -CONFIG_IMA_WRITE_POLICY=y -CONFIG_IMA_READ_POLICY=y -CONFIG_IMA_APPRAISE=y -CONFIG_IMA_ARCH_POLICY=y -# CONFIG_IMA_APPRAISE_BUILD_POLICY is not set -CONFIG_IMA_APPRAISE_BOOTPARAM=y -CONFIG_IMA_APPRAISE_MODSIG=y -# CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY is not set -# CONFIG_IMA_BLACKLIST_KEYRING is not set -# CONFIG_IMA_LOAD_X509 is not set -CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS=y -CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS=y -CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT=y -# CONFIG_IMA_DISABLE_HTABLE is not set -CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB=0 -# CONFIG_IMA_STAGING is not set -CONFIG_EVM=y -CONFIG_EVM_ATTR_FSUUID=y -CONFIG_EVM_EXTRA_SMACK_XATTRS=y -CONFIG_EVM_ADD_XATTRS=y -# CONFIG_EVM_LOAD_X509 is not set -# CONFIG_DEFAULT_SECURITY_SELINUX is not set -# CONFIG_DEFAULT_SECURITY_SMACK is not set -# CONFIG_DEFAULT_SECURITY_TOMOYO is not set -# CONFIG_DEFAULT_SECURITY_APPARMOR is not set -CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_LSM="landlock,lockdown,yama,integrity,bpf" - -# -# Kernel hardening options -# - -# -# Memory initialization -# -CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y -CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y -CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y -# CONFIG_INIT_STACK_NONE is not set -# CONFIG_INIT_STACK_ALL_PATTERN is not set -CONFIG_INIT_STACK_ALL_ZERO=y -# CONFIG_KSTACK_ERASE is not set -CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y -# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set -CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y -CONFIG_ZERO_CALL_USED_REGS=y -# end of Memory initialization - -# -# Bounds checking -# -CONFIG_FORTIFY_SOURCE=y -CONFIG_HARDENED_USERCOPY=y -CONFIG_HARDENED_USERCOPY_DEFAULT_ON=y -# end of Bounds checking - -# -# Hardening of kernel data structures -# -CONFIG_LIST_HARDENED=y -# CONFIG_BUG_ON_DATA_CORRUPTION is not set -# end of Hardening of kernel data structures - -CONFIG_RANDSTRUCT_NONE=y -# CONFIG_RANDSTRUCT_FULL is not set -# CONFIG_RANDSTRUCT_PERFORMANCE is not set -# end of Kernel hardening options -# end of Security options - -CONFIG_ASYNC_CORE=m -CONFIG_ASYNC_MEMCPY=m -CONFIG_ASYNC_XOR=m -CONFIG_ASYNC_PQ=m -CONFIG_ASYNC_RAID6_RECOV=m -CONFIG_ASYNC_TX_DISABLE_PQ_VAL_DMA=y -CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA=y -CONFIG_CRYPTO=y - -# -# Crypto core or helper -# -CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_ALGAPI2=y -CONFIG_CRYPTO_AEAD=y -CONFIG_CRYPTO_AEAD2=y -CONFIG_CRYPTO_SIG=y -CONFIG_CRYPTO_SIG2=y -CONFIG_CRYPTO_SKCIPHER=y -CONFIG_CRYPTO_SKCIPHER2=y -CONFIG_CRYPTO_HASH=y -CONFIG_CRYPTO_HASH2=y -CONFIG_CRYPTO_RNG=y -CONFIG_CRYPTO_RNG2=y -CONFIG_CRYPTO_AKCIPHER2=y -CONFIG_CRYPTO_AKCIPHER=y -CONFIG_CRYPTO_KPP2=y -CONFIG_CRYPTO_KPP=y -CONFIG_CRYPTO_ACOMP2=y -CONFIG_CRYPTO_ACOMP=m -CONFIG_CRYPTO_MANAGER=y -CONFIG_CRYPTO_MANAGER2=y -CONFIG_CRYPTO_USER=m -# CONFIG_CRYPTO_SELFTESTS is not set -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_PCRYPT=m -CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_AUTHENC=m -CONFIG_CRYPTO_KRB5ENC=m -CONFIG_CRYPTO_BENCHMARK=m -CONFIG_CRYPTO_ENGINE=m -# end of Crypto core or helper - -# -# Public-key cryptography -# -CONFIG_CRYPTO_RSA=y -CONFIG_CRYPTO_DH=y -CONFIG_CRYPTO_DH_RFC7919_GROUPS=y -CONFIG_CRYPTO_ECC=y -CONFIG_CRYPTO_ECDH=y -CONFIG_CRYPTO_ECDSA=m -CONFIG_CRYPTO_ECRDSA=m -CONFIG_CRYPTO_MLDSA=m -# end of Public-key cryptography - -# -# Block ciphers -# -CONFIG_CRYPTO_AES=y -CONFIG_CRYPTO_ARIA=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_BLOWFISH_COMMON=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_CAST_COMMON=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_SM4=m -CONFIG_CRYPTO_SM4_GENERIC=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_TWOFISH_COMMON=m -# end of Block ciphers - -# -# Length-preserving ciphers and modes -# -CONFIG_CRYPTO_ADIANTUM=m -CONFIG_CRYPTO_CHACHA20=m -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_CTS=y -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_HCTR2=m -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_XCTR=m -CONFIG_CRYPTO_XTS=y -# end of Length-preserving ciphers and modes - -# -# AEAD (authenticated encryption with associated data) ciphers -# -CONFIG_CRYPTO_AEGIS128=m -CONFIG_CRYPTO_AEGIS128_SIMD=y -CONFIG_CRYPTO_CHACHA20POLY1305=m -CONFIG_CRYPTO_CCM=m -CONFIG_CRYPTO_GCM=y -CONFIG_CRYPTO_GENIV=y -CONFIG_CRYPTO_SEQIV=y -CONFIG_CRYPTO_ECHAINIV=m -CONFIG_CRYPTO_ESSIV=m -# end of AEAD (authenticated encryption with associated data) ciphers - -# -# Hashes, digests, and MACs -# -CONFIG_CRYPTO_BLAKE2B=m -CONFIG_CRYPTO_CMAC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA256=y -CONFIG_CRYPTO_SHA512=y -CONFIG_CRYPTO_SHA3=y -CONFIG_CRYPTO_SM3=m -CONFIG_CRYPTO_STREEBOG=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_XXHASH=m -# end of Hashes, digests, and MACs - -# -# CRCs (cyclic redundancy checks) -# -CONFIG_CRYPTO_CRC32C=y -CONFIG_CRYPTO_CRC32=m -# end of CRCs (cyclic redundancy checks) - -# -# Compression -# -CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRYPTO_LZO=y -CONFIG_CRYPTO_842=m -CONFIG_CRYPTO_LZ4=m -CONFIG_CRYPTO_LZ4HC=m -CONFIG_CRYPTO_ZSTD=m -# end of Compression - -# -# Random number generation -# -CONFIG_CRYPTO_DRBG=y -CONFIG_CRYPTO_JITTERENTROPY=y -CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKS=64 -CONFIG_CRYPTO_JITTERENTROPY_MEMORY_BLOCKSIZE=32 -CONFIG_CRYPTO_JITTERENTROPY_OSR=1 -CONFIG_CRYPTO_KDF800108_CTR=y -# end of Random number generation - -# -# Userspace interface (deprecated) -# -CONFIG_CRYPTO_USER_API=m -CONFIG_CRYPTO_USER_API_HASH=m -CONFIG_CRYPTO_USER_API_SKCIPHER=m -CONFIG_CRYPTO_USER_API_RNG=m -# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set -CONFIG_CRYPTO_USER_API_AEAD=m -# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set -# end of Userspace interface (deprecated) - -# -# Accelerated Cryptographic Algorithms for CPU (arm64) -# -CONFIG_CRYPTO_GHASH_ARM64_CE=m -CONFIG_CRYPTO_AES_ARM64_CE_BLK=m -CONFIG_CRYPTO_AES_ARM64_NEON_BLK=m -CONFIG_CRYPTO_AES_ARM64_BS=m -CONFIG_CRYPTO_SM4_ARM64_CE=m -CONFIG_CRYPTO_SM4_ARM64_CE_BLK=m -CONFIG_CRYPTO_SM4_ARM64_NEON_BLK=m -CONFIG_CRYPTO_AES_ARM64_CE_CCM=m -CONFIG_CRYPTO_SM4_ARM64_CE_CCM=m -CONFIG_CRYPTO_SM4_ARM64_CE_GCM=m -# end of Accelerated Cryptographic Algorithms for CPU (arm64) - -CONFIG_CRYPTO_HW=y -CONFIG_CRYPTO_DEV_ALLWINNER=y -CONFIG_CRYPTO_DEV_SUN4I_SS=m -# CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG is not set -CONFIG_CRYPTO_DEV_SUN8I_CE=m -# CONFIG_CRYPTO_DEV_SUN8I_CE_DEBUG is not set -CONFIG_CRYPTO_DEV_SUN8I_CE_HASH=y -CONFIG_CRYPTO_DEV_SUN8I_CE_TRNG=y -CONFIG_CRYPTO_DEV_SUN8I_SS=m -# CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG is not set -CONFIG_CRYPTO_DEV_SUN8I_SS_HASH=y -CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON=m -CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC=m -CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC=m -CONFIG_CRYPTO_DEV_FSL_CAAM=m -# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set -CONFIG_CRYPTO_DEV_FSL_CAAM_JR=m -CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 -CONFIG_CRYPTO_DEV_FSL_CAAM_INTC=y -CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD=255 -CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD=2048 -CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=y -CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI=y -CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=y -CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API=y -CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y -CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API=y -# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set -CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM=m -CONFIG_CRYPTO_DEV_SAHARA=m -CONFIG_CRYPTO_DEV_ATMEL_AES=m -CONFIG_CRYPTO_DEV_ATMEL_I2C=m -CONFIG_CRYPTO_DEV_ATMEL_ECC=m -CONFIG_CRYPTO_DEV_ATMEL_SHA204A=m -CONFIG_CRYPTO_DEV_CCP=y -CONFIG_CRYPTO_DEV_CCP_DD=m -CONFIG_CRYPTO_DEV_SP_CCP=y -CONFIG_CRYPTO_DEV_CCP_CRYPTO=m -# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set -# CONFIG_CRYPTO_DEV_MXS_DCP is not set -CONFIG_CRYPTO_DEV_CPT=m -CONFIG_CAVIUM_CPT=m -CONFIG_CRYPTO_DEV_NITROX=m -CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m -CONFIG_CRYPTO_DEV_MARVELL=m -CONFIG_CRYPTO_DEV_MARVELL_CESA=m -CONFIG_CRYPTO_DEV_OCTEONTX_CPT=m -CONFIG_CRYPTO_DEV_OCTEONTX2_CPT=m -CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4=m -CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_ECB=y -CONFIG_CRYPTO_DEV_KEEMBAY_OCS_AES_SM4_CTS=y -CONFIG_CRYPTO_DEV_KEEMBAY_OCS_ECC=m -CONFIG_CRYPTO_DEV_KEEMBAY_OCS_HCU=m -CONFIG_CRYPTO_DEV_KEEMBAY_OCS_HCU_HMAC_SHA224=y -CONFIG_CRYPTO_DEV_QAT=m -CONFIG_CRYPTO_DEV_QAT_DH895xCC=m -CONFIG_CRYPTO_DEV_QAT_C3XXX=m -CONFIG_CRYPTO_DEV_QAT_C62X=m -CONFIG_CRYPTO_DEV_QAT_4XXX=m -CONFIG_CRYPTO_DEV_QAT_420XX=m -CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m -CONFIG_CRYPTO_DEV_QAT_C3XXXVF=m -CONFIG_CRYPTO_DEV_QAT_C62XVF=m -# CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION is not set -CONFIG_CRYPTO_DEV_QCE=m -CONFIG_CRYPTO_DEV_QCE_SKCIPHER=y -CONFIG_CRYPTO_DEV_QCE_SHA=y -CONFIG_CRYPTO_DEV_QCE_AEAD=y -CONFIG_CRYPTO_DEV_QCE_ENABLE_ALL=y -# CONFIG_CRYPTO_DEV_QCE_ENABLE_SKCIPHER is not set -# CONFIG_CRYPTO_DEV_QCE_ENABLE_SHA is not set -# CONFIG_CRYPTO_DEV_QCE_ENABLE_AEAD is not set -CONFIG_CRYPTO_DEV_QCE_SW_MAX_LEN=512 -CONFIG_CRYPTO_DEV_QCOM_RNG=m -CONFIG_CRYPTO_DEV_ROCKCHIP=m -CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG=y -CONFIG_CRYPTO_DEV_TEGRA=m -CONFIG_CRYPTO_DEV_ZYNQMP_AES=m -CONFIG_CRYPTO_DEV_ZYNQMP_SHA3=m -CONFIG_CRYPTO_DEV_CHELSIO=m -CONFIG_CRYPTO_DEV_VIRTIO=m -CONFIG_CRYPTO_DEV_STM32_HASH=m -CONFIG_CRYPTO_DEV_STM32_CRYP=m -CONFIG_CRYPTO_DEV_SAFEXCEL=m -CONFIG_CRYPTO_DEV_CCREE=m -CONFIG_CRYPTO_DEV_HISI_SEC=m -CONFIG_CRYPTO_DEV_HISI_SEC2=m -CONFIG_CRYPTO_DEV_HISI_QM=m -CONFIG_CRYPTO_DEV_HISI_ZIP=m -CONFIG_CRYPTO_DEV_HISI_HPRE=m -CONFIG_CRYPTO_DEV_AMLOGIC_GXL=m -# CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG is not set -CONFIG_CRYPTO_DEV_SA2UL=m -CONFIG_CRYPTO_DEV_EIP93=m -CONFIG_CRYPTO_DEV_TI_DTHEV2=m -CONFIG_ASYMMETRIC_KEY_TYPE=y -CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -CONFIG_X509_CERTIFICATE_PARSER=y -CONFIG_PKCS8_PRIVATE_KEY_PARSER=m -CONFIG_PKCS7_MESSAGE_PARSER=y -# CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA is not set -CONFIG_PKCS7_TEST_KEY=m -CONFIG_SIGNED_PE_FILE_VERIFICATION=y -# CONFIG_FIPS_SIGNATURE_SELFTEST is not set - -# -# Certificates for signature checking -# -CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" -CONFIG_MODULE_SIG_KEY_TYPE_RSA=y -# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set -# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44 is not set -# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65 is not set -# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87 is not set -CONFIG_SYSTEM_TRUSTED_KEYRING=y -CONFIG_SYSTEM_TRUSTED_KEYS="" -CONFIG_SYSTEM_EXTRA_CERTIFICATE=y -CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE=4096 -CONFIG_SECONDARY_TRUSTED_KEYRING=y -# CONFIG_SECONDARY_TRUSTED_KEYRING_SIGNED_BY_BUILTIN is not set -CONFIG_SYSTEM_BLACKLIST_KEYRING=y -CONFIG_SYSTEM_BLACKLIST_HASH_LIST="" -CONFIG_SYSTEM_REVOCATION_LIST=y -CONFIG_SYSTEM_REVOCATION_KEYS="" -# CONFIG_SYSTEM_BLACKLIST_AUTH_UPDATE is not set -CONFIG_OPENSSL_SUPPORTS_ML_DSA=y -# end of Certificates for signature checking - -CONFIG_CRYPTO_KRB5=m -CONFIG_CRYPTO_KRB5_SELFTESTS=y -CONFIG_BINARY_PRINTF=y - -# -# Library routines -# -CONFIG_LINEAR_RANGES=y -CONFIG_PACKING=y -CONFIG_BITREVERSE=y -CONFIG_HAVE_ARCH_BITREVERSE=y -CONFIG_GENERIC_STRNCPY_FROM_USER=y -CONFIG_GENERIC_STRNLEN_USER=y -CONFIG_GENERIC_NET_UTILS=y -CONFIG_CORDIC=m -CONFIG_POLYNOMIAL=m -# CONFIG_PRIME_NUMBERS is not set -CONFIG_RATIONAL=y -CONFIG_STMP_DEVICE=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_HAS_FAST_MULTIPLIER=y -CONFIG_ARCH_USE_SYM_ANNOTATIONS=y -CONFIG_INDIRECT_PIO=y -CONFIG_TRACE_MMIO_ACCESS=y -CONFIG_CRC4=m -CONFIG_CRC7=m -CONFIG_CRC8=y -CONFIG_CRC16=y -CONFIG_CRC_CCITT=y -CONFIG_CRC_ITU_T=m -CONFIG_CRC_T10DIF=y -CONFIG_CRC_T10DIF_ARCH=y -CONFIG_CRC32=y -CONFIG_CRC32_ARCH=y -CONFIG_CRC64=y -CONFIG_CRC64_ARCH=y -CONFIG_CRC_OPTIMIZATIONS=y -CONFIG_CRYPTO_HASH_INFO=y -CONFIG_CRYPTO_LIB_UTILS=y -CONFIG_CRYPTO_LIB_AES=y -CONFIG_CRYPTO_LIB_AES_ARCH=y -CONFIG_CRYPTO_LIB_AES_CBC_MACS=y -CONFIG_CRYPTO_LIB_ARC4=m -CONFIG_CRYPTO_LIB_GF128MUL=m -CONFIG_CRYPTO_LIB_BLAKE2B=y -CONFIG_CRYPTO_LIB_CHACHA=y -CONFIG_CRYPTO_LIB_CHACHA_ARCH=y -CONFIG_CRYPTO_LIB_CURVE25519=m -CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=y -CONFIG_CRYPTO_LIB_DES=m -CONFIG_CRYPTO_LIB_GF128HASH=y -CONFIG_CRYPTO_LIB_GF128HASH_ARCH=y -CONFIG_CRYPTO_LIB_MD5=y -CONFIG_CRYPTO_LIB_MLDSA=m -CONFIG_CRYPTO_LIB_NH=m -CONFIG_CRYPTO_LIB_NH_ARCH=y -CONFIG_CRYPTO_LIB_POLY1305=y -CONFIG_CRYPTO_LIB_POLY1305_ARCH=y -CONFIG_CRYPTO_LIB_POLY1305_GENERIC=y -CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 -CONFIG_CRYPTO_LIB_CHACHA20POLY1305=y -CONFIG_CRYPTO_LIB_SHA1=y -CONFIG_CRYPTO_LIB_SHA1_ARCH=y -CONFIG_CRYPTO_LIB_SHA256=y -CONFIG_CRYPTO_LIB_SHA256_ARCH=y -CONFIG_CRYPTO_LIB_SHA512=y -CONFIG_CRYPTO_LIB_SHA512_ARCH=y -CONFIG_CRYPTO_LIB_SHA3=y -CONFIG_CRYPTO_LIB_SHA3_ARCH=y -CONFIG_CRYPTO_LIB_SM3=m -CONFIG_CRYPTO_LIB_SM3_ARCH=y -CONFIG_XOR_BLOCKS=y -CONFIG_XOR_BLOCKS_ARCH=y -CONFIG_RAID6_PQ=y -CONFIG_RAID6_PQ_ARCH=y -CONFIG_RAID6_PQ_BENCHMARK=y -CONFIG_XXHASH=y -CONFIG_AUDIT_GENERIC=y -CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y -CONFIG_AUDIT_COMPAT_GENERIC=y -# CONFIG_RANDOM32_SELFTEST is not set -CONFIG_842_COMPRESS=m -CONFIG_842_DECOMPRESS=m -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=y -CONFIG_LZO_COMPRESS=y -CONFIG_LZO_DECOMPRESS=y -CONFIG_LZ4_COMPRESS=m -CONFIG_LZ4HC_COMPRESS=m -CONFIG_LZ4_DECOMPRESS=y -CONFIG_ZSTD_COMMON=y -CONFIG_ZSTD_COMPRESS=y -CONFIG_ZSTD_DECOMPRESS=y -CONFIG_XZ_DEC=y -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_ARM64=y -CONFIG_XZ_DEC_SPARC=y -CONFIG_XZ_DEC_RISCV=y -CONFIG_XZ_DEC_MICROLZMA=y -CONFIG_XZ_DEC_BCJ=y -CONFIG_XZ_DEC_TEST=m -CONFIG_DECOMPRESS_GZIP=y -CONFIG_DECOMPRESS_BZIP2=y -CONFIG_DECOMPRESS_LZMA=y -CONFIG_DECOMPRESS_XZ=y -CONFIG_DECOMPRESS_LZO=y -CONFIG_DECOMPRESS_LZ4=y -CONFIG_DECOMPRESS_ZSTD=y -CONFIG_GENERIC_ALLOCATOR=y -CONFIG_REED_SOLOMON=m -CONFIG_REED_SOLOMON_ENC8=y -CONFIG_REED_SOLOMON_DEC8=y -CONFIG_REED_SOLOMON_DEC16=y -CONFIG_BCH=y -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m -CONFIG_BTREE=y -CONFIG_INTERVAL_TREE=y -CONFIG_INTERVAL_TREE_SPAN_ITER=y -CONFIG_XARRAY_MULTI=y -CONFIG_ASSOCIATIVE_ARRAY=y -CONFIG_CLOSURES=y -CONFIG_HAS_IOMEM=y -CONFIG_HAS_IOPORT=y -CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAS_DMA=y -CONFIG_DMA_OPS_HELPERS=y -CONFIG_NEED_SG_DMA_FLAGS=y -CONFIG_NEED_SG_DMA_LENGTH=y -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_ARCH_DMA_ADDR_T_64BIT=y -CONFIG_DMA_DECLARE_COHERENT=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y -CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y -CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED=y -CONFIG_ARCH_HAS_BATCHED_DMA_SYNC=y -CONFIG_SWIOTLB=y -# CONFIG_SWIOTLB_DYNAMIC is not set -CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y -CONFIG_DMA_NEED_SYNC=y -CONFIG_DMA_RESTRICTED_POOL=y -CONFIG_DMA_NONCOHERENT_MMAP=y -CONFIG_DMA_COHERENT_POOL=y -CONFIG_DMA_DIRECT_REMAP=y -CONFIG_DMA_CMA=y -CONFIG_DMA_NUMA_CMA=y -CONFIG_CMA_SIZE_PERNUMA=y - -# -# Default contiguous memory area size: -# -CONFIG_CMA_SIZE_MBYTES=0 -CONFIG_CMA_SIZE_SEL_MBYTES=y -# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set -# CONFIG_CMA_SIZE_SEL_MIN is not set -# CONFIG_CMA_SIZE_SEL_MAX is not set -CONFIG_CMA_ALIGNMENT=8 -# CONFIG_DMA_API_DEBUG is not set -# CONFIG_DMA_MAP_BENCHMARK is not set -CONFIG_SGL_ALLOC=y -CONFIG_CHECK_SIGNATURE=y -CONFIG_CPUMASK_OFFSTACK=y -CONFIG_CPU_RMAP=y -CONFIG_DQL=y -CONFIG_GLOB=y -CONFIG_NLATTR=y -CONFIG_LRU_CACHE=m -CONFIG_CLZ_TAB=y -CONFIG_IRQ_POLL=y -CONFIG_MPILIB=y -CONFIG_SIGNATURE=y -CONFIG_DIMLIB=y -CONFIG_LIBFDT=y -CONFIG_OID_REGISTRY=y -CONFIG_UCS2_STRING=y -CONFIG_HAVE_GENERIC_VDSO=y -CONFIG_GENERIC_GETTIMEOFDAY=y -CONFIG_VDSO_GETRANDOM=y -CONFIG_FONT_SUPPORT=y -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_7x14 is not set -# CONFIG_FONT_PEARL_8x8 is not set -CONFIG_FONT_ACORN_8x8=y -# CONFIG_FONT_MINI_4x6 is not set -CONFIG_FONT_6x10=y -# CONFIG_FONT_10x18 is not set -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_SUN12x22 is not set -CONFIG_FONT_TER10x18=y -CONFIG_FONT_TER16x32=y -# CONFIG_FONT_6x8 is not set -CONFIG_SG_SPLIT=y -CONFIG_SG_POOL=y -CONFIG_ARCH_HAS_PMEM_API=y -CONFIG_MEMREGION=y -CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION=y -CONFIG_GENERIC_CPU_CACHE_MAINTENANCE=y -CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y -CONFIG_ARCH_STACKWALK=y -CONFIG_STACKDEPOT=y -CONFIG_STACKDEPOT_MAX_FRAMES=64 -CONFIG_SBITMAP=y -CONFIG_PARMAN=m -CONFIG_OBJAGG=m -# CONFIG_LWQ_TEST is not set -# end of Library routines - -CONFIG_GENERIC_IOREMAP=y -CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y -CONFIG_PLDMFW=y -CONFIG_ASN1_ENCODER=y -CONFIG_FIRMWARE_TABLE=y -CONFIG_UNION_FIND=y -CONFIG_MIN_HEAP=y - -# -# Kernel hacking -# - -# -# printk and dmesg options -# -CONFIG_PRINTK_TIME=y -# CONFIG_PRINTK_CALLER is not set -CONFIG_PRINTK_EXECUTION_CTX=y -# CONFIG_STACKTRACE_BUILD_ID is not set -CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 -CONFIG_CONSOLE_LOGLEVEL_QUIET=3 -CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 -CONFIG_BOOT_PRINTK_DELAY=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_DYNAMIC_DEBUG_CORE=y -CONFIG_SYMBOLIC_ERRNAME=y -CONFIG_DEBUG_BUGVERBOSE=y -# CONFIG_DEBUG_BUGVERBOSE_DETAILED is not set -# end of printk and dmesg options - -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_MISC=y - -# -# Compile-time checks and compiler options -# -CONFIG_DEBUG_INFO=y -CONFIG_AS_HAS_NON_CONST_ULEB128=y -# CONFIG_DEBUG_INFO_NONE is not set -# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set -# CONFIG_DEBUG_INFO_DWARF4 is not set -CONFIG_DEBUG_INFO_DWARF5=y -# CONFIG_DEBUG_INFO_REDUCED is not set -CONFIG_DEBUG_INFO_COMPRESSED_NONE=y -# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set -# CONFIG_DEBUG_INFO_COMPRESSED_ZSTD is not set -# CONFIG_DEBUG_INFO_SPLIT is not set -CONFIG_DEBUG_INFO_BTF=y -CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y -CONFIG_DEBUG_INFO_BTF_MODULES=y -# CONFIG_MODULE_ALLOW_BTF_MISMATCH is not set -CONFIG_GDB_SCRIPTS=y -CONFIG_FRAME_WARN=1024 -# CONFIG_STRIP_ASM_SYMS is not set -# CONFIG_READABLE_ASM is not set -# CONFIG_HEADERS_INSTALL is not set -# CONFIG_DEBUG_SECTION_MISMATCH is not set -CONFIG_SECTION_MISMATCH_WARN_ONLY=y -# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set -CONFIG_ARCH_WANT_FRAME_POINTERS=y -CONFIG_FRAME_POINTER=y -CONFIG_VMLINUX_MAP=y -CONFIG_BUILTIN_MODULE_RANGES=y -# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set -# end of Compile-time checks and compiler options - -# -# Generic Kernel Debugging Instruments -# -CONFIG_MAGIC_SYSRQ=y -CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6 -CONFIG_MAGIC_SYSRQ_SERIAL=y -CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_FS_ALLOW_ALL=y -# CONFIG_DEBUG_FS_ALLOW_NONE is not set -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_KGDB=y -CONFIG_KGDB_HONOUR_BLOCKLIST=y -CONFIG_KGDB_SERIAL_CONSOLE=y -# CONFIG_KGDB_TESTS is not set -CONFIG_KGDB_KDB=y -CONFIG_KDB_DEFAULT_ENABLE=0x1 -CONFIG_KDB_KEYBOARD=y -CONFIG_KDB_CONTINUE_CATASTROPHIC=0 -CONFIG_ARCH_HAS_UBSAN=y -CONFIG_UBSAN=y -# CONFIG_UBSAN_TRAP is not set -CONFIG_CC_HAS_UBSAN_BOUNDS_STRICT=y -CONFIG_UBSAN_BOUNDS=y -CONFIG_UBSAN_BOUNDS_STRICT=y -CONFIG_UBSAN_SHIFT=y -# CONFIG_UBSAN_DIV_ZERO is not set -# CONFIG_UBSAN_UNREACHABLE is not set -CONFIG_UBSAN_BOOL=y -CONFIG_UBSAN_ENUM=y -# CONFIG_UBSAN_ALIGNMENT is not set -# CONFIG_TEST_UBSAN is not set -# CONFIG_UBSAN_KVM_EL2 is not set -CONFIG_HAVE_ARCH_KCSAN=y -CONFIG_HAVE_KCSAN_COMPILER=y -# CONFIG_KCSAN is not set -# end of Generic Kernel Debugging Instruments - -# -# Networking Debugging -# -# CONFIG_NET_DEV_REFCNT_TRACKER is not set -# CONFIG_NET_NS_REFCNT_TRACKER is not set -# CONFIG_DEBUG_NET is not set -# CONFIG_DEBUG_NET_SMALL_RTNL is not set -# end of Networking Debugging - -# -# Memory Debugging -# -# CONFIG_PAGE_EXTENSION is not set -# CONFIG_DEBUG_PAGEALLOC is not set -CONFIG_SLUB_DEBUG=y -# CONFIG_SLUB_DEBUG_ON is not set -# CONFIG_PAGE_OWNER is not set -# CONFIG_PAGE_TABLE_CHECK is not set -CONFIG_PAGE_POISONING=y -# CONFIG_DEBUG_PAGE_REF is not set -# CONFIG_DEBUG_RODATA_TEST is not set -CONFIG_ARCH_HAS_DEBUG_WX=y -CONFIG_DEBUG_WX=y -CONFIG_ARCH_HAS_PTDUMP=y -CONFIG_PTDUMP=y -# CONFIG_PTDUMP_DEBUGFS is not set -CONFIG_HAVE_DEBUG_KMEMLEAK=y -# CONFIG_DEBUG_KMEMLEAK is not set -# CONFIG_PER_VMA_LOCK_STATS is not set -# CONFIG_DEBUG_OBJECTS is not set -# CONFIG_SHRINKER_DEBUG is not set -# CONFIG_DEBUG_STACK_USAGE is not set -CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y -# CONFIG_DEBUG_VFS is not set -# CONFIG_DEBUG_VM is not set -# CONFIG_DEBUG_VM_PGTABLE is not set -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -# CONFIG_DEBUG_VIRTUAL is not set -# CONFIG_DEBUG_MEMORY_INIT is not set -CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m -# CONFIG_DEBUG_PER_CPU_MAPS is not set -# CONFIG_MEM_ALLOC_PROFILING is not set -CONFIG_HAVE_ARCH_KASAN=y -CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y -CONFIG_HAVE_ARCH_KASAN_HW_TAGS=y -CONFIG_HAVE_ARCH_KASAN_VMALLOC=y -CONFIG_CC_HAS_KASAN_GENERIC=y -CONFIG_CC_HAS_KASAN_SW_TAGS=y -CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y -# CONFIG_KASAN is not set -CONFIG_HAVE_ARCH_KFENCE=y -CONFIG_KFENCE=y -CONFIG_KFENCE_SAMPLE_INTERVAL=0 -CONFIG_KFENCE_NUM_OBJECTS=255 -# CONFIG_KFENCE_DEFERRABLE is not set -# CONFIG_KFENCE_STATIC_KEYS is not set -CONFIG_KFENCE_STRESS_TEST_FAULTS=0 -# end of Memory Debugging - -# CONFIG_DEBUG_SHIRQ is not set - -# -# Debug Oops, Lockups and Hangs -# -# CONFIG_PANIC_ON_OOPS is not set -CONFIG_PANIC_TIMEOUT=0 -CONFIG_LOCKUP_DETECTOR=y -CONFIG_SOFTLOCKUP_DETECTOR=y -CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=0 -CONFIG_HAVE_HARDLOCKUP_DETECTOR_BUDDY=y -CONFIG_HARDLOCKUP_DETECTOR=y -# CONFIG_HARDLOCKUP_DETECTOR_PREFER_BUDDY is not set -CONFIG_HARDLOCKUP_DETECTOR_PERF=y -# CONFIG_HARDLOCKUP_DETECTOR_BUDDY is not set -# CONFIG_HARDLOCKUP_DETECTOR_ARCH is not set -CONFIG_HARDLOCKUP_DETECTOR_COUNTS_HRTIMER=y -# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set -CONFIG_DETECT_HUNG_TASK=y -CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 -CONFIG_BOOTPARAM_HUNG_TASK_PANIC=0 -CONFIG_DETECT_HUNG_TASK_BLOCKER=y -# CONFIG_WQ_WATCHDOG is not set -CONFIG_WQ_CPU_INTENSIVE_REPORT=y -# CONFIG_TEST_LOCKUP is not set -# end of Debug Oops, Lockups and Hangs - -# -# Scheduler Debugging -# -CONFIG_SCHED_INFO=y -CONFIG_SCHEDSTATS=y -# end of Scheduler Debugging - -# CONFIG_DEBUG_PREEMPT is not set -# CONFIG_DEBUG_ATOMIC is not set - -# -# Lock Debugging (spinlocks, mutexes, etc...) -# -CONFIG_LOCK_DEBUGGING_SUPPORT=y -# CONFIG_PROVE_LOCKING is not set -# CONFIG_LOCK_STAT is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set -# CONFIG_DEBUG_RWSEMS is not set -# CONFIG_DEBUG_LOCK_ALLOC is not set -# CONFIG_DEBUG_ATOMIC_SLEEP is not set -# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set -# CONFIG_LOCK_TORTURE_TEST is not set -# CONFIG_WW_MUTEX_SELFTEST is not set -# CONFIG_SCF_TORTURE_TEST is not set -# CONFIG_CSD_LOCK_WAIT_DEBUG is not set -# end of Lock Debugging (spinlocks, mutexes, etc...) - -# CONFIG_DEBUG_IRQFLAGS is not set -CONFIG_STACKTRACE=y -# CONFIG_DEBUG_KOBJECT is not set - -# -# Debug kernel data structures -# -# CONFIG_DEBUG_LIST is not set -# CONFIG_DEBUG_PLIST is not set -# CONFIG_DEBUG_SG is not set -# CONFIG_DEBUG_NOTIFIERS is not set -# CONFIG_DEBUG_CLOSURES is not set -# CONFIG_DEBUG_MAPLE_TREE is not set -# end of Debug kernel data structures - -# -# RCU Debugging -# -# CONFIG_RCU_SCALE_TEST is not set -# CONFIG_RCU_TORTURE_TEST is not set -# CONFIG_RCU_REF_SCALE_TEST is not set -CONFIG_RCU_CPU_STALL_TIMEOUT=60 -CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0 -CONFIG_RCU_CPU_STALL_CPUTIME=y -# CONFIG_RCU_TRACE is not set -# CONFIG_RCU_EQS_DEBUG is not set -# end of RCU Debugging - -# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set -# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set -CONFIG_LATENCYTOP=y -# CONFIG_DEBUG_CGROUP_REF is not set -CONFIG_USER_STACKTRACE_SUPPORT=y -CONFIG_NOP_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_GRAPH_FREGS=y -CONFIG_HAVE_FTRACE_GRAPH_FUNC=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS=y -CONFIG_HAVE_EXTRA_IPI_TRACEPOINTS=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y -CONFIG_BUILDTIME_MCOUNT_SORT=y -CONFIG_TRACER_MAX_TRACE=y -CONFIG_TRACE_CLOCK=y -CONFIG_RING_BUFFER=y -CONFIG_EVENT_TRACING=y -CONFIG_CONTEXT_SWITCH_TRACER=y -CONFIG_TRACING=y -CONFIG_GENERIC_TRACER=y -CONFIG_TRACING_SUPPORT=y -CONFIG_FTRACE=y -CONFIG_TRACEFS_AUTOMOUNT_DEPRECATED=y -CONFIG_BOOTTIME_TRACING=y -CONFIG_FUNCTION_TRACER=y -CONFIG_FUNCTION_GRAPH_TRACER=y -CONFIG_FUNCTION_GRAPH_RETVAL=y -CONFIG_FUNCTION_GRAPH_RETADDR=y -CONFIG_FUNCTION_TRACE_ARGS=y -CONFIG_DYNAMIC_FTRACE=y -CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y -CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y -CONFIG_DYNAMIC_FTRACE_WITH_ARGS=y -CONFIG_FUNCTION_SELF_TRACING=y -CONFIG_FPROBE=y -CONFIG_FUNCTION_PROFILER=y -CONFIG_STACK_TRACER=y -# CONFIG_IRQSOFF_TRACER is not set -# CONFIG_PREEMPT_TRACER is not set -CONFIG_SCHED_TRACER=y -CONFIG_HWLAT_TRACER=y -CONFIG_OSNOISE_TRACER=y -CONFIG_TIMERLAT_TRACER=y -CONFIG_FTRACE_SYSCALLS=y -CONFIG_TRACE_SYSCALL_BUF_SIZE_DEFAULT=63 -CONFIG_TRACER_SNAPSHOT=y -# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set -CONFIG_BRANCH_PROFILE_NONE=y -# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set -CONFIG_BLK_DEV_IO_TRACE=y -CONFIG_FPROBE_EVENTS=y -CONFIG_PROBE_EVENTS_BTF_ARGS=y -CONFIG_KPROBE_EVENTS=y -# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set -CONFIG_UPROBE_EVENTS=y -CONFIG_EPROBE_EVENTS=y -CONFIG_BPF_EVENTS=y -CONFIG_DYNAMIC_EVENTS=y -CONFIG_PROBE_EVENTS=y -CONFIG_BPF_KPROBE_OVERRIDE=y -CONFIG_FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY=y -CONFIG_TRACING_MAP=y -CONFIG_SYNTH_EVENTS=y -CONFIG_USER_EVENTS=y -CONFIG_HIST_TRIGGERS=y -CONFIG_TRACE_EVENT_INJECT=y -# CONFIG_TRACEPOINT_BENCHMARK is not set -# CONFIG_RING_BUFFER_BENCHMARK is not set -# CONFIG_TRACE_EVAL_MAP_FILE is not set -# CONFIG_FTRACE_RECORD_RECURSION is not set -# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set -# CONFIG_FTRACE_STARTUP_TEST is not set -# CONFIG_FTRACE_SORT_STARTUP_TEST is not set -# CONFIG_RING_BUFFER_STARTUP_TEST is not set -# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set -# CONFIG_RING_BUFFER_PERSISTENT_INJECT is not set -# CONFIG_PREEMPTIRQ_DELAY_TEST is not set -# CONFIG_SYNTH_EVENT_GEN_TEST is not set -# CONFIG_KPROBE_EVENT_GEN_TEST is not set -# CONFIG_HIST_TRIGGERS_DEBUG is not set -CONFIG_RV_MON_EVENTS=y -CONFIG_RV_MON_MAINTENANCE_EVENTS=y -CONFIG_DA_MON_EVENTS_ID=y -CONFIG_RV=y -CONFIG_RV_PER_TASK_MONITORS=2 -CONFIG_RV_MON_WWNR=y -# CONFIG_RV_MON_RTAPP is not set -# CONFIG_RV_MON_STALL is not set -# CONFIG_RV_MON_DEADLINE is not set -CONFIG_RV_REACTORS=y -CONFIG_RV_REACT_PRINTK=y -CONFIG_RV_REACT_PANIC=y -# CONFIG_TRACE_REMOTE_TEST is not set -CONFIG_SAMPLES=y -CONFIG_SAMPLE_AUXDISPLAY=y -# CONFIG_SAMPLE_TRACE_EVENTS is not set -# CONFIG_SAMPLE_TRACE_CUSTOM_EVENTS is not set -CONFIG_SAMPLE_TRACE_PRINTK=m -# CONFIG_SAMPLE_FTRACE_DIRECT is not set -# CONFIG_SAMPLE_FTRACE_DIRECT_MULTI is not set -# CONFIG_SAMPLE_FTRACE_OPS is not set -CONFIG_SAMPLE_TRACE_ARRAY=m -# CONFIG_SAMPLE_KOBJECT is not set -# CONFIG_SAMPLE_KPROBES is not set -# CONFIG_SAMPLE_HW_BREAKPOINT is not set -# CONFIG_SAMPLE_FPROBE is not set -# CONFIG_SAMPLE_KFIFO is not set -# CONFIG_SAMPLE_KDB is not set -# CONFIG_SAMPLE_QMI_CLIENT is not set -# CONFIG_SAMPLE_RPMSG_CLIENT is not set -# CONFIG_SAMPLE_LIVEPATCH is not set -# CONFIG_SAMPLE_CONFIGFS is not set -CONFIG_SAMPLE_TSM_MR=m -# CONFIG_SAMPLE_VFIO_MDEV_MTTY is not set -# CONFIG_SAMPLE_VFIO_MDEV_MDPY is not set -# CONFIG_SAMPLE_VFIO_MDEV_MDPY_FB is not set -# CONFIG_SAMPLE_VFIO_MDEV_MBOCHS is not set -CONFIG_SAMPLE_WATCHDOG=y -# CONFIG_SAMPLE_CORESIGHT_SYSCFG is not set -CONFIG_SAMPLE_HUNG_TASK=m - -# -# DAMON Samples -# -# end of DAMON Samples - -CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y -CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y -CONFIG_STRICT_DEVMEM=y -# CONFIG_IO_STRICT_DEVMEM is not set - -# -# arm64 Debugging -# -CONFIG_PID_IN_CONTEXTIDR=y -# CONFIG_DEBUG_EFI is not set -# CONFIG_ARM64_RELOC_TEST is not set -CONFIG_CORESIGHT=m -CONFIG_CORESIGHT_LINKS_AND_SINKS=m -CONFIG_CORESIGHT_LINK_AND_SINK_TMC=m -CONFIG_CORESIGHT_CATU=m -CONFIG_CORESIGHT_SINK_TPIU=m -CONFIG_CORESIGHT_SINK_ETBV10=m -CONFIG_CORESIGHT_SOURCE_ETM4X=m -# CONFIG_ETM4X_IMPDEF_FEATURE is not set -CONFIG_CORESIGHT_STM=m -CONFIG_CORESIGHT_CTCU=m -CONFIG_CORESIGHT_CPU_DEBUG=m -# CONFIG_CORESIGHT_CPU_DEBUG_DEFAULT_ON is not set -CONFIG_CORESIGHT_CTI=m -# CONFIG_CORESIGHT_CTI_INTEGRATION_REGS is not set -CONFIG_CORESIGHT_TRBE=m -# CONFIG_ULTRASOC_SMB is not set -# CONFIG_CORESIGHT_TPDM is not set -# CONFIG_CORESIGHT_TPDA is not set -# CONFIG_CORESIGHT_DUMMY is not set -CONFIG_CORESIGHT_TNOC=m -# end of arm64 Debugging - -# -# Kernel Testing and Coverage -# -# CONFIG_KUNIT is not set -CONFIG_NOTIFIER_ERROR_INJECTION=m -CONFIG_PM_NOTIFIER_ERROR_INJECT=m -# CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT is not set -# CONFIG_NETDEV_NOTIFIER_ERROR_INJECT is not set -CONFIG_FUNCTION_ERROR_INJECTION=y -# CONFIG_FAULT_INJECTION is not set -CONFIG_ARCH_HAS_KCOV=y -# CONFIG_KCOV is not set -CONFIG_RUNTIME_TESTING_MENU=y -# CONFIG_TEST_DHRY is not set -# CONFIG_LKDTM is not set -# CONFIG_TEST_DIV64 is not set -# CONFIG_TEST_MULDIV64 is not set -# CONFIG_BACKTRACE_SELF_TEST is not set -# CONFIG_TEST_REF_TRACKER is not set -# CONFIG_RBTREE_TEST is not set -# CONFIG_REED_SOLOMON_TEST is not set -# CONFIG_INTERVAL_TREE_TEST is not set -# CONFIG_PERCPU_TEST is not set -# CONFIG_ATOMIC64_SELFTEST is not set -# CONFIG_ASYNC_RAID6_TEST is not set -# CONFIG_TEST_HEXDUMP is not set -# CONFIG_TEST_KSTRTOX is not set -# CONFIG_TEST_BITMAP is not set -# CONFIG_TEST_XARRAY is not set -# CONFIG_TEST_MAPLE_TREE is not set -# CONFIG_TEST_RHASHTABLE is not set -# CONFIG_TEST_IDA is not set -# CONFIG_TEST_PARMAN is not set -# CONFIG_TEST_LKM is not set -# CONFIG_TEST_BITOPS is not set -# CONFIG_TEST_VMALLOC is not set -# CONFIG_TEST_WORKQUEUE is not set -CONFIG_TEST_BPF=m -# CONFIG_FIND_BIT_BENCHMARK is not set -# CONFIG_TEST_FIRMWARE is not set -# CONFIG_TEST_SYSCTL is not set -# CONFIG_CONTEXT_ANALYSIS_TEST is not set -# CONFIG_LIVEUPDATE_TEST is not set -# CONFIG_TEST_UDELAY is not set -# CONFIG_TEST_STATIC_KEYS is not set -# CONFIG_TEST_DYNAMIC_DEBUG is not set -# CONFIG_TEST_KMOD is not set -# CONFIG_TEST_KALLSYMS is not set -# CONFIG_TEST_MEMCAT_P is not set -# CONFIG_TEST_OBJAGG is not set -# CONFIG_TEST_MEMINIT is not set -# CONFIG_TEST_HMM is not set -# CONFIG_TEST_FREE_PAGES is not set -# CONFIG_TEST_FPU is not set -# CONFIG_TEST_OBJPOOL is not set -# CONFIG_TEST_KEXEC_HANDOVER is not set -CONFIG_ARCH_USE_MEMTEST=y -CONFIG_MEMTEST=y -# CONFIG_HYPERV_TESTING is not set -# end of Kernel Testing and Coverage - -# -# Rust hacking -# -# end of Rust hacking -# end of Kernel hacking - -CONFIG_IO_URING_ZCRX=y -CONFIG_IO_URING_BPF=y -CONFIG_IO_URING_BPF_OPS=y diff --git a/kernel/ipv4-free-inet_opt-ireq_opt-after-rcu.patch b/kernel/ipv4-free-inet_opt-ireq_opt-after-rcu.patch deleted file mode 100644 index 79661c2..0000000 --- a/kernel/ipv4-free-inet_opt-ireq_opt-after-rcu.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 26d4c36d318cffbbd160884a0e4cec0da4da4936 Mon Sep 17 00:00:00 2001 -From: Eric Dumazet -Date: Thu, 1 Oct 2026 22:12:53 +0000 -Subject: ipv4: free inet_opt and ireq_opt after an RCU grace period - -commit e3f33b0a1d89d738e2b913dab519226eaf76e15b upstream. - -tcp_v4_syn_recv_sock() transfers ownership of ireq->ireq_opt to the -child socket (newinet->inet_opt) without copying it. - -Another cpu can concurrently process a retransmitted SYN for the same -request socket, and send a SYNACK from tcp_check_req(). -tcp_v4_send_synack() and inet_csk_route_req() read ireq->ireq_opt -under rcu_read_lock() only, and ip_build_and_send_pkt() and -ip_options_build() then read opt->optlen twice. - -Note that the SYNACK timer itself is not an issue: it holds a -reference on its request socket, and inet_csk_reqsk_queue_drop() -calls timer_delete_sync() before the child can be freed. - -Since commit 079096f103fa ("tcp/dccp: install syn_recv requests -into ehash table"), request sockets are processed without holding -the listener lock, so nothing prevents the child socket from being -freed while the SYNACK is still being built. TCP child sockets do -not have SOCK_RCU_FREE, and inet_sock_destruct() frees inet_opt -with a plain kfree(), leading to a use-after-free in -ip_options_build(). - -A similar issue exists with request socket migration -(net.ipv4.tcp_migrate_req=1, or a BPF_SK_REUSEPORT_SELECT_OR_MIGRATE -program). reqsk_timer_handler() clones the request socket with -inet_reqsk_clone(), so that the old request socket and its clone -share the same ireq_opt, then reqsk_migrate_reset() clears the -pointer in the old one. Another cpu holding a reference on the old -request socket can still be using these options (sending a SYNACK, -or creating a child in tcp_v4_syn_recv_sock()) when the clone is -freed, and tcp_v4_reqsk_destructor() also uses a plain kfree(). - -Readers already use RCU, and other paths replacing inet_opt -(do_ip_setsockopt(), cipso_v4_sock_setattr()...) already use -kfree_rcu(). Use kfree_rcu() in inet_sock_destruct() and -tcp_v4_reqsk_destructor() as well. - -IPv6 is not affected by the first issue, because tcp_v6_syn_recv_sock() -duplicates the options. tcp_v6_reqsk_destructor() has the same -migration issue with ipv6_opt, which is only set by CALIPSO. This -will be addressed in a separate patch. - -Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table") -Fixes: c905dee62232 ("tcp: Migrate TCP_NEW_SYN_RECV requests at retransmitting SYN+ACKs.") -Reported-by: Xinyang Ge -Signed-off-by: Eric Dumazet -Reviewed-by: Kuniyuki Iwashima -Link: https://patch.msgid.link/20261001221253.2964024-1-edumazet@kernel.org -Signed-off-by: Jakub Kicinski -Signed-off-by: Greg Kroah-Hartman ---- - net/ipv4/af_inet.c | 2 +- - net/ipv4/tcp_ipv4.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c -index 4ce38c99fef9e..14ce01092fda6 100644 ---- a/net/ipv4/af_inet.c -+++ b/net/ipv4/af_inet.c -@@ -161,7 +161,7 @@ void inet_sock_destruct(struct sock *sk) - WARN_ON_ONCE(sk->sk_wmem_queued); - WARN_ON_ONCE(sk->sk_forward_alloc); - -- kfree(rcu_dereference_protected(inet->inet_opt, 1)); -+ kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu); - dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1)); - dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1)); - psp_sk_assoc_free(sk); -diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c -index 497b1a0370cda..f542d88ccfe3f 100644 ---- a/net/ipv4/tcp_ipv4.c -+++ b/net/ipv4/tcp_ipv4.c -@@ -1209,7 +1209,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, - */ - static void tcp_v4_reqsk_destructor(struct request_sock *req) - { -- kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); -+ kfree_rcu(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1), rcu); - } - - #ifdef CONFIG_TCP_MD5SIG --- -cgit 1.3.1-korg - diff --git a/kernel/keys/pgp/12D27D5D8C8E9BF1AABC7C7C7C64768D3DE334E7.asc b/kernel/keys/pgp/12D27D5D8C8E9BF1AABC7C7C7C64768D3DE334E7.asc deleted file mode 100644 index f4674c2..0000000 --- a/kernel/keys/pgp/12D27D5D8C8E9BF1AABC7C7C7C64768D3DE334E7.asc +++ /dev/null @@ -1,1615 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQINBFnWkEoBEACzKJK53/bCbBhwCeDUBJp8J/VPtbKKaYFksMaBH7QAS32J2UI9 -8/15JunhBwUwu17+95EXkUcnno0l44IwUSm3W4sYJXIQPwjtI7lIrLUavfky9D1m -QYlef6x8UP68UgfA9tolpH7/g6n9M4gmEFyGJ8cPs/U0Efxawv/no08cX+HBgB/Y -GrMj9pVyZpsUDpA1gxexhf7EoxhxHi9o2cZep0VPBL3B2mCz9M1kc7eoIe5SwyIx -N9lFXjNMTiguGfUgShm7YkhrLO1tlZyyLpd+Oh7JYP6s07rjpWMn8mtZoatzoAQt -VmodChQugH56b8kSkEgx35cUu5sn1rrPxYLt+C1sOCvtZ1tiKjvTFxxx233xDr61 -2Q82KL7vhIiO+ZuhfGsnoyTchOjS8uHHVTpFCRzpJy1BsQCySuzGYHugYGfVd6is -9oQyZEjfPQiri3Zoo5K++YEr4FC+V4VI5VTwAnF2KJ+YsBIUAbgTBMpqFNlmDC2U -0IB2dVPaes36GjyXF0YIf0EBEUq/crHE7p+qrN25V+w0DiKT6OM+Dot3HlK/qdJK -bnCVKTJsRZ3HxdHwewcJ/hcDpqy0EVRUq4RAPF4i6M+4rEsNUxXegK/OiqYqAI5F -ut0160cA1nPqNzCLkT73jA6tBxQQ0Ideec9eq2/QDHdvTwcWIiISkiN51wARAQAB -tCNLcnp5c3p0b2YgV2lsY3p5bnNraSA8a3dAbGludXguY29tPokCMAQTAQgAJAUC -WdaQegkQfGR2jT3jNOcCGwMFCwIJDQMEFQgJCgUWAwECAAAA2dsP/iNqZR/tGhiu -NUH7b5fDxel2GflBrltBmGmsssD+mCEhBAHz+860miqb89y2YsUfZWAjGCwRpeFV -eGaz+52ouEEVAdnk0JDT4hLheKFMkgV9GoR73LlcHA3qU1vLPOdG6uQouQ84KLy9 -bjsm1hf79MfGSn7Pqy63jL7CBCvXU/K3aZaYuwGzrv0OOZ1dT36oxV4aoE9baf+N -rxsL31jWQ2UYOko4vA6OKji+WAs8+kOwG03MLRbb8O/uvOJBB2zgFse2+OsZAwGW -JPrVHZRbMTf88U/8OJDgijQM5gz0j9TDyjfxIRZkxOdM8QtDI1PRLcfTYNmDNxzS -SI37o1fFLchs6hzLVwk2KIbbpvh3ZDT/LiwttV0NwSI7i4eV8LWtvBB+GuOt01fz -591uaSMWNEn2wJuZcT8jvoPawJHuQ7zvJ9ba+SaCzXY6+4/Owj8Dafue6+34e3dS -xg4+RSCKYcXga3VnC2hZu5GdrhfQXYlE6pKYx3RYeGYYk8+vPS9fOmJghlQWdAXB -9LjfRPLvg4u+eKX2R6rtep7H94gDc7841KxmiJ+Z6B3xy9yAOJKaBPoBeZ3qZNi5 -A9XNFWHiKQ7x/7Cw0FkewTrmZk9rwqlA+D/jTJhtLJNBHuYIiZMS97yPHphOYK9w -JSSRRLQ9Ni/Tpndqb93+6bgr2yZxFWuLiQN7BBMBCAFlAhsDBQsCCQ0DBBUICQoF -FgMBAgACHgECF4ACGQEWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCZ01ARjMUgAAA -AAAQABpwcm9vZkBhcmlhZG5lLmlkZG5zOmxpbnV4LXBjaS5kZXY/dHlwZT1UWFQt -FIAAAAAAEAAUcHJvb2ZAYXJpYWRuZS5pZGRuczpmc2NrLmlvP3R5cGU9VFhULxSA -AAAAABAAFnByb29mQGFyaWFkbmUuaWRkbnM6YXJpYWtlLnBsP3R5cGU9VFhUOhSA -AAAAABAAIXByb29mQGFyaWFkbmUuaWRpcmM6Ly9pcmMubGliZXJhLmNoYXQva3dp -bGN6eW5za2ldFIAAAAAAEABEcHJvb2ZAYXJpYWRuZS5pZGh0dHBzOi8vZ2lzdC5n -aXRodWIuY29tL2t3aWxjenluc2tpLzU3ZDgxODBkNjgyZGVlOTM4OGNhYTEzN2Mz -OTc5YThjAAoJEHxkdo094zTnJLYP/3zIm95xHl9lBJ+HAfgUead4S5wutwMzaPdd -zSc6hvqwbRbhTRg81+Hh6YpBnyGNiroPaxQGA8ixzmieoNdG+Kv4kvoVy1UOR6hP -lg9/kH2N0KQ9U9HJv1KDSKJ02mjT4pjn/KNhTXYud5hMdDdt5gybe7SVm+gN1N8p -DG0bQSuOEBuFmEB1HCsrhqw7rk2xrFmPmPnCusp8K+4EI8N27qdEi5lqpieQjZS1 -dp8rLPdyEobnSqz50f13TSCn3yM5fnrBkE2d8+749ip518vy9I/CJxPO9eVRGTt0 -NEb8/4g/PcOaFig2623tk9aLC4Fj2dsKhjWSkx1q20JlatqosfKGTVVuhkNV17gS -HuZITfZsKEeCT7tr1fGI1Vikvgx4a5Bl4QAJSnsX+uXcVo4WJ5EL+6RuV4C/vo/V -Li60ZKbSYAjvLzeHx6Q7FcOLPMPhBpyDnrN5/w+3Wo/iO+leruss6O3Dr08mhSwk -bh6L+NxjiC6hphPBK5fq7pgURZHGXdpgoNwpw7hEc4/bbNHZALIlzOkvNNU3waIR -Ev2lxADmH4d+6npIx2ya39yBTKT+QhczIy/PvXAkCUXBNdU0V3oSFB/D80h01N3/ -CZu73MOg6Idoy4eS/XFJEAzCGx02USBh1Nuw/PLwN6u4q+hGxpBiI2pK8tvISkAZ -amXmq5MyiQJNBBMBCAA3FiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAlnWkHoCGwMF -CwIJDQMEFQgJCgUWAwECAAIeAQIXgAAKCRB8ZHaNPeM052uLD/0RsBF+j5Z0OmHV -ojw2pBKwPc0IOQMENytLAT7vrdwLEblFisGpyFC17MIKaKZ++35DL+oKoV339dH9 -O+d58YEARw5vEY2w7bt9RnJupDtM39GBrVgIxb8u51sB6zS60Ik71Z1anbyCWbQN -/CGCb9mZmU+LbxsDGIOjqbiYaJ3/qhzWbY4PE9I2cXev+S3NA0suG4p21XIfZefn -RBgEOkwhJkoMo2Daz5Og3U+6PKBJeigEmgSEzbOhkQUYVI5KcjVaArwL4kNT51y+ -GIkfinXxkpNneDmN7Q046O1xbSbzGTZNuKUv4LDFxhw9+ajxIX9S8Xyq4e4TVAHR -bk27M1qYmnXHNGMwLvowVtAs78vGfIt7mzTWGUQqX+xyV45B4l5s1sKO2QEbQb14 -awrqKbuK0pHavfO/ojtqHhWMu+fveEf66cTRg268xQm+3mEU8aKLB8P/d09YC+4F -HATIKpOQkeLXofjReRn2RBRfe0kJ09LyzRoSSwkSpnP7CnTrPjhOdbcw/UrpuzhU -Lz+EbgUMXUKJ07WAbBX1rYwEPMq6tRLGVAEfz+cJOpj9VTpcmeWlrxao7w1eoEJF -O1eeZYgvIl6Ky4Mb7om/K2TmavdTK5a/X0tB4U5zuCH04nw0fDKIvYU8IbDZshbZ -8bmqPLiqYCyH1hS+i6d7hxruXsiMhIkCMwQQAQoAHRYhBIDHu5fuYfYZ8XbJ7lmI -oMA60/r8BQJjd+oUAAoJEFmIoMA60/r8kQ0P/iSM40InYcO0ZC5uMOMj+7eJvano -RvzlNFmO6N3ygjbEyi94gRyQKzvs+ha5vMbALBn1upo37lRmrcyZGX2iUQFJUEC7 -3BdLW4EwN8i0iu2E/CVMRcEiFBBeeI/E5Fed0i2KqfUIt1TZs1n0IROUeZoPcoYO -0z39iAsM20CmuNDlId7YbSL5eRYNDmoOfcqYRPDB9lyVGRKOc1v4Ozz+LvOQJE6+ -Y/pYeGzGvO13mnDsrlYtMHsi+ammn55TZzcVN72E9MZS5PSlMgfSI0WMBQ/uFONt -+jtfvFjHVz+t9o9BmHjZsVFpnqsZqpcNcYq1Ql0G+u4S+0RTaq9VmaORUlSHZrs6 -pWdwgTEYgB7fXlgxofZkVZjnOQjEjRgHDohmseF3ddeIE1pcDpMguVu27n47tlN9 -Rg9kwjLvFcKfGqS6lu8/HQrNcZmcvATrKm33aPwkQsY10QbBshDlfnCNQ7qGAwAA -FwRHGNNYifgeKjGmH5dwt/DgahL3iqt28oYaUKhAVOIGERIL5cD8sQIp0x1IYAVR -FwzC4LQxHqXBihvwsYQ7Hzd94SVXTRv3k20Rs+ANs9kGbMBEohQGzLTyqPXCd/1y -LfBAAZNmV0o9LjeJp5Hih8HkenqyGtPopT7vPRmTy/UjBli4Yf09JGKkHYDV0UoV -AQrcXmKvnIhfpaIYiQIzBBABCgAdFiEEqUDUNJksLo6ZED1QIk+n58yCpmQFAmN/ -Us0ACgkQIk+n58yCpmQnUBAAx6JYL4wew6A3fAeUu1aHUqpbq6iyTxCQjvonZbpc -FCgrFOrh0TaRSMm9zxMkhApbJ9DjnHcf4//vcnX62ZJGBSbcCxWhc3ooImVa5QTh -SCPGnTq9nyOB7sNYWMfEplykfuW1tFzXhNi/x3dS4Ni35vlgpbC4VyLEpoRV95RY -3IZ/6Xqsl8mgBRkstm63ndihcM5CHRF7ZOdP0stcytif0NG/tTUn1qxoapLY2bWJ -jE7Ev2gm+5e3ssvS5ZMU270Mpip8oUCkSqhDyKCeGdTL5I10L0jXt4sTbo/nlsL2 -F4i04zaO7YTRnVrO4s83sC6T91P7oy2uTjUYzFL4Yo7Sup7/oybev4Q20z5F2VPx -62toIPyTKrdk/srTZWhgPA0FOVwcjOcQR/2sYgvxvW696bAz3/ZU+fBp+McCOkh1 -sdNLfaz2XeK5zZcApxjMkWVUD6js9k4yKAtUX54MzpC0PotMkyHXUHoGDCYhxZ6M -Le/80Er9uNcf4mYQc4yUnilrDUqr80IzOHgvY1E6JobRtx66+vbg/h3fUmHU4cMH -4+IK0nHMw4ESI9gpnOMYs0yo13IXw/Pp39ZxkljvgYInO7lyc8QgCVH3Xsy7Sxi5 -481FNooKM4F9mBwvj8xx4kO4XzETAyIuZGpXC4Rx87L/jB3ZjBm8c6y+7Na2Y2h7 -/lmJAjMEEAEKAB0WIQRXDmMrk0YTEHNqe2+CizmmotE2fwUCY4COJQAKCRCCizmm -otE2f3hXD/sFuGxRuTM4HMUY1eyQOLEzlBtuHLguT62uafK6p/Am9fb58Hs7eJTt -6Q0NgQ2/BudCKUmm5hiMQg/wJWAYgUFTN2N8u9qzBK/regwI0EupCDscKxSe8GVU -ltlPSyyfVsgxAT7wYpHuxPb0Dc30Pia2VZdhEDIa2N6UOAIAyZt9dpQX0WNmpfim -oAfUO4f/DKc+YBJHoso/UdsXPXN70AanCAJCvfWVRjKZRIL4B5mpmuRcZLMM2aO/ -2Vwbn5dlp9Nzv/44FjEpqAI1bsqaioLCgQog8h1nL/ShG/jWyQEx7v/onYQShohf -bjO2oZ5M0HbGyJiCwsTM+NPkHJtFT9v5iYAnIKCYquUeOY3rKmQvP6wvGRmPVeiG -SsW5sRbZ57gw2sY8wx9DNC3MRbCL4/aS9h3O4teYgtLOW+Y++rhALWAFplSJXeF8 -n6Ncb/tdu2VBiAppw8JfVvlGMUup2SqadIwgUzQM8SUSU4vj7zMpn7gtLY9rxnXS -gZMkXmF46lwDdDGYhyT1exFXgwGN4clGotLUvpa2IkstSs4Nf2w1lgj5PKAeE1d6 -AsTujIxtrGfU8EginZ5aWmoW5Y8//9cewiaOATtwU1vDyb2mtIcLn7O36XGXhDGV -gzsa0hH0v6dzhcvPNYbX/iFb9mkGyW7Uwzl0gPzGVex4COYFEhvnA4kCMwQQAQoA -HRYhBJvQfg4MUfjVlne3VBuTQ307QWKbBQJjiHvdAAoJEBuTQ307QWKbtNIP/Rtn -mCi06K6WGGkd+tnjI/2tLev8EqAzi6mOMqv4e8s6R2yQ7zmYz6U/j2fUkgSXRa8E -/yV1Kncr1gZx9JO5x+9NDX3kjOfLMD4K4CNcJaXy5Vv/1I0dxsV9dQ+Kd63HBzt5 -IHlkEYv/tZt2pagC5mIJqvLisALZ/Jv6ndxG9q6Hyl9ocDLQiS0aZl3hA8OXKveL -oXG44/LyYvNlKIwdWcturwM60bTkN+r1qgZ2rFTi+Jv0wRaa/P48k2roVm4pfcdb -nulIGWTwmWmBPmO1uKOHek4MutDdzpkAJv07urbdiQ/clkn3cDdz1T2EOaFQlZMm -QMhv0+Zo8v3VTtLAQlF6WZevt7VG7Sc4Rz+rXfvk6ZUB/XGraz9T826ZQAdSm8JA -U4En6ufqD8Vt9C4w21MWhxV3rs25h3Ni/xSw9Z9BlK9479K2+5gLZoYzqvl4HQaN -/QCZSwm2jWsMIp+2191Y5JxadI7rpZ9n4OQcBbdhBsejUxtgMSNayAlZlq7vNUYh -fNtttBYK7rWmt31pUM7eHk2M+48ohSm9Iy2Y5+j60aTqtv+ARftApzkhC921dyNm -mA+fezcnJkC2Sdx7Z2dhBmdWrE7xnROk/3xpowUlj/g6nV1u/qta08VLNqXF0y9w -cBEHDyw9Mg1BW0l7J+bCYkhC0ked6RwglLxpmAO8iQJQBBMBCAA6AhsDBQsCCQ0D -BBUICQoFFgMBAgACHgECF4AWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCXH30wgIZ -AQAKCRB8ZHaNPeM05wEaD/428He+o/FhsRGa/tIhZCF9o2mOh+kSwwm8XQQw8KqJ -bVVKPP9hIEA7CfQmMmYU3sSBDRyToR2cw7AMOe3UisJF2FvXbvFekhU2A98ORT/w -0H/qG+Z9xedLyPmbqSghBKhXdhD1GcyUNBCkp55rjFQSszik/xs4kLQfNgxoWeOf -zOpH57RfAE1OOa4Ei1ghN6Kpa3R94WZBoFJ09R0zRvLN9GpbdIaNHMBcMaQR5Hw8 -hVY9uBlFhxKKh9c1+rRdMkaCMdUhpL/VAC3bAhL/0Yuy35vQTO3tWFl9p211+qTs -DAsKFF/RO2xVjs8zsmY+vdM9+iAd0VzvDDVnKngbdE8+HPikjdaRTTUD9tZuRCi6 -nGpC0IOLArH/SEwkT23Lw0Lud70OBlditWhtBHN9jbTU3weay+wCV6DOBJHNuQRG -4hijwXBPXUtN4Dl7H+5TK5weMjV0BW9RasF6mfdyqvJmVOglEMtmIWcYlDtWM9K+ -h4MMFJ2BeiO7m2M9RkGS5Ay+KQbOwqbJu34RpEWqH1DBGeRMufiI76xH/A/tousl -tVgAzIX9f2EFDVJ3BEpqzr10AMMEeOqSMzEB4OFXwrzEAAaDFOdtn5Jc3bu2imj4 -Toy+wRlstZuX1+FgRsXIHHakEIA2Sh3i61XnKmeDiCZG4TSsqwN29e+gjaULEBeV -7IkDRwQTAQgBMQIbAwULAgkNAwQVCAkKBRYDAQIAAh4BAheAAhkBFiEEEtJ9XYyO -m/GqvHx8fGR2jT3jNOcFAmOjb/ZdFIAAAAAAEABEcHJvb2ZAYXJpYWRuZS5pZGh0 -dHBzOi8vZ2lzdC5naXRodWIuY29tL2t3aWxjenluc2tpLzU3ZDgxODBkNjgyZGVl -OTM4OGNhYTEzN2MzOTc5YThjOhSAAAAAABAAIXByb29mQGFyaWFkbmUuaWRpcmM6 -Ly9pcmMubGliZXJhLmNoYXQva3dpbGN6eW5za2kvFIAAAAAAEAAWcHJvb2ZAYXJp -YWRuZS5pZGRuczphcmlha2UucGw/dHlwZT1UWFQtFIAAAAAAEAAUcHJvb2ZAYXJp -YWRuZS5pZGRuczpmc2NrLmlvP3R5cGU9VFhUAAoJEHxkdo094zTnigEP/1HvFBlA -g6EFHRE3w83FNlpImKV2GcG0bpqnnn+zDvg3/tFAYpa5NVdaoPR5jpEGxIavIwMX -oJ8QpNT0cmH/cW6NYgjU9B+V2g54hFzpjrh+qTtok+421SJdq/he38+OYCtNva7F -3TaSAsL+v9C5nNvJFhL7HobIZPkoKJZwA0fixkqTwPWR4SvgVfvdPHQ7x/2LUQMN -4OV8cAPtMusMu8rvXSwiNiFfRqdbJoWUB6fGwPj7Un42p6cNuM0aGPww547Kj1Qd -bIxzH3JhNhqevYqQnBKZKJBJWSb0+s2hnHvwt3f3I9mKHnzu8caVpRw8r/0dcoFL -hjtOZLkXK0U2DPKPL++b4DsuEV8QkTnCj7+4x9BaLGGLHfXh8SCy01yoYdT9T3aH -fMSIQhhTXH2lb7HmlXC1IA0J0XB6B81NAOvy5yv9Gpkd2pUiVVzRvu3mLnj9pNtD -I5s4P4x/I6iofexJqkCvLH6YJf5b52yQPzLhM85oOjrHX7Be+OBLv8NKBXQ9BzHY -g/C217S1CwbULW9YNqQB9SPYuMZu/J+PIY+GXtREQ0aBxZzh7G6Dkck1xI7BXL9s -1amS4rim/EjdzoDi8MiuOn8gs987W64L4eFhtHXmgJNl4ovEDyX4qhn2ANsN59ju -18G1/0dL9YF9k3417Lm737l7gCKsMxDXXIrgiHUEEBYKAB0WIQTR9fu1npxgoBF1 -QFgHK8J5kq4eLgUCZ1F2CgAKCRAHK8J5kq4eLkzwAP4ixRS7WcNrmOO6ZuQ7zYu3 -UGzuZY0vFebyQvzQ1ub49AD9EIxEX29mvzkRVCV3Y+DSOtme7vHfH0VQEQpcPUIi -twCJAjMEEAEIAB0WIQRb71VikIEC+1Zye3zFLXr+hfJVCQUCZ6DP7gAKCRDFLXr+ -hfJVCahYEACK+en3N4HHcS2Ng85iWMBdxhDy9fTH8qB26LyTqL0Fm78a+mHdtwaL -cPV2/6p4zknQsI9YLb7pq1dQC0JrmBsvqku+y79GksMZ+9Mlck+VYLPkSYnhqwxh -nNZdjSmQdy664kkzFxH+z8gNEj2F80OXpEtQhgmpwtGztYDvMHEw0/sXAZ1JOlhA -PNpfsFH2UmdWR6Bh3upiv3nqUelurhTPZuEffsycb+l6dchlD/NVmFDtFayBoJ8s -ra18700rVy/EbfN1rQqxJJf+ZZ8/EZffjH9SA0rsAY5Tb8jDXly7DpvExx7YhnLY -gAmpZtyfg0MRvcR03VAMaSVs3gNnSCzgblzs9tBtis8A6n17mRvL3t+gEVt8TJbF -jAWQsZmxDGt6h3gK0sjf1PWc0Sdh9RkGK4A7cs3Q/6VweZKjdQOrIYrxN5KUHhhx -Kx0PylU4dy5yOnu8DG/awBZF1PiIBcs8xHfCH0iBI/HXRkBHhD5izNnAd6llK5Fg -3gtAIzQwkihkxCMpAsCWI7IZTIabrMQsozHh9zDm43OZT+8HIe6LeZbVkHFpU6JZ -2fjGJy2qAAafFV6Cbda3pDR88jN4fC9AsuQ5W5ECQ/UI7/mJxWunviEAxVtkn8Wq -pRDgzWYIAu9OZ/Rko4ilQfzJsu3aDDGpBvwZb6qOXvEopd/3rJm2ibQzS3J6eXN6 -dG9mIFdpbGN6eW5za2kgPGtyenlzenRvZi53aWxjenluc2tpQGZzY2suaW8+iQIw -BBMBCAAkBQJZ1pDBCRB8ZHaNPeM05wIbAwULAgkNAwQVCAkKBRYDAQIAAAD/QQ// -fkOuOagcqRJx6ABgNq88cnaDqcx6Vi+RSpG/HXrOzfHlt6QWn8o6cGeZIUvJVzmW -G9uumdnotdSlAwE3CeEkbsX6y5CkVLWIOjfCVir3Xg8QJ++WNROrnUktcrAlL03l -O/uqBeoASEA3bpBivvZz4d0t5XNJwpn7Mzymms8D2wBJbRBQLcTlrZQzrk1tbuwW -AuTSZvD0ZteafNimDGEU1z6UExeTk3XVKY8W0j7oETURElXL7ftMxTRb/0Do0c0g -Buowdnj0s3e3zIArACH1KVz1Y8amNy8t3nchleChAwivsuT2POENislYh8DGIw88 -nJLVBg4+P3CU4HVWGrTtiY0Pnigz/45B8KobjBH8M6uAAVfGkTltetAkmQ2E7s8c -dOXDla1zriTKVtTCOXH7f4Wa+Tfev6OnNVDMdgp7i5Qb3AzAWDjzkAtuZ7ohHDwO -lYA97S5j37RPNlFR/w9u8rAMuTq+28hGNjxcnsQ5gq7yKu2RkqGaHgEeouqHUxJx -u6QviI9MPHOo5sJ0hPBk+akW2XEFhbU0TRNebCNxBJDkYrXJSY4L6UVPEt4J5yG7 -awZXrw8gu6tDopK0cMv2NXbXe/kVVTXh+7/Ve8EaAFPCDCbp7UzZPf854FMkioAA -gwtgnd5rfth+5JjbuBEHLue2O0O/f/rQ9E7eL4k0zNeJAk0EEwEIADcWIQQS0n1d -jI6b8aq8fHx8ZHaNPeM05wUCWdaQwQIbAwULAgkNAwQVCAkKBRYDAQIAAh4BAheA -AAoJEHxkdo094zTnbqcQAKk9c+A4HTyImR2gTAcLR9eut2FQGaZbkQYGWHKhhEFu -3va3AaMSW55UEDlHzro30+cpMIWZIQxcgApLpqlTLpx4OWGWGoeephXtuMVQdmk4 -yFZyUmlOOk6+cZwuHhkX4SbWMv6oaTrUU8ObasdwT9gHGuc+EYMA2C+i2ci7JcnV -tnhDyWj3Q22kFHBP+rGNnAgMZKpxQiPpB2GQpZK6Noezxgc+WPSsBn58uSNduDQf -ujk/ju+J26osGKKYPCBNt8Z2TrY7+MLBc/sXgh7Rimm6HSHl7om5Z5qA8mqZSfU6 -IIIvZAJWP7gnbonEhR/rZn2dnDeazmOstwTl8Ajl0r5F+PHiVbmLxjLTtHhFjWIt -DvBDGq7XApdAf4OqktgjENQ7k+53RyBIonlx+IUa2XLwhVj+lmHqYDFoTLTfV3+m -urkR3DUyPOlzEoNqbI/gjH/Hij5P6nOQipt9fDEl2Q/08WBA7tWKZHvpNhHAJeoC -4xRS/VqiyVeDBx9tIcpqINvaEQeFv+xTIULOQrlSbMqDXbHYMKMVAmyj1N5sEnsf -kBtuQKtxca2aPxlpKMcVRKDMnOgHCfMDSZ3DAFlB92is+t5Xo3jHtICGEzTCxwFO -owZQZtVTrIBi6YE1aqmwRwCDYeK/IXZ4G+PBX0QiO8HaOl40tExmyWoGP0zkij19 -iQIzBBABCgAdFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAmN36h4ACgkQWYigwDrT -+vwezRAAtvWTjqAQIRY4iwGLs8WPd6gD7/sgMto5iZE2eWzGYNXQb5rVV79ITiHX -XgQ8bUvsF8qMiUbQbg5ufu3dCWuY5fOPrXcePeLAPZTqT90zQS3ScjyrFaLBCP1W -5gmqzjevr+tcQZ885XmcI6yczFvzxikfokr2E2cTqwOydFfYUPfxWDuNZ/pucUHp -Y7Mcd4WHWtqBOUD2NReXwYIrcNpyqPqFR6DyKwmrSslRL+m1XwKZzsu0/pD2WnCa -okTb/SIMx64fMPQR84T7NaknnE6jagEpWJaEUOrkVRjzcF++oNB0hpWDgSPfduso -69lJVPwIdhkfwux0Svy8ECVKPVI0fg6lpezOKwMql6277uQ7hGMTrF0qiORsCBrR -u5H9NJdRmpTiaYA+enjWJQSRCDDK5Nm1VCm3xE7NjEpyYD78tU8kZoVp7FyNEGD4 -Txfcpsau84y6l4DgEeO2EyxGTJj5w1fhmdJjRbnsP3JudJl1dCMIR/308CT9lCrp -8vagazbrLr6XMlSuwMKogpyukjnrvCaqJmjDzCj+p/oujqZycz9uWbqmmkVjb7h4 -dOKJj3e1ZKI+d9warOErysc0P6XxiK5D50sW5BeMJdusNu7QJecyDc038cF+IRb3 -7djchaPNrAx7M3O8tRPtxgpOIIGKYBEv9w3NCOk6An90vRuX7lSJAjMEEAEKAB0W -IQSpQNQ0mSwujpkQPVAiT6fnzIKmZAUCY39S1QAKCRAiT6fnzIKmZFiOD/9sODK/ -gXWC2mAWwU++1S2CtoIs5QDwz0nmdB5a1GR0Ha3kDNsXU0blECGboYp0bs03Jlr6 -FevZKPvjmC3OJB8xypvo4I2LYWHk/QE+wvJ5NeFqD5LGvPc2d8yOlyBjhNULDLum -8PxPP2qi7NSLua27wOYtdI2Y2Dn5KsA2VHYMOBG//MsWDfomTrmi1sGcvjE/UzUX -mu6enNen31+GvVsvDstPRydnIEE9+gZsfWC7TkEen72LyIM7KOB9lpVhYQY6T2XK -4v3sFghxHscxPJ9FYcsmb99A86lOLMfFuZ37NOU3BU/pV6bIjk2Nd8SAXsxpRJdD -yK9Ys+nwZ/piJApV9m6dCiwBGZwIBi1hdGdgODrEtnfvgT/uxTj4Q/VlUX7SGm7a -g1C+2+t17dQTeW6oBma55SXaxvwIDRFEi/NPtZ87M6eg6Me8k75C5KgoqAZ7213a -2NAFNiZ92lCcNvaJNB9ZNdpuXf7TfM73+nf8lKBCxfZzaad2MSurOry7epCbNqcg -YaaGtYszWw/neAjLMpTTo5D/fEqeDRY1aFtNcVjjXDMeN/p+80ccaLoJni2ZDAGo -HwU+jncXUBh6kY1ZexzpD06+mK+AmTHWgeRNPDiEaTaEHfnU7+S754GjB6CnU6xM -FX8M61Djx4jQid3sFlGYEK1tI30y6KyCxt+16YkCMwQQAQoAHRYhBFcOYyuTRhMQ -c2p7b4KLOaai0TZ/BQJjgI4vAAoJEIKLOaai0TZ/i2cP/jKFiQ40JYO/iqAcx73Q -U6S955wxi0Z2FsPwau3BrugRyF9WEoRQGBk59uAxn0m7ZpOpHctCiCPkpEQD+cbb -wgSwkRIdwljWTq87k+HdRb4uWWejwxFzy8g/ycBAB27g4P7PWXG/GHWuRj0UYsxX -aCdfngtaVTM0dpzWjCpAia468OYPcPHO7qtqdTn1/JlNYYEAbFTgHkHP8J3ky3h3 -goTvyIrjJ4Ui+/KehIX0U2s1jC1bJWjRmWujKEjMxVh3mAOxxhtEO/aenFRnjofj -XVxp0zU9+FlQ0S4CRE2sJxO7PZE9u6Afu2hmleM3Mc9gOH29lQPTeg0qAYCEIT4K -VCDFXR33XdPo03ExVgrzvh4Pl10DCerx6LF5NypzRvc4eHxZ7rFxHXlKbKMPBkEC -E8/F+uI78eA9Few/Z2hZOjyxoHxEufrLBo/1nMJNBVFDz+8y7zmsdG5YBOB0c8V0 -xgbiOXgpaJ4YjtXe+faA28uPRYXFeY6irm1j1SML16pDxGO+o1vnDTfy++WV5iap -+8hYTfaGliF66G9Jfcv/3MDLXcTH0jj6PWPk+xjWE1HcJWf9t1RVRbCLGUjMFB1T -YAgBCdJBTdMYYEzG4/EeRBqV6vESNeqymcyW1JtmR1ICUjwFj98OlSsrg5XR2Ymj -INax96ANtojmyBbtwel5zWjIiQIzBBABCgAdFiEEm9B+DgxR+NWWd7dUG5NDfTtB -YpsFAmOIe+kACgkQG5NDfTtBYpt4ig/9EczcXuLjP/P8kyo+epYoYQty81644mZs -cVll8qKM3/dH+rPIQralTBXJlY1y4uYlyyIO/cvqCgmfRHicG45vHq32BCEaSslk -PC0cXl6L+F9cGhDvgQT7YMhfV1+smCo8X7DLyMiVXXmkbPzG0AjU0pPiKL1ury27 -ZdbyO+tzXlZvB30jjNmvgerJoDDHmNPyrsSSDthlt29mF0SpeoSi8oVoM8v9JDrP -bUIPhQeymwq0oiRSODfL9hPHG2hgNAv++lWyipVbjMlp8+j9BskOBAy6Ccws4qA9 -JXPIM1S9cWs0opROlEY4WSmJm2m3hyHOu32bqbALxUu2vikuiZgza5puRh0XEa4+ -IyH+u9heuearEjzHTRutcww1jCIT/pke1k73HYLJmnpdY5cwK9AINnSCEwalE+Nz -h9bjI8AEycs0gpdlrqKM/bwUWnuKFjjpbE30GFZkS4aj6uXbQR0bCSv6Z6hBW957 -lRceKBFl3O7nqk5PAuZMD1GyM07BnPknWRrOXfqeUpIkZL/eAn24eoRyYwTboUlL -+1FbdOww2N3gPu2a/r0S6zffcpCKQwxO2IJNWNDeleY8bR1KQmn1MVXasXY/N3Op -CbBrnw/xoSukhaCHvKTkTfpvXdClmKeATzU6/xfR4B8TBDqPmQn1i3dNTPCnXrvK -0xwsfHyFpI+IdQQQFgoAHRYhBNH1+7WenGCgEXVAWAcrwnmSrh4uBQJnUXYUAAoJ -EAcrwnmSrh4uTQ4BAJc+3sCjWc4Kyb8AKdJ6s3a2RGHuOnOBCSpwPKGdWNwyAP94 -bCTRTXfxUhaEgOj3WTUniWqk3XjdTBU6w7qR/S/+CIkCMgQQAQgAHRYhBFvvVWKQ -gQL7VnJ7fMUtev6F8lUJBQJnoM/zAAoJEMUtev6F8lUJu54P+KptmM6QY9nRKujb -SrVETRiwEypEhVz9bKk1OzYuDxaHgnYRTo5InerMcmiSjSWye8RwjzznastJdpqu -NSMJoeriXaUWPg6Utrgc0d73+NaAGL42DvQWdSNYKB2tin/uQRI3xkJE1e2J4mCp -QW8cerwZFJqZJClbf2djROuFux6Zet0Yl58zousy7ukZkg4sBvBSIxpdBQe5MLt/ -KzLca4fgnwrzOnRRMTRGZi2E8iqbogXfFafofJBjT/1zURhUpqOtmvLNmzRXzEMC -Yy3VYEK1z9MzZT51Aj+LOQT4mPpPo/QIZH4pb0cWf3bSP1GYmVA4FlDw1FnKmClr -/axHMs9Hfg2MXG5JHe2/E9a4G4H0FCpvAOz/mM3QSlxrj+hdLpxU/iuc+fRSQUV0 -qiHj1pyIQxsy3mGcm7Clx10oqYuPQ6TLhGm40YxbDqvs0KrEl9dSRDt5hmSQEis6 -6KvJPSoiFlEN/xUsob1BgZZTqb4ZJVAm64SId2B1w7y1y1+KlZ2WLSxsQbvqLcyF -ThsrfdKwGmJV9MQ/7j5N/7b4tgdeF0kXPew9lWGniI8npkbOalT4Xl+lk4MN8yjz -ieCCLgfMgN24jh5M+Vj5XLE12YL3s04gq9y5wDHP+yqBFqC2+yS9JqVjq/MFww33 -XTNsIgMYqEET5oy94Hos3jRUkSy0IUtyenlzenRvZiBXaWxjenluc2tpIDxrd0Bm -c2NrLmlvPokCMAQTAQgAJAUCWdaQzgkQfGR2jT3jNOcCGwMFCwIJDQMEFQgJCgUW -AwECAAAAkJwQAJ7GlS49bgbN7ebDu+6kUTiuOZXxdNGPcjDrqIE65QqosY0L4M2M -3ZgnnZ6uSO/NdyQBei17ZsIYeYTIrEWW2AmVJ+sRARAdl5oFXtgyP0hCm8FG6Tgb -9iC01wFfeVAfdBTQUhxFUELtHsO3LR1+SXAHYcxN0m/UX9l0iwjBPomgniwbbwiD -x1cH1O/Po4ZFCbUDMmyzr1yJ4mzSeD+vkPekpNBCyQpvtXZdoVj3wAv0LG2CWVGy -IH6MXLAHb7/+e/wWshdaKHS9GEUnFLIX7RefLDrNFN6pX3TZLMIfh0XygSXhp5SY -Bcm9649WLRR1CzgYOx7ffPYsR00AYsVexRREB+24XkaDm4NcC5RaDlml+y9u2hBJ -HfJ2ZDNVDUUkhJ8nQxrA7T3f1sudoSpdPfWfWmhqxl3NG30qNRSLv08GZBVUelP/ -6phcsdNVQn1c1Srl4lBJ8w/GGKAQptxROcuOlzqlLoG5ld+5iO+S1Hbxrzn5UVLb -N91OBXzk1T84snchph82440ts5HvwYNmUFOAuY0bFVKp3fgq3Ie4gUSBLpMAjmCE -9C4YcdKP86P/Hg+n5XcXr8Zjn7kxfzvLRxuW6mRyph2pO8YgCYHGGKo2B72i8D0Y -/81wCw1wOFKC4AaAaLjifmhvP39IKPD7rSZ0QyVeBFNztmihKIXj0edKiQJNBBMB -CAA3FiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAlnWkM4CGwMFCwIJDQMEFQgJCgUW -AwECAAIeAQIXgAAKCRB8ZHaNPeM05/5QD/sETr3RWbycyhNsp0NOa+VXFUVl2p0a -VTy2fekeh9Xkg4OkQULa9/OrLUN1shPd8cd/ANHBeO6eGKkYzWTtzXU8FRrPLudo -0Hvzu01HLly7YCyODDQCzcD5J9hd3UtWB4blPvWG6xWpHV3bNBi0LMdr7/rwhniY -MpA2D2KlWOP0PmbKfJNEMZwS9FruUBGBnIhodNua1wOB33vBPFaG7Rhd8Q495Vje -2afOXjbS0zBZjpkZ5Mnh8uc20QwywtEUojwphGZ8ofCboOt2XnXJDUa6nC0q/4We -SH7xQEjU6R2fWmRgC1BagE1BQfzoQGRLmhHOjrnA6lnKZs30oSP6Ch7L3GBLwzqj -D1khDlryrnkfMBQ1r10yLZLNg/umnHPzs2PL2OmyAX2aR6RtJ6/MPKMZf+ZOfQxu -0j4pgLOL8mHIpVdepn8pcCx/csu0rcJkV9zTirAIUX2R7Iwq7I3twtrX58dzbLUe -XqpkrkdApDCfk/TE7lh6NK7XS81KnDW2L3UftERWHqZ2PDorgPfWrWpjWUVgSMCP -QHwEkq01RI4bNA9n9PbiWuu+DRODqj63L/wA8NlDFfsWyHo2Oo11vsQwvlCraMZd -lWeqdVcYid0OQblF+4poEkMzFABM+zLvVrkb1X5OU2q6US67XKI2WU5O5u0n21St -2DHPyvVn69Vp3okCMwQQAQoAHRYhBIDHu5fuYfYZ8XbJ7lmIoMA60/r8BQJjd+od -AAoJEFmIoMA60/r8yGMP/2WGZc5sN3P0zHKkJH5X3fU40arUV/Zl5BByrFenAOb/ -8fuWum/LRlp8L+d4or0Bg+yyU2Fv+MtYAq11sOSp8TKklGIpgksuKpco8qa+rmsC -5qyIcsgrPX3SZr90jhz17Onge46OYOj3Brn8vcu1JQWl/EPWg7I/FMJXIL0Lj+Dg -4gXLn1zT5EOPa1XdESlV60M7ItOXMOLPIOBVvLRkkqr/7oGQCVkkz4A90XnvjWX6 -vUD5WcHXEr5k2BsDUBuiMneE5BriGT3Et4AK2S3uxUWD93ynYU2dj3CF4gBNoe8w -r9uh1BzzRQBuv9lUBHWtfC2AIk+FThkpfwLI5xBoHo/YR/WBjFGfjX2NcNT3CJj+ -+BiFD/aES9bHSI/15DU+Xacbrq64ErcsVk1dElAyuICq7lNYw9Khi6lRaUNNB3QP -y2OyG/9YuorO5bFIIyZrCJ1DVT+02P8ueI5N9AmzBICsNspf6YxyVczxlKxavybO -uVOPnGh+AhHkSTkE3kWoR6EKvDRhx0WpofuH0UxlNBhmvfVNOehLVge+XuWBT2kg -nI6SZ1CRvHvHuvGlaTAh55xiCcjNMlMd8qqx1ooNqFXDQo1sBFksiob562WbXcff -O0z1wkyL43ZB392LrJDrbgaI56iiQaHwp4Mh9KD88H5MQtlb35j7qmhrC+Oirngv -iQIzBBABCgAdFiEEqUDUNJksLo6ZED1QIk+n58yCpmQFAmN/UtUACgkQIk+n58yC -pmSMgg//Y40XQ/E0FGCEAZs4My0qC3Qcxz1OkXyMVZ7viibVgHv8VG6p3tz9G0OP -i/Uxc2OKntnk16iLxH/11EAY6lsrDTg1LbtAJDqzBnOCnY4reqtl7f9o33KggT+O -T85+frBZpkbLbcys60OixIox2P3W83lCoKRmEgWR66WRqTYgn+ZSMS0Fn35QLs6M -VRpjTw7e3tgDvU3RpLcmoHjKIOklUwAoeX351V7qvadjk1+k28BidjM+e/DCLFoZ -oQ/fTxOt7tmflzHgd/IsOYxt38ZZh6AK4NE5taI9NTflJQfhzkBPORrKHP4Epzn4 -YTTiUXFkNT0Y0beQGO2GkGRny36PGPCqeZ5xHSlTq/Yt8dplMBk4j9/wRjE50Xxz -XHsdlS+7T2DkA67vYV/nF/x3u6n13ewUyLVEFo/L1ke1jc8Htu9L06BoUHFNOyMw -1guvDzLxqfGJmpwG+HKpXDEQ5zsEt4erE2Y+cv8ovoIDAGdCJuJz7uxzkw8QkMgd -o8BiHPsGaWtYcZx7EvZPfDeFYr6aqV6CeXebQsQn2H5PpWg8bU1rkGymyhKRyFwY -e8/pImzf95/iRCuCTzRZMVB52Rrv6WHpcbVXcYyFS3JKlYPna/tgCz7GzeVNgu8v -DeVWpXVNdulk4NZbPwEuCWTO9gnK1fe0zGAno/b77oXTCV9yizOJAjMEEAEKAB0W -IQRXDmMrk0YTEHNqe2+CizmmotE2fwUCY4COLgAKCRCCizmmotE2fxoND/0X4XeK -hncS8TzYsPx73MPuoCxi049rsksato2jiG243k5pWpydmQ8ZDQeBIFZ8eGAQpDTK -NRdMLkrWdncsBnubf9z/lcH3QlMIwzty5XMbQmG5ObsHFHb+fHOijNeMW6HVg/2b -X0mBEtRIvuDwiuqYpbQ4GIcVKzO5CO3Z+WWq4N3i3G4UOEuf6QEwa2XSKmVZmzbd -63UWXMcbFB3pdQ3catWc6gN5kn6AFIZQdv6lwFHkVqdqsUMa9q/TW0jjFHr1lobf -IAeRNBQQjKB1MfixjJbRYNAuUEpQKI0y/pptCK5Hs0Kv7lC7XsE9Os/0p0+dM6PA -gr7YnWCTyI9isBZtQe1XmHZiU2R8gTUlfELMQBzVJ6ikw2VFYZ+bZOXCah2RiAGz -JfUhwvpOBc58WXszhyknY5u1ffkqsK75eGPTMeb3qEGmKi+qoKeJA24E+deKmuAl -vlPGTzzW/Gq60xo8hLfpUb4k8Fr0og48yZVZZcgiuNhOqtbApxfzFpoNAboPX9Dz -0xAIzIJK4Q/iljmPqbyFFosQyp0YGr89XxQ5RCf7KfpJ1QVZUTvYL3ClPA6+lcu4 -gEFAglyms3Jw1bQb4JTO1FiV9Ek8EEo4Hx3s/eunIhqPwUuRAgVjbGv/k66N1FUL -f5DUDUNn78T3L1MncjWyTbrjr4egKJ3UjFGEdIkCMwQQAQoAHRYhBJvQfg4MUfjV -lne3VBuTQ307QWKbBQJjiHvpAAoJEBuTQ307QWKbqRwP/0aafY8fRkSdUUcoH2BE -i21yERvpUtyfKVFANI61hi3xv7GpxMne4plla2s2I3LowQ/MaqmESm5cKPe7b1Mq -OsNKWt6tFmdAcQ0G7n2+wFt7ambfEG9zH8qv87bvqJeNRdz2C0Dn9vhI1qqWFYM1 -K20BO1hAAc7W88i5KC6VvD+tNBRAvtCEwtVOj7Gg+jWSrw0bBUshFRjTzA6hTup+ -NlG871D/byYlmPUoQHldvMU9Rh8vxQ1G+y0dXeTdo/hEau+WR7GgT3hNxgHh4qoD -TfSwAWMwQorrst12ql9vMYm/Ol9vzN6Ft66U5L2hh0E23NHYNEVbN30Of5xWfC+G -Cjq9cHhuGdbSBHV2+6ULy/GicTgy4Hk9MTR7lbxEk3PlSQ++pWFF2SAaUnleYF4/ -rNv2BziI/ESKDcA3hwH9NgXJRumCpdq+xjuBVfOT4Tu1LrrTnelvLU/bjr/iWLwc -ig5lE5qGS0wz4iKjSL4rlaqYo5h1i5thLq3boxw3GZn97136WzM9Uwc3dmozOS0b -6qYOVQRxWv/05aC+peIK0UqU79nOU83NkszLSOTOnRXHBASYau0TtXgukE6d075c -oD83Mkc7UB9pxXHluG6m7nnEJ1dVAhiAnqfO9bB2vsEJGLD6P+JPzg9oeQJIpFLj -GfN7q9d0qcxyuAq/tFzmD0JTiHUEEBYKAB0WIQTR9fu1npxgoBF1QFgHK8J5kq4e -LgUCZ1F2FQAKCRAHK8J5kq4eLkDQAP48vOzcDKqxFFFk2d4Z/VmNtoTr/MlDLN0g -ppGp6cDxnAD/QQBqjQ3llOjjK/+z8L+crT9Iy4kl3ShnYYIUfhNIEw6JAjMEEAEI -AB0WIQRb71VikIEC+1Zye3zFLXr+hfJVCQUCZ6DP8wAKCRDFLXr+hfJVCZCMD/43 -0Cdp6haDD9ZrKMUsqhTsCF1gItFyvl8A2Ugz0jAxx3nuwyNYY77r3TILG8AOYRkL -/Io2WTy8O70Q2QXbKb1Sn+5nJHO/WKXE/ahauCSxtMNlSshv0sDAuND3Q5IM2jTR -VRvyEGtJ5ulrtJuZ1mhFLFlezFB8pAGZk5vtBwaB89oeQDy54eJg5t1A74lZdEqr -RXrWPc+qAgh2ymIp7lwuvoRNMzO9CP3qEZRH9PEIVWEXLcc2mfaKGpp1qJ7YhfQg -C/mwZ+DrGGp6b0yzZ6mAko63b7Hkx0lF1qXOt0o9Yln0oGF+LPam2JBhTQ59ulxL -T1iNDJ/qoQfLzK73sJGg2u0bHA2/T3ReGXp0tUTXDH4KC0WQdmMApdz9mp+bh0yW -Uy+bbQ9ZxFJiYrPm+yrBBlzsXlTxNtNBVKI/UgC9r6jAcW2D5F1hM9Snt0q7vjgd -9XTd7uewhd6TVrYZCDK6LFreFqu7WM9YFGeahsHePJqRTLw5CfdUgDPiqyfm8j+E -78yT4BpmDARfu6E+KD5zAxHeOzpVA3qS52Huush1CPIVuXgt6Zpg5JhCh96SHgFZ -DnofUcNVKYDz/sgM3Gow+HzQMSJEbyKpj5ZufY9cpdUAwOdts66tkUFW7Ths+eUu -cfEprbsoFkhsveb17H2ZlDWJa3Gxcp614+FBhXG14LQva2V5YmFzZS5pby9rd2ls -Y3p5bnNraSA8a3dpbGN6eW5za2lAa2V5YmFzZS5pbz6JAjAEEwEIACQFAlnWkOMJ -EHxkdo094zTnAhsDBQsCCQ0DBBUICQoFFgMBAgAAAIIMEACNeYYjbcoXkLmxS8mk -vnvE4VMiYqMmIsXUddSql2yXNFi45pJ6Er3JW2Mk9QKyN1RYzp5UMTsr7FlmWwx7 -GZJHhuuPYAmLj2xIK25TI0XWWNTgQgW8yWSH1ZCXr8YU0V4ys22V/IuzGibZZmKB -c1H7g8jXG/65VGbyhmT7Sfqe0tkoV5xlNt8tHIPnFN9/EBTQc7C+QDzJlOtMCtCe -Y4gvTT3iyKJYJiByjR2F24Wf2KD9cBmKk1Cuc5yFpBSMjWC3Ndg1vBTJsZI1kRW/ -Z6yIaRhTK9NGuVdHW6m/2xRKShH7Vbof7t6ZSNnoo0oaa0jqeUGRPnAt0bBdvMLG -meHnXrVDVeAnxWvXeRjwWtWiHyGJsn/lIFkf2FU3nxGCcDkrtjPWUb1/Vy1q//TJ -mxQuXe3lKdAF09DQcxib+RnCdYb3wk9YgWSP/Z7VQSJ+0rL+EgOm80qTGlxW2oiM -euwXT+dHkfELTkNM6Pzl9RC4RnhnDjuMz6Mp+0b/c8K51LKS8SvsJ3FsVA4oL3vC -GYaCOW/Fcfg0JvVLpXkVdxOztEc2F/UxqILmG6wcqtLfhqX/655DzXIZ0bo9VHAo -YpnWyJ6Yed28R0QBeI7cgJ6g5CZ6tsSvI8B4EVEoAwQpc1q0lHZH8FuWbBLCRmpM -psZ6r/o5Jspm3OS1a30K5Xw0xIkCTQQTAQgANxYhBBLSfV2Mjpvxqrx8fHxkdo09 -4zTnBQJZ1pDjAhsDBQsCCQ0DBBUICQoFFgMBAgACHgECF4AACgkQfGR2jT3jNOfG -IQ/8DLxIUCWPwHXMloHoIb9wBIVrkjwt9YooHHxsO/pcrI3r+T/teqsffRXMfbf2 -mwyzgY44gsXyXHKfXSOGvvgdThNl+WGUUv+ISZG/ks+NdXjlVrDsCJ6zo6Ma3c7a -xI6JlV0YqisagoX2nh05AMlJxBvMrlTlT00NOJD3GcjESfvK0K+IB+CfuQ4JYzxQ -GSX4qH8NgQiBZAoG0MqcU5GDS35O7ImbS8iMRg2QGPiptoVbzkUhm/vDSIBO75AV -8tl30ZP8NU2EHx1OUov5ug7boCN5day5hSKMGRkH1vDfrNcV4P4yaknAKwJm0StJ -6maX6Is2uj1EShMTG2aCYmuTUzh/xN3ZtjffEH3SpQwNECSM1tkZATX4vBzXu1T2 -aOYmuEg3/iCVCfA0hJ/41xVxU/Ep8pzLMvG+LjuAnc1R+A4gQfFq5P4NOadNyUyc -h/QBM2YQ+dcR9aHrfx7oT7MPBqUeXbYpSBiI+cOt2JIRq2NZvmaXcmomdgfbRATr -olAm41itAnyNElKuOHnNvHIxQgxcaqsA3ST0SctzqUxpARmLyPj89i2OsaaDVvBW -omjEO9YgdVy/9sBtpj1DMOGH9yDnbb9SKLpMfCERrMZrMifCl2+M1EVPNvE9oBug -xR/acf+9O+omGYBBCfJeZrD85vcGegGbcYZiL7B2eU7zjZiJAjMEEAEKAB0WIQSp -QNQ0mSwujpkQPVAiT6fnzIKmZAUCY39S1QAKCRAiT6fnzIKmZNwgD/9IkOBX6I5d -Vfb9+0PFJiM4WzrNQXcNwdfOCHpYdxFpNdA9yRHeIvY+7eEFP8/Dr4zS6Oh4tKfX -bdRAVA/HBwYrc0pfOxWwf5VtntdccaHRMYeA4vsjSyifM0U3pHrr3Ix8oslflABb -WKg7+xgRAB7iYF4fi4yUVW2uJRRpz2lADKcFSY1crS5t6Cvt4fZGTPN0M1kBe9h1 -CuI4o6H/ZeceXIEDzRXq11u/UDoMeYvcXLUzROz9lcitPid9BuQDTCqYyBX+vWjo -QFV816vpMwbq8Y9+EVtnAlhcpWZ5GmY/VU8CCbQqEuy7xdFh2ToSBFO8hNFpMXGr -81HU0QZ/1LK1DN1eZ5xnUL+H6qu9CmkWelrAw4b/bzbkM9kam6Ghghxham/YKDdC -byO+V3en4VSEv4LRKbaBxcZObyxU2BZGfbfJsThPNQk3z9LcZb8NwohHoVvKn8vz -WkBB/3lRSdhMnoz45VCOE9QLHyMJpbyudlSZ30QZCem7cK4ONu6CWD6vgsKz/5JH -J1ZXkgzTZ5SN+6toqvggIOGga6VO5r4JVuKV/dzl0MyO+BhiJvazFVHJuRGwANWn -8zBH3n/kF7hyQcCS90NmZl/NunAYfWiPB2CRdwfbb5AcKGIjdXFra9D1LgMvRXvp -HvMRC48EcH/LwhpFp7nLGw/7KfOXUViR2IkCMwQQAQoAHRYhBJvQfg4MUfjVlne3 -VBuTQ307QWKbBQJjiHvpAAoJEBuTQ307QWKbdDIP/1j0OrFGrLfh1Khbj+ybujpT -MzaBhs4CAtxZeEBV820hkcWZeC7t4TQ1bXtnVqpR9nsTJnfPCdJRWpELYJXjOozF -TISw2aqIZpv7KQG2oWGY4OG1+4DdbDAvxqXgiazk7ZlcgdZuww6Lxo3TjIUC7Wk/ -lCnNncDPQcWHAkHlhC/NdWLmpLpGMQTSHXxaEajsZw6RqugSbakno8/hfZNRURT5 -+8lkGzhF2EiMxnTI7a09YYmbBjSvJxYM0IuaI+5dWMd27TDXVD7afJqD+vU9zhcR -ofjsZfdi7/OnUjhb/lh7S5nApaTTlJOGxP6tg7mqjp8xiUkCq6PU9UwcSWbZB1cs -CexQKEzjpQG51E059VCz77CvZ3qPbZ2bgiUtx3of3yUWX2KVuyjN4OP1HM1ng7U+ -D8PUlg5YDZOmuTD7FyxE7oQveGSYAhXgPDXCL93dzjVLyd7Sl3Xcnv9bdirli+8a -rFyK7P7mq3fKruRsAzrQ+kjGG2XfvZCTCoxmK8NpW8i6VXgAUug1kFVX14Bp3Ts9 -kWbrR/2WZO4PDMkIJSkA/XGW5UIprW2cuGQYyY4BqEpK8YyRTXWMXv27vFcYAzvZ -OC/+mfJpfA65x3KMQhVgz4nPWbjj7Wk6v86Jgyc+j6BTbzyyHPY9yqJ8jOgRKJ1C -czdqQxkunpOuJ5cfc/VtiQIzBBABCAAdFiEEW+9VYpCBAvtWcnt8xS16/oXyVQkF -Amegz/QACgkQxS16/oXyVQmbYQ//eB7j+D+T5nOujndQVNAvnRLtZVwDMtfzGgsu -2hVF//m7nqrpEhRXyFJzTCg/dWylgVIcSRKqJ4RgTbNLkNLI1f0crdlxXW9Se/HG -mTaHTGYtbk6S5dCmDI9gCXY4HpeOIFMVK5BpeXr4jGHAmEc8cKpyzSOAIduhTR2y -hU/2rLgWCRVwGyely2j12tYIq0WLeg2m4ctN5epyffEu3pS5zT0wK012PKYymqHC -FuzKFCQkjwmC73UNpVe2bWi7KiDW244prcgJlgSv/MQsR/QiUuIjMNGjsrKrns/J -9b5yY3A9jrKWL46H2rBUdmNYunShTgZc8fSTZzdw1B0KCkzxr+XnsTkXcFMnKnrT -7ex/tO42j8TF9Q7L+CuxtGb6ETnM7kFGi6UMN76sj2uPHk9evjsuLHCMLOFKFIXa -FtkTE+OFUYvIBWEtQl9WBWMF2uihHZp9xh3IqLdAj88cDY1TeQ7c/hsKHbv/0t9E -nO7bK0hL5R6FA70xmx/Y8xRXGlvkANtTsmTS7TL+mlo+bQAQ2i/+apgvMUSzILxB -Zu6XGVUCDsdE0cjIeZY7Sce2YgN4cwCIzNBZmH5Yx7lGVYnHRfbOL+xQydhAmk0L -5JyU1sLZiMDEaEAk83e6N3vO+OhADYjgoeAWi13ZvjDbCQFdCnSQlZKetyUy8N2c -XMJLUla0NUtyenlzenRvZiBXaWxjenluc2tpIDxrcnp5c3p0b2Yud2lsY3p5bnNr -aUBsaW51eC5jb20+iQIzBBMBCAAnBQJZ1pFtCRB8ZHaNPeM05wIbAwIZAQULAgkN -AwQVCAkKBRYDAQIAAAASOxAAoQThfcM7JNSjFEzT6ChTAyZUVbzzh67a2Rv10IV0 -8k3UtK+48eT1WnMDDtho4Bovb3npWCcx1J/QPxu2V9gEQ9Zh5mXItLXZ66fQTEs0 -bgbTLfbC7SvxirB9vX+fWVSdKMSh1rw6vISz0DP3BBWoGO8Cx9mJ74cBPP+Oremd -2yipOhYbTCUO6tRSNteUV0hNVfxAmp9irfPmUOCFFVIFv0CL2qRXtqOeTmO14Ja1 -gqrEKMb5yigGjZqbwkCt4zorRy0wgFzwgD44ZNcwNLZoH4qIg3aEqwxiXfLqoBrk -CsjkvFIa0h6xnP5KaEnC1DdgFNJDK2tVD2Yxqj9NfVDW56xVBauZ5ZnvfleMR7hK -JYUDrYt4xdgnhzK4FUb15PHdqnxlnja2qc9jgRGLiucOqh2DOQZNxAKf1PIkNfPX -NbNGVNLz/vAO5izLdZwtY3fFNzII1j92/a9ZbDHFndyxXA+hO+gziu7O4GIBQ2Vy -5zzOmH117cm2uKiMwY3xmSy7OvrmZrm/jxTXvhk17CznSumHJFzFn6VcfnOmqTrx -SpBKN1obkdF8o6S7Unv5rMsogBaKm2tYYF2VOgZxz5oCq3e8hoxMYcMhgn2W9WVa -UedeAGQiGh/x/SVlOJipHrzKNxLCEDaUpCm0AVgiZ3RHMzrjBkkxVfJ8T0QWg4Fj -S6CJAk0EEwEIADcCGwMFCwIJDQMEFQgJCgUWAwECAAIeAQIXgBYhBBLSfV2Mjpvx -qrx8fHxkdo094zTnBQJcffTCAAoJEHxkdo094zTnGpgQAKpdRlZgbYTT/rBEhcDc -1Az9NJfbWkGZaGRJxY5R/JZb57rttLbB5kyuR3BFxYoJnaZ9+mdyREBDfJf4gCiY -zUqzbq95/Kg/jKawDmkxzaFwNs6l2f4Ir7YPguohRm5IM1gL+k94j5u883ongY/2 -NBkfiLoXfbibD5LLC8Aplgl0+8sikpSvP4eHu8J9GdNpN/wTjil4Sh4DLNY641qz -tE20wT/DHb8fk9dI6CXJyx5TAzPhpc2RZZfN/1xCzB1PDEbP8Pbxgch2mlIPpCvb -7ZOvVxrmvNJYTeH4i4luGwdjDMoFCG8C5nV1zc0yRZTRo+h0K6Qv6K3z9mDVQPG1 -Vr3obPmqao5cgTE23v8IX0rBsfr/cqF91HbVg2oJDsIZLYNJR+zM9EhHu4eM8lj4 -7SpaKcVEEvTLwlU6oXYJU/bV93MO/geTLLL0aWpAP1pmrsMJea7jgDaiqdRP+LCS -oyjdeapkPkmJJxHVN0kufOUEG2EENng9DOc+AkRdd5L2BtGrA7DneYzZKalwkqOA -qSLnvsB+esDz4rPaBL3ijpdPgGjZCWa1UUcbqgD+YCLZnHccqFAYSMkzy7JjkPlI -1UvvQBcfNjNmEiZf5SL/9XcVCKWr8ObM/NapF9jf1SdoqZgRTjk2QWxOnigjJdDX -EtAbeiVCGF43oHKn0AJTFiOxiQJQBBMBCAA6AhsDBQsCCQ0DBBUICQoFFgMBAgAC -HgECF4AWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCWdaRbQIZAQAKCRB8ZHaNPeM0 -58pyEACD1uJgIT6/BOXsfHfbm/TcXGJdiOj4jJoIlDZV6Olvz1qAd0PDZO+zr3Q+ -q8wfxXyeJ5iDdc8gbgwMxzzMNaEVg9JNHtHoyPZVUiX5yxsW2Vo+J8KUBFgJNrLu -xZx2ue06q0tRLFq3BD8vPBSJ/QDcELUN/9U/DxWDE9jdp93HdpyLYX5vGknzWiME -rjdk1r3CSng4OJ1+SWEe8+n3Ord6TmrRkFZMG/gJqb09KJQF1Y7+QG72InYi9Kvj -ZFOEWSynSrZnN801jPAZv3cmN4AZRbJC6YhxMM9pY0T8Z2Koxyo55qO+6enMrKpw -deb/u5zLg7lK7ONokGDjt7f5O5/f9aMEaCTDEih5e1R2SkX1K0cCjGpxEzmbJivy -U7ZtKYAc7TPeGTbEO7bZNiHPdSpOXUs0KItWZgj4UuG3NysdcddF76qts5xoKkKd -w86+nWqbjyVu1j1vJrIWlzjDkrCKZPBcSXO5u4KNdswugboj/TdZnIfdjyc81MSL -Jln4MaRfvHBZDAgEWKDvnEqNVq3oMsHCIj2ZIXr5vSW4iMv+x8ihH/+Fne5T3XSp -GYoxhCEOIBgxcCMxz5ItuKQpzPbid8PfsKudXUD2WoGEPM/iT1fTn+cV/DhVFfA3 -3ois7jThCaQCY6387mnb+Y+iHVVpTVYlSTdFG+FL6Gs71jIheIkCMwQQAQoAHRYh -BIDHu5fuYfYZ8XbJ7lmIoMA60/r8BQJjd+oeAAoJEFmIoMA60/r8u9wP/jsIbAFf -nz0PJdOm0qF0D7bU2LP5b5SVSVXvVnarZtChsKm5FGMWEcdkOrYBO85kqJu86DmZ -9pqAOpaw+XO/GkZKpv8bTsS4livf9ErM/yIyxxbnhIat+dWldSXy7VPKd7ipyeZU -xF68Y5eF0/wh9XROTECK4tYvv0XoY8r7Svw6XfrEO0eseLT20Adzu0es5x+6t6/H -QgbmLYVCk5jHTdyfzJ+WMU00ltWa7/tYzHRk1iLmWuqMJPt+x84Vs9gZ5lmHV/zH -VkBiW4PSbino5PM+//jXxX0eX+2UVF7MEbz4FkqzbNEZv0SFKPVJJgjrc2D4ImJ0 -d4E7q4YPImaA3lWhpOuuNXEhBEBqjnIR6CXoyeWsaMNPWQZ+cDto6gM4b+JerGqV -82ChiR87U7QNlLbDkEdbyJF1eeMxa9MH9utLVSKNRBwB+5hW6Lh8w0LYG95j8G/o -QaYHcry5o9ajtQUqWVLkqRlppBEaAEj3YkzsVKZ2pU8qijl2jgc+AFh6+o+hwuNk -29uPCLX3emskNoWGjiytmT2HtqE37VOS4bT8jLXyB97E7eJA0drsljU008vkwZ1Y -is52/3xremIG0izAlpSv0zpZ5fnRjUsm2Qd92WYHm2mgBXeD3p71B7kYLDpXSvb6 -XSxscO40JmdAqfo52qZuZ/Bys7sotgNij2g3iQIzBBABCgAdFiEEqUDUNJksLo6Z -ED1QIk+n58yCpmQFAmN/UtUACgkQIk+n58yCpmSNnBAAg9TOC1KX8oI1TnLw6zls -/GkKOjao/TL0Q3Uah6pl0HIAVfZNgEYNGPHyadeC4zSJR8ZBioJmNkHLF+jJuBTW -ZV/rTnJ5QYC1nbyfW/I2m8FC2D4TJ0z+7iLGEN7VDz13D6+iqfT49T5IrNxfsM2G -3utj33LbtP8z0rA5zLg20p6Dl0eHvrotZhRfgrOr0wRECgPGmdl7w2FrgwGPh+Bd -s1iLKPWNaTk5NR9uA4uVyrOQWYKZuow4Yd13mw7RTLO2fuO9WkileOnKC+JgQOrm -SC3KIO2gdD/3P9ouOvSRVQrgw/x1t4BJvAfi5MJgdTG2y+CP1tl/PKGrWvnKIzT9 -XDKIi5EDU1qHpc/StlFGx3RXmPgQ+eDShlcN6wvcEQlvzSfrRIlrRrhE7SQDclBx -+jSC0q0mtoRRm3cprPqkws/FouRAfTWFGf6K4KElA1AO2zU5k0Bt7Gct7XVCfWVw -QVrXkLTZioOw57bQjbKstlFMyO4HCQ4xbywG6vvHfqU6UXhEkrqv4HkxuswPxPa/ -WNE7BONbj6fwzdNpmcvXdcr39TZV0Cp4MPkyw8lkx57aYEYwz/w8lSpG0JrXyTBG -Mukhg9ucbQhGFqjr51M9GvqvkjHd64KZuHhgKlZy2b/I/cGSyoIg5MrMZsEG1f1B -XyRtiz7VP5D8ztlGJhH/suqJAjMEEAEKAB0WIQRXDmMrk0YTEHNqe2+CizmmotE2 -fwUCY4COLQAKCRCCizmmotE2f2h1EAC2/bjb/8AXGBFO23GFBozJ17on1ni6hEGC -2QRcwX7lK15pqqea7JkLSi4ddGqT4Ra1u4H9yXf384KTutItDE7RUFy4gDnjJv0i -n0PAyKTpVeevgePYQWUROyT7fYXWA44DLlfUhqgst2Ieh6+VHocWxlHWgHtLtbN1 -C9bQp8PPm62E4AiMzIM0FlgKSRksQiiOV2nlQfTcbCugMhsay7qd3fsbq1zWUDP5 -NDS7NOs4EI6EelLjOa4QEzwSmX7Z8klCR4Q4F6Tdxo34l7fjsQgsSs2Z+w3LlLWz -fL2Od+/tM5EiI316bpL2rqmsRKHRKM0X+VZqE/ujl6vnnJn8RKrDp7mN/WIJWzPk -DkMlyNGTw/GwHzrI9MMPcRMBcFJfRvNGDG0dh4y8iwc/mTz6AlYktYwf7Bb1kdm9 -LetDjoxMnBeCqbFvjWjotOACL3Lwwzr6brIhGUS9temlZGihpqMfkLjcCo3URuhc -6FDV2qFeXihflydbNXEWkDY2s0Z+enrJ+DwIBLAv7CZxTvQmdPp/jo2XWT+qku5t -065RnRxztIP5weIvmmyPW4xBGsvOVsJbmaKlINHSI/cJHbLppXjd2cXUKNlowuKf -lg69xSVNe0emNEf9XRtvM6hKPgP9gS0PC2aox98uIMukW0o60FmejL4IHKM6QCjN -ismU2XCogIkCMwQQAQoAHRYhBJvQfg4MUfjVlne3VBuTQ307QWKbBQJjiHvpAAoJ -EBuTQ307QWKbpy0P/3hZuR5rBIQpjC1Z4CN0PEI4vVey2QxBQ9xsgEHCf3cnEGbW -rsPAI9ztt7ak/eaNuK8PQ8ThVw+Yj7UevUw0LdipLxVeTTn2ytNsKdUJlLLcQlnf -dwrCb0k/9oFgas7hFqJqzIW0JPcPLJOyzWT3mqG4/0+yYlfenk5SIN4sGqR5WO8E -nS5P9WgE2I5yViU5vytzQyHeMyi89Z5p6Rnf/4DdnAubnzAtV01FfZ3pkwrCJrJu -v5oW0yO6/QcNf898SmjoGhKojkCJ7n6bk+L9hmOjqcamJP2TqbTJWnthIzAcaDAn -wwFGUdOqMCcaFAXPIBuukePzyEdwCcVYzZEbMfObOuQdtTUdvAFPg4weqxJRmCip -SUH+zrIIKmhkH7VxpU5QmGmvR6BmuZm0+Pshx2U1Pr3SwGnNqH4iVLgSOXY4deHV -hvpUDxnqpH+a9Ycmo/zgdF6s84LSESEp7SS1aOtxPTXl9aT5Xif/AtYAFoHw/5mm -7sCk9Z1Y/LXGj38lqUvTxdIOOvXWOb5ASkeJsVG2uYOLPUEOK2fDMHw6czwGkILP -XcirrUNp4TxuRtQ35Rq37/JGIPWCcgVy+XX5j0JQyQqJqORCXdobW6s0uQnm7e0V -8UcwkY44OvESXhoGoRbzpoVoRIzCX8tSyKGRnJ11XJNihMeTUjNGxD4GBudQiHUE -EBYKAB0WIQTR9fu1npxgoBF1QFgHK8J5kq4eLgUCZ1F2FAAKCRAHK8J5kq4eLq26 -AQD8LRspmhbTVbkjZYTmKa/2g56yhB4zNfLi4DQw/zm/BwEAgw+6giVE8Hf+gQ7q -6Sz+aSEkdC/VXa2kWAIzXzVNBwOJAjMEEAEIAB0WIQRb71VikIEC+1Zye3zFLXr+ -hfJVCQUCZ6DP9AAKCRDFLXr+hfJVCa37D/9A/dAQIORCjUhu9S55DGrjtbDzukvK -tK9nMz59GTzyUhBjIuIG+vVe3e3IQ3ocLLscBSTfkq7LDdDvhalZFpVKZUg4uaQO -9t62oGmnyRcGuuaBeRPxE7TKFOEPwI5wQ16qgTPXgTDtIBJFqfbImlVtvjS4vksF -9VKNzQH3XCHbcyfE6BVQtvWbj4wwGq98IxELfL19PM1fbwXULlHaPJwAWereVtx1 -z8aK1vZPT4KILYbWipqxFSF2ibSeprETPqianXtqKH22nX/29zFzk2H7lugNxxME -zdK0yrjdTx9+k0oI0EaKmHrC+sPQx0gpVx6Ac7auyiQGyAl0WEZlV+Bz8je7/bwb -6n5bn/PACChfKyC5Z+q1v3WPr35P7anSsQH2544Vz+hpKALr2eZux937zGKLxlTx -OcNgWe6oK3CamZYXvhyM0ivTs4PJyfjT4pw1mPkQIWmNYzRaFxri09QFiFRHNe0x -nEIGGIJ3yZWqXjemR1OZbYcCPJSeHPTNFvFR/pJP0pFg3W6HoPC3gNtv/hscdw1/ -4xkCHe7LcpWllqxGzs6vEmXysTHNmHXl8dleGkm9ZSbEiJ7czTN0JFxkhvgb8/et -uX8trdciUVvlLz3FQ++6MLLAo3UdMusp7/AVlFsDlWTzdQ3StWMT15lsJCKo2VUN -H40H8vY9Nie4rLQuS3J6eXN6dG9mIFdpbGN6eW5za2kgPGt3aWxjenluc2tpQHRl -bmFibGUuY29tPokCNgQwAQgAIBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJiEdug -Ah0gAAoJEHxkdo094zTnDDUP/R1x2d4qyOqWIRLHkDD8JI9nBgzfmJbVn48YaK0M -DUN6/B7yn8ygo/RXX/+oofp/Qs6GB7naeCZnjl5wuEZHAXwlho++1tBmY/tQ0/1r -UIv3YT/k82fLsYYea9VB54GJGz98njjjp6aLgW9GAMxBWl2HsqEkQU6W3RIiu9+v -e3pKbDlYl8F+SIopZ0gUKHLmIeQpdG8pfEKWmuNeBC53ycOJICZIFnNCHC1MUe3N -T24DWOkyUBSj3sm82hDkGUK9rSkZWTDjbCdMqPKRoJEgKqIGQSMSHAy0HR80+yub -Jqa9aRoVC2miireSmnqEHGPdH4KDl6mMwNjJjoQnJXKZmZTjVbRrCdWc6R46vrWr -0AJSvn3jwunztiCpC4WNj0eKg359jCFDT4cw4VnGDRgl0B6QZ7xQqDKoUXgzLVUF -VHFqbAh1QnHJQYfL0Njs3/0wKLbIBpoV2hOre4FXR0KByub2vMnL1xRzbZrmxbXd -aHMnDE33BuzfCBwucZN4Y1VjE5l5DauJFZgnH7d96yjdpEvs7hqe1SMXBG0GQ5/S -yoE6nU4ZKrzy7h4y/2mMBXboawJbE3WSc5xanaRt+gIYNP6JXG9u3kYgwU1BdhZT -/DLIes9sl4Vj1FGwD1b5lOy9hSSW1wzRFH+Z6JDC0P24lAEkpjwqOtLQ3vyDoGsN -G5pWiQJNBBMBCAA3FiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAltDhGUCGwMFCwIJ -DQMEFQgJCgUWAwECAAIeAQIXgAAKCRB8ZHaNPeM05zmREACll76il9HOM+okUD7l -GQR5Y7M/29WksUJtySyw8pG4gpXEe/wBm/5rVPZoPWpTHL/lt0Wp367WNBAP7Idw -k6EEv++YOC+PrnoQs9tkRuIXbeXryKPcqBkCUq/kpgs6AorEi4bO1Z0MDwfus6xK -0nWkxCWDNJoQRflChlAnR9M1nmlc5D63Mg7lw0WbfH6297afK5leME6eDIYrW0En -YcgOaqVPS81epKwtld2X9lZTCUyRVcUt0dKc5Nl42sZ+Gas7snOjBQkyTrJ1v318 -OF8PPGe7wlsYXj8oMuCiCyU1J3GEVqJjAa6KnvfI5j0qFSkMfYG/5yF6MXBQihrF -0F9dE3Bsib3bQlNwCBXjVGUqmdDedrv1OJgU607AHhyvqCwa9eH3ItgPpa0YA8Hy -Nn58pRmfD86QzxYTprGtfI38CueKs+VBYlwEtnrM0/ly+mqmwk4adNs603V/Qhp2 -mBRJhC+o4AzC+VF/zLFsOU4q0vSa8G6GWQvsrWcgTpZvMHR2yP0wWOtEa7J3HXYG -fBodP5V+6vutge4njtznASG1itLcaPZl6Fqmi24Y6UZAcYwRS0ZgadIa1sszUAX6 -n6TvD3Dsh22XAQFkdgQKy+bTkGGn8Y3zTCBzv4F0PoDPkBtiQtUbJ6iJQ0KBY2WL -vciyr8s5HShRReHx51hgzfJemLQqS3J6eXN6dG9mIFdpbGN6eW5za2kgPGt3aWxj -enluc2tpQG9seC5jb20+iQI2BDABCAAgFiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcF -AmIR2+8CHSAACgkQfGR2jT3jNOeYNw/+Jm6GxONsYxTGYmDikveHSgEjGJOnQ20X -tM8UFVGuCZCZuAOCxMzspJtku1ykZ/EZnp1HKApgS98Q5LrQabcOlMHHxSew7oGw -4AKNNL6s+gSrZIAAjLxe1QkNKZS5NCIrGYYX/DrfXkCx0O92P0XzzCY73hpoLQc0 -zWADRbEpBqexjhu8mbnVzlZPzvNBON9EVBJLuX+WGiXjY2XAEqMOIX1jk9fQrgS3 -uQ9M8ecgl13ClnAjUtvuD8/tSBil8t0cqmfevK7mHhemM8fG2AwQuGbB7pGZvVKG -pI4VrtWD4OvvL28MHF6uHCF0w+2qjJyyi53jlG46v0VDuZr8YMR+5Vus9kQMPTAh -oa6t0bATiLjxOwhn6/Ho6CQpjpLhiCvo3N28cz2ud6jeJ9D1nv6TstBLJp939r4i -5OLmp1w9N0PJ+TYevt9zyvtUth4u76brMCMQ11gdUhntKekrUJ0vjOQUGxDDMc6Y -2XtzJa4Mhs/NE3P+Od4JGbCsNCEzf619jbBKgYfsFZEYZFDVvRhy1Z/Zjqw8Qk3V -3P/43cgcRUUtEboV3tkI1wbK/rdS90poGoTaI/yDsB87LUdZ5iH9b+2c3C/HnCFU -t3213DRDJe7KFoST+Zkx7RYhHKerYdgMnFzBA33d+JxPvm8BUXobbqfNC0eZzUxa -nmRGV2xOT1GJAk0EEwEIADcWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCWddTiAIb -AwULAgkNAwQVCAkKBRYDAQIAAh4BAheAAAoJEHxkdo094zTnK3MP/jWaCu13OG7R -XfNwpjKvfPPF3WJxMO4RaGOysAhw7bPSwHqIE+/lUITbQe6v/3J2rOMFT3fVHdxz -5zBX4F6qh7k9SV3UaHMfNzXYq5MAc+r/5P7edgQo76dc8dVlRhUQu0rxoUm3WOeR -vy4HG7SHlD7gEOv9WjWc+YLGe5IBY2GLwMUxBO6i2RlRp3hg50X4kSPN2ds3Rj+d -cT/V5FugNArvn5pvenuNSEXs+dbmXMnUS6Gt8LylRuOZb8CTeB6+0B0OSXcOAY9Y -HtuaLAkD1jsXltTEQ5/DsrIbn3IxCF62VsERjNRjlgoLzLbrj+ejEAJxg/dzLRFQ -pDC85amJtaP3dngo57eMzObkN6XnFMenpPUCtM1lYhtI9cWvuVML5g8M9yLGY5O9 -6D4JMEfu4dg3+cYiEuXI8vYNvs/JGBt+P33weDsAWWXmzwIHR0YeHVlgVKPUxNOz -cGuZOPAdyuKUHSzOqaf14fxJ16UHQ7spj3ejYt0VvHkzbTI+4GR89Toj97I8S+7E -YeX4QqyWwM9R46qL3xlbW4iRZhJNyVN+aaN0NaJlsaVRPuE/eHaEM8TjnyVIfLF6 -dPlabcvDiUdYvD8zeiTN1p9+p/u821VHezcGe8Utdz3XcPZgZSenIlvfcyrAu2Vp -DQPeEecoyYL9okzK/Eoz8CkPVYfFN6lstC1Lcnp5c3p0b2YgV2lsY3p5bnNraSA8 -a3dpbGN6eW5za2lAam95ZW50LmNvbT6JAjYEMAEIACAWIQQS0n1djI6b8aq8fHx8 -ZHaNPeM05wUCYhHb7wIdIAAKCRB8ZHaNPeM05xoJEACTtC08IBgTi6I+X3LV505K -d/O0bic31KuM+TnyCaqZ7pKirWOG2GvEmYLWnaK8u6Vd/bKJbD9eUj7Iwgzm6J+N -BY54aSJUJJmfSxSCrupD1dHt/tcVqyEOFJSzvPYEq8wmOZa5Ch55g5joHcVtb+yJ -5N+2rsEGpAMuNk1K+FuEUtDJblf2U6gSSNjPo/taLHSERh9WSsU1cMEiG5/3cj6s -gCldS23GmEtqo6g7OY4JwBX6PR8EaSQXOpIJVyHbmzg0A04/1eAdZBscU7kakO17 -NGNC2rIhS93c2Nsukqp3uOVWUaVV8U/X5nR4g9xsPorQGMKsgKMbphlwCB9H4Ub0 -bjuU1FysG1thzo14gchohUKNOWikgzxry57Du5epJv91B7LM6diClj9oBvtfJFDM -BdsSDoBcf8gZx3yVgnL288sxP1f+KcdBOlu63jY8TZ7ZDKLsuX0PCnPT7Is3Drmm -IjffOR3WJNzT6aUFm5qId0J9lkm9u3uhkOht+r4G1mHwcg2Og45O5IvqS71P4cwZ -/LTCtAWkR6vGUGvQmQC+vgKoEwGPblIRQpFgmg6+PJHesJfjX+fLuLdZZl5AN85I -CSS79vVm9UvdzrVtOY34RghBKOnb74oWHxkYXVoFwdfHlogZ/BuMYsY01QWXGBbQ -mFmwHTjRKFcb12v0/Wfi4okCTQQTAQgANxYhBBLSfV2Mjpvxqrx8fHxkdo094zTn -BQJaq8tkAhsDBQsCCQ0DBBUICQoFFgMBAgACHgECF4AACgkQfGR2jT3jNOdqHg// -SBImGRPrzFfl8zL9AB8mKOrJBn7r/pe+F9Zg+rU0zk2+wkiDUioNV7rzNgRYjmhg -L6/oWGM+D7ZK2p28RaG/6eEurZSKhL7qyDlanDHri1h7fyC4OxHJIT85NETEs+Js -T0iJo1SLqGXtfymhz0zBiK1g/iENGAER97WKlCyvHFx4yH/Va+pVbObrmLRlH1Ew -ehrt3ebBJYnol0b7r1zrJWjEnv/TqLuzNiDdcMClqbfowqWPhhhlq+EBAexT5nWD -zBK4dA+qKdMC1gUv+uvyfSA09cOl4KYUXWsU8tKwWs72mS+QkZ7jSu213bHiEeTR -UjfEr5uSfssM861vB3hfHxlnJTSM3Cm+8luhBD/imSC8U3aDyBbCQt/UxATfyV5s -37+ol6abupymqsfas8rpONpZfpqSw1kpCBiEx86Vd1s+Tf7CALlcIyZWbGXWPluZ -g5aO/hCvrZFe3/0jYn3nJUYQAO7CuTFY3lLLkfhPwTAk+9yaJviVDJNxNWKQhe/q -INDwiIwSVKsX3Fg+2v+FUSAVDGC16syfuD+CFD0NE8RkvrsZysuNlBKRJhZB9OmP -pPcz6aTlC6P0B75ovkE9COloT18zcGuoiN150fW/WP/e2OyMum2q0v68MRmcXAco -r20DeaGJMvWpw5Jn00SqKKD/PAUcfGUK1sCTNDhziFa0M0tyenlzenRvZiBXaWxj -enluc2tpIDxrcnp5c3p0b2Yud2lsY3p5bnNraUBvbHguY29tPokCNgQwAQgAIBYh -BBLSfV2Mjpvxqrx8fHxkdo094zTnBQJiEdvvAh0gAAoJEHxkdo094zTnUcoP/3CO -c6IKAOWX4Z1JjngrGOUZlZffyng+g1ETKrfJCsyGZRSMWciHxmHb4X9g9pk8dcuX -BA+2rk9Z2Q+akJ9qXZozGILast3RDlKF4ANAiSBFwvTpMQ4O+cnX76BQ+YbmQIBW -jAzC+7oJl+i5fHhuHenxVladXG8j4hrtk9zr/i5ViqkzxoFh7/z0T+FEpT5QUa/g -V1RUXMqj6qGSp+fkfDQdIhl5YmDxah2zUu6Vf/THpn8zk3PARgprWndPxIxvSwkf -9RHZcdGAQhQ8rEyLNDsILkvzfFBpKNR9sRMi+/TFyOBmSXmVSv9O7l9ZoGTydm7U -4KH6a3mP6oUneDax9zpd8EDzv33S8j3dD/P+fBvPNr17nzlsUqRV0GoipvhvM0Rp -m0GxgWUMwEGNqMNyPMt4R6G1FycnTW5/YxrVgU3+z4UzWLETlFuc8s9tIKLtiR2W -Zdz7g+5lWyRkND8LN9rojgXkvTvN23ezeg11VCyADbzXJw4xh/mRtRH3oQl3Za7z -7z3Fix4A3G01eSrtx/qagn681wTJIJoZ9pnrRG80P991AGtgLlTXuA3Zy3xcznc9 -lrkTzHE+NvoZjLZrFW0RT1k7YQ+gbUYd6Y/E1uCg5UBlB461m6der7R3vK3CwRwc -9g5mRKB7GgIGJabn75kxT2h3pttLMWcS7WycDNRriQJNBBMBCAA3FiEEEtJ9XYyO -m/GqvHx8fGR2jT3jNOcFAlnXU3sCGwMFCwIJDQMEFQgJCgUWAwECAAIeAQIXgAAK -CRB8ZHaNPeM0559yD/9iQU7Z3NL0oiP2NcAHEtbd7dfiv1YqlD21DhtUipORGNJs -fFNA7POMLwM34BazoLTTeG+dk0NdKk/DzX8k66zt2qr3ss1HtojKgfZdnK+gCPZ9 -YNI2Qb3UW6qilIXNAUUTqvK42vHTgjzhplVpQizRFfv0qfYq1QJtiGZKCC4FRUN9 -AQYWGvqCt4gIq4xPyXm5uLhDl2Q5NtrMmBy7fIvuwZvkyp26irPEL5JFJhKVWL2E -B1xsKq3Z/BtvxPwSsqOFWaMwn+Maq+jLxID69eMviuGBrJVNltX6rIv/ZDABvifh -opQ2sDVLkQYNMmV8dBFmbCOzkjo5aX7O1LHbiyu4XXHRqLEDsHqHh8YfQeyexKB9 -pgeViyJKjKXD1kg45KTqe2zerMhgRMYmnC/BXViyhZyWu5EGhSZVEqY/cSLrJRcW -WDa4ySKVU2bJHJuxk3SjAF65FFl2XsTjCpP2dNOJ0H60VDC0dsyE7KX7fGshIU88 -qmxdUrHIN9x7ZYUR+y/MpmUDbxdrQnEcTM1HU+XWbN1aA5ETnanTkKDUTOTb13zw -gvogzg2O5MIkdZuYRtyjJJFuTUbVhIsnxMMSxaF830WIhyk+WqFplRY45i0Wp6W2 -uTIeVU4LAZNNl94HH61hXGaiAd92bAOrv3l+UjdLUXELRqyHvpJCNEeiSmONUrQ2 -S3J6eXN6dG9mIFdpbGN6eW5za2kgPGtyenlzenRvZi53aWxjenluc2tpQGpveWVu -dC5jb20+iQI2BDABCAAgFiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAmIR2+8CHSAA -CgkQfGR2jT3jNOdWTw//dVwiKToZ++HOYgVTSkEDx1Sztfj0NJqS0rQ4406Sr2On -kjQdf6KiN58bi3GeEBLXNoppn3cWkf8pHF7Bb7JnEibIXvixrRpfo83yEEL+MZiH -dqxa4TbT3DV+uaLuFuxOuP6DBTox3naCOWHEzaZjFKhqNBALtMtHeHn0PztAEZIF -OziezIAoqWd+uDmfxW2ICK6DtffZlRPLVwTmXlO0xGFN4VzwRJvg54EAih89/wj5 -KFIHe3anTgu3gV4ehnUHb5MoyvCyf/rId3KtSK+WDFzV3jiLkAx4CvhSKzcEOhgT -bSVoKw/E9ps9rDtppkf96eQ9OxlJiJXEcc/EvCUoyqkFpBhYR+ZuQivAFr3wPkPe -GdlG3NhEuipO5iftcyTO5Z+6BxJf1De63noXfsS2sZBNdEUDIUKVZwLRurQbCJno -bbMHhvgGVKceVPgu2vAHDYowPH7E1ovmXT7L+f6kTihW5WSc64bGfAEdhhSbWQHB -Y0mgK72AXtd5t/hqiYI7L13Fnf57H1QFNi8lj6RpEZJSfXCk+69piYHQicbEUBUT -hKjPENuLOIsocTk1cDhVBJltlixG7IV+0mByKbLaKFwQavxC8VDeRvtqYJMvMGGi -7yS06uy7p1cypKA9oocIU0Q05QoMXQJ9fsb6RuAvShxGue/74caU4+3fPAWozlWJ -Ak0EEwEIADcWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCWqvLHQIbAwULAgkNAwQV -CAkKBRYDAQIAAh4BAheAAAoJEHxkdo094zTn40gP/2osZAq2QQBBofm8paAxKkee -WefhUtknT4EJ2PAjRJd+jn2lcXRyn7S7XvWpxGsw2wCk8B6kZP57nPrQh4yRrEN1 -9kGQMqi1ZvtVE+cMFJsX84i8ZP++B8ox5fP+I4ChMXrh0yAmQPDvI9gzT8CV3bNR -oFM7xzrb4TYa8xLj7iWgq/NOhdBlZqno5JgC9qbgKBaFeUBEk/naOWJB247zpPU4 -rfZmvhf6oL0xQfzKZMdmqobgpKYWx8UkYjsjoAsi1VTTGYCowCGfQizVuNk8JeZD -1XZI+0+J0fmvf5unZqn3Oh1fjSzBN1spiFfXfbWgGN3NG3kKXBoTQCguTEas7RXz -WxsZQfdPmNFM8lE7Itu2YgQ8FB1nDtlFwKQhkfSyzHwqeyHVZAZ33X2yENNKo/Ku -zG09VYazDOJKwnY0fdOuOlQHxMuTlM5ka9xcHh+HKEiTjx6DzP1b0W+oHxwB1W/v -VelG2OvYihaLw3Izb8i46NFv3DLpqHcKu+TjUiXMuxWbcG/XeqGuxBhU4KowVtg2 -QxlPrKWYE2zs1pGstDEG4JgbXkdpGsxCkjPf0pYQ5b4kSi36iiTt/zbP93r4VPEK -E4nkvuqz2iYN86yq0/okXcUAW0SL+r3Gr51xE+FYGnnPk10Lu3TkVfAiII+Np2K6 -zHxzu/ZJjus4L+Zn9MXhtDZLcnp5c3p0b2YgV2lsY3p5bnNraSA8a3J6eXN6dG9m -LndpbGN6eW5za2lAZWxhc3RpYy5jbz6JAjYEMAEIACAWIQQS0n1djI6b8aq8fHx8 -ZHaNPeM05wUCYhHb8AIdIAAKCRB8ZHaNPeM056pQD/9mYakRWdxq8f7+x7rLXkzZ -S1gpXTH1CMx+1RzKvFRimz68f4GwzTB1u3i1APkTYLuURzsf0F+u374IuKhD/CRP -PjD0d/+5nl0RZR291IjO+NpDEwg7+P0DzBeuhPtNFTsqF91D1POpmLFi6Y8FkUbI -pRJhxYjL+KgqynB4tcnKUj0ugVk/+UJ3Z2xFB8ilvYcxwRF9UZ2pXImnJAbHlBhW -irfRnOV2PJVyIJL4aVj2D7qB1TCPtU/jwCZyzNSj22CkwYmv8iVMFzZx3dLi8yRk -zU3KTQra9B4pZ75k07ii7rMXmqJBubd8A6yEvyZgFRolyydw2E/UxGhjEmnXKTFw -LrHFSptMXM6813Z6RHdCbz+AyzBs+CvRBbfcSP8sHWho9oCfyyVnHJQt9jdMyR9M -LT5wy1wC3Q6IWhj9+6nCBSz0KJpUy2Scn0uWtY8KbWnhqEB4pgbxVsn7TmOxNSB1 -XuUOGii/0DFvTAcQx91yJRAPuNk+qMXN37i9E1UUF+5yYqwueH+MAGMPpFlmUnS6 -SohB84W3vXOd2WhJiolV7Zs9cDhhMLXSKNkWExiRt0/yzvtfCUmHIhBAedtS3zHt -rHcWamct/TO8MLXmRb6DhU9p9xN4Wk9y1N4Dxdmfw9n6UTPr/3lhdMXvpJrL29Ua -+u+G6qjVLrirMM2ZqKDYk4kCTQQTAQgANxYhBBLSfV2Mjpvxqrx8fHxkdo094zTn -BQJcffSAAhsDBQsCCQ0DBBUICQoFFgMBAgACHgECF4AACgkQfGR2jT3jNOdNGg// -YgRhpKfP2Ls32/i/TYJWMwucg1endcjWBjbj/UT3pT2DziSXhntfxIGKm6owIysd -roh2QJMECLO5sf//x+xjFHdxpXQgaDVqPwvgbB8RX9mCDPQKchr3fFs24+Yp1k2q -jdO2M+P98TFL02vkMCkpuf3+19/75ILPi1vcfCHtslM6Un8sb+/UoAE/JXoMkndo -zDLMtx0uBAcWj0iD3B4WeOGxzOjEnYvY+qA244q2wTU7XZoLJKWdejEmxEz6JOms -0h8QOp1nCq+kJwsP3OjrYjVFPEvJF7KHaQ94sq9Rbo55COET0hm8fa4lVDnTpAn+ -aULTcFY6MQui3BwRrI1veLaovw248xDL78IqIDqKiISAAwTRZJnCnKebEv6QYU28 -O1YZfp3m/1CtlqVF03VJb80Me8Y0N1cmjU1zx9DHEHuzxmmSXMEE41WYmWf0kKG/ -xSK/qzsopel/16RpTalNdYFiVPpIBotoXJMJtH1K4lEl9EnD9qWVYAEQin09sHHV -30r08lLExbIlrnd/MJhT+3nr/4yHq4CZM40MDdSzdJe9OrILXuAkSd+fgelI9uJp -S24SINbFn7JTplFA4DNQRRzloaMsDoJED7OFxA4n39ewtSmoHMlc2n2CTdT+SIdq -GyGBgSVhM3496CfG6RjpXBev9kqcN2eBIE6mlJHi+sy0OUtyenlzenRvZiBXaWxj -enluc2tpIDxrcnp5c3p0b2Yud2lsY3p5bnNraUBub3JkY2xvdWQuY29tPokCNgQw -AQgAIBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJiEdvwAh0gAAoJEHxkdo094zTn -d8cQAJWbuCqBYCEVCRmOrpjQKwyLgqkhde91ijJWy9H8jH7LOICh+mQkJlnV2E1L -eMHXJ/9s8aSpe2lyIQJrK1kKs3AUYVdUr+/X/6u9GeQNwUXOtHr+NBs2v7tUM5r+ -qoKD7a5QnIKJfSS88EpPeDJn4oUYrYLD1mBb+hbJ1vqkn8pLQFgibQl9XL4CvkY/ -Lerw2720aEqA67Q2ijKdAQgM+Nol/I3Yay5LLLrG5tcG95SsCPT1+7bgJ24F2twq -TvAlSoQJOjFOMbo/2TqzInEwp5hIA+cAv58J4O7zjk7YydquKRyJ0QzjfeLFHn7q -qlbuXJWI6IO5L4LKv3UZBVPtYn0wBazYbSei0DfbC9zv/jliIRulXG28G8ee7/py -b5njD9Osh0FonZdhQZqwzqoKb7UtD8by8v91xH/W8WRvUKEUISj4vFfLjza3N0cd -fHls+MtLW9Aw/xtAyF4V7D8WnR5gApb6+YfPSWIMxBz5M6KwM2GN4/QyOgUpDwBc -jylZGOajaTCv96LskASZrals+xWcD1lkldUEJserzu+pqGMGiuYgFvUHx0jiVTCv -dLTm+ET8A9l6+LMalcLD3KwacqGtBUsdUeNhCDeF0IzJdaAWr3pz93Qer1mXH8PI -Te5Nyv21aepcDmXOaw6cJqc4hFDLXYcsFHplMghIgzIT/xNkiQJNBBMBCAA3FiEE -EtJ9XYyOm/GqvHx8fGR2jT3jNOcFAl3AJXsCGwMFCwIJDQMEFQgJCgUWAwECAAIe -AQIXgAAKCRB8ZHaNPeM057+8EACyNP+o3BNsZ9DqdkREHmxZD0Ek+DWBQMpq9ubp -jMef1ACnYhIj/+bzwyw+2FR8avmtzuJ8qGTs80o8tx7Fy1bttrqZnVz8xmNzhLTU -Qp5fVG9FbDFjfIGVZDDLM0WAke1KMrubrmshS8suLXAF6EdfOf0USBfphzf39nON -YPWcFK9pQfXdfwlzJ4aI8r1ecUSilzJ0ch8OpfkIl+Q20AH7IJP/ajcr4lfOX8mz -NG2JuvC2+z0/HdC2p/HXX1WxMz4jzmIkzn4EiP0QeiLfw+t/xr2HHK1sWOcUnJva -t5a3D616Id5qXm5PrhAaDhrmmd+SCZv61P6jB64LxwxVFVvulpyySwaShjE+d1ot -9Hic86JZ9okzrEiPwfDAcwUbkj9KI7+aNL/02BXG1RchZhozxMKmfJR9bBichS+E -Mim1IIBDR/RybnasD2H8kUwDJY2dv0CG/8xLcP79ZJzwfMTy+tyfqurArPEu4v4z -/6moSJ823lGec3w3/JHQPbS0EN+2nUqxwzm46L29t7ojO2y4wmCfhtrFXHcQtmo+ -9l+Y2Afjz8ka1aTpnU16WRU8v50+3wWbGNtCHnzvDYjxA9EgkNEscS9w7e1eb9Y/ -oNbjsmFjmsiW0KZiPBpjT82H1qNgmBCENxsYbCBfgUdvLWkEi+Ahx3i4o01u11k0 -IBfXp7Q5S3J6eXN6dG9mIFdpbGN6eW5za2kgPGtyenlzenRvZi53aWxjenluc2tp -QGxpZ2h0YmVuZC5jb20+iQI2BDABCAAgFiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcF -AmIR2/ACHSAACgkQfGR2jT3jNOcz+BAAjfKKUs8Zehi4/U4xm2nMcgWMAFsL0ie+ -O+WZse1k4jSdVgSS8L9LZfnpJT8jqZWhXXl12f1J7c65itCRzlqxSaEuDC5BidQQ -n4nUU9jd0maGY5W8dczfvXHs/SKU0lSlYhuWWQATSfdUsXxdwhcaAJvLZsE2XpPb -HnelrrvFcRT2L/f9junmMNOXktV07yrridZeWkniaNJKFB2LCuJiaixFDtX7IuKZ -g1+uJqSx3/ujtR9W9obhOZiuEfdSxwq+kvuMObrBJf19ElssU/iGkrpjBCmtTbn3 -lhFuO09i3ZaH8Qc/4vVwbQA7rIEawekZ+8c3IClLbwTGUeMg9f4kqQxOJztloChx -Go7Eig6+HXm82o28mY8SqqFkpBkE8w+n4wCFDyEOMApOKY3X2XnTy6j78T/eDHfi -RrCvnpTYU0FSwe/fa/7KCzXEenyBdyObJs+hQNiS2JqZV85nvgRQP36yr48a2z6f -xjbJ8ga+dk27Y/aFgkDzuy8HQI17tuLmfAVbenP5i2nXxRMVAFhUT0IaQn+b2i5q -ITMLYlMx2CHW7ca7JsfZYsybXOl1EusuSA7MvuFXf2EsMFC/LpgbJSWdoN000PXG -oJWECkLSPPm2+n19ptVSvl0RKRS2Li4HH5R7dJNQ/C12uexpzT07iIFRoH07nCy1 -axIPsKJhsHmJAk0EEwEIADcWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCXoSwqQIb -AwULAgkNAwQVCAkKBRYDAQIAAh4BAheAAAoJEHxkdo094zTnycwP/1jWKxIm+4dE -FoUllomZWe41Uv+rjbkw4IdGMmr8+aoIsqevNILZSQIAZNsYAjafcNXXeiATZBGp -V+peuHz28YefTPHowx5V1iX/1pSQACd2hkgzdVN9j0Eam0sCumoSL5aNFwyMjM8y -kXPa/j8D1sHflPqlM+V//99owurcsRY7NXV9pK3dcfJ7IC5BuYDeAGu3IcPy1pNy -wD7UvV78nfPbbuwrqCGidXHCk6EADACK7J5s+zPjGM6Kk5G7gaWZbs7+ICfUBX5J -/OHP2FxQIJRG3IFFyKw4SxO7i35PtyWErbHdC5Z9OuB1VIbV5sj4Mk0arLVMhppJ -+om9F0WF4lP/h7lYH5J990CfX5lOPDwXEDXhd47bNw2y5jNXEmIfRxzFSFo5g6BA -rqhm4YflLm18zOA2h1NTylW1Qun4rbOxOgts8sYZrzcbFpWrC/CrHkcjcuhUULa8 -7iuyI+0oZAC2Da6cIYA/uQuaKt6bB90wg3woR1+uSrPUOMElmlQ+reJAbJikB/5k -j1Hpg9+jkgw1S4Lojl/opZCj1GMWszlFT0VGK/tCd4XSPP1g0qeuF1Zqqf1dz8Bc -XTY3tpEQILNZiV6+sIu9XSho9JGLrsO56BpwsKONUS08jZ2cNGHsdHz1jRSck9ue -6Ll1KGanegGVyTN1n6OUxrK8f7hXVBbttCdLcnp5c3p0b2YgV2lsY3p5bnNraSA8 -a3dAbGlnaHRiZW5kLmNvbT6JAjYEMAEIACAWIQQS0n1djI6b8aq8fHx8ZHaNPeM0 -5wUCYhHb8AIdIAAKCRB8ZHaNPeM05xoWD/4lPV3P1NoGGSiCh0obbtY2LWeiLEe2 -VRT1DZh2g59AwrY7HWW4jeYxwXO33FkX2VkwpcL0bHg6sExPVuzOq11Ru9YwSvvR -Vi+8e8HDAMuo/nSRdWCbRi9avnk863dpBzlvr4xGOre72Gol7p5VoVHHyJzpWX5X -r0+ESIXKcbzBVDgCviiTC6PZcX36T1GQEhFd+RWceIryKtTiAVTp1fNtt3DPDAsn -0LxQGiEKha3BrdeEFkl4TAA8DDwzYN8Zp6fc0XehS4DlLNowxBbX/7JCCqQem8OF -/tWZ9jpzWAJ2qSd2oA7cP+ESUAAi6TIyU0NeYp/4WStvhDhoREmBkIOfMo0mhdMq -e0xliy48Bgb2nkH9NjCwXNg4FW2QNDykOqrETNU6KJeqM+OHUAmI9xfeIHoLQQF/ -5F6pBFRnJgCJU8djp5szoSu59ujwqzTiYijcL5JyNZGVQjeonc/yUGHVdtcWK3wH -zE/CTh87iwoyKunEkEovDnuBjsBFfLirj63LFwHuJnsh4k93hRCLDuu7aAe5IKK/ -gbFz9Gsa5eH2Nmes2aJk2SOu1TnWI8U+C9iDNKaNexQfrt9WoTUIe8kYHfBdFT7e -HyQe5g1hO6vSReklNBlMX5ZfEXqokCd6GDHrrxd00vV/HiB2vOuNRdCzYy2zO5/H -aNUdVyK8zThVTIkCTQQTAQgANxYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJehLC0 -AhsDBQsCCQ0DBBUICQoFFgMBAgACHgECF4AACgkQfGR2jT3jNOcTpRAAneFlExG5 -/XgmFXMt9l9x/7pFIy++rEYxUyMOsM6auVgynIeUE8wsWE0/w0whvJZFFObPzupN -HUFYRZdxZa32W50/u+5NrdZF+DCeuF5YFdOjbm2Al4Y8jVUd6AesfUep4ETbtAL0 -0KclWx63/DbpTqVrHh5/tMdQq5whr9avo2Jr2tdwzJXmY+uXgzQ4ftV5Idqdf2zK -oJ3E8kuqL2d+xhi2aRmZ/6YzsV6DbBuOVFA9/6Z8m0zqFg9scbQ2SAcNdGZPB8we -baZewXTqsbQEUGF9K2KyLhyPA6+yUrqpj/+T5esaaSJAeea7nhfT5BAcoY+pCsK1 -SVwUU7KTJWFA8iqwzf61AlcgRCFO3H+q/ZmCea7CWyOxg/Tc3rA0y3Nqkx5cnWU2 -R3VPmPfEQM46Omjg5aaeIhvkuQElHE9WvDO7E430MsT7UTSOZkML4QPtnGSK1h4n -VkiFY/Vv8qXdTw8l3jx80boTrdOmsiNub3mhBCZHnXFr1JxuLxPXdJLDclQCIasd -OPP04vb+X6WUyLGOHNhn9Uezu4LrLsdatpARgslkSPpe+n8N7c+YeFCAFm6/X4Ep -SsvfKWd0EtxlcSV6fb+hxuIdsfcehHS47MRw7IVBfiOWklT9IXRbeJoaDfR4zDr+ -5Dbdyikm0hUG6GQ46YJUwFZuNakEEymCX1y0NUtyenlzenRvZiBXaWxjenluc2tp -IDxrcnp5c3p0b2Yud2lsY3p5bnNraUBub2JsOS5jb20+iQI2BDABCAAgFiEEEtJ9 -XYyOm/GqvHx8fGR2jT3jNOcFAmIR2/ACHSAACgkQfGR2jT3jNOeRAA//RO+1NcdR -zcb8zSF3vOHkbgRrdRwtc5aHnwbyJ9zqsOy3z1T6lPx8jcXO6IuTeaVvL/BxnDu6 -IOoEbFZZRhqp9h80heTJ2rsqTF0jMyyFt2+9ZrsudCz8v88Uv2Ms1UW7gGUj2HAD -yjjz40JgKdzh4k0Gvwv6Kun4a0VVMBk62M/ezEoacJ0PhOK2UYHi5kRfvmmOnbDk -I+ZWZnZHVlJOThL6QfsFz89BfEhbR0mn4uaQuoWhXV45TNMRMDcknI/C2MpRr4wW -jgKBHfvntelFKpo5y4P9pulGhcbBMaR2OYiUgZX0f87Zna6N7znSDMFGfIqGO0qG -Vr33ymYLaUJuw2b1N1wpIhvcPOZbPBYpvE5gWB/TKoyXQnMhYUaNo/q8uWC/foL/ -m4TSiH7YPGJW0IKBc+rLFCl4jNDZr3V+7svAJALHel77r8+nFyjkhTl9C21VJYCm -k3DjRfIPic63e85PHlGiAVH248kvoa/sHFA2OnCrLRPS56XyCQf0baArskkB7jjN -cSU3n4+lcoujq2dNqWGn3TklKhKSHRFK3JCMwjcWzK0ro15XK7NpbcnDyD/Xw+8Q -Ru+XbsO9cDnnbsJ4sWU1BCj9nrYpWsAgv1Yj97HJPzbRHQCbuqpw6I6yKzNWW08Q -esacwm9dhiebuLgvrM9X6QXPqG5ooWnmeaKJAk0EEwEIADcWIQQS0n1djI6b8aq8 -fHx8ZHaNPeM05wUCXxhVLQIbAwULAgkNAwQVCAkKBRYDAQIAAh4BAheAAAoJEHxk -do094zTnrPIP/1WfUZURfD4kj/XG4GG9v7fbep7u7NbdREwAQHiH3g4IHq/FyMfq -spRCrubaEphe5/C+sKA+M6SDcOlL31xLBgzj9WQIWFLFk1iWcERdNHE7maduDuz1 -QA3hgW6ulfMw3umVMIaKU8OWwu2OSex8KQg5peys+Ohu30b26huEfhDJUII+m+9C -G/QIpVp3wIu2GEjdzUYinmwh5G6xmqtxmDnNYKA83WDu9KuoWFgkMFbThYMb7Dpf -0wzgVNuUeH6jrAVCBQv3B+aCgvdgR02IS8wbpfEq0j0KlE/i2xhq3XR/Ppgd2aNI -xOGu7XnTF4gOz78WqldmKw7cBVNu6LjXL4KbV3NwPjGOY3U62O8dpOx+REIIQquG -WpXYKeJ3PYFvB4LExG447UKQZuKXYTbC0vLQqNHMhR9cuX+fv3FBqTTT3x3o039h -fKStM8iqQcaqAs+FoMAEwY5dLXP/d27/9tCnQrlO9v1VrjrJnfxzwpVkRaHbLfVN -mz8AxL3odjBZqWp59bnvb0FSvPsTqSoyNT8PPrMuPLqV37eHcqks8Ks5iTDX5RAP -Ts28mV+HFq2e/ATiVMWAVAKIhywfKUZJEyJrPWGefApKcoO9Lm4/10J3ReAi3afj -Fk+nvR9SQar9EXjZKrcY+uoHtFkQuL0ZXHMgZVasVcN/z5Itx5xh9e8stCNLcnp5 -c3p0b2YgV2lsY3p5bnNraSA8a3dAbm9ibDkuY29tPokCNgQwAQgAIBYhBBLSfV2M -jpvxqrx8fHxkdo094zTnBQJiEdvwAh0gAAoJEHxkdo094zTnsXYP/jGDnFLUwJqN -7snv1+y2VoFshQpDK/ePiywY8JAIvs1YP7+IxPH1Ujjor9CPi5s5I5KAG6B1L6CB -8EZYzpWYCYlqa58vbIw+kyOx5p7k/LTOxg10R7lmlfcETMPWsod2OL/mRkU0N9dU -16i01fyLt5rZjNzEFQwhfxqjOR/dD3vFreFlDoC/0/AopD8XW+cKd3ch9r2vhjMM -t89yeP1eNbMHtIRnfbnDnJusGFg/MOBLdZjkNn7u2OqY/ZG71tsqL2DvCeRYwSeF -3awtaXeJEK4ncgxvbXvYrTzxsEQTibpA1tgN/YnfVlGlXxnJ+2upjEeWP/cImiWu -PyxH55QtN3/06N3uyrhE1+L4i5s1AmV0hfDPqjJErEVeNs6mwvMaO5ly5+AGJHMR -YlkBXzmvZqoTydOXIAXe5jLQuLGvVeJ6SjjHXLLRzBm7NEF7Rs8WZHXGbm3FEwyj -8bYW641n3+wKFkZgwwpFEn87RG/25chR7hbwNUwPY3GCEig5a5N8XfOLzpvZX7+J -NtmJB6iIyGuBLbSy8EC6GNI7tiJsnbfc/PhaAvzWPY/nagv+jSGSkbhsVPdYV8ff -HBOYQARM4M6YFHfcUovzsVU/rNYz8ZLdfbgTYc4U4uIA1NxruYokK9TXywOB/+3Q -v+dN4UfIyVopFx3VbPyZc1VvMtAYIlIgiQJNBBMBCAA3FiEEEtJ9XYyOm/GqvHx8 -fGR2jT3jNOcFAl8YVTsCGwMFCwIJDQMEFQgJCgUWAwECAAIeAQIXgAAKCRB8ZHaN -PeM05+iPD/9o4gMpuwWaP2mGdIQPDB028JLeUfc+DFr4ry54KYC/lK6XFanD+M4l -fXE2RdncsFpJBggl7ekVLSZ7oIphEQvDh9CX1b1A4ohsoOOOT8XHNt0kMEQ3nTzR -lkFUj5SG12Qgyfjsskl9+UJvR8rZBuiHJvhGRHYK/4Pa2ORKAEEvZgBNBfW6lHfu -vku1YvFzRawFLWMGh7PM/zlj0EFi+etGNYf+2/pvZSUE32OWjtvl/VYR33Mdwmz8 -t02uupAPTz0VFu0XcWVahVleK45B4a63XQz1t4fzGbYDt5ekf5hXIAoojCjtPsCK -zrvNP6zY7Uc/+zKjVrCnxPhi6/AfLKsKykSUZBryg6bA4qooDNb8+xLDSeDcVuwe -YHQHP3gO2Ty3zuKHc/FCIT765Wg8jlC5GRKfRo6D3yT7cKOWk6RRMX2WJvU9GO0b -+tHXHlFa0Z1UYYD4KQrEusek0sWWXQwKTfpehzB24n7gI38+aQ83StE7lkNCUQqR -eT8eemPgwCNt0v4bzCjexWMm0o5TWdRGLjiPPSR9NMQC1DzIlkhomLAA2aW5dWP/ -pg5iD3yswYzhN0gu4+V/ykNMCZJWs9Gt22rQk2w6sjXBxKvVlQHsUVLAg8VjOETR -a99gpaYE6xMgPVK/GYj/aig+qVglagWwjuUwh3BOgrcJTg7wxgBpWLQtS3J6eXN6 -dG9mIFdpbGN6eW5za2kgPGt3aWxjenluc2tpQHBhY2tldC5jb20+iQI2BDABCAAg -FiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAmIR2/ACHSAACgkQfGR2jT3jNOdIohAA -n6jXagEhC/iwmYsYhwG9SAOEZXw9kpaBjJmuXBJmM3HvTSfI3VwA6fgqoRoDPqcz -2nEWh9lP31ZB6MeIQFDbYHkJE2kYc5taAQt+o+cWWKSRETAYjE/HepfTb087PX5m -IijbRw6n2XHcU23mHbdRmPvi7xDo2HqDmy3owQOqGJZN5bACWWGFyJGrq3KoXzRH -guaBeJFt5KWBOV/u/oLoQHPAn+5xtbV+Ij8pA2ZJDBTDKaj4PKbea0nTT7FRAV4j -wSOYp+7gHTSDzTt1w6bA2/UrREs/7fXxFIXGsq1X0fjmD2nFMswAHqSIhJukxxNl -38Pqsn3aT8hCMkicbnLHFUpgCe2+W9uLQ0w/1nvGUehYjrwaiIZJWB2ZJy/xYYIg -Wpe25YMDBKPvcWs5UhAx6x3fTzv9tvOu7Vq7RjymBcUu30Lfqn4NpiQePyftYNHr -VU53YmGM+3z+n/aq7e5LgjAGiB/M/XYAw9STgrdbiTdVbOKe47g0N3Woo5AHze0G -1g383aurB1L/2heDKEmWLxQDCSY2Ky1x8l7J+RG62zO3Xpu8lkYEKRlJujeGM4is -Pfxo7lVQHnKODSgSVPU7eyvJ+NGDlDwE9MAeqaeW1WpLo88X+tQ9oxNn9kAkoa/W -kGmXizW8tOi540b4DReP/11e7YTLceSLq4rUnhYhhz2JAk0EEwEIADcWIQQS0n1d -jI6b8aq8fHx8ZHaNPeM05wUCX8aPvgIbAwULAgkNAwQVCAkKBRYDAQIAAh4BAheA -AAoJEHxkdo094zTnZJMQAIQkzmti5ZNmDH9RoRWrHKIffYZjvJ9LrErouVhVRR5B -72dSS+DHfff9ZAELAFFIHZHiTcOGuM5vvlGrfTtc/pTs7yDhyoUFhjD3Q+gBhXHA -O0RPf9Ft8p1NfCSIbUVzMFxu7uwHC504InQ2kB6YSTWsF8kOxq7uUT9jAiIKtN1b -uB5htcTaj0+vIjL00dfmxqMWHIlKoHyqtdTFQ9IjrpfvvFBOJKbuDHtiCyIroS44 -i3uqN73O03/2NA8Hr+DbPUTCj7TF0b606h4gAF/CsC9V1VTNg6YLkrTMqECZxRP5 -JADoHLrZxLKrlIIaGMize26nGTGicVVuF3cPXObkY08TKGcUq3aqe8qdxgIStpou -OEvqTXA0avgmmSh9gzL2oNrpjwwYaALuZjLg/dk4mfbyE0sqYCo9DnLpHxqvtL9Z -bFdFJiPKUs4AtYxi6FnoVavPMZhlZyaIhMII7jOW0yxZDYdFT8Hm1ntjWSdMytQl -qvVbb4Ws2m3oEAsHvrqbKQL7DplEbkMi60Oj4/mVTsp2jTJpaLRqEmJpWtpLI+Ao -SGFLa/7as5bUuwQ216Sf1AUF1fo4JHlY/rwmsG7wohSLaXewaCGZU0qtSiTNMvir -yJ7t0B8YVqyF7rdjnUSoRdQ6oMZPWzeQJxzwJJXL8sWesv4Y3LkWnulvZUcl7A4d -tDpLcnp5c3p0b2YgV2lsY3p5bnNraSA8a3J6eXN6dG9mLndpbGN6eW5za2lAZXUu -ZXF1aW5peC5jb20+iQI2BDABCAAgFiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAmIR -2/ACHSAACgkQfGR2jT3jNOd+Ng//TU6LgCYsNdJ9UKDnYtHq2BUAxUwqp9hcytZE -lTUnYjUvj3YWHP4ICHesO+mnSNuOUlRCCMRJBheLm3taCLJumIX9C7sAITrxIrtl -1DvnPyLLqT93ljrer+kjS8vgWAnNx5Jn0KcHITvbwHqPYy6Dx6xiy4JaI0Xg6I4E -ZoLQ1GbEEtKwFY0l3qBeIxijiS0jJR4496aTBcfrxUQ5z0ITSBlp6Yl7QMdwjhtd -hcT1C7yKHWc4nq5BNJQmtpzchxWq2nbNpI7mVAWAM2JLXHEzwu63hPlqJe54TTfG -jmM1X8HzMXOLlm5eJcexXYGRKOSeM/HtVspEg75s86Ysb5xLlloJAqkvvgcezDAW -Xw2mRaYmsknBKDuY7UtRptA4yKZtUhcQQ2QRFWaH3jJrsuu7n7pOjpbQQa+CCq/C -o3dlWp/leRO3nx25RDwybtSXEPFeK4vqJg/1acmLPRmQyeLS9/TM9HPJHPF2Vuy9 -xVBg0aYmdQWO/BVM09PYYtE7CzWKvWXcrBhUCYoRipooR6u06ewJNwE9QIDuFm27 -YgP1kk51SnmFgUjDH/Z21/pU8YpEjRSixVDoA+bgK81fscvHvvf5jmo1GnFFEIXl -7M5+MlYnK4eIDKzP5jOUJfzpjyMDG1X3NBHNXvRHKxoTrNoF4HKWtFqf8FkK6sSf -qOEvE/2JAk0EEwEIADcWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCX8aP0QIbAwUL -AgkNAwQVCAkKBRYDAQIAAh4BAheAAAoJEHxkdo094zTnpRsP/2/EcTernRRMqO4l -QMQSxSjjg9DuKxuKDUAXde3V58NbZ3jBFJ0CWTLIQmg76SeoVjHvhYXVTs3A8PVf -F8xeQOsWmZOIwvFzz6LLOV8IO9C7YO36wSXsheTDjFfTKxHpAlaUCBDycWRJKsXI -fRR8/00IkaoQjyPbxJvlAMpfTjoORr1xhJQCarJgfqpjdvoa3aFYPr+dDLzhRt/H -ETcRVbYLVb/Nzb61vEqPO4/7GZP6aBc47o5Z8MNfSFlUjKKqEm10z0qpNnR7lh/o -CgiQL84R+YohPE4WsQFTnsI/qnR/XoOD4sI0Q4jNSsJmrdG5D9INzSlPlo+wBKgM -MJpcFWIcZEn6PB7wvIOAbPH1POpkU51SnSGtmV3VZz9AoxShpP6eOIYOa4mjJsYB -XkxG0N3SXs/S+l/fy2i8O0yRpJKZTgsvCmNMUVrddXUcio0urxCi4x9w7etasMiJ -hogunDfXCefeylTslMm0bIW2FpcUNJRcVqPMy5/ws/CN+8AACNOVu4u89vPn//hZ -rV7niYLP+9yJA02MS/fRwElcbHkOuGHdxDovfrjKFzx7TgdtBAmo/Hc2xrSdbDla -zsVnRa545hQ8E21UNIrpwDwL/yzGvDc0Oz2ndQRGKnbN+iVDMiPOC1+clFlFyj1M -9WCY3wyVG+xORtr6ArPe9uniJdnbtCNLcnp5c3p0b2YgV2lsY3p5bnNraSA8a3dA -YXJpYWtlLnBsPokCTQQTAQgANxYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJgiM7S -AhsDBQsCCQ0DBBUICQoFFgMBAgACHgUCF4AACgkQfGR2jT3jNOdYMxAAguKbVSQM -nt1USsf2OeWxnkbaJqVQgO0ymqtu623MIQNQunXx+f7YOCZuVEJtA/5pKMqtCo4k -dVbE1QD6srWJvKznWBuOZIwV5vnCWUC80WzbRQ6P8PprrzgJewaqfPIxueR7Ufq7 -iXeZoCMO4kBGTV8TTijJGp4NWqdKvws8zAhmF6SkNTYat7EUssZIPhNu/NdwsFpX -3x/DR0izFgERuvI0MZFd5BqpQw5mEmqkrs6BDMz4EJrIN5cMAOTJRULjKQMrkKjB -kVqrrMlpbDXsgFF6KHPos6/RAJ68mrTqGHiGL8pNGGGkNXtiqak6jpqN3L4qtmB3 -/1D0V2yH+FviQrZIb16Vb3pnpbJv2VLczSGdD3h1kuXf9oMuA/ecqJkbCP+4gdQv -NJuHwK3CDw40T7hkyfPPyH851h2GpkIzkJ21yJ+rUDFzbe6nMQghf/F7+d0youWs -H56Y5ifTifmK+OIiCUTpa0Uluav9PQ6qMr+LQq4OTL+cGzWWo8rWNkS3vyzrF/yx -ZInP3VVJP6fWNxdA62R5eDc8Auk+SQRnUmkPjZzKkzcRj6S08gltd0SSoDYllxLT -0XCSi5JfQFBSclZ715iKxc6PIl/++12/IfiCdv5dKsbPxgAmJWAEuCZwrcHQdIqy -54PyXrFRHXnrjkLlchqBuvoYaffqqfW3h0uJAjMEEAEKAB0WIQSAx7uX7mH2GfF2 -ye5ZiKDAOtP6/AUCY3fqHQAKCRBZiKDAOtP6/D7RD/9ggDbiymKf/IQUVLfDLJmt -OyYqBBwHsizC/sou+q1iGPy9DHK2vgW+wCodSpUp/8aUlQlsZnWHzJgD1hMsoqJc -le2/Ps0p0J3d2LDmwHsNqeXtPFSdz6QXud3ufqim7x/b+eiuXFJb/XUWeDEqSMH/ -7AfYUbdXplz+cwyMaZoNiy7KmDXK5meKuXueUUmyErL/a2zfnbMlqCwOGK8a2ciV -vuJHUhMVlQDtVi+tnc/Nl7USdD1sBPJlgNwaelmA1jSZYPcpe3cR6ExfiWz32l3P -r907KcqR3uTE2AHJoyktut7XEykVkQZzN5w2vSNxXGVzRmXl6z4HDUjm+TLzJb0d -I+d8IOqs/gRDkDrubk3rHgP4aOm3XSEWfFSvL9RiHzGho79+LcXrwkwk2c4lTCH2 -ZgqjSNtuKIxoygBPjUR0AaZSwjfgLE4Jdo0vxeMhmhR4QpmyQzyYKnCjUYGBYY3E -bGYHOSqr7QWyHjBcUn1lQ9K7H3kSr91r73NiqmGmqJRCf7XJT+vHdR6Al8Av2T1P -ekkeTb7TO5JOKfSs0LXvH9DHz0bm1GyKXjFi0LZt4AsZC0lCZH77iYymuWxrCep3 -gz7uO7vpU4kVsNhT9UXhHE83VQtyUAUuXsLdlSgz86pKfzdkvnFpuXEpMAbOWHZc -Yf2fStAOwR61xKkicy6BQIkCMwQQAQoAHRYhBKlA1DSZLC6OmRA9UCJPp+fMgqZk -BQJjf1LVAAoJECJPp+fMgqZkiEUP/20iayXhVm11csjkxgqR3gP6Ejyv9WUveaUH -KPYRqSzVIHVWE5osU2MXs0DQOK6Mtkk4kINsejmJC40JkoN2YJWO9h0Z60pfgqfT -i6QJaWQDZXJhgaZBfOavoNRV7vPxJShVsNAVOVeRSkljH9J+GlKtQFnrc+kWHHDd -UMn50Pn82Gk/3l8BFCWlP8XuyVBBQsTV5tTh+JV/q4d0gVXJwXH0mjWiu+XXfZfy -P9WgQ2S8ffED4aQni/Dab6fDm119q2T7XVkKOB9KpQZdILaGru2gImWIBpBQMsA7 -3MXGBhU4nKSYG/vQ09B2voHcwZScVbWTK9HMuV1Jj8tlxKgPd1UlxguudWsAbUXc -DvYe8S17Ny4/ZjfWVs5yCNrDatZh6cVl/q+3KcIPWWaiKVmour7ccDcY+ShT0GLb -5d0YDUxrJpObXEbg+9Kl0Qx3e2PAUVxFfs4FLDOAwtSA0IQuT5q9Ybxc3Z2xZ50z -xv3PQxbvkcPgRZXgL31RUyIyBWysPYXNvPjgSlV/yrBP4otwtxWSXykO3ZRmcAGC -43+23QAP0Z8NSeINrNZ/njEKDaH2js1pVPLFt73Dgy246g+F3u4HgRoig8sQU+8G -u+WGrcFAtsOguaJw3UxuVRx8Cc1ulEULsMzH0o9NVvfAnmHKGmXc5hb+pksXVMKf -AY7+FIWfiQIzBBABCgAdFiEEVw5jK5NGExBzantvgos5pqLRNn8FAmOAji4ACgkQ -gos5pqLRNn90Sg/9EygJLK1E+LGQ9sSNq6WSrzVU9QSXUTh7NnOTNR66COV1LhIQ -wuG7ufEuxoQzRdX92pq3s8+s8DFfW7QNOR/0DpkRolhjDLjU4sbzlkP5JGOyd0vh -1eQNYNN5OP4LXiNSsLMc0r0xYvO8mNBXZq/ANTGDLqb9g/kIY8TJ3WBB4ipnxVo/ -8xUe6MjIThYB009BfKtjX/s3JrZjSOqxBqkYjo+iRCGfx5Rz5VcnVtPRban86quu -0nqqaF4OqFlfUQ0bGcRhOvUgGrmTA298H26QWIGr1gDHKfHcdyDry9y1MRypqG5j -sQ4I7JhPiuSP7xmDpSWakwOz8mZWfFNhoT3UbitTvciI536I88oKzQT/Dd4dHSd4 -IArbhGm98zNfh7wcOn2mbPCseWvuTK5FqhjsuX3ahv/64PzuJiAih2Yt2R37XBbo -1l7pkUk+kf/lWGbrKCSZvuCmz+mbqsQxHGBPSbKmJTICoTyldnAcADpJK02SYzL/ -4FOajrmSmfsUJwIPe4aGgPGMoa+T2AY9pVQXgV5IAO/gBqTK1jDQ4AEYeXfB5A8j -2puIQZ9gQ+j78WvnF/jIc39yfmP3NGjJ3iAXb+x46iqFx3h0DOZZPTLezMsG8GDE -yptAw9QF1+vXDdpXyOiOgYQ8CS+zgx5C9COSakAdCoHtUQOQsA62FI5QplKJAjME -EAEKAB0WIQSb0H4ODFH41ZZ3t1Qbk0N9O0FimwUCY4h76QAKCRAbk0N9O0Fim+P5 -EACVXiNnRNS588pxdjINXkKgIeozkkf/nSGT01H/FWRn1sH/k8Iaj299QNNZEV4T -R87i5Dz6jduBJZCzZhnS6YHZ67+5/QsBrFmPdd0e0wbff5JiTkqljuklhZH47G/5 -ldYUXMQazoT/a7zpwXSDroEwViNYUBSpuncLK2SRNPdhzj3pcMOavekM+ZQkd/VL -fD2flsACuU34iJs6Ja1SmxeR3fqCe1/f6l5V8G+zQ8L5BzbXIQIWW1I9yZHEa2fc -6PEoJO9VFcZJNl8amKH+0tHE7sZRbWZ4hAednkOazZs/Qu0oqglLrZ3IENsp2PB5 -5cZdrLFFQQhyC9vOI9gqsLE7xnUKKnHlzlgVfBwiPdXrNHDe5DfvwblOS8+vUTGM -K1lxHtW9qnW5XeVu+mHRawHsuD7PJW83wwqxB9lJA2VPCJyyo3qho6yiOGzGBAi9 -HFdAOCTUrRPDhu/ZuRbyHdemG0FvZlBYziJ2SaIAIOE25heu0WAgIlonRu1eVqkH -ndwijMB2Nrk7msUnUgyY7DEwDPuaIxt4GWjNGTgQzq1qg0ljiM8uUBi5w+UOL+kO -lF3xfL+MgIVXz0cK/2bc473B7IBlOC07X+J/6Gc6x0cG2Bo4NULs70N8HmtQbfRy -L/q8VNFBsLIzrgrA3q9Z9x+6J0ZC1fyp8N29H4KDG7oD1oh1BBAWCgAdFiEE0fX7 -tZ6cYKARdUBYByvCeZKuHi4FAmdRdhQACgkQByvCeZKuHi6ZYAD/VjptskL8vllH -cwQiLvuo061KyMpLXz05YrY0+tzX3ZQA/ilMkpiJpvQdzO6P0VC5t/1UStXq1aIg -qRrDf2BI0iwHiQIzBBABCAAdFiEEW+9VYpCBAvtWcnt8xS16/oXyVQkFAmegz/QA -CgkQxS16/oXyVQl5MA/+MfXFN5ycHV0/0sPL0FMbzto1E4Y+qXRDLcTjBhNiWmft -q++pFzHl+GqOeerYHx+RZvCIu04KqVaU6hRstfsoYc3K+7KFXZ/r3Q9h6IBM7aj1 -FEJw72xihinEBjl3cwWsF7LWsuC07UtyppqejTxT6VnEsPydQZyMrD+MosGsOgR6 -5oMWsmYKqUDq2nWqNYD1uAVlWvCv5gS0lnBswvQaLBtAr8TERt6meJITUzR4ayFH -e5csQmwbR6n4e+w1ZuUvh6+7IyGF6cnfoXsDhAdsx4vS2VfOloMUH+AtOET4PP4k -MaMAYSbK9SJnSEBeekn9fbb4HZV911NYeAb2cRo5ZzcRhaNDolrku24a06AW7unB -aNgM2WLIHO+P9ndAL4sUxe8udwSSy50bKpqA7LB2AKqy0Aa5ak4vljxXTLgeqBGu -4QsyxGTZAJ/pNqIIvQITAXZacva4Xy4wSHpjRwCqTNYpWbFZIzpomZxbc2oYw0xk -mRasPZGCn26h0fzJHaudwz54ZJHDQF+VBwWgKqC/Z6iqp6QsicQ9gkJsA7RpKgVP -YkhNzt/iS58U9jbccN2n6RI2GrL5MryG0F5zBzwMPBQ9hHK4cHuL23zEFT+Scp1A -b05x9QVZIvscBFCUY4mxZtnNwcSmtposypQ0Grsy3IbIcYbuM8DzJnx8DvLvE8K0 -NUtyenlzenRvZiBXaWxjenluc2tpIDxrcnp5c3p0b2Yud2lsY3p5bnNraUBhcmlh -a2UucGw+iQJNBBMBCAA3FiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAmCIzuMCGwMF -CwIJDQMEFQgJCgUWAwECAAIeBQIXgAAKCRB8ZHaNPeM050uFEACyNKkYTrhuqsDY -9Ym8vlQOTPUfQ0jHV8SLejJlCzdnPfHVMIldAHDYfU2wjJqNa+mHfkdO6c8NcjFY -7QXkhO9xubgG/xli0PTyZpww32Y5hqcRDLRy8tKe+sYVz5iuioZIMJGGwZZ/ijBx -VURNmkeGWaF6e3jFOBk8OlywPgoFIpg/VvYNVjTeN+kww+L1bZRjtFczIqLkUbaL -IpUx/ELDXfD8vLnJywhd2blSAile/HeBYvmweZol3N2WOYBIG72PdQ1+1Z0O+hys -yB7dbjwIFnX6TuJdwm60DmWpcTgzyFCZiesfh9W9E5OmuUUk11XZV4B26DjgMKDk -mS+ngxeDvoMVkchkudVSMLVj0GkgIgMspf2GaX9ujo7ykGbGKTFX8j7PVAWyBkQX -bkjHVgHUiewFFH7bh9O2ppIBU9l/0N+D5z8TJEKDomzQUugVz4qkhB3oPKSoYV9E -aYQA1yGzZQ1ZxKvQPSNCtuDKZfb3MFrjw3nZLtc2Mk/5iyNCTi3jEk4jjQUgKG9S -5qlG3Qzsb/JmL6HXUSqICJI29AKkLJz0uTB2Uq0SNGHZFrsqN5nwTnHVodMRLfbt -MzHDNzOVmPcvvhp/XGEMMNNXltBsyLXAaVjRwW6TRMJkqP2JzikbHPumF9iaLn6E -GhAQlL32WX0tjoOfeywOo47MHRvJ+4kCMwQQAQoAHRYhBIDHu5fuYfYZ8XbJ7lmI -oMA60/r8BQJjd+oeAAoJEFmIoMA60/r8u2wP/iPcZ8G8fRZudS0ooW+A06j6IZBF -Yv7BRLLRaxQboCkipJsk63XPGD96DPSwUM8u8e795s3YbowRpxjg5O4xW7ogrYoV -obt06gUdNgN6Zfs3S3LXfyN/is4czAfu1zBx6JW4jH1bBCMPLEiTKg9K5UeQzWxd -zBvKajzjA48/5gFWvWCdRdlepzqxJioYQ8rzi9nFJEdc0aNaUUxKEph85Yqg9E/m -lxodcdB1T/Ofq5RGv7S7ugevNHsGK3giiszYZ9Y8K0TDmNLDO5Zaq9iirExe0a5B -a6OgS+TDNVznHVgayO/RXBw/ACWzpVbCw08EkHO2TY7DtCYN2tKYAIrjeEVfxBce -aUW0HxI/YLwW1cOGKA/ydfmIYqSjwBWCL7ANSf4esy6dl/2DVvkE92pze3GVUnrg -PAzF+vFCnYbOwnmpHo8T04plMnFovA3R7XFb6ZdL3XigbCPUV0doa43dGM4evfC5 -gg4Ok9haw53EdC6KKl413JZZUlJ+CsMhAjbvCyemSDp8P9UnZIOoi2tdNxi3Qmy3 -jVYGHSv3Y/7AAQ+hvzK3KkU3PMJgeMPUbUcqD3gtrFze0GCBwaTqSagjtP26M+ZZ -2AXALcOr0wTrhwlDfDOY34kQet02z+N7hRUAegP/O05Dh05XuzW7ttYBqkF0HFON -AsX0H/Sjfe48uFJ7iQIzBBABCgAdFiEEqUDUNJksLo6ZED1QIk+n58yCpmQFAmN/ -UtUACgkQIk+n58yCpmSGFg/+IN8UBx26m0CwOqC0Xa8hbCCE1b8093LyS1FZraJT -zfbKWNyrL0NEO/baOBJ8RCf7jR3YhvG34yTizUZjHQNd3K4gKFaZuIdRn713NsV7 -D0A6+LoCVQO0B9AqqsGTybClUDU7gf/a+dSbV5ISYiOCcclhA7zkJ/FNo+OAt130 -56bEnReNMMI9nU7St3y3CJQXfOfxJLh7vkpJItbxQshc7SEaEDltt7xw5dFfIoT3 -Mt/w5th9ImMJH3C9UCJql0ZZs1dynxhp824Xtp9ldRhYReL3Dq6G6McwfgDOWxvi -IHwQd4F44lSy3Z+3OTSGmC+1dAA7tHW/uunkTEXBh5Lxnz6Zet6iUgbeLz2Yo64s -jq/uorrJodHhnn3nebv69Rhemm5HCyMp7/KOizBo0NaDvsYWRmGLyH2JcVhQSvyb -KMQ5jirZP7BjrB/REHEKclaFXC+/kobOfGdVh/uYjf9z5vjW5LBGg4FZULMmG8Qe -L96nlHAz/4A8CLGZQT1NAvg+12C4dF+SwU1mn9OvX96RS6d8N8gAq8hYumN3WrZw -Sk21rsbtTRA/pB5Q4MEuWq2qXUTnxf+KdyOrIkBDNHmusw4sXLnZPo8NcdLFDJsI -bOba6PphCWrT2ezgzqqY4ez0x6lhT/iaP2SFQZqKizQ09khYobU1t7C5wETbeoZJ -E/aJAjMEEAEKAB0WIQRXDmMrk0YTEHNqe2+CizmmotE2fwUCY4COLgAKCRCCizmm -otE2f0JQEACqu/Z0oWNPhEhZjcbgjqoT3d+byJdz6LBLT399O2UDpVV8bEyfESTd -nLpQB+ayvo9PZsh98EvSulSDhBMi5ZVtN6nj4EOFX/DT91kISGur1FwaQiuk3weh -1/cNAlVkRKRDvfsh6F164cM3d+do78OcTEb0ZcZTTxYEI2UqG+eVCJDpX8mAZMAU -L42OnAkoW4fNBxBZTJF+eR9btZnUH4q+QiiUki9SsJWL60DUgj5rzCeNoMv5O32u -x7al5RyStcUvvJOEx4DNx+V/p2B8HqVpRt71FmUCgkJOFuHx8bQeGSYCJr2JL+sE -dWkT8dX0UJ4cgatJYZJvd8wvPvwoE8uL6uKo3jfLmJnEeuVSP9LYcYyoe7spzOt8 -PTpc3OslPerOzMqejdPGkptD2tzcez2I+8jyoQqB0jCZV1VfvLYKLIWRMDarP1wI -4xB7QXv2QfsEsd2Np6UItsZu0yRvTXYZYiblQcbkSYGmFIUnrGLFhsv+RB0FFOzq -u5s76IPCeikLllZoMhAt3/bUYe8cOzW737wCkL/zYow66uw5WiZMwGF6E7IT7j3s -sJxiQGDOsaCqR2ex82qqq/T3m22YCeublzQhnWj8GmkKWZadMg8ssNexnamz+XaE -VHsjIsz+aDHgd5c/co5emQxeqIrkE0HzNdUEWHj52mLTyxJQztxBCokCMwQQAQoA -HRYhBJvQfg4MUfjVlne3VBuTQ307QWKbBQJjiHvpAAoJEBuTQ307QWKbc+0P/AsS -ZBeBERLxBl7GZB8ISBG7vQRhom+nvs4nlNsXyY1wWwxhnWlbeSmeUWP+r4Calx4u -mdlyxW7mZ6QMdfKLad9CCGd8lPpOulrYRjdLsZI9YTFgWzLzQfoLyAFZPhhriwPE -LMU4g91JyuUZIcizUnv6bjbPCpviF/oxspkIppa2L5ouy6yFs7RQDKcNCMsPyoNi -ZA+w6Utx0D2jwHaJfpe+4na8akN0bsivY0eqAKR1RUOXiWqClGpkTGDzHeo9QyzM -PKR/EV54iXe5wcfsrbJ/Op5XoGOgBcO495BlLjQjogHMylyt3I/WB3NV88sMPres -1dUFb4SNTkbJfCANucXY0+0eQd0xJ5KYQ7M5Y3FRISrhTPfVcywyNlBe3+z6HIOl -eSJOnVP8SQPDqDSwuDoj7lxVTjGXVi1X/KoArMOHo+u6RND9LqsSBexfmcJmfVyZ -bKHYB/ILrvr0Bcz5k2yyNHC1mi+A3loeYU3yEf8SXOn9HjAhZEJ1kjuD52ZrvIZ0 -2hZzXalZkreOZcCnjrgSkQuCcscM6cZowZuTwFaUcFlycOYpY5hKlgeeL+dkQO7C -ZBN8Jlk9J7dg1P5m9fiAbevnrn2mtMXF05tQRIE9I7qTdwxDMKqvKK13dzgdNIou -iTBBEGcM0JSQIpb7Ajv7biLNi5DDn9suzRNGOa95iHUEEBYKAB0WIQTR9fu1npxg -oBF1QFgHK8J5kq4eLgUCZ1F2FAAKCRAHK8J5kq4eLuzCAPoDarJ8bD99BC/oQhg0 -f7JLFQHkAjv+x/0tklmO50Fs/wEAh2yRCra25kWKEYyOztaN0u2JWP0CrC7ihsTe -JBD2CgGJAjMEEAEIAB0WIQRb71VikIEC+1Zye3zFLXr+hfJVCQUCZ6DP9AAKCRDF -LXr+hfJVCVlRD/985zXhE+E3vs+p3GZFOlnhhnQ1M2xZQKDsuHGZgDSMokZgYaUM -pIkramc0xUhZ2pB8mU9qLFcrhfn09FtwLClhWpO5PsNJnyGcBuQZtg7+Kb7WRxxD -d7vvm8A+iuT36haFj1n+LFJ6lktvwqUcIctVHffdCA2mNOrdBu1iHgA00njoBGzJ -e1+WI7jyLTc3yFwlvKeupOlwi5pDQFAtIdxzOKnggGlm02fQSKKInXTHdbO2Kn2E -20qPpYhVmLa5UtNQuRjgMp+RUC0zl3rbvXJXoIo2sj4BX4qWEmqDreOnY7osXWuW -NdHh9IM3bqkJEg7RJLgehCiQJ+klqVBIEIv3rQabLJMBmORARxOecYkseMnqs6ko -VtTcnP6bA387bW/lUGLsIJJ8/YBsWCidKMb92+Pfo0DeWF/uGZHrPjm5c+9fHezH -KqmLpP9gTUaABhJLac5eNj6dvUYdzTomAcybbFDgapMRTdKW/4eg10AO/mc+lsUw -L5sVVPMAqx3GXU1avo8hj+LIrM2YIOqwwSJTByFOnFrelNEhzTW0CzrSJ5YcUANc -mK7h/PPVw7qNwxBBcYk4PBJ4/0eQy3ezt5L3GNiFylzXZOiJeBmsV6wwjrLwyv6I -kW14jnzjD9Ap848hOTGA1xOjtUrbg5ow99LELXVHxcGM/bbnFsSSOz0gI7Q7S3J6 -eXN6dG9mIFdpbGN6eW5za2kgPGV4dC1rcnp5c3p0b2Yud2lsY3p5bnNraUBnb2Zs -aW5rLmNvbT6JAjYEMAEIACAWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCYhHb8AId -IAAKCRB8ZHaNPeM058XPD/9+0WKWBcQPm0lR9dPQ7U7XLFkl2zSwzOxDv6Cf8+DN -ndaJXIsmkgPWqOFRJxrm3cIfHB89jzCLAwR5jkZ5LLv6yUqSC6qjGxC+q78eY2kO -JvfiOeBbtdraQF4lWWgkdFQrUxcX88A7lNr3AuXVDDxHyccH7O+LyByIb8GkGZ19 -dImWB7ssyZ3GhRwi0jbgH/XJDU06QNowB5P2SIzWfXLu+HlJNeCNUAP35HM8nr1h -AFgi3DIhPLUTTGIhG4ekVETb3C5KSTFY01bPirB+RiIqMb0MvmzdZMB6Y++UIfqg -oCm75tEvgz2iXtXWELbidxuls96e+8za26TmCgomjSDIPw4T7VrUoh8qEPR8f1ne -WJu9pB6FHmJuKN3fg+Fji2jMDQuZnWKM5iw6oZQg+FhTR2Hd9qgPUjWQgD3G1krW -ydAqJUkbyEDWl8iFx+go6QdKfp4m0Jt95P1fKPbhLoRMJrxWmW+v46diyb36u2YP -vEOM68hmoTnsfChThxGvpVuvTgZ4JeCNO/zpWpaLXXMzIBMlhN4U/ZCgz211rIPd -ikR+lWpmz14tFMHM8m1dE3xQWoDefCEqhIUxM3JfK8qXaZtxODs5Q3rOjHvY9woC -0e6JjJ8lUT3E7CkfxVIT1ag5n7040lk6eTQ33TpbceROXYB0Q/VXypNMhqjgnoqk -BYkCTQQTAQgANxYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJhri8iAhsDBQsCCQ0D -BBUICQoFFgMBAgACHgUCF4AACgkQfGR2jT3jNOfXJg//Tu48d7nm9sY2fME3ysg4 -kWAJva5xB3jdyvEkHLapDU4Fmm9XX/2DdKReVtiT6isYvsLtqPV4KdrtauhvQqOB -6HRUzaNvfBzmR49xEF7l5vf+RGetJuLOpbo1TBah2hZ+NkLzDOqbFjY3Jr2cQv/J -DlpnnRdC8EmLrBJtIyFvMHL8E9fDPEuJMKUCuhOtGv976mqXuIvpl0iVQq1FC2WZ -AbZ0rZFcjdbXX4Y6OIi6vRfcfVX68LMCGFAg22wKG/hMr3e+u0Z4/Y2+GSenwum7 -sH33nM7i7UmWPTS/v+wezFK25tQMQZfBxtHYI9jj6U69IgZzrlyEY8CUR///q92c -igyPcAkwJgGm29rY85iIeUNKAPoxKZoDntD4T36+SrKoPeV31rjKcOGLUL7r39pO -KprqPeITWOQ80q8HqcxHLsNjjF19fBAYDbwIUxqWpGD4faV4PscF0blhNEpIL2Cb -8PmOZbhCOTJJDyopcjhYBKWwd0mfB/vdqN+FO0yzUhDb5abx5tQeoLOuZlXfYOgj -Ww3BV5uabu64UXVzago/ipcLz7J2aso9F0RqAVjnem1+ZoU1fCVCXr16vVeyqcxE -JYMpvX/H/UOznldlZaO5Uzfz7nFpEX2zZvrUbM01yVGFQifACMHtaMSThKQaut/5 -LxAPvNoO4dOWsnfUhr5W1SvR0r3SuwEQAAEBAAAAAAAAAAAAAAAA/9j/4AAQSkZJ -RgABAQEASABIAAD/2wBDABQODxIPDRQSEBIXFRQYHjIhHhwcHj0sLiQySUBMS0dA -RkVQWnNiUFVtVkVGZIhlbXd7gYKBTmCNl4x9lnN+gXz/2wBDARUXFx4aHjshITt8 -U0ZTfHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8 -fHx8fHz/wAARCAEgANgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAEC -AwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJx -FDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpT -VFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ip -qrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6 -/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcF -BAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl -8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6 -goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU -1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDRxRinYoxWRoNx -SEU6koAYRUM3Sp2qvN0oAWPiEE1UuLhRGUHLGnXE22FI1PJ5NUerUWGNIPbrTkgd -jwKu21m0nzMMZrThtFXtQ5WKUTIjsHarSaa3pWukIHQVKEqOZjsjHGmkdqkXTwOo -rWEdO2UXEZX2AelL9iA7VqbKQqO9K7C5izWGRleDVGWJ4W+YV0jR1DLbrIpDDNUm -FjEhuZIHDoc+o9a27S+juFyPlPcVlXViYslPu/yqlFK8T5U4P86rclnXg04GsvTb -4TDYx5HrWkpqRElLTRTqQBRRRTEFFFFAGRRS0VQCUhpaQ0AMaqF3ME46mr0p2qSe -1YU8hkcselCGIz7jk9a0LGz3YeQfQVW0+282TewyorfhjAFKTLSHRRADpVhVoVak -AqBtibacopcUoFBNxMUtLijFAhKKWigBpGRUbLU1NIpgmV3jDDBFYepWflHzEHHe -uhIqvcRCRCpFCZRzUUjIwZThh3ro9PuhcRjP3h1Fc7PEYJih6dR71Ys7gwTowOFP -Bq3qSdQDTxUSMGAI6VIKkkWiiigBaKSigDJoooqgEpDS0lAFLUXKw7R1Y4rMZdzh -F+lWtTk/fhf7optjHvlDHtQUjTtIRHGFArQjWoIFq2orJ6mg9RT6atOoM2LQKSlp -iFopM0maAFozSZooGLSGig0ANqN6kNMPSgpGPq0G5Q4HIrLGdtdFdR74yKwXADEV -cWJm3o1z50BRjlk4/CtMVy2kTmG+VSflbg11Ioe5I6igUUgFooooEZFFLSVQBSUt -JQBz92xe6f61f05MKT61m3B23En+9itXTh+6BolsXE1IelWVqtHU6msi2SilzTQa -dTICkp1GKBCUlOxRigLiYpQKKKACg0U0mgBCaaaC1JmgpDHGQRXP3qeXOfeuiNZO -rRYUSDt1px3BmUmVnVhXYQvvhRvVQa5DIwD3Brq7A5sof90VbILIooFFSAtFFFAG -TSUUZqhBSUtIaAOcvhtuH/3jW1ZLthT6Vk6muLr2Na8XyovsKUtjSJbRqnVhWYbp -QcZoN0R0JP0qLF3NcMPWn7x2NYRupPRqVbuQdmFFidDc304NWTFe5+8cfWrkcwYZ -zQFi3uoJxUQOaR3CjLEAe5oJsOMlQS3aR9TVae7Xoh3VSlcufmOPpTSK0Lr6mvQC -m/b93fFZ+6FT820e5qZHtTj94PwxTsK5b+1juw/OnLdgn7w/OodkBA2sfzpPJRuj -Giwal5JA44INRXcXm27r6iqn2Zs/Iw/LFRvNPASrMwPoeaLCuZfPlsPSussvltIQ -f7g/lXLhdzNnucGupi4RQOwFUySyDS1GrVIKkBRRSUUAZNFFNJqhATio5JFjUs5A -A70rGq15GZ4CikA5BGaBlK723MqsuQF9utWkhlcfOxA9DUNn8suHHI4rUUBhSbLR -WS3QdcmpCYY/vBfxomO0HFUtjSPk81K1GTS3tun8GfoKgF9E7ACPH4U++tWwsijK -gYOB0qtBBJO6r1wfTpVpIltlozRkjAIoZyFyjEe44qW4gXeNvYdhUMq+XEfXuKVx -2I4r6YcF3b8aPtDyTDduH1rQ020TaSwzj1p+pWimLdGoDDpii6uFiqRhBjliKhaC -R2xk4HWp7aQMFOBkcEVZW3ByQT1zjNFwRmXtmIhGcZGOfc1WRAxULHtI469a6Hyg -ybWGR70yOyjjbcigGhSsDjcz7q3aIoY85I5FLbysDhutaTRZ5Y5qB7YE5HBpc1x2 -JI5KgvzlAe/arUMWBzUF+v7yCIdWahPUTKsVn+/2sRx3rbWs6Zf9Mx0zg1oDpTJZ -KpqZTxVZTzU6GkSPooooGZBpjGnE1GxqgGsaYTSk0wmgCAYW8Gejj9a00TA4rKuv -uBh1U5Fa9pKJoFcd6mXcuJXmjLGlitwtWygZ6eIgKi5RAEIGO1KI8DgAfhVgIAKX -bRcd0VmjwM1m3YDTomcZOW+la87LFGWcgAVjw5nlaVh948fSmhbmvaKFTAqWdQyE -GmQYC1K/IpA9zG3LBeD5cK4wc9jWnGnFVby2EqEVFbX5gTy7pGyvAcDINVuLY0TH -SeXUa6jaN/y2UfWl+3Wv/PdPzpWYXJBHS+XUB1K1X/lqD9KY2pxtxFHJIfZaLMLl -tUxWfn7RquRysK/rTyb65GFUQIe5PNWLa0S1jIUlmblmPensLcrSjN6g9qu1WI/0 -xfoas00KQoqZKhHWpUpkEwooFFIZimo2p7VG1UAwmmMac1RsaAGScofpUltBPEoa -1kAB5KN0qJjxV2zPyClIqI4XF4hG+2DH/ZapPttwf+XNv++hU23NKI81FzSxB9qu -2+7agf7z0jPfP1eKMewyatiEetO8paLi0Mx7Tcd00jzH3OB+VPiQB8dKuT4VOKrx -j56LlItovAqXtSRjipCBikQ2VpF9qg2AnpVxhVd1pjE+yowztU/VRR9jj/uJ/wB8 -ipI34qYGgGQLbqvRVH0FPCEVLSGgVxopT0ooPSgCmT/pQ+hqxVXOboVaFUiJDhUq -VEKlSmSTCigUUhmG1RtT2NRtVARsajJp7VGaAGtVyxbKY9KpGrFi2HIpS2Kiaa1M -vSoVqZelZmg8UtIKM0Ele4qq1wkRBY4q86huoqnLa5ORihFoniuVZcg8VKZhiqK2 -7r93j6VII5O9MTQ6W4YD5Rk1DHPK7YIH4VMICetSJEq9BQIWNSBzUgNJRSGSA0pp -gNOFBIUyRsKaeelV7hvlxTArQtuuauCqNqP35+lXhVoiQ8VItRCpVoJJl6UUi9KK -QzDNRtT2pjVQETUw09jUZpgNNLbttmHvTTSKcMDSY1ubkTBlFTLVC1lyoq+hyKyZ -qPpaSoZZgjYoESmo3YDrUJuCwyKiZy7c9KLDLUbbqlxVeIhR8xqcSof4hTBg3SoG -cqxFSSTovHWqslxGT3osBOJKbJNhciq3msxwiE/WkMc38YA+lFhF+Jw6hhUwqlYA -jIOavHgUgYxmwKqTvwakmkzwKqTHNNCH2QyWargqvajEefWrAqzNjhUq1EKkWgRM -tFC0UhmEajanmo26VQERphp7VGTTAa1NpSabQBZtpdvetW2lBGKxVUo4bHBq9byY -9qzaNUzWHNZ90GaXA71bhk3CnNEGOTUhsUFgd+MkCnfY3H8bVfAx0oxRcZQ+yt/e -J/GlFqT/ABEfjV7bUcgwMincdyAWyg88/Wni3Bp0ZyeanAouK4yOJU6CnsoYcinA -UtBJHHGEzjvUdxJjgVKzBRk1Wl+YhjQBEzHGaryn5TmpGbrVC8nwpGeTwKaQM2YS -rRKV6Yp4qppjboQPWrnQ1ZmKKlWoh1qVaQiZaKF6UUhmATUbmnE1ExzVANY1Gal2 -MegNCwSO2MY96YFc07y3IyEOPpWjFbJH2yfU1IVzQwKIQsmO+KIm2sVPUVdaMIOa -r+WJoywGDng1JSZZtn2nrxV5GDDNYSTGNtjHkVeguVPANQ0WaFLUSvnvUgNSA4Cm -SrlTing0tMRXiHSrAHFIFANOpg2FJmio5HCjNAEd04UdarNN8o9qrXdzvfaD0qB5 -S2ADTSAlkkycLySayLsyCQh1wBW7bW+P3jdew9KpajGM5qk9SXqW9CbfBz24rUcY -Oe1ZmgJthY+rVsYzxVMghHWpVpmzBOKevWpAmXpRSLRSGc8kTydBx61OsCpyeTV2 -NVT5cYAqtOw83C9KoCEKZHwOlThQowBRGPLUk9TTkBYkmmAJ096fGmTk9BTsADHp -T9yhcDrSApXz7IGPftRBFtt1HfFNvfnkij9WyauYKx+1AzBm51DYehWkJeB/an3Y -xqEbetXHhEqcjmkykQwahyAxrTjmDY5rn5ICknAqeC5aM4pNDTOhVxSmQAVmR3QI -69OtPa5HODU2GXPP5qQPkVlfaMtjNPF4u3iiwGg0oFZ97dALwahmueBjqapZaYjG -TTSExFJd+OSa0bS1CjdIMt/KmWdp5fzP96tFQKbZImMCsy/5OK1H4FZjr5tyq+pp -IZqabD5Vog74yat96bEuFxTu9WZsRuDn86SiTjb7nFIhyvuKAHK+KKTrRSsBTZjy -fypiRfxvUxUD8KidixwKYxMGR/apwuBgUka7V96dQAlRgky47AU5m7DrQqYyaAKp -y+oAdlWrz7QmM9fU1Si+WeaUjOBVSdWknikdict+VFgIr9StzGcdjWhbkNGDVPWj -sWJ8d6l0+UMmM0pLQpMluLUSLkdaypo3jbByK6FRkVHLbpIMMKlOxRhpIFB59qcJ -hyc4q5Npy/w1VazA4wc09BETS5T5TzR5oUAA5xUi2bHohqxHp5BywFO6ArAPcHCj -jFaFtahOcdqsw24VQAOKsrHipbAiVMU8D2qTbQRgUgKly+1cVVs033G70qS8fLU+ -xTdCxU4bPWqQPY01GFpO9U7W7bzmhmIznCn1q33qzMSc4VP98UqjDMPemz9I/wDf -FSDrmgBQAKKa7dqKAKsh7U1E70pGWp44FIYE0xn7DrQ744HWiNO560AOjTHJp3b6 -0vQUyQ4xQBF5eFk9zmqlyuyJD/tirpIGCejHBqKaIyOqHpn+lNCH3FqLiAowBPVc -+tc/ayvaXBik+Ug4rooWbYuTyKzfEFrkLdIOejYpLsM0beQSICKsY4rA0q9+YI55 -rfRtwzWbVi07iGMGozACc1ZxRikMriECniMVLtFLigBoTFLjFOHFGKBDTUMzbUNT -McVlanfJCuAcv6U0rhcq31wsYyep6Cr2i7msN7dWYmuZllaVyznJrrNIAGmwkela -2sQ3cqaghhnil9WrWU5wao6pzb7z1Vgaux/cB9qYhJ+WhH+1/SpD0qCc/wCkQL9T -+lWKQDDRSkcUUAV6Rm2jNO6c1A5LvgdKQxYxvbcanpFXCgUtAAelQznDAVMRzVec -5kAoQBefLYk+gp6MGkj9duTSzgG3AYccZqGDJumkPQgAUxFhU4bHY1Hcp59pLEep -Wps4kI/vChly2aQzilLJJ6EVvabqgYCOU4PY+tV9T0ryt00GSnVh6VlAkVTSkhJ2 -O3VgwyDkU4GuXtNUmgABO5fetOLW4iPnUis3BotM1hS1m/2vbYzk/lTG1uADgMfw -pcrHc1c0ySZI1yxAArDm1x2BEaAe5rOnupZzl3JqlBk3Rp32r9Ug/OsWRy5LMck0 -E0EetaJJEt3Iq63RDu01B6ZrlDXS6A2bDHoxpMCbUfmgCjuwq9CMouPSqhAmuyD9 -1Fx+NWICUBjPb+VJgR3B/wBPhH+yas1Um/5CEX+6at0AAooooAqSthajgGWyaW4P -NLB92l0GTUCignAoAO+apv8ANP8AjVs/dJqpHzPQBZuDiMCo41+TIpbr7op8YHlD -6U+ghx5w1OQ5Jpq8x0sXekMdInHseDXHXsX2e7kj7BuPpXZnmuX14f8AEwP+6KqI -igB6UtNHFOBqhBSigUuaADmjFGaKYAKDwKWmgbjSAbtLEBQST0rpNFj8iFoz1+8a -o2FpsXzpByfuj0rQtcguexXFS2Mt2q/ffuzE0+RWJDJww/WnQrtjAp/agCozb7xG -6YGKuCqZGJxVwUgA0UUUAZ05y9TRjCiocbpPxqyOlIYtITk0E0CkAkhwhqtbDM1T -zfcqG05ZjTAfcnkVLF9wCoZzlhU0f3BQAqdxRHwSKReHPPWlH+sNAElczrp/4mB/ -3RXTdBXL62c6i/0FOO4iiKMUCnVoISlooFAC0UUUAIx7VasoPNk5+6vJqpnvXQ6b -YkQqW4B5PvUsByRtNwvQVbSPa4UfdX9TVhYgi/KAKYf9ZUjJB0pT0oHWg9KAKh/1 -1XBVM/6+rY6CgBaKDRQB/9mJAk0EEwEIADcWIQQS0n1djI6b8aq8fHx8ZHaNPeM0 -5wUCYhHl8QIbAwULAgkNAwQVCAkKBRYDAQIAAh4FAheAAAoJEHxkdo094zTnWUAP -/jaOft4wdcPDuvhIfp+LItwx/8cT2U/PLKyCAMiVrI00tlLnkNBkzKOdUH3dibu6 -ua36HKg/20bWVplYGtdyM9MRDNOrt4/uFAC5wVNr/u5dCBNszvC2QQWijkUO+EAQ -5hqwKMeB/PWjv5wnlqSZga4Mn8MWhQ8XtjXfEfPnEqUoH5yPa0v7wqWH4iqwQs62 -XsI4XY0JosTJGX2msxYi1crST8gbAyX++lWCBxBO/YlEIGB97RLXLI4b1xZg2gr8 -n6RrGlnFPB3bgIHoi2fMtPpimKUEhwb9WsSatE02gGz83187rNQW1uxHCK8FMWJR -FYD783xKHYm4iad59PDoMwMurf0u2jzrlxl2oyzgVSUeEzutXJZLcUTL4kO9EV6g -6JAn72Kr2fM6X7Fle3lVJsOWob7QM5WsqOAzfWMz+MXu5Jlym6Njg19D1DQ+TNBm -7tN9wN4cCoq0u3kIxzUQ2eJwqMRmmTVFUokaPAlfl+psq242QbFRxUO8YhcuszR1 -qJQI4t3Vq1amYFIjkD26BeZbr/2aAEU/fG866Nl13XDH1Ad9cCNn3DEMekvVi8SX -curqA+B+MDyZYIl0nULOG2dy1xKKO+oAOPBR0EVbbeSmaFYt2Heu35W1gXVpN1ng -fMWJbee70ypr25wmIzqpExw6hXB1LVaLMKtck13+TF8xiQIzBBABCgAdFiEEgMe7 -l+5h9hnxdsnuWYigwDrT+vwFAmN36h8ACgkQWYigwDrT+vz77xAAgCWJwLVR5Qv/ -n0YyvojiBxgwST2342DFiJ0Dp8btRrq0WysG9ANQxsa4k8veS3FHlq1vN7e+rOI5 -F4Vn6FkFA3LLpsEZfLL4HlQjE0Y50dqXcR8x436ibEvrtmWPAncanICnDG7tBIvd -ecrpVDeN7W6scQ+WcRwoAapJuu3AdtH+3zTxwIGvO8f469zNSMSwBCGtY3GEQATi -VAi9TjlTZtAQV6tEHjZlCNafnyDgr2EeaU+LU7qP4PxDhTogbEV8LE/eFawSzsPP -7W395GYM5dKEW+94JO2k14XgFthCVkWU6/N5Qh+kAMpteQxQrgMjc/Dm76WgtAFN -9gWCuvkxwSM2CU41ylXPtzgkzCtekj10sF0qeDPIdK69OyKDDMhvoBjeyN4HD0oy -rU0DOWU5yCIAK8oxEj+4IjwZTr8e5myzpUhMX3lFZ2onyQVItqyBZwDvi3QgOtUf -0YX4+/Mj7zWPNzVTdytwqscvGYZRrR3YdGrKc8vUg5in8bxzcTExkLACIRPxuXE2 -EBPezQccyy3yDdJscNLJRD4eyxzdgAcLR7Y14mu/p6rpe6gIK0/uu2aca78xymSx -whACe3svxZVDu0p5NJtcoIdlY4yOQ3hSEiR7p4tDeVRtgzGKTpX4NRwk+UYUxyWn -Ch4PiQ1u/hab5fGbDPXKQqEv+v+Y0GKJAjMEEAEKAB0WIQSpQNQ0mSwujpkQPVAi -T6fnzIKmZAUCY39S1QAKCRAiT6fnzIKmZCCQEACNUttUwBI5QWQsGk9Tt+X9UvMi -i0/0/7TDTTkSuL16uBMU/s8D57qdsfrMYNbvZfxAVFTVH/hyuIlooBb5MSD0x0PO -zstaj25agIScLksLtSCE/qHyaUW4kcQp5Qg8l8vyAs2D3OXTGpyct1j5+o2bwYKt -I9IKO4vE0qC/JQSW/ZaoBguPL5ocl4wxYNNVhmV/t7huZnpLWlAgy2rAwbeypRTq -QPbHcumhZGf//jIZZJS8MgUZ9i3mF+8I350ImWhTmrrrMFf/qKp/ANyxAV9QgFaU -0N+YDBJRAj0KRARzITabYerNUjVteet+Qa0DpqulYtYFOD3/v9L3deS5yFCNxIDz -xu9oPu1WfM82Fms5oM2TB7Xfzji7swMBPkoEiEdrL+bot2laQxUKAJfR2O3jf+nL -vPY+qMfrLfV587lhA5UupFXPfPTPkpycEvmXdZbIuK2LjwxRUft1WfvxGAYF/iXy -Ld8tH33Cx4hsWZjl80aRhit8TJrlZLCcOOGSfDlFSKpFU+y/Ib0xZrWhEesKgvEn -nYYWFkaO24r0p8LzK6v8KbtKxh7Y6f4ODec8hbP0kmuLUZ57enNEe6wQ4KcRRI9U -pCocjh6JsFifT9N4EJ/yWIYzaJO3ZdDYRgnwbt/K+ii9nFzjRSFp5IwWAzfWhJrw -zTfVT82AeoqS/DTCdIkCMwQQAQoAHRYhBFcOYyuTRhMQc2p7b4KLOaai0TZ/BQJj -gI4vAAoJEIKLOaai0TZ/0wkP+wZRBkPY0KqXmevfpWdxYUl0JvZ96gLqBG0B2MOI -6IqwWClvuBVl/8yOe1g1BwcomZC1X6lEGSjjMOTQGU0DJn6uxn3lih9rrkLvmdUR -usC0AF9gKesVHfY09dVYWYSNtk3wNqAFJDJGUjPYmXX2XCHYf7OL5jlnhrjNz/N2 -NN6PCpOaDFx8wv0+q27Ir4JwtMWKAbMHWF3FSOjVJCH9MExQ4+g7ZN1mTUp5Sy+9 -0VbP3mwN/54KVTPuMP4zcegC16cNrvEL3RQTY0Ysb3SKpbMzaWgZddOLKLbpZsEt -SU8c5Bu+iifCGOEyA6tPv2stYMBZvUpiXTuxVSbIScJoWWSuJ8law0r0osU4lbey -HY0V4+xafc6FJlP6RucGjLruce9c8uRl3K5toorzjFPiq2VmxuV2aqy7W7Q0Yuol -/pBZJpkAmUCgYupjH1uv+6UsrJKMD7K4TEh0dIbZyo/Wco5IGcXpLzlmPlpXOonq -8UkC0YX/a4lcn16ER5i7N2olAm79wUzRG9Z+aB8mQQHF+A38yAdsFLYex4GJ9UAh -ZAKcjunZLyAw3tceAeTYE4kl35joyBlZcNdiAvq+P8NTGLJOjT0ilBDnugmAzsHA -g0Vt6ViOhWtICF2gXvD0t8k5n2QZ0L32TK6wAE/vVvjOnViICx1OfrlCFjqDXPie -PqHaiQIzBBABCgAdFiEEm9B+DgxR+NWWd7dUG5NDfTtBYpsFAmOIe+kACgkQG5ND -fTtBYpuMuQ/+J/HGCHvcP+HDSg3zPYGoX6ipc8BzCIUSAlhST/tCUpIRn4a8jkRf -THsciFVT/ULzD+wQRRsE2fotlhZQ60zMMaDersQ+z5pdga9QQrt9L78cXJpBtp5E -GjnvScEhoxuTs8fq5viJ7dN2rIIILSoiEWXRSFSkVU4wSIn0s71YE0/zrVpk1VCC -mN3EyotiWDQfg7BrwC82hvffO8d6I5CNYLQcWDEiRbhsOKVK85up1wyt6XQx3Awn -L5L+qHV9l+fUX6Iu474hXPCGHLeqh8o1AQ55d0Yn+ipk+W8WXhQXE8gGvV5Bl1nU -GZuX8XH6HcbxSbMZMtii1UVpYZBY//KUazhZZu/6+HZ6qhDQYTyyZJ2zYZWaRp/g -Bb/6fjvDPbafHk+nbViHD5NnU85Ajk8aUkW+J+HWmB8nloZgWVpU/kQw+881lmkj -5SFbhJ+580A+YVkQORETz99vAN44zCvXcq7DEt3eSK6GSi58zOZrzFd0H/SjSBcu -d4ArXOTJp1s+/mY5EhbiHRAb9TZ8MnrXJRUUZ4yFyHMpD+WSQAzkIVyUSwGmwirO -qN7iIlheMQurgsk1kwdNEIfR5c0mvGPvfuPsFAiL6KnBLvXNQTFXwH5tHL2RFtYU -GfYlmzUBHkNWUcUY6YjJAjqF35WWbtBTtIO3LaawekyC/eVVz3UExvGJAjMEEAEI -AB0WIQRb71VikIEC+1Zye3zFLXr+hfJVCQUCZ6DP9AAKCRDFLXr+hfJVCXl/D/47 -G2JqPowyY2aj7cDGNRCOUrVzpl1RIzJchlgqGOkDOLPY9JmExf1eKdu1B6urqlW2 -5igeFhVp93rJnG0lZsFhFEXlNA8FFdKbJFUVd0otW10pcs+vx47yNG8Wj/JBs8Kt -fNIgBF6UhEsnqK0SrruP6BLcRvBmDpv8niXqN06iKfshZiAKuXyJiH2DAHn+soUy -Q3AwcTvqspcWvlXzQWvQHJdn0UlPOzW0vahf0sv0lMrlsrjtC4JXo8gSiMo9xi76 -TW3M0u3I66c6JBdk9pKhlQmZTGLNY5B4Jee45urRg8fL2NTJ5M8m2Lyq49yrMv6L -rotEF51NUv96ne63RYhcO0A+hwoiCAtOTnEiiQMbBA9XXT/Hl5sm1q4NQxkv9FCS -1gov4SJpD98MbypBcBKhp70c8dhmLwfiFbB8oZ2qD3kc9vEUYmCS6shWxUxpxfqL -Uv2EGWzfvI0jrNC6esQ594yaIW06k2vYLevmgqOhfzdxL8+7Rm0FDZHoYwEMoXDM -UFAatSmaaJMbffC3KDofgBo/ggsIjxBL+Ryv1iih2vdMDx/g6CUkNXofQZMHmpOj -Rbmki0PO0V3qkIwiv2aUgp5Ro1Zd9TRb5PXcWeUjQvUblgvp1lk+YDWKAoxGJhWM -9O5lMBdqd0P2Mz10BYPncxIbP/xqJlUDGGa+72yKrrQuS3J6eXN6dG9mIFdpbGN6 -ecWEc2tpIDxrd2lsY3p5bnNraUBnaXRsYWIuY29tPokCNgQwAQgAIBYhBBLSfV2M -jpvxqrx8fHxkdo094zTnBQJjGh6yAh0gAAoJEHxkdo094zTnpZEP/2y+Uf4zhs77 -01Y13Onqb3reJvKa8wTFbhOe38KNUsRIXfy33tOAYyGWHufkc0llw6zHZC7hFEbS -wGFdlDqxykqfeSHx3NNBU8xxprl4d2c7c+/70EdNnsW4W/Ia1ZpVYQ0jpC3f/feL -dg7Vs4IXnxZ24NFN18lL5qyqJn1py22LchO+JR9nrGa5vYaiNT6zjU/RekBBt5HN -ttjvwocrRC/M+J1/zp68yh25DX7C0pFAmpQTrWnuVQYRoYlCAhJidGRiiRlyWzj/ -aGmT1Ix6LwnZQL08hgvWU5XFLKnLXRa+UJHvLCwSoR/1GHVvIK1lglE9U4ElKklb -m+SBR5pFsfSxIsep9IkX5YHdzkNezrJ8Z+TY55RqVDMg35Y7dhKXeSnUpp4EMVOE -SOb1pR6DEssBL0b4iJugEJcH+SJaVsS0VpJCg3Xswz43xz5YpXWchcEyLdqhiRkt -YyfRpHjueHQBOFFnPul1H6vOwHPn/l2Aa0nAJhUeEHgpXXFH/Wo4H/S818ijFwyj -3oBszQ9sNnG9Y96uaN+atVrTi1pRKl0FlEyDRTYcUMtWfiMzq9jlSkAY+wFiikuz -i0/QZJMkD4K7OTL/hdlaLkiUOYLNgoQAaU9BQGbI/HHb5ADKpx/sDQsFUx92ZPs5 -d4ZU9G2PBLy3aaOp/2qe4JPuUUAlL/sbiQJNBBMBCAA3FiEEEtJ9XYyOm/GqvHx8 -fGR2jT3jNOcFAmKfYccCGwMFCwIJDQMEFQgJCgUWAwECAAIeBQIXgAAKCRB8ZHaN -PeM0571PD/9UXjsNeoAsEjhVzVYuPlLSL6zWJ1kzfT1DOHvKFaIvIn1Fx2WXC8aT -E8frkMaPBUXR4BxeNJTZUg1R/9YxSLNs1JA+8FDpB/xM6ObiLV2LAFYSzLfZktoa -TXL44AQFPyBdzgeJja6leRpRKQSg1Vp3m2vsGMtwH1ZB4RxKUS1A/oOJcteMXLsI -5rlfIut7cMPzFmlAjTBeda+aItPieMi53THf1dMtXBB+q2VRd5HzL3ziEuoIwmsv -b9odaaXFqgEtq3afsbUL305oT8q6TX1tRwKAag1gB4hCH+y/CH0Lj9E6huoyQ9uj -G+0qSvRvfPLLcnpDBK/Pv4JQtMLkGpN1s9r4+OLNykw/Y3abhlrxWIshMLOqyMbx -vOCP9Ph/b5Xg2swo5C916hZ2Zl6b4mQb7qC4jRo94rMyH+oks5A8Zd+gJCP4T09L -+1nKrvZu/hOM77QU8eHikRVD6vZD5GX+lrad0Vcm/M7pB2vZouxILPmozaOyzJZh -G8Fi9xDVFJxfIfO2AhvAVq09rf8aswWi/NVYrr3lfyEWHlzOjdEaPRGA6OYXj+h3 -Y4/+b9ADP6pxFfZyL+XrcAq90D3TBqYQbx/Jteb+JRIElmBKpUAi07WvKyQXYdz2 -wjog8rgTABN1NsJfm1WuTlmHDvpYl2CNxIkQOkhbuwoRZK6862Vg4rQrS3J6eXN6 -dG9mIFdpbGN6ecWEc2tpIDxrd2lsY3p5bkByZWRoYXQuY29tPokCNgQwAQgAIBYh -BBLSfV2Mjpvxqrx8fHxkdo094zTnBQJn653CAh0gAAoJEHxkdo094zTnNucQAIV0 -k8Ws67p0eg8p2aG0XdhxkZd31Q5BG95rZ3Ef1we/H97HPsD2ZI/u3zadpDHNMbxu -B5duKV1lpiDL/2rXwkz5pnySTcPwWS/MFz+Qqzr0rb9teKmSUnOBTZw0tic0F+30 -fbRNlvE+Slg+SvSzSYpq2gbLjWrfnW/oQjLzh3yqN8LTREKCsNYpiDst9WWH6CM1 -6pEasv9o4s+wVJgvpkqrna80/uvlHAqr47mPqEJI2o1YJQdmuI6PjiBhsCan4uCR -SmoDA3zR0cXdvkeaM7E8qU3PVSVeDn/rV1xlylrOB66njoAA1o0HyQnWMaHPLRRf -k6MyAAbCPVCUYxklLZSq3f7nCVjPyn2elg9eQsxz57+h6cloSfD1kYzbk06XxFRq -Fu0XVb+0yl3UZuY2OkYTIWkveKwk6iTWImRurAIqqBciauod+KFRNsgCswPXLNvj -ewBD+uUqbFJGkRka1hJCkCMIrKFQ/+oNt0HlfrYJm78sjHKjOCzlfQ5iOvVS8N5a -Kh965DFJQS52XVHB3nUwYeztMk4uPMl0DqhEVAZf8ESFlwhv74gba4sOJOzmSFix -G7krpSf/modklMtGef9m7oR1+7qnEv7LrFyGUuOk3DaASTvIn4QWWOHBaZ86U9Rb -QCLxwrVfJX8RbsYazXU7C53miZFhvjjVk2a7bXbviQJNBBMBCAA3FiEEEtJ9XYyO -m/GqvHx8fGR2jT3jNOcFAmMqp8MCGwMFCwIJDQMEFQgJCgUWAwECAAIeBQIXgAAK -CRB8ZHaNPeM05+rvD/9Ok4euSID+L4uFxxtadWhLBVUFjRlBYf/LIMYjcP89m1H0 -jT3ysybECiQ/PmrlTJf0JOXC6nseZ+qwgfgYjHLhrUYFM+n2iSq3XtBxOMUw/cvR -f3qa+Je1554LYdYwDlhy2hzk15sIKjGUcC4yFxnJmhBg4Y9zp0T5OO8Ruia9ZDXS -3WfQKAV/OrAge+7Irgs1RL6tYFlrIdWOXMQnQCyOx2KREmf4rVtW3IXlmcuDpY+L -e6xVHc/2K0YxsBFTOCAF2Bgc+jgYMI2s1K9HGQEgMci4LPlR5DrU4eHGPf9pbSqQ -6R+FfxMtuB4ss1y8XHnu4BGtzb4SDlv4XoTpLcgmNXhqJgpY9boOILxlID7JzPOr -H5ggK4sO3vxhgV1PNmkr1jLuewu4FuhB+lbGnNhD4NhLTuFb0pr9jM192po2PANN -uudjBnh5CtOqcS159Hw7+zpdymtbch6FsJu7BP08obrGE6JA302kO6Z2aMso/yZR -FZ/emvOGXU03ViCPWKuqpNHCZm0oTBcxGvFB60y73NPqoeQCXKlnAiiNH3wgvHFA -OnYkcTRpzltw8p8NLbS4QydFGKFBSCYgbhKOrqfcUMFR4ZRe7Nftg4BiQbvwFkg3 -FX9bBWrW3xJvUV2grW0G1KNOPNoNJcR/UHnyoJr2Xme5WIcdOssNHdDyGOasPIkC -MwQQAQoAHRYhBIDHu5fuYfYZ8XbJ7lmIoMA60/r8BQJjd+odAAoJEFmIoMA60/r8 -RWwQAJySS87+am6DqOUntFQO2uqcqsqPQ6ViB9yscn7M0M9juYZkabJUVxPA+E2n -ukoqpOda0RCzFXXc6Ixaih8k65hbFeTZJ01QSBgydL6LlN5E4RRVEjyVO+gkttCC -rt1biOoO2vXZAUiqqpMxmJfEAvyupMGT17d1r4jez0ocvwukWe2kfQc8BVQrqqbI -r+fX329quzHv5QbPchMxrn901rEzlxuyHv9HTlC5M+9j2Lvew8tR1IO/Av28T2FC -tSoguPl42VUljNd4XxaVDLOoHRsNTeR35YLZz7jPAl/OxVAHNjslMM2WAVKRYxtg -LMIBkIkDLcBGriedh6GIzr+HMD2UHWLhT5kB0SPw6vjn2oNzLtvgmw5nlfdLaXqG -W9qGtsLZehxNtrzK+6bOC496ONyx+F2dYkzIhgsJ/eRpylLppxKYqHTIa41iPoNH -JZE5MvJflKjlD2MlRR58AGrI5ZfUM7juTu+ZcOhUvimTD37n1pfqAtuvP8MbwXkH -7zdgA5lSK9A+rM3iLLLg91XDAavBer8sFitrCkzLOMSAvH3lgknDghsl5IvkDuVf -Hf0Viy+9nrq1O+uFbIvV/H2J/wjytCGLbUloETrL7PvlUXf5Z4aiqetgnMdCElHW -DRtdUVGV3suQE1nkdAHbFBM+Uh2s/95OSlg1pMXJCu7UYthYiQIzBBABCgAdFiEE -qUDUNJksLo6ZED1QIk+n58yCpmQFAmN/UtYACgkQIk+n58yCpmTKrQ/8ChJBkkc/ -Wqc6M+pmwtFSfdM+gZleytPd1M7JOoJ3rYjkoUVVnglDng+PPUXGObsi6hmWrx4Y -pUniFlZlsw4xlqdotggulBJ3CZEua85URMOOe9SJclYMKLW+ozR5a+Bke393os3A -X58Y84VypI/vvXgOV0cXSNVvYLibK6B/HTiwV8kSyG4VOx+0Vuqg6rs7o/Avgwww -fhtuHqm34Bf05UbdlSgK3PhAqQ3RghAIEFYTrx3r/xBmTgg5HzS0e6OuPvI7qYkS -izHb7lh8ByuJDrtpofbMHkApFKnagZvVKCcyYY6e80DpF69gCvGxcnYtYGlIjCzF -kJzORbehDAaYlOHU101o0nEl88nNJfZk7IwvfSoexTQFbTYrCEkcGq2jHZmewZG3 -geovtOjvibFHyjnahCcbQEIKTe46GDg2feJkScYwICeLl4ZbKMH+Kp+uT1e7kyWH -+z5StA2HOjmGUc8HalBApaEyhJuOGaME+4llci62G0dvpF2IyveErhx3MaE5nLd4 -rXeZkFEwsldcDVOdhudAznFmNuUHnh6x0bnf8ga8vfYORzawB0v0HXiPwLJqXexN -HbqOr9kvdIDglSqivpgBJPAuiVxApApvnK8TmA2Mwy4zulwYLclBM/dmwimDZxgI -4xcXnKBeUjzSmIMTXgq7/3dupv23UINByBqJAjMEEAEKAB0WIQRXDmMrk0YTEHNq -e2+CizmmotE2fwUCY4COMAAKCRCCizmmotE2fzOLD/4jkJi5yZNZS2b+EggVomsS -Qr3vmTX5NJlbdqFnJKwHrzad9F861hAM/xhOudYxGsgSE4kIbxdaBTC4tL8ZqAbn -WuMFRVxffm0tu9YwG797fxPBQiU9vhI4t1dm+x2De5sdZBz2TI9soI+tWKwB9swb -1iZ/43Zkj2fmc2zYOyBLPhjT41QYwzB0dBUqMlvJBPEg2/qh97H0qSET29xXucYN -LSQaN+Briv0JcASXNBr2WEyTSH8baLYIGUc71IvKBvvL3JIrx/eRlRV3+UDnsxuc -och+aJT2c5CikYl3uhN3ARrv3SkFWKziOHkH9tNrqP3hpYoVPcJju2EwkcHv9S5n -UT9ok/B74aNI8l6vW3K9UDCVwsnO6pKZFjFCJ3YLmTIaAFClvfRtgTFPuzeROSla -UHrDFEUmbShXvNndt9gPu/PrfGoTcw7t2mZVs7aXWz7uHktqR0jC/2vvBnWicJiy -I9DlCmVIjlH1Y5K7Gg4mNsWqRinSThuj3/o1mB9c6yTSvXg5wqtX+vTYL4B1ZmAV -z37n1/BbHXWFIboyXLDyjMdgxeR2QkBZbNQj9ShxGSRuKYRXWXWXIQ8AVSGqo/r1 -36S0XRpTkzq3eSmkNQoXZoueXC+ibKvI8sgx7Xv8JUcfVkp0wEm5EVsjVlXI6Xz3 -jnzNyR65WZ1/81iNo/PkwIkCMwQQAQoAHRYhBJvQfg4MUfjVlne3VBuTQ307QWKb -BQJjiHvpAAoJEBuTQ307QWKb32UP/0mGP0/iH80jH4kzccAH3KKR/6zs14qK4w66 -JJXhjPvLf1rW6aJRtf+e53Px7MA5d5ERY5bA1QOdsnxxoloyNDLc5VkOfctXygnC -H8No5IRhin+b/l7rC/BPX0q437ilcxAS6vTmKqr+kpZJ2qZjNFDRm6Ow0hCe50ws -sbVaKwhivjJ6FVw2ncWgbj1ZAS8XQwsxW+jfKhdWYdszdYMXAzisME16kMHFkZ/I -4hsuSk/ewU5BT7189Lf8ln4ETl3HqaKcSeh/hV6Szvvz26Ykv8391KlHusrtqwOt -RCpbIugiyjRDMOHaw1W6rvIET8qoFfUPCyakAZ5lRBAYg6tX2cxgy1jhdysB4umk -b+vSp5Mw1izbnrhqb+KjfyJjZjUaEs3LXxH6FDJJSnn95mkP15LIPWcfqFizsskE -t9tpei57AlxQZlJ+BIcxWrsq2+Holz6jmgRm/7ckLzlxf7PGnTKX/5oas8zPboi2 -AkO/ocU3P0MbwzvZiAvFcHvIDS3VbiKwY6dVr2LTQSDDkdK+++PIcojx6rpsjDAI -hHR/6hDsF3UQjVKoQ+IoTIF+MqGC7n0XfaGE2Vm/KaopqYA8yERStliVaFqgUvx0 -p3s/krYPwW7xWveTBJc69dlA70Kb2UNYQpW8IzylsrpJ6C46Hnj16OgOJn8UMtxU -NJ57V+dqiHUEEBYKAB0WIQTR9fu1npxgoBF1QFgHK8J5kq4eLgUCZ1F2FQAKCRAH -K8J5kq4eLtJrAQDdu+H4b50nVIuJHx5Vox+2nfFn8wkMa/4YtJPAu2lv8wEA19FR -fxNriAnppRJ9RmIQQ7Yze62a9zu+QWU/hqbywwKJAjMEEAEIAB0WIQRb71VikIEC -+1Zye3zFLXr+hfJVCQUCZ6DP9AAKCRDFLXr+hfJVCXG/D/9qrinrkvpovg0VXIBF -oPjVkJXwCeGLcIpZQcjRbglqg51UIg2veIJkDPPdEtDGRP8uUwII19FmEx9vy8u1 -MvifXmFYVGkEIWbkmHMidazaHBHvnjYU64vNKu01Xo0U2ZFJztiFoUSnG0GQspni -EBtkqLxRCl04R7UBgeCg9tK3XYtkZfShT8z+YH7yPT5nBLTkzzPUyXAQml2X8vyy -E7ZOnRImF9jDCFSesDSNJ1Qkac3uwg6pQHsBrKiKrFKvmblkJy6dHwm9e77NPfv5 -TqUSXy7wum+5iF+djCHJhK1fbRe+q2gNLd3+8M/nD5u28z09BjlIClKTjIIbhkND -wmvCJW/3TyoH0UOXziXIzKKMvibpZ1C/HZvnU3S9WGx9W1nGfHCqeLhL0k7USRuN -wjt5MPxbB4vZbdWxxzjjwMTXp4bVaU7RsmK/z8W+ViCpGziNqynvRT3rUN9g791/ -+5QXxDG8al5/B24U/H6E3j8fPfJYdcDZ8ZW5dSxCFcBlEiwJPrnSkIcYw+v374Y0 -CQUTdmywZED9dzgTHfN/mLlpHInOJlxi7Mr3X66UBH98h0+58VJZ13GF2d0QGx3q -OJHl1lsoq+0wI3j4jFsDZ3TNaLj1nUtiVnYLSOnGSpM98vzqftWr18jQsXB9fJ5H -zLVL8r4251W/syFGySXx+NELlLQuS3J6eXN6dG9mIFdpbGN6ecWEc2tpIDxrd2ls -Y3p5bnNraUByZWRoYXQuY29tPokCNgQwAQgAIBYhBBLSfV2Mjpvxqrx8fHxkdo09 -4zTnBQJn652yAh0gAAoJEHxkdo094zTnHgwQAK6aN11gTBBsb+R8NiQ+vRIG8SrX -UMZDggXwsL0DGfJFDxxlBmNCsujD3A52ic2cOdac+cfw5lsFH2wlcs8WH3mGT7C5 -7R+9uEKpCpgq2J61FxUfcSKAe2VnDYJZPj0Qo1m4DQ2df1Pjp3DMvB3IfCQ9dpRv -pZHb2/8Gn6TG6mbzceKdizV8UDrIZt9u9BNKvsyQTfsS4khvzZs662XPwjuEuRFd -/1ZFu7SdOz7bero1Y33Lac2u3pyA8tzscBznF0QmU7HIuvChiIs3TTQ4Fx6wf1+U -8bTe2hQaMrwYPAbs4q9kOtEIFCmov/YiPzAz/nF6XeOtRMVqZ32eAGqOXfEfT5mL -h6EixqSt0QzixetNyMD15ij2X2OppbEZs4zPh1iHhghhoEkvqa71i2hTCmUw5yeV -akqMHDh2M532JzR5KJYPdoJQAlsU36eRzjHCFamH4MIJzquEiGTLsSl5RnnjFxY6 -Z/Ft9DytsQtHgcxWrCElsFNluBPTGiIkIz4KmHm3DhdfDlXpfefZDHt0LF7PeOvX -QtgbozFQogSH8T1Q9Jzytw0r6eZDl6pSbYr1J7zxKOCJHO2UnI0wEn9uxijlsfpW -SJZUpL57JVreU4ZFwzWRY/jPdiLqPg882kNiy2klAKah+c3A9gpjh8VCW6X/s/z6 -RxdPXSw4ynJJP5mIiQJNBBMBCAA3FiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAmMr -DTUCGwMFCwIJDQMEFQgJCgUWAwECAAIeBQIXgAAKCRB8ZHaNPeM056+sD/4xuIyI -M4v008E+9ES6qTLCjC5AYOwI23NLGtFMOD7ge76r7q/m4O0pyg3vjG7WO6z7uYMu -Q4QUpMVny71Lyw1D4P69LbWca/P6a8iCO/nHkpncvxnD37HBfm+ULHkK0ITT0azE -sKlId0CzYrp4NYtr3ry2IqOOfAIw+2TPXUnHsN3qYkEIbgmOm+sK6ob8vM+q1qe3 -HGDHOP2QwmGp1pEzaegc3CSU6OKx03coKkdpsmF7W6YkvAifannh+OeojswNfQ+u -RLK86YneA+7Xd21txLCwrdJJxiComq9jXsSf7gPRRQciOk0XyYSdTJRprmnBclib -PMQLKA8U8cN0jQ0NrJw2aspOjo+wQfwqexRhdbJCQgckUc/oUYTJ6LeWXIo5nOJK -1AkoUo+AbANQcF9Y4ntPJmU1XnOwqvam4bQlsRUPdXqv5a/kh5aDsTqvVolS4iSG -ZL7tBjdsWRSxf3iRVqbfq4aPzZ/SzRe9exPUsdhshp8+Utre0sbAT2s2PvhrjY6i -Yak4WjMJOQMGsX1hxvFORSxtu6msr8Rjx6NVKZ8PJnMmq9YKKSlGA3/cez5/elg4 -3nw5fzrdV6ZdHA1TIZ0njDCE8KCYwCR0V72l7mS7GY7kR3JemVifGYiMkIl4j5ld -ZgU3mlOBSpUk7b/46gfLX+fJWojFBAiI8U/C5YkCMwQQAQoAHRYhBIDHu5fuYfYZ -8XbJ7lmIoMA60/r8BQJjd+oeAAoJEFmIoMA60/r8P3sP/0mBVbaqVSuum/F9Ct2o -KBAzCJPNn4NJF4oBEW9IE17DEOHUt3IyL2E7Xu+NEaVnPBKL1CWsnqEsE2HhSNjl -mLGekF/8U4CtZNqjuZW/MOYqOe0cSlZkLfn3/5sXV5DmcTLtGjKvG4Ij0c3j+Ukp -0NLRt9PmMF3EavfPBpy9+GrY2H0Avmj/Xba73sV0XswbaHfsv1Lzgh3IcGMyKcsY -cS26u9pfCLm/uffWxRSPv+FegCjbw+woVWZ5Hscw7+BUZ86DDB7eMhlG7OGhkpZP -BeWNIRPpT64daHA0MWLdhSC1vyuX4mXtp9/q5RvULvRgU2KEnAmCPcVZTPAWYYKj -Vd1I0LWhn1zR70AvPS5IYZVXhJl0E+R/E63iqjsUyouc+7hCSZqSVoAqDE5t+UaQ -KmqgbS1qznY2WagSFMh0wTiVilhONOJR38+LTpVp6skSr8Xs0iJYasb1GEaToauL -+lP6jyMtz7972aeBmFPGMOmLWe1vzMQe141JgwXYL7rj2W91iwRDbDMlO3v7j93o -tMF4F9EMlyiNbjrd28B27rj3W6hpMBXuBSqGuwvEk4XceB1huXge54RA/U0smDne -KOEGSpN6969qhMKhy6QKtB6UOD00ZLudiSgEZSWFvD8Ik0RgtfY1Sx9CODIJBEl2 -ARKs4HjWjA2Dtt/4U+f8mxC1iQIzBBABCgAdFiEEqUDUNJksLo6ZED1QIk+n58yC -pmQFAmN/UtYACgkQIk+n58yCpmR2UxAAoYjM/Kahz+xo+aZ3uCj+MCc5wYh2yJ3L -l97wv0aYXHlFUY3VksD0kS3DXKqIQ1HqU+jN7zdx/GaW37y0dTLtruYhfqMcbqgL -hlAetv9QG8S7FXVzifBzzSSAcr8NT41Ppi4oCkOZw/y6W6D0I0KJFHe43IpjgFfU -pcr5qideJonTsBCMu0fjBJjlC3ZCokmF6iRfcRqNXAfcgJtaNIeC1Utq7pRbAeKk -MAJ6RLtuVp6MHfTgLghNBMG+GEWI1Q8jOSt9MCxe8iKPUCJjBbrY8PUh59uDIpYN -SHQb85yz1WJ3jsKEcxD9YaVHXn6mcT3tQrlQ1VM9OMsKuQ/l09n1YS758JAxddls -lTs153TQnu0TDHbl7sh7ZIAEfauivIDb+dHYsSD5Pm+tPXOfgKLgilyBKWZ+0gQ2 -EyyD5QkPZ9l7sEBJVohAC2ly64GRW48kPln2R4ZzUYq0agXcQVMHHm0F0j+F86TE -XTBviCTLaF+jKTMYUQtWY0qolLQPUi5Tojkj0gJlXWfiCryU+SSLGGkHIpc0FepI -idKNz0hsIcC3bHvxgjw5jdCGlWGhes+waihm9ElTMzO+3iBAVjnqO9lBdaZigdTs -33HcwLmCXPXtCYXASiP3Trct/FNbxgl4x2PEKxbEfYf9N6NQY4kzLu6GrfT8ZKzA -gkO7V66VoCSJAjMEEAEKAB0WIQRXDmMrk0YTEHNqe2+CizmmotE2fwUCY4COMAAK -CRCCizmmotE2f/bdEACz+wFDNGuH4Wia5/1m5FREomThGp1GyoZ/hG4ndgYkxY70 -NcgM6vFURv67P/4wQee7mPM8c9f7RTZGJ1+LkuNjZs932JwLpjM5g4ZCX5aopE1m -UT77vQLAfrn5UWkQG4xffOxkGQeBMSPSSxEGcmQokVHF4/Nr3GIaQKD35VligIQ5 -+AsuhuPBhTJBHDw0eTA+G22tOX1tvhI96wtsQiZqkut9xhqa/OXPiUk1nPsM9Z8a -CIcs+u/gEMrXCGkOJbQHV6ZyMKHOf/U6Psl9q56wWVoE3fzhqGzvVrn4FOTq7vvd -C2fZ5KZz8UIad5kXTfIy8EX6YnXorphyL5xLRxsw7PqkvIKs8q0WlKME5Xb7xJHE -plXodsn2JahWCqEVT/SkDI+0M6wW/V38G8U4YeME1Ff23k73KEVY1im+8vgiPxTW -y0YPZkK3n49o0Il7ymPoH2NtURjD0BE4BfUnsGntiU+pgY4ys5vvKZHgNj5fu2W6 -FMjN/fBPmBPRV/0+m4VoNisdvrD1FO4O5SAue9KfVoteGyy8rvlAneeiNG3mwGEM -V+Hp8ksJjW0g7WW94HzGzBr30yfjtqmgu03YFfEIu6MYf3N9XtYy2ZYvsV0Oh35l -HxbeNLWMxAqIYRyO+6pxG2MdDtoYNLGxh/BS7x08UbB5rg39LGcuNCx5G3+LXokC -MwQQAQoAHRYhBJvQfg4MUfjVlne3VBuTQ307QWKbBQJjiHvqAAoJEBuTQ307QWKb -0FMP/ifmFzE6Q60f4UaILJFjaGTcs8R6Kn4Tc3GhzVc1JR1wnfE6I4Um7U1f91Wq -R5rXlQrvf6nxGfT7orrXjkrkRVbldveGfRERBc7L9GBG/QKvsy1km5b+n40+JQ34 -ySwvkvy2iQ8kdfloJsSwRNqhX2DW96xz3PGn3zzBVG8MjpatnLpmmxF8iereQGbO -3XaPogVL6dKg/T0IbUqVO0XMshnMA+F1luG7bNIGWaBVb+/JeLOltUkuyZAIbywJ -p9cI8fFWeTqGpISYDKFiOHss3wRlBt7J6PFslSNNyOoqF3Yrt53ykWpcozNE2td3 -iNHSmTKkjqnSuclIO7fham1y9RCibvSfBJv901+7YGdUTVb9ZujLe9iwTOJoeQEV -wYREgBNycD0Nta2T3hKHtgXiIo6N5u8Bra/5eMoQ4eekyuanZSDjU7IvmWsLFRNY -iAPvu++YwHp4bUmdj6KzK6bXinCtOCDI3jdh/H19caL8BA63hdjQVb6gFIjLLYQd -/D04Ss/f9248ipkjsKMdwb150mDtGJA62NElp+BHjJN9x0z60DPGo9usArV8DSfJ -uqxfFgX4aFpcv5UdOaiF7zzqHZMdwWZfvsBFY5GfnsqfroHOgcvCKQ+gdnAIuIwg -37BT/UZu+g0YHHAsBVU/xCGJb7czBbWtdM5x+Gm+l/XZFrcLiHUEEBYKAB0WIQTR -9fu1npxgoBF1QFgHK8J5kq4eLgUCZ1F2FQAKCRAHK8J5kq4eLpinAQCrT2SeVHwR -Y3ZUeUY8r9yQppTNfD/EK14ZzWGX1nnElAD+ITnTq91JwXJFpbj+OMegNwXr54NA -SzVERubMfiqkFAmJAjMEEAEIAB0WIQRb71VikIEC+1Zye3zFLXr+hfJVCQUCZ6DP -9AAKCRDFLXr+hfJVCeLZEACljNC9ICnZ5O32ZwITfiUY6yEm4yR+AouLg1/hjBHM -PCpaCvko/oaj+TchlmUILYNtFXX9A4C41Y6tydSLx/PnUtjalLSShEEdQUXNl8rI -vx9h4C6ACmdHszooRgROq/FpWvKGR39L5cPKdxnilBXHMB88iWEohagzEeGYS4Hd -vH4Hlzrtqe4kMRPu6AsdTqr58C61aIXhh+qpY+abASgNpaz5MWAgUHP8BmfJiz9c -ATCug+yW9IAd7StH9wKMbrwmQKXWWPoooKhD7HBxrW2CNCjLkwhjAVfNEY3b1sQQ -H+Mrm4ED1ndEFlJHXpeCsc48ynxSwJnlOt03j84IuFya8Y3lyPY1YhPvyloproie -3MqcrPVad6b0PiGoLDAepULIoPSmi5VpIlo0VYgaTK4hvqjNplFUfKrmny5o9rYh -OvNsDJJLRXCBrn1ATNu1cg+N0kkXQH5EDbGQhXqX7umgpyB4heKwJx9fkuhedF+l -OO9NqNgyOvnaXfAQ7dNW2k2/lqMzQXQ4AxzT9j1RE/CTEh+VF36xM6oWBxmxfVXl -0MH0ZCR7pQ+1rSzwlEfTOyOby2OA93XKmpG7RU7VW9DZdqpBlEd7k7hMNUcfAOnR -nKmvIMKZ2ThJF6plYoA3+pU06sMzJhgOS6540Ng63RZ+xNU+DYFl/zhWVOMzyrCX -grQ3S3J6eXN6dG9mIFdpbGN6ecWEc2tpIDxrcnp5c3p0b2Yud2lsY3p5bnNraUBy -ZWRoYXQuY29tPokCNgQwAQgAIBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJn652y -Ah0gAAoJEHxkdo094zTnW58P/3xmJeUEDn/ZeCuidxxfvgKhPFtPyA0mis6dCEji -JoDlokjDiXDW0h4TAWupQ6YdFb0GghlplPoGHWxigGq3vktgvy29a0qiU+/4SZt5 -3wlTMt+bnHmbZax3phu/a/TejmDwv638XRgqA1nWjjuxoSIfpsCSMA8u+G5rAVXc -tbyhZlhEtLlvglYrgtBHxU+220gUwTqqhEg7ijkVm3eRuxf5qXa7f1mJl2LgleGM -vDZtO9HPjF2k7ZI6aa6RQbEgeMIMWGHeUMudcErauTOqSLZHMUY6pgqhslcwRLOu -sXc9xPk+gfrHff6IuDb2Fo2afliicwqvta8o/YKuouldO0kyOkZmry1AznZf6D68 -jREMsl78/BnhYTYJHB9p3UD3yGnNzaSz7DV7ZD+CBx9Ao4SXCbm4LSo3B2FzNJdh -U264GTHAFs5CrwrkwHDiUo+FXjhycM9P+JPn1tsKgVAGrW14aHU/eWt1u8wOUhDu -uIxFdxvdAYz09wKGIF8RHUc+Gz5RlwtkFa6HmPROGtlVBkYocOIhX3XTHrfrhr1/ -0RY8X6+BwZ0jylkRFoQ8Y5Gal7L51sHNzNMERn8rZzuYwe/Y/QhDvBMmZwUQlT/P -2Kb9J1E+NraBWwQXe0FDhMU8XhbCSb1r6phdkWgf0Pk3TQAqJwcG7d6JfPKzql8l -kdzmiQJNBBMBCAA3FiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAmMrDUgCGwMFCwIJ -DQMEFQgJCgUWAwECAAIeBQIXgAAKCRB8ZHaNPeM05+eMD/4qSexwc5Cck/RbtKAs -7+NGpEhXgCEQ+zBZmMmpsNUcKJ3h5H9OSmy1kpRc7nYgnUJSOGN5stNOli5HW6hI -VC6I/3F7cpuacK5vj8MybiYSZyvsfT2xZRN/M0J2e2+hSLzo9k2H2hkrz8XUIfbx -MrFh0yuL4DX9BgA9glowgnrS5BgQ3y+10894mJfLbC+K7JSJMukOOXUmiFre3j/m -T9NjALMxckvjX2Yf1Td8W2sZTuQg0TkS3f2AFrqkywgYKrJt6k3IAWlSHgcfVL/k -HBYKcwXg+g3gvsR+8ToEBfWgEDL/nuHUe0jb6z9ajhwIIkFkgkB5Bl1qjVb6eg+8 -poP+j/K4RqhKFGl5uUNgjDV4bICARq5vi+avfve01zo9FtUQfW9o9A2vwaXrhVop -Eqh2K0vMBO+xDhfNfVvr8b+xN+YqoVX0xKhJdHhwD3rduUr9WJ2q9y7hDl/4p9M6 -lKhW8bGpWtP2OEoOwUnzSdgIECz1AJW5X+YjlPiQjyMbAzOhi0lm3Ub4Ej2ReraG -LBAxgZpZ7cRVQtMJhh1KXaVxCYPT5su9Sc+kT7QyO+c5mGPMQWEKLMPRRC6Pnjdz -8ErteIuRfh5VYtY13YIOzxCVAVC819b5y5wx9pY+XJ7EQZ30h6dYYxwEeQjWJYYW -Aa7bRycg9U++459xJSWEjRPMzokCMwQQAQoAHRYhBIDHu5fuYfYZ8XbJ7lmIoMA6 -0/r8BQJjd+oeAAoJEFmIoMA60/r8drcP/0sNUA+hvurTRXJI9UhP7l2dRaqh+3M7 -zYMNQGooUbEPM1Uk/FgeIr5o7SaYMcRbISM5abSrl6ykSVDjt1VbGMr/+nwfYGmw -qE0dcthi8d2gtCxZ1iNZGOQMD+ku6kzzlpPrAuY27rJ62MhoWfYAgN44xBV1tEr2 -ZmZw8JFBPCFmnpGemibVqCCha/lP5q7bcHqn59w2p1wyP41BHH3U5NLuaIdEjgwY -9gkns6VM40/YfG+lpm1Wp97rFbyNGhXAFdXWBNjD6GwY1cKH/mavuDoLanE/hoG+ -4SbSo73Q/s9eAeAPPMi9Zkg5udhymjg8oe0JjiX5sfnXMtF6HTmR6FMvQbLMa9v0 -QlKsP4ymKCPzpwtkGmZCExrepB71JK/2vdKrQNvfBvj7dtTux1BwhtIT69r0r/U0 -tU7mJUfD1VIl1tWc2K5iTIJWhoF/Ge2iL2UQL5BdFj3aP2GR4T3gVg2cmI/sgw3d -UcaDvkncWYbTBvg8NO8DGMWV+c2sJJ5h7U3Kj64WCf9W5jCkiyS3H3JvgsVMFG6K -X98N+K0a2fn0e1y4ubuWXsNTTB1ae0wf2CKlGTm+Zh9/JgBduAZfHFSXS3t+3LTQ -MC5K6Xs8n5LWkq60u1HP0XRf6e369DcAwSgqYZH00xyDBxvnH1j5Zt4eXvBgeeBf -JgO508/EKXl0iQIzBBABCgAdFiEEqUDUNJksLo6ZED1QIk+n58yCpmQFAmN/UtYA -CgkQIk+n58yCpmSQbQ/+LIl3ntD8Vr63oVa4+u411FndMOILy4hWNYTyVnqwPuwB -riABgweGjguS/Q0dQEdr6yDA+CyrJdtocj66XayHqlQ3Xnbsql0hUQQNjLXc6/tI -e2MPjjPp1Wjac/HdaizKUtlXEnm5jXUrXuMmrCc3RgjiuW7/wd9HQify5jI/B+P1 -2QYiSVLIwSPRFQ/ozKFSRAeN+wvor4UULbkWODY5PdmVhNPn6cbqzHOqVYmW1iVi -vRye2XNoFD6RGk/ynnRfgYvJcv4cnZ1eH/xUwlfQH5MlScH6z+nf0+Qagyklbb91 -bfUVkKdmrEZ58/Rp3YolnSw0d5Vn0IcCMiGakrOJionQ2PrZs6qlqnLsM9e7/gUL -6VGF2Q32BOGhwulppHyWAm0rGfLbLs5U36T4BkWO4WNSSCAqob9pcFhDFU06fXzO -htfK+cWyIxQ9ZmxA6BzvE72i9SuATJI5fggTirgPEQrPjufP0Y7a8MPinlt7A0Hn -Uk4ld5yliVDhh2whPh3lUGxrnCVOLPOZSMoCGQhe/hCon3DQkSQWR7J1RnrwnQ11 -mDQTugmhvhyA9Ro52IuQ5KrbYxAU823dZaTPcn6xXhM4iiE4MP1cfQDGX4IcYcp0 -c50ypszbfEtDXy0USKYTVIQDx6ksh9HK5b57P0bMCZ2+1xb8p4QBoAfLNpALxCuJ -AjMEEAEKAB0WIQRXDmMrk0YTEHNqe2+CizmmotE2fwUCY4COMAAKCRCCizmmotE2 -f5SuEACuBpv0+yG68eop6ukXv4/KF3oPjtCzDSj3DBfjD7uu178uyIxJHFarcpuO -Z/MS8wIti+EGQ6dh1fLhagOgPx0GyAMsQK59dajQzJNAdEs7OxduC4BDd0rmYTJu -rGLlT+skIaU26YbLQBeWUWtU4uflx8bdJMWXB3JJCzGa5FRaAioNCUL8AABXIijm -9JqnO4TzF17GzzjI9kpStvO2DXhxwNd1Ek+7xbQegic5gqPSHCuY+veGZVhcA77j -bJd9z1sZm/9E9mYvMjFSJufEKH0TCJE69kG9ytjJPSjSvCochuqB4OsdHdNbfkXZ -4zoCnjRNF1UcRGjudOMpP+zCy15enCQMKARBdQdTKXGSjCkG5IyFQxLP4x4rMc9D -V8V0zGsx/NKExBKHCr7G7IVCdBVfxQpbkafHkziHsZycqTVDRoAuN1wh93SwYqDE -nRzxYHiyv6+zrsFH+6j7UpoymGQp0Qx/mh6H+V8AnTJ8B39az2wfDMaklYOf+xuA -S+dWenXyQzQnG1dUf/WljSFo95GI9ewsDTfyFIBu93RgyspAWNm1kH2/C+kjIoaD -Vh4A37jMWnX/x8OZU2P9MZAuydHHj2eLx8U0MOgb42ZRCMPp0dwnd6DIklw8jwXm -UXhkGMQpMsKjf9lZDa2UhAHGEZDn4mK4QEonUfI3Q931+Zbx54kCMwQQAQoAHRYh -BJvQfg4MUfjVlne3VBuTQ307QWKbBQJjiHvqAAoJEBuTQ307QWKbiuUQAJNOYlDm -2TDNVnQmv64OC6wVjy45yIYaa7uOIh5eReTKNlFJ9WCvutdxahyVNrVdDR4lnfmV -TnWeMHyeXQTwfxJwzHILr0TI6QIzdjtGSxiukyGgSR6a4jskzuo1NoGusg6qIqgI -TocADNDcwVMxMST/ES4wL+A9R7zsTwklv4L5qZetNBoWc8ZtuVSsAMGsS2gMRNBz -xccEciaQADKzvFYIqDVY7qjShG9Vx6dhIvPROKAu3K77WGjR7FwLjz7gs/XL3lFc -GkxvL438gt76BCNKvu4/lPNtmE4bNfjO0LvW5qNtTmZ+FxKaVUGu4gDPNIGpvgTn -PpnMCyXnrht7SY2X8rI6cGHDi+vkQ4fj5Cqqmc8mJSW1afrdbpo9Ljkq31iRQLSt -eDIL7GQkTnTBKd2ohrzjFc3ZquDXLfNAxO5e/ZnXVRT3t2ZFpoPQFByqY8ToCKeH -jRIlv4hIiWb9BI+3ljZU8AJ3js/LWqi2Fji/JJLPKhIrrOoDijjh+znOa6zOA2Jd -ECxqeM/a3kYfshfv0edS7yzp/xJPf2n1sXAnmesnhBQsoi8d+qtFLXagG3KgdCu4 -UwgXNN7HJzTAl87YNAB73hteScaBGxqnApX7rfvPjJ+aQ8B912HKlShLfc6ZXowq -2oV93yK6RMQYEKhTReZxhIhHQiUgVhT+bLNIiHUEEBYKAB0WIQTR9fu1npxgoBF1 -QFgHK8J5kq4eLgUCZ1F2FQAKCRAHK8J5kq4eLqIzAQDYXPIRvWDqxGfOVUavmY1q -nIFMuEHgX9+RQzrsiK+BQAD/eca3PyjRVj/EZtTtecpk9I61ACpwo4IDe2cCq+GC -eQmJAjMEEAEIAB0WIQRb71VikIEC+1Zye3zFLXr+hfJVCQUCZ6DP9AAKCRDFLXr+ -hfJVCVchEACTdEGFsRsVBNU2uffiMkT7kL+tjG3FmsT2rl8JmCEewNIXG0BP7hcX -ZSKrTO94RaTJKQJaJ9pqHWayiuuGssJqfnBuq9ORWTOxD8flgsWu07vzGWcPhN41 -/iOqxylI/RLnEkZwPQiqY06kcaBzHujHoij0umRtVzU1zUa488C+x4XT8sZEjvGU -JHRKJxMl8pjN7P7a7gcwfyB59jr3iztaX9yAPnckJZJWyq5MUS3PddM3lkqjMVGy -oGLK5dkAC6izevfRvR6kLHGHeFF9cbUshEmH8K6yzJK9wSyofwTFW/2+hzNzQ58S -FtK+vWhE7lHGhjxD7cVV7nAy/h03juDlF81bETvffvbpzoBtoXTONEyPkCEBO5+W -YDAu5x7mPZlyoUo4wDRUDEcMdklQRvkIe1QbVBkK02BecVui5jNCRPLlfy1KVErw -vlfzvn1oDk1nZmypYqhBnCVWDOhzu1UEW/uzHA6hE++ZW1WlUmRuwNbo4SlRC3yx -UhqR45trypiD3+bj54Q9cZpqoN0fDA7WV9YmRNB3m+nOv9OBlsA1nk+gOxzCZOmy -rxIOUf7UnmIwUa1DcNbCs9S2oJX4bxcc9TBLy4RhWUF5ZpwKs+B+mwz0pFipoD4E -st+OfhksLcEtSsz9uaEfLIF4nH/wVEvW1zHhULBaiCayhceP71ZymbQuS3J6eXN6 -dG9mIFdpbGN6ecWEc2tpIDxrd2lsY3p5bnNraUBrZXJuZWwub3JnPokCTgQTAQgA -OBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJjo19jAhsDBgsJCAINAwQVCgkIBRYD -AgEAAh4FAheAAAoJEHxkdo094zTnm6EQAIU5K/C0d2/3Z2GUQWP9kFxUsuL5Q+P6 -fxRmnDIXGWuorSlEVtW0VWZM1pStBpqPqVkg5bP/tLO2o6YzXumPK3f4q8Mtg5OY -41xuhFqW34OxXLvtbSFEaHTZp7y5p9sUYleb4+pgkEMEVCqJvXaswVqdRQNKH1Tu -roTqt2QYT3yGIW+ulpLpH0SBJYF87/uQXzCR3HQhnxOdX+FjO+RzoD/BMLzaR1yz -MiNQDItSaKR82tn/ERyVLeum7uB4GdaSsQkksmeLoLxeqfXLtYWEI0+gVOPMdA+w -xJxGJDHuHbujkJFzvq/btAvdMNAkjwv0EGY4knorAzPeIuzIKCD/UzCwNWK8qWF0 -pxwKiiwgqalq+3Ae2ecm1hw/HPUxXWTOqb2gmRt5XebDXzflX1QY2YMElx7c/aXS -4p8M+RdmdEUKjQg1mJ6ETg30wnF+Hbhzd/MwEDLELAHaeRBznjRzv6qBip6cb6f6 -mBJZ43imCDXTgvBAr7cLD1XHaPYHtgAWh7CMCXqQvsb9mDCOjorPWa8oImLsGJAN -eDSpJxKCbd5ecsB8es+2U4sqlj8gghw7ojmn4ZBDbQRBYAnryefr212UZxXANmVw -u3nOolGrXFYLnKwdGQe7kCqL1WnTjyX8TPiyzvhZnJMsx8Ye4qT8t3Wzbul21gpu -8e0rwKbe6frxiHUEEBYKAB0WIQTR9fu1npxgoBF1QFgHK8J5kq4eLgUCZ1F2FQAK -CRAHK8J5kq4eLtBGAQCJ/p3flYyS5fC3f44geQd2AdykG6u+gjK49kz27WfDUgD9 -ECJt8BeQgquoqE85Jm+ZHk4upKJ/xY6UjuIVaZPXqwOJAjMEEAEIAB0WIQRb71Vi -kIEC+1Zye3zFLXr+hfJVCQUCZ6DP9AAKCRDFLXr+hfJVCRpXEACxGKCokoHH+oG9 -u2xB04QsUQ1erTGuJGJHFtRWA3MRAdzu3A5L7zXhlNcbg5COmLzyoeG503njGHQr -pPvUy5uR2OWkhZbvfQD/0pypmg4fYJs2oKcrmWAz9uRsKuAMiNEv/eZmiKGhpCB9 -kvHe32t6+MnBPG3R3ilErldLn+NenGXVOAwUNF8dfKK3BHC6w9DyiedB3yzYAynH -noJjNirxNI4GGSYB/rwJJM8qV+DynZoAWHka6kuhhQjEp1MrQg4A9dsa0RGHzx8i -OqeuyWb+EMvpeuPXKbMKL72Yln541F9xKfv3L8v/aUeZFF4Jb/tVrwst5Mgtcq7G -afh4aKLB9ezCXd09WrHzRUxIrn1zxUGUJKCJdTago/62tRJtKGQnouQM6OwDpjF9 -AYp5U+nIRRBF7ZHJGMDHyd4lVJ8d/LFxqZLiqTXQ1Iyyo7ocRH+dqKEac/vfX4/X -KUJh6CkWbLOjosHZ98ZW2nLmiWjN9ehMm0svByG6iQr8rNjP4sC6iMz/F+CB9k8P -07oWOSm1HDt0M5iXg6c7sD8ljpCDPWDO5/wPfR0WrmzhKM7gnSlniwC8NW50jKHd -eCG6ehr50X7rGBmR3ORnl4unfgbgXT9Z86kwqHxcsxRE6UMKDWK3rCzXe9d2al3V -Qg8/BGhsmhOsMSaqouBWGPj6HYddYbQ6S3J6eXN6dG9mIFdpbGN6ecWEc2tpIDxr -cnp5c3p0b2Yud2lsY3p5bnNraUBjb2xsYWJvcmEuY29tPokCNgQwAQgAIBYhBBLS -fV2Mjpvxqrx8fHxkdo094zTnBQJoPSaVAh0gAAoJEHxkdo094zTnLtcP/j8kN8dg -U39W21OrD3Z4nVi1Ie27eQ83RUq0ovQgp9ipEezIj+K3+pRGH1auO5fKezrOPOqc -eX+6o7qbFDIFGOeuk987uU2a1siCcczFQnmBXHG7PAxfafGmJHW5FUOQyPxoIBi0 -Kpc0tOawqw/8RadQizCAT0YaQcfUi52k3CQdU2dcsDttXHdfFHkvnrIbjYvj5f6p -88TLsyFAvLT1zDpHAnHddC9j4LP4GaKPJCR3Bnl6AWe2i7QsCrcU/HOl0hnIapsC -k+HNXPwzLswMFnbsPqi5EePjx1Inx68/4Pnyfqsw+eS1f+2V0UyHOsofnqvCZNC2 -4KyopcYIdQo7IuZCcbLigtq1mu2d+U4AYUb3sT2cdRSa4kmct0UsHJBttdFsc3XV -EwdMU82ZNf+GGSSt42/9yBw3uBgeu94L/BG9NiAVJxnfHHBO6C8eU71UgUMK0Jht -Nra1NvyLEU9GwdM01Cc5ubGfsRE3WlCyr/GGy+4XzHrmA8wWfrqafU+oGcaU4erA -sLduFaAcWK2Rej+4tZ1jSQp7AT+hl0dKqClqs2yxLv8AZiFoUHLf07w0AJ2F72eq -ZOVbGF+ypMxxnmbRybZqlzlEKOPyClue8SBCrmx08dHycvrk5NpQXI5R7weOknCC -3t0vK7DqOURSy4W6ffKhnXrx3koVSdzHPfTgiQJOBBMBCAA4FiEEEtJ9XYyOm/Gq -vHx8fGR2jT3jNOcFAmfrndkCGwMGCwkIAg0DBBUKCQgFFgMCAQACHgUCF4AACgkQ -fGR2jT3jNOcLQA//YinxhM56wEQ4cHAzxyUdWiK0jRiUyQpTQZ/3+377KUBR3rGk -LXY3+MOGVyeiMi8NUIJkadpBRDrcnqD6byL2kv+HxpirR1qevNsH3s0Ow/Zplidc -nocc8VzLknMeY9b0MvzNKApJ30TmybsJNnR7O1/prsanU2D9O8bVVs922CxD+m/j -GD8gJTs5G/fUyPm3QoXXoWyCMeB1bZBmhgjg4YPJVMSk5WF5uvVSb9gPoE7jZRLR -8Lv6eA/CVXHMCOMG9dCYSMcw2Hz/mOKNrjtnLj9iYK90uEnee/Nzl+P/4hkQ7fuQ -aWYcrxnUmncBVoJ/y/Es+WqbKsdkerJ0MI3FDie2hZzw1zsMuY3mjYMfEdLGs24K -eMchUG7uR17nYC/OHgusqMcGMMHMxxejTLsvy/vSOsYMC2Qx/o4++WLaArunuuU0 -zH8kHbE0lgc15OmODASaRJMQe/4BYlv4IEetCyV1ehISUdwo2KrIigC4YGbSbDXt -8Bq6vFphtPIqwrigfwQmbGIzFb6Pjw2nqxFZzOjoEePg0+ep9Nl7dvxXAaMaapLg -khMOLM4u/zzMaUfZGZivCYHpH6Igd9I88AJvZ9zPimMpkUL6cs+DXzx9NoukDBQ3 -jl48uvYNgP/Od2hXzFh3NVsPtTTjSxJIe92iQb6BtyFQckjdxfHPfTG4KlO0MUty -enlzenRvZiBXaWxjennFhHNraSA8a3dpbGN6eW5za2lAY29sbGFib3JhLmNvbT6J -AjYEMAEIACAWIQQS0n1djI6b8aq8fHx8ZHaNPeM05wUCaD0mlQIdIAAKCRB8ZHaN -PeM05+DED/9+gSe5LfObsrgsvIQ4nmaF1dbJOF3eqknG433Y+WEuO5ihl2CSk4I0 -GUYDFKvMa73Bcqsl06rg6bpMsbAtfPO5/G9enL8Z7ZINbiVQY/TctYxz7LQhzOLx -6H65kTBL5y9f9AQC7aw1CPR4XaOHpaOJlDTxeNqNaV8Mp7ld1f05/8AD/bQjnNa5 -7YWxuqfHk6IW5i1H6qO2hS5OVMWA7oC/Vr9R73H14rq6fRP0+TKUeprXq8eNKGaV -86mScnUbC452jobcW4M0zMandF7BXCCJ8NmA1N/z/hL2tzGhk8mKXUZ6iU0RZzQH -GQKEp8keqnCa04j9bR8AgdmzylQrv8l5uoDfC1n4hZclUFg0jLIt8rJlu+UsJMSo -C4CJ+AUoYbleJhkRadlqitnTTXO6jNG56bQCRT0T0aj2qwT3CbUrapRWs68m/VH3 -tjx0RNuAkCcDjruNehSclLqid178ETxMLw2orsmnEA1df7ZtSmw2sKy/cwdCKNFz -3Qz8pzQ/Ns6vNOYh1+B56wROxdTdjk/vL/EO3txDpLSZrqWQ5wUzjnl2bsI131O3 -EgdRbOX57ppS8CD+XYpiY5wA8cVylaEFWxobax+r/J+kck8GVKpZMfKNhdjYFkqC -c7zi06bC4qwSwg1GLU9um1S9h9PfVAdJMu9oRutq1FoWNQwF5Sz/eIkCTgQTAQgA -OBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJn653yAhsDBgsJCAINAwQVCgkIBRYD -AgEAAh4FAheAAAoJEHxkdo094zTnQbcP/0fV7ih34KWhUX3KdgM3UDq8uxmPOd5/ -gwF/9ES9ZSycnMLUZvo+GDphdHZly0M4blnKl4WZ6ZND/QbAJOzmFzLPN93/AvTA -dE1KmMt9pqlmyY/HNK6AXA7xo94s8f8jOjumfcL9HrawnSZDeqLlT+3yFe7ejrDZ -Ur5G/tlPGfCPaCIhVJYwq8g/l3/7ci7xYSRiRShDYgq27GdVBpkQ4cr9/c7faEVa -3wGzNScUnQF80vzSHxPyaA9VxuUGlXJq2akK6+/+GhrWs9QbuqeedmzxXExamtMb -/TdBmcW+Utp4QLtllMad4L2c29LUKMt9xz7dofQ9C4n7xCxVP+NSx4Tr6mboR+xY -a3xc3EWKnmmfTTNt+hpEvrk1okjFaWzKVJs9MGI66DyWXYdibZmt2vNdnXEdi6lw -fsIgti1GsyCNU6MQWGfiQ3Fo5FF0sDX1ojMyY93Fr67EmKRK9I8Wb1bXSerputZ1 -d6W1uVnb2SNnpkqYfaE3V1aUw4v5zztFpT9bCSpiMk+CGfHrFLTSmSVB3YzdVZBr -PxQfwfW5AT0iUzhrKjd4dpSUhNxTc6XYBI+Mt7zB0SAOw68H16iaHLPMV6Pa3uuS -dQE1/GdVg5AYve6GyUPUeQNPYqw+4gK4fSBl6OmAoAgaHreoIakGf1zLTskILUzf -bXbVmSj7frhLtDtLcnp5c3p0b2YgV2lsY3p5xYRza2kgPGtyenlzenRvZi53aWxj -enluc2tpQG9wZW5zcmNzZWMuY29tPokCTgQTAQgAOBYhBBLSfV2Mjpvxqrx8fHxk -do094zTnBQJoPSanAhsDBgsJCAINAwQVCgkIBRYDAgEAAh4FAheAAAoJEHxkdo09 -4zTnnLUQAIA+joQoo8L57cGnoJEXzhmreZWKMi8/XFaaC7RjH0Q0a2atFfdReOoj -j8UrU9ucTG0zvVJsD+TPN3hP0oMu7wmhKrAk4YWDffvzIoHbcPzzcFhER3dzTCf/ -2MyjSD9HryQ4Ty/IFAV+D7lVDcaCwdqndiLcCb6Y+QxlACbSThOqcubpFRSD2bD0 -rYD/F4QyNYOPOWmFBCWRukCVgEc+JP2+9L0n13dWdtdlKnUFD5OI2pTNPdp+FONz -yEos6hkDUgM+haDfQPaUeeqNWZ0hXKdUc0CyGY4o7zjMOAnpijpQdSdWS1+wNhxt -b1KTC5eCHzvucmjqazai1Z02pfGbZFfy+d1iYquxVmjLzsqg7KStBLz0Jgo8yI5G -Cuk+m4GQuFyHB8KrfT25y08DXodBDWdCXWZUd2/7qumrC2aJhlOPbG+BDdx3qyav -M/wcTAQRAht5MT6zYN71QWRO+cPmbbvTDXff5dBecdOLFObsrEwb4YdJQBV5548K -WV8B0ClisaF+aZr4kcN6v/GNbwU23DuO75n+MYmGZ/5IH2wM4yKXpIkWPWwaLDt2 -vs3jQXIWLm25U4caPfAHmjCdEwzSayLNxGEHeHKyz1V1MfCh0SmnN58QFMtb69SB -sylueSVd58KO5PwZci9D/JPHXVtxOS4j8dSbOlx2424bl0Z2WSR+tDJLcnp5c3p0 -b2YgV2lsY3p5xYRza2kgPGt3aWxjenluc2tpQG9wZW5zcmNzZWMuY29tPokCTgQT -AQgAOBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJoPSawAhsDBgsJCAINAwQVCgkI -BRYDAgEAAh4FAheAAAoJEHxkdo094zTnxhAP/in/kVp7yZo+z9h5oUChqBKPqaK4 -c8qP9P42JW08TXPp8kolrumTuX3soR9PhASwsz6iikTNaLcAjLDkKW/ywOUzmIpm -IpsvmLDZhHmFRDs6giycWfvBoX3VBcrrUVFFUP2m4MXqIE+LmtD4aCa8ynJ7vkax -YbzY+4MhxIpGLMOKqG87uBXlM4f4OYEWNg7kfjdZuo5u8YPvg4YCz/fF7yMk5dJG -MpXNaoIQ3QmwrVW0W0eBkaC5EOlcJiRoc/x8HQ+97Zw/VFE0+N4sMXPKmFRnDBJJ -3vXvIK7vjsDnrUookI3ZrrRE/bwGPikLTYAX/+ySwmPa3BXK6KTp1WQD56BZfOyF -eRXtrYYGkZZYkF15DswyO0BNOadJrgIbgWMeuR1D0gJdOQYuuZNfs0how8Ps75Ks -Y2ifALCtriuv6NQs8buuCpmoWTrFXeuUSQ/p+xRfj7cFLUrdU2JY9LVcONFBSfh4 -lOaERWhWLhdtF+8IEXwpQ9+NZrGhYagrzdAussF6WB18MZRnRoRn1wmpidTpx76p -NicHGhQXuQqnbIpHvjHDtmtjECJVO0jFdoEUZIheplG16lYVDfkLG2/aPckRnwiX -iOASqGl0eNuKUqkEbQ28Hgrhx5CLlWkTCVa6dHZ9bKBVS2TSWxV3PCkMdGr8Wnhc -2Rq71ce9ogTqc9CetClLcnp5c3p0b2YgV2lsY3p5xYRza2kgPGt3QG9wZW5zcmNz -ZWMuY29tPokCTgQTAQgAOBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJoPSa7AhsD -BgsJCAINAwQVCgkIBRYDAgEAAh4FAheAAAoJEHxkdo094zTnQLUP/1Q096I+OhbZ -EQkk498QlzUaACnu4B7kdy1FwoJ8pNHZpU6Y56N0smfcklQ1C/OBfHxomE1ikNbY -FqotQeKCPLvawo0oFSWsJ8508O/YfBVKE+hlVP2XyWVLujONIYGSe+JwhWu4oYdc -KTAkd+D1XGwo3JWMrnsRySHFwTad346jpmbbuICy3g1KVrFgGsM1U9OvVY5AmVbC -n0YYlRvQiwMfqG71UI2YdYpQL3sTIQvykQWbxTKjrhPKhjA9oa/qWncXfju+z27P -Zw7o43f4XlrA7WqDyQcvfdSqtpH0UaeW11uqcBX2VZj4ERDYco4tKcLzigdJMpMr -38C9ERJWe355pBqX3ORoftXAsE5+l7ReHjTRFV3plel7874AhA1r4kY4qIYxI+lJ -PcOx/4vA4HHLufp+MpwMJfgeI5QMXow+ODzsJvEq/R5G5ZFzMgFX+bT3DQrrpGdX -g3XfQZZI4tc4+UUpwa9J0VdtcYJmf6oAgu+gC0EhplBfQFaVpvQw1ELs1EbEkklN -rCtFCZpFEkDeazV2KgNIpteU9mV0ihSs9Jp5Mb9Zo7DXO1gIiVIa6PkGBnf0ZrK7 -a57NbccXfPiQNAXVF6uDPz7fLK5VqAS5XdKIkUmty/hgoKQnO//T1KO1LOq2JBRY -N3bRNv6Ji9LFKAeC6DZUwfJmkW+fkxy0tDJLcnp5c3p0b2YgV2lsY3p5xYRza2kg -PGt3aWxjenluc2tpQGdyc2VjdXJpdHkubmV0PokCTgQTAQgAOBYhBBLSfV2Mjpvx -qrx8fHxkdo094zTnBQJoPSbwAhsDBgsJCAINAwQVCgkIBRYDAgEAAh4FAheAAAoJ -EHxkdo094zTn8w8P/3/Rd3vqSW6GUJrgFUECB/ai43PKveQQryqdr50aKvsVZRwr -9caxc/mafb0NKaajeyXe9DKBmXX9mLJ9DiJ1VDwGWbRCXeBz/DQ+SkaQEBHgNYXu -hywJARrNzjJrmVPzRjBYYg0GQoBCARk5aO7xWnLpNpMRjQKEUd78sd4A1Gh3cS0W -eeQSO5cPAX0gFDsfP0O+gmmgHqpHoGiEIzqVxi10d28582J6TqRDJwkirjQigLIM -1iSUujhEpv4T4FYWYwzNL2tWDn6SPNqX/E/zI95KIBV6rJROljbAeY10qi9aD4/6 -Y1mntrJu9SSQJQJ/NeXVZaSNlUCAoYewYZepaiDQ8HHsb+tacs6+J0cVa08H3JZr -7YFfFFdTUJYMPy7L7sutToT2Do6tei5JG4mxQDq/ASvIrLM0Fnh4RybukFa+EjuG -YV1yMNNupL0LRgIm8U1DeNkBJ1oOXbSnaNwRYNy/Kt4uujmjgcz4tJR8J1Hx1xuQ -vm6v1Fh6PBK0LwSK7oImettazqNiNsK4nPHq/y5hmGLk96afu62ld4w4WFSLkUH4 -m2dVmPGciWWYxxIpbpxeqU4yO81KJlCgNUYc9etJNwCy+C53afl3SHRe2F0wnT/j -qygVpLTLowqilebq8Zsbes3Bb6ZUSMzgjqlr90/sbj3BXwk0rq/injHyUbvFtClL -cnp5c3p0b2YgV2lsY3p5xYRza2kgPGt3QGdyc2VjdXJpdHkubmV0PokCTgQTAQgA -OBYhBBLSfV2Mjpvxqrx8fHxkdo094zTnBQJoPScSAhsDBgsJCAINAwQVCgkIBRYD -AgEAAh4FAheAAAoJEHxkdo094zTnhb0P/iP+nVmcUW4vl/gKlhvZHVOZq2PsekNA -sWa7pSKNquVmkSywVrMTRm6s+YBAB+wNMoad0YhoYGfdF1+Lv7w9/1l8FLvaG/0F -f4sSnRbM9+IAL11CKTmLEgwjwR2BbhuI9W3Eg9YAxdzku3tO7lrHDwD/A9wvpy85 -xxV6XDGbAP1HONXY2T2VcQcqVaW2geXZ75ZULZ0pwrgPU+cDMsnq9EqgGRStiaGG -juyUt35jl0LGg/7+hNwKQLlUEi+gp2TrLdOWX2m7U4WfFiH4PwY7CXzu6CDpvLGO -QjKu5p8CcMtY38cNvbPQNXPDFSVKdQPsOutnJqmi0PjMv4/hx9jE5WB2K14Ow2H7 -E4HVukewN2hTxjmT3fytU2Q03/AMpr3IOxNHjqEkdy172U36QbrRHw4EiBV/3uBk -Gp11l2gLgIphIiPo11YpFkTmHpOvRKcMZhvELuzsq/5LnnSbIQmHxNerx+vDd4Y2 -j1eXaipbn94Td78/1AoJFzo2mCwEZWuXKqor6xLdJt8NoI3whj2Ty866sFvq7WYO -P8KukTSD0oVIQzrt4LjAhPzbyq8pUU3jbIpYyiaitUgDDlxMOq0o6EwqySffeyFr -fPugKau5n1Q+stCqgkIiIcN9NiwGbAKWyRYoSa6aCr4rnA53X3BacBLE5s5XXtRw -L+UMwj0GbUfxuQINBFnWkEoBEACuLtPayeInMmq9AiQ/sNqFSh6k9qGF3z5sm0QM -5o63RQirHjXtgAsL4tNOxs4DJNrETQZ3JT5XtT3NWmdXgzQjWkV/fXFVwFhyV0UQ -c0kXiDBS887wsXLACHGJa87rIhRC9C7kSs9fosBhz5NwNBpfRfSpjsACiuEt0fG5 -za6fR2i/F7dV9XcM9BsePecYlVhzg+X9Rh2XXFBTiYtPDcoo7SetnWorFdh+RDJF -YrlrQkO2nGjvZAazsEtCmRklo9d16rkA+vOsd8ublbs+XEZXENvNVMuSsNwsLpgC -QJgeoFnuLbCTwBJRCd43zgTHniLUcPlMokuOIJNFW4MXOVegdfTPsrMt9a5pWyWo -WQ5FmgWkJHgnL/3rB7DLMsguPDDVRZ4Mt88GMQfiwuK8iGN0V1dErXeEQza6oY0l -I8xyUNgs2bcHiKNfQtKCpGoDlJieKZ3MfAQIuNeo+IeV8MTGUnP0qkZ7uenKbQNn -CXrtYo78V6gK4NgsnURL5TW0KZNhc1VVARsk2VexLWgsJPjbaS15teatwkV8VeIp -AZ4Kod1vYOAb+q2GH61BorSVpEhMHIttMbgSdY4dkevHboJ2Cffvk4d7HjfTEOSv -MDAp0ELhQWBRPFlMZ5zboCH9oXTJQqpgtjVy7kVs+ifAYvK8eYvDzvFwheoRaLvp -QQHfuwARAQABiQI2BBgBCAAgFiEEEtJ9XYyOm/GqvHx8fGR2jT3jNOcFAlnWkEoC -GwwACgkQfGR2jT3jNOf/zg/+LqojCgoPnceTZ1tSkJ1w6+f4gIfxY0S3QAgjuFHf -L7GxJLoNKXvzm/EMJWds5wRXWqLBQjd+WY4DHAk0uF+7gomVq8iHH5vDy/eCynI2 -JkmxTJ92G2LC7vzRTZI1ZSBJBO/ALmg3nWERzj0/VHKYt3H1ga0AznhGTo/52t4d -rTmazSgY2JxSdpINFrKKdTEaPzpUpTvUBXp6qRs2LxWHfmhHjd72KE24ABPBbATo -RUaHpAVKZsUu/7xUgxJEL+Ciu1KVCgluOA3c+NhqOAV2GutSwR7ldR0V0t24sS9B -S1m02/V2e/opdR92wmtz+6wLljP1nvPiNgkooRQJsSbt7g7dNP+cj0PrFYiIE64g -T2uRhC7NIB6b56vTCmBeQSOWalVajOX/ejk4YpUsrKridy20YZxYdTYqUkNwFoBE -YyezJyTpvRSl3kcx1+koFefAWHlk0Mh/gScrx8uuvYOrzaGrkNOh6rkeGQ7L/eno -Eg30KhsbRfiHoOchJ8ZQnuq2lngg6KVFOxdKQsRyAQ20WoNcQV4m7ybZ+28fBzVO -oZiCFWUGZNx5Jut9O317iQ1s4ByB4XJWL6e/xkenBNE0S3kw8vhKE0g0w/sOWOck -NY8LMepTOtz75SF6xV3oNYaKufwlJP8oU1q6HbKbbrHa+5fihlS8zcDB3Qs0Ts8t -uZQ= -=xADA ------END PGP PUBLIC KEY BLOCK----- diff --git a/kernel/keys/pgp/647F28654894E3BD457199BE38DBBDC86092693E.asc b/kernel/keys/pgp/647F28654894E3BD457199BE38DBBDC86092693E.asc deleted file mode 100644 index 6c91d9b..0000000 --- a/kernel/keys/pgp/647F28654894E3BD457199BE38DBBDC86092693E.asc +++ /dev/null @@ -1,78 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQINBE58tdUBEADY5iQsoL4k8l06dNt+uP2lH8IPi14M51/tOHsW1ZNc8Iok0stH -+uA8w0LpN97UgNhsvXFEkIK2JjLalasUTiUoIeeTshD9t+ekFBx5a9SbLCFlBrDS -TwfieK2xalzomoL22N5ztj1XbdLWh6NRM6kKMeYvgAGo8p884WJk4pPIJK6G0wEw -e9/TG6ilRSLOtxyaF9yZ+FC1eOA1S47Ld2K25Y5GsQF5agwi7nES+9tVVBZp97kB -8IOvELeiSiY0xFXi60yfwIlK6x9dfcxsx5nCyrp2qdqQiPiMD0EJMiuA6wymoi5W -XtmfCpweTB8TvW8Y8uqrwYApzmDleBDTIDP0vCY1o9eftJcWWMkRKC9c7Ziy4nT6 -TzmVkNXgqC8/BuOQbpU7I/1VCMoa6e+2a8jrgy5to4dGgu6xQ6jTxWbvgDeB6Hct -WGqf8f9s5lSpH8D8OZLDOXKolqnBd5YrJr0Qmpq4cCcIqwNCMbURtsTpbW/EdWl+ -AKwnStXXLI5O6Hg+m4c3O8ZwbzcnAOgTJePm2Xoi71t9SbAZZx1/W7p6/57UGrXR -Q4WfiwpOPD0siF33yO2L7G7Gmm4zh8ieX8aS8guqfWFhuSsDta77F2FB9ozD9WN0 -Z5tJowiy3Z1VkxvZjZH8IbcB05yBBBV47BJxrPnSuDT+w45yNTqZ6m4VYwARAQAB -tC9HcmVnIEtyb2FoLUhhcnRtYW4gPGdyZWdraEBsaW51eGZvdW5kYXRpb24ub3Jn -PokCTgQTAQgAOBYhBGR/KGVIlOO9RXGZvjjbvchgkmk+BQJaHvQRAhsDBQsJCAcC -BhUICQoLAgQWAgMBAh4BAheAAAoJEDjbvchgkmk+3/8P+gJ85fYDzXoy47y90FFi -PJqqtkZhf/VPMP5YOJzxCnGVh0CUwC2fGFV6SIU5V78Ede+gArocYq+LpTV4nJz5 -SJZZxNBzuEW8t42juF6GZ9uB5SNlqYHUjWbM0bLpl1gut3pe9yJ7mQ2DaZUMYlav -D7sOAiKw/5pCyFLvY9a6ZJmp8QmPUU8Fb9kbbudxfjxgDrAwuVlnGU/I8YIZOHhX -s1hjBNagZCWcxawktDLPylifNOL5UtNuoLJRjsUVatAEjp+g1Xq2A8/t/mfi5K1p -juQaEr5fVzqhkPqt7UQbT1QuZghStYJ5QRunaYT1trvBXmrXKzebBKk85+nlh58g -fRNTyEt2eflNkU1XpFtNcCWo6rke/PZjtHb1CivHD/GhyogeGBfRAMRfmfNDZRZw -e5V+EBNI+RUexscvhVyTp0XhxgXdGy9KpSpWbuwGaQ+q9mVLrYRlNn1k3dnYaWxD -nk0x7xGCE59dd6vpckcD6t/SXujRwT4b0Ypw1jy3Ve3h8OTB5sP5SBpCA33DoQs9 -ONbgtL3nX3XST7frXxBkfCD7D58gGCvFvZYAEd1MDGj3250UnBHUPGeVp7/+t/wH -MJ/E3rvb45RGYadd736i0vnJStPIae4M/bVG5qddRjU6mcpir5qYHAIrDz6QwWWF -2BvR7vqYKa36TGX7TORxuyfotCZHcmVnIEtyb2FoLUhhcnRtYW4gPGdyZWdraEBr -ZXJuZWwub3JnPokCTgQTAQgAOBYhBGR/KGVIlOO9RXGZvjjbvchgkmk+BQJaHvNA -AhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEDjbvchgkmk+TLEQAJ1Ux/6n -//f2jEVBdWb13qYFBBxKJMNeTU9yPMedQAAhrt68IU1Bt8+/nmZLm1iXWOvPQ019 -21i3HBxANnbTqEYYYWnQJJyROiyTuwY7HWlguQXlkxLa1mahVuFee6DHO+O8IGU8 -IM+PHdEL08e629sIluu3WGmNXXJ307j47UBu3QFA67YQ7YBmChl7AHBcSpKSplgN -82tbAYtrm5ywYHM5uMFhmbw/DJpzLdFsnzRT9E7PKhH+q1MyPojGT4Oytj3D1QZr -hp8yZ+Zp8TQnleXeBczLfpQPduzurqVomZpWwIZLHCgBJRWmz7/M0kTDIndQle9L -VcJtJqasrRmgL3NsKrYYBw+jHnBe2hp8aq6W3DVaUmkSdshran9ZCaLCpxt62NAg -UkI/eg1sSljo1aeXmF33ymYIpxavW5CGUYKlqYRLUT7en6t/mFiYCwPD22KOdLSf -svVG+pr4UNsfSZdIF+W9/FLW7HJVZGMIldsrGFv4lOtqiXdbRafMtylYw/mU+xhu -9+NslRRrbi1TlWS/BH7ULYu9zKahApf1DFRcrx0PyvtlFleoDZa88uIbmcUO8GzZ -XEhejTv9vNnbmjgvYsRywFcJPkJ/TObfasvvSU9GZn6aU36Y7GYSUGjD1anLiUpr -0FKkruymqBdXHaXGJ44GZ8Hhd5ZMTavwEX7BtE1HcmVnIEtyb2FoLUhhcnRtYW4g -KExpbnV4IGtlcm5lbCBzdGFibGUgcmVsZWFzZSBzaWduaW5nIGtleSkgPGdyZWdA -a3JvYWguY29tPokCOAQTAQIAIgUCTny11QIbAwYLCQgHAwIGFQgCCQoLBBYCAwEC -HgECF4AACgkQONu9yGCSaT5fXBAAx2NfTb1IZ59eV3PKtqNG0qwQdq/62oSqNKlv -lp/JzkeynjeJ7ic1IOs/CTTv2+xoPkLNcNhOPz7uem/4aa/my9A0AEp5UsF6Lvdo -/Hy7Jxc++0EgW//TyvWcU9qd5qS/85VZf8I5pL9TZtHVwfIfLME+G8hkQx0+CWRJ -loLFG48lwi8khp+TsCRYv1tQei7G22xAY5s+53TssaC1MXyQT7aJBGhwnbspY2Ia -RMzsrX0msZn+Fn5WlxxMDxUmUACFMyKGJ+1F6VY01nWolT3G1udOnpee66qXHJo6 -XnzkNhzeH8Vf3sMe0sXx8YkN682g1NFaa+el0SDcXZvB91pFkWnQaQSfac5gI4Ki -ShxAqePAH6Og+a/fhs5XdyYw0SN50O+yaSnqEDl7JkByXVKJiVVihDuEe5JZXkoI -O/eTN6uceF89ZQiO/dFn0Kcqc4vL7uuI6FDMRZK7mY7bjFxFW1VjspcxhT1NdR7S -FNrK8Glzd5FS67oTwSNB3CzkJ3ON/kOJ8JSxFEt1ZTc2ZpQujrFyTtbksWm3Yy63 -kbpwxRoR6xgaGwtx0SdkkWDCcA+2GZymCjk5FFQkAhoEk0tu/n5fvHS7TTZui9a2 -HMsyqmgTJzeU0eQJDgmb/ahzW0VgjHtABaJr40Q83M9upkZdHFXSZb7UHFYkAdH1 -OxdvSFW5Ag0ETny11QEQALIiIb/niWy6M6GfBMt/2EBWpLuE+FYVeUQGpGhXD2rU -hOo9UpoxBD/Y5mc5OaJsVL3fySYQldVFOaT7Pu0J1N5FXIBckgtbT3eg+TGD9WIf -Jy6ZpWjBKf6K4frwTwRpLBKqZhcA/78KzxFHeRHjV4cEVZVNoRtVqLYuTlbdlkH6 -G2YxgCioxAfqvsGjsg2ES7Xl6xz3uaBH1DFX7S2LXHkDHnloWOTaDRe/4h2VnFHf -76xsJCgt2seJp91kI8bhuR7CUrO5mkRMhnp/z9v6vc2qcMv8EMK62FiBaqENaKg5 -6ag8Icujar1YwXG7oYhOuYiWxqGpJUwg5+h/HeYw5Q8ue0UwHPCUZR14pzQCKxag -RMibiufOlS6URbCcBG44ddFAt2vqqopIo069moxfqt6OGig59cYv7PSMfHX25dV0 -1Ns+2R1eo7qiktkV+3CSSs/dUArcTxyovuadIAUaZAJ3XqsS3FGzZsPYMYNM9faZ -qOfF6mmGmCZRJMMESWuWjc8ZnVAv4luyD18vlsr/J9rO0t28s4PJyqJGozEXLBLt -saCVihxBHMY7QK/pC0jRniLpeniDDHY875TIiG3nrmtR84nnW9WNOG6tuaIcB6hD -/DmSr72rRoNEpCa/eT7XiCOymGHS5gWR+94R1+J1rQZbd1T8gSq/nQQluJII7oz7 -ABEBAAGJAjYEGAEKACACGwwWIQRkfyhlSJTjvUVxmb44273IYJJpPgUCafiYQgAK -CRA4273IYJJpPhxAEACqoI90rwbASUFgZLeu3XnuXvkU991ZnH9Szvlsa1N4KBjK -9Rw+JgJoC26poHstLzfJXHvgbNnycgpyYB04/9P1W86d5Ab37QicRZEa25KIlTLU -CffBOdi/XgjichVUZca5sKgB3zloFSZxock3JtYFYRtrQThOMvjkDS3Dw85hwsDg -41BqdKT1GEDVV6nKWFNqyQAJekNHfYwD5ZK0GVP/59OsLRFofq5eX1HtbeG/FoER -cYseRs7I3FXDkWL7hIrkWrUNNjBRHnBZPs63Z+Tek555cGL31gPHTaobPC44Aiwr -lztjtQzRQf5nHBAUj/++4KNUr/yvtQnT80eUu+B2EpZs5JKHPo2Secs17dfUyB9Q -tdXWlKyVdWbPQfF7jqK3G9eWMroXKB7tX/hWY78mtt9dp9OZ2takkoI79cwVumeJ -n6sNIy1yY26IX2cJibYioy/X1k0Xgrjpq4gNxmxGzur3tmnLkmFa2V5yPpCjLxe4 -EK0UYxCjUBM+faFOrQ1A8POYcfUgBJ5CMOVd/n1Jht2uvphLVeVx9MiC8JsW9z0J -0CAC86WSRfcxbvLvgX6cxzezFbDeci3FoAlvrTqIykxPKul3jw+Bk6+1Jx5siXtn -WZLEHgjYDN7F4eJ3yyFANs1zAKIKTlvzuI6A9VSb7KFyn9+GF+QCIgDfGjmr4Q== -=P+GO ------END PGP PUBLIC KEY BLOCK----- diff --git a/kernel/keys/pgp/ABAF11C65A2970B130ABE3C479BE3E4300411886.asc b/kernel/keys/pgp/ABAF11C65A2970B130ABE3C479BE3E4300411886.asc deleted file mode 100644 index fa46e9d..0000000 --- a/kernel/keys/pgp/ABAF11C65A2970B130ABE3C479BE3E4300411886.asc +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBE55CJIBCACkn+aOLmsaq1ejUcXCAOXkO3w7eiLqjR/ziTL2KZ30p7bxP8cT -UXvfM7fwE7EnqCCkji25x2xsoKXB8AlUswIEYUFCOupj2BOsVmJ/rKZW7fCvKTOK -+BguKjebDxNbgmif39bfSnHDWrW832f5HrYmZn7a/VySDQFdul8Gl/R6gs6PHJbg -jjt+K7Px6cQVMVNvY/VBWdvA1zckO/4h6gf3kWWZN+Wlq8wv/pxft8QzNFgweH9o -5bj4tnQ+wMCLCLiDsgEuVawoOAkg3dRMugIUoiKoBKw7b21q9Vjp4jezRvciC6Ys -4kGUSFG1ZjIn3MpY3f3xZ3yuYwrxQ8JcA7KTABEBAAG0JExpbnVzIFRvcnZhbGRz -IDx0b3J2YWxkc0BrZXJuZWwub3JnPokBTgQTAQgAOBYhBKuvEcZaKXCxMKvjxHm+ -PkMAQRiGBQJaHxkTAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEHm+PkMA -QRiGzMcH/ieyxrsHR0ng3pi+qy1/sLiTT4WEBN53+1FsGWdP6/DCD3sprFdWDkkB -Dfh9vPCVzPqX7siZMJxw3+wOfjNnGBRiGj7mTE/1XeXJHDwFRyBEVa/bY8ExLKbv -Bf+xpiWOg2Myj5RYaOUBFbOEtfTPob0FtvfZvK3PXkjODTHhDH7QJT2zNPivHG+E -R5VyF1yJEpl10rDTM91NhEeV0n4wpfZkgL8a3JSzo9H2AJX3y35+Dk9wtNge440Z -SVWAnjwxhBLX2R0LUszRhU925c0vP2l20eFncBmAT0NKpn7v9a670WHv45PluG+S -KKktf6b5/BtfqpC3eV58I6FEtSVpM1u0LkxpbnVzIFRvcnZhbGRzIDx0b3J2YWxk -c0BsaW51eC1mb3VuZGF0aW9uLm9yZz6JATgEEwECACIFAk55CJICGwMGCwkIBwMC -BhUIAgkKCwQWAgMBAh4BAheAAAoJEHm+PkMAQRiGbpwH/2jMNyBq6SjFrltEwt6c -wOJak1lkjpP5IfFMemfKPH03jBv98Yb7nnVE/VofRQi0erPvzU9HPitzmq9Hdaz8 -pTVD1nNiejn6MBHREY5T10U8J9Holn9S1G3CUvEUaBg+YEhHwWA8hhxFCIRcfz6N -PRkZH5zi9xdXBnjLrE3CpoZwVguwCT/25DuSqqJnviKiH+BOvJi/BnHSnjV1J71M -OpVabaTZKxQ1Qkwiyo7KRa/MrBV4Cw87MjF1jmja91wWNOuAwv1ST+aSaI038zcl -VqbFrc9gHkTeP3o5p8DG3Q7A1pE/yVLRUW+3jucKtiojylWaqxX7FD0RZtIuhNsU -ig+5AQ0ETnkIkgEIAN+ybgD0IlgKRPJ3eksafd+KORseBWwxUy3GH0yAg/4jZCsf -HZ7jpbRKzxNTKW1kE6ClSqehUsuXT5Vc1eh6079erN3y+JNxl6zZPC9v+5GNyc28 -qSfNejt4wmwa/y86T7oQfgo77o8Gu/aO/xzOjw7jSDDR3u9p/hFVtsqzptxZzvs3 -hVaiLS+0mar9qYZheaCUqOXOKVo38Vg5gkOhMEwKvZs9x3fINU/t8ckxOHq6KiLa -p5Bq87XP0ZJsCaMBwdLYhOFxAiEVtlzwyo3DvMplIahqqNELb71YDhpMq/Hu+42o -R3pqASCPLfO/0GUSdAGXJVhv7L7ng02ETSBmVOUAEQEAAYkBNgQYAQoAIAIbDBYh -BKuvEcZaKXCxMKvjxHm+PkMAQRiGBQJp+i1OAAoJEHm+PkMAQRiG1JMH/0Dnlg9q -tV0CBoaHWFR78YNAo2VpSVjUw6oINeEYvIRR5XoCUzUV6icrxDn1DIhELMxJ7KFp -ie1Ny6D1vzl2NjJagtlPTfi8TfwluxrH5Y/w6pEei/PDw/CawFa7GSkarARipF1H -Yq+DnG8hUm7HA+U6hEyssCPcpYVwjTfLrSB1PJd7OCo6qNzcuEX3b6bJ3et0Eqqt -N4EOg+Krvn+OLSGPFLmu2TBgTV9RKcFRztjHpkY/ipfRdAt+bYXqrAC4w0UZbw22 -tOx4cPe2Ru/i6VpfQy9AmL9p7N8V4aaXmcAJtHYVeD0i9wr3scgqRnztKhyikjVm -2CQKI+uoDKHN45k= -=9Sy5 ------END PGP PUBLIC KEY BLOCK----- diff --git a/kernel/p16-virtual-gpio.patch b/kernel/p16-virtual-gpio.patch deleted file mode 100644 index 9b92b9f..0000000 --- a/kernel/p16-virtual-gpio.patch +++ /dev/null @@ -1,128 +0,0 @@ ---- a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h -+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8901.h -@@ -1913,6 +1913,63 @@ - MTK_FUNCTION(0, "B_GPIO181"), - MTK_FUNCTION(1, "O_GPU_PWRGOOD") - ), -+ /* EINT-only inputs have no GPIO mux/data registers. Firmware uses -+ * virtual line 190 for the SPI HID sensor hub (MSFW1111). -+ */ -+ MTK_PIN(182, "GPIO182", MTK_EINT_FUNCTION(0, 182), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(183, "GPIO183", MTK_EINT_FUNCTION(0, 183), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(184, "GPIO184", MTK_EINT_FUNCTION(0, 184), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(185, "GPIO185", MTK_EINT_FUNCTION(0, 185), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(186, "GPIO186", MTK_EINT_FUNCTION(0, 186), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(187, "GPIO187", MTK_EINT_FUNCTION(0, 187), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(188, "GPIO188", MTK_EINT_FUNCTION(0, 188), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(189, "GPIO189", MTK_EINT_FUNCTION(0, 189), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(190, "GPIO190", MTK_EINT_FUNCTION(0, 190), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(191, "GPIO191", MTK_EINT_FUNCTION(0, 191), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(192, "GPIO192", MTK_EINT_FUNCTION(0, 192), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(193, "GPIO193", MTK_EINT_FUNCTION(0, 193), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(194, "GPIO194", MTK_EINT_FUNCTION(0, 194), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(195, "GPIO195", MTK_EINT_FUNCTION(0, 195), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(196, "GPIO196", MTK_EINT_FUNCTION(0, 196), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(197, "GPIO197", MTK_EINT_FUNCTION(0, 197), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(198, "GPIO198", MTK_EINT_FUNCTION(0, 198), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(199, "GPIO199", MTK_EINT_FUNCTION(0, 199), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(200, "GPIO200", MTK_EINT_FUNCTION(0, 200), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(201, "GPIO201", MTK_EINT_FUNCTION(0, 201), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(202, "GPIO202", MTK_EINT_FUNCTION(0, 202), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(203, "GPIO203", MTK_EINT_FUNCTION(0, 203), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(204, "GPIO204", MTK_EINT_FUNCTION(0, 204), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(205, "GPIO205", MTK_EINT_FUNCTION(0, 205), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(206, "GPIO206", MTK_EINT_FUNCTION(0, 206), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(207, "GPIO207", MTK_EINT_FUNCTION(0, 207), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), -+ MTK_PIN(208, "GPIO208", MTK_EINT_FUNCTION(0, 208), -+ DRV_FIXED, MTK_FUNCTION(0, NULL)), - }; - - static struct mtk_eint_pin eint_pins_mt8901[] = { ---- a/drivers/pinctrl/mediatek/pinctrl-paris.c -+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c -@@ -107,6 +107,9 @@ - struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - const struct mtk_pin_desc *desc; - -+ if (mtk_is_virt_gpio(hw, pin)) -+ return 0; -+ - desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; - - return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, -@@ -120,6 +123,9 @@ - struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); - const struct mtk_pin_desc *desc; - -+ if (mtk_is_virt_gpio(hw, pin)) -+ return input ? 0 : -ENOTSUPP; -+ - desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; - - /* hardware would take 0 as input direction */ -@@ -137,6 +143,9 @@ - if (pin >= hw->soc->npins) - return -EINVAL; - -+ if (mtk_is_virt_gpio(hw, pin)) -+ return -ENOTSUPP; -+ - desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; - - mutex_lock(&hw->pinconf_lock); -@@ -272,6 +281,9 @@ - if (pin >= hw->soc->npins) - return -EINVAL; - -+ if (mtk_is_virt_gpio(hw, pin)) -+ return -ENOTSUPP; -+ - desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; - - mutex_lock(&hw->pinconf_lock); -@@ -879,6 +891,9 @@ - const struct mtk_pin_desc *desc; - int value, err; - -+ if (mtk_is_virt_gpio(hw, gpio)) -+ return -ENOTSUPP; -+ - desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; - - err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); -@@ -893,6 +908,9 @@ - struct mtk_pinctrl *hw = gpiochip_get_data(chip); - const struct mtk_pin_desc *desc; - -+ if (mtk_is_virt_gpio(hw, gpio)) -+ return -ENOTSUPP; -+ - desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; - - return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); diff --git a/kernel/spi-acpi-irq-retry.patch b/kernel/spi-acpi-irq-retry.patch deleted file mode 100644 index b80d1a7..0000000 --- a/kernel/spi-acpi-irq-retry.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- a/drivers/hid/spi-hid/spi-hid-acpi.c -+++ b/drivers/hid/spi-hid/spi-hid-acpi.c -@@ -207,6 +207,15 @@ - return -ENODEV; - } - -+ /* Retry GPIO IRQ lookup at driver probe if enumeration had no IRQ. */ -+ if (spi->irq <= 0) { -+ error = acpi_dev_gpio_irq_get(adev, 0); -+ if (error <= 0) -+ return dev_err_probe(dev, error ?: -EINVAL, -+ "ACPI GPIO IRQ lookup failed\n"); -+ spi->irq = error; -+ } -+ - config = devm_kzalloc(dev, sizeof(struct spi_hid_acpi_config), - GFP_KERNEL); - if (!config) diff --git a/scripts/build-kernel.sh b/scripts/build-kernel.sh index 8d2dbd2..1b959e8 100755 --- a/scripts/build-kernel.sh +++ b/scripts/build-kernel.sh @@ -1,10 +1,32 @@ #!/usr/bin/env bash +# Assemble build/kernel/ from the Omarchy recipe at the commit sources.json pins +# plus the P16 delta in kernel/, then run makepkg there. source "$(dirname "$0")/common.sh" check_machine [[ $EUID != 0 ]] || { echo 'makepkg als normaler Benutzer ausführen.' >&2; exit 1; } +pin=$(python3 -c 'import json, sys; k = json.load(open(sys.argv[1]))["kernel"]; print(k["repository"], k["commit"], k["path"])' "$REPO/sources.json") +read -r repository commit path <<<"$pin" +# A commit hash names its content, so the fetched recipe needs no checksum of its own. +upstream=$REPO/build/omarchy-pkgs +if [[ ! -d $upstream ]]; then + git init -q "$upstream" + git -C "$upstream" remote add origin "$repository" +fi +git -C "$upstream" sparse-checkout set "$path" +git -C "$upstream" fetch -q --depth=1 --filter=blob:none origin "$commit" +git -C "$upstream" -c advice.detachedHead=false checkout -q --force "$commit" +recipe=$REPO/build/kernel +rm -rf "$recipe" +cp -a "$upstream/$path" "$recipe" +shopt -s extglob +cp "$REPO"/kernel/!(PKGBUILD).patch "$recipe"/ +patch -d "$recipe" -p1 --fuzz=0 --forward --batch --no-backup-if-mismatch -i "$REPO/kernel/PKGBUILD.patch" # Isolated keyring: upstream signatures remain enabled. export GNUPGHOME="$REPO/build/gnupg" install -d -m700 "$GNUPGHOME" -gpg --batch --import "$REPO"/kernel/keys/pgp/*.asc -cd "$REPO/kernel" +gpg --batch --import "$recipe"/keys/pgp/*.asc +# Downloads stay outside the recipe, so a new assembly does not fetch them again. +export SRCDEST="$REPO/build/sources" +install -d "$SRCDEST" +cd "$recipe" PKGEXT=.pkg.tar.zst makepkg --syncdeps --cleanbuild "$@" diff --git a/scripts/check-issue-9.sh b/scripts/check-issue-9.sh index bd4d410..f8217d9 100755 --- a/scripts/check-issue-9.sh +++ b/scripts/check-issue-9.sh @@ -7,6 +7,8 @@ # backlight=1 2 3 0 1 asus::kbd_backlight level before and after each of four presses # fn_esc=KEY_MUTE KEY_F1 KEY_MUTE the Mute key's code before and after each of two Fn+Esc presses source "$(dirname "$0")/common.sh" +release=$(python3 "$REPO/scripts/p16_release.py" --shell) +eval "$release" results=$(<"${1:?Usage: check-issue-9.sh RESULTS}") fail() { echo "FAIL: $*" >&2; exit 1; } value() { sed -n "s/^$1=//p" <<<"$results"; } @@ -14,9 +16,6 @@ value() { sed -n "s/^$1=//p" <<<"$results"; } [[ $(uname -r) == "$RELEASE" ]] || fail "kernel is $(uname -r), not $RELEASE" [[ $(readlink -f /sys/bus/platform/drivers/asus-nb-wmi/asus-nb-wmi) == /sys/devices/platform/asus-nb-wmi ]] || fail 'asus-nb-wmi is not bound' -# The unpatched module carries the filter; the patched one compiles it out. -! grep -qE ' asus_i8042_filter[[:space:]]+\[asus_nb_wmi\]$' /proc/kallsyms || - fail 'the running asus-nb-wmi is the unpatched module' log=$(journalctl -k -b -o cat --no-pager) [[ $log == *'input: Asus WMI hotkeys'* ]] || fail 'the kernel log of this boot has no asus-wmi probe' [[ $log != *'Unable to install key filter'* ]] || fail 'asus-wmi tried to install the i8042 key filter' diff --git a/scripts/check-system.sh b/scripts/check-system.sh index dede046..55f04c0 100755 --- a/scripts/check-system.sh +++ b/scripts/check-system.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash source "$(dirname "$0")/common.sh" check_machine +release=$(python3 "$REPO/scripts/p16_release.py" --shell) +eval "$release" python3 "$REPO/scripts/peripherals.py" check-installed [[ $(uname -r) == "$RELEASE" ]] printf '\nKernel\n'; uname -r diff --git a/scripts/common.sh b/scripts/common.sh index fe7dbc9..3e07220 100755 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -1,10 +1,6 @@ #!/usr/bin/env bash set -euo pipefail REPO=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) -PKGVER=$(sed -n 's/^pkgver=//p' "$REPO/kernel/PKGBUILD") -PKGREL=$(sed -n 's/^pkgrel=//p' "$REPO/kernel/PKGBUILD") -PACKAGE=linux-p16-asus-$PKGREL -RELEASE=$PKGVER-$PKGREL-omarchy-p16-asus check_model() { [[ $(uname -m) == aarch64 ]] || { echo 'AArch64 required.' >&2; exit 1; } [[ $(cat /sys/class/dmi/id/sys_vendor) == ASUS && diff --git a/scripts/install-kernel.sh b/scripts/install-kernel.sh index ab9fcc9..d58f5f1 100755 --- a/scripts/install-kernel.sh +++ b/scripts/install-kernel.sh @@ -2,6 +2,8 @@ source "$(dirname "$0")/common.sh" require_root check_machine +release=$(python3 "$REPO/scripts/p16_release.py" --shell) +eval "$release" resume_backup="" if [[ $# != 0 ]]; then [[ $# == 2 && $1 == --resume ]] || { echo "Aufruf: sudo $0 [--resume /root/p16-install.]" >&2; exit 1; } @@ -13,12 +15,11 @@ mountpoint -q /boot || { echo '/boot muss eingehängt sein.' >&2; exit 1; } exec 200>/run/lock/boot-partition.lock flock -w 30 200 if [[ -z $resume_backup ]]; then - [[ ! -e /usr/lib/modules/$RELEASE && ! -e /boot/EFI/Linux/omarchy_$PACKAGE.efi ]] || { + [[ ! -e /usr/lib/modules/$RELEASE && ! -e /boot$IMAGE ]] || { echo 'P16-Kernel ist bereits vorhanden. Für eine abgebrochene Installation --resume mit ihrer Sicherung verwenden.' >&2; exit 1; } fi -packages=("$REPO/kernel/$PACKAGE-$PKGVER-$PKGREL-aarch64.pkg.tar.zst" "$REPO/kernel/$PACKAGE-headers-$PKGVER-$PKGREL-aarch64.pkg.tar.zst") -for pkg in "${packages[@]}"; do [[ -s $pkg ]] || { echo "Paket fehlt: $pkg" >&2; exit 1; }; done +for pkg in "${PACKAGES[@]}"; do [[ -s $pkg ]] || { echo "Paket fehlt: $pkg" >&2; exit 1; }; done python3 - "$REPO" <<'PY' from pathlib import Path import hashlib, sys @@ -54,11 +55,11 @@ trap 'exit 130' INT trap 'exit 143' TERM if [[ -n $resume_backup ]]; then # Require a root-owned checkpoint and byte-identical package inputs. - python3 "$REPO/scripts/install_state.py" resume "$resume_backup" "${packages[@]}" + python3 "$REPO/scripts/install_state.py" resume "$resume_backup" "${PACKAGES[@]}" backup=$resume_backup else backup=$(mktemp -d /root/p16-install.XXXXXXXX) - python3 "$REPO/scripts/install_state.py" begin "$backup" "${packages[@]}" + python3 "$REPO/scripts/install_state.py" begin "$backup" "${PACKAGES[@]}" fi printf 'Sicherung und Checkpoint: %s\n' "$backup" python3 "$REPO/scripts/peripherals.py" apply --backup "$backup" @@ -69,7 +70,7 @@ for directory in /usr/share/libalpm/hooks /etc/pacman.d/hooks; do if [[ -e $hook ]]; then ln -sf /dev/null "$hooks/${hook##*/}"; fi done done -pacman -U --noconfirm --hookdir "$hooks" "${packages[@]}" +pacman -U --noconfirm --hookdir "$hooks" "${PACKAGES[@]}" dkms autoinstall -k "$RELEASE" depmod -a "$RELEASE" install -Dm644 "$REPO/config/p16-acpi" /etc/initcpio/install/p16-acpi @@ -83,6 +84,8 @@ done for conf in 00-omarchy-n1x-usb4.conf 00-omarchy-n1x-gpu.conf 00-omarchy-n1x-sleep.conf; do install -Dm644 "$REPO/config/$conf" "/etc/limine-entry-tool.d/$conf" done +# With Secure Boot off, the menu entry's cmdline overrides the one in the UKI. Give the entry the same one, unquoted. +printf 'KERNEL_CMDLINE[%s]=%s\n' "$PACKAGE" "$(<"$REPO/build/p16.cmdline")" > "$CMDLINE_DROPIN" for table in DSDT.aml SSDT.aml; do install -Dm644 "$REPO/build/acpi/kernel/firmware/acpi/$table" "/etc/initcpio/p16-acpi/$table" done diff --git a/scripts/install_state.py b/scripts/install_state.py index 8faa8a8..09dd615 100755 --- a/scripts/install_state.py +++ b/scripts/install_state.py @@ -5,10 +5,11 @@ import json import os from pathlib import Path +import re import shutil import tempfile -from p16_release import IMAGE, PACKAGE, RELEASE +from p16_release import CMDLINE_DROPIN, IMAGE, PACKAGE, RELEASE TARGET = '/boot' + IMAGE CONFIG_PATHS = [ @@ -37,6 +38,7 @@ '/etc/libinput/local-overrides.quirks', '/etc/mkinitcpio.conf.d/zz-p16-speakers.conf', '/etc/UPower/UPower.conf.d/50-p16-critical.conf', + CMDLINE_DROPIN, '/usr/lib/firmware/cirrus/cs35l56-b0-dsp1-misc-10431484-spkid0.wmfw', '/usr/lib/firmware/cirrus/cs35l56-b0-dsp1-misc-10431484-spkid0-l1u0.bin', '/usr/lib/firmware/cirrus/cs35l56-b0-dsp1-misc-10431484-spkid0-l1u1.bin', @@ -149,6 +151,17 @@ def resume(backup, packages, root=Path('/')): save(backup, state) +def menu_entries(menu): + """Each Limine entry: its /-line and the lines below it, up to the next /-line.""" + entries = [] + for line in menu.splitlines(): + if line.lstrip().startswith('/'): + entries.append([line]) + elif entries and line.strip(): + entries[-1].append(line.rstrip()) + return ['\n'.join(entry) for entry in entries] + + def verify_preserved(backup, root=Path('/')): state = load(backup) for name, info in state['files'].items(): @@ -157,9 +170,11 @@ def verify_preserved(backup, root=Path('/')): require(current.is_file() and digest(current) == info['digest'], 'Vorhandenes EFI-Image verändert: ' + name) old = (backup / 'files/boot/limine.conf').read_text() current = (root / 'boot/limine.conf').read_text() - import re require(re.findall(r'^default_entry:.*$', old, re.M) == re.findall(r'^default_entry:.*$', current, re.M), 'Bootstandard wurde geändert') + kept = menu_entries(current) + lost = [entry.splitlines()[0].strip() for entry in menu_entries(old) if entry not in kept] + require(not lost, 'Vorhandene Booteinträge fehlen oder wurden verändert: ' + ', '.join(lost)) def restore(backup, root=Path('/'), status='restored'): diff --git a/scripts/kernel_cmdline.py b/scripts/kernel_cmdline.py index 91bb399..44bc357 100644 --- a/scripts/kernel_cmdline.py +++ b/scripts/kernel_cmdline.py @@ -6,9 +6,7 @@ PLATFORM_OPTIONS = [ 'console=tty0', 'acpi=nospcr', 'acpi_osi=!Windows 2022', - 'power_wrap_drv.usb4_release=0', 'pci=hpbussize=0x80,hpmmiosize=32M,hpmmioprefsize=32G', - 'mem_sleep_default=s2idle', ] @@ -27,13 +25,17 @@ def build(text): for name in names: if name.startswith('initcall_blacklist='): initcalls.extend(x for x in name.split('=', 1)[1].split(',') if x) - args = [a for a, n in zip(args, names) if not n.startswith(blocked)] + # An empty word says nothing, and limine-entry-tool drops it from the menu entry. + args = [a for a, n in zip(args, names) if n and not n.startswith(blocked)] args += PLATFORM_OPTIONS + ['initcall_blacklist=' + ','.join(dict.fromkeys(initcalls))] for arg in args: - if any(c in arg for c in ('"', '\n', '\r', '\x00')): + # limine-entry-tool reads ' and " as quotes when it splits the entry's line into words. + if any(c in arg for c in ('"', "'", '\n', '\r', '\x00')): raise ValueError('Invalid character in kernel command line.') - return ' '.join('acpi_osi="!Windows 2022"' if a == 'acpi_osi=!Windows 2022' else - '"' + a + '"' if any(c.isspace() for c in a) else a for a in args) + '\n' + words = ('acpi_osi="!Windows 2022"' if a == 'acpi_osi=!Windows 2022' else + '"' + a + '"' if any(c.isspace() for c in a) else a for a in args) + # limine-entry-tool keeps the first of equal words in the menu entry; the UKI gets the same line. + return ' '.join(dict.fromkeys(words)) + '\n' if __name__ == '__main__': diff --git a/scripts/p16-boot-menu-policy.py b/scripts/p16-boot-menu-policy.py index bebdad2..b4de901 100644 --- a/scripts/p16-boot-menu-policy.py +++ b/scripts/p16-boot-menu-policy.py @@ -12,6 +12,7 @@ 'Omarchy/linux-p16-asus-23', 'Omarchy/linux-p16-asus-24', 'Omarchy/linux-p16-asus-25', + 'Omarchy/linux-p16-asus-26', 'Omarchy/linux-p16-asus-23-npu2', 'Omarchy/linux-rtx-spark-npu', } diff --git a/scripts/p16_release.py b/scripts/p16_release.py index 48ba6a7..fc62190 100644 --- a/scripts/p16_release.py +++ b/scripts/p16_release.py @@ -1,9 +1,26 @@ -"""The P16 kernel release, read from its one source: pkgver and pkgrel in kernel/PKGBUILD.""" +"""The P16 kernel release, read from the recipe makepkg builds: pkgver and pkgrel in build/kernel/PKGBUILD. + +scripts/build-kernel.sh assembles that recipe. Shell scripts read the release with --shell. +""" from pathlib import Path import re +import shlex +import sys -_PKGBUILD = (Path(__file__).resolve().parents[1] / 'kernel/PKGBUILD').read_text() +RECIPE = Path(__file__).resolve().parents[1] / 'build/kernel' +_PKGBUILD = (RECIPE / 'PKGBUILD').read_text() PKGVER, PKGREL = (re.search(rf'^{name}=(\S+)$', _PKGBUILD, re.M)[1] for name in ('pkgver', 'pkgrel')) PACKAGE = 'linux-p16-asus-' + PKGREL -RELEASE = f'{PKGVER}-{PKGREL}-omarchy-p16-asus' +# The kernel names version x.y as x.y.0. +RELEASE = '.'.join((PKGVER.split('.') + ['0'])[:3]) + f'-{PKGREL}-omarchy-p16-asus' IMAGE = f'/EFI/Linux/omarchy_{PACKAGE}.efi' +# limine-entry-tool writes this kernel's menu command line from KERNEL_CMDLINE[PACKAGE], on install and on every rebuild. +CMDLINE_DROPIN = f'/etc/limine-entry-tool.d/zz-p16-cmdline-{PACKAGE}.conf' +PACKAGES = [RECIPE / f'{PACKAGE}{part}-{PKGVER}-{PKGREL}-aarch64.pkg.tar.zst' for part in ('', '-headers')] + +if __name__ == '__main__': + if sys.argv[1:] != ['--shell']: + sys.exit('Usage: p16_release.py --shell') + for name in ('PACKAGE', 'RELEASE', 'IMAGE', 'CMDLINE_DROPIN'): + print(f'{name}={shlex.quote(globals()[name])}') + print('PACKAGES=(' + ' '.join(shlex.quote(str(p)) for p in PACKAGES) + ')') diff --git a/scripts/usb4-pcie-hotplug-check b/scripts/usb4-pcie-hotplug-check new file mode 100755 index 0000000..dfefc13 --- /dev/null +++ b/scripts/usb4-pcie-hotplug-check @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +"""Check that a USB4 PCIe device connected after boot gets its PCIe tunnel. + +Run with nothing connected to USB4, connect the device when asked, then +disconnect it when asked. PASS needs, while connected: PCIe devices below a +10de:22cf tunnel root port, that port in D0 with a runtime PM reference, and at +least one NVMe controller behind it, each with a block device. After disconnect: the port +back in D3cold with no reference. Read-only; root is not needed. +""" +from pathlib import Path +import re +import subprocess +import sys +import time + +PCI = Path('/sys/bus/pci/devices') +CHILD = re.compile(r'[0-9a-f]{4}:[0-9a-f]{2}:[0-9a-f]{2}\.[0-7]') +WAIT = 120 +NVME_CLASS = '0x010802' + + +def read(path): + return Path(path).read_text().strip() + + +def tunnel_ports(): + return [p for p in sorted(PCI.iterdir()) + if read(p / 'vendor') == '0x10de' and read(p / 'device') == '0x22cf'] + + +def children(port): + """Every PCI function below the port, at any depth.""" + return sorted(d for d in port.resolve().rglob('*') if CHILD.fullmatch(d.name) and (d / 'vendor').exists()) + + +def disks(function): + """Block devices of an NVMe PCI function. A multipath namespace shows as nvmeXcYnZ; its disk is nvmeXnZ.""" + names = {re.sub(r'c\d+n', 'n', n.name) for n in function.glob('nvme/nvme*/nvme*n*')} + return [f'/dev/{n}' for n in sorted(names) if Path('/dev', n).is_block_device()] + + +def state(port): + return read(port / 'power_state'), int(read(port / 'power/runtime_usage')) + + +def show(port): + power, usage = state(port) + print(f' {port.name}: {power}, runtime PM references {usage}, {len(children(port))} devices below') + + +def wait_for(condition, what): + for _ in range(WAIT * 2): + found = condition() + if found: + return found + time.sleep(0.5) + print(f'No {what} within {WAIT} s.') + return None + + +def main(): + print('Kernel', read('/proc/sys/kernel/osrelease')) + ports = tunnel_ports() + if not ports: + sys.exit('FAIL: no 10de:22cf tunnel root port found') + for port in ports: + show(port) + if any(children(p) for p in ports): + sys.exit('Disconnect every USB4 PCIe device, then run this again.') + + input('\nConnect the USB4 NVMe enclosure, or a dock with an NVMe drive, then press Enter. ') + port = wait_for(lambda: next((p for p in ports if children(p)), None), 'PCIe device below a tunnel root port') + failures = [] + if port is None: + failures.append('no PCIe tunnel: the device is on USB only') + else: + time.sleep(5) + print(f'\nConnected below {port.name}:') + print(subprocess.run(['lspci', '-tv', '-s', port.name.split(':')[0] + ':'], + capture_output=True, text=True).stdout.rstrip()) + show(port) + power, usage = state(port) + if power != 'D0': + failures.append(f'{port.name} is {power} while connected') + if usage < 1: + failures.append(f'{port.name} has no runtime PM reference while connected') + nvme = [d for d in children(port) if read(d / 'class') == NVME_CLASS] + if not nvme: + failures.append(f'no NVMe controller below {port.name}') + for function in nvme: + speed = f"{read(function / 'current_link_speed')} x{read(function / 'current_link_width')}" + found = wait_for(lambda: disks(function), f'block device for NVMe {function.name}') + print(f' NVMe {function.name}: {", ".join(found or ["no block device"])}, PCIe {speed}') + if not found: + failures.append(f'NVMe {function.name} has no block device') + + input('\nDisconnect the device, then press Enter. ') + gone = wait_for(lambda: not children(port) and state(port) == ('D3cold', 0) and port, + 'D3cold without a runtime PM reference after disconnect') + print('After disconnect:') + show(port) + if gone is None: + power, usage = state(port) + failures.append(f'{port.name} is {power} with {usage} references after disconnect') + + print() + for failure in failures: + print('FAIL:', failure) + print('FAIL' if failures else 'PASS') + sys.exit(1 if failures else 0) + + +if __name__ == '__main__': + main() diff --git a/scripts/verify-boot.py b/scripts/verify-boot.py index 0959180..2f9a0c9 100755 --- a/scripts/verify-boot.py +++ b/scripts/verify-boot.py @@ -8,6 +8,7 @@ import subprocess import tempfile from p16_release import IMAGE, PACKAGE, RELEASE +from install_state import menu_entries PINS = {'DSDT.aml': '80e0ad4a051704003d09029cb600a9814e1cd370ce774b9749dc09d2232b5aaf', 'SSDT.aml': '9b28ffc14c19f8b7ea2278de88ff9ec070f5f70401107d81fef067a916aa9695'} def sections(path): @@ -89,8 +90,10 @@ def verify_image(path): if not subprocess.check_output(['pacman', '-Qoq', '/usr/lib/modules/' + RELEASE + '/vmlinuz'], text=True).strip() == PACKAGE: raise ValueError('Kernelimage gehört nicht zum P16-Paket') print('UKI, ACPI-Overrides und Modulabhängigkeiten gültig:', path) + return cmd.strip() -def verify_menu(config_path=Path('/boot/limine.conf'), boot_root=Path('/boot')): +def verify_menu(cmdline, config_path=Path('/boot/limine.conf'), boot_root=Path('/boot')): + """cmdline: the P16 UKI's own. With Secure Boot off, the entry's cmdline overrides it, so they must match.""" config = config_path.read_text() entries = [] for line in config.splitlines(): @@ -107,8 +110,12 @@ def verify_menu(config_path=Path('/boot/limine.conf'), boot_root=Path('/boot')): if hashlib.blake2b(image.read_bytes()).hexdigest() != pin.lower(): raise ValueError('EFI-Hash stimmt nicht: ' + path) entries.append(path) - if IMAGE not in entries: + # The P16 entry is the one whose active path line boots the image; text elsewhere that names it is not. + p16 = [entry for entry in menu_entries(config) if re.search(r'^\s*path:\s*boot\(\):' + re.escape(IMAGE) + '#', entry, re.M)] + if not p16: raise ValueError('P16-Eintrag fehlt im Limine-Menü') + if any(re.findall(r'^\s*cmdline:\s*(.*?)\s*$', entry, re.M) != [cmdline] for entry in p16): + raise ValueError('P16-Eintrag startet nicht mit der Befehlszeile des UKI') for key, expected in [('quiet', 'no'), ('timeout', '10')]: values = re.findall(r'^' + key + r':\s*(.*?)\s*$', config, re.M) if values != [expected]: @@ -121,8 +128,8 @@ def verify_menu(config_path=Path('/boot/limine.conf'), boot_root=Path('/boot')): parser.add_argument('--image-only', action='store_true') args = parser.parse_args() try: - verify_image(args.image) + cmdline = verify_image(args.image) if not args.image_only: - verify_menu() + verify_menu(cmdline) except (ValueError, OSError, KeyError, struct.error, subprocess.CalledProcessError) as error: parser.exit(1, 'Boot-Prüfung fehlgeschlagen: ' + str(error) + '\n') diff --git a/sources.json b/sources.json index 62cfcc4..78d0bc7 100644 --- a/sources.json +++ b/sources.json @@ -1,17 +1,23 @@ { "kernel": { "repository": "https://github.com/omacom/omarchy-pkgs", - "commit": "9db7ac36d410aca6d571975be1a5a77677918569", - "path": "pkgbuilds/linux-omarchy-aarch64", - "version": "7.2.8-23" + "commit": "b4e7d40dd9aec8173dbd532479b56f585e6ebba3", + "path": "pkgbuilds/linux-omarchy-aarch64" + }, + "p16_platform": { + "pull_request": "https://github.com/omacom/omarchy-pkgs/pull/1958", + "commit": "f9a172dad09e5cd171039debf4d4aa281c880ab6", + "patches": [ + "9100-asus-arm64-wmi-p16.patch", + "9101-p16-virtual-gpio.patch", + "9103-asus-capability-aware-initialization.patch", + "9104-spi-hid-acpi-reset-handle.patch" + ] }, "acpi": { "repository": "https://github.com/pfeifferj/archlinuxarm-proart-p16", "commit": "3484cc008a9ee00b34c086c729e28e935cbc3430" }, - "spi_hid": "Included by Omarchy patches 2110-2120; see pinned kernel source", - "wmi_arm64": "https://lore.kernel.org/all/20260917021055.8029-2-chipang_kao@asus.com/", - "asus_arm64": "https://lore.kernel.org/all/20260922032157.120188-1-chipang_kao@asus.com/", "acpica": { "version": "20260408", "url": "https://github.com/acpica/acpica/releases/download/20260408/acpica-unix-20260408.tar.gz", diff --git a/tests/test_installation.py b/tests/test_installation.py index 55fdad6..fe796f7 100644 --- a/tests/test_installation.py +++ b/tests/test_installation.py @@ -5,7 +5,9 @@ import json import os from pathlib import Path +import re import runpy +import shlex import shutil import struct import subprocess @@ -15,21 +17,32 @@ from unittest.mock import patch REPO = Path(__file__).resolve().parents[1] -sys.path.insert(0, str(REPO / 'scripts')) +# The scripts read the release from the assembled recipe. The reader runs here +# from a temporary repository root that holds a small one. +_ROOT = tempfile.TemporaryDirectory() +ROOT = Path(_ROOT.name) +(ROOT / 'scripts').mkdir() +for _name in ('common.sh', 'p16_release.py'): + shutil.copy2(REPO / 'scripts' / _name, ROOT / 'scripts' / _name) +(ROOT / 'build/kernel').mkdir(parents=True) +(ROOT / 'build/kernel/PKGBUILD').write_text('pkgver=7.3\npkgrel=26\n') +sys.path.insert(0, str(ROOT / 'scripts')) +import p16_release as release # noqa: E402 from p16_release import IMAGE # noqa: E402 P16_EFI = Path(IMAGE).name +CMDLINE = 'root=/dev/mapper/root rootflags=subvol=@nv620 rw acpi_osi="!Windows 2022" console=tty0' def module(name, filename): spec = importlib.util.spec_from_file_location(name, REPO / 'scripts' / filename) - loaded = importlib.util.module_from_spec(spec) + loaded = sys.modules[name] = importlib.util.module_from_spec(spec) spec.loader.exec_module(loaded) return loaded +state = module('install_state', 'install_state.py') # verify-boot imports it boot = module('verify_boot', 'verify-boot.py') -state = module('install_state', 'install_state.py') cmdline = module('kernel_cmdline', 'kernel_cmdline.py') @@ -44,17 +57,28 @@ def setUp(self): for name in ['stock.efi', P16_EFI]: (self.images / name).write_bytes(name.encode()) - def entry(self, name): + def entry(self, name, cmdline=CMDLINE): pin = hashlib.blake2b((self.images / name).read_bytes()).hexdigest() - return ' path: boot():/EFI/Linux/' + name + '#' + pin + '\n' + return ' //' + name + '\n path: boot():/EFI/Linux/' + name + '#' + pin + '\n cmdline: ' + cmdline + '\n' def verify(self, extra, options='quiet: no\ntimeout: 10\n'): - self.config.write_text(options + self.entry('stock.efi') + extra) - boot.verify_menu(self.config, self.root) + self.config.write_text(options + self.entry('stock.efi', 'rootflags=subvol=@') + extra) + boot.verify_menu(CMDLINE, self.config, self.root) def test_valid_stock_and_p16(self): self.verify(self.entry(P16_EFI)) + def test_p16_entry_must_boot_the_uki_cmdline(self): + # limine-entry-tool gave a 7.3 entry the default cmdline: root @, no RMSkipACPIBattCap. With Secure Boot off it wins. + for line in ['rootflags=subvol=@ rw acpi_osi="!Windows 2022"', CMDLINE + ' mem_sleep_default=s2idle']: + with self.subTest(line=line): + with self.assertRaisesRegex(ValueError, 'Befehlszeile des UKI'): + self.verify(self.entry(P16_EFI, line)) + + def test_p16_entry_is_found_by_its_path(self): + # A comment that names the P16 image does not make the stock entry the P16 entry. + self.verify(' # old: boot():' + IMAGE + '#' + '0' * 128 + '\n' + self.entry(P16_EFI)) + def test_missing_p16_is_rejected(self): with self.assertRaisesRegex(ValueError, 'P16-Eintrag fehlt'): self.verify('') @@ -77,7 +101,11 @@ def test_missing_image_is_rejected(self): def test_comments_do_not_supply_missing_entry(self): with self.assertRaisesRegex(ValueError, 'P16-Eintrag fehlt'): - self.verify('# '+self.entry(P16_EFI)) + self.verify(''.join('# ' + line + '\n' for line in self.entry(P16_EFI).splitlines())) + # A comment field that holds the image's pinned path is not an entry either. + pinned = self.entry(P16_EFI).splitlines()[1].split('path: ')[1] + with self.assertRaisesRegex(ValueError, 'P16-Eintrag fehlt'): + self.verify(' comment: ' + pinned + '\n') def test_conflicting_menu_options_are_rejected(self): with self.assertRaises(ValueError): @@ -179,7 +207,7 @@ def test_shell_failure_handler_restores_and_preserves_exit_code(self): python = commands/'python3' python.write_text('#!/usr/bin/python3\n' 'import importlib.util, os, pathlib, sys\n' - 'sys.path.insert(0, os.path.dirname(os.environ["TEST_STATE_MODULE"]))\n' + 'sys.path.insert(0, os.environ["TEST_RELEASE_DIR"])\n' 'spec=importlib.util.spec_from_file_location("state", os.environ["TEST_STATE_MODULE"])\n' 'm=importlib.util.module_from_spec(spec);spec.loader.exec_module(m)\n' 'm.restore(pathlib.Path(sys.argv[3]), pathlib.Path(os.environ["TEST_ROOT"]), status="failed")\n') @@ -193,7 +221,7 @@ def test_shell_failure_handler_restores_and_preserves_exit_code(self): handler=source[source.index('finish() {'):source.index('if [[ -n $resume_backup ]]; then')] env=dict(os.environ, backup=str(self.backup), hooks='', PATH=str(commands)+':'+os.environ['PATH'], TEST_ROOT=str(self.root), - TEST_STATE_MODULE=str(REPO/'scripts/install_state.py')) + TEST_STATE_MODULE=str(REPO/'scripts/install_state.py'), TEST_RELEASE_DIR=str(ROOT/'scripts')) script='source '+str(REPO/'scripts/common.sh')+'\n'+handler+'\nexit 7\n' process=subprocess.run(['bash', '-c', script], env=env, capture_output=True, text=True) self.assertEqual(process.returncode, 7, process.stderr) @@ -270,6 +298,19 @@ def test_preservation_detects_changed_existing_image(self): with self.assertRaisesRegex(ValueError, 'EFI-Image verändert'): state.verify_preserved(self.backup, self.root) + def test_preservation_requires_every_saved_menu_entry(self): + stock = '/+Omarchy\n//linux-p16-asus-24\n protocol: efi\n path: boot():/EFI/Linux/stock.efi#' + 'a' * 128 + '\n' + self.menu.write_text('default_entry: 2\n' + stock) + backup = self.base / 'menu-backup' + backup.mkdir() + state.begin(backup, self.packages, self.root) + added = '//linux-p16-asus-26\n protocol: efi\n path: boot():' + IMAGE + '#' + 'b' * 128 + '\n' + self.menu.write_text('timeout: 10\ndefault_entry: 2\n' + stock + added) + state.verify_preserved(backup, self.root) + self.menu.write_text('default_entry: 2\n/+Omarchy\n' + added) + with self.assertRaisesRegex(ValueError, 'linux-p16-asus-24'): + state.verify_preserved(backup, self.root) + class ValidationTests(unittest.TestCase): def test_fresh_build_directory_has_compiling_users_owner(self): @@ -279,8 +320,6 @@ def test_fresh_build_directory_has_compiling_users_owner(self): root = Path(tmp) (root/'scripts').mkdir() shutil.copy2(REPO/'scripts/common.sh', root/'scripts/common.sh') - (root/'kernel').mkdir() - shutil.copy2(REPO/'kernel/PKGBUILD', root/'kernel/PKGBUILD') env = dict(os.environ, SUDO_UID=str(os.getuid()), SUDO_GID=str(os.getgid())) subprocess.run(['bash', '-c', 'source "$1"; prepare_build_dir', 'bash', str(root/'scripts/common.sh')], env=env, check=True) build = root/'build' @@ -346,7 +385,6 @@ def test_downloader_rejects_wrong_architecture_before_curl(self): class CommandLineTests(unittest.TestCase): def test_fresh_install_preserves_encryption_and_adds_platform_options(self): - import shlex host = 'cryptdevice=UUID=example:root root=/dev/mapper/root rootflags=subvol=@ rw' result = cmdline.build(host) args = shlex.split(result) @@ -357,19 +395,20 @@ def test_fresh_install_preserves_encryption_and_adds_platform_options(self): self.assertEqual(cmdline.build(result), result) def test_conflicts_and_recovery_flags_are_replaced(self): - import shlex args = shlex.split(cmdline.build( 'root=/dev/mapper/root pci=nomsi mem_sleep_default=deep acpi=off ' + 'power_wrap_drv.usb4_release=0 ' 'module_blacklist=nvidia systemd.unit=emergency.target ' 'initcall_blacklist=other_init')) self.assertNotIn('pci=nomsi', args) self.assertNotIn('acpi=off', args) self.assertNotIn('systemd.unit=emergency.target', args) self.assertNotIn('module_blacklist=nvidia', args) + # Omarchy 1112 and 1113 make these the defaults; the new entry carries neither. + self.assertFalse([a for a in args if a.startswith(('mem_sleep_default=', 'power_wrap_drv.usb4_release='))]) self.assertIn('initcall_blacklist=simpledrm_platform_driver_init,other_init', args) def test_limine_dropins_preserve_option_boundaries(self): - import shlex files = [REPO/'config'/name for name in ( '00-omarchy-n1x-usb4.conf', '00-omarchy-n1x-gpu.conf', '00-omarchy-n1x-sleep.conf', 'limine-p16-keyboard.conf')] @@ -400,36 +439,74 @@ def test_quoted_dropin_argument_is_replaced(self): # A kept argument keeps its exact value, spaces included. self.assertIn('"rootflags=subvol=system "', result) + def test_menu_entry_keeps_the_built_line(self): + # limine-entry-tool 1.40.0 BootOptions.cleanKernelParameters rewrites the entry's line: it splits words at + # whitespace outside ' or " and keeps the first of equal words. A line it changed failed the menu check. + def entry_line(text): + words, word, quote = [], '', '' + for c in text: + if quote: + word += c + quote = '' if c == quote else quote + elif c in '"\'': + quote, word = c, word + c + elif c.isspace(): + words, word = words + [word] if word else words, '' + else: + word += c + return ' '.join(dict.fromkeys(words + [word] if word else words)) + for text in ['root=/dev/mapper/root quiet quiet splash quiet', 'root=/dev/mapper/root ""', + 'root=/dev/mapper/root "rootflags=subvol=a b" \' acpi_osi="!Windows 2022"\'']: + with self.subTest(text=text): + line = cmdline.build(text).strip() + self.assertEqual(entry_line(line), line) + with self.assertRaises(ValueError): + cmdline.build('root=/dev/mapper/root "rootflags=subvol=O\'Reilly"') + def test_live_iso_is_rejected(self): with self.assertRaises(ValueError): cmdline.build('quiet splash') +class ReleaseTests(unittest.TestCase): + SHELL = 'source "$1"; release=$(python3 "$REPO/scripts/p16_release.py" --shell); eval "$release"; ' + + def test_shell_reads_the_release_the_kernel_reports(self): + # pkgver 7.3 builds the kernel 7.3.0. A plain join gave 7.3-26, which no kernel reports. + self.assertEqual(release.RELEASE, '7.3.0-26-omarchy-p16-asus') + script = self.SHELL + 'printf "%s\\n" "$PACKAGE" "$RELEASE" "$IMAGE" "${PACKAGES[@]}"' + shell = subprocess.check_output(['bash', '-c', script, 'bash', str(ROOT/'scripts/common.sh')], text=True) + self.assertEqual(shell.splitlines(), [release.PACKAGE, release.RELEASE, release.IMAGE, *map(str, release.PACKAGES)]) + + def test_missing_recipe_stops_the_script(self): + with tempfile.TemporaryDirectory() as tmp: + scripts = Path(tmp)/'scripts' + scripts.mkdir() + for name in ('common.sh', 'p16_release.py'): + shutil.copy2(REPO/'scripts'/name, scripts/name) + result = subprocess.run(['bash', '-c', self.SHELL + 'echo reached', 'bash', str(scripts/'common.sh')], + capture_output=True, text=True) + self.assertNotEqual(result.returncode, 0) + self.assertNotIn('reached', result.stdout) + self.assertIn('FileNotFoundError', result.stderr) + + class KernelInputsTests(unittest.TestCase): - def test_kernel_inputs_are_complete_verified_and_have_no_orphan_patches(self): - script = r'''source PKGBUILD -for ((i=0; i<${#source[@]}; i++)); do - printf '%s\t%s\t%s\n' "${source[i]}" "${sha256sums[i]}" "${b2sums[i]}" -done -for ((i=0; i<${#source_aarch64[@]}; i++)); do - printf '%s\t%s\t%s\n' "${source_aarch64[i]}" "${sha256sums_aarch64[i]}" "${b2sums_aarch64[i]}" -done -''' + def test_delta_patches_are_in_the_recipe_with_their_sums_and_none_is_orphaned(self): kernel = REPO / 'kernel' - records = subprocess.check_output(['bash', '-c', script], cwd=kernel, text=True) - local = set() - for line in records.splitlines(): - name, sha256, blake2 = line.split('\t') - if '://' in name: - continue - local.add(name) - data = (kernel / name).read_bytes() - if sha256 != 'SKIP': - self.assertEqual(hashlib.sha256(data).hexdigest(), sha256, name) - if blake2 != 'SKIP': - self.assertEqual(hashlib.blake2b(data).hexdigest(), blake2, name) - bundled = {p.name for p in kernel.iterdir() if p.suffix in ('.patch', '.sig')} - self.assertEqual(bundled - local, set(), 'Unreferenced kernel patch/signature') + added = ''.join(line[1:] + '\n' for line in (kernel/'PKGBUILD.patch').read_text().splitlines() + if line.startswith('+') and not line.startswith('+++')) + names, sha256, blake2 = ( + shlex.split(re.search(rf'^{array}\+=\((.*?)^\)', added, re.M | re.S)[1]) + for array in ('source', 'sha256sums', 'b2sums')) + self.assertEqual(len(names), len(sha256)) + self.assertEqual(len(names), len(blake2)) + for name, sha, b2 in zip(names, sha256, blake2): + data = (kernel/name).read_bytes() + self.assertEqual(hashlib.sha256(data).hexdigest(), sha, name) + self.assertEqual(hashlib.blake2b(data).hexdigest(), b2, name) + bundled = {p.name for p in kernel.iterdir()} - {'PKGBUILD.patch'} + self.assertEqual(bundled, set(names), 'Every delta file is a listed patch') if __name__ == '__main__':