Skip to content

IMX I2C driver#662

Draft
omeh-a wants to merge 4 commits into
mainfrom
i2c_imx_driver
Draft

IMX I2C driver#662
omeh-a wants to merge 4 commits into
mainfrom
i2c_imx_driver

Conversation

@omeh-a

@omeh-a omeh-a commented Mar 6, 2026

Copy link
Copy Markdown
Member

This PR adds support for the I2C core of almost IMX8M boards. This was only tested on the IMX8MQ on the Maaxboard for now however, but theoretically this should work for all other IMX8MQ and IMX8Mmini boards.

On the Maaxboard, there is an odd quirk. Using any bus other than I2C1 (PMIC bus) causes the driver to silently hang. Consulting with @midnightveil and @Ivan-Velickovic leads me to believe that this is probably due to the other I2C buses being clock gated at boot.

This PR is a draft that we are rushing for a deliverable. We need to do the following things before merging:

  • Add CI for build and test with bus scan example
  • (optional) add CI for the full I2C tester with the PN532/DS3231
  • Linting

mt-fns and others added 3 commits March 6, 2026 15:17
add returh of data handler to imx i2c

update i2c imx registers to align with data sheet memory map

update i2c imx init step to use fast-mode divider

add notes on i2c clock calculation

update i2c imx driver to send start when await start

update imx i2c address cycle handling

add transmit successful check

update boards.py to contain i2c region for imx

add read handling in state_cmd_ret for i2c imx

update i2c imx to set TXAK register when reading second to last byte
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
…r why.

Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
@omeh-a omeh-a marked this pull request as draft March 6, 2026 04:19
Comment thread drivers/i2c/imx/i2c_driver.mk Outdated
Comment on lines +16 to +21
I2C_BUS_NUM ?= 1

i2c_driver.elf: i2c/i2c_driver.o i2c/i2c_common.o
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@

i2c/i2c_driver.o: CFLAGS+=-I${I2C_DRIVER_DIR} -DI2C_BUS_NUM=${I2C_BUS_NUM}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Replaced this with DTS parsing! Will remove

${CC} ${CFLAGS} -c -o $@ $<

i2c/i2c_common.o: CFLAGS+=-I${I2C_DRIVER_DIR}
i2c/i2c_common.o: ${I2C_DRIVER_DIR}/../i2c_common.c |i2c $(SDDF_LIBC_INCLUDE)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems a bit weird with the relative paths

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other i2c drivers are identical, so I will leave this as is. If we want to change it, worth an issue to do this to all of them.

Comment thread drivers/i2c/imx/driver.h
Comment on lines +27 to +41
#define REG_CR_IEN (1 << 7) // I2C Enable
#define REG_CR_IIEN (1 << 6) // I2C Interrupt Enable
#define REG_CR_MSTA (1 << 5) // Master/Slave mode (1=Master, generates START when 0->1)
#define REG_CR_MTX (1 << 4) // Transmit/Receive (1=Transmit, 0=Receive)
#define REG_CR_TXAK (1 << 3) // Transmit Acknowledge (1=No ACK sent)
#define REG_CR_RSTA (1 << 2) // Repeat Start (1=Generate repeated START)

// I2SR Status Register bits
#define REG_SR_ICF (1 << 7) // Transfer Complete (set at 9th clock falling edge)
#define REG_SR_IAAS (1 << 6) // Addressed As Slave
#define REG_SR_IBB (1 << 5) // Bus Busy (1=Busy, set by START, cleared by STOP)
#define REG_SR_IAL (1 << 4) // Arbitration Lost
#define REG_SR_SRW (1 << 2) // Slave Read/Write (1=Slave transmit)
#define REG_SR_IIF (1 << 1) // I2C Interrupt (set when byte transfer complete)
#define REG_SR_RXAK (1 << 0) // Received Acknowledge (1=No ACK received, 0=ACK received)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably use BIT(n) macro here

Comment thread drivers/i2c/imx/i2c.c
Comment on lines +67 to +69
// busy wait for ibb to clear ...
int timeout = 10000;
while ((regs->i2sr & REG_SR_IBB) && timeout-- > 0) {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this was just done to be quick but we do generally not want to busy wait.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah correct. Theoretically this should never take longer than a few microseconds, and I personally think we ought to leave this as is until we have sdfgen able to support driver-to-driver dependencies so we can use a timer driver here nicely.

Comment thread drivers/i2c/imx/i2c.c Outdated
Comment thread drivers/i2c/imx/i2c.c
}

/**
* Send a start condition. This method should short circuit other writes to the CR register.

@midnightveil midnightveil Mar 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does "short circuit" mean here?

is this related to the fact that you do |= and &= multiple times in the body here (to registers)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Short circuit" as in will overwrite outstanding operations. I will reword this to be more clear, the tldr is that you have to make sure the ops inside start land before doing anything else

Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants