Synopsys DesignWareI2C master 数据的发送和接收

在i2c_dw_probe 中会对i2c_adapter的重要成员变量algo赋值
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
    struct i2c_adapter *adap = &dev->adapter;
    int r;

    init_completion(&dev->cmd_complete);

    r = i2c_dw_init(dev);
    if (r)
        return r;

    snprintf(adap->name, sizeof(adap->name),
         "Synopsys DesignWare I2C adapter");
    adap->retries = 3;
    adap->algo = &i2c_dw_algo;
    adap->dev.parent = dev->dev;
    i2c_set_adapdata(adap, dev);
}
这里的i2c_dw_algo 定义如下:
static struct i2c_algorithm i2c_dw_algo = {
    .master_xfer    = i2c_dw_xfer,
    .functionality    = i2c_dw_func,
};

这样在i2c_detect_address 中就会调用i2c_default_probe->i2c_smbus_xfer->i2c_smbus_xfer_emulated->i2c_transfer->__i2c_transfer
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
    unsigned long orig_jiffies;
    int ret, try;

    if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
        return -EOPNOTSUPP;

    /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
     * enabled.  This is an efficient way of keeping the for-loop from
     * being executed when not needed.
     */
    if (static_key_false(&i2c_trace_msg)) {
        int i;
        for (i = 0; i < num; i++)
            if (msgs[i].flags & I2C_M_RD)
                trace_i2c_read(adap, &msgs[i], i);
            else
                trace_i2c_write(adap, &msgs[i], i);
    }

    /* Retry automatically on arbitration loss */
    orig_jiffies = jiffies;
    for (ret = 0, try = 0; try <= adap->retries; try++) {
//关键的一句这里的algo->master_xfer 就是对应i2c_dw_algo中的master_xfer
        ret = adap->algo->master_xfer(adap, msgs, num);
        if (ret != -EAGAIN)
            break;
        if (time_after(jiffies, orig_jiffies + adap->timeout))
            break;
    }


}
所以在__i2c_transfer 中最终调用master_xfer来发送数据
static int
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
    struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
    int ret;

    dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);

    pm_runtime_get_sync(dev->dev);
//重新初始化完成量,从这里也可以看出完成量是一次性的,第二次使用之前必须调用reinit_completion 来重新初始化
    reinit_completion(&dev->cmd_complete);
    dev->msgs = msgs;
    dev->msgs_num = num;
    dev->cmd_err = 0;
    dev->msg_write_idx = 0;
    dev->msg_read_idx = 0;
    dev->msg_err = 0;
    dev->status = STATUS_IDLE;
    dev->abort_source = 0;
    dev->rx_outstanding = 0;

    ret = i2c_dw_acquire_lock(dev);
    if (ret)
        goto done_nolock;

    ret = i2c_dw_wait_bus_not_busy(dev);
    if (ret < 0)
        goto done;
// 发送数据,这里主要设置平台相关的寄存器
    /* start the transfers */
    i2c_dw_xfer_init(dev);
//等待释放完成量
    /* wait for tx to complete */
    if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
        dev_err(dev->dev, "controller timed out\n");
        /* i2c_dw_init implicitly disables the adapter */
        i2c_dw_init(dev);
        ret = -ETIMEDOUT;
        goto done;
    }

    /*
     * We must disable the adapter before returning and signaling the end
     * of the current transfer. Otherwise the hardware might continue
     * generating interrupts which in turn causes a race condition with
     * the following transfer.  Needs some more investigation if the
     * additional interrupts are a hardware bug or this driver doesn't
     * handle them correctly yet.
     */
    __i2c_dw_enable(dev, false);

    if (dev->msg_err) {
        ret = dev->msg_err;
        goto done;
    }
    return ret;
}
那完成量是在哪里释放的呢?
答案是在中断的处理函数i2c_dw_isr
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
    struct dw_i2c_dev *dev = dev_id;
    u32 stat, enabled;

    enabled = dw_readl(dev, DW_IC_ENABLE);
    stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
    dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled, stat);
    if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
        return IRQ_NONE;

    stat = i2c_dw_read_clear_intrbits(dev);

    if (stat & DW_IC_INTR_TX_ABRT) {
        dev->cmd_err |= DW_IC_ERR_TX_ABRT;
        dev->status = STATUS_IDLE;

        /*
         * Anytime TX_ABRT is set, the contents of the tx/rx
         * buffers are flushed.  Make sure to skip them.
         */
        dw_writel(dev, 0, DW_IC_INTR_MASK);
        goto tx_aborted;
    }

    if (stat & DW_IC_INTR_RX_FULL)
        i2c_dw_read(dev);

    if (stat & DW_IC_INTR_TX_EMPTY)
        i2c_dw_xfer_msg(dev);

    /*
     * No need to modify or disable the interrupt mask here.
     * i2c_dw_xfer_msg() will take care of it according to
     * the current transmit status.
     */

tx_aborted:
    //正常情况下这里就会释放完成量
    if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
        complete(&dev->cmd_complete);
    else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
        /* workaround to trigger pending interrupt */
        stat = dw_readl(dev, DW_IC_INTR_MASK);
        i2c_dw_disable_int(dev);
        dw_writel(dev, stat, DW_IC_INTR_MASK);
    }

    return IRQ_HANDLED;
}

Synopsys DMA(直接存取存储器)数据手册是一本详细介绍Synopsys公司设计的DMA控制器芯片的技术规格和使用方法的手册。 DMA控制器是一种硬件设备,用于实现在计算机系统中进行数据传输的功能。它可以实现高速的数据传输,减轻主处理器的负担,并提高整体系统性能。 Synopsys DMA数据手册提供了对DMA控制器的全面了解。手册首先介绍了DMA控制器的基本工作原理和主要功能,例如数据传输模式、通道数量、优先级等。然后详细描述了各个部件的规格,例如寄存器及其功能、总线接口和中断控制等。 该手册还通过具体的数据通路图和时序图等详细说明了DMA控制器的内部结构和工作流程。这些图形能够帮助用户更好地理解数据在DMA控制器中的传输路径和相应的时序约束。此外,手册还提供了一些基于硬件电路实现的示例和最佳实践,帮助用户更好地使用和配置DMA控制器。 Synopsys DMA数据手册还包含了一些常见问题和解决方案,以及常见错误和故障排除方法。这些信息可以帮助用户在使用DMA控制器时及时发现和解决问题,提高系统稳定性和可靠性。 总之,Synopsys DMA数据手册是一本全面介绍Synopsys DMA控制器的技术规格和使用方法的重要参考资料。用户可以通过阅读该手册来深入了解DMA控制器的工作原理和内部结构,从而更好地应用该控制器进行高效的数据传输。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值