Search code examples
x86-64linux-device-drivergpiospiacpi

ACPI: sc16is741 UART on DLN-2 compatible USB to SPI/GPIO adapter on Linux


I have a ACPI problem on Linux 6.12.6 (Debian). I have a Pico USB I/O Board (USB to SPI and GPIO adapter) used with the DLN-2 driver that is initialized thru a (for my laptop adapted) ACPI SSDT file found on meta-acpi edison.

On this DLN-2 compatible adapter i have connected a NXP sc16is741 UART with the interrupt(active low) connected to gpio14 and the reset(active low) to gpio15 of the adapter.

The uart is not getting an irq assigned. It is 0.

My improved DLN-2 SSDT file:

/*
 * Intel Edison
 *
 * This adds Diolan DLN-2 USB interface adapter to the high speed port
 * available on Intel Edison header.
 *
 * In Linux you need to set CONFIG_MFD_DLN2=y (or m) and at least
 * one of the CONFIG_GPIO_DLN2=y (or m), CONFIG_I2C_DLN2=y (or m),
 * and CONFIG_SPI_DLN2=y (or m) to be able to use this device.
 *
 * Additionally you may enable ADC with CONFIG_DLN2_ADC=y (or m).
 */
DefinitionBlock ("dln2.aml", "SSDT", 5, "", "DLN2", 1)
{
    External (\_SB.PCI0.EHCI.RHUB.PRT1.PRT3, DeviceObj)
    External (\_SB.PCI0.EHCI.RHUB.GPLD, MethodObj)

    /*
     * We set the port to hard wired state to get the connected device
     * enumerated properly. See more details here:
     * https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/other-acpi-namespace-objects#acpi-namespace-hierarchy-and-_adr-for-embedded-usb-devices
     */

    Scope (\_SB_.PCI0.EHCI.RHUB.PRT1.PRT3)
    {
        Name (_UPC, Package ()
        {
            0xFF,
            0xFF,
            Zero,
            Zero,
        })

        Method (_PLD, 0, NotSerialized)
        {
                Return (GPLD (Zero))
        }

        Device (GPIO)
        {
            Name (_ADR, Zero)
            Name (_STA, 0x0F)
            Name (_DSD, Package ()
            {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package ()
                {
                    Package () {
                        "gpio-line-names",
                        Package () {
                            "", // 0
                            "", // 1
                            "", // 2
                            "", // 3
                            "", // 4
                            "", // 5
                            "", // 6
                            "", // 7
                            "", // 8
                            "", // 9
                            "", // 10
                            "", // 11
                            "", // 12
                            "", // 13
                            "irq", // 14
                            "reset", // 15
                            "",
                            "",
                        }
                    }
                }
            })
        }

        Device (I2C0)
        {
            Name (_ADR, One)
            Name (_STA, 0x0F)
        }

        Device (SPI0)
        {
            Name (_ADR, 0x02)
            Name (_STA, 0x0F)
        }
    }
}

My improved sc16is741 SSDT file:

