From patchwork Sat Aug 10 10:56:19 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Mack X-Patchwork-Id: 266220 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from casper.infradead.org (unknown [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id D50AA2C00D8 for ; Sat, 10 Aug 2013 20:57:29 +1000 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V86qz-0004oV-7A; Sat, 10 Aug 2013 10:57:01 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V86qu-0003pH-Si; Sat, 10 Aug 2013 10:56:56 +0000 Received: from mail-ea0-x234.google.com ([2a00:1450:4013:c01::234]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V86qj-0003oF-Te; Sat, 10 Aug 2013 10:56:47 +0000 Received: by mail-ea0-f180.google.com with SMTP id h10so2552475eaj.11 for ; Sat, 10 Aug 2013 03:56:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type; bh=eWG6yGpvA0Vk6FoAtVuJzWaLGJw1ITmI65aU7msdfj4=; b=HVDDbn52LYh+Jg2VpbpQa45g+AB2G3qrWwE2Isv8pBxmUFaTlHiKpyLljw3qa6g+pb CvQuI1JThriuPUaUEuKj5yP+3aUIOT0SHfilMLC7y3cyu+ALABtq2kgZ39ROk1f+DneC hdriTlZ7Vdd6BDuoXl/agDPXu/YpWnWZ+QxEXwAhwVfShUTAZCV+sWV/5/3/xLkY/xoy FZ1y54g6f0z9s5uN5ZYsChO56qL6S4ARgTZxkLRMsd/mcfxDvpG0uPrvCdjAp7ZacV/q R7Iyu0BoyKTSK/bmZSQXDdeXauARJBdgwHUcDZFKDdy3UlOtIAceSTwablycXNPv5dAf 5rBw== X-Received: by 10.14.107.2 with SMTP id n2mr16833674eeg.122.1376132182561; Sat, 10 Aug 2013 03:56:22 -0700 (PDT) Received: from ?IPv6:2001:4dd0:ff00:9394:58c0:d10a:dc3b:b349? ([2001:4dd0:ff00:9394:58c0:d10a:dc3b:b349]) by mx.google.com with ESMTPSA id a1sm37098352eem.1.2013.08.10.03.56.19 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Sat, 10 Aug 2013 03:56:21 -0700 (PDT) Message-ID: <52061C53.4050905@gmail.com> Date: Sat, 10 Aug 2013 12:56:19 +0200 From: Daniel Mack User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130625 Thunderbird/17.0.7 MIME-Version: 1.0 To: Robert Jarzmik Subject: Re: [PATCH 00/20] ARM: pxa: move core and drivers to dmaengine References: <1375889649-14638-1-git-send-email-zonque@gmail.com> <87zjsqzdg8.fsf@free.fr> In-Reply-To: <87zjsqzdg8.fsf@free.fr> X-Enigmail-Version: 1.5.2 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130810_065646_255116_597209A3 X-CRM114-Status: GOOD ( 40.12 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- 1.8 KHOP_BIG_TO_CC Sent to 10+ recipients instaed of Bcc or a list 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (zonque[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: mark.rutland@arm.com, s.neumann@raumfeld.com, linux-mtd@lists.infradead.org, haojian.zhuang@linaro.org, cxie4@marvell.com, lars@metafoo.de, nico@linaro.org, vinod.koul@intel.com, marek.vasut@gmail.com, ezequiel.garcia@free-electrons.com, rmk+kernel@arm.linux.org.uk, devicetree@vger.kernel.org, samuel@sortiz.org, arnd@arndb.de, broonie@kernel.org, mika.westerberg@linux.intel.com, linux-arm-kernel@lists.infradead.org, thomas.petazzoni@free-electrons.com, eric.y.miao@gmail.com, gregkh@linuxfoundation.org, davem@davemloft.net, sachin.kamat@linaro.org, kernel@pengutronix.de, djbw@fb.com, g.liakhovetski@gmx.de X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Hi Robert, On 10.08.2013 00:50, Robert Jarzmik wrote: > Daniel Mack writes: > >> * camera driver: >> I started the transition, but I'm not sure how much sense that >> makes without access to the hardware. I'd much appreciate if >> anyone could volunteer for this piece; I'll happily share what >> I got so far. Sascha, Sachin, Guennadi? > Hi Daniel, > > Do you mean this driver ? : > drivers/media/platform/soc_camera/pxa_camera.c Yes, exactly. > In that case I might help. But before I can do that, I have to be convinced that > dmaengine can deal with this driver. I'm thinking in particular of : > - "hot running DMA" queuing > - multiple DMA channel synchronization (ie. 3 channel sync) > > All that is described in there : > Documentation/video4linux/pxa_camera.txt Yes, I've seen that, and while the documentation about all that is excellent, I lack an explanation why things are so complicated for this application, and why a simple cyclic DMA approach does not suffice here. I'm sure there's a reason though. There might be need to teach the dmaengine core more functionality, but in order to do that, we first need to understand the exact requirements. > If someone with dmaengine knowledge could have a look at pxa_camera.txt (maybe > Vinod ?) and tell me that dma_engine framework fullfills the 2 requirements, > then I'll be happy to help. Yes, Vinod and and Dan are certainly the best ones to comment on that I think. > One minor point though is that I'm working on pxa27x. If the serie is not > compatible in a way with pxa27x, I won't be able to do anything. No, it should work just fine on pxa27x. > Another point I'd like to know, is what is the performance penalty in using > dmaengine, and do you have any figures ? The DMA transfers themselves certainly perform equally well, and the framework is just a thin layer. Where would you expect performance penalty? > Lastly, they was debug information to debug descriptors chaining, channel > statuses, requestors. I didn't see where these had gone, could you point me to > the right file ? Such a debug interface is not part of the mmp-pdma implementation at this point, and the core doesn't have a generic debugfs feature either. If you need that, we'd have to add it back. FWIW, I attached my work-in-progress patch for this driver which just does some basic dmaengine preparations. Be aware that this does not even compile, it's really just a snapshot. Thanks, Daniel From 8d7333689479640d2586358ffb8f4e1704e4b015 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 4 Aug 2013 00:23:00 +0200 Subject: [PATCH] drivers/media/platform/soc_camera/pxa_camera.c DMAENGINE WIP --- drivers/media/platform/soc_camera/pxa_camera.c | 262 ++++++++++++------------- 1 file changed, 121 insertions(+), 141 deletions(-) diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index d4df305..4dfd97f 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include #include @@ -37,7 +40,6 @@ #include -#include #include #define PXA_CAM_VERSION "0.0.6" @@ -177,8 +179,6 @@ enum pxa_camera_active_dma { /* descriptor needed for the PXA DMA engine */ struct pxa_cam_dma { dma_addr_t sg_dma; - struct pxa_dma_desc *sg_cpu; - size_t sg_size; int sglen; }; @@ -206,7 +206,8 @@ struct pxa_camera_dev { void __iomem *base; int channels; - unsigned int dma_chans[3]; + struct dma_chan *dma_chans[3]; + unsigned int dma_len; struct pxacamera_platform_data *pdata; struct resource *res; @@ -257,15 +258,18 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) { struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - int i; BUG_ON(in_interrupt()); dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, &buf->vb, buf->vb.baddr, buf->vb.bsize); + /* FIXME */ + dmaengine_terminate_all(NULL); + dmaengine_terminate_all(NULL); + dmaengine_terminate_all(NULL); + /* * This waits until this buffer is out of danger, i.e., until it is no * longer in STATE_QUEUED or STATE_ACTIVE @@ -274,15 +278,6 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); - for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { - if (buf->dmas[i].sg_cpu) - dma_free_coherent(ici->v4l2_dev.dev, - buf->dmas[i].sg_size, - buf->dmas[i].sg_cpu, - buf->dmas[i].sg_dma); - buf->dmas[i].sg_cpu = NULL; - } - buf->vb.state = VIDEOBUF_NEEDS_INIT; } @@ -309,6 +304,27 @@ static int calculate_dma_sglen(struct scatterlist *sglist, int sglen, return i + 1; } +static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, + enum pxa_camera_active_dma act_dma); + +static void pxa_camera_dma_irq_y(int channel, void *data) +{ + struct pxa_camera_dev *pcdev = data; + pxa_camera_dma_irq(channel, pcdev, DMA_Y); +} + +static void pxa_camera_dma_irq_u(int channel, void *data) +{ + struct pxa_camera_dev *pcdev = data; + pxa_camera_dma_irq(channel, pcdev, DMA_U); +} + +static void pxa_camera_dma_irq_v(int channel, void *data) +{ + struct pxa_camera_dev *pcdev = data; + pxa_camera_dma_irq(channel, pcdev, DMA_V); +} + /** * pxa_init_dma_channel - init dma descriptors * @pcdev: pxa camera device @@ -332,61 +348,61 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, struct scatterlist **sg_first, int *sg_first_ofs) { struct pxa_cam_dma *pxa_dma = &buf->dmas[channel]; + struct dma_chan *dma_chan = pcdev->dma_chans[channel]; struct device *dev = pcdev->soc_host.v4l2_dev.dev; struct scatterlist *sg; - int i, offset, sglen; + int ret, i, offset, sglen; int dma_len = 0, xfer_len = 0; + struct dma_slave_config config; + struct dma_async_tx_descriptor *tx; - if (pxa_dma->sg_cpu) - dma_free_coherent(dev, pxa_dma->sg_size, - pxa_dma->sg_cpu, pxa_dma->sg_dma); + dmaengine_terminate_all(dma_chan); sglen = calculate_dma_sglen(*sg_first, dma->sglen, *sg_first_ofs, size); - pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); - pxa_dma->sg_cpu = dma_alloc_coherent(dev, pxa_dma->sg_size, - &pxa_dma->sg_dma, GFP_KERNEL); - if (!pxa_dma->sg_cpu) - return -ENOMEM; - pxa_dma->sglen = sglen; offset = *sg_first_ofs; dev_dbg(dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma); + memset(&config, 0, sizeof(config)); + config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; /* FIXME? */ + config.src_maxburst = 8; + config.src_addr = pcdev->res->start + cibr; + config.direction = DMA_DEV_TO_MEM; - for_each_sg(*sg_first, sg, sglen, i) { - dma_len = sg_dma_len(sg); - - /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */ - xfer_len = roundup(min(dma_len - offset, size), 8); - - size = max(0, size - xfer_len); + ret = dmaengine_slave_config(dma_chan, &config); + if (ret < 0) { + printk("%s(): dma slave config failed: %d\n", __func__, ret); + return ret; + } - pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr; - pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset; - pxa_dma->sg_cpu[i].dcmd = - DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len; -#ifdef DEBUG - if (!i) - pxa_dma->sg_cpu[i].dcmd |= DCMD_STARTIRQEN; -#endif - pxa_dma->sg_cpu[i].ddadr = - pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); + pcdev->dma_len = dma_map_sg(dma_chan->device->dev, *sg_first, sg_len, + DMA_FROM_DEVICE); - dev_vdbg(dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", - pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc), - sg_dma_address(sg) + offset, xfer_len); - offset = 0; + tx = dmaengine_prep_slave_sg(chan, *sg_first, pcdev->dma_len, + config.direction, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx) { + printk("%s(): prep_slave_sg() failed\n", __func__, ret); + return; + } - if (size == 0) - break; + switch (channel) { + case 0: + tx->callback = pxa_camera_dma_irq_y; + break; + case 1: + tx->callback = pxa_camera_dma_irq_u; + break; + case 2: + tx->callback = pxa_camera_dma_irq_v; + break; } - pxa_dma->sg_cpu[sglen].ddadr = DDADR_STOP; - pxa_dma->sg_cpu[sglen].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN; + tx->callback_param = pcdev; /* * Handle 1 special case : @@ -395,14 +411,16 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, * for next plane should be the next after the last used to store the * last scatter gather RAM page */ - if (xfer_len >= dma_len) { - *sg_first_ofs = xfer_len - dma_len; + if (xfer_len >= pcdev->dma_len) { + *sg_first_ofs = xfer_len - pcdev->dma_len; *sg_first = sg_next(sg); } else { *sg_first_ofs = xfer_len; *sg_first = sg; } + dmaengine_submit(tx); + return 0; } @@ -524,11 +542,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, return 0; fail_v: - dma_free_coherent(dev, buf->dmas[1].sg_size, - buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); fail_u: - dma_free_coherent(dev, buf->dmas[0].sg_size, - buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); fail: free_buffer(vq, buf); out: @@ -552,10 +566,8 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) for (i = 0; i < pcdev->channels; i++) { dev_dbg(pcdev->soc_host.v4l2_dev.dev, - "%s (channel=%d) ddadr=%08x\n", __func__, - i, active->dmas[i].sg_dma); - DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; - DCSR(pcdev->dma_chans[i]) = DCSR_RUN; + "%s (channel=%d)\n", __func__, i); + dma_async_issue_pending(pcdev->dma_chans[i]); } } @@ -566,7 +578,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) for (i = 0; i < pcdev->channels; i++) { dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s (channel=%d)\n", __func__, i); - DCSR(pcdev->dma_chans[i]) = 0; + dmaengine_terminate_all(pcdev->dma_chans[i]); } } @@ -739,25 +751,13 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, spin_lock_irqsave(&pcdev->lock, flags); - status = DCSR(channel); - DCSR(channel) = status; +/* FIXME: dma_unmap_sg() */ camera_status = __raw_readl(pcdev->base + CISR); overrun = CISR_IFO_0; if (pcdev->channels == 3) overrun |= CISR_IFO_1 | CISR_IFO_2; - if (status & DCSR_BUSERR) { - dev_err(dev, "DMA Bus Error IRQ!\n"); - goto out; - } - - if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { - dev_err(dev, "Unknown DMA IRQ source, status: 0x%08x\n", - status); - goto out; - } - /* * pcdev->active should not be NULL in DMA irq handler. * @@ -777,52 +777,28 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, buf = container_of(vb, struct pxa_buffer, vb); WARN_ON(buf->inwork || list_empty(&vb->queue)); - dev_dbg(dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", - __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", - status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); - - if (status & DCSR_ENDINTR) { - /* - * It's normal if the last frame creates an overrun, as there - * are no more DMA descriptors to fetch from QCI fifos - */ - if (camera_status & overrun && - !list_is_last(pcdev->capture.next, &pcdev->capture)) { - dev_dbg(dev, "FIFO overrun! CISR: %x\n", - camera_status); - pxa_camera_stop_capture(pcdev); - pxa_camera_start_capture(pcdev); - goto out; - } - buf->active_dma &= ~act_dma; - if (!buf->active_dma) { - pxa_camera_wakeup(pcdev, vb, buf); - pxa_camera_check_link_miss(pcdev); - } + /* + * It's normal if the last frame creates an overrun, as there + * are no more DMA descriptors to fetch from QCI fifos + */ + if (camera_status & overrun && + !list_is_last(pcdev->capture.next, &pcdev->capture)) { + dev_dbg(dev, "FIFO overrun! CISR: %x\n", + camera_status); + pxa_camera_stop_capture(pcdev); + pxa_camera_start_capture(pcdev); + goto out; + } + buf->active_dma &= ~act_dma; + if (!buf->active_dma) { + pxa_camera_wakeup(pcdev, vb, buf); + pxa_camera_check_link_miss(pcdev); } out: spin_unlock_irqrestore(&pcdev->lock, flags); } -static void pxa_camera_dma_irq_y(int channel, void *data) -{ - struct pxa_camera_dev *pcdev = data; - pxa_camera_dma_irq(channel, pcdev, DMA_Y); -} - -static void pxa_camera_dma_irq_u(int channel, void *data) -{ - struct pxa_camera_dev *pcdev = data; - pxa_camera_dma_irq(channel, pcdev, DMA_U); -} - -static void pxa_camera_dma_irq_v(int channel, void *data) -{ - struct pxa_camera_dev *pcdev = data; - pxa_camera_dma_irq(channel, pcdev, DMA_V); -} - static struct videobuf_queue_ops pxa_videobuf_ops = { .buf_setup = pxa_videobuf_setup, .buf_prepare = pxa_videobuf_prepare, @@ -1655,6 +1631,7 @@ static int pxa_camera_probe(struct platform_device *pdev) struct pxa_camera_dev *pcdev; struct resource *res; void __iomem *base; + unsigned int drcmr; int irq; int err = 0; @@ -1717,36 +1694,35 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->base = base; /* request dma */ - err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, - pxa_camera_dma_irq_y, pcdev); - if (err < 0) { + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + drcmr = 68; + pcdev->dma_chans[0] = + dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn, + &drcmr, &pdev->dev, "CI_Y"); + if (!pcdev->dma_chans[0]) { dev_err(&pdev->dev, "Can't request DMA for Y\n"); - return err; + return -ENODEV; } - pcdev->dma_chans[0] = err; - dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); - err = pxa_request_dma("CI_U", DMA_PRIO_HIGH, - pxa_camera_dma_irq_u, pcdev); - if (err < 0) { - dev_err(&pdev->dev, "Can't request DMA for U\n"); + drcmr = 69; + pcdev->dma_chans[1] = + dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn, + &drcmr, &pdev->dev, "CI_U"); + if (!pcdev->dma_chans[1]) { + dev_err(&pdev->dev, "Can't request DMA for Y\n"); goto exit_free_dma_y; } - pcdev->dma_chans[1] = err; - dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); - err = pxa_request_dma("CI_V", DMA_PRIO_HIGH, - pxa_camera_dma_irq_v, pcdev); - if (err < 0) { + drcmr = 70; + pcdev->dma_chans[2] = + dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn, + &drcmr, &pdev->dev, "CI_V"); + if (!pcdev->dma_chans[2]) { dev_err(&pdev->dev, "Can't request DMA for V\n"); goto exit_free_dma_u; } - pcdev->dma_chans[2] = err; - dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); - - DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; - DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; - DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; /* request irq */ err = devm_request_irq(&pdev->dev, pcdev->irq, pxa_camera_irq, 0, @@ -1769,11 +1745,11 @@ static int pxa_camera_probe(struct platform_device *pdev) return 0; exit_free_dma: - pxa_free_dma(pcdev->dma_chans[2]); + dma_release_channel(dma_chans[2]); exit_free_dma_u: - pxa_free_dma(pcdev->dma_chans[1]); + dma_release_channel(dma_chans[1]); exit_free_dma_y: - pxa_free_dma(pcdev->dma_chans[0]); + dma_release_channel(dma_chans[0]); return err; } @@ -1783,9 +1759,13 @@ static int pxa_camera_remove(struct platform_device *pdev) struct pxa_camera_dev *pcdev = container_of(soc_host, struct pxa_camera_dev, soc_host); - pxa_free_dma(pcdev->dma_chans[0]); - pxa_free_dma(pcdev->dma_chans[1]); - pxa_free_dma(pcdev->dma_chans[2]); + dmaengine_terminate_all(dma_chans[0]); + dmaengine_terminate_all(dma_chans[1]); + dmaengine_terminate_all(dma_chans[2]); + + dma_release_channel(dma_chans[0]); + dma_release_channel(dma_chans[1]); + dma_release_channel(dma_chans[2]); soc_camera_host_unregister(soc_host); -- 1.8.3.1