All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Add ASoC drivers for SPEAr platform
@ 2012-03-20 11:33 Rajeev Kumar
  2012-03-20 11:33 ` [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec Rajeev Kumar
                   ` (7 more replies)
  0 siblings, 8 replies; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, spear-devel, Rajeev Kumar, lrg

This patch set adds support for ASoC sound drivers on ST's SPEAr
platforms. Details of the SPEAr platforms can be seen here:

http://www.st.com/internet/mcu/product/250658.jsp

This patch set supports the following modules:

1. Audio codec sta529 (connected to I2S controller).
2. SPDIF IN dummy Codec.
3. Synopsys Designware I2S controller.
4. ST SPDIF IN controller.
5. ST SPDIF OUT controller.

This patch set has been tested for linux-kernel-version 3.3-rc3 on SPEAr
platform.

In past, I had circulated the patch for the same and got some review
comments. I have incorporate those commnets also. Please find the link
below.
http://mailman.alsa-project.org/pipermail/alsa-devel/2011-April/038738.html

Rajeev Kumar (6):
  sound:asoc: Add support for STA529 Audio Codec
  sound:asoc: Add support for synopsys i2s controller as per ASoC
    framework.
  sound:asoc: Add support for SPEAr ASoC pcm layer.
  sound:asoc: Add support for SPEAr ASoC machine driver.
  sound:asoc: Add Kconfig and Makefile to support SPEAr audio driver
  sound:asoc: Update Kconfig and Makefile(sound/soc/) to support SPEAr
    audio

Vipin Kumar (2):
  sound:asoc:spdif_in: Add spdif IN support
  sound:asoc:spdif_out: Add spdif out support

 include/linux/designware_i2s.h   |   63 ++++
 sound/soc/Kconfig                |    1 +
 sound/soc/Makefile               |    1 +
 sound/soc/codecs/Kconfig         |    5 +
 sound/soc/codecs/Makefile        |    2 +
 sound/soc/codecs/sta529.c        |  414 ++++++++++++++++++++++++++
 sound/soc/spear/Kconfig          |   46 +++
 sound/soc/spear/Makefile         |   16 +
 sound/soc/spear/designware_i2s.c |  610 ++++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spdif_in.c       |  304 +++++++++++++++++++
 sound/soc/spear/spdif_in_regs.h  |   60 ++++
 sound/soc/spear/spdif_out.c      |  397 +++++++++++++++++++++++++
 sound/soc/spear/spdif_out_regs.h |   79 +++++
 sound/soc/spear/spear_evb.c      |  278 +++++++++++++++++
 sound/soc/spear/spear_pcm.c      |  460 ++++++++++++++++++++++++++++
 sound/soc/spear/spear_pcm.h      |   33 ++
 16 files changed, 2769 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/designware_i2s.h
 create mode 100644 sound/soc/codecs/sta529.c
 create mode 100644 sound/soc/spear/Kconfig
 create mode 100644 sound/soc/spear/Makefile
 create mode 100644 sound/soc/spear/designware_i2s.c
 create mode 100644 sound/soc/spear/spdif_in.c
 create mode 100644 sound/soc/spear/spdif_in_regs.h
 create mode 100644 sound/soc/spear/spdif_out.c
 create mode 100644 sound/soc/spear/spdif_out_regs.h
 create mode 100644 sound/soc/spear/spear_evb.c
 create mode 100644 sound/soc/spear/spear_pcm.c
 create mode 100644 sound/soc/spear/spear_pcm.h

-- 
1.7.2.2

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

