x86-64linux-device-drivergpioi2cacpi

ACPI ASL/AML: Get GPIOs and LEDs working withing linux-drivers


I have a GPIO-Expander (PCF8574) in my x86-based System which is connected to the SMBus.

To get it to work and later hopefully into the BIOS/EFI I use ACPI ASL.

Currently I'm using Ubuntu 22.04.03 LTS with HWE Kernel 6.5.0-14

I searched a lot like this or this thread and also asked chatgpt for help but yeaaaaah... that didnt work either :D

I'm currently stuck with following ASL, which almost work but as I try to load it, I receive this:

[   48.736439] ACPI: Host-directed Dynamic ACPI Table Load:
[   48.736468] ACPI: SSDT 0xFFFF8A7BCF287800 000435 (v01 VENDOR EXPANDER 00000001 INTL 20200925)
[   48.747914] pcf857x i2c-PRP0001:03: probed
[   48.748820] leds-gpio: probe of PRP0001:04 failed with error -16

The GPIOs are recognized via gpioinfo/gpiodetect, are controllable and named properly.

-16 would mean device or resource busy. It seems that the led-drivers says the resource is busy, but I thought that the leds-gpio driver will use the provided gpios not the i2c-resource. Am I wrong? Is it possible to "split" a gpio-expander like this?

My ASL:

DefinitionBlock ("expander.aml", "SSDT", 1, "VENDOR", "EXPANDER", 0x00000001)
{
    External (\_SB.PC00.SBUS, DeviceObj) 

    Scope (\_SB.PC00.SBUS)  // Scope of the I2C controller
    {
        Device (EXIO)  // GPIO expander device
        {
            Name (_HID, "PRP0001")  // Hardware ID
            Name (_DDN, "GPIO-Expander")
            Name (_UID, 3)     // Unique ID
            Name (_CID, "nxp,pcf8574")
            Name (_DSD, Package ()
            {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () { "compatible", Package() { "nxp,pcf8574" } },
                    Package () { "gpio-line-names", Package () {
                        "SATA1-Status",
                        "SATA1-Hotplug",
                        "SATA2-Status",
                        "SATA2-Hotplug",
                        }
                    },
                }
            })

            Name (_CRS, ResourceTemplate () {
                I2CSerialBusV2 (
                    0x21,                        // SlaveAddress
                    ControllerInitiated,         // SlaveMode
                    100000,                      // ConnectionSpeed
                    AddressingMode7Bit,          // AddressingMode
                    "\\_SB.PC00.SBUS",           // ResourceSource
                    0x00,                        // ResourceSourceIndex
                    ResourceConsumer,            // ResourceUsage
                    ,                            // DescriptorName
                    Exclusive                    // ShareType
                                                 // VendorData
                )
            })

            Method (_STA, 0, NotSerialized)
            {
                Return (0x0F)
            }
        }

        Device (LEDS)
        {
            Name (_HID, "PRP0001")
            Name (_DDN, "GPIO LEDs device")
            Name (_UID, 3)
            Name (_CRS, ResourceTemplate () {
                GpioIo (
                    Exclusive,                  // Not shared
                    PullNone,                   // Default off
                    0,                          // Debounce timeout
                    0,                          // Drive strength
                    IoRestrictionOutputOnly,    // Only used as output
                    "\\_SB.PC00.SBUS.EXIO",     // GPIO controller
                    0)                          // Must be 0
                {
                    4,  // LED1
                    5,  // LED2
                    6,  // LED3
                    7,  // LED4                        
                }
            })
            
            Name (_DSD, Package () {
                ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
                Package () {
                    Package () { "led-4", "LED0" },
                    Package () { "led-5", "LED1" },
                    Package () { "led-6", "LED2" },
                    Package () { "led-7", "LED3" },
                },
                
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () { "compatible", Package() { "gpio-leds" } },
                },
            })
            
            Name (LED0, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () { "label", "led-4" },
                    Package () { "led-max-microamp", 10000 },
                    Package () { "default-state", "off"},
                    Package () { "gpios", Package () {^LEDS, 0, 0, 1}},
                }
            })
            
            Name (LED1, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () { "label", "led-5" },
                    Package () { "led-max-microamp", 10000 },
                    Package () { "default-state", "off"},
                    Package () { "gpios", Package () {^LEDS, 0, 1, 1}},
                }
            })
            
            Name (LED2, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () { "label", "led-6" },
                    Package () { "led-max-microamp", 10000 },
                    Package () { "default-state", "off"},
                    Package () { "gpios", Package () {^LEDS, 0, 2, 1}},
                }
            })
            
            Name (LED3, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () { "label", "led-7" },
                    Package () { "led-max-microamp", 10000 },
                    Package () { "default-state", "off"},
                    Package () { "gpios", Package () {^LEDS, 0, 3, 1}},
                }
            })
        }
    }
}

EDIT: I changed the LED pin within their property to the corresponding index number, the problem is solved Big thanks to 0andriy who pointed this out.


Solution

  • Thanks to 0andriy who pointed out the problems:

    1. I assigned all LEDs to the same index/pin.
    2. I assigned the LEDs to their "Hardware-Pin" and not the index of the GpioIo-Property

    After changing the LEDs to their corresponding Indexes, it worked. :)

    Name (LED0, Package () {
        [...]
        Package () { "gpios", Package () {^LEDS, 0, 0, 1}},
        [...]
    })
    Name (LED1, Package () {
        [...]
        Package () { "gpios", Package () {^LEDS, 0, 1, 1}},
        [...]
    })
    Name (LED2, Package () {
        [...]
        Package () { "gpios", Package () {^LEDS, 0, 2, 1}},
        [...]
    })
    Name (LED3, Package () {
        [...]
        Package () { "gpios", Package () {^LEDS, 0, 3, 1}},
        [...]
    })
    

    In hindsight it totally made sense that the device is responsing with busy, due to the fact that I assigned four LEDs to the same GPIO...