All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2 v5] Add I2S/ADV7511 audio support for ARC AXS10x boards
@ 2016-04-12 12:56 ` Jose Abreu
  0 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc, alsa-devel, linux-kernel, devicetree
  Cc: lgirdwood, broonie, perex, tiwai, robh+dt, CARLOS.PALMINHA, lars,
	Jose Abreu

Hi all,

This is v5 of these patches. In this version I dropped the ADV7511 audio patch
because, quoting Lars-Peter Clausen:
"The reason why this driver is still out of tree, is because there has been no
conclusion yet on how to go forward with the whole HDMI integration. So this
is not going to get merged until that issue has been addressed."

So, until that issue is addressed I will not send any ADV7511 audio related
patches but if for some reason anyone wants to merge it I can send the
pathes again. V4, which includes the ADV7511 audio patches is available at:
	http://mailman.alsa-project.org/pipermail/alsa-devel/2016-April/106650.html

Looking forward to your comments!

Best regards,
Jose Miguel Abreu

-----

ARC AXS10x platforms consist of a mainboard with several peripherals.
One of those peripherals is an HDMI output port controlled by the ADV7511
transmitter.

This patch set adds I2S audio for the AXS10x platform.

Changes v4 -> v5
* Resolve undefined references when compiling as module
* Dropped adv7511 audio patches
* Use DMA properties in I2S to check which mode to use: PIO or DMA (as suggested by Lars-Peter Clausen)

Changes v3 -> v4:
* Reintroduced custom PCM driver (see note below)
* Use DT boolean to switch between ALSA DMA engine PCM or custom PCM
* Use fifo depth to program I2S FCR
* Update I2S documentation

Changes v2 -> v3:
* Removed pll_config functions (as suggested by Alexey Brodkin)
* Removed HDMI start at adv7511_core (as suggested by Archit Taneja)
* Use NOP functions for adv7511_audio (as suggested by Archit Taneja)
* Added adv7511_audio_exit() function (as suggested by Archit Taneja)
* Moved adv7511 to its own folder (as suggested by Archit Taneja)
* Separated file rename of adv7511_core (as suggested by Emil Velikov)
* Compile adv7511 as module if ALSA SoC is compiled as module
* Load adv7511 audio only if declared in device tree (as suggested by Laurent Pinchart)
* Dropped custom platform driver, using now ALSA DMA engine
* Dropped IRQ handler for I2S

Changes v1 -> v2:
* DT bindings moved to separate patch (as suggested by Alexey Brodkin)
* Removed defconfigs entries (as suggested by Alexey Brodkin)


NOTE:
Although the mainline I2S driver uses ALSA DMA engine,
this controller can be built without DMA support so it
was necessary to add this custom platform driver so that
HDMI audio works in AXS boards.

Jose Abreu (2):
  ASoC: dwc: Add custom PCM driver
  ASoC: dwc: Update DOCUMENTATION for I2S Driver

 .../devicetree/bindings/sound/designware-i2s.txt   |   9 +-
 sound/soc/dwc/Kconfig                              |   9 +
 sound/soc/dwc/Makefile                             |   1 +
 sound/soc/dwc/designware.h                         |  71 +++++++
 sound/soc/dwc/designware_i2s.c                     |  94 ++++++---
 sound/soc/dwc/designware_pcm.c                     | 230 +++++++++++++++++++++
 6 files changed, 385 insertions(+), 29 deletions(-)
 create mode 100644 sound/soc/dwc/designware.h
 create mode 100644 sound/soc/dwc/designware_pcm.c

-- 
1.9.1

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

* [PATCH 0/2 v5] Add I2S/ADV7511 audio support for ARC AXS10x boards
@ 2016-04-12 12:56 ` Jose Abreu
  0 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w,
	lars-Qo5EllUWu/uELgA04lAiVw, Jose Abreu

Hi all,

This is v5 of these patches. In this version I dropped the ADV7511 audio patch
because, quoting Lars-Peter Clausen:
"The reason why this driver is still out of tree, is because there has been no
conclusion yet on how to go forward with the whole HDMI integration. So this
is not going to get merged until that issue has been addressed."

So, until that issue is addressed I will not send any ADV7511 audio related
patches but if for some reason anyone wants to merge it I can send the
pathes again. V4, which includes the ADV7511 audio patches is available at:
	http://mailman.alsa-project.org/pipermail/alsa-devel/2016-April/106650.html

Looking forward to your comments!

Best regards,
Jose Miguel Abreu

-----

ARC AXS10x platforms consist of a mainboard with several peripherals.
One of those peripherals is an HDMI output port controlled by the ADV7511
transmitter.

This patch set adds I2S audio for the AXS10x platform.

Changes v4 -> v5
* Resolve undefined references when compiling as module
* Dropped adv7511 audio patches
* Use DMA properties in I2S to check which mode to use: PIO or DMA (as suggested by Lars-Peter Clausen)

Changes v3 -> v4:
* Reintroduced custom PCM driver (see note below)
* Use DT boolean to switch between ALSA DMA engine PCM or custom PCM
* Use fifo depth to program I2S FCR
* Update I2S documentation

Changes v2 -> v3:
* Removed pll_config functions (as suggested by Alexey Brodkin)
* Removed HDMI start at adv7511_core (as suggested by Archit Taneja)
* Use NOP functions for adv7511_audio (as suggested by Archit Taneja)
* Added adv7511_audio_exit() function (as suggested by Archit Taneja)
* Moved adv7511 to its own folder (as suggested by Archit Taneja)
* Separated file rename of adv7511_core (as suggested by Emil Velikov)
* Compile adv7511 as module if ALSA SoC is compiled as module
* Load adv7511 audio only if declared in device tree (as suggested by Laurent Pinchart)
* Dropped custom platform driver, using now ALSA DMA engine
* Dropped IRQ handler for I2S

Changes v1 -> v2:
* DT bindings moved to separate patch (as suggested by Alexey Brodkin)
* Removed defconfigs entries (as suggested by Alexey Brodkin)


NOTE:
Although the mainline I2S driver uses ALSA DMA engine,
this controller can be built without DMA support so it
was necessary to add this custom platform driver so that
HDMI audio works in AXS boards.

Jose Abreu (2):
  ASoC: dwc: Add custom PCM driver
  ASoC: dwc: Update DOCUMENTATION for I2S Driver

 .../devicetree/bindings/sound/designware-i2s.txt   |   9 +-
 sound/soc/dwc/Kconfig                              |   9 +
 sound/soc/dwc/Makefile                             |   1 +
 sound/soc/dwc/designware.h                         |  71 +++++++
 sound/soc/dwc/designware_i2s.c                     |  94 ++++++---
 sound/soc/dwc/designware_pcm.c                     | 230 +++++++++++++++++++++
 6 files changed, 385 insertions(+), 29 deletions(-)
 create mode 100644 sound/soc/dwc/designware.h
 create mode 100644 sound/soc/dwc/designware_pcm.c

-- 
1.9.1


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 0/2 v5] Add I2S/ADV7511 audio support for ARC AXS10x boards
@ 2016-04-12 12:56 ` Jose Abreu
  0 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc

Hi all,

This is v5 of these patches. In this version I dropped the ADV7511 audio patch
because, quoting Lars-Peter Clausen:
"The reason why this driver is still out of tree, is because there has been no
conclusion yet on how to go forward with the whole HDMI integration. So this
is not going to get merged until that issue has been addressed."

So, until that issue is addressed I will not send any ADV7511 audio related
patches but if for some reason anyone wants to merge it I can send the
pathes again. V4, which includes the ADV7511 audio patches is available at:
	http://mailman.alsa-project.org/pipermail/alsa-devel/2016-April/106650.html

Looking forward to your comments!

Best regards,
Jose Miguel Abreu

-----

ARC AXS10x platforms consist of a mainboard with several peripherals.
One of those peripherals is an HDMI output port controlled by the ADV7511
transmitter.

This patch set adds I2S audio for the AXS10x platform.

Changes v4 -> v5
* Resolve undefined references when compiling as module
* Dropped adv7511 audio patches
* Use DMA properties in I2S to check which mode to use: PIO or DMA (as suggested by Lars-Peter Clausen)

Changes v3 -> v4:
* Reintroduced custom PCM driver (see note below)
* Use DT boolean to switch between ALSA DMA engine PCM or custom PCM
* Use fifo depth to program I2S FCR
* Update I2S documentation

Changes v2 -> v3:
* Removed pll_config functions (as suggested by Alexey Brodkin)
* Removed HDMI start at adv7511_core (as suggested by Archit Taneja)
* Use NOP functions for adv7511_audio (as suggested by Archit Taneja)
* Added adv7511_audio_exit() function (as suggested by Archit Taneja)
* Moved adv7511 to its own folder (as suggested by Archit Taneja)
* Separated file rename of adv7511_core (as suggested by Emil Velikov)
* Compile adv7511 as module if ALSA SoC is compiled as module
* Load adv7511 audio only if declared in device tree (as suggested by Laurent Pinchart)
* Dropped custom platform driver, using now ALSA DMA engine
* Dropped IRQ handler for I2S

Changes v1 -> v2:
* DT bindings moved to separate patch (as suggested by Alexey Brodkin)
* Removed defconfigs entries (as suggested by Alexey Brodkin)


NOTE:
Although the mainline I2S driver uses ALSA DMA engine,
this controller can be built without DMA support so it
was necessary to add this custom platform driver so that
HDMI audio works in AXS boards.

Jose Abreu (2):
  ASoC: dwc: Add custom PCM driver
  ASoC: dwc: Update DOCUMENTATION for I2S Driver

 .../devicetree/bindings/sound/designware-i2s.txt   |   9 +-
 sound/soc/dwc/Kconfig                              |   9 +
 sound/soc/dwc/Makefile                             |   1 +
 sound/soc/dwc/designware.h                         |  71 +++++++
 sound/soc/dwc/designware_i2s.c                     |  94 ++++++---
 sound/soc/dwc/designware_pcm.c                     | 230 +++++++++++++++++++++
 6 files changed, 385 insertions(+), 29 deletions(-)
 create mode 100644 sound/soc/dwc/designware.h
 create mode 100644 sound/soc/dwc/designware_pcm.c

-- 
1.9.1

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

* [PATCH 1/2 v5] ASoC: dwc: Add custom PCM driver
  2016-04-12 12:56 ` Jose Abreu
