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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|