Files
arcs/arcs-sdk/drivers/lisa_spi/lisa_spi_arcs.c
2026-08-13 16:50:52 +08:00

519 lines
17 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2025, LISTENAI
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file lisa_spi_arcs.c
* @brief LISA SPI ARCS 平台适配层
*
* 此文件实现 ARCS 芯片平台的 SPI 硬件适配
*/
#include "lisa_spi.h"
#include "Driver_SPI.h"
#include "ClockManager.h"
#include "dma.h"
#include <lisa_mutex.h>
#include <string.h>
#include "board.h"
#define LOG_TAG "lisa_spi_arcs"
#include <lisa_log.h>
/* 配置锁宏 - 用于保护配置和设备级控制操作 */
#define CONFIG_LOCK(priv) \
do { \
if (priv->config_mutex) { \
lisa_mutex_lock(priv->config_mutex, LISA_OS_WAIT_FOREVER); \
} \
} while (0)
#define CONFIG_UNLOCK(priv) \
do { \
if (priv->config_mutex) { \
lisa_mutex_unlock(priv->config_mutex); \
} \
} while (0)
/* 传输锁宏 - 用于保护传输操作 */
#define TRANSFER_LOCK(priv) \
do { \
if (priv->transfer_mutex) { \
lisa_mutex_lock(priv->transfer_mutex, LISA_OS_WAIT_FOREVER); \
} \
} while (0)
#define TRANSFER_UNLOCK(priv) \
do { \
if (priv->transfer_mutex) { \
lisa_mutex_unlock(priv->transfer_mutex); \
} \
} while (0)
typedef struct {
void *hal_handler; /* HAL SPI 句柄 (SPI0/SPI1)*/
lisa_spi_config_t current_config; /* 当前配置 */
lisa_mutex_t *config_mutex; /* 配置互斥锁 */
lisa_mutex_t *transfer_mutex; /* 传输互斥锁 */
uint32_t rx_buf_addr; /* 用于DMA接收的缓存地址 */
uint32_t rx_size; /* 用于DMA接收的缓存大小 */
lisa_spi_transfer_callback_t callback; /* 传输完成回调函数 */
void *user_data; /* 用户自定义数据指针 */
} lisa_spi_priv_t;
/* ===== SPI 设备静态实例 ===== */
#ifdef CONFIG_LISA_SPI0
static lisa_spi_priv_t spi0_priv;
#endif
#ifdef CONFIG_LISA_SPI1
static lisa_spi_priv_t spi1_priv;
#endif
#ifdef CONFIG_LISA_SPI2
static lisa_spi_priv_t spi2_priv;
#endif
/**
* @brief HAL SPI 事件回调函数
*/
static void spi_hal_event_callback(uint32_t event, uint32_t usr_param)
{
lisa_spi_priv_t *priv = (lisa_spi_priv_t *)usr_param;
if (event & CSK_SPI_EVENT_TRANSFER_COMPLETE) {
#if CONFIG_DCACHE_ENABLE
if (priv->current_config.rx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
// DMA模式需要刷cache
if (priv->rx_buf_addr && priv->rx_size) {
HAL_InvalidateDCache_by_Addr((unsigned long)priv->rx_buf_addr, priv->rx_size);
priv->rx_buf_addr = 0;
priv->rx_size = 0;
}
}
#endif
if (priv->callback) {
priv->callback(priv->user_data);
}
}
}
/* ===== ARCS平台SPI实现函数 ===== */
static int arcs_spi_configure(lisa_device_t *dev, const lisa_spi_config_t *config)
{
if (!lisa_device_is_initialized(dev) || !config) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_spi_priv_t *priv = (lisa_spi_priv_t *)dev->priv_data;
uint32_t control = 0;
int32_t ret;
/* 验证 DMA 通道 (仅当使用 DMA 传输模式时) */
if (config->tx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
if (config->tx_dma_channel > 3) {
LISA_LOGE(LOG_TAG, "Invalid DMA TX channel: %d (valid range: 0-3)", config->tx_dma_channel);
return LISA_DEVICE_ERR_INVALID;
}
}
if (config->rx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
if (config->rx_dma_channel > 3) {
LISA_LOGE(LOG_TAG, "Invalid DMA RX channel: %d (valid range: 0-3)", config->rx_dma_channel);
return LISA_DEVICE_ERR_INVALID;
}
}
CONFIG_LOCK(priv);
/* 检查是否需要释放旧的DMA通道 */
bool old_tx_is_dma = (priv->current_config.tx_transfer_mode == LISA_SPI_DMA_TRANSFER);
bool old_rx_is_dma = (priv->current_config.rx_transfer_mode == LISA_SPI_DMA_TRANSFER);
bool new_tx_is_dma = (config->tx_transfer_mode == LISA_SPI_DMA_TRANSFER);
bool new_rx_is_dma = (config->rx_transfer_mode == LISA_SPI_DMA_TRANSFER);
/* 如果从DMA模式切换到中断模式释放DMA通道 */
if (old_tx_is_dma && !new_tx_is_dma) {
dma_channel_unreserve(priv->current_config.tx_dma_channel);
}
if (old_rx_is_dma && !new_rx_is_dma) {
dma_channel_unreserve(priv->current_config.rx_dma_channel);
}
/* 配置SPI基本参数 */
if (config->master_mode) {
control |= CSK_SPI_MODE_MASTER;
} else {
control |= CSK_SPI_MODE_SLAVE;
}
if (config->mode == LISA_SPI_MODE_0) {
control |= CSK_SPI_CPOL0_CPHA0;
} else if (config->mode == LISA_SPI_MODE_1) {
control |= CSK_SPI_CPOL0_CPHA1;
} else if (config->mode == LISA_SPI_MODE_2) {
control |= CSK_SPI_CPOL1_CPHA0;
} else if (config->mode == LISA_SPI_MODE_3) {
control |= CSK_SPI_CPOL1_CPHA1;
}
if (config->bit_order == LISA_SPI_BIT_ORDER_MSB_FIRST) {
control |= CSK_SPI_MSB_LSB;
} else {
control |= CSK_SPI_LSB_MSB;
}
control |= CSK_SPI_DATA_BITS(config->data_bits);
/* 配置传输模式 */
if (config->tx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
control |= CSK_SPI_TXIO_DMA;
} else {
control |= CSK_SPI_TXIO_PIO;
}
if (config->rx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
control |= CSK_SPI_RXIO_DMA;
} else {
control |= CSK_SPI_RXIO_PIO;
}
/* 执行SPI控制配置 */
if (priv->current_config.frequency == config->frequency) {
ret = SPI_Control(priv->hal_handler, control, 0);
}
else {
ret = SPI_Control(priv->hal_handler, control, config->frequency);
}
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Control failed: %d", ret);
ret = LISA_DEVICE_ERR_NOT_SUPPORT;
goto exit;
}
/* 如果新配置使用DMA模式配置DMA通道 */
if (new_tx_is_dma || new_rx_is_dma) {
SPI_ADV_ATTR spi_attr = {0};
if (new_tx_is_dma) {
spi_attr.flags |= SPI_ATTR_TX_DMACH_RSVD | SPI_ATTR_TX_NSYNCA | SPI_ATTR_TX_DMA_BSIZE;
spi_attr.tx_dmach_rsvd = config->tx_dma_channel;
spi_attr.tx_nsynca = 1;
spi_attr.tx_dma_bsize = DMA_WIDTH_HALFWORD;
}
if (new_rx_is_dma) {
spi_attr.flags |= SPI_ATTR_RX_NSYNCA | SPI_ATTR_RX_DMACH_RSVD;
spi_attr.rx_dmach_rsvd = config->rx_dma_channel;
spi_attr.rx_nsynca = 1;
}
ret = SPI_Control(priv->hal_handler, CSK_SPI_SET_ADV_ATTR, (uint32_t)&spi_attr);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Control set ADV_ATTR failed: %d", ret);
ret = LISA_DEVICE_ERR_NOT_SUPPORT;
goto exit;
}
}
/* 保存新配置 */
memcpy(&priv->current_config, config, sizeof(lisa_spi_config_t));
ret = LISA_DEVICE_OK;
exit:
CONFIG_UNLOCK(priv);
return ret;
}
static int arcs_spi_get_config(lisa_device_t *dev, lisa_spi_config_t *config)
{
if (!lisa_device_is_initialized(dev) || !config) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_spi_priv_t *priv = (lisa_spi_priv_t *)dev->priv_data;
CONFIG_LOCK(priv);
memcpy(config, &priv->current_config, sizeof(lisa_spi_config_t));
CONFIG_UNLOCK(priv);
return LISA_DEVICE_OK;
}
static int arcs_spi_register_callback(lisa_device_t *dev, lisa_spi_transfer_callback_t callback, void *user_data)
{
if (!lisa_device_is_initialized(dev)) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_spi_priv_t *priv = (lisa_spi_priv_t *)dev->priv_data;
CONFIG_LOCK(priv);
priv->callback = callback;
priv->user_data = user_data;
CONFIG_UNLOCK(priv);
return LISA_DEVICE_OK;
}
static int arcs_spi_transfer(lisa_device_t *dev, const lisa_spi_transfer_t *xfer)
{
if (!lisa_device_is_initialized(dev) || !xfer || (!xfer->tx_buf || !xfer->rx_buf) || xfer->len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_spi_priv_t *priv = (lisa_spi_priv_t *)dev->priv_data;
int ret;
TRANSFER_LOCK(priv);
#if CONFIG_DCACHE_ENABLE
if (priv->current_config.tx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
// DMA模式需要刷cache
HAL_FlushDCache_by_Addr((unsigned long)xfer->tx_buf, xfer->len);
HAL_FlushDCache_by_Addr((unsigned long)xfer->rx_buf, xfer->len);
}
#endif
ret = SPI_Transfer(priv->hal_handler, xfer->tx_buf, xfer->rx_buf, xfer->len);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Transfer failed: %d", ret);
ret = LISA_DEVICE_ERR_NOT_SUPPORT;
goto exit;
}
priv->rx_buf_addr = (uint32_t)xfer->rx_buf;
priv->rx_size = xfer->len;
ret = LISA_DEVICE_OK;
TRANSFER_UNLOCK(priv);
exit:
return ret;
}
static int arcs_spi_write(lisa_device_t *dev, const uint8_t *buf, uint32_t len)
{
if (!lisa_device_is_initialized(dev) || !buf || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_spi_priv_t *priv = (lisa_spi_priv_t *)dev->priv_data;
int ret;
TRANSFER_LOCK(priv);
#if CONFIG_DCACHE_ENABLE
if (priv->current_config.tx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
// DMA模式需要刷cache
HAL_FlushDCache_by_Addr((unsigned long)buf, len);
}
#endif
ret = SPI_Send(priv->hal_handler, buf, len);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Send failed: %d", ret);
ret = LISA_DEVICE_ERR_NOT_SUPPORT;
goto exit;
}
ret = LISA_DEVICE_OK;
exit:
TRANSFER_UNLOCK(priv);
return ret;
}
static int arcs_spi_read(lisa_device_t *dev, uint8_t *buf, uint32_t len)
{
if (!lisa_device_is_initialized(dev) || !buf || len == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_spi_priv_t *priv = (lisa_spi_priv_t *)dev->priv_data;
int ret;
TRANSFER_LOCK(priv);
#if CONFIG_DCACHE_ENABLE
if (priv->current_config.rx_transfer_mode == LISA_SPI_DMA_TRANSFER) {
// DMA模式需要刷cache
HAL_FlushDCache_by_Addr((unsigned long)buf, len);
}
#endif
if (priv->current_config.flags == LISA_SPI_FLAG_SOFTWARE_CS && (!priv->current_config.master_mode)) {
ret = SPI_Receive_NEnd(priv->hal_handler, buf, len);
} else {
ret = SPI_Receive(priv->hal_handler, buf, len);
}
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Receive failed: %d", ret);
ret = LISA_DEVICE_ERR_NOT_SUPPORT;
goto exit;
}
priv->rx_buf_addr = (uint32_t)buf;
priv->rx_size = len;
ret = LISA_DEVICE_OK;
exit:
TRANSFER_UNLOCK(priv);
return ret;
}
/* ===== 设备初始化函数 ===== */
#ifdef CONFIG_LISA_SPI0
static int arcs_spi0_init(void)
{
int ret;
memset(&spi0_priv, 0, sizeof(spi0_priv));
spi0_priv.hal_handler = SPI0();
if (!spi0_priv.hal_handler) {
LISA_LOGE(LOG_TAG, "Failed to get SPI0 handler");
return LISA_DEVICE_ERR_INIT_FAIL;
}
ret = SPI_Initialize(spi0_priv.hal_handler, spi_hal_event_callback, (uint32_t)&spi0_priv);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Initialize failed: %d", ret);
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
ret = SPI_PowerControl(spi0_priv.hal_handler, CSK_POWER_FULL);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_PowerControl failed: %d", ret);
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
HAL_CRM_SetSpi0ClkSrc(CRM_IpSrcPeriClk);
spi0_priv.config_mutex = lisa_mutex_create();
if (!spi0_priv.config_mutex) {
LISA_LOGE(LOG_TAG, "Failed to create config_mutex for SPI0");
return LISA_DEVICE_ERR_INIT_FAIL;
}
spi0_priv.transfer_mutex = lisa_mutex_create();
if (!spi0_priv.transfer_mutex) {
LISA_LOGE(LOG_TAG, "Failed to create transfer_mutex for SPI0");
return LISA_DEVICE_ERR_INIT_FAIL;
}
lisa_spi0_pinmux();
return LISA_DEVICE_OK;
}
#endif
#ifdef CONFIG_LISA_SPI1
static int arcs_spi1_init(void)
{
int ret;
memset(&spi1_priv, 0, sizeof(spi1_priv));
spi1_priv.hal_handler = SPI1();
if (!spi1_priv.hal_handler) {
LISA_LOGE(LOG_TAG, "Failed to get SPI1 handler");
return LISA_DEVICE_ERR_INIT_FAIL;
}
ret = SPI_Initialize(spi1_priv.hal_handler, spi_hal_event_callback, (uint32_t)&spi1_priv);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Initialize failed: %d", ret);
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
ret = SPI_PowerControl(spi1_priv.hal_handler, CSK_POWER_FULL);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_PowerControl failed: %d", ret);
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
HAL_CRM_SetSpi1ClkSrc(CRM_IpSrcPeriClk);
spi1_priv.config_mutex = lisa_mutex_create();
if (!spi1_priv.config_mutex) {
LISA_LOGE(LOG_TAG, "Failed to create config_mutex for SPI1");
return LISA_DEVICE_ERR_INIT_FAIL;
}
spi1_priv.transfer_mutex = lisa_mutex_create();
if (!spi1_priv.transfer_mutex) {
LISA_LOGE(LOG_TAG, "Failed to create transfer_mutex for SPI1");
return LISA_DEVICE_ERR_INIT_FAIL;
}
lisa_spi1_pinmux();
return LISA_DEVICE_OK;
}
#endif
#ifdef CONFIG_LISA_SPI2
static int arcs_spi2_init(void)
{
int ret;
memset(&spi2_priv, 0, sizeof(spi2_priv));
spi2_priv.hal_handler = SPI2();
if (!spi2_priv.hal_handler) {
LISA_LOGE(LOG_TAG, "Failed to get SPI2 handler");
return LISA_DEVICE_ERR_INIT_FAIL;
}
ret = SPI_Initialize(spi2_priv.hal_handler, spi_hal_event_callback, (uint32_t)&spi2_priv);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_Initialize failed: %d", ret);
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
ret = SPI_PowerControl(spi2_priv.hal_handler, CSK_POWER_FULL);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "SPI_PowerControl failed: %d", ret);
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
HAL_CRM_SetSpi2ClkSrc(CRM_IpSrcPeriClk);
spi2_priv.config_mutex = lisa_mutex_create();
if (!spi2_priv.config_mutex) {
LISA_LOGE(LOG_TAG, "Failed to create config_mutex for SPI2");
return LISA_DEVICE_ERR_INIT_FAIL;
}
spi2_priv.transfer_mutex = lisa_mutex_create();
if (!spi2_priv.transfer_mutex) {
LISA_LOGE(LOG_TAG, "Failed to create transfer_mutex for SPI2");
return LISA_DEVICE_ERR_INIT_FAIL;
}
lisa_spi2_pinmux();
return LISA_DEVICE_OK;
}
#endif
/* ===== ARCS SPI API 实例 ===== */
static const lisa_spi_api_t arcs_spi_api = {
.configure = arcs_spi_configure,
.get_config = arcs_spi_get_config,
.transfer = arcs_spi_transfer,
.write = arcs_spi_write,
.read = arcs_spi_read,
.register_callback = arcs_spi_register_callback,
};
/* ===== 设备注册 ===== */
#ifdef CONFIG_LISA_SPI0
LISA_DEVICE_REGISTER(spi0, &arcs_spi_api, &spi0_priv, NULL, arcs_spi0_init, LISA_DEVICE_PRIORITY_NORMAL);
#endif
#ifdef CONFIG_LISA_SPI1
LISA_DEVICE_REGISTER(spi1, &arcs_spi_api, &spi1_priv, NULL, arcs_spi1_init, LISA_DEVICE_PRIORITY_NORMAL);
#endif
#ifdef CONFIG_LISA_SPI2
LISA_DEVICE_REGISTER(spi2, &arcs_spi_api, &spi2_priv, NULL, arcs_spi2_init, LISA_DEVICE_PRIORITY_NORMAL);
#endif