i2c: Refactor

This commit is contained in:
CTCaer 2020-08-27 10:04:26 +03:00
parent 9686eaf3f1
commit b20a0e74c2
2 changed files with 116 additions and 60 deletions

View file

@ -20,31 +20,85 @@
#include <soc/i2c.h> #include <soc/i2c.h>
#include <utils/util.h> #include <utils/util.h>
#define I2C_PACKET_PROT_I2C (1 << 4)
#define I2C_HEADER_IE_ENABLE (1 << 17)
#define I2C_HEADER_READ (1 << 19)
#define I2C_CNFG (0x00 / 4)
#define CMD1_WRITE (0 << 6)
#define CMD1_READ (1 << 6)
#define NORMAL_MODE_GO (1 << 9)
#define PACKET_MODE_GO (1 << 10)
#define NEW_MASTER_FSM (1 << 11)
#define DEBOUNCE_CNT_4T (2 << 12)
#define I2C_CMD_ADDR0 (0x04 / 4)
#define ADDR0_WRITE 0
#define ADDR0_READ 1
#define I2C_CMD_DATA1 (0x0C / 4)
#define I2C_CMD_DATA2 (0x10 / 4)
#define I2C_STATUS (0x1C / 4)
#define I2C_STATUS_NOACK (0xF << 0)
#define I2C_STATUS_BUSY (1 << 8)
#define I2C_TX_FIFO (0x50 / 4)
#define I2C_RX_FIFO (0x54 / 4)
#define I2C_FIFO_CONTROL (0x5C / 4)
#define RX_FIFO_FLUSH (1 << 0)
#define TX_FIFO_FLUSH (1 << 1)
#define I2C_FIFO_STATUS (0x60 / 4)
#define RX_FIFO_FULL_CNT (0xF << 0)
#define TX_FIFO_EMPTY_CNT (0xF << 4)
#define I2C_INT_EN (0x64 / 4)
#define I2C_INT_STATUS (0x68 / 4)
#define I2C_INT_SOURCE (0x70 / 4)
#define RX_FIFO_DATA_REQ (1 << 0)
#define TX_FIFO_DATA_REQ (1 << 1)
#define ARB_LOST (1 << 2)
#define NO_ACK (1 << 3)
#define RX_FIFO_UNDER (1 << 4)
#define TX_FIFO_OVER (1 << 5)
#define ALL_PACKETS_COMPLETE (1 << 6)
#define PACKET_COMPLETE (1 << 7)
#define BUS_CLEAR_DONE (1 << 11)
#define I2C_CLK_DIVISOR (0x6C / 4)
#define I2C_BUS_CLEAR_CONFIG (0x84 / 4)
#define BC_ENABLE (1 << 0)
#define BC_TERMINATE (1 << 1)
#define I2C_BUS_CLEAR_STATUS (0x88 / 4)
#define I2C_CONFIG_LOAD (0x8C / 4)
#define MSTR_CONFIG_LOAD (1 << 0)
#define TIMEOUT_CONFIG_LOAD (1 << 2)
static const u32 i2c_addrs[] = { static const u32 i2c_addrs[] = {
0x7000C000, 0x7000C400, 0x7000C500, 0x7000C000, // I2C_1.
0x7000C700, 0x7000D000, 0x7000D100 0x7000C400, // I2C_2.
0x7000C500, // I2C_3.
0x7000C700, // I2C_4.
0x7000D000, // I2C_5.
0x7000D100 // I2C_6.
}; };
static void _i2c_wait(vu32 *base) static void _i2c_load_cfg_wait(vu32 *base)
{ {
base[I2C_CONFIG_LOAD] = 0x25; base[I2C_CONFIG_LOAD] = (1 << 5) | TIMEOUT_CONFIG_LOAD | MSTR_CONFIG_LOAD;
for (u32 i = 0; i < 20; i++) for (u32 i = 0; i < 20; i++)
{ {
usleep(1); usleep(1);
if (!(base[I2C_CONFIG_LOAD] & 1)) if (!(base[I2C_CONFIG_LOAD] & MSTR_CONFIG_LOAD))
break; break;
} }
} }
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size) static int _i2c_send_single(u32 i2c_idx, u32 dev_addr, u8 *buf, u32 size)
{ {
if (size > 8) if (size > 8)
return 0; return 0;
u32 tmp = 0; u32 tmp = 0;
vu32 *base = (vu32 *)i2c_addrs[idx]; vu32 *base = (vu32 *)i2c_addrs[i2c_idx];
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
// Set device address and send mode.
base[I2C_CMD_ADDR0] = dev_addr << 1 | ADDR0_WRITE;
if (size > 4) if (size > 4)
{ {
@ -60,44 +114,55 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
base[I2C_CMD_DATA1] = tmp; //Set value. base[I2C_CMD_DATA1] = tmp; //Set value.
} }
base[I2C_CNFG] = ((size - 1) << 1) | 0x2800; //Set size and send mode. // Set size and send mode.
_i2c_wait(base); //Kick transaction. base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_WRITE;
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; // Load configuration.
_i2c_load_cfg_wait(base);
// Initiate transaction on normal mode.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO;
u32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms. u32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms.
while (base[I2C_STATUS] & 0x100) while (base[I2C_STATUS] & I2C_STATUS_BUSY)
{ {
if (get_tmr_ms() > timeout) if (get_tmr_ms() > timeout)
return 0; return 0;
} }
if (base[I2C_STATUS] << 28) if (base[I2C_STATUS] & I2C_STATUS_NOACK)
return 0; return 0;
return 1; return 1;
} }
static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x) static int _i2c_recv_single(u32 i2c_idx, u8 *buf, u32 size, u32 dev_addr)
{ {
if (size > 8) if (size > 8)
return 0; return 0;
vu32 *base = (vu32 *)i2c_addrs[idx]; vu32 *base = (vu32 *)i2c_addrs[i2c_idx];
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
base[I2C_CNFG] = ((size - 1) << 1) | 0x2840; // Set size and recv mode.
_i2c_wait(base); // Kick transaction.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200; // Set device address and recv mode.
base[I2C_CMD_ADDR0] = (dev_addr << 1) | ADDR0_READ;
// Set size and recv mode.
base[I2C_CNFG] = ((size - 1) << 1) | DEBOUNCE_CNT_4T | NEW_MASTER_FSM | CMD1_READ;
// Load configuration.
_i2c_load_cfg_wait(base);
// Initiate transaction on normal mode.
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFF9FF) | NORMAL_MODE_GO;
u32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms. u32 timeout = get_tmr_ms() + 100; // Actual for max 8 bytes at 100KHz is 0.74ms.
while (base[I2C_STATUS] & 0x100) while (base[I2C_STATUS] & I2C_STATUS_BUSY)
{ {
if (get_tmr_ms() > timeout) if (get_tmr_ms() > timeout)
return 0; return 0;
} }
if (base[I2C_STATUS] << 28) if (base[I2C_STATUS] & I2C_STATUS_NOACK)
return 0; return 0;
u32 tmp = base[I2C_CMD_DATA1]; // Get LS value. u32 tmp = base[I2C_CMD_DATA1]; // Get LS value.
@ -113,60 +178,62 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
return 1; return 1;
} }
void i2c_init(u32 idx) void i2c_init(u32 i2c_idx)
{ {
vu32 *base = (vu32 *)i2c_addrs[idx]; vu32 *base = (vu32 *)i2c_addrs[i2c_idx];
base[I2C_CLK_DIVISOR_REGISTER] = 0x50001; base[I2C_CLK_DIVISOR] = (5 << 16) | 1; // SF mode Div: 6, HS mode div: 2.
base[I2C_BUS_CLEAR_CONFIG] = 0x90003; base[I2C_BUS_CLEAR_CONFIG] = (9 << 16) | BC_TERMINATE | BC_ENABLE;
_i2c_wait(base);
// Load configuration.
_i2c_load_cfg_wait(base);
for (u32 i = 0; i < 10; i++) for (u32 i = 0; i < 10; i++)
{ {
usleep(20000); usleep(20000);
if (base[INTERRUPT_STATUS_REGISTER] & 0x800) if (base[I2C_INT_STATUS] & BUS_CLEAR_DONE)
break; break;
} }
(vu32)base[I2C_BUS_CLEAR_STATUS]; (vu32)base[I2C_BUS_CLEAR_STATUS];
base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER]; base[I2C_INT_STATUS] = base[I2C_INT_STATUS];
} }
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size) int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr)
{
return _i2c_recv_single(i2c_idx, buf, size, dev_addr);
}
int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size)
{ {
u8 tmp[4]; u8 tmp[4];
if (size > 7) if (size > 7)
return 0; return 0;
tmp[0] = y; tmp[0] = reg;
memcpy(tmp + 1, buf, size); memcpy(tmp + 1, buf, size);
return _i2c_send_pkt(idx, x, tmp, size + 1); return _i2c_send_single(i2c_idx, dev_addr, tmp, size + 1);
} }
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x) int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg)
{ {
return _i2c_recv_pkt(idx, buf, size, x); int res = _i2c_send_single(i2c_idx, dev_addr, (u8 *)&reg, 1);
}
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
{
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
if (res) if (res)
res = _i2c_recv_pkt(idx, buf, size, x); res = _i2c_recv_single(i2c_idx, buf, size, dev_addr);
return res; return res;
} }
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b) int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val)
{ {
return i2c_send_buf_small(idx, x, y, &b, 1); return i2c_send_buf_small(i2c_idx, dev_addr, reg, &val, 1);
} }
u8 i2c_recv_byte(u32 idx, u32 x, u32 y) u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg)
{ {
u8 tmp = 0; u8 tmp = 0;
i2c_recv_buf_small(&tmp, 1, idx, x, y); i2c_recv_buf_small(&tmp, 1, i2c_idx, dev_addr, reg);
return tmp; return tmp;
} }