DefinitionBlock ("sc16is741.aml", "SSDT", 5, "NXP", "UART", 1)
{
    External (_SB.PCI0.EHCI.RHUB.PRT1.PRT3.SPI0, DeviceObj)
    External (_SB.PCI0.EHCI.RHUB.PRT1.PRT3.GPIO, DeviceObj)

    Scope (\_SB.PCI0.EHCI.RHUB.PRT1.PRT3.SPI0)
    {
        Device (SER)
        {
            Name (_HID, "PRP0001")
            Name (_DDN, "SC16IS741 SPI-SERIAL")
            Name (_CRS, ResourceTemplate ()
            {
                SpiSerialBus (
                    0,                      // Chip select
                    PolarityLow,            // Chip select is active low
                    FourWireMode,           // Full duplex
                    8,                      // Bits per word is 8 (byte)
                    ControllerInitiated,    // slave mode
                    4000000,                // 4 MHz
                    ClockPolarityLow,       // SPI mode 0
                    ClockPhaseFirst,        // SPI mode 0
                    "\\_SB.PCI0.EHCI.RHUB.PRT1.PRT3.SPI0",      // SPI host controller
                    0                       // Must be 0
                )

                // Interrupt for the device
                GpioInt(Level, ActiveLow, ExclusiveAndWake, PullUp, 0x0000,
                    "\\_SB.PCI0.EHCI.RHUB.PRT1.PRT3.GPIO", 0x00, ResourceConsumer, , ) { 14 } // SC16IS741 irq
                GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly,
                    "\\_SB.PCI0.EHCI.RHUB.PRT1.PRT3.GPIO", 0, ResourceConsumer, , ) { 15 } // SC16IS741 reset
            })

            Name (_DSD, Package ()
            {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package ()
                {
                    Package () {"compatible", Package () {"nxp,sc16is741"}},
                    Package () {"clock-frequency", 1843200},
                    Package () {"reset-gpios", Package () {^SER, 1, 0, 1 }}, // active low
                }
            })

            Name (_DEP, Package ()
            {
                \_SB.PCI0.EHCI.RHUB.PRT1.PRT3.SPI0,
                \_SB.PCI0.EHCI.RHUB.PRT1.PRT3.GPIO,
            })
        }
    }
}

My dmesg result now:

[  393.336758] usb 2-1.3: new full-speed USB device number 6 using ehci-pci
[  393.435123] usb 2-1.3: New USB device found, idVendor=1d50, idProduct=6170, bcdDevice= 0.12
[  393.435150] usb 2-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  393.435159] usb 2-1.3: Product: Pico USB I/O Board
[  393.435166] usb 2-1.3: Manufacturer: Raspberry Pi
[  393.435171] usb 2-1.3: SerialNumber: 50335927325C489F
[  393.437274] dln2 2-1.3:1.0: Diolan DLN2 serial 844908703
[  393.437797] gpiochip_find_base_unlocked: found new base at 512
[  393.438158] gpio gpiochip0: (dln2): added GPIO chardev (254:0)
[  393.438251] gpio gpiochip0: registered GPIOs 512 to 540 on dln2
[  393.438898] dln2-spi dln2-spi.4.auto: cs_num = 1
[  393.439278] dln2-spi dln2-spi.4.auto: freq_min = 1922, freq_max = 62500000
[  393.439523] dln2-spi dln2-spi.4.auto: bpw_mask = 0xFFF8
[  393.440312] dln2-spi dln2-spi.4.auto: registered host spi0
[  393.444992] spi spi-PRP0001:00: setup mode 0, 8 bits/w, 4000000 Hz max --> 0
[  393.445200] dln2-spi dln2-spi.4.auto: registered child spi-PRP0001:00
[  393.451432] cdc_acm 2-1.3:1.1: ttyACM0: USB ACM device
[  393.452090] cdc_acm 2-1.3:1.3: ttyACM1: USB ACM device
[  420.714632] acpi PRP0001:00: GPIO: looking up gpios
[  420.714639] acpi PRP0001:00: GPIO: looking up gpio
[  420.714641] acpi PRP0001:00: GPIO: looking up 0 in _CRS
[  420.714692] gpio gpiochip0: Persistence not supported for GPIO 14
[  420.714882] sc16is7xx spi-PRP0001:00: setup mode 0, 8 bits/w, 4000000 Hz max --> 0
[  420.716394] sc16is7xx spi-PRP0001:00: using ACPI '\_SB.PCI0.EHCI.RHUB.PRT1.PRT3.SPI0.SER' for 'reset' GPIO lookup
[  420.716403] acpi PRP0001:00: GPIO: looking up reset-gpios
[  420.716406] acpi PRP0001:00: GPIO: _DSD returned PRP0001:00 1 0 1
[  420.716418] acpi PRP0001:00: Override GPIO initialization flags
[  420.716716] gpio gpiochip0: Persistence not supported for GPIO 15
[  420.717208] sc16is7xx spi-PRP0001:00: using ACPI '\_SB.PCI0.EHCI.RHUB.PRT1.PRT3.SPI0.SER' for 'rs485-term' GPIO lookup
[  420.717218] acpi PRP0001:00: GPIO: looking up rs485-term-gpios
[  420.717220] acpi PRP0001:00: GPIO: looking up rs485-term-gpio
[  420.717222] sc16is7xx spi-PRP0001:00: using lookup tables for GPIO lookup
[  420.717223] sc16is7xx spi-PRP0001:00: No GPIO consumer rs485-term found
[  420.717225] sc16is7xx spi-PRP0001:00: using ACPI '\_SB.PCI0.EHCI.RHUB.PRT1.PRT3.SPI0.SER' for 'rs485-rx-during-tx' GPIO lookup
[  420.717230] acpi PRP0001:00: GPIO: looking up rs485-rx-during-tx-gpios
[  420.717231] acpi PRP0001:00: GPIO: looking up rs485-rx-during-tx-gpio
[  420.717232] sc16is7xx spi-PRP0001:00: using lookup tables for GPIO lookup
[  420.717234] sc16is7xx spi-PRP0001:00: No GPIO consumer rs485-rx-during-tx found
[  420.717675] spi-PRP0001:00: ttySC0 at I/O 0x0 (irq = 0, base_baud = 115200) is a SC16IS74X
[  420.720999] genirq: Flags mismatch irq 0. 00002088 (spi-PRP0001:00) vs. 00215a00 (timer)
[  420.721055] genirq: Flags mismatch irq 0. 00002002 (spi-PRP0001:00) vs. 00215a00 (timer)
[  420.721429] sc16is7xx spi-PRP0001:00: probe with driver sc16is7xx failed with error -16

