| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- /*
- * 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: fi2c_master.c
- * Date: 2022-02-10 14:53:42
- * LastEditTime: 2022-02-18 08:36:46
- * Description: This files is for
- *
- * Modify History:
- * Ver Who Date Changes
- * ----- ------ -------- --------------------------------------
- */
- /*
- - 一些驱动模块,直接操作硬件的I/O接口,无法实现有意义的操作,此时需要针对中间件或者用户使用习惯设计此模块 (i2c,nand,eth)
- - 部分场景适用, 分角色的 I/O 操作
- - 此模块的函数原型,在fooxx.h 中声明一次,方便用户或者中间件层调用
- */
- /***************************** Include Files *********************************/
- #include "fio.h"
- #include "fsleep.h"
- #include "fdebug.h"
- #include "fi2c_hw.h"
- #include "fi2c.h"
- #include "finterrupt.h"
- /************************** Constant Definitions *****************************/
- /**************************** Type Definitions *******************************/
- /***************** Macros (Inline Functions) Definitions *********************/
- #define FI2C_DEBUG_TAG "I2C_MASTER"
- #define FI2C_ERROR(format, ...) FT_DEBUG_PRINT_E(FI2C_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FI2C_INFO(format, ...) FT_DEBUG_PRINT_I(FI2C_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FI2C_DEBUG(format, ...) FT_DEBUG_PRINT_D(FI2C_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FI2C_TIMEOUT 500
- /************************** Function Prototypes ******************************/
- /************************** Variable Definitions *****************************/
- /*****************************************************************************/
- /**
- * @name: FI2cMasterStartTrans
- * @msg: I2C主机开始传输
- * @return {*}
- * @param {FI2c} *instance_p, I2C驱动实例数据
- * @param {u32} mem_addr, 从机的片内偏移
- * @param {u8} mem_byte_len, Size of internal memory address 1->8bit ~ 4->32bit
- * @param {u8} flag ,for cmd reg STOP,RESTART.
- */
- static FError FI2cMasterStartTrans(FI2c *instance_p, u32 mem_addr, u8 mem_byte_len, u16 flag)
- {
- FASSERT(instance_p);
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FI2C_SUCCESS;
- u32 addr_len = mem_byte_len;
- ret = FI2cWaitBusBusy(base_addr);
- if (FI2C_SUCCESS != ret)
- return ret;
- ret = FI2cSetTar(base_addr, instance_p->config.slave_addr); /* 设备地址 */
- if (FI2C_SUCCESS != ret)
- return ret;
- while (addr_len)
- {
- ret = FI2cWaitStatus(base_addr, FI2C_STATUS_TFNF);
- if (FI2C_SUCCESS != ret)
- break;
- if (FI2C_GET_STATUS(base_addr) & FI2C_STATUS_TFNF)
- {
- addr_len--;
- if (addr_len != 0)
- {
- FI2C_WRITE_REG32(base_addr, FI2C_DATA_CMD_OFFSET,
- (mem_addr >> (addr_len * BITS_PER_BYTE)) & FI2C_DATA_MASK); /* word address */
- }
- else
- {
- FI2C_WRITE_REG32(base_addr, FI2C_DATA_CMD_OFFSET,
- ((mem_addr >> (addr_len * BITS_PER_BYTE)) & FI2C_DATA_MASK) + flag); /* word address */
- }
- }
- }
- return ret;
- }
- /**
- * @name: FI2cMasterStopTrans
- * @msg: I2C主机结束传输
- * @return {*}
- * @param {FI2c} *instance_p, I2C驱动实例数据
- */
- static FError FI2cMasterStopTrans(FI2c *instance_p)
- {
- FASSERT(instance_p);
- FError ret = FI2C_SUCCESS;
- uintptr base_addr = instance_p->config.base_addr;
- u32 reg_val;
- u32 timeout = 0;
- FI2C_INFO("GET MASTER STOP, stat: 0x%x, 0x%x", FI2C_READ_INTR_STAT(base_addr),
- FI2C_READ_RAW_INTR_STAT(base_addr));
- while (TRUE)
- {
- if (FI2C_READ_RAW_INTR_STAT(base_addr) & FI2C_INTR_STOP_DET)
- {
- reg_val = FI2C_READ_REG32(base_addr, FI2C_CLR_STOP_DET_OFFSET); /* read to clr intr status */
- break;
- }
- else if (FI2C_TIMEOUT < ++timeout)
- {
- break; /* wait timeout, but no error code ret */
- }
- }
- ret = FI2cWaitBusBusy(base_addr);
- if (FI2C_SUCCESS == ret)
- ret = FI2cFlushRxFifo(base_addr);
- return ret;
- }
- /**
- * @name: FI2cMasterReadPoll
- * @msg: I2C主机读,阻塞直到完成读操作或失败
- * @return {FError *} 返回错误码
- * @param {FI2c} *instance_p I2C驱动实例数据
- * @param {u32} mem_addr 从机的内部偏移地址
- * @param {u8} mem_byte_len, Size of internal memory address 1->8bit ~ 4->32bit
- * @param {u8} *buf_p 读目的缓冲区
- * @param {int} buf_len 读目的缓冲区长度
- */
- FError FI2cMasterReadPoll(FI2c *instance_p, u32 mem_addr, u8 mem_byte_len, u8 *buf_p, u32 buf_len)
- {
- FError ret = FI2C_SUCCESS;
- FASSERT(instance_p);
- u32 mask;
- u32 reg_val;
- u32 tx_len = buf_len;
- u32 rx_len = buf_len;
- u32 rx_limit, tx_limit;
- u32 trans_timeout = 0;
- uintptr base_addr = instance_p->config.base_addr;
- if (FT_COMPONENT_IS_READY != instance_p->is_ready)
- {
- FI2C_ERROR("i2c driver not ready");
- return FI2C_ERR_NOT_READY;
- }
- if (FI2C_MASTER != instance_p->config.work_mode)
- {
- FI2C_ERROR("i2c work mode shall be master");
- return FI2C_ERR_INVAL_STATE;
- }
- ret = FI2cMasterStartTrans(instance_p, mem_addr, mem_byte_len, FI2C_DATA_CMD_WRITE);
- if (FI2C_SUCCESS != ret)
- return ret;
- /*for trigger rx intr*/
- while (tx_len > 0 || rx_len > 0)
- {
- /* code */
- rx_limit = FI2C_IIC_FIFO_MAX_LV - FI2C_READ_REG32(base_addr, FI2C_RXFLR_OFFSET);
- tx_limit = FI2C_IIC_FIFO_MAX_LV - FI2C_READ_REG32(base_addr, FI2C_TXFLR_OFFSET);
- while (tx_len > 0 & rx_limit > 0 & tx_limit > 0)
- {
- /* code */
- if (tx_len == 1)
- {
- reg_val = FI2C_DATA_CMD_READ | FI2C_DATA_CMD_STOP;
- FI2C_WRITE_REG32(instance_p->config.base_addr, FI2C_DATA_CMD_OFFSET, reg_val);
- }
- else
- {
- reg_val = FI2C_DATA_CMD_READ;
- FI2C_WRITE_REG32(instance_p->config.base_addr, FI2C_DATA_CMD_OFFSET, reg_val);
- }
- tx_len--;
- rx_limit--;
- tx_limit--;
- }
- u8 rx_tem = FI2C_READ_REG32(base_addr, FI2C_RXFLR_OFFSET);
- while (rx_tem > 0 & rx_len > 0)
- {
- /* code */
- if (FI2C_GET_STATUS(base_addr) & FI2C_STATUS_RFNE)
- {
- /* trans one byte */
- *buf_p++ = FI2C_READ_DATA(base_addr);
- rx_len--;
- rx_tem--;
- trans_timeout = 0;
- }
- else if (FI2C_TIMEOUT < (++trans_timeout))
- {
- ret = FI2C_ERR_TIMEOUT;
- FI2C_ERROR("timeout in i2c master read");
- break;
- }
- }
- }
- if (FI2C_SUCCESS == ret)
- {
- ret = FI2cMasterStopTrans(instance_p);
- }
- return ret;
- }
- /**
- * @name: FI2cMasterWritePoll
- * @msg: I2C主机写,阻塞直到完成写操作或失败
- * @return {FError *} 返回错误码
- * @param {FI2c} *instance_p I2C驱动实例数据
- * @param {u32} mem_addr 从机的内部偏移地址
- * @param {u8} mem_byte_len, Size of internal memory address 1->8bit ~ 4->32bit
- * @param {u8} *buf_p 写源缓冲区
- * @param {size_t} buf_len 写源缓冲区长度
- */
- FError FI2cMasterWritePoll(FI2c *instance_p, u32 mem_addr, u8 mem_byte_len, const u8 *buf_p, u32 buf_len)
- {
- FASSERT(instance_p && buf_p);
- FError ret = FI2C_SUCCESS;
- u32 buf_idx = buf_len;
- u32 tx_limit;
- uintptr base_addr = instance_p->config.base_addr;
- u32 reg_val;
- u32 trans_timeout = 0;
- if (FT_COMPONENT_IS_READY != instance_p->is_ready)
- {
- FI2C_ERROR("i2c driver not ready");
- return FI2C_ERR_NOT_READY;
- }
- if (FI2C_MASTER != instance_p->config.work_mode)
- {
- FI2C_ERROR("i2c work mode shall be master");
- return FI2C_ERR_INVAL_STATE;
- }
- ret = FI2cMasterStartTrans(instance_p, mem_addr, mem_byte_len, FI2C_DATA_CMD_WRITE);
- if (FI2C_SUCCESS != ret)
- return ret;
- while (buf_idx)
- {
- tx_limit = FI2C_IIC_FIFO_MAX_LV - FI2C_READ_REG32(base_addr, FI2C_TXFLR_OFFSET);
- while (tx_limit > 0 & buf_idx > 0)
- {
- if (FI2C_GET_STATUS(base_addr) & FI2C_STATUS_TFNF)
- {
- if (1 == buf_idx)
- {
- reg_val = (FI2C_DATA_MASK & *buf_p) |
- FI2C_DATA_CMD_WRITE |
- FI2C_DATA_CMD_STOP;
- FI2C_INFO("Write Stop Singal");
- }
- else
- {
- reg_val = (FI2C_DATA_MASK & *buf_p) |
- FI2C_DATA_CMD_WRITE;
- }
- buf_idx--;
- tx_limit--;
- FI2C_WRITE_REG32(base_addr, FI2C_DATA_CMD_OFFSET, reg_val);
- buf_p++;
- trans_timeout = 0;
- }
- else if (FI2C_TIMEOUT < ++trans_timeout)
- {
- ret = FI2C_ERR_TIMEOUT;
- FI2C_ERROR("timeout in i2c master write");
- break;
- }
- }
- }
- if (FI2C_SUCCESS == ret)
- {
- ret = FI2cMasterStopTrans(instance_p);
- }
- return ret;
- }
- /**
- * @name: FI2cMasterReadIntr
- * @msg: I2C主机读,中断完成读操作或失败
- * @return {FError *} 返回错误码
- * @param {FI2c} *instance_p I2C驱动实例数据
- * @param {u32} mem_addr 从机的内部偏移地址
- * @param {u8} mem_byte_len, Size of internal memory address 1->8bit ~ 4->32bit
- * @param {u8} *buf_p 读目的缓冲区
- * @param {int} buf_len 读目的缓冲区长度
- */
- FError FI2cMasterReadIntr(FI2c *instance_p, u32 mem_addr, u8 mem_byte_len, u8 *buf_p, u32 buf_len)
- {
- FError ret = FI2C_SUCCESS;
- FASSERT(instance_p);
- u32 mask;
- u32 reg_val;
- u32 trans_timeout;
- if (FT_COMPONENT_IS_READY != instance_p->is_ready)
- {
- FI2C_ERROR("i2c driver not ready");
- return FI2C_ERR_NOT_READY;
- }
- if (FI2C_MASTER != instance_p->config.work_mode)
- {
- FI2C_ERROR("i2c work mode shall be master");
- return FI2C_ERR_INVAL_STATE;
- }
- while (instance_p->status != STATUS_IDLE)
- {
- /* code */
- fsleep_millisec(1);
- if (FI2C_TIMEOUT < (++trans_timeout))
- {
- ret = FI2C_ERR_TIMEOUT;
- FI2C_ERROR("timeout in i2c master read intr.");
- break;
- }
- }
- instance_p->rxframe.data_buff = buf_p;
- instance_p->rxframe.rx_total_num = buf_len;
- instance_p->txframe.tx_total_num = buf_len;
- instance_p->rxframe.rx_cnt = 0;
- FI2C_SET_RX_TL(instance_p->config.base_addr, 0);/* 0 表示接收缓冲区大于等于 1 时触发中断 */
- ret = FI2cMasterStartTrans(instance_p, mem_addr, mem_byte_len, FI2C_DATA_CMD_WRITE);
- instance_p->status = STATUS_READ_IN_PROGRESS;
- if (FI2C_SUCCESS != ret)
- return ret;
- mask = FI2C_GET_INTRRUPT_MASK(instance_p->config.base_addr);
- mask |= FI2C_INTR_MASTER_RD_MASK;
- ret = FI2cMasterSetupIntr(instance_p, mask);
- if (FI2C_SUCCESS != ret)
- return ret;
- return ret;
- }
- /**
- * @name: FI2cMasterWriteIntr
- * @msg: I2C主机写,中断写操作或失败
- * @return {FError *} 返回错误码
- * @param {FI2c} *instance_p I2C驱动实例数据
- * @param {u32} mem_addr 从机的内部偏移地址
- * @param {u8} mem_byte_len, Size of internal memory address 1->8bit ~ 4->32bit
- * @param {u8} *buf_p 写源缓冲区
- * @param {size_t} buf_len 写源缓冲区长度
- */
- FError FI2cMasterWriteIntr(FI2c *instance_p, u32 mem_addr, u8 mem_byte_len, const u8 *buf_p, u32 buf_len)
- {
- FError ret = FI2C_SUCCESS;
- FASSERT(instance_p);
- u32 mask;
- u32 trans_timeout = 0;
- if (FT_COMPONENT_IS_READY != instance_p->is_ready)
- {
- FI2C_ERROR("i2c driver not ready");
- return FI2C_ERR_NOT_READY;
- }
- if (FI2C_MASTER != instance_p->config.work_mode)
- {
- FI2C_ERROR("i2c work mode shall be master");
- return FI2C_ERR_INVAL_STATE;
- }
- while (instance_p->status != STATUS_IDLE)
- {
- /* code */
- fsleep_millisec(1);
- if (FI2C_TIMEOUT < (++trans_timeout))
- {
- ret = FI2C_ERR_TIMEOUT;
- FI2C_ERROR("timeout in i2c master write intr.");
- break;
- }
- }
- instance_p->txframe.data_buff = buf_p;
- instance_p->txframe.tx_total_num = buf_len;
- instance_p->txframe.tx_cnt = 0;
- ret = FI2cMasterStartTrans(instance_p, mem_addr, mem_byte_len, FI2C_DATA_CMD_WRITE);
- if (FI2C_SUCCESS != ret)
- return ret;
- instance_p->status = STATUS_WRITE_IN_PROGRESS;
- mask = FI2C_GET_INTRRUPT_MASK(instance_p->config.base_addr);
- mask |= FI2C_INTR_MASTER_WR_MASK;
- ret = FI2cMasterSetupIntr(instance_p, mask);
- if (FI2C_SUCCESS != ret)
- return ret;
- return ret;
- }
|