All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V3 0/5] Adding ASoC drivers for SPEAr13XX platform
@ 2011-04-11  5:29 Rajeev Kumar
  2011-04-11  5:30 ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Rajeev Kumar
  0 siblings, 1 reply; 27+ messages in thread
From: Rajeev Kumar @ 2011-04-11  5:29 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, Rajeev Kumar, lrg

This patchset contains five patches which add support for ASoC sound
drivers on ST's SPEAr13XX platform. Details of the SPEAr13XX
platforms can be seen here:
http://www.st.com/internet/mcu/product/250658.jsp

The ARCH and PLATFORM specific code for SPEAr13XX are
already under review in Russell King's ARM mailing
list(Linux-kernel-version 2.6.38-rc4).

This patchset has been tested for linux-kernel-version 2.6.38-rc4 and
on ARM platform.

Please review the same and consider for mainline inclusion.

Changes in spear Kconfig and Makefile since V2:
1.giving all the the modules snd-soc- prefixes to their names
Changes in codec code since V2:
1. use SOC_DOUBLE for volume control
2. remove default configuration for codec .offer them as runtime controls.
3. restore the register cache in resume
changes in platform code since V1:
1. Spilt machine driver from platform driver.
2. Updated rate supported.
3. Moved clock specific part from "spear13xx_i2s_set_dai_sysclk".
   function to platform code. This function is removed now.
4. Function "spear13xx_i2s_startup" removed.
5. Function "spear13xx_i2s_shutdown" removed.

Changes in codec code since V1:
1. Removed sta529 version number.
2. Removed "sta529_read_reg_cache".
3. Removed function "sta529_write_reg_cache".
4. Removed function "sta529_write".
5. Moved sta529.h file contents to sta529.c file.
6. Move clock specific part from "spear_sta_set_dai_sysclk".
   function to platform code. This function is removed now.
7. Renamed function names from spear_sta_* to sta_*.
8. Modified probe() function to avoid rewriting default chip values to hardware.

Rajeev Kumar (5):
  sound: asoc: Adding support for STA529 Audio Codec
  sound: asoc: Adding support for SPEAr13XX ASoC platform driver
  sound: asoc: Adding support for SPEAr13XX ASoC machine driver
  sound: asoc: Adding Kconfig and Makefile to support SPEAr13XX ASoC
    driver
  sound: asoc: Adding support for SPEAr13XX in soc

 sound/soc/Kconfig               |    1 +
 sound/soc/Makefile              |    1 +
 sound/soc/codecs/Kconfig        |    5 +
 sound/soc/codecs/Makefile       |    2 +
 sound/soc/codecs/sta529.c       |  383 ++++++++++++++++++++++++++++
 sound/soc/spear/Kconfig         |   19 ++
 sound/soc/spear/Makefile        |   12 +
 sound/soc/spear/evb_sta529.c    |  103 ++++++++
 sound/soc/spear/spear13xx-i2s.c |  523 +++++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spear13xx-i2s.h |   19 ++
 sound/soc/spear/spear13xx-pcm.c |  500 +++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spear13xx-pcm.h |   50 ++++
 12 files changed, 1618 insertions(+), 0 deletions(-)
 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/evb_sta529.c
 create mode 100644 sound/soc/spear/spear13xx-i2s.c
 create mode 100644 sound/soc/spear/spear13xx-i2s.h
 create mode 100644 sound/soc/spear/spear13xx-pcm.c
 create mode 100644 sound/soc/spear/spear13xx-pcm.h

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

* [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11  5:29 [PATCH V3 0/5] Adding ASoC drivers for SPEAr13XX platform Rajeev Kumar
@ 2011-04-11  5:30 ` Rajeev Kumar
  2011-04-11  5:30   ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Rajeev Kumar
                     ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Rajeev Kumar @ 2011-04-11  5:30 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-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 |  383 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 390 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/codecs/sta529.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b814ed0..d536740 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -40,6 +40,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_SN95031 if INTEL_SCU_IPC
 	select SND_SOC_SPDIF
 	select SND_SOC_SSM2602 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
@@ -206,6 +207,10 @@ config SND_SOC_SPDIF
 config SND_SOC_SSM2602
 	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 49121ad..f889ef5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -26,6 +26,7 @@ snd-soc-alc5623-objs := alc5623.o
 snd-soc-sn95031-objs := sn95031.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.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
@@ -114,6 +115,7 @@ obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 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_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..8dda5cd
--- /dev/null
+++ b/sound/soc/codecs/sta529.c
@@ -0,0 +1,383 @@
+/*
+ * ASoC codec driver for spear platform
+ *
+ * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver
+ *
+ * Copyright (C) 2011 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_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] = {
+	0x75, 0xf8, 0x50, 0x00,
+	0x00, 0x00, 0x02, 0x00,
+	0x02, 0x02, 0xD2, 0x91,
+	0xD3, 0x91, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x80, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x52, 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 *op_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, op_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_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 = 0;
+
+	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;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_soc_update_bits(codec, STA529_S2PCFG1, 0xB0, pdata);
+	else
+		snd_soc_update_bits(codec, STA529_P2SCFG1, 0xB0, pdata);
+
+	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 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_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->bias_level = level;
+	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;
+
+	codec->hw_write = (hw_write_t)i2c_master_send;
+	codec->hw_read = NULL;
+	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)
+{
+	int i;
+	u8 data[2];
+	u8 *cache = codec->reg_cache;
+
+	for (i = 0; i < ARRAY_SIZE(sta529_reg); i++) {
+		data[0] = i;
+		data[1] = cache[i];
+		codec->hw_write(codec->control_data, data, 2);
+	}
+
+	sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	sta529_set_bias_level(codec, codec->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.6.0.2

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

* [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver
  2011-04-11  5:30 ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Rajeev Kumar
@ 2011-04-11  5:30   ` Rajeev Kumar
  2011-04-11  5:30     ` [PATCH V3 3/5] sound: asoc: Adding support for SPEAr13XX ASoC machine driver Rajeev Kumar
  2011-04-11 13:00     ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Lu Guanqun
  2011-04-11 12:53   ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Lu Guanqun
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 27+ messages in thread
From: Rajeev Kumar @ 2011-04-11  5:30 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, Rajeev Kumar, lrg

This patch adds the support for the SPEAr13XX Platform Driver (I2S based)
as per the ASoC framework.

SPEAr13XX internally uses a Designware I2S IP and some glue logic on top
of the same.

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 sound/soc/spear/spear13xx-i2s.c |  523 +++++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spear13xx-i2s.h |   19 ++
 sound/soc/spear/spear13xx-pcm.c |  500 +++++++++++++++++++++++++++++++++++++
 sound/soc/spear/spear13xx-pcm.h |   50 ++++
 4 files changed, 1092 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/spear/spear13xx-i2s.c
 create mode 100644 sound/soc/spear/spear13xx-i2s.h
 create mode 100644 sound/soc/spear/spear13xx-pcm.c
 create mode 100644 sound/soc/spear/spear13xx-pcm.h

diff --git a/sound/soc/spear/spear13xx-i2s.c b/sound/soc/spear/spear13xx-i2s.c
new file mode 100644
index 0000000..33d2d11
--- /dev/null
+++ b/sound/soc/spear/spear13xx-i2s.c
@@ -0,0 +1,523 @@
+/*
+ * ALSA SoC I2S Audio Layer for ST spear13xx processor
+ *
+ * sound/soc/spear/spear13xx-i2s.c
+ *
+ * Copyright (C) 2011 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/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <mach/misc_regs.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include "spear13xx-pcm.h"
+#include "spear13xx-i2s.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 channel 0 */
+#define LRBR0_LTHR0	0x020
+#define RRBR0_RTHR0	0x024
+#define RER0		0x028
+#define TER0		0x02C
+#define RCR0		0x030
+#define TCR0		0x034
+#define ISR0		0x038
+#define IMR0		0x03C
+#define ROR0		0x040
+#define TOR0		0x044
+#define RFCR0		0x048
+#define TFCR0		0x04C
+#define RFF0		0x050
+#define TFF0		0x054
+
+/* I2STxRxRegisters for channel 1 */
+#define LRBR1_LTHR1	0x060
+#define RRBR1_RTHR1	0x064
+#define RER1		0x068
+#define TER1		0x06C
+#define RCR1		0x070
+#define TCR1		0x074
+#define ISR1		0x078
+#define IMR1		0x07C
+#define ROR1		0x080
+#define TOR1		0x084
+#define RFCR1		0x088
+#define TFCR1		0x08C
+#define RFF1		0x090
+#define TFF1		0x094
+
+/* I2STxRxRegisters for channel 2 */
+#define LRBR2_LTHR2	0x0A0
+#define RRBR2_RTHR2	0x0A4
+#define RER2		0x0A8
+#define TER2		0x0AC
+#define RCR2		0x0B0
+#define TCR2		0x0B4
+#define ISR2		0x0B8
+#define IMR2		0x0BC
+#define ROR2		0x0C0
+#define TOR2		0x0C4
+#define RFCR2		0x0C8
+#define TFCR2		0x0CC
+#define RFF2		0x0D0
+#define TFF2		0x0D4
+
+/* I2STxRxRegisters for channel 3*/
+#define LRBR3_LTHR3	0x0E0
+#define RRBR3_RTHR3	0x0E4
+#define RER3		0x0E8
+#define TER3		0x0EC
+#define RCR3		0x0F0
+#define TCR3		0x0F4
+#define ISR3		0x0F8
+#define IMR3		0x0FC
+#define ROR3		0x100
+#define TOR3		0x104
+#define RFCR3		0x108
+#define TFCR3		0x10C
+#define RFF3		0x110
+#define TFF3		0x114
+
+/* I2SDMARegisters */
+#define RXDMA		0x01C0
+#define RRXDMA		0x01C4
+#define TXDMA		0x01C8
+#define RTXDMA		0x01CC
+
+/* I2SCOMPRegisters */
+#define I2S_COMP_PARAM_2	0x01F0
+#define I2S_COMP_PARAM_1	0x01F4
+#define I2S_COMP_VERSION	0x01F8
+#define I2S_COMP_TYPE		0x01FC
+
+#define SPEAR13XX_I2S_RATES	SNDRV_PCM_RATE_8000_96000
+#define SPEAR13XX_I2S_FORMAT	SNDRV_PCM_FMTBIT_S16_LE
+#define MAX_CHANNEL_NUM		2
+#define MIN_CHANNEL_NUM		2
+
+struct spear13xx_i2s_dev {
+	void __iomem *i2s_base;
+	struct resource *res;
+	struct clk *clk;
+	int play_irq;
+	int mode;
+	int active;
+	int capture_irq;
+	struct device *dev;
+	struct spear13xx_pcm_dma_params *dma_params[2];
+};
+
+void get_dma_start_addr(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
+	struct spear13xx_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+	prtd->txdma = dev->res->start + TXDMA;
+	prtd->rxdma = dev->res->start + RXDMA;
+
+	substream->runtime->private_data = prtd;
+}
+
+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 void i2s_start_play(struct spear13xx_i2s_dev *dev,
+		struct snd_pcm_substream *substream)
+{
+	u32 val; /*dma mode slection*/
+
+	val = readl(PERIP_CFG);
+	val &= ~0xFFFFFFFC;
+	i2s_write_reg(dev->i2s_base, TER0, 0);
+	i2s_write_reg(dev->i2s_base, TER1, 0);
+
+	/* for 2.0 audio*/
+	if (dev->mode <= 2) {
+		if (!val) {
+			i2s_write_reg(dev->i2s_base, TCR0, 0x2);
+			i2s_write_reg(dev->i2s_base, TFCR0, 0x07);
+			i2s_write_reg(dev->i2s_base, IMR0, 0x00);
+			i2s_write_reg(dev->i2s_base, TER0, 1);
+		} else {
+			i2s_write_reg(dev->i2s_base, TCR1, 0x2);
+			i2s_write_reg(dev->i2s_base, TFCR1, 0x07);
+			i2s_write_reg(dev->i2s_base, IMR1, 0x00);
+			i2s_write_reg(dev->i2s_base, TER1, 1);
+		}
+	} else { /*audio 2.0 onwards */
+		i2s_write_reg(dev->i2s_base, TCR0, 0x5);
+		i2s_write_reg(dev->i2s_base, TCR1, 0x5);
+
+		i2s_write_reg(dev->i2s_base, TFCR0, 0x07);
+		i2s_write_reg(dev->i2s_base, TFCR1, 0x07);
+		i2s_write_reg(dev->i2s_base, IMR0, 0x00);
+		i2s_write_reg(dev->i2s_base, IMR1, 0x00);
+		i2s_write_reg(dev->i2s_base, TER0, 1);
+		i2s_write_reg(dev->i2s_base, TER1, 1);
+	}
+
+	i2s_write_reg(dev->i2s_base, ITER, 1);
+}
+
+static void i2s_start_rec(struct spear13xx_i2s_dev *dev,
+		struct snd_pcm_substream *substream)
+{
+	u32 val; /*dma mode slection*/
+
+	val = readl(PERIP_CFG);
+	val &= ~0xFFFFFFFC;
+	i2s_write_reg(dev->i2s_base, RER0, 0);
+	i2s_write_reg(dev->i2s_base, RER1, 0);
+
+	/* for 2.0 audio*/
+	if (dev->mode <= 2) {
+		if (!val) {
+			i2s_write_reg(dev->i2s_base, RCR0, 0x2);
+			i2s_write_reg(dev->i2s_base, RFCR0, 0x07);
+			i2s_write_reg(dev->i2s_base, IMR0, 0x00);
+			i2s_write_reg(dev->i2s_base, RER0, 1);
+		} else {
+			i2s_write_reg(dev->i2s_base, RCR1, 0x2);
+			i2s_write_reg(dev->i2s_base, RFCR1, 0x07);
+			i2s_write_reg(dev->i2s_base, IMR1, 0x00);
+			i2s_write_reg(dev->i2s_base, TER1, 1);
+		}
+	} else { /*audio 2.0 onwards */
+		i2s_write_reg(dev->i2s_base, RCR0, 0x5);
+		i2s_write_reg(dev->i2s_base, RCR1, 0x5);
+
+		i2s_write_reg(dev->i2s_base, RFCR0, 0x07);
+		i2s_write_reg(dev->i2s_base, RFCR1, 0x07);
+		i2s_write_reg(dev->i2s_base, IMR0, 0x00);
+		i2s_write_reg(dev->i2s_base, IMR1, 0x00);
+		i2s_write_reg(dev->i2s_base, RER0, 1);
+		i2s_write_reg(dev->i2s_base, RER1, 1);
+	}
+
+	i2s_write_reg(dev->i2s_base, IRER, 1);
+}
+
+static void i2s_stop(struct spear13xx_i2s_dev *dev,
+		struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		i2s_write_reg(dev->i2s_base, ITER, 0);
+		i2s_write_reg(dev->i2s_base, ITER, 1);
+		i2s_write_reg(dev->i2s_base, IMR0, 0x30);
+		i2s_write_reg(dev->i2s_base, IMR1, 0x30);
+	} else {
+		i2s_write_reg(dev->i2s_base, IRER, 0);
+		i2s_write_reg(dev->i2s_base, IRER, 1);
+		i2s_write_reg(dev->i2s_base, IMR0, 0x03);
+		i2s_write_reg(dev->i2s_base, IMR1, 0x03);
+	}
+	if (!dev->active--) {
+		i2s_write_reg(dev->i2s_base, CER, 0);
+		i2s_write_reg(dev->i2s_base, IER, 0);
+		dev->active = 0;
+	}
+
+}
+
+static irqreturn_t i2s_play_irq(int irq, void *_dev)
+{
+	struct spear13xx_i2s_dev *dev = (struct spear13xx_i2s_dev *)_dev;
+	u32 ch0, ch1;
+
+	/* check for the tx data overrun condition */
+	ch0 = i2s_read_reg(dev->i2s_base, ISR0) & 0x20;
+	ch1 = i2s_read_reg(dev->i2s_base, ISR1) & 0x20;
+	if (ch0 || ch1) {
+
+		/* 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: channel 0 */
+		i2s_read_reg(dev->i2s_base, TOR0);
+
+		/* clear tx data overrun interrupt: channel 1 */
+		i2s_read_reg(dev->i2s_base, TOR1);
+
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t i2s_capture_irq(int irq, void *_dev)
+{
+	struct spear13xx_i2s_dev *dev = (struct spear13xx_i2s_dev *)_dev;
+	u32 ch0, ch1;
+
+	/* check for the rx data overrun condition */
+	ch0 = i2s_read_reg(dev->i2s_base, ISR0) & 0x02;
+	ch1 = i2s_read_reg(dev->i2s_base, ISR1) & 0x02;
+	if (ch0 || ch1) {
+
+		/* 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: channel 0 */
+		i2s_read_reg(dev->i2s_base, ROR0);
+
+		/* clear rx data overrun interrupt: channel 1 */
+		i2s_read_reg(dev->i2s_base, ROR1);
+
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int spear13xx_i2s_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct spear13xx_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+	dev->mode = params_channels(params);
+
+	if (dev->mode <= 2)
+		i2s_write_reg(dev->i2s_base, CCR, 0x00);
+	else
+		i2s_write_reg(dev->i2s_base, CCR, 0x10);
+
+	return 0;
+}
+
+static int
+spear13xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct spear13xx_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+	int ret = 0;
+
+	i2s_write_reg(dev->i2s_base, IER, 1);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dev->active++;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			i2s_start_play(dev, substream);
+		else
+			i2s_start_rec(dev, substream);
+		i2s_write_reg(dev->i2s_base, CER, 1);
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		i2s_stop(dev, substream);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static struct snd_soc_dai_ops spear13xx_i2s_dai_ops = {
+	.hw_params	= spear13xx_i2s_hw_params,
+	.trigger	= spear13xx_i2s_trigger,
+};
+
+struct snd_soc_dai_driver spear13xx_i2s_dai = {
+	.playback = {
+		.channels_min = MAX_CHANNEL_NUM,
+		.channels_max = MIN_CHANNEL_NUM,
+		.rates = SPEAR13XX_I2S_RATES,
+		.formats = SPEAR13XX_I2S_FORMAT,
+	},
+	.capture = {
+		.channels_min = MAX_CHANNEL_NUM,
+		.channels_max = MIN_CHANNEL_NUM,
+		.rates = SPEAR13XX_I2S_RATES,
+		.formats = SPEAR13XX_I2S_FORMAT,
+	},
+	.ops = &spear13xx_i2s_dai_ops,
+};
+
+static int spear13xx_i2s_probe(struct platform_device *pdev)
+{
+	struct spear13xx_i2s_dev *dev;
+	struct resource *res;
+	int ret;
+
+	if (!pdev) {
+		dev_err(&pdev->dev, "Invalid platform device\n");
+		return -EINVAL;
+	}
+
+	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->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;
+	}
+
+	dev->play_irq = platform_get_irq_byname(pdev, "play_irq");
+	if (!dev->play_irq) {
+		dev_err(&pdev->dev, "play irq not defined\n");
+		ret = -EBUSY;
+		goto err_iounmap_i2s;
+	}
+	ret = request_irq(dev->play_irq, i2s_play_irq, 0, "spear13xx-i2s", dev);
+	if (ret) {
+		dev_err(&pdev->dev, "play IRQ%d already claimed\n",
+				dev->play_irq);
+		goto err_iounmap_i2s;
+	}
+
+	dev->capture_irq = platform_get_irq_byname(pdev, "record_irq");
+
+	if (!dev->capture_irq) {
+		dev_err(&pdev->dev, "record irq not defined\n");
+		ret = -EBUSY;
+		goto err_free_play_irq;
+	}
+
+	ret = request_irq(dev->capture_irq, i2s_capture_irq, 0, "spear13xx-i2s",
+			dev);
+	if (ret) {
+		dev_err(&pdev->dev, "capture IRQ%d already claimed\n",
+				dev->capture_irq);
+		goto err_free_play_irq;
+	}
+
+	dev->dev = &pdev->dev;
+	dev_set_drvdata(&pdev->dev, dev);
+
+	ret = snd_soc_register_dai(&pdev->dev, &spear13xx_i2s_dai);
+	if (ret != 0)
+		goto err_free_capture_irq;
+
+	/* unmask i2s interrupt for channel 0 */
+	i2s_write_reg(dev->i2s_base, IMR0, 0x00);
+
+	/* unmask i2s interrupt for channel 1 */
+	i2s_write_reg(dev->i2s_base, IMR1, 0x00);
+
+	return 0;
+
+err_free_capture_irq:
+	dev_set_drvdata(&pdev->dev, NULL);
+	free_irq(dev->capture_irq, pdev);
+err_free_play_irq:
+	free_irq(dev->play_irq, pdev);
+err_iounmap_i2s:
+	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 spear13xx_i2s_remove(struct platform_device *pdev)
+{
+	struct spear13xx_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	free_irq(dev->capture_irq, pdev);
+	free_irq(dev->play_irq, pdev);
+	iounmap(dev->i2s_base);
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	kfree(dev);
+	release_mem_region(dev->res->start, resource_size(dev->res));
+
+	return 0;
+}
+
+static struct platform_driver spear13xx_i2s_driver = {
+	.probe		= spear13xx_i2s_probe,
+	.remove		= spear13xx_i2s_remove,
+	.driver		= {
+		.name	= "spear13xx-i2s",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init spear13xx_i2s_init(void)
+{
+	return platform_driver_register(&spear13xx_i2s_driver);
+}
+module_init(spear13xx_i2s_init);
+
+static void __exit spear13xx_i2s_exit(void)
+{
+	platform_driver_unregister(&spear13xx_i2s_driver);
+}
+module_exit(spear13xx_i2s_exit);
+
+MODULE_AUTHOR("Rajeev Kumar");
+MODULE_DESCRIPTION("SPEAr I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spear13xx-i2s");
diff --git a/sound/soc/spear/spear13xx-i2s.h b/sound/soc/spear/spear13xx-i2s.h
new file mode 100644
index 0000000..26e2ea2
--- /dev/null
+++ b/sound/soc/spear/spear13xx-i2s.h
@@ -0,0 +1,19 @@
+/*
+ * ALSA SoC I2S Audio Layer for ST spear13xx processor
+ *
+ * sound/soc/spear/spear13xx-i2s.h
+ *
+ * Copyright (C) 2011 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_I2S_H
+#define SPEAR_I2S_H
+
+void get_dma_start_addr(struct snd_pcm_substream *substream);
+
+#endif /*end if i2s header file */
diff --git a/sound/soc/spear/spear13xx-pcm.c b/sound/soc/spear/spear13xx-pcm.c
new file mode 100644
index 0000000..8746ef7
--- /dev/null
+++ b/sound/soc/spear/spear13xx-pcm.c
@@ -0,0 +1,500 @@
+/*
+ * ALSA PCM interface for ST spear Processor
+ *
+ * sound/soc/spear/spear13xx-pcm.c
+ *
+ * Copyright (C) 2011 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/dma.h>
+#include "spear13xx-i2s.h"
+#include "spear13xx-pcm.h"
+
+static u64 spear13xx_pcm_dmamask = 0xffffffff;
+struct pcm_dma_data data;
+#define MAX_DMA_CHAIN		2
+
+struct snd_pcm_hardware spear13xx_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),
+	.formats = (SNDRV_PCM_FMTBIT_S16_LE),
+	.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+			SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			SNDRV_PCM_RATE_KNOT),
+	.rate_min = 8000,
+	.rate_max = 96000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.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 */
+};
+
+void pcm_init(struct device *dma_dev)
+{
+
+	data.mem2i2s_slave.dma_dev = dma_dev;
+	data.i2s2mem_slave.dma_dev = dma_dev;
+	/* doing 16 bit audio transfer */
+	data.mem2i2s_slave.reg_width = DW_DMA_SLAVE_WIDTH_16BIT;
+	data.mem2i2s_slave.cfg_hi = DWC_CFGH_DST_PER(DMA_REQ_I2S_TX);
+	data.mem2i2s_slave.cfg_lo = 0;
+	data.mem2i2s_slave.src_master = 1;
+	data.mem2i2s_slave.dst_master = 1;
+	data.mem2i2s_slave.src_msize = DW_DMA_MSIZE_16;
+	/* threshold for i2s is 7 */
+	data.mem2i2s_slave.dst_msize = DW_DMA_MSIZE_16;
+	data.mem2i2s_slave.fc = DW_DMA_FC_D_M2P;
+
+	data.i2s2mem_slave.reg_width = DW_DMA_SLAVE_WIDTH_16BIT;
+	data.i2s2mem_slave.cfg_hi = DWC_CFGH_SRC_PER(DMA_REQ_I2S_RX);
+	data.i2s2mem_slave.src_master = 1;
+	data.i2s2mem_slave.dst_master = 1;
+	data.i2s2mem_slave.src_msize = DW_DMA_MSIZE_16;
+	data.i2s2mem_slave.dst_msize = DW_DMA_MSIZE_16;
+	data.i2s2mem_slave.fc = DW_DMA_FC_D_P2M;
+	data.i2s2mem_slave.cfg_lo = 0;
+
+}
+
+static int spear13xx_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct spear13xx_runtime_data *prtd = runtime->private_data;
+	int ret;
+
+	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+	if (ret < 0)
+		return ret;
+
+	prtd->substream = substream;
+	prtd->pos = 0;
+	return 0;
+}
+
+static int spear13xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int spear13xx_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct spear13xx_runtime_data *prtd = runtime->private_data;
+
+	prtd->dma_addr = runtime->dma_addr;
+	prtd->buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+	prtd->period_bytes = snd_pcm_lib_period_bytes(substream);
+
+	if (prtd->buffer_bytes == prtd->period_bytes) {
+		prtd->frag_bytes = prtd->period_bytes >> 1;
+		prtd->frags = 2;
+	} else {
+		prtd->frag_bytes = prtd->period_bytes;
+		prtd->frags = prtd->buffer_bytes / prtd->period_bytes;
+	}
+	prtd->frag_count = 0;
+	prtd->pos = 0;
+	return 0;
+}
+
+static void spear13xx_dma_complete(void *arg)
+{
+	struct spear13xx_runtime_data *prtd = arg;
+	unsigned long flags;
+
+	/* dma completion handler cannot submit new operations */
+	spin_lock_irqsave(&prtd->lock, flags);
+	if (prtd->frag_count >= 0) {
+		prtd->dmacount--;
+		BUG_ON(prtd->dmacount < 0);
+		tasklet_schedule(&prtd->tasklet);
+	}
+	spin_unlock_irqrestore(&prtd->lock, flags);
+}
+
+static struct dma_async_tx_descriptor *
+spear13xx_dma_submit(struct spear13xx_runtime_data *prtd,
+		dma_addr_t buf_dma_addr)
+{
+	struct dma_chan *chan;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist sg;
+	struct snd_pcm_substream *substream = prtd->substream;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		chan = prtd->dma_chan[0];
+	else
+		chan = prtd->dma_chan[1];
+	sg_init_table(&sg, 1);
+	sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf_dma_addr)),
+			prtd->frag_bytes, buf_dma_addr & (PAGE_SIZE - 1));
+	sg_dma_address(&sg) = buf_dma_addr;
+	desc = chan->device->device_prep_slave_sg(chan, &sg, 1,
+			prtd->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE,
+			DMA_PREP_INTERRUPT);
+	if (!desc) {
+		dev_err(&chan->dev->device, "cannot prepare slave dma\n");
+		return NULL;
+	}
+	desc->callback = spear13xx_dma_complete;
+	desc->callback_param = prtd;
+	desc->tx_submit(desc);
+	return desc;
+}
+
+static void spear13xx_dma_tasklet(unsigned long data)
+{
+	struct spear13xx_runtime_data *prtd =
+		(struct spear13xx_runtime_data *)data;
+	struct dma_chan *chan;
+	struct dma_async_tx_descriptor *desc;
+	struct snd_pcm_substream *substream = prtd->substream;
+	int i;
+	unsigned long flags;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		chan = prtd->dma_chan[0];
+	else
+		chan = prtd->dma_chan[1];
+
+	spin_lock_irqsave(&prtd->lock, flags);
+
+	if (prtd->frag_count < 0) {
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+		/* first time */
+		for (i = 0; i < MAX_DMA_CHAIN; i++) {
+			desc = spear13xx_dma_submit(prtd,
+					prtd->dma_addr + i * prtd->frag_bytes);
+			if (!desc)
+				return;
+		}
+		prtd->dmacount = MAX_DMA_CHAIN;
+		chan->device->device_issue_pending(chan);
+		spin_lock_irqsave(&prtd->lock, flags);
+		prtd->frag_count = MAX_DMA_CHAIN % prtd->frags;
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		return;
+	}
+
+	while (prtd->dmacount < MAX_DMA_CHAIN) {
+		prtd->dmacount++;
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		desc = spear13xx_dma_submit(prtd,
+				prtd->dma_addr +
+				prtd->frag_count * prtd->frag_bytes);
+		if (!desc)
+			return;
+		chan->device->device_issue_pending(chan);
+
+		spin_lock_irqsave(&prtd->lock, flags);
+		prtd->frag_count++;
+		prtd->frag_count %= prtd->frags;
+		prtd->pos += prtd->frag_bytes;
+		prtd->pos %= prtd->buffer_bytes;
+		if ((prtd->frag_count * prtd->frag_bytes) %
+				prtd->period_bytes == 0)
+			snd_pcm_period_elapsed(substream);
+	}
+	spin_unlock_irqrestore(&prtd->lock, flags);
+}
+
+static int spear13xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		prtd->frag_count = -1;
+		tasklet_schedule(&prtd->tasklet);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static snd_pcm_uframes_t
+spear13xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
+
+	return bytes_to_frames(substream->runtime, prtd->pos);
+}
+
+static void dma_configure(struct snd_pcm_substream *substream)
+{
+	struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
+
+	dma_cap_zero(prtd->mask);
+	dma_cap_set(DMA_SLAVE, prtd->mask);
+
+	prtd->slaves = &data;
+	/* we need to pass physical address here */
+	prtd->slaves->mem2i2s_slave.tx_reg = (dma_addr_t)prtd->txdma;
+	prtd->slaves->mem2i2s_slave.rx_reg = 0;
+	prtd->slaves->i2s2mem_slave.tx_reg = 0;
+	prtd->slaves->i2s2mem_slave.rx_reg = (dma_addr_t)prtd->rxdma;
+
+	substream->runtime->private_data = prtd;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+	chan->private = slave;
+	return true;
+}
+
+static int spear13xx_pcm_dma_request(struct snd_pcm_substream *substream)
+{
+	struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		prtd->dma_chan[0] = dma_request_channel(prtd->mask, filter,
+				&prtd->slaves->mem2i2s_slave);
+		if (!prtd->dma_chan[0])
+			return -EAGAIN;
+	} else {
+		prtd->dma_chan[1] = dma_request_channel(prtd->mask, filter,
+				&prtd->slaves->i2s2mem_slave);
+		if (!prtd->dma_chan[1])
+			return -EAGAIN;
+
+	}
+	substream->runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int spear13xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct spear13xx_runtime_data *prtd;
+	int ret;
+
+	ret = snd_soc_set_runtime_hwparams(substream, &spear13xx_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 == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&prtd->lock);
+
+	substream->runtime->private_data = prtd;
+
+	get_dma_start_addr(substream);
+	dma_configure(substream);
+	ret = spear13xx_pcm_dma_request(substream);
+	if (ret) {
+		dev_err(&prtd->dev, "pcm:Failed to get dma channels\n");
+		kfree(prtd);
+
+	}
+
+	tasklet_init(&prtd->tasklet, spear13xx_dma_tasklet,
+			(unsigned long)prtd);
+
+	return 0;
+}
+
+static void dma_stop(struct snd_pcm_substream *substream)
+{
+	struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_release_channel(prtd->dma_chan[0]);
+	else
+		dma_release_channel(prtd->dma_chan[1]);
+
+}
+
+static int spear13xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct spear13xx_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];
+
+	prtd->frag_count = -1;
+	chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+	dma_stop(substream);
+	kfree(prtd);
+	return 0;
+}
+
+static int spear13xx_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 spear13xx_pcm_ops = {
+	.open		= spear13xx_pcm_open,
+	.close		= spear13xx_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= spear13xx_pcm_hw_params,
+	.hw_free	= spear13xx_pcm_hw_free,
+	.prepare	= spear13xx_pcm_prepare,
+	.trigger	= spear13xx_pcm_trigger,
+	.pointer	= spear13xx_pcm_pointer,
+	.mmap		= spear13xx_pcm_mmap,
+};
+
+static int
+spear13xx_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);
+	dev_dbg(buf->dev.dev,
+			" preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
+			(void *)buf->area, (void *)buf->addr, size);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	return 0;
+}
+
+static void spear13xx_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static int spear13xx_pcm_new(struct snd_card *card,
+		struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+	int ret;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &spear13xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->driver->playback.channels_min) {
+		ret = spear13xx_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_PLAYBACK,
+				spear13xx_pcm_hardware.buffer_bytes_max);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->driver->capture.channels_min) {
+		ret = spear13xx_pcm_preallocate_dma_buffer(pcm,
+				SNDRV_PCM_STREAM_CAPTURE,
+				spear13xx_pcm_hardware.buffer_bytes_max);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct snd_soc_platform_driver spear13xx_soc_platform = {
+	.ops		=	&spear13xx_pcm_ops,
+	.pcm_new	=	spear13xx_pcm_new,
+	.pcm_free	=	spear13xx_pcm_free,
+};
+
+static int __devinit spear13xx_soc_platform_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev, &spear13xx_soc_platform);
+}
+
+static int __devexit spear13xx_soc_platform_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver spear13xx_pcm_driver = {
+	.driver = {
+		.name = "spear-pcm-audio",
+		.owner = THIS_MODULE,
+	},
+
+	.probe = spear13xx_soc_platform_probe,
+	.remove = __devexit_p(spear13xx_soc_platform_remove),
+};
+
+static int __init snd_spear13xx_pcm_init(void)
+{
+	return platform_driver_register(&spear13xx_pcm_driver);
+}
+module_init(snd_spear13xx_pcm_init);
+
+static void __exit snd_spear13xx_pcm_exit(void)
+{
+	platform_driver_unregister(&spear13xx_pcm_driver);
+}
+module_exit(snd_spear13xx_pcm_exit);
+
+MODULE_AUTHOR("Rajeev Kumar");
+MODULE_DESCRIPTION("spear PCM DMA module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spear13xx-pcm");
diff --git a/sound/soc/spear/spear13xx-pcm.h b/sound/soc/spear/spear13xx-pcm.h
new file mode 100644
index 0000000..c5e0c74
--- /dev/null
+++ b/sound/soc/spear/spear13xx-pcm.h
@@ -0,0 +1,50 @@
+/*
+ * ALSA PCM interface for ST spear Processor
+ *
+ * sound/soc/spear/spear13xx-pcm.h
+ *
+ * Copyright (C) 2011 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
+
+#include <linux/dw_dmac.h>
+
+struct pcm_dma_data {
+	struct dw_dma_slave mem2i2s_slave;
+	struct dw_dma_slave i2s2mem_slave;
+};
+
+struct spear13xx_pcm_dma_params {
+	char *name;		/* stream identifier */
+	dma_addr_t dma_addr;	/* device physical address for DMA */
+};
+
+struct spear13xx_runtime_data {
+	struct device dev;
+	struct pcm_dma_data *slaves;
+	struct dma_chan *dma_chan[2];
+	struct tasklet_struct tasklet;
+	spinlock_t lock;
+	dma_addr_t txdma;
+	struct spear13xx_pcm_dma_params *params;	/* DMA params */
+	dma_addr_t rxdma;
+	dma_cap_mask_t mask;
+	int stream;
+	struct snd_pcm_substream *substream;
+	unsigned long pos;
+	dma_addr_t dma_addr;
+	unsigned long buffer_bytes;
+	unsigned long period_bytes;
+	unsigned long frag_bytes;
+	int frags;
+	int frag_count;
+	int dmacount;
+};
+#endif /* end of pcm header file */
-- 
1.6.0.2

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

* [PATCH V3 3/5] sound: asoc: Adding support for SPEAr13XX ASoC machine driver
  2011-04-11  5:30   ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Rajeev Kumar
@ 2011-04-11  5:30     ` Rajeev Kumar
  2011-04-11  5:30       ` [PATCH V3 4/5] sound: asoc: Adding Kconfig and Makefile to support SPEAr13XX ASoC driver Rajeev Kumar
  2011-04-11 13:00     ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Lu Guanqun
  1 sibling, 1 reply; 27+ messages in thread
From: Rajeev Kumar @ 2011-04-11  5:30 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, Rajeev Kumar, lrg

The patch adds support for SPEAr13XX machine driver.

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

diff --git a/sound/soc/spear/evb_sta529.c b/sound/soc/spear/evb_sta529.c
new file mode 100644
index 0000000..748efeb
--- /dev/null
+++ b/sound/soc/spear/evb_sta529.c
@@ -0,0 +1,103 @@
+/*
+ * ASoC machine driver for spear platform
+ *
+ * sound/soc/spear/evb_sta529.c
+ *
+ * Copyright (C) 2011 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/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+
+#include <mach/generic.h>
+#include <mach/misc_regs.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "spear13xx-i2s.h"
+#include "spear13xx-pcm.h"
+
+static int
+sta529_evb_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;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_CBS_CFM);
+
+	return ret;
+
+}
+
+static struct snd_soc_ops sta529_evb_ops = {
+	.hw_params	= sta529_evb_hw_params,
+};
+
+/* spear digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link evb_dai = {
+	.name		= "SPEARSTA529",
+	.stream_name	= "I2S Audio",
+	.cpu_dai_name	= "spear13xx-i2s.0",
+	.platform_name	= "spear-pcm-audio",
+	.codec_dai_name	= "sta529-audio",
+	.codec_name	= "sta529.0-001a",
+	.ops		= &sta529_evb_ops,
+};
+
+/* spear audio machine driver */
+static struct snd_soc_card snd_soc_evb = {
+	.name		= "sta529-codec",
+	.dai_link	= &evb_dai,
+	.num_links	= 1,
+};
+
+static struct platform_device *evb_snd_device;
+
+static int __init spear_init(void)
+{
+	int ret;
+
+	/* Create and register platform device */
+	evb_snd_device = platform_device_alloc("soc-audio", 0);
+	if (!evb_snd_device) {
+		printk(KERN_ERR "platform_device_alloc fails\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(evb_snd_device, &snd_soc_evb);
+	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_init);
+
+static void __exit spear_exit(void)
+{
+	platform_device_unregister(evb_snd_device);
+}
+module_exit(spear_exit);
+
+MODULE_AUTHOR("Rajeev Kumar");
+MODULE_DESCRIPTION("ST SPEAR EVB ASoC driver");
+MODULE_LICENSE("GPL");
-- 
1.6.0.2

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

* [PATCH V3 4/5] sound: asoc: Adding Kconfig and Makefile to support SPEAr13XX ASoC driver
  2011-04-11  5:30     ` [PATCH V3 3/5] sound: asoc: Adding support for SPEAr13XX ASoC machine driver Rajeev Kumar
@ 2011-04-11  5:30       ` Rajeev Kumar
  2011-04-11  5:30         ` [PATCH V3 5/5] sound: asoc: Adding support for SPEAr13XX in soc Rajeev Kumar
  0 siblings, 1 reply; 27+ messages in thread
From: Rajeev Kumar @ 2011-04-11  5:30 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, Rajeev Kumar, lrg

This patch adds Kconfig and Makefile to support SPEAr13XX ASoC driver

Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
---
 sound/soc/spear/Kconfig  |   19 +++++++++++++++++++
 sound/soc/spear/Makefile |   12 ++++++++++++
 2 files changed, 31 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..666f95f
--- /dev/null
+++ b/sound/soc/spear/Kconfig
@@ -0,0 +1,19 @@
+config SND_SOC_SPEAR_PCM
+	tristate "SoC Audio for the ST chip"
+	help
+	 Say Y or M if you want to add support for codecs attached to
+	 the I2S interface. You will also need
+	 to select the audio interfaces to support below.
+
+config SND_SOC_SPEAR_I2S
+	tristate
+
+config SND_SOC_SPEAR_EVM
+	tristate "SoC Audio support for Spear EVM"
+	depends on SND_SOC_SPEAR_PCM
+	select SND_SOC_SPEAR_I2S
+	select SND_SOC_STA529
+	help
+	 A driver for the EVM machine.
+	 Say Y if you want to select audio on ST SPEAR board
+
diff --git a/sound/soc/spear/Makefile b/sound/soc/spear/Makefile
new file mode 100644
index 0000000..cc0972e
--- /dev/null
+++ b/sound/soc/spear/Makefile
@@ -0,0 +1,12 @@
+# SPEAR Platform Support
+snd-soc-pcm-objs := spear13xx-pcm.o
+snd-soc-i2s-objs := spear13xx-i2s.o
+
+obj-$(CONFIG_SND_SOC_SPEAR_PCM) += snd-soc-pcm.o
+obj-$(CONFIG_SND_SOC_SPEAR_I2S) += snd-soc-i2s.o
+
+# SPEAR Machine Support
+snd-soc-evb-objs := evb_sta529.o
+
+obj-$(CONFIG_SND_SOC_SPEAR_EVM) += snd-soc-evb.o
+
-- 
1.6.0.2

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

* [PATCH V3 5/5] sound: asoc: Adding support for SPEAr13XX in soc
  2011-04-11  5:30       ` [PATCH V3 4/5] sound: asoc: Adding Kconfig and Makefile to support SPEAr13XX ASoC driver Rajeev Kumar
@ 2011-04-11  5:30         ` Rajeev Kumar
  0 siblings, 0 replies; 27+ messages in thread
From: Rajeev Kumar @ 2011-04-11  5:30 UTC (permalink / raw)
  To: tiwai, broonie, perex; +Cc: alsa-devel, Rajeev Kumar, lrg

This patch adds the SPEAr13XX support by updating the Kconfig and Makefile
present in soc directory

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 8224db5..31cceca 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -55,6 +55,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 1ed61c5..dd9c624 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -18,5 +18,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.6.0.2

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11  5:30 ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Rajeev Kumar
  2011-04-11  5:30   ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Rajeev Kumar
@ 2011-04-11 12:53   ` Lu Guanqun
  2011-04-11 13:35     ` Mark Brown
  2011-04-11 14:56   ` Mark Brown
  2011-04-11 15:45   ` Lu Guanqun
  3 siblings, 1 reply; 27+ messages in thread
From: Lu Guanqun @ 2011-04-11 12:53 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, broonie, lrg

On Mon, Apr 11, 2011 at 01:30:00PM +0800, 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
> 
> 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 |  383 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 390 insertions(+), 0 deletions(-)
>  create mode 100644 sound/soc/codecs/sta529.c
> 
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index b814ed0..d536740 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -40,6 +40,7 @@ config SND_SOC_ALL_CODECS
>         select SND_SOC_SN95031 if INTEL_SCU_IPC
>         select SND_SOC_SPDIF
>         select SND_SOC_SSM2602 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
> @@ -206,6 +207,10 @@ config SND_SOC_SPDIF
>  config SND_SOC_SSM2602
>         tristate
> 
> +config SND_SOC_STA529
> +       tristate
> +       depends on I2C

I see many drivers depend on I2C, but they don't add the line above. Any
reasons for it?

> +
>  config SND_SOC_STAC9766
>         tristate
> 
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 49121ad..f889ef5 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -26,6 +26,7 @@ snd-soc-alc5623-objs := alc5623.o
>  snd-soc-sn95031-objs := sn95031.o
>  snd-soc-spdif-objs := spdif_transciever.o
>  snd-soc-ssm2602-objs := ssm2602.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
> @@ -114,6 +115,7 @@ obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
>  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_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..8dda5cd
> --- /dev/null
> +++ b/sound/soc/codecs/sta529.c
> @@ -0,0 +1,383 @@
> +/*
> + * ASoC codec driver for spear platform
> + *
> + * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver
> + *
> + * Copyright (C) 2011 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_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] = {
> +       0x75, 0xf8, 0x50, 0x00,
> +       0x00, 0x00, 0x02, 0x00,
> +       0x02, 0x02, 0xD2, 0x91,
> +       0xD3, 0x91, 0x00, 0x00,
> +       0x00, 0x00, 0x00, 0x00,
> +       0x00, 0x00, 0x00, 0x00,
> +       0x80, 0x00, 0x00, 0x00,
> +       0x00, 0x00, 0x52, 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 *op_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, op_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_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 = 0;
> +
> +       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;
> +       }
> +       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +               snd_soc_update_bits(codec, STA529_S2PCFG1, 0xB0, pdata);
> +       else
> +               snd_soc_update_bits(codec, STA529_P2SCFG1, 0xB0, pdata);
> +
> +       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 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_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->bias_level = level;
> +       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;
> +
> +       codec->hw_write = (hw_write_t)i2c_master_send;
> +       codec->hw_read = NULL;
> +       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)
> +{
> +       int i;
> +       u8 data[2];
> +       u8 *cache = codec->reg_cache;
> +
> +       for (i = 0; i < ARRAY_SIZE(sta529_reg); i++) {
> +               data[0] = i;
> +               data[1] = cache[i];
> +               codec->hw_write(codec->control_data, data, 2);
> +       }
> +
> +       sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
> +       sta529_set_bias_level(codec, codec->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);

As an idiom, I often see the above code surrounded with an #ifdef, see
below code snippet from sound/soc/codecs/wm8974.c

static int __init wm8974_modinit(void)
{
        int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8974_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
                       ret);
        }
#endif
        return ret;
}

Maybe you should add the simlar structure as well.

> +       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.6.0.2
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

-- 
guanqun

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

* Re: [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver
  2011-04-11  5:30   ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Rajeev Kumar
  2011-04-11  5:30     ` [PATCH V3 3/5] sound: asoc: Adding support for SPEAr13XX ASoC machine driver Rajeev Kumar
@ 2011-04-11 13:00     ` Lu Guanqun
  2011-04-18  5:00       ` rajeev
  1 sibling, 1 reply; 27+ messages in thread
From: Lu Guanqun @ 2011-04-11 13:00 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, broonie, lrg

On Mon, Apr 11, 2011 at 01:30:01PM +0800, Rajeev Kumar wrote:
> This patch adds the support for the SPEAr13XX Platform Driver (I2S based)
> as per the ASoC framework.
> 
> SPEAr13XX internally uses a Designware I2S IP and some glue logic on top
> of the same.
> 
> Signed-off-by: Rajeev Kumar <rajeev-dlh.kumar@st.com>
> ---
>  sound/soc/spear/spear13xx-i2s.c |  523 +++++++++++++++++++++++++++++++++++++++
>  sound/soc/spear/spear13xx-i2s.h |   19 ++
>  sound/soc/spear/spear13xx-pcm.c |  500 +++++++++++++++++++++++++++++++++++++
>  sound/soc/spear/spear13xx-pcm.h |   50 ++++
>  4 files changed, 1092 insertions(+), 0 deletions(-)
>  create mode 100644 sound/soc/spear/spear13xx-i2s.c
>  create mode 100644 sound/soc/spear/spear13xx-i2s.h
>  create mode 100644 sound/soc/spear/spear13xx-pcm.c
>  create mode 100644 sound/soc/spear/spear13xx-pcm.h
> 
> diff --git a/sound/soc/spear/spear13xx-i2s.c b/sound/soc/spear/spear13xx-i2s.c
> new file mode 100644
> index 0000000..33d2d11
> --- /dev/null
> +++ b/sound/soc/spear/spear13xx-i2s.c
> @@ -0,0 +1,523 @@
> +/*
> + * ALSA SoC I2S Audio Layer for ST spear13xx processor
> + *
> + * sound/soc/spear/spear13xx-i2s.c
> + *
> + * Copyright (C) 2011 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/device.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <mach/misc_regs.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/core.h>
> +#include <sound/initval.h>
> +#include <sound/soc.h>
> +#include "spear13xx-pcm.h"
> +#include "spear13xx-i2s.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 channel 0 */
> +#define LRBR0_LTHR0    0x020
> +#define RRBR0_RTHR0    0x024
> +#define RER0           0x028
> +#define TER0           0x02C
> +#define RCR0           0x030
> +#define TCR0           0x034
> +#define ISR0           0x038
> +#define IMR0           0x03C
> +#define ROR0           0x040
> +#define TOR0           0x044
> +#define RFCR0          0x048
> +#define TFCR0          0x04C
> +#define RFF0           0x050
> +#define TFF0           0x054
> +
> +/* I2STxRxRegisters for channel 1 */
> +#define LRBR1_LTHR1    0x060
> +#define RRBR1_RTHR1    0x064
> +#define RER1           0x068
> +#define TER1           0x06C
> +#define RCR1           0x070
> +#define TCR1           0x074
> +#define ISR1           0x078
> +#define IMR1           0x07C
> +#define ROR1           0x080
> +#define TOR1           0x084
> +#define RFCR1          0x088
> +#define TFCR1          0x08C
> +#define RFF1           0x090
> +#define TFF1           0x094
> +
> +/* I2STxRxRegisters for channel 2 */
> +#define LRBR2_LTHR2    0x0A0
> +#define RRBR2_RTHR2    0x0A4
> +#define RER2           0x0A8
> +#define TER2           0x0AC
> +#define RCR2           0x0B0
> +#define TCR2           0x0B4
> +#define ISR2           0x0B8
> +#define IMR2           0x0BC
> +#define ROR2           0x0C0
> +#define TOR2           0x0C4
> +#define RFCR2          0x0C8
> +#define TFCR2          0x0CC
> +#define RFF2           0x0D0
> +#define TFF2           0x0D4
> +
> +/* I2STxRxRegisters for channel 3*/
> +#define LRBR3_LTHR3    0x0E0
> +#define RRBR3_RTHR3    0x0E4
> +#define RER3           0x0E8
> +#define TER3           0x0EC
> +#define RCR3           0x0F0
> +#define TCR3           0x0F4
> +#define ISR3           0x0F8
> +#define IMR3           0x0FC
> +#define ROR3           0x100
> +#define TOR3           0x104
> +#define RFCR3          0x108
> +#define TFCR3          0x10C
> +#define RFF3           0x110
> +#define TFF3           0x114
> +
> +/* I2SDMARegisters */
> +#define RXDMA          0x01C0
> +#define RRXDMA         0x01C4
> +#define TXDMA          0x01C8
> +#define RTXDMA         0x01CC
> +
> +/* I2SCOMPRegisters */
> +#define I2S_COMP_PARAM_2       0x01F0
> +#define I2S_COMP_PARAM_1       0x01F4
> +#define I2S_COMP_VERSION       0x01F8
> +#define I2S_COMP_TYPE          0x01FC
> +
> +#define SPEAR13XX_I2S_RATES    SNDRV_PCM_RATE_8000_96000
> +#define SPEAR13XX_I2S_FORMAT   SNDRV_PCM_FMTBIT_S16_LE
> +#define MAX_CHANNEL_NUM                2
> +#define MIN_CHANNEL_NUM                2
> +
> +struct spear13xx_i2s_dev {
> +       void __iomem *i2s_base;
> +       struct resource *res;
> +       struct clk *clk;
> +       int play_irq;
> +       int mode;
> +       int active;
> +       int capture_irq;
> +       struct device *dev;
> +       struct spear13xx_pcm_dma_params *dma_params[2];
> +};
> +
> +void get_dma_start_addr(struct snd_pcm_substream *substream)
> +{
> +       struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +       struct spear13xx_runtime_data *prtd = substream->runtime->private_data;
> +       struct spear13xx_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
> +
> +       prtd->txdma = dev->res->start + TXDMA;
> +       prtd->rxdma = dev->res->start + RXDMA;
> +
> +       substream->runtime->private_data = prtd;
> +}
> +
> +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 void i2s_start_play(struct spear13xx_i2s_dev *dev,
> +               struct snd_pcm_substream *substream)
> +{
> +       u32 val; /*dma mode slection*/
> +
> +       val = readl(PERIP_CFG);
> +       val &= ~0xFFFFFFFC;
> +       i2s_write_reg(dev->i2s_base, TER0, 0);
> +       i2s_write_reg(dev->i2s_base, TER1, 0);
> +
> +       /* for 2.0 audio*/
> +       if (dev->mode <= 2) {
> +               if (!val) {
> +                       i2s_write_reg(dev->i2s_base, TCR0, 0x2);
> +                       i2s_write_reg(dev->i2s_base, TFCR0, 0x07);
> +                       i2s_write_reg(dev->i2s_base, IMR0, 0x00);
> +                       i2s_write_reg(dev->i2s_base, TER0, 1);
> +               } else {
> +                       i2s_write_reg(dev->i2s_base, TCR1, 0x2);
> +                       i2s_write_reg(dev->i2s_base, TFCR1, 0x07);
> +                       i2s_write_reg(dev->i2s_base, IMR1, 0x00);
> +                       i2s_write_reg(dev->i2s_base, TER1, 1);
> +               }
> +       } else { /*audio 2.0 onwards */
> +               i2s_write_reg(dev->i2s_base, TCR0, 0x5);
> +               i2s_write_reg(dev->i2s_base, TCR1, 0x5);
> +
> +               i2s_write_reg(dev->i2s_base, TFCR0, 0x07);
> +               i2s_write_reg(dev->i2s_base, TFCR1, 0x07);
> +               i2s_write_reg(dev->i2s_base, IMR0, 0x00);
> +               i2s_write_reg(dev->i2s_base, IMR1, 0x00);
> +               i2s_write_reg(dev->i2s_base, TER0, 1);
> +               i2s_write_reg(dev->i2s_base, TER1, 1);
> +       }
> +
> +       i2s_write_reg(dev->i2s_base, ITER, 1);
> +}
> +
> +static void i2s_start_rec(struct spear13xx_i2s_dev *dev,
> +               struct snd_pcm_substream *substream)
> +{
> +       u32 val; /*dma mode slection*/
> +
> +       val = readl(PERIP_CFG);
> +       val &= ~0xFFFFFFFC;
> +       i2s_write_reg(dev->i2s_base, RER0, 0);
> +       i2s_write_reg(dev->i2s_base, RER1, 0);
> +
> +       /* for 2.0 audio*/
> +       if (dev->mode <= 2) {
> +               if (!val) {
> +                       i2s_write_reg(dev->i2s_base, RCR0, 0x2);
> +                       i2s_write_reg(dev->i2s_base, RFCR0, 0x07);
> +                       i2s_write_reg(dev->i2s_base, IMR0, 0x00);
> +                       i2s_write_reg(dev->i2s_base, RER0, 1);
> +               } else {
> +                       i2s_write_reg(dev->i2s_base, RCR1, 0x2);
> +                       i2s_write_reg(dev->i2s_base, RFCR1, 0x07);
> +                       i2s_write_reg(dev->i2s_base, IMR1, 0x00);
> +                       i2s_write_reg(dev->i2s_base, TER1, 1);
> +               }
> +       } else { /*audio 2.0 onwards */
> +               i2s_write_reg(dev->i2s_base, RCR0, 0x5);
> +               i2s_write_reg(dev->i2s_base, RCR1, 0x5);
> +
> +               i2s_write_reg(dev->i2s_base, RFCR0, 0x07);
> +               i2s_write_reg(dev->i2s_base, RFCR1, 0x07);
> +               i2s_write_reg(dev->i2s_base, IMR0, 0x00);
> +               i2s_write_reg(dev->i2s_base, IMR1, 0x00);
> +               i2s_write_reg(dev->i2s_base, RER0, 1);
> +               i2s_write_reg(dev->i2s_base, RER1, 1);
> +       }
> +
> +       i2s_write_reg(dev->i2s_base, IRER, 1);
> +}
> +
> +static void i2s_stop(struct spear13xx_i2s_dev *dev,
> +               struct snd_pcm_substream *substream)
> +{
> +       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +               i2s_write_reg(dev->i2s_base, ITER, 0);
> +               i2s_write_reg(dev->i2s_base, ITER, 1);
> +               i2s_write_reg(dev->i2s_base, IMR0, 0x30);
> +               i2s_write_reg(dev->i2s_base, IMR1, 0x30);
> +       } else {
> +               i2s_write_reg(dev->i2s_base, IRER, 0);
> +               i2s_write_reg(dev->i2s_base, IRER, 1);
> +               i2s_write_reg(dev->i2s_base, IMR0, 0x03);
> +               i2s_write_reg(dev->i2s_base, IMR1, 0x03);
> +       }
> +       if (!dev->active--) {
> +               i2s_write_reg(dev->i2s_base, CER, 0);
> +               i2s_write_reg(dev->i2s_base, IER, 0);
> +               dev->active = 0;
> +       }
> +
> +}
> +
> +static irqreturn_t i2s_play_irq(int irq, void *_dev)
> +{
> +       struct spear13xx_i2s_dev *dev = (struct spear13xx_i2s_dev *)_dev;
> +       u32 ch0, ch1;
> +
> +       /* check for the tx data overrun condition */
> +       ch0 = i2s_read_reg(dev->i2s_base, ISR0) & 0x20;
> +       ch1 = i2s_read_reg(dev->i2s_base, ISR1) & 0x20;
> +       if (ch0 || ch1) {
> +
> +               /* 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: channel 0 */
> +               i2s_read_reg(dev->i2s_base, TOR0);
> +
> +               /* clear tx data overrun interrupt: channel 1 */
> +               i2s_read_reg(dev->i2s_base, TOR1);
> +
> +       }
> +
> +       return IRQ_HANDLED;
> +}

I remember Mark had some comments on adding some logs when it's overrun,
how do you think?

-- 
guanqun

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11 12:53   ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Lu Guanqun
@ 2011-04-11 13:35     ` Mark Brown
  2011-04-11 15:09       ` Lu Guanqun
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2011-04-11 13:35 UTC (permalink / raw)
  To: Lu Guanqun; +Cc: tiwai, alsa-devel, Rajeev Kumar, lrg

On Mon, Apr 11, 2011 at 08:53:18PM +0800, Lu Guanqun wrote:

Please *always* delete irrelevant context from replies - it makes it
much easier to find the new text.

> On Mon, Apr 11, 2011 at 01:30:00PM +0800, Rajeev Kumar wrote:

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

> I see many drivers depend on I2C, but they don't add the line above. Any
> reasons for it?

It won't actually do anything - select ignores depends.

> > +static int __init sta529_modinit(void)
> > +{
> > +       int ret = 0;
> > +
> > +       ret = i2c_add_driver(&sta529_i2c_driver);
> 
> As an idiom, I often see the above code surrounded with an #ifdef, see
> below code snippet from sound/soc/codecs/wm8974.c

This is only for devices that support more than one control interface.
If the device only supports one control interface there is no need to
make anything conditional.

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11  5:30 ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Rajeev Kumar
  2011-04-11  5:30   ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Rajeev Kumar
  2011-04-11 12:53   ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Lu Guanqun
@ 2011-04-11 14:56   ` Mark Brown
  2011-04-14  9:54     ` Takashi Iwai
  2011-04-20  4:24     ` rajeev
  2011-04-11 15:45   ` Lu Guanqun
  3 siblings, 2 replies; 27+ messages in thread
From: Mark Brown @ 2011-04-11 14:56 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, lrg

On Mon, Apr 11, 2011 at 11:00:00AM +0530, Rajeev Kumar wrote:

> +static const char *op_mode_text[] = { "slave", "master"};

What is op_mode?  This sounds like it should be configured by
set_dai_fmt()...

> +static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
> +	SOC_ENUM("pwm select", pwm_src_enum),
> +	SOC_ENUM("mode select", mode_src_enum),
> +};

ALSA control names are idiomatically things like "PWM Select" with
capitalisation.

> +	/*store the label for powers down audio subsystem for suspend.This is
> +	 ** used by soc core layer*/
> +	codec->bias_level = level;

The formatting of this comment isn't terribly idiomatic.

> +static int sta529_probe(struct snd_soc_codec *codec)
> +{
> +	struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
> +	int ret;
> +
> +	codec->hw_write = (hw_write_t)i2c_master_send;
> +	codec->hw_read = NULL;
> +	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;
> +	}

You shouldn't need to be assigning the I/O functions if you set the
control type.  If the device only supports I2C that can just be hard
coded.

> +static int sta529_resume(struct snd_soc_codec *codec)
> +{
> +	int i;
> +	u8 data[2];
> +	u8 *cache = codec->reg_cache;
> +
> +	for (i = 0; i < ARRAY_SIZE(sta529_reg); i++) {
> +		data[0] = i;
> +		data[1] = cache[i];
> +		codec->hw_write(codec->control_data, data, 2);
> +	}

It looks like you can use the standard cache sync implementation here?
snd_soc_cache_sync().

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11 13:35     ` Mark Brown
@ 2011-04-11 15:09       ` Lu Guanqun
  2011-04-11 23:54         ` Mark Brown
  0 siblings, 1 reply; 27+ messages in thread
From: Lu Guanqun @ 2011-04-11 15:09 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, Rajeev Kumar, lrg

On Mon, Apr 11, 2011 at 09:35:01PM +0800, Mark Brown wrote:
> On Mon, Apr 11, 2011 at 08:53:18PM +0800, Lu Guanqun wrote:
> 
> Please *always* delete irrelevant context from replies - it makes it
> much easier to find the new text.

Sure.

> > > +static int __init sta529_modinit(void)
> > > +{
> > > +       int ret = 0;
> > > +
> > > +       ret = i2c_add_driver(&sta529_i2c_driver);
> > 
> > As an idiom, I often see the above code surrounded with an #ifdef, see
> > below code snippet from sound/soc/codecs/wm8974.c
> 
> This is only for devices that support more than one control interface.
> If the device only supports one control interface there is no need to
> make anything conditional.

Well, but there are many codecs which support only one control interface
while having this #ifdef condition...

-- 
guanqun

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11  5:30 ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Rajeev Kumar
                     ` (2 preceding siblings ...)
  2011-04-11 14:56   ` Mark Brown
@ 2011-04-11 15:45   ` Lu Guanqun
  3 siblings, 0 replies; 27+ messages in thread
From: Lu Guanqun @ 2011-04-11 15:45 UTC (permalink / raw)
  To: Rajeev Kumar; +Cc: tiwai, alsa-devel, broonie, lrg

On Mon, Apr 11, 2011 at 01:30:00PM +0800, Rajeev Kumar wrote:
> +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 = 0;
> +
> +       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;
> +       }
> +       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +               snd_soc_update_bits(codec, STA529_S2PCFG1, 0xB0, pdata);
> +       else
> +               snd_soc_update_bits(codec, STA529_P2SCFG1, 0xB0, pdata);

