From a28a94e84bca8ba7db66bcc0db1bea51840b08b2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Jul 2013 17:37:58 +0200 Subject: [PATCH 01/12] DMA: shdma: fix CHCLR register address calculation struct sh_dmae_device::chan_reg is a pointer to u32, therefore when adding offsets to it care should be taken to add offsets in sizeof(u32) units, not in bytes. This patch corrects such a bug. While at it we also remove the redundant parameter of the affected function. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index b67f45f5c271..fca7a0cdfd28 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -49,12 +49,12 @@ static DEFINE_SPINLOCK(sh_dmae_lock); static LIST_HEAD(sh_dmae_devices); -static void chclr_write(struct sh_dmae_chan *sh_dc, u32 data) +static void channel_clear(struct sh_dmae_chan *sh_dc) { struct sh_dmae_device *shdev = to_sh_dev(sh_dc); - __raw_writel(data, shdev->chan_reg + - shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset); + __raw_writel(0, shdev->chan_reg + + shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset / sizeof(u32)); } static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) @@ -133,7 +133,7 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev) for (i = 0; i < shdev->pdata->channel_num; i++) { struct sh_dmae_chan *sh_chan = shdev->chan[i]; if (sh_chan) - chclr_write(sh_chan, 0); + channel_clear(sh_chan); } } From 115357e9774ff8d70a84d3c31f271209913637b0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Jul 2013 17:46:01 +0200 Subject: [PATCH 02/12] DMA: shdma: switch all __iomem pointers to void In the shdma driver __iomem pointers are used to point to hardware registers. Using typed pointers like "u32 __iomem *" in this case is inconvenient, because then offsets, added to such pointers, have to be devided by sizeof(u32) or similar. Switch the driver to use void pointers, which avoids this clumsiness. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma.c | 22 +++++++++++----------- drivers/dma/sh/shdma.h | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index fca7a0cdfd28..9ee1272604b4 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -54,22 +54,22 @@ static void channel_clear(struct sh_dmae_chan *sh_dc) struct sh_dmae_device *shdev = to_sh_dev(sh_dc); __raw_writel(0, shdev->chan_reg + - shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset / sizeof(u32)); + shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset); } static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) { - __raw_writel(data, sh_dc->base + reg / sizeof(u32)); + __raw_writel(data, sh_dc->base + reg); } static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg) { - return __raw_readl(sh_dc->base + reg / sizeof(u32)); + return __raw_readl(sh_dc->base + reg); } static u16 dmaor_read(struct sh_dmae_device *shdev) { - u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32); + void __iomem *addr = shdev->chan_reg + DMAOR; if (shdev->pdata->dmaor_is_32bit) return __raw_readl(addr); @@ -79,7 +79,7 @@ static u16 dmaor_read(struct sh_dmae_device *shdev) static void dmaor_write(struct sh_dmae_device *shdev, u16 data) { - u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32); + void __iomem *addr = shdev->chan_reg + DMAOR; if (shdev->pdata->dmaor_is_32bit) __raw_writel(data, addr); @@ -91,14 +91,14 @@ static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data) { struct sh_dmae_device *shdev = to_sh_dev(sh_dc); - __raw_writel(data, sh_dc->base + shdev->chcr_offset / sizeof(u32)); + __raw_writel(data, sh_dc->base + shdev->chcr_offset); } static u32 chcr_read(struct sh_dmae_chan *sh_dc) { struct sh_dmae_device *shdev = to_sh_dev(sh_dc); - return __raw_readl(sh_dc->base + shdev->chcr_offset / sizeof(u32)); + return __raw_readl(sh_dc->base + shdev->chcr_offset); } /* @@ -242,7 +242,7 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) struct sh_dmae_device *shdev = to_sh_dev(sh_chan); struct sh_dmae_pdata *pdata = shdev->pdata; const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id]; - u16 __iomem *addr = shdev->dmars; + void __iomem *addr = shdev->dmars; unsigned int shift = chan_pdata->dmars_bit; if (dmae_is_busy(sh_chan)) @@ -253,8 +253,8 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) /* in the case of a missing DMARS resource use first memory window */ if (!addr) - addr = (u16 __iomem *)shdev->chan_reg; - addr += chan_pdata->dmars / sizeof(u16); + addr = shdev->chan_reg; + addr += chan_pdata->dmars; __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift), addr); @@ -517,7 +517,7 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, shdma_chan_probe(sdev, schan, id); - sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32); + sh_chan->base = shdev->chan_reg + chan_pdata->offset; /* set up channel irq */ if (pdev->id >= 0) diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h index 9314e93225db..06aae6ebc82b 100644 --- a/drivers/dma/sh/shdma.h +++ b/drivers/dma/sh/shdma.h @@ -28,7 +28,7 @@ struct sh_dmae_chan { struct shdma_chan shdma_chan; const struct sh_dmae_slave_config *config; /* Slave DMA configuration */ int xmit_shift; /* log_2(bytes_per_xfer) */ - u32 __iomem *base; + void __iomem *base; char dev_id[16]; /* unique name per DMAC of channel */ int pm_error; }; @@ -38,8 +38,8 @@ struct sh_dmae_device { struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS]; struct sh_dmae_pdata *pdata; struct list_head node; - u32 __iomem *chan_reg; - u16 __iomem *dmars; + void __iomem *chan_reg; + void __iomem *dmars; unsigned int chcr_offset; u32 chcr_ie_bit; }; From ca8b387803072a16baf6d8090591b10bfdf4e253 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Jul 2013 12:09:47 +0200 Subject: [PATCH 03/12] DMA: shdma: support the new CHCLR register layout On newer r-car SoCs the CHCLR register only contains one bit per channel, to which a 1 has to be written to reset the channel. Older SoC versions had one CHCLR register per channel, to which a 0 must be written to reset the channel and clear its buffers. This patch adds support for the newer layout. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma.c | 14 ++++++++++++-- include/linux/sh_dma.h | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index 9ee1272604b4..53bd6308fc2f 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -49,12 +49,22 @@ static DEFINE_SPINLOCK(sh_dmae_lock); static LIST_HEAD(sh_dmae_devices); +/* + * Different DMAC implementations provide different ways to clear DMA channels: + * (1) none - no CHCLR registers are available + * (2) one CHCLR register per channel - 0 has to be written to it to clear + * channel buffers + * (3) one CHCLR per several channels - 1 has to be written to the bit, + * corresponding to the specific channel to reset it + */ static void channel_clear(struct sh_dmae_chan *sh_dc) { struct sh_dmae_device *shdev = to_sh_dev(sh_dc); + const struct sh_dmae_channel *chan_pdata = shdev->pdata->channel + + sh_dc->shdma_chan.id; + u32 val = shdev->pdata->chclr_bitwise ? 1 << chan_pdata->chclr_bit : 0; - __raw_writel(0, shdev->chan_reg + - shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset); + __raw_writel(val, shdev->chan_reg + chan_pdata->chclr_offset); } static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) diff --git a/include/linux/sh_dma.h b/include/linux/sh_dma.h index 4e83f3e034f3..776ed9d682f4 100644 --- a/include/linux/sh_dma.h +++ b/include/linux/sh_dma.h @@ -33,13 +33,44 @@ struct sh_dmae_slave_config { char mid_rid; }; +/** + * struct sh_dmae_channel - DMAC channel platform data + * @offset: register offset within the main IOMEM resource + * @dmars: channel DMARS register offset + * @chclr_offset: channel CHCLR register offset + * @dmars_bit: channel DMARS field offset within the register + * @chclr_bit: bit position, to be set to reset the channel + */ struct sh_dmae_channel { unsigned int offset; unsigned int dmars; - unsigned int dmars_bit; unsigned int chclr_offset; + unsigned char dmars_bit; + unsigned char chclr_bit; }; +/** + * struct sh_dmae_pdata - DMAC platform data + * @slave: array of slaves + * @slave_num: number of slaves in the above array + * @channel: array of DMA channels + * @channel_num: number of channels in the above array + * @ts_low_shift: shift of the low part of the TS field + * @ts_low_mask: low TS field mask + * @ts_high_shift: additional shift of the high part of the TS field + * @ts_high_mask: high TS field mask + * @ts_shift: array of Transfer Size shifts, indexed by TS value + * @ts_shift_num: number of shifts in the above array + * @dmaor_init: DMAOR initialisation value + * @chcr_offset: CHCR address offset + * @chcr_ie_bit: CHCR Interrupt Enable bit + * @dmaor_is_32bit: DMAOR is a 32-bit register + * @needs_tend_set: the TEND register has to be set + * @no_dmars: DMAC has no DMARS registers + * @chclr_present: DMAC has one or several CHCLR registers + * @chclr_bitwise: channel CHCLR registers are bitwise + * @slave_only: DMAC cannot be used for MEMCPY + */ struct sh_dmae_pdata { const struct sh_dmae_slave_config *slave; int slave_num; @@ -59,6 +90,7 @@ struct sh_dmae_pdata { unsigned int needs_tend_set:1; unsigned int no_dmars:1; unsigned int chclr_present:1; + unsigned int chclr_bitwise:1; unsigned int slave_only:1; }; From c1c63a14f4f2419d093acd7164eccdff315baa86 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Jul 2013 17:45:55 +0200 Subject: [PATCH 04/12] DMA: shdma: switch to managed resource allocation Switch shdma to using devm_* managed functions for allocation of memory, requesting IRQs, mapping IO resources etc. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma-base.c | 11 ++----- drivers/dma/sh/shdma.c | 66 ++++++++----------------------------- drivers/dma/sh/sudmac.c | 1 - include/linux/shdma-base.h | 1 - 4 files changed, 15 insertions(+), 64 deletions(-) diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 28ca36121631..c5ea256c2819 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -831,8 +831,8 @@ static irqreturn_t chan_irqt(int irq, void *dev) int shdma_request_irq(struct shdma_chan *schan, int irq, unsigned long flags, const char *name) { - int ret = request_threaded_irq(irq, chan_irq, chan_irqt, - flags, name, schan); + int ret = devm_request_threaded_irq(schan->dev, irq, chan_irq, + chan_irqt, flags, name, schan); schan->irq = ret < 0 ? ret : irq; @@ -840,13 +840,6 @@ int shdma_request_irq(struct shdma_chan *schan, int irq, } EXPORT_SYMBOL(shdma_request_irq); -void shdma_free_irq(struct shdma_chan *schan) -{ - if (schan->irq >= 0) - free_irq(schan->irq, schan); -} -EXPORT_SYMBOL(shdma_free_irq); - void shdma_chan_probe(struct shdma_dev *sdev, struct shdma_chan *schan, int id) { diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index 53bd6308fc2f..e507bb285fd0 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -515,7 +515,8 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, struct shdma_chan *schan; int err; - sh_chan = kzalloc(sizeof(struct sh_dmae_chan), GFP_KERNEL); + sh_chan = devm_kzalloc(sdev->dma_dev.dev, sizeof(struct sh_dmae_chan), + GFP_KERNEL); if (!sh_chan) { dev_err(sdev->dma_dev.dev, "No free memory for allocating dma channels!\n"); @@ -551,7 +552,6 @@ static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, err_no_irq: /* remove from dmaengine device node */ shdma_chan_remove(schan); - kfree(sh_chan); return err; } @@ -562,14 +562,9 @@ static void sh_dmae_chan_remove(struct sh_dmae_device *shdev) int i; shdma_for_each_chan(schan, &shdev->shdma_dev, i) { - struct sh_dmae_chan *sh_chan = container_of(schan, - struct sh_dmae_chan, shdma_chan); BUG_ON(!schan); - shdma_free_irq(&sh_chan->shdma_chan); - shdma_chan_remove(schan); - kfree(sh_chan); } dma_dev->chancnt = 0; } @@ -706,33 +701,22 @@ static int sh_dmae_probe(struct platform_device *pdev) if (!chan || !errirq_res) return -ENODEV; - if (!request_mem_region(chan->start, resource_size(chan), pdev->name)) { - dev_err(&pdev->dev, "DMAC register region already claimed\n"); - return -EBUSY; - } - - if (dmars && !request_mem_region(dmars->start, resource_size(dmars), pdev->name)) { - dev_err(&pdev->dev, "DMAC DMARS region already claimed\n"); - err = -EBUSY; - goto ermrdmars; - } - - err = -ENOMEM; - shdev = kzalloc(sizeof(struct sh_dmae_device), GFP_KERNEL); + shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device), + GFP_KERNEL); if (!shdev) { dev_err(&pdev->dev, "Not enough memory\n"); - goto ealloc; + return -ENOMEM; } dma_dev = &shdev->shdma_dev.dma_dev; - shdev->chan_reg = ioremap(chan->start, resource_size(chan)); - if (!shdev->chan_reg) - goto emapchan; + shdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan); + if (IS_ERR(shdev->chan_reg)) + return PTR_ERR(shdev->chan_reg); if (dmars) { - shdev->dmars = ioremap(dmars->start, resource_size(dmars)); - if (!shdev->dmars) - goto emapdmars; + shdev->dmars = devm_ioremap_resource(&pdev->dev, dmars); + if (IS_ERR(shdev->dmars)) + return PTR_ERR(shdev->dmars); } if (!pdata->slave_only) @@ -793,8 +777,8 @@ static int sh_dmae_probe(struct platform_device *pdev) errirq = errirq_res->start; - err = request_irq(errirq, sh_dmae_err, irqflags, - "DMAC Address Error", shdev); + err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, irqflags, + "DMAC Address Error", shdev); if (err) { dev_err(&pdev->dev, "DMA failed requesting irq #%d, error %d\n", @@ -872,7 +856,6 @@ static int sh_dmae_probe(struct platform_device *pdev) sh_dmae_chan_remove(shdev); #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) - free_irq(errirq, shdev); eirq_err: #endif rst_err: @@ -886,18 +869,7 @@ static int sh_dmae_probe(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); shdma_cleanup(&shdev->shdma_dev); eshdma: - if (dmars) - iounmap(shdev->dmars); -emapdmars: - iounmap(shdev->chan_reg); synchronize_rcu(); -emapchan: - kfree(shdev); -ealloc: - if (dmars) - release_mem_region(dmars->start, resource_size(dmars)); -ermrdmars: - release_mem_region(chan->start, resource_size(chan)); return err; } @@ -923,21 +895,9 @@ static int sh_dmae_remove(struct platform_device *pdev) sh_dmae_chan_remove(shdev); shdma_cleanup(&shdev->shdma_dev); - if (shdev->dmars) - iounmap(shdev->dmars); - iounmap(shdev->chan_reg); - platform_set_drvdata(pdev, NULL); synchronize_rcu(); - kfree(shdev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) - release_mem_region(res->start, resource_size(res)); return 0; } diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c index e7c94bbddb53..347790167e59 100644 --- a/drivers/dma/sh/sudmac.c +++ b/drivers/dma/sh/sudmac.c @@ -302,7 +302,6 @@ static void sudmac_chan_remove(struct sudmac_device *su_dev) BUG_ON(!schan); - shdma_free_irq(&sc->shdma_chan); shdma_chan_remove(schan); } dma_dev->chancnt = 0; diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index 5b1c9848124c..31cf89fb1d5b 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -116,7 +116,6 @@ struct shdma_dev { int shdma_request_irq(struct shdma_chan *, int, unsigned long, const char *); -void shdma_free_irq(struct shdma_chan *); bool shdma_reset(struct shdma_dev *sdev); void shdma_chan_probe(struct shdma_dev *sdev, struct shdma_chan *schan, int id); From cc6b0f023875a67f0c2ca7211fe6859d60b14852 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 2 Aug 2013 15:23:01 +0200 Subject: [PATCH 05/12] DMA: sudmac: fix compiler warning Fix the following compiler warning: drivers/dma/sh/sudmac.c: In function 'sudmac_chan_remove': drivers/dma/sh/sudmac.c:302: warning: unused variable 'sc' Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/sudmac.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c index 347790167e59..4808b45141b4 100644 --- a/drivers/dma/sh/sudmac.c +++ b/drivers/dma/sh/sudmac.c @@ -298,8 +298,6 @@ static void sudmac_chan_remove(struct sudmac_device *su_dev) int i; shdma_for_each_chan(schan, &su_dev->shdma_dev, i) { - struct sudmac_chan *sc = to_chan(schan); - BUG_ON(!schan); shdma_chan_remove(schan); From 2833c47e0ecc74b300716e56810143125ad7a3f1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 2 Aug 2013 16:18:09 +0200 Subject: [PATCH 06/12] DMA: shdma: make a pointer const Platform data shouldn't be changed at run-time, so, pointers to it should be const. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma.c | 10 +++++----- drivers/dma/sh/shdma.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index e507bb285fd0..3b4bee933dd7 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -177,7 +177,7 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan) static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr) { struct sh_dmae_device *shdev = to_sh_dev(sh_chan); - struct sh_dmae_pdata *pdata = shdev->pdata; + const struct sh_dmae_pdata *pdata = shdev->pdata; int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) | ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift); @@ -190,7 +190,7 @@ static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr) static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size) { struct sh_dmae_device *shdev = to_sh_dev(sh_chan); - struct sh_dmae_pdata *pdata = shdev->pdata; + const struct sh_dmae_pdata *pdata = shdev->pdata; int i; for (i = 0; i < pdata->ts_shift_num; i++) @@ -250,7 +250,7 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val) static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) { struct sh_dmae_device *shdev = to_sh_dev(sh_chan); - struct sh_dmae_pdata *pdata = shdev->pdata; + const struct sh_dmae_pdata *pdata = shdev->pdata; const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id]; void __iomem *addr = shdev->dmars; unsigned int shift = chan_pdata->dmars_bit; @@ -319,7 +319,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave( struct sh_dmae_chan *sh_chan, int match) { struct sh_dmae_device *shdev = to_sh_dev(sh_chan); - struct sh_dmae_pdata *pdata = shdev->pdata; + const struct sh_dmae_pdata *pdata = shdev->pdata; const struct sh_dmae_slave_config *cfg; int i; @@ -665,7 +665,7 @@ static const struct shdma_ops sh_dmae_shdma_ops = { static int sh_dmae_probe(struct platform_device *pdev) { - struct sh_dmae_pdata *pdata = pdev->dev.platform_data; + const struct sh_dmae_pdata *pdata = pdev->dev.platform_data; unsigned long irqflags = IRQF_DISABLED, chan_flag[SH_DMAE_MAX_CHANNELS] = {}; int errirq, chan_irq[SH_DMAE_MAX_CHANNELS]; diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h index 06aae6ebc82b..3d9dca177860 100644 --- a/drivers/dma/sh/shdma.h +++ b/drivers/dma/sh/shdma.h @@ -36,7 +36,7 @@ struct sh_dmae_chan { struct sh_dmae_device { struct shdma_dev shdma_dev; struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS]; - struct sh_dmae_pdata *pdata; + const struct sh_dmae_pdata *pdata; struct list_head node; void __iomem *chan_reg; void __iomem *dmars; From 4981c4dc194efb18f0e9a02f1b43e926f2f0d2bb Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 2 Aug 2013 16:50:36 +0200 Subject: [PATCH 07/12] DMA: shdma: switch DT mode to use configuration data from a match table This facilitates DMAC DT support by eliminating the need in AUXDATA and avoiding creating complex DT data. This also fits well with DMAC devices, of which SoCs often have multiple identical copies and it is perfectly valid to use a single configuration data set for all of them. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/shdma.txt | 61 +++++++++++-------- drivers/dma/sh/Makefile | 2 + drivers/dma/sh/shdma-base.c | 15 +++-- drivers/dma/sh/shdma-of.c | 3 - drivers/dma/sh/shdma.h | 1 + drivers/dma/sh/{shdma.c => shdmac.c} | 30 +++++---- drivers/dma/sh/sudmac.c | 3 +- include/linux/shdma-base.h | 2 +- 8 files changed, 69 insertions(+), 48 deletions(-) rename drivers/dma/sh/{shdma.c => shdmac.c} (98%) diff --git a/Documentation/devicetree/bindings/dma/shdma.txt b/Documentation/devicetree/bindings/dma/shdma.txt index c15994aa1939..2a3f3b8946b9 100644 --- a/Documentation/devicetree/bindings/dma/shdma.txt +++ b/Documentation/devicetree/bindings/dma/shdma.txt @@ -22,42 +22,51 @@ Optional properties (currently unused): * DMA controller Required properties: -- compatible: should be "renesas,shdma" +- compatible: should be of the form "renesas,shdma-", where should + be replaced with the desired SoC model, e.g. + "renesas,shdma-r8a73a4" for the system DMAC on r8a73a4 SoC Example: - dmac: dma-mux0 { + dmac: dma-multiplexer@0 { compatible = "renesas,shdma-mux"; #dma-cells = <1>; - dma-channels = <6>; + dma-channels = <20>; dma-requests = <256>; - reg = <0 0>; /* Needed for AUXDATA */ - #address-cells = <1>; - #size-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; ranges; - dma0: shdma@fe008020 { - compatible = "renesas,shdma"; - reg = <0xfe008020 0x270>, - <0xfe009000 0xc>; + dma0: dma-controller@e6700020 { + compatible = "renesas,shdma-r8a73a4"; + reg = <0 0xe6700020 0 0x89e0>; interrupt-parent = <&gic>; - interrupts = <0 34 4 - 0 28 4 - 0 29 4 - 0 30 4 - 0 31 4 - 0 32 4 - 0 33 4>; + interrupts = <0 220 4 + 0 200 4 + 0 201 4 + 0 202 4 + 0 203 4 + 0 204 4 + 0 205 4 + 0 206 4 + 0 207 4 + 0 208 4 + 0 209 4 + 0 210 4 + 0 211 4 + 0 212 4 + 0 213 4 + 0 214 4 + 0 215 4 + 0 216 4 + 0 217 4 + 0 218 4 + 0 219 4>; interrupt-names = "error", "ch0", "ch1", "ch2", "ch3", - "ch4", "ch5"; - }; - - dma1: shdma@fe018020 { - ... - }; - - dma2: shdma@fe028020 { - ... + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15", + "ch16", "ch17", "ch18", "ch19"; }; }; diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile index c962138dde96..893ee095f93c 100644 --- a/drivers/dma/sh/Makefile +++ b/drivers/dma/sh/Makefile @@ -1,3 +1,5 @@ obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o obj-$(CONFIG_SH_DMAE) += shdma.o +shdma-y := shdmac.o +shdma-objs := $(shdma-y) obj-$(CONFIG_SUDMAC) += sudmac.o diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index c5ea256c2819..d94ab592cc1b 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -171,7 +171,8 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan) return NULL; } -static int shdma_setup_slave(struct shdma_chan *schan, int slave_id) +static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, + dma_addr_t slave_addr) { struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); const struct shdma_ops *ops = sdev->ops; @@ -179,7 +180,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id) if (schan->dev->of_node) { match = schan->hw_req; - ret = ops->set_slave(schan, match, true); + ret = ops->set_slave(schan, match, slave_addr, true); if (ret < 0) return ret; @@ -194,7 +195,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id) if (test_and_set_bit(slave_id, shdma_slave_used)) return -EBUSY; - ret = ops->set_slave(schan, match, false); + ret = ops->set_slave(schan, match, slave_addr, false); if (ret < 0) { clear_bit(slave_id, shdma_slave_used); return ret; @@ -236,7 +237,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) if (!schan->dev->of_node && match >= slave_num) return false; - ret = ops->set_slave(schan, match, true); + ret = ops->set_slave(schan, match, 0, true); if (ret < 0) return false; @@ -259,7 +260,7 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan) */ if (slave) { /* Legacy mode: .private is set in filter */ - ret = shdma_setup_slave(schan, slave->slave_id); + ret = shdma_setup_slave(schan, slave->slave_id, 0); if (ret < 0) goto esetslave; } else { @@ -680,7 +681,9 @@ static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, * channel, while using it... */ config = (struct dma_slave_config *)arg; - ret = shdma_setup_slave(schan, config->slave_id); + ret = shdma_setup_slave(schan, config->slave_id, + config->direction == DMA_DEV_TO_MEM ? + config->src_addr : config->dst_addr); if (ret < 0) return ret; break; diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c index 11bcb05cd79c..2acf7b62d6b6 100644 --- a/drivers/dma/sh/shdma-of.c +++ b/drivers/dma/sh/shdma-of.c @@ -45,9 +45,6 @@ static int shdma_of_probe(struct platform_device *pdev) const struct of_dev_auxdata *lookup = pdev->dev.platform_data; int ret; - if (!lookup) - return -EINVAL; - ret = of_dma_controller_register(pdev->dev.of_node, shdma_of_xlate, pdev); if (ret < 0) diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h index 3d9dca177860..ff2f93b612ca 100644 --- a/drivers/dma/sh/shdma.h +++ b/drivers/dma/sh/shdma.h @@ -31,6 +31,7 @@ struct sh_dmae_chan { void __iomem *base; char dev_id[16]; /* unique name per DMAC of channel */ int pm_error; + dma_addr_t slave_addr; }; struct sh_dmae_device { diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdmac.c similarity index 98% rename from drivers/dma/sh/shdma.c rename to drivers/dma/sh/shdmac.c index 3b4bee933dd7..a47b70879e05 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdmac.c @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include #include @@ -333,7 +335,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave( } else { for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) if (cfg->mid_rid == match) { - sh_chan->shdma_chan.slave_id = cfg->slave_id; + sh_chan->shdma_chan.slave_id = i; return cfg; } } @@ -342,7 +344,7 @@ static const struct sh_dmae_slave_config *dmae_find_slave( } static int sh_dmae_set_slave(struct shdma_chan *schan, - int slave_id, bool try) + int slave_id, dma_addr_t slave_addr, bool try) { struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan, shdma_chan); @@ -350,8 +352,10 @@ static int sh_dmae_set_slave(struct shdma_chan *schan, if (!cfg) return -ENXIO; - if (!try) + if (!try) { sh_chan->config = cfg; + sh_chan->slave_addr = slave_addr ? : cfg->addr; + } return 0; } @@ -641,7 +645,7 @@ static dma_addr_t sh_dmae_slave_addr(struct shdma_chan *schan) * This is an exclusive slave DMA operation, may only be called after a * successful slave configuration. */ - return sh_chan->config->addr; + return sh_chan->slave_addr; } static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i) @@ -663,9 +667,14 @@ static const struct shdma_ops sh_dmae_shdma_ops = { .get_partial = sh_dmae_get_partial, }; +static const struct of_device_id sh_dmae_of_match[] = { + {} +}; +MODULE_DEVICE_TABLE(of, sh_dmae_of_match); + static int sh_dmae_probe(struct platform_device *pdev) { - const struct sh_dmae_pdata *pdata = pdev->dev.platform_data; + const struct sh_dmae_pdata *pdata; unsigned long irqflags = IRQF_DISABLED, chan_flag[SH_DMAE_MAX_CHANNELS] = {}; int errirq, chan_irq[SH_DMAE_MAX_CHANNELS]; @@ -674,6 +683,11 @@ static int sh_dmae_probe(struct platform_device *pdev) struct dma_device *dma_dev; struct resource *chan, *dmars, *errirq_res, *chanirq_res; + if (pdev->dev.of_node) + pdata = of_match_device(sh_dmae_of_match, &pdev->dev)->data; + else + pdata = pdev->dev.platform_data; + /* get platform data */ if (!pdata || !pdata->channel_num) return -ENODEV; @@ -902,12 +916,6 @@ static int sh_dmae_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id sh_dmae_of_match[] = { - { .compatible = "renesas,shdma", }, - { } -}; -MODULE_DEVICE_TABLE(of, sh_dmae_of_match); - static struct platform_driver sh_dmae_driver = { .driver = { .owner = THIS_MODULE, diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c index 4808b45141b4..4600b429603e 100644 --- a/drivers/dma/sh/sudmac.c +++ b/drivers/dma/sh/sudmac.c @@ -150,7 +150,8 @@ static const struct sudmac_slave_config *sudmac_find_slave( return NULL; } -static int sudmac_set_slave(struct shdma_chan *schan, int slave_id, bool try) +static int sudmac_set_slave(struct shdma_chan *schan, int slave_id, + dma_addr_t slave_addr, bool try) { struct sudmac_chan *sc = to_chan(schan); const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id); diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index 31cf89fb1d5b..f92c0a43c54c 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -96,7 +96,7 @@ struct shdma_ops { dma_addr_t (*slave_addr)(struct shdma_chan *); int (*desc_setup)(struct shdma_chan *, struct shdma_desc *, dma_addr_t, dma_addr_t, size_t *); - int (*set_slave)(struct shdma_chan *, int, bool); + int (*set_slave)(struct shdma_chan *, int, dma_addr_t, bool); void (*setup_xfer)(struct shdma_chan *, int); void (*start_xfer)(struct shdma_chan *, struct shdma_desc *); struct shdma_desc *(*embedded_desc)(void *, int); From 4620ad5419612fcd9ab412410440d3a7e8a9a90a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 2 Aug 2013 16:50:37 +0200 Subject: [PATCH 08/12] DMA: shdma: remove private and unused defines from a global header Macros, named like TEND or SAR lack a namespace and are too broadly named for a global header. Besides, they aren't needed globally. Move them to where they belong - into the driver. Some other macros aren't used at all, remove them. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdmac.c | 9 +++++++++ include/linux/sh_dma.h | 21 --------------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index a47b70879e05..03efd4ad0f0b 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -37,6 +37,15 @@ #include "../dmaengine.h" #include "shdma.h" +/* DMA register */ +#define SAR 0x00 +#define DAR 0x04 +#define TCR 0x08 +#define CHCR 0x0C +#define DMAOR 0x40 + +#define TEND 0x18 /* USB-DMAC */ + #define SH_DMAE_DRV_NAME "sh-dma-engine" /* Default MEMCPY transfer size = 2^2 = 4 bytes */ diff --git a/include/linux/sh_dma.h b/include/linux/sh_dma.h index 776ed9d682f4..b7b43b82231e 100644 --- a/include/linux/sh_dma.h +++ b/include/linux/sh_dma.h @@ -94,39 +94,18 @@ struct sh_dmae_pdata { unsigned int slave_only:1; }; -/* DMA register */ -#define SAR 0x00 -#define DAR 0x04 -#define TCR 0x08 -#define CHCR 0x0C -#define DMAOR 0x40 - -#define TEND 0x18 /* USB-DMAC */ - /* DMAOR definitions */ #define DMAOR_AE 0x00000004 #define DMAOR_NMIF 0x00000002 #define DMAOR_DME 0x00000001 /* Definitions for the SuperH DMAC */ -#define REQ_L 0x00000000 -#define REQ_E 0x00080000 -#define RACK_H 0x00000000 -#define RACK_L 0x00040000 -#define ACK_R 0x00000000 -#define ACK_W 0x00020000 -#define ACK_H 0x00000000 -#define ACK_L 0x00010000 #define DM_INC 0x00004000 #define DM_DEC 0x00008000 #define DM_FIX 0x0000c000 #define SM_INC 0x00001000 #define SM_DEC 0x00002000 #define SM_FIX 0x00003000 -#define RS_IN 0x00000200 -#define RS_OUT 0x00000300 -#define TS_BLK 0x00000040 -#define TM_BUR 0x00000020 #define CHCR_DE 0x00000001 #define CHCR_TE 0x00000002 #define CHCR_IE 0x00000004 From 8eb742a0914cd79053d092a14bfac5315993dd61 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 2 Aug 2013 16:50:38 +0200 Subject: [PATCH 09/12] DMA: shdma: add a header with common for ARM SoCs defines All shdma DMACs on ARM SoCs share certain register layout patterns, which are currently defined in arch/arm/mach-shmobile/include/mach/dma-register.h. That header is included by SoC-specific setup-*.c files to be used in DMAC platform data. That header, however, cannot be directly used by the driver. This patch copies those defines into a driver-local header to be used by Device Tree configurations. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdma-arm.h | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 drivers/dma/sh/shdma-arm.h diff --git a/drivers/dma/sh/shdma-arm.h b/drivers/dma/sh/shdma-arm.h new file mode 100644 index 000000000000..a2b8258426c9 --- /dev/null +++ b/drivers/dma/sh/shdma-arm.h @@ -0,0 +1,51 @@ +/* + * Renesas SuperH DMA Engine support + * + * Copyright (C) 2013 Renesas Electronics, Inc. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of version 2 the GNU General Public License as published by the Free + * Software Foundation. + */ + +#ifndef SHDMA_ARM_H +#define SHDMA_ARM_H + +#include "shdma.h" + +/* Transmit sizes and respective CHCR register values */ +enum { + XMIT_SZ_8BIT = 0, + XMIT_SZ_16BIT = 1, + XMIT_SZ_32BIT = 2, + XMIT_SZ_64BIT = 7, + XMIT_SZ_128BIT = 3, + XMIT_SZ_256BIT = 4, + XMIT_SZ_512BIT = 5, +}; + +/* log2(size / 8) - used to calculate number of transfers */ +#define SH_DMAE_TS_SHIFT { \ + [XMIT_SZ_8BIT] = 0, \ + [XMIT_SZ_16BIT] = 1, \ + [XMIT_SZ_32BIT] = 2, \ + [XMIT_SZ_64BIT] = 3, \ + [XMIT_SZ_128BIT] = 4, \ + [XMIT_SZ_256BIT] = 5, \ + [XMIT_SZ_512BIT] = 6, \ +} + +#define TS_LOW_BIT 0x3 /* --xx */ +#define TS_HI_BIT 0xc /* xx-- */ + +#define TS_LOW_SHIFT (3) +#define TS_HI_SHIFT (20 - 2) /* 2 bits for shifted low TS */ + +#define TS_INDEX2VAL(i) \ + ((((i) & TS_LOW_BIT) << TS_LOW_SHIFT) |\ + (((i) & TS_HI_BIT) << TS_HI_SHIFT)) + +#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz))) +#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz))) + +#endif From 1e69653d40f1a280dbfef48b0c62473ac415dd57 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 2 Aug 2013 16:50:39 +0200 Subject: [PATCH 10/12] DMA: shdma: add r8a73a4 DMAC data to the device ID table This configuration data will be used, when DMAC DT support is added to r8a73a4. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/Kconfig | 4 ++ drivers/dma/sh/Makefile | 3 ++ drivers/dma/sh/shdma-r8a73a4.c | 77 ++++++++++++++++++++++++++++++++++ drivers/dma/sh/shdma.h | 7 ++++ drivers/dma/sh/shdmac.c | 1 + 5 files changed, 92 insertions(+) create mode 100644 drivers/dma/sh/shdma-r8a73a4.c diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig index 5c1dee20c13e..d0924b6948e0 100644 --- a/drivers/dma/sh/Kconfig +++ b/drivers/dma/sh/Kconfig @@ -22,3 +22,7 @@ config SUDMAC depends on SH_DMAE_BASE help Enable support for the Renesas SUDMAC controllers. + +config SHDMA_R8A73A4 + def_bool y + depends on ARCH_R8A73A4 && SH_DMAE != n diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile index 893ee095f93c..05a31d447bd4 100644 --- a/drivers/dma/sh/Makefile +++ b/drivers/dma/sh/Makefile @@ -1,5 +1,8 @@ obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o obj-$(CONFIG_SH_DMAE) += shdma.o shdma-y := shdmac.o +ifeq ($(CONFIG_OF),y) +shdma-$(CONFIG_SHDMA_R8A73A4) += shdma-r8a73a4.o +endif shdma-objs := $(shdma-y) obj-$(CONFIG_SUDMAC) += sudmac.o diff --git a/drivers/dma/sh/shdma-r8a73a4.c b/drivers/dma/sh/shdma-r8a73a4.c new file mode 100644 index 000000000000..4fb99970a3ea --- /dev/null +++ b/drivers/dma/sh/shdma-r8a73a4.c @@ -0,0 +1,77 @@ +/* + * Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs + * + * Copyright (C) 2013 Renesas Electronics, Inc. + * + * This is free software; you can redistribute it and/or modify it under the + * terms of version 2 the GNU General Public License as published by the Free + * Software Foundation. + */ +#include + +#include "shdma-arm.h" + +const unsigned int dma_ts_shift[] = SH_DMAE_TS_SHIFT; + +static const struct sh_dmae_slave_config dma_slaves[] = { + { + .chcr = CHCR_TX(XMIT_SZ_32BIT), + .mid_rid = 0xd1, /* MMC0 Tx */ + }, { + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0xd2, /* MMC0 Rx */ + }, { + .chcr = CHCR_TX(XMIT_SZ_32BIT), + .mid_rid = 0xe1, /* MMC1 Tx */ + }, { + .chcr = CHCR_RX(XMIT_SZ_32BIT), + .mid_rid = 0xe2, /* MMC1 Rx */ + }, +}; + +#define DMAE_CHANNEL(a, b) \ + { \ + .offset = (a) - 0x20, \ + .dmars = (a) - 0x20 + 0x40, \ + .chclr_bit = (b), \ + .chclr_offset = 0x80 - 0x20, \ + } + +static const struct sh_dmae_channel dma_channels[] = { + DMAE_CHANNEL(0x8000, 0), + DMAE_CHANNEL(0x8080, 1), + DMAE_CHANNEL(0x8100, 2), + DMAE_CHANNEL(0x8180, 3), + DMAE_CHANNEL(0x8200, 4), + DMAE_CHANNEL(0x8280, 5), + DMAE_CHANNEL(0x8300, 6), + DMAE_CHANNEL(0x8380, 7), + DMAE_CHANNEL(0x8400, 8), + DMAE_CHANNEL(0x8480, 9), + DMAE_CHANNEL(0x8500, 10), + DMAE_CHANNEL(0x8580, 11), + DMAE_CHANNEL(0x8600, 12), + DMAE_CHANNEL(0x8680, 13), + DMAE_CHANNEL(0x8700, 14), + DMAE_CHANNEL(0x8780, 15), + DMAE_CHANNEL(0x8800, 16), + DMAE_CHANNEL(0x8880, 17), + DMAE_CHANNEL(0x8900, 18), + DMAE_CHANNEL(0x8980, 19), +}; + +const struct sh_dmae_pdata r8a73a4_dma_pdata = { + .slave = dma_slaves, + .slave_num = ARRAY_SIZE(dma_slaves), + .channel = dma_channels, + .channel_num = ARRAY_SIZE(dma_channels), + .ts_low_shift = TS_LOW_SHIFT, + .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, + .ts_high_shift = TS_HI_SHIFT, + .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, + .ts_shift = dma_ts_shift, + .ts_shift_num = ARRAY_SIZE(dma_ts_shift), + .dmaor_init = DMAOR_DME, + .chclr_present = 1, + .chclr_bitwise = 1, +}; diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h index ff2f93b612ca..758a57b51875 100644 --- a/drivers/dma/sh/shdma.h +++ b/drivers/dma/sh/shdma.h @@ -62,4 +62,11 @@ struct sh_dmae_desc { #define to_sh_dev(chan) container_of(chan->shdma_chan.dma_chan.device,\ struct sh_dmae_device, shdma_dev.dma_dev) +#ifdef CONFIG_SHDMA_R8A73A4 +extern const struct sh_dmae_pdata r8a73a4_dma_pdata; +#define r8a73a4_shdma_devid (&r8a73a4_dma_pdata) +#else +#define r8a73a4_shdma_devid NULL +#endif + #endif /* __DMA_SHDMA_H */ diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 03efd4ad0f0b..77de5e4375f2 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -677,6 +677,7 @@ static const struct shdma_ops sh_dmae_shdma_ops = { }; static const struct of_device_id sh_dmae_of_match[] = { + {.compatible = "renesas,shdma-r8a73a4", .data = r8a73a4_shdma_devid,}, {} }; MODULE_DEVICE_TABLE(of, sh_dmae_of_match); From eb262a5419708319a3174d4ddf2777f472779182 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 26 Aug 2013 09:32:05 +0900 Subject: [PATCH 11/12] dma: sh: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Acked-by: Simon Horman Acked-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdmac.c | 3 --- drivers/dma/sh/sudmac.c | 2 -- 2 files changed, 5 deletions(-) diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 77de5e4375f2..6128715973a4 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -890,7 +890,6 @@ static int sh_dmae_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - platform_set_drvdata(pdev, NULL); shdma_cleanup(&shdev->shdma_dev); eshdma: synchronize_rcu(); @@ -919,8 +918,6 @@ static int sh_dmae_remove(struct platform_device *pdev) sh_dmae_chan_remove(shdev); shdma_cleanup(&shdev->shdma_dev); - platform_set_drvdata(pdev, NULL); - synchronize_rcu(); return 0; diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c index 4600b429603e..90ba2ded2455 100644 --- a/drivers/dma/sh/sudmac.c +++ b/drivers/dma/sh/sudmac.c @@ -391,7 +391,6 @@ static int sudmac_probe(struct platform_device *pdev) chan_probe_err: sudmac_chan_remove(su_dev); - platform_set_drvdata(pdev, NULL); shdma_cleanup(&su_dev->shdma_dev); return err; @@ -405,7 +404,6 @@ static int sudmac_remove(struct platform_device *pdev) dma_async_device_unregister(dma_dev); sudmac_chan_remove(su_dev); shdma_cleanup(&su_dev->shdma_dev); - platform_set_drvdata(pdev, NULL); return 0; } From e5ffa401eacd0e74178e20ba932200fc9fe41c07 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 26 Aug 2013 14:27:51 +0200 Subject: [PATCH 12/12] DMA: shdma: fix a bad merge - remove free_irq() A bad merge resulted in a left-over free_irq() call. This patch removes it. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Vinod Koul --- drivers/dma/sh/shdmac.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 6128715973a4..33ce47eef0bf 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -901,14 +901,9 @@ static int sh_dmae_remove(struct platform_device *pdev) { struct sh_dmae_device *shdev = platform_get_drvdata(pdev); struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev; - struct resource *res; - int errirq = platform_get_irq(pdev, 0); dma_async_device_unregister(dma_dev); - if (errirq > 0) - free_irq(errirq, shdev); - spin_lock_irq(&sh_dmae_lock); list_del_rcu(&shdev->node); spin_unlock_irq(&sh_dmae_lock);