* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
2014-01-24 2:32 [PATCH] shdma: add R-Car Audio DMAC peri peri driver Kuninori Morimoto
@ 2014-01-24 7:34 ` Geert Uytterhoeven
2014-01-24 8:18 ` Kuninori Morimoto
2014-01-24 9:06 ` [PATCH v2] dma: " Kuninori Morimoto
` (3 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 7:34 UTC (permalink / raw)
To: Kuninori Morimoto
Cc: Vinod Koul, Morimoto, Linux-SH, linux-kernel@vger.kernel.org
Hi Morimoto-san,
On Fri, Jan 24, 2014 at 3:32 AM, Kuninori Morimoto
<kuninori.morimoto.gx@gmail.com> wrote:
> --- a/drivers/dma/sh/Kconfig
> +++ b/drivers/dma/sh/Kconfig
> @@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
> help
> Enable support for the Renesas R-Car series DMA controllers.
>
> +config RCAR_AUDMAC_PP
> + tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
double "Peripheral"
> + depends on SH_DMAE_BASE
> + help
> + Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral controllers.
idem.
> --- /dev/null
> +++ b/drivers/dma/sh/rcar-audmapp.c
> @@ -0,0 +1,325 @@
> +static void audmapp_halt(struct shdma_chan *schan)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + int i;
unsigned int
> +
> + audmapp_write(auchan, 0, PDMACHCR);
> +
> + for(i = 0; i < 1024; i++) {
Missing space between "for" and "(" (have you run checkpatch.pl?)
What's a typical value of i when leaving the loop?
> + if (0 == audmapp_read(auchan, PDMACHCR))
> + return;
> + udelay(1);
> + }
> +}
> +
> +
> +static struct audmapp_slave_config *
> +audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
> +{
> + struct audmapp_device *audev = to_dev(auchan);
> + struct audmapp_pdata *pdata = audev->pdata;
> + struct audmapp_slave_config *cfg;
> + int i;
unsigned int
> +
> + if (slave_id >= AUDMAPP_SLAVE_NUMBER)
So slave_id should be unsigned int, too, and AUDMAPP_SLAVE_NUMBER
too ("29U").
> + return NULL;
> +
> + for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
> + if (cfg->slave_id == slave_id)
> + return cfg;
> +
> + return NULL;
> +}
> +static int audmapp_desc_setup(struct shdma_chan *schan,
> + struct shdma_desc *sdecs,
> + dma_addr_t src, dma_addr_t dst, size_t *len)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_slave_config *cfg = auchan->config;
> +
> + if (!cfg)
> + return -ENODEV;
> +
> + if (*len > (size_t)AUDMAPP_LEN_MAX)
I think you can get rid of the cast by adding a "U" suffix to one of
the constants in the definition of AUDMAPP_LEN_MAX.
> + *len = (size_t)AUDMAPP_LEN_MAX;
The cast is not needed (I think even without the change above).
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
2014-01-24 7:34 ` Geert Uytterhoeven
@ 2014-01-24 8:18 ` Kuninori Morimoto
2014-01-24 8:33 ` Geert Uytterhoeven
0 siblings, 1 reply; 17+ messages in thread
From: Kuninori Morimoto @ 2014-01-24 8:18 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Vinod Koul, Morimoto, Linux-SH, linux-kernel@vger.kernel.org
Hi Geert
Thank you for your review
> > --- a/drivers/dma/sh/Kconfig
> > +++ b/drivers/dma/sh/Kconfig
> > @@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
> > help
> > Enable support for the Renesas R-Car series DMA controllers.
> >
> > +config RCAR_AUDMAC_PP
> > + tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
>
> double "Peripheral"
Unfortunately (?) "Audio DMAC Peripheral Peripheral"
(= double Peripheral) is the formal name
> > + for(i = 0; i < 1024; i++) {
>
> Missing space between "for" and "(" (have you run checkpatch.pl?)
>
> What's a typical value of i when leaving the loop?
Oops, this is my fault.
I will fix in v2
> > +static struct audmapp_slave_config *
> > +audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
> > +{
> > + struct audmapp_device *audev = to_dev(auchan);
> > + struct audmapp_pdata *pdata = audev->pdata;
> > + struct audmapp_slave_config *cfg;
> > + int i;
>
> unsigned int
>
> > +
> > + if (slave_id >= AUDMAPP_SLAVE_NUMBER)
>
> So slave_id should be unsigned int, too, and AUDMAPP_SLAVE_NUMBER
> too ("29U").
Hmm...
This driver is called from shdma-base.c.
And shdmac.c/sudmac.c/rcar-hpbdmac.c are same style.
1) this "slave_id" came from shdma_ops::set_slave
and, it is using "int"
2) above drivers have same xxx_find_slave(),
they are using "int".
(this driver is based on that)
What should I do ?
> > + if (*len > (size_t)AUDMAPP_LEN_MAX)
>
> I think you can get rid of the cast by adding a "U" suffix to one of
> the constants in the definition of AUDMAPP_LEN_MAX.
>
> > + *len = (size_t)AUDMAPP_LEN_MAX;
>
> The cast is not needed (I think even without the change above).
I will fixup these in v2
Thank you
Best regards
---
Kuninori Morimoto
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
2014-01-24 8:18 ` Kuninori Morimoto
@ 2014-01-24 8:33 ` Geert Uytterhoeven
2014-01-24 8:58 ` Kuninori Morimoto
0 siblings, 1 reply; 17+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:33 UTC (permalink / raw)
To: Kuninori Morimoto
Cc: Vinod Koul, Morimoto, Linux-SH, linux-kernel@vger.kernel.org
Hi Morimoto-san,
On Fri, Jan 24, 2014 at 9:18 AM, Kuninori Morimoto
<kuninori.morimoto.gx@gmail.com> wrote:
>> > + if (slave_id >= AUDMAPP_SLAVE_NUMBER)
>>
>> So slave_id should be unsigned int, too, and AUDMAPP_SLAVE_NUMBER
>> too ("29U").
>
> Hmm...
> This driver is called from shdma-base.c.
> And shdmac.c/sudmac.c/rcar-hpbdmac.c are same style.
>
> 1) this "slave_id" came from shdma_ops::set_slave
> and, it is using "int"
> 2) above drivers have same xxx_find_slave(),
> they are using "int".
> (this driver is based on that)
>
> What should I do ?
OK, then you should keep using int, and change the test to:
if (slave_id < 0 || slave_id >= AUDMAPP_SLAVE_NUMBER)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
2014-01-24 8:33 ` Geert Uytterhoeven
@ 2014-01-24 8:58 ` Kuninori Morimoto
0 siblings, 0 replies; 17+ messages in thread
From: Kuninori Morimoto @ 2014-01-24 8:58 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Vinod Koul, Morimoto, Linux-SH, linux-kernel@vger.kernel.org
Hi Geert
> > This driver is called from shdma-base.c.
> > And shdmac.c/sudmac.c/rcar-hpbdmac.c are same style.
> >
> > 1) this "slave_id" came from shdma_ops::set_slave
> > and, it is using "int"
> > 2) above drivers have same xxx_find_slave(),
> > they are using "int".
> > (this driver is based on that)
> >
> > What should I do ?
>
> OK, then you should keep using int, and change the test to:
>
> if (slave_id < 0 || slave_id >= AUDMAPP_SLAVE_NUMBER)
I see
Thank you
Best regards
---
Kuninori Morimoto
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
2014-01-24 2:32 [PATCH] shdma: add R-Car Audio DMAC peri peri driver Kuninori Morimoto
2014-01-24 7:34 ` Geert Uytterhoeven
@ 2014-01-24 9:06 ` Kuninori Morimoto
2014-02-12 5:29 ` Kuninori Morimoto
2014-03-10 1:34 ` [PATCH v2][RESENT] " Kuninori Morimoto
` (2 subsequent siblings)
4 siblings, 1 reply; 17+ messages in thread
From: Kuninori Morimoto @ 2014-01-24 9:06 UTC (permalink / raw)
To: Vinod Koul; +Cc: Morimoto, Linux-SH, linux-kernel, Geert Uytterhoeven
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Add support Audio DMAC peri peri driver
for Renesas R-Car Gen2 SoC, using 'shdma-base'
DMA driver framework.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v1 -> v2
- run scripts/checkpatch.pl
- ecchange length settings on audmapp_desc_setup()
- exchange slave_id check on audmapp_find_slave()
drivers/dma/sh/Kconfig | 6 +
drivers/dma/sh/Makefile | 1 +
drivers/dma/sh/rcar-audmapp.c | 325 ++++++++++++++++++++++++
include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
4 files changed, 366 insertions(+)
create mode 100644 drivers/dma/sh/rcar-audmapp.c
create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index dadd9e01..b4c8138 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
help
Enable support for the Renesas R-Car series DMA controllers.
+config RCAR_AUDMAC_PP
+ tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
+ depends on SH_DMAE_BASE
+ help
+ Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -7,3 +7,4 @@ endif
shdma-objs := $(shdma-y)
obj-$(CONFIG_SUDMAC) += sudmac.o
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
+obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
new file mode 100644
index 0000000..cd3c237
--- /dev/null
+++ b/drivers/dma/sh/rcar-audmapp.c
@@ -0,0 +1,325 @@
+/*
+ * drivers/dma/sh/rcar-audmapp.c
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on the drivers/dma/sh/shdma.c
+ *
+ * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+ * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/dma-rcar-audmapp.h>
+#include <linux/platform_device.h>
+#include <linux/shdma-base.h>
+
+/*
+ * DMA register
+ */
+#define PDMASAR 0x00
+#define PDMADAR 0x04
+#define PDMACHCR 0x0c
+
+/* PDMACHCR */
+#define PDMACHCR_DE (1 << 0)
+
+#define AUDMAPP_MAX_CHANNELS 29
+
+/* Default MEMCPY transfer size = 2^2 = 4 bytes */
+#define LOG2_DEFAULT_XFER_SIZE 2
+#define AUDMAPP_SLAVE_NUMBER 256
+#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
+
+struct audmapp_chan {
+ struct shdma_chan shdma_chan;
+ struct audmapp_slave_config *config;
+ void __iomem *base;
+};
+
+struct audmapp_device {
+ struct shdma_dev shdma_dev;
+ struct audmapp_pdata *pdata;
+ struct device *dev;
+ void __iomem *chan_reg;
+};
+
+#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
+#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
+ struct audmapp_device, shdma_dev.dma_dev)
+
+static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct device *dev = audev->dev;
+
+ dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
+
+ iowrite32(data, auchan->base + reg);
+}
+
+static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
+{
+ return ioread32(auchan->base + reg);
+}
+
+static void audmapp_halt(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ int i;
+
+ audmapp_write(auchan, 0, PDMACHCR);
+
+ for (i = 0; i < 1024; i++) {
+ if (0 == audmapp_read(auchan, PDMACHCR))
+ return;
+ udelay(1);
+ }
+}
+
+static void audmapp_start_xfer(struct shdma_chan *schan,
+ struct shdma_desc *sdecs)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_slave_config *cfg = auchan->config;
+ struct device *dev = audev->dev;
+ u32 chcr = cfg->chcr | PDMACHCR_DE;
+
+ dev_dbg(dev, "src/dst/chcr = %x/%x/%x\n",
+ cfg->src, cfg->dst, cfg->chcr);
+
+ audmapp_write(auchan, cfg->src, PDMASAR);
+ audmapp_write(auchan, cfg->dst, PDMADAR);
+ audmapp_write(auchan, chcr, PDMACHCR);
+}
+
+static struct audmapp_slave_config *
+audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_pdata *pdata = audev->pdata;
+ struct audmapp_slave_config *cfg;
+ int i;
+
+ if (slave_id < 0 || slave_id >= AUDMAPP_SLAVE_NUMBER)
+ return NULL;
+
+ for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+ if (cfg->slave_id == slave_id)
+ return cfg;
+
+ return NULL;
+}
+
+static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
+ dma_addr_t slave_addr, bool try)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg =
+ audmapp_find_slave(auchan, slave_id);
+
+ if (!cfg)
+ return -ENODEV;
+ if (try)
+ return 0;
+
+ auchan->config = cfg;
+
+ return 0;
+}
+
+static int audmapp_desc_setup(struct shdma_chan *schan,
+ struct shdma_desc *sdecs,
+ dma_addr_t src, dma_addr_t dst, size_t *len)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg = auchan->config;
+
+ if (!cfg)
+ return -ENODEV;
+
+ if (*len > schan->max_xfer_len)
+ *len = schan->max_xfer_len;
+
+ return 0;
+}
+
+static void audmapp_setup_xfer(struct shdma_chan *schan,
+ int slave_id)
+{
+}
+
+static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
+{
+ return 0; /* always fixed address */
+}
+
+static bool audmapp_channel_busy(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ u32 chcr = audmapp_read(auchan, PDMACHCR);
+
+ return chcr & ~PDMACHCR_DE;
+}
+
+static bool audmapp_desc_completed(struct shdma_chan *schan,
+ struct shdma_desc *sdesc)
+{
+ return true;
+}
+
+static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
+{
+ return &((struct shdma_desc *)buf)[i];
+}
+
+static const struct shdma_ops audmapp_shdma_ops = {
+ .halt_channel = audmapp_halt,
+ .desc_setup = audmapp_desc_setup,
+ .set_slave = audmapp_set_slave,
+ .start_xfer = audmapp_start_xfer,
+ .embedded_desc = audmapp_embedded_desc,
+ .setup_xfer = audmapp_setup_xfer,
+ .slave_addr = audmapp_slave_addr,
+ .channel_busy = audmapp_channel_busy,
+ .desc_completed = audmapp_desc_completed,
+};
+
+static int audmapp_chan_probe(struct platform_device *pdev,
+ struct audmapp_device *audev, int id)
+{
+ struct shdma_dev *sdev = &audev->shdma_dev;
+ struct audmapp_chan *auchan;
+ struct shdma_chan *schan;
+ struct device *dev = audev->dev;
+
+ auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
+ if (!auchan) {
+ dev_err(dev, "No free memory for allocating dma channels!\n");
+ return -ENOMEM;
+ }
+
+ schan = &auchan->shdma_chan;
+ schan->max_xfer_len = AUDMAPP_LEN_MAX;
+
+ shdma_chan_probe(sdev, schan, id);
+
+ auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
+ dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
+
+ return 0;
+}
+
+static void audmapp_chan_remove(struct audmapp_device *audev)
+{
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+ struct shdma_chan *schan;
+ int i;
+
+ shdma_for_each_chan(schan, &audev->shdma_dev, i) {
+ BUG_ON(!schan);
+ shdma_chan_remove(schan);
+ }
+ dma_dev->chancnt = 0;
+}
+
+static int audmapp_probe(struct platform_device *pdev)
+{
+ struct audmapp_pdata *pdata = pdev->dev.platform_data;
+ struct audmapp_device *audev;
+ struct shdma_dev *sdev;
+ struct dma_device *dma_dev;
+ struct resource *res;
+ int err, i;
+
+ if (!pdata)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
+ GFP_KERNEL);
+ if (!audev) {
+ dev_err(&pdev->dev, "Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ audev->dev = &pdev->dev;
+ audev->pdata = pdata;
+ audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(audev->chan_reg))
+ return PTR_ERR(audev->chan_reg);
+
+ sdev = &audev->shdma_dev;
+ sdev->ops = &audmapp_shdma_ops;
+ sdev->desc_size = sizeof(struct shdma_desc);
+
+ dma_dev = &sdev->dma_dev;
+ dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
+ dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+
+ err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
+ if (err < 0)
+ return err;
+
+ platform_set_drvdata(pdev, audev);
+
+ /* Create DMA Channel */
+ for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
+ err = audmapp_chan_probe(pdev, audev, i);
+ if (err)
+ goto chan_probe_err;
+ }
+
+ err = dma_async_device_register(dma_dev);
+ if (err < 0)
+ goto chan_probe_err;
+
+ return err;
+
+chan_probe_err:
+ audmapp_chan_remove(audev);
+ shdma_cleanup(sdev);
+
+ return err;
+}
+
+static int audmapp_remove(struct platform_device *pdev)
+{
+ struct audmapp_device *audev = platform_get_drvdata(pdev);
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+
+ dma_async_device_unregister(dma_dev);
+
+ audmapp_chan_remove(audev);
+ shdma_cleanup(&audev->shdma_dev);
+
+ return 0;
+}
+
+static struct platform_driver audmapp_driver = {
+ .probe = audmapp_probe,
+ .remove = audmapp_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rcar-audmapp-engine",
+ },
+};
+module_platform_driver(audmapp_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
new file mode 100644
index 0000000..346df66
--- /dev/null
+++ b/include/linux/platform_data/dma-rcar-audmapp.h
@@ -0,0 +1,34 @@
+/*
+ * include/linux/sh_audma-pp.h
+ * This file is header file for Audio-DMAC-pp peripheral.
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ *
+ * This file is based on the include/linux/sh_dma.h
+ *
+ * Header for the new SH dmaengine driver
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef SH_AUDMAPP_H
+#define SH_AUDMAPP_H
+
+#include <linux/dmaengine.h>
+
+struct audmapp_slave_config {
+ int slave_id;
+ dma_addr_t src;
+ dma_addr_t dst;
+ u32 chcr;
+};
+
+struct audmapp_pdata {
+ struct audmapp_slave_config *slave;
+ int slave_num;
+};
+
+#endif /* SH_AUDMAPP_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
2014-01-24 9:06 ` [PATCH v2] dma: " Kuninori Morimoto
@ 2014-02-12 5:29 ` Kuninori Morimoto
2014-02-25 5:13 ` Kuninori Morimoto
0 siblings, 1 reply; 17+ messages in thread
From: Kuninori Morimoto @ 2014-02-12 5:29 UTC (permalink / raw)
To: Vinod Koul; +Cc: Morimoto, Linux-SH, linux-kernel
Hi Vinod
Can I ask you about current status of this patch ?
> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
>
> Add support Audio DMAC peri peri driver
> for Renesas R-Car Gen2 SoC, using 'shdma-base'
> DMA driver framework.
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
> v1 -> v2
>
> - run scripts/checkpatch.pl
> - ecchange length settings on audmapp_desc_setup()
> - exchange slave_id check on audmapp_find_slave()
>
> drivers/dma/sh/Kconfig | 6 +
> drivers/dma/sh/Makefile | 1 +
> drivers/dma/sh/rcar-audmapp.c | 325 ++++++++++++++++++++++++
> include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
> 4 files changed, 366 insertions(+)
> create mode 100644 drivers/dma/sh/rcar-audmapp.c
> create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
>
> diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
> index dadd9e01..b4c8138 100644
> --- a/drivers/dma/sh/Kconfig
> +++ b/drivers/dma/sh/Kconfig
> @@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
> help
> Enable support for the Renesas R-Car series DMA controllers.
>
> +config RCAR_AUDMAC_PP
> + tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
> + depends on SH_DMAE_BASE
> + help
> + Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
> --- a/drivers/dma/sh/Makefile
> +++ b/drivers/dma/sh/Makefile
> @@ -7,3 +7,4 @@ endif
> shdma-objs := $(shdma-y)
> obj-$(CONFIG_SUDMAC) += sudmac.o
> obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
> +obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
> diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
> new file mode 100644
> index 0000000..cd3c237
> --- /dev/null
> +++ b/drivers/dma/sh/rcar-audmapp.c
> @@ -0,0 +1,325 @@
> +/*
> + * drivers/dma/sh/rcar-audmapp.c
> + *
> + * Copyright (C) 2013 Renesas Electronics Corporation
> + * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> + *
> + * based on the drivers/dma/sh/shdma.c
> + *
> + * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
> + * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
> + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * This is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/dmaengine.h>
> +#include <linux/platform_data/dma-rcar-audmapp.h>
> +#include <linux/platform_device.h>
> +#include <linux/shdma-base.h>
> +
> +/*
> + * DMA register
> + */
> +#define PDMASAR 0x00
> +#define PDMADAR 0x04
> +#define PDMACHCR 0x0c
> +
> +/* PDMACHCR */
> +#define PDMACHCR_DE (1 << 0)
> +
> +#define AUDMAPP_MAX_CHANNELS 29
> +
> +/* Default MEMCPY transfer size = 2^2 = 4 bytes */
> +#define LOG2_DEFAULT_XFER_SIZE 2
> +#define AUDMAPP_SLAVE_NUMBER 256
> +#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
> +
> +struct audmapp_chan {
> + struct shdma_chan shdma_chan;
> + struct audmapp_slave_config *config;
> + void __iomem *base;
> +};
> +
> +struct audmapp_device {
> + struct shdma_dev shdma_dev;
> + struct audmapp_pdata *pdata;
> + struct device *dev;
> + void __iomem *chan_reg;
> +};
> +
> +#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
> +#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
> + struct audmapp_device, shdma_dev.dma_dev)
> +
> +static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
> +{
> + struct audmapp_device *audev = to_dev(auchan);
> + struct device *dev = audev->dev;
> +
> + dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
> +
> + iowrite32(data, auchan->base + reg);
> +}
> +
> +static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
> +{
> + return ioread32(auchan->base + reg);
> +}
> +
> +static void audmapp_halt(struct shdma_chan *schan)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + int i;
> +
> + audmapp_write(auchan, 0, PDMACHCR);
> +
> + for (i = 0; i < 1024; i++) {
> + if (0 == audmapp_read(auchan, PDMACHCR))
> + return;
> + udelay(1);
> + }
> +}
> +
> +static void audmapp_start_xfer(struct shdma_chan *schan,
> + struct shdma_desc *sdecs)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_device *audev = to_dev(auchan);
> + struct audmapp_slave_config *cfg = auchan->config;
> + struct device *dev = audev->dev;
> + u32 chcr = cfg->chcr | PDMACHCR_DE;
> +
> + dev_dbg(dev, "src/dst/chcr = %x/%x/%x\n",
> + cfg->src, cfg->dst, cfg->chcr);
> +
> + audmapp_write(auchan, cfg->src, PDMASAR);
> + audmapp_write(auchan, cfg->dst, PDMADAR);
> + audmapp_write(auchan, chcr, PDMACHCR);
> +}
> +
> +static struct audmapp_slave_config *
> +audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
> +{
> + struct audmapp_device *audev = to_dev(auchan);
> + struct audmapp_pdata *pdata = audev->pdata;
> + struct audmapp_slave_config *cfg;
> + int i;
> +
> + if (slave_id < 0 || slave_id >= AUDMAPP_SLAVE_NUMBER)
> + return NULL;
> +
> + for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
> + if (cfg->slave_id == slave_id)
> + return cfg;
> +
> + return NULL;
> +}
> +
> +static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
> + dma_addr_t slave_addr, bool try)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_slave_config *cfg =
> + audmapp_find_slave(auchan, slave_id);
> +
> + if (!cfg)
> + return -ENODEV;
> + if (try)
> + return 0;
> +
> + auchan->config = cfg;
> +
> + return 0;
> +}
> +
> +static int audmapp_desc_setup(struct shdma_chan *schan,
> + struct shdma_desc *sdecs,
> + dma_addr_t src, dma_addr_t dst, size_t *len)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_slave_config *cfg = auchan->config;
> +
> + if (!cfg)
> + return -ENODEV;
> +
> + if (*len > schan->max_xfer_len)
> + *len = schan->max_xfer_len;
> +
> + return 0;
> +}
> +
> +static void audmapp_setup_xfer(struct shdma_chan *schan,
> + int slave_id)
> +{
> +}
> +
> +static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
> +{
> + return 0; /* always fixed address */
> +}
> +
> +static bool audmapp_channel_busy(struct shdma_chan *schan)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + u32 chcr = audmapp_read(auchan, PDMACHCR);
> +
> + return chcr & ~PDMACHCR_DE;
> +}
> +
> +static bool audmapp_desc_completed(struct shdma_chan *schan,
> + struct shdma_desc *sdesc)
> +{
> + return true;
> +}
> +
> +static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
> +{
> + return &((struct shdma_desc *)buf)[i];
> +}
> +
> +static const struct shdma_ops audmapp_shdma_ops = {
> + .halt_channel = audmapp_halt,
> + .desc_setup = audmapp_desc_setup,
> + .set_slave = audmapp_set_slave,
> + .start_xfer = audmapp_start_xfer,
> + .embedded_desc = audmapp_embedded_desc,
> + .setup_xfer = audmapp_setup_xfer,
> + .slave_addr = audmapp_slave_addr,
> + .channel_busy = audmapp_channel_busy,
> + .desc_completed = audmapp_desc_completed,
> +};
> +
> +static int audmapp_chan_probe(struct platform_device *pdev,
> + struct audmapp_device *audev, int id)
> +{
> + struct shdma_dev *sdev = &audev->shdma_dev;
> + struct audmapp_chan *auchan;
> + struct shdma_chan *schan;
> + struct device *dev = audev->dev;
> +
> + auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
> + if (!auchan) {
> + dev_err(dev, "No free memory for allocating dma channels!\n");
> + return -ENOMEM;
> + }
> +
> + schan = &auchan->shdma_chan;
> + schan->max_xfer_len = AUDMAPP_LEN_MAX;
> +
> + shdma_chan_probe(sdev, schan, id);
> +
> + auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
> + dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
> +
> + return 0;
> +}
> +
> +static void audmapp_chan_remove(struct audmapp_device *audev)
> +{
> + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> + struct shdma_chan *schan;
> + int i;
> +
> + shdma_for_each_chan(schan, &audev->shdma_dev, i) {
> + BUG_ON(!schan);
> + shdma_chan_remove(schan);
> + }
> + dma_dev->chancnt = 0;
> +}
> +
> +static int audmapp_probe(struct platform_device *pdev)
> +{
> + struct audmapp_pdata *pdata = pdev->dev.platform_data;
> + struct audmapp_device *audev;
> + struct shdma_dev *sdev;
> + struct dma_device *dma_dev;
> + struct resource *res;
> + int err, i;
> +
> + if (!pdata)
> + return -ENODEV;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
> + GFP_KERNEL);
> + if (!audev) {
> + dev_err(&pdev->dev, "Not enough memory\n");
> + return -ENOMEM;
> + }
> +
> + audev->dev = &pdev->dev;
> + audev->pdata = pdata;
> + audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(audev->chan_reg))
> + return PTR_ERR(audev->chan_reg);
> +
> + sdev = &audev->shdma_dev;
> + sdev->ops = &audmapp_shdma_ops;
> + sdev->desc_size = sizeof(struct shdma_desc);
> +
> + dma_dev = &sdev->dma_dev;
> + dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
> + dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
> +
> + err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
> + if (err < 0)
> + return err;
> +
> + platform_set_drvdata(pdev, audev);
> +
> + /* Create DMA Channel */
> + for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
> + err = audmapp_chan_probe(pdev, audev, i);
> + if (err)
> + goto chan_probe_err;
> + }
> +
> + err = dma_async_device_register(dma_dev);
> + if (err < 0)
> + goto chan_probe_err;
> +
> + return err;
> +
> +chan_probe_err:
> + audmapp_chan_remove(audev);
> + shdma_cleanup(sdev);
> +
> + return err;
> +}
> +
> +static int audmapp_remove(struct platform_device *pdev)
> +{
> + struct audmapp_device *audev = platform_get_drvdata(pdev);
> + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> +
> + dma_async_device_unregister(dma_dev);
> +
> + audmapp_chan_remove(audev);
> + shdma_cleanup(&audev->shdma_dev);
> +
> + return 0;
> +}
> +
> +static struct platform_driver audmapp_driver = {
> + .probe = audmapp_probe,
> + .remove = audmapp_remove,
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "rcar-audmapp-engine",
> + },
> +};
> +module_platform_driver(audmapp_driver);
> +
> +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
> +MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
> new file mode 100644
> index 0000000..346df66
> --- /dev/null
> +++ b/include/linux/platform_data/dma-rcar-audmapp.h
> @@ -0,0 +1,34 @@
> +/*
> + * include/linux/sh_audma-pp.h
> + * This file is header file for Audio-DMAC-pp peripheral.
> + *
> + * Copyright (C) 2013 Renesas Electronics Corporation
> + *
> + * This file is based on the include/linux/sh_dma.h
> + *
> + * Header for the new SH dmaengine driver
> + *
> + * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef SH_AUDMAPP_H
> +#define SH_AUDMAPP_H
> +
> +#include <linux/dmaengine.h>
> +
> +struct audmapp_slave_config {
> + int slave_id;
> + dma_addr_t src;
> + dma_addr_t dst;
> + u32 chcr;
> +};
> +
> +struct audmapp_pdata {
> + struct audmapp_slave_config *slave;
> + int slave_num;
> +};
> +
> +#endif /* SH_AUDMAPP_H */
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
2014-02-12 5:29 ` Kuninori Morimoto
@ 2014-02-25 5:13 ` Kuninori Morimoto
0 siblings, 0 replies; 17+ messages in thread
From: Kuninori Morimoto @ 2014-02-25 5:13 UTC (permalink / raw)
To: Kuninori Morimoto; +Cc: Vinod Koul, Morimoto, Linux-SH, linux-kernel
Hi Vinod, Linux-kernel ML
ping ?
> Can I ask you about current status of this patch ?
>
> > From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> >
> > Add support Audio DMAC peri peri driver
> > for Renesas R-Car Gen2 SoC, using 'shdma-base'
> > DMA driver framework.
> >
> > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> > ---
> > v1 -> v2
> >
> > - run scripts/checkpatch.pl
> > - ecchange length settings on audmapp_desc_setup()
> > - exchange slave_id check on audmapp_find_slave()
> >
> > drivers/dma/sh/Kconfig | 6 +
> > drivers/dma/sh/Makefile | 1 +
> > drivers/dma/sh/rcar-audmapp.c | 325 ++++++++++++++++++++++++
> > include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
> > 4 files changed, 366 insertions(+)
> > create mode 100644 drivers/dma/sh/rcar-audmapp.c
> > create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
> >
> > diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
> > index dadd9e01..b4c8138 100644
> > --- a/drivers/dma/sh/Kconfig
> > +++ b/drivers/dma/sh/Kconfig
> > @@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
> > help
> > Enable support for the Renesas R-Car series DMA controllers.
> >
> > +config RCAR_AUDMAC_PP
> > + tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
> > + depends on SH_DMAE_BASE
> > + help
> > + Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
> > --- a/drivers/dma/sh/Makefile
> > +++ b/drivers/dma/sh/Makefile
> > @@ -7,3 +7,4 @@ endif
> > shdma-objs := $(shdma-y)
> > obj-$(CONFIG_SUDMAC) += sudmac.o
> > obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
> > +obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
> > diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
> > new file mode 100644
> > index 0000000..cd3c237
> > --- /dev/null
> > +++ b/drivers/dma/sh/rcar-audmapp.c
> > @@ -0,0 +1,325 @@
> > +/*
> > + * drivers/dma/sh/rcar-audmapp.c
> > + *
> > + * Copyright (C) 2013 Renesas Electronics Corporation
> > + * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> > + *
> > + * based on the drivers/dma/sh/shdma.c
> > + *
> > + * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > + * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
> > + * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
> > + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
> > + *
> > + * This is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + */
> > +#include <linux/delay.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/platform_data/dma-rcar-audmapp.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/shdma-base.h>
> > +
> > +/*
> > + * DMA register
> > + */
> > +#define PDMASAR 0x00
> > +#define PDMADAR 0x04
> > +#define PDMACHCR 0x0c
> > +
> > +/* PDMACHCR */
> > +#define PDMACHCR_DE (1 << 0)
> > +
> > +#define AUDMAPP_MAX_CHANNELS 29
> > +
> > +/* Default MEMCPY transfer size = 2^2 = 4 bytes */
> > +#define LOG2_DEFAULT_XFER_SIZE 2
> > +#define AUDMAPP_SLAVE_NUMBER 256
> > +#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
> > +
> > +struct audmapp_chan {
> > + struct shdma_chan shdma_chan;
> > + struct audmapp_slave_config *config;
> > + void __iomem *base;
> > +};
> > +
> > +struct audmapp_device {
> > + struct shdma_dev shdma_dev;
> > + struct audmapp_pdata *pdata;
> > + struct device *dev;
> > + void __iomem *chan_reg;
> > +};
> > +
> > +#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
> > +#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
> > + struct audmapp_device, shdma_dev.dma_dev)
> > +
> > +static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
> > +{
> > + struct audmapp_device *audev = to_dev(auchan);
> > + struct device *dev = audev->dev;
> > +
> > + dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
> > +
> > + iowrite32(data, auchan->base + reg);
> > +}
> > +
> > +static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
> > +{
> > + return ioread32(auchan->base + reg);
> > +}
> > +
> > +static void audmapp_halt(struct shdma_chan *schan)
> > +{
> > + struct audmapp_chan *auchan = to_chan(schan);
> > + int i;
> > +
> > + audmapp_write(auchan, 0, PDMACHCR);
> > +
> > + for (i = 0; i < 1024; i++) {
> > + if (0 == audmapp_read(auchan, PDMACHCR))
> > + return;
> > + udelay(1);
> > + }
> > +}
> > +
> > +static void audmapp_start_xfer(struct shdma_chan *schan,
> > + struct shdma_desc *sdecs)
> > +{
> > + struct audmapp_chan *auchan = to_chan(schan);
> > + struct audmapp_device *audev = to_dev(auchan);
> > + struct audmapp_slave_config *cfg = auchan->config;
> > + struct device *dev = audev->dev;
> > + u32 chcr = cfg->chcr | PDMACHCR_DE;
> > +
> > + dev_dbg(dev, "src/dst/chcr = %x/%x/%x\n",
> > + cfg->src, cfg->dst, cfg->chcr);
> > +
> > + audmapp_write(auchan, cfg->src, PDMASAR);
> > + audmapp_write(auchan, cfg->dst, PDMADAR);
> > + audmapp_write(auchan, chcr, PDMACHCR);
> > +}
> > +
> > +static struct audmapp_slave_config *
> > +audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
> > +{
> > + struct audmapp_device *audev = to_dev(auchan);
> > + struct audmapp_pdata *pdata = audev->pdata;
> > + struct audmapp_slave_config *cfg;
> > + int i;
> > +
> > + if (slave_id < 0 || slave_id >= AUDMAPP_SLAVE_NUMBER)
> > + return NULL;
> > +
> > + for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
> > + if (cfg->slave_id == slave_id)
> > + return cfg;
> > +
> > + return NULL;
> > +}
> > +
> > +static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
> > + dma_addr_t slave_addr, bool try)
> > +{
> > + struct audmapp_chan *auchan = to_chan(schan);
> > + struct audmapp_slave_config *cfg =
> > + audmapp_find_slave(auchan, slave_id);
> > +
> > + if (!cfg)
> > + return -ENODEV;
> > + if (try)
> > + return 0;
> > +
> > + auchan->config = cfg;
> > +
> > + return 0;
> > +}
> > +
> > +static int audmapp_desc_setup(struct shdma_chan *schan,
> > + struct shdma_desc *sdecs,
> > + dma_addr_t src, dma_addr_t dst, size_t *len)
> > +{
> > + struct audmapp_chan *auchan = to_chan(schan);
> > + struct audmapp_slave_config *cfg = auchan->config;
> > +
> > + if (!cfg)
> > + return -ENODEV;
> > +
> > + if (*len > schan->max_xfer_len)
> > + *len = schan->max_xfer_len;
> > +
> > + return 0;
> > +}
> > +
> > +static void audmapp_setup_xfer(struct shdma_chan *schan,
> > + int slave_id)
> > +{
> > +}
> > +
> > +static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
> > +{
> > + return 0; /* always fixed address */
> > +}
> > +
> > +static bool audmapp_channel_busy(struct shdma_chan *schan)
> > +{
> > + struct audmapp_chan *auchan = to_chan(schan);
> > + u32 chcr = audmapp_read(auchan, PDMACHCR);
> > +
> > + return chcr & ~PDMACHCR_DE;
> > +}
> > +
> > +static bool audmapp_desc_completed(struct shdma_chan *schan,
> > + struct shdma_desc *sdesc)
> > +{
> > + return true;
> > +}
> > +
> > +static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
> > +{
> > + return &((struct shdma_desc *)buf)[i];
> > +}
> > +
> > +static const struct shdma_ops audmapp_shdma_ops = {
> > + .halt_channel = audmapp_halt,
> > + .desc_setup = audmapp_desc_setup,
> > + .set_slave = audmapp_set_slave,
> > + .start_xfer = audmapp_start_xfer,
> > + .embedded_desc = audmapp_embedded_desc,
> > + .setup_xfer = audmapp_setup_xfer,
> > + .slave_addr = audmapp_slave_addr,
> > + .channel_busy = audmapp_channel_busy,
> > + .desc_completed = audmapp_desc_completed,
> > +};
> > +
> > +static int audmapp_chan_probe(struct platform_device *pdev,
> > + struct audmapp_device *audev, int id)
> > +{
> > + struct shdma_dev *sdev = &audev->shdma_dev;
> > + struct audmapp_chan *auchan;
> > + struct shdma_chan *schan;
> > + struct device *dev = audev->dev;
> > +
> > + auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
> > + if (!auchan) {
> > + dev_err(dev, "No free memory for allocating dma channels!\n");
> > + return -ENOMEM;
> > + }
> > +
> > + schan = &auchan->shdma_chan;
> > + schan->max_xfer_len = AUDMAPP_LEN_MAX;
> > +
> > + shdma_chan_probe(sdev, schan, id);
> > +
> > + auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
> > + dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
> > +
> > + return 0;
> > +}
> > +
> > +static void audmapp_chan_remove(struct audmapp_device *audev)
> > +{
> > + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> > + struct shdma_chan *schan;
> > + int i;
> > +
> > + shdma_for_each_chan(schan, &audev->shdma_dev, i) {
> > + BUG_ON(!schan);
> > + shdma_chan_remove(schan);
> > + }
> > + dma_dev->chancnt = 0;
> > +}
> > +
> > +static int audmapp_probe(struct platform_device *pdev)
> > +{
> > + struct audmapp_pdata *pdata = pdev->dev.platform_data;
> > + struct audmapp_device *audev;
> > + struct shdma_dev *sdev;
> > + struct dma_device *dma_dev;
> > + struct resource *res;
> > + int err, i;
> > +
> > + if (!pdata)
> > + return -ENODEV;
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +
> > + audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
> > + GFP_KERNEL);
> > + if (!audev) {
> > + dev_err(&pdev->dev, "Not enough memory\n");
> > + return -ENOMEM;
> > + }
> > +
> > + audev->dev = &pdev->dev;
> > + audev->pdata = pdata;
> > + audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
> > + if (IS_ERR(audev->chan_reg))
> > + return PTR_ERR(audev->chan_reg);
> > +
> > + sdev = &audev->shdma_dev;
> > + sdev->ops = &audmapp_shdma_ops;
> > + sdev->desc_size = sizeof(struct shdma_desc);
> > +
> > + dma_dev = &sdev->dma_dev;
> > + dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
> > + dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
> > +
> > + err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
> > + if (err < 0)
> > + return err;
> > +
> > + platform_set_drvdata(pdev, audev);
> > +
> > + /* Create DMA Channel */
> > + for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
> > + err = audmapp_chan_probe(pdev, audev, i);
> > + if (err)
> > + goto chan_probe_err;
> > + }
> > +
> > + err = dma_async_device_register(dma_dev);
> > + if (err < 0)
> > + goto chan_probe_err;
> > +
> > + return err;
> > +
> > +chan_probe_err:
> > + audmapp_chan_remove(audev);
> > + shdma_cleanup(sdev);
> > +
> > + return err;
> > +}
> > +
> > +static int audmapp_remove(struct platform_device *pdev)
> > +{
> > + struct audmapp_device *audev = platform_get_drvdata(pdev);
> > + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> > +
> > + dma_async_device_unregister(dma_dev);
> > +
> > + audmapp_chan_remove(audev);
> > + shdma_cleanup(&audev->shdma_dev);
> > +
> > + return 0;
> > +}
> > +
> > +static struct platform_driver audmapp_driver = {
> > + .probe = audmapp_probe,
> > + .remove = audmapp_remove,
> > + .driver = {
> > + .owner = THIS_MODULE,
> > + .name = "rcar-audmapp-engine",
> > + },
> > +};
> > +module_platform_driver(audmapp_driver);
> > +
> > +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
> > +MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
> > new file mode 100644
> > index 0000000..346df66
> > --- /dev/null
> > +++ b/include/linux/platform_data/dma-rcar-audmapp.h
> > @@ -0,0 +1,34 @@
> > +/*
> > + * include/linux/sh_audma-pp.h
> > + * This file is header file for Audio-DMAC-pp peripheral.
> > + *
> > + * Copyright (C) 2013 Renesas Electronics Corporation
> > + *
> > + * This file is based on the include/linux/sh_dma.h
> > + *
> > + * Header for the new SH dmaengine driver
> > + *
> > + * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +#ifndef SH_AUDMAPP_H
> > +#define SH_AUDMAPP_H
> > +
> > +#include <linux/dmaengine.h>
> > +
> > +struct audmapp_slave_config {
> > + int slave_id;
> > + dma_addr_t src;
> > + dma_addr_t dst;
> > + u32 chcr;
> > +};
> > +
> > +struct audmapp_pdata {
> > + struct audmapp_slave_config *slave;
> > + int slave_num;
> > +};
> > +
> > +#endif /* SH_AUDMAPP_H */
> > --
> > 1.7.9.5
> >
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
2014-01-24 2:32 [PATCH] shdma: add R-Car Audio DMAC peri peri driver Kuninori Morimoto
2014-01-24 7:34 ` Geert Uytterhoeven
2014-01-24 9:06 ` [PATCH v2] dma: " Kuninori Morimoto
@ 2014-03-10 1:34 ` Kuninori Morimoto
2014-03-10 1:47 ` Joe Perches
2014-03-10 9:13 ` Shevchenko, Andriy
2014-03-10 2:25 ` [PATCH v3] shdma: " Kuninori Morimoto
2014-03-11 1:11 ` Kuninori Morimoto
4 siblings, 2 replies; 17+ messages in thread
From: Kuninori Morimoto @ 2014-03-10 1:34 UTC (permalink / raw)
To: Vinod Koul
Cc: Morimoto, Linux-SH, linux-kernel, Geert Uytterhoeven, dmaengine
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Add support Audio DMAC peri peri driver
for Renesas R-Car Gen2 SoC, using 'shdma-base'
DMA driver framework.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
resent
- add missing "dmaengine@vger.kernel.org"
v1 -> v2
- run scripts/checkpatch.pl
- ecchange length settings on audmapp_desc_setup()
- exchange slave_id check on audmapp_find_slave()
drivers/dma/sh/Kconfig | 6 +
drivers/dma/sh/Makefile | 1 +
drivers/dma/sh/rcar-audmapp.c | 325 ++++++++++++++++++++++++
include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
4 files changed, 366 insertions(+)
create mode 100644 drivers/dma/sh/rcar-audmapp.c
create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index dadd9e01..b4c8138 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
help
Enable support for the Renesas R-Car series DMA controllers.
+config RCAR_AUDMAC_PP
+ tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
+ depends on SH_DMAE_BASE
+ help
+ Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -7,3 +7,4 @@ endif
shdma-objs := $(shdma-y)
obj-$(CONFIG_SUDMAC) += sudmac.o
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
+obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
new file mode 100644
index 0000000..cd3c237
--- /dev/null
+++ b/drivers/dma/sh/rcar-audmapp.c
@@ -0,0 +1,325 @@
+/*
+ * drivers/dma/sh/rcar-audmapp.c
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on the drivers/dma/sh/shdma.c
+ *
+ * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+ * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/dma-rcar-audmapp.h>
+#include <linux/platform_device.h>
+#include <linux/shdma-base.h>
+
+/*
+ * DMA register
+ */
+#define PDMASAR 0x00
+#define PDMADAR 0x04
+#define PDMACHCR 0x0c
+
+/* PDMACHCR */
+#define PDMACHCR_DE (1 << 0)
+
+#define AUDMAPP_MAX_CHANNELS 29
+
+/* Default MEMCPY transfer size = 2^2 = 4 bytes */
+#define LOG2_DEFAULT_XFER_SIZE 2
+#define AUDMAPP_SLAVE_NUMBER 256
+#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
+
+struct audmapp_chan {
+ struct shdma_chan shdma_chan;
+ struct audmapp_slave_config *config;
+ void __iomem *base;
+};
+
+struct audmapp_device {
+ struct shdma_dev shdma_dev;
+ struct audmapp_pdata *pdata;
+ struct device *dev;
+ void __iomem *chan_reg;
+};
+
+#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
+#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
+ struct audmapp_device, shdma_dev.dma_dev)
+
+static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct device *dev = audev->dev;
+
+ dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
+
+ iowrite32(data, auchan->base + reg);
+}
+
+static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
+{
+ return ioread32(auchan->base + reg);
+}
+
+static void audmapp_halt(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ int i;
+
+ audmapp_write(auchan, 0, PDMACHCR);
+
+ for (i = 0; i < 1024; i++) {
+ if (0 == audmapp_read(auchan, PDMACHCR))
+ return;
+ udelay(1);
+ }
+}
+
+static void audmapp_start_xfer(struct shdma_chan *schan,
+ struct shdma_desc *sdecs)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_slave_config *cfg = auchan->config;
+ struct device *dev = audev->dev;
+ u32 chcr = cfg->chcr | PDMACHCR_DE;
+
+ dev_dbg(dev, "src/dst/chcr = %x/%x/%x\n",
+ cfg->src, cfg->dst, cfg->chcr);
+
+ audmapp_write(auchan, cfg->src, PDMASAR);
+ audmapp_write(auchan, cfg->dst, PDMADAR);
+ audmapp_write(auchan, chcr, PDMACHCR);
+}
+
+static struct audmapp_slave_config *
+audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_pdata *pdata = audev->pdata;
+ struct audmapp_slave_config *cfg;
+ int i;
+
+ if (slave_id < 0 || slave_id >= AUDMAPP_SLAVE_NUMBER)
+ return NULL;
+
+ for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+ if (cfg->slave_id == slave_id)
+ return cfg;
+
+ return NULL;
+}
+
+static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
+ dma_addr_t slave_addr, bool try)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg =
+ audmapp_find_slave(auchan, slave_id);
+
+ if (!cfg)
+ return -ENODEV;
+ if (try)
+ return 0;
+
+ auchan->config = cfg;
+
+ return 0;
+}
+
+static int audmapp_desc_setup(struct shdma_chan *schan,
+ struct shdma_desc *sdecs,
+ dma_addr_t src, dma_addr_t dst, size_t *len)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg = auchan->config;
+
+ if (!cfg)
+ return -ENODEV;
+
+ if (*len > schan->max_xfer_len)
+ *len = schan->max_xfer_len;
+
+ return 0;
+}
+
+static void audmapp_setup_xfer(struct shdma_chan *schan,
+ int slave_id)
+{
+}
+
+static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
+{
+ return 0; /* always fixed address */
+}
+
+static bool audmapp_channel_busy(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ u32 chcr = audmapp_read(auchan, PDMACHCR);
+
+ return chcr & ~PDMACHCR_DE;
+}
+
+static bool audmapp_desc_completed(struct shdma_chan *schan,
+ struct shdma_desc *sdesc)
+{
+ return true;
+}
+
+static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
+{
+ return &((struct shdma_desc *)buf)[i];
+}
+
+static const struct shdma_ops audmapp_shdma_ops = {
+ .halt_channel = audmapp_halt,
+ .desc_setup = audmapp_desc_setup,
+ .set_slave = audmapp_set_slave,
+ .start_xfer = audmapp_start_xfer,
+ .embedded_desc = audmapp_embedded_desc,
+ .setup_xfer = audmapp_setup_xfer,
+ .slave_addr = audmapp_slave_addr,
+ .channel_busy = audmapp_channel_busy,
+ .desc_completed = audmapp_desc_completed,
+};
+
+static int audmapp_chan_probe(struct platform_device *pdev,
+ struct audmapp_device *audev, int id)
+{
+ struct shdma_dev *sdev = &audev->shdma_dev;
+ struct audmapp_chan *auchan;
+ struct shdma_chan *schan;
+ struct device *dev = audev->dev;
+
+ auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
+ if (!auchan) {
+ dev_err(dev, "No free memory for allocating dma channels!\n");
+ return -ENOMEM;
+ }
+
+ schan = &auchan->shdma_chan;
+ schan->max_xfer_len = AUDMAPP_LEN_MAX;
+
+ shdma_chan_probe(sdev, schan, id);
+
+ auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
+ dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
+
+ return 0;
+}
+
+static void audmapp_chan_remove(struct audmapp_device *audev)
+{
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+ struct shdma_chan *schan;
+ int i;
+
+ shdma_for_each_chan(schan, &audev->shdma_dev, i) {
+ BUG_ON(!schan);
+ shdma_chan_remove(schan);
+ }
+ dma_dev->chancnt = 0;
+}
+
+static int audmapp_probe(struct platform_device *pdev)
+{
+ struct audmapp_pdata *pdata = pdev->dev.platform_data;
+ struct audmapp_device *audev;
+ struct shdma_dev *sdev;
+ struct dma_device *dma_dev;
+ struct resource *res;
+ int err, i;
+
+ if (!pdata)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
+ GFP_KERNEL);
+ if (!audev) {
+ dev_err(&pdev->dev, "Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ audev->dev = &pdev->dev;
+ audev->pdata = pdata;
+ audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(audev->chan_reg))
+ return PTR_ERR(audev->chan_reg);
+
+ sdev = &audev->shdma_dev;
+ sdev->ops = &audmapp_shdma_ops;
+ sdev->desc_size = sizeof(struct shdma_desc);
+
+ dma_dev = &sdev->dma_dev;
+ dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
+ dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+
+ err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
+ if (err < 0)
+ return err;
+
+ platform_set_drvdata(pdev, audev);
+
+ /* Create DMA Channel */
+ for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
+ err = audmapp_chan_probe(pdev, audev, i);
+ if (err)
+ goto chan_probe_err;
+ }
+
+ err = dma_async_device_register(dma_dev);
+ if (err < 0)
+ goto chan_probe_err;
+
+ return err;
+
+chan_probe_err:
+ audmapp_chan_remove(audev);
+ shdma_cleanup(sdev);
+
+ return err;
+}
+
+static int audmapp_remove(struct platform_device *pdev)
+{
+ struct audmapp_device *audev = platform_get_drvdata(pdev);
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+
+ dma_async_device_unregister(dma_dev);
+
+ audmapp_chan_remove(audev);
+ shdma_cleanup(&audev->shdma_dev);
+
+ return 0;
+}
+
+static struct platform_driver audmapp_driver = {
+ .probe = audmapp_probe,
+ .remove = audmapp_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rcar-audmapp-engine",
+ },
+};
+module_platform_driver(audmapp_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
new file mode 100644
index 0000000..346df66
--- /dev/null
+++ b/include/linux/platform_data/dma-rcar-audmapp.h
@@ -0,0 +1,34 @@
+/*
+ * include/linux/sh_audma-pp.h
+ * This file is header file for Audio-DMAC-pp peripheral.
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ *
+ * This file is based on the include/linux/sh_dma.h
+ *
+ * Header for the new SH dmaengine driver
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef SH_AUDMAPP_H
+#define SH_AUDMAPP_H
+
+#include <linux/dmaengine.h>
+
+struct audmapp_slave_config {
+ int slave_id;
+ dma_addr_t src;
+ dma_addr_t dst;
+ u32 chcr;
+};
+
+struct audmapp_pdata {
+ struct audmapp_slave_config *slave;
+ int slave_num;
+};
+
+#endif /* SH_AUDMAPP_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
2014-03-10 1:34 ` [PATCH v2][RESENT] " Kuninori Morimoto
@ 2014-03-10 1:47 ` Joe Perches
2014-03-10 2:19 ` Kuninori Morimoto
2014-03-10 9:13 ` Shevchenko, Andriy
1 sibling, 1 reply; 17+ messages in thread
From: Joe Perches @ 2014-03-10 1:47 UTC (permalink / raw)
To: Kuninori Morimoto
Cc: Vinod Koul, Morimoto, Linux-SH, linux-kernel, Geert Uytterhoeven,
dmaengine
On Sun, 2014-03-09 at 18:34 -0700, Kuninori Morimoto wrote:
> Add support Audio DMAC peri peri driver
> for Renesas R-Car Gen2 SoC, using 'shdma-base'
> DMA driver framework.
Trivial notes:
> diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
[]
> +static int audmapp_chan_probe(struct platform_device *pdev,
> + struct audmapp_device *audev, int id)
> +{
[]
> + auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
> + if (!auchan) {
> + dev_err(dev, "No free memory for allocating dma channels!\n");
Unnecessary OOM as the alloc has a generic OOM
and a dump_stack()
[]
> +static int audmapp_probe(struct platform_device *pdev)
> +{
[]
> + audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
> + GFP_KERNEL);
> + if (!audev) {
> + dev_err(&pdev->dev, "Not enough memory\n");
here too
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
2014-03-10 1:47 ` Joe Perches
@ 2014-03-10 2:19 ` Kuninori Morimoto
0 siblings, 0 replies; 17+ messages in thread
From: Kuninori Morimoto @ 2014-03-10 2:19 UTC (permalink / raw)
To: Joe Perches
Cc: Vinod Koul, Morimoto, Linux-SH, linux-kernel, Geert Uytterhoeven,
dmaengine
Hi Joe
> > diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
> []
> > +static int audmapp_chan_probe(struct platform_device *pdev,
> > + struct audmapp_device *audev, int id)
> > +{
> []
> > + auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
> > + if (!auchan) {
> > + dev_err(dev, "No free memory for allocating dma channels!\n");
>
> Unnecessary OOM as the alloc has a generic OOM
> and a dump_stack()
>
> []
> > +static int audmapp_probe(struct platform_device *pdev)
> > +{
> []
> > + audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
> > + GFP_KERNEL);
> > + if (!audev) {
> > + dev_err(&pdev->dev, "Not enough memory\n");
>
> here too
Thank you.
will fix in v3
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
2014-03-10 1:34 ` [PATCH v2][RESENT] " Kuninori Morimoto
2014-03-10 1:47 ` Joe Perches
@ 2014-03-10 9:13 ` Shevchenko, Andriy
1 sibling, 0 replies; 17+ messages in thread
From: Shevchenko, Andriy @ 2014-03-10 9:13 UTC (permalink / raw)
To: Kuninori Morimoto
Cc: Koul, Vinod, Morimoto, Linux-SH, linux-kernel@vger.kernel.org,
Geert Uytterhoeven, dmaengine@vger.kernel.org
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 12974 bytes --]
On Sun, 2014-03-09 at 18:34 -0700, Kuninori Morimoto wrote:
> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
>
> Add support Audio DMAC peri peri driver
> for Renesas R-Car Gen2 SoC, using 'shdma-base'
> DMA driver framework.
Few comments below.
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
> resent
>
> - add missing "dmaengine@vger.kernel.org"
>
> v1 -> v2
>
> - run scripts/checkpatch.pl
> - ecchange length settings on audmapp_desc_setup()
> - exchange slave_id check on audmapp_find_slave()
>
> drivers/dma/sh/Kconfig | 6 +
> drivers/dma/sh/Makefile | 1 +
> drivers/dma/sh/rcar-audmapp.c | 325 ++++++++++++++++++++++++
> include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
> 4 files changed, 366 insertions(+)
> create mode 100644 drivers/dma/sh/rcar-audmapp.c
> create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
>
> diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
> index dadd9e01..b4c8138 100644
> --- a/drivers/dma/sh/Kconfig
> +++ b/drivers/dma/sh/Kconfig
> @@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
> help
> Enable support for the Renesas R-Car series DMA controllers.
>
> +config RCAR_AUDMAC_PP
> + tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
> + depends on SH_DMAE_BASE
> + help
> + Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
> --- a/drivers/dma/sh/Makefile
> +++ b/drivers/dma/sh/Makefile
> @@ -7,3 +7,4 @@ endif
> shdma-objs := $(shdma-y)
> obj-$(CONFIG_SUDMAC) += sudmac.o
> obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
> +obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
> diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
> new file mode 100644
> index 0000000..cd3c237
> --- /dev/null
> +++ b/drivers/dma/sh/rcar-audmapp.c
> @@ -0,0 +1,325 @@
> +/*
> + * drivers/dma/sh/rcar-audmapp.c
> + *
> + * Copyright (C) 2013 Renesas Electronics Corporation
> + * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
2014?
> + *
> + * based on the drivers/dma/sh/shdma.c
> + *
> + * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
> + * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
> + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * This is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/dmaengine.h>
> +#include <linux/platform_data/dma-rcar-audmapp.h>
> +#include <linux/platform_device.h>
> +#include <linux/shdma-base.h>
> +
> +/*
> + * DMA register
> + */
> +#define PDMASAR 0x00
> +#define PDMADAR 0x04
> +#define PDMACHCR 0x0c
> +
> +/* PDMACHCR */
> +#define PDMACHCR_DE (1 << 0)
> +
> +#define AUDMAPP_MAX_CHANNELS 29
> +
> +/* Default MEMCPY transfer size = 2^2 = 4 bytes */
> +#define LOG2_DEFAULT_XFER_SIZE 2
> +#define AUDMAPP_SLAVE_NUMBER 256
> +#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
> +
> +struct audmapp_chan {
> + struct shdma_chan shdma_chan;
> + struct audmapp_slave_config *config;
> + void __iomem *base;
> +};
> +
> +struct audmapp_device {
> + struct shdma_dev shdma_dev;
> + struct audmapp_pdata *pdata;
> + struct device *dev;
> + void __iomem *chan_reg;
> +};
> +
> +#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
> +#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
> + struct audmapp_device, shdma_dev.dma_dev)
> +
> +static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
> +{
> + struct audmapp_device *audev = to_dev(auchan);
> + struct device *dev = audev->dev;
> +
> + dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
> +
> + iowrite32(data, auchan->base + reg);
> +}
> +
> +static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
> +{
> + return ioread32(auchan->base + reg);
> +}
> +
> +static void audmapp_halt(struct shdma_chan *schan)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + int i;
> +
> + audmapp_write(auchan, 0, PDMACHCR);
> +
> + for (i = 0; i < 1024; i++) {
> + if (0 == audmapp_read(auchan, PDMACHCR))
> + return;
> + udelay(1);
> + }
> +}
> +
> +static void audmapp_start_xfer(struct shdma_chan *schan,
> + struct shdma_desc *sdecs)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_device *audev = to_dev(auchan);
> + struct audmapp_slave_config *cfg = auchan->config;
> + struct device *dev = audev->dev;
> + u32 chcr = cfg->chcr | PDMACHCR_DE;
> +
> + dev_dbg(dev, "src/dst/chcr = %x/%x/%x\n",
%pad for src/dst.
> + cfg->src, cfg->dst, cfg->chcr);
> +
> + audmapp_write(auchan, cfg->src, PDMASAR);
> + audmapp_write(auchan, cfg->dst, PDMADAR);
> + audmapp_write(auchan, chcr, PDMACHCR);
> +}
> +
> +static struct audmapp_slave_config *
> +audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
> +{
> + struct audmapp_device *audev = to_dev(auchan);
> + struct audmapp_pdata *pdata = audev->pdata;
> + struct audmapp_slave_config *cfg;
> + int i;
> +
> + if (slave_id < 0 || slave_id >= AUDMAPP_SLAVE_NUMBER)
> + return NULL;
> +
> + for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
> + if (cfg->slave_id == slave_id)
> + return cfg;
> +
> + return NULL;
> +}
> +
> +static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
> + dma_addr_t slave_addr, bool try)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_slave_config *cfg =
> + audmapp_find_slave(auchan, slave_id);
> +
> + if (!cfg)
> + return -ENODEV;
> + if (try)
> + return 0;
> +
> + auchan->config = cfg;
> +
> + return 0;
> +}
> +
> +static int audmapp_desc_setup(struct shdma_chan *schan,
> + struct shdma_desc *sdecs,
> + dma_addr_t src, dma_addr_t dst, size_t *len)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_slave_config *cfg = auchan->config;
> +
> + if (!cfg)
> + return -ENODEV;
> +
> + if (*len > schan->max_xfer_len)
> + *len = schan->max_xfer_len;
> +
> + return 0;
> +}
> +
> +static void audmapp_setup_xfer(struct shdma_chan *schan,
> + int slave_id)
> +{
> +}
> +
> +static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
> +{
> + return 0; /* always fixed address */
> +}
> +
> +static bool audmapp_channel_busy(struct shdma_chan *schan)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + u32 chcr = audmapp_read(auchan, PDMACHCR);
> +
> + return chcr & ~PDMACHCR_DE;
> +}
> +
> +static bool audmapp_desc_completed(struct shdma_chan *schan,
> + struct shdma_desc *sdesc)
> +{
> + return true;
> +}
> +
> +static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
> +{
> + return &((struct shdma_desc *)buf)[i];
> +}
> +
> +static const struct shdma_ops audmapp_shdma_ops = {
> + .halt_channel = audmapp_halt,
> + .desc_setup = audmapp_desc_setup,
> + .set_slave = audmapp_set_slave,
> + .start_xfer = audmapp_start_xfer,
> + .embedded_desc = audmapp_embedded_desc,
> + .setup_xfer = audmapp_setup_xfer,
> + .slave_addr = audmapp_slave_addr,
> + .channel_busy = audmapp_channel_busy,
> + .desc_completed = audmapp_desc_completed,
> +};
> +
> +static int audmapp_chan_probe(struct platform_device *pdev,
> + struct audmapp_device *audev, int id)
> +{
> + struct shdma_dev *sdev = &audev->shdma_dev;
> + struct audmapp_chan *auchan;
> + struct shdma_chan *schan;
> + struct device *dev = audev->dev;
> +
> + auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
sizeof(*auchan)
> + if (!auchan) {
> + dev_err(dev, "No free memory for allocating dma channels!\n");
> + return -ENOMEM;
> + }
> +
> + schan = &auchan->shdma_chan;
> + schan->max_xfer_len = AUDMAPP_LEN_MAX;
> +
> + shdma_chan_probe(sdev, schan, id);
> +
> + auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
> + dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
> +
> + return 0;
> +}
> +
> +static void audmapp_chan_remove(struct audmapp_device *audev)
> +{
> + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> + struct shdma_chan *schan;
> + int i;
> +
> + shdma_for_each_chan(schan, &audev->shdma_dev, i) {
> + BUG_ON(!schan);
> + shdma_chan_remove(schan);
> + }
> + dma_dev->chancnt = 0;
> +}
> +
> +static int audmapp_probe(struct platform_device *pdev)
> +{
> + struct audmapp_pdata *pdata = pdev->dev.platform_data;
> + struct audmapp_device *audev;
> + struct shdma_dev *sdev;
> + struct dma_device *dma_dev;
> + struct resource *res;
> + int err, i;
> +
> + if (!pdata)
> + return -ENODEV;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
> + GFP_KERNEL);
sizeof(*audev)
> + if (!audev) {
> + dev_err(&pdev->dev, "Not enough memory\n");
> + return -ENOMEM;
> + }
> +
> + audev->dev = &pdev->dev;
> + audev->pdata = pdata;
> + audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(audev->chan_reg))
> + return PTR_ERR(audev->chan_reg);
> +
> + sdev = &audev->shdma_dev;
> + sdev->ops = &audmapp_shdma_ops;
> + sdev->desc_size = sizeof(struct shdma_desc);
> +
> + dma_dev = &sdev->dma_dev;
> + dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
> + dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
> +
> + err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
> + if (err < 0)
> + return err;
> +
> + platform_set_drvdata(pdev, audev);
> +
> + /* Create DMA Channel */
> + for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
> + err = audmapp_chan_probe(pdev, audev, i);
> + if (err)
> + goto chan_probe_err;
> + }
> +
> + err = dma_async_device_register(dma_dev);
> + if (err < 0)
> + goto chan_probe_err;
> +
> + return err;
> +
> +chan_probe_err:
> + audmapp_chan_remove(audev);
> + shdma_cleanup(sdev);
> +
> + return err;
> +}
> +
> +static int audmapp_remove(struct platform_device *pdev)
> +{
> + struct audmapp_device *audev = platform_get_drvdata(pdev);
> + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> +
> + dma_async_device_unregister(dma_dev);
> +
> + audmapp_chan_remove(audev);
> + shdma_cleanup(&audev->shdma_dev);
> +
> + return 0;
> +}
> +
> +static struct platform_driver audmapp_driver = {
> + .probe = audmapp_probe,
> + .remove = audmapp_remove,
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "rcar-audmapp-engine",
> + },
> +};
> +module_platform_driver(audmapp_driver);
> +
> +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
> +MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
> new file mode 100644
> index 0000000..346df66
> --- /dev/null
> +++ b/include/linux/platform_data/dma-rcar-audmapp.h
> @@ -0,0 +1,34 @@
> +/*
> + * include/linux/sh_audma-pp.h
> + * This file is header file for Audio-DMAC-pp peripheral.
> + *
> + * Copyright (C) 2013 Renesas Electronics Corporation
2014?
> + *
> + * This file is based on the include/linux/sh_dma.h
> + *
> + * Header for the new SH dmaengine driver
> + *
> + * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef SH_AUDMAPP_H
> +#define SH_AUDMAPP_H
> +
> +#include <linux/dmaengine.h>
> +
> +struct audmapp_slave_config {
> + int slave_id;
> + dma_addr_t src;
> + dma_addr_t dst;
> + u32 chcr;
> +};
> +
> +struct audmapp_pdata {
> + struct audmapp_slave_config *slave;
> + int slave_num;
> +};
> +
> +#endif /* SH_AUDMAPP_H */
--
Andy Shevchenko <andriy.shevchenko@intel.com>
Intel Finland Oy
---------------------------------------------------------------------
Intel Finland Oy
Registered Address: PL 281, 00181 Helsinki
Business Identity Code: 0357606 - 4
Domiciled in Helsinki
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
ÿôèº{.nÇ+·®+%Ëÿ±éݶ\x17¥wÿº{.nÇ+·¥{±þG«éÿ{ayº\x1dÊÚë,j\a¢f£¢·hïêÿêçz_è®\x03(éÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?¨èÚ&£ø§~á¶iOæ¬z·vØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?I¥
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
2014-01-24 2:32 [PATCH] shdma: add R-Car Audio DMAC peri peri driver Kuninori Morimoto
` (2 preceding siblings ...)
2014-03-10 1:34 ` [PATCH v2][RESENT] " Kuninori Morimoto
@ 2014-03-10 2:25 ` Kuninori Morimoto
2014-03-10 9:15 ` Shevchenko, Andriy
2014-03-11 1:11 ` Kuninori Morimoto
4 siblings, 1 reply; 17+ messages in thread
From: Kuninori Morimoto @ 2014-03-10 2:25 UTC (permalink / raw)
To: Vinod Koul
Cc: Morimoto, Linux-SH, linux-kernel, Geert Uytterhoeven, dmaengine
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Add support Audio DMAC peri peri driver
for Renesas R-Car Gen2 SoC, using 'shdma-base'
DMA driver framework.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3
- remove error message when devm_kzalloc() was failed
drivers/dma/sh/Kconfig | 6 +
drivers/dma/sh/Makefile | 1 +
drivers/dma/sh/rcar-audmapp.c | 321 ++++++++++++++++++++++++
include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
4 files changed, 362 insertions(+)
create mode 100644 drivers/dma/sh/rcar-audmapp.c
create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index dadd9e01..b4c8138 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
help
Enable support for the Renesas R-Car series DMA controllers.
+config RCAR_AUDMAC_PP
+ tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
+ depends on SH_DMAE_BASE
+ help
+ Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -7,3 +7,4 @@ endif
shdma-objs := $(shdma-y)
obj-$(CONFIG_SUDMAC) += sudmac.o
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
+obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
new file mode 100644
index 0000000..884ad3b80
--- /dev/null
+++ b/drivers/dma/sh/rcar-audmapp.c
@@ -0,0 +1,321 @@
+/*
+ * drivers/dma/sh/rcar-audmapp.c
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on the drivers/dma/sh/shdma.c
+ *
+ * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+ * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/dma-rcar-audmapp.h>
+#include <linux/platform_device.h>
+#include <linux/shdma-base.h>
+
+/*
+ * DMA register
+ */
+#define PDMASAR 0x00
+#define PDMADAR 0x04
+#define PDMACHCR 0x0c
+
+/* PDMACHCR */
+#define PDMACHCR_DE (1 << 0)
+
+#define AUDMAPP_MAX_CHANNELS 29
+
+/* Default MEMCPY transfer size = 2^2 = 4 bytes */
+#define LOG2_DEFAULT_XFER_SIZE 2
+#define AUDMAPP_SLAVE_NUMBER 256
+#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
+
+struct audmapp_chan {
+ struct shdma_chan shdma_chan;
+ struct audmapp_slave_config *config;
+ void __iomem *base;
+};
+
+struct audmapp_device {
+ struct shdma_dev shdma_dev;
+ struct audmapp_pdata *pdata;
+ struct device *dev;
+ void __iomem *chan_reg;
+};
+
+#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
+#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
+ struct audmapp_device, shdma_dev.dma_dev)
+
+static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct device *dev = audev->dev;
+
+ dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
+
+ iowrite32(data, auchan->base + reg);
+}
+
+static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
+{
+ return ioread32(auchan->base + reg);
+}
+
+static void audmapp_halt(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ int i;
+
+ audmapp_write(auchan, 0, PDMACHCR);
+
+ for(i = 0; i < 1024; i++) {
+ if (0 == audmapp_read(auchan, PDMACHCR))
+ return;
+ udelay(1);
+ }
+}
+
+static void audmapp_start_xfer(struct shdma_chan *schan,
+ struct shdma_desc *sdecs)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_slave_config *cfg = auchan->config;
+ struct device *dev = audev->dev;
+ u32 chcr = cfg->chcr | PDMACHCR_DE;
+
+ dev_dbg(dev, "src/dst/chcr = %x/%x/%x\n",
+ cfg->src, cfg->dst, cfg->chcr);
+
+ audmapp_write(auchan, cfg->src, PDMASAR);
+ audmapp_write(auchan, cfg->dst, PDMADAR);
+ audmapp_write(auchan, chcr, PDMACHCR);
+}
+
+static struct audmapp_slave_config *
+audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_pdata *pdata = audev->pdata;
+ struct audmapp_slave_config *cfg;
+ int i;
+
+ if (slave_id >= AUDMAPP_SLAVE_NUMBER)
+ return NULL;
+
+ for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+ if (cfg->slave_id == slave_id)
+ return cfg;
+
+ return NULL;
+}
+
+static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
+ dma_addr_t slave_addr, bool try)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg =
+ audmapp_find_slave(auchan, slave_id);
+
+ if (!cfg)
+ return -ENODEV;
+ if (try)
+ return 0;
+
+ auchan->config = cfg;
+
+ return 0;
+}
+
+static int audmapp_desc_setup(struct shdma_chan *schan,
+ struct shdma_desc *sdecs,
+ dma_addr_t src, dma_addr_t dst, size_t *len)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg = auchan->config;
+
+ if (!cfg)
+ return -ENODEV;
+
+ if (*len > (size_t)AUDMAPP_LEN_MAX)
+ *len = (size_t)AUDMAPP_LEN_MAX;
+
+ return 0;
+}
+
+static void audmapp_setup_xfer(struct shdma_chan *schan,
+ int slave_id)
+{
+}
+
+static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
+{
+ return 0; /* always fixed address */
+}
+
+static bool audmapp_channel_busy(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ u32 chcr = audmapp_read(auchan, PDMACHCR);
+
+ return chcr & ~PDMACHCR_DE;
+}
+
+static bool audmapp_desc_completed(struct shdma_chan *schan,
+ struct shdma_desc *sdesc)
+{
+ return true;
+}
+
+static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
+{
+ return &((struct shdma_desc *)buf)[i];
+}
+
+static const struct shdma_ops audmapp_shdma_ops = {
+ .halt_channel = audmapp_halt,
+ .desc_setup = audmapp_desc_setup,
+ .set_slave = audmapp_set_slave,
+ .start_xfer = audmapp_start_xfer,
+ .embedded_desc = audmapp_embedded_desc,
+ .setup_xfer = audmapp_setup_xfer,
+ .slave_addr = audmapp_slave_addr,
+ .channel_busy = audmapp_channel_busy,
+ .desc_completed = audmapp_desc_completed,
+};
+
+static int audmapp_chan_probe(struct platform_device *pdev,
+ struct audmapp_device *audev, int id)
+{
+ struct shdma_dev *sdev = &audev->shdma_dev;
+ struct audmapp_chan *auchan;
+ struct shdma_chan *schan;
+ struct device *dev = audev->dev;
+
+ auchan = devm_kzalloc(dev, sizeof(struct audmapp_chan), GFP_KERNEL);
+ if (!auchan)
+ return -ENOMEM;
+
+ schan = &auchan->shdma_chan;
+ schan->max_xfer_len = AUDMAPP_LEN_MAX;
+
+ shdma_chan_probe(sdev, schan, id);
+
+ auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
+ dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
+
+ return 0;
+}
+
+static void audmapp_chan_remove(struct audmapp_device *audev)
+{
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+ struct shdma_chan *schan;
+ int i;
+
+ shdma_for_each_chan(schan, &audev->shdma_dev, i) {
+ BUG_ON(!schan);
+ shdma_chan_remove(schan);
+ }
+ dma_dev->chancnt = 0;
+}
+
+static int audmapp_probe(struct platform_device *pdev)
+{
+ struct audmapp_pdata *pdata = pdev->dev.platform_data;
+ struct audmapp_device *audev;
+ struct shdma_dev *sdev;
+ struct dma_device *dma_dev;
+ struct resource *res;
+ int err, i;
+
+ if (!pdata)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ audev = devm_kzalloc(&pdev->dev, sizeof(struct audmapp_device),
+ GFP_KERNEL);
+ if (!audev)
+ return -ENOMEM;
+
+ audev->dev = &pdev->dev;
+ audev->pdata = pdata;
+ audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(audev->chan_reg))
+ return PTR_ERR(audev->chan_reg);
+
+ sdev = &audev->shdma_dev;
+ sdev->ops = &audmapp_shdma_ops;
+ sdev->desc_size = sizeof(struct shdma_desc);
+
+ dma_dev = &sdev->dma_dev;
+ dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
+ dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+
+ err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
+ if (err < 0)
+ return err;
+
+ platform_set_drvdata(pdev, audev);
+
+ /* Create DMA Channel */
+ for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
+ err = audmapp_chan_probe(pdev, audev, i);
+ if (err)
+ goto chan_probe_err;
+ }
+
+ err = dma_async_device_register(dma_dev);
+ if (err < 0)
+ goto chan_probe_err;
+
+ return err;
+
+chan_probe_err:
+ audmapp_chan_remove(audev);
+ shdma_cleanup(sdev);
+
+ return err;
+}
+
+static int audmapp_remove(struct platform_device *pdev)
+{
+ struct audmapp_device *audev = platform_get_drvdata(pdev);
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+
+ dma_async_device_unregister(dma_dev);
+
+ audmapp_chan_remove(audev);
+ shdma_cleanup(&audev->shdma_dev);
+
+ return 0;
+}
+
+static struct platform_driver audmapp_driver = {
+ .probe = audmapp_probe,
+ .remove = audmapp_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rcar-audmapp-engine",
+ },
+};
+module_platform_driver(audmapp_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
new file mode 100644
index 0000000..346df66
--- /dev/null
+++ b/include/linux/platform_data/dma-rcar-audmapp.h
@@ -0,0 +1,34 @@
+/*
+ * include/linux/sh_audma-pp.h
+ * This file is header file for Audio-DMAC-pp peripheral.
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ *
+ * This file is based on the include/linux/sh_dma.h
+ *
+ * Header for the new SH dmaengine driver
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef SH_AUDMAPP_H
+#define SH_AUDMAPP_H
+
+#include <linux/dmaengine.h>
+
+struct audmapp_slave_config {
+ int slave_id;
+ dma_addr_t src;
+ dma_addr_t dst;
+ u32 chcr;
+};
+
+struct audmapp_pdata {
+ struct audmapp_slave_config *slave;
+ int slave_num;
+};
+
+#endif /* SH_AUDMAPP_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
2014-03-10 2:25 ` [PATCH v3] shdma: " Kuninori Morimoto
@ 2014-03-10 9:15 ` Shevchenko, Andriy
0 siblings, 0 replies; 17+ messages in thread
From: Shevchenko, Andriy @ 2014-03-10 9:15 UTC (permalink / raw)
To: Kuninori Morimoto
Cc: Koul, Vinod, Morimoto, Linux-SH, linux-kernel@vger.kernel.org,
Geert Uytterhoeven, dmaengine@vger.kernel.org
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1064 bytes --]
On Sun, 2014-03-09 at 19:25 -0700, Kuninori Morimoto wrote:
> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
>
> Add support Audio DMAC peri peri driver
> for Renesas R-Car Gen2 SoC, using 'shdma-base'
> DMA driver framework.
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
> v2 -> v3
My previous mail is applicable to this version too.
--
Andy Shevchenko <andriy.shevchenko@intel.com>
Intel Finland Oy
---------------------------------------------------------------------
Intel Finland Oy
Registered Address: PL 281, 00181 Helsinki
Business Identity Code: 0357606 - 4
Domiciled in Helsinki
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
ÿôèº{.nÇ+·®+%Ëÿ±éݶ\x17¥wÿº{.nÇ+·¥{±þG«éÿ{ayº\x1dÊÚë,j\a¢f£¢·hïêÿêçz_è®\x03(éÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?¨èÚ&£ø§~á¶iOæ¬z·vØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?I¥
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
2014-01-24 2:32 [PATCH] shdma: add R-Car Audio DMAC peri peri driver Kuninori Morimoto
` (3 preceding siblings ...)
2014-03-10 2:25 ` [PATCH v3] shdma: " Kuninori Morimoto
@ 2014-03-11 1:11 ` Kuninori Morimoto
2014-03-25 1:08 ` Kuninori Morimoto
2014-03-29 14:08 ` Vinod Koul
4 siblings, 2 replies; 17+ messages in thread
From: Kuninori Morimoto @ 2014-03-11 1:11 UTC (permalink / raw)
To: Vinod Koul; +Cc: Morimoto, Linux-SH, linux-kernel, dmaengine
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Add support Audio DMAC peri peri driver
for Renesas R-Car Gen2 SoC, using 'shdma-base'
DMA driver framework.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3
- modiry copyright
- use %pad for dma_addr_t
- use sizeof(*hoge) for devm_kzalloc()
drivers/dma/sh/Kconfig | 6 +
drivers/dma/sh/Makefile | 1 +
drivers/dma/sh/rcar-audmapp.c | 320 ++++++++++++++++++++++++
include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
4 files changed, 361 insertions(+)
create mode 100644 drivers/dma/sh/rcar-audmapp.c
create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index dadd9e01..b4c8138 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
help
Enable support for the Renesas R-Car series DMA controllers.
+config RCAR_AUDMAC_PP
+ tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
+ depends on SH_DMAE_BASE
+ help
+ Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -7,3 +7,4 @@ endif
shdma-objs := $(shdma-y)
obj-$(CONFIG_SUDMAC) += sudmac.o
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
+obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
new file mode 100644
index 0000000..72d7475
--- /dev/null
+++ b/drivers/dma/sh/rcar-audmapp.c
@@ -0,0 +1,320 @@
+/*
+ * This is for Renesas R-Car Audio-DMAC-peri-peri.
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2014 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on the drivers/dma/sh/shdma.c
+ *
+ * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+ * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/dma-rcar-audmapp.h>
+#include <linux/platform_device.h>
+#include <linux/shdma-base.h>
+
+/*
+ * DMA register
+ */
+#define PDMASAR 0x00
+#define PDMADAR 0x04
+#define PDMACHCR 0x0c
+
+/* PDMACHCR */
+#define PDMACHCR_DE (1 << 0)
+
+#define AUDMAPP_MAX_CHANNELS 29
+
+/* Default MEMCPY transfer size = 2^2 = 4 bytes */
+#define LOG2_DEFAULT_XFER_SIZE 2
+#define AUDMAPP_SLAVE_NUMBER 256
+#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
+
+struct audmapp_chan {
+ struct shdma_chan shdma_chan;
+ struct audmapp_slave_config *config;
+ void __iomem *base;
+};
+
+struct audmapp_device {
+ struct shdma_dev shdma_dev;
+ struct audmapp_pdata *pdata;
+ struct device *dev;
+ void __iomem *chan_reg;
+};
+
+#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
+#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
+ struct audmapp_device, shdma_dev.dma_dev)
+
+static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct device *dev = audev->dev;
+
+ dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
+
+ iowrite32(data, auchan->base + reg);
+}
+
+static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
+{
+ return ioread32(auchan->base + reg);
+}
+
+static void audmapp_halt(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ int i;
+
+ audmapp_write(auchan, 0, PDMACHCR);
+
+ for(i = 0; i < 1024; i++) {
+ if (0 == audmapp_read(auchan, PDMACHCR))
+ return;
+ udelay(1);
+ }
+}
+
+static void audmapp_start_xfer(struct shdma_chan *schan,
+ struct shdma_desc *sdecs)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_slave_config *cfg = auchan->config;
+ struct device *dev = audev->dev;
+ u32 chcr = cfg->chcr | PDMACHCR_DE;
+
+ dev_dbg(dev, "src/dst/chcr = %pad/%pad/%x\n",
+ &cfg->src, &cfg->dst, cfg->chcr);
+
+ audmapp_write(auchan, cfg->src, PDMASAR);
+ audmapp_write(auchan, cfg->dst, PDMADAR);
+ audmapp_write(auchan, chcr, PDMACHCR);
+}
+
+static struct audmapp_slave_config *
+audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
+{
+ struct audmapp_device *audev = to_dev(auchan);
+ struct audmapp_pdata *pdata = audev->pdata;
+ struct audmapp_slave_config *cfg;
+ int i;
+
+ if (slave_id >= AUDMAPP_SLAVE_NUMBER)
+ return NULL;
+
+ for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+ if (cfg->slave_id == slave_id)
+ return cfg;
+
+ return NULL;
+}
+
+static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
+ dma_addr_t slave_addr, bool try)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg =
+ audmapp_find_slave(auchan, slave_id);
+
+ if (!cfg)
+ return -ENODEV;
+ if (try)
+ return 0;
+
+ auchan->config = cfg;
+
+ return 0;
+}
+
+static int audmapp_desc_setup(struct shdma_chan *schan,
+ struct shdma_desc *sdecs,
+ dma_addr_t src, dma_addr_t dst, size_t *len)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ struct audmapp_slave_config *cfg = auchan->config;
+
+ if (!cfg)
+ return -ENODEV;
+
+ if (*len > (size_t)AUDMAPP_LEN_MAX)
+ *len = (size_t)AUDMAPP_LEN_MAX;
+
+ return 0;
+}
+
+static void audmapp_setup_xfer(struct shdma_chan *schan,
+ int slave_id)
+{
+}
+
+static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
+{
+ return 0; /* always fixed address */
+}
+
+static bool audmapp_channel_busy(struct shdma_chan *schan)
+{
+ struct audmapp_chan *auchan = to_chan(schan);
+ u32 chcr = audmapp_read(auchan, PDMACHCR);
+
+ return chcr & ~PDMACHCR_DE;
+}
+
+static bool audmapp_desc_completed(struct shdma_chan *schan,
+ struct shdma_desc *sdesc)
+{
+ return true;
+}
+
+static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
+{
+ return &((struct shdma_desc *)buf)[i];
+}
+
+static const struct shdma_ops audmapp_shdma_ops = {
+ .halt_channel = audmapp_halt,
+ .desc_setup = audmapp_desc_setup,
+ .set_slave = audmapp_set_slave,
+ .start_xfer = audmapp_start_xfer,
+ .embedded_desc = audmapp_embedded_desc,
+ .setup_xfer = audmapp_setup_xfer,
+ .slave_addr = audmapp_slave_addr,
+ .channel_busy = audmapp_channel_busy,
+ .desc_completed = audmapp_desc_completed,
+};
+
+static int audmapp_chan_probe(struct platform_device *pdev,
+ struct audmapp_device *audev, int id)
+{
+ struct shdma_dev *sdev = &audev->shdma_dev;
+ struct audmapp_chan *auchan;
+ struct shdma_chan *schan;
+ struct device *dev = audev->dev;
+
+ auchan = devm_kzalloc(dev, sizeof(*auchan), GFP_KERNEL);
+ if (!auchan)
+ return -ENOMEM;
+
+ schan = &auchan->shdma_chan;
+ schan->max_xfer_len = AUDMAPP_LEN_MAX;
+
+ shdma_chan_probe(sdev, schan, id);
+
+ auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
+ dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
+
+ return 0;
+}
+
+static void audmapp_chan_remove(struct audmapp_device *audev)
+{
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+ struct shdma_chan *schan;
+ int i;
+
+ shdma_for_each_chan(schan, &audev->shdma_dev, i) {
+ BUG_ON(!schan);
+ shdma_chan_remove(schan);
+ }
+ dma_dev->chancnt = 0;
+}
+
+static int audmapp_probe(struct platform_device *pdev)
+{
+ struct audmapp_pdata *pdata = pdev->dev.platform_data;
+ struct audmapp_device *audev;
+ struct shdma_dev *sdev;
+ struct dma_device *dma_dev;
+ struct resource *res;
+ int err, i;
+
+ if (!pdata)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ audev = devm_kzalloc(&pdev->dev, sizeof(*audev), GFP_KERNEL);
+ if (!audev)
+ return -ENOMEM;
+
+ audev->dev = &pdev->dev;
+ audev->pdata = pdata;
+ audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(audev->chan_reg))
+ return PTR_ERR(audev->chan_reg);
+
+ sdev = &audev->shdma_dev;
+ sdev->ops = &audmapp_shdma_ops;
+ sdev->desc_size = sizeof(struct shdma_desc);
+
+ dma_dev = &sdev->dma_dev;
+ dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
+ dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+
+ err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
+ if (err < 0)
+ return err;
+
+ platform_set_drvdata(pdev, audev);
+
+ /* Create DMA Channel */
+ for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
+ err = audmapp_chan_probe(pdev, audev, i);
+ if (err)
+ goto chan_probe_err;
+ }
+
+ err = dma_async_device_register(dma_dev);
+ if (err < 0)
+ goto chan_probe_err;
+
+ return err;
+
+chan_probe_err:
+ audmapp_chan_remove(audev);
+ shdma_cleanup(sdev);
+
+ return err;
+}
+
+static int audmapp_remove(struct platform_device *pdev)
+{
+ struct audmapp_device *audev = platform_get_drvdata(pdev);
+ struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+
+ dma_async_device_unregister(dma_dev);
+
+ audmapp_chan_remove(audev);
+ shdma_cleanup(&audev->shdma_dev);
+
+ return 0;
+}
+
+static struct platform_driver audmapp_driver = {
+ .probe = audmapp_probe,
+ .remove = audmapp_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rcar-audmapp-engine",
+ },
+};
+module_platform_driver(audmapp_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
new file mode 100644
index 0000000..471fffe
--- /dev/null
+++ b/include/linux/platform_data/dma-rcar-audmapp.h
@@ -0,0 +1,34 @@
+/*
+ * This is for Renesas R-Car Audio-DMAC-peri-peri.
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2014 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is based on the include/linux/sh_dma.h
+ *
+ * Header for the new SH dmaengine driver
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef SH_AUDMAPP_H
+#define SH_AUDMAPP_H
+
+#include <linux/dmaengine.h>
+
+struct audmapp_slave_config {
+ int slave_id;
+ dma_addr_t src;
+ dma_addr_t dst;
+ u32 chcr;
+};
+
+struct audmapp_pdata {
+ struct audmapp_slave_config *slave;
+ int slave_num;
+};
+
+#endif /* SH_AUDMAPP_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
2014-03-11 1:11 ` Kuninori Morimoto
@ 2014-03-25 1:08 ` Kuninori Morimoto
2014-03-29 14:08 ` Vinod Koul
1 sibling, 0 replies; 17+ messages in thread
From: Kuninori Morimoto @ 2014-03-25 1:08 UTC (permalink / raw)
To: Vinod Koul; +Cc: Morimoto, Linux-SH, linux-kernel, dmaengine
Hi Vinod, and all
Could you please teach me current status of this patch ??
> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
>
> Add support Audio DMAC peri peri driver
> for Renesas R-Car Gen2 SoC, using 'shdma-base'
> DMA driver framework.
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
> v2 -> v3
>
> - modiry copyright
> - use %pad for dma_addr_t
> - use sizeof(*hoge) for devm_kzalloc()
>
> drivers/dma/sh/Kconfig | 6 +
> drivers/dma/sh/Makefile | 1 +
> drivers/dma/sh/rcar-audmapp.c | 320 ++++++++++++++++++++++++
> include/linux/platform_data/dma-rcar-audmapp.h | 34 +++
> 4 files changed, 361 insertions(+)
> create mode 100644 drivers/dma/sh/rcar-audmapp.c
> create mode 100644 include/linux/platform_data/dma-rcar-audmapp.h
>
> diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
> index dadd9e01..b4c8138 100644
> --- a/drivers/dma/sh/Kconfig
> +++ b/drivers/dma/sh/Kconfig
> @@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
> help
> Enable support for the Renesas R-Car series DMA controllers.
>
> +config RCAR_AUDMAC_PP
> + tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
> + depends on SH_DMAE_BASE
> + help
> + Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral 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 e856af2..1ce88b2 100644
> --- a/drivers/dma/sh/Makefile
> +++ b/drivers/dma/sh/Makefile
> @@ -7,3 +7,4 @@ endif
> shdma-objs := $(shdma-y)
> obj-$(CONFIG_SUDMAC) += sudmac.o
> obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
> +obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
> diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
> new file mode 100644
> index 0000000..72d7475
> --- /dev/null
> +++ b/drivers/dma/sh/rcar-audmapp.c
> @@ -0,0 +1,320 @@
> +/*
> + * This is for Renesas R-Car Audio-DMAC-peri-peri.
> + *
> + * Copyright (C) 2014 Renesas Electronics Corporation
> + * Copyright (C) 2014 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> + *
> + * based on the drivers/dma/sh/shdma.c
> + *
> + * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
> + * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
> + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * This is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/dmaengine.h>
> +#include <linux/platform_data/dma-rcar-audmapp.h>
> +#include <linux/platform_device.h>
> +#include <linux/shdma-base.h>
> +
> +/*
> + * DMA register
> + */
> +#define PDMASAR 0x00
> +#define PDMADAR 0x04
> +#define PDMACHCR 0x0c
> +
> +/* PDMACHCR */
> +#define PDMACHCR_DE (1 << 0)
> +
> +#define AUDMAPP_MAX_CHANNELS 29
> +
> +/* Default MEMCPY transfer size = 2^2 = 4 bytes */
> +#define LOG2_DEFAULT_XFER_SIZE 2
> +#define AUDMAPP_SLAVE_NUMBER 256
> +#define AUDMAPP_LEN_MAX (16 * 1024 * 1024)
> +
> +struct audmapp_chan {
> + struct shdma_chan shdma_chan;
> + struct audmapp_slave_config *config;
> + void __iomem *base;
> +};
> +
> +struct audmapp_device {
> + struct shdma_dev shdma_dev;
> + struct audmapp_pdata *pdata;
> + struct device *dev;
> + void __iomem *chan_reg;
> +};
> +
> +#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
> +#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device, \
> + struct audmapp_device, shdma_dev.dma_dev)
> +
> +static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
> +{
> + struct audmapp_device *audev = to_dev(auchan);
> + struct device *dev = audev->dev;
> +
> + dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
> +
> + iowrite32(data, auchan->base + reg);
> +}
> +
> +static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
> +{
> + return ioread32(auchan->base + reg);
> +}
> +
> +static void audmapp_halt(struct shdma_chan *schan)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + int i;
> +
> + audmapp_write(auchan, 0, PDMACHCR);
> +
> + for(i = 0; i < 1024; i++) {
> + if (0 == audmapp_read(auchan, PDMACHCR))
> + return;
> + udelay(1);
> + }
> +}
> +
> +static void audmapp_start_xfer(struct shdma_chan *schan,
> + struct shdma_desc *sdecs)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_device *audev = to_dev(auchan);
> + struct audmapp_slave_config *cfg = auchan->config;
> + struct device *dev = audev->dev;
> + u32 chcr = cfg->chcr | PDMACHCR_DE;
> +
> + dev_dbg(dev, "src/dst/chcr = %pad/%pad/%x\n",
> + &cfg->src, &cfg->dst, cfg->chcr);
> +
> + audmapp_write(auchan, cfg->src, PDMASAR);
> + audmapp_write(auchan, cfg->dst, PDMADAR);
> + audmapp_write(auchan, chcr, PDMACHCR);
> +}
> +
> +static struct audmapp_slave_config *
> +audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
> +{
> + struct audmapp_device *audev = to_dev(auchan);
> + struct audmapp_pdata *pdata = audev->pdata;
> + struct audmapp_slave_config *cfg;
> + int i;
> +
> + if (slave_id >= AUDMAPP_SLAVE_NUMBER)
> + return NULL;
> +
> + for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
> + if (cfg->slave_id == slave_id)
> + return cfg;
> +
> + return NULL;
> +}
> +
> +static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
> + dma_addr_t slave_addr, bool try)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_slave_config *cfg =
> + audmapp_find_slave(auchan, slave_id);
> +
> + if (!cfg)
> + return -ENODEV;
> + if (try)
> + return 0;
> +
> + auchan->config = cfg;
> +
> + return 0;
> +}
> +
> +static int audmapp_desc_setup(struct shdma_chan *schan,
> + struct shdma_desc *sdecs,
> + dma_addr_t src, dma_addr_t dst, size_t *len)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + struct audmapp_slave_config *cfg = auchan->config;
> +
> + if (!cfg)
> + return -ENODEV;
> +
> + if (*len > (size_t)AUDMAPP_LEN_MAX)
> + *len = (size_t)AUDMAPP_LEN_MAX;
> +
> + return 0;
> +}
> +
> +static void audmapp_setup_xfer(struct shdma_chan *schan,
> + int slave_id)
> +{
> +}
> +
> +static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
> +{
> + return 0; /* always fixed address */
> +}
> +
> +static bool audmapp_channel_busy(struct shdma_chan *schan)
> +{
> + struct audmapp_chan *auchan = to_chan(schan);
> + u32 chcr = audmapp_read(auchan, PDMACHCR);
> +
> + return chcr & ~PDMACHCR_DE;
> +}
> +
> +static bool audmapp_desc_completed(struct shdma_chan *schan,
> + struct shdma_desc *sdesc)
> +{
> + return true;
> +}
> +
> +static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
> +{
> + return &((struct shdma_desc *)buf)[i];
> +}
> +
> +static const struct shdma_ops audmapp_shdma_ops = {
> + .halt_channel = audmapp_halt,
> + .desc_setup = audmapp_desc_setup,
> + .set_slave = audmapp_set_slave,
> + .start_xfer = audmapp_start_xfer,
> + .embedded_desc = audmapp_embedded_desc,
> + .setup_xfer = audmapp_setup_xfer,
> + .slave_addr = audmapp_slave_addr,
> + .channel_busy = audmapp_channel_busy,
> + .desc_completed = audmapp_desc_completed,
> +};
> +
> +static int audmapp_chan_probe(struct platform_device *pdev,
> + struct audmapp_device *audev, int id)
> +{
> + struct shdma_dev *sdev = &audev->shdma_dev;
> + struct audmapp_chan *auchan;
> + struct shdma_chan *schan;
> + struct device *dev = audev->dev;
> +
> + auchan = devm_kzalloc(dev, sizeof(*auchan), GFP_KERNEL);
> + if (!auchan)
> + return -ENOMEM;
> +
> + schan = &auchan->shdma_chan;
> + schan->max_xfer_len = AUDMAPP_LEN_MAX;
> +
> + shdma_chan_probe(sdev, schan, id);
> +
> + auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
> + dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
> +
> + return 0;
> +}
> +
> +static void audmapp_chan_remove(struct audmapp_device *audev)
> +{
> + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> + struct shdma_chan *schan;
> + int i;
> +
> + shdma_for_each_chan(schan, &audev->shdma_dev, i) {
> + BUG_ON(!schan);
> + shdma_chan_remove(schan);
> + }
> + dma_dev->chancnt = 0;
> +}
> +
> +static int audmapp_probe(struct platform_device *pdev)
> +{
> + struct audmapp_pdata *pdata = pdev->dev.platform_data;
> + struct audmapp_device *audev;
> + struct shdma_dev *sdev;
> + struct dma_device *dma_dev;
> + struct resource *res;
> + int err, i;
> +
> + if (!pdata)
> + return -ENODEV;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + audev = devm_kzalloc(&pdev->dev, sizeof(*audev), GFP_KERNEL);
> + if (!audev)
> + return -ENOMEM;
> +
> + audev->dev = &pdev->dev;
> + audev->pdata = pdata;
> + audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(audev->chan_reg))
> + return PTR_ERR(audev->chan_reg);
> +
> + sdev = &audev->shdma_dev;
> + sdev->ops = &audmapp_shdma_ops;
> + sdev->desc_size = sizeof(struct shdma_desc);
> +
> + dma_dev = &sdev->dma_dev;
> + dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
> + dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
> +
> + err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
> + if (err < 0)
> + return err;
> +
> + platform_set_drvdata(pdev, audev);
> +
> + /* Create DMA Channel */
> + for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
> + err = audmapp_chan_probe(pdev, audev, i);
> + if (err)
> + goto chan_probe_err;
> + }
> +
> + err = dma_async_device_register(dma_dev);
> + if (err < 0)
> + goto chan_probe_err;
> +
> + return err;
> +
> +chan_probe_err:
> + audmapp_chan_remove(audev);
> + shdma_cleanup(sdev);
> +
> + return err;
> +}
> +
> +static int audmapp_remove(struct platform_device *pdev)
> +{
> + struct audmapp_device *audev = platform_get_drvdata(pdev);
> + struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
> +
> + dma_async_device_unregister(dma_dev);
> +
> + audmapp_chan_remove(audev);
> + shdma_cleanup(&audev->shdma_dev);
> +
> + return 0;
> +}
> +
> +static struct platform_driver audmapp_driver = {
> + .probe = audmapp_probe,
> + .remove = audmapp_remove,
> + .driver = {
> + .owner = THIS_MODULE,
> + .name = "rcar-audmapp-engine",
> + },
> +};
> +module_platform_driver(audmapp_driver);
> +
> +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
> +MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
> new file mode 100644
> index 0000000..471fffe
> --- /dev/null
> +++ b/include/linux/platform_data/dma-rcar-audmapp.h
> @@ -0,0 +1,34 @@
> +/*
> + * This is for Renesas R-Car Audio-DMAC-peri-peri.
> + *
> + * Copyright (C) 2014 Renesas Electronics Corporation
> + * Copyright (C) 2014 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> + *
> + * This file is based on the include/linux/sh_dma.h
> + *
> + * Header for the new SH dmaengine driver
> + *
> + * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef SH_AUDMAPP_H
> +#define SH_AUDMAPP_H
> +
> +#include <linux/dmaengine.h>
> +
> +struct audmapp_slave_config {
> + int slave_id;
> + dma_addr_t src;
> + dma_addr_t dst;
> + u32 chcr;
> +};
> +
> +struct audmapp_pdata {
> + struct audmapp_slave_config *slave;
> + int slave_num;
> +};
> +
> +#endif /* SH_AUDMAPP_H */
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
2014-03-11 1:11 ` Kuninori Morimoto
2014-03-25 1:08 ` Kuninori Morimoto
@ 2014-03-29 14:08 ` Vinod Koul
1 sibling, 0 replies; 17+ messages in thread
From: Vinod Koul @ 2014-03-29 14:08 UTC (permalink / raw)
To: Kuninori Morimoto; +Cc: Morimoto, Linux-SH, linux-kernel, dmaengine
On Mon, Mar 10, 2014 at 06:11:50PM -0700, Kuninori Morimoto wrote:
> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
>
> Add support Audio DMAC peri peri driver
> for Renesas R-Car Gen2 SoC, using 'shdma-base'
> DMA driver framework.
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Please run checkpatch *everytime* you generate a patch. I have fixes a simple
format error :(
Applied, now
--
~Vinod
^ permalink raw reply [flat|nested] 17+ messages in thread