* [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  2012-03-20 15:25   ` Mark Brown
  2012-03-20 17:57   ` Lars-Peter Clausen
  2012-03-20 11:33 ` [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework Rajeev Kumar
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, spear-devel, Rajeev Kumar, lrg

This patch adds the support for STA529 audio codec.
Details of the audio codec can be seen here:
http://www.st.com/internet/imag_video/product/159187.jsp

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 sound/soc/codecs/Kconfig  |    5 +
 sound/soc/codecs/Makefile |    2 +
 sound/soc/codecs/sta529.c |  414 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 421 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/sta529.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 59d8efa..2c003d1 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_SPDIF
 	select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_STA32X if I2C
+	select SND_SOC_STA529 if I2C
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -252,6 +253,10 @@ config SND_SOC_SSM2602
 config SND_SOC_STA32X
 	tristate
 
+config SND_SOC_STA529
+	tristate
+	depends on I2C
+
 config SND_SOC_STAC9766
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0c0e6ce..a0e43cd 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-sn95031-objs := sn95031.o
 snd-soc-spdif-objs := spdif_transciever.o spdif_receiver.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-sta32x-objs := sta32x.o
+snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
@@ -143,6 +144,7 @@ obj-$(CONFIG_SND_SOC_SN95031)	+=snd-soc-sn95031.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
+obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
new file mode 100644
index 0000000..1294947
--- /dev/null
+++ b/sound/soc/codecs/sta529.c
@@ -0,0 +1,414 @@
+/*
+ * ASoC codec driver for spear platform
+ *
+ * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Rajeev Kumar <rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+/* STA529 Register offsets */
+#define	 STA529_FFXCFG0		0x00
+#define	 STA529_FFXCFG1		0x01
+#define	 STA529_MVOL		0x02
+#define	 STA529_LVOL		0x03
+#define	 STA529_RVOL		0x04
+#define	 STA529_TTF0		0x05
+#define	 STA529_TTF1		0x06
+#define	 STA529_TTP0		0x07
+#define	 STA529_TTP1		0x08
+#define	 STA529_S2PCFG0		0x0A
+#define	 STA529_S2PCFG1		0x0B
+#define	 STA529_P2SCFG0		0x0C
+#define	 STA529_P2SCFG1		0x0D
+#define	 STA529_PLLCFG0		0x14
+#define	 STA529_PLLCFG1		0x15
+#define	 STA529_PLLCFG2		0x16
+#define	 STA529_PLLCFG3		0x17
+#define	 STA529_PLLPFE		0x18
+#define	 STA529_PLLST		0x19
+#define	 STA529_ADCCFG		0x1E /*mic_select*/
+#define	 STA529_CKOCFG		0x1F
+#define	 STA529_MISC		0x20
+#define	 STA529_PADST0		0x21
+#define	 STA529_PADST1		0x22
+#define	 STA529_FFXST		0x23
+#define	 STA529_PWMIN1		0x2D
+#define	 STA529_PWMIN2		0x2E
+#define	 STA529_POWST		0x32
+
+#define STA529_CACHEREGNUM	0x33 /*total num of reg. in sta529*/
+
+#define STA529_RATES		(SNDRV_PCM_RATE_8000 | \
+				SNDRV_PCM_RATE_11025 | \
+				SNDRV_PCM_RATE_16000 | \
+				SNDRV_PCM_RATE_22050 | \
+				SNDRV_PCM_RATE_32000 | \
+				SNDRV_PCM_RATE_44100 | \
+				SNDRV_PCM_RATE_48000)
+
+#define STA529_FORMAT		SNDRV_PCM_FMTBIT_S16_LE
+#define	S2PC_VALUE		0x98
+#define CLOCK_OUT		0x60
+#define LEFT_J_DATA_FORMAT	0x10
+#define I2S_DATA_FORMAT		0x12
+#define RIGHT_J_DATA_FORMAT	0x14
+#define CODEC_MUTE_VAL		0x80
+
+#define POWER_CNTLMSAK		0x40
+#define POWER_STDBY		0x40
+#define FFX_MASK		0x80
+#define FFX_OFF			0x80
+#define POWER_UP		0x00
+
+static const u8 sta529_reg[STA529_CACHEREGNUM] = {
+	0x35, 0xc8, 0x50, 0x00,
+	0x00, 0x00, 0x02, 0x00,
+	0x02, 0x05, 0xb2, 0x41,
+	0x92, 0x41, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x80, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xD2, 0x40,
+	0x21, 0xef, 0x04, 0x06,
+	0x41, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+};
+
+struct sta529 {
+	unsigned int sysclk;
+	enum snd_soc_control_type control_type;
+	void *control_data;
+};
+
+static const char *pwm_mode_text[] = { "binary", "headphone", "ternary",
+	"phase-shift"};
+static const char *interface_mode_text[] = { "slave", "master"};
+
+static const struct soc_enum pwm_src_enum =
+SOC_ENUM_SINGLE(STA529_FFXCFG1, 4, 4, pwm_mode_text);
+
+static const struct soc_enum mode_src_enum =
+SOC_ENUM_SINGLE(STA529_P2SCFG0, 0, 2, interface_mode_text);
+
+static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
+	SOC_ENUM("PWM Select", pwm_src_enum),
+	SOC_ENUM("MODE Select", mode_src_enum),
+};
+
+static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0);
+static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0);
+
+static const struct snd_kcontrol_new sta529_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0,
+			127, 0, out_gain_tlv),
+	SOC_SINGLE_TLV("Master Playback Volume", STA529_MVOL, 0, 127, 1,
+			master_vol_tlv),
+};
+
+static int
+sta529_set_bias_level(struct snd_soc_codec *codec,
+		enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK,
+				POWER_UP);
+		snd_soc_update_bits(codec, STA529_MISC, 1, 0x01);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK,
+				POWER_STDBY);
+		/* Making FFX output to zero */
+		snd_soc_update_bits(codec, STA529_FFXCFG0, FFX_MASK,
+				FFX_OFF);
+		snd_soc_update_bits(codec, STA529_MISC, 1, 0x00);
+
+		break;
+	}
+
+	/*
+	 * store the label for powers down audio subsystem for suspend.This is
+	 * used by soc core layer
+	 */
+	codec->dapm.bias_level = level;
+	return 0;
+
+}
+
+static int sta529_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	int pdata, play_freq_val, record_freq_val;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		pdata = 1;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		pdata = 2;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		pdata = 3;
+		break;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 11025:
+		play_freq_val = 0;
+		record_freq_val = 2;
+		break;
+	case 16000:
+	case 22050:
+		play_freq_val = 1;
+		record_freq_val = 0;
+		break;
+
+	case 32000:
+	case 44100:
+	case 48000:
+		play_freq_val = 2;
+		record_freq_val = 0;
+		break;
+	default:
+		printk(KERN_WARNING, "bad rate\n");
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		snd_soc_update_bits(codec, STA529_S2PCFG1, 0xC0, (pdata << 6));
+		snd_soc_update_bits(codec, STA529_MISC, 0x0C,
+				(play_freq_val << 4));
+	} else {
+		snd_soc_update_bits(codec, STA529_P2SCFG1, 0xC0, (pdata << 6));
+		snd_soc_update_bits(codec, STA529_MISC, 0x0C,
+				(record_freq_val << 2));
+
+	}
+
+	sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+	mdelay(10);
+
+	return 0;
+}
+
+static int sta529_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	u8 mute_reg = snd_soc_read(codec, STA529_FFXCFG0) & ~CODEC_MUTE_VAL;
+
+	if (mute)
+		mute_reg |= CODEC_MUTE_VAL;
+
+	snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, 00);
+
+	return 0;
+}
+
+static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 mode = 0;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode = LEFT_J_DATA_FORMAT;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		mode = I2S_DATA_FORMAT;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		mode = RIGHT_J_DATA_FORMAT;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mode |= 0x20;
+	snd_soc_update_bits(codec, STA529_S2PCFG0, 0xE0, mode);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops sta529_dai_ops = {
+	.hw_params	=	sta529_hw_params,
+	.set_fmt	=	sta529_set_dai_fmt,
+	.digital_mute	=	sta529_mute,
+};
+
+static struct snd_soc_dai_driver sta529_dai = {
+	.name = "sta529-audio",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = STA529_RATES,
+		.formats = STA529_FORMAT,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = STA529_RATES,
+		.formats = STA529_FORMAT,
+	},
+	.ops	= &sta529_dai_ops,
+};
+
+static int sta529_probe(struct snd_soc_codec *codec)
+{
+	struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, sta529->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+	sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_add_controls(codec, sta529_snd_controls,
+			ARRAY_SIZE(sta529_snd_controls));
+
+	snd_soc_add_controls(codec, sta529_new_snd_controls,
+			ARRAY_SIZE(sta529_new_snd_controls));
+	return 0;
+}
+
+/* power down chip */
+static int sta529_remove(struct snd_soc_codec *codec)
+{
+	sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int sta529_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int sta529_resume(struct snd_soc_codec *codec)
+{
+	snd_soc_cache_sync(codec);
+	sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	sta529_set_bias_level(codec, codec->dapm.suspend_bias_level);
+
+	return 0;
+}
+
+struct snd_soc_codec_driver soc_codec_dev_sta529 = {
+	.probe = sta529_probe,
+	.remove = sta529_remove,
+	.set_bias_level = sta529_set_bias_level,
+	.suspend = sta529_suspend,
+	.resume = sta529_resume,
+	.reg_cache_size = STA529_CACHEREGNUM,
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = sta529_reg,
+
+};
+
+static __devinit int sta529_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	struct sta529 *sta529;
+	int ret;
+
+	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EINVAL;
+
+	sta529 = kzalloc(sizeof(struct sta529), GFP_KERNEL);
+	if (sta529 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, sta529);
+	sta529->control_data = i2c;
+	sta529->control_type = SND_SOC_I2C;
+
+	ret = snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_sta529, &sta529_dai, 1);
+	if (ret < 0)
+		kfree(sta529);
+	return ret;
+}
+
+static int sta529_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id sta529_i2c_id[] = {
+	{ "sta529", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, sta529_i2c_id);
+
+static struct i2c_driver sta529_i2c_driver = {
+	.driver = {
+		.name = "sta529",
+		.owner = THIS_MODULE,
+	},
+	.probe		= sta529_i2c_probe,
+	.remove		= __devexit_p(sta529_i2c_remove),
+	.id_table	= sta529_i2c_id,
+};
+
+static int __init sta529_modinit(void)
+{
+	int ret = 0;
+
+	ret = i2c_add_driver(&sta529_i2c_driver);
+	if (ret != 0)
+		printk(KERN_ERR "Failed to reg sta529 I2C driver: %d\n", ret);
+
+	return ret;
+
+}
+module_init(sta529_modinit);
+
+static void __exit sta529_exit(void)
+{
+	i2c_del_driver(&sta529_i2c_driver);
+}
+module_exit(sta529_exit);
+
+MODULE_DESCRIPTION("ASoC STA529 codec driver");
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.2.2

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

* [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework.
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
  2012-03-20 11:33 ` [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  2012-03-20 15:44   ` Mark Brown
  2012-03-20 11:33 ` [PATCH 3/8] sound:asoc: Add support for SPEAr ASoC pcm layer Rajeev Kumar
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, spear-devel, Rajeev Kumar, lrg

This patch add support for synopsys I2S controller as per the ASoC framework.

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 include/linux/designware_i2s.h   |   63 ++++
 sound/soc/spear/designware_i2s.c |  610 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 673 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/designware_i2s.h
 create mode 100644 sound/soc/spear/designware_i2s.c

diff --git a/include/linux/designware_i2s.h b/include/linux/designware_i2s.h
new file mode 100644
index 0000000..5433b06
--- /dev/null
+++ b/include/linux/designware_i2s.h
@@ -0,0 +1,63 @@
+/*
+* linux/designware_i2s.h
+*
+* Copyright (ST) 2011 Rajeev Kumar (rajeev-dlh.kumar@st.com)
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#ifndef DESIGNWARE_I2S_H
+#define DESIGNWARE_I2S_H
+
+#include <linux/dmaengine.h>
+#include <linux/types.h>
+
+/*
+ * struct i2s_clk_config_data - represent i2s clk configuration data
+ * @chan_nr: number of channel
+ * @data_width: number of bits per sample (8/16/24/32 bit)
+ * @sample_rate: sampling frequency (8Khz, 16Khz, 32Khz, 44Khz, 48Khz)
+ */
+struct i2s_clk_config_data {
+	int chan_nr;
+	u32 data_width;
+	u32 sample_rate;
+};
+
+struct i2s_platform_data {
+	#define PLAY	(1 << 0)
+	#define RECORD	(1 << 1)
+	unsigned int cap;
+	int channel;
+	u8 swidth;
+	u32 snd_rates;
+
+	void *play_dma_data;
+	void *capture_dma_data;
+	bool (*filter)(struct dma_chan *chan, void *slave);
+	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
+};
+
+/* I2S DMA registers */
+#define I2S_RXDMA		0x01C0
+#define I2S_TXDMA		0x01C8
+
+#define TWO_CHANNEL_SUPPORT	2	/* up to 2.0 */
+#define FOUR_CHANNEL_SUPPORT	4	/* up to 3.1 */
+#define SIX_CHANNEL_SUPPORT	6	/* up to 5.1 */
+#define EIGHT_CHANNEL_SUPPORT	8	/* up to 7.1 */
+
+#endif /* DESIGNWARE_I2S_H */
diff --git a/sound/soc/spear/designware_i2s.c b/sound/soc/spear/designware_i2s.c
new file mode 100644
index 0000000..ca83c49
--- /dev/null
+++ b/sound/soc/spear/designware_i2s.c
@@ -0,0 +1,610 @@
+/*
+ * ALSA SoC I2S Audio Layer for ST SPEAr processors
+ *
+ * sound/soc/spear/designware_i2s.c
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Rajeev Kumar <rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/designware_i2s.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spear_dma.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+/* common register for all channel */
+#define IER		0x000
+#define IRER		0x004
+#define ITER		0x008
+#define CER		0x00C
+#define CCR		0x010
+#define RXFFR		0x014
+#define TXFFR		0x018
+
+/* I2STxRxRegisters for all channels */
+#define LRBR_LTHR(x)	(0x40 * x + 0x020)
+#define RRBR_RTHR(x)	(0x40 * x + 0x024)
+#define RER(x)		(0x40 * x + 0x028)
+#define TER(x)		(0x40 * x + 0x02C)
+#define RCR(x)		(0x40 * x + 0x030)
+#define TCR(x)		(0x40 * x + 0x034)
+#define ISR(x)		(0x40 * x + 0x038)
+#define IMR(x)		(0x40 * x + 0x03C)
+#define ROR(x)		(0x40 * x + 0x040)
+#define TOR(x)		(0x40 * x + 0x044)
+#define RFCR(x)		(0x40 * x + 0x048)
+#define TFCR(x)		(0x40 * x + 0x04C)
+#define RFF(x)		(0x40 * x + 0x050)
+#define TFF(x)		(0x40 * x + 0x054)
+
+/* I2SCOMPRegisters */
+#define I2S_COMP_PARAM_2	0x01F0
+#define I2S_COMP_PARAM_1	0x01F4
+#define I2S_COMP_VERSION	0x01F8
+#define I2S_COMP_TYPE		0x01FC
+
+#define DESIGNWARE_I2S_FORMAT	SNDRV_PCM_FMTBIT_S16_LE
+#define MAX_CHANNEL_NUM		8
+#define MIN_CHANNEL_NUM		2
+
+struct dw_i2s_dev {
+	void __iomem *i2s_base;
+	struct resource *res;
+	struct clk *clk;
+	int active;
+	int play_irq;
+	int max_channel;
+	int capture_irq;
+	unsigned int capability;
+	struct device *dev;
+	struct snd_soc_dai_driver *dai_driver;
+
+	/* data related to DMA transfers b/w i2s and DMAC */
+	u8 swidth;
+	u8 ccr;
+	u8 xfer_resolution;
+	struct dma_data play_dma_data;
+	struct dma_data capture_dma_data;
+	struct i2s_clk_config_data config;
+	int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
+};
+
+static inline void i2s_write_reg(void *io_base, int reg, u32 val)
+{
+	writel(val, io_base + reg);
+}
+
+static inline u32 i2s_read_reg(void *io_base, int reg)
+{
+	return readl(io_base + reg);
+}
+
+static inline void
+i2s_config_channel(struct dw_i2s_dev *dev, u32 ch, u32 stream, u32 cr)
+{
+	u32 irq;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_write_reg(dev->i2s_base, TCR(ch), dev->xfer_resolution);
+		i2s_write_reg(dev->i2s_base, TFCR(ch), 0x02);
+		irq = i2s_read_reg(dev->i2s_base, IMR(ch));
+		i2s_write_reg(dev->i2s_base, IMR(ch), irq & ~0x30);
+		i2s_write_reg(dev->i2s_base, TER(ch), 1);
+	} else {
+		i2s_write_reg(dev->i2s_base, RCR(ch), dev->xfer_resolution);
+		i2s_write_reg(dev->i2s_base, RFCR(ch), 0x07);
+		irq = i2s_read_reg(dev->i2s_base, IMR(ch));
+		i2s_write_reg(dev->i2s_base, IMR(ch), irq & ~0x03);
+		i2s_write_reg(dev->i2s_base, RER(ch), 1);
+	}
+}
+
+static inline void
+i2s_disable_channels(struct dw_i2s_dev *dev, u32 stream)
+{
+	u32 i = 0;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, TER(i), 0);
+	} else {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, RER(i), 0);
+	}
+}
+
+static inline void
+i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream)
+{
+	u32 i = 0;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, TOR(i), 0);
+	} else {
+		for (i = 0; i < 4; i++)
+			i2s_write_reg(dev->i2s_base, ROR(i), 0);
+	}
+}
+
+void i2s_start(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream)
+{
+
+	i2s_write_reg(dev->i2s_base, IER, 1);
+	i2s_disable_channels(dev, substream->stream);
+
+	switch (dev->max_channel) {
+	case EIGHT_CHANNEL_SUPPORT:
+		i2s_config_channel(dev, 3, substream->stream, 0x5);
+	case SIX_CHANNEL_SUPPORT:
+		i2s_config_channel(dev, 2, substream->stream, 0x5);
+	case FOUR_CHANNEL_SUPPORT:
+		i2s_config_channel(dev, 1, substream->stream, 0x5);
+	case TWO_CHANNEL_SUPPORT:
+		i2s_config_channel(dev, 0, substream->stream, 0x2);
+		break;
+	default:
+		dev_err(dev->dev, "channel not supported\n");
+	}
+
+	i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		i2s_write_reg(dev->i2s_base, ITER, 1);
+	else
+		i2s_write_reg(dev->i2s_base, IRER, 1);
+
+	i2s_write_reg(dev->i2s_base, CER, 1);
+}
+
+static void
+i2s_stop(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream)
+{
+	u32 i = 0, irq;
+
+	i2s_clear_irqs(dev, substream->stream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_write_reg(dev->i2s_base, ITER, 0);
+
+		for (i = 0; i < 4; i++) {
+			irq = i2s_read_reg(dev->i2s_base, IMR(i));
+			i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30);
+		}
+	} else {
+		i2s_write_reg(dev->i2s_base, IRER, 0);
+
+		for (i = 0; i < 4; i++) {
+			irq = i2s_read_reg(dev->i2s_base, IMR(i));
+			i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03);
+		}
+	}
+
+	if (!dev->active) {
+		i2s_write_reg(dev->i2s_base, CER, 0);
+		i2s_write_reg(dev->i2s_base, IER, 0);
+	}
+}
+
+static irqreturn_t dw_i2s_play_irq(int irq, void *_dev)
+{
+	struct dw_i2s_dev *dev = (struct dw_i2s_dev *)_dev;
+	u32 ch0, ch1;
+
+	/* check for the tx data overrun condition */
+	ch0 = i2s_read_reg(dev->i2s_base, ISR(0)) & 0x20;
+	ch1 = i2s_read_reg(dev->i2s_base, ISR(1)) & 0x20;
+	if (ch0 || ch1) {
+		/* disable i2s block */
+		i2s_write_reg(dev->i2s_base, IER, 0);
+
+		/* disable tx block */
+		i2s_write_reg(dev->i2s_base, ITER, 0);
+
+		/* flush all the tx fifo */
+		i2s_write_reg(dev->i2s_base, TXFFR, 1);
+
+		/* clear tx data overrun interrupt */
+		i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK);
+
+		/* enable rx block */
+		i2s_write_reg(dev->i2s_base, ITER, 1);
+
+		/* enable i2s block */
+		i2s_write_reg(dev->i2s_base, IER, 1);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dw_i2s_capture_irq(int irq, void *_dev)
+{
+	struct dw_i2s_dev *dev = (struct dw_i2s_dev *)_dev;
+	u32 ch0, ch1;
+
+	/* check for the rx data overrun condition */
+	ch0 = i2s_read_reg(dev->i2s_base, ISR(0)) & 0x02;
+	ch1 = i2s_read_reg(dev->i2s_base, ISR(1)) & 0x02;
+	if (ch0 || ch1) {
+		/* disable i2s block */
+		i2s_write_reg(dev->i2s_base, IER, 0);
+
+		/* disable rx block */
+		i2s_write_reg(dev->i2s_base, IRER, 0);
+
+		/* flush all the rx fifo */
+		i2s_write_reg(dev->i2s_base, RXFFR, 1);
+
+		/* clear rx data overrun interrupt */
+		i2s_clear_irqs(dev, SNDRV_PCM_STREAM_CAPTURE);
+
+		/* enable rx block */
+		i2s_write_reg(dev->i2s_base, IRER, 1);
+
+		/* enable i2s block */
+		i2s_write_reg(dev->i2s_base, IER, 1);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int
+dw_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+	struct dma_data *dma_data = NULL;
+
+	if (!(dev->capability & RECORD) &&
+			(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
+		return -EINVAL;
+
+	if (!(dev->capability & PLAY) &&
+			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+		return -EINVAL;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &dev->play_dma_data;
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		dma_data = &dev->capture_dma_data;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
+
+	return 0;
+}
+
+static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	struct i2s_clk_config_data *config = &dev->config;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		config->data_width = 16;
+		dev->ccr = 0x00;
+		dev->xfer_resolution = 0x02;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		config->data_width = 24;
+		dev->ccr = 0x08;
+		dev->xfer_resolution = 0x04;
+		break;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		config->data_width = 32;
+		dev->ccr = 0x10;
+		dev->xfer_resolution = 0x05;
+		break;
+
+	default:
+		dev_err(dev->dev, "designware-i2s: unsuppted PCM fmt");
+		return -EINVAL;
+	}
+
+	config->sample_rate = params_rate(params);
+	dev->max_channel = config->chan_nr = params_channels(params);
+
+	if (dev->i2s_clk_cfg) {
+		if (dev->i2s_clk_cfg(config)) {
+			dev_err(dev->dev, "runtime audio clk config fail\n");
+			if (cpu_dai->driver->ops->trigger) {
+				int ret =
+					cpu_dai->driver->ops->trigger(substream,
+							SNDRV_PCM_TRIGGER_STOP,
+							cpu_dai);
+				if (ret < 0) {
+					dev_err(dev->dev,
+							"trigger stop fail\n");
+					return ret;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void
+dw_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int
+dw_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		dev->active++;
+		i2s_start(dev, substream);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		dev->active--;
+		i2s_stop(dev, substream);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static struct snd_soc_dai_ops dw_i2s_dai_ops = {
+	.startup	= dw_i2s_startup,
+	.shutdown	= dw_i2s_shutdown,
+	.hw_params	= dw_i2s_hw_params,
+	.trigger	= dw_i2s_trigger,
+};
+
+#ifdef CONFIG_PM
+
+static int dw_i2s_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_i2s_dev *i2s_dev = dev_get_drvdata(&pdev->dev);
+
+	clk_disable(i2s_dev->clk);
+	return 0;
+}
+
+static int dw_i2s_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_i2s_dev *i2s_dev = dev_get_drvdata(&pdev->dev);
+
+	clk_enable(i2s_dev->clk);
+	return 0;
+}
+
+static const struct dev_pm_ops dw_i2s_dev_pm_ops = {
+	.suspend = dw_i2s_suspend,
+	.resume = dw_i2s_resume,
+};
+
+#define I2S_DW_DEV_PM_OPS (&dw_i2s_dev_pm_ops)
+#else
+#define I2S_DW_DEV_PM_OPS NULL
+#endif
+
+static int
+dw_i2s_probe(struct platform_device *pdev)
+{
+	const struct i2s_platform_data *pdata = pdev->dev.platform_data;
+	struct dw_i2s_dev *dev;
+	struct resource *res;
+	int ret;
+	unsigned int cap;
+	struct snd_soc_dai_driver *dw_i2s_dai;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "Invalid platform data\n");
+		return -EINVAL;
+	}
+
+	cap = pdata->cap;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no i2s resource defined\n");
+		return -ENODEV;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "i2s region already claimed\n");
+		return -EBUSY;
+	}
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_release_mem_region;
+	}
+
+	dev->res = res;
+	dev->max_channel = pdata->channel;
+	dev->capability = cap;
+	dev->swidth = pdata->swidth;
+	dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
+
+	/* Set DMA slaves info */
+
+	dev->play_dma_data.data = pdata->play_dma_data;
+	dev->capture_dma_data.data = pdata->capture_dma_data;
+	dev->play_dma_data.addr = res->start + I2S_TXDMA;
+	dev->capture_dma_data.addr = res->start + I2S_RXDMA;
+	dev->play_dma_data.max_burst = 16;
+	dev->capture_dma_data.max_burst = 16;
+	dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	dev->play_dma_data.filter = pdata->filter;
+	dev->capture_dma_data.filter = pdata->filter;
+
+	dev->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
+		ret = PTR_ERR(dev->clk);
+		goto err_kfree;
+	}
+
+	ret = clk_enable(dev->clk);
+	if (ret < 0)
+		goto err_clk_put;
+
+	dev->i2s_base = ioremap(res->start, resource_size(res));
+	if (!dev->i2s_base) {
+		dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
+		ret = -ENOMEM;
+		goto err_clk_disable;
+	}
+
+	dw_i2s_dai = kzalloc(sizeof(*dw_i2s_dai), GFP_KERNEL);
+	if (!dw_i2s_dai) {
+		dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
+		ret = -ENOMEM;
+		goto err_soc_dai_driver;
+	}
+
+	if (cap & PLAY) {
+		dev_dbg(&pdev->dev, " SPEAr: play supported\n");
+		dev->play_irq = platform_get_irq_byname(pdev, "play_irq");
+		if (dev->play_irq < 0)
+			dev_warn(&pdev->dev, "play irq not defined\n");
+		else {
+			ret = request_irq(dev->play_irq, dw_i2s_play_irq, 0,
+					"dw-i2s-play", dev);
+			if (ret) {
+				dev_err(&pdev->dev,
+						"Can't register play irq\n");
+				goto err_play_irq;
+			}
+		}
+
+		dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
+		dw_i2s_dai->playback.channels_max = dev->max_channel;
+		dw_i2s_dai->playback.rates = pdata->snd_rates;
+		dw_i2s_dai->playback.formats = DESIGNWARE_I2S_FORMAT;
+	}
+
+	if (cap & RECORD) {
+		dev_dbg(&pdev->dev, "SPEAr: record supported\n");
+		dev->capture_irq = platform_get_irq_byname(pdev, "record_irq");
+		if (dev->capture_irq < 0)
+			dev_warn(&pdev->dev, "record irq not defined\n");
+		else {
+			ret = request_irq(dev->capture_irq, dw_i2s_capture_irq,
+					0, "dw-i2s-rec", dev);
+			if (ret) {
+				dev_err(&pdev->dev,
+						"Can't register capture irq\n");
+				goto err_capture_irq;
+			}
+		}
+
+		dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
+		dw_i2s_dai->capture.channels_max = dev->max_channel;
+		dw_i2s_dai->capture.rates = pdata->snd_rates;
+		dw_i2s_dai->capture.formats = DESIGNWARE_I2S_FORMAT;
+	}
+
+	dw_i2s_dai->ops = &dw_i2s_dai_ops,
+
+	dev->dev = &pdev->dev;
+	dev->dai_driver = dw_i2s_dai;
+	dev_set_drvdata(&pdev->dev, dev);
+	ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "not able to register dai\n");
+		goto err_set_drvdata;
+	}
+
+	return 0;
+
+err_set_drvdata:
+	dev_set_drvdata(&pdev->dev, NULL);
+	free_irq(dev->capture_irq, pdev);
+err_capture_irq:
+	free_irq(dev->play_irq, pdev);
+err_play_irq:
+	kfree(dw_i2s_dai);
+err_soc_dai_driver:
+	iounmap(dev->i2s_base);
+err_clk_disable:
+	clk_disable(dev->clk);
+err_clk_put:
+	clk_put(dev->clk);
+err_kfree:
+	kfree(dev);
+err_release_mem_region:
+	release_mem_region(res->start, resource_size(res));
+	return ret;
+}
+
+static int
+dw_i2s_remove(struct platform_device *pdev)
+{
+	struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+
+	if (dev->play_irq)
+		free_irq(dev->play_irq, dev);
+
+	if (dev->capture_irq)
+		free_irq(dev->capture_irq, dev);
+
+	iounmap(dev->i2s_base);
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	kfree(dev->dai_driver);
+	kfree(dev);
+	release_mem_region(dev->res->start, resource_size(dev->res));
+
+	return 0;
+}
+
+static struct platform_driver dw_i2s_driver = {
+	.probe		= dw_i2s_probe,
+	.remove		= dw_i2s_remove,
+	.driver		= {
+		.name	= "designware-i2s",
+		.owner	= THIS_MODULE,
+		.pm	= I2S_DW_DEV_PM_OPS,
+	},
+};
+
+static int __init dw_i2s_init(void)
+{
+	return platform_driver_register(&dw_i2s_driver);
+}
+module_init(dw_i2s_init);
+
+static void __exit dw_i2s_exit(void)
+{
+	platform_driver_unregister(&dw_i2s_driver);
+}
+module_exit(dw_i2s_exit);
+
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:designware_i2s");
-- 
1.7.2.2

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