gpioinfo now:

    line  14:   "irq"               input active-low bias=pull-up
    line  15:   "reset"             output

PS.: I have also tried to replace the sc16is741 with a switch on GPIO14 and use the gpio-keys driver with a button SSDT. Then i get a IRQ and it works OK.


Solution

  • So far I have noticed a few issues with your ASL code, let me list them below (in order from most important to less important one):

    1. In one case you have GPIO, and in the other GPI0 (See the difference? It's 0 (zero) instead of O (CAPITAL O), that's most likely the issue with the reset GPIO.

    2. Remove gpios from _DSD, the GpioInt() resource doesn't need an additional information in _DSD. Interrupt is requested by index, see https://elixir.bootlin.com/linux/v6.12.6/source/drivers/spi/spi.c#L430.

    3. Use PullUp for GpioInt() as we don't have _DSD for it and most likely you don't want it to float in case of missing pull-up on the PCB or bad connection (sh*t happens sometimes :).

    4. The gpio-line-names property is the property of the GPIO controller, you put it wrongly into consumer. It needs to be present under \_SB.PCI0.EHCI.RHUB.PRT1.PRT3.GPIO device object. I.o.w. you need to add _DSD method there as you done in serial device and move this only property to there. See meta-acpi project examples for that, e.g., https://github.com/westeri/meta-acpi/blob/master/recipes-bsp/acpi-tables/samples/edison/arduino.asli#L374.

    5. I would add _DEP method to the serial device object (SER) and list SPI0 and GPIO host controllers as dependencies. I don't remember if we do anything special about the probing order, but it might affect it inside ACPI glue layer in the Linux kernel. See meta-acpi project examples for that, e.g., https://github.com/westeri/meta-acpi/blob/master/recipes-bsp/acpi-tables/samples/edison/gpioexp-dep.asli. UPDATE You mentioned in the comment that you added a sc16is741-dep.asli. No need to have a separate file, just add _DEP method and its contents directly to the original device object (SER) description.