All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch 5/6] kirkwood: Add i2s support
  2010-05-11 16:23 [patch 0/6] kirkwood openrd client audio support apatard
@ 2010-05-11 16:23 ` apatard
  2010-05-12 10:24   ` Mark Brown
  0 siblings, 1 reply; 45+ messages in thread
From: apatard @ 2010-05-11 16:23 UTC (permalink / raw)
  To: alsa-devel; +Cc: Arnaud Patard, broonie, saeed, nico, tbm

[-- Attachment #1: kirkwood_i2s.patch --]
[-- Type: text/plain, Size: 33099 bytes --]

This patch enables support for the i2s codec available on kirkwood platforms

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

---
 sound/soc/Kconfig                 |    1 	1 +	0 -	0 !
 sound/soc/Makefile                |    1 	1 +	0 -	0 !
 sound/soc/kirkwood/Kconfig        |   11 	11 +	0 -	0 !
 sound/soc/kirkwood/Makefile       |    6 	6 +	0 -	0 !
 sound/soc/kirkwood/kirkwood-dma.c |  366 	366 +	0 -	0 !
 sound/soc/kirkwood/kirkwood-dma.h |   17 	17 +	0 -	0 !
 sound/soc/kirkwood/kirkwood-i2s.c |  471 	471 +	0 -	0 !
 sound/soc/kirkwood/kirkwood-i2s.h |   17 	17 +	0 -	0 !
 sound/soc/kirkwood/kirkwood.h     |  168 	168 +	0 -	0 !
 9 files changed, 1058 insertions(+)

Index: linux-2.6.33/sound/soc/kirkwood/Kconfig
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.33/sound/soc/kirkwood/Kconfig	2010-05-11 18:05:14.981650112 +0200
@@ -0,0 +1,11 @@
+config SND_KIRKWOOD_SOC
+	tristate "SoC Audio for the Marvell Kirkwood chip"
+	depends on ARCH_KIRKWOOD
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the Kirkwood I2S interface. You will also need
+	  to select the audio interfaces to support below.
+
+config SND_KIRKWOOD_SOC_I2S
+	tristate
+
Index: linux-2.6.33/sound/soc/kirkwood/kirkwood-dma.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.33/sound/soc/kirkwood/kirkwood-dma.c	2010-05-11 18:09:38.361669930 +0200
@@ -0,0 +1,366 @@
+/*
+ * kirkwood-dma.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mbus.h>
+#include <sound/soc.h>
+#include "kirkwood-dma.h"
+#include "kirkwood.h"
+
+
+struct kirkwood_dma_priv {
+	struct snd_pcm_substream *play_stream;
+	struct snd_pcm_substream *rec_stream;
+	struct kirkwood_dma_data *data;
+};
+
+static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_PAUSE),
+	.formats		= KIRKWOOD_FORMATS,
+	.rates			= KIRKWOOD_RATES,
+	.rate_min		= 44100,
+	.rate_max		= 96000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
+	.period_bytes_min	= KIRKWOOD_SND_MIN_PERIOD_BYTES,
+	.period_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES,
+	.periods_min		= KIRKWOOD_SND_MIN_PERIODS,
+	.periods_max		= KIRKWOOD_SND_MAX_PERIODS,
+	.fifo_size		= 0,
+};
+
+static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL;
+
+static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
+{
+	struct kirkwood_dma_priv *prdata = dev_id;
+	struct kirkwood_dma_data *priv = prdata->data;
+	unsigned long mask, status, cause;
+
+	mask = readl(priv->io + KIRKWOOD_INT_MASK);
+	status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
+
+	cause = readl(priv->io + KIRKWOOD_ERR_CAUSE);
+	if (unlikely(cause)) {
+		printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
+				__func__, cause);
+		writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
+		return IRQ_HANDLED;
+	}
+
+	do {
+		/* we've enabled only bytes interrupts ... */
+		if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
+				KIRKWOOD_INT_CAUSE_REC_BYTES))
+			return IRQ_NONE;
+
+		/* ack int */
+		writel(status, priv->io + KIRKWOOD_INT_CAUSE);
+
+		if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
+			snd_pcm_period_elapsed(prdata->play_stream);
+
+		if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
+			snd_pcm_period_elapsed(prdata->rec_stream);
+
+		mask = readl(priv->io + KIRKWOOD_INT_MASK);
+		status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
+	} while (status);
+
+	return IRQ_HANDLED;
+}
+
+static int kirkwood_dma_open(struct snd_pcm_substream *substream)
+{
+	int err;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+	snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
+
+	/* Ensure that all constraints linked to dma burst are fullfilled */
+	err = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			priv->burst * 2,
+			KIRKWOOD_AUDIO_BUF_MAX-1);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_hw_constraint_step(runtime, 0,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			priv->burst);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_hw_constraint_step(substream->runtime, 0,
+			 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+			 priv->burst);
+	if (err < 0)
+		return err;
+
+	if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+		prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
+		if (prdata == NULL)
+			return -ENOMEM;
+
+		prdata->data = priv;
+
+		err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
+				  "kirkwood-dma", prdata);
+		if (err) {
+			kfree(prdata);
+			return -EBUSY;
+		}
+
+		soc_runtime->dai->cpu_dai->private_data = prdata;
+
+		/*
+		 * Enable Error interrupts. We're only ack'ing them but
+		 * it's usefull for diagnostics
+		 */
+		writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prdata->play_stream = substream;
+	else
+		prdata->rec_stream = substream;
+
+	return 0;
+}
+
+static int kirkwood_dma_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+	struct kirkwood_dma_data *priv;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	if (!prdata || !priv)
+		return 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prdata->play_stream = NULL;
+	else
+		prdata->rec_stream = NULL;
+
+	if (!prdata->play_stream && !prdata->rec_stream) {
+		writel(0, priv->io + KIRKWOOD_ERR_MASK);
+		free_irq(priv->irq, prdata);
+		kfree(prdata);
+		soc_runtime->dai->cpu_dai->private_data = NULL;
+	}
+
+	return 0;
+}
+
+static int kirkwood_dma_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 int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	unsigned long size, count;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	/* compute buffer size in term of "words" as requested in specs */
+	size = frames_to_bytes(runtime, runtime->buffer_size);
+	size = (size>>2)-1;
+	count = snd_pcm_lib_period_bytes(substream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT);
+		writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR);
+		writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE);
+	} else {
+		writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT);
+		writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR);
+		writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE);
+	}
+
+
+	return 0;
+}
+
+static int kirkwood_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	return 0;
+}
+
+static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
+						*substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	snd_pcm_uframes_t count;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		count = bytes_to_frames(substream->runtime,
+			readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
+	else
+		count = bytes_to_frames(substream->runtime,
+			readl(priv->io + KIRKWOOD_REC_BYTE_COUNT));
+
+	return count;
+}
+
+static int kirkwood_dma_mmap(struct snd_pcm_substream *substream,
+		struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_coherent(substream->pcm->card->dev, vma,
+					runtime->dma_area,
+					runtime->dma_addr,
+					runtime->dma_bytes);
+}
+
+
+struct snd_pcm_ops kirkwood_dma_ops = {
+	.open =		kirkwood_dma_open,
+	.close =        kirkwood_dma_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	kirkwood_dma_hw_params,
+	.hw_free =      kirkwood_dma_hw_free,
+	.prepare =      kirkwood_dma_prepare,
+	.trigger =	kirkwood_dma_trigger,
+	.pointer =	kirkwood_dma_pointer,
+	.mmap =		kirkwood_dma_mmap,
+};
+
+static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
+		int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+			&buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	buf->private_data = NULL;
+
+	return 0;
+}
+
+static int kirkwood_dma_new(struct snd_card *card,
+		struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+	int ret;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &kirkwood_dma_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].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;
+	}
+}
+
+struct snd_soc_platform kirkwood_soc_platform = {
+	.name		= "kirkwood-dma",
+	.pcm_ops	= &kirkwood_dma_ops,
+	.pcm_new	= kirkwood_dma_new,
+	.pcm_free	= kirkwood_dma_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
+
+static int __init kirkwood_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&kirkwood_soc_platform);
+}
+module_init(kirkwood_soc_platform_init);
+
+static void __exit kirkwood_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&kirkwood_soc_platform);
+}
+module_exit(kirkwood_soc_platform_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
+MODULE_LICENSE("GPL");
+
Index: linux-2.6.33/sound/soc/kirkwood/kirkwood.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.33/sound/soc/kirkwood/kirkwood.h	2010-05-11 18:05:14.985650562 +0200
@@ -0,0 +1,168 @@
+/*
+ * kirkwood.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_AUDIO_H
+#define _KIRKWOOD_AUDIO_H
+
+#define KIRKWOOD_RECORD_WIN			0
+#define KIRKWOOD_PLAYBACK_WIN			1
+#define KIRKWOOD_MAX_AUDIO_WIN			2
+
+#define AUDIO_WIN_BASE_REG(win)			(0xA00 + ((win)<<3))
+#define AUDIO_WIN_CTRL_REG(win)			(0xA04 + ((win)<<3))
+
+
+#define KIRKWOOD_RECCTL				0x1000
+#define KIRKWOOD_RECCTL_SPDIF_EN		(1<<11)
+#define KIRKWOOD_RECCTL_I2S_EN			(1<<10)
+#define KIRKWOOD_RECCTL_PAUSE			(1<<9)
+#define KIRKWOOD_RECCTL_MUTE			(1<<8)
+#define KIRKWOOD_RECCTL_BURST_MASK		(3<<5)
+#define KIRKWOOD_RECCTL_BURST_128		(2<<5)
+#define KIRKWOOD_RECCTL_BURST_32		(1<<5)
+#define KIRKWOOD_RECCTL_MONO			(1<<4)
+#define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT		(1<<3)
+#define KIRKWOOD_RECCTL_MONO_CHAN_LEFT		(0<<3)
+#define KIRKWOOD_RECCTL_SIZE_MASK		(7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16			(7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16_C		(3<<0)
+#define KIRKWOOD_RECCTL_SIZE_20			(2<<0)
+#define KIRKWOOD_RECCTL_SIZE_24			(1<<0)
+#define KIRKWOOD_RECCTL_SIZE_32			(0<<0)
+
+#define KIRKWOOD_REC_BUF_ADDR			0x1004
+#define KIRKWOOD_REC_BUF_SIZE			0x1008
+#define KIRKWOOD_REC_BYTE_COUNT			0x100C
+
+#define KIRKWOOD_PLAYCTL			0x1100
+#define KIRKWOOD_PLAYCTL_PLAY_BUSY		(1<<16)
+#define KIRKWOOD_PLAYCTL_BURST_MASK		(3<<11)
+#define KIRKWOOD_PLAYCTL_BURST_128		(2<<11)
+#define KIRKWOOD_PLAYCTL_BURST_32		(1<<11)
+#define KIRKWOOD_PLAYCTL_PAUSE			(1<<9)
+#define KIRKWOOD_PLAYCTL_SPDIF_MUTE		(1<<8)
+#define KIRKWOOD_PLAYCTL_I2S_MUTE		(1<<7)
+#define KIRKWOOD_PLAYCTL_SPDIF_EN		(1<<4)
+#define KIRKWOOD_PLAYCTL_I2S_EN			(1<<3)
+#define KIRKWOOD_PLAYCTL_SIZE_MASK		(7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16		(7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16_C		(3<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_20		(2<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_24		(1<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_32		(0<<0)
+
+#define KIRKWOOD_PLAY_BUF_ADDR			0x1104
+#define KIRKWOOD_PLAY_BUF_SIZE			0x1108
+#define KIRKWOOD_PLAY_BYTE_COUNT		0x110C
+
+#define KIRKWOOD_DCO_CTL			0x1204
+#define KIRKWOOD_DCO_CTL_OFFSET_MASK		(0xFFF<<2)
+#define KIRKWOOD_DCO_CTL_OFFSET_0		(0x800<<2)
+#define KIRKWOOD_DCO_CTL_FREQ_MASK		(3<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_11		(0<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_12		(1<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_24		(2<<0)
+
+#define KIRKWOOD_DCO_SPCR_STATUS		0x120c
+#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK	(1<<16)
+
+#define KIRKWOOD_ERR_CAUSE			0x1300
+#define KIRKWOOD_ERR_MASK			0x1304
+
+#define KIRKWOOD_INT_CAUSE			0x1308
+#define KIRKWOOD_INT_MASK			0x130C
+#define KIRKWOOD_INT_CAUSE_PLAY_BYTES		(1<<14)
+#define KIRKWOOD_INT_CAUSE_REC_BYTES		(1<<13)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_END		(1<<7)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q		(1<<6)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF	(1<<5)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q		(1<<4)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_END		(1<<3)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_3Q		(1<<2)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_HALF		(1<<1)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_1Q		(1<<0)
+
+#define KIRKWOOD_REC_BYTE_INT_COUNT		0x1310
+#define KIRKWOOD_PLAY_BYTE_INT_COUNT		0x1314
+#define KIRKWOOD_BYTE_INT_COUNT_MASK		0xffffff
+
+#define KIRKWOOD_I2S_PLAYCTL			0x2508
+#define KIRKWOOD_I2S_RECCTL			0x2408
+#define KIRKWOOD_I2S_CTL_JUST_MASK		(0xf<<26)
+#define KIRKWOOD_I2S_CTL_LJ			(0<<26)
+#define KIRKWOOD_I2S_CTL_I2S			(5<<26)
+#define KIRKWOOD_I2S_CTL_RJ			(8<<26)
+#define KIRKWOOD_I2S_CTL_SIZE_MASK		(3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_16		(3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_20		(2<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_24		(1<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_32		(0<<30)
+
+#define KIRKWOOD_AUDIO_BUF_MAX			(16*1024*1024)
+
+/* Theses values come from the marvell alsa driver */
+/* need to find where they come from               */
+#define KIRKWOOD_SND_MIN_PERIODS		8
+#define KIRKWOOD_SND_MAX_PERIODS		16
+#define	KIRKWOOD_SND_MIN_PERIOD_BYTES		0x4000
+#define	KIRKWOOD_SND_MAX_PERIOD_BYTES		0x4000
+
+
+#define KIRKWOOD_RATES \
+	(SNDRV_PCM_RATE_44100 | \
+	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
+
+/* I2S formats and kirkwood dma are the same but it's not
+ * true for SPDIF (which can't do 32
+ */
+#define KIRKWOOD_I2S_RATES			KIRKWOOD_RATES
+#define KIRKWOOD_I2S_FORMATS			KIRKWOOD_FORMATS
+
+struct kirkwood_dma_data {
+	struct resource *mem;
+	void __iomem *io;
+	int irq;
+	int burst;
+	struct mbus_dram_target_info *dram;
+};
+
+static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
+{
+	unsigned long value;
+
+	value = KIRKWOOD_DCO_CTL_OFFSET_0;
+	switch (rate) {
+	default:
+	case 44100:
+		value |= KIRKWOOD_DCO_CTL_FREQ_11;
+		break;
+	case 48000:
+		value |= KIRKWOOD_DCO_CTL_FREQ_12;
+		break;
+	case 96000:
+		value |= KIRKWOOD_DCO_CTL_FREQ_24;
+		break;
+	}
+	writel(value, io + KIRKWOOD_DCO_CTL);
+
+	/* wait for dco locked */
+	do {
+		cpu_relax();
+		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
+		value &= KIRKWOOD_DCO_SPCR_STATUS;
+	} while (value == 0);
+}
+
+#endif
Index: linux-2.6.33/sound/soc/kirkwood/kirkwood-i2s.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.33/sound/soc/kirkwood/kirkwood-i2s.c	2010-05-11 18:10:30.769691011 +0200
@@ -0,0 +1,471 @@
+/*
+ * kirkwood-i2s.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mbus.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/audio.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood.h"
+
+#define DRV_NAME	"kirkwood-i2s"
+
+struct snd_soc_dai kirkwood_i2s_dai;
+static struct kirkwood_dma_data *priv;
+
+static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	unsigned long mask;
+	unsigned long value;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		mask = KIRKWOOD_I2S_CTL_RJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mask = KIRKWOOD_I2S_CTL_LJ;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mask = KIRKWOOD_I2S_CTL_I2S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Set same format for playback and record
+	 * This avoids some troubles.
+	 */
+	value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
+	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+	value |= mask;
+	writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
+
+	value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
+	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+	value |= mask;
+	writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
+
+	return 0;
+}
+
+static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	unsigned int i2s_reg, reg;
+	unsigned long i2s_value, value;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_reg = KIRKWOOD_I2S_PLAYCTL;
+		reg = KIRKWOOD_PLAYCTL;
+	} else {
+		i2s_reg = KIRKWOOD_I2S_RECCTL;
+		reg = KIRKWOOD_RECCTL;
+	}
+
+	/* set dco conf */
+	kirkwood_set_dco(priv->io, params_rate(params));
+
+	i2s_value = readl(priv->io+i2s_reg);
+	i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
+
+	value = readl(priv->io+reg);
+	value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
+
+	/*
+	 * Size settings in play/rec i2s control regs and play/rec control
+	 * regs must be the same.
+	 */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
+		value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
+		break;
+	/*
+	 * doesn't work... S20_3LE != kirkwood 20bit format ?
+	 *
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
+		value |= KIRKWOOD_PLAYCTL_SIZE_20;
+		break;
+	*/
+	case SNDRV_PCM_FORMAT_S24_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
+		value |= KIRKWOOD_PLAYCTL_SIZE_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
+		value |= KIRKWOOD_PLAYCTL_SIZE_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+	writel(i2s_value, priv->io+i2s_reg);
+	writel(value, priv->io+reg);
+
+	return 0;
+}
+
+static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	unsigned long value;
+
+	/*
+	 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
+	 * changing it. So read 1 time here and 1 later.
+	 */
+	value = readl(priv->io + KIRKWOOD_PLAYCTL);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* stop audio, enable interrupts */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* configure audio & enable i2s playback */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
+		value &= ~(KIRKWOOD_PLAYCTL_PAUSE|KIRKWOOD_PLAYCTL_SPDIF_EN);
+
+		if (priv->burst == 32)
+			value |= KIRKWOOD_PLAYCTL_BURST_32;
+		else
+			value |= KIRKWOOD_PLAYCTL_BURST_128;
+		value |= KIRKWOOD_PLAYCTL_I2S_EN;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* stop audio, disable interrupts */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* disable all playbacks */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	unsigned long value;
+
+	value = readl(priv->io + KIRKWOOD_RECCTL);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* stop audio, enable interrupts */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* configure audio & enable i2s record */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~KIRKWOOD_RECCTL_BURST_MASK;
+		value &= ~KIRKWOOD_RECCTL_MONO;
+		value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_SPDIF_EN);
+
+		if (priv->burst == 32)
+			value |= KIRKWOOD_RECCTL_BURST_32;
+		else
+			value |= KIRKWOOD_RECCTL_BURST_128;
+		value |= KIRKWOOD_RECCTL_I2S_EN;
+
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* stop audio, disable interrupts */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* disable all records */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return kirkwood_i2s_play_trigger(substream, cmd, dai);
+	else
+		return kirkwood_i2s_rec_trigger(substream, cmd, dai);
+
+	return 0;
+}
+
+static int kirkwood_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
+				int clk_id, unsigned int freq, int dir)
+{
+	return 0;
+}
+
+static void kirkwood_i2s_conf_mbus_windows(void __iomem *base,
+					struct mbus_dram_target_info *dram)
+{
+	int win_num;
+
+	/* First disable and clear windows */
+	for (win_num = 0; win_num < KIRKWOOD_MAX_AUDIO_WIN; win_num++) {
+		writel(0, base + AUDIO_WIN_CTRL_REG(win_num));
+		writel(0, base + AUDIO_WIN_BASE_REG(win_num));
+	}
+
+	/* Setup windows for DDR */
+	for (win_num = 0; win_num < KIRKWOOD_MAX_AUDIO_WIN; win_num++) {
+		/* We will set the Window to DRAM_CS1 in default */
+		struct mbus_dram_window *cs = &dram->cs[1];
+		writel(cs->base & 0xffff0000,
+		       base + AUDIO_WIN_BASE_REG(win_num));
+		writel(((cs->size - 1) & 0xffff0000) |
+		       (cs->mbus_attr << 8) |
+		       (dram->mbus_dram_target_id << 4) | 1,
+			base + AUDIO_WIN_CTRL_REG(win_num));
+	}
+}
+
+static void mv_audio_init(void __iomem *base)
+{
+	int timeout = 10000000;
+	unsigned int reg_data;
+
+	reg_data = readl(base + 0x1200);
+	reg_data &= (~(0x333FF8));
+	reg_data |= 0x111D18;
+	writel(reg_data, base + 0x1200);
+
+	do {
+		timeout--;
+	} while (timeout);
+
+	reg_data = readl(base + 0x1200);
+	reg_data &= (~(0x333FF8));
+	reg_data |= 0x111D18;
+
+	writel(reg_data, base + 0x1200);
+}
+
+static int kirkwood_i2s_probe(struct platform_device *pdev,
+			     struct snd_soc_dai *dai)
+{
+	struct resource *mem;
+	struct kirkwood_soc_platform_data *data =
+		pdev->dev.platform_data;
+	int err;
+	unsigned long value;
+
+	priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "allocation failed\n");
+		err = -ENOMEM;
+		goto error;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "platform_get_resource failed\n");
+		err = -ENXIO;
+		goto err_alloc;
+	}
+
+	priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME);
+	if (!priv->mem) {
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		err = -EBUSY;
+		goto error;
+	}
+
+	priv->io = ioremap(priv->mem->start, SZ_16K);
+	if (!priv->io) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		err = -ENOMEM;
+		goto err_iomem;
+	}
+
+	priv->irq = platform_get_irq(pdev, 0);
+	if (priv->irq <= 0) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		err = -ENXIO;
+		goto err_ioremap;
+	}
+
+	if (!data || !data->dram) {
+		dev_err(&pdev->dev, "no platform data ?!\n");
+		err = -EINVAL;
+		goto err_ioremap;
+	}
+
+	kirkwood_i2s_conf_mbus_windows(priv->io, data->dram);
+	priv->dram = data->dram;
+
+	/* FIXME : should not be hardcoded */
+	priv->burst = 128;
+
+	kirkwood_i2s_dai.capture.dma_data = priv;
+	kirkwood_i2s_dai.playback.dma_data = priv;
+
+	/* put system in a "safe" state : */
+	/* disable audio interrupts */
+	writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
+	writel(0, priv->io + KIRKWOOD_INT_MASK);
+
+	mv_audio_init(priv->io);
+
+	/* disable playback/record */
+	value = readl(priv->io + KIRKWOOD_PLAYCTL);
+	value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
+	writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+	value = readl(priv->io + KIRKWOOD_RECCTL);
+	value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+	writel(value, priv->io + KIRKWOOD_RECCTL);
+
+	dev_info(&pdev->dev, "kirkwood-i2s driver loaded\n");
+
+	return 0;
+
+err_ioremap:
+	iounmap(priv->io);
+err_iomem:
+	release_mem_region(priv->mem->start, SZ_16K);
+err_alloc:
+	kfree(priv);
+error:
+	return err;
+}
+
+static void kirkwood_i2s_remove(struct platform_device *pdev,
+				struct snd_soc_dai *dai)
+{
+	if (priv) {
+		iounmap(priv->io);
+		release_mem_region(priv->mem->start, SZ_16K);
+		kfree(priv);
+	}
+}
+
+static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+	.trigger	= kirkwood_i2s_trigger,
+	.hw_params      = kirkwood_i2s_hw_params,
+	.set_sysclk     = kirkwood_i2s_set_sysclk,
+	.set_fmt        = kirkwood_i2s_set_fmt,
+};
+
+
+struct snd_soc_dai kirkwood_i2s_dai = {
+	.name = DRV_NAME,
+	.id = 0,
+	.probe = kirkwood_i2s_probe,
+	.remove = kirkwood_i2s_remove,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = KIRKWOOD_I2S_RATES,
+		.formats = KIRKWOOD_I2S_FORMATS,},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = KIRKWOOD_I2S_RATES,
+		.formats = KIRKWOOD_I2S_FORMATS,},
+	.ops = &kirkwood_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
+
+static int __init kirkwood_i2s_init(void)
+{
+	return snd_soc_register_dai(&kirkwood_i2s_dai);
+}
+module_init(kirkwood_i2s_init);
+
+static void __exit kirkwood_i2s_exit(void)
+{
+	snd_soc_unregister_dai(&kirkwood_i2s_dai);
+}
+module_exit(kirkwood_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
+MODULE_LICENSE("GPL");
Index: linux-2.6.33/sound/soc/kirkwood/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.33/sound/soc/kirkwood/Makefile	2010-05-11 18:05:14.985650562 +0200
@@ -0,0 +1,6 @@
+snd-soc-kirkwood-objs := kirkwood-dma.o
+snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
+obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
+
Index: linux-2.6.33/sound/soc/Makefile
===================================================================
--- linux-2.6.33.orig/sound/soc/Makefile	2010-05-11 17:38:48.533649884 +0200
+++ linux-2.6.33/sound/soc/Makefile	2010-05-11 18:05:14.985650562 +0200
@@ -8,6 +8,7 @@ obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= davinci/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)   += imx/
+obj-$(CONFIG_SND_SOC)	+= kirkwood/
 obj-$(CONFIG_SND_SOC)	+= omap/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
