Skip to content

Instantly share code, notes, and snippets.

@lamperez
Last active November 11, 2024 11:16
Show Gist options
  • Save lamperez/862763881c0e1c812392b5574727f6ff to your computer and use it in GitHub Desktop.
Save lamperez/862763881c0e1c812392b5574727f6ff to your computer and use it in GitHub Desktop.
CS35L41 amplifiers in an ASUS Zenbook on linux

Asus Zenbook UX3402 speakers on Linux

Important

THIS IS NOW OBSOLETE WITH KERNEL VERSIONS ≥ 6.7.0

A recent announcement in the kernel mail list by Cirrus developers will solve the problem described here. Therefore, the proposed solutions will be soon obsolete. See this comment (thanks, @flukejones, for the tip).

I got the speakers working on my Asus Zenbook 14 OLED UX3402, the one with Intel CPU and the two CS35L41 audio amplifiers connected over SPI (not the UM3402YA, with AMD and I²C). The amplifiers are supported by the snd_hda_scodec_cs35l41 module in recent kernel versions, but they require some model-specific configuration paramaters, that should be provided by the BIOS, via ACPI. Of course, they are missing. It seems that the Windows drivers have those parameters somehow hardcoded, instead of using ACPI (bad idea, but who am I to criticise). Since Asus has been nasty and refused/was not able to update the BIOS with the missing data, I have patched the ACPI tables myself.

Warning

As stated by Cirrus developers, if you try this there is a non-zero (low, I hope) possibility of blowing your speakers. Take into account that this procedure is not just configuring your box, it is hardware-level hacking with very scarce information about the hardware (thank you, ASUS, and thank you, Cirrus, for not publishing the CS35L41 datasheet and making it only available by request). Additionally, You should know how to work with DSDT or SSDT files (I have a brief guide here) and how to recover from a non booting system. You are on your own. You have been warned.

Note

I have used the patch for some months, and everything seems OK. As you can see, the most recent versions do not require electrical parameters to be specified, just providing the functions of several GPIO pins, that are already present in the original BIOS, and the behavior associated to them. I am almost sure that the patch is totally safe.

My BIOS is the most recent one (version 310). I have added two _DSD objects in the SSDT file (ssdt_csc3551.dsl, or its already assembled version, ssdt_csc3551.aml):

  • One inside the SPK1 device, providing the missing "cirrus,dev-index" and other properties, just like the I2C models. You can also provide these properties by patching the kernel module (the linux/sound/pci/hda/cs35l41_hda.c file).

  • Another one, after the SPK1 device, with the chip select GPIOs, "cs-gpios", required by the SPI bus (the somehow simpler I²C bus does not use chip select pins, but addresses). Without this _DSD object, only one amplifier can be addressed and activated. In this case, the driver refuses to load even for this single working amplifier.

Obsolete: DSDT patch

Instead of applying a SSDT file, you may patch the full DSDT dissassembled DSDT file (dsdt.dsl). This was my original solution (thanks to @thor2002ro for pointing to the simpler, nicer SSDT solution, see the comment, especially if you use grub). The patch is available for reference, just apply the SSDT file.

Obsolete: internal boost

I keep the old, original patch, that produced AMP short error messages when the volume was high enough, for reference. Please try first the simpler patch with external boost, that seems to work without flaws (thanks to @bdandy, see the comment).

Boot log

Output from journalctl -b -g CSC3551 --output short-monotonic after the old patch:

[5.358062] zenbook kernel: Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 SPI devices.
[5.643640] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
[5.680302] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
[5.996217] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Falling back to default firmware.
[5.996608] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: Firmware version: 3
[5.996611] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: cirrus/cs35l41-dsp1-spk-prot.wmfw: Fri 24 Jun 2022 14:55:56 GMT Daylight Time
[6.069598] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: Firmware: 400a4 vendor: 0x2 v0.58.0, 2 algorithms
[6.070173] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: 0: ID cd v29.78.0 XM@94 YM@e
[6.070185] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: 1: ID f20b v0.1.0 XM@17c YM@0
[6.070192] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: spk-prot: e:\workspace\workspace\tibranch_release_playback_6.76_2\ormis\staging\default_tunings\internal\CS35L53\Fixed_Attenuation_Mono_48000_29.78.0\full\Fixed_Attenuation_Mono_48000_29.78.0_full.bin
[6.083485] zenbook kernel: snd_hda_codec_realtek ehdaudio0D0: bound spi1-CSC3551:00-cs35l41-hda.0 (ops cs35l41_hda_comp_ops [snd_hda_scodec_cs35l41])
[6.083899] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Falling back to default firmware.
[6.083962] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: Firmware version: 3
[6.083966] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: cirrus/cs35l41-dsp1-spk-prot.wmfw: Fri 24 Jun 2022 14:55:56 GMT Daylight Time
[6.145224] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: Firmware: 400a4 vendor: 0x2 v0.58.0, 2 algorithms
[6.145817] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: 0: ID cd v29.78.0 XM@94 YM@e
[6.145828] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: 1: ID f20b v0.1.0 XM@17c YM@0
[6.145834] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: spk-prot: e:\workspace\workspace\tibranch_release_playback_6.76_2\ormis\staging\default_tunings\internal\CS35L53\Fixed_Attenuation_Mono_48000_29.78.0\full\Fixed_Attenuation_Mono_48000_29.78.0_full.bin
[6.161484] zenbook kernel: snd_hda_codec_realtek ehdaudio0D0: bound spi1-CSC3551:00-cs35l41-hda.1 (ops cs35l41_hda_comp_ops [snd_hda_scodec_cs35l41])

The "Falling back to default firmware" disappears if spk-id-gpios are provided (the block is commented in the patch). As a result, a different firmware is loaded, resulting in very low volume and strong distortion. If the new patch is used, that uses external boost, the sound is correct, and the log is