@ 2016-04-12 12:56   ` Jose Abreu
  -1 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc, alsa-devel, linux-kernel, devicetree
  Cc: lgirdwood, broonie, perex, tiwai, robh+dt, CARLOS.PALMINHA, lars,
	Jose Abreu

HDMI audio support was added to the AXS board using an
I2S cpu driver and a custom platform driver.

The platform driver supports two channels @ 16 bits with
rates 32k, 44.1k and 48k.

Although the mainline I2S driver uses ALSA DMA engine,
this controller can be built without DMA support so it
was necessary to add this custom platform driver so that
HDMI audio works in AXS boards.

The selection between the use of DMA engine or PIO mode
is detected by declaring or not the DMA parameters in
the device tree.

Signed-off-by: Jose Abreu <joabreu@synopsys.com>
---

Changes v4 -> v5:
* Resolve undefined references when compiling as module
* Use DMA properties in I2S to check which mode to use: PIO or DMA (as suggested by Lars-Peter Clausen)

Changes v3 -> v4:
* Reintroduced custom PCM driver
* Use DT boolean to switch between ALSA DMA engine PCM or custom PCM

Changes v2 -> v3:
* Removed pll_config functions (as suggested by Alexey Brodkin)
* Dropped custom platform driver, using now ALSA DMA engine
* Dropped IRQ handler for I2S

No changes v1 -> v2.

 sound/soc/dwc/Kconfig          |   9 ++
 sound/soc/dwc/Makefile         |   1 +
 sound/soc/dwc/designware.h     |  71 +++++++++++++
 sound/soc/dwc/designware_i2s.c |  94 ++++++++++++-----
 sound/soc/dwc/designware_pcm.c | 230 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 378 insertions(+), 27 deletions(-)
 create mode 100644 sound/soc/dwc/designware.h
 create mode 100644 sound/soc/dwc/designware_pcm.c

diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig
index d50e085..2a21120 100644
--- a/sound/soc/dwc/Kconfig
+++ b/sound/soc/dwc/Kconfig
@@ -7,4 +7,13 @@ config SND_DESIGNWARE_I2S
 	 Synopsys desigwnware I2S device. The device supports upto
 	 maximum of 8 channels each for play and record.
 
+config SND_DESIGNWARE_PCM
+	tristate "Synopsys I2S PCM Driver"
+	help
+	 Say Y or M if you want to add support for ALSA ASoC platform driver
+	 using I2S.
+
+	 Select this option if you want to be able to create a sound interface
+	 using the I2S device driver as CPU driver. Instead of using ALSA
+	 DMA engine by selecting this driver a custom PCM driver will be used.
 
diff --git a/sound/soc/dwc/Makefile b/sound/soc/dwc/Makefile
index 319371f..1b48bccc 100644
--- a/sound/soc/dwc/Makefile
+++ b/sound/soc/dwc/Makefile
@@ -1,3 +1,4 @@
 # SYNOPSYS Platform Support
 obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o
+obj-$(CONFIG_SND_DESIGNWARE_PCM) += designware_pcm.o
 
diff --git a/sound/soc/dwc/designware.h b/sound/soc/dwc/designware.h
new file mode 100644
index 0000000..f702ed1
--- /dev/null
+++ b/sound/soc/dwc/designware.h
@@ -0,0 +1,71 @@
+/*
+ * ALSA SoC Synopsys Audio Layer
+ *
+ * sound/soc/dwc/designware.h
+ *
+ * Copyright (C) 2016 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __DESIGNWARE_H
+#define __DESIGNWARE_H
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <sound/designware_i2s.h>
+#include <sound/dmaengine_pcm.h>
+
+struct dw_pcm_binfo {
+	struct snd_pcm_substream *stream;
+	unsigned char *dma_base;
+	unsigned char *dma_pointer;
+	unsigned int period_size_frames;
+	unsigned int size;
+	snd_pcm_uframes_t period_pointer;
+	unsigned int total_periods;
+	unsigned int current_period;
+};
+
+union dw_i2s_snd_dma_data {
+	struct i2s_dma_data pd;
+	struct snd_dmaengine_dai_dma_data dt;
+};
+
+struct dw_i2s_dev {
+	void __iomem *i2s_base;
+	struct clk *clk;
+	int active;
+	unsigned int capability;
+	unsigned int quirks;
+	unsigned int i2s_reg_comp1;
+	unsigned int i2s_reg_comp2;
+	struct device *dev;
+	u32 ccr;
+	u32 xfer_resolution;
+	u32 fifo_th;
+
+	/* data related to DMA transfers b/w i2s and DMAC */
+	bool use_dmaengine;
+	union dw_i2s_snd_dma_data play_dma_data;
+	union dw_i2s_snd_dma_data capture_dma_data;
+	struct i2s_clk_config_data config;
+	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
+	struct dw_pcm_binfo binfo;
+};
+
+#if defined(CONFIG_SND_DESIGNWARE_PCM) || \
+	defined(CONFIG_SND_DESIGNWARE_PCM_MODULE)
+int dw_pcm_transfer(u32 *lsample, u32 *rsample, int bytes, int buf_size,
+		struct dw_pcm_binfo *bi);
+#else
+int dw_pcm_transfer(u32 *lsample, u32 *rsample, int bytes, int buf_size,
+		struct dw_pcm_binfo *bi)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 0db69b7..3040a14 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -24,6 +24,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
+#include "designware.h"
 
 /* common register for all channel */
 #define IER		0x000
@@ -84,31 +85,6 @@
 #define MAX_CHANNEL_NUM		8
 #define MIN_CHANNEL_NUM		2
 
-union dw_i2s_snd_dma_data {
-	struct i2s_dma_data pd;
-	struct snd_dmaengine_dai_dma_data dt;
-};
-
-struct dw_i2s_dev {
-	void __iomem *i2s_base;
-	struct clk *clk;
-	int active;
-	unsigned int capability;
-	unsigned int quirks;
-	unsigned int i2s_reg_comp1;
-	unsigned int i2s_reg_comp2;
-	struct device *dev;
-	u32 ccr;
-	u32 xfer_resolution;
-	u32 fifo_th;
-
-	/* data related to DMA transfers b/w i2s and DMAC */
-	union dw_i2s_snd_dma_data play_dma_data;
-	union dw_i2s_snd_dma_data capture_dma_data;
-	struct i2s_clk_config_data config;
-	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
-};
-
 static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
 {
 	writel(val, io_base + reg);
@@ -145,6 +121,54 @@ static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream)
 	}
 }
 
+static irqreturn_t dw_i2s_irq_handler(int irq, void *dev_id)
+{
+	struct dw_i2s_dev *dev = dev_id;
+	u32 isr[4], sleft[dev->fifo_th], sright[dev->fifo_th];
+	int i, j, xfer_bytes = dev->config.data_width / 8;
+	int dir = dev->binfo.stream->stream;
+
+	for (i = 0; i < 4; i++)
+		isr[i] = i2s_read_reg(dev->i2s_base, ISR(i));
+
+	i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK);
+	i2s_clear_irqs(dev, SNDRV_PCM_STREAM_CAPTURE);
+
+	if (dev->use_dmaengine)
+		return IRQ_HANDLED;
+
+	for (i = 0; i < 4; i++) {
+		/* Copy only to/from first two channels
+		 * TODO: Remaining channels
+		 */
+		if ((isr[i] & 0x10) && (i == 0) &&
+				(dir == SNDRV_PCM_STREAM_PLAYBACK)) {
+			/* TXFEM - TX FIFO is empty */
+			dw_pcm_transfer(sleft, sright, xfer_bytes, dev->fifo_th,
+					&dev->binfo);
+			for (j = 0; j < dev->fifo_th; j++) {
+				i2s_write_reg(dev->i2s_base, LRBR_LTHR(i),
+						sleft[j]);
+				i2s_write_reg(dev->i2s_base, RRBR_RTHR(i),
+						sright[j]);
+			}
+		} else if ((isr[i] & 0x01) && (i == 0) &&
+				(dir == SNDRV_PCM_STREAM_CAPTURE)) {
+			/* RXDAM - RX FIFO is full */
+			for (j = 0; j < dev->fifo_th; j++) {
+				sleft[j] = i2s_read_reg(dev->i2s_base,
+						LRBR_LTHR(i));
+				sright[j] = i2s_read_reg(dev->i2s_base,
+						RRBR_RTHR(i));
+			}
+			dw_pcm_transfer(sleft, sright, xfer_bytes, dev->fifo_th,
+					&dev->binfo);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static void i2s_start(struct dw_i2s_dev *dev,
 		      struct snd_pcm_substream *substream)
 {
@@ -626,7 +650,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 	const struct i2s_platform_data *pdata = pdev->dev.platform_data;
 	struct dw_i2s_dev *dev;
 	struct resource *res;
-	int ret;
+	int ret, irq_number;
 	struct snd_soc_dai_driver *dw_i2s_dai;
 	const char *clk_id;
 
@@ -649,6 +673,19 @@ static int dw_i2s_probe(struct platform_device *pdev)
 	if (IS_ERR(dev->i2s_base))
 		return PTR_ERR(dev->i2s_base);
 
+	irq_number = platform_get_irq(pdev, 0);
+	if (irq_number <= 0) {
+		dev_err(&pdev->dev, "get_irq fail\n");
+		return -EINVAL;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq_number, dw_i2s_irq_handler,
+			IRQF_SHARED, "dw_i2s_irq_handler", dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "request_irq fail\n");
+		return ret;
+	}
+
 	dev->dev = &pdev->dev;
 
 	dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
@@ -657,6 +694,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 		dev->capability = pdata->cap;
 		clk_id = NULL;
 		dev->quirks = pdata->quirks;
+		dev->use_dmaengine = false;
 		if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
 			dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
 			dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
@@ -664,6 +702,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
 		ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
 	} else {
 		clk_id = "i2sclk";
+		dev->use_dmaengine = of_property_read_bool(pdev->dev.of_node,
+				"dmas");
 		ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res);
 	}
 	if (ret < 0)
@@ -695,7 +735,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 		goto err_clk_disable;
 	}
 
-	if (!pdata) {
+	if (dev->use_dmaengine) {
 		ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 		if (ret) {
 			dev_err(&pdev->dev,
diff --git a/sound/soc/dwc/designware_pcm.c b/sound/soc/dwc/designware_pcm.c
new file mode 100644
index 0000000..8926e40
--- /dev/null
+++ b/sound/soc/dwc/designware_pcm.c
@@ -0,0 +1,230 @@
+/*
+ * Synopsys I2S PCM Driver
+ *
+ * Copyright (C) 2016 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include "designware.h"
+
+#define BUFFER_BYTES_MAX	384000
+#define PERIOD_BYTES_MIN	2048
+#define PERIODS_MIN		8
+
+static const struct snd_pcm_hardware dw_pcm_hardware = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.rates = SNDRV_PCM_RATE_32000 |
+		SNDRV_PCM_RATE_44100 |
+		SNDRV_PCM_RATE_48000,
+	.rate_min = 32000,
+	.rate_max = 48000,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
+	.periods_min = PERIODS_MIN,
+	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+};
+
+int dw_pcm_transfer(u32 *lsample, u32 *rsample, int bytes, int buf_size,
+		struct dw_pcm_binfo *bi)
+{
+	struct snd_pcm_runtime *rt = bi->stream->runtime;
+	int dir = bi->stream->stream;
+	int i;
+
+	for (i = 0; i < buf_size; i++) {
+		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+			memcpy(&lsample[i], bi->dma_pointer, bytes);
+			bi->dma_pointer += bytes;
+			memcpy(&rsample[i], bi->dma_pointer, bytes);
+			bi->dma_pointer += bytes;
+		} else {
+			memcpy(bi->dma_pointer, &lsample[i], bytes);
+			bi->dma_pointer += bytes;
+			memcpy(bi->dma_pointer, &rsample[i], bytes);
+			bi->dma_pointer += bytes;
+		}
+	}
+
+	bi->period_pointer += bytes_to_frames(rt, bytes * 2 * buf_size);
+
+	if (bi->period_pointer >= (bi->period_size_frames * bi->current_period)) {
+		bi->current_period++;
+		if (bi->current_period > bi->total_periods) {
+			bi->dma_pointer = bi->dma_base;
+			bi->period_pointer = 0;
+			bi->current_period = 1;
+		}
+		snd_pcm_period_elapsed(bi->stream);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_pcm_transfer);
+
+static int dw_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+	snd_soc_set_runtime_hwparams(substream, &dw_pcm_hardware);
+	snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
+
+	dev->binfo.stream = substream;
+	rt->private_data = &dev->binfo;
+	return 0;
+}
+
+static int dw_pcm_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static int dw_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_pcm_binfo *bi = rt->private_data;
+	int ret;
+
+	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+			params_buffer_bytes(hw_params));
+	if (ret < 0)
+		return ret;
+
+	memset(rt->dma_area, 0, params_buffer_bytes(hw_params));
+	bi->dma_base = rt->dma_area;
+	bi->dma_pointer = bi->dma_base;
+
+	return 0;
+}
+
+static int dw_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	int ret;
+
+	ret = snd_pcm_lib_free_vmalloc_buffer(substream);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int dw_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_pcm_binfo *bi = rt->private_data;
+	u32 buffer_size_frames = 0;
+
+	bi->period_size_frames = bytes_to_frames(rt,
+			snd_pcm_lib_period_bytes(substream));
+	bi->size = snd_pcm_lib_buffer_bytes(substream);
+	buffer_size_frames = bytes_to_frames(rt, bi->size);
+	bi->total_periods = buffer_size_frames / bi->period_size_frames;
+	bi->current_period = 1;
+
+	if ((buffer_size_frames % bi->period_size_frames) != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_pcm_binfo *bi = rt->private_data;
+
+	return bi->period_pointer;
+}
+
+static struct snd_pcm_ops dw_pcm_ops = {
+	.open = dw_pcm_open,
+	.close = dw_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = dw_pcm_hw_params,
+	.hw_free = dw_pcm_hw_free,
+	.prepare = dw_pcm_prepare,
+	.trigger = dw_pcm_trigger,
+	.pointer = dw_pcm_pointer,
+	.page = snd_pcm_lib_get_vmalloc_page,
+	.mmap = snd_pcm_lib_mmap_vmalloc,
+};
+
+static int dw_pcm_new(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_pcm *pcm = runtime->pcm;
+
+	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+			snd_dma_continuous_data(GFP_KERNEL), BUFFER_BYTES_MAX,
+			BUFFER_BYTES_MAX);
+}
+
+static void dw_pcm_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static struct snd_soc_platform_driver dw_pcm_platform = {
+	.pcm_new = dw_pcm_new,
+	.pcm_free = dw_pcm_free,
+	.ops = &dw_pcm_ops,
+};
+
+static int dw_pcm_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_platform(&pdev->dev, &dw_pcm_platform);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dw_pcm_of[] = {
+	{ .compatible = "snps,designware-pcm" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dw_pcm_of);
+#endif
+
+static struct platform_driver dw_pcm_driver = {
+	.driver = {
+		.name = "designware-pcm",
+		.of_match_table = of_match_ptr(dw_pcm_of),
+	},
+	.probe = dw_pcm_probe,
+};
+module_platform_driver(dw_pcm_driver);
+
+MODULE_AUTHOR("Jose Abreu <joabreu@synopsys.com>, Tiago Duarte");
+MODULE_DESCRIPTION("Synopsys Designware PCM Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

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

* [PATCH 1/2 v5] ASoC: dwc: Add custom PCM driver
@ 2016-04-12 12:56   ` Jose Abreu
  0 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc

HDMI audio support was added to the AXS board using an
I2S cpu driver and a custom platform driver.

The platform driver supports two channels @ 16 bits with
rates 32k, 44.1k and 48k.

Although the mainline I2S driver uses ALSA DMA engine,
this controller can be built without DMA support so it
was necessary to add this custom platform driver so that
HDMI audio works in AXS boards.

The selection between the use of DMA engine or PIO mode
is detected by declaring or not the DMA parameters in
the device tree.

Signed-off-by: Jose Abreu <joabreu at synopsys.com>
---

Changes v4 -> v5:
* Resolve undefined references when compiling as module
* Use DMA properties in I2S to check which mode to use: PIO or DMA (as suggested by Lars-Peter Clausen)

Changes v3 -> v4:
* Reintroduced custom PCM driver
* Use DT boolean to switch between ALSA DMA engine PCM or custom PCM

Changes v2 -> v3:
* Removed pll_config functions (as suggested by Alexey Brodkin)
* Dropped custom platform driver, using now ALSA DMA engine
* Dropped IRQ handler for I2S

No changes v1 -> v2.

 sound/soc/dwc/Kconfig          |   9 ++
 sound/soc/dwc/Makefile         |   1 +
 sound/soc/dwc/designware.h     |  71 +++++++++++++
 sound/soc/dwc/designware_i2s.c |  94 ++++++++++++-----
 sound/soc/dwc/designware_pcm.c | 230 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 378 insertions(+), 27 deletions(-)
 create mode 100644 sound/soc/dwc/designware.h
 create mode 100644 sound/soc/dwc/designware_pcm.c

diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig
index d50e085..2a21120 100644
--- a/sound/soc/dwc/Kconfig
+++ b/sound/soc/dwc/Kconfig
@@ -7,4 +7,13 @@ config SND_DESIGNWARE_I2S
 	 Synopsys desigwnware I2S device. The device supports upto
 	 maximum of 8 channels each for play and record.
 
+config SND_DESIGNWARE_PCM
+	tristate "Synopsys I2S PCM Driver"
+	help
+	 Say Y or M if you want to add support for ALSA ASoC platform driver
+	 using I2S.
+
+	 Select this option if you want to be able to create a sound interface
+	 using the I2S device driver as CPU driver. Instead of using ALSA
+	 DMA engine by selecting this driver a custom PCM driver will be used.
 
diff --git a/sound/soc/dwc/Makefile b/sound/soc/dwc/Makefile
index 319371f..1b48bccc 100644
--- a/sound/soc/dwc/Makefile
+++ b/sound/soc/dwc/Makefile
@@ -1,3 +1,4 @@
 # SYNOPSYS Platform Support
 obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o
+obj-$(CONFIG_SND_DESIGNWARE_PCM) += designware_pcm.o
 
diff --git a/sound/soc/dwc/designware.h b/sound/soc/dwc/designware.h
new file mode 100644
index 0000000..f702ed1
--- /dev/null
+++ b/sound/soc/dwc/designware.h
@@ -0,0 +1,71 @@
+/*
+ * ALSA SoC Synopsys Audio Layer
+ *
+ * sound/soc/dwc/designware.h
+ *
+ * Copyright (C) 2016 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __DESIGNWARE_H
+#define __DESIGNWARE_H
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <sound/designware_i2s.h>
+#include <sound/dmaengine_pcm.h>
+
+struct dw_pcm_binfo {
+	struct snd_pcm_substream *stream;
+	unsigned char *dma_base;
+	unsigned char *dma_pointer;
+	unsigned int period_size_frames;
+	unsigned int size;
+	snd_pcm_uframes_t period_pointer;
+	unsigned int total_periods;
+	unsigned int current_period;
+};
+
+union dw_i2s_snd_dma_data {
+	struct i2s_dma_data pd;
+	struct snd_dmaengine_dai_dma_data dt;
+};
+
+struct dw_i2s_dev {
+	void __iomem *i2s_base;
+	struct clk *clk;
+	int active;
+	unsigned int capability;
+	unsigned int quirks;
+	unsigned int i2s_reg_comp1;
+	unsigned int i2s_reg_comp2;
+	struct device *dev;
+	u32 ccr;
+	u32 xfer_resolution;
+	u32 fifo_th;
+
+	/* data related to DMA transfers b/w i2s and DMAC */
+	bool use_dmaengine;
+	union dw_i2s_snd_dma_data play_dma_data;
+	union dw_i2s_snd_dma_data capture_dma_data;
+	struct i2s_clk_config_data config;
+	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
+	struct dw_pcm_binfo binfo;
+};
+
+#if defined(CONFIG_SND_DESIGNWARE_PCM) || \
+	defined(CONFIG_SND_DESIGNWARE_PCM_MODULE)
+int dw_pcm_transfer(u32 *lsample, u32 *rsample, int bytes, int buf_size,
+		struct dw_pcm_binfo *bi);
+#else
+int dw_pcm_transfer(u32 *lsample, u32 *rsample, int bytes, int buf_size,
+		struct dw_pcm_binfo *bi)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 0db69b7..3040a14 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -24,6 +24,7 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
+#include "designware.h"
 
 /* common register for all channel */
 #define IER		0x000
@@ -84,31 +85,6 @@
 #define MAX_CHANNEL_NUM		8
 #define MIN_CHANNEL_NUM		2
 
-union dw_i2s_snd_dma_data {
-	struct i2s_dma_data pd;
-	struct snd_dmaengine_dai_dma_data dt;
-};
-
-struct dw_i2s_dev {
-	void __iomem *i2s_base;
-	struct clk *clk;
-	int active;
-	unsigned int capability;
-	unsigned int quirks;
-	unsigned int i2s_reg_comp1;
-	unsigned int i2s_reg_comp2;
-	struct device *dev;
-	u32 ccr;
-	u32 xfer_resolution;
-	u32 fifo_th;
-
-	/* data related to DMA transfers b/w i2s and DMAC */
-	union dw_i2s_snd_dma_data play_dma_data;
-	union dw_i2s_snd_dma_data capture_dma_data;
-	struct i2s_clk_config_data config;
-	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
-};
-
 static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
 {
 	writel(val, io_base + reg);
@@ -145,6 +121,54 @@ static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream)
 	}
 }
 
