All of lore.kernel.org
 help / color / mirror / Atom feed
From: sourav <sourav.poddar-l0cyMroinI0@public.gmane.org>
To: Yuan Yao <yao.yuan-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Cc: wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org,
	marex-ynQEQJNshbs@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH v4 1/2] i2c: add DMA support for freescale i2c driver
Date: Fri, 4 Apr 2014 15:34:12 +0530	[thread overview]
Message-ID: <533E839C.9090500@ti.com> (raw)
In-Reply-To: <533E8033.70904-l0cyMroinI0@public.gmane.org>


>> +
>> +    dma->chan_tx = dma_request_slave_channel(dev, "tx");
>> +    return 0;

To be more clear,
return here looks to be some leftover.

> ?? Looks to be some leftover?
>> +    if (!dma->chan_tx) {
>> +        dev_info(dev, "DMA tx channel request failed\n");
>> +        ret = -ENODEV;
>> +        goto fail_al;
>> +    }
>> +
>> +    dma_sconfig.dst_addr = phy_addr +
>> +                (IMX_I2C_I2DR<<  i2c_imx->hwdata->regshift);
>> +    dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>> +    dma_sconfig.dst_maxburst = 1;
>> +    dma_sconfig.direction = DMA_MEM_TO_DEV;
>> +    ret = dmaengine_slave_config(dma->chan_tx,&dma_sconfig);
>> +    if (ret<  0) {
>> +        dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>> +        goto fail_tx;
>> +    }
>> +
>> +    dma->chan_rx = dma_request_slave_channel(dev, "rx");
>> +    if (!dma->chan_rx) {
>> +        dev_info(dev, "DMA rx channel request failed\n");
>> +        ret = -ENODEV;
>> +        goto fail_tx;
>> +    }
>> +
>> +    dma_sconfig.src_addr = phy_addr +
>> +                (IMX_I2C_I2DR<<  i2c_imx->hwdata->regshift);
>> +    dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>> +    dma_sconfig.src_maxburst = 1;
>> +    dma_sconfig.direction = DMA_DEV_TO_MEM;
>> +    ret = dmaengine_slave_config(dma->chan_rx,&dma_sconfig);
>> +    if (ret<  0) {
>> +        dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>> +        goto fail_rx;
>> +    }
>> +
>> +    i2c_imx->dma = dma;
>> +
>> +    init_completion(&dma->cmd_complete);
>> +
>> +    return 0;
>> +
>> +fail_rx:
>> +    dma_release_channel(dma->chan_rx);
>> +fail_tx:
>> +    dma_release_channel(dma->chan_tx);
>> +fail_al:
>> +    devm_kfree(dev, dma);
>> +
>> +    return ret;
>> +}
>> +
>> +static void i2c_imx_dma_callback(void *arg)
>> +{
>> +    struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *)arg;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +
>> +    dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
>> +            dma->dma_len, dma->dma_data_dir);
>> +    complete(&dma->cmd_complete);
>> +}
>> +
>> +static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
>> +                    struct i2c_msg *msgs)
>> +{
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct dma_async_tx_descriptor *txdesc;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>> +
>> +    dma->dma_buf = dma_map_single(dma->chan_using->device->dev, 
>> msgs->buf,
>> +                    dma->dma_len, dma->dma_data_dir);
>> +    if (dma_mapping_error(dma->chan_using->device->dev, 
>> dma->dma_buf)) {
>> +        dev_err(dev, "DMA mapping failed\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
>> +                    dma->dma_len, dma->dma_transfer_dir,
>> +                    DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
>> +    if (!txdesc) {
>> +        dev_err(dev, "Not able to get desc for DMA xfer\n");
>> +        dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
>> +                    dma->dma_len, dma->dma_data_dir);
>> +        return -EINVAL;
>> +    }
>> +
>> +    txdesc->callback = i2c_imx_dma_callback;
>> +    txdesc->callback_param = i2c_imx;
>> +    dmaengine_submit(txdesc);
>> +    dma_async_issue_pending(dma->chan_using);
>> +
>> +    return 0;
>> +}
>> +
>> +static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +
>> +    dma->dma_buf = 0;
>> +    dma->dma_len = 0;
>> +
>> +    dma_release_channel(dma->chan_tx);
>> +    dma->chan_tx = NULL;
>> +
>> +    dma_release_channel(dma->chan_rx);
>> +    dma->chan_rx = NULL;
>> +
>> +    dma->chan_using = NULL;
>> +}
>> +
>>   /** Functions for IMX I2C adapter driver 
>> ***************************************
>>   
>> *******************************************************************************/
>>
>> @@ -334,6 +483,11 @@ static int i2c_imx_start(struct imx_i2c_struct 
>> *i2c_imx)
>>
>>       temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
>>       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp&= ~I2CR_DMAEN;
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>>       return result;
>>   }
>>
>> @@ -427,44 +581,101 @@ static irqreturn_t i2c_imx_isr(int irq, void 
>> *dev_id)
>>
>>   static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct 
>> i2c_msg *msgs)
>>   {
>> -    int i, result;
>> +    int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
>> +    unsigned int temp = 0;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  write slave address: 
>> addr=0x%x\n",
>> +    dev_dbg(dev, "<%s>  write slave address: addr=0x%x\n",
>>           __func__, msgs->addr<<  1);
>> +    if (dma&&  msgs->len>= IMX_I2C_DMA_THRESHOLD) {
>> +        reinit_completion(&i2c_imx->dma->cmd_complete);
>> +        dma->chan_using = dma->chan_tx;
>> +        dma->dma_transfer_dir = DMA_MEM_TO_DEV;
>> +        dma->dma_data_dir = DMA_TO_DEVICE;
>> +        dma->dma_len = msgs->len - 1;
>> +        result = i2c_imx_dma_xfer(i2c_imx, msgs);
>> +        if (result)
>> +            return result;
>>
>> -    /* write slave address */
>> -    imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> -    result = i2c_imx_trx_complete(i2c_imx);
>> -    if (result)
>> -        return result;
>> -    result = i2c_imx_acked(i2c_imx);
>> -    if (result)
>> -        return result;
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  write data\n", __func__);
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp |= I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>>
>> -    /* write data */
>> -    for (i = 0; i<  msgs->len; i++) {
>> -        dev_dbg(&i2c_imx->adapter.dev,
>> -            "<%s>  write byte: B%d=0x%X\n",
>> -            __func__, i, msgs->buf[i]);
>> -        imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
>> +        /* write slave address */
>> +        imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> +        result = wait_for_completion_interruptible_timeout(
>> + &i2c_imx->dma->cmd_complete,
>> +                    msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
>> +        if (result<= 0) {
>> +            dmaengine_terminate_all(dma->chan_using);
>> +            if (result)
>> +                return result;
>> +            else
>> +                return -ETIMEDOUT;
>> +        }
>> +
>> +        /* waiting for Transfer complete. */
>> +        while (timeout--) {
>> +            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +            if (temp&  I2SR_ICF)
>> +                break;
>> +            udelay(10);
>> +        }
>> +
>> +        if (!timeout)
>> +            return -ETIMEDOUT;
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp&= ~I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        /* write the last byte */
>> +        imx_i2c_write_reg(msgs->buf[msgs->len-1],
>> +                    i2c_imx, IMX_I2C_I2DR);
>>           result = i2c_imx_trx_complete(i2c_imx);
>>           if (result)
>>               return result;
>> +
>> +        result = i2c_imx_acked(i2c_imx);
>> +        if (result)
>> +            return result;
>> +    } else {
>> +        /* write slave address */
>> +        imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> +        result = i2c_imx_trx_complete(i2c_imx);
>> +        if (result)
>> +            return result;
>> +
>>           result = i2c_imx_acked(i2c_imx);
>>           if (result)
>>               return result;
>> +
>> +        dev_dbg(dev, "<%s>  write data\n", __func__);
>> +
>> +        /* write data */
>> +        for (i = 0; i<  msgs->len; i++) {
>> +            dev_dbg(dev, "<%s>  write byte: B%d=0x%X\n",
>> +                __func__, i, msgs->buf[i]);
>> +            imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
>> +            result = i2c_imx_trx_complete(i2c_imx);
>> +            if (result)
>> +                return result;
>> +            result = i2c_imx_acked(i2c_imx);
>> +            if (result)
>> +                return result;
>> +        }
>>       }
>>       return 0;
>>   }
>>
>>   static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct 
>> i2c_msg *msgs)
>>   {
>> -    int i, result;
>> +    int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
>>       unsigned int temp;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev,
>> -        "<%s>  write slave address: addr=0x%x\n",
>> +    dev_dbg(dev, "<%s>  write slave address: addr=0x%x\n",
>>           __func__, (msgs->addr<<  1) | 0x01);
>>
>>       /* write slave address */
>> @@ -476,7 +687,7 @@ static int i2c_imx_read(struct imx_i2c_struct 
>> *i2c_imx, struct i2c_msg *msgs)
>>       if (result)
>>           return result;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  setup bus\n", __func__);
>> +    dev_dbg(dev, "<%s>  setup bus\n", __func__);
>>
>>       /* setup bus to read data */
>>       temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> @@ -486,35 +697,81 @@ static int i2c_imx_read(struct imx_i2c_struct 
>> *i2c_imx, struct i2c_msg *msgs)
>>       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>>       imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  read data\n", __func__);
>> +    dev_dbg(dev, "<%s>  read data\n", __func__);
>>
>> -    /* read data */
>> -    for (i = 0; i<  msgs->len; i++) {
>> -        result = i2c_imx_trx_complete(i2c_imx);
>> +    if (dma&&  msgs->len>= IMX_I2C_DMA_THRESHOLD) {
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp |= I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        reinit_completion(&i2c_imx->dma->cmd_complete);
>> +        dma->chan_using = dma->chan_rx;
>> +        dma->dma_transfer_dir = DMA_DEV_TO_MEM;
>> +        dma->dma_data_dir = DMA_FROM_DEVICE;
>> +        dma->dma_len = msgs->len - 2;
>> +        result = i2c_imx_dma_xfer(i2c_imx, msgs);
>>           if (result)
>>               return result;
>> -        if (i == (msgs->len - 1)) {
>> -            /* It must generate STOP before read I2DR to prevent
>> -               controller from generating another clock cycle */
>> -            dev_dbg(&i2c_imx->adapter.dev,
>> -                "<%s>  clear MSTA\n", __func__);
>> -            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> -            temp&= ~(I2CR_MSTA | I2CR_MTX);
>> -            imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> -            i2c_imx_bus_busy(i2c_imx, 0);
>> -            i2c_imx->stopped = 1;
>> -        } else if (i == (msgs->len - 2)) {
>> -            dev_dbg(&i2c_imx->adapter.dev,
>> -                "<%s>  set TXAK\n", __func__);
>> -            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> -            temp |= I2CR_TXAK;
>> -            imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        result = wait_for_completion_interruptible_timeout(
>> + &i2c_imx->dma->cmd_complete,
>> +                    msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
>> +        if (result<= 0) {
>> +            dmaengine_terminate_all(dma->chan_using);
>> +            if (result)
>> +                return result;
>> +            else
>> +                return -ETIMEDOUT;
>>           }
>> -        msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> -        dev_dbg(&i2c_imx->adapter.dev,
>> -            "<%s>  read byte: B%d=0x%X\n",
>> -            __func__, i, msgs->buf[i]);
>> +
>> +        /* waiting for Transfer complete. */
>> +        while (timeout--) {
>> +            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +            if (temp&  I2SR_ICF)
>> +                break;
>> +            udelay(10);
>> +        }
>> +
>> +        if(!timeout)
>> +            return -ETIMEDOUT;
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp&= ~I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +    } else {
>> +        /* read data */
>> +        for (i = 0; i<  msgs->len - 2; i++) {
>> +            result = i2c_imx_trx_complete(i2c_imx);
>> +            if (result)
>> +                return result;
>> +            msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +            dev_dbg(dev, "<%s>  read byte: B%d=0x%X\n",
>> +                __func__, i, msgs->buf[i]);
>> +        }
>> +        result = i2c_imx_trx_complete(i2c_imx);
>>       }
>> +
>> +    /* read n-1 byte data */
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp |= I2CR_TXAK;
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +    msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +    /* read n byte data */
>> +    result = i2c_imx_trx_complete(i2c_imx);
>> +    if (result)
>> +        return result;
>> +
>> +    /*
>> +     * It must generate STOP before read I2DR to prevent
>> +     * controller from generating another clock cycle
>> +     */
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp&= ~(I2CR_MSTA | I2CR_MTX);
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +    i2c_imx_bus_busy(i2c_imx, 0);
>> +    i2c_imx->stopped = 1;
>> +    msgs->buf[msgs->len-1] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +
>>       return 0;
>>   }
>>
>> @@ -601,6 +858,7 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>       void __iomem *base;
>>       int irq, ret;
>>       u32 bitrate;
>> +    u32 phy_addr;
>>
>>       dev_dbg(&pdev->dev, "<%s>\n", __func__);
>>
>> @@ -611,6 +869,7 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>       }
>>
>>       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +    phy_addr = res->start;
>>       base = devm_ioremap_resource(&pdev->dev, res);
>>       if (IS_ERR(base))
>>           return PTR_ERR(base);
>> @@ -696,6 +955,10 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>           i2c_imx->adapter.name);
>>       dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
>>
>> +    /* Init DMA config if support*/
>> +    if (i2c_imx_dma_request(i2c_imx, (dma_addr_t)phy_addr))
>> +        dev_warn(&pdev->dev, "can't request DMA\n");
>> +
>>       return 0;   /* Return OK */
>>   }
>>
>> @@ -707,6 +970,9 @@ static int i2c_imx_remove(struct platform_device 
>> *pdev)
>>       dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
>>       i2c_del_adapter(&i2c_imx->adapter);
>>
>> +    if (i2c_imx->dma)
>> +        i2c_imx_dma_free(i2c_imx);
>> +
>>       /* setup chip registers to defaults */
>>       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
>>       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
>
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: sourav.poddar@ti.com (sourav)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 1/2] i2c: add DMA support for freescale i2c driver
Date: Fri, 4 Apr 2014 15:34:12 +0530	[thread overview]
Message-ID: <533E839C.9090500@ti.com> (raw)
In-Reply-To: <533E8033.70904@ti.com>