Index: linux-2.6.33/sound/soc/kirkwood/kirkwood-dma.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.33/sound/soc/kirkwood/kirkwood-dma.h	2010-05-11 18:05:14.985650562 +0200
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-dma.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_DMA_H
+#define _KIRKWOOD_DMA_H
+
+extern struct snd_soc_platform kirkwood_soc_platform;
+
+#endif
Index: linux-2.6.33/sound/soc/kirkwood/kirkwood-i2s.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.33/sound/soc/kirkwood/kirkwood-i2s.h	2010-05-11 18:05:14.989649860 +0200
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-i2s.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_I2S_H
+#define _KIRKWOOD_I2S_H
+
+extern struct snd_soc_dai kirkwood_i2s_dai;
+
+#endif
Index: linux-2.6.33/sound/soc/Kconfig
===================================================================
--- linux-2.6.33.orig/sound/soc/Kconfig	2010-05-11 17:38:48.509650210 +0200
+++ linux-2.6.33/sound/soc/Kconfig	2010-05-11 18:05:14.989649860 +0200
@@ -30,6 +30,7 @@ source "sound/soc/blackfin/Kconfig"
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/imx/Kconfig"
+source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"

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

* Re: [patch 5/6] kirkwood: Add i2s support
  2010-05-11 16:23 ` [patch 5/6] kirkwood: Add i2s support apatard
@ 2010-05-12 10:24   ` Mark Brown
  2010-05-12 10:43     ` Saeed Bishara
                       ` (2 more replies)
  0 siblings, 3 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-12 10:24 UTC (permalink / raw)
  To: apatard; +Cc: alsa-devel, nico, saeed, tbm

On Tue, May 11, 2010 at 06:23:47PM +0200, apatard@mandriva.com wrote:
> This patch enables support for the i2s codec available on kirkwood platforms

It's not a CODEC, it's the I2S controller in the CPU.  A CODEC is a
device with DACs and ADCs in it.

> +	do {
> +		/* we've enabled only bytes interrupts ... */

You were checking for error interrupts further up the function?

> +		if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
> +				KIRKWOOD_INT_CAUSE_REC_BYTES))
> +			return IRQ_NONE;

Surely it'd make sense to log the unexpected interrupts for diagnostics?
You should never get here if there are no interrupts you've enabled.
Unless the interrupt is shared, but that'd be a bit surprising for a
SoC.

It also looks like it'd be more sensible to either drop the do/while
loop entirely (the IRQ core should handle the interrupt still being
asserted and it doesn't look like any of the handling should take so
long that interrupts reassert while it's running anyway) or move the
handling of error interrupts and the first read into the loop so you
don't have two slightly different paths.

> +		/* ack int */
> +		writel(status, priv->io + KIRKWOOD_INT_CAUSE);
> +
> +		if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
> +			snd_pcm_period_elapsed(prdata->play_stream);
> +
> +		if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
> +			snd_pcm_period_elapsed(prdata->rec_stream);
> +
> +		mask = readl(priv->io + KIRKWOOD_INT_MASK);
> +		status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;

This masking didn't happen prior to the first entry into the loop.

> +       if (soc_runtime->dai->cpu_dai->private_data == NULL) {

It seems a bit icky to be managing the DAI private data here...

> +		err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
> +				  "kirkwood-dma", prdata);

I'd suggest "kirkwood-i2s" as a name here.  Or take the name from the
DAI.

> +static int kirkwood_dma_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> +	return 0;
> +}

Remove this if it's not implemented.

> +static int kirkwood_dma_mmap(struct snd_pcm_substream *substream,
> +		struct vm_area_struct *vma)
> +{
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +
> +	return dma_mmap_coherent(substream->pcm->card->dev, vma,
> +					runtime->dma_area,
> +					runtime->dma_addr,
> +					runtime->dma_bytes);
> +}

Hrm, this looks like there should be a utility function to do it, it's
not terribly driver specific.

