1
0
Эх сурвалжийг харах

[Bsp][Tina]Add spi driver

zyh 7 жил өмнө
parent
commit
39558535f2

+ 16 - 1
bsp/allwinner_tina/drivers/Kconfig

@@ -19,4 +19,19 @@ config TINA_USING_SDIO0
     bool "Using SDIO0"
     select RT_USING_SDIO
     default y
-    
+
+config TINA_USING_SPI0
+    bool "Using spi0"
+    select RT_USING_SPI
+    default y
+
+config TINA_USING_SPI1
+    bool "Using spi1"
+    select RT_USING_SPI
+    default y
+
+config TINA_USING_SPI_FLASH
+    bool "Using flash"
+    select TINA_USING_SPI0
+    select RT_USING_SFUD
+    default y

+ 9 - 0
bsp/allwinner_tina/drivers/spi/SConscript

@@ -0,0 +1,9 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+CPPPATH = [cwd, str(Dir('#'))]
+
+group = DefineGroup('spi', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 793 - 0
bsp/allwinner_tina/drivers/spi/drv_spi.c

@@ -0,0 +1,793 @@
+/*
+ * File      : drv_spi.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2017, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2017-08-30     tanek        first implementation.
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include <rtdevice.h>
+#include <stdbool.h>
+
+#include "drv_spi.h"
+#include "drv_gpio.h"
+#include "drv_clock.h"
+
+#define SPI_BUS_MAX_CLK    (30 * 1000 * 1000)
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME  "[SPI]"
+#define DBG_LEVEL         DBG_WARNING
+#define DBG_COLOR
+#include <rtdbg.h>
+
+#ifdef RT_USING_SPI
+
+//#define DEBUG
+
+#define ARR_LEN(__N)      (sizeof(__N) / sizeof(__N[0]))
+
+#ifdef DEBUG
+#define DEBUG_PRINTF(...)   rt_kprintf(__VA_ARGS__)
+#else
+#define DEBUG_PRINTF(...)
+#endif
+
+
+#define __SPI_STATIC_INLINE__ rt_inline
+
+/*
+ * @brief Hardware Layer Interface
+ */
+__SPI_STATIC_INLINE__
+rt_uint32_t SPI_GetVersion(SPI_T *spi)
+{
+    return spi->VER;
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_Reset(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->CTRL, SPI_CTRL_RST_MASK);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetMode(SPI_T *spi, SPI_CTRL_Mode mode)
+{
+    HAL_MODIFY_REG(spi->CTRL, SPI_CTRL_MODE_MASK, mode);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_Enable(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->CTRL, SPI_CTRL_EN_MASK);
+}
+
+__SPI_STATIC_INLINE__
+void SPI_Disable(SPI_T *spi)
+{
+    HAL_CLR_BIT(spi->CTRL, SPI_CTRL_EN_MASK);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_StartTransmit(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->TCTRL, SPI_TCTRL_XCH_MASK);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetFirstTransmitBit(SPI_T *spi, SPI_TCTRL_Fbs bit)
+{
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_FBS_MASK, bit);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_EnableRapidsMode(SPI_T *spi, bool delay_sample)
+{
+    HAL_SET_BIT(spi->TCTRL, SPI_TCTRL_RPSM_MASK);
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_SDC_MASK, delay_sample << SPI_TCTRL_SDC_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_DisableRapidsMode(SPI_T *spi)
+{
+    HAL_CLR_BIT(spi->TCTRL, SPI_TCTRL_RPSM_MASK);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetDuplex(SPI_T *spi, SPI_TCTRL_DHB_Duplex duplex)
+{
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_DHB_MASK, duplex);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetCsLevel(SPI_T *spi,  bool level)
+{
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_SS_LEVEL_MASK, level << SPI_TCTRL_SS_LEVEL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_ManualChipSelect(SPI_T *spi, SPI_TCTRL_SS_Sel cs)
+{
+    HAL_SET_BIT(spi->TCTRL, SPI_TCTRL_SS_OWNER_MASK);
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_SS_SEL_MASK, cs);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_AutoChipSelect(SPI_T *spi, SPI_TCTRL_SS_Sel cs, bool cs_remain)
+{
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_SS_SEL_MASK, cs);
+    HAL_CLR_BIT(spi->TCTRL, SPI_TCTRL_SS_OWNER_MASK);
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_SS_CTL_MASK, (!cs_remain) << SPI_TCTRL_SS_CTL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetCsIdle(SPI_T *spi, bool idle)
+{
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_SPOL_MASK, (!!idle) << SPI_TCTRL_SPOL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetSclkMode(SPI_T *spi, SPI_SCLK_Mode mode)
+{
+    HAL_MODIFY_REG(spi->TCTRL, SPI_TCTRL_CPOL_MASK | SPI_TCTRL_CPHA_MASK, mode);
+}
+
+typedef enum
+{
+    SPI_INT_CS_DESELECT = SPI_IER_SS_INT_EN_MASK,
+    SPI_INT_TRANSFER_COMPLETE = SPI_IER_TC_INT_EN_MASK,
+    SPI_INT_TXFIFO_UNDER_RUN = SPI_IER_TF_UDR_INT_EN_MASK,
+    SPI_INT_TXFIFO_OVERFLOW = SPI_IER_TF_OVF_INT_EN_MASK,
+    SPI_INT_RXFIFO_UNDER_RUN = SPI_IER_RF_UDR_INT_EN_MASK,
+    SPI_INT_RXFIFO_OVERFLOW = SPI_IER_RF_OVF_INT_EN_MASK,
+    SPI_INT_TXFIFO_FULL = SPI_IER_TF_FUL_INT_EN_MASK,
+    SPI_INT_TXFIFO_EMPTY = SPI_IER_TX_EMP_INT_EN_MASK,
+    SPI_INT_TXFIFO_READY = SPI_IER_TX_ERQ_INT_EN_MASK,
+    SPI_INT_RXFIFO_FULL = SPI_IER_RF_FUL_INT_EN_MASK,
+    SPI_INT_RXFIFO_EMPTY = SPI_IER_RX_EMP_INT_EN_MASK,
+    SPI_INT_RXFIFO_READY = SPI_IER_RF_RDY_INT_EN_MASK
+} SPI_Int_Type;
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_EnableInt(SPI_T *spi, SPI_Int_Type type)
+{
+    HAL_SET_BIT(spi->IER, type);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_DisableInt(SPI_T *spi, SPI_Int_Type type)
+{
+    HAL_CLR_BIT(spi->IER, type);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+bool SPI_IntState(SPI_T *spi, SPI_Int_Type type)
+{
+    return !!HAL_GET_BIT(spi->STA, type);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+bool SPI_ClearInt(SPI_T *spi, SPI_Int_Type type)
+{
+    HAL_SET_BIT(spi->STA, type);
+    return HAL_GET_BIT(spi->STA, type);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_DebugReadTx(SPI_T *spi, rt_uint32_t *data)
+{
+    // tbc...
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_DebugWriteRx(SPI_T *spi, rt_uint32_t *data)
+{
+    // tbc...
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_ResetTxFifo(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->FCTL, SPI_FCTL_TF_RST_MASK);
+    while (HAL_GET_BIT(spi->FCTL, SPI_FCTL_TF_RST_MASK) != 0);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_ResetRxFifo(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->FCTL, SPI_FCTL_RF_RST_MASK);
+    while (HAL_GET_BIT(spi->FCTL, SPI_FCTL_RF_RST_MASK) != 0);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_DMA(SPI_T *spi, bool txEn, bool rxEn)
+{
+    HAL_MODIFY_REG(spi->FCTL,
+                   SPI_FCTL_TF_DRQ_EN_MASK | SPI_FCTL_RF_DRQ_EN_MASK,
+                   ((!!txEn) << SPI_FCTL_TF_DRQ_EN_SHIFT) | ((!!rxEn) << SPI_FCTL_RF_DRQ_EN_SHIFT));
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetTxFifoThreshold(SPI_T *spi, uint8_t threshold)
+{
+    HAL_MODIFY_REG(spi->FCTL, SPI_FCTL_TX_TRIG_LEVEL_MASK, threshold << SPI_FCTL_TX_TRIG_LEVEL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetRxFifoThreshold(SPI_T *spi, uint8_t threshold)
+{
+    HAL_MODIFY_REG(spi->FCTL, SPI_FCTL_RX_TRIG_LEVEL_MASK, threshold << SPI_FCTL_RX_TRIG_LEVEL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+uint8_t SPI_GetTxFifoCounter(SPI_T *spi)
+{
+    return (uint8_t)((spi->FST & SPI_FST_TF_CNT_MASK) >> SPI_FST_TF_CNT_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+uint8_t SPI_GetRxFifoCounter(SPI_T *spi)
+{
+    return (uint8_t)((spi->FST & SPI_FST_RF_CNT_MASK) >> SPI_FST_RF_CNT_SHIFT);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_EnableDualMode(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->BCC, SPI_BCC_DRM_MASK);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_DisableDualMode(SPI_T *spi)
+{
+    HAL_CLR_BIT(spi->BCC, SPI_BCC_DRM_MASK);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetInterval(SPI_T *spi, uint16_t nSCLK)
+{
+    HAL_MODIFY_REG(spi->WAIT, SPI_WAIT_WCC_MASK, nSCLK << SPI_WAIT_WCC_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static void SPI_SetClkDiv(SPI_T *spi, uint16_t div)
+{
+    uint8_t n = 0;
+    if (div < 1)
+    {
+        return;
+    }
+
+    if (div > 2 * (0xFF + 1))
+    {
+        HAL_CLR_BIT(spi->CCTR, SPI_CCTR_DRS_MASK);
+        do
+        {
+            div = (div == 1) ? 0 : ((div + 1) / 2);
+            n++;
+        }
+        while (div);
+
+        HAL_MODIFY_REG(spi->CCTR, SPI_CCTR_CDR1_MASK, (n & 0x0F) << SPI_CCTR_CDR1_SHIFT);
+    }
+    else
+    {
+        HAL_SET_BIT(spi->CCTR, SPI_CCTR_DRS_MASK);
+        n = ((div + 1) / 2) - 1;
+        HAL_MODIFY_REG(spi->CCTR, SPI_CCTR_CDR2_MASK, (n & 0xFF) << SPI_CCTR_CDR2_SHIFT);
+    }
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_SetDataSize(SPI_T *spi, rt_uint32_t data_size, rt_uint32_t dummy_size)
+{
+    HAL_MODIFY_REG(spi->BC, SPI_BC_MBC_MASK, data_size + dummy_size);
+    HAL_MODIFY_REG(spi->TC, SPI_TC_MWTC_MASK, data_size);
+    HAL_MODIFY_REG(spi->BCC, SPI_BCC_STC_MASK, data_size);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_Write(SPI_T *spi, uint8_t *data)
+{
+    HAL_REG_8BIT(&spi->TXD) = *data;
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+void SPI_Read(SPI_T *spi, uint8_t *data)
+{
+    *data = HAL_REG_8BIT(&spi->RXD);
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+uint8_t *SPI_TxAddress(SPI_T *spi)
+{
+    return (uint8_t *)&spi->TXD;
+}
+
+/*
+ * @brief
+ */
+__SPI_STATIC_INLINE__
+uint8_t *SPI_RxAddress(SPI_T *spi)
+{
+    return (uint8_t *)&spi->RXD;
+}
+
+/* private rt-thread spi ops function */
+static rt_err_t configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
+static rt_uint32_t xfer(struct rt_spi_device *device, struct rt_spi_message *message);
+
+static struct rt_spi_ops tina_spi_ops =
+{
+    configure,
+    xfer
+};
+
+static rt_err_t configure(struct rt_spi_device *device,
+                          struct rt_spi_configuration *configuration)
+{
+    struct rt_spi_bus *spi_bus = (struct rt_spi_bus *)device->bus;
+    struct tina_spi_cs *tina_spi_cs = device->parent.user_data;
+    struct tina_spi *_spi_info = (struct tina_spi *)spi_bus->parent.user_data;
+    SPI_T *spi = _spi_info->spi;
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+    RT_ASSERT(device != RT_NULL);
+    RT_ASSERT(configuration != RT_NULL);
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+    DEBUG_PRINTF("spi address: %08X\n", (rt_uint32_t)spi);
+
+    SPI_Disable(spi);
+    SPI_Reset(spi);
+    SPI_ResetRxFifo(spi);
+    SPI_ResetTxFifo(spi);
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+    /* data_width */
+    if (configuration->data_width != 8)
+    {
+        DEBUG_PRINTF("error: data_width is %d\n", configuration->data_width);
+        return RT_EIO;
+    }
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+    SPI_SetDuplex(spi, SPI_TCTRL_DHB_FULL_DUPLEX);
+    SPI_SetMode(spi, SPI_CTRL_MODE_MASTER);
+
+    /* MSB or LSB */
+    if (configuration->mode & RT_SPI_MSB)
+    {
+        SPI_SetFirstTransmitBit(spi, SPI_TCTRL_FBS_MSB);
+    }
+    else
+    {
+        SPI_SetFirstTransmitBit(spi, SPI_TCTRL_FBS_LSB);
+    }
+
+    switch (configuration->mode)
+    {
+    case RT_SPI_MODE_0:
+        SPI_SetSclkMode(spi, SPI_SCLK_Mode0);
+        break;
+    case RT_SPI_MODE_1:
+        SPI_SetSclkMode(spi, SPI_SCLK_Mode1);
+        break;
+    case RT_SPI_MODE_2:
+        SPI_SetSclkMode(spi, SPI_SCLK_Mode2);
+        break;
+    case RT_SPI_MODE_3:
+        SPI_SetSclkMode(spi, SPI_SCLK_Mode3);
+        break;
+    }
+
+    /* baudrate */
+    {
+        unsigned int spi_clock = 0;
+        rt_uint32_t max_hz;
+        rt_uint32_t div;
+
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+        max_hz = configuration->max_hz;
+
+        if (max_hz > SPI_BUS_MAX_CLK)
+        {
+            max_hz = SPI_BUS_MAX_CLK;
+        }
+        spi_clock = ahb_get_clk();
+
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+        div = (spi_clock + max_hz - 1) / max_hz;
+
+        dbg_log(DBG_LOG, "configuration->max_hz: %d\n", configuration->max_hz);
+        dbg_log(DBG_LOG, "max freq: %d\n", max_hz);
+        dbg_log(DBG_LOG, "spi_clock: %d\n", spi_clock);
+        dbg_log(DBG_LOG, "div: %d\n", div);
+
+        SPI_SetClkDiv(spi, div / 2);
+    } /* baudrate */
+
+    SPI_ManualChipSelect(spi, tina_spi_cs->cs);
+    SPI_SetDataSize(spi, 0, 0);
+    SPI_Enable(spi);
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+    return RT_EOK;
+};
+
+static rt_uint32_t xfer(struct rt_spi_device *device, struct rt_spi_message *message)
+{
+    struct rt_spi_bus *r6_spi_bus = (struct rt_spi_bus *)device->bus;
+    struct tina_spi *_spi_info = (struct tina_spi *)r6_spi_bus->parent.user_data;
+    SPI_T *spi = _spi_info->spi;
+    struct rt_spi_configuration *config = &device->config;
+    struct tina_spi_cs *tina_spi_cs = device->parent.user_data;
+
+    RT_ASSERT(device != NULL);
+    RT_ASSERT(message != NULL);
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+    DEBUG_PRINTF("spi_info: %08X\n", (rt_uint32_t)_spi_info);
+    DEBUG_PRINTF("spi address: %08X\n", (rt_uint32_t)spi);
+
+    /* take CS */
+    if (message->cs_take)
+    {
+        SPI_ManualChipSelect(spi, tina_spi_cs->cs);
+        SPI_SetCsLevel(spi, false);
+        DEBUG_PRINTF("spi take cs\n");
+    }
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+    {
+        if ((config->data_width <= 8) && (message->length > 0))
+        {
+            const rt_uint8_t *send_ptr = message->send_buf;
+            rt_uint8_t *recv_ptr = message->recv_buf;
+            rt_uint32_t tx_size = message->length;
+            rt_uint32_t rx_size = message->length;
+
+            DEBUG_PRINTF("spi poll transfer start: %d\n", tx_size);
+
+            SPI_ResetTxFifo(spi);
+            SPI_ResetRxFifo(spi);
+            SPI_SetDataSize(spi, tx_size, 0);
+
+            SPI_StartTransmit(spi);
+
+            DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+            while (tx_size > 0 || rx_size > 0)
+            {
+                uint8_t tx_data = 0xFF;
+                uint8_t rx_data = 0xFF;
+
+                while ((SPI_GetTxFifoCounter(spi) < SPI_FIFO_SIZE) && (tx_size > 0))
+                {
+                    if (send_ptr != RT_NULL)
+                    {
+                        tx_data = *send_ptr++;
+                    }
+                    SPI_Write(spi, &tx_data);
+                    tx_size--;
+                }
+
+                while (SPI_GetRxFifoCounter(spi) > 0)
+                {
+                    rx_size--;
+                    SPI_Read(spi, &rx_data);
+
+                    if (recv_ptr != RT_NULL)
+                    {
+                        *recv_ptr++ = rx_data;
+                    }
+                }
+            }
+
+            DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+            if ((tx_size != 0) || (rx_size != 0))
+            {
+                DEBUG_PRINTF("spi_tx_rx error with tx count = %d, rx count = %d.\n", tx_size, rx_size);
+
+                return 0;
+            }
+
+            DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+            while (SPI_IntState(spi, SPI_INT_TRANSFER_COMPLETE) == 0);
+            SPI_ClearInt(spi, SPI_INT_TRANSFER_COMPLETE);
+
+            DEBUG_PRINTF("spi poll transfer finsh\n");
+        }
+        else if (config->data_width > 8)
+        {
+            DEBUG_PRINTF("data width: %d\n", config->data_width);
+            RT_ASSERT(NULL);
+        }
+    }
+
+    /* release CS */
+    if (message->cs_release)
+    {
+        SPI_SetCsLevel(spi, true);
+        DEBUG_PRINTF("spi release cs\n");
+    }
+
+    return message->length;
+};
+
+#ifdef TINA_USING_SPI0
+static struct rt_spi_bus spi_bus0;
+#endif
+
+#ifdef TINA_USING_SPI1
+static struct rt_spi_bus spi_bus1;
+#endif
+
+static const struct tina_spi spis[] =
+{
+#ifdef TINA_USING_SPI0
+    {(SPI_T *)SPI0_BASE_ADDR, SPI0_GATING, &spi_bus0},
+#endif
+
+#ifdef TINA_USING_SPI1
+    {(SPI_T *)SPI1_BASE_ADDR, SPI1_GATING, &spi_bus1},
+#endif
+};
+
+
+
+/** \brief init and register r6 spi bus.
+ *
+ * \param SPI: R6 SPI, e.g: SPI1,SPI2,SPI3.
+ * \param spi_bus_name: spi bus name, e.g: "spi1"
+ * \return
+ *
+ */
+rt_err_t tina_spi_bus_register(SPI_T *spi, const char *spi_bus_name)
+{
+    int i;
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+    RT_ASSERT(spi_bus_name != RT_NULL);
+
+    for (i = 0; i < ARR_LEN(spis); i++)
+    {
+        if (spi == spis[i].spi)
+        {
+            bus_software_reset_disalbe(spis[i].spi_gate);
+            bus_gate_clk_enalbe(spis[i].spi_gate);
+
+            spis[i].spi_bus->parent.user_data = (void *)&spis[i];
+            DEBUG_PRINTF("bus  addr: %08X\n", (rt_uint32_t)spis[i].spi_bus);
+            DEBUG_PRINTF("user_data: %08X\n", (rt_uint32_t)spis[i].spi_bus->parent.user_data);
+            DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+            rt_spi_bus_register(spis[i].spi_bus, spi_bus_name, &tina_spi_ops);
+            DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+            return RT_EOK;
+        }
+    }
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+    return RT_ERROR;
+}
+
+int rt_hw_spi_init(void)
+{
+    DEBUG_PRINTF("register spi bus\n");
+
+#ifdef TINA_USING_SPI0
+    /* register spi bus */
+    {
+        rt_err_t result;
+
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+        gpio_set_func(GPIO_PORT_C, GPIO_PIN_0, IO_FUN_1);
+        gpio_set_func(GPIO_PORT_C, GPIO_PIN_2, IO_FUN_1);
+        gpio_set_func(GPIO_PORT_C, GPIO_PIN_3, IO_FUN_1);
+
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+
+        result = tina_spi_bus_register((SPI_T *)SPI0_BASE_ADDR, "spi0");
+        if (result != RT_EOK)
+        {
+            DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+            return result;
+        }
+    }
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+    /* attach cs */
+    {
+        static struct rt_spi_device spi_device;
+        static struct tina_spi_cs  spi_cs;
+        rt_err_t result;
+
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+        spi_cs.cs = SPI_TCTRL_SS_SEL_SS0;
+
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+        gpio_set_func(GPIO_PORT_C, GPIO_PIN_1, IO_FUN_1);
+
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+        result = rt_spi_bus_attach_device(&spi_device, "spi00", "spi0", (void *)&spi_cs);
+        if (result != RT_EOK)
+        {
+            DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+            return result;
+        }
+    }
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+#endif
+
+#ifdef TINA_USING_SPI1
+    /* register spi bus */
+    {
+        rt_err_t result;
+
+        gpio_set_func(GPIO_PORT_A, GPIO_PIN_1,  IO_FUN_5);
+        gpio_set_func(GPIO_PORT_A, GPIO_PIN_2,  IO_FUN_5);
+        gpio_set_func(GPIO_PORT_A, GPIO_PIN_3, IO_FUN_5);
+
+        result = tina_spi_bus_register((SPI_T *)SPI1_BASE_ADDR, "spi1");
+        if (result != RT_EOK)
+        {
+            DEBUG_PRINTF("register spi bus faild: %d\n", result);
+            return result;
+        }
+    }
+
+    DEBUG_PRINTF("attach cs\n");
+    /* attach cs */
+    {
+        static struct rt_spi_device spi_device;
+        static struct tina_spi_cs spi_cs;
+        rt_err_t result;
+
+        spi_cs.cs = SPI_TCTRL_SS_SEL_SS0;
+        gpio_set_func(GPIO_PORT_A, GPIO_PIN_0,  IO_FUN_5);
+
+        result = rt_spi_bus_attach_device(&spi_device, "spi10", "spi1", (void *)&spi_cs);
+        if (result != RT_EOK)
+        {
+            DEBUG_PRINTF("attach cs faild: %d\n", result);
+            return result;
+        }
+    }
+#endif
+
+    return RT_EOK;
+}
+INIT_BOARD_EXPORT(rt_hw_spi_init);
+#endif

+ 428 - 0
bsp/allwinner_tina/drivers/spi/drv_spi.h

@@ -0,0 +1,428 @@
+/*
+ * File      : drv_spi.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2017, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-02-08     RT-Thread    the first version
+ */
+
+#ifndef __DRV_SPI_H__
+#define __DRV_SPI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/********************** private ************************************/
+
+#define SPI0_BASE_ADDR     (0x01C05000)
+#define SPI1_BASE_ADDR     (0x01C06000)
+
+/**
+  * @brief Serial Peripheral Interface
+  */
+typedef struct
+{
+    volatile rt_uint32_t VER;               /* SPI Version number Register,                          Address offset: 0x00   */
+    volatile rt_uint32_t CTRL;              /* SPI Global Control Register,                          Address offset: 0x04   */
+    volatile rt_uint32_t TCTRL;             /* SPI Transfer Control Register,                        Address offset: 0x08   */
+    volatile rt_uint32_t RESERVED1[1];      /* Reserved, 0x0C                                                               */
+    volatile rt_uint32_t IER;               /* SPI Interrupt Control Register,                       Address offset: 0x10   */
+    volatile rt_uint32_t STA;               /* SPI Interrupt Status Register,                        Address offset: 0x14   */
+    volatile rt_uint32_t FCTL;              /* SPI FIFO Control Register,                            Address offset: 0x18   */
+    volatile rt_uint32_t FST;               /* SPI FIFO Status Register,                             Address offset: 0x1C   */
+    volatile rt_uint32_t WAIT;              /* SPI Wait Clock Counter Register,                      Address offset: 0x20   */
+    volatile rt_uint32_t CCTR;              /* SPI Clock Rate Control Register,                      Address offset: 0x24   */
+    volatile rt_uint32_t RESERVED2[2];      /* Reserved, 0x28-0x2C                                                          */
+    volatile rt_uint32_t BC;                /* SPI Master mode Burst Control Register,               Address offset: 0x30   */
+    volatile rt_uint32_t TC;                /* SPI Master mode Transmit Counter Register,            Address offset: 0x34   */
+    volatile rt_uint32_t BCC;               /* SPI Burst Control Register,                           Address offset: 0x38   */
+    volatile rt_uint32_t RESERVED3[19];     /* Reserved, 0x3C-0x84                                                          */
+    volatile rt_uint32_t NDMA_MODE_CTRL;    /* SPI Nomal DMA Mode Control Regist                     Address offset: 0x88   */
+    volatile rt_uint32_t RESERVED4[93];     /* Reserved, 0x8C-0x1FC                                                         */
+    volatile rt_uint32_t TXD;               /* SPI TX Date Register,                                 Address offset: 0x200  */
+    volatile rt_uint32_t RESERVED5[63];     /* Reserved, 0x204-0x2FC                                                        */
+    volatile rt_uint32_t RXD;               /* SPI RX Date Register,                                 Address offset: 0x300  */
+} SPI_T;
+
+/*
+ * @brief SPI Global Control Register
+ */
+#define SPI_CTRL_RST_SHIFT                  (31)
+#define SPI_CTRL_RST_MASK                   (0x1U << SPI_CTRL_RST_SHIFT)
+
+#define SPI_CTRL_TP_EN_SHIFT                (7)
+#define SPI_CTRL_TP_EN_MASK                 (0x1U << SPI_CTRL_TP_EN_SHIFT)
+
+#define SPI_CTRL_MODE_SHIFT                 (1)
+#define SPI_CTRL_MODE_MASK                  (0x1U << SPI_CTRL_MODE_SHIFT)
+typedef enum
+{
+    SPI_CTRL_MODE_SLAVE = 0 << SPI_CTRL_MODE_SHIFT,
+    SPI_CTRL_MODE_MASTER = 1 << SPI_CTRL_MODE_SHIFT
+} SPI_CTRL_Mode;
+
+#define SPI_CTRL_EN_SHIFT                   (0)
+#define SPI_CTRL_EN_MASK                    (0x1U << SPI_CTRL_EN_SHIFT)
+typedef enum
+{
+    SPI_CTRL_EN_DISABLE = 0 << SPI_CTRL_EN_SHIFT,
+    SPI_CTRL_EN_ENABLE = 1 << SPI_CTRL_EN_SHIFT
+} SPI_CTRL_En;
+
+/*
+ * @brief SPI Transfer Control Register
+ */
+#define SPI_TCTRL_XCH_SHIFT                 (31)
+#define SPI_TCTRL_XCH_MASK                  (0x1U << SPI_TCTRL_XCH_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_XCH_IDLE = 0 << SPI_TCTRL_XCH_SHIFT,
+    SPI_TCTRL_XCH_START = 1 << SPI_TCTRL_XCH_SHIFT
+} SPI_TCTRL_Xch;
+
+#define SPI_TCTRL_SDDM_SHIFT                (14)
+#define SPI_TCTRL_SDDM_MASK                 (0x0U << SPI_TCTRL_SDDM_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_SDDM_SEND_NODELAY = 0 << SPI_TCTRL_SDDM_SHIFT,
+    SPI_TCTRL_SDDM_SEND_DELAY = 1 << SPI_TCTRL_SDDM_SHIFT
+} SPI_TCTRL_Sddm;
+
+#define SPI_TCTRL_SDM_SHIFT                 (13)
+#define SPI_TCTRL_SDM_MASK                  (0x1U << SPI_TCTRL_SDM_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_SDM_SAMPLE_NODELAY = 1 << SPI_TCTRL_SDM_SHIFT,
+    SPI_TCTRL_SDM_SAMPLE_DELAY = 0 << SPI_TCTRL_SDM_SHIFT
+} SPI_TCTRL_Sdm;
+
+#define SPI_TCTRL_FBS_SHIFT                 (12)
+#define SPI_TCTRL_FBS_MASK                  (0x1U << SPI_TCTRL_FBS_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_FBS_MSB = 0 << SPI_TCTRL_FBS_SHIFT,
+    SPI_TCTRL_FBS_LSB = 1 << SPI_TCTRL_FBS_SHIFT
+} SPI_TCTRL_Fbs;
+
+#define SPI_TCTRL_SDC_SHIFT                 (11)
+#define SPI_TCTRL_SDC_MASK                  (0x1U << SPI_TCTRL_SDC_SHIFT)
+
+#define SPI_TCTRL_RPSM_SHIFT                (10)
+#define SPI_TCTRL_RPSM_MASK                 (0x1U << SPI_TCTRL_RPSM_SHIFT)
+
+#define SPI_TCTRL_DDB_SHIFT                 (9)
+#define SPI_TCTRL_DDB_MASK                  (0x1U << SPI_TCTRL_DDB_SHIFT)
+
+#define SPI_TCTRL_DHB_SHIFT                 (8)
+#define SPI_TCTRL_DHB_MASK                  (0x1U << SPI_TCTRL_DHB_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_DHB_FULL_DUPLEX = 0 << SPI_TCTRL_DHB_SHIFT,
+    SPI_TCTRL_DHB_HALF_DUPLEX = 1 << SPI_TCTRL_DHB_SHIFT
+} SPI_TCTRL_DHB_Duplex;
+
+#define SPI_TCTRL_SS_LEVEL_SHIFT            (7)
+#define SPI_TCTRL_SS_LEVEL_MASK             (0x1U << SPI_TCTRL_SS_LEVEL_SHIFT)
+
+#define SPI_TCTRL_SS_OWNER_SHIFT            (6)
+#define SPI_TCTRL_SS_OWNER_MASK             (0x1U << SPI_TCTRL_SS_OWNER_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_SS_OWNER_CONTROLLER = 0 << SPI_TCTRL_SS_OWNER_SHIFT,
+    SPI_TCTRL_SS_OWNER_SOFTWARE = 1 << SPI_TCTRL_SS_OWNER_SHIFT
+} SPI_TCTRL_SS_OWNER;
+
+#define SPI_TCTRL_SS_SEL_SHIFT              (4)
+#define SPI_TCTRL_SS_SEL_MASK               (0x3U << SPI_TCTRL_SS_SEL_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_SS_SEL_SS0 = 0 << SPI_TCTRL_SS_SEL_SHIFT,
+    SPI_TCTRL_SS_SEL_SS1 = 1 << SPI_TCTRL_SS_SEL_SHIFT,
+    SPI_TCTRL_SS_SEL_SS2 = 2 << SPI_TCTRL_SS_SEL_SHIFT,
+    SPI_TCTRL_SS_SEL_SS3 = 3 << SPI_TCTRL_SS_SEL_SHIFT
+} SPI_TCTRL_SS_Sel;
+
+#define SPI_TCTRL_SS_CTL_SHIFT              (3)
+#define SPI_TCTRL_SS_CTL_MASK               (0x1U << SPI_TCTRL_SS_CTL_SHIFT)
+
+#define SPI_TCTRL_SPOL_SHIFT                (2)
+#define SPI_TCTRL_SPOL_MASK                 (0x1U << SPI_TCTRL_SPOL_SHIFT)
+
+#define SPI_TCTRL_CPOL_SHIFT                (1)
+#define SPI_TCTRL_CPOL_MASK                 (0x1U << SPI_TCTRL_CPOL_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_CPOL_HIGH = 0 << SPI_TCTRL_CPOL_SHIFT,
+    SPI_TCTRL_CPOL_LOW = 1 << SPI_TCTRL_CPOL_SHIFT
+} SPI_TCTRL_Cpol;
+
+#define SPI_TCTRL_CPHA_SHIFT                (0)
+#define SPI_TCTRL_CPHA_MASK                 (0x1U << SPI_TCTRL_CPHA_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_CPHA_PHASE0  = 0 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_TCTRL_CPHA_PHASE1  = 1 << SPI_TCTRL_CPHA_SHIFT
+} SPI_TCTRL_Cpha;
+
+typedef enum
+{
+    SPI_SCLK_Mode0 = 0 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_SCLK_Mode1 = 1 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_SCLK_Mode2 = 2 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_SCLK_Mode3 = 3 << SPI_TCTRL_CPHA_SHIFT
+} SPI_SCLK_Mode;
+
+/*
+ * @brief SPI Interrupt Control Register
+ */
+#define SPI_IER_SS_INT_EN_SHIFT             (13)
+#define SPI_IER_SS_INT_EN_MASK              (0x1U << SPI_IER_SS_INT_EN_SHIFT)
+
+#define SPI_IER_TC_INT_EN_SHIFT             (12)
+#define SPI_IER_TC_INT_EN_MASK              (0x1U << SPI_IER_TC_INT_EN_SHIFT)
+
+#define SPI_IER_TF_UDR_INT_EN_SHIFT         (11)
+#define SPI_IER_TF_UDR_INT_EN_MASK          (0x1U << SPI_IER_TF_UDR_INT_EN_SHIFT)
+
+#define SPI_IER_TF_OVF_INT_EN_SHIFT         (10)
+#define SPI_IER_TF_OVF_INT_EN_MASK          (0x1U << SPI_IER_TF_OVF_INT_EN_SHIFT)
+
+#define SPI_IER_RF_UDR_INT_EN_SHIFT         (9)
+#define SPI_IER_RF_UDR_INT_EN_MASK          (0x1U << SPI_IER_RF_UDR_INT_EN_SHIFT)
+
+#define SPI_IER_RF_OVF_INT_EN_SHIFT         (8)
+#define SPI_IER_RF_OVF_INT_EN_MASK          (0x1U << SPI_IER_RF_OVF_INT_EN_SHIFT)
+
+#define SPI_IER_TF_FUL_INT_EN_SHIFT         (6)
+#define SPI_IER_TF_FUL_INT_EN_MASK          (0x1U << SPI_IER_TF_FUL_INT_EN_SHIFT)
+
+#define SPI_IER_TX_EMP_INT_EN_SHIFT         (5)
+#define SPI_IER_TX_EMP_INT_EN_MASK          (0x1U << SPI_IER_TX_EMP_INT_EN_SHIFT)
+
+#define SPI_IER_TX_ERQ_INT_EN_SHIFT         (4)
+#define SPI_IER_TX_ERQ_INT_EN_MASK          (0x1U << SPI_IER_TX_ERQ_INT_EN_SHIFT)
+
+#define SPI_IER_RF_FUL_INT_EN_SHIFT         (2)
+#define SPI_IER_RF_FUL_INT_EN_MASK          (0x1U << SPI_IER_RF_FUL_INT_EN_SHIFT)
+
+#define SPI_IER_RX_EMP_INT_EN_SHIFT         (1)
+#define SPI_IER_RX_EMP_INT_EN_MASK          (0x1U << SPI_IER_RX_EMP_INT_EN_SHIFT)
+
+#define SPI_IER_RF_RDY_INT_EN_SHIFT         (0)
+#define SPI_IER_RF_RDY_INT_EN_MASK          (0x1U << SPI_IER_RF_RDY_INT_EN_SHIFT)
+
+/*
+ * @brief SPI Interrupt Status Register
+ */
+#define SPI_STA_SSI_SHIFT                   (13)
+#define SPI_STA_SSI_MASK                    (0x1U << SPI_STA_SSI_SHIFT)
+
+#define SPI_STA_TC_SHIFT                    (12)
+#define SPI_STA_TC_MASK                     (0x1U << SPI_STA_TC_SHIFT)
+
+#define SPI_STA_TF_UDF_SHIFT                (11)
+#define SPI_STA_TF_UDF_MASK                 (0x1U << SPI_STA_TF_UDF_SHIFT)
+
+#define SPI_STA_TF_OVF_SHIFT                (10)
+#define SPI_STA_TF_OVF_MASK                 (0x1U << SPI_STA_TF_OVF_SHIFT)
+
+#define SPI_STA_RX_UDF_SHIFT                (9)
+#define SPI_STA_RX_UDF_MASK                 (0x1U << SPI_STA_RX_UDF_SHIFT)
+
+#define SPI_STA_RX_OVF_SHIFT                (8)
+#define SPI_STA_RX_OVF_MASK                 (0x1U << SPI_STA_RX_OVF_SHIFT)
+
+#define SPI_STA_TX_FULL_SHIFT               (6)
+#define SPI_STA_TX_FULL_MASK                (0x1U << SPI_STA_TX_FULL_SHIFT)
+
+#define SPI_STA_TX_EMP_SHIFT                (5)
+#define SPI_STA_TX_EMP_MASK                 (0x1U << SPI_STA_TX_EMP_SHIFT)
+
+#define SPI_STA_TX_READY_SHIFT              (4)
+#define SPI_STA_TX_READY_MASK               (0x1U << SPI_STA_TX_READY_SHIFT)
+
+#define SPI_STA_RX_FULL_SHIFT               (2)
+#define SPI_STA_RX_FULL_MASK                (0x1U << SPI_STA_RX_FULL_SHIFT)
+
+#define SPI_STA_RX_EMP_SHIFT                (1)
+#define SPI_STA_RX_EMP_MASK                 (0x1U << SPI_STA_RX_EMP_SHIFT)
+
+#define SPI_STA_RX_RDY_SHIFT                (0)
+#define SPI_STA_RX_RDY_MASK                 (0x1U << SPI_STA_RX_RDY_SHIFT)
+
+/*
+ * @brief SPI FIFO Control Register
+ */
+#define SPI_FCTL_TF_RST_SHIFT               (31)
+#define SPI_FCTL_TF_RST_MASK                (0x1U << SPI_FCTL_TF_RST_SHIFT)
+
+#define SPI_FCTL_TF_TEST_EN_SHIFT           (30)
+#define SPI_FCTL_TF_TEST_EN_MASK            (0x1U << SPI_FCTL_TF_TEST_EN_SHIFT)
+
+#define SPI_FCTL_TF_DRQ_EN_SHIFT            (24)
+#define SPI_FCTL_TF_DRQ_EN_MASK             (0x1U << SPI_FCTL_TF_DRQ_EN_SHIFT)
+#define SPI_FCTL_TF_DRQ_EN_BIT              HAL_BIT(24)
+
+#define SPI_FCTL_TX_TRIG_LEVEL_SHIFT        (16)
+#define SPI_FCTL_TX_TRIG_LEVEL_MASK         (0xFFU << SPI_FCTL_TX_TRIG_LEVEL_SHIFT)
+
+#define SPI_FCTL_RF_RST_SHIFT               (15)
+#define SPI_FCTL_RF_RST_MASK                (0x1U << SPI_FCTL_RF_RST_SHIFT)
+
+#define SPI_FCTL_RF_TEST_SHIFT              (14)
+#define SPI_FCTL_RF_TEST_MASK               (0x1U << SPI_FCTL_RF_TEST_SHIFT)
+
+#define SPI_FCTL_RF_DRQ_EN_SHIFT            (8)
+#define SPI_FCTL_RF_DRQ_EN_MASK             (0x1U << SPI_FCTL_RF_DRQ_EN_SHIFT)
+
+#define SPI_FCTL_RX_TRIG_LEVEL_SHIFT        (0)
+#define SPI_FCTL_RX_TRIG_LEVEL_MASK         (0xFFU << SPI_FCTL_RX_TRIG_LEVEL_SHIFT)
+
+/*
+ * @brief SPI FIFO Status Registe
+ */
+#define SPI_FST_TB_WR_SHIFT                 (31)
+#define SPI_FST_TB_WR_MASK                  (0x1U << SPI_FST_TB_WR_SHIFT)
+
+#define SPI_FST_TB_CNT_SHIFT                (28)
+#define SPI_FST_TB_CNT_MASK                 (0x7U << SPI_FST_TB_CNT_SHIFT)
+
+#define SPI_FST_TF_CNT_SHIFT                (16)
+#define SPI_FST_TF_CNT_MASK                 (0xFFU << SPI_FST_TF_CNT_SHIFT)
+
+#define SPI_FST_RB_WR_SHIFT                 (15)
+#define SPI_FST_RB_WR_MASK                  (0x1U << SPI_FST_RB_WR_SHIFT)
+
+#define SPI_FST_RB_CNT_SHIFT                (12)
+#define SPI_FST_RB_CNT_MASK                 (0x7U << SPI_FST_RB_CNT_SHIFT)
+
+#define SPI_FST_RF_CNT_SHIFT                (0)
+#define SPI_FST_RF_CNT_MASK                 (0xFFU << SPI_FST_RF_CNT_SHIFT)
+
+/*
+ * @brief SPI Wait Clock Counter Register
+ */
+#define SPI_WAIT_SWC_SHIFT                  (16)
+#define SPI_WAIT_SWC_MASK                   (0xFU << SPI_WAIT_SWC_SHIFT)
+
+#define SPI_WAIT_WCC_SHIFT                  (0)
+#define SPI_WAIT_WCC_MASK                   (0xFFFFU << SPI_WAIT_WCC_SHIFT)
+
+/*
+ * @brief SPI Clock Rate Control Register
+ */
+#define SPI_CCTR_DRS_SHIFT                  (12)
+#define SPI_CCTR_DRS_MASK                   (0x1U << SPI_CCTR_DRS_SHIFT)
+typedef enum
+{
+    SPI_CCTR_DRS_type_divRate1 = 0 << SPI_CCTR_DRS_SHIFT,
+    SPI_CCTR_DRS_type_divRate2 = 1 << SPI_CCTR_DRS_SHIFT
+} SPI_CCTR_DRS_type;
+
+#define SPI_CCTR_CDR1_SHIFT                 (8)
+#define SPI_CCTR_CDR1_MASK                  (0xFU << SPI_CCTR_CDR1_SHIFT)
+
+#define SPI_CCTR_CDR2_SHIFT                 (0)
+#define SPI_CCTR_CDR2_MASK                  (0xFFU << SPI_CCTR_CDR2_SHIFT)
+
+/*
+ * @brief SPI Master mode Burst Control Register
+ */
+#define SPI_BC_MBC_SHIFT                    (0)
+#define SPI_BC_MBC_MASK                     (0xFFFFFFU << SPI_BC_MBC_SHIFT)
+
+/*
+ * @brief SPI Master mode Transmit Counter Register
+ */
+#define SPI_TC_MWTC_SHIFT                   (0)
+#define SPI_TC_MWTC_MASK                    (0xFFFFFFU << SPI_TC_MWTC_SHIFT)
+
+/*
+ * @brief SPI Burst Control Register
+ */
+#define SPI_BCC_DRM_SHIFT                   (28)
+#define SPI_BCC_DRM_MASK                    (0x1U << SPI_BCC_DRM_SHIFT)
+
+#define SPI_BCC_DBC_SHIFT                   (24)
+#define SPI_BCC_DBC_MASK                    (0xFU << SPI_BCC_DBC_SHIFT)
+
+#define SPI_BCC_STC_SHIFT                   (0)
+#define SPI_BCC_STC_MASK                    (0xFFFFFFU << SPI_BCC_STC_SHIFT)
+
+/*
+ * @brief SPI Nomal DMA Mode Control Regist
+ */
+#define SPI_NDMA_MODE_CTRL_SHIFT            (0)
+#define SPI_NDMA_MODE_CTRL_MASK             (0xFFU << SPI_NDMA_MODE_CTRL_SHIFT)
+
+/*
+ * @brief SPI TX Date Register
+ */
+#define SPI_TXD_SHIFT                       (0)
+#define SPI_TXD_MASK                        (0xFFFFFFFFU << SPI_TXD_SHIFT)
+
+/*
+ * @brief SPI RX Date Register
+ */
+#define SPI_RXD_SHIFT                       (0)
+#define SPI_RXD_MASK                        (0xFFFFFFFFU << SPI_RXD_SHIFT)
+
+/* other */
+#define SPI_FIFO_SIZE                       (64)
+#define SPI_MAX_WAIT_MS (2000)
+#define SPI_SOURCE_CLK (24 * 1000 * 1000)
+
+/* io ops */
+#define HAL_BIT(pos)                        (1U << (pos))
+
+#define HAL_SET_BIT(reg, mask)              ((reg) |= (mask))
+#define HAL_CLR_BIT(reg, mask)              ((reg) &= ~(mask))
+#define HAL_GET_BIT(reg, mask)              ((reg) & (mask))
+#define HAL_GET_BIT_VAL(reg, shift, vmask)  (((reg) >> (shift)) & (vmask))
+
+#define HAL_MODIFY_REG(reg, clr_mask, set_mask) \
+    ((reg) = (((reg) & (~(clr_mask))) | (set_mask)))
+
+/* access LSBs of a 32-bit register (little endian only) */
+#define HAL_REG_32BIT(reg_addr)  (*((volatile rt_uint32_t *)(reg_addr)))
+#define HAL_REG_16BIT(reg_addr)  (*((volatile rt_uint16_t *)(reg_addr)))
+#define HAL_REG_8BIT(reg_addr)   (*((volatile rt_uint8_t  *)(reg_addr)))
+
+#define HAL_WAIT_FOREVER    OS_WAIT_FOREVER
+
+#define HAL_ARRAY_SIZE(a)   (sizeof((a)) / sizeof((a)[0]))
+
+struct tina_spi
+{
+    SPI_T *spi;
+    unsigned int spi_gate;
+    struct rt_spi_bus *spi_bus;
+};
+
+struct tina_spi_cs
+{
+    SPI_TCTRL_SS_Sel cs;
+};
+/* public function */
+rt_err_t r6_spi_bus_register(SPI_T *spi, const char *spi_bus_name);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //

+ 80 - 0
bsp/allwinner_tina/drivers/spi/drv_spi_flash.c

@@ -0,0 +1,80 @@
+/*
+ * File      : drv_spi_flash.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2017, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-02-08     RT-Thread    the first version
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include <rtdevice.h>
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME  "[FLASH]"
+#define DBG_LEVEL         DBG_LOG
+#define DBG_COLOR
+#include <rtdbg.h>
+
+#define SPI_FLASH_DEVICE_NAME       "spi00"
+#define SPI_FLASH_CHIP              "gd25qxx"
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DEBUG_PRINTF(...)   rt_kprintf(__VA_ARGS__)
+#else
+#define DEBUG_PRINTF(...)
+#endif
+
+#ifdef TINA_USING_SPI_FLASH
+
+#include "spi_flash.h"
+
+#if defined(RT_USING_SFUD)
+#include "spi_flash_sfud.h"
+rt_spi_flash_device_t spi_device;
+int rt_hw_spi_flash_with_sfud_init(void)
+{
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+    spi_device = rt_sfud_flash_probe(SPI_FLASH_CHIP, SPI_FLASH_DEVICE_NAME);
+    if (spi_device == NULL)
+    {
+        DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+        return RT_ERROR;
+    };
+
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+    return RT_EOK;
+}
+INIT_PREV_EXPORT(rt_hw_spi_flash_with_sfud_init);
+
+#elif defined(RT_USING_W25QXX)
+#include "spi_flash_w25qxx.h"
+
+int rt_hw_spi_flash_init(void)
+{
+    DEBUG_PRINTF("%s -> %d\n", __FUNCTION__, __LINE__);
+    return w25qxx_init(SPI_FLASH_CHIP, SPI_FLASH_DEVICE_NAME);
+}
+INIT_DEVICE_EXPORT(rt_hw_spi_flash_init);
+
+#endif
+
+#endif