4

I am building a PCB that will communicate via a i2c bus with a UDOO x86 running ubuntu 18.04 with two accesible i2c buses and multiple GPIO

the device has 3 i2c chips on it i2c-mux-pca954x

  • PCA9543 - level shifting bus switch
  • SC18IS602B - i2c to SPI Bus master
  • SC16IS741A - i2c to uart

each of which has a kernel driver module(i2c-mux-pca954x,spi-sc18is602,sc16is7xx)

both the SC18IS602B and SC16IS741A are connected to one channel of the PCA9543 and corresponding interrupt. the second channel for additional devices yet to be specified.

the SPI bus connects to a 4 TPS92518HV-Q1 (programmable dual current drivers) the UART connects to 8 TPS92662-Q1 (Led Matrix Controllers) (It uses a addressed form of uart that looks similar to RS-485 but im not familiar enough to be sure)

the UDOO x86 is initially just standard Ubuntu server 18.04.2 and has no device tree.

I am not very familiar with this and am not sure where to start.

I now i need to somehow specify the i2c addresses of the 3 chips and the GPIO that the interrupt from the PCA9543 is connected.

Then i think i need to produce a combined "driver" for the combination that encapsulates the individual i2c chip drivers plus the current drivers and led matrix controllers.

i believe i can in theory use acpi to do this (https://www.kernel.org/doc/Documentation/acpi/enumeration.txt)

can anyone give me a rough outline and/or examples of how to go about this

--

using a combination of

i have the following rough template

DefinitionBlock ("fbsLedCon.aml", "SSDT", 5, "", "FBLEDC01", 1)
{
    External (_SB_.PCI0.I2C0, DeviceObj) // Define Correct I2C controller 

    Scope (\_SB.PCI0.I2C0)
    {
        Device (SMB1)
        {
            Name (_HID, "FBLEDC01")
            Device (MUX0)
            {
                Name (_HID, "PCA9542A")
                Name (_DDN, "NXP PCA9542A I2C bus switch")
                Name (_CRS, ResourceTemplate () {
                        I2cSerialBus (
                                0x70,                   // I2C Address
                                ControllerInitiated, 
                                I2C_SPEED,              // Bus Speed
                                AddressingMode7Bit,     
                                "^SMB1",
                                0x00,
                                ResourceConsumer,,)
                }
                Name (_DSD, Package () {
                    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                    Package () {
                        Package () {"compatible", "nxp,pca9542"},
                    }
                })

                Device (CH00)
                {
                    Name (_ADR, 0)


                }

                Device (CH01)
                {
                    Name (_ADR, 1)

                    Device (CLI1A)
                    {
                        Name (_HID, "SC18IS602B")
                        Name (_DDN, "NXP SC18IS602B i2c to SPI Bus master")
                        Name (_CRS, ResourceTemplate () {
                            I2cSerialBus (
                                    0x50,                   //I2C Address
                                    ControllerInitiated, 
                                    I2C_SPEED,              //Bus Speed
                                    AddressingMode7Bit, 
                                    "^CH01", 
                                    0x00,
                                    ResourceConsumer,,)
                        }
                        Name (_DSD, Package () {
                            ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                            Package () {
                                Package () {"compatible", "nxp,sc18is602b"},
                            }
                        })
                    }    

                    Device (CLI1B)
                    {
                        Name (_HID, "SC16IS741A")
                        Name (_DDN, "NXP SC16IS741A  I2C to UART")
                        Name (_CRS, ResourceTemplate () {
                            I2cSerialBus (
                                    0x50,                   //I2C Address
                                    ControllerInitiated,
                                    I2C_SPEED,              //Bus Speed
                                    AddressingMode7Bit,
                                    "^CH01", 
                                    0x00,
                                    ResourceConsumer,,)
                        }
                        Name (_DSD, Package () {
                            ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                            Package () {
                                Package () {"compatible", "nxp,sc16is741"},
                            }
                        })
                    }
                }
            }
        }
    }
}

Though i don't think this is entirely correct and is missing the GPIO Interrupt from the PCA9543, and im not sure how to define the SPI and UART bus provided by the SC18IS602B and the SC16IS741A (or the TPS92518HV-Q1 and TPS92662-Q1 assuming they had drivers)

fireblade
  • 39
  • 7
  • 1
    I think you can do this with software-loaded [SSDT overlays](https://www.kernel.org/doc/Documentation/acpi/ssdt-overlays.txt), which are conceptually similar to the device tree overlays used to add support for plug-in Hats on Raspberry Pi etc. – Ian Abbott Feb 21 '19 at 17:10
  • @IanAbbott, yes they can, however the drivers and driver developers in Linux too OF-centric, so, it still requires to patch some drivers (see my answer for the details). – 0andriy Mar 03 '19 at 12:03

1 Answers1

2

Nice you choose the correct way of solving this up! Now, to the question.

First of all, let me describe the schematic of what you have how I understand it (correct me if I'm wrong).

                                         I2C
+-------------+          +------------+  bus   +-----------+
|             |          |            +-------->           |
|             |          |            <--------+ Some chip |
|             |   I2C    |            |        |           |
|    HOST     |   bus    |            |        +-----------+
|  UDOO X86   +---------->   PCA9543  |
|             <----------+     I2C    |  I2C
|             |          |    switch  |  bus   +-----------+
|             |          |            +-----+-->           |
|  GPIO IRQ   +<---------+            <--+-----+ SC16IS741A|
|             |          |            |  |  |  |           |
+-------------+          +------------+  |  |  +-----------+
                                         |  |
                                         |  |  +-----------+
                                         |  +-->           |
                                         +-----+ SC18IS602B|
                                               |           |
                                               +-----------+

It's a bit more complicated than the usual case when all devices are sitting on the same bus, but let's go with it.

Consider your ACPI excerpt the mistakes I see:

  • The identifiers in ACPI are only 4 characters long: CLI1A, CLI1B, etc are wrong names
  • The device SMB1 is not needed. What did you try to put there?
  • The _HID for the devices that are not yet have a properly allocated ACPI IDs must be PRP0001 (Note Revert "Add ACPI support for pca954x" as well)
  • The MUX chip compatible is pca9543 as you stated
  • ASL reference objects either pathes or references (in a format of <LEVEL_UP>, where <LEVEL_UP> is exact amount of '^' characters to which level you want go up followed by 4 characters object ). This is described by chapter 5.3 of the specification. Though, for I2cSerialBusV2() type of resources, the ResourceSource field is supposed to be a string with a reference
  • UPDATE Just noticed that you have two devices on the same bus with the same address, it wouldn't work, so, I fixed the address of I2C-to-Serial converted to be the same as in excerpt I below have referred to.

Now let look at it after fixing the issues.

#define I2C_SPEED 100000
DefinitionBlock ("fbsLedCon.aml", "SSDT", 5, "", "FBLEDC01", 1)
{
    External (_SB_.PCI0.I2C0, DeviceObj) // Define Correct I2C controller
    Scope (\_SB.PCI0.I2C0)
    {
            Device (MUX0)
            {
                Name (_HID, "PRP0001")
                Name (_DDN, "NXP PCA9542A I2C bus switch")
                Name (_CRS, ResourceTemplate () {
                        I2cSerialBus (
                                0x70,                   // I2C Address
                                ControllerInitiated, 
                                I2C_SPEED,              // Bus Speed
                                AddressingMode7Bit,     
                                "\\_SB.PCI0.I2C0",
                                0x00,
                                ResourceConsumer,,)
                })
                Name (_DSD, Package () {
                    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                    Package () {
                        Package () {"compatible", "nxp,pca9543"},
                    }
                })

                Device (CH00)
                {
                    Name (_ADR, 0)  
                }
    
                Device (CH01)
                {
                    Name (_ADR, 1)

                    Device (I2SM)
                    {
                        Name (_HID, "PRP0001")
                        Name (_DDN, "NXP SC18IS602B i2c to SPI Bus master")
                        Name (_CRS, ResourceTemplate () {
                            I2cSerialBus (
                                    0x50,                   // I2C Address
                                    ControllerInitiated, 
                                    I2C_SPEED,              // Bus Speed
                                    AddressingMode7Bit, 
                                    "^CH01", 
                                    0x00,
                                    ResourceConsumer,,)
                        })
                        Name (_DSD, Package () {
                            ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                            Package () {
                                Package () {"compatible", "nxp,sc18is602b"},
                            }
                        })
                    }    

                    Device (I2UM)
                    {
                        Name (_HID, "PRP0001")
                        Name (_DDN, "NXP SC16IS741A I2C to UART")
                        Name (_CRS, ResourceTemplate () {
                            I2cSerialBus (
                                    0x4d,                   // I2C Address
                                    ControllerInitiated,
                                    I2C_SPEED,              // Bus Speed
                                    AddressingMode7Bit,
                                    "^CH01", 
                                    0x00,
                                    ResourceConsumer,,)
                        })
                        Name (_DSD, Package () {
                            ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                            Package () {
                                Package () {"compatible", "nxp,sc16is741"},
                            }
                        })
                    }
                }
            }
    }
}

Disclaimer: I have never dealt with I2C muxes in my life, so, above still may contain uncertainties.

Now consider the code of individual drivers as per Elixir.

I2C mux PCA954x. The driver, unfortunately, is OF-centric and should be slightly patched to get it working in ACPI-based environments.

As an example, you may look at Make use of device properties which is now part of upstream kernel.

Similar applies to the rest of the drivers you need.

Fortunately for you, someone earlier had an interest in I2C-to-Serial convertor support, thus the patch series (not yet applied will be part of new kernel soon) had been published with a corresponding ASL excerpt.

The latter code has an example of the device with GPIO IRQ in use.

0andriy
  • 4,183
  • 1
  • 24
  • 37
  • the SMB1 device is from the i2c muxes example (https://www.kernel.org/doc/Documentation/acpi/i2c-muxes.txt) im not sure why its there, maybe to wrap the sub components into one device – fireblade Mar 03 '19 at 13:49
  • Im not sure if this has to be reflected in some way but both but the PCA9543 has interrupt inputs from the SC16IS741A and SC18IS602B – fireblade Mar 03 '19 at 14:10
  • @fireblade, The `SMB1` is a name of I2C bus controller, which in your case is defined as I2C0 on PCI0 bus. So, it's not needed. However, I'm in doubt now how to correctly put the references to MUX from the slave devices. Should it be always string? (Need to check specification). – 0andriy Mar 03 '19 at 18:37
  • @fireblade, yes, PCA9543 acts as interrupt controller. In this case you define in a slave `GpioInt()` resource and supply the reference to the MUX device. – 0andriy Mar 03 '19 at 18:39
  • Okay, I have read datasheet for PCA9543, it's just an AND logic on the inputs. Each INT signal is dedicated per switch channel. In the above scheme only one device can use it, the second one needs to be connected directly to the GPIO host controller. – 0andriy Mar 03 '19 at 19:15
  • To the naming scheme, ACPI specification chapter 5.3 defines name conventions and references to them. Chapter 19.6.57 describes ResourceSource as a string with a name. I will fix the answer. – 0andriy Mar 03 '19 at 19:17
  • Okay, In the case of IRQ connected to PCA9543 it seems in ACPI they need to be described via `Interrupt()` resource with `ResourceSource` string defined! I dunno if it's working and ever been tested in Linux. Chapter *6.4.3.6 Extended Interrupt Descriptor* tells more information. – 0andriy Mar 03 '19 at 19:29
  • One more comment to IRQ connection. It's possible to connect few devices on the same interrupt line, though in this case in ACPI and in the corresponding drivers the interrupts must be declared as shared and have same settings of course. – 0andriy Mar 03 '19 at 19:40
  • I think there is a `)` missing at the end of some of the `Name (_CRS`... blocks – mallwright Jul 08 '20 at 14:20
  • 1
    @allsey87, thanks! I have updated (and actually compile-tested) the excerpt. Moreover, I have updated the state of affairs of ACPI support in upstream kernel (it's there now!). – 0andriy Jul 10 '20 at 22:21
  • Digging through the docs, I am wondering whether an additional UUID that indicates that a hierarchy is in use is required. Specifically, I think the `_DSD` object for the mux needs to two UUIDs similar to CAM0 [in this example](https://www.kernel.org/doc/Documentation/acpi/dsd/graph.txt). – mallwright Jul 24 '20 at 13:47
  • 1
    @allsey87, I2C muxes are implemented via `_ADR` without any graph involved. So, AFAICS no need to have a hierarchy properties. – 0andriy Jul 24 '20 at 21:06
  • @0andriy I'm sure I'm breaking SO etiquette here, but could I get you to weigh in on this question? https://stackoverflow.com/questions/63490765/how-does-one-declare-devices-behind-muxes-in-acpi – mallwright Aug 19 '20 at 16:00