[PATCH 1/3] bsps/xilinx_zynq: Add SPI driver for xilinx-axi-spi

Jan Sommer jan.sommer at dlr.de
Wed Mar 10 20:14:46 UTC 2021


Updates #4321
---
 bsps/include/dev/spi/xilinx-axi-spi-regs.h |  88 +++++
 bsps/include/dev/spi/xilinx-axi-spi.h      |  67 ++++
 bsps/shared/dev/spi/xilinx-axi-spi.c       | 402 +++++++++++++++++++++
 3 files changed, 557 insertions(+)
 create mode 100644 bsps/include/dev/spi/xilinx-axi-spi-regs.h
 create mode 100644 bsps/include/dev/spi/xilinx-axi-spi.h
 create mode 100644 bsps/shared/dev/spi/xilinx-axi-spi.c

diff --git a/bsps/include/dev/spi/xilinx-axi-spi-regs.h b/bsps/include/dev/spi/xilinx-axi-spi-regs.h
new file mode 100644
index 0000000000..6211c5b97f
--- /dev/null
+++ b/bsps/include/dev/spi/xilinx-axi-spi-regs.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
+#define LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
+
+#include <bsp/utility.h>
+
+typedef struct {
+    uint32_t reserved1[7];
+    uint32_t globalirq;
+#define XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE BSP_BIT32(31)
+    uint32_t irqstatus;
+    uint32_t reserved2;
+    uint32_t irqenable;
+#define XILINX_AXI_SPI_IRQ_CMD_ERR BSP_BIT32(13)
+#define XILINX_AXI_SPI_IRQ_LOOP_ERR BSP_BIT32(12)
+#define XILINX_AXI_SPI_IRQ_MSB_ERR BSP_BIT32(11)
+#define XILINX_AXI_SPI_IRQ_SLV_ERR BSP_BIT32(10)
+#define XILINX_AXI_SPI_IRQ_CPOL_CPHA_ERR BSP_BIT32(9)
+#define XILINX_AXI_SPI_IRQ_RXNEMPTY BSP_BIT32(8)
+#define XILINX_AXI_SPI_IRQ_CS_MODE BSP_BIT32(7)
+#define XILINX_AXI_SPI_IRQ_TXHALF BSP_BIT32(6)
+#define XILINX_AXI_SPI_IRQ_RXOVR BSP_BIT32(5)
+#define XILINX_AXI_SPI_IRQ_RXFULL BSP_BIT32(4)
+#define XILINX_AXI_SPI_IRQ_TXUF BSP_BIT32(3)
+#define XILINX_AXI_SPI_IRQ_TXEMPTY BSP_BIT32(2)
+#define XILINX_AXI_SPI_IRQ_SLV_MODF BSP_BIT32(1)
+#define XILINX_AXI_SPI_IRQ_MODF BSP_BIT32(0)
+    uint32_t reserved3[5];
+    uint32_t reset;
+#define XILINX_AXI_SPI_RESET 0x0000000a
+    uint32_t reserved4[7];
+    uint32_t control;
+#define XILINX_AXI_SPI_CONTROL_LSBFIRST BSP_BIT32(9)
+#define XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT BSP_BIT32(8)
+#define XILINX_AXI_SPI_CONTROL_MANUAL_CS BSP_BIT32(7)
+#define XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET BSP_BIT32(6)
+#define XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET BSP_BIT32(5)
+#define XILINX_AXI_SPI_CONTROL_CPHA BSP_BIT32(4)
+#define XILINX_AXI_SPI_CONTROL_CPOL BSP_BIT32(3)
+#define XILINX_AXI_SPI_CONTROL_MSTREN BSP_BIT32(2)
+#define XILINX_AXI_SPI_CONTROL_SPIEN BSP_BIT32(1)
+#define XILINX_AXI_SPI_CONTROL_LOOP BSP_BIT32(0)
+    uint32_t status;
+#define XILINX_AXI_SPI_STATUS_CMD_ERR BSP_BIT32(10)
+#define XILINX_AXI_SPI_STATUS_LOOP_ERR BSP_BIT32(9)
+#define XILINX_AXI_SPI_STATUS_MSB_ERR BSP_BIT32(8)
+#define XILINX_AXI_SPI_STATUS_SLV_ERR BSP_BIT32(7)
+#define XILINX_AXI_SPI_STATUS_CPOL_CPHA_ERR BSP_BIT32(6)
+#define XILINX_AXI_SPI_STATUS_SLV_MODE BSP_BIT32(5)
+#define XILINX_AXI_SPI_STATUS_MODF BSP_BIT32(4)
+#define XILINX_AXI_SPI_STATUS_TXFULL BSP_BIT32(3)
+#define XILINX_AXI_SPI_STATUS_TXEMPTY BSP_BIT32(2)
+#define XILINX_AXI_SPI_STATUS_RXFULL BSP_BIT32(1)
+#define XILINX_AXI_SPI_STATUS_RXEMPTY BSP_BIT32(0)
+    uint32_t txdata;
+    uint32_t rxdata;
+    uint32_t cs;
+    uint32_t tx_fifo_len;
+    uint32_t rx_fifo_len;
+} xilinx_axi_spi;
+
+#endif /* LIBBSP_ARM_XILINX_AXI_SPI_REGS_H */
diff --git a/bsps/include/dev/spi/xilinx-axi-spi.h b/bsps/include/dev/spi/xilinx-axi-spi.h
new file mode 100644
index 0000000000..1f5e2a9989
--- /dev/null
+++ b/bsps/include/dev/spi/xilinx-axi-spi.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_AXI_SPI_H
+#define LIBBSP_ARM_XILINX_AXI_SPI_H
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** 
+ * Register Xilinx AXI SPI device
+ *
+ * Note:
+ *   The Xilinx Quad SPI device is very versatile and
+ *   supports many options. This driver assumes the 
+ *   following setup:
+ *     - Standard SPI mode and AXI Lite interface
+ *     - FIFO available (driver might also work without FIFOs)
+ *
+ * @param bus_path path for the new device node (e.g. "/dev/spi0")
+ * @param register_base base address of the device
+ * @param fifo_size Configured fifo size. Either 0, 16 or 256
+ * @param num_cs Number of configured CS lines (0-32)
+ *
+ * @return 0 on success. Negative number otherwise.
+ *
+ */
+int spi_bus_register_xilinx_axi(
+  const char *bus_path,
+  uintptr_t register_base,
+  uint32_t fifo_size,
+  uint32_t num_cs,
+  rtems_vector_number irq
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_XILINX_AXI_SPI_H */
diff --git a/bsps/shared/dev/spi/xilinx-axi-spi.c b/bsps/shared/dev/spi/xilinx-axi-spi.c
new file mode 100644
index 0000000000..7b8b280291
--- /dev/null
+++ b/bsps/shared/dev/spi/xilinx-axi-spi.c
@@ -0,0 +1,402 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <bsp.h>
+
+#include <rtems/irq-extension.h>
+#include <sys/param.h> /* MAX() */
+
+#include <dev/spi/spi.h>
+#include <dev/spi/xilinx-axi-spi.h>
+#include <dev/spi/xilinx-axi-spi-regs.h>
+
+#define XILINX_AXI_SPI_CS_NONE 0xFF
+
+typedef struct xilinx_axi_spi_bus xilinx_axi_spi_bus;
+
+struct xilinx_axi_spi_bus {
+  spi_bus base;
+  volatile xilinx_axi_spi *regs;
+  uint32_t fifo_size;
+  uint32_t num_cs;
+  uint32_t msg_todo;
+  const spi_ioc_transfer *msg;
+  uint32_t todo;
+  uint32_t in_transfer;
+  uint8_t *rx_buf;
+  const uint8_t *tx_buf;
+  rtems_id task_id;
+  rtems_vector_number irq;
+};
+
+
+static void xilinx_axi_spi_disable_interrupts(volatile xilinx_axi_spi *regs)
+{
+  regs->globalirq = 0;
+  regs->irqenable = 0;
+}
+
+static bool xilinx_axi_spi_rx_fifo_not_empty(volatile xilinx_axi_spi *regs)
+{
+  return (regs->status & XILINX_AXI_SPI_STATUS_RXEMPTY) == 0;
+}
+
+static void xilinx_axi_spi_reset(xilinx_axi_spi_bus *bus)
+{
+  volatile xilinx_axi_spi *regs = bus->regs;
+  uint32_t control;
+
+  /* Initiate soft reset for initial state */
+  regs->reset = XILINX_AXI_SPI_RESET;
+
+  /* Configure as master */
+  control = regs->control;
+  control |= XILINX_AXI_SPI_CONTROL_MSTREN;
+  regs->control = control;
+}
+
+static void xilinx_axi_spi_done(xilinx_axi_spi_bus *bus)
+{
+  volatile xilinx_axi_spi *regs = bus->regs;
+  uint32_t control = regs->control;
+  control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
+  regs->control = control;
+
+  xilinx_axi_spi_disable_interrupts(regs);
+  rtems_event_transient_send(bus->task_id);
+}
+
+static void xilinx_axi_spi_push(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
+{
+  while (bus->todo > 0 && bus->in_transfer < bus->fifo_size) {
+    uint8_t val = 0;
+    if (bus->tx_buf != NULL) {
+        val = *bus->tx_buf;
+        ++bus->tx_buf;
+    }
+
+    --bus->todo;
+    regs->txdata = val;
+    ++bus->in_transfer;
+  }
+}
+
+static void
+xilinx_axi_spi_set_chipsel(xilinx_axi_spi_bus *bus, uint32_t cs)
+{
+
+   volatile xilinx_axi_spi *regs = bus->regs;
+   uint32_t cs_bit = XILINX_AXI_SPI_CS_NONE;
+
+  if (cs != SPI_NO_CS && cs < bus->num_cs) {
+      cs_bit &= ~(1<<cs);
+  }
+  bus->base.cs = cs;
+
+  regs->cs = cs_bit;
+}
+
+static void xilinx_axi_spi_config(
+  xilinx_axi_spi_bus *bus,
+  volatile xilinx_axi_spi *regs,
+  uint32_t mode,
+  uint8_t  cs
+)
+{
+  spi_bus *base = &bus->base;
+  uint32_t control = regs->control;
+
+  control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
+  regs->control = control;
+  
+  if ((mode & SPI_CPHA) != 0) {
+    control |= XILINX_AXI_SPI_CONTROL_CPHA;
+  } else {
+    control &= ~XILINX_AXI_SPI_CONTROL_CPHA;
+  }
+
+  if ((mode & SPI_CPOL) != 0) {
+    control |= XILINX_AXI_SPI_CONTROL_CPOL;
+  } else {
+    control &= ~XILINX_AXI_SPI_CONTROL_CPOL;
+  }
+
+  if ((mode & SPI_LOOP) != 0) {
+    control |= XILINX_AXI_SPI_CONTROL_LOOP;
+  } else {
+    control &= ~XILINX_AXI_SPI_CONTROL_LOOP;
+  }
+
+  regs->control = control;
+  xilinx_axi_spi_set_chipsel(bus, cs);
+
+  base->mode = mode;
+  base->cs = cs;
+
+}
+
+static void
+xilinx_axi_spi_next_msg(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
+{
+    uint32_t control = regs->control;
+    control |= XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT
+               | XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET
+               | XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET;
+    regs->control = control;
+
+  if (bus->msg_todo > 0) {
+    const spi_ioc_transfer *msg;
+    spi_bus *base = &bus->base;
+
+    msg = bus->msg;
+
+    if (
+        msg->mode != base->mode
+        || msg->cs != base->cs
+    ) {
+      xilinx_axi_spi_config(
+        bus,
+        regs,
+        msg->mode,
+        msg->cs
+      );
+    }
+
+    if ((msg->mode & SPI_NO_CS) != 0) {
+      xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
+    }
+
+    bus->todo = msg->len;
+    bus->rx_buf = msg->rx_buf;
+    bus->tx_buf = msg->tx_buf;
+    xilinx_axi_spi_push(bus, regs);
+    
+    xilinx_axi_spi_disable_interrupts(regs);
+    if (
+        bus->todo < bus->fifo_size
+        || bus->fifo_size == 1) {
+        /* if the msg fits into the FIFO, wait for empty TX buffer */
+        regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
+
+    } else {
+        /* if the msg does not fit, refill tx_buf when the tx FIFO is half empty */
+        regs->irqenable = XILINX_AXI_SPI_IRQ_TXHALF;
+    }
+    regs->globalirq = XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE;
+    control = regs->control;
+    control |= XILINX_AXI_SPI_CONTROL_SPIEN;
+    control &= ~XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT;
+    regs->control = control;
+  } else {
+    xilinx_axi_spi_done(bus);
+  }
+}
+
+static void xilinx_axi_spi_interrupt(void *arg)
+{
+  xilinx_axi_spi_bus *bus;
+  volatile xilinx_axi_spi *regs;
+
+  bus = arg;
+  regs = bus->regs;
+
+  /* Clear interrupt flag. It's safe, since only one IRQ active at a time */
+  regs->irqstatus = regs->irqenable;
+
+  while (xilinx_axi_spi_rx_fifo_not_empty(regs)) {
+    uint32_t val = regs->rxdata;
+    if (bus->rx_buf != NULL) {
+        *bus->rx_buf = (uint8_t)val;
+        ++bus->rx_buf;
+    }
+    --bus->in_transfer;
+  }
+
+  if (bus->todo > 0) {
+    xilinx_axi_spi_push(bus, regs);
+  } else if (bus->in_transfer > 0) {
+    /* Wait until all bytes have been transfered */
+    regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
+  } else {
+    --bus->msg_todo;
+    ++bus->msg;
+    xilinx_axi_spi_next_msg(bus, regs);
+  }
+}
+
+static int xilinx_axi_spi_check_messages(
+  xilinx_axi_spi_bus *bus,
+  const spi_ioc_transfer *msg,
+  uint32_t size)
+{
+  while(size > 0) {
+    if (msg->bits_per_word != 8) {
+      return -EINVAL;
+    }
+    if ((msg->mode &
+        ~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
+      return -EINVAL;
+    }
+    if ((msg->mode & SPI_NO_CS) == 0 &&
+        (msg->cs > bus->num_cs)) {
+      return -EINVAL;
+    }
+
+    ++msg;
+    --size;
+  }
+
+  return 0;
+}
+
+static int xilinx_axi_spi_transfer(
+  spi_bus *base,
+  const spi_ioc_transfer *msgs,
+  uint32_t n
+)
+{
+  xilinx_axi_spi_bus *bus;
+  int rv;
+
+  bus = (xilinx_axi_spi_bus *) base;
+
+  rv = xilinx_axi_spi_check_messages(bus, msgs, n);
+
+  if (rv == 0) {
+    bus->msg_todo = n;
+    bus->msg = &msgs[0];
+    bus->task_id = rtems_task_self();
+
+    xilinx_axi_spi_next_msg(bus, bus->regs);
+    rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+    xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
+  }
+  return rv;
+}
+
+static void xilinx_axi_spi_destroy(spi_bus *base)
+{
+  xilinx_axi_spi_bus *bus;
+
+  bus = (xilinx_axi_spi_bus *) base;
+  rtems_interrupt_handler_remove(bus->irq, xilinx_axi_spi_interrupt, bus);
+  spi_bus_destroy_and_free(&bus->base);
+}
+
+static int xilinx_axi_spi_setup(spi_bus *base)
+{
+  xilinx_axi_spi_bus *bus;
+  uint32_t mode = base->mode;
+
+  bus = (xilinx_axi_spi_bus *) base;
+
+  if (bus->base.bits_per_word > 8) {
+    return -EINVAL;
+  }
+
+  /* SPI_CS_HIGH not supported */
+  if (mode & SPI_CS_HIGH) {
+      return -EINVAL;
+  }
+
+  xilinx_axi_spi_config(
+    bus,
+    bus->regs,
+    base->mode,
+    base->cs
+  );
+  return 0;
+}
+
+int spi_bus_register_xilinx_axi(
+        const char *bus_path,
+        uintptr_t register_base,
+        uint32_t fifo_size,
+        uint32_t num_cs,
+        rtems_vector_number irq)
+{
+  xilinx_axi_spi_bus *bus;
+  spi_bus *base;
+  int sc;
+
+  if (fifo_size != 0 && fifo_size != 16 && fifo_size != 256) {
+      return -1;
+  }
+
+  if (num_cs > 32) {
+      return -1;
+  }
+
+  bus = (xilinx_axi_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
+  if (bus == NULL){
+    return -1;
+  }
+
+  base = &bus->base;
+  bus->regs = (volatile xilinx_axi_spi *) register_base;
+  bus->irq = irq;
+  bus->num_cs = num_cs;
+
+  /* For operation without FIFO set fifo_size to 1
+   * so that comparison operators work
+   */
+  if (fifo_size == 0) {
+    bus->fifo_size = 1;
+  } else {
+    bus->fifo_size = fifo_size;
+  }
+
+  base->cs = SPI_NO_CS;
+
+  xilinx_axi_spi_reset(bus);
+  xilinx_axi_spi_config(
+    bus,
+    bus->regs,
+    base->mode,
+    base->cs
+    );
+
+
+  sc = rtems_interrupt_handler_install(
+    bus->irq,
+    "XSPI",
+    RTEMS_INTERRUPT_UNIQUE,
+    xilinx_axi_spi_interrupt,
+    bus
+  );
+  if (sc != RTEMS_SUCCESSFUL) {
+    (*bus->base.destroy)(&bus->base);
+    rtems_set_errno_and_return_minus_one(EAGAIN);
+  }
+
+  bus->base.transfer = xilinx_axi_spi_transfer;
+  bus->base.destroy = xilinx_axi_spi_destroy;
+  bus->base.setup = xilinx_axi_spi_setup;
+
+  return spi_bus_register(&bus->base, bus_path);
+}
-- 
2.17.1



More information about the devel mailing list