Re: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-07 Thread Lothar Waßmann
Hi,

fugang.d...@freescale.com wrote:
> From: Yuan Yao-B46683 Data: Thursday, August 07, 2014 4:05 PM
> >To: Duan Fugang-B38611; w...@the-dreams.de; ma...@denx.de
> >Cc: l...@karo-electronics.de; mark.rutl...@arm.com; shawn@linaro.org;
> >linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux-
> >i...@vger.kernel.org; Li Frank-B20596
> >Subject: RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c
> >driver
> >
> >Hi Fugang,
> >
> >> >> >+  /* Waiting for Transfer complete. */
> >> >> >+  while (timeout--) {
> >> >> >+  temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
> >> >> >+  if (temp & I2SR_ICF)
> >> >> >+  break;
> >> >> >+  udelay(10);
> >> >> >+  }
> >> >> Whether there have better method like interrupt to avoid dead wait
> >> >> here until timeout ?
> >> >
> >> >Can you give me more suggestion? We have discussed it with our team,
> >> >It seems the short query wait is necessary.
> >> >
> >> At least, you can use schdule_timeout() instead of udelay() ?
> >
> >In fact, the waiting time normally is less than 10-50us, but the minimum
> >time interval for schdule_timeout() is 1 jiffies.
> >So maybe schdule_timeout() is not very necessary?
> >
> Oh, if the waiting time is 10 ~ 50us, you can use usleep_range(10, 50).
>
The loop is not meant to generate a certain delay, but to wait for some
HW flag to change within a certain time frame. So usleep_range() is
rather inadequate here!


But looking a little closer at the function, the timeout value seems to
be rather bogus to me. The loop counter 'timeout' is initialized from 
the constant IMX_I2C_DMA_TIMEOUT which is also used in
|wait_for_completion_interruptible_timeout(
|   &i2c_imx->dma->cmd_complete,
|   msecs_to_jiffies(IMX_I2C_DMA_TIMEOUT));
 ^^^
as a number of milliseconds to wait for DMA completion.


Lothar Waßmann
-- 
___

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | i...@karo-electronics.de
___
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-07 Thread fugang.d...@freescale.com
From: Yuan Yao-B46683 Data: Thursday, August 07, 2014 4:05 PM
>To: Duan Fugang-B38611; w...@the-dreams.de; ma...@denx.de
>Cc: l...@karo-electronics.de; mark.rutl...@arm.com; shawn@linaro.org;
>linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux-
>i...@vger.kernel.org; Li Frank-B20596
>Subject: RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c
>driver
>
>Hi Fugang,
>
>> >> >+/* Waiting for Transfer complete. */
>> >> >+while (timeout--) {
>> >> >+temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> >> >+if (temp & I2SR_ICF)
>> >> >+break;
>> >> >+udelay(10);
>> >> >+}
>> >> Whether there have better method like interrupt to avoid dead wait
>> >> here until timeout ?
>> >
>> >Can you give me more suggestion? We have discussed it with our team,
>> >It seems the short query wait is necessary.
>> >
>> At least, you can use schdule_timeout() instead of udelay() ?
>
>In fact, the waiting time normally is less than 10-50us, but the minimum
>time interval for schdule_timeout() is 1 jiffies.
>So maybe schdule_timeout() is not very necessary?
>
Oh, if the waiting time is 10 ~ 50us, you can use usleep_range(10, 50).
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-07 Thread Yao Yuan
Hi Fugang,

> >> >+ /* Waiting for Transfer complete. */
> >> >+ while (timeout--) {
> >> >+ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
> >> >+ if (temp & I2SR_ICF)
> >> >+ break;
> >> >+ udelay(10);
> >> >+ }
> >> Whether there have better method like interrupt to avoid dead wait
> >> here until timeout ?
> >
> >Can you give me more suggestion? We have discussed it with our team, It
> >seems the short query wait is necessary.
> >
> At least, you can use schdule_timeout() instead of udelay() ?

In fact, the waiting time normally is less than 10-50us, but the minimum time 
interval for schdule_timeout() is 1 jiffies.
So maybe schdule_timeout() is not very necessary?




Thanks for your review.

Best Regards,
Yuan Yao
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-06 Thread fugang.d...@freescale.com
From: Yuan Yao-B46683 Data: Wednesday, August 06, 2014 3:07 PM
>To: Duan Fugang-B38611; w...@the-dreams.de; ma...@denx.de
>Cc: l...@karo-electronics.de; mark.rutl...@arm.com; shawn@linaro.org;
>linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux-
>i...@vger.kernel.org; Li Frank-B20596
>Subject: RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c
>driver
>
>Hi Fugang,
>
>Duan Fugang wrote:
>[...]
>>+ dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>>+ dma_sconfig.dst_maxburst = 1;
>> The maxburst is 1 cause very slow efficiency for DMA copy, which
>> system performance even is slower Than cpu mode.
>
>There is no FIFO for IMX i2c, so the maxburst shoud be 1 for hardware
>request.
>
Understand. Thanks.

