Linux MIPS Architecture development
 help / color / mirror / Atom feed
* [PATCH] ASoC: Add TXx9 AC link controller driver
@ 2009-05-14 14:50 Atsushi Nemoto
  2009-05-14 18:59 ` [alsa-devel] " Mark Brown
  0 siblings, 1 reply; 13+ messages in thread
From: Atsushi Nemoto @ 2009-05-14 14:50 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf, alsa-devel, Mark Brown

This patch adds support for the integrated ACLC of the TXx9 family.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
This patch depends on txx9dmac patch (driver) in linux-mips queue tree
or linux-next tree.

 sound/soc/Kconfig                 |    1 +
 sound/soc/Makefile                |    1 +
 sound/soc/txx9/Kconfig            |   29 +++
 sound/soc/txx9/Makefile           |   11 +
 sound/soc/txx9/txx9aclc-ac97.c    |  214 +++++++++++++++++++
 sound/soc/txx9/txx9aclc-generic.c |  129 ++++++++++++
 sound/soc/txx9/txx9aclc.c         |  415 +++++++++++++++++++++++++++++++++++++
 sound/soc/txx9/txx9aclc.h         |   74 +++++++
 8 files changed, 874 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/txx9/Kconfig
 create mode 100644 sound/soc/txx9/Makefile
 create mode 100644 sound/soc/txx9/txx9aclc-ac97.c
 create mode 100644 sound/soc/txx9/txx9aclc-generic.c
 create mode 100644 sound/soc/txx9/txx9aclc.c
 create mode 100644 sound/soc/txx9/txx9aclc.h

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 3d2bb6f..85e985a 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -33,6 +33,7 @@ source "sound/soc/omap/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/txx9/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 0237879..6039b0d 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_SND_SOC)	+= omap/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
 obj-$(CONFIG_SND_SOC)	+= sh/
+obj-$(CONFIG_SND_SOC)	+= txx9/
diff --git a/sound/soc/txx9/Kconfig b/sound/soc/txx9/Kconfig
new file mode 100644
index 0000000..ebc9327
--- /dev/null
+++ b/sound/soc/txx9/Kconfig
@@ -0,0 +1,29 @@
+##
+## TXx9 ACLC
+##
+config SND_SOC_TXX9ACLC
+	tristate "SoC Audio for TXx9"
+	depends on HAS_TXX9_ACLC && TXX9_DMAC
+	help
+	  This option enables support for the AC Link Controllers in TXx9 SoC.
+
+config HAS_TXX9_ACLC
+	bool
+
+config SND_SOC_TXX9ACLC_AC97
+	tristate
+	select AC97_BUS
+	select SND_AC97_CODEC
+	select SND_SOC_AC97_BUS
+
+
+##
+## Boards
+##
+config SND_SOC_TXX9ACLC_GENERIC
+	tristate "Generic TXx9 ACLC sound machine"
+	depends on SND_SOC_TXX9ACLC
+	select SND_SOC_TXX9ACLC_AC97
+	select SND_SOC_AC97_CODEC
+	help
+	  This is a generic AC97 sound machine for use in TXx9 based systems.
diff --git a/sound/soc/txx9/Makefile b/sound/soc/txx9/Makefile
new file mode 100644
index 0000000..551f16c
--- /dev/null
+++ b/sound/soc/txx9/Makefile
@@ -0,0 +1,11 @@
+# Platform
+snd-soc-txx9aclc-objs := txx9aclc.o
+snd-soc-txx9aclc-ac97-objs := txx9aclc-ac97.o
+
+obj-$(CONFIG_SND_SOC_TXX9ACLC) += snd-soc-txx9aclc.o
+obj-$(CONFIG_SND_SOC_TXX9ACLC_AC97) += snd-soc-txx9aclc-ac97.o
+
+# Machine
+snd-soc-txx9aclc-generic-objs := txx9aclc-generic.o
+
+obj-$(CONFIG_SND_SOC_TXX9ACLC_GENERIC) += snd-soc-txx9aclc-generic.o
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
new file mode 100644
index 0000000..5bf9fd0
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -0,0 +1,214 @@
+/*
+ * TXx9 ACLC AC97 driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "txx9aclc.h"
+
+#define AC97_DIR	\
+	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define AC97_RATES	\
+	SNDRV_PCM_RATE_8000_48000
+
+#ifdef __BIG_ENDIAN
+#define AC97_FMTS	SNDRV_PCM_FMTBIT_S16_BE
+#else
+#define AC97_FMTS	SNDRV_PCM_FMTBIT_S16_LE
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
+
+/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
+static struct txx9aclc_soc_device *txx9aclc_soc_dev;
+
+static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
+{
+	return __raw_readl(dev->base + ACINTSTS) & ACINT_REGACCRDY;
+}
+
+/* AC97 controller reads codec register */
+static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
+					 unsigned short reg)
+{
+	struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+	u32 dat;
+
+	if (!(__raw_readl(dev->base + ACINTSTS) & ACINT_CODECRDY(ac97->num)))
+		return 0xffff;
+	reg |= ac97->num << 7;
+	dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
+	__raw_writel(dat, dev->base + ACREGACC);
+	__raw_writel(ACINT_REGACCRDY, dev->base + ACINTEN);
+	if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+		__raw_writel(ACINT_REGACCRDY, dev->base + ACINTDIS);
+		dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg);
+		dat = 0xffff;
+		goto done;
+	}
+	dat = __raw_readl(dev->base + ACREGACC);
+	if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
+		dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n",
+			dat, reg);
+		dat = 0xffff;
+		goto done;
+	}
+	dat = (dat >> ACREGACC_DAT_SHIFT) & 0xffff;
+done:
+	__raw_writel(ACINT_REGACCRDY, dev->base + ACINTDIS);
+	return dat;
+}
+
+/* AC97 controller writes to codec register */
+static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+				unsigned short val)
+{
+	struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+
+	__raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
+		     (val << ACREGACC_DAT_SHIFT),
+		     dev->base + ACREGACC);
+	__raw_writel(ACINT_REGACCRDY, dev->base + ACINTEN);
+	if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+		dev_err(dev->soc_dev.dev,
+			"ac97 write timeout (reg %#x)\n", reg);
+	}
+	__raw_writel(ACINT_REGACCRDY, dev->base + ACINTDIS);
+}
+
+static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
+	u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
+
+	__raw_writel(ACCTL_ENLINK, dev->base + ACCTLDIS);
+	mmiowb();
+	udelay(1);
+	__raw_writel(ACCTL_ENLINK, dev->base + ACCTLEN);
+	/* wait for primary codec ready status */
+	__raw_writel(ready, dev->base + ACINTEN);
+	if (!wait_event_timeout(ac97_waitq,
+				(__raw_readl(dev->base + ACINTSTS) & ready)
+				== ready, HZ)) {
+		dev_err(&ac97->dev, "primary codec is not ready "
+			"(status %#x)\n",
+			__raw_readl(dev->base + ACINTSTS));
+	}
+	__raw_writel(ACINT_REGACCRDY, dev->base + ACINTSTS);
+	__raw_writel(ready, dev->base + ACINTDIS);
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read		= txx9aclc_ac97_read,
+	.write		= txx9aclc_ac97_write,
+	.reset		= txx9aclc_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
+{
+	struct txx9aclc_soc_device *dev = dev_id;
+
+	__raw_writel(__raw_readl(dev->base + ACINTMSTS), dev->base + ACINTDIS);
+	wake_up(&ac97_waitq);
+	return IRQ_HANDLED;
+}
+
+static int txx9aclc_ac97_probe(struct platform_device *pdev,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct txx9aclc_soc_device *dev =
+		container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+	int err;
+
+	err = request_irq(dev->irq, txx9aclc_ac97_irq,
+			  IRQF_DISABLED, dev_name(&pdev->dev), dev);
+	if (err < 0)
+		return err;
+	txx9aclc_soc_dev = dev;
+	return 0;
+}
+
+static void txx9aclc_ac97_remove(struct platform_device *pdev,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct txx9aclc_soc_device *dev =
+		container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+
+	/* disable AC-link */
+	__raw_writel(ACCTL_ENLINK, dev->base + ACCTLDIS);
+	free_irq(dev->irq, dev);
+	txx9aclc_soc_dev = NULL;
+}
+
+#ifdef CONFIG_PM
+static int txx9aclc_ac97_suspend(struct snd_soc_dai *dai)
+{
+	return 0;
+}
+
+static int txx9aclc_ac97_resume(struct snd_soc_dai *dai)
+{
+	return 0;
+}
+#else
+#define txx9aclc_ac97_suspend	NULL
+#define txx9aclc_ac97_resume	NULL
+#endif
+
+struct snd_soc_dai txx9aclc_ac97_dai = {
+	.name			= "txx9aclc_ac97",
+	.ac97_control		= 1,
+	.probe			= txx9aclc_ac97_probe,
+	.remove			= txx9aclc_ac97_remove,
+	.suspend		= txx9aclc_ac97_suspend,
+	.resume			= txx9aclc_ac97_resume,
+	.playback = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+	.capture = {
+		.rates		= AC97_RATES,
+		.formats	= AC97_FMTS,
+		.channels_min	= 2,
+		.channels_max	= 2,
+	},
+};
+EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai);
+
+static int __init txx9aclc_ac97_init(void)
+{
+	return snd_soc_register_dai(&txx9aclc_ac97_dai);
+}
+
+static void __exit txx9aclc_ac97_exit(void)
+{
+	snd_soc_unregister_dai(&txx9aclc_ac97_dai);
+}
+
+module_init(txx9aclc_ac97_init);
+module_exit(txx9aclc_ac97_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc-generic.c b/sound/soc/txx9/txx9aclc-generic.c
new file mode 100644
index 0000000..edd1c37
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc-generic.c
@@ -0,0 +1,129 @@
+/*
+ * Generic TXx9 ACLC machine driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This is a very generic AC97 sound machine driver for boards which
+ * have (AC97) audio at ACLC (e.g. RBTX49XX boards).
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "../codecs/ac97.h"
+#include "txx9aclc.h"
+
+static struct snd_soc_dai_link txx9aclc_generic_dai = {
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.cpu_dai = &txx9aclc_ac97_dai,
+	.codec_dai = &ac97_dai,
+};
+
+static struct snd_soc_card txx9aclc_generic_card = {
+	.name		= "Generic TXx9 ACLC Audio",
+	.platform	= &txx9aclc_soc_platform,
+	.dai_link	= &txx9aclc_generic_dai,
+	.num_links	= 1,
+};
+
+static struct txx9aclc_soc_device txx9aclc_generic_soc_device = {
+	.soc_dev = {
+		.card		= &txx9aclc_generic_card,
+		.codec_dev	= &soc_codec_dev_ac97,
+	},
+};
+
+static int __init txx9aclc_generic_probe(struct platform_device *pdev)
+{
+	struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
+	struct platform_device *soc_pdev;
+	struct resource *r;
+	int ret;
+	int i;
+	int irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+	dev->irq = irq;
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -EBUSY;
+
+	if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
+				     dev_name(&pdev->dev)))
+		return -EBUSY;
+	dev->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+	if (!dev->base)
+		return -EBUSY;
+	dev->physbase = r->start;
+	if (sizeof(dev->physbase) > sizeof(r->start) &&
+	    r->start >= TXX9_DIRECTMAP_BASE &&
+	    r->start < TXX9_DIRECTMAP_BASE + 0x400000)
+		dev->physbase |= 0xf00000000ull;
+
+	for (i = 0; i < 2; i++) {
+		r = platform_get_resource(pdev, IORESOURCE_DMA, i);
+		if (!r)
+			return -EBUSY;
+		dev->dmadata[i].dma_res = r;
+	}
+
+	soc_pdev = platform_device_alloc("soc-audio", -1);
+	if (!soc_pdev)
+		return -ENOMEM;
+	platform_set_drvdata(soc_pdev, &dev->soc_dev);
+	dev->soc_dev.dev = &soc_pdev->dev;
+	ret = platform_device_add(soc_pdev);
+	if (ret) {
+		platform_device_put(soc_pdev);
+		return ret;
+	}
+	platform_set_drvdata(pdev, soc_pdev);
+	return 0;
+}
+
+static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
+{
+	struct platform_device *soc_pdev = platform_get_drvdata(pdev);
+
+	platform_device_unregister(soc_pdev);
+	return 0;
+}
+
+static struct platform_driver txx9aclc_generic_driver = {
+	.remove = txx9aclc_generic_remove,
+	.driver = {
+		.name = "txx9aclc-generic",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init txx9aclc_generic_init(void)
+{
+	return platform_driver_probe(&txx9aclc_generic_driver,
+				     txx9aclc_generic_probe);
+}
+
+static void __exit txx9aclc_generic_exit(void)
+{
+	platform_driver_unregister(&txx9aclc_generic_driver);
+}
+
+module_init(txx9aclc_generic_init);
+module_exit(txx9aclc_generic_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Generic TXx9 ACLC ALSA SoC audio driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
new file mode 100644
index 0000000..0dc3153
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc.c
@@ -0,0 +1,415 @@
+/*
+ * Generic TXx9 ACLC platform driver
+ *
+ * Copyright (C) 2009 Atsushi Nemoto
+ *
+ * Based on RBTX49xx patch from CELF patch archive.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "txx9aclc.h"
+
+static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
+	/*
+	 * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
+	 * needs more works for noncoherent MIPS.
+	 */
+	.info		  = SNDRV_PCM_INFO_INTERLEAVED |
+			    SNDRV_PCM_INFO_BATCH |
+			    SNDRV_PCM_INFO_PAUSE,
+#ifdef __BIG_ENDIAN
+	.formats	  = SNDRV_PCM_FMTBIT_S16_BE,
+#else
+	.formats	  = SNDRV_PCM_FMTBIT_S16_LE,
+#endif
+	.period_bytes_min = 1024,
+	.period_bytes_max = 8 * 1024,
+	.periods_min	  = 2,
+	.periods_max	  = 4096,
+	.buffer_bytes_max = 32 * 1024,
+};
+
+static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct txx9aclc_dmadata *dmadata = runtime->private_data;
+	int ret;
+
+	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(socdev->dev,
+		"runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
+		"runtime->min_align %ld\n",
+		(unsigned long)runtime->dma_area,
+		(unsigned long)runtime->dma_addr, runtime->dma_bytes,
+		runtime->min_align);
+	dev_dbg(socdev->dev,
+		"periods %d period_bytes %d stream %d\n",
+		params_periods(params), params_period_bytes(params),
+		substream->stream);
+
+	dmadata->substream = substream;
+	dmadata->pos = 0;
+	return 0;
+}
+
+static int txx9aclc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int txx9aclc_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct txx9aclc_dmadata *dmadata = runtime->private_data;
+
+	dmadata->dma_addr = runtime->dma_addr;
+	dmadata->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+	dmadata->period_bytes = snd_pcm_lib_period_bytes(substream);
+
+	if (dmadata->buffer_bytes == dmadata->period_bytes) {
+		dmadata->frag_bytes = dmadata->period_bytes >> 1;
+		dmadata->frags = 2;
+	} else {
+		dmadata->frag_bytes = dmadata->period_bytes;
+		dmadata->frags = dmadata->buffer_bytes / dmadata->period_bytes;
+	}
+	dmadata->frag_count = 0;
+	dmadata->pos = 0;
+	return 0;
+}
+
+static void txx9aclc_dma_complete(void *arg)
+{
+	struct txx9aclc_dmadata *dmadata = arg;
+	unsigned long flags;
+
+	/* dma completion handler cannot submit new operations */
+	spin_lock_irqsave(&dmadata->dma_lock, flags);
+	if (dmadata->frag_count >= 0) {
+		dmadata->dmacount--;
+		BUG_ON(dmadata->dmacount < 0);
+		tasklet_schedule(&dmadata->tasklet);
+	}
+	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+}
+
+static struct dma_async_tx_descriptor *
+txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr)
+{
+	struct dma_chan *chan = dmadata->dma_chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)),
+		    dmadata->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1));
+	sg_dma_address(&sg) = buf_dma_addr;
+	desc = chan->device->device_prep_slave_sg(chan, &sg, 1,
+		dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		DMA_TO_DEVICE : DMA_FROM_DEVICE,
+		DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc) {
+		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+		return NULL;
+	}
+	desc->callback = txx9aclc_dma_complete;
+	desc->callback_param = dmadata;
+	desc->tx_submit(desc);
+	return desc;
+}
+
+#define NR_DMA_CHAIN		2
+
+static void txx9aclc_dma_tasklet(unsigned long data)
+{
+	struct txx9aclc_dmadata *dmadata = (struct txx9aclc_dmadata *)data;
+	struct dma_chan *chan = dmadata->dma_chan;
+	struct dma_async_tx_descriptor *desc;
+	struct snd_pcm_substream *substream = dmadata->substream;
+	u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		ACCTL_AUDODMA : ACCTL_AUDIDMA;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dmadata->dma_lock, flags);
+	if (dmadata->frag_count < 0) {
+		struct txx9aclc_soc_device *dev =
+			container_of(dmadata, struct txx9aclc_soc_device,
+				     dmadata[substream->stream]);
+		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+		chan->device->device_terminate_all(chan);
+		/* first time */
+		for (i = 0; i < NR_DMA_CHAIN; i++) {
+			desc = txx9aclc_dma_submit(dmadata,
+				dmadata->dma_addr + i * dmadata->frag_bytes);
+			if (!desc)
+				return;
+		}
+		dmadata->dmacount = NR_DMA_CHAIN;
+		chan->device->device_issue_pending(chan);
+		spin_lock_irqsave(&dmadata->dma_lock, flags);
+		__raw_writel(ctlbit, dev->base + ACCTLEN);
+		dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags;
+		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+		return;
+	}
+	BUG_ON(dmadata->dmacount >= NR_DMA_CHAIN);
+	while (dmadata->dmacount < NR_DMA_CHAIN) {
+		dmadata->dmacount++;
+		spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+		desc = txx9aclc_dma_submit(dmadata,
+			dmadata->dma_addr +
+			dmadata->frag_count * dmadata->frag_bytes);
+		if (!desc)
+			return;
+		chan->device->device_issue_pending(chan);
+
+		spin_lock_irqsave(&dmadata->dma_lock, flags);
+		dmadata->frag_count++;
+		dmadata->frag_count %= dmadata->frags;
+		dmadata->pos += dmadata->frag_bytes;
+		dmadata->pos %= dmadata->buffer_bytes;
+		if ((dmadata->frag_count * dmadata->frag_bytes) %
+		    dmadata->period_bytes == 0)
+			snd_pcm_period_elapsed(substream);
+	}
+	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+}
+
+static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct txx9aclc_soc_device *dev =
+		container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+	unsigned long flags;
+	int ret = 0;
+	u32 ctlbit = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+		ACCTL_AUDODMA : ACCTL_AUDIDMA;
+
+	spin_lock_irqsave(&dmadata->dma_lock, flags);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dmadata->frag_count = -1;
+		tasklet_schedule(&dmadata->tasklet);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		__raw_writel(ctlbit, dev->base + ACCTLDIS);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		__raw_writel(ctlbit, dev->base + ACCTLEN);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+	return ret;
+}
+
+static snd_pcm_uframes_t
+txx9aclc_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+
+	return bytes_to_frames(substream->runtime, dmadata->pos);
+}
+
+static int txx9aclc_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct txx9aclc_soc_device *dev =
+		container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+	struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
+	int ret;
+
+	ret = snd_soc_set_runtime_hwparams(substream, &txx9aclc_pcm_hardware);
+	if (ret)
+		return ret;
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+	substream->runtime->private_data = dmadata;
+	return 0;
+}
+
+static int txx9aclc_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
+	struct dma_chan *chan = dmadata->dma_chan;
+
+	dmadata->frag_count = -1;
+	chan->device->device_terminate_all(chan);
+	return 0;
+}
+
+static struct snd_pcm_ops txx9aclc_pcm_ops = {
+	.open		= txx9aclc_pcm_open,
+	.close		= txx9aclc_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= txx9aclc_pcm_hw_params,
+	.hw_free	= txx9aclc_pcm_hw_free,
+	.prepare	= txx9aclc_pcm_prepare,
+	.trigger	= txx9aclc_pcm_trigger,
+	.pointer	= txx9aclc_pcm_pointer,
+};
+
+static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+			    struct snd_pcm *pcm)
+{
+	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+		card->dev, 64 * 1024, 4 * 1024 * 1024);
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct txx9aclc_dmadata *dmadata = param;
+	char devname[BUS_ID_SIZE + 2];
+
+	sprintf(devname, "%s.%d", dmadata->dma_res->name,
+		(int)dmadata->dma_res->start);
+	if (strcmp(dev_name(chan->device->dev), devname) == 0) {
+		chan->private = &dmadata->dma_slave;
+		return true;
+	}
+	return false;
+}
+
+static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
+			     struct txx9aclc_dmadata *dmadata)
+{
+	struct txx9dmac_slave *ds = &dmadata->dma_slave;
+	dma_cap_mask_t mask;
+
+	spin_lock_init(&dmadata->dma_lock);
+
+	ds->reg_width = sizeof(u32);
+	if (dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ds->tx_reg = dev->physbase + ACAUDODAT;
+		ds->rx_reg = 0;
+	} else {
+		ds->tx_reg = 0;
+		ds->rx_reg = dev->physbase + ACAUDIDAT;
+	}
+
+	/* Try to grab a DMA channel */
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
+	if (!dmadata->dma_chan) {
+		dev_err(dev->soc_dev.dev,
+			"DMA channel for %s is not available\n",
+			dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+			"playback" : "capture");
+		return -EBUSY;
+	}
+	tasklet_init(&dmadata->tasklet, txx9aclc_dma_tasklet,
+		     (unsigned long)dmadata);
+	return 0;
+}
+
+static int txx9aclc_pcm_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct txx9aclc_soc_device *dev =
+		container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+	int i;
+	int ret;
+
+	dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
+	dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
+	for (i = 0; i < 2; i++) {
+		ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
+		if (ret)
+			goto exit;
+	}
+	return 0;
+
+exit:
+	for (i = 0; i < 2; i++) {
+		if (dev->dmadata[i].dma_chan)
+			dma_release_channel(dev->dmadata[i].dma_chan);
+		dev->dmadata[i].dma_chan = NULL;
+	}
+	return ret;
+}
+
+static int txx9aclc_pcm_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct txx9aclc_soc_device *dev =
+		container_of(socdev, struct txx9aclc_soc_device, soc_dev);
+	int i;
+
+	/* disable all FIFO DMAs */
+	__raw_writel(ACCTL_AUDODMA | ACCTL_AUDIDMA, dev->base + ACCTLDIS);
+	/* dummy R/W to clear pending DMAREQ if any */
+	__raw_writel(__raw_readl(dev->base + ACAUDIDAT),
+		     dev->base + ACAUDODAT);
+
+	for (i = 0; i < 2; i++) {
+		struct txx9aclc_dmadata *dmadata = &dev->dmadata[i];
+		struct dma_chan *chan = dmadata->dma_chan;
+		if (chan) {
+			dmadata->frag_count = -1;
+			chan->device->device_terminate_all(chan);
+			dma_release_channel(chan);
+		}
+		dev->dmadata[i].dma_chan = NULL;
+	}
+	return 0;
+}
+
+struct snd_soc_platform txx9aclc_soc_platform = {
+	.name		= "txx9aclc-audio",
+	.probe		= txx9aclc_pcm_probe,
+	.remove		= txx9aclc_pcm_remove,
+	.pcm_ops 	= &txx9aclc_pcm_ops,
+	.pcm_new	= txx9aclc_pcm_new,
+	.pcm_free	= txx9aclc_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
+
+static int __init txx9aclc_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&txx9aclc_soc_platform);
+}
+
+static void __exit txx9aclc_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&txx9aclc_soc_platform);
+}
+
+module_init(txx9aclc_soc_platform_init);
+module_exit(txx9aclc_soc_platform_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/txx9/txx9aclc.h b/sound/soc/txx9/txx9aclc.h
new file mode 100644
index 0000000..c1c1162
--- /dev/null
+++ b/sound/soc/txx9/txx9aclc.h
@@ -0,0 +1,74 @@
+/*
+ * TXx9 SoC AC Link Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TXX9ACLC_H
+#define __TXX9ACLC_H
+
+#include <linux/interrupt.h>
+#include <asm/txx9/dmac.h>
+
+#define ACCTLEN			0x00	/* control enable */
+#define ACCTLDIS		0x04	/* control disable */
+#define   ACCTL_ENLINK		0x00000001	/* enable/disable AC-link */
+#define   ACCTL_AUDODMA		0x00000100	/* AUDODMA enable/disable */
+#define   ACCTL_AUDIDMA		0x00001000	/* AUDIDMA enable/disable */
+#define   ACCTL_AUDOEHLT	0x00010000	/* AUDO error halt
+						   enable/disable */
+#define   ACCTL_AUDIEHLT	0x00100000	/* AUDI error halt
+						   enable/disable */
+#define ACREGACC		0x08	/* codec register access */
+#define   ACREGACC_DAT_SHIFT	0	/* data field */
+#define   ACREGACC_REG_SHIFT	16	/* address field */
+#define   ACREGACC_CODECID_SHIFT	24	/* CODEC ID field */
+#define   ACREGACC_READ		0x80000000	/* CODEC read */
+#define   ACREGACC_WRITE	0x00000000	/* CODEC write */
+#define ACINTSTS		0x10	/* interrupt status */
+#define ACINTMSTS		0x14	/* interrupt masked status */
+#define ACINTEN			0x18	/* interrupt enable */
+#define ACINTDIS		0x1c	/* interrupt disable */
+#define   ACINT_CODECRDY(n)	(0x00000001 << (n))	/* CODECn ready */
+#define   ACINT_REGACCRDY	0x00000010	/* ACREGACC ready */
+#define   ACINT_AUDOERR		0x00000100	/* AUDO underrun error */
+#define   ACINT_AUDIERR		0x00001000	/* AUDI overrun error */
+#define ACDMASTS		0x80	/* DMA request status */
+#define   ACDMA_AUDO		0x00000001	/* AUDODMA pending */
+#define   ACDMA_AUDI		0x00000010	/* AUDIDMA pending */
+#define ACAUDODAT		0xa0	/* audio out data */
+#define ACAUDIDAT		0xb0	/* audio in data */
+#define ACREVID			0xfc	/* revision ID */
+
+struct txx9aclc_dmadata {
+	struct resource *dma_res;
+	struct txx9dmac_slave dma_slave;
+	struct dma_chan *dma_chan;
+	struct tasklet_struct tasklet;
+	spinlock_t dma_lock;
+	int stream; /* SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE */
+	struct snd_pcm_substream *substream;
+	unsigned long pos;
+	dma_addr_t dma_addr;
+	unsigned long buffer_bytes;
+	unsigned long period_bytes;
+	unsigned long frag_bytes;
+	int frags;
+	int frag_count;
+	int dmacount;
+};
+
+struct txx9aclc_soc_device {
+	struct snd_soc_device soc_dev;
+	void __iomem *base;
+	u64 physbase;
+	int irq;
+	struct txx9aclc_dmadata dmadata[2];
+};
+
+extern struct snd_soc_platform txx9aclc_soc_platform;
+extern struct snd_soc_dai txx9aclc_ac97_dai;
+
+#endif /* __TXX9ACLC_H */
-- 
1.5.6.5

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

* [PATCH] TXx9: Add ACLC support
@ 2009-05-14 14:50       ` Atsushi Nemoto
  2009-05-15  9:01         ` Ralf Baechle
                           ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Atsushi Nemoto @ 2009-05-14 14:50 UTC (permalink / raw)
  To: linux-mips; +Cc: ralf, alsa-devel, Mark Brown

Add platform support for ACLC of TXx9 SoCs.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
---
This patch depends on txx9dmac patch (platform) in linux-mips queue
tree or linux-next tree.

 arch/mips/include/asm/txx9/generic.h  |    5 ++++
 arch/mips/include/asm/txx9/tx4927.h   |    2 +
 arch/mips/include/asm/txx9/tx4938.h   |    1 +
 arch/mips/include/asm/txx9/tx4939.h   |    1 +
 arch/mips/txx9/Kconfig                |    3 ++
 arch/mips/txx9/generic/setup.c        |   36 +++++++++++++++++++++++++++
 arch/mips/txx9/generic/setup_tx4927.c |   43 +++++++++++++++++++++++++++++++++
 arch/mips/txx9/generic/setup_tx4938.c |   11 ++++++++
 arch/mips/txx9/generic/setup_tx4939.c |    9 +++++++
 arch/mips/txx9/rbtx4927/setup.c       |    7 ++++-
 arch/mips/txx9/rbtx4938/setup.c       |    1 +
 arch/mips/txx9/rbtx4939/setup.c       |    1 +
 12 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/arch/mips/include/asm/txx9/generic.h b/arch/mips/include/asm/txx9/generic.h
index 9cde009..8169477 100644
--- a/arch/mips/include/asm/txx9/generic.h
+++ b/arch/mips/include/asm/txx9/generic.h
@@ -91,4 +91,9 @@ void txx9_7segled_init(unsigned int num,
 		       void (*putc)(unsigned int pos, unsigned char val));
 int txx9_7segled_putc(unsigned int pos, char c);
 
+void __init txx9_aclc_init(unsigned long baseaddr, int irq,
+			   unsigned int dmac_id,
+			   unsigned int dma_chan_out,
+			   unsigned int dma_chan_in);
+
 #endif /* __ASM_TXX9_GENERIC_H */
diff --git a/arch/mips/include/asm/txx9/tx4927.h b/arch/mips/include/asm/txx9/tx4927.h
index d92ae07..18c98c5 100644
--- a/arch/mips/include/asm/txx9/tx4927.h
+++ b/arch/mips/include/asm/txx9/tx4927.h
@@ -50,6 +50,7 @@
 #define TX4927_NR_SIO	2
 #define TX4927_SIO_REG(ch)	(TX4927_REG_BASE + 0xf300 + (ch) * 0x100)
 #define TX4927_PIO_REG		(TX4927_REG_BASE + 0xf500)
+#define TX4927_ACLC_REG		(TX4927_REG_BASE + 0xf700)
 
 #define TX4927_IR_ECCERR	0
 #define TX4927_IR_WTOERR	1
@@ -267,5 +268,6 @@ void tx4927_setup_pcierr_irq(void);
 void tx4927_irq_init(void);
 void tx4927_mtd_init(int ch);
 void tx4927_dmac_init(int memcpy_chan);
+void tx4927_aclc_init(unsigned int dma_chan_out, unsigned int dma_chan_in);
 
 #endif /* __ASM_TXX9_TX4927_H */
diff --git a/arch/mips/include/asm/txx9/tx4938.h b/arch/mips/include/asm/txx9/tx4938.h
index 0758a0c..54e4674 100644
--- a/arch/mips/include/asm/txx9/tx4938.h
+++ b/arch/mips/include/asm/txx9/tx4938.h
@@ -306,5 +306,6 @@ struct tx4938ide_platform_info {
 
 void tx4938_ata_init(unsigned int irq, unsigned int shift, int tune);
 void tx4938_dmac_init(int memcpy_chan0, int memcpy_chan1);
+void tx4938_aclc_init(void);
 
 #endif
diff --git a/arch/mips/include/asm/txx9/tx4939.h b/arch/mips/include/asm/txx9/tx4939.h
index 1be9798..f13b708 100644
--- a/arch/mips/include/asm/txx9/tx4939.h
+++ b/arch/mips/include/asm/txx9/tx4939.h
@@ -545,5 +545,6 @@ void tx4939_rtc_init(void);
 void tx4939_ndfmc_init(unsigned int hold, unsigned int spw,
 		       unsigned char ch_mask, unsigned char wide_mask);
 void tx4939_dmac_init(int memcpy_chan0, int memcpy_chan1);
+void tx4939_aclc_init(void);
 
 #endif /* __ASM_TXX9_TX4939_H */
diff --git a/arch/mips/txx9/Kconfig b/arch/mips/txx9/Kconfig
index 0db7cf3..852ae4b 100644
--- a/arch/mips/txx9/Kconfig
+++ b/arch/mips/txx9/Kconfig
@@ -69,6 +69,7 @@ config SOC_TX4927
 	select IRQ_TXX9
 	select PCI_TX4927
 	select GPIO_TXX9
+	select HAS_TXX9_ACLC
 
 config SOC_TX4938
 	bool
@@ -78,6 +79,7 @@ config SOC_TX4938
 	select IRQ_TXX9
 	select PCI_TX4927
 	select GPIO_TXX9
+	select HAS_TXX9_ACLC
 
 config SOC_TX4939
 	bool
@@ -85,6 +87,7 @@ config SOC_TX4939
 	select HAS_TXX9_SERIAL
 	select HW_HAS_PCI
 	select PCI_TX4927
+	select HAS_TXX9_ACLC
 
 config TXX9_7SEGLED
 	bool
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
index 369d863..bc358ab 100644
--- a/arch/mips/txx9/generic/setup.c
+++ b/arch/mips/txx9/generic/setup.c
@@ -876,3 +876,39 @@ void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
 	}
 #endif
 }
+
+void __init txx9_aclc_init(unsigned long baseaddr, int irq,
+			   unsigned int dmac_id,
+			   unsigned int dma_chan_out,
+			   unsigned int dma_chan_in)
+{
+#if defined(CONFIG_SND_SOC_TXX9ACLC_GENERIC) || \
+	defined(CONFIG_SND_SOC_TXX9ACLC_GENERIC_MODULE)
+	unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS;
+	struct resource res[] = {
+		{
+			.start = baseaddr,
+			.end = baseaddr + 0x100 - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = irq,
+			.flags = IORESOURCE_IRQ,
+		}, {
+			.name = "txx9dmac-chan",
+			.start = dma_base + dma_chan_out,
+			.flags = IORESOURCE_DMA,
+		}, {
+			.name = "txx9dmac-chan",
+			.start = dma_base + dma_chan_in,
+			.flags = IORESOURCE_DMA,
+		}
+	};
+	struct platform_device *pdev =
+		platform_device_alloc("txx9aclc-generic", -1);
+
+	if (!pdev ||
+	    platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
+	    platform_device_add(pdev))
+		platform_device_put(pdev);
+#endif
+}
diff --git a/arch/mips/txx9/generic/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c
index 6b681cd..3418b2a 100644
--- a/arch/mips/txx9/generic/setup_tx4927.c
+++ b/arch/mips/txx9/generic/setup_tx4927.c
@@ -265,6 +265,49 @@ void __init tx4927_dmac_init(int memcpy_chan)
 		       TXX9_IRQ_BASE + TX4927_IR_DMA(0), &plat_data);
 }
 
+void __init tx4927_aclc_init(unsigned int dma_chan_out,
+			     unsigned int dma_chan_in)
+{
+	u64 pcfg = __raw_readq(&tx4927_ccfgptr->pcfg);
+	__u64 dmasel_mask = 0, dmasel = 0;
+	unsigned long flags;
+
+	if (!(pcfg & TX4927_PCFG_SEL2))
+		return;
+	/* setup DMASEL (playback:ACLC ch0, capture:ACLC ch1) */
+	switch (dma_chan_out) {
+	case 0:
+		dmasel_mask |= TX4927_PCFG_DMASEL0_MASK;
+		dmasel |= TX4927_PCFG_DMASEL0_ACL0;
+		break;
+	case 2:
+		dmasel_mask |= TX4927_PCFG_DMASEL2_MASK;
+		dmasel |= TX4927_PCFG_DMASEL2_ACL0;
+		break;
+	default:
+		return;
+	}
+	switch (dma_chan_in) {
+	case 1:
+		dmasel_mask |= TX4927_PCFG_DMASEL1_MASK;
+		dmasel |= TX4927_PCFG_DMASEL1_ACL1;
+		break;
+	case 3:
+		dmasel_mask |= TX4927_PCFG_DMASEL3_MASK;
+		dmasel |= TX4927_PCFG_DMASEL3_ACL1;
+		break;
+	default:
+		return;
+	}
+	local_irq_save(flags);
+	txx9_clear64(&tx4927_ccfgptr->pcfg, dmasel_mask);
+	txx9_set64(&tx4927_ccfgptr->pcfg, dmasel);
+	local_irq_restore(flags);
+	txx9_aclc_init(TX4927_ACLC_REG & 0xfffffffffULL,
+		       TXX9_IRQ_BASE + TX4927_IR_ACLC,
+		       0, dma_chan_out, dma_chan_in);
+}
+
 static void __init tx4927_stop_unused_modules(void)
 {
 	__u64 pcfg, rst = 0, ckd = 0;
diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c
index b2b8529..4dfdb52 100644
--- a/arch/mips/txx9/generic/setup_tx4938.c
+++ b/arch/mips/txx9/generic/setup_tx4938.c
@@ -414,6 +414,17 @@ void __init tx4938_dmac_init(int memcpy_chan0, int memcpy_chan1)
 	}
 }
 
+void __init tx4938_aclc_init(void)
+{
+	u64 pcfg = __raw_readq(&tx4938_ccfgptr->pcfg);
+
+	if ((pcfg & TX4938_PCFG_SEL2) &&
+	    !(pcfg & TX4938_PCFG_ETH0_SEL))
+		txx9_aclc_init(TX4938_ACLC_REG & 0xfffffffffULL,
+			       TXX9_IRQ_BASE + TX4938_IR_ACLC,
+			       1, 0, 1);
+}
+
 static void __init tx4938_stop_unused_modules(void)
 {
 	__u64 pcfg, rst = 0, ckd = 0;
diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c
index 98effef..7139686 100644
--- a/arch/mips/txx9/generic/setup_tx4939.c
+++ b/arch/mips/txx9/generic/setup_tx4939.c
@@ -485,6 +485,15 @@ void __init tx4939_dmac_init(int memcpy_chan0, int memcpy_chan1)
 	}
 }
 
+void __init tx4939_aclc_init(void)
+{
+	u64 pcfg = __raw_readq(&tx4939_ccfgptr->pcfg);
+
+	if ((pcfg & TX4939_PCFG_I2SMODE_MASK) == TX4939_PCFG_I2SMODE_ACLC)
+		txx9_aclc_init(TX4939_ACLC_REG & 0xfffffffffULL,
+			       TXX9_IRQ_BASE + TX4939_IR_ACLC, 1, 0, 1);
+}
+
 static void __init tx4939_stop_unused_modules(void)
 {
 	__u64 pcfg, rst = 0, ckd = 0;
diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c
index 332cdbc..ece43db 100644
--- a/arch/mips/txx9/rbtx4927/setup.c
+++ b/arch/mips/txx9/rbtx4927/setup.c
@@ -337,10 +337,13 @@ static void __init rbtx4927_device_init(void)
 	rbtx4927_ne_init();
 	tx4927_wdt_init();
 	rbtx4927_mtd_init();
-	if (TX4927_REV_PCODE() == 0x4927)
+	if (TX4927_REV_PCODE() == 0x4927) {
 		tx4927_dmac_init(2);
-	else
+		tx4927_aclc_init(0, 1);
+	} else {
 		tx4938_dmac_init(0, 2);
+		tx4938_aclc_init();
+	}
 	txx9_iocled_init(RBTX4927_LED_ADDR - IO_BASE, -1, 3, 1, "green", NULL);
 	rbtx4927_gpioled_init();
 }
diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c
index 37c5e3d..c0aa889 100644
--- a/arch/mips/txx9/rbtx4938/setup.c
+++ b/arch/mips/txx9/rbtx4938/setup.c
@@ -356,6 +356,7 @@ static void __init rbtx4938_device_init(void)
 	tx4938_ndfmc_init(10, 35);
 	tx4938_ata_init(RBTX4938_IRQ_IOC_ATA, 0, 1);
 	tx4938_dmac_init(0, 2);
+	tx4938_aclc_init();
 	txx9_iocled_init(RBTX4938_LED_ADDR - IO_BASE, -1, 8, 1, "green", NULL);
 }
 
diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c
index 91f2ec8..1d01126 100644
--- a/arch/mips/txx9/rbtx4939/setup.c
+++ b/arch/mips/txx9/rbtx4939/setup.c
@@ -499,6 +499,7 @@ static void __init rbtx4939_device_init(void)
 	tx4939_ata_init();
 	tx4939_rtc_init();
 	tx4939_dmac_init(0, 2);
+	tx4939_aclc_init();
 }
 
 static void __init rbtx4939_setup(void)
-- 
1.5.6.5

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

* Re: [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver
  2009-05-14 14:50 [PATCH] ASoC: Add TXx9 AC link controller driver Atsushi Nemoto
@ 2009-05-14 18:59 ` Mark Brown
  2009-05-15 15:12   ` Atsushi Nemoto
  0 siblings, 1 reply; 13+ messages in thread
From: Mark Brown @ 2009-05-14 18:59 UTC (permalink / raw)
  To: Atsushi Nemoto; +Cc: linux-mips, alsa-devel, ralf

On Thu, May 14, 2009 at 11:50:04PM +0900, Atsushi Nemoto wrote:

This all looks basically fine - just a few comments below, the main one
being the way you're registering things.

> +#ifdef CONFIG_PM
> +static int txx9aclc_ac97_suspend(struct snd_soc_dai *dai)
> +{
> +	return 0;
> +}
> +
> +static int txx9aclc_ac97_resume(struct snd_soc_dai *dai)
> +{
> +	return 0;
> +}
> +#else
> +#define txx9aclc_ac97_suspend	NULL
> +#define txx9aclc_ac97_resume	NULL
> +#endif

Just remove all this if there's no implementation.

> +static int __init txx9aclc_ac97_init(void)
> +{
> +	return snd_soc_register_dai(&txx9aclc_ac97_dai);
> +}
> +
> +static void __exit txx9aclc_ac97_exit(void)
> +{
> +	snd_soc_unregister_dai(&txx9aclc_ac97_dai);
> +}

Ideally you'd be registering a platform device in your arch code and
then the DAI would only be registered when the device is probed.  This
(and similar stuff for the DMA) would mean that...

> +static int __init txx9aclc_generic_probe(struct platform_device *pdev)
> +{
> +	struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
> +	struct platform_device *soc_pdev;
> +	struct resource *r;
> +	int ret;
> +	int i;
> +	int irq;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;
> +	dev->irq = irq;

...all this resource stuff wouldn't need to be done by the machine
driver, it'd be done by your DAI and DMA drivers.  That means less
duplication of code for multiple machines both in the machine driver and
in registering the resources along with the platform device.

> +static int __init txx9aclc_soc_platform_init(void)
> +{
> +	return snd_soc_register_platform(&txx9aclc_soc_platform);
> +}
> +
> +static void __exit txx9aclc_soc_platform_exit(void)
> +{
> +	snd_soc_unregister_platform(&txx9aclc_soc_platform);
> +}

Same comment applies here.

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

* Re: [PATCH] TXx9: Add ACLC support
  2009-05-14 14:50       ` [PATCH] TXx9: Add ACLC support Atsushi Nemoto
@ 2009-05-15  9:01         ` Ralf Baechle
  2009-05-15  9:17           ` [alsa-devel] " Mark Brown
  2009-05-15 13:45         ` Geert Uytterhoeven
  2009-05-16 13:45         ` [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver Atsushi Nemoto
  2 siblings, 1 reply; 13+ messages in thread
From: Ralf Baechle @ 2009-05-15  9:01 UTC (permalink / raw)
  To: Atsushi Nemoto; +Cc: linux-mips, alsa-devel, Mark Brown

On Thu, May 14, 2009 at 11:50:05PM +0900, Atsushi Nemoto wrote:
> From: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
> Date: Thu, 14 May 2009 23:50:05 +0900
> To: linux-mips@linux-mips.org
> Cc: ralf@linux-mips.org, alsa-devel@alsa-project.org,
> 	Mark Brown <broonie@opensource.wolfsonmicro.com>
> Subject: [PATCH] TXx9: Add ACLC support
> 
> Add platform support for ACLC of TXx9 SoCs.

Thanks, queued up for 2.6.31 / linux-next.

  Ralf

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

* Re: [alsa-devel] [PATCH] TXx9: Add ACLC support
  2009-05-15  9:01         ` Ralf Baechle
@ 2009-05-15  9:17           ` Mark Brown
  2009-05-15 10:09             ` Ralf Baechle
  0 siblings, 1 reply; 13+ messages in thread
From: Mark Brown @ 2009-05-15  9:17 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Atsushi Nemoto, linux-mips, alsa-devel

On Fri, May 15, 2009 at 10:01:19AM +0100, Ralf Baechle wrote:
> On Thu, May 14, 2009 at 11:50:05PM +0900, Atsushi Nemoto wrote:

> > Add platform support for ACLC of TXx9 SoCs.

> Thanks, queued up for 2.6.31 / linux-next.

These will need revision after fixing my review comments for the audio
drivers - the way the platform devices are set up needs to be changed so
that the resources are associated with devices for the CPU rather than
the machine driver that says how a given board is connected up.

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

* Re: [alsa-devel] [PATCH] TXx9: Add ACLC support
  2009-05-15  9:17           ` [alsa-devel] " Mark Brown
@ 2009-05-15 10:09             ` Ralf Baechle
  0 siblings, 0 replies; 13+ messages in thread
From: Ralf Baechle @ 2009-05-15 10:09 UTC (permalink / raw)
  To: Mark Brown; +Cc: Atsushi Nemoto, linux-mips, alsa-devel

On Fri, May 15, 2009 at 10:17:43AM +0100, Mark Brown wrote:

> On Fri, May 15, 2009 at 10:01:19AM +0100, Ralf Baechle wrote:
> > On Thu, May 14, 2009 at 11:50:05PM +0900, Atsushi Nemoto wrote:
> 
> > > Add platform support for ACLC of TXx9 SoCs.
> 
> > Thanks, queued up for 2.6.31 / linux-next.
> 
> These will need revision after fixing my review comments for the audio
> drivers - the way the platform devices are set up needs to be changed so
> that the resources are associated with devices for the CPU rather than
> the machine driver that says how a given board is connected up.

Ok; I re-queued the patch into my -mm tree until we declare it ripe.

  Ralf

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

* Re: [PATCH] TXx9: Add ACLC support
  2009-05-14 14:50       ` [PATCH] TXx9: Add ACLC support Atsushi Nemoto
  2009-05-15  9:01         ` Ralf Baechle
@ 2009-05-15 13:45         ` Geert Uytterhoeven
  2009-05-15 15:14           ` Atsushi Nemoto
  2009-05-16 13:45         ` [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver Atsushi Nemoto
  2 siblings, 1 reply; 13+ messages in thread
From: Geert Uytterhoeven @ 2009-05-15 13:45 UTC (permalink / raw)
  To: Atsushi Nemoto
  Cc: Linux/MIPS Development, Ralf Baechle, alsa-devel, Mark Brown

On Thu, 14 May 2009, Atsushi Nemoto wrote:
> Add platform support for ACLC of TXx9 SoCs.

I gave it a try on my RBTX4927, and after some fight^H^H^H^H^Hplaying with the
alsa tools, I could play sound using `speaker-test --test wav --channels 2'!

With kind regards,

Geert Uytterhoeven
Software Architect
Techsoft Centre

Technology and Software Centre Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium

Phone:    +32 (0)2 700 8453
Fax:      +32 (0)2 700 8622
E-mail:   Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/

A division of Sony Europe (Belgium) N.V.
VAT BE 0413.825.160 · RPR Brussels
Fortis · BIC GEBABEBB · IBAN BE41293037680010

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

* Re: [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver
  2009-05-14 18:59 ` [alsa-devel] " Mark Brown
@ 2009-05-15 15:12   ` Atsushi Nemoto
  2009-05-15 19:05     ` Mark Brown
  0 siblings, 1 reply; 13+ messages in thread
From: Atsushi Nemoto @ 2009-05-15 15:12 UTC (permalink / raw)
  To: broonie; +Cc: linux-mips, alsa-devel, ralf

On Thu, 14 May 2009 19:59:46 +0100, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> This all looks basically fine - just a few comments below, the main one
> being the way you're registering things.

Thank you for quick review!

> > +#define txx9aclc_ac97_suspend	NULL
> > +#define txx9aclc_ac97_resume	NULL
> > +#endif
> 
> Just remove all this if there's no implementation.

OK.  I will do.

> Ideally you'd be registering a platform device in your arch code and
> then the DAI would only be registered when the device is probed.  This
> (and similar stuff for the DMA) would mean that...
...
> ...all this resource stuff wouldn't need to be done by the machine
> driver, it'd be done by your DAI and DMA drivers.  That means less
> duplication of code for multiple machines both in the machine driver and
> in registering the resources along with the platform device.

OK, then I will move irq/mem resource stuff to the DAI driver and dma
resource stuff to the DMA driver.

I placed them in the machine driver because both DAI and DMA drivers
need the mem resource.  I can move the mem resource stuff into the DAI
driver since the DAI driver will be probed before the DMA driver.

OTOH, I want to keep arch code as is.  There are some TXx9 SoC
variations and they can have different baseaddr/irq/dma.  I want to
leave these details in arch code and make ASoC drivers generic as
possible.

---
Atsushi Nemoto

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

* Re: [PATCH] TXx9: Add ACLC support
  2009-05-15 13:45         ` Geert Uytterhoeven
@ 2009-05-15 15:14           ` Atsushi Nemoto
  0 siblings, 0 replies; 13+ messages in thread
From: Atsushi Nemoto @ 2009-05-15 15:14 UTC (permalink / raw)
  To: Geert.Uytterhoeven; +Cc: linux-mips, ralf, alsa-devel, broonie

On Fri, 15 May 2009 15:45:36 +0200 (CEST), Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> wrote:
> > Add platform support for ACLC of TXx9 SoCs.
> 
> I gave it a try on my RBTX4927, and after some fight^H^H^H^H^Hplaying with the
> alsa tools, I could play sound using `speaker-test --test wav --channels 2'!

Good news!  Thanks for your trial.

---
Atsushi Nemoto

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

* Re: [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver
  2009-05-15 15:12   ` Atsushi Nemoto
@ 2009-05-15 19:05     ` Mark Brown
  2009-05-14 14:50       ` [PATCH] TXx9: Add ACLC support Atsushi Nemoto
  0 siblings, 1 reply; 13+ messages in thread
From: Mark Brown @ 2009-05-15 19:05 UTC (permalink / raw)
  To: Atsushi Nemoto; +Cc: linux-mips, alsa-devel, ralf

On Sat, May 16, 2009 at 12:12:02AM +0900, Atsushi Nemoto wrote:

> OK, then I will move irq/mem resource stuff to the DAI driver and dma
> resource stuff to the DMA driver.

Either is fine - do whatever makes most sense for your system.

> OTOH, I want to keep arch code as is.  There are some TXx9 SoC
> variations and they can have different baseaddr/irq/dma.  I want to
> leave these details in arch code and make ASoC drivers generic as
> possible.

This is the common situation for SoC CPUs - most silicon vendors reuse
the same IPs in diffierent combinations on different CPUs.  The normal
approach is to have the generic code for each SoC set up the resources
for the devices that are present on that particular SoC.  This avoids
the need for each board using the SoC to have to replicate the
information.

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

* Re: [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver
  2009-05-14 14:50       ` [PATCH] TXx9: Add ACLC support Atsushi Nemoto
  2009-05-15  9:01         ` Ralf Baechle
  2009-05-15 13:45         ` Geert Uytterhoeven
@ 2009-05-16 13:45         ` Atsushi Nemoto
  2009-05-16 14:25           ` Mark Brown
  2 siblings, 1 reply; 13+ messages in thread
From: Atsushi Nemoto @ 2009-05-16 13:45 UTC (permalink / raw)
  To: broonie; +Cc: linux-mips, alsa-devel, ralf

On Fri, 15 May 2009 20:05:58 +0100, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> > OTOH, I want to keep arch code as is.  There are some TXx9 SoC
> > variations and they can have different baseaddr/irq/dma.  I want to
> > leave these details in arch code and make ASoC drivers generic as
> > possible.
> 
> This is the common situation for SoC CPUs - most silicon vendors reuse
> the same IPs in diffierent combinations on different CPUs.  The normal
> approach is to have the generic code for each SoC set up the resources
> for the devices that are present on that particular SoC.  This avoids
> the need for each board using the SoC to have to replicate the
> information.

Yes, and I tried to do so in "TXx9: Add ACLC support" patch.

>  arch/mips/include/asm/txx9/generic.h  |    5 ++++
>  arch/mips/include/asm/txx9/tx4927.h   |    2 +
>  arch/mips/include/asm/txx9/tx4938.h   |    1 +
>  arch/mips/include/asm/txx9/tx4939.h   |    1 +
>  arch/mips/txx9/Kconfig                |    3 ++
>  arch/mips/txx9/generic/setup.c        |   36 +++++++++++++++++++++++++++
>  arch/mips/txx9/generic/setup_tx4927.c |   43 +++++++++++++++++++++++++++++++++
>  arch/mips/txx9/generic/setup_tx4938.c |   11 ++++++++
>  arch/mips/txx9/generic/setup_tx4939.c |    9 +++++++

These are "the generic code for each SoC set up the resources for
the devices that are present on that particular SoC".

>  arch/mips/txx9/rbtx4927/setup.c       |    7 ++++-
>  arch/mips/txx9/rbtx4938/setup.c       |    1 +
>  arch/mips/txx9/rbtx4939/setup.c       |    1 +

And these are setup codes for each boards.

Is this acceptable?  I'm not sure whether you are saying Ack or Nack
for this approach.

---
Atsushi Nemoto

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

* Re: [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver
  2009-05-16 13:45         ` [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver Atsushi Nemoto
@ 2009-05-16 14:25           ` Mark Brown
  2009-05-17 14:46             ` Atsushi Nemoto
  0 siblings, 1 reply; 13+ messages in thread
From: Mark Brown @ 2009-05-16 14:25 UTC (permalink / raw)
  To: Atsushi Nemoto; +Cc: linux-mips, alsa-devel, ralf

On Sat, May 16, 2009 at 10:45:41PM +0900, Atsushi Nemoto wrote:

> Is this acceptable?  I'm not sure whether you are saying Ack or Nack
> for this approach.

Yes, this approach is fine.  All I'm saying is that you should be
setting up devices for the DAIs and the platform device and putting the
resources that are common to the SoC in there and not in the device that
is being used to use the board-specific sound driver.

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

* Re: [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver
  2009-05-16 14:25           ` Mark Brown
@ 2009-05-17 14:46             ` Atsushi Nemoto
  0 siblings, 0 replies; 13+ messages in thread
From: Atsushi Nemoto @ 2009-05-17 14:46 UTC (permalink / raw)
  To: broonie; +Cc: linux-mips, alsa-devel, ralf

On Sat, 16 May 2009 15:25:12 +0100, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> > Is this acceptable?  I'm not sure whether you are saying Ack or Nack
> > for this approach.
> 
> Yes, this approach is fine.  All I'm saying is that you should be
> setting up devices for the DAIs and the platform device and putting the
> resources that are common to the SoC in there and not in the device that
> is being used to use the board-specific sound driver.

Then I will update "ASoC: Add TXx9 AC link controller driver" part and
send again in a few days.  Thanks.

---
Atsushi Nemoto

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

end of thread, other threads:[~2009-05-17 14:47 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-14 14:50 [PATCH] ASoC: Add TXx9 AC link controller driver Atsushi Nemoto
2009-05-14 18:59 ` [alsa-devel] " Mark Brown
2009-05-15 15:12   ` Atsushi Nemoto
2009-05-15 19:05     ` Mark Brown
2009-05-14 14:50       ` [PATCH] TXx9: Add ACLC support Atsushi Nemoto
2009-05-15  9:01         ` Ralf Baechle
2009-05-15  9:17           ` [alsa-devel] " Mark Brown
2009-05-15 10:09             ` Ralf Baechle
2009-05-15 13:45         ` Geert Uytterhoeven
2009-05-15 15:14           ` Atsushi Nemoto
2009-05-16 13:45         ` [alsa-devel] [PATCH] ASoC: Add TXx9 AC link controller driver Atsushi Nemoto
2009-05-16 14:25           ` Mark Brown
2009-05-17 14:46             ` Atsushi Nemoto

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox