All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-01-24  2:32 ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ messages in thread
From: Kuninori Morimoto @ 2014-01-24  2:32 UTC (permalink / raw)
  To: Vinod Koul; +Cc: Morimoto, Linux-SH, linux-kernel

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>
---
 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..a5e5a1a
--- /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 >= 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) {
+		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] 34+ messages in thread

* [PATCH] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-01-24  2:32 ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ messages in thread
From: Kuninori Morimoto @ 2014-01-24  2:32 UTC (permalink / raw)
  To: Vinod Koul; +Cc: Morimoto, Linux-SH, linux-kernel

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>
---
 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..a5e5a1a
--- /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 >= 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) {
+		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] 34+ messages in thread

* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
  2014-01-24  2:32 ` Kuninori Morimoto
@ 2014-01-24  7:34   ` Geert Uytterhoeven
  -1 siblings, 0 replies; 34+ 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

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] 34+ messages in thread

* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-01-24  7:34   ` Geert Uytterhoeven
  0 siblings, 0 replies; 34+ 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

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] 34+ 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
  -1 siblings, 0 replies; 34+ 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


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] 34+ messages in thread

* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-01-24  8:18     ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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


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] 34+ 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
  -1 siblings, 0 replies; 34+ 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

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] 34+ messages in thread

* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-01-24  8:33       ` Geert Uytterhoeven
  0 siblings, 0 replies; 34+ 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

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] 34+ 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
  -1 siblings, 0 replies; 34+ 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


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] 34+ messages in thread

* Re: [PATCH] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-01-24  8:58         ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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


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] 34+ messages in thread

* [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
  2014-01-24  2:32 ` Kuninori Morimoto
@ 2014-01-24  9:06   ` Kuninori Morimoto
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
@ 2014-01-24  9:06   ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
  2014-01-24  9:06   ` Kuninori Morimoto
@ 2014-02-12  5:29     ` Kuninori Morimoto
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
@ 2014-02-12  5:29     ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ 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
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v2] dma: add R-Car Audio DMAC peri peri driver
@ 2014-02-25  5:13       ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
  2014-01-24  2:32 ` Kuninori Morimoto
@ 2014-03-10  1:34   ` Kuninori Morimoto
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
@ 2014-03-10  1:34   ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
  2014-03-10  1:34   ` Kuninori Morimoto
@ 2014-03-10  1:47     ` Joe Perches
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
@ 2014-03-10  1:47     ` Joe Perches
  0 siblings, 0 replies; 34+ 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] 34+ 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
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
@ 2014-03-10  2:19       ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
  2014-01-24  2:32 ` Kuninori Morimoto
@ 2014-03-10  2:25   ` Kuninori Morimoto
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-03-10  2:25   ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
  2014-03-10  1:34   ` Kuninori Morimoto
