mcu_ab568x/app/platform/bsp/bsp_i2c.c
2025-05-30 18:03:10 +08:00

400 lines
9.6 KiB
C

#include "include.h"
#define TRACE_EN 0
#if TRACE_EN
#define TRACE(...) printf(__VA_ARGS__)
#define TRACE_K(...) printk(__VA_ARGS__)
#else
#define TRACE(...)
#define TRACE_K(...)
#endif
#if I2C_SW_EN
//AT(.text.bsp.i2c)
//static void bsp_i2c_delay(void)
//{
// u8 delay = 60;
// while (delay--) {
// asm("nop");
// }
//}
#define bsp_i2c_delay() delay_us(5)
//ACK: The transmitter releases the SDA line (HIGH->LOW) during the acknowledge clock pulse
AT(.text.bsp.i2c)
void bsp_i2c_tx_ack(void)
{
I2C_SDA_OUT();
I2C_SDA_L();
bsp_i2c_delay();
I2C_SCL_H();
bsp_i2c_delay();
I2C_SCL_L();
}
AT(.text.bsp.i2c)
bool bsp_i2c_rx_ack(void)
{
bool ret = false;
I2C_SDA_IN();
bsp_i2c_delay();
I2C_SCL_H();
bsp_i2c_delay();
if (!I2C_SDA_IS_H()) {
ret = true;
}
I2C_SCL_L();
return ret;
}
//NACK: The transmitter holds the SDA line (keep HIGH) during the acknowledge clock pulse
AT(.text.bsp.i2c)
void bsp_i2c_tx_nack(void)
{
I2C_SDA_OUT();
I2C_SDA_H();
bsp_i2c_delay();
I2C_SCL_H();
bsp_i2c_delay();
I2C_SCL_L();
}
//START: A HIGH to LOW transition on the SDA line while SCL is HIGH is one such unique case.
AT(.text.bsp.i2c)
void bsp_i2c_start(void)
{
I2C_SDA_SCL_OUT();
I2C_SDA_SCL_H();
bsp_i2c_delay();
I2C_SDA_L();
bsp_i2c_delay();
I2C_SCL_L();
}
//STOP: A LOW to HIGH transition on the SDA line while SCL is HIGH
AT(.text.bsp.i2c)
void bsp_i2c_stop(void)
{
I2C_SDA_OUT();
I2C_SDA_L();
bsp_i2c_delay();
I2C_SCL_H();
bsp_i2c_delay();
I2C_SDA_H();
}
//tx 1byte
AT(.text.bsp.i2c)
void bsp_i2c_tx_byte(uint8_t dat)
{
u8 i;
I2C_SDA_OUT();
for (i=0; i<8; i++) {
if (dat & BIT(7)) {
I2C_SDA_H();
} else {
I2C_SDA_L();
}
bsp_i2c_delay();
I2C_SCL_H();
bsp_i2c_delay();
I2C_SCL_L();
dat <<= 1;
}
}
//rx 1byte
AT(.text.bsp.i2c)
uint8_t bsp_i2c_rx_byte(void)
{
u8 i, dat = 0;
I2C_SDA_IN();
for (i=0; i<8; i++) {
bsp_i2c_delay();
I2C_SCL_H();
bsp_i2c_delay();
dat <<= 1;
if (I2C_SDA_IS_H()) {
dat |= BIT(0);
}
I2C_SCL_L();
}
return dat;
}
#endif //I2C_SW_EN
#if I2C_HW_EN
#if CHIP_PACKAGE_QFN40
static i2c_t __IIC0 = {
.sfr = (i2c_sfr_t *)&IIC0CON0,
.map = (i2c_map_t *)&FUNCMCON2,
};
i2c_t *HW_IIC = &__IIC0;
#else
#if (CHIP_PACKAGE_SELECT == CHIP_5682C)
static i2c_t __IIC0 = {
.sfr = (i2c_sfr_t *)&IIC0CON0,
.map = (i2c_map_t *)&FUNCMCON2,
};
i2c_t *HW_IIC = &__IIC0;
#else
static i2c_t __IIC1 = {
.sfr = (i2c_sfr_t *)&IIC1CON0,
.map = (i2c_map_t *)&FUNCMCON2,
};
i2c_t *HW_IIC = &__IIC1;
#endif
#endif
void bsp_i2c0_lock(void)
{
os_i2c0_lock(100);
}
void bsp_i2c0_unlock(void)
{
os_i2c0_unlock();
}
AT(.com_text.str)
char str_tmp[] = ">>>bsp_i2c_isr\n";
AT(.com_text.isr.i2c)
void bsp_i2c_isr(void)
{
if (HW_IIC->sfr->IICxCON0 & BIT(31)) {
HW_IIC->sfr->IICxCON0 |= BIT(29); // clear pending
HW_IIC->sfr->IICxCON0 &= ~BIT(1); // disable irq
HW_IIC->sfr->IICxDMACNT = 0; // Disable DMA
// printf(str_tmp);
}
}
static u32 bsp_hw_i2c_config(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u32 dat)
{
TRACE("%s: cfg=%X dev=%X reg=%X\n", __FUNCTION__, i2c_cfg, dev_addr, reg_addr);
HW_IIC->sfr->IICxCMDA = (u8)dev_addr | ((u32)(dev_addr >> 8)) << 24 |
(u32)((u8)reg_addr) << 8 | (u32)((u8)(reg_addr >> 8)) << 16;
HW_IIC->sfr->IICxCON1 = i2c_cfg;
HW_IIC->sfr->IICxDATA = dat;
HW_IIC->sfr->IICxCON0 |= BIT(28); // kick
u32 ticks = tick_get();
while ((!(HW_IIC->sfr->IICxCON0 & BIT(31)))) {
if (tick_check_expire(ticks, 20)) {
TRACE("IIC ERROR[%x %x %x %x]\n", i2c_cfg, dev_addr, reg_addr, dat);
return false;
}
}
HW_IIC->sfr->IICxCON0 |= BIT(29);
if (i2c_cfg & RDATA) {
return HW_IIC->sfr->IICxDATA;
} else {
return true;
}
}
void bsp_hw_i2c_tx_byte(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u32 data)
{
bsp_i2c0_lock();
bsp_hw_i2c_config(i2c_cfg, dev_addr, reg_addr, data);
bsp_i2c0_unlock();
}
void bsp_hw_i2c_tx_buf(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u8 *buf, u16 len)
{
int i;
u32 cfg;
if (buf == NULL || len == 0) {
return;
}
bsp_i2c0_lock();
for (i = 0; i < len; i++) {
cfg = WDATA;
if (i == 0) { //收第1byte
cfg |= i2c_cfg;
}
if (i == (len - 1)) { //收最后1byte
cfg |= STOP_FLAG;
}
bsp_hw_i2c_config(cfg | DATA_CNT_1B, dev_addr, reg_addr, buf[i]);
}
bsp_i2c0_unlock();
}
void bsp_hw_i2c_rx_buf(u32 i2c_cfg, u16 dev_addr, u16 reg_addr, u8 *buf, u16 len)
{
int i;
u32 cfg;
if (buf == NULL || len == 0) {
return;
}
bsp_i2c0_lock();
for (i = 0; i < len; i++) {
cfg = RDATA;
if (i == 0) { //收第1byte
cfg |= i2c_cfg;
}
if (i == (len - 1)) { //收最后1byte
cfg |= STOP_FLAG | NACK;
}
buf[i] = bsp_hw_i2c_config(cfg | DATA_CNT_1B, dev_addr, reg_addr, 0);
}
bsp_i2c0_unlock();
}
void i2c_init(void)
{
#if CHIP_PACKAGE_QFN40
CLKCON1 |= BIT(7); // x26m_clkdiv8
CLKGAT2 |= BIT(0); // en iic0 clk
RSTCON0 |= BIT(3); // Release IIC0
#else
#if (CHIP_PACKAGE_SELECT == CHIP_5682C)
CLKCON1 |= BIT(7); // x26m_clkdiv8
CLKGAT2 |= BIT(0); // en iic0 clk
RSTCON0 |= BIT(3); // Release IIC0
#else
CLKCON1 |= BIT(8); // x26m_clkdiv8
CLKGAT2 |= BIT(1); // en iic1 clk
RSTCON0 |= BIT(7); // Release IIC1
#endif
#endif
#if CHIP_PACKAGE_QFN40
GPIOEDIR |= BIT(4) | BIT(5); // SCL SDA
GPIOEPU |= BIT(4) | BIT(5);
GPIOEDE |= BIT(4) | BIT(5);
GPIOEFEN |= BIT(4) | BIT(5);
#else
GPIOBDIR |= BIT(2) | BIT(1); // SCL SDA
GPIOBPU |= BIT(2) | BIT(1);
GPIOBDE |= BIT(2) | BIT(1);
GPIOBFEN |= BIT(2) | BIT(1);
#endif
#if CHIP_PACKAGE_QFN40
HW_IIC->map->FUNCMCONx = (0xf << 8);
HW_IIC->map->FUNCMCONx = (4 << 8);
#else
#if (CHIP_PACKAGE_SELECT == CHIP_5682C)
HW_IIC->map->FUNCMCONx = (0xf << 8);
HW_IIC->map->FUNCMCONx = (2 << 8);
#else
HW_IIC->map->FUNCMCONx = (0xf << 12);
HW_IIC->map->FUNCMCONx = (2 << 12);
#endif
#endif
HW_IIC->sfr->IICxCON0 = 1 << 0 | // IIC EN
0 << 1 | // IIC INT
0 << 2 | // IIC HOLD CNT [3:2]
20 << 4 | // IIC POSDIV [9:4]
1 << 10; // IIC WSCL_OPT
delay_5ms(8);
}
#endif
#if SECURITY_PAY_EN
static i2c_t __IIC1 = {
.sfr = (i2c_sfr_t *) &IIC1CON0,
.map = (i2c_map_t *) &FUNCMCON2,
};
i2c_t *HS_IIC = &__IIC1;
void ctp_int_isr(void);
AT(.text.bsp.i2c)
void bsp_hs_i2c_tx_buf(u16 dev_addr, u8 *buf, u16 len)
{
u32 ticks;
HS_IIC->sfr->IICxCMDA = (buf[0]<<8) | dev_addr;
HS_IIC->sfr->IICxCON1 = BIT(12) | BIT(11) | BIT(10) | BIT(5) | BIT(4) | BIT(3);
HS_IIC->sfr->IICxDMAADR = DMA_ADR(&buf[1]);
HS_IIC->sfr->IICxDMACNT = ((len - 2) << 16) | BIT(1) |BIT(0);
HS_IIC->sfr->IICxCON0 |= BIT(28); //KICK
// printf("IICxCMDA: 0x%x, IICxDMAADR: 0x%x, IICxDMACNT: 0x%x, IICxCON0: 0x%x, IICxCON1: 0x%x\n",
// HS_IIC->sfr->IICxCMDA, HS_IIC->sfr->IICxDMAADR, HS_IIC->sfr->IICxDMACNT, HS_IIC->sfr->IICxCON0, HS_IIC->sfr->IICxCON1);
ticks = tick_get();
while (!(HS_IIC->sfr->IICxCON0 & BIT(31))) {
if (tick_check_expire(ticks, 1000)) {
printf("i2c_write time out ERROR\n");
return;
}
}
HS_IIC->sfr->IICxCON0 |= BIT(29); //Clear Pending
}
AT(.text.bsp.i2c)
void bsp_hs_i2c_rx_buf(u16 dev_addr, u8 *buf, u16 len)
{
u32 ticks;
HS_IIC->sfr->IICxCMDA = dev_addr<<24;
HS_IIC->sfr->IICxCON1 = BIT(12) | BIT(11) | BIT(9) | BIT(8) | BIT(7);
HS_IIC->sfr->IICxDMAADR = DMA_ADR(buf);
HS_IIC->sfr->IICxDMACNT = ((len - 1) << 16) | BIT(0);
HS_IIC->sfr->IICxCON0 |= BIT(28); //KICK
ticks = tick_get();
while (!(HS_IIC->sfr->IICxCON0 & BIT(31))) {
if (tick_check_expire(ticks, 2000)) {
printf("alipay_i2c_read time out ERROR\n");
return;
}
}
HS_IIC->sfr->IICxCON0 |= BIT(29); //Clear Pending
}
AT(.text.bsp.i2c)
void bsp_hs_i2c_rx_byte(u16 dev_addr, u8 *buf)
{
u32 ticks;
HS_IIC->sfr->IICxCMDA = dev_addr<<24;
HS_IIC->sfr->IICxCON1 = BIT(12) | BIT(11) | BIT(9) | BIT(8) | BIT(7);
HS_IIC->sfr->IICxDMAADR = DMA_ADR(buf);
HS_IIC->sfr->IICxDMACNT = BIT(0);
HS_IIC->sfr->IICxCON0 |= BIT(28); //KICK
ticks = tick_get();
while (!(HS_IIC->sfr->IICxCON0 & BIT(31))) {
if (tick_check_expire(ticks, 50)) {
printf("alipay_i2c_read time out ERROR\n");
return;
}
}
HS_IIC->sfr->IICxCON0 |= BIT(29); //Clear Pending
}
#endif // SECURITY_PAY_EN
AT(.text.bsp.i2c)
void bsp_i2c_init(void)
{
#if I2C_SW_EN
I2C_SDA_SCL_OUT();
I2C_SDA_H();
delay_5ms(2);
#endif
#if I2C_HW_EN
i2c_init();
sys_irq_init(IRQ_I2C_VECTOR, 0, bsp_i2c_isr);
#endif
}