[0.004000] zenbook kernel: ACPI: Table Upgrade: install [SSDT-CUSTOM- CSC3551]
[0.004000] zenbook kernel: ACPI: SSDT 0x00000000368FD000 0001A0 (v01 CUSTOM CSC3551  00000001 INTL 20200925)
[5.607253] zenbook kernel: Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 SPI devices.
[5.906936] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
[5.907354] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Reset line busy, assuming shared reset
[5.938136] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
[6.239406] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: Firmware version: 3
[6.239415] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: cirrus/cs35l41-dsp1-spk-prot-10431e02.wmfw: Fri 27 Aug 2021 14:58:19 W. Europe Daylight Time
[6.313109] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: Firmware: 400a4 vendor: 0x2 v0.43.1, 2 algorithms
[6.313524] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: 0: ID cd v29.63.1 XM@94 YM@e
[6.313530] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: 1: ID f20b v0.1.0 XM@176 YM@0
[6.313535] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: DSP1: spk-prot: C:\Users\tyang\Desktop\Product Setting\SmartAMP\ASUS\ASUS_Zenbook\UX3402\Tuning Release\220304\ASUS_UX3402_L_tuning_IDYC_ReDc_PICL_RTL_0304.bin
[6.337211] zenbook kernel: snd_hda_codec_realtek ehdaudio0D0: bound spi1-CSC3551:00-cs35l41-hda.0 (ops cs35l41_hda_comp_ops [snd_hda_scodec_cs35l41])
[6.337534] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: Firmware version: 3
[6.337540] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: cirrus/cs35l41-dsp1-spk-prot-10431e02.wmfw: Fri 27 Aug 2021 14:58:19 W. Europe Daylight Time
[6.399070] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: Firmware: 400a4 vendor: 0x2 v0.43.1, 2 algorithms
[6.399612] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: 0: ID cd v29.63.1 XM@94 YM@e
[6.399623] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: 1: ID f20b v0.1.0 XM@176 YM@0
[6.399629] zenbook kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: DSP1: spk-prot: C:\Users\tyang\Desktop\Product Setting\SmartAMP\ASUS\ASUS_Zenbook\UX3402\Tuning Release\220304\ASUS_UX3402_R_tuning_IDYC_ReDc_PICL_RTL_0304.bin
[6.427637] zenbook kernel: snd_hda_codec_realtek ehdaudio0D0: bound spi1-CSC3551:00-cs35l41-hda.1 (ops cs35l41_hda_comp_ops [snd_hda_scodec_cs35l41])
--- dsdt.dsl.old 2023-03-26 01:06:48.845795666 +0100
+++ dsdt.dsl 2023-03-26 12:00:45.643851841 +0200
@@ -18,7 +18,7 @@
* Compiler ID "INTL"
* Compiler Version 0x20200717 (538969879)
*/
-DefinitionBlock ("", "DSDT", 2, "_ASUS_", "Notebook", 0x01072009)
+DefinitionBlock ("", "DSDT", 2, "_ASUS_", "Notebook", 0x0107200A)
{
/*
* iASL Warning: There were 233 external control methods found during
@@ -90642,7 +90642,48 @@
Method (_DIS, 0, NotSerialized) // _DIS: Disable Device
{
}
+
+ Name (_DSD, Package () // _DSD: Device-Specific Data
+ {
+ ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () { "cirrus,dev-index", Package () { Zero, One }},
+ Package () { "reset-gpios", Package () {
+ SPK1, One, Zero, Zero,
+ SPK1, One, Zero, Zero,
+ } },
+ // Package () { "spk-id-gpios", Package () {
+ // SPK1, 0x02, Zero, Zero,
+ // SPK1, 0x02, Zero, Zero,
+ // } },
+ Package () { "cirrus,speaker-position", Package () { Zero, One } },
+ Package () { "cirrus,gpio1-func", Package () { Zero, Zero } },
+ Package () { "cirrus,gpio2-func", Package () { 0x02, 0x02 } },
+ // boost-type: 0 internal, 1 external
+ Package () { "cirrus,boost-type", Package () { Zero, Zero } },
+ // boost-peak-milliamp: 1600 to 4500, increments of 50 mA
+ Package () { "cirrus,boost-peak-milliamp", Package () { 4500, 4500 } },
+ // boost-ind-nanohenry: 1000 | 1200 | 1500 | 2200 nH
+ Package () { "cirrus,boost-ind-nanohenry", Package () { 1000, 1000 } },
+ // boost-cap-microfarad: rounded to the nearest integer
+ Package () { "cirrus,boost-cap-microfarad", Package () { 24, 24 } },
+ },
+ })
}
+
+ Name (_DSD, Package ()
+ {
+ ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () { "cs-gpios", Package () {
+ Zero, // Native CS
+ SPK1, Zero, Zero, Zero // GPIO CS
+ } }
+ }
+ })
+
}
Scope (_SB.PC00.LPCB)
--- dsdt.dsl.old 2023-03-26 01:06:48.845795666 +0100
+++ dsdt.dsl 2023-03-26 12:00:45.643851841 +0200
@@ -18,7 +18,7 @@
* Compiler ID "INTL"
* Compiler Version 0x20200717 (538969879)
*/
-DefinitionBlock ("", "DSDT", 2, "_ASUS_", "Notebook", 0x01072009)
+DefinitionBlock ("", "DSDT", 2, "_ASUS_", "Notebook", 0x0107200A)
{
/*
* iASL Warning: There were 233 external control methods found during
@@ -90642,7 +90642,43 @@
Method (_DIS, 0, NotSerialized) // _DIS: Disable Device
{
}
+
+ Name (_DSD, Package () // _DSD: Device-Specific Data
+ {
+ ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () { "cirrus,dev-index", Package () { Zero, One }},
+ Package () { "reset-gpios", Package () {
+ SPK1, One, Zero, Zero,
+ SPK1, One, Zero, Zero,
+ } },
+ Package () { "spk-id-gpios", Package () {
+ SPK1, 0x02, Zero, Zero,
+ SPK1, 0x02, Zero, Zero,
+ } },
+ Package () { "cirrus,speaker-position", Package () { Zero, One } },
+ // gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
+ Package () { "cirrus,gpio1-func", Package () { One, One } },
+ Package () { "cirrus,gpio2-func", Package () { 0x02, 0x02 } },
+ // boost-type: 0 internal, 1 external
+ Package () { "cirrus,boost-type", Package () { One, One } },
+ },
+ })
}
+
+ Name (_DSD, Package ()
+ {
+ ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () { "cs-gpios", Package () {
+ Zero, // Native CS
+ SPK1, Zero, Zero, Zero // GPIO CS
+ } }
+ }
+ })
+
}
Scope (_SB.PC00.LPCB)
DefinitionBlock ("", "SSDT", 1, "CUSTOM", "CSC3551", 0x00000001)
{
External (_SB_.PC00.SPI0, DeviceObj)
External (_SB_.PC00.SPI0.SPK1, DeviceObj)
Scope (_SB.PC00.SPI0.SPK1)
{
Name (_DSD, Package ()
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () { "cirrus,dev-index", Package () { Zero, One }},
Package () { "reset-gpios", Package () {
SPK1, One, Zero, Zero,
SPK1, One, Zero, Zero
} },
Package () { "spk-id-gpios", Package () {
SPK1, 0x02, Zero, Zero,
SPK1, 0x02, Zero, Zero
} },
Package () { "cirrus,speaker-position", Package () { Zero, One } },
// gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
Package () { "cirrus,gpio1-func", Package () { One, One } },
Package () { "cirrus,gpio2-func", Package () { 0x02, 0x02 } },
// boost-type: 0 internal, 1 external
Package () { "cirrus,boost-type", Package () { One, One } }
}
})
}
Scope (_SB.PC00.SPI0)
{
Name (_DSD, Package ()
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () { "cs-gpios", Package () {
Zero, // Native CS
SPK1, Zero, Zero, Zero // GPIO CS
} }
}
})
}
}
@BillOTei
Copy link

@lamperez indeed... Something must be wrong with my grub as I did all the checks and update steps I think https://gist.github.com/lamperez/862763881c0e1c812392b5574727f6ff?permalink_comment_id=4573514#gistcomment-4573514

@Moooebie
Copy link

Hello. I have a Lenovo Thinkbook Plus Gen 3 (Alder-lake) which has exactly the same cs35l41 amps and exactly the same issue. Would you mind to share about the idea behind this patch and how are the "model specific" configurations obtained?
I'd like to see if I can also get it working on my laptop.
(I am pretty much a noob, these things are a bit overwhelming to me though)

@lamperez
Copy link
Author

lamperez commented May 26, 2023

@Moooebie The cs35l41 amplifiers are smart, they have their own microcontroller that must be booted and some firmware loaded. On the other hand, the ACPI tables contain a description of the computer hardware. Part of this description should be how the amplifiers are connected to the computer main chipset. It can be through a I2C or a SPI bus, with some additional GPIO pins of the chipset, that control things like the reset of the amplifiers during boot. Both buses are rather, similar with small differences (for example, the SPI connection requires an additional pin, a chip-select for the second amp).

Basically, the problem is that official ACPI contains the identification of the bus devices and the GPIO pins, in some lines like these:

SpiSerialBusV2 (0x0000, ... )
SpiSerialBusV2 (0x0001, ... )
GpioIo (Exclusive, PullUp, 0x0000, 0x0000, IoRestrictionOutputOnly,
    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
    )
        0x0156
    }
GpioIo (...)
...

but the functions of these devices and pins are not provided. For example, the kernel has no way to know that these two SpiSerialBusV2 devices connected to the SPI bus are cirrus,dev-index, as the driver expects, or that the 0x0156 GPIO is just the chip select pin for the second amplifier. Therefore the linux kernel is not able to communicate with the amplifiers, or even check their status or existence. I suppose the windows driver contains this information, somehow hardcoded.

The SSDT patch just provides the missing information about the bus devices, GPIO pins functions, and some configuration required to correctly boot the amplifiers and load their corresponding firmware (for example, which amplifier is left, which is right). Everything else is already available in linux kernels version 6.2 and above, and modern distro packages (I have checked current Ubuntu and PopOS!).

If your computer is different, expect different GPIO pins, but they should have the same functions. You should start by:

  • Check if your amplifiers are connected through SPI or I2C. The command journalctl -b -g CSC3551 is your friend.
  • The patches here are for SPI. For I2C they should be a bit simpler (no chip-select, the cs-gpios part).
  • Extract and disassemble your ACPI (see my guide).
  • Find the table corresponding to the amplifiers (mine is called CSC3551, easy to find with an editor).
  • If the table has no _DSD block, this is the one the patch needs to provide.
  • The the GPIOs are identified in the patch in order (the first one is SPK1, Zero, Zero, Zero, the second one SPK1, One, Zero, Zero, and so on).

@Moooebie
Copy link

@Moooebie The cs35l41 amplifiers are smart, they have their own microcontroller that must be booted and some firmware loaded. On the other hand, the ACPI tables contain a description of the computer hardware. Part of this description should be how the amplifiers are connected to the computer main chipset. It can be through a I2C or a SPI bus, with some additional GPIO pins of the chipset, that control things like the reset of the amplifiers during boot. Both buses are rather, similar with small differences (for example, the SPI connection requires an additional pin, a chip-select for the second amp).

Basically, the problem is that official ACPI contains the identification of the bus devices and the GPIO pins, in some lines like these:

SpiSerialBusV2 (0x0000, ... )
SpiSerialBusV2 (0x0001, ... )
GpioIo (Exclusive, PullUp, 0x0000, 0x0000, IoRestrictionOutputOnly,
    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
    )
        0x0156
    }
GpioIo (...)
...

but the functions of these devices and pins are not provided. For example, the kernel has no way to know that these two SpiSerialBusV2 devices connected to the SPI bus are cirrus,dev-index, as the driver expects, or that the 0x0156 GPIO is just the chip select pin for the second amplifier. Therefore the linux kernel is not able to communicate with the amplifiers, or even check their status or existence. I suppose the windows driver contains this information, somehow hardcoded.

The SSDT patch just provides the missing information about the bus devices, GPIO pins functions, and some configuration required to correctly boot the amplifiers and load their corresponding firmware (for example, which amplifier is left, which is right). Everything else is already available in linux kernels version 6.2 and above, and modern distro packages (I have checked current Ubuntu and PopOS!).

If your computer is different, expect different GPIO pins, but they should have the same functions. You should start by:

  • Check if your amplifiers are connected through SPI or I2C. The command journalctl -b -g CSC3551 is your friend.
  • The patches here are for SPI. For I2C they should be a bit simpler (no chip-select, the cs-gpios part).
  • Extract and disassemble your ACPI (see my guide).
  • Find the table corresponding to the amplifiers (mine is called CSC3551, easy to find with an editor).
  • If the table has no _DSD block, this is the one the patch needs to provide.
  • The the GPIOs are identified in the patch in order (the first one is SPK1, Zero, Zero, Zero, the second one SPK1, One, Zero, Zero, and so on).

I run that journalctl command and got these results:

May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Error: ACPI _DSD Properties are missing for HID CSC3551.
May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: error -EINVAL: Platform not supported
May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda: probe of i2c-CSC3551:00-cs35l41-hda.0 failed with error -22

So I believe they are the same speakers but on i2c bus. Following your guide to dump the file, I got the dsdt.dsl file and as expected it looks different from yours.
Since I don't really understand how the patch works, I just blindly inserted it after the "_DIS" block. The only change is that I replaced the SPK1 with SPKR since my device has a different name there. I also did not include the cs-gpios because it is on I2C bus. The whole scope block looks like this:

    Scope (_SB.PC00.I2C7)
    {
        Name (I2CN, Zero)
        Name (I2CX, Zero)
        Name (I2CI, 0x07)
        Method (_INI, 0, NotSerialized)  // _INI: Initialize
        {
            I2CN = SDS7 /* \SDS7 */
            I2CX = 0x07
        }

        Device (SPKR)
        {
            Name (_HID, "CSC3551")  // _HID: Hardware ID
            Method (_SUB, 0, NotSerialized)  // _SUB: Subsystem ID
            {
                If ((GGIV (0x090E000B) == One))
                {
                    Return ("17AA3846")
                }

                Return ("17AA3845")
            }

            Name (_UID, One)  // _UID: Unique ID
            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                Name (RBUF, ResourceTemplate ()
                {
                    I2cSerialBusV2 (0x0040, ControllerInitiated, 0x000F4240,
                        AddressingMode7Bit, "\\_SB.PC00.I2C7",
                        0x00, ResourceConsumer, , Exclusive,
                        )
                    I2cSerialBusV2 (0x0041, ControllerInitiated, 0x000F4240,
                        AddressingMode7Bit, "\\_SB.PC00.I2C7",
                        0x00, ResourceConsumer, , Exclusive,
                        )
                    GpioIo (Exclusive, PullDown, 0x0000, 0x0000, IoRestrictionOutputOnly,
                        "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                        )
                        {   // Pin list
                            0x0166
                        }
                    GpioIo (Shared, PullUp, 0x0064, 0x0000, IoRestrictionInputOnly,
                        "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                        )
                        {   // Pin list
                            0x0165
                        }
                    GpioInt (Edge, ActiveBoth, Shared, PullUp, 0x0064,
                        "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                        )
                        {   // Pin list
                            0x0165
                        }
                })
                Return (RBUF) /* \_SB_.PC00.I2C7.SPKR._CRS.RBUF */
            }

            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Return (0x0F)
            }

            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
            }

            Name (_DSD, Package ()   // _DSD: Device-Specific Data
            {
                ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package ()
                {
                    Package () { "cirrus,dev-index", Package () { Zero, One }},
                    Package () { "reset-gpios", Package () {
                       SPKR, One, Zero, Zero,
                       SPKR, One, Zero, Zero,
                    } },
                    Package () { "spk-id-gpios", Package () {
                       SPKR, 0x02, Zero, Zero,
                       SPKR, 0x02, Zero, Zero,
                    } },
                    Package () { "cirrus,speaker-position",     Package () { Zero, One } },
                    // gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
                    Package () { "cirrus,gpio1-func",           Package () { One, One } },
                    Package () { "cirrus,gpio2-func",           Package () { 0x02, 0x02 } },
                    // boost-type: 0 internal, 1 external
                    Package () { "cirrus,boost-type",           Package () { One, One } },
                },
            })

        }



    }

I also changed the Definition line to prioritize it over the ACPI table from BIOS.
I then compiled it and packed it into cpio following your guide, put it under /boot and manually added the initrd command in grub to load it before initramfs just as your example.
Now when I boot into system, the amps are still not working but with a different error:

May 26 16:34:12 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: No index found in cirrus,dev-index
May 26 16:34:12 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Failed property cirrus,dev-index: -19
May 26 16:34:12 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: error -ENODEV: Platform not supported
May 26 16:34:12 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: No index found in cirrus,dev-index
May 26 16:34:12 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Failed property cirrus,dev-index: -19
May 26 16:34:12 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: error -ENODEV: Platform not supported

I guess this means the patched ACPI table is loaded but I did not configure the "device specific" part correctly. Would you give me some help on how I should change it to resolve this error?
Sorry if I did ask a dumb question and thank you so much for the help!

@Moooebie
Copy link

I went to do some research and learned some basics about the ACPI Source Language. For now what I understand is that the patch which adds the _DSD object with that particular UUID is defining some properties of the device in package() {Key, Val} format, and according to your reply those are things about "GPIO pins functions" and "buses".
So with these errors, there is likely something I didn't correctly configure for the "cirrus,dev-index" part which defines the buses to be connected? If so, I wonder where I will be able to figure out the correct configuration. Also you said "they (GPIO pins) should have the same functions", does that mean that the configs for "gpio*-func" are likely to be good if I just leave them as is? Or I still have to find some other datasheets to figure out the specific config for my computer?
Sorry again for bothering, I don't have experiences in tinkering around these kind of things before and I am feeling lost. Really appreciate for your help!