> +struct snd_soc_platform kirkwood_soc_platform = {
> +	.name		= "kirkwood-dma",

I'd also add an audio in here or something.

> +#define AUDIO_WIN_BASE_REG(win)			(0xA00 + ((win)<<3))
> +#define AUDIO_WIN_CTRL_REG(win)			(0xA04 + ((win)<<3))

Namespacing.  Or move into the driver, there seems little reason for
anything else to be peering at these.

> +#define KIRKWOOD_RATES \
> +	(SNDRV_PCM_RATE_44100 | \
> +	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
> +#define KIRKWOOD_FORMATS \
> +	(SNDRV_PCM_FMTBIT_S16_LE | \
> +	 SNDRV_PCM_FMTBIT_S24_LE | \
> +	 SNDRV_PCM_FMTBIT_S32_LE)

Move these into the driver.

> +static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
> +{
> +	unsigned long value;
> +
> +	value = KIRKWOOD_DCO_CTL_OFFSET_0;
> +	switch (rate) {
> +	default:
> +	case 44100:
> +		value |= KIRKWOOD_DCO_CTL_FREQ_11;
> +		break;
> +	case 48000:
> +		value |= KIRKWOOD_DCO_CTL_FREQ_12;
> +		break;
> +	case 96000:
> +		value |= KIRKWOOD_DCO_CTL_FREQ_24;
> +		break;
> +	}
> +	writel(value, io + KIRKWOOD_DCO_CTL);
> +
> +	/* wait for dco locked */
> +	do {
> +		cpu_relax();
> +		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
> +		value &= KIRKWOOD_DCO_SPCR_STATUS;
> +	} while (value == 0);
> +}

Why is this an inline function in the header?

> +	 * Size settings in play/rec i2s control regs and play/rec control
> +	 * regs must be the same.
> +	 */

Ideally you'd be setting up constraints for this.

> +	/*
> +	 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
> +	 * changing it. So read 1 time here and 1 later.
> +	 */
> +	value = readl(priv->io + KIRKWOOD_PLAYCTL);

Nice...

> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +		/* stop audio, enable interrupts */

If audio is running when you're getting a start trigger something is
wrong...

> +static int kirkwood_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
> +				int clk_id, unsigned int freq, int dir)
> +{
> +	return 0;
> +}

Remove this.

> +static void mv_audio_init(void __iomem *base)
> +{
> +	int timeout = 10000000;
> +	unsigned int reg_data;
> +
> +	reg_data = readl(base + 0x1200);
> +	reg_data &= (~(0x333FF8));
> +	reg_data |= 0x111D18;
> +	writel(reg_data, base + 0x1200);

It's like magic!

> +
> +	do {
> +		timeout--;
> +	} while (timeout);

The driver is busy waiting here but not polling anything.  Just use a
sleep?

> +	/* FIXME : should not be hardcoded */
> +	priv->burst = 128;

Platform data?

> +static int kirkwood_i2s_probe(struct platform_device *pdev,
> +                            struct snd_soc_dai *dai)

This is the ASoC probe but...

+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

...it's pulling all sorts of resources out of the device which are
specific to the I2S controller.  You should have the I2S controller have
a normal platform device which is probed on system startup and triggers
DAI registration, just as you're doing in the CODEC driver.  All the
resources should be there.  Apart from anything else this means you only
need to set up each I2S controller once in the arch/arm code for the
CPU.

> +	mv_audio_init(priv->io);

Seems a bit odd ot have the separate init function in the middle of a
bunch of other register writes.

> +	dev_info(&pdev->dev, "kirkwood-i2s driver loaded\n");

May as well remove this.  The core logs device registration anyway.

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

* Re: [patch 5/6] kirkwood: Add i2s support
  2010-05-12 10:24   ` Mark Brown
@ 2010-05-12 10:43     ` Saeed Bishara
  2010-05-12 10:48     ` saeed bishara
  2010-05-12 14:38     ` Arnaud Patard
  2 siblings, 0 replies; 45+ messages in thread
From: Saeed Bishara @ 2010-05-12 10:43 UTC (permalink / raw)
  To: apatard@mandriva.com
  Cc: alsa-devel@alsa-project.org, Mark Brown, tbm@cyrius.com,
	nico@fluxnic.net

Hi, 
	some of the dma stuff handled by the i2s! For example the i2s trigger function actually enables the dma, this should be moved to the dma driver. Also, the playback and capture trigger funtions looks alike except to registers offsets, maybe you can unify them.
	I suggest also to used devm_ functions in the i2s_probe (devm_request_mem_region, devm_kzalloc, devm_ioremap), this way you can remove the err_ cases. 


saeed
	  

>-----Original Message-----
>From: Mark Brown [mailto:broonie@opensource.wolfsonmicro.com] 
>Sent: Wednesday, May 12, 2010 1:24 PM
>To: apatard@mandriva.com
>Cc: alsa-devel@alsa-project.org; Saeed Bishara; 
>tbm@cyrius.com; nico@fluxnic.net
>Subject: Re: [patch 5/6] kirkwood: Add i2s support
>
>On Tue, May 11, 2010 at 06:23:47PM +0200, apatard@mandriva.com wrote:
>> This patch enables support for the i2s codec available on 
>kirkwood platforms
>
>It's not a CODEC, it's the I2S controller in the CPU.  A CODEC is a
>device with DACs and ADCs in it.
>
>> +	do {
>> +		/* we've enabled only bytes interrupts ... */
>
>You were checking for error interrupts further up the function?
>
>> +		if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
>> +				KIRKWOOD_INT_CAUSE_REC_BYTES))
>> +			return IRQ_NONE;
>
>Surely it'd make sense to log the unexpected interrupts for 
>diagnostics?
>You should never get here if there are no interrupts you've enabled.
>Unless the interrupt is shared, but that'd be a bit surprising for a
>SoC.
>
>It also looks like it'd be more sensible to either drop the do/while
>loop entirely (the IRQ core should handle the interrupt still being
>asserted and it doesn't look like any of the handling should take so
>long that interrupts reassert while it's running anyway) or move the
>handling of error interrupts and the first read into the loop so you
>don't have two slightly different paths.
>
>> +		/* ack int */
>> +		writel(status, priv->io + KIRKWOOD_INT_CAUSE);
>> +
>> +		if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
>> +			snd_pcm_period_elapsed(prdata->play_stream);
>> +
>> +		if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
>> +			snd_pcm_period_elapsed(prdata->rec_stream);
>> +
>> +		mask = readl(priv->io + KIRKWOOD_INT_MASK);
>> +		status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
>
>This masking didn't happen prior to the first entry into the loop.
>
>> +       if (soc_runtime->dai->cpu_dai->private_data == NULL) {
>
>It seems a bit icky to be managing the DAI private data here...
>
>> +		err = request_irq(priv->irq, kirkwood_dma_irq, 
>IRQF_SHARED,
>> +				  "kirkwood-dma", prdata);
>
>I'd suggest "kirkwood-i2s" as a name here.  Or take the name from the
>DAI.
>
>> +static int kirkwood_dma_trigger(struct snd_pcm_substream 
>*substream, int cmd)
>> +{
>> +	return 0;
>> +}
>
>Remove this if it's not implemented.
>
>> +static int kirkwood_dma_mmap(struct snd_pcm_substream *substream,
>> +		struct vm_area_struct *vma)
>> +{
>> +	struct snd_pcm_runtime *runtime = substream->runtime;
>> +
>> +	return dma_mmap_coherent(substream->pcm->card->dev, vma,
>> +					runtime->dma_area,
>> +					runtime->dma_addr,
>> +					runtime->dma_bytes);
>> +}
>
>Hrm, this looks like there should be a utility function to do it, it's
>not terribly driver specific.
>
>> +struct snd_soc_platform kirkwood_soc_platform = {
>> +	.name		= "kirkwood-dma",
>
>I'd also add an audio in here or something.
>
>> +#define AUDIO_WIN_BASE_REG(win)			(0xA00 
>+ ((win)<<3))
>> +#define AUDIO_WIN_CTRL_REG(win)			(0xA04 
>+ ((win)<<3))
>
>Namespacing.  Or move into the driver, there seems little reason for
>anything else to be peering at these.
>
>> +#define KIRKWOOD_RATES \
>> +	(SNDRV_PCM_RATE_44100 | \
>> +	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
>> +#define KIRKWOOD_FORMATS \
>> +	(SNDRV_PCM_FMTBIT_S16_LE | \
>> +	 SNDRV_PCM_FMTBIT_S24_LE | \
>> +	 SNDRV_PCM_FMTBIT_S32_LE)
>
>Move these into the driver.
>
>> +static inline void kirkwood_set_dco(void __iomem *io, 
>unsigned long rate)
>> +{
>> +	unsigned long value;
>> +
>> +	value = KIRKWOOD_DCO_CTL_OFFSET_0;
>> +	switch (rate) {
>> +	default:
>> +	case 44100:
>> +		value |= KIRKWOOD_DCO_CTL_FREQ_11;
>> +		break;
>> +	case 48000:
>> +		value |= KIRKWOOD_DCO_CTL_FREQ_12;
>> +		break;
>> +	case 96000:
>> +		value |= KIRKWOOD_DCO_CTL_FREQ_24;
>> +		break;
>> +	}
>> +	writel(value, io + KIRKWOOD_DCO_CTL);
>> +
>> +	/* wait for dco locked */
>> +	do {
>> +		cpu_relax();
>> +		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
>> +		value &= KIRKWOOD_DCO_SPCR_STATUS;
>> +	} while (value == 0);
>> +}
>
>Why is this an inline function in the header?
>
>> +	 * Size settings in play/rec i2s control regs and 
>play/rec control
>> +	 * regs must be the same.
>> +	 */
>
>Ideally you'd be setting up constraints for this.
>
>> +	/*
>> +	 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
>> +	 * changing it. So read 1 time here and 1 later.
>> +	 */
>> +	value = readl(priv->io + KIRKWOOD_PLAYCTL);
>
>Nice...
>
>> +	switch (cmd) {
>> +	case SNDRV_PCM_TRIGGER_START:
>> +		/* stop audio, enable interrupts */
>
>If audio is running when you're getting a start trigger something is
>wrong...
>
>> +static int kirkwood_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
>> +				int clk_id, unsigned int freq, int dir)
>> +{
>> +	return 0;
>> +}
>
>Remove this.
>
>> +static void mv_audio_init(void __iomem *base)
>> +{
>> +	int timeout = 10000000;
>> +	unsigned int reg_data;
>> +
>> +	reg_data = readl(base + 0x1200);
>> +	reg_data &= (~(0x333FF8));
>> +	reg_data |= 0x111D18;
>> +	writel(reg_data, base + 0x1200);
>
>It's like magic!
>
>> +
>> +	do {
>> +		timeout--;
>> +	} while (timeout);
>
>The driver is busy waiting here but not polling anything.  Just use a
>sleep?
>
>> +	/* FIXME : should not be hardcoded */
>> +	priv->burst = 128;
>
>Platform data?
>
>> +static int kirkwood_i2s_probe(struct platform_device *pdev,
>> +                            struct snd_soc_dai *dai)
>
>This is the ASoC probe but...
>
>+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>
>...it's pulling all sorts of resources out of the device which are
>specific to the I2S controller.  You should have the I2S 
>controller have
>a normal platform device which is probed on system startup and triggers
>DAI registration, just as you're doing in the CODEC driver.  All the
>resources should be there.  Apart from anything else this 
>means you only
>need to set up each I2S controller once in the arch/arm code for the
>CPU.
>
>> +	mv_audio_init(priv->io);
>
>Seems a bit odd ot have the separate init function in the middle of a
>bunch of other register writes.
>
>> +	dev_info(&pdev->dev, "kirkwood-i2s driver loaded\n");
>
>May as well remove this.  The core logs device registration anyway.
>

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

* Re: [patch 5/6] kirkwood: Add i2s support
  2010-05-12 10:24   ` Mark Brown
  2010-05-12 10:43     ` Saeed Bishara
@ 2010-05-12 10:48     ` saeed bishara
  2010-05-12 10:54       ` Mark Brown
  2010-05-12 14:38     ` Arnaud Patard
  2 siblings, 1 reply; 45+ messages in thread
From: saeed bishara @ 2010-05-12 10:48 UTC (permalink / raw)
  To: Mark Brown; +Cc: apatard, alsa-devel, tbm, saeed, nico

Hi,
	some of the dma stuff handled by the i2s! For example the i2s trigger
function actually enables the dma, this should be moved to the dma
driver. Also, the playback and capture trigger funtions looks alike
except to registers offsets, maybe you can unify them.
	I suggest also to used devm_ functions in the i2s_probe
(devm_request_mem_region, devm_kzalloc, devm_ioremap), this way you
can remove the err_ cases.


saeed


On Wed, May 12, 2010 at 1:24 PM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Tue, May 11, 2010 at 06:23:47PM +0200, apatard@mandriva.com wrote:
>> This patch enables support for the i2s codec available on kirkwood platforms
>
> It's not a CODEC, it's the I2S controller in the CPU.  A CODEC is a
> device with DACs and ADCs in it.
>
>> +     do {
>> +             /* we've enabled only bytes interrupts ... */
>
> You were checking for error interrupts further up the function?
>
>> +             if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
>> +                             KIRKWOOD_INT_CAUSE_REC_BYTES))
>> +                     return IRQ_NONE;
>
> Surely it'd make sense to log the unexpected interrupts for diagnostics?
> You should never get here if there are no interrupts you've enabled.
> Unless the interrupt is shared, but that'd be a bit surprising for a
> SoC.
>
> It also looks like it'd be more sensible to either drop the do/while
> loop entirely (the IRQ core should handle the interrupt still being
> asserted and it doesn't look like any of the handling should take so
> long that interrupts reassert while it's running anyway) or move the
> handling of error interrupts and the first read into the loop so you
> don't have two slightly different paths.
>
>> +             /* ack int */
>> +             writel(status, priv->io + KIRKWOOD_INT_CAUSE);
>> +
>> +             if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
>> +                     snd_pcm_period_elapsed(prdata->play_stream);
>> +
>> +             if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
>> +                     snd_pcm_period_elapsed(prdata->rec_stream);
>> +
>> +             mask = readl(priv->io + KIRKWOOD_INT_MASK);
>> +             status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
>
> This masking didn't happen prior to the first entry into the loop.
>
>> +       if (soc_runtime->dai->cpu_dai->private_data == NULL) {
>
> It seems a bit icky to be managing the DAI private data here...
>
>> +             err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
>> +                               "kirkwood-dma", prdata);
>
> I'd suggest "kirkwood-i2s" as a name here.  Or take the name from the
> DAI.
>
>> +static int kirkwood_dma_trigger(struct snd_pcm_substream *substream, int cmd)
>> +{
>> +     return 0;
>> +}
>
> Remove this if it's not implemented.
>
>> +static int kirkwood_dma_mmap(struct snd_pcm_substream *substream,
>> +             struct vm_area_struct *vma)
>> +{
>> +     struct snd_pcm_runtime *runtime = substream->runtime;
>> +
>> +     return dma_mmap_coherent(substream->pcm->card->dev, vma,
>> +                                     runtime->dma_area,
>> +                                     runtime->dma_addr,
>> +                                     runtime->dma_bytes);
>> +}
>
> Hrm, this looks like there should be a utility function to do it, it's
> not terribly driver specific.
>
>> +struct snd_soc_platform kirkwood_soc_platform = {
>> +     .name           = "kirkwood-dma",
>
> I'd also add an audio in here or something.
>
>> +#define AUDIO_WIN_BASE_REG(win)                      (0xA00 + ((win)<<3))
>> +#define AUDIO_WIN_CTRL_REG(win)                      (0xA04 + ((win)<<3))
>
> Namespacing.  Or move into the driver, there seems little reason for
> anything else to be peering at these.
>
>> +#define KIRKWOOD_RATES \
>> +     (SNDRV_PCM_RATE_44100 | \
>> +      SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
>> +#define KIRKWOOD_FORMATS \
>> +     (SNDRV_PCM_FMTBIT_S16_LE | \
>> +      SNDRV_PCM_FMTBIT_S24_LE | \
>> +      SNDRV_PCM_FMTBIT_S32_LE)
>
> Move these into the driver.
>
>> +static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
>> +{
>> +     unsigned long value;
>> +
>> +     value = KIRKWOOD_DCO_CTL_OFFSET_0;
>> +     switch (rate) {
>> +     default:
>> +     case 44100:
>> +             value |= KIRKWOOD_DCO_CTL_FREQ_11;
>> +             break;
>> +     case 48000:
>> +             value |= KIRKWOOD_DCO_CTL_FREQ_12;
>> +             break;
>> +     case 96000:
>> +             value |= KIRKWOOD_DCO_CTL_FREQ_24;
>> +             break;
>> +     }
>> +     writel(value, io + KIRKWOOD_DCO_CTL);
>> +
>> +     /* wait for dco locked */
>> +     do {
>> +             cpu_relax();
>> +             value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
>> +             value &= KIRKWOOD_DCO_SPCR_STATUS;
>> +     } while (value == 0);
>> +}
>
> Why is this an inline function in the header?
>
>> +      * Size settings in play/rec i2s control regs and play/rec control
>> +      * regs must be the same.
>> +      */
>
> Ideally you'd be setting up constraints for this.
>
>> +     /*
>> +      * specs says KIRKWOOD_PLAYCTL must be read 2 times before
>> +      * changing it. So read 1 time here and 1 later.
>> +      */
>> +     value = readl(priv->io + KIRKWOOD_PLAYCTL);
>
> Nice...
>
>> +     switch (cmd) {
>> +     case SNDRV_PCM_TRIGGER_START:
>> +             /* stop audio, enable interrupts */
>
> If audio is running when you're getting a start trigger something is
> wrong...
>
>> +static int kirkwood_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
>> +                             int clk_id, unsigned int freq, int dir)
>> +{
>> +     return 0;
>> +}
>
> Remove this.
>
>> +static void mv_audio_init(void __iomem *base)
>> +{
>> +     int timeout = 10000000;
>> +     unsigned int reg_data;
>> +
>> +     reg_data = readl(base + 0x1200);
>> +     reg_data &= (~(0x333FF8));
>> +     reg_data |= 0x111D18;
>> +     writel(reg_data, base + 0x1200);
>
> It's like magic!
>
>> +
>> +     do {
>> +             timeout--;
>> +     } while (timeout);
>
> The driver is busy waiting here but not polling anything.  Just use a
> sleep?
>
>> +     /* FIXME : should not be hardcoded */
>> +     priv->burst = 128;
>
> Platform data?
>
>> +static int kirkwood_i2s_probe(struct platform_device *pdev,
>> +                            struct snd_soc_dai *dai)
>
> This is the ASoC probe but...
>
> +       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>
> ...it's pulling all sorts of resources out of the device which are
> specific to the I2S controller.  You should have the I2S controller have
> a normal platform device which is probed on system startup and triggers
> DAI registration, just as you're doing in the CODEC driver.  All the
> resources should be there.  Apart from anything else this means you only
> need to set up each I2S controller once in the arch/arm code for the
> CPU.
>
>> +     mv_audio_init(priv->io);
>
> Seems a bit odd ot have the separate init function in the middle of a
> bunch of other register writes.
>
>> +     dev_info(&pdev->dev, "kirkwood-i2s driver loaded\n");
>
> May as well remove this.  The core logs device registration anyway.
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

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

* Re: [patch 5/6] kirkwood: Add i2s support
  2010-05-12 10:48     ` saeed bishara
@ 2010-05-12 10:54       ` Mark Brown
  0 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-12 10:54 UTC (permalink / raw)
  To: saeed bishara; +Cc: apatard, alsa-devel, tbm, saeed, nico

On Wed, May 12, 2010 at 01:48:57PM +0300, saeed bishara wrote:

Please don't top post.

> 	some of the dma stuff handled by the i2s! For example the i2s trigger
> function actually enables the dma, this should be moved to the dma
> driver. Also, the playback and capture trigger funtions looks alike

There's no real problem with doing this from an ASoC point of view, both
devices are part of the same chip so they're free to peer into each
other's implementations as much as makes sense for that hardware.

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

* Re: [patch 5/6] kirkwood: Add i2s support
  2010-05-12 10:24   ` Mark Brown
  2010-05-12 10:43     ` Saeed Bishara
  2010-05-12 10:48     ` saeed bishara
@ 2010-05-12 14:38     ` Arnaud Patard
  2010-05-12 14:59       ` Mark Brown
  2 siblings, 1 reply; 45+ messages in thread
From: Arnaud Patard @ 2010-05-12 14:38 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, nico, saeed, tbm

Mark Brown <broonie@opensource.wolfsonmicro.com> writes:

> On Tue, May 11, 2010 at 06:23:47PM +0200, apatard@mandriva.com wrote:
>> This patch enables support for the i2s codec available on kirkwood platforms
>
> It's not a CODEC, it's the I2S controller in the CPU.  A CODEC is a
> device with DACs and ADCs in it.
>
>> +	do {
>> +		/* we've enabled only bytes interrupts ... */
>
> You were checking for error interrupts further up the function?
>
>> +		if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
>> +				KIRKWOOD_INT_CAUSE_REC_BYTES))
>> +			return IRQ_NONE;
>
> Surely it'd make sense to log the unexpected interrupts for diagnostics?
> You should never get here if there are no interrupts you've enabled.
> Unless the interrupt is shared, but that'd be a bit surprising for a
> SoC.

it's not shared iirc but there are different possible interrupt
cause. There used to be a message but I think it has been removed by
error. Should I had it back or remove the check ? (I prefer adding it
back but your point of view does matter).

>
> It also looks like it'd be more sensible to either drop the do/while
> loop entirely (the IRQ core should handle the interrupt still being
> asserted and it doesn't look like any of the handling should take so
> long that interrupts reassert while it's running anyway) or move the
> handling of error interrupts and the first read into the loop so you
> don't have two slightly different paths.

The loop is there to handle playback and record interrupts at the same
time. As regards the error interrupts, I preferred to put outside the
loop to differentiate "normal" interrupts from "error" interrupts.

>
>> +		/* ack int */
>> +		writel(status, priv->io + KIRKWOOD_INT_CAUSE);
>> +
>> +		if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
>> +			snd_pcm_period_elapsed(prdata->play_stream);
>> +
>> +		if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
>> +			snd_pcm_period_elapsed(prdata->rec_stream);
>> +
>> +		mask = readl(priv->io + KIRKWOOD_INT_MASK);
>> +		status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
>
> This masking didn't happen prior to the first entry into the loop.

Can you explain a little bit more ? at the beginning of the function,
there are the 2 same lines.

>
>> +       if (soc_runtime->dai->cpu_dai->private_data == NULL) {
>
> It seems a bit icky to be managing the DAI private data here...
>
>> +		err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
>> +				  "kirkwood-dma", prdata);
>
> I'd suggest "kirkwood-i2s" as a name here.  Or take the name from the
> DAI.

ok

>
>> +static int kirkwood_dma_trigger(struct snd_pcm_substream *substream, int cmd)
>> +{
>> +	return 0;
>> +}
>
> Remove this if it's not implemented.
>
>> +static int kirkwood_dma_mmap(struct snd_pcm_substream *substream,
>> +		struct vm_area_struct *vma)
>> +{
>> +	struct snd_pcm_runtime *runtime = substream->runtime;
>> +
>> +	return dma_mmap_coherent(substream->pcm->card->dev, vma,
>> +					runtime->dma_area,
>> +					runtime->dma_addr,
>> +					runtime->dma_bytes);
>> +}
>
> Hrm, this looks like there should be a utility function to do it, it's
> not terribly driver specific.

hmm... I need to double check. I got some troubles with this kind of
stuff on my ST LS2E/F mips platforms, so I wrote something known to be
working.

>
>> +struct snd_soc_platform kirkwood_soc_platform = {
>> +	.name		= "kirkwood-dma",
>
> I'd also add an audio in here or something.
>
>> +#define AUDIO_WIN_BASE_REG(win)			(0xA00 + ((win)<<3))
>> +#define AUDIO_WIN_CTRL_REG(win)			(0xA04 + ((win)<<3))
>
> Namespacing.  Or move into the driver, there seems little reason for
> anything else to be peering at these.
>
>> +#define KIRKWOOD_RATES \
>> +	(SNDRV_PCM_RATE_44100 | \
>> +	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
>> +#define KIRKWOOD_FORMATS \
>> +	(SNDRV_PCM_FMTBIT_S16_LE | \
>> +	 SNDRV_PCM_FMTBIT_S24_LE | \
>> +	 SNDRV_PCM_FMTBIT_S32_LE)
>
> Move these into the driver.
>
>> +static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
>> +{
>> +	unsigned long value;
>> +
>> +	value = KIRKWOOD_DCO_CTL_OFFSET_0;
>> +	switch (rate) {
>> +	default:
>> +	case 44100:
>> +		value |= KIRKWOOD_DCO_CTL_FREQ_11;
>> +		break;
>> +	case 48000:
>> +		value |= KIRKWOOD_DCO_CTL_FREQ_12;
>> +		break;
>> +	case 96000:
>> +		value |= KIRKWOOD_DCO_CTL_FREQ_24;
>> +		break;
>> +	}
>> +	writel(value, io + KIRKWOOD_DCO_CTL);
>> +
>> +	/* wait for dco locked */
>> +	do {
>> +		cpu_relax();
>> +		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
>> +		value &= KIRKWOOD_DCO_SPCR_STATUS;
>> +	} while (value == 0);
>> +}
>
> Why is this an inline function in the header?
>
>> +	 * Size settings in play/rec i2s control regs and play/rec control
>> +	 * regs must be the same.
>> +	 */
>
> Ideally you'd be setting up constraints for this.
>
>> +	/*
>> +	 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
>> +	 * changing it. So read 1 time here and 1 later.
>> +	 */
>> +	value = readl(priv->io + KIRKWOOD_PLAYCTL);
>
> Nice...
>
>> +	switch (cmd) {
>> +	case SNDRV_PCM_TRIGGER_START:
>> +		/* stop audio, enable interrupts */
>
> If audio is running when you're getting a start trigger something is
> wrong...

I'm too paranoid ? here

>
>> +static int kirkwood_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
>> +				int clk_id, unsigned int freq, int dir)
>> +{
>> +	return 0;
>> +}
>
> Remove this.
>
>> +static void mv_audio_init(void __iomem *base)
>> +{
>> +	int timeout = 10000000;
>> +	unsigned int reg_data;
>> +
>> +	reg_data = readl(base + 0x1200);
>> +	reg_data &= (~(0x333FF8));
>> +	reg_data |= 0x111D18;
>> +	writel(reg_data, base + 0x1200);
>
> It's like magic!

yeah. I've not been able to find out any info in the specs about that
and last time I tried with that it was not working :(

>
>> +
>> +	do {
>> +		timeout--;
>> +	} while (timeout);
>
> The driver is busy waiting here but not polling anything.  Just use a
> sleep?
>
>> +	/* FIXME : should not be hardcoded */
>> +	priv->burst = 128;
>
> Platform data?
>
>> +static int kirkwood_i2s_probe(struct platform_device *pdev,
>> +                            struct snd_soc_dai *dai)
>
> This is the ASoC probe but...
>
> +       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>
> ...it's pulling all sorts of resources out of the device which are
> specific to the I2S controller.  You should have the I2S controller have
> a normal platform device which is probed on system startup and triggers
> DAI registration, just as you're doing in the CODEC driver.  All the
> resources should be there.  Apart from anything else this means you only
> need to set up each I2S controller once in the arch/arm code for the
> CPU.

ok. Will look at that stuff.

>
>> +	mv_audio_init(priv->io);
>
> Seems a bit odd ot have the separate init function in the middle of a
> bunch of other register writes.

I want to have interrupts disable before calling it. I don't want bad
suprises.


Arnaud

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

* Re: [patch 5/6] kirkwood: Add i2s support
  2010-05-12 14:38     ` Arnaud Patard
@ 2010-05-12 14:59       ` Mark Brown
  0 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-12 14:59 UTC (permalink / raw)
  To: Arnaud Patard; +Cc: alsa-devel, nico, saeed, tbm

On Wed, May 12, 2010 at 04:38:25PM +0200, Arnaud Patard wrote:
> Mark Brown <broonie@opensource.wolfsonmicro.com> writes:
> > On Tue, May 11, 2010 at 06:23:47PM +0200, apatard@mandriva.com wrote:

> >> +		if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
> >> +				KIRKWOOD_INT_CAUSE_REC_BYTES))
> >> +			return IRQ_NONE;

> > Surely it'd make sense to log the unexpected interrupts for diagnostics?
> > You should never get here if there are no interrupts you've enabled.
> > Unless the interrupt is shared, but that'd be a bit surprising for a
> > SoC.

> it's not shared iirc but there are different possible interrupt
> cause. There used to be a message but I think it has been removed by
> error. Should I had it back or remove the check ? (I prefer adding it
> back but your point of view does matter).

Add it back and also log it, but also fix the IRQ_NONE thing - it's
defintiely going to be wrong if this is the second spin through the loop
for example.

> > It also looks like it'd be more sensible to either drop the do/while
> > loop entirely (the IRQ core should handle the interrupt still being
> > asserted and it doesn't look like any of the handling should take so
> > long that interrupts reassert while it's running anyway) or move the
> > handling of error interrupts and the first read into the loop so you
> > don't have two slightly different paths.

> The loop is there to handle playback and record interrupts at the same

Why is this required?  You check both interrupts in sequence anyway.

> time. As regards the error interrupts, I preferred to put outside the
> loop to differentiate "normal" interrupts from "error" interrupts.

Actually looking again they are in a separate status register too so I
suppose that's not quite so bad.  It is a bit odd that they all come in
on the same status line and can't be muxed out from a single register
but hardware designers are like that sometimes.

> >> +		mask = readl(priv->io + KIRKWOOD_INT_MASK);
> >> +		status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;

> > This masking didn't happen prior to the first entry into the loop.

> Can you explain a little bit more ? at the beginning of the function,
> there are the 2 same lines.

I was looking at the read of cause there, I hadn't noticed the separate
status register.

> >> +static int kirkwood_dma_mmap(struct snd_pcm_substream *substream,
> >> +		struct vm_area_struct *vma)
> >> +{
> >> +	struct snd_pcm_runtime *runtime = substream->runtime;
> >> +
> >> +	return dma_mmap_coherent(substream->pcm->card->dev, vma,
> >> +					runtime->dma_area,
> >> +					runtime->dma_addr,
> >> +					runtime->dma_bytes);
> >> +}

> > Hrm, this looks like there should be a utility function to do it, it's
> > not terribly driver specific.

> hmm... I need to double check. I got some troubles with this kind of
> stuff on my ST LS2E/F mips platforms, so I wrote something known to be
> working.

The point is that it looks like either there should already be an
implementation of this function you can use or this should be put
somewhere were other folks are able to use it.

> >> +	mv_audio_init(priv->io);

> > Seems a bit odd ot have the separate init function in the middle of a
> > bunch of other register writes.

> I want to have interrupts disable before calling it. I don't want bad
> suprises.

My point is that you may as well just have the mv_audio_init() function
in line in the code here, jumping out into another function seems a bit
odd when all it is is more register writes.

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

* [patch 0/6] kirkwood openrd client audio support - v4
@ 2010-05-27 12:57 ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-27 12:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: nico, broonie, saeed, tbm, linux-arm-kernel, lrg


Hi,

This patchset is an other try to get merged openrd audio support mainline.
The main change is going back to using kirkwood instead of orion, as the 
only orion having i2s is not merged mainline (if I got it right).
I've also fixed the lastests comments on the cs42l51 codec patch.

Arnaud

Changes :
- changed back from orion to kirkwood
- removed cs42l51 adc input register initialisation
- moved the DAPM event macro to soc-dapm
- fixed cs42l51_set_dai_fmt() master/slave check
- removed cs42l51 startup message
- use snd_soc_update_bits() in cs42l51_pdn_event()

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

* [patch 0/6] kirkwood openrd client audio support - v4
@ 2010-05-27 12:57 ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-27 12:57 UTC (permalink / raw)
  To: linux-arm-kernel


Hi,

This patchset is an other try to get merged openrd audio support mainline.
The main change is going back to using kirkwood instead of orion, as the 
only orion having i2s is not merged mainline (if I got it right).
I've also fixed the lastests comments on the cs42l51 codec patch.

Arnaud

Changes :
- changed back from orion to kirkwood
- removed cs42l51 adc input register initialisation
- moved the DAPM event macro to soc-dapm
- fixed cs42l51_set_dai_fmt() master/slave check
- removed cs42l51 startup message
- use snd_soc_update_bits() in cs42l51_pdn_event()

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

* [patch 1/6] orion/kirkwood: add audio functions.
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-27 12:57   ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-27 12:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: kirkwood_add_audio_dev.patch --]
[-- Type: text/plain, Size: 3970 bytes --]

This patch add audio related definitions and functions


Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/arch/arm/mach-kirkwood/common.c
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/common.c	2010-05-27 14:09:33.244174174 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/common.c	2010-05-27 14:09:35.840194356 +0200
@@ -25,6 +25,7 @@
 #include <asm/mach/time.h>
 #include <mach/kirkwood.h>
 #include <mach/bridge-regs.h>
+#include <plat/audio.h>
 #include <plat/cache-feroceon-l2.h>
 #include <plat/ehci-orion.h>
 #include <plat/mvsdio.h>
@@ -855,6 +856,42 @@ struct sys_timer kirkwood_timer = {
 	.init = kirkwood_timer_init,
 };
 
+/*****************************************************************************
+ * Audio
+ ****************************************************************************/
+static struct resource kirkwood_i2s_resources[] = {
+	[0] = {
+		.start  = AUDIO_PHYS_BASE,
+		.end    = AUDIO_PHYS_BASE + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = IRQ_KIRKWOOD_I2S,
+		.end    = IRQ_KIRKWOOD_I2S,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
+	.dram        = &kirkwood_mbus_dram_info,
+	.burst       = 128,
+};
+
+static struct platform_device kirkwood_i2s_device = {
+	.name		= "kirkwood-i2s",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(kirkwood_i2s_resources),
+	.resource	= kirkwood_i2s_resources,
+	.dev		= {
+		.platform_data	= &kirkwood_i2s_data,
+	},
+};
+
+void __init kirkwood_audio_init(void)
+{
+	kirkwood_clk_ctrl |= CGC_AUDIO;
+	platform_device_register(&kirkwood_i2s_device);
+}
 
 /*****************************************************************************
  * General
@@ -914,6 +951,7 @@ void __init kirkwood_init(void)
 	kirkwood_spi_plat_data.tclk = kirkwood_tclk;
 	kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
 	kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
+	kirkwood_i2s_data.tclk = kirkwood_tclk;
 
 	/*
 	 * Disable propagation of mbus errors to the CPU local bus,
Index: sound-2.6/arch/arm/mach-kirkwood/common.h
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/common.h	2010-05-27 14:09:33.204173835 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/common.h	2010-05-27 14:09:35.883694381 +0200
@@ -16,6 +16,7 @@ struct mv643xx_eth_platform_data;
 struct mv_sata_platform_data;
 struct mvsdio_platform_data;
 struct mtd_partition;
+struct kirkwood_asoc_platform_data;
 
 /*
  * Basic Kirkwood init functions used early by machine-setup.
@@ -41,6 +42,7 @@ void kirkwood_i2c_init(void);
 void kirkwood_uart0_init(void);
 void kirkwood_uart1_init(void);
 void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
+void kirkwood_audio_init(void);
 
 extern int kirkwood_tclk;
 extern struct sys_timer kirkwood_timer;
Index: sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-27 14:09:33.188174747 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-27 14:09:35.895694344 +0200
@@ -96,6 +96,9 @@
 
 #define SDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x90000)
 
+#define AUDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
+#define AUDIO_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
+
 /*
  * Supported devices and revisions.
  */
Index: sound-2.6/arch/arm/plat-orion/include/plat/audio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/arch/arm/plat-orion/include/plat/audio.h	2010-05-27 14:09:35.895694344 +0200
@@ -0,0 +1,11 @@
+#ifndef __PLAT_AUDIO_H
+#define __PLAT_AUDIO_H
+
+#include <linux/mbus.h>
+
+struct kirkwood_asoc_platform_data {
+	u32 tclk;
+	struct mbus_dram_target_info *dram;
+	int burst;
+};
+#endif

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

* [patch 1/6] orion/kirkwood: add audio functions.
@ 2010-05-27 12:57   ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-27 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: kirkwood_add_audio_dev.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100527/86aa58b8/attachment.el>

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

* [patch 2/6] openrd-client: initialise audio
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-27 12:57   ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-27 12:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: openrd_init_audio_dev.patch --]
[-- Type: text/plain, Size: 1201 bytes --]

This patch is reponsible for enabling audio on the openrd client board

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/arch/arm/mach-kirkwood/openrd-setup.c
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/openrd-setup.c	2010-05-27 14:09:33.076174419 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/openrd-setup.c	2010-05-27 14:09:42.067694397 +0200
@@ -15,6 +15,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
@@ -60,6 +61,12 @@ static unsigned int openrd_mpp_config[]
 	0
 };
 
+static struct i2c_board_info i2c_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("cs42l51", 0x4a),
+	},
+};
+
 static void __init openrd_init(void)
 {
 	/*
@@ -80,6 +87,12 @@ static void __init openrd_init(void)
 	kirkwood_sdio_init(&openrd_mvsdio_data);
 
 	kirkwood_i2c_init();
+
+	if (machine_is_openrd_client()) {
+		i2c_register_board_info(0, i2c_board_info,
+			ARRAY_SIZE(i2c_board_info));
+		kirkwood_audio_init();
+	}
 }
 
 static int __init openrd_pci_init(void)

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

* [patch 2/6] openrd-client: initialise audio
@ 2010-05-27 12:57   ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-27 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: openrd_init_audio_dev.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100527/e036f32d/attachment.el>

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

* [patch 3/6] soc-dapm.h: add SND_SOC_DAPM_PRE_POST_PMD event
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-27 12:57   ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-27 12:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: add_dapm_pre_port_pmd.patch --]
[-- Type: text/plain, Size: 853 bytes --]

Some systems codecs need to configure some registers before and after powering down
some of their part. As a convenience, I'm adding a macro for that.

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/include/sound/soc-dapm.h
===================================================================
--- sound-2.6.orig/include/sound/soc-dapm.h	2010-05-27 14:09:32.932174265 +0200
+++ sound-2.6/include/sound/soc-dapm.h	2010-05-27 14:09:47.536194064 +0200
@@ -273,6 +273,8 @@
 #define SND_SOC_DAPM_POST_PMD	0x8		/* after widget power down */
 #define SND_SOC_DAPM_PRE_REG	0x10	/* before audio path setup */
 #define SND_SOC_DAPM_POST_REG	0x20	/* after audio path setup */
+#define SND_SOC_DAPM_PRE_POST_PMD \
+				(SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
 
 /* convenience event type detection */
 #define SND_SOC_DAPM_EVENT_ON(e)	\

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

* [patch 3/6] soc-dapm.h: add SND_SOC_DAPM_PRE_POST_PMD event
@ 2010-05-27 12:57   ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-27 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: add_dapm_pre_port_pmd.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100527/ed9cb853/attachment.el>

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

* [patch 4/6] cs42l51: add asoc driver
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-27 12:57   ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-27 12:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: cs42l51_support.patch --]
[-- Type: text/plain, Size: 29569 bytes --]

This patch is adding a ASoC driver for the cs42l51 from Cirrus Logic.
Master mode and spi mode are not supported.

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/sound/soc/codecs/cs42l51.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/codecs/cs42l51.c	2010-05-27 14:09:52.079674615 +0200
@@ -0,0 +1,763 @@
+/*
+ * cs42l51.c
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * Based on cs4270.c - Copyright (c) Freescale Semiconductor
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For now:
+ *  - Only I2C is support. Not SPI
+ *  - master mode *NOT* supported
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <linux/i2c.h>
+
+#include "cs42l51.h"
+
+enum master_slave_mode {
+	MODE_SLAVE,
+	MODE_SLAVE_AUTO,
+	MODE_MASTER,
+};
+
+struct cs42l51_private {
+	unsigned int mclk;
+	unsigned int audio_mode;	/* The mode (I2S or left-justified) */
+	enum master_slave_mode func;
+	struct snd_soc_codec codec;
+	u8 reg_cache[CS42L51_NUMREGS];
+};
+
+static struct snd_soc_codec *cs42l51_codec;
+
+#define CS42L51_FORMATS ( \
+		SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+		SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+		SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+		SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
+
+static int cs42l51_fill_cache(struct snd_soc_codec *codec)
+{
+	u8 *cache = codec->reg_cache + 1;
+	struct i2c_client *i2c_client = codec->control_data;
+	s32 length;
+
+	length = i2c_smbus_read_i2c_block_data(i2c_client,
+			CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
+	if (length != CS42L51_NUMREGS) {
+		dev_err(&i2c_client->dev,
+				"I2C read failure, addr=0x%x (ret=%d vs %d)\n",
+				i2c_client->addr, length, CS42L51_NUMREGS);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+	const struct i2c_device_id *id)
+{
+	struct snd_soc_codec *codec;
+	struct cs42l51_private *cs42l51;
+	int ret = 0;
+	int reg;
+
+	if (cs42l51_codec)
+		return -EBUSY;
+
+	/* Verify that we have a CS42L51 */
+	ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "failed to read I2C\n");
+		goto error;
+	}
+
+	if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+	    (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+		dev_err(&i2c_client->dev, "Invalid chip id\n");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+				ret & 7);
+
+	cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+	if (!cs42l51) {
+		dev_err(&i2c_client->dev, "could not allocate codec\n");
+		return -ENOMEM;
+	}
+	codec = &cs42l51->codec;
+
+	mutex_init(&codec->mutex);
+	INIT_LIST_HEAD(&codec->dapm_widgets);
+	INIT_LIST_HEAD(&codec->dapm_paths);
+
+	codec->dev = &i2c_client->dev;
+	codec->name = "CS42L51";
+	codec->owner = THIS_MODULE;
+	codec->dai = &cs42l51_dai;
+	codec->num_dai = 1;
+	snd_soc_codec_set_drvdata(codec, cs42l51);
+
+	codec->control_data = i2c_client;
+	codec->reg_cache = cs42l51->reg_cache;
+	codec->reg_cache_size = CS42L51_NUMREGS;
+	i2c_set_clientdata(i2c_client, codec);
+
+	ret = cs42l51_fill_cache(codec);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "failed to fill register cache\n");
+		goto error_alloc;
+	}
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
+		goto error_alloc;
+	}
+
+	/*
+	 * DAC configuration
+	 * - Use signal processor
+	 * - auto mute
+	 * - vol changes immediate
+	 * - no de-emphasize
+	 */
+	reg = CS42L51_DAC_CTL_DATA_SEL(1)
+		| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+	ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+	if (ret < 0)
+		goto error_alloc;
+
+	cs42l51_dai.dev = codec->dev;
+	cs42l51_codec = codec;
+
+	ret = snd_soc_register_codec(codec);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		goto error_alloc;
+	}
+
+	ret = snd_soc_register_dai(&cs42l51_dai);
+	if (ret < 0) {
+		dev_err(&i2c_client->dev, "failed to register DAIe\n");
+		goto error_reg;
+	}
+
+	return 0;
+
+error_reg:
+	snd_soc_unregister_codec(codec);
+error_alloc:
+	kfree(cs42l51);
+error:
+	return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+	struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+	snd_soc_unregister_dai(&cs42l51_dai);
+	snd_soc_unregister_codec(cs42l51_codec);
+	cs42l51_codec = NULL;
+	kfree(cs42l51);
+	return 0;
+}
+
+
+static const struct i2c_device_id cs42l51_id[] = {
+	{"cs42l51", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+	.driver = {
+		.name = "CS42L51 I2C",
+		.owner = THIS_MODULE,
+	},
+	.id_table = cs42l51_id,
+	.probe = cs42l51_i2c_probe,
+	.remove = cs42l51_i2c_remove,
+};
+
+static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
+
+	switch (value) {
+	default:
+	case 0:
+		ucontrol->value.integer.value[0] = 0;
+		break;
+	/* same value : (L+R)/2 and (R+L)/2 */
+	case 1:
+	case 2:
+		ucontrol->value.integer.value[0] = 1;
+		break;
+	case 3:
+		ucontrol->value.integer.value[0] = 2;
+		break;
+	}
+
+	return 0;
+}
+
+#define CHAN_MIX_NORMAL	0x00
+#define CHAN_MIX_BOTH	0x55
+#define CHAN_MIX_SWAP	0xFF
+
+static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned char val;
+
+	switch (ucontrol->value.integer.value[0]) {
+	default:
+	case 0:
+		val = CHAN_MIX_NORMAL;
+		break;
+	case 1:
+		val = CHAN_MIX_BOTH;
+		break;
+	case 2:
+		val = CHAN_MIX_SWAP;
+		break;
+	}
+
+	snd_soc_write(codec, CS42L51_PCM_MIXER, val);
+
+	return 1;
+}
+
+static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
+/* This is a lie. after -102 db, it stays at -102 */
+/* maybe a range would be better */
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
+static const char *chan_mix[] = {
+	"L R",
+	"L+R",
+	"R L",
+};
+
+static const struct soc_enum cs42l51_chan_mix =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
+
+static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
+	SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
+			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
+			7, 0xffffff99, 0x18, adc_pcm_tlv),
+	SOC_DOUBLE_R("PCM Playback Switch",
+			CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
+	SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
+			CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
+			8, 0xffffff19, 0x18, aout_tlv),
+	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
+			7, 0xffffff99, 0x18, adc_pcm_tlv),
+	SOC_DOUBLE_R("ADC Mixer Switch",
+			CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
+	SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
+	SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
+	SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
+	SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
+	SOC_DOUBLE_TLV("Mic Boost Volume",
+			CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
+	SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
+	SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
+	SOC_ENUM_EXT("PCM channel mixer",
+			cs42l51_chan_mix,
+			cs42l51_get_chan_mix, cs42l51_set_chan_mix),
+};
+
+/*
+ * to power down, one must:
+ * 1.) Enable the PDN bit
+ * 2.) enable power-down for the select channels
+ * 3.) disable the PDN bit.
+ */
+static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	unsigned long value;
+
+	value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
+	value &= ~CS42L51_POWER_CTL1_PDN;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		value |= CS42L51_POWER_CTL1_PDN;
+		break;
+	default:
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	}
+	snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+		CS42L51_POWER_CTL1_PDN, value);
+
+	return 0;
+}
+
+static const char *cs42l51_dac_names[] = {"Direct PCM",
+	"DSP PCM", "ADC"};
+static const struct soc_enum cs42l51_dac_mux_enum =
+	SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
+static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
+
+static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
+	"MIC Left", "MIC+preamp Left"};
+static const struct soc_enum cs42l51_adcl_mux_enum =
+	SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
+static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
+
+static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
+	"MIC Right", "MIC+preamp Right"};
+static const struct soc_enum cs42l51_adcr_mux_enum =
+	SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
+static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
+	SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
+
+static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
+	SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
+	SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
+		CS42L51_POWER_CTL1, 1, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
+		CS42L51_POWER_CTL1, 2, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
+		CS42L51_POWER_CTL1, 5, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+	SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
+		CS42L51_POWER_CTL1, 6, 1,
+		cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+
+	/* analog/mic */
+	SND_SOC_DAPM_INPUT("AIN1L"),
+	SND_SOC_DAPM_INPUT("AIN1R"),
+	SND_SOC_DAPM_INPUT("AIN2L"),
+	SND_SOC_DAPM_INPUT("AIN2R"),
+	SND_SOC_DAPM_INPUT("MICL"),
+	SND_SOC_DAPM_INPUT("MICR"),
+
+	SND_SOC_DAPM_MIXER("Mic Preamp Left",
+		CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
+	SND_SOC_DAPM_MIXER("Mic Preamp Right",
+		CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
+
+	/* HP */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+
+	/* mux */
+	SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
+		&cs42l51_dac_mux_controls),
+	SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
+		&cs42l51_adcl_mux_controls),
+	SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
+		&cs42l51_adcr_mux_controls),
+};
+
+static const struct snd_soc_dapm_route cs42l51_routes[] = {
+	{"HPL", NULL, "Left DAC"},
+	{"HPR", NULL, "Right DAC"},
+
+	{"Left ADC", NULL, "Left PGA"},
+	{"Right ADC", NULL, "Right PGA"},
+
+	{"Mic Preamp Left",  NULL,  "MICL"},
+	{"Mic Preamp Right", NULL,  "MICR"},
+
+	{"PGA-ADC Mux Left",  "AIN1 Left",        "AIN1L" },
+	{"PGA-ADC Mux Left",  "AIN2 Left",        "AIN2L" },
+	{"PGA-ADC Mux Left",  "MIC Left",         "MICL"  },
+	{"PGA-ADC Mux Left",  "MIC+preamp Left",  "Mic Preamp Left" },
+	{"PGA-ADC Mux Right", "AIN1 Right",       "AIN1R" },
+	{"PGA-ADC Mux Right", "AIN2 Right",       "AIN2R" },
+	{"PGA-ADC Mux Right", "MIC Right",        "MICR" },
+	{"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
+
+	{"Left PGA", NULL, "PGA-ADC Mux Left"},
+	{"Right PGA", NULL, "PGA-ADC Mux Right"},
+};
+
+static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_LEFT_J:
+	case SND_SOC_DAIFMT_RIGHT_J:
+		cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+		break;
+	default:
+		dev_err(codec->dev, "invalid DAI format\n");
+		ret = -EINVAL;
+	}
+
+	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		cs42l51->func = MODE_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		cs42l51->func = MODE_SLAVE_AUTO;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+struct cs42l51_ratios {
+	unsigned int ratio;
+	unsigned char speed_mode;
+	unsigned char mclk;
+};
+
+static struct cs42l51_ratios slave_ratios[] = {
+	{  512, CS42L51_QSM_MODE, 0 }, {  768, CS42L51_QSM_MODE, 0 },
+	{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+	{ 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
+	{  256, CS42L51_HSM_MODE, 0 }, {  384, CS42L51_HSM_MODE, 0 },
+	{  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
+	{ 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
+	{  128, CS42L51_SSM_MODE, 0 }, {  192, CS42L51_SSM_MODE, 0 },
+	{  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
+	{  512, CS42L51_SSM_MODE, 0 }, {  768, CS42L51_SSM_MODE, 0 },
+	{  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
+	{  256, CS42L51_DSM_MODE, 0 }, {  384, CS42L51_DSM_MODE, 0 },
+};
+
+static struct cs42l51_ratios slave_auto_ratios[] = {
+	{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+	{ 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
+	{  512, CS42L51_HSM_MODE, 0 }, {  768, CS42L51_HSM_MODE, 0 },
+	{ 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
+	{  256, CS42L51_SSM_MODE, 0 }, {  384, CS42L51_SSM_MODE, 0 },
+	{  512, CS42L51_SSM_MODE, 1 }, {  768, CS42L51_SSM_MODE, 1 },
+	{  128, CS42L51_DSM_MODE, 0 }, {  192, CS42L51_DSM_MODE, 0 },
+	{  256, CS42L51_DSM_MODE, 1 }, {  384, CS42L51_DSM_MODE, 1 },
+};
+
+static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	struct cs42l51_ratios *ratios = NULL;
+	int nr_ratios = 0;
+	unsigned int rates = 0;
+	unsigned int rate_min = -1;
+	unsigned int rate_max = 0;
+	int i;
+
+	cs42l51->mclk = freq;
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		return -EINVAL;
+	case MODE_SLAVE:
+		ratios = slave_ratios;
+		nr_ratios = ARRAY_SIZE(slave_ratios);
+		break;
+	case MODE_SLAVE_AUTO:
+		ratios = slave_auto_ratios;
+		nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+		break;
+	}
+
+	for (i = 0; i < nr_ratios; i++) {
+		unsigned int rate = freq / ratios[i].ratio;
+		rates |= snd_pcm_rate_to_rate_bit(rate);
+		if (rate < rate_min)
+			rate_min = rate;
+		if (rate > rate_max)
+			rate_max = rate;
+	}
+	rates &= ~SNDRV_PCM_RATE_KNOT;
+
+	if (!rates) {
+		dev_err(codec->dev, "could not find a valid sample rate\n");
+		return -EINVAL;
+	}
+
+	codec_dai->playback.rates = rates;
+	codec_dai->playback.rate_min = rate_min;
+	codec_dai->playback.rate_max = rate_max;
+
+	codec_dai->capture.rates = rates;
+	codec_dai->capture.rate_min = rate_min;
+	codec_dai->capture.rate_max = rate_max;
+
+	return 0;
+}
+
+static int cs42l51_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_device *socdev = rtd->socdev;
+	struct snd_soc_codec *codec = socdev->card->codec;
+	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+	unsigned int i;
+	unsigned int rate;
+	unsigned int ratio;
+	struct cs42l51_ratios *ratios = NULL;
+	int nr_ratios = 0;
+	int intf_ctl, power_ctl, fmt;
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		return -EINVAL;
+	case MODE_SLAVE:
+		ratios = slave_ratios;
+		nr_ratios = ARRAY_SIZE(slave_ratios);
+		break;
+	case MODE_SLAVE_AUTO:
+		ratios = slave_auto_ratios;
+		nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+		break;
+	}
+
+	/* Figure out which MCLK/LRCK ratio to use */
+	rate = params_rate(params);     /* Sampling rate, in Hz */
+	ratio = cs42l51->mclk / rate;    /* MCLK/LRCK ratio */
+	for (i = 0; i < nr_ratios; i++) {
+		if (ratios[i].ratio == ratio)
+			break;
+	}
+
+	if (i == nr_ratios) {
+		/* We did not find a matching ratio */
+		dev_err(codec->dev, "could not find matching ratio\n");
+		return -EINVAL;
+	}
+
+	intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
+	power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
+
+	intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
+			| CS42L51_INTF_CTL_DAC_FORMAT(7));
+	power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
+			| CS42L51_MIC_POWER_CTL_MCLK_DIV2);
+
+	switch (cs42l51->func) {
+	case MODE_MASTER:
+		intf_ctl |= CS42L51_INTF_CTL_MASTER;
+		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+		break;
+	case MODE_SLAVE:
+		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+		break;
+	case MODE_SLAVE_AUTO:
+		power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
+		break;
+	}
+
+	switch (cs42l51->audio_mode) {
+	case SND_SOC_DAIFMT_I2S:
+		intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		switch (params_format(params)) {
+		case SNDRV_PCM_FORMAT_S16_LE:
+		case SNDRV_PCM_FORMAT_S16_BE:
+			fmt = CS42L51_DAC_DIF_RJ16;
+			break;
+		case SNDRV_PCM_FORMAT_S18_3LE:
+		case SNDRV_PCM_FORMAT_S18_3BE:
+			fmt = CS42L51_DAC_DIF_RJ18;
+			break;
+		case SNDRV_PCM_FORMAT_S20_3LE:
+		case SNDRV_PCM_FORMAT_S20_3BE:
+			fmt = CS42L51_DAC_DIF_RJ20;
+			break;
+		case SNDRV_PCM_FORMAT_S24_LE:
+		case SNDRV_PCM_FORMAT_S24_BE:
+			fmt = CS42L51_DAC_DIF_RJ24;
+			break;
+		default:
+			dev_err(codec->dev, "unknown format\n");
+			return -EINVAL;
+		}
+		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
+		break;
+	default:
+		dev_err(codec->dev, "unknown format\n");
+		return -EINVAL;
+	}
+
+	if (ratios[i].mclk)
+		power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
+
+	ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int reg;
+	int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
+
+	reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
+
+	if (mute)
+		reg |= mask;
+	else
+		reg &= ~mask;
+
+	return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
+}
+
+static struct snd_soc_dai_ops cs42l51_dai_ops = {
+	.hw_params      = cs42l51_hw_params,
+	.set_sysclk     = cs42l51_set_dai_sysclk,
+	.set_fmt        = cs42l51_set_dai_fmt,
+	.digital_mute   = cs42l51_dai_mute,
+};
+
+struct snd_soc_dai cs42l51_dai = {
+	.name = "CS42L51 HiFi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = CS42L51_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = CS42L51_FORMATS,
+	},
+	.ops = &cs42l51_dai_ops,
+};
+EXPORT_SYMBOL_GPL(cs42l51_dai);
+
+
+static int cs42l51_probe(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+	struct snd_soc_codec *codec;
+	int ret = 0;
+
+	if (!cs42l51_codec) {
+		dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
+		return -EINVAL;
+	}
+
+	socdev->card->codec = cs42l51_codec;
+	codec = socdev->card->codec;
+
+	/* Register PCMs */
+	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to create PCMs\n");
+		return ret;
+	}
+
+	snd_soc_add_controls(codec, cs42l51_snd_controls,
+		ARRAY_SIZE(cs42l51_snd_controls));
+	snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
+		ARRAY_SIZE(cs42l51_dapm_widgets));
+	snd_soc_dapm_add_routes(codec, cs42l51_routes,
+		ARRAY_SIZE(cs42l51_routes));
+
+	return 0;
+}
+
+
+static int cs42l51_remove(struct platform_device *pdev)
+{
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
+
+	return 0;
+}
+
+struct snd_soc_codec_device soc_codec_device_cs42l51 = {
+	.probe =	cs42l51_probe,
+	.remove =	cs42l51_remove
+};
+EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
+
+static int __init cs42l51_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&cs42l51_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
+		return ret;
+	}
+	return 0;
+}
+module_init(cs42l51_init);
+
+static void __exit cs42l51_exit(void)
+{
+	i2c_del_driver(&cs42l51_i2c_driver);
+}
+module_exit(cs42l51_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
Index: sound-2.6/sound/soc/codecs/cs42l51.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/codecs/cs42l51.h	2010-05-27 14:09:52.103694289 +0200
@@ -0,0 +1,163 @@
+/*
+ * cs42l51.h
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CS42L51_H
+#define _CS42L51_H
+
+#define CS42L51_CHIP_ID			0x1B
+#define CS42L51_CHIP_REV_A		0x00
+#define CS42L51_CHIP_REV_B		0x01
+
+#define CS42L51_CHIP_REV_ID		0x01
+#define CS42L51_MK_CHIP_REV(a, b)	((a)<<3|(b))
+
+#define CS42L51_POWER_CTL1		0x02
+#define CS42L51_POWER_CTL1_PDN_DACB	(1<<6)
+#define CS42L51_POWER_CTL1_PDN_DACA	(1<<5)
+#define CS42L51_POWER_CTL1_PDN_PGAB	(1<<4)
+#define CS42L51_POWER_CTL1_PDN_PGAA	(1<<3)
+#define CS42L51_POWER_CTL1_PDN_ADCB	(1<<2)
+#define CS42L51_POWER_CTL1_PDN_ADCA	(1<<1)
+#define CS42L51_POWER_CTL1_PDN		(1<<0)
+
+#define CS42L51_MIC_POWER_CTL		0x03
+#define CS42L51_MIC_POWER_CTL_AUTO	(1<<7)
+#define CS42L51_MIC_POWER_CTL_SPEED(x)	(((x)&3)<<5)
+#define CS42L51_QSM_MODE		3
+#define CS42L51_HSM_MODE		2
+#define	CS42L51_SSM_MODE		1
+#define CS42L51_DSM_MODE		0
+#define CS42L51_MIC_POWER_CTL_3ST_SP	(1<<4)
+#define CS42L51_MIC_POWER_CTL_PDN_MICB	(1<<3)
+#define CS42L51_MIC_POWER_CTL_PDN_MICA	(1<<2)
+#define CS42L51_MIC_POWER_CTL_PDN_BIAS	(1<<1)
+#define CS42L51_MIC_POWER_CTL_MCLK_DIV2	(1<<0)
+
+#define CS42L51_INTF_CTL		0x04
+#define CS42L51_INTF_CTL_LOOPBACK	(1<<7)
+#define CS42L51_INTF_CTL_MASTER		(1<<6)
+#define CS42L51_INTF_CTL_DAC_FORMAT(x)	(((x)&7)<<3)
+#define CS42L51_DAC_DIF_LJ24		0x00
+#define CS42L51_DAC_DIF_I2S		0x01
+#define CS42L51_DAC_DIF_RJ24		0x02
+#define CS42L51_DAC_DIF_RJ20		0x03
+#define CS42L51_DAC_DIF_RJ18		0x04
+#define CS42L51_DAC_DIF_RJ16		0x05
+#define CS42L51_INTF_CTL_ADC_I2S	(1<<2)
+#define CS42L51_INTF_CTL_DIGMIX		(1<<1)
+#define CS42L51_INTF_CTL_MICMIX		(1<<0)
+
+#define CS42L51_MIC_CTL			0x05
+#define CS42L51_MIC_CTL_ADC_SNGVOL	(1<<7)
+#define CS42L51_MIC_CTL_ADCD_DBOOST	(1<<6)
+#define CS42L51_MIC_CTL_ADCA_DBOOST	(1<<5)
+#define CS42L51_MIC_CTL_MICBIAS_SEL	(1<<4)
+#define CS42L51_MIC_CTL_MICBIAS_LVL(x)	(((x)&3)<<2)
+#define CS42L51_MIC_CTL_MICB_BOOST	(1<<1)
+#define CS42L51_MIC_CTL_MICA_BOOST	(1<<0)
+
+#define CS42L51_ADC_CTL			0x06
+#define CS42L51_ADC_CTL_ADCB_HPFEN	(1<<7)
+#define CS42L51_ADC_CTL_ADCB_HPFRZ	(1<<6)
+#define CS42L51_ADC_CTL_ADCA_HPFEN	(1<<5)
+#define CS42L51_ADC_CTL_ADCA_HPFRZ	(1<<4)
+#define CS42L51_ADC_CTL_SOFTB		(1<<3)
+#define CS42L51_ADC_CTL_ZCROSSB		(1<<2)
+#define CS42L51_ADC_CTL_SOFTA		(1<<1)
+#define CS42L51_ADC_CTL_ZCROSSA		(1<<0)
+
+#define CS42L51_ADC_INPUT		0x07
+#define CS42L51_ADC_INPUT_AINB_MUX(x)	(((x)&3)<<6)
+#define CS42L51_ADC_INPUT_AINA_MUX(x)	(((x)&3)<<4)
+#define CS42L51_ADC_INPUT_INV_ADCB	(1<<3)
+#define CS42L51_ADC_INPUT_INV_ADCA	(1<<2)
+#define CS42L51_ADC_INPUT_ADCB_MUTE	(1<<1)
+#define CS42L51_ADC_INPUT_ADCA_MUTE	(1<<0)
+
+#define CS42L51_DAC_OUT_CTL		0x08
+#define CS42L51_DAC_OUT_CTL_HP_GAIN(x)	(((x)&7)<<5)
+#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL	(1<<4)
+#define CS42L51_DAC_OUT_CTL_INV_PCMB	(1<<3)
+#define CS42L51_DAC_OUT_CTL_INV_PCMA	(1<<2)
+#define CS42L51_DAC_OUT_CTL_DACB_MUTE	(1<<1)
+#define CS42L51_DAC_OUT_CTL_DACA_MUTE	(1<<0)
+
+#define CS42L51_DAC_CTL			0x09
+#define CS42L51_DAC_CTL_DATA_SEL(x)	(((x)&3)<<6)
+#define CS42L51_DAC_CTL_FREEZE		(1<<5)
+#define CS42L51_DAC_CTL_DEEMPH		(1<<3)
+#define CS42L51_DAC_CTL_AMUTE		(1<<2)
+#define CS42L51_DAC_CTL_DACSZ(x)	(((x)&3)<<0)
+
+#define CS42L51_ALC_PGA_CTL		0x0A
+#define CS42L51_ALC_PGB_CTL		0x0B
+#define CS42L51_ALC_PGX_ALCX_SRDIS	(1<<7)
+#define CS42L51_ALC_PGX_ALCX_ZCDIS	(1<<6)
+#define CS42L51_ALC_PGX_PGX_VOL(x)	(((x)&0x1f)<<0)
+
+#define CS42L51_ADCA_ATT		0x0C
+#define CS42L51_ADCB_ATT		0x0D
+
+#define CS42L51_ADCA_VOL		0x0E
+#define CS42L51_ADCB_VOL		0x0F
+#define CS42L51_PCMA_VOL		0x10
+#define CS42L51_PCMB_VOL		0x11
+#define CS42L51_MIX_MUTE_ADCMIX		(1<<7)
+#define CS42L51_MIX_VOLUME(x)		(((x)&0x7f)<<0)
+
+#define CS42L51_BEEP_FREQ		0x12
+#define CS42L51_BEEP_VOL		0x13
+#define CS42L51_BEEP_CONF		0x14
+
+#define CS42L51_TONE_CTL		0x15
+#define CS42L51_TONE_CTL_TREB(x)	(((x)&0xf)<<4)
+#define CS42L51_TONE_CTL_BASS(x)	(((x)&0xf)<<0)
+
+#define CS42L51_AOUTA_VOL		0x16
+#define CS42L51_AOUTB_VOL		0x17
+#define CS42L51_PCM_MIXER		0x18
+#define CS42L51_LIMIT_THRES_DIS		0x19
+#define CS42L51_LIMIT_REL		0x1A
+#define CS42L51_LIMIT_ATT		0x1B
+#define CS42L51_ALC_EN			0x1C
+#define CS42L51_ALC_REL			0x1D
+#define CS42L51_ALC_THRES		0x1E
+#define CS42L51_NOISE_CONF		0x1F
+
+#define CS42L51_STATUS			0x20
+#define CS42L51_STATUS_SP_CLKERR	(1<<6)
+#define CS42L51_STATUS_SPEA_OVFL	(1<<5)
+#define CS42L51_STATUS_SPEB_OVFL	(1<<4)
+#define CS42L51_STATUS_PCMA_OVFL	(1<<3)
+#define CS42L51_STATUS_PCMB_OVFL	(1<<2)
+#define CS42L51_STATUS_ADCA_OVFL	(1<<1)
+#define CS42L51_STATUS_ADCB_OVFL	(1<<0)
+
+#define CS42L51_CHARGE_FREQ		0x21
+
+#define CS42L51_FIRSTREG	0x01
+/*
+ * Hack: with register 0x21, it makes 33 registers. Looks like someone in the
+ * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
+ * 32 regs
+ */
+#define CS42L51_LASTREG		0x20
+#define CS42L51_NUMREGS		(CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
+
+extern struct snd_soc_dai cs42l51_dai;
+extern struct snd_soc_codec_device soc_codec_device_cs42l51;
+#endif
Index: sound-2.6/sound/soc/codecs/Kconfig
===================================================================
--- sound-2.6.orig/sound/soc/codecs/Kconfig	2010-05-27 14:09:32.812174230 +0200
+++ sound-2.6/sound/soc/codecs/Kconfig	2010-05-27 14:09:52.107735223 +0200
@@ -22,6 +22,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+	select SND_SOC_CS42L51 if I2C
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_DA7210 if I2C
@@ -120,6 +121,9 @@ config SND_SOC_AK4671
 config SND_SOC_CQ0093VC
 	tristate
 
+config SND_SOC_CS42L51
+	tristate
+
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
 	tristate
Index: sound-2.6/sound/soc/codecs/Makefile
===================================================================
--- sound-2.6.orig/sound/soc/codecs/Makefile	2010-05-27 14:09:32.836174105 +0200
+++ sound-2.6/sound/soc/codecs/Makefile	2010-05-27 14:09:52.107735223 +0200
@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
@@ -74,6 +75,7 @@ obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o

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

* [patch 4/6] cs42l51: add asoc driver
@ 2010-05-27 12:57   ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-27 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: cs42l51_support.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100527/2a0cd5a1/attachment.el>

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

* [patch 5/6] kirkwood: Add i2s support
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-27 12:57   ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-27 12:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: kirkwood_i2s.patch --]
[-- Type: text/plain, Size: 32343 bytes --]

