Maxim MAX14830 in Linux x86 / ACPI

636 views Asked by At

I am receiving a fatal error when attempting to load the Maxim MAX14830 SPI-to-QuadUART chip in a CentOS8 (x86_64) environment. The SPI controller in use is the Intel E3900 Atom, from which I am able to successfully mount and interact with using SPIDEV.

After reviewing several examples from the ARM world, I believe the issue lies in that I am not passing the "clocks" parameter to the max310x driver, but I have been unable to find a suitable example for describing a "phandle to the IC source clock" in ACPI.

The chip's clock input (Pin 45, XIN) is driven by a standard clock oscillator running at 7.3728 MHz.

DefinitionBlock ("e3900-spi.aml", "SSDT", 5, "INTEL", "SPIDEV", 1)
{
    External (_SB_.PCI0.SPI1, DeviceObj)

    Scope (\_SB.PCI0.SPI1)
    {
        Device (MAX1) {
            Name (_HID, "PRP0001")
            Name (_DDN, "Maxim MAX14380 Quad UART")
            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
                    1000000,                // 1 MHz
                    ClockPolarityLow,       // SPI mode 0
                    ClockPhaseFirst,        // SPI mode 0
                    "\\_SB.PCI0.SPI1",      // SPI host controller
                    0,                      // Must be 0
                    ResourceConsumer        // Slave device
                )
            })

            Name (_DSD, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () {"compatible", "maxim,max14830"},
                    Package () {"clock-names", "osc"},
                    Package () {"clock-frequency", 7372800},
                    Package () {"reg", 0},
                }
            })
        }

        Device (TP11) {
            Name (_HID, "SPT0001")
            Name (_DDN, "E3900-SPI1-CS1")
            Name (_CRS, ResourceTemplate () {
                SpiSerialBus (
                    1,                      // Chip select
                    PolarityLow,            // Chip select is active low
                    FourWireMode,           // Full duplex
                    8,                      // Bits per word is 8 (byte)
                    ControllerInitiated,    // Don't care
                    1000000,                // 1 MHz
                    ClockPolarityLow,       // SPI mode 0
                    ClockPhaseFirst,        // SPI mode 0
                    "\\_SB.PCI0.SPI1",      // SPI host controller
                    0                       // Must be 0
                )
            })
        }
    }
}

The relevant output from dmesg is:

[    1.974203] max310x spi-PRP0001:03: Cannot get clock
[    1.975951] max310x: probe of spi-PRP0001:03 failed with error -22

The datasheet for the part can be found here: https://datasheets.maximintegrated.com/en/ds/MAX14830.pdf

Any guidance or relevant example link would be appreciated. Thanks!

EDIT: I found an example for how to reference another object at https://www.kernel.org/doc/html/latest/firmware-guide/acpi/dsd/leds.html; the following AML complied correctly, but resulted in a kernel panic. This discussion (https://lore.kernel.org/lkml/[email protected]/T/) leads me to believe that use of the common clock framework is not supported in ACPI, so any drivers that make use of it cannot be used with a ACPI + _DSD configuration.

DefinitionBlock ("e3900-spi.aml", "SSDT", 5, "INTEL", "SPIDEV", 1)
{
    External (_SB_.PCI0.SPI1, DeviceObj)

    Scope (\_SB.PCI0.SPI1)
    {

        Device (CLK1) {
            Name (_HID, "PRP0001")
            Name (_DDN, "Maxim Clock Object")
            Name (_DSD, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () {"compatible", "fixed-clock"},
                    Package () {"clock-cells", 0},
                    Package () {"clock-frequency", 7372800},
                }
            })
        }

        Device (MAX1) {
            Name (_HID, "PRP0001")
            Name (_DDN, "Maxim MAX14380 Quad UART")
            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
                    100000,                 // 100 kHz
                    ClockPolarityLow,       // SPI mode 0
                    ClockPhaseFirst,        // SPI mode 0
                    "\\_SB.PCI0.SPI1",      // SPI host controller
                    0,                      // Must be 0
                    ResourceConsumer        // Slave device
                )
            })

            Name (_DSD, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () {"compatible", "maxim,max14830"},
                    Package () {"clock-names", "osc"},
                    Package () {"clocks", ^CLK1},
                    Package () {"reg", 0},
                }
            })
        }

        Device (TP11) {
            Name (_HID, "SPT0001")
            Name (_DDN, "E3900-SPI1-CS1")
            Name (_CRS, ResourceTemplate () {
                SpiSerialBus (
                    1,                      // Chip select
                    PolarityLow,            // Chip select is active low
                    FourWireMode,           // Full duplex
                    8,                      // Bits per word is 8 (byte)
                    ControllerInitiated,    // Don't care
                    1000000,                // 1 MHz
                    ClockPolarityLow,       // SPI mode 0
                    ClockPhaseFirst,        // SPI mode 0
                    "\\_SB.PCI0.SPI1",      // SPI host controller
                    0                       // Must be 0
                )
            })
        }
    }
}
1