+static irqreturn_t dw_i2s_irq_handler(int irq, void *dev_id)
+{
+	struct dw_i2s_dev *dev = dev_id;
+	u32 isr[4], sleft[dev->fifo_th], sright[dev->fifo_th];
+	int i, j, xfer_bytes = dev->config.data_width / 8;
+	int dir = dev->binfo.stream->stream;
+
+	for (i = 0; i < 4; i++)
+		isr[i] = i2s_read_reg(dev->i2s_base, ISR(i));
+
+	i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK);
+	i2s_clear_irqs(dev, SNDRV_PCM_STREAM_CAPTURE);
+
+	if (dev->use_dmaengine)
+		return IRQ_HANDLED;
+
+	for (i = 0; i < 4; i++) {
+		/* Copy only to/from first two channels
+		 * TODO: Remaining channels
+		 */
+		if ((isr[i] & 0x10) && (i == 0) &&
+				(dir == SNDRV_PCM_STREAM_PLAYBACK)) {
+			/* TXFEM - TX FIFO is empty */
+			dw_pcm_transfer(sleft, sright, xfer_bytes, dev->fifo_th,
+					&dev->binfo);
+			for (j = 0; j < dev->fifo_th; j++) {
+				i2s_write_reg(dev->i2s_base, LRBR_LTHR(i),
+						sleft[j]);
+				i2s_write_reg(dev->i2s_base, RRBR_RTHR(i),
+						sright[j]);
+			}
+		} else if ((isr[i] & 0x01) && (i == 0) &&
+				(dir == SNDRV_PCM_STREAM_CAPTURE)) {
+			/* RXDAM - RX FIFO is full */
+			for (j = 0; j < dev->fifo_th; j++) {
+				sleft[j] = i2s_read_reg(dev->i2s_base,
+						LRBR_LTHR(i));
+				sright[j] = i2s_read_reg(dev->i2s_base,
+						RRBR_RTHR(i));
+			}
+			dw_pcm_transfer(sleft, sright, xfer_bytes, dev->fifo_th,
+					&dev->binfo);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static void i2s_start(struct dw_i2s_dev *dev,
 		      struct snd_pcm_substream *substream)
 {
@@ -626,7 +650,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 	const struct i2s_platform_data *pdata = pdev->dev.platform_data;
 	struct dw_i2s_dev *dev;
 	struct resource *res;
-	int ret;
+	int ret, irq_number;
 	struct snd_soc_dai_driver *dw_i2s_dai;
 	const char *clk_id;
 
@@ -649,6 +673,19 @@ static int dw_i2s_probe(struct platform_device *pdev)
 	if (IS_ERR(dev->i2s_base))
 		return PTR_ERR(dev->i2s_base);
 
+	irq_number = platform_get_irq(pdev, 0);
+	if (irq_number <= 0) {
+		dev_err(&pdev->dev, "get_irq fail\n");
+		return -EINVAL;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq_number, dw_i2s_irq_handler,
+			IRQF_SHARED, "dw_i2s_irq_handler", dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "request_irq fail\n");
+		return ret;
+	}
+
 	dev->dev = &pdev->dev;
 
 	dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
@@ -657,6 +694,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 		dev->capability = pdata->cap;
 		clk_id = NULL;
 		dev->quirks = pdata->quirks;
+		dev->use_dmaengine = false;
 		if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
 			dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
 			dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
@@ -664,6 +702,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
 		ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
 	} else {
 		clk_id = "i2sclk";
+		dev->use_dmaengine = of_property_read_bool(pdev->dev.of_node,
+				"dmas");
 		ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res);
 	}
 	if (ret < 0)
@@ -695,7 +735,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 		goto err_clk_disable;
 	}
 