This patch enables support for the i2s controller available on kirkwood platforms

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/sound/soc/kirkwood/Kconfig
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/Kconfig	2010-05-27 14:09:55.807674540 +0200
@@ -0,0 +1,11 @@
+config SND_KIRKWOOD_SOC
+	tristate "SoC Audio for the Marvell Kirkwood chip"
+	depends on ARCH_KIRKWOOD
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the Kirkwood I2S interface. You will also need to select the
+	  audio interfaces to support below.
+
+config SND_KIRKWOOD_SOC_I2S
+	tristate
+
Index: sound-2.6/sound/soc/kirkwood/kirkwood-dma.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-dma.c	2010-05-27 14:09:55.844174800 +0200
@@ -0,0 +1,383 @@
+/*
+ * kirkwood-dma.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mbus.h>
+#include <sound/soc.h>
+#include "kirkwood-dma.h"
+#include "kirkwood.h"
+
+#define KIRKWOOD_RATES \
+	(SNDRV_PCM_RATE_44100 | \
+	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
+
+struct kirkwood_dma_priv {
+	struct snd_pcm_substream *play_stream;
+	struct snd_pcm_substream *rec_stream;
+	struct kirkwood_dma_data *data;
+};
+
+static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_PAUSE),
+	.formats		= KIRKWOOD_FORMATS,
+	.rates			= KIRKWOOD_RATES,
+	.rate_min		= 44100,
+	.rate_max		= 96000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
+	.period_bytes_min	= KIRKWOOD_SND_MIN_PERIOD_BYTES,
+	.period_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES,
+	.periods_min		= KIRKWOOD_SND_MIN_PERIODS,
+	.periods_max		= KIRKWOOD_SND_MAX_PERIODS,
+	.fifo_size		= 0,
+};
+
+static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL;
+
+static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
+{
+	struct kirkwood_dma_priv *prdata = dev_id;
+	struct kirkwood_dma_data *priv = prdata->data;
+	unsigned long mask, status, cause;
+
+	mask = readl(priv->io + KIRKWOOD_INT_MASK);
+	status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
+
+	cause = readl(priv->io + KIRKWOOD_ERR_CAUSE);
+	if (unlikely(cause)) {
+		printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
+				__func__, cause);
+		writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
+		return IRQ_HANDLED;
+	}
+
+	/* we've enabled only bytes interrupts ... */
+	if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
+			KIRKWOOD_INT_CAUSE_REC_BYTES)) {
+		printk(KERN_WARNING "%s: unexpected interrupt %lx\n",
+			__func__, status);
+		return IRQ_NONE;
+	}
+
+	/* ack int */
+	writel(status, priv->io + KIRKWOOD_INT_CAUSE);
+
+	if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
+		snd_pcm_period_elapsed(prdata->play_stream);
+
+	if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
+		snd_pcm_period_elapsed(prdata->rec_stream);
+
+	return IRQ_HANDLED;
+}
+
+static void kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
+					unsigned long dma,
+					struct mbus_dram_target_info *dram)
+{
+	int i;
+
+	/* First disable and clear windows */
+	writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+	writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+
+	/* try to find matching cs for current dma address */
+	for (i = 0; i < dram->num_cs; i++) {
+		struct mbus_dram_window *cs = dram->cs + i;
+		if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) {
+			writel(cs->base & 0xffff0000,
+				base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+			writel(((cs->size - 1) & 0xffff0000) |
+				(cs->mbus_attr << 8) |
+				(dram->mbus_dram_target_id << 4) | 1,
+				base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+		}
+	}
+}
+
+static int kirkwood_dma_open(struct snd_pcm_substream *substream)
+{
+	int err;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+	unsigned long addr;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+	snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
+
+	/* Ensure that all constraints linked to dma burst are fullfilled */
+	err = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			priv->burst * 2,
+			KIRKWOOD_AUDIO_BUF_MAX-1);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_hw_constraint_step(runtime, 0,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			priv->burst);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_hw_constraint_step(substream->runtime, 0,
+			 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+			 priv->burst);
+	if (err < 0)
+		return err;
+
+	if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+		prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
+		if (prdata == NULL)
+			return -ENOMEM;
+
+		prdata->data = priv;
+
+		err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
+				  "kirkwood-i2s", prdata);
+		if (err) {
+			kfree(prdata);
+			return -EBUSY;
+		}
+
+		soc_runtime->dai->cpu_dai->private_data = prdata;
+
+		/*
+		 * Enable Error interrupts. We're only ack'ing them but
+		 * it's usefull for diagnostics
+		 */
+		writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
+	}
+
+	addr = virt_to_phys(substream->dma_buffer.area);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		prdata->play_stream = substream;
+		kirkwood_dma_conf_mbus_windows(priv->io,
+			KIRKWOOD_PLAYBACK_WIN, addr, priv->dram);
+	} else {
+		prdata->rec_stream = substream;
+		kirkwood_dma_conf_mbus_windows(priv->io,
+			KIRKWOOD_RECORD_WIN, addr, priv->dram);
+	}
+
+	return 0;
+}
+
+static int kirkwood_dma_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+	struct kirkwood_dma_data *priv;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	if (!prdata || !priv)
+		return 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prdata->play_stream = NULL;
+	else
+		prdata->rec_stream = NULL;
+
+	if (!prdata->play_stream && !prdata->rec_stream) {
+		writel(0, priv->io + KIRKWOOD_ERR_MASK);
+		free_irq(priv->irq, prdata);
+		kfree(prdata);
+		soc_runtime->dai->cpu_dai->private_data = NULL;
+	}
+
+	return 0;
+}
+
+static int kirkwood_dma_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 int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	unsigned long size, count;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	/* compute buffer size in term of "words" as requested in specs */
+	size = frames_to_bytes(runtime, runtime->buffer_size);
+	size = (size>>2)-1;
+	count = snd_pcm_lib_period_bytes(substream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT);
+		writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR);
+		writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE);
+	} else {
+		writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT);
+		writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR);
+		writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE);
+	}
+
+
+	return 0;
+}
+
+static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
+						*substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	snd_pcm_uframes_t count;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		count = bytes_to_frames(substream->runtime,
+			readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
+	else
+		count = bytes_to_frames(substream->runtime,
+			readl(priv->io + KIRKWOOD_REC_BYTE_COUNT));
+
+	return count;
+}
+
+struct snd_pcm_ops kirkwood_dma_ops = {
+	.open =		kirkwood_dma_open,
+	.close =        kirkwood_dma_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	kirkwood_dma_hw_params,
+	.hw_free =      kirkwood_dma_hw_free,
+	.prepare =      kirkwood_dma_prepare,
+	.pointer =	kirkwood_dma_pointer,
+};
+
+static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
+		int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+			&buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	buf->private_data = NULL;
+
+	return 0;
+}
+
+static int kirkwood_dma_new(struct snd_card *card,
+		struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+	int ret;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &kirkwood_dma_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].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;
+	}
+}
+
+struct snd_soc_platform kirkwood_soc_platform = {
+	.name		= "kirkwood-dma",
+	.pcm_ops	= &kirkwood_dma_ops,
+	.pcm_new	= kirkwood_dma_new,
+	.pcm_free	= kirkwood_dma_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
+
+static int __init kirkwood_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&kirkwood_soc_platform);
+}
+module_init(kirkwood_soc_platform_init);
+
+static void __exit kirkwood_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&kirkwood_soc_platform);
+}
+module_exit(kirkwood_soc_platform_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
+MODULE_LICENSE("GPL");
+
Index: sound-2.6/sound/soc/kirkwood/kirkwood.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood.h	2010-05-27 14:09:55.851714894 +0200
@@ -0,0 +1,126 @@
+/*
+ * kirkwood.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_AUDIO_H
+#define _KIRKWOOD_AUDIO_H
+
+#define KIRKWOOD_RECORD_WIN			0
+#define KIRKWOOD_PLAYBACK_WIN			1
+#define KIRKWOOD_MAX_AUDIO_WIN			2
+
+#define KIRKWOOD_AUDIO_WIN_BASE_REG(win)	(0xA00 + ((win)<<3))
+#define KIRKWOOD_AUDIO_WIN_CTRL_REG(win)	(0xA04 + ((win)<<3))
+
+
+#define KIRKWOOD_RECCTL			0x1000
+#define KIRKWOOD_RECCTL_SPDIF_EN		(1<<11)
+#define KIRKWOOD_RECCTL_I2S_EN			(1<<10)
+#define KIRKWOOD_RECCTL_PAUSE			(1<<9)
+#define KIRKWOOD_RECCTL_MUTE			(1<<8)
+#define KIRKWOOD_RECCTL_BURST_MASK		(3<<5)
+#define KIRKWOOD_RECCTL_BURST_128		(2<<5)
+#define KIRKWOOD_RECCTL_BURST_32		(1<<5)
+#define KIRKWOOD_RECCTL_MONO			(1<<4)
+#define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT	(1<<3)
+#define KIRKWOOD_RECCTL_MONO_CHAN_LEFT		(0<<3)
+#define KIRKWOOD_RECCTL_SIZE_MASK		(7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16		(7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16_C		(3<<0)
+#define KIRKWOOD_RECCTL_SIZE_20		(2<<0)
+#define KIRKWOOD_RECCTL_SIZE_24		(1<<0)
+#define KIRKWOOD_RECCTL_SIZE_32		(0<<0)
+
+#define KIRKWOOD_REC_BUF_ADDR			0x1004
+#define KIRKWOOD_REC_BUF_SIZE			0x1008
+#define KIRKWOOD_REC_BYTE_COUNT			0x100C
+
+#define KIRKWOOD_PLAYCTL			0x1100
+#define KIRKWOOD_PLAYCTL_PLAY_BUSY		(1<<16)
+#define KIRKWOOD_PLAYCTL_BURST_MASK		(3<<11)
+#define KIRKWOOD_PLAYCTL_BURST_128		(2<<11)
+#define KIRKWOOD_PLAYCTL_BURST_32		(1<<11)
+#define KIRKWOOD_PLAYCTL_PAUSE			(1<<9)
+#define KIRKWOOD_PLAYCTL_SPDIF_MUTE		(1<<8)
+#define KIRKWOOD_PLAYCTL_I2S_MUTE		(1<<7)
+#define KIRKWOOD_PLAYCTL_SPDIF_EN		(1<<4)
+#define KIRKWOOD_PLAYCTL_I2S_EN		(1<<3)
+#define KIRKWOOD_PLAYCTL_SIZE_MASK		(7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16		(7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16_C		(3<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_20		(2<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_24		(1<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_32		(0<<0)
+
+#define KIRKWOOD_PLAY_BUF_ADDR			0x1104
+#define KIRKWOOD_PLAY_BUF_SIZE			0x1108
+#define KIRKWOOD_PLAY_BYTE_COUNT		0x110C
+
+#define KIRKWOOD_DCO_CTL			0x1204
+#define KIRKWOOD_DCO_CTL_OFFSET_MASK		(0xFFF<<2)
+#define KIRKWOOD_DCO_CTL_OFFSET_0		(0x800<<2)
+#define KIRKWOOD_DCO_CTL_FREQ_MASK		(3<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_11		(0<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_12		(1<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_24		(2<<0)
+
+#define KIRKWOOD_DCO_SPCR_STATUS		0x120c
+#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK	(1<<16)
+
+#define KIRKWOOD_ERR_CAUSE			0x1300
+#define KIRKWOOD_ERR_MASK			0x1304
+
+#define KIRKWOOD_INT_CAUSE			0x1308
+#define KIRKWOOD_INT_MASK			0x130C
+#define KIRKWOOD_INT_CAUSE_PLAY_BYTES		(1<<14)
+#define KIRKWOOD_INT_CAUSE_REC_BYTES		(1<<13)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_END	(1<<7)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q		(1<<6)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF	(1<<5)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q		(1<<4)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_END		(1<<3)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_3Q		(1<<2)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_HALF	(1<<1)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_1Q		(1<<0)
+
+#define KIRKWOOD_REC_BYTE_INT_COUNT		0x1310
+#define KIRKWOOD_PLAY_BYTE_INT_COUNT		0x1314
+#define KIRKWOOD_BYTE_INT_COUNT_MASK		0xffffff
+
+#define KIRKWOOD_I2S_PLAYCTL			0x2508
+#define KIRKWOOD_I2S_RECCTL			0x2408
+#define KIRKWOOD_I2S_CTL_JUST_MASK		(0xf<<26)
+#define KIRKWOOD_I2S_CTL_LJ			(0<<26)
+#define KIRKWOOD_I2S_CTL_I2S			(5<<26)
+#define KIRKWOOD_I2S_CTL_RJ			(8<<26)
+#define KIRKWOOD_I2S_CTL_SIZE_MASK		(3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_16		(3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_20		(2<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_24		(1<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_32		(0<<30)
+
+#define KIRKWOOD_AUDIO_BUF_MAX			(16*1024*1024)
+
+/* Theses values come from the marvell alsa driver */
+/* need to find where they come from               */
+#define KIRKWOOD_SND_MIN_PERIODS		8
+#define KIRKWOOD_SND_MAX_PERIODS		16
+#define KIRKWOOD_SND_MIN_PERIOD_BYTES		0x4000
+#define KIRKWOOD_SND_MAX_PERIOD_BYTES		0x4000
+
+struct kirkwood_dma_data {
+	struct resource *mem;
+	void __iomem *io;
+	int irq;
+	int burst;
+	struct mbus_dram_target_info *dram;
+};
+
+#endif
Index: sound-2.6/sound/soc/kirkwood/kirkwood-i2s.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-i2s.c	2010-05-27 14:09:55.859694735 +0200
@@ -0,0 +1,485 @@
+/*
+ * kirkwood-i2s.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mbus.h>
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <plat/audio.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood.h"
+
+#define DRV_NAME	"kirkwood-i2s"
+
+#define KIRKWOOD_I2S_RATES \
+	(SNDRV_PCM_RATE_44100 | \
+	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_I2S_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+struct snd_soc_dai kirkwood_i2s_dai;
+static struct kirkwood_dma_data *priv;
+
+static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	unsigned long mask;
+	unsigned long value;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		mask = KIRKWOOD_I2S_CTL_RJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mask = KIRKWOOD_I2S_CTL_LJ;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mask = KIRKWOOD_I2S_CTL_I2S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Set same format for playback and record
+	 * This avoids some troubles.
+	 */
+	value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
+	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+	value |= mask;
+	writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
+
+	value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
+	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+	value |= mask;
+	writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
+
+	return 0;
+}
+
+static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
+{
+	unsigned long value;
+
+	value = KIRKWOOD_DCO_CTL_OFFSET_0;
+	switch (rate) {
+	default:
+	case 44100:
+		value |= KIRKWOOD_DCO_CTL_FREQ_11;
+		break;
+	case 48000:
+		value |= KIRKWOOD_DCO_CTL_FREQ_12;
+		break;
+	case 96000:
+		value |= KIRKWOOD_DCO_CTL_FREQ_24;
+		break;
+	}
+	writel(value, io + KIRKWOOD_DCO_CTL);
+
+	/* wait for dco locked */
+	do {
+		cpu_relax();
+		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
+		value &= KIRKWOOD_DCO_SPCR_STATUS;
+	} while (value == 0);
+}
+
+static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	unsigned int i2s_reg, reg;
+	unsigned long i2s_value, value;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_reg = KIRKWOOD_I2S_PLAYCTL;
+		reg = KIRKWOOD_PLAYCTL;
+	} else {
+		i2s_reg = KIRKWOOD_I2S_RECCTL;
+		reg = KIRKWOOD_RECCTL;
+	}
+
+	/* set dco conf */
+	kirkwood_set_dco(priv->io, params_rate(params));
+
+	i2s_value = readl(priv->io+i2s_reg);
+	i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
+
+	value = readl(priv->io+reg);
+	value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
+
+	/*
+	 * Size settings in play/rec i2s control regs and play/rec control
+	 * regs must be the same.
+	 */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
+		value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
+		break;
+	/*
+	 * doesn't work... S20_3LE != kirkwood 20bit format ?
+	 *
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
+		value |= KIRKWOOD_PLAYCTL_SIZE_20;
+		break;
+	*/
+	case SNDRV_PCM_FORMAT_S24_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
+		value |= KIRKWOOD_PLAYCTL_SIZE_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
+		value |= KIRKWOOD_PLAYCTL_SIZE_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+	writel(i2s_value, priv->io+i2s_reg);
+	writel(value, priv->io+reg);
+
+	return 0;
+}
+
+static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	unsigned long value;
+
+	/*
+	 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
+	 * changing it. So read 1 time here and 1 later.
+	 */
+	value = readl(priv->io + KIRKWOOD_PLAYCTL);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* stop audio, enable interrupts */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* configure audio & enable i2s playback */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
+		value &= ~(KIRKWOOD_PLAYCTL_PAUSE|KIRKWOOD_PLAYCTL_SPDIF_EN);
+
+		if (priv->burst == 32)
+			value |= KIRKWOOD_PLAYCTL_BURST_32;
+		else
+			value |= KIRKWOOD_PLAYCTL_BURST_128;
+		value |= KIRKWOOD_PLAYCTL_I2S_EN;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* stop audio, disable interrupts */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* disable all playbacks */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	unsigned long value;
+
+	value = readl(priv->io + KIRKWOOD_RECCTL);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* stop audio, enable interrupts */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* configure audio & enable i2s record */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~KIRKWOOD_RECCTL_BURST_MASK;
+		value &= ~KIRKWOOD_RECCTL_MONO;
+		value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_SPDIF_EN);
+
+		if (priv->burst == 32)
+			value |= KIRKWOOD_RECCTL_BURST_32;
+		else
+			value |= KIRKWOOD_RECCTL_BURST_128;
+		value |= KIRKWOOD_RECCTL_I2S_EN;
+
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* stop audio, disable interrupts */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* disable all records */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return kirkwood_i2s_play_trigger(substream, cmd, dai);
+	else
+		return kirkwood_i2s_rec_trigger(substream, cmd, dai);
+
+	return 0;
+}
+
+static int kirkwood_i2s_probe(struct platform_device *pdev,
+			     struct snd_soc_dai *dai)
+{
+	unsigned long value;
+	unsigned int reg_data;
+
+	/* put system in a "safe" state : */
+	/* disable audio interrupts */
+	writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
+	writel(0, priv->io + KIRKWOOD_INT_MASK);
+
+	reg_data = readl(priv->io + 0x1200);
+	reg_data &= (~(0x333FF8));
+	reg_data |= 0x111D18;
+	writel(reg_data, priv->io + 0x1200);
+
+	msleep(500);
+
+	reg_data = readl(priv->io + 0x1200);
+	reg_data &= (~(0x333FF8));
+	reg_data |= 0x111D18;
+	writel(reg_data, priv->io + 0x1200);
+
+	/* disable playback/record */
+	value = readl(priv->io + KIRKWOOD_PLAYCTL);
+	value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
+	writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+	value = readl(priv->io + KIRKWOOD_RECCTL);
+	value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+	writel(value, priv->io + KIRKWOOD_RECCTL);
+
+	return 0;
+
+}
+
+static void kirkwood_i2s_remove(struct platform_device *pdev,
+				struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+	.trigger	= kirkwood_i2s_trigger,
+	.hw_params      = kirkwood_i2s_hw_params,
+	.set_fmt        = kirkwood_i2s_set_fmt,
+};
+
+
+struct snd_soc_dai kirkwood_i2s_dai = {
+	.name = DRV_NAME,
+	.id = 0,
+	.probe = kirkwood_i2s_probe,
+	.remove = kirkwood_i2s_remove,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = KIRKWOOD_I2S_RATES,
+		.formats = KIRKWOOD_I2S_FORMATS,},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = KIRKWOOD_I2S_RATES,
+		.formats = KIRKWOOD_I2S_FORMATS,},
+	.ops = &kirkwood_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
+
+static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
+{
+	struct resource *mem;
+	struct kirkwood_asoc_platform_data *data =
+		pdev->dev.platform_data;
+	int err;
+
+	priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "allocation failed\n");
+		err = -ENOMEM;
+		goto error;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "platform_get_resource failed\n");
+		err = -ENXIO;
+		goto err_alloc;
+	}
+
+	priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME);
+	if (!priv->mem) {
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		err = -EBUSY;
+		goto error;
+	}
+
+	priv->io = ioremap(priv->mem->start, SZ_16K);
+	if (!priv->io) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		err = -ENOMEM;
+		goto err_iomem;
+	}
+
+	priv->irq = platform_get_irq(pdev, 0);
+	if (priv->irq <= 0) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		err = -ENXIO;
+		goto err_ioremap;
+	}
+
+	if (!data || !data->dram) {
+		dev_err(&pdev->dev, "no platform data ?!\n");
+		err = -EINVAL;
+		goto err_ioremap;
+	}
+
+	priv->dram = data->dram;
+	priv->burst = data->burst;
+
+	kirkwood_i2s_dai.capture.dma_data = priv;
+	kirkwood_i2s_dai.playback.dma_data = priv;
+
+	return snd_soc_register_dai(&kirkwood_i2s_dai);
+
+err_ioremap:
+	iounmap(priv->io);
+err_iomem:
+	release_mem_region(priv->mem->start, SZ_16K);
+err_alloc:
+	kfree(priv);
+error:
+	return err;
+}
+
+static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
+{
+	if (priv) {
+		iounmap(priv->io);
+		release_mem_region(priv->mem->start, SZ_16K);
+		kfree(priv);
+	}
+	snd_soc_unregister_dai(&kirkwood_i2s_dai);
+	return 0;
+}
+
+static struct platform_driver kirkwood_i2s_driver = {
+	.probe  = kirkwood_i2s_dev_probe,
+	.remove = kirkwood_i2s_dev_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init kirkwood_i2s_init(void)
+{
+	return platform_driver_register(&kirkwood_i2s_driver);
+}
+module_init(kirkwood_i2s_init);
+
+static void __exit kirkwood_i2s_exit(void)
+{
+	platform_driver_unregister(&kirkwood_i2s_driver);
+}
+module_exit(kirkwood_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kirkwood-i2s");
Index: sound-2.6/sound/soc/kirkwood/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/Makefile	2010-05-27 14:09:55.867694480 +0200
@@ -0,0 +1,6 @@
+snd-soc-kirkwood-objs := kirkwood-dma.o
+snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
+obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
+
Index: sound-2.6/sound/soc/Makefile
===================================================================
--- sound-2.6.orig/sound/soc/Makefile	2010-05-27 14:09:32.411724822 +0200
+++ sound-2.6/sound/soc/Makefile	2010-05-27 14:09:55.875714679 +0200
@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)	+= nuc900/
 obj-$(CONFIG_SND_SOC)	+= omap/
+obj-$(CONFIG_SND_SOC)	+= kirkwood/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
 obj-$(CONFIG_SND_SOC)	+= s6000/
Index: sound-2.6/sound/soc/kirkwood/kirkwood-dma.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-dma.h	2010-05-27 14:09:55.883714769 +0200
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-dma.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_DMA_H
+#define _KIRKWOOD_DMA_H
+
+extern struct snd_soc_platform kirkwood_soc_platform;
+
+#endif
Index: sound-2.6/sound/soc/kirkwood/kirkwood-i2s.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-i2s.h	2010-05-27 14:09:55.891695033 +0200
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-i2s.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_I2S_H
+#define _KIRKWOOD_I2S_H
+
+extern struct snd_soc_dai kirkwood_i2s_dai;
+
+#endif
Index: sound-2.6/sound/soc/Kconfig
===================================================================
--- sound-2.6.orig/sound/soc/Kconfig	2010-05-27 14:09:32.303673990 +0200
+++ sound-2.6/sound/soc/Kconfig	2010-05-27 14:09:55.899714700 +0200
@@ -32,6 +32,7 @@ source "sound/soc/fsl/Kconfig"
 source "sound/soc/imx/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
+source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/s6000/Kconfig"

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

* [patch 5/6] kirkwood: Add i2s support
@ 2010-05-27 12:57   ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-27 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: kirkwood_i2s.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100527/e0e3feaa/attachment.el>

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

* [patch 6/6] kirkwood: Add audio support to openrd client platforms
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-27 12:57   ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-27 12:57 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: openrd_audio.patch --]
[-- Type: text/plain, Size: 4790 bytes --]

This patch is adding support for openrd client platforms. It's using
the cs42l51 codec and has one mic and one speaker plugs.

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/sound/soc/kirkwood/Kconfig
===================================================================
--- sound-2.6.orig/sound/soc/kirkwood/Kconfig	2010-05-27 14:09:55.807674540 +0200
+++ sound-2.6/sound/soc/kirkwood/Kconfig	2010-05-27 14:10:03.887694459 +0200
@@ -9,3 +9,12 @@ config SND_KIRKWOOD_SOC
 config SND_KIRKWOOD_SOC_I2S
 	tristate
 
+config SND_KIRKWOOD_SOC_OPENRD
+	tristate "SoC Audio support for Kirkwood Openrd Client"
+	depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT
+	select SND_KIRKWOOD_SOC_I2S
+	select SND_SOC_CS42L51
+	help
+	  Say Y if you want to add support for SoC audio on
+	  Openrd Client.
+
Index: sound-2.6/sound/soc/kirkwood/Makefile
===================================================================
--- sound-2.6.orig/sound/soc/kirkwood/Makefile	2010-05-27 14:09:55.867694480 +0200
+++ sound-2.6/sound/soc/kirkwood/Makefile	2010-05-27 14:10:03.953137222 +0200
@@ -4,3 +4,6 @@ snd-soc-kirkwood-i2s-objs := kirkwood-i2
 obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
 obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
 
+snd-soc-openrd-objs := kirkwood-openrd.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
Index: sound-2.6/sound/soc/kirkwood/kirkwood-openrd.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-openrd.c	2010-05-27 14:10:03.987735275 +0200
@@ -0,0 +1,126 @@
+/*
+ * kirkwood-openrd.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <mach/kirkwood.h>
+#include <plat/audio.h>
+#include <asm/mach-types.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood-dma.h"
+#include "../codecs/cs42l51.h"
+
+static int openrd_client_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+	unsigned int freq, fmt;
+
+	fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	switch (params_rate(params)) {
+	default:
+	case 44100:
+		freq = 11289600;
+		break;
+	case 48000:
+		freq = 12288000;
+		break;
+	case 96000:
+		freq = 24576000;
+		break;
+	}
+
+	return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
+
+}
+
+static struct snd_soc_ops openrd_client_ops = {
+	.hw_params = openrd_client_hw_params,
+};
+
+
+static struct snd_soc_dai_link openrd_client_dai[] = {
+{
+	.name = "CS42L51",
+	.stream_name = "CS42L51 HiFi",
+	.cpu_dai = &kirkwood_i2s_dai,
+	.codec_dai = &cs42l51_dai,
+	.ops = &openrd_client_ops,
+},
+};
+
+
+static struct snd_soc_card openrd_client = {
+	.name = "OpenRD Client",
+	.platform = &kirkwood_soc_platform,
+	.dai_link = openrd_client_dai,
+	.num_links = ARRAY_SIZE(openrd_client_dai),
+};
+
+static struct snd_soc_device openrd_client_snd_devdata = {
+	.card = &openrd_client,
+	.codec_dev = &soc_codec_device_cs42l51,
+};
+
+static struct platform_device *openrd_client_snd_device;
+
+static int __init openrd_client_init(void)
+{
+	int ret;
+
+	if (!machine_is_openrd_client())
+		return 0;
+
+	openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!openrd_client_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(openrd_client_snd_device,
+			&openrd_client_snd_devdata);
+	openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+
+	ret = platform_device_add(openrd_client_snd_device);
+	if (ret) {
+		printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
+		platform_device_put(openrd_client_snd_device);
+	}
+
+	return ret;
+}
+
+static void __exit openrd_client_exit(void)
+{
+	platform_device_unregister(openrd_client_snd_device);
+}
+
+module_init(openrd_client_init);
+module_exit(openrd_client_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-audio");

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

* [patch 6/6] kirkwood: Add audio support to openrd client platforms
@ 2010-05-27 12:57   ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-27 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: openrd_audio.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100527/5e9e49eb/attachment.el>

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

* Re: [patch 1/6] orion/kirkwood: add audio functions.
  2010-05-27 12:57   ` apatard at mandriva.com
@ 2010-05-30 20:16     ` Nicolas Pitre
  -1 siblings, 0 replies; 45+ messages in thread
From: Nicolas Pitre @ 2010-05-30 20:16 UTC (permalink / raw)
  To: Arnaud Patard; +Cc: alsa-devel, broonie, saeed, tbm, linux-arm-kernel, lrg

On Thu, 27 May 2010, apatard@mandriva.com wrote:

> This patch add audio related definitions and functions
> 
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Acked-by: Nicolas Pitre <nico@fluxnic.net>



> 
> Index: sound-2.6/arch/arm/mach-kirkwood/common.c
> ===================================================================
> --- sound-2.6.orig/arch/arm/mach-kirkwood/common.c	2010-05-27 14:09:33.244174174 +0200
> +++ sound-2.6/arch/arm/mach-kirkwood/common.c	2010-05-27 14:09:35.840194356 +0200
> @@ -25,6 +25,7 @@
>  #include <asm/mach/time.h>
>  #include <mach/kirkwood.h>
>  #include <mach/bridge-regs.h>
> +#include <plat/audio.h>
>  #include <plat/cache-feroceon-l2.h>
>  #include <plat/ehci-orion.h>
>  #include <plat/mvsdio.h>
> @@ -855,6 +856,42 @@ struct sys_timer kirkwood_timer = {
>  	.init = kirkwood_timer_init,
>  };
>  
> +/*****************************************************************************
> + * Audio
> + ****************************************************************************/
> +static struct resource kirkwood_i2s_resources[] = {
> +	[0] = {
> +		.start  = AUDIO_PHYS_BASE,
> +		.end    = AUDIO_PHYS_BASE + SZ_16K - 1,
> +		.flags  = IORESOURCE_MEM,
> +	},
> +	[1] = {
> +		.start  = IRQ_KIRKWOOD_I2S,
> +		.end    = IRQ_KIRKWOOD_I2S,
> +		.flags  = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
> +	.dram        = &kirkwood_mbus_dram_info,
> +	.burst       = 128,
> +};
> +
> +static struct platform_device kirkwood_i2s_device = {
> +	.name		= "kirkwood-i2s",
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(kirkwood_i2s_resources),
> +	.resource	= kirkwood_i2s_resources,
> +	.dev		= {
> +		.platform_data	= &kirkwood_i2s_data,
> +	},
> +};
> +
> +void __init kirkwood_audio_init(void)
> +{
> +	kirkwood_clk_ctrl |= CGC_AUDIO;
> +	platform_device_register(&kirkwood_i2s_device);
> +}
>  
>  /*****************************************************************************
>   * General
> @@ -914,6 +951,7 @@ void __init kirkwood_init(void)
>  	kirkwood_spi_plat_data.tclk = kirkwood_tclk;
>  	kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
>  	kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
> +	kirkwood_i2s_data.tclk = kirkwood_tclk;
>  
>  	/*
>  	 * Disable propagation of mbus errors to the CPU local bus,
> Index: sound-2.6/arch/arm/mach-kirkwood/common.h
> ===================================================================
> --- sound-2.6.orig/arch/arm/mach-kirkwood/common.h	2010-05-27 14:09:33.204173835 +0200
> +++ sound-2.6/arch/arm/mach-kirkwood/common.h	2010-05-27 14:09:35.883694381 +0200
> @@ -16,6 +16,7 @@ struct mv643xx_eth_platform_data;
>  struct mv_sata_platform_data;
>  struct mvsdio_platform_data;
>  struct mtd_partition;
> +struct kirkwood_asoc_platform_data;
>  
>  /*
>   * Basic Kirkwood init functions used early by machine-setup.
> @@ -41,6 +42,7 @@ void kirkwood_i2c_init(void);
>  void kirkwood_uart0_init(void);
>  void kirkwood_uart1_init(void);
>  void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
> +void kirkwood_audio_init(void);
>  
>  extern int kirkwood_tclk;
>  extern struct sys_timer kirkwood_timer;
> Index: sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h
> ===================================================================
> --- sound-2.6.orig/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-27 14:09:33.188174747 +0200
> +++ sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-27 14:09:35.895694344 +0200
> @@ -96,6 +96,9 @@
>  
>  #define SDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x90000)
>  
> +#define AUDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
> +#define AUDIO_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
> +
>  /*
>   * Supported devices and revisions.
>   */
> Index: sound-2.6/arch/arm/plat-orion/include/plat/audio.h
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ sound-2.6/arch/arm/plat-orion/include/plat/audio.h	2010-05-27 14:09:35.895694344 +0200
> @@ -0,0 +1,11 @@
> +#ifndef __PLAT_AUDIO_H
> +#define __PLAT_AUDIO_H
> +
> +#include <linux/mbus.h>
> +
> +struct kirkwood_asoc_platform_data {
> +	u32 tclk;
> +	struct mbus_dram_target_info *dram;
> +	int burst;
> +};
> +#endif
> 

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

* [patch 1/6] orion/kirkwood: add audio functions.
@ 2010-05-30 20:16     ` Nicolas Pitre
  0 siblings, 0 replies; 45+ messages in thread
From: Nicolas Pitre @ 2010-05-30 20:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 27 May 2010, apatard at mandriva.com wrote:

> This patch add audio related definitions and functions
> 
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Acked-by: Nicolas Pitre <nico@fluxnic.net>



> 
> Index: sound-2.6/arch/arm/mach-kirkwood/common.c
> ===================================================================
> --- sound-2.6.orig/arch/arm/mach-kirkwood/common.c	2010-05-27 14:09:33.244174174 +0200
> +++ sound-2.6/arch/arm/mach-kirkwood/common.c	2010-05-27 14:09:35.840194356 +0200
> @@ -25,6 +25,7 @@
>  #include <asm/mach/time.h>
>  #include <mach/kirkwood.h>
>  #include <mach/bridge-regs.h>
> +#include <plat/audio.h>
>  #include <plat/cache-feroceon-l2.h>
>  #include <plat/ehci-orion.h>
>  #include <plat/mvsdio.h>
> @@ -855,6 +856,42 @@ struct sys_timer kirkwood_timer = {
>  	.init = kirkwood_timer_init,
>  };
>  
> +/*****************************************************************************
> + * Audio
> + ****************************************************************************/
> +static struct resource kirkwood_i2s_resources[] = {
> +	[0] = {
> +		.start  = AUDIO_PHYS_BASE,
> +		.end    = AUDIO_PHYS_BASE + SZ_16K - 1,
> +		.flags  = IORESOURCE_MEM,
> +	},
> +	[1] = {
> +		.start  = IRQ_KIRKWOOD_I2S,
> +		.end    = IRQ_KIRKWOOD_I2S,
> +		.flags  = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
> +	.dram        = &kirkwood_mbus_dram_info,
> +	.burst       = 128,
> +};
> +
> +static struct platform_device kirkwood_i2s_device = {
> +	.name		= "kirkwood-i2s",
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(kirkwood_i2s_resources),
> +	.resource	= kirkwood_i2s_resources,
> +	.dev		= {
> +		.platform_data	= &kirkwood_i2s_data,
> +	},
> +};
> +
> +void __init kirkwood_audio_init(void)
> +{
> +	kirkwood_clk_ctrl |= CGC_AUDIO;
> +	platform_device_register(&kirkwood_i2s_device);
> +}
>  
>  /*****************************************************************************
>   * General
> @@ -914,6 +951,7 @@ void __init kirkwood_init(void)
>  	kirkwood_spi_plat_data.tclk = kirkwood_tclk;
>  	kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
>  	kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
> +	kirkwood_i2s_data.tclk = kirkwood_tclk;
>  
>  	/*
>  	 * Disable propagation of mbus errors to the CPU local bus,
> Index: sound-2.6/arch/arm/mach-kirkwood/common.h
> ===================================================================
> --- sound-2.6.orig/arch/arm/mach-kirkwood/common.h	2010-05-27 14:09:33.204173835 +0200
> +++ sound-2.6/arch/arm/mach-kirkwood/common.h	2010-05-27 14:09:35.883694381 +0200
> @@ -16,6 +16,7 @@ struct mv643xx_eth_platform_data;
>  struct mv_sata_platform_data;
>  struct mvsdio_platform_data;
>  struct mtd_partition;
> +struct kirkwood_asoc_platform_data;
>  
>  /*
>   * Basic Kirkwood init functions used early by machine-setup.
> @@ -41,6 +42,7 @@ void kirkwood_i2c_init(void);
>  void kirkwood_uart0_init(void);
>  void kirkwood_uart1_init(void);
>  void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
> +void kirkwood_audio_init(void);
>  
>  extern int kirkwood_tclk;
>  extern struct sys_timer kirkwood_timer;
> Index: sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h
> ===================================================================
> --- sound-2.6.orig/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-27 14:09:33.188174747 +0200
> +++ sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-27 14:09:35.895694344 +0200
> @@ -96,6 +96,9 @@
>  
>  #define SDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x90000)
>  
> +#define AUDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
> +#define AUDIO_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
> +
>  /*
>   * Supported devices and revisions.
>   */
> Index: sound-2.6/arch/arm/plat-orion/include/plat/audio.h
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ sound-2.6/arch/arm/plat-orion/include/plat/audio.h	2010-05-27 14:09:35.895694344 +0200
> @@ -0,0 +1,11 @@
> +#ifndef __PLAT_AUDIO_H
> +#define __PLAT_AUDIO_H
> +
> +#include <linux/mbus.h>
> +
> +struct kirkwood_asoc_platform_data {
> +	u32 tclk;
> +	struct mbus_dram_target_info *dram;
> +	int burst;
> +};
> +#endif
> 

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

* Re: [patch 0/6] kirkwood openrd client audio support - v4
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-30 20:44   ` Nicolas Pitre
  -1 siblings, 0 replies; 45+ messages in thread
From: Nicolas Pitre @ 2010-05-30 20:44 UTC (permalink / raw)
  To: apatard; +Cc: alsa-devel, broonie, saeed, tbm, linux-arm-kernel, lrg

On Thu, 27 May 2010, apatard@mandriva.com wrote:

> 
> Hi,
> 
> This patchset is an other try to get merged openrd audio support mainline.
> The main change is going back to using kirkwood instead of orion, as the 
> only orion having i2s is not merged mainline (if I got it right).

Right.

> I've also fixed the lastests comments on the cs42l51 codec patch.
> 
> Arnaud
> 
> Changes :
> - changed back from orion to kirkwood
> - removed cs42l51 adc input register initialisation
> - moved the DAPM event macro to soc-dapm
> - fixed cs42l51_set_dai_fmt() master/slave check
> - removed cs42l51 startup message
> - use snd_soc_update_bits() in cs42l51_pdn_event()

I acked the first patch which touches directly the directory I normally 
handle patches for.  Given the series is mostly about ASOC stuff, I 
think it is best if the whole series, including the first patch, is 
pushed through the ASOC tree (if Mark agrees with the rest that is of 
course).


Nicolas

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

* [patch 0/6] kirkwood openrd client audio support - v4
@ 2010-05-30 20:44   ` Nicolas Pitre
  0 siblings, 0 replies; 45+ messages in thread
From: Nicolas Pitre @ 2010-05-30 20:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 27 May 2010, apatard at mandriva.com wrote:

> 
> Hi,
> 
> This patchset is an other try to get merged openrd audio support mainline.
> The main change is going back to using kirkwood instead of orion, as the 
> only orion having i2s is not merged mainline (if I got it right).

Right.

> I've also fixed the lastests comments on the cs42l51 codec patch.
> 
> Arnaud
> 
> Changes :
> - changed back from orion to kirkwood
> - removed cs42l51 adc input register initialisation
> - moved the DAPM event macro to soc-dapm
> - fixed cs42l51_set_dai_fmt() master/slave check
> - removed cs42l51 startup message
> - use snd_soc_update_bits() in cs42l51_pdn_event()

I acked the first patch which touches directly the directory I normally 
handle patches for.  Given the series is mostly about ASOC stuff, I 
think it is best if the whole series, including the first patch, is 
pushed through the ASOC tree (if Mark agrees with the rest that is of 
course).


Nicolas

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

* Re: [patch 0/6] kirkwood openrd client audio support - v4
  2010-05-27 12:57 ` apatard at mandriva.com
@ 2010-05-31 10:15   ` Liam Girdwood
  -1 siblings, 0 replies; 45+ messages in thread
From: Liam Girdwood @ 2010-05-31 10:15 UTC (permalink / raw)
  To: apatard; +Cc: alsa-devel, nico, broonie, saeed, tbm, linux-arm-kernel

On Thu, 2010-05-27 at 14:57 +0200, apatard@mandriva.com wrote:
> Hi,
> 
> This patchset is an other try to get merged openrd audio support mainline.
> The main change is going back to using kirkwood instead of orion, as the 
> only orion having i2s is not merged mainline (if I got it right).
> I've also fixed the lastests comments on the cs42l51 codec patch.
> 
> Arnaud
> 
> Changes :
> - changed back from orion to kirkwood
> - removed cs42l51 adc input register initialisation
> - moved the DAPM event macro to soc-dapm
> - fixed cs42l51_set_dai_fmt() master/slave check
> - removed cs42l51 startup message
> - use snd_soc_update_bits() in cs42l51_pdn_event()

Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk

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

* [alsa-devel] [patch 0/6] kirkwood openrd client audio support - v4
@ 2010-05-31 10:15   ` Liam Girdwood
  0 siblings, 0 replies; 45+ messages in thread
From: Liam Girdwood @ 2010-05-31 10:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 2010-05-27 at 14:57 +0200, apatard at mandriva.com wrote:
> Hi,
> 
> This patchset is an other try to get merged openrd audio support mainline.
> The main change is going back to using kirkwood instead of orion, as the 
> only orion having i2s is not merged mainline (if I got it right).
> I've also fixed the lastests comments on the cs42l51 codec patch.
> 
> Arnaud
> 
> Changes :
> - changed back from orion to kirkwood
> - removed cs42l51 adc input register initialisation
> - moved the DAPM event macro to soc-dapm
> - fixed cs42l51_set_dai_fmt() master/slave check
> - removed cs42l51 startup message
> - use snd_soc_update_bits() in cs42l51_pdn_event()

Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk

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

* Re: [patch 1/6] orion/kirkwood: add audio functions.
  2010-05-27 12:57   ` apatard at mandriva.com
@ 2010-05-31 11:14     ` Mark Brown
  -1 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 11:14 UTC (permalink / raw)
  To: apatard; +Cc: alsa-devel, nico, saeed, tbm, linux-arm-kernel, lrg

On Thu, May 27, 2010 at 02:57:38PM +0200, apatard@mandriva.com wrote:
> This patch add audio related definitions and functions
> 
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

I'm not sure which tree this patch was generated against but it won't
apply to either 2.6.35-rc1 or my old for-2.6.35 branch.  Please
regenerate against my for-2.6.36 branch.  The patches look fine but I'm
not able to apply them.

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

* [patch 1/6] orion/kirkwood: add audio functions.
@ 2010-05-31 11:14     ` Mark Brown
  0 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 11:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 27, 2010 at 02:57:38PM +0200, apatard at mandriva.com wrote:
> This patch add audio related definitions and functions
> 
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

I'm not sure which tree this patch was generated against but it won't
apply to either 2.6.35-rc1 or my old for-2.6.35 branch.  Please
regenerate against my for-2.6.36 branch.  The patches look fine but I'm
not able to apply them.

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

* Re: [patch 3/6] soc-dapm.h: add SND_SOC_DAPM_PRE_POST_PMD event
  2010-05-27 12:57   ` apatard at mandriva.com
@ 2010-05-31 11:20     ` Mark Brown
  -1 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 11:20 UTC (permalink / raw)
  To: apatard; +Cc: alsa-devel, nico, saeed, tbm, linux-arm-kernel, lrg

On Thu, May 27, 2010 at 02:57:40PM +0200, apatard@mandriva.com wrote:
> Some systems codecs need to configure some registers before and after powering down
> some of their part. As a convenience, I'm adding a macro for that.
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Applied with modified changelog, thanks.

Please put an appropriate prefix on patches you submit ("ASoC: " for
ASoC) - this makes it easier to apply.

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

* [patch 3/6] soc-dapm.h: add SND_SOC_DAPM_PRE_POST_PMD event
@ 2010-05-31 11:20     ` Mark Brown
  0 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 27, 2010 at 02:57:40PM +0200, apatard at mandriva.com wrote:
> Some systems codecs need to configure some registers before and after powering down
> some of their part. As a convenience, I'm adding a macro for that.
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Applied with modified changelog, thanks.

Please put an appropriate prefix on patches you submit ("ASoC: " for
ASoC) - this makes it easier to apply.

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

* Re: [patch 4/6] cs42l51: add asoc driver
  2010-05-27 12:57   ` apatard at mandriva.com
@ 2010-05-31 11:20     ` Mark Brown
  -1 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 11:20 UTC (permalink / raw)
  To: apatard; +Cc: alsa-devel, nico, saeed, tbm, linux-arm-kernel, lrg

On Thu, May 27, 2010 at 02:57:41PM +0200, apatard@mandriva.com wrote:
> This patch is adding a ASoC driver for the cs42l51 from Cirrus Logic.
> Master mode and spi mode are not supported.
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Applied, thanks.

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

* [patch 4/6] cs42l51: add asoc driver
@ 2010-05-31 11:20     ` Mark Brown
  0 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 27, 2010 at 02:57:41PM +0200, apatard at mandriva.com wrote:
> This patch is adding a ASoC driver for the cs42l51 from Cirrus Logic.
> Master mode and spi mode are not supported.
> 
> Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Applied, thanks.

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

* [patch 0/4] Re: [patch 1/6] orion/kirkwood: add audio functions.
  2010-05-31 11:14     ` Mark Brown
@ 2010-05-31 11:49       ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-31 11:49 UTC (permalink / raw)
  To: alsa-devel; +Cc: nico, broonie, saeed, tbm, linux-arm-kernel, lrg



> I'm not sure which tree this patch was generated against but it won't
> apply to either 2.6.35-rc1 or my old for-2.6.35 branch.  Please
> regenerate against my for-2.6.36 branch.  The patches look fine but I'm
> not able to apply them.

oh, ok. Sorry. It was based on a previous for-2.6.36 branch and the newer one conflicts
due to the mtd RnB patch.

This new serie is based on your for-2.6.36 branch with HEAD 72ed5a8c9b057aeb779d161ac6fab1e98f091697


Arnaud

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

* [patch 0/4] Re: [patch 1/6] orion/kirkwood: add audio functions.
@ 2010-05-31 11:49       ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-31 11:49 UTC (permalink / raw)
  To: linux-arm-kernel



> I'm not sure which tree this patch was generated against but it won't
> apply to either 2.6.35-rc1 or my old for-2.6.35 branch.  Please
> regenerate against my for-2.6.36 branch.  The patches look fine but I'm
> not able to apply them.

oh, ok. Sorry. It was based on a previous for-2.6.36 branch and the newer one conflicts
due to the mtd RnB patch.

This new serie is based on your for-2.6.36 branch with HEAD 72ed5a8c9b057aeb779d161ac6fab1e98f091697


Arnaud

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

* [patch 1/4] orion/kirkwood: add audio functions.
  2010-05-31 11:49       ` apatard at mandriva.com
@ 2010-05-31 11:49         ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-31 11:49 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: kirkwood_add_audio_dev.patch --]
[-- Type: text/plain, Size: 4032 bytes --]

This patch add audio related definitions and functions


Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/arch/arm/mach-kirkwood/common.c
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/common.c	2010-05-31 13:30:24.000000000 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/common.c	2010-05-31 13:35:21.567036892 +0200
@@ -25,6 +25,7 @@
 #include <asm/mach/time.h>
 #include <mach/kirkwood.h>
 #include <mach/bridge-regs.h>
+#include <plat/audio.h>
 #include <plat/cache-feroceon-l2.h>
 #include <plat/ehci-orion.h>
 #include <plat/mvsdio.h>
@@ -864,6 +865,42 @@ struct sys_timer kirkwood_timer = {
 	.init = kirkwood_timer_init,
 };
 
+/*****************************************************************************
+ * Audio
+ ****************************************************************************/
+static struct resource kirkwood_i2s_resources[] = {
+	[0] = {
+		.start  = AUDIO_PHYS_BASE,
+		.end    = AUDIO_PHYS_BASE + SZ_16K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = IRQ_KIRKWOOD_I2S,
+		.end    = IRQ_KIRKWOOD_I2S,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
+	.dram        = &kirkwood_mbus_dram_info,
+	.burst       = 128,
+};
+
+static struct platform_device kirkwood_i2s_device = {
+	.name		= "kirkwood-i2s",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(kirkwood_i2s_resources),
+	.resource	= kirkwood_i2s_resources,
+	.dev		= {
+		.platform_data	= &kirkwood_i2s_data,
+	},
+};
+
+void __init kirkwood_audio_init(void)
+{
+	kirkwood_clk_ctrl |= CGC_AUDIO;
+	platform_device_register(&kirkwood_i2s_device);
+}
 
 /*****************************************************************************
  * General
@@ -923,6 +960,7 @@ void __init kirkwood_init(void)
 	kirkwood_spi_plat_data.tclk = kirkwood_tclk;
 	kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
 	kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
+	kirkwood_i2s_data.tclk = kirkwood_tclk;
 
 	/*
 	 * Disable propagation of mbus errors to the CPU local bus,
Index: sound-2.6/arch/arm/mach-kirkwood/common.h
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/common.h	2010-05-31 13:30:24.000000000 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/common.h	2010-05-31 13:35:21.579077473 +0200
@@ -17,6 +17,7 @@ struct mv_sata_platform_data;
 struct mvsdio_platform_data;
 struct mtd_partition;
 struct mtd_info;
+struct kirkwood_asoc_platform_data;
 
 /*
  * Basic Kirkwood init functions used early by machine-setup.
@@ -43,6 +44,7 @@ void kirkwood_uart0_init(void);
 void kirkwood_uart1_init(void);
 void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
 void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *));
+void kirkwood_audio_init(void);
 
 extern int kirkwood_tclk;
 extern struct sys_timer kirkwood_timer;
Index: sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-31 13:25:39.000000000 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/include/mach/kirkwood.h	2010-05-31 13:35:21.611577218 +0200
@@ -96,6 +96,9 @@
 
 #define SDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0x90000)
 
+#define AUDIO_PHYS_BASE		(KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
+#define AUDIO_VIRT_BASE		(KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
+
 /*
  * Supported devices and revisions.
  */
Index: sound-2.6/arch/arm/plat-orion/include/plat/audio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/arch/arm/plat-orion/include/plat/audio.h	2010-05-31 13:35:21.623077514 +0200
@@ -0,0 +1,11 @@
+#ifndef __PLAT_AUDIO_H
+#define __PLAT_AUDIO_H
+
+#include <linux/mbus.h>
+
+struct kirkwood_asoc_platform_data {
+	u32 tclk;
+	struct mbus_dram_target_info *dram;
+	int burst;
+};
+#endif

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

* [patch 1/4] orion/kirkwood: add audio functions.
@ 2010-05-31 11:49         ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-31 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: kirkwood_add_audio_dev.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100531/6758ab30/attachment.el>

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

* [patch 2/4] openrd-client: initialise audio
  2010-05-31 11:49       ` apatard at mandriva.com
@ 2010-05-31 11:49         ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-31 11:49 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: openrd_init_audio_dev.patch --]
[-- Type: text/plain, Size: 1201 bytes --]