Hi,

Reading the spec, the bit 7 and bit 6 of these two registers are related
to the length of data.

While from your code, you're masking bit 10110000, which is weird.
Shouldn't it be 0xC0?

Besides, the value to snd_soc_update_bits should be shifted accordingly.
So the improved one should be something like this:
	snd_soc_update_bits(codec, STA529_P2SCFG1, 0xC0, (pdata << 6));

-- 
guanqun

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11 15:09       ` Lu Guanqun
@ 2011-04-11 23:54         ` Mark Brown
  2011-04-12  0:06           ` Lu Guanqun
  0 siblings, 1 reply; 27+ messages in thread
From: Mark Brown @ 2011-04-11 23:54 UTC (permalink / raw)
  To: Lu Guanqun; +Cc: tiwai, alsa-devel, Rajeev Kumar, lrg

On Mon, Apr 11, 2011 at 11:09:37PM +0800, Lu Guanqun wrote:
> On Mon, Apr 11, 2011 at 09:35:01PM +0800, Mark Brown wrote:

> > This is only for devices that support more than one control interface.
> > If the device only supports one control interface there is no need to
> > make anything conditional.

> Well, but there are many codecs which support only one control interface
> while having this #ifdef condition...

Usually you'll find that these are devices which support multiple
control interfaces but where the driver has only implemented one so far
for some reason.

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11 23:54         ` Mark Brown
@ 2011-04-12  0:06           ` Lu Guanqun
  0 siblings, 0 replies; 27+ messages in thread
From: Lu Guanqun @ 2011-04-12  0:06 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, Rajeev Kumar, lrg

On Tue, Apr 12, 2011 at 07:54:20AM +0800, Mark Brown wrote:
> On Mon, Apr 11, 2011 at 11:09:37PM +0800, Lu Guanqun wrote:
> > On Mon, Apr 11, 2011 at 09:35:01PM +0800, Mark Brown wrote:
> 
> > > This is only for devices that support more than one control interface.
> > > If the device only supports one control interface there is no need to
> > > make anything conditional.
> 
> > Well, but there are many codecs which support only one control interface
> > while having this #ifdef condition...
> 
> Usually you'll find that these are devices which support multiple
> control interfaces but where the driver has only implemented one so far
> for some reason.

OK. Thanks for the explanation.

-- 
guanqun

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11 14:56   ` Mark Brown
@ 2011-04-14  9:54     ` Takashi Iwai
  2011-04-14 12:18       ` Mark Brown
  2011-04-14 14:19       ` Lu Guanqun
  2011-04-20  4:24     ` rajeev
  1 sibling, 2 replies; 27+ messages in thread
