summaryrefslogtreecommitdiffstats
path: root/cpukit/dev/serial/sc16is752-spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/dev/serial/sc16is752-spi.c')
-rw-r--r--cpukit/dev/serial/sc16is752-spi.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/cpukit/dev/serial/sc16is752-spi.c b/cpukit/dev/serial/sc16is752-spi.c
new file mode 100644
index 0000000000..f51a3638a1
--- /dev/null
+++ b/cpukit/dev/serial/sc16is752-spi.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <info@embedded-brains.de>
+ *
+ * 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.
+ */
+
+#include <dev/serial/sc16is752.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <dev/spi/spi.h>
+
+#include "sc16is752-regs.h"
+
+static void msg_init(
+ struct spi_ioc_transfer *msg,
+ uint8_t cs,
+ uint32_t speed,
+ size_t len,
+ uint8_t *rx_buf,
+ const uint8_t *tx_buf
+)
+{
+ msg->rx_buf = rx_buf;
+ msg->tx_buf = tx_buf;
+ msg->len = len;
+ msg->speed_hz = speed;
+ msg->delay_usecs = 1;
+ msg->bits_per_word = 8;
+ msg->cs_change = 0;
+ msg->rx_nbits = 0;
+ msg->tx_nbits = 0;
+ msg->mode = 0;
+ msg->cs = cs;
+}
+
+static int sc16is752_spi_write_reg(
+ sc16is752_context *base,
+ uint8_t addr,
+ const uint8_t *data,
+ size_t len
+)
+{
+ sc16is752_spi_context *ctx = (sc16is752_spi_context *) base;
+ spi_ioc_transfer msg[2];
+ uint8_t unused[SC16IS752_FIFO_DEPTH];
+ uint8_t tx_cmd;
+
+ _Assert(len < RTEMS_ARRAY_SIZE(unused));
+
+ msg_init(&msg[0], ctx->cs, ctx->speed_hz, 1, &unused[0], &tx_cmd);
+ msg_init(&msg[1], ctx->cs, ctx->speed_hz, len, &unused[0], &data[0]);
+
+ tx_cmd = addr << 3;
+ msg[1].cs_change = 1;
+
+ return ioctl(ctx->fd, SPI_IOC_MESSAGE(2), &msg[0]);
+}
+
+static int sc16is752_spi_read_reg(
+ sc16is752_context *base,
+ uint8_t addr,
+ uint8_t *data,
+ size_t len
+)
+{
+ sc16is752_spi_context *ctx = (sc16is752_spi_context *) base;
+ spi_ioc_transfer msg[2];
+ uint8_t unused;
+ uint8_t tx_cmd;
+ uint8_t tx_buf[SC16IS752_FIFO_DEPTH];
+
+ _Assert(len < RTEMS_ARRAY_SIZE(tx_buf));
+
+ msg_init(&msg[0], ctx->cs, ctx->speed_hz, 1, &unused, &tx_cmd);
+ msg_init(&msg[1], ctx->cs, ctx->speed_hz, len, &data[0], &tx_buf[0]);
+
+ tx_cmd = 0x80 | (addr << 3);
+ msg[1].cs_change = 1;
+
+ return ioctl(ctx->fd, SPI_IOC_MESSAGE(2), &msg[0]);
+}
+
+static int sc16is752_spi_read_2_reg(
+ sc16is752_context *base,
+ uint8_t addr_0,
+ uint8_t addr_1,
+ uint8_t data[2]
+)
+{
+ sc16is752_spi_context *ctx = (sc16is752_spi_context *) base;
+ spi_ioc_transfer msg[4];
+ uint8_t unused;
+ uint8_t tx_cmd_0;
+ uint8_t tx_cmd_1;
+
+ msg_init(&msg[0], ctx->cs, ctx->speed_hz, 1, &unused, &tx_cmd_0);
+ msg_init(&msg[1], ctx->cs, ctx->speed_hz, 1, &data[0], &unused);
+ msg_init(&msg[2], ctx->cs, ctx->speed_hz, 1, &unused, &tx_cmd_1);
+ msg_init(&msg[3], ctx->cs, ctx->speed_hz, 1, &data[1], &unused);
+
+ tx_cmd_0 = 0x80 | (addr_0 << 3);
+ tx_cmd_1 = 0x80 | (addr_1 << 3);
+ msg[1].cs_change = 1;
+ msg[3].cs_change = 1;
+
+ return ioctl(ctx->fd, SPI_IOC_MESSAGE(4), &msg[0]);
+}
+
+static bool sc16is752_spi_first_open(sc16is752_context *base)
+{
+ sc16is752_spi_context *ctx = (sc16is752_spi_context *) base;
+ ctx->fd = open(ctx->spi_path, O_RDWR);
+ return ctx->fd >= 0;
+}
+
+static void sc16is752_spi_last_close(sc16is752_context *base)
+{
+ sc16is752_spi_context *ctx = (sc16is752_spi_context *) base;
+ close(ctx->fd);
+}
+
+rtems_status_code sc16is752_spi_create(
+ sc16is752_spi_context *ctx,
+ const char *device_path
+)
+{
+ ctx->base.write_reg = sc16is752_spi_write_reg;
+ ctx->base.read_reg = sc16is752_spi_read_reg;
+ ctx->base.read_2_reg = sc16is752_spi_read_2_reg;
+ ctx->base.first_open = sc16is752_spi_first_open;
+ ctx->base.last_close = sc16is752_spi_last_close;
+
+ return rtems_termios_device_install(
+ device_path,
+ &sc16is752_termios_handler,
+ NULL,
+ &ctx->base.base
+ );
+}