fspim_hw.c 7.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
/*
 * 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 files is for
 *
 * Modify History:
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 * 1.0   zhugengyu  2021-12-3   init commit
 * 1.1   zhugengyu  2022-4-15   support test mode
 */


#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("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("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)
{
    u32 clk_div;
    boolean enabled = FSpimGetEnable(base_addr);

    if (enabled)
        FSpimSetEnable(base_addr, FALSE);

    clk_div = FSPI_FREQ / speed;
    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: 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: 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: 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;
}