From: Takashi Iwai @ 2011-04-14  9:54 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Rajeev Kumar, lrg

At Mon, 11 Apr 2011 07:56:22 -0700,
Mark Brown wrote:
> 
> > +static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
> > +	SOC_ENUM("pwm select", pwm_src_enum),
> > +	SOC_ENUM("mode select", mode_src_enum),
> > +};
> 
> ALSA control names are idiomatically things like "PWM Select" with
> capitalisation.

Actually, the capital words are no mandatory requirement (although
it's conventionally so).  It's just alsa-mixer grouping rule that
requires the capital words "Play", "Capture", "Volume", "Switch",
etc.

You don't have to obey Capitalism :)


Takashi

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-14  9:54     ` Takashi Iwai
@ 2011-04-14 12:18       ` Mark Brown
  2011-04-14 12:25         ` Takashi Iwai
  2011-04-14 14:19       ` Lu Guanqun
  1 sibling, 1 reply; 27+ messages in thread
From: Mark Brown @ 2011-04-14 12:18 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Rajeev Kumar, lrg

On Thu, Apr 14, 2011 at 11:54:11AM +0200, Takashi Iwai wrote:
> Mark Brown wrote:

> > ALSA control names are idiomatically things like "PWM Select" with
> > capitalisation.

> Actually, the capital words are no mandatory requirement (although
> it's conventionally so).  It's just alsa-mixer grouping rule that
> requires the capital words "Play", "Capture", "Volume", "Switch",
> etc.

Right, but they generally are hence idiomatically (as opposed to having
a technical requirement).

> You don't have to obey Capitalism :)

But the UIs tend to look neater if you do.

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-14 12:18       ` Mark Brown
@ 2011-04-14 12:25         ` Takashi Iwai
  0 siblings, 0 replies; 27+ messages in thread
From: Takashi Iwai @ 2011-04-14 12:25 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, Rajeev Kumar, lrg

At Thu, 14 Apr 2011 05:18:47 -0700,
Mark Brown wrote:
> 
> On Thu, Apr 14, 2011 at 11:54:11AM +0200, Takashi Iwai wrote:
> > Mark Brown wrote:
> 
> > > ALSA control names are idiomatically things like "PWM Select" with
> > > capitalisation.
> 
> > Actually, the capital words are no mandatory requirement (although
> > it's conventionally so).  It's just alsa-mixer grouping rule that
> > requires the capital words "Play", "Capture", "Volume", "Switch",
> > etc.
> 
> Right, but they generally are hence idiomatically (as opposed to having
> a technical requirement).

Sure.

> > You don't have to obey Capitalism :)
> 
> But the UIs tend to look neater if you do.

De facto standard in the world is Capitalism, of course.
(Heh, don't take it seriously.  My post is just a silly spinal reflex :)


Takashi

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-14  9:54     ` Takashi Iwai
  2011-04-14 12:18       ` Mark Brown
@ 2011-04-14 14:19       ` Lu Guanqun
  2011-04-14 14:28         ` Lu Guanqun
  2011-04-15  9:23         ` Takashi Iwai
  1 sibling, 2 replies; 27+ messages in thread
From: Lu Guanqun @ 2011-04-14 14:19 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Mark Brown, Rajeev Kumar, lrg

On Thu, Apr 14, 2011 at 05:54:11PM +0800, Takashi Iwai wrote:
> At Mon, 11 Apr 2011 07:56:22 -0700,
> Mark Brown wrote:
> > 
> > > +static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
> > > +	SOC_ENUM("pwm select", pwm_src_enum),
> > > +	SOC_ENUM("mode select", mode_src_enum),
> > > +};
> > 
> > ALSA control names are idiomatically things like "PWM Select" with
> > capitalisation.
> 
> Actually, the capital words are no mandatory requirement (although
> it's conventionally so).  It's just alsa-mixer grouping rule that
> requires the capital words "Play", "Capture", "Volume", "Switch",
> etc.

Hi Takashi,

Where can I find these alsa-mixer grouping rule?
So that I can obey these rules and make them appear in the right view in
alsamixer.

> 
> You don't have to obey Capitalism :)
> 
> 
> Takashi
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

-- 
guanqun

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-14 14:19       ` Lu Guanqun
@ 2011-04-14 14:28         ` Lu Guanqun
  2011-04-15  9:27           ` Takashi Iwai
  2011-04-15  9:23         ` Takashi Iwai
  1 sibling, 1 reply; 27+ messages in thread
From: Lu Guanqun @ 2011-04-14 14:28 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Mark Brown, Rajeev Kumar, lrg

On Thu, Apr 14, 2011 at 10:19:36PM +0800, Lu Guanqun wrote:
> On Thu, Apr 14, 2011 at 05:54:11PM +0800, Takashi Iwai wrote:
> > At Mon, 11 Apr 2011 07:56:22 -0700,
> > Mark Brown wrote:
> > > 
> > > > +static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
> > > > +	SOC_ENUM("pwm select", pwm_src_enum),
> > > > +	SOC_ENUM("mode select", mode_src_enum),
> > > > +};
> > > 
> > > ALSA control names are idiomatically things like "PWM Select" with
> > > capitalisation.
> > 
> > Actually, the capital words are no mandatory requirement (although
> > it's conventionally so).  It's just alsa-mixer grouping rule that
> > requires the capital words "Play", "Capture", "Volume", "Switch",
> > etc.
> 
> Hi Takashi,
> 
> Where can I find these alsa-mixer grouping rule?
> So that I can obey these rules and make them appear in the right view in
> alsamixer.

Hi Takashi,

I'm reading this comment from file `sound/aoa/codecs/tas.c`:

        /* If we name this 'Input Source', it properly shows up in
         * alsamixer as a selection, * but it's shown under the
         * 'Playback' category.
         * If I name it 'Capture Source', it shows up in strange
         * ways (two bools of which one can be selected at a
         * time) but at least it's shown in the 'Capture'
         * category.
         * I was told that this was due to backward compatibility,
         * but I don't understand then why the mangling is *not*
         * done when I name it "Input Source".....
         */

I'm wondering what's the story behind? Can you shed some lights?

> 
> > 
> > You don't have to obey Capitalism :)
> > 
> > 
> > Takashi
> > _______________________________________________
> > Alsa-devel mailing list
> > Alsa-devel@alsa-project.org
> > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 
> -- 
> guanqun
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

-- 
guanqun

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-14 14:19       ` Lu Guanqun
  2011-04-14 14:28         ` Lu Guanqun
@ 2011-04-15  9:23         ` Takashi Iwai
  1 sibling, 0 replies; 27+ messages in thread
From: Takashi Iwai @ 2011-04-15  9:23 UTC (permalink / raw)
  To: Lu Guanqun; +Cc: alsa-devel, Mark Brown, Rajeev Kumar, lrg

At Thu, 14 Apr 2011 22:19:36 +0800,
Lu Guanqun wrote:
> 
> On Thu, Apr 14, 2011 at 05:54:11PM +0800, Takashi Iwai wrote:
> > At Mon, 11 Apr 2011 07:56:22 -0700,
> > Mark Brown wrote:
> > > 
> > > > +static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
> > > > +	SOC_ENUM("pwm select", pwm_src_enum),
> > > > +	SOC_ENUM("mode select", mode_src_enum),
> > > > +};
> > > 
> > > ALSA control names are idiomatically things like "PWM Select" with
> > > capitalisation.
> > 
> > Actually, the capital words are no mandatory requirement (although
> > it's conventionally so).  It's just alsa-mixer grouping rule that
> > requires the capital words "Play", "Capture", "Volume", "Switch",
> > etc.
> 
> Hi Takashi,
> 
> Where can I find these alsa-mixer grouping rule?

See Documentation/sound/alsa/ControlNames.txt.  It's old but still
valid in most cases.

Since then there are a few additions and exceptions.  "Input Source"
control is one of them.  Also, "Enum" is now also a function word.


Takashi

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-14 14:28         ` Lu Guanqun
@ 2011-04-15  9:27           ` Takashi Iwai
  2011-04-15 14:10             ` Lu Guanqun
  0 siblings, 1 reply; 27+ messages in thread
From: Takashi Iwai @ 2011-04-15  9:27 UTC (permalink / raw)
  To: Lu Guanqun; +Cc: alsa-devel, Mark Brown, Rajeev Kumar, lrg

At Thu, 14 Apr 2011 22:28:45 +0800,
Lu Guanqun wrote:
> 
> On Thu, Apr 14, 2011 at 10:19:36PM +0800, Lu Guanqun wrote:
> > On Thu, Apr 14, 2011 at 05:54:11PM +0800, Takashi Iwai wrote:
> > > At Mon, 11 Apr 2011 07:56:22 -0700,
> > > Mark Brown wrote:
> > > > 
> > > > > +static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
> > > > > +	SOC_ENUM("pwm select", pwm_src_enum),
> > > > > +	SOC_ENUM("mode select", mode_src_enum),
> > > > > +};
> > > > 
> > > > ALSA control names are idiomatically things like "PWM Select" with
> > > > capitalisation.
> > > 
> > > Actually, the capital words are no mandatory requirement (although
> > > it's conventionally so).  It's just alsa-mixer grouping rule that
> > > requires the capital words "Play", "Capture", "Volume", "Switch",
> > > etc.
> > 
> > Hi Takashi,
> > 
> > Where can I find these alsa-mixer grouping rule?
> > So that I can obey these rules and make them appear in the right view in
> > alsamixer.
> 
> Hi Takashi,
> 
> I'm reading this comment from file `sound/aoa/codecs/tas.c`:
> 
>         /* If we name this 'Input Source', it properly shows up in
>          * alsamixer as a selection, * but it's shown under the
>          * 'Playback' category.
>          * If I name it 'Capture Source', it shows up in strange
>          * ways (two bools of which one can be selected at a
>          * time) but at least it's shown in the 'Capture'
>          * category.
>          * I was told that this was due to backward compatibility,
>          * but I don't understand then why the mangling is *not*
>          * done when I name it "Input Source".....
>          */
> 
> I'm wondering what's the story behind? Can you shed some lights?

In alsa-mixer abstraction, the "Capture Source" enum control is split
over multiple switches (a switch per enum item).  This was a historical
design at the time SoundBlaster is still standard.

One of the problems with this abstraction is that it can't handle
multiple capture-source controls.  So, many drivers use nowadays
"Input Source" control instead.  But, in the earlier alsa-lib, this
wasn't handled as the capture control, thus it appears as a global
(both directional) control in alsamixer.

Now, this control is handled as a capture control in alsa-lib, so the
appearance is corrected.


Takashi

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-15  9:27           ` Takashi Iwai
@ 2011-04-15 14:10             ` Lu Guanqun
  0 siblings, 0 replies; 27+ messages in thread
From: Lu Guanqun @ 2011-04-15 14:10 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Mark Brown, Rajeev Kumar, lrg

On Fri, Apr 15, 2011 at 05:27:29PM +0800, Takashi Iwai wrote:
> In alsa-mixer abstraction, the "Capture Source" enum control is split
> over multiple switches (a switch per enum item).  This was a historical
> design at the time SoundBlaster is still standard.
> 
> One of the problems with this abstraction is that it can't handle
> multiple capture-source controls.  So, many drivers use nowadays
> "Input Source" control instead.  But, in the earlier alsa-lib, this
> wasn't handled as the capture control, thus it appears as a global
> (both directional) control in alsamixer.
> 
> Now, this control is handled as a capture control in alsa-lib, so the
> appearance is corrected.
> 

Thanks for your insightful information. :)
Much appreciated!

-- 
guanqun

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

* Re: [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver
  2011-04-11 13:00     ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Lu Guanqun
@ 2011-04-18  5:00       ` rajeev
  0 siblings, 0 replies; 27+ messages in thread
From: rajeev @ 2011-04-18  5:00 UTC (permalink / raw)
  To: Lu Guanqun; +Cc: tiwai, alsa-devel, broonie, lrg

Hi Lu Guanqun

On 4/11/2011 6:30 PM, Lu Guanqun wrote:
> I remember Mark had some comments on adding some logs when it's overrun,
> how do you think?
>
Oops,
Next patch will contain this changes

Best Rgds
Rajeev 
 

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-11 14:56   ` Mark Brown
  2011-04-14  9:54     ` Takashi Iwai
@ 2011-04-20  4:24     ` rajeev
  2011-04-20 10:56       ` Mark Brown
  1 sibling, 1 reply; 27+ messages in thread
From: rajeev @ 2011-04-20  4:24 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, lrg

Hi Mark
 please find my answer below.

On 4/11/2011 8:26 PM, Mark Brown wrote:
> On Mon, Apr 11, 2011 at 11:00:00AM +0530, Rajeev Kumar wrote:
> 
>> +static const char *op_mode_text[] = { "slave", "master"};
> 
> What is op_mode?  This sounds like it should be configured by
> set_dai_fmt()...
> 
OK, I will change the name.

>> +static const struct snd_kcontrol_new sta529_new_snd_controls[] = {
>> +	SOC_ENUM("pwm select", pwm_src_enum),
>> +	SOC_ENUM("mode select", mode_src_enum),
>> +};
> 
> ALSA control names are idiomatically things like "PWM Select" with
> capitalisation.
>
Using PWM Select
 
>> +	/*store the label for powers down audio subsystem for suspend.This is
>> +	 ** used by soc core layer*/
>> +	codec->bias_level = level;
> 
> The formatting of this comment isn't terribly idiomatic.
> 
OK

>> +static int sta529_probe(struct snd_soc_codec *codec)
>> +{
>> +	struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec);
>> +	int ret;
>> +
>> +	codec->hw_write = (hw_write_t)i2c_master_send;
>> +	codec->hw_read = NULL;
>> +	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;
>> +	}
> 
> You shouldn't need to be assigning the I/O functions if you set the
> control type.  If the device only supports I2C that can just be hard
> coded.
>
explained below.
 
>> +static int sta529_resume(struct snd_soc_codec *codec)
>> +{
>> +	int i;
>> +	u8 data[2];
>> +	u8 *cache = codec->reg_cache;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(sta529_reg); i++) {
>> +		data[0] = i;
>> +		data[1] = cache[i];
>> +		codec->hw_write(codec->control_data, data, 2);
>> +	}
> 
> It looks like you can use the standard cache sync implementation here?
> snd_soc_cache_sync().
> .
> 
This patch set has been compiled and tested for Linux-kernel-version 2.6.38-rc4,
since SPEAr patches for this linux version are already under review in Russel King's
ARM branch.This version does not have snd_soc_cache_sync() function. 

We plan to start porting the SPEAr patches on latest kernel after the earlier SPEAr patches
are ACKED. After the same, I will circulate the next SPEAr ASoC patch set containing changes
specific to this new kernel version.

Best Rgds
Rajeev

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-20  4:24     ` rajeev
@ 2011-04-20 10:56       ` Mark Brown
  2011-04-20 11:41         ` rajeev
  2011-04-20 11:42         ` rajeev
  0 siblings, 2 replies; 27+ messages in thread
From: Mark Brown @ 2011-04-20 10:56 UTC (permalink / raw)
  To: rajeev; +Cc: tiwai, alsa-devel, lrg

On Wed, Apr 20, 2011 at 09:54:47AM +0530, rajeev wrote:
> On 4/11/2011 8:26 PM, Mark Brown wrote:
> > On Mon, Apr 11, 2011 at 11:00:00AM +0530, Rajeev Kumar wrote:

> >> +static const char *op_mode_text[] = { "slave", "master"};

> > What is op_mode?  This sounds like it should be configured by
> > set_dai_fmt()...

> OK, I will change the name.

You're missing the point here.  The name isn't an issue.

> This patch set has been compiled and tested for Linux-kernel-version 2.6.38-rc4,
> since SPEAr patches for this linux version are already under review in Russel King's
> ARM branch.This version does not have snd_soc_cache_sync() function. 

This isn't how mainline works.  You're not submitting code against some
old, released kernel version.  You're submitting code for the
development version of the kernel and need to fit in with that.  Code
for an older kernel may not even compile with current development
kernels.  For integration testing -next is often a good bet.

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-20 10:56       ` Mark Brown
@ 2011-04-20 11:41         ` rajeev
  2011-04-20 11:42         ` rajeev
  1 sibling, 0 replies; 27+ messages in thread
From: rajeev @ 2011-04-20 11:41 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, lrg

Hi Mark
     
On 4/20/2011 4:26 PM, Mark Brown wrote:
> On Wed, Apr 20, 2011 at 09:54:47AM +0530, rajeev wrote:
>> On 4/11/2011 8:26 PM, Mark Brown wrote:
>>> On Mon, Apr 11, 2011 at 11:00:00AM +0530, Rajeev Kumar wrote:
> 
>>>> +static const char *op_mode_text[] = { "slave", "master"};
> 
>>> What is op_mode?  This sounds like it should be configured by
>>> set_dai_fmt()...
> 
>> OK, I will change the name.
> 
> You're missing the point here.  The name isn't an issue.
> 
Oops
Got the point, ThanX

>> This patch set has been compiled and tested for Linux-kernel-version 2.6.38-rc4,
>> since SPEAr patches for this linux version are already under review in Russel King's
>> ARM branch.This version does not have snd_soc_cache_sync() function. 
> 
> This isn't how mainline works.  You're not submitting code against some
> old, released kernel version.  You're submitting code for the
> development version of the kernel and need to fit in with that.  Code
> for an older kernel may not even compile with current development
> kernels.  For integration testing -next is often a good bet.
> .
> 
OK, I will do the changes as per your guidelines.

best rgds
Rajeev

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

* Re: [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec
  2011-04-20 10:56       ` Mark Brown
  2011-04-20 11:41         ` rajeev
@ 2011-04-20 11:42         ` rajeev
  1 sibling, 0 replies; 27+ messages in thread
From: rajeev @ 2011-04-20 11:42 UTC (permalink / raw)
  To: Mark Brown; +Cc: tiwai, alsa-devel, lrg

Hi Mark
     
On 4/20/2011 4:26 PM, Mark Brown wrote:
> On Wed, Apr 20, 2011 at 09:54:47AM +0530, rajeev wrote:
>> On 4/11/2011 8:26 PM, Mark Brown wrote:
>>> On Mon, Apr 11, 2011 at 11:00:00AM +0530, Rajeev Kumar wrote:
> 
>>>> +static const char *op_mode_text[] = { "slave", "master"};
> 
>>> What is op_mode?  This sounds like it should be configured by
>>> set_dai_fmt()...
> 
>> OK, I will change the name.
> 
> You're missing the point here.  The name isn't an issue.
> 
Oops
Got the point, ThanX

>> This patch set has been compiled and tested for Linux-kernel-version 2.6.38-rc4,
>> since SPEAr patches for this linux version are already under review in Russel King's
>> ARM branch.This version does not have snd_soc_cache_sync() function. 
> 
> This isn't how mainline works.  You're not submitting code against some
> old, released kernel version.  You're submitting code for the
> development version of the kernel and need to fit in with that.  Code
> for an older kernel may not even compile with current development
> kernels.  For integration testing -next is often a good bet.
> .
> 
OK, I will do the changes as per your guidelines.

best rgds
Rajeev

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

end of thread, other threads:[~2011-04-20 11:46 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-11  5:29 [PATCH V3 0/5] Adding ASoC drivers for SPEAr13XX platform Rajeev Kumar
2011-04-11  5:30 ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Rajeev Kumar
2011-04-11  5:30   ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Rajeev Kumar
2011-04-11  5:30     ` [PATCH V3 3/5] sound: asoc: Adding support for SPEAr13XX ASoC machine driver Rajeev Kumar
2011-04-11  5:30       ` [PATCH V3 4/5] sound: asoc: Adding Kconfig and Makefile to support SPEAr13XX ASoC driver Rajeev Kumar
2011-04-11  5:30         ` [PATCH V3 5/5] sound: asoc: Adding support for SPEAr13XX in soc Rajeev Kumar
2011-04-11 13:00     ` [PATCH V3 2/5] sound: asoc: Adding support for SPEAr13XX ASoC platform driver Lu Guanqun
2011-04-18  5:00       ` rajeev
2011-04-11 12:53   ` [PATCH V3 1/5] sound: asoc: Adding support for STA529 Audio Codec Lu Guanqun
2011-04-11 13:35     ` Mark Brown
2011-04-11 15:09       ` Lu Guanqun
2011-04-11 23:54         ` Mark Brown
2011-04-12  0:06           ` Lu Guanqun
2011-04-11 14:56   ` Mark Brown
2011-04-14  9:54     ` Takashi Iwai
2011-04-14 12:18       ` Mark Brown
2011-04-14 12:25         ` Takashi Iwai
2011-04-14 14:19       ` Lu Guanqun
2011-04-14 14:28         ` Lu Guanqun
2011-04-15  9:27           ` Takashi Iwai
2011-04-15 14:10             ` Lu Guanqun
2011-04-15  9:23         ` Takashi Iwai
2011-04-20  4:24     ` rajeev
2011-04-20 10:56       ` Mark Brown
2011-04-20 11:41         ` rajeev
2011-04-20 11:42         ` rajeev
2011-04-11 15:45   ` Lu Guanqun

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.