From 5bb5e013563ed6825aa5ca0c93e1b01db7e721cd Mon Sep 17 00:00:00 2001 From: Christian Mauderer Date: Wed, 26 May 2021 16:33:40 +0200 Subject: i2c: Add non blocking read / write This adds the possibility to open an I2C bus with O_NONBLOCK (or set it later via fcntl) to get non-blocking transmissions. This means that if the bus is busy, a read, write or transfer ioctl will return with a EAGAIN errno. --- cpukit/dev/i2c/i2c-bus.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'cpukit/dev/i2c/i2c-bus.c') diff --git a/cpukit/dev/i2c/i2c-bus.c b/cpukit/dev/i2c/i2c-bus.c index 472222c4ab..618a817b1a 100644 --- a/cpukit/dev/i2c/i2c-bus.c +++ b/cpukit/dev/i2c/i2c-bus.c @@ -31,6 +31,11 @@ #include #include +int i2c_bus_try_obtain(i2c_bus *bus) +{ + return rtems_recursive_mutex_try_lock(&bus->mutex); +} + void i2c_bus_obtain(i2c_bus *bus) { rtems_recursive_mutex_lock(&bus->mutex); @@ -41,7 +46,12 @@ void i2c_bus_release(i2c_bus *bus) rtems_recursive_mutex_unlock(&bus->mutex); } -int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count) +int i2c_bus_do_transfer( + i2c_bus *bus, + i2c_msg *msgs, + uint32_t msg_count, + uint32_t flags +) { int err; uint32_t i; @@ -63,13 +73,24 @@ int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count) } } - i2c_bus_obtain(bus); + if ((flags & I2C_BUS_NOBLOCK) != 0) { + if (i2c_bus_try_obtain(bus) != 0) { + return -EAGAIN; + } + } else { + i2c_bus_obtain(bus); + } err = (*bus->transfer)(bus, msgs, msg_count); i2c_bus_release(bus); return err; } +int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count) +{ + return i2c_bus_do_transfer(bus, msgs, msg_count, 0); +} + static ssize_t i2c_bus_read( rtems_libio_t *iop, void *buffer, @@ -84,12 +105,17 @@ static ssize_t i2c_bus_read( .buf = buffer }; int err; + unsigned flags = 0; if (bus->ten_bit_address) { msg.flags |= I2C_M_TEN; } - err = i2c_bus_transfer(bus, &msg, 1); + if (rtems_libio_iop_is_no_delay(iop)) { + flags |= I2C_BUS_NOBLOCK; + } + + err = i2c_bus_do_transfer(bus, &msg, 1, flags); if (err == 0) { return msg.len; } else { @@ -111,12 +137,17 @@ static ssize_t i2c_bus_write( .buf = RTEMS_DECONST(void *, buffer) }; int err; + unsigned flags = 0; if (bus->ten_bit_address) { msg.flags |= I2C_M_TEN; } - err = i2c_bus_transfer(bus, &msg, 1); + if (rtems_libio_iop_is_no_delay(iop)) { + flags |= I2C_BUS_NOBLOCK; + } + + err = i2c_bus_do_transfer(bus, &msg, 1, flags); if (err == 0) { return msg.len; } else { @@ -133,12 +164,16 @@ static int i2c_bus_ioctl( i2c_bus *bus = IMFS_generic_get_context_by_iop(iop); i2c_rdwr_ioctl_data *rdwr; int err; + unsigned flags = 0; switch (command) { case I2C_RDWR: rdwr = arg; if (rdwr->nmsgs > 0) { - err = i2c_bus_transfer(bus, rdwr->msgs, rdwr->nmsgs); + if (rtems_libio_iop_is_no_delay(iop)) { + flags |= I2C_BUS_NOBLOCK; + } + err = i2c_bus_do_transfer(bus, rdwr->msgs, rdwr->nmsgs, flags); } else { err = 0; } -- cgit v1.2.3