>
>> >+   /* Waiting for Transfer complete. */
>> >+   while (timeout--) {
>> >+   temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
>> >+   if (temp & I2SR_ICF)
>> >+   break;
>> >+   udelay(10);
>> >+   }
>> Whether there have better method like interrupt to avoid dead wait
>> here until timeout ?
>
>Can you give me more suggestion? We have discussed it with our team, It
>seems the short query wait is necessary.
>
At least, you can use schdule_timeout() instead of udelay() ?

>> >+
>> >+   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);
>> >+
>> >+   /* The last data byte must be transferred by the CPU. */
>> >+   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;
>> I don't understand why the last data need to be transmited by cpu. I
>> guess you want to get IIF interrupt ?
>
>Yes, we need the interrupt to do some mop-up.
>
>Also follow the hardware request as:
>
>The following flow diagram details exactly the operation for using a DMA
>controller to transmit "n" data bytes to a slave. The first byte (the
>slave calling address) is always transmitted by the CPU. All subsequent
>data bytes (apart from the last data byte) can be transferred by the DMA
>controller. The last data byte must be transferred by the CPU.
>
>> >+
>> >+   result = i2c_imx_acked(i2c_imx);
>> >+   if (result)
>> >+   return result;
>> >+
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-06 Thread Wolfram Sang
> > static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
> >  struct i2c_msg *msgs)
> > 
> > run checkpatch.pl on this patch...
> 
> Sorry for my code style. I will match open parenthesis in this case.

FYI, I am not strict on the open parenthesis thingie.



signature.asc
Description: Digital signature


RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-06 Thread Yao Yuan
Hi Fugang,

Duan Fugang wrote:
[...]
>+  dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
>+  dma_sconfig.dst_maxburst = 1;
> The maxburst is 1 cause very slow efficiency for DMA copy, which system
> performance even is slower Than cpu mode.

There is no FIFO for IMX i2c, so the maxburst shoud be 1 for hardware request.

[...]

> >+/* Waiting for Transfer complete. */
> >+while (timeout--) {
> >+temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
> >+if (temp & I2SR_ICF)
> >+break;
> >+udelay(10);
> >+}
> Whether there have better method like interrupt to avoid dead wait here until
> timeout ?

Can you give me more suggestion? We have discussed it with our team, It seems 
the short query wait is necessary.

> >+
> >+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);
> >+
> >+/* The last data byte must be transferred by the CPU. */
> >+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;
> I don't understand why the last data need to be transmited by cpu. I guess you
> want to get IIF interrupt ?

Yes, we need the interrupt to do some mop-up.

Also follow the hardware request as:

The following flow diagram details exactly the operation for using a DMA 
controller to
transmit "n" data bytes to a slave. The first byte (the slave calling address) 
is always
transmitted by the CPU. All subsequent data bytes (apart from the last data 
byte) can be
transferred by the DMA controller. The last data byte must be transferred by 
the CPU.


> >+
> >+result = i2c_imx_acked(i2c_imx);
> >+if (result)
> >+return result;
> >+

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-05 Thread fugang.d...@freescale.com
From:  Yuan Yao Data: Tuesday, August 05, 2014 5:56 PM
>To: w...@the-dreams.de; ma...@denx.de
>Cc: l...@karo-electronics.de; mark.rutl...@arm.com; shawn@linaro.org;
>linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux-
>i...@vger.kernel.org
>Subject: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver
>
>Add dma support for i2c. This function depend on DMA driver.
>You can turn on it by write both the dmas and dma-name properties in dts
>node.
>DMA is optional, even DMA request unsuccessfully, i2c can also work well.
>
>Signed-off-by: Yuan Yao 
>---
> drivers/i2c/busses/i2c-imx.c | 341
>+--
> 1 file changed, 331 insertions(+), 10 deletions(-)
>
>diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
>index aa8bc14..60ea946 100644
>--- a/drivers/i2c/busses/i2c-imx.c
>+++ b/drivers/i2c/busses/i2c-imx.c
>@@ -37,22 +37,27 @@
> /** Includes
>***
>
>**
>*/
[...]

