rt-thread/bsp/phytium/libraries/standalone/drivers/spi/fspim/fspim_hw.c

346 lines
9.0 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 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 Phytium Public License for more details.
*
*
* FilePath: fspim_hw.c
* Date: 2022-02-10 14:53:42
* LastEditTime: 2022-02-18 09:08:00
* Description:  This file is for providing spim Hardware interaction func.
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 zhugengyu 2021/12/3 init commit
* 1.1 zhugengyu 2022/4/15 support test mode
* 1.2 liqiaozhong 2023/1/4 add data get func
*/
#include "fassert.h"
#include "fdebug.h"
#include "fspim_hw.h"
#include "fspim.h"
/***************************** Include Files *********************************/
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
#define FSPIM_DEBUG_TAG "SPIM-HW"
#define FSPIM_ERROR(format, ...) FT_DEBUG_PRINT_E(FSPIM_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSPIM_WARN(format, ...) FT_DEBUG_PRINT_W(FSPIM_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSPIM_INFO(format, ...) FT_DEBUG_PRINT_I(FSPIM_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSPIM_DEBUG(format, ...) FT_DEBUG_PRINT_D(FSPIM_DEBUG_TAG, format, ##__VA_ARGS__)
/************************** Function Prototypes ******************************/
/**
* @name: FSpimGetTxFifoDepth
* @msg: 获取TX Fifo可以设置的最大深度
* @return {u32} TX Fifo的深度
* @param {uintptr} base_addr, SPI控制器基地址
*/
u32 FSpimGetTxFifoDepth(uintptr base_addr)
{
u32 fifo_depth;
for (fifo_depth = 1; fifo_depth < FSPIM_MAX_FIFO_DEPTH; fifo_depth++)
{
FSpimSetTxFifoThreshold(base_addr, fifo_depth);
if (fifo_depth != FSpimGetTxFifoThreshold(base_addr))
{
FSPIM_INFO("The Tx fifo threshold is %d", fifo_depth);
break;
}
}
FSpimSetTxFifoThreshold(base_addr, 0);
return fifo_depth;
}
/**
* @name: FSpimGetRxFifoDepth
* @msg: 获取RX Fifo可以设置的最大深度
* @return {u32} Rx Fifo的深度
* @param {uintptr} base_addr, SPI控制器基地址
*/
u32 FSpimGetRxFifoDepth(uintptr base_addr)
{
u32 fifo_depth = FSPIM_MIN_FIFO_DEPTH;
while (FSPIM_MAX_FIFO_DEPTH >= fifo_depth)
{
FSpimSetRxFifoThreshold(base_addr, fifo_depth);
if (fifo_depth != FSpimGetRxFifoThreshold(base_addr))
{
FSPIM_INFO("The Rx fifo threshold is %d", fifo_depth);
break;
}
fifo_depth++;
}
return fifo_depth;
}
/**
* @name: FSpimSelSlaveDev
* @msg: 选择SPI从设备
* @return {无}
* @param {uintptr} base_addr, SPI控制器基地址
* @param {u32} slave_dev_id, 从设备ID
*/
void FSpimSelSlaveDev(uintptr base_addr, u32 slave_dev_id)
{
FASSERT(slave_dev_id < FSPIM_NUM_OF_SLAVE_DEV);
u32 reg_val;
reg_val = (FSPIM_SER_SELECT << slave_dev_id);
FSPIM_WRITE_REG32(base_addr, FSPIM_SER_OFFSET, reg_val);
return;
}
/**
* @name: FSpimSetSpeed
* @msg: 设置SPI传输速度
* @return {FError}
* @param {uintptr} base_addr, SPI控制器基地址
* @param {u32} speed, SPI传输速度设置
*/
FError FSpimSetSpeed(uintptr base_addr, u32 speed)
{
FASSERT(speed != 0);
u32 clk_div;
boolean enabled = FSpimGetEnable(base_addr);
if (enabled)
{
FSpimSetEnable(base_addr, FALSE);
}
clk_div = FSPI_CLK_FREQ_HZ / speed;
if (clk_div < FSPIM_BAUD_R_SCKDV_MIN || clk_div > FSPIM_BAUD_R_SCKDV_MAX)
{
FSPIM_ERROR("Clk div is %d => do not support, this parameter should be set as an even from 2 to 65534.", clk_div);
return FSPIM_ERR_NOT_SUPPORT;
}
FSPIM_INFO("Set clk div as %d", clk_div);
FSPIM_WRITE_REG32(base_addr, FSPIM_BAUD_R_OFFSET, clk_div);
if (enabled)
{
FSpimSetEnable(base_addr, TRUE);
}
return FSPIM_SUCCESS;
}
/**
* @name: FSpimGetSpeed
* @msg: 获取SPI传输速度
* @return {u32}FSPIM传输频率
* @param {uintptr} base_addr, SPI控制器基地址
* @param {u32} speed, SPI传输速度设置
*/
u32 FSpimGetSpeed(uintptr base_addr)
{
u32 clk_div;
u32 spim_speed;
return FSPIM_READ_REG32(base_addr, FSPIM_BAUD_R_OFFSET);
}
/**
* @name: FSpimSetTransMode
* @msg: 设置SPI传输模式
* @return {无}
* @param {uintptr} base_addr, SPI控制器基地址
* @param {u32} trans_mode, SPI传输模式设置
*/
void FSpimSetTransMode(uintptr base_addr, u32 trans_mode)
{
FASSERT(trans_mode < FSPIM_TRANS_MODE_MAX);
u32 reg_val;
boolean enabled = FSpimGetEnable(base_addr);
if (enabled)
{
FSpimSetEnable(base_addr, FALSE);
}
reg_val = FSpimGetCtrlR0(base_addr);
reg_val &= ~FSPIM_CTRL_R0_TMOD_MASK; /* clear trans mode bits */
switch (trans_mode)
{
case FSPIM_TRANS_MODE_RX_TX:
reg_val |= FSPIM_CTRL_R0_TMOD(FSPIM_TMOD_RX_TX);
break;
case FSPIM_TRANS_MODE_TX_ONLY:
reg_val |= FSPIM_CTRL_R0_TMOD(FSPIM_TMOD_TX_ONLY);
break;
case FSPIM_TRANS_MODE_RX_ONLY:
reg_val |= FSPIM_CTRL_R0_TMOD(FSPIM_TMOD_RX_ONLY);
break;
case FSPIM_TRANS_MODE_READ_EEPROM:
reg_val |= FSPIM_CTRL_R0_TMOD(FSPIM_TMOD_RD_EEPROM);
break;
default:
FASSERT(0);
break;
}
FSpimSetCtrlR0(base_addr, reg_val);
if (enabled)
{
FSpimSetEnable(base_addr, TRUE);
}
return;
}
/**
* @name: FSpimSetCpha
* @msg: 设置串行时钟相位
* @return {无}
* @param {uintptr} base_addr, SPI控制器基地址
* @param {u32} cpha_mode, SPI控制器的相位设置
*/
void FSpimSetCpha(uintptr base_addr, u32 cpha_mode)
{
u32 reg_val = FSpimGetCtrlR0(base_addr);
reg_val &= ~FSPIM_CTRL_R0_SCPHA_MASK; /* clear bits */
if (FSPIM_CPHA_1_EDGE == cpha_mode)
{
reg_val |= FSPIM_CTRL_R0_SCPHA(FSPIM_SCPHA_SWITCH_DATA_MID);
}
else if (FSPIM_CPHA_2_EDGE == cpha_mode)
{
reg_val |= FSPIM_CTRL_R0_SCPHA(FSPIM_SCPHA_SWITCH_DATA_BEG);
}
else
{
FASSERT(0);
}
FSpimSetCtrlR0(base_addr, reg_val);
}
/**
* @name: FSpimGetCpha
* @msg: 获取串行时钟相位
* @return {FSpimCphaType}串行时钟相位
* @param {uintptr} base_addr, SPI控制器基地址
*/
FSpimCphaType FSpimGetCpha(uintptr base_addr)
{
u32 reg_val = FSpimGetCtrlR0(base_addr);
if (reg_val &= FSPIM_CTRL_R0_SCPHA(FSPIM_SCPHA_SWITCH_DATA_BEG))
{
return FSPIM_CPHA_2_EDGE;
}
else
{
return FSPIM_CPHA_1_EDGE;
}
}
/**
* @name: FSpimSetCpol
* @msg: 设置串行时钟极性
* @return {无}
* @param {uintptr} base_addr, SPI控制器基地址
* @param {u32} cpol_mode, SPI控制器的极性设置
*/
void FSpimSetCpol(uintptr base_addr, u32 cpol_mode)
{
u32 reg_val = FSpimGetCtrlR0(base_addr);
reg_val &= ~FSPIM_CTRL_R0_SCPOL_MASK; /* clear bits */
if (FSPIM_CPOL_LOW == cpol_mode)
{
reg_val |= FSPIM_CTRL_R0_SCPOL(FSPIM_SCPOL_INACTIVE_LOW);
}
else if (FSPIM_CPOL_HIGH == cpol_mode)
{
reg_val |= FSPIM_CTRL_R0_SCPOL(FSPIM_SCPOL_INACTIVE_HIGH);
}
else
{
FASSERT(0);
}
FSpimSetCtrlR0(base_addr, reg_val);
}
/**
* @name: FSpimGetCpol
* @msg: 获取串行时钟极性
* @return {无}
* @param {uintptr} base_addr, SPI控制器基地址
*/
FSpimCpolType FSpimGetCpol(uintptr base_addr)
{
u32 reg_val = FSpimGetCtrlR0(base_addr);
if (reg_val &= FSPIM_CTRL_R0_SCPOL(FSPIM_SCPOL_INACTIVE_HIGH))
{
return FSPIM_CPOL_HIGH;
}
else
{
return FSPIM_CPOL_LOW;
}
}
/**
* @name: FSpimSetSlaveEnable
* @msg: 使能/去使能和从设备的连接
* @return {无}
* @param {uintptr} base_addr, SPI控制器基地址
* @param {boolean} enable, TRUE: 使能从设备, FALSE: 去使能从设备
*/
void FSpimSetSlaveEnable(uintptr base_addr, boolean enable)
{
u32 reg_val;
boolean enabled = FSpimGetEnable(base_addr);
if (enabled)
{
FSpimSetEnable(base_addr, FALSE);
}
reg_val = FSpimGetCtrlR0(base_addr);
reg_val &= ~FSPIM_CTRL_R0_SLV_OE_MASK;
if (enable)
{
reg_val |= FSPIM_CTRL_R0_SLV_OE(FSPIM_SLAVE_TX_ENABLE);
}
else
{
reg_val |= FSPIM_CTRL_R0_SLV_OE(FSPIM_SLAVE_TX_DISALE);
}
FSpimSetCtrlR0(base_addr, reg_val);
if (enabled)
{
FSpimSetEnable(base_addr, TRUE);
}
return;
}