773 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * timb_dma.c timberdale FPGA DMA driver4 * Copyright (c) 2010 Intel Corporation5 */6 7/* Supports:8 * Timberdale FPGA DMA engine9 */10 11#include <linux/dmaengine.h>12#include <linux/dma-mapping.h>13#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/io.h>16#include <linux/module.h>17#include <linux/platform_device.h>18#include <linux/slab.h>19 20#include <linux/timb_dma.h>21 22#include "dmaengine.h"23 24#define DRIVER_NAME "timb-dma"25 26/* Global DMA registers */27#define TIMBDMA_ACR 0x3428#define TIMBDMA_32BIT_ADDR 0x0129 30#define TIMBDMA_ISR 0x08000031#define TIMBDMA_IPR 0x08000432#define TIMBDMA_IER 0x08000833 34/* Channel specific registers */35/* RX instances base addresses are 0x00, 0x40, 0x80 ...36 * TX instances base addresses are 0x18, 0x58, 0x98 ...37 */38#define TIMBDMA_INSTANCE_OFFSET 0x4039#define TIMBDMA_INSTANCE_TX_OFFSET 0x1840 41/* RX registers, relative the instance base */42#define TIMBDMA_OFFS_RX_DHAR 0x0043#define TIMBDMA_OFFS_RX_DLAR 0x0444#define TIMBDMA_OFFS_RX_LR 0x0C45#define TIMBDMA_OFFS_RX_BLR 0x1046#define TIMBDMA_OFFS_RX_ER 0x1447#define TIMBDMA_RX_EN 0x0148/* bytes per Row, video specific register49 * which is placed after the TX registers...50 */51#define TIMBDMA_OFFS_RX_BPRR 0x3052 53/* TX registers, relative the instance base */54#define TIMBDMA_OFFS_TX_DHAR 0x0055#define TIMBDMA_OFFS_TX_DLAR 0x0456#define TIMBDMA_OFFS_TX_BLR 0x0C57#define TIMBDMA_OFFS_TX_LR 0x1458 59 60#define TIMB_DMA_DESC_SIZE 861 62struct timb_dma_desc {63 struct list_head desc_node;64 struct dma_async_tx_descriptor txd;65 u8 *desc_list;66 unsigned int desc_list_len;67 bool interrupt;68};69 70struct timb_dma_chan {71 struct dma_chan chan;72 void __iomem *membase;73 spinlock_t lock; /* Used to protect data structures,74 especially the lists and descriptors,75 from races between the tasklet and calls76 from above */77 bool ongoing;78 struct list_head active_list;79 struct list_head queue;80 struct list_head free_list;81 unsigned int bytes_per_line;82 enum dma_transfer_direction direction;83 unsigned int descs; /* Descriptors to allocate */84 unsigned int desc_elems; /* number of elems per descriptor */85};86 87struct timb_dma {88 struct dma_device dma;89 void __iomem *membase;90 struct tasklet_struct tasklet;91 struct timb_dma_chan channels[];92};93 94static struct device *chan2dev(struct dma_chan *chan)95{96 return &chan->dev->device;97}98static struct device *chan2dmadev(struct dma_chan *chan)99{100 return chan2dev(chan)->parent->parent;101}102 103static struct timb_dma *tdchantotd(struct timb_dma_chan *td_chan)104{105 int id = td_chan->chan.chan_id;106 return (struct timb_dma *)((u8 *)td_chan -107 id * sizeof(struct timb_dma_chan) - sizeof(struct timb_dma));108}109 110/* Must be called with the spinlock held */111static void __td_enable_chan_irq(struct timb_dma_chan *td_chan)112{113 int id = td_chan->chan.chan_id;114 struct timb_dma *td = tdchantotd(td_chan);115 u32 ier;116 117 /* enable interrupt for this channel */118 ier = ioread32(td->membase + TIMBDMA_IER);119 ier |= 1 << id;120 dev_dbg(chan2dev(&td_chan->chan), "Enabling irq: %d, IER: 0x%x\n", id,121 ier);122 iowrite32(ier, td->membase + TIMBDMA_IER);123}124 125/* Should be called with the spinlock held */126static bool __td_dma_done_ack(struct timb_dma_chan *td_chan)127{128 int id = td_chan->chan.chan_id;129 struct timb_dma *td = (struct timb_dma *)((u8 *)td_chan -130 id * sizeof(struct timb_dma_chan) - sizeof(struct timb_dma));131 u32 isr;132 bool done = false;133 134 dev_dbg(chan2dev(&td_chan->chan), "Checking irq: %d, td: %p\n", id, td);135 136 isr = ioread32(td->membase + TIMBDMA_ISR) & (1 << id);137 if (isr) {138 iowrite32(isr, td->membase + TIMBDMA_ISR);139 done = true;140 }141 142 return done;143}144 145static int td_fill_desc(struct timb_dma_chan *td_chan, u8 *dma_desc,146 struct scatterlist *sg, bool last)147{148 if (sg_dma_len(sg) > USHRT_MAX) {149 dev_err(chan2dev(&td_chan->chan), "Too big sg element\n");150 return -EINVAL;151 }152 153 /* length must be word aligned */154 if (sg_dma_len(sg) % sizeof(u32)) {155 dev_err(chan2dev(&td_chan->chan), "Incorrect length: %d\n",156 sg_dma_len(sg));157 return -EINVAL;158 }159 160 dev_dbg(chan2dev(&td_chan->chan), "desc: %p, addr: 0x%llx\n",161 dma_desc, (unsigned long long)sg_dma_address(sg));162 163 dma_desc[7] = (sg_dma_address(sg) >> 24) & 0xff;164 dma_desc[6] = (sg_dma_address(sg) >> 16) & 0xff;165 dma_desc[5] = (sg_dma_address(sg) >> 8) & 0xff;166 dma_desc[4] = (sg_dma_address(sg) >> 0) & 0xff;167 168 dma_desc[3] = (sg_dma_len(sg) >> 8) & 0xff;169 dma_desc[2] = (sg_dma_len(sg) >> 0) & 0xff;170 171 dma_desc[1] = 0x00;172 dma_desc[0] = 0x21 | (last ? 0x02 : 0); /* tran, valid */173 174 return 0;175}176 177/* Must be called with the spinlock held */178static void __td_start_dma(struct timb_dma_chan *td_chan)179{180 struct timb_dma_desc *td_desc;181 182 if (td_chan->ongoing) {183 dev_err(chan2dev(&td_chan->chan),184 "Transfer already ongoing\n");185 return;186 }187 188 td_desc = list_entry(td_chan->active_list.next, struct timb_dma_desc,189 desc_node);190 191 dev_dbg(chan2dev(&td_chan->chan),192 "td_chan: %p, chan: %d, membase: %p\n",193 td_chan, td_chan->chan.chan_id, td_chan->membase);194 195 if (td_chan->direction == DMA_DEV_TO_MEM) {196 197 /* descriptor address */198 iowrite32(0, td_chan->membase + TIMBDMA_OFFS_RX_DHAR);199 iowrite32(td_desc->txd.phys, td_chan->membase +200 TIMBDMA_OFFS_RX_DLAR);201 /* Bytes per line */202 iowrite32(td_chan->bytes_per_line, td_chan->membase +203 TIMBDMA_OFFS_RX_BPRR);204 /* enable RX */205 iowrite32(TIMBDMA_RX_EN, td_chan->membase + TIMBDMA_OFFS_RX_ER);206 } else {207 /* address high */208 iowrite32(0, td_chan->membase + TIMBDMA_OFFS_TX_DHAR);209 iowrite32(td_desc->txd.phys, td_chan->membase +210 TIMBDMA_OFFS_TX_DLAR);211 }212 213 td_chan->ongoing = true;214 215 if (td_desc->interrupt)216 __td_enable_chan_irq(td_chan);217}218 219static void __td_finish(struct timb_dma_chan *td_chan)220{221 struct dmaengine_desc_callback cb;222 struct dma_async_tx_descriptor *txd;223 struct timb_dma_desc *td_desc;224 225 /* can happen if the descriptor is canceled */226 if (list_empty(&td_chan->active_list))227 return;228 229 td_desc = list_entry(td_chan->active_list.next, struct timb_dma_desc,230 desc_node);231 txd = &td_desc->txd;232 233 dev_dbg(chan2dev(&td_chan->chan), "descriptor %u complete\n",234 txd->cookie);235 236 /* make sure to stop the transfer */237 if (td_chan->direction == DMA_DEV_TO_MEM)238 iowrite32(0, td_chan->membase + TIMBDMA_OFFS_RX_ER);239/* Currently no support for stopping DMA transfers240 else241 iowrite32(0, td_chan->membase + TIMBDMA_OFFS_TX_DLAR);242*/243 dma_cookie_complete(txd);244 td_chan->ongoing = false;245 246 dmaengine_desc_get_callback(txd, &cb);247 248 list_move(&td_desc->desc_node, &td_chan->free_list);249 250 dma_descriptor_unmap(txd);251 /*252 * The API requires that no submissions are done from a253 * callback, so we don't need to drop the lock here254 */255 dmaengine_desc_callback_invoke(&cb, NULL);256}257 258static u32 __td_ier_mask(struct timb_dma *td)259{260 int i;261 u32 ret = 0;262 263 for (i = 0; i < td->dma.chancnt; i++) {264 struct timb_dma_chan *td_chan = td->channels + i;265 if (td_chan->ongoing) {266 struct timb_dma_desc *td_desc =267 list_entry(td_chan->active_list.next,268 struct timb_dma_desc, desc_node);269 if (td_desc->interrupt)270 ret |= 1 << i;271 }272 }273 274 return ret;275}276 277static void __td_start_next(struct timb_dma_chan *td_chan)278{279 struct timb_dma_desc *td_desc;280 281 BUG_ON(list_empty(&td_chan->queue));282 BUG_ON(td_chan->ongoing);283 284 td_desc = list_entry(td_chan->queue.next, struct timb_dma_desc,285 desc_node);286 287 dev_dbg(chan2dev(&td_chan->chan), "%s: started %u\n",288 __func__, td_desc->txd.cookie);289 290 list_move(&td_desc->desc_node, &td_chan->active_list);291 __td_start_dma(td_chan);292}293 294static dma_cookie_t td_tx_submit(struct dma_async_tx_descriptor *txd)295{296 struct timb_dma_desc *td_desc = container_of(txd, struct timb_dma_desc,297 txd);298 struct timb_dma_chan *td_chan = container_of(txd->chan,299 struct timb_dma_chan, chan);300 dma_cookie_t cookie;301 302 spin_lock_bh(&td_chan->lock);303 cookie = dma_cookie_assign(txd);304 305 if (list_empty(&td_chan->active_list)) {306 dev_dbg(chan2dev(txd->chan), "%s: started %u\n", __func__,307 txd->cookie);308 list_add_tail(&td_desc->desc_node, &td_chan->active_list);309 __td_start_dma(td_chan);310 } else {311 dev_dbg(chan2dev(txd->chan), "tx_submit: queued %u\n",312 txd->cookie);313 314 list_add_tail(&td_desc->desc_node, &td_chan->queue);315 }316 317 spin_unlock_bh(&td_chan->lock);318 319 return cookie;320}321 322static struct timb_dma_desc *td_alloc_init_desc(struct timb_dma_chan *td_chan)323{324 struct dma_chan *chan = &td_chan->chan;325 struct timb_dma_desc *td_desc;326 int err;327 328 td_desc = kzalloc(sizeof(struct timb_dma_desc), GFP_KERNEL);329 if (!td_desc)330 goto out;331 332 td_desc->desc_list_len = td_chan->desc_elems * TIMB_DMA_DESC_SIZE;333 334 td_desc->desc_list = kzalloc(td_desc->desc_list_len, GFP_KERNEL);335 if (!td_desc->desc_list)336 goto err;337 338 dma_async_tx_descriptor_init(&td_desc->txd, chan);339 td_desc->txd.tx_submit = td_tx_submit;340 td_desc->txd.flags = DMA_CTRL_ACK;341 342 td_desc->txd.phys = dma_map_single(chan2dmadev(chan),343 td_desc->desc_list, td_desc->desc_list_len, DMA_TO_DEVICE);344 345 err = dma_mapping_error(chan2dmadev(chan), td_desc->txd.phys);346 if (err) {347 dev_err(chan2dev(chan), "DMA mapping error: %d\n", err);348 goto err;349 }350 351 return td_desc;352err:353 kfree(td_desc->desc_list);354 kfree(td_desc);355out:356 return NULL;357 358}359 360static void td_free_desc(struct timb_dma_desc *td_desc)361{362 dev_dbg(chan2dev(td_desc->txd.chan), "Freeing desc: %p\n", td_desc);363 dma_unmap_single(chan2dmadev(td_desc->txd.chan), td_desc->txd.phys,364 td_desc->desc_list_len, DMA_TO_DEVICE);365 366 kfree(td_desc->desc_list);367 kfree(td_desc);368}369 370static void td_desc_put(struct timb_dma_chan *td_chan,371 struct timb_dma_desc *td_desc)372{373 dev_dbg(chan2dev(&td_chan->chan), "Putting desc: %p\n", td_desc);374 375 spin_lock_bh(&td_chan->lock);376 list_add(&td_desc->desc_node, &td_chan->free_list);377 spin_unlock_bh(&td_chan->lock);378}379 380static struct timb_dma_desc *td_desc_get(struct timb_dma_chan *td_chan)381{382 struct timb_dma_desc *td_desc, *_td_desc;383 struct timb_dma_desc *ret = NULL;384 385 spin_lock_bh(&td_chan->lock);386 list_for_each_entry_safe(td_desc, _td_desc, &td_chan->free_list,387 desc_node) {388 if (async_tx_test_ack(&td_desc->txd)) {389 list_del(&td_desc->desc_node);390 ret = td_desc;391 break;392 }393 dev_dbg(chan2dev(&td_chan->chan), "desc %p not ACKed\n",394 td_desc);395 }396 spin_unlock_bh(&td_chan->lock);397 398 return ret;399}400 401static int td_alloc_chan_resources(struct dma_chan *chan)402{403 struct timb_dma_chan *td_chan =404 container_of(chan, struct timb_dma_chan, chan);405 int i;406 407 dev_dbg(chan2dev(chan), "%s: entry\n", __func__);408 409 BUG_ON(!list_empty(&td_chan->free_list));410 for (i = 0; i < td_chan->descs; i++) {411 struct timb_dma_desc *td_desc = td_alloc_init_desc(td_chan);412 if (!td_desc) {413 if (i)414 break;415 else {416 dev_err(chan2dev(chan),417 "Couldn't allocate any descriptors\n");418 return -ENOMEM;419 }420 }421 422 td_desc_put(td_chan, td_desc);423 }424 425 spin_lock_bh(&td_chan->lock);426 dma_cookie_init(chan);427 spin_unlock_bh(&td_chan->lock);428 429 return 0;430}431 432static void td_free_chan_resources(struct dma_chan *chan)433{434 struct timb_dma_chan *td_chan =435 container_of(chan, struct timb_dma_chan, chan);436 struct timb_dma_desc *td_desc, *_td_desc;437 LIST_HEAD(list);438 439 dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);440 441 /* check that all descriptors are free */442 BUG_ON(!list_empty(&td_chan->active_list));443 BUG_ON(!list_empty(&td_chan->queue));444 445 spin_lock_bh(&td_chan->lock);446 list_splice_init(&td_chan->free_list, &list);447 spin_unlock_bh(&td_chan->lock);448 449 list_for_each_entry_safe(td_desc, _td_desc, &list, desc_node) {450 dev_dbg(chan2dev(chan), "%s: Freeing desc: %p\n", __func__,451 td_desc);452 td_free_desc(td_desc);453 }454}455 456static enum dma_status td_tx_status(struct dma_chan *chan, dma_cookie_t cookie,457 struct dma_tx_state *txstate)458{459 enum dma_status ret;460 461 dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);462 463 ret = dma_cookie_status(chan, cookie, txstate);464 465 dev_dbg(chan2dev(chan), "%s: exit, ret: %d\n", __func__, ret);466 467 return ret;468}469 470static void td_issue_pending(struct dma_chan *chan)471{472 struct timb_dma_chan *td_chan =473 container_of(chan, struct timb_dma_chan, chan);474 475 dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);476 spin_lock_bh(&td_chan->lock);477 478 if (!list_empty(&td_chan->active_list))479 /* transfer ongoing */480 if (__td_dma_done_ack(td_chan))481 __td_finish(td_chan);482 483 if (list_empty(&td_chan->active_list) && !list_empty(&td_chan->queue))484 __td_start_next(td_chan);485 486 spin_unlock_bh(&td_chan->lock);487}488 489static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,490 struct scatterlist *sgl, unsigned int sg_len,491 enum dma_transfer_direction direction, unsigned long flags,492 void *context)493{494 struct timb_dma_chan *td_chan =495 container_of(chan, struct timb_dma_chan, chan);496 struct timb_dma_desc *td_desc;497 struct scatterlist *sg;498 unsigned int i;499 unsigned int desc_usage = 0;500 501 if (!sgl || !sg_len) {502 dev_err(chan2dev(chan), "%s: No SG list\n", __func__);503 return NULL;504 }505 506 /* even channels are for RX, odd for TX */507 if (td_chan->direction != direction) {508 dev_err(chan2dev(chan),509 "Requesting channel in wrong direction\n");510 return NULL;511 }512 513 td_desc = td_desc_get(td_chan);514 if (!td_desc) {515 dev_err(chan2dev(chan), "Not enough descriptors available\n");516 return NULL;517 }518 519 td_desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;520 521 for_each_sg(sgl, sg, sg_len, i) {522 int err;523 if (desc_usage > td_desc->desc_list_len) {524 dev_err(chan2dev(chan), "No descriptor space\n");525 return NULL;526 }527 528 err = td_fill_desc(td_chan, td_desc->desc_list + desc_usage, sg,529 i == (sg_len - 1));530 if (err) {531 dev_err(chan2dev(chan), "Failed to update desc: %d\n",532 err);533 td_desc_put(td_chan, td_desc);534 return NULL;535 }536 desc_usage += TIMB_DMA_DESC_SIZE;537 }538 539 dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys,540 td_desc->desc_list_len, DMA_TO_DEVICE);541 542 return &td_desc->txd;543}544 545static int td_terminate_all(struct dma_chan *chan)546{547 struct timb_dma_chan *td_chan =548 container_of(chan, struct timb_dma_chan, chan);549 struct timb_dma_desc *td_desc, *_td_desc;550 551 dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);552 553 /* first the easy part, put the queue into the free list */554 spin_lock_bh(&td_chan->lock);555 list_for_each_entry_safe(td_desc, _td_desc, &td_chan->queue,556 desc_node)557 list_move(&td_desc->desc_node, &td_chan->free_list);558 559 /* now tear down the running */560 __td_finish(td_chan);561 spin_unlock_bh(&td_chan->lock);562 563 return 0;564}565 566static void td_tasklet(struct tasklet_struct *t)567{568 struct timb_dma *td = from_tasklet(td, t, tasklet);569 u32 isr;570 u32 ipr;571 u32 ier;572 int i;573 574 isr = ioread32(td->membase + TIMBDMA_ISR);575 ipr = isr & __td_ier_mask(td);576 577 /* ack the interrupts */578 iowrite32(ipr, td->membase + TIMBDMA_ISR);579 580 for (i = 0; i < td->dma.chancnt; i++)581 if (ipr & (1 << i)) {582 struct timb_dma_chan *td_chan = td->channels + i;583 spin_lock(&td_chan->lock);584 __td_finish(td_chan);585 if (!list_empty(&td_chan->queue))586 __td_start_next(td_chan);587 spin_unlock(&td_chan->lock);588 }589 590 ier = __td_ier_mask(td);591 iowrite32(ier, td->membase + TIMBDMA_IER);592}593 594 595static irqreturn_t td_irq(int irq, void *devid)596{597 struct timb_dma *td = devid;598 u32 ipr = ioread32(td->membase + TIMBDMA_IPR);599 600 if (ipr) {601 /* disable interrupts, will be re-enabled in tasklet */602 iowrite32(0, td->membase + TIMBDMA_IER);603 604 tasklet_schedule(&td->tasklet);605 606 return IRQ_HANDLED;607 } else608 return IRQ_NONE;609}610 611 612static int td_probe(struct platform_device *pdev)613{614 struct timb_dma_platform_data *pdata = dev_get_platdata(&pdev->dev);615 struct timb_dma *td;616 struct resource *iomem;617 int irq;618 int err;619 int i;620 621 if (!pdata) {622 dev_err(&pdev->dev, "No platform data\n");623 return -EINVAL;624 }625 626 iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);627 if (!iomem)628 return -EINVAL;629 630 irq = platform_get_irq(pdev, 0);631 if (irq < 0)632 return irq;633 634 if (!request_mem_region(iomem->start, resource_size(iomem),635 DRIVER_NAME))636 return -EBUSY;637 638 td = kzalloc(struct_size(td, channels, pdata->nr_channels),639 GFP_KERNEL);640 if (!td) {641 err = -ENOMEM;642 goto err_release_region;643 }644 645 dev_dbg(&pdev->dev, "Allocated TD: %p\n", td);646 647 td->membase = ioremap(iomem->start, resource_size(iomem));648 if (!td->membase) {649 dev_err(&pdev->dev, "Failed to remap I/O memory\n");650 err = -ENOMEM;651 goto err_free_mem;652 }653 654 /* 32bit addressing */655 iowrite32(TIMBDMA_32BIT_ADDR, td->membase + TIMBDMA_ACR);656 657 /* disable and clear any interrupts */658 iowrite32(0x0, td->membase + TIMBDMA_IER);659 iowrite32(0xFFFFFFFF, td->membase + TIMBDMA_ISR);660 661 tasklet_setup(&td->tasklet, td_tasklet);662 663 err = request_irq(irq, td_irq, IRQF_SHARED, DRIVER_NAME, td);664 if (err) {665 dev_err(&pdev->dev, "Failed to request IRQ\n");666 goto err_tasklet_kill;667 }668 669 td->dma.device_alloc_chan_resources = td_alloc_chan_resources;670 td->dma.device_free_chan_resources = td_free_chan_resources;671 td->dma.device_tx_status = td_tx_status;672 td->dma.device_issue_pending = td_issue_pending;673 674 dma_cap_set(DMA_SLAVE, td->dma.cap_mask);675 dma_cap_set(DMA_PRIVATE, td->dma.cap_mask);676 td->dma.device_prep_slave_sg = td_prep_slave_sg;677 td->dma.device_terminate_all = td_terminate_all;678 679 td->dma.dev = &pdev->dev;680 681 INIT_LIST_HEAD(&td->dma.channels);682 683 for (i = 0; i < pdata->nr_channels; i++) {684 struct timb_dma_chan *td_chan = &td->channels[i];685 struct timb_dma_platform_data_channel *pchan =686 pdata->channels + i;687 688 /* even channels are RX, odd are TX */689 if ((i % 2) == pchan->rx) {690 dev_err(&pdev->dev, "Wrong channel configuration\n");691 err = -EINVAL;692 goto err_free_irq;693 }694 695 td_chan->chan.device = &td->dma;696 dma_cookie_init(&td_chan->chan);697 spin_lock_init(&td_chan->lock);698 INIT_LIST_HEAD(&td_chan->active_list);699 INIT_LIST_HEAD(&td_chan->queue);700 INIT_LIST_HEAD(&td_chan->free_list);701 702 td_chan->descs = pchan->descriptors;703 td_chan->desc_elems = pchan->descriptor_elements;704 td_chan->bytes_per_line = pchan->bytes_per_line;705 td_chan->direction = pchan->rx ? DMA_DEV_TO_MEM :706 DMA_MEM_TO_DEV;707 708 td_chan->membase = td->membase +709 (i / 2) * TIMBDMA_INSTANCE_OFFSET +710 (pchan->rx ? 0 : TIMBDMA_INSTANCE_TX_OFFSET);711 712 dev_dbg(&pdev->dev, "Chan: %d, membase: %p\n",713 i, td_chan->membase);714 715 list_add_tail(&td_chan->chan.device_node, &td->dma.channels);716 }717 718 err = dma_async_device_register(&td->dma);719 if (err) {720 dev_err(&pdev->dev, "Failed to register async device\n");721 goto err_free_irq;722 }723 724 platform_set_drvdata(pdev, td);725 726 dev_dbg(&pdev->dev, "Probe result: %d\n", err);727 return err;728 729err_free_irq:730 free_irq(irq, td);731err_tasklet_kill:732 tasklet_kill(&td->tasklet);733 iounmap(td->membase);734err_free_mem:735 kfree(td);736err_release_region:737 release_mem_region(iomem->start, resource_size(iomem));738 739 return err;740 741}742 743static void td_remove(struct platform_device *pdev)744{745 struct timb_dma *td = platform_get_drvdata(pdev);746 struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);747 int irq = platform_get_irq(pdev, 0);748 749 dma_async_device_unregister(&td->dma);750 free_irq(irq, td);751 tasklet_kill(&td->tasklet);752 iounmap(td->membase);753 kfree(td);754 release_mem_region(iomem->start, resource_size(iomem));755 756 dev_dbg(&pdev->dev, "Removed...\n");757}758 759static struct platform_driver td_driver = {760 .driver = {761 .name = DRIVER_NAME,762 },763 .probe = td_probe,764 .remove_new = td_remove,765};766 767module_platform_driver(td_driver);768 769MODULE_LICENSE("GPL v2");770MODULE_DESCRIPTION("Timberdale DMA controller driver");771MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");772MODULE_ALIAS("platform:"DRIVER_NAME);773