summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbsp/cvitek/README.md1
-rwxr-xr-xbsp/cvitek/c906_little/board/Kconfig5
-rwxr-xr-xbsp/cvitek/cv180x/board/Kconfig5
-rwxr-xr-xbsp/cvitek/drivers/SConscript3
-rw-r--r--bsp/cvitek/drivers/drv_spi.c235
-rw-r--r--bsp/cvitek/drivers/drv_spi.h155
6 files changed, 404 insertions, 0 deletions
diff --git a/bsp/cvitek/README.md b/bsp/cvitek/README.md
index a343b557ce..6bf2821c96 100755
--- a/bsp/cvitek/README.md
+++ b/bsp/cvitek/README.md
@@ -56,6 +56,7 @@ $ scons
| gpio | 支持 | |
| i2c | 支持 | |
| adc | 支持 | |
+| spi | 支持 | 默认CS引脚,每个数据之间CS会拉高,请根据时序选择GPIO作为CS。若读取数据,tx需持续dummy数据。|
## 支持开发板
- milk-v duo: [https://milkv.io/duo](https://milkv.io/duo)
diff --git a/bsp/cvitek/c906_little/board/Kconfig b/bsp/cvitek/c906_little/board/Kconfig
index 3780246c59..6a0d10c0f3 100755
--- a/bsp/cvitek/c906_little/board/Kconfig
+++ b/bsp/cvitek/c906_little/board/Kconfig
@@ -45,6 +45,11 @@ menu "General Drivers Configuration"
select RT_USING_ADC
default n
+ config BSP_USING_SPI
+ bool "Using SPI"
+ select RT_USING_SPI
+ default n
+
menuconfig BSP_USING_WDT
bool "Enable Watchdog Timer"
select RT_USING_WDT
diff --git a/bsp/cvitek/cv180x/board/Kconfig b/bsp/cvitek/cv180x/board/Kconfig
index 82f7886f09..a743c804de 100755
--- a/bsp/cvitek/cv180x/board/Kconfig
+++ b/bsp/cvitek/cv180x/board/Kconfig
@@ -37,6 +37,11 @@ menu "General Drivers Configuration"
select RT_USING_ADC
default n
+ config BSP_USING_SPI
+ bool "Using SPI"
+ select RT_USING_SPI
+ default n
+
menuconfig BSP_USING_PWM
bool "Using PWM"
select RT_USING_PWM
diff --git a/bsp/cvitek/drivers/SConscript b/bsp/cvitek/drivers/SConscript
index f5cde6b1e8..90aa68f80e 100755
--- a/bsp/cvitek/drivers/SConscript
+++ b/bsp/cvitek/drivers/SConscript
@@ -30,6 +30,9 @@ if GetDepend('BSP_USING_ADC'):
if GetDepend('BSP_USING_WDT'):
src += ['drv_wdt.c']
+if GetDepend(['BSP_USING_SPI']):
+ src += ['drv_spi.c']
+
if GetDepend('BSP_USING_PWM'):
src += ['drv_pwm.c']
CPPPATH += [cwd + r'/libraries/cv180x/pwm']
diff --git a/bsp/cvitek/drivers/drv_spi.c b/bsp/cvitek/drivers/drv_spi.c
new file mode 100644
index 0000000000..aa6b3dd0b9
--- /dev/null
+++ b/bsp/cvitek/drivers/drv_spi.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-28 qiujingbao first version
+ */
+
+#include "drv_spi.h"
+#ifdef RT_USING_SPI
+
+#define DBG_TAG "drv.spi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+static struct cv1800_spi cv1800_spi_obj[] =
+{
+#ifdef BSP_USING_SPI
+ {
+ .spi_id = SPI2,
+ .device_name = "spi2",
+ .fifo_len = SPI_TXFTLR,
+ },
+#endif
+};
+
+static struct spi_regs *get_spi_base(uint8_t spi_id)
+{
+ struct spi_regs *spi_base = NULL;
+
+ switch (spi_id)
+ {
+ case SPI0:
+ spi_base = (struct spi_regs *)SPI0_BASE;
+ break;
+ case SPI1:
+ spi_base = (struct spi_regs *)SPI1_BASE;
+ break;
+ case SPI2:
+ spi_base = (struct spi_regs *)SPI2_BASE;
+ break;
+ case SPI3:
+ spi_base = (struct spi_regs *)SPI3_BASE;
+ break;
+ }
+
+ return spi_base;
+}
+
+static rt_err_t drv_spi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
+{
+ rt_err_t ret = RT_EOK;
+ struct cv1800_spi *spi_dev = RT_NULL;
+ uint32_t mode;
+
+ spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data);
+
+ spi_dev->data_width = configuration->data_width;
+
+ /* disable spi */
+ spi_enable(spi_dev->reg, 0);
+
+ /* clear irq */
+ spi_clear_irq(spi_dev->reg, SPI_IRQ_MSAK);
+
+ /* set clk */
+ ret = spi_set_frequency(spi_dev->reg, configuration->max_hz);
+ if (ret)
+ return ret;
+
+ /* set mode */
+ ret = gen_spi_mode(configuration, &mode);
+ if (ret)
+ return ret;
+
+ spi_set_mode(spi_dev->reg, mode);
+
+ /* set cs */
+ spi_enable_cs(spi_dev->reg, 0x1);
+
+ spi_enable(spi_dev->reg, 0x1);
+
+ mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_ctrl0);
+ LOG_D("mode: %x", mode);
+ mode = mmio_read_32((uintptr_t)&spi_dev->reg->spi_baudr);
+ LOG_D("spi_baudr: %x", mode);
+
+ return ret;
+}
+
+int hw_spi_recv(struct cv1800_spi *dev) {
+ uint32_t rever;
+ uint32_t tem;
+ int ret;
+
+ rever = mmio_read_32((uintptr_t)&dev->reg->spi_rxflr);
+ ret = (int)rever;
+
+ while (rever)
+ {
+ tem = mmio_read_32((uintptr_t)&dev->reg->spi_dr);
+
+ if (dev->recv_buf < dev->recv_end)
+ {
+ if (dev->data_width == 8)
+ *(uint8_t *)(dev->recv_buf) = tem;
+ else
+ *(uint16_t *)(dev->recv_buf) = tem;
+ }
+ else
+ {
+ return 0;
+ }
+
+ rever--;
+ dev->recv_buf += dev->data_width >> 3;
+ }
+ return ret;
+}
+
+int hw_spi_send(struct cv1800_spi *dev) {
+ uint32_t txflr;
+ uint32_t max;
+ uint16_t value;
+
+ txflr = mmio_read_32((uintptr_t)&dev->reg->spi_txflr);
+ max = dev->fifo_len - txflr;
+
+ while (max)
+ {
+ if (dev->send_end - dev->send_buf)
+ {
+ if (dev->data_width == 8)
+ value = *(uint8_t *)(dev->send_buf);
+ else
+ value = *(uint16_t *)(dev->send_buf);
+ }
+ else
+ {
+ return 0;
+ }
+
+ mmio_write_32((uintptr_t)&dev->reg->spi_dr, value);
+ dev->send_buf += dev->data_width >> 3;
+ max--;
+ }
+
+ return 0;
+}
+static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message) {
+ int ret = 0;
+ struct cv1800_spi *spi_dev;
+
+ RT_ASSERT(device != RT_NULL);
+ RT_ASSERT(device->bus != RT_NULL);
+ RT_ASSERT(message != RT_NULL);
+
+ spi_dev = (struct cv1800_spi *)(device->bus->parent.user_data);
+
+ if (message->send_buf != RT_NULL)
+ {
+ spi_dev->send_buf = message->send_buf;
+ spi_dev->send_end = (void *)((uint8_t *)spi_dev->send_buf + message->length);
+ }
+
+ if (message->recv_buf != RT_NULL)
+ {
+ spi_dev->recv_buf = message->recv_buf;
+ spi_dev->recv_end = (void *)((uint8_t *)spi_dev->recv_buf + message->length);
+ }
+
+ /* if user use their cs */
+ if (message->cs_take && device->cs_pin != PIN_NONE)
+ rt_pin_write(device->cs_pin, PIN_LOW);
+
+ if (message->send_buf)
+ {
+ while (spi_dev->send_buf != spi_dev->send_end)
+ {
+ hw_spi_send(spi_dev);
+ }
+
+ /* wait for complete */
+ while (mmio_read_32((uintptr_t)&spi_dev->reg->spi_txflr)) {}
+
+ ret = message->length;
+ }
+
+ if (message->recv_buf)
+ {
+ while (spi_dev->recv_buf != spi_dev->recv_end)
+ {
+ hw_spi_recv(spi_dev);
+ }
+
+ ret = message->length;
+ }
+
+ if (message->cs_release && device->cs_pin != PIN_NONE)
+ rt_pin_write(device->cs_pin, PIN_HIGH);
+
+ return ret;
+}
+
+const static struct rt_spi_ops drv_spi_ops =
+{
+ drv_spi_configure,
+ spixfer,
+};
+
+int rt_hw_spi_init(void)
+{
+ rt_err_t ret = RT_EOK;
+ struct spi_regs *reg = NULL;
+
+ for (rt_size_t i = 0; i < sizeof(cv1800_spi_obj) / sizeof(struct cv1800_spi); i++) {
+ /* set reg base addr */
+ reg = get_spi_base(cv1800_spi_obj[i].spi_id);
+ if (!reg)
+ return -RT_ERROR;
+
+ cv1800_spi_obj[i].reg = reg;
+ cv1800_spi_obj[i].spi_bus.parent.user_data = &cv1800_spi_obj[i];
+
+ /* register spix bus */
+ ret = rt_spi_bus_register(&cv1800_spi_obj[i].spi_bus, cv1800_spi_obj[i].device_name, &drv_spi_ops);
+ }
+
+ return ret;
+}
+INIT_BOARD_EXPORT(rt_hw_spi_init);
+
+#endif /* RT_USING_SPI */
diff --git a/bsp/cvitek/drivers/drv_spi.h b/bsp/cvitek/drivers/drv_spi.h
new file mode 100644
index 0000000000..2e20b15b2e
--- /dev/null
+++ b/bsp/cvitek/drivers/drv_spi.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2024-03-28 qiujingbao first version
+ */
+#ifndef __DRV_SPI_H__
+#define __DRV_SPI_H__
+
+#include "rtdevice.h"
+#include <rthw.h>
+#include <rtthread.h>
+
+#include "mmio.h"
+#include "pinctrl.h"
+
+#define SPI0 0x0
+#define SPI1 0x1
+#define SPI2 0x2
+#define SPI3 0x3
+
+#define SPI0_BASE 0x04180000
+#define SPI1_BASE 0x04190000
+#define SPI2_BASE 0x041A0000
+#define SPI3_BASE 0x041B0000
+
+#define SPI_IRQ_MSAK 0x3e
+#define SPI_FREQUENCY 187500000
+
+/* Transmit FiFO Threshold Level */
+#define SPI_TXFTLR 0xf
+
+#define SPI_CTRL0_DATA_FREAM_SHIFT 0
+#define SPI_CTRL0_FREAM_FORMAT_SHIFT 4
+#define SPI_CTRL0_CPHA_SHIFT 6
+#define SPI_CTRL0_CPOL_SHIFT 7
+#define SPI_CTRL0_TRANS_MODE 8
+#define SPI_CTRL0_LOOP_SHIFT 11
+#define SPI_CTRL0_CTRL_FREAM_SHIFT 12
+
+struct cv1800_spi {
+ uint8_t spi_id;
+ char *device_name;
+
+ uint8_t fifo_len;
+ uint8_t data_width;
+
+ const void *send_buf;
+ void *recv_buf;
+
+ const void *send_end;
+ void *recv_end;
+
+ struct rt_spi_bus spi_bus;
+ struct spi_regs *reg;
+};
+
+struct spi_regs {
+ uint32_t spi_ctrl0; // 0x00
+ uint32_t spi_ctrl1; // 0x04
+ uint32_t spi_ssienr; // 0x08
+ uint32_t spi_mwcr; // 0x0c
+ uint32_t spi_ser; // 0x10
+ uint32_t spi_baudr; // 0x14
+ uint32_t spi_txftlr; // 0x18
+ uint32_t spi_rxftlr; // 0x1c
+ uint32_t spi_txflr; // 0x20
+ uint32_t spi_rxflr; // 0x24
+ uint32_t spi_sr; // 0x28
+ uint32_t spi_imr; // 0x2c
+ uint32_t spi_isr; // 0x30
+ uint32_t spi_risr; // 0x34
+ uint32_t spi_txoicr; // 0x38
+ uint32_t spi_rxoicr; // 0x3c
+ uint32_t spi_rxuicr; // 0x40
+ uint32_t spi_msticr; // 0x44
+ uint32_t spi_icr; // 0x48
+ uint32_t spi_dmacr; // 0x4c
+ uint32_t spi_dmatdlr; // 0x50
+ uint32_t spi_dmardlr; // 0x54
+ uint32_t spi_idr; // 0x58
+ uint32_t spi_version; // 0x5c
+ uint32_t spi_dr; // 0x60
+ uint32_t spi_rx_sample_dly; // 0xf0
+ uint32_t spi_cs_override; // 0xf4
+};
+
+uint32_t gen_spi_mode(struct rt_spi_configuration *cfg, uint32_t *mode)
+{
+ uint32_t value = 0;
+
+ if (cfg->data_width != 8 && cfg->data_width != 16)
+ return -1;
+
+ value |= (cfg->data_width - 1) >> SPI_CTRL0_DATA_FREAM_SHIFT;
+ value |= cfg->mode >> SPI_CTRL0_CPHA_SHIFT;
+
+ *mode = value;
+ return 0;
+}
+
+/* set spi mode */
+static inline void spi_set_mode(struct spi_regs *reg, uint32_t mode)
+{
+ mmio_write_32((uintptr_t)&reg->spi_ctrl0, mode);
+}
+
+/* clear irq */
+static inline void spi_clear_irq(struct spi_regs *reg, uint32_t mode)
+{
+ mmio_write_32((uintptr_t)&reg->spi_imr, mode);
+}
+
+static inline void spi_enable_cs(struct spi_regs *reg, uint32_t enable)
+{
+ if (enable)
+ enable = 0x1;
+ else
+ enable = 0x0;
+
+ mmio_write_32((uintptr_t)&reg->spi_ser, enable);
+}
+
+/* set spi frequency*/
+static inline rt_err_t spi_set_frequency(struct spi_regs *reg, uint32_t speed)
+{
+ uint16_t value;
+
+ /* The value of the BAUDR register must be an even number between 2-65534 */
+ value = SPI_FREQUENCY / speed;
+ if (value % 2 != 0)
+ value++;
+
+ if (value < 4 || value > 65534)
+ value = 4;
+
+ mmio_write_32((uintptr_t)&reg->spi_baudr, value);
+
+ return RT_EOK;
+}
+
+static inline void spi_enable(struct spi_regs *reg, uint32_t enable)
+{
+ if (enable)
+ enable = 0x1;
+ else
+ enable = 0x0;
+
+ mmio_write_32((uintptr_t)&reg->spi_ssienr, enable);
+}
+
+#endif /* __DRV_SPI_H__ */