All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] ARM: mxs: add audio support
@ 2011-07-08 15:59 ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

This patch series is to add audio support based on saif for mxs platform.
The driver only supports playback currently.
For capturing, due to hardware limitation that we have to use two saif
instances to implement full duplex (playback & recording), we need to
figure out a good design to fit in ASoC as the following work.

In addition, we simply just support master mode since saif tx can
only work in master mode due to hw limitation(rx can work in both
master & slave mode).

Dong Aisheng (10):
  ASoc: mxs: add mxs-pcm driver
  ASoc: mxs: add mxs-saif driver
  ASoc: mxs: add mxs-sgtl5000 machine driver
  ASoc: mxs: add asoc configuration files
  ARM: mxs: add saif clock
  ARM: mxs: add saif device
  ARM: mxs: add sgtl5000 i2c device
  ARM: mxs: add mxs-sgtl5000 device
  ARM: mxs: correct the using of frac div for saif
  ARM: mxs-dma: include <linux/dmaengine.h>

 arch/arm/mach-mxs/Kconfig                       |    1 +
 arch/arm/mach-mxs/clock-mx28.c                  |    8 +-
 arch/arm/mach-mxs/devices-mx28.h                |    7 +
 arch/arm/mach-mxs/devices/Kconfig               |    3 +
 arch/arm/mach-mxs/devices/Makefile              |    1 +
 arch/arm/mach-mxs/devices/platform-mxs-saif.c   |   60 +++
 arch/arm/mach-mxs/include/mach/audio.h          |   18 +
 arch/arm/mach-mxs/include/mach/devices-common.h |   12 +
 arch/arm/mach-mxs/include/mach/dma.h            |    2 +
 arch/arm/mach-mxs/mach-mx28evk.c                |   39 ++
 sound/soc/Kconfig                               |    1 +
 sound/soc/Makefile                              |    1 +
 sound/soc/mxs/Kconfig                           |   20 +
 sound/soc/mxs/Makefile                          |   10 +
 sound/soc/mxs/mxs-pcm.c                         |  377 ++++++++++++++++
 sound/soc/mxs/mxs-pcm.h                         |   43 ++
 sound/soc/mxs/mxs-saif.c                        |  523 +++++++++++++++++++++++
 sound/soc/mxs/mxs-saif.h                        |  132 ++++++
 sound/soc/mxs/mxs-sgtl5000.c                    |  181 ++++++++
 19 files changed, 1437 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-mxs/devices/platform-mxs-saif.c
 create mode 100644 arch/arm/mach-mxs/include/mach/audio.h
 create mode 100644 sound/soc/mxs/Kconfig
 create mode 100644 sound/soc/mxs/Makefile
 create mode 100644 sound/soc/mxs/mxs-pcm.c
 create mode 100644 sound/soc/mxs/mxs-pcm.h
 create mode 100644 sound/soc/mxs/mxs-saif.c
 create mode 100644 sound/soc/mxs/mxs-saif.h
 create mode 100644 sound/soc/mxs/mxs-sgtl5000.c

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

* [PATCH 00/10] ARM: mxs: add audio support
@ 2011-07-08 15:59 ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series is to add audio support based on saif for mxs platform.
The driver only supports playback currently.
For capturing, due to hardware limitation that we have to use two saif
instances to implement full duplex (playback & recording), we need to
figure out a good design to fit in ASoC as the following work.

In addition, we simply just support master mode since saif tx can
only work in master mode due to hw limitation(rx can work in both
master & slave mode).

Dong Aisheng (10):
  ASoc: mxs: add mxs-pcm driver
  ASoc: mxs: add mxs-saif driver
  ASoc: mxs: add mxs-sgtl5000 machine driver
  ASoc: mxs: add asoc configuration files
  ARM: mxs: add saif clock
  ARM: mxs: add saif device
  ARM: mxs: add sgtl5000 i2c device
  ARM: mxs: add mxs-sgtl5000 device
  ARM: mxs: correct the using of frac div for saif
  ARM: mxs-dma: include <linux/dmaengine.h>

 arch/arm/mach-mxs/Kconfig                       |    1 +
 arch/arm/mach-mxs/clock-mx28.c                  |    8 +-
 arch/arm/mach-mxs/devices-mx28.h                |    7 +
 arch/arm/mach-mxs/devices/Kconfig               |    3 +
 arch/arm/mach-mxs/devices/Makefile              |    1 +
 arch/arm/mach-mxs/devices/platform-mxs-saif.c   |   60 +++
 arch/arm/mach-mxs/include/mach/audio.h          |   18 +
 arch/arm/mach-mxs/include/mach/devices-common.h |   12 +
 arch/arm/mach-mxs/include/mach/dma.h            |    2 +
 arch/arm/mach-mxs/mach-mx28evk.c                |   39 ++
 sound/soc/Kconfig                               |    1 +
 sound/soc/Makefile                              |    1 +
 sound/soc/mxs/Kconfig                           |   20 +
 sound/soc/mxs/Makefile                          |   10 +
 sound/soc/mxs/mxs-pcm.c                         |  377 ++++++++++++++++
 sound/soc/mxs/mxs-pcm.h                         |   43 ++
 sound/soc/mxs/mxs-saif.c                        |  523 +++++++++++++++++++++++
 sound/soc/mxs/mxs-saif.h                        |  132 ++++++
 sound/soc/mxs/mxs-sgtl5000.c                    |  181 ++++++++
 19 files changed, 1437 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-mxs/devices/platform-mxs-saif.c
 create mode 100644 arch/arm/mach-mxs/include/mach/audio.h
 create mode 100644 sound/soc/mxs/Kconfig
 create mode 100644 sound/soc/mxs/Makefile
 create mode 100644 sound/soc/mxs/mxs-pcm.c
 create mode 100644 sound/soc/mxs/mxs-pcm.h
 create mode 100644 sound/soc/mxs/mxs-saif.c
 create mode 100644 sound/soc/mxs/mxs-saif.h
 create mode 100644 sound/soc/mxs/mxs-sgtl5000.c

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

* [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 sound/soc/mxs/mxs-pcm.c |  378 +++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/mxs/mxs-pcm.h |   43 ++++++
 2 files changed, 421 insertions(+), 0 deletions(-)

diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
new file mode 100644
index 0000000..32e4e29
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Refer to sound/soc/imx/imx-pcm-dma-mx2.c
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include "mxs-pcm.h"
+
+static struct snd_pcm_hardware snd_mxs_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_PAUSE |
+				  SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S20_3LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192,
+	.periods_min		= 1,
+	.periods_max		= 255,
+	.buffer_bytes_max	= 64 * 1024,
+	.fifo_size		= 32,
+
+};
+
+static void audio_dma_irq(void *data)
+{
+	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	/* FIXME: There's unexpected dma irq before iprtd is initialised */
+	if (iprtd->periods == 0)
+		return;
+
+	iprtd->offset += iprtd->period_bytes;
+	iprtd->offset %= iprtd->period_bytes * iprtd->periods;
+	snd_pcm_period_elapsed(substream);
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct mxs_pcm_runtime_data *iprtd = param;
+	struct mxs_pcm_dma_params *dma_params = iprtd->dma_params;
+
+	if (!mxs_dma_is_apbx(chan))
+		return false;
+
+	if (chan->chan_id != dma_params->chan_num)
+		return false;
+
+	chan->private = &iprtd->dma_data;
+
+	return true;
+}
+
+static int mxs_dma_alloc(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+	dma_cap_mask_t mask;
+
+	iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq;
+	iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
+	if (!iprtd->dma_chan)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+	unsigned long dma_addr;
+	struct dma_chan *chan;
+	int ret;
+
+	ret = mxs_dma_alloc(substream, params);
+	if (ret)
+		return ret;
+	chan = iprtd->dma_chan;
+
+	iprtd->size = params_buffer_bytes(params);
+	iprtd->periods = params_periods(params);
+	iprtd->period_bytes = params_period_bytes(params);
+	iprtd->offset = 0;
+	iprtd->period_time = HZ / (params_rate(params) /
+			params_period_size(params));
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	dma_addr = runtime->dma_addr;
+
+	iprtd->buf = (unsigned int *)substream->dma_buffer.area;
+
+	iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
+			iprtd->period_bytes * iprtd->periods,
+			iprtd->period_bytes,
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	if (!iprtd->desc) {
+		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+		return -EINVAL;
+	}
+
+	iprtd->desc->callback = audio_dma_irq;
+	iprtd->desc->callback_param = substream;
+
+	return 0;
+}
+
+static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	if (iprtd->dma_chan) {
+		dma_release_channel(iprtd->dma_chan);
+		iprtd->dma_chan = NULL;
+	}
+
+	return 0;
+}
+
+static int snd_mxs_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dmaengine_submit(iprtd->desc);
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		dmaengine_terminate_all(iprtd->dma_chan);
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_mxs_pcm_pointer(
+		struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	pr_debug("%s: %ld %ld\n", __func__, iprtd->offset,
+			bytes_to_frames(substream->runtime, iprtd->offset));
+
+	return bytes_to_frames(substream->runtime, iprtd->offset);
+}
+
+static int snd_mxs_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd;
+	int ret;
+
+	iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
+	if (iprtd == NULL)
+		return -ENOMEM;
+	runtime->private_data = iprtd;
+
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		kfree(iprtd);
+		return ret;
+	}
+
+	snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
+
+	return 0;
+}
+
+static int snd_mxs_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	kfree(iprtd);
+
+	return 0;
+}
+
+static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
+		struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
+			runtime->dma_addr, runtime->dma_bytes);
+
+	pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+			runtime->dma_area,
+			runtime->dma_addr,
+			runtime->dma_bytes);
+	return ret;
+}
+
+static struct snd_pcm_ops mxs_pcm_ops = {
+	.open		= snd_mxs_open,
+	.close		= snd_mxs_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_mxs_pcm_hw_params,
+	.hw_free	= snd_mxs_pcm_hw_free,
+	.prepare	= snd_mxs_pcm_prepare,
+	.trigger	= snd_mxs_pcm_trigger,
+	.pointer	= snd_mxs_pcm_pointer,
+	.mmap		= snd_mxs_pcm_mmap,
+};
+
+static int mxs_pcm_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 = 64 * 1024;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+
+	return 0;
+}
+
+static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32);
+static int mxs_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+	struct snd_pcm *pcm)
+{
+
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &mxs_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	if (dai->driver->playback.channels_min) {
+		ret = mxs_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->driver->capture.channels_min) {
+		ret = mxs_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+
+out:
+	return ret;
+}
+
+static void mxs_pcm_free(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_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static struct snd_soc_platform_driver mxs_soc_platform = {
+	.ops		= &mxs_pcm_ops,
+	.pcm_new	= mxs_pcm_new,
+	.pcm_free	= mxs_pcm_free,
+};
+
+static int __devinit mxs_soc_platform_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform);
+}
+
+static int __devexit mxs_soc_platform_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver mxs_pcm_driver = {
+	.driver = {
+			.name = "mxs-pcm-audio",
+			.owner = THIS_MODULE,
+	},
+	.probe = mxs_soc_platform_probe,
+	.remove = __devexit_p(mxs_soc_platform_remove),
+};
+
+static int __init snd_mxs_pcm_init(void)
+{
+	return platform_driver_register(&mxs_pcm_driver);
+}
+module_init(snd_mxs_pcm_init);
+
+static void __exit snd_mxs_pcm_exit(void)
+{
+	platform_driver_unregister(&mxs_pcm_driver);
+}
+module_exit(snd_mxs_pcm_exit);
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
new file mode 100644
index 0000000..f55ac4f
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MXS_PCM_H
+#define _MXS_PCM_H
+
+#include <mach/dma.h>
+
+struct mxs_pcm_dma_params {
+	int chan_irq;
+	int chan_num;
+};
+
+struct mxs_pcm_runtime_data {
+	int period_bytes;
+	int periods;
+	int dma;
+	unsigned long offset;
+	unsigned long size;
+	void *buf;
+	int period_time;
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *dma_chan;
+	struct mxs_dma_data dma_data;
+	struct mxs_pcm_dma_params *dma_params;
+};
+
+#endif
-- 
1.7.0.4

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

* [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 sound/soc/mxs/mxs-pcm.c |  378 +++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/mxs/mxs-pcm.h |   43 ++++++
 2 files changed, 421 insertions(+), 0 deletions(-)

diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
new file mode 100644
index 0000000..32e4e29
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Refer to sound/soc/imx/imx-pcm-dma-mx2.c
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include "mxs-pcm.h"
+
+static struct snd_pcm_hardware snd_mxs_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_PAUSE |
+				  SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_INTERLEAVED,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S20_3LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192,
+	.periods_min		= 1,
+	.periods_max		= 255,
+	.buffer_bytes_max	= 64 * 1024,
+	.fifo_size		= 32,
+
+};
+
+static void audio_dma_irq(void *data)
+{
+	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	/* FIXME: There's unexpected dma irq before iprtd is initialised */
+	if (iprtd->periods == 0)
+		return;
+
+	iprtd->offset += iprtd->period_bytes;
+	iprtd->offset %= iprtd->period_bytes * iprtd->periods;
+	snd_pcm_period_elapsed(substream);
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct mxs_pcm_runtime_data *iprtd = param;
+	struct mxs_pcm_dma_params *dma_params = iprtd->dma_params;
+
+	if (!mxs_dma_is_apbx(chan))
+		return false;
+
+	if (chan->chan_id != dma_params->chan_num)
+		return false;
+
+	chan->private = &iprtd->dma_data;
+
+	return true;
+}
+
+static int mxs_dma_alloc(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+	dma_cap_mask_t mask;
+
+	iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq;
+	iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
+	if (!iprtd->dma_chan)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+	unsigned long dma_addr;
+	struct dma_chan *chan;
+	int ret;
+
+	ret = mxs_dma_alloc(substream, params);
+	if (ret)
+		return ret;
+	chan = iprtd->dma_chan;
+
+	iprtd->size = params_buffer_bytes(params);
+	iprtd->periods = params_periods(params);
+	iprtd->period_bytes = params_period_bytes(params);
+	iprtd->offset = 0;
+	iprtd->period_time = HZ / (params_rate(params) /
+			params_period_size(params));
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	dma_addr = runtime->dma_addr;
+
+	iprtd->buf = (unsigned int *)substream->dma_buffer.area;
+
+	iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
+			iprtd->period_bytes * iprtd->periods,
+			iprtd->period_bytes,
+			substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	if (!iprtd->desc) {
+		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+		return -EINVAL;
+	}
+
+	iprtd->desc->callback = audio_dma_irq;
+	iprtd->desc->callback_param = substream;
+
+	return 0;
+}
+
+static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	if (iprtd->dma_chan) {
+		dma_release_channel(iprtd->dma_chan);
+		iprtd->dma_chan = NULL;
+	}
+
+	return 0;
+}
+
+static int snd_mxs_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dmaengine_submit(iprtd->desc);
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		dmaengine_terminate_all(iprtd->dma_chan);
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_mxs_pcm_pointer(
+		struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	pr_debug("%s: %ld %ld\n", __func__, iprtd->offset,
+			bytes_to_frames(substream->runtime, iprtd->offset));
+
+	return bytes_to_frames(substream->runtime, iprtd->offset);
+}
+
+static int snd_mxs_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd;
+	int ret;
+
+	iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
+	if (iprtd == NULL)
+		return -ENOMEM;
+	runtime->private_data = iprtd;
+
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0) {
+		kfree(iprtd);
+		return ret;
+	}
+
+	snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
+
+	return 0;
+}
+
+static int snd_mxs_close(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
+
+	kfree(iprtd);
+
+	return 0;
+}
+
+static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
+		struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
+			runtime->dma_addr, runtime->dma_bytes);
+
+	pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+			runtime->dma_area,
+			runtime->dma_addr,
+			runtime->dma_bytes);
+	return ret;
+}
+
+static struct snd_pcm_ops mxs_pcm_ops = {
+	.open		= snd_mxs_open,
+	.close		= snd_mxs_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_mxs_pcm_hw_params,
+	.hw_free	= snd_mxs_pcm_hw_free,
+	.prepare	= snd_mxs_pcm_prepare,
+	.trigger	= snd_mxs_pcm_trigger,
+	.pointer	= snd_mxs_pcm_pointer,
+	.mmap		= snd_mxs_pcm_mmap,
+};
+
+static int mxs_pcm_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 = 64 * 1024;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+
+	return 0;
+}
+
+static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32);
+static int mxs_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+	struct snd_pcm *pcm)
+{
+
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &mxs_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	if (dai->driver->playback.channels_min) {
+		ret = mxs_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (dai->driver->capture.channels_min) {
+		ret = mxs_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+
+out:
+	return ret;
+}
+
+static void mxs_pcm_free(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_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static struct snd_soc_platform_driver mxs_soc_platform = {
+	.ops		= &mxs_pcm_ops,
+	.pcm_new	= mxs_pcm_new,
+	.pcm_free	= mxs_pcm_free,
+};
+
+static int __devinit mxs_soc_platform_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform);
+}
+
+static int __devexit mxs_soc_platform_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver mxs_pcm_driver = {
+	.driver = {
+			.name = "mxs-pcm-audio",
+			.owner = THIS_MODULE,
+	},
+	.probe = mxs_soc_platform_probe,
+	.remove = __devexit_p(mxs_soc_platform_remove),
+};
+
+static int __init snd_mxs_pcm_init(void)
+{
+	return platform_driver_register(&mxs_pcm_driver);
+}
+module_init(snd_mxs_pcm_init);
+
+static void __exit snd_mxs_pcm_exit(void)
+{
+	platform_driver_unregister(&mxs_pcm_driver);
+}
+module_exit(snd_mxs_pcm_exit);
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
new file mode 100644
index 0000000..f55ac4f
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _MXS_PCM_H
+#define _MXS_PCM_H
+
+#include <mach/dma.h>
+
+struct mxs_pcm_dma_params {
+	int chan_irq;
+	int chan_num;
+};
+
+struct mxs_pcm_runtime_data {
+	int period_bytes;
+	int periods;
+	int dma;
+	unsigned long offset;
+	unsigned long size;
+	void *buf;
+	int period_time;
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan *dma_chan;
+	struct mxs_dma_data dma_data;
+	struct mxs_pcm_dma_params *dma_params;
+};
+
+#endif
-- 
1.7.0.4

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 sound/soc/mxs/mxs-saif.c |  524 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/mxs/mxs-saif.h |  124 +++++++++++
 2 files changed, 648 insertions(+), 0 deletions(-)

diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
new file mode 100644
index 0000000..afc6e57
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/dma.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/mx28.h>
+
+#include "mxs-saif.h"
+
+/*
+* SAIF system clock configuration.
+* Should only be called when port is inactive.
+*/
+static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+			int clk_id, unsigned int freq, int dir)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	switch (clk_id) {
+	case MXS_SAIF_SYS_CLK:
+		clk_set_rate(saif->clk, freq);
+		clk_enable(saif->clk);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * SAIF Clock dividers
+ * Should only be called when port is inactive.
+ */
+static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+				  int div_id, int div)
+{
+	u32 scr;
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	scr = __raw_readl(saif->base + SAIF_CTRL);
+	scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
+	scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+
+	switch (div_id) {
+	case MXS_SAIF_MCLK:
+		switch (div) {
+		case 32:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 64:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 128:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 256:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 512:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 48:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 96:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 192:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 384:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	__raw_writel(scr, saif->base + SAIF_CTRL);
+
+	return 0;
+}
+
+/*
+ * SAIF DAI format configuration.
+ * Should only be called when port is inactive.
+ * Note: We don't use the I2S modes but instead manually configure the
+ * SAIF for I2S.
+ */
+static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	u32 scr, stat;
+	u32 scr0;
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	stat = __raw_readl(saif->base + SAIF_STAT);
+	if (stat & BM_SAIF_STAT_BUSY)
+		return 0;
+
+	scr0 = __raw_readl(saif->base + SAIF_CTRL);
+	scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
+		& ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
+	scr = 0;
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* data frame low 1clk before data */
+		scr |= BM_SAIF_CTRL_DELAY;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		/* data frame high with data */
+		scr &= ~BM_SAIF_CTRL_DELAY;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		scr &= ~BM_SAIF_CTRL_JUSTIFY;
+		break;
+	}
+
+	/* DAI clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
+		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
+		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	}
+
+	/*
+	 * Note: We simply just support master mode since SAIF TX only supports
+	 * master mode.
+	 */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
+		__raw_writel(scr | scr0, saif->base + SAIF_CTRL);
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+static int mxs_saif_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+	snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
+
+	return 0;
+}
+
+/*
+ * Should only be called when port is inactive.
+ * although can be called multiple times by upper layers.
+ */
+static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 scr;
+
+	scr = __raw_readl(saif->base + SAIF_CTRL);
+
+	/* cant change any parameters when SAIF is running */
+	/* DAI data (word) size */
+	scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
+	scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
+		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
+		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+		break;
+	}
+
+	/* Tx/Rx config */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* enable TX mode */
+		scr &= ~BM_SAIF_CTRL_READ_MODE;
+	} else {
+		/* enable RX mode */
+		scr |= BM_SAIF_CTRL_READ_MODE;
+	}
+
+	__raw_writel(scr, saif->base + SAIF_CTRL);
+	return 0;
+}
+
+static int mxs_saif_prepare(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+	__raw_writel(BM_SAIF_CTRL_CLKGATE,
+		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+	return 0;
+}
+
+static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			/*write a data to saif data register to trigger
+				the transfer*/
+			__raw_writel(0, saif->base + SAIF_DATA);
+		else
+			/*read a data from saif data register to trigger
+				the receive*/
+			__raw_readl(saif->base + SAIF_DATA);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define MXS_SAIF_RATES		SNDRV_PCM_RATE_8000_192000
+#define MXS_SAIF_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops mxs_saif_dai_ops = {
+	.startup = mxs_saif_startup,
+	.trigger = mxs_saif_trigger,
+	.prepare = mxs_saif_prepare,
+	.hw_params = mxs_saif_hw_params,
+	.set_sysclk = mxs_saif_set_dai_sysclk,
+	.set_clkdiv = mxs_saif_set_dai_clkdiv,
+	.set_fmt = mxs_saif_set_dai_fmt,
+};
+
+static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct mxs_saif *saif = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, saif);
+
+	/* Reset */
+	__raw_writel(BM_SAIF_CTRL_SFTRST,
+		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+	/* enable MCLK output early since codec may need it */
+	__raw_writel(BM_SAIF_CTRL_CLKGATE,
+		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+	__raw_writel(BM_SAIF_CTRL_RUN,
+		saif->base + SAIF_CTRL + MXS_SET_ADDR);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver mxs_saif_dai = {
+	.name = "mxs-saif",
+	.probe = mxs_saif_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = MXS_SAIF_RATES,
+		.formats = MXS_SAIF_FORMATS,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = MXS_SAIF_RATES,
+		.formats = MXS_SAIF_FORMATS,
+	},
+	.ops = &mxs_saif_dai_ops,
+};
+
+static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
+{
+	struct mxs_saif *saif = dev_id;
+
+	if (saif->fifo_err_counter++ % 100 == 0)
+		printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
+			fifo_errs=%d \n",
+		       __raw_readl(saif->base + SAIF_STAT),
+		       __raw_readl(saif->base + SAIF_CTRL),
+		       saif->fifo_err_counter);
+	__raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
+			BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
+			saif->base + SAIF_STAT + MXS_CLR_ADDR);
+
+	return IRQ_HANDLED;
+}
+
+static int mxs_saif_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct mxs_saif *saif;
+	int ret = 0;
+
+	saif = kzalloc(sizeof(*saif), GFP_KERNEL);
+	if (!saif)
+		return -ENOMEM;
+
+	saif->irq = platform_get_irq(pdev, 0);
+	if (saif->irq < 0) {
+		ret = saif->irq;
+		dev_err(&pdev->dev, "failed to get irq resource: %d\n",
+			ret);
+		goto failed_get_irq1;
+	}
+
+	saif->fifo_err_counter = 0;
+	ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		goto failed_req_irq;
+	}
+
+	saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
+	if (saif->dma_param.chan_irq < 0) {
+		ret = saif->dma_param.chan_irq;
+		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
+			ret);
+		goto failed_get_irq2;
+	}
+
+	saif->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(saif->clk)) {
+		ret = PTR_ERR(saif->clk);
+		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
+			ret);
+		goto failed_clk;
+	}
+	clk_set_rate(saif->clk, 12000000);
+	clk_enable(saif->clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "failed to get io resource: %d\n",
+			ret);
+		goto failed_get_resource;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) {
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		ret = -EBUSY;
+		goto failed_get_resource;
+	}
+
+	saif->base = ioremap(res->start, resource_size(res));
+	if (!saif->base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENODEV;
+		goto failed_ioremap;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "failed to get dma resource: %d\n",
+			ret);
+		goto failed_get_resource;
+	}
+	saif->dma_param.chan_num = res->start;
+
+	platform_set_drvdata(pdev, saif);
+
+	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
+	if (ret) {
+		dev_err(&pdev->dev, "register DAI failed\n");
+		goto failed_register;
+	}
+
+	saif->soc_platform_pdev = platform_device_alloc(
+					"mxs-pcm-audio", pdev->id);
+	if (!saif->soc_platform_pdev) {
+		ret = -ENOMEM;
+		goto failed_pdev_alloc;
+	}
+
+	platform_set_drvdata(saif->soc_platform_pdev, saif);
+	ret = platform_device_add(saif->soc_platform_pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add soc platform device\n");
+		goto failed_pdev_add;
+	}
+
+	return 0;
+
+failed_pdev_add:
+	platform_device_put(saif->soc_platform_pdev);
+failed_pdev_alloc:
+	snd_soc_unregister_dai(&pdev->dev);
+failed_register:
+	iounmap(saif->base);
+failed_ioremap:
+	release_mem_region(res->start, resource_size(res));
+failed_get_resource:
+	clk_disable(saif->clk);
+	clk_put(saif->clk);
+failed_clk:
+failed_get_irq2:
+	free_irq(saif->irq, saif);
+failed_req_irq:
+failed_get_irq1:
+	kfree(saif);
+
+	return ret;
+}
+
+static int __devexit mxs_saif_remove(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct mxs_saif *saif = platform_get_drvdata(pdev);
+
+	platform_device_unregister(saif->soc_platform_pdev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+
+	iounmap(saif->base);
+	release_mem_region(res->start, resource_size(res));
+	free_irq(saif->irq, saif);
+
+	clk_disable(saif->clk);
+	clk_put(saif->clk);
+
+	kfree(saif);
+
+	return 0;
+}
+
+static struct platform_driver mxs_saif_driver = {
+	.probe = mxs_saif_probe,
+	.remove = __devexit_p(mxs_saif_remove),
+
+	.driver = {
+		.name = "mxs-saif",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mxs_saif_init(void)
+{
+	return platform_driver_register(&mxs_saif_driver);
+}
+
+static void __exit mxs_saif_exit(void)
+{
+	platform_driver_unregister(&mxs_saif_driver);
+}
+
+module_init(mxs_saif_init);
+module_exit(mxs_saif_exit);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXS ASoC SAIF driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
new file mode 100644
index 0000000..dd26b37
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef _MXS_SAIF_H
+#define _MXS_SAIF_H
+
+#define SAIF_CTRL	0x0
+#define SAIF_STAT	0x10
+#define SAIF_DATA	0x20
+#define SAIF_VERSION	0X30
+
+/* SAIF_CTRL */
+#define BM_SAIF_CTRL_SFTRST		0x80000000
+#define BM_SAIF_CTRL_CLKGATE		0x40000000
+#define BP_SAIF_CTRL_BITCLK_MULT_RATE	27
+#define BM_SAIF_CTRL_BITCLK_MULT_RATE	0x38000000
+#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
+		(((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
+#define BM_SAIF_CTRL_BITCLK_BASE_RATE	0x04000000
+#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN	0x02000000
+#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN	0x01000000
+#define BP_SAIF_CTRL_RSRVD2		21
+#define BM_SAIF_CTRL_RSRVD2		0x00E00000
+
+#define BP_SAIF_CTRL_DMAWAIT_COUNT	16
+#define BM_SAIF_CTRL_DMAWAIT_COUNT	0x001F0000
+#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
+		(((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
+#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
+#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
+#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
+		(((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
+#define BM_SAIF_CTRL_LRCLK_PULSE	0x00002000
+#define BM_SAIF_CTRL_BIT_ORDER		0x00001000
+#define BM_SAIF_CTRL_DELAY		0x00000800
+#define BM_SAIF_CTRL_JUSTIFY		0x00000400
+#define BM_SAIF_CTRL_LRCLK_POLARITY	0x00000200
+#define BM_SAIF_CTRL_BITCLK_EDGE	0x00000100
+#define BP_SAIF_CTRL_WORD_LENGTH	4
+#define BM_SAIF_CTRL_WORD_LENGTH	0x000000F0
+#define BF_SAIF_CTRL_WORD_LENGTH(v) \
+		(((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
+#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE	0x00000008
+#define BM_SAIF_CTRL_SLAVE_MODE		0x00000004
+#define BM_SAIF_CTRL_READ_MODE		0x00000002
+#define BM_SAIF_CTRL_RUN		0x00000001
+
+/* SAIF_STAT */
+#define BM_SAIF_STAT_PRESENT		0x80000000
+#define BP_SAIF_STAT_RSRVD2		17
+#define BM_SAIF_STAT_RSRVD2		0x7FFE0000
+#define BF_SAIF_STAT_RSRVD2(v) \
+		(((v) << 17) & BM_SAIF_STAT_RSRVD2)
+#define BM_SAIF_STAT_DMA_PREQ		0x00010000
+#define BP_SAIF_STAT_RSRVD1		7
+#define BM_SAIF_STAT_RSRVD1		0x0000FF80
+#define BF_SAIF_STAT_RSRVD1(v) \
+		(((v) << 7) & BM_SAIF_STAT_RSRVD1)
+
+#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
+#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ	0x00000020
+#define BM_SAIF_STAT_FIFO_SERVICE_IRQ	0x00000010
+#define BP_SAIF_STAT_RSRVD0		1
+#define BM_SAIF_STAT_RSRVD0		0x0000000E
+#define BF_SAIF_STAT_RSRVD0(v) \
+		(((v) << 1) & BM_SAIF_STAT_RSRVD0)
+#define BM_SAIF_STAT_BUSY		0x00000001
+
+/* SAFI_DATA */
+#define BP_SAIF_DATA_PCM_RIGHT		16
+#define BM_SAIF_DATA_PCM_RIGHT		0xFFFF0000
+#define BF_SAIF_DATA_PCM_RIGHT(v) \
+		(((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
+#define BP_SAIF_DATA_PCM_LEFT		0
+#define BM_SAIF_DATA_PCM_LEFT		0x0000FFFF
+#define BF_SAIF_DATA_PCM_LEFT(v)	\
+		(((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
+
+/* SAIF_VERSION */
+#define BP_SAIF_VERSION_MAJOR		24
+#define BM_SAIF_VERSION_MAJOR		0xFF000000
+#define BF_SAIF_VERSION_MAJOR(v) \
+		(((v) << 24) & BM_SAIF_VERSION_MAJOR)
+#define BP_SAIF_VERSION_MINOR		16
+#define BM_SAIF_VERSION_MINOR		0x00FF0000
+#define BF_SAIF_VERSION_MINOR(v) \
+		(((v) << 16) & BM_SAIF_VERSION_MINOR)
+#define BP_SAIF_VERSION_STEP		0
+#define BM_SAIF_VERSION_STEP		0x0000FFFF
+#define BF_SAIF_VERSION_STEP(v) \
+		(((v) << 0) & BM_SAIF_VERSION_STEP)
+
+#define MXS_SAIF_SYS_CLK	0
+#define MXS_SAIF_MCLK		1
+
+#include "mxs-pcm.h"
+
+struct mxs_saif {
+	struct clk *clk;
+	void __iomem *base;
+	int irq;
+	struct mxs_pcm_dma_params dma_param;
+
+	struct platform_device *soc_platform_pdev;
+	u32 fifo_err_counter;
+};
+
+#endif
-- 
1.7.0.4

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 sound/soc/mxs/mxs-saif.c |  524 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/mxs/mxs-saif.h |  124 +++++++++++
 2 files changed, 648 insertions(+), 0 deletions(-)

diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
new file mode 100644
index 0000000..afc6e57
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/dma.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/mx28.h>
+
+#include "mxs-saif.h"
+
+/*
+* SAIF system clock configuration.
+* Should only be called when port is inactive.
+*/
+static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+			int clk_id, unsigned int freq, int dir)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	switch (clk_id) {
+	case MXS_SAIF_SYS_CLK:
+		clk_set_rate(saif->clk, freq);
+		clk_enable(saif->clk);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * SAIF Clock dividers
+ * Should only be called when port is inactive.
+ */
+static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+				  int div_id, int div)
+{
+	u32 scr;
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	scr = __raw_readl(saif->base + SAIF_CTRL);
+	scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
+	scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+
+	switch (div_id) {
+	case MXS_SAIF_MCLK:
+		switch (div) {
+		case 32:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 64:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 128:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 256:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 512:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
+			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 48:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 96:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 192:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		case 384:
+			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
+			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	__raw_writel(scr, saif->base + SAIF_CTRL);
+
+	return 0;
+}
+
+/*
+ * SAIF DAI format configuration.
+ * Should only be called when port is inactive.
+ * Note: We don't use the I2S modes but instead manually configure the
+ * SAIF for I2S.
+ */
+static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	u32 scr, stat;
+	u32 scr0;
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	stat = __raw_readl(saif->base + SAIF_STAT);
+	if (stat & BM_SAIF_STAT_BUSY)
+		return 0;
+
+	scr0 = __raw_readl(saif->base + SAIF_CTRL);
+	scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
+		& ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
+	scr = 0;
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* data frame low 1clk before data */
+		scr |= BM_SAIF_CTRL_DELAY;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		/* data frame high with data */
+		scr &= ~BM_SAIF_CTRL_DELAY;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		scr &= ~BM_SAIF_CTRL_JUSTIFY;
+		break;
+	}
+
+	/* DAI clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_IB_IF:
+		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
+		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
+		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
+		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
+		break;
+	}
+
+	/*
+	 * Note: We simply just support master mode since SAIF TX only supports
+	 * master mode.
+	 */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
+		__raw_writel(scr | scr0, saif->base + SAIF_CTRL);
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+static int mxs_saif_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+	snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
+
+	return 0;
+}
+
+/*
+ * Should only be called when port is inactive.
+ * although can be called multiple times by upper layers.
+ */
+static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+	u32 scr;
+
+	scr = __raw_readl(saif->base + SAIF_CTRL);
+
+	/* cant change any parameters when SAIF is running */
+	/* DAI data (word) size */
+	scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
+	scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
+		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
+		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
+		break;
+	}
+
+	/* Tx/Rx config */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		/* enable TX mode */
+		scr &= ~BM_SAIF_CTRL_READ_MODE;
+	} else {
+		/* enable RX mode */
+		scr |= BM_SAIF_CTRL_READ_MODE;
+	}
+
+	__raw_writel(scr, saif->base + SAIF_CTRL);
+	return 0;
+}
+
+static int mxs_saif_prepare(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+	__raw_writel(BM_SAIF_CTRL_CLKGATE,
+		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+	return 0;
+}
+
+static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *cpu_dai)
+{
+	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			/*write a data to saif data register to trigger
+				the transfer*/
+			__raw_writel(0, saif->base + SAIF_DATA);
+		else
+			/*read a data from saif data register to trigger
+				the receive*/
+			__raw_readl(saif->base + SAIF_DATA);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#define MXS_SAIF_RATES		SNDRV_PCM_RATE_8000_192000
+#define MXS_SAIF_FORMATS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops mxs_saif_dai_ops = {
+	.startup = mxs_saif_startup,
+	.trigger = mxs_saif_trigger,
+	.prepare = mxs_saif_prepare,
+	.hw_params = mxs_saif_hw_params,
+	.set_sysclk = mxs_saif_set_dai_sysclk,
+	.set_clkdiv = mxs_saif_set_dai_clkdiv,
+	.set_fmt = mxs_saif_set_dai_fmt,
+};
+
+static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct mxs_saif *saif = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, saif);
+
+	/* Reset */
+	__raw_writel(BM_SAIF_CTRL_SFTRST,
+		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+
+	/* enable MCLK output early since codec may need it */
+	__raw_writel(BM_SAIF_CTRL_CLKGATE,
+		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+	__raw_writel(BM_SAIF_CTRL_RUN,
+		saif->base + SAIF_CTRL + MXS_SET_ADDR);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver mxs_saif_dai = {
+	.name = "mxs-saif",
+	.probe = mxs_saif_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = MXS_SAIF_RATES,
+		.formats = MXS_SAIF_FORMATS,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = MXS_SAIF_RATES,
+		.formats = MXS_SAIF_FORMATS,
+	},
+	.ops = &mxs_saif_dai_ops,
+};
+
+static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
+{
+	struct mxs_saif *saif = dev_id;
+
+	if (saif->fifo_err_counter++ % 100 == 0)
+		printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
+			fifo_errs=%d \n",
+		       __raw_readl(saif->base + SAIF_STAT),
+		       __raw_readl(saif->base + SAIF_CTRL),
+		       saif->fifo_err_counter);
+	__raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
+			BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
+			saif->base + SAIF_STAT + MXS_CLR_ADDR);
+
+	return IRQ_HANDLED;
+}
+
+static int mxs_saif_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct mxs_saif *saif;
+	int ret = 0;
+
+	saif = kzalloc(sizeof(*saif), GFP_KERNEL);
+	if (!saif)
+		return -ENOMEM;
+
+	saif->irq = platform_get_irq(pdev, 0);
+	if (saif->irq < 0) {
+		ret = saif->irq;
+		dev_err(&pdev->dev, "failed to get irq resource: %d\n",
+			ret);
+		goto failed_get_irq1;
+	}
+
+	saif->fifo_err_counter = 0;
+	ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		goto failed_req_irq;
+	}
+
+	saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
+	if (saif->dma_param.chan_irq < 0) {
+		ret = saif->dma_param.chan_irq;
+		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
+			ret);
+		goto failed_get_irq2;
+	}
+
+	saif->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(saif->clk)) {
+		ret = PTR_ERR(saif->clk);
+		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
+			ret);
+		goto failed_clk;
+	}
+	clk_set_rate(saif->clk, 12000000);
+	clk_enable(saif->clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "failed to get io resource: %d\n",
+			ret);
+		goto failed_get_resource;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) {
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		ret = -EBUSY;
+		goto failed_get_resource;
+	}
+
+	saif->base = ioremap(res->start, resource_size(res));
+	if (!saif->base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENODEV;
+		goto failed_ioremap;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "failed to get dma resource: %d\n",
+			ret);
+		goto failed_get_resource;
+	}
+	saif->dma_param.chan_num = res->start;
+
+	platform_set_drvdata(pdev, saif);
+
+	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
+	if (ret) {
+		dev_err(&pdev->dev, "register DAI failed\n");
+		goto failed_register;
+	}
+
+	saif->soc_platform_pdev = platform_device_alloc(
+					"mxs-pcm-audio", pdev->id);
+	if (!saif->soc_platform_pdev) {
+		ret = -ENOMEM;
+		goto failed_pdev_alloc;
+	}
+
+	platform_set_drvdata(saif->soc_platform_pdev, saif);
+	ret = platform_device_add(saif->soc_platform_pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add soc platform device\n");
+		goto failed_pdev_add;
+	}
+
+	return 0;
+
+failed_pdev_add:
+	platform_device_put(saif->soc_platform_pdev);
+failed_pdev_alloc:
+	snd_soc_unregister_dai(&pdev->dev);
+failed_register:
+	iounmap(saif->base);
+failed_ioremap:
+	release_mem_region(res->start, resource_size(res));
+failed_get_resource:
+	clk_disable(saif->clk);
+	clk_put(saif->clk);
+failed_clk:
+failed_get_irq2:
+	free_irq(saif->irq, saif);
+failed_req_irq:
+failed_get_irq1:
+	kfree(saif);
+
+	return ret;
+}
+
+static int __devexit mxs_saif_remove(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct mxs_saif *saif = platform_get_drvdata(pdev);
+
+	platform_device_unregister(saif->soc_platform_pdev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+
+	iounmap(saif->base);
+	release_mem_region(res->start, resource_size(res));
+	free_irq(saif->irq, saif);
+
+	clk_disable(saif->clk);
+	clk_put(saif->clk);
+
+	kfree(saif);
+
+	return 0;
+}
+
+static struct platform_driver mxs_saif_driver = {
+	.probe = mxs_saif_probe,
+	.remove = __devexit_p(mxs_saif_remove),
+
+	.driver = {
+		.name = "mxs-saif",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mxs_saif_init(void)
+{
+	return platform_driver_register(&mxs_saif_driver);
+}
+
+static void __exit mxs_saif_exit(void)
+{
+	platform_driver_unregister(&mxs_saif_driver);
+}
+
+module_init(mxs_saif_init);
+module_exit(mxs_saif_exit);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXS ASoC SAIF driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
new file mode 100644
index 0000000..dd26b37
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef _MXS_SAIF_H
+#define _MXS_SAIF_H
+
+#define SAIF_CTRL	0x0
+#define SAIF_STAT	0x10
+#define SAIF_DATA	0x20
+#define SAIF_VERSION	0X30
+
+/* SAIF_CTRL */
+#define BM_SAIF_CTRL_SFTRST		0x80000000
+#define BM_SAIF_CTRL_CLKGATE		0x40000000
+#define BP_SAIF_CTRL_BITCLK_MULT_RATE	27
+#define BM_SAIF_CTRL_BITCLK_MULT_RATE	0x38000000
+#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
+		(((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
+#define BM_SAIF_CTRL_BITCLK_BASE_RATE	0x04000000
+#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN	0x02000000
+#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN	0x01000000
+#define BP_SAIF_CTRL_RSRVD2		21
+#define BM_SAIF_CTRL_RSRVD2		0x00E00000
+
+#define BP_SAIF_CTRL_DMAWAIT_COUNT	16
+#define BM_SAIF_CTRL_DMAWAIT_COUNT	0x001F0000
+#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
+		(((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
+#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
+#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
+#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
+		(((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
+#define BM_SAIF_CTRL_LRCLK_PULSE	0x00002000
+#define BM_SAIF_CTRL_BIT_ORDER		0x00001000
+#define BM_SAIF_CTRL_DELAY		0x00000800
+#define BM_SAIF_CTRL_JUSTIFY		0x00000400
+#define BM_SAIF_CTRL_LRCLK_POLARITY	0x00000200
+#define BM_SAIF_CTRL_BITCLK_EDGE	0x00000100
+#define BP_SAIF_CTRL_WORD_LENGTH	4
+#define BM_SAIF_CTRL_WORD_LENGTH	0x000000F0
+#define BF_SAIF_CTRL_WORD_LENGTH(v) \
+		(((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
+#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE	0x00000008
+#define BM_SAIF_CTRL_SLAVE_MODE		0x00000004
+#define BM_SAIF_CTRL_READ_MODE		0x00000002
+#define BM_SAIF_CTRL_RUN		0x00000001
+
+/* SAIF_STAT */
+#define BM_SAIF_STAT_PRESENT		0x80000000
+#define BP_SAIF_STAT_RSRVD2		17
+#define BM_SAIF_STAT_RSRVD2		0x7FFE0000
+#define BF_SAIF_STAT_RSRVD2(v) \
+		(((v) << 17) & BM_SAIF_STAT_RSRVD2)
+#define BM_SAIF_STAT_DMA_PREQ		0x00010000
+#define BP_SAIF_STAT_RSRVD1		7
+#define BM_SAIF_STAT_RSRVD1		0x0000FF80
+#define BF_SAIF_STAT_RSRVD1(v) \
+		(((v) << 7) & BM_SAIF_STAT_RSRVD1)
+
+#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
+#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ	0x00000020
+#define BM_SAIF_STAT_FIFO_SERVICE_IRQ	0x00000010
+#define BP_SAIF_STAT_RSRVD0		1
+#define BM_SAIF_STAT_RSRVD0		0x0000000E
+#define BF_SAIF_STAT_RSRVD0(v) \
+		(((v) << 1) & BM_SAIF_STAT_RSRVD0)
+#define BM_SAIF_STAT_BUSY		0x00000001
+
+/* SAFI_DATA */
+#define BP_SAIF_DATA_PCM_RIGHT		16
+#define BM_SAIF_DATA_PCM_RIGHT		0xFFFF0000
+#define BF_SAIF_DATA_PCM_RIGHT(v) \
+		(((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
+#define BP_SAIF_DATA_PCM_LEFT		0
+#define BM_SAIF_DATA_PCM_LEFT		0x0000FFFF
+#define BF_SAIF_DATA_PCM_LEFT(v)	\
+		(((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
+
+/* SAIF_VERSION */
+#define BP_SAIF_VERSION_MAJOR		24
+#define BM_SAIF_VERSION_MAJOR		0xFF000000
+#define BF_SAIF_VERSION_MAJOR(v) \
+		(((v) << 24) & BM_SAIF_VERSION_MAJOR)
+#define BP_SAIF_VERSION_MINOR		16
+#define BM_SAIF_VERSION_MINOR		0x00FF0000
+#define BF_SAIF_VERSION_MINOR(v) \
+		(((v) << 16) & BM_SAIF_VERSION_MINOR)
+#define BP_SAIF_VERSION_STEP		0
+#define BM_SAIF_VERSION_STEP		0x0000FFFF
+#define BF_SAIF_VERSION_STEP(v) \
+		(((v) << 0) & BM_SAIF_VERSION_STEP)
+
+#define MXS_SAIF_SYS_CLK	0
+#define MXS_SAIF_MCLK		1
+
+#include "mxs-pcm.h"
+
+struct mxs_saif {
+	struct clk *clk;
+	void __iomem *base;
+	int irq;
+	struct mxs_pcm_dma_params dma_param;
+
+	struct platform_device *soc_platform_pdev;
+	u32 fifo_err_counter;
+};
+
+#endif
-- 
1.7.0.4

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

* [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

The driver only supports playback firstly.
For recording, as we have to use two saif instances to implement full
duplex (playback & recording) due to hardware limitation, we need to
figure out a good design to fit in ASoC.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/include/mach/audio.h |   18 +++
 sound/soc/mxs/mxs-sgtl5000.c           |  181 ++++++++++++++++++++++++++++++++
 2 files changed, 199 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/include/mach/audio.h b/arch/arm/mach-mxs/include/mach/audio.h
new file mode 100644
index 0000000..2f543d2
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/audio.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MACH_MXS_SAIF_H__
+#define __MACH_MXS_SAIF_H__
+
+struct mxs_audio_platform_data {
+	int sysclk;
+
+	int (*init) (void);     /* board specific init */
+	int (*finit) (void);    /* board specific finit */
+};
+#endif /* __MACH_MXS_SAIF_H__ */
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
new file mode 100644
index 0000000..7ae7c86
--- /dev/null
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include <mach/audio.h>
+#include "../codecs/sgtl5000.h"
+#include "mxs-saif.h"
+
+static struct mxs_sgtl5000_priv {
+	int sysclk;
+	struct platform_device *pdev;
+} card_priv;
+
+static struct snd_soc_card mxs_sgtl5000;
+static struct platform_device *mxs_sgtl5000_snd_device;
+
+static int mxs_sgtl5000_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->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int rate = params_rate(params);
+	u32 dai_format;
+	int ret;
+
+	/* The SAIF clock should be either 512*fs or 384*fs */
+	card_priv.sysclk = 512 * rate;
+	ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_SYS_CLK,
+			card_priv.sysclk,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* set SGTL5000_SYSCLK as 256*fs to support 96k sample rate */
+	snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 256 * rate, 0);
+
+	/* The MCLK output rate is 256*fs */
+	snd_soc_dai_set_clkdiv(cpu_dai, MXS_SAIF_MCLK, 256);
+
+	/* set codec to slave mode */
+	dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
+	.hw_params = mxs_sgtl5000_hw_params,
+};
+
+static int mxs_sgtl5000_soc_init(struct snd_soc_pcm_runtime *rtd)
+{
+	/* TBD: add dapm widgets */
+
+	return 0;
+}
+
+static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
+	{
+		.name		= "HiFi",
+		.stream_name	= "HiFi Playback",
+		.codec_dai_name	= "sgtl5000",
+		.codec_name	= "sgtl5000.0-000a",
+		.cpu_dai_name	= "mxs-saif.0",
+		.platform_name	= "mxs-pcm-audio.0",
+		.init		= mxs_sgtl5000_soc_init,
+		.ops		= &mxs_sgtl5000_hifi_ops,
+	},
+};
+
+static struct snd_soc_card mxs_sgtl5000 = {
+	.name		= "mxs_sgtl5000",
+	.dai_link	= mxs_sgtl5000_dai,
+	.num_links	= ARRAY_SIZE(mxs_sgtl5000_dai),
+};
+
+static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
+{
+	struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
+	int ret;
+
+	card_priv.pdev = pdev;
+
+	ret = -EINVAL;
+	if (plat && plat->init && plat->init())
+		return ret;
+
+	return 0;
+}
+
+static int mxs_sgtl5000_remove(struct platform_device *pdev)
+{
+	struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
+
+	if (plat && plat->finit)
+		plat->finit();
+
+	return 0;
+}
+
+static struct platform_driver mxs_sgtl5000_audio_driver = {
+	.probe = mxs_sgtl5000_probe,
+	.remove = mxs_sgtl5000_remove,
+	.driver = {
+		   .name = "mxs-sgtl5000",
+		   },
+};
+
+static int __init mxs_sgtl5000_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&mxs_sgtl5000_audio_driver);
+	if (ret)
+		return ret;
+
+	mxs_sgtl5000_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mxs_sgtl5000_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mxs_sgtl5000_snd_device, &mxs_sgtl5000);
+
+	ret = platform_device_add(mxs_sgtl5000_snd_device);
+	if (ret) {
+		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+		platform_device_put(mxs_sgtl5000_snd_device);
+	}
+
+	return ret;
+}
+
+static void __exit mxs_sgtl5000_exit(void)
+{
+	platform_driver_unregister(&mxs_sgtl5000_audio_driver);
+	platform_device_unregister(mxs_sgtl5000_snd_device);
+}
+
+late_initcall(mxs_sgtl5000_init);
+module_exit(mxs_sgtl5000_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXS ALSA SoC Machine driver");
+MODULE_LICENSE("GPL");
-- 
1.7.0.4

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

* [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

The driver only supports playback firstly.
For recording, as we have to use two saif instances to implement full
duplex (playback & recording) due to hardware limitation, we need to
figure out a good design to fit in ASoC.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/include/mach/audio.h |   18 +++
 sound/soc/mxs/mxs-sgtl5000.c           |  181 ++++++++++++++++++++++++++++++++
 2 files changed, 199 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/include/mach/audio.h b/arch/arm/mach-mxs/include/mach/audio.h
new file mode 100644
index 0000000..2f543d2
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/audio.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MACH_MXS_SAIF_H__
+#define __MACH_MXS_SAIF_H__
+
+struct mxs_audio_platform_data {
+	int sysclk;
+
+	int (*init) (void);     /* board specific init */
+	int (*finit) (void);    /* board specific finit */
+};
+#endif /* __MACH_MXS_SAIF_H__ */
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
new file mode 100644
index 0000000..7ae7c86
--- /dev/null
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include <mach/audio.h>
+#include "../codecs/sgtl5000.h"
+#include "mxs-saif.h"
+
+static struct mxs_sgtl5000_priv {
+	int sysclk;
+	struct platform_device *pdev;
+} card_priv;
+
+static struct snd_soc_card mxs_sgtl5000;
+static struct platform_device *mxs_sgtl5000_snd_device;
+
+static int mxs_sgtl5000_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->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int rate = params_rate(params);
+	u32 dai_format;
+	int ret;
+
+	/* The SAIF clock should be either 512*fs or 384*fs */
+	card_priv.sysclk = 512 * rate;
+	ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_SYS_CLK,
+			card_priv.sysclk,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* set SGTL5000_SYSCLK as 256*fs to support 96k sample rate */
+	snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 256 * rate, 0);
+
+	/* The MCLK output rate is 256*fs */
+	snd_soc_dai_set_clkdiv(cpu_dai, MXS_SAIF_MCLK, 256);
+
+	/* set codec to slave mode */
+	dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
+	.hw_params = mxs_sgtl5000_hw_params,
+};
+
+static int mxs_sgtl5000_soc_init(struct snd_soc_pcm_runtime *rtd)
+{
+	/* TBD: add dapm widgets */
+
+	return 0;
+}
+
+static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
+	{
+		.name		= "HiFi",
+		.stream_name	= "HiFi Playback",
+		.codec_dai_name	= "sgtl5000",
+		.codec_name	= "sgtl5000.0-000a",
+		.cpu_dai_name	= "mxs-saif.0",
+		.platform_name	= "mxs-pcm-audio.0",
+		.init		= mxs_sgtl5000_soc_init,
+		.ops		= &mxs_sgtl5000_hifi_ops,
+	},
+};
+
+static struct snd_soc_card mxs_sgtl5000 = {
+	.name		= "mxs_sgtl5000",
+	.dai_link	= mxs_sgtl5000_dai,
+	.num_links	= ARRAY_SIZE(mxs_sgtl5000_dai),
+};
+
+static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
+{
+	struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
+	int ret;
+
+	card_priv.pdev = pdev;
+
+	ret = -EINVAL;
+	if (plat && plat->init && plat->init())
+		return ret;
+
+	return 0;
+}
+
+static int mxs_sgtl5000_remove(struct platform_device *pdev)
+{
+	struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
+
+	if (plat && plat->finit)
+		plat->finit();
+
+	return 0;
+}
+
+static struct platform_driver mxs_sgtl5000_audio_driver = {
+	.probe = mxs_sgtl5000_probe,
+	.remove = mxs_sgtl5000_remove,
+	.driver = {
+		   .name = "mxs-sgtl5000",
+		   },
+};
+
+static int __init mxs_sgtl5000_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&mxs_sgtl5000_audio_driver);
+	if (ret)
+		return ret;
+
+	mxs_sgtl5000_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mxs_sgtl5000_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mxs_sgtl5000_snd_device, &mxs_sgtl5000);
+
+	ret = platform_device_add(mxs_sgtl5000_snd_device);
+	if (ret) {
+		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+		platform_device_put(mxs_sgtl5000_snd_device);
+	}
+
+	return ret;
+}
+
+static void __exit mxs_sgtl5000_exit(void)
+{
+	platform_driver_unregister(&mxs_sgtl5000_audio_driver);
+	platform_device_unregister(mxs_sgtl5000_snd_device);
+}
+
+late_initcall(mxs_sgtl5000_init);
+module_exit(mxs_sgtl5000_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXS ALSA SoC Machine driver");
+MODULE_LICENSE("GPL");
-- 
1.7.0.4

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

* [PATCH 04/10] ASoc: mxs: add asoc configuration files
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 sound/soc/Kconfig      |    1 +
 sound/soc/Makefile     |    1 +
 sound/soc/mxs/Kconfig  |   20 ++++++++++++++++++++
 sound/soc/mxs/Makefile |   10 ++++++++++
 4 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 8224db5..aff2592 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -57,6 +57,7 @@ source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
+source "sound/soc/mxs/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1ed61c5..2023771 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SND_SOC)	+= s6000/
 obj-$(CONFIG_SND_SOC)	+= sh/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
+obj-$(CONFIG_SND_SOC)	+= mxs/
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
new file mode 100644
index 0000000..675e27c
--- /dev/null
+++ b/sound/soc/mxs/Kconfig
@@ -0,0 +1,20 @@
+menuconfig SND_MXS_SOC
+	tristate "SoC Audio for Freescale MXS CPUs"
+	depends on ARCH_MXS
+	select SND_PCM
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the MXS SAIF interface.
+
+
+if SND_MXS_SOC
+
+config SND_SOC_MXS_SGTL5000
+	tristate "SoC Audio support for i.MX boards with sgtl5000"
+#	depends on MACH_MX28
+	select SND_SOC_SGTL5000
+	help
+	  Say Y if you want to add support for SoC audio on an MXS board with
+	  a sgtl5000 codec.
+
+endif	# SND_MXS_SOC
diff --git a/sound/soc/mxs/Makefile b/sound/soc/mxs/Makefile
new file mode 100644
index 0000000..565b5b5
--- /dev/null
+++ b/sound/soc/mxs/Makefile
@@ -0,0 +1,10 @@
+# MXS Platform Support
+snd-soc-mxs-objs := mxs-saif.o
+snd-soc-mxs-pcm-objs := mxs-pcm.o
+
+obj-$(CONFIG_SND_MXS_SOC) += snd-soc-mxs.o snd-soc-mxs-pcm.o
+
+# i.MX Machine Support
+snd-soc-mxs-sgtl5000-objs := mxs-sgtl5000.o
+
+obj-$(CONFIG_SND_SOC_MXS_SGTL5000) += snd-soc-mxs-sgtl5000.o
-- 
1.7.0.4

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

* [PATCH 04/10] ASoc: mxs: add asoc configuration files
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 sound/soc/Kconfig      |    1 +
 sound/soc/Makefile     |    1 +
 sound/soc/mxs/Kconfig  |   20 ++++++++++++++++++++
 sound/soc/mxs/Makefile |   10 ++++++++++
 4 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 8224db5..aff2592 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -57,6 +57,7 @@ source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
+source "sound/soc/mxs/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1ed61c5..2023771 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SND_SOC)	+= s6000/
 obj-$(CONFIG_SND_SOC)	+= sh/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
+obj-$(CONFIG_SND_SOC)	+= mxs/
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
new file mode 100644
index 0000000..675e27c
--- /dev/null
+++ b/sound/soc/mxs/Kconfig
@@ -0,0 +1,20 @@
+menuconfig SND_MXS_SOC
+	tristate "SoC Audio for Freescale MXS CPUs"
+	depends on ARCH_MXS
+	select SND_PCM
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the MXS SAIF interface.
+
+
+if SND_MXS_SOC
+
+config SND_SOC_MXS_SGTL5000
+	tristate "SoC Audio support for i.MX boards with sgtl5000"
+#	depends on MACH_MX28
+	select SND_SOC_SGTL5000
+	help
+	  Say Y if you want to add support for SoC audio on an MXS board with
+	  a sgtl5000 codec.
+
+endif	# SND_MXS_SOC
diff --git a/sound/soc/mxs/Makefile b/sound/soc/mxs/Makefile
new file mode 100644
index 0000000..565b5b5
--- /dev/null
+++ b/sound/soc/mxs/Makefile
@@ -0,0 +1,10 @@
+# MXS Platform Support
+snd-soc-mxs-objs := mxs-saif.o
+snd-soc-mxs-pcm-objs := mxs-pcm.o
+
+obj-$(CONFIG_SND_MXS_SOC) += snd-soc-mxs.o snd-soc-mxs-pcm.o
+
+# i.MX Machine Support
+snd-soc-mxs-sgtl5000-objs := mxs-sgtl5000.o
+
+obj-$(CONFIG_SND_SOC_MXS_SGTL5000) += snd-soc-mxs-sgtl5000.o
-- 
1.7.0.4

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

* [PATCH 05/10] ARM: mxs: add saif clock
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Set pll0 as parent.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/clock-mx28.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 5dcc59d..7b3657b 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -640,6 +640,8 @@ static struct clk_lookup lookups[] = {
 	_REGISTER_CLOCK(NULL, "lradc", lradc_clk)
 	_REGISTER_CLOCK(NULL, "spdif", spdif_clk)
 	_REGISTER_CLOCK("imx28-fb", NULL, lcdif_clk)
+	_REGISTER_CLOCK("mxs-saif.0", NULL, saif0_clk)
+	_REGISTER_CLOCK("mxs-saif.1", NULL, saif1_clk)
 };
 
 static int clk_misc_init(void)
@@ -774,6 +776,8 @@ int __init mx28_clocks_init(void)
 	clk_enable(&uart_clk);
 
 	clk_set_parent(&lcdif_clk, &ref_pix_clk);
+	clk_set_parent(&saif0_clk, &pll0_clk);
+	clk_set_parent(&saif1_clk, &pll0_clk);
 
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
-- 
1.7.0.4

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

* [PATCH 05/10] ARM: mxs: add saif clock
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Set pll0 as parent.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/clock-mx28.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 5dcc59d..7b3657b 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -640,6 +640,8 @@ static struct clk_lookup lookups[] = {
 	_REGISTER_CLOCK(NULL, "lradc", lradc_clk)
 	_REGISTER_CLOCK(NULL, "spdif", spdif_clk)
 	_REGISTER_CLOCK("imx28-fb", NULL, lcdif_clk)
+	_REGISTER_CLOCK("mxs-saif.0", NULL, saif0_clk)
+	_REGISTER_CLOCK("mxs-saif.1", NULL, saif1_clk)
 };
 
 static int clk_misc_init(void)
@@ -774,6 +776,8 @@ int __init mx28_clocks_init(void)
 	clk_enable(&uart_clk);
 
 	clk_set_parent(&lcdif_clk, &ref_pix_clk);
+	clk_set_parent(&saif0_clk, &pll0_clk);
+	clk_set_parent(&saif1_clk, &pll0_clk);
 
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
-- 
1.7.0.4

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

* [PATCH 06/10] ARM: mxs: add saif device
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/Kconfig                       |    1 +
 arch/arm/mach-mxs/devices-mx28.h                |    7 +++
 arch/arm/mach-mxs/devices/Kconfig               |    3 +
 arch/arm/mach-mxs/devices/Makefile              |    1 +
 arch/arm/mach-mxs/devices/platform-mxs-saif.c   |   60 +++++++++++++++++++++++
 arch/arm/mach-mxs/include/mach/devices-common.h |   12 +++++
 arch/arm/mach-mxs/mach-mx28evk.c                |   20 ++++++++
 7 files changed, 104 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 4cd0231..405c28d 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -48,6 +48,7 @@ config MACH_MX28EVK
 	select MXS_HAVE_PLATFORM_FLEXCAN
 	select MXS_HAVE_PLATFORM_MXS_MMC
 	select MXS_HAVE_PLATFORM_MXSFB
+	select MXS_HAVE_PLATFORM_MXS_SAIF
 	select MXS_OCOTP
 	help
 	  Include support for MX28EVK platform. This includes specific
diff --git a/arch/arm/mach-mxs/devices-mx28.h b/arch/arm/mach-mxs/devices-mx28.h
index 79b9452..f0fa46f 100644
--- a/arch/arm/mach-mxs/devices-mx28.h
+++ b/arch/arm/mach-mxs/devices-mx28.h
@@ -11,6 +11,7 @@
 #include <mach/mx28.h>
 #include <mach/devices-common.h>
 #include <mach/mxsfb.h>
+#include <mach/audio.h>
 
 extern const struct amba_device mx28_duart_device __initconst;
 #define mx28_add_duart() \
@@ -45,3 +46,9 @@ extern const struct mxs_mxs_mmc_data mx28_mxs_mmc_data[] __initconst;
 
 struct platform_device *__init mx28_add_mxsfb(
 		const struct mxsfb_platform_data *pdata);
+
+extern const struct mxs_saif_data mx28_saif_data[] __initconst;
+#define mx28_add_saif(id)              mxs_add_saif(&mx28_saif_data[id])
+
+struct platform_device *__init mx28_add_audio(
+		const struct mxs_audio_platform_data *pdata);
diff --git a/arch/arm/mach-mxs/devices/Kconfig b/arch/arm/mach-mxs/devices/Kconfig
index acf9eea..b554371 100644
--- a/arch/arm/mach-mxs/devices/Kconfig
+++ b/arch/arm/mach-mxs/devices/Kconfig
@@ -23,3 +23,6 @@ config MXS_HAVE_PLATFORM_MXS_PWM
 
 config MXS_HAVE_PLATFORM_MXSFB
 	bool
+
+config MXS_HAVE_PLATFORM_MXS_SAIF
+	bool
diff --git a/arch/arm/mach-mxs/devices/Makefile b/arch/arm/mach-mxs/devices/Makefile
index 351915c..d3e8cc3 100644
--- a/arch/arm/mach-mxs/devices/Makefile
+++ b/arch/arm/mach-mxs/devices/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_MMC) += platform-mxs-mmc.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_PWM) += platform-mxs-pwm.o
 obj-y += platform-gpio-mxs.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXSFB) += platform-mxsfb.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_SAIF) += platform-mxs-saif.o
diff --git a/arch/arm/mach-mxs/devices/platform-mxs-saif.c b/arch/arm/mach-mxs/devices/platform-mxs-saif.c
new file mode 100644
index 0000000..1ec965e
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-mxs-saif.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+
+#define mxs_saif_data_entry_single(soc, _id)				\
+	{								\
+		.id = _id,						\
+		.iobase = soc ## _SAIF ## _id ## _BASE_ADDR,		\
+		.irq = soc ## _INT_SAIF ## _id,				\
+		.dma = soc ## _DMA_SAIF ## _id,				\
+		.dmairq = soc ## _INT_SAIF ## _id ##_DMA,		\
+	}
+
+#define mxs_saif_data_entry(soc, _id)					\
+	[_id] = mxs_saif_data_entry_single(soc, _id)
+
+#ifdef CONFIG_SOC_IMX28
+const struct mxs_saif_data mx28_saif_data[] __initconst = {
+	mxs_saif_data_entry(MX28, 0),
+	mxs_saif_data_entry(MX28, 1),
+};
+#endif
+
+struct platform_device *__init mxs_add_saif(const struct mxs_saif_data *data)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		}, {
+			.start = data->dma,
+			.end = data->dma,
+			.flags = IORESOURCE_DMA,
+		}, {
+			.start = data->dmairq,
+			.end = data->dmairq,
+			.flags = IORESOURCE_IRQ,
+		},
+
+	};
+
+	return mxs_add_platform_device("mxs-saif", data->id, res,
+					ARRAY_SIZE(res), NULL, 0);
+}
diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h
index 812d7a8..a8080f4 100644
--- a/arch/arm/mach-mxs/include/mach/devices-common.h
+++ b/arch/arm/mach-mxs/include/mach/devices-common.h
@@ -92,3 +92,15 @@ struct platform_device *__init mxs_add_mxs_mmc(
 /* pwm */
 struct platform_device *__init mxs_add_mxs_pwm(
 		resource_size_t iobase, int id);
+
+/* saif */
+struct mxs_saif_data {
+	int id;
+	resource_size_t iobase;
+	resource_size_t irq;
+	resource_size_t dma;
+	resource_size_t dmairq;
+};
+
+struct platform_device *__init mxs_add_saif(
+		const struct mxs_saif_data *data);
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index eaaf6ff..7837a87 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -40,6 +40,8 @@
 #define MX28EVK_MMC0_SLOT_POWER		MXS_GPIO_NR(3, 28)
 #define MX28EVK_MMC1_SLOT_POWER		MXS_GPIO_NR(3, 29)
 
+#define DIGCTRL_BASE_ADDR      MX28_IO_ADDRESS(MX28_DIGCTL_BASE_ADDR)
+
 static const iomux_cfg_t mx28evk_pads[] __initconst = {
 	/* duart */
 	MX28_PAD_PWM0__DUART_RX | MXS_PAD_CTRL,
@@ -183,6 +185,18 @@ static const iomux_cfg_t mx28evk_pads[] __initconst = {
 
 	/* led */
 	MX28_PAD_AUART1_TX__GPIO_3_5 | MXS_PAD_CTRL,
+
+	/* saif0 & saif1 */
+	MX28_PAD_SAIF0_MCLK__SAIF0_MCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0 |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0 |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
 };
 
 /* led */
@@ -392,6 +406,12 @@ static void __init mx28evk_init(void)
 
 	mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
 
+	mx28_add_saif(0);
+	mx28_add_saif(1);
+
+	/*set the saif clk mux, both saif0/saif1 use saif0 clk*/
+	__raw_writel(0x2 << 10, DIGCTRL_BASE_ADDR);
+
 	/* power on mmc slot by writing 0 to the gpio */
 	ret = gpio_request_one(MX28EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW,
 			       "mmc0-slot-power");
-- 
1.7.0.4

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

* [PATCH 06/10] ARM: mxs: add saif device
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/Kconfig                       |    1 +
 arch/arm/mach-mxs/devices-mx28.h                |    7 +++
 arch/arm/mach-mxs/devices/Kconfig               |    3 +
 arch/arm/mach-mxs/devices/Makefile              |    1 +
 arch/arm/mach-mxs/devices/platform-mxs-saif.c   |   60 +++++++++++++++++++++++
 arch/arm/mach-mxs/include/mach/devices-common.h |   12 +++++
 arch/arm/mach-mxs/mach-mx28evk.c                |   20 ++++++++
 7 files changed, 104 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 4cd0231..405c28d 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -48,6 +48,7 @@ config MACH_MX28EVK
 	select MXS_HAVE_PLATFORM_FLEXCAN
 	select MXS_HAVE_PLATFORM_MXS_MMC
 	select MXS_HAVE_PLATFORM_MXSFB
+	select MXS_HAVE_PLATFORM_MXS_SAIF
 	select MXS_OCOTP
 	help
 	  Include support for MX28EVK platform. This includes specific
diff --git a/arch/arm/mach-mxs/devices-mx28.h b/arch/arm/mach-mxs/devices-mx28.h
index 79b9452..f0fa46f 100644
--- a/arch/arm/mach-mxs/devices-mx28.h
+++ b/arch/arm/mach-mxs/devices-mx28.h
@@ -11,6 +11,7 @@
 #include <mach/mx28.h>
 #include <mach/devices-common.h>
 #include <mach/mxsfb.h>
+#include <mach/audio.h>
 
 extern const struct amba_device mx28_duart_device __initconst;
 #define mx28_add_duart() \
@@ -45,3 +46,9 @@ extern const struct mxs_mxs_mmc_data mx28_mxs_mmc_data[] __initconst;
 
 struct platform_device *__init mx28_add_mxsfb(
 		const struct mxsfb_platform_data *pdata);
+
+extern const struct mxs_saif_data mx28_saif_data[] __initconst;
+#define mx28_add_saif(id)              mxs_add_saif(&mx28_saif_data[id])
+
+struct platform_device *__init mx28_add_audio(
+		const struct mxs_audio_platform_data *pdata);
diff --git a/arch/arm/mach-mxs/devices/Kconfig b/arch/arm/mach-mxs/devices/Kconfig
index acf9eea..b554371 100644
--- a/arch/arm/mach-mxs/devices/Kconfig
+++ b/arch/arm/mach-mxs/devices/Kconfig
@@ -23,3 +23,6 @@ config MXS_HAVE_PLATFORM_MXS_PWM
 
 config MXS_HAVE_PLATFORM_MXSFB
 	bool
+
+config MXS_HAVE_PLATFORM_MXS_SAIF
+	bool
diff --git a/arch/arm/mach-mxs/devices/Makefile b/arch/arm/mach-mxs/devices/Makefile
index 351915c..d3e8cc3 100644
--- a/arch/arm/mach-mxs/devices/Makefile
+++ b/arch/arm/mach-mxs/devices/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_MMC) += platform-mxs-mmc.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_PWM) += platform-mxs-pwm.o
 obj-y += platform-gpio-mxs.o
 obj-$(CONFIG_MXS_HAVE_PLATFORM_MXSFB) += platform-mxsfb.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_SAIF) += platform-mxs-saif.o
diff --git a/arch/arm/mach-mxs/devices/platform-mxs-saif.c b/arch/arm/mach-mxs/devices/platform-mxs-saif.c
new file mode 100644
index 0000000..1ec965e
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-mxs-saif.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+
+#define mxs_saif_data_entry_single(soc, _id)				\
+	{								\
+		.id = _id,						\
+		.iobase = soc ## _SAIF ## _id ## _BASE_ADDR,		\
+		.irq = soc ## _INT_SAIF ## _id,				\
+		.dma = soc ## _DMA_SAIF ## _id,				\
+		.dmairq = soc ## _INT_SAIF ## _id ##_DMA,		\
+	}
+
+#define mxs_saif_data_entry(soc, _id)					\
+	[_id] = mxs_saif_data_entry_single(soc, _id)
+
+#ifdef CONFIG_SOC_IMX28
+const struct mxs_saif_data mx28_saif_data[] __initconst = {
+	mxs_saif_data_entry(MX28, 0),
+	mxs_saif_data_entry(MX28, 1),
+};
+#endif
+
+struct platform_device *__init mxs_add_saif(const struct mxs_saif_data *data)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		}, {
+			.start = data->dma,
+			.end = data->dma,
+			.flags = IORESOURCE_DMA,
+		}, {
+			.start = data->dmairq,
+			.end = data->dmairq,
+			.flags = IORESOURCE_IRQ,
+		},
+
+	};
+
+	return mxs_add_platform_device("mxs-saif", data->id, res,
+					ARRAY_SIZE(res), NULL, 0);
+}
diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h
index 812d7a8..a8080f4 100644
--- a/arch/arm/mach-mxs/include/mach/devices-common.h
+++ b/arch/arm/mach-mxs/include/mach/devices-common.h
@@ -92,3 +92,15 @@ struct platform_device *__init mxs_add_mxs_mmc(
 /* pwm */
 struct platform_device *__init mxs_add_mxs_pwm(
 		resource_size_t iobase, int id);
+
+/* saif */
+struct mxs_saif_data {
+	int id;
+	resource_size_t iobase;
+	resource_size_t irq;
+	resource_size_t dma;
+	resource_size_t dmairq;
+};
+
+struct platform_device *__init mxs_add_saif(
+		const struct mxs_saif_data *data);
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index eaaf6ff..7837a87 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -40,6 +40,8 @@
 #define MX28EVK_MMC0_SLOT_POWER		MXS_GPIO_NR(3, 28)
 #define MX28EVK_MMC1_SLOT_POWER		MXS_GPIO_NR(3, 29)
 
+#define DIGCTRL_BASE_ADDR      MX28_IO_ADDRESS(MX28_DIGCTL_BASE_ADDR)
+
 static const iomux_cfg_t mx28evk_pads[] __initconst = {
 	/* duart */
 	MX28_PAD_PWM0__DUART_RX | MXS_PAD_CTRL,
@@ -183,6 +185,18 @@ static const iomux_cfg_t mx28evk_pads[] __initconst = {
 
 	/* led */
 	MX28_PAD_AUART1_TX__GPIO_3_5 | MXS_PAD_CTRL,
+
+	/* saif0 & saif1 */
+	MX28_PAD_SAIF0_MCLK__SAIF0_MCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0 |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0 |
+		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
 };
 
 /* led */
@@ -392,6 +406,12 @@ static void __init mx28evk_init(void)
 
 	mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
 
+	mx28_add_saif(0);
+	mx28_add_saif(1);
+
+	/*set the saif clk mux, both saif0/saif1 use saif0 clk*/
+	__raw_writel(0x2 << 10, DIGCTRL_BASE_ADDR);
+
 	/* power on mmc slot by writing 0 to the gpio */
 	ret = gpio_request_one(MX28EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW,
 			       "mmc0-slot-power");
-- 
1.7.0.4

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

* [PATCH 07/10] ARM: mxs: add sgtl5000 i2c device
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/mach-mx28evk.c |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index 7837a87..c8b154a 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -186,6 +186,12 @@ static const iomux_cfg_t mx28evk_pads[] __initconst = {
 	/* led */
 	MX28_PAD_AUART1_TX__GPIO_3_5 | MXS_PAD_CTRL,
 
+	/* I2C */
+	MX28_PAD_I2C0_SCL__I2C0_SCL |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_I2C0_SDA__I2C0_SDA |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+
 	/* saif0 & saif1 */
 	MX28_PAD_SAIF0_MCLK__SAIF0_MCLK |
 		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
@@ -366,6 +372,12 @@ static struct mxs_mmc_platform_data mx28evk_mmc_pdata[] __initdata = {
 	},
 };
 
+static struct i2c_board_info mxs_i2c0_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sgtl5000", 0x0a),
+	},
+};
+
 static void __init mx28evk_init(void)
 {
 	int ret;
@@ -409,6 +421,10 @@ static void __init mx28evk_init(void)
 	mx28_add_saif(0);
 	mx28_add_saif(1);
 
+	mx28_add_mxs_i2c(0);
+	i2c_register_board_info(0, mxs_i2c0_board_info,
+				ARRAY_SIZE(mxs_i2c0_board_info));
+
 	/*set the saif clk mux, both saif0/saif1 use saif0 clk*/
 	__raw_writel(0x2 << 10, DIGCTRL_BASE_ADDR);
 
-- 
1.7.0.4

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

* [PATCH 07/10] ARM: mxs: add sgtl5000 i2c device
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/mach-mx28evk.c |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index 7837a87..c8b154a 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -186,6 +186,12 @@ static const iomux_cfg_t mx28evk_pads[] __initconst = {
 	/* led */
 	MX28_PAD_AUART1_TX__GPIO_3_5 | MXS_PAD_CTRL,
 
+	/* I2C */
+	MX28_PAD_I2C0_SCL__I2C0_SCL |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+	MX28_PAD_I2C0_SDA__I2C0_SDA |
+		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+
 	/* saif0 & saif1 */
 	MX28_PAD_SAIF0_MCLK__SAIF0_MCLK |
 		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
@@ -366,6 +372,12 @@ static struct mxs_mmc_platform_data mx28evk_mmc_pdata[] __initdata = {
 	},
 };
 
+static struct i2c_board_info mxs_i2c0_board_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sgtl5000", 0x0a),
+	},
+};
+
 static void __init mx28evk_init(void)
 {
 	int ret;
@@ -409,6 +421,10 @@ static void __init mx28evk_init(void)
 	mx28_add_saif(0);
 	mx28_add_saif(1);
 
+	mx28_add_mxs_i2c(0);
+	i2c_register_board_info(0, mxs_i2c0_board_info,
+				ARRAY_SIZE(mxs_i2c0_board_info));
+
 	/*set the saif clk mux, both saif0/saif1 use saif0 clk*/
 	__raw_writel(0x2 << 10, DIGCTRL_BASE_ADDR);
 
-- 
1.7.0.4

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

* [PATCH 08/10] ARM: mxs: add mxs-sgtl5000 device
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/mach-mx28evk.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index c8b154a..03f75fe 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -425,6 +425,9 @@ static void __init mx28evk_init(void)
 	i2c_register_board_info(0, mxs_i2c0_board_info,
 				ARRAY_SIZE(mxs_i2c0_board_info));
 
+	mxs_add_platform_device("mxs-sgtl5000", 0, NULL, 0,
+			NULL, 0);
+
 	/*set the saif clk mux, both saif0/saif1 use saif0 clk*/
 	__raw_writel(0x2 << 10, DIGCTRL_BASE_ADDR);
 
-- 
1.7.0.4

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

* [PATCH 08/10] ARM: mxs: add mxs-sgtl5000 device
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/mach-mx28evk.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index c8b154a..03f75fe 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -425,6 +425,9 @@ static void __init mx28evk_init(void)
 	i2c_register_board_info(0, mxs_i2c0_board_info,
 				ARRAY_SIZE(mxs_i2c0_board_info));
 
+	mxs_add_platform_device("mxs-sgtl5000", 0, NULL, 0,
+			NULL, 0);
+
 	/*set the saif clk mux, both saif0/saif1 use saif0 clk*/
 	__raw_writel(0x2 << 10, DIGCTRL_BASE_ADDR);
 
-- 
1.7.0.4

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

* [PATCH 09/10] ARM: mxs: correct the using of frac div for saif
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

According to spec, set to 1 is the enable of fractional devide
or the clock can not be generated properly.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/clock-mx28.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 7b3657b..7954013 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -710,11 +710,11 @@ static int clk_misc_init(void)
 
 	/* SAIF has to use frac div for functional operation */
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0);
-	reg &= ~BM_CLKCTRL_SAIF0_DIV_FRAC_EN;
+	reg |= BM_CLKCTRL_SAIF0_DIV_FRAC_EN;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0);
 
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1);
-	reg &= ~BM_CLKCTRL_SAIF1_DIV_FRAC_EN;
+	reg |= BM_CLKCTRL_SAIF1_DIV_FRAC_EN;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1);
 
 	/*
-- 
1.7.0.4

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

* [PATCH 09/10] ARM: mxs: correct the using of frac div for saif
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

According to spec, set to 1 is the enable of fractional devide
or the clock can not be generated properly.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/clock-mx28.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 7b3657b..7954013 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -710,11 +710,11 @@ static int clk_misc_init(void)
 
 	/* SAIF has to use frac div for functional operation */
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0);
-	reg &= ~BM_CLKCTRL_SAIF0_DIV_FRAC_EN;
+	reg |= BM_CLKCTRL_SAIF0_DIV_FRAC_EN;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0);
 
 	reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1);
-	reg &= ~BM_CLKCTRL_SAIF1_DIV_FRAC_EN;
+	reg |= BM_CLKCTRL_SAIF1_DIV_FRAC_EN;
 	__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1);
 
 	/*
-- 
1.7.0.4

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

* [PATCH 10/10] ARM: mxs-dma: include <linux/dmaengine.h>
  2011-07-08 15:59 ` Dong Aisheng
@ 2011-07-08 15:59   ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: alsa-devel; +Cc: s.hauer, lrg, linux-arm-kernel

Other files using dma.h may fail to compile as follows:
In file included from sound/soc/mxs/mxs-pcm.h:22,
                 from sound/soc/mxs/mxs-saif.h:112,
                 from sound/soc/mxs/mxs-sgtl5000.c:34:
arch/arm/mach-mxs/include/mach/dma.h:16: warning: 'struct dma_chan' declared inside parameter list
arch/arm/mach-mxs/include/mach/dma.h:16: warning: its scope is only this definition or declaration, which is probably not what you want
arch/arm/mach-mxs/include/mach/dma.h: In function 'mxs_dma_is_apbh':
arch/arm/mach-mxs/include/mach/dma.h:18: error: dereferencing pointer to incomplete type
arch/arm/mach-mxs/include/mach/dma.h: At top level:
arch/arm/mach-mxs/include/mach/dma.h:21: warning: 'struct dma_chan' declared inside parameter list
arch/arm/mach-mxs/include/mach/dma.h: In function 'mxs_dma_is_apbx':
arch/arm/mach-mxs/include/mach/dma.h:23: error: dereferencing pointer to incomplete type
make[3]: *** [sound/soc/mxs/mxs-sgtl5000.o] Error 1
make[2]: *** [sound/soc/mxs] Error 2
make[1]: *** [sound/soc] Error 2
make: *** [sound] Error 2

It seems it's better for dma.h to include dmaengine.h himself.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/include/mach/dma.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/include/mach/dma.h b/arch/arm/mach-mxs/include/mach/dma.h
index 7f4aeea..203d7c4 100644
--- a/arch/arm/mach-mxs/include/mach/dma.h
+++ b/arch/arm/mach-mxs/include/mach/dma.h
@@ -9,6 +9,8 @@
 #ifndef __MACH_MXS_DMA_H__
 #define __MACH_MXS_DMA_H__
 
+#include <linux/dmaengine.h>
+
 struct mxs_dma_data {
 	int chan_irq;
 };
-- 
1.7.0.4

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

* [PATCH 10/10] ARM: mxs-dma: include <linux/dmaengine.h>
@ 2011-07-08 15:59   ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Other files using dma.h may fail to compile as follows:
In file included from sound/soc/mxs/mxs-pcm.h:22,
                 from sound/soc/mxs/mxs-saif.h:112,
                 from sound/soc/mxs/mxs-sgtl5000.c:34:
arch/arm/mach-mxs/include/mach/dma.h:16: warning: 'struct dma_chan' declared inside parameter list
arch/arm/mach-mxs/include/mach/dma.h:16: warning: its scope is only this definition or declaration, which is probably not what you want
arch/arm/mach-mxs/include/mach/dma.h: In function 'mxs_dma_is_apbh':
arch/arm/mach-mxs/include/mach/dma.h:18: error: dereferencing pointer to incomplete type
arch/arm/mach-mxs/include/mach/dma.h: At top level:
arch/arm/mach-mxs/include/mach/dma.h:21: warning: 'struct dma_chan' declared inside parameter list
arch/arm/mach-mxs/include/mach/dma.h: In function 'mxs_dma_is_apbx':
arch/arm/mach-mxs/include/mach/dma.h:23: error: dereferencing pointer to incomplete type
make[3]: *** [sound/soc/mxs/mxs-sgtl5000.o] Error 1
make[2]: *** [sound/soc/mxs] Error 2
make[1]: *** [sound/soc] Error 2
make: *** [sound] Error 2

It seems it's better for dma.h to include dmaengine.h himself.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 arch/arm/mach-mxs/include/mach/dma.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mxs/include/mach/dma.h b/arch/arm/mach-mxs/include/mach/dma.h
index 7f4aeea..203d7c4 100644
--- a/arch/arm/mach-mxs/include/mach/dma.h
+++ b/arch/arm/mach-mxs/include/mach/dma.h
@@ -9,6 +9,8 @@
 #ifndef __MACH_MXS_DMA_H__
 #define __MACH_MXS_DMA_H__
 
+#include <linux/dmaengine.h>
+
 struct mxs_dma_data {
 	int chan_irq;
 };
-- 
1.7.0.4

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-08 15:59   ` Dong Aisheng
@ 2011-07-08 16:19     ` Sascha Hauer
  -1 siblings, 0 replies; 60+ messages in thread
From: Sascha Hauer @ 2011-07-08 16:19 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, lrg, linux-arm-kernel

On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  sound/soc/mxs/mxs-saif.c |  524 ++++++++++++++++++++++++++++++++++++++++++++++
>  sound/soc/mxs/mxs-saif.h |  124 +++++++++++
>  2 files changed, 648 insertions(+), 0 deletions(-)
> 
> diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
> new file mode 100644
> index 0000000..afc6e57
> --- /dev/null
> +++ b/sound/soc/mxs/mxs-saif.c
> @@ -0,0 +1,524 @@
> +/*
> + * Copyright 2011 Freescale Semiconductor, Inc.
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <mach/dma.h>
> +#include <asm/mach-types.h>
> +#include <mach/hardware.h>
> +#include <mach/mx28.h>

Is this include really needed?

> +
> +#include "mxs-saif.h"
> +
> +/*
> +* SAIF system clock configuration.
> +* Should only be called when port is inactive.
> +*/
> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
> +			int clk_id, unsigned int freq, int dir)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	switch (clk_id) {
> +	case MXS_SAIF_SYS_CLK:
> +		clk_set_rate(saif->clk, freq);
> +		clk_enable(saif->clk);

This clk_enable is unbalanced. You enabled the clock in probe() already.

> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * SAIF Clock dividers
> + * Should only be called when port is inactive.
> + */
> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
> +				  int div_id, int div)
> +{
> +	u32 scr;
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	scr = __raw_readl(saif->base + SAIF_CTRL);
> +	scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
> +	scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +
> +	switch (div_id) {
> +	case MXS_SAIF_MCLK:
> +		switch (div) {
> +		case 32:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 64:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 128:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 256:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 512:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 48:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 96:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 192:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 384:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	__raw_writel(scr, saif->base + SAIF_CTRL);
> +
> +	return 0;
> +}
> +
> +/*
> + * SAIF DAI format configuration.
> + * Should only be called when port is inactive.
> + * Note: We don't use the I2S modes but instead manually configure the
> + * SAIF for I2S.
> + */
> +static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
> +{
> +	u32 scr, stat;
> +	u32 scr0;
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	stat = __raw_readl(saif->base + SAIF_STAT);
> +	if (stat & BM_SAIF_STAT_BUSY)
> +		return 0;

Returning succesfully doesn't seem right here.

> +
> +	scr0 = __raw_readl(saif->base + SAIF_CTRL);
> +	scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
> +		& ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
> +	scr = 0;
> +
> +	/* DAI mode */
> +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> +	case SND_SOC_DAIFMT_I2S:
> +		/* data frame low 1clk before data */
> +		scr |= BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_LEFT_J:
> +		/* data frame high with data */
> +		scr &= ~BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		scr &= ~BM_SAIF_CTRL_JUSTIFY;
> +		break;

	default:
		return -EINVAL;

> +	}
> +
> +	/* DAI clock inversion */
> +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> +	case SND_SOC_DAIFMT_IB_IF:
> +		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_IB_NF:
> +		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_NB_IF:
> +		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_NB_NF:
> +		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	}

A question more for Liam and Mark: Would it make sense to add individual
masks for the clock inversion and frame sync inversion? I code like the
above in every driver, and I think this could become simpler.


> +
> +	/*
> +	 * Note: We simply just support master mode since SAIF TX only supports
> +	 * master mode.
> +	 */

When this is true...

> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +		scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
> +		__raw_writel(scr | scr0, saif->base + SAIF_CTRL);
> +		break;
> +	case SND_SOC_DAIFMT_CBM_CFS:
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFM:
> +		break;

You should return an error here.

> +	case SND_SOC_DAIFMT_CBM_CFM:
> +		return -EINVAL;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
> +			   struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
> +
> +	return 0;
> +}
> +
> +/*
> + * Should only be called when port is inactive.
> + * although can be called multiple times by upper layers.
> + */
> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params,
> +			     struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	u32 scr;
> +
> +	scr = __raw_readl(saif->base + SAIF_CTRL);
> +
> +	/* cant change any parameters when SAIF is running */
> +	/* DAI data (word) size */
> +	scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
> +	scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
> +		break;
> +	case SNDRV_PCM_FORMAT_S20_3LE:
> +		scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
> +		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
> +		break;
> +	case SNDRV_PCM_FORMAT_S24_LE:
> +		scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
> +		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
> +		break;

	default:
		return -EINVAL;

> +	}
> +
> +	/* Tx/Rx config */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		/* enable TX mode */
> +		scr &= ~BM_SAIF_CTRL_READ_MODE;
> +	} else {
> +		/* enable RX mode */
> +		scr |= BM_SAIF_CTRL_READ_MODE;
> +	}
> +
> +	__raw_writel(scr, saif->base + SAIF_CTRL);
> +	return 0;
> +}
> +
> +static int mxs_saif_prepare(struct snd_pcm_substream *substream,
> +			   struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	__raw_writel(BM_SAIF_CTRL_CLKGATE,
> +		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
> +
> +	return 0;
> +}
> +
> +static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
> +				struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +			/*write a data to saif data register to trigger
> +				the transfer*/

/* multiline comments
 * like this please
 */

> +			__raw_writel(0, saif->base + SAIF_DATA);
> +		else
> +			/*read a data from saif data register to trigger
> +				the receive*/
> +			__raw_readl(saif->base + SAIF_DATA);
> +		break;
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +#define MXS_SAIF_RATES		SNDRV_PCM_RATE_8000_192000
> +#define MXS_SAIF_FORMATS \
> +	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
> +	SNDRV_PCM_FMTBIT_S24_LE)
> +
> +static struct snd_soc_dai_ops mxs_saif_dai_ops = {
> +	.startup = mxs_saif_startup,
> +	.trigger = mxs_saif_trigger,
> +	.prepare = mxs_saif_prepare,
> +	.hw_params = mxs_saif_hw_params,
> +	.set_sysclk = mxs_saif_set_dai_sysclk,
> +	.set_clkdiv = mxs_saif_set_dai_clkdiv,
> +	.set_fmt = mxs_saif_set_dai_fmt,
> +};
> +
> +static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
> +{
> +	struct mxs_saif *saif = dev_get_drvdata(dai->dev);
> +
> +	snd_soc_dai_set_drvdata(dai, saif);
> +
> +	/* Reset */
> +	__raw_writel(BM_SAIF_CTRL_SFTRST,
> +		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
> +
> +	/* enable MCLK output early since codec may need it */
> +	__raw_writel(BM_SAIF_CTRL_CLKGATE,
> +		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
> +	__raw_writel(BM_SAIF_CTRL_RUN,
> +		saif->base + SAIF_CTRL + MXS_SET_ADDR);
> +
> +	return 0;
> +}
> +
> +static struct snd_soc_dai_driver mxs_saif_dai = {
> +	.name = "mxs-saif",
> +	.probe = mxs_saif_dai_probe,
> +	.playback = {
> +		.channels_min = 2,
> +		.channels_max = 2,
> +		.rates = MXS_SAIF_RATES,
> +		.formats = MXS_SAIF_FORMATS,
> +	},
> +	.capture = {
> +		.channels_min = 2,
> +		.channels_max = 2,
> +		.rates = MXS_SAIF_RATES,
> +		.formats = MXS_SAIF_FORMATS,
> +	},
> +	.ops = &mxs_saif_dai_ops,
> +};
> +
> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
> +{
> +	struct mxs_saif *saif = dev_id;
> +
> +	if (saif->fifo_err_counter++ % 100 == 0)
> +		printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
> +			fifo_errs=%d \n",
> +		       __raw_readl(saif->base + SAIF_STAT),
> +		       __raw_readl(saif->base + SAIF_CTRL),
> +		       saif->fifo_err_counter);
> +	__raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
> +			BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
> +			saif->base + SAIF_STAT + MXS_CLR_ADDR);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int mxs_saif_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct mxs_saif *saif;
> +	int ret = 0;
> +
> +	saif = kzalloc(sizeof(*saif), GFP_KERNEL);
> +	if (!saif)
> +		return -ENOMEM;

Consider using devm_kzalloc and friends, it makes the error path less
error prone.

> +
> +	saif->irq = platform_get_irq(pdev, 0);
> +	if (saif->irq < 0) {
> +		ret = saif->irq;
> +		dev_err(&pdev->dev, "failed to get irq resource: %d\n",
> +			ret);
> +		goto failed_get_irq1;
> +	}
> +
> +	saif->fifo_err_counter = 0;
> +	ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to request irq\n");
> +		goto failed_req_irq;
> +	}
> +
> +	saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
> +	if (saif->dma_param.chan_irq < 0) {
> +		ret = saif->dma_param.chan_irq;
> +		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
> +			ret);
> +		goto failed_get_irq2;
> +	}
> +
> +	saif->clk = clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(saif->clk)) {
> +		ret = PTR_ERR(saif->clk);
> +		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
> +			ret);
> +		goto failed_clk;
> +	}
> +	clk_set_rate(saif->clk, 12000000);
> +	clk_enable(saif->clk);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		ret = -ENODEV;
> +		dev_err(&pdev->dev, "failed to get io resource: %d\n",
> +			ret);
> +		goto failed_get_resource;
> +	}
> +
> +	if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) {
> +		dev_err(&pdev->dev, "request_mem_region failed\n");
> +		ret = -EBUSY;
> +		goto failed_get_resource;
> +	}
> +
> +	saif->base = ioremap(res->start, resource_size(res));
> +	if (!saif->base) {
> +		dev_err(&pdev->dev, "ioremap failed\n");
> +		ret = -ENODEV;
> +		goto failed_ioremap;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> +	if (!res) {
> +		ret = -ENODEV;
> +		dev_err(&pdev->dev, "failed to get dma resource: %d\n",
> +			ret);
> +		goto failed_get_resource;
> +	}
> +	saif->dma_param.chan_num = res->start;
> +
> +	platform_set_drvdata(pdev, saif);
> +
> +	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
> +	if (ret) {
> +		dev_err(&pdev->dev, "register DAI failed\n");
> +		goto failed_register;
> +	}
> +
> +	saif->soc_platform_pdev = platform_device_alloc(
> +					"mxs-pcm-audio", pdev->id);
> +	if (!saif->soc_platform_pdev) {
> +		ret = -ENOMEM;
> +		goto failed_pdev_alloc;
> +	}
> +
> +	platform_set_drvdata(saif->soc_platform_pdev, saif);
> +	ret = platform_device_add(saif->soc_platform_pdev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to add soc platform device\n");
> +		goto failed_pdev_add;
> +	}
> +
> +	return 0;
> +
> +failed_pdev_add:
> +	platform_device_put(saif->soc_platform_pdev);
> +failed_pdev_alloc:
> +	snd_soc_unregister_dai(&pdev->dev);
> +failed_register:
> +	iounmap(saif->base);
> +failed_ioremap:
> +	release_mem_region(res->start, resource_size(res));
> +failed_get_resource:
> +	clk_disable(saif->clk);
> +	clk_put(saif->clk);
> +failed_clk:
> +failed_get_irq2:
> +	free_irq(saif->irq, saif);
> +failed_req_irq:
> +failed_get_irq1:
> +	kfree(saif);
> +
> +	return ret;
> +}
> +
> +static int __devexit mxs_saif_remove(struct platform_device *pdev)
> +{
> +	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	struct mxs_saif *saif = platform_get_drvdata(pdev);
> +
> +	platform_device_unregister(saif->soc_platform_pdev);
> +
> +	snd_soc_unregister_dai(&pdev->dev);
> +
> +	iounmap(saif->base);
> +	release_mem_region(res->start, resource_size(res));
> +	free_irq(saif->irq, saif);
> +
> +	clk_disable(saif->clk);
> +	clk_put(saif->clk);
> +
> +	kfree(saif);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver mxs_saif_driver = {
> +	.probe = mxs_saif_probe,
> +	.remove = __devexit_p(mxs_saif_remove),
> +
> +	.driver = {
> +		.name = "mxs-saif",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +static int __init mxs_saif_init(void)
> +{
> +	return platform_driver_register(&mxs_saif_driver);
> +}
> +
> +static void __exit mxs_saif_exit(void)
> +{
> +	platform_driver_unregister(&mxs_saif_driver);
> +}
> +
> +module_init(mxs_saif_init);
> +module_exit(mxs_saif_exit);
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("MXS ASoC SAIF driver");
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
> new file mode 100644
> index 0000000..dd26b37
> --- /dev/null
> +++ b/sound/soc/mxs/mxs-saif.h
> @@ -0,0 +1,124 @@
> +/*
> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +
> +#ifndef _MXS_SAIF_H
> +#define _MXS_SAIF_H
> +
> +#define SAIF_CTRL	0x0
> +#define SAIF_STAT	0x10
> +#define SAIF_DATA	0x20
> +#define SAIF_VERSION	0X30
> +
> +/* SAIF_CTRL */
> +#define BM_SAIF_CTRL_SFTRST		0x80000000
> +#define BM_SAIF_CTRL_CLKGATE		0x40000000
> +#define BP_SAIF_CTRL_BITCLK_MULT_RATE	27
> +#define BM_SAIF_CTRL_BITCLK_MULT_RATE	0x38000000
> +#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
> +		(((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
> +#define BM_SAIF_CTRL_BITCLK_BASE_RATE	0x04000000
> +#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN	0x02000000
> +#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN	0x01000000
> +#define BP_SAIF_CTRL_RSRVD2		21
> +#define BM_SAIF_CTRL_RSRVD2		0x00E00000
> +
> +#define BP_SAIF_CTRL_DMAWAIT_COUNT	16
> +#define BM_SAIF_CTRL_DMAWAIT_COUNT	0x001F0000
> +#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
> +		(((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
> +#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
> +#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
> +#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
> +		(((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
> +#define BM_SAIF_CTRL_LRCLK_PULSE	0x00002000
> +#define BM_SAIF_CTRL_BIT_ORDER		0x00001000
> +#define BM_SAIF_CTRL_DELAY		0x00000800
> +#define BM_SAIF_CTRL_JUSTIFY		0x00000400
> +#define BM_SAIF_CTRL_LRCLK_POLARITY	0x00000200
> +#define BM_SAIF_CTRL_BITCLK_EDGE	0x00000100
> +#define BP_SAIF_CTRL_WORD_LENGTH	4
> +#define BM_SAIF_CTRL_WORD_LENGTH	0x000000F0
> +#define BF_SAIF_CTRL_WORD_LENGTH(v) \
> +		(((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
> +#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE	0x00000008
> +#define BM_SAIF_CTRL_SLAVE_MODE		0x00000004
> +#define BM_SAIF_CTRL_READ_MODE		0x00000002
> +#define BM_SAIF_CTRL_RUN		0x00000001
> +
> +/* SAIF_STAT */
> +#define BM_SAIF_STAT_PRESENT		0x80000000
> +#define BP_SAIF_STAT_RSRVD2		17
> +#define BM_SAIF_STAT_RSRVD2		0x7FFE0000
> +#define BF_SAIF_STAT_RSRVD2(v) \
> +		(((v) << 17) & BM_SAIF_STAT_RSRVD2)
> +#define BM_SAIF_STAT_DMA_PREQ		0x00010000
> +#define BP_SAIF_STAT_RSRVD1		7
> +#define BM_SAIF_STAT_RSRVD1		0x0000FF80
> +#define BF_SAIF_STAT_RSRVD1(v) \
> +		(((v) << 7) & BM_SAIF_STAT_RSRVD1)
> +
> +#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
> +#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ	0x00000020
> +#define BM_SAIF_STAT_FIFO_SERVICE_IRQ	0x00000010
> +#define BP_SAIF_STAT_RSRVD0		1
> +#define BM_SAIF_STAT_RSRVD0		0x0000000E
> +#define BF_SAIF_STAT_RSRVD0(v) \
> +		(((v) << 1) & BM_SAIF_STAT_RSRVD0)
> +#define BM_SAIF_STAT_BUSY		0x00000001
> +
> +/* SAFI_DATA */
> +#define BP_SAIF_DATA_PCM_RIGHT		16
> +#define BM_SAIF_DATA_PCM_RIGHT		0xFFFF0000
> +#define BF_SAIF_DATA_PCM_RIGHT(v) \
> +		(((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
> +#define BP_SAIF_DATA_PCM_LEFT		0
> +#define BM_SAIF_DATA_PCM_LEFT		0x0000FFFF
> +#define BF_SAIF_DATA_PCM_LEFT(v)	\
> +		(((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
> +
> +/* SAIF_VERSION */
> +#define BP_SAIF_VERSION_MAJOR		24
> +#define BM_SAIF_VERSION_MAJOR		0xFF000000
> +#define BF_SAIF_VERSION_MAJOR(v) \
> +		(((v) << 24) & BM_SAIF_VERSION_MAJOR)
> +#define BP_SAIF_VERSION_MINOR		16
> +#define BM_SAIF_VERSION_MINOR		0x00FF0000
> +#define BF_SAIF_VERSION_MINOR(v) \
> +		(((v) << 16) & BM_SAIF_VERSION_MINOR)
> +#define BP_SAIF_VERSION_STEP		0
> +#define BM_SAIF_VERSION_STEP		0x0000FFFF
> +#define BF_SAIF_VERSION_STEP(v) \
> +		(((v) << 0) & BM_SAIF_VERSION_STEP)
> +
> +#define MXS_SAIF_SYS_CLK	0
> +#define MXS_SAIF_MCLK		1
> +
> +#include "mxs-pcm.h"
> +
> +struct mxs_saif {
> +	struct clk *clk;
> +	void __iomem *base;
> +	int irq;
> +	struct mxs_pcm_dma_params dma_param;
> +
> +	struct platform_device *soc_platform_pdev;
> +	u32 fifo_err_counter;
> +};
> +
> +#endif
> -- 
> 1.7.0.4
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-08 16:19     ` Sascha Hauer
  0 siblings, 0 replies; 60+ messages in thread
From: Sascha Hauer @ 2011-07-08 16:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  sound/soc/mxs/mxs-saif.c |  524 ++++++++++++++++++++++++++++++++++++++++++++++
>  sound/soc/mxs/mxs-saif.h |  124 +++++++++++
>  2 files changed, 648 insertions(+), 0 deletions(-)
> 
> diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
> new file mode 100644
> index 0000000..afc6e57
> --- /dev/null
> +++ b/sound/soc/mxs/mxs-saif.c
> @@ -0,0 +1,524 @@
> +/*
> + * Copyright 2011 Freescale Semiconductor, Inc.
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <mach/dma.h>
> +#include <asm/mach-types.h>
> +#include <mach/hardware.h>
> +#include <mach/mx28.h>

Is this include really needed?

> +
> +#include "mxs-saif.h"
> +
> +/*
> +* SAIF system clock configuration.
> +* Should only be called when port is inactive.
> +*/
> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
> +			int clk_id, unsigned int freq, int dir)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	switch (clk_id) {
> +	case MXS_SAIF_SYS_CLK:
> +		clk_set_rate(saif->clk, freq);
> +		clk_enable(saif->clk);

This clk_enable is unbalanced. You enabled the clock in probe() already.

> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * SAIF Clock dividers
> + * Should only be called when port is inactive.
> + */
> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
> +				  int div_id, int div)
> +{
> +	u32 scr;
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	scr = __raw_readl(saif->base + SAIF_CTRL);
> +	scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
> +	scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +
> +	switch (div_id) {
> +	case MXS_SAIF_MCLK:
> +		switch (div) {
> +		case 32:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 64:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 128:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 256:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 512:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
> +			scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 48:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 96:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 192:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		case 384:
> +			scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
> +			scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	__raw_writel(scr, saif->base + SAIF_CTRL);
> +
> +	return 0;
> +}
> +
> +/*
> + * SAIF DAI format configuration.
> + * Should only be called when port is inactive.
> + * Note: We don't use the I2S modes but instead manually configure the
> + * SAIF for I2S.
> + */
> +static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
> +{
> +	u32 scr, stat;
> +	u32 scr0;
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	stat = __raw_readl(saif->base + SAIF_STAT);
> +	if (stat & BM_SAIF_STAT_BUSY)
> +		return 0;

Returning succesfully doesn't seem right here.

> +
> +	scr0 = __raw_readl(saif->base + SAIF_CTRL);
> +	scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
> +		& ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
> +	scr = 0;
> +
> +	/* DAI mode */
> +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> +	case SND_SOC_DAIFMT_I2S:
> +		/* data frame low 1clk before data */
> +		scr |= BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_LEFT_J:
> +		/* data frame high with data */
> +		scr &= ~BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		scr &= ~BM_SAIF_CTRL_JUSTIFY;
> +		break;

	default:
		return -EINVAL;

> +	}
> +
> +	/* DAI clock inversion */
> +	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> +	case SND_SOC_DAIFMT_IB_IF:
> +		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_IB_NF:
> +		scr |= BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_NB_IF:
> +		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_NB_NF:
> +		scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	}

A question more for Liam and Mark: Would it make sense to add individual
masks for the clock inversion and frame sync inversion? I code like the
above in every driver, and I think this could become simpler.


> +
> +	/*
> +	 * Note: We simply just support master mode since SAIF TX only supports
> +	 * master mode.
> +	 */

When this is true...

> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +		scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
> +		__raw_writel(scr | scr0, saif->base + SAIF_CTRL);
> +		break;
> +	case SND_SOC_DAIFMT_CBM_CFS:
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFM:
> +		break;

You should return an error here.

> +	case SND_SOC_DAIFMT_CBM_CFM:
> +		return -EINVAL;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
> +			   struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
> +
> +	return 0;
> +}
> +
> +/*
> + * Should only be called when port is inactive.
> + * although can be called multiple times by upper layers.
> + */
> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params,
> +			     struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	u32 scr;
> +
> +	scr = __raw_readl(saif->base + SAIF_CTRL);
> +
> +	/* cant change any parameters when SAIF is running */
> +	/* DAI data (word) size */
> +	scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
> +	scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
> +		break;
> +	case SNDRV_PCM_FORMAT_S20_3LE:
> +		scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
> +		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
> +		break;
> +	case SNDRV_PCM_FORMAT_S24_LE:
> +		scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
> +		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
> +		break;

	default:
		return -EINVAL;

> +	}
> +
> +	/* Tx/Rx config */
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		/* enable TX mode */
> +		scr &= ~BM_SAIF_CTRL_READ_MODE;
> +	} else {
> +		/* enable RX mode */
> +		scr |= BM_SAIF_CTRL_READ_MODE;
> +	}
> +
> +	__raw_writel(scr, saif->base + SAIF_CTRL);
> +	return 0;
> +}
> +
> +static int mxs_saif_prepare(struct snd_pcm_substream *substream,
> +			   struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	__raw_writel(BM_SAIF_CTRL_CLKGATE,
> +		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
> +
> +	return 0;
> +}
> +
> +static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
> +				struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +			/*write a data to saif data register to trigger
> +				the transfer*/

/* multiline comments
 * like this please
 */

> +			__raw_writel(0, saif->base + SAIF_DATA);
> +		else
> +			/*read a data from saif data register to trigger
> +				the receive*/
> +			__raw_readl(saif->base + SAIF_DATA);
> +		break;
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +#define MXS_SAIF_RATES		SNDRV_PCM_RATE_8000_192000
> +#define MXS_SAIF_FORMATS \
> +	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
> +	SNDRV_PCM_FMTBIT_S24_LE)
> +
> +static struct snd_soc_dai_ops mxs_saif_dai_ops = {
> +	.startup = mxs_saif_startup,
> +	.trigger = mxs_saif_trigger,
> +	.prepare = mxs_saif_prepare,
> +	.hw_params = mxs_saif_hw_params,
> +	.set_sysclk = mxs_saif_set_dai_sysclk,
> +	.set_clkdiv = mxs_saif_set_dai_clkdiv,
> +	.set_fmt = mxs_saif_set_dai_fmt,
> +};
> +
> +static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
> +{
> +	struct mxs_saif *saif = dev_get_drvdata(dai->dev);
> +
> +	snd_soc_dai_set_drvdata(dai, saif);
> +
> +	/* Reset */
> +	__raw_writel(BM_SAIF_CTRL_SFTRST,
> +		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
> +
> +	/* enable MCLK output early since codec may need it */
> +	__raw_writel(BM_SAIF_CTRL_CLKGATE,
> +		saif->base + SAIF_CTRL + MXS_CLR_ADDR);
> +	__raw_writel(BM_SAIF_CTRL_RUN,
> +		saif->base + SAIF_CTRL + MXS_SET_ADDR);
> +
> +	return 0;
> +}
> +
> +static struct snd_soc_dai_driver mxs_saif_dai = {
> +	.name = "mxs-saif",
> +	.probe = mxs_saif_dai_probe,
> +	.playback = {
> +		.channels_min = 2,
> +		.channels_max = 2,
> +		.rates = MXS_SAIF_RATES,
> +		.formats = MXS_SAIF_FORMATS,
> +	},
> +	.capture = {
> +		.channels_min = 2,
> +		.channels_max = 2,
> +		.rates = MXS_SAIF_RATES,
> +		.formats = MXS_SAIF_FORMATS,
> +	},
> +	.ops = &mxs_saif_dai_ops,
> +};
> +
> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
> +{
> +	struct mxs_saif *saif = dev_id;
> +
> +	if (saif->fifo_err_counter++ % 100 == 0)
> +		printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
> +			fifo_errs=%d \n",
> +		       __raw_readl(saif->base + SAIF_STAT),
> +		       __raw_readl(saif->base + SAIF_CTRL),
> +		       saif->fifo_err_counter);
> +	__raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
> +			BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
> +			saif->base + SAIF_STAT + MXS_CLR_ADDR);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int mxs_saif_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct mxs_saif *saif;
> +	int ret = 0;
> +
> +	saif = kzalloc(sizeof(*saif), GFP_KERNEL);
> +	if (!saif)
> +		return -ENOMEM;

Consider using devm_kzalloc and friends, it makes the error path less
error prone.

> +
> +	saif->irq = platform_get_irq(pdev, 0);
> +	if (saif->irq < 0) {
> +		ret = saif->irq;
> +		dev_err(&pdev->dev, "failed to get irq resource: %d\n",
> +			ret);
> +		goto failed_get_irq1;
> +	}
> +
> +	saif->fifo_err_counter = 0;
> +	ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to request irq\n");
> +		goto failed_req_irq;
> +	}
> +
> +	saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
> +	if (saif->dma_param.chan_irq < 0) {
> +		ret = saif->dma_param.chan_irq;
> +		dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
> +			ret);
> +		goto failed_get_irq2;
> +	}
> +
> +	saif->clk = clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(saif->clk)) {
> +		ret = PTR_ERR(saif->clk);
> +		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
> +			ret);
> +		goto failed_clk;
> +	}
> +	clk_set_rate(saif->clk, 12000000);
> +	clk_enable(saif->clk);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		ret = -ENODEV;
> +		dev_err(&pdev->dev, "failed to get io resource: %d\n",
> +			ret);
> +		goto failed_get_resource;
> +	}
> +
> +	if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) {
> +		dev_err(&pdev->dev, "request_mem_region failed\n");
> +		ret = -EBUSY;
> +		goto failed_get_resource;
> +	}
> +
> +	saif->base = ioremap(res->start, resource_size(res));
> +	if (!saif->base) {
> +		dev_err(&pdev->dev, "ioremap failed\n");
> +		ret = -ENODEV;
> +		goto failed_ioremap;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
> +	if (!res) {
> +		ret = -ENODEV;
> +		dev_err(&pdev->dev, "failed to get dma resource: %d\n",
> +			ret);
> +		goto failed_get_resource;
> +	}
> +	saif->dma_param.chan_num = res->start;
> +
> +	platform_set_drvdata(pdev, saif);
> +
> +	ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
> +	if (ret) {
> +		dev_err(&pdev->dev, "register DAI failed\n");
> +		goto failed_register;
> +	}
> +
> +	saif->soc_platform_pdev = platform_device_alloc(
> +					"mxs-pcm-audio", pdev->id);
> +	if (!saif->soc_platform_pdev) {
> +		ret = -ENOMEM;
> +		goto failed_pdev_alloc;
> +	}
> +
> +	platform_set_drvdata(saif->soc_platform_pdev, saif);
> +	ret = platform_device_add(saif->soc_platform_pdev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to add soc platform device\n");
> +		goto failed_pdev_add;
> +	}
> +
> +	return 0;
> +
> +failed_pdev_add:
> +	platform_device_put(saif->soc_platform_pdev);
> +failed_pdev_alloc:
> +	snd_soc_unregister_dai(&pdev->dev);
> +failed_register:
> +	iounmap(saif->base);
> +failed_ioremap:
> +	release_mem_region(res->start, resource_size(res));
> +failed_get_resource:
> +	clk_disable(saif->clk);
> +	clk_put(saif->clk);
> +failed_clk:
> +failed_get_irq2:
> +	free_irq(saif->irq, saif);
> +failed_req_irq:
> +failed_get_irq1:
> +	kfree(saif);
> +
> +	return ret;
> +}
> +
> +static int __devexit mxs_saif_remove(struct platform_device *pdev)
> +{
> +	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	struct mxs_saif *saif = platform_get_drvdata(pdev);
> +
> +	platform_device_unregister(saif->soc_platform_pdev);
> +
> +	snd_soc_unregister_dai(&pdev->dev);
> +
> +	iounmap(saif->base);
> +	release_mem_region(res->start, resource_size(res));
> +	free_irq(saif->irq, saif);
> +
> +	clk_disable(saif->clk);
> +	clk_put(saif->clk);
> +
> +	kfree(saif);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver mxs_saif_driver = {
> +	.probe = mxs_saif_probe,
> +	.remove = __devexit_p(mxs_saif_remove),
> +
> +	.driver = {
> +		.name = "mxs-saif",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +static int __init mxs_saif_init(void)
> +{
> +	return platform_driver_register(&mxs_saif_driver);
> +}
> +
> +static void __exit mxs_saif_exit(void)
> +{
> +	platform_driver_unregister(&mxs_saif_driver);
> +}
> +
> +module_init(mxs_saif_init);
> +module_exit(mxs_saif_exit);
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("MXS ASoC SAIF driver");
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
> new file mode 100644
> index 0000000..dd26b37
> --- /dev/null
> +++ b/sound/soc/mxs/mxs-saif.h
> @@ -0,0 +1,124 @@
> +/*
> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +
> +#ifndef _MXS_SAIF_H
> +#define _MXS_SAIF_H
> +
> +#define SAIF_CTRL	0x0
> +#define SAIF_STAT	0x10
> +#define SAIF_DATA	0x20
> +#define SAIF_VERSION	0X30
> +
> +/* SAIF_CTRL */
> +#define BM_SAIF_CTRL_SFTRST		0x80000000
> +#define BM_SAIF_CTRL_CLKGATE		0x40000000
> +#define BP_SAIF_CTRL_BITCLK_MULT_RATE	27
> +#define BM_SAIF_CTRL_BITCLK_MULT_RATE	0x38000000
> +#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
> +		(((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
> +#define BM_SAIF_CTRL_BITCLK_BASE_RATE	0x04000000
> +#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN	0x02000000
> +#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN	0x01000000
> +#define BP_SAIF_CTRL_RSRVD2		21
> +#define BM_SAIF_CTRL_RSRVD2		0x00E00000
> +
> +#define BP_SAIF_CTRL_DMAWAIT_COUNT	16
> +#define BM_SAIF_CTRL_DMAWAIT_COUNT	0x001F0000
> +#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
> +		(((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
> +#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
> +#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
> +#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
> +		(((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
> +#define BM_SAIF_CTRL_LRCLK_PULSE	0x00002000
> +#define BM_SAIF_CTRL_BIT_ORDER		0x00001000
> +#define BM_SAIF_CTRL_DELAY		0x00000800
> +#define BM_SAIF_CTRL_JUSTIFY		0x00000400
> +#define BM_SAIF_CTRL_LRCLK_POLARITY	0x00000200
> +#define BM_SAIF_CTRL_BITCLK_EDGE	0x00000100
> +#define BP_SAIF_CTRL_WORD_LENGTH	4
> +#define BM_SAIF_CTRL_WORD_LENGTH	0x000000F0
> +#define BF_SAIF_CTRL_WORD_LENGTH(v) \
> +		(((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
> +#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE	0x00000008
> +#define BM_SAIF_CTRL_SLAVE_MODE		0x00000004
> +#define BM_SAIF_CTRL_READ_MODE		0x00000002
> +#define BM_SAIF_CTRL_RUN		0x00000001
> +
> +/* SAIF_STAT */
> +#define BM_SAIF_STAT_PRESENT		0x80000000
> +#define BP_SAIF_STAT_RSRVD2		17
> +#define BM_SAIF_STAT_RSRVD2		0x7FFE0000
> +#define BF_SAIF_STAT_RSRVD2(v) \
> +		(((v) << 17) & BM_SAIF_STAT_RSRVD2)
> +#define BM_SAIF_STAT_DMA_PREQ		0x00010000
> +#define BP_SAIF_STAT_RSRVD1		7
> +#define BM_SAIF_STAT_RSRVD1		0x0000FF80
> +#define BF_SAIF_STAT_RSRVD1(v) \
> +		(((v) << 7) & BM_SAIF_STAT_RSRVD1)
> +
> +#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
> +#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ	0x00000020
> +#define BM_SAIF_STAT_FIFO_SERVICE_IRQ	0x00000010
> +#define BP_SAIF_STAT_RSRVD0		1
> +#define BM_SAIF_STAT_RSRVD0		0x0000000E
> +#define BF_SAIF_STAT_RSRVD0(v) \
> +		(((v) << 1) & BM_SAIF_STAT_RSRVD0)
> +#define BM_SAIF_STAT_BUSY		0x00000001
> +
> +/* SAFI_DATA */
> +#define BP_SAIF_DATA_PCM_RIGHT		16
> +#define BM_SAIF_DATA_PCM_RIGHT		0xFFFF0000
> +#define BF_SAIF_DATA_PCM_RIGHT(v) \
> +		(((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
> +#define BP_SAIF_DATA_PCM_LEFT		0
> +#define BM_SAIF_DATA_PCM_LEFT		0x0000FFFF
> +#define BF_SAIF_DATA_PCM_LEFT(v)	\
> +		(((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
> +
> +/* SAIF_VERSION */
> +#define BP_SAIF_VERSION_MAJOR		24
> +#define BM_SAIF_VERSION_MAJOR		0xFF000000
> +#define BF_SAIF_VERSION_MAJOR(v) \
> +		(((v) << 24) & BM_SAIF_VERSION_MAJOR)
> +#define BP_SAIF_VERSION_MINOR		16
> +#define BM_SAIF_VERSION_MINOR		0x00FF0000
> +#define BF_SAIF_VERSION_MINOR(v) \
> +		(((v) << 16) & BM_SAIF_VERSION_MINOR)
> +#define BP_SAIF_VERSION_STEP		0
> +#define BM_SAIF_VERSION_STEP		0x0000FFFF
> +#define BF_SAIF_VERSION_STEP(v) \
> +		(((v) << 0) & BM_SAIF_VERSION_STEP)
> +
> +#define MXS_SAIF_SYS_CLK	0
> +#define MXS_SAIF_MCLK		1
> +
> +#include "mxs-pcm.h"
> +
> +struct mxs_saif {
> +	struct clk *clk;
> +	void __iomem *base;
> +	int irq;
> +	struct mxs_pcm_dma_params dma_param;
> +
> +	struct platform_device *soc_platform_pdev;
> +	u32 fifo_err_counter;
> +};
> +
> +#endif
> -- 
> 1.7.0.4
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-08 16:19     ` Sascha Hauer
@ 2011-07-08 17:10       ` Wolfram Sang
  -1 siblings, 0 replies; 60+ messages in thread
From: Wolfram Sang @ 2011-07-08 17:10 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: alsa-devel, Dong Aisheng, lrg, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 344 bytes --]


> > +			/*write a data to saif data register to trigger
> > +				the transfer*/
> 
> /* multiline comments
>  * like this please
>  */

/*
 * Actually,
 * like this :)
 */

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

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

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-08 17:10       ` Wolfram Sang
  0 siblings, 0 replies; 60+ messages in thread
From: Wolfram Sang @ 2011-07-08 17:10 UTC (permalink / raw)
  To: linux-arm-kernel


> > +			/*write a data to saif data register to trigger
> > +				the transfer*/
> 
> /* multiline comments
>  * like this please
>  */

/*
 * Actually,
 * like this :)
 */

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110708/25e7ddeb/attachment.sig>

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-08 16:19     ` Sascha Hauer
@ 2011-07-08 18:35       ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 18:35 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: alsa-devel, Dong Aisheng, lrg, linux-arm-kernel

2011/7/9 Sascha Hauer <s.hauer@pengutronix.de>:
> On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>> ---
>>  sound/soc/mxs/mxs-saif.c |  524 ++++++++++++++++++++++++++++++++++++++++++++++
>>  sound/soc/mxs/mxs-saif.h |  124 +++++++++++
>>  2 files changed, 648 insertions(+), 0 deletions(-)
>>
>> diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
>> new file mode 100644
>> index 0000000..afc6e57
>> --- /dev/null
>> +++ b/sound/soc/mxs/mxs-saif.c
>> @@ -0,0 +1,524 @@
>> +/*
>> + * Copyright 2011 Freescale Semiconductor, Inc.
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, write to the Free Software Foundation, Inc.,
>> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/dma-mapping.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <sound/core.h>
>> +#include <sound/pcm.h>
>> +#include <sound/pcm_params.h>
>> +#include <sound/soc.h>
>> +#include <mach/dma.h>
>> +#include <asm/mach-types.h>
>> +#include <mach/hardware.h>
>> +#include <mach/mx28.h>
>
> Is this include really needed?
Thanks a lot for your quick review.
i checked and it's not needed.
Including mxs.h would be ok for using MXS_CLR_ADDR.

>> +
>> +#include "mxs-saif.h"
>> +
>> +/*
>> +* SAIF system clock configuration.
>> +* Should only be called when port is inactive.
>> +*/
>> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
>> +                     int clk_id, unsigned int freq, int dir)
>> +{
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> +     switch (clk_id) {
>> +     case MXS_SAIF_SYS_CLK:
>> +             clk_set_rate(saif->clk, freq);
>> +             clk_enable(saif->clk);
>
> This clk_enable is unbalanced. You enabled the clock in probe() already.
Yes, will fix it.

>> +             break;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +     return 0;
>> +}
>> +
>> +/*
>> + * SAIF Clock dividers
>> + * Should only be called when port is inactive.
>> + */
>> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
>> +                               int div_id, int div)
>> +{
>> +     u32 scr;
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> +     scr = __raw_readl(saif->base + SAIF_CTRL);
>> +     scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
>> +     scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +
>> +     switch (div_id) {
>> +     case MXS_SAIF_MCLK:
>> +             switch (div) {
>> +             case 32:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
>> +                     scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 64:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
>> +                     scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 128:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
>> +                     scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 256:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
>> +                     scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 512:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
>> +                     scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 48:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
>> +                     scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 96:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
>> +                     scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 192:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
>> +                     scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             case 384:
>> +                     scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
>> +                     scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +                     break;
>> +             default:
>> +                     return -EINVAL;
>> +             }
>> +             break;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     __raw_writel(scr, saif->base + SAIF_CTRL);
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * SAIF DAI format configuration.
>> + * Should only be called when port is inactive.
>> + * Note: We don't use the I2S modes but instead manually configure the
>> + * SAIF for I2S.
>> + */
>> +static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
>> +{
>> +     u32 scr, stat;
>> +     u32 scr0;
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> +     stat = __raw_readl(saif->base + SAIF_STAT);
>> +     if (stat & BM_SAIF_STAT_BUSY)
>> +             return 0;
>
> Returning succesfully doesn't seem right here.
Will replace with -EBUSY.

>> +
>> +     scr0 = __raw_readl(saif->base + SAIF_CTRL);
>> +     scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
>> +             & ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
>> +     scr = 0;
>> +
>> +     /* DAI mode */
>> +     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
>> +     case SND_SOC_DAIFMT_I2S:
>> +             /* data frame low 1clk before data */
>> +             scr |= BM_SAIF_CTRL_DELAY;
>> +             scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             break;
>> +     case SND_SOC_DAIFMT_LEFT_J:
>> +             /* data frame high with data */
>> +             scr &= ~BM_SAIF_CTRL_DELAY;
>> +             scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             scr &= ~BM_SAIF_CTRL_JUSTIFY;
>> +             break;
>
>        default:
>                return -EINVAL;
Will add.

>> +     }
>> +
>> +     /* DAI clock inversion */
>> +     switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>> +     case SND_SOC_DAIFMT_IB_IF:
>> +             scr |= BM_SAIF_CTRL_BITCLK_EDGE;
>> +             scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             break;
>> +     case SND_SOC_DAIFMT_IB_NF:
>> +             scr |= BM_SAIF_CTRL_BITCLK_EDGE;
>> +             scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             break;
>> +     case SND_SOC_DAIFMT_NB_IF:
>> +             scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
>> +             scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             break;
>> +     case SND_SOC_DAIFMT_NB_NF:
>> +             scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
>> +             scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             break;
>> +     }
>
> A question more for Liam and Mark: Would it make sense to add individual
> masks for the clock inversion and frame sync inversion? I code like the
> above in every driver, and I think this could become simpler.
>
>
>> +
>> +     /*
>> +      * Note: We simply just support master mode since SAIF TX only supports
>> +      * master mode.
>> +      */
>
> When this is true...
It's hw limitation.
Defined in MX28 spec 35.2.1.
i quote it as follows;
For transmit, BITCLK and LRCLK are always driven by the SAIF.
...
Coniguring the SAIF for transmit makes it the master by default.
....

>> +     switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>> +     case SND_SOC_DAIFMT_CBS_CFS:
>> +             scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
>> +             __raw_writel(scr | scr0, saif->base + SAIF_CTRL);
>> +             break;
>> +     case SND_SOC_DAIFMT_CBM_CFS:
>> +             break;
>> +     case SND_SOC_DAIFMT_CBS_CFM:
>> +             break;
>
> You should return an error here.
Will add.

>> +     case SND_SOC_DAIFMT_CBM_CFM:
>> +             return -EINVAL;
>> +             break;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
>> +                        struct snd_soc_dai *cpu_dai)
>> +{
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +     snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
>> +
>> +     return 0;
>> +}
>> +
>> +/*
>> + * Should only be called when port is inactive.
>> + * although can be called multiple times by upper layers.
>> + */
>> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
>> +                          struct snd_pcm_hw_params *params,
>> +                          struct snd_soc_dai *cpu_dai)
>> +{
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +     u32 scr;
>> +
>> +     scr = __raw_readl(saif->base + SAIF_CTRL);
>> +
>> +     /* cant change any parameters when SAIF is running */
>> +     /* DAI data (word) size */
>> +     scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
>> +     scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
>> +     switch (params_format(params)) {
>> +     case SNDRV_PCM_FORMAT_S16_LE:
>> +             scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
>> +             break;
>> +     case SNDRV_PCM_FORMAT_S20_3LE:
>> +             scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
>> +             scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
>> +             break;
>> +     case SNDRV_PCM_FORMAT_S24_LE:
>> +             scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
>> +             scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
>> +             break;
>
>        default:
>                return -EINVAL;
Will add.

>> +     }
>> +
>> +     /* Tx/Rx config */
>> +     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> +             /* enable TX mode */
>> +             scr &= ~BM_SAIF_CTRL_READ_MODE;
>> +     } else {
>> +             /* enable RX mode */
>> +             scr |= BM_SAIF_CTRL_READ_MODE;
>> +     }
>> +
>> +     __raw_writel(scr, saif->base + SAIF_CTRL);
>> +     return 0;
>> +}
>> +
>> +static int mxs_saif_prepare(struct snd_pcm_substream *substream,
>> +                        struct snd_soc_dai *cpu_dai)
>> +{
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +     __raw_writel(BM_SAIF_CTRL_CLKGATE,
>> +             saif->base + SAIF_CTRL + MXS_CLR_ADDR);
>> +
>> +     return 0;
>> +}
>> +
>> +static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
>> +                             struct snd_soc_dai *cpu_dai)
>> +{
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> +     switch (cmd) {
>> +     case SNDRV_PCM_TRIGGER_START:
>> +     case SNDRV_PCM_TRIGGER_RESUME:
>> +     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> +             if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
>> +                     /*write a data to saif data register to trigger
>> +                             the transfer*/
>
> /* multiline comments
>  * like this please
>  */
Got it.

>> +                     __raw_writel(0, saif->base + SAIF_DATA);
>> +             else
>> +                     /*read a data from saif data register to trigger
>> +                             the receive*/
>> +                     __raw_readl(saif->base + SAIF_DATA);
>> +             break;
>> +     case SNDRV_PCM_TRIGGER_SUSPEND:
>> +     case SNDRV_PCM_TRIGGER_STOP:
>> +     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>> +             break;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +#define MXS_SAIF_RATES               SNDRV_PCM_RATE_8000_192000
>> +#define MXS_SAIF_FORMATS \
>> +     (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
>> +     SNDRV_PCM_FMTBIT_S24_LE)
>> +
>> +static struct snd_soc_dai_ops mxs_saif_dai_ops = {
>> +     .startup = mxs_saif_startup,
>> +     .trigger = mxs_saif_trigger,
>> +     .prepare = mxs_saif_prepare,
>> +     .hw_params = mxs_saif_hw_params,
>> +     .set_sysclk = mxs_saif_set_dai_sysclk,
>> +     .set_clkdiv = mxs_saif_set_dai_clkdiv,
>> +     .set_fmt = mxs_saif_set_dai_fmt,
>> +};
>> +
>> +static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
>> +{
>> +     struct mxs_saif *saif = dev_get_drvdata(dai->dev);
>> +
>> +     snd_soc_dai_set_drvdata(dai, saif);
>> +
>> +     /* Reset */
>> +     __raw_writel(BM_SAIF_CTRL_SFTRST,
>> +             saif->base + SAIF_CTRL + MXS_CLR_ADDR);
>> +
>> +     /* enable MCLK output early since codec may need it */
>> +     __raw_writel(BM_SAIF_CTRL_CLKGATE,
>> +             saif->base + SAIF_CTRL + MXS_CLR_ADDR);
>> +     __raw_writel(BM_SAIF_CTRL_RUN,
>> +             saif->base + SAIF_CTRL + MXS_SET_ADDR);
>> +
>> +     return 0;
>> +}
>> +
>> +static struct snd_soc_dai_driver mxs_saif_dai = {
>> +     .name = "mxs-saif",
>> +     .probe = mxs_saif_dai_probe,
>> +     .playback = {
>> +             .channels_min = 2,
>> +             .channels_max = 2,
>> +             .rates = MXS_SAIF_RATES,
>> +             .formats = MXS_SAIF_FORMATS,
>> +     },
>> +     .capture = {
>> +             .channels_min = 2,
>> +             .channels_max = 2,
>> +             .rates = MXS_SAIF_RATES,
>> +             .formats = MXS_SAIF_FORMATS,
>> +     },
>> +     .ops = &mxs_saif_dai_ops,
>> +};
>> +
>> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
>> +{
>> +     struct mxs_saif *saif = dev_id;
>> +
>> +     if (saif->fifo_err_counter++ % 100 == 0)
>> +             printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
>> +                     fifo_errs=%d \n",
>> +                    __raw_readl(saif->base + SAIF_STAT),
>> +                    __raw_readl(saif->base + SAIF_CTRL),
>> +                    saif->fifo_err_counter);
>> +     __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
>> +                     BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
>> +                     saif->base + SAIF_STAT + MXS_CLR_ADDR);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +static int mxs_saif_probe(struct platform_device *pdev)
>> +{
>> +     struct resource *res;
>> +     struct mxs_saif *saif;
>> +     int ret = 0;
>> +
>> +     saif = kzalloc(sizeof(*saif), GFP_KERNEL);
>> +     if (!saif)
>> +             return -ENOMEM;
>
> Consider using devm_kzalloc and friends, it makes the error path less
> error prone.
Will use it. Thanks for the suggestion.

>> +
>> +     saif->irq = platform_get_irq(pdev, 0);
>> +     if (saif->irq < 0) {
>> +             ret = saif->irq;
>> +             dev_err(&pdev->dev, "failed to get irq resource: %d\n",
>> +                     ret);
>> +             goto failed_get_irq1;
>> +     }
>> +
>> +     saif->fifo_err_counter = 0;
>> +     ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
>> +     if (ret) {
>> +             dev_err(&pdev->dev, "failed to request irq\n");
>> +             goto failed_req_irq;
>> +     }
>> +
>> +     saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
>> +     if (saif->dma_param.chan_irq < 0) {
>> +             ret = saif->dma_param.chan_irq;
>> +             dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
>> +                     ret);
>> +             goto failed_get_irq2;
>> +     }
>> +
>> +     saif->clk = clk_get(&pdev->dev, NULL);
>> +     if (IS_ERR(saif->clk)) {
>> +             ret = PTR_ERR(saif->clk);
>> +             dev_err(&pdev->dev, "Cannot get the clock: %d\n",
>> +                     ret);
>> +             goto failed_clk;
>> +     }
>> +     clk_set_rate(saif->clk, 12000000);
>> +     clk_enable(saif->clk);
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     if (!res) {
>> +             ret = -ENODEV;
>> +             dev_err(&pdev->dev, "failed to get io resource: %d\n",
>> +                     ret);
>> +             goto failed_get_resource;
>> +     }
>> +
>> +     if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) {
>> +             dev_err(&pdev->dev, "request_mem_region failed\n");
>> +             ret = -EBUSY;
>> +             goto failed_get_resource;
>> +     }
>> +
>> +     saif->base = ioremap(res->start, resource_size(res));
>> +     if (!saif->base) {
>> +             dev_err(&pdev->dev, "ioremap failed\n");
>> +             ret = -ENODEV;
>> +             goto failed_ioremap;
>> +     }
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
>> +     if (!res) {
>> +             ret = -ENODEV;
>> +             dev_err(&pdev->dev, "failed to get dma resource: %d\n",
>> +                     ret);
>> +             goto failed_get_resource;
>> +     }
>> +     saif->dma_param.chan_num = res->start;
>> +
>> +     platform_set_drvdata(pdev, saif);
>> +
>> +     ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
>> +     if (ret) {
>> +             dev_err(&pdev->dev, "register DAI failed\n");
>> +             goto failed_register;
>> +     }
>> +
>> +     saif->soc_platform_pdev = platform_device_alloc(
>> +                                     "mxs-pcm-audio", pdev->id);
>> +     if (!saif->soc_platform_pdev) {
>> +             ret = -ENOMEM;
>> +             goto failed_pdev_alloc;
>> +     }
>> +
>> +     platform_set_drvdata(saif->soc_platform_pdev, saif);
>> +     ret = platform_device_add(saif->soc_platform_pdev);
>> +     if (ret) {
>> +             dev_err(&pdev->dev, "failed to add soc platform device\n");
>> +             goto failed_pdev_add;
>> +     }
>> +
>> +     return 0;
>> +
>> +failed_pdev_add:
>> +     platform_device_put(saif->soc_platform_pdev);
>> +failed_pdev_alloc:
>> +     snd_soc_unregister_dai(&pdev->dev);
>> +failed_register:
>> +     iounmap(saif->base);
>> +failed_ioremap:
>> +     release_mem_region(res->start, resource_size(res));
>> +failed_get_resource:
>> +     clk_disable(saif->clk);
>> +     clk_put(saif->clk);
>> +failed_clk:
>> +failed_get_irq2:
>> +     free_irq(saif->irq, saif);
>> +failed_req_irq:
>> +failed_get_irq1:
>> +     kfree(saif);
>> +
>> +     return ret;
>> +}
>> +
>> +static int __devexit mxs_saif_remove(struct platform_device *pdev)
>> +{
>> +     struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     struct mxs_saif *saif = platform_get_drvdata(pdev);
>> +
>> +     platform_device_unregister(saif->soc_platform_pdev);
>> +
>> +     snd_soc_unregister_dai(&pdev->dev);
>> +
>> +     iounmap(saif->base);
>> +     release_mem_region(res->start, resource_size(res));
>> +     free_irq(saif->irq, saif);
>> +
>> +     clk_disable(saif->clk);
>> +     clk_put(saif->clk);
>> +
>> +     kfree(saif);
>> +
>> +     return 0;
>> +}
>> +
>> +static struct platform_driver mxs_saif_driver = {
>> +     .probe = mxs_saif_probe,
>> +     .remove = __devexit_p(mxs_saif_remove),
>> +
>> +     .driver = {
>> +             .name = "mxs-saif",
>> +             .owner = THIS_MODULE,
>> +     },
>> +};
>> +
>> +static int __init mxs_saif_init(void)
>> +{
>> +     return platform_driver_register(&mxs_saif_driver);
>> +}
>> +
>> +static void __exit mxs_saif_exit(void)
>> +{
>> +     platform_driver_unregister(&mxs_saif_driver);
>> +}
>> +
>> +module_init(mxs_saif_init);
>> +module_exit(mxs_saif_exit);
>> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
>> +MODULE_DESCRIPTION("MXS ASoC SAIF driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
>> new file mode 100644
>> index 0000000..dd26b37
>> --- /dev/null
>> +++ b/sound/soc/mxs/mxs-saif.h
>> @@ -0,0 +1,124 @@
>> +/*
>> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, write to the Free Software Foundation, Inc.,
>> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>> + */
>> +
>> +
>> +#ifndef _MXS_SAIF_H
>> +#define _MXS_SAIF_H
>> +
>> +#define SAIF_CTRL    0x0
>> +#define SAIF_STAT    0x10
>> +#define SAIF_DATA    0x20
>> +#define SAIF_VERSION 0X30
>> +
>> +/* SAIF_CTRL */
>> +#define BM_SAIF_CTRL_SFTRST          0x80000000
>> +#define BM_SAIF_CTRL_CLKGATE         0x40000000
>> +#define BP_SAIF_CTRL_BITCLK_MULT_RATE        27
>> +#define BM_SAIF_CTRL_BITCLK_MULT_RATE        0x38000000
>> +#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
>> +             (((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
>> +#define BM_SAIF_CTRL_BITCLK_BASE_RATE        0x04000000
>> +#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN       0x02000000
>> +#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN     0x01000000
>> +#define BP_SAIF_CTRL_RSRVD2          21
>> +#define BM_SAIF_CTRL_RSRVD2          0x00E00000
>> +
>> +#define BP_SAIF_CTRL_DMAWAIT_COUNT   16
>> +#define BM_SAIF_CTRL_DMAWAIT_COUNT   0x001F0000
>> +#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
>> +             (((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
>> +#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
>> +#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
>> +#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
>> +             (((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
>> +#define BM_SAIF_CTRL_LRCLK_PULSE     0x00002000
>> +#define BM_SAIF_CTRL_BIT_ORDER               0x00001000
>> +#define BM_SAIF_CTRL_DELAY           0x00000800
>> +#define BM_SAIF_CTRL_JUSTIFY         0x00000400
>> +#define BM_SAIF_CTRL_LRCLK_POLARITY  0x00000200
>> +#define BM_SAIF_CTRL_BITCLK_EDGE     0x00000100
>> +#define BP_SAIF_CTRL_WORD_LENGTH     4
>> +#define BM_SAIF_CTRL_WORD_LENGTH     0x000000F0
>> +#define BF_SAIF_CTRL_WORD_LENGTH(v) \
>> +             (((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
>> +#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE     0x00000008
>> +#define BM_SAIF_CTRL_SLAVE_MODE              0x00000004
>> +#define BM_SAIF_CTRL_READ_MODE               0x00000002
>> +#define BM_SAIF_CTRL_RUN             0x00000001
>> +
>> +/* SAIF_STAT */
>> +#define BM_SAIF_STAT_PRESENT         0x80000000
>> +#define BP_SAIF_STAT_RSRVD2          17
>> +#define BM_SAIF_STAT_RSRVD2          0x7FFE0000
>> +#define BF_SAIF_STAT_RSRVD2(v) \
>> +             (((v) << 17) & BM_SAIF_STAT_RSRVD2)
>> +#define BM_SAIF_STAT_DMA_PREQ                0x00010000
>> +#define BP_SAIF_STAT_RSRVD1          7
>> +#define BM_SAIF_STAT_RSRVD1          0x0000FF80
>> +#define BF_SAIF_STAT_RSRVD1(v) \
>> +             (((v) << 7) & BM_SAIF_STAT_RSRVD1)
>> +
>> +#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
>> +#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ       0x00000020
>> +#define BM_SAIF_STAT_FIFO_SERVICE_IRQ        0x00000010
>> +#define BP_SAIF_STAT_RSRVD0          1
>> +#define BM_SAIF_STAT_RSRVD0          0x0000000E
>> +#define BF_SAIF_STAT_RSRVD0(v) \
>> +             (((v) << 1) & BM_SAIF_STAT_RSRVD0)
>> +#define BM_SAIF_STAT_BUSY            0x00000001
>> +
>> +/* SAFI_DATA */
>> +#define BP_SAIF_DATA_PCM_RIGHT               16
>> +#define BM_SAIF_DATA_PCM_RIGHT               0xFFFF0000
>> +#define BF_SAIF_DATA_PCM_RIGHT(v) \
>> +             (((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
>> +#define BP_SAIF_DATA_PCM_LEFT                0
>> +#define BM_SAIF_DATA_PCM_LEFT                0x0000FFFF
>> +#define BF_SAIF_DATA_PCM_LEFT(v)     \
>> +             (((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
>> +
>> +/* SAIF_VERSION */
>> +#define BP_SAIF_VERSION_MAJOR                24
>> +#define BM_SAIF_VERSION_MAJOR                0xFF000000
>> +#define BF_SAIF_VERSION_MAJOR(v) \
>> +             (((v) << 24) & BM_SAIF_VERSION_MAJOR)
>> +#define BP_SAIF_VERSION_MINOR                16
>> +#define BM_SAIF_VERSION_MINOR                0x00FF0000
>> +#define BF_SAIF_VERSION_MINOR(v) \
>> +             (((v) << 16) & BM_SAIF_VERSION_MINOR)
>> +#define BP_SAIF_VERSION_STEP         0
>> +#define BM_SAIF_VERSION_STEP         0x0000FFFF
>> +#define BF_SAIF_VERSION_STEP(v) \
>> +             (((v) << 0) & BM_SAIF_VERSION_STEP)
>> +
>> +#define MXS_SAIF_SYS_CLK     0
>> +#define MXS_SAIF_MCLK                1
>> +
>> +#include "mxs-pcm.h"
>> +
>> +struct mxs_saif {
>> +     struct clk *clk;
>> +     void __iomem *base;
>> +     int irq;
>> +     struct mxs_pcm_dma_params dma_param;
>> +
>> +     struct platform_device *soc_platform_pdev;
>> +     u32 fifo_err_counter;
>> +};
>> +
>> +#endif
>> --
>> 1.7.0.4
>>
>>
>>
>
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-08 18:35       ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-08 18:35 UTC (permalink / raw)
  To: linux-arm-kernel

2011/7/9 Sascha Hauer <s.hauer@pengutronix.de>:
> On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>> ---
>> ?sound/soc/mxs/mxs-saif.c | ?524 ++++++++++++++++++++++++++++++++++++++++++++++
>> ?sound/soc/mxs/mxs-saif.h | ?124 +++++++++++
>> ?2 files changed, 648 insertions(+), 0 deletions(-)
>>
>> diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
>> new file mode 100644
>> index 0000000..afc6e57
>> --- /dev/null
>> +++ b/sound/soc/mxs/mxs-saif.c
>> @@ -0,0 +1,524 @@
>> +/*
>> + * Copyright 2011 Freescale Semiconductor, Inc.
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, write to the Free Software Foundation, Inc.,
>> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/dma-mapping.h>
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <sound/core.h>
>> +#include <sound/pcm.h>
>> +#include <sound/pcm_params.h>
>> +#include <sound/soc.h>
>> +#include <mach/dma.h>
>> +#include <asm/mach-types.h>
>> +#include <mach/hardware.h>
>> +#include <mach/mx28.h>
>
> Is this include really needed?
Thanks a lot for your quick review.
i checked and it's not needed.
Including mxs.h would be ok for using MXS_CLR_ADDR.

>> +
>> +#include "mxs-saif.h"
>> +
>> +/*
>> +* SAIF system clock configuration.
>> +* Should only be called when port is inactive.
>> +*/
>> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
>> + ? ? ? ? ? ? ? ? ? ? int clk_id, unsigned int freq, int dir)
>> +{
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> + ? ? switch (clk_id) {
>> + ? ? case MXS_SAIF_SYS_CLK:
>> + ? ? ? ? ? ? clk_set_rate(saif->clk, freq);
>> + ? ? ? ? ? ? clk_enable(saif->clk);
>
> This clk_enable is unbalanced. You enabled the clock in probe() already.
Yes, will fix it.

>> + ? ? ? ? ? ? break;
>> + ? ? default:
>> + ? ? ? ? ? ? return -EINVAL;
>> + ? ? }
>> + ? ? return 0;
>> +}
>> +
>> +/*
>> + * SAIF Clock dividers
>> + * Should only be called when port is inactive.
>> + */
>> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int div_id, int div)
>> +{
>> + ? ? u32 scr;
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> + ? ? scr = __raw_readl(saif->base + SAIF_CTRL);
>> + ? ? scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
>> + ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +
>> + ? ? switch (div_id) {
>> + ? ? case MXS_SAIF_MCLK:
>> + ? ? ? ? ? ? switch (div) {
>> + ? ? ? ? ? ? case 32:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
>> + ? ? ? ? ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 64:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
>> + ? ? ? ? ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 128:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
>> + ? ? ? ? ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 256:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
>> + ? ? ? ? ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 512:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
>> + ? ? ? ? ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 48:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
>> + ? ? ? ? ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 96:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
>> + ? ? ? ? ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 192:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
>> + ? ? ? ? ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? case 384:
>> + ? ? ? ? ? ? ? ? ? ? scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
>> + ? ? ? ? ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> + ? ? ? ? ? ? ? ? ? ? break;
>> + ? ? ? ? ? ? default:
>> + ? ? ? ? ? ? ? ? ? ? return -EINVAL;
>> + ? ? ? ? ? ? }
>> + ? ? ? ? ? ? break;
>> + ? ? default:
>> + ? ? ? ? ? ? return -EINVAL;
>> + ? ? }
>> +
>> + ? ? __raw_writel(scr, saif->base + SAIF_CTRL);
>> +
>> + ? ? return 0;
>> +}
>> +
>> +/*
>> + * SAIF DAI format configuration.
>> + * Should only be called when port is inactive.
>> + * Note: We don't use the I2S modes but instead manually configure the
>> + * SAIF for I2S.
>> + */
>> +static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
>> +{
>> + ? ? u32 scr, stat;
>> + ? ? u32 scr0;
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> + ? ? stat = __raw_readl(saif->base + SAIF_STAT);
>> + ? ? if (stat & BM_SAIF_STAT_BUSY)
>> + ? ? ? ? ? ? return 0;
>
> Returning succesfully doesn't seem right here.
Will replace with -EBUSY.

>> +
>> + ? ? scr0 = __raw_readl(saif->base + SAIF_CTRL);
>> + ? ? scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
>> + ? ? ? ? ? ? & ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
>> + ? ? scr = 0;
>> +
>> + ? ? /* DAI mode */
>> + ? ? switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
>> + ? ? case SND_SOC_DAIFMT_I2S:
>> + ? ? ? ? ? ? /* data frame low 1clk before data */
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_DELAY;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_LEFT_J:
>> + ? ? ? ? ? ? /* data frame high with data */
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_DELAY;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_JUSTIFY;
>> + ? ? ? ? ? ? break;
>
> ? ? ? ?default:
> ? ? ? ? ? ? ? ?return -EINVAL;
Will add.

>> + ? ? }
>> +
>> + ? ? /* DAI clock inversion */
>> + ? ? switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>> + ? ? case SND_SOC_DAIFMT_IB_IF:
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_EDGE;
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_IB_NF:
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_EDGE;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_NB_IF:
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_NB_NF:
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? break;
>> + ? ? }
>
> A question more for Liam and Mark: Would it make sense to add individual
> masks for the clock inversion and frame sync inversion? I code like the
> above in every driver, and I think this could become simpler.
>
>
>> +
>> + ? ? /*
>> + ? ? ?* Note: We simply just support master mode since SAIF TX only supports
>> + ? ? ?* master mode.
>> + ? ? ?*/
>
> When this is true...
It's hw limitation.
Defined in MX28 spec 35.2.1.
i quote it as follows;
For transmit, BITCLK and LRCLK are always driven by the SAIF.
...
Coniguring the SAIF for transmit makes it the master by default.
....

>> + ? ? switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>> + ? ? case SND_SOC_DAIFMT_CBS_CFS:
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
>> + ? ? ? ? ? ? __raw_writel(scr | scr0, saif->base + SAIF_CTRL);
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_CBM_CFS:
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_CBS_CFM:
>> + ? ? ? ? ? ? break;
>
> You should return an error here.
Will add.

>> + ? ? case SND_SOC_DAIFMT_CBM_CFM:
>> + ? ? ? ? ? ? return -EINVAL;
>> + ? ? ? ? ? ? break;
>> + ? ? }
>> +
>> + ? ? return 0;
>> +}
>> +
>> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
>> + ? ? ? ? ? ? ? ? ? ? ? ?struct snd_soc_dai *cpu_dai)
>> +{
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> + ? ? snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
>> +
>> + ? ? return 0;
>> +}
>> +
>> +/*
>> + * Should only be called when port is inactive.
>> + * although can be called multiple times by upper layers.
>> + */
>> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?struct snd_pcm_hw_params *params,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?struct snd_soc_dai *cpu_dai)
>> +{
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> + ? ? u32 scr;
>> +
>> + ? ? scr = __raw_readl(saif->base + SAIF_CTRL);
>> +
>> + ? ? /* cant change any parameters when SAIF is running */
>> + ? ? /* DAI data (word) size */
>> + ? ? scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
>> + ? ? scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
>> + ? ? switch (params_format(params)) {
>> + ? ? case SNDRV_PCM_FORMAT_S16_LE:
>> + ? ? ? ? ? ? scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
>> + ? ? ? ? ? ? break;
>> + ? ? case SNDRV_PCM_FORMAT_S20_3LE:
>> + ? ? ? ? ? ? scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
>> + ? ? ? ? ? ? break;
>> + ? ? case SNDRV_PCM_FORMAT_S24_LE:
>> + ? ? ? ? ? ? scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
>> + ? ? ? ? ? ? break;
>
> ? ? ? ?default:
> ? ? ? ? ? ? ? ?return -EINVAL;
Will add.

>> + ? ? }
>> +
>> + ? ? /* Tx/Rx config */
>> + ? ? if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> + ? ? ? ? ? ? /* enable TX mode */
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_READ_MODE;
>> + ? ? } else {
>> + ? ? ? ? ? ? /* enable RX mode */
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_READ_MODE;
>> + ? ? }
>> +
>> + ? ? __raw_writel(scr, saif->base + SAIF_CTRL);
>> + ? ? return 0;
>> +}
>> +
>> +static int mxs_saif_prepare(struct snd_pcm_substream *substream,
>> + ? ? ? ? ? ? ? ? ? ? ? ?struct snd_soc_dai *cpu_dai)
>> +{
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> + ? ? __raw_writel(BM_SAIF_CTRL_CLKGATE,
>> + ? ? ? ? ? ? saif->base + SAIF_CTRL + MXS_CLR_ADDR);
>> +
>> + ? ? return 0;
>> +}
>> +
>> +static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct snd_soc_dai *cpu_dai)
>> +{
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> + ? ? switch (cmd) {
>> + ? ? case SNDRV_PCM_TRIGGER_START:
>> + ? ? case SNDRV_PCM_TRIGGER_RESUME:
>> + ? ? case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> + ? ? ? ? ? ? if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
>> + ? ? ? ? ? ? ? ? ? ? /*write a data to saif data register to trigger
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? the transfer*/
>
> /* multiline comments
> ?* like this please
> ?*/
Got it.

>> + ? ? ? ? ? ? ? ? ? ? __raw_writel(0, saif->base + SAIF_DATA);
>> + ? ? ? ? ? ? else
>> + ? ? ? ? ? ? ? ? ? ? /*read a data from saif data register to trigger
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? the receive*/
>> + ? ? ? ? ? ? ? ? ? ? __raw_readl(saif->base + SAIF_DATA);
>> + ? ? ? ? ? ? break;
>> + ? ? case SNDRV_PCM_TRIGGER_SUSPEND:
>> + ? ? case SNDRV_PCM_TRIGGER_STOP:
>> + ? ? case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>> + ? ? ? ? ? ? break;
>> + ? ? default:
>> + ? ? ? ? ? ? return -EINVAL;
>> + ? ? }
>> +
>> + ? ? return 0;
>> +}
>> +
>> +#define MXS_SAIF_RATES ? ? ? ? ? ? ? SNDRV_PCM_RATE_8000_192000
>> +#define MXS_SAIF_FORMATS \
>> + ? ? (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
>> + ? ? SNDRV_PCM_FMTBIT_S24_LE)
>> +
>> +static struct snd_soc_dai_ops mxs_saif_dai_ops = {
>> + ? ? .startup = mxs_saif_startup,
>> + ? ? .trigger = mxs_saif_trigger,
>> + ? ? .prepare = mxs_saif_prepare,
>> + ? ? .hw_params = mxs_saif_hw_params,
>> + ? ? .set_sysclk = mxs_saif_set_dai_sysclk,
>> + ? ? .set_clkdiv = mxs_saif_set_dai_clkdiv,
>> + ? ? .set_fmt = mxs_saif_set_dai_fmt,
>> +};
>> +
>> +static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
>> +{
>> + ? ? struct mxs_saif *saif = dev_get_drvdata(dai->dev);
>> +
>> + ? ? snd_soc_dai_set_drvdata(dai, saif);
>> +
>> + ? ? /* Reset */
>> + ? ? __raw_writel(BM_SAIF_CTRL_SFTRST,
>> + ? ? ? ? ? ? saif->base + SAIF_CTRL + MXS_CLR_ADDR);
>> +
>> + ? ? /* enable MCLK output early since codec may need it */
>> + ? ? __raw_writel(BM_SAIF_CTRL_CLKGATE,
>> + ? ? ? ? ? ? saif->base + SAIF_CTRL + MXS_CLR_ADDR);
>> + ? ? __raw_writel(BM_SAIF_CTRL_RUN,
>> + ? ? ? ? ? ? saif->base + SAIF_CTRL + MXS_SET_ADDR);
>> +
>> + ? ? return 0;
>> +}
>> +
>> +static struct snd_soc_dai_driver mxs_saif_dai = {
>> + ? ? .name = "mxs-saif",
>> + ? ? .probe = mxs_saif_dai_probe,
>> + ? ? .playback = {
>> + ? ? ? ? ? ? .channels_min = 2,
>> + ? ? ? ? ? ? .channels_max = 2,
>> + ? ? ? ? ? ? .rates = MXS_SAIF_RATES,
>> + ? ? ? ? ? ? .formats = MXS_SAIF_FORMATS,
>> + ? ? },
>> + ? ? .capture = {
>> + ? ? ? ? ? ? .channels_min = 2,
>> + ? ? ? ? ? ? .channels_max = 2,
>> + ? ? ? ? ? ? .rates = MXS_SAIF_RATES,
>> + ? ? ? ? ? ? .formats = MXS_SAIF_FORMATS,
>> + ? ? },
>> + ? ? .ops = &mxs_saif_dai_ops,
>> +};
>> +
>> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
>> +{
>> + ? ? struct mxs_saif *saif = dev_id;
>> +
>> + ? ? if (saif->fifo_err_counter++ % 100 == 0)
>> + ? ? ? ? ? ? printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
>> + ? ? ? ? ? ? ? ? ? ? fifo_errs=%d \n",
>> + ? ? ? ? ? ? ? ? ? ?__raw_readl(saif->base + SAIF_STAT),
>> + ? ? ? ? ? ? ? ? ? ?__raw_readl(saif->base + SAIF_CTRL),
>> + ? ? ? ? ? ? ? ? ? ?saif->fifo_err_counter);
>> + ? ? __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
>> + ? ? ? ? ? ? ? ? ? ? BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
>> + ? ? ? ? ? ? ? ? ? ? saif->base + SAIF_STAT + MXS_CLR_ADDR);
>> +
>> + ? ? return IRQ_HANDLED;
>> +}
>> +
>> +static int mxs_saif_probe(struct platform_device *pdev)
>> +{
>> + ? ? struct resource *res;
>> + ? ? struct mxs_saif *saif;
>> + ? ? int ret = 0;
>> +
>> + ? ? saif = kzalloc(sizeof(*saif), GFP_KERNEL);
>> + ? ? if (!saif)
>> + ? ? ? ? ? ? return -ENOMEM;
>
> Consider using devm_kzalloc and friends, it makes the error path less
> error prone.
Will use it. Thanks for the suggestion.

>> +
>> + ? ? saif->irq = platform_get_irq(pdev, 0);
>> + ? ? if (saif->irq < 0) {
>> + ? ? ? ? ? ? ret = saif->irq;
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "failed to get irq resource: %d\n",
>> + ? ? ? ? ? ? ? ? ? ? ret);
>> + ? ? ? ? ? ? goto failed_get_irq1;
>> + ? ? }
>> +
>> + ? ? saif->fifo_err_counter = 0;
>> + ? ? ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
>> + ? ? if (ret) {
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "failed to request irq\n");
>> + ? ? ? ? ? ? goto failed_req_irq;
>> + ? ? }
>> +
>> + ? ? saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
>> + ? ? if (saif->dma_param.chan_irq < 0) {
>> + ? ? ? ? ? ? ret = saif->dma_param.chan_irq;
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
>> + ? ? ? ? ? ? ? ? ? ? ret);
>> + ? ? ? ? ? ? goto failed_get_irq2;
>> + ? ? }
>> +
>> + ? ? saif->clk = clk_get(&pdev->dev, NULL);
>> + ? ? if (IS_ERR(saif->clk)) {
>> + ? ? ? ? ? ? ret = PTR_ERR(saif->clk);
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "Cannot get the clock: %d\n",
>> + ? ? ? ? ? ? ? ? ? ? ret);
>> + ? ? ? ? ? ? goto failed_clk;
>> + ? ? }
>> + ? ? clk_set_rate(saif->clk, 12000000);
>> + ? ? clk_enable(saif->clk);
>> +
>> + ? ? res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + ? ? if (!res) {
>> + ? ? ? ? ? ? ret = -ENODEV;
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "failed to get io resource: %d\n",
>> + ? ? ? ? ? ? ? ? ? ? ret);
>> + ? ? ? ? ? ? goto failed_get_resource;
>> + ? ? }
>> +
>> + ? ? if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) {
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "request_mem_region failed\n");
>> + ? ? ? ? ? ? ret = -EBUSY;
>> + ? ? ? ? ? ? goto failed_get_resource;
>> + ? ? }
>> +
>> + ? ? saif->base = ioremap(res->start, resource_size(res));
>> + ? ? if (!saif->base) {
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "ioremap failed\n");
>> + ? ? ? ? ? ? ret = -ENODEV;
>> + ? ? ? ? ? ? goto failed_ioremap;
>> + ? ? }
>> +
>> + ? ? res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
>> + ? ? if (!res) {
>> + ? ? ? ? ? ? ret = -ENODEV;
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "failed to get dma resource: %d\n",
>> + ? ? ? ? ? ? ? ? ? ? ret);
>> + ? ? ? ? ? ? goto failed_get_resource;
>> + ? ? }
>> + ? ? saif->dma_param.chan_num = res->start;
>> +
>> + ? ? platform_set_drvdata(pdev, saif);
>> +
>> + ? ? ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
>> + ? ? if (ret) {
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "register DAI failed\n");
>> + ? ? ? ? ? ? goto failed_register;
>> + ? ? }
>> +
>> + ? ? saif->soc_platform_pdev = platform_device_alloc(
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "mxs-pcm-audio", pdev->id);
>> + ? ? if (!saif->soc_platform_pdev) {
>> + ? ? ? ? ? ? ret = -ENOMEM;
>> + ? ? ? ? ? ? goto failed_pdev_alloc;
>> + ? ? }
>> +
>> + ? ? platform_set_drvdata(saif->soc_platform_pdev, saif);
>> + ? ? ret = platform_device_add(saif->soc_platform_pdev);
>> + ? ? if (ret) {
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "failed to add soc platform device\n");
>> + ? ? ? ? ? ? goto failed_pdev_add;
>> + ? ? }
>> +
>> + ? ? return 0;
>> +
>> +failed_pdev_add:
>> + ? ? platform_device_put(saif->soc_platform_pdev);
>> +failed_pdev_alloc:
>> + ? ? snd_soc_unregister_dai(&pdev->dev);
>> +failed_register:
>> + ? ? iounmap(saif->base);
>> +failed_ioremap:
>> + ? ? release_mem_region(res->start, resource_size(res));
>> +failed_get_resource:
>> + ? ? clk_disable(saif->clk);
>> + ? ? clk_put(saif->clk);
>> +failed_clk:
>> +failed_get_irq2:
>> + ? ? free_irq(saif->irq, saif);
>> +failed_req_irq:
>> +failed_get_irq1:
>> + ? ? kfree(saif);
>> +
>> + ? ? return ret;
>> +}
>> +
>> +static int __devexit mxs_saif_remove(struct platform_device *pdev)
>> +{
>> + ? ? struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + ? ? struct mxs_saif *saif = platform_get_drvdata(pdev);
>> +
>> + ? ? platform_device_unregister(saif->soc_platform_pdev);
>> +
>> + ? ? snd_soc_unregister_dai(&pdev->dev);
>> +
>> + ? ? iounmap(saif->base);
>> + ? ? release_mem_region(res->start, resource_size(res));
>> + ? ? free_irq(saif->irq, saif);
>> +
>> + ? ? clk_disable(saif->clk);
>> + ? ? clk_put(saif->clk);
>> +
>> + ? ? kfree(saif);
>> +
>> + ? ? return 0;
>> +}
>> +
>> +static struct platform_driver mxs_saif_driver = {
>> + ? ? .probe = mxs_saif_probe,
>> + ? ? .remove = __devexit_p(mxs_saif_remove),
>> +
>> + ? ? .driver = {
>> + ? ? ? ? ? ? .name = "mxs-saif",
>> + ? ? ? ? ? ? .owner = THIS_MODULE,
>> + ? ? },
>> +};
>> +
>> +static int __init mxs_saif_init(void)
>> +{
>> + ? ? return platform_driver_register(&mxs_saif_driver);
>> +}
>> +
>> +static void __exit mxs_saif_exit(void)
>> +{
>> + ? ? platform_driver_unregister(&mxs_saif_driver);
>> +}
>> +
>> +module_init(mxs_saif_init);
>> +module_exit(mxs_saif_exit);
>> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
>> +MODULE_DESCRIPTION("MXS ASoC SAIF driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
>> new file mode 100644
>> index 0000000..dd26b37
>> --- /dev/null
>> +++ b/sound/soc/mxs/mxs-saif.h
>> @@ -0,0 +1,124 @@
>> +/*
>> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, write to the Free Software Foundation, Inc.,
>> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
>> + */
>> +
>> +
>> +#ifndef _MXS_SAIF_H
>> +#define _MXS_SAIF_H
>> +
>> +#define SAIF_CTRL ? ?0x0
>> +#define SAIF_STAT ? ?0x10
>> +#define SAIF_DATA ? ?0x20
>> +#define SAIF_VERSION 0X30
>> +
>> +/* SAIF_CTRL */
>> +#define BM_SAIF_CTRL_SFTRST ? ? ? ? ?0x80000000
>> +#define BM_SAIF_CTRL_CLKGATE ? ? ? ? 0x40000000
>> +#define BP_SAIF_CTRL_BITCLK_MULT_RATE ? ? ? ?27
>> +#define BM_SAIF_CTRL_BITCLK_MULT_RATE ? ? ? ?0x38000000
>> +#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
>> + ? ? ? ? ? ? (((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
>> +#define BM_SAIF_CTRL_BITCLK_BASE_RATE ? ? ? ?0x04000000
>> +#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN ? ? ? 0x02000000
>> +#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN ? ? 0x01000000
>> +#define BP_SAIF_CTRL_RSRVD2 ? ? ? ? ?21
>> +#define BM_SAIF_CTRL_RSRVD2 ? ? ? ? ?0x00E00000
>> +
>> +#define BP_SAIF_CTRL_DMAWAIT_COUNT ? 16
>> +#define BM_SAIF_CTRL_DMAWAIT_COUNT ? 0x001F0000
>> +#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
>> + ? ? ? ? ? ? (((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
>> +#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
>> +#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
>> +#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
>> + ? ? ? ? ? ? (((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
>> +#define BM_SAIF_CTRL_LRCLK_PULSE ? ? 0x00002000
>> +#define BM_SAIF_CTRL_BIT_ORDER ? ? ? ? ? ? ? 0x00001000
>> +#define BM_SAIF_CTRL_DELAY ? ? ? ? ? 0x00000800
>> +#define BM_SAIF_CTRL_JUSTIFY ? ? ? ? 0x00000400
>> +#define BM_SAIF_CTRL_LRCLK_POLARITY ?0x00000200
>> +#define BM_SAIF_CTRL_BITCLK_EDGE ? ? 0x00000100
>> +#define BP_SAIF_CTRL_WORD_LENGTH ? ? 4
>> +#define BM_SAIF_CTRL_WORD_LENGTH ? ? 0x000000F0
>> +#define BF_SAIF_CTRL_WORD_LENGTH(v) \
>> + ? ? ? ? ? ? (((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
>> +#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE ? ? 0x00000008
>> +#define BM_SAIF_CTRL_SLAVE_MODE ? ? ? ? ? ? ?0x00000004
>> +#define BM_SAIF_CTRL_READ_MODE ? ? ? ? ? ? ? 0x00000002
>> +#define BM_SAIF_CTRL_RUN ? ? ? ? ? ? 0x00000001
>> +
>> +/* SAIF_STAT */
>> +#define BM_SAIF_STAT_PRESENT ? ? ? ? 0x80000000
>> +#define BP_SAIF_STAT_RSRVD2 ? ? ? ? ?17
>> +#define BM_SAIF_STAT_RSRVD2 ? ? ? ? ?0x7FFE0000
>> +#define BF_SAIF_STAT_RSRVD2(v) \
>> + ? ? ? ? ? ? (((v) << 17) & BM_SAIF_STAT_RSRVD2)
>> +#define BM_SAIF_STAT_DMA_PREQ ? ? ? ? ? ? ? ?0x00010000
>> +#define BP_SAIF_STAT_RSRVD1 ? ? ? ? ?7
>> +#define BM_SAIF_STAT_RSRVD1 ? ? ? ? ?0x0000FF80
>> +#define BF_SAIF_STAT_RSRVD1(v) \
>> + ? ? ? ? ? ? (((v) << 7) & BM_SAIF_STAT_RSRVD1)
>> +
>> +#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
>> +#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ ? ? ? 0x00000020
>> +#define BM_SAIF_STAT_FIFO_SERVICE_IRQ ? ? ? ?0x00000010
>> +#define BP_SAIF_STAT_RSRVD0 ? ? ? ? ?1
>> +#define BM_SAIF_STAT_RSRVD0 ? ? ? ? ?0x0000000E
>> +#define BF_SAIF_STAT_RSRVD0(v) \
>> + ? ? ? ? ? ? (((v) << 1) & BM_SAIF_STAT_RSRVD0)
>> +#define BM_SAIF_STAT_BUSY ? ? ? ? ? ?0x00000001
>> +
>> +/* SAFI_DATA */
>> +#define BP_SAIF_DATA_PCM_RIGHT ? ? ? ? ? ? ? 16
>> +#define BM_SAIF_DATA_PCM_RIGHT ? ? ? ? ? ? ? 0xFFFF0000
>> +#define BF_SAIF_DATA_PCM_RIGHT(v) \
>> + ? ? ? ? ? ? (((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
>> +#define BP_SAIF_DATA_PCM_LEFT ? ? ? ? ? ? ? ?0
>> +#define BM_SAIF_DATA_PCM_LEFT ? ? ? ? ? ? ? ?0x0000FFFF
>> +#define BF_SAIF_DATA_PCM_LEFT(v) ? ? \
>> + ? ? ? ? ? ? (((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
>> +
>> +/* SAIF_VERSION */
>> +#define BP_SAIF_VERSION_MAJOR ? ? ? ? ? ? ? ?24
>> +#define BM_SAIF_VERSION_MAJOR ? ? ? ? ? ? ? ?0xFF000000
>> +#define BF_SAIF_VERSION_MAJOR(v) \
>> + ? ? ? ? ? ? (((v) << 24) & BM_SAIF_VERSION_MAJOR)
>> +#define BP_SAIF_VERSION_MINOR ? ? ? ? ? ? ? ?16
>> +#define BM_SAIF_VERSION_MINOR ? ? ? ? ? ? ? ?0x00FF0000
>> +#define BF_SAIF_VERSION_MINOR(v) \
>> + ? ? ? ? ? ? (((v) << 16) & BM_SAIF_VERSION_MINOR)
>> +#define BP_SAIF_VERSION_STEP ? ? ? ? 0
>> +#define BM_SAIF_VERSION_STEP ? ? ? ? 0x0000FFFF
>> +#define BF_SAIF_VERSION_STEP(v) \
>> + ? ? ? ? ? ? (((v) << 0) & BM_SAIF_VERSION_STEP)
>> +
>> +#define MXS_SAIF_SYS_CLK ? ? 0
>> +#define MXS_SAIF_MCLK ? ? ? ? ? ? ? ?1
>> +
>> +#include "mxs-pcm.h"
>> +
>> +struct mxs_saif {
>> + ? ? struct clk *clk;
>> + ? ? void __iomem *base;
>> + ? ? int irq;
>> + ? ? struct mxs_pcm_dma_params dma_param;
>> +
>> + ? ? struct platform_device *soc_platform_pdev;
>> + ? ? u32 fifo_err_counter;
>> +};
>> +
>> +#endif
>> --
>> 1.7.0.4
>>
>>
>>
>
> --
> Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
> Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 ? ?|
> Amtsgericht Hildesheim, HRA 2686 ? ? ? ? ? | Fax: ? +49-5121-206917-5555 |
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

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

* Re: [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
  2011-07-08 15:59   ` Dong Aisheng
@ 2011-07-09  2:33     ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  2:33 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, s.hauer, linux-arm-kernel, lrg

On Fri, Jul 08, 2011 at 11:59:41PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

*Always* CC maintainers on patches.

> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * Refer to sound/soc/imx/imx-pcm-dma-mx2.c

Why?

> +	iprtd->buf = (unsigned int *)substream->dma_buffer.area;

This cast looks incredibly suspicious...

> +static int snd_mxs_pcm_prepare(struct snd_pcm_substream *substream)
> +{
> +	return 0;
> +}
> +

Remove empty functions.

> +static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		dmaengine_submit(iprtd->desc);
> +
> +		break;
> +

Why the random blank line?

> +static struct platform_driver mxs_pcm_driver = {
> +	.driver = {
> +			.name = "mxs-pcm-audio",
> +			.owner = THIS_MODULE,

Indentation here is very odd...

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

* [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
@ 2011-07-09  2:33     ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  2:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 11:59:41PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

*Always* CC maintainers on patches.

> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * Refer to sound/soc/imx/imx-pcm-dma-mx2.c

Why?

> +	iprtd->buf = (unsigned int *)substream->dma_buffer.area;

This cast looks incredibly suspicious...

> +static int snd_mxs_pcm_prepare(struct snd_pcm_substream *substream)
> +{
> +	return 0;
> +}
> +

Remove empty functions.

> +static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +	struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		dmaengine_submit(iprtd->desc);
> +
> +		break;
> +

Why the random blank line?

> +static struct platform_driver mxs_pcm_driver = {
> +	.driver = {
> +			.name = "mxs-pcm-audio",
> +			.owner = THIS_MODULE,

Indentation here is very odd...

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-08 15:59   ` Dong Aisheng
@ 2011-07-09  2:52     ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  2:52 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, s.hauer, linux-arm-kernel, lrg

On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

Again, *always* CC maintainers on patches.

> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
> +			int clk_id, unsigned int freq, int dir)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	switch (clk_id) {
> +	case MXS_SAIF_SYS_CLK:
> +		clk_set_rate(saif->clk, freq);
> +		clk_enable(saif->clk);

How would one turn this clock off?

> + * SAIF Clock dividers
> + * Should only be called when port is inactive.
> + */
> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
> +				  int div_id, int div)
> +{
> +	u32 scr;
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	scr = __raw_readl(saif->base + SAIF_CTRL);
> +	scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
> +	scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +
> +	switch (div_id) {
> +	case MXS_SAIF_MCLK:
> +		switch (div) {
> +		case 32:

No, this stuff should all be figured out automatically by the driver -
the user shouldn't have to manually set the ratio, especially if they've
already set the master clock.

> +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> +	case SND_SOC_DAIFMT_I2S:
> +		/* data frame low 1clk before data */
> +		scr |= BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_LEFT_J:
> +		/* data frame high with data */
> +		scr &= ~BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		scr &= ~BM_SAIF_CTRL_JUSTIFY;
> +		break;
> +	}

This should return an error if the parameters are invalid.  The rest of
the code has many other instances of this missing check.

> +	/*
> +	 * Note: We simply just support master mode since SAIF TX only supports
> +	 * master mode.
> +	 */
> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +		scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
> +		__raw_writel(scr | scr0, saif->base + SAIF_CTRL);
> +		break;
> +	case SND_SOC_DAIFMT_CBM_CFS:
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFM:
> +		break;

This is clearly wrong, you're doing exactly the same thing for two
different inputs.

> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
> +			   struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
> +
> +	return 0;
> +}

Remove empty functions.

> +/*
> + * Should only be called when port is inactive.
> + * although can be called multiple times by upper layers.
> + */
> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params,
> +			     struct snd_soc_dai *cpu_dai)

The requirement for the port to be inactive is totally unreasonable,
especially given that the params are configured by applications and you
support simultaneous playback and record.

> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
> +{
> +	struct mxs_saif *saif = dev_id;
> +
> +	if (saif->fifo_err_counter++ % 100 == 0)

The rate limit looks awfully suspicious...

> +		printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
> +			fifo_errs=%d \n",
> +		       __raw_readl(saif->base + SAIF_STAT),
> +		       __raw_readl(saif->base + SAIF_CTRL),
> +		       saif->fifo_err_counter);

dev_err()

> +	__raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
> +			BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
> +			saif->base + SAIF_STAT + MXS_CLR_ADDR);
> +
> +	return IRQ_HANDLED;

You're not actually checking that the relevant interrupt fired...

> +	saif->clk = clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(saif->clk)) {
> +		ret = PTR_ERR(saif->clk);
> +		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
> +			ret);
> +		goto failed_clk;
> +	}
> +	clk_set_rate(saif->clk, 12000000);
> +	clk_enable(saif->clk);

How did you pick this clock rate and why does it need to be set?  It's
not an obvious audio rate...

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-09  2:52     ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  2:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

Again, *always* CC maintainers on patches.

> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
> +			int clk_id, unsigned int freq, int dir)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	switch (clk_id) {
> +	case MXS_SAIF_SYS_CLK:
> +		clk_set_rate(saif->clk, freq);
> +		clk_enable(saif->clk);

How would one turn this clock off?

> + * SAIF Clock dividers
> + * Should only be called when port is inactive.
> + */
> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
> +				  int div_id, int div)
> +{
> +	u32 scr;
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +
> +	scr = __raw_readl(saif->base + SAIF_CTRL);
> +	scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
> +	scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
> +
> +	switch (div_id) {
> +	case MXS_SAIF_MCLK:
> +		switch (div) {
> +		case 32:

No, this stuff should all be figured out automatically by the driver -
the user shouldn't have to manually set the ratio, especially if they've
already set the master clock.

> +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> +	case SND_SOC_DAIFMT_I2S:
> +		/* data frame low 1clk before data */
> +		scr |= BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		break;
> +	case SND_SOC_DAIFMT_LEFT_J:
> +		/* data frame high with data */
> +		scr &= ~BM_SAIF_CTRL_DELAY;
> +		scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
> +		scr &= ~BM_SAIF_CTRL_JUSTIFY;
> +		break;
> +	}

This should return an error if the parameters are invalid.  The rest of
the code has many other instances of this missing check.

> +	/*
> +	 * Note: We simply just support master mode since SAIF TX only supports
> +	 * master mode.
> +	 */
> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +		scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
> +		__raw_writel(scr | scr0, saif->base + SAIF_CTRL);
> +		break;
> +	case SND_SOC_DAIFMT_CBM_CFS:
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFM:
> +		break;

This is clearly wrong, you're doing exactly the same thing for two
different inputs.

> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
> +			   struct snd_soc_dai *cpu_dai)
> +{
> +	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
> +	snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
> +
> +	return 0;
> +}

Remove empty functions.

> +/*
> + * Should only be called when port is inactive.
> + * although can be called multiple times by upper layers.
> + */
> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params,
> +			     struct snd_soc_dai *cpu_dai)

The requirement for the port to be inactive is totally unreasonable,
especially given that the params are configured by applications and you
support simultaneous playback and record.

> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
> +{
> +	struct mxs_saif *saif = dev_id;
> +
> +	if (saif->fifo_err_counter++ % 100 == 0)

The rate limit looks awfully suspicious...

> +		printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
> +			fifo_errs=%d \n",
> +		       __raw_readl(saif->base + SAIF_STAT),
> +		       __raw_readl(saif->base + SAIF_CTRL),
> +		       saif->fifo_err_counter);

dev_err()

> +	__raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
> +			BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
> +			saif->base + SAIF_STAT + MXS_CLR_ADDR);
> +
> +	return IRQ_HANDLED;

You're not actually checking that the relevant interrupt fired...

> +	saif->clk = clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(saif->clk)) {
> +		ret = PTR_ERR(saif->clk);
> +		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
> +			ret);
> +		goto failed_clk;
> +	}
> +	clk_set_rate(saif->clk, 12000000);
> +	clk_enable(saif->clk);

How did you pick this clock rate and why does it need to be set?  It's
not an obvious audio rate...

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

* Re: [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
  2011-07-08 15:59   ` Dong Aisheng
@ 2011-07-09  3:00     ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  3:00 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, s.hauer, linux-arm-kernel, lrg

On Fri, Jul 08, 2011 at 11:59:43PM +0800, Dong Aisheng wrote:
> The driver only supports playback firstly.

Once more, *always* CC maintainers.

> +struct mxs_audio_platform_data {
> +	int sysclk;
> +
> +	int (*init) (void);     /* board specific init */
> +	int (*finit) (void);    /* board specific finit */

Eh?  Your machine driver is already entirely board specific...

> +	/* The SAIF clock should be either 512*fs or 384*fs */
> +	card_priv.sysclk = 512 * rate;
> +	ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_SYS_CLK,
> +			card_priv.sysclk,
> +			SND_SOC_CLOCK_OUT);

Why are you storing the sysclk?  You never reference it again and
you're using different sysclks for everything in the system.

> +	/* set SGTL5000_SYSCLK as 256*fs to support 96k sample rate */
> +	snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 256 * rate, 0);
> +
> +	/* The MCLK output rate is 256*fs */
> +	snd_soc_dai_set_clkdiv(cpu_dai, MXS_SAIF_MCLK, 256);

Why are you not checking errors on these?

> +static int mxs_sgtl5000_soc_init(struct snd_soc_pcm_runtime *rtd)
> +{
> +	/* TBD: add dapm widgets */
> +
> +	return 0;
> +}

Remove empty functions.

> +static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
> +{
> +	struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
> +	int ret;
> +
> +	card_priv.pdev = pdev;
> +
> +	ret = -EINVAL;
> +	if (plat && plat->init && plat->init())
> +		return ret;

You're not calling snd_soc_register_card()...

> +	mxs_sgtl5000_snd_device = platform_device_alloc("soc-audio", -1);
> +	if (!mxs_sgtl5000_snd_device)
> +		return -ENOMEM;

...and you're using both a platform device and soc-audio to instantate
which is a bit confused.  New code should not be using soc-audio.

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

* [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
@ 2011-07-09  3:00     ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  3:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 11:59:43PM +0800, Dong Aisheng wrote:
> The driver only supports playback firstly.

Once more, *always* CC maintainers.

> +struct mxs_audio_platform_data {
> +	int sysclk;
> +
> +	int (*init) (void);     /* board specific init */
> +	int (*finit) (void);    /* board specific finit */

Eh?  Your machine driver is already entirely board specific...

> +	/* The SAIF clock should be either 512*fs or 384*fs */
> +	card_priv.sysclk = 512 * rate;
> +	ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_SYS_CLK,
> +			card_priv.sysclk,
> +			SND_SOC_CLOCK_OUT);

Why are you storing the sysclk?  You never reference it again and
you're using different sysclks for everything in the system.

> +	/* set SGTL5000_SYSCLK as 256*fs to support 96k sample rate */
> +	snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 256 * rate, 0);
> +
> +	/* The MCLK output rate is 256*fs */
> +	snd_soc_dai_set_clkdiv(cpu_dai, MXS_SAIF_MCLK, 256);

Why are you not checking errors on these?

> +static int mxs_sgtl5000_soc_init(struct snd_soc_pcm_runtime *rtd)
> +{
> +	/* TBD: add dapm widgets */
> +
> +	return 0;
> +}

Remove empty functions.

> +static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
> +{
> +	struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
> +	int ret;
> +
> +	card_priv.pdev = pdev;
> +
> +	ret = -EINVAL;
> +	if (plat && plat->init && plat->init())
> +		return ret;

You're not calling snd_soc_register_card()...

> +	mxs_sgtl5000_snd_device = platform_device_alloc("soc-audio", -1);
> +	if (!mxs_sgtl5000_snd_device)
> +		return -ENOMEM;

...and you're using both a platform device and soc-audio to instantate
which is a bit confused.  New code should not be using soc-audio.

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

* Re: [PATCH 04/10] ASoc: mxs: add asoc configuration files
  2011-07-08 15:59   ` Dong Aisheng
@ 2011-07-09  3:01     ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  3:01 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, s.hauer, linux-arm-kernel, lrg

On Fri, Jul 08, 2011 at 11:59:44PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

*Always* CC maintainers on patches.

> @@ -57,6 +57,7 @@ source "sound/soc/s6000/Kconfig"
>  source "sound/soc/sh/Kconfig"
>  source "sound/soc/tegra/Kconfig"
>  source "sound/soc/txx9/Kconfig"
> +source "sound/soc/mxs/Kconfig"

Keep all these files sorted.  

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

* [PATCH 04/10] ASoc: mxs: add asoc configuration files
@ 2011-07-09  3:01     ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-09  3:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 08, 2011 at 11:59:44PM +0800, Dong Aisheng wrote:
> Signed-off-by: Dong Aisheng <b29396@freescale.com>

*Always* CC maintainers on patches.

> @@ -57,6 +57,7 @@ source "sound/soc/s6000/Kconfig"
>  source "sound/soc/sh/Kconfig"
>  source "sound/soc/tegra/Kconfig"
>  source "sound/soc/txx9/Kconfig"
> +source "sound/soc/mxs/Kconfig"

Keep all these files sorted.  

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

* Re: [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
  2011-07-09  2:33     ` Mark Brown
@ 2011-07-10  6:28       ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  6:28 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:41PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>
> *Always* CC maintainers on patches.
Sorry for missed it.
Will add in patch v2.
Thanks a lot for the review.

>> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + *
>> + * Refer to sound/soc/imx/imx-pcm-dma-mx2.c
>
> Why?
Just with the reference of  imx-pcm-dma-mx2.c code.

>> +     iprtd->buf = (unsigned int *)substream->dma_buffer.area;
>
> This cast looks incredibly suspicious...
Will remove the cast.

>> +static int snd_mxs_pcm_prepare(struct snd_pcm_substream *substream)
>> +{
>> +     return 0;
>> +}
>> +
>
> Remove empty functions.
Will clean up it.

>> +static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
>> +{
>> +     struct snd_pcm_runtime *runtime = substream->runtime;
>> +     struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
>> +
>> +     switch (cmd) {
>> +     case SNDRV_PCM_TRIGGER_START:
>> +     case SNDRV_PCM_TRIGGER_RESUME:
>> +     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> +             dmaengine_submit(iprtd->desc);
>> +
>> +             break;
>> +
>
> Why the random blank line?
Sorry for the typo, WIll remove.

>> +static struct platform_driver mxs_pcm_driver = {
>> +     .driver = {
>> +                     .name = "mxs-pcm-audio",
>> +                     .owner = THIS_MODULE,
>
> Indentation here is very odd...
Will fix in the next patch.

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

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

* [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
@ 2011-07-10  6:28       ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  6:28 UTC (permalink / raw)
  To: linux-arm-kernel

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:41PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>
> *Always* CC maintainers on patches.
Sorry for missed it.
Will add in patch v2.
Thanks a lot for the review.

>> + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + *
>> + * Refer to sound/soc/imx/imx-pcm-dma-mx2.c
>
> Why?
Just with the reference of  imx-pcm-dma-mx2.c code.

>> + ? ? iprtd->buf = (unsigned int *)substream->dma_buffer.area;
>
> This cast looks incredibly suspicious...
Will remove the cast.

>> +static int snd_mxs_pcm_prepare(struct snd_pcm_substream *substream)
>> +{
>> + ? ? return 0;
>> +}
>> +
>
> Remove empty functions.
Will clean up it.

>> +static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
>> +{
>> + ? ? struct snd_pcm_runtime *runtime = substream->runtime;
>> + ? ? struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
>> +
>> + ? ? switch (cmd) {
>> + ? ? case SNDRV_PCM_TRIGGER_START:
>> + ? ? case SNDRV_PCM_TRIGGER_RESUME:
>> + ? ? case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> + ? ? ? ? ? ? dmaengine_submit(iprtd->desc);
>> +
>> + ? ? ? ? ? ? break;
>> +
>
> Why the random blank line?
Sorry for the typo, WIll remove.

>> +static struct platform_driver mxs_pcm_driver = {
>> + ? ? .driver = {
>> + ? ? ? ? ? ? ? ? ? ? .name = "mxs-pcm-audio",
>> + ? ? ? ? ? ? ? ? ? ? .owner = THIS_MODULE,
>
> Indentation here is very odd...
Will fix in the next patch.

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

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-09  2:52     ` Mark Brown
@ 2011-07-10  8:17       ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:17 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>
> Again, *always* CC maintainers on patches.
Will add in the updated patch.

>> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
>> +                     int clk_id, unsigned int freq, int dir)
>> +{
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> +     switch (clk_id) {
>> +     case MXS_SAIF_SYS_CLK:
>> +             clk_set_rate(saif->clk, freq);
>> +             clk_enable(saif->clk);
>
> How would one turn this clock off?
Currenty simply enable clock always.
The problem is that the codec may use the MCLK supplied by SAIF as its
system clock for normal operations such as i2c r/w.
If we disable it after playback or capture. The automatic dapm
operations of codec may fail on i2c r/w. Will check if dapm has any
machnism to avoid this.
Can you share your experience ont this issue?

>> + * SAIF Clock dividers
>> + * Should only be called when port is inactive.
>> + */
>> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
>> +                               int div_id, int div)
>> +{
>> +     u32 scr;
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> +     scr = __raw_readl(saif->base + SAIF_CTRL);
>> +     scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
>> +     scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +
>> +     switch (div_id) {
>> +     case MXS_SAIF_MCLK:
>> +             switch (div) {
>> +             case 32:
>
> No, this stuff should all be figured out automatically by the driver -
> the user shouldn't have to manually set the ratio, especially if they've
> already set the master clock.
Yes, that's a good point and i will try to do it in the updated patch.

>> +     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
>> +     case SND_SOC_DAIFMT_I2S:
>> +             /* data frame low 1clk before data */
>> +             scr |= BM_SAIF_CTRL_DELAY;
>> +             scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             break;
>> +     case SND_SOC_DAIFMT_LEFT_J:
>> +             /* data frame high with data */
>> +             scr &= ~BM_SAIF_CTRL_DELAY;
>> +             scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> +             scr &= ~BM_SAIF_CTRL_JUSTIFY;
>> +             break;
>> +     }
>
> This should return an error if the parameters are invalid.  The rest of
> the code has many other instances of this missing check.
Will add them.

>> +     /*
>> +      * Note: We simply just support master mode since SAIF TX only supports
>> +      * master mode.
>> +      */
>> +     switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>> +     case SND_SOC_DAIFMT_CBS_CFS:
>> +             scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
>> +             __raw_writel(scr | scr0, saif->base + SAIF_CTRL);
>> +             break;
>> +     case SND_SOC_DAIFMT_CBM_CFS:
>> +             break;
>> +     case SND_SOC_DAIFMT_CBS_CFM:
>> +             break;
>
> This is clearly wrong, you're doing exactly the same thing for two
> different inputs.
Will fix in next patch.

>> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
>> +                        struct snd_soc_dai *cpu_dai)
>> +{
>> +     struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +     snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
>> +
>> +     return 0;
>> +}
>
> Remove empty functions.
This is to set dma param.

>> +/*
>> + * Should only be called when port is inactive.
>> + * although can be called multiple times by upper layers.
>> + */
>> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
>> +                          struct snd_pcm_hw_params *params,
>> +                          struct snd_soc_dai *cpu_dai)
>
> The requirement for the port to be inactive is totally unreasonable,
> especially given that the params are configured by applications and you
> support simultaneous playback and record.
Yes, i will remove it. Finally we will support simultaneous playback and record.

>> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
>> +{
>> +     struct mxs_saif *saif = dev_id;
>> +
>> +     if (saif->fifo_err_counter++ % 100 == 0)
>
> The rate limit looks awfully suspicious...
Originally it's just for printing less error messages when the issue happens.
I could remove the rate limit.

>> +             printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
>> +                     fifo_errs=%d \n",
>> +                    __raw_readl(saif->base + SAIF_STAT),
>> +                    __raw_readl(saif->base + SAIF_CTRL),
>> +                    saif->fifo_err_counter);
>
> dev_err()
Will change.

>> +     __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
>> +                     BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
>> +                     saif->base + SAIF_STAT + MXS_CLR_ADDR);
>> +
>> +     return IRQ_HANDLED;
>
> You're not actually checking that the relevant interrupt fired...
I will add the checking for different errors.

>> +     saif->clk = clk_get(&pdev->dev, NULL);
>> +     if (IS_ERR(saif->clk)) {
>> +             ret = PTR_ERR(saif->clk);
>> +             dev_err(&pdev->dev, "Cannot get the clock: %d\n",
>> +                     ret);
>> +             goto failed_clk;
>> +     }
>> +     clk_set_rate(saif->clk, 12000000);
>> +     clk_enable(saif->clk);
>
> How did you pick this clock rate and why does it need to be set?  It's
> not an obvious audio rate...
It's initial clock rate for normal operations of codecs based on MCLK.
We found the default MCLK ouput(only about 7.3Khz) can not work for codecs like
sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz.
So we set a common working clock 12Mhz here.
Maybe i should try to set it elsewhere or just set it via platform data.

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

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-10  8:17       ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:17 UTC (permalink / raw)
  To: linux-arm-kernel

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>
> Again, *always* CC maintainers on patches.
Will add in the updated patch.

>> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
>> + ? ? ? ? ? ? ? ? ? ? int clk_id, unsigned int freq, int dir)
>> +{
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> + ? ? switch (clk_id) {
>> + ? ? case MXS_SAIF_SYS_CLK:
>> + ? ? ? ? ? ? clk_set_rate(saif->clk, freq);
>> + ? ? ? ? ? ? clk_enable(saif->clk);
>
> How would one turn this clock off?
Currenty simply enable clock always.
The problem is that the codec may use the MCLK supplied by SAIF as its
system clock for normal operations such as i2c r/w.
If we disable it after playback or capture. The automatic dapm
operations of codec may fail on i2c r/w. Will check if dapm has any
machnism to avoid this.
Can you share your experience ont this issue?

>> + * SAIF Clock dividers
>> + * Should only be called when port is inactive.
>> + */
>> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int div_id, int div)
>> +{
>> + ? ? u32 scr;
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> +
>> + ? ? scr = __raw_readl(saif->base + SAIF_CTRL);
>> + ? ? scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
>> + ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
>> +
>> + ? ? switch (div_id) {
>> + ? ? case MXS_SAIF_MCLK:
>> + ? ? ? ? ? ? switch (div) {
>> + ? ? ? ? ? ? case 32:
>
> No, this stuff should all be figured out automatically by the driver -
> the user shouldn't have to manually set the ratio, especially if they've
> already set the master clock.
Yes, that's a good point and i will try to do it in the updated patch.

>> + ? ? switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
>> + ? ? case SND_SOC_DAIFMT_I2S:
>> + ? ? ? ? ? ? /* data frame low 1clk before data */
>> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_DELAY;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_LEFT_J:
>> + ? ? ? ? ? ? /* data frame high with data */
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_DELAY;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_JUSTIFY;
>> + ? ? ? ? ? ? break;
>> + ? ? }
>
> This should return an error if the parameters are invalid. ?The rest of
> the code has many other instances of this missing check.
Will add them.

>> + ? ? /*
>> + ? ? ?* Note: We simply just support master mode since SAIF TX only supports
>> + ? ? ?* master mode.
>> + ? ? ?*/
>> + ? ? switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
>> + ? ? case SND_SOC_DAIFMT_CBS_CFS:
>> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
>> + ? ? ? ? ? ? __raw_writel(scr | scr0, saif->base + SAIF_CTRL);
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_CBM_CFS:
>> + ? ? ? ? ? ? break;
>> + ? ? case SND_SOC_DAIFMT_CBS_CFM:
>> + ? ? ? ? ? ? break;
>
> This is clearly wrong, you're doing exactly the same thing for two
> different inputs.
Will fix in next patch.

>> +static int mxs_saif_startup(struct snd_pcm_substream *substream,
>> + ? ? ? ? ? ? ? ? ? ? ? ?struct snd_soc_dai *cpu_dai)
>> +{
>> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
>> + ? ? snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
>> +
>> + ? ? return 0;
>> +}
>
> Remove empty functions.
This is to set dma param.

>> +/*
>> + * Should only be called when port is inactive.
>> + * although can be called multiple times by upper layers.
>> + */
>> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?struct snd_pcm_hw_params *params,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?struct snd_soc_dai *cpu_dai)
>
> The requirement for the port to be inactive is totally unreasonable,
> especially given that the params are configured by applications and you
> support simultaneous playback and record.
Yes, i will remove it. Finally we will support simultaneous playback and record.

>> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
>> +{
>> + ? ? struct mxs_saif *saif = dev_id;
>> +
>> + ? ? if (saif->fifo_err_counter++ % 100 == 0)
>
> The rate limit looks awfully suspicious...
Originally it's just for printing less error messages when the issue happens.
I could remove the rate limit.

>> + ? ? ? ? ? ? printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \
>> + ? ? ? ? ? ? ? ? ? ? fifo_errs=%d \n",
>> + ? ? ? ? ? ? ? ? ? ?__raw_readl(saif->base + SAIF_STAT),
>> + ? ? ? ? ? ? ? ? ? ?__raw_readl(saif->base + SAIF_CTRL),
>> + ? ? ? ? ? ? ? ? ? ?saif->fifo_err_counter);
>
> dev_err()
Will change.

>> + ? ? __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
>> + ? ? ? ? ? ? ? ? ? ? BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
>> + ? ? ? ? ? ? ? ? ? ? saif->base + SAIF_STAT + MXS_CLR_ADDR);
>> +
>> + ? ? return IRQ_HANDLED;
>
> You're not actually checking that the relevant interrupt fired...
I will add the checking for different errors.

>> + ? ? saif->clk = clk_get(&pdev->dev, NULL);
>> + ? ? if (IS_ERR(saif->clk)) {
>> + ? ? ? ? ? ? ret = PTR_ERR(saif->clk);
>> + ? ? ? ? ? ? dev_err(&pdev->dev, "Cannot get the clock: %d\n",
>> + ? ? ? ? ? ? ? ? ? ? ret);
>> + ? ? ? ? ? ? goto failed_clk;
>> + ? ? }
>> + ? ? clk_set_rate(saif->clk, 12000000);
>> + ? ? clk_enable(saif->clk);
>
> How did you pick this clock rate and why does it need to be set? ?It's
> not an obvious audio rate...
It's initial clock rate for normal operations of codecs based on MCLK.
We found the default MCLK ouput(only about 7.3Khz) can not work for codecs like
sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz.
So we set a common working clock 12Mhz here.
Maybe i should try to set it elsewhere or just set it via platform data.

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

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

* Re: [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
  2011-07-10  6:28       ` Dong Aisheng
@ 2011-07-10  8:21         ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  8:21 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

On Sun, Jul 10, 2011 at 02:28:26PM +0800, Dong Aisheng wrote:
> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Fri, Jul 08, 2011 at 11:59:41PM +0800, Dong Aisheng wrote:

> >> + * Refer to sound/soc/imx/imx-pcm-dma-mx2.c

> > Why?

> Just with the reference of  imx-pcm-dma-mx2.c code.

What is the relevance of that specific code compared to other DMA
drivers, though?

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

* [PATCH 01/10] ASoc: mxs: add mxs-pcm driver
@ 2011-07-10  8:21         ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  8:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2011 at 02:28:26PM +0800, Dong Aisheng wrote:
> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Fri, Jul 08, 2011 at 11:59:41PM +0800, Dong Aisheng wrote:

> >> + * Refer to sound/soc/imx/imx-pcm-dma-mx2.c

> > Why?

> Just with the reference of  imx-pcm-dma-mx2.c code.

What is the relevance of that specific code compared to other DMA
drivers, though?

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-10  8:17       ` Dong Aisheng
@ 2011-07-10  8:34         ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  8:34 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:
> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:

> >> +     switch (clk_id) {
> >> +     case MXS_SAIF_SYS_CLK:
> >> +             clk_set_rate(saif->clk, freq);
> >> +             clk_enable(saif->clk);

> > How would one turn this clock off?

> Currenty simply enable clock always.

If that's what you're doing you should enable the clock when the device
is probed and disable it when the device is removed.  These repeated
enables will mean that you're constantly leaking references.

> The problem is that the codec may use the MCLK supplied by SAIF as its
> system clock for normal operations such as i2c r/w.

That may be true for your particular system but it is not going to be
true in general - most devices can handle having their MCLK removed.

> If we disable it after playback or capture. The automatic dapm
> operations of codec may fail on i2c r/w. Will check if dapm has any
> machnism to avoid this.
> Can you share your experience ont this issue?

You should ideally let the machine driver or other system integration
code control if the clock is constantly enabled, or at the very least
control it from the probe and remove.

> >> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
> >> +{
> >> +     struct mxs_saif *saif = dev_id;
> >> +
> >> +     if (saif->fifo_err_counter++ % 100 == 0)
> >
> > The rate limit looks awfully suspicious...
> Originally it's just for printing less error messages when the issue happens.
> I could remove the rate limit.

Please do so.

> >> +     clk_set_rate(saif->clk, 12000000);
> >> +     clk_enable(saif->clk);

> > How did you pick this clock rate and why does it need to be set?  It's
> > not an obvious audio rate...

> It's initial clock rate for normal operations of codecs based on MCLK.
> We found the default MCLK ouput(only about 7.3Khz) can not work for codecs like
> sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz.
> So we set a common working clock 12Mhz here.
> Maybe i should try to set it elsewhere or just set it via platform data.

This is the same issue as the above one with repeated enables?  You
should delegate the rate selection and ideally also the enable control
to the machine driver, it can set something in its probe() function.

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-10  8:34         ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  8:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:
> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:

> >> + ? ? switch (clk_id) {
> >> + ? ? case MXS_SAIF_SYS_CLK:
> >> + ? ? ? ? ? ? clk_set_rate(saif->clk, freq);
> >> + ? ? ? ? ? ? clk_enable(saif->clk);

> > How would one turn this clock off?

> Currenty simply enable clock always.

If that's what you're doing you should enable the clock when the device
is probed and disable it when the device is removed.  These repeated
enables will mean that you're constantly leaking references.

> The problem is that the codec may use the MCLK supplied by SAIF as its
> system clock for normal operations such as i2c r/w.

That may be true for your particular system but it is not going to be
true in general - most devices can handle having their MCLK removed.

> If we disable it after playback or capture. The automatic dapm
> operations of codec may fail on i2c r/w. Will check if dapm has any
> machnism to avoid this.
> Can you share your experience ont this issue?

You should ideally let the machine driver or other system integration
code control if the clock is constantly enabled, or at the very least
control it from the probe and remove.

> >> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
> >> +{
> >> + ? ? struct mxs_saif *saif = dev_id;
> >> +
> >> + ? ? if (saif->fifo_err_counter++ % 100 == 0)
> >
> > The rate limit looks awfully suspicious...
> Originally it's just for printing less error messages when the issue happens.
> I could remove the rate limit.

Please do so.

> >> + ? ? clk_set_rate(saif->clk, 12000000);
> >> + ? ? clk_enable(saif->clk);

> > How did you pick this clock rate and why does it need to be set? ?It's
> > not an obvious audio rate...

> It's initial clock rate for normal operations of codecs based on MCLK.
> We found the default MCLK ouput(only about 7.3Khz) can not work for codecs like
> sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz.
> So we set a common working clock 12Mhz here.
> Maybe i should try to set it elsewhere or just set it via platform data.

This is the same issue as the above one with repeated enables?  You
should delegate the rate selection and ideally also the enable control
to the machine driver, it can set something in its probe() function.

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

* Re: [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
  2011-07-09  3:00     ` Mark Brown
@ 2011-07-10  8:36       ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:36 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:43PM +0800, Dong Aisheng wrote:
>> The driver only supports playback firstly.
>
> Once more, *always* CC maintainers.
Got it.

>> +struct mxs_audio_platform_data {
>> +     int sysclk;
>> +
>> +     int (*init) (void);     /* board specific init */
>> +     int (*finit) (void);    /* board specific finit */
>
> Eh?  Your machine driver is already entirely board specific...
Still not.
It's originally used for some board's codec that do not need SAIF to
provide mclk.
I will remove it if we still do not need it to make the things simply.

>> +     /* The SAIF clock should be either 512*fs or 384*fs */
>> +     card_priv.sysclk = 512 * rate;
>> +     ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_SYS_CLK,
>> +                     card_priv.sysclk,
>> +                     SND_SOC_CLOCK_OUT);
>
> Why are you storing the sysclk?  You never reference it again and
> you're using different sysclks for everything in the system.
Yes, it may not really need to store it in this version of code.
I will change this part of clock setting in the next patch.

>> +     /* set SGTL5000_SYSCLK as 256*fs to support 96k sample rate */
>> +     snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 256 * rate, 0);
>> +
>> +     /* The MCLK output rate is 256*fs */
>> +     snd_soc_dai_set_clkdiv(cpu_dai, MXS_SAIF_MCLK, 256);
>
> Why are you not checking errors on these?
Will add it.

>> +static int mxs_sgtl5000_soc_init(struct snd_soc_pcm_runtime *rtd)
>> +{
>> +     /* TBD: add dapm widgets */
>> +
>> +     return 0;
>> +}
>
> Remove empty functions.
Will do that.

>> +static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
>> +{
>> +     struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
>> +     int ret;
>> +
>> +     card_priv.pdev = pdev;
>> +
>> +     ret = -EINVAL;
>> +     if (plat && plat->init && plat->init())
>> +             return ret;
>
> You're not calling snd_soc_register_card()...
>
>> +     mxs_sgtl5000_snd_device = platform_device_alloc("soc-audio", -1);
>> +     if (!mxs_sgtl5000_snd_device)
>> +             return -ENOMEM;
>
> ...and you're using both a platform device and soc-audio to instantate
> which is a bit confused.  New code should not be using soc-audio.
Thanks for reminder.
I will change this part of code to following the new rule.

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

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

* [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
@ 2011-07-10  8:36       ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:36 UTC (permalink / raw)
  To: linux-arm-kernel

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:43PM +0800, Dong Aisheng wrote:
>> The driver only supports playback firstly.
>
> Once more, *always* CC maintainers.
Got it.

>> +struct mxs_audio_platform_data {
>> + ? ? int sysclk;
>> +
>> + ? ? int (*init) (void); ? ? /* board specific init */
>> + ? ? int (*finit) (void); ? ?/* board specific finit */
>
> Eh? ?Your machine driver is already entirely board specific...
Still not.
It's originally used for some board's codec that do not need SAIF to
provide mclk.
I will remove it if we still do not need it to make the things simply.

>> + ? ? /* The SAIF clock should be either 512*fs or 384*fs */
>> + ? ? card_priv.sysclk = 512 * rate;
>> + ? ? ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_SYS_CLK,
>> + ? ? ? ? ? ? ? ? ? ? card_priv.sysclk,
>> + ? ? ? ? ? ? ? ? ? ? SND_SOC_CLOCK_OUT);
>
> Why are you storing the sysclk? ?You never reference it again and
> you're using different sysclks for everything in the system.
Yes, it may not really need to store it in this version of code.
I will change this part of clock setting in the next patch.

>> + ? ? /* set SGTL5000_SYSCLK as 256*fs to support 96k sample rate */
>> + ? ? snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 256 * rate, 0);
>> +
>> + ? ? /* The MCLK output rate is 256*fs */
>> + ? ? snd_soc_dai_set_clkdiv(cpu_dai, MXS_SAIF_MCLK, 256);
>
> Why are you not checking errors on these?
Will add it.

>> +static int mxs_sgtl5000_soc_init(struct snd_soc_pcm_runtime *rtd)
>> +{
>> + ? ? /* TBD: add dapm widgets */
>> +
>> + ? ? return 0;
>> +}
>
> Remove empty functions.
Will do that.

>> +static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
>> +{
>> + ? ? struct mxs_audio_platform_data *plat = pdev->dev.platform_data;
>> + ? ? int ret;
>> +
>> + ? ? card_priv.pdev = pdev;
>> +
>> + ? ? ret = -EINVAL;
>> + ? ? if (plat && plat->init && plat->init())
>> + ? ? ? ? ? ? return ret;
>
> You're not calling snd_soc_register_card()...
>
>> + ? ? mxs_sgtl5000_snd_device = platform_device_alloc("soc-audio", -1);
>> + ? ? if (!mxs_sgtl5000_snd_device)
>> + ? ? ? ? ? ? return -ENOMEM;
>
> ...and you're using both a platform device and soc-audio to instantate
> which is a bit confused. ?New code should not be using soc-audio.
Thanks for reminder.
I will change this part of code to following the new rule.

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

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

* Re: [PATCH 04/10] ASoc: mxs: add asoc configuration files
  2011-07-09  3:01     ` Mark Brown
@ 2011-07-10  8:37       ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:37 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:44PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>
> *Always* CC maintainers on patches.
>
>> @@ -57,6 +57,7 @@ source "sound/soc/s6000/Kconfig"
>>  source "sound/soc/sh/Kconfig"
>>  source "sound/soc/tegra/Kconfig"
>>  source "sound/soc/txx9/Kconfig"
>> +source "sound/soc/mxs/Kconfig"
>
> Keep all these files sorted.
Thanks for reminder.
Will fix in the updated v2 patch soon.

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

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

* [PATCH 04/10] ASoc: mxs: add asoc configuration files
@ 2011-07-10  8:37       ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:37 UTC (permalink / raw)
  To: linux-arm-kernel

2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Fri, Jul 08, 2011 at 11:59:44PM +0800, Dong Aisheng wrote:
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>
> *Always* CC maintainers on patches.
>
>> @@ -57,6 +57,7 @@ source "sound/soc/s6000/Kconfig"
>> ?source "sound/soc/sh/Kconfig"
>> ?source "sound/soc/tegra/Kconfig"
>> ?source "sound/soc/txx9/Kconfig"
>> +source "sound/soc/mxs/Kconfig"
>
> Keep all these files sorted.
Thanks for reminder.
Will fix in the updated v2 patch soon.

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

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

* Re: [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
  2011-07-10  8:36       ` Dong Aisheng
@ 2011-07-10  8:40         ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  8:40 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

On Sun, Jul 10, 2011 at 04:36:44PM +0800, Dong Aisheng wrote:
> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Fri, Jul 08, 2011 at 11:59:43PM +0800, Dong Aisheng wrote:

> >> +     int (*init) (void);     /* board specific init */
> >> +     int (*finit) (void);    /* board specific finit */

> > Eh?  Your machine driver is already entirely board specific...

> Still not.

> It's originally used for some board's codec that do not need SAIF to
> provide mclk.
> I will remove it if we still do not need it to make the things simply.

If you've got different CODECs you almost certainly want to have
different machine drivers for the relevant boards.

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

* [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver
@ 2011-07-10  8:40         ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  8:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2011 at 04:36:44PM +0800, Dong Aisheng wrote:
> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Fri, Jul 08, 2011 at 11:59:43PM +0800, Dong Aisheng wrote:

> >> + ? ? int (*init) (void); ? ? /* board specific init */
> >> + ? ? int (*finit) (void); ? ?/* board specific finit */

> > Eh? ?Your machine driver is already entirely board specific...

> Still not.

> It's originally used for some board's codec that do not need SAIF to
> provide mclk.
> I will remove it if we still do not need it to make the things simply.

If you've got different CODECs you almost certainly want to have
different machine drivers for the relevant boards.

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-10  8:34         ` Mark Brown
@ 2011-07-10  8:58           ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:58 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:
>> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
>> > On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
>
>> >> +     switch (clk_id) {
>> >> +     case MXS_SAIF_SYS_CLK:
>> >> +             clk_set_rate(saif->clk, freq);
>> >> +             clk_enable(saif->clk);
>
>> > How would one turn this clock off?
>
>> Currenty simply enable clock always.
>
> If that's what you're doing you should enable the clock when the device
> is probed and disable it when the device is removed.  These repeated
> enables will mean that you're constantly leaking references.
Yes, i noticed this issue.

>> The problem is that the codec may use the MCLK supplied by SAIF as its
>> system clock for normal operations such as i2c r/w.
>
> That may be true for your particular system but it is not going to be
> true in general - most devices can handle having their MCLK removed.
Yes, if i cover that, that may make driver a little complicated.
Should i do that now or as the next work?
Also i still do not have such type of codecs integrated on hand.

>> If we disable it after playback or capture. The automatic dapm
>> operations of codec may fail on i2c r/w. Will check if dapm has any
>> machnism to avoid this.
>> Can you share your experience ont this issue?
>
> You should ideally let the machine driver or other system integration
> code control if the clock is constantly enabled, or at the very least
> control it from the probe and remove.
Thanks for the suggestions.
I will try them.

>> >> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
>> >> +{
>> >> +     struct mxs_saif *saif = dev_id;
>> >> +
>> >> +     if (saif->fifo_err_counter++ % 100 == 0)
>> >
>> > The rate limit looks awfully suspicious...
>> Originally it's just for printing less error messages when the issue happens.
>> I could remove the rate limit.
>
> Please do so.
Got it.

>> >> +     clk_set_rate(saif->clk, 12000000);
>> >> +     clk_enable(saif->clk);
>
>> > How did you pick this clock rate and why does it need to be set?  It's
>> > not an obvious audio rate...
>
>> It's initial clock rate for normal operations of codecs based on MCLK.
>> We found the default MCLK ouput(only about 7.3Khz) can not work for codecs like
>> sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz.
>> So we set a common working clock 12Mhz here.
>> Maybe i should try to set it elsewhere or just set it via platform data.
>
> This is the same issue as the above one with repeated enables?  You
> should delegate the rate selection and ideally also the enable control
> to the machine driver, it can set something in its probe() function.
Not the same one. The repeated enables is a bug.(Will fix)
Here we just need set a init proper clock rate of MCLK for codec firstly.
(Codec's initialization(i2c r/w) in probe function may need it).
I would try your suggestion to let machine driver to set it.

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-10  8:58           ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10  8:58 UTC (permalink / raw)
  To: linux-arm-kernel

2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:
>> 2011/7/9 Mark Brown <broonie@opensource.wolfsonmicro.com>:
>> > On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote:
>
>> >> + ? ? switch (clk_id) {
>> >> + ? ? case MXS_SAIF_SYS_CLK:
>> >> + ? ? ? ? ? ? clk_set_rate(saif->clk, freq);
>> >> + ? ? ? ? ? ? clk_enable(saif->clk);
>
>> > How would one turn this clock off?
>
>> Currenty simply enable clock always.
>
> If that's what you're doing you should enable the clock when the device
> is probed and disable it when the device is removed. ?These repeated
> enables will mean that you're constantly leaking references.
Yes, i noticed this issue.

>> The problem is that the codec may use the MCLK supplied by SAIF as its
>> system clock for normal operations such as i2c r/w.
>
> That may be true for your particular system but it is not going to be
> true in general - most devices can handle having their MCLK removed.
Yes, if i cover that, that may make driver a little complicated.
Should i do that now or as the next work?
Also i still do not have such type of codecs integrated on hand.

>> If we disable it after playback or capture. The automatic dapm
>> operations of codec may fail on i2c r/w. Will check if dapm has any
>> machnism to avoid this.
>> Can you share your experience ont this issue?
>
> You should ideally let the machine driver or other system integration
> code control if the clock is constantly enabled, or at the very least
> control it from the probe and remove.
Thanks for the suggestions.
I will try them.

>> >> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
>> >> +{
>> >> + ? ? struct mxs_saif *saif = dev_id;
>> >> +
>> >> + ? ? if (saif->fifo_err_counter++ % 100 == 0)
>> >
>> > The rate limit looks awfully suspicious...
>> Originally it's just for printing less error messages when the issue happens.
>> I could remove the rate limit.
>
> Please do so.
Got it.

>> >> + ? ? clk_set_rate(saif->clk, 12000000);
>> >> + ? ? clk_enable(saif->clk);
>
>> > How did you pick this clock rate and why does it need to be set? ?It's
>> > not an obvious audio rate...
>
>> It's initial clock rate for normal operations of codecs based on MCLK.
>> We found the default MCLK ouput(only about 7.3Khz) can not work for codecs like
>> sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz.
>> So we set a common working clock 12Mhz here.
>> Maybe i should try to set it elsewhere or just set it via platform data.
>
> This is the same issue as the above one with repeated enables? ?You
> should delegate the rate selection and ideally also the enable control
> to the machine driver, it can set something in its probe() function.
Not the same one. The repeated enables is a bug.(Will fix)
Here we just need set a init proper clock rate of MCLK for codec firstly.
(Codec's initialization(i2c r/w) in probe function may need it).
I would try your suggestion to let machine driver to set it.

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-10  8:58           ` Dong Aisheng
@ 2011-07-10  9:26             ` Mark Brown
  -1 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  9:26 UTC (permalink / raw)
  To: Dong Aisheng; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

On Sun, Jul 10, 2011 at 04:58:10PM +0800, Dong Aisheng wrote:
> 2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:

> >> The problem is that the codec may use the MCLK supplied by SAIF as its
> >> system clock for normal operations such as i2c r/w.

> > That may be true for your particular system but it is not going to be
> > true in general - most devices can handle having their MCLK removed.

> Yes, if i cover that, that may make driver a little complicated.
> Should i do that now or as the next work?

It should simply be a case of adding handling of setting the sysclk to 0
(this is how ASoC indicates clocks should be disabled).  The machine
driver is then responsible for making sure it does the refcounting
properly, and for your system where the clock is enabled all the time
that's just a case of enabling on startup and disabling on remove.

> Also i still do not have such type of codecs integrated on hand.

That's fine, audio hardware is so flexible that it's unreasonable to
expect that all possible systems have been tested.  So long as the code
looks sensible it should be fine and if there are problems people can
always come back and fix them.

> > This is the same issue as the above one with repeated enables?  You
> > should delegate the rate selection and ideally also the enable control
> > to the machine driver, it can set something in its probe() function.

> Not the same one. The repeated enables is a bug.(Will fix)

Yes, but both are a result of the requirements of your CODEC?  Just
trying to understand if the I2S controller needs this itself or if it's
only for the CODEC.

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-10  9:26             ` Mark Brown
  0 siblings, 0 replies; 60+ messages in thread
From: Mark Brown @ 2011-07-10  9:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2011 at 04:58:10PM +0800, Dong Aisheng wrote:
> 2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> > On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:

> >> The problem is that the codec may use the MCLK supplied by SAIF as its
> >> system clock for normal operations such as i2c r/w.

> > That may be true for your particular system but it is not going to be
> > true in general - most devices can handle having their MCLK removed.

> Yes, if i cover that, that may make driver a little complicated.
> Should i do that now or as the next work?

It should simply be a case of adding handling of setting the sysclk to 0
(this is how ASoC indicates clocks should be disabled).  The machine
driver is then responsible for making sure it does the refcounting
properly, and for your system where the clock is enabled all the time
that's just a case of enabling on startup and disabling on remove.

> Also i still do not have such type of codecs integrated on hand.

That's fine, audio hardware is so flexible that it's unreasonable to
expect that all possible systems have been tested.  So long as the code
looks sensible it should be fine and if there are problems people can
always come back and fix them.

> > This is the same issue as the above one with repeated enables? ?You
> > should delegate the rate selection and ideally also the enable control
> > to the machine driver, it can set something in its probe() function.

> Not the same one. The repeated enables is a bug.(Will fix)

Yes, but both are a result of the requirements of your CODEC?  Just
trying to understand if the I2S controller needs this itself or if it's
only for the CODEC.

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-10  9:26             ` Mark Brown
@ 2011-07-10 11:59               ` Dong Aisheng
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10 11:59 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Dong Aisheng, s.hauer, linux-arm-kernel, lrg

2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Sun, Jul 10, 2011 at 04:58:10PM +0800, Dong Aisheng wrote:
>> 2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
>> > On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:
>
>> >> The problem is that the codec may use the MCLK supplied by SAIF as its
>> >> system clock for normal operations such as i2c r/w.
>
>> > That may be true for your particular system but it is not going to be
>> > true in general - most devices can handle having their MCLK removed.
>
>> Yes, if i cover that, that may make driver a little complicated.
>> Should i do that now or as the next work?
>
> It should simply be a case of adding handling of setting the sysclk to 0
> (this is how ASoC indicates clocks should be disabled).  The machine
> driver is then responsible for making sure it does the refcounting
> properly, and for your system where the clock is enabled all the time
> that's just a case of enabling on startup and disabling on remove.
Ok, i will take account of that.
Thanks for your suggestion.

>> Also i still do not have such type of codecs integrated on hand.
>
> That's fine, audio hardware is so flexible that it's unreasonable to
> expect that all possible systems have been tested.  So long as the code
> looks sensible it should be fine and if there are problems people can
> always come back and fix them.
OK.

>> > This is the same issue as the above one with repeated enables?  You
>> > should delegate the rate selection and ideally also the enable control
>> > to the machine driver, it can set something in its probe() function.
>
>> Not the same one. The repeated enables is a bug.(Will fix)
>
> Yes, but both are a result of the requirements of your CODEC?  Just
> trying to understand if the I2S controller needs this itself or if it's
> only for the CODEC.
Based on my understanding, only for codec.
I will double check it with IC man.

Regards
Dong Aisheng

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-10 11:59               ` Dong Aisheng
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng @ 2011-07-10 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Sun, Jul 10, 2011 at 04:58:10PM +0800, Dong Aisheng wrote:
>> 2011/7/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
>> > On Sun, Jul 10, 2011 at 04:17:13PM +0800, Dong Aisheng wrote:
>
>> >> The problem is that the codec may use the MCLK supplied by SAIF as its
>> >> system clock for normal operations such as i2c r/w.
>
>> > That may be true for your particular system but it is not going to be
>> > true in general - most devices can handle having their MCLK removed.
>
>> Yes, if i cover that, that may make driver a little complicated.
>> Should i do that now or as the next work?
>
> It should simply be a case of adding handling of setting the sysclk to 0
> (this is how ASoC indicates clocks should be disabled). ?The machine
> driver is then responsible for making sure it does the refcounting
> properly, and for your system where the clock is enabled all the time
> that's just a case of enabling on startup and disabling on remove.
Ok, i will take account of that.
Thanks for your suggestion.

>> Also i still do not have such type of codecs integrated on hand.
>
> That's fine, audio hardware is so flexible that it's unreasonable to
> expect that all possible systems have been tested. ?So long as the code
> looks sensible it should be fine and if there are problems people can
> always come back and fix them.
OK.

>> > This is the same issue as the above one with repeated enables? ?You
>> > should delegate the rate selection and ideally also the enable control
>> > to the machine driver, it can set something in its probe() function.
>
>> Not the same one. The repeated enables is a bug.(Will fix)
>
> Yes, but both are a result of the requirements of your CODEC? ?Just
> trying to understand if the I2S controller needs this itself or if it's
> only for the CODEC.
Based on my understanding, only for codec.
I will double check it with IC man.

Regards
Dong Aisheng

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-10  9:26             ` Mark Brown
@ 2011-07-11 10:00               ` Wolfram Sang
  -1 siblings, 0 replies; 60+ messages in thread
From: Wolfram Sang @ 2011-07-11 10:00 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, Dong Aisheng, s.hauer, Dong Aisheng, lrg, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 586 bytes --]


> > Also i still do not have such type of codecs integrated on hand.
> 
> That's fine, audio hardware is so flexible that it's unreasonable to
> expect that all possible systems have been tested.  So long as the code
> looks sensible it should be fine and if there are problems people can
> always come back and fix them.

I will get a custom board with a different codec in about a month and
will happily do tests.

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

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

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-11 10:00               ` Wolfram Sang
  0 siblings, 0 replies; 60+ messages in thread
From: Wolfram Sang @ 2011-07-11 10:00 UTC (permalink / raw)
  To: linux-arm-kernel


> > Also i still do not have such type of codecs integrated on hand.
> 
> That's fine, audio hardware is so flexible that it's unreasonable to
> expect that all possible systems have been tested.  So long as the code
> looks sensible it should be fine and if there are problems people can
> always come back and fix them.

I will get a custom board with a different codec in about a month and
will happily do tests.

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110711/ef0ed5d0/attachment.sig>

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

* Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
  2011-07-11 10:00               ` Wolfram Sang
@ 2011-07-13  3:28                 ` Dong Aisheng-B29396
  -1 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng-B29396 @ 2011-07-13  3:28 UTC (permalink / raw)
  To: Wolfram Sang, Mark Brown
  Cc: alsa-devel, s.hauer, Dong Aisheng, linux-arm-kernel, lrg

> -----Original Message-----
> From: Wolfram Sang [mailto:w.sang@pengutronix.de]
> Sent: Monday, July 11, 2011 6:00 PM
> To: Mark Brown
> Cc: Dong Aisheng; alsa-devel@alsa-project.org; Dong Aisheng-B29396;
> s.hauer@pengutronix.de; linux-arm-kernel@lists.infradead.org; lrg@ti.com
> Subject: Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
> 
> 
> > > Also i still do not have such type of codecs integrated on hand.
> >
> > That's fine, audio hardware is so flexible that it's unreasonable to
> > expect that all possible systems have been tested.  So long as the
> > code looks sensible it should be fine and if there are problems people
> > can always come back and fix them.
> 
> I will get a custom board with a different codec in about a month and
> will happily do tests.

That would be good.
Thanks a lot.

Regards
Dong Aisheng

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

* [PATCH 02/10] ASoc: mxs: add mxs-saif driver
@ 2011-07-13  3:28                 ` Dong Aisheng-B29396
  0 siblings, 0 replies; 60+ messages in thread
From: Dong Aisheng-B29396 @ 2011-07-13  3:28 UTC (permalink / raw)
  To: linux-arm-kernel

> -----Original Message-----
> From: Wolfram Sang [mailto:w.sang at pengutronix.de]
> Sent: Monday, July 11, 2011 6:00 PM
> To: Mark Brown
> Cc: Dong Aisheng; alsa-devel at alsa-project.org; Dong Aisheng-B29396;
> s.hauer at pengutronix.de; linux-arm-kernel at lists.infradead.org; lrg at ti.com
> Subject: Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver
> 
> 
> > > Also i still do not have such type of codecs integrated on hand.
> >
> > That's fine, audio hardware is so flexible that it's unreasonable to
> > expect that all possible systems have been tested.  So long as the
> > code looks sensible it should be fine and if there are problems people
> > can always come back and fix them.
> 
> I will get a custom board with a different codec in about a month and
> will happily do tests.

That would be good.
Thanks a lot.

Regards
Dong Aisheng

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

end of thread, other threads:[~2011-07-13  3:28 UTC | newest]

Thread overview: 60+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-08 15:59 [PATCH 00/10] ARM: mxs: add audio support Dong Aisheng
2011-07-08 15:59 ` Dong Aisheng
2011-07-08 15:59 ` [PATCH 01/10] ASoc: mxs: add mxs-pcm driver Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-09  2:33   ` Mark Brown
2011-07-09  2:33     ` Mark Brown
2011-07-10  6:28     ` Dong Aisheng
2011-07-10  6:28       ` Dong Aisheng
2011-07-10  8:21       ` Mark Brown
2011-07-10  8:21         ` Mark Brown
2011-07-08 15:59 ` [PATCH 02/10] ASoc: mxs: add mxs-saif driver Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-08 16:19   ` Sascha Hauer
2011-07-08 16:19     ` Sascha Hauer
2011-07-08 17:10     ` Wolfram Sang
2011-07-08 17:10       ` Wolfram Sang
2011-07-08 18:35     ` Dong Aisheng
2011-07-08 18:35       ` Dong Aisheng
2011-07-09  2:52   ` Mark Brown
2011-07-09  2:52     ` Mark Brown
2011-07-10  8:17     ` Dong Aisheng
2011-07-10  8:17       ` Dong Aisheng
2011-07-10  8:34       ` Mark Brown
2011-07-10  8:34         ` Mark Brown
2011-07-10  8:58         ` Dong Aisheng
2011-07-10  8:58           ` Dong Aisheng
2011-07-10  9:26           ` Mark Brown
2011-07-10  9:26             ` Mark Brown
2011-07-10 11:59             ` Dong Aisheng
2011-07-10 11:59               ` Dong Aisheng
2011-07-11 10:00             ` Wolfram Sang
2011-07-11 10:00               ` Wolfram Sang
2011-07-13  3:28               ` Dong Aisheng-B29396
2011-07-13  3:28                 ` Dong Aisheng-B29396
2011-07-08 15:59 ` [PATCH 03/10] ASoc: mxs: add mxs-sgtl5000 machine driver Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-09  3:00   ` Mark Brown
2011-07-09  3:00     ` Mark Brown
2011-07-10  8:36     ` Dong Aisheng
2011-07-10  8:36       ` Dong Aisheng
2011-07-10  8:40       ` Mark Brown
2011-07-10  8:40         ` Mark Brown
2011-07-08 15:59 ` [PATCH 04/10] ASoc: mxs: add asoc configuration files Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-09  3:01   ` Mark Brown
2011-07-09  3:01     ` Mark Brown
2011-07-10  8:37     ` Dong Aisheng
2011-07-10  8:37       ` Dong Aisheng
2011-07-08 15:59 ` [PATCH 05/10] ARM: mxs: add saif clock Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-08 15:59 ` [PATCH 06/10] ARM: mxs: add saif device Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-08 15:59 ` [PATCH 07/10] ARM: mxs: add sgtl5000 i2c device Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-08 15:59 ` [PATCH 08/10] ARM: mxs: add mxs-sgtl5000 device Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-08 15:59 ` [PATCH 09/10] ARM: mxs: correct the using of frac div for saif Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng
2011-07-08 15:59 ` [PATCH 10/10] ARM: mxs-dma: include <linux/dmaengine.h> Dong Aisheng
2011-07-08 15:59   ` Dong Aisheng

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.