Files
TAIXIN/sdk/driver/i2c/hgi2c_v1.c

1102 lines
30 KiB
C
Raw Normal View History

/**
* @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;
/*!
* 16tPRESC = 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;
}