[PATCH 1/2] arm/beagle: SPI driver
Pierre-Louis Garnier
garnie_a at epita.fr
Mon Feb 25 22:30:09 UTC 2019
---
bsps/arm/beagle/headers.am | 1 +
bsps/arm/beagle/include/bsp.h | 4 +-
bsps/arm/beagle/include/bsp/spi.h | 144 +++++++
bsps/arm/beagle/spi/spi.c | 535 ++++++++++++++++++++++++
bsps/arm/include/libcpu/am335x.h | 93 +++-
c/src/lib/libbsp/arm/beagle/Makefile.am | 3 +
6 files changed, 778 insertions(+), 2 deletions(-)
create mode 100644 bsps/arm/beagle/include/bsp/spi.h
create mode 100644 bsps/arm/beagle/spi/spi.c
diff --git a/bsps/arm/beagle/headers.am b/bsps/arm/beagle/headers.am
index 6692d0b69c..4dc35f2e2a 100644
--- a/bsps/arm/beagle/headers.am
+++ b/bsps/arm/beagle/headers.am
@@ -12,3 +12,4 @@ include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/bbb-pwm.h
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/beagleboneblack.h
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/i2c.h
include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/irq.h
+include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/spi.h
diff --git a/bsps/arm/beagle/include/bsp.h b/bsps/arm/beagle/include/bsp.h
index f394c84157..7767456a8e 100644
--- a/bsps/arm/beagle/include/bsp.h
+++ b/bsps/arm/beagle/include/bsp.h
@@ -52,7 +52,9 @@
#define REG16(x)(*((volatile uint16_t *)(x)))
#define REG(x)(*((volatile uint32_t *)(x)))
-#define BIT(x)(0x1 << x)
+#define BIT(x)(0x1 << (x))
+// Start and End included
+#define BITS(Start, End) (((1 << (End+1)) - 1) & ~((1 << (Start)) - 1))
#define udelay(u) rtems_task_wake_after(1 + ((u)/rtems_configuration_get_microseconds_per_tick()))
diff --git a/bsps/arm/beagle/include/bsp/spi.h b/bsps/arm/beagle/include/bsp/spi.h
new file mode 100644
index 0000000000..ffda7edf60
--- /dev/null
+++ b/bsps/arm/beagle/include/bsp/spi.h
@@ -0,0 +1,144 @@
+/**
+ * @file
+ *
+ * @ingroup arm_beagle
+ *
+ * @brief SPI support API.
+ *
+ * Based on bsps/m68k/gen68360/spi/m360_spi.h
+ */
+
+/*
+ * Copyright (c) 2018 Pierre-Louis Garnier <garnie_a at epita.fr>
+ *
+ * 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_BEAGLE_SPI_H
+#define LIBBSP_ARM_BEAGLE_SPI_H
+
+#include <bsp.h>
+#include <rtems/libi2c.h>
+#include <rtems/irq.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define BBB_SPI_TIMEOUT 1000
+
+#define BBB_SPI_0_BUS_PATH "/dev/spi-0"
+
+#define BBB_SPI_0_IRQ AM335X_INT_SPI0INT
+
+typedef enum {
+ SPI0,
+ SPI1,
+ SPI_COUNT
+} bbb_spi_id_t;
+
+
+
+typedef struct BEAGLE_SPI_BufferDescriptor_ {
+ unsigned short status;
+ unsigned short length;
+ volatile void *buffer;
+} BEAGLE_SPI_BufferDescriptor_t;
+
+typedef struct beagle_spi_softc {
+ int initialized;
+ rtems_id task_id;
+ uintptr_t regs_base;
+ rtems_vector_number irq;
+} beagle_spi_softc_t;
+
+typedef struct {
+ rtems_libi2c_bus_t bus_desc;
+ beagle_spi_softc_t softc;
+} beagle_spi_desc_t;
+
+/*
+ * Initialize the driver
+ *
+ * Returns: o = ok or error code
+ */
+rtems_status_code beagle_spi_init
+(
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+);
+
+/*
+ * Receive some bytes from SPI device
+ *
+ * Returns: number of bytes received or (negative) error code
+ */
+int beagle_spi_read_bytes
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to store bytes */
+ int len /* number of bytes to receive */
+);
+
+/*
+ * Send some bytes to SPI device
+ *
+ * Returns: number of bytes sent or (negative) error code
+ */
+int beagle_spi_write_bytes
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to send */
+ int len /* number of bytes to send */
+);
+
+/*
+ * Set SPI to desired baudrate/clock mode/character mode
+ *
+ * Returns: rtems_status_code
+ */
+rtems_status_code beagle_spi_set_tfr_mode
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info */
+);
+
+/*
+ * Perform selected ioctl function for SPI
+ *
+ * Returns: rtems_status_code
+ */
+int beagle_spi_ioctl
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ int cmd, /* ioctl command code */
+ void *arg /* additional argument array */
+);
+
+/*
+ * Register SPI bus and devices
+ *
+ * Returns: Bus number or error code
+ */
+rtems_status_code bsp_register_spi
+(
+ const char *bus_path,
+ uintptr_t register_base,
+ rtems_vector_number irq
+);
+
+static inline rtems_status_code bbb_register_spi_0(void)
+{
+ return bsp_register_spi(
+ BBB_SPI_0_BUS_PATH,
+ AM335X_SPI0_BASE,
+ BBB_SPI_0_IRQ
+ );
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_BEAGLE_SPI_H */
diff --git a/bsps/arm/beagle/spi/spi.c b/bsps/arm/beagle/spi/spi.c
new file mode 100644
index 0000000000..38c0a503e0
--- /dev/null
+++ b/bsps/arm/beagle/spi/spi.c
@@ -0,0 +1,535 @@
+/**
+ * @file
+ *
+ * @ingroup arm_beagle
+ *
+ * @brief BeagleBoard SPI bus initialization and API Support.
+ *
+ * Based on bsps/m68k/gen68360/spi/m360_spi.c
+ */
+
+/*
+ * Copyright (c) 2018 Pierre-Louis Garnier <garnie_a at epita.fr>
+ *
+ * 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 <bsp.h>
+#include <bsp/bbb-gpio.h>
+#include <bsp/spi.h>
+#include <errno.h>
+#include <rtems/bspIo.h>
+#include <rtems/error.h>
+#include <rtems/libi2c.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// #define DEBUG
+// #define TRACE
+
+#define EVENT_TXEMPTY RTEMS_EVENT_0
+#define EVENT_RXFULL RTEMS_EVENT_1
+
+static void SPI0ModuleClkConfig(void)
+{
+ /* Writing to MODULEMODE field of AM335X_CM_PER_SPI0_CLKCTRL register. */
+ REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) |=
+ AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE;
+
+ /* Waiting for MODULEMODE field to reflect the written value. */
+ while ( AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE !=
+ ( REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) &
+ AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE ) )
+ continue;
+
+ /*
+ * Waiting for IDLEST field in AM335X_CM_PER_SPI0_CLKCTRL
+ * register to attain desired value.
+ */
+ while ( ( AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_FUNC <<
+ AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_SHIFT ) !=
+ ( REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) &
+ AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST ) )
+ continue;
+}
+
+static inline void am335x_spi_clear_irqstatus(uint32_t reg_base, uint32_t irqs)
+{
+ REG(reg_base + AM335X_SPI_SYST) &= ~AM335X_SPI_SYST_SSB;
+ REG(reg_base + AM335X_SPI_IRQSTATUS) = irqs;
+}
+
+static void am335x_spi0_pinmux(void)
+{
+ REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_SCLK) =
+ (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN);
+
+ REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D0) =
+ (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN);
+
+ REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D1) =
+ (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN);
+
+ REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_CS0) =
+ (BBB_RXACTIVE | BBB_PU_EN);
+}
+
+static void am335x_spi_reset(uint32_t reg_base)
+{
+ int timeout = BBB_SPI_TIMEOUT;
+
+ REG(reg_base + AM335X_SPI_SYSCONFIG) |= AM335X_SPI_SYSCONFIG_SOFTRESET;
+
+ while ((REG(reg_base + AM335X_SPI_SYSSTATUS) & AM335X_SPI_SYSSTATUS_RESETDONE) == 0 && timeout--) {
+ if (timeout <= 0) {
+ puts("ERROR: Timeout in soft-reset\n");
+
+ return;
+ }
+
+ udelay(1000);
+ }
+}
+
+static void beagle_spi_irq_handler(void *arg)
+{
+ const uint32_t handled_irqs = AM335X_SPI_IRQSTATUS_TX0_EMPTY | AM335X_SPI_IRQSTATUS_RX0_FULL;
+
+ beagle_spi_softc_t *softc_ptr = arg;
+
+ rtems_status_code sc = -1;
+
+ uint32_t irq = 0;
+ uint32_t events = 0;
+
+ uint32_t tmp;
+ while ((tmp = (REG(softc_ptr->regs_base + AM335X_SPI_IRQSTATUS)) & handled_irqs) != 0) {
+ irq |= tmp;
+ am335x_spi_clear_irqstatus(softc_ptr->regs_base, tmp);
+ }
+
+#if defined(TRACE)
+ printk("beagle_spi_irq_handler: AM335X_SPI_IRQSTATUS = 0x%04lx\r\n", irq);
+#endif
+
+ if (irq & AM335X_SPI_IRQSTATUS_TX0_EMPTY) {
+#if defined(TRACE)
+ printk("beagle_spi_irq_handler: sending event TXEMPTY to task_id = %ld\r\n", softc_ptr->task_id);
+#endif
+
+ events |= EVENT_TXEMPTY;
+ }
+
+ if (irq & AM335X_SPI_IRQSTATUS_RX0_FULL) {
+#if defined(TRACE)
+ printk("beagle_spi_irq_handler: sending event RXFULL to task_id = %ld\r\n", softc_ptr->task_id);
+#endif
+
+ events |= EVENT_RXFULL;
+ }
+
+ sc = rtems_event_send(softc_ptr->task_id, events);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+ (void)sc;
+}
+
+/* Initialize the driver
+ *
+ * Returns: o = ok or error code
+ */
+rtems_status_code beagle_spi_init
+(
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+)
+{
+ beagle_spi_softc_t *softc_ptr = &(((beagle_spi_desc_t *)(bh))->softc);
+
+ rtems_status_code rc = RTEMS_SUCCESSFUL;
+
+#if defined(DEBUG)
+ printk("beagle_spi_init called...\r\n");
+#endif
+
+ SPI0ModuleClkConfig();
+ am335x_spi0_pinmux();
+ am335x_spi_reset(softc_ptr->regs_base);
+
+ REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_PIN34;
+ REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_MS; // Master mode
+ REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) |= AM335X_SPI_MODULCTRL_SINGLE; // Single channel
+ REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_PIN34; // SPIEN is usedas a chip select
+ // REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) |= (1 << 3); // Test mode
+
+ // REG(softc_ptr->regs_base + AM335X_SPI_SYST) |= AM335X_SPI_SYST_SPIEN_0; // Not sure about this
+ // REG(softc_ptr->regs_base + AM335X_SPI_SYST) |= AM335X_SPI_SYST_SPIDATDIR0; // Input
+ // REG(softc_ptr->regs_base + AM335X_SPI_SYST) &= ~AM335X_SPI_SYST_SPIDATDIR1; // Output
+
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_TRM_MASK;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_DPE0;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_DPE1;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_IS;
+
+ // REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FFEW;
+ // REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FFER;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_WL(8 - 1);
+
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_PHA;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_POL;
+
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_EPOL;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_CLKD(0x1);
+
+
+ // Setup interrupt
+ rc = rtems_interrupt_handler_install(
+ softc_ptr->irq,
+ NULL,
+ RTEMS_INTERRUPT_UNIQUE,
+ (rtems_interrupt_handler)beagle_spi_irq_handler,
+ softc_ptr
+ );
+
+#if defined(DEBUG)
+ printk("beagle_spi_init done\r\n");
+#endif
+
+ if (rc == RTEMS_SUCCESSFUL) {
+ softc_ptr->initialized = TRUE;
+ }
+
+ return rc;
+}
+
+static int beagle_spi_read_write_bytes(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *rx_buf, /* buffer to store bytes */
+ unsigned char *tx_buf, /* buffer to send */
+ int len /* number of bytes to send */
+)
+{
+ beagle_spi_softc_t *softc_ptr = &(((beagle_spi_desc_t *)(bh))->softc);
+
+ rtems_status_code sc;
+ rtems_event_set received_events;
+
+#if defined(TRACE)
+ printk("beagle_spi_read_write_bytes called...\r\n");
+#endif
+
+ softc_ptr->task_id = rtems_task_self();
+
+ // Enable IRQs
+
+ if (rx_buf) {
+ am335x_spi_clear_irqstatus(softc_ptr->regs_base, AM335X_SPI_IRQSTATUS_RX0_FULL);
+ REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) |= AM335X_SPI_IRQENABLE_RX0_FULL;
+ }
+
+ if (tx_buf) {
+ am335x_spi_clear_irqstatus(softc_ptr->regs_base, AM335X_SPI_IRQSTATUS_TX0_EMPTY);
+ REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) |= AM335X_SPI_IRQENABLE_TX0_EMPTY;
+ }
+
+ // Enable Channel
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FORCE;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CTRL) |= AM335X_SPI_CH0CTRL_EN;
+
+ // Main loop
+ for (int i = 0; i < len; i++) {
+ received_events = 0;
+
+ if (tx_buf) {
+ // Wait for IRQ to wake us up (room in TX FIFO)
+#if defined(TRACE)
+ printk("beagle_spi_read_write_bytes: waiting (task_id = %ld)\r\n", softc_ptr->task_id);
+#endif
+
+ sc = rtems_event_receive(EVENT_TXEMPTY, RTEMS_WAIT, BBB_SPI_TIMEOUT, &received_events);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printk("ERROR: beagle_spi_read_write_bytes timed out on tx byte number %d\n", i);
+ return i > 0 ? i : -RTEMS_TIMEOUT;
+ }
+
+ _Assert(received_events == EVENT_TXEMPTY);
+
+#if defined(TRACE)
+ printk("beagle_spi_read_write_bytes: sending byte: i = %d, tx_buf[i] = 0x%x\r\n", i, tx_buf[i]);
+#endif
+
+ REG(softc_ptr->regs_base + AM335X_SPI_TX0) = tx_buf[i];
+ }
+
+ if (rx_buf) {
+ // Wait for IRQ to wake us up (data in RX FIFO)
+ if ((received_events & EVENT_RXFULL) == 0) {
+ sc = rtems_event_receive(EVENT_RXFULL, RTEMS_WAIT, BBB_SPI_TIMEOUT, &received_events);
+ if (sc != RTEMS_SUCCESSFUL) {
+ printk("ERROR: beagle_spi_read_write_bytes timed out on rx byte number %d\n", i);
+ return i > 0 ? i : -RTEMS_TIMEOUT;
+ }
+
+ _Assert(received_events == EVENT_RXFULL);
+ }
+
+ rx_buf[i] = REG(softc_ptr->regs_base + AM335X_SPI_RX0);
+
+#if defined(TRACE)
+ printk("beagle_spi_read_write_bytes: received byte: i = %d, rx_buf[i] = 0x%x\r\n", i, rx_buf[i]);
+#endif
+ }
+ }
+
+ // REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) &= ~AM335X_SPI_IRQENABLE_RX0_FULL;
+ // REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) &= ~AM335X_SPI_IRQENABLE_TX0_EMPTY;
+
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CTRL) &= ~AM335X_SPI_CH0CTRL_EN;
+ REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_FORCE;
+
+#if defined(TRACE)
+ printk("beagle_spi_read_write_bytes done\r\n");
+#endif
+
+ return len;
+}
+
+/*
+ * Receive some bytes from SPI device
+ *
+ * Returns: number of bytes received or (negative) error code
+ */
+int beagle_spi_read_bytes
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to store bytes */
+ int len /* number of bytes to receive */
+)
+{
+ // FIXME
+#if defined(DEBUG)
+ printk("beagle_spi_read_bytes called...\r\n");
+#endif
+
+ int n = beagle_spi_read_write_bytes(bh, buf, NULL, len);
+
+#if defined(DEBUG)
+ printk("beagle_spi_read_bytes done\r\n");
+#endif
+
+ return n;
+}
+
+/*
+ * Send some bytes to SPI device
+ *
+ * Returns: number of bytes sent or (negative) error code
+ */
+int beagle_spi_write_bytes
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ unsigned char *buf, /* buffer to send */
+ int len /* number of bytes to send */
+)
+{
+#if defined(DEBUG)
+ printk("beagle_spi_write_bytes called...\r\n");
+#endif
+
+ int n = beagle_spi_read_write_bytes(bh, NULL, buf, len);
+
+#if defined(DEBUG)
+ printk("beagle_spi_write_bytes done\r\n");
+#endif
+
+ return n;
+}
+
+/*
+ * Perform selected ioctl function for SPI
+ *
+ * Returns: rtems_status_code
+ */
+int beagle_spi_ioctl
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ int cmd, /* ioctl command code */
+ void *arg /* additional argument array */
+)
+{
+ int ret_val = -1;
+
+#if defined(DEBUG)
+ printk("beagle_spi_ioctl called...\r\n");
+#endif
+
+ switch(cmd) { // FIXME: other ioctls
+ case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
+#if defined(TRACE)
+ printk("cmd == RTEMS_LIBI2C_IOCTL_SET_TFRMODE\r\n");
+#endif
+ // FIXME
+ // ret_val =
+ // -m360_spi_set_tfr_mode(bh,
+ // (const rtems_libi2c_tfr_mode_t *)arg);
+ break;
+ case RTEMS_LIBI2C_IOCTL_READ_WRITE: {
+#if defined(TRACE)
+ printk("cmd == RTEMS_LIBI2C_IOCTL_READ_WRITE\r\n");
+#endif
+ const rtems_libi2c_read_write_t *cmd = (const rtems_libi2c_read_write_t *)arg;
+
+ ret_val = beagle_spi_read_write_bytes(
+ bh,
+ (unsigned char *)cmd->rd_buf,
+ (unsigned char *)cmd->wr_buf,
+ cmd->byte_cnt
+ );
+ break;
+ }
+ default:
+ ret_val = -RTEMS_NOT_DEFINED;
+ break;
+ }
+
+#if defined(DEBUG)
+ printk("beagle_spi_ioctl done\r\n");
+#endif
+
+ return ret_val;
+}
+
+/*=========================================================================*\
+| Board-specific adaptation functions |
+\*=========================================================================*/
+
+/*
+ * Address a slave device on the bus
+ *
+ * Returns: o = ok or error code
+ */
+static rtems_status_code bsp_spi_sel_addr
+(
+ rtems_libi2c_bus_t *bh, /* bus specifier structure */
+ uint32_t addr, /* address to send on bus */
+ int rw /* 0=write,1=read */
+)
+{
+ if (addr != 0)
+ return RTEMS_NOT_IMPLEMENTED;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Dummy function, SPI has no start condition
+ *
+ * Returns: o = ok or error code
+ */
+static rtems_status_code bsp_spi_send_start_dummy
+(
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+)
+{
+#if defined(DEBUG)
+ printk("bsp_spi_send_start_dummy OK\r\n");
+#endif
+
+ return 0;
+}
+
+/*
+ * Deselect SPI
+ *
+ * Returns: o = ok or error code
+ */
+static rtems_status_code bsp_spi_send_stop
+(
+ rtems_libi2c_bus_t *bh /* bus specifier structure */
+)
+{
+#if defined(DEBUG)
+ printk("bsp_spi_send_stop called... ");
+#endif
+
+ // FIXME
+
+#if defined(DEBUG)
+ printk("... exit OK\r\n");
+#endif
+ return 0;
+}
+
+/*=========================================================================*\
+| list of handlers |
+\*=========================================================================*/
+
+rtems_libi2c_bus_ops_t bsp_spi_ops = {
+ init: beagle_spi_init,
+ send_start: bsp_spi_send_start_dummy,
+ send_stop: bsp_spi_send_stop,
+ send_addr: bsp_spi_sel_addr,
+ read_bytes: beagle_spi_read_bytes,
+ write_bytes: beagle_spi_write_bytes,
+ ioctl: beagle_spi_ioctl
+};
+
+static beagle_spi_desc_t bsp_spi_bus_desc = {
+ {/* public fields */
+ ops: &bsp_spi_ops,
+ size: sizeof(bsp_spi_bus_desc)
+ },
+ { /* our private fields */
+ initialized: FALSE,
+ }
+};
+
+/*=========================================================================*\
+| initialization |
+\*=========================================================================*/
+
+/*
+ * Register SPI bus and devices
+ *
+ * Returns: Bus number or error code
+ */
+rtems_status_code bsp_register_spi
+(
+ const char *bus_path,
+ uintptr_t register_base,
+ rtems_vector_number irq
+)
+{
+ int ret_code;
+ int spi_busno;
+
+ beagle_spi_softc_t *softc_ptr = &bsp_spi_bus_desc.softc;
+
+ if (softc_ptr->initialized) {
+ printk("ERROR: Only one SPI bus at a time is supported\n");
+ return -RTEMS_RESOURCE_IN_USE;
+ }
+
+ softc_ptr->regs_base = register_base;
+ softc_ptr->irq = irq;
+
+ /*
+ * init I2C library (if not already done)
+ */
+ rtems_libi2c_initialize();
+
+ /*
+ * register SPI bus
+ */
+ ret_code = rtems_libi2c_register_bus(bus_path,
+ &(bsp_spi_bus_desc.bus_desc));
+ if (ret_code < 0) {
+ return -ret_code;
+ }
+ spi_busno = ret_code;
+
+#if IS_AM335X
+ // TODO: register board devices
+#endif
+
+ return spi_busno;
+}
diff --git a/bsps/arm/include/libcpu/am335x.h b/bsps/arm/include/libcpu/am335x.h
index 367e97cae9..a78cbd028d 100644
--- a/bsps/arm/include/libcpu/am335x.h
+++ b/bsps/arm/include/libcpu/am335x.h
@@ -19,6 +19,9 @@
#if !defined(_AM335X_H_)
#define _AM335X_H_
+#define AM335X_MASK(Shift, Width) (((1 << (Width)) - 1) << (Shift))
+
+
/* Interrupt controller memory map */
#define OMAP3_DM37XX_INTR_BASE 0x48200000 /* INTCPS physical address */
@@ -649,6 +652,9 @@
#define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK (0x00000100u)
#define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_I2C_FCLK (0x01000000u)
#define AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE (0x00000003u)
+#define AM335X_CM_PER_SPI0_CLKCTRL (0x4c)
+#define AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE (0x2u)
+#define AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE (0x00000003u)
#define AM335X_I2C_CON_XSA (0x00000100u)
#define AM335X_I2C_CFG_10BIT_SLAVE_ADDR AM335X_I2C_CON_XSA
#define AM335X_I2C_CON_XSA_SHIFT (0x00000008u)
@@ -660,7 +666,6 @@
#define AM335X_I2C_SYSC_AUTOIDLE (0x00000001u)
/*I2C0 module clock registers*/
-
#define AM335X_CM_WKUP_CONTROL_CLKCTRL (0x4)
#define AM335X_CM_WKUP_CLKSTCTRL (0x0)
#define AM335X_CM_WKUP_I2C0_CLKCTRL (0xb8)
@@ -675,6 +680,12 @@
#define AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST (0x00030000u)
#define AM335X_SOC_CM_WKUP_REGS (AM335X_CM_PER_ADDR + 0x400)
+/* SPI0 module clock registers */
+#define AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_FUNC (0x0u)
+#define AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_SHIFT (0x00000010u)
+#define AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST (0x00030000u)
+
+
/* I2C status Register */
#define AM335X_I2C_IRQSTATUS_NACK (1 << 1)
#define AM335X_I2C_IRQSTATUS_ROVR (1 << 11)
@@ -701,4 +712,84 @@
#define AM335X_CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK (0x00000020u)
#define AM335X_I2C_INT_STOP_CONDITION AM335X_I2C_IRQSTATUS_BF
+
+/* SPI registers */
+#define AM335X_SPI0_BASE 0x48030000
+ /* SPI0 base address */
+#define AM335X_SPI1_BASE 0x481A0000
+ /* SPI1 base address */
+
+#define AM335X_SPI_REVISION 0x000
+#define AM335X_SPI_SYSCONFIG 0x110
+#define AM335X_SPI_SYSSTATUS 0x114
+#define AM335X_SPI_IRQSTATUS 0x118
+#define AM335X_SPI_IRQENABLE 0x11c
+#define AM335X_SPI_WAKEUPENABLE 0x120
+#define AM335X_SPI_SYST 0x124
+#define AM335X_SPI_MODULCTRL 0x128
+#define AM335X_SPI_CH0CONF 0x12c
+#define AM335X_SPI_CH0STAT 0x130
+#define AM335X_SPI_CH0CTRL 0x134
+#define AM335X_SPI_TX0 0x138
+#define AM335X_SPI_RX0 0x13C
+#define AM335X_SPI_XFERLEVEL 0x17c
+
+/* SPI sysconfig Register */
+#define AM335X_SPI_SYSCONFIG_SOFTRESET (1 << 1)
+
+/* SPI sysstatus Register */
+#define AM335X_SPI_SYSSTATUS_RESETDONE (1 << 0)
+
+/* SPI interrupt status Register */
+#define AM335X_SPI_IRQSTATUS_TX0_EMPTY (1 << 0)
+#define AM335X_SPI_IRQSTATUS_RX0_FULL (1 << 2)
+
+/* SPI interrupt enable Register */
+#define AM335X_SPI_IRQENABLE_TX0_EMPTY (1 << 0)
+#define AM335X_SPI_IRQENABLE_RX0_FULL (1 << 2)
+
+/* SPI system Register */
+#define AM335X_SPI_SYST_SPIEN_0 (1 << 0)
+#define AM335X_SPI_SYST_SPIDAT_0 (1 << 4)
+#define AM335X_SPI_SYST_SPIDAT_1 (1 << 5)
+#define AM335X_SPI_SYST_SPIDATDIR0 (1 << 8)
+#define AM335X_SPI_SYST_SPIDATDIR1 (1 << 9)
+#define AM335X_SPI_SYST_SSB (1 << 11)
+
+/* SPI modulctrl Register */
+#define AM335X_SPI_MODULCTRL_SINGLE (1 << 0)
+#define AM335X_SPI_MODULCTRL_PIN34 (1 << 1)
+#define AM335X_SPI_MODULCTRL_MS (1 << 2)
+
+/* SPI Channel 0 Configuration Register */
+#define AM335X_SPI_CH0CONF_PHA (1 << 0)
+#define AM335X_SPI_CH0CONF_POL (1 << 1)
+#define AM335X_SPI_CH0CONF_CLKD_SHIFT 2
+#define AM335X_SPI_CH0CONF_CLKD_WIDTH 4
+#define AM335X_SPI_CH0CONF_CLKD_MASK AM335X_MASK(AM335X_SPI_CH0CONF_CLKD_SHIFT, AM335X_SPI_CH0CONF_CLKD_WIDTH)
+#define AM335X_SPI_CH0CONF_CLKD(X) (((X) << AM335X_SPI_CH0CONF_CLKD_SHIFT) & AM335X_SPI_CH0CONF_CLKD_MASK)
+#define AM335X_SPI_CH0CONF_EPOL (1 << 6)
+#define AM335X_SPI_CH0CONF_WL_SHIFT 7
+#define AM335X_SPI_CH0CONF_WL_WIDTH 5
+#define AM335X_SPI_CH0CONF_WL_MASK AM335X_MASK(AM335X_SPI_CH0CONF_WL_SHIFT, AM335X_SPI_CH0CONF_WL_WIDTH)
+#define AM335X_SPI_CH0CONF_WL(X) (((X) << AM335X_SPI_CH0CONF_WL_SHIFT) & AM335X_SPI_CH0CONF_WL_MASK)
+#define AM335X_SPI_CH0CONF_TRM_SHIFT 12
+#define AM335X_SPI_CH0CONF_TRM_WIDTH 2
+#define AM335X_SPI_CH0CONF_TRM_MASK AM335X_MASK(AM335X_SPI_CH0CONF_TRM_SHIFT, AM335X_SPI_CH0CONF_TRM_WIDTH)
+#define AM335X_SPI_CH0CONF_TRM(X) (((X) << AM335X_SPI_CH0CONF_TRM_SHIFT) & AM335X_SPI_CH0CONF_TRM_MASK)
+#define AM335X_SPI_CH0CONF_DPE0 (1 << 16)
+#define AM335X_SPI_CH0CONF_DPE1 (1 << 17)
+#define AM335X_SPI_CH0CONF_IS (1 << 18)
+#define AM335X_SPI_CH0CONF_FORCE (1 << 20)
+#define AM335X_SPI_CH0CONF_SBPOL (1 << 27)
+#define AM335X_SPI_CH0CONF_FFEW (1 << 27)
+#define AM335X_SPI_CH0CONF_FFER (1 << 28)
+
+/* SPI Channel 0 Status Register */
+#define AM335X_SPI_CH0STAT_RXS (1 << 0)
+#define AM335X_SPI_CH0STAT_TXS (1 << 1)
+
+/* SPI Channel 0 Control Register */
+#define AM335X_SPI_CH0CTRL_EN (1 << 0)
+
#endif
diff --git a/c/src/lib/libbsp/arm/beagle/Makefile.am b/c/src/lib/libbsp/arm/beagle/Makefile.am
index acab25c52f..332536c428 100644
--- a/c/src/lib/libbsp/arm/beagle/Makefile.am
+++ b/c/src/lib/libbsp/arm/beagle/Makefile.am
@@ -70,6 +70,9 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/console/console-confi
# I2C
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/i2c/bbb-i2c.c
+# SPI
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/spi/spi.c
+
# GPIO
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/gpio/bbb-gpio.c
--
2.17.2 (Apple Git-113)
More information about the devel
mailing list