@ 2014-03-10  9:13     ` Shevchenko, Andriy
  -1 siblings, 0 replies; 34+ 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,
	Geert Uytterhoeven, dmaengine

T24gU3VuLCAyMDE0LTAzLTA5IGF0IDE4OjM0IC0wNzAwLCBLdW5pbm9yaSBNb3JpbW90byB3cm90
ZToNCj4gRnJvbTogS3VuaW5vcmkgTW9yaW1vdG8gPGt1bmlub3JpLm1vcmltb3RvLmd4QHJlbmVz
YXMuY29tPg0KPiANCj4gQWRkIHN1cHBvcnQgQXVkaW8gRE1BQyBwZXJpIHBlcmkgZHJpdmVyDQo+
IGZvciBSZW5lc2FzIFItQ2FyIEdlbjIgU29DLCB1c2luZyAnc2hkbWEtYmFzZScNCj4gRE1BIGRy
aXZlciBmcmFtZXdvcmsuDQoNCkZldyBjb21tZW50cyBiZWxvdy4NCg0KPiANCj4gU2lnbmVkLW9m
Zi1ieTogS3VuaW5vcmkgTW9yaW1vdG8gPGt1bmlub3JpLm1vcmltb3RvLmd4QHJlbmVzYXMuY29t
Pg0KPiAtLS0NCj4gcmVzZW50DQo+IA0KPiAgLSBhZGQgbWlzc2luZyAiZG1hZW5naW5lQHZnZXIu
a2VybmVsLm9yZyINCj4gDQo+IHYxIC0+IHYyDQo+IA0KPiAgLSBydW4gc2NyaXB0cy9jaGVja3Bh
dGNoLnBsDQo+ICAtIGVjY2hhbmdlIGxlbmd0aCBzZXR0aW5ncyBvbiBhdWRtYXBwX2Rlc2Nfc2V0
dXAoKQ0KPiAgLSBleGNoYW5nZSBzbGF2ZV9pZCBjaGVjayBvbiBhdWRtYXBwX2ZpbmRfc2xhdmUo
KQ0KPiANCj4gIGRyaXZlcnMvZG1hL3NoL0tjb25maWcgICAgICAgICAgICAgICAgICAgICAgICAg
fCAgICA2ICsNCj4gIGRyaXZlcnMvZG1hL3NoL01ha2VmaWxlICAgICAgICAgICAgICAgICAgICAg
ICAgfCAgICAxICsNCj4gIGRyaXZlcnMvZG1hL3NoL3JjYXItYXVkbWFwcC5jICAgICAgICAgICAg
ICAgICAgfCAgMzI1ICsrKysrKysrKysrKysrKysrKysrKysrKw0KPiAgaW5jbHVkZS9saW51eC9w
bGF0Zm9ybV9kYXRhL2RtYS1yY2FyLWF1ZG1hcHAuaCB8ICAgMzQgKysrDQo+ICA0IGZpbGVzIGNo
YW5nZWQsIDM2NiBpbnNlcnRpb25zKCspDQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9k
bWEvc2gvcmNhci1hdWRtYXBwLmMNCj4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL2xpbnV4
L3BsYXRmb3JtX2RhdGEvZG1hLXJjYXItYXVkbWFwcC5oDQo+IA0KPiBkaWZmIC0tZ2l0IGEvZHJp
dmVycy9kbWEvc2gvS2NvbmZpZyBiL2RyaXZlcnMvZG1hL3NoL0tjb25maWcNCj4gaW5kZXggZGFk
ZDllMDEuLmI0YzgxMzggMTAwNjQ0DQo+IC0tLSBhL2RyaXZlcnMvZG1hL3NoL0tjb25maWcNCj4g
KysrIGIvZHJpdmVycy9kbWEvc2gvS2NvbmZpZw0KPiBAQCAtMjksNiArMjksMTIgQEAgY29uZmln
IFJDQVJfSFBCX0RNQUUNCj4gIAloZWxwDQo+ICAJICBFbmFibGUgc3VwcG9ydCBmb3IgdGhlIFJl
bmVzYXMgUi1DYXIgc2VyaWVzIERNQSBjb250cm9sbGVycy4NCj4gIA0KPiArY29uZmlnIFJDQVJf
QVVETUFDX1BQDQo+ICsJdHJpc3RhdGUgIlJlbmVzYXMgUi1DYXIgQXVkaW8gRE1BQyBQZXJpcGhl
cmFsIFBlcmlwaGVyYWwgc3VwcG9ydCINCj4gKwlkZXBlbmRzIG9uIFNIX0RNQUVfQkFTRQ0KPiAr
CWhlbHANCj4gKwkgIEVuYWJsZSBzdXBwb3J0IGZvciB0aGUgUmVuZXNhcyBSLUNhciBBdWRpbyBE
TUFDIFBlcmlwaGVyYWwgUGVyaXBoZXJhbCBjb250cm9sbGVycy4NCj4gKw0KPiAgY29uZmlnIFNI
RE1BX1I4QTczQTQNCj4gIAlkZWZfYm9vbCB5DQo+ICAJZGVwZW5kcyBvbiBBUkNIX1I4QTczQTQg
JiYgU0hfRE1BRSAhPSBuDQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2RtYS9zaC9NYWtlZmlsZSBi
L2RyaXZlcnMvZG1hL3NoL01ha2VmaWxlDQo+IGluZGV4IGU4NTZhZjIuLjFjZTg4YjIgMTAwNjQ0
DQo+IC0tLSBhL2RyaXZlcnMvZG1hL3NoL01ha2VmaWxlDQo+ICsrKyBiL2RyaXZlcnMvZG1hL3No
L01ha2VmaWxlDQo+IEBAIC03LDMgKzcsNCBAQCBlbmRpZg0KPiAgc2hkbWEtb2JqcyA6PSAkKHNo
ZG1hLXkpDQo+ICBvYmotJChDT05GSUdfU1VETUFDKSArPSBzdWRtYWMubw0KPiAgb2JqLSQoQ09O
RklHX1JDQVJfSFBCX0RNQUUpICs9IHJjYXItaHBiZG1hLm8NCj4gK29iai0kKENPTkZJR19SQ0FS
X0FVRE1BQ19QUCkgKz0gcmNhci1hdWRtYXBwLm8NCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1h
L3NoL3JjYXItYXVkbWFwcC5jIGIvZHJpdmVycy9kbWEvc2gvcmNhci1hdWRtYXBwLmMNCj4gbmV3
IGZpbGUgbW9kZSAxMDA2NDQNCj4gaW5kZXggMDAwMDAwMC4uY2QzYzIzNw0KPiAtLS0gL2Rldi9u
dWxsDQo+ICsrKyBiL2RyaXZlcnMvZG1hL3NoL3JjYXItYXVkbWFwcC5jDQo+IEBAIC0wLDAgKzEs
MzI1IEBADQo+ICsvKg0KPiArICogZHJpdmVycy9kbWEvc2gvcmNhci1hdWRtYXBwLmMNCj4gKyAq
DQo+ICsgKiBDb3B5cmlnaHQgKEMpIDIwMTMgUmVuZXNhcyBFbGVjdHJvbmljcyBDb3Jwb3JhdGlv
bg0KPiArICogQ29weXJpZ2h0IChDKSAyMDEzIEt1bmlub3JpIE1vcmltb3RvIDxrdW5pbm9yaS5t
b3JpbW90by5neEByZW5lc2FzLmNvbT4NCg0KMjAxND8NCg0KPiArICoNCj4gKyAqIGJhc2VkIG9u
IHRoZSBkcml2ZXJzL2RtYS9zaC9zaGRtYS5jDQo+ICsgKg0KPiArICogQ29weXJpZ2h0IChDKSAy
MDExLTIwMTIgR3Vlbm5hZGkgTGlha2hvdmV0c2tpIDxnLmxpYWtob3ZldHNraUBnbXguZGU+DQo+
ICsgKiBDb3B5cmlnaHQgKEMpIDIwMDkgTm9idWhpcm8gSXdhbWF0c3UgPGl3YW1hdHN1Lm5vYnVo
aXJvQHJlbmVzYXMuY29tPg0KPiArICogQ29weXJpZ2h0IChDKSAyMDA5IFJlbmVzYXMgU29sdXRp
b25zLCBJbmMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQo+ICsgKiBDb3B5cmlnaHQgKEMpIDIwMDcg
RnJlZXNjYWxlIFNlbWljb25kdWN0b3IsIEluYy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCj4gKyAq
DQo+ICsgKiBUaGlzIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFu
ZC9vciBtb2RpZnkNCj4gKyAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwg
UHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5DQo+ICsgKiB0aGUgRnJlZSBTb2Z0d2FyZSBG
b3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAyIG9mIHRoZSBMaWNlbnNlLCBvcg0KPiArICogKGF0
IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4NCj4gKyAqDQo+ICsgKi8NCj4gKyNpbmNs
dWRlIDxsaW51eC9kZWxheS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2luaXQuaD4NCj4gKyNpbmNs
dWRlIDxsaW51eC9tb2R1bGUuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+DQo+ICsjaW5j
bHVkZSA8bGludXgvZG1hZW5naW5lLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGF0
YS9kbWEtcmNhci1hdWRtYXBwLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGV2aWNl
Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgvc2hkbWEtYmFzZS5oPg0KPiArDQo+ICsvKg0KPiArICog
RE1BIHJlZ2lzdGVyDQo+ICsgKi8NCj4gKyNkZWZpbmUgUERNQVNBUgkJMHgwMA0KPiArI2RlZmlu
ZSBQRE1BREFSCQkweDA0DQo+ICsjZGVmaW5lIFBETUFDSENSCTB4MGMNCj4gKw0KPiArLyogUERN
QUNIQ1IgKi8NCj4gKyNkZWZpbmUgUERNQUNIQ1JfREUJCSgxIDw8IDApDQo+ICsNCj4gKyNkZWZp
bmUgQVVETUFQUF9NQVhfQ0hBTk5FTFMJMjkNCj4gKw0KPiArLyogRGVmYXVsdCBNRU1DUFkgdHJh
bnNmZXIgc2l6ZSA9IDJeMiA9IDQgYnl0ZXMgKi8NCj4gKyNkZWZpbmUgTE9HMl9ERUZBVUxUX1hG
RVJfU0laRQkyDQo+ICsjZGVmaW5lIEFVRE1BUFBfU0xBVkVfTlVNQkVSCTI1Ng0KPiArI2RlZmlu
ZSBBVURNQVBQX0xFTl9NQVgJCSgxNiAqIDEwMjQgKiAxMDI0KQ0KPiArDQo+ICtzdHJ1Y3QgYXVk
bWFwcF9jaGFuIHsNCj4gKwlzdHJ1Y3Qgc2hkbWFfY2hhbiBzaGRtYV9jaGFuOw0KPiArCXN0cnVj
dCBhdWRtYXBwX3NsYXZlX2NvbmZpZyAqY29uZmlnOw0KPiArCXZvaWQgX19pb21lbSAqYmFzZTsN
Cj4gK307DQo+ICsNCj4gK3N0cnVjdCBhdWRtYXBwX2RldmljZSB7DQo+ICsJc3RydWN0IHNoZG1h
X2RldiBzaGRtYV9kZXY7DQo+ICsJc3RydWN0IGF1ZG1hcHBfcGRhdGEgKnBkYXRhOw0KPiArCXN0
cnVjdCBkZXZpY2UgKmRldjsNCj4gKwl2b2lkIF9faW9tZW0gKmNoYW5fcmVnOw0KPiArfTsNCj4g
Kw0KPiArI2RlZmluZSB0b19jaGFuKGNoYW4pIGNvbnRhaW5lcl9vZihjaGFuLCBzdHJ1Y3QgYXVk
bWFwcF9jaGFuLCBzaGRtYV9jaGFuKQ0KPiArI2RlZmluZSB0b19kZXYoY2hhbikgY29udGFpbmVy
X29mKGNoYW4tPnNoZG1hX2NoYW4uZG1hX2NoYW4uZGV2aWNlLAlcDQo+ICsJCQkJICBzdHJ1Y3Qg
YXVkbWFwcF9kZXZpY2UsIHNoZG1hX2Rldi5kbWFfZGV2KQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBh
dWRtYXBwX3dyaXRlKHN0cnVjdCBhdWRtYXBwX2NoYW4gKmF1Y2hhbiwgdTMyIGRhdGEsIHUzMiBy
ZWcpDQo+ICt7DQo+ICsJc3RydWN0IGF1ZG1hcHBfZGV2aWNlICphdWRldiA9IHRvX2RldihhdWNo
YW4pOw0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9IGF1ZGV2LT5kZXY7DQo+ICsNCj4gKwlkZXZf
ZGJnKGRldiwgIncgJXAgOiAlMDh4XG4iLCBhdWNoYW4tPmJhc2UgKyByZWcsIGRhdGEpOw0KPiAr
DQo+ICsJaW93cml0ZTMyKGRhdGEsIGF1Y2hhbi0+YmFzZSArIHJlZyk7DQo+ICt9DQo+ICsNCj4g
K3N0YXRpYyB1MzIgYXVkbWFwcF9yZWFkKHN0cnVjdCBhdWRtYXBwX2NoYW4gKmF1Y2hhbiwgdTMy
IHJlZykNCj4gK3sNCj4gKwlyZXR1cm4gaW9yZWFkMzIoYXVjaGFuLT5iYXNlICsgcmVnKTsNCj4g
K30NCj4gKw0KPiArc3RhdGljIHZvaWQgYXVkbWFwcF9oYWx0KHN0cnVjdCBzaGRtYV9jaGFuICpz
Y2hhbikNCj4gK3sNCj4gKwlzdHJ1Y3QgYXVkbWFwcF9jaGFuICphdWNoYW4gPSB0b19jaGFuKHNj
aGFuKTsNCj4gKwlpbnQgaTsNCj4gKw0KPiArCWF1ZG1hcHBfd3JpdGUoYXVjaGFuLCAwLCBQRE1B
Q0hDUik7DQo+ICsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgMTAyNDsgaSsrKSB7DQo+ICsJCWlmICgw
ID09IGF1ZG1hcHBfcmVhZChhdWNoYW4sIFBETUFDSENSKSkNCj4gKwkJCXJldHVybjsNCj4gKwkJ
dWRlbGF5KDEpOw0KPiArCX0NCj4gK30NCj4gKw0KPiArc3RhdGljIHZvaWQgYXVkbWFwcF9zdGFy
dF94ZmVyKHN0cnVjdCBzaGRtYV9jaGFuICpzY2hhbiwNCj4gKwkJCSAgICAgICBzdHJ1Y3Qgc2hk
bWFfZGVzYyAqc2RlY3MpDQo+ICt7DQo+ICsJc3RydWN0IGF1ZG1hcHBfY2hhbiAqYXVjaGFuID0g
dG9fY2hhbihzY2hhbik7DQo+ICsJc3RydWN0IGF1ZG1hcHBfZGV2aWNlICphdWRldiA9IHRvX2Rl
dihhdWNoYW4pOw0KPiArCXN0cnVjdCBhdWRtYXBwX3NsYXZlX2NvbmZpZyAqY2ZnID0gYXVjaGFu
LT5jb25maWc7DQo+ICsJc3RydWN0IGRldmljZSAqZGV2ID0gYXVkZXYtPmRldjsNCj4gKwl1MzIg
Y2hjciA9IGNmZy0+Y2hjciB8IFBETUFDSENSX0RFOw0KPiArDQo+ICsJZGV2X2RiZyhkZXYsICJz
cmMvZHN0L2NoY3IgPSAleC8leC8leFxuIiwNCg0KJXBhZCBmb3Igc3JjL2RzdC4NCg0KPiArCQlj
ZmctPnNyYywgY2ZnLT5kc3QsIGNmZy0+Y2hjcik7DQo+ICsNCj4gKwlhdWRtYXBwX3dyaXRlKGF1
Y2hhbiwgY2ZnLT5zcmMsCVBETUFTQVIpOw0KPiArCWF1ZG1hcHBfd3JpdGUoYXVjaGFuLCBjZmct
PmRzdCwJUERNQURBUik7DQo+ICsJYXVkbWFwcF93cml0ZShhdWNoYW4sIGNoY3IsCVBETUFDSENS
KTsNCj4gK30NCj4gKw0KPiArc3RhdGljIHN0cnVjdCBhdWRtYXBwX3NsYXZlX2NvbmZpZyAqDQo+
ICthdWRtYXBwX2ZpbmRfc2xhdmUoc3RydWN0IGF1ZG1hcHBfY2hhbiAqYXVjaGFuLCBpbnQgc2xh
dmVfaWQpDQo+ICt7DQo+ICsJc3RydWN0IGF1ZG1hcHBfZGV2aWNlICphdWRldiA9IHRvX2Rldihh
dWNoYW4pOw0KPiArCXN0cnVjdCBhdWRtYXBwX3BkYXRhICpwZGF0YSA9IGF1ZGV2LT5wZGF0YTsN
Cj4gKwlzdHJ1Y3QgYXVkbWFwcF9zbGF2ZV9jb25maWcgKmNmZzsNCj4gKwlpbnQgaTsNCj4gKw0K
PiArCWlmIChzbGF2ZV9pZCA8IDAgfHwgc2xhdmVfaWQgPj0gQVVETUFQUF9TTEFWRV9OVU1CRVIp
DQo+ICsJCXJldHVybiBOVUxMOw0KPiArDQo+ICsJZm9yIChpID0gMCwgY2ZnID0gcGRhdGEtPnNs
YXZlOyBpIDwgcGRhdGEtPnNsYXZlX251bTsgaSsrLCBjZmcrKykNCj4gKwkJaWYgKGNmZy0+c2xh
dmVfaWQgPT0gc2xhdmVfaWQpDQo+ICsJCQlyZXR1cm4gY2ZnOw0KPiArDQo+ICsJcmV0dXJuIE5V
TEw7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgYXVkbWFwcF9zZXRfc2xhdmUoc3RydWN0IHNo
ZG1hX2NoYW4gKnNjaGFuLCBpbnQgc2xhdmVfaWQsDQo+ICsJCQkgICAgIGRtYV9hZGRyX3Qgc2xh
dmVfYWRkciwgYm9vbCB0cnkpDQo+ICt7DQo+ICsJc3RydWN0IGF1ZG1hcHBfY2hhbiAqYXVjaGFu
ID0gdG9fY2hhbihzY2hhbik7DQo+ICsJc3RydWN0IGF1ZG1hcHBfc2xhdmVfY29uZmlnICpjZmcg
PQ0KPiArCQlhdWRtYXBwX2ZpbmRfc2xhdmUoYXVjaGFuLCBzbGF2ZV9pZCk7DQo+ICsNCj4gKwlp
ZiAoIWNmZykNCj4gKwkJcmV0dXJuIC1FTk9ERVY7DQo+ICsJaWYgKHRyeSkNCj4gKwkJcmV0dXJu
IDA7DQo+ICsNCj4gKwlhdWNoYW4tPmNvbmZpZwk9IGNmZzsNCj4gKw0KPiArCXJldHVybiAwOw0K
PiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IGF1ZG1hcHBfZGVzY19zZXR1cChzdHJ1Y3Qgc2hkbWFf
Y2hhbiAqc2NoYW4sDQo+ICsJCQkgICAgICBzdHJ1Y3Qgc2hkbWFfZGVzYyAqc2RlY3MsDQo+ICsJ
CQkgICAgICBkbWFfYWRkcl90IHNyYywgZG1hX2FkZHJfdCBkc3QsIHNpemVfdCAqbGVuKQ0KPiAr
ew0KPiArCXN0cnVjdCBhdWRtYXBwX2NoYW4gKmF1Y2hhbiA9IHRvX2NoYW4oc2NoYW4pOw0KPiAr
CXN0cnVjdCBhdWRtYXBwX3NsYXZlX2NvbmZpZyAqY2ZnID0gYXVjaGFuLT5jb25maWc7DQo+ICsN
Cj4gKwlpZiAoIWNmZykNCj4gKwkJcmV0dXJuIC1FTk9ERVY7DQo+ICsNCj4gKwlpZiAoKmxlbiA+
IHNjaGFuLT5tYXhfeGZlcl9sZW4pDQo+ICsJCSpsZW4gPSBzY2hhbi0+bWF4X3hmZXJfbGVuOw0K
PiArDQo+ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2b2lkIGF1ZG1hcHBfc2V0
dXBfeGZlcihzdHJ1Y3Qgc2hkbWFfY2hhbiAqc2NoYW4sDQo+ICsJCQkgICAgICAgaW50IHNsYXZl
X2lkKQ0KPiArew0KPiArfQ0KPiArDQo+ICtzdGF0aWMgZG1hX2FkZHJfdCBhdWRtYXBwX3NsYXZl
X2FkZHIoc3RydWN0IHNoZG1hX2NoYW4gKnNjaGFuKQ0KPiArew0KPiArCXJldHVybiAwOyAvKiBh
bHdheXMgZml4ZWQgYWRkcmVzcyAqLw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgYm9vbCBhdWRtYXBw
X2NoYW5uZWxfYnVzeShzdHJ1Y3Qgc2hkbWFfY2hhbiAqc2NoYW4pDQo+ICt7DQo+ICsJc3RydWN0
IGF1ZG1hcHBfY2hhbiAqYXVjaGFuID0gdG9fY2hhbihzY2hhbik7DQo+ICsJdTMyIGNoY3IgPSBh
dWRtYXBwX3JlYWQoYXVjaGFuLCBQRE1BQ0hDUik7DQo+ICsNCj4gKwlyZXR1cm4gY2hjciAmIH5Q
RE1BQ0hDUl9ERTsNCj4gK30NCj4gKw0KPiArc3RhdGljIGJvb2wgYXVkbWFwcF9kZXNjX2NvbXBs
ZXRlZChzdHJ1Y3Qgc2hkbWFfY2hhbiAqc2NoYW4sDQo+ICsJCQkJICAgc3RydWN0IHNoZG1hX2Rl
c2MgKnNkZXNjKQ0KPiArew0KPiArCXJldHVybiB0cnVlOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMg
c3RydWN0IHNoZG1hX2Rlc2MgKmF1ZG1hcHBfZW1iZWRkZWRfZGVzYyh2b2lkICpidWYsIGludCBp
KQ0KPiArew0KPiArCXJldHVybiAmKChzdHJ1Y3Qgc2hkbWFfZGVzYyAqKWJ1ZilbaV07DQo+ICt9
DQo+ICsNCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgc2hkbWFfb3BzIGF1ZG1hcHBfc2hkbWFfb3Bz
ID0gew0KPiArCS5oYWx0X2NoYW5uZWwJPSBhdWRtYXBwX2hhbHQsDQo+ICsJLmRlc2Nfc2V0dXAJ
PSBhdWRtYXBwX2Rlc2Nfc2V0dXAsDQo+ICsJLnNldF9zbGF2ZQk9IGF1ZG1hcHBfc2V0X3NsYXZl
LA0KPiArCS5zdGFydF94ZmVyCT0gYXVkbWFwcF9zdGFydF94ZmVyLA0KPiArCS5lbWJlZGRlZF9k
ZXNjCT0gYXVkbWFwcF9lbWJlZGRlZF9kZXNjLA0KPiArCS5zZXR1cF94ZmVyCT0gYXVkbWFwcF9z
ZXR1cF94ZmVyLA0KPiArCS5zbGF2ZV9hZGRyCT0gYXVkbWFwcF9zbGF2ZV9hZGRyLA0KPiArCS5j
aGFubmVsX2J1c3kJPSBhdWRtYXBwX2NoYW5uZWxfYnVzeSwNCj4gKwkuZGVzY19jb21wbGV0ZWQJ
PSBhdWRtYXBwX2Rlc2NfY29tcGxldGVkLA0KPiArfTsNCj4gKw0KPiArc3RhdGljIGludCBhdWRt
YXBwX2NoYW5fcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiwNCj4gKwkJCSAgICAg
IHN0cnVjdCBhdWRtYXBwX2RldmljZSAqYXVkZXYsIGludCBpZCkNCj4gK3sNCj4gKwlzdHJ1Y3Qg
c2hkbWFfZGV2ICpzZGV2ID0gJmF1ZGV2LT5zaGRtYV9kZXY7DQo+ICsJc3RydWN0IGF1ZG1hcHBf
Y2hhbiAqYXVjaGFuOw0KPiArCXN0cnVjdCBzaGRtYV9jaGFuICpzY2hhbjsNCj4gKwlzdHJ1Y3Qg
ZGV2aWNlICpkZXYgPSBhdWRldi0+ZGV2Ow0KPiArDQo+ICsJYXVjaGFuID0gZGV2bV9remFsbG9j
KGRldiwgc2l6ZW9mKHN0cnVjdCBhdWRtYXBwX2NoYW4pLCBHRlBfS0VSTkVMKTsNCg0Kc2l6ZW9m
KCphdWNoYW4pDQoNCj4gKwlpZiAoIWF1Y2hhbikgew0KPiArCQlkZXZfZXJyKGRldiwgIk5vIGZy
ZWUgbWVtb3J5IGZvciBhbGxvY2F0aW5nIGRtYSBjaGFubmVscyFcbiIpOw0KPiArCQlyZXR1cm4g
LUVOT01FTTsNCj4gKwl9DQo+ICsNCj4gKwlzY2hhbiA9ICZhdWNoYW4tPnNoZG1hX2NoYW47DQo+
ICsJc2NoYW4tPm1heF94ZmVyX2xlbiA9IEFVRE1BUFBfTEVOX01BWDsNCj4gKw0KPiArCXNoZG1h
X2NoYW5fcHJvYmUoc2Rldiwgc2NoYW4sIGlkKTsNCj4gKw0KPiArCWF1Y2hhbi0+YmFzZSA9IGF1
ZGV2LT5jaGFuX3JlZyArIDB4MjAgKyAoMHgxMCAqIGlkKTsNCj4gKwlkZXZfZGJnKGRldiwgIiUw
MmQgOiAlcCAvICVwIiwgaWQsIGF1Y2hhbi0+YmFzZSwgYXVkZXYtPmNoYW5fcmVnKTsNCj4gKw0K
PiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBhdWRtYXBwX2NoYW5fcmVt
b3ZlKHN0cnVjdCBhdWRtYXBwX2RldmljZSAqYXVkZXYpDQo+ICt7DQo+ICsJc3RydWN0IGRtYV9k
ZXZpY2UgKmRtYV9kZXYgPSAmYXVkZXYtPnNoZG1hX2Rldi5kbWFfZGV2Ow0KPiArCXN0cnVjdCBz
aGRtYV9jaGFuICpzY2hhbjsNCj4gKwlpbnQgaTsNCj4gKw0KPiArCXNoZG1hX2Zvcl9lYWNoX2No
YW4oc2NoYW4sICZhdWRldi0+c2hkbWFfZGV2LCBpKSB7DQo+ICsJCUJVR19PTighc2NoYW4pOw0K
PiArCQlzaGRtYV9jaGFuX3JlbW92ZShzY2hhbik7DQo+ICsJfQ0KPiArCWRtYV9kZXYtPmNoYW5j
bnQgPSAwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IGF1ZG1hcHBfcHJvYmUoc3RydWN0IHBs
YXRmb3JtX2RldmljZSAqcGRldikNCj4gK3sNCj4gKwlzdHJ1Y3QgYXVkbWFwcF9wZGF0YSAqcGRh
dGEgPSBwZGV2LT5kZXYucGxhdGZvcm1fZGF0YTsNCj4gKwlzdHJ1Y3QgYXVkbWFwcF9kZXZpY2Ug
KmF1ZGV2Ow0KPiArCXN0cnVjdCBzaGRtYV9kZXYgKnNkZXY7DQo+ICsJc3RydWN0IGRtYV9kZXZp
Y2UgKmRtYV9kZXY7DQo+ICsJc3RydWN0IHJlc291cmNlICpyZXM7DQo+ICsJaW50IGVyciwgaTsN
Cj4gKw0KPiArCWlmICghcGRhdGEpDQo+ICsJCXJldHVybiAtRU5PREVWOw0KPiArDQo+ICsJcmVz
ID0gcGxhdGZvcm1fZ2V0X3Jlc291cmNlKHBkZXYsIElPUkVTT1VSQ0VfTUVNLCAwKTsNCj4gKw0K
PiArCWF1ZGV2ID0gZGV2bV9remFsbG9jKCZwZGV2LT5kZXYsIHNpemVvZihzdHJ1Y3QgYXVkbWFw
cF9kZXZpY2UpLA0KPiArCQkJICAgICBHRlBfS0VSTkVMKTsNCg0Kc2l6ZW9mKCphdWRldikNCg0K
PiArCWlmICghYXVkZXYpIHsNCj4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAiTm90IGVub3VnaCBt
ZW1vcnlcbiIpOw0KPiArCQlyZXR1cm4gLUVOT01FTTsNCj4gKwl9DQo+ICsNCj4gKwlhdWRldi0+
ZGV2CT0gJnBkZXYtPmRldjsNCj4gKwlhdWRldi0+cGRhdGEJPSBwZGF0YTsNCj4gKwlhdWRldi0+
Y2hhbl9yZWcJPSBkZXZtX2lvcmVtYXBfcmVzb3VyY2UoJnBkZXYtPmRldiwgcmVzKTsNCj4gKwlp
ZiAoSVNfRVJSKGF1ZGV2LT5jaGFuX3JlZykpDQo+ICsJCXJldHVybiBQVFJfRVJSKGF1ZGV2LT5j
aGFuX3JlZyk7DQo+ICsNCj4gKwlzZGV2CQk9ICZhdWRldi0+c2hkbWFfZGV2Ow0KPiArCXNkZXYt
Pm9wcwk9ICZhdWRtYXBwX3NoZG1hX29wczsNCj4gKwlzZGV2LT5kZXNjX3NpemUJPSBzaXplb2Yo
c3RydWN0IHNoZG1hX2Rlc2MpOw0KPiArDQo+ICsJZG1hX2RldgkJCT0gJnNkZXYtPmRtYV9kZXY7
DQo+ICsJZG1hX2Rldi0+Y29weV9hbGlnbgk9IExPRzJfREVGQVVMVF9YRkVSX1NJWkU7DQo+ICsJ
ZG1hX2NhcF9zZXQoRE1BX1NMQVZFLCBkbWFfZGV2LT5jYXBfbWFzayk7DQo+ICsNCj4gKwllcnIg
PSBzaGRtYV9pbml0KCZwZGV2LT5kZXYsIHNkZXYsIEFVRE1BUFBfTUFYX0NIQU5ORUxTKTsNCj4g
KwlpZiAoZXJyIDwgMCkNCj4gKwkJcmV0dXJuIGVycjsNCj4gKw0KPiArCXBsYXRmb3JtX3NldF9k
cnZkYXRhKHBkZXYsIGF1ZGV2KTsNCj4gKw0KPiArCS8qIENyZWF0ZSBETUEgQ2hhbm5lbCAqLw0K
PiArCWZvciAoaSA9IDA7IGkgPCBBVURNQVBQX01BWF9DSEFOTkVMUzsgaSsrKSB7DQo+ICsJCWVy
ciA9IGF1ZG1hcHBfY2hhbl9wcm9iZShwZGV2LCBhdWRldiwgaSk7DQo+ICsJCWlmIChlcnIpDQo+
ICsJCQlnb3RvIGNoYW5fcHJvYmVfZXJyOw0KPiArCX0NCj4gKw0KPiArCWVyciA9IGRtYV9hc3lu
Y19kZXZpY2VfcmVnaXN0ZXIoZG1hX2Rldik7DQo+ICsJaWYgKGVyciA8IDApDQo+ICsJCWdvdG8g
Y2hhbl9wcm9iZV9lcnI7DQo+ICsNCj4gKwlyZXR1cm4gZXJyOw0KPiArDQo+ICtjaGFuX3Byb2Jl
X2VycjoNCj4gKwlhdWRtYXBwX2NoYW5fcmVtb3ZlKGF1ZGV2KTsNCj4gKwlzaGRtYV9jbGVhbnVw
KHNkZXYpOw0KPiArDQo+ICsJcmV0dXJuIGVycjsNCj4gK30NCj4gKw0KPiArc3RhdGljIGludCBh
dWRtYXBwX3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQ0KPiArew0KPiArCXN0
cnVjdCBhdWRtYXBwX2RldmljZSAqYXVkZXYgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsN
Cj4gKwlzdHJ1Y3QgZG1hX2RldmljZSAqZG1hX2RldiA9ICZhdWRldi0+c2hkbWFfZGV2LmRtYV9k
ZXY7DQo+ICsNCj4gKwlkbWFfYXN5bmNfZGV2aWNlX3VucmVnaXN0ZXIoZG1hX2Rldik7DQo+ICsN
Cj4gKwlhdWRtYXBwX2NoYW5fcmVtb3ZlKGF1ZGV2KTsNCj4gKwlzaGRtYV9jbGVhbnVwKCZhdWRl
di0+c2hkbWFfZGV2KTsNCj4gKw0KPiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMg
c3RydWN0IHBsYXRmb3JtX2RyaXZlciBhdWRtYXBwX2RyaXZlciA9IHsNCj4gKwkucHJvYmUJCT0g
YXVkbWFwcF9wcm9iZSwNCj4gKwkucmVtb3ZlCQk9IGF1ZG1hcHBfcmVtb3ZlLA0KPiArCS5kcml2
ZXIJCT0gew0KPiArCQkub3duZXIJPSBUSElTX01PRFVMRSwNCj4gKwkJLm5hbWUJPSAicmNhci1h
dWRtYXBwLWVuZ2luZSIsDQo+ICsJfSwNCj4gK307DQo+ICttb2R1bGVfcGxhdGZvcm1fZHJpdmVy
KGF1ZG1hcHBfZHJpdmVyKTsNCj4gKw0KPiArTU9EVUxFX0FVVEhPUigiS3VuaW5vcmkgTW9yaW1v
dG8gPGt1bmlub3JpLm1vcmltb3RvLmd4QHJlbmVzYXMuY29tPiIpOw0KPiArTU9EVUxFX0RFU0NS
SVBUSU9OKCJSZW5lc2FzIFItQ2FyIEF1ZGlvIERNQUMgcGVyaS1wZXJpIGRyaXZlciIpOw0KPiAr
TU9EVUxFX0xJQ0VOU0UoIkdQTCIpOw0KPiBkaWZmIC0tZ2l0IGEvaW5jbHVkZS9saW51eC9wbGF0
Zm9ybV9kYXRhL2RtYS1yY2FyLWF1ZG1hcHAuaCBiL2luY2x1ZGUvbGludXgvcGxhdGZvcm1fZGF0
YS9kbWEtcmNhci1hdWRtYXBwLmgNCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gaW5kZXggMDAw
MDAwMC4uMzQ2ZGY2Ng0KPiAtLS0gL2Rldi9udWxsDQo+ICsrKyBiL2luY2x1ZGUvbGludXgvcGxh
dGZvcm1fZGF0YS9kbWEtcmNhci1hdWRtYXBwLmgNCj4gQEAgLTAsMCArMSwzNCBAQA0KPiArLyoN
Cj4gKyAqIGluY2x1ZGUvbGludXgvc2hfYXVkbWEtcHAuaA0KPiArICogICAgIFRoaXMgZmlsZSBp
cyBoZWFkZXIgZmlsZSBmb3IgQXVkaW8tRE1BQy1wcCBwZXJpcGhlcmFsLg0KPiArICoNCj4gKyAq
IENvcHlyaWdodCAoQykgMjAxMyBSZW5lc2FzIEVsZWN0cm9uaWNzIENvcnBvcmF0aW9uDQoNCjIw
MTQ/DQoNCj4gKyAqDQo+ICsgKiBUaGlzIGZpbGUgaXMgYmFzZWQgb24gdGhlIGluY2x1ZGUvbGlu
dXgvc2hfZG1hLmgNCj4gKyAqDQo+ICsgKiBIZWFkZXIgZm9yIHRoZSBuZXcgU0ggZG1hZW5naW5l
IGRyaXZlcg0KPiArICoNCj4gKyAqIENvcHlyaWdodCAoQykgMjAxMCBHdWVubmFkaSBMaWFraG92
ZXRza2kgPGcubGlha2hvdmV0c2tpQGdteC5kZT4NCj4gKyAqDQo+ICsgKiBUaGlzIHByb2dyYW0g
aXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQ0K
PiArICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z
ZSB2ZXJzaW9uIDIgYXMNCj4gKyAqIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3Vu
ZGF0aW9uLg0KPiArICovDQo+ICsjaWZuZGVmIFNIX0FVRE1BUFBfSA0KPiArI2RlZmluZSBTSF9B
VURNQVBQX0gNCj4gKw0KPiArI2luY2x1ZGUgPGxpbnV4L2RtYWVuZ2luZS5oPg0KPiArDQo+ICtz
dHJ1Y3QgYXVkbWFwcF9zbGF2ZV9jb25maWcgew0KPiArCWludAkJc2xhdmVfaWQ7DQo+ICsJZG1h
X2FkZHJfdAlzcmM7DQo+ICsJZG1hX2FkZHJfdAlkc3Q7DQo+ICsJdTMyCQljaGNyOw0KPiArfTsN
Cj4gKw0KPiArc3RydWN0IGF1ZG1hcHBfcGRhdGEgew0KPiArCXN0cnVjdCBhdWRtYXBwX3NsYXZl
X2NvbmZpZyAqc2xhdmU7DQo+ICsJaW50IHNsYXZlX251bTsNCj4gK307DQo+ICsNCj4gKyNlbmRp
ZiAvKiBTSF9BVURNQVBQX0ggKi8NCg0KDQotLSANCkFuZHkgU2hldmNoZW5rbyA8YW5kcml5LnNo
ZXZjaGVua29AaW50ZWwuY29tPg0KSW50ZWwgRmlubGFuZCBPeQ0KLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCkludGVs
IEZpbmxhbmQgT3kKUmVnaXN0ZXJlZCBBZGRyZXNzOiBQTCAyODEsIDAwMTgxIEhlbHNpbmtpIApC
dXNpbmVzcyBJZGVudGl0eSBDb2RlOiAwMzU3NjA2IC0gNCAKRG9taWNpbGVkIGluIEhlbHNpbmtp
IAoKVGhpcyBlLW1haWwgYW5kIGFueSBhdHRhY2htZW50cyBtYXkgY29udGFpbiBjb25maWRlbnRp
YWwgbWF0ZXJpYWwgZm9yCnRoZSBzb2xlIHVzZSBvZiB0aGUgaW50ZW5kZWQgcmVjaXBpZW50KHMp
LiBBbnkgcmV2aWV3IG9yIGRpc3RyaWJ1dGlvbgpieSBvdGhlcnMgaXMgc3RyaWN0bHkgcHJvaGli
aXRlZC4gSWYgeW91IGFyZSBub3QgdGhlIGludGVuZGVkCnJlY2lwaWVudCwgcGxlYXNlIGNvbnRh
Y3QgdGhlIHNlbmRlciBhbmQgZGVsZXRlIGFsbCBjb3BpZXMuCg=


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v2][RESENT] dma: add R-Car Audio DMAC peri peri driver
@ 2014-03-10  9:13     ` Shevchenko, Andriy
  0 siblings, 0 replies; 34+ 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,
	Geert Uytterhoeven, dmaengine

[-- 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] 34+ messages in thread

* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
  2014-03-10  2:25   ` Kuninori Morimoto
@ 2014-03-10  9:15     ` Shevchenko, Andriy
  -1 siblings, 0 replies; 34+ 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,
	Geert Uytterhoeven, dmaengine

T24gU3VuLCAyMDE0LTAzLTA5IGF0IDE5OjI1IC0wNzAwLCBLdW5pbm9yaSBNb3JpbW90byB3cm90
ZToNCj4gRnJvbTogS3VuaW5vcmkgTW9yaW1vdG8gPGt1bmlub3JpLm1vcmltb3RvLmd4QHJlbmVz
YXMuY29tPg0KPiANCj4gQWRkIHN1cHBvcnQgQXVkaW8gRE1BQyBwZXJpIHBlcmkgZHJpdmVyDQo+
IGZvciBSZW5lc2FzIFItQ2FyIEdlbjIgU29DLCB1c2luZyAnc2hkbWEtYmFzZScNCj4gRE1BIGRy
aXZlciBmcmFtZXdvcmsuDQo+IA0KPiBTaWduZWQtb2ZmLWJ5OiBLdW5pbm9yaSBNb3JpbW90byA8
a3VuaW5vcmkubW9yaW1vdG8uZ3hAcmVuZXNhcy5jb20+DQo+IC0tLQ0KPiB2MiAtPiB2Mw0KDQpN
eSBwcmV2aW91cyBtYWlsIGlzIGFwcGxpY2FibGUgdG8gdGhpcyB2ZXJzaW9uIHRvby4NCg0KLS0g
DQpBbmR5IFNoZXZjaGVua28gPGFuZHJpeS5zaGV2Y2hlbmtvQGludGVsLmNvbT4NCkludGVsIEZp
bmxhbmQgT3kNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpJbnRlbCBGaW5sYW5kIE95ClJlZ2lzdGVyZWQgQWRkcmVz
czogUEwgMjgxLCAwMDE4MSBIZWxzaW5raSAKQnVzaW5lc3MgSWRlbnRpdHkgQ29kZTogMDM1NzYw
NiAtIDQgCkRvbWljaWxlZCBpbiBIZWxzaW5raSAKClRoaXMgZS1tYWlsIGFuZCBhbnkgYXR0YWNo
bWVudHMgbWF5IGNvbnRhaW4gY29uZmlkZW50aWFsIG1hdGVyaWFsIGZvcgp0aGUgc29sZSB1c2Ug
b2YgdGhlIGludGVuZGVkIHJlY2lwaWVudChzKS4gQW55IHJldmlldyBvciBkaXN0cmlidXRpb24K
Ynkgb3RoZXJzIGlzIHN0cmljdGx5IHByb2hpYml0ZWQuIElmIHlvdSBhcmUgbm90IHRoZSBpbnRl
bmRlZApyZWNpcGllbnQsIHBsZWFzZSBjb250YWN0IHRoZSBzZW5kZXIgYW5kIGRlbGV0ZSBhbGwg
Y29waWVzLgo

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-03-10  9:15     ` Shevchenko, Andriy
  0 siblings, 0 replies; 34+ 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,
	Geert Uytterhoeven, dmaengine

[-- 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] 34+ messages in thread

* [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
  2014-01-24  2:32 ` Kuninori Morimoto
