Patchwork [2/5] sgtl5000 audio: more porting to 2.6.31

login
register
mail settings
Submitter Brad Figg
Date Oct. 8, 2009, 4:39 p.m.
Message ID <1255019953-21442-3-git-send-email-brad.figg@canonical.com>
Download mbox | patch
Permalink /patch/35483/
State Accepted
Headers show

Comments

Brad Figg - Oct. 8, 2009, 4:39 p.m.
From: Alan Tull <r80115@freescale.com>

With this patch record and playback work at various sample rates
---
 sound/soc/codecs/sgtl5000.c         |  244 ++++++++++++++++++-----------------
 sound/soc/imx/imx-3stack-sgtl5000.c |   62 ++++-----
 sound/soc/imx/imx-pcm.c             |   15 ++-
 sound/soc/imx/imx-ssi.c             |   87 ++++++-------
 4 files changed, 205 insertions(+), 203 deletions(-)

Patch

diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 27e83b6..3d754de 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -379,21 +379,6 @@  static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
 		   1),
 };
 
-static int sgtl5000_add_controls(struct snd_soc_codec *codec)
-{
-	int err, i;
-
-	for (i = 0; i < ARRAY_SIZE(sgtl5000_snd_controls); i++) {
-		err = snd_ctl_add(codec->card,
-				  snd_soc_cnew(&sgtl5000_snd_controls[i],
-					       codec, NULL));
-		if (err < 0)
-			return err;
-	}
-
-	return 0;
-}
-
 static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