@Moooebie
Copy link

Moooebie commented May 27, 2023

Just figured out that I should replace the package() {Zero, One} with the actual number for my device (package() {0x40, 0x41}). Now there are no more errors but speakers still not working:

May 27 02:03:55 mx3340-tbplus kernel: Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 I2C devices.
May 27 02:03:55 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
May 27 02:03:55 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Reset line busy, assuming shared reset
May 27 02:03:55 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
May 27 02:04:18 mx3340-tbplus dbus-daemon[548]: [system] Activating via systemd: service name='org.freedesktop.home1' unit='dbus-org.freedesktop.home1.service' >
May 27 02:04:19 mx3340-tbplus sudo[1581]:   mx3340 : TTY=pts/1 ; PWD=/home/mx3340 ; USER=root ; COMMAND=/usr/bin/journalctl -b -g CSC3551
May 27 02:05:11 mx3340-tbplus dbus-daemon[548]: [system] Activating via systemd: service name='org.freedesktop.home1' unit='dbus-org.freedesktop.home1.service' >
May 27 02:05:11 mx3340-tbplus sudo[1667]:   mx3340 : TTY=pts/1 ; PWD=/home/mx3340 ; USER=root ; COMMAND=/usr/bin/journalctl -b -g CSC3551

Looks like for now I have to also do some patch on the kernel driver?

EDIT: I saw another person had the exactly same situation, he figured it out and posted the solution under your dsdt patching guide. I'll try it tomorrow and hopefully it will work for me!

@Moooebie
Copy link

It worked!!! Thank you soooo much!!!!

@BillOTei
Copy link

BillOTei commented May 27, 2023 via email

@Moooebie
Copy link

amazing! Could you list the steps you took please? I need to do the same with my asus strix scar 18 Le sam. 27 mai 2023 à 17:37, Moebie Wu @.> a écrit :

@.
* commented on this gist. ------------------------------ It worked!!! Thank you soooo much!!!! — Reply to this email directly, view it on GitHub https://gist.github.com/lamperez/862763881c0e1c812392b5574727f6ff#gistcomment-4581541 or unsubscribe https://github.com/notifications/unsubscribe-auth/AARUVKXBT76HQRVIOQ2OF2LXIINSVBFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFQKSXMYLMOVS2I5DSOVS2I3TBNVS3W5DIOJSWCZC7OBQXE5DJMNUXAYLOORPWCY3UNF3GS5DZVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVEYTEMJVHE2TGMBTU52HE2LHM5SXFJTDOJSWC5DF . You are receiving this email because you commented on the thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .

Sure! Give me a few hours, I'm going to write in details about all what I did to get it working on my laptop/

@lamperez
Copy link
Author

@Moooebie Nice!

@Moooebie
Copy link

Moooebie commented May 29, 2023

amazing! Could you list the steps you took please? I need to do the same with my asus strix scar 18 Le sam. 27 mai 2023 à 17:37, Moebie Wu @.> a écrit :