-	if (!pdata) {
+	if (dev->use_dmaengine) {
 		ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
 		if (ret) {
 			dev_err(&pdev->dev,
diff --git a/sound/soc/dwc/designware_pcm.c b/sound/soc/dwc/designware_pcm.c
new file mode 100644
index 0000000..8926e40
--- /dev/null
+++ b/sound/soc/dwc/designware_pcm.c
@@ -0,0 +1,230 @@
+/*
+ * Synopsys I2S PCM Driver
+ *
+ * Copyright (C) 2016 Synopsys
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include "designware.h"
+
+#define BUFFER_BYTES_MAX	384000
+#define PERIOD_BYTES_MIN	2048
+#define PERIODS_MIN		8
+
+static const struct snd_pcm_hardware dw_pcm_hardware = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.rates = SNDRV_PCM_RATE_32000 |
+		SNDRV_PCM_RATE_44100 |
+		SNDRV_PCM_RATE_48000,
+	.rate_min = 32000,
+	.rate_max = 48000,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
+	.periods_min = PERIODS_MIN,
+	.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
+};
+
+int dw_pcm_transfer(u32 *lsample, u32 *rsample, int bytes, int buf_size,
+		struct dw_pcm_binfo *bi)
+{
+	struct snd_pcm_runtime *rt = bi->stream->runtime;
+	int dir = bi->stream->stream;
+	int i;
+
+	for (i = 0; i < buf_size; i++) {
+		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+			memcpy(&lsample[i], bi->dma_pointer, bytes);
+			bi->dma_pointer += bytes;
+			memcpy(&rsample[i], bi->dma_pointer, bytes);
+			bi->dma_pointer += bytes;
+		} else {
+			memcpy(bi->dma_pointer, &lsample[i], bytes);
+			bi->dma_pointer += bytes;
+			memcpy(bi->dma_pointer, &rsample[i], bytes);
+			bi->dma_pointer += bytes;
+		}
+	}
+
+	bi->period_pointer += bytes_to_frames(rt, bytes * 2 * buf_size);
+
+	if (bi->period_pointer >= (bi->period_size_frames * bi->current_period)) {
+		bi->current_period++;
+		if (bi->current_period > bi->total_periods) {
+			bi->dma_pointer = bi->dma_base;
+			bi->period_pointer = 0;
+			bi->current_period = 1;
+		}
+		snd_pcm_period_elapsed(bi->stream);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_pcm_transfer);
+
+static int dw_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+	snd_soc_set_runtime_hwparams(substream, &dw_pcm_hardware);
+	snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
+
+	dev->binfo.stream = substream;
+	rt->private_data = &dev->binfo;
+	return 0;
+}
+
+static int dw_pcm_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static int dw_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *hw_params)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_pcm_binfo *bi = rt->private_data;
+	int ret;
+
+	ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+			params_buffer_bytes(hw_params));
+	if (ret < 0)
+		return ret;
+
+	memset(rt->dma_area, 0, params_buffer_bytes(hw_params));
+	bi->dma_base = rt->dma_area;
+	bi->dma_pointer = bi->dma_base;
+
+	return 0;
+}
+
+static int dw_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	int ret;
+
+	ret = snd_pcm_lib_free_vmalloc_buffer(substream);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int dw_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_pcm_binfo *bi = rt->private_data;
+	u32 buffer_size_frames = 0;
+
+	bi->period_size_frames = bytes_to_frames(rt,
+			snd_pcm_lib_period_bytes(substream));
+	bi->size = snd_pcm_lib_buffer_bytes(substream);
+	buffer_size_frames = bytes_to_frames(rt, bi->size);
+	bi->total_periods = buffer_size_frames / bi->period_size_frames;
+	bi->current_period = 1;
+
+	if ((buffer_size_frames % bi->period_size_frames) != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct dw_pcm_binfo *bi = rt->private_data;
+
+	return bi->period_pointer;
+}
+
+static struct snd_pcm_ops dw_pcm_ops = {
+	.open = dw_pcm_open,
+	.close = dw_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = dw_pcm_hw_params,
+	.hw_free = dw_pcm_hw_free,
+	.prepare = dw_pcm_prepare,
+	.trigger = dw_pcm_trigger,
+	.pointer = dw_pcm_pointer,
+	.page = snd_pcm_lib_get_vmalloc_page,
+	.mmap = snd_pcm_lib_mmap_vmalloc,
+};
+
+static int dw_pcm_new(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_pcm *pcm = runtime->pcm;
+
+	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+			snd_dma_continuous_data(GFP_KERNEL), BUFFER_BYTES_MAX,
+			BUFFER_BYTES_MAX);
+}
+
+static void dw_pcm_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static struct snd_soc_platform_driver dw_pcm_platform = {
+	.pcm_new = dw_pcm_new,
+	.pcm_free = dw_pcm_free,
+	.ops = &dw_pcm_ops,
+};
+
+static int dw_pcm_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_platform(&pdev->dev, &dw_pcm_platform);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dw_pcm_of[] = {
+	{ .compatible = "snps,designware-pcm" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dw_pcm_of);
+#endif
+
+static struct platform_driver dw_pcm_driver = {
+	.driver = {
+		.name = "designware-pcm",
+		.of_match_table = of_match_ptr(dw_pcm_of),
+	},
+	.probe = dw_pcm_probe,
+};
+module_platform_driver(dw_pcm_driver);
+
+MODULE_AUTHOR("Jose Abreu <joabreu at synopsys.com>, Tiago Duarte");
+MODULE_DESCRIPTION("Synopsys Designware PCM Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

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

* [PATCH 2/2 v5] ASoC: dwc: Update DOCUMENTATION for I2S Driver
@ 2016-04-12 12:56   ` Jose Abreu
  0 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc, alsa-devel, linux-kernel, devicetree
  Cc: lgirdwood, broonie, perex, tiwai, robh+dt, CARLOS.PALMINHA, lars,
	Jose Abreu

This patch updates documentation for the Designware I2S
driver.

Signed-off-by: Jose Abreu <joabreu@synopsys.com>
---

Changes v4 -> v5:
* interrupts is now required property
* Drop 'snps-use-dmaengine' property

This patch was only introduced in v4.

 Documentation/devicetree/bindings/sound/designware-i2s.txt | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt
index 7bb5424..9c1fecd 100644
--- a/Documentation/devicetree/bindings/sound/designware-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/designware-i2s.txt
@@ -3,14 +3,18 @@ DesignWare I2S controller
 Required properties:
  - compatible : Must be "snps,designware-i2s"
  - reg : Must contain the I2S core's registers location and length
+ - interrupts: <IRQ> where IRQ is the interrupt number.
  - clocks : Pairs of phandle and specifier referencing the controller's
    clocks. The controller expects one clock: the clock used as the sampling
    rate reference clock sample.
  - clock-names : "i2sclk" for the sample rate reference clock.
+
+Optional properties:
  - dmas: Pairs of phandle and specifier for the DMA channels that are used by
    the core. The core expects one or two dma channels: one for transmit and
-   one for receive.
- - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+   one for receive. Set this parameter if the I2S DMA block is enabled.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel. Set
+   this parameter if the I2S DMA block is enabled.
 
 For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
 properties please check:
@@ -23,6 +27,7 @@ Example:
 	soc_i2s: i2s@7ff90000 {
 		compatible = "snps,designware-i2s";
 		reg = <0x0 0x7ff90000 0x0 0x1000>;
+		interrupts = <15>;
 		clocks = <&scpi_i2sclk 0>;
 		clock-names = "i2sclk";
 		#sound-dai-cells = <0>;
-- 
1.9.1

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

* [PATCH 2/2 v5] ASoC: dwc: Update DOCUMENTATION for I2S Driver
@ 2016-04-12 12:56   ` Jose Abreu
  0 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w,
	lars-Qo5EllUWu/uELgA04lAiVw, Jose Abreu

This patch updates documentation for the Designware I2S
driver.

Signed-off-by: Jose Abreu <joabreu-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
---

Changes v4 -> v5:
* interrupts is now required property
* Drop 'snps-use-dmaengine' property

This patch was only introduced in v4.

 Documentation/devicetree/bindings/sound/designware-i2s.txt | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt
index 7bb5424..9c1fecd 100644
--- a/Documentation/devicetree/bindings/sound/designware-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/designware-i2s.txt
@@ -3,14 +3,18 @@ DesignWare I2S controller
 Required properties:
  - compatible : Must be "snps,designware-i2s"
  - reg : Must contain the I2S core's registers location and length
+ - interrupts: <IRQ> where IRQ is the interrupt number.
  - clocks : Pairs of phandle and specifier referencing the controller's
    clocks. The controller expects one clock: the clock used as the sampling
    rate reference clock sample.
  - clock-names : "i2sclk" for the sample rate reference clock.
+
+Optional properties:
  - dmas: Pairs of phandle and specifier for the DMA channels that are used by
    the core. The core expects one or two dma channels: one for transmit and
-   one for receive.
- - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+   one for receive. Set this parameter if the I2S DMA block is enabled.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel. Set
+   this parameter if the I2S DMA block is enabled.
 
 For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
 properties please check:
@@ -23,6 +27,7 @@ Example:
 	soc_i2s: i2s@7ff90000 {
 		compatible = "snps,designware-i2s";
 		reg = <0x0 0x7ff90000 0x0 0x1000>;
+		interrupts = <15>;
 		clocks = <&scpi_i2sclk 0>;
 		clock-names = "i2sclk";
 		#sound-dai-cells = <0>;
-- 
1.9.1


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/2 v5] ASoC: dwc: Update DOCUMENTATION for I2S Driver
@ 2016-04-12 12:56   ` Jose Abreu
  0 siblings, 0 replies; 11+ messages in thread
From: Jose Abreu @ 2016-04-12 12:56 UTC (permalink / raw)
  To: linux-snps-arc

This patch updates documentation for the Designware I2S
driver.

Signed-off-by: Jose Abreu <joabreu at synopsys.com>
---

Changes v4 -> v5:
* interrupts is now required property
* Drop 'snps-use-dmaengine' property

This patch was only introduced in v4.

 Documentation/devicetree/bindings/sound/designware-i2s.txt | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt
index 7bb5424..9c1fecd 100644
--- a/Documentation/devicetree/bindings/sound/designware-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/designware-i2s.txt
@@ -3,14 +3,18 @@ DesignWare I2S controller
 Required properties:
  - compatible : Must be "snps,designware-i2s"
  - reg : Must contain the I2S core's registers location and length
+ - interrupts: <IRQ> where IRQ is the interrupt number.
  - clocks : Pairs of phandle and specifier referencing the controller's
    clocks. The controller expects one clock: the clock used as the sampling
    rate reference clock sample.
  - clock-names : "i2sclk" for the sample rate reference clock.
+
+Optional properties:
  - dmas: Pairs of phandle and specifier for the DMA channels that are used by
    the core. The core expects one or two dma channels: one for transmit and
-   one for receive.
- - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+   one for receive. Set this parameter if the I2S DMA block is enabled.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel. Set
+   this parameter if the I2S DMA block is enabled.
 
 For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
 properties please check:
@@ -23,6 +27,7 @@ Example:
 	soc_i2s: i2s at 7ff90000 {
 		compatible = "snps,designware-i2s";
 		reg = <0x0 0x7ff90000 0x0 0x1000>;
+		interrupts = <15>;
 		clocks = <&scpi_i2sclk 0>;
 		clock-names = "i2sclk";
 		#sound-dai-cells = <0>;
-- 
1.9.1

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

* Re: [PATCH 2/2 v5] ASoC: dwc: Update DOCUMENTATION for I2S Driver
@ 2016-04-13 20:17     ` Rob Herring
  0 siblings, 0 replies; 11+ messages in thread
From: Rob Herring @ 2016-04-13 20:17 UTC (permalink / raw)
  To: Jose Abreu
  Cc: linux-snps-arc, alsa-devel, linux-kernel, devicetree, lgirdwood,
	broonie, perex, tiwai, CARLOS.PALMINHA, lars

On Tue, Apr 12, 2016 at 01:56:28PM +0100, Jose Abreu wrote:
> This patch updates documentation for the Designware I2S
> driver.
> 
> Signed-off-by: Jose Abreu <joabreu@synopsys.com>
> ---
> 
> Changes v4 -> v5:
> * interrupts is now required property
> * Drop 'snps-use-dmaengine' property
> 
> This patch was only introduced in v4.
> 
>  Documentation/devicetree/bindings/sound/designware-i2s.txt | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH 2/2 v5] ASoC: dwc: Update DOCUMENTATION for I2S Driver
@ 2016-04-13 20:17     ` Rob Herring
  0 siblings, 0 replies; 11+ messages in thread
From: Rob Herring @ 2016-04-13 20:17 UTC (permalink / raw)
  To: Jose Abreu
  Cc: linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w,
	lars-Qo5EllUWu/uELgA04lAiVw

On Tue, Apr 12, 2016 at 01:56:28PM +0100, Jose Abreu wrote:
> This patch updates documentation for the Designware I2S
> driver.
> 
> Signed-off-by: Jose Abreu <joabreu-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
> ---
> 
> Changes v4 -> v5:
> * interrupts is now required property
> * Drop 'snps-use-dmaengine' property
> 
> This patch was only introduced in v4.
> 
>  Documentation/devicetree/bindings/sound/designware-i2s.txt | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/2 v5] ASoC: dwc: Update DOCUMENTATION for I2S Driver
@ 2016-04-13 20:17     ` Rob Herring
  0 siblings, 0 replies; 11+ messages in thread
From: Rob Herring @ 2016-04-13 20:17 UTC (permalink / raw)
  To: linux-snps-arc

On Tue, Apr 12, 2016@01:56:28PM +0100, Jose Abreu wrote:
> This patch updates documentation for the Designware I2S
> driver.
> 
> Signed-off-by: Jose Abreu <joabreu at synopsys.com>
> ---
> 
> Changes v4 -> v5:
> * interrupts is now required property
> * Drop 'snps-use-dmaengine' property
> 
> This patch was only introduced in v4.
> 
>  Documentation/devicetree/bindings/sound/designware-i2s.txt | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)

Acked-by: Rob Herring <robh at kernel.org>

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

end of thread, other threads:[~2016-04-13 20:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-12 12:56 [PATCH 0/2 v5] Add I2S/ADV7511 audio support for ARC AXS10x boards Jose Abreu
2016-04-12 12:56 ` Jose Abreu
2016-04-12 12:56 ` Jose Abreu
2016-04-12 12:56 ` [PATCH 1/2 v5] ASoC: dwc: Add custom PCM driver Jose Abreu
2016-04-12 12:56   ` Jose Abreu
2016-04-12 12:56 ` [PATCH 2/2 v5] ASoC: dwc: Update DOCUMENTATION for I2S Driver Jose Abreu
2016-04-12 12:56   ` Jose Abreu
2016-04-12 12:56   ` Jose Abreu
2016-04-13 20:17   ` Rob Herring
2016-04-13 20:17     ` Rob Herring
2016-04-13 20:17     ` Rob Herring

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.