* [PATCH 3/8] sound:asoc: Add support for SPEAr ASoC pcm layer.
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
  2012-03-20 11:33 ` [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec Rajeev Kumar
  2012-03-20 11:33 ` [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  2012-03-20 15:50   ` Mark Brown
  2012-03-20 11:33 ` [PATCH 4/8] sound:asoc:spdif_in: Add spdif IN support Rajeev Kumar
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, spear-devel, Rajeev Kumar, lrg

This patch add support for the SPEAr ASoC pcm layer in ASoC framework.

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 sound/soc/spear/spear_pcm.c |  460 +++++++++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spear_pcm.h |   33 +++
 2 files changed, 493 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/spear/spear_pcm.c
 create mode 100644 sound/soc/spear/spear_pcm.h

diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
new file mode 100644
index 0000000..3693fde
--- /dev/null
+++ b/sound/soc/spear/spear_pcm.c
@@ -0,0 +1,460 @@
+/*
+ * ALSA PCM interface for ST SPEAr Processors
+ *
+ * sound/soc/spear/spear_pcm.c
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spear_dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include "spear_pcm.h"
+
+struct snd_pcm_hardware spear_pcm_hardware = {
+	.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+		 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.buffer_bytes_max = 16 * 1024, /* max buffer size */
+	.period_bytes_min = 2 * 1024, /* 1 msec data minimum period size */
+	.period_bytes_max = 2 * 1024, /* maximum period size */
+	.periods_min = 1, /* min # periods */
+	.periods_max = 8, /* max # of periods */
+	.fifo_size = 0, /* fifo size in bytes */
+};
+
+static void pcm_dma_complete(void *arg);
+
+static int spear_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	int ret = snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(params));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int spear_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int spear_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct spear_runtime_data *prtd = runtime->private_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prtd->lock, flags);
+	prtd->dma_addr = runtime->dma_addr;
+
+	prtd->buf_index = 0;
+	prtd->dmacount = 0;
+	prtd->xfer_len = snd_pcm_lib_period_bytes(substream);
+	prtd->xfer_cnt = snd_pcm_lib_buffer_bytes(substream) / prtd->xfer_len;
+
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	return 0;
+}
+
+static int start_dma(struct spear_runtime_data *prtd)
+{
+	struct dma_slave_config conf = {
+		.device_fc = false,
+	};
+
+	struct dma_chan *chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+	enum dma_data_direction direction;
+	dma_addr_t addr;
+	struct snd_soc_pcm_runtime *rtd = prtd->substream->private_data;
+	struct dma_data *dma_data =
+		snd_soc_dai_get_dma_data(rtd->cpu_dai, prtd->substream);
+	addr = prtd->dma_addr + prtd->buf_index * prtd->xfer_len;
+	if (prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		chan = prtd->dma_chan[0];
+		direction = DMA_TO_DEVICE;
+		conf.dst_addr = dma_data->addr;
+	} else {
+		chan = prtd->dma_chan[1];
+		direction = DMA_FROM_DEVICE;
+		conf.src_addr = dma_data->addr;
+	}
+
+	conf.src_maxburst = dma_data->max_burst;
+	conf.dst_maxburst = dma_data->max_burst;
+	conf.src_addr_width = dma_data->addr_width;
+	conf.dst_addr_width = dma_data->addr_width;
+
+	/* Prepare sg's */
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, pfn_to_page(PFN_DOWN(addr)), prtd->xfer_len,
+			addr & (PAGE_SIZE - 1));
+	sg_dma_address(&sg) = addr;
+
+	conf.direction = direction;
+	dmaengine_slave_config(chan, &conf);
+
+	desc = chan->device->device_prep_slave_sg(chan, &sg, 1, direction,
+			DMA_PREP_INTERRUPT);
+	if (!desc) {
+		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+		return -EAGAIN;
+	}
+
+	desc->callback = pcm_dma_complete;
+	desc->callback_param = prtd;
+	desc->tx_submit(desc);
+
+	return 0;
+}
+
+static void pcm_dma_xfer(struct spear_runtime_data *prtd,
+		bool from_callback)
+{
+	struct snd_pcm_substream *substream = prtd->substream;
+	struct dma_chan *chan;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&prtd->lock, flags);
+	if (!prtd->pcm_running) {
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		return;
+	}
+
+	BUG_ON(prtd->dmacount >= prtd->xfer_cnt);
+
+	while (prtd->dmacount < prtd->xfer_cnt) {
+
+		ret = start_dma(prtd);
+		if (ret) {
+			spin_unlock_irqrestore(&prtd->lock, flags);
+			return;
+		}
+
+		prtd->dmacount++;
+		prtd->buf_index++;
+
+		/* Set to zero, if crosses buffer size */
+		prtd->buf_index %= prtd->xfer_cnt;
+
+		/* Inform framework that a transfer is finished */
+		if (from_callback) {
+			spin_unlock_irqrestore(&prtd->lock, flags);
+			snd_pcm_period_elapsed(substream);
+			spin_lock_irqsave(&prtd->lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	/* Issue pending should be called after locks */
+	if (prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		chan = prtd->dma_chan[0];
+	else
+		chan = prtd->dma_chan[1];
+
+	chan->device->device_issue_pending(chan);
+}
+
+static void pcm_dma_complete(void *arg)
+{
+	struct spear_runtime_data *prtd = arg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&prtd->lock, flags);
+	prtd->dmacount--;
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	if (prtd->pcm_running)
+		pcm_dma_xfer(prtd, true);
+}
+
+static int spear_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct spear_runtime_data *prtd = substream->runtime->private_data;
+	struct dma_chan *chan;
+	unsigned long flags;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_RESUME:
+		spin_lock_irqsave(&prtd->lock, flags);
+		/* Go to last successfully transferred index + 1 */
+		prtd->buf_index += prtd->xfer_cnt - prtd->dmacount;
+		prtd->buf_index %= prtd->xfer_cnt;
+		prtd->dmacount = 0;
+		spin_unlock_irqrestore(&prtd->lock, flags);
+	case SNDRV_PCM_TRIGGER_START:
+		spin_lock_irqsave(&prtd->lock, flags);
+		prtd->pcm_running = true;
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		pcm_dma_xfer(prtd, false);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		spin_lock_irqsave(&prtd->lock, flags);
+		prtd->pcm_running = false;
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			chan = prtd->dma_chan[0];
+		else
+			chan = prtd->dma_chan[1];
+
+		chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t
+spear_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct spear_runtime_data *prtd = substream->runtime->private_data;
+
+	return bytes_to_frames(substream->runtime, prtd->buf_index *
+			prtd->xfer_len);
+}
+
+static int pcm_alloc_dma_chan(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct spear_runtime_data *prtd = substream->runtime->private_data;
+
+	int stream = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+	struct dma_data *dma_data =
+		snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	prtd->dma_chan[stream] = dma_request_channel(prtd->smask,
+			dma_data->filter, dma_data->data);
+	if (!prtd->dma_chan[stream])
+		return -EAGAIN;
+
+	return 0;
+}
+
+static void pcm_dma_free_chan(struct snd_pcm_substream *substream)
+{
+	struct spear_runtime_data *prtd = substream->runtime->private_data;
+	struct dma_chan *chan;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		chan = prtd->dma_chan[0];
+	else
+		chan = prtd->dma_chan[1];
+
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	dma_release_channel(chan);
+}
+
+static int spear_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct spear_runtime_data *prtd;
+	int ret;
+
+	ret = snd_soc_set_runtime_hwparams(substream, &spear_pcm_hardware);
+	if (ret)
+		return ret;
+
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+			SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+	if (!prtd)
+		return -ENOMEM;
+
+	spin_lock_init(&prtd->lock);
+	substream->runtime->private_data = prtd;
+	prtd->substream = substream;
+	dma_cap_zero(prtd->smask);
+	dma_cap_set(DMA_SLAVE, prtd->smask);
+
+	ret = pcm_alloc_dma_chan(substream);
+	if (ret) {
+		dev_err(substream->pcm->card->dev,
+				"pcm:Failed to get dma channels\n");
+		kfree(prtd);
+	}
+
+	return 0;
+}
+
+static int spear_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct spear_runtime_data *prtd = substream->runtime->private_data;
+
+	pcm_dma_free_chan(substream);
+	kfree(prtd);
+
+	return 0;
+}
+
+static int spear_pcm_mmap(struct snd_pcm_substream *substream,
+		struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+			runtime->dma_area, runtime->dma_addr,
+			runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops spear_pcm_ops = {
+	.open		= spear_pcm_open,
+	.close		= spear_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= spear_pcm_hw_params,
+	.hw_free	= spear_pcm_hw_free,
+	.prepare	= spear_pcm_prepare,
+	.trigger	= spear_pcm_trigger,
+	.pointer	= spear_pcm_pointer,
+	.mmap		= spear_pcm_mmap,
+};
+
+static int
+spear_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
+		size_t size)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+	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;
+
+	dev_info(buf->dev.dev,
+			" preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+			(void *)buf->area, (void *)buf->addr, size);
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void spear_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 && !buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 spear_pcm_dmamask = DMA_BIT_MASK(32);
+
+static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &spear_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	if (dai->driver->playback.channels_min) {
+		ret = spear_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK,
+				spear_pcm_hardware.buffer_bytes_max);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->driver->capture.channels_min) {
+		ret = spear_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE,
+				spear_pcm_hardware.buffer_bytes_max);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct snd_soc_platform_driver spear_soc_platform = {
+	.ops		=	&spear_pcm_ops,
+	.pcm_new	=	spear_pcm_new,
+	.pcm_free	=	spear_pcm_free,
+};
+
+static int __devinit spear_soc_platform_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev, &spear_soc_platform);
+}
+
+static int __devexit spear_soc_platform_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver spear_pcm_driver = {
+	.driver = {
+		.name = "spear-pcm-audio",
+		.owner = THIS_MODULE,
+	},
+
+	.probe = spear_soc_platform_probe,
+	.remove = __devexit_p(spear_soc_platform_remove),
+};
+static int __init snd_spear_pcm_init(void)
+{
+	return platform_driver_register(&spear_pcm_driver);
+}
+module_init(snd_spear_pcm_init);
+
+static void __exit snd_spear_pcm_exit(void)
+{
+	platform_driver_unregister(&spear_pcm_driver);
+}
+module_exit(snd_spear_pcm_exit);
+
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_DESCRIPTION("SPEAr PCM DMA module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spear_pcm");
diff --git a/sound/soc/spear/spear_pcm.h b/sound/soc/spear/spear_pcm.h
new file mode 100644
index 0000000..07a7b3d
--- /dev/null
+++ b/sound/soc/spear/spear_pcm.h
@@ -0,0 +1,33 @@
+/*
+ * ALSA PCM interface for ST SPEAr Processors
+ *
+ * sound/soc/spear/spear_pcm.h
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef SPEAR_PCM_H
+#define SPEAR_PCM_H
+
+struct spear_runtime_data {
+	struct dma_chan *dma_chan[2];
+	spinlock_t lock;
+	struct snd_pcm_substream *substream;
+	dma_addr_t dma_addr;
+
+	/* DMA related mask */
+	dma_cap_mask_t smask;
+
+	/* For Keeping track of buffers */
+	unsigned long xfer_len;	/* Data transfered by one transfer */
+	int xfer_cnt; /* Total number of transfers to be done */
+	int buf_index; /* Current buffer count */
+	int dmacount; /* No. of DMA transfer ongoing */
+	bool pcm_running; /* Current state of pcm, true if running */
+};
+#endif /* end of pcm header file */
-- 
1.7.2.2

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

* [PATCH 4/8] sound:asoc:spdif_in: Add spdif IN support
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
                   ` (2 preceding siblings ...)
  2012-03-20 11:33 ` [PATCH 3/8] sound:asoc: Add support for SPEAr ASoC pcm layer Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  2012-03-20 15:55   ` Mark Brown
  2012-03-20 11:33 ` [PATCH 5/8] sound:asoc:spdif_out: Add spdif out support Rajeev Kumar
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex
  Cc: Vipin Kumar, alsa-devel, Rajeev Kumar, spear-devel, Vipin Kumar, lrg

From: Vipin Kumar <vipin.kumar@st.com>

This patch implements the spdif IN driver for ST peripheral

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
Signed-off-by: Vipin Kumar <Vipin.kumar@st.com>
---
 sound/soc/spear/spdif_in.c      |  304 +++++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spdif_in_regs.h |   60 ++++++++
 2 files changed, 364 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/spear/spdif_in.c
 create mode 100644 sound/soc/spear/spdif_in_regs.h

diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
new file mode 100644
index 0000000..9a7b3b8
--- /dev/null
+++ b/sound/soc/spear/spdif_in.c
@@ -0,0 +1,304 @@
+/*
+ * ALSA SoC SPDIF In Audio Layer for spear processors
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Vipin Kumar <vipin.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spear_dma.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/spdif.h>
+#include "spdif_in_regs.h"
+
+struct spdif_in_params {
+	u32 format;
+};
+
+struct spdif_in_dev {
+	struct clk *clk;
+	struct dma_data dma_params;
+	struct spdif_in_params saved_params;
+	void *io_base;
+	void (*reset_perip)(void);
+	int irq;
+};
+
+static void spdif_in_configure(struct spdif_in_dev *host)
+{
+	u32 ctrl = SPDIF_IN_PRTYEN | SPDIF_IN_STATEN | SPDIF_IN_USREN |
+		SPDIF_IN_VALEN | SPDIF_IN_BLKEN;
+	ctrl |= SPDIF_MODE_16BIT | SPDIF_FIFO_THRES_16;
+
+	writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+	writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
+}
+
+static int spdif_in_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *cpu_dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return -EINVAL;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
+	return 0;
+}
+
+static void spdif_in_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return;
+
+	writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static void spdif_in_format(struct spdif_in_dev *host, u32 format)
+{
+	u32 ctrl = readl(host->io_base + SPDIF_IN_CTRL);
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		ctrl |= SPDIF_XTRACT_16BIT;
+		break;
+
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		ctrl &= ~SPDIF_XTRACT_16BIT;
+		break;
+	}
+
+	writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+}
+
+static int spdif_in_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
+	u32 format;
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return -EINVAL;
+
+	format = params_format(params);
+	host->saved_params.format = format;
+
+	return 0;
+}
+
+static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
+	u32 ctrl;
+	int ret = 0;
+
+	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+		return -EINVAL;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		clk_enable(host->clk);
+		spdif_in_configure(host);
+		spdif_in_format(host, host->saved_params.format);
+
+		ctrl = readl(host->io_base + SPDIF_IN_CTRL);
+		ctrl |= SPDIF_IN_SAMPLE | SPDIF_IN_ENB;
+		writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+		writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ctrl = readl(host->io_base + SPDIF_IN_CTRL);
+		ctrl &= ~(SPDIF_IN_SAMPLE | SPDIF_IN_ENB);
+		writel(ctrl, host->io_base + SPDIF_IN_CTRL);
+		writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
+
+		if (host->reset_perip)
+			host->reset_perip();
+		clk_disable(host->clk);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static struct snd_soc_dai_ops spdif_in_dai_ops = {
+	.startup	= spdif_in_startup,
+	.shutdown	= spdif_in_shutdown,
+	.trigger	= spdif_in_trigger,
+	.hw_params	= spdif_in_hw_params,
+};
+
+struct snd_soc_dai_driver spdif_in_dai = {
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+				 SNDRV_PCM_RATE_192000),
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | \
+			   SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+	},
+	.ops = &spdif_in_dai_ops,
+};
+
+static irqreturn_t spdif_in_irq(int irq, void *arg)
+{
+	struct spdif_in_dev *host = (struct spdif_in_dev *)arg;
+
+	u32 irq_status = readl(host->io_base + SPDIF_IN_IRQ);
+
+	if (!irq_status)
+		return IRQ_NONE;
+
+	if (irq_status & SPDIF_IRQ_FIFOWRITE)
+		pr_err("spdif in: fifo write error\n");
+	if (irq_status & SPDIF_IRQ_EMPTYFIFOREAD)
+		pr_err("spdif in: empty fifo read error\n");
+	if (irq_status & SPDIF_IRQ_FIFOFULL)
+		pr_err("spdif in: fifo full error\n");
+	if (irq_status & SPDIF_IRQ_OUTOFRANGE)
+		pr_err("spdif in: out of range error\n");
+
+	writel(0, host->io_base + SPDIF_IN_IRQ);
+
+	return IRQ_HANDLED;
+}
+
+static int spdif_in_probe(struct platform_device *pdev)
+{
+	struct spdif_in_dev *host;
+	struct spdif_platform_data *pdata;
+	struct resource *res, *res_fifo;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!res_fifo)
+		return -EINVAL;
+
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				resource_size(res), pdev->name)) {
+		dev_warn(&pdev->dev, "Failed to get memory resourse\n");
+		return -ENOENT;
+	}
+
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host) {
+		dev_warn(&pdev->dev, "kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	host->io_base = devm_ioremap(&pdev->dev, res->start,
+				resource_size(res));
+	if (!host->io_base) {
+		dev_warn(&pdev->dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq < 0)
+		return -EINVAL;
+
+	host->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
+
+	pdata = dev_get_platdata(&pdev->dev);
+
+	host->dma_params.data = pdata->dma_params;
+	host->dma_params.addr = res_fifo->start;
+	host->dma_params.max_burst = 16;
+	host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_params.filter = pdata->filter;
+	host->reset_perip = pdata->reset_perip;
+
+	dev_set_drvdata(&pdev->dev, host);
+
+	ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
+			"spdif-in", host);
+	if (ret) {
+		clk_put(host->clk);
+		dev_warn(&pdev->dev, "request_irq failed\n");
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai);
+	if (ret != 0) {
+		clk_put(host->clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int spdif_in_remove(struct platform_device *pdev)
+{
+	struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	clk_put(host->clk);
+
+	return 0;
+}
+
+#define SPDIF_IN_DEV_PM_OPS NULL
+
+static struct platform_driver spdif_in_driver = {
+	.probe		= spdif_in_probe,
+	.remove		= spdif_in_remove,
+	.driver		= {
+		.name	= "spdif-in",
+		.owner	= THIS_MODULE,
+		.pm	= SPDIF_IN_DEV_PM_OPS,
+	},
+};
+
+static int __init spdif_in_init(void)
+{
+	return platform_driver_register(&spdif_in_driver);
+}
+module_init(spdif_in_init);
+
+static void __exit spdif_in_exit(void)
+{
+	platform_driver_unregister(&spdif_in_driver);
+}
+module_exit(spdif_in_exit);
+
+MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
+MODULE_DESCRIPTION("SPEAr SPDIF IN SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/spear/spdif_in_regs.h b/sound/soc/spear/spdif_in_regs.h
new file mode 100644
index 0000000..69f3816
--- /dev/null
+++ b/sound/soc/spear/spdif_in_regs.h
@@ -0,0 +1,60 @@
+/*
+ * SPEAr SPDIF IN controller header file
+ *
+ * Copyright (ST) 2012 Vipin Kumar (vipin.kumar@st.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SPDIF_IN_REGS_H
+#define SPDIF_IN_REGS_H
+
+#define SPDIF_IN_CTRL		0x00
+	#define SPDIF_IN_PRTYEN		(1 << 20)
+	#define SPDIF_IN_STATEN		(1 << 19)
+	#define SPDIF_IN_USREN		(1 << 18)
+	#define SPDIF_IN_VALEN		(1 << 17)
+	#define SPDIF_IN_BLKEN		(1 << 16)
+
+	#define SPDIF_MODE_24BIT	(8 << 12)
+	#define SPDIF_MODE_23BIT	(7 << 12)
+	#define SPDIF_MODE_22BIT	(6 << 12)
+	#define SPDIF_MODE_21BIT	(5 << 12)
+	#define SPDIF_MODE_20BIT	(4 << 12)
+	#define SPDIF_MODE_19BIT	(3 << 12)
+	#define SPDIF_MODE_18BIT	(2 << 12)
+	#define SPDIF_MODE_17BIT	(1 << 12)
+	#define SPDIF_MODE_16BIT	(0 << 12)
+	#define SPDIF_MODE_MASK		(0x0F << 12)
+
+	#define SPDIF_IN_VALID		(1 << 11)
+	#define SPDIF_IN_SAMPLE		(1 << 10)
+	#define SPDIF_DATA_SWAP		(1 << 9)
+	#define SPDIF_IN_ENB		(1 << 8)
+	#define SPDIF_DATA_REVERT	(1 << 7)
+	#define SPDIF_XTRACT_16BIT	(1 << 6)
+	#define SPDIF_FIFO_THRES_16	(16 << 0)
+
+#define SPDIF_IN_IRQ_MASK	0x04
+#define SPDIF_IN_IRQ		0x08
+	#define SPDIF_IRQ_FIFOWRITE	(1 << 0)
+	#define SPDIF_IRQ_EMPTYFIFOREAD	(1 << 1)
+	#define SPDIF_IRQ_FIFOFULL	(1 << 2)
+	#define SPDIF_IRQ_OUTOFRANGE	(1 << 3)
+
+#define SPDIF_IN_STA		0x0C
+	#define SPDIF_IN_LOCK		(0x1 << 0)
+
+#endif /* SPDIF_IN_REGS_H */
-- 
1.7.2.2

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

* [PATCH 5/8] sound:asoc:spdif_out: Add spdif out support
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
                   ` (3 preceding siblings ...)
  2012-03-20 11:33 ` [PATCH 4/8] sound:asoc:spdif_in: Add spdif IN support Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  2012-03-20 11:33 ` [PATCH 6/8] sound:asoc: Add support for SPEAr ASoC machine driver Rajeev Kumar
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex
  Cc: Vipin Kumar, alsa-devel, spear-devel, Rajeev Kumar, lrg

From: Vipin Kumar <vipin.kumar@st.com>

This patch implements the spdif out driver for ST peripheral
This peripheral implements IEC60958 standard

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
Signed-off-by: vipin Kumar <vipin.kumar@st.com>
---
 sound/soc/spear/spdif_out.c      |  397 ++++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spdif_out_regs.h |   79 ++++++++
 2 files changed, 476 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/spear/spdif_out.c
 create mode 100644 sound/soc/spear/spdif_out_regs.h

diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
new file mode 100644
index 0000000..757fac1
--- /dev/null
+++ b/sound/soc/spear/spdif_out.c
@@ -0,0 +1,397 @@
+/*
+ * ALSA SoC SPDIF Out Audio Layer for spear processors
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Vipin Kumar <vipin.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spear_dma.h>
+#include <sound/soc.h>
+#include <mach/spdif.h>
+#include "spdif_out_regs.h"
+
+static int spdif_out_mute;
+
+struct spdif_out_params {
+	u32 rate;
+	u32 core_freq;
+};
+
+struct spdif_out_dev {
+	struct clk *clk;
+	struct dma_data dma_params;
+	struct spdif_out_params saved_params;
+	u32 running;
+	void *io_base;
+};
+
+static void spdif_out_configure(struct spdif_out_dev *host)
+{
+	writel(SPDIF_OUT_RESET, host->io_base + SPDIF_OUT_SOFT_RST);
+	mdelay(1);
+	writel(readl(host->io_base + SPDIF_OUT_SOFT_RST) & ~SPDIF_OUT_RESET,
+			host->io_base + SPDIF_OUT_SOFT_RST);
+
+	writel(SPDIF_OUT_FDMA_TRIG_16 | SPDIF_OUT_MEMFMT_16_16 |
+			SPDIF_OUT_VALID_HW | SPDIF_OUT_USER_HW |
+			SPDIF_OUT_CHNLSTA_HW | SPDIF_OUT_PARITY_HW,
+			host->io_base + SPDIF_OUT_CFG);
+
+	writel(0x7F, host->io_base + SPDIF_OUT_INT_STA_CLR);
+	writel(0x7F, host->io_base + SPDIF_OUT_INT_EN_CLR);
+}
+
+static int spdif_out_startup(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *cpu_dai)
+{
+	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+	int ret;
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -EINVAL;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
+
+	ret = clk_enable(host->clk);
+	if (ret)
+		return ret;
+
+	host->running = true;
+	spdif_out_configure(host);
+
+	return 0;
+}
+
+static void spdif_out_shutdown(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return;
+
+	clk_disable(host->clk);
+	host->running = false;
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static void spdif_out_clock(struct spdif_out_dev *host, u32 core_freq,
+		u32 rate)
+{
+	u32 divider, ctrl;
+
+	clk_set_rate(host->clk, core_freq);
+	divider = DIV_ROUND_CLOSEST(clk_get_rate(host->clk), (rate * 128));
+
+	ctrl = readl(host->io_base + SPDIF_OUT_CTRL);
+	ctrl &= ~SPDIF_DIVIDER_MASK;
+	ctrl |= (divider << SPDIF_DIVIDER_SHIFT) & SPDIF_DIVIDER_MASK;
+	writel(ctrl, host->io_base + SPDIF_OUT_CTRL);
+}
+
+static int spdif_out_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
+	u32 rate, core_freq;
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -EINVAL;
+
+	rate = params_rate(params);
+
+	switch (rate) {
+	case 8000:
+	case 16000:
+	case 32000:
+	case 64000:
+		/*
+		 * The clock is multiplied by 10 to bring it to feasible range
+		 * of frequencies for sscg
+		 */
+		core_freq = 64000 * 128 * 10;	/* 81.92 MHz */
+		break;
+	case 5512:
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+	case 176400:
+		core_freq = 176400 * 128;	/* 22.5792 MHz */
+		break;
+	case 48000:
+	case 96000:
+	case 192000:
+	default:
+		core_freq = 192000 * 128;	/* 24.576 MHz */
+		break;
+	}
+
+	spdif_out_clock(host, core_freq, rate);
+	host->saved_params.core_freq = core_freq;
+	host->saved_params.rate = rate;
+
+	return 0;
+}
+
+static int spdif_out_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
+	u32 ctrl;
+	int ret = 0;
+
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+		return -EINVAL;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+			ctrl = readl(host->io_base + SPDIF_OUT_CTRL);
+			ctrl &= ~SPDIF_OPMODE_MASK;
+			if (!spdif_out_mute)
+				ctrl |= SPDIF_OPMODE_AUD_DATA |
+					SPDIF_STATE_NORMAL;
+			else
+				ctrl |= SPDIF_OPMODE_MUTE_PCM;
+			writel(ctrl, host->io_base + SPDIF_OUT_CTRL);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ctrl = readl(host->io_base + SPDIF_OUT_CTRL);
+		ctrl &= ~SPDIF_OPMODE_MASK;
+		ctrl |= SPDIF_OPMODE_OFF;
+		writel(ctrl, host->io_base + SPDIF_OUT_CTRL);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int spdif_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
+	u32 val;
+
+	spdif_out_mute = mute;
+	val = readl(host->io_base + SPDIF_OUT_CTRL);
+	val &= ~SPDIF_OPMODE_MASK;
+
+	if (mute)
+		val |= SPDIF_OPMODE_MUTE_PCM;
+	else {
+		if (host->running)
+			val |= SPDIF_OPMODE_AUD_DATA | SPDIF_STATE_NORMAL;
+		else
+			val |= SPDIF_OPMODE_OFF;
+	}
+
+	writel(val, host->io_base + SPDIF_OUT_CTRL);
+	return 0;
+}
+
+static int spdif_mute_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = spdif_out_mute;
+	return 0;
+}
+
+static int spdif_mute_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_card *card = codec->card;
+	struct snd_soc_pcm_runtime *rtd = card->rtd;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	if (spdif_out_mute == ucontrol->value.integer.value[0])
+		return 0;
+
+	spdif_digital_mute(cpu_dai, ucontrol->value.integer.value[0]);
+
+	return 1;
+}
+static const struct snd_kcontrol_new spdif_out_controls[] = {
+	SOC_SINGLE_BOOL_EXT("SPDIF Play Mute", (unsigned long)&spdif_out_mute,
+			spdif_mute_get, spdif_mute_put),
+};
+
+int spdif_soc_dai_probe(struct snd_soc_dai *dai)
+{
+	struct snd_soc_card *card = dai->card;
+	struct snd_soc_pcm_runtime *rtd = card->rtd;
+	struct snd_soc_codec *codec = rtd->codec;
+
+	return snd_soc_add_controls(codec, spdif_out_controls,
+				ARRAY_SIZE(spdif_out_controls));
+}
+
+static struct snd_soc_dai_ops spdif_out_dai_ops = {
+	.digital_mute	= spdif_digital_mute,
+	.startup	= spdif_out_startup,
+	.shutdown	= spdif_out_shutdown,
+	.trigger	= spdif_out_trigger,
+	.hw_params	= spdif_out_hw_params,
+};
+
+struct snd_soc_dai_driver spdif_out_dai = {
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+				 SNDRV_PCM_RATE_192000),
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.probe = spdif_soc_dai_probe,
+	.ops = (struct snd_soc_dai_ops *)&spdif_out_dai_ops,
+};
+
+static int spdif_out_probe(struct platform_device *pdev)
+{
+	struct spdif_out_dev *host;
+	struct spdif_platform_data *pdata;
+	struct resource *res;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				resource_size(res), pdev->name)) {
+		dev_warn(&pdev->dev, "Failed to get memory resourse\n");
+		return -ENOENT;
+	}
+
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host) {
+		dev_warn(&pdev->dev, "kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	host->io_base = devm_ioremap(&pdev->dev, res->start,
+				resource_size(res));
+	if (!host->io_base) {
+		dev_warn(&pdev->dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	host->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
+
+	pdata = dev_get_platdata(&pdev->dev);
+
+	host->dma_params.data = pdata->dma_params;
+	host->dma_params.addr = res->start + SPDIF_OUT_FIFO_DATA;
+	host->dma_params.max_burst = 16;
+	host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	host->dma_params.filter = pdata->filter;
+
+	dev_set_drvdata(&pdev->dev, host);
+
+	ret = snd_soc_register_dai(&pdev->dev, &spdif_out_dai);
+	if (ret != 0) {
+		clk_put(host->clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int spdif_out_remove(struct platform_device *pdev)
+{
+	struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	clk_put(host->clk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int spdif_out_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
+
+	if (host->running)
+		clk_disable(host->clk);
+
+	return 0;
+}
+
+static int spdif_out_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
+
+	if (host->running) {
+		clk_enable(host->clk);
+		spdif_out_configure(host);
+		spdif_out_clock(host, host->saved_params.core_freq,
+				host->saved_params.rate);
+	}
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(spdif_out_dev_pm_ops, spdif_out_suspend, \
+		spdif_out_resume);
+
+#define SPDIF_OUT_DEV_PM_OPS (&spdif_out_dev_pm_ops)
+
+#else
+#define SPDIF_OUT_DEV_PM_OPS NULL
+
+#endif
+
+static struct platform_driver spdif_out_driver = {
+	.probe		= spdif_out_probe,
+	.remove		= spdif_out_remove,
+	.driver		= {
+		.name	= "spdif-out",
+		.owner	= THIS_MODULE,
+		.pm	= SPDIF_OUT_DEV_PM_OPS,
+	},
+};
+
+static int __init spdif_out_init(void)
+{
+	return platform_driver_register(&spdif_out_driver);
+}
+module_init(spdif_out_init);
+
+static void __exit spdif_out_exit(void)
+{
+	platform_driver_unregister(&spdif_out_driver);
+}
+module_exit(spdif_out_exit);
+
+MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
+MODULE_DESCRIPTION("SPEAr SPDIF OUT SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/spear/spdif_out_regs.h b/sound/soc/spear/spdif_out_regs.h
new file mode 100644
index 0000000..233cc67
--- /dev/null
+++ b/sound/soc/spear/spdif_out_regs.h
@@ -0,0 +1,79 @@
+/*
+ * SPEAr SPDIF OUT controller header file
+ *
+ * Copyright (ST) 2012 Vipin Kumar (vipin.kumar@st.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SPDIF_OUT_REGS_H
+#define SPDIF_OUT_REGS_H
+
+#define SPDIF_OUT_SOFT_RST	0x00
+	#define SPDIF_OUT_RESET		(1 << 0)
+#define SPDIF_OUT_FIFO_DATA	0x04
+#define SPDIF_OUT_INT_STA	0x08
+#define SPDIF_OUT_INT_STA_CLR	0x0C
+	#define SPDIF_INT_UNDERFLOW	(1 << 0)
+	#define SPDIF_INT_EODATA	(1 << 1)
+	#define SPDIF_INT_EOBLOCK	(1 << 2)
+	#define SPDIF_INT_EOLATENCY	(1 << 3)
+	#define SPDIF_INT_EOPD_DATA	(1 << 4)
+	#define SPDIF_INT_MEMFULLREAD	(1 << 5)
+	#define SPDIF_INT_EOPD_PAUSE	(1 << 6)
+
+#define SPDIF_OUT_INT_EN	0x10
+#define SPDIF_OUT_INT_EN_SET	0x14
+#define SPDIF_OUT_INT_EN_CLR	0x18
+#define SPDIF_OUT_CTRL		0x1C
+	#define SPDIF_OPMODE_MASK	(7 << 0)
+	#define SPDIF_OPMODE_OFF	(0 << 0)
+	#define SPDIF_OPMODE_MUTE_PCM	(1 << 0)
+	#define SPDIF_OPMODE_MUTE_PAUSE	(2 << 0)
+	#define SPDIF_OPMODE_AUD_DATA	(3 << 0)
+	#define SPDIF_OPMODE_ENCODE	(4 << 0)
+	#define SPDIF_STATE_NORMAL	(1 << 3)
+	#define SPDIF_DIVIDER_MASK	(0xff << 5)
+	#define SPDIF_DIVIDER_SHIFT	(5)
+	#define SPDIF_SAMPLEREAD_MASK	(0x1ffff << 15)
+	#define SPDIF_SAMPLEREAD_SHIFT	(15)
+#define SPDIF_OUT_STA		0x20
+#define SPDIF_OUT_PA_PB		0x24
+#define SPDIF_OUT_PC_PD		0x28
+#define SPDIF_OUT_CL1		0x2C
+#define SPDIF_OUT_CR1		0x30
+#define SPDIF_OUT_CL2_CR2_UV	0x34
+#define SPDIF_OUT_PAUSE_LAT	0x38
+#define SPDIF_OUT_FRMLEN_BRST	0x3C
+#define SPDIF_OUT_CFG		0x40
+	#define SPDIF_OUT_MEMFMT_16_0	(0 << 5)
+	#define SPDIF_OUT_MEMFMT_16_16	(1 << 5)
+	#define SPDIF_OUT_VALID_DMA	(0 << 3)
+	#define SPDIF_OUT_VALID_HW	(1 << 3)
+	#define SPDIF_OUT_USER_DMA	(0 << 2)
+	#define SPDIF_OUT_USER_HW	(1 << 2)
+	#define SPDIF_OUT_CHNLSTA_DMA	(0 << 1)
+	#define SPDIF_OUT_CHNLSTA_HW	(1 << 1)
+	#define SPDIF_OUT_PARITY_HW	(0 << 0)
+	#define SPDIF_OUT_PARITY_DMA	(1 << 0)
+	#define SPDIF_OUT_FDMA_TRIG_2	(2 << 8)
+	#define SPDIF_OUT_FDMA_TRIG_6	(6 << 8)
+	#define SPDIF_OUT_FDMA_TRIG_8	(8 << 8)
+	#define SPDIF_OUT_FDMA_TRIG_10	(10 << 8)
+	#define SPDIF_OUT_FDMA_TRIG_12	(12 << 8)
+	#define SPDIF_OUT_FDMA_TRIG_16	(16 << 8)
+	#define SPDIF_OUT_FDMA_TRIG_18	(18 << 8)
+
+#endif /* SPDIF_OUT_REGS_H */
-- 
1.7.2.2

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

* [PATCH 6/8] sound:asoc: Add support for SPEAr ASoC machine driver.
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
                   ` (4 preceding siblings ...)
  2012-03-20 11:33 ` [PATCH 5/8] sound:asoc:spdif_out: Add spdif out support Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  2012-03-20 16:00   ` Mark Brown
  2012-03-20 11:33 ` [PATCH 7/8] sound:asoc: Add Kconfig and Makefile to support SPEAr audio driver Rajeev Kumar
  2012-03-20 11:33 ` [PATCH 8/8] sound:asoc: Update Kconfig and Makefile(sound/soc/) to support SPEAr audio Rajeev Kumar
  7 siblings, 1 reply; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, spear-devel, Rajeev Kumar, lrg

The patch add support for SPEAr ASoC machine driver.

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 sound/soc/spear/spear_evb.c |  278 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 278 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/spear/spear_evb.c

diff --git a/sound/soc/spear/spear_evb.c b/sound/soc/spear/spear_evb.c
new file mode 100644
index 0000000..66907c0
--- /dev/null
+++ b/sound/soc/spear/spear_evb.c
@@ -0,0 +1,278 @@
+/*
+ * ASoC machine driver for SPEAr evaluation boards
+ *
+ * sound/soc/spear/spear_evb.c
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/hardware.h>
+#include <mach/misc_regs.h>
+
+static int sta529_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;
+	int ret = 0;
+	u32 channel;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_CBS_CFM);
+	if (ret < 0)
+		return ret;
+
+	channel = params_channels(params);
+
+	if (cpu_is_spear1340()) {
+#ifdef CONFIG_CPU_SPEAR1340
+		u32 mode = 0;
+		u32 val = readl(VA_SPEAR1340_PERIP_CFG);
+
+		switch (channel) {
+		case 8:
+			mode = SPEAR1340_I2S_CHNL_7_1;
+			break;
+		case 6:
+			mode = SPEAR1340_I2S_CHNL_5_1;
+			break;
+		case 4:
+			mode = SPEAR1340_I2S_CHNL_3_1;
+			break;
+		case 2:
+		default:
+			mode = SPEAR1340_I2S_CHNL_2_0;
+			break;
+		}
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			mode = mode << SPEAR1340_I2S_CHNL_PLAY_SHIFT;
+			val = (val & ~SPEAR1340_I2S_CHNL_PLAY_MASK) | mode;
+		} else {
+			mode = mode << SPEAR1340_I2S_CHNL_REC_SHIFT;
+			val = (val & ~SPEAR1340_I2S_CHNL_REC_MASK) | mode;
+		}
+		writel(val, VA_SPEAR1340_PERIP_CFG);
+#endif
+	} else if (cpu_is_spear1300() || cpu_is_spear1310_reva() ||
+			cpu_is_spear900() || cpu_is_spear1310()) {
+#if defined(CONFIG_CPU_SPEAR1300) || defined(CONFIG_CPU_SPEAR1310_REVA) || \
+	defined(CONFIG_CPU_SPEAR900) || defined(CONFIG_CPU_SPEAR1310)
+		/* setting mode 0 in conf register: 32c offset */
+		u32 val = readl(VA_PERIP_CFG);
+		val &= ~I2S_MODE_MASK;
+		val |= I2S_MODE_I2S2_ONE_PORT;
+		writel(val, VA_PERIP_CFG);
+#endif
+	}
+
+	return 0;
+}
+
+/* Audio machine driver for SPEAr evb */
+static struct snd_soc_ops sta529_ops = {
+	.hw_params	= sta529_hw_params,
+};
+
+/* SPEAr audio interface glue - connects codec <--> CPU <--> platform */
+static struct snd_soc_dai_link spear_evb_dai[] = {
+	{
+		.name		= "sta529-pcm",
+		.stream_name	= "pcm",
+		.cpu_dai_name	= "designware-i2s.0",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "sta529-audio",
+		.codec_name	= "sta529-codec.0-001a",
+		.ops		= &sta529_ops,
+	},
+};
+
+/* SPEAr audio machine driver */
+static struct snd_soc_card spear_snd_card = {
+	.name		= "spear-evb",
+	.dai_link	= spear_evb_dai,
+	.num_links	= ARRAY_SIZE(spear_evb_dai),
+};
+
+/* SPEAr320s audio interface glue - connects codec <--> CPU <--> platform */
+static struct snd_soc_dai_link spear320s_evb_dai[] = {
+	{
+		.name		= "sta529-pcm",
+		.stream_name	= "pcm",
+		.cpu_dai_name	= "designware-i2s",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "sta529-audio",
+		.codec_name	= "sta529-codec.0-001a",
+		.ops		= &sta529_ops,
+	},
+};
+
+/* SPEAr320s audio machine driver */
+static struct snd_soc_card spear320s_snd_card = {
+	.name		= "spear320s-evb",
+	.dai_link	= spear320s_evb_dai,
+	.num_links	= ARRAY_SIZE(spear320s_evb_dai),
+};
+
+/* LCAD audio interface glue - connects codec <--> CPU <--> platform */
+static struct snd_soc_dai_link lcad_evb_dai[] = {
+	{
+		.name		= "sta529-pcm0",
+		.stream_name	= "I2S Playback",
+		.cpu_dai_name	= "designware-i2s.0",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "sta529-audio",
+		.codec_name	= "sta529-codec.0-001a",
+		.ops		= &sta529_ops,
+	}, {
+		.name		= "sta529-pcm1",
+		.stream_name	= "I2S Capture",
+		.cpu_dai_name	= "designware-i2s.1",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "sta529-audio",
+		.codec_name	= "sta529-codec.0-001a",
+		.ops		= &sta529_ops,
+	},
+};
+
+static struct snd_soc_card lcad_snd_card = {
+	.name		= "lcad-evb",
+	.dai_link	= lcad_evb_dai,
+	.num_links	= ARRAY_SIZE(lcad_evb_dai),
+};
+
+/* Audio machine driver for SPEAr1340 evb */
+
+/* SPEAr1340 audio interface glue - connects codec <--> CPU <--> platform */
+static struct snd_soc_dai_link spear1340_evb_dai[] = {
+	{
+		.name		= "spdif-pcm0",
+		.stream_name	= "SPDIF Playback",
+		.cpu_dai_name	= "spdif-out",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "dit-hifi",
+		.codec_name	= "spdif-dit",
+		.ops		= NULL,
+	}, {
+		.name		= "spdif-pcm1",
+		.stream_name	= "SPDIF Capture",
+		.cpu_dai_name	= "spdif-in",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "dir-hifi",
+		.codec_name	= "spdif-dir",
+		.ops		= NULL,
+	}, {
+		.name		= "sta529-pcm0",
+		.stream_name	= "I2S Playback",
+		.cpu_dai_name	= "designware-i2s.0",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "sta529-audio",
+		.codec_name	= "sta529-codec.0-001a",
+		.ops		= &sta529_ops,
+	}, {
+		.name		= "sta529-pcm1",
+		.stream_name	= "I2S Capture",
+		.cpu_dai_name	= "designware-i2s.1",
+		.platform_name	= "spear-pcm-audio",
+		.codec_dai_name	= "sta529-audio",
+		.codec_name	= "sta529-codec.0-001a",
+		.ops		= &sta529_ops,
+	},
+};
+
+static struct snd_soc_card spear1340_snd_card = {
+	.name		= "spear1340-evb",
+	.dai_link	= spear1340_evb_dai,
+	.num_links	= ARRAY_SIZE(spear1340_evb_dai),
+};
+
+static struct platform_device *evb_snd_device;
+#if defined(CONFIG_CPU_SPEAR1340)
+static struct platform_device *spdif_dit_device;
+static struct platform_device *spdif_dir_device;
+#endif
+
+static int __init spear_audio_init(void)
+{
+	int ret;
+	struct snd_soc_card *spear_soc_card;
+
+	if (machine_is_spear1340_lcad())
+		spear_soc_card = &lcad_snd_card;
+	else if (cpu_is_spear1340())
+		spear_soc_card = &spear1340_snd_card;
+	else if (cpu_is_spear320())
+		spear_soc_card = &spear320s_snd_card;
+	else
+		spear_soc_card = &spear_snd_card;
+
+#if defined(CONFIG_CPU_SPEAR1340)
+	if (cpu_is_spear1340()) {
+		/* Create and register spdif platform devices */
+		spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+		if (!spdif_dit_device) {
+			printk(KERN_ERR "spdif transceiver " \
+					"platform_device_alloc fails\n");
+			return -ENOMEM;
+		}
+		ret = platform_device_add(spdif_dit_device);
+		if (ret) {
+			printk(KERN_ERR "Unable to add spdif transceiver " \
+					"platform device\n");
+			platform_device_put(spdif_dit_device);
+		}
+
+		spdif_dir_device = platform_device_alloc("spdif-dir", -1);
+		if (!spdif_dir_device) {
+			printk(KERN_ERR "spdif receive platform_device_alloc " \
+					"fails\n");
+			return -ENOMEM;
+		}
+		ret = platform_device_add(spdif_dir_device);
+		if (ret) {
+			printk(KERN_ERR "Unable to add spdif receive platform" \
+					"device\n");
+			platform_device_put(spdif_dir_device);
+		}
+	}
+#endif
+	/* Create and register platform device */
+	evb_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!evb_snd_device) {
+		printk(KERN_ERR "soc audio platform_device_alloc fails\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(evb_snd_device, spear_soc_card);
+	ret = platform_device_add(evb_snd_device);
+	if (ret) {
+		printk(KERN_ERR "Unable to add platform device\n");
+		platform_device_put(evb_snd_device);
+	}
+
+	return ret;
+}
+module_init(spear_audio_init);
+
+static void __exit spear_audio_exit(void)
+{
+	platform_device_unregister(evb_snd_device);
+}
+module_exit(spear_audio_exit);
+
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_DESCRIPTION("ST SPEAr EVB ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spear_evb");
-- 
1.7.2.2

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

* [PATCH 7/8] sound:asoc: Add Kconfig and Makefile to support SPEAr audio driver
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
                   ` (5 preceding siblings ...)
  2012-03-20 11:33 ` [PATCH 6/8] sound:asoc: Add support for SPEAr ASoC machine driver Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  2012-03-20 11:33 ` [PATCH 8/8] sound:asoc: Update Kconfig and Makefile(sound/soc/) to support SPEAr audio Rajeev Kumar
  7 siblings, 0 replies; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, spear-devel, Rajeev Kumar, lrg

This patch add Kconfig and Makefile to support SPEAr Audio driver

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 sound/soc/spear/Kconfig  |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/spear/Makefile |   16 ++++++++++++++++
 2 files changed, 62 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/spear/Kconfig
 create mode 100644 sound/soc/spear/Makefile

diff --git a/sound/soc/spear/Kconfig b/sound/soc/spear/Kconfig
new file mode 100644
index 0000000..4ab9154
--- /dev/null
+++ b/sound/soc/spear/Kconfig
@@ -0,0 +1,46 @@
+config SND_SOC_SPEAR_EVM
+	tristate "SoC Audio support for SPEAr EVM"
+	select SND_SOC_DESIGNWARE_I2S
+	select SND_SOC_STA529
+	select SND_SOC_SPEAR_PCM
+	help
+	 Say Y if you want to add support for SoC audio on SPEAr
+	 platform
+
+config SND_SOC_SPEAR1340_EVM
+	tristate "SoC Audio support for SPEAr1340 EVM"
+	select SND_SOC_DESIGNWARE_I2S
+	select SND_SOC_STA529
+	select SND_SOC_SPEAR_SPDIF_OUT
+	select SND_SOC_SPEAR_SPDIF_IN
+	select SND_SOC_SPDIF
+	select SND_SOC_SPEAR_PCM
+	help
+	 Say Y if you want to add support for SoC audio on SPEAr1340
+	 platform
+
+config SND_SOC_SPEAR_PCM
+	tristate "SoC Audio for the ST chip"
+	depends on SND_SOC_DESIGNWARE_I2S || SND_SOC_SPEAR_SPDIF_OUT || \
+		SND_SOC_SPEAR_SPDIF_IN
+	help
+	 Say Y or M if you want to add support for any of the audio
+	 controllers (I2S/SPDIF). You will also need to select
+	 the audio interface codecs to support below.
+
+config SND_SOC_DESIGNWARE_I2S
+	tristate "Synopsys I2S Device Driver"
+	help
+	 Say Y or M if you want to add support for I2S driver for
+	 Synopsys desigwnware I2S device. The device supports upto
+	 maximum of 8 channels each for play, record or both.
+
+config SND_SOC_SPEAR_SPDIF_OUT
+	tristate "SPEAr SPDIF Out Device Driver"
+	help
+	 Say Y or M if you want to add support for SPDIF OUT driver.
+
+config SND_SOC_SPEAR_SPDIF_IN
+	tristate "SPEAr SPDIF IN Device Driver"
+	help
+	 Say Y or M if you want to add support for SPDIF IN driver.
diff --git a/sound/soc/spear/Makefile b/sound/soc/spear/Makefile
new file mode 100644
index 0000000..bc49e75
--- /dev/null
+++ b/sound/soc/spear/Makefile
@@ -0,0 +1,16 @@
+# SPEAr Platform Support
+snd-soc-pcm-objs := spear_pcm.o
+snd-soc-i2s-objs := designware_i2s.o
+snd-soc-spdif-in-objs := spdif_in.o
+snd-soc-spdif-out-objs := spdif_out.o
+
+obj-$(CONFIG_SND_SOC_SPEAR_PCM) += snd-soc-pcm.o
+obj-$(CONFIG_SND_SOC_DESIGNWARE_I2S) += snd-soc-i2s.o
+obj-$(CONFIG_SND_SOC_SPEAR_SPDIF_IN) += snd-soc-spdif-in.o
+obj-$(CONFIG_SND_SOC_SPEAR_SPDIF_OUT) += snd-soc-spdif-out.o
+
+# SPEAr Machine Support
+snd-soc-evb-objs := spear_evb.o
+
+obj-$(CONFIG_SND_SOC_SPEAR_EVM) += snd-soc-evb.o
+obj-$(CONFIG_SND_SOC_SPEAR1340_EVM) += snd-soc-evb.o
-- 
1.7.2.2

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

* [PATCH 8/8] sound:asoc: Update Kconfig and Makefile(sound/soc/) to support SPEAr audio
  2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
                   ` (6 preceding siblings ...)
  2012-03-20 11:33 ` [PATCH 7/8] sound:asoc: Add Kconfig and Makefile to support SPEAr audio driver Rajeev Kumar
@ 2012-03-20 11:33 ` Rajeev Kumar
  7 siblings, 0 replies; 25+ messages in thread
From: Rajeev Kumar @ 2012-03-20 11:33 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, spear-devel, Rajeev Kumar, lrg

This patch update Kconfig and Makefile present in soc directory to
support SPEAr.

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 sound/soc/Kconfig  |    1 +
 sound/soc/Makefile |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 35e662d..3860465 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -43,6 +43,7 @@ source "sound/soc/pxa/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/spear/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 9ea8ac8..238da08 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -20,5 +20,6 @@ obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= samsung/
 obj-$(CONFIG_SND_SOC)	+= s6000/
 obj-$(CONFIG_SND_SOC)	+= sh/
+obj-$(CONFIG_SND_SOC)	+= spear/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
-- 
1.7.2.2

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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-20 11:33 ` [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec Rajeev Kumar
@ 2012-03-20 15:25   ` Mark Brown
  2012-03-23  3:42     ` Rajeev kumar
  2012-03-20 17:57   ` Lars-Peter Clausen
  1 sibling, 1 reply; 25+ messages in thread
From: Mark Brown @ 2012-03-20 15:25 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, lrg, spear-devel


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

On Tue, Mar 20, 2012 at 05:03:45PM +0530, Rajeev Kumar wrote:
> This patch adds the support for STA529 audio codec.
> Details of the audio codec can be seen here:
> http://www.st.com/internet/imag_video/product/159187.jsp

Please use subject lines appropriate for the subsystem.  If your commits
look visually different to all the other commits in the log that's not a
good sign.

> +config SND_SOC_STA529
> +	tristate
> +	depends on I2C
> +

Drop the dependency, none of the other CODECs have this for a reason...

> +#include <linux/platform_device.h>

If you need this something went wrong...

> +static const u8 sta529_reg[STA529_CACHEREGNUM] = {

Use regmap for register I/O.

> +struct sta529 {
> +	unsigned int sysclk;
> +	enum snd_soc_control_type control_type;
> +	void *control_data;

Your device only supports I2C, no need for the infrastructure for other
buses (though this will go away with regmap).

> +static const char *pwm_mode_text[] = { "binary", "headphone", "ternary",
> +	"phase-shift"};
> +static const char *interface_mode_text[] = { "slave", "master"};

ALSA controls always use capitalisation.

> +	case SND_SOC_BIAS_PREPARE:
> +		snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK,
> +				POWER_UP);
> +		snd_soc_update_bits(codec, STA529_MISC, 1, 0x01);

One of these has magic numbers and the other doesn't, and the magic
numbers are a little confusing as the mask is written in decimal but the
binary in hex.

> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		pdata = 1;
> +		break;
> +	case SNDRV_PCM_FORMAT_S24_LE:
> +		pdata = 2;
> +		break;
> +	case SNDRV_PCM_FORMAT_S32_LE:
> +		pdata = 3;
> +		break;
> +	}

Return an error on unsupported sample sizes.

> +	default:
> +		printk(KERN_WARNING, "bad rate\n");
> +		return -EINVAL;
> +	}

dev_warn() - always use the dev_ prints where possible.

> +	sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
> +	mdelay(10);

Absolutely no - why are you doing this?

> +static int sta529_mute(struct snd_soc_dai *dai, int mute)
> +{
> +	struct snd_soc_codec *codec = dai->codec;
> +
> +	u8 mute_reg = snd_soc_read(codec, STA529_FFXCFG0) & ~CODEC_MUTE_VAL;
> +
> +	if (mute)
> +		mute_reg |= CODEC_MUTE_VAL;
> +
> +	snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, 00);

You're always setting the same value here...

> +	snd_soc_add_controls(codec, sta529_snd_controls,
> +			ARRAY_SIZE(sta529_snd_controls));
> +
> +	snd_soc_add_controls(codec, sta529_new_snd_controls,
> +			ARRAY_SIZE(sta529_new_snd_controls));

Use the initialisers in the card struct.

> +	sta529 = kzalloc(sizeof(struct sta529), GFP_KERNEL);
> +	if (sta529 == NULL)
> +		return -ENOMEM;

devm_kzalloc().

> +static int __init sta529_modinit(void)

module_i2c_driver().

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

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



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

* Re: [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework.
  2012-03-20 11:33 ` [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework Rajeev Kumar
@ 2012-03-20 15:44   ` Mark Brown
  2012-03-26  9:03     ` Rajeev kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Brown @ 2012-03-20 15:44 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, lrg, spear-devel


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

On Tue, Mar 20, 2012 at 05:03:46PM +0530, Rajeev Kumar wrote:
> This patch add support for synopsys I2S controller as per the ASoC framework.

If this really is a generic Synopsys block shouldn't it be in a Synopsys
directory, possibly with a wrapper in the SPEAr directory for the
platform integration?

> +struct i2s_platform_data {
> +	#define PLAY	(1 << 0)
> +	#define RECORD	(1 << 1)

Namespacing here and with most of the other defines in the header (and
the driver, though the ones in the code are less important).  Normally
ALSA headers go in include/sound.

> +
> +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		i2s_write_reg(dev->i2s_base, TCR(ch), dev->xfer_resolution);
> +		i2s_write_reg(dev->i2s_base, TFCR(ch), 0x02);
> +		irq = i2s_read_reg(dev->i2s_base, IMR(ch));
> +		i2s_write_reg(dev->i2s_base, IMR(ch), irq & ~0x30);
> +		i2s_write_reg(dev->i2s_base, TER(ch), 1);
> +	} else {
> +		i2s_write_reg(dev->i2s_base, RCR(ch), dev->xfer_resolution);
> +		i2s_write_reg(dev->i2s_base, RFCR(ch), 0x07);
> +		irq = i2s_read_reg(dev->i2s_base, IMR(ch));
> +		i2s_write_reg(dev->i2s_base, IMR(ch), irq & ~0x03);
> +		i2s_write_reg(dev->i2s_base, RER(ch), 1);
> +	}

It would be good to split out the bits that are common from the bits
that vary per stream.

> +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		for (i = 0; i < 4; i++)
> +			i2s_write_reg(dev->i2s_base, TER(i), 0);
> +	} else {
> +		for (i = 0; i < 4; i++)
> +			i2s_write_reg(dev->i2s_base, RER(i), 0);

Magic numbers!

> +static irqreturn_t dw_i2s_play_irq(int irq, void *_dev)
> +{
> +	struct dw_i2s_dev *dev = (struct dw_i2s_dev *)_dev;
> +	u32 ch0, ch1;
> +
> +	/* check for the tx data overrun condition */
> +	ch0 = i2s_read_reg(dev->i2s_base, ISR(0)) & 0x20;
> +	ch1 = i2s_read_reg(dev->i2s_base, ISR(1)) & 0x20;
> +	if (ch0 || ch1) {
> +		/* disable i2s block */
> +		i2s_write_reg(dev->i2s_base, IER, 0);
> +
> +		/* disable tx block */
> +		i2s_write_reg(dev->i2s_base, ITER, 0);
> +
> +		/* flush all the tx fifo */
> +		i2s_write_reg(dev->i2s_base, TXFFR, 1);
> +
> +		/* clear tx data overrun interrupt */
> +		i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK);
> +
> +		/* enable rx block */
> +		i2s_write_reg(dev->i2s_base, ITER, 1);
> +
> +		/* enable i2s block */
> +		i2s_write_reg(dev->i2s_base, IER, 1);
> +	}

This is somewhat unusual - normally ALSA detects underrun and overrun
and restarts the stream at the application layer.  This looks like it
attempts to mask information about errors from the application which
probably isn't waht we want to do.  Why is the normal ALSA handling not
sufficient?

> +
> +	return IRQ_HANDLED;

This unconditionally says it handled the interrupt even if it didn't.

> +static int
> +dw_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
> +{
> +	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
> +	struct dma_data *dma_data = NULL;
> +
> +	if (!(dev->capability & RECORD) &&
> +			(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
> +		return -EINVAL;

Indentation.

> +
> +	if (dev->i2s_clk_cfg) {
> +		if (dev->i2s_clk_cfg(config)) {
> +			dev_err(dev->dev, "runtime audio clk config fail\n");
> +			if (cpu_dai->driver->ops->trigger) {
> +				int ret =
> +					cpu_dai->driver->ops->trigger(substream,
> +							SNDRV_PCM_TRIGGER_STOP,
> +							cpu_dai);
> +				if (ret < 0) {
> +					dev_err(dev->dev,
> +							"trigger stop fail\n");
> +					return ret;
> +				}
> +			}

No, return an error if you encounter an error!

> +static void
> +dw_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)

Indentation - throughout the kernel the type goes on the same line as
the function name.

> +static const struct dev_pm_ops dw_i2s_dev_pm_ops = {
> +	.suspend = dw_i2s_suspend,
> +	.resume = dw_i2s_resume,
> +};

No, do this at the ASoC level like other CPU drivers (runtime PM
callbacks are OK).

> +	cap = pdata->cap;
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "no i2s resource defined\n");
> +		return -ENODEV;
> +	}
> +
> +	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
> +		dev_err(&pdev->dev, "i2s region already claimed\n");
> +		return -EBUSY;
> +	}

There's devm_ versions of this stuff too.

> +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);

devm_kzalloc()

> +	dev->i2s_base = ioremap(res->start, resource_size(res));
> +	if (!dev->i2s_base) {

devm_ioremap().

> +		if (dev->play_irq < 0)
> +			dev_warn(&pdev->dev, "play irq not defined\n");
> +		else {

Braces on both sides of the if.

> +static int __init dw_i2s_init(void)

module_platform_driver().

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

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



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

* Re: [PATCH 3/8] sound:asoc: Add support for SPEAr ASoC pcm layer.
  2012-03-20 11:33 ` [PATCH 3/8] sound:asoc: Add support for SPEAr ASoC pcm layer Rajeev Kumar
@ 2012-03-20 15:50   ` Mark Brown
  0 siblings, 0 replies; 25+ messages in thread
From: Mark Brown @ 2012-03-20 15:50 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, lrg, spear-devel


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

On Tue, Mar 20, 2012 at 05:03:47PM +0530, Rajeev Kumar wrote:
> This patch add support for the SPEAr ASoC pcm layer in ASoC framework.

This should really be rewritten in terms of the dmaengine helper library
which Lars-Peter contributed for 3.4.  It looks like you're not using
cyclic mode here which is currently a requirement for the library - if
your hardware doesn't have cyclic support then that'll need to be added.

We've already got too many independant implementations of an ALSA to
dmaengine mapping, we should be cutting down on the amount of code as
much as possible in order to avoid code duplication and make sure that
we're able to roll out good practice and new features as easily as
possible.

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

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



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

* Re: [PATCH 4/8] sound:asoc:spdif_in: Add spdif IN support
  2012-03-20 11:33 ` [PATCH 4/8] sound:asoc:spdif_in: Add spdif IN support Rajeev Kumar
@ 2012-03-20 15:55   ` Mark Brown
  2012-03-27  9:25     ` Rajeev kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Brown @ 2012-03-20 15:55 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: alsa-devel, tiwai, spear-devel, Vipin Kumar, lrg


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

On Tue, Mar 20, 2012 at 05:03:48PM +0530, Rajeev Kumar wrote:

This looks good, a few minor things but almost good to go.

> This patch implements the spdif IN driver for ST peripheral

S/PDIF.

> +	if (irq_status & SPDIF_IRQ_FIFOWRITE)
> +		pr_err("spdif in: fifo write error\n");
> +	if (irq_status & SPDIF_IRQ_EMPTYFIFOREAD)
> +		pr_err("spdif in: empty fifo read error\n");
> +	if (irq_status & SPDIF_IRQ_FIFOFULL)
> +		pr_err("spdif in: fifo full error\n");
> +	if (irq_status & SPDIF_IRQ_OUTOFRANGE)
> +		pr_err("spdif in: out of range error\n");

dev_err().

> +	if (!devm_request_mem_region(&pdev->dev, res->start,
> +				resource_size(res), pdev->name)) {
> +		dev_warn(&pdev->dev, "Failed to get memory resourse\n");
> +		return -ENOENT;
> +	}
> +
> +	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
> +	if (!host) {
> +		dev_warn(&pdev->dev, "kzalloc fail\n");
> +		return -ENOMEM;
> +	}

Good to see this - this is the sort of stuff I was looking for in the
I2S driver.

> +	host->clk = clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(host->clk))
> +		return PTR_ERR(host->clk);

> +	pdata = dev_get_platdata(&pdev->dev);

Should really be error checking in case you didn't get your platform
data.

> +	ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
> +			"spdif-in", host);
> +	if (ret) {

I'm really not enthused about the idea of using devm_request_irq() here
- what steps are you taking to make sure that the IRQ can't possibly
fire after you've started tearing down the device.  In general it's
relatively hard to use devm_request_irq() safely.

> +#define SPDIF_IN_DEV_PM_OPS NULL

Just remove this if it's unconditionally empty.

> +static int __init spdif_in_init(void)

module_platform_driver().

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

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



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

* Re: [PATCH 6/8] sound:asoc: Add support for SPEAr ASoC machine driver.
  2012-03-20 11:33 ` [PATCH 6/8] sound:asoc: Add support for SPEAr ASoC machine driver Rajeev Kumar
@ 2012-03-20 16:00   ` Mark Brown
  0 siblings, 0 replies; 25+ messages in thread
From: Mark Brown @ 2012-03-20 16:00 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, lrg, spear-devel


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

On Tue, Mar 20, 2012 at 05:03:50PM +0530, Rajeev Kumar wrote:
> The patch add support for SPEAr ASoC machine driver.

This is the support for some particular board rather than for the SoC.

> +	if (cpu_is_spear1340()) {
> +#ifdef CONFIG_CPU_SPEAR1340
> +		u32 mode = 0;
> +		u32 val = readl(VA_SPEAR1340_PERIP_CFG);

Ick, no!  This should be in a driver for the SoC somewhere, not in the
board.  I've not really read most of the rest of the driver.

> +static int __init spear_audio_init(void)
> +{
> +	int ret;
> +	struct snd_soc_card *spear_soc_card;
> +
> +	if (machine_is_spear1340_lcad())
> +		spear_soc_card = &lcad_snd_card;
> +	else if (cpu_is_spear1340())
> +		spear_soc_card = &spear1340_snd_card;
> +	else if (cpu_is_spear320())
> +		spear_soc_card = &spear320s_snd_card;
> +	else
> +		spear_soc_card = &spear_snd_card;

Use snd_soc_register_card().

> +#if defined(CONFIG_CPU_SPEAR1340)
> +	if (cpu_is_spear1340()) {
> +		/* Create and register spdif platform devices */
> +		spdif_dit_device = platform_device_alloc("spdif-dit", -1);
> +		if (!spdif_dit_device) {
> +			printk(KERN_ERR "spdif transceiver " \
> +					"platform_device_alloc fails\n");
> +			return -ENOMEM;
> +		}

Absolutely no, all this setup of the devices for the SoC should be in
your arch/arm code somewhere.  This should only be a driver for the
board.

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

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



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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-20 11:33 ` [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec Rajeev Kumar
  2012-03-20 15:25   ` Mark Brown
@ 2012-03-20 17:57   ` Lars-Peter Clausen
  2012-03-23  4:00     ` Rajeev kumar
  1 sibling, 1 reply; 25+ messages in thread
From: Lars-Peter Clausen @ 2012-03-20 17:57 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: alsa-devel, spear-devel, tiwai, broonie, lrg

On 03/20/2012 12:33 PM, Rajeev Kumar wrote:
> +static const char *interface_mode_text[] = { "slave", "master"};

Master/slave mode should be configured using the set_dai_fmt callback.

> +
> +static struct snd_soc_dai_ops sta529_dai_ops = {

const

> +	.hw_params	=	sta529_hw_params,
> +	.set_fmt	=	sta529_set_dai_fmt,
> +	.digital_mute	=	sta529_mute,
> +};
> +
> +/* power down chip */
> +static int sta529_remove(struct snd_soc_codec *codec)
> +{
> +	sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
> +
> +	return 0;
> +}
> +
> +static int sta529_suspend(struct snd_soc_codec *codec, pm_message_t state)

The suspend callback doesn't take the state parameter anymore.

> +{
> +	sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
> +
> +	return 0;
> +}
> +
> +static int sta529_resume(struct snd_soc_codec *codec)
> +{
> +	snd_soc_cache_sync(codec);
> +	sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
> +	sta529_set_bias_level(codec, codec->dapm.suspend_bias_level);
> +
> +	return 0;
> +}
> +
> +struct snd_soc_codec_driver soc_codec_dev_sta529 = {

A better name is be sta520_codec_driver
[...]
> +
> +static int sta529_i2c_remove(struct i2c_client *client)
__devexit
> +{
> +	snd_soc_unregister_codec(&client->dev);
> +	kfree(i2c_get_clientdata(client));
> +	return 0;
> +}
river");
> +MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
> +MODULE_LICENSE("GPL");

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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-20 15:25   ` Mark Brown
@ 2012-03-23  3:42     ` Rajeev kumar
  2012-03-23  9:07       ` Lars-Peter Clausen
  0 siblings, 1 reply; 25+ messages in thread
From: Rajeev kumar @ 2012-03-23  3:42 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, lrg, spear-devel

Hello Mark

On 3/20/2012 8:55 PM, Mark Brown wrote:
> On Tue, Mar 20, 2012 at 05:03:45PM +0530, Rajeev Kumar wrote:
>> This patch adds the support for STA529 audio codec.
>> Details of the audio codec can be seen here:
>> http://www.st.com/internet/imag_video/product/159187.jsp
>
> Please use subject lines appropriate for the subsystem.  If your commits
> look visually different to all the other commits in the log that's not a
> good sign.
>

Ok


>> +config SND_SOC_STA529
>> +	tristate
>> +	depends on I2C
>> +
>

Agreed

> Drop the dependency, none of the other CODECs have this for a reason...
>
>> +#include<linux/platform_device.h>
>
> If you need this something went wrong...
>

Oops


>> +static const u8 sta529_reg[STA529_CACHEREGNUM] = {
>
> Use regmap for register I/O.
>

OK

>> +struct sta529 {
>> +	unsigned int sysclk;
>> +	enum snd_soc_control_type control_type;
>> +	void *control_data;
>
> Your device only supports I2C, no need for the infrastructure for other
> buses (though this will go away with regmap).
>

Agreed,

>> +static const char *pwm_mode_text[] = { "binary", "headphone", "ternary",
>> +	"phase-shift"};
>> +static const char *interface_mode_text[] = { "slave", "master"};
>
> ALSA controls always use capitalisation.
>

you mean to say
static const char *interface_mode_text[] = { "SLAVE", "MASTER"}


>> +	case SND_SOC_BIAS_PREPARE:
>> +		snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK,
>> +				POWER_UP);
>> +		snd_soc_update_bits(codec, STA529_MISC, 1, 0x01);
>
> One of these has magic numbers and the other doesn't, and the magic
> numbers are a little confusing as the mask is written in decimal but the
> binary in hex.
>

OK I will take mask for this.


>> +	switch (params_format(params)) {
>> +	case SNDRV_PCM_FORMAT_S16_LE:
>> +		pdata = 1;
>> +		break;
>> +	case SNDRV_PCM_FORMAT_S24_LE:
>> +		pdata = 2;
>> +		break;
>> +	case SNDRV_PCM_FORMAT_S32_LE:
>> +		pdata = 3;
>> +		break;
>> +	}
>
> Return an error on unsupported sample sizes.
>

In default , it is returning an error.

>> +	default:
>> +		printk(KERN_WARNING, "bad rate\n");
>> +		return -EINVAL;
>> +	}
>
> dev_warn() - always use the dev_ prints where possible.
>

Agreed,

>> +	sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
>> +	mdelay(10);
>
> Absolutely no - why are you doing this?
>

In probe I am putting codec in standby mode. so to come out of this 
sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE) is called. Since 
there are some transition time between STANDBY and ON/PREAPRE, so a 
delay is introduced in the code.

>> +static int sta529_mute(struct snd_soc_dai *dai, int mute)
>> +{
>> +	struct snd_soc_codec *codec = dai->codec;
>> +
>> +	u8 mute_reg = snd_soc_read(codec, STA529_FFXCFG0)&  ~CODEC_MUTE_VAL;
>> +
>> +	if (mute)
>> +		mute_reg |= CODEC_MUTE_VAL;
>> +
>> +	snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, 00);
>
> You're always setting the same value here...
>

Oops, it should be
snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, mute_reg);


>> +	snd_soc_add_controls(codec, sta529_snd_controls,
>> +			ARRAY_SIZE(sta529_snd_controls));
>> +
>> +	snd_soc_add_controls(codec, sta529_new_snd_controls,
>> +			ARRAY_SIZE(sta529_new_snd_controls));
>
> Use the initialisers in the card struct.
>
ok


>> +	sta529 = kzalloc(sizeof(struct sta529), GFP_KERNEL);
>> +	if (sta529 == NULL)
>> +		return -ENOMEM;
>
> devm_kzalloc().

OK

Best Regards
Rajeev

>
>> +static int __init sta529_modinit(void)
>
> module_i2c_driver().

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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-20 17:57   ` Lars-Peter Clausen
@ 2012-03-23  4:00     ` Rajeev kumar
  2012-03-23  8:51       ` Lars-Peter Clausen
  0 siblings, 1 reply; 25+ messages in thread
From: Rajeev kumar @ 2012-03-23  4:00 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: alsa-devel, spear-devel, tiwai, broonie, lrg

Hello Lars,

On 3/20/2012 11:27 PM, Lars-Peter Clausen wrote:
> On 03/20/2012 12:33 PM, Rajeev Kumar wrote:
>> +static const char *interface_mode_text[] = { "slave", "master"};
>
> Master/slave mode should be configured using the set_dai_fmt callback.
>
You mean to say with the help of clock direction. I think you can do it 
in either way.
By this,  I am giving full control to user for the selection.

>> +
>> +static struct snd_soc_dai_ops sta529_dai_ops = {
>
> const
>

Ok,

>> +	.hw_params	=	sta529_hw_params,
>> +	.set_fmt	=	sta529_set_dai_fmt,
>> +	.digital_mute	=	sta529_mute,
>> +};
>> +
>> +/* power down chip */
>> +static int sta529_remove(struct snd_soc_codec *codec)
>> +{
>> +	sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
>> +
>> +	return 0;
>> +}
>> +
>> +static int sta529_suspend(struct snd_soc_codec *codec, pm_message_t state)
>
> The suspend callback doesn't take the state parameter anymore.
>

Oops,

>> +{
>> +	sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
>> +
>> +	return 0;
>> +}
>> +
>> +static int sta529_resume(struct snd_soc_codec *codec)
>> +{
>> +	snd_soc_cache_sync(codec);
>> +	sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
>> +	sta529_set_bias_level(codec, codec->dapm.suspend_bias_level);
>> +
>> +	return 0;
>> +}
>> +
>> +struct snd_soc_codec_driver soc_codec_dev_sta529 = {
>
> A better name is be sta520_codec_driver

Ok,

> [...]
>> +
>> +static int sta529_i2c_remove(struct i2c_client *client)
> __devexit
>> +{
>> +	snd_soc_unregister_codec(&client->dev);
>> +	kfree(i2c_get_clientdata(client));
>> +	return 0;
>> +}
> river");

This comment is not clear to me , please explain.

Best Regards
Rajeev

>> +MODULE_AUTHOR("Rajeev Kumar<rajeev-dlh.kumar@st.com>");
>> +MODULE_LICENSE("GPL");
>
> .
>

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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-23  4:00     ` Rajeev kumar
@ 2012-03-23  8:51       ` Lars-Peter Clausen
  2012-03-23  9:15         ` Rajeev kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Lars-Peter Clausen @ 2012-03-23  8:51 UTC (permalink / raw)
  To: Rajeev kumar; +Cc: tiwai, alsa-devel, spear-devel, lrg, broonie

On 03/23/2012 05:00 AM, Rajeev kumar wrote:
> Hello Lars,
> 
> On 3/20/2012 11:27 PM, Lars-Peter Clausen wrote:
>> On 03/20/2012 12:33 PM, Rajeev Kumar wrote:
>>> +static const char *interface_mode_text[] = { "slave", "master"};
>>
>> Master/slave mode should be configured using the set_dai_fmt callback.
>>
> You mean to say with the help of clock direction. I think you can do it 
> in either way.
> By this,  I am giving full control to user for the selection.

Maybe I'm misunderstanding what this control does. But if it is about
putting the CODEC in master or slave mode, so whether it should generate the
frame- and bitclocks or if the other end of the DAI link should do it, then
this should be configured using set_dai_fmt. Making this runtime selectable
from userspace doesn't make much sense since both sides of the DAI link have
to agree on who is master and who is slave. If you just change one side the
link will just stop working.

>> [...]
>>> +
>>> +static int sta529_i2c_remove(struct i2c_client *client)
>> __devexit
>>> +{
>>> +	snd_soc_unregister_codec(&client->dev);
>>> +	kfree(i2c_get_clientdata(client));
>>> +	return 0;
>>> +}
>> river");
> 
> This comment is not clear to me , please explain.

Annotate the remove function with __devexit. Like this:
+static int __devexit sta529_i2c_remove(struct i2c_client *client)

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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-23  3:42     ` Rajeev kumar
@ 2012-03-23  9:07       ` Lars-Peter Clausen
  2012-03-23  9:20         ` Rajeev kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Lars-Peter Clausen @ 2012-03-23  9:07 UTC (permalink / raw)
  To: Rajeev kumar; +Cc: tiwai, alsa-devel, Mark Brown, spear-devel, lrg


>>> +static const char *pwm_mode_text[] = { "binary", "headphone", "ternary",
>>> +	"phase-shift"};
>>> +static const char *interface_mode_text[] = { "slave", "master"};
>>
>> ALSA controls always use capitalisation.
>>
> 
> you mean to say
> static const char *interface_mode_text[] = { "SLAVE", "MASTER"}
> 

No, only the first letter upper case.

> 
>>> +	sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
>>> +	mdelay(10);
>>
>> Absolutely no - why are you doing this?
>>
> 
> In probe I am putting codec in standby mode. so to come out of this 
> sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE) is called. Since 
> there are some transition time between STANDBY and ON/PREAPRE, so a 
> delay is introduced in the code.

The framework will take care of taking the CODEC out of standby mode when it
is required, so you shouldn't need it here. Also, if the delay is required
put it into the set_bias_level function.

> 
>>> +static int sta529_mute(struct snd_soc_dai *dai, int mute)
>>> +{
>>> +	struct snd_soc_codec *codec = dai->codec;
>>> +
>>> +	u8 mute_reg = snd_soc_read(codec, STA529_FFXCFG0)&  ~CODEC_MUTE_VAL;
>>> +
>>> +	if (mute)
>>> +		mute_reg |= CODEC_MUTE_VAL;
>>> +
>>> +	snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, 00);
>>
>> You're always setting the same value here...
>>
> 
> Oops, it should be
> snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, mute_reg);

If you use snd_soc_update_bits, you don't have to read the register first.

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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-23  8:51       ` Lars-Peter Clausen
@ 2012-03-23  9:15         ` Rajeev kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Rajeev kumar @ 2012-03-23  9:15 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: tiwai, alsa-devel, spear-devel, lrg, broonie

Hello Lars,

On 3/23/2012 2:21 PM, Lars-Peter Clausen wrote:
> On 03/23/2012 05:00 AM, Rajeev kumar wrote:
>> Hello Lars,
>>
>> On 3/20/2012 11:27 PM, Lars-Peter Clausen wrote:
>>> On 03/20/2012 12:33 PM, Rajeev Kumar wrote:
>>>> +static const char *interface_mode_text[] = { "slave", "master"};
>>>
>>> Master/slave mode should be configured using the set_dai_fmt callback.
>>>
>> You mean to say with the help of clock direction. I think you can do it
>> in either way.
>> By this,  I am giving full control to user for the selection.
>
> Maybe I'm misunderstanding what this control does. But if it is about
> putting the CODEC in master or slave mode, so whether it should generate the
> frame- and bitclocks or if the other end of the DAI link should do it, then
> this should be configured using set_dai_fmt. Making this runtime selectable
> from userspace doesn't make much sense since both sides of the DAI link have
> to agree on who is master and who is slave. If you just change one side the
> link will just stop working.
>

Yes, This will put CODEC in master or slave mode.
OK I will do it in set_dai_fmt.

>>> [...]
>>>> +
>>>> +static int sta529_i2c_remove(struct i2c_client *client)
>>> __devexit
>>>> +{
>>>> +	snd_soc_unregister_codec(&client->dev);
>>>> +	kfree(i2c_get_clientdata(client));
>>>> +	return 0;
>>>> +}
>>> river");
>>
>> This comment is not clear to me , please explain.
>
> Annotate the remove function with __devexit. Like this:
> +static int __devexit sta529_i2c_remove(struct i2c_client *client)
>

Ok,

Best Regards
Rajeev

> .
>

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

* Re: [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec
  2012-03-23  9:07       ` Lars-Peter Clausen
@ 2012-03-23  9:20         ` Rajeev kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Rajeev kumar @ 2012-03-23  9:20 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: tiwai, alsa-devel, Mark Brown, spear-devel, lrg

Hello Clausen,

On 3/23/2012 2:37 PM, Lars-Peter Clausen wrote:
>
>>>> +static const char *pwm_mode_text[] = { "binary", "headphone", "ternary",
>>>> +	"phase-shift"};
>>>> +static const char *interface_mode_text[] = { "slave", "master"};
>>>
>>> ALSA controls always use capitalisation.
>>>
>>
>> you mean to say
>> static const char *interface_mode_text[] = { "SLAVE", "MASTER"}
>>
>
> No, only the first letter upper case.
>
>>
>>>> +	sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
>>>> +	mdelay(10);
>>>
>>> Absolutely no - why are you doing this?
>>>
>>
>> In probe I am putting codec in standby mode. so to come out of this
>> sta529_set_bias_level(codec, SND_SOC_BIAS_PREPARE) is called. Since
>> there are some transition time between STANDBY and ON/PREAPRE, so a
>> delay is introduced in the code.
>

Actually I was hoping for the same but not able to locate the code.
Ok, I will made the changes.

> The framework will take care of taking the CODEC out of standby mode when it
> is required, so you shouldn't need it here. Also, if the delay is required
> put it into the set_bias_level function.
>
>>
>>>> +static int sta529_mute(struct snd_soc_dai *dai, int mute)
>>>> +{
>>>> +	struct snd_soc_codec *codec = dai->codec;
>>>> +
>>>> +	u8 mute_reg = snd_soc_read(codec, STA529_FFXCFG0)&   ~CODEC_MUTE_VAL;
>>>> +
>>>> +	if (mute)
>>>> +		mute_reg |= CODEC_MUTE_VAL;
>>>> +
>>>> +	snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, 00);
>>>
>>> You're always setting the same value here...
>>>
>>
>> Oops, it should be
>> snd_soc_update_bits(codec, STA529_FFXCFG0, 0x80, mute_reg);
>
> If you use snd_soc_update_bits, you don't have to read the register first.
>

Ok

Best Regards
Rajeev

>
>
> .
>

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

* Re: [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework.
  2012-03-20 15:44   ` Mark Brown
@ 2012-03-26  9:03     ` Rajeev kumar
  2012-03-26 11:10       ` Mark Brown
  0 siblings, 1 reply; 25+ messages in thread
From: Rajeev kumar @ 2012-03-26  9:03 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, lrg, spear-devel

Hello Mark

On 3/20/2012 9:14 PM, Mark Brown wrote:
> On Tue, Mar 20, 2012 at 05:03:46PM +0530, Rajeev Kumar wrote:
>> This patch add support for synopsys I2S controller as per the ASoC framework.
>
> If this really is a generic Synopsys block shouldn't it be in a Synopsys
> directory, possibly with a wrapper in the SPEAr directory for the
> platform integration?
>

I will create a new directory by name dwc.

>> +struct i2s_platform_data {
>> +	#define PLAY	(1<<  0)
>> +	#define RECORD	(1<<  1)
>
> Namespacing here and with most of the other defines in the header (and
> the driver, though the ones in the code are less important).  Normally
> ALSA headers go in include/sound.
>

OK I will move it in include/sound/.
Next Patch will contains name spacing also.

>> +
>> +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> +		i2s_write_reg(dev->i2s_base, TCR(ch), dev->xfer_resolution);
>> +		i2s_write_reg(dev->i2s_base, TFCR(ch), 0x02);
>> +		irq = i2s_read_reg(dev->i2s_base, IMR(ch));
>> +		i2s_write_reg(dev->i2s_base, IMR(ch), irq&  ~0x30);
>> +		i2s_write_reg(dev->i2s_base, TER(ch), 1);
>> +	} else {
>> +		i2s_write_reg(dev->i2s_base, RCR(ch), dev->xfer_resolution);
>> +		i2s_write_reg(dev->i2s_base, RFCR(ch), 0x07);
>> +		irq = i2s_read_reg(dev->i2s_base, IMR(ch));
>> +		i2s_write_reg(dev->i2s_base, IMR(ch), irq&  ~0x03);
>> +		i2s_write_reg(dev->i2s_base, RER(ch), 1);
>> +	}
>
> It would be good to split out the bits that are common from the bits
> that vary per stream.
>

OK,


>> +	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> +		for (i = 0; i<  4; i++)
>> +			i2s_write_reg(dev->i2s_base, TER(i), 0);
>> +	} else {
>> +		for (i = 0; i<  4; i++)
>> +			i2s_write_reg(dev->i2s_base, RER(i), 0);
>
> Magic numbers!
>

will be replaced with macro

>> +static irqreturn_t dw_i2s_play_irq(int irq, void *_dev)
>> +{
>> +	struct dw_i2s_dev *dev = (struct dw_i2s_dev *)_dev;
>> +	u32 ch0, ch1;
>> +
>> +	/* check for the tx data overrun condition */
>> +	ch0 = i2s_read_reg(dev->i2s_base, ISR(0))&  0x20;
>> +	ch1 = i2s_read_reg(dev->i2s_base, ISR(1))&  0x20;
>> +	if (ch0 || ch1) {
>> +		/* disable i2s block */
>> +		i2s_write_reg(dev->i2s_base, IER, 0);
>> +
>> +		/* disable tx block */
>> +		i2s_write_reg(dev->i2s_base, ITER, 0);
>> +
>> +		/* flush all the tx fifo */
>> +		i2s_write_reg(dev->i2s_base, TXFFR, 1);
>> +
>> +		/* clear tx data overrun interrupt */
>> +		i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK);
>> +
>> +		/* enable rx block */
>> +		i2s_write_reg(dev->i2s_base, ITER, 1);
>> +
>> +		/* enable i2s block */
>> +		i2s_write_reg(dev->i2s_base, IER, 1);
>> +	}
>
> This is somewhat unusual - normally ALSA detects underrun and overrun
> and restarts the stream at the application layer.  This looks like it
> attempts to mask information about errors from the application which
> probably isn't waht we want to do.  Why is the normal ALSA handling not5
> sufficient?
>

Normal ALSA handling is sufficient for underrun and overrun. This 
handler is not required.

>> +
>> +	return IRQ_HANDLED;
>
> This unconditionally says it handled the interrupt even if it didn't.
>

Removing handler will remove this too.

>> +static int
>> +dw_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
>> +{
>> +	struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
>> +	struct dma_data *dma_data = NULL;
>> +
>> +	if (!(dev->capability&  RECORD)&&
>> +			(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
>> +		return -EINVAL;
>
> Indentation.
>

Ok

>> +
>> +	if (dev->i2s_clk_cfg) {
>> +		if (dev->i2s_clk_cfg(config)) {
>> +			dev_err(dev->dev, "runtime audio clk config fail\n");
>> +			if (cpu_dai->driver->ops->trigger) {
>> +				int ret =
>> +					cpu_dai->driver->ops->trigger(substream,
>> +							SNDRV_PCM_TRIGGER_STOP,
>> +							cpu_dai);
>> +				if (ret<  0) {
>> +					dev_err(dev->dev,
>> +							"trigger stop fail\n");
>> +					return ret;
>> +				}
>> +			}
>
> No, return an error if you encounter an error!
>

You need not to stop controller in case clock fail ?


>> +static void
>> +dw_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
>
> Indentation - throughout the kernel the type goes on the same line asi2s
> the function name.
>

Ok

>> +static const struct dev_pm_ops dw_i2s_dev_pm_ops = {
>> +	.suspend = dw_i2s_suspend,
>> +	.resume = dw_i2s_resume,
>> +};
>
> No, do this at the ASoC level like other CPU drivers (runtime PM
> callbacks are OK).
>

Ok,

>> +	cap = pdata->cap;
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	if (!res) {
>> +		dev_err(&pdev->dev, "no i2s resource defined\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
>> +		dev_err(&pdev->dev, "i2s region already claimed\n");
>> +		return -EBUSY;
>> +	}
>
> There's devm_ versions of this stuff too.
>

OK

>> +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
>
> devm_kzalloc()
>

Ok

>> +	dev->i2s_base = ioremap(res->start, resource_size(res));
>> +	if (!dev->i2s_base) {
>
> devm_ioremap().
>

Ok


>> +		if (dev->play_irq<  0)
>> +			dev_warn(&pdev->dev, "play irq not defined\n");
>> +		else {
>
> Braces on both sides of the if.
>
Ok,


Best Regards
Rajeev

>> +static int __init dw_i2s_init(void)
>
> module_platform_driver().

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

* Re: [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework.
  2012-03-26  9:03     ` Rajeev kumar
@ 2012-03-26 11:10       ` Mark Brown
  2012-03-27  3:51         ` Rajeev kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Brown @ 2012-03-26 11:10 UTC (permalink / raw)
  To: Rajeev kumar; +Cc: tiwai, alsa-devel, lrg, spear-devel


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

On Mon, Mar 26, 2012 at 02:33:22PM +0530, Rajeev kumar wrote:
> On 3/20/2012 9:14 PM, Mark Brown wrote:
> >On Tue, Mar 20, 2012 at 05:03:46PM +0530, Rajeev Kumar wrote:

> >>+		if (dev->i2s_clk_cfg(config)) {
> >>+			dev_err(dev->dev, "runtime audio clk config fail\n");
> >>+			if (cpu_dai->driver->ops->trigger) {
> >>+				int ret =
> >>+					cpu_dai->driver->ops->trigger(substream,
> >>+							SNDRV_PCM_TRIGGER_STOP,
> >>+							cpu_dai);
> >>+				if (ret<  0) {
> >>+					dev_err(dev->dev,
> >>+							"trigger stop fail\n");
> >>+					return ret;
> >>+				}
> >>+			}

> >No, return an error if you encounter an error!

> You need not to stop controller in case clock fail ?

Let the upper layers worry about that.  Don't randomly change the state
of the controller without them knowing about it.


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

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



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

* Re: [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework.
  2012-03-26 11:10       ` Mark Brown
@ 2012-03-27  3:51         ` Rajeev kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Rajeev kumar @ 2012-03-27  3:51 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, lrg, spear-devel

Hello Mark,

On 3/26/2012 4:40 PM, Mark Brown wrote:
> On Mon, Mar 26, 2012 at 02:33:22PM +0530, Rajeev kumar wrote:
>> On 3/20/2012 9:14 PM, Mark Brown wrote:
>>> On Tue, Mar 20, 2012 at 05:03:46PM +0530, Rajeev Kumar wrote:
>
>>>> +		if (dev->i2s_clk_cfg(config)) {
>>>> +			dev_err(dev->dev, "runtime audio clk config fail\n");
>>>> +			if (cpu_dai->driver->ops->trigger) {
>>>> +				int ret =
>>>> +					cpu_dai->driver->ops->trigger(substream,
>>>> +							SNDRV_PCM_TRIGGER_STOP,
>>>> +							cpu_dai);
>>>> +				if (ret<   0) {
>>>> +					dev_err(dev->dev,
>>>> +							"trigger stop fail\n");
>>>> +					return ret;
>>>> +				}
>>>> +			}
>
>>> No, return an error if you encounter an error!
>
>> You need not to stop controller in case clock fail ?
>
> Let the upper layers worry about that.  Don't randomly change the state
> of the controller without them knowing about it.
>

Ok

Best Regards
Rajeev

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

* Re: [PATCH 4/8] sound:asoc:spdif_in: Add spdif IN support
  2012-03-20 15:55   ` Mark Brown
@ 2012-03-27  9:25     ` Rajeev kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Rajeev kumar @ 2012-03-27  9:25 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, tiwai, spear-devel, Vipin KUMAR, lrg

Hello Mark,

On 3/20/2012 9:25 PM, Mark Brown wrote:
> On Tue, Mar 20, 2012 at 05:03:48PM +0530, Rajeev Kumar wrote:
>
> This looks good, a few minor things but almost good to go.
>
>> This patch implements the spdif IN driver for ST peripheral
>
> S/PDIF.
>

Ok,


>> +	if (irq_status&  SPDIF_IRQ_FIFOWRITE)
>> +		pr_err("spdif in: fifo write error\n");
>> +	if (irq_status&  SPDIF_IRQ_EMPTYFIFOREAD)
>> +		pr_err("spdif in: empty fifo read error\n");
>> +	if (irq_status&  SPDIF_IRQ_FIFOFULL)
>> +		pr_err("spdif in: fifo full error\n");
>> +	if (irq_status&  SPDIF_IRQ_OUTOFRANGE)
>> +		pr_err("spdif in: out of range error\n");
>
> dev_err().
>

Ok

>> +	if (!devm_request_mem_region(&pdev->dev, res->start,
>> +				resource_size(res), pdev->name)) {
>> +		dev_warn(&pdev->dev, "Failed to get memory resourse\n");
>> +		return -ENOENT;
>> +	}
>> +
>> +	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
>> +	if (!host) {
>> +		dev_warn(&pdev->dev, "kzalloc fail\n");
>> +		return -ENOMEM;
>> +	}
>
> Good to see this - this is the sort of stuff I was looking for in the
> I2S driver.
>

Will follow this in I2S driver.

>> +	host->clk = clk_get(&pdev->dev, NULL);
>> +	if (IS_ERR(host->clk))
>> +		return PTR_ERR(host->clk);
>
>> +	pdata = dev_get_platdata(&pdev->dev);
>
> Should really be error checking in case you didn't get your platform
> data.
>

Agreed,

>> +	ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
>> +			"spdif-in", host);
>> +	if (ret) {
>
> I'm really not enthused about the idea of using devm_request_irq() here
> - what steps are you taking to make sure that the IRQ can't possibly
> fire after you've started tearing down the device.  In general it's
> relatively hard to use devm_request_irq() safely.
>

Disabling interrupt in remove will insure that interrupt will not fire 
after tearing down the device.


>> +#define SPDIF_IN_DEV_PM_OPS NULL
>
> Just remove this if it's unconditionally empty.
>

OK,

Best Regards
Rajeev

>> +static int __init spdif_in_init(void)
>
> module_platform_driver().

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

end of thread, other threads:[~2012-03-27  9:25 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-20 11:33 [PATCH 0/8] Add ASoC drivers for SPEAr platform Rajeev Kumar
2012-03-20 11:33 ` [PATCH 1/8] sound:asoc: Add support for STA529 Audio Codec Rajeev Kumar
2012-03-20 15:25   ` Mark Brown
2012-03-23  3:42     ` Rajeev kumar
2012-03-23  9:07       ` Lars-Peter Clausen
2012-03-23  9:20         ` Rajeev kumar
2012-03-20 17:57   ` Lars-Peter Clausen
2012-03-23  4:00     ` Rajeev kumar
2012-03-23  8:51       ` Lars-Peter Clausen
2012-03-23  9:15         ` Rajeev kumar
2012-03-20 11:33 ` [PATCH 2/8] sound:asoc: Add support for synopsys i2s controller as per ASoC framework Rajeev Kumar
2012-03-20 15:44   ` Mark Brown
2012-03-26  9:03     ` Rajeev kumar
2012-03-26 11:10       ` Mark Brown
2012-03-27  3:51         ` Rajeev kumar
2012-03-20 11:33 ` [PATCH 3/8] sound:asoc: Add support for SPEAr ASoC pcm layer Rajeev Kumar
2012-03-20 15:50   ` Mark Brown
2012-03-20 11:33 ` [PATCH 4/8] sound:asoc:spdif_in: Add spdif IN support Rajeev Kumar
2012-03-20 15:55   ` Mark Brown
2012-03-27  9:25     ` Rajeev kumar
2012-03-20 11:33 ` [PATCH 5/8] sound:asoc:spdif_out: Add spdif out support Rajeev Kumar
2012-03-20 11:33 ` [PATCH 6/8] sound:asoc: Add support for SPEAr ASoC machine driver Rajeev Kumar
2012-03-20 16:00   ` Mark Brown
2012-03-20 11:33 ` [PATCH 7/8] sound:asoc: Add Kconfig and Makefile to support SPEAr audio driver Rajeev Kumar
2012-03-20 11:33 ` [PATCH 8/8] sound:asoc: Update Kconfig and Makefile(sound/soc/) to support SPEAr audio Rajeev Kumar

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.