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

1102 lines
30 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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;
}