diff options
Diffstat (limited to 'cpukit/dev/i2c/fpga-i2c-slave.c')
-rw-r--r-- | cpukit/dev/i2c/fpga-i2c-slave.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/cpukit/dev/i2c/fpga-i2c-slave.c b/cpukit/dev/i2c/fpga-i2c-slave.c new file mode 100644 index 0000000000..cf00a57b41 --- /dev/null +++ b/cpukit/dev/i2c/fpga-i2c-slave.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org> + * All rights reserved. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +/* + * I2C slave for testing: + * https://github.com/oetr/FPGA-I2C-Slave + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include <dev/i2c/i2c.h> +#include <dev/i2c/fpga-i2c-slave.h> + +typedef struct { + i2c_dev base; + uint16_t address; + size_t size; +} fpga_i2c_slave; + +static ssize_t +fpga_i2c_slave_read(i2c_dev* base, void* buf, size_t n, off_t offset) +{ + fpga_i2c_slave* dev = (fpga_i2c_slave*) base; + off_t avail = dev->size - offset; + uint8_t* in = buf; + size_t todo; + + if (avail <= 0) { + return 0; + } + + if (n > avail) { + n = (size_t) avail; + } + + todo = n; + + while (todo > 0) { + /* + * Limit the transfer size so that it can be stored in 8-bits. This may + * help some bus controllers. + */ + uint16_t cur = (uint16_t) (todo < 255 ? todo : 255); + i2c_msg msgs = { + .addr = dev->base.address, + .flags = I2C_M_RD, + .buf = in, + .len = cur + }; + int err; + err = i2c_bus_transfer(dev->base.bus, &msgs, 1); + if (err != 0) { + return err; + } + todo -= cur; + in += cur; + } + + return (ssize_t) n; +} + +static ssize_t +fpga_i2c_slave_write(i2c_dev* base, const void* buf, size_t n, off_t offset) +{ + fpga_i2c_slave* dev = (fpga_i2c_slave*) base; + off_t avail = dev->size - offset; + const uint8_t* out = buf; + size_t todo; + + if (avail <= 0) { + return 0; + } + + if (n > avail) { + n = (size_t) avail; + } + + todo = n; + + while (todo > 0) { + /* + * Limit the transfer size so that it can be stored in 8-bits. This may + * help some bus controllers. + */ + uint16_t cur = (uint16_t) (todo < 255 ? todo : 255); + i2c_msg msgs = { + .addr = dev->base.address, + .flags = 0, + .buf = RTEMS_DECONST(uint8_t*, out), + .len = cur + }; + int err; + err = i2c_bus_transfer(dev->base.bus, &msgs, 1); + if (err != 0) { + return err; + } + todo -= cur; + out += cur; + } + + return (ssize_t) n; +} + +int +i2c_dev_register_fpga_i2c_slave(const char* bus_path, + const char* dev_path, + uint16_t address, + size_t size) + +{ + fpga_i2c_slave* dev; + + dev = (fpga_i2c_slave*) + i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address); + if (dev == NULL) { + return -1; + } + + dev->base.read = fpga_i2c_slave_read; + dev->base.write = fpga_i2c_slave_write; + dev->size = size; + + return i2c_dev_register(&dev->base, dev_path); +} |