>> +
>> +    dma->chan_tx = dma_request_slave_channel(dev, "tx");
>> +    return 0;

To be more clear,
return here looks to be some leftover.

> ?? Looks to be some leftover?
>> +    if (!dma->chan_tx) {
>> +        dev_info(dev, "DMA tx channel request failed\n");
>> +        ret = -ENODEV;
>> +        goto fail_al;
>> +    }
>> +
>> +    dma_sconfig.dst_addr = phy_addr +
>> +                (IMX_I2C_I2DR<<  i2c_imx->hwdata->regshift);
>> +    dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>> +    dma_sconfig.dst_maxburst = 1;
>> +    dma_sconfig.direction = DMA_MEM_TO_DEV;
>> +    ret = dmaengine_slave_config(dma->chan_tx,&dma_sconfig);
>> +    if (ret<  0) {
>> +        dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>> +        goto fail_tx;
>> +    }
>> +
>> +    dma->chan_rx = dma_request_slave_channel(dev, "rx");
>> +    if (!dma->chan_rx) {
>> +        dev_info(dev, "DMA rx channel request failed\n");
>> +        ret = -ENODEV;
>> +        goto fail_tx;
>> +    }
>> +
>> +    dma_sconfig.src_addr = phy_addr +
>> +                (IMX_I2C_I2DR<<  i2c_imx->hwdata->regshift);
>> +    dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>> +    dma_sconfig.src_maxburst = 1;
>> +    dma_sconfig.direction = DMA_DEV_TO_MEM;
>> +    ret = dmaengine_slave_config(dma->chan_rx,&dma_sconfig);
>> +    if (ret<  0) {
>> +        dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>> +        goto fail_rx;
>> +    }
>> +
>> +    i2c_imx->dma = dma;
>> +
>> +    init_completion(&dma->cmd_complete);
>> +
>> +    return 0;
>> +
>> +fail_rx:
>> +    dma_release_channel(dma->chan_rx);
>> +fail_tx:
>> +    dma_release_channel(dma->chan_tx);
>> +fail_al:
>> +    devm_kfree(dev, dma);
>> +
>> +    return ret;
>> +}
>> +
>> +static void i2c_imx_dma_callback(void *arg)
>> +{
>> +    struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *)arg;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +
>> +    dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
>> +            dma->dma_len, dma->dma_data_dir);
>> +    complete(&dma->cmd_complete);
>> +}
>> +
>> +static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
>> +                    struct i2c_msg *msgs)
>> +{
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct dma_async_tx_descriptor *txdesc;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>> +
>> +    dma->dma_buf = dma_map_single(dma->chan_using->device->dev, 
>> msgs->buf,
>> +                    dma->dma_len, dma->dma_data_dir);
>> +    if (dma_mapping_error(dma->chan_using->device->dev, 
>> dma->dma_buf)) {
>> +        dev_err(dev, "DMA mapping failed\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
>> +                    dma->dma_len, dma->dma_transfer_dir,
>> +                    DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
>> +    if (!txdesc) {
>> +        dev_err(dev, "Not able to get desc for DMA xfer\n");
>> +        dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
>> +                    dma->dma_len, dma->dma_data_dir);
>> +        return -EINVAL;
>> +    }
>> +
>> +    txdesc->callback = i2c_imx_dma_callback;
>> +    txdesc->callback_param = i2c_imx;
>> +    dmaengine_submit(txdesc);
>> +    dma_async_issue_pending(dma->chan_using);
>> +
>> +    return 0;
>> +}
>> +
>> +static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +
>> +    dma->dma_buf = 0;
>> +    dma->dma_len = 0;
>> +
>> +    dma_release_channel(dma->chan_tx);
>> +    dma->chan_tx = NULL;
>> +
>> +    dma_release_channel(dma->chan_rx);
>> +    dma->chan_rx = NULL;
>> +
>> +    dma->chan_using = NULL;
>> +}
>> +
>>   /** Functions for IMX I2C adapter driver 
>> ***************************************
>>   
>> *******************************************************************************/
>>
>> @@ -334,6 +483,11 @@ static int i2c_imx_start(struct imx_i2c_struct 
>> *i2c_imx)
>>
>>       temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
>>       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp&= ~I2CR_DMAEN;
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>>       return result;
>>   }
>>
>> @@ -427,44 +581,101 @@ static irqreturn_t i2c_imx_isr(int irq, void 
>> *dev_id)
>>
>>   static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct 
>> i2c_msg *msgs)
>>   {
>> -    int i, result;
>> +    int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
>> +    unsigned int temp = 0;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  write slave address: 
>> addr=0x%x\n",
>> +    dev_dbg(dev, "<%s>  write slave address: addr=0x%x\n",
>>           __func__, msgs->addr<<  1);
>> +    if (dma&&  msgs->len>= IMX_I2C_DMA_THRESHOLD) {
>> +        reinit_completion(&i2c_imx->dma->cmd_complete);
>> +        dma->chan_using = dma->chan_tx;
>> +        dma->dma_transfer_dir = DMA_MEM_TO_DEV;
>> +        dma->dma_data_dir = DMA_TO_DEVICE;
>> +        dma->dma_len = msgs->len - 1;
>> +        result = i2c_imx_dma_xfer(i2c_imx, msgs);
>> +        if (result)
>> +            return result;
>>
>> -    /* write slave address */
>> -    imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> -    result = i2c_imx_trx_complete(i2c_imx);
>> -    if (result)
>> -        return result;
>> -    result = i2c_imx_acked(i2c_imx);
>> -    if (result)
>> -        return result;
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  write data\n", __func__);
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp |= I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>>
>> -    /* write data */
>> -    for (i = 0; i<  msgs->len; i++) {
>> -        dev_dbg(&i2c_imx->adapter.dev,
>> -            "<%s>  write byte: B%d=0x%X\n",
>> -            __func__, i, msgs->buf[i]);
>> -        imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
>> +        /* write slave address */
>> +        imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> +        result = wait_for_completion_interruptible_timeout(
>> + &i2c_imx->dma->cmd_complete,
>> +                    msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
>> +        if (result<= 0) {
>> +            dmaengine_terminate_all(dma->chan_using);
>> +            if (result)
>> +                return result;
>> +            else
>> +                return -ETIMEDOUT;
>> +        }
>> +
>> +        /* waiting for Transfer complete. */
>> +        while (timeout--) {
>> +            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +            if (temp&  I2SR_ICF)
>> +                break;
>> +            udelay(10);
>> +        }
>> +
>> +        if (!timeout)
>> +            return -ETIMEDOUT;
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp&= ~I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        /* write the last byte */
>> +        imx_i2c_write_reg(msgs->buf[msgs->len-1],
>> +                    i2c_imx, IMX_I2C_I2DR);
>>           result = i2c_imx_trx_complete(i2c_imx);
>>           if (result)
>>               return result;
>> +
>> +        result = i2c_imx_acked(i2c_imx);
>> +        if (result)
>> +            return result;
>> +    } else {
>> +        /* write slave address */
>> +        imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> +        result = i2c_imx_trx_complete(i2c_imx);
>> +        if (result)
>> +            return result;
>> +
>>           result = i2c_imx_acked(i2c_imx);
>>           if (result)
>>               return result;
>> +
>> +        dev_dbg(dev, "<%s>  write data\n", __func__);
>> +
>> +        /* write data */
>> +        for (i = 0; i<  msgs->len; i++) {
>> +            dev_dbg(dev, "<%s>  write byte: B%d=0x%X\n",
>> +                __func__, i, msgs->buf[i]);
>> +            imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
>> +            result = i2c_imx_trx_complete(i2c_imx);
>> +            if (result)
>> +                return result;
>> +            result = i2c_imx_acked(i2c_imx);
>> +            if (result)
>> +                return result;
>> +        }
>>       }
>>       return 0;
>>   }
>>
>>   static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct 
>> i2c_msg *msgs)
>>   {
>> -    int i, result;
>> +    int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
>>       unsigned int temp;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev,
>> -        "<%s>  write slave address: addr=0x%x\n",
>> +    dev_dbg(dev, "<%s>  write slave address: addr=0x%x\n",
>>           __func__, (msgs->addr<<  1) | 0x01);
>>
>>       /* write slave address */
>> @@ -476,7 +687,7 @@ static int i2c_imx_read(struct imx_i2c_struct 
>> *i2c_imx, struct i2c_msg *msgs)
>>       if (result)
>>           return result;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  setup bus\n", __func__);
>> +    dev_dbg(dev, "<%s>  setup bus\n", __func__);
>>
>>       /* setup bus to read data */
>>       temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> @@ -486,35 +697,81 @@ static int i2c_imx_read(struct imx_i2c_struct 
>> *i2c_imx, struct i2c_msg *msgs)
>>       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>>       imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  read data\n", __func__);
>> +    dev_dbg(dev, "<%s>  read data\n", __func__);
>>
>> -    /* read data */
>> -    for (i = 0; i<  msgs->len; i++) {
>> -        result = i2c_imx_trx_complete(i2c_imx);
>> +    if (dma&&  msgs->len>= IMX_I2C_DMA_THRESHOLD) {
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp |= I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        reinit_completion(&i2c_imx->dma->cmd_complete);
>> +        dma->chan_using = dma->chan_rx;
>> +        dma->dma_transfer_dir = DMA_DEV_TO_MEM;
>> +        dma->dma_data_dir = DMA_FROM_DEVICE;
>> +        dma->dma_len = msgs->len - 2;
>> +        result = i2c_imx_dma_xfer(i2c_imx, msgs);
>>           if (result)
>>               return result;
>> -        if (i == (msgs->len - 1)) {
>> -            /* It must generate STOP before read I2DR to prevent
>> -               controller from generating another clock cycle */
>> -            dev_dbg(&i2c_imx->adapter.dev,
>> -                "<%s>  clear MSTA\n", __func__);
>> -            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> -            temp&= ~(I2CR_MSTA | I2CR_MTX);
>> -            imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> -            i2c_imx_bus_busy(i2c_imx, 0);
>> -            i2c_imx->stopped = 1;
>> -        } else if (i == (msgs->len - 2)) {
>> -            dev_dbg(&i2c_imx->adapter.dev,
>> -                "<%s>  set TXAK\n", __func__);
>> -            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> -            temp |= I2CR_TXAK;
>> -            imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        result = wait_for_completion_interruptible_timeout(
>> + &i2c_imx->dma->cmd_complete,
>> +                    msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
>> +        if (result<= 0) {
>> +            dmaengine_terminate_all(dma->chan_using);
>> +            if (result)
>> +                return result;
>> +            else
>> +                return -ETIMEDOUT;
>>           }
>> -        msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> -        dev_dbg(&i2c_imx->adapter.dev,
>> -            "<%s>  read byte: B%d=0x%X\n",
>> -            __func__, i, msgs->buf[i]);
>> +
>> +        /* waiting for Transfer complete. */
>> +        while (timeout--) {
>> +            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +            if (temp&  I2SR_ICF)
>> +                break;
>> +            udelay(10);
>> +        }
>> +
>> +        if(!timeout)
>> +            return -ETIMEDOUT;
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp&= ~I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +    } else {
>> +        /* read data */
>> +        for (i = 0; i<  msgs->len - 2; i++) {
>> +            result = i2c_imx_trx_complete(i2c_imx);
>> +            if (result)
>> +                return result;
>> +            msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +            dev_dbg(dev, "<%s>  read byte: B%d=0x%X\n",
>> +                __func__, i, msgs->buf[i]);
>> +        }
>> +        result = i2c_imx_trx_complete(i2c_imx);
>>       }
>> +
>> +    /* read n-1 byte data */
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp |= I2CR_TXAK;
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +    msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +    /* read n byte data */
>> +    result = i2c_imx_trx_complete(i2c_imx);
>> +    if (result)
>> +        return result;
>> +
>> +    /*
>> +     * It must generate STOP before read I2DR to prevent
>> +     * controller from generating another clock cycle
>> +     */
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp&= ~(I2CR_MSTA | I2CR_MTX);
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +    i2c_imx_bus_busy(i2c_imx, 0);
>> +    i2c_imx->stopped = 1;
>> +    msgs->buf[msgs->len-1] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +
>>       return 0;
>>   }
>>
>> @@ -601,6 +858,7 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>       void __iomem *base;
>>       int irq, ret;
>>       u32 bitrate;
>> +    u32 phy_addr;
>>
>>       dev_dbg(&pdev->dev, "<%s>\n", __func__);
>>
>> @@ -611,6 +869,7 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>       }
>>
>>       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +    phy_addr = res->start;
>>       base = devm_ioremap_resource(&pdev->dev, res);
>>       if (IS_ERR(base))
>>           return PTR_ERR(base);
>> @@ -696,6 +955,10 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>           i2c_imx->adapter.name);
>>       dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
>>
>> +    /* Init DMA config if support*/
>> +    if (i2c_imx_dma_request(i2c_imx, (dma_addr_t)phy_addr))
>> +        dev_warn(&pdev->dev, "can't request DMA\n");
>> +
>>       return 0;   /* Return OK */
>>   }
>>
>> @@ -707,6 +970,9 @@ static int i2c_imx_remove(struct platform_device 
>> *pdev)
>>       dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
>>       i2c_del_adapter(&i2c_imx->adapter);
>>
>> +    if (i2c_imx->dma)
>> +        i2c_imx_dma_free(i2c_imx);
>> +
>>       /* setup chip registers to defaults */
>>       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
>>       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
>
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: sourav <sourav.poddar@ti.com>
To: Yuan Yao <yao.yuan@freescale.com>
Cc: <wsa@the-dreams.de>, <marex@denx.de>, <mark.rutland@arm.com>,
	<shawn.guo@linaro.org>, <linux-kernel@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-i2c@vger.kernel.org>
Subject: Re: [PATCH v4 1/2] i2c: add DMA support for freescale i2c driver
Date: Fri, 4 Apr 2014 15:34:12 +0530	[thread overview]
Message-ID: <533E839C.9090500@ti.com> (raw)
In-Reply-To: <533E8033.70904@ti.com>


>> +
>> +    dma->chan_tx = dma_request_slave_channel(dev, "tx");
>> +    return 0;

To be more clear,
return here looks to be some leftover.

> ?? Looks to be some leftover?
>> +    if (!dma->chan_tx) {
>> +        dev_info(dev, "DMA tx channel request failed\n");
>> +        ret = -ENODEV;
>> +        goto fail_al;
>> +    }
>> +
>> +    dma_sconfig.dst_addr = phy_addr +
>> +                (IMX_I2C_I2DR<<  i2c_imx->hwdata->regshift);
>> +    dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>> +    dma_sconfig.dst_maxburst = 1;
>> +    dma_sconfig.direction = DMA_MEM_TO_DEV;
>> +    ret = dmaengine_slave_config(dma->chan_tx,&dma_sconfig);
>> +    if (ret<  0) {
>> +        dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>> +        goto fail_tx;
>> +    }
>> +
>> +    dma->chan_rx = dma_request_slave_channel(dev, "rx");
>> +    if (!dma->chan_rx) {
>> +        dev_info(dev, "DMA rx channel request failed\n");
>> +        ret = -ENODEV;
>> +        goto fail_tx;
>> +    }
>> +
>> +    dma_sconfig.src_addr = phy_addr +
>> +                (IMX_I2C_I2DR<<  i2c_imx->hwdata->regshift);
>> +    dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>> +    dma_sconfig.src_maxburst = 1;
>> +    dma_sconfig.direction = DMA_DEV_TO_MEM;
>> +    ret = dmaengine_slave_config(dma->chan_rx,&dma_sconfig);
>> +    if (ret<  0) {
>> +        dev_info(dev, "DMA slave config failed, err = %d\n", ret);
>> +        goto fail_rx;
>> +    }
>> +
>> +    i2c_imx->dma = dma;
>> +
>> +    init_completion(&dma->cmd_complete);
>> +
>> +    return 0;
>> +
>> +fail_rx:
>> +    dma_release_channel(dma->chan_rx);
>> +fail_tx:
>> +    dma_release_channel(dma->chan_tx);
>> +fail_al:
>> +    devm_kfree(dev, dma);
>> +
>> +    return ret;
>> +}
>> +
>> +static void i2c_imx_dma_callback(void *arg)
>> +{
>> +    struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *)arg;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +
>> +    dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
>> +            dma->dma_len, dma->dma_data_dir);
>> +    complete(&dma->cmd_complete);
>> +}
>> +
>> +static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
>> +                    struct i2c_msg *msgs)
>> +{
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct dma_async_tx_descriptor *txdesc;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>> +
>> +    dma->dma_buf = dma_map_single(dma->chan_using->device->dev, 
>> msgs->buf,
>> +                    dma->dma_len, dma->dma_data_dir);
>> +    if (dma_mapping_error(dma->chan_using->device->dev, 
>> dma->dma_buf)) {
>> +        dev_err(dev, "DMA mapping failed\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
>> +                    dma->dma_len, dma->dma_transfer_dir,
>> +                    DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
>> +    if (!txdesc) {
>> +        dev_err(dev, "Not able to get desc for DMA xfer\n");
>> +        dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf,
>> +                    dma->dma_len, dma->dma_data_dir);
>> +        return -EINVAL;
>> +    }
>> +
>> +    txdesc->callback = i2c_imx_dma_callback;
>> +    txdesc->callback_param = i2c_imx;
>> +    dmaengine_submit(txdesc);
>> +    dma_async_issue_pending(dma->chan_using);
>> +
>> +    return 0;
>> +}
>> +
>> +static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
>> +{
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +
>> +    dma->dma_buf = 0;
>> +    dma->dma_len = 0;
>> +
>> +    dma_release_channel(dma->chan_tx);
>> +    dma->chan_tx = NULL;
>> +
>> +    dma_release_channel(dma->chan_rx);
>> +    dma->chan_rx = NULL;
>> +
>> +    dma->chan_using = NULL;
>> +}
>> +
>>   /** Functions for IMX I2C adapter driver 
>> ***************************************
>>   
>> *******************************************************************************/
>>
>> @@ -334,6 +483,11 @@ static int i2c_imx_start(struct imx_i2c_struct 
>> *i2c_imx)
>>
>>       temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
>>       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp&= ~I2CR_DMAEN;
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>>       return result;
>>   }
>>
>> @@ -427,44 +581,101 @@ static irqreturn_t i2c_imx_isr(int irq, void 
>> *dev_id)
>>
>>   static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct 
>> i2c_msg *msgs)
>>   {
>> -    int i, result;
>> +    int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
>> +    unsigned int temp = 0;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  write slave address: 
>> addr=0x%x\n",
>> +    dev_dbg(dev, "<%s>  write slave address: addr=0x%x\n",
>>           __func__, msgs->addr<<  1);
>> +    if (dma&&  msgs->len>= IMX_I2C_DMA_THRESHOLD) {
>> +        reinit_completion(&i2c_imx->dma->cmd_complete);
>> +        dma->chan_using = dma->chan_tx;
>> +        dma->dma_transfer_dir = DMA_MEM_TO_DEV;
>> +        dma->dma_data_dir = DMA_TO_DEVICE;
>> +        dma->dma_len = msgs->len - 1;
>> +        result = i2c_imx_dma_xfer(i2c_imx, msgs);
>> +        if (result)
>> +            return result;
>>
>> -    /* write slave address */
>> -    imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> -    result = i2c_imx_trx_complete(i2c_imx);
>> -    if (result)
>> -        return result;
>> -    result = i2c_imx_acked(i2c_imx);
>> -    if (result)
>> -        return result;
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  write data\n", __func__);
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp |= I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>>
>> -    /* write data */
>> -    for (i = 0; i<  msgs->len; i++) {
>> -        dev_dbg(&i2c_imx->adapter.dev,
>> -            "<%s>  write byte: B%d=0x%X\n",
>> -            __func__, i, msgs->buf[i]);
>> -        imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
>> +        /* write slave address */
>> +        imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> +        result = wait_for_completion_interruptible_timeout(
>> + &i2c_imx->dma->cmd_complete,
>> +                    msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
>> +        if (result<= 0) {
>> +            dmaengine_terminate_all(dma->chan_using);
>> +            if (result)
>> +                return result;
>> +            else
>> +                return -ETIMEDOUT;
>> +        }
>> +
>> +        /* waiting for Transfer complete. */
>> +        while (timeout--) {
>> +            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +            if (temp&  I2SR_ICF)
>> +                break;
>> +            udelay(10);
>> +        }
>> +
>> +        if (!timeout)
>> +            return -ETIMEDOUT;
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp&= ~I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        /* write the last byte */
>> +        imx_i2c_write_reg(msgs->buf[msgs->len-1],
>> +                    i2c_imx, IMX_I2C_I2DR);
>>           result = i2c_imx_trx_complete(i2c_imx);
>>           if (result)
>>               return result;
>> +
>> +        result = i2c_imx_acked(i2c_imx);
>> +        if (result)
>> +            return result;
>> +    } else {
>> +        /* write slave address */
>> +        imx_i2c_write_reg(msgs->addr<<  1, i2c_imx, IMX_I2C_I2DR);
>> +        result = i2c_imx_trx_complete(i2c_imx);
>> +        if (result)
>> +            return result;
>> +
>>           result = i2c_imx_acked(i2c_imx);
>>           if (result)
>>               return result;
>> +
>> +        dev_dbg(dev, "<%s>  write data\n", __func__);
>> +
>> +        /* write data */
>> +        for (i = 0; i<  msgs->len; i++) {
>> +            dev_dbg(dev, "<%s>  write byte: B%d=0x%X\n",
>> +                __func__, i, msgs->buf[i]);
>> +            imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
>> +            result = i2c_imx_trx_complete(i2c_imx);
>> +            if (result)
>> +                return result;
>> +            result = i2c_imx_acked(i2c_imx);
>> +            if (result)
>> +                return result;
>> +        }
>>       }
>>       return 0;
>>   }
>>
>>   static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct 
>> i2c_msg *msgs)
>>   {
>> -    int i, result;
>> +    int i, result, timeout = IMX_I2C_DMA_TIMEOUT;
>>       unsigned int temp;
>> +    struct imx_i2c_dma *dma = i2c_imx->dma;
>> +    struct device *dev =&i2c_imx->adapter.dev;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev,
>> -        "<%s>  write slave address: addr=0x%x\n",
>> +    dev_dbg(dev, "<%s>  write slave address: addr=0x%x\n",
>>           __func__, (msgs->addr<<  1) | 0x01);
>>
>>       /* write slave address */
>> @@ -476,7 +687,7 @@ static int i2c_imx_read(struct imx_i2c_struct 
>> *i2c_imx, struct i2c_msg *msgs)
>>       if (result)
>>           return result;
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  setup bus\n", __func__);
>> +    dev_dbg(dev, "<%s>  setup bus\n", __func__);
>>
>>       /* setup bus to read data */
>>       temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> @@ -486,35 +697,81 @@ static int i2c_imx_read(struct imx_i2c_struct 
>> *i2c_imx, struct i2c_msg *msgs)
>>       imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>>       imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
>>
>> -    dev_dbg(&i2c_imx->adapter.dev, "<%s>  read data\n", __func__);
>> +    dev_dbg(dev, "<%s>  read data\n", __func__);
>>
>> -    /* read data */
>> -    for (i = 0; i<  msgs->len; i++) {
>> -        result = i2c_imx_trx_complete(i2c_imx);
>> +    if (dma&&  msgs->len>= IMX_I2C_DMA_THRESHOLD) {
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp |= I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        reinit_completion(&i2c_imx->dma->cmd_complete);
>> +        dma->chan_using = dma->chan_rx;
>> +        dma->dma_transfer_dir = DMA_DEV_TO_MEM;
>> +        dma->dma_data_dir = DMA_FROM_DEVICE;
>> +        dma->dma_len = msgs->len - 2;
>> +        result = i2c_imx_dma_xfer(i2c_imx, msgs);
>>           if (result)
>>               return result;
>> -        if (i == (msgs->len - 1)) {
>> -            /* It must generate STOP before read I2DR to prevent
>> -               controller from generating another clock cycle */
>> -            dev_dbg(&i2c_imx->adapter.dev,
>> -                "<%s>  clear MSTA\n", __func__);
>> -            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> -            temp&= ~(I2CR_MSTA | I2CR_MTX);
>> -            imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> -            i2c_imx_bus_busy(i2c_imx, 0);
>> -            i2c_imx->stopped = 1;
>> -        } else if (i == (msgs->len - 2)) {
>> -            dev_dbg(&i2c_imx->adapter.dev,
>> -                "<%s>  set TXAK\n", __func__);
>> -            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> -            temp |= I2CR_TXAK;
>> -            imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +        result = wait_for_completion_interruptible_timeout(
>> + &i2c_imx->dma->cmd_complete,
>> +                    msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
>> +        if (result<= 0) {
>> +            dmaengine_terminate_all(dma->chan_using);
>> +            if (result)
>> +                return result;
>> +            else
>> +                return -ETIMEDOUT;
>>           }
>> -        msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> -        dev_dbg(&i2c_imx->adapter.dev,
>> -            "<%s>  read byte: B%d=0x%X\n",
>> -            __func__, i, msgs->buf[i]);
>> +
>> +        /* waiting for Transfer complete. */
>> +        while (timeout--) {
>> +            temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> +            if (temp&  I2SR_ICF)
>> +                break;
>> +            udelay(10);
>> +        }
>> +
>> +        if(!timeout)
>> +            return -ETIMEDOUT;
>> +        temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +        temp&= ~I2CR_DMAEN;
>> +        imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +    } else {
>> +        /* read data */
>> +        for (i = 0; i<  msgs->len - 2; i++) {
>> +            result = i2c_imx_trx_complete(i2c_imx);
>> +            if (result)
>> +                return result;
>> +            msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +            dev_dbg(dev, "<%s>  read byte: B%d=0x%X\n",
>> +                __func__, i, msgs->buf[i]);
>> +        }
>> +        result = i2c_imx_trx_complete(i2c_imx);
>>       }
>> +
>> +    /* read n-1 byte data */
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp |= I2CR_TXAK;
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +
>> +    msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +    /* read n byte data */
>> +    result = i2c_imx_trx_complete(i2c_imx);
>> +    if (result)
>> +        return result;
>> +
>> +    /*
>> +     * It must generate STOP before read I2DR to prevent
>> +     * controller from generating another clock cycle
>> +     */
>> +    temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
>> +    temp&= ~(I2CR_MSTA | I2CR_MTX);
>> +    imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
>> +    i2c_imx_bus_busy(i2c_imx, 0);
>> +    i2c_imx->stopped = 1;
>> +    msgs->buf[msgs->len-1] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
>> +
>>       return 0;
>>   }
>>
>> @@ -601,6 +858,7 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>       void __iomem *base;
>>       int irq, ret;
>>       u32 bitrate;
>> +    u32 phy_addr;
>>
>>       dev_dbg(&pdev->dev, "<%s>\n", __func__);
>>
>> @@ -611,6 +869,7 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>       }
>>
>>       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +    phy_addr = res->start;
>>       base = devm_ioremap_resource(&pdev->dev, res);
>>       if (IS_ERR(base))
>>           return PTR_ERR(base);
>> @@ -696,6 +955,10 @@ static int i2c_imx_probe(struct platform_device 
>> *pdev)
>>           i2c_imx->adapter.name);
>>       dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
>>
>> +    /* Init DMA config if support*/
>> +    if (i2c_imx_dma_request(i2c_imx, (dma_addr_t)phy_addr))
>> +        dev_warn(&pdev->dev, "can't request DMA\n");
>> +
>>       return 0;   /* Return OK */
>>   }
>>
>> @@ -707,6 +970,9 @@ static int i2c_imx_remove(struct platform_device 
>> *pdev)
>>       dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
>>       i2c_del_adapter(&i2c_imx->adapter);
>>
>> +    if (i2c_imx->dma)
>> +        i2c_imx_dma_free(i2c_imx);
>> +
>>       /* setup chip registers to defaults */
>>       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
>>       imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
>
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


  parent reply	other threads:[~2014-04-04 10:04 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-04  2:41 [PATCH v4 0/2] i2c: add DMA support for freescale i2c driver Yuan Yao
2014-04-04  2:41 ` Yuan Yao
2014-04-04  2:41 ` Yuan Yao
2014-04-04  2:41 ` [PATCH v4 1/2] " Yuan Yao
2014-04-04  2:41   ` Yuan Yao
2014-04-04  2:41   ` Yuan Yao
     [not found]   ` <1396579272-19542-2-git-send-email-yao.yuan-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2014-04-04  9:49     ` sourav
2014-04-04  9:49       ` sourav
2014-04-04  9:49       ` sourav
     [not found]       ` <533E8033.70904-l0cyMroinI0@public.gmane.org>
2014-04-04 10:04         ` sourav [this message]
2014-04-04 10:04           ` sourav
2014-04-04 10:04           ` sourav
2014-04-04 11:49         ` Marek Vasut
2014-04-04 11:49           ` Marek Vasut
2014-04-04 11:49           ` Marek Vasut
2014-04-04 14:28     ` Marek Vasut
2014-04-04 14:28       ` Marek Vasut
2014-04-04 14:28       ` Marek Vasut
     [not found]       ` <201404041628.55471.marex-ynQEQJNshbs@public.gmane.org>
2014-04-04 14:40         ` Wolfram Sang
2014-04-04 14:40           ` Wolfram Sang
2014-04-04 14:40           ` Wolfram Sang
2014-04-04 15:45       ` Yao Yuan
2014-04-04 15:45         ` Yao Yuan
     [not found]         ` <aab78696ac364d9c832993c08915bad3-AZ66ij2kwaZYLYlmg7qx2OO6mTEJWrR4XA4E9RH9d+qIuWR1G4zioA@public.gmane.org>
2014-04-04 17:40           ` Wolfram Sang
2014-04-04 17:40             ` Wolfram Sang
2014-04-04 17:40             ` Wolfram Sang
2014-05-21  8:00             ` Wolfram Sang
2014-05-21  8:00               ` Wolfram Sang
2014-05-21  8:00               ` Wolfram Sang
2014-07-24  3:19               ` Yao Yuan
2014-07-24  3:19                 ` Yao Yuan
2014-07-24  3:19                 ` Yao Yuan
     [not found]                 ` <e97f086de6e9427f96ca5ac582031f86-AZ66ij2kwaZYLYlmg7qx2OO6mTEJWrR4XA4E9RH9d+qIuWR1G4zioA@public.gmane.org>
2014-07-24  4:14                   ` Marek Vasut
2014-07-24  4:14                     ` Marek Vasut
2014-07-24  4:14                     ` Marek Vasut
     [not found] ` <1396579272-19542-1-git-send-email-yao.yuan-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2014-04-04  2:41   ` [PATCH v4 2/2] Documentation:add " Yuan Yao
2014-04-04  2:41     ` Yuan Yao
2014-04-04  2:41     ` Yuan Yao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=533E839C.9090500@ti.com \
    --to=sourav.poddar-l0cymroini0@public.gmane.org \
    --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=marex-ynQEQJNshbs@public.gmane.org \
    --cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
    --cc=shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org \
    --cc=yao.yuan-KZfg59tc24xl57MIdRCFDg@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.