summaryrefslogtreecommitdiffstats
path: root/cpukit/dev/i2c/fpga-i2c-slave.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/dev/i2c/fpga-i2c-slave.c')
-rw-r--r--cpukit/dev/i2c/fpga-i2c-slave.c132
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);
+}