>+/* Functions for DMA support */
>+static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
>+  dma_addr_t phy_addr)
>+{
>+  struct imx_i2c_dma *dma;
>+  struct dma_slave_config dma_sconfig;
>+  struct device *dev = &i2c_imx->adapter.dev;
>+  int ret;
>+
>+  dma = devm_kzalloc(dev, sizeof(struct imx_i2c_dma), GFP_KERNEL);
>+  if (!dma)
>+  return -ENOMEM;
>+
>+  dma->chan_tx = dma_request_slave_channel(dev, "tx");
>+  if (!dma->chan_tx) {
>+  dev_dbg(dev, "can't request DMA tx channel\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;
The maxburst is 1 cause very slow efficiency for DMA copy, which system 
performance even is slower
Than cpu mode.

>+  dma_sconfig.direction = DMA_MEM_TO_DEV;
>+  ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
>+  if (ret < 0) {
>+  dev_dbg(dev, "can't configure tx channel\n");
>+  goto fail_tx;
>+  }
>+
>+  dma->chan_rx = dma_request_slave_channel(dev, "rx");
>+  if (!dma->chan_rx) {
>+  dev_dbg(dev, "can't request DMA rx channel\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;
As above.

>+  dma_sconfig.direction = DMA_DEV_TO_MEM;
>+  ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
>+  if (ret < 0) {
>+  dev_dbg(dev, "can't configure rx channel\n");
>+  goto fail_rx;
>+  }
>+
>+  i2c_imx->dma = dma;
>+  init_completion(&dma->cmd_complete);
>+  dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
>+  dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
>+
>+  return 0;
>+
>+fail_rx:
>+  dma_release_channel(dma->chan_rx);
>+fail_tx:
>+  dma_release_channel(dma->chan_tx);
>+fail_al:
>+  devm_kfree(dev, dma);
>+  dev_info(dev, "can't use DMA\n");
>+
>+  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;
>+  struct device *chan_dev = dma->chan_using->device->dev;
>+
>+  dma->dma_buf = dma_map_single(chan_dev, msgs->buf,
>+  dma->dma_len, dma->dma_data_dir);
>+  if (dma_mapping_error(chan_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(chan_dev, dma->dma_buf,
>+  dma->dma_len, dma->dma_data_dir);
>+  return -EINVAL;
>+  }
>+

RE: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-05 Thread Yao Yuan
Thanks for your review.

Varka Bhadram wrote:
> On 08/05/2014 03:26 PM, Yuan Yao wrote:
> 
> (...)
> > +fail_rx:
> > +   dma_release_channel(dma->chan_rx);
> > +fail_tx:
> > +   dma_release_channel(dma->chan_tx);
> > +fail_al:
> > +   devm_kfree(dev, dma);
> 
> no need to use devm_kfree() if we use devm_kzalloc()...
> 
We have discussed it before.
As Lothar Waßmann said:
"The devm_kfree() is not in the failure path of the driver's probe() function, 
but in the function that tries to initialize the optional DMA support."
So It seems need to use devm_kfree().
Do you have some other opinions?

> > +   dev_info(dev, "can't use DMA\n");
> > +
> > +   return ret;
> > +}

(...)

> > +static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
> > +   struct i2c_msg *msgs)
> 
> static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
>struct i2c_msg *msgs)
> 
> run checkpatch.pl on this patch...

Sorry for my code style. I will match open parenthesis in this case.

I had run this script before, just one warning.


> --
> Regards,
> Varka Bhadram.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v6 1/2] i2c: imx: add DMA support for freescale i2c driver

2014-08-05 Thread Varka Bhadram

On 08/05/2014 03:26 PM, Yuan Yao wrote:

(...)


+/* Functions for DMA support */
+static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
+   dma_addr_t phy_addr)


should match open parenthesis...

static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
   dma_addr_t phy_addr)


+{
+   struct imx_i2c_dma *dma;
+   struct dma_slave_config dma_sconfig;
+   struct device *dev = &i2c_imx->adapter.dev;
+   int ret;
+
+   dma = devm_kzalloc(dev, sizeof(struct imx_i2c_dma), GFP_KERNEL);


sizeof(*dma) ?


+   if (!dma)
+   return -ENOMEM;
+
+   dma->chan_tx = dma_request_slave_channel(dev, "tx");
+   if (!dma->chan_tx) {
+   dev_dbg(dev, "can't request DMA tx channel\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_dbg(dev, "can't configure tx channel\n");
+   goto fail_tx;
+   }
+
+   dma->chan_rx = dma_request_slave_channel(dev, "rx");
+   if (!dma->chan_rx) {
+   dev_dbg(dev, "can't request DMA rx channel\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_dbg(dev, "can't configure rx channel\n");
+   goto fail_rx;
+   }
+
+   i2c_imx->dma = dma;
+   init_completion(&dma->cmd_complete);
+   dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+   dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+
+   return 0;
+
+fail_rx:
+   dma_release_channel(dma->chan_rx);
+fail_tx:
+   dma_release_channel(dma->chan_tx);
+fail_al:
+   devm_kfree(dev, dma);


no need to use devm_kfree() if we use devm_kzalloc()...


+   dev_info(dev, "can't use DMA\n");
+
+   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)


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;
+   struct device *chan_dev = dma->chan_using->device->dev;
+
+   dma->dma_buf = dma_map_single(chan_dev, msgs->buf,
+   dma->dma_len, dma->dma_data_dir);


dma_map_single(chan_dev, msgs->buf,
   dma->dma_len, dma->dma_data_dir);


+   if (dma_mapping_error(chan_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);


 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(chan_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 I