1102 lines
30 KiB
C
1102 lines
30 KiB
C
/**
|
||
* @file hgi2c_v1.c
|
||
* @author bxd
|
||
* @brief iic
|
||
* @version
|
||
* TXW81X
|
||
* @date 2023-08-02
|
||
*
|
||
* @copyright Copyright (c) 2023
|
||
*
|
||
*/
|
||
#include "typesdef.h"
|
||
#include "list.h"
|
||
#include "errno.h"
|
||
#include "dev.h"
|
||
#include "osal/semaphore.h"
|
||
#include "osal/mutex.h"
|
||
#include "osal/irq.h"
|
||
#include "osal/string.h"
|
||
#include "hal/i2c.h"
|
||
#include "dev/i2c/hgi2c_v1.h"
|
||
#include "hgi2c_v1_hw.h"
|
||
|
||
/**********************************************************************************/
|
||
/* IIC LOW LAYER FUNCTION */
|
||
/**********************************************************************************/
|
||
|
||
static inline void hgi2c_v1_set_dir_tx(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
p_i2c->CON1 |= LL_IIC_CON1_TX_EN;
|
||
}
|
||
|
||
static inline void hgi2c_v1_set_dir_rx(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
p_i2c->CON1 &= ~LL_IIC_CON1_TX_EN;
|
||
}
|
||
|
||
static inline void hgi2c_v1_set_ack(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
p_i2c->CON0 &= ~LL_IIC_CON0_TX_NACK;
|
||
}
|
||
|
||
static inline void hgi2c_v1_set_nack(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
p_i2c->CON0 |= LL_IIC_CON0_TX_NACK;
|
||
}
|
||
|
||
static inline void hgi2c_v1_set_write_table_mode(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
p_i2c->CON0 |= LL_IIC_CON0_ISP_MODE_EN;
|
||
}
|
||
static inline void hgi2c_v1_set_write_table_cmd_len(struct hgi2c_v1_hw *p_i2c, uint8 len)
|
||
{
|
||
p_i2c->CON0 = (p_i2c->CON0 & ~LL_IIC_CON0_ISP_CMD_LEN(0XF)) | LL_IIC_CON0_ISP_CMD_LEN(len);
|
||
}
|
||
static inline int32 hgi2c_v1_get_nack_pending(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
return ((p_i2c->STA2 & LL_IIC_STA2_RX_NACK(0x1)));
|
||
}
|
||
|
||
static inline int32 hgi2c_v1_get_busy(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
__NOP();__NOP();
|
||
return ((p_i2c->STA1 & LL_IIC_STA1_SSP_BUSY_PENDING));
|
||
}
|
||
|
||
static inline int32 hgi2c_v1_get_rx_ready_sta(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
return (!(p_i2c->STA1 & LL_IIC_STA1_BUF_EMPTY_PENDING));
|
||
}
|
||
|
||
static inline int32 hgi2c_v1_get_tx_ready_sta(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
return (!(p_i2c->STA1 & LL_IIC_STA1_BUF_FULL_PENDING));
|
||
}
|
||
static inline int32 hgi2c_v1_get_tx_table_sta(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
return ((p_i2c->STA1 & LL_IIC_STA1_DMA_PENDING));
|
||
}
|
||
|
||
|
||
static inline uint32 hgi2c_v1_get_slave_address(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
return ((p_i2c->OWNADRCON) & 0x3FF);
|
||
}
|
||
|
||
|
||
static inline void hgi2c_v1_write_data(struct hgi2c_v1_hw *p_i2c,uint32 data)
|
||
{
|
||
((p_i2c)->CMD_DATA = (data));
|
||
}
|
||
|
||
static inline uint32 hgi2c_v1_get_slave_address_bitwidth(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
return p_i2c->OWNADRCON & LL_IIC_OWNADRCON_OWN_ADR1_S(0x1);
|
||
}
|
||
|
||
static inline uint32 hgi2c_v1_is_slave_mode(struct hgi2c_v1_hw *p_i2c)
|
||
{
|
||
return ((p_i2c->CON1 >> 2) & BIT(0));
|
||
}
|
||
|
||
void Delay_nopCnt(uint32 cnt)
|
||
{
|
||
volatile uint32 dat;
|
||
dat = cnt;
|
||
while(dat-->0)
|
||
{
|
||
;
|
||
}
|
||
}
|
||
|
||
static inline uint32 hgi2c_v1_set_slave_addr(struct hgi2c_v1_hw *hw, uint32 addr) {
|
||
|
||
if (addr > 0x3FF) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
hw->OWNADRCON = (hw->OWNADRCON &~ LL_IIC_OWNADRCON_OWN_ADR1(0x3FF)) | LL_IIC_OWNADRCON_OWN_ADR1(addr);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
void hgi2c_v1_master_tx(struct hgi2c_v1_hw *p_iic, uint8 data, uint8 flag)
|
||
{
|
||
uint32 tx_data = data;
|
||
|
||
if(flag & LL_IIC_START_FLAG) {
|
||
tx_data |= LL_IIC_CMD_DATA_START_BIT_EN;
|
||
}
|
||
|
||
if(flag & LL_IIC_STOP_FLAG) {
|
||
tx_data |= LL_IIC_CMD_DATA_STOP_BIT_EN;
|
||
}
|
||
|
||
hgi2c_v1_set_dir_tx(p_iic);
|
||
hgi2c_v1_write_data(p_iic,tx_data);
|
||
|
||
/* Waiting for transmission to complete */
|
||
while(hgi2c_v1_get_busy(p_iic));
|
||
/* Set to input to prevent pulling SCL */
|
||
hgi2c_v1_set_dir_rx(p_iic);
|
||
}
|
||
|
||
|
||
static uint8 hgi2c_v1_master_rx(struct hgi2c_v1_hw *p_iic, uint8 flag)
|
||
{
|
||
uint32 data = 0;
|
||
|
||
if(flag & LL_IIC_NACK_FLAG) {
|
||
p_iic->CON0 |= LL_IIC_CON0_TX_NACK;
|
||
} else {
|
||
p_iic->CON0 &= ~LL_IIC_CON0_TX_NACK;
|
||
}
|
||
if(flag & LL_IIC_START_FLAG) {
|
||
data |= LL_IIC_CMD_DATA_START_BIT_EN;
|
||
}
|
||
if(flag & LL_IIC_STOP_FLAG) {
|
||
data |= LL_IIC_CMD_DATA_STOP_BIT_EN;
|
||
}
|
||
|
||
hgi2c_v1_set_dir_rx(p_iic);
|
||
/* Configure the number of data to receive */
|
||
p_iic->RDMALEN = LL_IIC_DMA_RX_LEN(1);
|
||
/* When receiving, you need to write the flag to be sent
|
||
by the host first.
|
||
*/
|
||
//p_iic->CMD_DATA = data;
|
||
hgi2c_v1_write_data(p_iic,data);
|
||
/* Waiting for transmission to complete */
|
||
while(hgi2c_v1_get_busy(p_iic));
|
||
//Delay_nopCnt(2000);
|
||
return p_iic->CMD_DATA;
|
||
}
|
||
|
||
|
||
/* Baudrate is SCL frequency for master mode, and is delay time in APB0_CLK uint for slave mode */
|
||
static int32 hgi2c_v1_set_baudrate(struct i2c_device *i2c, uint32 baudrate)
|
||
{
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
uint32 sclh_cnt = 0;
|
||
|
||
/*!
|
||
* 预分频默认16,即tPRESC = 1/(SYSCLK/16)
|
||
* sclh_cnt = (T/2) / (tPRESC),其中(T/2) = ((1/baudrate)/2)
|
||
*/
|
||
sclh_cnt = peripheral_clock_get(HG_APB0_PT_IIC0)/(16*2*baudrate);
|
||
|
||
ASSERT((sclh_cnt >= 0) && (sclh_cnt <= 2048));
|
||
|
||
hw->TIMECON = LL_IIC_TIMECON_PRESC(16-1) |\
|
||
LL_IIC_TIMECON_SCLH(sclh_cnt-1) |\
|
||
LL_IIC_TIMECON_SCLL(sclh_cnt-1) |\
|
||
LL_IIC_TIMECON_SDADEL((sclh_cnt/2)-1) |\
|
||
LL_IIC_TIMECON_SCLDEL((sclh_cnt/2)-1) ;
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hgi2c_v1_strong_output(struct i2c_device *i2c, uint32 enable) {
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1*)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
|
||
if (enable) {
|
||
hw->CON0 |= LL_IIC_CON0_STRONG_DRV_EN;
|
||
} else {
|
||
hw->CON0 &= ~ LL_IIC_CON0_STRONG_DRV_EN;
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
|
||
static int32 hgi2c_v1_filtering(struct i2c_device *i2c, uint32 value) {
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1*)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
if (value < 0 || value > 0x1F) {
|
||
return -EINVAL;
|
||
}
|
||
|
||
hw->CON0 = (hw->CON0 &~(LL_IIC_CON0_I2C_FILTER_MAX(0xFF))) | LL_IIC_CON0_I2C_FILTER_MAX(value);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
/**********************************************************************************/
|
||
/* IIC ATTCH FUNCTION */
|
||
/**********************************************************************************/
|
||
|
||
static int32 hgi2c_v1_open(struct i2c_device *i2c, enum i2c_mode mode_sel, enum i2c_addr_mode addr_bit_sel, uint32 addr) {
|
||
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
if (dev->opened) {
|
||
if (!dev->dsleep) {
|
||
return -EBUSY;
|
||
}
|
||
}
|
||
|
||
if (pin_func(i2c->dev.dev_id, 1) != RET_OK) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/*
|
||
* open IIC clk
|
||
*/
|
||
if (SPI0_BASE == (uint32)hw) {
|
||
sysctrl_spi0_clk_open();
|
||
} else if (SPI1_BASE == (uint32)hw) {
|
||
sysctrl_spi1_clk_open();
|
||
} else if (SPI2_BASE == (uint32)hw) {
|
||
sysctrl_spi2_clk_open();
|
||
}
|
||
|
||
|
||
/* clear reg */
|
||
hw->CON0 = 0;
|
||
hw->CON1 = 0;
|
||
hw->TIMECON = 0;
|
||
hw->TDMALEN = 0;
|
||
hw->RDMALEN = 0;
|
||
hw->TSTADR = 0;
|
||
hw->RSTADR = 0;
|
||
hw->OWNADRCON = 0;
|
||
hw->RXTIMEOUTCON = 0;
|
||
hw->STA1 = 0xFFFFFFFF;
|
||
hw->STA2 = 0xFFFFFFFF;
|
||
|
||
|
||
hw->CON1 = LL_IIC_CON1_IIC_SEL;
|
||
if(mode_sel == IIC_MODE_MASTER) {
|
||
hw->CON1 |= LL_IIC_CON1_MODE(0x0);
|
||
} else {
|
||
hw->CON1 |= LL_IIC_CON1_MODE(0x1);
|
||
if(addr_bit_sel == IIC_ADDR_10BIT) {
|
||
hw->OWNADRCON = LL_IIC_OWNADRCON_OWN_ADR1_S(0x1);
|
||
} else {
|
||
hw->OWNADRCON = LL_IIC_OWNADRCON_OWN_ADR1_S(0x0);
|
||
}
|
||
}
|
||
|
||
/* Open DMA tansfer done interrupt */
|
||
hw->CON1 |= LL_IIC_CON1_DMA_IE_EN;
|
||
|
||
/* Address for master mode is slave device that attempted to communicate
|
||
or itself slave address in slave mode */
|
||
hw->OWNADRCON = (hw->OWNADRCON &~ LL_IIC_OWNADRCON_OWN_ADR1(0x3FF)) | LL_IIC_OWNADRCON_OWN_ADR1(addr);
|
||
hw->CON1 |= LL_IIC_CON1_SSP_EN;
|
||
|
||
dev->opened = 1;
|
||
dev->dsleep = 0;
|
||
dev->flag_rx_done = 1;
|
||
dev->flag_tx_done = 1;
|
||
dev->flag_table_done = 1;
|
||
dev->flag_table_config_en = 0;
|
||
dev->irq_rx_done_en = 0;
|
||
dev->irq_tx_done_en = 0;
|
||
|
||
irq_enable(dev->irq_num);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hgi2c_v1_close(struct i2c_device *i2c)
|
||
{
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
if (!dev->opened) {
|
||
return RET_OK;
|
||
}
|
||
|
||
/*
|
||
* close IIC clk
|
||
*/
|
||
if (SPI0_BASE == (uint32)hw) {
|
||
sysctrl_spi0_clk_close();
|
||
} else if (SPI1_BASE == (uint32)hw) {
|
||
sysctrl_spi1_clk_close();
|
||
} else if (SPI2_BASE == (uint32)hw) {
|
||
sysctrl_spi2_clk_close();
|
||
}
|
||
|
||
|
||
irq_disable(dev->irq_num);
|
||
|
||
hw->CON1 &= ~LL_IIC_CON1_SSP_EN;
|
||
|
||
pin_func(i2c->dev.dev_id, 0);
|
||
dev->irq_hdl = NULL;
|
||
dev->irq_data = 0;
|
||
dev->opened = 0;
|
||
dev->dsleep = 0;
|
||
dev->flag_rx_done = 1;
|
||
dev->flag_tx_done = 1;
|
||
dev->irq_rx_done_en = 0;
|
||
dev->irq_tx_done_en = 0;
|
||
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
|
||
static int32 hgi2c_v1_read(struct i2c_device *i2c, int8 *addr_buf, uint32 addr_len, int8 *buf, uint32 len) {
|
||
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
uint32 slave_addr = 0;
|
||
uint32 len_temp = len;
|
||
uint32 addr_len_temp = addr_len;
|
||
uint32 len_offset = 0;
|
||
int32 ret_sema = 0;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
|
||
/* Make sure the write done */
|
||
if (!dev->flag_tx_done || !dev->flag_table_done) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* make sure that a least one buf is existent */
|
||
if ((NULL == addr_buf) && (NULL == buf)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* make sure that a least one len is existent */
|
||
if ((0 == addr_len) && (0 == len)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
os_mutex_lock(&dev->i2c_lock, osWaitForever);
|
||
|
||
/* Indcate IIC module is reading */
|
||
dev->flag_rx_done = 0;
|
||
|
||
/* IIC master mode */
|
||
if (!hgi2c_v1_is_slave_mode(hw)) {
|
||
/* set IIC to send status */
|
||
hgi2c_v1_set_dir_tx(hw);
|
||
|
||
/* send the iic slave address configured by "open" function */
|
||
slave_addr = hgi2c_v1_get_slave_address(hw);
|
||
|
||
if(hgi2c_v1_get_slave_address_bitwidth(hw) == IIC_ADDR_10BIT) {
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_START_BIT_EN | LL_IIC_CMD_DATA_WRITE(slave_addr >> 8 << 1) | 0xf0;
|
||
/* It doesn't stop here when mode is IIC master */
|
||
while (hgi2c_v1_get_busy(hw));
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_WRITE(slave_addr);
|
||
} else {
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_START_BIT_EN | LL_IIC_CMD_DATA_WRITE(slave_addr << 1);
|
||
}
|
||
|
||
/* It doesn't stop here when mode is IIC master */
|
||
while (hgi2c_v1_get_busy(hw));
|
||
|
||
/* send the addr, may be register address */
|
||
while(addr_len_temp > 0) {
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_WRITE(*addr_buf++);
|
||
addr_len_temp--;
|
||
/* It doesn't stop here when mode is IIC master */
|
||
while (hgi2c_v1_get_busy(hw));
|
||
}
|
||
|
||
if(hgi2c_v1_get_slave_address_bitwidth(hw) == IIC_ADDR_10BIT) {
|
||
// 10bit read operate only need first byte
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_START_BIT_EN | LL_IIC_CMD_DATA_WRITE(slave_addr >> 8 << 1) | 0xf1;
|
||
} else {
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_START_BIT_EN | LL_IIC_CMD_DATA_WRITE(slave_addr << 1) | 0x1;
|
||
}
|
||
while (hgi2c_v1_get_busy(hw));
|
||
}
|
||
|
||
/* set IIC to receive status */
|
||
hgi2c_v1_set_dir_rx(hw);
|
||
|
||
/* data length more than 4095 byte(limited by hardware) */
|
||
len_offset = 0;
|
||
if (len_temp >= 4095) {
|
||
|
||
do {
|
||
/* set ACK when receive data */
|
||
hgi2c_v1_set_ack(hw);
|
||
|
||
hw->RSTADR = (uint32)(buf + len_offset);
|
||
hw->RDMALEN = 4095;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
/* DMA interrupt to sema_up */
|
||
/* master use 6s for timeout */
|
||
/* slave use wait forever */
|
||
if (!hgi2c_v1_is_slave_mode(hw)) {
|
||
ret_sema = os_sema_down(&dev->i2c_done, 6*1000);
|
||
if (!ret_sema) {
|
||
_os_printf("***IIC modoule info: M read err, 1 phase timeout!\r\n");
|
||
goto err_handle;
|
||
}
|
||
} else {
|
||
os_sema_down(&dev->i2c_done, osWaitForever);
|
||
}
|
||
|
||
len_offset += 4095;
|
||
}while ((len_temp -= 4095) >= 4095);
|
||
}
|
||
|
||
/* IIC master mode need to send the stop signal & NACK in last byte */
|
||
if (!hgi2c_v1_is_slave_mode(hw)) {
|
||
|
||
/* make sure the remain (len-1) more than 0 */
|
||
if (len_temp - 1) {
|
||
|
||
/* set ACK when receive data */
|
||
hgi2c_v1_set_ack(hw);
|
||
|
||
hw->RSTADR = (uint32)(buf + len_offset);
|
||
hw->RDMALEN = len_temp - 1;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
/* DMA interrupt to sema_up */
|
||
/* master use 6s for timeout */
|
||
ret_sema = os_sema_down(&dev->i2c_done, 6*1000);
|
||
if (!ret_sema) {
|
||
_os_printf("***IIC modoule info: M read err, 2 phase timeout!\r\n");
|
||
goto err_handle;
|
||
}
|
||
|
||
len_offset += (len_temp - 1);
|
||
}
|
||
|
||
/* set NACK when receive the last byte */
|
||
hgi2c_v1_set_nack(hw);
|
||
|
||
//send the last byte with the stop signal
|
||
while (hgi2c_v1_get_busy(hw));
|
||
hw->RDMALEN = 1;
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_STOP_BIT_EN | LL_IIC_CMD_DATA_WRITE(0x00);
|
||
while (hgi2c_v1_get_busy(hw));
|
||
/* Read the last from hardware */
|
||
*(buf+len_offset) = hw->CMD_DATA;
|
||
|
||
} else {
|
||
/* make sure the remain (len-1) more than 0 */
|
||
if (len_temp - 1) {
|
||
/* set ACK when receive data */
|
||
hgi2c_v1_set_ack(hw);
|
||
|
||
hw->RSTADR = (uint32)(buf + len_offset);
|
||
hw->RDMALEN = len_temp - 1;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
/* DMA interrupt to sema_up */
|
||
/* slave use wait forever */
|
||
os_sema_down(&dev->i2c_done, osWaitForever);
|
||
len_offset += (len_temp - 1);
|
||
}
|
||
|
||
/* set NACK when receive the last byte */
|
||
hgi2c_v1_set_nack(hw);
|
||
|
||
hw->RSTADR = (uint32)(buf + len_offset);
|
||
hw->RDMALEN = 1;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
/* DMA interrupt to sema_up */
|
||
/* slave use wait forever */
|
||
os_sema_down(&dev->i2c_done, osWaitForever);
|
||
len_offset += 1;
|
||
}
|
||
|
||
if (dev->irq_rx_done_en) {
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(I2C_IRQ_FLAG_RX_DONE, dev->irq_data, 0, 0);
|
||
}
|
||
}
|
||
|
||
err_handle:
|
||
|
||
os_mutex_unlock(&dev->i2c_lock);
|
||
|
||
/* Indcate IIC module has read done */
|
||
dev->flag_rx_done = 1;
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hgi2c_v1_write(struct i2c_device *i2c, int8 *addr_buf, uint32 addr_len, int8 *buf, uint32 len) {
|
||
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
uint32 slave_addr = 0;
|
||
uint32 len_temp = len;
|
||
uint32 addr_len_temp = addr_len;
|
||
uint32 len_offset = 0;
|
||
int32 ret_sema = 0;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* Make sure the read done */
|
||
if (!dev->flag_rx_done || !dev->flag_table_done) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* make sure that a least one buf is existent */
|
||
if ((NULL == addr_buf) && (NULL == buf)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* make sure that a least one len is existent */
|
||
if ((0 == addr_len) && (0 == len)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
os_mutex_lock(&dev->i2c_lock, osWaitForever);
|
||
|
||
/* Indcate IIC module is writing */
|
||
dev->flag_tx_done = 0;
|
||
|
||
/* set IIC to send status */
|
||
hgi2c_v1_set_dir_tx(hw);
|
||
|
||
|
||
/* IIC master mode */
|
||
if (!hgi2c_v1_is_slave_mode(hw)) {
|
||
/* send the iic slave address configured by "open" function */
|
||
slave_addr = hgi2c_v1_get_slave_address(hw);
|
||
|
||
if(hgi2c_v1_get_slave_address_bitwidth(hw) == IIC_ADDR_10BIT) {
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_START_BIT_EN | LL_IIC_CMD_DATA_WRITE(slave_addr >> 8 << 1) | 0xf0;
|
||
/* It doesn't stop here when mode is IIC master */
|
||
while (hgi2c_v1_get_busy(hw));
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_WRITE(slave_addr);
|
||
} else {
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_START_BIT_EN | LL_IIC_CMD_DATA_WRITE(slave_addr << 1);
|
||
}
|
||
|
||
/* It doesn't stop here when mode is IIC master */
|
||
while (hgi2c_v1_get_busy(hw));
|
||
|
||
/* send the addr, may be register address */
|
||
while(addr_len_temp > 0) {
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_WRITE(*addr_buf++);
|
||
addr_len_temp--;
|
||
/* It doesn't stop here when mode is IIC master */
|
||
while (hgi2c_v1_get_busy(hw));
|
||
}
|
||
}
|
||
|
||
/* data length more than 4095 byte(limited by hardware) */
|
||
len_offset = 0;
|
||
if (len_temp >= 4095) {
|
||
do {
|
||
hw->TSTADR = (uint32)(buf + len_offset);
|
||
hw->TDMALEN = 4095;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
/* DMA interrupt to sema_up */
|
||
/* master use 6s for timeout */
|
||
/* slave use wait forever */
|
||
if (!hgi2c_v1_is_slave_mode(hw)) {
|
||
ret_sema = os_sema_down(&dev->i2c_done, 6*1000);
|
||
if (!ret_sema) {
|
||
_os_printf("***IIC modoule info: M send err, 1 phase timeout!\r\n");
|
||
goto err_handle;
|
||
}
|
||
} else {
|
||
os_sema_down(&dev->i2c_done, osWaitForever);
|
||
}
|
||
|
||
len_offset += 4095;
|
||
}while ((len_temp -= 4095) >= 4095);
|
||
}
|
||
|
||
/* IIC master mode need to send the stop signal in last byte */
|
||
if (!hgi2c_v1_is_slave_mode(hw)) {
|
||
|
||
if(len_temp == 0) {
|
||
goto err_handle;
|
||
}
|
||
|
||
/* make sure the remain (len-1) more than 0 */
|
||
if (len_temp - 1) {
|
||
hw->TSTADR = (uint32)(buf + len_offset);
|
||
hw->TDMALEN = len_temp - 1;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
/* DMA interrupt to sema_up */
|
||
/* master use 6s for timeout */
|
||
ret_sema = os_sema_down(&dev->i2c_done, 6*1000);
|
||
if (!ret_sema) {
|
||
_os_printf("***IIC modoule info: M send err, 2 phase timeout!\r\n");
|
||
goto err_handle;
|
||
}
|
||
|
||
len_offset += (len_temp - 1);
|
||
}
|
||
|
||
//send the last byte with the stop signal
|
||
while (hgi2c_v1_get_busy(hw));
|
||
hw->CMD_DATA = LL_IIC_CMD_DATA_STOP_BIT_EN | LL_IIC_CMD_DATA_WRITE(*(buf+len_offset));
|
||
while (hgi2c_v1_get_busy(hw));
|
||
|
||
} else {
|
||
/* make sure the remain (len-1) more than 0 */
|
||
if (len_temp) {
|
||
hw->TSTADR = (uint32)(buf + len_offset);
|
||
hw->TDMALEN = len_temp;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
/* DMA interrupt to sema_up */
|
||
/* slave use wait forever */
|
||
os_sema_down(&dev->i2c_done, osWaitForever);
|
||
len_offset += (len_temp);
|
||
}
|
||
}
|
||
|
||
if (dev->irq_tx_done_en) {
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(I2C_IRQ_FLAG_TX_DONE, dev->irq_data, 0, 0);
|
||
}
|
||
}
|
||
|
||
err_handle:
|
||
|
||
os_mutex_unlock(&dev->i2c_lock);
|
||
|
||
/* Indcate IIC module has written done */
|
||
dev->flag_tx_done = 1;
|
||
|
||
return RET_OK;
|
||
|
||
}
|
||
|
||
static int32 hgi2c_v1_write_table(struct i2c_device *i2c, uint8 cmd_len, uint8 slave_id, scatter_data *data)
|
||
{
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
int32 ret_sema = 0;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* Make sure the read done */
|
||
if (!dev->flag_rx_done || !dev->flag_tx_done || !dev->flag_table_config_en || !dev->flag_table_done) {
|
||
if (!dev->flag_table_config_en) os_printf("unenable iic write_table_mode!!!");
|
||
if (!dev->flag_table_done) os_printf("iic write table status busy ");
|
||
return RET_ERR;
|
||
}
|
||
|
||
if ((cmd_len == 0) || (slave_id == 0)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
if ((data->size == 0) || (data->addr == NULL)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
// if (pin_func(i2c->dev.dev_id, 1) != RET_OK) {
|
||
// return RET_ERR;
|
||
// }
|
||
|
||
os_mutex_lock(&dev->i2c_lock, osWaitForever);
|
||
|
||
dev->flag_table_done = 0;
|
||
|
||
hgi2c_v1_set_dir_tx(hw);
|
||
hgi2c_v1_set_write_table_cmd_len(hw, cmd_len);
|
||
hgi2c_v1_set_slave_addr(hw, (slave_id << 1));
|
||
|
||
|
||
hw->TSTADR = (uint32)data->addr;
|
||
hw->TDMALEN = data->size;
|
||
hw->CON1 |= LL_IIC_CON1_DMA_EN; /* kick DMA */
|
||
|
||
ret_sema = os_sema_down(&dev->i2c_done, 6*1000);
|
||
if (!ret_sema) {
|
||
_os_printf("***IIC modoule info: M send err, write_talbe timeout!\r\n");
|
||
goto err_handle;
|
||
}
|
||
|
||
err_handle:
|
||
|
||
os_mutex_unlock(&dev->i2c_lock);
|
||
|
||
dev->flag_table_done = 1;
|
||
return RET_OK;
|
||
}
|
||
|
||
#ifdef CONFIG_SLEEP
|
||
static int32 hgi2c_v1_suspend(struct dev_obj *obj)
|
||
{
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)obj;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_OK;
|
||
}
|
||
|
||
if (0 > os_mutex_lock(&dev->bp_suspend_lock, 10000)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
|
||
// pin_func(dev->dev.dev.dev_id, 0);
|
||
|
||
/*!
|
||
* Close the IIC
|
||
*/
|
||
hw->CON1 &= ~ BIT(0);
|
||
|
||
|
||
/*
|
||
* close irq
|
||
*/
|
||
irq_disable(dev->irq_num);
|
||
|
||
/*
|
||
* clear pending
|
||
*/
|
||
hw->STA1 = 0xFFFFFFFF;
|
||
hw->STA2 = 0xFFFFFFFF;
|
||
|
||
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
|
||
|
||
/*
|
||
* save the reglist
|
||
*/
|
||
dev->bp_regs.con0 = hw->CON0;
|
||
dev->bp_regs.con1 = hw->CON1;
|
||
dev->bp_regs.timecon = hw->TIMECON;
|
||
dev->bp_regs.tdmalen = hw->TDMALEN;
|
||
dev->bp_regs.rdmalen = hw->RDMALEN;
|
||
dev->bp_regs.tstadr = hw->TSTADR;
|
||
dev->bp_regs.rstadr = hw->RSTADR;
|
||
dev->bp_regs.slavesta = hw->SLAVESTA;
|
||
dev->bp_regs.ownadrcon = hw->OWNADRCON;
|
||
dev->bp_regs.timeoutcon = hw->TIMEOUTCON;
|
||
dev->bp_regs.rxtimeoutcon = hw->RXTIMEOUTCON;
|
||
dev->bp_regs.rstadr1 = hw->RSTADR1;
|
||
dev->bp_regs.vsync_tcon = hw->VSYNC_TCON;
|
||
dev->bp_regs.hsync_tcon = hw->HSYNC_TCON;
|
||
|
||
|
||
/*
|
||
* save the irq_hdl created by user
|
||
*/
|
||
dev->bp_irq_hdl = dev->irq_hdl;
|
||
dev->bp_irq_data = dev->irq_data;
|
||
|
||
/*
|
||
* close IIC clk
|
||
*/
|
||
if (SPI0_BASE == (uint32)hw) {
|
||
sysctrl_spi0_clk_close();
|
||
} else if (SPI1_BASE == (uint32)hw) {
|
||
sysctrl_spi1_clk_close();
|
||
} else if (SPI2_BASE == (uint32)hw) {
|
||
sysctrl_spi2_clk_close();
|
||
}
|
||
|
||
dev->dsleep = 1;
|
||
|
||
os_mutex_unlock(&dev->bp_suspend_lock);
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hgi2c_v1_resume(struct dev_obj *obj)
|
||
{
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)obj;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (!dev->dsleep)) {
|
||
return RET_OK;
|
||
}
|
||
|
||
if (0 > os_mutex_lock(&dev->bp_resume_lock, 10000)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
/* pin config */
|
||
// if (pin_func(dev->dev.dev.dev_id , 1) != RET_OK) {
|
||
// return RET_ERR;
|
||
// }
|
||
|
||
|
||
/*
|
||
* recovery the IIC clk
|
||
*/
|
||
if (SPI0_BASE == (uint32)hw) {
|
||
sysctrl_spi0_clk_open();
|
||
sysctrl_display_clk_open();
|
||
} else if (SPI1_BASE == (uint32)hw) {
|
||
sysctrl_spi1_clk_open();
|
||
sysctrl_display_clk_open();
|
||
} else if (SPI2_BASE == (uint32)hw) {
|
||
sysctrl_spi2_clk_open();
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
* recovery the reglist from sram
|
||
*/
|
||
hw->CON0 = dev->bp_regs.con0;
|
||
hw->CON1 = dev->bp_regs.con1;
|
||
hw->TIMECON = dev->bp_regs.timecon;
|
||
hw->TDMALEN = dev->bp_regs.tdmalen;
|
||
hw->RDMALEN = dev->bp_regs.rdmalen;
|
||
hw->TSTADR = dev->bp_regs.tstadr;
|
||
hw->RSTADR = dev->bp_regs.rstadr;
|
||
hw->SLAVESTA = dev->bp_regs.slavesta;
|
||
hw->OWNADRCON = dev->bp_regs.ownadrcon;
|
||
hw->TIMEOUTCON = dev->bp_regs.timeoutcon;
|
||
hw->RXTIMEOUTCON = dev->bp_regs.rxtimeoutcon;
|
||
hw->RSTADR1 = dev->bp_regs.rstadr1;
|
||
hw->VSYNC_TCON = dev->bp_regs.vsync_tcon;
|
||
hw->HSYNC_TCON = dev->bp_regs.hsync_tcon;
|
||
|
||
|
||
/*
|
||
* recovery the irq handle and data
|
||
*/
|
||
dev->irq_hdl = dev->bp_irq_hdl;
|
||
dev->irq_data = dev->bp_irq_data;
|
||
|
||
os_memset((void *)&dev->bp_regs, 0, sizeof(dev->bp_regs));
|
||
|
||
/*!
|
||
* Open the IIC
|
||
*/
|
||
hw->CON1 |= BIT(0);
|
||
|
||
|
||
/*
|
||
* open irq
|
||
*/
|
||
irq_enable(dev->irq_num);
|
||
|
||
dev->dsleep = 0;
|
||
|
||
os_mutex_unlock(&dev->bp_resume_lock);
|
||
|
||
return RET_OK;
|
||
}
|
||
#endif
|
||
|
||
static int32 hgi2c_v1_ioctl(struct i2c_device *i2c, int32 cmd, uint32 param)
|
||
{
|
||
int32 ret_val = RET_OK;
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw*)( ( (struct hgi2c_v1 *)i2c )->hw );
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
switch (cmd) {
|
||
case (IIC_SET_DEVICE_ADDR):
|
||
ret_val = hgi2c_v1_set_slave_addr(hw, param);
|
||
break;
|
||
case (IIC_FILTERING):
|
||
ret_val = hgi2c_v1_filtering(i2c, param);
|
||
break;
|
||
case (IIC_STRONG_OUTPUT):
|
||
ret_val = hgi2c_v1_strong_output(i2c, param);
|
||
break;
|
||
case (IIC_SET_WRITE_TABLE_MODE) :
|
||
hgi2c_v1_set_write_table_mode(hw);
|
||
dev->flag_table_config_en = 1;
|
||
break;
|
||
case (IIC_GET_TX_STATUS):
|
||
if(dev->flag_table_done == 1){
|
||
ret_val = 1;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
ret_val = -ENOTSUPP;
|
||
break;
|
||
}
|
||
|
||
return ret_val;
|
||
}
|
||
|
||
/**
|
||
* @brief IIC0 Interrupt handler
|
||
* @param None.
|
||
* @retval None.
|
||
*/
|
||
static void hgi2c_v1_irq_handler(void *data)
|
||
{
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)data;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
/* DMA Done interrupt */
|
||
if ((hw->CON1 & LL_IIC_CON1_DMA_IE_EN) && (hw->STA1 & LL_IIC_STA1_DMA_PENDING)) {
|
||
/* clear interrupt flag */
|
||
hw->STA1 = LL_IIC_STA1_DMA_PENDING;
|
||
os_sema_up(&dev->i2c_done);
|
||
}
|
||
|
||
/* I2C_IRQ_FLAG_RX_NACK */
|
||
if ((hw->CON0 & LL_IIC_CON0_RX_NACK_IE_EN) && (hw->STA2 & LL_IIC_STA2_RX_NACK(1))) {
|
||
/* clear interrupt flag */
|
||
hw->STA2 = LL_IIC_STA2_RX_NACK(1);
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(I2C_IRQ_FLAG_RX_NACK, dev->irq_data, 0, 0);
|
||
}
|
||
}
|
||
|
||
/* I2C_IRQ_FLAG_RX_ERROR */
|
||
if ((hw->CON1 & LL_IIC_CON1_BUF_OV_IE_EN) && (hw->STA1 & LL_IIC_STA1_BUF_OV_PENDING)) {
|
||
/* clear interrupt flag */
|
||
hw->STA1 = LL_IIC_STA1_BUF_OV_PENDING;
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(I2C_IRQ_FLAG_RX_ERROR, dev->irq_data, 0, 0);
|
||
}
|
||
}
|
||
|
||
/* I2C_IRQ_FLAG_DETECT_STOP */
|
||
if ((hw->CON0 & LL_IIC_CON0_STOP_IE_EN) && (hw->STA2 & LL_IIC_STA2_STOP_PEND(1))) {
|
||
/* clear interrupt flag */
|
||
hw->STA2 = LL_IIC_STA2_STOP_PEND(1);
|
||
if (dev->irq_hdl) {
|
||
dev->irq_hdl(I2C_IRQ_FLAG_DETECT_STOP, dev->irq_data, 0, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
static int32 hgi2c_v1_request_irq(struct i2c_device *i2c, i2c_irq_hdl irqhdl, uint32 irq_data, uint32 irq_flag)
|
||
{
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
dev->irq_hdl = irqhdl;
|
||
dev->irq_data = irq_data;
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_TX_DONE) {
|
||
dev->irq_tx_done_en = 1;
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_RX_DONE) {
|
||
dev->irq_rx_done_en = 1;
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_DETECT_STOP) {
|
||
hw->CON0 |= BIT(20);
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_RX_NACK) {
|
||
hw->CON0 |= BIT(22);
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_RX_ERROR) {
|
||
hw->CON1 |= BIT(8);
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_SLAVE_ADDRESSED) {
|
||
hw->CON0 |= BIT(19);
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static int32 hgi2c_v1_release_irq(struct i2c_device *i2c, uint32 irq_flag) {
|
||
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
struct hgi2c_v1_hw *hw = (struct hgi2c_v1_hw *)dev->hw;
|
||
|
||
if ((!dev->opened) || (dev->dsleep)) {
|
||
return RET_ERR;
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_TX_DONE) {
|
||
dev->irq_tx_done_en = 0;
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_RX_DONE) {
|
||
dev->irq_rx_done_en = 0;
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_DETECT_STOP) {
|
||
hw->CON0 &= ~ BIT(20);
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_RX_NACK) {
|
||
hw->CON0 &= ~ BIT(22);
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_RX_ERROR) {
|
||
hw->CON1 &= ~ BIT(8);
|
||
}
|
||
|
||
if (irq_flag & I2C_IRQ_FLAG_SLAVE_ADDRESSED) {
|
||
hw->CON0 &= ~ BIT(19);
|
||
}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static const struct i2c_hal_ops i2c_ops = {
|
||
|
||
.open = hgi2c_v1_open,
|
||
.close = hgi2c_v1_close,
|
||
.ioctl = hgi2c_v1_ioctl,
|
||
.baudrate = hgi2c_v1_set_baudrate,
|
||
.request_irq = hgi2c_v1_request_irq,
|
||
.read = hgi2c_v1_read,
|
||
.write = hgi2c_v1_write,
|
||
.write_table = hgi2c_v1_write_table,
|
||
.release_irq = hgi2c_v1_release_irq,
|
||
#ifdef CONFIG_SLEEP
|
||
.ops.suspend = hgi2c_v1_suspend,
|
||
.ops.resume = hgi2c_v1_resume,
|
||
#endif
|
||
};
|
||
|
||
int32 hgi2c_v1_attach(uint32 dev_id, struct hgi2c_v1 *i2c)
|
||
{
|
||
|
||
struct hgi2c_v1 *dev = (struct hgi2c_v1 *)i2c;
|
||
|
||
i2c->dev.dev.ops = (const struct devobj_ops *)&i2c_ops;
|
||
i2c->irq_hdl = NULL;
|
||
i2c->irq_data = 0;
|
||
i2c->opened = 0;
|
||
i2c->dsleep = 0;
|
||
i2c->flag_rx_done = 1;
|
||
i2c->flag_tx_done = 1;
|
||
i2c->irq_rx_done_en = 0;
|
||
i2c->irq_tx_done_en = 0;
|
||
|
||
#ifdef CONFIG_SLEEP
|
||
os_mutex_init(&i2c->bp_suspend_lock);
|
||
os_mutex_init(&i2c->bp_resume_lock);
|
||
#endif
|
||
|
||
os_mutex_init(&i2c->i2c_lock);
|
||
os_sema_init(&i2c->i2c_done, 0);
|
||
|
||
request_irq(dev->irq_num, hgi2c_v1_irq_handler, dev);
|
||
|
||
dev_register(dev_id, (struct dev_obj *)i2c);
|
||
return RET_OK;
|
||
}
|
||
|
||
|