601 lines
14 KiB
C
601 lines
14 KiB
C
#include <io.h>
|
|
#include <timer.h>
|
|
#include "i2c.h"
|
|
|
|
struct platform_i2c {
|
|
unsigned int msg_buf_ptr;
|
|
int status;
|
|
#define I2C_WAIT_RESPOND (1 << 0)
|
|
};
|
|
|
|
struct i2c_platform_data {
|
|
unsigned int freq;
|
|
unsigned int clk;
|
|
};
|
|
|
|
struct i2c_msg {
|
|
unsigned short addr; /* slave address */
|
|
unsigned short flags;
|
|
#define I2C_M_TEN 0x0010
|
|
#define I2C_M_RD 0x0001
|
|
#define I2C_M_STOP 0x8000
|
|
#define I2C_M_NOSTART 0x4000
|
|
#define I2C_M_REV_DIR_ADDR 0x2000
|
|
#define I2C_M_IGNORE_NAK 0x1000
|
|
#define I2C_M_NO_RD_ACK 0x0800
|
|
#define I2C_M_RECV_LEN 0x0400
|
|
#define I2C_M_16BIT_DATA 0x0008
|
|
#define I2C_M_16BIT_REG 0x0002
|
|
unsigned short len; /* msg length */
|
|
unsigned char *buf; /* pointer to msg data */
|
|
};
|
|
|
|
struct i2c_driver_data {
|
|
unsigned int reg_base;
|
|
unsigned int freq;
|
|
unsigned int irq;
|
|
unsigned int clk;
|
|
struct i2c_msg *msgs;
|
|
unsigned int msg_num;
|
|
unsigned int msg_idx;
|
|
unsigned int lock;
|
|
void *private;
|
|
};
|
|
|
|
#ifdef CONFIG_LOTUS_FPGA
|
|
#define CLK_LIMIT_DEFAULT 40000
|
|
#else
|
|
#define CLK_LIMIT_DEFAULT 400000
|
|
#endif
|
|
#define write_reg_bit(value, offset, addr) ({ \
|
|
unsigned long t, mask; \
|
|
mask = 1 << (offset); \
|
|
t = readl(addr); \
|
|
t &= ~mask; \
|
|
t |= (value << (offset)) & mask; \
|
|
writel(t, addr); \
|
|
})
|
|
|
|
#define I2C_WAIT_TIMEOUT (100 * 3)
|
|
#define I2C_TIMEOUT_COUNT 0x10000
|
|
#define I2C_BUF_SIZE 8
|
|
#define I2C_INTERRUPT_NUM 0
|
|
|
|
#if defined(CONFIG_PLATFORM_XMFALCON) || defined(CONFIG_PLATFORM_XMORCA)
|
|
|
|
#ifdef CONFIG_LOTUS_FPGA
|
|
#define get_bus_clk() 25000000
|
|
#else
|
|
#define get_bus_clk() 50000000
|
|
#endif
|
|
#define get_host_clock(i2c_num) ({ get_bus_clk(); })
|
|
|
|
static struct platform_i2c g_i2c_platform_data[I2C_NUM] = {0};
|
|
static int g_i2c_host_cfg[I2C_NUM] = {0, 1, 2, 3, 4, 5, 6, 7}; /* i2c index */
|
|
static struct i2c_driver_data g_i2c_data[I2C_NUM] = {
|
|
{I2C0_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C1_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C2_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C3_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C4_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C5_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C6_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C7_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
};
|
|
|
|
#elif defined(CONFIG_TARGET_XM720XXX)
|
|
|
|
#define get_bus_clk() 50000000
|
|
#define get_host_clock(i2c_num) ({ get_bus_clk(); })
|
|
|
|
static struct platform_i2c g_i2c_platform_data[I2C_NUM] = {0};
|
|
static int g_i2c_host_cfg[I2C_NUM] = {0, 1, 2}; /* 0,1,2: i2c index */
|
|
static struct i2c_driver_data g_i2c_data[I2C_NUM] = {
|
|
{I2C0_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C1_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
{I2C2_REG_BASE, CLK_LIMIT_DEFAULT, I2C_INTERRUPT_NUM},
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
static void i2c_disable(const struct i2c_driver_data *i2c);
|
|
static void i2c_cfg_irq(const struct i2c_driver_data *i2c, unsigned int flag);
|
|
static unsigned int i2c_clr_irq(const struct i2c_driver_data *i2c);
|
|
|
|
static void i2c_rescue(const struct i2c_driver_data *i2c)
|
|
{
|
|
i2c_disable(i2c);
|
|
i2c_cfg_irq(i2c, 0);
|
|
i2c_clr_irq(i2c);
|
|
|
|
unsigned int val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) |
|
|
(0x1 << FORCE_SDA_OEN_SHIFT);
|
|
writel(val, i2c->reg_base + I2C_CTRL2);
|
|
|
|
unsigned int time_cnt = 0;
|
|
do {
|
|
for (int index = 0; index < 9; index++) { /* shift:9 */
|
|
val = (0x1 << GPIO_MODE_SHIFT) | 0x1;
|
|
writel(val, i2c->reg_base + I2C_CTRL2);
|
|
udelay(5); /* delay: 5 us */
|
|
val = (0x1 << GPIO_MODE_SHIFT) |
|
|
(0x1 << FORCE_SCL_OEN_SHIFT) |
|
|
(0x1 << FORCE_SDA_OEN_SHIFT);
|
|
writel(val, i2c->reg_base + I2C_CTRL2);
|
|
udelay(5); /* delay: 5 us */
|
|
}
|
|
|
|
time_cnt++;
|
|
if (time_cnt > I2C_WAIT_TIMEOUT) {
|
|
goto disable_rescue;
|
|
}
|
|
|
|
val = readl(i2c->reg_base + I2C_CTRL2);
|
|
} while (!(val & (0x1 << CHECK_SDA_IN_SHIFT)));
|
|
|
|
val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) |
|
|
(0x1 << FORCE_SDA_OEN_SHIFT);
|
|
writel(val, i2c->reg_base + I2C_CTRL2);
|
|
val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT);
|
|
writel(val, i2c->reg_base + I2C_CTRL2);
|
|
udelay(10); /* delay: 10 us */
|
|
val = (0x1 << GPIO_MODE_SHIFT) | (0x1 << FORCE_SCL_OEN_SHIFT) |
|
|
(0x1 << FORCE_SDA_OEN_SHIFT);
|
|
writel(val, i2c->reg_base + I2C_CTRL2);
|
|
|
|
disable_rescue:
|
|
val = (0x1 << FORCE_SCL_OEN_SHIFT) | 0x1;
|
|
writel(val, i2c->reg_base + I2C_CTRL2);
|
|
}
|
|
|
|
static void i2c_disable(const struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int val = readl(i2c->reg_base + I2C_GLB);
|
|
val &= ~GLB_EN_MASK;
|
|
writel(val, i2c->reg_base + I2C_GLB);
|
|
}
|
|
|
|
static void i2c_disable_irq(const struct i2c_driver_data *i2c, unsigned int flag)
|
|
{
|
|
unsigned int val = readl(i2c->reg_base + I2C_INTR_EN);
|
|
val &= ~flag;
|
|
writel(val, i2c->reg_base + I2C_INTR_EN);
|
|
}
|
|
|
|
static unsigned int i2c_clr_irq(const struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int val = readl(i2c->reg_base + I2C_INTR_STAT);
|
|
writel(INTR_ALL_MASK, i2c->reg_base + I2C_INTR_RAW);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void i2c_set_freq(struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int val;
|
|
unsigned int freq = i2c->freq;
|
|
unsigned int clk_rate = i2c->clk;
|
|
unsigned int max_freq = clk_rate >> 1;
|
|
|
|
if (freq > max_freq) {
|
|
i2c->freq = max_freq;
|
|
freq = i2c->freq;
|
|
}
|
|
|
|
if (freq <= 100000) { /* 100000:100KHz */
|
|
val = clk_rate / (freq * 2); /* 1/2:0.5 */
|
|
writel(val, i2c->reg_base + I2C_SCL_H);
|
|
writel(val, i2c->reg_base + I2C_SCL_L);
|
|
} else {
|
|
val = (clk_rate * 36) / (freq * 100); /* 36/100:0.36 */
|
|
writel(val, i2c->reg_base + I2C_SCL_H);
|
|
val = (clk_rate * 64) / (freq * 100); /* 64/100:0.64 */
|
|
writel(val, i2c->reg_base + I2C_SCL_L);
|
|
}
|
|
val = readl(i2c->reg_base + I2C_GLB);
|
|
val &= ~GLB_SDA_HOLD_MASK;
|
|
val |= ((0xa << GLB_SDA_HOLD_SHIFT) & GLB_SDA_HOLD_MASK);
|
|
writel(val, i2c->reg_base + I2C_GLB);
|
|
}
|
|
|
|
/*
|
|
* set i2c controller TX and RX FIFO water
|
|
*/
|
|
static void i2c_set_water(const struct i2c_driver_data *i2c)
|
|
{
|
|
writel(I2C_TXF_WATER, i2c->reg_base + I2C_TX_WATER);
|
|
writel(I2C_RXF_WATER, i2c->reg_base + I2C_RX_WATER);
|
|
}
|
|
|
|
static void i2c_enable_clk(unsigned char i2c_num)
|
|
{
|
|
const unsigned int clk_start_bit = 16 + i2c_num; /* 16: i2c clk start bit */
|
|
const unsigned int rst_start_bit = 24 + i2c_num; /* 24: i2c rst start bit */
|
|
const unsigned int enable_clck = 1;
|
|
const unsigned int enable_rst = 0;
|
|
write_reg_bit(enable_clck, clk_start_bit, (uintptr_t)I2C_CRG_REG_BASE);
|
|
write_reg_bit(enable_rst, rst_start_bit, (uintptr_t)I2C_CRG_REG_BASE);
|
|
}
|
|
|
|
/*
|
|
* initialise the controller, set i2c bus interface freq
|
|
*/
|
|
static void i2c_init_cfg(const struct i2c_driver_data *i2c, unsigned char i2c_num)
|
|
{
|
|
i2c_enable_clk(i2c_num);
|
|
i2c_disable(i2c);
|
|
i2c_disable_irq(i2c, INTR_ALL_MASK);
|
|
i2c_set_freq((struct i2c_driver_data *)i2c);
|
|
i2c_set_water(i2c);
|
|
}
|
|
|
|
static void i2c_cmdreg_set(const struct i2c_driver_data *i2c, unsigned int cmd,
|
|
unsigned int *offset)
|
|
{
|
|
writel(cmd, i2c->reg_base + I2C_CMD_BASE + (*offset) * 4); /* 4: bytes */
|
|
(*offset)++;
|
|
}
|
|
|
|
static void i2c_cfg_cmd(const struct i2c_driver_data *i2c)
|
|
{
|
|
struct i2c_msg *msg = i2c->msgs;
|
|
unsigned int offset = 0;
|
|
|
|
if (i2c->msg_idx == 0)
|
|
i2c_cmdreg_set(i2c, CMD_TX_S, &offset);
|
|
else
|
|
i2c_cmdreg_set(i2c, CMD_TX_RS, &offset);
|
|
|
|
if (msg->flags & I2C_M_TEN) {
|
|
if (i2c->msg_idx == 0) {
|
|
i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset);
|
|
i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset);
|
|
i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset);
|
|
} else {
|
|
i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset);
|
|
}
|
|
} else {
|
|
i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset);
|
|
}
|
|
|
|
if (msg->flags & I2C_M_IGNORE_NAK)
|
|
i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset);
|
|
else
|
|
i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset);
|
|
|
|
if (msg->flags & I2C_M_RD) {
|
|
if (msg->len >= 2) { /* msg len:2 */
|
|
writel(offset, i2c->reg_base + I2C_DST1);
|
|
writel(msg->len - 2, i2c->reg_base + I2C_LOOP1); /* 2: max len */
|
|
i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset);
|
|
i2c_cmdreg_set(i2c, CMD_TX_ACK, &offset);
|
|
i2c_cmdreg_set(i2c, CMD_JMP1, &offset);
|
|
}
|
|
i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset);
|
|
i2c_cmdreg_set(i2c, CMD_TX_NACK, &offset);
|
|
} else {
|
|
writel(offset, i2c->reg_base + I2C_DST1);
|
|
writel(msg->len - 1, i2c->reg_base + I2C_LOOP1);
|
|
i2c_cmdreg_set(i2c, CMD_UP_TXF, &offset);
|
|
i2c_cmdreg_set(i2c, CMD_TX_FIFO, &offset);
|
|
|
|
if (msg->flags & I2C_M_IGNORE_NAK) {
|
|
i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset);
|
|
}
|
|
else {
|
|
i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset);
|
|
}
|
|
i2c_cmdreg_set(i2c, CMD_JMP1, &offset);
|
|
}
|
|
|
|
if ((i2c->msg_idx == (i2c->msg_num - 1)) || (msg->flags & I2C_M_STOP)) {
|
|
i2c_cmdreg_set(i2c, CMD_TX_P, &offset);
|
|
}
|
|
|
|
i2c_cmdreg_set(i2c, CMD_EXIT, &offset);
|
|
}
|
|
|
|
static void i2c_enable(const struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int val = readl(i2c->reg_base + I2C_GLB);
|
|
val |= GLB_EN_MASK;
|
|
writel(val, i2c->reg_base + I2C_GLB);
|
|
}
|
|
|
|
/*
|
|
* config i2c slave addr
|
|
*/
|
|
static void i2c_set_addr(const struct i2c_driver_data *i2c)
|
|
{
|
|
struct i2c_msg *msg = i2c->msgs;
|
|
unsigned int addr;
|
|
|
|
if (msg->flags & I2C_M_TEN) {
|
|
/* first byte is 11110XX0 where XX is upper 2 bits */
|
|
addr = ((msg->addr & 0x300) << 1) | 0xf000;
|
|
if (msg->flags & I2C_M_RD) {
|
|
addr |= 1 << 8; /* shift:8 */
|
|
}
|
|
|
|
/* second byte is the remaining 8 bits */
|
|
addr |= msg->addr & 0xff;
|
|
} else {
|
|
addr = (msg->addr & 0x7f) << 1;
|
|
if (msg->flags & I2C_M_RD) {
|
|
addr |= 1;
|
|
}
|
|
}
|
|
|
|
writel(addr, i2c->reg_base + I2C_DATA1);
|
|
}
|
|
|
|
/*
|
|
* start command sequence
|
|
*/
|
|
static void i2c_start_cmd(const struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int val = readl(i2c->reg_base + I2C_CTRL1);
|
|
val |= CTRL1_CMD_START_MASK;
|
|
writel(val, i2c->reg_base + I2C_CTRL1);
|
|
}
|
|
|
|
static int i2c_wait_rx_noempty(const struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int time_cnt = 0;
|
|
unsigned int val;
|
|
|
|
do {
|
|
val = readl(i2c->reg_base + I2C_STAT);
|
|
if (val & STAT_RXF_NOE_MASK) {
|
|
return 0;
|
|
}
|
|
udelay(50); /* delay:50 us */
|
|
time_cnt++;
|
|
} while (time_cnt < I2C_TIMEOUT_COUNT);
|
|
|
|
i2c_rescue(i2c);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int i2c_wait_tx_nofull(const struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int time_cnt = 0;
|
|
unsigned int val;
|
|
|
|
do {
|
|
val = readl(i2c->reg_base + I2C_STAT);
|
|
if (val & STAT_TXF_NOF_MASK) {
|
|
return 0;
|
|
}
|
|
udelay(50); /* delay:50 us */
|
|
time_cnt++;
|
|
} while (time_cnt < I2C_TIMEOUT_COUNT);
|
|
|
|
i2c_rescue(i2c);
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int i2c_wait_idle(const struct i2c_driver_data *i2c)
|
|
{
|
|
unsigned int time_cnt = 0;
|
|
unsigned int val;
|
|
|
|
do {
|
|
val = readl(i2c->reg_base + I2C_INTR_RAW);
|
|
if (val & (INTR_ABORT_MASK)) {
|
|
//printf("i2c wait idle 1,val==0x%x\n",val);
|
|
return -1;
|
|
}
|
|
|
|
if (val & INTR_CMD_DONE_MASK) {
|
|
return 0;
|
|
}
|
|
udelay(50); /* delay:50 us */
|
|
time_cnt++;
|
|
} while (time_cnt < I2C_WAIT_TIMEOUT);
|
|
|
|
i2c_rescue(i2c);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int i2c_polling_xfer_one_msg(const struct i2c_driver_data *i2c)
|
|
{
|
|
int status;
|
|
unsigned int val;
|
|
struct i2c_msg *msg = i2c->msgs;
|
|
unsigned int msg_buf_ptr = 0;
|
|
|
|
i2c_enable(i2c);
|
|
i2c_clr_irq(i2c);
|
|
i2c_set_addr(i2c);
|
|
i2c_cfg_cmd(i2c);
|
|
i2c_start_cmd(i2c);
|
|
|
|
if (msg->flags & I2C_M_RD) {
|
|
while (msg_buf_ptr < msg->len) {
|
|
status = i2c_wait_rx_noempty(i2c);
|
|
if (status) {
|
|
goto end;
|
|
}
|
|
val = readl(i2c->reg_base + I2C_RXF);
|
|
msg->buf[msg_buf_ptr] = val;
|
|
msg_buf_ptr++;
|
|
}
|
|
} else {
|
|
while (msg_buf_ptr < msg->len) {
|
|
status = i2c_wait_tx_nofull(i2c);
|
|
if (status) {
|
|
goto end;
|
|
}
|
|
val = msg->buf[msg_buf_ptr];
|
|
writel(val, i2c->reg_base + I2C_TXF);
|
|
msg_buf_ptr++;
|
|
}
|
|
}
|
|
|
|
status = i2c_wait_idle(i2c);
|
|
end:
|
|
i2c_disable(i2c);
|
|
|
|
return status;
|
|
}
|
|
|
|
static void i2c_cfg_irq(const struct i2c_driver_data *i2c, unsigned int flag)
|
|
{
|
|
writel(flag, i2c->reg_base + I2C_INTR_EN);
|
|
}
|
|
|
|
static int i2c_xfer(unsigned char i2c_num, const struct i2c_msg *msgs, int num)
|
|
{
|
|
int status = 0;
|
|
|
|
if (msgs == NULL) {
|
|
//printf("[error] msg pointer is null.\n");
|
|
return -1;
|
|
}
|
|
|
|
struct i2c_driver_data *i2c = &g_i2c_data[i2c_num];
|
|
struct platform_i2c *hpi = &g_i2c_platform_data[i2c_num];
|
|
|
|
i2c->clk = get_host_clock(0);
|
|
i2c->private = (void *)(hpi);
|
|
|
|
i2c->msgs = (struct i2c_msg *)msgs;
|
|
i2c->msg_num = (unsigned int)num;
|
|
i2c->msg_idx = 0;
|
|
|
|
while (i2c->msg_idx < i2c->msg_num) {
|
|
status = i2c_polling_xfer_one_msg(i2c);
|
|
if (status) {
|
|
break;
|
|
}
|
|
|
|
i2c->msgs++;
|
|
i2c->msg_idx++;
|
|
}
|
|
|
|
if (!status || i2c->msg_idx > 0) {
|
|
status = i2c->msg_idx;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static int i2c_check_enable(unsigned char i2c_num)
|
|
{
|
|
if (i2c_num >= I2C_NUM) {
|
|
return -1;
|
|
}
|
|
|
|
return g_i2c_host_cfg[i2c_num];
|
|
}
|
|
|
|
static int hal_i2c_recv_inner(const struct i2c_client *client, unsigned char *buf,
|
|
unsigned int count)
|
|
{
|
|
struct i2c_msg msg[I2C_BUF_SIZE] = {0};
|
|
unsigned char reg_addr[2] = {0};
|
|
|
|
if (client->reg_width == 2) { /* reg_width:2 */
|
|
reg_addr[0] = (client->reg_addr >> 8) & 0xff; /* shift:8 */
|
|
reg_addr[1] = client->reg_addr & 0xff;
|
|
} else {
|
|
reg_addr[0] = client->reg_addr & 0xff;
|
|
}
|
|
|
|
msg[0].addr = client->dev_addr;
|
|
msg[0].flags = 0;
|
|
msg[0].len = client->reg_width;
|
|
msg[0].buf = reg_addr;
|
|
|
|
msg[1].addr = client->dev_addr;
|
|
msg[1].flags = 0;
|
|
msg[1].flags |= I2C_M_RD;
|
|
msg[1].len = count;
|
|
msg[1].buf = buf;
|
|
|
|
return i2c_xfer(client->i2c_num, msg, 2); /* msg num:2 */
|
|
}
|
|
|
|
static int hal_i2c_send_inner(unsigned char i2c_num, unsigned short dev_addr, const char *buf,
|
|
unsigned int count)
|
|
{
|
|
struct i2c_msg msg = {0};
|
|
msg.addr = dev_addr;
|
|
msg.flags = 0;
|
|
msg.len = count;
|
|
msg.buf = (unsigned char *)buf;
|
|
int ret = i2c_xfer(i2c_num, &msg, 1);
|
|
return (ret == 1) ? count : ret;
|
|
}
|
|
|
|
static int hal_i2c_init_inner(unsigned char i2c_num)
|
|
{
|
|
struct i2c_driver_data *i2c = NULL;
|
|
struct platform_i2c *hpi = NULL;
|
|
|
|
int ret = i2c_check_enable(i2c_num);
|
|
if (ret < 0) {
|
|
return -1;
|
|
}
|
|
|
|
i2c = &g_i2c_data[i2c_num];
|
|
hpi = &g_i2c_platform_data[i2c_num];
|
|
i2c->clk = get_host_clock(i2c_num);
|
|
i2c->private = (void *)(hpi);
|
|
i2c->irq = 0;
|
|
i2c_init_cfg(i2c, i2c_num);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int i2c_recv(const struct i2c_client *client, unsigned char *buf,
|
|
unsigned int count)
|
|
{
|
|
if ((client == NULL) || (buf == NULL)) {
|
|
return -1;
|
|
}
|
|
|
|
if (client->i2c_num >= I2C_NUM) {
|
|
return -1;
|
|
}
|
|
|
|
if (count > I2C_BUF_SIZE) {
|
|
return -1;
|
|
}
|
|
|
|
return hal_i2c_recv_inner(client, buf, count);
|
|
}
|
|
|
|
int i2c_send(unsigned char i2c_num, unsigned short dev_addr, const char *buf,
|
|
unsigned int count)
|
|
{
|
|
if (i2c_num >= I2C_NUM) {
|
|
return -1;
|
|
}
|
|
|
|
if (buf == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (count > I2C_BUF_SIZE) {
|
|
return -1;
|
|
}
|
|
|
|
return hal_i2c_send_inner(i2c_num, dev_addr, buf, count);
|
|
}
|
|
|
|
int i2c_init(unsigned char i2c_num)
|
|
{
|
|
if (i2c_num >= I2C_NUM) {
|
|
return -1;
|
|
}
|
|
|
|
return hal_i2c_init_inner(i2c_num);
|
|
}
|