There are 1 answers

2
drkwood On

With the driver updates provided by 0andriy (https://lore.kernel.org/linux-serial/[email protected]/T/#u), I was able to get the /dev/ttyMAX devices to appear, although I needed to perform further modifications to force oscillator clocking; the driver was still dropping to the "Cannot get clock" error.

I modeled my AML after this example (https://github.com/westeri/meta-acpi/blob/master/recipes-bsp/acpi-tables/samples/edison/sc16is7xx.asl), which resulted in the following:

DefinitionBlock ("e3900-spi.aml", "SSDT", 5, "INTEL", "SPI", 1)
{
    External (_SB_.PCI0.XHC_.RHUB.HS06.GPIO, DeviceObj)
    External (_SB_.PCI0.SPI1, DeviceObj)

    Scope (\_SB.PCI0.SPI1)
    {
        Device (MAX1) {
            Name (_HID, "PRP0001")
            Name (_DDN, "Maxim MAX14380 Quad UART")
            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
                    1000000,                // 1 MHz
                    ClockPolarityLow,       // SPI mode 0
                    ClockPhaseFirst,        // SPI mode 0
                    "\\_SB.PCI0.SPI1",      // SPI host controller
                    0,                      // Must be 0
                    ResourceConsumer        // Slave device
                )

                GpioInt (Level, ActiveLow, Exclusive, PullDefault, 0x0000,
                "\\_SB.PCI0.XHC.RHUB.HS06.GPIO", 0x00, ResourceConsumer, , ) { 18 }
            })

            Name (_DSD, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () {"compatible", "maxim,max14830"},
                    Package () {"clock-frequency", 7372800},
                }
            })
        }
    }
}

However, the driver was still failing in the devm_request_threaded_irq function:

[   15.951778] max310x spi-PRP0001:00: MAX14830 ID: 0xb4
[   15.965699] max310x spi-PRP0001:00: Reference clock set to 7372800 Hz
[   15.968883] spi-PRP0001:00: ttyMAX0 at I/O 0x0 (irq = -517, base_baud = 460800) is a MAX14830
[   15.972907] spi-PRP0001:00: ttyMAX1 at I/O 0x20 (irq = -517, base_baud = 460800) is a MAX14830
[   15.985941] spi-PRP0001:00: ttyMAX2 at I/O 0x40 (irq = -517, base_baud = 460800) is a MAX14830
[   15.990046] spi-PRP0001:00: ttyMAX3 at I/O 0x60 (irq = -517, base_baud = 460800) is a MAX14830
[   16.009260] max310x spi-PRP0001:00: Unable to reguest IRQ -517
[   16.021810] max310x: probe of spi-PRP0001:00 failed with error -22

Being a novice at C code, I wasn't able to find a way to correct the issue and ended up just commenting it out so that the mounts were not automatically torn down.

At this point, I am able to successfully query them with the setserial utility and access the devices with minicom.

[root@hwtest ~]# setserial -g /dev/ttyMAX*
/dev/ttyMAX0, UART: undefined, Port: 0x0000, IRQ: -517, Flags: low_latency
/dev/ttyMAX1, UART: undefined, Port: 0x0020, IRQ: -517, Flags: low_latency
/dev/ttyMAX2, UART: undefined, Port: 0x0040, IRQ: -517, Flags: low_latency
/dev/ttyMAX3, UART: undefined, Port: 0x0060, IRQ: -517, Flags: low_latency

I am handing the PCB back to the EE to verify the serial ports are actually working (it does not have easy test points exposed), and I will update this answer if it doesn't.

EDIT: We are able to send data while configured in this manner, but the receive path is not working, likely due to the IRQ issue. I will retest with a 5.11 kernel and report back. The current status is with LTS kernel version 5.4.70, with manual patching of the max310x driver.