bsp/arch64/raspberrypi: Add I2C TX interrupt support

Adds the interrupt support for TX in the I2C driver
This commit is contained in:
Shaunak Datar
2025-08-18 19:35:13 +05:30
committed by Kinsey Moore
parent 94251a25fb
commit 02de8a383d
4 changed files with 110 additions and 52 deletions

View File

@@ -65,6 +65,7 @@
typedef struct {
i2c_bus base;
rtems_binary_semaphore sem;
uint32_t input_clock;
uintptr_t base_address;
raspberrypi_bsc_masters device;
@@ -75,65 +76,54 @@ typedef struct {
bool read_transfer;
} raspberrypi_i2c_bus;
static int i2c_polling_read( raspberrypi_i2c_bus *bus )
static int rpi_i2c_bus_transfer( raspberrypi_i2c_bus *bus )
{
while ( !( S_REG( bus ) & S_DONE ) && ( bus->remaining_bytes > 0 ) ) {
while ( ( S_REG( bus ) & S_RXD ) && ( bus->remaining_bytes > 0 ) ) {
while ( bus->remaining_bytes > 0 ) {
if ( bus->read_transfer ) {
while ( ( S_REG( bus ) & ( S_RXD | S_CLKT ) ) == 0 ) {
}
if ( S_REG( bus ) & S_CLKT ) {
return -EIO;
}
*bus->current_buffer = BCM2835_REG(
bus->base_address + BCM2711_I2C_FIFO
) &
BCM2711_I2C_FIFO_MASK;
bus->current_buffer++;
bus->remaining_bytes--;
/* Check for errors */
if ( S_REG( bus ) & ( S_CLKT | S_ERR ) ) {
++bus->current_buffer;
if ( ( S_REG( bus ) & S_ERR ) || ( S_REG( bus ) & S_CLKT ) ) {
return -EIO;
}
} else {
#ifdef BSP_I2C_USE_INTERRUPTS
C_REG( bus ) |= C_INTT;
if ( rtems_binary_semaphore_wait_timed_ticks(
&bus->sem,
bus->base.timeout
) != RTEMS_SUCCESSFUL ) {
rtems_binary_semaphore_try_wait( &bus->sem );
return -ETIMEDOUT;
}
#else
while ( ( S_REG( bus ) & ( S_TXW | S_CLKT ) ) == 0 ) {
}
if ( S_REG( bus ) & S_CLKT ) {
return -EIO;
}
#endif
BCM2835_REG(
bus->base_address + BCM2711_I2C_FIFO
) = *bus->current_buffer;
++bus->current_buffer;
if ( ( S_REG( bus ) & S_ERR ) || ( S_REG( bus ) & S_CLKT ) ) {
return -EIO;
}
}
}
return 0;
}
static int i2c_polling_write( raspberrypi_i2c_bus *bus )
{
while ( !( S_REG( bus ) & S_DONE ) && ( bus->remaining_bytes > 0 ) ) {
while ( bus->remaining_bytes > 0 && ( S_REG( bus ) & S_TXD ) ) {
BCM2835_REG( bus->base_address + BCM2711_I2C_FIFO ) = *(
bus->current_buffer
);
bus->current_buffer++;
bus->remaining_bytes--;
/* Check for errors */
if ( S_REG( bus ) & ( S_CLKT | S_ERR ) ) {
return -EIO;
}
}
}
return 0;
}
static int rpi_i2c_bus_transfer( raspberrypi_i2c_bus *bus )
{
int rv;
if ( bus->read_transfer ) {
rv = i2c_polling_read( bus );
if ( rv < 0 ) {
return rv;
}
} else {
rv = i2c_polling_write( bus );
if ( rv < 0 ) {
return rv;
}
}
if ( ( S_REG( bus ) & S_ERR ) || ( S_REG( bus ) & S_CLKT ) ||
( bus->remaining_bytes != 0 ) ) {
return -EIO;
--bus->remaining_bytes;
}
S_REG( bus ) = S_DONE;
return 0;
}
@@ -172,9 +162,10 @@ static int rpi_i2c_setup_and_transfer( raspberrypi_i2c_bus *bus )
BCM2711_I2C_DLEN_MASK :
( bus->current_buffer_size & BCM2711_I2C_DLEN_MASK
);
BCM2835_REG( bus->base_address + BCM2711_I2C_DLEN ) = bus->remaining_bytes;
BCM2835_REG( bus->base_address + BCM2711_I2C_DLEN ) = bus->remaining_bytes;
/* Clear the error bits before starting new transfer */
S_REG( bus ) = S_ERROR;
S_REG( bus ) = S_ERROR;
C_REG( bus ) |= C_ST;
rv = rpi_i2c_bus_transfer( bus );
@@ -182,11 +173,41 @@ static int rpi_i2c_setup_and_transfer( raspberrypi_i2c_bus *bus )
return rv;
}
#ifdef BSP_I2C_USE_INTERRUPTS
C_REG( bus ) |= C_INTD;
if ( rtems_binary_semaphore_wait_timed_ticks(
&bus->sem,
bus->base.timeout
) != 0 ) {
rtems_binary_semaphore_try_wait( &bus->sem );
return -ETIMEDOUT;
}
#else
while ( ( S_REG( bus ) & ( S_DONE | S_CLKT ) ) == 0 ) {
}
if ( S_REG( bus ) & S_CLKT ) {
return -EIO;
}
#endif
--bus->remaining_transfers;
}
return 0;
}
#ifdef BSP_I2C_USE_INTERRUPTS
static void i2c_handler( void *args )
{
raspberrypi_i2c_bus *bus = (raspberrypi_i2c_bus *) args;
if ( C_REG( bus ) & C_INTT ) {
C_REG( bus ) &= ~C_INTT;
} else if ( C_REG( bus ) & C_INTD ) {
C_REG( bus ) &= ~C_INTD;
}
rtems_binary_semaphore_post( &bus->sem );
}
#endif
static int rpi_i2c_transfer( i2c_bus *base, i2c_msg *msgs, uint32_t msg_count )
{
raspberrypi_i2c_bus *bus = (raspberrypi_i2c_bus *) base;
@@ -231,10 +252,11 @@ static int rpi_i2c_transfer( i2c_bus *base, i2c_msg *msgs, uint32_t msg_count )
}
if ( msgs[ i ].flags & I2C_M_RD ) {
C_REG( bus ) |= C_CLEAR | C_READ | C_ST; // Read packet transfer
C_REG( bus ) |= C_CLEAR | C_READ;
bus->read_transfer = true;
} else {
C_REG( bus ) |= C_CLEAR | C_ST; // Write packet transfer
C_REG( bus ) |= C_CLEAR;
C_REG( bus ) &= ~C_READ;
bus->read_transfer = false;
}
/* Disable clock stretch timeout */
@@ -346,6 +368,20 @@ rtems_status_code rpi_i2c_init(
C_REG( bus ) = C_CLEAR;
C_REG( bus ) = C_I2CEN;
#ifdef BSP_I2C_USE_INTERRUPTS
sc = rtems_interrupt_handler_install(
BCM2711_IRQ_I2C,
"I2C",
RTEMS_INTERRUPT_SHARED,
(rtems_interrupt_handler) i2c_handler,
bus
);
rtems_binary_semaphore_init( &bus->sem, "RPII2C" );
if ( sc != RTEMS_SUCCESSFUL ) {
return -EIO;
}
#endif
sc = rpi_i2c_set_clock( &bus->base, bus_clock );
if ( sc != RTEMS_SUCCESSFUL ) {
i2c_bus_destroy_and_free( &bus->base );

View File

@@ -71,6 +71,9 @@ extern "C" {
/* Interrupt Vectors: SPI */
#define BCM2711_IRQ_SPI (BCM2711_IRQ_VC_PERIPHERAL_BASE + 54)
/* Interrupt Vectors: I2C */
#define BCM2711_IRQ_I2C ( BCM2711_IRQ_VC_PERIPHERAL_BASE + 53 )
/* Interrupt Vectors: Videocore */
#define BCM2711_IRQ_VC_PERIPHERAL_BASE 96
#define BCM2711_IRQ_AUX (BCM2711_IRQ_VC_PERIPHERAL_BASE + 29)

View File

@@ -23,6 +23,8 @@ links:
uid: optcorerate
- role: build-dependency
uid: optspiirq
- role: build-dependency
uid: opti2cirq
- role: build-dependency
uid: objclock
- role: build-dependency

View File

@@ -0,0 +1,17 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-boolean: null
- define-condition: null
build-type: option
copyrights:
- Copyright (C) 2025 Shaunak Datar
default:
- enabled-by: true
value: true
description: |
Use interrupt mode in the I2C driver.
enabled-by: true
format: '{}'
links: []
name: BSP_I2C_USE_INTERRUPTS
type: build