@.
* commented on this gist. ------------------------------ It worked!!! Thank you soooo much!!!! — Reply to this email directly, view it on GitHub https://gist.github.com/lamperez/862763881c0e1c812392b5574727f6ff#gistcomment-4581541 or unsubscribe https://github.com/notifications/unsubscribe-auth/AARUVKXBT76HQRVIOQ2OF2LXIINSVBFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFQKSXMYLMOVS2I5DSOVS2I3TBNVS3W5DIOJSWCZC7OBQXE5DJMNUXAYLOORPWCY3UNF3GS5DZVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVEYTEMJVHE2TGMBTU52HE2LHM5SXFJTDOJSWC5DF . You are receiving this email because you commented on the thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .

Sorry for replying a bit late, I was busy during the weekend and I faced some other problems with my laptop and I just managed to solve it yesterday.
First, you want to see whether your amps are on i2c or spi. To do this, you run the comman sudo journalctl -b -g CSC3551. If it does not show up anything then maybe you do not have the exactly same amp. My laptop has it on i2c so I see similar things like this:

May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Error: ACPI _DSD Properties are missing for HID CSC3551.
May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: error -EINVAL: Platform not supported
May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda: probe of i2c-CSC3551:00-cs35l41-hda.0 failed with error -22

Then you'll have to dump your dsdt table following OP's guide (here). One you have it decompiled and got the dsdt.dsl, you open it and search for CSC3551. All of the things you have to patch will be inside that scope (...) block. First you copy the first _DSD block from the patch and add it directly after the empty _DIS method, so it will look something like this:

...
            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
            }

            Name (_DSD, Package ()   // _DSD: Device-Specific Data
            {
                ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package ()
                {
                    Package () { "cirrus,dev-index", Package () { 0x0040, 0x0041 }},
                    Package () { "reset-gpios", Package () {
                       SPKR, One, Zero, Zero,
                       SPKR, One, Zero, Zero,
                    } },
                    Package () { "spk-id-gpios", Package () {
                       SPKR, 0x02, Zero, Zero,
                       SPKR, 0x02, Zero, Zero,
                    } },
                    Package () { "cirrus,speaker-position",     Package () { Zero, One } },
                    // gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
                    Package () { "cirrus,gpio1-func",           Package () { One, One } },
                    Package () { "cirrus,gpio2-func",           Package () { 0x02, 0x02 } },
                    // boost-type: 0 internal, 1 external
                    Package () { "cirrus,boost-type",           Package () { One, One } },
                },
            })
...

The whole scope block of my laptop could be found in my previous post.
Notice that I have SPKR instead of SPK1 and Package () { "cirrus,dev-index", Package () { 0x0040, 0x0041 }} instead of {Zero, One}? These are the device specific thing you have to change here. The device name could be found in the brackets of the header of the device block, in my case it is: Device (SPKR) {... so I replace SPK1 with SPKR. Since your device is also ASUS maybe it is the same SPK1 so you don't have to change it.
The second change there was the ID of the two buses. You kind find these information under the Name (BRUF, ... which is inside the Name (_UID, .... That for my device looks like:

...
            Name (_UID, One)  // _UID: Unique ID
            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                Name (RBUF, ResourceTemplate ()
                {
                    I2cSerialBusV2 (0x0040, ControllerInitiated, 0x000F4240,
                        AddressingMode7Bit, "\\_SB.PC00.I2C7",
                        0x00, ResourceConsumer, , Exclusive,
                        )
                    I2cSerialBusV2 (0x0041, ControllerInitiated, 0x000F4240,
                        AddressingMode7Bit, "\\_SB.PC00.I2C7",
                        0x00, ResourceConsumer, , Exclusive,
                        )
...

So I replace the {Zero, One} with {0x0040, 0x0041}.
According to OP, if your amps are on SPI then you also want to add the second _DSD block in the patch outside of the device (...) block but still inside the scope.
Once you done that, go back to nearly the beginning of the file, change the very last parameter in the DefinitionBlock (... to a larger value to prioritize this patched table over that from the BIOS. It was 0x00 on my device, but it is probably a larger value on your device and you just have to change it to a larger number. Mine is:

DefinitionBlock ("", "DSDT", 2, "LENOVO", "CB-01   ", 0x00000009)

After that you follow the guide to recompile and package it into a .cpio file. Copy the .cpio file into /boot. If you use grub, on reboot you press "e" toward the boot option to enter the edit screen, load this cpio as an init ramdisk after the microcode and before the kernel's initrd. For example it might look like this:

...
initrd  /boot/intel-ucode.img /patched_dsdt.cpio /boot/initramfs-6.3.4.img

Run sudo journalctl -b -g CSC3551 again, if there is no error but similar output as that in my previous post, then the ACPI table patch worked. If your speakers work at this moment, then you are done (you may want to write the initrd loading command into grub's config so you won't need to type that manually on every reboot).
If they are still not working, you need to patch the driver in the kernel. Look for a guide to build a mainline kernel (btw. you need Linux 6.1+ for these speakers to work). I am using Manjaro Linux and I followed the guide on ArchWiki. Once you have the full kernel source ready, go to kernel_source_root/sound/pci/hda/patch_realtek.c and search for FIXUP_CS35L41_ until you find a list of things like this:

SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
...

Add a new line in the same format for your laptop.
The first two parameters can be find from the Subsystem ID. Run alsa-info to obtain it. In the output file, search for Subsystem Id and you get a 4 bytes long hex string, for example mine looks like: Subsystem Id: 0x17aa3875. Put the first four characters into the first parameter and the second for characters into the second parameter. The third parameter is just how you call your laptop, it does not matter in terms of functions and can be whatever. The last parameter could be ALC245_FIXUP_CS35L41_SPI_2 or ALC287_FIXUP_CS35L41_I2C_2 depends on whether your amps are on spi or i2c.
For my device specifically, the line is like:

SND_PCI_QUIRK(0x17aa, 0x3875, "Thinkbook Plus Gen3", ALC287_FIXUP_CS35L41_I2C_2)

Then you just build the kernel and set it up for the bootloader. Don't forget to include the .cpio with your patched dsdt table as a initrd. If you are lucky enough at this point your speakers should be finally working.

@Moooebie
Copy link

@Moooebie Nice!

Thank you so much for the patch and the help!!!

@lamperez
Copy link
Author

And thank you for the excellent guide for the i2c case.

@MotoG1980
Copy link

MotoG1980 commented May 29, 2023

Hello everyone. I would like to thank you very much first of all @Moooebie @lamperez for all that great work !
I need some help also with my rog strix laptop, regarding my spi

Here below, is what I extracted from my latest bios (acpi table) and want to know if I need to modify something here. I think in my case, asus has already patched the acpi table for my laptop. Please, let me know if I need to patch anything here.

sudo journalctl -b -g CSC3551

ACPI: SSDT 0x000000003073118B 000191 (v02 CUSTOM CSC3551 00000003 INTL 20221020)
cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Error: ACPI _DSD Properties are missing for HID CSC3551.
cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: error -EINVAL: Platform not supported
cs35l41-hda: probe of spi1-CSC3551:00-cs35l41-hda.0 failed with error -22
cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Error: ACPI _DSD Properties are missing for HID CSC3551.
cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: error -EINVAL: Platform not supported
cs35l41-hda: probe of spi1-CSC3551:00-cs35l41-hda.1 failed with error -22

Method (XWAK, 1, NotSerialized)
{
}

Scope (_SB.PC00.SPI3)
{
    Device (SPK1)
    {
        Name (_HID, "CSC3551")  // _HID: Hardware ID
        Name (_SUB, "10431C9F")  // _SUB: Subsystem ID
        Name (_UID, One)  // _UID: Unique ID
        Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
        {
            Name (SBUF, ResourceTemplate ()
            {
                SpiSerialBusV2 (0x0000, PolarityLow, FourWireMode, 0x08,
                    ControllerInitiated, 0x003D0900, ClockPolarityLow,
                    ClockPhaseFirst, "\\_SB.PC00.SPI3",
                    0x00, ResourceConsumer, , Exclusive,
                    )
                SpiSerialBusV2 (0x0001, PolarityLow, FourWireMode, 0x08,
                    ControllerInitiated, 0x003D0900, ClockPolarityLow,
                    ClockPhaseFirst, "\\_SB.PC00.SPI3",
                    0x00, ResourceConsumer, , Exclusive,
                    )
                GpioIo (Exclusive, PullUp, 0x0000, 0x0000, IoRestrictionOutputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x01D4
                    }
                GpioIo (Exclusive, PullDown, 0x0000, 0x0000, IoRestrictionOutputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x0140
                    }
                GpioIo (Exclusive, PullUp, 0x0000, 0x0000, IoRestrictionInputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x00C0
                    }
                GpioIo (Shared, PullUp, 0x0064, 0x0000, IoRestrictionInputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x0141
                    }
                GpioInt (Edge, ActiveBoth, Shared, PullUp, 0x0064,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x0141
                    }
            })
            Return (SBUF) /* \_SB_.PC00.SPI3.SPK1._CRS.SBUF */
        }

        Method (_STA, 0, NotSerialized)  // _STA: Status
        {
            Return (0x0F)
        }

        Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
        {
        }
    }
}

}

@Moooebie
Copy link

Moooebie commented May 29, 2023

@MotoG1980

Hi! I think your laptop has the exactly same problem which is the dsdt table missing _DSD properties (and I don't really think ASUS did already fixed it in your case). From the information I see, you can probably just apply the patch by OP without any changes. So the patched table for your laptop would probably be like this:

Scope (_SB.PC00.SPI3)
{
    Device (SPK1)
    {
        Name (_HID, "CSC3551")  // _HID: Hardware ID
        Name (_SUB, "10431C9F")  // _SUB: Subsystem ID
        Name (_UID, One)  // _UID: Unique ID
        Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
        {
            Name (SBUF, ResourceTemplate ()
            {
                SpiSerialBusV2 (0x0000, PolarityLow, FourWireMode, 0x08,
                    ControllerInitiated, 0x003D0900, ClockPolarityLow,
                    ClockPhaseFirst, "\\_SB.PC00.SPI3",
                    0x00, ResourceConsumer, , Exclusive,
                    )
                SpiSerialBusV2 (0x0001, PolarityLow, FourWireMode, 0x08,
                    ControllerInitiated, 0x003D0900, ClockPolarityLow,
                    ClockPhaseFirst, "\\_SB.PC00.SPI3",
                    0x00, ResourceConsumer, , Exclusive,
                    )
                GpioIo (Exclusive, PullUp, 0x0000, 0x0000, IoRestrictionOutputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x01D4
                    }
                GpioIo (Exclusive, PullDown, 0x0000, 0x0000, IoRestrictionOutputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x0140
                    }
                GpioIo (Exclusive, PullUp, 0x0000, 0x0000, IoRestrictionInputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x00C0
                    }
                GpioIo (Shared, PullUp, 0x0064, 0x0000, IoRestrictionInputOnly,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x0141
                    }
                GpioInt (Edge, ActiveBoth, Shared, PullUp, 0x0064,
                    "\\_SB.GPI0", 0x00, ResourceConsumer, ,
                    )
                    {   // Pin list
                        0x0141
                    }
            })
            Return (SBUF) /* \_SB_.PC00.SPI3.SPK1._CRS.SBUF */
        }

        Method (_STA, 0, NotSerialized)  // _STA: Status
        {
            Return (0x0F)
        }

        Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
        {
        }

        Name (_DSD, Package ()
        {
            ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
            Package ()
            {
                Package () { "cirrus,dev-index", Package () { Zero, One }},
                Package () { "reset-gpios", Package () {
                    SPK1, One, Zero, Zero,
                    SPK1, One, Zero, Zero
                } },
                Package () { "spk-id-gpios", Package () {
                    SPK1, 0x02, Zero, Zero,
                    SPK1, 0x02, Zero, Zero
                } },
                Package () { "cirrus,speaker-position", Package () { Zero, One } },
                // gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
                Package () { "cirrus,gpio1-func", Package () { One, One } },
                Package () { "cirrus,gpio2-func", Package () { 0x02, 0x02 } },
                // boost-type: 0 internal, 1 external
                Package () { "cirrus,boost-type", Package () { One, One } }
            }
        })
    }
    Name (_DSD, Package ()
    {
        ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
        Package ()
        {
            Package () { "cs-gpios", Package () { 
                Zero,                    // Native CS
                SPK1, Zero, Zero, Zero   // GPIO CS
            } }
        }
    })
}

Alternatively, since the exactly same patch will likely work for your laptop, you cam probably use the sddt patch directly provided by OP following the the "Option 2" of this guide which would be easier.
After applying the patch if the errors are gong but speakers still not working, you'll need to patch the kernel following the steps in my previous post.
BTW. you should really thank @lamperez for the patch and other people who figured out how the kernel driver should be patched! All what I did is just sharing the process how I used their works to get the speakers of my laptop working.

@JulienQNN
Copy link

Hi guys, thanks for good work and the great discussions, after following the process i'm getting stuck at Instantiated SPI devices, now when i do : journalctl -b -g CSC3551

Jun` 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Reset line busy, assuming shared reset
Jun 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
Jun 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
Jun 03 00:19:34 archlinux kernel: Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 SPI devices. 

This would be a kernel problem ?
Any clue ?

Thanks a lot

@Moooebie
Copy link

Moooebie commented Jun 2, 2023

Hi guys, thanks for good work and the great discussions, after following the process i'm getting stuck at Instantiated SPI devices, now when i do : journalctl -b -g CSC3551

Jun` 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Reset line busy, assuming shared reset
Jun 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
Jun 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
Jun 03 00:19:34 archlinux kernel: Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 SPI devices. 

This would be a kernel problem ? Any clue ?

Thanks a lot

If your speakers are still not working, then that means the ACPI patch is done correctly but the kernel has to patched for them to work.

@JulienQNN
Copy link

JulienQNN commented Jun 2, 2023

Hi guys, thanks for good work and the great discussions, after following the process i'm getting stuck at Instantiated SPI devices, now when i do : journalctl -b -g CSC3551

Jun` 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Reset line busy, assuming shared reset
Jun 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
Jun 03 00:19:34 archlinux kernel: cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
Jun 03 00:19:34 archlinux kernel: Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 SPI devices. 

This would be a kernel problem ? Any clue ?
Thanks a lot

If your speakers are still not working, then that means the ACPI patch is done correctly but the kernel has to patched for them to work.

Sorry to bother but i don't understand what i need to do more to the kernel, i saw your very useful comment here where you get the same error,
but i have no idea, what to do with linux/sound/pci/hda/patch_realtek.c, i have an UX3402ZA so i'm not sure i need to do something else ?

Thanks.

@BillOTei
Copy link

BillOTei commented Jun 5, 2023

amazing! Could you list the steps you took please? I need to do the same with my asus strix scar 18 Le sam. 27 mai 2023 à 17:37, Moebie Wu @.> a écrit :

_
@**
.**_* commented on this gist. ------------------------------ It worked!!! Thank you soooo much!!!! — Reply to this email directly, view it on GitHub https://gist.github.com/lamperez/862763881c0e1c812392b5574727f6ff#gistcomment-4581541 or unsubscribe https://github.com/notifications/unsubscribe-auth/AARUVKXBT76HQRVIOQ2OF2LXIINSVBFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFQKSXMYLMOVS2I5DSOVS2I3TBNVS3W5DIOJSWCZC7OBQXE5DJMNUXAYLOORPWCY3UNF3GS5DZVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFVEYTEMJVHE2TGMBTU52HE2LHM5SXFJTDOJSWC5DF . You are receiving this email because you commented on the thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .

Sorry for replying a bit late, I was busy during the weekend and I faced some other problems with my laptop and I just managed to solve it yesterday. First, you want to see whether your amps are on i2c or spi. To do this, you run the comman sudo journalctl -b -g CSC3551. If it does not show up anything then maybe you do not have the exactly same amp. My laptop has it on i2c so I see similar things like this:

May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Error: ACPI _DSD Properties are missing for HID CSC3551.
May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: error -EINVAL: Platform not supported
May 26 15:38:06 mx3340-tbplus kernel: cs35l41-hda: probe of i2c-CSC3551:00-cs35l41-hda.0 failed with error -22

Then you'll have to dump your dsdt table following OP's guide (here). One you have it decompiled and got the dsdt.dsl, you open it and search for CSC3551. All of the things you have to patch will be inside that scope (...) block. First you copy the first _DSD block from the patch and add it directly after the empty _DIS method, so it will look something like this:

...
            Method (_DIS, 0, NotSerialized)  // _DIS: Disable Device
            {
            }

            Name (_DSD, Package ()   // _DSD: Device-Specific Data
            {
                ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package ()
                {
                    Package () { "cirrus,dev-index", Package () { 0x0040, 0x0041 }},
                    Package () { "reset-gpios", Package () {
                       SPKR, One, Zero, Zero,
                       SPKR, One, Zero, Zero,
                    } },
                    Package () { "spk-id-gpios", Package () {
                       SPKR, 0x02, Zero, Zero,
                       SPKR, 0x02, Zero, Zero,
                    } },
                    Package () { "cirrus,speaker-position",     Package () { Zero, One } },
                    // gpioX-func: 0 not used, 1 VPSK_SWITCH, 2: INTERRUPT, 3: SYNC
                    Package () { "cirrus,gpio1-func",           Package () { One, One } },
                    Package () { "cirrus,gpio2-func",           Package () { 0x02, 0x02 } },
                    // boost-type: 0 internal, 1 external
                    Package () { "cirrus,boost-type",           Package () { One, One } },
                },
            })
...

The whole scope block of my laptop could be found in my previous post. Notice that I have SPKR instead of SPK1 and Package () { "cirrus,dev-index", Package () { 0x0040, 0x0041 }} instead of {Zero, One}? These are the device specific thing you have to change here. The device name could be found in the brackets of the header of the device block, in my case it is: Device (SPKR) {... so I replace SPK1 with SPKR. Since your device is also ASUS maybe it is the same SPK1 so you don't have to change it. The second change there was the ID of the two buses. You kind find these information under the Name (BRUF, ... which is inside the Name (_UID, .... That for my device looks like:

...
            Name (_UID, One)  // _UID: Unique ID
            Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
            {
                Name (RBUF, ResourceTemplate ()
                {
                    I2cSerialBusV2 (0x0040, ControllerInitiated, 0x000F4240,
                        AddressingMode7Bit, "\\_SB.PC00.I2C7",
                        0x00, ResourceConsumer, , Exclusive,
                        )
                    I2cSerialBusV2 (0x0041, ControllerInitiated, 0x000F4240,
                        AddressingMode7Bit, "\\_SB.PC00.I2C7",
                        0x00, ResourceConsumer, , Exclusive,
                        )
...

So I replace the {Zero, One} with {0x0040, 0x0041}. According to OP, if your amps are on SPI then you also want to add the second _DSD block in the patch outside of the device (...) block but still inside the scope. Once you done that, go back to nearly the beginning of the file, change the very last parameter in the DefinitionBlock (... to a larger value to prioritize this patched table over that from the BIOS. It was 0x00 on my device, but it is probably a larger value on your device and you just have to change it to a larger number. Mine is:

DefinitionBlock ("", "DSDT", 2, "LENOVO", "CB-01   ", 0x00000009)

After that you follow the guide to recompile and package it into a .cpio file. Copy the .cpio file into /boot. If you use grub, on reboot you press "e" toward the boot option to enter the edit screen, load this cpio as an init ramdisk after the microcode and before the kernel's initrd. For example it might look like this:

...
initrd  /boot/intel-ucode.img /patched_dsdt.cpio /boot/initramfs-6.3.4.img

Run sudo journalctl -b -g CSC3551 again, if there is no error but similar output as that in my previous post, then the ACPI table patch worked. If your speakers work at this moment, then you are done (you may want to write the initrd loading command into grub's config so you won't need to type that manually on every reboot). If they are still not working, you need to patch the driver in the kernel. Look for a guide to build a mainline kernel (btw. you need Linux 6.1+ for these speakers to work). I am using Manjaro Linux and I followed the guide on ArchWiki. Once you have the full kernel source ready, go to kernel_source_root/sound/pci/hda/patch_realtek.c and search for FIXUP_CS35L41_ until you find a list of things like this:

SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
...

Add a new line in the same format for your laptop. The first two parameters can be find from the Subsystem ID. Run alsa-info to obtain it. In the output file, search for Subsystem Id and you get a 4 bytes long hex string, for example mine looks like: Subsystem Id: 0x17aa3875. Put the first four characters into the first parameter and the second for characters into the second parameter. The third parameter is just how you call your laptop, it does not matter in terms of functions and can be whatever. The last parameter could be ALC245_FIXUP_CS35L41_SPI_2 or ALC287_FIXUP_CS35L41_I2C_2 depends on whether your amps are on spi or i2c. For my device specifically, the line is like:

SND_PCI_QUIRK(0x17aa, 0x3875, "Thinkbook Plus Gen3", ALC287_FIXUP_CS35L41_I2C_2)

Then you just build the kernel and set it up for the bootloader. Don't forget to include the .cpio with your patched dsdt table as a initrd. If you are lucky enough at this point your speakers should be finally working.

thanks!

@crazyc4t
Copy link

crazyc4t commented Jun 5, 2023

Hello everyone! First of all thank you to @Moooebie @lamperez for their awesome work! I got the same problem as @Moooebie but with a thinkbook 13x gen2, I was just following your steps, so what I did is:

  1. sudo journalctl -b -g CSC3551
Jun 05 14:45:05 wizard kernel: Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 I2C devices.
Jun 05 14:45:05 wizard kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Error: ACPI _DSD Properties are missing for HID CSC3551.
Jun 05 14:45:05 wizard kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: error -EINVAL: Platform not supported
Jun 05 14:45:05 wizard kernel: cs35l41-hda: probe of i2c-CSC3551:00-cs35l41-hda.0 failed with error -22
Jun 05 14:45:05 wizard kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Error: ACPI _DSD Properties are missing for HID CSC3551.
Jun 05 14:45:05 wizard kernel: cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: error -EINVAL: Platform not supported
Jun 05 14:45:05 wizard kernel: cs35l41-hda: probe of i2c-CSC3551:00-cs35l41-hda.1 failed with error -22

By reading this for sure my speaker is in I2C.

  1. Decompile and get the dsdt.dsl, then search for CSC3551

I did it but there's no match for CSC3551, nor SPKR or SPK1, although I have SPKP, so I don't want to do something that I'm not that certain, so just wanted to ask you guys what could be the best move from here? Thank you so much for reading!

@lamperez
Copy link
Author

lamperez commented Jun 6, 2023

It seems strange, since the devices are called i2c-CSC3551:00-cs35l41-hda.0 (and 1). To my understanding, the kernel only tries to load the cs35l41-hda module if the ACPI device is called CLSA0100, CLSA0101 or CSC3551, as you can see in the source file (for SPI connected devices, only the last one).

@PoSayDone
Copy link

PoSayDone commented Jun 9, 2023

Not working for me with ux3402va

[    0.009317] ACPI: Table Upgrade: install [SSDT-CUSTOM- CSC3551]
[    0.009318] ACPI: SSDT 0x0000000036E63000 0001A0 (v01 CUSTOM CSC3551  0000000A INTL 20200925)
[    3.437382] cs35l41-hda spi1-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
[    3.478326] cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Reset line busy, assuming shared reset
[    3.511465] cs35l41-hda spi1-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
[    3.511517] Serial bus multi instantiate pseudo device driver CSC3551:00: Instantiated 2 SPI devices.

Used SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402", ALC245_FIXUP_CS35L41_SPI_2). I have a chinese version, so maybe I need to use another id? How could I find out which one I need to use?

@PoSayDone
Copy link

Installed sof-firmware package and now everything works!

@JulienQNN
Copy link

The Tables modifications and Updating to Kernel: 6.3.7-arch1-1 today made everything working thanks again for this great work @lamperez

@PoSayDone
Copy link

Maybe someone familiar with contributing to kernel could submit this patch to make ux3402va also work?
https://gist.github.com/PoSayDone/ec01ba84e5aad40f229b034f6beec5d9

@ruineka
Copy link

ruineka commented Jun 15, 2023

It looks like the Asus Ally has the same missing fields....How exactly did you know what values to use?

@tghe-retford
Copy link

Thank you for the patch and @lamperez for the explanation as to what steps to take to attempt to get this to work. I have a ASUS ROG Strix G733PZ which is also missing the DSD properties. I followed the guide, created the CPIO file and booted into Arch Linux. The kernel can now see the device. I also installed sol-firmware but I still get no sound. So it will need the laptop adding to the driver's sound PCI quirk section (at this time by compiling the kernel which I haven't got round to yet due to work commitments).

To save anyone in the future the work I did, the laptop's ID for the two buses is the same as in the guide, the speakers are referred to as SPKR and the amps are on i2c so the sound PCI quirk line should be:

SND_PCI_QUIRK(0x1043, 0x1503, "ASUS ROG Strix G733PZ", ALC287_FIXUP_CS35L41_I2C_2),

I'm not familiar with submitting patches to the kernel but hopefully this helps in the investigation to get other people's speakers working.

@ruineka
Copy link

ruineka commented Jun 18, 2023

Anyone else here have i2c and have it where you won't have sound during reboots and if you do a full power restart (hold power button) then the sound will work again? Another way to get it working is to do three reboots. I suspected it was the GPIO reset but I'm not so sure.

@Moooebie
Copy link

Anyone else here have i2c and have it where you won't have sound during reboots and if you do a full power restart (hold power button) then the sound will work again? Another way to get it working is to do three reboots. I suspected it was the GPIO reset but I'm not so sure.

I have the same issue (also i2c), but not necessarily a force power off by holding the power button, but simply using the "shutdown" option in the OS is enough. If the computer is rebooted then the sound will not work, there are some errors in journalctl log but I don't really have an idea about that...

@ruineka
Copy link

ruineka commented Jun 18, 2023

Anyone else here have i2c and have it where you won't have sound during reboots and if you do a full power restart (hold power button) then the sound will work again? Another way to get it working is to do three reboots. I suspected it was the GPIO reset but I'm not so sure.

I have the same issue (also i2c), but not necessarily a force power off by holding the power button, but simply using the "shutdown" option in the OS is enough. If the computer is rebooted then the sound will not work, there are some errors in journalctl log but I don't really have an idea about that...

What errors are you getting in your log?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment