I2c控制器数据收发函数举例

文章详细解释了设备驱动中的I2C数据收发函数实现,包括使用例程如`ap3216c_read_regs`,以及`i2c_transfer`和`master_xfer`的工作原理,特别强调了中断处理在读写操作中的关键作用。
摘要由CSDN通过智能技术生成

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值