[PATCH] dev: Add NXP SC16IS752 serial device driver
Sebastian Huber
sebastian.huber at embedded-brains.de
Wed Dec 14 14:23:43 UTC 2016
From: Alexander Krutwig <alexander.krutwig at embedded-brains.de>
Update #2841.
---
cpukit/dev/Makefile.am | 7 +
cpukit/dev/include/dev/serial/nxp-sc16is752.h | 165 +++++++++++++++++
cpukit/dev/preinstall.am | 9 +
cpukit/dev/serial/nxp-sc16is752-regs.h | 108 +++++++++++
cpukit/dev/serial/nxp-sc16is752-spi.c | 126 +++++++++++++
cpukit/dev/serial/nxp-sc16is752.c | 257 ++++++++++++++++++++++++++
6 files changed, 672 insertions(+)
create mode 100644 cpukit/dev/include/dev/serial/nxp-sc16is752.h
create mode 100644 cpukit/dev/serial/nxp-sc16is752-regs.h
create mode 100644 cpukit/dev/serial/nxp-sc16is752-spi.c
create mode 100644 cpukit/dev/serial/nxp-sc16is752.c
diff --git a/cpukit/dev/Makefile.am b/cpukit/dev/Makefile.am
index 2b65390..cdc3fe8 100644
--- a/cpukit/dev/Makefile.am
+++ b/cpukit/dev/Makefile.am
@@ -15,6 +15,10 @@ include_dev_spidir = $(includedir)/dev/spi
include_dev_spi_HEADERS =
include_dev_spi_HEADERS += include/dev/spi/spi.h
+include_dev_serialdir = $(includedir)/dev/serial
+include_dev_serial_HEADERS =
+include_dev_serial_HEADERS += include/dev/serial/nxp-sc16is752.h
+
include_linuxdir = $(includedir)/linux
include_linux_HEADERS =
include_linux_HEADERS += include/linux/i2c.h
@@ -33,6 +37,9 @@ libdev_a_SOURCES += i2c/i2c-bus.c
libdev_a_SOURCES += i2c/i2c-dev.c
libdev_a_SOURCES += i2c/switch-nxp-pca9548a.c
libdev_a_SOURCES += spi/spi-bus.c
+libdev_a_SOURCES += serial/nxp-sc16is752.c
+libdev_a_SOURCES += serial/nxp-sc16is752-spi.c
+libdev_a_SOURCES += serial/nxp-sc16is752-regs.h
include $(srcdir)/preinstall.am
include $(top_srcdir)/automake/local.am
diff --git a/cpukit/dev/include/dev/serial/nxp-sc16is752.h b/cpukit/dev/include/dev/serial/nxp-sc16is752.h
new file mode 100644
index 0000000..9d6cc59
--- /dev/null
+++ b/cpukit/dev/include/dev/serial/nxp-sc16is752.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <info at 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.
+ */
+
+#ifndef _DEV_SERIAL_SC16IS752_H
+#define _DEV_SERIAL_SC16IS752_H
+
+#include <rtems/termiostypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup NXP-SC16IS752 Device Support
+ *
+ * @ingroup TermiostypesSupport
+ *
+ * @brief NXP-SC16IS752 Device Support Internal Data Structures
+ */
+
+typedef struct sc16is752_context sc16is752_context;
+
+/**
+ * @brief SC16IS752 device context.
+ */
+struct sc16is752_context {
+ rtems_termios_device_context base;
+
+ int (*write_reg)(
+ sc16is752_context *ctx,
+ uint8_t addr,
+ const uint8_t *data,
+ size_t len
+ );
+
+ int (*read_reg)(
+ sc16is752_context *ctx,
+ uint8_t addr,
+ uint8_t *data,
+ size_t len
+ );
+
+ bool (*first_open)(sc16is752_context *ctx);
+
+ void (*last_close)(sc16is752_context *ctx);
+
+ /**
+ * @brief Interrupt install handler must be given by user before termios device
+ * creation.
+ */
+ bool (*install_irq)(sc16is752_context *ctx);
+
+ /**
+ * @brief Interrupt remove handler must be given by user before termios device
+ * creation.
+ */
+ void (*remove_irq)(sc16is752_context *ctx);
+
+ /**
+ * @brief Mode must be given by user before termios device creation.
+ */
+ enum {
+ SC16IS752_MODE_RS232,
+ SC16IS752_MODE_RS485
+ } mode;
+
+ /**
+ * @brief Input frequency (dependent on crystal) must be given by user before
+ * termios device creation
+ */
+ uint32_t input_frequency;
+
+ rtems_termios_tty *tty;
+
+ /**
+ * @brief Shadow interrupt enable register (IER).
+ */
+ uint8_t ier;
+
+ /**
+ * @brief Characters placed into transmit FIFO.
+ */
+ uint8_t tx_in_progress;
+
+ /**
+ * @brief Count of free characters in the transmit FIFO.
+ */
+ uint8_t tx_fifo_free;
+};
+
+/**
+ * @brief SC16IS752 SPI context.
+ */
+typedef struct {
+ sc16is752_context base;
+
+ int fd;
+
+ /*
+ * @brief chip select shall be set by user before spi bus creation.
+ */
+ uint8_t cs;
+
+ /*
+ * @brief Message speed shall be set by user before spi bus creation.
+ */
+ uint32_t speed_hz;
+
+ /*
+ * SPI bus path shall be provided by the user before spi bus creation.
+ */
+ const char *spi_path;
+} sc16is752_spi_context;
+
+/**
+ * @brief SC16IS752 I2C context.
+ */
+typedef struct {
+ sc16is752_context base;
+ int fd;
+ /*
+ * SPI bus path shall be provided by the user before i2c bus creation.
+ */
+ const char *bus_path;
+} sc16is752_i2c_context;
+
+const rtems_termios_device_handler sc16is752_termios_handler;
+
+/**
+ * @brief The interrupt handler for receive and transmit operations.
+ *
+ * @param[in] arg Function argument.
+ */
+void sc16is752_interrupt_handler(void *arg);
+
+/**
+ * @brief Creates a termios device that runs in polled mode.
+ *
+ * @param[in] spi_ctx Pointer to the current spi context.
+ * @param[in] device_path Buffer which contains the desired device path.
+ *
+ * If return value is not RTEMS_SUCCESSFUL, please check the function
+ * "rtems_termios_device_install" for possible errors.
+ */
+rtems_status_code sc16is752_spi_create(
+ sc16is752_spi_context *spi_ctx,
+ const char *device_path
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _DEV_SERIAL_SC16IS752_H */
diff --git a/cpukit/dev/preinstall.am b/cpukit/dev/preinstall.am
index d2e63ba..801bdb5 100644
--- a/cpukit/dev/preinstall.am
+++ b/cpukit/dev/preinstall.am
@@ -48,6 +48,15 @@ $(PROJECT_INCLUDE)/dev/spi/spi.h: include/dev/spi/spi.h $(PROJECT_INCLUDE)/dev/s
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/spi/spi.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/dev/spi/spi.h
+$(PROJECT_INCLUDE)/dev/serial/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/dev/serial
+ @: > $(PROJECT_INCLUDE)/dev/serial/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/dev/serial/$(dirstamp)
+
+$(PROJECT_INCLUDE)/dev/serial/nxp-sc16is752.h: include/dev/serial/nxp-sc16is752.h $(PROJECT_INCLUDE)/dev/serial/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/serial/nxp-sc16is752.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/dev/serial/nxp-sc16is752.h
+
$(PROJECT_INCLUDE)/linux/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/linux
@: > $(PROJECT_INCLUDE)/linux/$(dirstamp)
diff --git a/cpukit/dev/serial/nxp-sc16is752-regs.h b/cpukit/dev/serial/nxp-sc16is752-regs.h
new file mode 100644
index 0000000..69dcfdf
--- /dev/null
+++ b/cpukit/dev/serial/nxp-sc16is752-regs.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <info at 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.
+ */
+
+#ifndef LIBBSP_ARM_ATSAM_SC16IS752_H
+#define LIBBSP_ARM_ATSAM_SC16IS752_H
+
+#include <dev/serial/nxp-sc16is752.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* General register set */
+#define SC16IS752_RHR 0x0
+#define SC16IS752_THR 0x0
+#define SC16IS752_IER 0x1
+#define SC16IS752_FCR 0x2
+#define SC16IS752_IIR 0x2
+#define SC16IS752_LCR 0x3
+#define SC16IS752_MCR 0x4
+#define SC16IS752_LSR 0x5
+#define SC16IS752_MSR 0x6
+#define SC16IS752_TCR 0x6
+#define SC16IS752_SPR 0x7
+#define SC16IS752_TLR 0x7
+#define SC16IS752_TXLVL 0x8
+#define SC16IS752_RXLVL 0x9
+#define SC16IS752_IODIR 0xA
+#define SC16IS752_IOSTATE 0xB
+#define SC16IS752_IOINTENA 0xC
+#define SC16IS752_IOCONTROL 0xE
+#define SC16IS752_EFCR 0xF
+
+/* FCR bits */
+#define FCR_FIFO_EN 0x01
+#define FCR_RX_FIFO_RST 0x02
+#define FCR_TX_FIFO_RST 0x04
+#define FCR_TX_FIFO_TRG_8 0x00
+#define FCR_TX_FIFO_TRG_16 0x10
+#define FCR_TX_FIFO_TRG_32 0x20
+#define FCR_TX_FIFO_TRG_56 0x30
+#define FCR_RX_FIFO_TRG_8 0x00
+#define FCR_RX_FIFO_TRG_16 0x40
+#define FCR_RX_FIFO_TRG_56 0x80
+#define FCR_RX_FIFO_TRG_60 0xc0
+
+/* Special register set */
+#define SC16IS752_DLL 0x0
+#define SC16IS752_DLH 0x1
+
+/* Enhanced register set */
+#define SC16IS752_EFR 0x2
+#define SC16IS752_XON1 0x4
+#define SC16IS752_XON2 0x5
+#define SC16IS752_XOFF1 0x6
+#define SC16IS752_XOFF2 0x7
+
+/* EFCR Bit masks */
+#define EFCR_RS485ENABLE (1 << 0)
+#define EFCR_RXENABLE (0 << 1)
+#define EFCR_TXENABLE (0 << 2)
+
+/* IER Bit masks */
+#define IER_ENABLE_RHR_INTERRUPT (1u << 0)
+#define IER_ENABLE_THR_INTERRUPT (1u << 1)
+#define IER_ENABLE_RECEIVE_LINE_INTERRUPT (1u << 2)
+#define IER_ENABLE_MODEM_STATUS_INTERRUPT (1u << 3)
+
+/* IIR Bit masks */
+#define IIR_TX_INTERRUPT (1u << 1)
+#define IIR_RX_INTERRUPT (1u << 2)
+
+/* LCR Bit masks */
+#define LCR_CHRL_5_BIT (0u << 1) | (0u << 0)
+#define LCR_CHRL_6_BIT (0u << 1) | (1u << 0)
+#define LCR_CHRL_7_BIT (1u << 1) | (0u << 0)
+#define LCR_CHRL_8_BIT (1u << 1) | (1u << 0)
+#define LCR_2_STOP_BIT (1u << 2)
+#define LCR_SET_PARITY (1u << 3)
+#define LCR_EVEN_PARITY (1u << 4)
+#define LCR_ENABLE_DIVISOR (1u << 7)
+
+/* LSR Bit masks */
+#define LSR_TXEMPTY (1u << 5)
+#define LSR_RXRDY (1u << 0)
+#define LSR_ERROR_BITS (7u << 2)
+
+/* MCR Bit masks */
+#define MCR_PRESCALE_NEEDED (1u << 0)
+
+#define SC16IS752_FIFO_DEPTH 64
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_ATSAM_SC16IS752_H */
diff --git a/cpukit/dev/serial/nxp-sc16is752-spi.c b/cpukit/dev/serial/nxp-sc16is752-spi.c
new file mode 100644
index 0000000..74e273b
--- /dev/null
+++ b/cpukit/dev/serial/nxp-sc16is752-spi.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <info at 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 "nxp-sc16is752-regs.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <dev/spi/spi.h>
+
+static void set_default_msg(
+ 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 *ctx,
+ uint8_t reg_addr,
+ const uint8_t *reg_val,
+ size_t len
+)
+{
+ int rv;
+ spi_ioc_transfer msg[2];
+ uint8_t rx_buf_cmd;
+ uint8_t rx_buf[len];
+ uint8_t tx_buf_cmd;
+ sc16is752_spi_context *spi_ctx = (sc16is752_spi_context *) ctx;
+
+ tx_buf_cmd = reg_addr << 3;
+ set_default_msg(&msg[0], spi_ctx->cs, spi_ctx->speed_hz, 1, &rx_buf_cmd, &tx_buf_cmd);
+
+ set_default_msg(&msg[1], spi_ctx->cs, spi_ctx->speed_hz, len, &rx_buf[0], ®_val[0]);
+ msg[1].cs_change = 1;
+
+ rv = ioctl(spi_ctx->fd, SPI_IOC_MESSAGE(2), &msg[0]);
+
+ return rv;
+}
+
+static int sc16is752_spi_read_reg(
+ sc16is752_context *ctx,
+ uint8_t reg_addr,
+ uint8_t *reg_val,
+ size_t len
+)
+{
+ int rv;
+ spi_ioc_transfer msg[2];
+ uint8_t rx_buf_cmd;
+ uint8_t tx_buf_cmd;
+ uint8_t tx_buf[len];
+ sc16is752_spi_context *spi_ctx = (sc16is752_spi_context *) ctx;
+
+ tx_buf_cmd = 0x80 | reg_addr << 3;
+
+ set_default_msg(&msg[0], spi_ctx->cs, spi_ctx->speed_hz, 1, &rx_buf_cmd, &tx_buf_cmd);
+
+ set_default_msg(&msg[1], spi_ctx->cs, spi_ctx->speed_hz, len, ®_val[0], &tx_buf[0]);
+ msg[1].cs_change = 1;
+
+ rv = ioctl(spi_ctx->fd, SPI_IOC_MESSAGE(2), &msg[0]);
+
+ return rv;
+}
+
+static bool sc16is752_spi_first_open(sc16is752_context *ctx)
+{
+ sc16is752_spi_context *spi_ctx = (sc16is752_spi_context *) ctx;
+ spi_ctx->fd = open(spi_ctx->spi_path, O_RDWR);
+ return spi_ctx->fd >= 0;
+}
+
+static void sc16is752_spi_last_close(sc16is752_context *ctx)
+{
+ sc16is752_spi_context *spi_ctx = (sc16is752_spi_context *) ctx;
+ close(spi_ctx->fd);
+}
+
+rtems_status_code sc16is752_spi_create(
+ sc16is752_spi_context *spi_ctx,
+ const char *device_path
+)
+{
+ spi_ctx->base.write_reg = sc16is752_spi_write_reg;
+ spi_ctx->base.read_reg = sc16is752_spi_read_reg;
+ spi_ctx->base.first_open = sc16is752_spi_first_open;
+ spi_ctx->base.last_close = sc16is752_spi_last_close;
+
+ return rtems_termios_device_install(
+ device_path,
+ &sc16is752_termios_handler,
+ NULL,
+ &spi_ctx->base.base
+ );
+}
diff --git a/cpukit/dev/serial/nxp-sc16is752.c b/cpukit/dev/serial/nxp-sc16is752.c
new file mode 100644
index 0000000..4601de5
--- /dev/null
+++ b/cpukit/dev/serial/nxp-sc16is752.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at 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 <sys/param.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include <dev/serial/nxp-sc16is752.h>
+#include "nxp-sc16is752-regs.h"
+
+#include <rtems/termiostypes.h>
+
+#define SC16IS752_CONSOLE_BAUD 115200
+
+static void write_reg(
+ sc16is752_context *ctx,
+ uint8_t addr,
+ const uint8_t *val,
+ size_t len
+)
+{
+ ctx->write_reg(ctx, addr, val, len);
+}
+
+static void read_reg(
+ sc16is752_context *ctx,
+ uint8_t addr,
+ uint8_t *val,
+ size_t len
+)
+{
+ ctx->read_reg(ctx, addr, val, len);
+}
+
+static void sc16is752_set_baud_rate(
+ sc16is752_context *ctx,
+ uint32_t value_mcr,
+ uint32_t divisor
+)
+{
+ uint8_t value_lcr;
+ uint8_t value_mcr_8bit = (uint8_t)value_mcr;
+ uint8_t divisor_8bit = (uint8_t)divisor;
+ uint8_t divisor_shift = divisor >> 8;
+
+ read_reg(ctx, SC16IS752_LCR, &value_lcr, 1);
+ value_lcr |= LCR_ENABLE_DIVISOR;
+
+ write_reg(ctx, SC16IS752_LCR, &value_lcr, 1);
+ write_reg(ctx, SC16IS752_MCR, &value_mcr_8bit, 1);
+ write_reg(ctx, SC16IS752_DLH, &divisor_shift, 1);
+ write_reg(ctx, SC16IS752_DLL, &divisor_8bit, 1);
+ value_lcr &= ~LCR_ENABLE_DIVISOR;
+ write_reg(ctx, SC16IS752_LCR, &value_lcr, 1);
+}
+
+static bool sc16is752_prepare_baud_rate(
+ sc16is752_context *ctx,
+ rtems_termios_baud_t baud
+)
+{
+ uint32_t freq = ctx->input_frequency;
+ uint8_t value_mcr;
+ uint32_t divisor;
+
+ read_reg(ctx, SC16IS752_MCR, &value_mcr, 1);
+
+ divisor = freq / baud / 16;
+ if (divisor > 0xFFFF){
+ divisor = (freq / (4 * baud)) / 16;
+ if (divisor > 0xFFFF){
+ return false;
+ } else {
+ value_mcr |= MCR_PRESCALE_NEEDED;
+ sc16is752_set_baud_rate(ctx, value_mcr, divisor);
+ }
+ } else {
+ value_mcr &= ~MCR_PRESCALE_NEEDED;
+ sc16is752_set_baud_rate(ctx, value_mcr, divisor);
+ }
+ return true;
+}
+
+static bool sc16is752_set_attributes(
+ rtems_termios_device_context *base,
+ const struct termios *term
+)
+{
+ sc16is752_context *ctx = (sc16is752_context *) base;
+ uint8_t lcr_value = 0;
+ uint8_t lcr_read_value = 0;
+ uint8_t efcr_value = 0;
+ bool baud_successful;
+ rtems_termios_baud_t baud;
+
+ baud = rtems_termios_baud_to_number(term->c_cflag);
+ baud_successful = sc16is752_prepare_baud_rate(ctx, baud);
+ if (!baud_successful){
+ return false;
+ }
+
+ if (ctx->mode == SC16IS752_MODE_RS485){
+ efcr_value = EFCR_RS485ENABLE;
+ }
+
+ if ((term->c_cflag & CREAD) != 0){
+ efcr_value |= EFCR_RXENABLE | EFCR_TXENABLE;
+ } else {
+ efcr_value |= EFCR_TXENABLE;
+ }
+ write_reg(ctx, SC16IS752_EFCR, &efcr_value, 1);
+
+ switch (term->c_cflag & CSIZE) {
+ case CS5:
+ lcr_value |= LCR_CHRL_5_BIT;
+ break;
+ case CS6:
+ lcr_value |= LCR_CHRL_6_BIT;
+ break;
+ case CS7:
+ lcr_value |= LCR_CHRL_7_BIT;
+ break;
+ case CS8:
+ lcr_value |= LCR_CHRL_8_BIT;
+ break;
+ }
+
+ if ((term->c_cflag & PARENB) != 0){
+ if ((term->c_cflag & PARODD) != 0) {
+ lcr_value &= ~LCR_EVEN_PARITY;
+ } else {
+ lcr_value |= LCR_EVEN_PARITY;
+ }
+ } else {
+ lcr_value &= ~LCR_SET_PARITY;
+ }
+
+ if ((term->c_cflag & CSTOPB) != 0) {
+ lcr_value |= LCR_2_STOP_BIT;
+ } else {
+ lcr_value &= ~LCR_2_STOP_BIT;
+ }
+
+ write_reg(ctx, SC16IS752_LCR, &lcr_value, 1);
+ read_reg(ctx, SC16IS752_LCR, &lcr_read_value, 1);
+
+ return true;
+}
+
+static bool sc16is752_first_open(
+ rtems_termios_tty *tty,
+ rtems_termios_device_context *base,
+ struct termios *term,
+ rtems_libio_open_close_args_t *args
+)
+{
+ bool ok;
+ uint8_t fcr;
+
+ (void)args;
+ sc16is752_context *ctx = (sc16is752_context *) base;
+
+ ctx->tty = tty;
+
+ ok = (*ctx->first_open)(ctx);
+ if (!ok) {
+ return ok;
+ }
+
+ fcr = FCR_FIFO_EN | FCR_RX_FIFO_RST | FCR_TX_FIFO_RST
+ | FCR_RX_FIFO_TRG_8 | FCR_TX_FIFO_TRG_56;
+ write_reg(ctx, SC16IS752_FCR, &fcr, 1);
+
+ ctx->ier = IER_ENABLE_RHR_INTERRUPT;
+ write_reg(ctx, SC16IS752_IER, &ctx->ier, 1);
+
+ rtems_termios_set_initial_baud(tty, SC16IS752_CONSOLE_BAUD);
+ sc16is752_set_attributes(base, term);
+
+ (*ctx->install_irq)(ctx);
+
+ return true;
+}
+
+static void sc16is752_last_close(
+ rtems_termios_tty *tty,
+ rtems_termios_device_context *base,
+ rtems_libio_open_close_args_t *args
+)
+{
+ (void) tty;
+ (void) args;
+ sc16is752_context *ctx = (sc16is752_context *) base;
+ (*ctx->last_close)(ctx);
+}
+
+static void sc16is752_write(
+ rtems_termios_device_context *base,
+ const char *buf,
+ size_t len
+)
+{
+ sc16is752_context *ctx = (sc16is752_context *) base;
+
+ if (len > 0) {
+ ctx->ier |= IER_ENABLE_THR_INTERRUPT;
+ len = MIN(len, SC16IS752_FIFO_DEPTH / 4);
+ ctx->tx_in_progress = (uint8_t)len;
+ write_reg(ctx, SC16IS752_THR, (const uint8_t *)&buf[0], len);
+ write_reg(ctx, SC16IS752_IER, &ctx->ier, 1);
+ } else {
+ ctx->tx_in_progress = 0;
+ ctx->ier &= ~IER_ENABLE_THR_INTERRUPT;
+ write_reg(ctx, SC16IS752_IER, &ctx->ier, 1);
+ }
+}
+
+const rtems_termios_device_handler sc16is752_termios_handler = {
+ .first_open = sc16is752_first_open,
+ .last_close = sc16is752_last_close,
+ .write = sc16is752_write,
+ .set_attributes = sc16is752_set_attributes,
+ .mode = TERMIOS_IRQ_SERVER_DRIVEN
+};
+
+void sc16is752_interrupt_handler(void *arg)
+{
+ sc16is752_context *ctx = (sc16is752_context *) arg;
+ uint8_t iir = 0;
+
+ read_reg(ctx, SC16IS752_IIR, &iir, 1);
+
+ if((iir & IIR_RX_INTERRUPT) != 0) {
+ uint8_t buf[SC16IS752_FIFO_DEPTH];
+ uint8_t rxlvl = 0;
+
+ read_reg(ctx, SC16IS752_RXLVL, &rxlvl, 1);
+ rxlvl = MIN(rxlvl, SC16IS752_FIFO_DEPTH);
+ read_reg(ctx, SC16IS752_RHR, &buf[0], rxlvl);
+ rtems_termios_enqueue_raw_characters(ctx->tty, (const char *)&buf[0], rxlvl);
+ } else if ((iir & IIR_TX_INTERRUPT) != 0 && ctx->tx_in_progress > 0) {
+ rtems_termios_dequeue_characters(ctx->tty, ctx->tx_in_progress);
+ }
+}
--
1.8.4.5
More information about the devel
mailing list