linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support
@ 2019-08-30 21:06 Miquel Raynal
  2019-08-30 21:06 ` [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings Miquel Raynal
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Miquel Raynal @ 2019-08-30 21:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai
  Cc: Mark Rutland, devicetree, alsa-devel, Michal Simek, Rob Herring,
	Thomas Petazzoni, Miquel Raynal, alexandre, linux-arm-kernel

This IP is very simple so this driver manage both the DAI and the PCM
streams, hence the presence of both components in this driver.

There are plenty available interruptions when capturing or playing
back audio that can be triggered but the only one that fits the ALSA
sound system is the XFER_DONE which is used to bound sound
periods. Other interrupts are masked. Please note that capture and
playback are not possible at the same time though.

Capture seems to work (at least it creates a file with something
inside) but I have no capture mechanism on the board to actually test
that it works correctly.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---

Hello,

This is my first contribution in the sound subsystem, I hope I've
understood the core but I might be entirely wrong as well, so please
do not hesitate to be critical on my choices.

Thanks,
Miquèl

 sound/soc/xilinx/Kconfig            |   7 +
 sound/soc/xilinx/Makefile           |   2 +
 sound/soc/xilinx/xlnx-logicpd-i2s.c | 468 ++++++++++++++++++++++++++++
 3 files changed, 477 insertions(+)
 create mode 100644 sound/soc/xilinx/xlnx-logicpd-i2s.c

diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig
index 47f606b924e4..b62cae6750b9 100644
--- a/sound/soc/xilinx/Kconfig
+++ b/sound/soc/xilinx/Kconfig
@@ -7,6 +7,13 @@ config SND_SOC_XILINX_I2S
 	  PCM data. In receiver mode, IP receives PCM audio and
 	  encapsulates PCM in AES format and sends AES data.
 
+config SND_SOC_XILINX_LOGICPD_I2S
+	tristate "Audio support for the Xilinx logicPD I2S"
+	help
+	  Select this option to enable Xilinx logicPD I2S slave
+	  transceiver. This enables I2S playback and capture using
+	  Xilinx/logicPD IP.
+
 config SND_SOC_XILINX_AUDIO_FORMATTER
         tristate "Audio support for the the Xilinx audio formatter"
         help
diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile
index d79fd38b094b..d127c30f8fe2 100644
--- a/sound/soc/xilinx/Makefile
+++ b/sound/soc/xilinx/Makefile
@@ -1,5 +1,7 @@
 snd-soc-xlnx-i2s-objs      := xlnx_i2s.o
 obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o
+snd-soc-xlnx-logicpd-i2s-objs := xlnx-logicpd-i2s.o
+obj-$(CONFIG_SND_SOC_XILINX_LOGICPD_I2S) += snd-soc-xlnx-logicpd-i2s.o
 snd-soc-xlnx-formatter-pcm-objs := xlnx_formatter_pcm.o
 obj-$(CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER) += snd-soc-xlnx-formatter-pcm.o
 snd-soc-xlnx-spdif-objs := xlnx_spdif.o
diff --git a/sound/soc/xilinx/xlnx-logicpd-i2s.c b/sound/soc/xilinx/xlnx-logicpd-i2s.c
new file mode 100644
index 000000000000..325a5bb6978a
--- /dev/null
+++ b/sound/soc/xilinx/xlnx-logicpd-i2s.c
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx logicPD logiI2S - I2S slave transceiver v2 support
+ *
+ * Copyright (C) 2019 Bootlin
+ *
+ * Author: Miquel Raynal <miquel.raynal@bootlin.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "xlnx_logicpd_i2s"
+
+#define IP_VERSION 0x0
+#define   PATCH_LEVEL(reg) (((reg) & GENMASK(4, 0)) + 'a')
+#define   MINOR_REV(reg) (((reg) & GENMASK(10, 5)) >> 5)
+#define   MAJOR_REV(reg) (((reg) & GENMASK(16, 11)) >> 11)
+#define   LICENSE_TYPE(reg) (((reg) & GENMASK(18, 17)) >> 17)
+#define CONTROL_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x4 : 0x24)
+#define   ENGINE_EN BIT(0)
+#define   XFER_DONE BIT(1)
+#define BUFF_BASE_ADDR_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x8 : 0x28)
+#define BUFF_LEN_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0xC : 0x2C)
+#define FIFO_STAT_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x10 : 0x30)
+#define INTR_MASK_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x14 : 0x34)
+#define   XFER_DONE_INTR BIT(31)
+#define INTR_STAT_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x18 : 0x38)
+#define   FIFO_COUNT(reg) ((reg) >> 20)
+
+#define BYTES_TO_WORDS(n) ((n) / 4)
+
+/* Arbitrarily chosen period size */
+#define PCM_PERIOD_WORDS SZ_8K
+#define PCM_PERIOD_BYTES (PCM_PERIOD_WORDS * 4)
+/* This is the actual maximum size that can actually be moved in one chunk */
+#define PCM_BUF_WORDS (SZ_64K - 1)
+#define PCM_BUF_BYTES (PCM_BUF_WORDS * 4)
+
+struct xlnx_logicpd_i2s;
+
+/**
+ * struct xlnx_logicpd_stream - Internal stream representation
+ *
+ * @i2s: Chip data
+ * @substream: Core substream structure
+ * @period_idx: Index of the period within the circular buffer
+ */
+struct xlnx_logicpd_stream {
+	struct xlnx_logicpd_i2s *i2s;
+	struct snd_pcm_substream *substream;
+	unsigned int period_idx;
+};
+
+/**
+ * struct xlnx_logicpd_i2s - Chip structure
+ *
+ * @base: Registers base address
+ * @streams: Playback and capture streams in an array
+ */
+struct xlnx_logicpd_i2s {
+	void __iomem *base;
+	struct xlnx_logicpd_stream streams[2];
+};
+
+static struct xlnx_logicpd_i2s *substream_to_cpu_dai_chip(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+	return snd_soc_dai_get_drvdata(rtd->cpu_dai);
+}
+
+/* PCM methods */
+
+static const struct snd_pcm_hardware xlnx_logicpd_pcm_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_HALF_DUPLEX,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_8000_192000,
+	.rate_min = 8000,
+	.rate_max = 192000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.period_bytes_min = 0,
+	.period_bytes_max = PCM_PERIOD_BYTES,
+	.periods_min = 0,
+	.periods_max = -1,
+	.buffer_bytes_max = PCM_BUF_BYTES,
+};
+
+static int xlnx_logicpd_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct xlnx_logicpd_i2s *i2s = substream_to_cpu_dai_chip(substream);
+	unsigned int dir = substream->stream;
+
+	snd_soc_set_runtime_hwparams(substream, &xlnx_logicpd_pcm_hardware);
+
+	i2s->streams[dir].substream = substream;
+
+	return 0;
+}
+
+static int xlnx_logicpd_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct xlnx_logicpd_i2s *i2s = substream_to_cpu_dai_chip(substream);
+	unsigned int dir = substream->stream;
+
+	i2s->streams[dir].substream = NULL;
+
+	return 0;
+}
+
+static int xlnx_logicpd_pcm_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = params_buffer_bytes(params);
+
+	return 0;
+}
+
+static snd_pcm_uframes_t xlnx_logicpd_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct xlnx_logicpd_i2s *i2s = substream_to_cpu_dai_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int period_sz = snd_pcm_lib_period_bytes(substream);
+	unsigned int dir = substream->stream;
+
+	return bytes_to_frames(runtime,
+			       i2s->streams[dir].period_idx * period_sz);
+}
+
+static int xlnx_logicpd_pcm_mmap(struct snd_pcm_substream *substream,
+				 struct vm_area_struct *vma)
+{
+	return remap_pfn_range(vma, vma->vm_start,
+			       substream->dma_buffer.addr >> PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static const struct snd_pcm_ops xlnx_logicpd_pcm_ops = {
+	.open = xlnx_logicpd_pcm_open,
+	.close = xlnx_logicpd_pcm_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = xlnx_logicpd_pcm_hw_params,
+	.pointer = xlnx_logicpd_pcm_pointer,
+	.mmap = xlnx_logicpd_pcm_mmap,
+};
+
+static int xlnx_logicpd_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int dir;
+
+	for (dir = SNDRV_PCM_STREAM_PLAYBACK;
+	     dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
+		substream = pcm->streams[dir].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		buf->area = dma_alloc_coherent(pcm->card->dev, PCM_BUF_BYTES,
+					       &buf->addr, GFP_KERNEL);
+		buf->bytes = PCM_BUF_BYTES;
+		if (!buf->area)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void xlnx_logicpd_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int dir;
+
+	for (dir = SNDRV_PCM_STREAM_PLAYBACK;
+	     dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
+		substream = pcm->streams[dir].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				  buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static const struct snd_soc_component_driver xlnx_logicpd_pcm_component = {
+	.name = "xlnx-logicp-pcm",
+	.ops = &xlnx_logicpd_pcm_ops,
+	.pcm_new = xlnx_logicpd_pcm_new,
+	.pcm_free = xlnx_logicpd_pcm_free,
+};
+
+/* DAI methods */
+
+static void xlnx_logicpd_dai_int_en(struct xlnx_logicpd_i2s *i2s, int dir)
+{
+	u32 reg;
+
+	reg = readl_relaxed(i2s->base + INTR_MASK_REG(dir));
+	reg &= ~XFER_DONE_INTR;
+	writel(reg, i2s->base + INTR_MASK_REG(dir));
+}
+
+static void xlnx_logicpd_dai_int_dis(struct xlnx_logicpd_i2s *i2s, int dir)
+{
+	u32 reg;
+
+	reg = readl_relaxed(i2s->base + INTR_MASK_REG(dir));
+	reg |= XFER_DONE_INTR;
+	writel_relaxed(reg, i2s->base + INTR_MASK_REG(dir));
+}
+
+static irqreturn_t xlnx_logicpd_dai_isr(int irq, void *dev_id)
+{
+	struct xlnx_logicpd_stream *stream = dev_id;
+	struct xlnx_logicpd_i2s *i2s = stream->i2s;
+	struct snd_pcm_substream *substream = stream->substream;
+	unsigned int period_sz = snd_pcm_lib_period_bytes(substream);
+	unsigned int buf_sz = snd_pcm_lib_buffer_bytes(substream);
+	dma_addr_t buf_addr = substream->dma_buffer.addr;
+	unsigned int dir = substream->stream;
+	u32 reg;
+
+	/* Reading INTR_STAT deasserts the host interrupt */
+	reg = readl_relaxed(i2s->base + INTR_STAT_REG(dir));
+
+	/*
+	 * When the XFER_DONE interrupt is triggered, it means the period has
+	 * been entirely shifted into the FIFO. At this point, we can move the
+	 * buffer pointer to the next period and ask to transfer another chunk
+	 * of data. Whenever the FIFO will be at its "almost full" state (4096
+	 * words minus the threshold of 100 words) the internal DMA engine will
+	 * automatically restart shifting data to the FIFO until its full state.
+	 * Hence, the host has up to 3996 words (in our case, 3996 frames) to
+	 * serve the interrupt before an underrun that would happen, at eg.
+	 * 44100Hz, after 90ms.
+	 */
+	if (reg & XFER_DONE_INTR) {
+		unsigned int offset_in_buf = ++stream->period_idx * period_sz;
+
+		if (offset_in_buf >= buf_sz) {
+			stream->period_idx = 0;
+			offset_in_buf = stream->period_idx * period_sz;
+		}
+
+		/* Move on to the next period in the overall buffer */
+		writel_relaxed(buf_addr + offset_in_buf,
+			       i2s->base + BUFF_BASE_ADDR_REG(dir));
+		/* The last period might be smaller, update length if needed */
+		period_sz = min(period_sz, buf_sz - offset_in_buf);
+		writel_relaxed(BYTES_TO_WORDS(period_sz),
+			       i2s->base + BUFF_LEN_REG(dir));
+
+		/* Inform the PCM middle-layer */
+		snd_pcm_period_elapsed(substream);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int xlnx_logicpd_dai_trigger(struct snd_pcm_substream *substream,
+				    int cmd, struct snd_soc_dai *dai)
+{
+	struct xlnx_logicpd_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int period_sz = snd_pcm_lib_period_bytes(substream);
+	dma_addr_t buf_addr = substream->dma_buffer.addr;
+	unsigned int dir = substream->stream;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		i2s->streams[dir].period_idx = 0;
+		/* Disable the other engine if enabled */
+		if (readl(i2s->base + CONTROL_REG(!dir)) & ENGINE_EN)
+			writel(0, i2s->base + CONTROL_REG(!dir));
+		/* Enable the desired engine */
+		writel_relaxed(ENGINE_EN, i2s->base + CONTROL_REG(dir));
+		/* Set the buffer start address */
+		writel_relaxed(buf_addr, i2s->base + BUFF_BASE_ADDR_REG(dir));
+		/* Enable the XFER_DONE IRQ, signaling the end of the period */
+		xlnx_logicpd_dai_int_en(i2s, dir);
+		/* Actually start the internal DMA engine */
+		writel(BYTES_TO_WORDS(period_sz),
+		       i2s->base + BUFF_LEN_REG(dir));
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* Disable the interrupts */
+		xlnx_logicpd_dai_int_dis(i2s, dir);
+		/* Ensure the host IRQ is deasserted */
+		readl_relaxed(i2s->base + INTR_STAT_REG(dir));
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops xlnx_logicpd_dai_ops = {
+	.trigger = xlnx_logicpd_dai_trigger,
+};
+
+static int xlnx_logicpd_dai_probe(struct snd_soc_dai *dai)
+{
+	struct xlnx_logicpd_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+	unsigned int dir;
+
+	for (dir = SNDRV_PCM_STREAM_PLAYBACK;
+	     dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
+		i2s->streams[dir].i2s = i2s;
+
+		/* Reset the transmitter/receiver engine */
+		writel_relaxed(0, i2s->base + CONTROL_REG(dir));
+		/* Mask all interrupts */
+		writel_relaxed(GENMASK(31, 0), i2s->base + INTR_MASK_REG(dir));
+	}
+
+	return 0;
+}
+
+struct snd_soc_dai_driver xlnx_logicpd_dai = {
+	.name = "xylinx-logicpd-dai",
+	.probe = xlnx_logicpd_dai_probe,
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.rate_min = 8000,
+		.rate_max = 192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_192000,
+		.rate_min = 8000,
+		.rate_max = 192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.symmetric_rates = 1,
+	.ops = &xlnx_logicpd_dai_ops,
+};
+
+static const struct snd_soc_component_driver xlnx_logicpd_i2s_component = {
+	.name = DRV_NAME,
+	.ops = &xlnx_logicpd_pcm_ops,
+};
+
+static const struct of_device_id xlnx_logicpd_i2s_of_match[] = {
+	{
+		.compatible = "xlnx,logicpd-i2s-dai",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, xlnx_logicpd_i2s_of_match);
+
+static int xlnx_logicpd_i2s_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct xlnx_logicpd_i2s *i2s;
+	struct xlnx_logicpd_stream *stream;
+	int tx_irq, rx_irq, ret;
+	u32 reg;
+
+	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
+	if (!i2s)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, i2s);
+
+	i2s->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(i2s->base))
+		return PTR_ERR(i2s->base);
+
+	stream = &i2s->streams[SNDRV_PCM_STREAM_PLAYBACK];
+	tx_irq = platform_get_irq_byname(pdev, "tx");
+	if (tx_irq > 0) {
+		ret = devm_request_irq(dev, tx_irq, xlnx_logicpd_dai_isr,
+				       0, "logicpd-i2s-tx", stream);
+		if (ret)
+			return ret;
+	} else {
+		dev_err(dev, "TX IRQ not available (%d), disabling playback\n",
+			tx_irq);
+		tx_irq = 0;
+	}
+
+	stream = &i2s->streams[SNDRV_PCM_STREAM_CAPTURE];
+	rx_irq = platform_get_irq_byname(pdev, "rx");
+	if (rx_irq > 0) {
+		ret = devm_request_irq(dev, rx_irq, xlnx_logicpd_dai_isr,
+				       0, "logicpd-i2s-rx", stream);
+		if (ret)
+			return ret;
+	} else {
+		dev_err(dev, "RX IRQ not available (%d), disabling capture\n",
+			rx_irq);
+		rx_irq = 0;
+	}
+
+	if (!tx_irq && !rx_irq)
+		return -EINVAL;
+
+	ret = devm_snd_soc_register_component(dev, &xlnx_logicpd_pcm_component,
+					      NULL, 0);
+	if (ret) {
+		dev_err(dev, "cannot register PCM component (%d)\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(dev, &xlnx_logicpd_i2s_component,
+					      &xlnx_logicpd_dai, 1);
+	if (ret) {
+		dev_err(dev, "cannot register I2S component (%d)\n", ret);
+		return ret;
+	}
+
+	reg = readl_relaxed(i2s->base + IP_VERSION);
+	dev_info(dev, "%s DAI version %u.%u.%c (license: %s) registered\n",
+		 xlnx_logicpd_dai.name,
+		 (unsigned int)MAJOR_REV(reg),
+		 (unsigned int)MINOR_REV(reg),
+		 (char)PATCH_LEVEL(reg),
+		 LICENSE_TYPE(reg) == 0 ? "source" :
+		 (LICENSE_TYPE(reg) == 1 ? "eval" : "release"));
+
+	return ret;
+}
+
+static struct platform_driver xlnx_logicpd_i2s_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = xlnx_logicpd_i2s_of_match,
+	},
+	.probe = xlnx_logicpd_i2s_probe,
+};
+
+module_platform_driver(xlnx_logicpd_i2s_driver);
+
+MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
+MODULE_DESCRIPTION("Xilinx logicPD I2S module");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings
  2019-08-30 21:06 [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Miquel Raynal
@ 2019-08-30 21:06 ` Miquel Raynal
  2019-09-02 13:39   ` Rob Herring
  2019-08-30 21:06 ` [PATCH 3/3] MAINTAINERS: Add an entry for the Xilinx logicPD-I2S block Miquel Raynal
  2019-09-02  7:39 ` [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Michal Simek
  2 siblings, 1 reply; 9+ messages in thread
From: Miquel Raynal @ 2019-08-30 21:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai
  Cc: Mark Rutland, devicetree, alsa-devel, Michal Simek, Rob Herring,
	Thomas Petazzoni, Miquel Raynal, alexandre, linux-arm-kernel

Document the logicPD I2S FPGA block bindings in yaml.

Syntax verified with dt-doc-validate.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 .../bindings/sound/xlnx,logicpd-i2s.yaml      | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml

diff --git a/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
new file mode 100644
index 000000000000..cbff641af199
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/xlnx,logicpd-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Device-Tree bindings for Xilinx logicPD I2S FPGA block
+
+maintainers:
+  - Miquel Raynal <miquel.raynal@bootlin.com>
+
+description: |
+  The IP supports I2S playback/capture audio. It acts as a slave and
+  clocks should come from the codec. It only supports two channels and
+  S16_LE format.
+
+properties:
+  compatible:
+    items:
+      - const: xlnx,logicpd-i2s
+
+  reg:
+    maxItems: 1
+    description:
+      Base address and size of the IP core instance.
+
+  interrupts:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: tx interrupt
+      - description: rx interrupt
+    description:
+      Either the Tx interruption or the Rx interruption or both.
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      - const: tx
+      - const: rx
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupts-controller
+
+examples:
+  - |
+    logii2s_dai: logii2s-dai@43c10000 {
+        reg = <0x43c10000 0x1000>;
+        compatible = "xlnx,logicpd-i2s-dai";
+        interrupt-parent = <&intc>;
+        interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>, <0 30 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "rx", "tx";
+    };
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 3/3] MAINTAINERS: Add an entry for the Xilinx logicPD-I2S block
  2019-08-30 21:06 [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Miquel Raynal
  2019-08-30 21:06 ` [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings Miquel Raynal
@ 2019-08-30 21:06 ` Miquel Raynal
  2019-09-02  7:39 ` [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Michal Simek
  2 siblings, 0 replies; 9+ messages in thread
From: Miquel Raynal @ 2019-08-30 21:06 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai
  Cc: Mark Rutland, devicetree, alsa-devel, Michal Simek, Rob Herring,
	Thomas Petazzoni, Miquel Raynal, alexandre, linux-arm-kernel

Reference the driver and and the bindings.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 5bf8f340e6a8..382c33a1adef 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17136,6 +17136,12 @@ L:	linux-serial@vger.kernel.org
 S:	Maintained
 F:	drivers/tty/serial/uartlite.c
 
+XILINX LOGICPD I2S SOUND DRIVER
+M:	Miquel Raynal <miquel.raynal@bootlin.com>
+S:	Maintained
+F:	sound/soc/xilinx/xlnx-logicpd-i2s.c
+F:	Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
+
 XILINX VIDEO IP CORES
 M:	Hyun Kwon <hyun.kwon@xilinx.com>
 M:	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support
  2019-08-30 21:06 [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Miquel Raynal
  2019-08-30 21:06 ` [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings Miquel Raynal
  2019-08-30 21:06 ` [PATCH 3/3] MAINTAINERS: Add an entry for the Xilinx logicPD-I2S block Miquel Raynal
@ 2019-09-02  7:39 ` Michal Simek
  2019-09-02 20:21   ` Miquel Raynal
  2 siblings, 1 reply; 9+ messages in thread
From: Michal Simek @ 2019-09-02  7:39 UTC (permalink / raw)
  To: Miquel Raynal, Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai
  Cc: Mark Rutland, devicetree, alsa-devel,
	Maruthi Srinivas Bayyavarapu, Michal Simek, Rob Herring,
	Thomas Petazzoni, praveenv, alexandre, linux-arm-kernel

Hi Miquel

On 30. 08. 19 23:06, Miquel Raynal wrote:
> This IP is very simple so this driver manage both the DAI and the PCM
> streams, hence the presence of both components in this driver.
> 
> There are plenty available interruptions when capturing or playing
> back audio that can be triggered but the only one that fits the ALSA
> sound system is the XFER_DONE which is used to bound sound
> periods. Other interrupts are masked. Please note that capture and
> playback are not possible at the same time though.
> 
> Capture seems to work (at least it creates a file with something
> inside) but I have no capture mechanism on the board to actually test
> that it works correctly.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
> 
> Hello,
> 
> This is my first contribution in the sound subsystem, I hope I've
> understood the core but I might be entirely wrong as well, so please
> do not hesitate to be critical on my choices.
> 
> Thanks,
> Miquèl
> 
>  sound/soc/xilinx/Kconfig            |   7 +
>  sound/soc/xilinx/Makefile           |   2 +
>  sound/soc/xilinx/xlnx-logicpd-i2s.c | 468 ++++++++++++++++++++++++++++

What IP is this?
https://www.xilinx.com/products/intellectual-property/audio-i2s.html

https://github.com/Xilinx/linux-xlnx/blob/master/sound/soc/xilinx/xlnx_i2s.c

Anyway I am adding Praveen and Maruthi to take a look.

Thanks,
Michal



>  3 files changed, 477 insertions(+)
>  create mode 100644 sound/soc/xilinx/xlnx-logicpd-i2s.c
> 
> diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig
> index 47f606b924e4..b62cae6750b9 100644
> --- a/sound/soc/xilinx/Kconfig
> +++ b/sound/soc/xilinx/Kconfig
> @@ -7,6 +7,13 @@ config SND_SOC_XILINX_I2S
>  	  PCM data. In receiver mode, IP receives PCM audio and
>  	  encapsulates PCM in AES format and sends AES data.
>  
> +config SND_SOC_XILINX_LOGICPD_I2S
> +	tristate "Audio support for the Xilinx logicPD I2S"
> +	help
> +	  Select this option to enable Xilinx logicPD I2S slave
> +	  transceiver. This enables I2S playback and capture using
> +	  Xilinx/logicPD IP.
> +
>  config SND_SOC_XILINX_AUDIO_FORMATTER
>          tristate "Audio support for the the Xilinx audio formatter"
>          help
> diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile
> index d79fd38b094b..d127c30f8fe2 100644
> --- a/sound/soc/xilinx/Makefile
> +++ b/sound/soc/xilinx/Makefile
> @@ -1,5 +1,7 @@
>  snd-soc-xlnx-i2s-objs      := xlnx_i2s.o
>  obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o
> +snd-soc-xlnx-logicpd-i2s-objs := xlnx-logicpd-i2s.o
> +obj-$(CONFIG_SND_SOC_XILINX_LOGICPD_I2S) += snd-soc-xlnx-logicpd-i2s.o
>  snd-soc-xlnx-formatter-pcm-objs := xlnx_formatter_pcm.o
>  obj-$(CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER) += snd-soc-xlnx-formatter-pcm.o
>  snd-soc-xlnx-spdif-objs := xlnx_spdif.o
> diff --git a/sound/soc/xilinx/xlnx-logicpd-i2s.c b/sound/soc/xilinx/xlnx-logicpd-i2s.c
> new file mode 100644
> index 000000000000..325a5bb6978a
> --- /dev/null
> +++ b/sound/soc/xilinx/xlnx-logicpd-i2s.c
> @@ -0,0 +1,468 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Xilinx logicPD logiI2S - I2S slave transceiver v2 support
> + *
> + * Copyright (C) 2019 Bootlin
> + *
> + * Author: Miquel Raynal <miquel.raynal@bootlin.com>
> + */
> +
> +#include <linux/dma-mapping.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <sound/dmaengine_pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +
> +#define DRV_NAME "xlnx_logicpd_i2s"
> +
> +#define IP_VERSION 0x0
> +#define   PATCH_LEVEL(reg) (((reg) & GENMASK(4, 0)) + 'a')
> +#define   MINOR_REV(reg) (((reg) & GENMASK(10, 5)) >> 5)
> +#define   MAJOR_REV(reg) (((reg) & GENMASK(16, 11)) >> 11)
> +#define   LICENSE_TYPE(reg) (((reg) & GENMASK(18, 17)) >> 17)
> +#define CONTROL_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x4 : 0x24)
> +#define   ENGINE_EN BIT(0)
> +#define   XFER_DONE BIT(1)
> +#define BUFF_BASE_ADDR_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x8 : 0x28)
> +#define BUFF_LEN_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0xC : 0x2C)
> +#define FIFO_STAT_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x10 : 0x30)
> +#define INTR_MASK_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x14 : 0x34)
> +#define   XFER_DONE_INTR BIT(31)
> +#define INTR_STAT_REG(s) ((s) == SNDRV_PCM_STREAM_PLAYBACK ? 0x18 : 0x38)
> +#define   FIFO_COUNT(reg) ((reg) >> 20)
> +
> +#define BYTES_TO_WORDS(n) ((n) / 4)
> +
> +/* Arbitrarily chosen period size */
> +#define PCM_PERIOD_WORDS SZ_8K
> +#define PCM_PERIOD_BYTES (PCM_PERIOD_WORDS * 4)
> +/* This is the actual maximum size that can actually be moved in one chunk */
> +#define PCM_BUF_WORDS (SZ_64K - 1)
> +#define PCM_BUF_BYTES (PCM_BUF_WORDS * 4)
> +
> +struct xlnx_logicpd_i2s;
> +
> +/**
> + * struct xlnx_logicpd_stream - Internal stream representation
> + *
> + * @i2s: Chip data
> + * @substream: Core substream structure
> + * @period_idx: Index of the period within the circular buffer
> + */
> +struct xlnx_logicpd_stream {
> +	struct xlnx_logicpd_i2s *i2s;
> +	struct snd_pcm_substream *substream;
> +	unsigned int period_idx;
> +};
> +
> +/**
> + * struct xlnx_logicpd_i2s - Chip structure
> + *
> + * @base: Registers base address
> + * @streams: Playback and capture streams in an array
> + */
> +struct xlnx_logicpd_i2s {
> +	void __iomem *base;
> +	struct xlnx_logicpd_stream streams[2];
> +};
> +
> +static struct xlnx_logicpd_i2s *substream_to_cpu_dai_chip(struct snd_pcm_substream *substream)
> +{
> +	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
> +
> +	return snd_soc_dai_get_drvdata(rtd->cpu_dai);
> +}
> +
> +/* PCM methods */
> +
> +static const struct snd_pcm_hardware xlnx_logicpd_pcm_hardware = {
> +	.info = SNDRV_PCM_INFO_MMAP |
> +		SNDRV_PCM_INFO_MMAP_VALID |
> +		SNDRV_PCM_INFO_INTERLEAVED |
> +		SNDRV_PCM_INFO_HALF_DUPLEX,
> +	.formats = SNDRV_PCM_FMTBIT_S16_LE,
> +	.rates = SNDRV_PCM_RATE_8000_192000,
> +	.rate_min = 8000,
> +	.rate_max = 192000,
> +	.channels_min = 2,
> +	.channels_max = 2,
> +	.period_bytes_min = 0,
> +	.period_bytes_max = PCM_PERIOD_BYTES,
> +	.periods_min = 0,
> +	.periods_max = -1,
> +	.buffer_bytes_max = PCM_BUF_BYTES,
> +};
> +
> +static int xlnx_logicpd_pcm_open(struct snd_pcm_substream *substream)
> +{
> +	struct xlnx_logicpd_i2s *i2s = substream_to_cpu_dai_chip(substream);
> +	unsigned int dir = substream->stream;
> +
> +	snd_soc_set_runtime_hwparams(substream, &xlnx_logicpd_pcm_hardware);
> +
> +	i2s->streams[dir].substream = substream;
> +
> +	return 0;
> +}
> +
> +static int xlnx_logicpd_pcm_close(struct snd_pcm_substream *substream)
> +{
> +	struct xlnx_logicpd_i2s *i2s = substream_to_cpu_dai_chip(substream);
> +	unsigned int dir = substream->stream;
> +
> +	i2s->streams[dir].substream = NULL;
> +
> +	return 0;
> +}
> +
> +static int xlnx_logicpd_pcm_hw_params(struct snd_pcm_substream *substream,
> +				      struct snd_pcm_hw_params *params)
> +{
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +
> +	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
> +	runtime->dma_bytes = params_buffer_bytes(params);
> +
> +	return 0;
> +}
> +
> +static snd_pcm_uframes_t xlnx_logicpd_pcm_pointer(struct snd_pcm_substream *substream)
> +{
> +	struct xlnx_logicpd_i2s *i2s = substream_to_cpu_dai_chip(substream);
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +	unsigned int period_sz = snd_pcm_lib_period_bytes(substream);
> +	unsigned int dir = substream->stream;
> +
> +	return bytes_to_frames(runtime,
> +			       i2s->streams[dir].period_idx * period_sz);
> +}
> +
> +static int xlnx_logicpd_pcm_mmap(struct snd_pcm_substream *substream,
> +				 struct vm_area_struct *vma)
> +{
> +	return remap_pfn_range(vma, vma->vm_start,
> +			       substream->dma_buffer.addr >> PAGE_SHIFT,
> +			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
> +}
> +
> +static const struct snd_pcm_ops xlnx_logicpd_pcm_ops = {
> +	.open = xlnx_logicpd_pcm_open,
> +	.close = xlnx_logicpd_pcm_close,
> +	.ioctl = snd_pcm_lib_ioctl,
> +	.hw_params = xlnx_logicpd_pcm_hw_params,
> +	.pointer = xlnx_logicpd_pcm_pointer,
> +	.mmap = xlnx_logicpd_pcm_mmap,
> +};
> +
> +static int xlnx_logicpd_pcm_new(struct snd_soc_pcm_runtime *rtd)
> +{
> +	struct snd_pcm *pcm = rtd->pcm;
> +	struct snd_pcm_substream *substream;
> +	struct snd_dma_buffer *buf;
> +	int dir;
> +
> +	for (dir = SNDRV_PCM_STREAM_PLAYBACK;
> +	     dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
> +		substream = pcm->streams[dir].substream;
> +		if (!substream)
> +			continue;
> +
> +		buf = &substream->dma_buffer;
> +		buf->area = dma_alloc_coherent(pcm->card->dev, PCM_BUF_BYTES,
> +					       &buf->addr, GFP_KERNEL);
> +		buf->bytes = PCM_BUF_BYTES;
> +		if (!buf->area)
> +			return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
> +static void xlnx_logicpd_pcm_free(struct snd_pcm *pcm)
> +{
> +	struct snd_pcm_substream *substream;
> +	struct snd_dma_buffer *buf;
> +	int dir;
> +
> +	for (dir = SNDRV_PCM_STREAM_PLAYBACK;
> +	     dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
> +		substream = pcm->streams[dir].substream;
> +		if (!substream)
> +			continue;
> +
> +		buf = &substream->dma_buffer;
> +		if (!buf->area)
> +			continue;
> +
> +		dma_free_coherent(pcm->card->dev, buf->bytes,
> +				  buf->area, buf->addr);
> +		buf->area = NULL;
> +	}
> +}
> +
> +static const struct snd_soc_component_driver xlnx_logicpd_pcm_component = {
> +	.name = "xlnx-logicp-pcm",
> +	.ops = &xlnx_logicpd_pcm_ops,
> +	.pcm_new = xlnx_logicpd_pcm_new,
> +	.pcm_free = xlnx_logicpd_pcm_free,
> +};
> +
> +/* DAI methods */
> +
> +static void xlnx_logicpd_dai_int_en(struct xlnx_logicpd_i2s *i2s, int dir)
> +{
> +	u32 reg;
> +
> +	reg = readl_relaxed(i2s->base + INTR_MASK_REG(dir));
> +	reg &= ~XFER_DONE_INTR;
> +	writel(reg, i2s->base + INTR_MASK_REG(dir));
> +}
> +
> +static void xlnx_logicpd_dai_int_dis(struct xlnx_logicpd_i2s *i2s, int dir)
> +{
> +	u32 reg;
> +
> +	reg = readl_relaxed(i2s->base + INTR_MASK_REG(dir));
> +	reg |= XFER_DONE_INTR;
> +	writel_relaxed(reg, i2s->base + INTR_MASK_REG(dir));
> +}
> +
> +static irqreturn_t xlnx_logicpd_dai_isr(int irq, void *dev_id)
> +{
> +	struct xlnx_logicpd_stream *stream = dev_id;
> +	struct xlnx_logicpd_i2s *i2s = stream->i2s;
> +	struct snd_pcm_substream *substream = stream->substream;
> +	unsigned int period_sz = snd_pcm_lib_period_bytes(substream);
> +	unsigned int buf_sz = snd_pcm_lib_buffer_bytes(substream);
> +	dma_addr_t buf_addr = substream->dma_buffer.addr;
> +	unsigned int dir = substream->stream;
> +	u32 reg;
> +
> +	/* Reading INTR_STAT deasserts the host interrupt */
> +	reg = readl_relaxed(i2s->base + INTR_STAT_REG(dir));
> +
> +	/*
> +	 * When the XFER_DONE interrupt is triggered, it means the period has
> +	 * been entirely shifted into the FIFO. At this point, we can move the
> +	 * buffer pointer to the next period and ask to transfer another chunk
> +	 * of data. Whenever the FIFO will be at its "almost full" state (4096
> +	 * words minus the threshold of 100 words) the internal DMA engine will
> +	 * automatically restart shifting data to the FIFO until its full state.
> +	 * Hence, the host has up to 3996 words (in our case, 3996 frames) to
> +	 * serve the interrupt before an underrun that would happen, at eg.
> +	 * 44100Hz, after 90ms.
> +	 */
> +	if (reg & XFER_DONE_INTR) {
> +		unsigned int offset_in_buf = ++stream->period_idx * period_sz;
> +
> +		if (offset_in_buf >= buf_sz) {
> +			stream->period_idx = 0;
> +			offset_in_buf = stream->period_idx * period_sz;
> +		}
> +
> +		/* Move on to the next period in the overall buffer */
> +		writel_relaxed(buf_addr + offset_in_buf,
> +			       i2s->base + BUFF_BASE_ADDR_REG(dir));
> +		/* The last period might be smaller, update length if needed */
> +		period_sz = min(period_sz, buf_sz - offset_in_buf);
> +		writel_relaxed(BYTES_TO_WORDS(period_sz),
> +			       i2s->base + BUFF_LEN_REG(dir));
> +
> +		/* Inform the PCM middle-layer */
> +		snd_pcm_period_elapsed(substream);
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int xlnx_logicpd_dai_trigger(struct snd_pcm_substream *substream,
> +				    int cmd, struct snd_soc_dai *dai)
> +{
> +	struct xlnx_logicpd_i2s *i2s = snd_soc_dai_get_drvdata(dai);
> +	unsigned int period_sz = snd_pcm_lib_period_bytes(substream);
> +	dma_addr_t buf_addr = substream->dma_buffer.addr;
> +	unsigned int dir = substream->stream;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +		i2s->streams[dir].period_idx = 0;
> +		/* Disable the other engine if enabled */
> +		if (readl(i2s->base + CONTROL_REG(!dir)) & ENGINE_EN)
> +			writel(0, i2s->base + CONTROL_REG(!dir));
> +		/* Enable the desired engine */
> +		writel_relaxed(ENGINE_EN, i2s->base + CONTROL_REG(dir));
> +		/* Set the buffer start address */
> +		writel_relaxed(buf_addr, i2s->base + BUFF_BASE_ADDR_REG(dir));
> +		/* Enable the XFER_DONE IRQ, signaling the end of the period */
> +		xlnx_logicpd_dai_int_en(i2s, dir);
> +		/* Actually start the internal DMA engine */
> +		writel(BYTES_TO_WORDS(period_sz),
> +		       i2s->base + BUFF_LEN_REG(dir));
> +		break;
> +	case SNDRV_PCM_TRIGGER_STOP:
> +		/* Disable the interrupts */
> +		xlnx_logicpd_dai_int_dis(i2s, dir);
> +		/* Ensure the host IRQ is deasserted */
> +		readl_relaxed(i2s->base + INTR_STAT_REG(dir));
> +		break;
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct snd_soc_dai_ops xlnx_logicpd_dai_ops = {
> +	.trigger = xlnx_logicpd_dai_trigger,
> +};
> +
> +static int xlnx_logicpd_dai_probe(struct snd_soc_dai *dai)
> +{
> +	struct xlnx_logicpd_i2s *i2s = snd_soc_dai_get_drvdata(dai);
> +	unsigned int dir;
> +
> +	for (dir = SNDRV_PCM_STREAM_PLAYBACK;
> +	     dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
> +		i2s->streams[dir].i2s = i2s;
> +
> +		/* Reset the transmitter/receiver engine */
> +		writel_relaxed(0, i2s->base + CONTROL_REG(dir));
> +		/* Mask all interrupts */
> +		writel_relaxed(GENMASK(31, 0), i2s->base + INTR_MASK_REG(dir));
> +	}
> +
> +	return 0;
> +}
> +
> +struct snd_soc_dai_driver xlnx_logicpd_dai = {
> +	.name = "xylinx-logicpd-dai",
> +	.probe = xlnx_logicpd_dai_probe,
> +	.capture = {
> +		.stream_name = "Capture",
> +		.channels_min = 2,
> +		.channels_max = 2,
> +		.rates = SNDRV_PCM_RATE_8000_192000,
> +		.rate_min = 8000,
> +		.rate_max = 192000,
> +		.formats = SNDRV_PCM_FMTBIT_S16_LE,
> +	},
> +	.playback = {
> +		.stream_name = "Playback",
> +		.channels_min = 2,
> +		.channels_max = 2,
> +		.rates = SNDRV_PCM_RATE_8000_192000,
> +		.rate_min = 8000,
> +		.rate_max = 192000,
> +		.formats = SNDRV_PCM_FMTBIT_S16_LE,
> +	},
> +	.symmetric_rates = 1,
> +	.ops = &xlnx_logicpd_dai_ops,
> +};
> +
> +static const struct snd_soc_component_driver xlnx_logicpd_i2s_component = {
> +	.name = DRV_NAME,
> +	.ops = &xlnx_logicpd_pcm_ops,
> +};
> +
> +static const struct of_device_id xlnx_logicpd_i2s_of_match[] = {
> +	{
> +		.compatible = "xlnx,logicpd-i2s-dai",
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, xlnx_logicpd_i2s_of_match);
> +
> +static int xlnx_logicpd_i2s_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct xlnx_logicpd_i2s *i2s;
> +	struct xlnx_logicpd_stream *stream;
> +	int tx_irq, rx_irq, ret;
> +	u32 reg;
> +
> +	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
> +	if (!i2s)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(dev, i2s);
> +
> +	i2s->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(i2s->base))
> +		return PTR_ERR(i2s->base);
> +
> +	stream = &i2s->streams[SNDRV_PCM_STREAM_PLAYBACK];
> +	tx_irq = platform_get_irq_byname(pdev, "tx");
> +	if (tx_irq > 0) {
> +		ret = devm_request_irq(dev, tx_irq, xlnx_logicpd_dai_isr,
> +				       0, "logicpd-i2s-tx", stream);
> +		if (ret)
> +			return ret;
> +	} else {
> +		dev_err(dev, "TX IRQ not available (%d), disabling playback\n",
> +			tx_irq);
> +		tx_irq = 0;
> +	}
> +
> +	stream = &i2s->streams[SNDRV_PCM_STREAM_CAPTURE];
> +	rx_irq = platform_get_irq_byname(pdev, "rx");
> +	if (rx_irq > 0) {
> +		ret = devm_request_irq(dev, rx_irq, xlnx_logicpd_dai_isr,
> +				       0, "logicpd-i2s-rx", stream);
> +		if (ret)
> +			return ret;
> +	} else {
> +		dev_err(dev, "RX IRQ not available (%d), disabling capture\n",
> +			rx_irq);
> +		rx_irq = 0;
> +	}
> +
> +	if (!tx_irq && !rx_irq)
> +		return -EINVAL;
> +
> +	ret = devm_snd_soc_register_component(dev, &xlnx_logicpd_pcm_component,
> +					      NULL, 0);
> +	if (ret) {
> +		dev_err(dev, "cannot register PCM component (%d)\n", ret);
> +		return ret;
> +	}
> +
> +	ret = devm_snd_soc_register_component(dev, &xlnx_logicpd_i2s_component,
> +					      &xlnx_logicpd_dai, 1);
> +	if (ret) {
> +		dev_err(dev, "cannot register I2S component (%d)\n", ret);
> +		return ret;
> +	}
> +
> +	reg = readl_relaxed(i2s->base + IP_VERSION);
> +	dev_info(dev, "%s DAI version %u.%u.%c (license: %s) registered\n",
> +		 xlnx_logicpd_dai.name,
> +		 (unsigned int)MAJOR_REV(reg),
> +		 (unsigned int)MINOR_REV(reg),
> +		 (char)PATCH_LEVEL(reg),
> +		 LICENSE_TYPE(reg) == 0 ? "source" :
> +		 (LICENSE_TYPE(reg) == 1 ? "eval" : "release"));
> +
> +	return ret;
> +}
> +
> +static struct platform_driver xlnx_logicpd_i2s_driver = {
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = xlnx_logicpd_i2s_of_match,
> +	},
> +	.probe = xlnx_logicpd_i2s_probe,
> +};
> +
> +module_platform_driver(xlnx_logicpd_i2s_driver);
> +
> +MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
> +MODULE_DESCRIPTION("Xilinx logicPD I2S module");
> +MODULE_LICENSE("GPL v2");
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings
  2019-08-30 21:06 ` [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings Miquel Raynal
@ 2019-09-02 13:39   ` Rob Herring
  2019-09-02 13:51     ` Miquel Raynal
  0 siblings, 1 reply; 9+ messages in thread
From: Rob Herring @ 2019-09-02 13:39 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, devicetree, alsa-devel, Takashi Iwai,
	Liam Girdwood, Mark Brown, alexandre, Thomas Petazzoni,
	Jaroslav Kysela, Michal Simek, linux-arm-kernel

On Fri, Aug 30, 2019 at 11:06:06PM +0200, Miquel Raynal wrote:
> Document the logicPD I2S FPGA block bindings in yaml.
> 
> Syntax verified with dt-doc-validate.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  .../bindings/sound/xlnx,logicpd-i2s.yaml      | 57 +++++++++++++++++++
>  1 file changed, 57 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> new file mode 100644
> index 000000000000..cbff641af199
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> @@ -0,0 +1,57 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/xlnx,logicpd-i2s.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Device-Tree bindings for Xilinx logicPD I2S FPGA block
> +
> +maintainers:
> +  - Miquel Raynal <miquel.raynal@bootlin.com>
> +
> +description: |
> +  The IP supports I2S playback/capture audio. It acts as a slave and
> +  clocks should come from the codec. It only supports two channels and
> +  S16_LE format.
> +
> +properties:
> +  compatible:
> +    items:
> +      - const: xlnx,logicpd-i2s
> +
> +  reg:
> +    maxItems: 1
> +    description:
> +      Base address and size of the IP core instance.
> +
> +  interrupts:
> +    minItems: 1
> +    maxItems: 2
> +    items:
> +      - description: tx interrupt
> +      - description: rx interrupt
> +    description:
> +      Either the Tx interruption or the Rx interruption or both.

The schema says either tx or both. Doesn't really matter here as it's 
just numbers.

> +
> +  interrupt-names:
> +    minItems: 1
> +    maxItems: 2
> +    items:
> +      - const: tx
> +      - const: rx

But here it does matter.

The easiest way to express this is:

oneOf:
  - items:
      - enum: [ tx, rx ]
  - items:
      - const: tx
      - const: rx

> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - interrupts-controller
> +
> +examples:
> +  - |
> +    logii2s_dai: logii2s-dai@43c10000 {
> +        reg = <0x43c10000 0x1000>;
> +        compatible = "xlnx,logicpd-i2s-dai";
> +        interrupt-parent = <&intc>;
> +        interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>, <0 30 IRQ_TYPE_LEVEL_HIGH>;
> +        interrupt-names = "rx", "tx";
> +    };
> -- 
> 2.20.1
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings
  2019-09-02 13:39   ` Rob Herring
@ 2019-09-02 13:51     ` Miquel Raynal
  2019-09-02 14:24       ` Rob Herring
  0 siblings, 1 reply; 9+ messages in thread
From: Miquel Raynal @ 2019-09-02 13:51 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, devicetree, alsa-devel, Takashi Iwai,
	Liam Girdwood, Mark Brown, alexandre, Thomas Petazzoni,
	Jaroslav Kysela, Michal Simek, linux-arm-kernel

Hi Rob,

Thanks for the review, one question below.

Rob Herring <robh@kernel.org> wrote on Mon, 02 Sep 2019 14:39:09 +0100:

> On Fri, Aug 30, 2019 at 11:06:06PM +0200, Miquel Raynal wrote:
> > Document the logicPD I2S FPGA block bindings in yaml.
> > 
> > Syntax verified with dt-doc-validate.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  .../bindings/sound/xlnx,logicpd-i2s.yaml      | 57 +++++++++++++++++++
> >  1 file changed, 57 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> > new file mode 100644
> > index 000000000000..cbff641af199
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> > @@ -0,0 +1,57 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/sound/xlnx,logicpd-i2s.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Device-Tree bindings for Xilinx logicPD I2S FPGA block
> > +
> > +maintainers:
> > +  - Miquel Raynal <miquel.raynal@bootlin.com>
> > +
> > +description: |
> > +  The IP supports I2S playback/capture audio. It acts as a slave and
> > +  clocks should come from the codec. It only supports two channels and
> > +  S16_LE format.
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - const: xlnx,logicpd-i2s
> > +
> > +  reg:
> > +    maxItems: 1
> > +    description:
> > +      Base address and size of the IP core instance.
> > +
> > +  interrupts:
> > +    minItems: 1
> > +    maxItems: 2
> > +    items:
> > +      - description: tx interrupt
> > +      - description: rx interrupt
> > +    description:
> > +      Either the Tx interruption or the Rx interruption or both.  
> 
> The schema says either tx or both. Doesn't really matter here as it's 
> just numbers.

I see , I'll drop the 'items' entry.

> 
> > +
> > +  interrupt-names:
> > +    minItems: 1
> > +    maxItems: 2
> > +    items:
> > +      - const: tx
> > +      - const: rx  
> 
> But here it does matter.
> 
> The easiest way to express this is:
> 
> oneOf:
>   - items:
>       - enum: [ tx, rx ]
>   - items:
>       - const: tx
>       - const: rx
> 

Does this enforce an order? (I don't know if it matters, though, but in
the bellow example I put the Rx interrupt first).

> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - interrupts-controller
> > +
> > +examples:
> > +  - |
> > +    logii2s_dai: logii2s-dai@43c10000 {
> > +        reg = <0x43c10000 0x1000>;
> > +        compatible = "xlnx,logicpd-i2s-dai";
> > +        interrupt-parent = <&intc>;
> > +        interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>, <0 30 IRQ_TYPE_LEVEL_HIGH>;
> > +        interrupt-names = "rx", "tx";
> > +    };
> > -- 
> > 2.20.1
> >   
> 

Thanks,
Miquèl

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings
  2019-09-02 13:51     ` Miquel Raynal
@ 2019-09-02 14:24       ` Rob Herring
  0 siblings, 0 replies; 9+ messages in thread
From: Rob Herring @ 2019-09-02 14:24 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mark Rutland, devicetree, Linux-ALSA, Takashi Iwai,
	Liam Girdwood, Mark Brown, alexandre, Thomas Petazzoni,
	Jaroslav Kysela, Michal Simek,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Mon, Sep 2, 2019 at 2:51 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> Hi Rob,
>
> Thanks for the review, one question below.
>
> Rob Herring <robh@kernel.org> wrote on Mon, 02 Sep 2019 14:39:09 +0100:
>
> > On Fri, Aug 30, 2019 at 11:06:06PM +0200, Miquel Raynal wrote:
> > > Document the logicPD I2S FPGA block bindings in yaml.
> > >
> > > Syntax verified with dt-doc-validate.
> > >
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  .../bindings/sound/xlnx,logicpd-i2s.yaml      | 57 +++++++++++++++++++
> > >  1 file changed, 57 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> > > new file mode 100644
> > > index 000000000000..cbff641af199
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/sound/xlnx,logicpd-i2s.yaml
> > > @@ -0,0 +1,57 @@
> > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/sound/xlnx,logicpd-i2s.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Device-Tree bindings for Xilinx logicPD I2S FPGA block
> > > +
> > > +maintainers:
> > > +  - Miquel Raynal <miquel.raynal@bootlin.com>
> > > +
> > > +description: |
> > > +  The IP supports I2S playback/capture audio. It acts as a slave and
> > > +  clocks should come from the codec. It only supports two channels and
> > > +  S16_LE format.
> > > +
> > > +properties:
> > > +  compatible:
> > > +    items:
> > > +      - const: xlnx,logicpd-i2s
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +    description:
> > > +      Base address and size of the IP core instance.
> > > +
> > > +  interrupts:
> > > +    minItems: 1
> > > +    maxItems: 2
> > > +    items:
> > > +      - description: tx interrupt
> > > +      - description: rx interrupt
> > > +    description:
> > > +      Either the Tx interruption or the Rx interruption or both.
> >
> > The schema says either tx or both. Doesn't really matter here as it's
> > just numbers.
>
> I see , I'll drop the 'items' entry.
>
> >
> > > +
> > > +  interrupt-names:
> > > +    minItems: 1
> > > +    maxItems: 2
> > > +    items:
> > > +      - const: tx
> > > +      - const: rx
> >
> > But here it does matter.
> >
> > The easiest way to express this is:
> >
> > oneOf:
> >   - items:
> >       - enum: [ tx, rx ]
> >   - items:
> >       - const: tx
> >       - const: rx
> >
>
> Does this enforce an order? (I don't know if it matters, though, but in
> the bellow example I put the Rx interrupt first).

Yes. It does matter and should be defined what the order it.

Rob

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support
  2019-09-02  7:39 ` [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Michal Simek
@ 2019-09-02 20:21   ` Miquel Raynal
  2019-09-03  6:51     ` Michal Simek
  0 siblings, 1 reply; 9+ messages in thread
From: Miquel Raynal @ 2019-09-02 20:21 UTC (permalink / raw)
  To: Michal Simek
  Cc: Mark Rutland, devicetree, alsa-devel,
	Maruthi Srinivas Bayyavarapu, Takashi Iwai, Rob Herring,
	Liam Girdwood, Mark Brown, Thomas Petazzoni, praveenv,
	Jaroslav Kysela, alexandre, linux-arm-kernel

Hi Michal,

Michal Simek <michal.simek@xilinx.com> wrote on Mon, 2 Sep 2019
09:39:11 +0200:

> Hi Miquel
> 
> On 30. 08. 19 23:06, Miquel Raynal wrote:
> > This IP is very simple so this driver manage both the DAI and the PCM
> > streams, hence the presence of both components in this driver.
> > 
> > There are plenty available interruptions when capturing or playing
> > back audio that can be triggered but the only one that fits the ALSA
> > sound system is the XFER_DONE which is used to bound sound
> > periods. Other interrupts are masked. Please note that capture and
> > playback are not possible at the same time though.
> > 
> > Capture seems to work (at least it creates a file with something
> > inside) but I have no capture mechanism on the board to actually test
> > that it works correctly.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> > 
> > Hello,
> > 
> > This is my first contribution in the sound subsystem, I hope I've
> > understood the core but I might be entirely wrong as well, so please
> > do not hesitate to be critical on my choices.
> > 
> > Thanks,
> > Miquèl
> > 
> >  sound/soc/xilinx/Kconfig            |   7 +
> >  sound/soc/xilinx/Makefile           |   2 +
> >  sound/soc/xilinx/xlnx-logicpd-i2s.c | 468 ++++++++++++++++++++++++++++  
> 
> What IP is this?
> https://www.xilinx.com/products/intellectual-property/audio-i2s.html
> 
> https://github.com/Xilinx/linux-xlnx/blob/master/sound/soc/xilinx/xlnx_i2s.c
> 
> Anyway I am adding Praveen and Maruthi to take a look.

Actually I have been tricked by a datasheet with the wrong title: this
is a LogicPD IP, it is not from Xilinx. I will resubmit with a new
driver name/compatible and add the relevant people.

Thanks,
Miquèl

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support
  2019-09-02 20:21   ` Miquel Raynal
@ 2019-09-03  6:51     ` Michal Simek
  0 siblings, 0 replies; 9+ messages in thread
From: Michal Simek @ 2019-09-03  6:51 UTC (permalink / raw)
  To: Miquel Raynal, Michal Simek
  Cc: Mark Rutland, devicetree, alsa-devel,
	Maruthi Srinivas Bayyavarapu, Takashi Iwai, Rob Herring,
	Liam Girdwood, Mark Brown, Thomas Petazzoni, praveenv,
	Jaroslav Kysela, alexandre, linux-arm-kernel

On 02. 09. 19 22:21, Miquel Raynal wrote:
> Hi Michal,
> 
> Michal Simek <michal.simek@xilinx.com> wrote on Mon, 2 Sep 2019
> 09:39:11 +0200:
> 
>> Hi Miquel
>>
>> On 30. 08. 19 23:06, Miquel Raynal wrote:
>>> This IP is very simple so this driver manage both the DAI and the PCM
>>> streams, hence the presence of both components in this driver.
>>>
>>> There are plenty available interruptions when capturing or playing
>>> back audio that can be triggered but the only one that fits the ALSA
>>> sound system is the XFER_DONE which is used to bound sound
>>> periods. Other interrupts are masked. Please note that capture and
>>> playback are not possible at the same time though.
>>>
>>> Capture seems to work (at least it creates a file with something
>>> inside) but I have no capture mechanism on the board to actually test
>>> that it works correctly.
>>>
>>> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
>>> ---
>>>
>>> Hello,
>>>
>>> This is my first contribution in the sound subsystem, I hope I've
>>> understood the core but I might be entirely wrong as well, so please
>>> do not hesitate to be critical on my choices.
>>>
>>> Thanks,
>>> Miquèl
>>>
>>>  sound/soc/xilinx/Kconfig            |   7 +
>>>  sound/soc/xilinx/Makefile           |   2 +
>>>  sound/soc/xilinx/xlnx-logicpd-i2s.c | 468 ++++++++++++++++++++++++++++  
>>
>> What IP is this?
>> https://www.xilinx.com/products/intellectual-property/audio-i2s.html
>>
>> https://github.com/Xilinx/linux-xlnx/blob/master/sound/soc/xilinx/xlnx_i2s.c
>>
>> Anyway I am adding Praveen and Maruthi to take a look.
> 
> Actually I have been tricked by a datasheet with the wrong title: this
> is a LogicPD IP, it is not from Xilinx. I will resubmit with a new
> driver name/compatible and add the relevant people.

ok. Great.

M

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2019-09-03  6:54 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-30 21:06 [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Miquel Raynal
2019-08-30 21:06 ` [PATCH 2/3] dt-bindings: sound: Add Xilinx logicPD-I2S FPGA IP bindings Miquel Raynal
2019-09-02 13:39   ` Rob Herring
2019-09-02 13:51     ` Miquel Raynal
2019-09-02 14:24       ` Rob Herring
2019-08-30 21:06 ` [PATCH 3/3] MAINTAINERS: Add an entry for the Xilinx logicPD-I2S block Miquel Raynal
2019-09-02  7:39 ` [PATCH 1/3] ASoC: xlnx: add Xilinx logicPD-I2S FPGA IP support Michal Simek
2019-09-02 20:21   ` Miquel Raynal
2019-09-03  6:51     ` Michal Simek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).