This patch is reponsible for enabling audio on the openrd client board

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/arch/arm/mach-kirkwood/openrd-setup.c
===================================================================
--- sound-2.6.orig/arch/arm/mach-kirkwood/openrd-setup.c	2010-05-27 14:09:33.076174419 +0200
+++ sound-2.6/arch/arm/mach-kirkwood/openrd-setup.c	2010-05-27 14:09:42.067694397 +0200
@@ -15,6 +15,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
@@ -60,6 +61,12 @@ static unsigned int openrd_mpp_config[]
 	0
 };
 
+static struct i2c_board_info i2c_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("cs42l51", 0x4a),
+	},
+};
+
 static void __init openrd_init(void)
 {
 	/*
@@ -80,6 +87,12 @@ static void __init openrd_init(void)
 	kirkwood_sdio_init(&openrd_mvsdio_data);
 
 	kirkwood_i2c_init();
+
+	if (machine_is_openrd_client()) {
+		i2c_register_board_info(0, i2c_board_info,
+			ARRAY_SIZE(i2c_board_info));
+		kirkwood_audio_init();
+	}
 }
 
 static int __init openrd_pci_init(void)

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

* [patch 2/4] openrd-client: initialise audio
@ 2010-05-31 11:49         ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-31 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: openrd_init_audio_dev.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100531/556de3c2/attachment.el>

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

* [patch 3/4] kirkwood: Add i2s support
  2010-05-31 11:49       ` apatard at mandriva.com
@ 2010-05-31 11:49         ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-31 11:49 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: kirkwood_i2s.patch --]
[-- Type: text/plain, Size: 32343 bytes --]

This patch enables support for the i2s controller available on kirkwood platforms

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/sound/soc/kirkwood/Kconfig
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/Kconfig	2010-05-27 14:09:55.807674540 +0200
@@ -0,0 +1,11 @@
+config SND_KIRKWOOD_SOC
+	tristate "SoC Audio for the Marvell Kirkwood chip"
+	depends on ARCH_KIRKWOOD
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the Kirkwood I2S interface. You will also need to select the
+	  audio interfaces to support below.
+
+config SND_KIRKWOOD_SOC_I2S
+	tristate
+
Index: sound-2.6/sound/soc/kirkwood/kirkwood-dma.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-dma.c	2010-05-27 14:09:55.844174800 +0200
@@ -0,0 +1,383 @@
+/*
+ * kirkwood-dma.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mbus.h>
+#include <sound/soc.h>
+#include "kirkwood-dma.h"
+#include "kirkwood.h"
+
+#define KIRKWOOD_RATES \
+	(SNDRV_PCM_RATE_44100 | \
+	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
+
+struct kirkwood_dma_priv {
+	struct snd_pcm_substream *play_stream;
+	struct snd_pcm_substream *rec_stream;
+	struct kirkwood_dma_data *data;
+};
+
+static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED |
+		 SNDRV_PCM_INFO_MMAP |
+		 SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_PAUSE),
+	.formats		= KIRKWOOD_FORMATS,
+	.rates			= KIRKWOOD_RATES,
+	.rate_min		= 44100,
+	.rate_max		= 96000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
+	.period_bytes_min	= KIRKWOOD_SND_MIN_PERIOD_BYTES,
+	.period_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES,
+	.periods_min		= KIRKWOOD_SND_MIN_PERIODS,
+	.periods_max		= KIRKWOOD_SND_MAX_PERIODS,
+	.fifo_size		= 0,
+};
+
+static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL;
+
+static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
+{
+	struct kirkwood_dma_priv *prdata = dev_id;
+	struct kirkwood_dma_data *priv = prdata->data;
+	unsigned long mask, status, cause;
+
+	mask = readl(priv->io + KIRKWOOD_INT_MASK);
+	status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
+
+	cause = readl(priv->io + KIRKWOOD_ERR_CAUSE);
+	if (unlikely(cause)) {
+		printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
+				__func__, cause);
+		writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
+		return IRQ_HANDLED;
+	}
+
+	/* we've enabled only bytes interrupts ... */
+	if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
+			KIRKWOOD_INT_CAUSE_REC_BYTES)) {
+		printk(KERN_WARNING "%s: unexpected interrupt %lx\n",
+			__func__, status);
+		return IRQ_NONE;
+	}
+
+	/* ack int */
+	writel(status, priv->io + KIRKWOOD_INT_CAUSE);
+
+	if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
+		snd_pcm_period_elapsed(prdata->play_stream);
+
+	if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
+		snd_pcm_period_elapsed(prdata->rec_stream);
+
+	return IRQ_HANDLED;
+}
+
+static void kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
+					unsigned long dma,
+					struct mbus_dram_target_info *dram)
+{
+	int i;
+
+	/* First disable and clear windows */
+	writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+	writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+
+	/* try to find matching cs for current dma address */
+	for (i = 0; i < dram->num_cs; i++) {
+		struct mbus_dram_window *cs = dram->cs + i;
+		if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) {
+			writel(cs->base & 0xffff0000,
+				base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+			writel(((cs->size - 1) & 0xffff0000) |
+				(cs->mbus_attr << 8) |
+				(dram->mbus_dram_target_id << 4) | 1,
+				base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+		}
+	}
+}
+
+static int kirkwood_dma_open(struct snd_pcm_substream *substream)
+{
+	int err;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+	unsigned long addr;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+	snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
+
+	/* Ensure that all constraints linked to dma burst are fullfilled */
+	err = snd_pcm_hw_constraint_minmax(runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			priv->burst * 2,
+			KIRKWOOD_AUDIO_BUF_MAX-1);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_hw_constraint_step(runtime, 0,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+			priv->burst);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_hw_constraint_step(substream->runtime, 0,
+			 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+			 priv->burst);
+	if (err < 0)
+		return err;
+
+	if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+		prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
+		if (prdata == NULL)
+			return -ENOMEM;
+
+		prdata->data = priv;
+
+		err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
+				  "kirkwood-i2s", prdata);
+		if (err) {
+			kfree(prdata);
+			return -EBUSY;
+		}
+
+		soc_runtime->dai->cpu_dai->private_data = prdata;
+
+		/*
+		 * Enable Error interrupts. We're only ack'ing them but
+		 * it's usefull for diagnostics
+		 */
+		writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
+	}
+
+	addr = virt_to_phys(substream->dma_buffer.area);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		prdata->play_stream = substream;
+		kirkwood_dma_conf_mbus_windows(priv->io,
+			KIRKWOOD_PLAYBACK_WIN, addr, priv->dram);
+	} else {
+		prdata->rec_stream = substream;
+		kirkwood_dma_conf_mbus_windows(priv->io,
+			KIRKWOOD_RECORD_WIN, addr, priv->dram);
+	}
+
+	return 0;
+}
+
+static int kirkwood_dma_close(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+	struct kirkwood_dma_data *priv;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	if (!prdata || !priv)
+		return 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		prdata->play_stream = NULL;
+	else
+		prdata->rec_stream = NULL;
+
+	if (!prdata->play_stream && !prdata->rec_stream) {
+		writel(0, priv->io + KIRKWOOD_ERR_MASK);
+		free_irq(priv->irq, prdata);
+		kfree(prdata);
+		soc_runtime->dai->cpu_dai->private_data = NULL;
+	}
+
+	return 0;
+}
+
+static int kirkwood_dma_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 int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	unsigned long size, count;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	/* compute buffer size in term of "words" as requested in specs */
+	size = frames_to_bytes(runtime, runtime->buffer_size);
+	size = (size>>2)-1;
+	count = snd_pcm_lib_period_bytes(substream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT);
+		writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR);
+		writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE);
+	} else {
+		writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT);
+		writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR);
+		writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE);
+	}
+
+
+	return 0;
+}
+
+static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
+						*substream)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+	struct kirkwood_dma_data *priv;
+	snd_pcm_uframes_t count;
+
+	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		count = bytes_to_frames(substream->runtime,
+			readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
+	else
+		count = bytes_to_frames(substream->runtime,
+			readl(priv->io + KIRKWOOD_REC_BYTE_COUNT));
+
+	return count;
+}
+
+struct snd_pcm_ops kirkwood_dma_ops = {
+	.open =		kirkwood_dma_open,
+	.close =        kirkwood_dma_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	kirkwood_dma_hw_params,
+	.hw_free =      kirkwood_dma_hw_free,
+	.prepare =      kirkwood_dma_prepare,
+	.pointer =	kirkwood_dma_pointer,
+};
+
+static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
+		int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+			&buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	buf->private_data = NULL;
+
+	return 0;
+}
+
+static int kirkwood_dma_new(struct snd_card *card,
+		struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+	int ret;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &kirkwood_dma_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].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;
+	}
+}
+
+struct snd_soc_platform kirkwood_soc_platform = {
+	.name		= "kirkwood-dma",
+	.pcm_ops	= &kirkwood_dma_ops,
+	.pcm_new	= kirkwood_dma_new,
+	.pcm_free	= kirkwood_dma_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
+
+static int __init kirkwood_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&kirkwood_soc_platform);
+}
+module_init(kirkwood_soc_platform_init);
+
+static void __exit kirkwood_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&kirkwood_soc_platform);
+}
+module_exit(kirkwood_soc_platform_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
+MODULE_LICENSE("GPL");
+
Index: sound-2.6/sound/soc/kirkwood/kirkwood.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood.h	2010-05-27 14:09:55.851714894 +0200
@@ -0,0 +1,126 @@
+/*
+ * kirkwood.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_AUDIO_H
+#define _KIRKWOOD_AUDIO_H
+
+#define KIRKWOOD_RECORD_WIN			0
+#define KIRKWOOD_PLAYBACK_WIN			1
+#define KIRKWOOD_MAX_AUDIO_WIN			2
+
+#define KIRKWOOD_AUDIO_WIN_BASE_REG(win)	(0xA00 + ((win)<<3))
+#define KIRKWOOD_AUDIO_WIN_CTRL_REG(win)	(0xA04 + ((win)<<3))
+
+
+#define KIRKWOOD_RECCTL			0x1000
+#define KIRKWOOD_RECCTL_SPDIF_EN		(1<<11)
+#define KIRKWOOD_RECCTL_I2S_EN			(1<<10)
+#define KIRKWOOD_RECCTL_PAUSE			(1<<9)
+#define KIRKWOOD_RECCTL_MUTE			(1<<8)
+#define KIRKWOOD_RECCTL_BURST_MASK		(3<<5)
+#define KIRKWOOD_RECCTL_BURST_128		(2<<5)
+#define KIRKWOOD_RECCTL_BURST_32		(1<<5)
+#define KIRKWOOD_RECCTL_MONO			(1<<4)
+#define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT	(1<<3)
+#define KIRKWOOD_RECCTL_MONO_CHAN_LEFT		(0<<3)
+#define KIRKWOOD_RECCTL_SIZE_MASK		(7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16		(7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16_C		(3<<0)
+#define KIRKWOOD_RECCTL_SIZE_20		(2<<0)
+#define KIRKWOOD_RECCTL_SIZE_24		(1<<0)
+#define KIRKWOOD_RECCTL_SIZE_32		(0<<0)
+
+#define KIRKWOOD_REC_BUF_ADDR			0x1004
+#define KIRKWOOD_REC_BUF_SIZE			0x1008
+#define KIRKWOOD_REC_BYTE_COUNT			0x100C
+
+#define KIRKWOOD_PLAYCTL			0x1100
+#define KIRKWOOD_PLAYCTL_PLAY_BUSY		(1<<16)
+#define KIRKWOOD_PLAYCTL_BURST_MASK		(3<<11)
+#define KIRKWOOD_PLAYCTL_BURST_128		(2<<11)
+#define KIRKWOOD_PLAYCTL_BURST_32		(1<<11)
+#define KIRKWOOD_PLAYCTL_PAUSE			(1<<9)
+#define KIRKWOOD_PLAYCTL_SPDIF_MUTE		(1<<8)
+#define KIRKWOOD_PLAYCTL_I2S_MUTE		(1<<7)
+#define KIRKWOOD_PLAYCTL_SPDIF_EN		(1<<4)
+#define KIRKWOOD_PLAYCTL_I2S_EN		(1<<3)
+#define KIRKWOOD_PLAYCTL_SIZE_MASK		(7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16		(7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16_C		(3<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_20		(2<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_24		(1<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_32		(0<<0)
+
+#define KIRKWOOD_PLAY_BUF_ADDR			0x1104
+#define KIRKWOOD_PLAY_BUF_SIZE			0x1108
+#define KIRKWOOD_PLAY_BYTE_COUNT		0x110C
+
+#define KIRKWOOD_DCO_CTL			0x1204
+#define KIRKWOOD_DCO_CTL_OFFSET_MASK		(0xFFF<<2)
+#define KIRKWOOD_DCO_CTL_OFFSET_0		(0x800<<2)
+#define KIRKWOOD_DCO_CTL_FREQ_MASK		(3<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_11		(0<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_12		(1<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_24		(2<<0)
+
+#define KIRKWOOD_DCO_SPCR_STATUS		0x120c
+#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK	(1<<16)
+
+#define KIRKWOOD_ERR_CAUSE			0x1300
+#define KIRKWOOD_ERR_MASK			0x1304
+
+#define KIRKWOOD_INT_CAUSE			0x1308
+#define KIRKWOOD_INT_MASK			0x130C
+#define KIRKWOOD_INT_CAUSE_PLAY_BYTES		(1<<14)
+#define KIRKWOOD_INT_CAUSE_REC_BYTES		(1<<13)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_END	(1<<7)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q		(1<<6)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF	(1<<5)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q		(1<<4)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_END		(1<<3)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_3Q		(1<<2)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_HALF	(1<<1)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_1Q		(1<<0)
+
+#define KIRKWOOD_REC_BYTE_INT_COUNT		0x1310
+#define KIRKWOOD_PLAY_BYTE_INT_COUNT		0x1314
+#define KIRKWOOD_BYTE_INT_COUNT_MASK		0xffffff
+
+#define KIRKWOOD_I2S_PLAYCTL			0x2508
+#define KIRKWOOD_I2S_RECCTL			0x2408
+#define KIRKWOOD_I2S_CTL_JUST_MASK		(0xf<<26)
+#define KIRKWOOD_I2S_CTL_LJ			(0<<26)
+#define KIRKWOOD_I2S_CTL_I2S			(5<<26)
+#define KIRKWOOD_I2S_CTL_RJ			(8<<26)
+#define KIRKWOOD_I2S_CTL_SIZE_MASK		(3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_16		(3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_20		(2<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_24		(1<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_32		(0<<30)
+
+#define KIRKWOOD_AUDIO_BUF_MAX			(16*1024*1024)
+
+/* Theses values come from the marvell alsa driver */
+/* need to find where they come from               */
+#define KIRKWOOD_SND_MIN_PERIODS		8
+#define KIRKWOOD_SND_MAX_PERIODS		16
+#define KIRKWOOD_SND_MIN_PERIOD_BYTES		0x4000
+#define KIRKWOOD_SND_MAX_PERIOD_BYTES		0x4000
+
+struct kirkwood_dma_data {
+	struct resource *mem;
+	void __iomem *io;
+	int irq;
+	int burst;
+	struct mbus_dram_target_info *dram;
+};
+
+#endif
Index: sound-2.6/sound/soc/kirkwood/kirkwood-i2s.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-i2s.c	2010-05-27 14:09:55.859694735 +0200
@@ -0,0 +1,485 @@
+/*
+ * kirkwood-i2s.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mbus.h>
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <plat/audio.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood.h"
+
+#define DRV_NAME	"kirkwood-i2s"
+
+#define KIRKWOOD_I2S_RATES \
+	(SNDRV_PCM_RATE_44100 | \
+	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_I2S_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
+
+
+struct snd_soc_dai kirkwood_i2s_dai;
+static struct kirkwood_dma_data *priv;
+
+static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	unsigned long mask;
+	unsigned long value;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		mask = KIRKWOOD_I2S_CTL_RJ;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mask = KIRKWOOD_I2S_CTL_LJ;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mask = KIRKWOOD_I2S_CTL_I2S;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Set same format for playback and record
+	 * This avoids some troubles.
+	 */
+	value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
+	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+	value |= mask;
+	writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
+
+	value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
+	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+	value |= mask;
+	writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
+
+	return 0;
+}
+
+static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
+{
+	unsigned long value;
+
+	value = KIRKWOOD_DCO_CTL_OFFSET_0;
+	switch (rate) {
+	default:
+	case 44100:
+		value |= KIRKWOOD_DCO_CTL_FREQ_11;
+		break;
+	case 48000:
+		value |= KIRKWOOD_DCO_CTL_FREQ_12;
+		break;
+	case 96000:
+		value |= KIRKWOOD_DCO_CTL_FREQ_24;
+		break;
+	}
+	writel(value, io + KIRKWOOD_DCO_CTL);
+
+	/* wait for dco locked */
+	do {
+		cpu_relax();
+		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
+		value &= KIRKWOOD_DCO_SPCR_STATUS;
+	} while (value == 0);
+}
+
+static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	unsigned int i2s_reg, reg;
+	unsigned long i2s_value, value;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_reg = KIRKWOOD_I2S_PLAYCTL;
+		reg = KIRKWOOD_PLAYCTL;
+	} else {
+		i2s_reg = KIRKWOOD_I2S_RECCTL;
+		reg = KIRKWOOD_RECCTL;
+	}
+
+	/* set dco conf */
+	kirkwood_set_dco(priv->io, params_rate(params));
+
+	i2s_value = readl(priv->io+i2s_reg);
+	i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
+
+	value = readl(priv->io+reg);
+	value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
+
+	/*
+	 * Size settings in play/rec i2s control regs and play/rec control
+	 * regs must be the same.
+	 */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
+		value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
+		break;
+	/*
+	 * doesn't work... S20_3LE != kirkwood 20bit format ?
+	 *
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
+		value |= KIRKWOOD_PLAYCTL_SIZE_20;
+		break;
+	*/
+	case SNDRV_PCM_FORMAT_S24_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
+		value |= KIRKWOOD_PLAYCTL_SIZE_24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
+		value |= KIRKWOOD_PLAYCTL_SIZE_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+	writel(i2s_value, priv->io+i2s_reg);
+	writel(value, priv->io+reg);
+
+	return 0;
+}
+
+static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	unsigned long value;
+
+	/*
+	 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
+	 * changing it. So read 1 time here and 1 later.
+	 */
+	value = readl(priv->io + KIRKWOOD_PLAYCTL);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* stop audio, enable interrupts */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* configure audio & enable i2s playback */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
+		value &= ~(KIRKWOOD_PLAYCTL_PAUSE|KIRKWOOD_PLAYCTL_SPDIF_EN);
+
+		if (priv->burst == 32)
+			value |= KIRKWOOD_PLAYCTL_BURST_32;
+		else
+			value |= KIRKWOOD_PLAYCTL_BURST_128;
+		value |= KIRKWOOD_PLAYCTL_I2S_EN;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* stop audio, disable interrupts */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* disable all playbacks */
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value |= KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		value = readl(priv->io + KIRKWOOD_PLAYCTL);
+		value &= ~KIRKWOOD_PLAYCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_PLAYCTL);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	unsigned long value;
+
+	value = readl(priv->io + KIRKWOOD_RECCTL);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* stop audio, enable interrupts */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* configure audio & enable i2s record */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~KIRKWOOD_RECCTL_BURST_MASK;
+		value &= ~KIRKWOOD_RECCTL_MONO;
+		value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_SPDIF_EN);
+
+		if (priv->burst == 32)
+			value |= KIRKWOOD_RECCTL_BURST_32;
+		else
+			value |= KIRKWOOD_RECCTL_BURST_128;
+		value |= KIRKWOOD_RECCTL_I2S_EN;
+
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* stop audio, disable interrupts */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+
+		value = readl(priv->io + KIRKWOOD_INT_MASK);
+		value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
+		writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+		/* disable all records */
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value |= KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		value = readl(priv->io + KIRKWOOD_RECCTL);
+		value &= ~KIRKWOOD_RECCTL_PAUSE;
+		writel(value, priv->io + KIRKWOOD_RECCTL);
+		break;
+
+	default:
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return kirkwood_i2s_play_trigger(substream, cmd, dai);
+	else
+		return kirkwood_i2s_rec_trigger(substream, cmd, dai);
+
+	return 0;
+}
+
+static int kirkwood_i2s_probe(struct platform_device *pdev,
+			     struct snd_soc_dai *dai)
+{
+	unsigned long value;
+	unsigned int reg_data;
+
+	/* put system in a "safe" state : */
+	/* disable audio interrupts */
+	writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
+	writel(0, priv->io + KIRKWOOD_INT_MASK);
+
+	reg_data = readl(priv->io + 0x1200);
+	reg_data &= (~(0x333FF8));
+	reg_data |= 0x111D18;
+	writel(reg_data, priv->io + 0x1200);
+
+	msleep(500);
+
+	reg_data = readl(priv->io + 0x1200);
+	reg_data &= (~(0x333FF8));
+	reg_data |= 0x111D18;
+	writel(reg_data, priv->io + 0x1200);
+
+	/* disable playback/record */
+	value = readl(priv->io + KIRKWOOD_PLAYCTL);
+	value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
+	writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+	value = readl(priv->io + KIRKWOOD_RECCTL);
+	value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+	writel(value, priv->io + KIRKWOOD_RECCTL);
+
+	return 0;
+
+}
+
+static void kirkwood_i2s_remove(struct platform_device *pdev,
+				struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+	.trigger	= kirkwood_i2s_trigger,
+	.hw_params      = kirkwood_i2s_hw_params,
+	.set_fmt        = kirkwood_i2s_set_fmt,
+};
+
+
+struct snd_soc_dai kirkwood_i2s_dai = {
+	.name = DRV_NAME,
+	.id = 0,
+	.probe = kirkwood_i2s_probe,
+	.remove = kirkwood_i2s_remove,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = KIRKWOOD_I2S_RATES,
+		.formats = KIRKWOOD_I2S_FORMATS,},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = KIRKWOOD_I2S_RATES,
+		.formats = KIRKWOOD_I2S_FORMATS,},
+	.ops = &kirkwood_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
+
+static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
+{
+	struct resource *mem;
+	struct kirkwood_asoc_platform_data *data =
+		pdev->dev.platform_data;
+	int err;
+
+	priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "allocation failed\n");
+		err = -ENOMEM;
+		goto error;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "platform_get_resource failed\n");
+		err = -ENXIO;
+		goto err_alloc;
+	}
+
+	priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME);
+	if (!priv->mem) {
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		err = -EBUSY;
+		goto error;
+	}
+
+	priv->io = ioremap(priv->mem->start, SZ_16K);
+	if (!priv->io) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		err = -ENOMEM;
+		goto err_iomem;
+	}
+
+	priv->irq = platform_get_irq(pdev, 0);
+	if (priv->irq <= 0) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		err = -ENXIO;
+		goto err_ioremap;
+	}
+
+	if (!data || !data->dram) {
+		dev_err(&pdev->dev, "no platform data ?!\n");
+		err = -EINVAL;
+		goto err_ioremap;
+	}
+
+	priv->dram = data->dram;
+	priv->burst = data->burst;
+
+	kirkwood_i2s_dai.capture.dma_data = priv;
+	kirkwood_i2s_dai.playback.dma_data = priv;
+
+	return snd_soc_register_dai(&kirkwood_i2s_dai);
+
+err_ioremap:
+	iounmap(priv->io);
+err_iomem:
+	release_mem_region(priv->mem->start, SZ_16K);
+err_alloc:
+	kfree(priv);
+error:
+	return err;
+}
+
+static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
+{
+	if (priv) {
+		iounmap(priv->io);
+		release_mem_region(priv->mem->start, SZ_16K);
+		kfree(priv);
+	}
+	snd_soc_unregister_dai(&kirkwood_i2s_dai);
+	return 0;
+}
+
+static struct platform_driver kirkwood_i2s_driver = {
+	.probe  = kirkwood_i2s_dev_probe,
+	.remove = kirkwood_i2s_dev_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init kirkwood_i2s_init(void)
+{
+	return platform_driver_register(&kirkwood_i2s_driver);
+}
+module_init(kirkwood_i2s_init);
+
+static void __exit kirkwood_i2s_exit(void)
+{
+	platform_driver_unregister(&kirkwood_i2s_driver);
+}
+module_exit(kirkwood_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kirkwood-i2s");
Index: sound-2.6/sound/soc/kirkwood/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/Makefile	2010-05-27 14:09:55.867694480 +0200
@@ -0,0 +1,6 @@
+snd-soc-kirkwood-objs := kirkwood-dma.o
+snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
+obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
+
Index: sound-2.6/sound/soc/Makefile
===================================================================
--- sound-2.6.orig/sound/soc/Makefile	2010-05-27 14:09:32.411724822 +0200
+++ sound-2.6/sound/soc/Makefile	2010-05-27 14:09:55.875714679 +0200
@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)	+= nuc900/
 obj-$(CONFIG_SND_SOC)	+= omap/
+obj-$(CONFIG_SND_SOC)	+= kirkwood/
 obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= s3c24xx/
 obj-$(CONFIG_SND_SOC)	+= s6000/
Index: sound-2.6/sound/soc/kirkwood/kirkwood-dma.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-dma.h	2010-05-27 14:09:55.883714769 +0200
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-dma.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_DMA_H
+#define _KIRKWOOD_DMA_H
+
+extern struct snd_soc_platform kirkwood_soc_platform;
+
+#endif
Index: sound-2.6/sound/soc/kirkwood/kirkwood-i2s.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-i2s.h	2010-05-27 14:09:55.891695033 +0200
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-i2s.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#ifndef _KIRKWOOD_I2S_H
+#define _KIRKWOOD_I2S_H
+
+extern struct snd_soc_dai kirkwood_i2s_dai;
+
+#endif
Index: sound-2.6/sound/soc/Kconfig
===================================================================
--- sound-2.6.orig/sound/soc/Kconfig	2010-05-27 14:09:32.303673990 +0200
+++ sound-2.6/sound/soc/Kconfig	2010-05-27 14:09:55.899714700 +0200
@@ -32,6 +32,7 @@ source "sound/soc/fsl/Kconfig"
 source "sound/soc/imx/Kconfig"
 source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
+source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/s6000/Kconfig"

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

* [patch 3/4] kirkwood: Add i2s support
@ 2010-05-31 11:49         ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-31 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: kirkwood_i2s.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100531/306733e6/attachment.el>

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

* [patch 4/4] kirkwood: Add audio support to openrd client platforms
  2010-05-31 11:49       ` apatard at mandriva.com
@ 2010-05-31 11:49         ` apatard at mandriva.com
  -1 siblings, 0 replies; 45+ messages in thread
From: apatard @ 2010-05-31 11:49 UTC (permalink / raw)
  To: alsa-devel
  Cc: nico, broonie, saeed, Arnaud Patard, tbm, linux-arm-kernel, lrg

[-- Attachment #1: openrd_audio.patch --]
[-- Type: text/plain, Size: 4790 bytes --]

This patch is adding support for openrd client platforms. It's using
the cs42l51 codec and has one mic and one speaker plugs.

Signed-off-by: Arnaud Patard <apatard@mandriva.com>

Index: sound-2.6/sound/soc/kirkwood/Kconfig
===================================================================
--- sound-2.6.orig/sound/soc/kirkwood/Kconfig	2010-05-27 14:09:55.807674540 +0200
+++ sound-2.6/sound/soc/kirkwood/Kconfig	2010-05-27 14:10:03.887694459 +0200
@@ -9,3 +9,12 @@ config SND_KIRKWOOD_SOC
 config SND_KIRKWOOD_SOC_I2S
 	tristate
 
+config SND_KIRKWOOD_SOC_OPENRD
+	tristate "SoC Audio support for Kirkwood Openrd Client"
+	depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT
+	select SND_KIRKWOOD_SOC_I2S
+	select SND_SOC_CS42L51
+	help
+	  Say Y if you want to add support for SoC audio on
+	  Openrd Client.
+
Index: sound-2.6/sound/soc/kirkwood/Makefile
===================================================================
--- sound-2.6.orig/sound/soc/kirkwood/Makefile	2010-05-27 14:09:55.867694480 +0200
+++ sound-2.6/sound/soc/kirkwood/Makefile	2010-05-27 14:10:03.953137222 +0200
@@ -4,3 +4,6 @@ snd-soc-kirkwood-i2s-objs := kirkwood-i2
 obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
 obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
 
+snd-soc-openrd-objs := kirkwood-openrd.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
Index: sound-2.6/sound/soc/kirkwood/kirkwood-openrd.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ sound-2.6/sound/soc/kirkwood/kirkwood-openrd.c	2010-05-27 14:10:03.987735275 +0200
@@ -0,0 +1,126 @@
+/*
+ * kirkwood-openrd.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <mach/kirkwood.h>
+#include <plat/audio.h>
+#include <asm/mach-types.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood-dma.h"
+#include "../codecs/cs42l51.h"
+
+static int openrd_client_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+	unsigned int freq, fmt;
+
+	fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
+	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+	if (ret < 0)
+		return ret;
+
+	switch (params_rate(params)) {
+	default:
+	case 44100:
+		freq = 11289600;
+		break;
+	case 48000:
+		freq = 12288000;
+		break;
+	case 96000:
+		freq = 24576000;
+		break;
+	}
+
+	return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
+
+}
+
+static struct snd_soc_ops openrd_client_ops = {
+	.hw_params = openrd_client_hw_params,
+};
+
+
+static struct snd_soc_dai_link openrd_client_dai[] = {
+{
+	.name = "CS42L51",
+	.stream_name = "CS42L51 HiFi",
+	.cpu_dai = &kirkwood_i2s_dai,
+	.codec_dai = &cs42l51_dai,
+	.ops = &openrd_client_ops,
+},
+};
+
+
+static struct snd_soc_card openrd_client = {
+	.name = "OpenRD Client",
+	.platform = &kirkwood_soc_platform,
+	.dai_link = openrd_client_dai,
+	.num_links = ARRAY_SIZE(openrd_client_dai),
+};
+
+static struct snd_soc_device openrd_client_snd_devdata = {
+	.card = &openrd_client,
+	.codec_dev = &soc_codec_device_cs42l51,
+};
+
+static struct platform_device *openrd_client_snd_device;
+
+static int __init openrd_client_init(void)
+{
+	int ret;
+
+	if (!machine_is_openrd_client())
+		return 0;
+
+	openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!openrd_client_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(openrd_client_snd_device,
+			&openrd_client_snd_devdata);
+	openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+
+	ret = platform_device_add(openrd_client_snd_device);
+	if (ret) {
+		printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
+		platform_device_put(openrd_client_snd_device);
+	}
+
+	return ret;
+}
+
+static void __exit openrd_client_exit(void)
+{
+	platform_device_unregister(openrd_client_snd_device);
+}
+
+module_init(openrd_client_init);
+module_exit(openrd_client_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-audio");

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

* [patch 4/4] kirkwood: Add audio support to openrd client platforms
@ 2010-05-31 11:49         ` apatard at mandriva.com
  0 siblings, 0 replies; 45+ messages in thread
From: apatard at mandriva.com @ 2010-05-31 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

An embedded and charset-unspecified text was scrubbed...
Name: openrd_audio.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100531/cfaaacc9/attachment.el>

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

* Re: [patch 1/4] orion/kirkwood: add audio functions.
  2010-05-31 11:49         ` apatard at mandriva.com
@ 2010-05-31 12:17           ` Mark Brown
  -1 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 12:17 UTC (permalink / raw)
  To: apatard; +Cc: alsa-devel, nico, saeed, tbm, linux-arm-kernel, lrg

On Mon, May 31, 2010 at 01:49:12PM +0200, apatard@mandriva.com wrote:
> This patch add audio related definitions and functions

Applied, thanks.

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

* [patch 1/4] orion/kirkwood: add audio functions.
@ 2010-05-31 12:17           ` Mark Brown
  0 siblings, 0 replies; 45+ messages in thread
From: Mark Brown @ 2010-05-31 12:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 31, 2010 at 01:49:12PM +0200, apatard at mandriva.com wrote:
> This patch add audio related definitions and functions

Applied, thanks.

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

end of thread, other threads:[~2010-05-31 12:17 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-27 12:57 [patch 0/6] kirkwood openrd client audio support - v4 apatard
2010-05-27 12:57 ` apatard at mandriva.com
2010-05-27 12:57 ` [patch 1/6] orion/kirkwood: add audio functions apatard
2010-05-27 12:57   ` apatard at mandriva.com
2010-05-30 20:16   ` Nicolas Pitre
2010-05-30 20:16     ` Nicolas Pitre
2010-05-31 11:14   ` Mark Brown
2010-05-31 11:14     ` Mark Brown
2010-05-31 11:49     ` [patch 0/4] " apatard
2010-05-31 11:49       ` apatard at mandriva.com
2010-05-31 11:49       ` [patch 1/4] " apatard
2010-05-31 11:49         ` apatard at mandriva.com
2010-05-31 12:17         ` Mark Brown
2010-05-31 12:17           ` Mark Brown
2010-05-31 11:49       ` [patch 2/4] openrd-client: initialise audio apatard
2010-05-31 11:49         ` apatard at mandriva.com
2010-05-31 11:49       ` [patch 3/4] kirkwood: Add i2s support apatard
2010-05-31 11:49         ` apatard at mandriva.com
2010-05-31 11:49       ` [patch 4/4] kirkwood: Add audio support to openrd client platforms apatard
2010-05-31 11:49         ` apatard at mandriva.com
2010-05-27 12:57 ` [patch 2/6] openrd-client: initialise audio apatard
2010-05-27 12:57   ` apatard at mandriva.com
2010-05-27 12:57 ` [patch 3/6] soc-dapm.h: add SND_SOC_DAPM_PRE_POST_PMD event apatard
2010-05-27 12:57   ` apatard at mandriva.com
2010-05-31 11:20   ` Mark Brown
2010-05-31 11:20     ` Mark Brown
2010-05-27 12:57 ` [patch 4/6] cs42l51: add asoc driver apatard
2010-05-27 12:57   ` apatard at mandriva.com
2010-05-31 11:20   ` Mark Brown
2010-05-31 11:20     ` Mark Brown
2010-05-27 12:57 ` [patch 5/6] kirkwood: Add i2s support apatard
2010-05-27 12:57   ` apatard at mandriva.com
2010-05-27 12:57 ` [patch 6/6] kirkwood: Add audio support to openrd client platforms apatard
2010-05-27 12:57   ` apatard at mandriva.com
2010-05-30 20:44 ` [patch 0/6] kirkwood openrd client audio support - v4 Nicolas Pitre
2010-05-30 20:44   ` Nicolas Pitre
2010-05-31 10:15 ` Liam Girdwood
2010-05-31 10:15   ` [alsa-devel] " Liam Girdwood
  -- strict thread matches above, loose matches on Subject: below --
2010-05-11 16:23 [patch 0/6] kirkwood openrd client audio support apatard
2010-05-11 16:23 ` [patch 5/6] kirkwood: Add i2s support apatard
2010-05-12 10:24   ` Mark Brown
2010-05-12 10:43     ` Saeed Bishara
2010-05-12 10:48     ` saeed bishara
2010-05-12 10:54       ` Mark Brown
2010-05-12 14:38     ` Arnaud Patard
2010-05-12 14:59       ` Mark Brown

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