@@ -497,8 +482,8 @@  static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
-static void sgtl5000_pcm_shutdown(struct snd_pcm_substream *substream,
-				  struct snd_soc_dai *dia)
+static int sgtl5000_pcm_prepare(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
@@ -526,11 +511,12 @@  static void sgtl5000_pcm_shutdown(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int sgtl5000_pcm_startup(struct snd_pcm_substream *substream)
+static int sgtl5000_pcm_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->codec;
+	struct snd_soc_codec *codec = socdev->card->codec;
 	struct sgtl5000_priv *sgtl5000 = codec->private_data;
 	struct snd_pcm_runtime *master_runtime;
 
@@ -545,13 +531,8 @@  static int sgtl5000_pcm_startup(struct snd_pcm_substream *substream)
 	if (sgtl5000->master_substream) {
 		master_runtime = sgtl5000->master_substream->runtime;
 
-		pr_debug("Constraining to %d bits at %dHz\n",
-			 master_runtime->sample_bits, master_runtime->rate);
-
-		snd_pcm_hw_constraint_minmax(substream->runtime,
-					     SNDRV_PCM_HW_PARAM_RATE,
-					     master_runtime->rate,
-					     master_runtime->rate);
+		pr_debug("Constraining to %d bits\n",
+			 master_runtime->sample_bits);
 
 		snd_pcm_hw_constraint_minmax(substream->runtime,
 					     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
@@ -565,11 +546,12 @@  static int sgtl5000_pcm_startup(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static void sgtl5000_pcm_shutdown(struct snd_pcm_substream *substream)
+static void sgtl5000_pcm_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->codec;
+	struct snd_soc_codec *codec = socdev->card->codec;
 	struct sgtl5000_priv *sgtl5000 = codec->private_data;
 	int reg, dig_pwr, ana_pwr;
 
@@ -609,7 +591,7 @@  static void sgtl5000_pcm_shutdown(struct snd_pcm_substream *substream)
  */
 static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
 				  struct snd_pcm_hw_params *params,
-				  struct snd_soc_dai *dia)
+				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
@@ -874,10 +856,10 @@  static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
 			SNDRV_PCM_FMTBIT_S24_LE)
 
 struct snd_soc_dai_ops sgtl5000_ops = {
-	.shutdown = sgtl5000_pcm_shutdown,
-	.hw_params = sgtl5000_pcm_hw_params,
 	.prepare = sgtl5000_pcm_prepare,
 	.startup = sgtl5000_pcm_startup,
+	.shutdown = sgtl5000_pcm_shutdown,
+	.hw_params = sgtl5000_pcm_hw_params,
 	.digital_mute = sgtl5000_digital_mute,
 	.set_fmt = sgtl5000_set_dai_fmt,
 	.set_sysclk = sgtl5000_set_dai_sysclk
@@ -899,7 +881,8 @@  struct snd_soc_dai sgtl5000_dai = {
 		    .rates = SGTL5000_RATES,
 		    .formats = SGTL5000_FORMATS,
 		    },
-	.ops = &sgtl5000_ops
+	.ops = &sgtl5000_ops,
+	.symmetric_rates = 1,
 };
 EXPORT_SYMBOL_GPL(sgtl5000_dai);
 
@@ -917,7 +900,6 @@  static int sgtl5000_resume(struct platform_device *pdev)
 {
 	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec = socdev->card->codec;
-
 	unsigned int i;
 
 	/* Restore refs first in same order as in sgtl5000_init */
@@ -942,56 +924,31 @@  static int sgtl5000_resume(struct platform_device *pdev)
 	return 0;
 }
 
+static struct snd_soc_codec *sgtl5000_codec;
+
 /*
  * initialise the SGTL5000 driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int sgtl5000_init(struct snd_soc_device *socdev)
+static int sgtl5000_probe(struct platform_device *pdev)
 {
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct sgtl5000_platform_data *plat = socdev->codec_data;
-	struct snd_soc_codec *codec = socdev->card->codec;
-	struct i2c_client *client = codec->control_data;
+	struct snd_soc_codec *codec = sgtl5000_codec;
 	struct sgtl5000_priv *sgtl5000 = codec->private_data;
 	u16 reg, ana_pwr, lreg_ctrl, ref_ctrl, lo_ctrl, short_ctrl, sss;
 	int vag;
-	unsigned int val;
 	int ret = 0;
 
-	val = sgtl5000_read(codec, SGTL5000_CHIP_ID);
-	if (((val & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
-	    SGTL5000_PARTID_PART_ID) {
-		pr_err("Device with ID register %x is not a SGTL5000\n", val);
-		return -ENODEV;
-	}
-
-	sgtl5000->rev = (val & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
-	dev_info(&client->dev, "SGTL5000 revision %d\n", sgtl5000->rev);
-
-	codec->name = "SGTL5000";
-	codec->owner = THIS_MODULE;
-	codec->read = sgtl5000_read_reg_cache;
-	codec->write = sgtl5000_write;
-	codec->bias_level = SND_SOC_BIAS_OFF;
-	codec->set_bias_level = sgtl5000_set_bias_level;
-	codec->dai = &sgtl5000_dai;
-	codec->num_dai = 1;
-	codec->reg_cache_size = sizeof(sgtl5000_regs);
-	codec->reg_cache_step = 2;
-	codec->reg_cache = (void *)&sgtl5000_regs;
-	if (codec->reg_cache == NULL) {
-		dev_err(&client->dev, "Failed to allocate register cache\n");
-		return -ENOMEM;
-	}
+	socdev->card->codec = sgtl5000_codec;
 
 	/* register pcms */
 	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 	if (ret < 0) {
-		dev_err(&client->dev, "failed to create pcms\n");
+		dev_err(codec->dev, "failed to create pcms\n");
 		return ret;
 	}
 
-	sgtl5000_sync_reg_cache(codec);
-
 	/* reset value */
 	ana_pwr = SGTL5000_DAC_STEREO |
 	    SGTL5000_LINREG_SIMPLE_POWERUP |
@@ -1056,7 +1013,8 @@  static int sgtl5000_init(struct snd_soc_device *socdev)
 	ref_ctrl |= SGTL5000_SMALL_POP;
 
 	/* Controls the output bias current for the lineout */
-	lo_ctrl |= (SGTL5000_LINE_OUT_CURRENT_360u << SGTL5000_LINE_OUT_CURRENT_SHIFT);
+	lo_ctrl |=
+	    (SGTL5000_LINE_OUT_CURRENT_360u << SGTL5000_LINE_OUT_CURRENT_SHIFT);
 
 	/* set short detect */
 	/* keep default */
@@ -1108,7 +1066,8 @@  static int sgtl5000_init(struct snd_soc_device *socdev)
 	sgtl5000_write(codec, SGTL5000_DAP_CTRL, 0);
 	/* TODO: initialize DAP */
 
-	sgtl5000_add_controls(codec);
+	snd_soc_add_controls(codec, sgtl5000_snd_controls,
+			     ARRAY_SIZE(sgtl5000_snd_controls));
 	sgtl5000_add_widgets(codec);
 
 	sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1124,47 +1083,41 @@  static int sgtl5000_init(struct snd_soc_device *socdev)
 	return 0;
 }
 
-static struct snd_soc_device *sgtl5000_socdev;
-
-static int sgtl5000_i2c_probe(struct i2c_client *i2c,
-			      const struct i2c_device_id *id)
+/* power down chip */
+static int sgtl5000_remove(struct platform_device *pdev)
 {
-	struct snd_soc_device *socdev = sgtl5000_socdev;
+	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 	struct snd_soc_codec *codec = socdev->card->codec;
-	int ret;
-
-	i2c_set_clientdata(i2c, codec);
-	codec->control_data = i2c;
 
-	ret = sgtl5000_init(socdev);
-	if (ret < 0)
-		dev_err(&i2c->dev, "Device initialisation failed\n");
+	if (codec->control_data)
+		sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	snd_soc_free_pcms(socdev);
+	snd_soc_dapm_free(socdev);
 
-	return ret;
+	return 0;
 }
 
-static const struct i2c_device_id sgtl5000_id[] = {
-	{"sgtl5000-i2c", 0},
-	{},
-};
-
-MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
-
-static struct i2c_driver sgtl5000_i2c_driver = {
-	.driver = {
-		   .name = "sgtl5000-i2c",
-		   .owner = THIS_MODULE,
-		   },
-	.probe = sgtl5000_i2c_probe,
-	.id_table = sgtl5000_id,
+struct snd_soc_codec_device soc_codec_dev_sgtl5000 = {
+	.probe = sgtl5000_probe,
+	.remove = sgtl5000_remove,
+	.suspend = sgtl5000_suspend,
+	.resume = sgtl5000_resume,
 };
+EXPORT_SYMBOL_GPL(soc_codec_dev_sgtl5000);
 
-static int sgtl5000_probe(struct platform_device *pdev)
+static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
 	struct sgtl5000_priv *sgtl5000;
+	struct snd_soc_codec *codec;
 	int ret = 0;
+	u32 val;
+
+	if (sgtl5000_codec) {
+		dev_err(&client->dev,
+			"Multiple SGTL5000 devices not supported\n");
+		return -ENOMEM;
+	}
 
 	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
 	if (codec == NULL)
@@ -1177,46 +1130,97 @@  static int sgtl5000_probe(struct platform_device *pdev)
 	}
 
 	codec->private_data = sgtl5000;
-	socdev->card->codec = codec;
 	mutex_init(&codec->mutex);
 	INIT_LIST_HEAD(&codec->dapm_widgets);
 	INIT_LIST_HEAD(&codec->dapm_paths);
-	sgtl5000_socdev = socdev;
 
-	ret = i2c_add_driver(&sgtl5000_i2c_driver);
+	i2c_set_clientdata(client, codec);
+	codec->control_data = client;
+
+	val = sgtl5000_read(codec, SGTL5000_CHIP_ID);
+	if (((val & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
+	    SGTL5000_PARTID_PART_ID) {
+		pr_err("Device with ID register %x is not a SGTL5000\n", val);
+		return -ENODEV;
+	}
+
+	sgtl5000->rev = (val & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
+	dev_info(&client->dev, "SGTL5000 revision %d\n", sgtl5000->rev);
+
+	codec->dev = &client->dev;
+	codec->name = "SGTL5000";
+	codec->owner = THIS_MODULE;
+	codec->read = sgtl5000_read_reg_cache;
+	codec->write = sgtl5000_write;
+	codec->bias_level = SND_SOC_BIAS_OFF;
+	codec->set_bias_level = sgtl5000_set_bias_level;
+	codec->dai = &sgtl5000_dai;
+	codec->num_dai = 1;
+	codec->reg_cache_size = sizeof(sgtl5000_regs);
+	codec->reg_cache_step = 2;
+	codec->reg_cache = (void *)&sgtl5000_regs;
+
+	sgtl5000_sync_reg_cache(codec);
+
+	sgtl5000_codec = codec;
+	sgtl5000_dai.dev = &client->dev;
+
+	ret = snd_soc_register_codec(codec);
 	if (ret != 0) {
-		dev_err(&pdev->dev, "can't add i2c driver\n");
-		kfree(codec->private_data);
-		kfree(codec);
+		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_dai(&sgtl5000_dai);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
+		return ret;
 	}
 
 	return ret;
 }
 
-/* power down chip */
-static int sgtl5000_remove(struct platform_device *pdev)
+static __devexit int sgtl5000_i2c_remove(struct i2c_client *client)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct snd_soc_codec *codec = i2c_get_clientdata(client);
+	struct sgtl5000_priv *sgtl5000 = codec->private_data;
 
-	if (codec->control_data)
-		sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
-	i2c_del_driver(&sgtl5000_i2c_driver);
-	kfree(codec->private_data);
+	snd_soc_unregister_dai(&sgtl5000_dai);
+	snd_soc_unregister_codec(codec);
 	kfree(codec);
-
+	kfree(sgtl5000);
+	sgtl5000_codec = NULL;
 	return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_sgtl5000 = {
-	.probe = sgtl5000_probe,
-	.remove = sgtl5000_remove,
-	.suspend = sgtl5000_suspend,
-	.resume = sgtl5000_resume,
+static const struct i2c_device_id sgtl5000_id[] = {
+	{"sgtl5000-i2c", 0},
+	{},
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_sgtl5000);
+
+MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
+
+static struct i2c_driver sgtl5000_i2c_driver = {
+	.driver = {
+		   .name = "sgtl5000-i2c",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = sgtl5000_i2c_probe,
+	.remove = __devexit_p(sgtl5000_i2c_remove),
+	.id_table = sgtl5000_id,
+};
+
+static int __init sgtl5000_modinit(void)
+{
+	return i2c_add_driver(&sgtl5000_i2c_driver);
+}
+module_init(sgtl5000_modinit);
+
+static void __exit sgtl5000_exit(void)
+{
+	i2c_del_driver(&sgtl5000_i2c_driver);
+}
+module_exit(sgtl5000_exit);
 
 MODULE_DESCRIPTION("ASoC SGTL5000 driver");
 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
diff --git a/sound/soc/imx/imx-3stack-sgtl5000.c b/sound/soc/imx/imx-3stack-sgtl5000.c
index 9d44125..5ff90db 100644
--- a/sound/soc/imx/imx-3stack-sgtl5000.c
+++ b/sound/soc/imx/imx-3stack-sgtl5000.c
@@ -29,7 +29,6 @@ 
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dai.h>
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
@@ -75,7 +74,7 @@  struct imx_3stack_priv {
 	struct regulator *reg_vddd;
 };
 
-static struct imx_3stack_priv machine_priv;
+static struct imx_3stack_priv card_priv;
 
 static int imx_3stack_audio_hw_params(struct snd_pcm_substream *substream,
 				      struct snd_pcm_hw_params *params)
@@ -84,7 +83,7 @@  static int imx_3stack_audio_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_dai_link *machine = rtd->dai;
 	struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 	struct snd_soc_dai *codec_dai = machine->codec_dai;
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 	unsigned int rate = params_rate(params);
 	int ret = 0;
 
@@ -105,7 +104,7 @@  static int imx_3stack_audio_hw_params(struct snd_pcm_substream *substream,
 		    substream->runtime->private_data;
 		struct asrc_config config;
 		struct mxc_audio_platform_data *plat;
-		struct imx_3stack_priv *priv = &machine_priv;
+		struct imx_3stack_priv *priv = &card_priv;
 		int retVal = 0;
 		retVal = asrc_req_pair(channel, &asrc_ssi_data.asrc_index);
 		if (retVal < 0) {
@@ -141,38 +140,24 @@  static int imx_3stack_audio_hw_params(struct snd_pcm_substream *substream,
 #if SGTL5000_SSI_MASTER
 	dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 	    SND_SOC_DAIFMT_CBM_CFM;
-//	if (channels == 2)
-//		dai_format |= SND_SOC_DAIFMT_TDM;
-
-	/* set codec DAI configuration */
-	ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
-	if (ret < 0)
-		return ret;
-
-	/* set cpu DAI configuration */
-	ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
-	if (ret < 0)
-		return ret;
 #else
 	dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 	    SND_SOC_DAIFMT_CBS_CFS;
-//	if (channels == 2)
-//		dai_format |= SND_SOC_DAIFMT_TDM;
+#endif
 
 	/* set codec DAI configuration */
 	ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
 	if (ret < 0)
 		return ret;
 
+	/* set i.MX active slot mask */
+	snd_soc_dai_set_tdm_slot(cpu_dai,
+				 channels == 1 ? 0xfffffffe : 0xfffffffc, 2);
+
 	/* set cpu DAI configuration */
 	ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
 	if (ret < 0)
 		return ret;
-#endif
-
-	/* set i.MX active slot mask */
-	snd_soc_dai_set_tdm_slot(cpu_dai,
-				 channels == 1 ? 0xfffffffe : 0xfffffffc, 2);
 
 	/* set the SSI system clock as input (unused) */
 	snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN);
@@ -205,7 +190,7 @@  static int imx_3stack_startup(struct snd_pcm_substream *substream)
 
 static void imx_3stack_shutdown(struct snd_pcm_substream *substream)
 {
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 
 #if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE)
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -306,7 +291,7 @@  static int sgtl5000_spk_func;
 
 static void headphone_detect_handler(struct work_struct *work)
 {
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 	struct platform_device *pdev = priv->pdev;
 	struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
 	int hp_status;
@@ -331,7 +316,7 @@  static irqreturn_t imx_headphone_detect_handler(int irq, void *data)
 
 static ssize_t show_headphone(struct device_driver *dev, char *buf)
 {
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 	struct platform_device *pdev = priv->pdev;
 	struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
 	u16 hp_status;
@@ -412,7 +397,7 @@  static int sgtl5000_set_spk(struct snd_kcontrol *kcontrol,
 static int spk_amp_event(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol, int event)
 {
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 	struct platform_device *pdev = priv->pdev;
 	struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
 
@@ -427,7 +412,7 @@  static int spk_amp_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-/* imx_3stack machine dapm widgets */
+/* imx_3stack card dapm widgets */
 static const struct snd_soc_dapm_widget imx_3stack_dapm_widgets[] = {
 	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 	SND_SOC_DAPM_LINE("Line In Jack", NULL),
@@ -521,11 +506,12 @@  static struct snd_soc_dai_link imx_3stack_dai = {
 	.codec_dai = &sgtl5000_dai,
 	.init = imx_3stack_sgtl5000_init,
 	.ops = &imx_3stack_ops,
+	.symmetric_rates = 1,
 };
 
-static int imx_3stack_machine_remove(struct platform_device *pdev)
+static int imx_3stack_card_remove(struct platform_device *pdev)
 {
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 	struct mxc_audio_platform_data *plat;
 	if (priv->reg_vddio)
 		regulator_disable(priv->reg_vddio);
@@ -548,17 +534,16 @@  static int imx_3stack_machine_remove(struct platform_device *pdev)
 	return 0;
 }
 
-/* imx_3stack audio machine driver */
-static struct snd_soc_card snd_soc_machine_imx_3stack = {
+static struct snd_soc_card snd_soc_card_imx_3stack = {
 	.name = "imx-3stack",
 	.platform = &imx_soc_platform,
 	.dai_link = &imx_3stack_dai,
 	.num_links = 1,
-	.remove = imx_3stack_machine_remove,
+	.remove = imx_3stack_card_remove,
 };
 
 static struct snd_soc_device imx_3stack_snd_devdata = {
-	.card = &snd_soc_machine_imx_3stack,
+	.card = &snd_soc_card_imx_3stack,
 	.codec_dev = &soc_codec_dev_sgtl5000,
 };
 
@@ -566,13 +551,15 @@  static int __devinit imx_3stack_sgtl5000_probe(struct platform_device *pdev)
 {
 	struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
 	struct regulator *reg;
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 	struct sgtl5000_platform_data *codec_data;
 	int ret = 0;
 
 	priv->sysclk = plat->sysclk;
 	priv->pdev = pdev;
+
 	imx_ssi_dai.private_data = plat;
+	imx_ssi_dai.dev = &pdev->dev;
 
 	codec_data = kzalloc(sizeof(struct sgtl5000_platform_data), GFP_KERNEL);
 	if (!codec_data) {
@@ -592,6 +579,9 @@  static int __devinit imx_3stack_sgtl5000_probe(struct platform_device *pdev)
 	else
 		imx_ssi_dai.name = "imx-ssi-1";
 
+	imx_ssi_dai.symmetric_rates = 1;
+	snd_soc_register_dai(&imx_ssi_dai);
+
 	ret = driver_create_file(pdev->dev.driver, &driver_attr_headphone);
 	if (ret < 0) {
 		pr_err("%s:failed to create driver_attr_headphone\n", __func__);
@@ -681,7 +671,7 @@  err_codec_data:
 static int imx_3stack_sgtl5000_remove(struct platform_device *pdev)
 {
 	struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
-	struct imx_3stack_priv *priv = &machine_priv;
+	struct imx_3stack_priv *priv = &card_priv;
 
 	free_irq(plat->hp_irq, priv);
 
diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/imx/imx-pcm.c
index a173367..bcfc59a 100644
--- a/sound/soc/imx/imx-pcm.c
+++ b/sound/soc/imx/imx-pcm.c
@@ -102,7 +102,7 @@  static int imx_iram_audio_playback_mmap(struct snd_pcm_substream *substream,
 	if (off + size > SND_RAM_SIZE)
 		return -EINVAL;
 
-	area->vm_page_prot = pgprot_nonshareddev(area->vm_page_prot);
+	area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
 	area->vm_flags |= VM_IO;
 	ret =
 	    remap_pfn_range(area, area->vm_start, phys >> PAGE_SHIFT,
@@ -681,9 +681,20 @@  struct snd_soc_platform imx_soc_platform = {
 	.pcm_new = imx_pcm_new,
 	.pcm_free = imx_pcm_free_dma_buffers,
 };
-
 EXPORT_SYMBOL_GPL(imx_soc_platform);
 
+static int __init imx_pcm_init(void)
+{
+	return snd_soc_register_platform(&imx_soc_platform);
+}
+module_init(imx_pcm_init);
+
+static void __exit imx_pcm_exit(void)
+{
+	snd_soc_unregister_platform(&imx_soc_platform);
+}
+module_exit(imx_pcm_exit);
+
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_DESCRIPTION("Freescale i.MX3x PCM DMA module");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 91b5019..2dba33b 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -39,6 +39,13 @@ 
 #include "imx-ssi.h"
 #include "imx-pcm.h"
 
+/* private info */
+struct imx_ssi {
+	bool network_mode;
+};
+
+static struct imx_ssi imx_ssi_data[IMX_DAI_SSI3];
+
 /* debug */
 #define IMX_SSI_DEBUG 0
 #if IMX_SSI_DEBUG
@@ -187,8 +194,11 @@  static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 				    unsigned int mask, int slots)
 {
+	bool network_mode = (!(mask & 0x2));
 	u32 stmsk, srmsk, stccr;
 
+	imx_ssi_data[cpu_dai->id].network_mode = network_mode;
+
 	if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI1) {
 		if (__raw_readl(SSI1_SCR) & SSI_SCR_SSIEN)
 			return 0;
@@ -226,8 +236,12 @@  static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
  */
 static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
+  	bool sync_mode = cpu_dai->symmetric_rates;
+	bool network_mode;
 	u32 stcr = 0, srcr = 0, scr;
 
+	network_mode = imx_ssi_data[cpu_dai->id].network_mode;
+
 	if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI1)
 		scr = __raw_readl(SSI1_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
 	else
@@ -288,11 +302,11 @@  static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
-//		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
-//		    && (fmt & SND_SOC_DAIFMT_TDM)) {
-//			scr &= ~SSI_SCR_I2S_MODE_MASK;
-//			scr |= SSI_SCR_I2S_MODE_MSTR;
-//		}
+		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
+		    && network_mode) {
+			scr &= ~SSI_SCR_I2S_MODE_MASK;
+			scr |= SSI_SCR_I2S_MODE_MSTR;
+		}
 		break;
 	case SND_SOC_DAIFMT_CBM_CFS:
 		stcr |= SSI_STCR_TFDIR;
@@ -303,21 +317,21 @@  static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 		srcr |= SSI_SRCR_RXDIR;
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
-//		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
-//		    && (fmt & SND_SOC_DAIFMT_TDM)) {
-//			scr &= ~SSI_SCR_I2S_MODE_MASK;
-//			scr |= SSI_SCR_I2S_MODE_SLAVE;
-//		}
+		if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
+		    && network_mode) {
+			scr &= ~SSI_SCR_I2S_MODE_MASK;
+			scr |= SSI_SCR_I2S_MODE_SLAVE;
+		}
 		break;
 	}
 
 	/* sync */
-//	if (!(fmt & SND_SOC_DAIFMT_ASYNC))
-//		scr |= SSI_SCR_SYN;
+	if (sync_mode)
+		scr |= SSI_SCR_SYN;
 
 	/* tdm - only for stereo atm */
-//	if (fmt & SND_SOC_DAIFMT_TDM)
-//		scr |= SSI_SCR_NET;
+	if (network_mode)
+		scr |= SSI_SCR_NET;
 
 	if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI1) {
 		__raw_writel(stcr, SSI1_STCR);
@@ -336,11 +350,8 @@  static struct clk *ssi1_clk;
 static struct clk *ssi2_clk;
 
 static int imx_ssi_startup(struct snd_pcm_substream *substream,
-			struct snd_soc_dai *dai)
+			   struct snd_soc_dai *cpu_dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
 	/* we cant really change any SSI values after SSI is enabled
 	 * need to fix in software for max flexibility - lrg */
 	if (cpu_dai->playback.active || cpu_dai->capture.active)
@@ -388,10 +399,9 @@  static int imx_ssi_startup(struct snd_pcm_substream *substream,
 }
 
 static int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *cpu_dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	u32 stccr, stcr, sier;
 
 	if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI1) {
@@ -438,24 +448,19 @@  static int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream,
 }
 
 static int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *cpu_dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	bool sync_mode = cpu_dai->symmetric_rates;
 	u32 srccr, srcr, sier;
-	bool sync_mode;
 
 	if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI1) {
-		sync_mode =
-		    (__raw_readl(SSI1_SCR) & SSI_SCR_SYN) ? true : false;
 		srccr =
 		    sync_mode ? __raw_readl(SSI1_STCCR) :
 		    __raw_readl(SSI1_SRCCR);
 		srcr = __raw_readl(SSI1_SRCR);
 		sier = __raw_readl(SSI1_SIER);
 	} else {
-		sync_mode =
-		    (__raw_readl(SSI2_SCR) & SSI_SCR_SYN) ? true : false;
 		srccr =
 		    sync_mode ? __raw_readl(SSI2_STCCR) :
 		    __raw_readl(SSI2_SRCCR);
@@ -507,11 +512,9 @@  static int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream,
  * although can be called multiple times by upper layers.
  */
 static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
-			struct snd_pcm_hw_params *params,
-			struct snd_soc_dai *da)
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *cpu_dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	int id;
 
 	id = cpu_dai->id;
@@ -528,7 +531,7 @@  static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
 			    (__raw_readl(SSI2_SCR) & SSI_SCR_TE))
 				return 0;
 		}
-		return imx_ssi_hw_tx_params(substream, params);
+		return imx_ssi_hw_tx_params(substream, params, cpu_dai);
 	} else {
 		/* cant change any parameters when SSI is running */
 		if (id == IMX_DAI_SSI0 || id == IMX_DAI_SSI1) {
@@ -540,15 +543,13 @@  static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
 			    (__raw_readl(SSI2_SCR) & SSI_SCR_RE))
 				return 0;
 		}
-		return imx_ssi_hw_rx_params(substream, params);
+		return imx_ssi_hw_rx_params(substream, params, cpu_dai);
 	}
 }
 
 static int imx_ssi_prepare(struct snd_pcm_substream *substream,
-			struct snd_soc_dai *da)
+			   struct snd_soc_dai *cpu_dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	u32 scr;
 
 	/* enable the SSI port, note that no other port config
@@ -565,10 +566,8 @@  static int imx_ssi_prepare(struct snd_pcm_substream *substream,
 }
 
 static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
-			struct snd_soc_dai *da)
+			   struct snd_soc_dai *cpu_dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	u32 scr;
 
 	if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI1)
@@ -613,10 +612,8 @@  static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
 }
 
 static void imx_ssi_shutdown(struct snd_pcm_substream *substream,
-			struct snd_soc_dai *da)
+			     struct snd_soc_dai *cpu_dai)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	int id;
 
 	id = cpu_dai->id;
@@ -748,7 +745,7 @@  static void imx_ssi_remove(struct platform_device *pdev,
 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 	SNDRV_PCM_FMTBIT_S24_LE)
 
-struct snd_soc_dai_ops imx_ssi_dai_ops = {
+static struct snd_soc_dai_ops imx_ssi_dai_ops = {
 	.startup = imx_ssi_startup,
 	.shutdown = imx_ssi_shutdown,
 	.trigger = imx_ssi_trigger,