View file

@ -27,22 +27,11 @@
#define I2C_5 4 #define I2C_5 4
#define I2C_6 5 #define I2C_6 5
#define I2C_CNFG 0x00 void i2c_init(u32 i2c_idx);
#define I2C_CMD_ADDR0 0x01 int i2c_recv_buf(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr);
#define I2C_CMD_DATA1 0x03 int i2c_send_buf_small(u32 i2c_idx, u32 dev_addr, u32 reg, u8 *buf, u32 size);
#define I2C_CMD_DATA2 0x04 int i2c_recv_buf_small(u8 *buf, u32 size, u32 i2c_idx, u32 dev_addr, u32 reg);
#define I2C_STATUS 0x07 int i2c_send_byte(u32 i2c_idx, u32 dev_addr, u32 reg, u8 val);
#define INTERRUPT_STATUS_REGISTER 0x1A u8 i2c_recv_byte(u32 i2c_idx, u32 dev_addr, u32 reg);
#define I2C_CLK_DIVISOR_REGISTER 0x1B
#define I2C_BUS_CLEAR_CONFIG 0x21
#define I2C_BUS_CLEAR_STATUS 0x22
#define I2C_CONFIG_LOAD 0x23
void i2c_init(u32 idx);
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
int i2c_recv_buf(u8 *buf, u32 size, u32 idx, u32 x);
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
u8 i2c_recv_byte(u32 idx, u32 x, u32 y);
#endif #endif