@ 2014-03-11  1:11   ` Kuninori Morimoto
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-03-11  1:11   ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ 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
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-03-25  1:08     ` Kuninori Morimoto
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
  2014-03-11  1:11   ` Kuninori Morimoto
@ 2014-03-29 14:20     ` Vinod Koul
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH v3] shdma: add R-Car Audio DMAC peri peri driver
@ 2014-03-29 14:20     ` Vinod Koul
  0 siblings, 0 replies; 34+ messages in thread
From: Vinod Koul @ 2014-03-29 14:20 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] 34+ messages in thread

end of thread, other threads:[~2014-03-29 14:20 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-24  2:32 [PATCH] shdma: add R-Car Audio DMAC peri peri driver Kuninori Morimoto
2014-01-24  2:32 ` Kuninori Morimoto
2014-01-24  7:34 ` Geert Uytterhoeven
2014-01-24  7:34   ` Geert Uytterhoeven
2014-01-24  8:18   ` Kuninori Morimoto
2014-01-24  8:18     ` Kuninori Morimoto
2014-01-24  8:33     ` Geert Uytterhoeven
2014-01-24  8:33       ` Geert Uytterhoeven
2014-01-24  8:58       ` Kuninori Morimoto
2014-01-24  8:58         ` Kuninori Morimoto
2014-01-24  9:06 ` [PATCH v2] dma: " Kuninori Morimoto
2014-01-24  9:06   ` Kuninori Morimoto
2014-02-12  5:29   ` Kuninori Morimoto
2014-02-12  5:29     ` Kuninori Morimoto
2014-02-25  5:13     ` Kuninori Morimoto
2014-02-25  5:13       ` Kuninori Morimoto
2014-03-10  1:34 ` [PATCH v2][RESENT] " Kuninori Morimoto
2014-03-10  1:34   ` Kuninori Morimoto
2014-03-10  1:47   ` Joe Perches
2014-03-10  1:47     ` Joe Perches
2014-03-10  2:19     ` Kuninori Morimoto
2014-03-10  2:19       ` Kuninori Morimoto
2014-03-10  9:13   ` Shevchenko, Andriy
2014-03-10  9:13     ` Shevchenko, Andriy
2014-03-10  2:25 ` [PATCH v3] shdma: " Kuninori Morimoto
2014-03-10  2:25   ` Kuninori Morimoto
2014-03-10  9:15   ` Shevchenko, Andriy
2014-03-10  9:15     ` Shevchenko, Andriy
2014-03-11  1:11 ` Kuninori Morimoto
2014-03-11  1:11   ` Kuninori Morimoto
2014-03-25  1:08   ` Kuninori Morimoto
2014-03-25  1:08     ` Kuninori Morimoto
2014-03-29 14:08   ` Vinod Koul
2014-03-29 14:20     ` Vinod Koul

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.