Building a i2c device controller
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
- (adding i2c client devices on x86_64)
- (https://www.kernel.org/doc/Documentation/acpi/i2c-muxes.txt)
- (https://www.kernel.org/doc/Documentation/acpi/ssdt-overlays.txt)
- (https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf)
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)
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.