diff options
author | Marek Vasut <marex@denx.de> | 2012-08-23 23:44:31 -0400 |
---|---|---|
committer | Wolfram Sang <w.sang@pengutronix.de> | 2012-10-08 06:47:33 -0400 |
commit | 62885f59a26195d9f6a3f8c795225dfbab62a110 (patch) | |
tree | 56773f6a15d22154816b240c4988cb906df7ed5f /drivers/i2c/busses/i2c-mxs.c | |
parent | 102084d3d3969646cc89ea159e50898aeafc6649 (diff) |
MXS: Implement DMA support into mxs-i2c
This patch implements DMA support into mxs-i2c. DMA transfers are now enabled
via DT. The DMA operation is enabled by default.
Signed-off-by: Marek Vasut <marex@denx.de>
Tested-by: Fabio Estevam <fabio.estevam@freescale.com>
[wsa: rebased to 3.6-rc7]
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Diffstat (limited to 'drivers/i2c/busses/i2c-mxs.c')
-rw-r--r-- | drivers/i2c/busses/i2c-mxs.c | 269 |
1 files changed, 247 insertions, 22 deletions
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 51f05b8520ed..1f58197062cf 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c | |||
@@ -7,8 +7,6 @@ | |||
7 | * | 7 | * |
8 | * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. | 8 | * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. |
9 | * | 9 | * |
10 | * TODO: add dma-support if platform-support for it is available | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
14 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
@@ -31,9 +29,16 @@ | |||
31 | #include <linux/of.h> | 29 | #include <linux/of.h> |
32 | #include <linux/of_device.h> | 30 | #include <linux/of_device.h> |
33 | #include <linux/of_i2c.h> | 31 | #include <linux/of_i2c.h> |
32 | #include <linux/dma-mapping.h> | ||
33 | #include <linux/dmaengine.h> | ||
34 | #include <linux/fsl/mxs-dma.h> | ||
34 | 35 | ||
35 | #define DRIVER_NAME "mxs-i2c" | 36 | #define DRIVER_NAME "mxs-i2c" |
36 | 37 | ||
38 | static bool use_pioqueue; | ||
39 | module_param(use_pioqueue, bool, 0); | ||
40 | MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA"); | ||
41 | |||
37 | #define MXS_I2C_CTRL0 (0x00) | 42 | #define MXS_I2C_CTRL0 (0x00) |
38 | #define MXS_I2C_CTRL0_SET (0x04) | 43 | #define MXS_I2C_CTRL0_SET (0x04) |
39 | 44 | ||
@@ -146,6 +151,16 @@ struct mxs_i2c_dev { | |||
146 | u32 cmd_err; | 151 | u32 cmd_err; |
147 | struct i2c_adapter adapter; | 152 | struct i2c_adapter adapter; |
148 | const struct mxs_i2c_speed_config *speed; | 153 | const struct mxs_i2c_speed_config *speed; |
154 | |||
155 | /* DMA support components */ | ||
156 | bool dma_mode; | ||
157 | int dma_channel; | ||
158 | struct dma_chan *dmach; | ||
159 | struct mxs_dma_data dma_data; | ||
160 | uint32_t pio_data[2]; | ||
161 | uint32_t addr_data; | ||
162 | struct scatterlist sg_io[2]; | ||
163 | bool dma_read; | ||
149 | }; | 164 | }; |
150 | 165 | ||
151 | static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) | 166 | static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) |
@@ -157,7 +172,11 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) | |||
157 | writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); | 172 | writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); |
158 | 173 | ||
159 | writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); | 174 | writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); |
160 | writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, | 175 | if (i2c->dma_mode) |
176 | writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, | ||
177 | i2c->regs + MXS_I2C_QUEUECTRL_CLR); | ||
178 | else | ||
179 | writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, | ||
161 | i2c->regs + MXS_I2C_QUEUECTRL_SET); | 180 | i2c->regs + MXS_I2C_QUEUECTRL_SET); |
162 | } | 181 | } |
163 | 182 | ||
@@ -248,6 +267,150 @@ static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len) | |||
248 | return 0; | 267 | return 0; |
249 | } | 268 | } |
250 | 269 | ||
270 | static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c) | ||
271 | { | ||
272 | if (i2c->dma_read) { | ||
273 | dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); | ||
274 | dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); | ||
275 | } else { | ||
276 | dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | static void mxs_i2c_dma_irq_callback(void *param) | ||
281 | { | ||
282 | struct mxs_i2c_dev *i2c = param; | ||
283 | |||
284 | complete(&i2c->cmd_complete); | ||
285 | mxs_i2c_dma_finish(i2c); | ||
286 | } | ||
287 | |||
288 | static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, | ||
289 | struct i2c_msg *msg, uint32_t flags) | ||
290 | { | ||
291 | struct dma_async_tx_descriptor *desc; | ||
292 | struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); | ||
293 | |||
294 | if (msg->flags & I2C_M_RD) { | ||
295 | i2c->dma_read = 1; | ||
296 | i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; | ||
297 | |||
298 | /* | ||
299 | * SELECT command. | ||
300 | */ | ||
301 | |||
302 | /* Queue the PIO register write transfer. */ | ||
303 | i2c->pio_data[0] = MXS_CMD_I2C_SELECT; | ||
304 | desc = dmaengine_prep_slave_sg(i2c->dmach, | ||
305 | (struct scatterlist *)&i2c->pio_data[0], | ||
306 | 1, DMA_TRANS_NONE, 0); | ||
307 | if (!desc) { | ||
308 | dev_err(i2c->dev, | ||
309 | "Failed to get PIO reg. write descriptor.\n"); | ||
310 | goto select_init_pio_fail; | ||
311 | } | ||
312 | |||
313 | /* Queue the DMA data transfer. */ | ||
314 | sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1); | ||
315 | dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); | ||
316 | desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1, | ||
317 | DMA_MEM_TO_DEV, | ||
318 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
319 | if (!desc) { | ||
320 | dev_err(i2c->dev, | ||
321 | "Failed to get DMA data write descriptor.\n"); | ||
322 | goto select_init_dma_fail; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * READ command. | ||
327 | */ | ||
328 | |||
329 | /* Queue the PIO register write transfer. */ | ||
330 | i2c->pio_data[1] = flags | MXS_CMD_I2C_READ | | ||
331 | MXS_I2C_CTRL0_XFER_COUNT(msg->len); | ||
332 | desc = dmaengine_prep_slave_sg(i2c->dmach, | ||
333 | (struct scatterlist *)&i2c->pio_data[1], | ||
334 | 1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT); | ||
335 | if (!desc) { | ||
336 | dev_err(i2c->dev, | ||
337 | "Failed to get PIO reg. write descriptor.\n"); | ||
338 | goto select_init_dma_fail; | ||
339 | } | ||
340 | |||
341 | /* Queue the DMA data transfer. */ | ||
342 | sg_init_one(&i2c->sg_io[1], msg->buf, msg->len); | ||
343 | dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); | ||
344 | desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1, | ||
345 | DMA_DEV_TO_MEM, | ||
346 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
347 | if (!desc) { | ||
348 | dev_err(i2c->dev, | ||
349 | "Failed to get DMA data write descriptor.\n"); | ||
350 | goto read_init_dma_fail; | ||
351 | } | ||
352 | } else { | ||
353 | i2c->dma_read = 0; | ||
354 | i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; | ||
355 | |||
356 | /* | ||
357 | * WRITE command. | ||
358 | */ | ||
359 | |||
360 | /* Queue the PIO register write transfer. */ | ||
361 | i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE | | ||
362 | MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1); | ||
363 | desc = dmaengine_prep_slave_sg(i2c->dmach, | ||
364 | (struct scatterlist *)&i2c->pio_data[0], | ||
365 | 1, DMA_TRANS_NONE, 0); | ||
366 | if (!desc) { | ||
367 | dev_err(i2c->dev, | ||
368 | "Failed to get PIO reg. write descriptor.\n"); | ||
369 | goto write_init_pio_fail; | ||
370 | } | ||
371 | |||
372 | /* Queue the DMA data transfer. */ | ||
373 | sg_init_table(i2c->sg_io, 2); | ||
374 | sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1); | ||
375 | sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len); | ||
376 | dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); | ||
377 | desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2, | ||
378 | DMA_MEM_TO_DEV, | ||
379 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
380 | if (!desc) { | ||
381 | dev_err(i2c->dev, | ||
382 | "Failed to get DMA data write descriptor.\n"); | ||
383 | goto write_init_dma_fail; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * The last descriptor must have this callback, | ||
389 | * to finish the DMA transaction. | ||
390 | */ | ||
391 | desc->callback = mxs_i2c_dma_irq_callback; | ||
392 | desc->callback_param = i2c; | ||
393 | |||
394 | /* Start the transfer. */ | ||
395 | dmaengine_submit(desc); | ||
396 | dma_async_issue_pending(i2c->dmach); | ||
397 | return 0; | ||
398 | |||
399 | /* Read failpath. */ | ||
400 | read_init_dma_fail: | ||
401 | dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); | ||
402 | select_init_dma_fail: | ||
403 | dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); | ||
404 | select_init_pio_fail: | ||
405 | return -EINVAL; | ||
406 | |||
407 | /* Write failpath. */ | ||
408 | write_init_dma_fail: | ||
409 | dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); | ||
410 | write_init_pio_fail: | ||
411 | return -EINVAL; | ||
412 | } | ||
413 | |||
251 | /* | 414 | /* |
252 | * Low level master read/write transaction. | 415 | * Low level master read/write transaction. |
253 | */ | 416 | */ |
@@ -258,6 +421,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, | |||
258 | int ret; | 421 | int ret; |
259 | int flags; | 422 | int flags; |
260 | 423 | ||
424 | flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; | ||
425 | |||
261 | dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", | 426 | dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", |
262 | msg->addr, msg->len, msg->flags, stop); | 427 | msg->addr, msg->len, msg->flags, stop); |
263 | 428 | ||
@@ -267,23 +432,29 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, | |||
267 | init_completion(&i2c->cmd_complete); | 432 | init_completion(&i2c->cmd_complete); |
268 | i2c->cmd_err = 0; | 433 | i2c->cmd_err = 0; |
269 | 434 | ||
270 | flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; | 435 | if (i2c->dma_mode) { |
271 | 436 | ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); | |
272 | if (msg->flags & I2C_M_RD) | 437 | if (ret) |
273 | mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags); | 438 | return ret; |
274 | else | 439 | } else { |
275 | mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len, | 440 | if (msg->flags & I2C_M_RD) { |
276 | flags); | 441 | mxs_i2c_pioq_setup_read(i2c, msg->addr, |
442 | msg->len, flags); | ||
443 | } else { | ||
444 | mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, | ||
445 | msg->len, flags); | ||
446 | } | ||
277 | 447 | ||
278 | writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, | 448 | writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, |
279 | i2c->regs + MXS_I2C_QUEUECTRL_SET); | 449 | i2c->regs + MXS_I2C_QUEUECTRL_SET); |
450 | } | ||
280 | 451 | ||
281 | ret = wait_for_completion_timeout(&i2c->cmd_complete, | 452 | ret = wait_for_completion_timeout(&i2c->cmd_complete, |
282 | msecs_to_jiffies(1000)); | 453 | msecs_to_jiffies(1000)); |
283 | if (ret == 0) | 454 | if (ret == 0) |
284 | goto timeout; | 455 | goto timeout; |
285 | 456 | ||
286 | if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) { | 457 | if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) { |
287 | ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len); | 458 | ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len); |
288 | if (ret) | 459 | if (ret) |
289 | goto timeout; | 460 | goto timeout; |
@@ -301,6 +472,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, | |||
301 | 472 | ||
302 | timeout: | 473 | timeout: |
303 | dev_dbg(i2c->dev, "Timeout!\n"); | 474 | dev_dbg(i2c->dev, "Timeout!\n"); |
475 | if (i2c->dma_mode) | ||
476 | mxs_i2c_dma_finish(i2c); | ||
304 | mxs_i2c_reset(i2c); | 477 | mxs_i2c_reset(i2c); |
305 | return -ETIMEDOUT; | 478 | return -ETIMEDOUT; |
306 | } | 479 | } |
@@ -342,11 +515,13 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) | |||
342 | /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */ | 515 | /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */ |
343 | i2c->cmd_err = -EIO; | 516 | i2c->cmd_err = -EIO; |
344 | 517 | ||
345 | is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & | 518 | if (!i2c->dma_mode) { |
346 | MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; | 519 | is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & |
520 | MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; | ||
347 | 521 | ||
348 | if (is_last_cmd || i2c->cmd_err) | 522 | if (is_last_cmd || i2c->cmd_err) |
349 | complete(&i2c->cmd_complete); | 523 | complete(&i2c->cmd_complete); |
524 | } | ||
350 | 525 | ||
351 | writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); | 526 | writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); |
352 | 527 | ||
@@ -358,6 +533,21 @@ static const struct i2c_algorithm mxs_i2c_algo = { | |||
358 | .functionality = mxs_i2c_func, | 533 | .functionality = mxs_i2c_func, |
359 | }; | 534 | }; |
360 | 535 | ||
536 | static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param) | ||
537 | { | ||
538 | struct mxs_i2c_dev *i2c = param; | ||
539 | |||
540 | if (!mxs_dma_is_apbx(chan)) | ||
541 | return false; | ||
542 | |||
543 | if (chan->chan_id != i2c->dma_channel) | ||
544 | return false; | ||
545 | |||
546 | chan->private = &i2c->dma_data; | ||
547 | |||
548 | return true; | ||
549 | } | ||
550 | |||
361 | static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) | 551 | static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) |
362 | { | 552 | { |
363 | uint32_t speed; | 553 | uint32_t speed; |
@@ -365,6 +555,26 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) | |||
365 | struct device_node *node = dev->of_node; | 555 | struct device_node *node = dev->of_node; |
366 | int ret; | 556 | int ret; |
367 | 557 | ||
558 | /* | ||
559 | * The MXS I2C DMA mode is prefered and enabled by default. | ||
560 | * The PIO mode is still supported, but should be used only | ||
561 | * for debuging purposes etc. | ||
562 | */ | ||
563 | i2c->dma_mode = !use_pioqueue; | ||
564 | if (!i2c->dma_mode) | ||
565 | dev_info(dev, "Using PIOQUEUE mode for I2C transfers!\n"); | ||
566 | |||
567 | /* | ||
568 | * TODO: This is a temporary solution and should be changed | ||
569 | * to use generic DMA binding later when the helpers get in. | ||
570 | */ | ||
571 | ret = of_property_read_u32(node, "fsl,i2c-dma-channel", | ||
572 | &i2c->dma_channel); | ||
573 | if (ret) { | ||
574 | dev_warn(dev, "Failed to get DMA channel, using PIOQUEUE!\n"); | ||
575 | i2c->dma_mode = 0; | ||
576 | } | ||
577 | |||
368 | ret = of_property_read_u32(node, "clock-frequency", &speed); | 578 | ret = of_property_read_u32(node, "clock-frequency", &speed); |
369 | if (ret) | 579 | if (ret) |
370 | dev_warn(dev, "No I2C speed selected, using 100kHz\n"); | 580 | dev_warn(dev, "No I2C speed selected, using 100kHz\n"); |
@@ -384,7 +594,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) | |||
384 | struct pinctrl *pinctrl; | 594 | struct pinctrl *pinctrl; |
385 | struct resource *res; | 595 | struct resource *res; |
386 | resource_size_t res_size; | 596 | resource_size_t res_size; |
387 | int err, irq; | 597 | int err, irq, dmairq; |
598 | dma_cap_mask_t mask; | ||
388 | 599 | ||
389 | pinctrl = devm_pinctrl_get_select_default(dev); | 600 | pinctrl = devm_pinctrl_get_select_default(dev); |
390 | if (IS_ERR(pinctrl)) | 601 | if (IS_ERR(pinctrl)) |
@@ -395,7 +606,10 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) | |||
395 | return -ENOMEM; | 606 | return -ENOMEM; |
396 | 607 | ||
397 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 608 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
398 | if (!res) | 609 | irq = platform_get_irq(pdev, 0); |
610 | dmairq = platform_get_irq(pdev, 1); | ||
611 | |||
612 | if (!res || irq < 0 || dmairq < 0) | ||
399 | return -ENOENT; | 613 | return -ENOENT; |
400 | 614 | ||
401 | res_size = resource_size(res); | 615 | res_size = resource_size(res); |
@@ -406,10 +620,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) | |||
406 | if (!i2c->regs) | 620 | if (!i2c->regs) |
407 | return -EBUSY; | 621 | return -EBUSY; |
408 | 622 | ||
409 | irq = platform_get_irq(pdev, 0); | ||
410 | if (irq < 0) | ||
411 | return irq; | ||
412 | |||
413 | err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c); | 623 | err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c); |
414 | if (err) | 624 | if (err) |
415 | return err; | 625 | return err; |
@@ -423,6 +633,18 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) | |||
423 | return err; | 633 | return err; |
424 | } | 634 | } |
425 | 635 | ||
636 | /* Setup the DMA */ | ||
637 | if (i2c->dma_mode) { | ||
638 | dma_cap_zero(mask); | ||
639 | dma_cap_set(DMA_SLAVE, mask); | ||
640 | i2c->dma_data.chan_irq = dmairq; | ||
641 | i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c); | ||
642 | if (!i2c->dmach) { | ||
643 | dev_err(dev, "Failed to request dma\n"); | ||
644 | return -ENODEV; | ||
645 | } | ||
646 | } | ||
647 | |||
426 | platform_set_drvdata(pdev, i2c); | 648 | platform_set_drvdata(pdev, i2c); |
427 | 649 | ||
428 | /* Do reset to enforce correct startup after pinmuxing */ | 650 | /* Do reset to enforce correct startup after pinmuxing */ |
@@ -458,6 +680,9 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev) | |||
458 | if (ret) | 680 | if (ret) |
459 | return -EBUSY; | 681 | return -EBUSY; |
460 | 682 | ||
683 | if (i2c->dmach) | ||
684 | dma_release_channel(i2c->dmach); | ||
685 | |||
461 | writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); | 686 | writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); |
462 | 687 | ||
463 | platform_set_drvdata(pdev, NULL); | 688 | platform_set_drvdata(pdev, NULL); |