1、设备驱动数据收发函数调用举例
注意I2C_M_RD,读的时候要赋值该标志,控制器实现的数据收发函数要用
static int ap3216c_read_regs(struct ap3216c_dev *dev,u8 reg,
void *val, int len)
{
int ret;
struct i2c_msg msg[2];
struct i2c_client *client = (struct i2c_client *)dev->private_data;
/*msg[0]发送要读取的寄存器首地址*/
msg[0].addr = client->addr;/*从机地址,也就是ap3216c*/
msg[0].flags = 0;/* 标记为发送数据 */
msg[0].buf = ®/*要发送的数据,也就是寄存器地址*/
msg[0].len = 1;/*要发送的寄存器地址长度为1*/
/*msg[1]读取数据*/
msg[1].addr = client->addr;/*从机地址,也就是ap3216c*/
msg[1].flags = I2C_M_RD;/*表示读数据*/
msg[1].buf = val;/*接收到的从机地址*/
msg[1].len = len;/*要读取的寄存器数据长度*/
ret = i2c_transfer(client->adapter,msg,2);
if(ret == 2){
ret = 0;
}else{
printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
2、i2c_transfer函数说明
i2c_transfer–>__i2c_transfer–>master_xfer(i2c控制器驱动初始化的时候注册的函数)
3、master_xfer怎么实现的数据收发
各个芯片的实现不一样,大致分为两种
1、写数据,master_xfer函数直接写寄存器发送数据,
读数据,配置寄存器使能中断,在中断处理函数中接收数据
2、写数据和读数据都是通过master_xfer该函数设置中断标志位,使能中断,然后注册的中断处理函数会读写数据
以下是第二种方式的举例说明
static const struct i2c_algorithm bsp_i2c_algo = {
.master_xfer = bsp_i2c_xfer,
.functionality = bsp_i2c_func,
};
bsp_i2c_xfer实际调用的函数
static int bsp_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct bsp_i2c_dev *i2c = i2c_get_adapdata(adap);
int status = -EINVAL;
unsigned long flags;
if (msgs == NULL || (num <= 0)) {
dev_err(i2c->dev, "msgs == NULL || num <= 0, Invalid argument!\n");
return -EINVAL;
}
spin_lock_irqsave(&i2c->lock, flags);
i2c->msg = msgs;//赋值msg,后面要用,实际上是i2c中断处理函数中用
i2c->msg_num = num;
i2c->msg_idx = 0;
while (i2c->msg_idx < i2c->msg_num) {
#if defined(CONFIG_EDMAC)
if ((i2c->msg->len >= CONFIG_DMA_MSG_MIN_LEN) &&
(i2c->msg->len <= CONFIG_DMA_MSG_MAX_LEN)) {
status = bsp_i2c_dma_xfer_one_msg(i2c);
if (status)
break;
} else if (i2c->irq >= 0) {
#else
if (i2c->irq >= 0) {
#endif
spin_unlock_irqrestore(&i2c->lock, flags);
status = bsp_i2c_interrupt_xfer_one_msg(i2c);//主要这个函数
spin_lock_irqsave(&i2c->lock, flags);
if (status)
break;
} else {
status = bsp_i2c_polling_xfer_one_msg(i2c);
if (status)
break;
}
i2c->msg++;
i2c->msg_idx++;
}
if (!status || i2c->msg_idx > 0)
status = i2c->msg_idx;
spin_unlock_irqrestore(&i2c->lock, flags);
return status;
}
static int bsp_i2c_interrupt_xfer_one_msg(struct bsp_i2c_dev *i2c)
{
int status;
struct i2c_msg *msg = i2c->msg;
unsigned long timeout;
unsigned long flags;
dev_dbg(i2c->dev, "[%s,%d]msg->flags=0x%x, len=0x%x\n",
__func__, __LINE__, msg->flags, msg->len);
reinit_completion(&i2c->msg_complete);
i2c->msg_buf_ptr = 0;
i2c->status = -EIO;
spin_lock_irqsave(&i2c->lock, flags);
check_i2c_send_complete(i2c);
bsp_i2c_enable(i2c);
bsp_i2c_clr_irq(i2c);
if (msg->flags & I2C_M_RD)//I2C_M_RD这个标志这里用了,判断是设置读还是写中断标志
bsp_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_TX_MASK);
else
bsp_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_RX_MASK);
bsp_i2c_set_addr(i2c);
bsp_i2c_cfg_cmd(i2c);
bsp_i2c_start_cmd(i2c);
spin_unlock_irqrestore(&i2c->lock, flags);
//这里在等完成量,只有数据收发完成或者超时才会继续往下走并返回,完成量在中断处理函数中释放
timeout = wait_for_completion_timeout(&i2c->msg_complete,
I2C_IRQ_TIMEOUT);
spin_lock_irqsave(&i2c->lock, flags);
if (timeout == 0) {
bsp_i2c_disable_irq(i2c, INTR_ALL_MASK);
status = -EIO;
dev_err(i2c->dev, "%s timeout\n",
msg->flags & I2C_M_RD ? "rx" : "tx");
} else {
status = i2c->status;
}
bsp_i2c_disable(i2c);
spin_unlock_irqrestore(&i2c->lock, flags);
return status;
}
//probe函数中注册的中断处理函数
status = devm_request_irq(&pdev->dev, i2c->irq, bsp_i2c_isr,
IRQF_SHARED, dev_name(&pdev->dev), i2c);
static irqreturn_t bsp_i2c_isr(int irq, void *dev_id)
{
struct bsp_i2c_dev *i2c = dev_id;
unsigned int irq_status;
struct i2c_msg *msg = i2c->msg;
spin_lock(&i2c->lock);
irq_status = bsp_i2c_clr_irq(i2c);
dev_dbg(i2c->dev, "%s RIS: 0x%x\n", __func__, irq_status);
if (!irq_status) {
dev_dbg(i2c->dev, "no irq\n");
goto end;
}
if (irq_status & INTR_ABORT_MASK) {
dev_err(i2c->dev, "irq handle abort, RIS: 0x%x\n",
irq_status);
i2c->status = -EIO;
bsp_i2c_disable_irq(i2c, INTR_ALL_MASK);
complete(&i2c->msg_complete);
goto end;
}
//中断使能之后就会调用中断处理函数,在这里会做实际的读写数据操作
if (msg->flags & I2C_M_RD) {
while ((readl(i2c->base + BSP_I2C_STAT) & STAT_RXF_NOE_MASK)
&& (i2c->msg_buf_ptr < msg->len)) {
msg->buf[i2c->msg_buf_ptr] =
readl(i2c->base + BSP_I2C_RXF);
i2c->msg_buf_ptr++;
}
} else {
while ((readl(i2c->base + BSP_I2C_STAT) & STAT_TXF_NOF_MASK)
&& (i2c->msg_buf_ptr < msg->len)) {
writel(msg->buf[i2c->msg_buf_ptr],
i2c->base + BSP_I2C_TXF);
i2c->msg_buf_ptr++;
}
}
if (i2c->msg_buf_ptr >= msg->len)
bsp_i2c_disable_irq(i2c, INTR_TX_MASK | INTR_RX_MASK);
if (irq_status & INTR_CMD_DONE_MASK) {
dev_dbg(i2c->dev, "cmd done\n");
i2c->status = 0;
bsp_i2c_disable_irq(i2c, INTR_ALL_MASK);
//这里释放完成量,bsp_i2c_interrupt_xfer_one_msg函数接着往下走并返回,完成数据收发
complete(&i2c->msg_complete);
}
end:
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
}